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());
 	}

Reply via email to