Skip to content

Commit d20c11d

Browse files
Jeff LaytonJ. Bruce Fields
authored andcommitted
nfsd: Protect session creation and client confirm using client_lock
In particular, we want to ensure that the move_to_confirmed() is protected by the nn->client_lock spin lock, so that we can use that when looking up the clientid etc. instead of relying on the client_mutex. Signed-off-by: Trond Myklebust <[email protected]> Signed-off-by: Jeff Layton <[email protected]> Signed-off-by: J. Bruce Fields <[email protected]>
1 parent 3dbacee commit d20c11d

File tree

1 file changed

+39
-26
lines changed

1 file changed

+39
-26
lines changed

fs/nfsd/nfs4state.c

Lines changed: 39 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -137,17 +137,6 @@ static __be32 mark_client_expired_locked(struct nfs4_client *clp)
137137
return nfs_ok;
138138
}
139139

140-
static __be32 mark_client_expired(struct nfs4_client *clp)
141-
{
142-
struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
143-
__be32 ret;
144-
145-
spin_lock(&nn->client_lock);
146-
ret = mark_client_expired_locked(clp);
147-
spin_unlock(&nn->client_lock);
148-
return ret;
149-
}
150-
151140
static __be32 get_client_locked(struct nfs4_client *clp)
152141
{
153142
if (is_client_expired(clp))
@@ -1437,12 +1426,10 @@ static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, stru
14371426
new->se_cb_sec = cses->cb_sec;
14381427
atomic_set(&new->se_ref, 0);
14391428
idx = hash_sessionid(&new->se_sessionid);
1440-
spin_lock(&nn->client_lock);
14411429
list_add(&new->se_hash, &nn->sessionid_hashtbl[idx]);
14421430
spin_lock(&clp->cl_lock);
14431431
list_add(&new->se_perclnt, &clp->cl_sessions);
14441432
spin_unlock(&clp->cl_lock);
1445-
spin_unlock(&nn->client_lock);
14461433

14471434
if (cses->flags & SESSION4_BACK_CHAN) {
14481435
struct sockaddr *sa = svc_addr(rqstp);
@@ -2411,6 +2398,7 @@ nfsd4_create_session(struct svc_rqst *rqstp,
24112398
{
24122399
struct sockaddr *sa = svc_addr(rqstp);
24132400
struct nfs4_client *conf, *unconf;
2401+
struct nfs4_client *old = NULL;
24142402
struct nfsd4_session *new;
24152403
struct nfsd4_conn *conn;
24162404
struct nfsd4_clid_slot *cs_slot = NULL;
@@ -2437,6 +2425,7 @@ nfsd4_create_session(struct svc_rqst *rqstp,
24372425
goto out_free_session;
24382426

24392427
nfs4_lock_state();
2428+
spin_lock(&nn->client_lock);
24402429
unconf = find_unconfirmed_client(&cr_ses->clientid, true, nn);
24412430
conf = find_confirmed_client(&cr_ses->clientid, true, nn);
24422431
WARN_ON_ONCE(conf && unconf);
@@ -2455,7 +2444,6 @@ nfsd4_create_session(struct svc_rqst *rqstp,
24552444
goto out_free_conn;
24562445
}
24572446
} else if (unconf) {
2458-
struct nfs4_client *old;
24592447
if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) ||
24602448
!rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) {
24612449
status = nfserr_clid_inuse;
@@ -2473,10 +2461,10 @@ nfsd4_create_session(struct svc_rqst *rqstp,
24732461
}
24742462
old = find_confirmed_client_by_name(&unconf->cl_name, nn);
24752463
if (old) {
2476-
status = mark_client_expired(old);
2464+
status = mark_client_expired_locked(old);
24772465
if (status)
24782466
goto out_free_conn;
2479-
expire_client(old);
2467+
unhash_client_locked(old);
24802468
}
24812469
move_to_confirmed(unconf);
24822470
conf = unconf;
@@ -2492,20 +2480,29 @@ nfsd4_create_session(struct svc_rqst *rqstp,
24922480
cr_ses->flags &= ~SESSION4_RDMA;
24932481

24942482
init_session(rqstp, new, conf, cr_ses);
2495-
nfsd4_init_conn(rqstp, conn, new);
2483+
nfsd4_get_session_locked(new);
24962484

24972485
memcpy(cr_ses->sessionid.data, new->se_sessionid.data,
24982486
NFS4_MAX_SESSIONID_LEN);
24992487
cs_slot->sl_seqid++;
25002488
cr_ses->seqid = cs_slot->sl_seqid;
25012489

2502-
/* cache solo and embedded create sessions under the state lock */
2490+
/* cache solo and embedded create sessions under the client_lock */
25032491
nfsd4_cache_create_session(cr_ses, cs_slot, status);
2492+
spin_unlock(&nn->client_lock);
2493+
/* init connection and backchannel */
2494+
nfsd4_init_conn(rqstp, conn, new);
2495+
nfsd4_put_session(new);
25042496
nfs4_unlock_state();
2497+
if (old)
2498+
expire_client(old);
25052499
return status;
25062500
out_free_conn:
2501+
spin_unlock(&nn->client_lock);
25072502
nfs4_unlock_state();
25082503
free_conn(conn);
2504+
if (old)
2505+
expire_client(old);
25092506
out_free_session:
25102507
__free_session(new);
25112508
out_release_drc_mem:
@@ -2965,6 +2962,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
29652962
struct nfsd4_setclientid_confirm *setclientid_confirm)
29662963
{
29672964
struct nfs4_client *conf, *unconf;
2965+
struct nfs4_client *old = NULL;
29682966
nfs4_verifier confirm = setclientid_confirm->sc_confirm;
29692967
clientid_t * clid = &setclientid_confirm->sc_clientid;
29702968
__be32 status;
@@ -2974,6 +2972,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
29742972
return nfserr_stale_clientid;
29752973
nfs4_lock_state();
29762974

2975+
spin_lock(&nn->client_lock);
29772976
conf = find_confirmed_client(clid, false, nn);
29782977
unconf = find_unconfirmed_client(clid, false, nn);
29792978
/*
@@ -2997,21 +2996,29 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
29972996
}
29982997
status = nfs_ok;
29992998
if (conf) { /* case 1: callback update */
2999+
old = unconf;
3000+
unhash_client_locked(old);
30003001
nfsd4_change_callback(conf, &unconf->cl_cb_conn);
3001-
nfsd4_probe_callback(conf);
3002-
expire_client(unconf);
30033002
} else { /* case 3: normal case; new or rebooted client */
3004-
conf = find_confirmed_client_by_name(&unconf->cl_name, nn);
3005-
if (conf) {
3006-
status = mark_client_expired(conf);
3003+
old = find_confirmed_client_by_name(&unconf->cl_name, nn);
3004+
if (old) {
3005+
status = mark_client_expired_locked(old);
30073006
if (status)
30083007
goto out;
3009-
expire_client(conf);
3008+
unhash_client_locked(old);
30103009
}
30113010
move_to_confirmed(unconf);
3012-
nfsd4_probe_callback(unconf);
3011+
conf = unconf;
30133012
}
3013+
get_client_locked(conf);
3014+
spin_unlock(&nn->client_lock);
3015+
nfsd4_probe_callback(conf);
3016+
spin_lock(&nn->client_lock);
3017+
put_client_renew_locked(conf);
30143018
out:
3019+
spin_unlock(&nn->client_lock);
3020+
if (old)
3021+
expire_client(old);
30153022
nfs4_unlock_state();
30163023
return status;
30173024
}
@@ -5648,7 +5655,13 @@ nfs4_check_open_reclaim(clientid_t *clid,
56485655

56495656
u64 nfsd_forget_client(struct nfs4_client *clp, u64 max)
56505657
{
5651-
if (mark_client_expired(clp))
5658+
__be32 ret;
5659+
struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
5660+
5661+
spin_lock(&nn->client_lock);
5662+
ret = mark_client_expired_locked(clp);
5663+
spin_unlock(&nn->client_lock);
5664+
if (ret != nfs_ok)
56525665
return 0;
56535666
expire_client(clp);
56545667
return 1;

0 commit comments

Comments
 (0)