|
@@ -213,41 +213,39 @@ out:
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * caller must hold freezer->lock
|
|
|
+ * We change from FREEZING to FROZEN lazily if the cgroup was only
|
|
|
+ * partially frozen when we exitted write. Caller must hold freezer->lock.
|
|
|
+ *
|
|
|
+ * Task states and freezer state might disagree while tasks are being
|
|
|
+ * migrated into @cgroup, so we can't verify task states against @freezer
|
|
|
+ * state here. See freezer_attach() for details.
|
|
|
*/
|
|
|
-static void update_if_frozen(struct cgroup *cgroup,
|
|
|
- struct freezer *freezer)
|
|
|
+static void update_if_frozen(struct cgroup *cgroup, struct freezer *freezer)
|
|
|
{
|
|
|
struct cgroup_iter it;
|
|
|
struct task_struct *task;
|
|
|
- unsigned int nfrozen = 0, ntotal = 0;
|
|
|
- enum freezer_state old_state = freezer->state;
|
|
|
+
|
|
|
+ if (freezer->state != CGROUP_FREEZING)
|
|
|
+ return;
|
|
|
|
|
|
cgroup_iter_start(cgroup, &it);
|
|
|
+
|
|
|
while ((task = cgroup_iter_next(cgroup, &it))) {
|
|
|
if (freezing(task)) {
|
|
|
- ntotal++;
|
|
|
/*
|
|
|
* freezer_should_skip() indicates that the task
|
|
|
* should be skipped when determining freezing
|
|
|
* completion. Consider it frozen in addition to
|
|
|
* the usual frozen condition.
|
|
|
*/
|
|
|
- if (frozen(task) || task_is_stopped_or_traced(task) ||
|
|
|
- freezer_should_skip(task))
|
|
|
- nfrozen++;
|
|
|
+ if (!frozen(task) && !task_is_stopped_or_traced(task) &&
|
|
|
+ !freezer_should_skip(task))
|
|
|
+ goto notyet;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (old_state == CGROUP_THAWED) {
|
|
|
- BUG_ON(nfrozen > 0);
|
|
|
- } else if (old_state == CGROUP_FREEZING) {
|
|
|
- if (nfrozen == ntotal)
|
|
|
- freezer->state = CGROUP_FROZEN;
|
|
|
- } else { /* old_state == CGROUP_FROZEN */
|
|
|
- BUG_ON(nfrozen != ntotal);
|
|
|
- }
|
|
|
-
|
|
|
+ freezer->state = CGROUP_FROZEN;
|
|
|
+notyet:
|
|
|
cgroup_iter_end(cgroup, &it);
|
|
|
}
|
|
|
|
|
@@ -262,13 +260,8 @@ static int freezer_read(struct cgroup *cgroup, struct cftype *cft,
|
|
|
|
|
|
freezer = cgroup_freezer(cgroup);
|
|
|
spin_lock_irq(&freezer->lock);
|
|
|
+ update_if_frozen(cgroup, freezer);
|
|
|
state = freezer->state;
|
|
|
- if (state == CGROUP_FREEZING) {
|
|
|
- /* We change from FREEZING to FROZEN lazily if the cgroup was
|
|
|
- * only partially frozen when we exitted write. */
|
|
|
- update_if_frozen(cgroup, freezer);
|
|
|
- state = freezer->state;
|
|
|
- }
|
|
|
spin_unlock_irq(&freezer->lock);
|
|
|
cgroup_unlock();
|
|
|
|
|
@@ -306,8 +299,6 @@ static void freezer_change_state(struct cgroup *cgroup,
|
|
|
|
|
|
spin_lock_irq(&freezer->lock);
|
|
|
|
|
|
- update_if_frozen(cgroup, freezer);
|
|
|
-
|
|
|
switch (goal_state) {
|
|
|
case CGROUP_THAWED:
|
|
|
if (freezer->state != CGROUP_THAWED)
|