g_multipath.c revision 234415
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: head/sys/geom/multipath/g_multipath.c 234415 2012-04-18 09:42:14Z mav $");
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, 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	if (md->md_size != 0) {
446		pp->mediasize = md->md_size -
447		    ((md->md_uuid[0] != 0) ? md->md_sectorsize : 0);
448		pp->sectorsize = md->md_sectorsize;
449	}
450	sc->sc_pp = pp;
451	g_error_provider(pp, 0);
452	printf("GEOM_MULTIPATH: %s created\n", gp->name);
453	return (gp);
454}
455
456static int
457g_multipath_add_disk(struct g_geom *gp, struct g_provider *pp)
458{
459	struct g_multipath_softc *sc;
460	struct g_consumer *cp, *nxtcp;
461	int error, acr, acw, ace;
462
463	g_topology_assert();
464
465	sc = gp->softc;
466	KASSERT(sc, ("no softc"));
467
468	/*
469	 * Make sure that the passed provider isn't already attached
470	 */
471	LIST_FOREACH(cp, &gp->consumer, consumer) {
472		if (cp->provider == pp)
473			break;
474	}
475	if (cp) {
476		printf("GEOM_MULTIPATH: provider %s already attached to %s\n",
477		    pp->name, gp->name);
478		return (EEXIST);
479	}
480	nxtcp = LIST_FIRST(&gp->consumer);
481	cp = g_new_consumer(gp);
482	cp->private = NULL;
483	cp->index = MP_NEW;
484	error = g_attach(cp, pp);
485	if (error != 0) {
486		printf("GEOM_MULTIPATH: cannot attach %s to %s",
487		    pp->name, sc->sc_name);
488		g_destroy_consumer(cp);
489		return (error);
490	}
491
492	/*
493	 * Set access permissions on new consumer to match other consumers
494	 */
495	if (sc->sc_pp) {
496		acr = sc->sc_pp->acr;
497		acw = sc->sc_pp->acw;
498		ace = sc->sc_pp->ace;
499	} else
500		acr = acw = ace = 0;
501	if (g_multipath_exclusive) {
502		acr++;
503		acw++;
504		ace++;
505	}
506	error = g_access(cp, acr, acw, ace);
507	if (error) {
508		printf("GEOM_MULTIPATH: cannot set access in "
509		    "attaching %s to %s (%d)\n",
510		    pp->name, sc->sc_name, error);
511		g_detach(cp);
512		g_destroy_consumer(cp);
513		return (error);
514	}
515	if (sc->sc_pp != NULL && sc->sc_pp->mediasize == 0) {
516		sc->sc_pp->mediasize = pp->mediasize -
517		    ((sc->sc_uuid[0] != 0) ? pp->sectorsize : 0);
518		sc->sc_pp->sectorsize = pp->sectorsize;
519	}
520	if (sc->sc_pp != NULL &&
521	    sc->sc_pp->stripesize == 0 && sc->sc_pp->stripeoffset == 0) {
522		sc->sc_pp->stripesize = pp->stripesize;
523		sc->sc_pp->stripeoffset = pp->stripeoffset;
524	}
525	mtx_lock(&sc->sc_mtx);
526	cp->index = 0;
527	sc->sc_ndisks++;
528	mtx_unlock(&sc->sc_mtx);
529	printf("GEOM_MULTIPATH: %s added to %s\n",
530	    pp->name, sc->sc_name);
531	if (sc->sc_active == NULL) {
532		sc->sc_active = cp;
533		if (sc->sc_active_active != 1)
534			printf("GEOM_MULTIPATH: %s is now active path in %s\n",
535			    pp->name, sc->sc_name);
536	}
537	return (0);
538}
539
540static int
541g_multipath_destroy(struct g_geom *gp)
542{
543	struct g_multipath_softc *sc;
544	struct g_consumer *cp, *cp1;
545
546	g_topology_assert();
547	if (gp->softc == NULL)
548		return (ENXIO);
549	sc = gp->softc;
550	if (!sc->sc_stopping) {
551		printf("GEOM_MULTIPATH: destroying %s\n", gp->name);
552		sc->sc_stopping = 1;
553	}
554	if (sc->sc_opened != 0) {
555		if (sc->sc_pp != NULL) {
556			g_wither_provider(sc->sc_pp, ENXIO);
557			sc->sc_pp = NULL;
558		}
559		return (EINPROGRESS);
560	}
561	LIST_FOREACH_SAFE(cp, &gp->consumer, consumer, cp1) {
562		mtx_lock(&sc->sc_mtx);
563		if ((cp->index & MP_POSTED) == 0) {
564			cp->index |= MP_POSTED;
565			mtx_unlock(&sc->sc_mtx);
566			g_mpd(cp, 0);
567			if (cp1 == NULL)
568				return(0);	/* Recursion happened. */
569		} else
570			mtx_unlock(&sc->sc_mtx);
571	}
572	if (!LIST_EMPTY(&gp->consumer))
573		return (EINPROGRESS);
574	mtx_destroy(&sc->sc_mtx);
575	g_free(gp->softc);
576	gp->softc = NULL;
577	printf("GEOM_MULTIPATH: %s destroyed\n", gp->name);
578	g_wither_geom(gp, ENXIO);
579	return (0);
580}
581
582static int
583g_multipath_destroy_geom(struct gctl_req *req, struct g_class *mp,
584    struct g_geom *gp)
585{
586
587	return (g_multipath_destroy(gp));
588}
589
590static int
591g_multipath_rotate(struct g_geom *gp)
592{
593	struct g_consumer *lcp;
594	struct g_multipath_softc *sc = gp->softc;
595
596	g_topology_assert();
597	if (sc == NULL)
598		return (ENXIO);
599	LIST_FOREACH(lcp, &gp->consumer, consumer) {
600		if ((lcp->index & MP_BAD) == 0) {
601			if (sc->sc_active != lcp)
602				break;
603		}
604	}
605	if (lcp) {
606		sc->sc_active = lcp;
607		if (sc->sc_active_active != 1)
608			printf("GEOM_MULTIPATH: %s is now active path in %s\n",
609			    lcp->provider->name, sc->sc_name);
610	}
611	return (0);
612}
613
614static void
615g_multipath_init(struct g_class *mp)
616{
617	bioq_init(&gmtbq);
618	mtx_init(&gmtbq_mtx, "gmtbq", NULL, MTX_DEF);
619	kproc_create(g_multipath_kt, mp, NULL, 0, 0, "g_mp_kt");
620}
621
622static void
623g_multipath_fini(struct g_class *mp)
624{
625	if (g_multipath_kt_state == GKT_RUN) {
626		mtx_lock(&gmtbq_mtx);
627		g_multipath_kt_state = GKT_DIE;
628		wakeup(&g_multipath_kt_state);
629		msleep(&g_multipath_kt_state, &gmtbq_mtx, PRIBIO,
630		    "gmp:fini", 0);
631		mtx_unlock(&gmtbq_mtx);
632	}
633}
634
635static int
636g_multipath_read_metadata(struct g_consumer *cp,
637    struct g_multipath_metadata *md)
638{
639	struct g_provider *pp;
640	u_char *buf;
641	int error;
642
643	g_topology_assert();
644	error = g_access(cp, 1, 0, 0);
645	if (error != 0)
646		return (error);
647	pp = cp->provider;
648	g_topology_unlock();
649	buf = g_read_data(cp, pp->mediasize - pp->sectorsize,
650	    pp->sectorsize, &error);
651	g_topology_lock();
652	g_access(cp, -1, 0, 0);
653	if (buf == NULL)
654		return (error);
655	multipath_metadata_decode(buf, md);
656	g_free(buf);
657	return (0);
658}
659
660static struct g_geom *
661g_multipath_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
662{
663	struct g_multipath_metadata md;
664	struct g_multipath_softc *sc;
665	struct g_consumer *cp;
666	struct g_geom *gp, *gp1;
667	int error, isnew;
668
669	g_topology_assert();
670
671	gp = g_new_geomf(mp, "multipath:taste");
672	gp->start = g_multipath_start;
673	gp->access = g_multipath_access;
674	gp->orphan = g_multipath_orphan;
675	cp = g_new_consumer(gp);
676	g_attach(cp, pp);
677	error = g_multipath_read_metadata(cp, &md);
678	g_detach(cp);
679	g_destroy_consumer(cp);
680	g_destroy_geom(gp);
681	if (error != 0)
682		return (NULL);
683	gp = NULL;
684
685	if (strcmp(md.md_magic, G_MULTIPATH_MAGIC) != 0) {
686		if (g_multipath_debug)
687			printf("%s is not MULTIPATH\n", pp->name);
688		return (NULL);
689	}
690	if (md.md_version != G_MULTIPATH_VERSION) {
691		printf("%s has version %d multipath id- this module is version "
692		    " %d: rejecting\n", pp->name, md.md_version,
693		    G_MULTIPATH_VERSION);
694		return (NULL);
695	}
696	if (md.md_size != 0 && md.md_size != pp->mediasize)
697		return (NULL);
698	if (md.md_sectorsize != 0 && md.md_sectorsize != pp->sectorsize)
699		return (NULL);
700	if (g_multipath_debug)
701		printf("MULTIPATH: %s/%s\n", md.md_name, md.md_uuid);
702
703	/*
704	 * Let's check if such a device already is present. We check against
705	 * uuid alone first because that's the true distinguishor. If that
706	 * passes, then we check for name conflicts. If there are conflicts,
707	 * modify the name.
708	 *
709	 * The whole purpose of this is to solve the problem that people don't
710	 * pick good unique names, but good unique names (like uuids) are a
711	 * pain to use. So, we allow people to build GEOMs with friendly names
712	 * and uuids, and modify the names in case there's a collision.
713	 */
714	sc = NULL;
715	LIST_FOREACH(gp, &mp->geom, geom) {
716		sc = gp->softc;
717		if (sc == NULL || sc->sc_stopping)
718			continue;
719		if (strncmp(md.md_uuid, sc->sc_uuid, sizeof(md.md_uuid)) == 0)
720			break;
721	}
722
723	LIST_FOREACH(gp1, &mp->geom, geom) {
724		if (gp1 == gp)
725			continue;
726		sc = gp1->softc;
727		if (sc == NULL || sc->sc_stopping)
728			continue;
729		if (strncmp(md.md_name, sc->sc_name, sizeof(md.md_name)) == 0)
730			break;
731	}
732
733	/*
734	 * If gp is NULL, we had no extant MULTIPATH geom with this uuid.
735	 *
736	 * If gp1 is *not* NULL, that means we have a MULTIPATH geom extant
737	 * with the same name (but a different UUID).
738	 *
739	 * If gp is NULL, then modify the name with a random number and
740  	 * complain, but allow the creation of the geom to continue.
741	 *
742	 * If gp is *not* NULL, just use the geom's name as we're attaching
743	 * this disk to the (previously generated) name.
744	 */
745
746	if (gp1) {
747		sc = gp1->softc;
748		if (gp == NULL) {
749			char buf[16];
750			u_long rand = random();
751
752			snprintf(buf, sizeof (buf), "%s-%lu", md.md_name, rand);
753			printf("GEOM_MULTIPATH: geom %s/%s exists already\n",
754			    sc->sc_name, sc->sc_uuid);
755			printf("GEOM_MULTIPATH: %s will be (temporarily) %s\n",
756			    md.md_uuid, buf);
757			strlcpy(md.md_name, buf, sizeof(md.md_name));
758		} else {
759			strlcpy(md.md_name, sc->sc_name, sizeof(md.md_name));
760		}
761	}
762
763	if (gp == NULL) {
764		gp = g_multipath_create(mp, &md);
765		if (gp == NULL) {
766			printf("GEOM_MULTIPATH: cannot create geom %s/%s\n",
767			    md.md_name, md.md_uuid);
768			return (NULL);
769		}
770		isnew = 1;
771	} else {
772		isnew = 0;
773	}
774
775	sc = gp->softc;
776	KASSERT(sc != NULL, ("sc is NULL"));
777	error = g_multipath_add_disk(gp, pp);
778	if (error != 0) {
779		if (isnew)
780			g_multipath_destroy(gp);
781		return (NULL);
782	}
783	return (gp);
784}
785
786static void
787g_multipath_ctl_add_name(struct gctl_req *req, struct g_class *mp,
788    const char *name)
789{
790	struct g_multipath_softc *sc;
791	struct g_geom *gp;
792	struct g_consumer *cp;
793	struct g_provider *pp;
794	const char *mpname;
795	static const char devpf[6] = "/dev/";
796
797	g_topology_assert();
798
799	mpname = gctl_get_asciiparam(req, "arg0");
800        if (mpname == NULL) {
801                gctl_error(req, "No 'arg0' argument");
802                return;
803        }
804	gp = g_multipath_find_geom(mp, mpname);
805	if (gp == NULL) {
806		gctl_error(req, "Device %s is invalid", mpname);
807		return;
808	}
809	sc = gp->softc;
810
811	if (strncmp(name, devpf, 5) == 0)
812		name += 5;
813	pp = g_provider_by_name(name);
814	if (pp == NULL) {
815		gctl_error(req, "Provider %s is invalid", name);
816		return;
817	}
818
819	/*
820	 * Check to make sure parameters match.
821	 */
822	LIST_FOREACH(cp, &gp->consumer, consumer) {
823		if (cp->provider == pp) {
824			gctl_error(req, "provider %s is already there",
825			    pp->name);
826			return;
827		}
828	}
829	if (sc->sc_pp != NULL && sc->sc_pp->mediasize != 0 &&
830	    sc->sc_pp->mediasize + (sc->sc_uuid[0] != 0 ? pp->sectorsize : 0)
831	     != pp->mediasize) {
832		gctl_error(req, "Providers size mismatch %jd != %jd",
833		    (intmax_t) sc->sc_pp->mediasize +
834			(sc->sc_uuid[0] != 0 ? pp->sectorsize : 0),
835		    (intmax_t) pp->mediasize);
836		return;
837	}
838	if (sc->sc_pp != NULL && sc->sc_pp->sectorsize != 0 &&
839	    sc->sc_pp->sectorsize != pp->sectorsize) {
840		gctl_error(req, "Providers sectorsize mismatch %u != %u",
841		    sc->sc_pp->sectorsize, pp->sectorsize);
842		return;
843	}
844
845	/*
846	 * Now add....
847	 */
848	(void) g_multipath_add_disk(gp, pp);
849}
850
851static void
852g_multipath_ctl_add(struct gctl_req *req, struct g_class *mp)
853{
854	struct g_multipath_softc *sc;
855	struct g_geom *gp;
856	const char *mpname, *name;
857
858	mpname = gctl_get_asciiparam(req, "arg0");
859        if (mpname == NULL) {
860                gctl_error(req, "No 'arg0' argument");
861                return;
862        }
863	gp = g_multipath_find_geom(mp, mpname);
864	if (gp == NULL) {
865		gctl_error(req, "Device %s not found", mpname);
866		return;
867	}
868	sc = gp->softc;
869
870	name = gctl_get_asciiparam(req, "arg1");
871	if (name == NULL) {
872		gctl_error(req, "No 'arg1' argument");
873		return;
874	}
875	g_multipath_ctl_add_name(req, mp, name);
876}
877
878static void
879g_multipath_ctl_create(struct gctl_req *req, struct g_class *mp)
880{
881	struct g_multipath_metadata md;
882	struct g_multipath_softc *sc;
883	struct g_geom *gp;
884	const char *mpname, *name;
885	char param[16];
886	int *nargs, i, *val;
887
888	g_topology_assert();
889
890	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
891	if (*nargs < 2) {
892		gctl_error(req, "wrong number of arguments.");
893		return;
894	}
895
896	mpname = gctl_get_asciiparam(req, "arg0");
897        if (mpname == NULL) {
898                gctl_error(req, "No 'arg0' argument");
899                return;
900        }
901	gp = g_multipath_find_geom(mp, mpname);
902	if (gp != NULL) {
903		gctl_error(req, "Device %s already exist", mpname);
904		return;
905	}
906	sc = gp->softc;
907
908	memset(&md, 0, sizeof(md));
909	strlcpy(md.md_magic, G_MULTIPATH_MAGIC, sizeof(md.md_magic));
910	md.md_version = G_MULTIPATH_VERSION;
911	strlcpy(md.md_name, mpname, sizeof(md.md_name));
912	md.md_size = 0;
913	md.md_sectorsize = 0;
914	md.md_uuid[0] = 0;
915	md.md_active_active = 0;
916	val = gctl_get_paraml(req, "active_active", sizeof(*val));
917	if (val != NULL && *val != 0)
918		md.md_active_active = 1;
919	val = gctl_get_paraml(req, "active_read", sizeof(*val));
920	if (val != NULL && *val != 0)
921		md.md_active_active = 2;
922	gp = g_multipath_create(mp, &md);
923	if (gp == NULL) {
924		gctl_error(req, "GEOM_MULTIPATH: cannot create geom %s/%s\n",
925		    md.md_name, md.md_uuid);
926		return;
927	}
928	sc = gp->softc;
929
930	for (i = 1; i < *nargs; i++) {
931		snprintf(param, sizeof(param), "arg%d", i);
932		name = gctl_get_asciiparam(req, param);
933		g_multipath_ctl_add_name(req, mp, name);
934	}
935
936	if (sc->sc_ndisks != (*nargs - 1))
937		g_multipath_destroy(gp);
938}
939
940static void
941g_multipath_ctl_configure(struct gctl_req *req, struct g_class *mp)
942{
943	struct g_multipath_softc *sc;
944	struct g_geom *gp;
945	struct g_consumer *cp;
946	struct g_provider *pp;
947	struct g_multipath_metadata *md;
948	const char *name;
949	int error, *val;
950	void *buf;
951
952	g_topology_assert();
953
954	name = gctl_get_asciiparam(req, "arg0");
955	if (name == NULL) {
956		gctl_error(req, "No 'arg0' argument");
957		return;
958	}
959	gp = g_multipath_find_geom(mp, name);
960	if (gp == NULL) {
961		gctl_error(req, "Device %s is invalid", name);
962		return;
963	}
964	sc = gp->softc;
965	val = gctl_get_paraml(req, "active_active", sizeof(*val));
966	if (val != NULL && *val != 0)
967		sc->sc_active_active = 1;
968	val = gctl_get_paraml(req, "active_read", sizeof(*val));
969	if (val != NULL && *val != 0)
970		sc->sc_active_active = 2;
971	val = gctl_get_paraml(req, "active_passive", sizeof(*val));
972	if (val != NULL && *val != 0)
973		sc->sc_active_active = 0;
974	if (sc->sc_uuid[0] != 0 && sc->sc_active != NULL) {
975		cp = sc->sc_active;
976		pp = cp->provider;
977		error = g_access(cp, 1, 1, 1);
978		if (error != 0) {
979			gctl_error(req, "Can't open %s (%d)", pp->name, error);
980			return;
981		}
982		g_topology_unlock();
983		md = buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO);
984		strlcpy(md->md_magic, G_MULTIPATH_MAGIC, sizeof(md->md_magic));
985		memcpy(md->md_uuid, sc->sc_uuid, sizeof (sc->sc_uuid));
986		strlcpy(md->md_name, name, sizeof(md->md_name));
987		md->md_version = G_MULTIPATH_VERSION;
988		md->md_size = pp->mediasize;
989		md->md_sectorsize = pp->sectorsize;
990		md->md_active_active = sc->sc_active_active;
991		error = g_write_data(cp, pp->mediasize - pp->sectorsize,
992		    buf, pp->sectorsize);
993		g_topology_lock();
994		g_access(cp, -1, -1, -1);
995		if (error != 0)
996			gctl_error(req, "Can't update metadata on %s (%d)",
997			    pp->name, error);
998	}
999}
1000
1001static void
1002g_multipath_ctl_fail(struct gctl_req *req, struct g_class *mp, int fail)
1003{
1004	struct g_multipath_softc *sc;
1005	struct g_geom *gp;
1006	struct g_consumer *cp;
1007	const char *mpname, *name;
1008	int found;
1009
1010	mpname = gctl_get_asciiparam(req, "arg0");
1011        if (mpname == NULL) {
1012                gctl_error(req, "No 'arg0' argument");
1013                return;
1014        }
1015	gp = g_multipath_find_geom(mp, mpname);
1016	if (gp == NULL) {
1017		gctl_error(req, "Device %s not found", mpname);
1018		return;
1019	}
1020	sc = gp->softc;
1021
1022	name = gctl_get_asciiparam(req, "arg1");
1023	if (name == NULL) {
1024		gctl_error(req, "No 'arg1' argument");
1025		return;
1026	}
1027
1028	found = 0;
1029	mtx_lock(&sc->sc_mtx);
1030	LIST_FOREACH(cp, &gp->consumer, consumer) {
1031		if (cp->provider != NULL &&
1032		    strcmp(cp->provider->name, name) == 0 &&
1033		    (cp->index & MP_LOST) == 0) {
1034			found = 1;
1035			if (!fail == !(cp->index & MP_FAIL))
1036				continue;
1037			printf("GEOM_MULTIPATH: %s in %s is marked %s.\n",
1038				name, sc->sc_name, fail ? "FAIL" : "OK");
1039			if (fail) {
1040				g_multipath_fault(cp, MP_FAIL);
1041			} else {
1042				cp->index &= ~MP_FAIL;
1043			}
1044		}
1045	}
1046	mtx_unlock(&sc->sc_mtx);
1047	if (found == 0)
1048		gctl_error(req, "Provider %s not found", name);
1049}
1050
1051static void
1052g_multipath_ctl_remove(struct gctl_req *req, struct g_class *mp)
1053{
1054	struct g_multipath_softc *sc;
1055	struct g_geom *gp;
1056	struct g_consumer *cp, *cp1;
1057	const char *mpname, *name;
1058	uintptr_t *cnt;
1059	int found;
1060
1061	mpname = gctl_get_asciiparam(req, "arg0");
1062        if (mpname == NULL) {
1063                gctl_error(req, "No 'arg0' argument");
1064                return;
1065        }
1066	gp = g_multipath_find_geom(mp, mpname);
1067	if (gp == NULL) {
1068		gctl_error(req, "Device %s not found", mpname);
1069		return;
1070	}
1071	sc = gp->softc;
1072
1073	name = gctl_get_asciiparam(req, "arg1");
1074	if (name == NULL) {
1075		gctl_error(req, "No 'arg1' argument");
1076		return;
1077	}
1078
1079	found = 0;
1080	mtx_lock(&sc->sc_mtx);
1081	LIST_FOREACH_SAFE(cp, &gp->consumer, consumer, cp1) {
1082		if (cp->provider != NULL &&
1083		    strcmp(cp->provider->name, name) == 0 &&
1084		    (cp->index & MP_LOST) == 0) {
1085			found = 1;
1086			printf("GEOM_MULTIPATH: removing %s from %s\n",
1087			    cp->provider->name, cp->geom->name);
1088			sc->sc_ndisks--;
1089			g_multipath_fault(cp, MP_LOST);
1090			cnt = (uintptr_t *)&cp->private;
1091			if (*cnt == 0 && (cp->index & MP_POSTED) == 0) {
1092				cp->index |= MP_POSTED;
1093				mtx_unlock(&sc->sc_mtx);
1094				g_mpd(cp, 0);
1095				if (cp1 == NULL)
1096					return;	/* Recursion happened. */
1097				mtx_lock(&sc->sc_mtx);
1098			}
1099		}
1100	}
1101	mtx_unlock(&sc->sc_mtx);
1102	if (found == 0)
1103		gctl_error(req, "Provider %s not found", name);
1104}
1105
1106static struct g_geom *
1107g_multipath_find_geom(struct g_class *mp, const char *name)
1108{
1109	struct g_geom *gp;
1110	struct g_multipath_softc *sc;
1111
1112	LIST_FOREACH(gp, &mp->geom, geom) {
1113		sc = gp->softc;
1114		if (sc == NULL || sc->sc_stopping)
1115			continue;
1116		if (strcmp(gp->name, name) == 0)
1117			return (gp);
1118	}
1119	return (NULL);
1120}
1121
1122static void
1123g_multipath_ctl_stop(struct gctl_req *req, struct g_class *mp)
1124{
1125	struct g_geom *gp;
1126	const char *name;
1127	int error;
1128
1129	g_topology_assert();
1130
1131	name = gctl_get_asciiparam(req, "arg0");
1132        if (name == NULL) {
1133                gctl_error(req, "No 'arg0' argument");
1134                return;
1135        }
1136	gp = g_multipath_find_geom(mp, name);
1137	if (gp == NULL) {
1138		gctl_error(req, "Device %s is invalid", name);
1139		return;
1140	}
1141	error = g_multipath_destroy(gp);
1142	if (error != 0 && error != EINPROGRESS)
1143		gctl_error(req, "failed to stop %s (err=%d)", name, error);
1144}
1145
1146static void
1147g_multipath_ctl_destroy(struct gctl_req *req, struct g_class *mp)
1148{
1149	struct g_geom *gp;
1150	struct g_multipath_softc *sc;
1151	struct g_consumer *cp;
1152	struct g_provider *pp;
1153	const char *name;
1154	uint8_t *buf;
1155	int error;
1156
1157	g_topology_assert();
1158
1159	name = gctl_get_asciiparam(req, "arg0");
1160        if (name == NULL) {
1161                gctl_error(req, "No 'arg0' argument");
1162                return;
1163        }
1164	gp = g_multipath_find_geom(mp, name);
1165	if (gp == NULL) {
1166		gctl_error(req, "Device %s is invalid", name);
1167		return;
1168	}
1169	sc = gp->softc;
1170
1171	if (sc->sc_uuid[0] != 0 && sc->sc_active != NULL) {
1172		cp = sc->sc_active;
1173		pp = cp->provider;
1174		error = g_access(cp, 1, 1, 1);
1175		if (error != 0) {
1176			gctl_error(req, "Can't open %s (%d)", pp->name, error);
1177			goto destroy;
1178		}
1179		g_topology_unlock();
1180		buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO);
1181		error = g_write_data(cp, pp->mediasize - pp->sectorsize,
1182		    buf, pp->sectorsize);
1183		g_topology_lock();
1184		g_access(cp, -1, -1, -1);
1185		if (error != 0)
1186			gctl_error(req, "Can't erase metadata on %s (%d)",
1187			    pp->name, error);
1188	}
1189
1190destroy:
1191	error = g_multipath_destroy(gp);
1192	if (error != 0 && error != EINPROGRESS)
1193		gctl_error(req, "failed to destroy %s (err=%d)", name, error);
1194}
1195
1196static void
1197g_multipath_ctl_rotate(struct gctl_req *req, struct g_class *mp)
1198{
1199	struct g_geom *gp;
1200	const char *name;
1201	int error;
1202
1203	g_topology_assert();
1204
1205	name = gctl_get_asciiparam(req, "arg0");
1206        if (name == NULL) {
1207                gctl_error(req, "No 'arg0' argument");
1208                return;
1209        }
1210	gp = g_multipath_find_geom(mp, name);
1211	if (gp == NULL) {
1212		gctl_error(req, "Device %s is invalid", name);
1213		return;
1214	}
1215	error = g_multipath_rotate(gp);
1216	if (error != 0) {
1217		gctl_error(req, "failed to rotate %s (err=%d)", name, error);
1218	}
1219}
1220
1221static void
1222g_multipath_ctl_getactive(struct gctl_req *req, struct g_class *mp)
1223{
1224	struct sbuf *sb;
1225	struct g_geom *gp;
1226	struct g_multipath_softc *sc;
1227	struct g_consumer *cp;
1228	const char *name;
1229	int empty;
1230
1231	sb = sbuf_new_auto();
1232
1233	g_topology_assert();
1234	name = gctl_get_asciiparam(req, "arg0");
1235        if (name == NULL) {
1236                gctl_error(req, "No 'arg0' argument");
1237                return;
1238        }
1239	gp = g_multipath_find_geom(mp, name);
1240	if (gp == NULL) {
1241		gctl_error(req, "Device %s is invalid", name);
1242		return;
1243	}
1244	sc = gp->softc;
1245	if (sc->sc_active_active == 1) {
1246		empty = 1;
1247		LIST_FOREACH(cp, &gp->consumer, consumer) {
1248			if (cp->index & MP_BAD)
1249				continue;
1250			if (!empty)
1251				sbuf_cat(sb, " ");
1252			sbuf_cat(sb, cp->provider->name);
1253			empty = 0;
1254		}
1255		if (empty)
1256			sbuf_cat(sb, "none");
1257		sbuf_cat(sb, "\n");
1258	} else if (sc->sc_active && sc->sc_active->provider) {
1259		sbuf_printf(sb, "%s\n", sc->sc_active->provider->name);
1260	} else {
1261		sbuf_printf(sb, "none\n");
1262	}
1263	sbuf_finish(sb);
1264	gctl_set_param_err(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
1265	sbuf_delete(sb);
1266}
1267
1268static void
1269g_multipath_config(struct gctl_req *req, struct g_class *mp, const char *verb)
1270{
1271	uint32_t *version;
1272	g_topology_assert();
1273	version = gctl_get_paraml(req, "version", sizeof(*version));
1274	if (version == NULL) {
1275		gctl_error(req, "No 'version' argument");
1276	} else if (*version != G_MULTIPATH_VERSION) {
1277		gctl_error(req, "Userland and kernel parts are out of sync");
1278	} else if (strcmp(verb, "add") == 0) {
1279		g_multipath_ctl_add(req, mp);
1280	} else if (strcmp(verb, "create") == 0) {
1281		g_multipath_ctl_create(req, mp);
1282	} else if (strcmp(verb, "configure") == 0) {
1283		g_multipath_ctl_configure(req, mp);
1284	} else if (strcmp(verb, "stop") == 0) {
1285		g_multipath_ctl_stop(req, mp);
1286	} else if (strcmp(verb, "destroy") == 0) {
1287		g_multipath_ctl_destroy(req, mp);
1288	} else if (strcmp(verb, "fail") == 0) {
1289		g_multipath_ctl_fail(req, mp, 1);
1290	} else if (strcmp(verb, "restore") == 0) {
1291		g_multipath_ctl_fail(req, mp, 0);
1292	} else if (strcmp(verb, "remove") == 0) {
1293		g_multipath_ctl_remove(req, mp);
1294	} else if (strcmp(verb, "rotate") == 0) {
1295		g_multipath_ctl_rotate(req, mp);
1296	} else if (strcmp(verb, "getactive") == 0) {
1297		g_multipath_ctl_getactive(req, mp);
1298	} else {
1299		gctl_error(req, "Unknown verb %s", verb);
1300	}
1301}
1302
1303static void
1304g_multipath_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
1305    struct g_consumer *cp, struct g_provider *pp)
1306{
1307	struct g_multipath_softc *sc;
1308	int good;
1309
1310	g_topology_assert();
1311
1312	sc = gp->softc;
1313	if (sc == NULL)
1314		return;
1315	if (cp != NULL) {
1316		sbuf_printf(sb, "%s<State>%s</State>", indent,
1317		    (cp->index & MP_NEW) ? "NEW" :
1318		    (cp->index & MP_LOST) ? "LOST" :
1319		    (cp->index & MP_FAIL) ? "FAIL" :
1320		    (sc->sc_active_active == 1 || sc->sc_active == cp) ?
1321		     "ACTIVE" :
1322		     sc->sc_active_active == 2 ? "READ" : "PASSIVE");
1323	} else {
1324		good = g_multipath_good(gp);
1325		sbuf_printf(sb, "%s<State>%s</State>", indent,
1326		    good == 0 ? "BROKEN" :
1327		    (good != sc->sc_ndisks || sc->sc_ndisks == 1) ?
1328		    "DEGRADED" : "OPTIMAL");
1329	}
1330	if (cp == NULL && pp == NULL) {
1331		sbuf_printf(sb, "%s<UUID>%s</UUID>", indent, sc->sc_uuid);
1332		sbuf_printf(sb, "%s<Mode>Active/%s</Mode>", indent,
1333		    sc->sc_active_active == 2 ? "Read" :
1334		    sc->sc_active_active == 1 ? "Active" : "Passive");
1335		sbuf_printf(sb, "%s<Type>%s</Type>", indent,
1336		    sc->sc_uuid[0] == 0 ? "MANUAL" : "AUTOMATIC");
1337	}
1338}
1339
1340DECLARE_GEOM_CLASS(g_multipath_class, g_multipath);
1341