aboutsummaryrefslogtreecommitdiffstats
path: root/net/core
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2009-11-04 08:43:23 -0500
committerDavid S. Miller <davem@davemloft.net>2009-11-04 08:43:23 -0500
commitc6d14c84566d6b70ad9dc1618db0dec87cca9300 (patch)
tree5ec75245cfda4d61e6b4506b6217f047ff4af01a /net/core
parentd0075634cf9d288988f57392a1f132d2053af961 (diff)
net: Introduce for_each_netdev_rcu() iterator
Adds RCU management to the list of netdevices. Convert some for_each_netdev() users to RCU version, if it can avoid read_lock-ing dev_base_lock Ie: read_lock(&dev_base_loack); for_each_netdev(net, dev) some_action(); read_unlock(&dev_base_lock); becomes : rcu_read_lock(); for_each_netdev_rcu(net, dev) some_action(); rcu_read_unlock(); Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core')
-rw-r--r--net/core/dev.c30
1 files changed, 16 insertions, 14 deletions
diff --git a/net/core/dev.c b/net/core/dev.c
index 76a1502efe67..bf629ac08b87 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -175,7 +175,7 @@ static struct list_head ptype_all __read_mostly; /* Taps */
175 * The @dev_base_head list is protected by @dev_base_lock and the rtnl 175 * The @dev_base_head list is protected by @dev_base_lock and the rtnl
176 * semaphore. 176 * semaphore.
177 * 177 *
178 * Pure readers hold dev_base_lock for reading. 178 * Pure readers hold dev_base_lock for reading, or rcu_read_lock()
179 * 179 *
180 * Writers must hold the rtnl semaphore while they loop through the 180 * Writers must hold the rtnl semaphore while they loop through the
181 * dev_base_head list, and hold dev_base_lock for writing when they do the 181 * dev_base_head list, and hold dev_base_lock for writing when they do the
@@ -212,7 +212,7 @@ static int list_netdevice(struct net_device *dev)
212 ASSERT_RTNL(); 212 ASSERT_RTNL();
213 213
214 write_lock_bh(&dev_base_lock); 214 write_lock_bh(&dev_base_lock);
215 list_add_tail(&dev->dev_list, &net->dev_base_head); 215 list_add_tail_rcu(&dev->dev_list, &net->dev_base_head);
216 hlist_add_head_rcu(&dev->name_hlist, dev_name_hash(net, dev->name)); 216 hlist_add_head_rcu(&dev->name_hlist, dev_name_hash(net, dev->name));
217 hlist_add_head_rcu(&dev->index_hlist, 217 hlist_add_head_rcu(&dev->index_hlist,
218 dev_index_hash(net, dev->ifindex)); 218 dev_index_hash(net, dev->ifindex));
@@ -229,7 +229,7 @@ static void unlist_netdevice(struct net_device *dev)
229 229
230 /* Unlink dev from the device chain */ 230 /* Unlink dev from the device chain */
231 write_lock_bh(&dev_base_lock); 231 write_lock_bh(&dev_base_lock);
232 list_del(&dev->dev_list); 232 list_del_rcu(&dev->dev_list);
233 hlist_del_rcu(&dev->name_hlist); 233 hlist_del_rcu(&dev->name_hlist);
234 hlist_del_rcu(&dev->index_hlist); 234 hlist_del_rcu(&dev->index_hlist);
235 write_unlock_bh(&dev_base_lock); 235 write_unlock_bh(&dev_base_lock);
@@ -799,15 +799,15 @@ struct net_device *dev_get_by_flags(struct net *net, unsigned short if_flags,
799 struct net_device *dev, *ret; 799 struct net_device *dev, *ret;
800 800
801 ret = NULL; 801 ret = NULL;
802 read_lock(&dev_base_lock); 802 rcu_read_lock();
803 for_each_netdev(net, dev) { 803 for_each_netdev_rcu(net, dev) {
804 if (((dev->flags ^ if_flags) & mask) == 0) { 804 if (((dev->flags ^ if_flags) & mask) == 0) {
805 dev_hold(dev); 805 dev_hold(dev);
806 ret = dev; 806 ret = dev;
807 break; 807 break;
808 } 808 }
809 } 809 }
810 read_unlock(&dev_base_lock); 810 rcu_read_unlock();
811 return ret; 811 return ret;
812} 812}
813EXPORT_SYMBOL(dev_get_by_flags); 813EXPORT_SYMBOL(dev_get_by_flags);
@@ -3077,18 +3077,18 @@ static int dev_ifconf(struct net *net, char __user *arg)
3077 * in detail. 3077 * in detail.
3078 */ 3078 */
3079void *dev_seq_start(struct seq_file *seq, loff_t *pos) 3079void *dev_seq_start(struct seq_file *seq, loff_t *pos)
3080 __acquires(dev_base_lock) 3080 __acquires(RCU)
3081{ 3081{
3082 struct net *net = seq_file_net(seq); 3082 struct net *net = seq_file_net(seq);
3083 loff_t off; 3083 loff_t off;
3084 struct net_device *dev; 3084 struct net_device *dev;
3085 3085
3086 read_lock(&dev_base_lock); 3086 rcu_read_lock();
3087 if (!*pos) 3087 if (!*pos)
3088 return SEQ_START_TOKEN; 3088 return SEQ_START_TOKEN;
3089 3089
3090 off = 1; 3090 off = 1;
3091 for_each_netdev(net, dev) 3091 for_each_netdev_rcu(net, dev)
3092 if (off++ == *pos) 3092 if (off++ == *pos)
3093 return dev; 3093 return dev;
3094 3094
@@ -3097,16 +3097,18 @@ void *dev_seq_start(struct seq_file *seq, loff_t *pos)
3097 3097
3098void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) 3098void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
3099{ 3099{
3100 struct net *net = seq_file_net(seq); 3100 struct net_device *dev = (v == SEQ_START_TOKEN) ?
3101 first_net_device(seq_file_net(seq)) :
3102 next_net_device((struct net_device *)v);
3103
3101 ++*pos; 3104 ++*pos;
3102 return v == SEQ_START_TOKEN ? 3105 return rcu_dereference(dev);
3103 first_net_device(net) : next_net_device((struct net_device *)v);
3104} 3106}
3105 3107
3106void dev_seq_stop(struct seq_file *seq, void *v) 3108void dev_seq_stop(struct seq_file *seq, void *v)
3107 __releases(dev_base_lock) 3109 __releases(RCU)
3108{ 3110{
3109 read_unlock(&dev_base_lock); 3111 rcu_read_unlock();
3110} 3112}
3111 3113
3112static void dev_seq_printf_stats(struct seq_file *seq, struct net_device *dev) 3114static void dev_seq_printf_stats(struct seq_file *seq, struct net_device *dev)