From: Christian Brauner <brauner@kernel.org>
To: linux-fsdevel@vger.kernel.org,
Linus Torvalds <torvalds@linux-foundation.org>
Cc: linux-kernel@vger.kernel.org,
Alexander Viro <viro@zeniv.linux.org.uk>,
Jens Axboe <axboe@kernel.dk>, Jan Kara <jack@suse.cz>,
Tejun Heo <tj@kernel.org>, Jann Horn <jannh@google.com>,
Christian Brauner <brauner@kernel.org>
Subject: [PATCH RFC DRAFT POC 03/11] kthread: add extensible kthread_create()/kthread_run() pattern
Date: Tue, 03 Mar 2026 14:49:14 +0100 [thread overview]
Message-ID: <20260303-work-kthread-nullfs-v1-3-87e559b94375@kernel.org> (raw)
In-Reply-To: <20260303-work-kthread-nullfs-v1-0-87e559b94375@kernel.org>
This is similar to what I did for kmem_cache_create() in
b2e7456b5c25 ("slab: create kmem_cache_create() compatibility layer").
Instead of piling on new variants of the functions add a struct
kthread_args variant that just passes the relevant paramter.
Signed-off-by: Christian Brauner <brauner@kernel.org>
---
include/linux/kthread.h | 69 +++++++++++++++++++++++++++-------------
kernel/kthread.c | 83 +++++++++++++++++++++++++++++++++++++++++--------
2 files changed, 118 insertions(+), 34 deletions(-)
diff --git a/include/linux/kthread.h b/include/linux/kthread.h
index 2630791295ac..972cb2960b61 100644
--- a/include/linux/kthread.h
+++ b/include/linux/kthread.h
@@ -25,26 +25,53 @@ static inline struct kthread *tsk_is_kthread(struct task_struct *p)
return NULL;
}
+/**
+ * struct kthread_args - kthread creation parameters.
+ * @threadfn: the function to run in the kthread.
+ * @data: data pointer passed to @threadfn.
+ * @node: NUMA node for stack/task allocation (NUMA_NO_NODE for any).
+ * @kthread_worker: set to 1 to create a kthread worker.
+ *
+ * Pass a pointer to this struct as the first argument of kthread_create()
+ * or kthread_run() to use the struct-based creation path. Legacy callers
+ * that pass a function pointer as the first argument continue to work
+ * unchanged via _Generic dispatch.
+ */
+struct kthread_args {
+ int (*threadfn)(void *data);
+ void *data;
+ int node;
+ u32 kthread_worker:1;
+};
+
__printf(4, 5)
struct task_struct *kthread_create_on_node(int (*threadfn)(void *data),
void *data,
int node,
const char namefmt[], ...);
+__printf(2, 3)
+struct task_struct *kthread_create_on_info(struct kthread_args *kargs,
+ const char namefmt[], ...);
+
+__printf(3, 4)
+struct task_struct *__kthread_create(int (*threadfn)(void *data),
+ void *data,
+ const char namefmt[], ...);
+
/**
- * kthread_create - create a kthread on the current node
- * @threadfn: the function to run in the thread
- * @data: data pointer for @threadfn()
- * @namefmt: printf-style format string for the thread name
- * @arg: arguments for @namefmt.
+ * kthread_create - create a kthread on the current node.
+ * @first: either a function pointer (legacy) or a &struct kthread_args
+ * pointer (struct-based).
*
- * This macro will create a kthread on the current node, leaving it in
- * the stopped state. This is just a helper for kthread_create_on_node();
- * see the documentation there for more details.
+ * _Generic dispatch: when @first is a &struct kthread_args pointer the
+ * call is forwarded to kthread_create_on_info(); otherwise it goes through
+ * __kthread_create() which wraps kthread_create_on_node() with NUMA_NO_NODE.
*/
-#define kthread_create(threadfn, data, namefmt, arg...) \
- kthread_create_on_node(threadfn, data, NUMA_NO_NODE, namefmt, ##arg)
-
+#define kthread_create(__first, ...) \
+ _Generic((__first), \
+ struct kthread_args *: kthread_create_on_info, \
+ default: __kthread_create)(__first, __VA_ARGS__)
struct task_struct *kthread_create_on_cpu(int (*threadfn)(void *data),
void *data,
@@ -59,20 +86,20 @@ bool kthread_is_per_cpu(struct task_struct *k);
/**
* kthread_run - create and wake a thread.
- * @threadfn: the function to run until signal_pending(current).
- * @data: data ptr for @threadfn.
- * @namefmt: printf-style name for the thread.
+ * @first: either a function pointer (legacy) or a &struct kthread_args
+ * pointer (struct-based). Remaining arguments are forwarded to
+ * kthread_create().
*
* Description: Convenient wrapper for kthread_create() followed by
* wake_up_process(). Returns the kthread or ERR_PTR(-ENOMEM).
*/
-#define kthread_run(threadfn, data, namefmt, ...) \
-({ \
- struct task_struct *__k \
- = kthread_create(threadfn, data, namefmt, ## __VA_ARGS__); \
- if (!IS_ERR(__k)) \
- wake_up_process(__k); \
- __k; \
+#define kthread_run(__first, ...) \
+({ \
+ struct task_struct *__k \
+ = kthread_create(__first, __VA_ARGS__); \
+ if (!IS_ERR(__k)) \
+ wake_up_process(__k); \
+ __k; \
})
/**
diff --git a/kernel/kthread.c b/kernel/kthread.c
index 4c60c8082126..20ec96142ce6 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -38,8 +38,7 @@ struct task_struct *kthreadd_task;
static LIST_HEAD(kthread_affinity_list);
static DEFINE_MUTEX(kthread_affinity_lock);
-struct kthread_create_info
-{
+struct kthread_create_req {
/* Information passed to kthread() from kthreadd. */
char *full_name;
int (*threadfn)(void *data);
@@ -382,7 +381,7 @@ static int kthread(void *_create)
{
static const struct sched_param param = { .sched_priority = 0 };
/* Copy data: it's on kthread's stack */
- struct kthread_create_info *create = _create;
+ struct kthread_create_req *create = _create;
int (*threadfn)(void *data) = create->threadfn;
void *data = create->data;
struct completion *done;
@@ -449,7 +448,7 @@ int tsk_fork_get_node(struct task_struct *tsk)
return NUMA_NO_NODE;
}
-static void create_kthread(struct kthread_create_info *create)
+static void create_kthread(struct kthread_create_req *create)
{
int pid;
struct kernel_clone_args args = {
@@ -480,20 +479,23 @@ static void create_kthread(struct kthread_create_info *create)
}
}
-static struct task_struct *__kthread_create_on_node(const struct kthread_create_info *info,
+static struct task_struct *__kthread_create_on_node(const struct kthread_args *kargs,
const char namefmt[],
va_list args)
{
DECLARE_COMPLETION_ONSTACK(done);
struct kthread_worker *worker = NULL;
struct task_struct *task;
- struct kthread_create_info *create;
+ struct kthread_create_req *create;
create = kmalloc_obj(*create);
if (!create)
return ERR_PTR(-ENOMEM);
- *create = *info;
+ create->threadfn = kargs->threadfn;
+ create->data = kargs->data;
+ create->node = kargs->node;
+ create->kthread_worker = kargs->kthread_worker;
if (create->kthread_worker) {
worker = kzalloc_obj(*worker);
@@ -573,7 +575,7 @@ struct task_struct *kthread_create_on_node(int (*threadfn)(void *data),
const char namefmt[],
...)
{
- struct kthread_create_info info = {
+ struct kthread_args kargs = {
.threadfn = threadfn,
.data = data,
.node = node,
@@ -582,13 +584,68 @@ struct task_struct *kthread_create_on_node(int (*threadfn)(void *data),
va_list args;
va_start(args, namefmt);
- task = __kthread_create_on_node(&info, namefmt, args);
+ task = __kthread_create_on_node(&kargs, namefmt, args);
va_end(args);
return task;
}
EXPORT_SYMBOL(kthread_create_on_node);
+/**
+ * kthread_create_on_info - create a kthread from a struct kthread_args.
+ * @kargs: kthread creation parameters.
+ * @namefmt: printf-style name for the thread.
+ *
+ * This is the struct-based kthread creation path, dispatched via the
+ * kthread_create() _Generic macro when the first argument is a
+ * &struct kthread_args pointer.
+ *
+ * Returns a task_struct or ERR_PTR(-ENOMEM) or ERR_PTR(-EINTR).
+ */
+struct task_struct *kthread_create_on_info(struct kthread_args *kargs,
+ const char namefmt[], ...)
+{
+ struct task_struct *task;
+ va_list args;
+
+ va_start(args, namefmt);
+ task = __kthread_create_on_node(kargs, namefmt, args);
+ va_end(args);
+
+ return task;
+}
+EXPORT_SYMBOL(kthread_create_on_info);
+
+/**
+ * __kthread_create - create a kthread (legacy positional-argument path).
+ * @threadfn: the function to run until signal_pending(current).
+ * @data: data ptr for @threadfn.
+ * @namefmt: printf-style name for the thread.
+ *
+ * _Generic dispatch target for kthread_create() when the first argument
+ * is a function pointer rather than a &struct kthread_args.
+ *
+ * Returns a task_struct or ERR_PTR(-ENOMEM) or ERR_PTR(-EINTR).
+ */
+struct task_struct *__kthread_create(int (*threadfn)(void *data),
+ void *data, const char namefmt[], ...)
+{
+ struct kthread_args kargs = {
+ .threadfn = threadfn,
+ .data = data,
+ .node = NUMA_NO_NODE,
+ };
+ struct task_struct *task;
+ va_list args;
+
+ va_start(args, namefmt);
+ task = __kthread_create_on_node(&kargs, namefmt, args);
+ va_end(args);
+
+ return task;
+}
+EXPORT_SYMBOL(__kthread_create);
+
static void __kthread_bind_mask(struct task_struct *p, const struct cpumask *mask, unsigned int state)
{
if (!wait_task_inactive(p, state)) {
@@ -833,10 +890,10 @@ int kthreadd(void *unused)
spin_lock(&kthread_create_lock);
while (!list_empty(&kthread_create_list)) {
- struct kthread_create_info *create;
+ struct kthread_create_req *create;
create = list_entry(kthread_create_list.next,
- struct kthread_create_info, list);
+ struct kthread_create_req, list);
list_del_init(&create->list);
spin_unlock(&kthread_create_lock);
@@ -1080,7 +1137,7 @@ EXPORT_SYMBOL_GPL(kthread_worker_fn);
struct kthread_worker *
kthread_create_worker_on_node(int node, const char namefmt[], ...)
{
- struct kthread_create_info info = {
+ struct kthread_args kargs = {
.node = node,
.kthread_worker = 1,
};
@@ -1089,7 +1146,7 @@ kthread_create_worker_on_node(int node, const char namefmt[], ...)
va_list args;
va_start(args, namefmt);
- task = __kthread_create_on_node(&info, namefmt, args);
+ task = __kthread_create_on_node(&kargs, namefmt, args);
va_end(args);
if (IS_ERR(task))
--
2.47.3
next prev parent reply other threads:[~2026-03-03 13:49 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-03 13:49 [PATCH RFC DRAFT POC 00/11] fs,kthread: isolate all kthreads in nullfs Christian Brauner
2026-03-03 13:49 ` [PATCH RFC DRAFT POC 01/11] kthread: refactor __kthread_create_on_node() to take a struct argument Christian Brauner
2026-03-03 13:49 ` [PATCH RFC DRAFT POC 02/11] kthread: remove unused flags argument from kthread worker creation API Christian Brauner
2026-03-03 13:49 ` Christian Brauner [this message]
2026-03-03 13:49 ` [PATCH RFC DRAFT POC 04/11] fs: notice when init abandons fs sharing Christian Brauner
2026-03-03 13:49 ` [PATCH RFC DRAFT POC 05/11] fs: add LOOKUP_IN_INIT Christian Brauner
2026-03-03 13:49 ` [PATCH RFC DRAFT POC 06/11] fs: add file_open_init() Christian Brauner
2026-03-03 13:49 ` [PATCH RFC DRAFT POC 07/11] block: add bdev_file_open_init() Christian Brauner
2026-03-03 13:49 ` [PATCH RFC DRAFT POC 08/11] fs: allow to pass lookup flags to filename_*() Christian Brauner
2026-03-03 13:49 ` [PATCH RFC DRAFT POC 09/11] fs: add init_root() Christian Brauner
2026-03-03 13:49 ` [PATCH RFC DRAFT POC 10/11] tree-wide: make all kthread path lookups to use LOOKUP_IN_INIT Christian Brauner
2026-03-03 15:03 ` Christoph Hellwig
2026-03-03 13:49 ` [PATCH RFC DRAFT POC 11/11] fs: isolate all kthreads in nullfs Christian Brauner
2026-03-06 7:26 ` [PATCH RFC DRAFT POC 00/11] fs,kthread: " Askar Safin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260303-work-kthread-nullfs-v1-3-87e559b94375@kernel.org \
--to=brauner@kernel.org \
--cc=axboe@kernel.dk \
--cc=jack@suse.cz \
--cc=jannh@google.com \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=tj@kernel.org \
--cc=torvalds@linux-foundation.org \
--cc=viro@zeniv.linux.org.uk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox