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$");
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 static off_t gv_plex_smallest_sd(struct gv_plex *, off_t);
58
59 /* Find the VINUM class and it's associated geom. */
60 struct g_geom *
61 find_vinum_geom(void)
62 {
63 struct g_class *mp;
64 struct g_geom *gp;
65
66 g_topology_assert();
67
68 gp = NULL;
69
70 LIST_FOREACH(mp, &g_classes, class) {
71 if (!strcmp(mp->name, "VINUM")) {
72 gp = LIST_FIRST(&mp->geom);
73 break;
74 }
75 }
76
77 return (gp);
78 }
79
80 /*
81 * Parse the vinum config provided in *buf and store it in *gp's softc.
82 * If parameter 'merge' is non-zero, then the given config is merged into
83 * *gp.
84 */
85 void
86 gv_parse_config(struct gv_softc *sc, u_char *buf, int merge)
87 {
88 char *aptr, *bptr, *cptr;
89 struct gv_volume *v, *v2;
90 struct gv_plex *p, *p2;
91 struct gv_sd *s, *s2;
92 int tokens;
93 char *token[GV_MAXARGS];
94
95 g_topology_assert();
96
97 KASSERT(sc != NULL, ("gv_parse_config: NULL softc"));
98
99 /* Until the end of the string *buf. */
100 for (aptr = buf; *aptr != '\0'; aptr = bptr) {
101 bptr = aptr;
102 cptr = aptr;
103
104 /* Seperate input lines. */
105 while (*bptr != '\n')
106 bptr++;
107 *bptr = '\0';
108 bptr++;
109
110 tokens = gv_tokenize(cptr, token, GV_MAXARGS);
111
112 if (tokens > 0) {
113 if (!strcmp(token[0], "volume")) {
114 v = gv_new_volume(tokens, token);
115 if (v == NULL) {
116 printf("geom_vinum: failed volume\n");
117 break;
118 }
119
120 if (merge) {
121 v2 = gv_find_vol(sc, v->name);
122 if (v2 != NULL) {
123 g_free(v);
124 continue;
125 }
126 }
127
128 v->vinumconf = sc;
129 LIST_INIT(&v->plexes);
130 LIST_INSERT_HEAD(&sc->volumes, v, volume);
131
132 } else if (!strcmp(token[0], "plex")) {
133 p = gv_new_plex(tokens, token);
134 if (p == NULL) {
135 printf("geom_vinum: failed plex\n");
136 break;
137 }
138
139 if (merge) {
140 p2 = gv_find_plex(sc, p->name);
141 if (p2 != NULL) {
142 g_free(p);
143 continue;
144 }
145 }
146
147 p->vinumconf = sc;
148 LIST_INIT(&p->subdisks);
149 LIST_INSERT_HEAD(&sc->plexes, p, plex);
150
151 } else if (!strcmp(token[0], "sd")) {
152 s = gv_new_sd(tokens, token);
153
154 if (s == NULL) {
155 printf("geom_vinum: failed subdisk\n");
156 break;
157 }
158
159 if (merge) {
160 s2 = gv_find_sd(sc, s->name);
161 if (s2 != NULL) {
162 g_free(s);
163 continue;
164 }
165 }
166
167 s->vinumconf = sc;
168 LIST_INSERT_HEAD(&sc->subdisks, s, sd);
169 }
170 }
171 }
172 }
173
174 /*
175 * Format the vinum configuration properly. If ondisk is non-zero then the
176 * configuration is intended to be written to disk later.
177 */
178 void
179 gv_format_config(struct gv_softc *sc, struct sbuf *sb, int ondisk, char *prefix)
180 {
181 struct gv_drive *d;
182 struct gv_sd *s;
183 struct gv_plex *p;
184 struct gv_volume *v;
185
186 g_topology_assert();
187
188 /*
189 * We don't need the drive configuration if we're not writing the
190 * config to disk.
191 */
192 if (!ondisk) {
193 LIST_FOREACH(d, &sc->drives, drive) {
194 sbuf_printf(sb, "%sdrive %s device /dev/%s\n", prefix,
195 d->name, d->device);
196 }
197 }
198
199 LIST_FOREACH(v, &sc->volumes, volume) {
200 if (!ondisk)
201 sbuf_printf(sb, "%s", prefix);
202 sbuf_printf(sb, "volume %s", v->name);
203 if (ondisk)
204 sbuf_printf(sb, " state %s", gv_volstate(v->state));
205 sbuf_printf(sb, "\n");
206 }
207
208 LIST_FOREACH(p, &sc->plexes, plex) {
209 if (!ondisk)
210 sbuf_printf(sb, "%s", prefix);
211 sbuf_printf(sb, "plex name %s org %s ", p->name,
212 gv_plexorg(p->org));
213 if (gv_is_striped(p))
214 sbuf_printf(sb, "%ds ", p->stripesize / 512);
215 if (p->vol_sc != NULL)
216 sbuf_printf(sb, "vol %s", p->volume);
217 if (ondisk)
218 sbuf_printf(sb, " state %s", gv_plexstate(p->state));
219 sbuf_printf(sb, "\n");
220 }
221
222 LIST_FOREACH(s, &sc->subdisks, sd) {
223 if (!ondisk)
224 sbuf_printf(sb, "%s", prefix);
225 sbuf_printf(sb, "sd name %s drive %s len %jds driveoffset "
226 "%jds", s->name, s->drive, s->size / 512,
227 s->drive_offset / 512);
228 if (s->plex_sc != NULL) {
229 sbuf_printf(sb, " plex %s plexoffset %jds", s->plex,
230 s->plex_offset / 512);
231 }
232 if (ondisk)
233 sbuf_printf(sb, " state %s", gv_sdstate(s->state));
234 sbuf_printf(sb, "\n");
235 }
236
237 return;
238 }
239
240 static off_t
241 gv_plex_smallest_sd(struct gv_plex *p, off_t smallest)
242 {
243 struct gv_sd *s;
244
245 KASSERT(p != NULL, ("gv_plex_smallest_sd: NULL p"));
246
247 LIST_FOREACH(s, &p->subdisks, in_plex) {
248 if (s->size < smallest)
249 smallest = s->size;
250 }
251 return (smallest);
252 }
253
254 int
255 gv_sd_to_plex(struct gv_plex *p, struct gv_sd *s, int check)
256 {
257 struct gv_sd *s2;
258
259 g_topology_assert();
260
261 /* If this subdisk was already given to this plex, do nothing. */
262 if (s->plex_sc == p)
263 return (0);
264
265 /* Check correct size of this subdisk. */
266 s2 = LIST_FIRST(&p->subdisks);
267 if (s2 != NULL && gv_is_striped(p) && (s2->size != s->size)) {
268 printf("GEOM_VINUM: need equal sized subdisks for "
269 "this plex organisation - %s (%jd) <-> %s (%jd)\n",
270 s2->name, s2->size, s->name, s->size);
271 return (-1);
272 }
273
274 /* Find the correct plex offset for this subdisk, if needed. */
275 if (s->plex_offset == -1) {
276 if (p->sdcount) {
277 LIST_FOREACH(s2, &p->subdisks, in_plex) {
278 if (gv_is_striped(p))
279 s->plex_offset = p->sdcount *
280 p->stripesize;
281 else
282 s->plex_offset = s2->plex_offset +
283 s2->size;
284 }
285 } else
286 s->plex_offset = 0;
287 }
288
289 p->sdcount++;
290
291 /* Adjust the size of our plex. */
292 switch (p->org) {
293 case GV_PLEX_CONCAT:
294 case GV_PLEX_STRIPED:
295 p->size += s->size;
296 break;
297
298 case GV_PLEX_RAID5:
299 p->size = (p->sdcount - 1) * gv_plex_smallest_sd(p, s->size);
300 break;
301
302 default:
303 break;
304 }
305
306 /* There are no subdisks for this plex yet, just insert it. */
307 if (LIST_EMPTY(&p->subdisks)) {
308 LIST_INSERT_HEAD(&p->subdisks, s, in_plex);
309
310 /* Insert in correct order, depending on plex_offset. */
311 } else {
312 LIST_FOREACH(s2, &p->subdisks, in_plex) {
313 if (s->plex_offset < s2->plex_offset) {
314 LIST_INSERT_BEFORE(s2, s, in_plex);
315 break;
316 } else if (LIST_NEXT(s2, in_plex) == NULL) {
317 LIST_INSERT_AFTER(s2, s, in_plex);
318 break;
319 }
320 }
321 }
322
323 s->plex_sc = p;
324
325 return (0);
326 }
327
328 void
329 gv_update_vol_size(struct gv_volume *v, off_t size)
330 {
331 struct g_geom *gp;
332 struct g_provider *pp;
333
334 if (v == NULL)
335 return;
336
337 gp = v->geom;
338 if (gp == NULL)
339 return;
340
341 LIST_FOREACH(pp, &gp->provider, provider) {
342 pp->mediasize = size;
343 }
344
345 v->size = size;
346 }
347
348 /* Calculates the plex size. */
349 off_t
350 gv_plex_size(struct gv_plex *p)
351 {
352 struct gv_sd *s;
353 off_t size;
354
355 KASSERT(p != NULL, ("gv_plex_size: NULL p"));
356
357 if (p->sdcount == 0)
358 return (0);
359
360 /* Adjust the size of our plex. */
361 size = 0;
362 switch (p->org) {
363 case GV_PLEX_CONCAT:
364 LIST_FOREACH(s, &p->subdisks, in_plex)
365 size += s->size;
366 break;
367 case GV_PLEX_STRIPED:
368 s = LIST_FIRST(&p->subdisks);
369 size = p->sdcount * s->size;
370 break;
371 case GV_PLEX_RAID5:
372 s = LIST_FIRST(&p->subdisks);
373 size = (p->sdcount - 1) * s->size;
374 break;
375 }
376
377 return (size);
378 }
379
380 /* Returns the size of a volume. */
381 off_t
382 gv_vol_size(struct gv_volume *v)
383 {
384 struct gv_plex *p;
385 off_t minplexsize;
386
387 KASSERT(v != NULL, ("gv_vol_size: NULL v"));
388
389 p = LIST_FIRST(&v->plexes);
390 if (p == NULL)
391 return (0);
392
393 minplexsize = p->size;
394 LIST_FOREACH(p, &v->plexes, plex) {
395 if (p->size < minplexsize) {
396 minplexsize = p->size;
397 }
398 }
399 return (minplexsize);
400 }
401
402 void
403 gv_update_plex_config(struct gv_plex *p)
404 {
405 struct gv_sd *s, *s2;
406 off_t remainder;
407 int required_sds, state;
408
409 KASSERT(p != NULL, ("gv_update_plex_config: NULL p"));
410
411 /* This is what we want the plex to be. */
412 state = GV_PLEX_UP;
413
414 /* The plex was added to an already running volume. */
415 if (p->flags & GV_PLEX_ADDED)
416 state = GV_PLEX_DOWN;
417
418 switch (p->org) {
419 case GV_PLEX_STRIPED:
420 required_sds = 2;
421 break;
422 case GV_PLEX_RAID5:
423 required_sds = 3;
424 break;
425 case GV_PLEX_CONCAT:
426 default:
427 required_sds = 0;
428 break;
429 }
430
431 if (required_sds) {
432 if (p->sdcount < required_sds) {
433 state = GV_PLEX_DOWN;
434 }
435
436 /*
437 * The subdisks in striped plexes must all have the same size.
438 */
439 s = LIST_FIRST(&p->subdisks);
440 LIST_FOREACH(s2, &p->subdisks, in_plex) {
441 if (s->size != s2->size) {
442 printf("geom_vinum: subdisk size mismatch "
443 "%s (%jd) <> %s (%jd)\n", s->name, s->size,
444 s2->name, s2->size);
445 state = GV_PLEX_DOWN;
446 }
447 }
448
449 /* Trim subdisk sizes so that they match the stripe size. */
450 LIST_FOREACH(s, &p->subdisks, in_plex) {
451 remainder = s->size % p->stripesize;
452 if (remainder) {
453 printf("gvinum: size of sd %s is not a "
454 "multiple of plex stripesize, taking off "
455 "%jd bytes\n", s->name,
456 (intmax_t)remainder);
457 gv_adjust_freespace(s, remainder);
458 }
459 }
460 }
461
462 /* Adjust the size of our plex. */
463 if (p->sdcount > 0) {
464 p->size = 0;
465 switch (p->org) {
466 case GV_PLEX_CONCAT:
467 LIST_FOREACH(s, &p->subdisks, in_plex)
468 p->size += s->size;
469 break;
470
471 case GV_PLEX_STRIPED:
472 s = LIST_FIRST(&p->subdisks);
473 p->size = p->sdcount * s->size;
474 break;
475
476 case GV_PLEX_RAID5:
477 s = LIST_FIRST(&p->subdisks);
478 p->size = (p->sdcount - 1) * s->size;
479 break;
480
481 default:
482 break;
483 }
484 }
485
486 if (p->sdcount == 0)
487 state = GV_PLEX_DOWN;
488 else if ((p->flags & GV_PLEX_ADDED) ||
489 ((p->org == GV_PLEX_RAID5) && (p->flags & GV_PLEX_NEWBORN))) {
490 LIST_FOREACH(s, &p->subdisks, in_plex)
491 s->state = GV_SD_STALE;
492 p->flags &= ~GV_PLEX_ADDED;
493 p->flags &= ~GV_PLEX_NEWBORN;
494 p->state = GV_PLEX_DOWN;
495 }
496 }
497
498 /*
499 * Give a subdisk to a drive, check and adjust several parameters, adjust
500 * freelist.
501 */
502 int
503 gv_sd_to_drive(struct gv_softc *sc, struct gv_drive *d, struct gv_sd *s,
504 char *errstr, int errlen)
505 {
506 struct gv_sd *s2;
507 struct gv_freelist *fl, *fl2;
508 off_t tmp;
509 int i;
510
511 g_topology_assert();
512
513 fl2 = NULL;
514
515 KASSERT(sc != NULL, ("gv_sd_to_drive: NULL softc"));
516 KASSERT(d != NULL, ("gv_sd_to_drive: NULL drive"));
517 KASSERT(s != NULL, ("gv_sd_to_drive: NULL subdisk"));
518 KASSERT(errstr != NULL, ("gv_sd_to_drive: NULL errstr"));
519 KASSERT(errlen >= ERRBUFSIZ, ("gv_sd_to_drive: short errlen (%d)",
520 errlen));
521
522 /* Check if this subdisk was already given to this drive. */
523 if (s->drive_sc == d)
524 return (0);
525
526 /* Preliminary checks. */
527 if (s->size > d->avail || d->freelist_entries == 0) {
528 snprintf(errstr, errlen, "not enough space on '%s' for '%s'",
529 d->name, s->name);
530 return (-1);
531 }
532
533 /* No size given, autosize it. */
534 if (s->size == -1) {
535 /* Find the largest available slot. */
536 LIST_FOREACH(fl, &d->freelist, freelist) {
537 if (fl->size >= s->size) {
538 s->size = fl->size;
539 s->drive_offset = fl->offset;
540 fl2 = fl;
541 }
542 }
543
544 /* No good slot found? */
545 if (s->size == -1) {
546 snprintf(errstr, errlen, "couldn't autosize '%s' on "
547 "'%s'", s->name, d->name);
548 return (-1);
549 }
550
551 /*
552 * Check if we have a free slot that's large enough for the given size.
553 */
554 } else {
555 i = 0;
556 LIST_FOREACH(fl, &d->freelist, freelist) {
557 /* Yes, this subdisk fits. */
558 if (fl->size >= s->size) {
559 i++;
560 /* Assign drive offset, if not given. */
561 if (s->drive_offset == -1)
562 s->drive_offset = fl->offset;
563 fl2 = fl;
564 break;
565 }
566 }
567
568 /* Couldn't find a good free slot. */
569 if (i == 0) {
570 snprintf(errstr, errlen, "free slots to small for '%s' "
571 "on '%s'", s->name, d->name);
572 return (-1);
573 }
574 }
575
576 /* No drive offset given, try to calculate it. */
577 if (s->drive_offset == -1) {
578
579 /* Add offsets and sizes from other subdisks on this drive. */
580 LIST_FOREACH(s2, &d->subdisks, from_drive) {
581 s->drive_offset = s2->drive_offset + s2->size;
582 }
583
584 /*
585 * If there are no other subdisks yet, then set the default
586 * offset to GV_DATA_START.
587 */
588 if (s->drive_offset == -1)
589 s->drive_offset = GV_DATA_START;
590
591 /* Check if we have a free slot at the given drive offset. */
592 } else {
593 i = 0;
594 LIST_FOREACH(fl, &d->freelist, freelist) {
595 /* Yes, this subdisk fits. */
596 if ((fl->offset <= s->drive_offset) &&
597 (fl->offset + fl->size >=
598 s->drive_offset + s->size)) {
599 i++;
600 fl2 = fl;
601 break;
602 }
603 }
604
605 /* Couldn't find a good free slot. */
606 if (i == 0) {
607 snprintf(errstr, errlen, "given drive_offset for '%s' "
608 "won't fit on '%s'", s->name, d->name);
609 return (-1);
610 }
611 }
612
613 /*
614 * Now that all parameters are checked and set up, we can give the
615 * subdisk to the drive and adjust the freelist.
616 */
617
618 /* First, adjust the freelist. */
619 LIST_FOREACH(fl, &d->freelist, freelist) {
620
621 /* This is the free slot that we have found before. */
622 if (fl == fl2) {
623
624 /*
625 * The subdisk starts at the beginning of the free
626 * slot.
627 */
628 if (fl->offset == s->drive_offset) {
629 fl->offset += s->size;
630 fl->size -= s->size;
631
632 /*
633 * The subdisk uses the whole slot, so remove
634 * it.
635 */
636 if (fl->size == 0) {
637 d->freelist_entries--;
638 LIST_REMOVE(fl, freelist);
639 }
640 /*
641 * The subdisk does not start at the beginning of the
642 * free slot.
643 */
644 } else {
645 tmp = fl->offset + fl->size;
646 fl->size = s->drive_offset - fl->offset;
647
648 /*
649 * The subdisk didn't use the complete rest of
650 * the free slot, so we need to split it.
651 */
652 if (s->drive_offset + s->size != tmp) {
653 fl2 = g_malloc(sizeof(*fl2),
654 M_WAITOK | M_ZERO);
655 fl2->offset = s->drive_offset + s->size;
656 fl2->size = tmp - fl2->offset;
657 LIST_INSERT_AFTER(fl, fl2, freelist);
658 d->freelist_entries++;
659 }
660 }
661 break;
662 }
663 }
664
665 /*
666 * This is the first subdisk on this drive, just insert it into the
667 * list.
668 */
669 if (LIST_EMPTY(&d->subdisks)) {
670 LIST_INSERT_HEAD(&d->subdisks, s, from_drive);
671
672 /* There are other subdisks, so insert this one in correct order. */
673 } else {
674 LIST_FOREACH(s2, &d->subdisks, from_drive) {
675 if (s->drive_offset < s2->drive_offset) {
676 LIST_INSERT_BEFORE(s2, s, from_drive);
677 break;
678 } else if (LIST_NEXT(s2, from_drive) == NULL) {
679 LIST_INSERT_AFTER(s2, s, from_drive);
680 break;
681 }
682 }
683 }
684
685 d->sdcount++;
686 d->avail -= s->size;
687
688 /* Link back from the subdisk to this drive. */
689 s->drive_sc = d;
690
691 return (0);
692 }
693
694 void
695 gv_free_sd(struct gv_sd *s)
696 {
697 struct gv_drive *d;
698 struct gv_freelist *fl, *fl2;
699
700 KASSERT(s != NULL, ("gv_free_sd: NULL s"));
701
702 d = s->drive_sc;
703 if (d == NULL)
704 return;
705
706 /*
707 * First, find the free slot that's immediately before or after this
708 * subdisk.
709 */
710 fl = NULL;
711 LIST_FOREACH(fl, &d->freelist, freelist) {
712 if (fl->offset == s->drive_offset + s->size)
713 break;
714 if (fl->offset + fl->size == s->drive_offset)
715 break;
716 }
717
718 /* If there is no free slot behind this subdisk, so create one. */
719 if (fl == NULL) {
720
721 fl = g_malloc(sizeof(*fl), M_WAITOK | M_ZERO);
722 fl->size = s->size;
723 fl->offset = s->drive_offset;
724
725 if (d->freelist_entries == 0) {
726 LIST_INSERT_HEAD(&d->freelist, fl, freelist);
727 } else {
728 LIST_FOREACH(fl2, &d->freelist, freelist) {
729 if (fl->offset < fl2->offset) {
730 LIST_INSERT_BEFORE(fl2, fl, freelist);
731 break;
732 } else if (LIST_NEXT(fl2, freelist) == NULL) {
733 LIST_INSERT_AFTER(fl2, fl, freelist);
734 break;
735 }
736 }
737 }
738
739 d->freelist_entries++;
740
741 /* Expand the free slot we just found. */
742 } else {
743 fl->size += s->size;
744 if (fl->offset > s->drive_offset)
745 fl->offset = s->drive_offset;
746 }
747
748 d->avail += s->size;
749 d->sdcount--;
750 }
751
752 void
753 gv_adjust_freespace(struct gv_sd *s, off_t remainder)
754 {
755 struct gv_drive *d;
756 struct gv_freelist *fl, *fl2;
757
758 KASSERT(s != NULL, ("gv_adjust_freespace: NULL s"));
759 d = s->drive_sc;
760 KASSERT(d != NULL, ("gv_adjust_freespace: NULL d"));
761
762 /* First, find the free slot that's immediately after this subdisk. */
763 fl = NULL;
764 LIST_FOREACH(fl, &d->freelist, freelist) {
765 if (fl->offset == s->drive_offset + s->size)
766 break;
767 }
768
769 /* If there is no free slot behind this subdisk, so create one. */
770 if (fl == NULL) {
771
772 fl = g_malloc(sizeof(*fl), M_WAITOK | M_ZERO);
773 fl->size = remainder;
774 fl->offset = s->drive_offset + s->size - remainder;
775
776 if (d->freelist_entries == 0) {
777 LIST_INSERT_HEAD(&d->freelist, fl, freelist);
778 } else {
779 LIST_FOREACH(fl2, &d->freelist, freelist) {
780 if (fl->offset < fl2->offset) {
781 LIST_INSERT_BEFORE(fl2, fl, freelist);
782 break;
783 } else if (LIST_NEXT(fl2, freelist) == NULL) {
784 LIST_INSERT_AFTER(fl2, fl, freelist);
785 break;
786 }
787 }
788 }
789
790 d->freelist_entries++;
791
792 /* Expand the free slot we just found. */
793 } else {
794 fl->offset -= remainder;
795 fl->size += remainder;
796 }
797
798 s->size -= remainder;
799 d->avail += remainder;
800 }
801
802 /* Check if the given plex is a striped one. */
803 int
804 gv_is_striped(struct gv_plex *p)
805 {
806 KASSERT(p != NULL, ("gv_is_striped: NULL p"));
807 switch(p->org) {
808 case GV_PLEX_STRIPED:
809 case GV_PLEX_RAID5:
810 return (1);
811 default:
812 return (0);
813 }
814 }
815
816 /* Find a volume by name. */
817 struct gv_volume *
818 gv_find_vol(struct gv_softc *sc, char *name)
819 {
820 struct gv_volume *v;
821
822 LIST_FOREACH(v, &sc->volumes, volume) {
823 if (!strncmp(v->name, name, GV_MAXVOLNAME))
824 return (v);
825 }
826
827 return (NULL);
828 }
829
830 /* Find a plex by name. */
831 struct gv_plex *
832 gv_find_plex(struct gv_softc *sc, char *name)
833 {
834 struct gv_plex *p;
835
836 LIST_FOREACH(p, &sc->plexes, plex) {
837 if (!strncmp(p->name, name, GV_MAXPLEXNAME))
838 return (p);
839 }
840
841 return (NULL);
842 }
843
844 /* Find a subdisk by name. */
845 struct gv_sd *
846 gv_find_sd(struct gv_softc *sc, char *name)
847 {
848 struct gv_sd *s;
849
850 LIST_FOREACH(s, &sc->subdisks, sd) {
851 if (!strncmp(s->name, name, GV_MAXSDNAME))
852 return (s);
853 }
854
855 return (NULL);
856 }
857
858 /* Find a drive by name. */
859 struct gv_drive *
860 gv_find_drive(struct gv_softc *sc, char *name)
861 {
862 struct gv_drive *d;
863
864 LIST_FOREACH(d, &sc->drives, drive) {
865 if (!strncmp(d->name, name, GV_MAXDRIVENAME))
866 return (d);
867 }
868
869 return (NULL);
870 }
871
872 /* Check if any consumer of the given geom is open. */
873 int
874 gv_is_open(struct g_geom *gp)
875 {
876 struct g_consumer *cp;
877
878 if (gp == NULL)
879 return (0);
880
881 LIST_FOREACH(cp, &gp->consumer, consumer) {
882 if (cp->acr || cp->acw || cp->ace)
883 return (1);
884 }
885
886 return (0);
887 }
888
889 /* Return the type of object identified by string 'name'. */
890 int
891 gv_object_type(struct gv_softc *sc, char *name)
892 {
893 struct gv_drive *d;
894 struct gv_plex *p;
895 struct gv_sd *s;
896 struct gv_volume *v;
897
898 LIST_FOREACH(v, &sc->volumes, volume) {
899 if (!strncmp(v->name, name, GV_MAXVOLNAME))
900 return (GV_TYPE_VOL);
901 }
902
903 LIST_FOREACH(p, &sc->plexes, plex) {
904 if (!strncmp(p->name, name, GV_MAXPLEXNAME))
905 return (GV_TYPE_PLEX);
906 }
907
908 LIST_FOREACH(s, &sc->subdisks, sd) {
909 if (!strncmp(s->name, name, GV_MAXSDNAME))
910 return (GV_TYPE_SD);
911 }
912
913 LIST_FOREACH(d, &sc->drives, drive) {
914 if (!strncmp(d->name, name, GV_MAXDRIVENAME))
915 return (GV_TYPE_DRIVE);
916 }
917
918 return (-1);
919 }
920
921 void
922 gv_kill_drive_thread(struct gv_drive *d)
923 {
924 if (d->flags & GV_DRIVE_THREAD_ACTIVE) {
925 d->flags |= GV_DRIVE_THREAD_DIE;
926 wakeup(d);
927 while (!(d->flags & GV_DRIVE_THREAD_DEAD))
928 tsleep(d, PRIBIO, "gv_die", hz);
929 d->flags &= ~GV_DRIVE_THREAD_ACTIVE;
930 d->flags &= ~GV_DRIVE_THREAD_DIE;
931 d->flags &= ~GV_DRIVE_THREAD_DEAD;
932 g_free(d->bqueue);
933 d->bqueue = NULL;
934 mtx_destroy(&d->bqueue_mtx);
935 }
936 }
937
938 void
939 gv_kill_plex_thread(struct gv_plex *p)
940 {
941 if (p->flags & GV_PLEX_THREAD_ACTIVE) {
942 p->flags |= GV_PLEX_THREAD_DIE;
943 wakeup(p);
944 while (!(p->flags & GV_PLEX_THREAD_DEAD))
945 tsleep(p, PRIBIO, "gv_die", hz);
946 p->flags &= ~GV_PLEX_THREAD_ACTIVE;
947 p->flags &= ~GV_PLEX_THREAD_DIE;
948 p->flags &= ~GV_PLEX_THREAD_DEAD;
949 g_free(p->bqueue);
950 g_free(p->wqueue);
951 p->bqueue = NULL;
952 p->wqueue = NULL;
953 mtx_destroy(&p->bqueue_mtx);
954 }
955 }
956
957 void
958 gv_kill_vol_thread(struct gv_volume *v)
959 {
960 if (v->flags & GV_VOL_THREAD_ACTIVE) {
961 v->flags |= GV_VOL_THREAD_DIE;
962 wakeup(v);
963 while (!(v->flags & GV_VOL_THREAD_DEAD))
964 tsleep(v, PRIBIO, "gv_die", hz);
965 v->flags &= ~GV_VOL_THREAD_ACTIVE;
966 v->flags &= ~GV_VOL_THREAD_DIE;
967 v->flags &= ~GV_VOL_THREAD_DEAD;
968 g_free(v->bqueue);
969 v->bqueue = NULL;
970 mtx_destroy(&v->bqueue_mtx);
971 }
972 }
Cache object: 291bfb708a8daf821c5cd8dd56e088f7
|