NFSv4.1: Only reap expired delegations
authorTrond Myklebust <trond.myklebust@hammerspace.com>
Fri, 26 Jul 2019 13:40:53 +0000 (14:40 +0100)
committerTrond Myklebust <trond.myklebust@hammerspace.com>
Mon, 5 Aug 2019 02:35:40 +0000 (22:35 -0400)
Fix nfs_reap_expired_delegations() to ensure that we only reap delegations
that are actually expired, rather than triggering on random errors.

Fixes: 45870d6909d5a ("NFSv4.1: Test delegation stateids when server...")
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
fs/nfs/delegation.c

index 0af854cce8ffa08958eb8ee584d82db5d78e0f6e..071b90a45933a4b95c176e8042a29130e07a71f1 100644 (file)
@@ -1046,6 +1046,22 @@ void nfs_test_expired_all_delegations(struct nfs_client *clp)
        nfs4_schedule_state_manager(clp);
 }
 
+static void
+nfs_delegation_test_free_expired(struct inode *inode,
+               nfs4_stateid *stateid,
+               const struct cred *cred)
+{
+       struct nfs_server *server = NFS_SERVER(inode);
+       const struct nfs4_minor_version_ops *ops = server->nfs_client->cl_mvops;
+       int status;
+
+       if (!cred)
+               return;
+       status = ops->test_and_free_expired(server, stateid, cred);
+       if (status == -NFS4ERR_EXPIRED || status == -NFS4ERR_BAD_STATEID)
+               nfs_remove_bad_delegation(inode, stateid);
+}
+
 /**
  * nfs_reap_expired_delegations - reap expired delegations
  * @clp: nfs_client to process
@@ -1057,7 +1073,6 @@ void nfs_test_expired_all_delegations(struct nfs_client *clp)
  */
 void nfs_reap_expired_delegations(struct nfs_client *clp)
 {
-       const struct nfs4_minor_version_ops *ops = clp->cl_mvops;
        struct nfs_delegation *delegation;
        struct nfs_server *server;
        struct inode *inode;
@@ -1088,11 +1103,7 @@ restart:
                        nfs4_stateid_copy(&stateid, &delegation->stateid);
                        clear_bit(NFS_DELEGATION_TEST_EXPIRED, &delegation->flags);
                        rcu_read_unlock();
-                       if (cred != NULL &&
-                           ops->test_and_free_expired(server, &stateid, cred) < 0) {
-                               nfs_revoke_delegation(inode, &stateid);
-                               nfs_inode_find_state_and_recover(inode, &stateid);
-                       }
+                       nfs_delegation_test_free_expired(inode, &stateid, cred);
                        put_cred(cred);
                        if (nfs4_server_rebooted(clp)) {
                                nfs_inode_mark_test_expired_delegation(server,inode);