Cleanup of net_device list use in net_dev core and IP. The cleanup consists of - converting the to list_head, to make the list double-linked (thus making remove operation O(1)), and list walks more readable; - introducing of for_each_netdev wrapper over list_for_each.
Signed-off-by: Andrey Savochkin <[EMAIL PROTECTED]> Signed-off-by: Kirill Korotaev <[EMAIL PROTECTED]> --- include/linux/netdevice.h | 29 ++++++++++++++++++++++++++- net/core/dev.c | 48 +++++++++++++++++++++++++--------------------- net/ipv4/devinet.c | 6 ++--- net/ipv6/addrconf.c | 8 +++---- net/ipv6/anycast.c | 10 +++++---- 5 files changed, 68 insertions(+), 33 deletions(-) --- ./include/linux/netdevice.h.vedevbase-core Mon Jul 3 15:14:15 2006 +++ ./include/linux/netdevice.h Mon Jul 3 16:09:11 2006 @@ -290,7 +290,8 @@ struct net_device unsigned long state; struct net_device *next; - + struct list_head dev_list; + /* The device initialization function. Called only once. */ int (*init)(struct net_device *dev); @@ -558,8 +559,34 @@ struct packet_type { extern struct net_device loopback_dev; /* The loopback */ extern struct net_device *dev_base; /* All devices */ +extern struct list_head dev_base_head; /* All devices */ extern rwlock_t dev_base_lock; /* Device list lock */ +#define for_each_netdev(p) list_for_each_entry(p, &dev_base_head, dev_list) + +/* + * When possible, it is preferrable to use for_each_netdev() loop + * defined above, rather than first_netdev()/next_netdev() macros. + * for_each_netdev() loop makes the intentions clearer, and gives more + * flexibility in device list implementation. + * While next_netdev() is unavoidable in seq_proc functions, + * first_netdev() should be needed quite rarely. + */ +#define first_netdev() ({ \ + list_empty(&dev_base_head) ? NULL : \ + list_entry(dev_base_head.next, \ + struct net_device, \ + dev_list); \ + }) +#define next_netdev(dev) ({ \ + struct list_head *__next; \ + __next = (dev)->dev_list.next; \ + __next == &dev_base_head ? NULL : \ + list_entry(__next, \ + struct net_device, \ + dev_list); \ + }) + 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); --- ./net/core/dev.c.vedevbase-core Mon Jul 3 15:14:19 2006 +++ ./net/core/dev.c Mon Jul 3 16:09:11 2006 @@ -181,6 +181,9 @@ DEFINE_RWLOCK(dev_base_lock); EXPORT_SYMBOL(dev_base); EXPORT_SYMBOL(dev_base_lock); +LIST_HEAD(dev_base_head); +EXPORT_SYMBOL(dev_base_head); + #define NETDEV_HASHBITS 8 static struct hlist_head dev_name_head[1<<NETDEV_HASHBITS]; static struct hlist_head dev_index_head[1<<NETDEV_HASHBITS]; @@ -575,11 +578,11 @@ struct net_device *dev_getbyhwaddr(unsig ASSERT_RTNL(); - for (dev = dev_base; dev; dev = dev->next) + for_each_netdev(dev) if (dev->type == type && !memcmp(dev->dev_addr, ha, dev->addr_len)) - break; - return dev; + return dev; + return NULL; } EXPORT_SYMBOL(dev_getbyhwaddr); @@ -589,14 +592,15 @@ struct net_device *dev_getfirstbyhwtype( struct net_device *dev; rtnl_lock(); - for (dev = dev_base; dev; dev = dev->next) { + for_each_netdev(dev) { if (dev->type == type) { dev_hold(dev); - break; + rtnl_unlock(); + return dev; } } rtnl_unlock(); - return dev; + return NULL; } EXPORT_SYMBOL(dev_getfirstbyhwtype); @@ -617,14 +621,15 @@ struct net_device * dev_get_by_flags(uns struct net_device *dev; read_lock(&dev_base_lock); - for (dev = dev_base; dev != NULL; dev = dev->next) { + for_each_netdev(dev) { if (((dev->flags ^ if_flags) & mask) == 0) { dev_hold(dev); - break; + read_unlock(&dev_base_lock); + return dev; } } read_unlock(&dev_base_lock); - return dev; + return NULL; } /** @@ -680,7 +685,7 @@ int dev_alloc_name(struct net_device *de if (!inuse) return -ENOMEM; - for (d = dev_base; d; d = d->next) { + for_each_netdev(d) { if (!sscanf(d->name, name, &i)) continue; if (i < 0 || i >= max_netdevices) @@ -966,7 +971,7 @@ int register_netdevice_notifier(struct n rtnl_lock(); err = raw_notifier_chain_register(&netdev_chain, nb); if (!err) { - for (dev = dev_base; dev; dev = dev->next) { + for_each_netdev(dev) { nb->notifier_call(nb, NETDEV_REGISTER, dev); if (dev->flags & IFF_UP) @@ -2035,7 +2040,7 @@ static int dev_ifconf(char __user *arg) */ total = 0; - for (dev = dev_base; dev; dev = dev->next) { + for_each_netdev(dev) { for (i = 0; i < NPROTO; i++) { if (gifconf_list[i]) { int done; @@ -2974,6 +2979,7 @@ int register_netdevice(struct net_device write_lock_bh(&dev_base_lock); *dev_tail = dev; dev_tail = &dev->next; + list_add_tail(&dev->dev_list, &dev_base_head); hlist_add_head(&dev->name_hlist, head); hlist_add_head(&dev->index_hlist, dev_index_hash(dev->ifindex)); dev_hold(dev); @@ -3271,22 +3277,22 @@ int unregister_netdevice(struct net_devi /* And unlink it from device chain. */ for (dp = &dev_base; (d = *dp) != NULL; dp = &d->next) { - if (d == dev) { - write_lock_bh(&dev_base_lock); - hlist_del(&dev->name_hlist); - hlist_del(&dev->index_hlist); - if (dev_tail == &dev->next) - dev_tail = dp; - *dp = d->next; - write_unlock_bh(&dev_base_lock); + if (d == dev) break; - } } if (!d) { printk(KERN_ERR "unregister net_device: '%s' not found\n", dev->name); return -ENODEV; } + write_lock_bh(&dev_base_lock); + list_del(&dev->dev_list); + hlist_del(&dev->name_hlist); + hlist_del(&dev->index_hlist); + if (dev_tail == &dev->next) + dev_tail = dp; + *dp = d->next; + write_unlock_bh(&dev_base_lock); dev->reg_state = NETREG_UNREGISTERING; --- ./net/ipv4/devinet.c.vedevbase-core Mon Jul 3 15:14:20 2006 +++ ./net/ipv4/devinet.c Mon Jul 3 16:09:11 2006 @@ -841,7 +841,7 @@ no_in_dev: */ read_lock(&dev_base_lock); rcu_read_lock(); - for (dev = dev_base; dev; dev = dev->next) { + for_each_netdev(dev) { if ((in_dev = __in_dev_get_rcu(dev)) == NULL) continue; @@ -920,7 +920,7 @@ u32 inet_confirm_addr(const struct net_d read_lock(&dev_base_lock); rcu_read_lock(); - for (dev = dev_base; dev; dev = dev->next) { + for_each_netdev(dev) { if ((in_dev = __in_dev_get_rcu(dev))) { addr = confirm_addr_indev(in_dev, dst, local, scope); if (addr) @@ -1170,7 +1170,7 @@ void inet_forward_change(void) ipv4_devconf_dflt.forwarding = on; read_lock(&dev_base_lock); - for (dev = dev_base; dev; dev = dev->next) { + for_each_netdev(dev) { struct in_device *in_dev; rcu_read_lock(); in_dev = __in_dev_get_rcu(dev); --- ./net/ipv6/addrconf.c.vedevbase-core Mon Jul 3 15:14:22 2006 +++ ./net/ipv6/addrconf.c Mon Jul 3 16:09:11 2006 @@ -469,7 +469,7 @@ static void addrconf_forward_change(void struct inet6_dev *idev; read_lock(&dev_base_lock); - for (dev=dev_base; dev; dev=dev->next) { + for_each_netdev(dev) { read_lock(&addrconf_lock); idev = __in6_dev_get(dev); if (idev) { @@ -894,7 +894,7 @@ int ipv6_dev_get_saddr(struct net_device read_lock(&dev_base_lock); read_lock(&addrconf_lock); - for (dev = dev_base; dev; dev=dev->next) { + for_each_netdev(dev) { struct inet6_dev *idev; struct inet6_ifaddr *ifa; @@ -1979,7 +1979,7 @@ static void sit_add_v4_addrs(struct inet return; } - for (dev = dev_base; dev != NULL; dev = dev->next) { + for_each_netdev(dev) { struct in_device * in_dev = __in_dev_get_rtnl(dev); if (in_dev && (dev->flags & IFF_UP)) { struct in_ifaddr * ifa; @@ -2128,7 +2128,7 @@ static void ip6_tnl_add_linklocal(struct return; } /* then try to inherit it from any device */ - for (link_dev = dev_base; link_dev; link_dev = link_dev->next) { + for_each_netdev(link_dev) { if (!ipv6_inherit_linklocal(idev, link_dev)) return; } --- ./net/ipv6/anycast.c.vedevbase-core Mon Jul 3 15:14:22 2006 +++ ./net/ipv6/anycast.c Mon Jul 3 16:09:11 2006 @@ -427,11 +427,13 @@ int ipv6_chk_acast_addr(struct net_devic if (dev) return ipv6_chk_acast_dev(dev, addr); read_lock(&dev_base_lock); - for (dev=dev_base; dev; dev=dev->next) - if (ipv6_chk_acast_dev(dev, addr)) - break; + for_each_netdev(dev) + if (ipv6_chk_acast_dev(dev, addr)) { + read_unlock(&dev_base_lock); + return 1; + } read_unlock(&dev_base_lock); - return dev != 0; + return 0; } - To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html