From d4c6a64967be6e34fec40ddff5714efe001be7c3 Mon Sep 17 00:00:00 2001 From: Chris Friesen Date: Tue, 24 Nov 2015 16:27:28 -0500 Subject: [PATCH] affine compute kernel threads This is a kernel enhancement to configure the cpu affinity of kernel threads via kernel boot option kthread_cpus=. The compute kickstart file and compute-huge.sh scripts will update grub with the new option. With kthread_cpus specified, the cpumask is immediately applied upon thread launch. This does not affect kernel threads that specify cpu and node. Note: this is based off of Christoph Lameter's patch at https://lwn.net/Articles/565932/ with the only difference being the kernel parameter changed from kthread to kthread_cpus. Signed-off-by: Christoph Lameter Signed-off-by: Chris Friesen [VT: The existing "isolcpus" kernel bootarg, cgroup/cpuset, and taskset might provide the some way to have cpu isolation. However none of them satisfies the requirements. Replacing spaces with tabs. Combine two calls of set_cpus_allowed_ptr() in kernel_init_freeable() in init/main.c into one. Performed tests] Signed-off-by: Vu Tran Signed-off-by: Jim Somerville Signed-off-by: Zhang Zhiguo Signed-off-by: Vefa Bicakci [jm: Adapted the patch for context changes.] Signed-off-by: Jiping Ma --- .../admin-guide/kernel-parameters.txt | 10 ++++++++ include/linux/cpumask.h | 3 +++ init/main.c | 2 ++ kernel/cpu.c | 23 +++++++++++++++++++ kernel/kthread.c | 5 ++-- kernel/umh.c | 3 +++ 6 files changed, 43 insertions(+), 3 deletions(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 19e9e220eaa1..0260789adc94 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -2223,6 +2223,16 @@ See also Documentation/trace/kprobetrace.rst "Kernel Boot Parameter" section. + kthread_cpus= [KNL, SMP] Only run kernel threads on the specified + list of processors. The kernel will start threads + on the indicated processors only (unless there + are specific reasons to run a thread with + different affinities). This can be used to make + init start on certain processors and also to + control where kmod and other user space threads + are being spawned. Allows to keep kernel threads + away from certain cores unless absoluteluy necessary. + kpti= [ARM64] Control page table isolation of user and kernel address spaces. Default: enabled on cores which need mitigation. diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h index f0d895d6ac39..45f338cfdd6f 100644 --- a/include/linux/cpumask.h +++ b/include/linux/cpumask.h @@ -55,6 +55,7 @@ extern unsigned int nr_cpu_ids; * cpu_present_mask - has bit 'cpu' set iff cpu is populated * cpu_online_mask - has bit 'cpu' set iff cpu available to scheduler * cpu_active_mask - has bit 'cpu' set iff cpu available to migration + * cpu_kthread_mask - has bit 'cpu' set iff general kernel threads allowed * * If !CONFIG_HOTPLUG_CPU, present == possible, and active == online. * @@ -91,10 +92,12 @@ extern struct cpumask __cpu_possible_mask; extern struct cpumask __cpu_online_mask; extern struct cpumask __cpu_present_mask; extern struct cpumask __cpu_active_mask; +extern struct cpumask __cpu_kthread_mask; #define cpu_possible_mask ((const struct cpumask *)&__cpu_possible_mask) #define cpu_online_mask ((const struct cpumask *)&__cpu_online_mask) #define cpu_present_mask ((const struct cpumask *)&__cpu_present_mask) #define cpu_active_mask ((const struct cpumask *)&__cpu_active_mask) +#define cpu_kthread_mask ((const struct cpumask *)&__cpu_kthread_mask) extern atomic_t __num_online_cpus; diff --git a/init/main.c b/init/main.c index db693781a12f..4e7777bdab6e 100644 --- a/init/main.c +++ b/init/main.c @@ -1536,6 +1536,8 @@ static noinline void __init kernel_init_freeable(void) do_basic_setup(); + set_cpus_allowed_ptr(current, cpu_kthread_mask); + kunit_run_all_tests(); console_on_rootfs(); diff --git a/kernel/cpu.c b/kernel/cpu.c index 67c22941b5f2..67b1a67bd8f0 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -2498,6 +2498,29 @@ EXPORT_SYMBOL(__cpu_active_mask); atomic_t __num_online_cpus __read_mostly; EXPORT_SYMBOL(__num_online_cpus); +struct cpumask __cpu_kthread_mask __read_mostly + = {CPU_BITS_ALL}; +EXPORT_SYMBOL(__cpu_kthread_mask); + +static int __init kthread_setup(char *str) +{ + cpumask_var_t tmp_mask; + int err; + + alloc_bootmem_cpumask_var(&tmp_mask); + + err = cpulist_parse(str, tmp_mask); + if (!err) + cpumask_copy(&__cpu_kthread_mask, tmp_mask); + else + pr_err("Cannot parse 'kthread_cpus=%s'; error %d\n", str, err); + + free_bootmem_cpumask_var(tmp_mask); + + return 1; +} +__setup("kthread_cpus=", kthread_setup); + void init_cpu_present(const struct cpumask *src) { cpumask_copy(&__cpu_present_mask, src); diff --git a/kernel/kthread.c b/kernel/kthread.c index 508fe5278285..a7bb87b00cea 100644 --- a/kernel/kthread.c +++ b/kernel/kthread.c @@ -405,8 +405,7 @@ struct task_struct *__kthread_create_on_node(int (*threadfn)(void *data), * The kernel thread should not inherit these properties. */ sched_setscheduler_nocheck(task, SCHED_NORMAL, ¶m); - set_cpus_allowed_ptr(task, - housekeeping_cpumask(HK_FLAG_KTHREAD)); + set_cpus_allowed_ptr(task, cpu_kthread_mask); } kfree(create); return task; @@ -655,7 +654,7 @@ int kthreadd(void *unused) /* Setup a clean context for our children to inherit. */ set_task_comm(tsk, "kthreadd"); ignore_signals(tsk); - set_cpus_allowed_ptr(tsk, housekeeping_cpumask(HK_FLAG_KTHREAD)); + set_cpus_allowed_ptr(tsk, cpu_kthread_mask); set_mems_allowed(node_states[N_MEMORY]); current->flags |= PF_NOFREEZE; diff --git a/kernel/umh.c b/kernel/umh.c index 3f646613a9d3..e5027cee43f7 100644 --- a/kernel/umh.c +++ b/kernel/umh.c @@ -80,6 +80,9 @@ static int call_usermodehelper_exec_async(void *data) */ current->fs->umask = 0022; + /* We can run only where init is allowed to run. */ + set_cpus_allowed_ptr(current, cpu_kthread_mask); + /* * Our parent (unbound workqueue) runs with elevated scheduling * priority. Avoid propagating that into the userspace child. -- 2.29.2