diff options
author | Patrick McHardy <kaber@trash.net> | 2007-02-12 14:13:43 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2007-02-12 14:13:43 -0500 |
commit | c0e912d7ed8999f87fa7f084928aac1266e251f3 (patch) | |
tree | ec48a83001871b4e0db78ee9eab520a1fbb02e14 /net/netfilter | |
parent | abbaccda4c364815b8b1a82c45a94f60760e13e1 (diff) |
[NETFILTER]: nf_conntrack: fix invalid conntrack statistics RCU assumption
NF_CT_STAT_INC assumes rcu_read_lock in nf_hook_slow disables
preemption as well, making it legal to use __get_cpu_var without
disabling preemption manually. The assumption is not correct anymore
with preemptable RCU, additionally we need to protect against softirqs
when not holding nf_conntrack_lock.
Add NF_CT_STAT_INC_ATOMIC macro, which disables local softirqs,
and use where necessary.
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/netfilter')
-rw-r--r-- | net/netfilter/nf_conntrack_core.c | 14 |
1 files changed, 7 insertions, 7 deletions
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 3deeb900263b..d59640e2377b 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c | |||
@@ -563,7 +563,7 @@ static int early_drop(struct list_head *chain) | |||
563 | if (del_timer(&ct->timeout)) { | 563 | if (del_timer(&ct->timeout)) { |
564 | death_by_timeout((unsigned long)ct); | 564 | death_by_timeout((unsigned long)ct); |
565 | dropped = 1; | 565 | dropped = 1; |
566 | NF_CT_STAT_INC(early_drop); | 566 | NF_CT_STAT_INC_ATOMIC(early_drop); |
567 | } | 567 | } |
568 | nf_ct_put(ct); | 568 | nf_ct_put(ct); |
569 | return dropped; | 569 | return dropped; |
@@ -821,7 +821,7 @@ nf_conntrack_in(int pf, unsigned int hooknum, struct sk_buff **pskb) | |||
821 | 821 | ||
822 | /* Previously seen (loopback or untracked)? Ignore. */ | 822 | /* Previously seen (loopback or untracked)? Ignore. */ |
823 | if ((*pskb)->nfct) { | 823 | if ((*pskb)->nfct) { |
824 | NF_CT_STAT_INC(ignore); | 824 | NF_CT_STAT_INC_ATOMIC(ignore); |
825 | return NF_ACCEPT; | 825 | return NF_ACCEPT; |
826 | } | 826 | } |
827 | 827 | ||
@@ -840,8 +840,8 @@ nf_conntrack_in(int pf, unsigned int hooknum, struct sk_buff **pskb) | |||
840 | * core what to do with the packet. */ | 840 | * core what to do with the packet. */ |
841 | if (l4proto->error != NULL && | 841 | if (l4proto->error != NULL && |
842 | (ret = l4proto->error(*pskb, dataoff, &ctinfo, pf, hooknum)) <= 0) { | 842 | (ret = l4proto->error(*pskb, dataoff, &ctinfo, pf, hooknum)) <= 0) { |
843 | NF_CT_STAT_INC(error); | 843 | NF_CT_STAT_INC_ATOMIC(error); |
844 | NF_CT_STAT_INC(invalid); | 844 | NF_CT_STAT_INC_ATOMIC(invalid); |
845 | return -ret; | 845 | return -ret; |
846 | } | 846 | } |
847 | 847 | ||
@@ -849,13 +849,13 @@ nf_conntrack_in(int pf, unsigned int hooknum, struct sk_buff **pskb) | |||
849 | &set_reply, &ctinfo); | 849 | &set_reply, &ctinfo); |
850 | if (!ct) { | 850 | if (!ct) { |
851 | /* Not valid part of a connection */ | 851 | /* Not valid part of a connection */ |
852 | NF_CT_STAT_INC(invalid); | 852 | NF_CT_STAT_INC_ATOMIC(invalid); |
853 | return NF_ACCEPT; | 853 | return NF_ACCEPT; |
854 | } | 854 | } |
855 | 855 | ||
856 | if (IS_ERR(ct)) { | 856 | if (IS_ERR(ct)) { |
857 | /* Too stressed to deal. */ | 857 | /* Too stressed to deal. */ |
858 | NF_CT_STAT_INC(drop); | 858 | NF_CT_STAT_INC_ATOMIC(drop); |
859 | return NF_DROP; | 859 | return NF_DROP; |
860 | } | 860 | } |
861 | 861 | ||
@@ -868,7 +868,7 @@ nf_conntrack_in(int pf, unsigned int hooknum, struct sk_buff **pskb) | |||
868 | DEBUGP("nf_conntrack_in: Can't track with proto module\n"); | 868 | DEBUGP("nf_conntrack_in: Can't track with proto module\n"); |
869 | nf_conntrack_put((*pskb)->nfct); | 869 | nf_conntrack_put((*pskb)->nfct); |
870 | (*pskb)->nfct = NULL; | 870 | (*pskb)->nfct = NULL; |
871 | NF_CT_STAT_INC(invalid); | 871 | NF_CT_STAT_INC_ATOMIC(invalid); |
872 | return -ret; | 872 | return -ret; |
873 | } | 873 | } |
874 | 874 | ||