* 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