Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src Current support for iterating over mnt_vnodelist is rudiment...



details:   https://anonhg.NetBSD.org/src/rev/5ff92bc3d986
branches:  trunk
changeset: 794089:5ff92bc3d986
user:      hannken <hannken%NetBSD.org@localhost>
date:      Wed Mar 05 09:37:29 2014 +0000

description:
Current support for iterating over mnt_vnodelist is rudimentary.  Every
caller has to care about list and vnode mutexes, reference count being zero,
intermediate vnode states like VI_CLEAN, VI_XLOCK, VI_MARKER and so on.

Add an interface to iterate over a vnode list:

void vfs_vnode_iterator_init(struct mount *mp, struct vnode_iterator **marker)
void vfs_vnode_iterator_destroy(struct vnode_iterator *marker)
bool vfs_vnode_iterator_next(struct vnode_iterator *marker, struct vnode **vpp)

vfs_vnode_iterator_next() returns either "false / *vpp == NULL" when done
or "true / *vpp != NULL" to return the next referenced vnode from the list.

To make vrecycle() work in this environment change it to

bool vrecycle(struct vnode *vp)

where "vp" is a referenced vnode to be destroyed if this is the last reference.

Discussed on tech-kern.

Welcome to 6.99.34

diffstat:

 share/man/man9/vnode.9         |   14 +-
 sys/kern/vfs_mount.c           |  155 +++++++++++++++++++++++++++-------------
 sys/kern/vfs_vnode.c           |   33 ++++---
 sys/sys/mount.h                |    7 +-
 sys/sys/param.h                |    4 +-
 sys/sys/vnode.h                |    4 +-
 sys/ufs/ext2fs/ext2fs_vfsops.c |   43 +++--------
 sys/ufs/ffs/ffs_vfsops.c       |   41 +++-------
 sys/ufs/lfs/lfs_syscalls.c     |   22 ++++-
 9 files changed, 180 insertions(+), 143 deletions(-)

diffs (truncated from 638 to 300 lines):

diff -r 853f1e5d1dba -r 5ff92bc3d986 share/man/man9/vnode.9
--- a/share/man/man9/vnode.9    Wed Mar 05 08:45:13 2014 +0000
+++ b/share/man/man9/vnode.9    Wed Mar 05 09:37:29 2014 +0000
@@ -1,4 +1,4 @@
-.\"     $NetBSD: vnode.9,v 1.59 2014/02/22 11:28:18 wiz Exp $
+.\"     $NetBSD: vnode.9,v 1.60 2014/03/05 09:37:29 hannken Exp $
 .\"
 .\" Copyright (c) 2001, 2005, 2006 The NetBSD Foundation, Inc.
 .\" All rights reserved.
@@ -27,7 +27,7 @@
 .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 .\" POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd February 22, 2014
+.Dd March 5, 2014
 .Dt VNODE 9
 .Os
 .Sh NAME
@@ -79,7 +79,7 @@
 .Ft void
 .Fn ungetnewvnode "struct vnode *vp"
 .Ft int
-.Fn vrecycle "struct vnode *vp" "struct kmutex_t *inter_lkp"
+.Fn vrecycle "struct vnode *vp"
 .Ft void
 .Fn vgone "struct vnode *vp"
 .Ft void
@@ -616,12 +616,12 @@
 .Xr VFS_VGET 9
 which may need to push back a vnode in case of a locking race
 condition.
-.It Fn vrecycle "vp" "inter_lkp"
-Recycle the unused vnode
+.It Fn vrecycle "vp"
+Recycle the referenced vnode
 .Fa vp
-from the front of the freelist.
+if this is the last reference.
 .Fn vrecycle
-is a null operation if the reference count is greater than zero.
+is a null operation if the reference count is greater than one.
 .It Fn vgone "vp"
 Eliminate all activity associated with the unlocked vnode
 .Fa vp
diff -r 853f1e5d1dba -r 5ff92bc3d986 sys/kern/vfs_mount.c
--- a/sys/kern/vfs_mount.c      Wed Mar 05 08:45:13 2014 +0000
+++ b/sys/kern/vfs_mount.c      Wed Mar 05 09:37:29 2014 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: vfs_mount.c,v 1.26 2014/02/27 13:00:06 hannken Exp $   */
+/*     $NetBSD: vfs_mount.c,v 1.27 2014/03/05 09:37:29 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.26 2014/02/27 13:00:06 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_mount.c,v 1.27 2014/03/05 09:37:29 hannken Exp $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -375,6 +375,82 @@
        return vp;
 }
 
+struct vnode_iterator {
+       struct vnode vi_vnode;
+}; 
+
+void
+vfs_vnode_iterator_init(struct mount *mp, struct vnode_iterator **vipp)
+{
+       struct vnode *vp;
+
+       vp = vnalloc(mp);
+
+       mutex_enter(&mntvnode_lock);
+       TAILQ_INSERT_HEAD(&mp->mnt_vnodelist, vp, v_mntvnodes);
+       vp->v_usecount = 1;
+       mutex_exit(&mntvnode_lock);
+
+       *vipp = (struct vnode_iterator *)vp;
+}
+
+void
+vfs_vnode_iterator_destroy(struct vnode_iterator *vi)
+{
+       struct vnode *mvp = &vi->vi_vnode;
+
+       mutex_enter(&mntvnode_lock);
+       KASSERT(ISSET(mvp->v_iflag, VI_MARKER));
+       if (mvp->v_usecount != 0)
+               TAILQ_REMOVE(&mvp->v_mount->mnt_vnodelist, mvp, v_mntvnodes);
+       mutex_exit(&mntvnode_lock);
+       vnfree(mvp);
+}
+
+bool
+vfs_vnode_iterator_next(struct vnode_iterator *vi, struct vnode **vpp)
+{
+       struct vnode *mvp = &vi->vi_vnode;
+       struct mount *mp = mvp->v_mount;
+       struct vnode *vp;
+       int error;
+
+       KASSERT(ISSET(mvp->v_iflag, VI_MARKER));
+
+       do {
+               mutex_enter(&mntvnode_lock);
+               vp = TAILQ_NEXT(mvp, v_mntvnodes);
+               TAILQ_REMOVE(&mp->mnt_vnodelist, mvp, v_mntvnodes);
+               mvp->v_usecount = 0;
+               if (vp == NULL) {
+                       mutex_exit(&mntvnode_lock);
+                       *vpp = NULL;
+                       return false;
+               }
+
+               mutex_enter(vp->v_interlock);
+               while ((vp->v_iflag & VI_MARKER) != 0) {
+                       mutex_exit(vp->v_interlock);
+                       vp = TAILQ_NEXT(vp, v_mntvnodes);
+                       if (vp == NULL) {
+                               mutex_exit(&mntvnode_lock);
+                               *vpp = NULL;
+                               return false;
+                       }
+                       mutex_enter(vp->v_interlock);
+               }
+
+               TAILQ_INSERT_AFTER(&mp->mnt_vnodelist, vp, mvp, v_mntvnodes);
+               mvp->v_usecount = 1;
+               mutex_exit(&mntvnode_lock);
+               error = vget(vp, 0);
+               KASSERT(error == 0 || error == ENOENT);
+       } while (error != 0);
+
+       *vpp = vp;
+       return true;
+}
+
 /*
  * Move a vnode from one mount queue to another.
  */
@@ -426,99 +502,78 @@
 #endif
 
 static vnode_t *
-vflushnext(vnode_t *mvp, int *when)
+vflushnext(struct vnode_iterator *marker, int *when)
 {
+       struct vnode *vp;
 
        if (hardclock_ticks > *when) {
-               mutex_exit(&mntvnode_lock);
                yield();
-               mutex_enter(&mntvnode_lock);
                *when = hardclock_ticks + hz / 10;
        }
-       return vunmark(mvp);
+       if (vfs_vnode_iterator_next(marker, &vp))
+               return vp;
+       return NULL;
 }
 
 int
 vflush(struct mount *mp, vnode_t *skipvp, int flags)
 {
-       vnode_t *vp, *mvp;
+       vnode_t *vp;
+       struct vnode_iterator *marker;
        int busy = 0, when = 0;
 
        /* First, flush out any vnode references from vrele_list. */
        vrele_flush();
 
-       /* Allocate a marker vnode. */
-       mvp = vnalloc(mp);
-
-       /*
-        * NOTE: not using the TAILQ_FOREACH here since in this loop vgone()
-        * and vclean() are called.
-        */
-       mutex_enter(&mntvnode_lock);
-       for (vp = TAILQ_FIRST(&mp->mnt_vnodelist);
-           vp != NULL;
-           vp = vflushnext(mvp, &when)) {
-               vmark(mvp, vp);
-               if (vp->v_mount != mp || vismarker(vp))
-                       continue;
+       vfs_vnode_iterator_init(mp, &marker);
+       while ((vp = vflushnext(marker, &when)) != NULL) {
                /*
                 * Skip over a selected vnode.
                 */
-               if (vp == skipvp)
-                       continue;
-               /*
-                * First try to recycle the vnode.
-                */
-               if (vrecycle(vp, &mntvnode_lock)) {
-                       mutex_enter(&mntvnode_lock);
-                       continue;
-               }
-               mutex_enter(vp->v_interlock);
-               /*
-                * Ignore clean but still referenced vnodes.
-                */
-               if ((vp->v_iflag & VI_CLEAN) != 0) {
-                       mutex_exit(vp->v_interlock);
+               if (vp == skipvp) {
+                       vrele(vp);
                        continue;
                }
                /*
                 * Skip over a vnodes marked VSYSTEM.
                 */
                if ((flags & SKIPSYSTEM) && (vp->v_vflag & VV_SYSTEM)) {
-                       mutex_exit(vp->v_interlock);
+                       vrele(vp);
                        continue;
                }
                /*
                 * If WRITECLOSE is set, only flush out regular file
                 * vnodes open for writing.
                 */
-               if ((flags & WRITECLOSE) &&
-                   (vp->v_writecount == 0 || vp->v_type != VREG)) {
+               if ((flags & WRITECLOSE) && vp->v_type == VREG) {
+                       mutex_enter(vp->v_interlock);
+                       if (vp->v_writecount == 0) {
+                               mutex_exit(vp->v_interlock);
+                               vrele(vp);
+                               continue;
+                       }
                        mutex_exit(vp->v_interlock);
+               }
+               /*
+                * First try to recycle the vnode.
+                */
+               if (vrecycle(vp))
                        continue;
-               }
                /*
                 * If FORCECLOSE is set, forcibly close the vnode.
-                * For block or character devices, revert to an
-                * anonymous device.  For all other files, just
-                * kill them.
                 */
                if (flags & FORCECLOSE) {
-                       mutex_exit(&mntvnode_lock);
-                       if (vget(vp, 0) == 0)
-                               vgone(vp);
-                       mutex_enter(&mntvnode_lock);
+                       vgone(vp);
                        continue;
                }
 #ifdef DEBUG
                if (busyprt)
                        vprint("vflush: busy vnode", vp);
 #endif
-               mutex_exit(vp->v_interlock);
+               vrele(vp);
                busy++;
        }
-       mutex_exit(&mntvnode_lock);
-       vnfree(mvp);
+       vfs_vnode_iterator_destroy(marker);
        if (busy)
                return (EBUSY);
        return (0);
diff -r 853f1e5d1dba -r 5ff92bc3d986 sys/kern/vfs_vnode.c
--- a/sys/kern/vfs_vnode.c      Wed Mar 05 08:45:13 2014 +0000
+++ b/sys/kern/vfs_vnode.c      Wed Mar 05 09:37:29 2014 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: vfs_vnode.c,v 1.32 2014/02/27 16:51:38 hannken Exp $   */
+/*     $NetBSD: vfs_vnode.c,v 1.33 2014/03/05 09:37:29 hannken Exp $   */
 
 /*-
  * Copyright (c) 1997-2011 The NetBSD Foundation, Inc.
@@ -116,7 +116,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_vnode.c,v 1.32 2014/02/27 16:51:38 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_vnode.c,v 1.33 2014/03/05 09:37:29 hannken Exp $");
 
 #define _VFS_VNODE_PRIVATE
 
@@ -1029,30 +1029,33 @@
 }
 
 /*
- * Recycle an unused vnode to the front of the free list.
- * Release the passed interlock if the vnode will be recycled.
+ * Recycle an unused vnode if caller holds the last reference.
  */
-int
-vrecycle(vnode_t *vp, kmutex_t *inter_lkp)



Home | Main Index | Thread Index | Old Index