Date: Thu, 14 Dec 2006 03:44:15 GMT From: Matt Jacob <mjacob@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 111670 for review Message-ID: <200612140344.kBE3iFFD051294@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=111670 Change 111670 by mjacob@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_ */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200612140344.kBE3iFFD051294>