aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@primarydata.com>2014-09-18 11:51:32 -0400
committerTrond Myklebust <trond.myklebust@primarydata.com>2014-09-18 13:04:22 -0400
commitcd9288ffaea4359d5cfe2b8d264911506aed26a4 (patch)
tree82bddbe31030ef1c460d0df957afb55ff1d99283 /fs/nfs
parent080af20cc945d110f9912d01cf6b66f94a375b8d (diff)
NFSv4: Fix another bug in the close/open_downgrade code
James Drew reports another bug whereby the NFS client is now sending an OPEN_DOWNGRADE in a situation where it should really have sent a CLOSE: the client is opening the file for O_RDWR, but then trying to do a downgrade to O_RDONLY, which is not allowed by the NFSv4 spec. Reported-by: James Drews <drews@engr.wisc.edu> Link: http://lkml.kernel.org/r/541AD7E5.8020409@engr.wisc.edu Fixes: aee7af356e15 (NFSv4: Fix problems with close in the presence...) Cc: stable@vger.kernel.org # 2.6.33+ Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/nfs4proc.c30
1 files changed, 15 insertions, 15 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index ac2dd953fc18..6ca0c8e7a945 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -2618,23 +2618,23 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
2618 is_rdwr = test_bit(NFS_O_RDWR_STATE, &state->flags); 2618 is_rdwr = test_bit(NFS_O_RDWR_STATE, &state->flags);
2619 is_rdonly = test_bit(NFS_O_RDONLY_STATE, &state->flags); 2619 is_rdonly = test_bit(NFS_O_RDONLY_STATE, &state->flags);
2620 is_wronly = test_bit(NFS_O_WRONLY_STATE, &state->flags); 2620 is_wronly = test_bit(NFS_O_WRONLY_STATE, &state->flags);
2621 /* Calculate the current open share mode */
2622 calldata->arg.fmode = 0;
2623 if (is_rdonly || is_rdwr)
2624 calldata->arg.fmode |= FMODE_READ;
2625 if (is_wronly || is_rdwr)
2626 calldata->arg.fmode |= FMODE_WRITE;
2627 /* Calculate the change in open mode */ 2621 /* Calculate the change in open mode */
2622 calldata->arg.fmode = 0;
2628 if (state->n_rdwr == 0) { 2623 if (state->n_rdwr == 0) {
2629 if (state->n_rdonly == 0) { 2624 if (state->n_rdonly == 0)
2630 call_close |= is_rdonly || is_rdwr; 2625 call_close |= is_rdonly;
2631 calldata->arg.fmode &= ~FMODE_READ; 2626 else if (is_rdonly)
2632 } 2627 calldata->arg.fmode |= FMODE_READ;
2633 if (state->n_wronly == 0) { 2628 if (state->n_wronly == 0)
2634 call_close |= is_wronly || is_rdwr; 2629 call_close |= is_wronly;
2635 calldata->arg.fmode &= ~FMODE_WRITE; 2630 else if (is_wronly)
2636 } 2631 calldata->arg.fmode |= FMODE_WRITE;
2637 } 2632 } else if (is_rdwr)
2633 calldata->arg.fmode |= FMODE_READ|FMODE_WRITE;
2634
2635 if (calldata->arg.fmode == 0)
2636 call_close |= is_rdwr;
2637
2638 if (!nfs4_valid_open_stateid(state)) 2638 if (!nfs4_valid_open_stateid(state))
2639 call_close = 0; 2639 call_close = 0;
2640 spin_unlock(&state->owner->so_lock); 2640 spin_unlock(&state->owner->so_lock);