diff options
author | Stanislav Kinsbursky <skinsbursky@parallels.com> | 2012-11-14 10:21:21 -0500 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2012-11-15 07:40:43 -0500 |
commit | 8daae4dc0d09d44d38194f72bc91740b46a6ce53 (patch) | |
tree | c4933515f589cee71d5140ffa1446b678d243bee /fs/nfsd/nfs4state.c | |
parent | 52e19c09a183d82d99f10c284bc8b27933b1d1fc (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.c | 75 |
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 | */ |
421 | static struct list_head conf_id_hashtbl[CLIENT_HASH_SIZE]; | ||
422 | static struct list_head unconf_id_hashtbl[CLIENT_HASH_SIZE]; | 421 | static struct list_head unconf_id_hashtbl[CLIENT_HASH_SIZE]; |
423 | static struct rb_root conf_name_tree; | 422 | static struct rb_root conf_name_tree; |
424 | static struct rb_root unconf_name_tree; | 423 | static struct rb_root unconf_name_tree; |
@@ -1385,9 +1384,10 @@ static void | |||
1385 | move_to_confirmed(struct nfs4_client *clp) | 1384 | move_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 | ||
1397 | static struct nfs4_client * | 1397 | static struct nfs4_client * |
1398 | find_confirmed_client(clientid_t *clid, bool sessions) | 1398 | find_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 | |||
4579 | nfs4_check_open_reclaim(clientid_t *clid, bool sessions) | 4582 | nfs4_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 | ||
4767 | static 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 | |||
4783 | static 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 | ||
4766 | int | 4801 | int |
@@ -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); |
4805 | out_recovery: | 4843 | out_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 */ |
4812 | static void | 4851 | static 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 | } |