From 631fc9ea05c97e5d1d14ea58a7347be4857d09da Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Mon, 14 May 2012 15:57:23 -0400 Subject: [PATCH] nfsd4: allow removing clients not holding state RFC 5661 actually says we should allow an exchange_id to remove a matching client, even if the exchange_id comes from a different principal, *if* the victim client lacks any state. Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 491f13a70db..5415550a63a 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1508,6 +1508,19 @@ nfsd4_set_ex_flags(struct nfs4_client *new, struct nfsd4_exchange_id *clid) clid->flags = new->cl_exchange_flags; } +static bool client_has_state(struct nfs4_client *clp) +{ + /* + * Note clp->cl_openowners check isn't quite right: there's no + * need to count owners without stateid's. + * + * Also note we should probably be using this in 4.0 case too. + */ + return list_empty(&clp->cl_openowners) + && list_empty(&clp->cl_delegations) + && list_empty(&clp->cl_sessions); +} + __be32 nfsd4_exchange_id(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, @@ -1576,8 +1589,11 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, goto out_copy; } if (!creds_match) { /* case 3 */ - status = nfserr_clid_inuse; - goto out; + if (client_has_state(conf)) { + status = nfserr_clid_inuse; + goto out; + } + goto expire_client; } if (verfs_match) { /* case 2 */ exid->flags |= EXCHGID4_FLAG_CONFIRMED_R; @@ -1585,6 +1601,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, goto out_copy; } /* case 5, client reboot */ +expire_client: expire_client(conf); goto out_new; } -- 2.41.0