aboutsummaryrefslogtreecommitdiffstats
path: root/net/core
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2011-01-26 13:08:02 -0500
committerDavid S. Miller <davem@davemloft.net>2011-01-27 18:02:56 -0500
commitccf434380d1a67df2dcb9113206b77d0cb0a1cef (patch)
tree1e1a36691f42ed7448f27f71a9ca9445e88ab5f1 /net/core
parent065825402c058f4a123ddc53dbbe864cc5caaf64 (diff)
net: fix dev_seq_next()
Commit c6d14c84566d (net: Introduce for_each_netdev_rcu() iterator) added a race in dev_seq_next(). The rcu_dereference() call should be done _before_ testing the end of list, or we might return a wrong net_device if a concurrent thread changes net_device list under us. Note : discovered thanks to a sparse warning : net/core/dev.c:3919:9: error: incompatible types in comparison expression (different address spaces) Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> CC: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core')
-rw-r--r--net/core/dev.c11
1 files changed, 7 insertions, 4 deletions
diff --git a/net/core/dev.c b/net/core/dev.c
index 1b4c07fe295f..ddd5df2b61d4 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4051,12 +4051,15 @@ void *dev_seq_start(struct seq_file *seq, loff_t *pos)
4051 4051
4052void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) 4052void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
4053{ 4053{
4054 struct net_device *dev = (v == SEQ_START_TOKEN) ? 4054 struct net_device *dev = v;
4055 first_net_device(seq_file_net(seq)) : 4055
4056 next_net_device((struct net_device *)v); 4056 if (v == SEQ_START_TOKEN)
4057 dev = first_net_device_rcu(seq_file_net(seq));
4058 else
4059 dev = next_net_device_rcu(dev);
4057 4060
4058 ++*pos; 4061 ++*pos;
4059 return rcu_dereference(dev); 4062 return dev;
4060} 4063}
4061 4064
4062void dev_seq_stop(struct seq_file *seq, void *v) 4065void dev_seq_stop(struct seq_file *seq, void *v)