diff options
author | J. Bruce Fields <bfields@redhat.com> | 2012-05-14 21:57:23 +0200 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2012-06-01 02:29:55 +0200 |
commit | 631fc9ea05c97e5d1d14ea58a7347be4857d09da (patch) | |
tree | 58c003e19609e7adf678bc9e197011ad2803c67e /fs/nfsd | |
parent | nfsd4: rearrange exchange_id logic to simplify (diff) | |
download | linux-631fc9ea05c97e5d1d14ea58a7347be4857d09da.tar.xz linux-631fc9ea05c97e5d1d14ea58a7347be4857d09da.zip |
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>
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/nfs4state.c | 21 |
1 files changed, 19 insertions, 2 deletions
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; } |