diff options
Diffstat (limited to 'kernel/cgroup_freezer.c')
-rw-r--r-- | kernel/cgroup_freezer.c | 51 |
1 files changed, 19 insertions, 32 deletions
diff --git a/kernel/cgroup_freezer.c b/kernel/cgroup_freezer.c index e95056954498..7fa476f01d05 100644 --- a/kernel/cgroup_freezer.c +++ b/kernel/cgroup_freezer.c | |||
@@ -162,9 +162,13 @@ static int freezer_can_attach(struct cgroup_subsys *ss, | |||
162 | struct task_struct *task) | 162 | struct task_struct *task) |
163 | { | 163 | { |
164 | struct freezer *freezer; | 164 | struct freezer *freezer; |
165 | int retval; | ||
166 | 165 | ||
167 | /* Anything frozen can't move or be moved to/from */ | 166 | /* |
167 | * Anything frozen can't move or be moved to/from. | ||
168 | * | ||
169 | * Since orig_freezer->state == FROZEN means that @task has been | ||
170 | * frozen, so it's sufficient to check the latter condition. | ||
171 | */ | ||
168 | 172 | ||
169 | if (is_task_frozen_enough(task)) | 173 | if (is_task_frozen_enough(task)) |
170 | return -EBUSY; | 174 | return -EBUSY; |
@@ -173,13 +177,7 @@ static int freezer_can_attach(struct cgroup_subsys *ss, | |||
173 | if (freezer->state == CGROUP_FROZEN) | 177 | if (freezer->state == CGROUP_FROZEN) |
174 | return -EBUSY; | 178 | return -EBUSY; |
175 | 179 | ||
176 | retval = 0; | 180 | return 0; |
177 | task_lock(task); | ||
178 | freezer = task_freezer(task); | ||
179 | if (freezer->state == CGROUP_FROZEN) | ||
180 | retval = -EBUSY; | ||
181 | task_unlock(task); | ||
182 | return retval; | ||
183 | } | 181 | } |
184 | 182 | ||
185 | static void freezer_fork(struct cgroup_subsys *ss, struct task_struct *task) | 183 | static void freezer_fork(struct cgroup_subsys *ss, struct task_struct *task) |
@@ -190,8 +188,9 @@ static void freezer_fork(struct cgroup_subsys *ss, struct task_struct *task) | |||
190 | freezer = task_freezer(task); | 188 | freezer = task_freezer(task); |
191 | task_unlock(task); | 189 | task_unlock(task); |
192 | 190 | ||
193 | BUG_ON(freezer->state == CGROUP_FROZEN); | ||
194 | spin_lock_irq(&freezer->lock); | 191 | spin_lock_irq(&freezer->lock); |
192 | BUG_ON(freezer->state == CGROUP_FROZEN); | ||
193 | |||
195 | /* Locking avoids race with FREEZING -> THAWED transitions. */ | 194 | /* Locking avoids race with FREEZING -> THAWED transitions. */ |
196 | if (freezer->state == CGROUP_FREEZING) | 195 | if (freezer->state == CGROUP_FREEZING) |
197 | freeze_task(task, true); | 196 | freeze_task(task, true); |
@@ -276,25 +275,18 @@ static int try_to_freeze_cgroup(struct cgroup *cgroup, struct freezer *freezer) | |||
276 | return num_cant_freeze_now ? -EBUSY : 0; | 275 | return num_cant_freeze_now ? -EBUSY : 0; |
277 | } | 276 | } |
278 | 277 | ||
279 | static int unfreeze_cgroup(struct cgroup *cgroup, struct freezer *freezer) | 278 | static void unfreeze_cgroup(struct cgroup *cgroup, struct freezer *freezer) |
280 | { | 279 | { |
281 | struct cgroup_iter it; | 280 | struct cgroup_iter it; |
282 | struct task_struct *task; | 281 | struct task_struct *task; |
283 | 282 | ||
284 | cgroup_iter_start(cgroup, &it); | 283 | cgroup_iter_start(cgroup, &it); |
285 | while ((task = cgroup_iter_next(cgroup, &it))) { | 284 | while ((task = cgroup_iter_next(cgroup, &it))) { |
286 | int do_wake; | 285 | thaw_process(task); |
287 | |||
288 | task_lock(task); | ||
289 | do_wake = __thaw_process(task); | ||
290 | task_unlock(task); | ||
291 | if (do_wake) | ||
292 | wake_up_process(task); | ||
293 | } | 286 | } |
294 | cgroup_iter_end(cgroup, &it); | 287 | cgroup_iter_end(cgroup, &it); |
295 | freezer->state = CGROUP_THAWED; | ||
296 | 288 | ||
297 | return 0; | 289 | freezer->state = CGROUP_THAWED; |
298 | } | 290 | } |
299 | 291 | ||
300 | static int freezer_change_state(struct cgroup *cgroup, | 292 | static int freezer_change_state(struct cgroup *cgroup, |
@@ -304,27 +296,22 @@ static int freezer_change_state(struct cgroup *cgroup, | |||
304 | int retval = 0; | 296 | int retval = 0; |
305 | 297 | ||
306 | freezer = cgroup_freezer(cgroup); | 298 | freezer = cgroup_freezer(cgroup); |
299 | |||
307 | spin_lock_irq(&freezer->lock); | 300 | spin_lock_irq(&freezer->lock); |
301 | |||
308 | update_freezer_state(cgroup, freezer); | 302 | update_freezer_state(cgroup, freezer); |
309 | if (goal_state == freezer->state) | 303 | if (goal_state == freezer->state) |
310 | goto out; | 304 | goto out; |
311 | switch (freezer->state) { | 305 | |
306 | switch (goal_state) { | ||
312 | case CGROUP_THAWED: | 307 | case CGROUP_THAWED: |
313 | retval = try_to_freeze_cgroup(cgroup, freezer); | 308 | unfreeze_cgroup(cgroup, freezer); |
314 | break; | 309 | break; |
315 | case CGROUP_FREEZING: | ||
316 | if (goal_state == CGROUP_FROZEN) { | ||
317 | /* Userspace is retrying after | ||
318 | * "/bin/echo FROZEN > freezer.state" returned -EBUSY */ | ||
319 | retval = try_to_freeze_cgroup(cgroup, freezer); | ||
320 | break; | ||
321 | } | ||
322 | /* state == FREEZING and goal_state == THAWED, so unfreeze */ | ||
323 | case CGROUP_FROZEN: | 310 | case CGROUP_FROZEN: |
324 | retval = unfreeze_cgroup(cgroup, freezer); | 311 | retval = try_to_freeze_cgroup(cgroup, freezer); |
325 | break; | 312 | break; |
326 | default: | 313 | default: |
327 | break; | 314 | BUG(); |
328 | } | 315 | } |
329 | out: | 316 | out: |
330 | spin_unlock_irq(&freezer->lock); | 317 | spin_unlock_irq(&freezer->lock); |