diff mbox

[v2] nfsd: deal with revoked delegations appropriately

Message ID 20171103140521.12173-1-aweits@rit.edu (mailing list archive)
State New, archived
Headers show

Commit Message

Andrew W Elble Nov. 3, 2017, 2:05 p.m. UTC
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. DELEGRETURN has also been
optimized to return NFS4_OK when called with a revoked delegation.

Thread on DELEGRETURN optimization is here:
https://www.spinics.net/lists/linux-nfs/msg55216.html

Signed-off-by: Andrew Elble <aweits@rit.edu>
---
 v2: deconflicting with Trond's OPEN/CLOSE locking work

 fs/nfsd/nfs4state.c | 41 ++++++++++++++++++++++++++++++++++++++---
 1 file changed, 38 insertions(+), 3 deletions(-)

Comments

Trond Myklebust Nov. 3, 2017, 4:20 p.m. UTC | #1
T24gRnJpLCAyMDE3LTExLTAzIGF0IDEwOjA1IC0wNDAwLCBBbmRyZXcgRWxibGUgd3JvdGU6DQo+
IA0KPiBERUxFR1JFVFVSTiBoYXMgYWxzbyBiZWVuDQo+IG9wdGltaXplZCB0byByZXR1cm4gTkZT
NF9PSyB3aGVuIGNhbGxlZCB3aXRoIGEgcmV2b2tlZCBkZWxlZ2F0aW9uLg0KDQpIbW0uLi4uIEkg
bWlzc2VkIHRoaXMgaW4gdGhlIG9yaWdpbmFsIHBhdGNoLCBhbmQgSSdtIG5vdCBzdXJlIHRoYXQg
aXQNCmlzIGEgZ29vZCBpZGVhLg0KDQpUaGlzIHdvdWxkIGJlIGdvaW5nIGJhY2sgdG8gdGhlIGlz
c3VlcyB0aGF0IE9sZ2EgYW5kIEkgZGlzY3Vzc2VkIGENCndoaWxlIGFnbyBjb25jZXJuaW5nIGxv
Y2sgcmVjb3ZlcnkuIFNpbmNlIHRoZSBMT0NLIG9wZXJhdGlvbiBkb2VzIG5vdA0KdGFrZSBhIGRl
bGVnYXRpb24gc3RhdGVpZCwgd2UgY2Fubm90IGtub3cgZm9yIHN1cmUgdGhhdCB0aGUgcmVjb3Zl
cmVkDQpsb2NrIHdhcyBwcm90ZWN0ZWQgYnkgdGhlIGRlbGVnYXRpb24gdW50aWwgd2Ugc2VuZCB0
aGUgREVMRUdSRVRVUk4sIGFuZA0KZ2V0IGVpdGhlciBORlNfT0sgb3IgTkZTNEVSUl9ERUxFR19S
RVZPS0VELg0KDQpXZSBjb3VsZCwgaW4gdGhlb3J5LCBhZGQgYSBURVNUX1NUQVRFSUQgZm9yIHRo
ZSBkZWxlZ2F0aW9uIHN0YXRlaWQgaW4NCnRoZSBzYW1lIENPTVBPVU5EIGltbWVkaWF0ZWx5IGFm
dGVyIHRoZSBMT0NLIG9wZXJhdGlvbiBpbiBvcmRlciB0byBnZXQNCnRoZSBORlM0RVJSX0RFTEVH
X1JFVk9LRUQgYXNzdXJhbmNlIGF0IGFuIGVhcmxpZXIgdGltZSwgYnV0IHRoYXQgb25seQ0Kd29y
a3MgZm9yIE5GU3Y0LjEgYW5kIG5ld2VyLg0KDQotLSANClRyb25kIE15a2xlYnVzdA0KTGludXgg
TkZTIGNsaWVudCBtYWludGFpbmVyLCBQcmltYXJ5RGF0YQ0KdHJvbmQubXlrbGVidXN0QHByaW1h
cnlkYXRhLmNvbQ0K

--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 0c04f81aa63b..a0249f3a2d22 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3966,7 +3966,8 @@  static struct nfs4_delegation *find_deleg_stateid(struct nfs4_client *cl, statei
 {
 	struct nfs4_stid *ret;
 
-	ret = find_stateid_by_type(cl, s, NFS4_DELEG_STID);
+	ret = find_stateid_by_type(cl, s,
+				NFS4_DELEG_STID|NFS4_REVOKED_DELEG_STID);
 	if (!ret)
 		return NULL;
 	return delegstateid(ret);
@@ -3989,6 +3990,12 @@  static bool nfsd4_is_deleg_cur(struct nfsd4_open *open)
 	deleg = find_deleg_stateid(cl, &open->op_delegate_stateid);
 	if (deleg == NULL)
 		goto out;
+	if (deleg->dl_stid.sc_type == NFS4_REVOKED_DELEG_STID) {
+		nfs4_put_stid(&deleg->dl_stid);
+		if (cl->cl_minorversion)
+			status = nfserr_deleg_revoked;
+		goto out;
+	}
 	flags = share_access_to_flags(open->op_share_access);
 	status = nfs4_check_delegmode(deleg, flags);
 	if (status) {
@@ -4858,6 +4865,16 @@  static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
 		     struct nfs4_stid **s, struct nfsd_net *nn)
 {
 	__be32 status;
+	bool return_revoked = false;
+
+	/*
+	 *  only return revoked delegations if explicitly asked.
+	 *  otherwise we report revoked or bad_stateid status.
+	 */
+	if (typemask & NFS4_REVOKED_DELEG_STID)
+		return_revoked = true;
+	else if (typemask & NFS4_DELEG_STID)
+		typemask |= NFS4_REVOKED_DELEG_STID;
 
 	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
 		return nfserr_bad_stateid;
@@ -4872,6 +4889,12 @@  static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)
 	*s = find_stateid_by_type(cstate->clp, stateid, typemask);
 	if (!*s)
 		return nfserr_bad_stateid;
+	if (((*s)->sc_type == NFS4_REVOKED_DELEG_STID) && !return_revoked) {
+		nfs4_put_stid(*s);
+		if (cstate->minorversion)
+			return nfserr_deleg_revoked;
+		return nfserr_bad_stateid;
+	}
 	return nfs_ok;
 }
 
@@ -5359,7 +5382,9 @@  static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s)
 	if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0)))
 		return status;
 
-	status = nfsd4_lookup_stateid(cstate, stateid, NFS4_DELEG_STID, &s, nn);
+	status = nfsd4_lookup_stateid(cstate, stateid,
+				NFS4_DELEG_STID|NFS4_REVOKED_DELEG_STID,
+				&s, nn);
 	if (status)
 		goto out;
 	dp = delegstateid(s);
@@ -5367,7 +5392,17 @@  static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s)
 	if (status)
 		goto put_stateid;
 
-	destroy_delegation(dp);
+	if (dp->dl_stid.sc_type == NFS4_DELEG_STID)
+		destroy_delegation(dp);
+	if (dp->dl_stid.sc_type == NFS4_REVOKED_DELEG_STID) {
+		/*
+		 * optimization: don't return error if client is
+		 * returning a revoked delegation
+		 */
+		list_del_init(&dp->dl_recall_lru);
+		nfs4_put_stid(s);
+	}
+
 put_stateid:
 	nfs4_put_stid(&dp->dl_stid);
 out: