1 /*- 2 * Copyright (c) 1997, 1998 3 * Nan Yang Computer Services Limited. All rights reserved. 4 * 5 * Written by Greg Lehey 6 * 7 * This software is distributed under the so-called ``Berkeley 8 * License'': 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by Nan Yang Computer 21 * Services Limited. 22 * 4. Neither the name of the Company nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * This software is provided ``as is'', and any express or implied 27 * warranties, including, but not limited to, the implied warranties of 28 * merchantability and fitness for a particular purpose are disclaimed. 29 * In no event shall the company or contributors be liable for any 30 * direct, indirect, incidental, special, exemplary, or consequential 31 * damages (including, but not limited to, procurement of substitute 32 * goods or services; loss of use, data, or profits; or business 33 * interruption) however caused and on any theory of liability, whether 34 * in contract, strict liability, or tort (including negligence or 35 * otherwise) arising in any way out of the use of this software, even if 36 * advised of the possibility of such damage. 37 * 38 * $Id: vinum.c,v 1.33 2001/01/09 06:19:15 grog Exp grog $ 39 * $FreeBSD: src/sys/dev/vinum/vinum.c,v 1.38.2.3 2003/01/07 12:14:16 joerg Exp $ 40 * $DragonFly: src/sys/dev/raid/vinum/vinum.c,v 1.20 2007/05/15 22:44:12 dillon Exp $ 41 */ 42 43 #define STATIC static /* nothing while we're testing XXX */ 44 45 #include "vinumhdr.h" 46 #include <sys/sysproto.h> /* for sync(2) */ 47 #include <sys/devicestat.h> 48 #include <sys/udev.h> 49 #ifdef VINUMDEBUG 50 #include <sys/reboot.h> 51 int debug = 0; 52 extern int total_malloced; 53 extern int malloccount; 54 extern struct mc malloced[]; 55 #endif 56 #include "request.h" 57 58 struct dev_ops vinum_ops = 59 { 60 { "vinum", VINUM_CDEV_MAJOR, D_DISK }, 61 .d_open = vinumopen, 62 .d_close = vinumclose, 63 .d_read = physread, 64 .d_write = physwrite, 65 .d_ioctl = vinumioctl, 66 .d_poll = vinumpoll, 67 .d_strategy = vinumstrategy, 68 .d_dump = vinumdump, 69 .d_psize = vinumsize, 70 }; 71 72 /* Called by main() during pseudo-device attachment. */ 73 STATIC void vinumattach(void *); 74 75 STATIC int vinum_modevent(module_t mod, modeventtype_t type, void *unused); 76 STATIC void vinum_initconf(void); 77 78 struct _vinum_conf vinum_conf; /* configuration information */ 79 cdev_t vinum_super_dev; 80 cdev_t vinum_wsuper_dev; 81 cdev_t vinum_daemon_dev; 82 83 /* 84 * Called by main() during pseudo-device attachment. All we need 85 * to do is allocate enough space for devices to be configured later, and 86 * add devsw entries. 87 */ 88 void 89 vinumattach(void *dummy) 90 { 91 char *cp, *cp1, *cp2, **drives; 92 int i, rv; 93 struct volume *vol; 94 95 /* modload should prevent multiple loads, so this is worth a panic */ 96 if ((vinum_conf.flags & VF_LOADED) != 0) 97 panic("vinum: already loaded"); 98 99 log(LOG_INFO, "vinum: loaded\n"); 100 vinum_conf.flags |= VF_LOADED; /* we're loaded now */ 101 102 daemonq = NULL; /* initialize daemon's work queue */ 103 dqend = NULL; 104 105 #if 0 106 dev_ops_add(&vinum_ops, 0, 0); 107 #endif 108 109 vinum_initconf(); 110 111 /* 112 * Create superdev, wrongsuperdev, and controld devices. 113 */ 114 vinum_super_dev = make_dev(&vinum_ops, VINUM_SUPERDEV, 115 UID_ROOT, GID_WHEEL, 0600, 116 VINUM_SUPERDEV_BASE); 117 vinum_wsuper_dev = make_dev(&vinum_ops, VINUM_WRONGSUPERDEV, 118 UID_ROOT, GID_WHEEL, 0600, 119 VINUM_WRONGSUPERDEV_BASE); 120 vinum_daemon_dev = make_dev(&vinum_ops, VINUM_DAEMON_DEV, 121 UID_ROOT, GID_WHEEL, 0600, 122 VINUM_DAEMON_DEV_BASE); 123 124 /* 125 * See if the loader has passed us a disk to 126 * read the initial configuration from. 127 */ 128 if ((cp = kgetenv("vinum.drives")) != NULL) { 129 for (cp1 = cp, i = 0, drives = 0; *cp1 != '\0'; i++) { 130 cp2 = cp1; 131 while (*cp1 != '\0' && *cp1 != ',' && *cp1 != ' ') 132 cp1++; 133 if (*cp1 != '\0') 134 *cp1++ = '\0'; 135 drives = krealloc(drives, (unsigned long)((i + 1) * sizeof(char *)), 136 M_TEMP, M_WAITOK); 137 drives[i] = cp2; 138 } 139 if (i == 0) 140 goto bailout; 141 rv = vinum_scandisk(drives, i); 142 if (rv) 143 log(LOG_NOTICE, "vinum_scandisk() returned %d", rv); 144 bailout: 145 kfree(drives, M_TEMP); 146 } 147 if ((cp = kgetenv("vinum.root")) != NULL) { 148 for (i = 0; i < vinum_conf.volumes_used; i++) { 149 vol = &vinum_conf.volume[i]; 150 if ((vol->state == volume_up) 151 && (strcmp (vol->name, cp) == 0) 152 ) { 153 rootdev = make_dev(&vinum_ops, i, UID_ROOT, GID_OPERATOR, 154 0640, VINUM_BASE "vinumroot"); 155 udev_dict_set_cstr(rootdev, "subsystem", "raid"); 156 udev_dict_set_cstr(rootdev, "disk-type", "raid"); 157 log(LOG_INFO, "vinum: using volume %s for root device\n", cp); 158 break; 159 } 160 } 161 } 162 } 163 164 /* 165 * Check if we have anything open. If confopen is != 0, 166 * that goes for the super device as well, otherwise 167 * only for volumes. 168 * 169 * Return 0 if not inactive, 1 if inactive. 170 */ 171 int 172 vinum_inactive(int confopen) 173 { 174 int i; 175 int can_do = 1; /* assume we can do it */ 176 177 if (confopen && (vinum_conf.flags & VF_OPEN)) /* open by vinum(8)? */ 178 return 0; /* can't do it while we're open */ 179 lock_config(); 180 for (i = 0; i < vinum_conf.volumes_allocated; i++) { 181 if ((VOL[i].state > volume_down) 182 && (VOL[i].flags & VF_OPEN)) { /* volume is open */ 183 can_do = 0; 184 break; 185 } 186 } 187 unlock_config(); 188 return can_do; 189 } 190 191 /* 192 * Free all structures. 193 * If cleardrive is 0, save the configuration; otherwise 194 * remove the configuration from the drive. 195 * 196 * Before coming here, ensure that no volumes are open. 197 */ 198 void 199 free_vinum(int cleardrive) 200 { 201 int i; 202 int drives_allocated = vinum_conf.drives_allocated; 203 204 if (DRIVE != NULL) { 205 if (cleardrive) { /* remove the vinum config */ 206 for (i = 0; i < drives_allocated; i++) 207 remove_drive(i); /* remove the drive */ 208 } else { /* keep the config */ 209 for (i = 0; i < drives_allocated; i++) 210 free_drive(&DRIVE[i]); /* close files and things */ 211 } 212 Free(DRIVE); 213 } 214 while ((vinum_conf.flags & (VF_STOPPING | VF_DAEMONOPEN)) 215 == (VF_STOPPING | VF_DAEMONOPEN)) { /* at least one daemon open, we're stopping */ 216 queue_daemon_request(daemonrq_return, (union daemoninfo) 0); /* stop the daemon */ 217 tsleep(&vinumclose, 0, "vstop", 1); /* and wait for it */ 218 } 219 if (SD != NULL) { 220 for (i = 0; i < vinum_conf.subdisks_allocated; i++) { 221 struct sd *sd = &vinum_conf.sd[i]; 222 if (sd->sd_dev) { 223 destroy_dev(sd->sd_dev); 224 sd->sd_dev = NULL; 225 } 226 } 227 Free(SD); 228 } 229 if (PLEX != NULL) { 230 for (i = 0; i < vinum_conf.plexes_allocated; i++) { 231 struct plex *plex = &vinum_conf.plex[i]; 232 233 if (plex->plex_dev) { 234 destroy_dev(plex->plex_dev); 235 plex->plex_dev = NULL; 236 } 237 238 if (plex->state != plex_unallocated) { /* we have real data there */ 239 if (plex->sdnos) 240 Free(plex->sdnos); 241 } 242 } 243 Free(PLEX); 244 } 245 if (VOL != NULL) { 246 for (i = 0; i < vinum_conf.volumes_allocated; i++) { 247 struct volume *vol = &vinum_conf.volume[i]; 248 249 if (vol->vol_dev) { 250 destroy_dev(vol->vol_dev); 251 vol->vol_dev = NULL; 252 } 253 } 254 Free(VOL); 255 } 256 bzero(&vinum_conf, sizeof(vinum_conf)); 257 vinum_initconf(); 258 } 259 260 STATIC void 261 vinum_initconf(void) 262 { 263 vinum_conf.physbufs = nswbuf / 2 + 1; 264 265 /* allocate space: drives... */ 266 DRIVE = (struct drive *) Malloc(sizeof(struct drive) * INITIAL_DRIVES); 267 CHECKALLOC(DRIVE, "vinum: no memory\n"); 268 bzero(DRIVE, sizeof(struct drive) * INITIAL_DRIVES); 269 vinum_conf.drives_allocated = INITIAL_DRIVES; 270 vinum_conf.drives_used = 0; 271 272 /* volumes, ... */ 273 VOL = (struct volume *) Malloc(sizeof(struct volume) * INITIAL_VOLUMES); 274 CHECKALLOC(VOL, "vinum: no memory\n"); 275 bzero(VOL, sizeof(struct volume) * INITIAL_VOLUMES); 276 vinum_conf.volumes_allocated = INITIAL_VOLUMES; 277 vinum_conf.volumes_used = 0; 278 279 /* plexes, ... */ 280 PLEX = (struct plex *) Malloc(sizeof(struct plex) * INITIAL_PLEXES); 281 CHECKALLOC(PLEX, "vinum: no memory\n"); 282 bzero(PLEX, sizeof(struct plex) * INITIAL_PLEXES); 283 vinum_conf.plexes_allocated = INITIAL_PLEXES; 284 vinum_conf.plexes_used = 0; 285 286 /* and subdisks */ 287 SD = (struct sd *) Malloc(sizeof(struct sd) * INITIAL_SUBDISKS); 288 CHECKALLOC(SD, "vinum: no memory\n"); 289 bzero(SD, sizeof(struct sd) * INITIAL_SUBDISKS); 290 vinum_conf.subdisks_allocated = INITIAL_SUBDISKS; 291 vinum_conf.subdisks_used = 0; 292 } 293 294 STATIC int 295 vinum_modevent(module_t mod, modeventtype_t type, void *unused) 296 { 297 switch (type) { 298 case MOD_LOAD: 299 vinumattach(NULL); 300 return 0; /* OK */ 301 case MOD_UNLOAD: 302 if (!vinum_inactive(1)) /* is anything open? */ 303 return EBUSY; /* yes, we can't do it */ 304 vinum_conf.flags |= VF_STOPPING; /* note that we want to stop */ 305 sys_sync(NULL); /* write out buffers */ 306 free_vinum(0); /* clean up */ 307 308 if (vinum_super_dev) { 309 destroy_dev(vinum_super_dev); 310 vinum_super_dev = NULL; 311 } 312 if (vinum_wsuper_dev) { 313 destroy_dev(vinum_wsuper_dev); 314 vinum_wsuper_dev = NULL; 315 } 316 if (vinum_daemon_dev) { 317 destroy_dev(vinum_daemon_dev); 318 vinum_daemon_dev = NULL; 319 } 320 321 sync_devs(); 322 #ifdef VINUMDEBUG 323 if (total_malloced) { 324 int i; 325 #ifdef INVARIANTS 326 int *poke; 327 #endif 328 329 for (i = 0; i < malloccount; i++) { 330 if (debug & DEBUG_WARNINGS) /* want to hear about them */ 331 log(LOG_WARNING, 332 "vinum: exiting with %d bytes malloced from %s:%d\n", 333 malloced[i].size, 334 malloced[i].file, 335 malloced[i].line); 336 #ifdef INVARIANTS 337 poke = &((int *) malloced[i].address) 338 [malloced[i].size / (2 * sizeof(int))]; /* middle of the area */ 339 if (*poke == 0xdeadc0de) /* already freed */ 340 log(LOG_ERR, 341 "vinum: exiting with malloc table inconsistency at %p from %s:%d\n", 342 malloced[i].address, 343 malloced[i].file, 344 malloced[i].line); 345 #endif 346 Free(malloced[i].address); 347 } 348 } 349 #endif 350 dev_ops_remove_all(&vinum_ops); 351 log(LOG_INFO, "vinum: unloaded\n"); /* tell the world */ 352 return 0; 353 default: 354 break; 355 } 356 return 0; 357 } 358 359 moduledata_t vinum_mod = 360 { 361 "vinum", 362 (modeventhand_t) vinum_modevent, 363 0 364 }; 365 DECLARE_MODULE(vinum, vinum_mod, SI_SUB_RAID, SI_ORDER_MIDDLE); 366 367 /* ARGSUSED */ 368 /* Open a vinum object */ 369 int 370 vinumopen(struct dev_open_args *ap) 371 { 372 cdev_t dev = ap->a_head.a_dev; 373 int error; 374 unsigned int index; 375 struct volume *vol; 376 struct plex *plex; 377 struct sd *sd; 378 int devminor; /* minor number */ 379 380 devminor = minor(dev); 381 error = 0; 382 /* First, decide what we're looking at */ 383 switch (DEVTYPE(dev)) { 384 case VINUM_VOLUME_TYPE: 385 index = Volno(dev); 386 if (index >= vinum_conf.volumes_allocated) 387 return ENXIO; /* no such device */ 388 vol = &VOL[index]; 389 390 switch (vol->state) { 391 case volume_unallocated: 392 case volume_uninit: 393 return ENXIO; 394 395 case volume_up: 396 vol->flags |= VF_OPEN; /* note we're open */ 397 return 0; 398 399 case volume_down: 400 return EIO; 401 402 default: 403 return EINVAL; 404 } 405 406 case VINUM_PLEX_TYPE: 407 if (Volno(dev) >= vinum_conf.volumes_allocated) 408 return ENXIO; 409 /* FALLTHROUGH */ 410 411 case VINUM_RAWPLEX_TYPE: 412 index = Plexno(dev); /* get plex index in vinum_conf */ 413 if (index >= vinum_conf.plexes_allocated) 414 return ENXIO; /* no such device */ 415 plex = &PLEX[index]; 416 417 switch (plex->state) { 418 case plex_referenced: 419 case plex_unallocated: 420 return EINVAL; 421 422 default: 423 plex->flags |= VF_OPEN; /* note we're open */ 424 return 0; 425 } 426 427 case VINUM_SD_TYPE: 428 if ((Volno(dev) >= vinum_conf.volumes_allocated) /* no such volume */ 429 ||(Plexno(dev) >= vinum_conf.plexes_allocated)) /* or no such plex */ 430 return ENXIO; /* no such device */ 431 432 /* FALLTHROUGH */ 433 434 case VINUM_RAWSD_TYPE: 435 index = Sdno(dev); /* get the subdisk number */ 436 if ((index >= vinum_conf.subdisks_allocated) /* not a valid SD entry */ 437 ||(SD[index].state < sd_init)) /* or SD is not real */ 438 return ENXIO; /* no such device */ 439 sd = &SD[index]; 440 441 /* 442 * Opening a subdisk is always a special operation, so we 443 * ignore the state as long as it represents a real subdisk 444 */ 445 switch (sd->state) { 446 case sd_unallocated: 447 case sd_uninit: 448 return EINVAL; 449 450 default: 451 sd->flags |= VF_OPEN; /* note we're open */ 452 return 0; 453 } 454 455 case VINUM_SUPERDEV_TYPE: 456 error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0); /* are we root? */ 457 if (error == 0) { /* yes, can do */ 458 if (devminor == VINUM_DAEMON_DEV) /* daemon device */ 459 vinum_conf.flags |= VF_DAEMONOPEN; /* we're open */ 460 else if (devminor == VINUM_SUPERDEV) 461 vinum_conf.flags |= VF_OPEN; /* we're open */ 462 else 463 error = ENODEV; /* nothing, maybe a debug mismatch */ 464 } 465 return error; 466 467 /* Vinum drives are disks. We already have a disk 468 * driver, so don't handle them here */ 469 case VINUM_DRIVE_TYPE: 470 default: 471 return ENODEV; /* don't know what to do with these */ 472 } 473 } 474 475 /* ARGSUSED */ 476 int 477 vinumclose(struct dev_close_args *ap) 478 { 479 cdev_t dev = ap->a_head.a_dev; 480 unsigned int index; 481 struct volume *vol; 482 int devminor; 483 484 devminor = minor(dev); 485 index = Volno(dev); 486 /* First, decide what we're looking at */ 487 switch (DEVTYPE(dev)) { 488 case VINUM_VOLUME_TYPE: 489 if (index >= vinum_conf.volumes_allocated) 490 return ENXIO; /* no such device */ 491 vol = &VOL[index]; 492 493 switch (vol->state) { 494 case volume_unallocated: 495 case volume_uninit: 496 return ENXIO; 497 498 case volume_up: 499 vol->flags &= ~VF_OPEN; /* reset our flags */ 500 return 0; 501 502 case volume_down: 503 return EIO; 504 505 default: 506 return EINVAL; 507 } 508 509 case VINUM_PLEX_TYPE: 510 if (Volno(dev) >= vinum_conf.volumes_allocated) 511 return ENXIO; 512 /* FALLTHROUGH */ 513 514 case VINUM_RAWPLEX_TYPE: 515 index = Plexno(dev); /* get plex index in vinum_conf */ 516 if (index >= vinum_conf.plexes_allocated) 517 return ENXIO; /* no such device */ 518 PLEX[index].flags &= ~VF_OPEN; /* reset our flags */ 519 return 0; 520 521 case VINUM_SD_TYPE: 522 if ((Volno(dev) >= vinum_conf.volumes_allocated) || /* no such volume */ 523 (Plexno(dev) >= vinum_conf.plexes_allocated)) /* or no such plex */ 524 return ENXIO; /* no such device */ 525 /* FALLTHROUGH */ 526 527 case VINUM_RAWSD_TYPE: 528 index = Sdno(dev); /* get the subdisk number */ 529 if (index >= vinum_conf.subdisks_allocated) 530 return ENXIO; /* no such device */ 531 SD[index].flags &= ~VF_OPEN; /* reset our flags */ 532 return 0; 533 534 case VINUM_SUPERDEV_TYPE: 535 /* 536 * don't worry about whether we're root: 537 * nobody else would get this far. 538 */ 539 if (devminor == VINUM_SUPERDEV) /* normal superdev */ 540 vinum_conf.flags &= ~VF_OPEN; /* no longer open */ 541 else if (devminor == VINUM_DAEMON_DEV) { /* the daemon device */ 542 vinum_conf.flags &= ~VF_DAEMONOPEN; /* no longer open */ 543 if (vinum_conf.flags & VF_STOPPING) /* we're stopping, */ 544 wakeup(&vinumclose); /* we can continue stopping now */ 545 } 546 return 0; 547 548 case VINUM_DRIVE_TYPE: 549 default: 550 return ENODEV; /* don't know what to do with these */ 551 } 552 } 553 554 /* size routine */ 555 int 556 vinumsize(struct dev_psize_args *ap) 557 { 558 cdev_t dev = ap->a_head.a_dev; 559 struct volume *vol; 560 561 vol = &VOL[Volno(dev)]; 562 563 if (vol->state == volume_up) { 564 ap->a_result = (int64_t)vol->size; 565 return(0); 566 } else { 567 return(ENXIO); 568 } 569 } 570 571 int 572 vinumdump(struct dev_dump_args *ap) 573 { 574 /* Not implemented. */ 575 return ENXIO; 576 } 577 578 int 579 vinumpoll(struct dev_poll_args *ap) 580 { 581 ap->a_events = seltrue(ap->a_head.a_dev, ap->a_events); 582 return(0); 583 } 584 585 /* Local Variables: */ 586 /* fill-column: 50 */ 587 /* End: */ 588