summaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfs4state.c
diff options
context:
space:
mode:
authorJeff Layton2014-07-30 14:27:15 +0200
committerJ. Bruce Fields2014-08-05 16:55:02 +0200
commit294ac32e99861f6efee548a6b7afb27c32cd502f (patch)
tree0050131c1e101462a193e9cc22115fc2ea37e94d /fs/nfsd/nfs4state.c
parentnfsd: don't destroy clients that are busy (diff)
downloadkernel-qcow2-linux-294ac32e99861f6efee548a6b7afb27c32cd502f.tar.gz
kernel-qcow2-linux-294ac32e99861f6efee548a6b7afb27c32cd502f.tar.xz
kernel-qcow2-linux-294ac32e99861f6efee548a6b7afb27c32cd502f.zip
nfsd: protect clid and verifier generation with client_lock
The clid counter is a global counter currently. Move it to be a per-net property so that it can be properly protected by the nn->client_lock instead of relying on the client_mutex. The verifier generator is also potentially racy if there are two simultaneous callers. Generate the verifier when we generate the clid value, so it's also created under the client_lock. With this, there's no need to keep two counters as they'd always be in sync anyway, so just use the clientid_counter for both. As Trond points out, what would be best is to eventually move this code to use IDR instead of the hash tables. That would also help ensure uniqueness, but that's probably best done as a separate project. Signed-off-by: Jeff Layton <jlayton@primarydata.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs/nfsd/nfs4state.c')
-rw-r--r--fs/nfsd/nfs4state.c21
1 files changed, 9 insertions, 12 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 037bb924ce63..2cb559017ac9 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1812,28 +1812,26 @@ static bool mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp)
return 0 == strcmp(cl->cl_cred.cr_principal, cr->cr_principal);
}
-static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn)
-{
- static u32 current_clientid = 1;
-
- clp->cl_clientid.cl_boot = nn->boot_time;
- clp->cl_clientid.cl_id = current_clientid++;
-}
-
-static void gen_confirm(struct nfs4_client *clp)
+static void gen_confirm(struct nfs4_client *clp, struct nfsd_net *nn)
{
__be32 verf[2];
- static u32 i;
/*
* This is opaque to client, so no need to byte-swap. Use
* __force to keep sparse happy
*/
verf[0] = (__force __be32)get_seconds();
- verf[1] = (__force __be32)i++;
+ verf[1] = (__force __be32)nn->clientid_counter;
memcpy(clp->cl_confirm.data, verf, sizeof(clp->cl_confirm.data));
}
+static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn)
+{
+ clp->cl_clientid.cl_boot = nn->boot_time;
+ clp->cl_clientid.cl_id = nn->clientid_counter++;
+ gen_confirm(clp, nn);
+}
+
static struct nfs4_stid *
find_stateid_locked(struct nfs4_client *cl, stateid_t *t)
{
@@ -1884,7 +1882,6 @@ static struct nfs4_client *create_client(struct xdr_netobj name,
clear_bit(0, &clp->cl_cb_slot_busy);
copy_verf(clp, verf);
rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa);
- gen_confirm(clp);
clp->cl_cb_session = NULL;
clp->net = net;
return clp;