Reclaim directory vnodes held in namecache if few free vnodes are

available.

Only directory vnodes holding no child directory vnodes held in
v_cache_src are recycled, so that directory vnodes near the root of
the filesystem hierarchy remain in namecache and directory vnodes are
not reclaimed in cascade.

The period of vnode reclaiming attempt and the number of vnodes
attempted to reclaim can be tuned via sysctl(2).

Suggested by:	tegge
Approved by:	phk
This commit is contained in:
Seigo Tanimura 2001-04-18 11:19:50 +00:00
parent 5c76ec115f
commit 759cb26335
4 changed files with 119 additions and 2 deletions

View File

@ -98,6 +98,10 @@ static u_long numneg; /* number of cache entries allocated */
SYSCTL_ULONG(_debug, OID_AUTO, numneg, CTLFLAG_RD, &numneg, 0, "");
static u_long numcache; /* number of cache entries allocated */
SYSCTL_ULONG(_debug, OID_AUTO, numcache, CTLFLAG_RD, &numcache, 0, "");
static u_long numcachehv; /* number of cache entries with vnodes held */
SYSCTL_ULONG(_debug, OID_AUTO, numcachehv, CTLFLAG_RD, &numcachehv, 0, "");
static u_long numcachepl; /* number of cache purge for leaf entries */
SYSCTL_ULONG(_debug, OID_AUTO, numcachepl, CTLFLAG_RD, &numcachepl, 0, "");
struct nchstats nchstats; /* cache effectiveness statistics */
static int doingcache = 1; /* 1 => enable the cache */
@ -227,8 +231,10 @@ cache_zap(ncp)
{
LIST_REMOVE(ncp, nc_hash);
LIST_REMOVE(ncp, nc_src);
if (LIST_EMPTY(&ncp->nc_dvp->v_cache_src))
if (LIST_EMPTY(&ncp->nc_dvp->v_cache_src)) {
vdrop(ncp->nc_dvp);
numcachehv--;
}
if (ncp->nc_vp) {
TAILQ_REMOVE(&ncp->nc_vp->v_cache_dst, ncp, nc_dst);
} else {
@ -404,8 +410,10 @@ cache_enter(dvp, vp, cnp)
hash = fnv_32_buf(&dvp->v_id, sizeof(dvp->v_id), hash);
ncpp = NCHHASH(hash);
LIST_INSERT_HEAD(ncpp, ncp, nc_hash);
if (LIST_EMPTY(&dvp->v_cache_src))
if (LIST_EMPTY(&dvp->v_cache_src)) {
vhold(dvp);
numcachehv++;
}
LIST_INSERT_HEAD(&dvp->v_cache_src, ncp, nc_src);
if (vp) {
TAILQ_INSERT_HEAD(&vp->v_cache_dst, ncp, nc_dst);
@ -490,6 +498,62 @@ cache_purgevfs(mp)
}
}
/*
* Flush all dirctory entries with no child directories held in
* the cache.
*
* Since we need to check it anyway, we will flush all the invalid
* entries at the same time.
*/
void
cache_purgeleafdirs(ndir)
int ndir;
{
struct nchashhead *ncpp;
struct namecache *ncp, *nnp, *ncpc, *nnpc;
struct vnode *dvp;
/* Scan hash tables for applicable entries */
for (ncpp = &nchashtbl[nchash]; ncpp >= nchashtbl && ndir > 0; ncpp--) {
for (ncp = LIST_FIRST(ncpp); ncp != 0 && ndir > 0; ncp = nnp) {
nnp = LIST_NEXT(ncp, nc_hash);
if (ncp->nc_dvp != 0) {
/*
* Skip over if nc_dvp of this cache holds
* a child directory, or the hold count of
* nc_dvp is greater than 1 (in which case
* nc_dvp is likely to be the working
* directory of a process).
*/
if (ncp->nc_dvp->v_holdcnt > 1)
continue;
for (ncpc = LIST_FIRST(&ncp->nc_dvp->v_cache_src);
ncpc != 0; ncpc = nnpc) {
nnpc = LIST_NEXT(ncpc, nc_src);
if (ncpc->nc_vp != 0 && ncpc->nc_vp->v_type == VDIR)
break;
}
if (ncpc == 0) {
/*
* Zap all of this directory's children,
* held in ncp->nc_dvp->v_cache_src.
*/
dvp = ncp->nc_dvp;
while (!LIST_EMPTY(&dvp->v_cache_src))
cache_zap(LIST_FIRST(&dvp->v_cache_src));
ndir--;
/* Restart in case where nnp is reclaimed. */
nnp = LIST_FIRST(ncpp);
continue;
}
}
}
}
numcachepl++;
}
/*
* Perform canonical checks and cache lookup and pass on to filesystem
* through the vop_cachedlookup only if needed.

View File

@ -122,6 +122,21 @@ SYSCTL_LONG(_debug, OID_AUTO, wantfreevnodes, CTLFLAG_RW, &wantfreevnodes, 0, ""
/* Number of vnodes in the free list. */
static u_long freevnodes = 0;
SYSCTL_LONG(_debug, OID_AUTO, freevnodes, CTLFLAG_RD, &freevnodes, 0, "");
/* Number of vnode allocation. */
static u_long vnodeallocs = 0;
SYSCTL_LONG(_debug, OID_AUTO, vnodeallocs, CTLFLAG_RD, &vnodeallocs, 0, "");
/* Period of vnode recycle from namecache in vnode allocation times. */
static u_long vnoderecycleperiod = 1000;
SYSCTL_LONG(_debug, OID_AUTO, vnoderecycleperiod, CTLFLAG_RW, &vnoderecycleperiod, 0, "");
/* Minimum number of total vnodes required to invoke vnode recycle from namecache. */
static u_long vnoderecyclemintotalvn = 2000;
SYSCTL_LONG(_debug, OID_AUTO, vnoderecyclemintotalvn, CTLFLAG_RW, &vnoderecyclemintotalvn, 0, "");
/* Minimum number of free vnodes required to invoke vnode recycle from namecache. */
static u_long vnoderecycleminfreevn = 2000;
SYSCTL_LONG(_debug, OID_AUTO, vnoderecycleminfreevn, CTLFLAG_RW, &vnoderecycleminfreevn, 0, "");
/* Number of vnodes attempted to recycle at a time. */
static u_long vnoderecyclenumber = 3000;
SYSCTL_LONG(_debug, OID_AUTO, vnoderecyclenumber, CTLFLAG_RW, &vnoderecyclenumber, 0, "");
/*
* Various variables used for debugging the new implementation of
@ -553,6 +568,7 @@ getnewvnode(tag, mp, vops, vpp)
if (vp == NULL || vp->v_usecount)
panic("getnewvnode: free vnode isn't");
TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);
/*
* Don't recycle if active in the namecache or
* if it still has cached pages or we cannot get
@ -632,9 +648,19 @@ getnewvnode(tag, mp, vops, vpp)
*vpp = vp;
vp->v_usecount = 1;
vp->v_data = 0;
splx(s);
vfs_object_create(vp, p, p->p_ucred);
vnodeallocs++;
if (vnodeallocs % vnoderecycleperiod == 0 &&
freevnodes < vnoderecycleminfreevn &&
vnoderecyclemintotalvn < numvnodes) {
/* Recycle vnodes. */
cache_purgeleafdirs(vnoderecyclenumber);
}
return (0);
}

View File

@ -122,6 +122,21 @@ SYSCTL_LONG(_debug, OID_AUTO, wantfreevnodes, CTLFLAG_RW, &wantfreevnodes, 0, ""
/* Number of vnodes in the free list. */
static u_long freevnodes = 0;
SYSCTL_LONG(_debug, OID_AUTO, freevnodes, CTLFLAG_RD, &freevnodes, 0, "");
/* Number of vnode allocation. */
static u_long vnodeallocs = 0;
SYSCTL_LONG(_debug, OID_AUTO, vnodeallocs, CTLFLAG_RD, &vnodeallocs, 0, "");
/* Period of vnode recycle from namecache in vnode allocation times. */
static u_long vnoderecycleperiod = 1000;
SYSCTL_LONG(_debug, OID_AUTO, vnoderecycleperiod, CTLFLAG_RW, &vnoderecycleperiod, 0, "");
/* Minimum number of total vnodes required to invoke vnode recycle from namecache. */
static u_long vnoderecyclemintotalvn = 2000;
SYSCTL_LONG(_debug, OID_AUTO, vnoderecyclemintotalvn, CTLFLAG_RW, &vnoderecyclemintotalvn, 0, "");
/* Minimum number of free vnodes required to invoke vnode recycle from namecache. */
static u_long vnoderecycleminfreevn = 2000;
SYSCTL_LONG(_debug, OID_AUTO, vnoderecycleminfreevn, CTLFLAG_RW, &vnoderecycleminfreevn, 0, "");
/* Number of vnodes attempted to recycle at a time. */
static u_long vnoderecyclenumber = 3000;
SYSCTL_LONG(_debug, OID_AUTO, vnoderecyclenumber, CTLFLAG_RW, &vnoderecyclenumber, 0, "");
/*
* Various variables used for debugging the new implementation of
@ -553,6 +568,7 @@ getnewvnode(tag, mp, vops, vpp)
if (vp == NULL || vp->v_usecount)
panic("getnewvnode: free vnode isn't");
TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);
/*
* Don't recycle if active in the namecache or
* if it still has cached pages or we cannot get
@ -632,9 +648,19 @@ getnewvnode(tag, mp, vops, vpp)
*vpp = vp;
vp->v_usecount = 1;
vp->v_data = 0;
splx(s);
vfs_object_create(vp, p, p->p_ucred);
vnodeallocs++;
if (vnodeallocs % vnoderecycleperiod == 0 &&
freevnodes < vnoderecycleminfreevn &&
vnoderecyclemintotalvn < numvnodes) {
/* Recycle vnodes. */
cache_purgeleafdirs(vnoderecyclenumber);
}
return (0);
}

View File

@ -552,6 +552,7 @@ int cache_lookup __P((struct vnode *dvp, struct vnode **vpp,
struct componentname *cnp));
void cache_purge __P((struct vnode *vp));
void cache_purgevfs __P((struct mount *mp));
void cache_purgeleafdirs __P((int ndir));
void cvtstat __P((struct stat *st, struct ostat *ost));
void cvtnstat __P((struct stat *sb, struct nstat *nsb));
int getnewvnode __P((enum vtagtype tag,