forked from Minki/linux
nl80211: use RCU to read regdom in reg get/dump
Use RCU here to read the regdomain, this will allow us to remove the RTNL locking from the setter. Note in nl80211_get_reg_do() we still need the RTNL to do the wiphy lookup. Link: https://lore.kernel.org/r/20220214101820.5d4acbcf2a46.Ibfc91980439862125e983d9adeebaba73fe38e2d@changeid Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
b59fb54611
commit
024fcf5efd
@ -7948,6 +7948,7 @@ static int nl80211_get_reg_do(struct sk_buff *skb, struct genl_info *info)
|
||||
struct cfg80211_registered_device *rdev;
|
||||
struct wiphy *wiphy = NULL;
|
||||
struct sk_buff *msg;
|
||||
int err = -EMSGSIZE;
|
||||
void *hdr;
|
||||
|
||||
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
||||
@ -7966,34 +7967,35 @@ static int nl80211_get_reg_do(struct sk_buff *skb, struct genl_info *info)
|
||||
|
||||
rdev = cfg80211_get_dev_from_info(genl_info_net(info), info);
|
||||
if (IS_ERR(rdev)) {
|
||||
nlmsg_free(msg);
|
||||
rtnl_unlock();
|
||||
return PTR_ERR(rdev);
|
||||
err = PTR_ERR(rdev);
|
||||
goto nla_put_failure;
|
||||
}
|
||||
|
||||
wiphy = &rdev->wiphy;
|
||||
self_managed = wiphy->regulatory_flags &
|
||||
REGULATORY_WIPHY_SELF_MANAGED;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
regdom = get_wiphy_regdom(wiphy);
|
||||
|
||||
/* a self-managed-reg device must have a private regdom */
|
||||
if (WARN_ON(!regdom && self_managed)) {
|
||||
nlmsg_free(msg);
|
||||
rtnl_unlock();
|
||||
return -EINVAL;
|
||||
err = -EINVAL;
|
||||
goto nla_put_failure_rcu;
|
||||
}
|
||||
|
||||
if (regdom &&
|
||||
nla_put_u32(msg, NL80211_ATTR_WIPHY, get_wiphy_idx(wiphy)))
|
||||
goto nla_put_failure;
|
||||
goto nla_put_failure_rcu;
|
||||
} else {
|
||||
rcu_read_lock();
|
||||
}
|
||||
|
||||
if (!wiphy && reg_last_request_cell_base() &&
|
||||
nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE,
|
||||
NL80211_USER_REG_HINT_CELL_BASE))
|
||||
goto nla_put_failure;
|
||||
|
||||
rcu_read_lock();
|
||||
goto nla_put_failure_rcu;
|
||||
|
||||
if (!regdom)
|
||||
regdom = rcu_dereference(cfg80211_regdomain);
|
||||
@ -8013,7 +8015,7 @@ nla_put_failure:
|
||||
rtnl_unlock();
|
||||
put_failure:
|
||||
nlmsg_free(msg);
|
||||
return -EMSGSIZE;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int nl80211_send_regdom(struct sk_buff *msg, struct netlink_callback *cb,
|
||||
@ -8059,19 +8061,19 @@ static int nl80211_get_reg_dump(struct sk_buff *skb,
|
||||
struct cfg80211_registered_device *rdev;
|
||||
int err, reg_idx, start = cb->args[2];
|
||||
|
||||
rtnl_lock();
|
||||
rcu_read_lock();
|
||||
|
||||
if (cfg80211_regdomain && start == 0) {
|
||||
err = nl80211_send_regdom(skb, cb, cb->nlh->nlmsg_seq,
|
||||
NLM_F_MULTI, NULL,
|
||||
rtnl_dereference(cfg80211_regdomain));
|
||||
rcu_dereference(cfg80211_regdomain));
|
||||
if (err < 0)
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/* the global regdom is idx 0 */
|
||||
reg_idx = 1;
|
||||
list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
|
||||
list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) {
|
||||
regdom = get_wiphy_regdom(&rdev->wiphy);
|
||||
if (!regdom)
|
||||
continue;
|
||||
@ -8090,7 +8092,7 @@ static int nl80211_get_reg_dump(struct sk_buff *skb,
|
||||
cb->args[2] = reg_idx;
|
||||
err = skb->len;
|
||||
out_err:
|
||||
rtnl_unlock();
|
||||
rcu_read_unlock();
|
||||
return err;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user