Date: Fri, 5 Apr 2013 10:29:15 +0000 (UTC) From: Alexander Motin <mav@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-9@freebsd.org Subject: svn commit: r249146 - stable/9/sys/geom Message-ID: <201304051029.r35ATFTl039376@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: mav Date: Fri Apr 5 10:29:14 2013 New Revision: 249146 URL: http://svnweb.freebsd.org/changeset/base/249146 Log: MFC r227015: Add mutex and two flags to make orphan() call properly asynchronous: - delay consumer closing and detaching on orphan() until all I/Os complete; - prevent new I/Os submission after orphan() called. Previous implementation could destroy consumers still having active requests and worked only because of global workaround made on GEOM level. Modified: stable/9/sys/geom/geom_vfs.c Directory Properties: stable/9/sys/ (props changed) Modified: stable/9/sys/geom/geom_vfs.c ============================================================================== --- stable/9/sys/geom/geom_vfs.c Fri Apr 5 10:27:05 2013 (r249145) +++ stable/9/sys/geom/geom_vfs.c Fri Apr 5 10:29:14 2013 (r249146) @@ -31,7 +31,9 @@ __FBSDID("$FreeBSD$"); #include <sys/systm.h> #include <sys/bio.h> #include <sys/kernel.h> +#include <sys/lock.h> #include <sys/malloc.h> +#include <sys/mutex.h> #include <sys/vnode.h> #include <sys/mount.h> /* XXX Temporary for VFS_LOCK_GIANT */ @@ -45,6 +47,13 @@ __FBSDID("$FreeBSD$"); */ #include <sys/buf.h> +struct g_vfs_softc { + struct mtx sc_mtx; + struct bufobj *sc_bo; + int sc_active; + int sc_orphaned; +}; + static struct buf_ops __g_vfs_bufops = { .bop_name = "GEOM_VFS", .bop_write = bufwrite, @@ -66,24 +75,32 @@ static struct g_class g_vfs_class = { DECLARE_GEOM_CLASS(g_vfs_class, g_vfs); static void +g_vfs_destroy(void *arg, int flags __unused) +{ + struct g_consumer *cp; + + g_topology_assert(); + cp = arg; + if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0) + g_access(cp, -cp->acr, -cp->acw, -cp->ace); + g_detach(cp); + if (cp->geom->softc == NULL) + g_wither_geom(cp->geom, ENXIO); +} + +static void g_vfs_done(struct bio *bip) { + struct g_consumer *cp; + struct g_vfs_softc *sc; struct buf *bp; - int vfslocked; + int vfslocked, destroy; struct mount *mp; struct vnode *vp; struct cdev *cdevp; - /* - * Provider ('bio_to') could have withered away sometime - * between incrementing the 'nend' in g_io_deliver() and now, - * making 'bio_to' a dangling pointer. We cannot do that - * in g_wither_geom(), as it would require going over - * the 'g_bio_run_up' list, resetting the pointer. - */ - if (bip->bio_from->provider == NULL) - bip->bio_to = NULL; - + cp = bip->bio_from; + sc = cp->geom->softc; /* * Collect statistics on synchronous and asynchronous read * and write counts for disks that have associated filesystems. @@ -134,6 +151,13 @@ g_vfs_done(struct bio *bip) bp->b_ioflags |= BIO_ERROR; bp->b_resid = bp->b_bcount - bip->bio_completed; g_destroy_bio(bip); + + mtx_lock(&sc->sc_mtx); + destroy = ((--sc->sc_active) == 0 && sc->sc_orphaned); + mtx_unlock(&sc->sc_mtx); + if (destroy) + g_post_event(g_vfs_destroy, cp, M_WAITOK, NULL); + vfslocked = VFS_LOCK_GIANT(((struct mount *)NULL)); bufdone(bp); VFS_UNLOCK_GIANT(vfslocked); @@ -142,17 +166,20 @@ g_vfs_done(struct bio *bip) void g_vfs_strategy(struct bufobj *bo, struct buf *bp) { + struct g_vfs_softc *sc; struct g_consumer *cp; struct bio *bip; int vfslocked; cp = bo->bo_private; - /* G_VALID_CONSUMER(cp); We likely lack topology lock */ + sc = cp->geom->softc; /* * If the provider has orphaned us, just return EXIO. */ - if (cp->provider == NULL) { + mtx_lock(&sc->sc_mtx); + if (sc->sc_orphaned) { + mtx_unlock(&sc->sc_mtx); bp->b_error = ENXIO; bp->b_ioflags |= BIO_ERROR; vfslocked = VFS_LOCK_GIANT(((struct mount *)NULL)); @@ -160,6 +187,8 @@ g_vfs_strategy(struct bufobj *bo, struct VFS_UNLOCK_GIANT(vfslocked); return; } + sc->sc_active++; + mtx_unlock(&sc->sc_mtx); bip = g_alloc_bio(); bip->bio_cmd = bp->b_iocmd; @@ -179,14 +208,20 @@ static void g_vfs_orphan(struct g_consumer *cp) { struct g_geom *gp; + struct g_vfs_softc *sc; + int destroy; g_topology_assert(); gp = cp->geom; + sc = gp->softc; g_trace(G_T_TOPOLOGY, "g_vfs_orphan(%p(%s))", cp, gp->name); - if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0) - g_access(cp, -cp->acr, -cp->acw, -cp->ace); - g_detach(cp); + mtx_lock(&sc->sc_mtx); + sc->sc_orphaned = 1; + destroy = (sc->sc_active == 0); + mtx_unlock(&sc->sc_mtx); + if (destroy) + g_vfs_destroy(cp, 0); /* * Do not destroy the geom. Filesystem will do that during unmount. @@ -199,6 +234,7 @@ g_vfs_open(struct vnode *vp, struct g_co struct g_geom *gp; struct g_provider *pp; struct g_consumer *cp; + struct g_vfs_softc *sc; struct bufobj *bo; int vfslocked; int error; @@ -214,6 +250,10 @@ g_vfs_open(struct vnode *vp, struct g_co if (pp == NULL) return (ENOENT); gp = g_new_geomf(&g_vfs_class, "%s.%s", fsname, pp->name); + sc = g_malloc(sizeof(*sc), M_WAITOK | M_ZERO); + mtx_init(&sc->sc_mtx, "g_vfs", NULL, MTX_DEF); + sc->sc_bo = bo; + gp->softc = sc; cp = g_new_consumer(gp); g_attach(cp, pp); error = g_access(cp, 1, wr, wr); @@ -229,7 +269,6 @@ g_vfs_open(struct vnode *vp, struct g_co bo->bo_ops = g_vfs_bufops; bo->bo_private = cp; bo->bo_bsize = pp->sectorsize; - gp->softc = bo; return (error); } @@ -238,13 +277,17 @@ void g_vfs_close(struct g_consumer *cp) { struct g_geom *gp; - struct bufobj *bo; + struct g_vfs_softc *sc; g_topology_assert(); gp = cp->geom; - bo = gp->softc; - bufobj_invalbuf(bo, V_SAVE, 0, 0); - bo->bo_private = cp->private; - g_wither_geom_close(gp, ENXIO); + sc = gp->softc; + bufobj_invalbuf(sc->sc_bo, V_SAVE, 0, 0); + sc->sc_bo->bo_private = cp->private; + gp->softc = NULL; + mtx_destroy(&sc->sc_mtx); + if (!sc->sc_orphaned || cp->provider == NULL) + g_wither_geom_close(gp, ENXIO); + g_free(sc); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201304051029.r35ATFTl039376>