1
0
mirror of https://git.FreeBSD.org/src.git synced 2025-01-11 14:10:34 +00:00

- Apply a big giant lock around the namecache. This has been sitting in

my tree since BSDcon.
This commit is contained in:
Jeff Roberson 2003-10-05 07:13:50 +00:00
parent bdcfcdecea
commit 98d7d155c1
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=120792

View File

@ -113,6 +113,12 @@ SYSCTL_ULONG(_debug, OID_AUTO, numcachepl, CTLFLAG_RD, &numcachepl, 0, "");
#endif #endif
struct nchstats nchstats; /* cache effectiveness statistics */ struct nchstats nchstats; /* cache effectiveness statistics */
struct mtx cache_lock;
MTX_SYSINIT(vfscache, &cache_lock, "Name Cache", MTX_DEF);
#define CACHE_LOCK() mtx_lock(&cache_lock)
#define CACHE_UNLOCK() mtx_unlock(&cache_lock)
/* /*
* UMA zones for the VFS cache. * UMA zones for the VFS cache.
* *
@ -166,7 +172,7 @@ SYSCTL_OPAQUE(_vfs_cache, OID_AUTO, nchstats, CTLFLAG_RD, &nchstats,
static void cache_zap(struct namecache *ncp); static void cache_zap(struct namecache *ncp, int locked);
static MALLOC_DEFINE(M_VFSCACHE, "vfscache", "VFS name cache entries"); static MALLOC_DEFINE(M_VFSCACHE, "vfscache", "VFS name cache entries");
@ -261,13 +267,19 @@ SYSCTL_PROC(_debug_hashstat, OID_AUTO, nchash, CTLTYPE_INT|CTLFLAG_RD,
* pointer to a vnode or if it is just a negative cache entry. * pointer to a vnode or if it is just a negative cache entry.
*/ */
static void static void
cache_zap(ncp) cache_zap(ncp, locked)
struct namecache *ncp; struct namecache *ncp;
int locked;
{ {
struct vnode *vp;
vp = NULL;
if (!locked)
CACHE_LOCK();
LIST_REMOVE(ncp, nc_hash); LIST_REMOVE(ncp, nc_hash);
LIST_REMOVE(ncp, nc_src); 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); vp = ncp->nc_dvp;
numcachehv--; numcachehv--;
} }
if (ncp->nc_vp) { if (ncp->nc_vp) {
@ -277,7 +289,12 @@ cache_zap(ncp)
numneg--; numneg--;
} }
numcache--; numcache--;
CACHE_UNLOCK();
cache_free(ncp); cache_free(ncp);
if (vp)
vdrop(vp);
if (locked)
CACHE_LOCK();
} }
/* /*
@ -294,15 +311,21 @@ int
cache_leaf_test(struct vnode *vp) cache_leaf_test(struct vnode *vp)
{ {
struct namecache *ncpc; struct namecache *ncpc;
int leaf;
leaf = 0;
CACHE_LOCK();
for (ncpc = LIST_FIRST(&vp->v_cache_src); for (ncpc = LIST_FIRST(&vp->v_cache_src);
ncpc != NULL; ncpc != NULL;
ncpc = LIST_NEXT(ncpc, nc_src) ncpc = LIST_NEXT(ncpc, nc_src)
) { ) {
if (ncpc->nc_vp != NULL && ncpc->nc_vp->v_type == VDIR) if (ncpc->nc_vp != NULL && ncpc->nc_vp->v_type == VDIR) {
return(-1); leaf = -1;
break;
}
} }
return(0); CACHE_UNLOCK();
return (leaf);
} }
/* /*
@ -330,12 +353,14 @@ cache_lookup(dvp, vpp, cnp)
return (0); return (0);
} }
CACHE_LOCK();
numcalls++; numcalls++;
if (cnp->cn_nameptr[0] == '.') { if (cnp->cn_nameptr[0] == '.') {
if (cnp->cn_namelen == 1) { if (cnp->cn_namelen == 1) {
*vpp = dvp; *vpp = dvp;
dothits++; dothits++;
CACHE_UNLOCK();
return (-1); return (-1);
} }
if (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.') { if (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.') {
@ -343,9 +368,11 @@ cache_lookup(dvp, vpp, cnp)
if (dvp->v_dd->v_id != dvp->v_ddid || if (dvp->v_dd->v_id != dvp->v_ddid ||
(cnp->cn_flags & MAKEENTRY) == 0) { (cnp->cn_flags & MAKEENTRY) == 0) {
dvp->v_ddid = 0; dvp->v_ddid = 0;
CACHE_UNLOCK();
return (0); return (0);
} }
*vpp = dvp->v_dd; *vpp = dvp->v_dd;
CACHE_UNLOCK();
return (-1); return (-1);
} }
} }
@ -367,6 +394,7 @@ cache_lookup(dvp, vpp, cnp)
nummiss++; nummiss++;
} }
nchstats.ncs_miss++; nchstats.ncs_miss++;
CACHE_UNLOCK();
return (0); return (0);
} }
@ -374,7 +402,8 @@ cache_lookup(dvp, vpp, cnp)
if ((cnp->cn_flags & MAKEENTRY) == 0) { if ((cnp->cn_flags & MAKEENTRY) == 0) {
numposzaps++; numposzaps++;
nchstats.ncs_badhits++; nchstats.ncs_badhits++;
cache_zap(ncp); CACHE_UNLOCK();
cache_zap(ncp, 0);
return (0); return (0);
} }
@ -383,6 +412,7 @@ cache_lookup(dvp, vpp, cnp)
numposhits++; numposhits++;
nchstats.ncs_goodhits++; nchstats.ncs_goodhits++;
*vpp = ncp->nc_vp; *vpp = ncp->nc_vp;
CACHE_UNLOCK();
return (-1); return (-1);
} }
@ -390,7 +420,8 @@ cache_lookup(dvp, vpp, cnp)
if (cnp->cn_nameiop == CREATE) { if (cnp->cn_nameiop == CREATE) {
numnegzaps++; numnegzaps++;
nchstats.ncs_badhits++; nchstats.ncs_badhits++;
cache_zap(ncp); CACHE_UNLOCK();
cache_zap(ncp, 0);
return (0); return (0);
} }
@ -406,6 +437,7 @@ cache_lookup(dvp, vpp, cnp)
nchstats.ncs_neghits++; nchstats.ncs_neghits++;
if (ncp->nc_flag & NCF_WHITE) if (ncp->nc_flag & NCF_WHITE)
cnp->cn_flags |= ISWHITEOUT; cnp->cn_flags |= ISWHITEOUT;
CACHE_UNLOCK();
return (ENOENT); return (ENOENT);
} }
@ -421,6 +453,8 @@ cache_enter(dvp, vp, cnp)
struct namecache *ncp; struct namecache *ncp;
struct nchashhead *ncpp; struct nchashhead *ncpp;
u_int32_t hash; u_int32_t hash;
int hold;
int zap;
int len; int len;
if (!doingcache) if (!doingcache)
@ -442,8 +476,10 @@ cache_enter(dvp, vp, cnp)
} }
} }
hold = 0;
zap = 0;
ncp = cache_alloc(cnp->cn_namelen); ncp = cache_alloc(cnp->cn_namelen);
/* XXX can uma_zalloc(..., M_WAITOK) fail? */ CACHE_LOCK();
numcache++; numcache++;
if (!vp) { if (!vp) {
numneg++; numneg++;
@ -467,7 +503,7 @@ cache_enter(dvp, vp, cnp)
ncpp = NCHHASH(hash); ncpp = NCHHASH(hash);
LIST_INSERT_HEAD(ncpp, ncp, nc_hash); LIST_INSERT_HEAD(ncpp, ncp, nc_hash);
if (LIST_EMPTY(&dvp->v_cache_src)) { if (LIST_EMPTY(&dvp->v_cache_src)) {
vhold(dvp); hold = 1;
numcachehv++; numcachehv++;
} }
LIST_INSERT_HEAD(&dvp->v_cache_src, ncp, nc_src); LIST_INSERT_HEAD(&dvp->v_cache_src, ncp, nc_src);
@ -483,8 +519,13 @@ cache_enter(dvp, vp, cnp)
} }
if (numneg * ncnegfactor > numcache) { if (numneg * ncnegfactor > numcache) {
ncp = TAILQ_FIRST(&ncneg); ncp = TAILQ_FIRST(&ncneg);
cache_zap(ncp); zap = 1;
} }
CACHE_UNLOCK();
if (hold)
vhold(dvp);
if (zap)
cache_zap(ncp, 0);
} }
/* /*
@ -522,16 +563,21 @@ SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_SECOND, nchinit, NULL)
* XXX: using the global v_id. * XXX: using the global v_id.
*/ */
/*
* XXX This is sometimes called when a vnode may still be re-used, in which
* case v_dd may be invalid. Need to look this up.
*/
void void
cache_purge(vp) cache_purge(vp)
struct vnode *vp; struct vnode *vp;
{ {
static u_long nextid; static u_long nextid;
CACHE_LOCK();
while (!LIST_EMPTY(&vp->v_cache_src)) while (!LIST_EMPTY(&vp->v_cache_src))
cache_zap(LIST_FIRST(&vp->v_cache_src)); cache_zap(LIST_FIRST(&vp->v_cache_src), 1);
while (!TAILQ_EMPTY(&vp->v_cache_dst)) while (!TAILQ_EMPTY(&vp->v_cache_dst))
cache_zap(TAILQ_FIRST(&vp->v_cache_dst)); cache_zap(TAILQ_FIRST(&vp->v_cache_dst), 1);
do do
nextid++; nextid++;
@ -539,6 +585,7 @@ cache_purge(vp)
vp->v_id = nextid; vp->v_id = nextid;
vp->v_dd = vp; vp->v_dd = vp;
vp->v_ddid = 0; vp->v_ddid = 0;
CACHE_UNLOCK();
} }
/* /*
@ -553,16 +600,25 @@ cache_purgevfs(mp)
{ {
struct nchashhead *ncpp; struct nchashhead *ncpp;
struct namecache *ncp, *nnp; struct namecache *ncp, *nnp;
struct nchashhead mplist;
LIST_INIT(&mplist);
ncp = NULL;
/* Scan hash tables for applicable entries */ /* Scan hash tables for applicable entries */
CACHE_LOCK();
for (ncpp = &nchashtbl[nchash]; ncpp >= nchashtbl; ncpp--) { for (ncpp = &nchashtbl[nchash]; ncpp >= nchashtbl; ncpp--) {
for (ncp = LIST_FIRST(ncpp); ncp != 0; ncp = nnp) { for (ncp = LIST_FIRST(ncpp); ncp != 0; ncp = nnp) {
nnp = LIST_NEXT(ncp, nc_hash); nnp = LIST_NEXT(ncp, nc_hash);
if (ncp->nc_dvp->v_mount == mp) { if (ncp->nc_dvp->v_mount == mp) {
cache_zap(ncp); LIST_REMOVE(ncp, nc_hash);
LIST_INSERT_HEAD(&mplist, ncp, nc_hash);
} }
} }
} }
CACHE_UNLOCK();
while (!LIST_EMPTY(&mplist))
cache_zap(LIST_FIRST(&mplist), 0);
} }
/* /*
@ -774,7 +830,6 @@ kern___getcwd(struct thread *td, u_char *buf, enum uio_seg bufseg, u_int buflen)
fdp = td->td_proc->p_fd; fdp = td->td_proc->p_fd;
slash_prefixed = 0; slash_prefixed = 0;
FILEDESC_LOCK(fdp); FILEDESC_LOCK(fdp);
mp_fixme("No vnode locking done!");
for (vp = fdp->fd_cdir; vp != fdp->fd_rdir && vp != rootvnode;) { for (vp = fdp->fd_cdir; vp != fdp->fd_rdir && vp != rootvnode;) {
if (vp->v_vflag & VV_ROOT) { if (vp->v_vflag & VV_ROOT) {
if (vp->v_mount == NULL) { /* forced unmount */ if (vp->v_mount == NULL) { /* forced unmount */
@ -791,37 +846,43 @@ kern___getcwd(struct thread *td, u_char *buf, enum uio_seg bufseg, u_int buflen)
free(tmpbuf, M_TEMP); free(tmpbuf, M_TEMP);
return (ENOTDIR); return (ENOTDIR);
} }
CACHE_LOCK();
ncp = TAILQ_FIRST(&vp->v_cache_dst); ncp = TAILQ_FIRST(&vp->v_cache_dst);
if (!ncp) { if (!ncp) {
FILEDESC_UNLOCK(fdp);
numcwdfail2++; numcwdfail2++;
CACHE_UNLOCK();
FILEDESC_UNLOCK(fdp);
free(tmpbuf, M_TEMP); free(tmpbuf, M_TEMP);
return (ENOENT); return (ENOENT);
} }
if (ncp->nc_dvp != vp->v_dd) { if (ncp->nc_dvp != vp->v_dd) {
FILEDESC_UNLOCK(fdp);
numcwdfail3++; numcwdfail3++;
CACHE_UNLOCK();
FILEDESC_UNLOCK(fdp);
free(tmpbuf, M_TEMP); free(tmpbuf, M_TEMP);
return (EBADF); return (EBADF);
} }
for (i = ncp->nc_nlen - 1; i >= 0; i--) { for (i = ncp->nc_nlen - 1; i >= 0; i--) {
if (bp == tmpbuf) { if (bp == tmpbuf) {
FILEDESC_UNLOCK(fdp);
numcwdfail4++; numcwdfail4++;
CACHE_UNLOCK();
FILEDESC_UNLOCK(fdp);
free(tmpbuf, M_TEMP); free(tmpbuf, M_TEMP);
return (ENOMEM); return (ENOMEM);
} }
*--bp = ncp->nc_name[i]; *--bp = ncp->nc_name[i];
} }
if (bp == tmpbuf) { if (bp == tmpbuf) {
FILEDESC_UNLOCK(fdp);
numcwdfail4++; numcwdfail4++;
CACHE_UNLOCK();
FILEDESC_UNLOCK(fdp);
free(tmpbuf, M_TEMP); free(tmpbuf, M_TEMP);
return (ENOMEM); return (ENOMEM);
} }
*--bp = '/'; *--bp = '/';
slash_prefixed = 1; slash_prefixed = 1;
vp = vp->v_dd; vp = vp->v_dd;
CACHE_UNLOCK();
} }
FILEDESC_UNLOCK(fdp); FILEDESC_UNLOCK(fdp);
if (!slash_prefixed) { if (!slash_prefixed) {
@ -884,9 +945,9 @@ vn_fullpath(struct thread *td, struct vnode *vn, char **retbuf, char **freebuf)
*bp = '\0'; *bp = '\0';
fdp = td->td_proc->p_fd; fdp = td->td_proc->p_fd;
slash_prefixed = 0; slash_prefixed = 0;
ASSERT_VOP_LOCKED(vn, "vn_fullpath");
FILEDESC_LOCK(fdp); FILEDESC_LOCK(fdp);
for (vp = vn; vp != fdp->fd_rdir && vp != rootvnode;) { for (vp = vn; vp != fdp->fd_rdir && vp != rootvnode;) {
ASSERT_VOP_LOCKED(vp, "vn_fullpath");
if (vp->v_vflag & VV_ROOT) { if (vp->v_vflag & VV_ROOT) {
if (vp->v_mount == NULL) { /* forced unmount */ if (vp->v_mount == NULL) { /* forced unmount */
FILEDESC_UNLOCK(fdp); FILEDESC_UNLOCK(fdp);
@ -898,46 +959,52 @@ vn_fullpath(struct thread *td, struct vnode *vn, char **retbuf, char **freebuf)
} }
if (vp != vn && vp->v_dd->v_id != vp->v_ddid) { if (vp != vn && vp->v_dd->v_id != vp->v_ddid) {
FILEDESC_UNLOCK(fdp); FILEDESC_UNLOCK(fdp);
numfullpathfail1++;
free(buf, M_TEMP); free(buf, M_TEMP);
numfullpathfail1++;
return (ENOTDIR); return (ENOTDIR);
} }
CACHE_LOCK();
ncp = TAILQ_FIRST(&vp->v_cache_dst); ncp = TAILQ_FIRST(&vp->v_cache_dst);
if (!ncp) { if (!ncp) {
FILEDESC_UNLOCK(fdp);
numfullpathfail2++; numfullpathfail2++;
CACHE_UNLOCK();
FILEDESC_UNLOCK(fdp);
free(buf, M_TEMP); free(buf, M_TEMP);
return (ENOENT); return (ENOENT);
} }
if (vp != vn && ncp->nc_dvp != vp->v_dd) { if (vp != vn && ncp->nc_dvp != vp->v_dd) {
FILEDESC_UNLOCK(fdp);
numfullpathfail3++; numfullpathfail3++;
CACHE_UNLOCK();
FILEDESC_UNLOCK(fdp);
free(buf, M_TEMP); free(buf, M_TEMP);
return (EBADF); return (EBADF);
} }
for (i = ncp->nc_nlen - 1; i >= 0; i--) { for (i = ncp->nc_nlen - 1; i >= 0; i--) {
if (bp == buf) { if (bp == buf) {
FILEDESC_UNLOCK(fdp);
numfullpathfail4++; numfullpathfail4++;
CACHE_UNLOCK();
FILEDESC_UNLOCK(fdp);
free(buf, M_TEMP); free(buf, M_TEMP);
return (ENOMEM); return (ENOMEM);
} }
*--bp = ncp->nc_name[i]; *--bp = ncp->nc_name[i];
} }
if (bp == buf) { if (bp == buf) {
FILEDESC_UNLOCK(fdp);
numfullpathfail4++; numfullpathfail4++;
CACHE_UNLOCK();
FILEDESC_UNLOCK(fdp);
free(buf, M_TEMP); free(buf, M_TEMP);
return (ENOMEM); return (ENOMEM);
} }
*--bp = '/'; *--bp = '/';
slash_prefixed = 1; slash_prefixed = 1;
vp = ncp->nc_dvp; vp = ncp->nc_dvp;
CACHE_UNLOCK();
} }
if (!slash_prefixed) { if (!slash_prefixed) {
if (bp == buf) { if (bp == buf) {
FILEDESC_UNLOCK(fdp);
numfullpathfail4++; numfullpathfail4++;
FILEDESC_UNLOCK(fdp);
free(buf, M_TEMP); free(buf, M_TEMP);
return (ENOMEM); return (ENOMEM);
} }