[NET]: Rework dev_base via list_head (v3)
Cleanup of dev_base list use, with the aim to simplify making device list per-namespace. In almost every occasion, use of dev_base variable and dev->next pointer could be easily replaced by for_each_netdev loop. A few most complicated places were converted to using first_netdev()/next_netdev(). Signed-off-by: Pavel Emelianov <xemul@openvz.org> Acked-by: Kirill Korotaev <dev@openvz.org> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
03fba04796
commit
7562f876cd
@@ -156,13 +156,13 @@ static spinlock_t net_dma_event_lock;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The @dev_base list is protected by @dev_base_lock and the rtnl
|
||||
* The @dev_base_head list is protected by @dev_base_lock and the rtnl
|
||||
* semaphore.
|
||||
*
|
||||
* Pure readers hold dev_base_lock for reading.
|
||||
*
|
||||
* Writers must hold the rtnl semaphore while they loop through the
|
||||
* dev_base list, and hold dev_base_lock for writing when they do the
|
||||
* dev_base_head list, and hold dev_base_lock for writing when they do the
|
||||
* actual updates. This allows pure readers to access the list even
|
||||
* while a writer is preparing to update it.
|
||||
*
|
||||
@@ -174,11 +174,10 @@ static spinlock_t net_dma_event_lock;
|
||||
* unregister_netdevice(), which must be called with the rtnl
|
||||
* semaphore held.
|
||||
*/
|
||||
struct net_device *dev_base;
|
||||
static struct net_device **dev_tail = &dev_base;
|
||||
LIST_HEAD(dev_base_head);
|
||||
DEFINE_RWLOCK(dev_base_lock);
|
||||
|
||||
EXPORT_SYMBOL(dev_base);
|
||||
EXPORT_SYMBOL(dev_base_head);
|
||||
EXPORT_SYMBOL(dev_base_lock);
|
||||
|
||||
#define NETDEV_HASHBITS 8
|
||||
@@ -567,11 +566,12 @@ struct net_device *dev_getbyhwaddr(unsigned short type, char *ha)
|
||||
|
||||
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);
|
||||
@@ -581,11 +581,11 @@ struct net_device *__dev_getfirstbyhwtype(unsigned short type)
|
||||
struct net_device *dev;
|
||||
|
||||
ASSERT_RTNL();
|
||||
for (dev = dev_base; dev; dev = dev->next) {
|
||||
for_each_netdev(dev)
|
||||
if (dev->type == type)
|
||||
break;
|
||||
}
|
||||
return dev;
|
||||
return dev;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(__dev_getfirstbyhwtype);
|
||||
@@ -617,17 +617,19 @@ EXPORT_SYMBOL(dev_getfirstbyhwtype);
|
||||
|
||||
struct net_device * dev_get_by_flags(unsigned short if_flags, unsigned short mask)
|
||||
{
|
||||
struct net_device *dev;
|
||||
struct net_device *dev, *ret;
|
||||
|
||||
ret = NULL;
|
||||
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);
|
||||
ret = dev;
|
||||
break;
|
||||
}
|
||||
}
|
||||
read_unlock(&dev_base_lock);
|
||||
return dev;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -693,7 +695,7 @@ int dev_alloc_name(struct net_device *dev, const char *name)
|
||||
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)
|
||||
@@ -975,7 +977,7 @@ int register_netdevice_notifier(struct notifier_block *nb)
|
||||
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)
|
||||
@@ -2049,7 +2051,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;
|
||||
@@ -2081,26 +2083,28 @@ static int dev_ifconf(char __user *arg)
|
||||
* This is invoked by the /proc filesystem handler to display a device
|
||||
* in detail.
|
||||
*/
|
||||
static struct net_device *dev_get_idx(loff_t pos)
|
||||
{
|
||||
struct net_device *dev;
|
||||
loff_t i;
|
||||
|
||||
for (i = 0, dev = dev_base; dev && i < pos; ++i, dev = dev->next);
|
||||
|
||||
return i == pos ? dev : NULL;
|
||||
}
|
||||
|
||||
void *dev_seq_start(struct seq_file *seq, loff_t *pos)
|
||||
{
|
||||
loff_t off;
|
||||
struct net_device *dev;
|
||||
|
||||
read_lock(&dev_base_lock);
|
||||
return *pos ? dev_get_idx(*pos - 1) : SEQ_START_TOKEN;
|
||||
if (!*pos)
|
||||
return SEQ_START_TOKEN;
|
||||
|
||||
off = 1;
|
||||
for_each_netdev(dev)
|
||||
if (off++ == *pos)
|
||||
return dev;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
|
||||
{
|
||||
++*pos;
|
||||
return v == SEQ_START_TOKEN ? dev_base : ((struct net_device *)v)->next;
|
||||
return v == SEQ_START_TOKEN ?
|
||||
first_net_device() : next_net_device((struct net_device *)v);
|
||||
}
|
||||
|
||||
void dev_seq_stop(struct seq_file *seq, void *v)
|
||||
@@ -3082,11 +3086,9 @@ int register_netdevice(struct net_device *dev)
|
||||
|
||||
set_bit(__LINK_STATE_PRESENT, &dev->state);
|
||||
|
||||
dev->next = NULL;
|
||||
dev_init_scheduler(dev);
|
||||
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);
|
||||
@@ -3360,8 +3362,6 @@ void synchronize_net(void)
|
||||
|
||||
void unregister_netdevice(struct net_device *dev)
|
||||
{
|
||||
struct net_device *d, **dp;
|
||||
|
||||
BUG_ON(dev_boot_phase);
|
||||
ASSERT_RTNL();
|
||||
|
||||
@@ -3381,19 +3381,11 @@ void unregister_netdevice(struct net_device *dev)
|
||||
dev_close(dev);
|
||||
|
||||
/* 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);
|
||||
break;
|
||||
}
|
||||
}
|
||||
BUG_ON(!d);
|
||||
write_lock_bh(&dev_base_lock);
|
||||
list_del(&dev->dev_list);
|
||||
hlist_del(&dev->name_hlist);
|
||||
hlist_del(&dev->index_hlist);
|
||||
write_unlock_bh(&dev_base_lock);
|
||||
|
||||
dev->reg_state = NETREG_UNREGISTERING;
|
||||
|
||||
|
@@ -223,7 +223,7 @@ static void *dev_mc_seq_start(struct seq_file *seq, loff_t *pos)
|
||||
loff_t off = 0;
|
||||
|
||||
read_lock(&dev_base_lock);
|
||||
for (dev = dev_base; dev; dev = dev->next) {
|
||||
for_each_netdev(dev) {
|
||||
if (off++ == *pos)
|
||||
return dev;
|
||||
}
|
||||
@@ -232,9 +232,8 @@ static void *dev_mc_seq_start(struct seq_file *seq, loff_t *pos)
|
||||
|
||||
static void *dev_mc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
|
||||
{
|
||||
struct net_device *dev = v;
|
||||
++*pos;
|
||||
return dev->next;
|
||||
return next_net_device((struct net_device *)v);
|
||||
}
|
||||
|
||||
static void dev_mc_seq_stop(struct seq_file *seq, void *v)
|
||||
|
@@ -539,13 +539,16 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
int s_idx = cb->args[0];
|
||||
struct net_device *dev;
|
||||
|
||||
for (dev=dev_base, idx=0; dev; dev = dev->next, idx++) {
|
||||
idx = 0;
|
||||
for_each_netdev(dev) {
|
||||
if (idx < s_idx)
|
||||
continue;
|
||||
goto cont;
|
||||
if (rtnl_fill_ifinfo(skb, dev, NULL, 0, RTM_NEWLINK,
|
||||
NETLINK_CB(cb->skb).pid,
|
||||
cb->nlh->nlmsg_seq, 0, NLM_F_MULTI) <= 0)
|
||||
break;
|
||||
cont:
|
||||
idx++;
|
||||
}
|
||||
cb->args[0] = idx;
|
||||
|
||||
|
Reference in New Issue
Block a user