aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBob Copeland <me@bobcopeland.com>2016-03-26 11:27:19 -0400
committerJohannes Berg <johannes.berg@intel.com>2016-04-05 15:34:54 -0400
commite596af827960c41a6051d4e719bafcfb7da11b64 (patch)
tree6f29fda7c51fd24fb943990a3c32846829ad45ec
parent0371a08fbb3e557f19db41e47a199ad8300c9c97 (diff)
mac80211: mesh: flush paths outside of plink lock
Lockdep warned of a lock dependency between the mesh_plink lock and the internal lock for the rhashtable. The problem is that the rhashtable code uses a spin lock with softirqs enabled, while mesh_plink_timer executes a walk (to flush paths on a state change) inside a softirq with the plink lock held. This leads to the following deadlock if the timer fires while rht lock is held on this CPU, and plink lock is held on another CPU: CPU0 CPU1 ---- ---- lock(&(&ht->lock)->rlock); local_irq_disable(); lock(&(&sta->mesh->plink_lock)->rlock); lock(&(&ht->lock)->rlock); <Interrupt> lock(&(&sta->mesh->plink_lock)->rlock); *** DEADLOCK *** Fix by waiting until we drop the plink lock to flush paths. Fixes: d48a1b7cd439 ("mac80211: mesh: convert path table to rhashtable") Signed-off-by: Bob Copeland <me@bobcopeland.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--net/mac80211/mesh_plink.c11
1 files changed, 9 insertions, 2 deletions
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index a07e93c21c9e..ecfba8ad29e4 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -331,7 +331,9 @@ free:
331 * 331 *
332 * @sta: mesh peer link to deactivate 332 * @sta: mesh peer link to deactivate
333 * 333 *
334 * All mesh paths with this peer as next hop will be flushed 334 * Mesh paths with this peer as next hop should be flushed
335 * by the caller outside of plink_lock.
336 *
335 * Returns beacon changed flag if the beacon content changed. 337 * Returns beacon changed flag if the beacon content changed.
336 * 338 *
337 * Locking: the caller must hold sta->mesh->plink_lock 339 * Locking: the caller must hold sta->mesh->plink_lock
@@ -346,7 +348,6 @@ static u32 __mesh_plink_deactivate(struct sta_info *sta)
346 if (sta->mesh->plink_state == NL80211_PLINK_ESTAB) 348 if (sta->mesh->plink_state == NL80211_PLINK_ESTAB)
347 changed = mesh_plink_dec_estab_count(sdata); 349 changed = mesh_plink_dec_estab_count(sdata);
348 sta->mesh->plink_state = NL80211_PLINK_BLOCKED; 350 sta->mesh->plink_state = NL80211_PLINK_BLOCKED;
349 mesh_path_flush_by_nexthop(sta);
350 351
351 ieee80211_mps_sta_status_update(sta); 352 ieee80211_mps_sta_status_update(sta);
352 changed |= ieee80211_mps_set_sta_local_pm(sta, 353 changed |= ieee80211_mps_set_sta_local_pm(sta,
@@ -374,6 +375,7 @@ u32 mesh_plink_deactivate(struct sta_info *sta)
374 sta->sta.addr, sta->mesh->llid, sta->mesh->plid, 375 sta->sta.addr, sta->mesh->llid, sta->mesh->plid,
375 sta->mesh->reason); 376 sta->mesh->reason);
376 spin_unlock_bh(&sta->mesh->plink_lock); 377 spin_unlock_bh(&sta->mesh->plink_lock);
378 mesh_path_flush_by_nexthop(sta);
377 379
378 return changed; 380 return changed;
379} 381}
@@ -748,6 +750,7 @@ u32 mesh_plink_block(struct sta_info *sta)
748 changed = __mesh_plink_deactivate(sta); 750 changed = __mesh_plink_deactivate(sta);
749 sta->mesh->plink_state = NL80211_PLINK_BLOCKED; 751 sta->mesh->plink_state = NL80211_PLINK_BLOCKED;
750 spin_unlock_bh(&sta->mesh->plink_lock); 752 spin_unlock_bh(&sta->mesh->plink_lock);
753 mesh_path_flush_by_nexthop(sta);
751 754
752 return changed; 755 return changed;
753} 756}
@@ -797,6 +800,7 @@ static u32 mesh_plink_fsm(struct ieee80211_sub_if_data *sdata,
797 struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg; 800 struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg;
798 enum ieee80211_self_protected_actioncode action = 0; 801 enum ieee80211_self_protected_actioncode action = 0;
799 u32 changed = 0; 802 u32 changed = 0;
803 bool flush = false;
800 804
801 mpl_dbg(sdata, "peer %pM in state %s got event %s\n", sta->sta.addr, 805 mpl_dbg(sdata, "peer %pM in state %s got event %s\n", sta->sta.addr,
802 mplstates[sta->mesh->plink_state], mplevents[event]); 806 mplstates[sta->mesh->plink_state], mplevents[event]);
@@ -885,6 +889,7 @@ static u32 mesh_plink_fsm(struct ieee80211_sub_if_data *sdata,
885 changed |= mesh_set_short_slot_time(sdata); 889 changed |= mesh_set_short_slot_time(sdata);
886 mesh_plink_close(sdata, sta, event); 890 mesh_plink_close(sdata, sta, event);
887 action = WLAN_SP_MESH_PEERING_CLOSE; 891 action = WLAN_SP_MESH_PEERING_CLOSE;
892 flush = true;
888 break; 893 break;
889 case OPN_ACPT: 894 case OPN_ACPT:
890 action = WLAN_SP_MESH_PEERING_CONFIRM; 895 action = WLAN_SP_MESH_PEERING_CONFIRM;
@@ -916,6 +921,8 @@ static u32 mesh_plink_fsm(struct ieee80211_sub_if_data *sdata,
916 break; 921 break;
917 } 922 }
918 spin_unlock_bh(&sta->mesh->plink_lock); 923 spin_unlock_bh(&sta->mesh->plink_lock);
924 if (flush)
925 mesh_path_flush_by_nexthop(sta);
919 if (action) { 926 if (action) {
920 mesh_plink_frame_tx(sdata, sta, action, sta->sta.addr, 927 mesh_plink_frame_tx(sdata, sta, action, sta->sta.addr,
921 sta->mesh->llid, sta->mesh->plid, 928 sta->mesh->llid, sta->mesh->plid,