From: Patrick McHardy Date: Fri, 26 Feb 2010 06:34:51 +0000 (+0000) Subject: rtnetlink: handle rtnl_link netlink notifications manually X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=a2835763e130c343ace5320c20d33c281e7097b7;p=linux.git rtnetlink: handle rtnl_link netlink notifications manually 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 Signed-off-by: David S. Miller --- diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 7a2aea56f1953..1bfda90c2625c 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -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); diff --git a/net/core/dev.c b/net/core/dev.c index eb7f1a4fefc6b..75332b0895294 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -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; diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index b7c7dfd86507a..020e43bfef5f6 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -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: