From owner-p4-projects@FreeBSD.ORG Thu Dec 14 03:44:16 2006 Return-Path: X-Original-To: p4-projects@freebsd.org Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 8D3B816A407; Thu, 14 Dec 2006 03:44:16 +0000 (UTC) X-Original-To: perforce@freebsd.org Delivered-To: perforce@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 48ED316A4CA for ; Thu, 14 Dec 2006 03:44:16 +0000 (UTC) (envelope-from mjacob@freebsd.org) Received: from repoman.freebsd.org (repoman.freebsd.org [69.147.83.41]) by mx1.FreeBSD.org (Postfix) with ESMTP id 5909543CA3 for ; Thu, 14 Dec 2006 03:42:43 +0000 (GMT) (envelope-from mjacob@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.13.6/8.13.6) with ESMTP id kBE3iFXk051301 for ; Thu, 14 Dec 2006 03:44:15 GMT (envelope-from mjacob@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.13.6/8.13.4/Submit) id kBE3iFFD051294 for perforce@freebsd.org; Thu, 14 Dec 2006 03:44:15 GMT (envelope-from mjacob@freebsd.org) Date: Thu, 14 Dec 2006 03:44:15 GMT Message-Id: <200612140344.kBE3iFFD051294@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to mjacob@freebsd.org using -f From: Matt Jacob To: Perforce Change Reviews Cc: Subject: PERFORCE change 111670 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 14 Dec 2006 03:44:16 -0000 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_ */