netfilter: nf_conntrack: fix racy timer handling with reliable events
[pandora-kernel.git] / net / netfilter / nf_conntrack_core.c
index 5acfaf5..7489bd3 100644 (file)
@@ -247,12 +247,15 @@ static void death_by_event(unsigned long ul_conntrack)
 {
        struct nf_conn *ct = (void *)ul_conntrack;
        struct net *net = nf_ct_net(ct);
+       struct nf_conntrack_ecache *ecache = nf_ct_ecache_find(ct);
+
+       BUG_ON(ecache == NULL);
 
        if (nf_conntrack_event(IPCT_DESTROY, ct) < 0) {
                /* bad luck, let's retry again */
-               ct->timeout.expires = jiffies +
+               ecache->timeout.expires = jiffies +
                        (random32() % net->ct.sysctl_events_retry_timeout);
-               add_timer(&ct->timeout);
+               add_timer(&ecache->timeout);
                return;
        }
        /* we've got the event delivered, now it's dying */
@@ -266,6 +269,9 @@ static void death_by_event(unsigned long ul_conntrack)
 void nf_ct_insert_dying_list(struct nf_conn *ct)
 {
        struct net *net = nf_ct_net(ct);
+       struct nf_conntrack_ecache *ecache = nf_ct_ecache_find(ct);
+
+       BUG_ON(ecache == NULL);
 
        /* add this conntrack to the dying list */
        spin_lock_bh(&nf_conntrack_lock);
@@ -273,10 +279,10 @@ void nf_ct_insert_dying_list(struct nf_conn *ct)
                             &net->ct.dying);
        spin_unlock_bh(&nf_conntrack_lock);
        /* set a new timer to retry event delivery */
-       setup_timer(&ct->timeout, death_by_event, (unsigned long)ct);
-       ct->timeout.expires = jiffies +
+       setup_timer(&ecache->timeout, death_by_event, (unsigned long)ct);
+       ecache->timeout.expires = jiffies +
                (random32() % net->ct.sysctl_events_retry_timeout);
-       add_timer(&ct->timeout);
+       add_timer(&ecache->timeout);
 }
 EXPORT_SYMBOL_GPL(nf_ct_insert_dying_list);
 
@@ -661,7 +667,6 @@ __nf_conntrack_alloc(struct net *net, u16 zone,
         */
        ct = kmem_cache_alloc(net->ct.nf_conntrack_cachep, gfp);
        if (ct == NULL) {
-               pr_debug("nf_conntrack_alloc: Can't alloc conntrack.\n");
                atomic_dec(&net->ct.count);
                return ERR_PTR(-ENOMEM);
        }
@@ -749,10 +754,8 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
 
        ct = __nf_conntrack_alloc(net, zone, tuple, &repl_tuple, GFP_ATOMIC,
                                  hash);
-       if (IS_ERR(ct)) {
-               pr_debug("Can't allocate conntrack.\n");
+       if (IS_ERR(ct))
                return (struct nf_conntrack_tuple_hash *)ct;
-       }
 
        if (!l4proto->new(ct, skb, dataoff)) {
                nf_conntrack_free(ct);
@@ -779,7 +782,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
                if (exp->helper) {
                        help = nf_ct_helper_ext_add(ct, GFP_ATOMIC);
                        if (help)
-                               RCU_INIT_POINTER(help->helper, exp->helper);
+                               rcu_assign_pointer(help->helper, exp->helper);
                }
 
 #ifdef CONFIG_NF_CONNTRACK_MARK