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