aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/notifier.h13
-rw-r--r--net/core/dev.c62
2 files changed, 65 insertions, 10 deletions
diff --git a/include/linux/notifier.h b/include/linux/notifier.h
index be3f2bb6fcf3..fad7ff17e468 100644
--- a/include/linux/notifier.h
+++ b/include/linux/notifier.h
@@ -157,6 +157,19 @@ extern int __srcu_notifier_call_chain(struct srcu_notifier_head *nh,
157 */ 157 */
158#define NOTIFY_STOP (NOTIFY_OK|NOTIFY_STOP_MASK) 158#define NOTIFY_STOP (NOTIFY_OK|NOTIFY_STOP_MASK)
159 159
160/* Encapsulate (negative) errno value (in particular, NOTIFY_BAD <=> EPERM). */
161static inline int notifier_from_errno(int err)
162{
163 return NOTIFY_STOP_MASK | (NOTIFY_OK - err);
164}
165
166/* Restore (negative) errno value from notify return value. */
167static inline int notifier_to_errno(int ret)
168{
169 ret &= ~NOTIFY_STOP_MASK;
170 return ret > NOTIFY_OK ? NOTIFY_OK - ret : 0;
171}
172
160/* 173/*
161 * Declared notifiers so far. I can imagine quite a few more chains 174 * Declared notifiers so far. I can imagine quite a few more chains
162 * over time (eg laptop power reset chains, reboot chain (to clean 175 * over time (eg laptop power reset chains, reboot chain (to clean
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;