public inbox for linux-fsdevel@vger.kernel.org
 help / color / mirror / Atom feed
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


  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