2013-11-22 01:00:09 +00:00
|
|
|
From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
|
|
|
|
Date: Wed, 20 Mar 2013 18:06:20 +0100
|
|
|
|
Subject: [PATCH] net: Add a mutex around devnet_rename_seq
|
2013-12-02 05:10:45 +00:00
|
|
|
Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/3.12/patches-3.12.1-rt4.tar.xz
|
2013-11-22 01:00:09 +00:00
|
|
|
|
|
|
|
On RT write_seqcount_begin() disables preemption and device_rename()
|
|
|
|
allocates memory with GFP_KERNEL and grabs later the sysfs_mutex
|
|
|
|
mutex. Serialize with a mutex and add use the non preemption disabling
|
|
|
|
__write_seqcount_begin().
|
|
|
|
|
|
|
|
To avoid writer starvation, let the reader grab the mutex and release
|
|
|
|
it when it detects a writer in progress. This keeps the normal case
|
|
|
|
(no reader on the fly) fast.
|
|
|
|
|
|
|
|
[ tglx: Instead of replacing the seqcount by a mutex, add the mutex ]
|
|
|
|
|
|
|
|
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
|
|
|
|
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
|
|
|
|
---
|
|
|
|
net/core/dev.c | 34 ++++++++++++++++++++--------------
|
|
|
|
1 file changed, 20 insertions(+), 14 deletions(-)
|
|
|
|
|
|
|
|
--- a/net/core/dev.c
|
|
|
|
+++ b/net/core/dev.c
|
|
|
|
@@ -175,6 +175,7 @@ static unsigned int napi_gen_id;
|
|
|
|
static DEFINE_HASHTABLE(napi_hash, 8);
|
|
|
|
|
|
|
|
static seqcount_t devnet_rename_seq;
|
|
|
|
+static DEFINE_MUTEX(devnet_rename_mutex);
|
|
|
|
|
|
|
|
static inline void dev_base_seq_inc(struct net *net)
|
|
|
|
{
|
|
|
|
@@ -826,7 +827,8 @@ int netdev_get_name(struct net *net, cha
|
|
|
|
strcpy(name, dev->name);
|
|
|
|
rcu_read_unlock();
|
|
|
|
if (read_seqcount_retry(&devnet_rename_seq, seq)) {
|
|
|
|
- cond_resched();
|
|
|
|
+ mutex_lock(&devnet_rename_mutex);
|
|
|
|
+ mutex_unlock(&devnet_rename_mutex);
|
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
|
|
|
|
@@ -1092,30 +1094,28 @@ int dev_change_name(struct net_device *d
|
|
|
|
if (dev->flags & IFF_UP)
|
|
|
|
return -EBUSY;
|
|
|
|
|
|
|
|
- write_seqcount_begin(&devnet_rename_seq);
|
|
|
|
+ mutex_lock(&devnet_rename_mutex);
|
|
|
|
+ __write_seqcount_begin(&devnet_rename_seq);
|
|
|
|
|
|
|
|
- if (strncmp(newname, dev->name, IFNAMSIZ) == 0) {
|
|
|
|
- write_seqcount_end(&devnet_rename_seq);
|
|
|
|
- return 0;
|
|
|
|
- }
|
|
|
|
+ if (strncmp(newname, dev->name, IFNAMSIZ) == 0)
|
|
|
|
+ goto outunlock;
|
|
|
|
|
|
|
|
memcpy(oldname, dev->name, IFNAMSIZ);
|
|
|
|
|
|
|
|
err = dev_get_valid_name(net, dev, newname);
|
|
|
|
- if (err < 0) {
|
|
|
|
- write_seqcount_end(&devnet_rename_seq);
|
|
|
|
- return err;
|
|
|
|
- }
|
|
|
|
+ if (err < 0)
|
|
|
|
+ goto outunlock;
|
|
|
|
|
|
|
|
rollback:
|
|
|
|
ret = device_rename(&dev->dev, dev->name);
|
|
|
|
if (ret) {
|
|
|
|
memcpy(dev->name, oldname, IFNAMSIZ);
|
|
|
|
- write_seqcount_end(&devnet_rename_seq);
|
|
|
|
- return ret;
|
|
|
|
+ err = ret;
|
|
|
|
+ goto outunlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
- write_seqcount_end(&devnet_rename_seq);
|
|
|
|
+ __write_seqcount_end(&devnet_rename_seq);
|
|
|
|
+ mutex_unlock(&devnet_rename_mutex);
|
|
|
|
|
|
|
|
write_lock_bh(&dev_base_lock);
|
|
|
|
hlist_del_rcu(&dev->name_hlist);
|
|
|
|
@@ -1134,7 +1134,8 @@ int dev_change_name(struct net_device *d
|
|
|
|
/* err >= 0 after dev_alloc_name() or stores the first errno */
|
|
|
|
if (err >= 0) {
|
|
|
|
err = ret;
|
|
|
|
- write_seqcount_begin(&devnet_rename_seq);
|
|
|
|
+ mutex_lock(&devnet_rename_mutex);
|
|
|
|
+ __write_seqcount_begin(&devnet_rename_seq);
|
|
|
|
memcpy(dev->name, oldname, IFNAMSIZ);
|
|
|
|
goto rollback;
|
|
|
|
} else {
|
|
|
|
@@ -1144,6 +1145,11 @@ int dev_change_name(struct net_device *d
|
|
|
|
}
|
|
|
|
|
|
|
|
return err;
|
|
|
|
+
|
|
|
|
+outunlock:
|
|
|
|
+ __write_seqcount_end(&devnet_rename_seq);
|
|
|
|
+ mutex_unlock(&devnet_rename_mutex);
|
|
|
|
+ return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|