diff options
Diffstat (limited to 'net/ipv6/mcast.c')
-rw-r--r-- | net/ipv6/mcast.c | 84 |
1 files changed, 40 insertions, 44 deletions
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index f9fcf690bd5d..c483ab9fd67b 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c | |||
@@ -43,6 +43,7 @@ | |||
43 | #include <linux/init.h> | 43 | #include <linux/init.h> |
44 | #include <linux/proc_fs.h> | 44 | #include <linux/proc_fs.h> |
45 | #include <linux/seq_file.h> | 45 | #include <linux/seq_file.h> |
46 | #include <linux/slab.h> | ||
46 | 47 | ||
47 | #include <linux/netfilter.h> | 48 | #include <linux/netfilter.h> |
48 | #include <linux/netfilter_ipv6.h> | 49 | #include <linux/netfilter_ipv6.h> |
@@ -793,10 +794,10 @@ static void mld_add_delrec(struct inet6_dev *idev, struct ifmcaddr6 *im) | |||
793 | } | 794 | } |
794 | spin_unlock_bh(&im->mca_lock); | 795 | spin_unlock_bh(&im->mca_lock); |
795 | 796 | ||
796 | write_lock_bh(&idev->mc_lock); | 797 | spin_lock_bh(&idev->mc_lock); |
797 | pmc->next = idev->mc_tomb; | 798 | pmc->next = idev->mc_tomb; |
798 | idev->mc_tomb = pmc; | 799 | idev->mc_tomb = pmc; |
799 | write_unlock_bh(&idev->mc_lock); | 800 | spin_unlock_bh(&idev->mc_lock); |
800 | } | 801 | } |
801 | 802 | ||
802 | static void mld_del_delrec(struct inet6_dev *idev, struct in6_addr *pmca) | 803 | static void mld_del_delrec(struct inet6_dev *idev, struct in6_addr *pmca) |
@@ -804,7 +805,7 @@ static void mld_del_delrec(struct inet6_dev *idev, struct in6_addr *pmca) | |||
804 | struct ifmcaddr6 *pmc, *pmc_prev; | 805 | struct ifmcaddr6 *pmc, *pmc_prev; |
805 | struct ip6_sf_list *psf, *psf_next; | 806 | struct ip6_sf_list *psf, *psf_next; |
806 | 807 | ||
807 | write_lock_bh(&idev->mc_lock); | 808 | spin_lock_bh(&idev->mc_lock); |
808 | pmc_prev = NULL; | 809 | pmc_prev = NULL; |
809 | for (pmc=idev->mc_tomb; pmc; pmc=pmc->next) { | 810 | for (pmc=idev->mc_tomb; pmc; pmc=pmc->next) { |
810 | if (ipv6_addr_equal(&pmc->mca_addr, pmca)) | 811 | if (ipv6_addr_equal(&pmc->mca_addr, pmca)) |
@@ -817,7 +818,8 @@ static void mld_del_delrec(struct inet6_dev *idev, struct in6_addr *pmca) | |||
817 | else | 818 | else |
818 | idev->mc_tomb = pmc->next; | 819 | idev->mc_tomb = pmc->next; |
819 | } | 820 | } |
820 | write_unlock_bh(&idev->mc_lock); | 821 | spin_unlock_bh(&idev->mc_lock); |
822 | |||
821 | if (pmc) { | 823 | if (pmc) { |
822 | for (psf=pmc->mca_tomb; psf; psf=psf_next) { | 824 | for (psf=pmc->mca_tomb; psf; psf=psf_next) { |
823 | psf_next = psf->sf_next; | 825 | psf_next = psf->sf_next; |
@@ -832,10 +834,10 @@ static void mld_clear_delrec(struct inet6_dev *idev) | |||
832 | { | 834 | { |
833 | struct ifmcaddr6 *pmc, *nextpmc; | 835 | struct ifmcaddr6 *pmc, *nextpmc; |
834 | 836 | ||
835 | write_lock_bh(&idev->mc_lock); | 837 | spin_lock_bh(&idev->mc_lock); |
836 | pmc = idev->mc_tomb; | 838 | pmc = idev->mc_tomb; |
837 | idev->mc_tomb = NULL; | 839 | idev->mc_tomb = NULL; |
838 | write_unlock_bh(&idev->mc_lock); | 840 | spin_unlock_bh(&idev->mc_lock); |
839 | 841 | ||
840 | for (; pmc; pmc = nextpmc) { | 842 | for (; pmc; pmc = nextpmc) { |
841 | nextpmc = pmc->next; | 843 | nextpmc = pmc->next; |
@@ -1696,7 +1698,7 @@ static void mld_send_cr(struct inet6_dev *idev) | |||
1696 | int type, dtype; | 1698 | int type, dtype; |
1697 | 1699 | ||
1698 | read_lock_bh(&idev->lock); | 1700 | read_lock_bh(&idev->lock); |
1699 | write_lock_bh(&idev->mc_lock); | 1701 | spin_lock(&idev->mc_lock); |
1700 | 1702 | ||
1701 | /* deleted MCA's */ | 1703 | /* deleted MCA's */ |
1702 | pmc_prev = NULL; | 1704 | pmc_prev = NULL; |
@@ -1730,7 +1732,7 @@ static void mld_send_cr(struct inet6_dev *idev) | |||
1730 | } else | 1732 | } else |
1731 | pmc_prev = pmc; | 1733 | pmc_prev = pmc; |
1732 | } | 1734 | } |
1733 | write_unlock_bh(&idev->mc_lock); | 1735 | spin_unlock(&idev->mc_lock); |
1734 | 1736 | ||
1735 | /* change recs */ | 1737 | /* change recs */ |
1736 | for (pmc=idev->mc_list; pmc; pmc=pmc->next) { | 1738 | for (pmc=idev->mc_list; pmc; pmc=pmc->next) { |
@@ -2311,7 +2313,7 @@ void ipv6_mc_up(struct inet6_dev *idev) | |||
2311 | void ipv6_mc_init_dev(struct inet6_dev *idev) | 2313 | void ipv6_mc_init_dev(struct inet6_dev *idev) |
2312 | { | 2314 | { |
2313 | write_lock_bh(&idev->lock); | 2315 | write_lock_bh(&idev->lock); |
2314 | rwlock_init(&idev->mc_lock); | 2316 | spin_lock_init(&idev->mc_lock); |
2315 | idev->mc_gq_running = 0; | 2317 | idev->mc_gq_running = 0; |
2316 | setup_timer(&idev->mc_gq_timer, mld_gq_timer_expire, | 2318 | setup_timer(&idev->mc_gq_timer, mld_gq_timer_expire, |
2317 | (unsigned long)idev); | 2319 | (unsigned long)idev); |
@@ -2375,9 +2377,9 @@ static inline struct ifmcaddr6 *igmp6_mc_get_first(struct seq_file *seq) | |||
2375 | struct net *net = seq_file_net(seq); | 2377 | struct net *net = seq_file_net(seq); |
2376 | 2378 | ||
2377 | state->idev = NULL; | 2379 | state->idev = NULL; |
2378 | for_each_netdev(net, state->dev) { | 2380 | for_each_netdev_rcu(net, state->dev) { |
2379 | struct inet6_dev *idev; | 2381 | struct inet6_dev *idev; |
2380 | idev = in6_dev_get(state->dev); | 2382 | idev = __in6_dev_get(state->dev); |
2381 | if (!idev) | 2383 | if (!idev) |
2382 | continue; | 2384 | continue; |
2383 | read_lock_bh(&idev->lock); | 2385 | read_lock_bh(&idev->lock); |
@@ -2387,7 +2389,6 @@ static inline struct ifmcaddr6 *igmp6_mc_get_first(struct seq_file *seq) | |||
2387 | break; | 2389 | break; |
2388 | } | 2390 | } |
2389 | read_unlock_bh(&idev->lock); | 2391 | read_unlock_bh(&idev->lock); |
2390 | in6_dev_put(idev); | ||
2391 | } | 2392 | } |
2392 | return im; | 2393 | return im; |
2393 | } | 2394 | } |
@@ -2398,16 +2399,15 @@ static struct ifmcaddr6 *igmp6_mc_get_next(struct seq_file *seq, struct ifmcaddr | |||
2398 | 2399 | ||
2399 | im = im->next; | 2400 | im = im->next; |
2400 | while (!im) { | 2401 | while (!im) { |
2401 | if (likely(state->idev != NULL)) { | 2402 | if (likely(state->idev != NULL)) |
2402 | read_unlock_bh(&state->idev->lock); | 2403 | read_unlock_bh(&state->idev->lock); |
2403 | in6_dev_put(state->idev); | 2404 | |
2404 | } | 2405 | state->dev = next_net_device_rcu(state->dev); |
2405 | state->dev = next_net_device(state->dev); | ||
2406 | if (!state->dev) { | 2406 | if (!state->dev) { |
2407 | state->idev = NULL; | 2407 | state->idev = NULL; |
2408 | break; | 2408 | break; |
2409 | } | 2409 | } |
2410 | state->idev = in6_dev_get(state->dev); | 2410 | state->idev = __in6_dev_get(state->dev); |
2411 | if (!state->idev) | 2411 | if (!state->idev) |
2412 | continue; | 2412 | continue; |
2413 | read_lock_bh(&state->idev->lock); | 2413 | read_lock_bh(&state->idev->lock); |
@@ -2426,31 +2426,31 @@ static struct ifmcaddr6 *igmp6_mc_get_idx(struct seq_file *seq, loff_t pos) | |||
2426 | } | 2426 | } |
2427 | 2427 | ||
2428 | static void *igmp6_mc_seq_start(struct seq_file *seq, loff_t *pos) | 2428 | static void *igmp6_mc_seq_start(struct seq_file *seq, loff_t *pos) |
2429 | __acquires(dev_base_lock) | 2429 | __acquires(RCU) |
2430 | { | 2430 | { |
2431 | read_lock(&dev_base_lock); | 2431 | rcu_read_lock(); |
2432 | return igmp6_mc_get_idx(seq, *pos); | 2432 | return igmp6_mc_get_idx(seq, *pos); |
2433 | } | 2433 | } |
2434 | 2434 | ||
2435 | static void *igmp6_mc_seq_next(struct seq_file *seq, void *v, loff_t *pos) | 2435 | static void *igmp6_mc_seq_next(struct seq_file *seq, void *v, loff_t *pos) |
2436 | { | 2436 | { |
2437 | struct ifmcaddr6 *im; | 2437 | struct ifmcaddr6 *im = igmp6_mc_get_next(seq, v); |
2438 | im = igmp6_mc_get_next(seq, v); | 2438 | |
2439 | ++*pos; | 2439 | ++*pos; |
2440 | return im; | 2440 | return im; |
2441 | } | 2441 | } |
2442 | 2442 | ||
2443 | static void igmp6_mc_seq_stop(struct seq_file *seq, void *v) | 2443 | static void igmp6_mc_seq_stop(struct seq_file *seq, void *v) |
2444 | __releases(dev_base_lock) | 2444 | __releases(RCU) |
2445 | { | 2445 | { |
2446 | struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq); | 2446 | struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq); |
2447 | |||
2447 | if (likely(state->idev != NULL)) { | 2448 | if (likely(state->idev != NULL)) { |
2448 | read_unlock_bh(&state->idev->lock); | 2449 | read_unlock_bh(&state->idev->lock); |
2449 | in6_dev_put(state->idev); | ||
2450 | state->idev = NULL; | 2450 | state->idev = NULL; |
2451 | } | 2451 | } |
2452 | state->dev = NULL; | 2452 | state->dev = NULL; |
2453 | read_unlock(&dev_base_lock); | 2453 | rcu_read_unlock(); |
2454 | } | 2454 | } |
2455 | 2455 | ||
2456 | static int igmp6_mc_seq_show(struct seq_file *seq, void *v) | 2456 | static int igmp6_mc_seq_show(struct seq_file *seq, void *v) |
@@ -2507,9 +2507,9 @@ static inline struct ip6_sf_list *igmp6_mcf_get_first(struct seq_file *seq) | |||
2507 | 2507 | ||
2508 | state->idev = NULL; | 2508 | state->idev = NULL; |
2509 | state->im = NULL; | 2509 | state->im = NULL; |
2510 | for_each_netdev(net, state->dev) { | 2510 | for_each_netdev_rcu(net, state->dev) { |
2511 | struct inet6_dev *idev; | 2511 | struct inet6_dev *idev; |
2512 | idev = in6_dev_get(state->dev); | 2512 | idev = __in6_dev_get(state->dev); |
2513 | if (unlikely(idev == NULL)) | 2513 | if (unlikely(idev == NULL)) |
2514 | continue; | 2514 | continue; |
2515 | read_lock_bh(&idev->lock); | 2515 | read_lock_bh(&idev->lock); |
@@ -2525,7 +2525,6 @@ static inline struct ip6_sf_list *igmp6_mcf_get_first(struct seq_file *seq) | |||
2525 | spin_unlock_bh(&im->mca_lock); | 2525 | spin_unlock_bh(&im->mca_lock); |
2526 | } | 2526 | } |
2527 | read_unlock_bh(&idev->lock); | 2527 | read_unlock_bh(&idev->lock); |
2528 | in6_dev_put(idev); | ||
2529 | } | 2528 | } |
2530 | return psf; | 2529 | return psf; |
2531 | } | 2530 | } |
@@ -2539,16 +2538,15 @@ static struct ip6_sf_list *igmp6_mcf_get_next(struct seq_file *seq, struct ip6_s | |||
2539 | spin_unlock_bh(&state->im->mca_lock); | 2538 | spin_unlock_bh(&state->im->mca_lock); |
2540 | state->im = state->im->next; | 2539 | state->im = state->im->next; |
2541 | while (!state->im) { | 2540 | while (!state->im) { |
2542 | if (likely(state->idev != NULL)) { | 2541 | if (likely(state->idev != NULL)) |
2543 | read_unlock_bh(&state->idev->lock); | 2542 | read_unlock_bh(&state->idev->lock); |
2544 | in6_dev_put(state->idev); | 2543 | |
2545 | } | 2544 | state->dev = next_net_device_rcu(state->dev); |
2546 | state->dev = next_net_device(state->dev); | ||
2547 | if (!state->dev) { | 2545 | if (!state->dev) { |
2548 | state->idev = NULL; | 2546 | state->idev = NULL; |
2549 | goto out; | 2547 | goto out; |
2550 | } | 2548 | } |
2551 | state->idev = in6_dev_get(state->dev); | 2549 | state->idev = __in6_dev_get(state->dev); |
2552 | if (!state->idev) | 2550 | if (!state->idev) |
2553 | continue; | 2551 | continue; |
2554 | read_lock_bh(&state->idev->lock); | 2552 | read_lock_bh(&state->idev->lock); |
@@ -2573,9 +2571,9 @@ static struct ip6_sf_list *igmp6_mcf_get_idx(struct seq_file *seq, loff_t pos) | |||
2573 | } | 2571 | } |
2574 | 2572 | ||
2575 | static void *igmp6_mcf_seq_start(struct seq_file *seq, loff_t *pos) | 2573 | static void *igmp6_mcf_seq_start(struct seq_file *seq, loff_t *pos) |
2576 | __acquires(dev_base_lock) | 2574 | __acquires(RCU) |
2577 | { | 2575 | { |
2578 | read_lock(&dev_base_lock); | 2576 | rcu_read_lock(); |
2579 | return *pos ? igmp6_mcf_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; | 2577 | return *pos ? igmp6_mcf_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; |
2580 | } | 2578 | } |
2581 | 2579 | ||
@@ -2591,7 +2589,7 @@ static void *igmp6_mcf_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |||
2591 | } | 2589 | } |
2592 | 2590 | ||
2593 | static void igmp6_mcf_seq_stop(struct seq_file *seq, void *v) | 2591 | static void igmp6_mcf_seq_stop(struct seq_file *seq, void *v) |
2594 | __releases(dev_base_lock) | 2592 | __releases(RCU) |
2595 | { | 2593 | { |
2596 | struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq); | 2594 | struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq); |
2597 | if (likely(state->im != NULL)) { | 2595 | if (likely(state->im != NULL)) { |
@@ -2600,11 +2598,10 @@ static void igmp6_mcf_seq_stop(struct seq_file *seq, void *v) | |||
2600 | } | 2598 | } |
2601 | if (likely(state->idev != NULL)) { | 2599 | if (likely(state->idev != NULL)) { |
2602 | read_unlock_bh(&state->idev->lock); | 2600 | read_unlock_bh(&state->idev->lock); |
2603 | in6_dev_put(state->idev); | ||
2604 | state->idev = NULL; | 2601 | state->idev = NULL; |
2605 | } | 2602 | } |
2606 | state->dev = NULL; | 2603 | state->dev = NULL; |
2607 | read_unlock(&dev_base_lock); | 2604 | rcu_read_unlock(); |
2608 | } | 2605 | } |
2609 | 2606 | ||
2610 | static int igmp6_mcf_seq_show(struct seq_file *seq, void *v) | 2607 | static int igmp6_mcf_seq_show(struct seq_file *seq, void *v) |
@@ -2651,7 +2648,7 @@ static const struct file_operations igmp6_mcf_seq_fops = { | |||
2651 | .release = seq_release_net, | 2648 | .release = seq_release_net, |
2652 | }; | 2649 | }; |
2653 | 2650 | ||
2654 | static int igmp6_proc_init(struct net *net) | 2651 | static int __net_init igmp6_proc_init(struct net *net) |
2655 | { | 2652 | { |
2656 | int err; | 2653 | int err; |
2657 | 2654 | ||
@@ -2671,23 +2668,22 @@ out_proc_net_igmp6: | |||
2671 | goto out; | 2668 | goto out; |
2672 | } | 2669 | } |
2673 | 2670 | ||
2674 | static void igmp6_proc_exit(struct net *net) | 2671 | static void __net_exit igmp6_proc_exit(struct net *net) |
2675 | { | 2672 | { |
2676 | proc_net_remove(net, "mcfilter6"); | 2673 | proc_net_remove(net, "mcfilter6"); |
2677 | proc_net_remove(net, "igmp6"); | 2674 | proc_net_remove(net, "igmp6"); |
2678 | } | 2675 | } |
2679 | #else | 2676 | #else |
2680 | static int igmp6_proc_init(struct net *net) | 2677 | static inline int igmp6_proc_init(struct net *net) |
2681 | { | 2678 | { |
2682 | return 0; | 2679 | return 0; |
2683 | } | 2680 | } |
2684 | static void igmp6_proc_exit(struct net *net) | 2681 | static inline void igmp6_proc_exit(struct net *net) |
2685 | { | 2682 | { |
2686 | ; | ||
2687 | } | 2683 | } |
2688 | #endif | 2684 | #endif |
2689 | 2685 | ||
2690 | static int igmp6_net_init(struct net *net) | 2686 | static int __net_init igmp6_net_init(struct net *net) |
2691 | { | 2687 | { |
2692 | int err; | 2688 | int err; |
2693 | 2689 | ||
@@ -2713,7 +2709,7 @@ out_sock_create: | |||
2713 | goto out; | 2709 | goto out; |
2714 | } | 2710 | } |
2715 | 2711 | ||
2716 | static void igmp6_net_exit(struct net *net) | 2712 | static void __net_exit igmp6_net_exit(struct net *net) |
2717 | { | 2713 | { |
2718 | inet_ctl_sock_destroy(net->ipv6.igmp_sk); | 2714 | inet_ctl_sock_destroy(net->ipv6.igmp_sk); |
2719 | igmp6_proc_exit(net); | 2715 | igmp6_proc_exit(net); |