mac80211: update mesh beacon on workqueue
Instead of updating the mesh beacon immediately when requested (which would require the sdata_lock()), defer it to the mac80211 workqueue. Fixes yet another deadlock on calling sta_info_flush() with the sdata_lock() held from ieee80211_stop_mesh(). We could just drop the sdata_lock() around the mesh_sta_cleanup() call, but this path is also taken from several non-locked error paths. Signed-off-by: Thomas Pedersen <thomas@cozybit.com> [fix comment position] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
a1193be83b
commit
f81a9dedaf
|
@ -544,6 +544,7 @@ struct ieee80211_if_mesh {
|
||||||
struct timer_list mesh_path_root_timer;
|
struct timer_list mesh_path_root_timer;
|
||||||
|
|
||||||
unsigned long wrkq_flags;
|
unsigned long wrkq_flags;
|
||||||
|
unsigned long mbss_changed;
|
||||||
|
|
||||||
u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN];
|
u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN];
|
||||||
size_t mesh_id_len;
|
size_t mesh_id_len;
|
||||||
|
|
|
@ -161,11 +161,8 @@ void mesh_sta_cleanup(struct sta_info *sta)
|
||||||
del_timer_sync(&sta->plink_timer);
|
del_timer_sync(&sta->plink_timer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changed) {
|
if (changed)
|
||||||
sdata_lock(sdata);
|
|
||||||
ieee80211_mbss_info_change_notify(sdata, changed);
|
ieee80211_mbss_info_change_notify(sdata, changed);
|
||||||
sdata_unlock(sdata);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int mesh_rmc_init(struct ieee80211_sub_if_data *sdata)
|
int mesh_rmc_init(struct ieee80211_sub_if_data *sdata)
|
||||||
|
@ -719,14 +716,18 @@ ieee80211_mesh_rebuild_beacon(struct ieee80211_sub_if_data *sdata)
|
||||||
void ieee80211_mbss_info_change_notify(struct ieee80211_sub_if_data *sdata,
|
void ieee80211_mbss_info_change_notify(struct ieee80211_sub_if_data *sdata,
|
||||||
u32 changed)
|
u32 changed)
|
||||||
{
|
{
|
||||||
if (sdata->vif.bss_conf.enable_beacon &&
|
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||||
(changed & (BSS_CHANGED_BEACON |
|
unsigned long bits = changed;
|
||||||
BSS_CHANGED_HT |
|
u32 bit;
|
||||||
BSS_CHANGED_BASIC_RATES |
|
|
||||||
BSS_CHANGED_BEACON_INT)))
|
if (!bits)
|
||||||
if (ieee80211_mesh_rebuild_beacon(sdata))
|
return;
|
||||||
return;
|
|
||||||
ieee80211_bss_info_change_notify(sdata, changed);
|
/* if we race with running work, worst case this work becomes a noop */
|
||||||
|
for_each_set_bit(bit, &bits, sizeof(changed) * BITS_PER_BYTE)
|
||||||
|
set_bit(bit, &ifmsh->mbss_changed);
|
||||||
|
set_bit(MESH_WORK_MBSS_CHANGED, &ifmsh->wrkq_flags);
|
||||||
|
ieee80211_queue_work(&sdata->local->hw, &sdata->work);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
|
int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
|
||||||
|
@ -799,6 +800,10 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
|
||||||
del_timer_sync(&sdata->u.mesh.mesh_path_root_timer);
|
del_timer_sync(&sdata->u.mesh.mesh_path_root_timer);
|
||||||
del_timer_sync(&sdata->u.mesh.mesh_path_timer);
|
del_timer_sync(&sdata->u.mesh.mesh_path_timer);
|
||||||
|
|
||||||
|
/* clear any mesh work (for next join) we may have accrued */
|
||||||
|
ifmsh->wrkq_flags = 0;
|
||||||
|
ifmsh->mbss_changed = 0;
|
||||||
|
|
||||||
local->fif_other_bss--;
|
local->fif_other_bss--;
|
||||||
atomic_dec(&local->iff_allmultis);
|
atomic_dec(&local->iff_allmultis);
|
||||||
ieee80211_configure_filter(local);
|
ieee80211_configure_filter(local);
|
||||||
|
@ -965,6 +970,28 @@ out:
|
||||||
sdata_unlock(sdata);
|
sdata_unlock(sdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void mesh_bss_info_changed(struct ieee80211_sub_if_data *sdata)
|
||||||
|
{
|
||||||
|
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||||
|
u32 bit, changed = 0;
|
||||||
|
|
||||||
|
for_each_set_bit(bit, &ifmsh->mbss_changed,
|
||||||
|
sizeof(changed) * BITS_PER_BYTE) {
|
||||||
|
clear_bit(bit, &ifmsh->mbss_changed);
|
||||||
|
changed |= BIT(bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sdata->vif.bss_conf.enable_beacon &&
|
||||||
|
(changed & (BSS_CHANGED_BEACON |
|
||||||
|
BSS_CHANGED_HT |
|
||||||
|
BSS_CHANGED_BASIC_RATES |
|
||||||
|
BSS_CHANGED_BEACON_INT)))
|
||||||
|
if (ieee80211_mesh_rebuild_beacon(sdata))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ieee80211_bss_info_change_notify(sdata, changed);
|
||||||
|
}
|
||||||
|
|
||||||
void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata)
|
void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata)
|
||||||
{
|
{
|
||||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||||
|
@ -995,6 +1022,8 @@ void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata)
|
||||||
if (test_and_clear_bit(MESH_WORK_DRIFT_ADJUST, &ifmsh->wrkq_flags))
|
if (test_and_clear_bit(MESH_WORK_DRIFT_ADJUST, &ifmsh->wrkq_flags))
|
||||||
mesh_sync_adjust_tbtt(sdata);
|
mesh_sync_adjust_tbtt(sdata);
|
||||||
|
|
||||||
|
if (test_and_clear_bit(MESH_WORK_MBSS_CHANGED, &ifmsh->wrkq_flags))
|
||||||
|
mesh_bss_info_changed(sdata);
|
||||||
out:
|
out:
|
||||||
sdata_unlock(sdata);
|
sdata_unlock(sdata);
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,7 @@ enum mesh_path_flags {
|
||||||
* @MESH_WORK_ROOT: the mesh root station needs to send a frame
|
* @MESH_WORK_ROOT: the mesh root station needs to send a frame
|
||||||
* @MESH_WORK_DRIFT_ADJUST: time to compensate for clock drift relative to other
|
* @MESH_WORK_DRIFT_ADJUST: time to compensate for clock drift relative to other
|
||||||
* mesh nodes
|
* mesh nodes
|
||||||
|
* @MESH_WORK_MBSS_CHANGED: rebuild beacon and notify driver of BSS changes
|
||||||
*/
|
*/
|
||||||
enum mesh_deferred_task_flags {
|
enum mesh_deferred_task_flags {
|
||||||
MESH_WORK_HOUSEKEEPING,
|
MESH_WORK_HOUSEKEEPING,
|
||||||
|
@ -65,6 +66,7 @@ enum mesh_deferred_task_flags {
|
||||||
MESH_WORK_GROW_MPP_TABLE,
|
MESH_WORK_GROW_MPP_TABLE,
|
||||||
MESH_WORK_ROOT,
|
MESH_WORK_ROOT,
|
||||||
MESH_WORK_DRIFT_ADJUST,
|
MESH_WORK_DRIFT_ADJUST,
|
||||||
|
MESH_WORK_MBSS_CHANGED,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue