[Devel] [PATCH vz9 02/14] ve/kthreadd: add per-ve kthreads creation interface

Nikita Yushchenko nikita.yushchenko at virtuozzo.com
Mon Sep 27 09:29:48 MSK 2021


From: Stanislav Kinsburskiy <skinsbursky at virtuozzo.com>

Patch introduces new function kthread_create_on_node_ve_flags and a few helpers:
1) kthread_create_on_node_ve and
1) kthread_run_ve and
2) kthread_create_ve

Note: we need to able to provide fork flags to kthread creation to be able to
fork one kthread from another as a sibling (this is needed to be able to put
kthreadd in contianer pid ns, but keep global kthreadd as its parent).

Signed-off-by: Stanislav Kinsburskiy <skinsbursky at virtuozzo.com>

+++
ve, kthread: Remove some useless crud.

Simplify the code by removing useless macroses.

Signed-off-by: Andrey Ryabinin <aryabinin at virtuozzo.com>

+++
ve,kthread: fix use-after-return.

__kthread_create_ve() passes pointer to the data on stack to
another thread, and return immidiately causing use-after-return.

Fix this by moving all in upper function which waits
another thread finishes it's job.

https://jira.sw.ru/browse/PSBM-93708
Signed-off-by: Andrey Ryabinin <aryabinin at virtuozzo.com>

(cherry-picked from vz8 commit 9aea2bf6c848 ("ve/kthreadd: add per-ve kthreads
creation interface"))

Signed-off-by: Nikita Yushchenko <nikita.yushchenko at virtuozzo.com>
---
 include/linux/kthread.h | 10 +++++
 kernel/kthread.c        | 97 ++++++++++++++++++++++++++++++++++++-----
 2 files changed, 95 insertions(+), 12 deletions(-)

diff --git a/include/linux/kthread.h b/include/linux/kthread.h
index 346b0f269161..6d5827ab4bf8 100644
--- a/include/linux/kthread.h
+++ b/include/linux/kthread.h
@@ -56,6 +56,16 @@ bool kthread_is_per_cpu(struct task_struct *k);
 	__k;								   \
 })
 
+#ifdef CONFIG_VE
+
+__printf(6, 7)
+struct task_struct *kthread_create_on_node_ve_flags(struct ve_struct *ve,
+						    unsigned long flags,
+						    int (*threadfn)(void *data),
+						    void *data, int node,
+						    const char namefmt[],
+						    ...);
+#endif
 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);
diff --git a/kernel/kthread.c b/kernel/kthread.c
index 5b37a8567168..127ecaa457b5 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -28,6 +28,7 @@
 #include <linux/uaccess.h>
 #include <linux/numa.h>
 #include <linux/sched/isolation.h>
+#include <linux/ve.h>
 #include <trace/events/sched.h>
 
 
@@ -331,7 +332,8 @@ 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_flags(struct kthread_create_info *create,
+				 unsigned long flags)
 {
 	int pid;
 
@@ -339,7 +341,8 @@ static void create_kthread(struct kthread_create_info *create)
 	current->pref_node_fork = create->node;
 #endif
 	/* We want our own signal handler (we take no signals by default). */
-	pid = kernel_thread(kthread, create, CLONE_FS | CLONE_FILES | SIGCHLD);
+	pid = kernel_thread(kthread, create,
+			    flags | CLONE_FS | CLONE_FILES | SIGCHLD);
 	if (pid < 0) {
 		/* If user was SIGKILLed, I release the structure. */
 		struct completion *done = xchg(&create->done, NULL);
@@ -353,13 +356,48 @@ static void create_kthread(struct kthread_create_info *create)
 	}
 }
 
-static __printf(4, 0)
-struct task_struct *__kthread_create_on_node(int (*threadfn)(void *data),
-						    void *data, int node,
-						    const char namefmt[],
-						    va_list args)
+static void create_kthread(struct kthread_create_info *create)
+{
+	return create_kthread_flags(create, 0);
+}
+
+#ifdef CONFIG_VE
+struct kthread_create_work {
+	struct kthread_work work;
+	struct kthread_create_info *info;
+	unsigned long flags;
+};
+
+static void kthread_create_fn(struct kthread_work *w)
+{
+	struct kthread_create_work *work = container_of(w,
+			struct kthread_create_work, work);
+
+	create_kthread_flags(work->info, work->flags);
+}
+
+#endif
+static void kthread_create_add(struct kthread_create_info *create)
+{
+	spin_lock(&kthread_create_lock);
+	list_add_tail(&create->list, &kthread_create_list);
+	spin_unlock(&kthread_create_lock);
+
+	wake_up_process(kthreadd_task);
+}
+
+static __printf(6, 0)
+struct task_struct *__kthread_create_on_node_ve(struct ve_struct *ve,
+						unsigned long flags,
+						int (*threadfn)(void *data),
+						void *data, int node,
+						const char namefmt[],
+						va_list args)
 {
 	DECLARE_COMPLETION_ONSTACK(done);
+	struct kthread_create_work work = {
+		KTHREAD_WORK_INIT(work.work, kthread_create_fn),
+	};
 	struct task_struct *task;
 	struct kthread_create_info *create = kmalloc(sizeof(*create),
 						     GFP_KERNEL);
@@ -371,11 +409,15 @@ struct task_struct *__kthread_create_on_node(int (*threadfn)(void *data),
 	create->node = node;
 	create->done = &done;
 
-	spin_lock(&kthread_create_lock);
-	list_add_tail(&create->list, &kthread_create_list);
-	spin_unlock(&kthread_create_lock);
-
-	wake_up_process(kthreadd_task);
+#ifdef CONFIG_VE
+	if (!ve_is_super(ve))
+	{
+		work.info = create;
+		work.flags = flags;
+		kthread_queue_work(ve->kthreadd_worker, &work.work);
+	} else
+#endif
+		kthread_create_add(create);
 	/*
 	 * Wait for completion in killable state, for I might be chosen by
 	 * the OOM killer while kthreadd is trying to allocate memory for
@@ -418,6 +460,16 @@ struct task_struct *__kthread_create_on_node(int (*threadfn)(void *data),
 	return task;
 }
 
+static __printf(4, 0)
+struct task_struct *__kthread_create_on_node(int (*threadfn)(void *data),
+						    void *data, int node,
+						    const char namefmt[],
+						    va_list args)
+{
+	return __kthread_create_on_node_ve(get_ve0(), 0,
+					   threadfn, data, node, namefmt, args);
+}
+
 /**
  * kthread_create_on_node - create a kthread.
  * @threadfn: the function to run until signal_pending(current).
@@ -457,6 +509,27 @@ struct task_struct *kthread_create_on_node(int (*threadfn)(void *data),
 }
 EXPORT_SYMBOL(kthread_create_on_node);
 
+#ifdef CONFIG_VE
+struct task_struct *kthread_create_on_node_ve_flags(struct ve_struct *ve,
+						    unsigned long flags,
+						    int (*threadfn)(void *data),
+						    void *data, int node,
+						    const char namefmt[],
+						    ...)
+{
+	struct task_struct *task;
+	va_list args;
+
+	va_start(args, namefmt);
+	task = __kthread_create_on_node_ve(ve, flags,
+					   threadfn, data, node, namefmt, args);
+	va_end(args);
+
+	return task;
+}
+EXPORT_SYMBOL(kthread_create_on_node_ve_flags);
+#endif
+
 static void __kthread_bind_mask(struct task_struct *p, const struct cpumask *mask, unsigned int state)
 {
 	unsigned long flags;
-- 
2.30.2



More information about the Devel mailing list