aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2010-02-26 01:34:53 -0500
committerDavid S. Miller <davem@davemloft.net>2010-02-27 05:43:40 -0500
commitbd38081160bb3d036db98472e537b6a7dd4da51a (patch)
tree26af1cae5e2dda3269da6f812586e93954582d54
parenta2835763e130c343ace5320c20d33c281e7097b7 (diff)
dev: support deferring device flag change notifications
Split dev_change_flags() into two functions: __dev_change_flags() to perform the actual changes and __dev_notify_flags() to invoke netdevice notifiers. This will be used by rtnl_link to defer netlink notifications until the device has been fully configured. This changes ordering of some operations, in particular: - netlink notifications are sent after all changes have been performed. As a side effect this surpresses one unnecessary netlink message when the IFF_UP and other flags are changed simultaneously. - The NETDEV_UP/NETDEV_DOWN and NETDEV_CHANGE notifiers are invoked after all changes have been performed. Their relative is unchanged. - net_dmaengine_put() is invoked before the NETDEV_DOWN notifier instead of afterwards. This should not make any difference since both RX and TX are already shut down at this point. Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/netdevice.h2
-rw-r--r--net/core/dev.c163
-rw-r--r--net/core/rtnetlink.c2
3 files changed, 106 insertions, 61 deletions
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 1bfda90c2625..c79a88be7c33 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1587,7 +1587,9 @@ extern int dev_valid_name(const char *name);
1587extern int dev_ioctl(struct net *net, unsigned int cmd, void __user *); 1587extern int dev_ioctl(struct net *net, unsigned int cmd, void __user *);
1588extern int dev_ethtool(struct net *net, struct ifreq *); 1588extern int dev_ethtool(struct net *net, struct ifreq *);
1589extern unsigned dev_get_flags(const struct net_device *); 1589extern unsigned dev_get_flags(const struct net_device *);
1590extern int __dev_change_flags(struct net_device *, unsigned int flags);
1590extern int dev_change_flags(struct net_device *, unsigned); 1591extern int dev_change_flags(struct net_device *, unsigned);
1592extern void __dev_notify_flags(struct net_device *, unsigned int old_flags);
1591extern int dev_change_name(struct net_device *, const char *); 1593extern int dev_change_name(struct net_device *, const char *);
1592extern int dev_set_alias(struct net_device *, const char *, size_t); 1594extern int dev_set_alias(struct net_device *, const char *, size_t);
1593extern int dev_change_net_namespace(struct net_device *, 1595extern int dev_change_net_namespace(struct net_device *,
diff --git a/net/core/dev.c b/net/core/dev.c
index 75332b089529..e5972f7f7e1b 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1113,19 +1113,7 @@ void dev_load(struct net *net, const char *name)
1113} 1113}
1114EXPORT_SYMBOL(dev_load); 1114EXPORT_SYMBOL(dev_load);
1115 1115
1116/** 1116static int __dev_open(struct net_device *dev)
1117 * dev_open - prepare an interface for use.
1118 * @dev: device to open
1119 *
1120 * Takes a device from down to up state. The device's private open
1121 * function is invoked and then the multicast lists are loaded. Finally
1122 * the device is moved into the up state and a %NETDEV_UP message is
1123 * sent to the netdev notifier chain.
1124 *
1125 * Calling this function on an active interface is a nop. On a failure
1126 * a negative errno code is returned.
1127 */
1128int dev_open(struct net_device *dev)
1129{ 1117{
1130 const struct net_device_ops *ops = dev->netdev_ops; 1118 const struct net_device_ops *ops = dev->netdev_ops;
1131 int ret; 1119 int ret;
@@ -1133,13 +1121,6 @@ int dev_open(struct net_device *dev)
1133 ASSERT_RTNL(); 1121 ASSERT_RTNL();
1134 1122
1135 /* 1123 /*
1136 * Is it already up?
1137 */
1138
1139 if (dev->flags & IFF_UP)
1140 return 0;
1141
1142 /*
1143 * Is it even present? 1124 * Is it even present?
1144 */ 1125 */
1145 if (!netif_device_present(dev)) 1126 if (!netif_device_present(dev))
@@ -1187,36 +1168,57 @@ int dev_open(struct net_device *dev)
1187 * Wakeup transmit queue engine 1168 * Wakeup transmit queue engine
1188 */ 1169 */
1189 dev_activate(dev); 1170 dev_activate(dev);
1190
1191 /*
1192 * ... and announce new interface.
1193 */
1194 call_netdevice_notifiers(NETDEV_UP, dev);
1195 } 1171 }
1196 1172
1197 return ret; 1173 return ret;
1198} 1174}
1199EXPORT_SYMBOL(dev_open);
1200 1175
1201/** 1176/**
1202 * dev_close - shutdown an interface. 1177 * dev_open - prepare an interface for use.
1203 * @dev: device to shutdown 1178 * @dev: device to open
1204 * 1179 *
1205 * This function moves an active device into down state. A 1180 * Takes a device from down to up state. The device's private open
1206 * %NETDEV_GOING_DOWN is sent to the netdev notifier chain. The device 1181 * function is invoked and then the multicast lists are loaded. Finally
1207 * is then deactivated and finally a %NETDEV_DOWN is sent to the notifier 1182 * the device is moved into the up state and a %NETDEV_UP message is
1208 * chain. 1183 * sent to the netdev notifier chain.
1184 *
1185 * Calling this function on an active interface is a nop. On a failure
1186 * a negative errno code is returned.
1209 */ 1187 */
1210int dev_close(struct net_device *dev) 1188int dev_open(struct net_device *dev)
1189{
1190 int ret;
1191
1192 /*
1193 * Is it already up?
1194 */
1195 if (dev->flags & IFF_UP)
1196 return 0;
1197
1198 /*
1199 * Open device
1200 */
1201 ret = __dev_open(dev);
1202 if (ret < 0)
1203 return ret;
1204
1205 /*
1206 * ... and announce new interface.
1207 */
1208 rtmsg_ifinfo(RTM_NEWLINK, dev, IFF_UP|IFF_RUNNING);
1209 call_netdevice_notifiers(NETDEV_UP, dev);
1210
1211 return ret;
1212}
1213EXPORT_SYMBOL(dev_open);
1214
1215static int __dev_close(struct net_device *dev)
1211{ 1216{
1212 const struct net_device_ops *ops = dev->netdev_ops; 1217 const struct net_device_ops *ops = dev->netdev_ops;
1213 ASSERT_RTNL();
1214 1218
1219 ASSERT_RTNL();
1215 might_sleep(); 1220 might_sleep();
1216 1221
1217 if (!(dev->flags & IFF_UP))
1218 return 0;
1219
1220 /* 1222 /*
1221 * Tell people we are going down, so that they can 1223 * Tell people we are going down, so that they can
1222 * prepare to death, when device is still operating. 1224 * prepare to death, when device is still operating.
@@ -1252,14 +1254,34 @@ int dev_close(struct net_device *dev)
1252 dev->flags &= ~IFF_UP; 1254 dev->flags &= ~IFF_UP;
1253 1255
1254 /* 1256 /*
1255 * Tell people we are down 1257 * Shutdown NET_DMA
1256 */ 1258 */
1257 call_netdevice_notifiers(NETDEV_DOWN, dev); 1259 net_dmaengine_put();
1260
1261 return 0;
1262}
1263
1264/**
1265 * dev_close - shutdown an interface.
1266 * @dev: device to shutdown
1267 *
1268 * This function moves an active device into down state. A
1269 * %NETDEV_GOING_DOWN is sent to the netdev notifier chain. The device
1270 * is then deactivated and finally a %NETDEV_DOWN is sent to the notifier
1271 * chain.
1272 */
1273int dev_close(struct net_device *dev)
1274{
1275 if (!(dev->flags & IFF_UP))
1276 return 0;
1277
1278 __dev_close(dev);
1258 1279
1259 /* 1280 /*
1260 * Shutdown NET_DMA 1281 * Tell people we are down
1261 */ 1282 */
1262 net_dmaengine_put(); 1283 rtmsg_ifinfo(RTM_NEWLINK, dev, IFF_UP|IFF_RUNNING);
1284 call_netdevice_notifiers(NETDEV_DOWN, dev);
1263 1285
1264 return 0; 1286 return 0;
1265} 1287}
@@ -4299,18 +4321,10 @@ unsigned dev_get_flags(const struct net_device *dev)
4299} 4321}
4300EXPORT_SYMBOL(dev_get_flags); 4322EXPORT_SYMBOL(dev_get_flags);
4301 4323
4302/** 4324int __dev_change_flags(struct net_device *dev, unsigned int flags)
4303 * dev_change_flags - change device settings
4304 * @dev: device
4305 * @flags: device state flags
4306 *
4307 * Change settings on device based state flags. The flags are
4308 * in the userspace exported format.
4309 */
4310int dev_change_flags(struct net_device *dev, unsigned flags)
4311{ 4325{
4312 int ret, changes;
4313 int old_flags = dev->flags; 4326 int old_flags = dev->flags;
4327 int ret;
4314 4328
4315 ASSERT_RTNL(); 4329 ASSERT_RTNL();
4316 4330
@@ -4341,17 +4355,12 @@ int dev_change_flags(struct net_device *dev, unsigned flags)
4341 4355
4342 ret = 0; 4356 ret = 0;
4343 if ((old_flags ^ flags) & IFF_UP) { /* Bit is different ? */ 4357 if ((old_flags ^ flags) & IFF_UP) { /* Bit is different ? */
4344 ret = ((old_flags & IFF_UP) ? dev_close : dev_open)(dev); 4358 ret = ((old_flags & IFF_UP) ? __dev_close : __dev_open)(dev);
4345 4359
4346 if (!ret) 4360 if (!ret)
4347 dev_set_rx_mode(dev); 4361 dev_set_rx_mode(dev);
4348 } 4362 }
4349 4363
4350 if (dev->flags & IFF_UP &&
4351 ((old_flags ^ dev->flags) & ~(IFF_UP | IFF_PROMISC | IFF_ALLMULTI |
4352 IFF_VOLATILE)))
4353 call_netdevice_notifiers(NETDEV_CHANGE, dev);
4354
4355 if ((flags ^ dev->gflags) & IFF_PROMISC) { 4364 if ((flags ^ dev->gflags) & IFF_PROMISC) {
4356 int inc = (flags & IFF_PROMISC) ? 1 : -1; 4365 int inc = (flags & IFF_PROMISC) ? 1 : -1;
4357 4366
@@ -4370,11 +4379,47 @@ int dev_change_flags(struct net_device *dev, unsigned flags)
4370 dev_set_allmulti(dev, inc); 4379 dev_set_allmulti(dev, inc);
4371 } 4380 }
4372 4381
4373 /* Exclude state transition flags, already notified */ 4382 return ret;
4374 changes = (old_flags ^ dev->flags) & ~(IFF_UP | IFF_RUNNING); 4383}
4384
4385void __dev_notify_flags(struct net_device *dev, unsigned int old_flags)
4386{
4387 unsigned int changes = dev->flags ^ old_flags;
4388
4389 if (changes & IFF_UP) {
4390 if (dev->flags & IFF_UP)
4391 call_netdevice_notifiers(NETDEV_UP, dev);
4392 else
4393 call_netdevice_notifiers(NETDEV_DOWN, dev);
4394 }
4395
4396 if (dev->flags & IFF_UP &&
4397 (changes & ~(IFF_UP | IFF_PROMISC | IFF_ALLMULTI | IFF_VOLATILE)))
4398 call_netdevice_notifiers(NETDEV_CHANGE, dev);
4399}
4400
4401/**
4402 * dev_change_flags - change device settings
4403 * @dev: device
4404 * @flags: device state flags
4405 *
4406 * Change settings on device based state flags. The flags are
4407 * in the userspace exported format.
4408 */
4409int dev_change_flags(struct net_device *dev, unsigned flags)
4410{
4411 int ret, changes;
4412 int old_flags = dev->flags;
4413
4414 ret = __dev_change_flags(dev, flags);
4415 if (ret < 0)
4416 return ret;
4417
4418 changes = old_flags ^ dev->flags;
4375 if (changes) 4419 if (changes)
4376 rtmsg_ifinfo(RTM_NEWLINK, dev, changes); 4420 rtmsg_ifinfo(RTM_NEWLINK, dev, changes);
4377 4421
4422 __dev_notify_flags(dev, old_flags);
4378 return ret; 4423 return ret;
4379} 4424}
4380EXPORT_SYMBOL(dev_change_flags); 4425EXPORT_SYMBOL(dev_change_flags);
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 020e43bfef5f..c21ec4236dd0 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -1427,8 +1427,6 @@ static int rtnetlink_event(struct notifier_block *this, unsigned long event, voi
1427 switch (event) { 1427 switch (event) {
1428 case NETDEV_UP: 1428 case NETDEV_UP:
1429 case NETDEV_DOWN: 1429 case NETDEV_DOWN:
1430 rtmsg_ifinfo(RTM_NEWLINK, dev, IFF_UP|IFF_RUNNING);
1431 break;
1432 case NETDEV_PRE_UP: 1430 case NETDEV_PRE_UP:
1433 case NETDEV_POST_INIT: 1431 case NETDEV_POST_INIT:
1434 case NETDEV_REGISTER: 1432 case NETDEV_REGISTER: