Commit 5bd3c047 authored by Trond Myklebust's avatar Trond Myklebust Committed by Ben Hutchings

NFSv4: Fix another bug in the close/open_downgrade code

commit cd9288ff upstream.

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: default avatarJames Drews <drews@engr.wisc.edu>
Link: http://lkml.kernel.org/r/541AD7E5.8020409@engr.wisc.edu
Fixes: aee7af35 (NFSv4: Fix problems with close in the presence...)
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@primarydata.com>
[bwh: Backported to 3.2: adjust context]
Signed-off-by: default avatarBen Hutchings <ben@decadent.org.uk>
parent 63cb95ba
...@@ -2015,23 +2015,23 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) ...@@ -2015,23 +2015,23 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
is_rdwr = test_bit(NFS_O_RDWR_STATE, &state->flags); is_rdwr = test_bit(NFS_O_RDWR_STATE, &state->flags);
is_rdonly = test_bit(NFS_O_RDONLY_STATE, &state->flags); is_rdonly = test_bit(NFS_O_RDONLY_STATE, &state->flags);
is_wronly = test_bit(NFS_O_WRONLY_STATE, &state->flags); is_wronly = test_bit(NFS_O_WRONLY_STATE, &state->flags);
/* Calculate the current open share mode */
calldata->arg.fmode = 0;
if (is_rdonly || is_rdwr)
calldata->arg.fmode |= FMODE_READ;
if (is_wronly || is_rdwr)
calldata->arg.fmode |= FMODE_WRITE;
/* Calculate the change in open mode */ /* Calculate the change in open mode */
calldata->arg.fmode = 0;
if (state->n_rdwr == 0) { if (state->n_rdwr == 0) {
if (state->n_rdonly == 0) { if (state->n_rdonly == 0)
call_close |= is_rdonly || is_rdwr; call_close |= is_rdonly;
calldata->arg.fmode &= ~FMODE_READ; else if (is_rdonly)
} calldata->arg.fmode |= FMODE_READ;
if (state->n_wronly == 0) { if (state->n_wronly == 0)
call_close |= is_wronly || is_rdwr; call_close |= is_wronly;
calldata->arg.fmode &= ~FMODE_WRITE; else if (is_wronly)
} calldata->arg.fmode |= FMODE_WRITE;
} } else if (is_rdwr)
calldata->arg.fmode |= FMODE_READ|FMODE_WRITE;
if (calldata->arg.fmode == 0)
call_close |= is_rdwr;
spin_unlock(&state->owner->so_lock); spin_unlock(&state->owner->so_lock);
if (!call_close) { if (!call_close) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment