]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
NFSv4.1: Ensure we always run TEST/FREE_STATEID on locks
authorTrond Myklebust <trond.myklebust@primarydata.com>
Thu, 22 Sep 2016 17:39:03 +0000 (13:39 -0400)
committerAnna Schumaker <Anna.Schumaker@Netapp.com>
Tue, 27 Sep 2016 18:34:12 +0000 (14:34 -0400)
Right now, we're only running TEST/FREE_STATEID on the locks if
the open stateid recovery succeeds. The protocol requires us to
always do so.
The fix would be to move the call to TEST/FREE_STATEID and do it
before we attempt open recovery.

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

index 02eab9113273a6f32242bef73dc220411b3bd77c..b5290fd992096d535fb8c2ae10a6cd9351d33755 100644 (file)
@@ -2485,6 +2485,45 @@ static void nfs41_check_delegation_stateid(struct nfs4_state *state)
        put_rpccred(cred);
 }
 
+/**
+ * nfs41_check_expired_locks - possibly free a lock stateid
+ *
+ * @state: NFSv4 state for an inode
+ *
+ * Returns NFS_OK if recovery for this stateid is now finished.
+ * Otherwise a negative NFS4ERR value is returned.
+ */
+static int nfs41_check_expired_locks(struct nfs4_state *state)
+{
+       int status, ret = NFS_OK;
+       struct nfs4_lock_state *lsp;
+       struct nfs_server *server = NFS_SERVER(state->inode);
+
+       if (!test_bit(LK_STATE_IN_USE, &state->flags))
+               goto out;
+       list_for_each_entry(lsp, &state->lock_states, ls_locks) {
+               if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) {
+                       struct rpc_cred *cred = lsp->ls_state->owner->so_cred;
+
+                       status = nfs41_test_and_free_expired_stateid(server,
+                                       &lsp->ls_stateid,
+                                       cred);
+                       trace_nfs4_test_lock_stateid(state, lsp, status);
+                       if (status == -NFS4ERR_EXPIRED ||
+                           status == -NFS4ERR_BAD_STATEID) {
+                               clear_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags);
+                               if (!recover_lost_locks)
+                                       set_bit(NFS_LOCK_LOST, &lsp->ls_flags);
+                       } else if (status != NFS_OK) {
+                               ret = status;
+                               break;
+                       }
+               }
+       };
+out:
+       return ret;
+}
+
 /**
  * nfs41_check_open_stateid - possibly free an open stateid
  *
@@ -2522,6 +2561,9 @@ static int nfs41_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st
        int status;
 
        nfs41_check_delegation_stateid(state);
+       status = nfs41_check_expired_locks(state);
+       if (status != NFS_OK)
+               return status;
        status = nfs41_check_open_stateid(state);
        if (status != NFS_OK)
                status = nfs4_open_expired(sp, state);
@@ -6106,49 +6148,19 @@ out:
 }
 
 #if defined(CONFIG_NFS_V4_1)
-/**
- * nfs41_check_expired_locks - possibly free a lock stateid
- *
- * @state: NFSv4 state for an inode
- *
- * Returns NFS_OK if recovery for this stateid is now finished.
- * Otherwise a negative NFS4ERR value is returned.
- */
-static int nfs41_check_expired_locks(struct nfs4_state *state)
-{
-       int status, ret = NFS_OK;
-       struct nfs4_lock_state *lsp;
-       struct nfs_server *server = NFS_SERVER(state->inode);
-
-       list_for_each_entry(lsp, &state->lock_states, ls_locks) {
-               if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) {
-                       struct rpc_cred *cred = lsp->ls_state->owner->so_cred;
-
-                       status = nfs41_test_and_free_expired_stateid(server,
-                                       &lsp->ls_stateid,
-                                       cred);
-                       trace_nfs4_test_lock_stateid(state, lsp, status);
-                       if (status == -NFS4ERR_EXPIRED ||
-                           status == -NFS4ERR_BAD_STATEID)
-                               clear_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags);
-                       else if (status != NFS_OK) {
-                               ret = status;
-                               break;
-                       }
-               }
-       };
-
-       return ret;
-}
-
 static int nfs41_lock_expired(struct nfs4_state *state, struct file_lock *request)
 {
-       int status = NFS_OK;
+       struct nfs4_lock_state *lsp;
+       int status;
 
-       if (test_bit(LK_STATE_IN_USE, &state->flags))
-               status = nfs41_check_expired_locks(state);
-       if (status != NFS_OK)
-               status = nfs4_lock_expired(state, request);
+       status = nfs4_set_lock_state(state, request);
+       if (status != 0)
+               return status;
+       lsp = request->fl_u.nfs4_fl.owner;
+       if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) ||
+           test_bit(NFS_LOCK_LOST, &lsp->ls_flags))
+               return 0;
+       status = nfs4_lock_expired(state, request);
        return status;
 }
 #endif