summaryrefslogtreecommitdiff
path: root/fs/nfs/nfs4proc.c
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.com>2015-06-29 14:28:54 +1000
committerTrond Myklebust <trond.myklebust@primarydata.com>2015-06-29 09:17:13 -0400
commit39f897fdbd46873defc8501102124f862e8f4d80 (patch)
tree0c55285eb2b01e4c764a11e7220f21494954ef01 /fs/nfs/nfs4proc.c
parent6c5a0d891543873aefc3aaf846c1e7afe0982ff9 (diff)
downloadlwn-39f897fdbd46873defc8501102124f862e8f4d80.tar.gz
lwn-39f897fdbd46873defc8501102124f862e8f4d80.zip
NFSv4: When returning a delegation, don't reclaim an incompatible open mode.
It is possible to have an active open with one mode, and a delegation for the same file with a different mode. In particular, a WR_ONLY open and an RD_ONLY delegation. This happens if a WR_ONLY open is followed by a RD_ONLY open which provides a delegation, but is then close. When returning the delegation, we currently try to claim opens for every open type (n_rdwr, n_rdonly, n_wronly). As there is no harm in claiming an open for a mode that we already have, this is often simplest. However if the delegation only provides a subset of the modes that we currently have open, this will produce an error from the server. So when claiming open modes prior to returning a delegation, skip the open request if the mode is not covered by the delegation - the open_stateid must already cover that mode, so there is nothing to do. Signed-off-by: NeilBrown <neilb@suse.de> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r--fs/nfs/nfs4proc.c7
1 files changed, 7 insertions, 0 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 8eab42407d39..605c203de556 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -1547,6 +1547,13 @@ static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, fmode_t fmod
struct nfs4_state *newstate;
int ret;
+ if ((opendata->o_arg.claim == NFS4_OPEN_CLAIM_DELEGATE_CUR ||
+ opendata->o_arg.claim == NFS4_OPEN_CLAIM_DELEG_CUR_FH) &&
+ (opendata->o_arg.u.delegation_type & fmode) != fmode)
+ /* This mode can't have been delegated, so we must have
+ * a valid open_stateid to cover it - not need to reclaim.
+ */
+ return 0;
opendata->o_arg.open_flags = 0;
opendata->o_arg.fmode = fmode;
opendata->o_arg.share_access = nfs4_map_atomic_open_share(