PERFORCE change 111670 for review

Matt Jacob mjacob at FreeBSD.org
Wed Dec 13 19:44:16 PST 2006


http://perforce.freebsd.org/chv.cgi?CH=111670

Change 111670 by mjacob at mjexp on 2006/12/14 03:44:06

	More toy tinkering- now get it to connect up correctly and,
	with fault injection, DTRT and ping-pong.

Affected files ...

.. //depot/projects/mjexp/sys/geom/multipath/g_multipath.c#3 edit
.. //depot/projects/mjexp/sys/geom/multipath/g_multipath.h#2 edit

Differences ...

==== //depot/projects/mjexp/sys/geom/multipath/g_multipath.c#3 (text+ko) ====

@@ -46,6 +46,10 @@
 SYSCTL_UINT(_kern_geom_multipath, OID_AUTO, debug, CTLFLAG_RW,
     &g_multipath_debug, 0, "Debug level");
 
+static void g_multipath_orphan(struct g_consumer *);
+static void g_multipath_start(struct bio *);
+static void g_multipath_done(struct bio *);
+
 static int g_multipath_destroy(struct g_geom *);
 static int
 g_multipath_destroy_geom(struct gctl_req *, struct g_class *, struct g_geom *);
@@ -72,43 +76,92 @@
 {
 	struct g_multipath_softc *sc;
 	struct g_geom *gp;
-	struct g_provider *pp;
+	struct g_consumer *cp;
 	struct bio *cbp;
 
 	gp = bp->bio_to->geom;
-	sc = gp->softc;
-	switch (bp->bio_cmd) {
-	case BIO_READ:
-		break;
-	case BIO_WRITE:
-		break;
-	}
 	cbp = g_clone_bio(bp);
 	if (cbp == NULL) {
 		g_io_deliver(bp, ENOMEM);
 		return;
 	}
-	cbp->bio_done = g_std_done;
-	cbp->bio_offset = bp->bio_offset;
-	cbp->bio_data = bp->bio_data;
-	cbp->bio_length = bp->bio_length;
-	pp = LIST_FIRST(&gp->provider);
-	KASSERT(pp != NULL, ("NULL pp"));
-	cbp->bio_to = pp;
-	g_io_request(cbp, LIST_FIRST(&gp->consumer));
+	cbp->bio_done = g_multipath_done;
+	sc = gp->softc;
+	KASSERT(sc != NULL, ("NULL sc"));
+	cp = sc->consumers[sc->cur_prov];
+	KASSERT(cp != NULL, ("NULL cp"));
+	g_io_request(cbp, cp);
+}
+
+static void
+g_multipath_done(struct bio *bp)
+{
+	struct bio *pbp = bp->bio_parent;
+	struct g_geom *gp = pbp->bio_to->geom;
+	struct g_multipath_softc *sc = gp->softc;
+	int dofail;
+
+	KASSERT(sc != NULL, ("NULL sc"));
+	if (sc->ready == 0) {
+		g_std_done(bp);
+		return;
+	}
+
+	if (bp->bio_error == ENXIO || bp->bio_error == EIO) {
+		dofail = 1;
+#if	0
+	} else if (bp->bio_error == 0) {
+		static uint8_t inject = 0;
+		if (++inject == 0) {
+			bp->bio_error = ENXIO;
+			dofail = 1;
+		} else {
+			dofail = 0;
+		}
+#endif
+	} else {
+		dofail = 0;
+	}
+		
+	/* XXX yes, this only handles single failures XXX */
+	if (dofail) {
+		if ((pbp->bio_pflags & G_MULTIPATH_BIO_PFLAG_ERROR) == 0) {
+			struct g_provider *pp0, *pp1;
+			pp0 = sc->providers[sc->cur_prov];
+			sc->cur_prov++;
+			pp1 = sc->providers[sc->cur_prov];
+			pbp->bio_pflags |= G_MULTIPATH_BIO_PFLAG_ERROR;
+			printf("error %d: switching from provider %s to"
+			    " provider %s\n", bp->bio_error,
+			    pp0->name, pp1->name);
+			g_destroy_bio(bp);
+			pbp->bio_children--;
+			g_multipath_start(pbp);
+			return;
+		}
+	}
+	g_std_done(bp);
 }
 
+
+
 static int
 g_multipath_access(struct g_provider *pp, int dr, int dw, int de)
 {
 	struct g_geom *gp;
-	struct g_consumer *cp;
+	struct g_multipath_softc *sc;
 	int error;
 
 	gp = pp->geom;
-	cp = LIST_FIRST(&gp->consumer);
-	error = g_access(cp, dr, dw, de);
-
+	sc = gp->softc;
+	KASSERT(sc != NULL, ("NULL sc"));
+	error = g_access(sc->consumers[0], dr, dw, de);
+	if (error == 0) {
+		error = g_access(sc->consumers[1], dr, dw, de);
+		if (error) {
+			(void) g_access(sc->consumers[0], -dr, -dw, -de);
+		}
+	}
 	return (error);
 }
 
@@ -119,8 +172,7 @@
 	struct g_multipath_softc *sc;
 	struct g_geom *gp;
 	struct g_provider *newpp;
-	struct g_consumer *cp0;
-	struct g_consumer *cp1;
+	struct g_consumer *cp0, *cp1;
 	char name[64];
 	int error;
 
@@ -129,9 +181,13 @@
 	/*
 	 * Check to make sure parameters from the two providers are the same
 	 */
+	if (pp0 == pp1) {
+		gctl_error(req, "providers are the same");
+		return (EINVAL);
+	}
     	if (pp0->mediasize != pp1->mediasize) {
-		gctl_error(req, "Provider %s has mediasize %zx; Provider %s "
-		    "has mediasize %zx", pp0->name, (intmax_t) pp0->mediasize,
+		gctl_error(req, "Provider %s has mediasize %zu; Provider %s "
+		    "has mediasize %zu", pp0->name, (intmax_t) pp0->mediasize,
 		    pp1->name, (intmax_t) pp1->mediasize);
 		return (EINVAL);
 	}
@@ -146,7 +202,6 @@
 	newpp = NULL;
 	cp0 = cp1 = NULL;
 
-
 	LIST_FOREACH(gp, &mp->geom, geom) {
 		if (strcmp(gp->name, mpname) == 0) {
 			gctl_error(req, "Provider %s already exists", mpname);
@@ -160,20 +215,17 @@
 	}
 
 	sc = g_malloc(sizeof(*sc), M_WAITOK | M_ZERO);
+	if (sc == NULL) {
+		gctl_error(req, "Cannot allocate softc");
+		error = ENOMEM;
+		goto fail;
+	}
+
 	gp->softc = sc;
 	gp->start = g_multipath_start;
 	gp->orphan = g_multipath_orphan;
 	gp->access = g_multipath_access;
 
-	snprintf(name, sizeof(name), "multipath/%s", mpname);
-	newpp = g_new_providerf(gp, name);
-	if (newpp == NULL) {
-		gctl_error(req, "Cannot create provider %s", name);
-		error = ENOMEM;
-		goto fail;
-	}
-	newpp->mediasize = pp0->mediasize;
-	newpp->sectorsize = pp0->sectorsize;
 
 	cp0 = g_new_consumer(gp);
 	if (cp0 == NULL) {
@@ -186,6 +238,8 @@
 		gctl_error(req, "Cannot attach provider %s", pp0->name);
 		goto fail;
 	}
+	cp0->private = sc;
+	cp0->index = 0;
 
 	cp1 = g_new_consumer(gp);
 	if (cp1 == NULL) {
@@ -198,8 +252,27 @@
 		gctl_error(req, "Cannot attach provider %s", pp1->name);
 		goto fail;
 	}
+	cp1->private = sc;
+	cp1->index = 1;
+
+	sc->consumers[0] = cp0;
+	sc->consumers[1] = cp1;
+	sc->providers[0] = pp0;
+	sc->providers[1] = pp1;
+
+	snprintf(name, sizeof(name), "multipath/%s", mpname);
+	newpp = g_new_providerf(gp, name);
+	if (newpp == NULL) {
+		gctl_error(req, "Cannot create provider %s", name);
+		error = ENOMEM;
+		goto fail;
+	}
+	newpp->mediasize = pp0->mediasize;
+	newpp->sectorsize = pp0->sectorsize;
 	sc->pp = newpp;
 	g_error_provider(newpp, 0);
+	sc->ready = 1;
+
 	return (0);
 fail:
 	if (cp0 != NULL) {

==== //depot/projects/mjexp/sys/geom/multipath/g_multipath.h#2 (text+ko) ====

@@ -33,8 +33,16 @@
 #define	G_MULTIPATH_VERSION		0
 
 #ifdef	_KERNEL
+
+#define G_MULTIPATH_BIO_PFLAG_ERROR	0x1
+
 struct g_multipath_softc {
-	struct g_provider *pp;
+	struct g_provider *	pp;
+	unsigned int				: 30,
+				ready		: 1,
+				cur_prov	: 1;
+	struct g_consumer *	consumers[2];
+	struct g_provider *	providers[2];
 };
 #endif	/* _KERNEL */
 #endif	/* _G_MULTIPATH_H_ */


More information about the p4-projects mailing list