diff options
author | Alexey Dobriyan <adobriyan@gmail.com> | 2008-11-25 20:28:57 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-11-25 20:28:57 -0500 |
commit | 66caf628c3b634c57b14a1a104dcd57e4fab2e3b (patch) | |
tree | d5a967f7c22e55208bc536c540efb85f26b9b483 | |
parent | dc2caba7b321289e7d02e63d7216961ccecfa103 (diff) |
netns xfrm: per-netns policy hash resizing work
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/netns/xfrm.h | 1 | ||||
-rw-r--r-- | net/xfrm/xfrm_policy.c | 52 |
2 files changed, 27 insertions, 26 deletions
diff --git a/include/net/netns/xfrm.h b/include/net/netns/xfrm.h index d5aadf06be46..c53d17357a49 100644 --- a/include/net/netns/xfrm.h +++ b/include/net/netns/xfrm.h | |||
@@ -38,6 +38,7 @@ struct netns_xfrm { | |||
38 | struct hlist_head policy_inexact[XFRM_POLICY_MAX * 2]; | 38 | struct hlist_head policy_inexact[XFRM_POLICY_MAX * 2]; |
39 | struct xfrm_policy_hash policy_bydst[XFRM_POLICY_MAX * 2]; | 39 | struct xfrm_policy_hash policy_bydst[XFRM_POLICY_MAX * 2]; |
40 | unsigned int policy_count[XFRM_POLICY_MAX * 2]; | 40 | unsigned int policy_count[XFRM_POLICY_MAX * 2]; |
41 | struct work_struct policy_hash_work; | ||
41 | }; | 42 | }; |
42 | 43 | ||
43 | #endif | 44 | #endif |
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 630ec048a0d3..1d300862dc04 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -396,12 +396,12 @@ static unsigned long xfrm_new_hash_mask(unsigned int old_hmask) | |||
396 | return ((old_hmask + 1) << 1) - 1; | 396 | return ((old_hmask + 1) << 1) - 1; |
397 | } | 397 | } |
398 | 398 | ||
399 | static void xfrm_bydst_resize(int dir) | 399 | static void xfrm_bydst_resize(struct net *net, int dir) |
400 | { | 400 | { |
401 | unsigned int hmask = init_net.xfrm.policy_bydst[dir].hmask; | 401 | unsigned int hmask = net->xfrm.policy_bydst[dir].hmask; |
402 | unsigned int nhashmask = xfrm_new_hash_mask(hmask); | 402 | unsigned int nhashmask = xfrm_new_hash_mask(hmask); |
403 | unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head); | 403 | unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head); |
404 | struct hlist_head *odst = init_net.xfrm.policy_bydst[dir].table; | 404 | struct hlist_head *odst = net->xfrm.policy_bydst[dir].table; |
405 | struct hlist_head *ndst = xfrm_hash_alloc(nsize); | 405 | struct hlist_head *ndst = xfrm_hash_alloc(nsize); |
406 | int i; | 406 | int i; |
407 | 407 | ||
@@ -413,20 +413,20 @@ static void xfrm_bydst_resize(int dir) | |||
413 | for (i = hmask; i >= 0; i--) | 413 | for (i = hmask; i >= 0; i--) |
414 | xfrm_dst_hash_transfer(odst + i, ndst, nhashmask); | 414 | xfrm_dst_hash_transfer(odst + i, ndst, nhashmask); |
415 | 415 | ||
416 | init_net.xfrm.policy_bydst[dir].table = ndst; | 416 | net->xfrm.policy_bydst[dir].table = ndst; |
417 | init_net.xfrm.policy_bydst[dir].hmask = nhashmask; | 417 | net->xfrm.policy_bydst[dir].hmask = nhashmask; |
418 | 418 | ||
419 | write_unlock_bh(&xfrm_policy_lock); | 419 | write_unlock_bh(&xfrm_policy_lock); |
420 | 420 | ||
421 | xfrm_hash_free(odst, (hmask + 1) * sizeof(struct hlist_head)); | 421 | xfrm_hash_free(odst, (hmask + 1) * sizeof(struct hlist_head)); |
422 | } | 422 | } |
423 | 423 | ||
424 | static void xfrm_byidx_resize(int total) | 424 | static void xfrm_byidx_resize(struct net *net, int total) |
425 | { | 425 | { |
426 | unsigned int hmask = init_net.xfrm.policy_idx_hmask; | 426 | unsigned int hmask = net->xfrm.policy_idx_hmask; |
427 | unsigned int nhashmask = xfrm_new_hash_mask(hmask); | 427 | unsigned int nhashmask = xfrm_new_hash_mask(hmask); |
428 | unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head); | 428 | unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head); |
429 | struct hlist_head *oidx = init_net.xfrm.policy_byidx; | 429 | struct hlist_head *oidx = net->xfrm.policy_byidx; |
430 | struct hlist_head *nidx = xfrm_hash_alloc(nsize); | 430 | struct hlist_head *nidx = xfrm_hash_alloc(nsize); |
431 | int i; | 431 | int i; |
432 | 432 | ||
@@ -438,18 +438,18 @@ static void xfrm_byidx_resize(int total) | |||
438 | for (i = hmask; i >= 0; i--) | 438 | for (i = hmask; i >= 0; i--) |
439 | xfrm_idx_hash_transfer(oidx + i, nidx, nhashmask); | 439 | xfrm_idx_hash_transfer(oidx + i, nidx, nhashmask); |
440 | 440 | ||
441 | init_net.xfrm.policy_byidx = nidx; | 441 | net->xfrm.policy_byidx = nidx; |
442 | init_net.xfrm.policy_idx_hmask = nhashmask; | 442 | net->xfrm.policy_idx_hmask = nhashmask; |
443 | 443 | ||
444 | write_unlock_bh(&xfrm_policy_lock); | 444 | write_unlock_bh(&xfrm_policy_lock); |
445 | 445 | ||
446 | xfrm_hash_free(oidx, (hmask + 1) * sizeof(struct hlist_head)); | 446 | xfrm_hash_free(oidx, (hmask + 1) * sizeof(struct hlist_head)); |
447 | } | 447 | } |
448 | 448 | ||
449 | static inline int xfrm_bydst_should_resize(int dir, int *total) | 449 | static inline int xfrm_bydst_should_resize(struct net *net, int dir, int *total) |
450 | { | 450 | { |
451 | unsigned int cnt = init_net.xfrm.policy_count[dir]; | 451 | unsigned int cnt = net->xfrm.policy_count[dir]; |
452 | unsigned int hmask = init_net.xfrm.policy_bydst[dir].hmask; | 452 | unsigned int hmask = net->xfrm.policy_bydst[dir].hmask; |
453 | 453 | ||
454 | if (total) | 454 | if (total) |
455 | *total += cnt; | 455 | *total += cnt; |
@@ -461,9 +461,9 @@ static inline int xfrm_bydst_should_resize(int dir, int *total) | |||
461 | return 0; | 461 | return 0; |
462 | } | 462 | } |
463 | 463 | ||
464 | static inline int xfrm_byidx_should_resize(int total) | 464 | static inline int xfrm_byidx_should_resize(struct net *net, int total) |
465 | { | 465 | { |
466 | unsigned int hmask = init_net.xfrm.policy_idx_hmask; | 466 | unsigned int hmask = net->xfrm.policy_idx_hmask; |
467 | 467 | ||
468 | if ((hmask + 1) < xfrm_policy_hashmax && | 468 | if ((hmask + 1) < xfrm_policy_hashmax && |
469 | total > hmask) | 469 | total > hmask) |
@@ -488,25 +488,24 @@ void xfrm_spd_getinfo(struct xfrmk_spdinfo *si) | |||
488 | EXPORT_SYMBOL(xfrm_spd_getinfo); | 488 | EXPORT_SYMBOL(xfrm_spd_getinfo); |
489 | 489 | ||
490 | static DEFINE_MUTEX(hash_resize_mutex); | 490 | static DEFINE_MUTEX(hash_resize_mutex); |
491 | static void xfrm_hash_resize(struct work_struct *__unused) | 491 | static void xfrm_hash_resize(struct work_struct *work) |
492 | { | 492 | { |
493 | struct net *net = container_of(work, struct net, xfrm.policy_hash_work); | ||
493 | int dir, total; | 494 | int dir, total; |
494 | 495 | ||
495 | mutex_lock(&hash_resize_mutex); | 496 | mutex_lock(&hash_resize_mutex); |
496 | 497 | ||
497 | total = 0; | 498 | total = 0; |
498 | for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) { | 499 | for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) { |
499 | if (xfrm_bydst_should_resize(dir, &total)) | 500 | if (xfrm_bydst_should_resize(net, dir, &total)) |
500 | xfrm_bydst_resize(dir); | 501 | xfrm_bydst_resize(net, dir); |
501 | } | 502 | } |
502 | if (xfrm_byidx_should_resize(total)) | 503 | if (xfrm_byidx_should_resize(net, total)) |
503 | xfrm_byidx_resize(total); | 504 | xfrm_byidx_resize(net, total); |
504 | 505 | ||
505 | mutex_unlock(&hash_resize_mutex); | 506 | mutex_unlock(&hash_resize_mutex); |
506 | } | 507 | } |
507 | 508 | ||
508 | static DECLARE_WORK(xfrm_hash_work, xfrm_hash_resize); | ||
509 | |||
510 | /* Generate new index... KAME seems to generate them ordered by cost | 509 | /* Generate new index... KAME seems to generate them ordered by cost |
511 | * of an absolute inpredictability of ordering of rules. This will not pass. */ | 510 | * of an absolute inpredictability of ordering of rules. This will not pass. */ |
512 | static u32 xfrm_gen_index(int dir) | 511 | static u32 xfrm_gen_index(int dir) |
@@ -607,8 +606,8 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
607 | 606 | ||
608 | if (delpol) | 607 | if (delpol) |
609 | xfrm_policy_kill(delpol); | 608 | xfrm_policy_kill(delpol); |
610 | else if (xfrm_bydst_should_resize(dir, NULL)) | 609 | else if (xfrm_bydst_should_resize(&init_net, dir, NULL)) |
611 | schedule_work(&xfrm_hash_work); | 610 | schedule_work(&init_net.xfrm.policy_hash_work); |
612 | 611 | ||
613 | read_lock_bh(&xfrm_policy_lock); | 612 | read_lock_bh(&xfrm_policy_lock); |
614 | gc_list = NULL; | 613 | gc_list = NULL; |
@@ -1079,8 +1078,8 @@ static void __xfrm_policy_link(struct xfrm_policy *pol, int dir) | |||
1079 | init_net.xfrm.policy_count[dir]++; | 1078 | init_net.xfrm.policy_count[dir]++; |
1080 | xfrm_pol_hold(pol); | 1079 | xfrm_pol_hold(pol); |
1081 | 1080 | ||
1082 | if (xfrm_bydst_should_resize(dir, NULL)) | 1081 | if (xfrm_bydst_should_resize(&init_net, dir, NULL)) |
1083 | schedule_work(&xfrm_hash_work); | 1082 | schedule_work(&init_net.xfrm.policy_hash_work); |
1084 | } | 1083 | } |
1085 | 1084 | ||
1086 | static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol, | 1085 | static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol, |
@@ -2415,6 +2414,7 @@ static int __net_init xfrm_policy_init(struct net *net) | |||
2415 | } | 2414 | } |
2416 | 2415 | ||
2417 | INIT_LIST_HEAD(&net->xfrm.policy_all); | 2416 | INIT_LIST_HEAD(&net->xfrm.policy_all); |
2417 | INIT_WORK(&net->xfrm.policy_hash_work, xfrm_hash_resize); | ||
2418 | if (net_eq(net, &init_net)) | 2418 | if (net_eq(net, &init_net)) |
2419 | register_netdevice_notifier(&xfrm_dev_notifier); | 2419 | register_netdevice_notifier(&xfrm_dev_notifier); |
2420 | return 0; | 2420 | return 0; |