diff options
Diffstat (limited to 'net/netfilter/nf_conntrack_expect.c')
-rw-r--r-- | net/netfilter/nf_conntrack_expect.c | 34 |
1 files changed, 20 insertions, 14 deletions
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index a20fb0bd1ef..cd1e8e0970f 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c | |||
@@ -319,7 +319,8 @@ static void nf_ct_expect_insert(struct nf_conntrack_expect *exp) | |||
319 | const struct nf_conntrack_expect_policy *p; | 319 | const struct nf_conntrack_expect_policy *p; |
320 | unsigned int h = nf_ct_expect_dst_hash(&exp->tuple); | 320 | unsigned int h = nf_ct_expect_dst_hash(&exp->tuple); |
321 | 321 | ||
322 | atomic_inc(&exp->use); | 322 | /* two references : one for hash insert, one for the timer */ |
323 | atomic_add(2, &exp->use); | ||
323 | 324 | ||
324 | if (master_help) { | 325 | if (master_help) { |
325 | hlist_add_head(&exp->lnode, &master_help->expectations); | 326 | hlist_add_head(&exp->lnode, &master_help->expectations); |
@@ -333,12 +334,14 @@ static void nf_ct_expect_insert(struct nf_conntrack_expect *exp) | |||
333 | setup_timer(&exp->timeout, nf_ct_expectation_timed_out, | 334 | setup_timer(&exp->timeout, nf_ct_expectation_timed_out, |
334 | (unsigned long)exp); | 335 | (unsigned long)exp); |
335 | if (master_help) { | 336 | if (master_help) { |
336 | p = &master_help->helper->expect_policy[exp->class]; | 337 | p = &rcu_dereference_protected( |
338 | master_help->helper, | ||
339 | lockdep_is_held(&nf_conntrack_lock) | ||
340 | )->expect_policy[exp->class]; | ||
337 | exp->timeout.expires = jiffies + p->timeout * HZ; | 341 | exp->timeout.expires = jiffies + p->timeout * HZ; |
338 | } | 342 | } |
339 | add_timer(&exp->timeout); | 343 | add_timer(&exp->timeout); |
340 | 344 | ||
341 | atomic_inc(&exp->use); | ||
342 | NF_CT_STAT_INC(net, expect_create); | 345 | NF_CT_STAT_INC(net, expect_create); |
343 | } | 346 | } |
344 | 347 | ||
@@ -369,7 +372,10 @@ static inline int refresh_timer(struct nf_conntrack_expect *i) | |||
369 | if (!del_timer(&i->timeout)) | 372 | if (!del_timer(&i->timeout)) |
370 | return 0; | 373 | return 0; |
371 | 374 | ||
372 | p = &master_help->helper->expect_policy[i->class]; | 375 | p = &rcu_dereference_protected( |
376 | master_help->helper, | ||
377 | lockdep_is_held(&nf_conntrack_lock) | ||
378 | )->expect_policy[i->class]; | ||
373 | i->timeout.expires = jiffies + p->timeout * HZ; | 379 | i->timeout.expires = jiffies + p->timeout * HZ; |
374 | add_timer(&i->timeout); | 380 | add_timer(&i->timeout); |
375 | return 1; | 381 | return 1; |
@@ -407,7 +413,10 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect) | |||
407 | } | 413 | } |
408 | /* Will be over limit? */ | 414 | /* Will be over limit? */ |
409 | if (master_help) { | 415 | if (master_help) { |
410 | p = &master_help->helper->expect_policy[expect->class]; | 416 | p = &rcu_dereference_protected( |
417 | master_help->helper, | ||
418 | lockdep_is_held(&nf_conntrack_lock) | ||
419 | )->expect_policy[expect->class]; | ||
411 | if (p->max_expected && | 420 | if (p->max_expected && |
412 | master_help->expecting[expect->class] >= p->max_expected) { | 421 | master_help->expecting[expect->class] >= p->max_expected) { |
413 | evict_oldest_expect(master, expect); | 422 | evict_oldest_expect(master, expect); |
@@ -478,7 +487,7 @@ static struct hlist_node *ct_expect_get_first(struct seq_file *seq) | |||
478 | struct hlist_node *n; | 487 | struct hlist_node *n; |
479 | 488 | ||
480 | for (st->bucket = 0; st->bucket < nf_ct_expect_hsize; st->bucket++) { | 489 | for (st->bucket = 0; st->bucket < nf_ct_expect_hsize; st->bucket++) { |
481 | n = rcu_dereference(net->ct.expect_hash[st->bucket].first); | 490 | n = rcu_dereference(hlist_first_rcu(&net->ct.expect_hash[st->bucket])); |
482 | if (n) | 491 | if (n) |
483 | return n; | 492 | return n; |
484 | } | 493 | } |
@@ -491,11 +500,11 @@ static struct hlist_node *ct_expect_get_next(struct seq_file *seq, | |||
491 | struct net *net = seq_file_net(seq); | 500 | struct net *net = seq_file_net(seq); |
492 | struct ct_expect_iter_state *st = seq->private; | 501 | struct ct_expect_iter_state *st = seq->private; |
493 | 502 | ||
494 | head = rcu_dereference(head->next); | 503 | head = rcu_dereference(hlist_next_rcu(head)); |
495 | while (head == NULL) { | 504 | while (head == NULL) { |
496 | if (++st->bucket >= nf_ct_expect_hsize) | 505 | if (++st->bucket >= nf_ct_expect_hsize) |
497 | return NULL; | 506 | return NULL; |
498 | head = rcu_dereference(net->ct.expect_hash[st->bucket].first); | 507 | head = rcu_dereference(hlist_first_rcu(&net->ct.expect_hash[st->bucket])); |
499 | } | 508 | } |
500 | return head; | 509 | return head; |
501 | } | 510 | } |
@@ -630,8 +639,7 @@ int nf_conntrack_expect_init(struct net *net) | |||
630 | } | 639 | } |
631 | 640 | ||
632 | net->ct.expect_count = 0; | 641 | net->ct.expect_count = 0; |
633 | net->ct.expect_hash = nf_ct_alloc_hashtable(&nf_ct_expect_hsize, | 642 | net->ct.expect_hash = nf_ct_alloc_hashtable(&nf_ct_expect_hsize, 0); |
634 | &net->ct.expect_vmalloc, 0); | ||
635 | if (net->ct.expect_hash == NULL) | 643 | if (net->ct.expect_hash == NULL) |
636 | goto err1; | 644 | goto err1; |
637 | 645 | ||
@@ -653,8 +661,7 @@ err3: | |||
653 | if (net_eq(net, &init_net)) | 661 | if (net_eq(net, &init_net)) |
654 | kmem_cache_destroy(nf_ct_expect_cachep); | 662 | kmem_cache_destroy(nf_ct_expect_cachep); |
655 | err2: | 663 | err2: |
656 | nf_ct_free_hashtable(net->ct.expect_hash, net->ct.expect_vmalloc, | 664 | nf_ct_free_hashtable(net->ct.expect_hash, nf_ct_expect_hsize); |
657 | nf_ct_expect_hsize); | ||
658 | err1: | 665 | err1: |
659 | return err; | 666 | return err; |
660 | } | 667 | } |
@@ -666,6 +673,5 @@ void nf_conntrack_expect_fini(struct net *net) | |||
666 | rcu_barrier(); /* Wait for call_rcu() before destroy */ | 673 | rcu_barrier(); /* Wait for call_rcu() before destroy */ |
667 | kmem_cache_destroy(nf_ct_expect_cachep); | 674 | kmem_cache_destroy(nf_ct_expect_cachep); |
668 | } | 675 | } |
669 | nf_ct_free_hashtable(net->ct.expect_hash, net->ct.expect_vmalloc, | 676 | nf_ct_free_hashtable(net->ct.expect_hash, nf_ct_expect_hsize); |
670 | nf_ct_expect_hsize); | ||
671 | } | 677 | } |