ipv6: use RCU to walk list of network devices
authorEric Dumazet <eric.dumazet@gmail.com>
Wed, 11 Nov 2009 17:34:30 +0000 (17:34 +0000)
committerDavid S. Miller <davem@davemloft.net>
Sat, 14 Nov 2009 04:38:49 +0000 (20:38 -0800)
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>
include/linux/netdevice.h
net/ipv6/anycast.c
net/ipv6/mcast.c

index 8b26639..61425d0 100644 (file)
@@ -1114,6 +1114,16 @@ static inline struct net_device *next_net_device(struct net_device *dev)
        return lh == &net->dev_base_head ? NULL : net_device_entry(lh);
 }
 
+static inline struct net_device *next_net_device_rcu(struct net_device *dev)
+{
+       struct list_head *lh;
+       struct net *net;
+
+       net = dev_net(dev);
+       lh = rcu_dereference(dev->dev_list.next);
+       return lh == &net->dev_base_head ? NULL : net_device_entry(lh);
+}
+
 static inline struct net_device *first_net_device(struct net *net)
 {
        return list_empty(&net->dev_base_head) ? NULL :
index 2f00ca8..f1c74c8 100644 (file)
@@ -431,9 +431,9 @@ static inline struct ifacaddr6 *ac6_get_first(struct seq_file *seq)
        struct net *net = seq_file_net(seq);
 
        state->idev = NULL;
-       for_each_netdev(net, state->dev) {
+       for_each_netdev_rcu(net, state->dev) {
                struct inet6_dev *idev;
-               idev = in6_dev_get(state->dev);
+               idev = __in6_dev_get(state->dev);
                if (!idev)
                        continue;
                read_lock_bh(&idev->lock);
@@ -443,7 +443,6 @@ static inline struct ifacaddr6 *ac6_get_first(struct seq_file *seq)
                        break;
                }
                read_unlock_bh(&idev->lock);
-               in6_dev_put(idev);
        }
        return im;
 }
@@ -454,16 +453,15 @@ static struct ifacaddr6 *ac6_get_next(struct seq_file *seq, struct ifacaddr6 *im
 
        im = im->aca_next;
        while (!im) {
-               if (likely(state->idev != NULL)) {
+               if (likely(state->idev != NULL))
                        read_unlock_bh(&state->idev->lock);
-                       in6_dev_put(state->idev);
-               }
-               state->dev = next_net_device(state->dev);
+
+               state->dev = next_net_device_rcu(state->dev);
                if (!state->dev) {
                        state->idev = NULL;
                        break;
                }
-               state->idev = in6_dev_get(state->dev);
+               state->idev = __in6_dev_get(state->dev);
                if (!state->idev)
                        continue;
                read_lock_bh(&state->idev->lock);
@@ -482,29 +480,30 @@ static struct ifacaddr6 *ac6_get_idx(struct seq_file *seq, loff_t pos)
 }
 
 static void *ac6_seq_start(struct seq_file *seq, loff_t *pos)
-       __acquires(dev_base_lock)
+       __acquires(RCU)
 {
-       read_lock(&dev_base_lock);
+       rcu_read_lock();
        return ac6_get_idx(seq, *pos);
 }
 
 static void *ac6_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
-       struct ifacaddr6 *im;
-       im = ac6_get_next(seq, v);
+       struct ifacaddr6 *im = ac6_get_next(seq, v);
+
        ++*pos;
        return im;
 }
 
 static void ac6_seq_stop(struct seq_file *seq, void *v)
-       __releases(dev_base_lock)
+       __releases(RCU)
 {
        struct ac6_iter_state *state = ac6_seq_private(seq);
+
        if (likely(state->idev != NULL)) {
                read_unlock_bh(&state->idev->lock);
-               in6_dev_put(state->idev);
+               state->idev = NULL;
        }
-       read_unlock(&dev_base_lock);
+       rcu_read_unlock();
 }
 
 static int ac6_seq_show(struct seq_file *seq, void *v)
index f9fcf69..1f9c444 100644 (file)
@@ -2375,9 +2375,9 @@ static inline struct ifmcaddr6 *igmp6_mc_get_first(struct seq_file *seq)
        struct net *net = seq_file_net(seq);
 
        state->idev = NULL;
-       for_each_netdev(net, state->dev) {
+       for_each_netdev_rcu(net, state->dev) {
                struct inet6_dev *idev;
-               idev = in6_dev_get(state->dev);
+               idev = __in6_dev_get(state->dev);
                if (!idev)
                        continue;
                read_lock_bh(&idev->lock);
@@ -2387,7 +2387,6 @@ static inline struct ifmcaddr6 *igmp6_mc_get_first(struct seq_file *seq)
                        break;
                }
                read_unlock_bh(&idev->lock);
-               in6_dev_put(idev);
        }
        return im;
 }
@@ -2398,16 +2397,15 @@ static struct ifmcaddr6 *igmp6_mc_get_next(struct seq_file *seq, struct ifmcaddr
 
        im = im->next;
        while (!im) {
-               if (likely(state->idev != NULL)) {
+               if (likely(state->idev != NULL))
                        read_unlock_bh(&state->idev->lock);
-                       in6_dev_put(state->idev);
-               }
-               state->dev = next_net_device(state->dev);
+
+               state->dev = next_net_device_rcu(state->dev);
                if (!state->dev) {
                        state->idev = NULL;
                        break;
                }
-               state->idev = in6_dev_get(state->dev);
+               state->idev = __in6_dev_get(state->dev);
                if (!state->idev)
                        continue;
                read_lock_bh(&state->idev->lock);
@@ -2426,31 +2424,31 @@ static struct ifmcaddr6 *igmp6_mc_get_idx(struct seq_file *seq, loff_t pos)
 }
 
 static void *igmp6_mc_seq_start(struct seq_file *seq, loff_t *pos)
-       __acquires(dev_base_lock)
+       __acquires(RCU)
 {
-       read_lock(&dev_base_lock);
+       rcu_read_lock();
        return igmp6_mc_get_idx(seq, *pos);
 }
 
 static void *igmp6_mc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
-       struct ifmcaddr6 *im;
-       im = igmp6_mc_get_next(seq, v);
+       struct ifmcaddr6 *im = igmp6_mc_get_next(seq, v);
+
        ++*pos;
        return im;
 }
 
 static void igmp6_mc_seq_stop(struct seq_file *seq, void *v)
-       __releases(dev_base_lock)
+       __releases(RCU)
 {
        struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq);
+
        if (likely(state->idev != NULL)) {
                read_unlock_bh(&state->idev->lock);
-               in6_dev_put(state->idev);
                state->idev = NULL;
        }
        state->dev = NULL;
-       read_unlock(&dev_base_lock);
+       rcu_read_unlock();
 }
 
 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)
 
        state->idev = NULL;
        state->im = NULL;
-       for_each_netdev(net, state->dev) {
+       for_each_netdev_rcu(net, state->dev) {
                struct inet6_dev *idev;
-               idev = in6_dev_get(state->dev);
+               idev = __in6_dev_get(state->dev);
                if (unlikely(idev == NULL))
                        continue;
                read_lock_bh(&idev->lock);
@@ -2525,7 +2523,6 @@ static inline struct ip6_sf_list *igmp6_mcf_get_first(struct seq_file *seq)
                        spin_unlock_bh(&im->mca_lock);
                }
                read_unlock_bh(&idev->lock);
-               in6_dev_put(idev);
        }
        return psf;
 }
@@ -2539,16 +2536,15 @@ static struct ip6_sf_list *igmp6_mcf_get_next(struct seq_file *seq, struct ip6_s
                spin_unlock_bh(&state->im->mca_lock);
                state->im = state->im->next;
                while (!state->im) {
-                       if (likely(state->idev != NULL)) {
+                       if (likely(state->idev != NULL))
                                read_unlock_bh(&state->idev->lock);
-                               in6_dev_put(state->idev);
-                       }
-                       state->dev = next_net_device(state->dev);
+
+                       state->dev = next_net_device_rcu(state->dev);
                        if (!state->dev) {
                                state->idev = NULL;
                                goto out;
                        }
-                       state->idev = in6_dev_get(state->dev);
+                       state->idev = __in6_dev_get(state->dev);
                        if (!state->idev)
                                continue;
                        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)
 }
 
 static void *igmp6_mcf_seq_start(struct seq_file *seq, loff_t *pos)
-       __acquires(dev_base_lock)
+       __acquires(RCU)
 {
-       read_lock(&dev_base_lock);
+       rcu_read_lock();
        return *pos ? igmp6_mcf_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
 }
 
@@ -2591,7 +2587,7 @@ static void *igmp6_mcf_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 }
 
 static void igmp6_mcf_seq_stop(struct seq_file *seq, void *v)
-       __releases(dev_base_lock)
+       __releases(RCU)
 {
        struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq);
        if (likely(state->im != NULL)) {
@@ -2600,11 +2596,10 @@ static void igmp6_mcf_seq_stop(struct seq_file *seq, void *v)
        }
        if (likely(state->idev != NULL)) {
                read_unlock_bh(&state->idev->lock);
-               in6_dev_put(state->idev);
                state->idev = NULL;
        }
        state->dev = NULL;
-       read_unlock(&dev_base_lock);
+       rcu_read_unlock();
 }
 
 static int igmp6_mcf_seq_show(struct seq_file *seq, void *v)