[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 = ¤t->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(¤t->task_ve_work, NULL);
+
+ atomic_dec(nr);
+}
+
+static void ve_wait_work(struct callback_head *head)
+{
+ atomic_t *nr = ¤t->task_ve_nr_works;
+
+ while (atomic_read(nr))
+ schedule_timeout(1);
+
+ init_task_work(¤t->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 = ¤t->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(¤t->task_ve_work, ve_wait_work);
+ task_work_add(current, ¤t->task_ve_work, true);
}
}
More information about the Devel
mailing list