diff options
author | Eric Dumazet <edumazet@google.com> | 2012-12-20 12:25:08 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-12-21 16:14:01 -0500 |
commit | 30e6c9fa93cf3dbc7cc6df1d748ad25e4264545a (patch) | |
tree | e313291a178010fb892d9725cbecb326bd63fdc0 /net | |
parent | f7e75ba1772bc712af0070655ffd8b09906993b5 (diff) |
net: devnet_rename_seq should be a seqcount
Using a seqlock for devnet_rename_seq is not a good idea,
as device_rename() can sleep.
As we hold RTNL, we dont need a protection for writers,
and only need a seqcount so that readers can catch a change done
by a writer.
Bug added in commit c91f6df2db4972d3 (sockopt: Change getsockopt() of
SO_BINDTODEVICE to return an interface name)
Reported-by: Dave Jones <davej@redhat.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Brian Haley <brian.haley@hp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/core/dev.c | 18 | ||||
-rw-r--r-- | net/core/sock.c | 4 |
2 files changed, 11 insertions, 11 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index d0cbc93fcf32..515473ee52cb 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -203,7 +203,7 @@ 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); | 206 | seqcount_t devnet_rename_seq; |
207 | 207 | ||
208 | static inline void dev_base_seq_inc(struct net *net) | 208 | static inline void dev_base_seq_inc(struct net *net) |
209 | { | 209 | { |
@@ -1093,10 +1093,10 @@ int dev_change_name(struct net_device *dev, const char *newname) | |||
1093 | if (dev->flags & IFF_UP) | 1093 | if (dev->flags & IFF_UP) |
1094 | return -EBUSY; | 1094 | return -EBUSY; |
1095 | 1095 | ||
1096 | write_seqlock(&devnet_rename_seq); | 1096 | write_seqcount_begin(&devnet_rename_seq); |
1097 | 1097 | ||
1098 | if (strncmp(newname, dev->name, IFNAMSIZ) == 0) { | 1098 | if (strncmp(newname, dev->name, IFNAMSIZ) == 0) { |
1099 | write_sequnlock(&devnet_rename_seq); | 1099 | write_seqcount_end(&devnet_rename_seq); |
1100 | return 0; | 1100 | return 0; |
1101 | } | 1101 | } |
1102 | 1102 | ||
@@ -1104,7 +1104,7 @@ int dev_change_name(struct net_device *dev, const char *newname) | |||
1104 | 1104 | ||
1105 | err = dev_get_valid_name(net, dev, newname); | 1105 | err = dev_get_valid_name(net, dev, newname); |
1106 | if (err < 0) { | 1106 | if (err < 0) { |
1107 | write_sequnlock(&devnet_rename_seq); | 1107 | write_seqcount_end(&devnet_rename_seq); |
1108 | return err; | 1108 | return err; |
1109 | } | 1109 | } |
1110 | 1110 | ||
@@ -1112,11 +1112,11 @@ rollback: | |||
1112 | ret = device_rename(&dev->dev, dev->name); | 1112 | ret = device_rename(&dev->dev, dev->name); |
1113 | if (ret) { | 1113 | if (ret) { |
1114 | memcpy(dev->name, oldname, IFNAMSIZ); | 1114 | memcpy(dev->name, oldname, IFNAMSIZ); |
1115 | write_sequnlock(&devnet_rename_seq); | 1115 | write_seqcount_end(&devnet_rename_seq); |
1116 | return ret; | 1116 | return ret; |
1117 | } | 1117 | } |
1118 | 1118 | ||
1119 | write_sequnlock(&devnet_rename_seq); | 1119 | write_seqcount_end(&devnet_rename_seq); |
1120 | 1120 | ||
1121 | write_lock_bh(&dev_base_lock); | 1121 | write_lock_bh(&dev_base_lock); |
1122 | hlist_del_rcu(&dev->name_hlist); | 1122 | hlist_del_rcu(&dev->name_hlist); |
@@ -1135,7 +1135,7 @@ rollback: | |||
1135 | /* err >= 0 after dev_alloc_name() or stores the first errno */ | 1135 | /* err >= 0 after dev_alloc_name() or stores the first errno */ |
1136 | if (err >= 0) { | 1136 | if (err >= 0) { |
1137 | err = ret; | 1137 | err = ret; |
1138 | write_seqlock(&devnet_rename_seq); | 1138 | write_seqcount_begin(&devnet_rename_seq); |
1139 | memcpy(dev->name, oldname, IFNAMSIZ); | 1139 | memcpy(dev->name, oldname, IFNAMSIZ); |
1140 | goto rollback; | 1140 | goto rollback; |
1141 | } else { | 1141 | } else { |
@@ -4180,7 +4180,7 @@ static int dev_ifname(struct net *net, struct ifreq __user *arg) | |||
4180 | return -EFAULT; | 4180 | return -EFAULT; |
4181 | 4181 | ||
4182 | retry: | 4182 | retry: |
4183 | seq = read_seqbegin(&devnet_rename_seq); | 4183 | seq = read_seqcount_begin(&devnet_rename_seq); |
4184 | rcu_read_lock(); | 4184 | rcu_read_lock(); |
4185 | dev = dev_get_by_index_rcu(net, ifr.ifr_ifindex); | 4185 | dev = dev_get_by_index_rcu(net, ifr.ifr_ifindex); |
4186 | if (!dev) { | 4186 | if (!dev) { |
@@ -4190,7 +4190,7 @@ retry: | |||
4190 | 4190 | ||
4191 | strcpy(ifr.ifr_name, dev->name); | 4191 | strcpy(ifr.ifr_name, dev->name); |
4192 | rcu_read_unlock(); | 4192 | rcu_read_unlock(); |
4193 | if (read_seqretry(&devnet_rename_seq, seq)) | 4193 | if (read_seqcount_retry(&devnet_rename_seq, seq)) |
4194 | goto retry; | 4194 | goto retry; |
4195 | 4195 | ||
4196 | if (copy_to_user(arg, &ifr, sizeof(struct ifreq))) | 4196 | if (copy_to_user(arg, &ifr, sizeof(struct ifreq))) |
diff --git a/net/core/sock.c b/net/core/sock.c index a692ef49c9bb..bc131d419683 100644 --- a/net/core/sock.c +++ b/net/core/sock.c | |||
@@ -583,7 +583,7 @@ static int sock_getbindtodevice(struct sock *sk, char __user *optval, | |||
583 | goto out; | 583 | goto out; |
584 | 584 | ||
585 | retry: | 585 | retry: |
586 | seq = read_seqbegin(&devnet_rename_seq); | 586 | seq = read_seqcount_begin(&devnet_rename_seq); |
587 | rcu_read_lock(); | 587 | rcu_read_lock(); |
588 | dev = dev_get_by_index_rcu(net, sk->sk_bound_dev_if); | 588 | dev = dev_get_by_index_rcu(net, sk->sk_bound_dev_if); |
589 | ret = -ENODEV; | 589 | ret = -ENODEV; |
@@ -594,7 +594,7 @@ retry: | |||
594 | 594 | ||
595 | strcpy(devname, dev->name); | 595 | strcpy(devname, dev->name); |
596 | rcu_read_unlock(); | 596 | rcu_read_unlock(); |
597 | if (read_seqretry(&devnet_rename_seq, seq)) | 597 | if (read_seqcount_retry(&devnet_rename_seq, seq)) |
598 | goto retry; | 598 | goto retry; |
599 | 599 | ||
600 | len = strlen(devname) + 1; | 600 | len = strlen(devname) + 1; |