* @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.
#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;
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;
{
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);
}
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);
}
}
local->hw.conf.radio_enabled = true;
INIT_LIST_HEAD(&local->interfaces);
+ mutex_init(&local->iflist_mtx);
spin_lock_init(&local->key_lock);
{
struct ieee80211_local *local = hw_to_local(hw);
+ mutex_destroy(&local->iflist_mtx);
+
wiphy_free(local->hw.wiphy);
}
EXPORT_SYMBOL(ieee80211_free_hw);
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) {
&sdata->vif);
}
- rtnl_unlock();
+ mutex_unlock(&local->iflist_mtx);
}
EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces);