diff options
Diffstat (limited to 'debian/patches-rt/sched-migrate_enable-Use-stop_one_cpu_nowait.patch')
-rw-r--r-- | debian/patches-rt/sched-migrate_enable-Use-stop_one_cpu_nowait.patch | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/debian/patches-rt/sched-migrate_enable-Use-stop_one_cpu_nowait.patch b/debian/patches-rt/sched-migrate_enable-Use-stop_one_cpu_nowait.patch new file mode 100644 index 000000000..e75d0e306 --- /dev/null +++ b/debian/patches-rt/sched-migrate_enable-Use-stop_one_cpu_nowait.patch @@ -0,0 +1,112 @@ +From: Scott Wood <swood@redhat.com> +Date: Sat, 12 Oct 2019 01:52:14 -0500 +Subject: [PATCH] sched: migrate_enable: Use stop_one_cpu_nowait() +Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/5.4/older/patches-5.4.3-rt1.tar.xz + +migrate_enable() can be called with current->state != TASK_RUNNING. +Avoid clobbering the existing state by using stop_one_cpu_nowait(). +Since we're stopping the current cpu, we know that we won't get +past __schedule() until migration_cpu_stop() has run (at least up to +the point of migrating us to another cpu). + +Signed-off-by: Scott Wood <swood@redhat.com> +[bigeasy: spin until the request has been processed] +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +--- + include/linux/stop_machine.h | 2 ++ + kernel/sched/core.c | 27 +++++++++++++++++---------- + kernel/stop_machine.c | 7 +++++-- + 3 files changed, 24 insertions(+), 12 deletions(-) + +--- a/include/linux/stop_machine.h ++++ b/include/linux/stop_machine.h +@@ -26,6 +26,8 @@ struct cpu_stop_work { + cpu_stop_fn_t fn; + void *arg; + struct cpu_stop_done *done; ++ /* Did not run due to disabled stopper; for nowait debug checks */ ++ bool disabled; + }; + + int stop_one_cpu(unsigned int cpu, cpu_stop_fn_t fn, void *arg); +--- a/kernel/sched/core.c ++++ b/kernel/sched/core.c +@@ -1536,6 +1536,7 @@ static struct rq *move_queued_task(struc + struct migration_arg { + struct task_struct *task; + int dest_cpu; ++ bool done; + }; + + /* +@@ -1571,6 +1572,11 @@ static int migration_cpu_stop(void *data + struct task_struct *p = arg->task; + struct rq *rq = this_rq(); + struct rq_flags rf; ++ int dest_cpu = arg->dest_cpu; ++ ++ /* We don't look at arg after this point. */ ++ smp_mb(); ++ arg->done = true; + + /* + * The original target CPU might have gone down and we might +@@ -1593,9 +1599,9 @@ static int migration_cpu_stop(void *data + */ + if (task_rq(p) == rq) { + if (task_on_rq_queued(p)) +- rq = __migrate_task(rq, &rf, p, arg->dest_cpu); ++ rq = __migrate_task(rq, &rf, p, dest_cpu); + else +- p->wake_cpu = arg->dest_cpu; ++ p->wake_cpu = dest_cpu; + } + rq_unlock(rq, &rf); + raw_spin_unlock(&p->pi_lock); +@@ -8144,7 +8150,8 @@ void migrate_enable(void) + + WARN_ON(smp_processor_id() != cpu); + if (!is_cpu_allowed(p, cpu)) { +- struct migration_arg arg = { p }; ++ struct migration_arg arg = { .task = p }; ++ struct cpu_stop_work work; + struct rq_flags rf; + + rq = task_rq_lock(p, &rf); +@@ -8152,13 +8159,13 @@ void migrate_enable(void) + arg.dest_cpu = select_fallback_rq(cpu, p); + task_rq_unlock(rq, p, &rf); + +- preempt_enable(); +- +- sleeping_lock_inc(); +- stop_one_cpu(task_cpu(p), migration_cpu_stop, &arg); +- sleeping_lock_dec(); +- return; +- ++ stop_one_cpu_nowait(task_cpu(p), migration_cpu_stop, ++ &arg, &work); ++ __schedule(true); ++ if (!work.disabled) { ++ while (!arg.done) ++ cpu_relax(); ++ } + } + + out: +--- a/kernel/stop_machine.c ++++ b/kernel/stop_machine.c +@@ -86,8 +86,11 @@ static bool cpu_stop_queue_work(unsigned + enabled = stopper->enabled; + if (enabled) + __cpu_stop_queue_work(stopper, work, &wakeq); +- else if (work->done) +- cpu_stop_signal_done(work->done); ++ else { ++ work->disabled = true; ++ if (work->done) ++ cpu_stop_signal_done(work->done); ++ } + raw_spin_unlock_irqrestore(&stopper->lock, flags); + + wake_up_q(&wakeq); |