aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfs4state.c
diff options
context:
space:
mode:
authorStanislav Kinsbursky <skinsbursky@parallels.com>2012-11-14 10:21:21 -0500
committerJ. Bruce Fields <bfields@redhat.com>2012-11-15 07:40:43 -0500
commit8daae4dc0d09d44d38194f72bc91740b46a6ce53 (patch)
treec4933515f589cee71d5140ffa1446b678d243bee /fs/nfsd/nfs4state.c
parent52e19c09a183d82d99f10c284bc8b27933b1d1fc (diff)
nfsd: make conf_id_hashtbl allocated per net
This hash holds nfs4_clients info, which are network namespace aware. So let's make it allocated per network namespace. Note: this hash can be allocated in per-net operations. But it looks better to allocate it on nfsd state start and thus don't waste resources if server is not running. Signed-off-by: Stanislav Kinsbursky <skinsbursky@parallels.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs/nfsd/nfs4state.c')
-rw-r--r--fs/nfsd/nfs4state.c75
1 files changed, 54 insertions, 21 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index ba4785559509..6df427773d01 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -418,7 +418,6 @@ static unsigned int clientstr_hashval(const char *name)
418 * 418 *
419 * All of the above fields are protected by the client_mutex. 419 * All of the above fields are protected by the client_mutex.
420 */ 420 */
421static struct list_head conf_id_hashtbl[CLIENT_HASH_SIZE];
422static struct list_head unconf_id_hashtbl[CLIENT_HASH_SIZE]; 421static struct list_head unconf_id_hashtbl[CLIENT_HASH_SIZE];
423static struct rb_root conf_name_tree; 422static struct rb_root conf_name_tree;
424static struct rb_root unconf_name_tree; 423static struct rb_root unconf_name_tree;
@@ -1385,9 +1384,10 @@ static void
1385move_to_confirmed(struct nfs4_client *clp) 1384move_to_confirmed(struct nfs4_client *clp)
1386{ 1385{
1387 unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id); 1386 unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id);
1387 struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
1388 1388
1389 dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp); 1389 dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp);
1390 list_move(&clp->cl_idhash, &conf_id_hashtbl[idhashval]); 1390 list_move(&clp->cl_idhash, &nn->conf_id_hashtbl[idhashval]);
1391 rb_erase(&clp->cl_namenode, &unconf_name_tree); 1391 rb_erase(&clp->cl_namenode, &unconf_name_tree);
1392 add_clp_to_name_tree(clp, &conf_name_tree); 1392 add_clp_to_name_tree(clp, &conf_name_tree);
1393 set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); 1393 set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags);
@@ -1395,12 +1395,12 @@ move_to_confirmed(struct nfs4_client *clp)
1395} 1395}
1396 1396
1397static struct nfs4_client * 1397static struct nfs4_client *
1398find_confirmed_client(clientid_t *clid, bool sessions) 1398find_confirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn)
1399{ 1399{
1400 struct nfs4_client *clp; 1400 struct nfs4_client *clp;
1401 unsigned int idhashval = clientid_hashval(clid->cl_id); 1401 unsigned int idhashval = clientid_hashval(clid->cl_id);
1402 1402
1403 list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) { 1403 list_for_each_entry(clp, &nn->conf_id_hashtbl[idhashval], cl_idhash) {
1404 if (same_clid(&clp->cl_clientid, clid)) { 1404 if (same_clid(&clp->cl_clientid, clid)) {
1405 if ((bool)clp->cl_minorversion != sessions) 1405 if ((bool)clp->cl_minorversion != sessions)
1406 return NULL; 1406 return NULL;
@@ -1787,6 +1787,7 @@ nfsd4_create_session(struct svc_rqst *rqstp,
1787 struct nfsd4_conn *conn; 1787 struct nfsd4_conn *conn;
1788 struct nfsd4_clid_slot *cs_slot = NULL; 1788 struct nfsd4_clid_slot *cs_slot = NULL;
1789 __be32 status = 0; 1789 __be32 status = 0;
1790 struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
1790 1791
1791 if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) 1792 if (cr_ses->flags & ~SESSION4_FLAG_MASK_A)
1792 return nfserr_inval; 1793 return nfserr_inval;
@@ -1802,7 +1803,7 @@ nfsd4_create_session(struct svc_rqst *rqstp,
1802 1803
1803 nfs4_lock_state(); 1804 nfs4_lock_state();
1804 unconf = find_unconfirmed_client(&cr_ses->clientid, true); 1805 unconf = find_unconfirmed_client(&cr_ses->clientid, true);
1805 conf = find_confirmed_client(&cr_ses->clientid, true); 1806 conf = find_confirmed_client(&cr_ses->clientid, true, nn);
1806 1807
1807 if (conf) { 1808 if (conf) {
1808 cs_slot = &conf->cl_cs_slot; 1809 cs_slot = &conf->cl_cs_slot;
@@ -2142,10 +2143,11 @@ nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta
2142{ 2143{
2143 struct nfs4_client *conf, *unconf, *clp; 2144 struct nfs4_client *conf, *unconf, *clp;
2144 __be32 status = 0; 2145 __be32 status = 0;
2146 struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
2145 2147
2146 nfs4_lock_state(); 2148 nfs4_lock_state();
2147 unconf = find_unconfirmed_client(&dc->clientid, true); 2149 unconf = find_unconfirmed_client(&dc->clientid, true);
2148 conf = find_confirmed_client(&dc->clientid, true); 2150 conf = find_confirmed_client(&dc->clientid, true, nn);
2149 2151
2150 if (conf) { 2152 if (conf) {
2151 clp = conf; 2153 clp = conf;
@@ -2280,7 +2282,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
2280 return nfserr_stale_clientid; 2282 return nfserr_stale_clientid;
2281 nfs4_lock_state(); 2283 nfs4_lock_state();
2282 2284
2283 conf = find_confirmed_client(clid, false); 2285 conf = find_confirmed_client(clid, false, nn);
2284 unconf = find_unconfirmed_client(clid, false); 2286 unconf = find_unconfirmed_client(clid, false);
2285 /* 2287 /*
2286 * We try hard to give out unique clientid's, so if we get an 2288 * We try hard to give out unique clientid's, so if we get an
@@ -2656,7 +2658,8 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate,
2656 oo = find_openstateowner_str(strhashval, open, cstate->minorversion); 2658 oo = find_openstateowner_str(strhashval, open, cstate->minorversion);
2657 open->op_openowner = oo; 2659 open->op_openowner = oo;
2658 if (!oo) { 2660 if (!oo) {
2659 clp = find_confirmed_client(clientid, cstate->minorversion); 2661 clp = find_confirmed_client(clientid, cstate->minorversion,
2662 nn);
2660 if (clp == NULL) 2663 if (clp == NULL)
2661 return nfserr_expired; 2664 return nfserr_expired;
2662 goto new_owner; 2665 goto new_owner;
@@ -3152,7 +3155,7 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
3152 status = nfserr_stale_clientid; 3155 status = nfserr_stale_clientid;
3153 if (STALE_CLIENTID(clid, nn)) 3156 if (STALE_CLIENTID(clid, nn))
3154 goto out; 3157 goto out;
3155 clp = find_confirmed_client(clid, cstate->minorversion); 3158 clp = find_confirmed_client(clid, cstate->minorversion, nn);
3156 status = nfserr_expired; 3159 status = nfserr_expired;
3157 if (clp == NULL) { 3160 if (clp == NULL) {
3158 /* We assume the client took too long to RENEW. */ 3161 /* We assume the client took too long to RENEW. */
@@ -3428,7 +3431,7 @@ static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask, s
3428 return nfserr_bad_stateid; 3431 return nfserr_bad_stateid;
3429 if (STALE_STATEID(stateid, nn)) 3432 if (STALE_STATEID(stateid, nn))
3430 return nfserr_stale_stateid; 3433 return nfserr_stale_stateid;
3431 cl = find_confirmed_client(&stateid->si_opaque.so_clid, sessions); 3434 cl = find_confirmed_client(&stateid->si_opaque.so_clid, sessions, nn);
3432 if (!cl) 3435 if (!cl)
3433 return nfserr_expired; 3436 return nfserr_expired;
3434 *s = find_stateid_by_type(cl, stateid, typemask); 3437 *s = find_stateid_by_type(cl, stateid, typemask);
@@ -4579,9 +4582,10 @@ __be32
4579nfs4_check_open_reclaim(clientid_t *clid, bool sessions) 4582nfs4_check_open_reclaim(clientid_t *clid, bool sessions)
4580{ 4583{
4581 struct nfs4_client *clp; 4584 struct nfs4_client *clp;
4585 struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);
4582 4586
4583 /* find clientid in conf_id_hashtbl */ 4587 /* find clientid in conf_id_hashtbl */
4584 clp = find_confirmed_client(clid, sessions); 4588 clp = find_confirmed_client(clid, sessions, nn);
4585 if (clp == NULL) 4589 if (clp == NULL)
4586 return nfserr_reclaim_bad; 4590 return nfserr_reclaim_bad;
4587 4591
@@ -4720,7 +4724,6 @@ nfs4_state_init(void)
4720 int i; 4724 int i;
4721 4725
4722 for (i = 0; i < CLIENT_HASH_SIZE; i++) { 4726 for (i = 0; i < CLIENT_HASH_SIZE; i++) {
4723 INIT_LIST_HEAD(&conf_id_hashtbl[i]);
4724 INIT_LIST_HEAD(&unconf_id_hashtbl[i]); 4727 INIT_LIST_HEAD(&unconf_id_hashtbl[i]);
4725 } 4728 }
4726 conf_name_tree = RB_ROOT; 4729 conf_name_tree = RB_ROOT;
@@ -4761,6 +4764,38 @@ set_max_delegations(void)
4761 max_delegations = nr_free_buffer_pages() >> (20 - 2 - PAGE_SHIFT); 4764 max_delegations = nr_free_buffer_pages() >> (20 - 2 - PAGE_SHIFT);
4762} 4765}
4763 4766
4767static int nfs4_state_start_net(struct net *net)
4768{
4769 struct nfsd_net *nn = net_generic(net, nfsd_net_id);
4770 int i;
4771
4772 nn->conf_id_hashtbl = kmalloc(sizeof(struct list_head) *
4773 CLIENT_HASH_SIZE, GFP_KERNEL);
4774 if (!nn->conf_id_hashtbl)
4775 return -ENOMEM;
4776
4777 for (i = 0; i < CLIENT_HASH_SIZE; i++)
4778 INIT_LIST_HEAD(&nn->conf_id_hashtbl[i]);
4779
4780 return 0;
4781}
4782
4783static void
4784__nfs4_state_shutdown_net(struct net *net)
4785{
4786 int i;
4787 struct nfs4_client *clp = NULL;
4788 struct nfsd_net *nn = net_generic(net, nfsd_net_id);
4789
4790 for (i = 0; i < CLIENT_HASH_SIZE; i++) {
4791 while (!list_empty(&nn->conf_id_hashtbl[i])) {
4792 clp = list_entry(nn->conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash);
4793 destroy_client(clp);
4794 }
4795 }
4796 kfree(nn->conf_id_hashtbl);
4797}
4798
4764/* initialization to perform when the nfsd service is started: */ 4799/* initialization to perform when the nfsd service is started: */
4765 4800
4766int 4801int
@@ -4778,6 +4813,9 @@ nfs4_state_start(void)
4778 * basis. 4813 * basis.
4779 */ 4814 */
4780 get_net(net); 4815 get_net(net);
4816 ret = nfs4_state_start_net(net);
4817 if (ret)
4818 return ret;
4781 nfsd4_client_tracking_init(net); 4819 nfsd4_client_tracking_init(net);
4782 nn->boot_time = get_seconds(); 4820 nn->boot_time = get_seconds();
4783 locks_start_grace(net, &nn->nfsd4_manager); 4821 locks_start_grace(net, &nn->nfsd4_manager);
@@ -4804,26 +4842,21 @@ out_free_laundry:
4804 destroy_workqueue(laundry_wq); 4842 destroy_workqueue(laundry_wq);
4805out_recovery: 4843out_recovery:
4806 nfsd4_client_tracking_exit(net); 4844 nfsd4_client_tracking_exit(net);
4845 __nfs4_state_shutdown_net(net);
4807 put_net(net); 4846 put_net(net);
4808 return ret; 4847 return ret;
4809} 4848}
4810 4849
4811/* should be called with the state lock held */ 4850/* should be called with the state lock held */
4812static void 4851static void
4813__nfs4_state_shutdown(void) 4852__nfs4_state_shutdown(struct net *net)
4814{ 4853{
4815 int i;
4816 struct nfs4_client *clp = NULL; 4854 struct nfs4_client *clp = NULL;
4817 struct nfs4_delegation *dp = NULL; 4855 struct nfs4_delegation *dp = NULL;
4818 struct list_head *pos, *next, reaplist; 4856 struct list_head *pos, *next, reaplist;
4819 struct rb_node *node, *tmp; 4857 struct rb_node *node, *tmp;
4820 4858
4821 for (i = 0; i < CLIENT_HASH_SIZE; i++) { 4859 __nfs4_state_shutdown_net(net);
4822 while (!list_empty(&conf_id_hashtbl[i])) {
4823 clp = list_entry(conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash);
4824 destroy_client(clp);
4825 }
4826 }
4827 4860
4828 node = rb_first(&unconf_name_tree); 4861 node = rb_first(&unconf_name_tree);
4829 while (node != NULL) { 4862 while (node != NULL) {
@@ -4860,7 +4893,7 @@ nfs4_state_shutdown(void)
4860 destroy_workqueue(laundry_wq); 4893 destroy_workqueue(laundry_wq);
4861 locks_end_grace(&nn->nfsd4_manager); 4894 locks_end_grace(&nn->nfsd4_manager);
4862 nfs4_lock_state(); 4895 nfs4_lock_state();
4863 __nfs4_state_shutdown(); 4896 __nfs4_state_shutdown(net);
4864 nfs4_unlock_state(); 4897 nfs4_unlock_state();
4865 nfsd4_destroy_callback_queue(); 4898 nfsd4_destroy_callback_queue();
4866} 4899}