| Subject: stomp_machine: Use mutex_trylock when called from inactive cpu |
| From: Thomas Gleixner <tglx@linutronix.de> |
| Date: Wed, 03 Oct 2012 17:21:53 +0100 |
| |
| If the stop machinery is called from inactive CPU we cannot use |
| mutex_lock, because some other stomp machine invokation might be in |
| progress and the mutex can be contended. We cannot schedule from this |
| context, so trylock and loop. |
| |
| Signed-off-by: Thomas Gleixner <tglx@linutronix.de> |
| Cc: stable-rt@vger.kernel.org |
| --- |
| kernel/stop_machine.c | 13 +++++++++---- |
| 1 file changed, 9 insertions(+), 4 deletions(-) |
| |
| Index: linux-stable/kernel/stop_machine.c |
| =================================================================== |
| --- linux-stable.orig/kernel/stop_machine.c |
| +++ linux-stable/kernel/stop_machine.c |
| @@ -158,7 +158,7 @@ static DEFINE_PER_CPU(struct cpu_stop_wo |
| |
| static void queue_stop_cpus_work(const struct cpumask *cpumask, |
| cpu_stop_fn_t fn, void *arg, |
| - struct cpu_stop_done *done) |
| + struct cpu_stop_done *done, bool inactive) |
| { |
| struct cpu_stop_work *work; |
| unsigned int cpu; |
| @@ -175,7 +175,12 @@ static void queue_stop_cpus_work(const s |
| * Make sure that all work is queued on all cpus before we |
| * any of the cpus can execute it. |
| */ |
| - mutex_lock(&stopper_lock); |
| + if (!inactive) { |
| + mutex_lock(&stopper_lock); |
| + } else { |
| + while (!mutex_trylock(&stopper_lock)) |
| + cpu_relax(); |
| + } |
| for_each_cpu(cpu, cpumask) |
| cpu_stop_queue_work(&per_cpu(cpu_stopper, cpu), |
| &per_cpu(stop_cpus_work, cpu)); |
| @@ -188,7 +193,7 @@ static int __stop_cpus(const struct cpum |
| struct cpu_stop_done done; |
| |
| cpu_stop_init_done(&done, cpumask_weight(cpumask)); |
| - queue_stop_cpus_work(cpumask, fn, arg, &done); |
| + queue_stop_cpus_work(cpumask, fn, arg, &done, false); |
| wait_for_stop_done(&done); |
| return done.executed ? done.ret : -ENOENT; |
| } |
| @@ -601,7 +606,7 @@ int stop_machine_from_inactive_cpu(int ( |
| set_state(&smdata, STOPMACHINE_PREPARE); |
| cpu_stop_init_done(&done, num_active_cpus()); |
| queue_stop_cpus_work(cpu_active_mask, stop_machine_cpu_stop, &smdata, |
| - &done); |
| + &done, true); |
| ret = stop_machine_cpu_stop(&smdata); |
| |
| /* Busy wait for completion. */ |