diff options
Diffstat (limited to 'net/core/dev.c')
-rw-r--r-- | net/core/dev.c | 21 |
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; | |||
203 | DEFINE_RWLOCK(dev_base_lock); | 203 | DEFINE_RWLOCK(dev_base_lock); |
204 | EXPORT_SYMBOL(dev_base_lock); | 204 | EXPORT_SYMBOL(dev_base_lock); |
205 | 205 | ||
206 | DEFINE_SEQLOCK(devnet_rename_seq); | ||
207 | |||
206 | static inline void dev_base_seq_inc(struct net *net) | 208 | static 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 | ||
1103 | rollback: | 1111 | rollback: |
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 | ||
4172 | retry: | ||
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; |