Skip to content

Commit 3dbacee

Browse files
trondmypdJ. Bruce Fields
authored andcommitted
nfsd: Protect unconfirmed client creation using client_lock
...instead of relying on the client_mutex. Signed-off-by: Trond Myklebust <[email protected]> Signed-off-by: J. Bruce Fields <[email protected]>
1 parent 5cc40fd commit 3dbacee

File tree

1 file changed

+22
-11
lines changed

1 file changed

+22
-11
lines changed

fs/nfsd/nfs4state.c

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1923,7 +1923,7 @@ add_to_unconfirmed(struct nfs4_client *clp)
19231923
add_clp_to_name_tree(clp, &nn->unconf_name_tree);
19241924
idhashval = clientid_hashval(clp->cl_clientid.cl_id);
19251925
list_add(&clp->cl_idhash, &nn->unconf_id_hashtbl[idhashval]);
1926-
renew_client(clp);
1926+
renew_client_locked(clp);
19271927
}
19281928

19291929
static void
@@ -1937,7 +1937,7 @@ move_to_confirmed(struct nfs4_client *clp)
19371937
rb_erase(&clp->cl_namenode, &nn->unconf_name_tree);
19381938
add_clp_to_name_tree(clp, &nn->conf_name_tree);
19391939
set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags);
1940-
renew_client(clp);
1940+
renew_client_locked(clp);
19411941
}
19421942

19431943
static struct nfs4_client *
@@ -1950,7 +1950,7 @@ find_client_in_id_table(struct list_head *tbl, clientid_t *clid, bool sessions)
19501950
if (same_clid(&clp->cl_clientid, clid)) {
19511951
if ((bool)clp->cl_minorversion != sessions)
19521952
return NULL;
1953-
renew_client(clp);
1953+
renew_client_locked(clp);
19541954
return clp;
19551955
}
19561956
}
@@ -2152,7 +2152,8 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
21522152
struct nfsd4_compound_state *cstate,
21532153
struct nfsd4_exchange_id *exid)
21542154
{
2155-
struct nfs4_client *unconf, *conf, *new;
2155+
struct nfs4_client *conf, *new;
2156+
struct nfs4_client *unconf = NULL;
21562157
__be32 status;
21572158
char addr_str[INET6_ADDRSTRLEN];
21582159
nfs4_verifier verf = exid->verifier;
@@ -2187,6 +2188,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
21872188

21882189
/* Cases below refer to rfc 5661 section 18.35.4: */
21892190
nfs4_lock_state();
2191+
spin_lock(&nn->client_lock);
21902192
conf = find_confirmed_client_by_name(&exid->clname, nn);
21912193
if (conf) {
21922194
bool creds_match = same_creds(&conf->cl_cred, &rqstp->rq_cred);
@@ -2218,14 +2220,14 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
22182220
status = nfserr_clid_inuse;
22192221
goto out;
22202222
}
2221-
expire_client(conf);
22222223
goto out_new;
22232224
}
22242225
if (verfs_match) { /* case 2 */
22252226
conf->cl_exchange_flags |= EXCHGID4_FLAG_CONFIRMED_R;
22262227
goto out_copy;
22272228
}
22282229
/* case 5, client reboot */
2230+
conf = NULL;
22292231
goto out_new;
22302232
}
22312233

@@ -2236,17 +2238,18 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
22362238

22372239
unconf = find_unconfirmed_client_by_name(&exid->clname, nn);
22382240
if (unconf) /* case 4, possible retry or client restart */
2239-
expire_client(unconf);
2241+
unhash_client_locked(unconf);
22402242

22412243
/* case 1 (normal case) */
22422244
out_new:
2245+
if (conf)
2246+
unhash_client_locked(conf);
22432247
new->cl_minorversion = cstate->minorversion;
22442248
new->cl_mach_cred = (exid->spa_how == SP4_MACH_CRED);
22452249

22462250
gen_clid(new, nn);
22472251
add_to_unconfirmed(new);
2248-
conf = new;
2249-
new = NULL;
2252+
swap(new, conf);
22502253
out_copy:
22512254
exid->clientid.cl_boot = conf->cl_clientid.cl_boot;
22522255
exid->clientid.cl_id = conf->cl_clientid.cl_id;
@@ -2259,9 +2262,12 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
22592262
status = nfs_ok;
22602263

22612264
out:
2265+
spin_unlock(&nn->client_lock);
22622266
nfs4_unlock_state();
22632267
if (new)
2264-
free_client(new);
2268+
expire_client(new);
2269+
if (unconf)
2270+
expire_client(unconf);
22652271
return status;
22662272
}
22672273

@@ -2900,7 +2906,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
29002906
{
29012907
struct xdr_netobj clname = setclid->se_name;
29022908
nfs4_verifier clverifier = setclid->se_verf;
2903-
struct nfs4_client *conf, *unconf, *new;
2909+
struct nfs4_client *conf, *new;
2910+
struct nfs4_client *unconf = NULL;
29042911
__be32 status;
29052912
struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
29062913

@@ -2909,6 +2916,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
29092916
return nfserr_jukebox;
29102917
/* Cases below refer to rfc 3530 section 14.2.33: */
29112918
nfs4_lock_state();
2919+
spin_lock(&nn->client_lock);
29122920
conf = find_confirmed_client_by_name(&clname, nn);
29132921
if (conf) {
29142922
/* case 0: */
@@ -2926,7 +2934,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
29262934
}
29272935
unconf = find_unconfirmed_client_by_name(&clname, nn);
29282936
if (unconf)
2929-
expire_client(unconf);
2937+
unhash_client_locked(unconf);
29302938
if (conf && same_verf(&conf->cl_verifier, &clverifier))
29312939
/* case 1: probable callback update */
29322940
copy_clid(new, conf);
@@ -2941,9 +2949,12 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
29412949
new = NULL;
29422950
status = nfs_ok;
29432951
out:
2952+
spin_unlock(&nn->client_lock);
29442953
nfs4_unlock_state();
29452954
if (new)
29462955
free_client(new);
2956+
if (unconf)
2957+
expire_client(unconf);
29472958
return status;
29482959
}
29492960

0 commit comments

Comments
 (0)