diff options
author | Trond Myklebust <trond.myklebust@primarydata.com> | 2014-08-25 22:09:08 -0400 |
---|---|---|
committer | Trond Myklebust <trond.myklebust@primarydata.com> | 2014-08-26 16:17:48 -0400 |
commit | 412f6c4c26fb1eba8844290663837561ac53fa6e (patch) | |
tree | 51fedde9765c9060328cd2d190cc634784234bf2 | |
parent | aee7af356e151494d5014f57b33460b162f181b5 (diff) |
NFSv4: Don't clear the open state when we just did an OPEN_DOWNGRADE
If we did an OPEN_DOWNGRADE, then the right thing to do on success, is
to apply the new open mode to the struct nfs4_state. Instead, we were
unconditionally clearing the state, making it appear to our state
machinery as if we had just performed a CLOSE.
Fixes: 226056c5c312b (NFSv4: Use correct locking when updating nfs4_state...)
Cc: stable@vger.kernel.org # 3.15+
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
-rw-r--r-- | fs/nfs/nfs4proc.c | 9 |
1 files changed, 5 insertions, 4 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index ff94a2f36051..7dd8aca31c29 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -2560,6 +2560,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
2560 | struct nfs4_closedata *calldata = data; | 2560 | struct nfs4_closedata *calldata = data; |
2561 | struct nfs4_state *state = calldata->state; | 2561 | struct nfs4_state *state = calldata->state; |
2562 | struct nfs_server *server = NFS_SERVER(calldata->inode); | 2562 | struct nfs_server *server = NFS_SERVER(calldata->inode); |
2563 | nfs4_stateid *res_stateid = NULL; | ||
2563 | 2564 | ||
2564 | dprintk("%s: begin!\n", __func__); | 2565 | dprintk("%s: begin!\n", __func__); |
2565 | if (!nfs4_sequence_done(task, &calldata->res.seq_res)) | 2566 | if (!nfs4_sequence_done(task, &calldata->res.seq_res)) |
@@ -2570,12 +2571,12 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
2570 | */ | 2571 | */ |
2571 | switch (task->tk_status) { | 2572 | switch (task->tk_status) { |
2572 | case 0: | 2573 | case 0: |
2573 | if (calldata->roc) | 2574 | res_stateid = &calldata->res.stateid; |
2575 | if (calldata->arg.fmode == 0 && calldata->roc) | ||
2574 | pnfs_roc_set_barrier(state->inode, | 2576 | pnfs_roc_set_barrier(state->inode, |
2575 | calldata->roc_barrier); | 2577 | calldata->roc_barrier); |
2576 | nfs_clear_open_stateid(state, &calldata->res.stateid, 0); | ||
2577 | renew_lease(server, calldata->timestamp); | 2578 | renew_lease(server, calldata->timestamp); |
2578 | goto out_release; | 2579 | break; |
2579 | case -NFS4ERR_ADMIN_REVOKED: | 2580 | case -NFS4ERR_ADMIN_REVOKED: |
2580 | case -NFS4ERR_STALE_STATEID: | 2581 | case -NFS4ERR_STALE_STATEID: |
2581 | case -NFS4ERR_OLD_STATEID: | 2582 | case -NFS4ERR_OLD_STATEID: |
@@ -2589,7 +2590,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
2589 | goto out_release; | 2590 | goto out_release; |
2590 | } | 2591 | } |
2591 | } | 2592 | } |
2592 | nfs_clear_open_stateid(state, NULL, calldata->arg.fmode); | 2593 | nfs_clear_open_stateid(state, res_stateid, calldata->arg.fmode); |
2593 | out_release: | 2594 | out_release: |
2594 | nfs_release_seqid(calldata->arg.seqid); | 2595 | nfs_release_seqid(calldata->arg.seqid); |
2595 | nfs_refresh_inode(calldata->inode, calldata->res.fattr); | 2596 | nfs_refresh_inode(calldata->inode, calldata->res.fattr); |