Skip to content

Commit

Permalink
cfg80211: use parallel_ops for genl
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Johannes Berg committed Jul 31, 2019
1 parent 05d610a commit 50508d9
Showing 1 changed file with 78 additions and 30 deletions.
108 changes: 78 additions & 30 deletions net/wireless/nl80211.c
Original file line number Diff line number Diff line change
Expand Up @@ -749,17 +749,25 @@ int nl80211_prepare_wdev_dump(struct netlink_callback *cb,
int err;

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,
GENL_HDRLEN + nl80211_fam.hdrsize,
genl_family_attrbuf(&nl80211_fam),
nl80211_fam.maxattr,
attrbuf, nl80211_fam.maxattr,
nl80211_policy, NULL);
if (err)
if (err) {
kfree(attrbuf);
return err;
}

*wdev = __cfg80211_wdev_from_attrs(
sock_net(cb->skb->sk),
genl_family_attrbuf(&nl80211_fam));
*wdev = __cfg80211_wdev_from_attrs(sock_net(cb->skb->sk),
attrbuf);
kfree(attrbuf);
if (IS_ERR(*wdev))
return PTR_ERR(*wdev);
*rdev = wiphy_to_rdev((*wdev)->wiphy);
Expand Down Expand Up @@ -2390,14 +2398,21 @@ static int nl80211_dump_wiphy_parse(struct sk_buff *skb,
struct netlink_callback *cb,
struct nl80211_dump_wiphy_state *state)
{
struct nlattr **tb = genl_family_attrbuf(&nl80211_fam);
int ret = nlmsg_parse_deprecated(cb->nlh,
GENL_HDRLEN + nl80211_fam.hdrsize,
tb, nl80211_fam.maxattr,
nl80211_policy, NULL);
struct nlattr **tb = kcalloc(NUM_NL80211_ATTR, sizeof(*tb), GFP_KERNEL);
int ret;

if (!tb)
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 */
if (ret)
return 0;
if (ret) {
ret = 0;
goto out;
}

state->split = tb[NL80211_ATTR_SPLIT_WIPHY_DUMP];
if (tb[NL80211_ATTR_WIPHY])
Expand All @@ -2410,16 +2425,21 @@ static int nl80211_dump_wiphy_parse(struct sk_buff *skb,
int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);

netdev = __dev_get_by_index(sock_net(skb->sk), ifidx);
if (!netdev)
return -ENODEV;
if (!netdev) {
ret = -ENODEV;
goto out;
}
if (netdev->ieee80211_ptr) {
rdev = wiphy_to_rdev(
netdev->ieee80211_ptr->wiphy);
state->filter_wiphy = rdev->wiphy_idx;
}
}

return 0;
ret = 0;
out:
kfree(tb);
return ret;
}

static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
Expand Down Expand Up @@ -8724,14 +8744,18 @@ 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)
{
struct nlattr **attrbuf = genl_family_attrbuf(&nl80211_fam);
struct nlattr **attrbuf;
struct survey_info survey;
struct cfg80211_registered_device *rdev;
struct wireless_dev *wdev;
int survey_idx = cb->args[2];
int res;
bool radio_stats;

attrbuf = kcalloc(NUM_NL80211_ATTR, sizeof(*attrbuf), GFP_KERNEL);
if (!attrbuf)
return -ENOMEM;

rtnl_lock();
res = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
if (res)
Expand Down Expand Up @@ -8776,6 +8800,7 @@ static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb)
cb->args[2] = survey_idx;
res = skb->len;
out_err:
kfree(attrbuf);
rtnl_unlock();
return res;
}
Expand Down Expand Up @@ -9635,6 +9660,7 @@ static int nl80211_testmode_dump(struct sk_buff *skb,
struct netlink_callback *cb)
{
struct cfg80211_registered_device *rdev;
struct nlattr **attrbuf = NULL;
int err;
long phy_idx;
void *data = NULL;
Expand All @@ -9655,7 +9681,12 @@ static int nl80211_testmode_dump(struct sk_buff *skb,
goto out_err;
}
} 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,
GENL_HDRLEN + nl80211_fam.hdrsize,
Expand Down Expand Up @@ -9722,6 +9753,7 @@ static int nl80211_testmode_dump(struct sk_buff *skb,
/* see above */
cb->args[0] = phy_idx + 1;
out_err:
kfree(attrbuf);
rtnl_unlock();
return err;
}
Expand Down Expand Up @@ -12815,7 +12847,7 @@ static int nl80211_prepare_vendor_dump(struct sk_buff *skb,
struct cfg80211_registered_device **rdev,
struct wireless_dev **wdev)
{
struct nlattr **attrbuf = genl_family_attrbuf(&nl80211_fam);
struct nlattr **attrbuf;
u32 vid, subcmd;
unsigned int i;
int vcmd_idx = -1;
Expand Down Expand Up @@ -12846,24 +12878,32 @@ static int nl80211_prepare_vendor_dump(struct sk_buff *skb,
return 0;
}

attrbuf = kcalloc(NUM_NL80211_ATTR, sizeof(*attrbuf), GFP_KERNEL);
if (!attrbuf)
return -ENOMEM;

err = nlmsg_parse_deprecated(cb->nlh,
GENL_HDRLEN + nl80211_fam.hdrsize,
attrbuf, nl80211_fam.maxattr,
nl80211_policy, NULL);
if (err)
return err;
goto out;

if (!attrbuf[NL80211_ATTR_VENDOR_ID] ||
!attrbuf[NL80211_ATTR_VENDOR_SUBCMD])
return -EINVAL;
!attrbuf[NL80211_ATTR_VENDOR_SUBCMD]) {
err = -EINVAL;
goto out;
}

*wdev = __cfg80211_wdev_from_attrs(sock_net(skb->sk), attrbuf);
if (IS_ERR(*wdev))
*wdev = NULL;

*rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk), attrbuf);
if (IS_ERR(*rdev))
return PTR_ERR(*rdev);
if (IS_ERR(*rdev)) {
err = PTR_ERR(*rdev);
goto out;
}

vid = nla_get_u32(attrbuf[NL80211_ATTR_VENDOR_ID]);
subcmd = nla_get_u32(attrbuf[NL80211_ATTR_VENDOR_SUBCMD]);
Expand All @@ -12876,15 +12916,19 @@ static int nl80211_prepare_vendor_dump(struct sk_buff *skb,
if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd)
continue;

if (!vcmd->dumpit)
return -EOPNOTSUPP;
if (!vcmd->dumpit) {
err = -EOPNOTSUPP;
goto out;
}

vcmd_idx = i;
break;
}

if (vcmd_idx < 0)
return -EOPNOTSUPP;
if (vcmd_idx < 0) {
err = -EOPNOTSUPP;
goto out;
}

if (attrbuf[NL80211_ATTR_VENDOR_DATA]) {
data = nla_data(attrbuf[NL80211_ATTR_VENDOR_DATA]);
Expand All @@ -12895,7 +12939,7 @@ static int nl80211_prepare_vendor_dump(struct sk_buff *skb,
attrbuf[NL80211_ATTR_VENDOR_DATA],
cb->extack);
if (err)
return err;
goto out;
}

/* 0 is the first index - add 1 to parse only once */
Expand All @@ -12907,7 +12951,10 @@ static int nl80211_prepare_vendor_dump(struct sk_buff *skb,
cb->args[4] = data_len;

/* 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,
Expand Down Expand Up @@ -14585,6 +14632,7 @@ static struct genl_family nl80211_fam __ro_after_init = {
.n_ops = ARRAY_SIZE(nl80211_ops),
.mcgrps = nl80211_mcgrps,
.n_mcgrps = ARRAY_SIZE(nl80211_mcgrps),
.parallel_ops = true,
};

/* notification functions */
Expand Down

0 comments on commit 50508d9

Please sign in to comment.