]> git.michaelhowe.org Git - packages/o/openafs.git/commitdiff
Linux: Do drop dentry if lookup returns ENOENT
authorMarc Dionne <marc.dionne@your-file-system.com>
Wed, 19 Mar 2014 15:15:13 +0000 (11:15 -0400)
committerStephan Wiesand <stephan.wiesand@desy.de>
Wed, 26 Mar 2014 20:31:12 +0000 (13:31 -0700)
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.

Reviewed-on: http://gerrit.openafs.org/10928
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: D Brashear <shadow@your-file-system.com>
(cherry picked from commit 389473032cf0b200c2c39fd5ace108bdc05c9d97)

Change-Id: Ifeda5a38a01bc136d3ecef01227ecd354da7cc3e
Reviewed-on: http://gerrit.openafs.org/10948
Reviewed-by: D Brashear <shadow@your-file-system.com>
Tested-by: D Brashear <shadow@your-file-system.com>
Reviewed-by: Andrew Deason <adeason@sinenomine.net>
Reviewed-by: Stephan Wiesand <stephan.wiesand@desy.de>
src/afs/LINUX/osi_vnodeops.c

index 1225392b440e2e3279c4c8a1071eddfb26b92956..03caf1c5e4b61854aa7119bd0be3527f97868b1e 100644 (file)
@@ -1115,6 +1115,7 @@ afs_linux_dentry_revalidate(struct dentry *dp, int flags)
     struct dentry *parent;
     int valid;
     struct afs_fakestat_state fakestate;
+    int force_drop = 0;
 
 #ifdef LOOKUP_RCU
     /* We don't support RCU path walking */
@@ -1182,11 +1183,15 @@ afs_linux_dentry_revalidate(struct dentry *dp, int flags)
         */
 
        if (hgetlo(pvcp->f.m.DataVersion) > dp->d_time || !(vcp->f.states & CStatd)) {
+           int code;
 
            credp = crref();
-           afs_lookup(pvcp, (char *)dp->d_name.name, &tvc, credp);
+           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;
            }
 
@@ -1234,8 +1239,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;