diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c
--- a/drivers/atm/idt77252.c
+++ b/drivers/atm/idt77252.c
@@ -3577,7 +3577,7 @@ init_card(struct atm_dev *dev)
* XXX:
*/
sprintf(tname, "eth%d", card->index);
- tmp = dev_get_by_name(tname); /* jhs: was "tmp = dev_get(tname);" */
+ tmp = dev_get_by_name(tname, NDRK_IDT77252); /* jhs: was "tmp = dev_get(tname);" */
if (tmp) {
memcpy(card->atmdev->esi, tmp->dev_addr, 6);
@@ -3585,6 +3585,7 @@ init_card(struct atm_dev *dev)
card->name, card->atmdev->esi[0], card->atmdev->esi[1],
card->atmdev->esi[2], card->atmdev->esi[3],
card->atmdev->esi[4], card->atmdev->esi[5]);
+ dev_put(tmp, NDRK_IDT77252); /* Need to free the reference. --BLG */
}
/*
* XXX:
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -4053,7 +4053,7 @@ static int bond_do_ioctl(struct net_devi
return -EINVAL;
}
- slave_dev = dev_get_by_name(ifr->ifr_slave);
+ slave_dev = dev_get_by_name(ifr->ifr_slave, NDRK_BOND);
dprintk("slave_dev=%p: \n", slave_dev);
@@ -4082,7 +4082,7 @@ static int bond_do_ioctl(struct net_devi
res = -EOPNOTSUPP;
}
- dev_put(slave_dev);
+ dev_put(slave_dev, NDRK_BOND);
}
if (res < 0) {
diff --git a/drivers/net/eql.c b/drivers/net/eql.c
--- a/drivers/net/eql.c
+++ b/drivers/net/eql.c
@@ -1,4 +1,4 @@
-/*
+/* -*- linux-c -*-
* Equalizer Load-balancer for serial network interfaces.
*
* (c) Copyright 1995 Simon "Guru Aleph-Null" Janes
@@ -219,7 +219,7 @@ static void eql_kill_one_slave(slave_que
list_del(&slave->list);
queue->num_slaves--;
slave->dev->flags &= ~IFF_SLAVE;
- dev_put(slave->dev);
+ dev_put(slave->dev, &slave->dev);
kfree(slave);
}
@@ -409,25 +409,29 @@ static int eql_enslave(struct net_device
{
struct net_device *slave_dev;
slaving_request_t srq;
+ slave_t* s;
if (copy_from_user(&srq, srqp, sizeof (slaving_request_t)))
return -EFAULT;
- slave_dev = dev_get_by_name(srq.slave_name);
+ /* Need this up here so we know what the eventual reference for
+ * the slave_dev will be. This is to help with debugging netdev
+ * ref counts. --Ben
+ */
+ s = kmalloc(sizeof(*s), GFP_KERNEL);
+ if (!s) {
+ return -ENOMEM;
+ }
+
+ slave_dev = dev_get_by_name(srq.slave_name, &s->dev);
if (slave_dev) {
if ((master_dev->flags & IFF_UP) == IFF_UP) {
/* slave is not a master & not already a slave: */
if (!eql_is_master(slave_dev) &&
!eql_is_slave(slave_dev)) {
- slave_t *s = kmalloc(sizeof(*s), GFP_KERNEL);
equalizer_t *eql = netdev_priv(master_dev);
int ret;
- if (!s) {
- dev_put(slave_dev);
- return -ENOMEM;
- }
-
memset(s, 0, sizeof(*s));
s->dev = slave_dev;
s->priority = srq.priority;
@@ -437,7 +441,7 @@ static int eql_enslave(struct net_device
spin_lock_bh(&eql->queue.lock);
ret = __eql_insert_slave(&eql->queue, s);
if (ret) {
- dev_put(slave_dev);
+ dev_put(slave_dev, &s->dev);
kfree(s);
}
spin_unlock_bh(&eql->queue.lock);
@@ -445,9 +449,11 @@ static int eql_enslave(struct net_device
return ret;
}
}
- dev_put(slave_dev);
+ dev_put(slave_dev, &s->dev);
}
+ kfree(s);
+
return -EINVAL;
}
@@ -461,7 +467,7 @@ static int eql_emancipate(struct net_dev
if (copy_from_user(&srq, srqp, sizeof (slaving_request_t)))
return -EFAULT;
- slave_dev = dev_get_by_name(srq.slave_name);
+ slave_dev = dev_get_by_name(srq.slave_name, NDRK_EQL);
ret = -EINVAL;
if (slave_dev) {
spin_lock_bh(&eql->queue.lock);
@@ -475,7 +481,7 @@ static int eql_emancipate(struct net_dev
ret = 0;
}
}
- dev_put(slave_dev);
+ dev_put(slave_dev, NDRK_EQL);
spin_unlock_bh(&eql->queue.lock);
}
@@ -494,7 +500,7 @@ static int eql_g_slave_cfg(struct net_de
if (copy_from_user(&sc, scp, sizeof (slave_config_t)))
return -EFAULT;
- slave_dev = dev_get_by_name(sc.slave_name);
+ slave_dev = dev_get_by_name(sc.slave_name, NDRK_EQL);
if (!slave_dev)
return -ENODEV;
@@ -510,7 +516,7 @@ static int eql_g_slave_cfg(struct net_de
}
spin_unlock_bh(&eql->queue.lock);
- dev_put(slave_dev);
+ dev_put(slave_dev, NDRK_EQL);
if (!ret && copy_to_user(scp, &sc, sizeof (slave_config_t)))
ret = -EFAULT;
@@ -529,7 +535,7 @@ static int eql_s_slave_cfg(struct net_de
if (copy_from_user(&sc, scp, sizeof (slave_config_t)))
return -EFAULT;
- slave_dev = dev_get_by_name(sc.slave_name);
+ slave_dev = dev_get_by_name(sc.slave_name, NDRK_EQL);
if (!slave_dev)
return -ENODEV;
@@ -547,7 +553,8 @@ static int eql_s_slave_cfg(struct net_de
}
}
spin_unlock_bh(&eql->queue.lock);
-
+ dev_put(slave_dev, NDRK_EQL);
+
return ret;
}
diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c
--- a/drivers/net/pppoe.c
+++ b/drivers/net/pppoe.c
@@ -268,7 +268,7 @@ static void pppoe_flush_dev(struct net_d
if (sk->sk_state &
(PPPOX_CONNECTED | PPPOX_BOUND)) {
pppox_unbind_sock(sk);
- dev_put(dev);
+ dev_put(dev, &po->pppoe_dev);
sk->sk_state = PPPOX_ZOMBIE;
sk->sk_state_change(sk);
}
@@ -538,7 +538,7 @@ static int pppoe_release(struct socket *
}
if (po->pppoe_dev)
- dev_put(po->pppoe_dev);
+ dev_put(po->pppoe_dev, &po->pppoe_dev);
po->pppoe_dev = NULL;
@@ -584,9 +584,11 @@ static int pppoe_connect(struct socket *
/* Delete the old binding */
delete_item(po->pppoe_pa.sid,po->pppoe_pa.remote);
- if(po->pppoe_dev)
- dev_put(po->pppoe_dev);
-
+ if (po->pppoe_dev) {
+ dev_put(po->pppoe_dev, &po->pppoe_dev);
+ /* Ensure no further reference is attempted. --BLG */
+ po->pppoe_dev = NULL;
+ }
memset(sk_pppox(po) + 1, 0,
sizeof(struct pppox_sock) - sizeof(struct sock));
@@ -595,7 +597,7 @@ static int pppoe_connect(struct socket *
/* Don't re-bind if sid==0 */
if (sp->sa_addr.pppoe.sid != 0) {
- dev = dev_get_by_name(sp->sa_addr.pppoe.dev);
+ dev = dev_get_by_name(sp->sa_addr.pppoe.dev, &po->pppoe_dev);
error = -ENODEV;
if (!dev)
@@ -634,7 +636,7 @@ static int pppoe_connect(struct socket *
return error;
err_put:
if (po->pppoe_dev) {
- dev_put(po->pppoe_dev);
+ dev_put(po->pppoe_dev, &po->pppoe_dev);
po->pppoe_dev = NULL;
}
goto end;
diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h
--- a/include/linux/inetdevice.h
+++ b/include/linux/inetdevice.h
@@ -103,7 +103,7 @@ struct in_ifaddr
extern int register_inetaddr_notifier(struct notifier_block *nb);
extern int unregister_inetaddr_notifier(struct notifier_block *nb);
-extern struct net_device *ip_dev_find(u32 addr);
+extern struct net_device *ip_dev_find(u32 addr, void* key);
extern int inet_addr_onlink(struct in_device *in_dev, u32 a, u32 b);
extern int devinet_ioctl(unsigned int cmd, void __user *);
extern void devinet_init(void);
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -515,14 +515,14 @@ extern rwlock_t dev_base_lock; /* De
extern int netdev_boot_setup_check(struct net_device *dev);
extern unsigned long netdev_boot_base(const char *prefix, int unit);
extern struct net_device *dev_getbyhwaddr(unsigned short type, char *hwaddr);
-extern struct net_device *dev_getfirstbyhwtype(unsigned short type);
+extern struct net_device *dev_getfirstbyhwtype(unsigned short type, void* key);
extern void dev_add_pack(struct packet_type *pt);
extern void dev_remove_pack(struct packet_type *pt);
extern void __dev_remove_pack(struct packet_type *pt);
extern struct net_device *dev_get_by_flags(unsigned short flags,
- unsigned short mask);
-extern struct net_device *dev_get_by_name(const char *name);
+ unsigned short mask, void* key);
+extern struct net_device *dev_get_by_name(const char *name, void* key);
extern struct net_device *__dev_get_by_name(const char *name);
extern int dev_alloc_name(struct net_device *dev, const char *name);
extern int dev_open(struct net_device *dev);
@@ -535,7 +535,7 @@ extern void synchronize_net(void);
extern int register_netdevice_notifier(struct notifier_block *nb);
extern int unregister_netdevice_notifier(struct notifier_block *nb);
extern int call_netdevice_notifiers(unsigned long val, void *v);
-extern struct net_device *dev_get_by_index(int ifindex);
+extern struct net_device *dev_get_by_index(int ifindex, void* key);
extern struct net_device *__dev_get_by_index(int ifindex);
extern int dev_restart(struct net_device *dev);
#ifdef CONFIG_NETPOLL_TRAP
@@ -675,13 +675,61 @@ extern int netdev_nit;
/* Called by rtnetlink.c:rtnl_unlock() */
extern void netdev_run_todo(void);
+/* Set of defined keys for NETDEV_REFCOUNT Debugging.
+ * Ensure these are odd or you may get false positives.
+ */
+#define NDRK_RX_SCHEDULE ((void*)(0x1))
+#define NDRK_IDT77252 ((void*)(0x3))
+#define NDRK_BOND ((void*)(0x5))
+#define NDRK_EQL ((void*)(0x7))
+#define NDRK_VLAN_UNREG ((void*)(0x9))
+#define NDRK_VLAN_REG ((void*)(0xb))
+#define NDRK_VLAN_INGR ((void*)(0xd))
+#define NDRK_VLAN_EGR ((void*)(0xf))
+#define NDRK_VLAN_FLG ((void*)(0x11))
+#define NDRK_VLAN_GEN ((void*)(0x13))
+#define NDRK_BR_IF ((void*)(0x15))
+#define NDRK_BR_IOCTL ((void*)(0x17))
+#define NDRK_DEV_BASE ((void*)(0x19))
+#define NDRK_DV_IOCTL ((void*)(0x1b))
+#define NDRK_NEIGH_DEL ((void*)(0x1d))
+#define NDRK_NEIGH_ADD ((void*)(0x1f))
+#define NDRK_NETLINK ((void*)(0x21))
+#define NDRK_SOCKOPT ((void*)(0x23))
+#define NDRK_SOCKGLUE ((void*)(0x25))
+#define NDRK_IPMR ((void*)(0x27))
+#define NDRK_IPMR_RCV ((void*)(0x29))
+#define NDRK_ROUTE ((void*)(0x2b))
+#define NDRK_ROUTE_SLOW ((void*)(0x2d))
+#define NDRK_IPX ((void*)(0x2f))
+#define NDRK_AF_PKT ((void*)(0x31))
+#define NDRK_TC_DUMP ((void*)(0x33))
+#define NDRK_SCHED ((void*)(0x35))
+#define NDRK_IGMP ((void*)(0x37))
+
+
+#ifdef CONFIG_DEBUG_NETDEV_REFCOUNT
+
+extern void __debug_dev_put(struct net_device* dev, void* key,
+ const char* file, u32 line);
+extern void __debug_dev_hold(struct net_device* dev, void* key,
+ const char* file, u32 line);
+
+#define __dev_put(dev, key) __debug_dev_put(dev, key, __FILE__, __LINE__)
+#define dev_put(dev, key) __dev_put(dev, key)
+#define dev_hold(dev, key) __debug_dev_hold(dev, key, __FILE__, __LINE__)
+
+#else
+
static inline void dev_put(struct net_device *dev)
{
atomic_dec(&dev->refcnt);
}
-#define __dev_put(dev) atomic_dec(&(dev)->refcnt)
-#define dev_hold(dev) atomic_inc(&(dev)->refcnt)
+#define __dev_put(dev, key) atomic_dec(&(dev)->refcnt)
+#define dev_hold(dev, key) atomic_inc(&(dev)->refcnt)
+
+#endif
/* Carrier loss detection, dial on demand. The functions netif_carrier_on
* and _off may be called from IRQ context, but it is caller
@@ -801,7 +849,7 @@ static inline void __netif_rx_schedule(s
unsigned long flags;
local_irq_save(flags);
- dev_hold(dev);
+ dev_hold(dev, NDRK_RX_SCHEDULE); /* released in net_rx_action */
list_add_tail(&dev->poll_list, &__get_cpu_var(softnet_data).poll_list);
if (dev->quota < 0)
dev->quota += dev->weight;
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -248,7 +248,7 @@ static int unregister_vlan_dev(struct ne
* VLAN device, but we get rid of the reference to
* real_dev here.
*/
- dev_put(real_dev);
+ dev_put(real_dev, &(VLAN_DEV_INFO(grp->vlan_devices[vlan_id])->real_dev));
/* If the group is now empty, kill off the
* group.
@@ -281,7 +281,7 @@ static int unregister_vlan_device(const
int ret;
- dev = dev_get_by_name(vlan_IF_name);
+ dev = dev_get_by_name(vlan_IF_name, NDRK_VLAN_UNREG);
ret = -EINVAL;
if (dev) {
if (dev->priv_flags & IFF_802_1Q_VLAN) {
@@ -290,7 +290,7 @@ static int unregister_vlan_device(const
ret = unregister_vlan_dev(VLAN_DEV_INFO(dev)->real_dev,
VLAN_DEV_INFO(dev)->vlan_id);
- dev_put(dev);
+ dev_put(dev, NDRK_VLAN_UNREG);
unregister_netdevice(dev);
rtnl_unlock();
@@ -302,7 +302,7 @@ static int unregister_vlan_device(const
"%s: ERROR: Tried to remove a non-vlan device "
"with VLAN code, name: %s priv_flags: %hX\n",
__FUNCTION__, dev->name, dev->priv_flags);
- dev_put(dev);
+ dev_put(dev, NDRK_VLAN_UNREG);
ret = -EPERM;
}
} else {
@@ -352,7 +352,10 @@ static struct net_device *register_vlan_
{
struct vlan_group *grp;
struct net_device *new_dev;
- struct net_device *real_dev; /* the ethernet device */
+ struct net_device *real_dev_tmp = NULL;
+ struct net_device *real_dev_keeper = NULL; /* the underlying device device */
+ void* ndk_key = NULL;
+
char name[IFNAMSIZ];
#ifdef VLAN_DEBUG
@@ -364,29 +367,29 @@ static struct net_device *register_vlan_
goto out_ret_null;
/* find the device relating to eth_IF_name. */
- real_dev = dev_get_by_name(eth_IF_name);
- if (!real_dev)
+ real_dev_tmp = dev_get_by_name(eth_IF_name, NDRK_VLAN_REG);
+ if (!real_dev_tmp)
goto out_ret_null;
- if (real_dev->features & NETIF_F_VLAN_CHALLENGED) {
+ if (real_dev_tmp->features & NETIF_F_VLAN_CHALLENGED) {
printk(VLAN_DBG "%s: VLANs not supported on %s.\n",
- __FUNCTION__, real_dev->name);
+ __FUNCTION__, real_dev_tmp->name);
goto out_put_dev;
}
- if ((real_dev->features & NETIF_F_HW_VLAN_RX) &&
- (real_dev->vlan_rx_register == NULL ||
- real_dev->vlan_rx_kill_vid == NULL)) {
+ if ((real_dev_tmp->features & NETIF_F_HW_VLAN_RX) &&
+ (real_dev_tmp->vlan_rx_register == NULL ||
+ real_dev_tmp->vlan_rx_kill_vid == NULL)) {
printk(VLAN_DBG "%s: Device %s has buggy VLAN hw accel.\n",
- __FUNCTION__, real_dev->name);
+ __FUNCTION__, real_dev_tmp->name);
goto out_put_dev;
}
- if ((real_dev->features & NETIF_F_HW_VLAN_FILTER) &&
- (real_dev->vlan_rx_add_vid == NULL ||
- real_dev->vlan_rx_kill_vid == NULL)) {
+ if ((real_dev_tmp->features & NETIF_F_HW_VLAN_FILTER) &&
+ (real_dev_tmp->vlan_rx_add_vid == NULL ||
+ real_dev_tmp->vlan_rx_kill_vid == NULL)) {
printk(VLAN_DBG "%s: Device %s has buggy VLAN hw accel.\n",
- __FUNCTION__, real_dev->name);
+ __FUNCTION__, real_dev_tmp->name);
goto out_put_dev;
}
@@ -398,10 +401,10 @@ static struct net_device *register_vlan_
/* The real device must be up and operating in order to
* assosciate a VLAN device with it.
*/
- if (!(real_dev->flags & IFF_UP))
+ if (!(real_dev_tmp->flags & IFF_UP))
goto out_unlock;
- if (__find_vlan_dev(real_dev, VLAN_ID) != NULL) {
+ if (__find_vlan_dev(real_dev_tmp, VLAN_ID) != NULL) {
/* was already registered. */
printk(VLAN_DBG "%s: ALREADY had VLAN registered\n", __FUNCTION__);
goto out_unlock;
@@ -415,7 +418,7 @@ static struct net_device *register_vlan_
switch (vlan_name_type) {
case VLAN_NAME_TYPE_RAW_PLUS_VID:
/* name will look like: eth1.0005 */
- snprintf(name, IFNAMSIZ, "%s.%.4i", real_dev->name, VLAN_ID);
+ snprintf(name, IFNAMSIZ, "%s.%.4i", real_dev_tmp->name, VLAN_ID);
break;
case VLAN_NAME_TYPE_PLUS_VID_NO_PAD:
/* Put our vlan.VID in the name.
@@ -427,7 +430,7 @@ static struct net_device *register_vlan_
/* Put our vlan.VID in the name.
* Name will look like: eth0.5
*/
- snprintf(name, IFNAMSIZ, "%s.%i", real_dev->name, VLAN_ID);
+ snprintf(name, IFNAMSIZ, "%s.%i", real_dev_tmp->name, VLAN_ID);
break;
case VLAN_NAME_TYPE_PLUS_VID:
/* Put our vlan.VID in the name.
@@ -436,31 +439,36 @@ static struct net_device *register_vlan_
default:
snprintf(name, IFNAMSIZ, "vlan%.4i", VLAN_ID);
};
-
+
new_dev = alloc_netdev(sizeof(struct vlan_dev_info), name,
vlan_setup);
if (new_dev == NULL)
goto out_unlock;
+ ndk_key = &(VLAN_DEV_INFO(new_dev)->real_dev);
+ real_dev_keeper = dev_get_by_name(eth_IF_name, ndk_key);
+ dev_put(real_dev_tmp, NDRK_VLAN_REG);
+ real_dev_tmp = NULL;
+
#ifdef VLAN_DEBUG
printk(VLAN_DBG "Allocated new name -:%s:-\n", new_dev->name);
#endif
/* IFF_BROADCAST|IFF_MULTICAST; ??? */
- new_dev->flags = real_dev->flags;
+ new_dev->flags = real_dev_keeper->flags;
new_dev->flags &= ~IFF_UP;
- new_dev->state = real_dev->state & VLAN_LINK_STATE_MASK;
+ new_dev->state = real_dev_keeper->state & VLAN_LINK_STATE_MASK;
/* need 4 bytes for extra VLAN header info,
* hope the underlying device can handle it.
*/
- new_dev->mtu = real_dev->mtu;
+ new_dev->mtu = real_dev_keeper->mtu;
/* TODO: maybe just assign it to be ETHERNET? */
- new_dev->type = real_dev->type;
+ new_dev->type = real_dev_keeper->type;
- new_dev->hard_header_len = real_dev->hard_header_len;
- if (!(real_dev->features & NETIF_F_HW_VLAN_TX)) {
+ new_dev->hard_header_len = real_dev_keeper->hard_header_len;
+ if (!(real_dev_keeper->features & NETIF_F_HW_VLAN_TX)) {
/* Regular ethernet + 4 bytes (18 total). */
new_dev->hard_header_len += VLAN_HLEN;
}
@@ -469,29 +477,29 @@ static struct net_device *register_vlan_
new_dev->priv,
sizeof(struct vlan_dev_info));
- memcpy(new_dev->broadcast, real_dev->broadcast, real_dev->addr_len);
- memcpy(new_dev->dev_addr, real_dev->dev_addr, real_dev->addr_len);
- new_dev->addr_len = real_dev->addr_len;
+ memcpy(new_dev->broadcast, real_dev_keeper->broadcast, real_dev_keeper->addr_len);
+ memcpy(new_dev->dev_addr, real_dev_keeper->dev_addr, real_dev_keeper->addr_len);
+ new_dev->addr_len = real_dev_keeper->addr_len;
- if (real_dev->features & NETIF_F_HW_VLAN_TX) {
- new_dev->hard_header = real_dev->hard_header;
+ if (real_dev_keeper->features & NETIF_F_HW_VLAN_TX) {
+ new_dev->hard_header = real_dev_keeper->hard_header;
new_dev->hard_start_xmit = vlan_dev_hwaccel_hard_start_xmit;
- new_dev->rebuild_header = real_dev->rebuild_header;
+ new_dev->rebuild_header = real_dev_keeper->rebuild_header;
} else {
new_dev->hard_header = vlan_dev_hard_header;
new_dev->hard_start_xmit = vlan_dev_hard_start_xmit;
new_dev->rebuild_header = vlan_dev_rebuild_header;
}
- new_dev->hard_header_parse = real_dev->hard_header_parse;
+ new_dev->hard_header_parse = real_dev_keeper->hard_header_parse;
VLAN_DEV_INFO(new_dev)->vlan_id = VLAN_ID; /* 1 through VLAN_VID_MASK */
- VLAN_DEV_INFO(new_dev)->real_dev = real_dev;
+ VLAN_DEV_INFO(new_dev)->real_dev = real_dev_keeper;
VLAN_DEV_INFO(new_dev)->dent = NULL;
VLAN_DEV_INFO(new_dev)->flags = 1;
#ifdef VLAN_DEBUG
printk(VLAN_DBG "About to go find the group for idx: %i\n",
- real_dev->ifindex);
+ real_dev_keeper->ifindex);
#endif
if (register_netdevice(new_dev))
@@ -500,7 +508,7 @@ static struct net_device *register_vlan_
/* So, got the sucker initialized, now lets place
* it into our local structure.
*/
- grp = __vlan_find_group(real_dev->ifindex);
+ grp = __vlan_find_group(real_dev_keeper->ifindex);
/* Note, we are running under the RTNL semaphore
* so it cannot "appear" on us.
@@ -512,13 +520,13 @@ static struct net_device *register_vlan_
/* printk(KERN_ALERT "VLAN REGISTER: Allocated new group.\n"); */
memset(grp, 0, sizeof(struct vlan_group));
- grp->real_dev_ifindex = real_dev->ifindex;
+ grp->real_dev_ifindex = real_dev_keeper->ifindex;
hlist_add_head_rcu(&grp->hlist,
- &vlan_group_hash[vlan_grp_hashfn(real_dev->ifindex)]);
+ &vlan_group_hash[vlan_grp_hashfn(real_dev_keeper->ifindex)]);
- if (real_dev->features & NETIF_F_HW_VLAN_RX)
- real_dev->vlan_rx_register(real_dev, grp);
+ if (real_dev_keeper->features & NETIF_F_HW_VLAN_RX)
+ real_dev_keeper->vlan_rx_register(real_dev_keeper, grp);
}
grp->vlan_devices[VLAN_ID] = new_dev;
@@ -527,8 +535,8 @@ static struct net_device *register_vlan_
printk(KERN_WARNING "VLAN: failed to add proc entry for %s\n",
new_dev->name);
- if (real_dev->features & NETIF_F_HW_VLAN_FILTER)
- real_dev->vlan_rx_add_vid(real_dev, VLAN_ID);
+ if (real_dev_keeper->features & NETIF_F_HW_VLAN_FILTER)
+ real_dev_keeper->vlan_rx_add_vid(real_dev_keeper, VLAN_ID);
rtnl_unlock();
@@ -549,7 +557,12 @@ out_unlock:
rtnl_unlock();
out_put_dev:
- dev_put(real_dev);
+ if (real_dev_tmp) {
+ dev_put(real_dev_tmp, NDRK_VLAN_REG);
+ }
+ if (real_dev_keeper) {
+ dev_put(real_dev_keeper, ndk_key);
+ }
out_ret_null:
return NULL;
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -532,24 +532,24 @@ int vlan_dev_change_mtu(struct net_devic
int vlan_dev_set_ingress_priority(char *dev_name, __u32 skb_prio, short vlan_prio)
{
- struct net_device *dev = dev_get_by_name(dev_name);
+ struct net_device *dev = dev_get_by_name(dev_name, NDRK_VLAN_INGR);
if (dev) {
if (dev->priv_flags & IFF_802_1Q_VLAN) {
/* see if a priority mapping exists.. */
VLAN_DEV_INFO(dev)->ingress_priority_map[vlan_prio & 0x7] = skb_prio;
- dev_put(dev);
+ dev_put(dev, NDRK_VLAN_INGR);
return 0;
}
- dev_put(dev);
+ dev_put(dev, NDRK_VLAN_INGR);
}
return -EINVAL;
}
int vlan_dev_set_egress_priority(char *dev_name, __u32 skb_prio, short vlan_prio)
{
- struct net_device *dev = dev_get_by_name(dev_name);
+ struct net_device *dev = dev_get_by_name(dev_name, NDRK_VLAN_EGR);
struct vlan_priority_tci_mapping *mp = NULL;
struct vlan_priority_tci_mapping *np;
@@ -560,7 +560,7 @@ int vlan_dev_set_egress_priority(char *d
while (mp) {
if (mp->priority == skb_prio) {
mp->vlan_qos = ((vlan_prio << 13) & 0xE000);
- dev_put(dev);
+ dev_put(dev, NDRK_VLAN_EGR);
return 0;
}
mp = mp->next;
@@ -574,22 +574,22 @@ int vlan_dev_set_egress_priority(char *d
np->priority = skb_prio;
np->vlan_qos = ((vlan_prio << 13) & 0xE000);
VLAN_DEV_INFO(dev)->egress_priority_map[skb_prio & 0xF] = np;
- dev_put(dev);
+ dev_put(dev, NDRK_VLAN_EGR);
return 0;
} else {
- dev_put(dev);
+ dev_put(dev, NDRK_VLAN_EGR);
return -ENOBUFS;
}
}
- dev_put(dev);
+ dev_put(dev, NDRK_VLAN_EGR);
}
- return -EINVAL;
+ return -ENODEV;
}
/* Flags are defined in the vlan_dev_info class in include/linux/if_vlan.h file. */
int vlan_dev_set_vlan_flag(char *dev_name, __u32 flag, short flag_val)
{
- struct net_device *dev = dev_get_by_name(dev_name);
+ struct net_device *dev = dev_get_by_name(dev_name, NDRK_VLAN_FLG);
if (dev) {
if (dev->priv_flags & IFF_802_1Q_VLAN) {
@@ -600,19 +600,19 @@ int vlan_dev_set_vlan_flag(char *dev_nam
} else {
VLAN_DEV_INFO(dev)->flags &= ~1;
}
- dev_put(dev);
+ dev_put(dev, NDRK_VLAN_FLG);
return 0;
} else {
printk(KERN_ERR "%s: flag %i is not valid.\n",
__FUNCTION__, (int)(flag));
- dev_put(dev);
+ dev_put(dev, NDRK_VLAN_FLG);
return -EINVAL;
}
} else {
printk(KERN_ERR
"%s: %s is not a vlan device, priv_flags: %hX.\n",
__FUNCTION__, dev->name, dev->priv_flags);
- dev_put(dev);
+ dev_put(dev, NDRK_VLAN_FLG);
}
} else {
printk(KERN_ERR "%s: Could not find device: %s\n",
@@ -625,7 +625,7 @@ int vlan_dev_set_vlan_flag(char *dev_nam
int vlan_dev_get_realdev_name(const char *dev_name, char* result)
{
- struct net_device *dev = dev_get_by_name(dev_name);
+ struct net_device *dev = dev_get_by_name(dev_name, NDRK_VLAN_GEN);
int rv = 0;
if (dev) {
if (dev->priv_flags & IFF_802_1Q_VLAN) {
@@ -634,7 +634,7 @@ int vlan_dev_get_realdev_name(const char
} else {
rv = -EINVAL;
}
- dev_put(dev);
+ dev_put(dev, NDRK_VLAN_GEN);
} else {
rv = -ENODEV;
}
@@ -643,7 +643,7 @@ int vlan_dev_get_realdev_name(const char
int vlan_dev_get_vid(const char *dev_name, unsigned short* result)
{
- struct net_device *dev = dev_get_by_name(dev_name);
+ struct net_device *dev = dev_get_by_name(dev_name, NDRK_VLAN_GEN);
int rv = 0;
if (dev) {
if (dev->priv_flags & IFF_802_1Q_VLAN) {
@@ -652,7 +652,7 @@ int vlan_dev_get_vid(const char *dev_nam
} else {
rv = -EINVAL;
}
- dev_put(dev);
+ dev_put(dev, NDRK_VLAN_GEN);
} else {
rv = -ENODEV;
}
diff --git a/net/Kconfig b/net/Kconfig
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -188,6 +188,13 @@ source "net/econet/Kconfig"
source "net/wanrouter/Kconfig"
source "net/sched/Kconfig"
+config DEBUG_NETDEV_REFCOUNT
+ bool "Debug network device reference counting."
+ help
+ You can say Y here if you want to debug netdevice reference
+ counting. This is likely to slow down the the networking code
+ so only enable if you actually need this.
+
menu "Network testing"
config NET_PKTGEN
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
--- a/net/appletalk/ddp.c
+++ b/net/appletalk/ddp.c
@@ -216,7 +216,7 @@ static void atif_drop_device(struct net_
while ((tmp = *iface) != NULL) {
if (tmp->dev == dev) {
*iface = tmp->next;
- dev_put(dev);
+ dev_put(dev, &(tmp->dev));
kfree(tmp);
dev->atalk_ptr = NULL;
} else
@@ -234,7 +234,7 @@ static struct atalk_iface *atif_add_devi
goto out;
memset(iface, 0, sizeof(*iface));
- dev_hold(dev);
+ dev_hold(dev, &(iface->dev));
iface->dev = dev;
dev->atalk_ptr = iface;
iface->address = *sa;
@@ -573,7 +573,7 @@ static int atrtr_create(struct rtentry *
/* Fill in the routing entry */
rt->target = ta->sat_addr;
- dev_hold(devhint);
+ dev_hold(devhint, &(rt->dev));
rt->dev = devhint;
rt->flags = r->rt_flags;
rt->gateway = ga->sat_addr;
@@ -598,7 +598,7 @@ static int atrtr_delete(struct atalk_add
(!(tmp->flags&RTF_GATEWAY) ||
tmp->target.s_node == addr->s_node)) {
*r = tmp->next;
- dev_put(tmp->dev);
+ dev_put(tmp->dev, &(tmp->dev));
kfree(tmp);
goto out;
}
@@ -623,7 +623,7 @@ static void atrtr_device_down(struct net
while ((tmp = *r) != NULL) {
if (tmp->dev == dev) {
*r = tmp->next;
- dev_put(dev);
+ dev_put(dev, &(tmp->dev));
kfree(tmp);
} else
r = &tmp->next;
diff --git a/net/atm/lec.c b/net/atm/lec.c
--- a/net/atm/lec.c
+++ b/net/atm/lec.c
@@ -1,4 +1,4 @@
-/*
+/* -*- linux-c -*-
* lec.c: Lan Emulation driver
* Marko Kiiskila mkiiskila@yahoo.com
*
@@ -1029,11 +1029,20 @@ static void *lec_itf_walk(struct lec_sta
{
struct net_device *dev;
void *v;
+ void* key;
+ if (state->dev) {
+ key = &(state->dev);
+ dev = state->dev;
+ }
+ else {
+ key = &(dev_lec[state->itf]);
+ dev = dev_lec[state->itf];
+ }
- dev = state->dev ? state->dev : dev_lec[state->itf];
+ /* dev = state->dev ? state->dev : dev_lec[state->itf]; */
v = (dev && dev->priv) ? lec_priv_walk(state, l, dev->priv) : NULL;
if (!v && dev) {
- dev_put(dev);
+ dev_put(dev, key);
/* Partial state reset for the next time we get called */
dev = NULL;
}
@@ -1074,7 +1083,8 @@ static void lec_seq_stop(struct seq_file
if (state->dev) {
spin_unlock_irqrestore(&state->locked->lec_arp_lock,
state->flags);
- dev_put(state->dev);
+ dev_put(state->dev, &(state->dev));
+ /* TODO: Maybe should set state->dev to NULL ?? --BLG */
}
}
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -82,7 +82,7 @@ static void destroy_nbp(struct net_bridg
dev->br_port = NULL;
p->br = NULL;
p->dev = NULL;
- dev_put(dev);
+ dev_put(dev, &(p->dev));
br_sysfs_freeif(p);
}
@@ -213,7 +213,7 @@ static struct net_bridge_port *new_nbp(s
memset(p, 0, sizeof(*p));
p->br = br;
- dev_hold(dev);
+ dev_hold(dev, &(p->dev));
p->dev = dev;
p->path_cost = cost;
p->priority = 0x8000 >> BR_PORT_BITS;
@@ -250,11 +250,11 @@ int br_add_bridge(const char *name)
* after rtnl_unlock does it's hotplug magic.
* so hold reference to avoid race.
*/
- dev_hold(dev);
+ dev_hold(dev, NDRK_BR_IF);
rtnl_unlock();
ret = br_sysfs_addbr(dev);
- dev_put(dev);
+ dev_put(dev, NDRK_BR_IF);
if (ret)
unregister_netdev(dev);
diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c
--- a/net/bridge/br_ioctl.c
+++ b/net/bridge/br_ioctl.c
@@ -86,7 +86,7 @@ static int add_del_if(struct net_bridge
if (!capable(CAP_NET_ADMIN))
return -EPERM;
- dev = dev_get_by_index(ifindex);
+ dev = dev_get_by_index(ifindex, NDRK_BR_IOCTL);
if (dev == NULL)
return -EINVAL;
@@ -95,7 +95,7 @@ static int add_del_if(struct net_bridge
else
ret = br_del_if(br, dev);
- dev_put(dev);
+ dev_put(dev, NDRK_BR_IOCTL);
return ret;
}
diff --git a/net/core/dev.c b/net/core/dev.c
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1,4 +1,4 @@
-/*
+/* -*- linux-c -*-
* NET3 Protocol independent device support routines.
*
* This program is free software; you can redistribute it and/or
@@ -457,6 +457,161 @@ __setup("netdev=", netdev_boot_setup);
*******************************************************************************/
+#ifdef CONFIG_DEBUG_NETDEV_REFCOUNT
+
+struct dbg_dev_rfcnt_info {
+ struct dbg_dev_rfcnt_info* next;
+ struct net_device* dev;
+ void* key;
+ const char* file;
+ u32 line;
+};
+
+static DEFINE_SPINLOCK(rfcnt_infos_lock);
+
+#define DBG_NETDEV_HASHLEN 512
+static struct dbg_dev_rfcnt_info* rfcnt_infos[DBG_NETDEV_HASHLEN];
+
+static void dump_rfcnt_info(void) {
+ int i;
+ printk(" NetDevice ref count hash table:\n");
+ for (i = 0; idev, rfi->key, rfi->file, rfi->line);
+ rfi = rfi->next;
+ }
+ }/* for */
+}
+
+static inline u32 get_rfcnt_hashkey(void* key) {
+ u32 rv = (((u32)(key)) & 0x1FF0) >> 4;
+ if (rv >= DBG_NETDEV_HASHLEN) {
+ printk("error: hashkey oob: %d\n", rv);
+ rv = (DBG_NETDEV_HASHLEN - 1);
+ }
+ return rv;
+}
+
+struct dbg_dev_rfcnt_info* findDevRfcntInfo(struct net_device* dev, void* key) {
+ struct dbg_dev_rfcnt_info* rv;
+ long flags;
+ spin_lock_irqsave(&rfcnt_infos_lock, flags);
+ rv = rfcnt_infos[get_rfcnt_hashkey(key)];
+ while (rv) {
+ if ((rv->key == key) && (rv->dev == dev)) {
+ goto out;
+ }
+ rv = rv->next;
+ }
+out:
+ spin_unlock_irqrestore(&rfcnt_infos_lock, flags);
+ return rv;
+}
+
+struct dbg_dev_rfcnt_info* removeDevRfcntInfo(struct net_device* dev, void* key) {
+ u32 hk = get_rfcnt_hashkey(key);
+ struct dbg_dev_rfcnt_info* prev = NULL;
+ struct dbg_dev_rfcnt_info* rv;
+ long flags;
+ spin_lock_irqsave(&rfcnt_infos_lock, flags);
+ rv = rfcnt_infos[hk];
+ while (rv) {
+ if ((rv->key == key) && (rv->dev == dev)) {
+ if (rv == rfcnt_infos[hk]) {
+ /* First in the list */
+ rfcnt_infos[hk] = rv->next;
+ }
+ else {
+ /* prev should be valid */
+ prev->next = rv->next;
+ }
+ goto out;
+ }
+ prev = rv;
+ rv = rv->next;
+ }
+out:
+ spin_unlock_irqrestore(&rfcnt_infos_lock, flags);
+ return rv;
+}
+
+void __debug_dev_put(struct net_device* dev, void* key,
+ const char* file, u32 line) {
+ struct dbg_dev_rfcnt_info* rfc = removeDevRfcntInfo(dev, key);
+ if (!rfc) {
+ printk("ERROR: can't find dev refcnt info, key: %p dev: %p file: %s:%d\n",
+ key, dev, file, line);
+ printk(" dev->name: %s\n", dev->name);
+ dump_rfcnt_info();
+ /* BUG(); */
+ atomic_dec(&dev->refcnt);
+ }
+ else {
+ kfree(rfc);
+ atomic_dec(&dev->refcnt);
+ }
+}
+
+
+void __debug_dev_hold(struct net_device* dev, void* key,
+ const char* file, u32 line) {
+ /* If key is odd, then we know it is not the address of
+ * something (that would be aligned to an even address I'm assuming). So,
+ * do not attempt to find it (it's OK if it's already here.)
+ * These sorts of keys are used when we don't have (or can't
+ * easily derive, a unique key that is a real address of something
+ * useful.
+ */
+ struct dbg_dev_rfcnt_info* rfc;
+ if (! ((u32)(key)) & 0x1) {
+ rfc = findDevRfcntInfo(dev, key);
+ if (rfc) {
+ printk("WARNING: found dev refcnt info, key: %p dev: %p file: %s:%d\n",
+ key, dev, file, line);
+ printk(" rfc: key: %p dev: %p file: %s:%d\n",
+ rfc->key, rfc->dev, rfc->file, rfc->line);
+ printk(" dev->name: %s\n", dev->name);
+ dump_rfcnt_info();
+ /* BUG(); */
+ }
+ }
+
+ /* Allocate a new one. */
+ rfc = kmalloc(sizeof(*rfc), GFP_ATOMIC);
+ if (!rfc) {
+ /* This is not good at all. Panic for now.
+ * for future work, should probably keep a
+ * cache of rfc structs around to use in this
+ * scenario. --Ben Greear
+ */
+ printk("ERROR: Could not allocate netdev debug refcount struct..!\n");
+ printk(" key: %p dev: %p file: %s:%d\n",
+ key, dev, file, line);
+ BUG();
+ }
+ else {
+ u32 hk = get_rfcnt_hashkey(key);
+ long flags;
+ rfc->key = key;
+ rfc->dev = dev;
+ rfc->file = file;
+ rfc->line = line;
+ spin_lock_irqsave(&rfcnt_infos_lock, flags);
+ rfc->next = rfcnt_infos[hk];
+ rfcnt_infos[hk] = rfc;
+ spin_unlock_irqrestore(&rfcnt_infos_lock, flags);
+ atomic_inc(&dev->refcnt);
+ }
+}
+
+#endif
+
+
/**
* __dev_get_by_name - find a device by its name
* @name: name to find
@@ -492,14 +647,14 @@ struct net_device *__dev_get_by_name(con
* matching device is found.
*/
-struct net_device *dev_get_by_name(const char *name)
+struct net_device *dev_get_by_name(const char *name, void* key)
{
struct net_device *dev;
read_lock(&dev_base_lock);
dev = __dev_get_by_name(name);
if (dev)
- dev_hold(dev);
+ dev_hold(dev, key);
read_unlock(&dev_base_lock);
return dev;
}
@@ -539,14 +694,14 @@ struct net_device *__dev_get_by_index(in
* dev_put to indicate they have finished with it.
*/
-struct net_device *dev_get_by_index(int ifindex)
+struct net_device *dev_get_by_index(int ifindex, void* key)
{
struct net_device *dev;
read_lock(&dev_base_lock);
dev = __dev_get_by_index(ifindex);
if (dev)
- dev_hold(dev);
+ dev_hold(dev, key);
read_unlock(&dev_base_lock);
return dev;
}
@@ -578,14 +733,14 @@ struct net_device *dev_getbyhwaddr(unsig
return dev;
}
-struct net_device *dev_getfirstbyhwtype(unsigned short type)
+struct net_device *dev_getfirstbyhwtype(unsigned short type, void* key)
{
struct net_device *dev;
rtnl_lock();
for (dev = dev_base; dev; dev = dev->next) {
if (dev->type == type) {
- dev_hold(dev);
+ dev_hold(dev, key);
break;
}
}
@@ -606,14 +761,14 @@ EXPORT_SYMBOL(dev_getfirstbyhwtype);
* dev_put to indicate they have finished with it.
*/
-struct net_device * dev_get_by_flags(unsigned short if_flags, unsigned short mask)
+struct net_device * dev_get_by_flags(unsigned short if_flags, unsigned short mask, void* key)
{
struct net_device *dev;
read_lock(&dev_base_lock);
for (dev = dev_base; dev != NULL; dev = dev->next) {
if (((dev->flags ^ if_flags) & mask) == 0) {
- dev_hold(dev);
+ dev_hold(dev, key);
break;
}
}
@@ -1393,7 +1548,7 @@ int netif_rx(struct sk_buff *skb)
if (queue->input_pkt_queue.qlen <= netdev_max_backlog) {
if (queue->input_pkt_queue.qlen) {
enqueue:
- dev_hold(skb->dev);
+ dev_hold(skb->dev, &(skb->dev));
__skb_queue_tail(&queue->input_pkt_queue, skb);
local_irq_restore(flags);
return NET_RX_SUCCESS;
@@ -1655,6 +1810,7 @@ static int process_backlog(struct net_de
for (;;) {
struct sk_buff *skb;
struct net_device *dev;
+ void* key;
local_irq_disable();
skb = __skb_dequeue(&queue->input_pkt_queue);
@@ -1663,10 +1819,11 @@ static int process_backlog(struct net_de
local_irq_enable();
dev = skb->dev;
-
+ key = &(skb->dev);
+
netif_receive_skb(skb);
- dev_put(dev);
+ dev_put(dev, key);
work++;
@@ -1697,7 +1854,7 @@ static void net_rx_action(struct softirq
unsigned long start_time = jiffies;
int budget = netdev_budget;
void *have;
-
+
local_irq_disable();
while (!list_empty(&queue->poll_list)) {
@@ -1723,7 +1880,8 @@ static void net_rx_action(struct softirq
dev->quota = dev->weight;
} else {
netpoll_poll_unlock(have);
- dev_put(dev);
+ /* This was acquired in netdevice.h, line 819 or so. --Ben */
+ dev_put(dev, NDRK_RX_SCHEDULE);
local_irq_disable();
}
}
@@ -2056,7 +2214,7 @@ int netdev_set_master(struct net_device
if (master) {
if (old)
return -EBUSY;
- dev_hold(master);
+ dev_hold(master, &(slave->master));
}
slave->master = master;
@@ -2064,7 +2222,7 @@ int netdev_set_master(struct net_device
synchronize_net();
if (old)
- dev_put(old);
+ dev_put(old, &slave->master);
if (master)
slave->flags |= IFF_SLAVE;
@@ -2729,7 +2887,7 @@ int register_netdevice(struct net_device
dev_tail = &dev->next;
hlist_add_head(&dev->name_hlist, head);
hlist_add_head(&dev->index_hlist, dev_index_hash(dev->ifindex));
- dev_hold(dev);
+ dev_hold(dev, NDRK_DEV_BASE); /* is on the dev_base list now */
dev->reg_state = NETREG_REGISTERING;
write_unlock_bh(&dev_base_lock);
@@ -2839,6 +2997,10 @@ static void netdev_wait_allrefs(struct n
"waiting for %s to become free. Usage "
"count = %d\n",
dev->name, atomic_read(&dev->refcnt));
+
+#ifdef CONFIG_DEBUG_NETDEV_REFCOUNT
+ dump_rfcnt_info();
+#endif
warning_time = jiffies;
}
}
@@ -3089,7 +3251,7 @@ int unregister_netdevice(struct net_devi
synchronize_net();
- dev_put(dev);
+ dev_put(dev, NDRK_DEV_BASE);
return 0;
}
@@ -3264,6 +3426,11 @@ EXPORT_SYMBOL(net_enable_timestamp);
EXPORT_SYMBOL(net_disable_timestamp);
EXPORT_SYMBOL(dev_get_flags);
+#ifdef CONFIG_DEBUG_NETDEV_REFCOUNT
+EXPORT_SYMBOL(__debug_dev_put);
+EXPORT_SYMBOL(__debug_dev_hold);
+#endif
+
#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
EXPORT_SYMBOL(br_handle_frame_hook);
EXPORT_SYMBOL(br_fdb_get_hook);
diff --git a/net/core/dst.c b/net/core/dst.c
--- a/net/core/dst.c
+++ b/net/core/dst.c
@@ -1,4 +1,4 @@
-/*
+/* -*- linux-c -*-
* net/core/dst.c Protocol independent destination cache.
*
* Authors: Alexey Kuznetsov,
@@ -197,7 +197,7 @@ again:
if (dst->ops->destroy)
dst->ops->destroy(dst);
if (dst->dev)
- dev_put(dst->dev);
+ dev_put(dst->dev, &(dst->dev));
#if RT_CACHE_DEBUG >= 2
atomic_dec(&dst_total);
#endif
@@ -243,12 +243,12 @@ static inline void dst_ifdown(struct dst
dst->output = dst_discard_out;
} else {
dst->dev = &loopback_dev;
- dev_hold(&loopback_dev);
- dev_put(dev);
+ dev_put(dev, &(dst->dev));
+ dev_hold(&loopback_dev, &(dst->dev));
if (dst->neighbour && dst->neighbour->dev == dev) {
dst->neighbour->dev = &loopback_dev;
- dev_put(dev);
- dev_hold(&loopback_dev);
+ dev_put(dev, &(dst->neighbour->dev));
+ dev_hold(&loopback_dev, &(dst->neighbour->dev));
}
}
}
diff --git a/net/core/dv.c b/net/core/dv.c
--- a/net/core/dv.c
+++ b/net/core/dv.c
@@ -1,4 +1,4 @@
-/*
+/* -*- linux-c -*-
* INET An implementation of the TCP/IP protocol suite for the LINUX
* operating system. INET is implemented using the BSD Socket
* interface as the means of communication with the user level.
@@ -63,7 +63,7 @@ int alloc_divert_blk(struct net_device *
}
memset(dev->divert, 0, sizeof(struct divert_blk));
- dev_hold(dev);
+ dev_hold(dev, &(dev->divert));
}
return 0;
@@ -78,7 +78,7 @@ void free_divert_blk(struct net_device *
if (dev->divert) {
kfree(dev->divert);
dev->divert=NULL;
- dev_put(dev);
+ dev_put(dev, &(dev->divert));
}
}
@@ -138,6 +138,9 @@ static int remove_port(u16 ports[], u16
}
/* Some basic sanity checks on the arguments passed to divert_ioctl() */
+/* TODO: This returns a pointer to dev, but it has already dropped the
+ * hold. This could lead to access-after-free. --Ben
+ */
static int check_args(struct divert_cf *div_cf, struct net_device **dev)
{
char devname[32];
@@ -151,16 +154,18 @@ static int check_args(struct divert_cf *
return 0;
/* Network device index should reasonably be between 0 and 1000 :) */
+ /* TODO: This is bogus, you can have thousands of devices in
+ * a single machine --BLG */
if (div_cf->dev_index < 0 || div_cf->dev_index > 1000)
return -EINVAL;
/* Let's try to find the ifname */
sprintf(devname, "eth%d", div_cf->dev_index);
- *dev = dev_get_by_name(devname);
+ *dev = dev_get_by_name(devname, NDRK_DV_IOCTL);
/* dev should NOT be null */
if (*dev == NULL)
- return -EINVAL;
+ return -EINVAL; /* TODO: maybe -ENODEV ?? --Ben */
ret = 0;
@@ -174,7 +179,7 @@ static int check_args(struct divert_cf *
if ((*dev)->divert == NULL)
ret = -EINVAL;
out:
- dev_put(*dev);
+ dev_put(*dev, NDRK_DV_IOCTL);
return ret;
}
diff --git a/net/core/link_watch.c b/net/core/link_watch.c
--- a/net/core/link_watch.c
+++ b/net/core/link_watch.c
@@ -1,4 +1,4 @@
-/*
+/* -*- linux-c -*-
* Linux network device link state notification
*
* Author:
@@ -62,6 +62,7 @@ void linkwatch_run_queue(void)
list_for_each_safe(n, next, &head) {
struct lw_event *event = list_entry(n, struct lw_event, list);
struct net_device *dev = event->dev;
+ void* key = &(event->dev);
if (event == &singleevent) {
clear_bit(LW_SE_USED, &linkwatch_flags);
@@ -84,7 +85,7 @@ void linkwatch_run_queue(void)
netdev_state_change(dev);
}
- dev_put(dev);
+ dev_put(dev, key);
}
}
@@ -122,7 +123,7 @@ void linkwatch_fire_event(struct net_dev
event = &singleevent;
}
- dev_hold(dev);
+ dev_hold(dev, &(event->dev));
event->dev = dev;
spin_lock_irqsave(&lweventlist_lock, flags);
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -1,4 +1,4 @@
-/*
+/* -*- linux-c -*-
* Generic address resolution entity
*
* Authors:
@@ -168,7 +168,7 @@ static void pneigh_queue_purge(struct sk
struct sk_buff *skb;
while ((skb = skb_dequeue(list)) != NULL) {
- dev_put(skb->dev);
+ dev_put(skb->dev, &(skb->dev));
kfree_skb(skb);
}
}
@@ -412,7 +412,7 @@ struct neighbour *neigh_create(struct ne
memcpy(n->primary_key, pkey, key_len);
n->dev = dev;
- dev_hold(dev);
+ dev_hold(dev, &(n->dev));
/* Protocol specific setup. */
if (tbl->constructor && (error = tbl->constructor(n)) < 0) {
@@ -498,11 +498,11 @@ struct pneigh_entry * pneigh_lookup(stru
memcpy(n->key, pkey, key_len);
n->dev = dev;
if (dev)
- dev_hold(dev);
+ dev_hold(dev, &(n->dev));
if (tbl->pconstructor && tbl->pconstructor(n)) {
if (dev)
- dev_put(dev);
+ dev_put(dev, &(n->dev));
kfree(n);
n = NULL;
goto out;
@@ -538,7 +538,7 @@ int pneigh_delete(struct neigh_table *tb
if (tbl->pdestructor)
tbl->pdestructor(n);
if (n->dev)
- dev_put(n->dev);
+ dev_put(n->dev, &(n->dev));
kfree(n);
return 0;
}
@@ -560,7 +560,7 @@ static int pneigh_ifdown(struct neigh_ta
if (tbl->pdestructor)
tbl->pdestructor(n);
if (n->dev)
- dev_put(n->dev);
+ dev_put(n->dev, &(n->dev));
kfree(n);
continue;
}
@@ -606,7 +606,7 @@ void neigh_destroy(struct neighbour *nei
skb_queue_purge(&neigh->arp_queue);
- dev_put(neigh->dev);
+ dev_put(neigh->dev, &(neigh->dev));
neigh_parms_put(neigh->parms);
NEIGH_PRINTK2("neigh %p is destroyed.\n", neigh);
@@ -1222,13 +1222,14 @@ static void neigh_proxy_process(unsigned
skb = skb->next;
if (tdif <= 0) {
struct net_device *dev = back->dev;
+ void* key = &(back->dev);
__skb_unlink(back, &tbl->proxy_queue);
if (tbl->proxy_redo && netif_running(dev))
tbl->proxy_redo(back);
else
kfree_skb(back);
- dev_put(dev);
+ dev_put(dev, key);
} else if (!sched_next || tdif < sched_next)
sched_next = tdif;
}
@@ -1258,7 +1259,7 @@ void pneigh_enqueue(struct neigh_table *
}
dst_release(skb->dst);
skb->dst = NULL;
- dev_hold(skb->dev);
+ dev_hold(skb->dev, &(skb->dev));
__skb_queue_tail(&tbl->proxy_queue, skb);
mod_timer(&tbl->proxy_timer, sched_next);
spin_unlock(&tbl->proxy_queue.lock);
@@ -1283,7 +1284,7 @@ struct neigh_parms *neigh_parms_alloc(st
return NULL;
}
- dev_hold(dev);
+ dev_hold(dev, &(p->dev));
p->dev = dev;
}
p->sysctl_table = NULL;
@@ -1316,7 +1317,7 @@ void neigh_parms_release(struct neigh_ta
parms->dead = 1;
write_unlock_bh(&tbl->lock);
if (parms->dev)
- dev_put(parms->dev);
+ dev_put(parms->dev, &(parms->dev));
call_rcu(&parms->rcu_head, neigh_rcu_free_parms);
return;
}
@@ -1433,7 +1434,7 @@ int neigh_delete(struct sk_buff *skb, st
int err = -ENODEV;
if (ndm->ndm_ifindex &&
- (dev = dev_get_by_index(ndm->ndm_ifindex)) == NULL)
+ (dev = dev_get_by_index(ndm->ndm_ifindex, NDRK_NEIGH_DEL)) == NULL)
goto out;
read_lock(&neigh_tbl_lock);
@@ -1470,7 +1471,7 @@ int neigh_delete(struct sk_buff *skb, st
err = -EADDRNOTAVAIL;
out_dev_put:
if (dev)
- dev_put(dev);
+ dev_put(dev, NDRK_NEIGH_DEL);
out:
return err;
}
@@ -1482,9 +1483,9 @@ int neigh_add(struct sk_buff *skb, struc
struct neigh_table *tbl;
struct net_device *dev = NULL;
int err = -ENODEV;
-
+
if (ndm->ndm_ifindex &&
- (dev = dev_get_by_index(ndm->ndm_ifindex)) == NULL)
+ (dev = dev_get_by_index(ndm->ndm_ifindex, NDRK_NEIGH_ADD)) == NULL)
goto out;
read_lock(&neigh_tbl_lock);
@@ -1549,7 +1550,7 @@ int neigh_add(struct sk_buff *skb, struc
err = -EADDRNOTAVAIL;
out_dev_put:
if (dev)
- dev_put(dev);
+ dev_put(dev, NDRK_NEIGH_DEL);
out:
return err;
}
diff --git a/net/core/netfilter.c b/net/core/netfilter.c
--- a/net/core/netfilter.c
+++ b/net/core/netfilter.c
@@ -1,4 +1,5 @@
-/* netfilter.c: look after the filters for various protocols.
+/* -*- linux-c -*-
+ * netfilter.c: look after the filters for various protocols.
* Heavily influenced by the old firewall.c by David Bonn and Alan Cox.
*
* Thanks to Rob `CmdrTaco' Malda for not influencing this code in any
@@ -281,6 +282,8 @@ static int nf_queue(struct sk_buff *skb,
#ifdef CONFIG_BRIDGE_NETFILTER
struct net_device *physindev = NULL;
struct net_device *physoutdev = NULL;
+ void* pikey = NULL;
+ void* pokey = NULL;
#endif
/* QUEUE == DROP if noone is waiting, to be safe. */
@@ -312,15 +315,17 @@ static int nf_queue(struct sk_buff *skb,
}
/* Bump dev refs so they don't vanish while packet is out */
- if (indev) dev_hold(indev);
- if (outdev) dev_hold(outdev);
+ if (indev) dev_hold(indev, &(info->indev));
+ if (outdev) dev_hold(outdev, &(info->outdev));
#ifdef CONFIG_BRIDGE_NETFILTER
if (skb->nf_bridge) {
physindev = skb->nf_bridge->physindev;
- if (physindev) dev_hold(physindev);
+ pikey = &(skb->nf_bridge->physindev);
+ if (physindev) dev_hold(physindev, pikey);
physoutdev = skb->nf_bridge->physoutdev;
- if (physoutdev) dev_hold(physoutdev);
+ pokey = &(skb->nf_bridge->physoutdev);
+ if (physoutdev) dev_hold(physoutdev, pokey);
}
#endif
@@ -329,11 +334,11 @@ static int nf_queue(struct sk_buff *skb,
if (status < 0) {
/* James M doesn't say fuck enough. */
- if (indev) dev_put(indev);
- if (outdev) dev_put(outdev);
+ if (indev) dev_put(indev, &(info->indev));
+ if (outdev) dev_put(outdev, &(info->outdev));
#ifdef CONFIG_BRIDGE_NETFILTER
- if (physindev) dev_put(physindev);
- if (physoutdev) dev_put(physoutdev);
+ if (physindev) dev_put(physindev, pikey);
+ if (physoutdev) dev_put(physoutdev, pokey);
#endif
module_put(info->elem->owner);
kfree(info);
@@ -387,14 +392,14 @@ void nf_reinject(struct sk_buff *skb, st
rcu_read_lock();
/* Release those devices we held, or Alexey will kill me. */
- if (info->indev) dev_put(info->indev);
- if (info->outdev) dev_put(info->outdev);
+ if (info->indev) dev_put(info->indev, &(info->indev));
+ if (info->outdev) dev_put(info->outdev, &(info->outdev));
#ifdef CONFIG_BRIDGE_NETFILTER
if (skb->nf_bridge) {
if (skb->nf_bridge->physindev)
- dev_put(skb->nf_bridge->physindev);
+ dev_put(skb->nf_bridge->physindev, &(skb->nf_bridge->physindev));
if (skb->nf_bridge->physoutdev)
- dev_put(skb->nf_bridge->physoutdev);
+ dev_put(skb->nf_bridge->physoutdev, &(skb->nf_bridge->physoutdev));
}
#endif
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -1,4 +1,4 @@
-/*
+/* -*- linux-c -*-
* Common framework for low-level network console, dump, and debugger code
*
* Sep 8 2003 Matt Mackall
@@ -630,7 +630,7 @@ int netpoll_setup(struct netpoll *np)
unsigned long flags;
if (np->dev_name)
- ndev = dev_get_by_name(np->dev_name);
+ ndev = dev_get_by_name(np->dev_name, &(np->dev));
if (!ndev) {
printk(KERN_ERR "%s: %s doesn't exist, aborting.\n",
np->name, np->dev_name);
@@ -740,7 +740,7 @@ int netpoll_setup(struct netpoll *np)
if (!ndev->npinfo)
kfree(npinfo);
np->dev = NULL;
- dev_put(ndev);
+ dev_put(ndev, &(np->dev));
return -1;
}
@@ -757,7 +757,7 @@ void netpoll_cleanup(struct netpoll *np)
npinfo->rx_flags &= ~NETPOLL_RX_ENABLED;
spin_unlock_irqrestore(&npinfo->rx_lock, flags);
}
- dev_put(np->dev);
+ dev_put(np->dev, &(np->dev));
}
np->dev = NULL;
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -1,4 +1,4 @@
-/*
+/* -*- linux-c -*-
* Authors:
* Copyright 2001, 2002 by Robert Olsson
* Uppsala University and
@@ -1566,11 +1566,11 @@ static struct net_device* pktgen_setup_d
/* Clean old setups */
if (pkt_dev->odev) {
- dev_put(pkt_dev->odev);
+ dev_put(pkt_dev->odev, &(pkt_dev->odev));
pkt_dev->odev = NULL;
}
- odev = dev_get_by_name(pkt_dev->ifname);
+ odev = dev_get_by_name(pkt_dev->ifname, &(pkt_dev->odev));
if (!odev) {
printk("pktgen: no such netdevice: \"%s\"\n", pkt_dev->ifname);
@@ -1589,7 +1589,7 @@ static struct net_device* pktgen_setup_d
return pkt_dev->odev;
out_put:
- dev_put(odev);
+ dev_put(odev, &(pkt_dev->odev));
out:
return NULL;
@@ -3039,7 +3039,7 @@ static int pktgen_remove_device(struct p
/* Dis-associate from the interface */
if (pkt_dev->odev) {
- dev_put(pkt_dev->odev);
+ dev_put(pkt_dev->odev, &(pkt_dev->odev));
pkt_dev->odev = NULL;
}
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -1,4 +1,4 @@
-/*
+/* -*- linux-c -*-
* INET An implementation of the TCP/IP protocol suite for the LINUX
* operating system. INET is implemented using the BSD Socket
* interface as the means of communication with the user level.
@@ -295,16 +295,16 @@ static int do_setlink(struct sk_buff *sk
struct rtattr **ida = arg;
struct net_device *dev;
int err, send_addr_notify = 0;
-
+
if (ifm->ifi_index >= 0)
- dev = dev_get_by_index(ifm->ifi_index);
+ dev = dev_get_by_index(ifm->ifi_index, NDRK_NETLINK);
else if (ida[IFLA_IFNAME - 1]) {
char ifname[IFNAMSIZ];
if (rtattr_strlcpy(ifname, ida[IFLA_IFNAME - 1],
IFNAMSIZ) >= IFNAMSIZ)
return -EINVAL;
- dev = dev_get_by_name(ifname);
+ dev = dev_get_by_name(ifname, NDRK_NETLINK);
} else
return -EINVAL;
@@ -415,7 +415,7 @@ out:
if (send_addr_notify)
call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
- dev_put(dev);
+ dev_put(dev, NDRK_NETLINK);
return err;
}
diff --git a/net/core/sock.c b/net/core/sock.c
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1,4 +1,4 @@
-/*
+/* -*- linux-c -*-
* INET An implementation of the TCP/IP protocol suite for the LINUX
* operating system. INET is implemented using the BSD Socket
* interface as the means of communication with the user level.
@@ -402,13 +402,13 @@ int sock_setsockopt(struct socket *sock,
if (devname[0] == '\0') {
sk->sk_bound_dev_if = 0;
} else {
- struct net_device *dev = dev_get_by_name(devname);
+ struct net_device *dev = dev_get_by_name(devname, NDRK_SOCKOPT);
if (!dev) {
ret = -ENODEV;
break;
}
sk->sk_bound_dev_if = dev->ifindex;
- dev_put(dev);
+ dev_put(dev, NDRK_SOCKOPT);
}
}
break;
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -125,7 +125,7 @@ void in_dev_finish_destroy(struct in_dev
printk(KERN_DEBUG "in_dev_finish_destroy: %p=%s\n",
idev, dev ? dev->name : "NIL");
#endif
- dev_put(dev);
+ dev_put(dev, &(idev->dev));
if (!idev->dead)
printk("Freeing alive in_device %p\n", idev);
else {
@@ -150,7 +150,7 @@ struct in_device *inetdev_init(struct ne
if ((in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl)) == NULL)
goto out_kfree;
/* Reference in_dev->dev */
- dev_hold(dev);
+ dev_hold(dev, &(in_dev->dev));
#ifdef CONFIG_SYSCTL
neigh_sysctl_register(dev, in_dev->arp_parms, NET_IPV4,
NET_IPV4_NEIGH, "ipv4", NULL, NULL);
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -1,4 +1,4 @@
-/*
+/* -*- linux-c -*-
* INET An implementation of the TCP/IP protocol suite for the LINUX
* operating system. INET is implemented using the BSD Socket
* interface as the means of communication with the user level.
@@ -100,7 +100,7 @@ static void fib_flush(void)
* Find the first device with a given source address.
*/
-struct net_device * ip_dev_find(u32 addr)
+struct net_device * ip_dev_find(u32 addr, void* key)
{
struct flowi fl = { .nl_u = { .ip4_u = { .daddr = addr } } };
struct fib_result res;
@@ -118,7 +118,7 @@ struct net_device * ip_dev_find(u32 addr
dev = FIB_RES_DEV(res);
if (dev)
- dev_hold(dev);
+ dev_hold(dev, key);
out:
fib_res_put(&res);
return dev;
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -1,4 +1,4 @@
-/*
+/* -*- linux-c -*-
* INET An implementation of the TCP/IP protocol suite for the LINUX
* operating system. INET is implemented using the BSD Socket
* interface as the means of communication with the user level.
@@ -149,7 +149,7 @@ void free_fib_info(struct fib_info *fi)
}
change_nexthops(fi) {
if (nh->nh_dev)
- dev_put(nh->nh_dev);
+ dev_put(nh->nh_dev, &(nh->nh_dev));
nh->nh_dev = NULL;
} endfor_nexthops(fi);
fib_info_cnt--;
@@ -510,7 +510,7 @@ static int fib_check_nh(const struct rtm
if (!(dev->flags&IFF_UP))
return -ENETDOWN;
nh->nh_dev = dev;
- dev_hold(dev);
+ dev_hold(dev, &(nh->nh_dev));
nh->nh_scope = RT_SCOPE_LINK;
return 0;
}
@@ -533,7 +533,7 @@ static int fib_check_nh(const struct rtm
nh->nh_oif = FIB_RES_OIF(res);
if ((nh->nh_dev = FIB_RES_DEV(res)) == NULL)
goto out;
- dev_hold(nh->nh_dev);
+ dev_hold(nh->nh_dev, &(nh->nh_dev));
err = -ENETDOWN;
if (!(nh->nh_dev->flags & IFF_UP))
goto out;
@@ -555,7 +555,7 @@ out:
return -ENETDOWN;
}
nh->nh_dev = in_dev->dev;
- dev_hold(nh->nh_dev);
+ dev_hold(nh->nh_dev, &(nh->nh_dev));
nh->nh_scope = RT_SCOPE_HOST;
in_dev_put(in_dev);
}
@@ -792,7 +792,7 @@ fib_create_info(const struct rtmsg *r, s
if (nhs != 1 || nh->nh_gw)
goto err_inval;
nh->nh_scope = RT_SCOPE_NOWHERE;
- nh->nh_dev = dev_get_by_index(fi->fib_nh->nh_oif);
+ nh->nh_dev = dev_get_by_index(fi->fib_nh->nh_oif, &(nh->nh_dev));
err = -ENODEV;
if (nh->nh_dev == NULL)
goto failure;
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -1,4 +1,4 @@
-/*
+/* -*- linux-c -*-
* Linux NET3: Internet Group Management Protocol [IGMP]
*
* This code implements the IGMP protocol as defined in RFC1112. There has
@@ -1311,10 +1311,10 @@ static struct in_device * ip_mc_find_dev
return idev;
}
if (imr->imr_address.s_addr) {
- dev = ip_dev_find(imr->imr_address.s_addr);
+ dev = ip_dev_find(imr->imr_address.s_addr, NDRK_IGMP);
if (!dev)
return NULL;
- __dev_put(dev);
+ __dev_put(dev, NDRK_IGMP);
}
if (!dev && !ip_route_output_key(&rt, &fl)) {
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -295,9 +295,10 @@ static void ip_expire(unsigned long arg)
if ((qp->last_in&FIRST_IN) && qp->fragments != NULL) {
struct sk_buff *head = qp->fragments;
/* Send an ICMP "Fragment Reassembly Timeout" message. */
- if ((head->dev = dev_get_by_index(qp->iif)) != NULL) {
+ if ((head->dev = dev_get_by_index(qp->iif, &(head->dev))) != NULL) {
icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0);
- dev_put(head->dev);
+ dev_put(head->dev, &(head->dev));
+ /* TODO: Set head->dev to NULL here??? --BLG */
}
}
out:
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -1,4 +1,4 @@
-/*
+/* -*- linux-c -*-
* Linux NET3: GRE over IP protocol decoder.
*
* Authors: Alexey Kuznetsov (kuznet@ms2.inr.ac.ru)
@@ -288,7 +288,7 @@ static struct ip_tunnel * ipgre_tunnel_l
nt = dev->priv;
nt->parms = *parms;
- dev_hold(dev);
+ dev_hold(dev, &(nt->dev));
ipgre_tunnel_link(nt);
return nt;
@@ -298,8 +298,9 @@ failed:
static void ipgre_tunnel_uninit(struct net_device *dev)
{
+ void* key = &(((struct ip_tunnel*)dev->priv)->dev);
ipgre_tunnel_unlink((struct ip_tunnel*)dev->priv);
- dev_put(dev);
+ dev_put(dev, key);
}
@@ -1229,7 +1230,7 @@ int __init ipgre_fb_tunnel_init(struct n
iph->ihl = 5;
tunnel->hlen = sizeof(struct iphdr) + 4;
- dev_hold(dev);
+ dev_hold(dev, &(tunnel->dev));
tunnels_wc[0] = tunnel;
return 0;
}
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -565,10 +565,10 @@ int ip_setsockopt(struct sock *sk, int l
err = 0;
break;
}
- dev = ip_dev_find(mreq.imr_address.s_addr);
+ dev = ip_dev_find(mreq.imr_address.s_addr, NDRK_SOCKGLUE);
if (dev) {
mreq.imr_ifindex = dev->ifindex;
- dev_put(dev);
+ dev_put(dev, NDRK_SOCKGLUE);
}
} else
dev = __dev_get_by_index(mreq.imr_ifindex);
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -1,4 +1,4 @@
-/*
+/* -*- linux-c -*-
* Linux NET3: IP/IP protocol decoder.
*
* Version: $Id: ipip.c,v 1.50 2001/10/02 02:22:36 davem Exp $
@@ -253,7 +253,7 @@ static struct ip_tunnel * ipip_tunnel_lo
goto failed;
}
- dev_hold(dev);
+ dev_hold(dev, &(nt->dev));
ipip_tunnel_link(nt);
return nt;
@@ -263,13 +263,14 @@ failed:
static void ipip_tunnel_uninit(struct net_device *dev)
{
+ void* key = &(((struct ip_tunnel*)dev->priv)->dev);
if (dev == ipip_fb_tunnel_dev) {
write_lock_bh(&ipip_lock);
tunnels_wc[0] = NULL;
write_unlock_bh(&ipip_lock);
} else
ipip_tunnel_unlink((struct ip_tunnel*)dev->priv);
- dev_put(dev);
+ dev_put(dev, key);
}
static void ipip_err(struct sk_buff *skb, u32 info)
@@ -846,7 +847,7 @@ static int __init ipip_fb_tunnel_init(st
iph->protocol = IPPROTO_IPIP;
iph->ihl = 5;
- dev_hold(dev);
+ dev_hold(dev, &(tunnel->dev));
tunnels_wc[0] = tunnel;
return 0;
}
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -1,4 +1,4 @@
-/*
+/* -*- linux-c -*-
* IP multicast routing support for mrouted 3.6/3.8
*
* (c) 1995 Alan Cox,
@@ -286,7 +286,7 @@ static int vif_delete(int vifi)
if (v->flags&(VIFF_TUNNEL|VIFF_REGISTER))
unregister_netdevice(dev);
- dev_put(dev);
+ dev_put(dev, &(v->dev));
return 0;
}
@@ -412,10 +412,10 @@ static int vif_add(struct vifctl *vifc,
return -ENOBUFS;
break;
case 0:
- dev=ip_dev_find(vifc->vifc_lcl_addr.s_addr);
+ dev=ip_dev_find(vifc->vifc_lcl_addr.s_addr, NDRK_IPMR);
if (!dev)
return -EADDRNOTAVAIL;
- __dev_put(dev);
+ __dev_put(dev, NDRK_IPMR);
break;
default:
return -EINVAL;
@@ -447,7 +447,7 @@ static int vif_add(struct vifctl *vifc,
/* And finish update writing critical data */
write_lock_bh(&mrt_lock);
- dev_hold(dev);
+ dev_hold(dev, &(v->dev));
v->dev=dev;
#ifdef CONFIG_IP_PIMSM
if (v->flags&VIFF_REGISTER)
@@ -1449,7 +1449,7 @@ int pim_rcv_v1(struct sk_buff * skb)
if (reg_vif_num >= 0)
reg_dev = vif_table[reg_vif_num].dev;
if (reg_dev)
- dev_hold(reg_dev);
+ dev_hold(reg_dev, NDRK_IPMR_RCV);
read_unlock(&mrt_lock);
if (reg_dev == NULL)
@@ -1469,7 +1469,7 @@ int pim_rcv_v1(struct sk_buff * skb)
((struct net_device_stats*)reg_dev->priv)->rx_packets++;
nf_reset(skb);
netif_rx(skb);
- dev_put(reg_dev);
+ dev_put(reg_dev, NDRK_IPMR_RCV);
return 0;
drop:
kfree_skb(skb);
@@ -1505,7 +1505,7 @@ static int pim_rcv(struct sk_buff * skb)
if (reg_vif_num >= 0)
reg_dev = vif_table[reg_vif_num].dev;
if (reg_dev)
- dev_hold(reg_dev);
+ dev_hold(reg_dev, NDRK_IPMR_RCV);
read_unlock(&mrt_lock);
if (reg_dev == NULL)
@@ -1525,7 +1525,7 @@ static int pim_rcv(struct sk_buff * skb)
skb->dst = NULL;
nf_reset(skb);
netif_rx(skb);
- dev_put(reg_dev);
+ dev_put(reg_dev, NDRK_IPMR_RCV);
return 0;
drop:
kfree_skb(skb);
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1,4 +1,4 @@
-/*
+/* -*- linux-c -*-
* INET An implementation of the TCP/IP protocol suite for the LINUX
* operating system. INET is implemented using the BSD Socket
* interface as the means of communication with the user level.
@@ -1181,7 +1181,7 @@ void ip_rt_redirect(u32 old_gw, u32 dadd
atomic_set(&rt->u.dst.__refcnt, 1);
rt->u.dst.child = NULL;
if (rt->u.dst.dev)
- dev_hold(rt->u.dst.dev);
+ dev_hold(rt->u.dst.dev, &(rt->u.dst.dev));
if (rt->idev)
in_dev_hold(rt->idev);
rt->u.dst.obsolete = 0;
@@ -1637,7 +1637,7 @@ static int ip_route_input_mc(struct sk_b
rth->rt_iif =
rth->fl.iif = dev->ifindex;
rth->u.dst.dev = &loopback_dev;
- dev_hold(rth->u.dst.dev);
+ dev_hold(rth->u.dst.dev, &(rth->u.dst.dev));
rth->idev = in_dev_get(rth->u.dst.dev);
rth->fl.oif = 0;
rth->rt_gateway = daddr;
@@ -1779,7 +1779,7 @@ static inline int __mkroute_input(struct
rth->rt_iif =
rth->fl.iif = in_dev->dev->ifindex;
rth->u.dst.dev = (out_dev)->dev;
- dev_hold(rth->u.dst.dev);
+ dev_hold(rth->u.dst.dev, &(rth->u.dst.dev));
rth->idev = in_dev_get(rth->u.dst.dev);
rth->fl.oif = 0;
rth->rt_spec_dst= spec_dst;
@@ -2030,7 +2030,7 @@ local_input:
rth->rt_iif =
rth->fl.iif = dev->ifindex;
rth->u.dst.dev = &loopback_dev;
- dev_hold(rth->u.dst.dev);
+ dev_hold(rth->u.dst.dev, &(rth->u.dst.dev));
rth->idev = in_dev_get(rth->u.dst.dev);
rth->rt_gateway = daddr;
rth->rt_spec_dst= spec_dst;
@@ -2232,7 +2232,7 @@ static inline int __mkroute_output(struc
/* get references to the devices that are to be hold by the routing
cache entry */
rth->u.dst.dev = dev_out;
- dev_hold(dev_out);
+ dev_hold(dev_out, &(rth->u.dst.dev));
rth->idev = in_dev_get(dev_out);
rth->rt_gateway = fl->fl4_dst;
rth->rt_spec_dst= fl->fl4_src;
@@ -2317,12 +2317,12 @@ static inline int ip_mkroute_output(stru
for (hop = 0; hop < hopcount; hop++) {
struct net_device *dev2nexthop;
-
+
res->nh_sel = hop;
/* hold a work reference to the output device */
dev2nexthop = FIB_RES_DEV(*res);
- dev_hold(dev2nexthop);
+ dev_hold(dev2nexthop, NDRK_ROUTE);
err = __mkroute_output(&rth, res, fl, oldflp,
dev2nexthop, flags);
@@ -2343,7 +2343,7 @@ static inline int ip_mkroute_output(stru
&FIB_RES_NH(*res));
cleanup:
/* release work reference to output device */
- dev_put(dev2nexthop);
+ dev_put(dev2nexthop, NDRK_ROUTE);
if (err != 0)
return err;
@@ -2385,7 +2385,6 @@ static int ip_route_output_slow(struct r
int free_res = 0;
int err;
-
res.fi = NULL;
#ifdef CONFIG_IP_MULTIPLE_TABLES
res.r = NULL;
@@ -2399,7 +2398,7 @@ static int ip_route_output_slow(struct r
goto out;
/* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */
- dev_out = ip_dev_find(oldflp->fl4_src);
+ dev_out = ip_dev_find(oldflp->fl4_src, NDRK_ROUTE_SLOW);
if (dev_out == NULL)
goto out;
@@ -2432,18 +2431,18 @@ static int ip_route_output_slow(struct r
goto make_route;
}
if (dev_out)
- dev_put(dev_out);
+ dev_put(dev_out, NDRK_ROUTE_SLOW);
dev_out = NULL;
}
if (oldflp->oif) {
- dev_out = dev_get_by_index(oldflp->oif);
+ dev_out = dev_get_by_index(oldflp->oif, NDRK_ROUTE_SLOW);
err = -ENODEV;
if (dev_out == NULL)
goto out;
if (__in_dev_get(dev_out) == NULL) {
- dev_put(dev_out);
+ dev_put(dev_out, NDRK_ROUTE_SLOW);
goto out; /* Wrong error code */
}
@@ -2468,9 +2467,9 @@ static int ip_route_output_slow(struct r
if (!fl.fl4_dst)
fl.fl4_dst = fl.fl4_src = htonl(INADDR_LOOPBACK);
if (dev_out)
- dev_put(dev_out);
+ dev_put(dev_out, NDRK_ROUTE_SLOW);
dev_out = &loopback_dev;
- dev_hold(dev_out);
+ dev_hold(dev_out, NDRK_ROUTE_SLOW);
fl.oif = loopback_dev.ifindex;
res.type = RTN_LOCAL;
flags |= RTCF_LOCAL;
@@ -2505,7 +2504,7 @@ static int ip_route_output_slow(struct r
goto make_route;
}
if (dev_out)
- dev_put(dev_out);
+ dev_put(dev_out, NDRK_ROUTE_SLOW);
err = -ENETUNREACH;
goto out;
}
@@ -2515,9 +2514,9 @@ static int ip_route_output_slow(struct r
if (!fl.fl4_src)
fl.fl4_src = fl.fl4_dst;
if (dev_out)
- dev_put(dev_out);
+ dev_put(dev_out, NDRK_ROUTE_SLOW);
dev_out = &loopback_dev;
- dev_hold(dev_out);
+ dev_hold(dev_out, NDRK_ROUTE_SLOW);
fl.oif = dev_out->ifindex;
if (res.fi)
fib_info_put(res.fi);
@@ -2538,9 +2537,9 @@ static int ip_route_output_slow(struct r
fl.fl4_src = FIB_RES_PREFSRC(res);
if (dev_out)
- dev_put(dev_out);
+ dev_put(dev_out, NDRK_ROUTE_SLOW);
dev_out = FIB_RES_DEV(res);
- dev_hold(dev_out);
+ dev_hold(dev_out, NDRK_ROUTE_SLOW);
fl.oif = dev_out->ifindex;
@@ -2551,7 +2550,7 @@ make_route:
if (free_res)
fib_res_put(&res);
if (dev_out)
- dev_put(dev_out);
+ dev_put(dev_out, NDRK_ROUTE_SLOW);
out: return err;
}
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -1,4 +1,4 @@
-/*
+/* -*- linux-c -*-
* xfrm4_policy.c
*
* Changes:
@@ -132,7 +132,7 @@ __xfrm4_bundle_create(struct xfrm_policy
dst_prev->xfrm = xfrm[i++];
dst_prev->dev = rt->u.dst.dev;
if (rt->u.dst.dev)
- dev_hold(rt->u.dst.dev);
+ dev_hold(rt->u.dst.dev, &(rt->u.dst.dev));
dst_prev->obsolete = -1;
dst_prev->flags |= DST_HOST;
dst_prev->lastuse = jiffies;
diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c
--- a/net/ipx/af_ipx.c
+++ b/net/ipx/af_ipx.c
@@ -1,4 +1,4 @@
-/*
+/* -*- linux-c -*-
* Implements an IPX socket layer.
*
* This code is derived from work by
@@ -324,7 +324,7 @@ static void __ipxitf_down(struct ipx_int
ipx_internal_net = NULL;
if (intrfc->if_dev)
- dev_put(intrfc->if_dev);
+ dev_put(intrfc->if_dev, &(intrfc->if_dev));
kfree(intrfc);
}
@@ -984,7 +984,7 @@ static int ipxitf_create(struct ipx_inte
if (intrfc)
ipxitf_put(intrfc);
- dev = dev_get_by_name(idef->ipx_device);
+ dev = dev_get_by_name(idef->ipx_device, NDRK_IPX);
rc = -ENODEV;
if (!dev)
goto out;
@@ -1052,6 +1052,11 @@ static int ipxitf_create(struct ipx_inte
memcpy(intrfc->if_node, idef->ipx_node, IPX_NODE_LEN);
ipxitf_hold(intrfc);
ipxitf_insert(intrfc);
+
+ /* Hold by correct netdevice refcount debugging key */
+ dev_hold(dev, &(intrfc->if_dev));
+ /* Release the old hold */
+ dev_put(dev, NDRK_IPX);
}
@@ -1065,7 +1070,7 @@ out_intrfc:
ipxitf_put(intrfc);
goto out;
out_dev:
- dev_put(dev);
+ dev_put(dev, NDRK_IPX);
out:
return rc;
}
@@ -1140,7 +1145,7 @@ static struct ipx_interface *ipxitf_auto
spin_lock_init(&intrfc->if_sklist_lock);
atomic_set(&intrfc->refcnt, 1);
ipxitf_insert(intrfc);
- dev_hold(dev);
+ dev_hold(dev, &(intrfc->if_dev));
}
out:
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -1,4 +1,4 @@
-/*
+/* -*- linux-c -*-
* INET An implementation of the TCP/IP protocol suite for the LINUX
* operating system. INET is implemented using the BSD Socket
* interface as the means of communication with the user level.
@@ -338,7 +338,7 @@ static int packet_sendmsg_spkt(struct ki
*/
saddr->spkt_device[13] = 0;
- dev = dev_get_by_name(saddr->spkt_device);
+ dev = dev_get_by_name(saddr->spkt_device, NDRK_AF_PKT);
err = -ENODEV;
if (dev == NULL)
goto out_unlock;
@@ -400,14 +400,14 @@ static int packet_sendmsg_spkt(struct ki
*/
dev_queue_xmit(skb);
- dev_put(dev);
+ dev_put(dev, NDRK_AF_PKT);
return(len);
out_free:
kfree_skb(skb);
out_unlock:
if (dev)
- dev_put(dev);
+ dev_put(dev, NDRK_AF_PKT);
return err;
}
#endif
@@ -722,7 +722,7 @@ static int packet_sendmsg(struct kiocb *
}
- dev = dev_get_by_index(ifindex);
+ dev = dev_get_by_index(ifindex, NDRK_AF_PKT);
err = -ENXIO;
if (dev == NULL)
goto out_unlock;
@@ -773,7 +773,7 @@ static int packet_sendmsg(struct kiocb *
if (err > 0 && (err = net_xmit_errno(err)) != 0)
goto out_unlock;
- dev_put(dev);
+ dev_put(dev, NDRK_AF_PKT);
return(len);
@@ -781,7 +781,7 @@ out_free:
kfree_skb(skb);
out_unlock:
if (dev)
- dev_put(dev);
+ dev_put(dev, NDRK_AF_PKT);
out:
return err;
}
@@ -921,10 +921,10 @@ static int packet_bind_spkt(struct socke
return -EINVAL;
strlcpy(name,uaddr->sa_data,sizeof(name));
- dev = dev_get_by_name(name);
+ dev = dev_get_by_name(name, NDRK_AF_PKT);
if (dev) {
err = packet_do_bind(sk, dev, pkt_sk(sk)->num);
- dev_put(dev);
+ dev_put(dev, NDRK_AF_PKT);
}
return err;
}
@@ -949,13 +949,13 @@ static int packet_bind(struct socket *so
if (sll->sll_ifindex) {
err = -ENODEV;
- dev = dev_get_by_index(sll->sll_ifindex);
+ dev = dev_get_by_index(sll->sll_ifindex, NDRK_AF_PKT);
if (dev == NULL)
goto out;
}
err = packet_do_bind(sk, dev, sll->sll_protocol ? : pkt_sk(sk)->num);
if (dev)
- dev_put(dev);
+ dev_put(dev, NDRK_AF_PKT);
out:
return err;
@@ -1130,10 +1130,10 @@ static int packet_getname_spkt(struct so
return -EOPNOTSUPP;
uaddr->sa_family = AF_PACKET;
- dev = dev_get_by_index(pkt_sk(sk)->ifindex);
+ dev = dev_get_by_index(pkt_sk(sk)->ifindex, NDRK_AF_PKT);
if (dev) {
strlcpy(uaddr->sa_data, dev->name, 15);
- dev_put(dev);
+ dev_put(dev, NDRK_AF_PKT);
} else
memset(uaddr->sa_data, 0, 14);
*uaddr_len = sizeof(*uaddr);
@@ -1156,12 +1156,12 @@ static int packet_getname(struct socket
sll->sll_family = AF_PACKET;
sll->sll_ifindex = po->ifindex;
sll->sll_protocol = po->num;
- dev = dev_get_by_index(po->ifindex);
+ dev = dev_get_by_index(po->ifindex, NDRK_AF_PKT);
if (dev) {
sll->sll_hatype = dev->type;
sll->sll_halen = dev->addr_len;
memcpy(sll->sll_addr, dev->dev_addr, dev->addr_len);
- dev_put(dev);
+ dev_put(dev, NDRK_AF_PKT);
} else {
sll->sll_hatype = 0; /* Bad: we have no ARPHRD_UNSPEC */
sll->sll_halen = 0;
@@ -1263,10 +1263,10 @@ static int packet_mc_drop(struct sock *s
if (--ml->count == 0) {
struct net_device *dev;
*mlp = ml->next;
- dev = dev_get_by_index(ml->ifindex);
+ dev = dev_get_by_index(ml->ifindex, NDRK_AF_PKT);
if (dev) {
packet_dev_mc(dev, ml, -1);
- dev_put(dev);
+ dev_put(dev, NDRK_AF_PKT);
}
kfree(ml);
}
@@ -1291,9 +1291,9 @@ static void packet_flush_mclist(struct s
struct net_device *dev;
po->mclist = ml->next;
- if ((dev = dev_get_by_index(ml->ifindex)) != NULL) {
+ if ((dev = dev_get_by_index(ml->ifindex, NDRK_AF_PKT)) != NULL) {
packet_dev_mc(dev, ml, -1);
- dev_put(dev);
+ dev_put(dev, NDRK_AF_PKT);
}
kfree(ml);
}
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -399,7 +399,7 @@ static int tc_dump_tfilter(struct sk_buf
if (cb->nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*tcm)))
return skb->len;
- if ((dev = dev_get_by_index(tcm->tcm_ifindex)) == NULL)
+ if ((dev = dev_get_by_index(tcm->tcm_ifindex, NDRK_TC_DUMP)) == NULL)
return skb->len;
read_lock_bh(&qdisc_tree_lock);
@@ -460,7 +460,7 @@ errout:
cops->put(q, cl);
out:
read_unlock_bh(&qdisc_tree_lock);
- dev_put(dev);
+ dev_put(dev, NDRK_TC_DUMP);
return skb->len;
}
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -133,7 +133,6 @@ static int tclass_notify(struct sk_buff
/* Protects list of registered TC modules. It is pure SMP lock. */
static DEFINE_RWLOCK(qdisc_mod_lock);
-
/************************************************
* Queueing disciplines manipulation. *
************************************************/
@@ -478,7 +477,7 @@ qdisc_create(struct net_device *dev, u32
return sch;
}
err_out3:
- dev_put(dev);
+ dev_put(dev, NDRK_SCHED);
kfree((char *) sch - sch->padded);
err_out2:
module_put(ops->owner);
@@ -1069,7 +1068,7 @@ static int tc_dump_tclass(struct sk_buff
if (cb->nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*tcm)))
return 0;
- if ((dev = dev_get_by_index(tcm->tcm_ifindex)) == NULL)
+ if ((dev = dev_get_by_index(tcm->tcm_ifindex, NDRK_SCHED)) == NULL)
return 0;
s_t = cb->args[0];
@@ -1101,7 +1100,7 @@ static int tc_dump_tclass(struct sk_buff
cb->args[0] = t;
- dev_put(dev);
+ dev_put(dev, NDRK_SCHED);
return skb->len;
}
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -1,4 +1,4 @@
-/*
+/* -*- linux-c -*-
* net/sched/sch_generic.c Generic packet scheduler routines.
*
* This program is free software; you can redistribute it and/or
@@ -186,7 +186,7 @@ requeue:
static void dev_watchdog(unsigned long arg)
{
struct net_device *dev = (struct net_device *)arg;
-
+
spin_lock(&dev->xmit_lock);
if (dev->qdisc != &noop_qdisc) {
if (netif_device_present(dev) &&
@@ -198,12 +198,12 @@ static void dev_watchdog(unsigned long a
dev->tx_timeout(dev);
}
if (!mod_timer(&dev->watchdog_timer, jiffies + dev->watchdog_timeo))
- dev_hold(dev);
+ dev_hold(dev, NDRK_SCHED);
}
}
spin_unlock(&dev->xmit_lock);
- dev_put(dev);
+ dev_put(dev, NDRK_SCHED);
}
static void dev_watchdog_init(struct net_device *dev)
@@ -219,7 +219,7 @@ void __netdev_watchdog_up(struct net_dev
if (dev->watchdog_timeo <= 0)
dev->watchdog_timeo = 5*HZ;
if (!mod_timer(&dev->watchdog_timer, jiffies + dev->watchdog_timeo))
- dev_hold(dev);
+ dev_hold(dev, NDRK_SCHED);
}
}
@@ -234,7 +234,7 @@ static void dev_watchdog_down(struct net
{
spin_lock_bh(&dev->xmit_lock);
if (del_timer(&dev->watchdog_timer))
- __dev_put(dev);
+ __dev_put(dev, NDRK_SCHED);
spin_unlock_bh(&dev->xmit_lock);
}
@@ -418,7 +418,7 @@ struct Qdisc *qdisc_alloc(struct net_dev
sch->enqueue = ops->enqueue;
sch->dequeue = ops->dequeue;
sch->dev = dev;
- dev_hold(dev);
+ dev_hold(dev, &(sch->dev));
sch->stats_lock = &dev->queue_lock;
atomic_set(&sch->refcnt, 1);
@@ -472,7 +472,7 @@ static void __qdisc_destroy(struct rcu_h
write_unlock(&qdisc_tree_lock);
module_put(ops->owner);
- dev_put(qdisc->dev);
+ dev_put(qdisc->dev, &(qdisc->dev));
kfree((char *) qdisc - qdisc->padded);
}
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -1032,9 +1032,9 @@ static int stale_bundle(struct dst_entry
void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev)
{
while ((dst = dst->child) && dst->xfrm && dst->dev == dev) {
+ dev_put(dev, &(dst->dev));
dst->dev = &loopback_dev;
- dev_hold(&loopback_dev);
- dev_put(dev);
+ dev_hold(&loopback_dev, &(dst->dev));
}
}
EXPORT_SYMBOL(xfrm_dst_ifdown);