linux-newvcache-clean-up-dentries-20020115
authorTed Anderson <ota@transarc.com>
Wed, 16 Jan 2002 02:03:49 +0000 (02:03 +0000)
committerDerrick Brashear <shadow@dementia.org>
Wed, 16 Jan 2002 02:03:49 +0000 (02:03 +0000)
With work and feedback from Omkar Sathe <somkar@in.ibm.com> and
Srikanth Vishwanathan <vsrikanth@in.ibm.com>

src/afs/afs.h
src/afs/afs_vcache.c

index 50d7d1f..1660ea2 100644 (file)
@@ -533,11 +533,19 @@ struct SimpleLocks {
 #define VREFCOUNT_SET(v, c)    atomic_set(&((vnode_t *) v)->v_count, c)
 #define VREFCOUNT_DEC(v)       atomic_dec(&((vnode_t *) v)->v_count)
 #define VREFCOUNT_INC(v)       atomic_inc(&((vnode_t *) v)->v_count)
+#define DLOCK()      spin_lock(&dcache_lock)
+#define DUNLOCK()    spin_unlock(&dcache_lock)
+#define DGET(d)      dget_locked(d)
+#define DCOUNT(d)    atomic_read(&(d)->d_count)
 #else
 #define VREFCOUNT(v)           ((v)->vrefCount)
 #define VREFCOUNT_SET(v, c)    (v)->vrefCount = c;
 #define VREFCOUNT_DEC(v)       (v)->vrefCount--;
 #define VREFCOUNT_INC(v)       (v)->vrefCount++;
+#define DLOCK()
+#define DUNLOCK()
+#define DGET(d)      dget(d)
+#define DCOUNT(d)    ((d)->d_count)
 #endif
 
 #define        AFS_MAXDV   0x7fffffff      /* largest dataversion number */
index 67d3461..75c198b 100644 (file)
@@ -525,7 +525,97 @@ afs_RemoveVCB(afid)
 } /*afs_RemoveVCB*/
 
 
+#if defined(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:
+    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);
+           DUNLOCK();
+           AFS_GUNLOCK();
+           d_drop(dentry);
+           dput(dentry);
+           AFS_GLOCK();
+           DLOCK();
+           goto repeat;
+       }
+        
+       /*
+        * Descend a level if the d_subdirs list is non-empty.
+        */
+       if (!list_empty(&dentry->d_subdirs)) {
+           this_parent = dentry;
+           goto repeat;
+       }
+    }
+    /*
+     * 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;
+    }
+}
 
+/* afs_TryFlushDcache -- Shakes loose vcache references held by the Linux
+ *                       dcache.
+ *
+ * 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.
+ */
+static void afs_TryFlushDcache(struct vcache *vcp)
+{
+    struct inode *ip = (struct inode *) vcp;
+  
+    DLOCK();
+ retry:
+    if (!list_empty(&ip->i_dentry)) {
+       struct list_head *cur, *head = &ip->i_dentry;
+       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)) {
+               DGET(dentry);
+               DUNLOCK();
+               AFS_GUNLOCK();
+               d_drop(dentry);
+               dput(dentry);
+               AFS_GLOCK();
+               DLOCK();
+               goto retry;
+           }
+       }
+       DUNLOCK();
+    }
+}
+#endif
+           
 /*
  * afs_NewVCache
  *
@@ -560,79 +650,6 @@ struct vcache *afs_NewVCache(struct VenusFid *afid, struct server *serverp,
     int code, fv_slept;
 
     AFS_STATCNT(afs_NewVCache);
-#ifdef AFS_LINUX22_ENV
-    if (!freeVCList) {
-       /* Free some if possible. */
-        struct afs_q *tq, *uq;
-        int i; char *panicstr;
-        int vmax = 2 * afs_cacheStats;
-        int vn = VCACHE_FREE;
-
-         AFS_GUNLOCK();
-        shrink_dcache_sb(afs_globalVFS);
-        AFS_GLOCK();
-
-        i = 0;
-        for(tq = VLRU.prev; tq != &VLRU && vn > 0; tq = uq) {
-           tvc = QTOV(tq);
-           uq = QPrev(tq);
-           if (tvc->states & CVFlushed) 
-                refpanic ("CVFlushed on VLRU");
-           else if (i++ > vmax)
-                refpanic ("Exceeded pool of AFS vnodes(VLRU cycle?)");
-           else if (QNext(uq) != tq)
-                refpanic ("VLRU inconsistent");
-
-           if (tvc == afs_globalVp)
-               continue;
-
-           if ( VREFCOUNT(tvc) && tvc->opens == 0 ) {
-               struct inode *ip = (struct inode*)tvc;
-               if (list_empty(&ip->i_dentry)) {
-                   vn --;
-               }
-               else {
-                   struct list_head *cur;
-                   struct list_head *head = &ip->i_dentry;
-                   int all = 1;
-               restart:
-#if defined(AFS_LINUX24_ENV)
-                   spin_lock(&dcache_lock);
-#endif
-                   cur = head;
-                   while ((cur = cur->next) != head) {
-                       struct dentry *dentry = list_entry(cur, struct dentry, d_alias);
-#if defined(AFS_LINUX24_ENV)
-                       if (!atomic_read(&dentry->d_count)) {
-#else
-                       if (!dentry->d_count) {
-#endif
-                           AFS_GUNLOCK();
-#if defined(AFS_LINUX24_ENV)
-                           dget_locked(dentry);
-                           spin_unlock(&dcache_lock);
-#else
-                           dget(dentry);
-#endif
-                           d_drop(dentry);
-                           dput(dentry);
-                           AFS_GLOCK();
-                           goto restart;
-                       }
-                       else {
-                           all = 0;
-                       }
-                   }
-#if defined(AFS_LINUX24_ENV)
-                   spin_unlock(&dcache_lock);
-#endif
-                   if (all) vn --;
-               }
-           }
-           if (tq == uq) break;
-        }
-    }
-#endif /* AFS_LINUX22_ENV */
 #ifdef AFS_OSF_ENV
 #ifdef AFS_OSF30_ENV
     if (afs_vcount >= afs_maxvcount) 
@@ -724,6 +741,10 @@ struct vcache *afs_NewVCache(struct VenusFid *afid, struct server *serverp,
                }
             }
 #endif
+#if defined(AFS_LINUX22_ENV)
+          if (tvc != afs_globalVp && VREFCOUNT(tvc) && tvc->opens == 0)
+              afs_TryFlushDcache(tvc);
+#endif
           if (VREFCOUNT(tvc) == 0 && tvc->opens == 0
               && (tvc->states & CUnlinkedDel) == 0) {
                code = afs_FlushVCache(tvc, &fv_slept);