Skip to content

Commit

Permalink
net: devnet_rename_seq should be a seqcount
Browse files Browse the repository at this point in the history
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 c91f6df (sockopt: Change getsockopt() of
SO_BINDTODEVICE to return an interface name)

Reported-by: Dave Jones <[email protected]>
Signed-off-by: Eric Dumazet <[email protected]>
Cc: Brian Haley <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
Eric Dumazet authored and davem330 committed Dec 21, 2012
1 parent f7e75ba commit 30e6c9f
Show file tree
Hide file tree
Showing 3 changed files with 12 additions and 12 deletions.
2 changes: 1 addition & 1 deletion include/linux/netdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) \
Expand Down
18 changes: 9 additions & 9 deletions net/core/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -1093,30 +1093,30 @@ 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;
}

memcpy(oldname, dev->name, IFNAMSIZ);

err = dev_get_valid_name(net, dev, newname);
if (err < 0) {
write_sequnlock(&devnet_rename_seq);
write_seqcount_end(&devnet_rename_seq);
return err;
}

rollback:
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);
Expand All @@ -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 {
Expand Down Expand Up @@ -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) {
Expand All @@ -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)))
Expand Down
4 changes: 2 additions & 2 deletions net/core/sock.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down

0 comments on commit 30e6c9f

Please sign in to comment.