]> git.michaelhowe.org Git - packages/o/openafs.git/commitdiff
STABLE12-linux-dcache-create-negative-dentries-22-needs-while-still-avoiding-vlru...
authorDerrick Brashear <shadow@dementia.org>
Tue, 2 Apr 2002 03:13:26 +0000 (03:13 +0000)
committerDerrick Brashear <shadow@dementia.org>
Tue, 2 Apr 2002 03:13:26 +0000 (03:13 +0000)
based on patch by Srikanth Vishwanathan and modifications based on suggestions
from Ted Anderson applicable to this part of the code.

the original theory we operated under, namely that negative dentries
could be banished entirely, causes file creation to stop working
under linux 2.2 kernels. reverting that change means we have to deal with
these negative dentries, and Srikanth's original suggested patch does so.

(cherry picked from commit 4beb9adb661bade7caff8adf40ecb3882ae7deac)

src/afs/afs_vcache.c

index 82a9c28b5c15972c2bcbfdd04495b3899bf97446..e89bd61cc2ceffff4dbbaf41ae7394b28f3dd2b7 100644 (file)
@@ -466,6 +466,59 @@ static afs_int32 afs_QueueVCB(struct vcache *avc)
     return 0;
 }
 
+#ifdef AFS_LINUX22_ENV
+/* afs_TryFlushDcacheChildren -- Shakes loose vcache references held by
+ *                               children of the dentry
+ *
+ * LOCKS -- Called with afs_xvcache write locked. Drops and reaquires
+ *          AFS_GLOCK, so it can call dput, which may call iput, but
+ *          keeps afs_xvcache exclusively.
+ *
+ * Tree traversal algorithm from fs/dcache.c: select_parent()
+ */
+static void afs_TryFlushDcacheChildren(struct dentry *parent)
+{
+    struct dentry *this_parent = parent;
+    struct list_head *next;
+
+ repeat:
+    next = this_parent->d_subdirs.next;
+ resume:
+    DLOCK();
+    while (next != &this_parent->d_subdirs) {
+       struct list_head *tmp = next;
+       struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
+
+       next = tmp->next;
+       if (!DCOUNT(dentry) && !dentry->d_inode) {
+           DGET(dentry);
+           AFS_GUNLOCK();
+           DUNLOCK();
+           d_drop(dentry);
+           dput(dentry);
+           AFS_GLOCK();
+           goto repeat;
+       }
+       /*
+        * Descend a level if the d_subdirs list is non-empty.
+         */
+       if (!list_empty(&dentry->d_subdirs)) {
+           this_parent = dentry;
+           goto repeat;
+       }
+    }
+    DUNLOCK();
+
+    /*
+     * All done at this level ... ascend and resume the search.
+     */
+    if (this_parent != parent) {
+       next = this_parent->d_child.next;
+       this_parent = this_parent->d_parent;
+       goto resume;
+    }
+}
+#endif /* AFS_LINUX22_ENV */
 
 /*
  * afs_RemoveVCB
@@ -595,6 +648,10 @@ struct vcache *afs_NewVCache(struct VenusFid *afid, struct server *serverp,
                    cur = head;
                    while ((cur = cur->next) != head) {
                        struct dentry *dentry = list_entry(cur, struct dentry, d_alias);
+                       if (DCOUNT(dentry)) {
+                           afs_TryFlushDcacheChildren(dentry);
+                       }
+
                        if (!DCOUNT(dentry)) {
                            AFS_GUNLOCK();
                            DGET(dentry);