aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-01-23 16:54:03 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-01-29 16:01:45 -0500
commitc771c9d8da1e8292ef8bf7fd4ce135dacc650130 (patch)
tree79b259a6b0396cbecf9e775c7ba5a80e2c4d94c9 /net/mac80211
parent506d03f97d10e54fd27c58c872a98242326d6419 (diff)
mac80211: add interface list lock
Using only the RTNL has a number of problems, most notably that ieee80211_iterate_active_interfaces() and other interface list traversals cannot be done from the internal workqueue because it needs to be flushed under the RTNL. This patch introduces a new mutex that protects the interface list against modifications. A more detailed explanation is part of the code change. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/ieee80211_i.h2
-rw-r--r--net/mac80211/iface.c31
-rw-r--r--net/mac80211/main.c3
-rw-r--r--net/mac80211/util.c4
4 files changed, 38 insertions, 2 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 927cbde8c19c..eaf3603862b7 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -643,7 +643,9 @@ struct ieee80211_local {
643 struct crypto_blkcipher *wep_rx_tfm; 643 struct crypto_blkcipher *wep_rx_tfm;
644 u32 wep_iv; 644 u32 wep_iv;
645 645
646 /* see iface.c */
646 struct list_head interfaces; 647 struct list_head interfaces;
648 struct mutex iflist_mtx;
647 649
648 /* 650 /*
649 * Key lock, protects sdata's key_list and sta_info's 651 * Key lock, protects sdata's key_list and sta_info's
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 8dc2c2188d92..00562a8b99cf 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -21,6 +21,23 @@
21#include "mesh.h" 21#include "mesh.h"
22#include "led.h" 22#include "led.h"
23 23
24/**
25 * DOC: Interface list locking
26 *
27 * The interface list in each struct ieee80211_local is protected
28 * three-fold:
29 *
30 * (1) modifications may only be done under the RTNL
31 * (2) modifications and readers are protected against each other by
32 * the iflist_mtx.
33 * (3) modifications are done in an RCU manner so atomic readers
34 * can traverse the list in RCU-safe blocks.
35 *
36 * As a consequence, reads (traversals) of the list can be protected
37 * by either the RTNL, the iflist_mtx or RCU.
38 */
39
40
24static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) 41static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
25{ 42{
26 int meshhdrlen; 43 int meshhdrlen;
@@ -800,7 +817,9 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
800 params->mesh_id_len, 817 params->mesh_id_len,
801 params->mesh_id); 818 params->mesh_id);
802 819
820 mutex_lock(&local->iflist_mtx);
803 list_add_tail_rcu(&sdata->list, &local->interfaces); 821 list_add_tail_rcu(&sdata->list, &local->interfaces);
822 mutex_unlock(&local->iflist_mtx);
804 823
805 if (new_dev) 824 if (new_dev)
806 *new_dev = ndev; 825 *new_dev = ndev;
@@ -816,7 +835,10 @@ void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata)
816{ 835{
817 ASSERT_RTNL(); 836 ASSERT_RTNL();
818 837
838 mutex_lock(&sdata->local->iflist_mtx);
819 list_del_rcu(&sdata->list); 839 list_del_rcu(&sdata->list);
840 mutex_unlock(&sdata->local->iflist_mtx);
841
820 synchronize_rcu(); 842 synchronize_rcu();
821 unregister_netdevice(sdata->dev); 843 unregister_netdevice(sdata->dev);
822} 844}
@@ -832,7 +854,16 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local)
832 ASSERT_RTNL(); 854 ASSERT_RTNL();
833 855
834 list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) { 856 list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) {
857 /*
858 * we cannot hold the iflist_mtx across unregister_netdevice,
859 * but we only need to hold it for list modifications to lock
860 * out readers since we're under the RTNL here as all other
861 * writers.
862 */
863 mutex_lock(&local->iflist_mtx);
835 list_del(&sdata->list); 864 list_del(&sdata->list);
865 mutex_unlock(&local->iflist_mtx);
866
836 unregister_netdevice(sdata->dev); 867 unregister_netdevice(sdata->dev);
837 } 868 }
838} 869}
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 210dfe3cf6c3..a109c06e8e4e 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -758,6 +758,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
758 local->hw.conf.radio_enabled = true; 758 local->hw.conf.radio_enabled = true;
759 759
760 INIT_LIST_HEAD(&local->interfaces); 760 INIT_LIST_HEAD(&local->interfaces);
761 mutex_init(&local->iflist_mtx);
761 762
762 spin_lock_init(&local->key_lock); 763 spin_lock_init(&local->key_lock);
763 764
@@ -1008,6 +1009,8 @@ void ieee80211_free_hw(struct ieee80211_hw *hw)
1008{ 1009{
1009 struct ieee80211_local *local = hw_to_local(hw); 1010 struct ieee80211_local *local = hw_to_local(hw);
1010 1011
1012 mutex_destroy(&local->iflist_mtx);
1013
1011 wiphy_free(local->hw.wiphy); 1014 wiphy_free(local->hw.wiphy);
1012} 1015}
1013EXPORT_SYMBOL(ieee80211_free_hw); 1016EXPORT_SYMBOL(ieee80211_free_hw);
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index fc30f2940e1e..73c7d7345abd 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -468,7 +468,7 @@ void ieee80211_iterate_active_interfaces(
468 struct ieee80211_local *local = hw_to_local(hw); 468 struct ieee80211_local *local = hw_to_local(hw);
469 struct ieee80211_sub_if_data *sdata; 469 struct ieee80211_sub_if_data *sdata;
470 470
471 rtnl_lock(); 471 mutex_lock(&local->iflist_mtx);
472 472
473 list_for_each_entry(sdata, &local->interfaces, list) { 473 list_for_each_entry(sdata, &local->interfaces, list) {
474 switch (sdata->vif.type) { 474 switch (sdata->vif.type) {
@@ -489,7 +489,7 @@ void ieee80211_iterate_active_interfaces(
489 &sdata->vif); 489 &sdata->vif);
490 } 490 }
491 491
492 rtnl_unlock(); 492 mutex_unlock(&local->iflist_mtx);
493} 493}
494EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces); 494EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces);
495 495