Merge branch '40GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/net...
[cascardo/linux.git] / fs / nfs / delegation.c
index 0ffead2..dff600a 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)
@@ -656,6 +654,7 @@ static void nfs_mark_delegation_revoked(struct nfs_server *server,
                struct nfs_delegation *delegation)
 {
        set_bit(NFS_DELEGATION_REVOKED, &delegation->flags);
+       delegation->stateid.type = NFS4_INVALID_STATEID_TYPE;
        nfs_mark_return_delegation(server, delegation);
 }
 
@@ -663,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;
 }
 
@@ -686,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);
 
@@ -894,6 +897,8 @@ static inline bool nfs4_server_rebooted(const struct nfs_client *clp)
 static void nfs_mark_test_expired_delegation(struct nfs_server *server,
            struct nfs_delegation *delegation)
 {
+       if (delegation->stateid.type == NFS4_INVALID_STATEID_TYPE)
+               return;
        clear_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags);
        set_bit(NFS_DELEGATION_TEST_EXPIRED, &delegation->flags);
        set_bit(NFS4CLNT_DELEGATION_EXPIRED, &server->nfs_client->cl_state);
@@ -998,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