diff options
author | Tejun Heo <tj@kernel.org> | 2012-10-16 18:03:14 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2012-10-20 19:28:56 -0400 |
commit | 8755ade683241e8c6b8fe8d22d0ae35041a3dc51 (patch) | |
tree | 34b0aaa3f6575d7edaf11cf18142399eaab70374 /kernel/cgroup_freezer.c | |
parent | 3c426d5e114035d00453bb5d82a92826db1ed71f (diff) |
cgroup_freezer: allow moving tasks in and out of a frozen cgroup
cgroup_freezer is one of the few users of cgroup_subsys->can_attach()
and uses it to prevent tasks from being migrated into or out of a
frozen cgroup. This makes cgroup_freezer cumbersome to use especially
when co-mounted with other controllers.
->can_attach() is problematic in general as it can make co-mounting
multiple cgroups difficult - migrating tasks may fail for reasons
completely irrelevant for other controllers. freezer_can_attach() in
particular is more problematic because it messes with cgroup internal
locking to ensure that the state verification performed at
freezer_can_attach() stays valid until migration is complete.
This patch replaces freezer_can_attach() with freezer_attach() so that
tasks are always allowed to migrate - they are nudged into the
conforming state from freezer_attach(). This means that there can be
tasks which are being migrated which don't conform to the current
cgroup_freezer state until freezer_attach() is complete. Under the
current locking scheme, the only such place is freezer_fork() which is
updated to handle such window.
While this patch doesn't remove the use of internal cgroup locking
from freezer_read/write() paths, it removes the requirement to keep
the freezer state constant while migrating and enables such change.
Note that this creates a userland visible behavior change - FROZEN
cgroup can no longer be used to lock migrations in and out of the
cgroup. This behavior change is intended. I don't think the feature
is necessary - userland should coordinate accesses to cgroup fs anyway
- and even if the feature is needed cgroup_freezer is the completely
wrong place to implement it.
Signed-off-by: Tejun Heo <tj@kernel.org>
LKML-Reference: <1350426526-14254-1-git-send-email-tj@kernel.org>
Cc: Matt Helsley <matthltc@linux.vnet.ibm.com>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Rafael J. Wysocki <rjw@sisk.pl>
Cc: Li Zefan <lizefan@huawei.com>
Diffstat (limited to 'kernel/cgroup_freezer.c')
-rw-r--r-- | kernel/cgroup_freezer.c | 51 |
1 files changed, 31 insertions, 20 deletions
diff --git a/kernel/cgroup_freezer.c b/kernel/cgroup_freezer.c index 557f3678c4e4..0b0e10545ef0 100644 --- a/kernel/cgroup_freezer.c +++ b/kernel/cgroup_freezer.c | |||
@@ -152,27 +152,38 @@ static void freezer_destroy(struct cgroup *cgroup) | |||
152 | 152 | ||
153 | /* | 153 | /* |
154 | * The call to cgroup_lock() in the freezer.state write method prevents | 154 | * The call to cgroup_lock() in the freezer.state write method prevents |
155 | * a write to that file racing against an attach, and hence the | 155 | * a write to that file racing against an attach, and hence we don't need |
156 | * can_attach() result will remain valid until the attach completes. | 156 | * to worry about racing against migration. |
157 | */ | 157 | */ |
158 | static int freezer_can_attach(struct cgroup *new_cgroup, | 158 | static void freezer_attach(struct cgroup *new_cgrp, struct cgroup_taskset *tset) |
159 | struct cgroup_taskset *tset) | ||
160 | { | 159 | { |
161 | struct freezer *freezer; | 160 | struct freezer *freezer = cgroup_freezer(new_cgrp); |
162 | struct task_struct *task; | 161 | struct task_struct *task; |
163 | 162 | ||
163 | spin_lock_irq(&freezer->lock); | ||
164 | |||
164 | /* | 165 | /* |
165 | * Anything frozen can't move or be moved to/from. | 166 | * Make the new tasks conform to the current state of @new_cgrp. |
167 | * For simplicity, when migrating any task to a FROZEN cgroup, we | ||
168 | * revert it to FREEZING and let update_if_frozen() determine the | ||
169 | * correct state later. | ||
170 | * | ||
171 | * Tasks in @tset are on @new_cgrp but may not conform to its | ||
172 | * current state before executing the following - !frozen tasks may | ||
173 | * be visible in a FROZEN cgroup and frozen tasks in a THAWED one. | ||
174 | * This means that, to determine whether to freeze, one should test | ||
175 | * whether the state equals THAWED. | ||
166 | */ | 176 | */ |
167 | cgroup_taskset_for_each(task, new_cgroup, tset) | 177 | cgroup_taskset_for_each(task, new_cgrp, tset) { |
168 | if (cgroup_freezing(task)) | 178 | if (freezer->state == CGROUP_THAWED) { |
169 | return -EBUSY; | 179 | __thaw_task(task); |
170 | 180 | } else { | |
171 | freezer = cgroup_freezer(new_cgroup); | 181 | freeze_task(task); |
172 | if (freezer->state != CGROUP_THAWED) | 182 | freezer->state = CGROUP_FREEZING; |
173 | return -EBUSY; | 183 | } |
184 | } | ||
174 | 185 | ||
175 | return 0; | 186 | spin_unlock_irq(&freezer->lock); |
176 | } | 187 | } |
177 | 188 | ||
178 | static void freezer_fork(struct task_struct *task) | 189 | static void freezer_fork(struct task_struct *task) |
@@ -190,12 +201,12 @@ static void freezer_fork(struct task_struct *task) | |||
190 | goto out; | 201 | goto out; |
191 | 202 | ||
192 | spin_lock_irq(&freezer->lock); | 203 | spin_lock_irq(&freezer->lock); |
193 | BUG_ON(freezer->state == CGROUP_FROZEN); | 204 | /* |
194 | 205 | * @task might have been just migrated into a FROZEN cgroup. Test | |
195 | /* Locking avoids race with FREEZING -> THAWED transitions. */ | 206 | * equality with THAWED. Read the comment in freezer_attach(). |
196 | if (freezer->state == CGROUP_FREEZING) | 207 | */ |
208 | if (freezer->state != CGROUP_THAWED) | ||
197 | freeze_task(task); | 209 | freeze_task(task); |
198 | |||
199 | spin_unlock_irq(&freezer->lock); | 210 | spin_unlock_irq(&freezer->lock); |
200 | out: | 211 | out: |
201 | rcu_read_unlock(); | 212 | rcu_read_unlock(); |
@@ -352,7 +363,7 @@ struct cgroup_subsys freezer_subsys = { | |||
352 | .create = freezer_create, | 363 | .create = freezer_create, |
353 | .destroy = freezer_destroy, | 364 | .destroy = freezer_destroy, |
354 | .subsys_id = freezer_subsys_id, | 365 | .subsys_id = freezer_subsys_id, |
355 | .can_attach = freezer_can_attach, | 366 | .attach = freezer_attach, |
356 | .fork = freezer_fork, | 367 | .fork = freezer_fork, |
357 | .base_cftypes = files, | 368 | .base_cftypes = files, |
358 | 369 | ||