Merge branch 'netdev-tracking'
Jakub Kicinski says: ==================== net: create device lookup API with reference tracking We still see dev_hold() / dev_put() calls without reference tracker getting added in new code. dev_get_by_name() / dev_get_by_index() seem to be one of the sources of those. Provide appropriate helpers. Allocating the tracker can obviously be done with an additional call to netdev_tracker_alloc(), but a single API feels cleaner. v2: - fix a dev_put() in ethtool v1: https://lore.kernel.org/all/20230609183207.1466075-1-kuba@kernel.org/ ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
473f5e13b3
@ -3124,6 +3124,10 @@ struct net_device *netdev_sk_get_lowest_dev(struct net_device *dev,
|
||||
struct sock *sk);
|
||||
struct net_device *dev_get_by_index(struct net *net, int ifindex);
|
||||
struct net_device *__dev_get_by_index(struct net *net, int ifindex);
|
||||
struct net_device *netdev_get_by_index(struct net *net, int ifindex,
|
||||
netdevice_tracker *tracker, gfp_t gfp);
|
||||
struct net_device *netdev_get_by_name(struct net *net, const char *name,
|
||||
netdevice_tracker *tracker, gfp_t gfp);
|
||||
struct net_device *dev_get_by_index_rcu(struct net *net, int ifindex);
|
||||
struct net_device *dev_get_by_napi_id(unsigned int napi_id);
|
||||
int dev_restart(struct net_device *dev);
|
||||
|
@ -758,18 +758,7 @@ struct net_device *dev_get_by_name_rcu(struct net *net, const char *name)
|
||||
}
|
||||
EXPORT_SYMBOL(dev_get_by_name_rcu);
|
||||
|
||||
/**
|
||||
* dev_get_by_name - find a device by its name
|
||||
* @net: the applicable net namespace
|
||||
* @name: name to find
|
||||
*
|
||||
* Find an interface by name. This can be called from any
|
||||
* context and does its own locking. The returned handle has
|
||||
* the usage count incremented and the caller must use dev_put() to
|
||||
* release it when it is no longer needed. %NULL is returned if no
|
||||
* matching device is found.
|
||||
*/
|
||||
|
||||
/* Deprecated for new users, call netdev_get_by_name() instead */
|
||||
struct net_device *dev_get_by_name(struct net *net, const char *name)
|
||||
{
|
||||
struct net_device *dev;
|
||||
@ -782,6 +771,31 @@ struct net_device *dev_get_by_name(struct net *net, const char *name)
|
||||
}
|
||||
EXPORT_SYMBOL(dev_get_by_name);
|
||||
|
||||
/**
|
||||
* netdev_get_by_name() - find a device by its name
|
||||
* @net: the applicable net namespace
|
||||
* @name: name to find
|
||||
* @tracker: tracking object for the acquired reference
|
||||
* @gfp: allocation flags for the tracker
|
||||
*
|
||||
* Find an interface by name. This can be called from any
|
||||
* context and does its own locking. The returned handle has
|
||||
* the usage count incremented and the caller must use netdev_put() to
|
||||
* release it when it is no longer needed. %NULL is returned if no
|
||||
* matching device is found.
|
||||
*/
|
||||
struct net_device *netdev_get_by_name(struct net *net, const char *name,
|
||||
netdevice_tracker *tracker, gfp_t gfp)
|
||||
{
|
||||
struct net_device *dev;
|
||||
|
||||
dev = dev_get_by_name(net, name);
|
||||
if (dev)
|
||||
netdev_tracker_alloc(dev, tracker, gfp);
|
||||
return dev;
|
||||
}
|
||||
EXPORT_SYMBOL(netdev_get_by_name);
|
||||
|
||||
/**
|
||||
* __dev_get_by_index - find a device by its ifindex
|
||||
* @net: the applicable net namespace
|
||||
@ -831,18 +845,7 @@ struct net_device *dev_get_by_index_rcu(struct net *net, int ifindex)
|
||||
}
|
||||
EXPORT_SYMBOL(dev_get_by_index_rcu);
|
||||
|
||||
|
||||
/**
|
||||
* dev_get_by_index - 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 returned has
|
||||
* had a reference added and the pointer is safe until the user calls
|
||||
* dev_put to indicate they have finished with it.
|
||||
*/
|
||||
|
||||
/* Deprecated for new users, call netdev_get_by_index() instead */
|
||||
struct net_device *dev_get_by_index(struct net *net, int ifindex)
|
||||
{
|
||||
struct net_device *dev;
|
||||
@ -855,6 +858,30 @@ struct net_device *dev_get_by_index(struct net *net, int ifindex)
|
||||
}
|
||||
EXPORT_SYMBOL(dev_get_by_index);
|
||||
|
||||
/**
|
||||
* netdev_get_by_index() - find a device by its ifindex
|
||||
* @net: the applicable net namespace
|
||||
* @ifindex: index of device
|
||||
* @tracker: tracking object for the acquired reference
|
||||
* @gfp: allocation flags for the tracker
|
||||
*
|
||||
* Search for an interface by index. Returns NULL if the device
|
||||
* is not found or a pointer to the device. The device returned has
|
||||
* had a reference added and the pointer is safe until the user calls
|
||||
* netdev_put() to indicate they have finished with it.
|
||||
*/
|
||||
struct net_device *netdev_get_by_index(struct net *net, int ifindex,
|
||||
netdevice_tracker *tracker, gfp_t gfp)
|
||||
{
|
||||
struct net_device *dev;
|
||||
|
||||
dev = dev_get_by_index(net, ifindex);
|
||||
if (dev)
|
||||
netdev_tracker_alloc(dev, tracker, gfp);
|
||||
return dev;
|
||||
}
|
||||
EXPORT_SYMBOL(netdev_get_by_index);
|
||||
|
||||
/**
|
||||
* dev_get_by_napi_id - find a device by napi_id
|
||||
* @napi_id: ID of the NAPI struct
|
||||
|
@ -690,7 +690,7 @@ int netpoll_setup(struct netpoll *np)
|
||||
err = -ENODEV;
|
||||
goto unlock;
|
||||
}
|
||||
dev_hold(ndev);
|
||||
netdev_hold(ndev, &np->dev_tracker, GFP_KERNEL);
|
||||
|
||||
if (netdev_master_upper_dev_get(ndev)) {
|
||||
np_err(np, "%s is a slave device, aborting\n", np->dev_name);
|
||||
@ -783,12 +783,11 @@ put_noaddr:
|
||||
err = __netpoll_setup(np, ndev);
|
||||
if (err)
|
||||
goto put;
|
||||
netdev_tracker_alloc(ndev, &np->dev_tracker, GFP_KERNEL);
|
||||
rtnl_unlock();
|
||||
return 0;
|
||||
|
||||
put:
|
||||
dev_put(ndev);
|
||||
netdev_put(ndev, &np->dev_tracker);
|
||||
unlock:
|
||||
rtnl_unlock();
|
||||
return err;
|
||||
|
@ -115,7 +115,8 @@ int ethnl_parse_header_dev_get(struct ethnl_req_info *req_info,
|
||||
if (tb[ETHTOOL_A_HEADER_DEV_INDEX]) {
|
||||
u32 ifindex = nla_get_u32(tb[ETHTOOL_A_HEADER_DEV_INDEX]);
|
||||
|
||||
dev = dev_get_by_index(net, ifindex);
|
||||
dev = netdev_get_by_index(net, ifindex, &req_info->dev_tracker,
|
||||
GFP_KERNEL);
|
||||
if (!dev) {
|
||||
NL_SET_ERR_MSG_ATTR(extack,
|
||||
tb[ETHTOOL_A_HEADER_DEV_INDEX],
|
||||
@ -125,13 +126,14 @@ int ethnl_parse_header_dev_get(struct ethnl_req_info *req_info,
|
||||
/* if both ifindex and ifname are passed, they must match */
|
||||
if (devname_attr &&
|
||||
strncmp(dev->name, nla_data(devname_attr), IFNAMSIZ)) {
|
||||
dev_put(dev);
|
||||
netdev_put(dev, &req_info->dev_tracker);
|
||||
NL_SET_ERR_MSG_ATTR(extack, header,
|
||||
"ifindex and name do not match");
|
||||
return -ENODEV;
|
||||
}
|
||||
} else if (devname_attr) {
|
||||
dev = dev_get_by_name(net, nla_data(devname_attr));
|
||||
dev = netdev_get_by_name(net, nla_data(devname_attr),
|
||||
&req_info->dev_tracker, GFP_KERNEL);
|
||||
if (!dev) {
|
||||
NL_SET_ERR_MSG_ATTR(extack, devname_attr,
|
||||
"no device matches name");
|
||||
@ -144,8 +146,6 @@ int ethnl_parse_header_dev_get(struct ethnl_req_info *req_info,
|
||||
}
|
||||
|
||||
req_info->dev = dev;
|
||||
if (dev)
|
||||
netdev_tracker_alloc(dev, &req_info->dev_tracker, GFP_KERNEL);
|
||||
req_info->flags = flags;
|
||||
return 0;
|
||||
}
|
||||
|
@ -3503,6 +3503,7 @@ int fib6_nh_init(struct net *net, struct fib6_nh *fib6_nh,
|
||||
struct fib6_config *cfg, gfp_t gfp_flags,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
netdevice_tracker *dev_tracker = &fib6_nh->fib_nh_dev_tracker;
|
||||
struct net_device *dev = NULL;
|
||||
struct inet6_dev *idev = NULL;
|
||||
int addr_type;
|
||||
@ -3520,7 +3521,8 @@ int fib6_nh_init(struct net *net, struct fib6_nh *fib6_nh,
|
||||
|
||||
err = -ENODEV;
|
||||
if (cfg->fc_ifindex) {
|
||||
dev = dev_get_by_index(net, cfg->fc_ifindex);
|
||||
dev = netdev_get_by_index(net, cfg->fc_ifindex,
|
||||
dev_tracker, gfp_flags);
|
||||
if (!dev)
|
||||
goto out;
|
||||
idev = in6_dev_get(dev);
|
||||
@ -3554,11 +3556,11 @@ int fib6_nh_init(struct net *net, struct fib6_nh *fib6_nh,
|
||||
/* hold loopback dev/idev if we haven't done so. */
|
||||
if (dev != net->loopback_dev) {
|
||||
if (dev) {
|
||||
dev_put(dev);
|
||||
netdev_put(dev, dev_tracker);
|
||||
in6_dev_put(idev);
|
||||
}
|
||||
dev = net->loopback_dev;
|
||||
dev_hold(dev);
|
||||
netdev_hold(dev, dev_tracker, gfp_flags);
|
||||
idev = in6_dev_get(dev);
|
||||
if (!idev) {
|
||||
err = -ENODEV;
|
||||
@ -3610,8 +3612,6 @@ pcpu_alloc:
|
||||
}
|
||||
|
||||
fib6_nh->fib_nh_dev = dev;
|
||||
netdev_tracker_alloc(dev, &fib6_nh->fib_nh_dev_tracker, gfp_flags);
|
||||
|
||||
fib6_nh->fib_nh_oif = dev->ifindex;
|
||||
err = 0;
|
||||
out:
|
||||
@ -3621,7 +3621,7 @@ out:
|
||||
if (err) {
|
||||
lwtstate_put(fib6_nh->fib_nh_lws);
|
||||
fib6_nh->fib_nh_lws = NULL;
|
||||
dev_put(dev);
|
||||
netdev_put(dev, dev_tracker);
|
||||
}
|
||||
|
||||
return err;
|
||||
|
Loading…
x
Reference in New Issue
Block a user