Re: [PATCH 1/2] smpboot: Allow restricting per-CPU threads to a CPU mask

Bradley Morgan brads at mainlining.org
Tue Nov 3 03:48:52 PST 2026


On 2 November 2026 23:09:40 GMT, Daniel Lezcano
<daniel.lezcano at oss.qualcomm.com> wrote:
>smpboot_register_percpu_thread() creates a thread for every online CPU
>and registers the descriptor for subsequent CPU hotplug operations.
>There is currently no way to restrict these threads to a subset of
>CPUs, even when the user only needs work performed on that subset.
>
>For example, an idle injection device targets a specific CPU mask.
>Creating threads outside that mask consumes resources unnecessarily.
>Supporting multiple such devices also requires each descriptor to
>manage only the threads associated with its own CPUs.
>
>Add an optional CPU mask to struct smp_hotplug_thread and apply it
>throughout the thread lifecycle. Registration creates threads only for
>online CPUs in the mask. CPU bring-up creates threads for selected
>CPUs that were offline at registration, while parking and unparking
>are restricted to the same mask.
>
>Apply the restriction to thread destruction as well, both during
>unregistration and registration failure cleanup. This is necessary
>when descriptors with disjoint masks share the same per-CPU task
>storage: tearing down one descriptor must not stop or clear threads
>owned by another descriptor.
>
>The caller must keep the mask valid and unchanged until the descriptor
>is unregistered. Callers sharing per-CPU task storage must ensure their
>masks do not overlap and serialize ownership changes themselves.
>
>A NULL mask preserves the existing behavior, so current users continue
>to manage threads on all CPUs.
>

This is simple as it gets, thanks.

Reviewed-by: Bradley Morgan <brads at mainlining.org>

>Signed-off-by: Daniel Lezcano <daniel.lezcano at oss.qualcomm.com>
>---
> include/linux/smpboot.h |  4 ++++
> kernel/smpboot.c        | 17 +++++++++++++++--
> 2 files changed, 19 insertions(+), 2 deletions(-)
>
>diff --git a/include/linux/smpboot.h b/include/linux/smpboot.h
>index 9d1bc65d226c..98c072eeaf24 100644
>--- a/include/linux/smpboot.h
>+++ b/include/linux/smpboot.h
>@@ -5,6 +5,7 @@
> #include <linux/types.h>
> 
> struct task_struct;
>+struct cpumask;
> /* Cookie handed to the thread_fn*/
> struct smpboot_thread_data;
> 
>@@ -27,6 +28,8 @@ struct smpboot_thread_data;
>  *			unparked (cpu online)
>  * @selfparking:	Thread is not parked by the park function.
>  * @thread_comm:	The base name of the thread
>+ * @cpumask:		Optional mask of CPUs on which to create threads. Must remain
>+ *			valid and unchanged until the descriptor is unregistered.
>  */
> struct smp_hotplug_thread {
> 	struct task_struct		* __percpu *store;
>@@ -40,6 +43,7 @@ struct smp_hotplug_thread {
> 	void				(*unpark)(unsigned int cpu);
> 	bool				selfparking;
> 	const char			*thread_comm;
>+	const struct cpumask		*cpumask;
> };
> 
> int smpboot_register_percpu_thread(struct smp_hotplug_thread
> *plug_thread);
>diff --git a/kernel/smpboot.c b/kernel/smpboot.c
>index 4503b60ce9bd..07857523a465 100644
>--- a/kernel/smpboot.c
>+++ b/kernel/smpboot.c
>@@ -168,6 +168,9 @@ __smpboot_create_thread(struct smp_hotplug_thread *ht, unsigned int cpu)
> 	struct task_struct *tsk = *per_cpu_ptr(ht->store, cpu);
> 	struct smpboot_thread_data *td;
> 
>+	if (ht->cpumask && !cpumask_test_cpu(cpu, ht->cpumask))
>+		return 0;
>+
> 	if (tsk)
> 		return 0;
> 
>@@ -225,6 +228,9 @@ static void smpboot_unpark_thread(struct smp_hotplug_thread *ht, unsigned int cp
> {
> 	struct task_struct *tsk = *per_cpu_ptr(ht->store, cpu);
> 
>+	if (ht->cpumask && !cpumask_test_cpu(cpu, ht->cpumask))
>+		return;
>+
> 	if (!ht->selfparking)
> 		kthread_unpark(tsk);
> }
>@@ -244,6 +250,9 @@ static void smpboot_park_thread(struct smp_hotplug_thread *ht, unsigned int cpu)
> {
> 	struct task_struct *tsk = *per_cpu_ptr(ht->store, cpu);
> 
>+	if (ht->cpumask && !cpumask_test_cpu(cpu, ht->cpumask))
>+		return;
>+
> 	if (tsk && !ht->selfparking)
> 		kthread_park(tsk);
> }
>@@ -267,6 +276,9 @@ static void smpboot_destroy_threads(struct smp_hotplug_thread *ht)
> 	for_each_possible_cpu(cpu) {
> 		struct task_struct *tsk = *per_cpu_ptr(ht->store, cpu);
> 
>+		if (ht->cpumask && !cpumask_test_cpu(cpu, ht->cpumask))
>+			continue;
>+
> 		if (tsk) {
> 			kthread_stop_put(tsk);
> 			*per_cpu_ptr(ht->store, cpu) = NULL;
>@@ -279,7 +291,8 @@ static void smpboot_destroy_threads(struct smp_hotplug_thread *ht)
>  * 					    to hotplug
>  * @plug_thread:	Hotplug thread descriptor
>  *
>- * Creates and starts the threads on all online cpus.
>+ * Creates and starts the threads on online CPUs selected by the descriptor's
>+ * cpumask, or all online CPUs if no mask is specified.
>  */
> int smpboot_register_percpu_thread(struct smp_hotplug_thread
> *plug_thread)
> {
>@@ -308,7 +321,7 @@ EXPORT_SYMBOL_GPL(smpboot_register_percpu_thread);
>  * smpboot_unregister_percpu_thread - Unregister a per_cpu thread related to hotplug
>  * @plug_thread:	Hotplug thread descriptor
>  *
>- * Stops all threads on all possible cpus.
>+ * Stops all threads associated with the descriptor, including offline CPUs.
>  */
> void smpboot_unregister_percpu_thread(struct smp_hotplug_thread
> *plug_thread)
> {
>


--- Thanks!



More information about the Linux-rockchip mailing list