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