rtnetlink: handle rtnl_link netlink notifications manually
authorPatrick McHardy <kaber@trash.net>
Fri, 26 Feb 2010 06:34:51 +0000 (06:34 +0000)
committerDavid S. Miller <davem@davemloft.net>
Sat, 27 Feb 2010 10:43:39 +0000 (02:43 -0800)
In order to support specifying device flags during device creation,
we must be able to roll back device registration in case setting the
flags fails without sending any notifications related to the device
to userspace.

This patch changes rollback_registered_many() and register_netdevice()
to manually send netlink notifications for devices not handled by
rtnl_link and allows to defer notifications for devices handled by
rtnl_link until setup is complete.

Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/linux/netdevice.h
net/core/dev.c
net/core/rtnetlink.c

index 7a2aea56f195327e9b89a21036fda4a611219f81..1bfda90c2625cf8df94d4de5c5eef8fed975dd43 100644 (file)
@@ -924,7 +924,12 @@ struct net_device {
               NETREG_UNREGISTERED,     /* completed unregister todo */
               NETREG_RELEASED,         /* called free_netdev */
               NETREG_DUMMY,            /* dummy device for NAPI poll */
-       } reg_state;
+       } reg_state:16;
+
+       enum {
+               RTNL_LINK_INITIALIZED,
+               RTNL_LINK_INITIALIZING,
+       } rtnl_link_state:16;
 
        /* Called from unregister, can be used to call free_netdev */
        void (*destructor)(struct net_device *dev);
index eb7f1a4fefc6b97058bd4548a0d1731404002180..75332b089529404fa38a6755cc5e93774998516d 100644 (file)
@@ -4865,6 +4865,10 @@ static void rollback_registered_many(struct list_head *head)
                */
                call_netdevice_notifiers(NETDEV_UNREGISTER, dev);
 
+               if (!dev->rtnl_link_ops ||
+                   dev->rtnl_link_state == RTNL_LINK_INITIALIZED)
+                       rtmsg_ifinfo(RTM_DELLINK, dev, ~0U);
+
                /*
                 *      Flush the unicast and multicast chains
                 */
@@ -5091,7 +5095,9 @@ int register_netdevice(struct net_device *dev)
         *      Prevent userspace races by waiting until the network
         *      device is fully setup before sending notifications.
         */
-       rtmsg_ifinfo(RTM_NEWLINK, dev, ~0U);
+       if (!dev->rtnl_link_ops ||
+           dev->rtnl_link_state == RTNL_LINK_INITIALIZED)
+               rtmsg_ifinfo(RTM_NEWLINK, dev, ~0U);
 
 out:
        return ret;
index b7c7dfd86507afd23402ba112900d9dfd7a86952..020e43bfef5f6a05231bf75dacd117391c2247fe 100644 (file)
@@ -1425,9 +1425,6 @@ static int rtnetlink_event(struct notifier_block *this, unsigned long event, voi
        struct net_device *dev = ptr;
 
        switch (event) {
-       case NETDEV_UNREGISTER:
-               rtmsg_ifinfo(RTM_DELLINK, dev, ~0U);
-               break;
        case NETDEV_UP:
        case NETDEV_DOWN:
                rtmsg_ifinfo(RTM_NEWLINK, dev, IFF_UP|IFF_RUNNING);
@@ -1437,6 +1434,7 @@ static int rtnetlink_event(struct notifier_block *this, unsigned long event, voi
        case NETDEV_REGISTER:
        case NETDEV_CHANGE:
        case NETDEV_GOING_DOWN:
+       case NETDEV_UNREGISTER:
        case NETDEV_UNREGISTER_BATCH:
                break;
        default: