diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 0addd45..39c65a2 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -56,6 +56,9 @@ struct net { struct list_head dev_base_head; struct hlist_head *dev_name_head; struct hlist_head *dev_index_head; + /* fast consecutive name allocation (e.g. eth0, eth1, ...) */ + char fcna_name[IFNAMSIZ]; + int fcna_no; /* core fib_rules */ struct list_head rules_ops; diff --git a/net/core/dev.c b/net/core/dev.c index ad8e320..008e3c7 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -226,8 +226,12 @@ static int list_netdevice(struct net_device *dev) */ static void unlist_netdevice(struct net_device *dev) { + struct net *net = dev_net(dev); + ASSERT_RTNL(); + net->fcna_no = -1; + /* Unlink dev from the device chain */ write_lock_bh(&dev_base_lock); list_del_rcu(&dev->dev_list); @@ -872,6 +876,16 @@ static int __dev_alloc_name(struct net *net, const char *name, char *buf) if (p[1] != 'd' || strchr(p + 2, '%')) return -EINVAL; + /* avoid fast allocation for strange templates like "fan%dcy" */ + if (net->fcna_no >= 0 && p[2] == 0 && + net->fcna_name[p - name] == 0 && + memcmp(name, net->fcna_name, p - name) == 0) { + snprintf(buf, IFNAMSIZ, name, ++net->fcna_no); + if (!__dev_get_by_name(net, buf)) + return net->fcna_no; + net->fcna_no = -1; + } + /* Use one page as a bit array of possible slots */ inuse = (unsigned long *) get_zeroed_page(GFP_ATOMIC); if (!inuse) @@ -894,8 +908,15 @@ static int __dev_alloc_name(struct net *net, const char *name, char *buf) } snprintf(buf, IFNAMSIZ, name, i); - if (!__dev_get_by_name(net, buf)) + if (!__dev_get_by_name(net, buf)) { + if (p[2] == 0) { + memcpy(net->fcna_name, name, p - name); + net->fcna_name[p - name] = 0; + net->fcna_no = i; + } else + net->fcna_no = -1; return i; + } /* It is possible to run out of possible slots * when the name is long and there isn't enough space left