Commit 30e6c9fa authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller

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 c91f6df2 (sockopt: Change getsockopt() of
SO_BINDTODEVICE to return an interface name)
Reported-by: default avatarDave Jones <davej@redhat.com>
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Cc: Brian Haley <brian.haley@hp.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f7e75ba1
...@@ -1576,7 +1576,7 @@ extern int call_netdevice_notifiers(unsigned long val, struct net_device *dev); ...@@ -1576,7 +1576,7 @@ extern int call_netdevice_notifiers(unsigned long val, struct net_device *dev);
extern rwlock_t dev_base_lock; /* Device list lock */ extern rwlock_t dev_base_lock; /* Device list lock */
extern seqlock_t devnet_rename_seq; /* Device rename lock */ extern seqcount_t devnet_rename_seq; /* Device rename seq */
#define for_each_netdev(net, d) \ #define for_each_netdev(net, d) \
......
...@@ -203,7 +203,7 @@ static struct list_head offload_base __read_mostly; ...@@ -203,7 +203,7 @@ static struct list_head offload_base __read_mostly;
DEFINE_RWLOCK(dev_base_lock); DEFINE_RWLOCK(dev_base_lock);
EXPORT_SYMBOL(dev_base_lock); EXPORT_SYMBOL(dev_base_lock);
DEFINE_SEQLOCK(devnet_rename_seq); seqcount_t devnet_rename_seq;
static inline void dev_base_seq_inc(struct net *net) static inline void dev_base_seq_inc(struct net *net)
{ {
...@@ -1093,10 +1093,10 @@ int dev_change_name(struct net_device *dev, const char *newname) ...@@ -1093,10 +1093,10 @@ int dev_change_name(struct net_device *dev, const char *newname)
if (dev->flags & IFF_UP) if (dev->flags & IFF_UP)
return -EBUSY; return -EBUSY;
write_seqlock(&devnet_rename_seq); write_seqcount_begin(&devnet_rename_seq);
if (strncmp(newname, dev->name, IFNAMSIZ) == 0) { if (strncmp(newname, dev->name, IFNAMSIZ) == 0) {
write_sequnlock(&devnet_rename_seq); write_seqcount_end(&devnet_rename_seq);
return 0; return 0;
} }
...@@ -1104,7 +1104,7 @@ int dev_change_name(struct net_device *dev, const char *newname) ...@@ -1104,7 +1104,7 @@ int dev_change_name(struct net_device *dev, const char *newname)
err = dev_get_valid_name(net, dev, newname); err = dev_get_valid_name(net, dev, newname);
if (err < 0) { if (err < 0) {
write_sequnlock(&devnet_rename_seq); write_seqcount_end(&devnet_rename_seq);
return err; return err;
} }
...@@ -1112,11 +1112,11 @@ int dev_change_name(struct net_device *dev, const char *newname) ...@@ -1112,11 +1112,11 @@ int dev_change_name(struct net_device *dev, const char *newname)
ret = device_rename(&dev->dev, dev->name); ret = device_rename(&dev->dev, dev->name);
if (ret) { if (ret) {
memcpy(dev->name, oldname, IFNAMSIZ); memcpy(dev->name, oldname, IFNAMSIZ);
write_sequnlock(&devnet_rename_seq); write_seqcount_end(&devnet_rename_seq);
return ret; return ret;
} }
write_sequnlock(&devnet_rename_seq); write_seqcount_end(&devnet_rename_seq);
write_lock_bh(&dev_base_lock); write_lock_bh(&dev_base_lock);
hlist_del_rcu(&dev->name_hlist); hlist_del_rcu(&dev->name_hlist);
...@@ -1135,7 +1135,7 @@ int dev_change_name(struct net_device *dev, const char *newname) ...@@ -1135,7 +1135,7 @@ int dev_change_name(struct net_device *dev, const char *newname)
/* err >= 0 after dev_alloc_name() or stores the first errno */ /* err >= 0 after dev_alloc_name() or stores the first errno */
if (err >= 0) { if (err >= 0) {
err = ret; err = ret;
write_seqlock(&devnet_rename_seq); write_seqcount_begin(&devnet_rename_seq);
memcpy(dev->name, oldname, IFNAMSIZ); memcpy(dev->name, oldname, IFNAMSIZ);
goto rollback; goto rollback;
} else { } else {
...@@ -4180,7 +4180,7 @@ static int dev_ifname(struct net *net, struct ifreq __user *arg) ...@@ -4180,7 +4180,7 @@ static int dev_ifname(struct net *net, struct ifreq __user *arg)
return -EFAULT; return -EFAULT;
retry: retry:
seq = read_seqbegin(&devnet_rename_seq); seq = read_seqcount_begin(&devnet_rename_seq);
rcu_read_lock(); rcu_read_lock();
dev = dev_get_by_index_rcu(net, ifr.ifr_ifindex); dev = dev_get_by_index_rcu(net, ifr.ifr_ifindex);
if (!dev) { if (!dev) {
...@@ -4190,7 +4190,7 @@ static int dev_ifname(struct net *net, struct ifreq __user *arg) ...@@ -4190,7 +4190,7 @@ static int dev_ifname(struct net *net, struct ifreq __user *arg)
strcpy(ifr.ifr_name, dev->name); strcpy(ifr.ifr_name, dev->name);
rcu_read_unlock(); rcu_read_unlock();
if (read_seqretry(&devnet_rename_seq, seq)) if (read_seqcount_retry(&devnet_rename_seq, seq))
goto retry; goto retry;
if (copy_to_user(arg, &ifr, sizeof(struct ifreq))) if (copy_to_user(arg, &ifr, sizeof(struct ifreq)))
......
...@@ -583,7 +583,7 @@ static int sock_getbindtodevice(struct sock *sk, char __user *optval, ...@@ -583,7 +583,7 @@ static int sock_getbindtodevice(struct sock *sk, char __user *optval,
goto out; goto out;
retry: retry:
seq = read_seqbegin(&devnet_rename_seq); seq = read_seqcount_begin(&devnet_rename_seq);
rcu_read_lock(); rcu_read_lock();
dev = dev_get_by_index_rcu(net, sk->sk_bound_dev_if); dev = dev_get_by_index_rcu(net, sk->sk_bound_dev_if);
ret = -ENODEV; ret = -ENODEV;
...@@ -594,7 +594,7 @@ static int sock_getbindtodevice(struct sock *sk, char __user *optval, ...@@ -594,7 +594,7 @@ static int sock_getbindtodevice(struct sock *sk, char __user *optval,
strcpy(devname, dev->name); strcpy(devname, dev->name);
rcu_read_unlock(); rcu_read_unlock();
if (read_seqretry(&devnet_rename_seq, seq)) if (read_seqcount_retry(&devnet_rename_seq, seq))
goto retry; goto retry;
len = strlen(devname) + 1; len = strlen(devname) + 1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment