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