xref: /freebsd/sys/geom/stripe/g_stripe.c (revision 68d75eff68281c1b445e3010bb975eae07aac225)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2004-2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/module.h>
36 #include <sys/lock.h>
37 #include <sys/mutex.h>
38 #include <sys/bio.h>
39 #include <sys/sbuf.h>
40 #include <sys/sysctl.h>
41 #include <sys/malloc.h>
42 #include <vm/uma.h>
43 #include <geom/geom.h>
44 #include <geom/geom_dbg.h>
45 #include <geom/stripe/g_stripe.h>
46 
47 FEATURE(geom_stripe, "GEOM striping support");
48 
49 static MALLOC_DEFINE(M_STRIPE, "stripe_data", "GEOM_STRIPE Data");
50 
51 static uma_zone_t g_stripe_zone;
52 
53 static int g_stripe_destroy(struct g_stripe_softc *sc, boolean_t force);
54 static int g_stripe_destroy_geom(struct gctl_req *req, struct g_class *mp,
55     struct g_geom *gp);
56 
57 static g_taste_t g_stripe_taste;
58 static g_ctl_req_t g_stripe_config;
59 static g_dumpconf_t g_stripe_dumpconf;
60 static g_init_t g_stripe_init;
61 static g_fini_t g_stripe_fini;
62 
63 struct g_class g_stripe_class = {
64 	.name = G_STRIPE_CLASS_NAME,
65 	.version = G_VERSION,
66 	.ctlreq = g_stripe_config,
67 	.taste = g_stripe_taste,
68 	.destroy_geom = g_stripe_destroy_geom,
69 	.init = g_stripe_init,
70 	.fini = g_stripe_fini
71 };
72 
73 SYSCTL_DECL(_kern_geom);
74 static SYSCTL_NODE(_kern_geom, OID_AUTO, stripe, CTLFLAG_RW, 0,
75     "GEOM_STRIPE stuff");
76 static u_int g_stripe_debug = 0;
77 SYSCTL_UINT(_kern_geom_stripe, OID_AUTO, debug, CTLFLAG_RWTUN, &g_stripe_debug, 0,
78     "Debug level");
79 static int g_stripe_fast = 0;
80 static int
81 g_sysctl_stripe_fast(SYSCTL_HANDLER_ARGS)
82 {
83 	int error, fast;
84 
85 	fast = g_stripe_fast;
86 	error = sysctl_handle_int(oidp, &fast, 0, req);
87 	if (error == 0 && req->newptr != NULL)
88 		g_stripe_fast = fast;
89 	return (error);
90 }
91 SYSCTL_PROC(_kern_geom_stripe, OID_AUTO, fast, CTLTYPE_INT | CTLFLAG_RWTUN,
92     NULL, 0, g_sysctl_stripe_fast, "I", "Fast, but memory-consuming, mode");
93 static u_int g_stripe_maxmem = MAXPHYS * 100;
94 SYSCTL_UINT(_kern_geom_stripe, OID_AUTO, maxmem, CTLFLAG_RDTUN, &g_stripe_maxmem,
95     0, "Maximum memory that can be allocated in \"fast\" mode (in bytes)");
96 static u_int g_stripe_fast_failed = 0;
97 SYSCTL_UINT(_kern_geom_stripe, OID_AUTO, fast_failed, CTLFLAG_RD,
98     &g_stripe_fast_failed, 0, "How many times \"fast\" mode failed");
99 
100 /*
101  * Greatest Common Divisor.
102  */
103 static u_int
104 gcd(u_int a, u_int b)
105 {
106 	u_int c;
107 
108 	while (b != 0) {
109 		c = a;
110 		a = b;
111 		b = (c % b);
112 	}
113 	return (a);
114 }
115 
116 /*
117  * Least Common Multiple.
118  */
119 static u_int
120 lcm(u_int a, u_int b)
121 {
122 
123 	return ((a * b) / gcd(a, b));
124 }
125 
126 static void
127 g_stripe_init(struct g_class *mp __unused)
128 {
129 
130 	g_stripe_zone = uma_zcreate("g_stripe_zone", MAXPHYS, NULL, NULL,
131 	    NULL, NULL, 0, 0);
132 	g_stripe_maxmem -= g_stripe_maxmem % MAXPHYS;
133 	uma_zone_set_max(g_stripe_zone, g_stripe_maxmem / MAXPHYS);
134 }
135 
136 static void
137 g_stripe_fini(struct g_class *mp __unused)
138 {
139 
140 	uma_zdestroy(g_stripe_zone);
141 }
142 
143 /*
144  * Return the number of valid disks.
145  */
146 static u_int
147 g_stripe_nvalid(struct g_stripe_softc *sc)
148 {
149 	u_int i, no;
150 
151 	no = 0;
152 	for (i = 0; i < sc->sc_ndisks; i++) {
153 		if (sc->sc_disks[i] != NULL)
154 			no++;
155 	}
156 
157 	return (no);
158 }
159 
160 static void
161 g_stripe_remove_disk(struct g_consumer *cp)
162 {
163 	struct g_stripe_softc *sc;
164 
165 	g_topology_assert();
166 	KASSERT(cp != NULL, ("Non-valid disk in %s.", __func__));
167 	sc = (struct g_stripe_softc *)cp->geom->softc;
168 	KASSERT(sc != NULL, ("NULL sc in %s.", __func__));
169 
170 	if (cp->private == NULL) {
171 		G_STRIPE_DEBUG(0, "Disk %s removed from %s.",
172 		    cp->provider->name, sc->sc_name);
173 		cp->private = (void *)(uintptr_t)-1;
174 	}
175 
176 	if (sc->sc_provider != NULL) {
177 		G_STRIPE_DEBUG(0, "Device %s deactivated.",
178 		    sc->sc_provider->name);
179 		g_wither_provider(sc->sc_provider, ENXIO);
180 		sc->sc_provider = NULL;
181 	}
182 
183 	if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0)
184 		return;
185 	sc->sc_disks[cp->index] = NULL;
186 	cp->index = 0;
187 	g_detach(cp);
188 	g_destroy_consumer(cp);
189 	/* If there are no valid disks anymore, remove device. */
190 	if (LIST_EMPTY(&sc->sc_geom->consumer))
191 		g_stripe_destroy(sc, 1);
192 }
193 
194 static void
195 g_stripe_orphan(struct g_consumer *cp)
196 {
197 	struct g_stripe_softc *sc;
198 	struct g_geom *gp;
199 
200 	g_topology_assert();
201 	gp = cp->geom;
202 	sc = gp->softc;
203 	if (sc == NULL)
204 		return;
205 
206 	g_stripe_remove_disk(cp);
207 }
208 
209 static int
210 g_stripe_access(struct g_provider *pp, int dr, int dw, int de)
211 {
212 	struct g_consumer *cp1, *cp2, *tmp;
213 	struct g_stripe_softc *sc;
214 	struct g_geom *gp;
215 	int error;
216 
217 	g_topology_assert();
218 	gp = pp->geom;
219 	sc = gp->softc;
220 	KASSERT(sc != NULL, ("NULL sc in %s.", __func__));
221 
222 	/* On first open, grab an extra "exclusive" bit */
223 	if (pp->acr == 0 && pp->acw == 0 && pp->ace == 0)
224 		de++;
225 	/* ... and let go of it on last close */
226 	if ((pp->acr + dr) == 0 && (pp->acw + dw) == 0 && (pp->ace + de) == 0)
227 		de--;
228 
229 	LIST_FOREACH_SAFE(cp1, &gp->consumer, consumer, tmp) {
230 		error = g_access(cp1, dr, dw, de);
231 		if (error != 0)
232 			goto fail;
233 		if (cp1->acr == 0 && cp1->acw == 0 && cp1->ace == 0 &&
234 		    cp1->private != NULL) {
235 			g_stripe_remove_disk(cp1); /* May destroy geom. */
236 		}
237 	}
238 	return (0);
239 
240 fail:
241 	LIST_FOREACH(cp2, &gp->consumer, consumer) {
242 		if (cp1 == cp2)
243 			break;
244 		g_access(cp2, -dr, -dw, -de);
245 	}
246 	return (error);
247 }
248 
249 static void
250 g_stripe_copy(struct g_stripe_softc *sc, char *src, char *dst, off_t offset,
251     off_t length, int mode)
252 {
253 	off_t stripesize;
254 	size_t len;
255 
256 	stripesize = sc->sc_stripesize;
257 	len = (size_t)(stripesize - (offset & (stripesize - 1)));
258 	do {
259 		bcopy(src, dst, len);
260 		if (mode) {
261 			dst += len + stripesize * (sc->sc_ndisks - 1);
262 			src += len;
263 		} else {
264 			dst += len;
265 			src += len + stripesize * (sc->sc_ndisks - 1);
266 		}
267 		length -= len;
268 		KASSERT(length >= 0,
269 		    ("Length < 0 (stripesize=%ju, offset=%ju, length=%jd).",
270 		    (uintmax_t)stripesize, (uintmax_t)offset, (intmax_t)length));
271 		if (length > stripesize)
272 			len = stripesize;
273 		else
274 			len = length;
275 	} while (length > 0);
276 }
277 
278 static void
279 g_stripe_done(struct bio *bp)
280 {
281 	struct g_stripe_softc *sc;
282 	struct bio *pbp;
283 
284 	pbp = bp->bio_parent;
285 	sc = pbp->bio_to->geom->softc;
286 	if (bp->bio_cmd == BIO_READ && bp->bio_caller1 != NULL) {
287 		g_stripe_copy(sc, bp->bio_data, bp->bio_caller1, bp->bio_offset,
288 		    bp->bio_length, 1);
289 		bp->bio_data = bp->bio_caller1;
290 		bp->bio_caller1 = NULL;
291 	}
292 	mtx_lock(&sc->sc_lock);
293 	if (pbp->bio_error == 0)
294 		pbp->bio_error = bp->bio_error;
295 	pbp->bio_completed += bp->bio_completed;
296 	pbp->bio_inbed++;
297 	if (pbp->bio_children == pbp->bio_inbed) {
298 		mtx_unlock(&sc->sc_lock);
299 		if (pbp->bio_driver1 != NULL)
300 			uma_zfree(g_stripe_zone, pbp->bio_driver1);
301 		g_io_deliver(pbp, pbp->bio_error);
302 	} else
303 		mtx_unlock(&sc->sc_lock);
304 	g_destroy_bio(bp);
305 }
306 
307 static int
308 g_stripe_start_fast(struct bio *bp, u_int no, off_t offset, off_t length)
309 {
310 	TAILQ_HEAD(, bio) queue = TAILQ_HEAD_INITIALIZER(queue);
311 	struct g_stripe_softc *sc;
312 	char *addr, *data = NULL;
313 	struct bio *cbp;
314 	off_t stripesize;
315 	u_int nparts = 0;
316 	int error;
317 
318 	sc = bp->bio_to->geom->softc;
319 
320 	addr = bp->bio_data;
321 	stripesize = sc->sc_stripesize;
322 
323 	cbp = g_clone_bio(bp);
324 	if (cbp == NULL) {
325 		error = ENOMEM;
326 		goto failure;
327 	}
328 	TAILQ_INSERT_TAIL(&queue, cbp, bio_queue);
329 	nparts++;
330 	/*
331 	 * Fill in the component buf structure.
332 	 */
333 	cbp->bio_done = g_stripe_done;
334 	cbp->bio_offset = offset;
335 	cbp->bio_data = addr;
336 	cbp->bio_caller1 = NULL;
337 	cbp->bio_length = length;
338 	cbp->bio_caller2 = sc->sc_disks[no];
339 
340 	/* offset -= offset % stripesize; */
341 	offset -= offset & (stripesize - 1);
342 	addr += length;
343 	length = bp->bio_length - length;
344 	for (no++; length > 0; no++, length -= stripesize, addr += stripesize) {
345 		if (no > sc->sc_ndisks - 1) {
346 			no = 0;
347 			offset += stripesize;
348 		}
349 		if (nparts >= sc->sc_ndisks) {
350 			cbp = TAILQ_NEXT(cbp, bio_queue);
351 			if (cbp == NULL)
352 				cbp = TAILQ_FIRST(&queue);
353 			nparts++;
354 			/*
355 			 * Update bio structure.
356 			 */
357 			/*
358 			 * MIN() is in case when
359 			 * (bp->bio_length % sc->sc_stripesize) != 0.
360 			 */
361 			cbp->bio_length += MIN(stripesize, length);
362 			if (cbp->bio_caller1 == NULL) {
363 				cbp->bio_caller1 = cbp->bio_data;
364 				cbp->bio_data = NULL;
365 				if (data == NULL) {
366 					data = uma_zalloc(g_stripe_zone,
367 					    M_NOWAIT);
368 					if (data == NULL) {
369 						error = ENOMEM;
370 						goto failure;
371 					}
372 				}
373 			}
374 		} else {
375 			cbp = g_clone_bio(bp);
376 			if (cbp == NULL) {
377 				error = ENOMEM;
378 				goto failure;
379 			}
380 			TAILQ_INSERT_TAIL(&queue, cbp, bio_queue);
381 			nparts++;
382 			/*
383 			 * Fill in the component buf structure.
384 			 */
385 			cbp->bio_done = g_stripe_done;
386 			cbp->bio_offset = offset;
387 			cbp->bio_data = addr;
388 			cbp->bio_caller1 = NULL;
389 			/*
390 			 * MIN() is in case when
391 			 * (bp->bio_length % sc->sc_stripesize) != 0.
392 			 */
393 			cbp->bio_length = MIN(stripesize, length);
394 			cbp->bio_caller2 = sc->sc_disks[no];
395 		}
396 	}
397 	if (data != NULL)
398 		bp->bio_driver1 = data;
399 	/*
400 	 * Fire off all allocated requests!
401 	 */
402 	while ((cbp = TAILQ_FIRST(&queue)) != NULL) {
403 		struct g_consumer *cp;
404 
405 		TAILQ_REMOVE(&queue, cbp, bio_queue);
406 		cp = cbp->bio_caller2;
407 		cbp->bio_caller2 = NULL;
408 		cbp->bio_to = cp->provider;
409 		if (cbp->bio_caller1 != NULL) {
410 			cbp->bio_data = data;
411 			if (bp->bio_cmd == BIO_WRITE) {
412 				g_stripe_copy(sc, cbp->bio_caller1, data,
413 				    cbp->bio_offset, cbp->bio_length, 0);
414 			}
415 			data += cbp->bio_length;
416 		}
417 		G_STRIPE_LOGREQ(cbp, "Sending request.");
418 		g_io_request(cbp, cp);
419 	}
420 	return (0);
421 failure:
422 	if (data != NULL)
423 		uma_zfree(g_stripe_zone, data);
424 	while ((cbp = TAILQ_FIRST(&queue)) != NULL) {
425 		TAILQ_REMOVE(&queue, cbp, bio_queue);
426 		if (cbp->bio_caller1 != NULL) {
427 			cbp->bio_data = cbp->bio_caller1;
428 			cbp->bio_caller1 = NULL;
429 		}
430 		bp->bio_children--;
431 		g_destroy_bio(cbp);
432 	}
433 	return (error);
434 }
435 
436 static int
437 g_stripe_start_economic(struct bio *bp, u_int no, off_t offset, off_t length)
438 {
439 	TAILQ_HEAD(, bio) queue = TAILQ_HEAD_INITIALIZER(queue);
440 	struct g_stripe_softc *sc;
441 	off_t stripesize;
442 	struct bio *cbp;
443 	char *addr;
444 	int error;
445 
446 	sc = bp->bio_to->geom->softc;
447 
448 	stripesize = sc->sc_stripesize;
449 
450 	cbp = g_clone_bio(bp);
451 	if (cbp == NULL) {
452 		error = ENOMEM;
453 		goto failure;
454 	}
455 	TAILQ_INSERT_TAIL(&queue, cbp, bio_queue);
456 	/*
457 	 * Fill in the component buf structure.
458 	 */
459 	if (bp->bio_length == length)
460 		cbp->bio_done = g_std_done;	/* Optimized lockless case. */
461 	else
462 		cbp->bio_done = g_stripe_done;
463 	cbp->bio_offset = offset;
464 	cbp->bio_length = length;
465 	if ((bp->bio_flags & BIO_UNMAPPED) != 0) {
466 		bp->bio_ma_n = round_page(bp->bio_ma_offset +
467 		    bp->bio_length) / PAGE_SIZE;
468 		addr = NULL;
469 	} else
470 		addr = bp->bio_data;
471 	cbp->bio_caller2 = sc->sc_disks[no];
472 
473 	/* offset -= offset % stripesize; */
474 	offset -= offset & (stripesize - 1);
475 	if (bp->bio_cmd != BIO_DELETE)
476 		addr += length;
477 	length = bp->bio_length - length;
478 	for (no++; length > 0; no++, length -= stripesize) {
479 		if (no > sc->sc_ndisks - 1) {
480 			no = 0;
481 			offset += stripesize;
482 		}
483 		cbp = g_clone_bio(bp);
484 		if (cbp == NULL) {
485 			error = ENOMEM;
486 			goto failure;
487 		}
488 		TAILQ_INSERT_TAIL(&queue, cbp, bio_queue);
489 
490 		/*
491 		 * Fill in the component buf structure.
492 		 */
493 		cbp->bio_done = g_stripe_done;
494 		cbp->bio_offset = offset;
495 		/*
496 		 * MIN() is in case when
497 		 * (bp->bio_length % sc->sc_stripesize) != 0.
498 		 */
499 		cbp->bio_length = MIN(stripesize, length);
500 		if ((bp->bio_flags & BIO_UNMAPPED) != 0) {
501 			cbp->bio_ma_offset += (uintptr_t)addr;
502 			cbp->bio_ma += cbp->bio_ma_offset / PAGE_SIZE;
503 			cbp->bio_ma_offset %= PAGE_SIZE;
504 			cbp->bio_ma_n = round_page(cbp->bio_ma_offset +
505 			    cbp->bio_length) / PAGE_SIZE;
506 		} else
507 			cbp->bio_data = addr;
508 
509 		cbp->bio_caller2 = sc->sc_disks[no];
510 
511 		if (bp->bio_cmd != BIO_DELETE)
512 			addr += stripesize;
513 	}
514 	/*
515 	 * Fire off all allocated requests!
516 	 */
517 	while ((cbp = TAILQ_FIRST(&queue)) != NULL) {
518 		struct g_consumer *cp;
519 
520 		TAILQ_REMOVE(&queue, cbp, bio_queue);
521 		cp = cbp->bio_caller2;
522 		cbp->bio_caller2 = NULL;
523 		cbp->bio_to = cp->provider;
524 		G_STRIPE_LOGREQ(cbp, "Sending request.");
525 		g_io_request(cbp, cp);
526 	}
527 	return (0);
528 failure:
529 	while ((cbp = TAILQ_FIRST(&queue)) != NULL) {
530 		TAILQ_REMOVE(&queue, cbp, bio_queue);
531 		bp->bio_children--;
532 		g_destroy_bio(cbp);
533 	}
534 	return (error);
535 }
536 
537 static void
538 g_stripe_pushdown(struct g_stripe_softc *sc, struct bio *bp)
539 {
540 	struct bio_queue_head queue;
541 	struct g_consumer *cp;
542 	struct bio *cbp;
543 	u_int no;
544 
545 	bioq_init(&queue);
546 	for (no = 0; no < sc->sc_ndisks; no++) {
547 		cbp = g_clone_bio(bp);
548 		if (cbp == NULL) {
549 			for (cbp = bioq_first(&queue); cbp != NULL;
550 			    cbp = bioq_first(&queue)) {
551 				bioq_remove(&queue, cbp);
552 				g_destroy_bio(cbp);
553 			}
554 			if (bp->bio_error == 0)
555 				bp->bio_error = ENOMEM;
556 			g_io_deliver(bp, bp->bio_error);
557 			return;
558 		}
559 		bioq_insert_tail(&queue, cbp);
560 		cbp->bio_done = g_stripe_done;
561 		cbp->bio_caller2 = sc->sc_disks[no];
562 		cbp->bio_to = sc->sc_disks[no]->provider;
563 	}
564 	for (cbp = bioq_first(&queue); cbp != NULL; cbp = bioq_first(&queue)) {
565 		bioq_remove(&queue, cbp);
566 		G_STRIPE_LOGREQ(cbp, "Sending request.");
567 		cp = cbp->bio_caller2;
568 		cbp->bio_caller2 = NULL;
569 		g_io_request(cbp, cp);
570 	}
571 }
572 
573 static void
574 g_stripe_start(struct bio *bp)
575 {
576 	off_t offset, start, length, nstripe, stripesize;
577 	struct g_stripe_softc *sc;
578 	u_int no;
579 	int error, fast = 0;
580 
581 	sc = bp->bio_to->geom->softc;
582 	/*
583 	 * If sc == NULL, provider's error should be set and g_stripe_start()
584 	 * should not be called at all.
585 	 */
586 	KASSERT(sc != NULL,
587 	    ("Provider's error should be set (error=%d)(device=%s).",
588 	    bp->bio_to->error, bp->bio_to->name));
589 
590 	G_STRIPE_LOGREQ(bp, "Request received.");
591 
592 	switch (bp->bio_cmd) {
593 	case BIO_READ:
594 	case BIO_WRITE:
595 	case BIO_DELETE:
596 		break;
597 	case BIO_SPEEDUP:
598 	case BIO_FLUSH:
599 		g_stripe_pushdown(sc, bp);
600 		return;
601 	case BIO_GETATTR:
602 		/* To which provider it should be delivered? */
603 	default:
604 		g_io_deliver(bp, EOPNOTSUPP);
605 		return;
606 	}
607 
608 	stripesize = sc->sc_stripesize;
609 
610 	/*
611 	 * Calculations are quite messy, but fast I hope.
612 	 */
613 
614 	/* Stripe number. */
615 	/* nstripe = bp->bio_offset / stripesize; */
616 	nstripe = bp->bio_offset >> (off_t)sc->sc_stripebits;
617 	/* Disk number. */
618 	no = nstripe % sc->sc_ndisks;
619 	/* Start position in stripe. */
620 	/* start = bp->bio_offset % stripesize; */
621 	start = bp->bio_offset & (stripesize - 1);
622 	/* Start position in disk. */
623 	/* offset = (nstripe / sc->sc_ndisks) * stripesize + start; */
624 	offset = ((nstripe / sc->sc_ndisks) << sc->sc_stripebits) + start;
625 	/* Length of data to operate. */
626 	length = MIN(bp->bio_length, stripesize - start);
627 
628 	/*
629 	 * Do use "fast" mode when:
630 	 * 1. "Fast" mode is ON.
631 	 * and
632 	 * 2. Request size is less than or equal to MAXPHYS,
633 	 *    which should always be true.
634 	 * and
635 	 * 3. Request size is bigger than stripesize * ndisks. If it isn't,
636 	 *    there will be no need to send more than one I/O request to
637 	 *    a provider, so there is nothing to optmize.
638 	 * and
639 	 * 4. Request is not unmapped.
640 	 * and
641 	 * 5. It is not a BIO_DELETE.
642 	 */
643 	if (g_stripe_fast && bp->bio_length <= MAXPHYS &&
644 	    bp->bio_length >= stripesize * sc->sc_ndisks &&
645 	    (bp->bio_flags & BIO_UNMAPPED) == 0 &&
646 	    bp->bio_cmd != BIO_DELETE) {
647 		fast = 1;
648 	}
649 	error = 0;
650 	if (fast) {
651 		error = g_stripe_start_fast(bp, no, offset, length);
652 		if (error != 0)
653 			g_stripe_fast_failed++;
654 	}
655 	/*
656 	 * Do use "economic" when:
657 	 * 1. "Economic" mode is ON.
658 	 * or
659 	 * 2. "Fast" mode failed. It can only fail if there is no memory.
660 	 */
661 	if (!fast || error != 0)
662 		error = g_stripe_start_economic(bp, no, offset, length);
663 	if (error != 0) {
664 		if (bp->bio_error == 0)
665 			bp->bio_error = error;
666 		g_io_deliver(bp, bp->bio_error);
667 	}
668 }
669 
670 static void
671 g_stripe_check_and_run(struct g_stripe_softc *sc)
672 {
673 	struct g_provider *dp;
674 	off_t mediasize, ms;
675 	u_int no, sectorsize = 0;
676 
677 	g_topology_assert();
678 	if (g_stripe_nvalid(sc) != sc->sc_ndisks)
679 		return;
680 
681 	sc->sc_provider = g_new_providerf(sc->sc_geom, "stripe/%s",
682 	    sc->sc_name);
683 	sc->sc_provider->flags |= G_PF_DIRECT_SEND | G_PF_DIRECT_RECEIVE;
684 	if (g_stripe_fast == 0)
685 		sc->sc_provider->flags |= G_PF_ACCEPT_UNMAPPED;
686 	/*
687 	 * Find the smallest disk.
688 	 */
689 	mediasize = sc->sc_disks[0]->provider->mediasize;
690 	if (sc->sc_type == G_STRIPE_TYPE_AUTOMATIC)
691 		mediasize -= sc->sc_disks[0]->provider->sectorsize;
692 	mediasize -= mediasize % sc->sc_stripesize;
693 	sectorsize = sc->sc_disks[0]->provider->sectorsize;
694 	for (no = 1; no < sc->sc_ndisks; no++) {
695 		dp = sc->sc_disks[no]->provider;
696 		ms = dp->mediasize;
697 		if (sc->sc_type == G_STRIPE_TYPE_AUTOMATIC)
698 			ms -= dp->sectorsize;
699 		ms -= ms % sc->sc_stripesize;
700 		if (ms < mediasize)
701 			mediasize = ms;
702 		sectorsize = lcm(sectorsize, dp->sectorsize);
703 
704 		/* A provider underneath us doesn't support unmapped */
705 		if ((dp->flags & G_PF_ACCEPT_UNMAPPED) == 0) {
706 			G_STRIPE_DEBUG(1, "Cancelling unmapped "
707 			    "because of %s.", dp->name);
708 			sc->sc_provider->flags &= ~G_PF_ACCEPT_UNMAPPED;
709 		}
710 	}
711 	sc->sc_provider->sectorsize = sectorsize;
712 	sc->sc_provider->mediasize = mediasize * sc->sc_ndisks;
713 	sc->sc_provider->stripesize = sc->sc_stripesize;
714 	sc->sc_provider->stripeoffset = 0;
715 	g_error_provider(sc->sc_provider, 0);
716 
717 	G_STRIPE_DEBUG(0, "Device %s activated.", sc->sc_provider->name);
718 }
719 
720 static int
721 g_stripe_read_metadata(struct g_consumer *cp, struct g_stripe_metadata *md)
722 {
723 	struct g_provider *pp;
724 	u_char *buf;
725 	int error;
726 
727 	g_topology_assert();
728 
729 	error = g_access(cp, 1, 0, 0);
730 	if (error != 0)
731 		return (error);
732 	pp = cp->provider;
733 	g_topology_unlock();
734 	buf = g_read_data(cp, pp->mediasize - pp->sectorsize, pp->sectorsize,
735 	    &error);
736 	g_topology_lock();
737 	g_access(cp, -1, 0, 0);
738 	if (buf == NULL)
739 		return (error);
740 
741 	/* Decode metadata. */
742 	stripe_metadata_decode(buf, md);
743 	g_free(buf);
744 
745 	return (0);
746 }
747 
748 /*
749  * Add disk to given device.
750  */
751 static int
752 g_stripe_add_disk(struct g_stripe_softc *sc, struct g_provider *pp, u_int no)
753 {
754 	struct g_consumer *cp, *fcp;
755 	struct g_geom *gp;
756 	int error;
757 
758 	g_topology_assert();
759 	/* Metadata corrupted? */
760 	if (no >= sc->sc_ndisks)
761 		return (EINVAL);
762 
763 	/* Check if disk is not already attached. */
764 	if (sc->sc_disks[no] != NULL)
765 		return (EEXIST);
766 
767 	gp = sc->sc_geom;
768 	fcp = LIST_FIRST(&gp->consumer);
769 
770 	cp = g_new_consumer(gp);
771 	cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE;
772 	cp->private = NULL;
773 	cp->index = no;
774 	error = g_attach(cp, pp);
775 	if (error != 0) {
776 		g_destroy_consumer(cp);
777 		return (error);
778 	}
779 
780 	if (fcp != NULL && (fcp->acr > 0 || fcp->acw > 0 || fcp->ace > 0)) {
781 		error = g_access(cp, fcp->acr, fcp->acw, fcp->ace);
782 		if (error != 0) {
783 			g_detach(cp);
784 			g_destroy_consumer(cp);
785 			return (error);
786 		}
787 	}
788 	if (sc->sc_type == G_STRIPE_TYPE_AUTOMATIC) {
789 		struct g_stripe_metadata md;
790 
791 		/* Reread metadata. */
792 		error = g_stripe_read_metadata(cp, &md);
793 		if (error != 0)
794 			goto fail;
795 
796 		if (strcmp(md.md_magic, G_STRIPE_MAGIC) != 0 ||
797 		    strcmp(md.md_name, sc->sc_name) != 0 ||
798 		    md.md_id != sc->sc_id) {
799 			G_STRIPE_DEBUG(0, "Metadata on %s changed.", pp->name);
800 			goto fail;
801 		}
802 	}
803 
804 	sc->sc_disks[no] = cp;
805 	G_STRIPE_DEBUG(0, "Disk %s attached to %s.", pp->name, sc->sc_name);
806 	g_stripe_check_and_run(sc);
807 
808 	return (0);
809 fail:
810 	if (fcp != NULL && (fcp->acr > 0 || fcp->acw > 0 || fcp->ace > 0))
811 		g_access(cp, -fcp->acr, -fcp->acw, -fcp->ace);
812 	g_detach(cp);
813 	g_destroy_consumer(cp);
814 	return (error);
815 }
816 
817 static struct g_geom *
818 g_stripe_create(struct g_class *mp, const struct g_stripe_metadata *md,
819     u_int type)
820 {
821 	struct g_stripe_softc *sc;
822 	struct g_geom *gp;
823 	u_int no;
824 
825 	g_topology_assert();
826 	G_STRIPE_DEBUG(1, "Creating device %s (id=%u).", md->md_name,
827 	    md->md_id);
828 
829 	/* Two disks is minimum. */
830 	if (md->md_all < 2) {
831 		G_STRIPE_DEBUG(0, "Too few disks defined for %s.", md->md_name);
832 		return (NULL);
833 	}
834 #if 0
835 	/* Stripe size have to be grater than or equal to sector size. */
836 	if (md->md_stripesize < sectorsize) {
837 		G_STRIPE_DEBUG(0, "Invalid stripe size for %s.", md->md_name);
838 		return (NULL);
839 	}
840 #endif
841 	/* Stripe size have to be power of 2. */
842 	if (!powerof2(md->md_stripesize)) {
843 		G_STRIPE_DEBUG(0, "Invalid stripe size for %s.", md->md_name);
844 		return (NULL);
845 	}
846 
847 	/* Check for duplicate unit */
848 	LIST_FOREACH(gp, &mp->geom, geom) {
849 		sc = gp->softc;
850 		if (sc != NULL && strcmp(sc->sc_name, md->md_name) == 0) {
851 			G_STRIPE_DEBUG(0, "Device %s already configured.",
852 			    sc->sc_name);
853 			return (NULL);
854 		}
855 	}
856 	gp = g_new_geomf(mp, "%s", md->md_name);
857 	sc = malloc(sizeof(*sc), M_STRIPE, M_WAITOK | M_ZERO);
858 	gp->start = g_stripe_start;
859 	gp->spoiled = g_stripe_orphan;
860 	gp->orphan = g_stripe_orphan;
861 	gp->access = g_stripe_access;
862 	gp->dumpconf = g_stripe_dumpconf;
863 
864 	sc->sc_id = md->md_id;
865 	sc->sc_stripesize = md->md_stripesize;
866 	sc->sc_stripebits = bitcount32(sc->sc_stripesize - 1);
867 	sc->sc_ndisks = md->md_all;
868 	sc->sc_disks = malloc(sizeof(struct g_consumer *) * sc->sc_ndisks,
869 	    M_STRIPE, M_WAITOK | M_ZERO);
870 	for (no = 0; no < sc->sc_ndisks; no++)
871 		sc->sc_disks[no] = NULL;
872 	sc->sc_type = type;
873 	mtx_init(&sc->sc_lock, "gstripe lock", NULL, MTX_DEF);
874 
875 	gp->softc = sc;
876 	sc->sc_geom = gp;
877 	sc->sc_provider = NULL;
878 
879 	G_STRIPE_DEBUG(0, "Device %s created (id=%u).", sc->sc_name, sc->sc_id);
880 
881 	return (gp);
882 }
883 
884 static int
885 g_stripe_destroy(struct g_stripe_softc *sc, boolean_t force)
886 {
887 	struct g_provider *pp;
888 	struct g_consumer *cp, *cp1;
889 	struct g_geom *gp;
890 
891 	g_topology_assert();
892 
893 	if (sc == NULL)
894 		return (ENXIO);
895 
896 	pp = sc->sc_provider;
897 	if (pp != NULL && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) {
898 		if (force) {
899 			G_STRIPE_DEBUG(0, "Device %s is still open, so it "
900 			    "can't be definitely removed.", pp->name);
901 		} else {
902 			G_STRIPE_DEBUG(1,
903 			    "Device %s is still open (r%dw%de%d).", pp->name,
904 			    pp->acr, pp->acw, pp->ace);
905 			return (EBUSY);
906 		}
907 	}
908 
909 	gp = sc->sc_geom;
910 	LIST_FOREACH_SAFE(cp, &gp->consumer, consumer, cp1) {
911 		g_stripe_remove_disk(cp);
912 		if (cp1 == NULL)
913 			return (0);	/* Recursion happened. */
914 	}
915 	if (!LIST_EMPTY(&gp->consumer))
916 		return (EINPROGRESS);
917 
918 	gp->softc = NULL;
919 	KASSERT(sc->sc_provider == NULL, ("Provider still exists? (device=%s)",
920 	    gp->name));
921 	free(sc->sc_disks, M_STRIPE);
922 	mtx_destroy(&sc->sc_lock);
923 	free(sc, M_STRIPE);
924 	G_STRIPE_DEBUG(0, "Device %s destroyed.", gp->name);
925 	g_wither_geom(gp, ENXIO);
926 	return (0);
927 }
928 
929 static int
930 g_stripe_destroy_geom(struct gctl_req *req __unused,
931     struct g_class *mp __unused, struct g_geom *gp)
932 {
933 	struct g_stripe_softc *sc;
934 
935 	sc = gp->softc;
936 	return (g_stripe_destroy(sc, 0));
937 }
938 
939 static struct g_geom *
940 g_stripe_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
941 {
942 	struct g_stripe_metadata md;
943 	struct g_stripe_softc *sc;
944 	struct g_consumer *cp;
945 	struct g_geom *gp;
946 	int error;
947 
948 	g_trace(G_T_TOPOLOGY, "%s(%s, %s)", __func__, mp->name, pp->name);
949 	g_topology_assert();
950 
951 	/* Skip providers that are already open for writing. */
952 	if (pp->acw > 0)
953 		return (NULL);
954 
955 	G_STRIPE_DEBUG(3, "Tasting %s.", pp->name);
956 
957 	gp = g_new_geomf(mp, "stripe:taste");
958 	gp->start = g_stripe_start;
959 	gp->access = g_stripe_access;
960 	gp->orphan = g_stripe_orphan;
961 	cp = g_new_consumer(gp);
962 	g_attach(cp, pp);
963 	error = g_stripe_read_metadata(cp, &md);
964 	g_detach(cp);
965 	g_destroy_consumer(cp);
966 	g_destroy_geom(gp);
967 	if (error != 0)
968 		return (NULL);
969 	gp = NULL;
970 
971 	if (strcmp(md.md_magic, G_STRIPE_MAGIC) != 0)
972 		return (NULL);
973 	if (md.md_version > G_STRIPE_VERSION) {
974 		printf("geom_stripe.ko module is too old to handle %s.\n",
975 		    pp->name);
976 		return (NULL);
977 	}
978 	/*
979 	 * Backward compatibility:
980 	 */
981 	/* There was no md_provider field in earlier versions of metadata. */
982 	if (md.md_version < 2)
983 		bzero(md.md_provider, sizeof(md.md_provider));
984 	/* There was no md_provsize field in earlier versions of metadata. */
985 	if (md.md_version < 3)
986 		md.md_provsize = pp->mediasize;
987 
988 	if (md.md_provider[0] != '\0' &&
989 	    !g_compare_names(md.md_provider, pp->name))
990 		return (NULL);
991 	if (md.md_provsize != pp->mediasize)
992 		return (NULL);
993 
994 	/*
995 	 * Let's check if device already exists.
996 	 */
997 	sc = NULL;
998 	LIST_FOREACH(gp, &mp->geom, geom) {
999 		sc = gp->softc;
1000 		if (sc == NULL)
1001 			continue;
1002 		if (sc->sc_type != G_STRIPE_TYPE_AUTOMATIC)
1003 			continue;
1004 		if (strcmp(md.md_name, sc->sc_name) != 0)
1005 			continue;
1006 		if (md.md_id != sc->sc_id)
1007 			continue;
1008 		break;
1009 	}
1010 	if (gp != NULL) {
1011 		G_STRIPE_DEBUG(1, "Adding disk %s to %s.", pp->name, gp->name);
1012 		error = g_stripe_add_disk(sc, pp, md.md_no);
1013 		if (error != 0) {
1014 			G_STRIPE_DEBUG(0,
1015 			    "Cannot add disk %s to %s (error=%d).", pp->name,
1016 			    gp->name, error);
1017 			return (NULL);
1018 		}
1019 	} else {
1020 		gp = g_stripe_create(mp, &md, G_STRIPE_TYPE_AUTOMATIC);
1021 		if (gp == NULL) {
1022 			G_STRIPE_DEBUG(0, "Cannot create device %s.",
1023 			    md.md_name);
1024 			return (NULL);
1025 		}
1026 		sc = gp->softc;
1027 		G_STRIPE_DEBUG(1, "Adding disk %s to %s.", pp->name, gp->name);
1028 		error = g_stripe_add_disk(sc, pp, md.md_no);
1029 		if (error != 0) {
1030 			G_STRIPE_DEBUG(0,
1031 			    "Cannot add disk %s to %s (error=%d).", pp->name,
1032 			    gp->name, error);
1033 			g_stripe_destroy(sc, 1);
1034 			return (NULL);
1035 		}
1036 	}
1037 
1038 	return (gp);
1039 }
1040 
1041 static void
1042 g_stripe_ctl_create(struct gctl_req *req, struct g_class *mp)
1043 {
1044 	u_int attached, no;
1045 	struct g_stripe_metadata md;
1046 	struct g_provider *pp;
1047 	struct g_stripe_softc *sc;
1048 	struct g_geom *gp;
1049 	struct sbuf *sb;
1050 	off_t *stripesize;
1051 	const char *name;
1052 	char param[16];
1053 	int *nargs;
1054 
1055 	g_topology_assert();
1056 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
1057 	if (nargs == NULL) {
1058 		gctl_error(req, "No '%s' argument.", "nargs");
1059 		return;
1060 	}
1061 	if (*nargs <= 2) {
1062 		gctl_error(req, "Too few arguments.");
1063 		return;
1064 	}
1065 
1066 	strlcpy(md.md_magic, G_STRIPE_MAGIC, sizeof(md.md_magic));
1067 	md.md_version = G_STRIPE_VERSION;
1068 	name = gctl_get_asciiparam(req, "arg0");
1069 	if (name == NULL) {
1070 		gctl_error(req, "No 'arg%u' argument.", 0);
1071 		return;
1072 	}
1073 	strlcpy(md.md_name, name, sizeof(md.md_name));
1074 	md.md_id = arc4random();
1075 	md.md_no = 0;
1076 	md.md_all = *nargs - 1;
1077 	stripesize = gctl_get_paraml(req, "stripesize", sizeof(*stripesize));
1078 	if (stripesize == NULL) {
1079 		gctl_error(req, "No '%s' argument.", "stripesize");
1080 		return;
1081 	}
1082 	md.md_stripesize = (uint32_t)*stripesize;
1083 	bzero(md.md_provider, sizeof(md.md_provider));
1084 	/* This field is not important here. */
1085 	md.md_provsize = 0;
1086 
1087 	/* Check all providers are valid */
1088 	for (no = 1; no < *nargs; no++) {
1089 		snprintf(param, sizeof(param), "arg%u", no);
1090 		name = gctl_get_asciiparam(req, param);
1091 		if (name == NULL) {
1092 			gctl_error(req, "No 'arg%u' argument.", no);
1093 			return;
1094 		}
1095 		if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
1096 			name += strlen("/dev/");
1097 		pp = g_provider_by_name(name);
1098 		if (pp == NULL) {
1099 			G_STRIPE_DEBUG(1, "Disk %s is invalid.", name);
1100 			gctl_error(req, "Disk %s is invalid.", name);
1101 			return;
1102 		}
1103 	}
1104 
1105 	gp = g_stripe_create(mp, &md, G_STRIPE_TYPE_MANUAL);
1106 	if (gp == NULL) {
1107 		gctl_error(req, "Can't configure %s.", md.md_name);
1108 		return;
1109 	}
1110 
1111 	sc = gp->softc;
1112 	sb = sbuf_new_auto();
1113 	sbuf_printf(sb, "Can't attach disk(s) to %s:", gp->name);
1114 	for (attached = 0, no = 1; no < *nargs; no++) {
1115 		snprintf(param, sizeof(param), "arg%u", no);
1116 		name = gctl_get_asciiparam(req, param);
1117 		if (name == NULL) {
1118 			gctl_error(req, "No 'arg%u' argument.", no);
1119 			continue;
1120 		}
1121 		if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
1122 			name += strlen("/dev/");
1123 		pp = g_provider_by_name(name);
1124 		KASSERT(pp != NULL, ("Provider %s disappear?!", name));
1125 		if (g_stripe_add_disk(sc, pp, no - 1) != 0) {
1126 			G_STRIPE_DEBUG(1, "Disk %u (%s) not attached to %s.",
1127 			    no, pp->name, gp->name);
1128 			sbuf_printf(sb, " %s", pp->name);
1129 			continue;
1130 		}
1131 		attached++;
1132 	}
1133 	sbuf_finish(sb);
1134 	if (md.md_all != attached) {
1135 		g_stripe_destroy(gp->softc, 1);
1136 		gctl_error(req, "%s", sbuf_data(sb));
1137 	}
1138 	sbuf_delete(sb);
1139 }
1140 
1141 static struct g_stripe_softc *
1142 g_stripe_find_device(struct g_class *mp, const char *name)
1143 {
1144 	struct g_stripe_softc *sc;
1145 	struct g_geom *gp;
1146 
1147 	LIST_FOREACH(gp, &mp->geom, geom) {
1148 		sc = gp->softc;
1149 		if (sc == NULL)
1150 			continue;
1151 		if (strcmp(sc->sc_name, name) == 0)
1152 			return (sc);
1153 	}
1154 	return (NULL);
1155 }
1156 
1157 static void
1158 g_stripe_ctl_destroy(struct gctl_req *req, struct g_class *mp)
1159 {
1160 	struct g_stripe_softc *sc;
1161 	int *force, *nargs, error;
1162 	const char *name;
1163 	char param[16];
1164 	u_int i;
1165 
1166 	g_topology_assert();
1167 
1168 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
1169 	if (nargs == NULL) {
1170 		gctl_error(req, "No '%s' argument.", "nargs");
1171 		return;
1172 	}
1173 	if (*nargs <= 0) {
1174 		gctl_error(req, "Missing device(s).");
1175 		return;
1176 	}
1177 	force = gctl_get_paraml(req, "force", sizeof(*force));
1178 	if (force == NULL) {
1179 		gctl_error(req, "No '%s' argument.", "force");
1180 		return;
1181 	}
1182 
1183 	for (i = 0; i < (u_int)*nargs; i++) {
1184 		snprintf(param, sizeof(param), "arg%u", i);
1185 		name = gctl_get_asciiparam(req, param);
1186 		if (name == NULL) {
1187 			gctl_error(req, "No 'arg%u' argument.", i);
1188 			return;
1189 		}
1190 		sc = g_stripe_find_device(mp, name);
1191 		if (sc == NULL) {
1192 			gctl_error(req, "No such device: %s.", name);
1193 			return;
1194 		}
1195 		error = g_stripe_destroy(sc, *force);
1196 		if (error != 0) {
1197 			gctl_error(req, "Cannot destroy device %s (error=%d).",
1198 			    sc->sc_name, error);
1199 			return;
1200 		}
1201 	}
1202 }
1203 
1204 static void
1205 g_stripe_config(struct gctl_req *req, struct g_class *mp, const char *verb)
1206 {
1207 	uint32_t *version;
1208 
1209 	g_topology_assert();
1210 
1211 	version = gctl_get_paraml(req, "version", sizeof(*version));
1212 	if (version == NULL) {
1213 		gctl_error(req, "No '%s' argument.", "version");
1214 		return;
1215 	}
1216 	if (*version != G_STRIPE_VERSION) {
1217 		gctl_error(req, "Userland and kernel parts are out of sync.");
1218 		return;
1219 	}
1220 
1221 	if (strcmp(verb, "create") == 0) {
1222 		g_stripe_ctl_create(req, mp);
1223 		return;
1224 	} else if (strcmp(verb, "destroy") == 0 ||
1225 	    strcmp(verb, "stop") == 0) {
1226 		g_stripe_ctl_destroy(req, mp);
1227 		return;
1228 	}
1229 
1230 	gctl_error(req, "Unknown verb.");
1231 }
1232 
1233 static void
1234 g_stripe_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
1235     struct g_consumer *cp, struct g_provider *pp)
1236 {
1237 	struct g_stripe_softc *sc;
1238 
1239 	sc = gp->softc;
1240 	if (sc == NULL)
1241 		return;
1242 	if (pp != NULL) {
1243 		/* Nothing here. */
1244 	} else if (cp != NULL) {
1245 		sbuf_printf(sb, "%s<Number>%u</Number>\n", indent,
1246 		    (u_int)cp->index);
1247 	} else {
1248 		sbuf_printf(sb, "%s<ID>%u</ID>\n", indent, (u_int)sc->sc_id);
1249 		sbuf_printf(sb, "%s<Stripesize>%ju</Stripesize>\n", indent,
1250 		    (uintmax_t)sc->sc_stripesize);
1251 		sbuf_printf(sb, "%s<Type>", indent);
1252 		switch (sc->sc_type) {
1253 		case G_STRIPE_TYPE_AUTOMATIC:
1254 			sbuf_cat(sb, "AUTOMATIC");
1255 			break;
1256 		case G_STRIPE_TYPE_MANUAL:
1257 			sbuf_cat(sb, "MANUAL");
1258 			break;
1259 		default:
1260 			sbuf_cat(sb, "UNKNOWN");
1261 			break;
1262 		}
1263 		sbuf_cat(sb, "</Type>\n");
1264 		sbuf_printf(sb, "%s<Status>Total=%u, Online=%u</Status>\n",
1265 		    indent, sc->sc_ndisks, g_stripe_nvalid(sc));
1266 		sbuf_printf(sb, "%s<State>", indent);
1267 		if (sc->sc_provider != NULL && sc->sc_provider->error == 0)
1268 			sbuf_cat(sb, "UP");
1269 		else
1270 			sbuf_cat(sb, "DOWN");
1271 		sbuf_cat(sb, "</State>\n");
1272 	}
1273 }
1274 
1275 DECLARE_GEOM_CLASS(g_stripe_class, g_stripe);
1276 MODULE_VERSION(geom_stripe, 0);
1277