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 <bfields@redhat.com>
This commit is contained in:
J. Bruce Fields 2012-05-14 15:57:23 -04:00
parent 136e658d62
commit 631fc9ea05

View File

@ -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;
}