aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/iface.c
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/iface.c
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/iface.c')
-rw-r--r--net/mac80211/iface.c31
1 files changed, 31 insertions, 0 deletions
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}