mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-19 21:21:09 +00:00
sched: Replace rq::wake_list
The recent commit: 90b5363acd
("sched: Clean up scheduler_ipi()")
got smp_call_function_single_async() subtly wrong. Even though it will
return -EBUSY when trying to re-use a csd, that condition is not
atomic and still requires external serialization.
The change in ttwu_queue_remote() got this wrong.
While on first reading ttwu_queue_remote() has an atomic test-and-set
that appears to serialize the use, the matching 'release' is not in
the right place to actually guarantee this serialization.
The actual race is vs the sched_ttwu_pending() call in the idle loop;
that can run the wakeup-list without consuming the CSD.
Instead of trying to chain the lists, merge them.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Link: https://lore.kernel.org/r/20200526161908.129371594@infradead.org
This commit is contained in:
parent
126c2092e5
commit
a148866489
6 changed files with 49 additions and 34 deletions
47
kernel/smp.c
47
kernel/smp.c
|
@ -196,6 +196,7 @@ void generic_smp_call_function_single_interrupt(void)
|
|||
flush_smp_call_function_queue(true);
|
||||
}
|
||||
|
||||
extern void sched_ttwu_pending(void *);
|
||||
extern void irq_work_single(void *);
|
||||
|
||||
/**
|
||||
|
@ -244,6 +245,10 @@ static void flush_smp_call_function_queue(bool warn_cpu_offline)
|
|||
csd->func);
|
||||
break;
|
||||
|
||||
case CSD_TYPE_TTWU:
|
||||
pr_warn("IPI task-wakeup sent to offline CPU\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
pr_warn("IPI callback, unknown type %d, sent to offline CPU\n",
|
||||
CSD_TYPE(csd));
|
||||
|
@ -275,22 +280,43 @@ static void flush_smp_call_function_queue(bool warn_cpu_offline)
|
|||
}
|
||||
}
|
||||
|
||||
if (!entry)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Second; run all !SYNC callbacks.
|
||||
*/
|
||||
prev = NULL;
|
||||
llist_for_each_entry_safe(csd, csd_next, entry, llist) {
|
||||
int type = CSD_TYPE(csd);
|
||||
|
||||
if (type == CSD_TYPE_ASYNC) {
|
||||
smp_call_func_t func = csd->func;
|
||||
void *info = csd->info;
|
||||
if (type != CSD_TYPE_TTWU) {
|
||||
if (prev) {
|
||||
prev->next = &csd_next->llist;
|
||||
} else {
|
||||
entry = &csd_next->llist;
|
||||
}
|
||||
|
||||
csd_unlock(csd);
|
||||
func(info);
|
||||
} else if (type == CSD_TYPE_IRQ_WORK) {
|
||||
irq_work_single(csd);
|
||||
if (type == CSD_TYPE_ASYNC) {
|
||||
smp_call_func_t func = csd->func;
|
||||
void *info = csd->info;
|
||||
|
||||
csd_unlock(csd);
|
||||
func(info);
|
||||
} else if (type == CSD_TYPE_IRQ_WORK) {
|
||||
irq_work_single(csd);
|
||||
}
|
||||
|
||||
} else {
|
||||
prev = &csd->llist;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Third; only CSD_TYPE_TTWU is left, issue those.
|
||||
*/
|
||||
if (entry)
|
||||
sched_ttwu_pending(entry);
|
||||
}
|
||||
|
||||
void flush_smp_call_function_from_idle(void)
|
||||
|
@ -659,6 +685,13 @@ void __init smp_init(void)
|
|||
BUILD_BUG_ON(offsetof(struct irq_work, flags) !=
|
||||
offsetof(struct __call_single_data, flags));
|
||||
|
||||
/*
|
||||
* Assert the CSD_TYPE_TTWU layout is similar enough
|
||||
* for task_struct to be on the @call_single_queue.
|
||||
*/
|
||||
BUILD_BUG_ON(offsetof(struct task_struct, wake_entry_type) - offsetof(struct task_struct, wake_entry) !=
|
||||
offsetof(struct __call_single_data, flags) - offsetof(struct __call_single_data, llist));
|
||||
|
||||
idle_threads_init();
|
||||
cpuhp_threads_init();
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue