diff options
Diffstat (limited to 'net/core/dev.c')
-rw-r--r-- | net/core/dev.c | 30 |
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 | } |
813 | EXPORT_SYMBOL(dev_get_by_flags); | 813 | EXPORT_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 | */ |
3079 | void *dev_seq_start(struct seq_file *seq, loff_t *pos) | 3079 | void *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 | ||
3098 | void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) | 3098 | void *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 | ||
3106 | void dev_seq_stop(struct seq_file *seq, void *v) | 3108 | void 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 | ||
3112 | static void dev_seq_printf_stats(struct seq_file *seq, struct net_device *dev) | 3114 | static void dev_seq_printf_stats(struct seq_file *seq, struct net_device *dev) |