diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2010-05-31 10:41:35 -0400 |
---|---|---|
committer | Patrick McHardy <kaber@trash.net> | 2010-05-31 10:41:35 -0400 |
commit | 7489aec8eed4f2f1eb3b4d35763bd3ea30b32ef5 (patch) | |
tree | fe2450679dc217183421e606b3912641545596bd | |
parent | c936e8bd1de2fa50c49e3df6fa5036bf07870b67 (diff) |
netfilter: xtables: stackptr should be percpu
commit f3c5c1bfd4 (netfilter: xtables: make ip_tables reentrant)
introduced a performance regression, because stackptr array is shared by
all cpus, adding cache line ping pongs. (16 cpus share a 64 bytes cache
line)
Fix this using alloc_percpu()
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Acked-By: Jan Engelhardt <jengelh@medozas.de>
Signed-off-by: Patrick McHardy <kaber@trash.net>
-rw-r--r-- | include/linux/netfilter/x_tables.h | 2 | ||||
-rw-r--r-- | net/ipv4/netfilter/ip_tables.c | 2 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6_tables.c | 2 | ||||
-rw-r--r-- | net/netfilter/x_tables.c | 13 |
4 files changed, 6 insertions, 13 deletions
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index c00cc0c4d0b7..24e5d01d27d0 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h | |||
@@ -397,7 +397,7 @@ struct xt_table_info { | |||
397 | * @stacksize jumps (number of user chains) can possibly be made. | 397 | * @stacksize jumps (number of user chains) can possibly be made. |
398 | */ | 398 | */ |
399 | unsigned int stacksize; | 399 | unsigned int stacksize; |
400 | unsigned int *stackptr; | 400 | unsigned int __percpu *stackptr; |
401 | void ***jumpstack; | 401 | void ***jumpstack; |
402 | /* ipt_entry tables: one per CPU */ | 402 | /* ipt_entry tables: one per CPU */ |
403 | /* Note : this field MUST be the last one, see XT_TABLE_INFO_SZ */ | 403 | /* Note : this field MUST be the last one, see XT_TABLE_INFO_SZ */ |
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 63958f3394a5..4b6c5ca610fc 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c | |||
@@ -336,7 +336,7 @@ ipt_do_table(struct sk_buff *skb, | |||
336 | cpu = smp_processor_id(); | 336 | cpu = smp_processor_id(); |
337 | table_base = private->entries[cpu]; | 337 | table_base = private->entries[cpu]; |
338 | jumpstack = (struct ipt_entry **)private->jumpstack[cpu]; | 338 | jumpstack = (struct ipt_entry **)private->jumpstack[cpu]; |
339 | stackptr = &private->stackptr[cpu]; | 339 | stackptr = per_cpu_ptr(private->stackptr, cpu); |
340 | origptr = *stackptr; | 340 | origptr = *stackptr; |
341 | 341 | ||
342 | e = get_entry(table_base, private->hook_entry[hook]); | 342 | e = get_entry(table_base, private->hook_entry[hook]); |
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 6f517bd83692..9d2d68f0e605 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c | |||
@@ -363,7 +363,7 @@ ip6t_do_table(struct sk_buff *skb, | |||
363 | cpu = smp_processor_id(); | 363 | cpu = smp_processor_id(); |
364 | table_base = private->entries[cpu]; | 364 | table_base = private->entries[cpu]; |
365 | jumpstack = (struct ip6t_entry **)private->jumpstack[cpu]; | 365 | jumpstack = (struct ip6t_entry **)private->jumpstack[cpu]; |
366 | stackptr = &private->stackptr[cpu]; | 366 | stackptr = per_cpu_ptr(private->stackptr, cpu); |
367 | origptr = *stackptr; | 367 | origptr = *stackptr; |
368 | 368 | ||
369 | e = get_entry(table_base, private->hook_entry[hook]); | 369 | e = get_entry(table_base, private->hook_entry[hook]); |
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 47b1e7917a9c..e34622fa0003 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c | |||
@@ -699,10 +699,8 @@ void xt_free_table_info(struct xt_table_info *info) | |||
699 | vfree(info->jumpstack); | 699 | vfree(info->jumpstack); |
700 | else | 700 | else |
701 | kfree(info->jumpstack); | 701 | kfree(info->jumpstack); |
702 | if (sizeof(unsigned int) * nr_cpu_ids > PAGE_SIZE) | 702 | |
703 | vfree(info->stackptr); | 703 | free_percpu(info->stackptr); |
704 | else | ||
705 | kfree(info->stackptr); | ||
706 | 704 | ||
707 | kfree(info); | 705 | kfree(info); |
708 | } | 706 | } |
@@ -753,14 +751,9 @@ static int xt_jumpstack_alloc(struct xt_table_info *i) | |||
753 | unsigned int size; | 751 | unsigned int size; |
754 | int cpu; | 752 | int cpu; |
755 | 753 | ||
756 | size = sizeof(unsigned int) * nr_cpu_ids; | 754 | i->stackptr = alloc_percpu(unsigned int); |
757 | if (size > PAGE_SIZE) | ||
758 | i->stackptr = vmalloc(size); | ||
759 | else | ||
760 | i->stackptr = kmalloc(size, GFP_KERNEL); | ||
761 | if (i->stackptr == NULL) | 755 | if (i->stackptr == NULL) |
762 | return -ENOMEM; | 756 | return -ENOMEM; |
763 | memset(i->stackptr, 0, size); | ||
764 | 757 | ||
765 | size = sizeof(void **) * nr_cpu_ids; | 758 | size = sizeof(void **) * nr_cpu_ids; |
766 | if (size > PAGE_SIZE) | 759 | if (size > PAGE_SIZE) |