Commit a05829a7 authored by Johannes Berg's avatar Johannes Berg
Browse files

cfg80211: avoid holding the RTNL when calling the driver

Currently, _everything_ in cfg80211 holds the RTNL, and if you
have a slow USB device (or a few) you can get some bad lock
contention on that.

Fix that by re-adding a mutex to each wiphy/rdev as we had at
some point, so we have locking for the wireless_dev lists and
all the other things in there, and also so that drivers still
don't have to worry too much about it (they still won't get
parallel calls for a single device).

Then, we can restrict the RTNL to a few cases where we add or
remove interfaces and really need the added protection. Some
of the global list management still also uses the RTNL, since
we need to have it anyway for netdev management, but we only
hold the RTNL for very short periods of time here.

Link: https://lore.kernel.org/r/20210122161942.81df9f5e047a.I4a8e1a60b18863ea8c5e6d3a0faeafb2d45b2f40@changeid


Tested-by: Marek Szyprowski <m.szyprowski@samsung.com> [marvell driver issues]
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 2fe8ef10
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -247,7 +247,9 @@ int ath11k_regd_update(struct ath11k *ar, bool init)
	}

	rtnl_lock();
	ret = regulatory_set_wiphy_regd_sync_rtnl(ar->hw->wiphy, regd_copy);
	wiphy_lock(ar->hw->wiphy);
	ret = regulatory_set_wiphy_regd_sync(ar->hw->wiphy, regd_copy);
	wiphy_unlock(ar->hw->wiphy);
	rtnl_unlock();

	kfree(regd_copy);
+2 −0
Original line number Diff line number Diff line
@@ -212,11 +212,13 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type)
		ar->avail_idx_map |= BIT(i);

	rtnl_lock();
	wiphy_lock(ar->wiphy);

	/* Add an initial station interface */
	wdev = ath6kl_interface_add(ar, "wlan%d", NET_NAME_ENUM,
				    NL80211_IFTYPE_STATION, 0, INFRA_NETWORK);

	wiphy_unlock(ar->wiphy);
	rtnl_unlock();

	if (!wdev) {
+2 −0
Original line number Diff line number Diff line
@@ -1904,7 +1904,9 @@ void ath6kl_stop_txrx(struct ath6kl *ar)
		spin_unlock_bh(&ar->list_lock);
		ath6kl_cfg80211_vif_stop(vif, test_bit(WMI_READY, &ar->flag));
		rtnl_lock();
		wiphy_lock(ar->wiphy);
		ath6kl_cfg80211_vif_cleanup(vif);
		wiphy_unlock(ar->wiphy);
		rtnl_unlock();
		spin_lock_bh(&ar->list_lock);
	}
+2 −0
Original line number Diff line number Diff line
@@ -2820,7 +2820,9 @@ void wil_p2p_wdev_free(struct wil6210_priv *wil)
	wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
	mutex_unlock(&wil->vif_mutex);
	if (p2p_wdev) {
		wiphy_lock(wil->wiphy);
		cfg80211_unregister_wdev(p2p_wdev);
		wiphy_unlock(wil->wiphy);
		kfree(p2p_wdev);
	}
}
+6 −1
Original line number Diff line number Diff line
@@ -473,7 +473,9 @@ int wil_if_add(struct wil6210_priv *wil)
	wil_update_net_queues_bh(wil, vif, NULL, true);

	rtnl_lock();
	wiphy_lock(wiphy);
	rc = wil_vif_add(wil, vif);
	wiphy_unlock(wiphy);
	rtnl_unlock();
	if (rc < 0)
		goto out_wiphy;
@@ -543,15 +545,18 @@ void wil_if_remove(struct wil6210_priv *wil)
{
	struct net_device *ndev = wil->main_ndev;
	struct wireless_dev *wdev = ndev->ieee80211_ptr;
	struct wiphy *wiphy = wdev->wiphy;

	wil_dbg_misc(wil, "if_remove\n");

	rtnl_lock();
	wiphy_lock(wiphy);
	wil_vif_remove(wil, 0);
	wiphy_unlock(wiphy);
	rtnl_unlock();

	netif_napi_del(&wil->napi_tx);
	netif_napi_del(&wil->napi_rx);

	wiphy_unregister(wdev->wiphy);
	wiphy_unregister(wiphy);
}
Loading