Commit fa13a7b8 authored by Stephen Hemminger's avatar Stephen Hemminger

[NET]: Hash netdevices by name for faster lookup.

parent cc1b2ba8
...@@ -375,6 +375,8 @@ struct net_device ...@@ -375,6 +375,8 @@ struct net_device
atomic_t refcnt; atomic_t refcnt;
/* delayed register/unregister */ /* delayed register/unregister */
struct list_head todo_list; struct list_head todo_list;
/* device name hash chain */
struct hlist_node name_hlist;
/* register/unregister state machine */ /* register/unregister state machine */
enum { NETREG_UNINITIALIZED=0, enum { NETREG_UNINITIALIZED=0,
......
...@@ -180,11 +180,21 @@ static struct timer_list samp_timer = TIMER_INITIALIZER(sample_queue, 0, 0); ...@@ -180,11 +180,21 @@ static struct timer_list samp_timer = TIMER_INITIALIZER(sample_queue, 0, 0);
* semaphore held. * semaphore held.
*/ */
struct net_device *dev_base; struct net_device *dev_base;
struct net_device **dev_tail = &dev_base;
rwlock_t dev_base_lock = RW_LOCK_UNLOCKED; rwlock_t dev_base_lock = RW_LOCK_UNLOCKED;
EXPORT_SYMBOL(dev_base); EXPORT_SYMBOL(dev_base);
EXPORT_SYMBOL(dev_base_lock); EXPORT_SYMBOL(dev_base_lock);
#define NETDEV_HASHBITS 8
static struct hlist_head dev_name_head[1<<NETDEV_HASHBITS];
static inline struct hlist_head *dev_name_hash(const char *name)
{
unsigned hash = full_name_hash(name, strnlen(name, IFNAMSIZ));
return &dev_name_head[hash & ((1<<NETDEV_HASHBITS)-1)];
}
/* /*
* Our notifier list * Our notifier list
*/ */
...@@ -468,12 +478,15 @@ __setup("netdev=", netdev_boot_setup); ...@@ -468,12 +478,15 @@ __setup("netdev=", netdev_boot_setup);
struct net_device *__dev_get_by_name(const char *name) struct net_device *__dev_get_by_name(const char *name)
{ {
struct net_device *dev; struct hlist_node *p;
for (dev = dev_base; dev; dev = dev->next) hlist_for_each(p, dev_name_hash(name)) {
struct net_device *dev
= hlist_entry(p, struct net_device, name_hlist);
if (!strncmp(dev->name, name, IFNAMSIZ)) if (!strncmp(dev->name, name, IFNAMSIZ))
break;
return dev; return dev;
}
return NULL;
} }
/** /**
...@@ -754,6 +767,9 @@ int dev_change_name(struct net_device *dev, char *newname) ...@@ -754,6 +767,9 @@ int dev_change_name(struct net_device *dev, char *newname)
else else
strlcpy(dev->name, newname, IFNAMSIZ); strlcpy(dev->name, newname, IFNAMSIZ);
hlist_del(&dev->name_hlist);
hlist_add_head(&dev->name_hlist, dev_name_hash(dev->name));
class_device_rename(&dev->class_dev, dev->name); class_device_rename(&dev->class_dev, dev->name);
notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev); notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev);
return 0; return 0;
...@@ -2742,7 +2758,8 @@ static inline void net_set_todo(struct net_device *dev) ...@@ -2742,7 +2758,8 @@ static inline void net_set_todo(struct net_device *dev)
int register_netdevice(struct net_device *dev) int register_netdevice(struct net_device *dev)
{ {
struct net_device *d, **dp; struct hlist_head *head;
struct hlist_node *p;
int ret; int ret;
BUG_ON(dev_boot_phase); BUG_ON(dev_boot_phase);
...@@ -2783,12 +2800,16 @@ int register_netdevice(struct net_device *dev) ...@@ -2783,12 +2800,16 @@ int register_netdevice(struct net_device *dev)
if (dev->iflink == -1) if (dev->iflink == -1)
dev->iflink = dev->ifindex; dev->iflink = dev->ifindex;
/* Check for existence, and append to tail of chain */ /* Check for existence of name */
head = dev_name_hash(dev->name);
hlist_for_each(p, head) {
struct net_device *d
= hlist_entry(p, struct net_device, name_hlist);
if (!strncmp(d->name, dev->name, IFNAMSIZ)) {
ret = -EEXIST; ret = -EEXIST;
for (dp = &dev_base; (d = *dp) != NULL; dp = &d->next) {
if (d == dev || !strcmp(d->name, dev->name))
goto out_err; goto out_err;
} }
}
/* Fix illegal SG+CSUM combinations. */ /* Fix illegal SG+CSUM combinations. */
if ((dev->features & NETIF_F_SG) && if ((dev->features & NETIF_F_SG) &&
...@@ -2818,7 +2839,9 @@ int register_netdevice(struct net_device *dev) ...@@ -2818,7 +2839,9 @@ int register_netdevice(struct net_device *dev)
dev->next = NULL; dev->next = NULL;
dev_init_scheduler(dev); dev_init_scheduler(dev);
write_lock_bh(&dev_base_lock); write_lock_bh(&dev_base_lock);
*dp = dev; *dev_tail = dev;
dev_tail = &dev->next;
hlist_add_head(&dev->name_hlist, head);
dev_hold(dev); dev_hold(dev);
dev->reg_state = NETREG_REGISTERING; dev->reg_state = NETREG_REGISTERING;
write_unlock_bh(&dev_base_lock); write_unlock_bh(&dev_base_lock);
...@@ -3040,6 +3063,9 @@ int unregister_netdevice(struct net_device *dev) ...@@ -3040,6 +3063,9 @@ int unregister_netdevice(struct net_device *dev)
for (dp = &dev_base; (d = *dp) != NULL; dp = &d->next) { for (dp = &dev_base; (d = *dp) != NULL; dp = &d->next) {
if (d == dev) { if (d == dev) {
write_lock_bh(&dev_base_lock); write_lock_bh(&dev_base_lock);
hlist_del(&dev->name_hlist);
if (dev_tail == &dev->next)
dev_tail = dp;
*dp = d->next; *dp = d->next;
write_unlock_bh(&dev_base_lock); write_unlock_bh(&dev_base_lock);
break; break;
...@@ -3116,6 +3142,9 @@ static int __init net_dev_init(void) ...@@ -3116,6 +3142,9 @@ static int __init net_dev_init(void)
for (i = 0; i < 16; i++) for (i = 0; i < 16; i++)
INIT_LIST_HEAD(&ptype_base[i]); INIT_LIST_HEAD(&ptype_base[i]);
for (i = 0; i < ARRAY_SIZE(dev_name_head); i++)
INIT_HLIST_HEAD(&dev_name_head[i]);
/* /*
* Initialise the packet receive queues. * Initialise the packet receive queues.
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment