* BUG: atomic counter underflow at ip_conntrack_event_cache_init+0x91/0xb0 (with patch)
@ 2005-08-01 14:13 Mattia Dongili
2005-08-01 14:27 ` Patrick McHardy
0 siblings, 1 reply; 9+ messages in thread
From: Mattia Dongili @ 2005-08-01 14:13 UTC (permalink / raw)
To: Linux Kernel Mailing List
Hello,
got this one while trying out 2.6.13-rc4-mm1 (not there in -r2-mm1),
from a quick look it seems to me that ip_conntrack_{get,put} are not
simmetric in updating the use count, thus simply adding this line might
help (it does actually, but I'm not aware if there could be any drawback):
--- include/linux/netfilter_ipv4/ip_conntrack.h.clean 2005-08-01 15:09:49.000000000 +0200
+++ include/linux/netfilter_ipv4/ip_conntrack.h 2005-08-01 15:08:52.000000000 +0200
@@ -298,6 +298,7 @@ static inline struct ip_conntrack *
ip_conntrack_get(const struct sk_buff *skb, enum ip_conntrack_info *ctinfo)
{
*ctinfo = skb->nfctinfo;
+ nf_conntrack_get(skb->nfct);
return (struct ip_conntrack *)skb->nfct;
}
here's the BUG log:
Aug 1 10:44:01 inferi kernel: BUG: atomic counter underflow at:
Aug 1 10:44:01 inferi kernel: [pg0+277500810/1069777920] ip_ct_iterate_cleanup+0xfa/0x100 [ip_conntrack]
Aug 1 10:44:01 inferi kernel: [pg0+277541331/1069777920] masq_inet_event+0x33/0x40 [ipt_MASQUERADE]
Aug 1 10:44:01 inferi kernel: [pg0+277541344/1069777920] device_cmp+0x0/0x40 [ipt_MASQUERADE]
Aug 1 10:44:01 inferi kernel: [notifier_call_chain+45/80] notifier_call_chain+0x2d/0x50
Aug 1 10:44:01 inferi kernel: [inet_del_ifa+147/464] inet_del_ifa+0x93/0x1d0
Aug 1 10:44:01 inferi kernel: [devinet_ioctl+1199/1440] devinet_ioctl+0x4af/0x5a0
Aug 1 10:44:01 inferi kernel: [inet_ioctl+102/176] inet_ioctl+0x66/0xb0
Aug 1 10:44:01 inferi kernel: [sock_ioctl+201/560] sock_ioctl+0xc9/0x230
Aug 1 10:44:01 inferi kernel: [do_ioctl+142/160] do_ioctl+0x8e/0xa0
Aug 1 10:44:01 inferi kernel: [do_page_fault+392/1555] do_page_fault+0x188/0x613
Aug 1 10:44:01 inferi kernel: [vfs_ioctl+101/496] vfs_ioctl+0x65/0x1f0
Aug 1 10:44:01 inferi kernel: [sys_ioctl+69/112] sys_ioctl+0x45/0x70
Aug 1 10:44:01 inferi kernel: [syscall_call+7/11] syscall_call+0x7/0xb
Aug 1 10:45:06 inferi kernel: BUG: atomic counter underflow at:
Aug 1 10:45:06 inferi kernel: [pg0+277491553/1069777920] ip_conntrack_event_cache_init+0x91/0xb0 [ip_conntrack]
Aug 1 10:45:06 inferi kernel: [pg0+277496567/1069777920] ip_conntrack_in+0xd7/0x2f0 [ip_conntrack]
Aug 1 10:45:06 inferi kernel: [ip_rcv_finish+0/768] ip_rcv_finish+0x0/0x300
Aug 1 10:45:06 inferi kernel: [nf_iterate+120/144] nf_iterate+0x78/0x90
Aug 1 10:45:06 inferi kernel: [ip_rcv_finish+0/768] ip_rcv_finish+0x0/0x300
Aug 1 10:45:06 inferi kernel: [ip_rcv_finish+0/768] ip_rcv_finish+0x0/0x300
Aug 1 10:45:06 inferi kernel: [nf_hook_slow+126/336] nf_hook_slow+0x7e/0x150
Aug 1 10:45:06 inferi kernel: [ip_rcv_finish+0/768] ip_rcv_finish+0x0/0x300
Aug 1 10:45:06 inferi kernel: [ip_rcv_finish+0/768] ip_rcv_finish+0x0/0x300
Aug 1 10:45:06 inferi kernel: [ip_rcv+1186/1424] ip_rcv+0x4a2/0x590
Aug 1 10:45:06 inferi kernel: [ip_rcv_finish+0/768] ip_rcv_finish+0x0/0x300
Aug 1 10:45:06 inferi kernel: [acpi_ut_value_exit+53/63] acpi_ut_value_exit+0x35/0x3f
Aug 1 10:45:06 inferi kernel: [netif_receive_skb+359/544] netif_receive_skb+0x167/0x220
Aug 1 10:45:06 inferi kernel: [pg0+277353520/1069777920] e100_poll+0x750/0x800 [e100]
Aug 1 10:45:06 inferi kernel: [net_rx_action+116/288] net_rx_action+0x74/0x120
Aug 1 10:45:06 inferi kernel: [__do_softirq+123/144] __do_softirq+0x7b/0x90
Aug 1 10:45:06 inferi kernel: [do_softirq+38/48] do_softirq+0x26/0x30
Aug 1 10:45:06 inferi kernel: [irq_exit+53/64] irq_exit+0x35/0x40
Aug 1 10:45:06 inferi kernel: [do_IRQ+30/48] do_IRQ+0x1e/0x30
Aug 1 10:45:06 inferi kernel: [common_interrupt+26/32] common_interrupt+0x1a/0x20
Aug 1 10:45:06 inferi kernel: [acpi_processor_idle+290/661] acpi_processor_idle+0x122/0x295
Aug 1 10:45:06 inferi kernel: [cpu_idle+80/96] cpu_idle+0x50/0x60
Aug 1 10:45:06 inferi kernel: [start_kernel+346/384] start_kernel+0x15a/0x180
Aug 1 10:45:06 inferi kernel: [unknown_bootoption+0/480] unknown_bootoption+0x0/0x1e0
Aug 1 10:46:05 inferi kernel: BUG: atomic counter underflow at:
Aug 1 10:46:05 inferi kernel: [pg0+277491553/1069777920] ip_conntrack_event_cache_init+0x91/0xb0 [ip_conntrack]
Aug 1 10:46:05 inferi kernel: [pg0+277496567/1069777920] ip_conntrack_in+0xd7/0x2f0 [ip_conntrack]
Aug 1 10:46:05 inferi kernel: [dst_output+0/48] dst_output+0x0/0x30
Aug 1 10:46:05 inferi kernel: [nf_iterate+120/144] nf_iterate+0x78/0x90
Aug 1 10:46:05 inferi kernel: [dst_output+0/48] dst_output+0x0/0x30
Aug 1 10:46:05 inferi kernel: [dst_output+0/48] dst_output+0x0/0x30
Aug 1 10:46:05 inferi kernel: [nf_hook_slow+126/336] nf_hook_slow+0x7e/0x150
Aug 1 10:46:05 inferi kernel: [dst_output+0/48] dst_output+0x0/0x30
Aug 1 10:46:05 inferi kernel: [dst_output+0/48] dst_output+0x0/0x30
Aug 1 10:46:05 inferi kernel: [ip_push_pending_frames+1059/1168] ip_push_pending_frames+0x423/0x490
Aug 1 10:46:05 inferi kernel: [dst_output+0/48] dst_output+0x0/0x30
Aug 1 10:46:05 inferi kernel: [udp_push_pending_frames+364/688] udp_push_pending_frames+0x16c/0x2b0
Aug 1 10:46:05 inferi kernel: [udp_sendmsg+946/1840] udp_sendmsg+0x3b2/0x730
Aug 1 10:46:05 inferi kernel: [do_no_page+104/848] do_no_page+0x68/0x350
Aug 1 10:46:05 inferi kernel: [handle_mm_fault+252/592] handle_mm_fault+0xfc/0x250
Aug 1 10:46:05 inferi kernel: [dput_recursive+30/768] dput_recursive+0x1e/0x300
Aug 1 10:46:05 inferi kernel: [do_lookup+80/176] do_lookup+0x50/0xb0
Aug 1 10:46:05 inferi kernel: [__do_page_cache_readahead+125/368] __do_page_cache_readahead+0x7d/0x170
Aug 1 10:46:05 inferi kernel: [inet_sendmsg+77/96] inet_sendmsg+0x4d/0x60
Aug 1 10:46:05 inferi kernel: [sock_sendmsg+221/256] sock_sendmsg+0xdd/0x100
Aug 1 10:46:05 inferi kernel: [do_generic_mapping_read+814/1520] do_generic_mapping_read+0x32e/0x5f0
Aug 1 10:46:05 inferi kernel: [autoremove_wake_function+0/96] autoremove_wake_function+0x0/0x60
Aug 1 10:46:05 inferi kernel: [sys_sendto+220/256] sys_sendto+0xdc/0x100
Aug 1 10:46:05 inferi kernel: [sys_connect+143/176] sys_connect+0x8f/0xb0
Aug 1 10:46:05 inferi kernel: [handle_mm_fault+252/592] handle_mm_fault+0xfc/0x250
Aug 1 10:46:05 inferi kernel: [sys_send+51/64] sys_send+0x33/0x40
Aug 1 10:46:05 inferi kernel: [sys_socketcall+323/608] sys_socketcall+0x143/0x260
Aug 1 10:46:05 inferi kernel: [do_page_fault+0/1555] do_page_fault+0x0/0x613
Aug 1 10:46:05 inferi kernel: [syscall_call+7/11] syscall_call+0x7/0xb
The BUG is repeated every minute, the full log is available at
http://oioio.altervista.org/kern.log
Attached my .config and below my very simple iptables rules:
Chain INPUT (policy DROP 254 packets, 10012 bytes)
pkts bytes target prot opt in out source destination
2567 1117K ACCEPT all -- lo any anywhere anywhere
5955 6519K ACCEPT all -- any any anywhere anywhere state RELATED,ESTABLISHED
0 0 ACCEPT tcp -- any any anywhere anywhere tcp dpt:ssh
Chain FORWARD (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 6549 packets, 1405K bytes)
pkts bytes target prot opt in out source destination
Chain PREROUTING (policy ACCEPT 256 packets, 10868 bytes)
pkts bytes target prot opt in out source destination
Chain POSTROUTING (policy ACCEPT 44 packets, 3319 bytes)
pkts bytes target prot opt in out source destination
95 7375 MASQUERADE all -- any eth0 anywhere anywhere
Chain OUTPUT (policy ACCEPT 139 packets, 10694 bytes)
pkts bytes target prot opt in out source destination
--
mattia
:wq!
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: BUG: atomic counter underflow at ip_conntrack_event_cache_init+0x91/0xb0 (with patch)
2005-08-01 14:13 BUG: atomic counter underflow at ip_conntrack_event_cache_init+0x91/0xb0 (with patch) Mattia Dongili
@ 2005-08-01 14:27 ` Patrick McHardy
2005-08-01 16:05 ` Mattia Dongili
0 siblings, 1 reply; 9+ messages in thread
From: Patrick McHardy @ 2005-08-01 14:27 UTC (permalink / raw)
To: Mattia Dongili
Cc: Linux Kernel Mailing List, Netfilter Development Mailinglist,
David S. Miller
[-- Attachment #1: Type: text/plain, Size: 886 bytes --]
Mattia Dongili wrote:
> Hello,
>
> got this one while trying out 2.6.13-rc4-mm1 (not there in -r2-mm1),
> from a quick look it seems to me that ip_conntrack_{get,put} are not
> simmetric in updating the use count, thus simply adding this line might
> help (it does actually, but I'm not aware if there could be any drawback):
>
> --- include/linux/netfilter_ipv4/ip_conntrack.h.clean 2005-08-01 15:09:49.000000000 +0200
> +++ include/linux/netfilter_ipv4/ip_conntrack.h 2005-08-01 15:08:52.000000000 +0200
> @@ -298,6 +298,7 @@ static inline struct ip_conntrack *
> ip_conntrack_get(const struct sk_buff *skb, enum ip_conntrack_info *ctinfo)
> {
> *ctinfo = skb->nfctinfo;
> + nf_conntrack_get(skb->nfct);
> return (struct ip_conntrack *)skb->nfct;
> }
This creates lots of refcnt leaks, which is probably why it makes the
underflow go away :) Please try this patch instead.
[-- Attachment #2: x --]
[-- Type: text/plain, Size: 1030 bytes --]
[NETFILTER]: Fix refcnt underflow in ip_conntrack_event_cache_init
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit 5d55b8c6bfba6e6e2ffe26c2a2e2561e278428b7
tree d43366a793d2fa3058c15a752010ef0fd22894cc
parent df2e0392536ecdd6385f4319f746045fd6fae38f
author Patrick McHardy <kaber@trash.net> Mon, 01 Aug 2005 16:25:53 +0200
committer Patrick McHardy <kaber@trash.net> Mon, 01 Aug 2005 16:25:53 +0200
net/ipv4/netfilter/ip_conntrack_core.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c
--- a/net/ipv4/netfilter/ip_conntrack_core.c
+++ b/net/ipv4/netfilter/ip_conntrack_core.c
@@ -146,6 +146,7 @@ void ip_conntrack_event_cache_init(const
/* initialize for this conntrack/packet */
ecache->ct = ip_conntrack_get(skb, &ctinfo);
+ nf_conntrack_get(&ecache->ct->ct_general);
/* ecache->events cleared by __deliver_cached_devents() */
} else {
DEBUGP("ecache: re-entered for conntrack %p.\n", ct);
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: BUG: atomic counter underflow at ip_conntrack_event_cache_init+0x91/0xb0 (with patch)
2005-08-01 14:27 ` Patrick McHardy
@ 2005-08-01 16:05 ` Mattia Dongili
2005-08-01 17:08 ` Patrick McHardy
0 siblings, 1 reply; 9+ messages in thread
From: Mattia Dongili @ 2005-08-01 16:05 UTC (permalink / raw)
To: Patrick McHardy
Cc: Linux Kernel Mailing List, Netfilter Development Mailinglist,
David S. Miller
On Mon, Aug 01, 2005 at 04:27:53PM +0200, Patrick McHardy wrote:
> Mattia Dongili wrote:
> > Hello,
> >
> > got this one while trying out 2.6.13-rc4-mm1 (not there in -r2-mm1),
> > from a quick look it seems to me that ip_conntrack_{get,put} are not
> > simmetric in updating the use count, thus simply adding this line might
> > help (it does actually, but I'm not aware if there could be any drawback):
> >
> > --- include/linux/netfilter_ipv4/ip_conntrack.h.clean 2005-08-01 15:09:49.000000000 +0200
> > +++ include/linux/netfilter_ipv4/ip_conntrack.h 2005-08-01 15:08:52.000000000 +0200
> > @@ -298,6 +298,7 @@ static inline struct ip_conntrack *
> > ip_conntrack_get(const struct sk_buff *skb, enum ip_conntrack_info *ctinfo)
> > {
> > *ctinfo = skb->nfctinfo;
> > + nf_conntrack_get(skb->nfct);
> > return (struct ip_conntrack *)skb->nfct;
> > }
>
> This creates lots of refcnt leaks, which is probably why it makes the
> underflow go away :) Please try this patch instead.
this doesn't fix it actually, see dmesg below:
...
ip_tables: (C) 2000-2002 Netfilter core team
Netfilter messages via NETLINK v0.30.
ip_conntrack version 2.3 (2044 buckets, 16352 max) - 252 bytes per conntrack
e100: eth0: e100_watchdog: link up, 10Mbps, half-duplex
BUG: atomic counter underflow at:
[<d0c6d38a>] ip_ct_iterate_cleanup+0xfa/0x100 [ip_conntrack]
[<d0c681d3>] masq_inet_event+0x33/0x40 [ipt_MASQUERADE]
[<d0c681e0>] device_cmp+0x0/0x40 [ipt_MASQUERADE]
[<c012733d>] notifier_call_chain+0x2d/0x50
[<c02bea43>] inet_del_ifa+0x93/0x1d0
[<c02bf6af>] devinet_ioctl+0x4af/0x5a0
[<c02c1946>] inet_ioctl+0x66/0xb0
[<c0278be9>] sock_ioctl+0xc9/0x230
[<c016df2e>] do_ioctl+0x8e/0xa0
[<c02d5e08>] do_page_fault+0x188/0x613
[<c016e0f5>] vfs_ioctl+0x65/0x1f0
[<c016e2c5>] sys_ioctl+0x45/0x70
[<c0103185>] syscall_call+0x7/0xb
Installing knfsd (copyright (C) 1996 okir@monad.swb.de).
BUG: atomic counter underflow at:
[<d0c6af61>] ip_conntrack_event_cache_init+0x91/0xb0 [ip_conntrack]
[<d0c6c2f7>] ip_conntrack_in+0xd7/0x2f0 [ip_conntrack]
[<c029e420>] dst_output+0x0/0x30
[<c028ef38>] nf_iterate+0x78/0x90
[<c029e420>] dst_output+0x0/0x30
[<c029e420>] dst_output+0x0/0x30
[<c028f42e>] nf_hook_slow+0x7e/0x150
[<c029e420>] dst_output+0x0/0x30
[<c029c313>] ip_queue_xmit+0x403/0x570
[<c029e420>] dst_output+0x0/0x30
[<c02487e2>] submit_bio+0x62/0x100
[<c0180ab3>] mpage_bio_submit+0x23/0x40
[<c0180dec>] do_mpage_readpage+0x1fc/0x3b0
[<c02b1c05>] tcp_v4_send_check+0x55/0x100
[<c02ab818>] tcp_transmit_skb+0x478/0x720
[<c02ae331>] tcp_connect+0x2c1/0x370
[<c02b0bbe>] tcp_v4_connect+0x45e/0xb70
[<c0143708>] cache_alloc_refill+0x178/0x230
[<c02c141b>] inet_stream_connect+0x8b/0x1b0
[<c0279783>] sys_connect+0x83/0xb0
[<c0278169>] sock_map_fd+0xf9/0x130
[<c02790f9>] __sock_create+0xd9/0x260
[<c01d4396>] copy_from_user+0x46/0x80
[<c027a211>] sys_socketcall+0xb1/0x260
[<c01598d1>] sys_close+0x61/0xa0
[<c02d5c80>] do_page_fault+0x0/0x613
[<c0103185>] syscall_call+0x7/0xb
BUG: atomic counter underflow at:
[<d0c6af61>] ip_conntrack_event_cache_init+0x91/0xb0 [ip_conntrack]
[<d0c6c2f7>] ip_conntrack_in+0xd7/0x2f0 [ip_conntrack]
[<c029e420>] dst_output+0x0/0x30
[<c028ef38>] nf_iterate+0x78/0x90
[<c029e420>] dst_output+0x0/0x30
[<c029e420>] dst_output+0x0/0x30
[<c028f42e>] nf_hook_slow+0x7e/0x150
[<c029e420>] dst_output+0x0/0x30
[<c029e420>] dst_output+0x0/0x30
[<c029df93>] ip_push_pending_frames+0x423/0x490
[<c029e420>] dst_output+0x0/0x30
[<c02b91dc>] udp_push_pending_frames+0x16c/0x2b0
[<c02b9722>] udp_sendmsg+0x3b2/0x730
[<c02bbc77>] arp_bind_neighbour+0x67/0xa0
[<c02946e9>] rt_intern_hash+0x2e9/0x3d0
[<c0296b39>] ip_route_output_slow+0x2a9/0x870
[<c02c16ed>] inet_sendmsg+0x4d/0x60
[<c027846d>] sock_sendmsg+0xdd/0x100
[<c012f060>] autoremove_wake_function+0x0/0x60
[<c02799ec>] sys_sendto+0xdc/0x100
[<c027978f>] sys_connect+0x8f/0xb0
[<c014b43c>] handle_mm_fault+0xfc/0x250
[<c0279a43>] sys_send+0x33/0x40
[<c027a2a3>] sys_socketcall+0x143/0x260
[<c02d5c80>] do_page_fault+0x0/0x613
[<c0103185>] syscall_call+0x7/0xb
BUG: atomic counter underflow at:
[<d0c6af61>] ip_conntrack_event_cache_init+0x91/0xb0 [ip_conntrack]
[<d0c6c2f7>] ip_conntrack_in+0xd7/0x2f0 [ip_conntrack]
[<c0298ff0>] ip_rcv_finish+0x0/0x300
[<c028ef38>] nf_iterate+0x78/0x90
[<c0298ff0>] ip_rcv_finish+0x0/0x300
[<c0298ff0>] ip_rcv_finish+0x0/0x300
[<c028f42e>] nf_hook_slow+0x7e/0x150
[<c0298ff0>] ip_rcv_finish+0x0/0x300
[<c0298ff0>] ip_rcv_finish+0x0/0x300
[<c0298d62>] ip_rcv+0x4a2/0x590
[<c0298ff0>] ip_rcv_finish+0x0/0x300
[<c0206e00>] acpi_ut_value_exit+0x35/0x3f
[<c0282b67>] netif_receive_skb+0x167/0x220
[<d0c4c430>] e100_poll+0x750/0x800 [e100]
[<c0282db4>] net_rx_action+0x74/0x120
[<c011e8fb>] __do_softirq+0x7b/0x90
[<c011e936>] do_softirq+0x26/0x30
[<c011ea05>] irq_exit+0x35/0x40
[<c0104bde>] do_IRQ+0x1e/0x30
[<c010334a>] common_interrupt+0x1a/0x20
[<c02154bf>] acpi_processor_idle+0x122/0x295
[<c01010f0>] cpu_idle+0x50/0x60
[<c036882a>] start_kernel+0x15a/0x180
[<c03683c0>] unknown_bootoption+0x0/0x1e0
While testing my patch I had the below error, is it related to the
refcount leak or might it be a different issue?
ctevent: skb->ct != ecache->ct !!!
[<d0c6e4e8>] tcp_packet+0x278/0x5d0 [ip_conntrack]
[<d0c6b697>] __ip_conntrack_find+0x17/0xb0 [ip_conntrack]
[<d0c6b782>] ip_conntrack_find_get+0x52/0x60 [ip_conntrack]
[<d0c6c33f>] ip_conntrack_in+0xef/0x2f0 [ip_conntrack]
[<c029e420>] dst_output+0x0/0x30
[<c028ef38>] nf_iterate+0x78/0x90
[<c029e420>] dst_output+0x0/0x30
[<c029e420>] dst_output+0x0/0x30
[<c028f42e>] nf_hook_slow+0x7e/0x150
[<c029e420>] dst_output+0x0/0x30
[<c029c313>] ip_queue_xmit+0x403/0x570
[<c029e420>] dst_output+0x0/0x30
[<c022185a>] extract_buf+0xda/0x120
[<c02b1c05>] tcp_v4_send_check+0x55/0x100
[<c02ab818>] tcp_transmit_skb+0x478/0x720
[<c02ac890>] tcp_write_xmit+0x150/0x3f0
[<c02acb69>] __tcp_push_pending_frames+0x39/0xd0
[<c02a1226>] tcp_sendmsg+0x346/0xb70
[<c02c16ed>] inet_sendmsg+0x4d/0x60
[<c0278886>] sock_aio_write+0xf6/0x120
[<c015a381>] do_sync_write+0xd1/0x120
[<c0150439>] page_add_file_rmap+0x59/0x70
[<c014b43c>] handle_mm_fault+0xfc/0x250
[<c012f060>] autoremove_wake_function+0x0/0x60
[<c015a53d>] vfs_write+0x16d/0x180
[<c015a621>] sys_write+0x51/0x80
[<c0103185>] syscall_call+0x7/0xb
ctevent: skb->ct != ecache->ct !!!
[<d0c6cfc6>] ip_ct_refresh_acct+0x146/0x150 [ip_conntrack]
[<d0c6e45a>] tcp_packet+0x1ea/0x5d0 [ip_conntrack]
[<d0c6b697>] __ip_conntrack_find+0x17/0xb0 [ip_conntrack]
[<d0c6b782>] ip_conntrack_find_get+0x52/0x60 [ip_conntrack]
[<d0c6c33f>] ip_conntrack_in+0xef/0x2f0 [ip_conntrack]
[<c029e420>] dst_output+0x0/0x30
[<c028ef38>] nf_iterate+0x78/0x90
[<c029e420>] dst_output+0x0/0x30
[<c029e420>] dst_output+0x0/0x30
[<c028f42e>] nf_hook_slow+0x7e/0x150
[<c029e420>] dst_output+0x0/0x30
[<c029c313>] ip_queue_xmit+0x403/0x570
[<c029e420>] dst_output+0x0/0x30
[<c022185a>] extract_buf+0xda/0x120
[<c02b1c05>] tcp_v4_send_check+0x55/0x100
[<c02ab818>] tcp_transmit_skb+0x478/0x720
[<c02ac890>] tcp_write_xmit+0x150/0x3f0
[<c02acb69>] __tcp_push_pending_frames+0x39/0xd0
[<c02a1226>] tcp_sendmsg+0x346/0xb70
[<c02c16ed>] inet_sendmsg+0x4d/0x60
[<c0278886>] sock_aio_write+0xf6/0x120
[<c015a381>] do_sync_write+0xd1/0x120
[<c0150439>] page_add_file_rmap+0x59/0x70
[<c014b43c>] handle_mm_fault+0xfc/0x250
[<c012f060>] autoremove_wake_function+0x0/0x60
[<c015a53d>] vfs_write+0x16d/0x180
[<c015a621>] sys_write+0x51/0x80
[<c0103185>] syscall_call+0x7/0xb
--
mattia
:wq!
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: BUG: atomic counter underflow at ip_conntrack_event_cache_init+0x91/0xb0 (with patch)
2005-08-01 16:05 ` Mattia Dongili
@ 2005-08-01 17:08 ` Patrick McHardy
2005-08-02 0:47 ` Patrick McHardy
0 siblings, 1 reply; 9+ messages in thread
From: Patrick McHardy @ 2005-08-01 17:08 UTC (permalink / raw)
To: Mattia Dongili
Cc: Linux Kernel Mailing List, Netfilter Development Mailinglist,
David S. Miller, Harald Welte
Mattia Dongili wrote:
> On Mon, Aug 01, 2005 at 04:27:53PM +0200, Patrick McHardy wrote:
>
>>>--- include/linux/netfilter_ipv4/ip_conntrack.h.clean 2005-08-01 15:09:49.000000000 +0200
>>>+++ include/linux/netfilter_ipv4/ip_conntrack.h 2005-08-01 15:08:52.000000000 +0200
>>>@@ -298,6 +298,7 @@ static inline struct ip_conntrack *
>>> ip_conntrack_get(const struct sk_buff *skb, enum ip_conntrack_info *ctinfo)
>>> {
>>> *ctinfo = skb->nfctinfo;
>>>+ nf_conntrack_get(skb->nfct);
>>> return (struct ip_conntrack *)skb->nfct;
>>> }
>>
>>This creates lots of refcnt leaks, which is probably why it makes the
>>underflow go away :) Please try this patch instead.
>
>
> this doesn't fix it actually, see dmesg below:
It looks like ip_ct_iterate_cleanup and ip_conntrack_event_cache_init
race against each other with assigning pointers and grabbing/putting the
refcounts if called from different contexts.
> While testing my patch I had the below error, is it related to the
> refcount leak or might it be a different issue?
>
> ctevent: skb->ct != ecache->ct !!!
> [<d0c6e4e8>] tcp_packet+0x278/0x5d0 [ip_conntrack]
> [<d0c6b697>] __ip_conntrack_find+0x17/0xb0 [ip_conntrack]
> [<d0c6b782>] ip_conntrack_find_get+0x52/0x60 [ip_conntrack]
> [<d0c6c33f>] ip_conntrack_in+0xef/0x2f0 [ip_conntrack]
> [<c029e420>] dst_output+0x0/0x30
> [<c028ef38>] nf_iterate+0x78/0x90
> [<c029e420>] dst_output+0x0/0x30
> [<c029e420>] dst_output+0x0/0x30
> [<c028f42e>] nf_hook_slow+0x7e/0x150
> [<c029e420>] dst_output+0x0/0x30
> [<c029c313>] ip_queue_xmit+0x403/0x570
> [<c029e420>] dst_output+0x0/0x30
> [<c022185a>] extract_buf+0xda/0x120
> [<c02b1c05>] tcp_v4_send_check+0x55/0x100
> [<c02ab818>] tcp_transmit_skb+0x478/0x720
> [<c02ac890>] tcp_write_xmit+0x150/0x3f0
> [<c02acb69>] __tcp_push_pending_frames+0x39/0xd0
> [<c02a1226>] tcp_sendmsg+0x346/0xb70
> [<c02c16ed>] inet_sendmsg+0x4d/0x60
> [<c0278886>] sock_aio_write+0xf6/0x120
> [<c015a381>] do_sync_write+0xd1/0x120
> [<c0150439>] page_add_file_rmap+0x59/0x70
> [<c014b43c>] handle_mm_fault+0xfc/0x250
> [<c012f060>] autoremove_wake_function+0x0/0x60
> [<c015a53d>] vfs_write+0x16d/0x180
> [<c015a621>] sys_write+0x51/0x80
> [<c0103185>] syscall_call+0x7/0xb
It could happen if the output path of a locally generated packet was
interrupted by a softirq, which would make the event cache point to a
different conntrack when it is resumed. But this doesn't happen in your
case, I don't understand how this happened.
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: BUG: atomic counter underflow at ip_conntrack_event_cache_init+0x91/0xb0 (with patch)
2005-08-01 17:08 ` Patrick McHardy
@ 2005-08-02 0:47 ` Patrick McHardy
2005-08-02 10:44 ` Mattia Dongili
2005-08-02 13:29 ` Mattia Dongili
0 siblings, 2 replies; 9+ messages in thread
From: Patrick McHardy @ 2005-08-02 0:47 UTC (permalink / raw)
To: Mattia Dongili
Cc: Harald Welte, Netfilter Development Mailinglist,
Linux Kernel Mailing List
[-- Attachment #1: Type: text/plain, Size: 1336 bytes --]
Patrick McHardy wrote:
> Mattia Dongili wrote:
>
>>On Mon, Aug 01, 2005 at 04:27:53PM +0200, Patrick McHardy wrote:
>>
>>
>>>>--- include/linux/netfilter_ipv4/ip_conntrack.h.clean 2005-08-01 15:09:49.000000000 +0200
>>>>+++ include/linux/netfilter_ipv4/ip_conntrack.h 2005-08-01 15:08:52.000000000 +0200
>>>>@@ -298,6 +298,7 @@ static inline struct ip_conntrack *
>>>>ip_conntrack_get(const struct sk_buff *skb, enum ip_conntrack_info *ctinfo)
>>>>{
>>>> *ctinfo = skb->nfctinfo;
>>>>+ nf_conntrack_get(skb->nfct);
>>>> return (struct ip_conntrack *)skb->nfct;
>>>>}
>>>
>>>This creates lots of refcnt leaks, which is probably why it makes the
>>>underflow go away :) Please try this patch instead.
>>
>>
>>this doesn't fix it actually, see dmesg below:
>
>
> It looks like ip_ct_iterate_cleanup and ip_conntrack_event_cache_init
> race against each other with assigning pointers and grabbing/putting the
> refcounts if called from different contexts.
This should be a fist step towards fixing it. It's probably incomplete
(I'm too tired to check it now), but it should fix the problem you're
seeing. Could you give it a spin?
BTW, ip_ct_iterate_cleanup can only be called from ipt_MASQUERADE when
a device goes down. It seems a bit odd that this is happending on boot,
is there anything special about your setup?
Regards
Patrick
[-- Attachment #2: x --]
[-- Type: text/plain, Size: 6365 bytes --]
diff --git a/include/linux/netfilter_ipv4/ip_conntrack.h b/include/linux/netfilter_ipv4/ip_conntrack.h
--- a/include/linux/netfilter_ipv4/ip_conntrack.h
+++ b/include/linux/netfilter_ipv4/ip_conntrack.h
@@ -411,6 +411,7 @@ struct ip_conntrack_stat
#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
#include <linux/notifier.h>
+#include <linux/interrupt.h>
struct ip_conntrack_ecache {
struct ip_conntrack *ct;
@@ -445,26 +446,25 @@ ip_conntrack_expect_unregister_notifier(
return notifier_chain_unregister(&ip_conntrack_expect_chain, nb);
}
+extern void ip_conntrack_event_cache_init(struct ip_conntrack *ct);
+extern void
+ip_conntrack_deliver_cached_events_for(const struct ip_conntrack *ct);
+
static inline void
ip_conntrack_event_cache(enum ip_conntrack_events event,
const struct sk_buff *skb)
{
- struct ip_conntrack_ecache *ecache =
- &__get_cpu_var(ip_conntrack_ecache);
-
- if (unlikely((struct ip_conntrack *) skb->nfct != ecache->ct)) {
- if (net_ratelimit()) {
- printk(KERN_ERR "ctevent: skb->ct != ecache->ct !!!\n");
- dump_stack();
- }
- }
+ struct ip_conntrack *ct = (struct ip_conntrack *)skb->nfct;
+ struct ip_conntrack_ecache *ecache;
+
+ local_bh_disable();
+ ecache = &__get_cpu_var(ip_conntrack_ecache);
+ if (unlikely(ct != ecache->ct))
+ ip_conntrack_event_cache_init(ct);
ecache->events |= event;
+ local_bh_enable();
}
-extern void
-ip_conntrack_deliver_cached_events_for(const struct ip_conntrack *ct);
-extern void ip_conntrack_event_cache_init(const struct sk_buff *skb);
-
static inline void ip_conntrack_event(enum ip_conntrack_events event,
struct ip_conntrack *ct)
{
diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c
--- a/net/ipv4/netfilter/ip_conntrack_core.c
+++ b/net/ipv4/netfilter/ip_conntrack_core.c
@@ -100,56 +100,45 @@ void __ip_ct_deliver_cached_events(struc
/* Deliver all cached events for a particular conntrack. This is called
* by code prior to async packet handling or freeing the skb */
-void
-ip_conntrack_deliver_cached_events_for(const struct ip_conntrack *ct)
+void ip_conntrack_deliver_cached_events_for(const struct ip_conntrack *ct)
{
- struct ip_conntrack_ecache *ecache =
- &__get_cpu_var(ip_conntrack_ecache);
-
- if (!ct)
- return;
-
+ struct ip_conntrack_ecache *ecache;
+
+ local_bh_disable();
+ ecache = &__get_cpu_var(ip_conntrack_ecache);
if (ecache->ct == ct) {
DEBUGP("ecache: delivering event for %p\n", ct);
__deliver_cached_events(ecache);
} else {
- if (net_ratelimit())
- printk(KERN_WARNING "ecache: want to deliver for %p, "
- "but cache has %p\n", ct, ecache->ct);
+ DEBUGP("ecache: already delivered for %p, cache %p",
+ ct, ecache->ct);
}
-
/* signalize that events have already been delivered */
ecache->ct = NULL;
+ local_bh_enable();
}
/* Deliver cached events for old pending events, if current conntrack != old */
-void ip_conntrack_event_cache_init(const struct sk_buff *skb)
+void ip_conntrack_event_cache_init(struct ip_conntrack *ct)
{
- struct ip_conntrack *ct = (struct ip_conntrack *) skb->nfct;
- struct ip_conntrack_ecache *ecache =
- &__get_cpu_var(ip_conntrack_ecache);
+ struct ip_conntrack_ecache *ecache;
/* take care of delivering potentially old events */
- if (ecache->ct != ct) {
- enum ip_conntrack_info ctinfo;
- /* we have to check, since at startup the cache is NULL */
- if (likely(ecache->ct)) {
- DEBUGP("ecache: entered for different conntrack: "
- "ecache->ct=%p, skb->nfct=%p. delivering "
- "events\n", ecache->ct, ct);
- __deliver_cached_events(ecache);
- ip_conntrack_put(ecache->ct);
- } else {
- DEBUGP("ecache: entered for conntrack %p, "
- "cache was clean before\n", ct);
- }
-
- /* initialize for this conntrack/packet */
- ecache->ct = ip_conntrack_get(skb, &ctinfo);
- /* ecache->events cleared by __deliver_cached_devents() */
+ ecache = &__get_cpu_var(ip_conntrack_ecache);
+ BUG_ON(ecache->ct == ct);
+ if (ecache->ct) {
+ DEBUGP("ecache: entered for different conntrack: "
+ "ecache->ct=%p, skb->nfct=%p. delivering "
+ "events\n", ecache->ct, ct);
+ __deliver_cached_events(ecache);
+ ip_conntrack_put(ecache->ct);
} else {
- DEBUGP("ecache: re-entered for conntrack %p.\n", ct);
+ DEBUGP("ecache: entered for conntrack %p, "
+ "cache was clean before\n", ct);
}
+ /* initialize for this conntrack/packet */
+ ecache->ct = ct;
+ nf_conntrack_get(&ct->ct_general);
}
#endif /* CONFIG_IP_NF_CONNTRACK_EVENTS */
@@ -873,8 +862,6 @@ unsigned int ip_conntrack_in(unsigned in
IP_NF_ASSERT((*pskb)->nfct);
- ip_conntrack_event_cache_init(*pskb);
-
ret = proto->packet(ct, *pskb, ctinfo);
if (ret < 0) {
/* Invalid: inverse of the return code tells
@@ -1279,15 +1266,18 @@ ip_ct_iterate_cleanup(int (*iter)(struct
/* we need to deliver all cached events in order to drop
* the reference counts */
int cpu;
+
+ local_bh_disable();
for_each_cpu(cpu) {
struct ip_conntrack_ecache *ecache =
&per_cpu(ip_conntrack_ecache, cpu);
if (ecache->ct) {
- __ip_ct_deliver_cached_events(ecache);
+ __deliver_cached_events(ecache);
ip_conntrack_put(ecache->ct);
ecache->ct = NULL;
}
}
+ local_bh_enable();
}
#endif
}
diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c
--- a/net/ipv4/netfilter/ip_conntrack_standalone.c
+++ b/net/ipv4/netfilter/ip_conntrack_standalone.c
@@ -401,9 +401,13 @@ static unsigned int ip_confirm(unsigned
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- ip_conntrack_event_cache_init(*pskb);
/* We've seen it coming out the other side: confirm it */
- return ip_conntrack_confirm(pskb);
+ struct ip_conntrack *ct = (struct ip_conntrack *)(*pskb)->nfct;
+ unsigned int ret;
+
+ ret = ip_conntrack_confirm(pskb);
+ ip_conntrack_deliver_cached_events_for(ct);
+ return ret;
}
static unsigned int ip_conntrack_help(unsigned int hooknum,
@@ -419,7 +423,7 @@ static unsigned int ip_conntrack_help(un
ct = ip_conntrack_get(*pskb, &ctinfo);
if (ct && ct->helper) {
unsigned int ret;
- ip_conntrack_event_cache_init(*pskb);
+ ip_conntrack_event_cache_init(ct);
ret = ct->helper->help(pskb, ct, ctinfo);
if (ret != NF_ACCEPT)
return ret;
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: BUG: atomic counter underflow at ip_conntrack_event_cache_init+0x91/0xb0 (with patch)
2005-08-02 0:47 ` Patrick McHardy
@ 2005-08-02 10:44 ` Mattia Dongili
2005-08-02 13:29 ` Mattia Dongili
1 sibling, 0 replies; 9+ messages in thread
From: Mattia Dongili @ 2005-08-02 10:44 UTC (permalink / raw)
To: Patrick McHardy
Cc: Harald Welte, Netfilter Development Mailinglist,
Linux Kernel Mailing List
On Tue, Aug 02, 2005 at 02:47:55AM +0200, Patrick McHardy wrote:
> Patrick McHardy wrote:
> > Mattia Dongili wrote:
[...]
> >>this doesn't fix it actually, see dmesg below:
blame me... It seems I forgot a damn --dry-run while applying your
first patch :P
And in fact your first fix solves the BUG I was seeing.
> > It looks like ip_ct_iterate_cleanup and ip_conntrack_event_cache_init
> > race against each other with assigning pointers and grabbing/putting the
> > refcounts if called from different contexts.
>
> This should be a fist step towards fixing it. It's probably incomplete
> (I'm too tired to check it now), but it should fix the problem you're
> seeing. Could you give it a spin?
building right now
> BTW, ip_ct_iterate_cleanup can only be called from ipt_MASQUERADE when
> a device goes down. It seems a bit odd that this is happending on boot,
> is there anything special about your setup?
yes, ifplugd. This morning I noticed that booting without networking a
nd without loading ip_conntrack (no iptables rules) everything proceeded
smoothly. So rebooting normally I noticed that the BUG was triggered as
soon as ifplugd configured eth0 (with ip_conntrack already loaded).
I'll try to narrow the thing more and let you know.
--
mattia
:wq!
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: BUG: atomic counter underflow at ip_conntrack_event_cache_init+0x91/0xb0 (with patch)
2005-08-02 0:47 ` Patrick McHardy
2005-08-02 10:44 ` Mattia Dongili
@ 2005-08-02 13:29 ` Mattia Dongili
2005-08-03 18:34 ` Patrick McHardy
1 sibling, 1 reply; 9+ messages in thread
From: Mattia Dongili @ 2005-08-02 13:29 UTC (permalink / raw)
To: Patrick McHardy
Cc: Harald Welte, Netfilter Development Mailinglist,
Linux Kernel Mailing List
On Tue, Aug 02, 2005 at 02:47:55AM +0200, Patrick McHardy wrote:
> Patrick McHardy wrote:
> > Mattia Dongili wrote:
[...]
> This should be a fist step towards fixing it. It's probably incomplete
> (I'm too tired to check it now), but it should fix the problem you're
> seeing. Could you give it a spin?
Done, also this patch fixes the uderflow problem.
> BTW, ip_ct_iterate_cleanup can only be called from ipt_MASQUERADE when
> a device goes down. It seems a bit odd that this is happending on boot,
> is there anything special about your setup?
So I played a little more with the BUGgy kernel and I traked some simple
actions to trigger the underflow:
0- boot at init 1
1- modprobe ipt_MASQUERADE
Netfilter messages via NETLINK v0.30.
ip_conntrack version 2.3 (2044 buckets, 16352 max) - 252 bytes per conntrack
ip_tables: (C) 2000-2002 Netfilter core team
2- ifup eth0
e100: eth0: e100_watchdog: link up, 10Mbps, half-duplex
BUG: atomic counter underflow at:
[<d0c6738a>] ip_ct_iterate_cleanup+0xfa/0x100 [ip_conntrack]
[<d0c441d3>] masq_inet_event+0x33/0x40 [ipt_MASQUERADE]
[<d0c441e0>] device_cmp+0x0/0x40 [ipt_MASQUERADE]
[<c012733d>] notifier_call_chain+0x2d/0x50
[<c02bea43>] inet_del_ifa+0x93/0x1d0
[<c02bf6af>] devinet_ioctl+0x4af/0x5a0
[<c02c1946>] inet_ioctl+0x66/0xb0
[<c0278be9>] sock_ioctl+0xc9/0x230
[<c016df2e>] do_ioctl+0x8e/0xa0
[<c02d5e08>] do_page_fault+0x188/0x613
[<c016e0f5>] vfs_ioctl+0x65/0x1f0
[<c016e2c5>] sys_ioctl+0x45/0x70
[<c0103185>] syscall_call+0x7/0xb
3- ifdown eth0 && ifup eth0
e100: eth0: e100_watchdog: link up, 10Mbps, half-duplex
BUG: atomic counter underflow at:
[<d0c6738a>] ip_ct_iterate_cleanup+0xfa/0x100 [ip_conntrack]
[<d0c441d3>] masq_inet_event+0x33/0x40 [ipt_MASQUERADE]
[<d0c441e0>] device_cmp+0x0/0x40 [ipt_MASQUERADE]
[<c012733d>] notifier_call_chain+0x2d/0x50
[<c02bea43>] inet_del_ifa+0x93/0x1d0
[<c02bf6af>] devinet_ioctl+0x4af/0x5a0
[<c02c1946>] inet_ioctl+0x66/0xb0
[<c0278be9>] sock_ioctl+0xc9/0x230
[<c016df2e>] do_ioctl+0x8e/0xa0
[<c02d5e08>] do_page_fault+0x188/0x613
[<c016e0f5>] vfs_ioctl+0x65/0x1f0
[<c016e2c5>] sys_ioctl+0x45/0x70
[<c0103185>] syscall_call+0x7/0xb
and that's all. So iflugd has not any influence here.
--
mattia
:wq!
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: BUG: atomic counter underflow at ip_conntrack_event_cache_init+0x91/0xb0 (with patch)
2005-08-02 13:29 ` Mattia Dongili
@ 2005-08-03 18:34 ` Patrick McHardy
2005-08-05 9:06 ` David S. Miller
0 siblings, 1 reply; 9+ messages in thread
From: Patrick McHardy @ 2005-08-03 18:34 UTC (permalink / raw)
To: Mattia Dongili
Cc: Harald Welte, Netfilter Development Mailinglist,
Linux Kernel Mailing List, David S. Miller
[-- Attachment #1: Type: text/plain, Size: 369 bytes --]
Mattia Dongili wrote:
> On Tue, Aug 02, 2005 at 02:47:55AM +0200, Patrick McHardy wrote:
>
>>This should be a fist step towards fixing it. It's probably incomplete
>>(I'm too tired to check it now), but it should fix the problem you're
>>seeing. Could you give it a spin?
>
> Done, also this patch fixes the uderflow problem.
Thanks. I've attached the final patch.
[-- Attachment #2: x --]
[-- Type: text/plain, Size: 10692 bytes --]
[NETFILTER]: Fix multiple problems with the conntrack event cache
refcnt underflow: the reference count is decremented when a conntrack
entry is removed from the hash but it is not incremented when entering
new entries.
missing protection of process context against softirq context: all
cache operations need to locally disable softirqs to avoid races.
Additionally the event cache can't be initialized when a packet enteres
the conntrack code but needs to be initialized whenever we cache an event
and the stored conntrack entry doesn't match the current one.
incorrect flushing of the event cache in ip_ct_iterate_cleanup: without
real locking we can't flush the cache for different CPUs without incurring
races. The cache for different CPUs can only be flushed when no packets
are going through the code. ip_ct_iterate_cleanup doesn't need to drop
all references, so flushing is moved to the cleanup path.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit d20d18715b8425060334e879ebb4835202457b3e
tree 3279243f59162c14f8ac145473e1c3f4c586b2fa
parent df2e0392536ecdd6385f4319f746045fd6fae38f
author Patrick McHardy <kaber@trash.net> Wed, 03 Aug 2005 20:33:25 +0200
committer Patrick McHardy <kaber@trash.net> Wed, 03 Aug 2005 20:33:25 +0200
include/linux/netfilter_ipv4/ip_conntrack.h | 29 +++---
include/linux/netfilter_ipv4/ip_conntrack_core.h | 14 +--
net/ipv4/netfilter/ip_conntrack_core.c | 107 ++++++++--------------
net/ipv4/netfilter/ip_conntrack_standalone.c | 3 -
4 files changed, 58 insertions(+), 95 deletions(-)
diff --git a/include/linux/netfilter_ipv4/ip_conntrack.h b/include/linux/netfilter_ipv4/ip_conntrack.h
--- a/include/linux/netfilter_ipv4/ip_conntrack.h
+++ b/include/linux/netfilter_ipv4/ip_conntrack.h
@@ -411,6 +411,7 @@ struct ip_conntrack_stat
#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
#include <linux/notifier.h>
+#include <linux/interrupt.h>
struct ip_conntrack_ecache {
struct ip_conntrack *ct;
@@ -445,26 +446,24 @@ ip_conntrack_expect_unregister_notifier(
return notifier_chain_unregister(&ip_conntrack_expect_chain, nb);
}
+extern void ip_ct_deliver_cached_events(const struct ip_conntrack *ct);
+extern void __ip_ct_event_cache_init(struct ip_conntrack *ct);
+
static inline void
ip_conntrack_event_cache(enum ip_conntrack_events event,
const struct sk_buff *skb)
{
- struct ip_conntrack_ecache *ecache =
- &__get_cpu_var(ip_conntrack_ecache);
-
- if (unlikely((struct ip_conntrack *) skb->nfct != ecache->ct)) {
- if (net_ratelimit()) {
- printk(KERN_ERR "ctevent: skb->ct != ecache->ct !!!\n");
- dump_stack();
- }
- }
+ struct ip_conntrack *ct = (struct ip_conntrack *)skb->nfct;
+ struct ip_conntrack_ecache *ecache;
+
+ local_bh_disable();
+ ecache = &__get_cpu_var(ip_conntrack_ecache);
+ if (ct != ecache->ct)
+ __ip_ct_event_cache_init(ct);
ecache->events |= event;
+ local_bh_enable();
}
-extern void
-ip_conntrack_deliver_cached_events_for(const struct ip_conntrack *ct);
-extern void ip_conntrack_event_cache_init(const struct sk_buff *skb);
-
static inline void ip_conntrack_event(enum ip_conntrack_events event,
struct ip_conntrack *ct)
{
@@ -483,9 +482,7 @@ static inline void ip_conntrack_event_ca
const struct sk_buff *skb) {}
static inline void ip_conntrack_event(enum ip_conntrack_events event,
struct ip_conntrack *ct) {}
-static inline void ip_conntrack_deliver_cached_events_for(
- struct ip_conntrack *ct) {}
-static inline void ip_conntrack_event_cache_init(const struct sk_buff *skb) {}
+static inline void ip_ct_deliver_cached_events(const struct ip_conntrack *ct) {}
static inline void
ip_conntrack_expect_event(enum ip_conntrack_expect_events event,
struct ip_conntrack_expect *exp) {}
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_core.h b/include/linux/netfilter_ipv4/ip_conntrack_core.h
--- a/include/linux/netfilter_ipv4/ip_conntrack_core.h
+++ b/include/linux/netfilter_ipv4/ip_conntrack_core.h
@@ -44,18 +44,14 @@ static inline int ip_conntrack_confirm(s
struct ip_conntrack *ct = (struct ip_conntrack *)(*pskb)->nfct;
int ret = NF_ACCEPT;
- if (ct && !is_confirmed(ct))
- ret = __ip_conntrack_confirm(pskb);
- ip_conntrack_deliver_cached_events_for(ct);
-
+ if (ct) {
+ if (!is_confirmed(ct))
+ ret = __ip_conntrack_confirm(pskb);
+ ip_ct_deliver_cached_events(ct);
+ }
return ret;
}
-#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
-struct ip_conntrack_ecache;
-extern void __ip_ct_deliver_cached_events(struct ip_conntrack_ecache *ec);
-#endif
-
extern void __ip_ct_expect_unlink_destroy(struct ip_conntrack_expect *exp);
extern struct list_head *ip_conntrack_hash;
diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c
--- a/net/ipv4/netfilter/ip_conntrack_core.c
+++ b/net/ipv4/netfilter/ip_conntrack_core.c
@@ -85,73 +85,62 @@ struct notifier_block *ip_conntrack_expe
DEFINE_PER_CPU(struct ip_conntrack_ecache, ip_conntrack_ecache);
-static inline void __deliver_cached_events(struct ip_conntrack_ecache *ecache)
+/* deliver cached events and clear cache entry - must be called with locally
+ * disabled softirqs */
+static inline void
+__ip_ct_deliver_cached_events(struct ip_conntrack_ecache *ecache)
{
+ DEBUGP("ecache: delivering events for %p\n", ecache->ct);
if (is_confirmed(ecache->ct) && !is_dying(ecache->ct) && ecache->events)
notifier_call_chain(&ip_conntrack_chain, ecache->events,
ecache->ct);
ecache->events = 0;
-}
-
-void __ip_ct_deliver_cached_events(struct ip_conntrack_ecache *ecache)
-{
- __deliver_cached_events(ecache);
+ ip_conntrack_put(ecache->ct);
+ ecache->ct = NULL;
}
/* Deliver all cached events for a particular conntrack. This is called
* by code prior to async packet handling or freeing the skb */
-void
-ip_conntrack_deliver_cached_events_for(const struct ip_conntrack *ct)
+void ip_ct_deliver_cached_events(const struct ip_conntrack *ct)
{
- struct ip_conntrack_ecache *ecache =
- &__get_cpu_var(ip_conntrack_ecache);
-
- if (!ct)
- return;
-
- if (ecache->ct == ct) {
- DEBUGP("ecache: delivering event for %p\n", ct);
- __deliver_cached_events(ecache);
- } else {
- if (net_ratelimit())
- printk(KERN_WARNING "ecache: want to deliver for %p, "
- "but cache has %p\n", ct, ecache->ct);
- }
-
- /* signalize that events have already been delivered */
- ecache->ct = NULL;
+ struct ip_conntrack_ecache *ecache;
+
+ local_bh_disable();
+ ecache = &__get_cpu_var(ip_conntrack_ecache);
+ if (ecache->ct == ct)
+ __ip_ct_deliver_cached_events(ecache);
+ local_bh_enable();
}
-/* Deliver cached events for old pending events, if current conntrack != old */
-void ip_conntrack_event_cache_init(const struct sk_buff *skb)
+void __ip_ct_event_cache_init(struct ip_conntrack *ct)
{
- struct ip_conntrack *ct = (struct ip_conntrack *) skb->nfct;
- struct ip_conntrack_ecache *ecache =
- &__get_cpu_var(ip_conntrack_ecache);
+ struct ip_conntrack_ecache *ecache;
/* take care of delivering potentially old events */
- if (ecache->ct != ct) {
- enum ip_conntrack_info ctinfo;
- /* we have to check, since at startup the cache is NULL */
- if (likely(ecache->ct)) {
- DEBUGP("ecache: entered for different conntrack: "
- "ecache->ct=%p, skb->nfct=%p. delivering "
- "events\n", ecache->ct, ct);
- __deliver_cached_events(ecache);
+ ecache = &__get_cpu_var(ip_conntrack_ecache);
+ BUG_ON(ecache->ct == ct);
+ if (ecache->ct)
+ __ip_ct_deliver_cached_events(ecache);
+ /* initialize for this conntrack/packet */
+ ecache->ct = ct;
+ nf_conntrack_get(&ct->ct_general);
+}
+
+/* flush the event cache - touches other CPU's data and must not be called while
+ * packets are still passing through the code */
+static void ip_ct_event_cache_flush(void)
+{
+ struct ip_conntrack_ecache *ecache;
+ int cpu;
+
+ for_each_cpu(cpu) {
+ ecache = &per_cpu(ip_conntrack_ecache, cpu);
+ if (ecache->ct)
ip_conntrack_put(ecache->ct);
- } else {
- DEBUGP("ecache: entered for conntrack %p, "
- "cache was clean before\n", ct);
- }
-
- /* initialize for this conntrack/packet */
- ecache->ct = ip_conntrack_get(skb, &ctinfo);
- /* ecache->events cleared by __deliver_cached_devents() */
- } else {
- DEBUGP("ecache: re-entered for conntrack %p.\n", ct);
}
}
-
+#else
+static inline void ip_ct_event_cache_flush(void) {}
#endif /* CONFIG_IP_NF_CONNTRACK_EVENTS */
DEFINE_PER_CPU(struct ip_conntrack_stat, ip_conntrack_stat);
@@ -873,8 +862,6 @@ unsigned int ip_conntrack_in(unsigned in
IP_NF_ASSERT((*pskb)->nfct);
- ip_conntrack_event_cache_init(*pskb);
-
ret = proto->packet(ct, *pskb, ctinfo);
if (ret < 0) {
/* Invalid: inverse of the return code tells
@@ -1273,23 +1260,6 @@ ip_ct_iterate_cleanup(int (*iter)(struct
ip_conntrack_put(ct);
}
-
-#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
- {
- /* we need to deliver all cached events in order to drop
- * the reference counts */
- int cpu;
- for_each_cpu(cpu) {
- struct ip_conntrack_ecache *ecache =
- &per_cpu(ip_conntrack_ecache, cpu);
- if (ecache->ct) {
- __ip_ct_deliver_cached_events(ecache);
- ip_conntrack_put(ecache->ct);
- ecache->ct = NULL;
- }
- }
- }
-#endif
}
/* Fast function for those who don't want to parse /proc (and I don't
@@ -1376,6 +1346,7 @@ void ip_conntrack_flush()
delete... */
synchronize_net();
+ ip_ct_event_cache_flush();
i_see_dead_people:
ip_ct_iterate_cleanup(kill_all, NULL);
if (atomic_read(&ip_conntrack_count) != 0) {
diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c
--- a/net/ipv4/netfilter/ip_conntrack_standalone.c
+++ b/net/ipv4/netfilter/ip_conntrack_standalone.c
@@ -401,7 +401,6 @@ static unsigned int ip_confirm(unsigned
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- ip_conntrack_event_cache_init(*pskb);
/* We've seen it coming out the other side: confirm it */
return ip_conntrack_confirm(pskb);
}
@@ -419,7 +418,6 @@ static unsigned int ip_conntrack_help(un
ct = ip_conntrack_get(*pskb, &ctinfo);
if (ct && ct->helper) {
unsigned int ret;
- ip_conntrack_event_cache_init(*pskb);
ret = ct->helper->help(pskb, ct, ctinfo);
if (ret != NF_ACCEPT)
return ret;
@@ -978,6 +976,7 @@ EXPORT_SYMBOL_GPL(ip_conntrack_chain);
EXPORT_SYMBOL_GPL(ip_conntrack_expect_chain);
EXPORT_SYMBOL_GPL(ip_conntrack_register_notifier);
EXPORT_SYMBOL_GPL(ip_conntrack_unregister_notifier);
+EXPORT_SYMBOL_GPL(__ip_ct_event_cache_init);
EXPORT_PER_CPU_SYMBOL_GPL(ip_conntrack_ecache);
#endif
EXPORT_SYMBOL(ip_conntrack_protocol_register);
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: BUG: atomic counter underflow at ip_conntrack_event_cache_init+0x91/0xb0 (with patch)
2005-08-03 18:34 ` Patrick McHardy
@ 2005-08-05 9:06 ` David S. Miller
0 siblings, 0 replies; 9+ messages in thread
From: David S. Miller @ 2005-08-05 9:06 UTC (permalink / raw)
To: kaber; +Cc: malattia, laforge, netfilter-devel, linux-kernel
From: Patrick McHardy <kaber@trash.net>
Date: Wed, 03 Aug 2005 20:34:57 +0200
> [NETFILTER]: Fix multiple problems with the conntrack event cache
Applied to net-2.6.14, thanks Patrick.
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2005-08-05 9:06 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-08-01 14:13 BUG: atomic counter underflow at ip_conntrack_event_cache_init+0x91/0xb0 (with patch) Mattia Dongili
2005-08-01 14:27 ` Patrick McHardy
2005-08-01 16:05 ` Mattia Dongili
2005-08-01 17:08 ` Patrick McHardy
2005-08-02 0:47 ` Patrick McHardy
2005-08-02 10:44 ` Mattia Dongili
2005-08-02 13:29 ` Mattia Dongili
2005-08-03 18:34 ` Patrick McHardy
2005-08-05 9:06 ` David S. Miller
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox