Module Name: src Committed By: hannken Date: Fri Aug 12 14:36:30 UTC 2011
Modified Files: src/sys/fs/union: union_vnops.c Log Message: Add missing parts to mount devices from a union file system: - union_close() has to lock/unlock the lower vnode. - union_fsync() has to call spec_fsync() for the union vnode. - union_strategy() must allow writes to devices on the lower file system. - union_bwrite() was completely missing. To generate a diff of this commit: cvs rdiff -u -r1.43 -r1.44 src/sys/fs/union/union_vnops.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/fs/union/union_vnops.c diff -u src/sys/fs/union/union_vnops.c:1.43 src/sys/fs/union/union_vnops.c:1.44 --- src/sys/fs/union/union_vnops.c:1.43 Wed Aug 10 06:27:02 2011 +++ src/sys/fs/union/union_vnops.c Fri Aug 12 14:36:29 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: union_vnops.c,v 1.43 2011/08/10 06:27:02 hannken Exp $ */ +/* $NetBSD: union_vnops.c,v 1.44 2011/08/12 14:36:29 hannken Exp $ */ /* * Copyright (c) 1992, 1993, 1994, 1995 @@ -72,7 +72,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: union_vnops.c,v 1.43 2011/08/10 06:27:02 hannken Exp $"); +__KERNEL_RCSID(0, "$NetBSD: union_vnops.c,v 1.44 2011/08/12 14:36:29 hannken Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -91,6 +91,7 @@ #include <fs/union/union.h> #include <miscfs/genfs/genfs.h> +#include <miscfs/specfs/specdev.h> int union_lookup(void *); int union_create(void *); @@ -128,6 +129,7 @@ int union_pathconf(void *); int union_advlock(void *); int union_strategy(void *); +int union_bwrite(void *); int union_getpages(void *); int union_putpages(void *); int union_kqfilter(void *); @@ -175,6 +177,7 @@ { &vop_unlock_desc, union_unlock }, /* unlock */ { &vop_bmap_desc, union_bmap }, /* bmap */ { &vop_strategy_desc, union_strategy }, /* strategy */ + { &vop_bwrite_desc, union_bwrite }, /* bwrite */ { &vop_print_desc, union_print }, /* print */ { &vop_islocked_desc, union_islocked }, /* islocked */ { &vop_pathconf_desc, union_pathconf }, /* pathconf */ @@ -182,9 +185,6 @@ { &vop_getpages_desc, union_getpages }, /* getpages */ { &vop_putpages_desc, union_putpages }, /* putpages */ { &vop_kqfilter_desc, union_kqfilter }, /* kqfilter */ -#ifdef notdef - { &vop_bwrite_desc, union_bwrite }, /* bwrite */ -#endif { NULL, NULL } }; const struct vnodeopv_desc union_vnodeop_opv_desc = @@ -195,6 +195,9 @@ union_fixup(un); \ } \ } +#define NODE_IS_SPECIAL(vp) \ + ((vp)->v_type == VBLK || (vp)->v_type == VCHR || \ + (vp)->v_type == VSOCK || (vp)->v_type == VFIFO) static void union_fixup(struct union_node *un) @@ -695,24 +698,28 @@ } */ *ap = v; struct union_node *un = VTOUNION(ap->a_vp); struct vnode *vp; + int error; + bool do_lock; vp = un->un_uppervp; - if (vp == NULLVP) { -#ifdef UNION_DIAGNOSTIC - if (un->un_openl <= 0) - panic("union: un_openl cnt"); -#endif + if (vp != NULLVP) { + do_lock = false; + } else { + KASSERT(un->un_openl > 0); --un->un_openl; vp = un->un_lowervp; + do_lock = true; } -#ifdef DIAGNOSTIC - if (vp == NULLVP) - panic("union_close empty union vnode"); -#endif - + KASSERT(vp != NULLVP); ap->a_vp = vp; - return (VCALL(vp, VOFFSET(vop_close), ap)); + if (do_lock) + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); + error = VCALL(vp, VOFFSET(vop_close), ap); + if (do_lock) + VOP_UNLOCK(vp); + + return error; } /* @@ -944,20 +951,14 @@ union_newsize(ap->a_vp, vap->va_size, VNOVAL); } else { KASSERT(un->un_lowervp != NULLVP); - switch (un->un_lowervp->v_type) { - case VCHR: - case VBLK: - case VSOCK: - case VFIFO: + if (NODE_IS_SPECIAL(un->un_lowervp)) { if (size_only && (vap->va_size == 0 || vap->va_size == VNOVAL)) error = 0; else error = EROFS; - break; - default: + } else { error = EROFS; - break; } } @@ -1023,20 +1024,14 @@ vp = UPPERVP(ap->a_vp); if (vp == NULLVP) { vp = LOWERVP(ap->a_vp); - KASSERT(vp != NULL); - switch (vp->v_type) { - case VBLK: - case VCHR: - case VSOCK: - case VFIFO: + if (NODE_IS_SPECIAL(vp)) { vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); error = VOP_WRITE(vp, ap->a_uio, ap->a_ioflag, ap->a_cred); VOP_UNLOCK(vp); return error; - default: - panic("union: missing upper layer in write"); } + panic("union: missing upper layer in write"); } FIXUP(un); @@ -1137,11 +1132,16 @@ * they're locked; otherwise, pass it through to the * underlying layer. */ + if (ap->a_vp->v_type == VBLK || ap->a_vp->v_type == VCHR) { + error = spec_fsync(v); + if (error) + return error; + } + if (ap->a_flags & FSYNC_RECLAIM) return 0; targetvp = OTHERVP(ap->a_vp); - if (targetvp != NULLVP) { int dolock = (targetvp == LOWERVP(ap->a_vp)); @@ -1885,12 +1885,6 @@ return (VCALL(ovp, VOFFSET(vop_advlock), ap)); } - -/* - * XXX - vop_strategy must be hand coded because it has no - * vnode in its arguments. - * This goes away with a merged VM/buffer cache. - */ int union_strategy(void *v) { @@ -1904,15 +1898,40 @@ #ifdef DIAGNOSTIC if (ovp == NULLVP) panic("union_strategy: nil vp"); - if (((bp->b_flags & B_READ) == 0) && - (ovp == LOWERVP(bp->b_vp))) - panic("union_strategy: writing to lowervp"); + if (!NODE_IS_SPECIAL(ovp)) { + if (((bp->b_flags & B_READ) == 0) && + (ovp == LOWERVP(bp->b_vp))) + panic("union_strategy: writing to lowervp"); + } #endif return (VOP_STRATEGY(ovp, bp)); } int +union_bwrite(void *v) +{ + struct vop_bwrite_args /* { + struct vnode *a_vp; + struct buf *a_bp; + } */ *ap = v; + struct vnode *ovp = OTHERVP(ap->a_vp); + struct buf *bp = ap->a_bp; + +#ifdef DIAGNOSTIC + if (ovp == NULLVP) + panic("union_bwrite: nil vp"); + if (!NODE_IS_SPECIAL(ovp)) { + if (((bp->b_flags & B_READ) == 0) && + (ovp == LOWERVP(bp->b_vp))) + panic("union_strategy: writing to lowervp"); + } +#endif + + return (VOP_BWRITE(ovp, bp)); +} + +int union_getpages(void *v) { struct vop_getpages_args /* {