linux: defer vcache evictions when sleep would be needed
[openafs.git] / src / afs / LINUX / osi_vcache.c
index fbe6fd8..e82d78e 100644 (file)
 #include "afsincludes.h"        /*AFS-based standard headers */
 
 int
-osi_TryEvictVCache(struct vcache *avc, int *slept) {
+osi_TryEvictVCache(struct vcache *avc, int *slept, int defersleep) {
     int code;
 
     struct dentry *dentry;
+    struct inode *inode = AFSTOV(avc);
     struct list_head *cur, *head;
 
     /* First, see if we can evict the inode from the dcache */
-    if (avc != afs_globalVp && VREFCOUNT(avc) > 1 && avc->opens == 0) {
+    if (defersleep && avc != afs_globalVp && VREFCOUNT(avc) > 1 && avc->opens == 0) {
+       *slept = 1;
+       ReleaseWriteLock(&afs_xvcache);
         AFS_GUNLOCK();
+
+#if defined(HAVE_DCACHE_LOCK)
         spin_lock(&dcache_lock);
-       head = &(AFSTOV(avc))->i_dentry;
+       head = &inode->i_dentry;
 
 restart:
         cur = head;
@@ -33,7 +38,6 @@ restart:
 
            if (d_unhashed(dentry))
                continue;
-
            dget_locked(dentry);
 
            spin_unlock(&dcache_lock);
@@ -47,17 +51,52 @@ restart:
            goto restart;
        }
        spin_unlock(&dcache_lock);
+#else /* HAVE_DCACHE_LOCK */
+       spin_lock(&inode->i_lock);
+       head = &inode->i_dentry;
+
+restart:
+       cur = head;
+       while ((cur = cur->next) != head) {
+           dentry = list_entry(cur, struct dentry, d_alias);
+
+           spin_lock(&dentry->d_lock);
+           if (d_unhashed(dentry)) {
+               spin_unlock(&dentry->d_lock);
+               continue;
+           }
+           spin_unlock(&dentry->d_lock);
+           dget(dentry);
+
+           spin_unlock(&inode->i_lock);
+           if (d_invalidate(dentry) == -EBUSY) {
+               dput(dentry);
+               /* perhaps lock and try to continue? (use cur as head?) */
+               goto inuse;
+           }
+           dput(dentry);
+           spin_lock(&inode->i_lock);
+           goto restart;
+       }
+       spin_unlock(&inode->i_lock);
+#endif /* HAVE_DCACHE_LOCK */
 inuse:
        AFS_GLOCK();
+       ObtainWriteLock(&afs_xvcache, 733);
     }
 
     /* See if we can evict it from the VLRUQ */
     if (VREFCOUNT_GT(avc,0) && !VREFCOUNT_GT(avc,1) && avc->opens == 0
        && (avc->f.states & CUnlinkedDel) == 0) {
+       int didsleep = *slept;
 
        code = afs_FlushVCache(avc, slept);
+       /* flushvcache wipes slept; restore slept if we did before */
+       if (didsleep)
+           *slept = didsleep;
+
        if (code == 0)
-          return 1;
+           return 1;
     }
 
     return 0;