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 | |
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>
-rw-r--r-- | include/linux/netdevice.h | 10 | ||||
-rw-r--r-- | net/ipv6/anycast.c | 29 | ||||
-rw-r--r-- | net/ipv6/mcast.c | 51 |
3 files changed, 47 insertions, 43 deletions
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 8b266390b9e2..61425d0c6123 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h | |||
@@ -1114,6 +1114,16 @@ static inline struct net_device *next_net_device(struct net_device *dev) | |||
1114 | return lh == &net->dev_base_head ? NULL : net_device_entry(lh); | 1114 | return lh == &net->dev_base_head ? NULL : net_device_entry(lh); |
1115 | } | 1115 | } |
1116 | 1116 | ||
1117 | static inline struct net_device *next_net_device_rcu(struct net_device *dev) | ||
1118 | { | ||
1119 | struct list_head *lh; | ||
1120 | struct net *net; | ||
1121 | |||
1122 | net = dev_net(dev); | ||
1123 | lh = rcu_dereference(dev->dev_list.next); | ||
1124 | return lh == &net->dev_base_head ? NULL : net_device_entry(lh); | ||
1125 | } | ||
1126 | |||
1117 | static inline struct net_device *first_net_device(struct net *net) | 1127 | static inline struct net_device *first_net_device(struct net *net) |
1118 | { | 1128 | { |
1119 | return list_empty(&net->dev_base_head) ? NULL : | 1129 | return list_empty(&net->dev_base_head) ? NULL : |
diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c index 2f00ca83f049..f1c74c8ef9de 100644 --- a/net/ipv6/anycast.c +++ b/net/ipv6/anycast.c | |||
@@ -431,9 +431,9 @@ static inline struct ifacaddr6 *ac6_get_first(struct seq_file *seq) | |||
431 | struct net *net = seq_file_net(seq); | 431 | struct net *net = seq_file_net(seq); |
432 | 432 | ||
433 | state->idev = NULL; | 433 | state->idev = NULL; |
434 | for_each_netdev(net, state->dev) { | 434 | for_each_netdev_rcu(net, state->dev) { |
435 | struct inet6_dev *idev; | 435 | struct inet6_dev *idev; |
436 | idev = in6_dev_get(state->dev); | 436 | idev = __in6_dev_get(state->dev); |
437 | if (!idev) | 437 | if (!idev) |
438 | continue; | 438 | continue; |
439 | read_lock_bh(&idev->lock); | 439 | read_lock_bh(&idev->lock); |
@@ -443,7 +443,6 @@ static inline struct ifacaddr6 *ac6_get_first(struct seq_file *seq) | |||
443 | break; | 443 | break; |
444 | } | 444 | } |
445 | read_unlock_bh(&idev->lock); | 445 | read_unlock_bh(&idev->lock); |
446 | in6_dev_put(idev); | ||
447 | } | 446 | } |
448 | return im; | 447 | return im; |
449 | } | 448 | } |
@@ -454,16 +453,15 @@ static struct ifacaddr6 *ac6_get_next(struct seq_file *seq, struct ifacaddr6 *im | |||
454 | 453 | ||
455 | im = im->aca_next; | 454 | im = im->aca_next; |
456 | while (!im) { | 455 | while (!im) { |
457 | if (likely(state->idev != NULL)) { | 456 | if (likely(state->idev != NULL)) |
458 | read_unlock_bh(&state->idev->lock); | 457 | read_unlock_bh(&state->idev->lock); |
459 | in6_dev_put(state->idev); | 458 | |
460 | } | 459 | state->dev = next_net_device_rcu(state->dev); |
461 | state->dev = next_net_device(state->dev); | ||
462 | if (!state->dev) { | 460 | if (!state->dev) { |
463 | state->idev = NULL; | 461 | state->idev = NULL; |
464 | break; | 462 | break; |
465 | } | 463 | } |
466 | state->idev = in6_dev_get(state->dev); | 464 | state->idev = __in6_dev_get(state->dev); |
467 | if (!state->idev) | 465 | if (!state->idev) |
468 | continue; | 466 | continue; |
469 | read_lock_bh(&state->idev->lock); | 467 | read_lock_bh(&state->idev->lock); |
@@ -482,29 +480,30 @@ static struct ifacaddr6 *ac6_get_idx(struct seq_file *seq, loff_t pos) | |||
482 | } | 480 | } |
483 | 481 | ||
484 | static void *ac6_seq_start(struct seq_file *seq, loff_t *pos) | 482 | static void *ac6_seq_start(struct seq_file *seq, loff_t *pos) |
485 | __acquires(dev_base_lock) | 483 | __acquires(RCU) |
486 | { | 484 | { |
487 | read_lock(&dev_base_lock); | 485 | rcu_read_lock(); |
488 | return ac6_get_idx(seq, *pos); | 486 | return ac6_get_idx(seq, *pos); |
489 | } | 487 | } |
490 | 488 | ||
491 | static void *ac6_seq_next(struct seq_file *seq, void *v, loff_t *pos) | 489 | static void *ac6_seq_next(struct seq_file *seq, void *v, loff_t *pos) |
492 | { | 490 | { |
493 | struct ifacaddr6 *im; | 491 | struct ifacaddr6 *im = ac6_get_next(seq, v); |
494 | im = ac6_get_next(seq, v); | 492 | |
495 | ++*pos; | 493 | ++*pos; |
496 | return im; | 494 | return im; |
497 | } | 495 | } |
498 | 496 | ||
499 | static void ac6_seq_stop(struct seq_file *seq, void *v) | 497 | static void ac6_seq_stop(struct seq_file *seq, void *v) |
500 | __releases(dev_base_lock) | 498 | __releases(RCU) |
501 | { | 499 | { |
502 | struct ac6_iter_state *state = ac6_seq_private(seq); | 500 | struct ac6_iter_state *state = ac6_seq_private(seq); |
501 | |||
503 | if (likely(state->idev != NULL)) { | 502 | if (likely(state->idev != NULL)) { |
504 | read_unlock_bh(&state->idev->lock); | 503 | read_unlock_bh(&state->idev->lock); |
505 | in6_dev_put(state->idev); | 504 | state->idev = NULL; |
506 | } | 505 | } |
507 | read_unlock(&dev_base_lock); | 506 | rcu_read_unlock(); |
508 | } | 507 | } |
509 | 508 | ||
510 | static int ac6_seq_show(struct seq_file *seq, void *v) | 509 | static int ac6_seq_show(struct seq_file *seq, void *v) |
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) |