Skip to content

Commit a8b8ab7

Browse files
aweitsgregkh
authored andcommitted
nfsd: deal with revoked delegations appropriately
commit 95da1b3a5aded124dd1bda1e3cdb876184813140 upstream. 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> Signed-off-by: J. Bruce Fields <bfields@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 2a2d4b4 commit a8b8ab7

1 file changed

Lines changed: 24 additions & 1 deletion

File tree

fs/nfsd/nfs4state.c

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3829,7 +3829,8 @@ static struct nfs4_delegation *find_deleg_stateid(struct nfs4_client *cl, statei
38293829
{
38303830
struct nfs4_stid *ret;
38313831

3832-
ret = find_stateid_by_type(cl, s, NFS4_DELEG_STID);
3832+
ret = find_stateid_by_type(cl, s,
3833+
NFS4_DELEG_STID|NFS4_REVOKED_DELEG_STID);
38333834
if (!ret)
38343835
return NULL;
38353836
return delegstateid(ret);
@@ -3852,6 +3853,12 @@ nfs4_check_deleg(struct nfs4_client *cl, struct nfsd4_open *open,
38523853
deleg = find_deleg_stateid(cl, &open->op_delegate_stateid);
38533854
if (deleg == NULL)
38543855
goto out;
3856+
if (deleg->dl_stid.sc_type == NFS4_REVOKED_DELEG_STID) {
3857+
nfs4_put_stid(&deleg->dl_stid);
3858+
if (cl->cl_minorversion)
3859+
status = nfserr_deleg_revoked;
3860+
goto out;
3861+
}
38553862
flags = share_access_to_flags(open->op_share_access);
38563863
status = nfs4_check_delegmode(deleg, flags);
38573864
if (status) {
@@ -4696,6 +4703,16 @@ nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate,
46964703
struct nfs4_stid **s, struct nfsd_net *nn)
46974704
{
46984705
__be32 status;
4706+
bool return_revoked = false;
4707+
4708+
/*
4709+
* only return revoked delegations if explicitly asked.
4710+
* otherwise we report revoked or bad_stateid status.
4711+
*/
4712+
if (typemask & NFS4_REVOKED_DELEG_STID)
4713+
return_revoked = true;
4714+
else if (typemask & NFS4_DELEG_STID)
4715+
typemask |= NFS4_REVOKED_DELEG_STID;
46994716

47004717
if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
47014718
return nfserr_bad_stateid;
@@ -4710,6 +4727,12 @@ nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate,
47104727
*s = find_stateid_by_type(cstate->clp, stateid, typemask);
47114728
if (!*s)
47124729
return nfserr_bad_stateid;
4730+
if (((*s)->sc_type == NFS4_REVOKED_DELEG_STID) && !return_revoked) {
4731+
nfs4_put_stid(*s);
4732+
if (cstate->minorversion)
4733+
return nfserr_deleg_revoked;
4734+
return nfserr_bad_stateid;
4735+
}
47134736
return nfs_ok;
47144737
}
47154738

0 commit comments

Comments
 (0)