mac80211: fix debugfs lockup
authorJohannes Berg <johannes@sipsolutions.net>
Tue, 7 Oct 2008 10:04:29 +0000 (12:04 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Wed, 15 Oct 2008 00:46:41 +0000 (20:46 -0400)
When debugfs_create_dir fails, sta_info_debugfs_add_work will not
terminate because it will find the same station again and again.
This is possible whenever debugfs fails for whatever reason; one
reason is a race condition in mac80211, unfortunately we cannot
do much about it, so just document it, it just means some station
may be missing from debugfs.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Cc: Robin Holt <holt@sgi.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
net/mac80211/debugfs_sta.c
net/mac80211/sta_info.c
net/mac80211/sta_info.h

index b9902e425f096f336f93c97aa2a4494508de4272..189d0bafa91ae0f274c2813f912012679f53903d 100644 (file)
@@ -249,11 +249,22 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
        DECLARE_MAC_BUF(mbuf);
        u8 *mac;
 
+       sta->debugfs.add_has_run = true;
+
        if (!stations_dir)
                return;
 
        mac = print_mac(mbuf, sta->sta.addr);
 
+       /*
+        * This might fail due to a race condition:
+        * When mac80211 unlinks a station, the debugfs entries
+        * remain, but it is already possible to link a new
+        * station with the same address which triggers adding
+        * it to debugfs; therefore, if the old station isn't
+        * destroyed quickly enough the old station's debugfs
+        * dir might still be around.
+        */
        sta->debugfs.dir = debugfs_create_dir(mac, stations_dir);
        if (!sta->debugfs.dir)
                return;
index 9b72d15bc8dcb7c12978c607e057a67626c482c1..7fef8ea1f5ecf53eaf5b1596479ef1d8a834b348 100644 (file)
@@ -635,7 +635,12 @@ static void sta_info_debugfs_add_work(struct work_struct *work)
 
                spin_lock_irqsave(&local->sta_lock, flags);
                list_for_each_entry(tmp, &local->sta_list, list) {
-                       if (!tmp->debugfs.dir) {
+                       /*
+                        * debugfs.add_has_run will be set by
+                        * ieee80211_sta_debugfs_add regardless
+                        * of what else it does.
+                        */
+                       if (!tmp->debugfs.add_has_run) {
                                sta = tmp;
                                __sta_info_pin(sta);
                                break;
index a6b51862a89d2b8fc46ab9bdf7ff8fc2e27d89df..168a39a298bdc1f754de9ad1d0ac04f311466d33 100644 (file)
@@ -300,6 +300,7 @@ struct sta_info {
                struct dentry *inactive_ms;
                struct dentry *last_seq_ctrl;
                struct dentry *agg_status;
+               bool add_has_run;
        } debugfs;
 #endif