* [RFC PATCH 11/20] kthread: Make sure kthread hasn't started while binding it
[not found] <20240726215701.19459-1-frederic@kernel.org>
@ 2024-07-26 21:56 ` Frederic Weisbecker
2024-07-30 15:20 ` Vlastimil Babka
2024-07-26 21:56 ` [RFC PATCH 12/20] kthread: Implement preferred affinity Frederic Weisbecker
` (4 subsequent siblings)
5 siblings, 1 reply; 16+ messages in thread
From: Frederic Weisbecker @ 2024-07-26 21:56 UTC (permalink / raw)
To: LKML
Cc: Frederic Weisbecker, Andrew Morton, Kees Cook, Peter Zijlstra,
Thomas Gleixner, Michal Hocko, Vlastimil Babka, linux-mm,
Paul E. McKenney, Neeraj Upadhyay, Joel Fernandes, Boqun Feng,
Zqiang, rcu
Make sure the kthread is sleeping in the schedule_preempt_disabled()
call before calling its handler when kthread_bind[_mask]() is called
on it. This provides a sanity check verifying that the task is not
randomly blocked later at some point within its function handler, in
which case it could be just concurrently awaken, leaving the call to
do_set_cpus_allowed() without any effect until the next voluntary sleep.
Rely on the wake-up ordering to ensure that the newly introduced "started"
field returns the expected value:
TASK A TASK B
------ ------
READ kthread->started
wake_up_process(B)
rq_lock()
...
rq_unlock() // RELEASE
schedule()
rq_lock() // ACQUIRE
// schedule task B
rq_unlock()
WRITE kthread->started
Similarly, writing kthread->started before subsequent voluntary sleeps
will be visible after calling wait_task_inactive() in
__kthread_bind_mask(), reporting potential misuse of the API.
Upcoming patches will make further use of this facility.
Signed-off-by: Frederic Weisbecker <frederic@kernel.org>
---
kernel/kthread.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/kernel/kthread.c b/kernel/kthread.c
index f7be976ff88a..ecb719f54f7a 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -53,6 +53,7 @@ struct kthread_create_info
struct kthread {
unsigned long flags;
unsigned int cpu;
+ int started;
int result;
int (*threadfn)(void *);
void *data;
@@ -382,6 +383,8 @@ static int kthread(void *_create)
schedule_preempt_disabled();
preempt_enable();
+ self->started = 1;
+
ret = -EINTR;
if (!test_bit(KTHREAD_SHOULD_STOP, &self->flags)) {
cgroup_kthread_ready();
@@ -540,7 +543,9 @@ static void __kthread_bind(struct task_struct *p, unsigned int cpu, unsigned int
void kthread_bind_mask(struct task_struct *p, const struct cpumask *mask)
{
+ struct kthread *kthread = to_kthread(p);
__kthread_bind_mask(p, mask, TASK_UNINTERRUPTIBLE);
+ WARN_ON_ONCE(kthread->started);
}
/**
@@ -554,7 +559,9 @@ void kthread_bind_mask(struct task_struct *p, const struct cpumask *mask)
*/
void kthread_bind(struct task_struct *p, unsigned int cpu)
{
+ struct kthread *kthread = to_kthread(p);
__kthread_bind(p, cpu, TASK_UNINTERRUPTIBLE);
+ WARN_ON_ONCE(kthread->started);
}
EXPORT_SYMBOL(kthread_bind);
--
2.45.2
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [RFC PATCH 12/20] kthread: Implement preferred affinity
[not found] <20240726215701.19459-1-frederic@kernel.org>
2024-07-26 21:56 ` [RFC PATCH 11/20] kthread: Make sure kthread hasn't started while binding it Frederic Weisbecker
@ 2024-07-26 21:56 ` Frederic Weisbecker
2024-07-26 22:31 ` Frederic Weisbecker
2024-07-30 15:49 ` Vlastimil Babka
2024-07-26 21:56 ` [RFC PATCH 17/20] rcu: Use kthread preferred affinity for RCU boost Frederic Weisbecker
` (3 subsequent siblings)
5 siblings, 2 replies; 16+ messages in thread
From: Frederic Weisbecker @ 2024-07-26 21:56 UTC (permalink / raw)
To: LKML
Cc: Frederic Weisbecker, Andrew Morton, Kees Cook, Peter Zijlstra,
Thomas Gleixner, Michal Hocko, Vlastimil Babka, linux-mm,
Paul E. McKenney, Neeraj Upadhyay, Joel Fernandes, Boqun Feng,
Zqiang, rcu
Affining kthreads follow either of three existing different patterns:
1) Per-CPU kthreads must stay affine to a single CPU and never execute
relevant code on any other CPU. This is currently handled by smpboot
code which takes care of CPU-hotplug operations.
2) Kthreads that _have_ to be affine to a specific set of CPUs and can't
run anywhere else. The affinity is set through kthread_bind_mask()
and the subsystem takes care by itself to handle CPU-hotplug operations.
3) Kthreads that have a _preferred_ affinity but that can run anywhere
without breaking correctness. Userspace can overwrite the affinity.
It is set manually like any other task and CPU-hotplug is supposed
to be handled by the relevant subsystem so that the task is properly
reaffined whenever a given CPU from the preferred affinity comes up
or down. Also care must be taken so that the preferred affinity
doesn't cross housekeeping cpumask boundaries.
Currently the preferred affinity pattern has at least 4 identified
users, with more or less success when it comes to handle CPU-hotplug
operations and housekeeping cpumask.
Provide an infrastructure to handle this usecase patter. A new
kthread_affine_preferred() API is introduced, to be used just like
kthread_bind_mask(), right after kthread creation and before the first
wake up. The kthread is then affine right away to the cpumask passed
through the API if it has online housekeeping CPUs. Otherwise it will
be affine to all online housekeeping CPUs as a last resort.
It is aware of CPU hotplug events such that:
* When a housekeeping CPU goes up and is part of the preferred affinity
of a given kthread, it is added to its applied affinity set (and
possibly the default last resort online housekeeping set is removed
from the set).
* When a housekeeping CPU goes down while it was part of the preferred
affinity of a kthread, it is removed from the kthread's applied
affinity. The last resort is to affine the kthread to all online
housekeeping CPUs.
Signed-off-by: Frederic Weisbecker <frederic@kernel.org>
---
include/linux/cpuhotplug.h | 1 +
include/linux/kthread.h | 1 +
kernel/kthread.c | 121 +++++++++++++++++++++++++++++++++++++
3 files changed, 123 insertions(+)
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
index 7a5785f405b6..5c204bd0fed6 100644
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -238,6 +238,7 @@ enum cpuhp_state {
CPUHP_AP_WORKQUEUE_ONLINE,
CPUHP_AP_RANDOM_ONLINE,
CPUHP_AP_RCUTREE_ONLINE,
+ CPUHP_AP_KTHREADS_ONLINE,
CPUHP_AP_BASE_CACHEINFO_ONLINE,
CPUHP_AP_ONLINE_DYN,
CPUHP_AP_ONLINE_DYN_END = CPUHP_AP_ONLINE_DYN + 40,
diff --git a/include/linux/kthread.h b/include/linux/kthread.h
index b11f53c1ba2e..30209bdf83a2 100644
--- a/include/linux/kthread.h
+++ b/include/linux/kthread.h
@@ -85,6 +85,7 @@ kthread_run_on_cpu(int (*threadfn)(void *data), void *data,
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_affine_preferred(struct task_struct *p, const struct cpumask *mask);
int kthread_stop(struct task_struct *k);
int kthread_stop_put(struct task_struct *k);
bool kthread_should_stop(void);
diff --git a/kernel/kthread.c b/kernel/kthread.c
index ecb719f54f7a..cfa6e1b8d933 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -35,6 +35,10 @@ static DEFINE_SPINLOCK(kthread_create_lock);
static LIST_HEAD(kthread_create_list);
struct task_struct *kthreadd_task;
+static struct cpumask kthread_online_mask;
+static LIST_HEAD(kthreads_hotplug);
+static DEFINE_MUTEX(kthreads_hotplug_lock);
+
struct kthread_create_info
{
/* Information passed to kthread() from kthreadd. */
@@ -64,6 +68,9 @@ struct kthread {
#endif
/* To store the full name if task comm is truncated. */
char *full_name;
+ struct task_struct *task;
+ struct list_head hotplug_node;
+ struct cpumask *preferred_affinity;
};
enum KTHREAD_BITS {
@@ -124,6 +131,7 @@ bool set_kthread_struct(struct task_struct *p)
init_completion(&kthread->parked);
p->vfork_done = &kthread->exited;
+ kthread->task = p;
p->worker_private = kthread;
return true;
}
@@ -314,6 +322,16 @@ void __noreturn kthread_exit(long result)
{
struct kthread *kthread = to_kthread(current);
kthread->result = result;
+ if (kthread->preferred_affinity) {
+ mutex_lock(&kthreads_hotplug_lock);
+ list_del(&kthread->hotplug_node);
+ /* Make sure the kthread never gets re-affined globally */
+ set_cpus_allowed_ptr(current, housekeeping_cpumask(HK_TYPE_KTHREAD));
+ mutex_unlock(&kthreads_hotplug_lock);
+
+ kfree(kthread->preferred_affinity);
+ kthread->preferred_affinity = NULL;
+ }
do_exit(0);
}
EXPORT_SYMBOL(kthread_exit);
@@ -779,6 +797,109 @@ int kthreadd(void *unused)
return 0;
}
+static void kthread_fetch_affinity(struct kthread *k, struct cpumask *mask)
+{
+ cpumask_and(mask, k->preferred_affinity, &kthread_online_mask);
+ cpumask_and(mask, mask, housekeeping_cpumask(HK_TYPE_KTHREAD));
+ if (cpumask_empty(mask))
+ cpumask_copy(mask, housekeeping_cpumask(HK_TYPE_KTHREAD));
+}
+
+int kthread_affine_preferred(struct task_struct *p, const struct cpumask *mask)
+{
+ struct kthread *kthread = to_kthread(p);
+ cpumask_var_t affinity;
+ unsigned long flags;
+ int ret;
+
+ if (!wait_task_inactive(p, TASK_UNINTERRUPTIBLE) || kthread->started) {
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ if (!zalloc_cpumask_var(&affinity, GFP_KERNEL))
+ return -ENOMEM;
+
+ kthread->preferred_affinity = kzalloc(sizeof(struct cpumask), GFP_KERNEL);
+ if (!kthread->preferred_affinity) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ mutex_lock(&kthreads_hotplug_lock);
+ cpumask_copy(kthread->preferred_affinity, mask);
+ list_add_tail(&kthread->hotplug_node, &kthreads_hotplug);
+ kthread_fetch_affinity(kthread, affinity);
+
+ /* It's safe because the task is inactive. */
+ raw_spin_lock_irqsave(&p->pi_lock, flags);
+ do_set_cpus_allowed(p, mask);
+ raw_spin_unlock_irqrestore(&p->pi_lock, flags);
+
+ mutex_unlock(&kthreads_hotplug_lock);
+out:
+ free_cpumask_var(affinity);
+
+ return 0;
+}
+
+static int kthreads_hotplug_update(void)
+{
+ cpumask_var_t affinity;
+ struct kthread *k;
+ int err = 0;
+
+ if (list_empty(&kthreads_hotplug))
+ return 0;
+
+ if (!zalloc_cpumask_var(&affinity, GFP_KERNEL))
+ return -ENOMEM;
+
+ list_for_each_entry(k, &kthreads_hotplug, hotplug_node) {
+ if (WARN_ON_ONCE(!k->preferred_affinity)) {
+ err = -EINVAL;
+ break;
+ }
+ kthread_fetch_affinity(k, affinity);
+ set_cpus_allowed_ptr(k->task, affinity);
+ }
+
+ free_cpumask_var(affinity);
+
+ return err;
+}
+
+static int kthreads_offline_cpu(unsigned int cpu)
+{
+ int ret = 0;
+
+ mutex_lock(&kthreads_hotplug_lock);
+ cpumask_clear_cpu(cpu, &kthread_online_mask);
+ ret = kthreads_hotplug_update();
+ mutex_unlock(&kthreads_hotplug_lock);
+
+ return ret;
+}
+
+static int kthreads_online_cpu(unsigned int cpu)
+{
+ int ret = 0;
+
+ mutex_lock(&kthreads_hotplug_lock);
+ cpumask_set_cpu(cpu, &kthread_online_mask);
+ ret = kthreads_hotplug_update();
+ mutex_unlock(&kthreads_hotplug_lock);
+
+ return ret;
+}
+
+static int kthreads_init(void)
+{
+ return cpuhp_setup_state(CPUHP_AP_KTHREADS_ONLINE, "kthreads:online",
+ kthreads_online_cpu, kthreads_offline_cpu);
+}
+early_initcall(kthreads_init);
+
void __kthread_init_worker(struct kthread_worker *worker,
const char *name,
struct lock_class_key *key)
--
2.45.2
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [RFC PATCH 17/20] rcu: Use kthread preferred affinity for RCU boost
[not found] <20240726215701.19459-1-frederic@kernel.org>
2024-07-26 21:56 ` [RFC PATCH 11/20] kthread: Make sure kthread hasn't started while binding it Frederic Weisbecker
2024-07-26 21:56 ` [RFC PATCH 12/20] kthread: Implement preferred affinity Frederic Weisbecker
@ 2024-07-26 21:56 ` Frederic Weisbecker
2024-07-26 21:56 ` [RFC PATCH 18/20] kthread: Unify kthread_create_on_cpu() and kthread_create_worker_on_cpu() automatic format Frederic Weisbecker
` (2 subsequent siblings)
5 siblings, 0 replies; 16+ messages in thread
From: Frederic Weisbecker @ 2024-07-26 21:56 UTC (permalink / raw)
To: LKML
Cc: Frederic Weisbecker, Paul E. McKenney, Neeraj Upadhyay,
Joel Fernandes, Boqun Feng, Zqiang, rcu, Andrew Morton,
Peter Zijlstra, Thomas Gleixner
Now that kthreads have an infrastructure to handle preferred affinity
against CPU hotplug and housekeeping cpumask, convert RCU boost to use
it instead of handling all the constraints by itself.
Signed-off-by: Frederic Weisbecker <frederic@kernel.org>
---
kernel/rcu/tree.c | 27 +++++++++++++++++++--------
kernel/rcu/tree_plugin.h | 11 ++---------
2 files changed, 21 insertions(+), 17 deletions(-)
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
index 28c7031711a3..6ff87a3e000b 100644
--- a/kernel/rcu/tree.c
+++ b/kernel/rcu/tree.c
@@ -148,7 +148,6 @@ static int rcu_scheduler_fully_active __read_mostly;
static void rcu_report_qs_rnp(unsigned long mask, struct rcu_node *rnp,
unsigned long gps, unsigned long flags);
-static struct task_struct *rcu_boost_task(struct rcu_node *rnp);
static void invoke_rcu_core(void);
static void rcu_report_exp_rdp(struct rcu_data *rdp);
static void sync_sched_exp_online_cleanup(int cpu);
@@ -4894,6 +4893,22 @@ int rcutree_prepare_cpu(unsigned int cpu)
return 0;
}
+static void rcu_thread_affine_rnp(struct task_struct *t, struct rcu_node *rnp)
+{
+ cpumask_var_t affinity;
+ int cpu;
+
+ if (!zalloc_cpumask_var(&affinity, GFP_KERNEL))
+ return;
+
+ for_each_leaf_node_possible_cpu(rnp, cpu)
+ cpumask_set_cpu(cpu, affinity);
+
+ kthread_affine_preferred(t, affinity);
+
+ free_cpumask_var(affinity);
+}
+
/*
* Update kthreads affinity during CPU-hotplug changes.
*
@@ -4913,19 +4928,18 @@ static void rcutree_affinity_setting(unsigned int cpu, int outgoingcpu)
unsigned long mask;
struct rcu_data *rdp;
struct rcu_node *rnp;
- struct task_struct *task_boost, *task_exp;
+ struct task_struct *task_exp;
rdp = per_cpu_ptr(&rcu_data, cpu);
rnp = rdp->mynode;
- task_boost = rcu_boost_task(rnp);
task_exp = rcu_exp_par_gp_task(rnp);
/*
- * If CPU is the boot one, those tasks are created later from early
+ * If CPU is the boot one, this task is created later from early
* initcall since kthreadd must be created first.
*/
- if (!task_boost && !task_exp)
+ if (!task_exp)
return;
if (!zalloc_cpumask_var(&cm, GFP_KERNEL))
@@ -4947,9 +4961,6 @@ static void rcutree_affinity_setting(unsigned int cpu, int outgoingcpu)
if (task_exp)
set_cpus_allowed_ptr(task_exp, cm);
- if (task_boost)
- set_cpus_allowed_ptr(task_boost, cm);
-
mutex_unlock(&rnp->kthread_mutex);
free_cpumask_var(cm);
diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h
index 340bbefe5f65..2d9eca53cb7e 100644
--- a/kernel/rcu/tree_plugin.h
+++ b/kernel/rcu/tree_plugin.h
@@ -1206,16 +1206,13 @@ static void rcu_spawn_one_boost_kthread(struct rcu_node *rnp)
raw_spin_lock_irqsave_rcu_node(rnp, flags);
rnp->boost_kthread_task = t;
raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
+
sp.sched_priority = kthread_prio;
sched_setscheduler_nocheck(t, SCHED_FIFO, &sp);
+ rcu_thread_affine_rnp(t, rnp);
wake_up_process(t); /* get to TASK_INTERRUPTIBLE quickly. */
}
-static struct task_struct *rcu_boost_task(struct rcu_node *rnp)
-{
- return READ_ONCE(rnp->boost_kthread_task);
-}
-
#else /* #ifdef CONFIG_RCU_BOOST */
static void rcu_initiate_boost(struct rcu_node *rnp, unsigned long flags)
@@ -1232,10 +1229,6 @@ static void rcu_spawn_one_boost_kthread(struct rcu_node *rnp)
{
}
-static struct task_struct *rcu_boost_task(struct rcu_node *rnp)
-{
- return NULL;
-}
#endif /* #else #ifdef CONFIG_RCU_BOOST */
/*
--
2.45.2
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [RFC PATCH 18/20] kthread: Unify kthread_create_on_cpu() and kthread_create_worker_on_cpu() automatic format
[not found] <20240726215701.19459-1-frederic@kernel.org>
` (2 preceding siblings ...)
2024-07-26 21:56 ` [RFC PATCH 17/20] rcu: Use kthread preferred affinity for RCU boost Frederic Weisbecker
@ 2024-07-26 21:56 ` Frederic Weisbecker
2024-07-26 21:56 ` [RFC PATCH 19/20] treewide: Introduce kthread_run_worker[_on_cpu]() Frederic Weisbecker
2024-07-26 21:56 ` [RFC PATCH 20/20] rcu: Use kthread preferred affinity for RCU exp kworkers Frederic Weisbecker
5 siblings, 0 replies; 16+ messages in thread
From: Frederic Weisbecker @ 2024-07-26 21:56 UTC (permalink / raw)
To: LKML
Cc: Frederic Weisbecker, Paul E. McKenney, Neeraj Upadhyay,
Joel Fernandes, Boqun Feng, Zqiang, rcu, Andrew Morton,
Peter Zijlstra, Thomas Gleixner
kthread_create_on_cpu() uses the CPU argument as an implicit and unique
printf argument to add to the format whereas
kthread_create_worker_on_cpu() still relies on explicitly passing the
printf arguments. This difference in behaviour is error prone and
doesn't help standardizing per-CPU kthread names.
Unify the behaviours and convert kthread_create_worker_on_cpu() to
use the printf behaviour of kthread_create_on_cpu().
Signed-off-by: Frederic Weisbecker <frederic@kernel.org>
---
fs/erofs/zdata.c | 2 +-
include/linux/kthread.h | 21 +++++++++++----
kernel/kthread.c | 59 ++++++++++++++++++++++++-----------------
3 files changed, 52 insertions(+), 30 deletions(-)
diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c
index d6fe002a4a71..f1ccdf47585b 100644
--- a/fs/erofs/zdata.c
+++ b/fs/erofs/zdata.c
@@ -356,7 +356,7 @@ static void erofs_destroy_percpu_workers(void)
static struct kthread_worker *erofs_init_percpu_worker(int cpu)
{
struct kthread_worker *worker =
- kthread_create_worker_on_cpu(cpu, 0, "erofs_worker/%u", cpu);
+ kthread_create_worker_on_cpu(cpu, 0, "erofs_worker/%u");
if (IS_ERR(worker))
return worker;
diff --git a/include/linux/kthread.h b/include/linux/kthread.h
index 30209bdf83a2..0c66e7c1092a 100644
--- a/include/linux/kthread.h
+++ b/include/linux/kthread.h
@@ -187,13 +187,24 @@ extern void __kthread_init_worker(struct kthread_worker *worker,
int kthread_worker_fn(void *worker_ptr);
-__printf(2, 3)
+__printf(3, 4)
+struct kthread_worker *kthread_create_worker_on_node(unsigned int flags,
+ int node,
+ const char namefmt[], ...);
+
+#define kthread_create_worker(flags, namefmt, ...) \
+({ \
+ struct kthread_worker *__kw \
+ = kthread_create_worker_on_node(flags, NUMA_NO_NODE, \
+ namefmt, ## __VA_ARGS__); \
+ if (!IS_ERR(__kw)) \
+ wake_up_process(__kw->task); \
+ __kw; \
+})
+
struct kthread_worker *
-kthread_create_worker(unsigned int flags, const char namefmt[], ...);
-
-__printf(3, 4) struct kthread_worker *
kthread_create_worker_on_cpu(int cpu, unsigned int flags,
- const char namefmt[], ...);
+ const char namefmt[]);
bool kthread_queue_work(struct kthread_worker *worker,
struct kthread_work *work);
diff --git a/kernel/kthread.c b/kernel/kthread.c
index cfa6e1b8d933..34b11dbfc756 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -983,12 +983,11 @@ int kthread_worker_fn(void *worker_ptr)
EXPORT_SYMBOL_GPL(kthread_worker_fn);
static __printf(3, 0) struct kthread_worker *
-__kthread_create_worker(int cpu, unsigned int flags,
- const char namefmt[], va_list args)
+__kthread_create_worker_on_node(unsigned int flags, int node,
+ const char namefmt[], va_list args)
{
struct kthread_worker *worker;
struct task_struct *task;
- int node = NUMA_NO_NODE;
worker = kzalloc(sizeof(*worker), GFP_KERNEL);
if (!worker)
@@ -996,20 +995,14 @@ __kthread_create_worker(int cpu, unsigned int flags,
kthread_init_worker(worker);
- if (cpu >= 0)
- node = cpu_to_node(cpu);
-
task = __kthread_create_on_node(kthread_worker_fn, worker,
- node, namefmt, args);
+ 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);
+
return worker;
fail_task:
@@ -1020,6 +1013,7 @@ __kthread_create_worker(int cpu, unsigned int flags,
/**
* kthread_create_worker - create a kthread worker
* @flags: flags modifying the default behavior of the worker
+ * @node: task structure for the thread is allocated on this node
* @namefmt: printf-style name for the kthread worker (task).
*
* Returns a pointer to the allocated worker on success, ERR_PTR(-ENOMEM)
@@ -1027,25 +1021,49 @@ __kthread_create_worker(int cpu, unsigned int flags,
* when the caller was killed by a fatal signal.
*/
struct kthread_worker *
-kthread_create_worker(unsigned int flags, const char namefmt[], ...)
+kthread_create_worker_on_node(unsigned int flags, int node, const char namefmt[], ...)
{
struct kthread_worker *worker;
va_list args;
va_start(args, namefmt);
- worker = __kthread_create_worker(-1, flags, namefmt, args);
+ worker = __kthread_create_worker_on_node(flags, node, namefmt, args);
va_end(args);
+ if (worker)
+ wake_up_process(worker->task);
+
+ return worker;
+}
+EXPORT_SYMBOL(kthread_create_worker_on_node);
+
+static __printf(3, 4) struct kthread_worker *
+__kthread_create_worker_on_cpu(int cpu, unsigned int flags,
+ const char namefmt[], ...)
+{
+ struct kthread_worker *worker;
+ va_list args;
+
+ va_start(args, namefmt);
+ worker = __kthread_create_worker_on_node(flags, cpu_to_node(cpu),
+ namefmt, args);
+ va_end(args);
+
+ if (worker) {
+ kthread_bind(worker->task, cpu);
+ wake_up_process(worker->task);
+ }
+
return worker;
}
-EXPORT_SYMBOL(kthread_create_worker);
/**
* kthread_create_worker_on_cpu - create a kthread worker and bind it
* to a given CPU and the associated NUMA node.
* @cpu: CPU number
* @flags: flags modifying the default behavior of the worker
- * @namefmt: printf-style name for the kthread worker (task).
+ * @namefmt: printf-style name for the thread. Format is restricted
+ * to "name.*%u". Code fills in cpu number.
*
* Use a valid CPU number if you want to bind the kthread worker
* to the given CPU and the associated NUMA node.
@@ -1077,16 +1095,9 @@ EXPORT_SYMBOL(kthread_create_worker);
*/
struct kthread_worker *
kthread_create_worker_on_cpu(int cpu, unsigned int flags,
- const char namefmt[], ...)
+ const char namefmt[])
{
- struct kthread_worker *worker;
- va_list args;
-
- va_start(args, namefmt);
- worker = __kthread_create_worker(cpu, flags, namefmt, args);
- va_end(args);
-
- return worker;
+ return __kthread_create_worker_on_cpu(cpu, flags, namefmt, cpu);
}
EXPORT_SYMBOL(kthread_create_worker_on_cpu);
--
2.45.2
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [RFC PATCH 19/20] treewide: Introduce kthread_run_worker[_on_cpu]()
[not found] <20240726215701.19459-1-frederic@kernel.org>
` (3 preceding siblings ...)
2024-07-26 21:56 ` [RFC PATCH 18/20] kthread: Unify kthread_create_on_cpu() and kthread_create_worker_on_cpu() automatic format Frederic Weisbecker
@ 2024-07-26 21:56 ` Frederic Weisbecker
2024-07-26 21:56 ` [RFC PATCH 20/20] rcu: Use kthread preferred affinity for RCU exp kworkers Frederic Weisbecker
5 siblings, 0 replies; 16+ messages in thread
From: Frederic Weisbecker @ 2024-07-26 21:56 UTC (permalink / raw)
To: LKML
Cc: Frederic Weisbecker, Paul E. McKenney, Neeraj Upadhyay,
Joel Fernandes, Boqun Feng, Zqiang, rcu, Andrew Morton,
Peter Zijlstra, Thomas Gleixner
kthread_create() creates a kthread without running it yet. kthread_run()
creates a kthread and runs it.
On the other hand, kthread_create_worker() creates a kthread worker and
runs it.
This difference in behaviours is confusing. Also there is no way to
create a kthread worker and affine it using kthread_bind_mask() or
kthread_affine_preferred() before starting it.
Consolidate the behaviours and introduce kthread_run_worker[_on_cpu]()
that behaves just like kthread_run(). kthread_create_worker[_on_cpu]()
will now only create a kthread worker without starting it.
Signed-off-by: Frederic Weisbecker <frederic@kernel.org>
---
arch/x86/kvm/i8254.c | 2 +-
crypto/crypto_engine.c | 2 +-
drivers/cpufreq/cppc_cpufreq.c | 2 +-
drivers/gpu/drm/drm_vblank_work.c | 2 +-
.../drm/i915/gem/selftests/i915_gem_context.c | 2 +-
drivers/gpu/drm/i915/gt/selftest_execlists.c | 2 +-
drivers/gpu/drm/i915/gt/selftest_hangcheck.c | 2 +-
drivers/gpu/drm/i915/gt/selftest_slpc.c | 2 +-
drivers/gpu/drm/i915/selftests/i915_request.c | 8 ++--
drivers/gpu/drm/msm/disp/msm_disp_snapshot.c | 2 +-
drivers/gpu/drm/msm/msm_atomic.c | 2 +-
drivers/gpu/drm/msm/msm_gpu.c | 2 +-
drivers/gpu/drm/msm/msm_kms.c | 2 +-
.../platform/chips-media/wave5/wave5-vpu.c | 2 +-
drivers/net/dsa/mv88e6xxx/chip.c | 2 +-
drivers/net/ethernet/intel/ice/ice_dpll.c | 2 +-
drivers/net/ethernet/intel/ice/ice_gnss.c | 2 +-
drivers/net/ethernet/intel/ice/ice_ptp.c | 2 +-
drivers/platform/chrome/cros_ec_spi.c | 2 +-
drivers/ptp/ptp_clock.c | 2 +-
drivers/spi/spi.c | 2 +-
drivers/usb/typec/tcpm/tcpm.c | 2 +-
drivers/vdpa/vdpa_sim/vdpa_sim.c | 2 +-
drivers/watchdog/watchdog_dev.c | 2 +-
fs/erofs/zdata.c | 2 +-
include/linux/kthread.h | 48 ++++++++++++++++---
kernel/kthread.c | 31 +++---------
kernel/rcu/tree.c | 4 +-
kernel/workqueue.c | 2 +-
net/dsa/tag_ksz.c | 2 +-
net/dsa/tag_ocelot_8021q.c | 2 +-
net/dsa/tag_sja1105.c | 2 +-
32 files changed, 82 insertions(+), 65 deletions(-)
diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c
index cd57a517d04a..d7ab8780ab9e 100644
--- a/arch/x86/kvm/i8254.c
+++ b/arch/x86/kvm/i8254.c
@@ -681,7 +681,7 @@ struct kvm_pit *kvm_create_pit(struct kvm *kvm, u32 flags)
pid_nr = pid_vnr(pid);
put_pid(pid);
- pit->worker = kthread_create_worker(0, "kvm-pit/%d", pid_nr);
+ pit->worker = kthread_run_worker(0, "kvm-pit/%d", pid_nr);
if (IS_ERR(pit->worker))
goto fail_kthread;
diff --git a/crypto/crypto_engine.c b/crypto/crypto_engine.c
index e60a0eb628e8..c7c16da5e649 100644
--- a/crypto/crypto_engine.c
+++ b/crypto/crypto_engine.c
@@ -517,7 +517,7 @@ struct crypto_engine *crypto_engine_alloc_init_and_set(struct device *dev,
crypto_init_queue(&engine->queue, qlen);
spin_lock_init(&engine->queue_lock);
- engine->kworker = kthread_create_worker(0, "%s", engine->name);
+ engine->kworker = kthread_run_worker(0, "%s", engine->name);
if (IS_ERR(engine->kworker)) {
dev_err(dev, "failed to create crypto request pump task\n");
return NULL;
diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
index 15f1d41920a3..09421424b4ec 100644
--- a/drivers/cpufreq/cppc_cpufreq.c
+++ b/drivers/cpufreq/cppc_cpufreq.c
@@ -241,7 +241,7 @@ static void __init cppc_freq_invariance_init(void)
if (fie_disabled)
return;
- kworker_fie = kthread_create_worker(0, "cppc_fie");
+ kworker_fie = kthread_run_worker(0, "cppc_fie");
if (IS_ERR(kworker_fie)) {
pr_warn("%s: failed to create kworker_fie: %ld\n", __func__,
PTR_ERR(kworker_fie));
diff --git a/drivers/gpu/drm/drm_vblank_work.c b/drivers/gpu/drm/drm_vblank_work.c
index 4fe9b1d3b00f..02ff12744396 100644
--- a/drivers/gpu/drm/drm_vblank_work.c
+++ b/drivers/gpu/drm/drm_vblank_work.c
@@ -255,7 +255,7 @@ int drm_vblank_worker_init(struct drm_vblank_crtc *vblank)
INIT_LIST_HEAD(&vblank->pending_work);
init_waitqueue_head(&vblank->work_wait_queue);
- worker = kthread_create_worker(0, "card%d-crtc%d",
+ worker = kthread_run_worker(0, "card%d-crtc%d",
vblank->dev->primary->index,
vblank->pipe);
if (IS_ERR(worker))
diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
index 89d4dc8b60c6..eb0158e43417 100644
--- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
@@ -369,7 +369,7 @@ static int live_parallel_switch(void *arg)
if (!data[n].ce[0])
continue;
- worker = kthread_create_worker(0, "igt/parallel:%s",
+ worker = kthread_run_worker(0, "igt/parallel:%s",
data[n].ce[0]->engine->name);
if (IS_ERR(worker)) {
err = PTR_ERR(worker);
diff --git a/drivers/gpu/drm/i915/gt/selftest_execlists.c b/drivers/gpu/drm/i915/gt/selftest_execlists.c
index 4202df5b8c12..7da05fd6807f 100644
--- a/drivers/gpu/drm/i915/gt/selftest_execlists.c
+++ b/drivers/gpu/drm/i915/gt/selftest_execlists.c
@@ -3574,7 +3574,7 @@ static int smoke_crescendo(struct preempt_smoke *smoke, unsigned int flags)
arg[id].batch = NULL;
arg[id].count = 0;
- worker[id] = kthread_create_worker(0, "igt/smoke:%d", id);
+ worker[id] = kthread_run_worker(0, "igt/smoke:%d", id);
if (IS_ERR(worker[id])) {
err = PTR_ERR(worker[id]);
break;
diff --git a/drivers/gpu/drm/i915/gt/selftest_hangcheck.c b/drivers/gpu/drm/i915/gt/selftest_hangcheck.c
index 9ce8ff1c04fe..9d3aeb237295 100644
--- a/drivers/gpu/drm/i915/gt/selftest_hangcheck.c
+++ b/drivers/gpu/drm/i915/gt/selftest_hangcheck.c
@@ -1025,7 +1025,7 @@ static int __igt_reset_engines(struct intel_gt *gt,
threads[tmp].engine = other;
threads[tmp].flags = flags;
- worker = kthread_create_worker(0, "igt/%s",
+ worker = kthread_run_worker(0, "igt/%s",
other->name);
if (IS_ERR(worker)) {
err = PTR_ERR(worker);
diff --git a/drivers/gpu/drm/i915/gt/selftest_slpc.c b/drivers/gpu/drm/i915/gt/selftest_slpc.c
index 4ecc4ae74a54..e218b229681f 100644
--- a/drivers/gpu/drm/i915/gt/selftest_slpc.c
+++ b/drivers/gpu/drm/i915/gt/selftest_slpc.c
@@ -489,7 +489,7 @@ static int live_slpc_tile_interaction(void *arg)
return -ENOMEM;
for_each_gt(gt, i915, i) {
- threads[i].worker = kthread_create_worker(0, "igt/slpc_parallel:%d", gt->info.id);
+ threads[i].worker = kthread_run_worker(0, "igt/slpc_parallel:%d", gt->info.id);
if (IS_ERR(threads[i].worker)) {
ret = PTR_ERR(threads[i].worker);
diff --git a/drivers/gpu/drm/i915/selftests/i915_request.c b/drivers/gpu/drm/i915/selftests/i915_request.c
index acae30a04a94..88870844b5bd 100644
--- a/drivers/gpu/drm/i915/selftests/i915_request.c
+++ b/drivers/gpu/drm/i915/selftests/i915_request.c
@@ -492,7 +492,7 @@ static int mock_breadcrumbs_smoketest(void *arg)
for (n = 0; n < ncpus; n++) {
struct kthread_worker *worker;
- worker = kthread_create_worker(0, "igt/%d", n);
+ worker = kthread_run_worker(0, "igt/%d", n);
if (IS_ERR(worker)) {
ret = PTR_ERR(worker);
ncpus = n;
@@ -1645,7 +1645,7 @@ static int live_parallel_engines(void *arg)
for_each_uabi_engine(engine, i915) {
struct kthread_worker *worker;
- worker = kthread_create_worker(0, "igt/parallel:%s",
+ worker = kthread_run_worker(0, "igt/parallel:%s",
engine->name);
if (IS_ERR(worker)) {
err = PTR_ERR(worker);
@@ -1806,7 +1806,7 @@ static int live_breadcrumbs_smoketest(void *arg)
unsigned int i = idx * ncpus + n;
struct kthread_worker *worker;
- worker = kthread_create_worker(0, "igt/%d.%d", idx, n);
+ worker = kthread_run_worker(0, "igt/%d.%d", idx, n);
if (IS_ERR(worker)) {
ret = PTR_ERR(worker);
goto out_flush;
@@ -3219,7 +3219,7 @@ static int perf_parallel_engines(void *arg)
memset(&engines[idx].p, 0, sizeof(engines[idx].p));
- worker = kthread_create_worker(0, "igt:%s",
+ worker = kthread_run_worker(0, "igt:%s",
engine->name);
if (IS_ERR(worker)) {
err = PTR_ERR(worker);
diff --git a/drivers/gpu/drm/msm/disp/msm_disp_snapshot.c b/drivers/gpu/drm/msm/disp/msm_disp_snapshot.c
index e75b97127c0d..2be00b11e557 100644
--- a/drivers/gpu/drm/msm/disp/msm_disp_snapshot.c
+++ b/drivers/gpu/drm/msm/disp/msm_disp_snapshot.c
@@ -109,7 +109,7 @@ int msm_disp_snapshot_init(struct drm_device *drm_dev)
mutex_init(&kms->dump_mutex);
- kms->dump_worker = kthread_create_worker(0, "%s", "disp_snapshot");
+ kms->dump_worker = kthread_run_worker(0, "%s", "disp_snapshot");
if (IS_ERR(kms->dump_worker))
DRM_ERROR("failed to create disp state task\n");
diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c
index 9c45d641b521..a7a2384044ff 100644
--- a/drivers/gpu/drm/msm/msm_atomic.c
+++ b/drivers/gpu/drm/msm/msm_atomic.c
@@ -115,7 +115,7 @@ int msm_atomic_init_pending_timer(struct msm_pending_timer *timer,
timer->kms = kms;
timer->crtc_idx = crtc_idx;
- timer->worker = kthread_create_worker(0, "atomic-worker-%d", crtc_idx);
+ timer->worker = kthread_run_worker(0, "atomic-worker-%d", crtc_idx);
if (IS_ERR(timer->worker)) {
int ret = PTR_ERR(timer->worker);
timer->worker = NULL;
diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c
index cd185b9636d2..5ce4f76ada53 100644
--- a/drivers/gpu/drm/msm/msm_gpu.c
+++ b/drivers/gpu/drm/msm/msm_gpu.c
@@ -857,7 +857,7 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
gpu->funcs = funcs;
gpu->name = name;
- gpu->worker = kthread_create_worker(0, "gpu-worker");
+ gpu->worker = kthread_run_worker(0, "gpu-worker");
if (IS_ERR(gpu->worker)) {
ret = PTR_ERR(gpu->worker);
gpu->worker = NULL;
diff --git a/drivers/gpu/drm/msm/msm_kms.c b/drivers/gpu/drm/msm/msm_kms.c
index af6a6fcb1173..8db9f3afb8ac 100644
--- a/drivers/gpu/drm/msm/msm_kms.c
+++ b/drivers/gpu/drm/msm/msm_kms.c
@@ -269,7 +269,7 @@ int msm_drm_kms_init(struct device *dev, const struct drm_driver *drv)
/* initialize event thread */
ev_thread = &priv->event_thread[drm_crtc_index(crtc)];
ev_thread->dev = ddev;
- ev_thread->worker = kthread_create_worker(0, "crtc_event:%d", crtc->base.id);
+ ev_thread->worker = kthread_run_worker(0, "crtc_event:%d", crtc->base.id);
if (IS_ERR(ev_thread->worker)) {
ret = PTR_ERR(ev_thread->worker);
DRM_DEV_ERROR(dev, "failed to create crtc_event kthread\n");
diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu.c b/drivers/media/platform/chips-media/wave5/wave5-vpu.c
index 68a519ac412d..0530954563c5 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-vpu.c
+++ b/drivers/media/platform/chips-media/wave5/wave5-vpu.c
@@ -218,7 +218,7 @@ static int wave5_vpu_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "failed to get irq resource, falling back to polling\n");
hrtimer_init(&dev->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED);
dev->hrtimer.function = &wave5_vpu_timer_callback;
- dev->worker = kthread_create_worker(0, "vpu_irq_thread");
+ dev->worker = kthread_run_worker(0, "vpu_irq_thread");
if (IS_ERR(dev->worker)) {
dev_err(&pdev->dev, "failed to create vpu irq worker\n");
ret = PTR_ERR(dev->worker);
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 07c897b13de1..9df4d113af35 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -393,7 +393,7 @@ static int mv88e6xxx_irq_poll_setup(struct mv88e6xxx_chip *chip)
kthread_init_delayed_work(&chip->irq_poll_work,
mv88e6xxx_irq_poll);
- chip->kworker = kthread_create_worker(0, "%s", dev_name(chip->dev));
+ chip->kworker = kthread_run_worker(0, "%s", dev_name(chip->dev));
if (IS_ERR(chip->kworker))
return PTR_ERR(chip->kworker);
diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c
index e92be6f130a3..f065a1dc0414 100644
--- a/drivers/net/ethernet/intel/ice/ice_dpll.c
+++ b/drivers/net/ethernet/intel/ice/ice_dpll.c
@@ -1833,7 +1833,7 @@ static int ice_dpll_init_worker(struct ice_pf *pf)
struct kthread_worker *kworker;
kthread_init_delayed_work(&d->work, ice_dpll_periodic_work);
- kworker = kthread_create_worker(0, "ice-dplls-%s",
+ kworker = kthread_run_worker(0, "ice-dplls-%s",
dev_name(ice_pf_to_dev(pf)));
if (IS_ERR(kworker))
return PTR_ERR(kworker);
diff --git a/drivers/net/ethernet/intel/ice/ice_gnss.c b/drivers/net/ethernet/intel/ice/ice_gnss.c
index c8ea1af51ad3..fcd1f808b696 100644
--- a/drivers/net/ethernet/intel/ice/ice_gnss.c
+++ b/drivers/net/ethernet/intel/ice/ice_gnss.c
@@ -182,7 +182,7 @@ static struct gnss_serial *ice_gnss_struct_init(struct ice_pf *pf)
pf->gnss_serial = gnss;
kthread_init_delayed_work(&gnss->read_work, ice_gnss_read);
- kworker = kthread_create_worker(0, "ice-gnss-%s", dev_name(dev));
+ kworker = kthread_run_worker(0, "ice-gnss-%s", dev_name(dev));
if (IS_ERR(kworker)) {
kfree(gnss);
return NULL;
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c
index fefaf52fd677..d6663876c721 100644
--- a/drivers/net/ethernet/intel/ice/ice_ptp.c
+++ b/drivers/net/ethernet/intel/ice/ice_ptp.c
@@ -3121,7 +3121,7 @@ static int ice_ptp_init_work(struct ice_pf *pf, struct ice_ptp *ptp)
/* Allocate a kworker for handling work required for the ports
* connected to the PTP hardware clock.
*/
- kworker = kthread_create_worker(0, "ice-ptp-%s",
+ kworker = kthread_run_worker(0, "ice-ptp-%s",
dev_name(ice_pf_to_dev(pf)));
if (IS_ERR(kworker))
return PTR_ERR(kworker);
diff --git a/drivers/platform/chrome/cros_ec_spi.c b/drivers/platform/chrome/cros_ec_spi.c
index 86a3d32a7763..08f566cc1480 100644
--- a/drivers/platform/chrome/cros_ec_spi.c
+++ b/drivers/platform/chrome/cros_ec_spi.c
@@ -715,7 +715,7 @@ static int cros_ec_spi_devm_high_pri_alloc(struct device *dev,
int err;
ec_spi->high_pri_worker =
- kthread_create_worker(0, "cros_ec_spi_high_pri");
+ kthread_run_worker(0, "cros_ec_spi_high_pri");
if (IS_ERR(ec_spi->high_pri_worker)) {
err = PTR_ERR(ec_spi->high_pri_worker);
diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c
index c56cd0f63909..89a4420972e7 100644
--- a/drivers/ptp/ptp_clock.c
+++ b/drivers/ptp/ptp_clock.c
@@ -295,7 +295,7 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info,
if (ptp->info->do_aux_work) {
kthread_init_delayed_work(&ptp->aux_work, ptp_aux_kworker);
- ptp->kworker = kthread_create_worker(0, "ptp%d", ptp->index);
+ ptp->kworker = kthread_run_worker(0, "ptp%d", ptp->index);
if (IS_ERR(ptp->kworker)) {
err = PTR_ERR(ptp->kworker);
pr_err("failed to create ptp aux_worker %d\n", err);
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index fc13fa192189..0a4b9b634631 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -2072,7 +2072,7 @@ static int spi_init_queue(struct spi_controller *ctlr)
ctlr->busy = false;
ctlr->queue_empty = true;
- ctlr->kworker = kthread_create_worker(0, dev_name(&ctlr->dev));
+ ctlr->kworker = kthread_run_worker(0, dev_name(&ctlr->dev));
if (IS_ERR(ctlr->kworker)) {
dev_err(&ctlr->dev, "failed to create message pump kworker\n");
return PTR_ERR(ctlr->kworker);
diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
index 5d4da962acc8..81ca212ed495 100644
--- a/drivers/usb/typec/tcpm/tcpm.c
+++ b/drivers/usb/typec/tcpm/tcpm.c
@@ -7558,7 +7558,7 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)
mutex_init(&port->lock);
mutex_init(&port->swap_lock);
- port->wq = kthread_create_worker(0, dev_name(dev));
+ port->wq = kthread_run_worker(0, dev_name(dev));
if (IS_ERR(port->wq))
return ERR_CAST(port->wq);
sched_set_fifo(port->wq->task);
diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim.c b/drivers/vdpa/vdpa_sim/vdpa_sim.c
index 8ffea8430f95..c204fc8e471a 100644
--- a/drivers/vdpa/vdpa_sim/vdpa_sim.c
+++ b/drivers/vdpa/vdpa_sim/vdpa_sim.c
@@ -229,7 +229,7 @@ struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *dev_attr,
dev = &vdpasim->vdpa.dev;
kthread_init_work(&vdpasim->work, vdpasim_work_fn);
- vdpasim->worker = kthread_create_worker(0, "vDPA sim worker: %s",
+ vdpasim->worker = kthread_run_worker(0, "vDPA sim worker: %s",
dev_attr->name);
if (IS_ERR(vdpasim->worker))
goto err_iommu;
diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c
index e2bd266b1b5b..ed4566997459 100644
--- a/drivers/watchdog/watchdog_dev.c
+++ b/drivers/watchdog/watchdog_dev.c
@@ -1229,7 +1229,7 @@ int __init watchdog_dev_init(void)
{
int err;
- watchdog_kworker = kthread_create_worker(0, "watchdogd");
+ watchdog_kworker = kthread_run_worker(0, "watchdogd");
if (IS_ERR(watchdog_kworker)) {
pr_err("Failed to create watchdog kworker\n");
return PTR_ERR(watchdog_kworker);
diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c
index f1ccdf47585b..cf108812c284 100644
--- a/fs/erofs/zdata.c
+++ b/fs/erofs/zdata.c
@@ -356,7 +356,7 @@ static void erofs_destroy_percpu_workers(void)
static struct kthread_worker *erofs_init_percpu_worker(int cpu)
{
struct kthread_worker *worker =
- kthread_create_worker_on_cpu(cpu, 0, "erofs_worker/%u");
+ kthread_run_worker_on_cpu(cpu, 0, "erofs_worker/%u");
if (IS_ERR(worker))
return worker;
diff --git a/include/linux/kthread.h b/include/linux/kthread.h
index 0c66e7c1092a..8d27403888ce 100644
--- a/include/linux/kthread.h
+++ b/include/linux/kthread.h
@@ -193,19 +193,53 @@ struct kthread_worker *kthread_create_worker_on_node(unsigned int flags,
const char namefmt[], ...);
#define kthread_create_worker(flags, namefmt, ...) \
-({ \
- struct kthread_worker *__kw \
- = kthread_create_worker_on_node(flags, NUMA_NO_NODE, \
- namefmt, ## __VA_ARGS__); \
- if (!IS_ERR(__kw)) \
- wake_up_process(__kw->task); \
- __kw; \
+ kthread_create_worker_on_node(flags, NUMA_NO_NODE, namefmt, ## __VA_ARGS__);
+
+/**
+ * kthread_run_worker - create and wake a kthread worker.
+ * @flags: flags modifying the default behavior of the worker
+ * @namefmt: printf-style name for the thread.
+ *
+ * Description: Convenient wrapper for kthread_create_worker() followed by
+ * wake_up_process(). Returns the kthread_worker or ERR_PTR(-ENOMEM).
+ */
+#define kthread_run_worker(flags, namefmt, ...) \
+({ \
+ struct kthread_worker *__kw \
+ = kthread_create_worker(flags, namefmt, ## __VA_ARGS__); \
+ if (!IS_ERR(__kw)) \
+ wake_up_process(__kw->task); \
+ __kw; \
})
struct kthread_worker *
kthread_create_worker_on_cpu(int cpu, unsigned int flags,
const char namefmt[]);
+/**
+ * kthread_run_worker_on_cpu - create and wake a cpu bound kthread worker.
+ * @cpu: CPU number
+ * @flags: flags modifying the default behavior of the worker
+ * @namefmt: printf-style name for the thread. Format is restricted
+ * to "name.*%u". Code fills in cpu number.
+ *
+ * Description: Convenient wrapper for kthread_create_worker_on_cpu()
+ * followed by wake_up_process(). Returns the kthread_worker or
+ * ERR_PTR(-ENOMEM).
+ */
+static inline struct kthread_worker *
+kthread_run_worker_on_cpu(int cpu, unsigned int flags,
+ const char namefmt[])
+{
+ struct kthread_worker *kw;
+
+ kw = kthread_create_worker_on_cpu(cpu, flags, namefmt);
+ if (!IS_ERR(kw))
+ wake_up_process(kw->task);
+
+ return kw;
+}
+
bool kthread_queue_work(struct kthread_worker *worker,
struct kthread_work *work);
diff --git a/kernel/kthread.c b/kernel/kthread.c
index 34b11dbfc756..379ebe7a217d 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -1030,33 +1030,10 @@ kthread_create_worker_on_node(unsigned int flags, int node, const char namefmt[]
worker = __kthread_create_worker_on_node(flags, node, namefmt, args);
va_end(args);
- if (worker)
- wake_up_process(worker->task);
-
return worker;
}
EXPORT_SYMBOL(kthread_create_worker_on_node);
-static __printf(3, 4) struct kthread_worker *
-__kthread_create_worker_on_cpu(int cpu, unsigned int flags,
- const char namefmt[], ...)
-{
- struct kthread_worker *worker;
- va_list args;
-
- va_start(args, namefmt);
- worker = __kthread_create_worker_on_node(flags, cpu_to_node(cpu),
- namefmt, args);
- va_end(args);
-
- if (worker) {
- kthread_bind(worker->task, cpu);
- wake_up_process(worker->task);
- }
-
- return worker;
-}
-
/**
* kthread_create_worker_on_cpu - create a kthread worker and bind it
* to a given CPU and the associated NUMA node.
@@ -1097,7 +1074,13 @@ struct kthread_worker *
kthread_create_worker_on_cpu(int cpu, unsigned int flags,
const char namefmt[])
{
- return __kthread_create_worker_on_cpu(cpu, flags, namefmt, cpu);
+ struct kthread_worker *worker;
+
+ worker = kthread_create_worker_on_node(flags, cpu_to_node(cpu), namefmt, cpu);
+ if (worker)
+ kthread_bind(worker->task, cpu);
+
+ return worker;
}
EXPORT_SYMBOL(kthread_create_worker_on_cpu);
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
index 6ff87a3e000b..e038f4abb872 100644
--- a/kernel/rcu/tree.c
+++ b/kernel/rcu/tree.c
@@ -4789,7 +4789,7 @@ static void rcu_spawn_exp_par_gp_kworker(struct rcu_node *rnp)
if (rnp->exp_kworker)
return;
- kworker = kthread_create_worker(0, name, rnp_index);
+ kworker = kthread_run_worker(0, name, rnp_index);
if (IS_ERR_OR_NULL(kworker)) {
pr_err("Failed to create par gp kworker on %d/%d\n",
rnp->grplo, rnp->grphi);
@@ -4816,7 +4816,7 @@ static void __init rcu_start_exp_gp_kworker(void)
const char *name = "rcu_exp_gp_kthread_worker";
struct sched_param param = { .sched_priority = kthread_prio };
- rcu_exp_gp_kworker = kthread_create_worker(0, name);
+ rcu_exp_gp_kworker = kthread_run_worker(0, name);
if (IS_ERR_OR_NULL(rcu_exp_gp_kworker)) {
pr_err("Failed to create %s!\n", name);
rcu_exp_gp_kworker = NULL;
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 3fbaecfc88c2..79229136c2b2 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -7789,7 +7789,7 @@ static void __init wq_cpu_intensive_thresh_init(void)
unsigned long thresh;
unsigned long bogo;
- pwq_release_worker = kthread_create_worker(0, "pool_workqueue_release");
+ pwq_release_worker = kthread_run_worker(0, "pool_workqueue_release");
BUG_ON(IS_ERR(pwq_release_worker));
/* if the user set it to a specific value, keep it */
diff --git a/net/dsa/tag_ksz.c b/net/dsa/tag_ksz.c
index ee7b272ab715..f21f2711921f 100644
--- a/net/dsa/tag_ksz.c
+++ b/net/dsa/tag_ksz.c
@@ -66,7 +66,7 @@ static int ksz_connect(struct dsa_switch *ds)
if (!priv)
return -ENOMEM;
- xmit_worker = kthread_create_worker(0, "dsa%d:%d_xmit",
+ xmit_worker = kthread_run_worker(0, "dsa%d:%d_xmit",
ds->dst->index, ds->index);
if (IS_ERR(xmit_worker)) {
ret = PTR_ERR(xmit_worker);
diff --git a/net/dsa/tag_ocelot_8021q.c b/net/dsa/tag_ocelot_8021q.c
index b059381310fe..8953add48d33 100644
--- a/net/dsa/tag_ocelot_8021q.c
+++ b/net/dsa/tag_ocelot_8021q.c
@@ -110,7 +110,7 @@ static int ocelot_connect(struct dsa_switch *ds)
if (!priv)
return -ENOMEM;
- priv->xmit_worker = kthread_create_worker(0, "felix_xmit");
+ priv->xmit_worker = kthread_run_worker(0, "felix_xmit");
if (IS_ERR(priv->xmit_worker)) {
err = PTR_ERR(priv->xmit_worker);
kfree(priv);
diff --git a/net/dsa/tag_sja1105.c b/net/dsa/tag_sja1105.c
index 1aba1d05c27a..d3d7b119babc 100644
--- a/net/dsa/tag_sja1105.c
+++ b/net/dsa/tag_sja1105.c
@@ -755,7 +755,7 @@ static int sja1105_connect(struct dsa_switch *ds)
spin_lock_init(&priv->meta_lock);
- xmit_worker = kthread_create_worker(0, "dsa%d:%d_xmit",
+ xmit_worker = kthread_run_worker(0, "dsa%d:%d_xmit",
ds->dst->index, ds->index);
if (IS_ERR(xmit_worker)) {
err = PTR_ERR(xmit_worker);
--
2.45.2
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [RFC PATCH 20/20] rcu: Use kthread preferred affinity for RCU exp kworkers
[not found] <20240726215701.19459-1-frederic@kernel.org>
` (4 preceding siblings ...)
2024-07-26 21:56 ` [RFC PATCH 19/20] treewide: Introduce kthread_run_worker[_on_cpu]() Frederic Weisbecker
@ 2024-07-26 21:56 ` Frederic Weisbecker
2024-07-26 22:40 ` Paul E. McKenney
5 siblings, 1 reply; 16+ messages in thread
From: Frederic Weisbecker @ 2024-07-26 21:56 UTC (permalink / raw)
To: LKML
Cc: Frederic Weisbecker, Paul E. McKenney, Neeraj Upadhyay,
Joel Fernandes, Boqun Feng, Zqiang, rcu, Andrew Morton,
Peter Zijlstra, Thomas Gleixner
Now that kthreads have an infrastructure to handle preferred affinity
against CPU hotplug and housekeeping cpumask, convert RCU exp workers to
use it instead of handling all the constraints by itself.
Signed-off-by: Frederic Weisbecker <frederic@kernel.org>
---
kernel/rcu/tree.c | 105 +++++++++-------------------------------------
1 file changed, 19 insertions(+), 86 deletions(-)
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
index e038f4abb872..f3e40a1dea65 100644
--- a/kernel/rcu/tree.c
+++ b/kernel/rcu/tree.c
@@ -4777,6 +4777,22 @@ rcu_boot_init_percpu_data(int cpu)
rcu_boot_init_nocb_percpu_data(rdp);
}
+static void rcu_thread_affine_rnp(struct task_struct *t, struct rcu_node *rnp)
+{
+ cpumask_var_t affinity;
+ int cpu;
+
+ if (!zalloc_cpumask_var(&affinity, GFP_KERNEL))
+ return;
+
+ for_each_leaf_node_possible_cpu(rnp, cpu)
+ cpumask_set_cpu(cpu, affinity);
+
+ kthread_affine_preferred(t, affinity);
+
+ free_cpumask_var(affinity);
+}
+
struct kthread_worker *rcu_exp_gp_kworker;
static void rcu_spawn_exp_par_gp_kworker(struct rcu_node *rnp)
@@ -4789,7 +4805,7 @@ static void rcu_spawn_exp_par_gp_kworker(struct rcu_node *rnp)
if (rnp->exp_kworker)
return;
- kworker = kthread_run_worker(0, name, rnp_index);
+ kworker = kthread_create_worker(0, name, rnp_index);
if (IS_ERR_OR_NULL(kworker)) {
pr_err("Failed to create par gp kworker on %d/%d\n",
rnp->grplo, rnp->grphi);
@@ -4799,16 +4815,9 @@ static void rcu_spawn_exp_par_gp_kworker(struct rcu_node *rnp)
if (IS_ENABLED(CONFIG_RCU_EXP_KTHREAD))
sched_setscheduler_nocheck(kworker->task, SCHED_FIFO, ¶m);
-}
-static struct task_struct *rcu_exp_par_gp_task(struct rcu_node *rnp)
-{
- struct kthread_worker *kworker = READ_ONCE(rnp->exp_kworker);
-
- if (!kworker)
- return NULL;
-
- return kworker->task;
+ rcu_thread_affine_rnp(kworker->task, rnp);
+ wake_up_process(kworker->task);
}
static void __init rcu_start_exp_gp_kworker(void)
@@ -4893,79 +4902,6 @@ int rcutree_prepare_cpu(unsigned int cpu)
return 0;
}
-static void rcu_thread_affine_rnp(struct task_struct *t, struct rcu_node *rnp)
-{
- cpumask_var_t affinity;
- int cpu;
-
- if (!zalloc_cpumask_var(&affinity, GFP_KERNEL))
- return;
-
- for_each_leaf_node_possible_cpu(rnp, cpu)
- cpumask_set_cpu(cpu, affinity);
-
- kthread_affine_preferred(t, affinity);
-
- free_cpumask_var(affinity);
-}
-
-/*
- * Update kthreads affinity during CPU-hotplug changes.
- *
- * Set the per-rcu_node kthread's affinity to cover all CPUs that are
- * served by the rcu_node in question. The CPU hotplug lock is still
- * held, so the value of rnp->qsmaskinit will be stable.
- *
- * We don't include outgoingcpu in the affinity set, use -1 if there is
- * no outgoing CPU. If there are no CPUs left in the affinity set,
- * this function allows the kthread to execute on any CPU.
- *
- * Any future concurrent calls are serialized via ->kthread_mutex.
- */
-static void rcutree_affinity_setting(unsigned int cpu, int outgoingcpu)
-{
- cpumask_var_t cm;
- unsigned long mask;
- struct rcu_data *rdp;
- struct rcu_node *rnp;
- struct task_struct *task_exp;
-
- rdp = per_cpu_ptr(&rcu_data, cpu);
- rnp = rdp->mynode;
-
- task_exp = rcu_exp_par_gp_task(rnp);
-
- /*
- * If CPU is the boot one, this task is created later from early
- * initcall since kthreadd must be created first.
- */
- if (!task_exp)
- return;
-
- if (!zalloc_cpumask_var(&cm, GFP_KERNEL))
- return;
-
- mutex_lock(&rnp->kthread_mutex);
- mask = rcu_rnp_online_cpus(rnp);
- for_each_leaf_node_possible_cpu(rnp, cpu)
- if ((mask & leaf_node_cpu_bit(rnp, cpu)) &&
- cpu != outgoingcpu)
- cpumask_set_cpu(cpu, cm);
- cpumask_and(cm, cm, housekeeping_cpumask(HK_TYPE_RCU));
- if (cpumask_empty(cm)) {
- cpumask_copy(cm, housekeeping_cpumask(HK_TYPE_RCU));
- if (outgoingcpu >= 0)
- cpumask_clear_cpu(outgoingcpu, cm);
- }
-
- if (task_exp)
- set_cpus_allowed_ptr(task_exp, cm);
-
- mutex_unlock(&rnp->kthread_mutex);
-
- free_cpumask_var(cm);
-}
-
/*
* Has the specified (known valid) CPU ever been fully online?
*/
@@ -4994,7 +4930,6 @@ int rcutree_online_cpu(unsigned int cpu)
if (rcu_scheduler_active == RCU_SCHEDULER_INACTIVE)
return 0; /* Too early in boot for scheduler work. */
sync_sched_exp_online_cleanup(cpu);
- rcutree_affinity_setting(cpu, -1);
// Stop-machine done, so allow nohz_full to disable tick.
tick_dep_clear(TICK_DEP_BIT_RCU);
@@ -5207,8 +5142,6 @@ int rcutree_offline_cpu(unsigned int cpu)
rnp->ffmask &= ~rdp->grpmask;
raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
- rcutree_affinity_setting(cpu, cpu);
-
// nohz_full CPUs need the tick for stop-machine to work quickly
tick_dep_set(TICK_DEP_BIT_RCU);
return 0;
--
2.45.2
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [RFC PATCH 12/20] kthread: Implement preferred affinity
2024-07-26 21:56 ` [RFC PATCH 12/20] kthread: Implement preferred affinity Frederic Weisbecker
@ 2024-07-26 22:31 ` Frederic Weisbecker
2024-07-30 15:49 ` Vlastimil Babka
1 sibling, 0 replies; 16+ messages in thread
From: Frederic Weisbecker @ 2024-07-26 22:31 UTC (permalink / raw)
To: LKML
Cc: Andrew Morton, Kees Cook, Peter Zijlstra, Thomas Gleixner,
Michal Hocko, Vlastimil Babka, linux-mm, Paul E. McKenney,
Neeraj Upadhyay, Joel Fernandes, Boqun Feng, Zqiang, rcu
Le Fri, Jul 26, 2024 at 11:56:48PM +0200, Frederic Weisbecker a écrit :
> +int kthread_affine_preferred(struct task_struct *p, const struct cpumask *mask)
> +{
> + struct kthread *kthread = to_kthread(p);
> + cpumask_var_t affinity;
> + unsigned long flags;
> + int ret;
> +
> + if (!wait_task_inactive(p, TASK_UNINTERRUPTIBLE) || kthread->started) {
> + WARN_ON(1);
> + return -EINVAL;
> + }
> +
> + if (!zalloc_cpumask_var(&affinity, GFP_KERNEL))
> + return -ENOMEM;
> +
> + kthread->preferred_affinity = kzalloc(sizeof(struct cpumask), GFP_KERNEL);
> + if (!kthread->preferred_affinity) {
> + ret = -ENOMEM;
> + goto out;
> + }
> +
> + mutex_lock(&kthreads_hotplug_lock);
> + cpumask_copy(kthread->preferred_affinity, mask);
> + list_add_tail(&kthread->hotplug_node, &kthreads_hotplug);
> + kthread_fetch_affinity(kthread, affinity);
> +
> + /* It's safe because the task is inactive. */
> + raw_spin_lock_irqsave(&p->pi_lock, flags);
> + do_set_cpus_allowed(p, mask);
s/mask/affinity
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [RFC PATCH 20/20] rcu: Use kthread preferred affinity for RCU exp kworkers
2024-07-26 21:56 ` [RFC PATCH 20/20] rcu: Use kthread preferred affinity for RCU exp kworkers Frederic Weisbecker
@ 2024-07-26 22:40 ` Paul E. McKenney
0 siblings, 0 replies; 16+ messages in thread
From: Paul E. McKenney @ 2024-07-26 22:40 UTC (permalink / raw)
To: Frederic Weisbecker
Cc: LKML, Neeraj Upadhyay, Joel Fernandes, Boqun Feng, Zqiang, rcu,
Andrew Morton, Peter Zijlstra, Thomas Gleixner
On Fri, Jul 26, 2024 at 11:56:56PM +0200, Frederic Weisbecker wrote:
> Now that kthreads have an infrastructure to handle preferred affinity
> against CPU hotplug and housekeeping cpumask, convert RCU exp workers to
> use it instead of handling all the constraints by itself.
>
> Signed-off-by: Frederic Weisbecker <frederic@kernel.org>
Nice consolidation of troublesome code!
For this one and 17/20:
Acked-by: Paul E. McKenney <paulmck@kernel.org>
> ---
> kernel/rcu/tree.c | 105 +++++++++-------------------------------------
> 1 file changed, 19 insertions(+), 86 deletions(-)
>
> diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
> index e038f4abb872..f3e40a1dea65 100644
> --- a/kernel/rcu/tree.c
> +++ b/kernel/rcu/tree.c
> @@ -4777,6 +4777,22 @@ rcu_boot_init_percpu_data(int cpu)
> rcu_boot_init_nocb_percpu_data(rdp);
> }
>
> +static void rcu_thread_affine_rnp(struct task_struct *t, struct rcu_node *rnp)
> +{
> + cpumask_var_t affinity;
> + int cpu;
> +
> + if (!zalloc_cpumask_var(&affinity, GFP_KERNEL))
> + return;
> +
> + for_each_leaf_node_possible_cpu(rnp, cpu)
> + cpumask_set_cpu(cpu, affinity);
> +
> + kthread_affine_preferred(t, affinity);
> +
> + free_cpumask_var(affinity);
> +}
> +
> struct kthread_worker *rcu_exp_gp_kworker;
>
> static void rcu_spawn_exp_par_gp_kworker(struct rcu_node *rnp)
> @@ -4789,7 +4805,7 @@ static void rcu_spawn_exp_par_gp_kworker(struct rcu_node *rnp)
> if (rnp->exp_kworker)
> return;
>
> - kworker = kthread_run_worker(0, name, rnp_index);
> + kworker = kthread_create_worker(0, name, rnp_index);
> if (IS_ERR_OR_NULL(kworker)) {
> pr_err("Failed to create par gp kworker on %d/%d\n",
> rnp->grplo, rnp->grphi);
> @@ -4799,16 +4815,9 @@ static void rcu_spawn_exp_par_gp_kworker(struct rcu_node *rnp)
>
> if (IS_ENABLED(CONFIG_RCU_EXP_KTHREAD))
> sched_setscheduler_nocheck(kworker->task, SCHED_FIFO, ¶m);
> -}
>
> -static struct task_struct *rcu_exp_par_gp_task(struct rcu_node *rnp)
> -{
> - struct kthread_worker *kworker = READ_ONCE(rnp->exp_kworker);
> -
> - if (!kworker)
> - return NULL;
> -
> - return kworker->task;
> + rcu_thread_affine_rnp(kworker->task, rnp);
> + wake_up_process(kworker->task);
> }
>
> static void __init rcu_start_exp_gp_kworker(void)
> @@ -4893,79 +4902,6 @@ int rcutree_prepare_cpu(unsigned int cpu)
> return 0;
> }
>
> -static void rcu_thread_affine_rnp(struct task_struct *t, struct rcu_node *rnp)
> -{
> - cpumask_var_t affinity;
> - int cpu;
> -
> - if (!zalloc_cpumask_var(&affinity, GFP_KERNEL))
> - return;
> -
> - for_each_leaf_node_possible_cpu(rnp, cpu)
> - cpumask_set_cpu(cpu, affinity);
> -
> - kthread_affine_preferred(t, affinity);
> -
> - free_cpumask_var(affinity);
> -}
> -
> -/*
> - * Update kthreads affinity during CPU-hotplug changes.
> - *
> - * Set the per-rcu_node kthread's affinity to cover all CPUs that are
> - * served by the rcu_node in question. The CPU hotplug lock is still
> - * held, so the value of rnp->qsmaskinit will be stable.
> - *
> - * We don't include outgoingcpu in the affinity set, use -1 if there is
> - * no outgoing CPU. If there are no CPUs left in the affinity set,
> - * this function allows the kthread to execute on any CPU.
> - *
> - * Any future concurrent calls are serialized via ->kthread_mutex.
> - */
> -static void rcutree_affinity_setting(unsigned int cpu, int outgoingcpu)
> -{
> - cpumask_var_t cm;
> - unsigned long mask;
> - struct rcu_data *rdp;
> - struct rcu_node *rnp;
> - struct task_struct *task_exp;
> -
> - rdp = per_cpu_ptr(&rcu_data, cpu);
> - rnp = rdp->mynode;
> -
> - task_exp = rcu_exp_par_gp_task(rnp);
> -
> - /*
> - * If CPU is the boot one, this task is created later from early
> - * initcall since kthreadd must be created first.
> - */
> - if (!task_exp)
> - return;
> -
> - if (!zalloc_cpumask_var(&cm, GFP_KERNEL))
> - return;
> -
> - mutex_lock(&rnp->kthread_mutex);
> - mask = rcu_rnp_online_cpus(rnp);
> - for_each_leaf_node_possible_cpu(rnp, cpu)
> - if ((mask & leaf_node_cpu_bit(rnp, cpu)) &&
> - cpu != outgoingcpu)
> - cpumask_set_cpu(cpu, cm);
> - cpumask_and(cm, cm, housekeeping_cpumask(HK_TYPE_RCU));
> - if (cpumask_empty(cm)) {
> - cpumask_copy(cm, housekeeping_cpumask(HK_TYPE_RCU));
> - if (outgoingcpu >= 0)
> - cpumask_clear_cpu(outgoingcpu, cm);
> - }
> -
> - if (task_exp)
> - set_cpus_allowed_ptr(task_exp, cm);
> -
> - mutex_unlock(&rnp->kthread_mutex);
> -
> - free_cpumask_var(cm);
> -}
> -
> /*
> * Has the specified (known valid) CPU ever been fully online?
> */
> @@ -4994,7 +4930,6 @@ int rcutree_online_cpu(unsigned int cpu)
> if (rcu_scheduler_active == RCU_SCHEDULER_INACTIVE)
> return 0; /* Too early in boot for scheduler work. */
> sync_sched_exp_online_cleanup(cpu);
> - rcutree_affinity_setting(cpu, -1);
>
> // Stop-machine done, so allow nohz_full to disable tick.
> tick_dep_clear(TICK_DEP_BIT_RCU);
> @@ -5207,8 +5142,6 @@ int rcutree_offline_cpu(unsigned int cpu)
> rnp->ffmask &= ~rdp->grpmask;
> raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
>
> - rcutree_affinity_setting(cpu, cpu);
> -
> // nohz_full CPUs need the tick for stop-machine to work quickly
> tick_dep_set(TICK_DEP_BIT_RCU);
> return 0;
> --
> 2.45.2
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [RFC PATCH 11/20] kthread: Make sure kthread hasn't started while binding it
2024-07-26 21:56 ` [RFC PATCH 11/20] kthread: Make sure kthread hasn't started while binding it Frederic Weisbecker
@ 2024-07-30 15:20 ` Vlastimil Babka
0 siblings, 0 replies; 16+ messages in thread
From: Vlastimil Babka @ 2024-07-30 15:20 UTC (permalink / raw)
To: Frederic Weisbecker, LKML
Cc: Andrew Morton, Kees Cook, Peter Zijlstra, Thomas Gleixner,
Michal Hocko, linux-mm, Paul E. McKenney, Neeraj Upadhyay,
Joel Fernandes, Boqun Feng, Zqiang, rcu
On 7/26/24 11:56 PM, Frederic Weisbecker wrote:
> Make sure the kthread is sleeping in the schedule_preempt_disabled()
> call before calling its handler when kthread_bind[_mask]() is called
> on it. This provides a sanity check verifying that the task is not
> randomly blocked later at some point within its function handler, in
> which case it could be just concurrently awaken, leaving the call to
> do_set_cpus_allowed() without any effect until the next voluntary sleep.
>
> Rely on the wake-up ordering to ensure that the newly introduced "started"
> field returns the expected value:
>
> TASK A TASK B
> ------ ------
> READ kthread->started
> wake_up_process(B)
> rq_lock()
> ...
> rq_unlock() // RELEASE
> schedule()
> rq_lock() // ACQUIRE
> // schedule task B
> rq_unlock()
> WRITE kthread->started
>
> Similarly, writing kthread->started before subsequent voluntary sleeps
> will be visible after calling wait_task_inactive() in
> __kthread_bind_mask(), reporting potential misuse of the API.
>
> Upcoming patches will make further use of this facility.
>
> Signed-off-by: Frederic Weisbecker <frederic@kernel.org>
Acked-by: Vlastimil Babka <vbabka@suse.cz>
> ---
> kernel/kthread.c | 7 +++++++
> 1 file changed, 7 insertions(+)
>
> diff --git a/kernel/kthread.c b/kernel/kthread.c
> index f7be976ff88a..ecb719f54f7a 100644
> --- a/kernel/kthread.c
> +++ b/kernel/kthread.c
> @@ -53,6 +53,7 @@ struct kthread_create_info
> struct kthread {
> unsigned long flags;
> unsigned int cpu;
> + int started;
> int result;
> int (*threadfn)(void *);
> void *data;
> @@ -382,6 +383,8 @@ static int kthread(void *_create)
> schedule_preempt_disabled();
> preempt_enable();
>
> + self->started = 1;
> +
> ret = -EINTR;
> if (!test_bit(KTHREAD_SHOULD_STOP, &self->flags)) {
> cgroup_kthread_ready();
> @@ -540,7 +543,9 @@ static void __kthread_bind(struct task_struct *p, unsigned int cpu, unsigned int
>
> void kthread_bind_mask(struct task_struct *p, const struct cpumask *mask)
> {
> + struct kthread *kthread = to_kthread(p);
> __kthread_bind_mask(p, mask, TASK_UNINTERRUPTIBLE);
> + WARN_ON_ONCE(kthread->started);
> }
>
> /**
> @@ -554,7 +559,9 @@ void kthread_bind_mask(struct task_struct *p, const struct cpumask *mask)
> */
> void kthread_bind(struct task_struct *p, unsigned int cpu)
> {
> + struct kthread *kthread = to_kthread(p);
> __kthread_bind(p, cpu, TASK_UNINTERRUPTIBLE);
> + WARN_ON_ONCE(kthread->started);
> }
> EXPORT_SYMBOL(kthread_bind);
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [RFC PATCH 12/20] kthread: Implement preferred affinity
2024-07-26 21:56 ` [RFC PATCH 12/20] kthread: Implement preferred affinity Frederic Weisbecker
2024-07-26 22:31 ` Frederic Weisbecker
@ 2024-07-30 15:49 ` Vlastimil Babka
2024-08-05 14:28 ` Frederic Weisbecker
1 sibling, 1 reply; 16+ messages in thread
From: Vlastimil Babka @ 2024-07-30 15:49 UTC (permalink / raw)
To: Frederic Weisbecker, LKML
Cc: Andrew Morton, Kees Cook, Peter Zijlstra, Thomas Gleixner,
Michal Hocko, linux-mm, Paul E. McKenney, Neeraj Upadhyay,
Joel Fernandes, Boqun Feng, Zqiang, rcu
On 7/26/24 11:56 PM, Frederic Weisbecker wrote:
> Affining kthreads follow either of three existing different patterns:
>
> 1) Per-CPU kthreads must stay affine to a single CPU and never execute
> relevant code on any other CPU. This is currently handled by smpboot
> code which takes care of CPU-hotplug operations.
>
> 2) Kthreads that _have_ to be affine to a specific set of CPUs and can't
> run anywhere else. The affinity is set through kthread_bind_mask()
> and the subsystem takes care by itself to handle CPU-hotplug operations.
>
> 3) Kthreads that have a _preferred_ affinity but that can run anywhere
> without breaking correctness. Userspace can overwrite the affinity.
> It is set manually like any other task and CPU-hotplug is supposed
> to be handled by the relevant subsystem so that the task is properly
> reaffined whenever a given CPU from the preferred affinity comes up
> or down. Also care must be taken so that the preferred affinity
> doesn't cross housekeeping cpumask boundaries.
>
> Currently the preferred affinity pattern has at least 4 identified
> users, with more or less success when it comes to handle CPU-hotplug
> operations and housekeeping cpumask.
>
> Provide an infrastructure to handle this usecase patter. A new
> kthread_affine_preferred() API is introduced, to be used just like
> kthread_bind_mask(), right after kthread creation and before the first
> wake up. The kthread is then affine right away to the cpumask passed
> through the API if it has online housekeeping CPUs. Otherwise it will
> be affine to all online housekeeping CPUs as a last resort.
>
> It is aware of CPU hotplug events such that:
>
> * When a housekeeping CPU goes up and is part of the preferred affinity
> of a given kthread, it is added to its applied affinity set (and
> possibly the default last resort online housekeeping set is removed
> from the set).
>
> * When a housekeeping CPU goes down while it was part of the preferred
> affinity of a kthread, it is removed from the kthread's applied
> affinity. The last resort is to affine the kthread to all online
> housekeeping CPUs.
>
> Signed-off-by: Frederic Weisbecker <frederic@kernel.org>
Acked-by: Vlastimil Babka <vbabka@suse.cz>
Nit:
> +int kthread_affine_preferred(struct task_struct *p, const struct cpumask *mask)
> +{
> + struct kthread *kthread = to_kthread(p);
> + cpumask_var_t affinity;
> + unsigned long flags;
> + int ret;
> +
> + if (!wait_task_inactive(p, TASK_UNINTERRUPTIBLE) || kthread->started) {
> + WARN_ON(1);
> + return -EINVAL;
> + }
> +
Should we also fail if kthread->preferred_affinity already exist? In
case somebody calls this twice.
Also for some of the use cases (kswapd, kcompactd) it would make sense
to be able to add cpus of a node as they are onlined. Which seems we
didn't do, except some corner case handling in kcompactd, but maybe we
should? I wonder if the current implementation of onlining a completely
new node with cpus does the right thing as a result of the individual
onlining operations, or we end up with being affined to a single cpu (or
none).
But that would need some kind of kthread_affine_preferred_update()
implementation?
> + if (!zalloc_cpumask_var(&affinity, GFP_KERNEL))
> + return -ENOMEM;
> +
> + kthread->preferred_affinity = kzalloc(sizeof(struct cpumask), GFP_KERNEL);
> + if (!kthread->preferred_affinity) {
> + ret = -ENOMEM;
> + goto out;
> + }
> +
> + mutex_lock(&kthreads_hotplug_lock);
> + cpumask_copy(kthread->preferred_affinity, mask);
> + list_add_tail(&kthread->hotplug_node, &kthreads_hotplug);
> + kthread_fetch_affinity(kthread, affinity);
> +
> + /* It's safe because the task is inactive. */
> + raw_spin_lock_irqsave(&p->pi_lock, flags);
> + do_set_cpus_allowed(p, mask);
> + raw_spin_unlock_irqrestore(&p->pi_lock, flags);
> +
> + mutex_unlock(&kthreads_hotplug_lock);
> +out:
> + free_cpumask_var(affinity);
> +
> + return 0;
> +}
> +
> +static int kthreads_hotplug_update(void)
> +{
> + cpumask_var_t affinity;
> + struct kthread *k;
> + int err = 0;
> +
> + if (list_empty(&kthreads_hotplug))
> + return 0;
> +
> + if (!zalloc_cpumask_var(&affinity, GFP_KERNEL))
> + return -ENOMEM;
> +
> + list_for_each_entry(k, &kthreads_hotplug, hotplug_node) {
> + if (WARN_ON_ONCE(!k->preferred_affinity)) {
> + err = -EINVAL;
> + break;
> + }
> + kthread_fetch_affinity(k, affinity);
> + set_cpus_allowed_ptr(k->task, affinity);
> + }
> +
> + free_cpumask_var(affinity);
> +
> + return err;
> +}
> +
> +static int kthreads_offline_cpu(unsigned int cpu)
> +{
> + int ret = 0;
> +
> + mutex_lock(&kthreads_hotplug_lock);
> + cpumask_clear_cpu(cpu, &kthread_online_mask);
> + ret = kthreads_hotplug_update();
> + mutex_unlock(&kthreads_hotplug_lock);
> +
> + return ret;
> +}
> +
> +static int kthreads_online_cpu(unsigned int cpu)
> +{
> + int ret = 0;
> +
> + mutex_lock(&kthreads_hotplug_lock);
> + cpumask_set_cpu(cpu, &kthread_online_mask);
> + ret = kthreads_hotplug_update();
> + mutex_unlock(&kthreads_hotplug_lock);
> +
> + return ret;
> +}
> +
> +static int kthreads_init(void)
> +{
> + return cpuhp_setup_state(CPUHP_AP_KTHREADS_ONLINE, "kthreads:online",
> + kthreads_online_cpu, kthreads_offline_cpu);
> +}
> +early_initcall(kthreads_init);
> +
> void __kthread_init_worker(struct kthread_worker *worker,
> const char *name,
> struct lock_class_key *key)
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [RFC PATCH 12/20] kthread: Implement preferred affinity
2024-07-30 15:49 ` Vlastimil Babka
@ 2024-08-05 14:28 ` Frederic Weisbecker
2024-08-05 14:53 ` Vlastimil Babka
0 siblings, 1 reply; 16+ messages in thread
From: Frederic Weisbecker @ 2024-08-05 14:28 UTC (permalink / raw)
To: Vlastimil Babka
Cc: LKML, Andrew Morton, Kees Cook, Peter Zijlstra, Thomas Gleixner,
Michal Hocko, linux-mm, Paul E. McKenney, Neeraj Upadhyay,
Joel Fernandes, Boqun Feng, Zqiang, rcu
Le Tue, Jul 30, 2024 at 05:49:51PM +0200, Vlastimil Babka a écrit :
> Acked-by: Vlastimil Babka <vbabka@suse.cz>
>
> Nit:
>
> > +int kthread_affine_preferred(struct task_struct *p, const struct cpumask *mask)
> > +{
> > + struct kthread *kthread = to_kthread(p);
> > + cpumask_var_t affinity;
> > + unsigned long flags;
> > + int ret;
> > +
> > + if (!wait_task_inactive(p, TASK_UNINTERRUPTIBLE) || kthread->started) {
> > + WARN_ON(1);
> > + return -EINVAL;
> > + }
> > +
>
> Should we also fail if kthread->preferred_affinity already exist? In
> case somebody calls this twice.
Good point!
>
> Also for some of the use cases (kswapd, kcompactd) it would make sense
> to be able to add cpus of a node as they are onlined. Which seems we
> didn't do, except some corner case handling in kcompactd, but maybe we
> should? I wonder if the current implementation of onlining a completely
> new node with cpus does the right thing as a result of the individual
> onlining operations, or we end up with being affined to a single cpu (or
> none).
>
> But that would need some kind of kthread_affine_preferred_update()
> implementation?
So you mean that the "for_each_node_state()" loop in kcompactd doesn't
handle all possible nodes but only those online when it's called? Or
am I confused?
If all users of preferred affinity were to use NUMA nodes, it could be
a good idea to do a flavour of kernel/smpboot.c which would handle
per-node kthreads instead of per-cpu kthreads. I initially thought
about that. It would have handled all the lifecycle of those kthreads,
including creation, against hotplug. Unfortunately RCU doesn't rely on
per-NUMA nodes but rather use its own tree.
If there be more users of real per NUMA nodes kthreads than kswapd and
kcompactd, of course that would be much worth considering.
Thanks.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [RFC PATCH 12/20] kthread: Implement preferred affinity
2024-08-05 14:28 ` Frederic Weisbecker
@ 2024-08-05 14:53 ` Vlastimil Babka
2024-08-05 16:23 ` Frederic Weisbecker
0 siblings, 1 reply; 16+ messages in thread
From: Vlastimil Babka @ 2024-08-05 14:53 UTC (permalink / raw)
To: Frederic Weisbecker
Cc: LKML, Andrew Morton, Kees Cook, Peter Zijlstra, Thomas Gleixner,
Michal Hocko, linux-mm, Paul E. McKenney, Neeraj Upadhyay,
Joel Fernandes, Boqun Feng, Zqiang, rcu
On 8/5/24 16:28, Frederic Weisbecker wrote:
> Le Tue, Jul 30, 2024 at 05:49:51PM +0200, Vlastimil Babka a écrit :
>> Acked-by: Vlastimil Babka <vbabka@suse.cz>
>>
>> Nit:
>>
>> > +int kthread_affine_preferred(struct task_struct *p, const struct cpumask *mask)
>> > +{
>> > + struct kthread *kthread = to_kthread(p);
>> > + cpumask_var_t affinity;
>> > + unsigned long flags;
>> > + int ret;
>> > +
>> > + if (!wait_task_inactive(p, TASK_UNINTERRUPTIBLE) || kthread->started) {
>> > + WARN_ON(1);
>> > + return -EINVAL;
>> > + }
>> > +
>>
>> Should we also fail if kthread->preferred_affinity already exist? In
>> case somebody calls this twice.
>
> Good point!
>
>>
>> Also for some of the use cases (kswapd, kcompactd) it would make sense
>> to be able to add cpus of a node as they are onlined. Which seems we
>> didn't do, except some corner case handling in kcompactd, but maybe we
>> should? I wonder if the current implementation of onlining a completely
>> new node with cpus does the right thing as a result of the individual
>> onlining operations, or we end up with being affined to a single cpu (or
>> none).
>>
>> But that would need some kind of kthread_affine_preferred_update()
>> implementation?
>
> So you mean that the "for_each_node_state()" loop in kcompactd doesn't
> handle all possible nodes but only those online when it's called? Or
> am I confused?
If you mean the loop in kcompactd_init() then indeed, but we also have a
hook in online_pages() to start new threads on newly onlined nodes, so
that's not a problem.
The problem (I think) I see is cpumask_of_node(pgdat->node_id) is a snapshot
of cpus running on the NUMA node the time, and is never updated later as new
cpus might be brought up.
kcompactd_cpu_online() does try to update that when cpus are onlined (in a
clumsy way), there was nothing like that for kswapd and after your series
this update is also removed for kcompactd.
> If all users of preferred affinity were to use NUMA nodes, it could be
> a good idea to do a flavour of kernel/smpboot.c which would handle
> per-node kthreads instead of per-cpu kthreads. I initially thought
> about that. It would have handled all the lifecycle of those kthreads,
> including creation, against hotplug. Unfortunately RCU doesn't rely on
> per-NUMA nodes but rather use its own tree.
>
> If there be more users of real per NUMA nodes kthreads than kswapd and
> kcompactd, of course that would be much worth considering.
Yeah it's not that compelling, but a way to update the preferred affine mask
in response to cpu hotplug events, that kswapd and kcompactd could use,
would be sufficient. And maybe more widely useful.
I guess there could be a callback defined for kthread to provide a new
preferred_affinity, that you'd call from kthreads_hotplug_update() ?
And kcompactd and kswapd could both use the same callback that interprets
kthread_data() as pgdat and fetches a new cpumask of it?
> Thanks.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [RFC PATCH 12/20] kthread: Implement preferred affinity
2024-08-05 14:53 ` Vlastimil Babka
@ 2024-08-05 16:23 ` Frederic Weisbecker
2024-08-05 21:25 ` Vlastimil Babka
0 siblings, 1 reply; 16+ messages in thread
From: Frederic Weisbecker @ 2024-08-05 16:23 UTC (permalink / raw)
To: Vlastimil Babka
Cc: LKML, Andrew Morton, Kees Cook, Peter Zijlstra, Thomas Gleixner,
Michal Hocko, linux-mm, Paul E. McKenney, Neeraj Upadhyay,
Joel Fernandes, Boqun Feng, Zqiang, rcu
Le Mon, Aug 05, 2024 at 04:53:51PM +0200, Vlastimil Babka a écrit :
> If you mean the loop in kcompactd_init() then indeed, but we also have a
> hook in online_pages() to start new threads on newly onlined nodes, so
> that's not a problem.
>
> The problem (I think) I see is cpumask_of_node(pgdat->node_id) is a snapshot
> of cpus running on the NUMA node the time, and is never updated later as new
> cpus might be brought up.
Oh I see now...
>
> kcompactd_cpu_online() does try to update that when cpus are onlined (in a
> clumsy way), there was nothing like that for kswapd and after your series
> this update is also removed for kcompactd.
Ok...
>
> > If all users of preferred affinity were to use NUMA nodes, it could be
> > a good idea to do a flavour of kernel/smpboot.c which would handle
> > per-node kthreads instead of per-cpu kthreads. I initially thought
> > about that. It would have handled all the lifecycle of those kthreads,
> > including creation, against hotplug. Unfortunately RCU doesn't rely on
> > per-NUMA nodes but rather use its own tree.
> >
> > If there be more users of real per NUMA nodes kthreads than kswapd and
> > kcompactd, of course that would be much worth considering.
>
> Yeah it's not that compelling, but a way to update the preferred affine mask
> in response to cpu hotplug events, that kswapd and kcompactd could use,
> would be sufficient. And maybe more widely useful.
>
> I guess there could be a callback defined for kthread to provide a new
> preferred_affinity, that you'd call from kthreads_hotplug_update() ?
> And kcompactd and kswapd could both use the same callback that interprets
> kthread_data() as pgdat and fetches a new cpumask of it?
It's too bad we don't have a way to have a cpumask_possible_of_node(). I've
looked into the guts of numa but that doesn't look easy to do.
Or there could be kthread_set_preferred_node()... ?
Thanks.
>
> > Thanks.
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [RFC PATCH 12/20] kthread: Implement preferred affinity
2024-08-05 16:23 ` Frederic Weisbecker
@ 2024-08-05 21:25 ` Vlastimil Babka
2024-08-05 23:59 ` Frederic Weisbecker
0 siblings, 1 reply; 16+ messages in thread
From: Vlastimil Babka @ 2024-08-05 21:25 UTC (permalink / raw)
To: Frederic Weisbecker
Cc: LKML, Andrew Morton, Kees Cook, Peter Zijlstra, Thomas Gleixner,
Michal Hocko, linux-mm, Paul E. McKenney, Neeraj Upadhyay,
Joel Fernandes, Boqun Feng, Zqiang, rcu
On 8/5/24 18:23, Frederic Weisbecker wrote:
> Le Mon, Aug 05, 2024 at 04:53:51PM +0200, Vlastimil Babka a écrit :
>> If you mean the loop in kcompactd_init() then indeed, but we also have a
>> hook in online_pages() to start new threads on newly onlined nodes, so
>> that's not a problem.
>>
>> The problem (I think) I see is cpumask_of_node(pgdat->node_id) is a snapshot
>> of cpus running on the NUMA node the time, and is never updated later as new
>> cpus might be brought up.
>
> Oh I see now...
>
>>
>> kcompactd_cpu_online() does try to update that when cpus are onlined (in a
>> clumsy way), there was nothing like that for kswapd and after your series
>> this update is also removed for kcompactd.
>
> Ok...
>
>>
>> > If all users of preferred affinity were to use NUMA nodes, it could be
>> > a good idea to do a flavour of kernel/smpboot.c which would handle
>> > per-node kthreads instead of per-cpu kthreads. I initially thought
>> > about that. It would have handled all the lifecycle of those kthreads,
>> > including creation, against hotplug. Unfortunately RCU doesn't rely on
>> > per-NUMA nodes but rather use its own tree.
>> >
>> > If there be more users of real per NUMA nodes kthreads than kswapd and
>> > kcompactd, of course that would be much worth considering.
>>
>> Yeah it's not that compelling, but a way to update the preferred affine mask
>> in response to cpu hotplug events, that kswapd and kcompactd could use,
>> would be sufficient. And maybe more widely useful.
>>
>> I guess there could be a callback defined for kthread to provide a new
>> preferred_affinity, that you'd call from kthreads_hotplug_update() ?
>> And kcompactd and kswapd could both use the same callback that interprets
>> kthread_data() as pgdat and fetches a new cpumask of it?
>
> It's too bad we don't have a way to have a cpumask_possible_of_node(). I've
> looked into the guts of numa but that doesn't look easy to do.
That was my impression as well. Maybe not even possible because exact cpu
ids might not be pre-determined like this?
> Or there could be kthread_set_preferred_node()... ?
Possible instead of the callback idea suggested above?
kthreads_hotplug_update() could check if this is set and construct the mask
accordingly.
> Thanks.
>
>>
>> > Thanks.
>>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [RFC PATCH 12/20] kthread: Implement preferred affinity
2024-08-05 21:25 ` Vlastimil Babka
@ 2024-08-05 23:59 ` Frederic Weisbecker
2024-08-06 11:08 ` Vlastimil Babka
0 siblings, 1 reply; 16+ messages in thread
From: Frederic Weisbecker @ 2024-08-05 23:59 UTC (permalink / raw)
To: Vlastimil Babka
Cc: LKML, Andrew Morton, Kees Cook, Peter Zijlstra, Thomas Gleixner,
Michal Hocko, linux-mm, Paul E. McKenney, Neeraj Upadhyay,
Joel Fernandes, Boqun Feng, Zqiang, rcu
On Mon, Aug 05, 2024 at 11:25:59PM +0200, Vlastimil Babka wrote:
> > It's too bad we don't have a way to have a cpumask_possible_of_node(). I've
> > looked into the guts of numa but that doesn't look easy to do.
>
> That was my impression as well. Maybe not even possible because exact cpu
> ids might not be pre-determined like this?
Probably.
>
> > Or there could be kthread_set_preferred_node()... ?
>
> Possible instead of the callback idea suggested above?
> kthreads_hotplug_update() could check if this is set and construct the mask
> accordingly.
Or even better, callers of kthread_create_on_node() with actual node passed
(!NUMA_NO_NODE) can be preferrably affined to the corresponding node by default
unless told otherwise (that is unless kthread_bind() or
kthread_set_preferred_affinity() has been called before the first wake up, and
that includes kthread_create_on_cpu()).
There are a few callers concerned: kswapd, kcompactd, some drivers:
drivers/block/mtip32xx/mtip32xx.c, drivers/firmware/stratix10-svc.c,
kernel/dma/map_benchmark.c, net/sunrpc/svc.c
After all kthread_create_on_cpu() affines to the corresponding CPU. So
it sounds natural that kthread_create_on_node() affines to the corresponding
node.
And then it's handled on hotplug just as a special case of preferred affinity.
Or is there something that wouldn't make that work?
Thanks.
>
> > Thanks.
> >
> >>
> >> > Thanks.
> >>
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [RFC PATCH 12/20] kthread: Implement preferred affinity
2024-08-05 23:59 ` Frederic Weisbecker
@ 2024-08-06 11:08 ` Vlastimil Babka
0 siblings, 0 replies; 16+ messages in thread
From: Vlastimil Babka @ 2024-08-06 11:08 UTC (permalink / raw)
To: Frederic Weisbecker
Cc: LKML, Andrew Morton, Kees Cook, Peter Zijlstra, Thomas Gleixner,
Michal Hocko, linux-mm, Paul E. McKenney, Neeraj Upadhyay,
Joel Fernandes, Boqun Feng, Zqiang, rcu
On 8/6/24 01:59, Frederic Weisbecker wrote:
> On Mon, Aug 05, 2024 at 11:25:59PM +0200, Vlastimil Babka wrote:
>> > It's too bad we don't have a way to have a cpumask_possible_of_node(). I've
>> > looked into the guts of numa but that doesn't look easy to do.
>>
>> That was my impression as well. Maybe not even possible because exact cpu
>> ids might not be pre-determined like this?
>
> Probably.
>
>>
>> > Or there could be kthread_set_preferred_node()... ?
>>
>> Possible instead of the callback idea suggested above?
>> kthreads_hotplug_update() could check if this is set and construct the mask
>> accordingly.
>
> Or even better, callers of kthread_create_on_node() with actual node passed
> (!NUMA_NO_NODE) can be preferrably affined to the corresponding node by default
> unless told otherwise (that is unless kthread_bind() or
> kthread_set_preferred_affinity() has been called before the first wake up, and
> that includes kthread_create_on_cpu()).
Sounds logical and great!
> There are a few callers concerned: kswapd, kcompactd, some drivers:
> drivers/block/mtip32xx/mtip32xx.c, drivers/firmware/stratix10-svc.c,
> kernel/dma/map_benchmark.c, net/sunrpc/svc.c
>
> After all kthread_create_on_cpu() affines to the corresponding CPU. So
> it sounds natural that kthread_create_on_node() affines to the corresponding
> node.
Yes.
> And then it's handled on hotplug just as a special case of preferred affinity.
>
> Or is there something that wouldn't make that work?
Hopefully not.
> Thanks.
>
>
>>
>> > Thanks.
>> >
>> >>
>> >> > Thanks.
>> >>
>>
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2024-08-06 11:08 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20240726215701.19459-1-frederic@kernel.org>
2024-07-26 21:56 ` [RFC PATCH 11/20] kthread: Make sure kthread hasn't started while binding it Frederic Weisbecker
2024-07-30 15:20 ` Vlastimil Babka
2024-07-26 21:56 ` [RFC PATCH 12/20] kthread: Implement preferred affinity Frederic Weisbecker
2024-07-26 22:31 ` Frederic Weisbecker
2024-07-30 15:49 ` Vlastimil Babka
2024-08-05 14:28 ` Frederic Weisbecker
2024-08-05 14:53 ` Vlastimil Babka
2024-08-05 16:23 ` Frederic Weisbecker
2024-08-05 21:25 ` Vlastimil Babka
2024-08-05 23:59 ` Frederic Weisbecker
2024-08-06 11:08 ` Vlastimil Babka
2024-07-26 21:56 ` [RFC PATCH 17/20] rcu: Use kthread preferred affinity for RCU boost Frederic Weisbecker
2024-07-26 21:56 ` [RFC PATCH 18/20] kthread: Unify kthread_create_on_cpu() and kthread_create_worker_on_cpu() automatic format Frederic Weisbecker
2024-07-26 21:56 ` [RFC PATCH 19/20] treewide: Introduce kthread_run_worker[_on_cpu]() Frederic Weisbecker
2024-07-26 21:56 ` [RFC PATCH 20/20] rcu: Use kthread preferred affinity for RCU exp kworkers Frederic Weisbecker
2024-07-26 22:40 ` Paul E. McKenney
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox