aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/chan.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2013-12-18 03:43:33 -0500
committerJohannes Berg <johannes.berg@intel.com>2013-12-19 07:33:33 -0500
commit34a3740d6b392896b71e36cd5cd68837a8f94a5c (patch)
tree128f9a3e35af1e7fc768b55fc7173cac9e1a3b08 /net/mac80211/chan.c
parent6924d0138acdf5026ee4463134d98e139fe025a2 (diff)
mac80211: fix iflist_mtx/mtx locking in radar detection
The scan code creates an iflist_mtx -> mtx locking dependency, and a few other places, notably radar detection, were creating the opposite dependency, causing lockdep to complain. As scan and radar detection are mutually exclusive, the deadlock can't really happen in practice, but it's still bad form. A similar issue exists in the monitor mode code, but this is only used by channel-context drivers right now and those have to have hardware scan, so that also can't happen. Still, fix these issues by making some of the channel context code require the mtx to be held rather than acquiring it, thus allowing the monitor/radar callers to keep the iflist_mtx->mtx lock ordering. While at it, also fix access to the local->scanning variable in the radar code, and document that radar_detect_enabled is now properly protected by the mtx. All this would now introduce an ABBA deadlock between the DFS work cancelling and local->mtx, so change the locking there a bit to not need to use cancel_delayed_work_sync() but be able to just use cancel_delayed_work(). The work is also safely stopped/removed when the interface is stopped, so no extra changes are needed. Reported-by: Kalle Valo <kvalo@qca.qualcomm.com> Tested-by: Simon Wunderlich <sw@simonwunderlich.de> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/chan.c')
-rw-r--r--net/mac80211/chan.c21
1 files changed, 11 insertions, 10 deletions
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index f20a98a70cc0..f43613a97dd6 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -232,8 +232,8 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
232 if (!local->use_chanctx) 232 if (!local->use_chanctx)
233 local->hw.conf.radar_enabled = ctx->conf.radar_enabled; 233 local->hw.conf.radar_enabled = ctx->conf.radar_enabled;
234 234
235 /* acquire mutex to prevent idle from changing */ 235 /* we hold the mutex to prevent idle from changing */
236 mutex_lock(&local->mtx); 236 lockdep_assert_held(&local->mtx);
237 /* turn idle off *before* setting channel -- some drivers need that */ 237 /* turn idle off *before* setting channel -- some drivers need that */
238 changed = ieee80211_idle_off(local); 238 changed = ieee80211_idle_off(local);
239 if (changed) 239 if (changed)
@@ -246,19 +246,14 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
246 err = drv_add_chanctx(local, ctx); 246 err = drv_add_chanctx(local, ctx);
247 if (err) { 247 if (err) {
248 kfree(ctx); 248 kfree(ctx);
249 ctx = ERR_PTR(err);
250
251 ieee80211_recalc_idle(local); 249 ieee80211_recalc_idle(local);
252 goto out; 250 return ERR_PTR(err);
253 } 251 }
254 } 252 }
255 253
256 /* and keep the mutex held until the new chanctx is on the list */ 254 /* and keep the mutex held until the new chanctx is on the list */
257 list_add_rcu(&ctx->list, &local->chanctx_list); 255 list_add_rcu(&ctx->list, &local->chanctx_list);
258 256
259 out:
260 mutex_unlock(&local->mtx);
261
262 return ctx; 257 return ctx;
263} 258}
264 259
@@ -294,9 +289,7 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local,
294 /* throw a warning if this wasn't the only channel context. */ 289 /* throw a warning if this wasn't the only channel context. */
295 WARN_ON(check_single_channel && !list_empty(&local->chanctx_list)); 290 WARN_ON(check_single_channel && !list_empty(&local->chanctx_list));
296 291
297 mutex_lock(&local->mtx);
298 ieee80211_recalc_idle(local); 292 ieee80211_recalc_idle(local);
299 mutex_unlock(&local->mtx);
300} 293}
301 294
302static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, 295static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
@@ -364,6 +357,8 @@ static void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local,
364 bool radar_enabled; 357 bool radar_enabled;
365 358
366 lockdep_assert_held(&local->chanctx_mtx); 359 lockdep_assert_held(&local->chanctx_mtx);
360 /* for setting local->radar_detect_enabled */
361 lockdep_assert_held(&local->mtx);
367 362
368 radar_enabled = ieee80211_is_radar_required(local); 363 radar_enabled = ieee80211_is_radar_required(local);
369 364
@@ -518,6 +513,8 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
518 struct ieee80211_chanctx *ctx; 513 struct ieee80211_chanctx *ctx;
519 int ret; 514 int ret;
520 515
516 lockdep_assert_held(&local->mtx);
517
521 WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev)); 518 WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
522 519
523 mutex_lock(&local->chanctx_mtx); 520 mutex_lock(&local->chanctx_mtx);
@@ -558,6 +555,8 @@ int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
558 int ret; 555 int ret;
559 u32 chanctx_changed = 0; 556 u32 chanctx_changed = 0;
560 557
558 lockdep_assert_held(&local->mtx);
559
561 /* should never be called if not performing a channel switch. */ 560 /* should never be called if not performing a channel switch. */
562 if (WARN_ON(!sdata->vif.csa_active)) 561 if (WARN_ON(!sdata->vif.csa_active))
563 return -EINVAL; 562 return -EINVAL;
@@ -655,6 +654,8 @@ void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
655{ 654{
656 WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev)); 655 WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
657 656
657 lockdep_assert_held(&sdata->local->mtx);
658
658 mutex_lock(&sdata->local->chanctx_mtx); 659 mutex_lock(&sdata->local->chanctx_mtx);
659 __ieee80211_vif_release_channel(sdata); 660 __ieee80211_vif_release_channel(sdata);
660 mutex_unlock(&sdata->local->chanctx_mtx); 661 mutex_unlock(&sdata->local->chanctx_mtx);