diff options
| author | Johannes Berg <johannes.berg@intel.com> | 2026-10-06 12:04:03 +0200 |
|---|---|---|
| committer | Johannes Berg <johannes.berg@intel.com> | 2026-10-09 16:12:46 +0200 |
| commit | 197d5f64e3bbb143d5fc27f4afbf772bfcd232de (patch) | |
| tree | a9d8d471ba4647368511e873ca46738b945d27d8 /net | |
| parent | 8e3d9039d280c61e1ef5c5cbe8ee8db342907173 (diff) | |
| download | linux-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.c | 63 |
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; } |
