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 --- 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