@@ -3536,7 +3536,7 @@ static netdev_features_t gso_features_check(const struct sk_buff *skb,
netdev_features_t netif_skb_features(struct sk_buff *skb)
{
struct net_device *dev = skb->dev;
- netdev_features_t features = dev->features;
+ netdev_features_t features = READ_ONCE(dev->features);
if (skb_is_gso(skb))
features = gso_features_check(skb, dev, features);
@@ -10016,7 +10016,7 @@ int __netdev_update_features(struct net_device *dev)
* but *after* calling udp_tunnel_drop_rx_info.
*/
if (features & NETIF_F_RX_UDP_TUNNEL_PORT) {
- dev->features = features;
+ WRITE_ONCE(dev->features, features);
udp_tunnel_get_rx_info(dev);
} else {
udp_tunnel_drop_rx_info(dev);
@@ -10025,7 +10025,7 @@ int __netdev_update_features(struct net_device *dev)
if (diff & NETIF_F_HW_VLAN_CTAG_FILTER) {
if (features & NETIF_F_HW_VLAN_CTAG_FILTER) {
- dev->features = features;
+ WRITE_ONCE(dev->features, features);
err |= vlan_get_rx_ctag_filter_info(dev);
} else {
vlan_drop_rx_ctag_filter_info(dev);
@@ -10034,14 +10034,14 @@ int __netdev_update_features(struct net_device *dev)
if (diff & NETIF_F_HW_VLAN_STAG_FILTER) {
if (features & NETIF_F_HW_VLAN_STAG_FILTER) {
- dev->features = features;
+ WRITE_ONCE(dev->features, features);
err |= vlan_get_rx_stag_filter_info(dev);
} else {
vlan_drop_rx_stag_filter_info(dev);
}
}
- dev->features = features;
+ WRITE_ONCE(dev->features, features);
}
return err < 0 ? 0 : 1;
@@ -245,13 +245,13 @@ static netdev_features_t ethtool_get_feature_mask(u32 eth_cmd)
}
}
-static int ethtool_get_one_feature(struct net_device *dev,
+static int ethtool_get_one_feature(const struct net_device *dev,
char __user *useraddr, u32 ethcmd)
{
netdev_features_t mask = ethtool_get_feature_mask(ethcmd);
struct ethtool_value edata = {
.cmd = ethcmd,
- .data = !!(dev->features & mask),
+ .data = !!(READ_ONCE(dev->features) & mask),
};
if (copy_to_user(useraddr, &edata, sizeof(edata)))
@@ -3049,14 +3049,6 @@ __dev_ethtool(struct net_device *dev, struct ifreq *ifr,
case ETHTOOL_SFEATURES:
rc = ethtool_set_features(dev, useraddr);
break;
- case ETHTOOL_GTXCSUM:
- case ETHTOOL_GRXCSUM:
- case ETHTOOL_GSG:
- case ETHTOOL_GTSO:
- case ETHTOOL_GGSO:
- case ETHTOOL_GGRO:
- rc = ethtool_get_one_feature(dev, useraddr, ethcmd);
- break;
case ETHTOOL_STXCSUM:
case ETHTOOL_SRXCSUM:
case ETHTOOL_SSG:
@@ -3178,10 +3170,20 @@ int dev_ethtool(struct net *net, struct ifreq *ifr, void __user *useraddr)
if (!netif_device_present(dev))
goto out_pm;
- rtnl_lock();
- rc = __dev_ethtool(dev, ifr, useraddr, ethcmd, sub_cmd, state);
- rtnl_unlock();
-
+ switch (ethcmd) {
+ case ETHTOOL_GTXCSUM:
+ case ETHTOOL_GRXCSUM:
+ case ETHTOOL_GSG:
+ case ETHTOOL_GTSO:
+ case ETHTOOL_GGSO:
+ case ETHTOOL_GGRO:
+ rc = ethtool_get_one_feature(dev, useraddr, ethcmd);
+ break;
+ default:
+ rtnl_lock();
+ rc = __dev_ethtool(dev, ifr, useraddr, ethcmd, sub_cmd, state);
+ rtnl_unlock();
+ }
out_pm:
if (dev->dev.parent)
pm_runtime_put(dev->dev.parent);
ethtool_get_one_feature() is used by ETHTOOL_GTXCSUM, ETHTOOL_GRXCSUM, ETHTOOL_GSG, ETHTOOL_GTSO, ETHTOOL_GGSO and ETHTOOL_GGRO. Add WRITE_ONCE() and READ_ONCE() annotations on dev->features. Note that many READ_ONCE() annotations are probably missing in many drivers, but this is orthogonal to this patch. Signed-off-by: Eric Dumazet <edumazet@google.com> --- net/core/dev.c | 10 +++++----- net/ethtool/ioctl.c | 30 ++++++++++++++++-------------- 2 files changed, 21 insertions(+), 19 deletions(-)