[Devel] [PATCH vz9 03/14] ve/kthreadd: create kthreadd in a containers pid ns

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


From: Stanislav Kinsburskiy <skinsbursky at virtuozzo.com>

The idea is simple: create another kworker in the one, attached to CT.
The latter has containers pid ns for children, so the former will appear in
containers pid ns.
The latter then can be destroyed, thus leaving us "kthreadd" kernel thread not
just attached, but also visible in the desired container.

Notes:
1) We create new kthread by using per-container creation helper.
2) We don't need original attached worker when we have this new fully entered
kthreadd, so this patch destroys original worker.
3) New kthreadd is forked with CLONE_PARENT flag and thus will be reparented
to host kthreadd.

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

(cherry-picked from vz8 commit 2f1fad726487 ("ve/kthreadd: create kthreadd
in a containers pid ns"))

Signed-off-by: Nikita Yushchenko <nikita.yushchenko at virtuozzo.com>
---
 include/linux/ve.h |  1 +
 kernel/ve/ve.c     | 41 ++++++++++++++++++++++++++++++++++++++---
 2 files changed, 39 insertions(+), 3 deletions(-)

diff --git a/include/linux/ve.h b/include/linux/ve.h
index 6f75bd084e2e..cea4fa48d939 100644
--- a/include/linux/ve.h
+++ b/include/linux/ve.h
@@ -61,6 +61,7 @@ struct ve_struct {
 	int			_randomize_va_space;
 
 	struct kthread_worker	*kthreadd_worker;
+	struct task_struct	*kthreadd_task;
 };
 
 extern int nr_ve;
diff --git a/kernel/ve/ve.c b/kernel/ve/ve.c
index da86dae1a5f4..9c0070c39eb4 100644
--- a/kernel/ve/ve.c
+++ b/kernel/ve/ve.c
@@ -267,7 +267,9 @@ static void ve_drop_context(struct ve_struct *ve)
 
 static void ve_stop_kthreadd(struct ve_struct *ve)
 {
-	kthread_destroy_worker(ve->kthreadd_worker);
+	kthread_flush_worker(ve->kthreadd_worker);
+	kthread_stop(ve->kthreadd_task);
+	kfree(ve->kthreadd_worker);
 	ve->kthreadd_worker = NULL;
 }
 
@@ -334,16 +336,49 @@ static struct kthread_worker *ve_create_kworker(struct ve_struct *ve)
 	return w;
 }
 
+static int ve_create_kthreadd(struct ve_struct *ve,
+			      struct kthread_worker *gastarbeiter)
+{
+	struct kthread_worker *w;
+	struct task_struct *task;
+
+	w = kmalloc(sizeof(struct kthread_worker), GFP_KERNEL);
+	if (!w)
+		return -ENOMEM;
+	kthread_init_worker(w);
+
+	/* This is a trick to fork kthread in a container */
+	ve->kthreadd_worker = gastarbeiter;
+
+	/* We create kthread with CLONE_PARENT flags, because otherwise when
+	 * gastarbeiter will be stopped, kthreadd will be reparented to idle,
+	 * while we want to keep all the threads in kthreadd pool */
+	task = kthread_create_on_node_ve_flags(ve, CLONE_PARENT, kthread_worker_fn,
+					       w, NUMA_NO_NODE, "kthreadd");
+	if (IS_ERR(task)) {
+		kfree(w);
+		return PTR_ERR(task);
+	}
+	wake_up_process(task);
+
+	ve->kthreadd_task = task;
+	ve->kthreadd_worker = w;
+	return 0;
+}
+
 static int ve_start_kthreadd(struct ve_struct *ve)
 {
 	struct kthread_worker *w;
+	int err;
 
 	w = ve_create_kworker(ve);
 	if (IS_ERR(w))
 		return PTR_ERR(w);
 
-	ve->kthreadd_worker = w;
-	return 0;
+	err = ve_create_kthreadd(ve, w);
+
+	kthread_destroy_worker(w);
+	return err;
 }
 
 /* under ve->op_sem write-lock */
-- 
2.30.2



More information about the Devel mailing list