diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2009-11-11 12:34:30 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-11-13 23:38:49 -0500 |
commit | ce81b76a39835a721cd168e0c0bcfe7132f1f66b (patch) | |
tree | ed725dd6163f328d4717fb3ed28c9e6c2691bc88 /net/ipv6/mcast.c | |
parent | bee7ca9ec03a26676ea2b1c28dc4039348eff3e1 (diff) |
ipv6: use RCU to walk list of network devices
No longer need read_lock(&dev_base_lock), use RCU instead.
We also can avoid taking references on inet6_dev structs.
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/mcast.c')
-rw-r--r-- | net/ipv6/mcast.c | 51 |
1 files changed, 23 insertions, 28 deletions
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index f9fcf690bd5d..1f9c44442e65 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c | |||
@@ -2375,9 +2375,9 @@ static inline struct ifmcaddr6 *igmp6_mc_get_first(struct seq_file *seq) | |||
2375 | struct net *net = seq_file_net(seq); | 2375 | struct net *net = seq_file_net(seq); |
2376 | 2376 | ||
2377 | state->idev = NULL; | 2377 | state->idev = NULL; |
2378 | for_each_netdev(net, state->dev) { | 2378 | for_each_netdev_rcu(net, state->dev) { |
2379 | struct inet6_dev *idev; | 2379 | struct inet6_dev *idev; |
2380 | idev = in6_dev_get(state->dev); | 2380 | idev = __in6_dev_get(state->dev); |
2381 | if (!idev) | 2381 | if (!idev) |
2382 | continue; | 2382 | continue; |
2383 | read_lock_bh(&idev->lock); | 2383 | read_lock_bh(&idev->lock); |
@@ -2387,7 +2387,6 @@ static inline struct ifmcaddr6 *igmp6_mc_get_first(struct seq_file *seq) | |||
2387 | break; | 2387 | break; |
2388 | } | 2388 | } |
2389 | read_unlock_bh(&idev->lock); | 2389 | read_unlock_bh(&idev->lock); |
2390 | in6_dev_put(idev); | ||
2391 | } | 2390 | } |
2392 | return im; | 2391 | return im; |
2393 | } | 2392 | } |
@@ -2398,16 +2397,15 @@ static struct ifmcaddr6 *igmp6_mc_get_next(struct seq_file *seq, struct ifmcaddr | |||
2398 | 2397 | ||
2399 | im = im->next; | 2398 | im = im->next; |
2400 | while (!im) { | 2399 | while (!im) { |
2401 | if (likely(state->idev != NULL)) { | 2400 | if (likely(state->idev != NULL)) |
2402 | read_unlock_bh(&state->idev->lock); | 2401 | read_unlock_bh(&state->idev->lock); |
2403 | in6_dev_put(state->idev); | 2402 | |
2404 | } | 2403 | state->dev = next_net_device_rcu(state->dev); |
2405 | state->dev = next_net_device(state->dev); | ||
2406 | if (!state->dev) { | 2404 | if (!state->dev) { |
2407 | state->idev = NULL; | 2405 | state->idev = NULL; |
2408 | break; | 2406 | break; |
2409 | } | 2407 | } |
2410 | state->idev = in6_dev_get(state->dev); | 2408 | state->idev = __in6_dev_get(state->dev); |
2411 | if (!state->idev) | 2409 | if (!state->idev) |
2412 | continue; | 2410 | continue; |
2413 | read_lock_bh(&state->idev->lock); | 2411 | read_lock_bh(&state->idev->lock); |
@@ -2426,31 +2424,31 @@ static struct ifmcaddr6 *igmp6_mc_get_idx(struct seq_file *seq, loff_t pos) | |||
2426 | } | 2424 | } |
2427 | 2425 | ||
2428 | static void *igmp6_mc_seq_start(struct seq_file *seq, loff_t *pos) | 2426 | static void *igmp6_mc_seq_start(struct seq_file *seq, loff_t *pos) |
2429 | __acquires(dev_base_lock) | 2427 | __acquires(RCU) |
2430 | { | 2428 | { |
2431 | read_lock(&dev_base_lock); | 2429 | rcu_read_lock(); |
2432 | return igmp6_mc_get_idx(seq, *pos); | 2430 | return igmp6_mc_get_idx(seq, *pos); |
2433 | } | 2431 | } |
2434 | 2432 | ||
2435 | static void *igmp6_mc_seq_next(struct seq_file *seq, void *v, loff_t *pos) | 2433 | static void *igmp6_mc_seq_next(struct seq_file *seq, void *v, loff_t *pos) |
2436 | { | 2434 | { |
2437 | struct ifmcaddr6 *im; | 2435 | struct ifmcaddr6 *im = igmp6_mc_get_next(seq, v); |
2438 | im = igmp6_mc_get_next(seq, v); | 2436 | |
2439 | ++*pos; | 2437 | ++*pos; |
2440 | return im; | 2438 | return im; |
2441 | } | 2439 | } |
2442 | 2440 | ||
2443 | static void igmp6_mc_seq_stop(struct seq_file *seq, void *v) | 2441 | static void igmp6_mc_seq_stop(struct seq_file *seq, void *v) |
2444 | __releases(dev_base_lock) | 2442 | __releases(RCU) |
2445 | { | 2443 | { |
2446 | struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq); | 2444 | struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq); |
2445 | |||
2447 | if (likely(state->idev != NULL)) { | 2446 | if (likely(state->idev != NULL)) { |
2448 | read_unlock_bh(&state->idev->lock); | 2447 | read_unlock_bh(&state->idev->lock); |
2449 | in6_dev_put(state->idev); | ||
2450 | state->idev = NULL; | 2448 | state->idev = NULL; |
2451 | } | 2449 | } |
2452 | state->dev = NULL; | 2450 | state->dev = NULL; |
2453 | read_unlock(&dev_base_lock); | 2451 | rcu_read_unlock(); |
2454 | } | 2452 | } |
2455 | 2453 | ||
2456 | static int igmp6_mc_seq_show(struct seq_file *seq, void *v) | 2454 | static int igmp6_mc_seq_show(struct seq_file *seq, void *v) |
@@ -2507,9 +2505,9 @@ static inline struct ip6_sf_list *igmp6_mcf_get_first(struct seq_file *seq) | |||
2507 | 2505 | ||
2508 | state->idev = NULL; | 2506 | state->idev = NULL; |
2509 | state->im = NULL; | 2507 | state->im = NULL; |
2510 | for_each_netdev(net, state->dev) { | 2508 | for_each_netdev_rcu(net, state->dev) { |
2511 | struct inet6_dev *idev; | 2509 | struct inet6_dev *idev; |
2512 | idev = in6_dev_get(state->dev); | 2510 | idev = __in6_dev_get(state->dev); |
2513 | if (unlikely(idev == NULL)) | 2511 | if (unlikely(idev == NULL)) |
2514 | continue; | 2512 | continue; |
2515 | read_lock_bh(&idev->lock); | 2513 | read_lock_bh(&idev->lock); |
@@ -2525,7 +2523,6 @@ static inline struct ip6_sf_list *igmp6_mcf_get_first(struct seq_file *seq) | |||
2525 | spin_unlock_bh(&im->mca_lock); | 2523 | spin_unlock_bh(&im->mca_lock); |
2526 | } | 2524 | } |
2527 | read_unlock_bh(&idev->lock); | 2525 | read_unlock_bh(&idev->lock); |
2528 | in6_dev_put(idev); | ||
2529 | } | 2526 | } |
2530 | return psf; | 2527 | return psf; |
2531 | } | 2528 | } |
@@ -2539,16 +2536,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); | 2536 | spin_unlock_bh(&state->im->mca_lock); |
2540 | state->im = state->im->next; | 2537 | state->im = state->im->next; |
2541 | while (!state->im) { | 2538 | while (!state->im) { |
2542 | if (likely(state->idev != NULL)) { | 2539 | if (likely(state->idev != NULL)) |
2543 | read_unlock_bh(&state->idev->lock); | 2540 | read_unlock_bh(&state->idev->lock); |
2544 | in6_dev_put(state->idev); | 2541 | |
2545 | } | 2542 | state->dev = next_net_device_rcu(state->dev); |
2546 | state->dev = next_net_device(state->dev); | ||
2547 | if (!state->dev) { | 2543 | if (!state->dev) { |
2548 | state->idev = NULL; | 2544 | state->idev = NULL; |
2549 | goto out; | 2545 | goto out; |
2550 | } | 2546 | } |
2551 | state->idev = in6_dev_get(state->dev); | 2547 | state->idev = __in6_dev_get(state->dev); |
2552 | if (!state->idev) | 2548 | if (!state->idev) |
2553 | continue; | 2549 | continue; |
2554 | read_lock_bh(&state->idev->lock); | 2550 | read_lock_bh(&state->idev->lock); |
@@ -2573,9 +2569,9 @@ static struct ip6_sf_list *igmp6_mcf_get_idx(struct seq_file *seq, loff_t pos) | |||
2573 | } | 2569 | } |
2574 | 2570 | ||
2575 | static void *igmp6_mcf_seq_start(struct seq_file *seq, loff_t *pos) | 2571 | static void *igmp6_mcf_seq_start(struct seq_file *seq, loff_t *pos) |
2576 | __acquires(dev_base_lock) | 2572 | __acquires(RCU) |
2577 | { | 2573 | { |
2578 | read_lock(&dev_base_lock); | 2574 | rcu_read_lock(); |
2579 | return *pos ? igmp6_mcf_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; | 2575 | return *pos ? igmp6_mcf_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; |
2580 | } | 2576 | } |
2581 | 2577 | ||
@@ -2591,7 +2587,7 @@ static void *igmp6_mcf_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |||
2591 | } | 2587 | } |
2592 | 2588 | ||
2593 | static void igmp6_mcf_seq_stop(struct seq_file *seq, void *v) | 2589 | static void igmp6_mcf_seq_stop(struct seq_file *seq, void *v) |
2594 | __releases(dev_base_lock) | 2590 | __releases(RCU) |
2595 | { | 2591 | { |
2596 | struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq); | 2592 | struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq); |
2597 | if (likely(state->im != NULL)) { | 2593 | if (likely(state->im != NULL)) { |
@@ -2600,11 +2596,10 @@ static void igmp6_mcf_seq_stop(struct seq_file *seq, void *v) | |||
2600 | } | 2596 | } |
2601 | if (likely(state->idev != NULL)) { | 2597 | if (likely(state->idev != NULL)) { |
2602 | read_unlock_bh(&state->idev->lock); | 2598 | read_unlock_bh(&state->idev->lock); |
2603 | in6_dev_put(state->idev); | ||
2604 | state->idev = NULL; | 2599 | state->idev = NULL; |
2605 | } | 2600 | } |
2606 | state->dev = NULL; | 2601 | state->dev = NULL; |
2607 | read_unlock(&dev_base_lock); | 2602 | rcu_read_unlock(); |
2608 | } | 2603 | } |
2609 | 2604 | ||
2610 | static int igmp6_mcf_seq_show(struct seq_file *seq, void *v) | 2605 | static int igmp6_mcf_seq_show(struct seq_file *seq, void *v) |