aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/core/dev.c')
-rw-r--r--net/core/dev.c21
1 files changed, 19 insertions, 2 deletions
diff --git a/net/core/dev.c b/net/core/dev.c
index 7304ea8a1f13..2a5f55866429 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -203,6 +203,8 @@ static struct list_head offload_base __read_mostly;
203DEFINE_RWLOCK(dev_base_lock); 203DEFINE_RWLOCK(dev_base_lock);
204EXPORT_SYMBOL(dev_base_lock); 204EXPORT_SYMBOL(dev_base_lock);
205 205
206DEFINE_SEQLOCK(devnet_rename_seq);
207
206static inline void dev_base_seq_inc(struct net *net) 208static inline void dev_base_seq_inc(struct net *net)
207{ 209{
208 while (++net->dev_base_seq == 0); 210 while (++net->dev_base_seq == 0);
@@ -1091,22 +1093,31 @@ int dev_change_name(struct net_device *dev, const char *newname)
1091 if (dev->flags & IFF_UP) 1093 if (dev->flags & IFF_UP)
1092 return -EBUSY; 1094 return -EBUSY;
1093 1095
1094 if (strncmp(newname, dev->name, IFNAMSIZ) == 0) 1096 write_seqlock(&devnet_rename_seq);
1097
1098 if (strncmp(newname, dev->name, IFNAMSIZ) == 0) {
1099 write_sequnlock(&devnet_rename_seq);
1095 return 0; 1100 return 0;
1101 }
1096 1102
1097 memcpy(oldname, dev->name, IFNAMSIZ); 1103 memcpy(oldname, dev->name, IFNAMSIZ);
1098 1104
1099 err = dev_get_valid_name(net, dev, newname); 1105 err = dev_get_valid_name(net, dev, newname);
1100 if (err < 0) 1106 if (err < 0) {
1107 write_sequnlock(&devnet_rename_seq);
1101 return err; 1108 return err;
1109 }
1102 1110
1103rollback: 1111rollback:
1104 ret = device_rename(&dev->dev, dev->name); 1112 ret = device_rename(&dev->dev, dev->name);
1105 if (ret) { 1113 if (ret) {
1106 memcpy(dev->name, oldname, IFNAMSIZ); 1114 memcpy(dev->name, oldname, IFNAMSIZ);
1115 write_sequnlock(&devnet_rename_seq);
1107 return ret; 1116 return ret;
1108 } 1117 }
1109 1118
1119 write_sequnlock(&devnet_rename_seq);
1120
1110 write_lock_bh(&dev_base_lock); 1121 write_lock_bh(&dev_base_lock);
1111 hlist_del_rcu(&dev->name_hlist); 1122 hlist_del_rcu(&dev->name_hlist);
1112 write_unlock_bh(&dev_base_lock); 1123 write_unlock_bh(&dev_base_lock);
@@ -1124,6 +1135,7 @@ rollback:
1124 /* err >= 0 after dev_alloc_name() or stores the first errno */ 1135 /* err >= 0 after dev_alloc_name() or stores the first errno */
1125 if (err >= 0) { 1136 if (err >= 0) {
1126 err = ret; 1137 err = ret;
1138 write_seqlock(&devnet_rename_seq);
1127 memcpy(dev->name, oldname, IFNAMSIZ); 1139 memcpy(dev->name, oldname, IFNAMSIZ);
1128 goto rollback; 1140 goto rollback;
1129 } else { 1141 } else {
@@ -4148,6 +4160,7 @@ static int dev_ifname(struct net *net, struct ifreq __user *arg)
4148{ 4160{
4149 struct net_device *dev; 4161 struct net_device *dev;
4150 struct ifreq ifr; 4162 struct ifreq ifr;
4163 unsigned seq;
4151 4164
4152 /* 4165 /*
4153 * Fetch the caller's info block. 4166 * Fetch the caller's info block.
@@ -4156,6 +4169,8 @@ static int dev_ifname(struct net *net, struct ifreq __user *arg)
4156 if (copy_from_user(&ifr, arg, sizeof(struct ifreq))) 4169 if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
4157 return -EFAULT; 4170 return -EFAULT;
4158 4171
4172retry:
4173 seq = read_seqbegin(&devnet_rename_seq);
4159 rcu_read_lock(); 4174 rcu_read_lock();
4160 dev = dev_get_by_index_rcu(net, ifr.ifr_ifindex); 4175 dev = dev_get_by_index_rcu(net, ifr.ifr_ifindex);
4161 if (!dev) { 4176 if (!dev) {
@@ -4165,6 +4180,8 @@ static int dev_ifname(struct net *net, struct ifreq __user *arg)
4165 4180
4166 strcpy(ifr.ifr_name, dev->name); 4181 strcpy(ifr.ifr_name, dev->name);
4167 rcu_read_unlock(); 4182 rcu_read_unlock();
4183 if (read_seqretry(&devnet_rename_seq, seq))
4184 goto retry;
4168 4185
4169 if (copy_to_user(arg, &ifr, sizeof(struct ifreq))) 4186 if (copy_to_user(arg, &ifr, sizeof(struct ifreq)))
4170 return -EFAULT; 4187 return -EFAULT;