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