Index: FreeBSD/sys/kern/vfs_cache.c diff -u FreeBSD/sys/kern/vfs_cache.c:1.1.1.13 FreeBSD/sys/kern/vfs_cache.c:1.1.1.10.2.7 --- FreeBSD/sys/kern/vfs_cache.c:1.1.1.13 Fri Apr 13 22:36:08 2001 +++ FreeBSD/sys/kern/vfs_cache.c Sun Apr 15 18:36:05 2001 @@ -98,6 +98,10 @@ 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 @@ { 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 @@ 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); @@ -488,6 +496,62 @@ } } } +} + +/* + * 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++; } /* Index: FreeBSD/sys/kern/vfs_subr.c diff -u FreeBSD/sys/kern/vfs_subr.c:1.1.1.31 FreeBSD/sys/kern/vfs_subr.c:1.1.1.27.2.10 --- FreeBSD/sys/kern/vfs_subr.c:1.1.1.31 Sat Feb 24 13:16:19 2001 +++ FreeBSD/sys/kern/vfs_subr.c Sun Apr 15 18:36:05 2001 @@ -122,6 +122,21 @@ /* 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 @@ 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 @@ *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); } Index: FreeBSD/sys/sys/vnode.h diff -u FreeBSD/sys/sys/vnode.h:1.1.1.27 FreeBSD/sys/sys/vnode.h:1.1.1.19.2.10 --- FreeBSD/sys/sys/vnode.h:1.1.1.27 Thu Apr 5 21:17:12 2001 +++ FreeBSD/sys/sys/vnode.h Fri Apr 6 18:08:36 2001 @@ -553,6 +553,7 @@ 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,