Deleted Added
full compact
geom_vinum_subr.c (135164) geom_vinum_subr.c (135173)
1/*-
2 * Copyright (c) 2004 Lukas Ertl
3 * Copyright (c) 1997, 1998, 1999
4 * Nan Yang Computer Services Limited. All rights reserved.
5 *
6 * Parts written by Greg Lehey
7 *
8 * This software is distributed under the so-called ``Berkeley
9 * License'':
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by Nan Yang Computer
22 * Services Limited.
23 * 4. Neither the name of the Company nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
26 *
27 * This software is provided ``as is'', and any express or implied
28 * warranties, including, but not limited to, the implied warranties of
29 * merchantability and fitness for a particular purpose are disclaimed.
30 * In no event shall the company or contributors be liable for any
31 * direct, indirect, incidental, special, exemplary, or consequential
32 * damages (including, but not limited to, procurement of substitute
33 * goods or services; loss of use, data, or profits; or business
34 * interruption) however caused and on any theory of liability, whether
35 * in contract, strict liability, or tort (including negligence or
36 * otherwise) arising in any way out of the use of this software, even if
37 * advised of the possibility of such damage.
38 *
39 */
40
41#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 2004 Lukas Ertl
3 * Copyright (c) 1997, 1998, 1999
4 * Nan Yang Computer Services Limited. All rights reserved.
5 *
6 * Parts written by Greg Lehey
7 *
8 * This software is distributed under the so-called ``Berkeley
9 * License'':
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by Nan Yang Computer
22 * Services Limited.
23 * 4. Neither the name of the Company nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
26 *
27 * This software is provided ``as is'', and any express or implied
28 * warranties, including, but not limited to, the implied warranties of
29 * merchantability and fitness for a particular purpose are disclaimed.
30 * In no event shall the company or contributors be liable for any
31 * direct, indirect, incidental, special, exemplary, or consequential
32 * damages (including, but not limited to, procurement of substitute
33 * goods or services; loss of use, data, or profits; or business
34 * interruption) however caused and on any theory of liability, whether
35 * in contract, strict liability, or tort (including negligence or
36 * otherwise) arising in any way out of the use of this software, even if
37 * advised of the possibility of such damage.
38 *
39 */
40
41#include <sys/cdefs.h>
42__FBSDID("$FreeBSD: head/sys/geom/vinum/geom_vinum_subr.c 135164 2004-09-13 17:44:47Z le $");
42__FBSDID("$FreeBSD: head/sys/geom/vinum/geom_vinum_subr.c 135173 2004-09-13 21:01:36Z le $");
43
44#include <sys/param.h>
45#include <sys/conf.h>
46#include <sys/kernel.h>
47#include <sys/libkern.h>
48#include <sys/malloc.h>
49#include <sys/systm.h>
50
51#include <geom/geom.h>
52#include <geom/geom_int.h>
53#include <geom/vinum/geom_vinum_var.h>
54#include <geom/vinum/geom_vinum.h>
55#include <geom/vinum/geom_vinum_share.h>
56
57/* Find the VINUM class and it's associated geom. */
58struct g_geom *
59find_vinum_geom(void)
60{
61 struct g_class *mp;
62 struct g_geom *gp;
63
64 g_topology_assert();
65
66 gp = NULL;
67
68 LIST_FOREACH(mp, &g_classes, class) {
69 if (!strcmp(mp->name, "VINUM")) {
70 gp = LIST_FIRST(&mp->geom);
71 break;
72 }
73 }
74
75 return (gp);
76}
77
78/*
79 * Parse the vinum config provided in *buf and store it in *gp's softc.
80 * If parameter 'merge' is non-zero, then the given config is merged into
81 * *gp.
82 */
83void
84gv_parse_config(struct gv_softc *sc, u_char *buf, int merge)
85{
86 char *aptr, *bptr, *cptr;
87 struct gv_volume *v, *v2;
88 struct gv_plex *p, *p2;
89 struct gv_sd *s, *s2;
90 int tokens;
91 char *token[GV_MAXARGS];
92
93 g_topology_assert();
94
95 KASSERT(sc != NULL, ("gv_parse_config: NULL softc"));
96
97 /* Until the end of the string *buf. */
98 for (aptr = buf; *aptr != '\0'; aptr = bptr) {
99 bptr = aptr;
100 cptr = aptr;
101
102 /* Seperate input lines. */
103 while (*bptr != '\n')
104 bptr++;
105 *bptr = '\0';
106 bptr++;
107
108 tokens = gv_tokenize(cptr, token, GV_MAXARGS);
109
110 if (tokens > 0) {
111 if (!strcmp(token[0], "volume")) {
112 v = gv_new_volume(tokens, token);
113 if (v == NULL) {
114 printf("geom_vinum: failed volume\n");
115 break;
116 }
117
118 if (merge) {
119 v2 = gv_find_vol(sc, v->name);
120 if (v2 != NULL) {
121 g_free(v);
122 continue;
123 }
124 }
125
126 v->vinumconf = sc;
127 LIST_INIT(&v->plexes);
128 LIST_INSERT_HEAD(&sc->volumes, v, volume);
129
130 } else if (!strcmp(token[0], "plex")) {
131 p = gv_new_plex(tokens, token);
132 if (p == NULL) {
133 printf("geom_vinum: failed plex\n");
134 break;
135 }
136
137 if (merge) {
138 p2 = gv_find_plex(sc, p->name);
139 if (p2 != NULL) {
140 g_free(p);
141 continue;
142 }
143 }
144
145 p->vinumconf = sc;
146 LIST_INIT(&p->subdisks);
147 LIST_INSERT_HEAD(&sc->plexes, p, plex);
148
149 } else if (!strcmp(token[0], "sd")) {
150 s = gv_new_sd(tokens, token);
151
152 if (s == NULL) {
153 printf("geom_vinum: failed subdisk\n");
154 break;
155 }
156
157 if (merge) {
158 s2 = gv_find_sd(sc, s->name);
159 if (s2 != NULL) {
160 g_free(s);
161 continue;
162 }
163 }
164
165 s->vinumconf = sc;
166 LIST_INSERT_HEAD(&sc->subdisks, s, sd);
167 }
168 }
169 }
170}
171
172/*
173 * Format the vinum configuration properly. If ondisk is non-zero then the
174 * configuration is intended to be written to disk later.
175 */
176void
177gv_format_config(struct gv_softc *sc, struct sbuf *sb, int ondisk, char *prefix)
178{
179 struct gv_drive *d;
180 struct gv_sd *s;
181 struct gv_plex *p;
182 struct gv_volume *v;
183
184 g_topology_assert();
185
186 /*
187 * We don't need the drive configuration if we're not writing the
188 * config to disk.
189 */
190 if (!ondisk) {
191 LIST_FOREACH(d, &sc->drives, drive) {
192 sbuf_printf(sb, "%sdrive %s device %s\n", prefix,
193 d->name, d->device);
194 }
195 }
196
197 LIST_FOREACH(v, &sc->volumes, volume) {
198 if (!ondisk)
199 sbuf_printf(sb, "%s", prefix);
200 sbuf_printf(sb, "volume %s", v->name);
201 if (ondisk)
202 sbuf_printf(sb, " state %s", gv_volstate(v->state));
203 sbuf_printf(sb, "\n");
204 }
205
206 LIST_FOREACH(p, &sc->plexes, plex) {
207 if (!ondisk)
208 sbuf_printf(sb, "%s", prefix);
209 sbuf_printf(sb, "plex name %s org %s ", p->name,
210 gv_plexorg(p->org));
211 if (gv_is_striped(p))
212 sbuf_printf(sb, "%ds ", p->stripesize / 512);
213 if (p->vol_sc != NULL)
214 sbuf_printf(sb, "vol %s", p->volume);
215 if (ondisk)
216 sbuf_printf(sb, " state %s", gv_plexstate(p->state));
217 sbuf_printf(sb, "\n");
218 }
219
220 LIST_FOREACH(s, &sc->subdisks, sd) {
221 if (!ondisk)
222 sbuf_printf(sb, "%s", prefix);
223 sbuf_printf(sb, "sd name %s drive %s len %jds driveoffset "
224 "%jds", s->name, s->drive, s->size / 512,
225 s->drive_offset / 512);
226 if (s->plex_sc != NULL) {
227 sbuf_printf(sb, " plex %s plexoffset %jds", s->plex,
228 s->plex_offset / 512);
229 }
230 if (ondisk)
231 sbuf_printf(sb, " state %s", gv_sdstate(s->state));
232 sbuf_printf(sb, "\n");
233 }
234
235 return;
236}
237
238/*
239 * Take a size in bytes and return a pointer to a string which represents the
240 * size best. If lj is != 0, return left justified, otherwise in a fixed 10
241 * character field suitable for columnar printing.
242 *
243 * Note this uses a static string: it's only intended to be used immediately
244 * for printing.
245 */
246const char *
247gv_roughlength(off_t bytes, int lj)
248{
249 static char desc[16];
250
251 /* Gigabytes. */
252 if (bytes > (off_t)MEGABYTE * 10000)
253 snprintf(desc, sizeof(desc), lj ? "%jd GB" : "%10jd GB",
254 bytes / GIGABYTE);
255
256 /* Megabytes. */
257 else if (bytes > KILOBYTE * 10000)
258 snprintf(desc, sizeof(desc), lj ? "%jd MB" : "%10jd MB",
259 bytes / MEGABYTE);
260
261 /* Kilobytes. */
262 else if (bytes > 10000)
263 snprintf(desc, sizeof(desc), lj ? "%jd kB" : "%10jd kB",
264 bytes / KILOBYTE);
265
266 /* Bytes. */
267 else
268 snprintf(desc, sizeof(desc), lj ? "%jd B" : "%10jd B", bytes);
269
270 return (desc);
271}
272
273int
274gv_sd_to_plex(struct gv_plex *p, struct gv_sd *s, int check)
275{
276 struct gv_sd *s2;
277
278 g_topology_assert();
279
280 /* If this subdisk was already given to this plex, do nothing. */
281 if (s->plex_sc == p)
282 return (0);
283
284 /* Find the correct plex offset for this subdisk, if needed. */
285 if (s->plex_offset == -1) {
286 if (p->sdcount) {
287 LIST_FOREACH(s2, &p->subdisks, in_plex) {
288 if (gv_is_striped(p))
289 s->plex_offset = p->sdcount *
290 p->stripesize;
291 else
292 s->plex_offset = s2->plex_offset +
293 s2->size;
294 }
295 } else
296 s->plex_offset = 0;
297 }
298
299 p->sdcount++;
300
301 /* Adjust the size of our plex. */
302 switch (p->org) {
303 case GV_PLEX_CONCAT:
304 case GV_PLEX_STRIPED:
305 p->size += s->size;
306 break;
307
308 case GV_PLEX_RAID5:
309 p->size = (p->sdcount - 1) * s->size;
310 break;
311
312 default:
313 break;
314 }
315
316 /* There are no subdisks for this plex yet, just insert it. */
317 if (LIST_EMPTY(&p->subdisks)) {
318 LIST_INSERT_HEAD(&p->subdisks, s, in_plex);
319
320 /* Insert in correct order, depending on plex_offset. */
321 } else {
322 LIST_FOREACH(s2, &p->subdisks, in_plex) {
323 if (s->plex_offset < s2->plex_offset) {
324 LIST_INSERT_BEFORE(s2, s, in_plex);
325 break;
326 } else if (LIST_NEXT(s2, in_plex) == NULL) {
327 LIST_INSERT_AFTER(s2, s, in_plex);
328 break;
329 }
330 }
331 }
332
333 s->plex_sc = p;
334
335 return (0);
336}
337
338void
339gv_update_vol_size(struct gv_volume *v, off_t size)
340{
341 struct g_geom *gp;
342 struct g_provider *pp;
343
344 if (v == NULL)
345 return;
346
347 gp = v->geom;
348 if (gp == NULL)
349 return;
350
351 LIST_FOREACH(pp, &gp->provider, provider) {
352 pp->mediasize = size;
353 }
354
355 v->size = size;
356}
357
358void
359gv_update_plex_config(struct gv_plex *p)
360{
361 struct gv_sd *s, *s2;
362 off_t remainder;
363 int required_sds, state;
364
365 KASSERT(p != NULL, ("gv_update_plex_config: NULL p"));
366
367 /* This is what we want the plex to be. */
368 state = GV_PLEX_UP;
369
370 /* The plex was added to an already running volume. */
371 if (p->flags & GV_PLEX_ADDED)
372 state = GV_PLEX_DOWN;
373
374 switch (p->org) {
375 case GV_PLEX_STRIPED:
376 required_sds = 2;
377 break;
378 case GV_PLEX_RAID5:
379 required_sds = 3;
380 break;
381 case GV_PLEX_CONCAT:
382 default:
383 required_sds = 0;
384 break;
385 }
386
387 if (required_sds) {
388 if (p->sdcount < required_sds) {
389 state = GV_PLEX_DOWN;
390 }
391
392 /*
393 * The subdisks in striped plexes must all have the same size.
394 */
395 s = LIST_FIRST(&p->subdisks);
396 LIST_FOREACH(s2, &p->subdisks, in_plex) {
397 if (s->size != s2->size) {
398 printf("geom_vinum: subdisk size mismatch "
399 "%s (%jd) <> %s (%jd)\n", s->name, s->size,
400 s2->name, s2->size);
401 state = GV_PLEX_DOWN;
402 }
403 }
404
405 /* Trim subdisk sizes so that they match the stripe size. */
406 LIST_FOREACH(s, &p->subdisks, in_plex) {
407 remainder = s->size % p->stripesize;
408 if (remainder) {
409 printf("gvinum: size of sd %s is not a "
410 "multiple of plex stripesize, taking off "
411 "%jd bytes\n", s->name,
412 (intmax_t)remainder);
413 gv_adjust_freespace(s, remainder);
414 }
415 }
416 }
417
418 /* Adjust the size of our plex. */
419 if (p->sdcount > 0) {
420 p->size = 0;
421 switch (p->org) {
422 case GV_PLEX_CONCAT:
423 LIST_FOREACH(s, &p->subdisks, in_plex)
424 p->size += s->size;
425 break;
426
427 case GV_PLEX_STRIPED:
428 s = LIST_FIRST(&p->subdisks);
429 p->size = p->sdcount * s->size;
430 break;
431
432 case GV_PLEX_RAID5:
433 s = LIST_FIRST(&p->subdisks);
434 p->size = (p->sdcount - 1) * s->size;
435 break;
436
437 default:
438 break;
439 }
440 }
441
442 if (p->sdcount == 0)
443 state = GV_PLEX_DOWN;
444 else if ((p->flags & GV_PLEX_ADDED) ||
445 ((p->org == GV_PLEX_RAID5) && (p->flags & GV_PLEX_NEWBORN))) {
446 LIST_FOREACH(s, &p->subdisks, in_plex)
447 s->state = GV_SD_STALE;
448 p->flags &= ~GV_PLEX_ADDED;
449 p->flags &= ~GV_PLEX_NEWBORN;
450 p->state = GV_PLEX_DOWN;
451 }
452}
453
454/*
455 * Give a subdisk to a drive, check and adjust several parameters, adjust
456 * freelist.
457 */
458int
459gv_sd_to_drive(struct gv_softc *sc, struct gv_drive *d, struct gv_sd *s,
460 char *errstr, int errlen)
461{
462 struct gv_sd *s2;
463 struct gv_freelist *fl, *fl2;
464 off_t tmp;
465 int i;
466
467 g_topology_assert();
468
469 fl2 = NULL;
470
471 KASSERT(sc != NULL, ("gv_sd_to_drive: NULL softc"));
472 KASSERT(d != NULL, ("gv_sd_to_drive: NULL drive"));
473 KASSERT(s != NULL, ("gv_sd_to_drive: NULL subdisk"));
474 KASSERT(errstr != NULL, ("gv_sd_to_drive: NULL errstr"));
475 KASSERT(errlen >= ERRBUFSIZ, ("gv_sd_to_drive: short errlen (%d)",
476 errlen));
477
478 /* Check if this subdisk was already given to this drive. */
479 if (s->drive_sc == d)
480 return (0);
481
482 /* Preliminary checks. */
483 if (s->size > d->avail || d->freelist_entries == 0) {
484 snprintf(errstr, errlen, "not enough space on '%s' for '%s'",
485 d->name, s->name);
486 return (-1);
487 }
488
489 /* No size given, autosize it. */
490 if (s->size == -1) {
491 /* Find the largest available slot. */
492 LIST_FOREACH(fl, &d->freelist, freelist) {
493 if (fl->size >= s->size) {
494 s->size = fl->size;
495 s->drive_offset = fl->offset;
496 fl2 = fl;
497 }
498 }
499
500 /* No good slot found? */
501 if (s->size == -1) {
502 snprintf(errstr, errlen, "couldn't autosize '%s' on "
503 "'%s'", s->name, d->name);
504 return (-1);
505 }
506
507 /*
508 * Check if we have a free slot that's large enough for the given size.
509 */
510 } else {
511 i = 0;
512 LIST_FOREACH(fl, &d->freelist, freelist) {
513 /* Yes, this subdisk fits. */
514 if (fl->size >= s->size) {
515 i++;
516 /* Assign drive offset, if not given. */
517 if (s->drive_offset == -1)
518 s->drive_offset = fl->offset;
519 fl2 = fl;
520 break;
521 }
522 }
523
524 /* Couldn't find a good free slot. */
525 if (i == 0) {
526 snprintf(errstr, errlen, "free slots to small for '%s' "
527 "on '%s'", s->name, d->name);
528 return (-1);
529 }
530 }
531
532 /* No drive offset given, try to calculate it. */
533 if (s->drive_offset == -1) {
534
535 /* Add offsets and sizes from other subdisks on this drive. */
536 LIST_FOREACH(s2, &d->subdisks, from_drive) {
537 s->drive_offset = s2->drive_offset + s2->size;
538 }
539
540 /*
541 * If there are no other subdisks yet, then set the default
542 * offset to GV_DATA_START.
543 */
544 if (s->drive_offset == -1)
545 s->drive_offset = GV_DATA_START;
546
547 /* Check if we have a free slot at the given drive offset. */
548 } else {
549 i = 0;
550 LIST_FOREACH(fl, &d->freelist, freelist) {
551 /* Yes, this subdisk fits. */
552 if ((fl->offset <= s->drive_offset) &&
553 (fl->offset + fl->size >=
554 s->drive_offset + s->size)) {
555 i++;
556 fl2 = fl;
557 break;
558 }
559 }
560
561 /* Couldn't find a good free slot. */
562 if (i == 0) {
563 snprintf(errstr, errlen, "given drive_offset for '%s' "
564 "won't fit on '%s'", s->name, d->name);
565 return (-1);
566 }
567 }
568
569 /*
570 * Now that all parameters are checked and set up, we can give the
571 * subdisk to the drive and adjust the freelist.
572 */
573
574 /* First, adjust the freelist. */
575 LIST_FOREACH(fl, &d->freelist, freelist) {
576
577 /* This is the free slot that we have found before. */
578 if (fl == fl2) {
579
580 /*
581 * The subdisk starts at the beginning of the free
582 * slot.
583 */
584 if (fl->offset == s->drive_offset) {
585 fl->offset += s->size;
586 fl->size -= s->size;
587
588 /*
589 * The subdisk uses the whole slot, so remove
590 * it.
591 */
592 if (fl->size == 0) {
593 d->freelist_entries--;
594 LIST_REMOVE(fl, freelist);
595 }
596 /*
597 * The subdisk does not start at the beginning of the
598 * free slot.
599 */
600 } else {
601 tmp = fl->offset + fl->size;
602 fl->size = s->drive_offset - fl->offset;
603
604 /*
605 * The subdisk didn't use the complete rest of
606 * the free slot, so we need to split it.
607 */
608 if (s->drive_offset + s->size != tmp) {
609 fl2 = g_malloc(sizeof(*fl2),
610 M_WAITOK | M_ZERO);
611 fl2->offset = s->drive_offset + s->size;
612 fl2->size = tmp - fl2->offset;
613 LIST_INSERT_AFTER(fl, fl2, freelist);
614 d->freelist_entries++;
615 }
616 }
617 break;
618 }
619 }
620
621 /*
622 * This is the first subdisk on this drive, just insert it into the
623 * list.
624 */
625 if (LIST_EMPTY(&d->subdisks)) {
626 LIST_INSERT_HEAD(&d->subdisks, s, from_drive);
627
628 /* There are other subdisks, so insert this one in correct order. */
629 } else {
630 LIST_FOREACH(s2, &d->subdisks, from_drive) {
631 if (s->drive_offset < s2->drive_offset) {
632 LIST_INSERT_BEFORE(s2, s, from_drive);
633 break;
634 } else if (LIST_NEXT(s2, from_drive) == NULL) {
635 LIST_INSERT_AFTER(s2, s, from_drive);
636 break;
637 }
638 }
639 }
640
641 d->sdcount++;
642 d->avail -= s->size;
643
644 /* Link back from the subdisk to this drive. */
645 s->drive_sc = d;
646
647 return (0);
648}
649
650void
651gv_adjust_freespace(struct gv_sd *s, off_t remainder)
652{
653 struct gv_drive *d;
654 struct gv_freelist *fl, *fl2;
655
656 KASSERT(s != NULL, ("gv_adjust_freespace: NULL s"));
657 d = s->drive_sc;
658 KASSERT(d != NULL, ("gv_adjust_freespace: NULL d"));
659
660 /* First, find the free slot that's immediately after this subdisk. */
661 fl = NULL;
662 LIST_FOREACH(fl, &d->freelist, freelist) {
663 if (fl->offset == s->drive_offset + s->size)
664 break;
665 }
666
667 /* If there is no free slot behind this subdisk, so create one. */
668 if (fl == NULL) {
669
670 fl = g_malloc(sizeof(*fl), M_WAITOK | M_ZERO);
671 fl->size = remainder;
672 fl->offset = s->drive_offset + s->size - remainder;
673
674 if (d->freelist_entries == 0) {
675 LIST_INSERT_HEAD(&d->freelist, fl, freelist);
676 } else {
677 LIST_FOREACH(fl2, &d->freelist, freelist) {
678 if (fl->offset < fl2->offset) {
679 LIST_INSERT_BEFORE(fl2, fl, freelist);
680 break;
681 } else if (LIST_NEXT(fl2, freelist) == NULL) {
682 LIST_INSERT_AFTER(fl2, fl, freelist);
683 break;
684 }
685 }
686 }
687
688 d->freelist_entries++;
689
690 /* Expand the free slot we just found. */
691 } else {
692 fl->offset -= remainder;
693 fl->size += remainder;
694 }
695
696 s->size -= remainder;
697 d->avail += remainder;
698}
699
700/* Check if the given plex is a striped one. */
701int
702gv_is_striped(struct gv_plex *p)
703{
704 KASSERT(p != NULL, ("gv_is_striped: NULL p"));
705 switch(p->org) {
706 case GV_PLEX_STRIPED:
707 case GV_PLEX_RAID5:
708 return (1);
709 default:
710 return (0);
711 }
712}
713
714/* Find a volume by name. */
715struct gv_volume *
716gv_find_vol(struct gv_softc *sc, char *name)
717{
718 struct gv_volume *v;
719
720 LIST_FOREACH(v, &sc->volumes, volume) {
721 if (!strncmp(v->name, name, GV_MAXVOLNAME))
722 return (v);
723 }
724
725 return (NULL);
726}
727
728/* Find a plex by name. */
729struct gv_plex *
730gv_find_plex(struct gv_softc *sc, char *name)
731{
732 struct gv_plex *p;
733
734 LIST_FOREACH(p, &sc->plexes, plex) {
735 if (!strncmp(p->name, name, GV_MAXPLEXNAME))
736 return (p);
737 }
738
739 return (NULL);
740}
741
742/* Find a subdisk by name. */
743struct gv_sd *
744gv_find_sd(struct gv_softc *sc, char *name)
745{
746 struct gv_sd *s;
747
748 LIST_FOREACH(s, &sc->subdisks, sd) {
749 if (!strncmp(s->name, name, GV_MAXSDNAME))
750 return (s);
751 }
752
753 return (NULL);
754}
755
756/* Find a drive by name. */
757struct gv_drive *
758gv_find_drive(struct gv_softc *sc, char *name)
759{
760 struct gv_drive *d;
761
762 LIST_FOREACH(d, &sc->drives, drive) {
763 if (!strncmp(d->name, name, GV_MAXDRIVENAME))
764 return (d);
765 }
766
767 return (NULL);
768}
769
770/* Check if any consumer of the given geom is open. */
771int
772gv_is_open(struct g_geom *gp)
773{
774 struct g_consumer *cp;
775
776 if (gp == NULL)
777 return (0);
778
779 LIST_FOREACH(cp, &gp->consumer, consumer) {
780 if (cp->acr || cp->acw || cp->ace)
781 return (1);
782 }
783
784 return (0);
785}
786
787/* Return the type of object identified by string 'name'. */
788int
789gv_object_type(struct gv_softc *sc, char *name)
790{
791 struct gv_drive *d;
792 struct gv_plex *p;
793 struct gv_sd *s;
794 struct gv_volume *v;
795
796 LIST_FOREACH(v, &sc->volumes, volume) {
797 if (!strncmp(v->name, name, GV_MAXVOLNAME))
798 return (GV_TYPE_VOL);
799 }
800
801 LIST_FOREACH(p, &sc->plexes, plex) {
802 if (!strncmp(p->name, name, GV_MAXPLEXNAME))
803 return (GV_TYPE_PLEX);
804 }
805
806 LIST_FOREACH(s, &sc->subdisks, sd) {
807 if (!strncmp(s->name, name, GV_MAXSDNAME))
808 return (GV_TYPE_SD);
809 }
810
811 LIST_FOREACH(d, &sc->drives, drive) {
812 if (!strncmp(d->name, name, GV_MAXDRIVENAME))
813 return (GV_TYPE_DRIVE);
814 }
815
816 return (-1);
817}
818
819void
43
44#include <sys/param.h>
45#include <sys/conf.h>
46#include <sys/kernel.h>
47#include <sys/libkern.h>
48#include <sys/malloc.h>
49#include <sys/systm.h>
50
51#include <geom/geom.h>
52#include <geom/geom_int.h>
53#include <geom/vinum/geom_vinum_var.h>
54#include <geom/vinum/geom_vinum.h>
55#include <geom/vinum/geom_vinum_share.h>
56
57/* Find the VINUM class and it's associated geom. */
58struct g_geom *
59find_vinum_geom(void)
60{
61 struct g_class *mp;
62 struct g_geom *gp;
63
64 g_topology_assert();
65
66 gp = NULL;
67
68 LIST_FOREACH(mp, &g_classes, class) {
69 if (!strcmp(mp->name, "VINUM")) {
70 gp = LIST_FIRST(&mp->geom);
71 break;
72 }
73 }
74
75 return (gp);
76}
77
78/*
79 * Parse the vinum config provided in *buf and store it in *gp's softc.
80 * If parameter 'merge' is non-zero, then the given config is merged into
81 * *gp.
82 */
83void
84gv_parse_config(struct gv_softc *sc, u_char *buf, int merge)
85{
86 char *aptr, *bptr, *cptr;
87 struct gv_volume *v, *v2;
88 struct gv_plex *p, *p2;
89 struct gv_sd *s, *s2;
90 int tokens;
91 char *token[GV_MAXARGS];
92
93 g_topology_assert();
94
95 KASSERT(sc != NULL, ("gv_parse_config: NULL softc"));
96
97 /* Until the end of the string *buf. */
98 for (aptr = buf; *aptr != '\0'; aptr = bptr) {
99 bptr = aptr;
100 cptr = aptr;
101
102 /* Seperate input lines. */
103 while (*bptr != '\n')
104 bptr++;
105 *bptr = '\0';
106 bptr++;
107
108 tokens = gv_tokenize(cptr, token, GV_MAXARGS);
109
110 if (tokens > 0) {
111 if (!strcmp(token[0], "volume")) {
112 v = gv_new_volume(tokens, token);
113 if (v == NULL) {
114 printf("geom_vinum: failed volume\n");
115 break;
116 }
117
118 if (merge) {
119 v2 = gv_find_vol(sc, v->name);
120 if (v2 != NULL) {
121 g_free(v);
122 continue;
123 }
124 }
125
126 v->vinumconf = sc;
127 LIST_INIT(&v->plexes);
128 LIST_INSERT_HEAD(&sc->volumes, v, volume);
129
130 } else if (!strcmp(token[0], "plex")) {
131 p = gv_new_plex(tokens, token);
132 if (p == NULL) {
133 printf("geom_vinum: failed plex\n");
134 break;
135 }
136
137 if (merge) {
138 p2 = gv_find_plex(sc, p->name);
139 if (p2 != NULL) {
140 g_free(p);
141 continue;
142 }
143 }
144
145 p->vinumconf = sc;
146 LIST_INIT(&p->subdisks);
147 LIST_INSERT_HEAD(&sc->plexes, p, plex);
148
149 } else if (!strcmp(token[0], "sd")) {
150 s = gv_new_sd(tokens, token);
151
152 if (s == NULL) {
153 printf("geom_vinum: failed subdisk\n");
154 break;
155 }
156
157 if (merge) {
158 s2 = gv_find_sd(sc, s->name);
159 if (s2 != NULL) {
160 g_free(s);
161 continue;
162 }
163 }
164
165 s->vinumconf = sc;
166 LIST_INSERT_HEAD(&sc->subdisks, s, sd);
167 }
168 }
169 }
170}
171
172/*
173 * Format the vinum configuration properly. If ondisk is non-zero then the
174 * configuration is intended to be written to disk later.
175 */
176void
177gv_format_config(struct gv_softc *sc, struct sbuf *sb, int ondisk, char *prefix)
178{
179 struct gv_drive *d;
180 struct gv_sd *s;
181 struct gv_plex *p;
182 struct gv_volume *v;
183
184 g_topology_assert();
185
186 /*
187 * We don't need the drive configuration if we're not writing the
188 * config to disk.
189 */
190 if (!ondisk) {
191 LIST_FOREACH(d, &sc->drives, drive) {
192 sbuf_printf(sb, "%sdrive %s device %s\n", prefix,
193 d->name, d->device);
194 }
195 }
196
197 LIST_FOREACH(v, &sc->volumes, volume) {
198 if (!ondisk)
199 sbuf_printf(sb, "%s", prefix);
200 sbuf_printf(sb, "volume %s", v->name);
201 if (ondisk)
202 sbuf_printf(sb, " state %s", gv_volstate(v->state));
203 sbuf_printf(sb, "\n");
204 }
205
206 LIST_FOREACH(p, &sc->plexes, plex) {
207 if (!ondisk)
208 sbuf_printf(sb, "%s", prefix);
209 sbuf_printf(sb, "plex name %s org %s ", p->name,
210 gv_plexorg(p->org));
211 if (gv_is_striped(p))
212 sbuf_printf(sb, "%ds ", p->stripesize / 512);
213 if (p->vol_sc != NULL)
214 sbuf_printf(sb, "vol %s", p->volume);
215 if (ondisk)
216 sbuf_printf(sb, " state %s", gv_plexstate(p->state));
217 sbuf_printf(sb, "\n");
218 }
219
220 LIST_FOREACH(s, &sc->subdisks, sd) {
221 if (!ondisk)
222 sbuf_printf(sb, "%s", prefix);
223 sbuf_printf(sb, "sd name %s drive %s len %jds driveoffset "
224 "%jds", s->name, s->drive, s->size / 512,
225 s->drive_offset / 512);
226 if (s->plex_sc != NULL) {
227 sbuf_printf(sb, " plex %s plexoffset %jds", s->plex,
228 s->plex_offset / 512);
229 }
230 if (ondisk)
231 sbuf_printf(sb, " state %s", gv_sdstate(s->state));
232 sbuf_printf(sb, "\n");
233 }
234
235 return;
236}
237
238/*
239 * Take a size in bytes and return a pointer to a string which represents the
240 * size best. If lj is != 0, return left justified, otherwise in a fixed 10
241 * character field suitable for columnar printing.
242 *
243 * Note this uses a static string: it's only intended to be used immediately
244 * for printing.
245 */
246const char *
247gv_roughlength(off_t bytes, int lj)
248{
249 static char desc[16];
250
251 /* Gigabytes. */
252 if (bytes > (off_t)MEGABYTE * 10000)
253 snprintf(desc, sizeof(desc), lj ? "%jd GB" : "%10jd GB",
254 bytes / GIGABYTE);
255
256 /* Megabytes. */
257 else if (bytes > KILOBYTE * 10000)
258 snprintf(desc, sizeof(desc), lj ? "%jd MB" : "%10jd MB",
259 bytes / MEGABYTE);
260
261 /* Kilobytes. */
262 else if (bytes > 10000)
263 snprintf(desc, sizeof(desc), lj ? "%jd kB" : "%10jd kB",
264 bytes / KILOBYTE);
265
266 /* Bytes. */
267 else
268 snprintf(desc, sizeof(desc), lj ? "%jd B" : "%10jd B", bytes);
269
270 return (desc);
271}
272
273int
274gv_sd_to_plex(struct gv_plex *p, struct gv_sd *s, int check)
275{
276 struct gv_sd *s2;
277
278 g_topology_assert();
279
280 /* If this subdisk was already given to this plex, do nothing. */
281 if (s->plex_sc == p)
282 return (0);
283
284 /* Find the correct plex offset for this subdisk, if needed. */
285 if (s->plex_offset == -1) {
286 if (p->sdcount) {
287 LIST_FOREACH(s2, &p->subdisks, in_plex) {
288 if (gv_is_striped(p))
289 s->plex_offset = p->sdcount *
290 p->stripesize;
291 else
292 s->plex_offset = s2->plex_offset +
293 s2->size;
294 }
295 } else
296 s->plex_offset = 0;
297 }
298
299 p->sdcount++;
300
301 /* Adjust the size of our plex. */
302 switch (p->org) {
303 case GV_PLEX_CONCAT:
304 case GV_PLEX_STRIPED:
305 p->size += s->size;
306 break;
307
308 case GV_PLEX_RAID5:
309 p->size = (p->sdcount - 1) * s->size;
310 break;
311
312 default:
313 break;
314 }
315
316 /* There are no subdisks for this plex yet, just insert it. */
317 if (LIST_EMPTY(&p->subdisks)) {
318 LIST_INSERT_HEAD(&p->subdisks, s, in_plex);
319
320 /* Insert in correct order, depending on plex_offset. */
321 } else {
322 LIST_FOREACH(s2, &p->subdisks, in_plex) {
323 if (s->plex_offset < s2->plex_offset) {
324 LIST_INSERT_BEFORE(s2, s, in_plex);
325 break;
326 } else if (LIST_NEXT(s2, in_plex) == NULL) {
327 LIST_INSERT_AFTER(s2, s, in_plex);
328 break;
329 }
330 }
331 }
332
333 s->plex_sc = p;
334
335 return (0);
336}
337
338void
339gv_update_vol_size(struct gv_volume *v, off_t size)
340{
341 struct g_geom *gp;
342 struct g_provider *pp;
343
344 if (v == NULL)
345 return;
346
347 gp = v->geom;
348 if (gp == NULL)
349 return;
350
351 LIST_FOREACH(pp, &gp->provider, provider) {
352 pp->mediasize = size;
353 }
354
355 v->size = size;
356}
357
358void
359gv_update_plex_config(struct gv_plex *p)
360{
361 struct gv_sd *s, *s2;
362 off_t remainder;
363 int required_sds, state;
364
365 KASSERT(p != NULL, ("gv_update_plex_config: NULL p"));
366
367 /* This is what we want the plex to be. */
368 state = GV_PLEX_UP;
369
370 /* The plex was added to an already running volume. */
371 if (p->flags & GV_PLEX_ADDED)
372 state = GV_PLEX_DOWN;
373
374 switch (p->org) {
375 case GV_PLEX_STRIPED:
376 required_sds = 2;
377 break;
378 case GV_PLEX_RAID5:
379 required_sds = 3;
380 break;
381 case GV_PLEX_CONCAT:
382 default:
383 required_sds = 0;
384 break;
385 }
386
387 if (required_sds) {
388 if (p->sdcount < required_sds) {
389 state = GV_PLEX_DOWN;
390 }
391
392 /*
393 * The subdisks in striped plexes must all have the same size.
394 */
395 s = LIST_FIRST(&p->subdisks);
396 LIST_FOREACH(s2, &p->subdisks, in_plex) {
397 if (s->size != s2->size) {
398 printf("geom_vinum: subdisk size mismatch "
399 "%s (%jd) <> %s (%jd)\n", s->name, s->size,
400 s2->name, s2->size);
401 state = GV_PLEX_DOWN;
402 }
403 }
404
405 /* Trim subdisk sizes so that they match the stripe size. */
406 LIST_FOREACH(s, &p->subdisks, in_plex) {
407 remainder = s->size % p->stripesize;
408 if (remainder) {
409 printf("gvinum: size of sd %s is not a "
410 "multiple of plex stripesize, taking off "
411 "%jd bytes\n", s->name,
412 (intmax_t)remainder);
413 gv_adjust_freespace(s, remainder);
414 }
415 }
416 }
417
418 /* Adjust the size of our plex. */
419 if (p->sdcount > 0) {
420 p->size = 0;
421 switch (p->org) {
422 case GV_PLEX_CONCAT:
423 LIST_FOREACH(s, &p->subdisks, in_plex)
424 p->size += s->size;
425 break;
426
427 case GV_PLEX_STRIPED:
428 s = LIST_FIRST(&p->subdisks);
429 p->size = p->sdcount * s->size;
430 break;
431
432 case GV_PLEX_RAID5:
433 s = LIST_FIRST(&p->subdisks);
434 p->size = (p->sdcount - 1) * s->size;
435 break;
436
437 default:
438 break;
439 }
440 }
441
442 if (p->sdcount == 0)
443 state = GV_PLEX_DOWN;
444 else if ((p->flags & GV_PLEX_ADDED) ||
445 ((p->org == GV_PLEX_RAID5) && (p->flags & GV_PLEX_NEWBORN))) {
446 LIST_FOREACH(s, &p->subdisks, in_plex)
447 s->state = GV_SD_STALE;
448 p->flags &= ~GV_PLEX_ADDED;
449 p->flags &= ~GV_PLEX_NEWBORN;
450 p->state = GV_PLEX_DOWN;
451 }
452}
453
454/*
455 * Give a subdisk to a drive, check and adjust several parameters, adjust
456 * freelist.
457 */
458int
459gv_sd_to_drive(struct gv_softc *sc, struct gv_drive *d, struct gv_sd *s,
460 char *errstr, int errlen)
461{
462 struct gv_sd *s2;
463 struct gv_freelist *fl, *fl2;
464 off_t tmp;
465 int i;
466
467 g_topology_assert();
468
469 fl2 = NULL;
470
471 KASSERT(sc != NULL, ("gv_sd_to_drive: NULL softc"));
472 KASSERT(d != NULL, ("gv_sd_to_drive: NULL drive"));
473 KASSERT(s != NULL, ("gv_sd_to_drive: NULL subdisk"));
474 KASSERT(errstr != NULL, ("gv_sd_to_drive: NULL errstr"));
475 KASSERT(errlen >= ERRBUFSIZ, ("gv_sd_to_drive: short errlen (%d)",
476 errlen));
477
478 /* Check if this subdisk was already given to this drive. */
479 if (s->drive_sc == d)
480 return (0);
481
482 /* Preliminary checks. */
483 if (s->size > d->avail || d->freelist_entries == 0) {
484 snprintf(errstr, errlen, "not enough space on '%s' for '%s'",
485 d->name, s->name);
486 return (-1);
487 }
488
489 /* No size given, autosize it. */
490 if (s->size == -1) {
491 /* Find the largest available slot. */
492 LIST_FOREACH(fl, &d->freelist, freelist) {
493 if (fl->size >= s->size) {
494 s->size = fl->size;
495 s->drive_offset = fl->offset;
496 fl2 = fl;
497 }
498 }
499
500 /* No good slot found? */
501 if (s->size == -1) {
502 snprintf(errstr, errlen, "couldn't autosize '%s' on "
503 "'%s'", s->name, d->name);
504 return (-1);
505 }
506
507 /*
508 * Check if we have a free slot that's large enough for the given size.
509 */
510 } else {
511 i = 0;
512 LIST_FOREACH(fl, &d->freelist, freelist) {
513 /* Yes, this subdisk fits. */
514 if (fl->size >= s->size) {
515 i++;
516 /* Assign drive offset, if not given. */
517 if (s->drive_offset == -1)
518 s->drive_offset = fl->offset;
519 fl2 = fl;
520 break;
521 }
522 }
523
524 /* Couldn't find a good free slot. */
525 if (i == 0) {
526 snprintf(errstr, errlen, "free slots to small for '%s' "
527 "on '%s'", s->name, d->name);
528 return (-1);
529 }
530 }
531
532 /* No drive offset given, try to calculate it. */
533 if (s->drive_offset == -1) {
534
535 /* Add offsets and sizes from other subdisks on this drive. */
536 LIST_FOREACH(s2, &d->subdisks, from_drive) {
537 s->drive_offset = s2->drive_offset + s2->size;
538 }
539
540 /*
541 * If there are no other subdisks yet, then set the default
542 * offset to GV_DATA_START.
543 */
544 if (s->drive_offset == -1)
545 s->drive_offset = GV_DATA_START;
546
547 /* Check if we have a free slot at the given drive offset. */
548 } else {
549 i = 0;
550 LIST_FOREACH(fl, &d->freelist, freelist) {
551 /* Yes, this subdisk fits. */
552 if ((fl->offset <= s->drive_offset) &&
553 (fl->offset + fl->size >=
554 s->drive_offset + s->size)) {
555 i++;
556 fl2 = fl;
557 break;
558 }
559 }
560
561 /* Couldn't find a good free slot. */
562 if (i == 0) {
563 snprintf(errstr, errlen, "given drive_offset for '%s' "
564 "won't fit on '%s'", s->name, d->name);
565 return (-1);
566 }
567 }
568
569 /*
570 * Now that all parameters are checked and set up, we can give the
571 * subdisk to the drive and adjust the freelist.
572 */
573
574 /* First, adjust the freelist. */
575 LIST_FOREACH(fl, &d->freelist, freelist) {
576
577 /* This is the free slot that we have found before. */
578 if (fl == fl2) {
579
580 /*
581 * The subdisk starts at the beginning of the free
582 * slot.
583 */
584 if (fl->offset == s->drive_offset) {
585 fl->offset += s->size;
586 fl->size -= s->size;
587
588 /*
589 * The subdisk uses the whole slot, so remove
590 * it.
591 */
592 if (fl->size == 0) {
593 d->freelist_entries--;
594 LIST_REMOVE(fl, freelist);
595 }
596 /*
597 * The subdisk does not start at the beginning of the
598 * free slot.
599 */
600 } else {
601 tmp = fl->offset + fl->size;
602 fl->size = s->drive_offset - fl->offset;
603
604 /*
605 * The subdisk didn't use the complete rest of
606 * the free slot, so we need to split it.
607 */
608 if (s->drive_offset + s->size != tmp) {
609 fl2 = g_malloc(sizeof(*fl2),
610 M_WAITOK | M_ZERO);
611 fl2->offset = s->drive_offset + s->size;
612 fl2->size = tmp - fl2->offset;
613 LIST_INSERT_AFTER(fl, fl2, freelist);
614 d->freelist_entries++;
615 }
616 }
617 break;
618 }
619 }
620
621 /*
622 * This is the first subdisk on this drive, just insert it into the
623 * list.
624 */
625 if (LIST_EMPTY(&d->subdisks)) {
626 LIST_INSERT_HEAD(&d->subdisks, s, from_drive);
627
628 /* There are other subdisks, so insert this one in correct order. */
629 } else {
630 LIST_FOREACH(s2, &d->subdisks, from_drive) {
631 if (s->drive_offset < s2->drive_offset) {
632 LIST_INSERT_BEFORE(s2, s, from_drive);
633 break;
634 } else if (LIST_NEXT(s2, from_drive) == NULL) {
635 LIST_INSERT_AFTER(s2, s, from_drive);
636 break;
637 }
638 }
639 }
640
641 d->sdcount++;
642 d->avail -= s->size;
643
644 /* Link back from the subdisk to this drive. */
645 s->drive_sc = d;
646
647 return (0);
648}
649
650void
651gv_adjust_freespace(struct gv_sd *s, off_t remainder)
652{
653 struct gv_drive *d;
654 struct gv_freelist *fl, *fl2;
655
656 KASSERT(s != NULL, ("gv_adjust_freespace: NULL s"));
657 d = s->drive_sc;
658 KASSERT(d != NULL, ("gv_adjust_freespace: NULL d"));
659
660 /* First, find the free slot that's immediately after this subdisk. */
661 fl = NULL;
662 LIST_FOREACH(fl, &d->freelist, freelist) {
663 if (fl->offset == s->drive_offset + s->size)
664 break;
665 }
666
667 /* If there is no free slot behind this subdisk, so create one. */
668 if (fl == NULL) {
669
670 fl = g_malloc(sizeof(*fl), M_WAITOK | M_ZERO);
671 fl->size = remainder;
672 fl->offset = s->drive_offset + s->size - remainder;
673
674 if (d->freelist_entries == 0) {
675 LIST_INSERT_HEAD(&d->freelist, fl, freelist);
676 } else {
677 LIST_FOREACH(fl2, &d->freelist, freelist) {
678 if (fl->offset < fl2->offset) {
679 LIST_INSERT_BEFORE(fl2, fl, freelist);
680 break;
681 } else if (LIST_NEXT(fl2, freelist) == NULL) {
682 LIST_INSERT_AFTER(fl2, fl, freelist);
683 break;
684 }
685 }
686 }
687
688 d->freelist_entries++;
689
690 /* Expand the free slot we just found. */
691 } else {
692 fl->offset -= remainder;
693 fl->size += remainder;
694 }
695
696 s->size -= remainder;
697 d->avail += remainder;
698}
699
700/* Check if the given plex is a striped one. */
701int
702gv_is_striped(struct gv_plex *p)
703{
704 KASSERT(p != NULL, ("gv_is_striped: NULL p"));
705 switch(p->org) {
706 case GV_PLEX_STRIPED:
707 case GV_PLEX_RAID5:
708 return (1);
709 default:
710 return (0);
711 }
712}
713
714/* Find a volume by name. */
715struct gv_volume *
716gv_find_vol(struct gv_softc *sc, char *name)
717{
718 struct gv_volume *v;
719
720 LIST_FOREACH(v, &sc->volumes, volume) {
721 if (!strncmp(v->name, name, GV_MAXVOLNAME))
722 return (v);
723 }
724
725 return (NULL);
726}
727
728/* Find a plex by name. */
729struct gv_plex *
730gv_find_plex(struct gv_softc *sc, char *name)
731{
732 struct gv_plex *p;
733
734 LIST_FOREACH(p, &sc->plexes, plex) {
735 if (!strncmp(p->name, name, GV_MAXPLEXNAME))
736 return (p);
737 }
738
739 return (NULL);
740}
741
742/* Find a subdisk by name. */
743struct gv_sd *
744gv_find_sd(struct gv_softc *sc, char *name)
745{
746 struct gv_sd *s;
747
748 LIST_FOREACH(s, &sc->subdisks, sd) {
749 if (!strncmp(s->name, name, GV_MAXSDNAME))
750 return (s);
751 }
752
753 return (NULL);
754}
755
756/* Find a drive by name. */
757struct gv_drive *
758gv_find_drive(struct gv_softc *sc, char *name)
759{
760 struct gv_drive *d;
761
762 LIST_FOREACH(d, &sc->drives, drive) {
763 if (!strncmp(d->name, name, GV_MAXDRIVENAME))
764 return (d);
765 }
766
767 return (NULL);
768}
769
770/* Check if any consumer of the given geom is open. */
771int
772gv_is_open(struct g_geom *gp)
773{
774 struct g_consumer *cp;
775
776 if (gp == NULL)
777 return (0);
778
779 LIST_FOREACH(cp, &gp->consumer, consumer) {
780 if (cp->acr || cp->acw || cp->ace)
781 return (1);
782 }
783
784 return (0);
785}
786
787/* Return the type of object identified by string 'name'. */
788int
789gv_object_type(struct gv_softc *sc, char *name)
790{
791 struct gv_drive *d;
792 struct gv_plex *p;
793 struct gv_sd *s;
794 struct gv_volume *v;
795
796 LIST_FOREACH(v, &sc->volumes, volume) {
797 if (!strncmp(v->name, name, GV_MAXVOLNAME))
798 return (GV_TYPE_VOL);
799 }
800
801 LIST_FOREACH(p, &sc->plexes, plex) {
802 if (!strncmp(p->name, name, GV_MAXPLEXNAME))
803 return (GV_TYPE_PLEX);
804 }
805
806 LIST_FOREACH(s, &sc->subdisks, sd) {
807 if (!strncmp(s->name, name, GV_MAXSDNAME))
808 return (GV_TYPE_SD);
809 }
810
811 LIST_FOREACH(d, &sc->drives, drive) {
812 if (!strncmp(d->name, name, GV_MAXDRIVENAME))
813 return (GV_TYPE_DRIVE);
814 }
815
816 return (-1);
817}
818
819void
820gv_kill_drive_thread(struct gv_drive *d)
821{
822 if (d->flags & GV_DRIVE_THREAD_ACTIVE) {
823 d->flags |= GV_DRIVE_THREAD_DIE;
824 wakeup(d);
825 while (!(d->flags & GV_DRIVE_THREAD_DEAD))
826 tsleep(d, PRIBIO, "gv_die", hz);
827 d->flags &= ~GV_DRIVE_THREAD_ACTIVE;
828 mtx_destroy(&d->bqueue_mtx);
829 }
830}
831
832void
820gv_kill_plex_thread(struct gv_plex *p)
821{
822 if ((p->org == GV_PLEX_RAID5) && (p->flags & GV_PLEX_THREAD_ACTIVE)) {
823 p->flags |= GV_PLEX_THREAD_DIE;
824 wakeup(p);
825 while (!(p->flags & GV_PLEX_THREAD_DEAD))
826 tsleep(p, PRIBIO, "gv_die", hz);
827 p->flags &= ~GV_PLEX_THREAD_ACTIVE;
828 mtx_destroy(&p->worklist_mtx);
829 }
830}
833gv_kill_plex_thread(struct gv_plex *p)
834{
835 if ((p->org == GV_PLEX_RAID5) && (p->flags & GV_PLEX_THREAD_ACTIVE)) {
836 p->flags |= GV_PLEX_THREAD_DIE;
837 wakeup(p);
838 while (!(p->flags & GV_PLEX_THREAD_DEAD))
839 tsleep(p, PRIBIO, "gv_die", hz);
840 p->flags &= ~GV_PLEX_THREAD_ACTIVE;
841 mtx_destroy(&p->worklist_mtx);
842 }
843}