Skip to content

Commit

Permalink
Merge branch 'netdev-tracking'
Browse files Browse the repository at this point in the history
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/[email protected]/
====================

Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
davem330 committed Jun 15, 2023
2 parents 89da780 + 48eed02 commit 473f5e1
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 32 deletions.
4 changes: 4 additions & 0 deletions include/linux/netdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
63 changes: 45 additions & 18 deletions net/core/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -758,29 +758,43 @@ struct net_device *dev_get_by_name_rcu(struct net *net, const char *name)
}
EXPORT_SYMBOL(dev_get_by_name_rcu);

/* 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;

rcu_read_lock();
dev = dev_get_by_name_rcu(net, name);
dev_hold(dev);
rcu_read_unlock();
return dev;
}
EXPORT_SYMBOL(dev_get_by_name);

/**
* dev_get_by_name - find a device by its 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 dev_put() to
* 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 *dev_get_by_name(struct net *net, const char *name)
struct net_device *netdev_get_by_name(struct net *net, const char *name,
netdevice_tracker *tracker, gfp_t gfp)
{
struct net_device *dev;

rcu_read_lock();
dev = dev_get_by_name_rcu(net, name);
dev_hold(dev);
rcu_read_unlock();
dev = dev_get_by_name(net, name);
if (dev)
netdev_tracker_alloc(dev, tracker, gfp);
return dev;
}
EXPORT_SYMBOL(dev_get_by_name);
EXPORT_SYMBOL(netdev_get_by_name);

/**
* __dev_get_by_index - find a device by its ifindex
Expand Down Expand Up @@ -831,29 +845,42 @@ struct net_device *dev_get_by_index_rcu(struct net *net, int ifindex)
}
EXPORT_SYMBOL(dev_get_by_index_rcu);

/* 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;

rcu_read_lock();
dev = dev_get_by_index_rcu(net, ifindex);
dev_hold(dev);
rcu_read_unlock();
return dev;
}
EXPORT_SYMBOL(dev_get_by_index);

/**
* dev_get_by_index - find a device by its ifindex
* 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
* dev_put to indicate they have finished with it.
* netdev_put() to indicate they have finished with it.
*/

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 *dev;

rcu_read_lock();
dev = dev_get_by_index_rcu(net, ifindex);
dev_hold(dev);
rcu_read_unlock();
dev = dev_get_by_index(net, ifindex);
if (dev)
netdev_tracker_alloc(dev, tracker, gfp);
return dev;
}
EXPORT_SYMBOL(dev_get_by_index);
EXPORT_SYMBOL(netdev_get_by_index);

/**
* dev_get_by_napi_id - find a device by napi_id
Expand Down
5 changes: 2 additions & 3 deletions net/core/netpoll.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -783,12 +783,11 @@ int netpoll_setup(struct netpoll *np)
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;
Expand Down
10 changes: 5 additions & 5 deletions net/ethtool/netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -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],
Expand All @@ -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");
Expand All @@ -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;
}
Expand Down
12 changes: 6 additions & 6 deletions net/ipv6/route.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -3610,8 +3612,6 @@ int fib6_nh_init(struct net *net, struct fib6_nh *fib6_nh,
}

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:
Expand All @@ -3621,7 +3621,7 @@ int fib6_nh_init(struct net *net, struct fib6_nh *fib6_nh,
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;
Expand Down

0 comments on commit 473f5e1

Please sign in to comment.