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);