workqueue: CPU hotplug keep idle workers
[linux-2.6.git] / kernel / cgroup_freezer.c
index e6a1b8d..5c248e5 100644 (file)
@@ -128,8 +128,7 @@ struct cgroup_subsys freezer_subsys;
  *    task->alloc_lock (inside __thaw_task(), prevents race with refrigerator())
  *     sighand->siglock
  */
-static struct cgroup_subsys_state *freezer_create(struct cgroup_subsys *ss,
-                                                 struct cgroup *cgroup)
+static struct cgroup_subsys_state *freezer_create(struct cgroup *cgroup)
 {
        struct freezer *freezer;
 
@@ -142,10 +141,20 @@ static struct cgroup_subsys_state *freezer_create(struct cgroup_subsys *ss,
        return &freezer->css;
 }
 
-static void freezer_destroy(struct cgroup_subsys *ss,
-                           struct cgroup *cgroup)
+static void freezer_destroy(struct cgroup *cgroup)
 {
-       kfree(cgroup_freezer(cgroup));
+       struct freezer *freezer = cgroup_freezer(cgroup);
+
+       if (freezer->state != CGROUP_THAWED)
+               atomic_dec(&system_freezing_cnt);
+       kfree(freezer);
+}
+
+/* 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));
 }
 
 /*
@@ -153,15 +162,26 @@ static void freezer_destroy(struct cgroup_subsys *ss,
  * 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)
+static int freezer_can_attach(struct cgroup *new_cgroup,
+                             struct cgroup_taskset *tset)
 {
        struct freezer *freezer;
+       struct task_struct *task;
+
+       if ((current != task) && (!capable(CAP_SYS_ADMIN))) {
+               const struct cred *cred = current_cred(), *tcred;
+
+               tcred = __task_cred(task);
+               if (cred->euid != tcred->uid && cred->euid != tcred->suid)
+                       return -EPERM;
+       }
 
        /*
         * Anything frozen can't move or be moved to/from.
         */
+       cgroup_taskset_for_each(task, new_cgroup, tset)
+               if (cgroup_freezing(task))
+                       return -EBUSY;
 
        freezer = cgroup_freezer(new_cgroup);
        if (freezer->state != CGROUP_THAWED)
@@ -170,12 +190,7 @@ static int freezer_can_attach(struct cgroup_subsys *ss,
        return 0;
 }
 
-static int freezer_can_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
-{
-       return cgroup_freezing(tsk) ? -EBUSY : 0;
-}
-
-static void freezer_fork(struct cgroup_subsys *ss, struct task_struct *task)
+static void freezer_fork(struct task_struct *task)
 {
        struct freezer *freezer;
 
@@ -202,7 +217,7 @@ static void freezer_fork(struct cgroup_subsys *ss, struct task_struct *task)
 
        /* Locking avoids race with FREEZING -> THAWED transitions. */
        if (freezer->state == CGROUP_FREEZING)
-               freeze_task(task, true);
+               freeze_task(task);
        spin_unlock_irq(&freezer->lock);
 }
 
@@ -220,7 +235,7 @@ static void update_if_frozen(struct cgroup *cgroup,
        cgroup_iter_start(cgroup, &it);
        while ((task = cgroup_iter_next(cgroup, &it))) {
                ntotal++;
-               if (freezing(task) && frozen(task))
+               if (freezing(task) && is_task_frozen_enough(task))
                        nfrozen++;
        }
 
@@ -270,9 +285,9 @@ static int try_to_freeze_cgroup(struct cgroup *cgroup, struct freezer *freezer)
 
        cgroup_iter_start(cgroup, &it);
        while ((task = cgroup_iter_next(cgroup, &it))) {
-               if (!freeze_task(task, true))
+               if (!freeze_task(task))
                        continue;
-               if (frozen(task))
+               if (is_task_frozen_enough(task))
                        continue;
                if (!freezing(task) && !freezer_should_skip(task))
                        num_cant_freeze_now++;
@@ -307,10 +322,14 @@ static int freezer_change_state(struct cgroup *cgroup,
 
        switch (goal_state) {
        case CGROUP_THAWED:
+               if (freezer->state != CGROUP_THAWED)
+                       atomic_dec(&system_freezing_cnt);
                freezer->state = CGROUP_THAWED;
                unfreeze_cgroup(cgroup, freezer);
                break;
        case CGROUP_FROZEN:
+               if (freezer->state == CGROUP_THAWED)
+                       atomic_inc(&system_freezing_cnt);
                freezer->state = CGROUP_FREEZING;
                retval = try_to_freeze_cgroup(cgroup, freezer);
                break;
@@ -366,10 +385,5 @@ struct cgroup_subsys freezer_subsys = {
        .populate       = freezer_populate,
        .subsys_id      = freezer_subsys_id,
        .can_attach     = freezer_can_attach,
-       .can_attach_task = freezer_can_attach_task,
-       .pre_attach     = NULL,
-       .attach_task    = NULL,
-       .attach         = NULL,
        .fork           = freezer_fork,
-       .exit           = NULL,
 };