Source-Changes-HG archive

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

[src/trunk]: src/sys A couple of small changes to lookup that cut 5-10% syste...



details:   https://anonhg.NetBSD.org/src/rev/d5d5ac3a771d
branches:  trunk
changeset: 972583:d5d5ac3a771d
user:      ad <ad%NetBSD.org@localhost>
date:      Sat May 30 20:16:14 2020 +0000

description:
A couple of small changes to lookup that cut 5-10% system time from
"build.sh release" on my test system:

- Crossing mount points during lookup is slow because the set up for, and
  act of doing VFS_ROOT() is quite involved.  Use the name cache to help
  with this.  Cache an "impossible" zero-length name with covered vnodes,
  that points to the root of the file system mounted there.  Use it to cross
  mounts.  When cache_purge() is called on either of the vnodes involved the
  cache entry will disappear.  All of the needed calls for that are already
  in place (vnode reclaim, unmount, etc).

- In lookup_fastforward(), if the the last component has been found and the
  parent directory (searchdir) is not going to be returned, then don't get a
  reference to it.

diffstat:

 sys/kern/vfs_cache.c  |   70 +++++++++++++++++++-
 sys/kern/vfs_lookup.c |  173 ++++++++++++++++++++++++++++++++++++-------------
 sys/sys/namei.src     |    5 +-
 3 files changed, 198 insertions(+), 50 deletions(-)

diffs (truncated from 405 to 300 lines):

diff -r b8f500b44268 -r d5d5ac3a771d sys/kern/vfs_cache.c
--- a/sys/kern/vfs_cache.c      Sat May 30 19:51:32 2020 +0000
+++ b/sys/kern/vfs_cache.c      Sat May 30 20:16:14 2020 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: vfs_cache.c,v 1.145 2020/05/30 18:06:17 ad Exp $       */
+/*     $NetBSD: vfs_cache.c,v 1.146 2020/05/30 20:16:14 ad Exp $       */
 
 /*-
  * Copyright (c) 2008, 2019, 2020 The NetBSD Foundation, Inc.
@@ -172,7 +172,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_cache.c,v 1.145 2020/05/30 18:06:17 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_cache.c,v 1.146 2020/05/30 20:16:14 ad Exp $");
 
 #define __NAMECACHE_PRIVATE
 #ifdef _KERNEL_OPT
@@ -269,6 +269,15 @@
 static struct  sysctllog *cache_sysctllog;
 
 /*
+ * This is a dummy name that cannot usually occur anywhere in the cache nor
+ * file system.  It's used when caching the root vnode of mounted file
+ * systems.  The name is attached to the directory that the file system is
+ * mounted on.
+ */
+static const char cache_mp_name[] = "";
+static const int cache_mp_nlen = sizeof(cache_mp_name) - 1;
+
+/*
  * Red-black tree stuff.
  */
 static const rb_tree_ops_t cache_rbtree_ops = {
@@ -507,6 +516,8 @@
        bool hit;
        krw_t op;
 
+       KASSERT(namelen != cache_mp_nlen || name == cache_mp_name);
+
        /* Establish default result values */
        if (iswht_ret != NULL) {
                *iswht_ret = 0;
@@ -630,6 +641,8 @@
        uint64_t key;
        int error;
 
+       KASSERT(namelen != cache_mp_nlen || name == cache_mp_name);
+
        /* If disabled, or file system doesn't support this, bail out. */
        if (__predict_false((dvp->v_mount->mnt_iflag & IMNT_NCLOOKUP) == 0)) {
                return false;
@@ -714,6 +727,7 @@
        }
        if (ncp->nc_vp == NULL) {
                /* found negative entry; vn is already null from above */
+               KASSERT(namelen != cache_mp_nlen && name != cache_mp_name);
                COUNT(ncs_neghits);
        } else {
                COUNT(ncs_goodhits); /* XXX can be "badhits" */
@@ -797,6 +811,13 @@
                nlen = ncp->nc_nlen;
 
                /*
+                * Ignore mountpoint entries.
+                */
+               if (ncp->nc_nlen == cache_mp_nlen) {
+                       continue;
+               }
+
+               /*
                 * The queue is partially sorted.  Once we hit dots, nothing
                 * else remains but dots and dotdots, so bail out.
                 */
@@ -866,6 +887,8 @@
        struct namecache *ncp, *oncp;
        int total;
 
+       KASSERT(namelen != cache_mp_nlen || name == cache_mp_name);
+
        /* First, check whether we can/should add a cache entry. */
        if ((cnflags & MAKEENTRY) == 0 ||
            __predict_false(namelen > cache_maxlen)) {
@@ -1002,6 +1025,49 @@
 }
 
 /*
+ * Enter a mount point.  cvp is the covered vnode, and rvp is the root of
+ * the mounted file system.
+ */
+void
+cache_enter_mount(struct vnode *cvp, struct vnode *rvp)
+{
+
+       KASSERT(vrefcnt(cvp) > 0);
+       KASSERT(vrefcnt(rvp) > 0);
+       KASSERT(cvp->v_type == VDIR);
+       KASSERT((rvp->v_vflag & VV_ROOT) != 0);
+
+       if (rvp->v_type == VDIR) {
+               cache_enter(cvp, rvp, cache_mp_name, cache_mp_nlen, MAKEENTRY);
+       }
+}
+
+/*
+ * Look up a cached mount point.  Used in the strongly locked path.
+ */
+bool
+cache_lookup_mount(struct vnode *dvp, struct vnode **vn_ret)
+{
+       bool ret;
+
+       ret = cache_lookup(dvp, cache_mp_name, cache_mp_nlen, LOOKUP,
+           MAKEENTRY, NULL, vn_ret);
+       KASSERT((*vn_ret != NULL) == ret);
+       return ret;
+}
+
+/*
+ * Try to cross a mount point.  For use with cache_lookup_linked().
+ */
+bool
+cache_cross_mount(struct vnode **dvp, krwlock_t **plock)
+{
+
+       return cache_lookup_linked(*dvp, cache_mp_name, cache_mp_nlen,
+          dvp, plock, FSCRED);
+}
+
+/*
  * Name cache initialization, from vfs_init() when the system is booting.
  */
 void
diff -r b8f500b44268 -r d5d5ac3a771d sys/kern/vfs_lookup.c
--- a/sys/kern/vfs_lookup.c     Sat May 30 19:51:32 2020 +0000
+++ b/sys/kern/vfs_lookup.c     Sat May 30 20:16:14 2020 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: vfs_lookup.c,v 1.220 2020/05/26 18:38:37 ad Exp $      */
+/*     $NetBSD: vfs_lookup.c,v 1.221 2020/05/30 20:16:14 ad Exp $      */
 
 /*
  * Copyright (c) 1982, 1986, 1989, 1993
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.220 2020/05/26 18:38:37 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.221 2020/05/30 20:16:14 ad Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_magiclinks.h"
@@ -925,7 +925,7 @@
                  bool *searchdir_locked)
 {
        struct componentname *cnp = state->cnp;
-       struct vnode *foundobj;
+       struct vnode *foundobj, *vp;
        struct vnode *searchdir;
        struct mount *mp;
        int error, lktype;
@@ -954,38 +954,65 @@
            (mp = foundobj->v_mountedhere) != NULL &&
            (cnp->cn_flags & NOCROSSMOUNT) == 0) {
                KASSERTMSG(searchdir != foundobj, "same vn %p", searchdir);
+
                /*
-                * First get the vnode stable.  LK_SHARED works brilliantly
-                * here because almost nothing else wants to lock the
-                * covered vnode.
+                * Try the namecache first.  If that doesn't work, do
+                * it the hard way.
                 */
-               error = vn_lock(foundobj, LK_SHARED);
-               if (error != 0) {
+               if (cache_lookup_mount(foundobj, &vp)) {
                        vrele(foundobj);
-                       foundobj = NULL;
-                       break;
-               }
+                       foundobj = vp;
+               } else {
+                       /* First get the vnode stable. */
+                       error = vn_lock(foundobj, LK_SHARED);
+                       if (error != 0) {
+                               vrele(foundobj);
+                               foundobj = NULL;
+                               break;
+                       }
 
-               /* Then check to see if something is still mounted on it. */
-               if ((mp = foundobj->v_mountedhere) == NULL) {
+                       /* 
+                        * Check to see if something is still mounted on it.
+                        */
+                       if ((mp = foundobj->v_mountedhere) == NULL) {
+                               VOP_UNLOCK(foundobj);
+                               break;
+                       }
+
+                       /*
+                        * Get a reference to the mountpoint, and unlock
+                        * foundobj.
+                        */
+                       error = vfs_busy(mp);
                        VOP_UNLOCK(foundobj);
-                       break;
-               }
+                       if (error != 0) {
+                               vrele(foundobj);
+                               foundobj = NULL;
+                               break;
+                       }
+
+                       /*
+                        * Now get a reference on the root vnode.
+                        * XXX Future - maybe allow only VDIR here.
+                        */
+                       error = VFS_ROOT(mp, LK_NONE, &vp);
 
-               /* Get a reference to the mountpoint, and ditch foundobj. */
-               error = vfs_busy(mp);
-               vput(foundobj);
-               if (error != 0) {
-                       foundobj = NULL;
-                       break;
-               }
+                       /*
+                        * If successful, enter it into the cache while
+                        * holding the mount busy (competing with unmount).
+                        */
+                       if (error == 0) {
+                               cache_enter_mount(foundobj, vp);
+                       }
 
-               /* Now get a reference on the root vnode, and drop mount. */
-               error = VFS_ROOT(mp, LK_NONE, &foundobj);
-               vfs_unbusy(mp);
-               if (error) {
-                       foundobj = NULL;
-                       break;
+                       /* Finally, drop references to foundobj & mountpoint. */
+                       vrele(foundobj);
+                       vfs_unbusy(mp);
+                       if (error) {
+                               foundobj = NULL;
+                               break;
+                       }
+                       foundobj = vp;
                }
 
                /*
@@ -1261,6 +1288,7 @@
        int error, error2;
        size_t oldpathlen;
        const char *oldnameptr;
+       bool terminal;
 
        /*
         * Eat as many path name components as possible before giving up and
@@ -1271,6 +1299,7 @@
        searchdir = *searchdir_ret;
        oldnameptr = cnp->cn_nameptr;
        oldpathlen = ndp->ni_pathlen;
+       terminal = false;
        for (;;) {
                foundobj = NULL;
 
@@ -1304,7 +1333,8 @@
                /*
                 * Can't deal with last component when modifying; this needs
                 * searchdir locked and VOP_LOOKUP() called (which can and
-                * does modify state, despite the name).
+                * does modify state, despite the name).  NB: this case means
+                * terminal is never set true when LOCKPARENT.
                 */
                if ((cnp->cn_flags & ISLASTCN) != 0) {
                        if (cnp->cn_nameiop != LOOKUP ||
@@ -1338,26 +1368,61 @@
                                error = EOPNOTSUPP;
                        } else {
                                error = ENOENT;
+                               terminal = ((cnp->cn_flags & ISLASTCN) != 0);
+                       }
+                       break;
+               }
+
+               /*
+                * Stop and get a hold on the vnode if we've encountered
+                * something other than a dirctory.
+                */
+               if (foundobj->v_type != VDIR) {
+                       error = vcache_tryvget(foundobj);
+                       if (error != 0) {
+                               foundobj = NULL;
+                               error = EOPNOTSUPP;
                        }
                        break;
                }
 
                /*



Home | Main Index | Thread Index | Old Index