Module Name:    src
Committed By:   hannken
Date:           Fri Jan 27 10:46:18 UTC 2017

Modified Files:
        src/sys/kern: vfs_mount.c

Log Message:
When called with WRITECLOSE vflush() must sync the vnode and take
care of unlinked but open vnodes.

PR kern/30525 remounting ffs read-only (mount -ur) does not sync metadata.


To generate a diff of this commit:
cvs rdiff -u -r1.45 -r1.46 src/sys/kern/vfs_mount.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/kern/vfs_mount.c
diff -u src/sys/kern/vfs_mount.c:1.45 src/sys/kern/vfs_mount.c:1.46
--- src/sys/kern/vfs_mount.c:1.45	Fri Jan 13 10:10:32 2017
+++ src/sys/kern/vfs_mount.c	Fri Jan 27 10:46:18 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: vfs_mount.c,v 1.45 2017/01/13 10:10:32 hannken Exp $	*/
+/*	$NetBSD: vfs_mount.c,v 1.46 2017/01/27 10:46:18 hannken Exp $	*/
 
 /*-
  * Copyright (c) 1997-2011 The NetBSD Foundation, Inc.
@@ -67,7 +67,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_mount.c,v 1.45 2017/01/13 10:10:32 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_mount.c,v 1.46 2017/01/27 10:46:18 hannken Exp $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -478,87 +478,108 @@ int busyprt = 0;	/* print out busy vnode
 struct ctldebug debug1 = { "busyprt", &busyprt };
 #endif
 
-struct vflush_ctx {
-	const struct vnode *skipvp;
-	int flags;
-};
+static vnode_t *
+vflushnext(struct vnode_iterator *marker, int *when)
+{
+	if (hardclock_ticks > *when) {
+		yield();
+		*when = hardclock_ticks + hz / 10;
+	}
+	return vfs_vnode_iterator_next1(marker, NULL, NULL, true);
+}
 
-static bool
-vflush_selector(void *cl, struct vnode *vp)
+/*
+ * Flush one vnode.  Referenced on entry, unreferenced on return.
+ */
+static int
+vflush_one(vnode_t *vp, vnode_t *skipvp, int flags)
 {
-	struct vflush_ctx *c = cl;
+	int error;
+	struct vattr vattr;
+
+	if (vp == skipvp ||
+	    ((flags & SKIPSYSTEM) && (vp->v_vflag & VV_SYSTEM))) {
+		vrele(vp);
+		return 0;
+	}
 	/*
-	 * Skip over a selected vnode.
+	 * If WRITECLOSE is set, only flush out regular file
+	 * vnodes open for writing or open and unlinked.
 	 */
-	if (vp == c->skipvp)
-		return false;
+	if ((flags & WRITECLOSE)) {
+		if (vp->v_type != VREG) {
+			vrele(vp);
+			return 0;
+		}
+		error = vn_lock(vp, LK_EXCLUSIVE);
+		if (error) {
+			KASSERT(error == ENOENT);
+			vrele(vp);
+			return 0;
+		}
+		error = VOP_FSYNC(vp, curlwp->l_cred, FSYNC_WAIT, 0, 0);
+		if (error == 0)
+			error = VOP_GETATTR(vp, &vattr, curlwp->l_cred);
+		VOP_UNLOCK(vp);
+		if (error) {
+			vrele(vp);
+			return error;
+		}
+		if (vp->v_writecount == 0 && vattr.va_nlink > 0) {
+			vrele(vp);
+			return 0;
+		}
+	}
 	/*
-	 * Skip over a vnodes marked VSYSTEM.
+	 * First try to recycle the vnode.
 	 */
-	if ((c->flags & SKIPSYSTEM) && (vp->v_vflag & VV_SYSTEM))
-		return false;
-
+	if (vrecycle(vp))
+		return 0;
 	/*
-	 * If WRITECLOSE is set, only flush out regular file
-	 * vnodes open for writing.
+	 * If FORCECLOSE is set, forcibly close the vnode.
 	 */
-	if ((c->flags & WRITECLOSE) && vp->v_type == VREG) {
-		if (vp->v_writecount == 0)
-			return false;
+	if (flags & FORCECLOSE) {
+		vgone(vp);
+		return 0;
 	}
-	return true;
+	vrele(vp);
+	return EBUSY;
 }
 
-static vnode_t *
-vflushnext(struct vnode_iterator *marker, void *ctx, int *when)
-{
-	if (hardclock_ticks > *when) {
-		yield();
-		*when = hardclock_ticks + hz / 10;
-	}
-	return vfs_vnode_iterator_next1(marker, vflush_selector, ctx, true);
-}
-
-
 int
 vflush(struct mount *mp, vnode_t *skipvp, int flags)
 {
 	vnode_t *vp;
 	struct vnode_iterator *marker;
-	int busy = 0, when = 0;
-	struct vflush_ctx ctx;
+	int busy, error, when;
+
+	busy = error = when = 0;
 
 	/* First, flush out any vnode references from deferred vrele list. */
 	vfs_drainvnodes();
 
 	vfs_vnode_iterator_init(mp, &marker);
 
-	ctx.skipvp = skipvp;
-	ctx.flags = flags;
-	while ((vp = vflushnext(marker, &ctx, &when)) != NULL) {
-		/*
-		 * First try to recycle the vnode.
-		 */
-		if (vrecycle(vp))
-			continue;
-		/*
-		 * If FORCECLOSE is set, forcibly close the vnode.
-		 */
-		if (flags & FORCECLOSE) {
-			vgone(vp);
-			continue;
-		}
+	while ((vp = vflushnext(marker, &when)) != NULL) {
+		error = vflush_one(vp, skipvp, flags);
+		if (error == EBUSY) {
+			error = 0;
+			busy++;
 #ifdef DEBUG
-		if (busyprt)
-			vprint("vflush: busy vnode", vp);
+			if (busyprt)
+				vprint("vflush: busy vnode", vp);
 #endif
-		vrele(vp);
-		busy++;
+		} else if (error != 0) {
+			break;
+		}
 	}
+
 	vfs_vnode_iterator_destroy(marker);
-	if (busy)
-		return (EBUSY);
 
+	if (error)
+		return error;
+	if (busy)
+		return EBUSY;
 	return 0;
 }
 

Reply via email to