From c08a2fb62910e26ef13beb3211272a513ebe5de7 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 4 Oct 2009 16:58:07 +0200 Subject: [PATCH] net: Fix netfilter percpu assumptions for real commit 00ef66ebb37437ca205d06224e7b956d205f7886 in tip. commit 21ece08 (net: fix the xtables smp_processor_id assumptions for -rt) fixed only half of the problem. The filter functions might run in thread context and can be preempted and migrated on -RT. Signed-off-by: Thomas Gleixner Signed-off-by: Paul Gortmaker --- include/linux/netfilter/x_tables.h | 25 +++++++++++++++++++------ net/ipv4/netfilter/arp_tables.c | 7 ++++--- net/ipv4/netfilter/ip_tables.c | 7 ++++--- net/ipv6/netfilter/ip6_tables.c | 7 ++++--- 4 files changed, 31 insertions(+), 15 deletions(-) diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index 5c588ca..dcc03d7 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h @@ -482,22 +482,35 @@ DECLARE_PER_CPU(struct xt_info_lock, xt_info_locks); * _Only_ that special combination of being per-cpu and never getting * re-entered asynchronously means that the count is safe. */ -static inline void xt_info_rdlock_bh(void) +static inline int xt_info_rdlock_bh(void) { struct xt_info_lock *lock; + int cpu; local_bh_disable(); - lock = &__raw_get_cpu_var(xt_info_locks); - if (likely(!lock->readers++)) + preempt_disable_rt(); + cpu = smp_processor_id(); + lock = &per_cpu(xt_info_locks, cpu); + if (likely(!lock->readers++)) { + preempt_enable_rt(); spin_lock(&lock->lock); + } else + preempt_enable_rt(); + return cpu; } -static inline void xt_info_rdunlock_bh(void) +static inline void xt_info_rdunlock_bh(int cpu) { - struct xt_info_lock *lock = &__raw_get_cpu_var(xt_info_locks); + struct xt_info_lock *lock = &per_cpu(xt_info_locks, cpu); - if (likely(!--lock->readers)) + preempt_disable_rt(); + + if (likely(!--lock->readers)) { + preempt_enable_rt(); spin_unlock(&lock->lock); + } else + preempt_enable_rt(); + local_bh_enable(); } diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 9438d18..4afb6c8 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -266,6 +266,7 @@ unsigned int arpt_do_table(struct sk_buff *skb, void *table_base; const struct xt_table_info *private; struct xt_target_param tgpar; + int cpu; if (!pskb_may_pull(skb, arp_hdr_len(skb->dev))) return NF_DROP; @@ -273,9 +274,9 @@ unsigned int arpt_do_table(struct sk_buff *skb, indev = in ? in->name : nulldevname; outdev = out ? out->name : nulldevname; - xt_info_rdlock_bh(); + cpu = xt_info_rdlock_bh(); private = table->private; - table_base = private->entries[raw_smp_processor_id()]; + table_base = private->entries[cpu]; e = get_entry(table_base, private->hook_entry[hook]); back = get_entry(table_base, private->underflow[hook]); @@ -346,7 +347,7 @@ unsigned int arpt_do_table(struct sk_buff *skb, /* Verdict */ break; } while (!hotdrop); - xt_info_rdunlock_bh(); + xt_info_rdunlock_bh(cpu); if (hotdrop) return NF_DROP; diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 83501d8..1c33431 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -335,6 +335,7 @@ ipt_do_table(struct sk_buff *skb, const struct xt_table_info *private; struct xt_match_param mtpar; struct xt_target_param tgpar; + int cpu; /* Initialization */ ip = ip_hdr(skb); @@ -355,9 +356,9 @@ ipt_do_table(struct sk_buff *skb, mtpar.hooknum = tgpar.hooknum = hook; IP_NF_ASSERT(table->valid_hooks & (1 << hook)); - xt_info_rdlock_bh(); + cpu = xt_info_rdlock_bh(); private = table->private; - table_base = private->entries[raw_smp_processor_id()]; + table_base = private->entries[cpu]; e = get_entry(table_base, private->hook_entry[hook]); @@ -447,7 +448,7 @@ ipt_do_table(struct sk_buff *skb, /* Verdict */ break; } while (!hotdrop); - xt_info_rdunlock_bh(); + xt_info_rdunlock_bh(cpu); #ifdef DEBUG_ALLOW_ALL return NF_ACCEPT; diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 66c78d0..6d5b78b 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -364,6 +364,7 @@ ip6t_do_table(struct sk_buff *skb, const struct xt_table_info *private; struct xt_match_param mtpar; struct xt_target_param tgpar; + int cpu; /* Initialization */ indev = in ? in->name : nulldevname; @@ -382,9 +383,9 @@ ip6t_do_table(struct sk_buff *skb, IP_NF_ASSERT(table->valid_hooks & (1 << hook)); - xt_info_rdlock_bh(); + cpu = xt_info_rdlock_bh(); private = table->private; - table_base = private->entries[raw_smp_processor_id()]; + table_base = private->entries[cpu]; e = get_entry(table_base, private->hook_entry[hook]); @@ -478,7 +479,7 @@ ip6t_do_table(struct sk_buff *skb, #ifdef CONFIG_NETFILTER_DEBUG tb_comefrom = NETFILTER_LINK_POISON; #endif - xt_info_rdunlock_bh(); + xt_info_rdunlock_bh(cpu); #ifdef DEBUG_ALLOW_ALL return NF_ACCEPT; -- 1.7.0.4