Module Name: src Committed By: hannken Date: Wed Apr 27 07:24:53 UTC 2011
Modified Files: src/sys/ufs/ffs: ffs_extern.h ffs_vfsops.c ffs_vnops.c Log Message: Cleanup ffs fsync and make devices on wapbl enabled file systems work here: - Replace the ugly sync loop in ffs_full_fsync() and ffs_vfs_fsync() with vflushbuf(). This loop is a relic of softdeps and not needed anymore. - Add ffs_spec_fsync() for device nodes on ffs file systems that calls spec_fsync() like all other file systems do and then updates the ctime. Discussed on tech-kern. Should fix PRs: PR #41192 wapbl diagnostic panic during cgdconfig PR #41977 kernel diagnostic assertion "rw_lock_held(&wl->wl_rwlock)" failed PR #42149 wapbl locking panic if watching DVD PR #42551 Lockdebug assert in wapbl when running zpool To generate a diff of this commit: cvs rdiff -u -r1.76 -r1.77 src/sys/ufs/ffs/ffs_extern.h cvs rdiff -u -r1.265 -r1.266 src/sys/ufs/ffs/ffs_vfsops.c cvs rdiff -u -r1.117 -r1.118 src/sys/ufs/ffs/ffs_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/ufs/ffs/ffs_extern.h diff -u src/sys/ufs/ffs/ffs_extern.h:1.76 src/sys/ufs/ffs/ffs_extern.h:1.77 --- src/sys/ufs/ffs/ffs_extern.h:1.76 Sun Mar 6 17:08:38 2011 +++ src/sys/ufs/ffs/ffs_extern.h Wed Apr 27 07:24:52 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: ffs_extern.h,v 1.76 2011/03/06 17:08:38 bouyer Exp $ */ +/* $NetBSD: ffs_extern.h,v 1.77 2011/04/27 07:24:52 hannken Exp $ */ /*- * Copyright (c) 1991, 1993, 1994 @@ -125,6 +125,7 @@ int ffs_read(void *); int ffs_write(void *); int ffs_fsync(void *); +int ffs_spec_fsync(void *); int ffs_reclaim(void *); int ffs_getpages(void *); void ffs_gop_size(struct vnode *, off_t, off_t *, int); Index: src/sys/ufs/ffs/ffs_vfsops.c diff -u src/sys/ufs/ffs/ffs_vfsops.c:1.265 src/sys/ufs/ffs/ffs_vfsops.c:1.266 --- src/sys/ufs/ffs/ffs_vfsops.c:1.265 Sun Mar 27 08:04:50 2011 +++ src/sys/ufs/ffs/ffs_vfsops.c Wed Apr 27 07:24:53 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: ffs_vfsops.c,v 1.265 2011/03/27 08:04:50 mlelstv Exp $ */ +/* $NetBSD: ffs_vfsops.c,v 1.266 2011/04/27 07:24:53 hannken Exp $ */ /*- * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc. @@ -61,7 +61,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ffs_vfsops.c,v 1.265 2011/03/27 08:04:50 mlelstv Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ffs_vfsops.c,v 1.266 2011/04/27 07:24:53 hannken Exp $"); #if defined(_KERNEL_OPT) #include "opt_ffs.h" @@ -2071,14 +2071,12 @@ } /* - * Synch vnode for a mounted file system. This is called for foreign - * vnodes, i.e. non-ffs. + * Synch vnode for a mounted file system. */ static int ffs_vfs_fsync(vnode_t *vp, int flags) { - int error, passes, skipmeta, i, pflags; - buf_t *bp, *nbp; + int error, i, pflags; #ifdef WAPBL struct mount *mp; #endif @@ -2130,80 +2128,9 @@ } #endif /* WAPBL */ - /* - * Write out metadata for non-logging file systems. XXX This block - * should be simplified now that softdep is gone. - */ - passes = NIADDR + 1; - skipmeta = 0; - if (flags & FSYNC_WAIT) - skipmeta = 1; - -loop: - mutex_enter(&bufcache_lock); - LIST_FOREACH(bp, &vp->v_dirtyblkhd, b_vnbufs) { - bp->b_cflags &= ~BC_SCANNED; - } - for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) { - nbp = LIST_NEXT(bp, b_vnbufs); - if (bp->b_cflags & (BC_BUSY | BC_SCANNED)) - continue; - if ((bp->b_oflags & BO_DELWRI) == 0) - panic("ffs_fsync: not dirty"); - if (skipmeta && bp->b_lblkno < 0) - continue; - bp->b_cflags |= BC_BUSY | BC_VFLUSH | BC_SCANNED; - mutex_exit(&bufcache_lock); - /* - * On our final pass through, do all I/O synchronously - * so that we can find out if our flush is failing - * because of write errors. - */ - if (passes > 0 || !(flags & FSYNC_WAIT)) - (void) bawrite(bp); - else if ((error = bwrite(bp)) != 0) - return (error); - /* - * Since we unlocked during the I/O, we need - * to start from a known point. - */ - mutex_enter(&bufcache_lock); - nbp = LIST_FIRST(&vp->v_dirtyblkhd); - } - mutex_exit(&bufcache_lock); - if (skipmeta) { - skipmeta = 0; - goto loop; - } - - if ((flags & FSYNC_WAIT) != 0) { - mutex_enter(&vp->v_interlock); - while (vp->v_numoutput) { - cv_wait(&vp->v_cv, &vp->v_interlock); - } - mutex_exit(&vp->v_interlock); - - if (!LIST_EMPTY(&vp->v_dirtyblkhd)) { - /* - * Block devices associated with filesystems may - * have new I/O requests posted for them even if - * the vnode is locked, so no amount of trying will - * get them clean. Thus we give block devices a - * good effort, then just give up. For all other file - * types, go around and try again until it is clean. - */ - if (passes > 0) { - passes--; - goto loop; - } -#ifdef DIAGNOSTIC - if (vp->v_type != VBLK) - vprint("ffs_fsync: dirty", vp); -#endif - } - } - + error = vflushbuf(vp, (flags & FSYNC_WAIT) != 0); if (error == 0 && (flags & FSYNC_CACHE) != 0) { + i = 1; (void)VOP_IOCTL(vp, DIOCCACHESYNC, &i, FWRITE, kauth_cred_get()); } Index: src/sys/ufs/ffs/ffs_vnops.c diff -u src/sys/ufs/ffs/ffs_vnops.c:1.117 src/sys/ufs/ffs/ffs_vnops.c:1.118 --- src/sys/ufs/ffs/ffs_vnops.c:1.117 Fri Apr 15 15:54:11 2011 +++ src/sys/ufs/ffs/ffs_vnops.c Wed Apr 27 07:24:53 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: ffs_vnops.c,v 1.117 2011/04/15 15:54:11 hannken Exp $ */ +/* $NetBSD: ffs_vnops.c,v 1.118 2011/04/27 07:24:53 hannken Exp $ */ /*- * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc. @@ -61,7 +61,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ffs_vnops.c,v 1.117 2011/04/15 15:54:11 hannken Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ffs_vnops.c,v 1.118 2011/04/27 07:24:53 hannken Exp $"); #if defined(_KERNEL_OPT) #include "opt_ffs.h" @@ -175,7 +175,7 @@ { &vop_kqfilter_desc, spec_kqfilter }, /* kqfilter */ { &vop_revoke_desc, spec_revoke }, /* revoke */ { &vop_mmap_desc, spec_mmap }, /* mmap */ - { &vop_fsync_desc, ffs_fsync }, /* fsync */ + { &vop_fsync_desc, ffs_spec_fsync }, /* fsync */ { &vop_seek_desc, spec_seek }, /* seek */ { &vop_remove_desc, spec_remove }, /* remove */ { &vop_link_desc, spec_link }, /* link */ @@ -266,6 +266,61 @@ #include <ufs/ufs/ufs_readwrite.c> int +ffs_spec_fsync(void *v) +{ + struct vop_fsync_args /* { + struct vnode *a_vp; + kauth_cred_t a_cred; + int a_flags; + off_t a_offlo; + off_t a_offhi; + struct lwp *a_l; + } */ *ap = v; + int error, flags, uflags; + struct vnode *vp; + struct mount *mp; + + flags = ap->a_flags; + uflags = UPDATE_CLOSE | ((flags & FSYNC_WAIT) ? UPDATE_WAIT : 0); + vp = ap->a_vp; + mp = vp->v_mount; + + fstrans_start(mp, FSTRANS_LAZY); + + error = spec_fsync(v); + if (error) + goto out; + +#ifdef WAPBL + if (mp && mp->mnt_wapbl) { + /* + * Don't bother writing out metadata if the syncer is + * making the request. We will let the sync vnode + * write it out in a single burst through a call to + * VFS_SYNC(). + */ + if ((flags & (FSYNC_DATAONLY | FSYNC_LAZY)) != 0) + goto out; + if ((VTOI(vp)->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE + | IN_MODIFY | IN_MODIFIED | IN_ACCESSED)) != 0) { + error = UFS_WAPBL_BEGIN(mp); + if (error != 0) + goto out; + error = ffs_update(vp, NULL, NULL, uflags); + UFS_WAPBL_END(mp); + } + goto out; + } +#endif /* WAPBL */ + + error = ffs_update(vp, NULL, NULL, uflags); + +out: + fstrans_done(mp); + return error; +} + +int ffs_fsync(void *v) { struct vop_fsync_args /* { @@ -399,32 +454,27 @@ int ffs_full_fsync(struct vnode *vp, int flags) { - struct buf *bp, *nbp; - int error, passes, skipmeta, waitfor, i; + int error, i, uflags; struct mount *mp; - KASSERT(VTOI(vp) != NULL); KASSERT(vp->v_tag == VT_UFS); + KASSERT(VTOI(vp) != NULL); + KASSERT(vp->v_type != VCHR && vp->v_type != VBLK); error = 0; + uflags = UPDATE_CLOSE | ((flags & FSYNC_WAIT) ? UPDATE_WAIT : 0); mp = vp->v_mount; - if (vp->v_type == VBLK && vp->v_specmountpoint != NULL) { - mp = vp->v_specmountpoint; - } else { - mp = vp->v_mount; - } /* * Flush all dirty data associated with the vnode. */ - if (vp->v_type == VREG || vp->v_type == VBLK) { + if (vp->v_type == VREG) { int pflags = PGO_ALLPAGES | PGO_CLEANIT; if ((flags & FSYNC_WAIT)) pflags |= PGO_SYNCIO; - if (vp->v_type == VREG && - fstrans_getstate(mp) == FSTRANS_SUSPENDING) + if (fstrans_getstate(mp) == FSTRANS_SUSPENDING) pflags |= PGO_FREE; mutex_enter(&vp->v_interlock); error = VOP_PUTPAGES(vp, 0, 0, pflags); @@ -433,7 +483,6 @@ } #ifdef WAPBL - mp = wapbl_vptomp(vp); if (mp && mp->mnt_wapbl) { /* * Don't bother writing out metadata if the syncer is @@ -449,8 +498,7 @@ error = UFS_WAPBL_BEGIN(mp); if (error) return error; - error = ffs_update(vp, NULL, NULL, UPDATE_CLOSE | - ((flags & FSYNC_WAIT) ? UPDATE_WAIT : 0)); + error = ffs_update(vp, NULL, NULL, uflags); UFS_WAPBL_END(mp); } if (error || (flags & FSYNC_NOLOG) != 0) @@ -477,87 +525,11 @@ } #endif /* WAPBL */ - /* - * Write out metadata for non-logging file systems. XXX This block - * should be simplified now that softdep is gone. - */ - passes = NIADDR + 1; - skipmeta = 0; - if (flags & FSYNC_WAIT) - skipmeta = 1; - -loop: - mutex_enter(&bufcache_lock); - LIST_FOREACH(bp, &vp->v_dirtyblkhd, b_vnbufs) { - bp->b_cflags &= ~BC_SCANNED; - } - for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) { - nbp = LIST_NEXT(bp, b_vnbufs); - if (bp->b_cflags & (BC_BUSY | BC_SCANNED)) - continue; - if ((bp->b_oflags & BO_DELWRI) == 0) - panic("ffs_fsync: not dirty"); - if (skipmeta && bp->b_lblkno < 0) - continue; - bp->b_cflags |= BC_BUSY | BC_VFLUSH | BC_SCANNED; - mutex_exit(&bufcache_lock); - /* - * On our final pass through, do all I/O synchronously - * so that we can find out if our flush is failing - * because of write errors. - */ - if (passes > 0 || !(flags & FSYNC_WAIT)) - (void) bawrite(bp); - else if ((error = bwrite(bp)) != 0) - return (error); - /* - * Since we unlocked during the I/O, we need - * to start from a known point. - */ - mutex_enter(&bufcache_lock); - nbp = LIST_FIRST(&vp->v_dirtyblkhd); - } - mutex_exit(&bufcache_lock); - if (skipmeta) { - skipmeta = 0; - goto loop; - } - - if ((flags & FSYNC_WAIT) != 0) { - mutex_enter(&vp->v_interlock); - while (vp->v_numoutput) { - cv_wait(&vp->v_cv, &vp->v_interlock); - } - mutex_exit(&vp->v_interlock); - - /* - * Ensure that any filesystem metadata associated - * with the vnode has been written. - */ - if (!LIST_EMPTY(&vp->v_dirtyblkhd)) { - /* - * Block devices associated with filesystems may - * have new I/O requests posted for them even if - * the vnode is locked, so no amount of trying will - * get them clean. Thus we give block devices a - * good effort, then just give up. For all other file - * types, go around and try again until it is clean. - */ - if (passes > 0) { - passes--; - goto loop; - } -#ifdef DIAGNOSTIC - if (vp->v_type != VBLK) - vprint("ffs_fsync: dirty", vp); -#endif - } - } - - waitfor = (flags & FSYNC_WAIT) ? UPDATE_WAIT : 0; - error = ffs_update(vp, NULL, NULL, UPDATE_CLOSE | waitfor); - + error = vflushbuf(vp, (flags & FSYNC_WAIT) != 0); + if (error == 0) + error = ffs_update(vp, NULL, NULL, uflags); if (error == 0 && (flags & FSYNC_CACHE) != 0) { + i = 1; (void)VOP_IOCTL(VTOI(vp)->i_devvp, DIOCCACHESYNC, &i, FWRITE, kauth_cred_get()); }