g_multipath.c revision 260385
1/*-
2 * Copyright (c) 2011 Alexander Motin <mav@FreeBSD.org>
3 * Copyright (c) 2006-2007 Matthew Jacob <mjacob@FreeBSD.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27/*
28 * Based upon work by Pawel Jakub Dawidek <pjd@FreeBSD.org> for all of the
29 * fine geom examples, and by Poul Henning Kamp <phk@FreeBSD.org> for GEOM
30 * itself, all of which is most gratefully acknowledged.
31 */
32
33#include <sys/cdefs.h>
34__FBSDID("$FreeBSD: stable/10/sys/geom/multipath/g_multipath.c 260385 2014-01-07 01:32:23Z scottl $");
35#include <sys/param.h>
36#include <sys/systm.h>
37#include <sys/kernel.h>
38#include <sys/module.h>
39#include <sys/lock.h>
40#include <sys/mutex.h>
41#include <sys/bio.h>
42#include <sys/sbuf.h>
43#include <sys/sysctl.h>
44#include <sys/kthread.h>
45#include <sys/malloc.h>
46#include <geom/geom.h>
47#include <geom/multipath/g_multipath.h>
48
49FEATURE(geom_multipath, "GEOM multipath support");
50
51SYSCTL_DECL(_kern_geom);
52static SYSCTL_NODE(_kern_geom, OID_AUTO, multipath, CTLFLAG_RW, 0,
53    "GEOM_MULTIPATH tunables");
54static u_int g_multipath_debug = 0;
55SYSCTL_UINT(_kern_geom_multipath, OID_AUTO, debug, CTLFLAG_RW,
56    &g_multipath_debug, 0, "Debug level");
57static u_int g_multipath_exclusive = 1;
58SYSCTL_UINT(_kern_geom_multipath, OID_AUTO, exclusive, CTLFLAG_RW,
59    &g_multipath_exclusive, 0, "Exclusively open providers");
60
61static enum {
62	GKT_NIL,
63	GKT_RUN,
64	GKT_DIE
65} g_multipath_kt_state;
66static struct bio_queue_head gmtbq;
67static struct mtx gmtbq_mtx;
68
69static void g_multipath_orphan(struct g_consumer *);
70static void g_multipath_start(struct bio *);
71static void g_multipath_done(struct bio *);
72static void g_multipath_done_error(struct bio *);
73static void g_multipath_kt(void *);
74
75static int g_multipath_destroy(struct g_geom *);
76static int
77g_multipath_destroy_geom(struct gctl_req *, struct g_class *, struct g_geom *);
78
79static struct g_geom *g_multipath_find_geom(struct g_class *, const char *);
80static int g_multipath_rotate(struct g_geom *);
81
82static g_taste_t g_multipath_taste;
83static g_ctl_req_t g_multipath_config;
84static g_init_t g_multipath_init;
85static g_fini_t g_multipath_fini;
86static g_dumpconf_t g_multipath_dumpconf;
87
88struct g_class g_multipath_class = {
89	.name		= G_MULTIPATH_CLASS_NAME,
90	.version	= G_VERSION,
91	.ctlreq		= g_multipath_config,
92	.taste		= g_multipath_taste,
93	.destroy_geom	= g_multipath_destroy_geom,
94	.init		= g_multipath_init,
95	.fini		= g_multipath_fini
96};
97
98#define	MP_FAIL		0x00000001
99#define	MP_LOST		0x00000002
100#define	MP_NEW		0x00000004
101#define	MP_POSTED	0x00000008
102#define	MP_BAD		(MP_FAIL | MP_LOST | MP_NEW)
103#define MP_IDLE		0x00000010
104#define MP_IDLE_MASK	0xfffffff0
105
106static int
107g_multipath_good(struct g_geom *gp)
108{
109	struct g_consumer *cp;
110	int n = 0;
111
112	LIST_FOREACH(cp, &gp->consumer, consumer) {
113		if ((cp->index & MP_BAD) == 0)
114			n++;
115	}
116	return (n);
117}
118
119static void
120g_multipath_fault(struct g_consumer *cp, int cause)
121{
122	struct g_multipath_softc *sc;
123	struct g_consumer *lcp;
124	struct g_geom *gp;
125
126	gp = cp->geom;
127	sc = gp->softc;
128	cp->index |= cause;
129	if (g_multipath_good(gp) == 0 && sc->sc_ndisks > 0) {
130		LIST_FOREACH(lcp, &gp->consumer, consumer) {
131			if (lcp->provider == NULL ||
132			    (lcp->index & (MP_LOST | MP_NEW)))
133				continue;
134			if (sc->sc_ndisks > 1 && lcp == cp)
135				continue;
136			printf("GEOM_MULTIPATH: "
137			    "all paths in %s were marked FAIL, restore %s\n",
138			    sc->sc_name, lcp->provider->name);
139			lcp->index &= ~MP_FAIL;
140		}
141	}
142	if (cp != sc->sc_active)
143		return;
144	sc->sc_active = NULL;
145	LIST_FOREACH(lcp, &gp->consumer, consumer) {
146		if ((lcp->index & MP_BAD) == 0) {
147			sc->sc_active = lcp;
148			break;
149		}
150	}
151	if (sc->sc_active == NULL) {
152		printf("GEOM_MULTIPATH: out of providers for %s\n",
153		    sc->sc_name);
154	} else if (sc->sc_active_active != 1) {
155		printf("GEOM_MULTIPATH: %s is now active path in %s\n",
156		    sc->sc_active->provider->name, sc->sc_name);
157	}
158}
159
160static struct g_consumer *
161g_multipath_choose(struct g_geom *gp, struct bio *bp)
162{
163	struct g_multipath_softc *sc;
164	struct g_consumer *best, *cp;
165
166	sc = gp->softc;
167	if (sc->sc_active_active == 0 ||
168	    (sc->sc_active_active == 2 && bp->bio_cmd != BIO_READ))
169		return (sc->sc_active);
170	best = NULL;
171	LIST_FOREACH(cp, &gp->consumer, consumer) {
172		if (cp->index & MP_BAD)
173			continue;
174		cp->index += MP_IDLE;
175		if (best == NULL || cp->private < best->private ||
176		    (cp->private == best->private && cp->index > best->index))
177			best = cp;
178	}
179	if (best != NULL)
180		best->index &= ~MP_IDLE_MASK;
181	return (best);
182}
183
184static void
185g_mpd(void *arg, int flags __unused)
186{
187	struct g_geom *gp;
188	struct g_multipath_softc *sc;
189	struct g_consumer *cp;
190	int w;
191
192	g_topology_assert();
193	cp = arg;
194	gp = cp->geom;
195	if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0) {
196		w = cp->acw;
197		g_access(cp, -cp->acr, -cp->acw, -cp->ace);
198		if (w > 0 && cp->provider != NULL &&
199		    (cp->provider->geom->flags & G_GEOM_WITHER) == 0) {
200			g_post_event(g_mpd, cp, M_WAITOK, NULL);
201			return;
202		}
203	}
204	sc = gp->softc;
205	mtx_lock(&sc->sc_mtx);
206	if (cp->provider) {
207		printf("GEOM_MULTIPATH: %s removed from %s\n",
208		    cp->provider->name, gp->name);
209		g_detach(cp);
210	}
211	g_destroy_consumer(cp);
212	mtx_unlock(&sc->sc_mtx);
213	if (LIST_EMPTY(&gp->consumer))
214		g_multipath_destroy(gp);
215}
216
217static void
218g_multipath_orphan(struct g_consumer *cp)
219{
220	struct g_multipath_softc *sc;
221	uintptr_t *cnt;
222
223	g_topology_assert();
224	printf("GEOM_MULTIPATH: %s in %s was disconnected\n",
225	    cp->provider->name, cp->geom->name);
226	sc = cp->geom->softc;
227	cnt = (uintptr_t *)&cp->private;
228	mtx_lock(&sc->sc_mtx);
229	sc->sc_ndisks--;
230	g_multipath_fault(cp, MP_LOST);
231	if (*cnt == 0 && (cp->index & MP_POSTED) == 0) {
232		cp->index |= MP_POSTED;
233		mtx_unlock(&sc->sc_mtx);
234		g_mpd(cp, 0);
235	} else
236		mtx_unlock(&sc->sc_mtx);
237}
238
239static void
240g_multipath_start(struct bio *bp)
241{
242	struct g_multipath_softc *sc;
243	struct g_geom *gp;
244	struct g_consumer *cp;
245	struct bio *cbp;
246	uintptr_t *cnt;
247
248	gp = bp->bio_to->geom;
249	sc = gp->softc;
250	KASSERT(sc != NULL, ("NULL sc"));
251	cbp = g_clone_bio(bp);
252	if (cbp == NULL) {
253		g_io_deliver(bp, ENOMEM);
254		return;
255	}
256	mtx_lock(&sc->sc_mtx);
257	cp = g_multipath_choose(gp, bp);
258	if (cp == NULL) {
259		mtx_unlock(&sc->sc_mtx);
260		g_destroy_bio(cbp);
261		g_io_deliver(bp, ENXIO);
262		return;
263	}
264	if ((uintptr_t)bp->bio_driver1 < sc->sc_ndisks)
265		bp->bio_driver1 = (void *)(uintptr_t)sc->sc_ndisks;
266	cnt = (uintptr_t *)&cp->private;
267	(*cnt)++;
268	mtx_unlock(&sc->sc_mtx);
269	cbp->bio_done = g_multipath_done;
270	g_io_request(cbp, cp);
271}
272
273static void
274g_multipath_done(struct bio *bp)
275{
276	struct g_multipath_softc *sc;
277	struct g_consumer *cp;
278	uintptr_t *cnt;
279
280	if (bp->bio_error == ENXIO || bp->bio_error == EIO) {
281		mtx_lock(&gmtbq_mtx);
282		bioq_insert_tail(&gmtbq, bp);
283		mtx_unlock(&gmtbq_mtx);
284		wakeup(&g_multipath_kt_state);
285	} else {
286		cp = bp->bio_from;
287		sc = cp->geom->softc;
288		cnt = (uintptr_t *)&cp->private;
289		mtx_lock(&sc->sc_mtx);
290		(*cnt)--;
291		if (*cnt == 0 && (cp->index & MP_LOST)) {
292			cp->index |= MP_POSTED;
293			mtx_unlock(&sc->sc_mtx);
294			g_post_event(g_mpd, cp, M_WAITOK, NULL);
295		} else
296			mtx_unlock(&sc->sc_mtx);
297		g_std_done(bp);
298	}
299}
300
301static void
302g_multipath_done_error(struct bio *bp)
303{
304	struct bio *pbp;
305	struct g_geom *gp;
306	struct g_multipath_softc *sc;
307	struct g_consumer *cp;
308	struct g_provider *pp;
309	uintptr_t *cnt;
310
311	/*
312	 * If we had a failure, we have to check first to see
313	 * whether the consumer it failed on was the currently
314	 * active consumer (i.e., this is the first in perhaps
315	 * a number of failures). If so, we then switch consumers
316	 * to the next available consumer.
317	 */
318
319	pbp = bp->bio_parent;
320	gp = pbp->bio_to->geom;
321	sc = gp->softc;
322	cp = bp->bio_from;
323	pp = cp->provider;
324	cnt = (uintptr_t *)&cp->private;
325
326	mtx_lock(&sc->sc_mtx);
327	if ((cp->index & MP_FAIL) == 0) {
328		printf("GEOM_MULTIPATH: Error %d, %s in %s marked FAIL\n",
329		    bp->bio_error, pp->name, sc->sc_name);
330		g_multipath_fault(cp, MP_FAIL);
331	}
332	(*cnt)--;
333	if (*cnt == 0 && (cp->index & (MP_LOST | MP_POSTED)) == MP_LOST) {
334		cp->index |= MP_POSTED;
335		mtx_unlock(&sc->sc_mtx);
336		g_post_event(g_mpd, cp, M_WAITOK, NULL);
337	} else
338		mtx_unlock(&sc->sc_mtx);
339
340	/*
341	 * If we can fruitfully restart the I/O, do so.
342	 */
343	if (pbp->bio_children < (uintptr_t)pbp->bio_driver1) {
344		pbp->bio_inbed++;
345		g_destroy_bio(bp);
346		g_multipath_start(pbp);
347	} else {
348		g_std_done(bp);
349	}
350}
351
352static void
353g_multipath_kt(void *arg)
354{
355
356	g_multipath_kt_state = GKT_RUN;
357	mtx_lock(&gmtbq_mtx);
358	while (g_multipath_kt_state == GKT_RUN) {
359		for (;;) {
360			struct bio *bp;
361
362			bp = bioq_takefirst(&gmtbq);
363			if (bp == NULL)
364				break;
365			mtx_unlock(&gmtbq_mtx);
366			g_multipath_done_error(bp);
367			mtx_lock(&gmtbq_mtx);
368		}
369		if (g_multipath_kt_state != GKT_RUN)
370			break;
371		msleep(&g_multipath_kt_state, &gmtbq_mtx, PRIBIO,
372		    "gkt:wait", 0);
373	}
374	mtx_unlock(&gmtbq_mtx);
375	wakeup(&g_multipath_kt_state);
376	kproc_exit(0);
377}
378
379
380static int
381g_multipath_access(struct g_provider *pp, int dr, int dw, int de)
382{
383	struct g_geom *gp;
384	struct g_consumer *cp, *badcp = NULL;
385	struct g_multipath_softc *sc;
386	int error;
387
388	gp = pp->geom;
389
390	LIST_FOREACH(cp, &gp->consumer, consumer) {
391		error = g_access(cp, dr, dw, de);
392		if (error) {
393			badcp = cp;
394			goto fail;
395		}
396	}
397	sc = gp->softc;
398	sc->sc_opened += dr + dw + de;
399	if (sc->sc_stopping && sc->sc_opened == 0)
400		g_multipath_destroy(gp);
401	return (0);
402
403fail:
404	LIST_FOREACH(cp, &gp->consumer, consumer) {
405		if (cp == badcp)
406			break;
407		(void) g_access(cp, -dr, -dw, -de);
408	}
409	return (error);
410}
411
412static struct g_geom *
413g_multipath_create(struct g_class *mp, struct g_multipath_metadata *md)
414{
415	struct g_multipath_softc *sc;
416	struct g_geom *gp;
417	struct g_provider *pp;
418
419	g_topology_assert();
420
421	LIST_FOREACH(gp, &mp->geom, geom) {
422		sc = gp->softc;
423		if (sc == NULL || sc->sc_stopping)
424			continue;
425		if (strcmp(gp->name, md->md_name) == 0) {
426			printf("GEOM_MULTIPATH: name %s already exists\n",
427			    md->md_name);
428			return (NULL);
429		}
430	}
431
432	gp = g_new_geomf(mp, "%s", md->md_name);
433	sc = g_malloc(sizeof(*sc), M_WAITOK | M_ZERO);
434	mtx_init(&sc->sc_mtx, "multipath", NULL, MTX_DEF);
435	memcpy(sc->sc_uuid, md->md_uuid, sizeof (sc->sc_uuid));
436	memcpy(sc->sc_name, md->md_name, sizeof (sc->sc_name));
437	sc->sc_active_active = md->md_active_active;
438	gp->softc = sc;
439	gp->start = g_multipath_start;
440	gp->orphan = g_multipath_orphan;
441	gp->access = g_multipath_access;
442	gp->dumpconf = g_multipath_dumpconf;
443
444	pp = g_new_providerf(gp, "multipath/%s", md->md_name);
445	pp->flags |= G_PF_DIRECT_SEND | G_PF_DIRECT_RECEIVE;
446	if (md->md_size != 0) {
447		pp->mediasize = md->md_size -
448		    ((md->md_uuid[0] != 0) ? md->md_sectorsize : 0);
449		pp->sectorsize = md->md_sectorsize;
450	}
451	sc->sc_pp = pp;
452	g_error_provider(pp, 0);
453	printf("GEOM_MULTIPATH: %s created\n", gp->name);
454	return (gp);
455}
456
457static int
458g_multipath_add_disk(struct g_geom *gp, struct g_provider *pp)
459{
460	struct g_multipath_softc *sc;
461	struct g_consumer *cp, *nxtcp;
462	int error, acr, acw, ace;
463
464	g_topology_assert();
465
466	sc = gp->softc;
467	KASSERT(sc, ("no softc"));
468
469	/*
470	 * Make sure that the passed provider isn't already attached
471	 */
472	LIST_FOREACH(cp, &gp->consumer, consumer) {
473		if (cp->provider == pp)
474			break;
475	}
476	if (cp) {
477		printf("GEOM_MULTIPATH: provider %s already attached to %s\n",
478		    pp->name, gp->name);
479		return (EEXIST);
480	}
481	nxtcp = LIST_FIRST(&gp->consumer);
482	cp = g_new_consumer(gp);
483	cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE;
484	cp->private = NULL;
485	cp->index = MP_NEW;
486	error = g_attach(cp, pp);
487	if (error != 0) {
488		printf("GEOM_MULTIPATH: cannot attach %s to %s",
489		    pp->name, sc->sc_name);
490		g_destroy_consumer(cp);
491		return (error);
492	}
493
494	/*
495	 * Set access permissions on new consumer to match other consumers
496	 */
497	if (sc->sc_pp) {
498		acr = sc->sc_pp->acr;
499		acw = sc->sc_pp->acw;
500		ace = sc->sc_pp->ace;
501	} else
502		acr = acw = ace = 0;
503	if (g_multipath_exclusive) {
504		acr++;
505		acw++;
506		ace++;
507	}
508	error = g_access(cp, acr, acw, ace);
509	if (error) {
510		printf("GEOM_MULTIPATH: cannot set access in "
511		    "attaching %s to %s (%d)\n",
512		    pp->name, sc->sc_name, error);
513		g_detach(cp);
514		g_destroy_consumer(cp);
515		return (error);
516	}
517	if (sc->sc_pp != NULL && sc->sc_pp->mediasize == 0) {
518		sc->sc_pp->mediasize = pp->mediasize -
519		    ((sc->sc_uuid[0] != 0) ? pp->sectorsize : 0);
520		sc->sc_pp->sectorsize = pp->sectorsize;
521	}
522	if (sc->sc_pp != NULL &&
523	    sc->sc_pp->stripesize == 0 && sc->sc_pp->stripeoffset == 0) {
524		sc->sc_pp->stripesize = pp->stripesize;
525		sc->sc_pp->stripeoffset = pp->stripeoffset;
526	}
527	if (sc->sc_pp != NULL)
528		sc->sc_pp->flags |= pp->flags & G_PF_ACCEPT_UNMAPPED;
529	mtx_lock(&sc->sc_mtx);
530	cp->index = 0;
531	sc->sc_ndisks++;
532	mtx_unlock(&sc->sc_mtx);
533	printf("GEOM_MULTIPATH: %s added to %s\n",
534	    pp->name, sc->sc_name);
535	if (sc->sc_active == NULL) {
536		sc->sc_active = cp;
537		if (sc->sc_active_active != 1)
538			printf("GEOM_MULTIPATH: %s is now active path in %s\n",
539			    pp->name, sc->sc_name);
540	}
541	return (0);
542}
543
544static int
545g_multipath_destroy(struct g_geom *gp)
546{
547	struct g_multipath_softc *sc;
548	struct g_consumer *cp, *cp1;
549
550	g_topology_assert();
551	if (gp->softc == NULL)
552		return (ENXIO);
553	sc = gp->softc;
554	if (!sc->sc_stopping) {
555		printf("GEOM_MULTIPATH: destroying %s\n", gp->name);
556		sc->sc_stopping = 1;
557	}
558	if (sc->sc_opened != 0) {
559		if (sc->sc_pp != NULL) {
560			g_wither_provider(sc->sc_pp, ENXIO);
561			sc->sc_pp = NULL;
562		}
563		return (EINPROGRESS);
564	}
565	LIST_FOREACH_SAFE(cp, &gp->consumer, consumer, cp1) {
566		mtx_lock(&sc->sc_mtx);
567		if ((cp->index & MP_POSTED) == 0) {
568			cp->index |= MP_POSTED;
569			mtx_unlock(&sc->sc_mtx);
570			g_mpd(cp, 0);
571			if (cp1 == NULL)
572				return(0);	/* Recursion happened. */
573		} else
574			mtx_unlock(&sc->sc_mtx);
575	}
576	if (!LIST_EMPTY(&gp->consumer))
577		return (EINPROGRESS);
578	mtx_destroy(&sc->sc_mtx);
579	g_free(gp->softc);
580	gp->softc = NULL;
581	printf("GEOM_MULTIPATH: %s destroyed\n", gp->name);
582	g_wither_geom(gp, ENXIO);
583	return (0);
584}
585
586static int
587g_multipath_destroy_geom(struct gctl_req *req, struct g_class *mp,
588    struct g_geom *gp)
589{
590
591	return (g_multipath_destroy(gp));
592}
593
594static int
595g_multipath_rotate(struct g_geom *gp)
596{
597	struct g_consumer *lcp, *first_good_cp = NULL;
598	struct g_multipath_softc *sc = gp->softc;
599	int active_cp_seen = 0;
600
601	g_topology_assert();
602	if (sc == NULL)
603		return (ENXIO);
604	LIST_FOREACH(lcp, &gp->consumer, consumer) {
605		if ((lcp->index & MP_BAD) == 0) {
606			if (first_good_cp == NULL)
607				first_good_cp = lcp;
608			if (active_cp_seen)
609				break;
610		}
611		if (sc->sc_active == lcp)
612			active_cp_seen = 1;
613	}
614	if (lcp == NULL)
615		lcp = first_good_cp;
616	if (lcp && lcp != sc->sc_active) {
617		sc->sc_active = lcp;
618		if (sc->sc_active_active != 1)
619			printf("GEOM_MULTIPATH: %s is now active path in %s\n",
620			    lcp->provider->name, sc->sc_name);
621	}
622	return (0);
623}
624
625static void
626g_multipath_init(struct g_class *mp)
627{
628	bioq_init(&gmtbq);
629	mtx_init(&gmtbq_mtx, "gmtbq", NULL, MTX_DEF);
630	kproc_create(g_multipath_kt, mp, NULL, 0, 0, "g_mp_kt");
631}
632
633static void
634g_multipath_fini(struct g_class *mp)
635{
636	if (g_multipath_kt_state == GKT_RUN) {
637		mtx_lock(&gmtbq_mtx);
638		g_multipath_kt_state = GKT_DIE;
639		wakeup(&g_multipath_kt_state);
640		msleep(&g_multipath_kt_state, &gmtbq_mtx, PRIBIO,
641		    "gmp:fini", 0);
642		mtx_unlock(&gmtbq_mtx);
643	}
644}
645
646static int
647g_multipath_read_metadata(struct g_consumer *cp,
648    struct g_multipath_metadata *md)
649{
650	struct g_provider *pp;
651	u_char *buf;
652	int error;
653
654	g_topology_assert();
655	error = g_access(cp, 1, 0, 0);
656	if (error != 0)
657		return (error);
658	pp = cp->provider;
659	g_topology_unlock();
660	buf = g_read_data(cp, pp->mediasize - pp->sectorsize,
661	    pp->sectorsize, &error);
662	g_topology_lock();
663	g_access(cp, -1, 0, 0);
664	if (buf == NULL)
665		return (error);
666	multipath_metadata_decode(buf, md);
667	g_free(buf);
668	return (0);
669}
670
671static struct g_geom *
672g_multipath_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
673{
674	struct g_multipath_metadata md;
675	struct g_multipath_softc *sc;
676	struct g_consumer *cp;
677	struct g_geom *gp, *gp1;
678	int error, isnew;
679
680	g_topology_assert();
681
682	gp = g_new_geomf(mp, "multipath:taste");
683	gp->start = g_multipath_start;
684	gp->access = g_multipath_access;
685	gp->orphan = g_multipath_orphan;
686	cp = g_new_consumer(gp);
687	g_attach(cp, pp);
688	error = g_multipath_read_metadata(cp, &md);
689	g_detach(cp);
690	g_destroy_consumer(cp);
691	g_destroy_geom(gp);
692	if (error != 0)
693		return (NULL);
694	gp = NULL;
695
696	if (strcmp(md.md_magic, G_MULTIPATH_MAGIC) != 0) {
697		if (g_multipath_debug)
698			printf("%s is not MULTIPATH\n", pp->name);
699		return (NULL);
700	}
701	if (md.md_version != G_MULTIPATH_VERSION) {
702		printf("%s has version %d multipath id- this module is version "
703		    " %d: rejecting\n", pp->name, md.md_version,
704		    G_MULTIPATH_VERSION);
705		return (NULL);
706	}
707	if (md.md_size != 0 && md.md_size != pp->mediasize)
708		return (NULL);
709	if (md.md_sectorsize != 0 && md.md_sectorsize != pp->sectorsize)
710		return (NULL);
711	if (g_multipath_debug)
712		printf("MULTIPATH: %s/%s\n", md.md_name, md.md_uuid);
713
714	/*
715	 * Let's check if such a device already is present. We check against
716	 * uuid alone first because that's the true distinguishor. If that
717	 * passes, then we check for name conflicts. If there are conflicts,
718	 * modify the name.
719	 *
720	 * The whole purpose of this is to solve the problem that people don't
721	 * pick good unique names, but good unique names (like uuids) are a
722	 * pain to use. So, we allow people to build GEOMs with friendly names
723	 * and uuids, and modify the names in case there's a collision.
724	 */
725	sc = NULL;
726	LIST_FOREACH(gp, &mp->geom, geom) {
727		sc = gp->softc;
728		if (sc == NULL || sc->sc_stopping)
729			continue;
730		if (strncmp(md.md_uuid, sc->sc_uuid, sizeof(md.md_uuid)) == 0)
731			break;
732	}
733
734	LIST_FOREACH(gp1, &mp->geom, geom) {
735		if (gp1 == gp)
736			continue;
737		sc = gp1->softc;
738		if (sc == NULL || sc->sc_stopping)
739			continue;
740		if (strncmp(md.md_name, sc->sc_name, sizeof(md.md_name)) == 0)
741			break;
742	}
743
744	/*
745	 * If gp is NULL, we had no extant MULTIPATH geom with this uuid.
746	 *
747	 * If gp1 is *not* NULL, that means we have a MULTIPATH geom extant
748	 * with the same name (but a different UUID).
749	 *
750	 * If gp is NULL, then modify the name with a random number and
751  	 * complain, but allow the creation of the geom to continue.
752	 *
753	 * If gp is *not* NULL, just use the geom's name as we're attaching
754	 * this disk to the (previously generated) name.
755	 */
756
757	if (gp1) {
758		sc = gp1->softc;
759		if (gp == NULL) {
760			char buf[16];
761			u_long rand = random();
762
763			snprintf(buf, sizeof (buf), "%s-%lu", md.md_name, rand);
764			printf("GEOM_MULTIPATH: geom %s/%s exists already\n",
765			    sc->sc_name, sc->sc_uuid);
766			printf("GEOM_MULTIPATH: %s will be (temporarily) %s\n",
767			    md.md_uuid, buf);
768			strlcpy(md.md_name, buf, sizeof(md.md_name));
769		} else {
770			strlcpy(md.md_name, sc->sc_name, sizeof(md.md_name));
771		}
772	}
773
774	if (gp == NULL) {
775		gp = g_multipath_create(mp, &md);
776		if (gp == NULL) {
777			printf("GEOM_MULTIPATH: cannot create geom %s/%s\n",
778			    md.md_name, md.md_uuid);
779			return (NULL);
780		}
781		isnew = 1;
782	} else {
783		isnew = 0;
784	}
785
786	sc = gp->softc;
787	KASSERT(sc != NULL, ("sc is NULL"));
788	error = g_multipath_add_disk(gp, pp);
789	if (error != 0) {
790		if (isnew)
791			g_multipath_destroy(gp);
792		return (NULL);
793	}
794	return (gp);
795}
796
797static void
798g_multipath_ctl_add_name(struct gctl_req *req, struct g_class *mp,
799    const char *name)
800{
801	struct g_multipath_softc *sc;
802	struct g_geom *gp;
803	struct g_consumer *cp;
804	struct g_provider *pp;
805	const char *mpname;
806	static const char devpf[6] = "/dev/";
807
808	g_topology_assert();
809
810	mpname = gctl_get_asciiparam(req, "arg0");
811        if (mpname == NULL) {
812                gctl_error(req, "No 'arg0' argument");
813                return;
814        }
815	gp = g_multipath_find_geom(mp, mpname);
816	if (gp == NULL) {
817		gctl_error(req, "Device %s is invalid", mpname);
818		return;
819	}
820	sc = gp->softc;
821
822	if (strncmp(name, devpf, 5) == 0)
823		name += 5;
824	pp = g_provider_by_name(name);
825	if (pp == NULL) {
826		gctl_error(req, "Provider %s is invalid", name);
827		return;
828	}
829
830	/*
831	 * Check to make sure parameters match.
832	 */
833	LIST_FOREACH(cp, &gp->consumer, consumer) {
834		if (cp->provider == pp) {
835			gctl_error(req, "provider %s is already there",
836			    pp->name);
837			return;
838		}
839	}
840	if (sc->sc_pp != NULL && sc->sc_pp->mediasize != 0 &&
841	    sc->sc_pp->mediasize + (sc->sc_uuid[0] != 0 ? pp->sectorsize : 0)
842	     != pp->mediasize) {
843		gctl_error(req, "Providers size mismatch %jd != %jd",
844		    (intmax_t) sc->sc_pp->mediasize +
845			(sc->sc_uuid[0] != 0 ? pp->sectorsize : 0),
846		    (intmax_t) pp->mediasize);
847		return;
848	}
849	if (sc->sc_pp != NULL && sc->sc_pp->sectorsize != 0 &&
850	    sc->sc_pp->sectorsize != pp->sectorsize) {
851		gctl_error(req, "Providers sectorsize mismatch %u != %u",
852		    sc->sc_pp->sectorsize, pp->sectorsize);
853		return;
854	}
855
856	/*
857	 * Now add....
858	 */
859	(void) g_multipath_add_disk(gp, pp);
860}
861
862static void
863g_multipath_ctl_prefer(struct gctl_req *req, struct g_class *mp)
864{
865	struct g_geom *gp;
866	struct g_multipath_softc *sc;
867	struct g_consumer *cp;
868	const char *name, *mpname;
869	static const char devpf[6] = "/dev/";
870	int *nargs;
871
872	g_topology_assert();
873
874	mpname = gctl_get_asciiparam(req, "arg0");
875        if (mpname == NULL) {
876                gctl_error(req, "No 'arg0' argument");
877                return;
878        }
879	gp = g_multipath_find_geom(mp, mpname);
880	if (gp == NULL) {
881		gctl_error(req, "Device %s is invalid", mpname);
882		return;
883	}
884	sc = gp->softc;
885
886	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
887	if (nargs == NULL) {
888		gctl_error(req, "No 'nargs' argument");
889		return;
890	}
891	if (*nargs != 2) {
892		gctl_error(req, "missing device");
893		return;
894	}
895
896	name = gctl_get_asciiparam(req, "arg1");
897	if (name == NULL) {
898		gctl_error(req, "No 'arg1' argument");
899		return;
900	}
901	if (strncmp(name, devpf, 5) == 0) {
902		name += 5;
903	}
904
905	LIST_FOREACH(cp, &gp->consumer, consumer) {
906		if (cp->provider != NULL
907                      && strcmp(cp->provider->name, name) == 0)
908		    break;
909	}
910
911	if (cp == NULL) {
912		gctl_error(req, "Provider %s not found", name);
913		return;
914	}
915
916	mtx_lock(&sc->sc_mtx);
917
918	if (cp->index & MP_BAD) {
919		gctl_error(req, "Consumer %s is invalid", name);
920		mtx_unlock(&sc->sc_mtx);
921		return;
922	}
923
924	/* Here when the consumer is present and in good shape */
925
926	sc->sc_active = cp;
927	if (!sc->sc_active_active)
928	    printf("GEOM_MULTIPATH: %s now active path in %s\n",
929		sc->sc_active->provider->name, sc->sc_name);
930
931	mtx_unlock(&sc->sc_mtx);
932}
933
934static void
935g_multipath_ctl_add(struct gctl_req *req, struct g_class *mp)
936{
937	struct g_multipath_softc *sc;
938	struct g_geom *gp;
939	const char *mpname, *name;
940
941	mpname = gctl_get_asciiparam(req, "arg0");
942        if (mpname == NULL) {
943                gctl_error(req, "No 'arg0' argument");
944                return;
945        }
946	gp = g_multipath_find_geom(mp, mpname);
947	if (gp == NULL) {
948		gctl_error(req, "Device %s not found", mpname);
949		return;
950	}
951	sc = gp->softc;
952
953	name = gctl_get_asciiparam(req, "arg1");
954	if (name == NULL) {
955		gctl_error(req, "No 'arg1' argument");
956		return;
957	}
958	g_multipath_ctl_add_name(req, mp, name);
959}
960
961static void
962g_multipath_ctl_create(struct gctl_req *req, struct g_class *mp)
963{
964	struct g_multipath_metadata md;
965	struct g_multipath_softc *sc;
966	struct g_geom *gp;
967	const char *mpname, *name;
968	char param[16];
969	int *nargs, i, *val;
970
971	g_topology_assert();
972
973	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
974	if (*nargs < 2) {
975		gctl_error(req, "wrong number of arguments.");
976		return;
977	}
978
979	mpname = gctl_get_asciiparam(req, "arg0");
980        if (mpname == NULL) {
981                gctl_error(req, "No 'arg0' argument");
982                return;
983        }
984	gp = g_multipath_find_geom(mp, mpname);
985	if (gp != NULL) {
986		gctl_error(req, "Device %s already exist", mpname);
987		return;
988	}
989	sc = gp->softc;
990
991	memset(&md, 0, sizeof(md));
992	strlcpy(md.md_magic, G_MULTIPATH_MAGIC, sizeof(md.md_magic));
993	md.md_version = G_MULTIPATH_VERSION;
994	strlcpy(md.md_name, mpname, sizeof(md.md_name));
995	md.md_size = 0;
996	md.md_sectorsize = 0;
997	md.md_uuid[0] = 0;
998	md.md_active_active = 0;
999	val = gctl_get_paraml(req, "active_active", sizeof(*val));
1000	if (val != NULL && *val != 0)
1001		md.md_active_active = 1;
1002	val = gctl_get_paraml(req, "active_read", sizeof(*val));
1003	if (val != NULL && *val != 0)
1004		md.md_active_active = 2;
1005	gp = g_multipath_create(mp, &md);
1006	if (gp == NULL) {
1007		gctl_error(req, "GEOM_MULTIPATH: cannot create geom %s/%s\n",
1008		    md.md_name, md.md_uuid);
1009		return;
1010	}
1011	sc = gp->softc;
1012
1013	for (i = 1; i < *nargs; i++) {
1014		snprintf(param, sizeof(param), "arg%d", i);
1015		name = gctl_get_asciiparam(req, param);
1016		g_multipath_ctl_add_name(req, mp, name);
1017	}
1018
1019	if (sc->sc_ndisks != (*nargs - 1))
1020		g_multipath_destroy(gp);
1021}
1022
1023static void
1024g_multipath_ctl_configure(struct gctl_req *req, struct g_class *mp)
1025{
1026	struct g_multipath_softc *sc;
1027	struct g_geom *gp;
1028	struct g_consumer *cp;
1029	struct g_provider *pp;
1030	struct g_multipath_metadata md;
1031	const char *name;
1032	int error, *val;
1033	void *buf;
1034
1035	g_topology_assert();
1036
1037	name = gctl_get_asciiparam(req, "arg0");
1038	if (name == NULL) {
1039		gctl_error(req, "No 'arg0' argument");
1040		return;
1041	}
1042	gp = g_multipath_find_geom(mp, name);
1043	if (gp == NULL) {
1044		gctl_error(req, "Device %s is invalid", name);
1045		return;
1046	}
1047	sc = gp->softc;
1048	val = gctl_get_paraml(req, "active_active", sizeof(*val));
1049	if (val != NULL && *val != 0)
1050		sc->sc_active_active = 1;
1051	val = gctl_get_paraml(req, "active_read", sizeof(*val));
1052	if (val != NULL && *val != 0)
1053		sc->sc_active_active = 2;
1054	val = gctl_get_paraml(req, "active_passive", sizeof(*val));
1055	if (val != NULL && *val != 0)
1056		sc->sc_active_active = 0;
1057	if (sc->sc_uuid[0] != 0 && sc->sc_active != NULL) {
1058		cp = sc->sc_active;
1059		pp = cp->provider;
1060		error = g_access(cp, 1, 1, 1);
1061		if (error != 0) {
1062			gctl_error(req, "Can't open %s (%d)", pp->name, error);
1063			return;
1064		}
1065		g_topology_unlock();
1066		buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO);
1067		strlcpy(md.md_magic, G_MULTIPATH_MAGIC, sizeof(md.md_magic));
1068		memcpy(md.md_uuid, sc->sc_uuid, sizeof (sc->sc_uuid));
1069		strlcpy(md.md_name, name, sizeof(md.md_name));
1070		md.md_version = G_MULTIPATH_VERSION;
1071		md.md_size = pp->mediasize;
1072		md.md_sectorsize = pp->sectorsize;
1073		md.md_active_active = sc->sc_active_active;
1074		multipath_metadata_encode(&md, buf);
1075		error = g_write_data(cp, pp->mediasize - pp->sectorsize,
1076		    buf, pp->sectorsize);
1077		g_topology_lock();
1078		g_access(cp, -1, -1, -1);
1079		if (error != 0)
1080			gctl_error(req, "Can't update metadata on %s (%d)",
1081			    pp->name, error);
1082	}
1083}
1084
1085static void
1086g_multipath_ctl_fail(struct gctl_req *req, struct g_class *mp, int fail)
1087{
1088	struct g_multipath_softc *sc;
1089	struct g_geom *gp;
1090	struct g_consumer *cp;
1091	const char *mpname, *name;
1092	int found;
1093
1094	mpname = gctl_get_asciiparam(req, "arg0");
1095        if (mpname == NULL) {
1096                gctl_error(req, "No 'arg0' argument");
1097                return;
1098        }
1099	gp = g_multipath_find_geom(mp, mpname);
1100	if (gp == NULL) {
1101		gctl_error(req, "Device %s not found", mpname);
1102		return;
1103	}
1104	sc = gp->softc;
1105
1106	name = gctl_get_asciiparam(req, "arg1");
1107	if (name == NULL) {
1108		gctl_error(req, "No 'arg1' argument");
1109		return;
1110	}
1111
1112	found = 0;
1113	mtx_lock(&sc->sc_mtx);
1114	LIST_FOREACH(cp, &gp->consumer, consumer) {
1115		if (cp->provider != NULL &&
1116		    strcmp(cp->provider->name, name) == 0 &&
1117		    (cp->index & MP_LOST) == 0) {
1118			found = 1;
1119			if (!fail == !(cp->index & MP_FAIL))
1120				continue;
1121			printf("GEOM_MULTIPATH: %s in %s is marked %s.\n",
1122				name, sc->sc_name, fail ? "FAIL" : "OK");
1123			if (fail) {
1124				g_multipath_fault(cp, MP_FAIL);
1125			} else {
1126				cp->index &= ~MP_FAIL;
1127			}
1128		}
1129	}
1130	mtx_unlock(&sc->sc_mtx);
1131	if (found == 0)
1132		gctl_error(req, "Provider %s not found", name);
1133}
1134
1135static void
1136g_multipath_ctl_remove(struct gctl_req *req, struct g_class *mp)
1137{
1138	struct g_multipath_softc *sc;
1139	struct g_geom *gp;
1140	struct g_consumer *cp, *cp1;
1141	const char *mpname, *name;
1142	uintptr_t *cnt;
1143	int found;
1144
1145	mpname = gctl_get_asciiparam(req, "arg0");
1146        if (mpname == NULL) {
1147                gctl_error(req, "No 'arg0' argument");
1148                return;
1149        }
1150	gp = g_multipath_find_geom(mp, mpname);
1151	if (gp == NULL) {
1152		gctl_error(req, "Device %s not found", mpname);
1153		return;
1154	}
1155	sc = gp->softc;
1156
1157	name = gctl_get_asciiparam(req, "arg1");
1158	if (name == NULL) {
1159		gctl_error(req, "No 'arg1' argument");
1160		return;
1161	}
1162
1163	found = 0;
1164	mtx_lock(&sc->sc_mtx);
1165	LIST_FOREACH_SAFE(cp, &gp->consumer, consumer, cp1) {
1166		if (cp->provider != NULL &&
1167		    strcmp(cp->provider->name, name) == 0 &&
1168		    (cp->index & MP_LOST) == 0) {
1169			found = 1;
1170			printf("GEOM_MULTIPATH: removing %s from %s\n",
1171			    cp->provider->name, cp->geom->name);
1172			sc->sc_ndisks--;
1173			g_multipath_fault(cp, MP_LOST);
1174			cnt = (uintptr_t *)&cp->private;
1175			if (*cnt == 0 && (cp->index & MP_POSTED) == 0) {
1176				cp->index |= MP_POSTED;
1177				mtx_unlock(&sc->sc_mtx);
1178				g_mpd(cp, 0);
1179				if (cp1 == NULL)
1180					return;	/* Recursion happened. */
1181				mtx_lock(&sc->sc_mtx);
1182			}
1183		}
1184	}
1185	mtx_unlock(&sc->sc_mtx);
1186	if (found == 0)
1187		gctl_error(req, "Provider %s not found", name);
1188}
1189
1190static struct g_geom *
1191g_multipath_find_geom(struct g_class *mp, const char *name)
1192{
1193	struct g_geom *gp;
1194	struct g_multipath_softc *sc;
1195
1196	LIST_FOREACH(gp, &mp->geom, geom) {
1197		sc = gp->softc;
1198		if (sc == NULL || sc->sc_stopping)
1199			continue;
1200		if (strcmp(gp->name, name) == 0)
1201			return (gp);
1202	}
1203	return (NULL);
1204}
1205
1206static void
1207g_multipath_ctl_stop(struct gctl_req *req, struct g_class *mp)
1208{
1209	struct g_geom *gp;
1210	const char *name;
1211	int error;
1212
1213	g_topology_assert();
1214
1215	name = gctl_get_asciiparam(req, "arg0");
1216        if (name == NULL) {
1217                gctl_error(req, "No 'arg0' argument");
1218                return;
1219        }
1220	gp = g_multipath_find_geom(mp, name);
1221	if (gp == NULL) {
1222		gctl_error(req, "Device %s is invalid", name);
1223		return;
1224	}
1225	error = g_multipath_destroy(gp);
1226	if (error != 0 && error != EINPROGRESS)
1227		gctl_error(req, "failed to stop %s (err=%d)", name, error);
1228}
1229
1230static void
1231g_multipath_ctl_destroy(struct gctl_req *req, struct g_class *mp)
1232{
1233	struct g_geom *gp;
1234	struct g_multipath_softc *sc;
1235	struct g_consumer *cp;
1236	struct g_provider *pp;
1237	const char *name;
1238	uint8_t *buf;
1239	int error;
1240
1241	g_topology_assert();
1242
1243	name = gctl_get_asciiparam(req, "arg0");
1244        if (name == NULL) {
1245                gctl_error(req, "No 'arg0' argument");
1246                return;
1247        }
1248	gp = g_multipath_find_geom(mp, name);
1249	if (gp == NULL) {
1250		gctl_error(req, "Device %s is invalid", name);
1251		return;
1252	}
1253	sc = gp->softc;
1254
1255	if (sc->sc_uuid[0] != 0 && sc->sc_active != NULL) {
1256		cp = sc->sc_active;
1257		pp = cp->provider;
1258		error = g_access(cp, 1, 1, 1);
1259		if (error != 0) {
1260			gctl_error(req, "Can't open %s (%d)", pp->name, error);
1261			goto destroy;
1262		}
1263		g_topology_unlock();
1264		buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO);
1265		error = g_write_data(cp, pp->mediasize - pp->sectorsize,
1266		    buf, pp->sectorsize);
1267		g_topology_lock();
1268		g_access(cp, -1, -1, -1);
1269		if (error != 0)
1270			gctl_error(req, "Can't erase metadata on %s (%d)",
1271			    pp->name, error);
1272	}
1273
1274destroy:
1275	error = g_multipath_destroy(gp);
1276	if (error != 0 && error != EINPROGRESS)
1277		gctl_error(req, "failed to destroy %s (err=%d)", name, error);
1278}
1279
1280static void
1281g_multipath_ctl_rotate(struct gctl_req *req, struct g_class *mp)
1282{
1283	struct g_geom *gp;
1284	const char *name;
1285	int error;
1286
1287	g_topology_assert();
1288
1289	name = gctl_get_asciiparam(req, "arg0");
1290        if (name == NULL) {
1291                gctl_error(req, "No 'arg0' argument");
1292                return;
1293        }
1294	gp = g_multipath_find_geom(mp, name);
1295	if (gp == NULL) {
1296		gctl_error(req, "Device %s is invalid", name);
1297		return;
1298	}
1299	error = g_multipath_rotate(gp);
1300	if (error != 0) {
1301		gctl_error(req, "failed to rotate %s (err=%d)", name, error);
1302	}
1303}
1304
1305static void
1306g_multipath_ctl_getactive(struct gctl_req *req, struct g_class *mp)
1307{
1308	struct sbuf *sb;
1309	struct g_geom *gp;
1310	struct g_multipath_softc *sc;
1311	struct g_consumer *cp;
1312	const char *name;
1313	int empty;
1314
1315	sb = sbuf_new_auto();
1316
1317	g_topology_assert();
1318	name = gctl_get_asciiparam(req, "arg0");
1319        if (name == NULL) {
1320                gctl_error(req, "No 'arg0' argument");
1321                return;
1322        }
1323	gp = g_multipath_find_geom(mp, name);
1324	if (gp == NULL) {
1325		gctl_error(req, "Device %s is invalid", name);
1326		return;
1327	}
1328	sc = gp->softc;
1329	if (sc->sc_active_active == 1) {
1330		empty = 1;
1331		LIST_FOREACH(cp, &gp->consumer, consumer) {
1332			if (cp->index & MP_BAD)
1333				continue;
1334			if (!empty)
1335				sbuf_cat(sb, " ");
1336			sbuf_cat(sb, cp->provider->name);
1337			empty = 0;
1338		}
1339		if (empty)
1340			sbuf_cat(sb, "none");
1341		sbuf_cat(sb, "\n");
1342	} else if (sc->sc_active && sc->sc_active->provider) {
1343		sbuf_printf(sb, "%s\n", sc->sc_active->provider->name);
1344	} else {
1345		sbuf_printf(sb, "none\n");
1346	}
1347	sbuf_finish(sb);
1348	gctl_set_param_err(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
1349	sbuf_delete(sb);
1350}
1351
1352static void
1353g_multipath_config(struct gctl_req *req, struct g_class *mp, const char *verb)
1354{
1355	uint32_t *version;
1356	g_topology_assert();
1357	version = gctl_get_paraml(req, "version", sizeof(*version));
1358	if (version == NULL) {
1359		gctl_error(req, "No 'version' argument");
1360	} else if (*version != G_MULTIPATH_VERSION) {
1361		gctl_error(req, "Userland and kernel parts are out of sync");
1362	} else if (strcmp(verb, "add") == 0) {
1363		g_multipath_ctl_add(req, mp);
1364	} else if (strcmp(verb, "prefer") == 0) {
1365		g_multipath_ctl_prefer(req, mp);
1366	} else if (strcmp(verb, "create") == 0) {
1367		g_multipath_ctl_create(req, mp);
1368	} else if (strcmp(verb, "configure") == 0) {
1369		g_multipath_ctl_configure(req, mp);
1370	} else if (strcmp(verb, "stop") == 0) {
1371		g_multipath_ctl_stop(req, mp);
1372	} else if (strcmp(verb, "destroy") == 0) {
1373		g_multipath_ctl_destroy(req, mp);
1374	} else if (strcmp(verb, "fail") == 0) {
1375		g_multipath_ctl_fail(req, mp, 1);
1376	} else if (strcmp(verb, "restore") == 0) {
1377		g_multipath_ctl_fail(req, mp, 0);
1378	} else if (strcmp(verb, "remove") == 0) {
1379		g_multipath_ctl_remove(req, mp);
1380	} else if (strcmp(verb, "rotate") == 0) {
1381		g_multipath_ctl_rotate(req, mp);
1382	} else if (strcmp(verb, "getactive") == 0) {
1383		g_multipath_ctl_getactive(req, mp);
1384	} else {
1385		gctl_error(req, "Unknown verb %s", verb);
1386	}
1387}
1388
1389static void
1390g_multipath_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
1391    struct g_consumer *cp, struct g_provider *pp)
1392{
1393	struct g_multipath_softc *sc;
1394	int good;
1395
1396	g_topology_assert();
1397
1398	sc = gp->softc;
1399	if (sc == NULL)
1400		return;
1401	if (cp != NULL) {
1402		sbuf_printf(sb, "%s<State>%s</State>\n", indent,
1403		    (cp->index & MP_NEW) ? "NEW" :
1404		    (cp->index & MP_LOST) ? "LOST" :
1405		    (cp->index & MP_FAIL) ? "FAIL" :
1406		    (sc->sc_active_active == 1 || sc->sc_active == cp) ?
1407		     "ACTIVE" :
1408		     sc->sc_active_active == 2 ? "READ" : "PASSIVE");
1409	} else {
1410		good = g_multipath_good(gp);
1411		sbuf_printf(sb, "%s<State>%s</State>\n", indent,
1412		    good == 0 ? "BROKEN" :
1413		    (good != sc->sc_ndisks || sc->sc_ndisks == 1) ?
1414		    "DEGRADED" : "OPTIMAL");
1415	}
1416	if (cp == NULL && pp == NULL) {
1417		sbuf_printf(sb, "%s<UUID>%s</UUID>\n", indent, sc->sc_uuid);
1418		sbuf_printf(sb, "%s<Mode>Active/%s</Mode>\n", indent,
1419		    sc->sc_active_active == 2 ? "Read" :
1420		    sc->sc_active_active == 1 ? "Active" : "Passive");
1421		sbuf_printf(sb, "%s<Type>%s</Type>\n", indent,
1422		    sc->sc_uuid[0] == 0 ? "MANUAL" : "AUTOMATIC");
1423	}
1424}
1425
1426DECLARE_GEOM_CLASS(g_multipath_class, g_multipath);
1427