aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2009-11-11 12:34:30 -0500
committerDavid S. Miller <davem@davemloft.net>2009-11-13 23:38:49 -0500
commitce81b76a39835a721cd168e0c0bcfe7132f1f66b (patch)
treeed725dd6163f328d4717fb3ed28c9e6c2691bc88
parentbee7ca9ec03a26676ea2b1c28dc4039348eff3e1 (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.h10
-rw-r--r--net/ipv6/anycast.c29
-rw-r--r--net/ipv6/mcast.c51
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
1117static 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
1117static inline struct net_device *first_net_device(struct net *net) 1127static 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
484static void *ac6_seq_start(struct seq_file *seq, loff_t *pos) 482static 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
491static void *ac6_seq_next(struct seq_file *seq, void *v, loff_t *pos) 489static 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
499static void ac6_seq_stop(struct seq_file *seq, void *v) 497static 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
510static int ac6_seq_show(struct seq_file *seq, void *v) 509static 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
2428static void *igmp6_mc_seq_start(struct seq_file *seq, loff_t *pos) 2426static 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
2435static void *igmp6_mc_seq_next(struct seq_file *seq, void *v, loff_t *pos) 2433static 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
2443static void igmp6_mc_seq_stop(struct seq_file *seq, void *v) 2441static 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
2456static int igmp6_mc_seq_show(struct seq_file *seq, void *v) 2454static 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
2575static void *igmp6_mcf_seq_start(struct seq_file *seq, loff_t *pos) 2571static 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
2593static void igmp6_mcf_seq_stop(struct seq_file *seq, void *v) 2589static 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
2610static int igmp6_mcf_seq_show(struct seq_file *seq, void *v) 2605static int igmp6_mcf_seq_show(struct seq_file *seq, void *v)