Commit adc76fc9 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'net-second-round-of-netdevice-refcount-tracking'

Eric Dumazet says:

====================
net: second round of netdevice refcount tracking

The most interesting part of this series is probably
("inet: add net device refcount tracker to struct fib_nh_common")
but only future reports will confirm this guess.
====================

Link: https://lore.kernel.org/r/20211207013039.1868645-1-eric.dumazet@gmail.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 59d58d93 ada066b2
...@@ -225,7 +225,7 @@ static void eql_kill_one_slave(slave_queue_t *queue, slave_t *slave) ...@@ -225,7 +225,7 @@ static void eql_kill_one_slave(slave_queue_t *queue, slave_t *slave)
list_del(&slave->list); list_del(&slave->list);
queue->num_slaves--; queue->num_slaves--;
slave->dev->flags &= ~IFF_SLAVE; slave->dev->flags &= ~IFF_SLAVE;
dev_put(slave->dev); dev_put_track(slave->dev, &slave->dev_tracker);
kfree(slave); kfree(slave);
} }
...@@ -399,7 +399,7 @@ static int __eql_insert_slave(slave_queue_t *queue, slave_t *slave) ...@@ -399,7 +399,7 @@ static int __eql_insert_slave(slave_queue_t *queue, slave_t *slave)
if (duplicate_slave) if (duplicate_slave)
eql_kill_one_slave(queue, duplicate_slave); eql_kill_one_slave(queue, duplicate_slave);
dev_hold(slave->dev); dev_hold_track(slave->dev, &slave->dev_tracker, GFP_ATOMIC);
list_add(&slave->list, &queue->all_slaves); list_add(&slave->list, &queue->all_slaves);
queue->num_slaves++; queue->num_slaves++;
slave->dev->flags |= IFF_SLAVE; slave->dev->flags |= IFF_SLAVE;
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
typedef struct slave { typedef struct slave {
struct list_head list; struct list_head list;
struct net_device *dev; struct net_device *dev;
netdevice_tracker dev_tracker;
long priority; long priority;
long priority_bps; long priority_bps;
long priority_Bps; long priority_Bps;
......
...@@ -162,6 +162,7 @@ struct netpoll; ...@@ -162,6 +162,7 @@ struct netpoll;
* @vlan_id: VLAN identifier * @vlan_id: VLAN identifier
* @flags: device flags * @flags: device flags
* @real_dev: underlying netdevice * @real_dev: underlying netdevice
* @dev_tracker: refcount tracker for @real_dev reference
* @real_dev_addr: address of underlying netdevice * @real_dev_addr: address of underlying netdevice
* @dent: proc dir entry * @dent: proc dir entry
* @vlan_pcpu_stats: ptr to percpu rx stats * @vlan_pcpu_stats: ptr to percpu rx stats
...@@ -177,6 +178,8 @@ struct vlan_dev_priv { ...@@ -177,6 +178,8 @@ struct vlan_dev_priv {
u16 flags; u16 flags;
struct net_device *real_dev; struct net_device *real_dev;
netdevice_tracker dev_tracker;
unsigned char real_dev_addr[ETH_ALEN]; unsigned char real_dev_addr[ETH_ALEN];
struct proc_dir_entry *dent; struct proc_dir_entry *dent;
......
...@@ -1951,6 +1951,7 @@ enum netdev_ml_priv_type { ...@@ -1951,6 +1951,7 @@ enum netdev_ml_priv_type {
* *
* @dev_addr_shadow: Copy of @dev_addr to catch direct writes. * @dev_addr_shadow: Copy of @dev_addr to catch direct writes.
* @linkwatch_dev_tracker: refcount tracker used by linkwatch. * @linkwatch_dev_tracker: refcount tracker used by linkwatch.
* @watchdog_dev_tracker: refcount tracker used by watchdog.
* *
* FIXME: cleanup struct net_device such that network protocol info * FIXME: cleanup struct net_device such that network protocol info
* moves out. * moves out.
...@@ -2282,6 +2283,7 @@ struct net_device { ...@@ -2282,6 +2283,7 @@ struct net_device {
u8 dev_addr_shadow[MAX_ADDR_LEN]; u8 dev_addr_shadow[MAX_ADDR_LEN];
netdevice_tracker linkwatch_dev_tracker; netdevice_tracker linkwatch_dev_tracker;
netdevice_tracker watchdog_dev_tracker;
}; };
#define to_net_dev(d) container_of(d, struct net_device, dev) #define to_net_dev(d) container_of(d, struct net_device, dev)
......
...@@ -229,7 +229,10 @@ struct ctl_table; ...@@ -229,7 +229,10 @@ struct ctl_table;
typedef struct ax25_dev { typedef struct ax25_dev {
struct ax25_dev *next; struct ax25_dev *next;
struct net_device *dev; struct net_device *dev;
netdevice_tracker dev_tracker;
struct net_device *forward; struct net_device *forward;
struct ctl_table_header *sysheader; struct ctl_table_header *sysheader;
int values[AX25_MAX_VALUES]; int values[AX25_MAX_VALUES];
......
...@@ -79,6 +79,7 @@ struct fnhe_hash_bucket { ...@@ -79,6 +79,7 @@ struct fnhe_hash_bucket {
struct fib_nh_common { struct fib_nh_common {
struct net_device *nhc_dev; struct net_device *nhc_dev;
netdevice_tracker nhc_dev_tracker;
int nhc_oif; int nhc_oif;
unsigned char nhc_scope; unsigned char nhc_scope;
u8 nhc_family; u8 nhc_family;
...@@ -111,6 +112,7 @@ struct fib_nh { ...@@ -111,6 +112,7 @@ struct fib_nh {
int nh_saddr_genid; int nh_saddr_genid;
#define fib_nh_family nh_common.nhc_family #define fib_nh_family nh_common.nhc_family
#define fib_nh_dev nh_common.nhc_dev #define fib_nh_dev nh_common.nhc_dev
#define fib_nh_dev_tracker nh_common.nhc_dev_tracker
#define fib_nh_oif nh_common.nhc_oif #define fib_nh_oif nh_common.nhc_oif
#define fib_nh_flags nh_common.nhc_flags #define fib_nh_flags nh_common.nhc_flags
#define fib_nh_lws nh_common.nhc_lwtstate #define fib_nh_lws nh_common.nhc_lwtstate
......
...@@ -38,6 +38,7 @@ struct llc_sock { ...@@ -38,6 +38,7 @@ struct llc_sock {
struct llc_addr laddr; /* lsap/mac pair */ struct llc_addr laddr; /* lsap/mac pair */
struct llc_addr daddr; /* dsap/mac pair */ struct llc_addr daddr; /* dsap/mac pair */
struct net_device *dev; /* device to send to remote */ struct net_device *dev; /* device to send to remote */
netdevice_tracker dev_tracker;
u32 copied_seq; /* head of yet unread data */ u32 copied_seq; /* head of yet unread data */
u8 retry_count; /* number of retries */ u8 retry_count; /* number of retries */
u8 ack_must_be_send; u8 ack_must_be_send;
......
...@@ -10,6 +10,7 @@ struct tcf_mirred { ...@@ -10,6 +10,7 @@ struct tcf_mirred {
int tcfm_eaction; int tcfm_eaction;
bool tcfm_mac_header_xmit; bool tcfm_mac_header_xmit;
struct net_device __rcu *tcfm_dev; struct net_device __rcu *tcfm_dev;
netdevice_tracker tcfm_dev_tracker;
struct list_head tcfm_list; struct list_head tcfm_list;
}; };
#define to_mirred(a) ((struct tcf_mirred *)a) #define to_mirred(a) ((struct tcf_mirred *)a)
......
...@@ -616,7 +616,7 @@ static int vlan_dev_init(struct net_device *dev) ...@@ -616,7 +616,7 @@ static int vlan_dev_init(struct net_device *dev)
return -ENOMEM; return -ENOMEM;
/* Get vlan's reference to real_dev */ /* Get vlan's reference to real_dev */
dev_hold(real_dev); dev_hold_track(real_dev, &vlan->dev_tracker, GFP_KERNEL);
return 0; return 0;
} }
...@@ -848,7 +848,7 @@ static void vlan_dev_free(struct net_device *dev) ...@@ -848,7 +848,7 @@ static void vlan_dev_free(struct net_device *dev)
vlan->vlan_pcpu_stats = NULL; vlan->vlan_pcpu_stats = NULL;
/* Get rid of the vlan's reference to real_dev */ /* Get rid of the vlan's reference to real_dev */
dev_put(vlan->real_dev); dev_put_track(vlan->real_dev, &vlan->dev_tracker);
} }
void vlan_setup(struct net_device *dev) void vlan_setup(struct net_device *dev)
......
...@@ -58,7 +58,7 @@ void ax25_dev_device_up(struct net_device *dev) ...@@ -58,7 +58,7 @@ void ax25_dev_device_up(struct net_device *dev)
dev->ax25_ptr = ax25_dev; dev->ax25_ptr = ax25_dev;
ax25_dev->dev = dev; ax25_dev->dev = dev;
dev_hold(dev); dev_hold_track(dev, &ax25_dev->dev_tracker, GFP_ATOMIC);
ax25_dev->forward = NULL; ax25_dev->forward = NULL;
ax25_dev->values[AX25_VALUES_IPDEFMODE] = AX25_DEF_IPDEFMODE; ax25_dev->values[AX25_VALUES_IPDEFMODE] = AX25_DEF_IPDEFMODE;
...@@ -114,7 +114,7 @@ void ax25_dev_device_down(struct net_device *dev) ...@@ -114,7 +114,7 @@ void ax25_dev_device_down(struct net_device *dev)
ax25_dev_list = s->next; ax25_dev_list = s->next;
spin_unlock_bh(&ax25_dev_lock); spin_unlock_bh(&ax25_dev_lock);
dev->ax25_ptr = NULL; dev->ax25_ptr = NULL;
dev_put(dev); dev_put_track(dev, &ax25_dev->dev_tracker);
kfree(ax25_dev); kfree(ax25_dev);
return; return;
} }
...@@ -124,7 +124,7 @@ void ax25_dev_device_down(struct net_device *dev) ...@@ -124,7 +124,7 @@ void ax25_dev_device_down(struct net_device *dev)
s->next = ax25_dev->next; s->next = ax25_dev->next;
spin_unlock_bh(&ax25_dev_lock); spin_unlock_bh(&ax25_dev_lock);
dev->ax25_ptr = NULL; dev->ax25_ptr = NULL;
dev_put(dev); dev_put_track(dev, &ax25_dev->dev_tracker);
kfree(ax25_dev); kfree(ax25_dev);
return; return;
} }
...@@ -188,7 +188,7 @@ void __exit ax25_dev_free(void) ...@@ -188,7 +188,7 @@ void __exit ax25_dev_free(void)
ax25_dev = ax25_dev_list; ax25_dev = ax25_dev_list;
while (ax25_dev != NULL) { while (ax25_dev != NULL) {
s = ax25_dev; s = ax25_dev;
dev_put(ax25_dev->dev); dev_put_track(ax25_dev->dev, &ax25_dev->dev_tracker);
ax25_dev = ax25_dev->next; ax25_dev = ax25_dev->next;
kfree(s); kfree(s);
} }
......
...@@ -274,7 +274,7 @@ static void destroy_nbp(struct net_bridge_port *p) ...@@ -274,7 +274,7 @@ static void destroy_nbp(struct net_bridge_port *p)
p->br = NULL; p->br = NULL;
p->dev = NULL; p->dev = NULL;
dev_put(dev); dev_put_track(dev, &p->dev_tracker);
kobject_put(&p->kobj); kobject_put(&p->kobj);
} }
...@@ -423,7 +423,7 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br, ...@@ -423,7 +423,7 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br,
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
p->br = br; p->br = br;
dev_hold(dev); dev_hold_track(dev, &p->dev_tracker, GFP_KERNEL);
p->dev = dev; p->dev = dev;
p->path_cost = port_cost(dev); p->path_cost = port_cost(dev);
p->priority = 0x8000 >> BR_PORT_BITS; p->priority = 0x8000 >> BR_PORT_BITS;
...@@ -434,7 +434,7 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br, ...@@ -434,7 +434,7 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br,
br_stp_port_timer_init(p); br_stp_port_timer_init(p);
err = br_multicast_add_port(p); err = br_multicast_add_port(p);
if (err) { if (err) {
dev_put(dev); dev_put_track(dev, &p->dev_tracker);
kfree(p); kfree(p);
p = ERR_PTR(err); p = ERR_PTR(err);
} }
......
...@@ -344,6 +344,7 @@ struct net_bridge_mdb_entry { ...@@ -344,6 +344,7 @@ struct net_bridge_mdb_entry {
struct net_bridge_port { struct net_bridge_port {
struct net_bridge *br; struct net_bridge *br;
struct net_device *dev; struct net_device *dev;
netdevice_tracker dev_tracker;
struct list_head list; struct list_head list;
unsigned long flags; unsigned long flags;
......
...@@ -410,6 +410,7 @@ struct pktgen_dev { ...@@ -410,6 +410,7 @@ struct pktgen_dev {
* device name (not when the inject is * device name (not when the inject is
* started as it used to do.) * started as it used to do.)
*/ */
netdevice_tracker dev_tracker;
char odevname[32]; char odevname[32];
struct flow_state *flows; struct flow_state *flows;
unsigned int cflows; /* Concurrent flows (config) */ unsigned int cflows; /* Concurrent flows (config) */
...@@ -2099,7 +2100,7 @@ static int pktgen_setup_dev(const struct pktgen_net *pn, ...@@ -2099,7 +2100,7 @@ static int pktgen_setup_dev(const struct pktgen_net *pn,
/* Clean old setups */ /* Clean old setups */
if (pkt_dev->odev) { if (pkt_dev->odev) {
dev_put(pkt_dev->odev); dev_put_track(pkt_dev->odev, &pkt_dev->dev_tracker);
pkt_dev->odev = NULL; pkt_dev->odev = NULL;
} }
...@@ -2117,6 +2118,7 @@ static int pktgen_setup_dev(const struct pktgen_net *pn, ...@@ -2117,6 +2118,7 @@ static int pktgen_setup_dev(const struct pktgen_net *pn,
err = -ENETDOWN; err = -ENETDOWN;
} else { } else {
pkt_dev->odev = odev; pkt_dev->odev = odev;
netdev_tracker_alloc(odev, &pkt_dev->dev_tracker, GFP_KERNEL);
return 0; return 0;
} }
...@@ -3805,7 +3807,7 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname) ...@@ -3805,7 +3807,7 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname)
return add_dev_to_thread(t, pkt_dev); return add_dev_to_thread(t, pkt_dev);
out2: out2:
dev_put(pkt_dev->odev); dev_put_track(pkt_dev->odev, &pkt_dev->dev_tracker);
out1: out1:
#ifdef CONFIG_XFRM #ifdef CONFIG_XFRM
free_SAs(pkt_dev); free_SAs(pkt_dev);
...@@ -3899,7 +3901,7 @@ static int pktgen_remove_device(struct pktgen_thread *t, ...@@ -3899,7 +3901,7 @@ static int pktgen_remove_device(struct pktgen_thread *t,
/* Dis-associate from the interface */ /* Dis-associate from the interface */
if (pkt_dev->odev) { if (pkt_dev->odev) {
dev_put(pkt_dev->odev); dev_put_track(pkt_dev->odev, &pkt_dev->dev_tracker);
pkt_dev->odev = NULL; pkt_dev->odev = NULL;
} }
......
...@@ -141,6 +141,7 @@ int ethnl_parse_header_dev_get(struct ethnl_req_info *req_info, ...@@ -141,6 +141,7 @@ int ethnl_parse_header_dev_get(struct ethnl_req_info *req_info,
} }
req_info->dev = dev; req_info->dev = dev;
netdev_tracker_alloc(dev, &req_info->dev_tracker, GFP_KERNEL);
req_info->flags = flags; req_info->flags = flags;
return 0; return 0;
} }
...@@ -399,7 +400,7 @@ static int ethnl_default_doit(struct sk_buff *skb, struct genl_info *info) ...@@ -399,7 +400,7 @@ static int ethnl_default_doit(struct sk_buff *skb, struct genl_info *info)
ops->cleanup_data(reply_data); ops->cleanup_data(reply_data);
genlmsg_end(rskb, reply_payload); genlmsg_end(rskb, reply_payload);
dev_put(req_info->dev); dev_put_track(req_info->dev, &req_info->dev_tracker);
kfree(reply_data); kfree(reply_data);
kfree(req_info); kfree(req_info);
return genlmsg_reply(rskb, info); return genlmsg_reply(rskb, info);
...@@ -411,7 +412,7 @@ static int ethnl_default_doit(struct sk_buff *skb, struct genl_info *info) ...@@ -411,7 +412,7 @@ static int ethnl_default_doit(struct sk_buff *skb, struct genl_info *info)
if (ops->cleanup_data) if (ops->cleanup_data)
ops->cleanup_data(reply_data); ops->cleanup_data(reply_data);
err_dev: err_dev:
dev_put(req_info->dev); dev_put_track(req_info->dev, &req_info->dev_tracker);
kfree(reply_data); kfree(reply_data);
kfree(req_info); kfree(req_info);
return ret; return ret;
...@@ -547,7 +548,7 @@ static int ethnl_default_start(struct netlink_callback *cb) ...@@ -547,7 +548,7 @@ static int ethnl_default_start(struct netlink_callback *cb)
* same parser as for non-dump (doit) requests is used, it * same parser as for non-dump (doit) requests is used, it
* would take reference to the device if it finds one * would take reference to the device if it finds one
*/ */
dev_put(req_info->dev); dev_put_track(req_info->dev, &req_info->dev_tracker);
req_info->dev = NULL; req_info->dev = NULL;
} }
if (ret < 0) if (ret < 0)
...@@ -624,6 +625,7 @@ static void ethnl_default_notify(struct net_device *dev, unsigned int cmd, ...@@ -624,6 +625,7 @@ static void ethnl_default_notify(struct net_device *dev, unsigned int cmd,
} }
req_info->dev = dev; req_info->dev = dev;
netdev_tracker_alloc(dev, &req_info->dev_tracker, GFP_KERNEL);
req_info->flags |= ETHTOOL_FLAG_COMPACT_BITSETS; req_info->flags |= ETHTOOL_FLAG_COMPACT_BITSETS;
ethnl_init_reply_data(reply_data, ops, dev); ethnl_init_reply_data(reply_data, ops, dev);
......
...@@ -222,6 +222,7 @@ static inline unsigned int ethnl_reply_header_size(void) ...@@ -222,6 +222,7 @@ static inline unsigned int ethnl_reply_header_size(void)
/** /**
* struct ethnl_req_info - base type of request information for GET requests * struct ethnl_req_info - base type of request information for GET requests
* @dev: network device the request is for (may be null) * @dev: network device the request is for (may be null)
* @dev_tracker: refcount tracker for @dev reference
* @flags: request flags common for all request types * @flags: request flags common for all request types
* *
* This is a common base for request specific structures holding data from * This is a common base for request specific structures holding data from
...@@ -230,6 +231,7 @@ static inline unsigned int ethnl_reply_header_size(void) ...@@ -230,6 +231,7 @@ static inline unsigned int ethnl_reply_header_size(void)
*/ */
struct ethnl_req_info { struct ethnl_req_info {
struct net_device *dev; struct net_device *dev;
netdevice_tracker dev_tracker;
u32 flags; u32 flags;
}; };
......
...@@ -208,7 +208,7 @@ static void rt_fibinfo_free_cpus(struct rtable __rcu * __percpu *rtp) ...@@ -208,7 +208,7 @@ static void rt_fibinfo_free_cpus(struct rtable __rcu * __percpu *rtp)
void fib_nh_common_release(struct fib_nh_common *nhc) void fib_nh_common_release(struct fib_nh_common *nhc)
{ {
dev_put(nhc->nhc_dev); dev_put_track(nhc->nhc_dev, &nhc->nhc_dev_tracker);
lwtstate_put(nhc->nhc_lwtstate); lwtstate_put(nhc->nhc_lwtstate);
rt_fibinfo_free_cpus(nhc->nhc_pcpu_rth_output); rt_fibinfo_free_cpus(nhc->nhc_pcpu_rth_output);
rt_fibinfo_free(&nhc->nhc_rth_input); rt_fibinfo_free(&nhc->nhc_rth_input);
...@@ -1006,7 +1006,7 @@ static int fib_check_nh_v6_gw(struct net *net, struct fib_nh *nh, ...@@ -1006,7 +1006,7 @@ static int fib_check_nh_v6_gw(struct net *net, struct fib_nh *nh,
err = ipv6_stub->fib6_nh_init(net, &fib6_nh, &cfg, GFP_KERNEL, extack); err = ipv6_stub->fib6_nh_init(net, &fib6_nh, &cfg, GFP_KERNEL, extack);
if (!err) { if (!err) {
nh->fib_nh_dev = fib6_nh.fib_nh_dev; nh->fib_nh_dev = fib6_nh.fib_nh_dev;
dev_hold(nh->fib_nh_dev); dev_hold_track(nh->fib_nh_dev, &nh->fib_nh_dev_tracker, GFP_KERNEL);
nh->fib_nh_oif = nh->fib_nh_dev->ifindex; nh->fib_nh_oif = nh->fib_nh_dev->ifindex;
nh->fib_nh_scope = RT_SCOPE_LINK; nh->fib_nh_scope = RT_SCOPE_LINK;
...@@ -1090,7 +1090,7 @@ static int fib_check_nh_v4_gw(struct net *net, struct fib_nh *nh, u32 table, ...@@ -1090,7 +1090,7 @@ static int fib_check_nh_v4_gw(struct net *net, struct fib_nh *nh, u32 table,
if (!netif_carrier_ok(dev)) if (!netif_carrier_ok(dev))
nh->fib_nh_flags |= RTNH_F_LINKDOWN; nh->fib_nh_flags |= RTNH_F_LINKDOWN;
nh->fib_nh_dev = dev; nh->fib_nh_dev = dev;
dev_hold(dev); dev_hold_track(dev, &nh->fib_nh_dev_tracker, GFP_ATOMIC);
nh->fib_nh_scope = RT_SCOPE_LINK; nh->fib_nh_scope = RT_SCOPE_LINK;
return 0; return 0;
} }
...@@ -1144,7 +1144,7 @@ static int fib_check_nh_v4_gw(struct net *net, struct fib_nh *nh, u32 table, ...@@ -1144,7 +1144,7 @@ static int fib_check_nh_v4_gw(struct net *net, struct fib_nh *nh, u32 table,
"No egress device for nexthop gateway"); "No egress device for nexthop gateway");
goto out; goto out;
} }
dev_hold(dev); dev_hold_track(dev, &nh->fib_nh_dev_tracker, GFP_ATOMIC);
if (!netif_carrier_ok(dev)) if (!netif_carrier_ok(dev))
nh->fib_nh_flags |= RTNH_F_LINKDOWN; nh->fib_nh_flags |= RTNH_F_LINKDOWN;
err = (dev->flags & IFF_UP) ? 0 : -ENETDOWN; err = (dev->flags & IFF_UP) ? 0 : -ENETDOWN;
...@@ -1178,7 +1178,7 @@ static int fib_check_nh_nongw(struct net *net, struct fib_nh *nh, ...@@ -1178,7 +1178,7 @@ static int fib_check_nh_nongw(struct net *net, struct fib_nh *nh,
} }
nh->fib_nh_dev = in_dev->dev; nh->fib_nh_dev = in_dev->dev;
dev_hold(nh->fib_nh_dev); dev_hold_track(nh->fib_nh_dev, &nh->fib_nh_dev_tracker, GFP_ATOMIC);
nh->fib_nh_scope = RT_SCOPE_HOST; nh->fib_nh_scope = RT_SCOPE_HOST;
if (!netif_carrier_ok(nh->fib_nh_dev)) if (!netif_carrier_ok(nh->fib_nh_dev))
nh->fib_nh_flags |= RTNH_F_LINKDOWN; nh->fib_nh_flags |= RTNH_F_LINKDOWN;
...@@ -1508,6 +1508,8 @@ struct fib_info *fib_create_info(struct fib_config *cfg, ...@@ -1508,6 +1508,8 @@ struct fib_info *fib_create_info(struct fib_config *cfg,
err = -ENODEV; err = -ENODEV;
if (!nh->fib_nh_dev) if (!nh->fib_nh_dev)
goto failure; goto failure;
netdev_tracker_alloc(nh->fib_nh_dev, &nh->fib_nh_dev_tracker,
GFP_KERNEL);
} else { } else {
int linkdown = 0; int linkdown = 0;
......
...@@ -3628,6 +3628,8 @@ int fib6_nh_init(struct net *net, struct fib6_nh *fib6_nh, ...@@ -3628,6 +3628,8 @@ int fib6_nh_init(struct net *net, struct fib6_nh *fib6_nh,
} }
fib6_nh->fib_nh_dev = dev; 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; fib6_nh->fib_nh_oif = dev->ifindex;
err = 0; err = 0;
out: out:
......
...@@ -224,7 +224,7 @@ static int llc_ui_release(struct socket *sock) ...@@ -224,7 +224,7 @@ static int llc_ui_release(struct socket *sock)
} else { } else {
release_sock(sk); release_sock(sk);
} }
dev_put(llc->dev); dev_put_track(llc->dev, &llc->dev_tracker);
sock_put(sk); sock_put(sk);
llc_sk_free(sk); llc_sk_free(sk);
out: out:
...@@ -295,6 +295,7 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr) ...@@ -295,6 +295,7 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr)
llc->dev = dev_getfirstbyhwtype(&init_net, addr->sllc_arphrd); llc->dev = dev_getfirstbyhwtype(&init_net, addr->sllc_arphrd);
if (!llc->dev) if (!llc->dev)
goto out; goto out;
netdev_tracker_alloc(llc->dev, &llc->dev_tracker, GFP_KERNEL);
rc = -EUSERS; rc = -EUSERS;
llc->laddr.lsap = llc_ui_autoport(); llc->laddr.lsap = llc_ui_autoport();
if (!llc->laddr.lsap) if (!llc->laddr.lsap)
...@@ -362,7 +363,7 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen) ...@@ -362,7 +363,7 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen)
} else } else
llc->dev = dev_getbyhwaddr_rcu(&init_net, addr->sllc_arphrd, llc->dev = dev_getbyhwaddr_rcu(&init_net, addr->sllc_arphrd,
addr->sllc_mac); addr->sllc_mac);
dev_hold(llc->dev); dev_hold_track(llc->dev, &llc->dev_tracker, GFP_ATOMIC);
rcu_read_unlock(); rcu_read_unlock();
if (!llc->dev) if (!llc->dev)
goto out; goto out;
......
...@@ -82,7 +82,7 @@ struct vport *ovs_netdev_link(struct vport *vport, const char *name) ...@@ -82,7 +82,7 @@ struct vport *ovs_netdev_link(struct vport *vport, const char *name)
err = -ENODEV; err = -ENODEV;
goto error_free_vport; goto error_free_vport;
} }
netdev_tracker_alloc(vport->dev, &vport->dev_tracker, GFP_KERNEL);
if (vport->dev->flags & IFF_LOOPBACK || if (vport->dev->flags & IFF_LOOPBACK ||
(vport->dev->type != ARPHRD_ETHER && (vport->dev->type != ARPHRD_ETHER &&
vport->dev->type != ARPHRD_NONE) || vport->dev->type != ARPHRD_NONE) ||
...@@ -115,7 +115,7 @@ struct vport *ovs_netdev_link(struct vport *vport, const char *name) ...@@ -115,7 +115,7 @@ struct vport *ovs_netdev_link(struct vport *vport, const char *name)
error_unlock: error_unlock:
rtnl_unlock(); rtnl_unlock();
error_put: error_put:
dev_put(vport->dev); dev_put_track(vport->dev, &vport->dev_tracker);
error_free_vport: error_free_vport:
ovs_vport_free(vport); ovs_vport_free(vport);
return ERR_PTR(err); return ERR_PTR(err);
...@@ -137,7 +137,7 @@ static void vport_netdev_free(struct rcu_head *rcu) ...@@ -137,7 +137,7 @@ static void vport_netdev_free(struct rcu_head *rcu)
{ {
struct vport *vport = container_of(rcu, struct vport, rcu); struct vport *vport = container_of(rcu, struct vport, rcu);
dev_put(vport->dev); dev_put_track(vport->dev, &vport->dev_tracker);
ovs_vport_free(vport); ovs_vport_free(vport);
} }
...@@ -173,7 +173,7 @@ void ovs_netdev_tunnel_destroy(struct vport *vport) ...@@ -173,7 +173,7 @@ void ovs_netdev_tunnel_destroy(struct vport *vport)
*/ */
if (vport->dev->reg_state == NETREG_REGISTERED) if (vport->dev->reg_state == NETREG_REGISTERED)
rtnl_delete_link(vport->dev); rtnl_delete_link(vport->dev);
dev_put(vport->dev); dev_put_track(vport->dev, &vport->dev_tracker);
vport->dev = NULL; vport->dev = NULL;
rtnl_unlock(); rtnl_unlock();
......
...@@ -58,6 +58,7 @@ struct vport_portids { ...@@ -58,6 +58,7 @@ struct vport_portids {
/** /**
* struct vport - one port within a datapath * struct vport - one port within a datapath
* @dev: Pointer to net_device. * @dev: Pointer to net_device.
* @dev_tracker: refcount tracker for @dev reference
* @dp: Datapath to which this port belongs. * @dp: Datapath to which this port belongs.
* @upcall_portids: RCU protected 'struct vport_portids'. * @upcall_portids: RCU protected 'struct vport_portids'.
* @port_no: Index into @dp's @ports array. * @port_no: Index into @dp's @ports array.
...@@ -69,6 +70,7 @@ struct vport_portids { ...@@ -69,6 +70,7 @@ struct vport_portids {
*/ */
struct vport { struct vport {
struct net_device *dev; struct net_device *dev;
netdevice_tracker dev_tracker;
struct datapath *dp; struct datapath *dp;
struct vport_portids __rcu *upcall_portids; struct vport_portids __rcu *upcall_portids;
u16 port_no; u16 port_no;
......
...@@ -79,7 +79,7 @@ static void tcf_mirred_release(struct tc_action *a) ...@@ -79,7 +79,7 @@ static void tcf_mirred_release(struct tc_action *a)
/* last reference to action, no need to lock */ /* last reference to action, no need to lock */
dev = rcu_dereference_protected(m->tcfm_dev, 1); dev = rcu_dereference_protected(m->tcfm_dev, 1);
dev_put(dev); dev_put_track(dev, &m->tcfm_dev_tracker);
} }
static const struct nla_policy mirred_policy[TCA_MIRRED_MAX + 1] = { static const struct nla_policy mirred_policy[TCA_MIRRED_MAX + 1] = {
...@@ -101,7 +101,6 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla, ...@@ -101,7 +101,6 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
bool mac_header_xmit = false; bool mac_header_xmit = false;
struct tc_mirred *parm; struct tc_mirred *parm;
struct tcf_mirred *m; struct tcf_mirred *m;
struct net_device *dev;
bool exists = false; bool exists = false;
int ret, err; int ret, err;
u32 index; u32 index;
...@@ -171,16 +170,19 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla, ...@@ -171,16 +170,19 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
spin_lock_bh(&m->tcf_lock); spin_lock_bh(&m->tcf_lock);
if (parm->ifindex) { if (parm->ifindex) {
dev = dev_get_by_index(net, parm->ifindex); struct net_device *odev, *ndev;
if (!dev) {
ndev = dev_get_by_index(net, parm->ifindex);
if (!ndev) {
spin_unlock_bh(&m->tcf_lock); spin_unlock_bh(&m->tcf_lock);
err = -ENODEV; err = -ENODEV;
goto put_chain; goto put_chain;
} }
mac_header_xmit = dev_is_mac_header_xmit(dev); mac_header_xmit = dev_is_mac_header_xmit(ndev);
dev = rcu_replace_pointer(m->tcfm_dev, dev, odev = rcu_replace_pointer(m->tcfm_dev, ndev,
lockdep_is_held(&m->tcf_lock)); lockdep_is_held(&m->tcf_lock));
dev_put(dev); dev_put_track(odev, &m->tcfm_dev_tracker);
netdev_tracker_alloc(ndev, &m->tcfm_dev_tracker, GFP_ATOMIC);
m->tcfm_mac_header_xmit = mac_header_xmit; m->tcfm_mac_header_xmit = mac_header_xmit;
} }
goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch); goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch);
...@@ -400,7 +402,7 @@ static int mirred_device_event(struct notifier_block *unused, ...@@ -400,7 +402,7 @@ static int mirred_device_event(struct notifier_block *unused,
list_for_each_entry(m, &mirred_list, tcfm_list) { list_for_each_entry(m, &mirred_list, tcfm_list) {
spin_lock_bh(&m->tcf_lock); spin_lock_bh(&m->tcf_lock);
if (tcf_mirred_dev_dereference(m) == dev) { if (tcf_mirred_dev_dereference(m) == dev) {
dev_put(dev); dev_put_track(dev, &m->tcfm_dev_tracker);
/* Note : no rcu grace period necessary, as /* Note : no rcu grace period necessary, as
* net_device are already rcu protected. * net_device are already rcu protected.
*/ */
......
...@@ -499,6 +499,7 @@ EXPORT_SYMBOL(netif_tx_unlock); ...@@ -499,6 +499,7 @@ EXPORT_SYMBOL(netif_tx_unlock);
static void dev_watchdog(struct timer_list *t) static void dev_watchdog(struct timer_list *t)
{ {
struct net_device *dev = from_timer(dev, t, watchdog_timer); struct net_device *dev = from_timer(dev, t, watchdog_timer);
bool release = true;
spin_lock(&dev->tx_global_lock); spin_lock(&dev->tx_global_lock);
if (!qdisc_tx_is_noop(dev)) { if (!qdisc_tx_is_noop(dev)) {
...@@ -534,12 +535,13 @@ static void dev_watchdog(struct timer_list *t) ...@@ -534,12 +535,13 @@ static void dev_watchdog(struct timer_list *t)
if (!mod_timer(&dev->watchdog_timer, if (!mod_timer(&dev->watchdog_timer,
round_jiffies(jiffies + round_jiffies(jiffies +
dev->watchdog_timeo))) dev->watchdog_timeo)))
dev_hold(dev); release = false;
} }
} }
spin_unlock(&dev->tx_global_lock); spin_unlock(&dev->tx_global_lock);
dev_put(dev); if (release)
dev_put_track(dev, &dev->watchdog_dev_tracker);
} }
void __netdev_watchdog_up(struct net_device *dev) void __netdev_watchdog_up(struct net_device *dev)
...@@ -549,7 +551,7 @@ void __netdev_watchdog_up(struct net_device *dev) ...@@ -549,7 +551,7 @@ void __netdev_watchdog_up(struct net_device *dev)
dev->watchdog_timeo = 5*HZ; dev->watchdog_timeo = 5*HZ;
if (!mod_timer(&dev->watchdog_timer, if (!mod_timer(&dev->watchdog_timer,
round_jiffies(jiffies + dev->watchdog_timeo))) round_jiffies(jiffies + dev->watchdog_timeo)))
dev_hold(dev); dev_hold_track(dev, &dev->watchdog_dev_tracker, GFP_ATOMIC);
} }
} }
EXPORT_SYMBOL_GPL(__netdev_watchdog_up); EXPORT_SYMBOL_GPL(__netdev_watchdog_up);
...@@ -563,7 +565,7 @@ static void dev_watchdog_down(struct net_device *dev) ...@@ -563,7 +565,7 @@ static void dev_watchdog_down(struct net_device *dev)
{ {
netif_tx_lock_bh(dev); netif_tx_lock_bh(dev);
if (del_timer(&dev->watchdog_timer)) if (del_timer(&dev->watchdog_timer))
dev_put(dev); dev_put_track(dev, &dev->watchdog_dev_tracker);
netif_tx_unlock_bh(dev); netif_tx_unlock_bh(dev);
} }
......
...@@ -64,6 +64,7 @@ struct smc_pnetentry { ...@@ -64,6 +64,7 @@ struct smc_pnetentry {
struct { struct {
char eth_name[IFNAMSIZ + 1]; char eth_name[IFNAMSIZ + 1];
struct net_device *ndev; struct net_device *ndev;
netdevice_tracker dev_tracker;
}; };
struct { struct {
char ib_name[IB_DEVICE_NAME_MAX + 1]; char ib_name[IB_DEVICE_NAME_MAX + 1];
...@@ -119,7 +120,7 @@ static int smc_pnet_remove_by_pnetid(struct net *net, char *pnet_name) ...@@ -119,7 +120,7 @@ static int smc_pnet_remove_by_pnetid(struct net *net, char *pnet_name)
smc_pnet_match(pnetelem->pnet_name, pnet_name)) { smc_pnet_match(pnetelem->pnet_name, pnet_name)) {
list_del(&pnetelem->list); list_del(&pnetelem->list);
if (pnetelem->type == SMC_PNET_ETH && pnetelem->ndev) { if (pnetelem->type == SMC_PNET_ETH && pnetelem->ndev) {
dev_put(pnetelem->ndev); dev_put_track(pnetelem->ndev, &pnetelem->dev_tracker);
pr_warn_ratelimited("smc: net device %s " pr_warn_ratelimited("smc: net device %s "
"erased user defined " "erased user defined "
"pnetid %.16s\n", "pnetid %.16s\n",
...@@ -195,7 +196,7 @@ static int smc_pnet_add_by_ndev(struct net_device *ndev) ...@@ -195,7 +196,7 @@ static int smc_pnet_add_by_ndev(struct net_device *ndev)
list_for_each_entry_safe(pnetelem, tmp_pe, &pnettable->pnetlist, list) { list_for_each_entry_safe(pnetelem, tmp_pe, &pnettable->pnetlist, list) {
if (pnetelem->type == SMC_PNET_ETH && !pnetelem->ndev && if (pnetelem->type == SMC_PNET_ETH && !pnetelem->ndev &&
!strncmp(pnetelem->eth_name, ndev->name, IFNAMSIZ)) { !strncmp(pnetelem->eth_name, ndev->name, IFNAMSIZ)) {
dev_hold(ndev); dev_hold_track(ndev, &pnetelem->dev_tracker, GFP_ATOMIC);
pnetelem->ndev = ndev; pnetelem->ndev = ndev;
rc = 0; rc = 0;
pr_warn_ratelimited("smc: adding net device %s with " pr_warn_ratelimited("smc: adding net device %s with "
...@@ -226,7 +227,7 @@ static int smc_pnet_remove_by_ndev(struct net_device *ndev) ...@@ -226,7 +227,7 @@ static int smc_pnet_remove_by_ndev(struct net_device *ndev)
write_lock(&pnettable->lock); write_lock(&pnettable->lock);
list_for_each_entry_safe(pnetelem, tmp_pe, &pnettable->pnetlist, list) { list_for_each_entry_safe(pnetelem, tmp_pe, &pnettable->pnetlist, list) {
if (pnetelem->type == SMC_PNET_ETH && pnetelem->ndev == ndev) { if (pnetelem->type == SMC_PNET_ETH && pnetelem->ndev == ndev) {
dev_put(pnetelem->ndev); dev_put_track(pnetelem->ndev, &pnetelem->dev_tracker);
pnetelem->ndev = NULL; pnetelem->ndev = NULL;
rc = 0; rc = 0;
pr_warn_ratelimited("smc: removing net device %s with " pr_warn_ratelimited("smc: removing net device %s with "
...@@ -368,7 +369,7 @@ static int smc_pnet_add_eth(struct smc_pnettable *pnettable, struct net *net, ...@@ -368,7 +369,7 @@ static int smc_pnet_add_eth(struct smc_pnettable *pnettable, struct net *net,
memcpy(new_pe->pnet_name, pnet_name, SMC_MAX_PNETID_LEN); memcpy(new_pe->pnet_name, pnet_name, SMC_MAX_PNETID_LEN);
strncpy(new_pe->eth_name, eth_name, IFNAMSIZ); strncpy(new_pe->eth_name, eth_name, IFNAMSIZ);
new_pe->ndev = ndev; new_pe->ndev = ndev;
netdev_tracker_alloc(ndev, &new_pe->dev_tracker, GFP_KERNEL);
rc = -EEXIST; rc = -EEXIST;
new_netdev = true; new_netdev = true;
write_lock(&pnettable->lock); write_lock(&pnettable->lock);
......
...@@ -28,6 +28,7 @@ typedef void switchdev_deferred_func_t(struct net_device *dev, ...@@ -28,6 +28,7 @@ typedef void switchdev_deferred_func_t(struct net_device *dev,
struct switchdev_deferred_item { struct switchdev_deferred_item {
struct list_head list; struct list_head list;
struct net_device *dev; struct net_device *dev;
netdevice_tracker dev_tracker;
switchdev_deferred_func_t *func; switchdev_deferred_func_t *func;
unsigned long data[]; unsigned long data[];
}; };
...@@ -63,7 +64,7 @@ void switchdev_deferred_process(void) ...@@ -63,7 +64,7 @@ void switchdev_deferred_process(void)
while ((dfitem = switchdev_deferred_dequeue())) { while ((dfitem = switchdev_deferred_dequeue())) {
dfitem->func(dfitem->dev, dfitem->data); dfitem->func(dfitem->dev, dfitem->data);
dev_put(dfitem->dev); dev_put_track(dfitem->dev, &dfitem->dev_tracker);
kfree(dfitem); kfree(dfitem);
} }
} }
...@@ -90,7 +91,7 @@ static int switchdev_deferred_enqueue(struct net_device *dev, ...@@ -90,7 +91,7 @@ static int switchdev_deferred_enqueue(struct net_device *dev,
dfitem->dev = dev; dfitem->dev = dev;
dfitem->func = func; dfitem->func = func;
memcpy(dfitem->data, data, data_len); memcpy(dfitem->data, data, data_len);
dev_hold(dev); dev_hold_track(dev, &dfitem->dev_tracker, GFP_ATOMIC);
spin_lock_bh(&deferred_lock); spin_lock_bh(&deferred_lock);
list_add_tail(&dfitem->list, &deferred); list_add_tail(&dfitem->list, &deferred);
spin_unlock_bh(&deferred_lock); spin_unlock_bh(&deferred_lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment