aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2013-06-04 13:21:08 -0400
committerJohannes Berg <johannes.berg@intel.com>2013-06-04 16:22:41 -0400
commit256c90dedf538c59c70e65ba1a1340ce793c5b37 (patch)
tree9b8e1290e91ee99bfc9edc88a5e7bcf500f64e70 /net/wireless
parent3430140ad9da9ec1caaf800af6b0378351919f9c (diff)
cfg80211: fix potential deadlock regression
My big locking cleanups caused a problem by registering the rfkill instance with the RTNL held, while the callback also acquires the RTNL. This potentially causes a deadlock since the two locks used (rfkill mutex and RTNL) can be acquired in two different orders. Fix this by (un)registering rfkill without holding the RTNL. This needs to be done after the device struct is registered, but that can also be done w/o holding the RTNL. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/wireless')
-rw-r--r--net/wireless/core.c23
1 files changed, 8 insertions, 15 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 221e76b53a97..99d86ddb6331 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -555,14 +555,18 @@ int wiphy_register(struct wiphy *wiphy)
555 /* check and set up bitrates */ 555 /* check and set up bitrates */
556 ieee80211_set_bitrate_flags(wiphy); 556 ieee80211_set_bitrate_flags(wiphy);
557 557
558 rtnl_lock();
559 558
560 res = device_add(&rdev->wiphy.dev); 559 res = device_add(&rdev->wiphy.dev);
560 if (res)
561 return res;
562
563 res = rfkill_register(rdev->rfkill);
561 if (res) { 564 if (res) {
562 rtnl_unlock(); 565 device_del(&rdev->wiphy.dev);
563 return res; 566 return res;
564 } 567 }
565 568
569 rtnl_lock();
566 /* set up regulatory info */ 570 /* set up regulatory info */
567 wiphy_regulatory_register(wiphy); 571 wiphy_regulatory_register(wiphy);
568 572
@@ -589,17 +593,6 @@ int wiphy_register(struct wiphy *wiphy)
589 593
590 cfg80211_debugfs_rdev_add(rdev); 594 cfg80211_debugfs_rdev_add(rdev);
591 595
592 res = rfkill_register(rdev->rfkill);
593 if (res) {
594 device_del(&rdev->wiphy.dev);
595
596 debugfs_remove_recursive(rdev->wiphy.debugfsdir);
597 list_del_rcu(&rdev->list);
598 wiphy_regulatory_deregister(wiphy);
599 rtnl_unlock();
600 return res;
601 }
602
603 rdev->wiphy.registered = true; 596 rdev->wiphy.registered = true;
604 rtnl_unlock(); 597 rtnl_unlock();
605 return 0; 598 return 0;
@@ -636,11 +629,11 @@ void wiphy_unregister(struct wiphy *wiphy)
636 rtnl_unlock(); 629 rtnl_unlock();
637 __count == 0; })); 630 __count == 0; }));
638 631
632 rfkill_unregister(rdev->rfkill);
633
639 rtnl_lock(); 634 rtnl_lock();
640 rdev->wiphy.registered = false; 635 rdev->wiphy.registered = false;
641 636
642 rfkill_unregister(rdev->rfkill);
643
644 BUG_ON(!list_empty(&rdev->wdev_list)); 637 BUG_ON(!list_empty(&rdev->wdev_list));
645 638
646 /* 639 /*