1 /*- 2 * Copyright (c) 1997, 1998 3 * Nan Yang Computer Services Limited. All rights reserved. 4 * 5 * This software is distributed under the so-called ``Berkeley 6 * License'': 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by Nan Yang Computer 19 * Services Limited. 20 * 4. Neither the name of the Company nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * This software is provided ``as is'', and any express or implied 25 * warranties, including, but not limited to, the implied warranties of 26 * merchantability and fitness for a particular purpose are disclaimed. 27 * In no event shall the company or contributors be liable for any 28 * direct, indirect, incidental, special, exemplary, or consequential 29 * damages (including, but not limited to, procurement of substitute 30 * goods or services; loss of use, data, or profits; or business 31 * interruption) however caused and on any theory of liability, whether 32 * in contract, strict liability, or tort (including negligence or 33 * otherwise) arising in any way out of the use of this software, even if 34 * advised of the possibility of such damage. 35 * 36 * $Id: vinumio.c,v 1.30 2000/05/10 23:23:30 grog Exp grog $ 37 * $FreeBSD: src/sys/dev/vinum/vinumio.c,v 1.52.2.6 2002/05/02 08:43:44 grog Exp $ 38 * $DragonFly: src/sys/dev/raid/vinum/vinumio.c,v 1.27 2007/07/16 21:31:06 dillon Exp $ 39 */ 40 41 #include "vinumhdr.h" 42 #include "request.h" 43 #include <vm/vm_zone.h> 44 45 static char *sappend(char *txt, char *s); 46 static int drivecmp(const void *va, const void *vb); 47 48 /* 49 * Open the device associated with the drive, and set drive's vp. 50 * Return an error number 51 */ 52 int 53 open_drive(struct drive *drive, struct proc *p, int verbose) 54 { 55 int devmajor; /* major devs for disk device */ 56 int devminor; /* minor devs for disk device */ 57 int unit; 58 int slice; 59 int part; 60 char *dname; 61 62 if (bcmp(drive->devicename, "/dev/", 5)) /* device name doesn't start with /dev */ 63 return ENOENT; /* give up */ 64 if (drive->flags & VF_OPEN) /* open already, */ 65 return EBUSY; /* don't do it again */ 66 67 /* 68 * Yes, Bruce, I know this is horrible, but we 69 * don't have a root file system when we first 70 * try to do this. If you can come up with a 71 * better solution, I'd really like it. I'm 72 * just putting it in now to add ammuntion to 73 * moving the system to devfs. 74 */ 75 dname = &drive->devicename[5]; 76 drive->dev = NULL; /* no device yet */ 77 78 /* Find the device */ 79 if (bcmp(dname, "ad", 2) == 0) /* IDE disk */ 80 devmajor = 116; 81 else if (bcmp(dname, "wd", 2) == 0) /* IDE disk */ 82 devmajor = 3; 83 else if (bcmp(dname, "da", 2) == 0) 84 devmajor = 13; 85 else if (bcmp(dname, "vn", 2) == 0) 86 devmajor = 43; 87 else if (bcmp(dname, "md", 2) == 0) 88 devmajor = 95; 89 else if (bcmp(dname, "vkd", 3) == 0) { 90 devmajor = 97; 91 dname += 1; 92 } else if (bcmp(dname, "amrd", 4) == 0) { 93 devmajor = 133; 94 dname += 2; 95 } else if (bcmp(dname, "mlxd", 4) == 0) { 96 devmajor = 131; 97 dname += 2; 98 } else if (bcmp(dname, "idad", 4) == 0) { 99 devmajor = 109; 100 dname += 2; 101 } else if (bcmp(dname, "twed", 4) == 0) { /* 3ware raid */ 102 devmajor = 147; 103 dname += 2; 104 } else if (bcmp(dname, "ar", 2) == 0) { 105 devmajor = 157; 106 } else 107 return ENODEV; 108 dname += 2; /* point past */ 109 110 /* 111 * Found the device. Require the form 112 * <unit>s<slice><partition> 113 */ 114 if (*dname < '0' || *dname > '9') 115 return(ENODEV); 116 unit = strtol(dname, &dname, 10); 117 if (*dname != 's') 118 return(ENODEV); 119 ++dname; 120 121 /* 122 * Convert slice number to value suitable for 123 * dkmakeminor(). 0->0, 1->2, 2->3, etc. 124 */ 125 slice = strtol(dname, &dname, 10); 126 if (slice > 0) 127 ++slice; 128 129 if (*dname < 'a' || *dname > 'p') 130 return ENODEV; 131 132 part = *dname - 'a'; 133 devminor = dkmakeminor(unit, slice, part); 134 135 /* 136 * Disallow partition c 137 */ 138 if (part == 2) 139 return ENOTTY; /* not buying that */ 140 141 drive->dev = udev2dev(makeudev(devmajor, devminor), 0); 142 143 if (drive->dev == NULL) 144 return ENODEV; 145 146 drive->dev->si_iosize_max = DFLTPHYS; 147 if (dev_is_good(drive->dev)) 148 drive->lasterror = dev_dopen(drive->dev, FWRITE, 0, proc0.p_ucred); 149 else 150 drive->lasterror = ENOENT; 151 152 if (drive->lasterror != 0) { /* failed */ 153 drive->state = drive_down; /* just force it down */ 154 if (verbose) 155 log(LOG_WARNING, 156 "vinum open_drive %s: failed with error %d\n", 157 drive->devicename, drive->lasterror); 158 } else 159 drive->flags |= VF_OPEN; /* we're open now */ 160 161 return drive->lasterror; 162 } 163 164 /* 165 * Set some variables in the drive struct 166 * in more convenient form. Return error indication 167 */ 168 int 169 set_drive_parms(struct drive *drive) 170 { 171 drive->blocksize = BLKDEV_IOSIZE; /* do we need this? */ 172 drive->secsperblock = drive->blocksize /* number of sectors per block */ 173 / drive->partinfo.media_blksize; 174 175 /* Now update the label part */ 176 bcopy(hostname, drive->label.sysname, VINUMHOSTNAMELEN); /* put in host name */ 177 getmicrotime(&drive->label.date_of_birth); /* and current time */ 178 drive->label.drive_size = drive->partinfo.media_size; 179 #if VINUMDEBUG 180 if (debug & DEBUG_BIGDRIVE) /* pretend we're 100 times as big */ 181 drive->label.drive_size *= 100; 182 #endif 183 184 /* number of sectors available for subdisks */ 185 drive->sectors_available = drive->label.drive_size / DEV_BSIZE - DATASTART; 186 187 /* 188 * Bug in 3.0 as of January 1998: you can open 189 * non-existent slices. They have a length of 0. 190 */ 191 if (drive->label.drive_size < MINVINUMSLICE) { /* too small to worry about */ 192 set_drive_state(drive->driveno, drive_down, setstate_force); 193 drive->lasterror = ENOSPC; 194 return ENOSPC; 195 } 196 drive->freelist_size = INITIAL_DRIVE_FREELIST; /* initial number of entries */ 197 drive->freelist = (struct drive_freelist *) 198 Malloc(INITIAL_DRIVE_FREELIST * sizeof(struct drive_freelist)); 199 if (drive->freelist == NULL) /* can't malloc, dammit */ 200 return ENOSPC; 201 drive->freelist_entries = 1; /* just (almost) the complete drive */ 202 drive->freelist[0].offset = DATASTART; /* starts here */ 203 drive->freelist[0].sectors = (drive->label.drive_size >> DEV_BSHIFT) - DATASTART; /* and it's this long */ 204 if (drive->label.name[0] != '\0') /* got a name */ 205 set_drive_state(drive->driveno, drive_up, setstate_force); /* our drive is accessible */ 206 else /* we know about it, but that's all */ 207 drive->state = drive_referenced; 208 return 0; 209 } 210 211 /* 212 * Initialize a drive: open the device and add device 213 * information 214 */ 215 int 216 init_drive(struct drive *drive, int verbose) 217 { 218 if (drive->devicename[0] != '/') { 219 drive->lasterror = EINVAL; 220 log(LOG_ERR, "vinum: Can't open drive without drive name\n"); 221 return EINVAL; 222 } 223 drive->lasterror = open_drive(drive, curproc, verbose); /* open the drive */ 224 if (drive->lasterror) 225 return drive->lasterror; 226 227 drive->lasterror = dev_dioctl( 228 drive->dev, 229 DIOCGPART, 230 (caddr_t) & drive->partinfo, 231 FREAD, 232 proc0.p_ucred); 233 if (drive->lasterror) { 234 if (verbose) 235 log(LOG_WARNING, 236 "vinum open_drive %s: Can't get partition information, drive->lasterror %d\n", 237 drive->devicename, 238 drive->lasterror); 239 close_drive(drive); 240 return drive->lasterror; 241 } 242 if (drive->partinfo.fstype != FS_VINUM && 243 !kuuid_is_vinum(&drive->partinfo.fstype_uuid) 244 ) { 245 drive->lasterror = EFTYPE; 246 if (verbose) 247 log(LOG_WARNING, 248 "vinum open_drive %s: Wrong partition type for vinum\n", 249 drive->devicename); 250 close_drive(drive); 251 return EFTYPE; 252 } 253 return set_drive_parms(drive); /* set various odds and ends */ 254 } 255 256 /* Close a drive if it's open. */ 257 void 258 close_drive(struct drive *drive) 259 { 260 LOCKDRIVE(drive); /* keep the daemon out */ 261 if (drive->flags & VF_OPEN) 262 close_locked_drive(drive); /* and close it */ 263 if (drive->state > drive_down) /* if it's up */ 264 drive->state = drive_down; /* make sure it's down */ 265 unlockdrive(drive); 266 } 267 268 /* 269 * Real drive close code, called with drive already locked. 270 * We have also checked that the drive is open. No errors. 271 */ 272 void 273 close_locked_drive(struct drive *drive) 274 { 275 /* 276 * If we can't access the drive, we can't flush 277 * the queues, which spec_close() will try to 278 * do. Get rid of them here first. 279 */ 280 drive->lasterror = dev_dclose(drive->dev, 0, 0); 281 drive->flags &= ~VF_OPEN; /* no longer open */ 282 } 283 284 /* 285 * Remove drive from the configuration. 286 * Caller must ensure that it isn't active. 287 */ 288 void 289 remove_drive(int driveno) 290 { 291 struct drive *drive = &vinum_conf.drive[driveno]; 292 struct vinum_hdr *vhdr; /* buffer for header */ 293 int error; 294 295 if (drive->state > drive_referenced) { /* real drive */ 296 if (drive->state == drive_up) { 297 vhdr = (struct vinum_hdr *) Malloc(VINUMHEADERLEN); /* allocate buffer */ 298 CHECKALLOC(vhdr, "Can't allocate memory"); 299 error = read_drive(drive, (void *) vhdr, VINUMHEADERLEN, VINUM_LABEL_OFFSET); 300 if (error) 301 drive->lasterror = error; 302 else { 303 vhdr->magic = VINUM_NOMAGIC; /* obliterate the magic, but leave the rest */ 304 write_drive(drive, (void *) vhdr, VINUMHEADERLEN, VINUM_LABEL_OFFSET); 305 } 306 Free(vhdr); 307 } 308 free_drive(drive); /* close it and free resources */ 309 save_config(); /* and save the updated configuration */ 310 } 311 } 312 313 /* 314 * Transfer drive data. Usually called from one of these defines; 315 * #define read_drive(a, b, c, d) driveio (a, b, c, d, BUF_CMD_READ) 316 * #define write_drive(a, b, c, d) driveio (a, b, c, d, BUF_CMD_WRITE) 317 * 318 * length and offset are in bytes, but must be multiples of sector 319 * size. The function *does not check* for this condition, and 320 * truncates ruthlessly. 321 * Return error number 322 */ 323 int 324 driveio(struct drive *drive, char *buf, size_t length, off_t offset, buf_cmd_t cmd) 325 { 326 int error; 327 struct buf *bp; 328 caddr_t saveaddr; 329 330 error = 0; /* to keep the compiler happy */ 331 while (length) { /* divide into small enough blocks */ 332 int len = min(length, MAXBSIZE); /* maximum block device transfer is MAXBSIZE */ 333 334 bp = geteblk(len); /* get a buffer header */ 335 bp->b_cmd = cmd; 336 bp->b_bio1.bio_offset = offset; /* disk offset */ 337 saveaddr = bp->b_data; 338 bp->b_data = buf; 339 bp->b_bcount = len; 340 dev_dstrategy(drive->dev, &bp->b_bio1); 341 error = biowait(bp); 342 bp->b_data = saveaddr; 343 bp->b_flags |= B_INVAL | B_AGE; 344 bp->b_flags &= ~B_ERROR; 345 brelse(bp); 346 if (error) 347 break; 348 length -= len; /* update pointers */ 349 buf += len; 350 offset += len; 351 } 352 return error; 353 } 354 355 /* 356 * Check a drive for a vinum header. If found, 357 * update the drive information. We come here 358 * with a partially populated drive structure 359 * which includes the device name. 360 * 361 * Return information on what we found. 362 * 363 * This function is called from two places: check_drive, 364 * which wants to find out whether the drive is a 365 * Vinum drive, and config_drive, which asserts that 366 * it is a vinum drive. In the first case, we don't 367 * print error messages (verbose==0), in the second 368 * we do (verbose==1). 369 */ 370 enum drive_label_info 371 read_drive_label(struct drive *drive, int verbose) 372 { 373 int error; 374 int result; /* result of our search */ 375 struct vinum_hdr *vhdr; /* and as header */ 376 377 error = init_drive(drive, 0); /* find the drive */ 378 if (error) /* find the drive */ 379 return DL_CANT_OPEN; /* not ours */ 380 381 vhdr = (struct vinum_hdr *) Malloc(VINUMHEADERLEN); /* allocate buffers */ 382 CHECKALLOC(vhdr, "Can't allocate memory"); 383 384 drive->state = drive_up; /* be optimistic */ 385 error = read_drive(drive, (void *) vhdr, VINUMHEADERLEN, VINUM_LABEL_OFFSET); 386 if (vhdr->magic == VINUM_MAGIC) { /* ours! */ 387 if (drive->label.name[0] /* we have a name for this drive */ 388 &&(strcmp(drive->label.name, vhdr->label.name))) { /* but it doesn't match the real name */ 389 drive->lasterror = EINVAL; 390 result = DL_WRONG_DRIVE; /* it's the wrong drive */ 391 drive->state = drive_unallocated; /* put it back, it's not ours */ 392 } else 393 result = DL_OURS; 394 /* 395 * We copy the drive anyway so that we have 396 * the correct name in the drive info. This 397 * may not be the name specified 398 */ 399 drive->label = vhdr->label; /* put in the label information */ 400 } else if (vhdr->magic == VINUM_NOMAGIC) /* was ours, but we gave it away */ 401 result = DL_DELETED_LABEL; /* and return the info */ 402 else 403 result = DL_NOT_OURS; /* we could have it, but we don't yet */ 404 Free(vhdr); /* that's all. */ 405 return result; 406 } 407 408 /* 409 * Check a drive for a vinum header. If found, 410 * read configuration information from the drive and 411 * incorporate the data into the configuration. 412 * 413 * Return drive number. 414 */ 415 struct drive * 416 check_drive(char *devicename) 417 { 418 int driveno; 419 int i; 420 struct drive *drive; 421 422 driveno = find_drive_by_dev(devicename, 1); /* if entry doesn't exist, create it */ 423 drive = &vinum_conf.drive[driveno]; /* and get a pointer */ 424 425 if (read_drive_label(drive, 0) == DL_OURS) { /* one of ours */ 426 for (i = 0; i < vinum_conf.drives_allocated; i++) { /* see if the name already exists */ 427 if ((i != driveno) /* not this drive */ 428 &&(DRIVE[i].state != drive_unallocated) /* and it's allocated */ 429 &&(strcmp(DRIVE[i].label.name, 430 DRIVE[driveno].label.name) == 0)) { /* and it has the same name */ 431 struct drive *mydrive = &DRIVE[i]; 432 433 if (mydrive->devicename[0] == '/') { /* we know a device name for it */ 434 /* 435 * set an error, but don't take the 436 * drive down: that would cause unneeded 437 * error messages. 438 */ 439 drive->lasterror = EEXIST; 440 break; 441 } else { /* it's just a place holder, */ 442 int sdno; 443 444 for (sdno = 0; sdno < vinum_conf.subdisks_allocated; sdno++) { /* look at each subdisk */ 445 if ((SD[sdno].driveno == i) /* it's pointing to this one, */ 446 &&(SD[sdno].state != sd_unallocated)) { /* and it's a real subdisk */ 447 SD[sdno].driveno = drive->driveno; /* point to the one we found */ 448 update_sd_state(sdno); /* and update its state */ 449 } 450 } 451 bzero(mydrive, sizeof(struct drive)); /* don't deallocate it, just remove it */ 452 } 453 } 454 } 455 } else { 456 if (drive->lasterror == 0) 457 drive->lasterror = ENODEV; 458 close_drive(drive); 459 drive->state = drive_down; 460 } 461 return drive; 462 } 463 464 static char * 465 sappend(char *txt, char *s) 466 { 467 while ((*s++ = *txt++) != 0); 468 return s - 1; 469 } 470 471 void 472 format_config(char *config, int len) 473 { 474 int i; 475 int j; 476 char *s = config; 477 char *configend = &config[len]; 478 479 bzero(config, len); 480 481 /* First write the volume configuration */ 482 for (i = 0; i < vinum_conf.volumes_allocated; i++) { 483 struct volume *vol; 484 485 vol = &vinum_conf.volume[i]; 486 if ((vol->state > volume_uninit) 487 && (vol->name[0] != '\0')) { /* paranoia */ 488 ksnprintf(s, 489 configend - s, 490 "volume %s state %s", 491 vol->name, 492 volume_state(vol->state)); 493 while (*s) 494 s++; /* find the end */ 495 if (vol->preferred_plex >= 0) /* preferences, */ 496 ksnprintf(s, 497 configend - s, 498 " readpol prefer %s", 499 vinum_conf.plex[vol->preferred_plex].name); 500 while (*s) 501 s++; /* find the end */ 502 s = sappend("\n", s); 503 } 504 } 505 506 /* Then the plex configuration */ 507 for (i = 0; i < vinum_conf.plexes_allocated; i++) { 508 struct plex *plex; 509 510 plex = &vinum_conf.plex[i]; 511 if ((plex->state > plex_referenced) 512 && (plex->name[0] != '\0')) { /* paranoia */ 513 ksnprintf(s, 514 configend - s, 515 "plex name %s state %s org %s ", 516 plex->name, 517 plex_state(plex->state), 518 plex_org(plex->organization)); 519 while (*s) 520 s++; /* find the end */ 521 if (isstriped(plex)) { 522 ksnprintf(s, 523 configend - s, 524 "%ds ", 525 (int) plex->stripesize); 526 while (*s) 527 s++; /* find the end */ 528 } 529 if (plex->volno >= 0) /* we have a volume */ 530 ksnprintf(s, 531 configend - s, 532 "vol %s ", 533 vinum_conf.volume[plex->volno].name); 534 while (*s) 535 s++; /* find the end */ 536 for (j = 0; j < plex->subdisks; j++) { 537 ksnprintf(s, 538 configend - s, 539 " sd %s", 540 vinum_conf.sd[plex->sdnos[j]].name); 541 } 542 s = sappend("\n", s); 543 } 544 } 545 546 /* And finally the subdisk configuration */ 547 for (i = 0; i < vinum_conf.subdisks_allocated; i++) { 548 struct sd *sd; 549 char *drivename; 550 551 sd = &SD[i]; 552 if ((sd->state != sd_referenced) 553 && (sd->state != sd_unallocated) 554 && (sd->name[0] != '\0')) { /* paranoia */ 555 drivename = vinum_conf.drive[sd->driveno].label.name; 556 /* 557 * XXX We've seen cases of dead subdisks 558 * which don't have a drive. If we let them 559 * through here, the drive name is null, so 560 * they get the drive named 'plex'. 561 * 562 * This is a breakage limiter, not a fix. 563 */ 564 if (drivename[0] == '\0') 565 drivename = "*invalid*"; 566 ksnprintf(s, 567 configend - s, 568 "sd name %s drive %s plex %s len %llus driveoffset %llus state %s", 569 sd->name, 570 drivename, 571 vinum_conf.plex[sd->plexno].name, 572 (unsigned long long) sd->sectors, 573 (unsigned long long) sd->driveoffset, 574 sd_state(sd->state)); 575 while (*s) 576 s++; /* find the end */ 577 if (sd->plexno >= 0) 578 ksnprintf(s, 579 configend - s, 580 " plexoffset %llds", 581 (long long) sd->plexoffset); 582 else 583 ksnprintf(s, configend - s, " detached"); 584 while (*s) 585 s++; /* find the end */ 586 if (sd->flags & VF_RETRYERRORS) { 587 ksnprintf(s, configend - s, " retryerrors"); 588 while (*s) 589 s++; /* find the end */ 590 } 591 ksnprintf(s, configend - s, " \n"); 592 while (*s) 593 s++; /* find the end */ 594 } 595 } 596 if (s > &config[len - 2]) 597 panic("vinum: configuration data overflow"); 598 } 599 600 /* 601 * issue a save config request to the d�mon. The actual work 602 * is done in process context by daemon_save_config 603 */ 604 void 605 save_config(void) 606 { 607 queue_daemon_request(daemonrq_saveconfig, (union daemoninfo) NULL); 608 } 609 610 /* 611 * Write the configuration to all vinum slices. This 612 * is performed by the d�mon only 613 */ 614 void 615 daemon_save_config(void) 616 { 617 int error; 618 int written_config; /* set when we first write the config to disk */ 619 int driveno; 620 struct drive *drive; /* point to current drive info */ 621 struct vinum_hdr *vhdr; /* and as header */ 622 char *config; /* point to config data */ 623 int wlabel_on; /* to set writing label on/off */ 624 625 /* don't save the configuration while we're still working on it */ 626 if (vinum_conf.flags & VF_CONFIGURING) 627 return; 628 written_config = 0; /* no config written yet */ 629 /* Build a volume header */ 630 vhdr = (struct vinum_hdr *) Malloc(VINUMHEADERLEN); /* get space for the config data */ 631 CHECKALLOC(vhdr, "Can't allocate config data"); 632 vhdr->magic = VINUM_MAGIC; /* magic number */ 633 vhdr->config_length = MAXCONFIG; /* length of following config info */ 634 635 config = Malloc(MAXCONFIG); /* get space for the config data */ 636 CHECKALLOC(config, "Can't allocate config data"); 637 638 format_config(config, MAXCONFIG); 639 error = 0; /* no errors yet */ 640 for (driveno = 0; driveno < vinum_conf.drives_allocated; driveno++) { 641 drive = &vinum_conf.drive[driveno]; /* point to drive */ 642 if (drive->state > drive_referenced) { 643 LOCKDRIVE(drive); /* don't let it change */ 644 645 /* 646 * First, do some drive consistency checks. Some 647 * of these are kludges, others require a process 648 * context and couldn't be done before 649 */ 650 if ((drive->devicename[0] == '\0') 651 || (drive->label.name[0] == '\0')) { 652 unlockdrive(drive); 653 free_drive(drive); /* get rid of it */ 654 break; 655 } 656 if (((drive->flags & VF_OPEN) == 0) /* drive not open */ 657 &&(drive->state > drive_down)) { /* and it thinks it's not down */ 658 unlockdrive(drive); 659 set_drive_state(driveno, drive_down, setstate_force); /* tell it what's what */ 660 continue; 661 } 662 if ((drive->state == drive_down) /* it's down */ 663 &&(drive->flags & VF_OPEN)) { /* but open, */ 664 unlockdrive(drive); 665 close_drive(drive); /* close it */ 666 } else if (drive->state > drive_down) { 667 getmicrotime(&drive->label.last_update); /* time of last update is now */ 668 bcopy((char *) &drive->label, /* and the label info from the drive structure */ 669 (char *) &vhdr->label, 670 sizeof(vhdr->label)); 671 if ((drive->state != drive_unallocated) 672 && (drive->state != drive_referenced)) { /* and it's a real drive */ 673 wlabel_on = 1; /* enable writing the label */ 674 error = 0; 675 #if 1 676 error = dev_dioctl(drive->dev, /* make the label writeable */ 677 DIOCWLABEL, 678 (caddr_t) & wlabel_on, 679 FWRITE, 680 proc0.p_ucred); 681 #endif 682 if (error == 0) 683 error = write_drive(drive, (char *) vhdr, VINUMHEADERLEN, VINUM_LABEL_OFFSET); 684 if (error == 0) 685 error = write_drive(drive, config, MAXCONFIG, VINUM_CONFIG_OFFSET); /* first config copy */ 686 if (error == 0) 687 error = write_drive(drive, config, MAXCONFIG, VINUM_CONFIG_OFFSET + MAXCONFIG); /* second copy */ 688 wlabel_on = 0; /* enable writing the label */ 689 #if 1 690 if (error == 0) 691 error = dev_dioctl(drive->dev, /* make the label non-writeable again */ 692 DIOCWLABEL, 693 (caddr_t) & wlabel_on, 694 FWRITE, 695 proc0.p_ucred); 696 #endif 697 unlockdrive(drive); 698 if (error) { 699 log(LOG_ERR, 700 "vinum: Can't write config to %s, error %d\n", 701 drive->devicename, 702 error); 703 set_drive_state(drive->driveno, drive_down, setstate_force); 704 } else 705 written_config = 1; /* we've written it on at least one drive */ 706 } 707 } else /* not worth looking at, */ 708 unlockdrive(drive); /* just unlock it again */ 709 } 710 } 711 Free(vhdr); 712 Free(config); 713 } 714 715 /* Look at all disks on the system for vinum slices */ 716 int 717 vinum_scandisk(char *devicename[], int drives) 718 { 719 struct drive *volatile drive; 720 volatile int driveno; 721 int firstdrive; /* first drive in this list */ 722 volatile int gooddrives; /* number of usable drives found */ 723 int firsttime; /* set if we have never configured before */ 724 int error; 725 char *config_text; /* read the config info from disk into here */ 726 char *volatile cptr; /* pointer into config information */ 727 char *eptr; /* end pointer into config information */ 728 char *config_line; /* copy the config line to */ 729 volatile int status; 730 int *volatile drivelist; /* list of drive indices */ 731 #define DRIVENAMELEN 64 732 #define DRIVEPARTS 35 /* max partitions per drive, excluding c */ 733 char partname[DRIVENAMELEN]; /* for creating partition names */ 734 735 status = 0; /* success indication */ 736 vinum_conf.flags |= VF_READING_CONFIG; /* reading config from disk */ 737 738 gooddrives = 0; /* number of usable drives found */ 739 firstdrive = vinum_conf.drives_used; /* the first drive */ 740 firsttime = vinum_conf.drives_used == 0; /* are we a virgin? */ 741 742 /* allocate a drive pointer list */ 743 drivelist = (int *) Malloc(drives * DRIVEPARTS * sizeof(int)); 744 CHECKALLOC(drivelist, "Can't allocate memory"); 745 746 /* Open all drives and find which was modified most recently */ 747 for (driveno = 0; driveno < drives; driveno++) { 748 char part; /* UNIX partition */ 749 int slice; 750 int founddrive; /* flag when we find a vinum drive */ 751 int has_slice = 0; 752 int has_part = 0; 753 char *tmp; 754 755 founddrive = 0; /* no vinum drive found yet on this spindle */ 756 757 /* 758 * If the device path contains a slice we do not try to tack on 759 * another slice. If the device path has a partition we only check 760 * that partition. 761 */ 762 if ((tmp = rindex(devicename[driveno], '/')) == NULL) 763 tmp = devicename[driveno]; 764 while (*tmp && (*tmp < '0' || *tmp > '9')) 765 ++tmp; 766 while (*tmp && *tmp >= '0' && *tmp <= '9') 767 ++tmp; 768 if (*tmp == 's') 769 has_slice = strtol(tmp + 1, &tmp, 0); 770 if (*tmp >= 'a' && *tmp <= 'p') 771 has_part = *tmp; 772 773 /* 774 * Scan slices if no slice was specified, only if no partition was 775 * specified. 776 */ 777 if (has_slice == 0 && has_part == 0) 778 for (slice = 1; slice < 5; slice++) { 779 if (has_slice && slice != has_slice) 780 continue; 781 782 for (part = 'a'; part < 'a' + MAXPARTITIONS; part++) { 783 if (has_part && part != has_part) 784 continue; 785 if (part == 'c') 786 continue; 787 ksnprintf(partname, DRIVENAMELEN, 788 "%ss%d%c", devicename[driveno], slice, part); 789 drive = check_drive(partname); /* try to open it */ 790 if ((drive->lasterror != 0) /* didn't work, */ 791 ||(drive->state != drive_up)) 792 free_drive(drive); /* get rid of it */ 793 else if (drive->flags & VF_CONFIGURED) /* already read this config, */ 794 log(LOG_WARNING, 795 "vinum: already read config from %s\n", /* say so */ 796 drive->label.name); 797 else { 798 drivelist[gooddrives] = drive->driveno; /* keep the drive index */ 799 drive->flags &= ~VF_NEWBORN; /* which is no longer newly born */ 800 gooddrives++; 801 founddrive++; 802 } 803 } 804 } 805 if (founddrive == 0 && has_slice == 0) { /* didn't find anything, */ 806 for (part = 'a'; part < 'a' + MAXPARTITIONS; part++) { /* try the compatibility partition */ 807 if (has_part && has_part != part) 808 continue; 809 if (part == 'c') 810 continue; 811 if (has_part) { 812 ksnprintf(partname, DRIVENAMELEN, 813 "%s", devicename[driveno]); 814 } else { 815 ksnprintf(partname, DRIVENAMELEN, 816 "%s%c", devicename[driveno], part); 817 } 818 drive = check_drive(partname); /* try to open it */ 819 if ((drive->lasterror != 0) /* didn't work, */ 820 ||(drive->state != drive_up)) 821 free_drive(drive); /* get rid of it */ 822 else if (drive->flags & VF_CONFIGURED) /* already read this config, */ 823 log(LOG_WARNING, 824 "vinum: already read config from %s\n", /* say so */ 825 drive->label.name); 826 else { 827 drivelist[gooddrives] = drive->driveno; /* keep the drive index */ 828 drive->flags &= ~VF_NEWBORN; /* which is no longer newly born */ 829 gooddrives++; 830 } 831 } 832 } 833 } 834 835 if (gooddrives == 0) { 836 if (firsttime) 837 log(LOG_WARNING, "vinum: no drives found\n"); 838 else 839 log(LOG_INFO, "vinum: no additional drives found\n"); 840 return ENOENT; 841 } 842 /* 843 * We now have at least one drive 844 * open. Sort them in order of config time 845 * and merge the config info with what we 846 * have already. 847 */ 848 kqsort(drivelist, gooddrives, sizeof(int), drivecmp); 849 config_text = (char *) Malloc(MAXCONFIG * 2); /* allocate buffers */ 850 CHECKALLOC(config_text, "Can't allocate memory"); 851 config_line = (char *) Malloc(MAXCONFIGLINE * 2); /* allocate buffers */ 852 CHECKALLOC(config_line, "Can't allocate memory"); 853 for (driveno = 0; driveno < gooddrives; driveno++) { /* now include the config */ 854 drive = &DRIVE[drivelist[driveno]]; /* point to the drive */ 855 856 if (firsttime && (driveno == 0)) /* we've never configured before, */ 857 log(LOG_INFO, "vinum: reading configuration from %s\n", drive->devicename); 858 else 859 log(LOG_INFO, "vinum: updating configuration from %s\n", drive->devicename); 860 861 if (drive->state == drive_up) 862 /* Read in both copies of the configuration information */ 863 error = read_drive(drive, config_text, MAXCONFIG * 2, VINUM_CONFIG_OFFSET); 864 else { 865 error = EIO; 866 kprintf("vinum_scandisk: %s is %s\n", drive->devicename, drive_state(drive->state)); 867 } 868 869 if (error != 0) { 870 log(LOG_ERR, "vinum: Can't read device %s, error %d\n", drive->devicename, error); 871 free_drive(drive); /* give it back */ 872 status = error; 873 } 874 /* 875 * At this point, check that the two copies 876 * are the same, and do something useful if 877 * not. In particular, consider which is 878 * newer, and what this means for the 879 * integrity of the data on the drive. 880 */ 881 else { 882 vinum_conf.drives_used++; /* another drive in use */ 883 /* Parse the configuration, and add it to the global configuration */ 884 for (cptr = config_text; *cptr != '\0';) { /* love this style(9) */ 885 volatile int parse_status; /* return value from parse_config */ 886 887 for (eptr = config_line; (*cptr != '\n') && (*cptr != '\0');) /* until the end of the line */ 888 *eptr++ = *cptr++; 889 *eptr = '\0'; /* and delimit */ 890 if (setjmp(command_fail) == 0) { /* come back here on error and continue */ 891 parse_status = parse_config(config_line, &keyword_set, 1); /* parse the config line */ 892 if (parse_status < 0) { /* error in config */ 893 /* 894 * This config should have been parsed in user 895 * space. If we run into problems here, something 896 * serious is afoot. Complain and let the user 897 * snarf the config to see what's wrong. 898 */ 899 log(LOG_ERR, 900 "vinum: Config error on %s, aborting integration\n", 901 drive->devicename); 902 free_drive(drive); /* give it back */ 903 status = EINVAL; 904 } 905 } 906 while (*cptr == '\n') 907 cptr++; /* skip to next line */ 908 } 909 } 910 drive->flags |= VF_CONFIGURED; /* read this drive's configuration */ 911 } 912 913 Free(config_line); 914 Free(config_text); 915 Free(drivelist); 916 vinum_conf.flags &= ~VF_READING_CONFIG; /* no longer reading from disk */ 917 if (status != 0) 918 kprintf("vinum: couldn't read configuration"); 919 else 920 updateconfig(VF_READING_CONFIG); /* update from disk config */ 921 return status; 922 } 923 924 /* 925 * Compare the modification dates of the drives, for qsort. 926 * Return 1 if a < b, 0 if a == b, 01 if a > b: in other 927 * words, sort backwards. 928 */ 929 int 930 drivecmp(const void *va, const void *vb) 931 { 932 const struct drive *a = &DRIVE[*(const int *) va]; 933 const struct drive *b = &DRIVE[*(const int *) vb]; 934 935 if ((a->label.last_update.tv_sec == b->label.last_update.tv_sec) 936 && (a->label.last_update.tv_usec == b->label.last_update.tv_usec)) 937 return 0; 938 else if ((a->label.last_update.tv_sec > b->label.last_update.tv_sec) 939 || ((a->label.last_update.tv_sec == b->label.last_update.tv_sec) 940 && (a->label.last_update.tv_usec > b->label.last_update.tv_usec))) 941 return -1; 942 else 943 return 1; 944 } 945 /* Local Variables: */ 946 /* fill-column: 50 */ 947 /* End: */ 948