linux26-vcache-reclaim-cleanup-20050119
authorChas Williams <chas@cmf.nrl.navy.mil>
Wed, 19 Jan 2005 22:46:06 +0000 (22:46 +0000)
committerDerrick Brashear <shadow@dementia.org>
Wed, 19 Jan 2005 22:46:06 +0000 (22:46 +0000)
"ok, if you ever drop
dcache_lock you need to go to restart (i think that's pretty clear).
shrink_dcache_parent() _might_ reduce a dentry count to 0.  in the
previous version, it seemed to make the assumption that this would
always happen.  if shrink_dcache_parent() is unsuccessful and the
dentry is a directory, we cant restart.  we would just find the
the dentry again and do the same thing over (we could always d_drop
but you shouldnt do this to active directories -- see d_invalidate).

if we find a busy dentry, we abort all processing for this inode.
going back to restart would find the same busy inode.  (i suppose
we could use a d_flag to keep track of which dentry has been shrunk.
this has other trouble, like who resets the flag and when?)  since we
only do this for directories and d_alias typically only grows due to
soft/hard links (as far as i can tell) this scheme seems reasonable."

src/afs/afs_vcache.c

index 6e38da8..1629bc6 100644 (file)
@@ -844,20 +844,44 @@ afs_NewVCache(struct VenusFid *afid, struct server *serverp)
                 struct list_head *cur, *head = &(AFSTOI(tvc))->i_dentry;
                 AFS_FAST_HOLD(tvc);
                 AFS_GUNLOCK();
-shrink_restart:
-                DLOCK();
-                cur=head;
+
+restart:
+                spin_lock(&dcache_lock);
+                cur = head;
                 while ((cur = cur->next) != head) {
                     dentry = list_entry(cur, struct dentry, d_alias);
-                    if (!d_unhashed(dentry) &&
-                        !list_empty(&dentry->d_subdirs)) {
+
+                   if (d_unhashed(dentry))
+                       continue;
+
+                   dget_locked(dentry);
+
+                   if (!list_empty(&dentry->d_subdirs)) {
                         DUNLOCK();
                        shrink_dcache_parent(dentry);
-                        goto shrink_restart;
+                        DLOCK();
                     }
+
+                   spin_lock(&dentry->d_lock);
+                   if (atomic_read(&dentry->d_count) > 1) {
+                       if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) {
+                           spin_unlock(&dentry->d_lock);
+                           spin_unlock(&dcache_lock);
+                           dput(dentry);
+                           goto inuse;
+                       }
+                   }
+
+                   __d_drop(dentry);
+                   spin_unlock(&dentry->d_lock);
+                   spin_unlock(&dcache_lock);
+                   dput(dentry);
+                   goto restart;
+
                 }
                 DUNLOCK();
-                d_prune_aliases(AFSTOI(tvc));
+inuse:
+
                 AFS_GLOCK();
                 AFS_FAST_RELE(tvc);
 #else