kthread: make struct kthread kmalloc'ed
Subsystems (3)
v2 cover kthread: make struct kthread kmalloc'ed
Hello,
I think that these patches were lost in confusing discussion, let me resend. The only change is that I added the acks from Thomas and Petr.
More to come.
Oleg.
include/linux/kthread.h | 1 + kernel/fork.c | 2 + kernel/kthread.c | 144 ++++++++++++++++++++++++------------------------ 3 files changed, 74 insertions(+), 73 deletions(-)
PATCH v2 1/5 kthread: make struct kthread kmalloc'ed
I still think we should kill struct kthread in its current form, but this needs cleanups outside of kthread.c.
So make it kmalloc'ed for now to avoid the problems with stack corruption, for example the crashed kthread will likely OOPS again because its .exited was destroyed by rewind_stack_do_exit().
--- include/linux/kthread.h | 1 + kernel/fork.c | 2 ++ kernel/kthread.c | 58 ++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 48 insertions(+), 13 deletions(-)
include/linux/kthread.h +1 -0
@@ -48,6 +48,7 @@ struct task_struct *kthread_create_on_cpu(int (*threadfn)(void *data), __k; \ }) +void free_kthread_struct (struct task_struct *k);void kthread_bind (struct task_struct *k,unsigned int cpu);void kthread_bind_mask (struct task_struct *k,const struct cpumask *mask);int kthread_stop (struct task_struct *k);
kernel/fork.c +2 -0
@@ -351,6 +351,8 @@ void free_task(struct task_struct *tsk)ftrace_graph_exit_task (tsk);put_seccomp_filter (tsk);arch_release_task_struct (tsk); +if (tsk->flags &PF_KTHREAD ) +free_kthread_struct (tsk);free_task_struct (tsk); }EXPORT_SYMBOL (free_task);
kernel/kthread.c +45 -13
91 lines not on this page · raw message
Signature · 1 line
2.5.0
tip-bot for Oleg Nesterov
merge bot[tip:sched/core] kthread: Make struct kthread kmalloc'ed
kthread: Make struct kthread kmalloc'ed
Commit-ID: 1da5c46fa965ff90f5ffc080b6ab3fae5e227bc3 Gitweb: http://git.kernel.org/tip/1da5c46fa965ff90f5ffc080b6ab3fae5e227bc3 Author: Oleg Nesterov <[email protected]> AuthorDate: Tue, 29 Nov 2016 18:50:57 +0100 Committer: Thomas Gleixner <[email protected]> CommitDate: Thu, 8 Dec 2016 14:36:18 +0100
kthread: Make struct kthread kmalloc'ed
commit 23196f2e5f5d "kthread: Pin the stack via try_get_task_stack() / put_task_stack() in to_live_kthread() function" is a workaround for the fragile design of struct kthread being allocated on the task stack.
struct kthread in its current form should be removed, but this needs cleanups outside of kthread.c.
As a first step move struct kthread away from the task stack by making it kmalloc'ed. This allows to access kthread.exited without the magic of trying to pin task stack and the try logic in to_live_kthread().
--- include/linux/kthread.h | 1 + kernel/fork.c | 2 ++ kernel/kthread.c | 58 ++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 48 insertions(+), 13 deletions(-)
include/linux/kthread.h +1 -0
@@ -48,6 +48,7 @@ struct task_struct *kthread_create_on_cpu(int (*threadfn)(void *data), __k; \ }) +void free_kthread_struct (struct task_struct *k);void kthread_bind (struct task_struct *k,unsigned int cpu);void kthread_bind_mask (struct task_struct *k,const struct cpumask *mask);int kthread_stop (struct task_struct *k);
kernel/fork.c +2 -0
@@ -354,6 +354,8 @@ void free_task(struct task_struct *tsk)ftrace_graph_exit_task (tsk);put_seccomp_filter (tsk);arch_release_task_struct (tsk); +if (tsk->flags &PF_KTHREAD ) +free_kthread_struct (tsk);free_task_struct (tsk); }EXPORT_SYMBOL (free_task);
kernel/kthread.c +45 -13
91 lines not on this page · raw message
PATCH v2 2/5 Revert "kthread: Pin the stack via try_get_task_stack()/put_task_stack() in to_live_kthread() function"
In reply to Oleg NesterovThis reverts commit 23196f2e5f5d810578a772785807dcdc2b9fdce9.
After the previous change struct kthread can't go away, no need to pin the stack.
TODO: kill to_live_kthread().
--- kernel/kthread.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-)
kernel/kthread.c +2 -6
@@ -88,7 +88,7 @@ void free_kthread_struct(struct task_struct *k)static struct kthread *to_live_kthread (struct task_struct *k) {struct completion *vfork =ACCESS_ONCE (k->vfork_done); -if (likely (vfork) &&try_get_task_stack (k)) +if (likely (vfork))return __to_kthread (vfork);return NULL ; }
@@ -473,10 +473,8 @@ void kthread_unpark(struct task_struct *k) {struct kthread *kthread =to_live_kthread (k); -if (kthread) { +if (kthread)__kthread_unpark (k, kthread); -put_task_stack (k); - } }EXPORT_SYMBOL_GPL (kthread_unpark);
@@ -505,7 +503,6 @@ int kthread_park(struct task_struct *k)wait_for_completion (&kthread->parked); } } -put_task_stack (k); ret =0 ; }return ret;
@@ -541,7 +538,6 @@ int kthread_stop(struct task_struct *k)__kthread_unpark (k, kthread);wake_up_process (k);wait_for_completion (&kthread->exited); -put_task_stack (k); } ret = k->exit_code;put_task_struct (k);
Signature · 1 line
2.5.0
tip-bot for Oleg Nesterov
merge bot[tip:sched/core] Revert "kthread: Pin the stack via try_get_task_stack()/put_task_stack() in to_live_kthread() function"
Revert "kthread: Pin the stack via try_get_task_stack()/put_task_stack() in to_live_kthread() function"
Commit-ID: eff9662547f358239b98dfc4a8e6905b494e14d6 Gitweb: http://git.kernel.org/tip/eff9662547f358239b98dfc4a8e6905b494e14d6 Author: Oleg Nesterov <[email protected]> AuthorDate: Tue, 29 Nov 2016 18:51:00 +0100 Committer: Thomas Gleixner <[email protected]> CommitDate: Thu, 8 Dec 2016 14:36:18 +0100
Revert "kthread: Pin the stack via try_get_task_stack()/put_task_stack() in to_live_kthread() function"
This reverts commit 23196f2e5f5d810578a772785807dcdc2b9fdce9.
Now that struct kthread is kmalloc'ed and not longer on the task stack there is no need anymore to pin the stack.
--- kernel/kthread.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-)
kernel/kthread.c +2 -6
@@ -88,7 +88,7 @@ void free_kthread_struct(struct task_struct *k)static struct kthread *to_live_kthread (struct task_struct *k) {struct completion *vfork =ACCESS_ONCE (k->vfork_done); -if (likely (vfork) &&try_get_task_stack (k)) +if (likely (vfork))return __to_kthread (vfork);return NULL ; }
@@ -473,10 +473,8 @@ void kthread_unpark(struct task_struct *k) {struct kthread *kthread =to_live_kthread (k); -if (kthread) { +if (kthread)__kthread_unpark (k, kthread); -put_task_stack (k); - } }EXPORT_SYMBOL_GPL (kthread_unpark);
@@ -505,7 +503,6 @@ int kthread_park(struct task_struct *k)wait_for_completion (&kthread->parked); } } -put_task_stack (k); ret =0 ; }return ret;
@@ -541,7 +538,6 @@ int kthread_stop(struct task_struct *k)__kthread_unpark (k, kthread);wake_up_process (k);wait_for_completion (&kthread->exited); -put_task_stack (k); } ret = k->exit_code;put_task_struct (k);
PATCH v2 3/5 kthread: don't use to_live_kthread() in kthread_stop()
In reply to Oleg Nesterovkthread_stop() had to use to_live_kthread() simply because it was not possible to access kthread->exited after the exiting kthread clears task_struct->vfork_done. Now that to_kthread() is always valid we can do wake_up_process() + wait_for_completion() unconditionally, we don't care if it has already passed complete_vfork_done() or even dead.
The exiting kthread can get the spurious wakeup after mm_release() but this is possible without this change too and this is fine, do_task_dead() ensures that this can't make any harm.
Note: we can even change this function to use task_work_add() and avoid ->vfork_done altogether, probably we will do this later.
--- kernel/kthread.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-)
kernel/kthread.c +5 -7
@@ -532,13 +532,11 @@ int kthread_stop(struct task_struct *k)trace_sched_kthread_stop (k);get_task_struct (k); - kthread =to_live_kthread (k); -if (kthread) { -set_bit (KTHREAD_SHOULD_STOP , &kthread->flags); -__kthread_unpark (k, kthread); -wake_up_process (k); -wait_for_completion (&kthread->exited); - } + kthread =to_kthread (k); +set_bit (KTHREAD_SHOULD_STOP , &kthread->flags); +__kthread_unpark (k, kthread); +wake_up_process (k); +wait_for_completion (&kthread->exited); ret = k->exit_code;put_task_struct (k);
Signature · 1 line
2.5.0
tip-bot for Oleg Nesterov
merge bot[tip:sched/core] kthread: Don't use to_live_kthread() in kthread_stop()
kthread: Don't use to_live_kthread() in kthread_stop()
Commit-ID: efb29fbfa50c490dac64a9418ebe553be82df781 Gitweb: http://git.kernel.org/tip/efb29fbfa50c490dac64a9418ebe553be82df781 Author: Oleg Nesterov <[email protected]> AuthorDate: Tue, 29 Nov 2016 18:51:03 +0100 Committer: Thomas Gleixner <[email protected]> CommitDate: Thu, 8 Dec 2016 14:36:19 +0100
kthread: Don't use to_live_kthread() in kthread_stop()
kthread_stop() had to use to_live_kthread() simply because it was not possible to access kthread->exited after the exiting task clears task_struct->vfork_done. Now that to_kthread() is always valid, wake_up_process() + wait_for_completion() can be done ununconditionally. It's not an issue anymore if the task has already issued complete_vfork_done() or died.
The exiting task can get the spurious wakeup after mm_release() but this is possible without this change too and is fine; do_task_dead() ensures that this can't make any harm.
As a further enhancement this could be converted to task_work_add() later, so ->vfork_done can be avoided completely.
--- kernel/kthread.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-)
kernel/kthread.c +5 -7
@@ -532,13 +532,11 @@ int kthread_stop(struct task_struct *k)trace_sched_kthread_stop (k);get_task_struct (k); - kthread =to_live_kthread (k); -if (kthread) { -set_bit (KTHREAD_SHOULD_STOP , &kthread->flags); -__kthread_unpark (k, kthread); -wake_up_process (k); -wait_for_completion (&kthread->exited); - } + kthread =to_kthread (k); +set_bit (KTHREAD_SHOULD_STOP , &kthread->flags); +__kthread_unpark (k, kthread); +wake_up_process (k); +wait_for_completion (&kthread->exited); ret = k->exit_code;put_task_struct (k);
PATCH v2 4/5 kthread: don't use to_live_kthread() in kthread_park() and kthread_unpark()
In reply to Oleg NesterovNow that to_kthread() is always valid we can change kthread_park() and kthread_unpark() to use it and kill to_live_kthread().
kthread_unpark() is trivial, if KTHREAD_IS_PARKED is set we know that this kthread has called complete(&self->parked), we do not care if it exits after that if we race with kthread_stop().
kthread_park() is more tricky, but only because its semantics is not well defined. It returns -ENOSYS if the thread exited but this can never happen and as Roman pointed out kthread_park() can obviously block forever if it could race with the exiting kthread.
I think we need to unexport kthread_park/unpark, and either make it return "void" or actually fix the race with kthred_stop/exit. This patch just adds WARN_ON(PF_EXITING) for now.
The usage of kthread_park() in cpuhp code (cpu.c, smpboot.c, stop_machine.c) is fine. It can never see an exiting/exited kthread, smpboot_destroy_threads() clears *ht->store, smpboot_park_thread() checks it is not NULL under the same smpboot_threads_lock. cpuhp_threads and cpu_stop_threads never exit, so other callers are fine too.
But it has two more users:
- watchdog_park_threads() and it does not look nice. The code is actually correct, get_online_cpus() ensures that kthread_park() can't race with itself (note that kthread_park() can't handle this race correctly), but imo it should not use kthread_park() directly.
- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c and I think it should not use kthread_park() too.
But this patch should not break this code. kthread_park() must not be called after amd_sched_fini() which does kthread_stop(), otherwise even to_live_kthread() is not safe because task_struct can be already freed and sched->thread can point to nowhere.
--- kernel/kthread.c | 69 ++++++++++++++++++++------------------------------------ 1 file changed, 24 insertions(+), 45 deletions(-)
kernel/kthread.c +24 -45
@@ -78,21 +78,6 @@ void free_kthread_struct(struct task_struct *k)kfree (to_kthread (k)); } -#define __to_kthread (vfork) \ - container_of(vfork, struct kthread, exited) - -/* -* TODO: kill it and use to_kthread(). But we still need the users -* like kthread_stop() which has to sync with the exiting kthread. -*/ -static struct kthread *to_live_kthread (struct task_struct *k) -{ -struct completion *vfork =ACCESS_ONCE (k->vfork_done); -if (likely (vfork)) -return __to_kthread (vfork); -return NULL ; -} -/** * kthread_should_stop - should this kthread return now? *
@@ -441,8 +426,18 @@ struct task_struct *kthread_create_on_cpu(int (*threadfn)(void *data),return p; } -static void __kthread_unpark (struct task_struct *k,struct kthread *kthread) +/** +* kthread_unpark - unpark a thread created by kthread_create(). +* @k: thread created by kthread_create(). +* +* Sets kthread_should_park() for @k to return false, wakes it, and +* waits for it to return. If the thread is marked percpu then its +* bound to the cpu again. +*/ +void kthread_unpark (struct task_struct *k) { +struct kthread *kthread =to_kthread (k); +clear_bit (KTHREAD_SHOULD_PARK , &kthread->flags);/* * We clear the IS_PARKED bit here as we don't wait
@@ -460,22 +455,6 @@ static void __kthread_unpark(struct task_struct *k, struct kthread *kthread)wake_up_state (k,TASK_PARKED ); } } - -/** -* kthread_unpark - unpark a thread created by kthread_create(). -* @k: thread created by kthread_create(). -* -* Sets kthread_should_park() for @k to return false, wakes it, and -* waits for it to return. If the thread is marked percpu then its -* bound to the cpu again. -*/ -void kthread_unpark (struct task_struct *k) -{ -struct kthread *kthread =to_live_kthread (k); - -if (kthread) -__kthread_unpark (k, kthread); -}EXPORT_SYMBOL_GPL (kthread_unpark);/**
@@ -492,20 +471,20 @@ EXPORT_SYMBOL_GPL(kthread_unpark);*/ int kthread_park (struct task_struct *k) { -struct kthread *kthread =to_live_kthread (k); -int ret = -ENOSYS ; - -if (kthread) { -if (!test_bit (KTHREAD_IS_PARKED , &kthread->flags)) { -set_bit (KTHREAD_SHOULD_PARK , &kthread->flags); -if (k != current) { -wake_up_process (k); -wait_for_completion (&kthread->parked); - } +struct kthread *kthread =to_kthread (k); + +if (WARN_ON (k->flags &PF_EXITING )) +return -ENOSYS ; + +if (!test_bit (KTHREAD_IS_PARKED , &kthread->flags)) { +set_bit (KTHREAD_SHOULD_PARK , &kthread->flags); +if (k != current) { +wake_up_process (k); +wait_for_completion (&kthread->parked); } - ret =0 ; } -return ret; + +return 0 ; }EXPORT_SYMBOL_GPL (kthread_park);
@@ -534,7 +513,7 @@ int kthread_stop(struct task_struct *k)get_task_struct (k); kthread =to_kthread (k);set_bit (KTHREAD_SHOULD_STOP , &kthread->flags); -__kthread_unpark (k, kthread); +kthread_unpark (k);wake_up_process (k);wait_for_completion (&kthread->exited); ret = k->exit_code;
Signature · 1 line
2.5.0
tip-bot for Oleg Nesterov
merge bot[tip:sched/core] kthread: Don't use to_live_kthread() in kthread_[un]park()
kthread: Don't use to_live_kthread() in kthread_[un]park()
Commit-ID: cf380a4a96e2260742051fa7fc831596bb26cc8b Gitweb: http://git.kernel.org/tip/cf380a4a96e2260742051fa7fc831596bb26cc8b Author: Oleg Nesterov <[email protected]> AuthorDate: Tue, 29 Nov 2016 18:51:07 +0100 Committer: Thomas Gleixner <[email protected]> CommitDate: Thu, 8 Dec 2016 14:36:19 +0100
kthread: Don't use to_live_kthread() in kthread_[un]park()
Now that to_kthread() is always validm change kthread_park() and kthread_unpark() to use it and kill to_live_kthread().
The conversion of kthread_unpark() is trivial. If KTHREAD_IS_PARKED is set then the task has called complete(&self->parked) and there the function cannot race against a concurrent kthread_stop() and exit.
kthread_park() is more tricky, because its semantics are not well defined. It returns -ENOSYS if the thread exited but this can never happen and as Roman pointed out kthread_park() can obviously block forever if it would race with the exiting kthread.
The usage of kthread_park() in cpuhp code (cpu.c, smpboot.c, stop_machine.c) is fine. It can never see an exiting/exited kthread, smpboot_destroy_threads() clears *ht->store, smpboot_park_thread() checks it is not NULL under the same smpboot_threads_lock. cpuhp_threads and cpu_stop_threads never exit, so other callers are fine too.
But it has two more users:
- watchdog_park_threads():
The code is actually correct, get_online_cpus() ensures that kthread_park() can't race with itself (note that kthread_park() can't handle this race correctly), but it should not use kthread_park() directly.
- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c should not use kthread_park() either.
kthread_park() must not be called after amd_sched_fini() which does kthread_stop(), otherwise even to_live_kthread() is not safe because task_struct can be already freed and sched->thread can point to nowhere.
The usage of kthread_park/unpark should either be restricted to core code which is properly protected against the exit race or made more robust so it is safe to use it in drivers.
To catch eventual exit issues, add a WARN_ON(PF_EXITING) for now.
--- kernel/kthread.c | 69 ++++++++++++++++++++------------------------------------ 1 file changed, 24 insertions(+), 45 deletions(-)
kernel/kthread.c +24 -45
@@ -78,21 +78,6 @@ void free_kthread_struct(struct task_struct *k)kfree (to_kthread (k)); } -#define __to_kthread (vfork) \ - container_of(vfork, struct kthread, exited) - -/* -* TODO: kill it and use to_kthread(). But we still need the users -* like kthread_stop() which has to sync with the exiting kthread. -*/ -static struct kthread *to_live_kthread (struct task_struct *k) -{ -struct completion *vfork =ACCESS_ONCE (k->vfork_done); -if (likely (vfork)) -return __to_kthread (vfork); -return NULL ; -} -/** * kthread_should_stop - should this kthread return now? *
@@ -441,8 +426,18 @@ struct task_struct *kthread_create_on_cpu(int (*threadfn)(void *data),return p; } -static void __kthread_unpark (struct task_struct *k,struct kthread *kthread) +/** +* kthread_unpark - unpark a thread created by kthread_create(). +* @k: thread created by kthread_create(). +* +* Sets kthread_should_park() for @k to return false, wakes it, and +* waits for it to return. If the thread is marked percpu then its +* bound to the cpu again. +*/ +void kthread_unpark (struct task_struct *k) { +struct kthread *kthread =to_kthread (k); +clear_bit (KTHREAD_SHOULD_PARK , &kthread->flags);/* * We clear the IS_PARKED bit here as we don't wait
@@ -460,22 +455,6 @@ static void __kthread_unpark(struct task_struct *k, struct kthread *kthread)wake_up_state (k,TASK_PARKED ); } } - -/** -* kthread_unpark - unpark a thread created by kthread_create(). -* @k: thread created by kthread_create(). -* -* Sets kthread_should_park() for @k to return false, wakes it, and -* waits for it to return. If the thread is marked percpu then its -* bound to the cpu again. -*/ -void kthread_unpark (struct task_struct *k) -{ -struct kthread *kthread =to_live_kthread (k); - -if (kthread) -__kthread_unpark (k, kthread); -}EXPORT_SYMBOL_GPL (kthread_unpark);/**
@@ -492,20 +471,20 @@ EXPORT_SYMBOL_GPL(kthread_unpark);*/ int kthread_park (struct task_struct *k) { -struct kthread *kthread =to_live_kthread (k); -int ret = -ENOSYS ; - -if (kthread) { -if (!test_bit (KTHREAD_IS_PARKED , &kthread->flags)) { -set_bit (KTHREAD_SHOULD_PARK , &kthread->flags); -if (k != current) { -wake_up_process (k); -wait_for_completion (&kthread->parked); - } +struct kthread *kthread =to_kthread (k); + +if (WARN_ON (k->flags &PF_EXITING )) +return -ENOSYS ; + +if (!test_bit (KTHREAD_IS_PARKED , &kthread->flags)) { +set_bit (KTHREAD_SHOULD_PARK , &kthread->flags); +if (k != current) { +wake_up_process (k); +wait_for_completion (&kthread->parked); } - ret =0 ; } -return ret; + +return 0 ; }EXPORT_SYMBOL_GPL (kthread_park);
@@ -534,7 +513,7 @@ int kthread_stop(struct task_struct *k)get_task_struct (k); kthread =to_kthread (k);set_bit (KTHREAD_SHOULD_STOP , &kthread->flags); -__kthread_unpark (k, kthread); +kthread_unpark (k);wake_up_process (k);wait_for_completion (&kthread->exited); ret = k->exit_code;
PATCH v2 5/5 kthread: don't abuse kthread_create_on_cpu() in __kthread_create_worker()
In reply to Oleg Nesterovkthread_create_on_cpu() sets KTHREAD_IS_PER_CPU and kthread->cpu, this only makes sense if this kthread can be parked/unparked by cpuhp code. kthread workers never call kthread_parkme() so this has no effect.
Change __kthread_create_worker() to simply call kthread_bind(task, cpu). The very fact that kthread_create_on_cpu() doesn't accept a generic fmt shows that it should not be used outside of smpboot.c.
Now, the only reason we can not unexport this helper and move it into smpboot.c is that it sets kthread->cpu and struct kthread is not exported. And the only reason we can not kill kthread->cpu is that kthread_unpark() is used by drivers/gpu/drm/amd/scheduler/gpu_scheduler.c and thus we can not turn _unpark into kthread_unpark(struct smp_hotplug_thread *, cpu).
--- kernel/kthread.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-)
kernel/kthread.c +8 -15
@@ -641,6 +641,7 @@ __kthread_create_worker(int cpu, unsigned int flags, {struct kthread_worker *worker;struct task_struct *task; +int node =-1 ; worker =kzalloc (sizeof (*worker),GFP_KERNEL );if (!worker)
@@ -648,25 +649,17 @@ __kthread_create_worker(int cpu, unsigned int flags,kthread_init_worker (worker); -if (cpu >=0 ) { -char name[TASK_COMM_LEN ]; - -/* -* kthread_create_worker_on_cpu() allows to pass a generic -* namefmt in compare with kthread_create_on_cpu. We need -* to format it here. -*/ -vsnprintf (name,sizeof (name), namefmt, args); - task =kthread_create_on_cpu (kthread_worker_fn, worker, - cpu, name); - }else { - task =__kthread_create_on_node (kthread_worker_fn, worker, --1 , namefmt, args); - } +if (cpu >=0 ) + node =cpu_to_node (cpu); + task =__kthread_create_on_node (kthread_worker_fn, worker, + node, namefmt, args);if (IS_ERR (task)) goto fail_task; +if (cpu >=0 ) +kthread_bind (task, cpu); + worker->flags = flags; worker->task = task;wake_up_process (task);
Signature · 1 line
2.5.0
tip-bot for Oleg Nesterov
merge bot[tip:sched/core] kthread: Don't abuse kthread_create_on_cpu() in __kthread_create_worker()
kthread: Don't abuse kthread_create_on_cpu() in __kthread_create_worker()
Commit-ID: 8fb9dcbdc3619741c10c573199d804161c34c89a Gitweb: http://git.kernel.org/tip/8fb9dcbdc3619741c10c573199d804161c34c89a Author: Oleg Nesterov <[email protected]> AuthorDate: Tue, 29 Nov 2016 18:51:10 +0100 Committer: Thomas Gleixner <[email protected]> CommitDate: Thu, 8 Dec 2016 14:36:20 +0100
kthread: Don't abuse kthread_create_on_cpu() in __kthread_create_worker()
kthread_create_on_cpu() sets KTHREAD_IS_PER_CPU and kthread->cpu, this only makes sense if this kthread can be parked/unparked by cpuhp code. kthread workers never call kthread_parkme() so this has no effect.
Change __kthread_create_worker() to simply call kthread_bind(task, cpu). The very fact that kthread_create_on_cpu() doesn't accept a generic fmt shows that it should not be used outside of smpboot.c.
Now, the only reason we can not unexport this helper and move it into smpboot.c is that it sets kthread->cpu and struct kthread is not exported. And the only reason we can not kill kthread->cpu is that kthread_unpark() is used by drivers/gpu/drm/amd/scheduler/gpu_scheduler.c and thus we can not turn _unpark into kthread_unpark(struct smp_hotplug_thread *, cpu).
--- kernel/kthread.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-)
kernel/kthread.c +8 -15
@@ -641,6 +641,7 @@ __kthread_create_worker(int cpu, unsigned int flags, {struct kthread_worker *worker;struct task_struct *task; +int node =-1 ; worker =kzalloc (sizeof (*worker),GFP_KERNEL );if (!worker)
@@ -648,25 +649,17 @@ __kthread_create_worker(int cpu, unsigned int flags,kthread_init_worker (worker); -if (cpu >=0 ) { -char name[TASK_COMM_LEN ]; - -/* -* kthread_create_worker_on_cpu() allows to pass a generic -* namefmt in compare with kthread_create_on_cpu. We need -* to format it here. -*/ -vsnprintf (name,sizeof (name), namefmt, args); - task =kthread_create_on_cpu (kthread_worker_fn, worker, - cpu, name); - }else { - task =__kthread_create_on_node (kthread_worker_fn, worker, --1 , namefmt, args); - } +if (cpu >=0 ) + node =cpu_to_node (cpu); + task =__kthread_create_on_node (kthread_worker_fn, worker, + node, namefmt, args);if (IS_ERR (task)) goto fail_task; +if (cpu >=0 ) +kthread_bind (task, cpu); + worker->flags = flags; worker->task = task;wake_up_process (task);
Quoted 6 lines · Oleg Nesterov
Hello,
I think that these patches were lost in confusing discussion, let me resend. The only change is that I added the acks from Thomas and Petr.
More to come.