]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/3.18.85/nfsd-deal-with-revoked-delegations-appropriately.patch
4.9-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 3.18.85 / nfsd-deal-with-revoked-delegations-appropriately.patch
1 From 95da1b3a5aded124dd1bda1e3cdb876184813140 Mon Sep 17 00:00:00 2001
2 From: Andrew Elble <aweits@rit.edu>
3 Date: Fri, 3 Nov 2017 14:06:31 -0400
4 Subject: nfsd: deal with revoked delegations appropriately
5
6 From: Andrew Elble <aweits@rit.edu>
7
8 commit 95da1b3a5aded124dd1bda1e3cdb876184813140 upstream.
9
10 If a delegation has been revoked by the server, operations using that
11 delegation should error out with NFS4ERR_DELEG_REVOKED in the >4.1
12 case, and NFS4ERR_BAD_STATEID otherwise.
13
14 The server needs NFSv4.1 clients to explicitly free revoked delegations.
15 If the server returns NFS4ERR_DELEG_REVOKED, the client will do that;
16 otherwise it may just forget about the delegation and be unable to
17 recover when it later sees SEQ4_STATUS_RECALLABLE_STATE_REVOKED set on a
18 SEQUENCE reply. That can cause the Linux 4.1 client to loop in its
19 stage manager.
20
21 Signed-off-by: Andrew Elble <aweits@rit.edu>
22 Reviewed-by: Trond Myklebust <trond.myklebust@primarydata.com>
23 Signed-off-by: J. Bruce Fields <bfields@redhat.com>
24 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
25
26 ---
27 fs/nfsd/nfs4state.c | 25 ++++++++++++++++++++++++-
28 1 file changed, 24 insertions(+), 1 deletion(-)
29
30 --- a/fs/nfsd/nfs4state.c
31 +++ b/fs/nfsd/nfs4state.c
32 @@ -3602,7 +3602,8 @@ static struct nfs4_delegation *find_dele
33 {
34 struct nfs4_stid *ret;
35
36 - ret = find_stateid_by_type(cl, s, NFS4_DELEG_STID);
37 + ret = find_stateid_by_type(cl, s,
38 + NFS4_DELEG_STID|NFS4_REVOKED_DELEG_STID);
39 if (!ret)
40 return NULL;
41 return delegstateid(ret);
42 @@ -3625,6 +3626,12 @@ nfs4_check_deleg(struct nfs4_client *cl,
43 deleg = find_deleg_stateid(cl, &open->op_delegate_stateid);
44 if (deleg == NULL)
45 goto out;
46 + if (deleg->dl_stid.sc_type == NFS4_REVOKED_DELEG_STID) {
47 + nfs4_put_stid(&deleg->dl_stid);
48 + if (cl->cl_minorversion)
49 + status = nfserr_deleg_revoked;
50 + goto out;
51 + }
52 flags = share_access_to_flags(open->op_share_access);
53 status = nfs4_check_delegmode(deleg, flags);
54 if (status) {
55 @@ -4451,6 +4458,16 @@ nfsd4_lookup_stateid(struct nfsd4_compou
56 struct nfs4_stid **s, struct nfsd_net *nn)
57 {
58 __be32 status;
59 + bool return_revoked = false;
60 +
61 + /*
62 + * only return revoked delegations if explicitly asked.
63 + * otherwise we report revoked or bad_stateid status.
64 + */
65 + if (typemask & NFS4_REVOKED_DELEG_STID)
66 + return_revoked = true;
67 + else if (typemask & NFS4_DELEG_STID)
68 + typemask |= NFS4_REVOKED_DELEG_STID;
69
70 if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
71 return nfserr_bad_stateid;
72 @@ -4465,6 +4482,12 @@ nfsd4_lookup_stateid(struct nfsd4_compou
73 *s = find_stateid_by_type(cstate->clp, stateid, typemask);
74 if (!*s)
75 return nfserr_bad_stateid;
76 + if (((*s)->sc_type == NFS4_REVOKED_DELEG_STID) && !return_revoked) {
77 + nfs4_put_stid(*s);
78 + if (cstate->minorversion)
79 + return nfserr_deleg_revoked;
80 + return nfserr_bad_stateid;
81 + }
82 return nfs_ok;
83 }
84