NFSv4.1: Allow revoked stateids to skip the call to TEST_STATEID
authorTrond Myklebust <trond.myklebust@primarydata.com>
Thu, 22 Sep 2016 17:39:02 +0000 (13:39 -0400)
committerAnna Schumaker <Anna.Schumaker@Netapp.com>
Tue, 27 Sep 2016 18:34:01 +0000 (14:34 -0400)
In some cases (e.g. when the SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED sequence
flag is set) we may already know that the stateid was revoked and that the
only valid operation we can call is FREE_STATEID. In those cases, allow
the stateid to carry the information in the type field, so that we skip
the redundant call to TEST_STATEID.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Tested-by: Oleg Drokin <green@linuxhacker.ru>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
fs/nfs/nfs4proc.c
include/linux/nfs4.h

index dfa46e4..02eab91 100644 (file)
@@ -2422,18 +2422,29 @@ static int nfs41_test_and_free_expired_stateid(struct nfs_server *server,
 {
        int status;
 
-       status = nfs41_test_stateid(server, stateid, cred);
+       switch (stateid->type) {
+       default:
+               break;
+       case NFS4_INVALID_STATEID_TYPE:
+       case NFS4_SPECIAL_STATEID_TYPE:
+               return -NFS4ERR_BAD_STATEID;
+       case NFS4_REVOKED_STATEID_TYPE:
+               goto out_free;
+       }
 
+       status = nfs41_test_stateid(server, stateid, cred);
        switch (status) {
        case -NFS4ERR_EXPIRED:
        case -NFS4ERR_ADMIN_REVOKED:
        case -NFS4ERR_DELEG_REVOKED:
-               /* Ack the revoked state to the server */
-               nfs41_free_stateid(server, stateid, cred);
-       case -NFS4ERR_BAD_STATEID:
+               break;
+       default:
                return status;
        }
-       return NFS_OK;
+out_free:
+       /* Ack the revoked state to the server */
+       nfs41_free_stateid(server, stateid, cred);
+       return -NFS4ERR_EXPIRED;
 }
 
 static void nfs41_check_delegation_stateid(struct nfs4_state *state)
@@ -2468,7 +2479,7 @@ static void nfs41_check_delegation_stateid(struct nfs4_state *state)
        rcu_read_unlock();
        status = nfs41_test_and_free_expired_stateid(server, &stateid, cred);
        trace_nfs4_test_delegation_stateid(state, NULL, status);
-       if (status != NFS_OK)
+       if (status == -NFS4ERR_EXPIRED || status == -NFS4ERR_BAD_STATEID)
                nfs_finish_clear_delegation_stateid(state, &stateid);
 
        put_rpccred(cred);
@@ -2497,7 +2508,7 @@ static int nfs41_check_open_stateid(struct nfs4_state *state)
 
        status = nfs41_test_and_free_expired_stateid(server, stateid, cred);
        trace_nfs4_test_open_stateid(state, NULL, status);
-       if (status != NFS_OK) {
+       if (status == -NFS4ERR_EXPIRED || status == -NFS4ERR_BAD_STATEID) {
                clear_bit(NFS_O_RDONLY_STATE, &state->flags);
                clear_bit(NFS_O_WRONLY_STATE, &state->flags);
                clear_bit(NFS_O_RDWR_STATE, &state->flags);
@@ -6105,7 +6116,7 @@ out:
  */
 static int nfs41_check_expired_locks(struct nfs4_state *state)
 {
-       int status, ret = -NFS4ERR_BAD_STATEID;
+       int status, ret = NFS_OK;
        struct nfs4_lock_state *lsp;
        struct nfs_server *server = NFS_SERVER(state->inode);
 
@@ -6117,9 +6128,12 @@ static int nfs41_check_expired_locks(struct nfs4_state *state)
                                        &lsp->ls_stateid,
                                        cred);
                        trace_nfs4_test_lock_stateid(state, lsp, status);
-                       if (status != NFS_OK) {
+                       if (status == -NFS4ERR_EXPIRED ||
+                           status == -NFS4ERR_BAD_STATEID)
                                clear_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags);
+                       else if (status != NFS_OK) {
                                ret = status;
+                               break;
                        }
                }
        };
index c6564ad..9094faf 100644 (file)
@@ -67,6 +67,7 @@ struct nfs4_stateid_struct {
                NFS4_DELEGATION_STATEID_TYPE,
                NFS4_LAYOUT_STATEID_TYPE,
                NFS4_PNFS_DS_STATEID_TYPE,
+               NFS4_REVOKED_STATEID_TYPE,
        } type;
 };