mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	net: hold netdev instance lock during ioctl operations
Convert all ndo_eth_ioctl invocations to dev_eth_ioctl which does the locking. Reflow some of the dev_siocxxx to drop else clause. Cc: Saeed Mahameed <saeed@kernel.org> Signed-off-by: Stanislav Fomichev <sdf@fomichev.me> Link: https://patch.msgid.link/20250305163732.2766420-8-sdf@fomichev.me Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
		
							parent
							
								
									7e4d784f58
								
							
						
					
					
						commit
						ffb7ed19ac
					
				
					 6 changed files with 80 additions and 37 deletions
				
			
		| 
						 | 
				
			
			@ -855,7 +855,6 @@ static int bond_check_dev_link(struct bonding *bond,
 | 
			
		|||
			       struct net_device *slave_dev, int reporting)
 | 
			
		||||
{
 | 
			
		||||
	const struct net_device_ops *slave_ops = slave_dev->netdev_ops;
 | 
			
		||||
	int (*ioctl)(struct net_device *, struct ifreq *, int);
 | 
			
		||||
	struct ifreq ifr;
 | 
			
		||||
	struct mii_ioctl_data *mii;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -871,8 +870,7 @@ static int bond_check_dev_link(struct bonding *bond,
 | 
			
		|||
			BMSR_LSTATUS : 0;
 | 
			
		||||
 | 
			
		||||
	/* Ethtool can't be used, fallback to MII ioctls. */
 | 
			
		||||
	ioctl = slave_ops->ndo_eth_ioctl;
 | 
			
		||||
	if (ioctl) {
 | 
			
		||||
	if (slave_ops->ndo_eth_ioctl) {
 | 
			
		||||
		/* TODO: set pointer to correct ioctl on a per team member
 | 
			
		||||
		 *       bases to make this more efficient. that is, once
 | 
			
		||||
		 *       we determine the correct ioctl, we will always
 | 
			
		||||
| 
						 | 
				
			
			@ -888,9 +886,10 @@ static int bond_check_dev_link(struct bonding *bond,
 | 
			
		|||
		/* Yes, the mii is overlaid on the ifreq.ifr_ifru */
 | 
			
		||||
		strscpy_pad(ifr.ifr_name, slave_dev->name, IFNAMSIZ);
 | 
			
		||||
		mii = if_mii(&ifr);
 | 
			
		||||
		if (ioctl(slave_dev, &ifr, SIOCGMIIPHY) == 0) {
 | 
			
		||||
 | 
			
		||||
		if (dev_eth_ioctl(slave_dev, &ifr, SIOCGMIIPHY) == 0) {
 | 
			
		||||
			mii->reg_num = MII_BMSR;
 | 
			
		||||
			if (ioctl(slave_dev, &ifr, SIOCGMIIREG) == 0)
 | 
			
		||||
			if (dev_eth_ioctl(slave_dev, &ifr, SIOCGMIIREG) == 0)
 | 
			
		||||
				return mii->val_out & BMSR_LSTATUS;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4229,6 +4229,8 @@ int put_user_ifreq(struct ifreq *ifr, void __user *arg);
 | 
			
		|||
int dev_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr,
 | 
			
		||||
		void __user *data, bool *need_copyout);
 | 
			
		||||
int dev_ifconf(struct net *net, struct ifconf __user *ifc);
 | 
			
		||||
int dev_eth_ioctl(struct net_device *dev,
 | 
			
		||||
		  struct ifreq *ifr, unsigned int cmd);
 | 
			
		||||
int generic_hwtstamp_get_lower(struct net_device *dev,
 | 
			
		||||
			       struct kernel_hwtstamp_config *kernel_cfg);
 | 
			
		||||
int generic_hwtstamp_set_lower(struct net_device *dev,
 | 
			
		||||
| 
						 | 
				
			
			@ -4251,6 +4253,7 @@ int netif_change_net_namespace(struct net_device *dev, struct net *net,
 | 
			
		|||
int dev_change_net_namespace(struct net_device *dev, struct net *net,
 | 
			
		||||
			     const char *pat);
 | 
			
		||||
int __dev_set_mtu(struct net_device *, int);
 | 
			
		||||
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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -377,7 +377,6 @@ static int vlan_hwtstamp_set(struct net_device *dev,
 | 
			
		|||
static int vlan_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 | 
			
		||||
{
 | 
			
		||||
	struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
 | 
			
		||||
	const struct net_device_ops *ops = real_dev->netdev_ops;
 | 
			
		||||
	struct ifreq ifrr;
 | 
			
		||||
	int err = -EOPNOTSUPP;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -388,8 +387,7 @@ static int vlan_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 | 
			
		|||
	case SIOCGMIIPHY:
 | 
			
		||||
	case SIOCGMIIREG:
 | 
			
		||||
	case SIOCSMIIREG:
 | 
			
		||||
		if (netif_device_present(real_dev) && ops->ndo_eth_ioctl)
 | 
			
		||||
			err = ops->ndo_eth_ioctl(real_dev, &ifrr, cmd);
 | 
			
		||||
		err = dev_eth_ioctl(real_dev, &ifrr, cmd);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9522,7 +9522,7 @@ int netif_set_mtu_ext(struct net_device *dev, int new_mtu,
 | 
			
		|||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int dev_set_mtu(struct net_device *dev, int new_mtu)
 | 
			
		||||
int netif_set_mtu(struct net_device *dev, int new_mtu)
 | 
			
		||||
{
 | 
			
		||||
	struct netlink_ext_ack extack;
 | 
			
		||||
	int err;
 | 
			
		||||
| 
						 | 
				
			
			@ -9533,7 +9533,7 @@ int dev_set_mtu(struct net_device *dev, int new_mtu)
 | 
			
		|||
		net_err_ratelimited("%s: %s\n", dev->name, extack._msg);
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL(dev_set_mtu);
 | 
			
		||||
EXPORT_SYMBOL(netif_set_mtu);
 | 
			
		||||
 | 
			
		||||
int netif_change_tx_queue_len(struct net_device *dev, unsigned long new_len)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -222,3 +222,33 @@ void dev_close(struct net_device *dev)
 | 
			
		|||
	netdev_unlock_ops(dev);
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL(dev_close);
 | 
			
		||||
 | 
			
		||||
int dev_eth_ioctl(struct net_device *dev,
 | 
			
		||||
		  struct ifreq *ifr, unsigned int cmd)
 | 
			
		||||
{
 | 
			
		||||
	const struct net_device_ops *ops = dev->netdev_ops;
 | 
			
		||||
	int ret = -ENODEV;
 | 
			
		||||
 | 
			
		||||
	if (!ops->ndo_eth_ioctl)
 | 
			
		||||
		return -EOPNOTSUPP;
 | 
			
		||||
 | 
			
		||||
	netdev_lock_ops(dev);
 | 
			
		||||
	if (netif_device_present(dev))
 | 
			
		||||
		ret = ops->ndo_eth_ioctl(dev, ifr, cmd);
 | 
			
		||||
	netdev_unlock_ops(dev);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL(dev_eth_ioctl);
 | 
			
		||||
 | 
			
		||||
int dev_set_mtu(struct net_device *dev, int new_mtu)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	netdev_lock_ops(dev);
 | 
			
		||||
	ret = netif_set_mtu(dev, new_mtu);
 | 
			
		||||
	netdev_unlock_ops(dev);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL(dev_set_mtu);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -110,7 +110,7 @@ static int dev_getifmap(struct net_device *dev, struct ifreq *ifr)
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int dev_setifmap(struct net_device *dev, struct ifreq *ifr)
 | 
			
		||||
static int netif_setifmap(struct net_device *dev, struct ifreq *ifr)
 | 
			
		||||
{
 | 
			
		||||
	struct compat_ifmap *cifmap = (struct compat_ifmap *)&ifr->ifr_map;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -240,20 +240,6 @@ int net_hwtstamp_validate(const struct kernel_hwtstamp_config *cfg)
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int dev_eth_ioctl(struct net_device *dev,
 | 
			
		||||
			 struct ifreq *ifr, unsigned int cmd)
 | 
			
		||||
{
 | 
			
		||||
	const struct net_device_ops *ops = dev->netdev_ops;
 | 
			
		||||
 | 
			
		||||
	if (!ops->ndo_eth_ioctl)
 | 
			
		||||
		return -EOPNOTSUPP;
 | 
			
		||||
 | 
			
		||||
	if (!netif_device_present(dev))
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
 | 
			
		||||
	return ops->ndo_eth_ioctl(dev, ifr, cmd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * dev_get_hwtstamp_phylib() - Get hardware timestamping settings of NIC
 | 
			
		||||
 *	or of attached phylib PHY
 | 
			
		||||
| 
						 | 
				
			
			@ -305,7 +291,9 @@ static int dev_get_hwtstamp(struct net_device *dev, struct ifreq *ifr)
 | 
			
		|||
		return -ENODEV;
 | 
			
		||||
 | 
			
		||||
	kernel_cfg.ifr = ifr;
 | 
			
		||||
	netdev_lock_ops(dev);
 | 
			
		||||
	err = dev_get_hwtstamp_phylib(dev, &kernel_cfg);
 | 
			
		||||
	netdev_unlock_ops(dev);
 | 
			
		||||
	if (err)
 | 
			
		||||
		return err;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -429,7 +417,9 @@ static int dev_set_hwtstamp(struct net_device *dev, struct ifreq *ifr)
 | 
			
		|||
	if (!netif_device_present(dev))
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
 | 
			
		||||
	netdev_lock_ops(dev);
 | 
			
		||||
	err = dev_set_hwtstamp_phylib(dev, &kernel_cfg, &extack);
 | 
			
		||||
	netdev_unlock_ops(dev);
 | 
			
		||||
	if (err)
 | 
			
		||||
		return err;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -504,10 +494,14 @@ static int dev_siocbond(struct net_device *dev,
 | 
			
		|||
	const struct net_device_ops *ops = dev->netdev_ops;
 | 
			
		||||
 | 
			
		||||
	if (ops->ndo_siocbond) {
 | 
			
		||||
		int ret = -ENODEV;
 | 
			
		||||
 | 
			
		||||
		netdev_lock_ops(dev);
 | 
			
		||||
		if (netif_device_present(dev))
 | 
			
		||||
			return ops->ndo_siocbond(dev, ifr, cmd);
 | 
			
		||||
		else
 | 
			
		||||
			return -ENODEV;
 | 
			
		||||
			ret = ops->ndo_siocbond(dev, ifr, cmd);
 | 
			
		||||
		netdev_unlock_ops(dev);
 | 
			
		||||
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return -EOPNOTSUPP;
 | 
			
		||||
| 
						 | 
				
			
			@ -519,10 +513,14 @@ static int dev_siocdevprivate(struct net_device *dev, struct ifreq *ifr,
 | 
			
		|||
	const struct net_device_ops *ops = dev->netdev_ops;
 | 
			
		||||
 | 
			
		||||
	if (ops->ndo_siocdevprivate) {
 | 
			
		||||
		int ret = -ENODEV;
 | 
			
		||||
 | 
			
		||||
		netdev_lock_ops(dev);
 | 
			
		||||
		if (netif_device_present(dev))
 | 
			
		||||
			return ops->ndo_siocdevprivate(dev, ifr, data, cmd);
 | 
			
		||||
		else
 | 
			
		||||
			return -ENODEV;
 | 
			
		||||
			ret = ops->ndo_siocdevprivate(dev, ifr, data, cmd);
 | 
			
		||||
		netdev_unlock_ops(dev);
 | 
			
		||||
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return -EOPNOTSUPP;
 | 
			
		||||
| 
						 | 
				
			
			@ -533,10 +531,14 @@ static int dev_siocwandev(struct net_device *dev, struct if_settings *ifs)
 | 
			
		|||
	const struct net_device_ops *ops = dev->netdev_ops;
 | 
			
		||||
 | 
			
		||||
	if (ops->ndo_siocwandev) {
 | 
			
		||||
		int ret = -ENODEV;
 | 
			
		||||
 | 
			
		||||
		netdev_lock_ops(dev);
 | 
			
		||||
		if (netif_device_present(dev))
 | 
			
		||||
			return ops->ndo_siocwandev(dev, ifs);
 | 
			
		||||
		else
 | 
			
		||||
			return -ENODEV;
 | 
			
		||||
			ret = ops->ndo_siocwandev(dev, ifs);
 | 
			
		||||
		netdev_unlock_ops(dev);
 | 
			
		||||
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return -EOPNOTSUPP;
 | 
			
		||||
| 
						 | 
				
			
			@ -580,11 +582,16 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, void __user *data,
 | 
			
		|||
		memcpy(dev->broadcast, ifr->ifr_hwaddr.sa_data,
 | 
			
		||||
		       min(sizeof(ifr->ifr_hwaddr.sa_data_min),
 | 
			
		||||
			   (size_t)dev->addr_len));
 | 
			
		||||
		netdev_lock_ops(dev);
 | 
			
		||||
		call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
 | 
			
		||||
		netdev_unlock_ops(dev);
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	case SIOCSIFMAP:
 | 
			
		||||
		return dev_setifmap(dev, ifr);
 | 
			
		||||
		netdev_lock_ops(dev);
 | 
			
		||||
		err = netif_setifmap(dev, ifr);
 | 
			
		||||
		netdev_unlock_ops(dev);
 | 
			
		||||
		return err;
 | 
			
		||||
 | 
			
		||||
	case SIOCADDMULTI:
 | 
			
		||||
		if (!ops->ndo_set_rx_mode ||
 | 
			
		||||
| 
						 | 
				
			
			@ -592,7 +599,10 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, void __user *data,
 | 
			
		|||
			return -EINVAL;
 | 
			
		||||
		if (!netif_device_present(dev))
 | 
			
		||||
			return -ENODEV;
 | 
			
		||||
		return dev_mc_add_global(dev, ifr->ifr_hwaddr.sa_data);
 | 
			
		||||
		netdev_lock_ops(dev);
 | 
			
		||||
		err = dev_mc_add_global(dev, ifr->ifr_hwaddr.sa_data);
 | 
			
		||||
		netdev_unlock_ops(dev);
 | 
			
		||||
		return err;
 | 
			
		||||
 | 
			
		||||
	case SIOCDELMULTI:
 | 
			
		||||
		if (!ops->ndo_set_rx_mode ||
 | 
			
		||||
| 
						 | 
				
			
			@ -600,7 +610,10 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, void __user *data,
 | 
			
		|||
			return -EINVAL;
 | 
			
		||||
		if (!netif_device_present(dev))
 | 
			
		||||
			return -ENODEV;
 | 
			
		||||
		return dev_mc_del_global(dev, ifr->ifr_hwaddr.sa_data);
 | 
			
		||||
		netdev_lock_ops(dev);
 | 
			
		||||
		err = dev_mc_del_global(dev, ifr->ifr_hwaddr.sa_data);
 | 
			
		||||
		netdev_unlock_ops(dev);
 | 
			
		||||
		return err;
 | 
			
		||||
 | 
			
		||||
	case SIOCSIFTXQLEN:
 | 
			
		||||
		if (ifr->ifr_qlen < 0)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue