1137034Sphk/*- 2137034Sphk * Copyright (c) 2004 Poul-Henning Kamp 3137034Sphk * All rights reserved. 4137034Sphk * 5137034Sphk * Redistribution and use in source and binary forms, with or without 6137034Sphk * modification, are permitted provided that the following conditions 7137034Sphk * are met: 8137034Sphk * 1. Redistributions of source code must retain the above copyright 9137034Sphk * notice, this list of conditions and the following disclaimer. 10137034Sphk * 2. Redistributions in binary form must reproduce the above copyright 11137034Sphk * notice, this list of conditions and the following disclaimer in the 12137034Sphk * documentation and/or other materials provided with the distribution. 13137034Sphk * 14137034Sphk * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15137034Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16137034Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17137034Sphk * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18137034Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19137034Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20137034Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21137034Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22137034Sphk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23137034Sphk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24137034Sphk * SUCH DAMAGE. 25137034Sphk */ 26137034Sphk 27137034Sphk#include <sys/cdefs.h> 28137034Sphk__FBSDID("$FreeBSD: releng/10.3/sys/geom/geom_vfs.c 260385 2014-01-07 01:32:23Z scottl $"); 29137034Sphk 30137034Sphk#include <sys/param.h> 31137034Sphk#include <sys/systm.h> 32137034Sphk#include <sys/bio.h> 33137034Sphk#include <sys/kernel.h> 34227015Smav#include <sys/lock.h> 35137034Sphk#include <sys/malloc.h> 36227015Smav#include <sys/mutex.h> 37137034Sphk#include <sys/vnode.h> 38241896Skib#include <sys/mount.h> 39137034Sphk 40137034Sphk#include <geom/geom.h> 41137034Sphk#include <geom/geom_vfs.h> 42137034Sphk 43137034Sphk/* 44137034Sphk * subroutines for use by filesystems. 45137034Sphk * 46137034Sphk * XXX: should maybe live somewhere else ? 47137034Sphk */ 48137034Sphk#include <sys/buf.h> 49137034Sphk 50227015Smavstruct g_vfs_softc { 51227015Smav struct mtx sc_mtx; 52227015Smav struct bufobj *sc_bo; 53227015Smav int sc_active; 54227015Smav int sc_orphaned; 55227015Smav}; 56227015Smav 57137034Sphkstatic struct buf_ops __g_vfs_bufops = { 58137034Sphk .bop_name = "GEOM_VFS", 59137034Sphk .bop_write = bufwrite, 60137034Sphk .bop_strategy = g_vfs_strategy, 61140056Sphk .bop_sync = bufsync, 62166193Skib .bop_bdflush = bufbdflush 63137034Sphk}; 64137034Sphk 65137034Sphkstruct buf_ops *g_vfs_bufops = &__g_vfs_bufops; 66137034Sphk 67141624Sphkstatic g_orphan_t g_vfs_orphan; 68141624Sphk 69137034Sphkstatic struct g_class g_vfs_class = { 70137034Sphk .name = "VFS", 71137034Sphk .version = G_VERSION, 72137034Sphk .orphan = g_vfs_orphan, 73137034Sphk}; 74137034Sphk 75137034SphkDECLARE_GEOM_CLASS(g_vfs_class, g_vfs); 76137034Sphk 77137034Sphkstatic void 78227015Smavg_vfs_destroy(void *arg, int flags __unused) 79227015Smav{ 80227015Smav struct g_consumer *cp; 81227015Smav 82227015Smav g_topology_assert(); 83227015Smav cp = arg; 84227015Smav if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0) 85227015Smav g_access(cp, -cp->acr, -cp->acw, -cp->ace); 86227015Smav g_detach(cp); 87227015Smav if (cp->geom->softc == NULL) 88227015Smav g_wither_geom(cp->geom, ENXIO); 89227015Smav} 90227015Smav 91227015Smavstatic void 92137034Sphkg_vfs_done(struct bio *bip) 93137034Sphk{ 94227015Smav struct g_consumer *cp; 95227015Smav struct g_vfs_softc *sc; 96137034Sphk struct buf *bp; 97241896Skib int destroy; 98233627Smckusick struct mount *mp; 99233627Smckusick struct vnode *vp; 100234026Smckusick struct cdev *cdevp; 101137034Sphk 102233627Smckusick /* 103233627Smckusick * Collect statistics on synchronous and asynchronous read 104233627Smckusick * and write counts for disks that have associated filesystems. 105233627Smckusick */ 106233627Smckusick bp = bip->bio_caller2; 107233627Smckusick vp = bp->b_vp; 108260385Sscottl if (vp != NULL) { 109234026Smckusick /* 110234026Smckusick * If not a disk vnode, use its associated mount point 111234026Smckusick * otherwise use the mountpoint associated with the disk. 112234026Smckusick */ 113234026Smckusick VI_LOCK(vp); 114234026Smckusick if (vp->v_type != VCHR || 115234026Smckusick (cdevp = vp->v_rdev) == NULL || 116234026Smckusick cdevp->si_devsw == NULL || 117234026Smckusick (cdevp->si_devsw->d_flags & D_DISK) == 0) 118234026Smckusick mp = vp->v_mount; 119234026Smckusick else 120234026Smckusick mp = cdevp->si_mountpt; 121260385Sscottl if (mp != NULL) { 122260385Sscottl if (bp->b_iocmd == BIO_READ) { 123260385Sscottl if (LK_HOLDER(bp->b_lock.lk_lock) == LK_KERNPROC) 124260385Sscottl mp->mnt_stat.f_asyncreads++; 125260385Sscottl else 126260385Sscottl mp->mnt_stat.f_syncreads++; 127260385Sscottl } else if (bp->b_iocmd == BIO_WRITE) { 128260385Sscottl if (LK_HOLDER(bp->b_lock.lk_lock) == LK_KERNPROC) 129260385Sscottl mp->mnt_stat.f_asyncwrites++; 130260385Sscottl else 131260385Sscottl mp->mnt_stat.f_syncwrites++; 132260385Sscottl } 133260385Sscottl } 134234026Smckusick VI_UNLOCK(vp); 135234026Smckusick } 136233627Smckusick 137227015Smav cp = bip->bio_from; 138227015Smav sc = cp->geom->softc; 139137034Sphk if (bip->bio_error) { 140137184Sphk printf("g_vfs_done():"); 141137034Sphk g_print_bio(bip); 142137034Sphk printf("error = %d\n", bip->bio_error); 143137034Sphk } 144137034Sphk bp->b_error = bip->bio_error; 145137034Sphk bp->b_ioflags = bip->bio_flags; 146137034Sphk if (bip->bio_error) 147137034Sphk bp->b_ioflags |= BIO_ERROR; 148137034Sphk bp->b_resid = bp->b_bcount - bip->bio_completed; 149137034Sphk g_destroy_bio(bip); 150227015Smav 151227015Smav mtx_lock(&sc->sc_mtx); 152227015Smav destroy = ((--sc->sc_active) == 0 && sc->sc_orphaned); 153227015Smav mtx_unlock(&sc->sc_mtx); 154227015Smav if (destroy) 155227015Smav g_post_event(g_vfs_destroy, cp, M_WAITOK, NULL); 156227015Smav 157137034Sphk bufdone(bp); 158137034Sphk} 159137034Sphk 160137034Sphkvoid 161137034Sphkg_vfs_strategy(struct bufobj *bo, struct buf *bp) 162137034Sphk{ 163227015Smav struct g_vfs_softc *sc; 164137034Sphk struct g_consumer *cp; 165137034Sphk struct bio *bip; 166137034Sphk 167137034Sphk cp = bo->bo_private; 168227015Smav sc = cp->geom->softc; 169137034Sphk 170186188Strasz /* 171218909Sbrucec * If the provider has orphaned us, just return EXIO. 172186188Strasz */ 173227015Smav mtx_lock(&sc->sc_mtx); 174227015Smav if (sc->sc_orphaned) { 175227015Smav mtx_unlock(&sc->sc_mtx); 176186188Strasz bp->b_error = ENXIO; 177186188Strasz bp->b_ioflags |= BIO_ERROR; 178186188Strasz bufdone(bp); 179186188Strasz return; 180186188Strasz } 181227015Smav sc->sc_active++; 182227015Smav mtx_unlock(&sc->sc_mtx); 183186188Strasz 184137034Sphk bip = g_alloc_bio(); 185137034Sphk bip->bio_cmd = bp->b_iocmd; 186137034Sphk bip->bio_offset = bp->b_iooffset; 187137034Sphk bip->bio_length = bp->b_bcount; 188248508Skib bdata2bio(bp, bip); 189248508Skib if ((bp->b_flags & B_BARRIER) != 0) { 190246876Smckusick bip->bio_flags |= BIO_ORDERED; 191246876Smckusick bp->b_flags &= ~B_BARRIER; 192246876Smckusick } 193248508Skib bip->bio_done = g_vfs_done; 194248508Skib bip->bio_caller2 = bp; 195137034Sphk g_io_request(bip, cp); 196137034Sphk} 197137034Sphk 198141624Sphkstatic void 199137034Sphkg_vfs_orphan(struct g_consumer *cp) 200137034Sphk{ 201186188Strasz struct g_geom *gp; 202227015Smav struct g_vfs_softc *sc; 203227015Smav int destroy; 204137034Sphk 205186188Strasz g_topology_assert(); 206186188Strasz 207186188Strasz gp = cp->geom; 208228204Smav g_trace(G_T_TOPOLOGY, "g_vfs_orphan(%p(%s))", cp, gp->name); 209227015Smav sc = gp->softc; 210228204Smav if (sc == NULL) 211228204Smav return; 212227015Smav mtx_lock(&sc->sc_mtx); 213227015Smav sc->sc_orphaned = 1; 214238892Smav destroy = (sc->sc_active == 0); 215227015Smav mtx_unlock(&sc->sc_mtx); 216227015Smav if (destroy) 217227015Smav g_vfs_destroy(cp, 0); 218186188Strasz 219137034Sphk /* 220187053Strasz * Do not destroy the geom. Filesystem will do that during unmount. 221137034Sphk */ 222137034Sphk} 223137034Sphk 224137034Sphkint 225137034Sphkg_vfs_open(struct vnode *vp, struct g_consumer **cpp, const char *fsname, int wr) 226137034Sphk{ 227137034Sphk struct g_geom *gp; 228137034Sphk struct g_provider *pp; 229137034Sphk struct g_consumer *cp; 230227015Smav struct g_vfs_softc *sc; 231137034Sphk struct bufobj *bo; 232137034Sphk int error; 233137034Sphk 234137034Sphk g_topology_assert(); 235137034Sphk 236137034Sphk *cpp = NULL; 237206130Savg bo = &vp->v_bufobj; 238206130Savg if (bo->bo_private != vp) 239206130Savg return (EBUSY); 240206130Savg 241137034Sphk pp = g_dev_getprovider(vp->v_rdev); 242137034Sphk if (pp == NULL) 243137034Sphk return (ENOENT); 244137034Sphk gp = g_new_geomf(&g_vfs_class, "%s.%s", fsname, pp->name); 245227015Smav sc = g_malloc(sizeof(*sc), M_WAITOK | M_ZERO); 246227015Smav mtx_init(&sc->sc_mtx, "g_vfs", NULL, MTX_DEF); 247227015Smav sc->sc_bo = bo; 248227015Smav gp->softc = sc; 249137034Sphk cp = g_new_consumer(gp); 250137034Sphk g_attach(cp, pp); 251223900Smckusick error = g_access(cp, 1, wr, wr); 252137034Sphk if (error) { 253137034Sphk g_wither_geom(gp, ENXIO); 254137034Sphk return (error); 255137034Sphk } 256140773Sphk vnode_create_vobject(vp, pp->mediasize, curthread); 257137034Sphk *cpp = cp; 258206130Savg cp->private = vp; 259260385Sscottl cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE; 260137034Sphk bo->bo_ops = g_vfs_bufops; 261137034Sphk bo->bo_private = cp; 262206097Savg bo->bo_bsize = pp->sectorsize; 263137034Sphk 264137034Sphk return (error); 265137034Sphk} 266140822Sphk 267140822Sphkvoid 268183754Sattiliog_vfs_close(struct g_consumer *cp) 269140822Sphk{ 270140822Sphk struct g_geom *gp; 271227015Smav struct g_vfs_softc *sc; 272140822Sphk 273140822Sphk g_topology_assert(); 274140822Sphk 275140822Sphk gp = cp->geom; 276227015Smav sc = gp->softc; 277227015Smav bufobj_invalbuf(sc->sc_bo, V_SAVE, 0, 0); 278227015Smav sc->sc_bo->bo_private = cp->private; 279227015Smav gp->softc = NULL; 280227015Smav mtx_destroy(&sc->sc_mtx); 281227015Smav if (!sc->sc_orphaned || cp->provider == NULL) 282227015Smav g_wither_geom_close(gp, ENXIO); 283227015Smav g_free(sc); 284140822Sphk} 285