]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - kernel/cgroup_freezer.c
container freezer: prevent frozen tasks or cgroups from changing
[net-next-2.6.git] / kernel / cgroup_freezer.c
index b08722de610c38aa41ef0fcbb125e8c63eb48749..df884022fbd9dbd12e025782c773f77e8f5b938a 100644 (file)
@@ -145,22 +145,40 @@ static void freezer_destroy(struct cgroup_subsys *ss,
        kfree(cgroup_freezer(cgroup));
 }
 
+/* Task is frozen or will freeze immediately when next it gets woken */
+static bool is_task_frozen_enough(struct task_struct *task)
+{
+       return frozen(task) ||
+               (task_is_stopped_or_traced(task) && freezing(task));
+}
 
+/*
+ * The call to cgroup_lock() in the freezer.state write method prevents
+ * a write to that file racing against an attach, and hence the
+ * can_attach() result will remain valid until the attach completes.
+ */
 static int freezer_can_attach(struct cgroup_subsys *ss,
                              struct cgroup *new_cgroup,
                              struct task_struct *task)
 {
        struct freezer *freezer;
-       int retval = 0;
+       int retval;
+
+       /* Anything frozen can't move or be moved to/from */
+
+       if (is_task_frozen_enough(task))
+               return -EBUSY;
 
-       /*
-        * The call to cgroup_lock() in the freezer.state write method prevents
-        * a write to that file racing against an attach, and hence the
-        * can_attach() result will remain valid until the attach completes.
-        */
        freezer = cgroup_freezer(new_cgroup);
+       if (freezer->state == STATE_FROZEN)
+               return -EBUSY;
+
+       retval = 0;
+       task_lock(task);
+       freezer = task_freezer(task);
        if (freezer->state == STATE_FROZEN)
                retval = -EBUSY;
+       task_unlock(task);
        return retval;
 }
 
@@ -193,12 +211,7 @@ static void check_if_frozen(struct cgroup *cgroup,
        cgroup_iter_start(cgroup, &it);
        while ((task = cgroup_iter_next(cgroup, &it))) {
                ntotal++;
-               /*
-                * Task is frozen or will freeze immediately when next it gets
-                * woken
-                */
-               if (frozen(task) ||
-                   (task_is_stopped_or_traced(task) && freezing(task)))
+               if (is_task_frozen_enough(task))
                        nfrozen++;
        }
 
@@ -249,11 +262,7 @@ static int try_to_freeze_cgroup(struct cgroup *cgroup, struct freezer *freezer)
        while ((task = cgroup_iter_next(cgroup, &it))) {
                if (!freeze_task(task, true))
                        continue;
-               if (task_is_stopped_or_traced(task) && freezing(task))
-                       /*
-                        * The freeze flag is set so these tasks will
-                        * immediately go into the fridge upon waking.
-                        */
+               if (is_task_frozen_enough(task))
                        continue;
                if (!freezing(task) && !freezer_should_skip(task))
                        num_cant_freeze_now++;