Commit 7562f876 authored by Pavel Emelianov's avatar Pavel Emelianov Committed by David S. Miller

[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: default avatarPavel Emelianov <xemul@openvz.org>
Acked-by: default avatarKirill Korotaev <dev@openvz.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 03fba047
......@@ -107,7 +107,7 @@ static void appldata_get_net_sum_data(void *data)
tx_dropped = 0;
collisions = 0;
read_lock(&dev_base_lock);
for (dev = dev_base; dev != NULL; dev = dev->next) {
for_each_netdev(dev) {
stats = dev->get_stats(dev);
rx_packets += stats->rx_packets;
tx_packets += stats->tx_packets;
......
......@@ -686,7 +686,8 @@ static inline int solaris_i(unsigned int fd, unsigned int cmd, u32 arg)
int i = 0;
read_lock_bh(&dev_base_lock);
for (d = dev_base; d; d = d->next) i++;
for_each_netdev(d)
i++;
read_unlock_bh(&dev_base_lock);
if (put_user (i, (int __user *)A(arg)))
......
......@@ -194,15 +194,15 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff **tail)
sl = sl_tail = NULL;
read_lock(&dev_base_lock);
for (ifp = dev_base; ifp; dev_put(ifp), ifp = ifp->next) {
for_each_netdev(ifp) {
dev_hold(ifp);
if (!is_aoe_netif(ifp))
continue;
goto cont;
skb = new_skb(sizeof *h + sizeof *ch);
if (skb == NULL) {
printk(KERN_INFO "aoe: skb alloc failure\n");
continue;
goto cont;
}
skb_put(skb, sizeof *h + sizeof *ch);
skb->dev = ifp;
......@@ -221,6 +221,8 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff **tail)
skb->next = sl;
sl = skb;
cont:
dev_put(ifp);
}
read_unlock(&dev_base_lock);
......
......@@ -1971,8 +1971,7 @@ static struct net_device *get_strip_dev(struct strip *strip_info)
sizeof(zero_address))) {
struct net_device *dev;
read_lock_bh(&dev_base_lock);
dev = dev_base;
while (dev) {
for_each_netdev(dev) {
if (dev->type == strip_info->dev->type &&
!memcmp(dev->dev_addr,
&strip_info->true_dev_addr,
......@@ -1983,7 +1982,6 @@ static struct net_device *get_strip_dev(struct strip *strip_info)
read_unlock_bh(&dev_base_lock);
return (dev);
}
dev = dev->next;
}
read_unlock_bh(&dev_base_lock);
}
......
......@@ -365,7 +365,7 @@ static __inline__ int led_get_net_activity(void)
* for reading should be OK */
read_lock(&dev_base_lock);
rcu_read_lock();
for (dev = dev_base; dev; dev = dev->next) {
for_each_netdev(dev) {
struct net_device_stats *stats;
struct in_device *in_dev = __in_dev_get_rcu(dev);
if (!in_dev || !in_dev->ifa_list)
......
......@@ -47,7 +47,7 @@ int afs_get_ipv4_interfaces(struct afs_interface *bufs, size_t maxbufs,
ASSERT(maxbufs > 0);
rtnl_lock();
for (dev = dev_base; dev; dev = dev->next) {
for_each_netdev(dev) {
if (dev->type == ARPHRD_LOOPBACK && !wantloopback)
continue;
idev = __in_dev_get_rtnl(dev);
......
......@@ -304,7 +304,7 @@ 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);
......@@ -575,9 +575,31 @@ struct packet_type {
#include <linux/notifier.h>
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(d) \
list_for_each_entry(d, &dev_base_head, dev_list)
#define for_each_netdev_safe(d, n) \
list_for_each_entry_safe(d, n, &dev_base_head, dev_list)
#define for_each_netdev_continue(d) \
list_for_each_entry_continue(d, &dev_base_head, dev_list)
#define net_device_entry(lh) list_entry(lh, struct net_device, dev_list)
static inline struct net_device *next_net_device(struct net_device *dev)
{
struct list_head *lh;
lh = dev->dev_list.next;
return lh == &dev_base_head ? NULL : net_device_entry(lh);
}
static inline struct net_device *first_net_device(void)
{
return list_empty(&dev_base_head) ? NULL :
net_device_entry(dev_base_head.next);
}
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);
......
......@@ -117,8 +117,7 @@ static void __exit vlan_cleanup_devices(void)
struct net_device *dev, *nxt;
rtnl_lock();
for (dev = dev_base; dev; dev = nxt) {
nxt = dev->next;
for_each_netdev_safe(dev, nxt) {
if (dev->priv_flags & IFF_802_1Q_VLAN) {
unregister_vlan_dev(VLAN_DEV_INFO(dev)->real_dev,
VLAN_DEV_INFO(dev)->vlan_id);
......
......@@ -237,13 +237,9 @@ int vlan_proc_rem_dev(struct net_device *vlandev)
* The following few functions build the content of /proc/net/vlan/config
*/
/* starting at dev, find a VLAN device */
static struct net_device *vlan_skip(struct net_device *dev)
static inline int is_vlan_dev(struct net_device *dev)
{
while (dev && !(dev->priv_flags & IFF_802_1Q_VLAN))
dev = dev->next;
return dev;
return dev->priv_flags & IFF_802_1Q_VLAN;
}
/* start read of /proc/net/vlan/config */
......@@ -257,19 +253,35 @@ static void *vlan_seq_start(struct seq_file *seq, loff_t *pos)
if (*pos == 0)
return SEQ_START_TOKEN;
for (dev = vlan_skip(dev_base); dev && i < *pos;
dev = vlan_skip(dev->next), ++i);
for_each_netdev(dev) {
if (!is_vlan_dev(dev))
continue;
if (i++ == *pos)
return dev;
}
return (i == *pos) ? dev : NULL;
return NULL;
}
static void *vlan_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
struct net_device *dev;
++*pos;
return vlan_skip((v == SEQ_START_TOKEN)
? dev_base
: ((struct net_device *)v)->next);
dev = (struct net_device *)v;
if (v == SEQ_START_TOKEN)
dev = net_device_entry(&dev_base_head);
for_each_netdev_continue(dev) {
if (!is_vlan_dev(dev))
continue;
return dev;
}
return NULL;
}
static void vlan_seq_stop(struct seq_file *seq, void *v)
......
......@@ -475,11 +475,9 @@ void __exit br_cleanup_bridges(void)
struct net_device *dev, *nxt;
rtnl_lock();
for (dev = dev_base; dev; dev = nxt) {
nxt = dev->next;
for_each_netdev_safe(dev, nxt)
if (dev->priv_flags & IFF_EBRIDGE)
del_br(dev->priv);
}
rtnl_unlock();
}
......@@ -27,7 +27,9 @@ static int get_bridge_ifindices(int *indices, int num)
struct net_device *dev;
int i = 0;
for (dev = dev_base; dev && i < num; dev = dev->next) {
for_each_netdev(dev) {
if (i >= num)
break;
if (dev->priv_flags & IFF_EBRIDGE)
indices[i++] = dev->ifindex;
}
......
......@@ -109,7 +109,8 @@ static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
struct net_device *dev;
int idx;
for (dev = dev_base, idx = 0; dev; dev = dev->next) {
idx = 0;
for_each_netdev(dev) {
/* not a bridge port */
if (dev->br_port == NULL || idx < cb->args[0])
goto skip;
......
......@@ -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)
void *dev_seq_start(struct seq_file *seq, loff_t *pos)
{
loff_t off;
struct net_device *dev;
loff_t i;
for (i = 0, dev = dev_base; dev && i < pos; ++i, dev = dev->next);
read_lock(&dev_base_lock);
if (!*pos)
return SEQ_START_TOKEN;
return i == pos ? dev : NULL;
}
off = 1;
for_each_netdev(dev)
if (off++ == *pos)
return dev;
void *dev_seq_start(struct seq_file *seq, loff_t *pos)
{
read_lock(&dev_base_lock);
return *pos ? dev_get_idx(*pos - 1) : SEQ_START_TOKEN;
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;
......
......@@ -721,7 +721,7 @@ static int dn_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
struct sock *sk = sock->sk;
struct dn_scp *scp = DN_SK(sk);
struct sockaddr_dn *saddr = (struct sockaddr_dn *)uaddr;
struct net_device *dev;
struct net_device *dev, *ldev;
int rv;
if (addr_len != sizeof(struct sockaddr_dn))
......@@ -746,14 +746,17 @@ static int dn_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
if (!(saddr->sdn_flags & SDF_WILD)) {
if (dn_ntohs(saddr->sdn_nodeaddrl)) {
read_lock(&dev_base_lock);
for(dev = dev_base; dev; dev = dev->next) {
ldev = NULL;
for_each_netdev(dev) {
if (!dev->dn_ptr)
continue;
if (dn_dev_islocal(dev, dn_saddr2dn(saddr)))
if (dn_dev_islocal(dev, dn_saddr2dn(saddr))) {
ldev = dev;
break;
}
}
read_unlock(&dev_base_lock);
if (dev == NULL)
if (ldev == NULL)
return -EADDRNOTAVAIL;
}
}
......
......@@ -799,9 +799,10 @@ static int dn_nl_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
skip_ndevs = cb->args[0];
skip_naddr = cb->args[1];
for (dev = dev_base, idx = 0; dev; dev = dev->next, idx++) {
idx = 0;
for_each_netdev(dev) {
if (idx < skip_ndevs)
continue;
goto cont;
else if (idx > skip_ndevs) {
/* Only skip over addresses for first dev dumped
* in this iteration (idx == skip_ndevs) */
......@@ -809,18 +810,20 @@ static int dn_nl_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
}
if ((dn_db = dev->dn_ptr) == NULL)
continue;
goto cont;
for (ifa = dn_db->ifa_list, dn_idx = 0; ifa;
ifa = ifa->ifa_next, dn_idx++) {
if (dn_idx < skip_naddr)
continue;
goto cont;
if (dn_nl_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq, RTM_NEWADDR,
NLM_F_MULTI) < 0)
goto done;
}
cont:
idx++;
}
done:
cb->args[0] = idx;
......@@ -1296,7 +1299,7 @@ void dn_dev_devices_off(void)
struct net_device *dev;
rtnl_lock();
for(dev = dev_base; dev; dev = dev->next)
for_each_netdev(dev)
dn_dev_down(dev);
rtnl_unlock();
......@@ -1307,7 +1310,7 @@ void dn_dev_devices_on(void)
struct net_device *dev;
rtnl_lock();
for(dev = dev_base; dev; dev = dev->next) {
for_each_netdev(dev) {
if (dev->flags & IFF_UP)
dn_dev_up(dev);
}
......@@ -1325,62 +1328,56 @@ int unregister_dnaddr_notifier(struct notifier_block *nb)
}
#ifdef CONFIG_PROC_FS
static inline struct net_device *dn_dev_get_next(struct seq_file *seq, struct net_device *dev)
static inline int is_dn_dev(struct net_device *dev)
{
do {
dev = dev->next;
} while(dev && !dev->dn_ptr);
return dev;
return dev->dn_ptr != NULL;
}
static struct net_device *dn_dev_get_idx(struct seq_file *seq, loff_t pos)
static void *dn_dev_seq_start(struct seq_file *seq, loff_t *pos)
{
int i;
struct net_device *dev;
dev = dev_base;
if (dev && !dev->dn_ptr)
dev = dn_dev_get_next(seq, dev);
if (pos) {
while(dev && (dev = dn_dev_get_next(seq, dev)))
--pos;
}
return dev;
}
read_lock(&dev_base_lock);
static void *dn_dev_seq_start(struct seq_file *seq, loff_t *pos)
{
if (*pos) {
struct net_device *dev;
read_lock(&dev_base_lock);
dev = dn_dev_get_idx(seq, *pos - 1);
if (dev == NULL)
read_unlock(&dev_base_lock);
return dev;
if (*pos == 0)
return SEQ_START_TOKEN;
i = 1;
for_each_netdev(dev) {
if (!is_dn_dev(dev))
continue;
if (i++ == *pos)
return dev;
}
return SEQ_START_TOKEN;
return NULL;
}
static void *dn_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
struct net_device *dev = v;
loff_t one = 1;
struct net_device *dev;
if (v == SEQ_START_TOKEN) {
dev = dn_dev_seq_start(seq, &one);
} else {
dev = dn_dev_get_next(seq, dev);
if (dev == NULL)
read_unlock(&dev_base_lock);
}
++*pos;
return dev;
dev = (struct net_device *)v;
if (v == SEQ_START_TOKEN)
dev = net_device_entry(&dev_base_head);
for_each_netdev_continue(dev) {
if (!is_dn_dev(dev))
continue;
return dev;
}
return NULL;
}
static void dn_dev_seq_stop(struct seq_file *seq, void *v)
{
if (v && v != SEQ_START_TOKEN)
read_unlock(&dev_base_lock);
read_unlock(&dev_base_lock);
}
static char *dn_type2asc(char type)
......
......@@ -602,7 +602,7 @@ static void dn_fib_del_ifaddr(struct dn_ifaddr *ifa)
/* Scan device list */
read_lock(&dev_base_lock);
for(dev = dev_base; dev; dev = dev->next) {
for_each_netdev(dev) {
dn_db = dev->dn_ptr;
if (dn_db == NULL)
continue;
......
......@@ -886,7 +886,7 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *old
.iif = loopback_dev.ifindex,
.oif = oldflp->oif };
struct dn_route *rt = NULL;
struct net_device *dev_out = NULL;
struct net_device *dev_out = NULL, *dev;
struct neighbour *neigh = NULL;
unsigned hash;
unsigned flags = 0;
......@@ -925,15 +925,17 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *old
goto out;
}
read_lock(&dev_base_lock);
for(dev_out = dev_base; dev_out; dev_out = dev_out->next) {
if (!dev_out->dn_ptr)
for_each_netdev(dev) {
if (!dev->dn_ptr)
continue;
if (!dn_dev_islocal(dev_out, oldflp->fld_src))
if (!dn_dev_islocal(dev, oldflp->fld_src))
continue;
if ((dev_out->flags & IFF_LOOPBACK) &&
if ((dev->flags & IFF_LOOPBACK) &&
oldflp->fld_dst &&
!dn_dev_islocal(dev_out, oldflp->fld_dst))
!dn_dev_islocal(dev, oldflp->fld_dst))
continue;
dev_out = dev;
break;
}
read_unlock(&dev_base_lock);
......
......@@ -910,7 +910,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;
......@@ -989,7 +989,7 @@ __be32 inet_confirm_addr(const struct net_device *dev, __be32 dst, __be32 local,
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)
......@@ -1182,23 +1182,26 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
int s_ip_idx, s_idx = cb->args[0];
s_ip_idx = ip_idx = cb->args[1];
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 (idx > s_idx)
s_ip_idx = 0;