aboutsummaryrefslogtreecommitdiff
path: root/sys/kern/vfs_cache.c
diff options
context:
space:
mode:
authorRobert Watson <rwatson@FreeBSD.org>2009-04-07 20:58:56 +0000
committerRobert Watson <rwatson@FreeBSD.org>2009-04-07 20:58:56 +0000
commit5d5c17486910471f488d8e1bbf1eb936602b3eb2 (patch)
tree440852e08bc0b975f38a79744050d6f0989eaec9 /sys/kern/vfs_cache.c
parentec85f7fa3901b4af247e606c09614677557f57ae (diff)
downloadsrc-5d5c17486910471f488d8e1bbf1eb936602b3eb2.tar.gz
src-5d5c17486910471f488d8e1bbf1eb936602b3eb2.zip
Nul-terminate strings in the VFS name cache, which negligibly change
the size and cost of name cache entries, but make adding debugging and tracing easier. Add SDT DTrace probes for various namecache events: vfs:namecache:enter:done - new entry in the name cache, passed parent directory vnode pointer, name added to the cache, and child vnode pointer. vfs:namecache:enter_negative:done - new negative entry in the name cache, passed parent vnode pointer, name added to the cache. vfs:namecache:fullpath:enter - call to vn_fullpath1() is made, passed the vnode to resolve to a name. vfs:namecache:fullpath:hit - vn_fullpath1() successfully resolved a search for the parent of an object using the namecache, passed the discovered parent directory vnode pointer, name, and child vnode pointer. vfs:namecache:fullpath:miss - vn_fullpath1() failed to resolve a search for the parent of an object using the namecache, passed the child vnode pointer. vfs:namecache:fullpath:return - vn_fullpath1() has completed, passed the error number, and if that is zero, the vnode to resolve, and the returned path. vfs:namecache:lookup:hit - postive name cache entry hit, passed the parent directory vnode pointer, name, and child vnode pointer. vfs:namecache:lookup:hit_negative - negative name cache entry hit, passed the parent directory vnode pointer and name. vfs:namecache:lookup:miss - name cache miss, passed the parent directory pointer and the full remaining component name (not terminated after the cache miss component). vfs:namecache:purge:done - name cache purge for a vnode, passed the vnode pointer to purge. vfs:namecache:purge_negative:done - name cache purge of negative entries for children of a vnode, passed the vnode pointer to purge. vfs:namecache:purgevfs - name cache purge for a mountpoint, passed the mount pointer. Separate probes will also be invoked for each cache entry zapped. vfs:namecache:zap:done - name cache entry zapped, passed the parent directory vnode pointer, name, and child vnode pointer. vfs:namecache:zap_negative:done - negative name cache entry zapped, passed the parent directory vnode pointer and name. For any probes involving an extant name cache entry (enter, hit, zapp), we use the nul-terminated string for the name component. For misses, the remainder of the path, including later components, is provided as an argument instead since there is no handy nul-terminated version of the string around. This is arguably a bug. MFC after: 1 month Sponsored by: Google, Inc. Reviewed by: jhb, kan, kib (earlier version)
Notes
Notes: svn path=/head/; revision=190829
Diffstat (limited to 'sys/kern/vfs_cache.c')
-rw-r--r--sys/kern/vfs_cache.c106
1 files changed, 96 insertions, 10 deletions
diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c
index 6427f652e842..49eccdd0e2f7 100644
--- a/sys/kern/vfs_cache.c
+++ b/sys/kern/vfs_cache.c
@@ -35,6 +35,7 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include "opt_kdtrace.h"
#include "opt_ktrace.h"
#include <sys/param.h>
@@ -47,6 +48,7 @@ __FBSDID("$FreeBSD$");
#include <sys/namei.h>
#include <sys/proc.h>
#include <sys/rwlock.h>
+#include <sys/sdt.h>
#include <sys/syscallsubr.h>
#include <sys/sysctl.h>
#include <sys/sysproto.h>
@@ -58,6 +60,31 @@ __FBSDID("$FreeBSD$");
#include <vm/uma.h>
+SDT_PROVIDER_DECLARE(vfs);
+SDT_PROBE_DEFINE3(vfs, namecache, enter, done, "struct vnode *", "char *",
+ "struct vnode *");
+SDT_PROBE_DEFINE2(vfs, namecache, enter_negative, done, "struct vnode *",
+ "char *");
+SDT_PROBE_DEFINE1(vfs, namecache, fullpath, entry, "struct vnode *");
+SDT_PROBE_DEFINE3(vfs, namecache, fullpath, hit, "struct vnode *",
+ "struct char *", "struct vnode *");
+SDT_PROBE_DEFINE1(vfs, namecache, fullpath, miss, "struct vnode *");
+SDT_PROBE_DEFINE3(vfs, namecache, fullpath, return, "int", "struct vnode *",
+ "struct char *");
+SDT_PROBE_DEFINE3(vfs, namecache, lookup, hit, "struct vnode *", "char *",
+ "struct vnode *");
+SDT_PROBE_DEFINE2(vfs, namecache, lookup, hit_negative, "struct vnode *",
+ "char *");
+SDT_PROBE_DEFINE2(vfs, namecache, lookup, miss, "struct vnode *",
+ "char *");
+SDT_PROBE_DEFINE1(vfs, namecache, purge, done, "struct vnode *");
+SDT_PROBE_DEFINE1(vfs, namecache, purge_negative, done, "struct vnode *");
+SDT_PROBE_DEFINE1(vfs, namecache, purgevfs, done, "struct mount *");
+SDT_PROBE_DEFINE3(vfs, namecache, zap, done, "struct vnode *", "char *",
+ "struct vnode *");
+SDT_PROBE_DEFINE2(vfs, namecache, zap_negative, done, "struct vnode *",
+ "char *");
+
/*
* This structure describes the elements in the cache of recent
* names looked up by namei.
@@ -71,7 +98,7 @@ struct namecache {
struct vnode *nc_vp; /* vnode the name refers to */
u_char nc_flag; /* flag bits */
u_char nc_nlen; /* length of name */
- char nc_name[0]; /* segment name */
+ char nc_name[0]; /* segment name + nul */
};
/*
@@ -133,9 +160,10 @@ RW_SYSINIT(vfscache, &cache_lock, "Name Cache");
static uma_zone_t cache_zone_small;
static uma_zone_t cache_zone_large;
-#define CACHE_PATH_CUTOFF 32
-#define CACHE_ZONE_SMALL (sizeof(struct namecache) + CACHE_PATH_CUTOFF)
-#define CACHE_ZONE_LARGE (sizeof(struct namecache) + NAME_MAX)
+#define CACHE_PATH_CUTOFF 35
+#define CACHE_ZONE_SMALL (sizeof(struct namecache) + CACHE_PATH_CUTOFF \
+ + 1)
+#define CACHE_ZONE_LARGE (sizeof(struct namecache) + NAME_MAX + 1)
#define cache_alloc(len) uma_zalloc(((len) <= CACHE_PATH_CUTOFF) ? \
cache_zone_small : cache_zone_large, M_WAITOK)
@@ -291,6 +319,15 @@ cache_zap(ncp)
rw_assert(&cache_lock, RA_WLOCKED);
CTR2(KTR_VFS, "cache_zap(%p) vp %p", ncp, ncp->nc_vp);
+#ifdef KDTRACE_HOOKS
+ if (ncp->nc_vp != NULL) {
+ SDT_PROBE(vfs, namecache, zap, done, ncp->nc_dvp,
+ ncp->nc_name, ncp->nc_vp, 0, 0);
+ } else {
+ SDT_PROBE(vfs, namecache, zap_negative, done, ncp->nc_dvp,
+ ncp->nc_name, 0, 0, 0);
+ }
+#endif
vp = NULL;
LIST_REMOVE(ncp, nc_hash);
if (ncp->nc_flag & NCF_ISDOTDOT) {
@@ -361,12 +398,17 @@ retry_wlocked:
CTR2(KTR_VFS, "cache_lookup(%p, %s) found via .",
dvp, cnp->cn_nameptr);
dothits++;
+ SDT_PROBE(vfs, namecache, lookup, hit, dvp, ".",
+ *vpp, 0, 0);
goto success;
}
if (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.') {
dotdothits++;
- if (dvp->v_cache_dd == NULL)
+ if (dvp->v_cache_dd == NULL) {
+ SDT_PROBE(vfs, namecache, lookup, miss, dvp,
+ "..", NULL, 0, 0);
goto unlock;
+ }
if ((cnp->cn_flags & MAKEENTRY) == 0) {
if (dvp->v_cache_dd->nc_flag & NCF_ISDOTDOT)
cache_zap(dvp->v_cache_dd);
@@ -379,6 +421,8 @@ retry_wlocked:
*vpp = dvp->v_cache_dd->nc_dvp;
CTR3(KTR_VFS, "cache_lookup(%p, %s) found %p via ..",
dvp, cnp->cn_nameptr, *vpp);
+ SDT_PROBE(vfs, namecache, lookup, hit, dvp, "..",
+ *vpp, 0, 0);
goto success;
}
}
@@ -394,6 +438,8 @@ retry_wlocked:
/* We failed to find an entry */
if (ncp == NULL) {
+ SDT_PROBE(vfs, namecache, lookup, miss, dvp, cnp->cn_nameptr,
+ NULL, 0, 0);
if ((cnp->cn_flags & MAKEENTRY) == 0) {
nummisszap++;
} else {
@@ -421,6 +467,8 @@ retry_wlocked:
*vpp = ncp->nc_vp;
CTR4(KTR_VFS, "cache_lookup(%p, %s) found %p via ncp %p",
dvp, cnp->cn_nameptr, *vpp, ncp);
+ SDT_PROBE(vfs, namecache, lookup, hit, dvp, ncp->nc_name,
+ *vpp, 0, 0);
goto success;
}
@@ -449,6 +497,8 @@ retry_wlocked:
nchstats.ncs_neghits++;
if (ncp->nc_flag & NCF_WHITE)
cnp->cn_flags |= ISWHITEOUT;
+ SDT_PROBE(vfs, namecache, lookup, hit_negative, dvp, ncp->nc_name,
+ 0, 0, 0);
CACHE_WUNLOCK();
return (ENOENT);
@@ -579,6 +629,8 @@ cache_enter(dvp, vp, cnp)
}
}
dvp->v_cache_dd = NULL;
+ SDT_PROBE(vfs, namecache, enter, done, dvp, "..", vp,
+ 0, 0);
CACHE_WUNLOCK();
flag = NCF_ISDOTDOT;
}
@@ -597,7 +649,7 @@ cache_enter(dvp, vp, cnp)
ncp->nc_flag = flag;
len = ncp->nc_nlen = cnp->cn_namelen;
hash = fnv_32_buf(cnp->cn_nameptr, len, FNV1_32_INIT);
- bcopy(cnp->cn_nameptr, ncp->nc_name, len);
+ strlcpy(ncp->nc_name, cnp->cn_nameptr, len + 1);
hash = fnv_32_buf(&dvp, sizeof(dvp), hash);
CACHE_WLOCK();
@@ -667,8 +719,12 @@ cache_enter(dvp, vp, cnp)
*/
if (vp) {
TAILQ_INSERT_HEAD(&vp->v_cache_dst, ncp, nc_dst);
+ SDT_PROBE(vfs, namecache, enter, done, dvp, ncp->nc_name, vp,
+ 0, 0);
} else {
TAILQ_INSERT_TAIL(&ncneg, ncp, nc_dst);
+ SDT_PROBE(vfs, namecache, enter_negative, done, dvp,
+ ncp->nc_name, 0, 0, 0);
}
if (numneg * ncnegfactor > numcache) {
ncp = TAILQ_FIRST(&ncneg);
@@ -709,6 +765,7 @@ cache_purge(vp)
{
CTR1(KTR_VFS, "cache_purge(%p)", vp);
+ SDT_PROBE(vfs, namecache, purge, done, vp, 0, 0, 0, 0);
CACHE_WLOCK();
while (!LIST_EMPTY(&vp->v_cache_src))
cache_zap(LIST_FIRST(&vp->v_cache_src));
@@ -733,6 +790,7 @@ cache_purge_negative(vp)
struct namecache *cp, *ncp;
CTR1(KTR_VFS, "cache_purge_negative(%p)", vp);
+ SDT_PROBE(vfs, namecache, purge_negative, done, vp, 0, 0, 0, 0);
CACHE_WLOCK();
LIST_FOREACH_SAFE(cp, &vp->v_cache_src, nc_src, ncp) {
if (cp->nc_vp == NULL)
@@ -752,6 +810,7 @@ cache_purgevfs(mp)
struct namecache *ncp, *nnp;
/* Scan hash tables for applicable entries */
+ SDT_PROBE(vfs, namecache, purgevfs, done, mp, 0, 0, 0, 0);
CACHE_WLOCK();
for (ncpp = &nchashtbl[nchash]; ncpp >= nchashtbl; ncpp--) {
LIST_FOREACH_SAFE(ncp, ncpp, nc_hash, nnp) {
@@ -998,6 +1057,9 @@ vn_fullpath1(struct thread *td, struct vnode *vp, struct vnode *rdir,
char *bp;
int error, i, slash_prefixed;
struct namecache *ncp;
+#ifdef KDTRACE_HOOKS
+ struct vnode *startvp = vp;
+#endif
buflen--;
bp = buf + buflen;
@@ -1005,6 +1067,7 @@ vn_fullpath1(struct thread *td, struct vnode *vp, struct vnode *rdir,
error = 0;
slash_prefixed = 0;
+ SDT_PROBE(vfs, namecache, fullpath, entry, vp, 0, 0, 0, 0);
CACHE_RLOCK();
numfullpathcalls++;
if (vp->v_type != VDIR) {
@@ -1016,18 +1079,31 @@ vn_fullpath1(struct thread *td, struct vnode *vp, struct vnode *rdir,
if (bp == buf) {
numfullpathfail4++;
CACHE_RUNLOCK();
- return (ENOMEM);
+ error = ENOMEM;
+ SDT_PROBE(vfs, namecache, fullpath, return,
+ error, startvp, NULL, 0, 0);
+ return (error);
}
+ SDT_PROBE(vfs, namecache, fullpath, hit, ncp->nc_dvp,
+ ncp->nc_name, vp, 0, 0);
vp = ncp->nc_dvp;
} else {
+ SDT_PROBE(vfs, namecache, fullpath, miss, vp, 0, 0,
+ 0, 0);
error = vn_vptocnp(&vp, &bp, buf, &buflen);
- if (error)
+ if (error) {
+ SDT_PROBE(vfs, namecache, fullpath, return,
+ error, startvp, NULL, 0, 0);
return (error);
+ }
}
if (buflen <= 0) {
numfullpathfail4++;
CACHE_RUNLOCK();
- return (ENOMEM);
+ error = ENOMEM;
+ SDT_PROBE(vfs, namecache, fullpath, return, error,
+ startvp, NULL, 0, 0);
+ return (error);
}
*--bp = '/';
buflen--;
@@ -1062,8 +1138,12 @@ vn_fullpath1(struct thread *td, struct vnode *vp, struct vnode *rdir,
error = ENOMEM;
break;
}
+ SDT_PROBE(vfs, namecache, fullpath, hit, ncp->nc_dvp,
+ ncp->nc_name, vp, 0, 0);
vp = ncp->nc_dvp;
} else {
+ SDT_PROBE(vfs, namecache, fullpath, miss, vp, 0, 0,
+ 0, 0);
error = vn_vptocnp(&vp, &bp, buf, &buflen);
if (error)
break;
@@ -1078,12 +1158,17 @@ vn_fullpath1(struct thread *td, struct vnode *vp, struct vnode *rdir,
buflen--;
slash_prefixed = 1;
}
- if (error)
+ if (error) {
+ SDT_PROBE(vfs, namecache, fullpath, return, error, startvp,
+ NULL, 0, 0);
return (error);
+ }
if (!slash_prefixed) {
if (bp == buf) {
numfullpathfail4++;
CACHE_RUNLOCK();
+ SDT_PROBE(vfs, namecache, fullpath, return, 0,
+ startvp, bp, 0, 0);
return (ENOMEM);
} else
*--bp = '/';
@@ -1091,6 +1176,7 @@ vn_fullpath1(struct thread *td, struct vnode *vp, struct vnode *rdir,
numfullpathfound++;
CACHE_RUNLOCK();
+ SDT_PROBE(vfs, namecache, fullpath, return, 0, startvp, bp, 0, 0);
*retbuf = bp;
return (0);
}