X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/blobdiff_plain/097a4fd11fac7bc82d1b152e3259da24a019f7b8..81c4868c0a715c2fe5fc2df73541b8d1dbec80a2:/sys/kern/vfs_cache.c diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c index 19031fca0d..d4899d364d 100644 --- a/sys/kern/vfs_cache.c +++ b/sys/kern/vfs_cache.c @@ -186,16 +186,17 @@ static void _cache_setunresolved(struct namecache *ncp); static void _cache_cleanneg(int count); static void _cache_cleanpos(int count); static void _cache_cleandefered(void); +static void _cache_unlink(struct namecache *ncp); /* * The new name cache statistics */ SYSCTL_NODE(_vfs, OID_AUTO, cache, CTLFLAG_RW, 0, "Name cache statistics"); static int numneg; -SYSCTL_ULONG(_vfs_cache, OID_AUTO, numneg, CTLFLAG_RD, &numneg, 0, +SYSCTL_INT(_vfs_cache, OID_AUTO, numneg, CTLFLAG_RD, &numneg, 0, "Number of negative namecache entries"); static int numcache; -SYSCTL_ULONG(_vfs_cache, OID_AUTO, numcache, CTLFLAG_RD, &numcache, 0, +SYSCTL_INT(_vfs_cache, OID_AUTO, numcache, CTLFLAG_RD, &numcache, 0, "Number of namecaches entries"); static u_long numcalls; SYSCTL_ULONG(_vfs_cache, OID_AUTO, numcalls, CTLFLAG_RD, &numcalls, 0, @@ -1372,14 +1373,26 @@ cache_rename(struct nchandle *fnch, struct nchandle *tnch) struct nchash_head *nchpp; u_int32_t hash; char *oname; + char *nname; + + if (tncp->nc_nlen) { + nname = kmalloc(tncp->nc_nlen + 1, M_VFSCACHE, M_WAITOK); + bcopy(tncp->nc_name, nname, tncp->nc_nlen); + nname[tncp->nc_nlen] = 0; + } else { + nname = NULL; + } /* * Rename fncp (unlink) */ _cache_unlink_parent(fncp); oname = fncp->nc_name; - fncp->nc_name = tncp->nc_name; + fncp->nc_name = nname; fncp->nc_nlen = tncp->nc_nlen; + if (oname) + kfree(oname, M_VFSCACHE); + tncp_par = tncp->nc_parent; _cache_hold(tncp_par); _cache_lock(tncp_par); @@ -1400,13 +1413,24 @@ cache_rename(struct nchandle *fnch, struct nchandle *tnch) /* * Get rid of the overwritten tncp (unlink) */ - _cache_setunresolved(tncp); - _cache_unlink_parent(tncp); - tncp->nc_name = NULL; - tncp->nc_nlen = 0; + _cache_unlink(tncp); +} - if (oname) - kfree(oname, M_VFSCACHE); +/* + * Perform actions consistent with unlinking a file. The namecache + * entry is marked DESTROYED so it no longer shows up in searches, + * and will be physically deleted when the vnode goes away. + */ +void +cache_unlink(struct nchandle *nch) +{ + _cache_unlink(nch->ncp); +} + +static void +_cache_unlink(struct namecache *ncp) +{ + ncp->nc_flag |= NCF_DESTROYED; } /* @@ -2571,6 +2595,20 @@ restart: return (ncp->nc_error); } + /* + * If the ncp was destroyed it will never resolve again. This + * can basically only happen when someone is chdir'd into an + * empty directory which is then rmdir'd. We want to catch this + * here and not dive the VFS because the VFS might actually + * have a way to re-resolve the disconnected ncp, which will + * result in inconsistencies in the cdir/nch for proc->p_fd. + */ + if (ncp->nc_flag & NCF_DESTROYED) { + kprintf("Warning: cache_resolve: ncp '%s' was unlinked\n", + ncp->nc_name); + return(EINVAL); + } + /* * Mount points need special handling because the parent does not * belong to the same filesystem as the ncp.