]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/nfs/delegation.c
Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm
[karo-tx-linux.git] / fs / nfs / delegation.c
index 484f147001083364bacc8d5a751a44c8473ed618..dff600ae0d7477333a3e41749cffe58ad77c7e3a 100644 (file)
@@ -195,15 +195,13 @@ void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred,
                        rcu_read_unlock();
                        put_rpccred(oldcred);
                        trace_nfs4_reclaim_delegation(inode, res->delegation_type);
-               } else {
-                       /* We appear to have raced with a delegation return. */
-                       spin_unlock(&delegation->lock);
-                       rcu_read_unlock();
-                       nfs_inode_set_delegation(inode, cred, res);
+                       return;
                }
-       } else {
-               rcu_read_unlock();
+               /* We appear to have raced with a delegation return. */
+               spin_unlock(&delegation->lock);
        }
+       rcu_read_unlock();
+       nfs_inode_set_delegation(inode, cred, res);
 }
 
 static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation *delegation, int issync)
@@ -664,18 +662,24 @@ static bool nfs_revoke_delegation(struct inode *inode,
                const nfs4_stateid *stateid)
 {
        struct nfs_delegation *delegation;
+       nfs4_stateid tmp;
        bool ret = false;
 
        rcu_read_lock();
        delegation = rcu_dereference(NFS_I(inode)->delegation);
        if (delegation == NULL)
                goto out;
-       if (stateid && !nfs4_stateid_match(stateid, &delegation->stateid))
+       if (stateid == NULL) {
+               nfs4_stateid_copy(&tmp, &delegation->stateid);
+               stateid = &tmp;
+       } else if (!nfs4_stateid_match(stateid, &delegation->stateid))
                goto out;
        nfs_mark_delegation_revoked(NFS_SERVER(inode), delegation);
        ret = true;
 out:
        rcu_read_unlock();
+       if (ret)
+               nfs_inode_find_state_and_recover(inode, stateid);
        return ret;
 }
 
@@ -687,10 +691,8 @@ void nfs_remove_bad_delegation(struct inode *inode,
        if (!nfs_revoke_delegation(inode, stateid))
                return;
        delegation = nfs_inode_detach_delegation(inode);
-       if (delegation) {
-               nfs_inode_find_state_and_recover(inode, &delegation->stateid);
+       if (delegation)
                nfs_free_delegation(delegation);
-       }
 }
 EXPORT_SYMBOL_GPL(nfs_remove_bad_delegation);
 
@@ -1001,6 +1003,25 @@ restart:
        rcu_read_unlock();
 }
 
+void nfs_inode_find_delegation_state_and_recover(struct inode *inode,
+               const nfs4_stateid *stateid)
+{
+       struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
+       struct nfs_delegation *delegation;
+       bool found = false;
+
+       rcu_read_lock();
+       delegation = rcu_dereference(NFS_I(inode)->delegation);
+       if (delegation &&
+           nfs4_stateid_match_other(&delegation->stateid, stateid)) {
+               nfs_mark_test_expired_delegation(NFS_SERVER(inode), delegation);
+               found = true;
+       }
+       rcu_read_unlock();
+       if (found)
+               nfs4_schedule_state_manager(clp);
+}
+
 /**
  * nfs_delegations_present - check for existence of delegations
  * @clp: client state handle