wext: remove atomic requirement for wireless stats
authorJohannes Berg <johannes@sipsolutions.net>
Tue, 19 May 2009 15:19:36 +0000 (17:19 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 22 May 2009 18:05:59 +0000 (14:05 -0400)
The requirement for wireless stats to be atomic is now mostly
artificial since we hold the rtnl _and_ the dev_base_lock for
iterating the device list. Doing that is not required, just the
rtnl is sufficient (and the rtnl is required for other reasons
outlined in commit "wext: fix get_wireless_stats locking").

This will fix http://bugzilla.kernel.org/show_bug.cgi?id=13344
and make things easier for drivers.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
net/wireless/wext.c

index d3bbef70cc7c3624882460569197b10c644c331a..22378daceb9464865f3be5a4d9ab4d223a2e82cf 100644 (file)
@@ -636,8 +636,10 @@ static void wireless_seq_printf_stats(struct seq_file *seq,
 /*
  * Print info for /proc/net/wireless (print all entries)
  */
-static int wireless_seq_show(struct seq_file *seq, void *v)
+static int wireless_dev_seq_show(struct seq_file *seq, void *v)
 {
+       might_sleep();
+
        if (v == SEQ_START_TOKEN)
                seq_printf(seq, "Inter-| sta-|   Quality        |   Discarded "
                                "packets               | Missed | WE\n"
@@ -651,21 +653,41 @@ static int wireless_seq_show(struct seq_file *seq, void *v)
 
 static void *wireless_dev_seq_start(struct seq_file *seq, loff_t *pos)
 {
+       struct net *net = seq_file_net(seq);
+       loff_t off;
+       struct net_device *dev;
+
        rtnl_lock();
-       return dev_seq_start(seq, pos);
+       if (!*pos)
+               return SEQ_START_TOKEN;
+
+       off = 1;
+       for_each_netdev(net, dev)
+               if (off++ == *pos)
+                       return dev;
+       return NULL;
+}
+
+static void *wireless_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+       struct net *net = seq_file_net(seq);
+
+       ++*pos;
+
+       return v == SEQ_START_TOKEN ?
+               first_net_device(net) : next_net_device(v);
 }
 
 static void wireless_dev_seq_stop(struct seq_file *seq, void *v)
 {
-       dev_seq_stop(seq, v);
        rtnl_unlock();
 }
 
 static const struct seq_operations wireless_seq_ops = {
        .start = wireless_dev_seq_start,
-       .next  = dev_seq_next,
+       .next  = wireless_dev_seq_next,
        .stop  = wireless_dev_seq_stop,
-       .show  = wireless_seq_show,
+       .show  = wireless_dev_seq_show,
 };
 
 static int seq_open_wireless(struct inode *inode, struct file *file)