rtnl: provide link dump consistency info
authorThomas Graf <tgraf@infradead.org>
Tue, 21 Jun 2011 03:11:20 +0000 (03:11 +0000)
committerDavid S. Miller <davem@davemloft.net>
Fri, 1 Jul 2011 22:39:53 +0000 (15:39 -0700)
This patch adds a change sequence counter to each net namespace
which is bumped whenever a netdevice is added or removed from
the list. If such a change occurred while a link dump took place,
the dump will have the NLM_F_DUMP_INTR flag set in the first
message which has been interrupted and in all subsequent messages
of the same dump.

Note that links may still be modified or renamed while a dump is
taking place but we can guarantee for userspace to receive a
complete list of links and not miss any.

Testing:
I have added 500 VLAN netdevices to make sure the dump is split
over multiple messages. Then while continuously dumping links in
one process I also continuously deleted and re-added a dummy
netdevice in another process. Multiple dumps per seconds have
had the NLM_F_DUMP_INTR flag set.

I guess we can wait for Johannes patch to hit net-next via the
wireless tree.  I just wanted to give this some testing right away.

Signed-off-by: Thomas Graf <tgraf@infradead.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/net_namespace.h
net/core/dev.c
net/core/net_namespace.c
net/core/rtnetlink.c

index aef430d779bdd07542f5be64967c8f5c8fb9d809..1ab1aec209ac25efbe37394a633102925f121dfc 100644 (file)
@@ -65,6 +65,7 @@ struct net {
        struct list_head        dev_base_head;
        struct hlist_head       *dev_name_head;
        struct hlist_head       *dev_index_head;
+       unsigned int            dev_base_seq;   /* protected by rtnl_mutex */
 
        /* core fib_rules */
        struct list_head        rules_ops;
index 6b6ef14b42f27fb866035ccbdc5246c01c10b906..4577e6711ec33233f67d4f8ce49350911b115477 100644 (file)
@@ -199,6 +199,11 @@ static struct list_head ptype_all __read_mostly;   /* Taps */
 DEFINE_RWLOCK(dev_base_lock);
 EXPORT_SYMBOL(dev_base_lock);
 
+static inline void dev_base_seq_inc(struct net *net)
+{
+       while (++net->dev_base_seq == 0);
+}
+
 static inline struct hlist_head *dev_name_hash(struct net *net, const char *name)
 {
        unsigned hash = full_name_hash(name, strnlen(name, IFNAMSIZ));
@@ -237,6 +242,9 @@ static int list_netdevice(struct net_device *dev)
        hlist_add_head_rcu(&dev->index_hlist,
                           dev_index_hash(net, dev->ifindex));
        write_unlock_bh(&dev_base_lock);
+
+       dev_base_seq_inc(net);
+
        return 0;
 }
 
@@ -253,6 +261,8 @@ static void unlist_netdevice(struct net_device *dev)
        hlist_del_rcu(&dev->name_hlist);
        hlist_del_rcu(&dev->index_hlist);
        write_unlock_bh(&dev_base_lock);
+
+       dev_base_seq_inc(dev_net(dev));
 }
 
 /*
index ea489db1bc2361c20001576a5e909aa22cb689d2..5bbdbf0d3664ce592f680d9670f26f7f96ce92cc 100644 (file)
@@ -129,6 +129,7 @@ static __net_init int setup_net(struct net *net)
 
        atomic_set(&net->count, 1);
        atomic_set(&net->passive, 1);
+       net->dev_base_seq = 1;
 
 #ifdef NETNS_REFCNT_DEBUG
        atomic_set(&net->use_count, 0);
index a798fc6f2aa1180c35158cea6ef0684f0cafbe35..99d9e953fe3953adf96cc44cf85be380b6b3ff55 100644 (file)
@@ -1032,6 +1032,8 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
        s_idx = cb->args[1];
 
        rcu_read_lock();
+       cb->seq = net->dev_base_seq;
+
        for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
                idx = 0;
                head = &net->dev_index_head[h];
@@ -1043,6 +1045,8 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
                                             cb->nlh->nlmsg_seq, 0,
                                             NLM_F_MULTI) <= 0)
                                goto out;
+
+                       nl_dump_check_consistent(cb, nlmsg_hdr(skb));
 cont:
                        idx++;
                }