|
@@ -63,6 +63,9 @@ EXPORT_SYMBOL_GPL(nfnetlink_parse_nat_setup_hook);
|
|
|
DEFINE_SPINLOCK(nf_conntrack_lock);
|
|
|
EXPORT_SYMBOL_GPL(nf_conntrack_lock);
|
|
|
|
|
|
+__cacheline_aligned_in_smp DEFINE_SPINLOCK(nf_conntrack_expect_lock);
|
|
|
+EXPORT_SYMBOL_GPL(nf_conntrack_expect_lock);
|
|
|
+
|
|
|
unsigned int nf_conntrack_htable_size __read_mostly;
|
|
|
EXPORT_SYMBOL_GPL(nf_conntrack_htable_size);
|
|
|
|
|
@@ -247,9 +250,6 @@ destroy_conntrack(struct nf_conntrack *nfct)
|
|
|
NF_CT_ASSERT(atomic_read(&nfct->use) == 0);
|
|
|
NF_CT_ASSERT(!timer_pending(&ct->timeout));
|
|
|
|
|
|
- /* To make sure we don't get any weird locking issues here:
|
|
|
- * destroy_conntrack() MUST NOT be called with a write lock
|
|
|
- * to nf_conntrack_lock!!! -HW */
|
|
|
rcu_read_lock();
|
|
|
l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct));
|
|
|
if (l4proto && l4proto->destroy)
|
|
@@ -257,17 +257,18 @@ destroy_conntrack(struct nf_conntrack *nfct)
|
|
|
|
|
|
rcu_read_unlock();
|
|
|
|
|
|
- spin_lock_bh(&nf_conntrack_lock);
|
|
|
+ local_bh_disable();
|
|
|
/* Expectations will have been removed in clean_from_lists,
|
|
|
* except TFTP can create an expectation on the first packet,
|
|
|
* before connection is in the list, so we need to clean here,
|
|
|
- * too. */
|
|
|
+ * too.
|
|
|
+ */
|
|
|
nf_ct_remove_expectations(ct);
|
|
|
|
|
|
nf_ct_del_from_dying_or_unconfirmed_list(ct);
|
|
|
|
|
|
NF_CT_STAT_INC(net, delete);
|
|
|
- spin_unlock_bh(&nf_conntrack_lock);
|
|
|
+ local_bh_enable();
|
|
|
|
|
|
if (ct->master)
|
|
|
nf_ct_put(ct->master);
|
|
@@ -851,7 +852,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
|
|
|
struct nf_conn_help *help;
|
|
|
struct nf_conntrack_tuple repl_tuple;
|
|
|
struct nf_conntrack_ecache *ecache;
|
|
|
- struct nf_conntrack_expect *exp;
|
|
|
+ struct nf_conntrack_expect *exp = NULL;
|
|
|
u16 zone = tmpl ? nf_ct_zone(tmpl) : NF_CT_DEFAULT_ZONE;
|
|
|
struct nf_conn_timeout *timeout_ext;
|
|
|
unsigned int *timeouts;
|
|
@@ -895,30 +896,35 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
|
|
|
ecache ? ecache->expmask : 0,
|
|
|
GFP_ATOMIC);
|
|
|
|
|
|
- spin_lock_bh(&nf_conntrack_lock);
|
|
|
- exp = nf_ct_find_expectation(net, zone, tuple);
|
|
|
- if (exp) {
|
|
|
- pr_debug("conntrack: expectation arrives ct=%p exp=%p\n",
|
|
|
- ct, exp);
|
|
|
- /* Welcome, Mr. Bond. We've been expecting you... */
|
|
|
- __set_bit(IPS_EXPECTED_BIT, &ct->status);
|
|
|
- /* exp->master safe, refcnt bumped in nf_ct_find_expectation */
|
|
|
- ct->master = exp->master;
|
|
|
- if (exp->helper) {
|
|
|
- help = nf_ct_helper_ext_add(ct, exp->helper,
|
|
|
- GFP_ATOMIC);
|
|
|
- if (help)
|
|
|
- rcu_assign_pointer(help->helper, exp->helper);
|
|
|
- }
|
|
|
+ local_bh_disable();
|
|
|
+ if (net->ct.expect_count) {
|
|
|
+ spin_lock(&nf_conntrack_expect_lock);
|
|
|
+ exp = nf_ct_find_expectation(net, zone, tuple);
|
|
|
+ if (exp) {
|
|
|
+ pr_debug("conntrack: expectation arrives ct=%p exp=%p\n",
|
|
|
+ ct, exp);
|
|
|
+ /* Welcome, Mr. Bond. We've been expecting you... */
|
|
|
+ __set_bit(IPS_EXPECTED_BIT, &ct->status);
|
|
|
+ /* exp->master safe, refcnt bumped in nf_ct_find_expectation */
|
|
|
+ ct->master = exp->master;
|
|
|
+ if (exp->helper) {
|
|
|
+ help = nf_ct_helper_ext_add(ct, exp->helper,
|
|
|
+ GFP_ATOMIC);
|
|
|
+ if (help)
|
|
|
+ rcu_assign_pointer(help->helper, exp->helper);
|
|
|
+ }
|
|
|
|
|
|
#ifdef CONFIG_NF_CONNTRACK_MARK
|
|
|
- ct->mark = exp->master->mark;
|
|
|
+ ct->mark = exp->master->mark;
|
|
|
#endif
|
|
|
#ifdef CONFIG_NF_CONNTRACK_SECMARK
|
|
|
- ct->secmark = exp->master->secmark;
|
|
|
+ ct->secmark = exp->master->secmark;
|
|
|
#endif
|
|
|
- NF_CT_STAT_INC(net, expect_new);
|
|
|
- } else {
|
|
|
+ NF_CT_STAT_INC(net, expect_new);
|
|
|
+ }
|
|
|
+ spin_unlock(&nf_conntrack_expect_lock);
|
|
|
+ }
|
|
|
+ if (!exp) {
|
|
|
__nf_ct_try_assign_helper(ct, tmpl, GFP_ATOMIC);
|
|
|
NF_CT_STAT_INC(net, new);
|
|
|
}
|
|
@@ -927,7 +933,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
|
|
|
nf_conntrack_get(&ct->ct_general);
|
|
|
nf_ct_add_to_unconfirmed_list(ct);
|
|
|
|
|
|
- spin_unlock_bh(&nf_conntrack_lock);
|
|
|
+ local_bh_enable();
|
|
|
|
|
|
if (exp) {
|
|
|
if (exp->expectfn)
|