From: J. Bruce Fields Date: Mon, 14 May 2012 19:57:23 +0000 (-0400) Subject: nfsd4: allow removing clients not holding state X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=631fc9ea05c97e5d1d14ea58a7347be4857d09da;p=linux-beck.git 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 --- diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 491f13a70db1..5415550a63a9 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; }