[Devel] [PATCH rh7 2/3] ve: Wait till ve's attaching work finished

Kirill Tkhai ktkhai at odin.com
Fri Oct 16 09:25:00 PDT 2015


Userspace (i.e. vzctl) may want to know that attaching
action has finished, because its further actions
may depend on that.

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     |    4 ++++
 kernel/fork.c             |    1 +
 kernel/ve/ve.c            |   36 ++++++++++++++++++++++++++++++++++--
 4 files changed, 41 insertions(+), 3 deletions(-)

diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index 1d5e271..d6caecc 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -137,7 +137,8 @@ extern struct task_group root_task_group;
 
 #ifdef CONFIG_VE
 #define	INIT_TASK_VE(tsk) .task_ve = &ve0,				\
-			  .task_ve_work.func = NULL,
+			  .task_ve_work.func = NULL,			\
+			  .task_ve_mover = NULL, /* zeroes task_ve_nr_works */
 #else
 #define	INIT_TASK_VE(tsk)
 #endif
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 20d2e4e..1a290e0 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1565,6 +1565,10 @@ struct task_struct {
 #ifdef CONFIG_VE
 	struct ve_struct *task_ve;
 	struct callback_head task_ve_work;
+	union {
+		struct task_struct *task_ve_mover;
+		atomic_t task_ve_nr_works;
+	};
 #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 b077751..c2fdc2c 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1380,6 +1380,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 #endif
 #ifdef CONFIG_VE
 	init_task_work(&p->task_ve_work, NULL);
+	p->task_ve_mover = NULL; /* leads to task_ve_nr_works = 0 */
 #endif
 
 	/* Perform scheduler related setup. Assign this task to a CPU. */
diff --git a/kernel/ve/ve.c b/kernel/ve/ve.c
index 23d5482..8ead598 100644
--- a/kernel/ve/ve.c
+++ b/kernel/ve/ve.c
@@ -703,11 +703,25 @@ static void ve_destroy(struct cgroup *cg)
 
 static void ve_attach_work(struct callback_head *head)
 {
+	atomic_t *nr = &current->task_ve_mover->task_ve_nr_works;
+
 	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);
+
+	atomic_dec(nr);
+}
+
+static void ve_wait_work(struct callback_head *head)
+{
+	atomic_t *nr = &current->task_ve_nr_works;
+
+	while (atomic_read(nr))
+		schedule_timeout(1);
+
+	init_task_work(&current->task_ve_work, NULL);
 }
 
 static int ve_can_attach(struct cgroup *cg, struct cgroup_taskset *tset)
@@ -747,6 +761,10 @@ static int ve_can_attach(struct cgroup *cg, struct cgroup_taskset *tset)
 		if (task->task_ve_work.func != NULL)
 			return -EAGAIN;
 	}
+	/* Someone is attaching and waiting for us */
+	if (current->task_ve_work.func == ve_attach_work)
+		return -EAGAIN;
+
 	smp_mb(); /* Pairs with smp_mb() in ve_attach_work() */
 
 	return 0;
@@ -754,6 +772,7 @@ static int ve_can_attach(struct cgroup *cg, struct cgroup_taskset *tset)
 
 static void ve_attach(struct cgroup *cg, struct cgroup_taskset *tset)
 {
+	atomic_t *nr = &current->task_ve_nr_works;
 	struct ve_struct *ve = cgroup_ve(cg);
 	struct task_struct *task;
 
@@ -769,8 +788,21 @@ static void ve_attach(struct cgroup *cg, struct cgroup_taskset *tset)
 		/* Leave parent exec domain */
 		task->parent_exec_id--;
 
-		init_task_work(&task->task_ve_work, ve_attach_work);
-		task_work_add(task, &task->task_ve_work, true);
+		if (task != current) {
+			task->task_ve_mover = current;
+			init_task_work(&task->task_ve_work, ve_attach_work);
+			if (task_work_add(task, &task->task_ve_work, true) == 0)
+				atomic_inc(nr);
+		} else {
+			/* cgroup attach code is OK with changing task_ve */
+			task->task_ve = ve;
+		}
+	}
+
+	task_work_cancel(current, ve_wait_work);
+	if (atomic_read(nr)) {
+		init_task_work(&current->task_ve_work, ve_wait_work);
+		task_work_add(current, &current->task_ve_work, true);
 	}
 }
 




More information about the Devel mailing list