cfg80211: use parallel_ops for genl
Over time, we really need to get rid of all of our global locking. One of the things needed is to use parallel_ops. This isn't really the most important (RTNL is much more important) but OTOH we just keep adding uses of genl_family_attrbuf() now. Use .parallel_ops to disallow this. Reviewed-By: Denis Kenzior <denkenz@gmail.com> Link: https://lore.kernel.org/r/20190729143109.18683-1-johannes@sipsolutions.net Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
05d610af3e
commit
50508d941c
@ -749,17 +749,25 @@ int nl80211_prepare_wdev_dump(struct netlink_callback *cb,
|
|||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (!cb->args[0]) {
|
if (!cb->args[0]) {
|
||||||
|
struct nlattr **attrbuf;
|
||||||
|
|
||||||
|
attrbuf = kcalloc(NUM_NL80211_ATTR, sizeof(*attrbuf),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!attrbuf)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
err = nlmsg_parse_deprecated(cb->nlh,
|
err = nlmsg_parse_deprecated(cb->nlh,
|
||||||
GENL_HDRLEN + nl80211_fam.hdrsize,
|
GENL_HDRLEN + nl80211_fam.hdrsize,
|
||||||
genl_family_attrbuf(&nl80211_fam),
|
attrbuf, nl80211_fam.maxattr,
|
||||||
nl80211_fam.maxattr,
|
|
||||||
nl80211_policy, NULL);
|
nl80211_policy, NULL);
|
||||||
if (err)
|
if (err) {
|
||||||
|
kfree(attrbuf);
|
||||||
return err;
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
*wdev = __cfg80211_wdev_from_attrs(
|
*wdev = __cfg80211_wdev_from_attrs(sock_net(cb->skb->sk),
|
||||||
sock_net(cb->skb->sk),
|
attrbuf);
|
||||||
genl_family_attrbuf(&nl80211_fam));
|
kfree(attrbuf);
|
||||||
if (IS_ERR(*wdev))
|
if (IS_ERR(*wdev))
|
||||||
return PTR_ERR(*wdev);
|
return PTR_ERR(*wdev);
|
||||||
*rdev = wiphy_to_rdev((*wdev)->wiphy);
|
*rdev = wiphy_to_rdev((*wdev)->wiphy);
|
||||||
@ -2390,14 +2398,21 @@ static int nl80211_dump_wiphy_parse(struct sk_buff *skb,
|
|||||||
struct netlink_callback *cb,
|
struct netlink_callback *cb,
|
||||||
struct nl80211_dump_wiphy_state *state)
|
struct nl80211_dump_wiphy_state *state)
|
||||||
{
|
{
|
||||||
struct nlattr **tb = genl_family_attrbuf(&nl80211_fam);
|
struct nlattr **tb = kcalloc(NUM_NL80211_ATTR, sizeof(*tb), GFP_KERNEL);
|
||||||
int ret = nlmsg_parse_deprecated(cb->nlh,
|
int ret;
|
||||||
GENL_HDRLEN + nl80211_fam.hdrsize,
|
|
||||||
tb, nl80211_fam.maxattr,
|
if (!tb)
|
||||||
nl80211_policy, NULL);
|
return -ENOMEM;
|
||||||
|
|
||||||
|
ret = nlmsg_parse_deprecated(cb->nlh,
|
||||||
|
GENL_HDRLEN + nl80211_fam.hdrsize,
|
||||||
|
tb, nl80211_fam.maxattr,
|
||||||
|
nl80211_policy, NULL);
|
||||||
/* ignore parse errors for backward compatibility */
|
/* ignore parse errors for backward compatibility */
|
||||||
if (ret)
|
if (ret) {
|
||||||
return 0;
|
ret = 0;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
state->split = tb[NL80211_ATTR_SPLIT_WIPHY_DUMP];
|
state->split = tb[NL80211_ATTR_SPLIT_WIPHY_DUMP];
|
||||||
if (tb[NL80211_ATTR_WIPHY])
|
if (tb[NL80211_ATTR_WIPHY])
|
||||||
@ -2410,8 +2425,10 @@ static int nl80211_dump_wiphy_parse(struct sk_buff *skb,
|
|||||||
int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
|
int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
|
||||||
|
|
||||||
netdev = __dev_get_by_index(sock_net(skb->sk), ifidx);
|
netdev = __dev_get_by_index(sock_net(skb->sk), ifidx);
|
||||||
if (!netdev)
|
if (!netdev) {
|
||||||
return -ENODEV;
|
ret = -ENODEV;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
if (netdev->ieee80211_ptr) {
|
if (netdev->ieee80211_ptr) {
|
||||||
rdev = wiphy_to_rdev(
|
rdev = wiphy_to_rdev(
|
||||||
netdev->ieee80211_ptr->wiphy);
|
netdev->ieee80211_ptr->wiphy);
|
||||||
@ -2419,7 +2436,10 @@ static int nl80211_dump_wiphy_parse(struct sk_buff *skb,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
ret = 0;
|
||||||
|
out:
|
||||||
|
kfree(tb);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
|
static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
|
||||||
@ -8724,7 +8744,7 @@ static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq,
|
|||||||
|
|
||||||
static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb)
|
static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb)
|
||||||
{
|
{
|
||||||
struct nlattr **attrbuf = genl_family_attrbuf(&nl80211_fam);
|
struct nlattr **attrbuf;
|
||||||
struct survey_info survey;
|
struct survey_info survey;
|
||||||
struct cfg80211_registered_device *rdev;
|
struct cfg80211_registered_device *rdev;
|
||||||
struct wireless_dev *wdev;
|
struct wireless_dev *wdev;
|
||||||
@ -8732,6 +8752,10 @@ static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb)
|
|||||||
int res;
|
int res;
|
||||||
bool radio_stats;
|
bool radio_stats;
|
||||||
|
|
||||||
|
attrbuf = kcalloc(NUM_NL80211_ATTR, sizeof(*attrbuf), GFP_KERNEL);
|
||||||
|
if (!attrbuf)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
rtnl_lock();
|
rtnl_lock();
|
||||||
res = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
|
res = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
|
||||||
if (res)
|
if (res)
|
||||||
@ -8776,6 +8800,7 @@ static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb)
|
|||||||
cb->args[2] = survey_idx;
|
cb->args[2] = survey_idx;
|
||||||
res = skb->len;
|
res = skb->len;
|
||||||
out_err:
|
out_err:
|
||||||
|
kfree(attrbuf);
|
||||||
rtnl_unlock();
|
rtnl_unlock();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -9635,6 +9660,7 @@ static int nl80211_testmode_dump(struct sk_buff *skb,
|
|||||||
struct netlink_callback *cb)
|
struct netlink_callback *cb)
|
||||||
{
|
{
|
||||||
struct cfg80211_registered_device *rdev;
|
struct cfg80211_registered_device *rdev;
|
||||||
|
struct nlattr **attrbuf = NULL;
|
||||||
int err;
|
int err;
|
||||||
long phy_idx;
|
long phy_idx;
|
||||||
void *data = NULL;
|
void *data = NULL;
|
||||||
@ -9655,7 +9681,12 @@ static int nl80211_testmode_dump(struct sk_buff *skb,
|
|||||||
goto out_err;
|
goto out_err;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
struct nlattr **attrbuf = genl_family_attrbuf(&nl80211_fam);
|
attrbuf = kcalloc(NUM_NL80211_ATTR, sizeof(*attrbuf),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!attrbuf) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto out_err;
|
||||||
|
}
|
||||||
|
|
||||||
err = nlmsg_parse_deprecated(cb->nlh,
|
err = nlmsg_parse_deprecated(cb->nlh,
|
||||||
GENL_HDRLEN + nl80211_fam.hdrsize,
|
GENL_HDRLEN + nl80211_fam.hdrsize,
|
||||||
@ -9722,6 +9753,7 @@ static int nl80211_testmode_dump(struct sk_buff *skb,
|
|||||||
/* see above */
|
/* see above */
|
||||||
cb->args[0] = phy_idx + 1;
|
cb->args[0] = phy_idx + 1;
|
||||||
out_err:
|
out_err:
|
||||||
|
kfree(attrbuf);
|
||||||
rtnl_unlock();
|
rtnl_unlock();
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -12815,7 +12847,7 @@ static int nl80211_prepare_vendor_dump(struct sk_buff *skb,
|
|||||||
struct cfg80211_registered_device **rdev,
|
struct cfg80211_registered_device **rdev,
|
||||||
struct wireless_dev **wdev)
|
struct wireless_dev **wdev)
|
||||||
{
|
{
|
||||||
struct nlattr **attrbuf = genl_family_attrbuf(&nl80211_fam);
|
struct nlattr **attrbuf;
|
||||||
u32 vid, subcmd;
|
u32 vid, subcmd;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
int vcmd_idx = -1;
|
int vcmd_idx = -1;
|
||||||
@ -12846,24 +12878,32 @@ static int nl80211_prepare_vendor_dump(struct sk_buff *skb,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
attrbuf = kcalloc(NUM_NL80211_ATTR, sizeof(*attrbuf), GFP_KERNEL);
|
||||||
|
if (!attrbuf)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
err = nlmsg_parse_deprecated(cb->nlh,
|
err = nlmsg_parse_deprecated(cb->nlh,
|
||||||
GENL_HDRLEN + nl80211_fam.hdrsize,
|
GENL_HDRLEN + nl80211_fam.hdrsize,
|
||||||
attrbuf, nl80211_fam.maxattr,
|
attrbuf, nl80211_fam.maxattr,
|
||||||
nl80211_policy, NULL);
|
nl80211_policy, NULL);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
goto out;
|
||||||
|
|
||||||
if (!attrbuf[NL80211_ATTR_VENDOR_ID] ||
|
if (!attrbuf[NL80211_ATTR_VENDOR_ID] ||
|
||||||
!attrbuf[NL80211_ATTR_VENDOR_SUBCMD])
|
!attrbuf[NL80211_ATTR_VENDOR_SUBCMD]) {
|
||||||
return -EINVAL;
|
err = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
*wdev = __cfg80211_wdev_from_attrs(sock_net(skb->sk), attrbuf);
|
*wdev = __cfg80211_wdev_from_attrs(sock_net(skb->sk), attrbuf);
|
||||||
if (IS_ERR(*wdev))
|
if (IS_ERR(*wdev))
|
||||||
*wdev = NULL;
|
*wdev = NULL;
|
||||||
|
|
||||||
*rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk), attrbuf);
|
*rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk), attrbuf);
|
||||||
if (IS_ERR(*rdev))
|
if (IS_ERR(*rdev)) {
|
||||||
return PTR_ERR(*rdev);
|
err = PTR_ERR(*rdev);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
vid = nla_get_u32(attrbuf[NL80211_ATTR_VENDOR_ID]);
|
vid = nla_get_u32(attrbuf[NL80211_ATTR_VENDOR_ID]);
|
||||||
subcmd = nla_get_u32(attrbuf[NL80211_ATTR_VENDOR_SUBCMD]);
|
subcmd = nla_get_u32(attrbuf[NL80211_ATTR_VENDOR_SUBCMD]);
|
||||||
@ -12876,15 +12916,19 @@ static int nl80211_prepare_vendor_dump(struct sk_buff *skb,
|
|||||||
if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd)
|
if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!vcmd->dumpit)
|
if (!vcmd->dumpit) {
|
||||||
return -EOPNOTSUPP;
|
err = -EOPNOTSUPP;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
vcmd_idx = i;
|
vcmd_idx = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vcmd_idx < 0)
|
if (vcmd_idx < 0) {
|
||||||
return -EOPNOTSUPP;
|
err = -EOPNOTSUPP;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (attrbuf[NL80211_ATTR_VENDOR_DATA]) {
|
if (attrbuf[NL80211_ATTR_VENDOR_DATA]) {
|
||||||
data = nla_data(attrbuf[NL80211_ATTR_VENDOR_DATA]);
|
data = nla_data(attrbuf[NL80211_ATTR_VENDOR_DATA]);
|
||||||
@ -12895,7 +12939,7 @@ static int nl80211_prepare_vendor_dump(struct sk_buff *skb,
|
|||||||
attrbuf[NL80211_ATTR_VENDOR_DATA],
|
attrbuf[NL80211_ATTR_VENDOR_DATA],
|
||||||
cb->extack);
|
cb->extack);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 0 is the first index - add 1 to parse only once */
|
/* 0 is the first index - add 1 to parse only once */
|
||||||
@ -12907,7 +12951,10 @@ static int nl80211_prepare_vendor_dump(struct sk_buff *skb,
|
|||||||
cb->args[4] = data_len;
|
cb->args[4] = data_len;
|
||||||
|
|
||||||
/* keep rtnl locked in successful case */
|
/* keep rtnl locked in successful case */
|
||||||
return 0;
|
err = 0;
|
||||||
|
out:
|
||||||
|
kfree(attrbuf);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nl80211_vendor_cmd_dump(struct sk_buff *skb,
|
static int nl80211_vendor_cmd_dump(struct sk_buff *skb,
|
||||||
@ -14585,6 +14632,7 @@ static struct genl_family nl80211_fam __ro_after_init = {
|
|||||||
.n_ops = ARRAY_SIZE(nl80211_ops),
|
.n_ops = ARRAY_SIZE(nl80211_ops),
|
||||||
.mcgrps = nl80211_mcgrps,
|
.mcgrps = nl80211_mcgrps,
|
||||||
.n_mcgrps = ARRAY_SIZE(nl80211_mcgrps),
|
.n_mcgrps = ARRAY_SIZE(nl80211_mcgrps),
|
||||||
|
.parallel_ops = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* notification functions */
|
/* notification functions */
|
||||||
|
Loading…
Reference in New Issue
Block a user