X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/blobdiff_plain/a6fe93dc81f66af3c2b899c1bc1ddb7fa9e6f42a..81c4868c0a715c2fe5fc2df73541b8d1dbec80a2:/sys/kern/vfs_cache.c diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c index 5b92fe5087..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, @@ -901,6 +902,11 @@ _cache_setvp(struct mount *mp, struct namecache *ncp, struct vnode *vp) } atomic_add_int(&numcache, 1); ncp->nc_error = 0; + /* XXX: this is a hack to work-around the lack of a real pfs vfs + * implementation*/ + if (mp != NULL) + if (strncmp(mp->mnt_stat.f_fstypename, "null", 5) == 0) + vp->v_pfsmp = mp; } else { /* * When creating a negative cache hit we set the @@ -916,7 +922,7 @@ _cache_setvp(struct mount *mp, struct namecache *ncp, struct vnode *vp) spin_unlock(&ncspin); ncp->nc_error = ENOENT; if (mp) - ncp->nc_namecache_gen = mp->mnt_namecache_gen; + VFS_NCPGEN_SET(mp, ncp); } ncp->nc_flag &= ~(NCF_UNRESOLVED | NCF_DEFEREDZAP); } @@ -1028,8 +1034,7 @@ _cache_auto_unresolve(struct mount *mp, struct namecache *ncp) * If a resolved negative cache hit is invalid due to * the mount's namecache generation being bumped, zap it. */ - if (ncp->nc_vp == NULL && - ncp->nc_namecache_gen != mp->mnt_namecache_gen) { + if (ncp->nc_vp == NULL && VFS_NCPGEN_TEST(mp, ncp)) { _cache_setunresolved(ncp); return; } @@ -1368,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); @@ -1396,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; } /* @@ -2495,6 +2523,7 @@ cache_findmount_callback(struct mount *mp, void *data) mp->mnt_ncmounton.ncp == info->nch_ncp ) { info->result = mp; + atomic_add_int(&mp->mnt_refs, 1); return(-1); } return(0); @@ -2513,6 +2542,12 @@ cache_findmount(struct nchandle *nch) return(info.result); } +void +cache_dropmount(struct mount *mp) +{ + atomic_add_int(&mp->mnt_refs, -1); +} + /* * Resolve an unresolved namecache entry, generally by looking it up. * The passed ncp must be locked and refd. @@ -2560,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.