summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2026-10-06 12:04:03 +0200
committerJohannes Berg <johannes.berg@intel.com>2026-10-09 16:12:46 +0200
commit197d5f64e3bbb143d5fc27f4afbf772bfcd232de (patch)
treea9d8d471ba4647368511e873ca46738b945d27d8 /net
parent8e3d9039d280c61e1ef5c5cbe8ee8db342907173 (diff)
downloadlinux-next-197d5f64e3bbb143d5fc27f4afbf772bfcd232de.tar.gz
linux-next-197d5f64e3bbb143d5fc27f4afbf772bfcd232de.zip
wifi: nl80211: don't take rtnl for most dumps
Most (wdev-related) dumps also take RTNL just for lookup. Apply the same logic as for pre_doit() in the previous commit to avoid the RTNL. Since I refactored the checks there into a helper to use here, it even simplifies the code. Link: https://patch.msgid.link/20261006120655.37954ad94c77.Ica4719b0054c949abf2528d9c4c13a5d6b7a1a49@changeid Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net')
-rw-r--r--net/wireless/nl80211.c63
1 files changed, 21 insertions, 42 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index ee18100de8f8..70fa69a9115d 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1304,6 +1304,8 @@ static int nl80211_prepare_wdev_dump(struct netlink_callback *cb,
struct wireless_dev **wdev,
struct nlattr **attrbuf)
{
+ struct net *netns = sock_net(cb->skb->sk);
+ u32 wdev_id;
int err;
if (!cb->args[0]) {
@@ -1325,60 +1327,37 @@ static int nl80211_prepare_wdev_dump(struct netlink_callback *cb,
return err;
}
- rtnl_lock();
- *wdev = __cfg80211_wdev_from_attrs(NULL, sock_net(cb->skb->sk),
- attrbuf);
+ rcu_read_lock();
+ *wdev = __cfg80211_wdev_from_attrs(NULL, netns, attrbuf);
kfree(attrbuf_free);
if (IS_ERR(*wdev)) {
- rtnl_unlock();
+ rcu_read_unlock();
return PTR_ERR(*wdev);
}
*rdev = wiphy_to_rdev((*wdev)->wiphy);
- mutex_lock(&(*rdev)->wiphy.mtx);
- rtnl_unlock();
- /* 0 is the first index - add 1 to parse only once */
- cb->args[0] = (*rdev)->wiphy_idx + 1;
- cb->args[1] = (*wdev)->identifier;
+ wdev_id = (*wdev)->identifier;
} else {
/* subtract the 1 again here */
- struct wiphy *wiphy;
- struct wireless_dev *tmp;
-
- rtnl_lock();
- wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1);
- if (!wiphy) {
- rtnl_unlock();
- return -ENODEV;
- }
-
- /*
- * The first invocation validated the wdev's netns against
- * the caller via __cfg80211_wdev_from_attrs(). The wiphy
- * may have moved netns between dumpit invocations (via
- * NL80211_CMD_SET_WIPHY_NETNS), so re-check here.
- */
- if (!net_eq(wiphy_net(wiphy), sock_net(cb->skb->sk))) {
- rtnl_unlock();
+ rcu_read_lock();
+ *rdev = cfg80211_rdev_by_wiphy_idx(cb->args[0] - 1);
+ if (!*rdev) {
+ rcu_read_unlock();
return -ENODEV;
}
+ wdev_id = cb->args[1];
+ }
- *rdev = wiphy_to_rdev(wiphy);
- *wdev = NULL;
+ get_device(&(*rdev)->wiphy.dev);
+ rcu_read_unlock();
- list_for_each_entry(tmp, &(*rdev)->wiphy.wdev_list, list) {
- if (tmp->identifier == cb->args[1]) {
- *wdev = tmp;
- break;
- }
- }
+ /* things may have changed since the lookup or the last dumpit call */
+ *wdev = nl80211_lock_and_recheck(*rdev, netns, wdev_id);
+ if (IS_ERR(*wdev))
+ return PTR_ERR(*wdev);
- if (!*wdev) {
- rtnl_unlock();
- return -ENODEV;
- }
- mutex_lock(&(*rdev)->wiphy.mtx);
- rtnl_unlock();
- }
+ /* 0 is the first index - add 1 to parse only once */
+ cb->args[0] = (*rdev)->wiphy_idx + 1;
+ cb->args[1] = wdev_id;
return 0;
}