Skip to content

Commit

Permalink
net: hold netdev instance lock during sysfs operations
Browse files Browse the repository at this point in the history
Most of them are already covered by the converted dev_xxx APIs.
Add the locking wrappers for the remaining ones.

Cc: Saeed Mahameed <saeed@kernel.org>
Signed-off-by: Stanislav Fomichev <sdf@fomichev.me>
Link: https://patch.msgid.link/20250305163732.2766420-9-sdf@fomichev.me
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  • Loading branch information
Stanislav Fomichev authored and Jakub Kicinski committed Mar 6, 2025
1 parent ffb7ed1 commit ad7c7b2
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 48 deletions.
7 changes: 5 additions & 2 deletions drivers/net/bonding/bond_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -2644,10 +2644,13 @@ static int __bond_release_one(struct net_device *bond_dev,
dev_set_mac_address(slave_dev, (struct sockaddr *)&ss, NULL);
}

if (unregister)
if (unregister) {
netdev_lock_ops(slave_dev);
__dev_set_mtu(slave_dev, slave->original_mtu);
else
netdev_unlock_ops(slave_dev);
} else {
dev_set_mtu(slave_dev, slave->original_mtu);
}

if (!netif_is_bond_master(slave_dev))
slave_dev->priv_flags &= ~IFF_BONDING;
Expand Down
4 changes: 4 additions & 0 deletions include/linux/netdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -3382,6 +3382,7 @@ void dev_close(struct net_device *dev);
void dev_close_many(struct list_head *head, bool unlink);
int dev_setup_tc(struct net_device *dev, enum tc_setup_type type,
void *type_data);
void netif_disable_lro(struct net_device *dev);
void dev_disable_lro(struct net_device *dev);
int dev_loopback_xmit(struct net *net, struct sock *sk, struct sk_buff *newskb);
u16 dev_pick_tx_zero(struct net_device *dev, struct sk_buff *skb,
Expand Down Expand Up @@ -4257,6 +4258,8 @@ int netif_set_mtu(struct net_device *dev, int new_mtu);
int dev_set_mtu(struct net_device *, int);
int dev_pre_changeaddr_notify(struct net_device *dev, const char *addr,
struct netlink_ext_ack *extack);
int netif_set_mac_address(struct net_device *dev, struct sockaddr *sa,
struct netlink_ext_ack *extack);
int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa,
struct netlink_ext_ack *extack);
int netif_set_mac_address_user(struct net_device *dev, struct sockaddr *sa,
Expand Down Expand Up @@ -5016,6 +5019,7 @@ static inline void __dev_mc_unsync(struct net_device *dev,
/* Functions used for secondary unicast and multicast support */
void dev_set_rx_mode(struct net_device *dev);
int dev_set_promiscuity(struct net_device *dev, int inc);
int netif_set_allmulti(struct net_device *dev, int inc, bool notify);
int dev_set_allmulti(struct net_device *dev, int inc);
void netdev_state_change(struct net_device *dev);
void __netdev_notify_peers(struct net_device *dev);
Expand Down
58 changes: 12 additions & 46 deletions net/core/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -1757,15 +1757,7 @@ int dev_setup_tc(struct net_device *dev, enum tc_setup_type type,
}
EXPORT_SYMBOL(dev_setup_tc);

/**
* dev_disable_lro - disable Large Receive Offload on a device
* @dev: device
*
* Disable Large Receive Offload (LRO) on a net device. Must be
* called under RTNL. This is needed if received packets may be
* forwarded to another interface.
*/
void dev_disable_lro(struct net_device *dev)
void netif_disable_lro(struct net_device *dev)
{
struct net_device *lower_dev;
struct list_head *iter;
Expand All @@ -1776,10 +1768,12 @@ void dev_disable_lro(struct net_device *dev)
if (unlikely(dev->features & NETIF_F_LRO))
netdev_WARN(dev, "failed to disable LRO!\n");

netdev_for_each_lower_dev(dev, lower_dev, iter)
dev_disable_lro(lower_dev);
netdev_for_each_lower_dev(dev, lower_dev, iter) {
netdev_lock_ops(lower_dev);
netif_disable_lro(lower_dev);
netdev_unlock_ops(lower_dev);
}
}
EXPORT_SYMBOL(dev_disable_lro);

/**
* dev_disable_gro_hw - disable HW Generic Receive Offload on a device
Expand Down Expand Up @@ -6038,7 +6032,7 @@ static int generic_xdp_install(struct net_device *dev, struct netdev_bpf *xdp)
static_branch_dec(&generic_xdp_needed_key);
} else if (new && !old) {
static_branch_inc(&generic_xdp_needed_key);
dev_disable_lro(dev);
netif_disable_lro(dev);
dev_disable_gro_hw(dev);
}
break;
Expand Down Expand Up @@ -9210,7 +9204,7 @@ int dev_set_promiscuity(struct net_device *dev, int inc)
}
EXPORT_SYMBOL(dev_set_promiscuity);

static int __dev_set_allmulti(struct net_device *dev, int inc, bool notify)
int netif_set_allmulti(struct net_device *dev, int inc, bool notify)
{
unsigned int old_flags = dev->flags, old_gflags = dev->gflags;
unsigned int allmulti, flags;
Expand Down Expand Up @@ -9245,25 +9239,6 @@ static int __dev_set_allmulti(struct net_device *dev, int inc, bool notify)
return 0;
}

/**
* dev_set_allmulti - update allmulti count on a device
* @dev: device
* @inc: modifier
*
* Add or remove reception of all multicast frames to a device. While the
* count in the device remains above zero the interface remains listening
* to all interfaces. Once it hits zero the device reverts back to normal
* filtering operation. A negative @inc value is used to drop the counter
* when releasing a resource needing all multicasts.
* Return 0 if successful or a negative errno code on error.
*/

int dev_set_allmulti(struct net_device *dev, int inc)
{
return __dev_set_allmulti(dev, inc, true);
}
EXPORT_SYMBOL(dev_set_allmulti);

/*
* Upload unicast and multicast address lists to device and
* configure RX filtering. When the device doesn't support unicast
Expand Down Expand Up @@ -9396,7 +9371,7 @@ int __dev_change_flags(struct net_device *dev, unsigned int flags,
int inc = (flags & IFF_ALLMULTI) ? 1 : -1;

dev->gflags ^= IFF_ALLMULTI;
__dev_set_allmulti(dev, inc, false);
netif_set_allmulti(dev, inc, false);
}

return ret;
Expand Down Expand Up @@ -9588,16 +9563,8 @@ int dev_pre_changeaddr_notify(struct net_device *dev, const char *addr,
}
EXPORT_SYMBOL(dev_pre_changeaddr_notify);

/**
* dev_set_mac_address - Change Media Access Control Address
* @dev: device
* @sa: new address
* @extack: netlink extended ack
*
* Change the hardware (MAC) address of the device
*/
int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa,
struct netlink_ext_ack *extack)
int netif_set_mac_address(struct net_device *dev, struct sockaddr *sa,
struct netlink_ext_ack *extack)
{
const struct net_device_ops *ops = dev->netdev_ops;
int err;
Expand All @@ -9621,7 +9588,6 @@ int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa,
add_device_randomness(dev->dev_addr, dev->addr_len);
return 0;
}
EXPORT_SYMBOL(dev_set_mac_address);

DECLARE_RWSEM(dev_addr_sem);

Expand All @@ -9631,7 +9597,7 @@ int netif_set_mac_address_user(struct net_device *dev, struct sockaddr *sa,
int ret;

down_write(&dev_addr_sem);
ret = dev_set_mac_address(dev, sa, extack);
ret = netif_set_mac_address(dev, sa, extack);
up_write(&dev_addr_sem);
return ret;
}
Expand Down
65 changes: 65 additions & 0 deletions net/core/dev_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -252,3 +252,68 @@ int dev_set_mtu(struct net_device *dev, int new_mtu)
return ret;
}
EXPORT_SYMBOL(dev_set_mtu);

/**
* dev_disable_lro() - disable Large Receive Offload on a device
* @dev: device
*
* Disable Large Receive Offload (LRO) on a net device. Must be
* called under RTNL. This is needed if received packets may be
* forwarded to another interface.
*/
void dev_disable_lro(struct net_device *dev)
{
netdev_lock_ops(dev);
netif_disable_lro(dev);
netdev_unlock_ops(dev);
}
EXPORT_SYMBOL(dev_disable_lro);

/**
* dev_set_allmulti() - update allmulti count on a device
* @dev: device
* @inc: modifier
*
* Add or remove reception of all multicast frames to a device. While the
* count in the device remains above zero the interface remains listening
* to all interfaces. Once it hits zero the device reverts back to normal
* filtering operation. A negative @inc value is used to drop the counter
* when releasing a resource needing all multicasts.
*
* Return: 0 on success, -errno on failure.
*/

int dev_set_allmulti(struct net_device *dev, int inc)
{
int ret;

netdev_lock_ops(dev);
ret = netif_set_allmulti(dev, inc, true);
netdev_unlock_ops(dev);

return ret;
}
EXPORT_SYMBOL(dev_set_allmulti);

/**
* dev_set_mac_address() - change Media Access Control Address
* @dev: device
* @sa: new address
* @extack: netlink extended ack
*
* Change the hardware (MAC) address of the device
*
* Return: 0 on success, -errno on failure.
*/
int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa,
struct netlink_ext_ack *extack)
{
int ret;

netdev_lock_ops(dev);
ret = netif_set_mac_address(dev, sa, extack);
netdev_unlock_ops(dev);

return ret;
}
EXPORT_SYMBOL(dev_set_mac_address);
2 changes: 2 additions & 0 deletions net/core/net-sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1483,8 +1483,10 @@ static ssize_t tx_maxrate_store(struct kobject *kobj, struct attribute *attr,
return err;

err = -EOPNOTSUPP;
netdev_lock_ops(dev);
if (dev->netdev_ops->ndo_set_tx_maxrate)
err = dev->netdev_ops->ndo_set_tx_maxrate(dev, index, rate);
netdev_unlock_ops(dev);

if (!err) {
queue->tx_maxrate = rate;
Expand Down

0 comments on commit ad7c7b2

Please sign in to comment.