From: Marc Dionne Date: Wed, 19 Mar 2014 15:15:13 +0000 (-0400) Subject: Linux: Do drop dentry if lookup returns ENOENT X-Git-Tag: openafs-stable-1_8_0pre1~756 X-Git-Url: https://git.openafs.org/?p=openafs.git;a=commitdiff_plain;h=389473032cf0b200c2c39fd5ace108bdc05c9d97;hp=5cc3aec78a4329885b450c15ce228fa6fb413fdf Linux: Do drop dentry if lookup returns ENOENT Commit 997f7fce437787a45ae0584beaae43affbd37cce switched to using d_invalidate instead of d_drop to prevent unhashing dentries which are only temporarily invalid and may still be referenced by someone having a current working directory pointing to it. This could result in getting ENOENT from getcwd() after some transient problems, even when the directory is there and accessible. The change had the side effect of potentially leaving something visible when it has actually been removed, for instance a mountpoint removed by "fs rm". If afs_lookup returns ENOENT, we want to forcibly drop (unhash) the dentry, even if it has current users. Change-Id: I0e7b6e09b2c4ae551fa6c84235ed31f7df476b45 Reviewed-on: http://gerrit.openafs.org/10928 Tested-by: BuildBot Reviewed-by: D Brashear --- diff --git a/src/afs/LINUX/osi_vnodeops.c b/src/afs/LINUX/osi_vnodeops.c index b7cae5a..d527dc9 100644 --- a/src/afs/LINUX/osi_vnodeops.c +++ b/src/afs/LINUX/osi_vnodeops.c @@ -1125,6 +1125,7 @@ afs_linux_dentry_revalidate(struct dentry *dp, int flags) int valid; struct afs_fakestat_state fakestate; int locked = 0; + int force_drop = 0; #ifdef LOOKUP_RCU /* We don't support RCU path walking */ @@ -1209,9 +1210,14 @@ afs_linux_dentry_revalidate(struct dentry *dp, int flags) } if (locked && (hgetlo(pvcp->f.m.DataVersion) > dp->d_time || !(vcp->f.states & CStatd))) { - afs_lookup(pvcp, (char *)dp->d_name.name, &tvc, credp); + int code; + + code = afs_lookup(pvcp, (char *)dp->d_name.name, &tvc, credp); if (!tvc || tvc != vcp) { dput(parent); + /* Force unhash if name is known not to exist. */ + if (code == ENOENT) + force_drop = 1; goto bad_dentry; } @@ -1262,8 +1268,18 @@ afs_linux_dentry_revalidate(struct dentry *dp, int flags) if (credp) crfree(credp); - if (!valid) - d_invalidate(dp); + if (!valid) { + /* + * If we had a negative lookup for the name we want to forcibly + * unhash the dentry. + * Otherwise use d_invalidate which will not unhash it if still in use. + */ + if (force_drop) { + shrink_dcache_parent(dp); + d_drop(dp); + } else + d_invalidate(dp); + } return valid;