xref: /freebsd/sys/geom/vinum/geom_vinum_subr.c (revision e17f5b1d)
1 /*-
2  * SPDX-License-Identifier: BSD-4-Clause
3  *
4  * Copyright (c) 2004, 2007 Lukas Ertl
5  * Copyright (c) 2007, 2009 Ulf Lilleengen
6  * Copyright (c) 1997, 1998, 1999
7  *      Nan Yang Computer Services Limited.  All rights reserved.
8  *
9  *  Parts written by Greg Lehey
10  *
11  *  This software is distributed under the so-called ``Berkeley
12  *  License'':
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions
16  * are met:
17  * 1. Redistributions of source code must retain the above copyright
18  *    notice, this list of conditions and the following disclaimer.
19  * 2. Redistributions in binary form must reproduce the above copyright
20  *    notice, this list of conditions and the following disclaimer in the
21  *    documentation and/or other materials provided with the distribution.
22  * 3. All advertising materials mentioning features or use of this software
23  *    must display the following acknowledgement:
24  *      This product includes software developed by Nan Yang Computer
25  *      Services Limited.
26  * 4. Neither the name of the Company nor the names of its contributors
27  *    may be used to endorse or promote products derived from this software
28  *    without specific prior written permission.
29  *
30  * This software is provided ``as is'', and any express or implied
31  * warranties, including, but not limited to, the implied warranties of
32  * merchantability and fitness for a particular purpose are disclaimed.
33  * In no event shall the company or contributors be liable for any
34  * direct, indirect, incidental, special, exemplary, or consequential
35  * damages (including, but not limited to, procurement of substitute
36  * goods or services; loss of use, data, or profits; or business
37  * interruption) however caused and on any theory of liability, whether
38  * in contract, strict liability, or tort (including negligence or
39  * otherwise) arising in any way out of the use of this software, even if
40  * advised of the possibility of such damage.
41  *
42  */
43 
44 #include <sys/cdefs.h>
45 __FBSDID("$FreeBSD$");
46 
47 #include <sys/param.h>
48 #include <sys/malloc.h>
49 #include <sys/sbuf.h>
50 #include <sys/systm.h>
51 
52 #include <geom/geom.h>
53 #include <geom/geom_dbg.h>
54 #include <geom/vinum/geom_vinum_var.h>
55 #include <geom/vinum/geom_vinum.h>
56 #include <geom/vinum/geom_vinum_share.h>
57 
58 int	gv_drive_is_newer(struct gv_softc *, struct gv_drive *);
59 static off_t gv_plex_smallest_sd(struct gv_plex *);
60 
61 void
62 gv_parse_config(struct gv_softc *sc, char *buf, struct gv_drive *d)
63 {
64 	char *aptr, *bptr, *cptr;
65 	struct gv_volume *v, *v2;
66 	struct gv_plex *p, *p2;
67 	struct gv_sd *s, *s2;
68 	int error, is_newer, tokens;
69 	char *token[GV_MAXARGS];
70 
71 	is_newer = gv_drive_is_newer(sc, d);
72 
73 	/* Until the end of the string *buf. */
74 	for (aptr = buf; *aptr != '\0'; aptr = bptr) {
75 		bptr = aptr;
76 		cptr = aptr;
77 
78 		/* Separate input lines. */
79 		while (*bptr != '\n')
80 			bptr++;
81 		*bptr = '\0';
82 		bptr++;
83 
84 		tokens = gv_tokenize(cptr, token, GV_MAXARGS);
85 
86 		if (tokens <= 0)
87 			continue;
88 
89 		if (!strcmp(token[0], "volume")) {
90 			v = gv_new_volume(tokens, token);
91 			if (v == NULL) {
92 				G_VINUM_DEBUG(0, "config parse failed volume");
93 				break;
94 			}
95 
96 			v2 = gv_find_vol(sc, v->name);
97 			if (v2 != NULL) {
98 				if (is_newer) {
99 					v2->state = v->state;
100 					G_VINUM_DEBUG(2, "newer volume found!");
101 				}
102 				g_free(v);
103 				continue;
104 			}
105 
106 			gv_create_volume(sc, v);
107 
108 		} else if (!strcmp(token[0], "plex")) {
109 			p = gv_new_plex(tokens, token);
110 			if (p == NULL) {
111 				G_VINUM_DEBUG(0, "config parse failed plex");
112 				break;
113 			}
114 
115 			p2 = gv_find_plex(sc, p->name);
116 			if (p2 != NULL) {
117 				/* XXX */
118 				if (is_newer) {
119 					p2->state = p->state;
120 					G_VINUM_DEBUG(2, "newer plex found!");
121 				}
122 				g_free(p);
123 				continue;
124 			}
125 
126 			error = gv_create_plex(sc, p);
127 			if (error)
128 				continue;
129 			/*
130 			 * These flags were set in gv_create_plex() and are not
131 			 * needed here (on-disk config parsing).
132 			 */
133 			p->flags &= ~GV_PLEX_ADDED;
134 
135 		} else if (!strcmp(token[0], "sd")) {
136 			s = gv_new_sd(tokens, token);
137 
138 			if (s == NULL) {
139 				G_VINUM_DEBUG(0, "config parse failed subdisk");
140 				break;
141 			}
142 
143 			s2 = gv_find_sd(sc, s->name);
144 			if (s2 != NULL) {
145 				/* XXX */
146 				if (is_newer) {
147 					s2->state = s->state;
148 					G_VINUM_DEBUG(2, "newer subdisk found!");
149 				}
150 				g_free(s);
151 				continue;
152 			}
153 
154 			/*
155 			 * Signal that this subdisk was tasted, and could
156 			 * possibly reference a drive that isn't in our config
157 			 * yet.
158 			 */
159 			s->flags |= GV_SD_TASTED;
160 
161 			if (s->state == GV_SD_UP)
162 				s->flags |= GV_SD_CANGOUP;
163 
164 			error = gv_create_sd(sc, s);
165 			if (error)
166 				continue;
167 
168 			/*
169 			 * This flag was set in gv_create_sd() and is not
170 			 * needed here (on-disk config parsing).
171 			 */
172 			s->flags &= ~GV_SD_NEWBORN;
173 			s->flags &= ~GV_SD_GROW;
174 		}
175 	}
176 }
177 
178 /*
179  * Format the vinum configuration properly.  If ondisk is non-zero then the
180  * configuration is intended to be written to disk later.
181  */
182 void
183 gv_format_config(struct gv_softc *sc, struct sbuf *sb, int ondisk, char *prefix)
184 {
185 	struct gv_drive *d;
186 	struct gv_sd *s;
187 	struct gv_plex *p;
188 	struct gv_volume *v;
189 
190 	/*
191 	 * We don't need the drive configuration if we're not writing the
192 	 * config to disk.
193 	 */
194 	if (!ondisk) {
195 		LIST_FOREACH(d, &sc->drives, drive) {
196 			sbuf_printf(sb, "%sdrive %s device /dev/%s\n", prefix,
197 			    d->name, d->device);
198 		}
199 	}
200 
201 	LIST_FOREACH(v, &sc->volumes, volume) {
202 		if (!ondisk)
203 			sbuf_printf(sb, "%s", prefix);
204 		sbuf_printf(sb, "volume %s", v->name);
205 		if (ondisk)
206 			sbuf_printf(sb, " state %s", gv_volstate(v->state));
207 		sbuf_printf(sb, "\n");
208 	}
209 
210 	LIST_FOREACH(p, &sc->plexes, plex) {
211 		if (!ondisk)
212 			sbuf_printf(sb, "%s", prefix);
213 		sbuf_printf(sb, "plex name %s org %s ", p->name,
214 		    gv_plexorg(p->org));
215 		if (gv_is_striped(p))
216 			sbuf_printf(sb, "%ds ", p->stripesize / 512);
217 		if (p->vol_sc != NULL)
218 			sbuf_printf(sb, "vol %s", p->volume);
219 		if (ondisk)
220 			sbuf_printf(sb, " state %s", gv_plexstate(p->state));
221 		sbuf_printf(sb, "\n");
222 	}
223 
224 	LIST_FOREACH(s, &sc->subdisks, sd) {
225 		if (!ondisk)
226 			sbuf_printf(sb, "%s", prefix);
227 		sbuf_printf(sb, "sd name %s drive %s len %jds driveoffset "
228 		    "%jds", s->name, s->drive, s->size / 512,
229 		    s->drive_offset / 512);
230 		if (s->plex_sc != NULL) {
231 			sbuf_printf(sb, " plex %s plexoffset %jds", s->plex,
232 			    s->plex_offset / 512);
233 		}
234 		if (ondisk)
235 			sbuf_printf(sb, " state %s", gv_sdstate(s->state));
236 		sbuf_printf(sb, "\n");
237 	}
238 }
239 
240 static off_t
241 gv_plex_smallest_sd(struct gv_plex *p)
242 {
243 	struct gv_sd *s;
244 	off_t smallest;
245 
246 	KASSERT(p != NULL, ("gv_plex_smallest_sd: NULL p"));
247 
248 	s = LIST_FIRST(&p->subdisks);
249 	if (s == NULL)
250 		return (-1);
251 	smallest = s->size;
252 	LIST_FOREACH(s, &p->subdisks, in_plex) {
253 		if (s->size < smallest)
254 			smallest = s->size;
255 	}
256 	return (smallest);
257 }
258 
259 /* Walk over plexes in a volume and count how many are down. */
260 int
261 gv_plexdown(struct gv_volume *v)
262 {
263 	int plexdown;
264 	struct gv_plex *p;
265 
266 	KASSERT(v != NULL, ("gv_plexdown: NULL v"));
267 
268 	plexdown = 0;
269 
270 	LIST_FOREACH(p, &v->plexes, plex) {
271 		if (p->state == GV_PLEX_DOWN)
272 			plexdown++;
273 	}
274 	return (plexdown);
275 }
276 
277 int
278 gv_sd_to_plex(struct gv_sd *s, struct gv_plex *p)
279 {
280 	struct gv_sd *s2;
281 	off_t psizeorig, remainder, smallest;
282 
283 	/* If this subdisk was already given to this plex, do nothing. */
284 	if (s->plex_sc == p)
285 		return (0);
286 
287 	/* Check correct size of this subdisk. */
288 	s2 = LIST_FIRST(&p->subdisks);
289 	/* Adjust the subdisk-size if necessary. */
290 	if (s2 != NULL && gv_is_striped(p)) {
291 		/* First adjust to the stripesize. */
292 		remainder = s->size % p->stripesize;
293 
294 		if (remainder) {
295 			G_VINUM_DEBUG(1, "size of sd %s is not a "
296 			    "multiple of plex stripesize, taking off "
297 			    "%jd bytes", s->name,
298 			    (intmax_t)remainder);
299 			gv_adjust_freespace(s, remainder);
300 		}
301 
302 		smallest = gv_plex_smallest_sd(p);
303 		/* Then take off extra if other subdisks are smaller. */
304 		remainder = s->size - smallest;
305 
306 		/*
307 		 * Don't allow a remainder below zero for running plexes, it's too
308 		 * painful, and if someone were to accidentally do this, the
309 		 * resulting array might be smaller than the original... not god
310 		 */
311 		if (remainder < 0) {
312 			if (!(p->flags & GV_PLEX_NEWBORN)) {
313 				G_VINUM_DEBUG(0, "sd %s too small for plex %s!",
314 				    s->name, p->name);
315 				return (GV_ERR_BADSIZE);
316 			}
317 			/* Adjust other subdisks. */
318 			LIST_FOREACH(s2, &p->subdisks, in_plex) {
319 				G_VINUM_DEBUG(1, "size of sd %s is to big, "
320 				    "taking off %jd bytes", s->name,
321 				    (intmax_t)remainder);
322 				gv_adjust_freespace(s2, (remainder * -1));
323 			}
324 		} else if (remainder > 0) {
325 			G_VINUM_DEBUG(1, "size of sd %s is to big, "
326 			    "taking off %jd bytes", s->name,
327 			    (intmax_t)remainder);
328 			gv_adjust_freespace(s, remainder);
329 		}
330 	}
331 
332 	/* Find the correct plex offset for this subdisk, if needed. */
333 	if (s->plex_offset == -1) {
334 		/*
335 		 * First set it to 0 to catch the case where we had a detached
336 		 * subdisk that didn't get any good offset.
337 		 */
338 		s->plex_offset = 0;
339 		if (p->sdcount) {
340 			LIST_FOREACH(s2, &p->subdisks, in_plex) {
341 				if (gv_is_striped(p))
342 					s->plex_offset = p->sdcount *
343 					    p->stripesize;
344 				else
345 					s->plex_offset = s2->plex_offset +
346 					    s2->size;
347 			}
348 		}
349 	}
350 
351 	/* There are no subdisks for this plex yet, just insert it. */
352 	if (LIST_EMPTY(&p->subdisks)) {
353 		LIST_INSERT_HEAD(&p->subdisks, s, in_plex);
354 
355 	/* Insert in correct order, depending on plex_offset. */
356 	} else {
357 		LIST_FOREACH(s2, &p->subdisks, in_plex) {
358 			if (s->plex_offset < s2->plex_offset) {
359 				LIST_INSERT_BEFORE(s2, s, in_plex);
360 				break;
361 			} else if (LIST_NEXT(s2, in_plex) == NULL) {
362 				LIST_INSERT_AFTER(s2, s, in_plex);
363 				break;
364 			}
365 		}
366 	}
367 
368 	s->plex_sc = p;
369         /* Adjust the size of our plex. We check if the plex misses a subdisk,
370 	 * so we don't make the plex smaller than it actually should be.
371 	 */
372 	psizeorig = p->size;
373 	p->size = gv_plex_size(p);
374 	/* Make sure the size is not changed. */
375 	if (p->sddetached > 0) {
376 		if (p->size < psizeorig) {
377 			p->size = psizeorig;
378 			/* We make sure wee need another subdisk. */
379 			if (p->sddetached == 1)
380 				p->sddetached++;
381 		}
382 		p->sddetached--;
383 	} else {
384 		if ((p->org == GV_PLEX_RAID5 ||
385 		    p->org == GV_PLEX_STRIPED) &&
386 		    !(p->flags & GV_PLEX_NEWBORN) &&
387 		    p->state == GV_PLEX_UP) {
388 			s->flags |= GV_SD_GROW;
389 		}
390 		p->sdcount++;
391 	}
392 
393 	return (0);
394 }
395 
396 void
397 gv_update_vol_size(struct gv_volume *v, off_t size)
398 {
399 	if (v == NULL)
400 		return;
401 	if (v->provider != NULL) {
402 		g_topology_lock();
403 		v->provider->mediasize = size;
404 		g_topology_unlock();
405 	}
406 	v->size = size;
407 }
408 
409 /* Return how many subdisks that constitute the original plex. */
410 int
411 gv_sdcount(struct gv_plex *p, int growing)
412 {
413 	struct gv_sd *s;
414 	int sdcount;
415 
416 	sdcount = p->sdcount;
417 	if (growing) {
418 		LIST_FOREACH(s, &p->subdisks, in_plex) {
419 			if (s->flags & GV_SD_GROW)
420 				sdcount--;
421 		}
422 	}
423 
424 	return (sdcount);
425 }
426 
427 /* Calculates the plex size. */
428 off_t
429 gv_plex_size(struct gv_plex *p)
430 {
431 	struct gv_sd *s;
432 	off_t size;
433 	int sdcount;
434 
435 	KASSERT(p != NULL, ("gv_plex_size: NULL p"));
436 
437 	/* Adjust the size of our plex. */
438 	size = 0;
439 	sdcount = gv_sdcount(p, 1);
440 	switch (p->org) {
441 	case GV_PLEX_CONCAT:
442 		LIST_FOREACH(s, &p->subdisks, in_plex)
443 			size += s->size;
444 		break;
445 	case GV_PLEX_STRIPED:
446 		s = LIST_FIRST(&p->subdisks);
447 		size = ((s != NULL) ? (sdcount * s->size) : 0);
448 		break;
449 	case GV_PLEX_RAID5:
450 		s = LIST_FIRST(&p->subdisks);
451 		size = ((s != NULL) ? ((sdcount - 1) * s->size) : 0);
452 		break;
453 	}
454 
455 	return (size);
456 }
457 
458 /* Returns the size of a volume. */
459 off_t
460 gv_vol_size(struct gv_volume *v)
461 {
462 	struct gv_plex *p;
463 	off_t minplexsize;
464 
465 	KASSERT(v != NULL, ("gv_vol_size: NULL v"));
466 
467 	p = LIST_FIRST(&v->plexes);
468 	if (p == NULL)
469 		return (0);
470 
471 	minplexsize = p->size;
472 	LIST_FOREACH(p, &v->plexes, in_volume) {
473 		if (p->size < minplexsize) {
474 			minplexsize = p->size;
475 		}
476 	}
477 	return (minplexsize);
478 }
479 
480 void
481 gv_update_plex_config(struct gv_plex *p)
482 {
483 	struct gv_sd *s, *s2;
484 	off_t remainder;
485 	int required_sds, state;
486 
487 	KASSERT(p != NULL, ("gv_update_plex_config: NULL p"));
488 
489 	/* The plex was added to an already running volume. */
490 	if (p->flags & GV_PLEX_ADDED)
491 		gv_set_plex_state(p, GV_PLEX_DOWN, GV_SETSTATE_FORCE);
492 
493 	switch (p->org) {
494 	case GV_PLEX_STRIPED:
495 		required_sds = 2;
496 		break;
497 	case GV_PLEX_RAID5:
498 		required_sds = 3;
499 		break;
500 	case GV_PLEX_CONCAT:
501 	default:
502 		required_sds = 0;
503 		break;
504 	}
505 
506 	if (required_sds) {
507 		if (p->sdcount < required_sds) {
508 			gv_set_plex_state(p, GV_PLEX_DOWN, GV_SETSTATE_FORCE);
509 		}
510 
511 		/*
512 		 * The subdisks in striped plexes must all have the same size.
513 		 */
514 		s = LIST_FIRST(&p->subdisks);
515 		LIST_FOREACH(s2, &p->subdisks, in_plex) {
516 			if (s->size != s2->size) {
517 				G_VINUM_DEBUG(0, "subdisk size mismatch %s"
518 				    "(%jd) <> %s (%jd)", s->name, s->size,
519 				    s2->name, s2->size);
520 				gv_set_plex_state(p, GV_PLEX_DOWN,
521 				    GV_SETSTATE_FORCE);
522 			}
523 		}
524 
525 		LIST_FOREACH(s, &p->subdisks, in_plex) {
526 			/* Trim subdisk sizes to match the stripe size. */
527 			remainder = s->size % p->stripesize;
528 			if (remainder) {
529 				G_VINUM_DEBUG(1, "size of sd %s is not a "
530 				    "multiple of plex stripesize, taking off "
531 				    "%jd bytes", s->name, (intmax_t)remainder);
532 				gv_adjust_freespace(s, remainder);
533 			}
534 		}
535 	}
536 
537 	p->size = gv_plex_size(p);
538 	if (p->sdcount == 0)
539 		gv_set_plex_state(p, GV_PLEX_DOWN, GV_SETSTATE_FORCE);
540 	else if (p->org == GV_PLEX_RAID5 && p->flags & GV_PLEX_NEWBORN) {
541 		LIST_FOREACH(s, &p->subdisks, in_plex)
542 			gv_set_sd_state(s, GV_SD_UP, GV_SETSTATE_FORCE);
543 		/* If added to a volume, we want the plex to be down. */
544 		state = (p->flags & GV_PLEX_ADDED) ? GV_PLEX_DOWN : GV_PLEX_UP;
545 		gv_set_plex_state(p, state, GV_SETSTATE_FORCE);
546 		p->flags &= ~GV_PLEX_ADDED;
547 	} else if (p->flags & GV_PLEX_ADDED) {
548 		LIST_FOREACH(s, &p->subdisks, in_plex)
549 			gv_set_sd_state(s, GV_SD_STALE, GV_SETSTATE_FORCE);
550 		gv_set_plex_state(p, GV_PLEX_DOWN, GV_SETSTATE_FORCE);
551 		p->flags &= ~GV_PLEX_ADDED;
552 	} else if (p->state == GV_PLEX_UP) {
553 		LIST_FOREACH(s, &p->subdisks, in_plex) {
554 			if (s->flags & GV_SD_GROW) {
555 				gv_set_plex_state(p, GV_PLEX_GROWABLE,
556 				    GV_SETSTATE_FORCE);
557 				break;
558 			}
559 		}
560 	}
561 	/* Our plex is grown up now. */
562 	p->flags &= ~GV_PLEX_NEWBORN;
563 }
564 
565 /*
566  * Give a subdisk to a drive, check and adjust several parameters, adjust
567  * freelist.
568  */
569 int
570 gv_sd_to_drive(struct gv_sd *s, struct gv_drive *d)
571 {
572 	struct gv_sd *s2;
573 	struct gv_freelist *fl, *fl2;
574 	off_t tmp;
575 	int i;
576 
577 	fl2 = NULL;
578 
579 	/* Shortcut for "referenced" drives. */
580 	if (d->flags & GV_DRIVE_REFERENCED) {
581 		s->drive_sc = d;
582 		return (0);
583 	}
584 
585 	/* Check if this subdisk was already given to this drive. */
586 	if (s->drive_sc != NULL) {
587 		if (s->drive_sc == d) {
588 			if (!(s->flags & GV_SD_TASTED)) {
589 				return (0);
590 			}
591 		} else {
592 			G_VINUM_DEBUG(0, "error giving subdisk '%s' to '%s' "
593 			    "(already on '%s')", s->name, d->name,
594 			    s->drive_sc->name);
595 			return (GV_ERR_ISATTACHED);
596 		}
597 	}
598 
599 	/* Preliminary checks. */
600 	if ((s->size > d->avail) || (d->freelist_entries == 0)) {
601 		G_VINUM_DEBUG(0, "not enough space on '%s' for '%s'", d->name,
602 		    s->name);
603 		return (GV_ERR_NOSPACE);
604 	}
605 
606 	/* If no size was given for this subdisk, try to auto-size it... */
607 	if (s->size == -1) {
608 		/* Find the largest available slot. */
609 		LIST_FOREACH(fl, &d->freelist, freelist) {
610 			if (fl->size < s->size)
611 				continue;
612 			s->size = fl->size;
613 			s->drive_offset = fl->offset;
614 			fl2 = fl;
615 		}
616 
617 		/* No good slot found? */
618 		if (s->size == -1) {
619 			G_VINUM_DEBUG(0, "unable to autosize '%s' on '%s'",
620 			    s->name, d->name);
621 			return (GV_ERR_BADSIZE);
622 		}
623 
624 	/*
625 	 * ... or check if we have a free slot that's large enough for the
626 	 * given size.
627 	 */
628 	} else {
629 		i = 0;
630 		LIST_FOREACH(fl, &d->freelist, freelist) {
631 			if (fl->size < s->size)
632 				continue;
633 			/* Assign drive offset, if not given. */
634 			if (s->drive_offset == -1)
635 				s->drive_offset = fl->offset;
636 			fl2 = fl;
637 			i++;
638 			break;
639 		}
640 
641 		/* Couldn't find a good free slot. */
642 		if (i == 0) {
643 			G_VINUM_DEBUG(0, "free slots to small for '%s' on '%s'",
644 			    s->name, d->name);
645 			return (GV_ERR_NOSPACE);
646 		}
647 	}
648 
649 	/* No drive offset given, try to calculate it. */
650 	if (s->drive_offset == -1) {
651 
652 		/* Add offsets and sizes from other subdisks on this drive. */
653 		LIST_FOREACH(s2, &d->subdisks, from_drive) {
654 			s->drive_offset = s2->drive_offset + s2->size;
655 		}
656 
657 		/*
658 		 * If there are no other subdisks yet, then set the default
659 		 * offset to GV_DATA_START.
660 		 */
661 		if (s->drive_offset == -1)
662 			s->drive_offset = GV_DATA_START;
663 
664 	/* Check if we have a free slot at the given drive offset. */
665 	} else {
666 		i = 0;
667 		LIST_FOREACH(fl, &d->freelist, freelist) {
668 			/* Yes, this subdisk fits. */
669 			if ((fl->offset <= s->drive_offset) &&
670 			    (fl->offset + fl->size >=
671 			    s->drive_offset + s->size)) {
672 				i++;
673 				fl2 = fl;
674 				break;
675 			}
676 		}
677 
678 		/* Couldn't find a good free slot. */
679 		if (i == 0) {
680 			G_VINUM_DEBUG(0, "given drive_offset for '%s' won't fit "
681 			    "on '%s'", s->name, d->name);
682 			return (GV_ERR_NOSPACE);
683 		}
684 	}
685 
686 	/*
687 	 * Now that all parameters are checked and set up, we can give the
688 	 * subdisk to the drive and adjust the freelist.
689 	 */
690 
691 	/* First, adjust the freelist. */
692 	LIST_FOREACH(fl, &d->freelist, freelist) {
693 		/* Look for the free slot that we have found before. */
694 		if (fl != fl2)
695 			continue;
696 
697 		/* The subdisk starts at the beginning of the free slot. */
698 		if (fl->offset == s->drive_offset) {
699 			fl->offset += s->size;
700 			fl->size -= s->size;
701 
702 			/* The subdisk uses the whole slot, so remove it. */
703 			if (fl->size == 0) {
704 				d->freelist_entries--;
705 				LIST_REMOVE(fl, freelist);
706 			}
707 		/*
708 		 * The subdisk does not start at the beginning of the free
709 		 * slot.
710 		 */
711 		} else {
712 			tmp = fl->offset + fl->size;
713 			fl->size = s->drive_offset - fl->offset;
714 
715 			/*
716 			 * The subdisk didn't use the complete rest of the free
717 			 * slot, so we need to split it.
718 			 */
719 			if (s->drive_offset + s->size != tmp) {
720 				fl2 = g_malloc(sizeof(*fl2), M_WAITOK | M_ZERO);
721 				fl2->offset = s->drive_offset + s->size;
722 				fl2->size = tmp - fl2->offset;
723 				LIST_INSERT_AFTER(fl, fl2, freelist);
724 				d->freelist_entries++;
725 			}
726 		}
727 		break;
728 	}
729 
730 	/*
731 	 * This is the first subdisk on this drive, just insert it into the
732 	 * list.
733 	 */
734 	if (LIST_EMPTY(&d->subdisks)) {
735 		LIST_INSERT_HEAD(&d->subdisks, s, from_drive);
736 
737 	/* There are other subdisks, so insert this one in correct order. */
738 	} else {
739 		LIST_FOREACH(s2, &d->subdisks, from_drive) {
740 			if (s->drive_offset < s2->drive_offset) {
741 				LIST_INSERT_BEFORE(s2, s, from_drive);
742 				break;
743 			} else if (LIST_NEXT(s2, from_drive) == NULL) {
744 				LIST_INSERT_AFTER(s2, s, from_drive);
745 				break;
746 			}
747 		}
748 	}
749 
750 	d->sdcount++;
751 	d->avail -= s->size;
752 
753 	s->flags &= ~GV_SD_TASTED;
754 
755 	/* Link back from the subdisk to this drive. */
756 	s->drive_sc = d;
757 
758 	return (0);
759 }
760 
761 void
762 gv_free_sd(struct gv_sd *s)
763 {
764 	struct gv_drive *d;
765 	struct gv_freelist *fl, *fl2;
766 
767 	KASSERT(s != NULL, ("gv_free_sd: NULL s"));
768 
769 	d = s->drive_sc;
770 	if (d == NULL)
771 		return;
772 
773 	/*
774 	 * First, find the free slot that's immediately before or after this
775 	 * subdisk.
776 	 */
777 	fl = NULL;
778 	LIST_FOREACH(fl, &d->freelist, freelist) {
779 		if (fl->offset == s->drive_offset + s->size)
780 			break;
781 		if (fl->offset + fl->size == s->drive_offset)
782 			break;
783 	}
784 
785 	/* If there is no free slot behind this subdisk, so create one. */
786 	if (fl == NULL) {
787 
788 		fl = g_malloc(sizeof(*fl), M_WAITOK | M_ZERO);
789 		fl->size = s->size;
790 		fl->offset = s->drive_offset;
791 
792 		if (d->freelist_entries == 0) {
793 			LIST_INSERT_HEAD(&d->freelist, fl, freelist);
794 		} else {
795 			LIST_FOREACH(fl2, &d->freelist, freelist) {
796 				if (fl->offset < fl2->offset) {
797 					LIST_INSERT_BEFORE(fl2, fl, freelist);
798 					break;
799 				} else if (LIST_NEXT(fl2, freelist) == NULL) {
800 					LIST_INSERT_AFTER(fl2, fl, freelist);
801 					break;
802 				}
803 			}
804 		}
805 
806 		d->freelist_entries++;
807 
808 	/* Expand the free slot we just found. */
809 	} else {
810 		fl->size += s->size;
811 		if (fl->offset > s->drive_offset)
812 			fl->offset = s->drive_offset;
813 	}
814 
815 	d->avail += s->size;
816 	d->sdcount--;
817 }
818 
819 void
820 gv_adjust_freespace(struct gv_sd *s, off_t remainder)
821 {
822 	struct gv_drive *d;
823 	struct gv_freelist *fl, *fl2;
824 
825 	KASSERT(s != NULL, ("gv_adjust_freespace: NULL s"));
826 	d = s->drive_sc;
827 	KASSERT(d != NULL, ("gv_adjust_freespace: NULL d"));
828 
829 	/* First, find the free slot that's immediately after this subdisk. */
830 	fl = NULL;
831 	LIST_FOREACH(fl, &d->freelist, freelist) {
832 		if (fl->offset == s->drive_offset + s->size)
833 			break;
834 	}
835 
836 	/* If there is no free slot behind this subdisk, so create one. */
837 	if (fl == NULL) {
838 
839 		fl = g_malloc(sizeof(*fl), M_WAITOK | M_ZERO);
840 		fl->size = remainder;
841 		fl->offset = s->drive_offset + s->size - remainder;
842 
843 		if (d->freelist_entries == 0) {
844 			LIST_INSERT_HEAD(&d->freelist, fl, freelist);
845 		} else {
846 			LIST_FOREACH(fl2, &d->freelist, freelist) {
847 				if (fl->offset < fl2->offset) {
848 					LIST_INSERT_BEFORE(fl2, fl, freelist);
849 					break;
850 				} else if (LIST_NEXT(fl2, freelist) == NULL) {
851 					LIST_INSERT_AFTER(fl2, fl, freelist);
852 					break;
853 				}
854 			}
855 		}
856 
857 		d->freelist_entries++;
858 
859 	/* Expand the free slot we just found. */
860 	} else {
861 		fl->offset -= remainder;
862 		fl->size += remainder;
863 	}
864 
865 	s->size -= remainder;
866 	d->avail += remainder;
867 }
868 
869 /* Check if the given plex is a striped one. */
870 int
871 gv_is_striped(struct gv_plex *p)
872 {
873 	KASSERT(p != NULL, ("gv_is_striped: NULL p"));
874 	switch(p->org) {
875 	case GV_PLEX_STRIPED:
876 	case GV_PLEX_RAID5:
877 		return (1);
878 	default:
879 		return (0);
880 	}
881 }
882 
883 /* Find a volume by name. */
884 struct gv_volume *
885 gv_find_vol(struct gv_softc *sc, char *name)
886 {
887 	struct gv_volume *v;
888 
889 	LIST_FOREACH(v, &sc->volumes, volume) {
890 		if (!strncmp(v->name, name, GV_MAXVOLNAME))
891 			return (v);
892 	}
893 
894 	return (NULL);
895 }
896 
897 /* Find a plex by name. */
898 struct gv_plex *
899 gv_find_plex(struct gv_softc *sc, char *name)
900 {
901 	struct gv_plex *p;
902 
903 	LIST_FOREACH(p, &sc->plexes, plex) {
904 		if (!strncmp(p->name, name, GV_MAXPLEXNAME))
905 			return (p);
906 	}
907 
908 	return (NULL);
909 }
910 
911 /* Find a subdisk by name. */
912 struct gv_sd *
913 gv_find_sd(struct gv_softc *sc, char *name)
914 {
915 	struct gv_sd *s;
916 
917 	LIST_FOREACH(s, &sc->subdisks, sd) {
918 		if (!strncmp(s->name, name, GV_MAXSDNAME))
919 			return (s);
920 	}
921 
922 	return (NULL);
923 }
924 
925 /* Find a drive by name. */
926 struct gv_drive *
927 gv_find_drive(struct gv_softc *sc, char *name)
928 {
929 	struct gv_drive *d;
930 
931 	LIST_FOREACH(d, &sc->drives, drive) {
932 		if (!strncmp(d->name, name, GV_MAXDRIVENAME))
933 			return (d);
934 	}
935 
936 	return (NULL);
937 }
938 
939 /* Find a drive given a device. */
940 struct gv_drive *
941 gv_find_drive_device(struct gv_softc *sc, char *device)
942 {
943 	struct gv_drive *d;
944 
945 	LIST_FOREACH(d, &sc->drives, drive) {
946 		if(!strcmp(d->device, device))
947 			return (d);
948 	}
949 
950 	return (NULL);
951 }
952 
953 /* Check if any consumer of the given geom is open. */
954 int
955 gv_consumer_is_open(struct g_consumer *cp)
956 {
957 	if (cp == NULL)
958 		return (0);
959 
960 	if (cp->acr || cp->acw || cp->ace)
961 		return (1);
962 
963 	return (0);
964 }
965 
966 int
967 gv_provider_is_open(struct g_provider *pp)
968 {
969 	if (pp == NULL)
970 		return (0);
971 
972 	if (pp->acr || pp->acw || pp->ace)
973 		return (1);
974 
975 	return (0);
976 }
977 
978 /*
979  * Compare the modification dates of the drives.
980  * Return 1 if a > b, 0 otherwise.
981  */
982 int
983 gv_drive_is_newer(struct gv_softc *sc, struct gv_drive *d)
984 {
985 	struct gv_drive *d2;
986 	struct timeval *a, *b;
987 
988 	KASSERT(!LIST_EMPTY(&sc->drives),
989 	    ("gv_is_drive_newer: empty drive list"));
990 
991 	a = &d->hdr->label.last_update;
992 	LIST_FOREACH(d2, &sc->drives, drive) {
993 		if ((d == d2) || (d2->state != GV_DRIVE_UP) ||
994 		    (d2->hdr == NULL))
995 			continue;
996 		b = &d2->hdr->label.last_update;
997 		if (timevalcmp(a, b, >))
998 			return (1);
999 	}
1000 
1001 	return (0);
1002 }
1003 
1004 /* Return the type of object identified by string 'name'. */
1005 int
1006 gv_object_type(struct gv_softc *sc, char *name)
1007 {
1008 	struct gv_drive *d;
1009 	struct gv_plex *p;
1010 	struct gv_sd *s;
1011 	struct gv_volume *v;
1012 
1013 	LIST_FOREACH(v, &sc->volumes, volume) {
1014 		if (!strncmp(v->name, name, GV_MAXVOLNAME))
1015 			return (GV_TYPE_VOL);
1016 	}
1017 
1018 	LIST_FOREACH(p, &sc->plexes, plex) {
1019 		if (!strncmp(p->name, name, GV_MAXPLEXNAME))
1020 			return (GV_TYPE_PLEX);
1021 	}
1022 
1023 	LIST_FOREACH(s, &sc->subdisks, sd) {
1024 		if (!strncmp(s->name, name, GV_MAXSDNAME))
1025 			return (GV_TYPE_SD);
1026 	}
1027 
1028 	LIST_FOREACH(d, &sc->drives, drive) {
1029 		if (!strncmp(d->name, name, GV_MAXDRIVENAME))
1030 			return (GV_TYPE_DRIVE);
1031 	}
1032 
1033 	return (GV_ERR_NOTFOUND);
1034 }
1035 
1036 void
1037 gv_setup_objects(struct gv_softc *sc)
1038 {
1039 	struct g_provider *pp;
1040 	struct gv_volume *v;
1041 	struct gv_plex *p;
1042 	struct gv_sd *s;
1043 	struct gv_drive *d;
1044 
1045 	LIST_FOREACH(s, &sc->subdisks, sd) {
1046 		d = gv_find_drive(sc, s->drive);
1047 		if (d != NULL)
1048 			gv_sd_to_drive(s, d);
1049 		p = gv_find_plex(sc, s->plex);
1050 		if (p != NULL)
1051 			gv_sd_to_plex(s, p);
1052 		gv_update_sd_state(s);
1053 	}
1054 
1055 	LIST_FOREACH(p, &sc->plexes, plex) {
1056 		gv_update_plex_config(p);
1057 		v = gv_find_vol(sc, p->volume);
1058 		if (v != NULL && p->vol_sc != v) {
1059 			p->vol_sc = v;
1060 			v->plexcount++;
1061 			LIST_INSERT_HEAD(&v->plexes, p, in_volume);
1062 		}
1063 		gv_update_plex_config(p);
1064 	}
1065 
1066 	LIST_FOREACH(v, &sc->volumes, volume) {
1067 		v->size = gv_vol_size(v);
1068 		if (v->provider == NULL) {
1069 			g_topology_lock();
1070 			pp = g_new_providerf(sc->geom, "gvinum/%s", v->name);
1071 			pp->mediasize = v->size;
1072 			pp->sectorsize = 512;    /* XXX */
1073 			g_error_provider(pp, 0);
1074 			v->provider = pp;
1075 			pp->private = v;
1076 			g_topology_unlock();
1077 		} else if (v->provider->mediasize != v->size) {
1078 			g_topology_lock();
1079 			v->provider->mediasize = v->size;
1080 			g_topology_unlock();
1081 		}
1082 		v->flags &= ~GV_VOL_NEWBORN;
1083 		gv_update_vol_state(v);
1084 	}
1085 }
1086 
1087 void
1088 gv_cleanup(struct gv_softc *sc)
1089 {
1090 	struct gv_volume *v, *v2;
1091 	struct gv_plex *p, *p2;
1092 	struct gv_sd *s, *s2;
1093 	struct gv_drive *d, *d2;
1094 	struct gv_freelist *fl, *fl2;
1095 
1096 	mtx_lock(&sc->config_mtx);
1097 	LIST_FOREACH_SAFE(v, &sc->volumes, volume, v2) {
1098 		LIST_REMOVE(v, volume);
1099 		g_free(v->wqueue);
1100 		g_free(v);
1101 	}
1102 	LIST_FOREACH_SAFE(p, &sc->plexes, plex, p2) {
1103 		LIST_REMOVE(p, plex);
1104 		g_free(p->bqueue);
1105 		g_free(p->rqueue);
1106 		g_free(p->wqueue);
1107 		g_free(p);
1108 	}
1109 	LIST_FOREACH_SAFE(s, &sc->subdisks, sd, s2) {
1110 		LIST_REMOVE(s, sd);
1111 		g_free(s);
1112 	}
1113 	LIST_FOREACH_SAFE(d, &sc->drives, drive, d2) {
1114 		LIST_FOREACH_SAFE(fl, &d->freelist, freelist, fl2) {
1115 			LIST_REMOVE(fl, freelist);
1116 			g_free(fl);
1117 		}
1118 		LIST_REMOVE(d, drive);
1119 		g_free(d->hdr);
1120 		g_free(d);
1121 	}
1122 	mtx_destroy(&sc->config_mtx);
1123 }
1124 
1125 /* General 'attach' routine. */
1126 int
1127 gv_attach_plex(struct gv_plex *p, struct gv_volume *v, int rename)
1128 {
1129 	struct gv_sd *s;
1130 	struct gv_softc *sc;
1131 
1132 	g_topology_assert();
1133 
1134 	sc = p->vinumconf;
1135 	KASSERT(sc != NULL, ("NULL sc"));
1136 
1137 	if (p->vol_sc != NULL) {
1138 		G_VINUM_DEBUG(1, "unable to attach %s: already attached to %s",
1139 		    p->name, p->volume);
1140 		return (GV_ERR_ISATTACHED);
1141 	}
1142 
1143 	/* Stale all subdisks of this plex. */
1144 	LIST_FOREACH(s, &p->subdisks, in_plex) {
1145 		if (s->state != GV_SD_STALE)
1146 			gv_set_sd_state(s, GV_SD_STALE, GV_SETSTATE_FORCE);
1147 	}
1148 	/* Attach to volume. Make sure volume is not up and running. */
1149 	if (gv_provider_is_open(v->provider)) {
1150 		G_VINUM_DEBUG(1, "unable to attach %s: volume %s is busy",
1151 		    p->name, v->name);
1152 		return (GV_ERR_ISBUSY);
1153 	}
1154 	p->vol_sc = v;
1155 	strlcpy(p->volume, v->name, sizeof(p->volume));
1156 	v->plexcount++;
1157 	if (rename) {
1158 		snprintf(p->name, sizeof(p->name), "%s.p%d", v->name,
1159 		    v->plexcount);
1160 	}
1161 	LIST_INSERT_HEAD(&v->plexes, p, in_volume);
1162 
1163 	/* Get plex up again. */
1164 	gv_update_vol_size(v, gv_vol_size(v));
1165 	gv_set_plex_state(p, GV_PLEX_UP, 0);
1166 	gv_save_config(p->vinumconf);
1167 	return (0);
1168 }
1169 
1170 int
1171 gv_attach_sd(struct gv_sd *s, struct gv_plex *p, off_t offset, int rename)
1172 {
1173 	struct gv_sd *s2;
1174 	int error, sdcount;
1175 
1176 	g_topology_assert();
1177 
1178 	/* If subdisk is attached, don't do it. */
1179 	if (s->plex_sc != NULL) {
1180 		G_VINUM_DEBUG(1, "unable to attach %s: already attached to %s",
1181 		    s->name, s->plex);
1182 		return (GV_ERR_ISATTACHED);
1183 	}
1184 
1185 	gv_set_sd_state(s, GV_SD_STALE, GV_SETSTATE_FORCE);
1186 	/* First check that this subdisk has a correct offset. If none other
1187 	 * starts at the same, and it's correct module stripesize, it is */
1188 	if (offset != -1 && offset % p->stripesize != 0)
1189 		return (GV_ERR_BADOFFSET);
1190 	LIST_FOREACH(s2, &p->subdisks, in_plex) {
1191 		if (s2->plex_offset == offset)
1192 			return (GV_ERR_BADOFFSET);
1193 	}
1194 
1195 	/* Attach the subdisk to the plex at given offset. */
1196 	s->plex_offset = offset;
1197 	strlcpy(s->plex, p->name, sizeof(s->plex));
1198 
1199 	sdcount = p->sdcount;
1200 	error = gv_sd_to_plex(s, p);
1201 	if (error)
1202 		return (error);
1203 	gv_update_plex_config(p);
1204 
1205 	if (rename) {
1206 		snprintf(s->name, sizeof(s->name), "%s.s%d", s->plex,
1207 		    p->sdcount);
1208 	}
1209 	if (p->vol_sc != NULL)
1210 		gv_update_vol_size(p->vol_sc, gv_vol_size(p->vol_sc));
1211 	gv_save_config(p->vinumconf);
1212 	/* We don't update the subdisk state since the user might have to
1213 	 * initiate a rebuild/sync first. */
1214 	return (0);
1215 }
1216 
1217 /* Detach a plex from a volume. */
1218 int
1219 gv_detach_plex(struct gv_plex *p, int flags)
1220 {
1221 	struct gv_volume *v;
1222 
1223 	g_topology_assert();
1224 	v = p->vol_sc;
1225 
1226 	if (v == NULL) {
1227 		G_VINUM_DEBUG(1, "unable to detach %s: already detached",
1228 		    p->name);
1229 		return (0); /* Not an error. */
1230 	}
1231 
1232 	/*
1233 	 * Only proceed if forced or volume inactive.
1234 	 */
1235 	if (!(flags & GV_FLAG_F) && (gv_provider_is_open(v->provider) ||
1236 	    p->state == GV_PLEX_UP)) {
1237 		G_VINUM_DEBUG(1, "unable to detach %s: volume %s is busy",
1238 		    p->name, p->volume);
1239 		return (GV_ERR_ISBUSY);
1240 	}
1241 	v->plexcount--;
1242 	/* Make sure someone don't read us when gone. */
1243 	v->last_read_plex = NULL;
1244 	LIST_REMOVE(p, in_volume);
1245 	p->vol_sc = NULL;
1246 	memset(p->volume, 0, GV_MAXVOLNAME);
1247 	gv_update_vol_size(v, gv_vol_size(v));
1248 	gv_save_config(p->vinumconf);
1249 	return (0);
1250 }
1251 
1252 /* Detach a subdisk from a plex. */
1253 int
1254 gv_detach_sd(struct gv_sd *s, int flags)
1255 {
1256 	struct gv_plex *p;
1257 
1258 	g_topology_assert();
1259 	p = s->plex_sc;
1260 
1261 	if (p == NULL) {
1262 		G_VINUM_DEBUG(1, "unable to detach %s: already detached",
1263 		    s->name);
1264 		return (0); /* Not an error. */
1265 	}
1266 
1267 	/*
1268 	 * Don't proceed if we're not forcing, and the plex is up, or degraded
1269 	 * with this subdisk up.
1270 	 */
1271 	if (!(flags & GV_FLAG_F) && ((p->state > GV_PLEX_DEGRADED) ||
1272 	    ((p->state == GV_PLEX_DEGRADED) && (s->state == GV_SD_UP)))) {
1273 	    	G_VINUM_DEBUG(1, "unable to detach %s: plex %s is busy",
1274 		    s->name, s->plex);
1275 		return (GV_ERR_ISBUSY);
1276 	}
1277 
1278 	LIST_REMOVE(s, in_plex);
1279 	s->plex_sc = NULL;
1280 	memset(s->plex, 0, GV_MAXPLEXNAME);
1281 	p->sddetached++;
1282 	gv_save_config(s->vinumconf);
1283 	return (0);
1284 }
1285