diff options
-rw-r--r-- | include/linux/kthread.h | 1 | ||||
-rw-r--r-- | include/linux/sched.h | 2 | ||||
-rw-r--r-- | kernel/kthread.c | 30 | ||||
-rw-r--r-- | kernel/sched/core.c | 31 |
4 files changed, 36 insertions, 28 deletions
diff --git a/include/linux/kthread.h b/include/linux/kthread.h index 2803264c512f..c1961761311d 100644 --- a/include/linux/kthread.h +++ b/include/linux/kthread.h | |||
@@ -62,7 +62,6 @@ void *kthread_probe_data(struct task_struct *k); | |||
62 | int kthread_park(struct task_struct *k); | 62 | int kthread_park(struct task_struct *k); |
63 | void kthread_unpark(struct task_struct *k); | 63 | void kthread_unpark(struct task_struct *k); |
64 | void kthread_parkme(void); | 64 | void kthread_parkme(void); |
65 | void kthread_park_complete(struct task_struct *k); | ||
66 | 65 | ||
67 | int kthreadd(void *unused); | 66 | int kthreadd(void *unused); |
68 | extern struct task_struct *kthreadd_task; | 67 | extern struct task_struct *kthreadd_task; |
diff --git a/include/linux/sched.h b/include/linux/sched.h index 9256118bd40c..43731fe51c97 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -118,7 +118,7 @@ struct task_group; | |||
118 | * the comment with set_special_state(). | 118 | * the comment with set_special_state(). |
119 | */ | 119 | */ |
120 | #define is_special_task_state(state) \ | 120 | #define is_special_task_state(state) \ |
121 | ((state) & (__TASK_STOPPED | __TASK_TRACED | TASK_DEAD)) | 121 | ((state) & (__TASK_STOPPED | __TASK_TRACED | TASK_PARKED | TASK_DEAD)) |
122 | 122 | ||
123 | #define __set_current_state(state_value) \ | 123 | #define __set_current_state(state_value) \ |
124 | do { \ | 124 | do { \ |
diff --git a/kernel/kthread.c b/kernel/kthread.c index 481951bf091d..750cb8082694 100644 --- a/kernel/kthread.c +++ b/kernel/kthread.c | |||
@@ -177,9 +177,20 @@ void *kthread_probe_data(struct task_struct *task) | |||
177 | static void __kthread_parkme(struct kthread *self) | 177 | static void __kthread_parkme(struct kthread *self) |
178 | { | 178 | { |
179 | for (;;) { | 179 | for (;;) { |
180 | set_current_state(TASK_PARKED); | 180 | /* |
181 | * TASK_PARKED is a special state; we must serialize against | ||
182 | * possible pending wakeups to avoid store-store collisions on | ||
183 | * task->state. | ||
184 | * | ||
185 | * Such a collision might possibly result in the task state | ||
186 | * changin from TASK_PARKED and us failing the | ||
187 | * wait_task_inactive() in kthread_park(). | ||
188 | */ | ||
189 | set_special_state(TASK_PARKED); | ||
181 | if (!test_bit(KTHREAD_SHOULD_PARK, &self->flags)) | 190 | if (!test_bit(KTHREAD_SHOULD_PARK, &self->flags)) |
182 | break; | 191 | break; |
192 | |||
193 | complete_all(&self->parked); | ||
183 | schedule(); | 194 | schedule(); |
184 | } | 195 | } |
185 | __set_current_state(TASK_RUNNING); | 196 | __set_current_state(TASK_RUNNING); |
@@ -191,11 +202,6 @@ void kthread_parkme(void) | |||
191 | } | 202 | } |
192 | EXPORT_SYMBOL_GPL(kthread_parkme); | 203 | EXPORT_SYMBOL_GPL(kthread_parkme); |
193 | 204 | ||
194 | void kthread_park_complete(struct task_struct *k) | ||
195 | { | ||
196 | complete_all(&to_kthread(k)->parked); | ||
197 | } | ||
198 | |||
199 | static int kthread(void *_create) | 205 | static int kthread(void *_create) |
200 | { | 206 | { |
201 | /* Copy data: it's on kthread's stack */ | 207 | /* Copy data: it's on kthread's stack */ |
@@ -461,6 +467,9 @@ void kthread_unpark(struct task_struct *k) | |||
461 | 467 | ||
462 | reinit_completion(&kthread->parked); | 468 | reinit_completion(&kthread->parked); |
463 | clear_bit(KTHREAD_SHOULD_PARK, &kthread->flags); | 469 | clear_bit(KTHREAD_SHOULD_PARK, &kthread->flags); |
470 | /* | ||
471 | * __kthread_parkme() will either see !SHOULD_PARK or get the wakeup. | ||
472 | */ | ||
464 | wake_up_state(k, TASK_PARKED); | 473 | wake_up_state(k, TASK_PARKED); |
465 | } | 474 | } |
466 | EXPORT_SYMBOL_GPL(kthread_unpark); | 475 | EXPORT_SYMBOL_GPL(kthread_unpark); |
@@ -487,7 +496,16 @@ int kthread_park(struct task_struct *k) | |||
487 | set_bit(KTHREAD_SHOULD_PARK, &kthread->flags); | 496 | set_bit(KTHREAD_SHOULD_PARK, &kthread->flags); |
488 | if (k != current) { | 497 | if (k != current) { |
489 | wake_up_process(k); | 498 | wake_up_process(k); |
499 | /* | ||
500 | * Wait for __kthread_parkme() to complete(), this means we | ||
501 | * _will_ have TASK_PARKED and are about to call schedule(). | ||
502 | */ | ||
490 | wait_for_completion(&kthread->parked); | 503 | wait_for_completion(&kthread->parked); |
504 | /* | ||
505 | * Now wait for that schedule() to complete and the task to | ||
506 | * get scheduled out. | ||
507 | */ | ||
508 | WARN_ON_ONCE(!wait_task_inactive(k, TASK_PARKED)); | ||
491 | } | 509 | } |
492 | 510 | ||
493 | return 0; | 511 | return 0; |
diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 22fce36426c0..fe365c9a08e9 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c | |||
@@ -7,7 +7,6 @@ | |||
7 | */ | 7 | */ |
8 | #include "sched.h" | 8 | #include "sched.h" |
9 | 9 | ||
10 | #include <linux/kthread.h> | ||
11 | #include <linux/nospec.h> | 10 | #include <linux/nospec.h> |
12 | 11 | ||
13 | #include <linux/kcov.h> | 12 | #include <linux/kcov.h> |
@@ -2724,28 +2723,20 @@ static struct rq *finish_task_switch(struct task_struct *prev) | |||
2724 | membarrier_mm_sync_core_before_usermode(mm); | 2723 | membarrier_mm_sync_core_before_usermode(mm); |
2725 | mmdrop(mm); | 2724 | mmdrop(mm); |
2726 | } | 2725 | } |
2727 | if (unlikely(prev_state & (TASK_DEAD|TASK_PARKED))) { | 2726 | if (unlikely(prev_state == TASK_DEAD)) { |
2728 | switch (prev_state) { | 2727 | if (prev->sched_class->task_dead) |
2729 | case TASK_DEAD: | 2728 | prev->sched_class->task_dead(prev); |
2730 | if (prev->sched_class->task_dead) | ||
2731 | prev->sched_class->task_dead(prev); | ||
2732 | 2729 | ||
2733 | /* | 2730 | /* |
2734 | * Remove function-return probe instances associated with this | 2731 | * Remove function-return probe instances associated with this |
2735 | * task and put them back on the free list. | 2732 | * task and put them back on the free list. |
2736 | */ | 2733 | */ |
2737 | kprobe_flush_task(prev); | 2734 | kprobe_flush_task(prev); |
2738 | |||
2739 | /* Task is done with its stack. */ | ||
2740 | put_task_stack(prev); | ||
2741 | 2735 | ||
2742 | put_task_struct(prev); | 2736 | /* Task is done with its stack. */ |
2743 | break; | 2737 | put_task_stack(prev); |
2744 | 2738 | ||
2745 | case TASK_PARKED: | 2739 | put_task_struct(prev); |
2746 | kthread_park_complete(prev); | ||
2747 | break; | ||
2748 | } | ||
2749 | } | 2740 | } |
2750 | 2741 | ||
2751 | tick_nohz_task_switch(); | 2742 | tick_nohz_task_switch(); |