Message ID | 20241024131807.0a6c07355832.I3df6aac71d38a5baa1c0a03d0c7e82d4395c030e@changeid |
---|---|
State | New |
Headers | show |
Series | [RFC,1/2] net: netlink: add nla_get_*_default() accessors | expand |
On Thu, 2024-10-24 at 13:18 +0200, Johannes Berg wrote: > > +MAKE_NLA_GET_DEFAULT(u8, nla_get_u8); > +MAKE_NLA_GET_DEFAULT(u16, nla_get_u16); > +MAKE_NLA_GET_DEFAULT(u32, nla_get_u32); > +MAKE_NLA_GET_DEFAULT(u64, nla_get_u64); > +MAKE_NLA_GET_DEFAULT(unsigned long, nla_get_msecs); > +MAKE_NLA_GET_DEFAULT(s8, nla_get_s8); > +MAKE_NLA_GET_DEFAULT(s16, nla_get_s16); > +MAKE_NLA_GET_DEFAULT(s32, nla_get_s32); > +MAKE_NLA_GET_DEFAULT(s64, nla_get_s64); > +MAKE_NLA_GET_DEFAULT(s16, nla_get_le16); > +MAKE_NLA_GET_DEFAULT(s32, nla_get_le32); > +MAKE_NLA_GET_DEFAULT(s64, nla_get_le64); > +MAKE_NLA_GET_DEFAULT(s16, nla_get_be16); > +MAKE_NLA_GET_DEFAULT(s32, nla_get_be32); > +MAKE_NLA_GET_DEFAULT(s64, nla_get_be64); > I obviously messed that up completely, but you get the point ... johannes
On Thu, 2024-10-24 at 13:18 +0200, Johannes Berg wrote: > From: Johannes Berg <johannes.berg@intel.com> > > This is mostly to illustrate, done with the following spatch: > And we can extend that and get bunch more: @@ expression attr, def; expression val; identifier fn =~ "^nla_get_.*"; fresh identifier dfn = fn ## "_default"; @@ ( -if (attr) - val = fn(attr); -else - val = def; +val = dfn(attr, def); | -if (!attr) - val = def; -else - val = fn(attr); +val = dfn(attr, def); | -val = def; ... where != val; -if (attr) - val = fn(attr); +val = dfn(attr, def); | -if (!attr) - return def; -return fn(attr); +return dfn(attr, def); ) (also just running it multiple times finds more instances?!) johannes
Also just realized that some of the conversions are wrong, e.g. > @@ -7378,17 +7375,11 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) > if (info->attrs[NL80211_ATTR_VLAN_ID]) > params.vlan_id = nla_get_u16(info->attrs[NL80211_ATTR_VLAN_ID]); > > - if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]) > - params.listen_interval = > - nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); > - else > - params.listen_interval = -1; > + params.listen_interval = nla_get_u16_default(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL], > + -1); this one clearly is. So need to be more careful with that :) But at least the spatch gives some candidates. johannes
2024-10-24, 14:11:05 +0200, Johannes Berg wrote: > On Thu, 2024-10-24 at 13:18 +0200, Johannes Berg wrote: > > From: Johannes Berg <johannes.berg@intel.com> > > > > This is mostly to illustrate, done with the following spatch: > > > > And we can extend that and get bunch more: > > @@ > expression attr, def; > expression val; > identifier fn =~ "^nla_get_.*"; > fresh identifier dfn = fn ## "_default"; > @@ > ( > -if (attr) > - val = fn(attr); > -else > - val = def; > +val = dfn(attr, def); > | > -if (!attr) > - val = def; > -else > - val = fn(attr); > +val = dfn(attr, def); > | > -val = def; > ... where != val; > -if (attr) > - val = fn(attr); > +val = dfn(attr, def); > | > -if (!attr) > - return def; > -return fn(attr); > +return dfn(attr, def); > ) Not really familiar with spatch, but I'm guessing this won't cover: val = attr ? getter(attr) : default; See macsec_validate_attr in drivers/net/macsec.c for some examples. There are also some cases where we have "if (data && data[IFLA_MACSEC_*])" guarding the attribute fetch (drivers/net/macvlan.c does that too), but I guess you can't really cover that without adding some kind of "default_with_cond" helpers.
On Thu, 2024-10-24 at 16:31 +0200, Johannes Berg wrote: > On Thu, 2024-10-24 at 16:28 +0200, Sabrina Dubroca wrote: > > > > > > Not really familiar with spatch, but I'm guessing this won't cover: > > val = attr ? getter(attr) : default; > > True, we could add > > -val = attr ? fn(attr) : def; > +val = dfn(attr); > There are about 50 of those :) thanks! johannes
On Thu, 2024-10-24 at 16:48 +0200, Sabrina Dubroca wrote: > > If nla_get_*_default was a macro (generating an "attr ? getter : > default" expression) you wouldn't have that problem I think, Hmm. Perhaps. In the conditional operator (?:) they're subject to integer promotion though, I wonder if that could cause some subtle issue too especially if nla_get_u*() is used with signed variables? > but you > couldn't nicely generate all the helpers with MAKE_NLA_GET_DEFAULT > anymore. Right, that too. I think it's probably better to just review them, and only commit the obvious ones originally? johannes
On Thu, 2024-10-24 at 17:17 +0200, Sabrina Dubroca wrote: > 2024-10-24, 16:52:00 +0200, Johannes Berg wrote: > > On Thu, 2024-10-24 at 16:48 +0200, Sabrina Dubroca wrote: > > > > > > If nla_get_*_default was a macro (generating an "attr ? getter : > > > default" expression) you wouldn't have that problem I think, > > > > Hmm. Perhaps. In the conditional operator (?:) they're subject to > > integer promotion though > > Is it? > > #define nla_get_u16_default(attr, d) (attr ? nla_get_u16(attr) : d) > int v = nla_get_u16_default(NULL, -1); > > seems to put the correct value into v. > (but -ENOFOOD and -ELOWCOFFEE here, so I don't trust this quick test > much :)) I'm probably -ELOWBLOODSUGAR right now ;-) But yeah, I couldn't yet construct a scenario where it mattered, but I' also couldn't convince myself that there isn't one. Maybe too much inspired by the enum compare warnings: https://lore.kernel.org/linux-wireless/20241018151841.3821671-1-arnd@kernel.org/ > > , I wonder if that could cause some subtle issue > > too especially if nla_get_u*() is used with signed variables? > > The issue in that example is pretty subtle and I'm fairly sure people > are going to mess up :/ I didn't think it was that bad, but it's well possible that my calibration for "subtle" is way off ;-) > But I'm not attached to that macro I just suggested, it's just a > thought. Sure. > > > but you > > > couldn't nicely generate all the helpers with MAKE_NLA_GET_DEFAULT > > > anymore. > > > > Right, that too. > > > > I think it's probably better to just review them, and only commit the > > obvious ones originally? > > Well, this one looked reasonable too. I'm not convinced reviewers are > going to catch those problems. Or authors of new code using those > _default helpers from the start. Fair point. I didn't think it was that bad, in fact there were some I was far less sure about, say > + request->page = nla_get_u8_default(info->attrs[NL802154_ATTR_PAGE], > + wpan_phy->current_page); which really depends on the types of 'page' and 'current_page'... I think for most cases it's probably still worth doing, and I wouldn't be _too_ concerned about the type issues here, most places are just using zero or a small constant as the default anyway. Even nla_get_XX_or_zero() would be a win, but that seemed too special ... johannes
diff --git a/include/net/netlink.h b/include/net/netlink.h index db6af207287c..b15bd0437945 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h @@ -142,6 +142,8 @@ * nla_get_flag(nla) return 1 if flag is true * nla_get_msecs(nla) get payload for a msecs attribute * + * The same functions also exist with _default(). + * * Attribute Misc: * nla_memcpy(dest, nla, count) copy attribute into memory * nla_memcmp(nla, data, size) compare attribute with memory area @@ -1867,6 +1869,31 @@ static inline unsigned long nla_get_msecs(const struct nlattr *nla) return msecs_to_jiffies((unsigned long) msecs); } +#define MAKE_NLA_GET_DEFAULT(tp, fn) \ +static inline tp fn##_default(const struct nlattr *nla, \ + tp defvalue) \ +{ \ + if (!nla) \ + return defvalue; \ + return n(nla); \ +} + +MAKE_NLA_GET_DEFAULT(u8, nla_get_u8); +MAKE_NLA_GET_DEFAULT(u16, nla_get_u16); +MAKE_NLA_GET_DEFAULT(u32, nla_get_u32); +MAKE_NLA_GET_DEFAULT(u64, nla_get_u64); +MAKE_NLA_GET_DEFAULT(unsigned long, nla_get_msecs); +MAKE_NLA_GET_DEFAULT(s8, nla_get_s8); +MAKE_NLA_GET_DEFAULT(s16, nla_get_s16); +MAKE_NLA_GET_DEFAULT(s32, nla_get_s32); +MAKE_NLA_GET_DEFAULT(s64, nla_get_s64); +MAKE_NLA_GET_DEFAULT(s16, nla_get_le16); +MAKE_NLA_GET_DEFAULT(s32, nla_get_le32); +MAKE_NLA_GET_DEFAULT(s64, nla_get_le64); +MAKE_NLA_GET_DEFAULT(s16, nla_get_be16); +MAKE_NLA_GET_DEFAULT(s32, nla_get_be32); +MAKE_NLA_GET_DEFAULT(s64, nla_get_be64); + /** * nla_get_in_addr - return payload of IPv4 address attribute * @nla: IPv4 address netlink attribute