aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Layton <jlayton@primarydata.com>2014-07-30 08:27:07 -0400
committerJ. Bruce Fields <bfields@redhat.com>2014-08-01 16:28:21 -0400
commitd20c11d86d8f821a64eac7d6c8f296f06d935f4f (patch)
tree4ec13f8ddb3e488c29c19cfda5e80daee0e83799
parent3dbacee6e127e7595f83654251cf129cbadc2c26 (diff)
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 <trond.myklebust@primarydata.com> Signed-off-by: Jeff Layton <jlayton@primarydata.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
-rw-r--r--fs/nfsd/nfs4state.c65
1 files changed, 39 insertions, 26 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index f149e30475db..52a4677f6f35 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -137,17 +137,6 @@ static __be32 mark_client_expired_locked(struct nfs4_client *clp)
137 return nfs_ok; 137 return nfs_ok;
138} 138}
139 139
140static __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
151static __be32 get_client_locked(struct nfs4_client *clp) 140static __be32 get_client_locked(struct nfs4_client *clp)
152{ 141{
153 if (is_client_expired(clp)) 142 if (is_client_expired(clp))
@@ -1437,12 +1426,10 @@ static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, stru
1437 new->se_cb_sec = cses->cb_sec; 1426 new->se_cb_sec = cses->cb_sec;
1438 atomic_set(&new->se_ref, 0); 1427 atomic_set(&new->se_ref, 0);
1439 idx = hash_sessionid(&new->se_sessionid); 1428 idx = hash_sessionid(&new->se_sessionid);
1440 spin_lock(&nn->client_lock);
1441 list_add(&new->se_hash, &nn->sessionid_hashtbl[idx]); 1429 list_add(&new->se_hash, &nn->sessionid_hashtbl[idx]);
1442 spin_lock(&clp->cl_lock); 1430 spin_lock(&clp->cl_lock);
1443 list_add(&new->se_perclnt, &clp->cl_sessions); 1431 list_add(&new->se_perclnt, &clp->cl_sessions);
1444 spin_unlock(&clp->cl_lock); 1432 spin_unlock(&clp->cl_lock);
1445 spin_unlock(&nn->client_lock);
1446 1433
1447 if (cses->flags & SESSION4_BACK_CHAN) { 1434 if (cses->flags & SESSION4_BACK_CHAN) {
1448 struct sockaddr *sa = svc_addr(rqstp); 1435 struct sockaddr *sa = svc_addr(rqstp);
@@ -2411,6 +2398,7 @@ nfsd4_create_session(struct svc_rqst *rqstp,
2411{ 2398{
2412 struct sockaddr *sa = svc_addr(rqstp); 2399 struct sockaddr *sa = svc_addr(rqstp);
2413 struct nfs4_client *conf, *unconf; 2400 struct nfs4_client *conf, *unconf;
2401 struct nfs4_client *old = NULL;
2414 struct nfsd4_session *new; 2402 struct nfsd4_session *new;
2415 struct nfsd4_conn *conn; 2403 struct nfsd4_conn *conn;
2416 struct nfsd4_clid_slot *cs_slot = NULL; 2404 struct nfsd4_clid_slot *cs_slot = NULL;
@@ -2437,6 +2425,7 @@ nfsd4_create_session(struct svc_rqst *rqstp,
2437 goto out_free_session; 2425 goto out_free_session;
2438 2426
2439 nfs4_lock_state(); 2427 nfs4_lock_state();
2428 spin_lock(&nn->client_lock);
2440 unconf = find_unconfirmed_client(&cr_ses->clientid, true, nn); 2429 unconf = find_unconfirmed_client(&cr_ses->clientid, true, nn);
2441 conf = find_confirmed_client(&cr_ses->clientid, true, nn); 2430 conf = find_confirmed_client(&cr_ses->clientid, true, nn);
2442 WARN_ON_ONCE(conf && unconf); 2431 WARN_ON_ONCE(conf && unconf);
@@ -2455,7 +2444,6 @@ nfsd4_create_session(struct svc_rqst *rqstp,
2455 goto out_free_conn; 2444 goto out_free_conn;
2456 } 2445 }
2457 } else if (unconf) { 2446 } else if (unconf) {
2458 struct nfs4_client *old;
2459 if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) || 2447 if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) ||
2460 !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) { 2448 !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) {
2461 status = nfserr_clid_inuse; 2449 status = nfserr_clid_inuse;
@@ -2473,10 +2461,10 @@ nfsd4_create_session(struct svc_rqst *rqstp,
2473 } 2461 }
2474 old = find_confirmed_client_by_name(&unconf->cl_name, nn); 2462 old = find_confirmed_client_by_name(&unconf->cl_name, nn);
2475 if (old) { 2463 if (old) {
2476 status = mark_client_expired(old); 2464 status = mark_client_expired_locked(old);
2477 if (status) 2465 if (status)
2478 goto out_free_conn; 2466 goto out_free_conn;
2479 expire_client(old); 2467 unhash_client_locked(old);
2480 } 2468 }
2481 move_to_confirmed(unconf); 2469 move_to_confirmed(unconf);
2482 conf = unconf; 2470 conf = unconf;
@@ -2492,20 +2480,29 @@ nfsd4_create_session(struct svc_rqst *rqstp,
2492 cr_ses->flags &= ~SESSION4_RDMA; 2480 cr_ses->flags &= ~SESSION4_RDMA;
2493 2481
2494 init_session(rqstp, new, conf, cr_ses); 2482 init_session(rqstp, new, conf, cr_ses);
2495 nfsd4_init_conn(rqstp, conn, new); 2483 nfsd4_get_session_locked(new);
2496 2484
2497 memcpy(cr_ses->sessionid.data, new->se_sessionid.data, 2485 memcpy(cr_ses->sessionid.data, new->se_sessionid.data,
2498 NFS4_MAX_SESSIONID_LEN); 2486 NFS4_MAX_SESSIONID_LEN);
2499 cs_slot->sl_seqid++; 2487 cs_slot->sl_seqid++;
2500 cr_ses->seqid = cs_slot->sl_seqid; 2488 cr_ses->seqid = cs_slot->sl_seqid;
2501 2489
2502 /* cache solo and embedded create sessions under the state lock */ 2490 /* cache solo and embedded create sessions under the client_lock */
2503 nfsd4_cache_create_session(cr_ses, cs_slot, status); 2491 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);
2504 nfs4_unlock_state(); 2496 nfs4_unlock_state();
2497 if (old)
2498 expire_client(old);
2505 return status; 2499 return status;
2506out_free_conn: 2500out_free_conn:
2501 spin_unlock(&nn->client_lock);
2507 nfs4_unlock_state(); 2502 nfs4_unlock_state();
2508 free_conn(conn); 2503 free_conn(conn);
2504 if (old)
2505 expire_client(old);
2509out_free_session: 2506out_free_session:
2510 __free_session(new); 2507 __free_session(new);
2511out_release_drc_mem: 2508out_release_drc_mem:
@@ -2965,6 +2962,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
2965 struct nfsd4_setclientid_confirm *setclientid_confirm) 2962 struct nfsd4_setclientid_confirm *setclientid_confirm)
2966{ 2963{
2967 struct nfs4_client *conf, *unconf; 2964 struct nfs4_client *conf, *unconf;
2965 struct nfs4_client *old = NULL;
2968 nfs4_verifier confirm = setclientid_confirm->sc_confirm; 2966 nfs4_verifier confirm = setclientid_confirm->sc_confirm;
2969 clientid_t * clid = &setclientid_confirm->sc_clientid; 2967 clientid_t * clid = &setclientid_confirm->sc_clientid;
2970 __be32 status; 2968 __be32 status;
@@ -2974,6 +2972,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
2974 return nfserr_stale_clientid; 2972 return nfserr_stale_clientid;
2975 nfs4_lock_state(); 2973 nfs4_lock_state();
2976 2974
2975 spin_lock(&nn->client_lock);
2977 conf = find_confirmed_client(clid, false, nn); 2976 conf = find_confirmed_client(clid, false, nn);
2978 unconf = find_unconfirmed_client(clid, false, nn); 2977 unconf = find_unconfirmed_client(clid, false, nn);
2979 /* 2978 /*
@@ -2997,21 +2996,29 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
2997 } 2996 }
2998 status = nfs_ok; 2997 status = nfs_ok;
2999 if (conf) { /* case 1: callback update */ 2998 if (conf) { /* case 1: callback update */
2999 old = unconf;
3000 unhash_client_locked(old);
3000 nfsd4_change_callback(conf, &unconf->cl_cb_conn); 3001 nfsd4_change_callback(conf, &unconf->cl_cb_conn);
3001 nfsd4_probe_callback(conf);
3002 expire_client(unconf);
3003 } else { /* case 3: normal case; new or rebooted client */ 3002 } else { /* case 3: normal case; new or rebooted client */
3004 conf = find_confirmed_client_by_name(&unconf->cl_name, nn); 3003 old = find_confirmed_client_by_name(&unconf->cl_name, nn);
3005 if (conf) { 3004 if (old) {
3006 status = mark_client_expired(conf); 3005 status = mark_client_expired_locked(old);
3007 if (status) 3006 if (status)
3008 goto out; 3007 goto out;
3009 expire_client(conf); 3008 unhash_client_locked(old);
3010 } 3009 }
3011 move_to_confirmed(unconf); 3010 move_to_confirmed(unconf);
3012 nfsd4_probe_callback(unconf); 3011 conf = unconf;
3013 } 3012 }
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);
3014out: 3018out:
3019 spin_unlock(&nn->client_lock);
3020 if (old)
3021 expire_client(old);
3015 nfs4_unlock_state(); 3022 nfs4_unlock_state();
3016 return status; 3023 return status;
3017} 3024}
@@ -5648,7 +5655,13 @@ nfs4_check_open_reclaim(clientid_t *clid,
5648 5655
5649u64 nfsd_forget_client(struct nfs4_client *clp, u64 max) 5656u64 nfsd_forget_client(struct nfs4_client *clp, u64 max)
5650{ 5657{
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)
5652 return 0; 5665 return 0;
5653 expire_client(clp); 5666 expire_client(clp);
5654 return 1; 5667 return 1;