sched: migrate_enable: Use stop_one_cpu_nowait()

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>
This commit is contained in:
Scott Wood 2019-10-12 01:52:14 -05:00 committed by Alibek Omarov
parent fe6fe368b0
commit 5be92193b8
3 changed files with 24 additions and 12 deletions

View File

@ -26,6 +26,8 @@ struct cpu_stop_work {
cpu_stop_fn_t fn; cpu_stop_fn_t fn;
void *arg; void *arg;
struct cpu_stop_done *done; 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); int stop_one_cpu(unsigned int cpu, cpu_stop_fn_t fn, void *arg);

View File

@ -1631,6 +1631,7 @@ static struct rq *move_queued_task(struct rq *rq, struct rq_flags *rf,
struct migration_arg { struct migration_arg {
struct task_struct *task; struct task_struct *task;
int dest_cpu; int dest_cpu;
bool done;
}; };
/* /*
@ -1666,6 +1667,11 @@ static int migration_cpu_stop(void *data)
struct task_struct *p = arg->task; struct task_struct *p = arg->task;
struct rq *rq = this_rq(); struct rq *rq = this_rq();
struct rq_flags rf; 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 * The original target CPU might have gone down and we might
@ -1688,9 +1694,9 @@ static int migration_cpu_stop(void *data)
*/ */
if (task_rq(p) == rq) { if (task_rq(p) == rq) {
if (task_on_rq_queued(p)) if (task_on_rq_queued(p))
rq = __migrate_task(rq, &rf, p, arg->dest_cpu); rq = __migrate_task(rq, &rf, p, dest_cpu);
else else
p->wake_cpu = arg->dest_cpu; p->wake_cpu = dest_cpu;
} }
rq_unlock(rq, &rf); rq_unlock(rq, &rf);
raw_spin_unlock(&p->pi_lock); raw_spin_unlock(&p->pi_lock);
@ -8272,7 +8278,8 @@ void migrate_enable(void)
WARN_ON(smp_processor_id() != cpu); WARN_ON(smp_processor_id() != cpu);
if (!is_cpu_allowed(p, 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; struct rq_flags rf;
rq = task_rq_lock(p, &rf); rq = task_rq_lock(p, &rf);
@ -8280,13 +8287,13 @@ void migrate_enable(void)
arg.dest_cpu = select_fallback_rq(cpu, p); arg.dest_cpu = select_fallback_rq(cpu, p);
task_rq_unlock(rq, p, &rf); task_rq_unlock(rq, p, &rf);
preempt_enable(); stop_one_cpu_nowait(task_cpu(p), migration_cpu_stop,
&arg, &work);
sleeping_lock_inc(); __schedule(true);
stop_one_cpu(task_cpu(p), migration_cpu_stop, &arg); if (!work.disabled) {
sleeping_lock_dec(); while (!arg.done)
return; cpu_relax();
}
} }
out: out:

View File

@ -86,8 +86,11 @@ static bool cpu_stop_queue_work(unsigned int cpu, struct cpu_stop_work *work)
enabled = stopper->enabled; enabled = stopper->enabled;
if (enabled) if (enabled)
__cpu_stop_queue_work(stopper, work, &wakeq); __cpu_stop_queue_work(stopper, work, &wakeq);
else if (work->done) else {
cpu_stop_signal_done(work->done); work->disabled = true;
if (work->done)
cpu_stop_signal_done(work->done);
}
raw_spin_unlock_irqrestore(&stopper->lock, flags); raw_spin_unlock_irqrestore(&stopper->lock, flags);
wake_up_q(&wakeq); wake_up_q(&wakeq);