[Devel] [PATCH rh7 1/3] ve: Attach a ve cgroup from task_work

Kirill Tkhai ktkhai at odin.com
Fri Oct 16 09:24:49 PDT 2015


We have many places where get_exec_env() is used.
Since a task may be attached to a ve not only by
itself, this may lead to a problem, when dereferenced
ve has changed, but a code is operating with the old
ve.

This patch makes task_ve to be changed using task_work,
i.e. in a place where we definitelly do not use
get_exec_env().

Suggested-by: Vladimir Davydov <vdavydov at odin.com>
Suggested-by: Pavel Emelyanov <xemul at odin.com>
Signed-off-by: Kirill Tkhai <ktkhai at odin.com>
---
 include/linux/init_task.h |    3 ++-
 include/linux/sched.h     |    1 +
 kernel/fork.c             |    4 ++++
 kernel/ve/ve.c            |   19 ++++++++++++++++++-
 4 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index d2cbad0..1d5e271 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -136,7 +136,8 @@ extern struct task_group root_task_group;
 #endif
 
 #ifdef CONFIG_VE
-#define	INIT_TASK_VE(tsk) .task_ve = &ve0,
+#define	INIT_TASK_VE(tsk) .task_ve = &ve0,				\
+			  .task_ve_work.func = NULL,
 #else
 #define	INIT_TASK_VE(tsk)
 #endif
diff --git a/include/linux/sched.h b/include/linux/sched.h
index e1bcabe..20d2e4e 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1564,6 +1564,7 @@ struct task_struct {
 #endif
 #ifdef CONFIG_VE
 	struct ve_struct *task_ve;
+	struct callback_head task_ve_work;
 #endif
 #ifdef CONFIG_MEMCG /* memcg uses this to do batch job */
 	struct memcg_batch_info {
diff --git a/kernel/fork.c b/kernel/fork.c
index 505fa21..b077751 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -73,6 +73,7 @@
 #include <linux/uprobes.h>
 #include <linux/aio.h>
 #include <linux/ve.h>
+#include <linux/task_work.h>
 
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
@@ -1377,6 +1378,9 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 	p->sequential_io	= 0;
 	p->sequential_io_avg	= 0;
 #endif
+#ifdef CONFIG_VE
+	init_task_work(&p->task_ve_work, NULL);
+#endif
 
 	/* Perform scheduler related setup. Assign this task to a CPU. */
 	sched_fork(clone_flags, p);
diff --git a/kernel/ve/ve.c b/kernel/ve/ve.c
index 12cfa33..23d5482 100644
--- a/kernel/ve/ve.c
+++ b/kernel/ve/ve.c
@@ -701,6 +701,15 @@ static void ve_destroy(struct cgroup *cg)
 	kmem_cache_free(ve_cachep, ve);
 }
 
+static void ve_attach_work(struct callback_head *head)
+{
+	rcu_read_lock();
+	current->task_ve = cgroup_ve(task_cgroup(current, ve_subsys_id));
+	rcu_read_unlock();
+	smp_mb(); /* Pairs with smp_mb() in ve_can_attach() */
+	init_task_work(&current->task_ve_work, NULL);
+}
+
 static int ve_can_attach(struct cgroup *cg, struct cgroup_taskset *tset)
 {
 	struct ve_struct *ve = cgroup_ve(cg);
@@ -733,6 +742,13 @@ static int ve_can_attach(struct cgroup *cg, struct cgroup_taskset *tset)
 		}
 	}
 
+	cgroup_taskset_for_each(task, cg, tset) {
+		/* Attaching is in process */
+		if (task->task_ve_work.func != NULL)
+			return -EAGAIN;
+	}
+	smp_mb(); /* Pairs with smp_mb() in ve_attach_work() */
+
 	return 0;
 }
 
@@ -753,7 +769,8 @@ static void ve_attach(struct cgroup *cg, struct cgroup_taskset *tset)
 		/* Leave parent exec domain */
 		task->parent_exec_id--;
 
-		task->task_ve = ve;
+		init_task_work(&task->task_ve_work, ve_attach_work);
+		task_work_add(task, &task->task_ve_work, true);
 	}
 }
 




More information about the Devel mailing list