diff options
author | mckusick <mckusick@FreeBSD.org> | 2015-09-22 00:43:05 +0000 |
---|---|---|
committer | mckusick <mckusick@FreeBSD.org> | 2015-09-22 00:43:05 +0000 |
commit | 198203431a0911024c97644b46a23e46215c26cd (patch) | |
tree | 67df2a0e32a73c0beb0b999eafad85e89cae31e4 /sys/kern/vfs_cache.c | |
parent | d91e3630bbbd2abb94422dfd294a62526d4f7d63 (diff) | |
download | FreeBSD-src-198203431a0911024c97644b46a23e46215c26cd.zip FreeBSD-src-198203431a0911024c97644b46a23e46215c26cd.tar.gz |
MFC of 281677:
More accurately collect name-cache statistics in sysctl functions
sysctl_debug_hashstat_nchash() and sysctl_debug_hashstat_rawnchash().
These changes are in preparation for allowing changes in the size
of the vnode hash tables driven by increases and decreases in the
maximum number of vnodes in the system.
Reviewed by: kib@
Phabric: D2265
MFC of 287497:
Track changes to kern.maxvnodes and appropriately increase or decrease
the size of the name cache hash table (mapping file names to vnodes)
and the vnode hash table (mapping mount point and inode number to vnode).
An appropriate locking strategy is the key to changing hash table sizes
while they are in active use.
Reviewed by: kib
Tested by: Peter Holm
Differential Revision: https://reviews.freebsd.org/D2265
Diffstat (limited to 'sys/kern/vfs_cache.c')
-rw-r--r-- | sys/kern/vfs_cache.c | 66 |
1 files changed, 54 insertions, 12 deletions
diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c index 17f72a7..48f7550 100644 --- a/sys/kern/vfs_cache.c +++ b/sys/kern/vfs_cache.c @@ -330,23 +330,27 @@ sysctl_debug_hashstat_rawnchash(SYSCTL_HANDLER_ARGS) int n_nchash; int count; +retry: n_nchash = nchash + 1; /* nchash is max index, not count */ if (!req->oldptr) return SYSCTL_OUT(req, 0, n_nchash * sizeof(int)); - - /* Scan hash tables for applicable entries */ - for (ncpp = nchashtbl; n_nchash > 0; n_nchash--, ncpp++) { - CACHE_RLOCK(); - count = 0; - LIST_FOREACH(ncp, ncpp, nc_hash) { - count++; - } + cntbuf = malloc(n_nchash * sizeof(int), M_TEMP, M_ZERO | M_WAITOK); + CACHE_RLOCK(); + if (n_nchash != nchash + 1) { CACHE_RUNLOCK(); - error = SYSCTL_OUT(req, &count, sizeof(count)); - if (error) - return (error); + free(cntbuf, M_TEMP); + goto retry; } - return (0); + /* Scan hash tables counting entries */ + for (ncpp = nchashtbl, i = 0; i < n_nchash; ncpp++, i++) + LIST_FOREACH(ncp, ncpp, nc_hash) + cntbuf[i]++; + CACHE_RUNLOCK(); + for (error = 0, i = 0; i < n_nchash; i++) + if ((error = SYSCTL_OUT(req, &cntbuf[i], sizeof(int))) != 0) + break; + free(cntbuf, M_TEMP); + return (error); } SYSCTL_PROC(_debug_hashstat, OID_AUTO, rawnchash, CTLTYPE_INT|CTLFLAG_RD| CTLFLAG_MPSAFE, 0, 0, sysctl_debug_hashstat_rawnchash, "S,int", @@ -935,6 +939,44 @@ nchinit(void *dummy __unused) } SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_SECOND, nchinit, NULL); +void +cache_changesize(int newmaxvnodes) +{ + struct nchashhead *new_nchashtbl, *old_nchashtbl; + u_long new_nchash, old_nchash; + struct namecache *ncp; + uint32_t hash; + int i; + + new_nchashtbl = hashinit(newmaxvnodes * 2, M_VFSCACHE, &new_nchash); + /* If same hash table size, nothing to do */ + if (nchash == new_nchash) { + free(new_nchashtbl, M_VFSCACHE); + return; + } + /* + * Move everything from the old hash table to the new table. + * None of the namecache entries in the table can be removed + * because to do so, they have to be removed from the hash table. + */ + CACHE_WLOCK(); + old_nchashtbl = nchashtbl; + old_nchash = nchash; + nchashtbl = new_nchashtbl; + nchash = new_nchash; + for (i = 0; i <= old_nchash; i++) { + while ((ncp = LIST_FIRST(&old_nchashtbl[i])) != NULL) { + hash = fnv_32_buf(nc_get_name(ncp), ncp->nc_nlen, + FNV1_32_INIT); + hash = fnv_32_buf(&ncp->nc_dvp, sizeof(ncp->nc_dvp), + hash); + LIST_REMOVE(ncp, nc_hash); + LIST_INSERT_HEAD(NCHHASH(hash), ncp, nc_hash); + } + } + CACHE_WUNLOCK(); + free(old_nchashtbl, M_VFSCACHE); +} /* * Invalidate all entries to a particular vnode. |