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