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/ae9f2da35103
branches: trunk
changeset: 1010618:ae9f2da35103
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 677a318bbd68 -r ae9f2da35103 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 677a318bbd68 -r ae9f2da35103 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