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:
parent
fe6fe368b0
commit
5be92193b8
|
@ -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);
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue