mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 20:22:09 +00:00
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.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
adc76fc97b
@ -225,7 +225,7 @@ static void eql_kill_one_slave(slave_queue_t *queue, slave_t *slave)
|
||||
list_del(&slave->list);
|
||||
queue->num_slaves--;
|
||||
slave->dev->flags &= ~IFF_SLAVE;
|
||||
dev_put(slave->dev);
|
||||
dev_put_track(slave->dev, &slave->dev_tracker);
|
||||
kfree(slave);
|
||||
}
|
||||
|
||||
@ -399,7 +399,7 @@ static int __eql_insert_slave(slave_queue_t *queue, slave_t *slave)
|
||||
if (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);
|
||||
queue->num_slaves++;
|
||||
slave->dev->flags |= IFF_SLAVE;
|
||||
|
@ -26,6 +26,7 @@
|
||||
typedef struct slave {
|
||||
struct list_head list;
|
||||
struct net_device *dev;
|
||||
netdevice_tracker dev_tracker;
|
||||
long priority;
|
||||
long priority_bps;
|
||||
long priority_Bps;
|
||||
|
@ -162,6 +162,7 @@ struct netpoll;
|
||||
* @vlan_id: VLAN identifier
|
||||
* @flags: device flags
|
||||
* @real_dev: underlying netdevice
|
||||
* @dev_tracker: refcount tracker for @real_dev reference
|
||||
* @real_dev_addr: address of underlying netdevice
|
||||
* @dent: proc dir entry
|
||||
* @vlan_pcpu_stats: ptr to percpu rx stats
|
||||
@ -177,6 +178,8 @@ struct vlan_dev_priv {
|
||||
u16 flags;
|
||||
|
||||
struct net_device *real_dev;
|
||||
netdevice_tracker dev_tracker;
|
||||
|
||||
unsigned char real_dev_addr[ETH_ALEN];
|
||||
|
||||
struct proc_dir_entry *dent;
|
||||
|
@ -1951,6 +1951,7 @@ enum netdev_ml_priv_type {
|
||||
*
|
||||
* @dev_addr_shadow: Copy of @dev_addr to catch direct writes.
|
||||
* @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
|
||||
* moves out.
|
||||
@ -2282,6 +2283,7 @@ struct net_device {
|
||||
|
||||
u8 dev_addr_shadow[MAX_ADDR_LEN];
|
||||
netdevice_tracker linkwatch_dev_tracker;
|
||||
netdevice_tracker watchdog_dev_tracker;
|
||||
};
|
||||
#define to_net_dev(d) container_of(d, struct net_device, dev)
|
||||
|
||||
|
@ -229,7 +229,10 @@ struct ctl_table;
|
||||
|
||||
typedef struct ax25_dev {
|
||||
struct ax25_dev *next;
|
||||
|
||||
struct net_device *dev;
|
||||
netdevice_tracker dev_tracker;
|
||||
|
||||
struct net_device *forward;
|
||||
struct ctl_table_header *sysheader;
|
||||
int values[AX25_MAX_VALUES];
|
||||
|
@ -79,6 +79,7 @@ struct fnhe_hash_bucket {
|
||||
|
||||
struct fib_nh_common {
|
||||
struct net_device *nhc_dev;
|
||||
netdevice_tracker nhc_dev_tracker;
|
||||
int nhc_oif;
|
||||
unsigned char nhc_scope;
|
||||
u8 nhc_family;
|
||||
@ -111,6 +112,7 @@ struct fib_nh {
|
||||
int nh_saddr_genid;
|
||||
#define fib_nh_family nh_common.nhc_family
|
||||
#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_flags nh_common.nhc_flags
|
||||
#define fib_nh_lws nh_common.nhc_lwtstate
|
||||
|
@ -38,6 +38,7 @@ struct llc_sock {
|
||||
struct llc_addr laddr; /* lsap/mac pair */
|
||||
struct llc_addr daddr; /* dsap/mac pair */
|
||||
struct net_device *dev; /* device to send to remote */
|
||||
netdevice_tracker dev_tracker;
|
||||
u32 copied_seq; /* head of yet unread data */
|
||||
u8 retry_count; /* number of retries */
|
||||
u8 ack_must_be_send;
|
||||
|
@ -10,6 +10,7 @@ struct tcf_mirred {
|
||||
int tcfm_eaction;
|
||||
bool tcfm_mac_header_xmit;
|
||||
struct net_device __rcu *tcfm_dev;
|
||||
netdevice_tracker tcfm_dev_tracker;
|
||||
struct list_head tcfm_list;
|
||||
};
|
||||
#define to_mirred(a) ((struct tcf_mirred *)a)
|
||||
|
@ -616,7 +616,7 @@ static int vlan_dev_init(struct net_device *dev)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Get vlan's reference to real_dev */
|
||||
dev_hold(real_dev);
|
||||
dev_hold_track(real_dev, &vlan->dev_tracker, GFP_KERNEL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -848,7 +848,7 @@ static void vlan_dev_free(struct net_device *dev)
|
||||
vlan->vlan_pcpu_stats = NULL;
|
||||
|
||||
/* 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)
|
||||
|
@ -58,7 +58,7 @@ void ax25_dev_device_up(struct net_device *dev)
|
||||
|
||||
dev->ax25_ptr = ax25_dev;
|
||||
ax25_dev->dev = dev;
|
||||
dev_hold(dev);
|
||||
dev_hold_track(dev, &ax25_dev->dev_tracker, GFP_ATOMIC);
|
||||
ax25_dev->forward = NULL;
|
||||
|
||||
ax25_dev->values[AX25_VALUES_IPDEFMODE] = AX25_DEF_IPDEFMODE;
|
||||
@ -114,7 +114,7 @@ void ax25_dev_device_down(struct net_device *dev)
|
||||
ax25_dev_list = s->next;
|
||||
spin_unlock_bh(&ax25_dev_lock);
|
||||
dev->ax25_ptr = NULL;
|
||||
dev_put(dev);
|
||||
dev_put_track(dev, &ax25_dev->dev_tracker);
|
||||
kfree(ax25_dev);
|
||||
return;
|
||||
}
|
||||
@ -124,7 +124,7 @@ void ax25_dev_device_down(struct net_device *dev)
|
||||
s->next = ax25_dev->next;
|
||||
spin_unlock_bh(&ax25_dev_lock);
|
||||
dev->ax25_ptr = NULL;
|
||||
dev_put(dev);
|
||||
dev_put_track(dev, &ax25_dev->dev_tracker);
|
||||
kfree(ax25_dev);
|
||||
return;
|
||||
}
|
||||
@ -188,7 +188,7 @@ void __exit ax25_dev_free(void)
|
||||
ax25_dev = ax25_dev_list;
|
||||
while (ax25_dev != NULL) {
|
||||
s = ax25_dev;
|
||||
dev_put(ax25_dev->dev);
|
||||
dev_put_track(ax25_dev->dev, &ax25_dev->dev_tracker);
|
||||
ax25_dev = ax25_dev->next;
|
||||
kfree(s);
|
||||
}
|
||||
|
@ -274,7 +274,7 @@ static void destroy_nbp(struct net_bridge_port *p)
|
||||
|
||||
p->br = NULL;
|
||||
p->dev = NULL;
|
||||
dev_put(dev);
|
||||
dev_put_track(dev, &p->dev_tracker);
|
||||
|
||||
kobject_put(&p->kobj);
|
||||
}
|
||||
@ -423,7 +423,7 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br,
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
p->br = br;
|
||||
dev_hold(dev);
|
||||
dev_hold_track(dev, &p->dev_tracker, GFP_KERNEL);
|
||||
p->dev = dev;
|
||||
p->path_cost = port_cost(dev);
|
||||
p->priority = 0x8000 >> BR_PORT_BITS;
|
||||
@ -434,7 +434,7 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br,
|
||||
br_stp_port_timer_init(p);
|
||||
err = br_multicast_add_port(p);
|
||||
if (err) {
|
||||
dev_put(dev);
|
||||
dev_put_track(dev, &p->dev_tracker);
|
||||
kfree(p);
|
||||
p = ERR_PTR(err);
|
||||
}
|
||||
|
@ -344,6 +344,7 @@ struct net_bridge_mdb_entry {
|
||||
struct net_bridge_port {
|
||||
struct net_bridge *br;
|
||||
struct net_device *dev;
|
||||
netdevice_tracker dev_tracker;
|
||||
struct list_head list;
|
||||
|
||||
unsigned long flags;
|
||||
|
@ -410,6 +410,7 @@ struct pktgen_dev {
|
||||
* device name (not when the inject is
|
||||
* started as it used to do.)
|
||||
*/
|
||||
netdevice_tracker dev_tracker;
|
||||
char odevname[32];
|
||||
struct flow_state *flows;
|
||||
unsigned int cflows; /* Concurrent flows (config) */
|
||||
@ -2099,7 +2100,7 @@ static int pktgen_setup_dev(const struct pktgen_net *pn,
|
||||
|
||||
/* Clean old setups */
|
||||
if (pkt_dev->odev) {
|
||||
dev_put(pkt_dev->odev);
|
||||
dev_put_track(pkt_dev->odev, &pkt_dev->dev_tracker);
|
||||
pkt_dev->odev = NULL;
|
||||
}
|
||||
|
||||
@ -2117,6 +2118,7 @@ static int pktgen_setup_dev(const struct pktgen_net *pn,
|
||||
err = -ENETDOWN;
|
||||
} else {
|
||||
pkt_dev->odev = odev;
|
||||
netdev_tracker_alloc(odev, &pkt_dev->dev_tracker, GFP_KERNEL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -3805,7 +3807,7 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname)
|
||||
|
||||
return add_dev_to_thread(t, pkt_dev);
|
||||
out2:
|
||||
dev_put(pkt_dev->odev);
|
||||
dev_put_track(pkt_dev->odev, &pkt_dev->dev_tracker);
|
||||
out1:
|
||||
#ifdef CONFIG_XFRM
|
||||
free_SAs(pkt_dev);
|
||||
@ -3899,7 +3901,7 @@ static int pktgen_remove_device(struct pktgen_thread *t,
|
||||
/* Dis-associate from the interface */
|
||||
|
||||
if (pkt_dev->odev) {
|
||||
dev_put(pkt_dev->odev);
|
||||
dev_put_track(pkt_dev->odev, &pkt_dev->dev_tracker);
|
||||
pkt_dev->odev = NULL;
|
||||
}
|
||||
|
||||
|
@ -141,6 +141,7 @@ int ethnl_parse_header_dev_get(struct ethnl_req_info *req_info,
|
||||
}
|
||||
|
||||
req_info->dev = dev;
|
||||
netdev_tracker_alloc(dev, &req_info->dev_tracker, GFP_KERNEL);
|
||||
req_info->flags = flags;
|
||||
return 0;
|
||||
}
|
||||
@ -399,7 +400,7 @@ static int ethnl_default_doit(struct sk_buff *skb, struct genl_info *info)
|
||||
ops->cleanup_data(reply_data);
|
||||
|
||||
genlmsg_end(rskb, reply_payload);
|
||||
dev_put(req_info->dev);
|
||||
dev_put_track(req_info->dev, &req_info->dev_tracker);
|
||||
kfree(reply_data);
|
||||
kfree(req_info);
|
||||
return genlmsg_reply(rskb, info);
|
||||
@ -411,7 +412,7 @@ err_cleanup:
|
||||
if (ops->cleanup_data)
|
||||
ops->cleanup_data(reply_data);
|
||||
err_dev:
|
||||
dev_put(req_info->dev);
|
||||
dev_put_track(req_info->dev, &req_info->dev_tracker);
|
||||
kfree(reply_data);
|
||||
kfree(req_info);
|
||||
return ret;
|
||||
@ -547,7 +548,7 @@ static int ethnl_default_start(struct netlink_callback *cb)
|
||||
* same parser as for non-dump (doit) requests is used, it
|
||||
* 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;
|
||||
}
|
||||
if (ret < 0)
|
||||
@ -624,6 +625,7 @@ static void ethnl_default_notify(struct net_device *dev, unsigned int cmd,
|
||||
}
|
||||
|
||||
req_info->dev = dev;
|
||||
netdev_tracker_alloc(dev, &req_info->dev_tracker, GFP_KERNEL);
|
||||
req_info->flags |= ETHTOOL_FLAG_COMPACT_BITSETS;
|
||||
|
||||
ethnl_init_reply_data(reply_data, ops, dev);
|
||||
|
@ -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
|
||||
* @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
|
||||
*
|
||||
* 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)
|
||||
*/
|
||||
struct ethnl_req_info {
|
||||
struct net_device *dev;
|
||||
netdevice_tracker dev_tracker;
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
dev_put(nhc->nhc_dev);
|
||||
dev_put_track(nhc->nhc_dev, &nhc->nhc_dev_tracker);
|
||||
lwtstate_put(nhc->nhc_lwtstate);
|
||||
rt_fibinfo_free_cpus(nhc->nhc_pcpu_rth_output);
|
||||
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,
|
||||
err = ipv6_stub->fib6_nh_init(net, &fib6_nh, &cfg, GFP_KERNEL, extack);
|
||||
if (!err) {
|
||||
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_scope = RT_SCOPE_LINK;
|
||||
|
||||
@ -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))
|
||||
nh->fib_nh_flags |= RTNH_F_LINKDOWN;
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
@ -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");
|
||||
goto out;
|
||||
}
|
||||
dev_hold(dev);
|
||||
dev_hold_track(dev, &nh->fib_nh_dev_tracker, GFP_ATOMIC);
|
||||
if (!netif_carrier_ok(dev))
|
||||
nh->fib_nh_flags |= RTNH_F_LINKDOWN;
|
||||
err = (dev->flags & IFF_UP) ? 0 : -ENETDOWN;
|
||||
@ -1178,7 +1178,7 @@ static int fib_check_nh_nongw(struct net *net, struct fib_nh *nh,
|
||||
}
|
||||
|
||||
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;
|
||||
if (!netif_carrier_ok(nh->fib_nh_dev))
|
||||
nh->fib_nh_flags |= RTNH_F_LINKDOWN;
|
||||
@ -1508,6 +1508,8 @@ struct fib_info *fib_create_info(struct fib_config *cfg,
|
||||
err = -ENODEV;
|
||||
if (!nh->fib_nh_dev)
|
||||
goto failure;
|
||||
netdev_tracker_alloc(nh->fib_nh_dev, &nh->fib_nh_dev_tracker,
|
||||
GFP_KERNEL);
|
||||
} else {
|
||||
int linkdown = 0;
|
||||
|
||||
|
@ -3628,6 +3628,8 @@ 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:
|
||||
|
@ -224,7 +224,7 @@ static int llc_ui_release(struct socket *sock)
|
||||
} else {
|
||||
release_sock(sk);
|
||||
}
|
||||
dev_put(llc->dev);
|
||||
dev_put_track(llc->dev, &llc->dev_tracker);
|
||||
sock_put(sk);
|
||||
llc_sk_free(sk);
|
||||
out:
|
||||
@ -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);
|
||||
if (!llc->dev)
|
||||
goto out;
|
||||
netdev_tracker_alloc(llc->dev, &llc->dev_tracker, GFP_KERNEL);
|
||||
rc = -EUSERS;
|
||||
llc->laddr.lsap = llc_ui_autoport();
|
||||
if (!llc->laddr.lsap)
|
||||
@ -362,7 +363,7 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen)
|
||||
} else
|
||||
llc->dev = dev_getbyhwaddr_rcu(&init_net, addr->sllc_arphrd,
|
||||
addr->sllc_mac);
|
||||
dev_hold(llc->dev);
|
||||
dev_hold_track(llc->dev, &llc->dev_tracker, GFP_ATOMIC);
|
||||
rcu_read_unlock();
|
||||
if (!llc->dev)
|
||||
goto out;
|
||||
|
@ -82,7 +82,7 @@ struct vport *ovs_netdev_link(struct vport *vport, const char *name)
|
||||
err = -ENODEV;
|
||||
goto error_free_vport;
|
||||
}
|
||||
|
||||
netdev_tracker_alloc(vport->dev, &vport->dev_tracker, GFP_KERNEL);
|
||||
if (vport->dev->flags & IFF_LOOPBACK ||
|
||||
(vport->dev->type != ARPHRD_ETHER &&
|
||||
vport->dev->type != ARPHRD_NONE) ||
|
||||
@ -115,7 +115,7 @@ error_master_upper_dev_unlink:
|
||||
error_unlock:
|
||||
rtnl_unlock();
|
||||
error_put:
|
||||
dev_put(vport->dev);
|
||||
dev_put_track(vport->dev, &vport->dev_tracker);
|
||||
error_free_vport:
|
||||
ovs_vport_free(vport);
|
||||
return ERR_PTR(err);
|
||||
@ -137,7 +137,7 @@ static void vport_netdev_free(struct rcu_head *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);
|
||||
}
|
||||
|
||||
@ -173,7 +173,7 @@ void ovs_netdev_tunnel_destroy(struct vport *vport)
|
||||
*/
|
||||
if (vport->dev->reg_state == NETREG_REGISTERED)
|
||||
rtnl_delete_link(vport->dev);
|
||||
dev_put(vport->dev);
|
||||
dev_put_track(vport->dev, &vport->dev_tracker);
|
||||
vport->dev = NULL;
|
||||
rtnl_unlock();
|
||||
|
||||
|
@ -58,6 +58,7 @@ struct vport_portids {
|
||||
/**
|
||||
* struct vport - one port within a datapath
|
||||
* @dev: Pointer to net_device.
|
||||
* @dev_tracker: refcount tracker for @dev reference
|
||||
* @dp: Datapath to which this port belongs.
|
||||
* @upcall_portids: RCU protected 'struct vport_portids'.
|
||||
* @port_no: Index into @dp's @ports array.
|
||||
@ -69,6 +70,7 @@ struct vport_portids {
|
||||
*/
|
||||
struct vport {
|
||||
struct net_device *dev;
|
||||
netdevice_tracker dev_tracker;
|
||||
struct datapath *dp;
|
||||
struct vport_portids __rcu *upcall_portids;
|
||||
u16 port_no;
|
||||
|
@ -79,7 +79,7 @@ static void tcf_mirred_release(struct tc_action *a)
|
||||
|
||||
/* last reference to action, no need to lock */
|
||||
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] = {
|
||||
@ -101,7 +101,6 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
|
||||
bool mac_header_xmit = false;
|
||||
struct tc_mirred *parm;
|
||||
struct tcf_mirred *m;
|
||||
struct net_device *dev;
|
||||
bool exists = false;
|
||||
int ret, err;
|
||||
u32 index;
|
||||
@ -171,16 +170,19 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
|
||||
spin_lock_bh(&m->tcf_lock);
|
||||
|
||||
if (parm->ifindex) {
|
||||
dev = dev_get_by_index(net, parm->ifindex);
|
||||
if (!dev) {
|
||||
struct net_device *odev, *ndev;
|
||||
|
||||
ndev = dev_get_by_index(net, parm->ifindex);
|
||||
if (!ndev) {
|
||||
spin_unlock_bh(&m->tcf_lock);
|
||||
err = -ENODEV;
|
||||
goto put_chain;
|
||||
}
|
||||
mac_header_xmit = dev_is_mac_header_xmit(dev);
|
||||
dev = rcu_replace_pointer(m->tcfm_dev, dev,
|
||||
mac_header_xmit = dev_is_mac_header_xmit(ndev);
|
||||
odev = rcu_replace_pointer(m->tcfm_dev, ndev,
|
||||
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;
|
||||
}
|
||||
goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch);
|
||||
@ -400,7 +402,7 @@ static int mirred_device_event(struct notifier_block *unused,
|
||||
list_for_each_entry(m, &mirred_list, tcfm_list) {
|
||||
spin_lock_bh(&m->tcf_lock);
|
||||
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
|
||||
* net_device are already rcu protected.
|
||||
*/
|
||||
|
@ -499,6 +499,7 @@ EXPORT_SYMBOL(netif_tx_unlock);
|
||||
static void dev_watchdog(struct timer_list *t)
|
||||
{
|
||||
struct net_device *dev = from_timer(dev, t, watchdog_timer);
|
||||
bool release = true;
|
||||
|
||||
spin_lock(&dev->tx_global_lock);
|
||||
if (!qdisc_tx_is_noop(dev)) {
|
||||
@ -534,12 +535,13 @@ static void dev_watchdog(struct timer_list *t)
|
||||
if (!mod_timer(&dev->watchdog_timer,
|
||||
round_jiffies(jiffies +
|
||||
dev->watchdog_timeo)))
|
||||
dev_hold(dev);
|
||||
release = false;
|
||||
}
|
||||
}
|
||||
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)
|
||||
@ -549,7 +551,7 @@ void __netdev_watchdog_up(struct net_device *dev)
|
||||
dev->watchdog_timeo = 5*HZ;
|
||||
if (!mod_timer(&dev->watchdog_timer,
|
||||
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);
|
||||
@ -563,7 +565,7 @@ static void dev_watchdog_down(struct net_device *dev)
|
||||
{
|
||||
netif_tx_lock_bh(dev);
|
||||
if (del_timer(&dev->watchdog_timer))
|
||||
dev_put(dev);
|
||||
dev_put_track(dev, &dev->watchdog_dev_tracker);
|
||||
netif_tx_unlock_bh(dev);
|
||||
}
|
||||
|
||||
|
@ -64,6 +64,7 @@ struct smc_pnetentry {
|
||||
struct {
|
||||
char eth_name[IFNAMSIZ + 1];
|
||||
struct net_device *ndev;
|
||||
netdevice_tracker dev_tracker;
|
||||
};
|
||||
struct {
|
||||
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)
|
||||
smc_pnet_match(pnetelem->pnet_name, pnet_name)) {
|
||||
list_del(&pnetelem->list);
|
||||
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 "
|
||||
"erased user defined "
|
||||
"pnetid %.16s\n",
|
||||
@ -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) {
|
||||
if (pnetelem->type == SMC_PNET_ETH && !pnetelem->ndev &&
|
||||
!strncmp(pnetelem->eth_name, ndev->name, IFNAMSIZ)) {
|
||||
dev_hold(ndev);
|
||||
dev_hold_track(ndev, &pnetelem->dev_tracker, GFP_ATOMIC);
|
||||
pnetelem->ndev = ndev;
|
||||
rc = 0;
|
||||
pr_warn_ratelimited("smc: adding net device %s with "
|
||||
@ -226,7 +227,7 @@ static int smc_pnet_remove_by_ndev(struct net_device *ndev)
|
||||
write_lock(&pnettable->lock);
|
||||
list_for_each_entry_safe(pnetelem, tmp_pe, &pnettable->pnetlist, list) {
|
||||
if (pnetelem->type == SMC_PNET_ETH && pnetelem->ndev == ndev) {
|
||||
dev_put(pnetelem->ndev);
|
||||
dev_put_track(pnetelem->ndev, &pnetelem->dev_tracker);
|
||||
pnetelem->ndev = NULL;
|
||||
rc = 0;
|
||||
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,
|
||||
memcpy(new_pe->pnet_name, pnet_name, SMC_MAX_PNETID_LEN);
|
||||
strncpy(new_pe->eth_name, eth_name, IFNAMSIZ);
|
||||
new_pe->ndev = ndev;
|
||||
|
||||
netdev_tracker_alloc(ndev, &new_pe->dev_tracker, GFP_KERNEL);
|
||||
rc = -EEXIST;
|
||||
new_netdev = true;
|
||||
write_lock(&pnettable->lock);
|
||||
|
@ -28,6 +28,7 @@ typedef void switchdev_deferred_func_t(struct net_device *dev,
|
||||
struct switchdev_deferred_item {
|
||||
struct list_head list;
|
||||
struct net_device *dev;
|
||||
netdevice_tracker dev_tracker;
|
||||
switchdev_deferred_func_t *func;
|
||||
unsigned long data[];
|
||||
};
|
||||
@ -63,7 +64,7 @@ void switchdev_deferred_process(void)
|
||||
|
||||
while ((dfitem = switchdev_deferred_dequeue())) {
|
||||
dfitem->func(dfitem->dev, dfitem->data);
|
||||
dev_put(dfitem->dev);
|
||||
dev_put_track(dfitem->dev, &dfitem->dev_tracker);
|
||||
kfree(dfitem);
|
||||
}
|
||||
}
|
||||
@ -90,7 +91,7 @@ static int switchdev_deferred_enqueue(struct net_device *dev,
|
||||
dfitem->dev = dev;
|
||||
dfitem->func = func;
|
||||
memcpy(dfitem->data, data, data_len);
|
||||
dev_hold(dev);
|
||||
dev_hold_track(dev, &dfitem->dev_tracker, GFP_ATOMIC);
|
||||
spin_lock_bh(&deferred_lock);
|
||||
list_add_tail(&dfitem->list, &deferred);
|
||||
spin_unlock_bh(&deferred_lock);
|
||||
|
Loading…
Reference in New Issue
Block a user