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: vinumconfig.c,v 1.41 2003/05/23 00:57:34 grog Exp grog $
37 */
38
39 #include <sys/cdefs.h>
40 __FBSDID("$FreeBSD$");
41
42 #define STATIC static
43
44 #include <dev/vinum/vinumhdr.h>
45 #include <dev/vinum/request.h>
46
47 #define MAXTOKEN 64 /* maximum number of tokens in a line */
48
49 /*
50 * We can afford the luxury of global variables here,
51 * since start_config ensures that these functions
52 * are single-threaded.
53 */
54
55 /* These are indices in vinum_conf of the last-mentioned of each kind of object */
56 static int current_drive; /* note the last drive we mention, for
57 * some defaults */
58 static int current_plex; /* and the same for the last plex */
59 static int current_volume; /* and the last volme */
60 static struct _ioctl_reply *ioctl_reply; /* struct to return via ioctl */
61
62
63 /* These values are used by most of these routines, so set them as globals */
64 static char *token[MAXTOKEN]; /* pointers to individual tokens */
65 static int tokens; /* number of tokens */
66
67 #define TOCONS 0x01
68 #define TOTTY 0x02
69 #define TOLOG 0x04
70
71 struct putchar_arg {
72 int flags;
73 struct tty *tty;
74 };
75
76 #define MSG_MAX 1024 /* maximum length of a formatted message */
77 /*
78 * Format an error message and return to the user
79 * in the reply. CARE: This routine is designed
80 * to be called only from the configuration
81 * routines, so it assumes it's the owner of the
82 * configuration lock, and unlocks it on exit.
83 */
84 void
85 throw_rude_remark(int error, char *msg,...)
86 {
87 int retval;
88 va_list ap;
89 char *text;
90 static int finishing; /* don't recurse */
91 int was_finishing;
92
93 if ((vinum_conf.flags & VF_LOCKED) == 0) /* bug catcher */
94 panic("throw_rude_remark: called without config lock");
95 va_start(ap, msg);
96 if ((ioctl_reply != NULL) /* we're called from the user */
97 &&(!(vinum_conf.flags & VF_READING_CONFIG))) { /* and not reading from disk: return msg */
98 /*
99 * We can't just format to ioctl_reply, since it
100 * may contain our input parameters
101 */
102 text = Malloc(MSG_MAX);
103 if (text == NULL) {
104 log(LOG_ERR, "vinum: can't allocate error message buffer\n");
105 printf("vinum: ");
106 vprintf(msg, ap); /* print to the console */
107 printf("\n");
108 } else {
109 retval = kvprintf(msg, NULL, (void *) text, 10, ap);
110 text[retval] = '\0'; /* delimit */
111 strlcpy(ioctl_reply->msg, text, sizeof(ioctl_reply->msg));
112 ioctl_reply->error = error; /* first byte is the error number */
113 Free(text);
114 }
115 } else {
116 printf("vinum: ");
117 vprintf(msg, ap); /* print to the console */
118 printf("\n");
119 }
120 va_end(ap);
121
122 if (vinum_conf.flags & VF_READING_CONFIG) { /* go through to the bitter end, */
123 if ((vinum_conf.flags & VF_READING_CONFIG) /* we're reading from disk, */
124 &&((daemon_options & daemon_noupdate) == 0)) {
125 log(LOG_NOTICE, "Disabling configuration updates\n");
126 daemon_options |= daemon_noupdate;
127 }
128 return;
129 }
130 /*
131 * We have a problem here: we want to unlock the
132 * configuration, which implies tidying up, but
133 * if we find an error while tidying up, we
134 * could recurse for ever. Use this kludge to
135 * only try once.
136 */
137 was_finishing = finishing;
138 finishing = 1;
139 finish_config(was_finishing); /* unlock anything we may be holding */
140 finishing = was_finishing;
141 longjmp(command_fail, error);
142 }
143
144 /*
145 * Check a volume to see if the plex is already assigned to it.
146 * Return index in volume->plex, or -1 if not assigned
147 */
148 int
149 my_plex(int volno, int plexno)
150 {
151 int i;
152 struct volume *vol;
153
154 vol = &VOL[volno]; /* point to volno */
155 for (i = 0; i < vol->plexes; i++)
156 if (vol->plex[i] == plexno)
157 return i;
158 return -1; /* not found */
159 }
160
161 /*
162 * Check a plex to see if the subdisk is already assigned to it.
163 * Return index in plex->sd, or -1 if not assigned
164 */
165 int
166 my_sd(int plexno, int sdno)
167 {
168 int i;
169 struct plex *plex;
170
171 plex = &PLEX[plexno];
172 for (i = 0; i < plex->subdisks; i++)
173 if (plex->sdnos[i] == sdno)
174 return i;
175 return -1; /* not found */
176 }
177
178 /* Add plex to the volume if possible */
179 int
180 give_plex_to_volume(int volno, int plexno, int preferme)
181 {
182 struct volume *vol;
183 int i;
184 int volplexno;
185
186 /*
187 * It's not an error for the plex to already
188 * belong to the volume, but we need to check a
189 * number of things to make sure it's done right.
190 * Some day.
191 */
192 volplexno = my_plex(volno, plexno);
193 vol = &VOL[volno]; /* point to volume */
194 if (volplexno < 0) {
195 if (vol->plexes == MAXPLEX) /* all plexes allocated */
196 throw_rude_remark(ENOSPC,
197 "Too many plexes for volume %s",
198 vol->name);
199 else if ((vol->plexes > 0) /* we have other plexes */
200 &&((vol->flags & VF_CONFIG_SETUPSTATE) == 0)) /* and we're not setting up state */
201 invalidate_subdisks(&PLEX[plexno], sd_stale); /* make our subdisks invalid */
202 vol->plex[vol->plexes] = plexno; /* this one */
203 vol->plexes++; /* add another plex */
204 PLEX[plexno].volno = volno; /* note the number of our volume */
205
206 /* Find out how big our volume is */
207 for (i = 0; i < vol->plexes; i++)
208 vol->size = max(vol->size, PLEX[vol->plex[i]].length);
209 volplexno = vol->plexes - 1; /* number of plex in volume */
210 }
211 if (preferme) {
212 if (vol->preferred_plex >= 0) /* already had a facourite, */
213 printf("vinum: changing preferred plex for %s from %s to %s\n",
214 vol->name,
215 PLEX[vol->plex[vol->preferred_plex]].name,
216 PLEX[plexno].name);
217 vol->preferred_plex = volplexno;
218 }
219 return volplexno;
220 }
221
222 /*
223 * Add subdisk to a plex if possible
224 */
225 int
226 give_sd_to_plex(int plexno, int sdno)
227 {
228 int i;
229 struct plex *plex;
230 struct sd *sd;
231
232 /*
233 * It's not an error for the sd to already
234 * belong to the plex, but we need to check a
235 * number of things to make sure it's done right.
236 * Some day.
237 */
238 i = my_sd(plexno, sdno);
239 if (i >= 0) /* does it already belong to us? */
240 return i; /* that's it */
241
242 plex = &PLEX[plexno]; /* point to the plex */
243 sd = &SD[sdno]; /* and the subdisk */
244
245 /* Do we have an offset? Otherwise put it after the last one */
246 if (sd->plexoffset < 0) { /* no offset specified */
247 if (plex->subdisks > 0) {
248 struct sd *lastsd = &SD[plex->sdnos[plex->subdisks - 1]]; /* last subdisk */
249
250 if (plex->organization == plex_concat) /* concat, */
251 sd->plexoffset = lastsd->sectors + lastsd->plexoffset; /* starts here */
252 else /* striped, RAID-4 or RAID-5 */
253 sd->plexoffset = plex->stripesize * plex->subdisks; /* starts here */
254 } else /* first subdisk */
255 sd->plexoffset = 0; /* start at the beginning */
256 }
257 if (plex->subdisks == MAXSD) { /* we already have our maximum */
258 if (sd->state == sd_unallocated) /* haven't finished allocating the sd, */
259 free_sd(sdno); /* free it to return drive space */
260 throw_rude_remark(ENOSPC, /* crap out */
261 "Can't add %s to %s: plex full",
262 sd->name,
263 plex->name);
264 }
265 plex->subdisks++; /* another entry */
266 if (plex->subdisks >= plex->subdisks_allocated) /* need more space */
267 EXPAND(plex->sdnos, int, plex->subdisks_allocated, INITIAL_SUBDISKS_IN_PLEX);
268
269 /* Adjust size of plex and volume. */
270 if (isparity(plex)) /* RAID-4 or RAID-5 */
271 plex->length = (plex->subdisks - 1) * sd->sectors; /* size is one disk short */
272 else
273 plex->length += sd->sectors; /* plex gets this much bigger */
274 if (plex->volno >= 0) /* we have a volume */
275 VOL[plex->volno].size = max(VOL[plex->volno].size, plex->length); /* adjust its size */
276
277 /*
278 * We need to check that the subdisks don't overlap,
279 * but we can't do that until a point where we *must*
280 * know the size of all the subdisks. That's not
281 * here. But we need to sort them by offset
282 */
283 for (i = 0; i < plex->subdisks - 1; i++) {
284 if (sd->plexoffset < SD[plex->sdnos[i]].plexoffset) { /* it fits before this one */
285 /* First move any remaining subdisks by one */
286 int j;
287
288 for (j = plex->subdisks - 1; j > i; j--) /* move up one at a time */
289 plex->sdnos[j] = plex->sdnos[j - 1];
290 plex->sdnos[i] = sdno;
291 sd->plexsdno = i; /* note where we are in the subdisk */
292 return i;
293 }
294 }
295
296 /*
297 * The plex doesn't have any subdisk with a
298 * larger offset. Insert it here.
299 */
300 plex->sdnos[i] = sdno;
301 sd->plexsdno = i; /* note where we are in the subdisk */
302 sd->plexno = plex->plexno; /* and who we belong to */
303 return i;
304 }
305
306 /*
307 * Add a subdisk to drive if possible. The
308 * pointer to the drive must already be stored in
309 * the sd structure, but the drive doesn't know
310 * about the subdisk yet.
311 */
312 void
313 give_sd_to_drive(int sdno)
314 {
315 struct sd *sd; /* pointer to subdisk */
316 struct drive *drive; /* and drive */
317 int fe; /* index in free list */
318 int sfe; /* and index of subdisk when assigning max */
319
320 sd = &SD[sdno]; /* point to sd */
321 drive = &DRIVE[sd->driveno]; /* and drive */
322
323 if (drive->state != drive_up) {
324 update_sd_state(sdno); /* that crashes the subdisk */
325 return;
326 }
327 sd->sectorsize = drive->sectorsize; /* get sector size from drive */
328 if (drive->flags & VF_HOTSPARE) /* the drive is a hot spare, */
329 throw_rude_remark(ENOSPC,
330 "Can't place %s on hot spare drive %s",
331 sd->name,
332 drive->label.name);
333 if ((drive->sectors_available == 0) /* no space left */
334 ||(sd->sectors > drive->sectors_available)) { /* or too big, */
335 sd->driveoffset = -1; /* don't be confusing */
336 free_sd(sd->sdno);
337 throw_rude_remark(ENOSPC, "No space for %s on %s", sd->name, drive->label.name);
338 return; /* in case we come back here */
339 }
340 drive->subdisks_used++; /* one more subdisk */
341
342 if (sd->sectors == 0) { /* take the largest chunk */
343 sfe = 0; /* to keep the compiler happy */
344 for (fe = 0; fe < drive->freelist_entries; fe++) {
345 if (drive->freelist[fe].sectors >= sd->sectors) { /* more space here */
346 sd->sectors = drive->freelist[fe].sectors; /* take it */
347 sd->driveoffset = drive->freelist[fe].offset;
348 sfe = fe; /* and note the index for later */
349 }
350 }
351 if (sd->sectors == 0) { /* no luck, */
352 sd->driveoffset = -1; /* don't be confusing */
353 free_sd(sd->sdno);
354 throw_rude_remark(ENOSPC, /* give up */
355 "No space for %s on %s",
356 sd->name,
357 drive->label.name);
358 }
359 if (sfe < (drive->freelist_entries - 1)) /* not the last one, */
360 bcopy(&drive->freelist[sfe + 1],
361 &drive->freelist[sfe],
362 (drive->freelist_entries - sfe) * sizeof(struct drive_freelist));
363 drive->freelist_entries--; /* one less entry */
364 drive->sectors_available -= sd->sectors; /* and note how much less space we have */
365 } else if (sd->driveoffset < 0) { /* no offset specified, find one */
366 for (fe = 0; fe < drive->freelist_entries; fe++) {
367 if (drive->freelist[fe].sectors >= sd->sectors) { /* it'll fit here */
368 sd->driveoffset = drive->freelist[fe].offset;
369 if (sd->sectors == drive->freelist[fe].sectors) { /* used up the entire entry */
370 if (fe < (drive->freelist_entries - 1)) /* not the last one, */
371 bcopy(&drive->freelist[fe + 1],
372 &drive->freelist[fe],
373 (drive->freelist_entries - fe) * sizeof(struct drive_freelist));
374 drive->freelist_entries--; /* one less entry */
375 } else {
376 drive->freelist[fe].sectors -= sd->sectors; /* this much less space */
377 drive->freelist[fe].offset += sd->sectors; /* this much further on */
378 }
379 drive->sectors_available -= sd->sectors; /* and note how much less space we have */
380 break;
381 }
382 }
383 if (sd->driveoffset < 0)
384 /*
385 * Didn't find anything. Although the drive has
386 * enough space, it's too fragmented
387 */
388 {
389 free_sd(sd->sdno);
390 throw_rude_remark(ENOSPC, "No space for %s on %s", sd->name, drive->label.name);
391 }
392 } else { /* specific offset */
393 /*
394 * For a specific offset to work, the space must be
395 * entirely in a single freelist entry. Look for it.
396 */
397 u_int64_t sdend = sd->driveoffset + sd->sectors; /* end of our subdisk */
398 for (fe = 0; fe < drive->freelist_entries; fe++) {
399 u_int64_t dend = drive->freelist[fe].offset + drive->freelist[fe].sectors; /* end of entry */
400 if (dend >= sdend) { /* fits before here */
401 if (drive->freelist[fe].offset > sd->driveoffset) { /* starts after the beginning of sd area */
402 sd->driveoffset = -1; /* don't be confusing */
403 set_sd_state(sd->sdno, sd_down, setstate_force);
404 throw_rude_remark(ENOSPC,
405 "No space for %s on drive %s at offset %lld",
406 sd->name,
407 drive->label.name,
408 sd->driveoffset);
409 return;
410 }
411 /*
412 * We've found the space, and we can allocate it.
413 * We don't need to say that to the subdisk, which
414 * already knows about it. We need to tell it to
415 * the free list, though. We have four possibilities:
416 *
417 * 1. The subdisk exactly eats up the entry. That's the
418 * same as above.
419 * 2. The subdisk starts at the beginning and leaves space
420 * at the end.
421 * 3. The subdisk starts after the beginning and leaves
422 * space at the end as well: we end up with another
423 * fragment.
424 * 4. The subdisk leaves space at the beginning and finishes
425 * at the end.
426 */
427 drive->sectors_available -= sd->sectors; /* note how much less space we have */
428 if (sd->driveoffset == drive->freelist[fe].offset) { /* 1 or 2 */
429 if (sd->sectors == drive->freelist[fe].sectors) { /* 1: used up the entire entry */
430 if (fe < (drive->freelist_entries - 1)) /* not the last one, */
431 bcopy(&drive->freelist[fe + 1],
432 &drive->freelist[fe],
433 (drive->freelist_entries - fe) * sizeof(struct drive_freelist));
434 drive->freelist_entries--; /* one less entry */
435 } else { /* 2: space at the end */
436 drive->freelist[fe].sectors -= sd->sectors; /* this much less space */
437 drive->freelist[fe].offset += sd->sectors; /* this much further on */
438 }
439 } else { /* 3 or 4 */
440 drive->freelist[fe].sectors = sd->driveoffset - drive->freelist[fe].offset;
441 if (dend > sdend) { /* 3: space at the end as well */
442 if (fe < (drive->freelist_entries - 1)) /* not the last one */
443 bcopy(&drive->freelist[fe], /* move the rest down */
444 &drive->freelist[fe + 1],
445 (drive->freelist_entries - fe) * sizeof(struct drive_freelist));
446 drive->freelist_entries++; /* one less entry */
447 drive->freelist[fe + 1].offset = sdend; /* second entry starts after sd */
448 drive->freelist[fe + 1].sectors = dend - sdend; /* and is this long */
449 }
450 }
451 break;
452 }
453 }
454 }
455 drive->opencount++; /* one more subdisk attached */
456 }
457
458 /* Get an empty drive entry from the drive table */
459 int
460 get_empty_drive(void)
461 {
462 int driveno;
463 struct drive *drive;
464
465 /* first see if we have one which has been deallocated */
466 for (driveno = 0; driveno < vinum_conf.drives_allocated; driveno++) {
467 if (DRIVE[driveno].state == drive_unallocated) /* bingo */
468 break;
469 }
470
471 if (driveno >= vinum_conf.drives_allocated) /* we've used all our allocation */
472 EXPAND(DRIVE, struct drive, vinum_conf.drives_allocated, INITIAL_DRIVES);
473
474 /* got a drive entry. Make it pretty */
475 drive = &DRIVE[driveno];
476 bzero(drive, sizeof(struct drive));
477 drive->driveno = driveno; /* put number in structure */
478 drive->flags |= VF_NEWBORN; /* newly born drive */
479 drive->dev = NULL;
480 strcpy(drive->devicename, "unknown"); /* and make the name ``unknown'' */
481 return driveno; /* return the index */
482 }
483
484 /*
485 * Find the named drive in vinum_conf.drive,
486 * return the index in vinum_conf.drive.
487 * Don't mark the drive as allocated (XXX SMP)
488 * If create != 0, create an entry if it doesn't exist
489 */
490 /* XXX check if we have it open from attach */
491 int
492 find_drive(const char *name, int create)
493 {
494 int driveno;
495 struct drive *drive;
496
497 if (name != NULL) {
498 for (driveno = 0; driveno < vinum_conf.drives_allocated; driveno++) {
499 drive = &DRIVE[driveno]; /* point to drive */
500 if ((drive->label.name[0] != '\0') /* it has a name */
501 &&(strcmp(drive->label.name, name) == 0) /* and it's this one */
502 &&(drive->state > drive_unallocated)) /* and it's a real one: found */
503 return driveno;
504 }
505 }
506 /* the drive isn't in the list. Add it if he wants */
507 if (create == 0) /* don't want to create */
508 return -1; /* give up */
509
510 driveno = get_empty_drive();
511 drive = &DRIVE[driveno];
512 if (name != NULL)
513 strlcpy(drive->label.name, /* put in its name */
514 name,
515 sizeof(drive->label.name));
516 drive->state = drive_referenced; /* in use, nothing worthwhile there */
517 return driveno; /* return the index */
518 }
519
520 /*
521 * Find a drive given its device name.
522 * devname must be valid.
523 * Otherwise the same as find_drive above.
524 */
525 int
526 find_drive_by_name(const char *devname, int create)
527 {
528 int driveno;
529 struct drive *drive;
530
531 for (driveno = 0; driveno < vinum_conf.drives_allocated; driveno++) {
532 drive = &DRIVE[driveno]; /* point to drive */
533 if ((strcmp(drive->devicename, devname) == 0) /* it's this device */
534 &&(drive->state > drive_unallocated)) /* and it's a real one: found */
535 return driveno;
536 }
537
538 /* the drive isn't in the list. Add it if he wants */
539 if (create == 0) /* don't want to create */
540 return -1; /* give up */
541
542 driveno = get_empty_drive();
543 drive = &DRIVE[driveno];
544 bcopy(devname, /* put in its name */
545 drive->devicename,
546 min(sizeof(drive->devicename),
547 strlen(devname)));
548 drive->state = drive_referenced; /* in use, nothing worthwhile there */
549 return driveno; /* return the index */
550 }
551
552 /* Find an empty subdisk in the subdisk table */
553 int
554 get_empty_sd(void)
555 {
556 int sdno;
557 struct sd *sd;
558
559 /* first see if we have one which has been deallocated */
560 for (sdno = 0; sdno < vinum_conf.subdisks_allocated; sdno++) {
561 if (SD[sdno].state == sd_unallocated) /* bingo */
562 break;
563 }
564 if (sdno >= vinum_conf.subdisks_allocated)
565 /*
566 * We've run out of space. sdno is pointing
567 * where we want it, but at the moment we
568 * don't have the space. Get it.
569 *
570 * XXX We should check for overflow here. We
571 * shouldn't allocate more than VINUM_MAXSD
572 * subdisks (currently at least a quarter of a
573 * million).
574 */
575 EXPAND(SD, struct sd, vinum_conf.subdisks_allocated, INITIAL_SUBDISKS);
576
577 /* initialize some things */
578 sd = &SD[sdno]; /* point to it */
579 bzero(sd, sizeof(struct sd)); /* initialize */
580 sd->flags |= VF_NEWBORN; /* newly born subdisk */
581 sd->plexno = -1; /* no plex */
582 sd->sectors = -1; /* no space */
583 sd->driveno = -1; /* no drive */
584 sd->plexoffset = -1; /* and no offsets */
585 sd->driveoffset = -1;
586 return sdno; /* return the index */
587 }
588
589 /* return a drive to the free pool */
590 void
591 free_drive(struct drive *drive)
592 {
593 LOCKDRIVE(drive);
594 if (drive->flags & VF_OPEN) /* it's open, */
595 close_locked_drive(drive); /* close it */
596 if (drive->freelist)
597 Free(drive->freelist);
598 if (drive->dev != NULL)
599 dev_rel(drive->dev);
600 bzero(drive, sizeof(struct drive)); /* this also sets drive_unallocated */
601 unlockdrive(drive);
602 }
603
604 /*
605 * Find the named subdisk in vinum_conf.sd.
606 *
607 * If create != 0, create an entry if it doesn't exist
608 *
609 * Return index in vinum_conf.sd
610 */
611 int
612 find_subdisk(const char *name, int create)
613 {
614 int sdno;
615 struct sd *sd;
616
617 for (sdno = 0; sdno < vinum_conf.subdisks_allocated; sdno++) {
618 if (strcmp(SD[sdno].name, name) == 0) /* found it */
619 return sdno;
620 }
621
622 /* the subdisk isn't in the list. Add it if he wants */
623 if (create == 0) /* don't want to create */
624 return -1; /* give up */
625
626 /* Allocate one and insert the name */
627 sdno = get_empty_sd();
628 sd = &SD[sdno];
629 bcopy(name, sd->name, min(sizeof(sd->name), strlen(name))); /* put in its name */
630 return sdno; /* return the pointer */
631 }
632
633 /* Return space to a drive */
634 void
635 return_drive_space(int driveno, int64_t offset, int length)
636 {
637 struct drive *drive;
638 int fe; /* free list entry */
639 u_int64_t sdend; /* end of our subdisk */
640 u_int64_t dend; /* end of our freelist entry */
641
642 drive = &DRIVE[driveno];
643 if (drive->state == drive_up) {
644 sdend = offset + length; /* end of our subdisk */
645
646 /* Look for where to return the sd address space */
647 for (fe = 0;
648 (fe < drive->freelist_entries) && (drive->freelist[fe].offset < offset);
649 fe++);
650 /*
651 * Now we are pointing to the last entry, the first
652 * with a higher offset than the subdisk, or both.
653 */
654 if ((fe > 1) /* not the first entry */
655 &&((fe == drive->freelist_entries) /* gone past the end */
656 ||(drive->freelist[fe].offset > offset))) /* or past the block were looking for */
657 fe--; /* point to the block before */
658 dend = drive->freelist[fe].offset + drive->freelist[fe].sectors; /* end of the entry */
659
660 /*
661 * At this point, we are pointing to the correct
662 * place in the free list. A number of possibilities
663 * exist:
664 *
665 * 1. The block to be freed starts at the end of the
666 * block to which we are pointing. This has two
667 * subcases:
668 *
669 * a. The block to be freed ends at the beginning
670 * of the following block. Merge the three
671 * areas into a single block.
672 *
673 * b. The block is shorter than the space between
674 * the current block and the next one. Enlarge
675 * the current block.
676 *
677 * 2. The block to be freed starts after the end
678 * of the block. Again, we have two cases:
679 *
680 * a. It ends before the start of the following block.
681 * Create a new free block.
682 *
683 * b. It ends at the start of the following block.
684 * Enlarge the following block downwards.
685 *
686 * When there is only one free space block, and the
687 * space to be returned is before it, the pointer is
688 * to a non-existent zeroth block. XXX check this
689 */
690 if (offset == dend) { /* Case 1: it starts at the end of this block */
691 if ((fe < drive->freelist_entries - 1) /* we're not the last block in the free list */
692 /* and the subdisk ends at the start of the next block */
693 &&(sdend == drive->freelist[fe + 1].offset)) {
694 drive->freelist[fe].sectors /* 1a: merge all three blocks */
695 = drive->freelist[fe + 1].sectors;
696 if (fe < drive->freelist_entries - 2) /* still more blocks after next */
697 bcopy(&drive->freelist[fe + 2], /* move down one */
698 &drive->freelist[fe + 1],
699 (drive->freelist_entries - 2 - fe)
700 * sizeof(struct drive_freelist));
701 drive->freelist_entries--; /* one less entry in the free list */
702 } else /* 1b: just enlarge this block */
703 drive->freelist[fe].sectors += length;
704 } else { /* Case 2 */
705 if (offset > dend) /* it starts after this block */
706 fe++; /* so look at the next block */
707 if ((fe < drive->freelist_entries) /* we're not the last block in the free list */
708 /* and the subdisk ends at the start of this block: case 4 */
709 &&(sdend == drive->freelist[fe].offset)) {
710 drive->freelist[fe].offset = offset; /* it starts where the sd was */
711 drive->freelist[fe].sectors += length; /* and it's this much bigger */
712 } else { /* case 3: non-contiguous */
713 if (fe < drive->freelist_entries) /* not after the last block, */
714 bcopy(&drive->freelist[fe], /* move the rest up one entry */
715 &drive->freelist[fe + 1],
716 (drive->freelist_entries - fe)
717 * sizeof(struct drive_freelist));
718 drive->freelist_entries++; /* one less entry */
719 drive->freelist[fe].offset = offset; /* this entry represents the sd */
720 drive->freelist[fe].sectors = length;
721 }
722 }
723 drive->sectors_available += length; /* the sectors are now available */
724 }
725 }
726
727 /*
728 * Free an allocated sd entry.
729 * This performs memory management only. remove()
730 * is responsible for checking relationships.
731 */
732 void
733 free_sd(int sdno)
734 {
735 struct sd *sd;
736
737 sd = &SD[sdno];
738 if ((sd->driveno >= 0) /* we have a drive, */
739 &&(sd->sectors > 0)) /* and some space on it */
740 return_drive_space(sd->driveno, /* return the space */
741 sd->driveoffset,
742 sd->sectors);
743 if (sd->plexno >= 0)
744 PLEX[sd->plexno].subdisks--; /* one less subdisk */
745 /*
746 * If we come here as the result of a
747 * configuration error, we may not yet have
748 * created a device entry for the subdisk.
749 */
750 if (sd->dev)
751 destroy_dev(sd->dev);
752 bzero(sd, sizeof(struct sd)); /* and clear it out */
753 sd->state = sd_unallocated;
754 vinum_conf.subdisks_used--; /* one less sd */
755 }
756
757 /* Find an empty plex in the plex table */
758 int
759 get_empty_plex(void)
760 {
761 int plexno;
762 struct plex *plex; /* if we allocate one */
763
764 /* first see if we have one which has been deallocated */
765 for (plexno = 0; plexno < vinum_conf.plexes_allocated; plexno++) {
766 if (PLEX[plexno].state == plex_unallocated) /* bingo */
767 break; /* and get out of here */
768 }
769
770 if (plexno >= vinum_conf.plexes_allocated)
771 EXPAND(PLEX, struct plex, vinum_conf.plexes_allocated, INITIAL_PLEXES);
772
773 /* Found a plex. Give it an sd structure */
774 plex = &PLEX[plexno]; /* this one is ours */
775 bzero(plex, sizeof(struct plex)); /* polish it up */
776 plex->sdnos = (int *) Malloc(sizeof(int) * INITIAL_SUBDISKS_IN_PLEX); /* allocate sd table */
777 CHECKALLOC(plex->sdnos, "vinum: Can't allocate plex subdisk table");
778 bzero(plex->sdnos, (sizeof(int) * INITIAL_SUBDISKS_IN_PLEX)); /* do we need this? */
779 plex->flags |= VF_NEWBORN; /* newly born plex */
780 plex->subdisks = 0; /* no subdisks in use */
781 plex->subdisks_allocated = INITIAL_SUBDISKS_IN_PLEX; /* and we have space for this many */
782 plex->organization = plex_disorg; /* and it's not organized */
783 plex->volno = -1; /* no volume yet */
784 return plexno; /* return the index */
785 }
786
787 /*
788 * Find the named plex in vinum_conf.plex
789 *
790 * If create != 0, create an entry if it doesn't exist
791 * return index in vinum_conf.plex
792 */
793 int
794 find_plex(const char *name, int create)
795 {
796 int plexno;
797 struct plex *plex;
798
799 for (plexno = 0; plexno < vinum_conf.plexes_allocated; plexno++) {
800 if (strcmp(PLEX[plexno].name, name) == 0) /* found it */
801 return plexno;
802 }
803
804 /* the plex isn't in the list. Add it if he wants */
805 if (create == 0) /* don't want to create */
806 return -1; /* give up */
807
808 /* Allocate one and insert the name */
809 plexno = get_empty_plex();
810 plex = &PLEX[plexno]; /* point to it */
811 bcopy(name, plex->name, min(sizeof(plex->name), strlen(name))); /* put in its name */
812 return plexno; /* return the pointer */
813 }
814
815 /*
816 * Free an allocated plex entry
817 * and its associated memory areas
818 */
819 void
820 free_plex(int plexno)
821 {
822 struct plex *plex;
823
824 plex = &PLEX[plexno];
825 if (plex->sdnos)
826 Free(plex->sdnos);
827 if (plex->lock)
828 Free(plex->lock);
829 if (plex->dev)
830 destroy_dev(plex->dev);
831 bzero(plex, sizeof(struct plex)); /* and clear it out */
832 plex->state = plex_unallocated;
833 }
834
835 /* Find an empty volume in the volume table */
836 int
837 get_empty_volume(void)
838 {
839 int volno;
840 struct volume *vol;
841 int i;
842
843 /* first see if we have one which has been deallocated */
844 for (volno = 0; volno < vinum_conf.volumes_allocated; volno++) {
845 if (VOL[volno].state == volume_unallocated) /* bingo */
846 break;
847 }
848
849 if (volno >= vinum_conf.volumes_allocated)
850 EXPAND(VOL, struct volume, vinum_conf.volumes_allocated, INITIAL_VOLUMES);
851
852 /* Now initialize fields */
853 vol = &VOL[volno];
854 bzero(vol, sizeof(struct volume));
855 vol->flags |= VF_NEWBORN | VF_CREATED; /* newly born volume */
856 vol->preferred_plex = ROUND_ROBIN_READPOL; /* round robin */
857 for (i = 0; i < MAXPLEX; i++) /* mark the plexes missing */
858 vol->plex[i] = -1;
859 return volno; /* return the index */
860 }
861
862 /*
863 * Find the named volume in vinum_conf.volume.
864 *
865 * If create != 0, create an entry if it doesn't exist
866 * return the index in vinum_conf
867 */
868 int
869 find_volume(const char *name, int create)
870 {
871 int volno;
872 struct volume *vol;
873
874 for (volno = 0; volno < vinum_conf.volumes_allocated; volno++) {
875 if (strcmp(VOL[volno].name, name) == 0) /* found it */
876 return volno;
877 }
878
879 /* the volume isn't in the list. Add it if he wants */
880 if (create == 0) /* don't want to create */
881 return -1; /* give up */
882
883 /* Allocate one and insert the name */
884 volno = get_empty_volume();
885 vol = &VOL[volno];
886 bcopy(name, vol->name, min(sizeof(vol->name), strlen(name))); /* put in its name */
887 vol->blocksize = DEV_BSIZE; /* block size of this volume */
888 return volno; /* return the pointer */
889 }
890
891 /*
892 * Free an allocated volume entry
893 * and its associated memory areas
894 */
895 void
896 free_volume(int volno)
897 {
898 struct volume *vol;
899
900 vol = &VOL[volno];
901 if (vol->dev)
902 destroy_dev(vol->dev);
903 bzero(vol, sizeof(struct volume)); /* and clear it out */
904 vol->state = volume_unallocated;
905 }
906
907 /*
908 * Handle a drive definition. We store the information in the global variable
909 * drive, so we don't need to allocate.
910 *
911 * If we find an error, print a message and return
912 */
913 void
914 config_drive(int update)
915 {
916 enum drive_label_info partition_status; /* info about the partition */
917 int parameter;
918 int driveno; /* index of drive in vinum_conf */
919 struct drive *drive; /* and pointer to it */
920 int otherdriveno; /* index of possible second drive */
921 int sdno;
922
923 if (tokens < 2) /* not enough tokens */
924 throw_rude_remark(EINVAL, "Drive has no name\n");
925 driveno = find_drive(token[1], 1); /* allocate a drive to initialize */
926 drive = &DRIVE[driveno]; /* and get a pointer */
927 if (update && ((drive->flags & VF_NEWBORN) == 0)) /* this drive exists already */
928 return; /* don't do anything */
929 drive->flags &= ~VF_NEWBORN; /* no longer newly born */
930
931 if (drive->state != drive_referenced) { /* we already know this drive */
932 /*
933 * XXX Check which definition is more up-to-date. Give
934 * preference for the definition on its own drive.
935 */
936 return; /* XXX */
937 }
938 for (parameter = 2; parameter < tokens; parameter++) { /* look at the other tokens */
939 switch (get_keyword(token[parameter], &keyword_set)) {
940 case kw_device:
941 parameter++;
942 otherdriveno = find_drive_by_name(token[parameter], 0); /* see if it exists already */
943 if (otherdriveno >= 0) { /* yup, */
944 drive->state = drive_unallocated; /* deallocate the drive */
945 throw_rude_remark(EEXIST, /* and complain */
946 "Drive %s would have same device as drive %s",
947 token[1],
948 DRIVE[otherdriveno].label.name);
949 }
950 if (drive->devicename[0] == '/') { /* we know this drive... */
951 if (strcmp(drive->devicename, token[parameter])) /* different name */
952 close_drive(drive); /* close it if it's open */
953 else /* no change */
954 break;
955 }
956 /* open the device and get the configuration */
957 bcopy(token[parameter], /* insert device information */
958 drive->devicename,
959 min(sizeof(drive->devicename),
960 strlen(token[parameter])));
961 partition_status = read_drive_label(drive, 1);
962 switch (partition_status) {
963 case DL_CANT_OPEN: /* not our kind */
964 close_drive(drive);
965 if (drive->lasterror == EFTYPE) /* wrong kind of partition */
966 throw_rude_remark(drive->lasterror,
967 "Drive %s has invalid partition type",
968 drive->label.name);
969 else /* I/O error of some kind */
970 throw_rude_remark(drive->lasterror,
971 "Can't initialize drive %s",
972 drive->label.name);
973 break;
974
975 case DL_WRONG_DRIVE: /* valid drive, not the name we expected */
976 if (vinum_conf.flags & VF_FORCECONFIG) { /* but we'll accept that */
977 bcopy(token[1], drive->label.name, sizeof(drive->label.name));
978 break;
979 }
980 close_drive(drive);
981 /*
982 * There's a potential race condition here:
983 * the rude remark refers to a field in an
984 * unallocated drive, which potentially could
985 * be reused. This works because we're the only
986 * thread accessing the config at the moment.
987 */
988 drive->state = drive_unallocated; /* throw it away completely */
989 throw_rude_remark(drive->lasterror,
990 "Incorrect drive name %s specified for drive %s",
991 token[1],
992 drive->label.name);
993 break;
994
995 case DL_DELETED_LABEL: /* it was a drive, but we deleted it */
996 case DL_NOT_OURS: /* nothing to do with the rest */
997 case DL_OURS:
998 break;
999 }
1000 /*
1001 * read_drive_label overwrites the device name.
1002 * If we get here, we can have the drive,
1003 * so put it back again
1004 */
1005 bcopy(token[parameter],
1006 drive->devicename,
1007 min(sizeof(drive->devicename),
1008 strlen(token[parameter])));
1009 break;
1010
1011 case kw_state:
1012 parameter++; /* skip the keyword */
1013 if (vinum_conf.flags & VF_READING_CONFIG)
1014 drive->state = DriveState(token[parameter]); /* set the state */
1015 break;
1016
1017 case kw_hotspare: /* this drive is a hot spare */
1018 drive->flags |= VF_HOTSPARE;
1019 break;
1020
1021 default:
1022 close_drive(drive);
1023 throw_rude_remark(EINVAL,
1024 "Drive %s, invalid keyword: %s",
1025 token[1],
1026 token[parameter]);
1027 }
1028 }
1029
1030 if (drive->devicename[0] != '/') {
1031 drive->state = drive_unallocated; /* deallocate the drive */
1032 throw_rude_remark(EINVAL, "No device name for %s", drive->label.name);
1033 }
1034 vinum_conf.drives_used++; /* passed all hurdles: one more in use */
1035 /*
1036 * If we're replacing a drive, it could be that
1037 * we already have subdisks referencing this
1038 * drive. Note where they should be and change
1039 * their state to obsolete.
1040 */
1041 for (sdno = 0; sdno < vinum_conf.subdisks_allocated; sdno++) {
1042 if ((SD[sdno].state > sd_referenced)
1043 && (SD[sdno].driveno == driveno)) {
1044 give_sd_to_drive(sdno);
1045 if (SD[sdno].state > sd_stale)
1046 SD[sdno].state = sd_stale;
1047 }
1048 }
1049 }
1050
1051 /*
1052 * Handle a subdisk definition. We store the
1053 * information in the global variable sd, so we
1054 * don't need to allocate.
1055 *
1056 * On error throw a message back to the caller.
1057 */
1058 void
1059 config_subdisk(int update)
1060 {
1061 int parameter;
1062 int sdno; /* index of sd in vinum_conf */
1063 struct sd *sd; /* and pointer to it */
1064 u_int64_t size;
1065 int detached = 0; /* set to 1 if this is a detached subdisk */
1066 int sdindex = -1; /* index in plexes subdisk table */
1067 enum sdstate state = sd_unallocated; /* state to set, if specified */
1068 int autosize = 0; /* set if we autosize in give_sd_to_drive */
1069 int namedsdno; /* index of another with this name */
1070 char partition = 0; /* partition of external subdisk */
1071
1072 sdno = get_empty_sd(); /* allocate an SD to initialize */
1073 sd = &SD[sdno]; /* and get a pointer */
1074
1075 for (parameter = 1; parameter < tokens; parameter++) { /* look at the other tokens */
1076 switch (get_keyword(token[parameter], &keyword_set)) {
1077 /*
1078 * If we have a 'name' parameter, it must
1079 * come first, because we're too lazy to tidy
1080 * up dangling refs if it comes later.
1081 */
1082 case kw_name:
1083 namedsdno = find_subdisk(token[++parameter], 0); /* find an existing sd with this name */
1084 if (namedsdno >= 0) { /* got one */
1085 if (SD[namedsdno].state == sd_referenced) { /* we've been told about this one */
1086 if (parameter > 2)
1087 throw_rude_remark(EINVAL,
1088 "sd %s: name parameter must come first\n", /* no go */
1089 token[parameter]);
1090 else {
1091 int i;
1092 struct plex *plex; /* for tidying up dangling references */
1093
1094 *sd = SD[namedsdno]; /* copy from the referenced one */
1095 SD[namedsdno].state = sd_unallocated; /* and deallocate the referenced one */
1096 plex = &PLEX[sd->plexno]; /* now take a look at our plex */
1097 for (i = 0; i < plex->subdisks; i++) { /* look for the pointer */
1098 if (plex->sdnos[i] == namedsdno) /* pointing to the old subdisk */
1099 plex->sdnos[i] = sdno; /* bend it to point here */
1100 }
1101 }
1102 }
1103 if (update) /* are we updating? */
1104 return; /* that's OK, nothing more to do */
1105 else
1106 throw_rude_remark(EINVAL, "Duplicate subdisk %s", token[parameter]);
1107 } else
1108 bcopy(token[parameter],
1109 sd->name,
1110 min(sizeof(sd->name), strlen(token[parameter])));
1111 break;
1112
1113 case kw_detached:
1114 detached = 1;
1115 break;
1116
1117 case kw_plexoffset:
1118 size = sizespec(token[++parameter]);
1119 if ((size == -1) /* unallocated */
1120 &&(vinum_conf.flags & VF_READING_CONFIG)) /* reading from disk */
1121 break; /* invalid sd; just ignore it */
1122 if ((size % DEV_BSIZE) != 0)
1123 throw_rude_remark(EINVAL,
1124 "sd %s, bad plex offset alignment: %lld",
1125 sd->name,
1126 (long long) size);
1127 else
1128 sd->plexoffset = size / DEV_BSIZE;
1129 break;
1130
1131 case kw_driveoffset:
1132 size = sizespec(token[++parameter]);
1133 if ((size == -1) /* unallocated */
1134 &&(vinum_conf.flags & VF_READING_CONFIG)) /* reading from disk */
1135 break; /* invalid sd; just ignore it */
1136 if ((size % DEV_BSIZE) != 0)
1137 throw_rude_remark(EINVAL,
1138 "sd %s, bad drive offset alignment: %lld",
1139 sd->name,
1140 (long long) size);
1141 else
1142 sd->driveoffset = size / DEV_BSIZE;
1143 break;
1144
1145 case kw_len:
1146 if (get_keyword(token[++parameter], &keyword_set) == kw_max) /* select maximum size from drive */
1147 size = 0; /* this is how we say it :-) */
1148 else
1149 size = sizespec(token[parameter]);
1150 if ((size % DEV_BSIZE) != 0)
1151 throw_rude_remark(EINVAL, "sd %s, length %d not multiple of sector size", sd->name, size);
1152 else
1153 sd->sectors = size / DEV_BSIZE;
1154 /*
1155 * We have a problem with autosizing: we need to
1156 * give the drive to the plex before we give it
1157 * to the drive, in order to be clean if we give
1158 * up in the middle, but at this time the size hasn't
1159 * been set. Note that we have to fix up after
1160 * giving the subdisk to the drive.
1161 */
1162 if (size == 0)
1163 autosize = 1; /* note that we're autosizing */
1164 break;
1165
1166 case kw_drive:
1167 sd->driveno = find_drive(token[++parameter], 1); /* insert drive information */
1168 break;
1169
1170 case kw_plex:
1171 sd->plexno = find_plex(token[++parameter], 1); /* insert plex information */
1172 break;
1173
1174 /*
1175 * Set the state. We can't do this directly,
1176 * because give_sd_to_plex may change it
1177 */
1178 case kw_state:
1179 parameter++; /* skip the keyword */
1180 if (vinum_conf.flags & VF_READING_CONFIG)
1181 state = SdState(token[parameter]); /* set the state */
1182 break;
1183
1184 case kw_partition:
1185 parameter++; /* skip the keyword */
1186 if ((strlen(token[parameter]) != 1)
1187 || (token[parameter][0] < 'a')
1188 || (token[parameter][0] > 'h'))
1189 throw_rude_remark(EINVAL,
1190 "%s: invalid partition %c",
1191 sd->name,
1192 token[parameter][0]);
1193 else
1194 partition = token[parameter][0];
1195 break;
1196
1197 case kw_retryerrors:
1198 sd->flags |= VF_RETRYERRORS;
1199 break;
1200
1201 default:
1202 throw_rude_remark(EINVAL, "%s: invalid keyword: %s", sd->name, token[parameter]);
1203 }
1204 }
1205
1206 /* Check we have a drive name */
1207 if (sd->driveno < 0) { /* didn't specify a drive */
1208 sd->driveno = current_drive; /* set to the current drive */
1209 if (sd->driveno < 0) /* no current drive? */
1210 throw_rude_remark(EINVAL, "Subdisk %s is not associated with a drive", sd->name);
1211 }
1212 if (DRIVE[sd->driveno].state != drive_up)
1213 sd->state = sd_crashed;
1214
1215 if (autosize != 0) /* need to find a size, */
1216 give_sd_to_drive(sdno); /* do it before the plex */
1217
1218 /* Check for a plex name */
1219 if ((sd->plexno < 0) /* didn't specify a plex */
1220 &&(!detached)) /* and didn't say not to, */
1221 sd->plexno = current_plex; /* set to the current plex */
1222
1223 if (sd->plexno >= 0)
1224 sdindex = give_sd_to_plex(sd->plexno, sdno); /* now tell the plex that it has this sd */
1225
1226 sd->sdno = sdno; /* point to our entry in the table */
1227
1228 /* Does the subdisk have a name? If not, give it one */
1229 if (sd->name[0] == '\0') { /* no name */
1230 char sdsuffix[8]; /* form sd name suffix here */
1231
1232 /* Do we have a plex name? */
1233 if (sdindex >= 0) /* we have a plex */
1234 strlcpy(sd->name, /* take it from there */
1235 PLEX[sd->plexno].name,
1236 sizeof(sd->name));
1237 else { /* no way */
1238 if (sd->state == sd_unallocated) { /* haven't finished allocating the sd, */
1239 if (autosize != 0) { /* but we might have allocated drive space */
1240 vinum_conf.subdisks_used++; /* ugly hack needed for free_sd() */
1241 free_sd(sdno); /* free it to return drive space */
1242 } else { /* just clear it */
1243 bzero(sd, sizeof(struct sd));
1244 sd->state = sd_unallocated;
1245 }
1246 }
1247 throw_rude_remark(EINVAL, "Unnamed sd is not associated with a plex");
1248 }
1249 sprintf(sdsuffix, ".s%d", sdindex); /* form the suffix */
1250 strlcat(sd->name, sdsuffix, sizeof(sd->name)); /* and add it to the name */
1251 }
1252 /* do we have complete info for this subdisk? */
1253 if (sd->sectors < 0)
1254 throw_rude_remark(EINVAL, "sd %s has no length spec", sd->name);
1255
1256 if (sd->dev == NULL)
1257 /*
1258 * sdno can (at least theoretically) overflow
1259 * into the low order bit of the type field.
1260 * This gives rise to a subdisk with type
1261 * VINUM_SD2_TYPE. This is a feature, not a
1262 * bug.
1263 */
1264 sd->dev = make_dev(&vinum_cdevsw,
1265 VINUMMINOR(sdno, VINUM_SD_TYPE),
1266 UID_ROOT,
1267 GID_OPERATOR,
1268 S_IRUSR | S_IWUSR | S_IRGRP,
1269 "vinum/sd/%s",
1270 sd->name);
1271 if (state != sd_unallocated) /* we had a specific state to set */
1272 sd->state = state; /* do it now */
1273 else if (sd->state == sd_unallocated) /* no, nothing set yet, */
1274 sd->state = sd_empty; /* must be empty */
1275 if (autosize == 0) /* no autoconfig, do the drive now */
1276 give_sd_to_drive(sdno);
1277 vinum_conf.subdisks_used++; /* one more in use */
1278 }
1279
1280 /*
1281 * Handle a plex definition.
1282 */
1283 void
1284 config_plex(int update)
1285 {
1286 int parameter;
1287 int plexno; /* index of plex in vinum_conf */
1288 struct plex *plex; /* and pointer to it */
1289 int pindex = MAXPLEX; /* index in volume's plex list */
1290 int detached = 0; /* don't give it to a volume */
1291 int namedplexno;
1292 enum plexstate state = plex_init; /* state to set at end */
1293 int preferme; /* set if we want to be preferred access */
1294 int stripesize;
1295
1296 stripesize = 0;
1297 current_plex = -1; /* forget the previous plex */
1298 preferme = 0; /* nothing special yet */
1299 plexno = get_empty_plex(); /* allocate a plex */
1300 plex = &PLEX[plexno]; /* and point to it */
1301 plex->plexno = plexno; /* and back to the config */
1302
1303 for (parameter = 1; parameter < tokens; parameter++) { /* look at the other tokens */
1304 switch (get_keyword(token[parameter], &keyword_set)) {
1305 /*
1306 * If we have a 'name' parameter, it must
1307 * come first, because we're too lazy to tidy
1308 * up dangling refs if it comes later.
1309 */
1310 case kw_name:
1311 namedplexno = find_plex(token[++parameter], 0); /* find an existing plex with this name */
1312 if (namedplexno >= 0) { /* plex exists already, */
1313 if (PLEX[namedplexno].state == plex_referenced) { /* we've been told about this one */
1314 if (parameter > 2) /* we've done other things first, */
1315 throw_rude_remark(EINVAL,
1316 "plex %s: name parameter must come first\n", /* no go */
1317 token[parameter]);
1318 else {
1319 int i;
1320 struct volume *vol; /* for tidying up dangling references */
1321
1322 *plex = PLEX[namedplexno]; /* get the info */
1323 PLEX[namedplexno].state = plex_unallocated; /* and deallocate the other one */
1324 vol = &VOL[plex->volno]; /* point to the volume */
1325 for (i = 0; i < MAXPLEX; i++) { /* for each plex */
1326 if (vol->plex[i] == namedplexno)
1327 vol->plex[i] = plexno; /* bend the pointer */
1328 }
1329 }
1330 break; /* use this one */
1331 }
1332 if (update) /* are we updating? */
1333 return; /* yes: that's OK, just return */
1334 else
1335 throw_rude_remark(EINVAL, "Duplicate plex %s", token[parameter]);
1336 } else
1337 bcopy(token[parameter], /* put in the name */
1338 plex->name,
1339 min(MAXPLEXNAME, strlen(token[parameter])));
1340 break;
1341
1342 case kw_detached:
1343 detached = 1;
1344 break;
1345
1346 case kw_org: /* plex organization */
1347 switch (get_keyword(token[++parameter], &keyword_set)) {
1348 case kw_concat:
1349 plex->organization = plex_concat;
1350 break;
1351
1352 case kw_striped:
1353 {
1354 plex->organization = plex_striped;
1355
1356 if (++parameter >= tokens) /* No stripe size specified. */
1357 stripesize = 0;
1358 else
1359 stripesize = sizespec(token[parameter]);
1360
1361 break;
1362 }
1363
1364 case kw_raid4:
1365 {
1366 plex->organization = plex_raid4;
1367
1368 if (++parameter >= tokens) /* No stripe size specified. */
1369 stripesize = 0;
1370 else
1371 stripesize = sizespec(token[parameter]);
1372
1373 break;
1374 }
1375
1376 case kw_raid5:
1377 {
1378 plex->organization = plex_raid5;
1379
1380 if (++parameter >= tokens) /* No stripe size specified. */
1381 stripesize = 0;
1382 else
1383 stripesize = sizespec(token[parameter]);
1384
1385 break;
1386 }
1387
1388 default:
1389 throw_rude_remark(EINVAL, "Invalid plex organization");
1390 }
1391 if (isstriped(plex)) {
1392 if (stripesize == 0) /* didn't specify a valid stripe size */
1393 throw_rude_remark(EINVAL, "Need a stripe size parameter");
1394 else if (stripesize % DEV_BSIZE != 0)
1395 throw_rude_remark(EINVAL, "plex %s: stripe size %d not a multiple of sector size",
1396 plex->name,
1397 stripesize);
1398 else
1399 plex->stripesize = stripesize / DEV_BSIZE;
1400 }
1401 break;
1402
1403 /*
1404 * We're the preferred plex of our volume.
1405 * Unfortunately, we don't know who our
1406 * volume is yet. Note that we want to be
1407 * preferred, and actually do it after we
1408 * get a volume.
1409 */
1410 case kw_preferred:
1411 preferme = 1;
1412 break;
1413
1414 case kw_volume:
1415 plex->volno = find_volume(token[++parameter], 1); /* insert a pointer to the volume */
1416 break;
1417
1418 case kw_sd: /* add a subdisk */
1419 {
1420 int sdno;
1421
1422 sdno = find_subdisk(token[++parameter], 1); /* find a subdisk */
1423 SD[sdno].plexoffset = sizespec(token[++parameter]); /* get the offset */
1424 give_sd_to_plex(plexno, sdno); /* and insert it there */
1425 break;
1426 }
1427
1428 case kw_state:
1429 parameter++; /* skip the keyword */
1430 if (vinum_conf.flags & VF_READING_CONFIG)
1431 state = PlexState(token[parameter]); /* set the state */
1432 break;
1433
1434 default:
1435 throw_rude_remark(EINVAL, "plex %s, invalid keyword: %s",
1436 plex->name,
1437 token[parameter]);
1438 }
1439 }
1440
1441 if (plex->organization == plex_disorg)
1442 throw_rude_remark(EINVAL, "No plex organization specified");
1443
1444 if ((plex->volno < 0) /* we don't have a volume */
1445 &&(!detached)) /* and we wouldn't object */
1446 plex->volno = current_volume;
1447
1448 if (plex->volno >= 0)
1449 pindex = give_plex_to_volume(plex->volno, /* Now tell the volume that it has this plex */
1450 plexno,
1451 preferme);
1452
1453 /* Does the plex have a name? If not, give it one */
1454 if (plex->name[0] == '\0') { /* no name */
1455 char plexsuffix[8]; /* form plex name suffix here */
1456 /* Do we have a volume name? */
1457 if (plex->volno >= 0) /* we have a volume */
1458 strlcpy(plex->name, /* take it from there */
1459 VOL[plex->volno].name,
1460 sizeof(plex->name));
1461 else /* no way */
1462 throw_rude_remark(EINVAL, "Unnamed plex is not associated with a volume");
1463 sprintf(plexsuffix, ".p%d", pindex); /* form the suffix */
1464 strlcat(plex->name, plexsuffix, sizeof(plex->name)); /* and add it to the name */
1465 }
1466 if (isstriped(plex)) {
1467 plex->lock = (struct rangelock *)
1468 Malloc(PLEX_LOCKS * sizeof(struct rangelock));
1469 CHECKALLOC(plex->lock, "vinum: Can't allocate lock table\n");
1470 bzero((char *) plex->lock, PLEX_LOCKS * sizeof(struct rangelock));
1471 plex->lockmtx = &plexmutex[plexno % PLEXMUTEXES]; /* use this mutex for locking */
1472 }
1473 /* Note the last plex we configured */
1474 current_plex = plexno;
1475 plex->state = state; /* set whatever state we chose */
1476 vinum_conf.plexes_used++; /* one more in use */
1477 if (plex->dev == NULL)
1478 plex->dev = make_dev(&vinum_cdevsw,
1479 VINUMMINOR(plexno, VINUM_PLEX_TYPE),
1480 UID_ROOT,
1481 GID_OPERATOR,
1482 S_IRUSR | S_IWUSR | S_IRGRP,
1483 "vinum/plex/%s",
1484 plex->name);
1485 }
1486
1487 /*
1488 * Handle a volume definition.
1489 * If we find an error, print a message, deallocate the nascent volume, and return
1490 */
1491 void
1492 config_volume(int update)
1493 {
1494 int parameter;
1495 int volno;
1496 struct volume *vol; /* collect volume info here */
1497 int i;
1498
1499 if (tokens < 2) /* not enough tokens */
1500 throw_rude_remark(EINVAL, "Volume has no name");
1501 current_volume = -1; /* forget the previous volume */
1502 volno = find_volume(token[1], 1); /* allocate a volume to initialize */
1503 vol = &VOL[volno]; /* and get a pointer */
1504 if (update && ((vol->flags & VF_CREATED) == 0)) /* this volume exists already */
1505 return; /* don't do anything */
1506 vol->flags &= ~VF_CREATED; /* it exists now */
1507
1508 for (parameter = 2; parameter < tokens; parameter++) { /* look at all tokens */
1509 switch (get_keyword(token[parameter], &keyword_set)) {
1510 case kw_plex:
1511 {
1512 int plexno; /* index of this plex */
1513 int myplexno; /* and index if it's already ours */
1514
1515 plexno = find_plex(token[++parameter], 1); /* find a plex */
1516 if (plexno < 0) /* couldn't */
1517 break; /* we've already had an error message */
1518 myplexno = my_plex(volno, plexno); /* does it already belong to us? */
1519 if (myplexno > 0) /* yes, shouldn't get it again */
1520 throw_rude_remark(EINVAL,
1521 "Plex %s already belongs to volume %s",
1522 token[parameter],
1523 vol->name);
1524 else if (++vol->plexes > 8) /* another entry */
1525 throw_rude_remark(EINVAL,
1526 "Too many plexes for volume %s",
1527 vol->name);
1528 vol->plex[vol->plexes - 1] = plexno;
1529 PLEX[plexno].state = plex_referenced; /* we know something about it */
1530 PLEX[plexno].volno = volno; /* and this volume references it */
1531 }
1532 break;
1533
1534 case kw_readpol:
1535 switch (get_keyword(token[++parameter], &keyword_set)) { /* decide what to do */
1536 case kw_round:
1537 vol->preferred_plex = ROUND_ROBIN_READPOL; /* default */
1538 break;
1539
1540 case kw_prefer:
1541 {
1542 int myplexno; /* index of this plex */
1543
1544 myplexno = find_plex(token[++parameter], 1); /* find a plex */
1545 if (myplexno < 0) { /* couldn't */
1546 printf("vinum: couldn't find preferred plex %s for %s\n",
1547 token[parameter],
1548 vol->name);
1549 break; /* we've already had an error message */
1550 }
1551 myplexno = my_plex(volno, myplexno); /* does it already belong to us? */
1552 if (myplexno > 0) /* yes */
1553 vol->preferred_plex = myplexno; /* just note the index */
1554 else if (++vol->plexes > 8) /* another entry */
1555 throw_rude_remark(EINVAL, "Too many plexes");
1556 else { /* space for the new plex */
1557 vol->plex[vol->plexes - 1] = myplexno; /* add it to our list */
1558 vol->preferred_plex = vol->plexes - 1; /* and note the index */
1559 }
1560 }
1561 break;
1562
1563 default:
1564 throw_rude_remark(EINVAL, "Invalid read policy");
1565 }
1566
1567 case kw_setupstate:
1568 vol->flags |= VF_CONFIG_SETUPSTATE; /* set the volume up later on */
1569 break;
1570
1571 case kw_state:
1572 parameter++; /* skip the keyword */
1573 if (vinum_conf.flags & VF_READING_CONFIG)
1574 vol->state = VolState(token[parameter]); /* set the state */
1575 break;
1576
1577 /*
1578 * XXX experimental ideas. These are not
1579 * documented, and will not be until I
1580 * decide they're worth keeping.
1581 */
1582 case kw_writethrough: /* set writethrough mode */
1583 vol->flags |= VF_WRITETHROUGH;
1584 break;
1585
1586 case kw_writeback: /* set writeback mode */
1587 vol->flags &= ~VF_WRITETHROUGH;
1588 break;
1589
1590 default:
1591 throw_rude_remark(EINVAL, "volume %s, invalid keyword: %s",
1592 vol->name,
1593 token[parameter]);
1594 }
1595 }
1596 current_volume = volno; /* note last referred volume */
1597 vol->volno = volno; /* also note in volume */
1598
1599 /*
1600 * Before we can actually use the volume, we need
1601 * a volume label. We could start to fake one here,
1602 * but it will be a lot easier when we have some
1603 * to copy from the drives, so defer it until we
1604 * set up the configuration. XXX
1605 */
1606 if (vol->state == volume_unallocated)
1607 vol->state = volume_down; /* now ready to bring up at the end */
1608
1609 /* Find out how big our volume is */
1610 for (i = 0; i < vol->plexes; i++)
1611 vol->size = max(vol->size, PLEX[vol->plex[i]].length);
1612 vinum_conf.volumes_used++; /* one more in use */
1613 if (vol->dev == NULL)
1614 vol->dev = make_dev(&vinum_cdevsw,
1615 VINUMMINOR(volno, VINUM_VOLUME_TYPE),
1616 UID_ROOT,
1617 GID_OPERATOR,
1618 S_IRUSR | S_IWUSR | S_IRGRP,
1619 "vinum/%s",
1620 vol->name);
1621 }
1622
1623 /*
1624 * Parse a config entry. CARE! This destroys the original contents of the
1625 * config entry, which we don't really need after this. More specifically, it
1626 * places \0 characters at the end of each token.
1627 *
1628 * Return 0 if all is well, otherwise EINVAL for invalid keyword,
1629 * or ENOENT if 'read' command doesn't find any drives.
1630 */
1631 int
1632 parse_config(char *cptr, struct keywordset *keyset, int update)
1633 {
1634 int status;
1635
1636 status = 0; /* until proven otherwise */
1637 tokens = tokenize(cptr, token, MAXTOKEN); /* chop up into tokens */
1638
1639 if (tokens <= 0) /* screwed up or empty line */
1640 return tokens; /* give up */
1641 else if (tokens == MAXTOKEN) /* too many */
1642 throw_rude_remark(E2BIG,
1643 "Configuration error for %s: too many parameters",
1644 token[1]);
1645
1646 if (token[0][0] == '#') /* comment line */
1647 return 0;
1648
1649 switch (get_keyword(token[0], keyset)) { /* decide what to do */
1650 case kw_drive:
1651 config_drive(update);
1652 break;
1653
1654 case kw_subdisk:
1655 config_subdisk(update);
1656 break;
1657
1658 case kw_plex:
1659 config_plex(update);
1660 break;
1661
1662 case kw_volume:
1663 config_volume(update);
1664 break;
1665
1666 /* Anything else is invalid in this context */
1667 default:
1668 throw_rude_remark(EINVAL, /* should we die? */
1669 "Invalid configuration information: %s",
1670 token[0]);
1671 }
1672 return status;
1673 }
1674
1675 /*
1676 * parse a line handed in from userland via ioctl.
1677 * This differs only by the error reporting mechanism:
1678 * we return the error indication in the reply to the
1679 * ioctl, so we need to set a global static pointer in
1680 * this file. This technique works because we have
1681 * ensured that configuration is performed in a single-
1682 * threaded manner
1683 */
1684 int
1685 parse_user_config(char *cptr, struct keywordset *keyset)
1686 {
1687 int status;
1688
1689 ioctl_reply = (struct _ioctl_reply *) cptr;
1690 status = parse_config(cptr, keyset, 0);
1691 ioctl_reply = NULL; /* don't do this again */
1692 return status;
1693 }
1694
1695 /* Remove an object */
1696 void
1697 remove(struct vinum_ioctl_msg *msg)
1698 {
1699 struct vinum_ioctl_msg message = *msg; /* make a copy to hand on */
1700
1701 ioctl_reply = (struct _ioctl_reply *) msg; /* reinstate the address to reply to */
1702 ioctl_reply->error = 0; /* no error, */
1703 ioctl_reply->msg[0] = '\0'; /* no message */
1704
1705 switch (message.type) {
1706 case drive_object:
1707 remove_drive_entry(message.index, message.force);
1708 updateconfig(0);
1709 return;
1710
1711 case sd_object:
1712 remove_sd_entry(message.index, message.force, message.recurse);
1713 updateconfig(0);
1714 return;
1715
1716 case plex_object:
1717 remove_plex_entry(message.index, message.force, message.recurse);
1718 updateconfig(0);
1719 return;
1720
1721 case volume_object:
1722 remove_volume_entry(message.index, message.force, message.recurse);
1723 updateconfig(0);
1724 return;
1725
1726 default:
1727 ioctl_reply->error = EINVAL;
1728 strcpy(ioctl_reply->msg, "Invalid object type");
1729 }
1730 }
1731
1732 /* Remove a drive. */
1733 void
1734 remove_drive_entry(int driveno, int force)
1735 {
1736 struct drive *drive = &DRIVE[driveno];
1737 int sdno;
1738
1739 if ((driveno > vinum_conf.drives_allocated) /* not a valid drive */
1740 ||(drive->state == drive_unallocated)) { /* or nothing there */
1741 ioctl_reply->error = EINVAL;
1742 strcpy(ioctl_reply->msg, "No such drive");
1743 } else if (drive->opencount > 0) { /* we have subdisks */
1744 if (force) { /* do it at any cost */
1745 for (sdno = 0; sdno < vinum_conf.subdisks_allocated; sdno++) {
1746 if ((SD[sdno].state != sd_unallocated) /* subdisk is allocated */
1747 &&(SD[sdno].driveno == driveno)) /* and it belongs to this drive */
1748 remove_sd_entry(sdno, force, 0);
1749 }
1750 remove_drive(driveno); /* now remove it */
1751 vinum_conf.drives_used--; /* one less drive */
1752 } else
1753 ioctl_reply->error = EBUSY; /* can't do that */
1754 } else {
1755 remove_drive(driveno); /* just remove it */
1756 vinum_conf.drives_used--; /* one less drive */
1757 }
1758 }
1759
1760 /* remove a subdisk */
1761 void
1762 remove_sd_entry(int sdno, int force, int recurse)
1763 {
1764 struct sd *sd = &SD[sdno];
1765
1766 if ((sdno > vinum_conf.subdisks_allocated) /* not a valid sd */
1767 ||(sd->state == sd_unallocated)) { /* or nothing there */
1768 ioctl_reply->error = EINVAL;
1769 strcpy(ioctl_reply->msg, "No such subdisk");
1770 } else if (sd->flags & VF_OPEN) /* we're open */
1771 ioctl_reply->error = EBUSY; /* no getting around that */
1772 else if (sd->plexno >= 0) { /* we have a plex */
1773 if (force) { /* do it at any cost */
1774 struct plex *plex = &PLEX[sd->plexno]; /* point to our plex */
1775 int mysdno;
1776
1777 for (mysdno = 0; /* look for ourselves */
1778 mysdno < plex->subdisks && &SD[plex->sdnos[mysdno]] != sd;
1779 mysdno++);
1780 if (mysdno == plex->subdisks) /* didn't find it */
1781 log(LOG_ERR,
1782 "Error removing subdisk %s: not found in plex %s\n",
1783 SD[mysdno].name,
1784 plex->name);
1785 else { /* remove the subdisk from plex */
1786 if (mysdno < (plex->subdisks - 1)) /* not the last subdisk */
1787 bcopy(&plex->sdnos[mysdno + 1],
1788 &plex->sdnos[mysdno],
1789 (plex->subdisks - 1 - mysdno) * sizeof(int));
1790 plex->subdisks--;
1791 sd->plexno = -1; /* disown the subdisk */
1792 }
1793
1794 /*
1795 * Removing a subdisk from a striped or
1796 * RAID-4 or RAID-5 plex really tears the
1797 * hell out of the structure, and it needs
1798 * to be reinitialized.
1799 */
1800 if (plex->organization != plex_concat) /* not concatenated, */
1801 set_plex_state(plex->plexno, plex_faulty, setstate_force); /* need to reinitialize */
1802 log(LOG_INFO, "vinum: removing %s\n", sd->name);
1803 free_sd(sdno);
1804 } else
1805 ioctl_reply->error = EBUSY; /* can't do that */
1806 } else {
1807 log(LOG_INFO, "vinum: removing %s\n", sd->name);
1808 free_sd(sdno);
1809 }
1810 }
1811
1812 /* remove a plex */
1813 void
1814 remove_plex_entry(int plexno, int force, int recurse)
1815 {
1816 struct plex *plex = &PLEX[plexno];
1817 int sdno;
1818
1819 if ((plexno > vinum_conf.plexes_allocated) /* not a valid plex */
1820 ||(plex->state == plex_unallocated)) { /* or nothing there */
1821 ioctl_reply->error = EINVAL;
1822 strcpy(ioctl_reply->msg, "No such plex");
1823 } else if (plex->flags & VF_OPEN) { /* we're open */
1824 ioctl_reply->error = EBUSY; /* no getting around that */
1825 return;
1826 }
1827 if (plex->subdisks) {
1828 if (force) { /* do it anyway */
1829 if (recurse) { /* remove all below */
1830 int sds = plex->subdisks;
1831 for (sdno = 0; sdno < sds; sdno++)
1832 free_sd(plex->sdnos[sdno]); /* free all subdisks */
1833 } else { /* just tear them out */
1834 int sds = plex->subdisks;
1835 for (sdno = 0; sdno < sds; sdno++)
1836 SD[plex->sdnos[sdno]].plexno = -1; /* no plex any more */
1837 }
1838 } else { /* can't do it without force */
1839 ioctl_reply->error = EBUSY; /* can't do that */
1840 return;
1841 }
1842 }
1843 if (plex->volno >= 0) { /* we are part of a volume */
1844 if (force) { /* do it at any cost */
1845 struct volume *vol = &VOL[plex->volno];
1846 int myplexno;
1847
1848 for (myplexno = 0; myplexno < vol->plexes; myplexno++)
1849 if (vol->plex[myplexno] == plexno) /* found it */
1850 break;
1851 if (myplexno == vol->plexes) /* didn't find it. Huh? */
1852 log(LOG_ERR,
1853 "Error removing plex %s: not found in volume %s\n",
1854 plex->name,
1855 vol->name);
1856 if (myplexno < (vol->plexes - 1)) /* not the last plex in the list */
1857 bcopy(&vol->plex[myplexno + 1],
1858 &vol->plex[myplexno],
1859 vol->plexes - 1 - myplexno);
1860 vol->plexes--;
1861 } else {
1862 ioctl_reply->error = EBUSY; /* can't do that */
1863 return;
1864 }
1865 }
1866 log(LOG_INFO, "vinum: removing %s\n", plex->name);
1867 free_plex(plexno);
1868 vinum_conf.plexes_used--; /* one less plex */
1869 }
1870
1871 /* remove a volume */
1872 void
1873 remove_volume_entry(int volno, int force, int recurse)
1874 {
1875 struct volume *vol = &VOL[volno];
1876 int plexno;
1877
1878 if ((volno > vinum_conf.volumes_allocated) /* not a valid volume */
1879 ||(vol->state == volume_unallocated)) { /* or nothing there */
1880 ioctl_reply->error = EINVAL;
1881 strcpy(ioctl_reply->msg, "No such volume");
1882 } else if (vol->flags & VF_OPEN) /* we're open */
1883 ioctl_reply->error = EBUSY; /* no getting around that */
1884 else if (vol->plexes) {
1885 if (recurse && force) { /* remove all below */
1886 int plexes = vol->plexes;
1887
1888 /* for (plexno = plexes - 1; plexno >= 0; plexno--) */
1889 for (plexno = 0; plexno < plexes; plexno++)
1890 remove_plex_entry(vol->plex[plexno], force, recurse);
1891 log(LOG_INFO, "vinum: removing %s\n", vol->name);
1892 free_volume(volno);
1893 vinum_conf.volumes_used--; /* one less volume */
1894 } else
1895 ioctl_reply->error = EBUSY; /* can't do that */
1896 } else {
1897 log(LOG_INFO, "vinum: removing %s\n", vol->name);
1898 free_volume(volno);
1899 vinum_conf.volumes_used--; /* one less volume */
1900 }
1901 }
1902
1903 /* Currently called only from ioctl */
1904 void
1905 update_sd_config(int sdno, int diskconfig)
1906 {
1907 if (!diskconfig)
1908 set_sd_state(sdno, sd_up, setstate_configuring);
1909 SD[sdno].flags &= ~VF_NEWBORN;
1910 }
1911
1912 void
1913 update_plex_config(int plexno, int diskconfig)
1914 {
1915 u_int64_t size;
1916 int sdno;
1917 struct plex *plex = &PLEX[plexno];
1918 enum plexstate state = plex_up; /* state we want the plex in */
1919 int remainder; /* size of fractional stripe at end */
1920 int added_plex; /* set if we add a plex to a volume */
1921 int required_sds; /* number of subdisks we need */
1922 struct sd *sd;
1923 struct volume *vol;
1924 int data_sds = 0; /* number of sds carrying data */
1925
1926 if (plex->state < plex_init) /* not a real plex, */
1927 return;
1928 added_plex = 0;
1929 if (plex->volno >= 0) { /* we have a volume */
1930 vol = &VOL[plex->volno];
1931
1932 /*
1933 * If we're newly born,
1934 * and the volume isn't,
1935 * and it has other plexes,
1936 * and we didn't read this mess from disk,
1937 * we were added later.
1938 */
1939 if ((plex->flags & VF_NEWBORN)
1940 && ((vol->flags & VF_NEWBORN) == 0)
1941 && (vol->plexes > 0)
1942 && (diskconfig == 0)) {
1943 added_plex = 1;
1944 state = plex_down; /* so take ourselves down */
1945 }
1946 }
1947 /*
1948 * Check that our subdisks make sense. For
1949 * striped plexes, we need at least two
1950 * subdisks, and for RAID-4 and RAID-5 plexes we
1951 * need at least three subdisks. In each case
1952 * they must all be the same size.
1953 */
1954 if (plex->organization == plex_striped) {
1955 data_sds = plex->subdisks;
1956 required_sds = 2;
1957 } else if (isparity(plex)) { /* RAID 4 or 5 */
1958 data_sds = plex->subdisks - 1;
1959 required_sds = 3;
1960 } else
1961 required_sds = 0;
1962 if (required_sds > 0) { /* striped, RAID-4 or RAID-5 */
1963 if (plex->subdisks < required_sds) {
1964 log(LOG_ERR,
1965 "vinum: plex %s does not have at least %d subdisks\n",
1966 plex->name,
1967 required_sds);
1968 state = plex_faulty;
1969 }
1970 /*
1971 * Now see if the plex size is a multiple of
1972 * the stripe size. If not, trim off the end
1973 * of each subdisk and return it to the drive.
1974 */
1975 if (plex->length > 0) {
1976 if (data_sds > 0) {
1977 if (plex->stripesize > 0) {
1978 remainder = (int) (plex->length /* are we exact? */
1979 % ((u_int64_t) plex->stripesize * data_sds));
1980 if (remainder) { /* no */
1981 log(LOG_INFO, "vinum: removing %d blocks of partial stripe at the end of %s\n",
1982 remainder,
1983 plex->name);
1984 plex->length -= remainder; /* shorten the plex */
1985 remainder /= data_sds; /* spread the remainder amongst the sds */
1986 for (sdno = 0; sdno < plex->subdisks; sdno++) {
1987 sd = &SD[plex->sdnos[sdno]]; /* point to the subdisk */
1988 return_drive_space(sd->driveno, /* return the space */
1989 sd->driveoffset + sd->sectors - remainder,
1990 remainder);
1991 sd->sectors -= remainder; /* and shorten it */
1992 }
1993 }
1994 } else /* no data sds, */
1995 plex->length = 0; /* reset length */
1996 }
1997 }
1998 }
1999 size = 0;
2000 for (sdno = 0; sdno < plex->subdisks; sdno++) {
2001 sd = &SD[plex->sdnos[sdno]];
2002 if (isstriped(plex)
2003 && (sdno > 0)
2004 && (sd->sectors != SD[plex->sdnos[sdno - 1]].sectors)) {
2005 log(LOG_ERR, "vinum: %s must have equal sized subdisks\n", plex->name);
2006 state = plex_down;
2007 }
2008 size += sd->sectors;
2009 if (added_plex) /* we were added later */
2010 sd->state = sd_stale; /* stale until proven otherwise */
2011 if (plex->sectorsize != 0) {
2012 if (sd->sectorsize != plex->sectorsize) /* incompatible sector sizes? */
2013 printf("vinum: incompatible sector sizes. "
2014 "%s has %d bytes, %s has %d bytes. Ignored.\n",
2015 sd->name,
2016 sd->sectorsize,
2017 plex->name,
2018 plex->sectorsize);
2019 } else /* not set yet, */
2020 plex->sectorsize = sd->sectorsize;
2021 }
2022
2023 if (plex->subdisks) { /* plex has subdisks, calculate size */
2024 /*
2025 * XXX We shouldn't need to calculate the size any
2026 * more. Check this some time
2027 */
2028 if (isparity(plex))
2029 size = size / plex->subdisks * (plex->subdisks - 1); /* less space for RAID-4 and RAID-5 */
2030 if (plex->length != size)
2031 log(LOG_INFO,
2032 "Correcting length of %s: was %lld, is %lld\n",
2033 plex->name,
2034 (long long) plex->length,
2035 (long long) size);
2036 plex->length = size;
2037 } else { /* no subdisks, */
2038 plex->length = 0; /* no size */
2039 state = plex_down; /* take it down */
2040 }
2041 update_plex_state(plexno); /* set the state */
2042 plex->flags &= ~VF_NEWBORN;
2043 }
2044
2045 void
2046 update_volume_config(int volno)
2047 {
2048 struct volume *vol = &VOL[volno];
2049 struct plex *plex;
2050 int plexno;
2051
2052 if (vol->state != volume_unallocated)
2053 /*
2054 * Recalculate the size of the volume,
2055 * which might change if the original
2056 * plexes were not a multiple of the
2057 * stripe size.
2058 */
2059 {
2060 vol->size = 0;
2061 for (plexno = 0; plexno < vol->plexes; plexno++) {
2062 plex = &PLEX[vol->plex[plexno]];
2063 vol->size = max(plex->length, vol->size); /* maximum size */
2064 plex->volplexno = plexno; /* note it in the plex */
2065 if (vol->sectorsize != 0) {
2066 if (plex->sectorsize != vol->sectorsize) /* incompatible sector sizes? */
2067 printf("vinum: incompatible sector sizes. "
2068 "%s has %d, %s has %d. Ignored.\n",
2069 plex->name,
2070 plex->sectorsize,
2071 vol->name,
2072 vol->sectorsize);
2073 } else /* not set yet, */
2074 vol->sectorsize = plex->sectorsize;
2075 }
2076 }
2077 vol->flags &= ~VF_NEWBORN; /* no longer newly born */
2078 }
2079
2080 /*
2081 * Update the global configuration. This is
2082 * called after configuration changes.
2083 *
2084 * diskconfig is != 0 if we're reading in a config
2085 * from disk. In this case, we don't try to bring
2086 * the devices up, though we will bring them down
2087 * if there's some error which got missed when
2088 * writing to disk.
2089 */
2090 void
2091 updateconfig(int diskconfig)
2092 {
2093 int plexno;
2094 int volno;
2095
2096 for (plexno = 0; plexno < vinum_conf.plexes_allocated; plexno++)
2097 update_plex_config(plexno, diskconfig);
2098
2099 for (volno = 0; volno < vinum_conf.volumes_allocated; volno++) {
2100 if (VOL[volno].state > volume_uninit) {
2101 VOL[volno].flags &= ~VF_CONFIG_SETUPSTATE; /* no more setupstate */
2102 update_volume_state(volno);
2103 update_volume_config(volno);
2104 }
2105 }
2106 save_config();
2107 }
2108
2109 /*
2110 * Start manual changes to the configuration and lock out
2111 * others who may wish to do so.
2112 * XXX why do we need this and lock_config too?
2113 */
2114 int
2115 start_config(int force)
2116 {
2117 int error;
2118
2119 current_drive = -1; /* note the last drive we mention, for
2120 * some defaults */
2121 current_plex = -1; /* and the same for the last plex */
2122 current_volume = -1; /* and the last volume */
2123 while ((vinum_conf.flags & VF_CONFIGURING) != 0) {
2124 vinum_conf.flags |= VF_WILL_CONFIGURE;
2125 if ((error = tsleep(&vinum_conf, PRIBIO | PCATCH, "vincfg", 0)) != 0)
2126 return error;
2127 }
2128 /*
2129 * We need two flags here: VF_CONFIGURING
2130 * tells other processes to hold off (this
2131 * function), and VF_CONFIG_INCOMPLETE
2132 * tells the state change routines not to
2133 * propagate incrememntal state changes
2134 */
2135 vinum_conf.flags |= VF_CONFIGURING | VF_CONFIG_INCOMPLETE;
2136 if (force)
2137 vinum_conf.flags |= VF_FORCECONFIG; /* overwrite differently named drives */
2138 current_drive = -1; /* reset the defaults */
2139 current_plex = -1; /* and the same for the last plex */
2140 current_volume = -1; /* and the last volme */
2141 return 0;
2142 }
2143
2144 /*
2145 * Update the config if update is 1, and unlock
2146 * it. We won't update the configuration if we
2147 * are called in a recursive loop via throw_rude_remark.
2148 */
2149 void
2150 finish_config(int update)
2151 {
2152 /* we've finished our config */
2153 vinum_conf.flags &= ~(VF_CONFIG_INCOMPLETE | VF_READING_CONFIG | VF_FORCECONFIG);
2154 if (update)
2155 updateconfig(0); /* so update things */
2156 else
2157 updateconfig(1); /* do some updates only */
2158 vinum_conf.flags &= ~VF_CONFIGURING; /* and now other people can take a turn */
2159 if ((vinum_conf.flags & VF_WILL_CONFIGURE) != 0) {
2160 vinum_conf.flags &= ~VF_WILL_CONFIGURE;
2161 wakeup_one(&vinum_conf);
2162 }
2163 }
2164 /* Local Variables: */
2165 /* fill-column: 50 */
2166 /* End: */
Cache object: 9df4159d805c956e5c2cbdc66ab43a38
|