Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F121061
diffs
All Users
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
mckusick
Apr 13 2015, 5:42 AM
2015-04-13 05:42:20 (UTC+0)
Size
6 KB
Referenced Files
None
Subscribers
None
diffs
View Options
Index: kern/vfs_hash.c
===================================================================
--- kern/vfs_hash.c (revision 281469)
+++ kern/vfs_hash.c (working copy)
@@ -161,3 +161,39 @@
vp->v_hash = hash;
rw_wunlock(&vfs_hash_lock);
}
+
+void
+vfs_hash_changesize(int newhashsize)
+{
+ struct vfs_hash_head *vfs_hash_newtbl, *vfs_hash_oldtbl;
+ u_long vfs_hash_newmask, vfs_hash_oldmask;
+ struct vnode *vp;
+ int i;
+
+ vfs_hash_newtbl = hashinit(newhashsize, M_VFS_HASH, &vfs_hash_newmask);
+ /* If same hash table size, nothing to do */
+ if (vfs_hash_mask == vfs_hash_newmask) {
+ free(vfs_hash_newtbl, M_VFS_HASH);
+ return;
+ }
+ /*
+ * Move everything from the old hash table to the new table.
+ * None of the vnodes in the table can be recycled because to
+ * do so, they have to be removed from the hash table.
+ */
+ rw_wlock(&vfs_hash_lock);
+ vfs_hash_oldtbl = vfs_hash_tbl;
+ vfs_hash_oldmask = vfs_hash_mask;
+ vfs_hash_tbl = vfs_hash_newtbl;
+ vfs_hash_mask = vfs_hash_newmask;
+ for (i = 0; i <= vfs_hash_oldmask; i++) {
+ while ((vp = LIST_FIRST(&vfs_hash_oldtbl[i])) != NULL) {
+ LIST_REMOVE(vp, v_hashlist);
+ LIST_INSERT_HEAD(
+ vfs_hash_bucket(vp->v_mount, vp->v_hash),
+ vp, v_hashlist);
+ }
+ }
+ rw_wunlock(&vfs_hash_lock);
+ free(vfs_hash_oldtbl, M_VFS_HASH);
+}
Index: kern/vfs_cache.c
===================================================================
--- kern/vfs_cache.c (revision 281469)
+++ kern/vfs_cache.c (working copy)
@@ -96,6 +96,7 @@
TAILQ_ENTRY(namecache) nc_dst; /* destination vnode list */
struct vnode *nc_dvp; /* vnode of parent of name */
struct vnode *nc_vp; /* vnode the name refers to */
+ u_long nc_hashval; /* hash value used for hasing list */
u_char nc_flag; /* flag bits */
u_char nc_nlen; /* length of name */
char nc_name[0]; /* segment name + nul */
@@ -115,6 +116,7 @@
TAILQ_ENTRY(namecache) nc_dst; /* destination vnode list */
struct vnode *nc_dvp; /* vnode of parent of name */
struct vnode *nc_vp; /* vnode the name refers to */
+ u_long nc_hashval; /* hash value used for hasing list */
u_char nc_flag; /* flag bits */
u_char nc_nlen; /* length of name */
struct timespec nc_time; /* timespec provided by fs */
@@ -324,7 +326,7 @@
sysctl_debug_hashstat_rawnchash(SYSCTL_HANDLER_ARGS)
{
int error;
- struct nchashhead *ncpp;
+ struct nchashhead *ncpp, starthashtbl;
struct namecache *ncp;
int n_nchash;
int count;
@@ -334,8 +336,14 @@
return SYSCTL_OUT(req, 0, n_nchash * sizeof(int));
/* Scan hash tables for applicable entries */
+ starthashtbl = nchashtbl;
for (ncpp = nchashtbl; n_nchash > 0; n_nchash--, ncpp++) {
CACHE_RLOCK();
+ /* If the hash table gets replaced, give up */
+ if (starthashtbl != nchashtbl) {
+ CACHE_RUNLOCK();
+ return (EAGAIN);
+ }
count = 0;
LIST_FOREACH(ncp, ncpp, nc_hash) {
count++;
@@ -363,6 +371,7 @@
if (!req->oldptr)
return SYSCTL_OUT(req, 0, 4 * sizeof(int));
+ CACHE_RLOCK();
n_nchash = nchash + 1; /* nchash is max index, not count */
used = 0;
maxlength = 0;
@@ -370,17 +379,16 @@
/* Scan hash tables for applicable entries */
for (ncpp = nchashtbl; n_nchash > 0; n_nchash--, ncpp++) {
count = 0;
- CACHE_RLOCK();
LIST_FOREACH(ncp, ncpp, nc_hash) {
count++;
}
- CACHE_RUNLOCK();
if (count)
used++;
if (maxlength < count)
maxlength = count;
}
n_nchash = nchash + 1;
+ CACHE_RUNLOCK();
pct = (used * 100) / (n_nchash / 100);
error = SYSCTL_OUT(req, &n_nchash, sizeof(n_nchash));
if (error)
@@ -872,6 +880,7 @@
* Insert the new namecache entry into the appropriate chain
* within the cache entries table.
*/
+ ncp->nc_hashval = hash;
LIST_INSERT_HEAD(ncpp, ncp, nc_hash);
if (flag != NCF_ISDOTDOT) {
if (LIST_EMPTY(&dvp->v_cache_src)) {
@@ -934,7 +943,41 @@
}
SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_SECOND, nchinit, NULL);
+void
+cache_changesize(int newhashsize)
+{
+ struct nchashhead *new_nchashtbl, *old_nchashtbl;
+ u_long new_nchash, old_nchash;
+ struct namecache *ncp;
+ int i;
+ new_nchashtbl = hashinit(newhashsize, 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) {
+ LIST_REMOVE(ncp, nc_hash);
+ LIST_INSERT_HEAD(NCHHASH(ncp->nc_hashval), ncp,
+ nc_hash);
+ }
+ }
+ CACHE_WUNLOCK();
+ free(old_nchashtbl, M_VFSCACHE);
+}
+
/*
* Invalidate all entries to a particular vnode.
*/
Index: kern/vfs_subr.c
===================================================================
--- kern/vfs_subr.c (revision 281469)
+++ kern/vfs_subr.c (working copy)
@@ -275,8 +275,22 @@
* XXX desiredvnodes is historical cruft and should not exist.
*/
int desiredvnodes;
-SYSCTL_INT(_kern, KERN_MAXVNODES, maxvnodes, CTLFLAG_RW,
- &desiredvnodes, 0, "Maximum number of vnodes");
+
+static int
+sysctl_update_desiredvnodes(SYSCTL_HANDLER_ARGS)
+{
+ int error;
+
+ if ((error = sysctl_handle_int(oidp, arg1, arg2, req)) != 0)
+ return (error);
+ vfs_hash_changesize(desiredvnodes);
+ cache_changesize(desiredvnodes);
+ return (0);
+}
+
+SYSCTL_PROC(_kern, KERN_MAXVNODES, maxvnodes,
+ CTLTYPE_INT | CTLFLAG_MPSAFE | CTLFLAG_RW, &desiredvnodes, 0,
+ sysctl_update_desiredvnodes, "I", "Maximum number of vnodes");
SYSCTL_ULONG(_kern, OID_AUTO, minvnodes, CTLFLAG_RW,
&wantfreevnodes, 0, "Minimum number of vnodes (legacy)");
static int vnlru_nowhere;
Index: sys/vnode.h
===================================================================
--- sys/vnode.h (revision 281469)
+++ sys/vnode.h (working copy)
@@ -602,6 +602,7 @@
typedef int (*vn_get_ino_t)(struct mount *, void *, int, struct vnode **);
/* cache_* may belong in namei.h. */
+void cache_changesize(int newhashsize);
#define cache_enter(dvp, vp, cnp) \
cache_enter_time(dvp, vp, cnp, NULL, NULL)
void cache_enter_time(struct vnode *dvp, struct vnode *vp,
@@ -838,6 +839,7 @@
/* vfs_hash.c */
typedef int vfs_hash_cmp_t(struct vnode *vp, void *arg);
+void vfs_hash_changesize(int newhashsize);
int vfs_hash_get(const struct mount *mp, u_int hash, int flags, struct thread *td, struct vnode **vpp, vfs_hash_cmp_t *fn, void *arg);
u_int vfs_hash_index(struct vnode *vp);
int vfs_hash_insert(struct vnode *vp, u_int hash, int flags, struct thread *td, struct vnode **vpp, vfs_hash_cmp_t *fn, void *arg);
File Metadata
Details
Attached
Mime Type
text/x-diff
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
120880
Default Alt Text
diffs (6 KB)
Attached To
Mode
D2265: kern.maxvnodes should be a tunable, and probably shouldn't be run-time modifiable
Attached
Detach File
Event Timeline
Log In to Comment