Re: bug: kernel timer added twice at c186be43

From: Rusty Russell (rusty@linuxcare.com.au)
Date: Mon Jun 19 2000 - 03:24:49 EST


In message <XFMail.20000618164614.narancs1@externet.hu> you write:
> After I resumed my laptop from suspend I got the mesg in $SUBJ twice.
> It's kernel 2.4.0-test1-ac10 compiled by
> gcc version 2.95.2 20000313 (Debian GNU/Linux 2.2)
> binutils 2.9.5.0.37-1
> the machine is a p150, 16mb ram portocom laptop. I have never seen this mesg
> before. What add. info do you need?
> What does it mean?

If you're using conntrack/NAT, that's my bug 8(.

Please try this race fix (untested as yet, but should be right). 8)

diff -urN -X /tmp/fileXpPx0Z --minimal tmp/include/linux/netfilter_ipv4/ip_conntrack.h working-2.4.0-test1/include/linux/netfilter_ipv4/ip_conntrack.h
--- tmp/include/linux/netfilter_ipv4/ip_conntrack.h Wed Jun 7 16:55:02 2000
+++ working-2.4.0-test1/include/linux/netfilter_ipv4/ip_conntrack.h Thu Jun 15 23:25:34 2000
@@ -48,13 +48,16 @@
 /* Bitset representing status of connection. */
 enum ip_conntrack_status {
         /* It's an expected connection: bit 0 set. This bit never changed */
- IPS_EXPECTED = 0x01,
+ IPS_EXPECTED_BIT = 0,
+ IPS_EXPECTED = (1 << IPS_EXPECTED_BIT),
 
         /* We've seen packets both ways: bit 1 set. Can be set, not unset. */
- IPS_SEEN_REPLY = 0x02,
+ IPS_SEEN_REPLY_BIT = 1,
+ IPS_SEEN_REPLY = (1 << IPS_SEEN_REPLY_BIT),
 
         /* Packet seen leaving box: bit 2 set. Can be set, not unset. */
- IPS_CONFIRMED = 0x04
+ IPS_CONFIRMED_BIT = 2,
+ IPS_CONFIRMED = (1 << IPS_CONFIRMED_BIT)
 };
 
 struct ip_conntrack_expect
diff -urN -X /tmp/fileZyMj0d --minimal tmp/net/ipv4/netfilter/ip_conntrack_core.c working-2.4.0-test1/net/ipv4/netfilter/ip_conntrack_core.c
--- tmp/net/ipv4/netfilter/ip_conntrack_core.c Sat Jun 17 02:22:40 2000
+++ working-2.4.0-test1/net/ipv4/netfilter/ip_conntrack_core.c Sat Jun 17 02:35:30 2000
@@ -262,7 +262,7 @@
         /* Race check */
         if (!(ct->status & IPS_CONFIRMED)) {
                 IP_NF_ASSERT(!timer_pending(&ct->timeout));
- ct->status |= IPS_CONFIRMED;
+ set_bit(IPS_CONFIRMED_BIT, &ct->status);
                 /* Timer relative to confirmation time, not original
                    setting time, otherwise we'd get timer wrap in
                    wierd delay cases. */
@@ -536,7 +536,7 @@
 static inline struct ip_conntrack *
 resolve_normal_ct(struct sk_buff *skb,
                   struct ip_conntrack_protocol *proto,
- unsigned int *newstatus,
+ int *set_reply,
                   enum ip_conntrack_info *ctinfo)
 {
         struct ip_conntrack_tuple tuple;
@@ -565,7 +565,8 @@
                 }
 
                 *ctinfo = IP_CT_ESTABLISHED + IP_CT_IS_REPLY;
- *newstatus = (h->ctrack->status | IPS_SEEN_REPLY);
+ /* Please set reply bit if this packet OK */
+ *set_reply = 1;
         } else {
                 /* Once we've had two way comms, always ESTABLISHED. */
                 if (h->ctrack->status & IPS_SEEN_REPLY) {
@@ -581,7 +582,7 @@
                                h->ctrack);
                         *ctinfo = IP_CT_NEW;
                 }
- *newstatus = h->ctrack->status;
+ *set_reply = 0;
         }
         skb->nfct = &h->ctrack->infos[*ctinfo];
         return h->ctrack;
@@ -614,7 +615,7 @@
         struct ip_conntrack *ct;
         enum ip_conntrack_info ctinfo;
         struct ip_conntrack_protocol *proto;
- unsigned int status;
+ int set_reply;
         int ret;
 
         /* FIXME: Do this right please. --RR */
@@ -654,10 +655,10 @@
             && icmp_error_track(*pskb, &ctinfo, hooknum))
                 return NF_ACCEPT;
 
- if (!(ct = resolve_normal_ct(*pskb, proto, &status, &ctinfo))) {
+ if (!(ct = resolve_normal_ct(*pskb, proto, &set_reply, &ctinfo)))
                 /* Not valid part of a connection */
                 return NF_ACCEPT;
- }
+
         IP_NF_ASSERT((*pskb)->nfct);
 
         ret = proto->packet(ct, (*pskb)->nh.iph, (*pskb)->len, ctinfo);
@@ -678,7 +679,8 @@
                         return NF_ACCEPT;
                 }
         }
- ct->status = status;
+ if (set_reply)
+ set_bit(IPS_SEEN_REPLY_BIT, &ct->status);
 
         return ret;
 }
@@ -877,9 +879,12 @@
                            mark confirmed so it gets cleaned as soon
                            as skb freed. */
                         WRITE_LOCK(&ip_conntrack_lock);
+ /* Lock protects race against another setting
+ of confirmed bit. set_bit isolates this
+ bit from the others. */
                         if (!(h->ctrack->status & IPS_CONFIRMED)) {
                                 clean_from_lists(h->ctrack);
- h->ctrack->status |= IPS_CONFIRMED;
+ set_bit(IPS_CONFIRMED_BIT, &h->ctrack->status);
                         }
                         WRITE_UNLOCK(&ip_conntrack_lock);
                 }

--
Hacking time.

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Fri Jun 23 2000 - 21:00:17 EST