diff options
author | Andrew Elble <aweits@rit.edu> | 2017-11-03 14:06:31 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2017-11-07 16:44:02 -0500 |
commit | 95da1b3a5aded124dd1bda1e3cdb876184813140 (patch) | |
tree | 6764bb8c88390cdfc1cdee2733b3be6767e3e9e2 /fs/nfsd | |
parent | 77a08867a66796f8316449e030e0bfc84f2a3f66 (diff) |
nfsd: deal with revoked delegations appropriately
If a delegation has been revoked by the server, operations using that
delegation should error out with NFS4ERR_DELEG_REVOKED in the >4.1
case, and NFS4ERR_BAD_STATEID otherwise.
The server needs NFSv4.1 clients to explicitly free revoked delegations.
If the server returns NFS4ERR_DELEG_REVOKED, the client will do that;
otherwise it may just forget about the delegation and be unable to
recover when it later sees SEQ4_STATUS_RECALLABLE_STATE_REVOKED set on a
SEQUENCE reply. That can cause the Linux 4.1 client to loop in its
stage manager.
Signed-off-by: Andrew Elble <aweits@rit.edu>
Reviewed-by: Trond Myklebust <trond.myklebust@primarydata.com>
Cc: stable@vger.kernel.org
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/nfs4state.c | 25 |
1 files changed, 24 insertions, 1 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index ecbc7b0dfa4d..b82817767b9d 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -4016,7 +4016,8 @@ static struct nfs4_delegation *find_deleg_stateid(struct nfs4_client *cl, statei | |||
4016 | { | 4016 | { |
4017 | struct nfs4_stid *ret; | 4017 | struct nfs4_stid *ret; |
4018 | 4018 | ||
4019 | ret = find_stateid_by_type(cl, s, NFS4_DELEG_STID); | 4019 | ret = find_stateid_by_type(cl, s, |
4020 | NFS4_DELEG_STID|NFS4_REVOKED_DELEG_STID); | ||
4020 | if (!ret) | 4021 | if (!ret) |
4021 | return NULL; | 4022 | return NULL; |
4022 | return delegstateid(ret); | 4023 | return delegstateid(ret); |
@@ -4039,6 +4040,12 @@ nfs4_check_deleg(struct nfs4_client *cl, struct nfsd4_open *open, | |||
4039 | deleg = find_deleg_stateid(cl, &open->op_delegate_stateid); | 4040 | deleg = find_deleg_stateid(cl, &open->op_delegate_stateid); |
4040 | if (deleg == NULL) | 4041 | if (deleg == NULL) |
4041 | goto out; | 4042 | goto out; |
4043 | if (deleg->dl_stid.sc_type == NFS4_REVOKED_DELEG_STID) { | ||
4044 | nfs4_put_stid(&deleg->dl_stid); | ||
4045 | if (cl->cl_minorversion) | ||
4046 | status = nfserr_deleg_revoked; | ||
4047 | goto out; | ||
4048 | } | ||
4042 | flags = share_access_to_flags(open->op_share_access); | 4049 | flags = share_access_to_flags(open->op_share_access); |
4043 | status = nfs4_check_delegmode(deleg, flags); | 4050 | status = nfs4_check_delegmode(deleg, flags); |
4044 | if (status) { | 4051 | if (status) { |
@@ -4908,6 +4915,16 @@ nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, | |||
4908 | struct nfs4_stid **s, struct nfsd_net *nn) | 4915 | struct nfs4_stid **s, struct nfsd_net *nn) |
4909 | { | 4916 | { |
4910 | __be32 status; | 4917 | __be32 status; |
4918 | bool return_revoked = false; | ||
4919 | |||
4920 | /* | ||
4921 | * only return revoked delegations if explicitly asked. | ||
4922 | * otherwise we report revoked or bad_stateid status. | ||
4923 | */ | ||
4924 | if (typemask & NFS4_REVOKED_DELEG_STID) | ||
4925 | return_revoked = true; | ||
4926 | else if (typemask & NFS4_DELEG_STID) | ||
4927 | typemask |= NFS4_REVOKED_DELEG_STID; | ||
4911 | 4928 | ||
4912 | if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) | 4929 | if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) |
4913 | return nfserr_bad_stateid; | 4930 | return nfserr_bad_stateid; |
@@ -4922,6 +4939,12 @@ nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, | |||
4922 | *s = find_stateid_by_type(cstate->clp, stateid, typemask); | 4939 | *s = find_stateid_by_type(cstate->clp, stateid, typemask); |
4923 | if (!*s) | 4940 | if (!*s) |
4924 | return nfserr_bad_stateid; | 4941 | return nfserr_bad_stateid; |
4942 | if (((*s)->sc_type == NFS4_REVOKED_DELEG_STID) && !return_revoked) { | ||
4943 | nfs4_put_stid(*s); | ||
4944 | if (cstate->minorversion) | ||
4945 | return nfserr_deleg_revoked; | ||
4946 | return nfserr_bad_stateid; | ||
4947 | } | ||
4925 | return nfs_ok; | 4948 | return nfs_ok; |
4926 | } | 4949 | } |
4927 | 4950 | ||