diff options
author | Emmanuel Grumbach <emmanuel.grumbach@intel.com> | 2014-01-23 07:28:16 -0500 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2014-02-06 03:55:18 -0500 |
commit | 8ffcc704c963b4157391bd87a4544cdfd18b574d (patch) | |
tree | d5bfd6432cf63ead2302b28a5aeb1712c5d291e5 /net | |
parent | 5a6aa705ffdd97552ff756bbfa7d5a3b62a6c690 (diff) |
mac80211: avoid deadlock revealed by lockdep
sdata->u.ap.request_smps_work can’t be flushed synchronously
under wdev_lock(wdev) since ieee80211_request_smps_ap_work
itself locks the same lock.
While at it, reset the driver_smps_mode when the ap is
stopped to its default: OFF.
This solves:
======================================================
[ INFO: possible circular locking dependency detected ]
3.12.0-ipeer+ #2 Tainted: G O
-------------------------------------------------------
rmmod/2867 is trying to acquire lock:
((&sdata->u.ap.request_smps_work)){+.+...}, at: [<c105b8d0>] flush_work+0x0/0x90
but task is already holding lock:
(&wdev->mtx){+.+.+.}, at: [<f9b32626>] cfg80211_stop_ap+0x26/0x230 [cfg80211]
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #1 (&wdev->mtx){+.+.+.}:
[<c10aefa9>] lock_acquire+0x79/0xe0
[<c1607a1a>] mutex_lock_nested+0x4a/0x360
[<fb06288b>] ieee80211_request_smps_ap_work+0x2b/0x50 [mac80211]
[<c105cdd8>] process_one_work+0x198/0x450
[<c105d469>] worker_thread+0xf9/0x320
[<c10669ff>] kthread+0x9f/0xb0
[<c1613397>] ret_from_kernel_thread+0x1b/0x28
-> #0 ((&sdata->u.ap.request_smps_work)){+.+...}:
[<c10ae9df>] __lock_acquire+0x183f/0x1910
[<c10aefa9>] lock_acquire+0x79/0xe0
[<c105b917>] flush_work+0x47/0x90
[<c105d867>] __cancel_work_timer+0x67/0xe0
[<c105d90f>] cancel_work_sync+0xf/0x20
[<fb0765cc>] ieee80211_stop_ap+0x8c/0x340 [mac80211]
[<f9b3268c>] cfg80211_stop_ap+0x8c/0x230 [cfg80211]
[<f9b0d8f9>] cfg80211_leave+0x79/0x100 [cfg80211]
[<f9b0da72>] cfg80211_netdev_notifier_call+0xf2/0x4f0 [cfg80211]
[<c160f2c9>] notifier_call_chain+0x59/0x130
[<c106c6de>] __raw_notifier_call_chain+0x1e/0x30
[<c106c70f>] raw_notifier_call_chain+0x1f/0x30
[<c14f8213>] call_netdevice_notifiers_info+0x33/0x70
[<c14f8263>] call_netdevice_notifiers+0x13/0x20
[<c14f82a4>] __dev_close_many+0x34/0xb0
[<c14f83fe>] dev_close_many+0x6e/0xc0
[<c14f9c77>] rollback_registered_many+0xa7/0x1f0
[<c14f9dd4>] unregister_netdevice_many+0x14/0x60
[<fb06f4d9>] ieee80211_remove_interfaces+0xe9/0x170 [mac80211]
[<fb055116>] ieee80211_unregister_hw+0x56/0x110 [mac80211]
[<fa3e9396>] iwl_op_mode_mvm_stop+0x26/0xe0 [iwlmvm]
[<f9b9d8ca>] _iwl_op_mode_stop+0x3a/0x70 [iwlwifi]
[<f9b9d96f>] iwl_opmode_deregister+0x6f/0x90 [iwlwifi]
[<fa405179>] __exit_compat+0xd/0x19 [iwlmvm]
[<c10b8bf9>] SyS_delete_module+0x179/0x2b0
[<c1613421>] sysenter_do_call+0x12/0x32
Fixes: 687da132234f ("mac80211: implement SMPS for AP")
Cc: <stable@vger.kernel.org> [3.13]
Reported-by: Ilan Peer <ilan.peer@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/cfg.c | 3 | ||||
-rw-r--r-- | net/mac80211/ht.c | 4 | ||||
-rw-r--r-- | net/mac80211/iface.c | 15 |
3 files changed, 15 insertions, 7 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 94b4acb5aabb..33acdca4a1df 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -1090,8 +1090,6 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) | |||
1090 | kfree(sdata->u.ap.next_beacon); | 1090 | kfree(sdata->u.ap.next_beacon); |
1091 | sdata->u.ap.next_beacon = NULL; | 1091 | sdata->u.ap.next_beacon = NULL; |
1092 | 1092 | ||
1093 | cancel_work_sync(&sdata->u.ap.request_smps_work); | ||
1094 | |||
1095 | /* turn off carrier for this interface and dependent VLANs */ | 1093 | /* turn off carrier for this interface and dependent VLANs */ |
1096 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) | 1094 | list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) |
1097 | netif_carrier_off(vlan->dev); | 1095 | netif_carrier_off(vlan->dev); |
@@ -1103,6 +1101,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) | |||
1103 | kfree_rcu(old_beacon, rcu_head); | 1101 | kfree_rcu(old_beacon, rcu_head); |
1104 | if (old_probe_resp) | 1102 | if (old_probe_resp) |
1105 | kfree_rcu(old_probe_resp, rcu_head); | 1103 | kfree_rcu(old_probe_resp, rcu_head); |
1104 | sdata->u.ap.driver_smps_mode = IEEE80211_SMPS_OFF; | ||
1106 | 1105 | ||
1107 | __sta_info_flush(sdata, true); | 1106 | __sta_info_flush(sdata, true); |
1108 | ieee80211_free_keys(sdata, true); | 1107 | ieee80211_free_keys(sdata, true); |
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index fab7b91923e0..70dd013de836 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c | |||
@@ -466,7 +466,9 @@ void ieee80211_request_smps_ap_work(struct work_struct *work) | |||
466 | u.ap.request_smps_work); | 466 | u.ap.request_smps_work); |
467 | 467 | ||
468 | sdata_lock(sdata); | 468 | sdata_lock(sdata); |
469 | __ieee80211_request_smps_ap(sdata, sdata->u.ap.driver_smps_mode); | 469 | if (sdata_dereference(sdata->u.ap.beacon, sdata)) |
470 | __ieee80211_request_smps_ap(sdata, | ||
471 | sdata->u.ap.driver_smps_mode); | ||
470 | sdata_unlock(sdata); | 472 | sdata_unlock(sdata); |
471 | } | 473 | } |
472 | 474 | ||
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 3dfd20a453ab..ae2eb148a028 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -770,12 +770,19 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
770 | 770 | ||
771 | ieee80211_roc_purge(local, sdata); | 771 | ieee80211_roc_purge(local, sdata); |
772 | 772 | ||
773 | if (sdata->vif.type == NL80211_IFTYPE_STATION) | 773 | switch (sdata->vif.type) { |
774 | case NL80211_IFTYPE_STATION: | ||
774 | ieee80211_mgd_stop(sdata); | 775 | ieee80211_mgd_stop(sdata); |
775 | 776 | break; | |
776 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) | 777 | case NL80211_IFTYPE_ADHOC: |
777 | ieee80211_ibss_stop(sdata); | 778 | ieee80211_ibss_stop(sdata); |
778 | 779 | break; | |
780 | case NL80211_IFTYPE_AP: | ||
781 | cancel_work_sync(&sdata->u.ap.request_smps_work); | ||
782 | break; | ||
783 | default: | ||
784 | break; | ||
785 | } | ||
779 | 786 | ||
780 | /* | 787 | /* |
781 | * Remove all stations associated with this interface. | 788 | * Remove all stations associated with this interface. |