forked from mirrors/linux
		
	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
					
				
					 1 changed files with 78 additions and 30 deletions
				
			
		| 
						 | 
					@ -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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!tb)
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = nlmsg_parse_deprecated(cb->nlh,
 | 
				
			||||||
				     GENL_HDRLEN + nl80211_fam.hdrsize,
 | 
									     GENL_HDRLEN + nl80211_fam.hdrsize,
 | 
				
			||||||
				     tb, nl80211_fam.maxattr,
 | 
									     tb, nl80211_fam.maxattr,
 | 
				
			||||||
				     nl80211_policy, NULL);
 | 
									     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 a new issue