forked from mirrors/linux
		
	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 c91f6df2db (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>
			
			
This commit is contained in:
		
							parent
							
								
									f7e75ba177
								
							
						
					
					
						commit
						30e6c9fa93
					
				
					 3 changed files with 12 additions and 12 deletions
				
			
		| 
						 | 
				
			
			@ -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 seqlock_t	devnet_rename_seq;	/* Device rename lock */
 | 
			
		||||
extern seqcount_t	devnet_rename_seq;	/* Device rename seq */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define for_each_netdev(net, d)		\
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -203,7 +203,7 @@ static struct list_head offload_base __read_mostly;
 | 
			
		|||
DEFINE_RWLOCK(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)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -1093,10 +1093,10 @@ int dev_change_name(struct net_device *dev, const char *newname)
 | 
			
		|||
	if (dev->flags & IFF_UP)
 | 
			
		||||
		return -EBUSY;
 | 
			
		||||
 | 
			
		||||
	write_seqlock(&devnet_rename_seq);
 | 
			
		||||
	write_seqcount_begin(&devnet_rename_seq);
 | 
			
		||||
 | 
			
		||||
	if (strncmp(newname, dev->name, IFNAMSIZ) == 0) {
 | 
			
		||||
		write_sequnlock(&devnet_rename_seq);
 | 
			
		||||
		write_seqcount_end(&devnet_rename_seq);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1104,7 +1104,7 @@ int dev_change_name(struct net_device *dev, const char *newname)
 | 
			
		|||
 | 
			
		||||
	err = dev_get_valid_name(net, dev, newname);
 | 
			
		||||
	if (err < 0) {
 | 
			
		||||
		write_sequnlock(&devnet_rename_seq);
 | 
			
		||||
		write_seqcount_end(&devnet_rename_seq);
 | 
			
		||||
		return err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1112,11 +1112,11 @@ int dev_change_name(struct net_device *dev, const char *newname)
 | 
			
		|||
	ret = device_rename(&dev->dev, dev->name);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		memcpy(dev->name, oldname, IFNAMSIZ);
 | 
			
		||||
		write_sequnlock(&devnet_rename_seq);
 | 
			
		||||
		write_seqcount_end(&devnet_rename_seq);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	write_sequnlock(&devnet_rename_seq);
 | 
			
		||||
	write_seqcount_end(&devnet_rename_seq);
 | 
			
		||||
 | 
			
		||||
	write_lock_bh(&dev_base_lock);
 | 
			
		||||
	hlist_del_rcu(&dev->name_hlist);
 | 
			
		||||
| 
						 | 
				
			
			@ -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 */
 | 
			
		||||
		if (err >= 0) {
 | 
			
		||||
			err = ret;
 | 
			
		||||
			write_seqlock(&devnet_rename_seq);
 | 
			
		||||
			write_seqcount_begin(&devnet_rename_seq);
 | 
			
		||||
			memcpy(dev->name, oldname, IFNAMSIZ);
 | 
			
		||||
			goto rollback;
 | 
			
		||||
		} else {
 | 
			
		||||
| 
						 | 
				
			
			@ -4180,7 +4180,7 @@ static int dev_ifname(struct net *net, struct ifreq __user *arg)
 | 
			
		|||
		return -EFAULT;
 | 
			
		||||
 | 
			
		||||
retry:
 | 
			
		||||
	seq = read_seqbegin(&devnet_rename_seq);
 | 
			
		||||
	seq = read_seqcount_begin(&devnet_rename_seq);
 | 
			
		||||
	rcu_read_lock();
 | 
			
		||||
	dev = dev_get_by_index_rcu(net, ifr.ifr_ifindex);
 | 
			
		||||
	if (!dev) {
 | 
			
		||||
| 
						 | 
				
			
			@ -4190,7 +4190,7 @@ static int dev_ifname(struct net *net, struct ifreq __user *arg)
 | 
			
		|||
 | 
			
		||||
	strcpy(ifr.ifr_name, dev->name);
 | 
			
		||||
	rcu_read_unlock();
 | 
			
		||||
	if (read_seqretry(&devnet_rename_seq, seq))
 | 
			
		||||
	if (read_seqcount_retry(&devnet_rename_seq, seq))
 | 
			
		||||
		goto retry;
 | 
			
		||||
 | 
			
		||||
	if (copy_to_user(arg, &ifr, sizeof(struct ifreq)))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -583,7 +583,7 @@ static int sock_getbindtodevice(struct sock *sk, char __user *optval,
 | 
			
		|||
		goto out;
 | 
			
		||||
 | 
			
		||||
retry:
 | 
			
		||||
	seq = read_seqbegin(&devnet_rename_seq);
 | 
			
		||||
	seq = read_seqcount_begin(&devnet_rename_seq);
 | 
			
		||||
	rcu_read_lock();
 | 
			
		||||
	dev = dev_get_by_index_rcu(net, sk->sk_bound_dev_if);
 | 
			
		||||
	ret = -ENODEV;
 | 
			
		||||
| 
						 | 
				
			
			@ -594,7 +594,7 @@ static int sock_getbindtodevice(struct sock *sk, char __user *optval,
 | 
			
		|||
 | 
			
		||||
	strcpy(devname, dev->name);
 | 
			
		||||
	rcu_read_unlock();
 | 
			
		||||
	if (read_seqretry(&devnet_rename_seq, seq))
 | 
			
		||||
	if (read_seqcount_retry(&devnet_rename_seq, seq))
 | 
			
		||||
		goto retry;
 | 
			
		||||
 | 
			
		||||
	len = strlen(devname) + 1;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue