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