diff options
author | Trond Myklebust <trond.myklebust@primarydata.com> | 2014-09-18 11:51:32 -0400 |
---|---|---|
committer | Ben Hutchings <ben@decadent.org.uk> | 2014-11-05 20:27:44 +0000 |
commit | 5bd3c0477993f54bac2c4618655e4102ffe1fab4 (patch) | |
tree | 7aa1a11c97256116abb9f455677f5887a33e0db7 /fs/nfs | |
parent | 63cb95ba25b2377728536a8114cd05105dd370d4 (diff) | |
download | kernel_samsung_smdk4412-5bd3c0477993f54bac2c4618655e4102ffe1fab4.zip kernel_samsung_smdk4412-5bd3c0477993f54bac2c4618655e4102ffe1fab4.tar.gz kernel_samsung_smdk4412-5bd3c0477993f54bac2c4618655e4102ffe1fab4.tar.bz2 |
NFSv4: Fix another bug in the close/open_downgrade code
commit cd9288ffaea4359d5cfe2b8d264911506aed26a4 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: 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...)
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
[bwh: Backported to 3.2: adjust context]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/nfs4proc.c | 30 |
1 files changed, 15 insertions, 15 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index c4a2a68..61a1303 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -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_rdonly = test_bit(NFS_O_RDONLY_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 */ + calldata->arg.fmode = 0; if (state->n_rdwr == 0) { - if (state->n_rdonly == 0) { - call_close |= is_rdonly || is_rdwr; - calldata->arg.fmode &= ~FMODE_READ; - } - if (state->n_wronly == 0) { - call_close |= is_wronly || is_rdwr; - calldata->arg.fmode &= ~FMODE_WRITE; - } - } + if (state->n_rdonly == 0) + call_close |= is_rdonly; + else if (is_rdonly) + calldata->arg.fmode |= FMODE_READ; + if (state->n_wronly == 0) + call_close |= is_wronly; + 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); if (!call_close) { |