mirror of https://gitee.com/openkylin/linux.git
net: Introduce dev_get_by_index_rcu()
Some workloads hit dev_base_lock rwlock pretty hard. We can use RCU lookups to avoid touching this rwlock. netdevices are already freed after a RCU grace period, so this patch adds no penalty at device dismantle time. dev_ifname() converted to dev_get_by_index_rcu() Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
e0c5567d06
commit
fb699dfd42
|
@ -1139,6 +1139,7 @@ extern void netdev_resync_ops(struct net_device *dev);
|
||||||
extern int call_netdevice_notifiers(unsigned long val, struct net_device *dev);
|
extern int call_netdevice_notifiers(unsigned long val, struct net_device *dev);
|
||||||
extern struct net_device *dev_get_by_index(struct net *net, int ifindex);
|
extern struct net_device *dev_get_by_index(struct net *net, int ifindex);
|
||||||
extern struct net_device *__dev_get_by_index(struct net *net, int ifindex);
|
extern struct net_device *__dev_get_by_index(struct net *net, int ifindex);
|
||||||
|
extern struct net_device *dev_get_by_index_rcu(struct net *net, int ifindex);
|
||||||
extern int dev_restart(struct net_device *dev);
|
extern int dev_restart(struct net_device *dev);
|
||||||
#ifdef CONFIG_NETPOLL_TRAP
|
#ifdef CONFIG_NETPOLL_TRAP
|
||||||
extern int netpoll_trap(void);
|
extern int netpoll_trap(void);
|
||||||
|
|
|
@ -214,12 +214,15 @@ static int list_netdevice(struct net_device *dev)
|
||||||
write_lock_bh(&dev_base_lock);
|
write_lock_bh(&dev_base_lock);
|
||||||
list_add_tail(&dev->dev_list, &net->dev_base_head);
|
list_add_tail(&dev->dev_list, &net->dev_base_head);
|
||||||
hlist_add_head(&dev->name_hlist, dev_name_hash(net, dev->name));
|
hlist_add_head(&dev->name_hlist, dev_name_hash(net, dev->name));
|
||||||
hlist_add_head(&dev->index_hlist, dev_index_hash(net, dev->ifindex));
|
hlist_add_head_rcu(&dev->index_hlist,
|
||||||
|
dev_index_hash(net, dev->ifindex));
|
||||||
write_unlock_bh(&dev_base_lock);
|
write_unlock_bh(&dev_base_lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Device list removal */
|
/* Device list removal
|
||||||
|
* caller must respect a RCU grace period before freeing/reusing dev
|
||||||
|
*/
|
||||||
static void unlist_netdevice(struct net_device *dev)
|
static void unlist_netdevice(struct net_device *dev)
|
||||||
{
|
{
|
||||||
ASSERT_RTNL();
|
ASSERT_RTNL();
|
||||||
|
@ -228,7 +231,7 @@ static void unlist_netdevice(struct net_device *dev)
|
||||||
write_lock_bh(&dev_base_lock);
|
write_lock_bh(&dev_base_lock);
|
||||||
list_del(&dev->dev_list);
|
list_del(&dev->dev_list);
|
||||||
hlist_del(&dev->name_hlist);
|
hlist_del(&dev->name_hlist);
|
||||||
hlist_del(&dev->index_hlist);
|
hlist_del_rcu(&dev->index_hlist);
|
||||||
write_unlock_bh(&dev_base_lock);
|
write_unlock_bh(&dev_base_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -646,6 +649,31 @@ struct net_device *__dev_get_by_index(struct net *net, int ifindex)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(__dev_get_by_index);
|
EXPORT_SYMBOL(__dev_get_by_index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dev_get_by_index_rcu - find a device by its ifindex
|
||||||
|
* @net: the applicable net namespace
|
||||||
|
* @ifindex: index of device
|
||||||
|
*
|
||||||
|
* Search for an interface by index. Returns %NULL if the device
|
||||||
|
* is not found or a pointer to the device. The device has not
|
||||||
|
* had its reference counter increased so the caller must be careful
|
||||||
|
* about locking. The caller must hold RCU lock.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct net_device *dev_get_by_index_rcu(struct net *net, int ifindex)
|
||||||
|
{
|
||||||
|
struct hlist_node *p;
|
||||||
|
struct net_device *dev;
|
||||||
|
struct hlist_head *head = dev_index_hash(net, ifindex);
|
||||||
|
|
||||||
|
hlist_for_each_entry_rcu(dev, p, head, index_hlist)
|
||||||
|
if (dev->ifindex == ifindex)
|
||||||
|
return dev;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(dev_get_by_index_rcu);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* dev_get_by_index - find a device by its ifindex
|
* dev_get_by_index - find a device by its ifindex
|
||||||
|
@ -662,11 +690,11 @@ struct net_device *dev_get_by_index(struct net *net, int ifindex)
|
||||||
{
|
{
|
||||||
struct net_device *dev;
|
struct net_device *dev;
|
||||||
|
|
||||||
read_lock(&dev_base_lock);
|
rcu_read_lock();
|
||||||
dev = __dev_get_by_index(net, ifindex);
|
dev = dev_get_by_index_rcu(net, ifindex);
|
||||||
if (dev)
|
if (dev)
|
||||||
dev_hold(dev);
|
dev_hold(dev);
|
||||||
read_unlock(&dev_base_lock);
|
rcu_read_unlock();
|
||||||
return dev;
|
return dev;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(dev_get_by_index);
|
EXPORT_SYMBOL(dev_get_by_index);
|
||||||
|
@ -2939,15 +2967,15 @@ static int dev_ifname(struct net *net, struct ifreq __user *arg)
|
||||||
if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
|
if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
read_lock(&dev_base_lock);
|
rcu_read_lock();
|
||||||
dev = __dev_get_by_index(net, ifr.ifr_ifindex);
|
dev = dev_get_by_index_rcu(net, ifr.ifr_ifindex);
|
||||||
if (!dev) {
|
if (!dev) {
|
||||||
read_unlock(&dev_base_lock);
|
rcu_read_unlock();
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
strcpy(ifr.ifr_name, dev->name);
|
strcpy(ifr.ifr_name, dev->name);
|
||||||
read_unlock(&dev_base_lock);
|
rcu_read_unlock();
|
||||||
|
|
||||||
if (copy_to_user(arg, &ifr, sizeof(struct ifreq)))
|
if (copy_to_user(arg, &ifr, sizeof(struct ifreq)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
Loading…
Reference in New Issue