xref: /freebsd/sys/geom/multipath/g_multipath.c (revision 7a1c0d963366a31363d3705697a083dd8efee077)
1 /*-
2  * Copyright (c) 2006-2007 Matthew Jacob <mjacob@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 /*
27  * Based upon work by Pawel Jakub Dawidek <pjd@FreeBSD.org> for all of the
28  * fine geom examples, and by Poul Henning Kamp <phk@FreeBSD.org> for GEOM
29  * itself, all of which is most gratefully acknowledged.
30  */
31 
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/kernel.h>
37 #include <sys/module.h>
38 #include <sys/lock.h>
39 #include <sys/mutex.h>
40 #include <sys/bio.h>
41 #include <sys/sysctl.h>
42 #include <sys/kthread.h>
43 #include <sys/malloc.h>
44 #include <geom/geom.h>
45 #include <geom/multipath/g_multipath.h>
46 
47 FEATURE(geom_multipath, "GEOM multipath support");
48 
49 SYSCTL_DECL(_kern_geom);
50 SYSCTL_NODE(_kern_geom, OID_AUTO, multipath, CTLFLAG_RW, 0,
51     "GEOM_MULTIPATH tunables");
52 static u_int g_multipath_debug = 0;
53 SYSCTL_UINT(_kern_geom_multipath, OID_AUTO, debug, CTLFLAG_RW,
54     &g_multipath_debug, 0, "Debug level");
55 
56 static enum {
57 	GKT_NIL,
58 	GKT_RUN,
59 	GKT_DIE
60 } g_multipath_kt_state;
61 static struct bio_queue_head gmtbq;
62 static struct mtx gmtbq_mtx;
63 
64 static void g_multipath_orphan(struct g_consumer *);
65 static void g_multipath_start(struct bio *);
66 static void g_multipath_done(struct bio *);
67 static void g_multipath_done_error(struct bio *);
68 static void g_multipath_kt(void *);
69 
70 static int g_multipath_destroy(struct g_geom *);
71 static int
72 g_multipath_destroy_geom(struct gctl_req *, struct g_class *, struct g_geom *);
73 
74 static struct g_geom *g_multipath_find_geom(struct g_class *, const char *);
75 static int g_multipath_rotate(struct g_geom *);
76 
77 static g_taste_t g_multipath_taste;
78 static g_ctl_req_t g_multipath_config;
79 static g_init_t g_multipath_init;
80 static g_fini_t g_multipath_fini;
81 
82 struct g_class g_multipath_class = {
83 	.name		= G_MULTIPATH_CLASS_NAME,
84 	.version	= G_VERSION,
85 	.ctlreq		= g_multipath_config,
86 	.taste		= g_multipath_taste,
87 	.destroy_geom	= g_multipath_destroy_geom,
88 	.init		= g_multipath_init,
89 	.fini		= g_multipath_fini
90 };
91 
92 #define	MP_BAD		0x1
93 #define	MP_POSTED	0x2
94 
95 static void
96 g_mpd(void *arg, int flags __unused)
97 {
98 	struct g_consumer *cp;
99 
100 	g_topology_assert();
101 	cp = arg;
102 	if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0)
103 		g_access(cp, -cp->acr, -cp->acw, -cp->ace);
104 	if (cp->provider) {
105 		printf("GEOM_MULTIPATH: %s removed from %s\n",
106 		    cp->provider->name, cp->geom->name);
107 		g_detach(cp);
108 	}
109 	g_destroy_consumer(cp);
110 }
111 
112 static void
113 g_multipath_orphan(struct g_consumer *cp)
114 {
115 	if ((cp->index & MP_POSTED) == 0) {
116 		cp->index |= MP_POSTED;
117 		printf("GEOM_MULTIPATH: %s orphaned in %s\n",
118 		    cp->provider->name, cp->geom->name);
119 		g_mpd(cp, 0);
120 	}
121 }
122 
123 static void
124 g_multipath_start(struct bio *bp)
125 {
126 	struct g_multipath_softc *sc;
127 	struct g_geom *gp;
128 	struct g_consumer *cp;
129 	struct bio *cbp;
130 
131 	gp = bp->bio_to->geom;
132 	sc = gp->softc;
133 	KASSERT(sc != NULL, ("NULL sc"));
134 	cp = sc->cp_active;
135 	if (cp == NULL) {
136 		g_io_deliver(bp, ENXIO);
137 		return;
138 	}
139 	cbp = g_clone_bio(bp);
140 	if (cbp == NULL) {
141 		g_io_deliver(bp, ENOMEM);
142 		return;
143 	}
144 	cbp->bio_done = g_multipath_done;
145 	g_io_request(cbp, cp);
146 }
147 
148 static void
149 g_multipath_done(struct bio *bp)
150 {
151 	if (bp->bio_error == ENXIO || bp->bio_error == EIO) {
152 		mtx_lock(&gmtbq_mtx);
153 		bioq_insert_tail(&gmtbq, bp);
154 		wakeup(&g_multipath_kt_state);
155 		mtx_unlock(&gmtbq_mtx);
156 	} else {
157 		g_std_done(bp);
158 	}
159 }
160 
161 static void
162 g_multipath_done_error(struct bio *bp)
163 {
164 	struct bio *pbp;
165 	struct g_geom *gp;
166 	struct g_multipath_softc *sc;
167 	struct g_consumer *cp;
168 	struct g_provider *pp;
169 
170 	/*
171 	 * If we had a failure, we have to check first to see
172 	 * whether the consumer it failed on was the currently
173 	 * active consumer (i.e., this is the first in perhaps
174 	 * a number of failures). If so, we then switch consumers
175 	 * to the next available consumer.
176 	 */
177 
178 	g_topology_lock();
179 	pbp = bp->bio_parent;
180 	gp = pbp->bio_to->geom;
181 	sc = gp->softc;
182 	cp = bp->bio_from;
183 	pp = cp->provider;
184 
185 	cp->index |= MP_BAD;
186 	if (cp->nend == cp->nstart && pp->nend == pp->nstart) {
187 		cp->index |= MP_POSTED;
188 		g_post_event(g_mpd, cp, M_NOWAIT, NULL);
189 	}
190 	if (cp == sc->cp_active) {
191 		struct g_consumer *lcp;
192 		printf("GEOM_MULTIPATH: %s failed in %s\n",
193 		    pp->name, sc->sc_name);
194 		sc->cp_active = NULL;
195 		LIST_FOREACH(lcp, &gp->consumer, consumer) {
196 			if ((lcp->index & MP_BAD) == 0) {
197 				sc->cp_active = lcp;
198 				break;
199 			}
200 		}
201 		if (sc->cp_active == NULL || sc->cp_active->provider == NULL) {
202 			printf("GEOM_MULTIPATH: out of providers for %s\n",
203 			    sc->sc_name);
204 			g_topology_unlock();
205 			return;
206 		} else {
207 			printf("GEOM_MULTIPATH: %s now active path in %s\n",
208 			    sc->cp_active->provider->name, sc->sc_name);
209 		}
210 	}
211 	g_topology_unlock();
212 
213 	/*
214 	 * If we can fruitfully restart the I/O, do so.
215 	 */
216 	if (sc->cp_active) {
217 		g_destroy_bio(bp);
218 		pbp->bio_children--;
219 		g_multipath_start(pbp);
220 	} else {
221 		g_std_done(bp);
222 	}
223 }
224 
225 static void
226 g_multipath_kt(void *arg)
227 {
228 
229 	g_multipath_kt_state = GKT_RUN;
230 	mtx_lock(&gmtbq_mtx);
231 	while (g_multipath_kt_state == GKT_RUN) {
232 		for (;;) {
233 			struct bio *bp;
234 
235 			bp = bioq_takefirst(&gmtbq);
236 			if (bp == NULL)
237 				break;
238 			mtx_unlock(&gmtbq_mtx);
239 			g_multipath_done_error(bp);
240 			mtx_lock(&gmtbq_mtx);
241 		}
242 		msleep(&g_multipath_kt_state, &gmtbq_mtx, PRIBIO,
243 		    "gkt:wait", hz / 10);
244 	}
245 	mtx_unlock(&gmtbq_mtx);
246 	wakeup(&g_multipath_kt_state);
247 	kproc_exit(0);
248 }
249 
250 
251 static int
252 g_multipath_access(struct g_provider *pp, int dr, int dw, int de)
253 {
254 	struct g_geom *gp;
255 	struct g_consumer *cp, *badcp = NULL;
256 	int error;
257 
258 	gp = pp->geom;
259 
260 	LIST_FOREACH(cp, &gp->consumer, consumer) {
261 		error = g_access(cp, dr, dw, de);
262 		if (error) {
263 			badcp = cp;
264 			goto fail;
265 		}
266 	}
267 	return (0);
268 
269 fail:
270 	LIST_FOREACH(cp, &gp->consumer, consumer) {
271 		if (cp == badcp)
272 			break;
273 		(void) g_access(cp, -dr, -dw, -de);
274 	}
275 	return (error);
276 }
277 
278 static struct g_geom *
279 g_multipath_create(struct g_class *mp, struct g_multipath_metadata *md)
280 {
281 	struct g_multipath_softc *sc;
282 	struct g_geom *gp;
283 	struct g_provider *pp;
284 
285 	g_topology_assert();
286 
287 	LIST_FOREACH(gp, &mp->geom, geom) {
288 		if (strcmp(gp->name, md->md_name) == 0) {
289 			printf("GEOM_MULTIPATH: name %s already exists\n",
290 			    md->md_name);
291 			return (NULL);
292 		}
293 	}
294 
295 	gp = g_new_geomf(mp, md->md_name);
296 	if (gp == NULL)
297 		goto fail;
298 
299 	sc = g_malloc(sizeof(*sc), M_WAITOK | M_ZERO);
300 	gp->softc = sc;
301 	gp->start = g_multipath_start;
302 	gp->orphan = g_multipath_orphan;
303 	gp->access = g_multipath_access;
304 	memcpy(sc->sc_uuid, md->md_uuid, sizeof (sc->sc_uuid));
305 	memcpy(sc->sc_name, md->md_name, sizeof (sc->sc_name));
306 
307 	pp = g_new_providerf(gp, "multipath/%s", md->md_name);
308 	if (pp == NULL)
309 		goto fail;
310 	/* limit the provider to not have it stomp on metadata */
311 	pp->mediasize = md->md_size - md->md_sectorsize;
312 	pp->sectorsize = md->md_sectorsize;
313 	sc->pp = pp;
314 	g_error_provider(pp, 0);
315 	return (gp);
316 fail:
317 	if (gp != NULL) {
318 		if (gp->softc != NULL)
319 			g_free(gp->softc);
320 		g_destroy_geom(gp);
321 	}
322 	return (NULL);
323 }
324 
325 static int
326 g_multipath_add_disk(struct g_geom *gp, struct g_provider *pp)
327 {
328 	struct g_multipath_softc *sc;
329 	struct g_consumer *cp, *nxtcp;
330 	int error;
331 
332 	g_topology_assert();
333 
334 	sc = gp->softc;
335 	KASSERT(sc, ("no softc"));
336 
337 	/*
338 	 * Make sure that the passed provider isn't already attached
339 	 */
340 	LIST_FOREACH(cp, &gp->consumer, consumer) {
341 		if (cp->provider == pp)
342 			break;
343 	}
344 	if (cp) {
345 		printf("GEOM_MULTIPATH: provider %s already attached to %s\n",
346 		    pp->name, gp->name);
347 		return (EEXIST);
348 	}
349 	nxtcp = LIST_FIRST(&gp->consumer);
350 	cp = g_new_consumer(gp);
351 	if (cp == NULL)
352 		return (ENOMEM);
353 	error = g_attach(cp, pp);
354 	if (error != 0) {
355 		printf("GEOM_MULTIPATH: cannot attach %s to %s",
356 		    pp->name, sc->sc_name);
357 		g_destroy_consumer(cp);
358 		return (error);
359 	}
360 	cp->private = sc;
361 	cp->index = 0;
362 
363 	/*
364 	 * Set access permissions on new consumer to match other consumers
365 	 */
366 	if (nxtcp && (nxtcp->acr + nxtcp->acw +  nxtcp->ace)) {
367 		error = g_access(cp, nxtcp->acr, nxtcp->acw, nxtcp->ace);
368 		if (error) {
369 			printf("GEOM_MULTIPATH: cannot set access in "
370 			    "attaching %s to %s/%s (%d)\n",
371 			    pp->name, sc->sc_name, sc->sc_uuid, error);
372 			g_detach(cp);
373 			g_destroy_consumer(cp);
374 			return (error);
375 		}
376 	}
377 	printf("GEOM_MULTIPATH: adding %s to %s/%s\n",
378 	    pp->name, sc->sc_name, sc->sc_uuid);
379 	if (sc->cp_active == NULL) {
380 		sc->cp_active = cp;
381 		printf("GEOM_MULTIPATH: %s now active path in %s\n",
382 		    pp->name, sc->sc_name);
383 	}
384 	return (0);
385 }
386 
387 static int
388 g_multipath_destroy(struct g_geom *gp)
389 {
390 	struct g_provider *pp;
391 
392 	g_topology_assert();
393 	if (gp->softc == NULL)
394 		return (ENXIO);
395 	pp = LIST_FIRST(&gp->provider);
396 	if (pp != NULL && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0))
397 		return (EBUSY);
398 	printf("GEOM_MULTIPATH: destroying %s\n", gp->name);
399 	g_free(gp->softc);
400 	gp->softc = NULL;
401 	g_wither_geom(gp, ENXIO);
402 	return (0);
403 }
404 
405 static int
406 g_multipath_destroy_geom(struct gctl_req *req, struct g_class *mp,
407     struct g_geom *gp)
408 {
409 
410 	return (g_multipath_destroy(gp));
411 }
412 
413 static int
414 g_multipath_rotate(struct g_geom *gp)
415 {
416 	struct g_consumer *lcp;
417 	struct g_multipath_softc *sc = gp->softc;
418 
419 	g_topology_assert();
420 	if (sc == NULL)
421 		return (ENXIO);
422 	LIST_FOREACH(lcp, &gp->consumer, consumer) {
423 		if ((lcp->index & MP_BAD) == 0) {
424 			if (sc->cp_active != lcp) {
425 				break;
426 			}
427 		}
428 	}
429 	if (lcp) {
430 		sc->cp_active = lcp;
431 		printf("GEOM_MULTIPATH: %s now active path in %s\n",
432 		    lcp->provider->name, sc->sc_name);
433 	}
434 	return (0);
435 }
436 
437 static void
438 g_multipath_init(struct g_class *mp)
439 {
440 	bioq_init(&gmtbq);
441 	mtx_init(&gmtbq_mtx, "gmtbq", NULL, MTX_DEF);
442 	if (kproc_create(g_multipath_kt, mp, NULL, 0, 0, "g_mp_kt") == 0)
443 		g_multipath_kt_state = GKT_RUN;
444 }
445 
446 static void
447 g_multipath_fini(struct g_class *mp)
448 {
449 	if (g_multipath_kt_state == GKT_RUN) {
450 		mtx_lock(&gmtbq_mtx);
451 		g_multipath_kt_state = GKT_DIE;
452 		wakeup(&g_multipath_kt_state);
453 		msleep(&g_multipath_kt_state, &gmtbq_mtx, PRIBIO,
454 		    "gmp:fini", 0);
455 		mtx_unlock(&gmtbq_mtx);
456 	}
457 }
458 
459 static int
460 g_multipath_read_metadata(struct g_consumer *cp,
461     struct g_multipath_metadata *md)
462 {
463 	struct g_provider *pp;
464 	u_char *buf;
465 	int error;
466 
467 	g_topology_assert();
468 	error = g_access(cp, 1, 0, 0);
469 	if (error != 0)
470 		return (error);
471 	pp = cp->provider;
472 	g_topology_unlock();
473 	buf = g_read_data(cp, pp->mediasize - pp->sectorsize,
474 	    pp->sectorsize, &error);
475 	g_topology_lock();
476 	g_access(cp, -1, 0, 0);
477 	if (buf == NULL)
478 		return (error);
479 	multipath_metadata_decode(buf, md);
480 	g_free(buf);
481 	return (0);
482 }
483 
484 static struct g_geom *
485 g_multipath_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
486 {
487 	struct g_multipath_metadata md;
488 	struct g_multipath_softc *sc;
489 	struct g_consumer *cp;
490 	struct g_geom *gp, *gp1;
491 	int error, isnew;
492 
493 	g_topology_assert();
494 
495 	gp = g_new_geomf(mp, "multipath:taste");
496 	gp->start = g_multipath_start;
497 	gp->access = g_multipath_access;
498 	gp->orphan = g_multipath_orphan;
499 	cp = g_new_consumer(gp);
500 	g_attach(cp, pp);
501 	error = g_multipath_read_metadata(cp, &md);
502 	g_detach(cp);
503 	g_destroy_consumer(cp);
504 	g_destroy_geom(gp);
505 	if (error != 0)
506 		return (NULL);
507 	gp = NULL;
508 
509 	if (strcmp(md.md_magic, G_MULTIPATH_MAGIC) != 0) {
510 		if (g_multipath_debug)
511 			printf("%s is not MULTIPATH\n", pp->name);
512 		return (NULL);
513 	}
514 	if (md.md_version != G_MULTIPATH_VERSION) {
515 		printf("%s has version %d multipath id- this module is version "
516 		    " %d: rejecting\n", pp->name, md.md_version,
517 		    G_MULTIPATH_VERSION);
518 		return (NULL);
519 	}
520 	if (g_multipath_debug)
521 		printf("MULTIPATH: %s/%s\n", md.md_name, md.md_uuid);
522 
523 	/*
524 	 * Let's check if such a device already is present. We check against
525 	 * uuid alone first because that's the true distinguishor. If that
526 	 * passes, then we check for name conflicts. If there are conflicts,
527 	 * modify the name.
528 	 *
529 	 * The whole purpose of this is to solve the problem that people don't
530 	 * pick good unique names, but good unique names (like uuids) are a
531 	 * pain to use. So, we allow people to build GEOMs with friendly names
532 	 * and uuids, and modify the names in case there's a collision.
533 	 */
534 	sc = NULL;
535 	LIST_FOREACH(gp, &mp->geom, geom) {
536 		sc = gp->softc;
537 		if (sc == NULL)
538 			continue;
539 		if (strncmp(md.md_uuid, sc->sc_uuid, sizeof(md.md_uuid)) == 0)
540 			break;
541 	}
542 
543 	LIST_FOREACH(gp1, &mp->geom, geom) {
544 		if (gp1 == gp)
545 			continue;
546 		sc = gp1->softc;
547 		if (sc == NULL)
548 			continue;
549 		if (strncmp(md.md_name, sc->sc_name, sizeof(md.md_name)) == 0)
550 			break;
551 	}
552 
553 	/*
554 	 * If gp is NULL, we had no extant MULTIPATH geom with this uuid.
555 	 *
556 	 * If gp1 is *not* NULL, that means we have a MULTIPATH geom extant
557 	 * with the same name (but a different UUID).
558 	 *
559 	 * If gp is NULL, then modify the name with a random number and
560   	 * complain, but allow the creation of the geom to continue.
561 	 *
562 	 * If gp is *not* NULL, just use the geom's name as we're attaching
563 	 * this disk to the (previously generated) name.
564 	 */
565 
566 	if (gp1) {
567 		sc = gp1->softc;
568 		if (gp == NULL) {
569 			char buf[16];
570 			u_long rand = random();
571 
572 			snprintf(buf, sizeof (buf), "%s-%lu", md.md_name, rand);
573 			printf("GEOM_MULTIPATH: geom %s/%s exists already\n",
574 			    sc->sc_name, sc->sc_uuid);
575 			printf("GEOM_MULTIPATH: %s will be (temporarily) %s\n",
576 			    md.md_uuid, buf);
577 			strlcpy(md.md_name, buf, sizeof(md.md_name));
578 		} else {
579 			strlcpy(md.md_name, sc->sc_name, sizeof(md.md_name));
580 		}
581 	}
582 
583 	if (gp == NULL) {
584 		gp = g_multipath_create(mp, &md);
585 		if (gp == NULL) {
586 			printf("GEOM_MULTIPATH: cannot create geom %s/%s\n",
587 			    md.md_name, md.md_uuid);
588 			return (NULL);
589 		}
590 		isnew = 1;
591 	} else {
592 		isnew = 0;
593 	}
594 
595 	sc = gp->softc;
596 	KASSERT(sc != NULL, ("sc is NULL"));
597 	error = g_multipath_add_disk(gp, pp);
598 	if (error != 0) {
599 		if (isnew)
600 			g_multipath_destroy(gp);
601 		return (NULL);
602 	}
603 	return (gp);
604 }
605 
606 static void
607 g_multipath_ctl_add(struct gctl_req *req, struct g_class *mp)
608 {
609 	struct g_geom *gp;
610 	struct g_consumer *cp;
611 	struct g_provider *pp, *pp0;
612 	const char *name, *mpname;
613 	static const char devpf[6] = "/dev/";
614 
615 	g_topology_assert();
616 
617 	mpname = gctl_get_asciiparam(req, "arg0");
618         if (mpname == NULL) {
619                 gctl_error(req, "No 'arg0' argument");
620                 return;
621         }
622 	gp = g_multipath_find_geom(mp, mpname);
623 	if (gp == NULL) {
624 		gctl_error(req, "Device %s is invalid", mpname);
625 		return;
626 	}
627 
628 	name = gctl_get_asciiparam(req, "arg1");
629 	if (name == NULL) {
630 		gctl_error(req, "No 'arg1' argument");
631 		return;
632 	}
633 	if (strncmp(name, devpf, 5) == 0)
634 		name += 5;
635 	pp = g_provider_by_name(name);
636 	if (pp == NULL) {
637 		gctl_error(req, "Provider %s is invalid", name);
638 		return;
639 	}
640 
641 	/*
642 	 * Check to make sure parameters match, if we already have one.
643 	 */
644 	cp = LIST_FIRST(&gp->consumer);
645 	if (cp) {
646 		pp0 = cp->provider;
647 	} else {
648 		pp0 = NULL;
649 	}
650 	if (pp0) {
651 		if (pp0 == pp) {
652 			gctl_error(req, "providers %s and %s are the same",
653 			    pp0->name, pp->name);
654 			return;
655 		}
656 		if (pp0->mediasize != pp->mediasize) {
657 			gctl_error(req, "Provider %s is %jd; Provider %s is %jd",
658 			    pp0->name, (intmax_t) pp0->mediasize,
659 			    pp->name, (intmax_t) pp->mediasize);
660 			return;
661 		}
662 		if (pp0->sectorsize != pp->sectorsize) {
663 			gctl_error(req, "Provider %s has sectorsize %u; Provider %s "
664 			    "has sectorsize %u", pp0->name, pp0->sectorsize,
665 			    pp->name, pp->sectorsize);
666 			return;
667 		}
668 	}
669 
670 	/*
671 	 * Now add....
672 	 */
673 	(void) g_multipath_add_disk(gp, pp);
674 }
675 
676 static struct g_geom *
677 g_multipath_find_geom(struct g_class *mp, const char *name)
678 {
679 	struct g_geom *gp;
680 
681 	LIST_FOREACH(gp, &mp->geom, geom) {
682 		if (strcmp(gp->name, name) == 0) {
683 			return (gp);
684 		}
685 	}
686 	return (NULL);
687 }
688 
689 static void
690 g_multipath_ctl_destroy(struct gctl_req *req, struct g_class *mp)
691 {
692 	struct g_geom *gp;
693 	const char *name;
694 	int error;
695 
696 	g_topology_assert();
697 
698 	name = gctl_get_asciiparam(req, "arg0");
699         if (name == NULL) {
700                 gctl_error(req, "No 'arg0' argument");
701                 return;
702         }
703 	gp = g_multipath_find_geom(mp, name);
704 	if (gp == NULL) {
705 		gctl_error(req, "Device %s is invalid", name);
706 		return;
707 	}
708 	error = g_multipath_destroy(gp);
709 	if (error != 0) {
710 		gctl_error(req, "failed to destroy %s (err=%d)", name, error);
711 	}
712 }
713 
714 static void
715 g_multipath_ctl_rotate(struct gctl_req *req, struct g_class *mp)
716 {
717 	struct g_geom *gp;
718 	const char *name;
719 	int error;
720 
721 	g_topology_assert();
722 
723 	name = gctl_get_asciiparam(req, "arg0");
724         if (name == NULL) {
725                 gctl_error(req, "No 'arg0' argument");
726                 return;
727         }
728 	gp = g_multipath_find_geom(mp, name);
729 	if (gp == NULL) {
730 		gctl_error(req, "Device %s is invalid", name);
731 		return;
732 	}
733 	error = g_multipath_rotate(gp);
734 	if (error != 0) {
735 		gctl_error(req, "failed to rotate %s (err=%d)", name, error);
736 	}
737 }
738 
739 static void
740 g_multipath_ctl_getactive(struct gctl_req *req, struct g_class *mp)
741 {
742 	struct sbuf *sb;
743 	struct g_geom *gp;
744 	struct g_multipath_softc *sc;
745 	const char *name;
746 
747 	sb = sbuf_new_auto();
748 
749 	g_topology_assert();
750 	name = gctl_get_asciiparam(req, "arg0");
751         if (name == NULL) {
752                 gctl_error(req, "No 'arg0' argument");
753                 return;
754         }
755 	gp = g_multipath_find_geom(mp, name);
756 	if (gp == NULL) {
757 		gctl_error(req, "Device %s is invalid", name);
758 		return;
759 	}
760 	sc = gp->softc;
761 	if (sc->cp_active && sc->cp_active->provider) {
762 		sbuf_printf(sb, "%s\n", sc->cp_active->provider->name);
763 	} else {
764 		sbuf_printf(sb, "none\n");
765 	}
766 	sbuf_finish(sb);
767 	gctl_set_param_err(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
768 	sbuf_delete(sb);
769 }
770 
771 static void
772 g_multipath_config(struct gctl_req *req, struct g_class *mp, const char *verb)
773 {
774 	uint32_t *version;
775 	g_topology_assert();
776 	version = gctl_get_paraml(req, "version", sizeof(*version));
777 	if (version == NULL) {
778 		gctl_error(req, "No 'version' argument");
779 	} else if (*version != G_MULTIPATH_VERSION) {
780 		gctl_error(req, "Userland and kernel parts are out of sync");
781 	} else if (strcmp(verb, "add") == 0) {
782 		g_multipath_ctl_add(req, mp);
783 	} else if (strcmp(verb, "destroy") == 0) {
784 		g_multipath_ctl_destroy(req, mp);
785 	} else if (strcmp(verb, "rotate") == 0) {
786 		g_multipath_ctl_rotate(req, mp);
787 	} else if (strcmp(verb, "getactive") == 0) {
788 		g_multipath_ctl_getactive(req, mp);
789 	} else {
790 		gctl_error(req, "Unknown verb %s", verb);
791 	}
792 }
793 DECLARE_GEOM_CLASS(g_multipath_class, g_multipath);
794