aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/dev.c
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2007-07-30 20:03:38 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-07-31 05:28:15 -0400
commitfcc5a03ac42564e9e255c1134dda47442289e466 (patch)
tree8be87d6dc1a58b8ccd27de930c17bc1c9c26bac9 /net/core/dev.c
parentaeed9e82cd258b9699eaa6568efefba9cc6d5f01 (diff)
[NET]: Allow netdev REGISTER/CHANGENAME events to fail
This patch adds code to allow errors to be passed up from event handlers of NETDEV_REGISTER and NETDEV_CHANGENAME. It also adds the notifier_from_errno/notifier_to_errnor helpers to pass the errno value up to the notifier caller. If an error is detected when a device is registered, it causes that operation to fail. A NETDEV_UNREGISTER will be sent to all event handlers. Similarly if NETDEV_CHANGENAME fails the original name is restored and a new NETDEV_CHANGENAME event is sent. As such all event handlers must be idempotent with respect to these events. When an event handler is registered NETDEV_REGISTER events are sent for all devices currently registered. Should any of them fail, we will send NETDEV_GOING_DOWN/NETDEV_DOWN/NETDEV_UNREGISTER events to that handler for the devices which have already been registered with it. The handler registration itself will fail. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core/dev.c')
-rw-r--r--net/core/dev.c62
1 files changed, 52 insertions, 10 deletions
diff --git a/net/core/dev.c b/net/core/dev.c
index 346cbf66534e..6cc8a70350ac 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -817,7 +817,9 @@ int dev_alloc_name(struct net_device *dev, const char *name)
817 */ 817 */
818int dev_change_name(struct net_device *dev, char *newname) 818int dev_change_name(struct net_device *dev, char *newname)
819{ 819{
820 char oldname[IFNAMSIZ];
820 int err = 0; 821 int err = 0;
822 int ret;
821 823
822 ASSERT_RTNL(); 824 ASSERT_RTNL();
823 825
@@ -827,6 +829,8 @@ int dev_change_name(struct net_device *dev, char *newname)
827 if (!dev_valid_name(newname)) 829 if (!dev_valid_name(newname))
828 return -EINVAL; 830 return -EINVAL;
829 831
832 memcpy(oldname, dev->name, IFNAMSIZ);
833
830 if (strchr(newname, '%')) { 834 if (strchr(newname, '%')) {
831 err = dev_alloc_name(dev, newname); 835 err = dev_alloc_name(dev, newname);
832 if (err < 0) 836 if (err < 0)
@@ -838,6 +842,7 @@ int dev_change_name(struct net_device *dev, char *newname)
838 else 842 else
839 strlcpy(dev->name, newname, IFNAMSIZ); 843 strlcpy(dev->name, newname, IFNAMSIZ);
840 844
845rollback:
841 device_rename(&dev->dev, dev->name); 846 device_rename(&dev->dev, dev->name);
842 847
843 write_lock_bh(&dev_base_lock); 848 write_lock_bh(&dev_base_lock);
@@ -845,7 +850,20 @@ int dev_change_name(struct net_device *dev, char *newname)
845 hlist_add_head(&dev->name_hlist, dev_name_hash(dev->name)); 850 hlist_add_head(&dev->name_hlist, dev_name_hash(dev->name));
846 write_unlock_bh(&dev_base_lock); 851 write_unlock_bh(&dev_base_lock);
847 852
848 raw_notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev); 853 ret = raw_notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev);
854 ret = notifier_to_errno(ret);
855
856 if (ret) {
857 if (err) {
858 printk(KERN_ERR
859 "%s: name change rollback failed: %d.\n",
860 dev->name, ret);
861 } else {
862 err = ret;
863 memcpy(dev->name, oldname, IFNAMSIZ);
864 goto rollback;
865 }
866 }
849 867
850 return err; 868 return err;
851} 869}
@@ -1058,20 +1076,43 @@ int dev_close(struct net_device *dev)
1058int register_netdevice_notifier(struct notifier_block *nb) 1076int register_netdevice_notifier(struct notifier_block *nb)
1059{ 1077{
1060 struct net_device *dev; 1078 struct net_device *dev;
1079 struct net_device *last;
1061 int err; 1080 int err;
1062 1081
1063 rtnl_lock(); 1082 rtnl_lock();
1064 err = raw_notifier_chain_register(&netdev_chain, nb); 1083 err = raw_notifier_chain_register(&netdev_chain, nb);
1065 if (!err) { 1084 if (err)
1066 for_each_netdev(dev) { 1085 goto unlock;
1067 nb->notifier_call(nb, NETDEV_REGISTER, dev);
1068 1086
1069 if (dev->flags & IFF_UP) 1087 for_each_netdev(dev) {
1070 nb->notifier_call(nb, NETDEV_UP, dev); 1088 err = nb->notifier_call(nb, NETDEV_REGISTER, dev);
1071 } 1089 err = notifier_to_errno(err);
1090 if (err)
1091 goto rollback;
1092
1093 if (!(dev->flags & IFF_UP))
1094 continue;
1095
1096 nb->notifier_call(nb, NETDEV_UP, dev);
1072 } 1097 }
1098
1099unlock:
1073 rtnl_unlock(); 1100 rtnl_unlock();
1074 return err; 1101 return err;
1102
1103rollback:
1104 last = dev;
1105 for_each_netdev(dev) {
1106 if (dev == last)
1107 break;
1108
1109 if (dev->flags & IFF_UP) {
1110 nb->notifier_call(nb, NETDEV_GOING_DOWN, dev);
1111 nb->notifier_call(nb, NETDEV_DOWN, dev);
1112 }
1113 nb->notifier_call(nb, NETDEV_UNREGISTER, dev);
1114 }
1115 goto unlock;
1075} 1116}
1076 1117
1077/** 1118/**
@@ -3434,9 +3475,10 @@ int register_netdevice(struct net_device *dev)
3434 write_unlock_bh(&dev_base_lock); 3475 write_unlock_bh(&dev_base_lock);
3435 3476
3436 /* Notify protocols, that a new device appeared. */ 3477 /* Notify protocols, that a new device appeared. */
3437 raw_notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev); 3478 ret = raw_notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev);
3438 3479 ret = notifier_to_errno(ret);
3439 ret = 0; 3480 if (ret)
3481 unregister_netdevice(dev);
3440 3482
3441out: 3483out:
3442 return ret; 3484 return ret;