Skip to content

Commit

Permalink
mac80211: add interface list lock
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Johannes Berg authored and John W. Linville committed Jan 29, 2009
1 parent 506d03f commit c771c9d
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 5 deletions.
5 changes: 2 additions & 3 deletions include/net/mac80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -928,9 +928,8 @@ enum ieee80211_hw_flags {
* @workqueue: single threaded workqueue available for driver use,
* allocated by mac80211 on registration and flushed when an
* interface is removed.
* NOTICE: All work performed on this workqueue should NEVER
* acquire the RTNL lock (i.e. Don't use the function
* ieee80211_iterate_active_interfaces())
* NOTICE: All work performed on this workqueue must not
* acquire the RTNL lock.
*
* @priv: pointer to private area that was allocated for driver use
* along with this structure.
Expand Down
2 changes: 2 additions & 0 deletions net/mac80211/ieee80211_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -643,7 +643,9 @@ struct ieee80211_local {
struct crypto_blkcipher *wep_rx_tfm;
u32 wep_iv;

/* see iface.c */
struct list_head interfaces;
struct mutex iflist_mtx;

/*
* Key lock, protects sdata's key_list and sta_info's
Expand Down
31 changes: 31 additions & 0 deletions net/mac80211/iface.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,23 @@
#include "mesh.h"
#include "led.h"

/**
* DOC: Interface list locking
*
* The interface list in each struct ieee80211_local is protected
* three-fold:
*
* (1) modifications may only be done under the RTNL
* (2) modifications and readers are protected against each other by
* the iflist_mtx.
* (3) modifications are done in an RCU manner so atomic readers
* can traverse the list in RCU-safe blocks.
*
* As a consequence, reads (traversals) of the list can be protected
* by either the RTNL, the iflist_mtx or RCU.
*/


static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
{
int meshhdrlen;
Expand Down Expand Up @@ -800,7 +817,9 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
params->mesh_id_len,
params->mesh_id);

mutex_lock(&local->iflist_mtx);
list_add_tail_rcu(&sdata->list, &local->interfaces);
mutex_unlock(&local->iflist_mtx);

if (new_dev)
*new_dev = ndev;
Expand All @@ -816,7 +835,10 @@ void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata)
{
ASSERT_RTNL();

mutex_lock(&sdata->local->iflist_mtx);
list_del_rcu(&sdata->list);
mutex_unlock(&sdata->local->iflist_mtx);

synchronize_rcu();
unregister_netdevice(sdata->dev);
}
Expand All @@ -832,7 +854,16 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local)
ASSERT_RTNL();

list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) {
/*
* we cannot hold the iflist_mtx across unregister_netdevice,
* but we only need to hold it for list modifications to lock
* out readers since we're under the RTNL here as all other
* writers.
*/
mutex_lock(&local->iflist_mtx);
list_del(&sdata->list);
mutex_unlock(&local->iflist_mtx);

unregister_netdevice(sdata->dev);
}
}
3 changes: 3 additions & 0 deletions net/mac80211/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -758,6 +758,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
local->hw.conf.radio_enabled = true;

INIT_LIST_HEAD(&local->interfaces);
mutex_init(&local->iflist_mtx);

spin_lock_init(&local->key_lock);

Expand Down Expand Up @@ -1008,6 +1009,8 @@ void ieee80211_free_hw(struct ieee80211_hw *hw)
{
struct ieee80211_local *local = hw_to_local(hw);

mutex_destroy(&local->iflist_mtx);

wiphy_free(local->hw.wiphy);
}
EXPORT_SYMBOL(ieee80211_free_hw);
Expand Down
4 changes: 2 additions & 2 deletions net/mac80211/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,7 @@ void ieee80211_iterate_active_interfaces(
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_sub_if_data *sdata;

rtnl_lock();
mutex_lock(&local->iflist_mtx);

list_for_each_entry(sdata, &local->interfaces, list) {
switch (sdata->vif.type) {
Expand All @@ -489,7 +489,7 @@ void ieee80211_iterate_active_interfaces(
&sdata->vif);
}

rtnl_unlock();
mutex_unlock(&local->iflist_mtx);
}
EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces);

Expand Down

0 comments on commit c771c9d

Please sign in to comment.