aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/tx.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2007-09-18 17:29:21 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-10 19:53:00 -0400
commit79010420cc3f78eab911598bfdd29c4b06a83e1f (patch)
treea9031164d7944f8aa90a455d297780b241f3d865 /net/mac80211/tx.c
parentea49c359f36d5b40bf033c45a08332cb73777aa2 (diff)
[PATCH] mac80211: fix virtual interface locking
Florian Lohoff noticed a bug in mac80211: when bringing the master interface down while other virtual interfaces are up we call dev_close() under a spinlock which is not allowed. This patch removes the sub_if_lock used by mac80211 in favour of using an RCU list. All list manipulations are already done under rtnl so are well protected against each other, and the read-side locks we took in the RX and TX code are already in RCU read-side critical sections. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Cc: Florian Lohoff <flo@rfc822.org> Cc: Herbert Xu <herbert@gondor.apana.org.au> Cc: Michal Piotrowski <michal.k.k.piotrowski@gmail.com> Cc: Satyam Sharma <satyam@infradead.org> Signed-off-by: Michael Wu <flamingice@sourmilk.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/tx.c')
-rw-r--r--net/mac80211/tx.c10
1 files changed, 7 insertions, 3 deletions
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 38394c40f6ad..244c80d0c8fb 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -295,8 +295,12 @@ static void purge_old_ps_buffers(struct ieee80211_local *local)
295 struct ieee80211_sub_if_data *sdata; 295 struct ieee80211_sub_if_data *sdata;
296 struct sta_info *sta; 296 struct sta_info *sta;
297 297
298 read_lock(&local->sub_if_lock); 298 /*
299 list_for_each_entry(sdata, &local->sub_if_list, list) { 299 * virtual interfaces are protected by RCU
300 */
301 rcu_read_lock();
302
303 list_for_each_entry_rcu(sdata, &local->interfaces, list) {
300 struct ieee80211_if_ap *ap; 304 struct ieee80211_if_ap *ap;
301 if (sdata->dev == local->mdev || 305 if (sdata->dev == local->mdev ||
302 sdata->type != IEEE80211_IF_TYPE_AP) 306 sdata->type != IEEE80211_IF_TYPE_AP)
@@ -309,7 +313,7 @@ static void purge_old_ps_buffers(struct ieee80211_local *local)
309 } 313 }
310 total += skb_queue_len(&ap->ps_bc_buf); 314 total += skb_queue_len(&ap->ps_bc_buf);
311 } 315 }
312 read_unlock(&local->sub_if_lock); 316 rcu_read_unlock();
313 317
314 read_lock_bh(&local->sta_lock); 318 read_lock_bh(&local->sta_lock);
315 list_for_each_entry(sta, &local->sta_list, list) { 319 list_for_each_entry(sta, &local->sta_list, list) {