NFSv4: Don't try to CLOSE if the stateid 'other' field has changed
authorTrond Myklebust <trond.myklebust@primarydata.com>
Mon, 6 Nov 2017 20:28:06 +0000 (15:28 -0500)
committerAnna Schumaker <Anna.Schumaker@Netapp.com>
Fri, 17 Nov 2017 21:43:47 +0000 (16:43 -0500)
If the stateid is no longer recognised on the server, either due to a
restart, or due to a competing CLOSE call, then we do not have to
retry. Any open contexts that triggered a reopen of the file, will
also act as triggers for any CLOSE for the updated stateids.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
fs/nfs/nfs4_fs.h
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c

index feb084bc55659e711aa035498d9b768f51a84f0c..9721b74786d116d0bf4dc805832425e170dca9f7 100644 (file)
@@ -462,6 +462,8 @@ extern int nfs4_select_rw_stateid(struct nfs4_state *, fmode_t,
                struct rpc_cred **);
 extern bool nfs4_refresh_open_stateid(nfs4_stateid *dst,
                struct nfs4_state *state);
+extern bool nfs4_copy_open_stateid(nfs4_stateid *dst,
+               struct nfs4_state *state);
 
 extern struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask);
 extern int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task);
index 3e385154196ae6539c44d34fb6ac98c5338ead7b..ef313d602a85746b9545e271cf81e505c5bda2b1 100644 (file)
@@ -3215,14 +3215,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
                                        task->tk_msg.rpc_cred);
                        /* Fallthrough */
                case -NFS4ERR_BAD_STATEID:
-                       if (!nfs4_stateid_match(&calldata->arg.stateid,
-                                               &state->open_stateid)) {
-                               rpc_restart_call_prepare(task);
-                               goto out_release;
-                       }
-                       if (calldata->arg.fmode == 0)
-                               break;
-                       /* Fallthrough */
+                       break;
                default:
                        if (nfs4_async_handle_error(task, server, state, NULL) == -EAGAIN) {
                                rpc_restart_call_prepare(task);
@@ -3254,7 +3247,6 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
        is_rdwr = test_bit(NFS_O_RDWR_STATE, &state->flags);
        is_rdonly = test_bit(NFS_O_RDONLY_STATE, &state->flags);
        is_wronly = test_bit(NFS_O_WRONLY_STATE, &state->flags);
-       nfs4_stateid_copy(&calldata->arg.stateid, &state->open_stateid);
        /* Calculate the change in open mode */
        calldata->arg.fmode = 0;
        if (state->n_rdwr == 0) {
@@ -3272,7 +3264,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
                calldata->arg.fmode |= FMODE_READ|FMODE_WRITE;
 
        if (!nfs4_valid_open_stateid(state) ||
-           test_bit(NFS_OPEN_STATE, &state->flags) == 0)
+           !nfs4_refresh_open_stateid(&calldata->arg.stateid, state))
                call_close = 0;
        spin_unlock(&state->owner->so_lock);
 
@@ -3366,6 +3358,8 @@ int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait)
        calldata->inode = state->inode;
        calldata->state = state;
        calldata->arg.fh = NFS_FH(state->inode);
+       if (!nfs4_copy_open_stateid(&calldata->arg.stateid, state))
+               goto out_free_calldata;
        /* Serialization for the sequence id */
        alloc_seqid = server->nfs_client->cl_mvops->alloc_seqid;
        calldata->arg.seqid = alloc_seqid(&state->owner->so_seqid, gfp_mask);
index cee1e000b41eac05b670a4b5688f1297a7d24ef8..b6a0cf7fa1f616521de94d6c63c41b095bfbaf86 100644 (file)
@@ -1002,18 +1002,23 @@ bool nfs4_refresh_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
        return ret;
 }
 
-static void nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
+bool nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
 {
+       bool ret;
        const nfs4_stateid *src;
        int seq;
 
        do {
+               ret = false;
                src = &zero_stateid;
                seq = read_seqbegin(&state->seqlock);
-               if (test_bit(NFS_OPEN_STATE, &state->flags))
+               if (test_bit(NFS_OPEN_STATE, &state->flags)) {
                        src = &state->open_stateid;
+                       ret = true;
+               }
                nfs4_stateid_copy(dst, src);
        } while (read_seqretry(&state->seqlock, seq));
+       return ret;
 }
 
 /*