[Devel] [PATCH rh7 v3] ve: Attach a ve cgroup from task_work
Kirill Tkhai
ktkhai at odin.com
Tue Nov 17 04:53:55 PST 2015
There are 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 it definitelly is not using
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/ve.h | 4 ++++
kernel/ve/ve.c | 38 +++++++++++++++++++++++++++++++++++++-
2 files changed, 41 insertions(+), 1 deletion(-)
diff --git a/include/linux/ve.h b/include/linux/ve.h
index 2554337..f4c139a 100644
--- a/include/linux/ve.h
+++ b/include/linux/ve.h
@@ -53,6 +53,10 @@ struct ve_struct {
/* see vzcalluser.h for VE_FEATURE_XXX definitions */
__u64 features;
+ struct callback_head task_attach_work;
+ struct callback_head task_wait_work;
+ struct completion task_completion;
+
struct task_struct *ve_kthread_task;
struct kthread_worker ve_kthread_worker;
diff --git a/kernel/ve/ve.c b/kernel/ve/ve.c
index 8f5f905..8b6c12b 100644
--- a/kernel/ve/ve.c
+++ b/kernel/ve/ve.c
@@ -42,6 +42,7 @@
#include <linux/tty.h>
#include <linux/console.h>
#include <linux/ctype.h>
+#include <linux/task_work.h>
#include <uapi/linux/vzcalluser.h>
#include <linux/venet.h>
@@ -61,8 +62,12 @@ struct kmapset_set ve_sysfs_perms;
static DEFINE_PER_CPU(struct kstat_lat_pcpu_snap_struct, ve0_lat_stats);
+static void task_attach_work(struct callback_head *head);
+
struct ve_struct ve0 = {
.ve_name = "0",
+ .task_attach_work.func = task_attach_work,
+ .task_wait_work.func = NULL,
.start_jiffies = INITIAL_JIFFIES,
.jiffies_fixup = 0,
RCU_POINTER_INITIALIZER(ve_ns, &init_nsproxy),
@@ -656,6 +661,8 @@ static struct cgroup_subsys_state *ve_create(struct cgroup *cg)
INIT_LIST_HEAD(&ve->devmnt_list);
mutex_init(&ve->devmnt_mutex);
kmapset_init_key(&ve->ve_sysfs_perms);
+ init_task_work(&ve->task_attach_work, task_attach_work);
+ init_task_work(&ve->task_wait_work, NULL);
#ifdef CONFIG_AIO
spin_lock_init(&ve->aio_nr_lock);
@@ -745,6 +752,11 @@ static int ve_can_attach(struct cgroup *cg, struct cgroup_taskset *tset)
} else
return -EINVAL;
+ /* Attaching in process? */
+ if (ve->task_wait_work.func != NULL)
+ return -EBUSY;
+ smp_mb(); /* Pairs with smp_mb() in task_wait_work() */
+
return 0;
}
@@ -753,6 +765,23 @@ static void ve_update_cpuid_faulting(void *dummy)
set_cpuid_faulting(!ve_is_super(get_exec_env()));
}
+static void task_attach_work(struct callback_head *head)
+{
+ struct ve_struct *ve = container_of(head, struct ve_struct, task_attach_work);
+
+ current->task_ve = ve;
+ complete(&ve->task_completion);
+}
+
+static void task_wait_work(struct callback_head *head)
+{
+ struct ve_struct *ve = container_of(head, struct ve_struct, task_wait_work);
+
+ wait_for_completion(&ve->task_completion);
+ smp_mb(); /* Pairs with smp_mb() in ve_can_attach() */
+ init_task_work(&ve->task_wait_work, NULL);
+}
+
static void ve_attach(struct cgroup *cg, struct cgroup_taskset *tset)
{
struct ve_struct *ve = cgroup_ve(cg);
@@ -770,7 +799,14 @@ static void ve_attach(struct cgroup *cg, struct cgroup_taskset *tset)
/* Leave parent exec domain */
task->parent_exec_id--;
- task->task_ve = ve;
+ if (cgroup_taskset_first(tset) == current) {
+ task->task_ve = ve;
+ } else {
+ init_completion(&ve->task_completion);
+ task_work_add(task, &ve->task_attach_work, true);
+ init_task_work(&ve->task_wait_work, task_wait_work);
+ task_work_add(current, &ve->task_wait_work, false);
+ }
}
/* Adjust cpuid faulting */
More information about the Devel
mailing list