|
@@ -448,7 +448,9 @@ nf_conntrack_hash_check_insert(struct nf_conn *ct)
|
|
|
goto out;
|
|
|
|
|
|
add_timer(&ct->timeout);
|
|
|
- nf_conntrack_get(&ct->ct_general);
|
|
|
+ smp_wmb();
|
|
|
+ /* The caller holds a reference to this object */
|
|
|
+ atomic_set(&ct->ct_general.use, 2);
|
|
|
__nf_conntrack_hash_insert(ct, hash, repl_hash);
|
|
|
NF_CT_STAT_INC(net, insert);
|
|
|
spin_unlock_bh(&nf_conntrack_lock);
|
|
@@ -462,6 +464,21 @@ out:
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(nf_conntrack_hash_check_insert);
|
|
|
|
|
|
+/* deletion from this larval template list happens via nf_ct_put() */
|
|
|
+void nf_conntrack_tmpl_insert(struct net *net, struct nf_conn *tmpl)
|
|
|
+{
|
|
|
+ __set_bit(IPS_TEMPLATE_BIT, &tmpl->status);
|
|
|
+ __set_bit(IPS_CONFIRMED_BIT, &tmpl->status);
|
|
|
+ nf_conntrack_get(&tmpl->ct_general);
|
|
|
+
|
|
|
+ spin_lock_bh(&nf_conntrack_lock);
|
|
|
+ /* Overload tuple linked list to put us in template list. */
|
|
|
+ hlist_nulls_add_head_rcu(&tmpl->tuplehash[IP_CT_DIR_ORIGINAL].hnnode,
|
|
|
+ &net->ct.tmpl);
|
|
|
+ spin_unlock_bh(&nf_conntrack_lock);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(nf_conntrack_tmpl_insert);
|
|
|
+
|
|
|
/* Confirm a connection given skb; places it in hash table */
|
|
|
int
|
|
|
__nf_conntrack_confirm(struct sk_buff *skb)
|
|
@@ -733,11 +750,10 @@ __nf_conntrack_alloc(struct net *net, u16 zone,
|
|
|
nf_ct_zone->id = zone;
|
|
|
}
|
|
|
#endif
|
|
|
- /*
|
|
|
- * changes to lookup keys must be done before setting refcnt to 1
|
|
|
+ /* Because we use RCU lookups, we set ct_general.use to zero before
|
|
|
+ * this is inserted in any list.
|
|
|
*/
|
|
|
- smp_wmb();
|
|
|
- atomic_set(&ct->ct_general.use, 1);
|
|
|
+ atomic_set(&ct->ct_general.use, 0);
|
|
|
return ct;
|
|
|
|
|
|
#ifdef CONFIG_NF_CONNTRACK_ZONES
|
|
@@ -761,6 +777,11 @@ void nf_conntrack_free(struct nf_conn *ct)
|
|
|
{
|
|
|
struct net *net = nf_ct_net(ct);
|
|
|
|
|
|
+ /* A freed object has refcnt == 0, that's
|
|
|
+ * the golden rule for SLAB_DESTROY_BY_RCU
|
|
|
+ */
|
|
|
+ NF_CT_ASSERT(atomic_read(&ct->ct_general.use) == 0);
|
|
|
+
|
|
|
nf_ct_ext_destroy(ct);
|
|
|
nf_ct_ext_free(ct);
|
|
|
kmem_cache_free(net->ct.nf_conntrack_cachep, ct);
|
|
@@ -856,6 +877,9 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
|
|
|
NF_CT_STAT_INC(net, new);
|
|
|
}
|
|
|
|
|
|
+ /* Now it is inserted into the unconfirmed list, bump refcount */
|
|
|
+ nf_conntrack_get(&ct->ct_general);
|
|
|
+
|
|
|
/* Overload tuple linked list to put us in unconfirmed list. */
|
|
|
hlist_nulls_add_head_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode,
|
|
|
&net->ct.unconfirmed);
|