diff options
Diffstat (limited to 'kernel/cgroup_freezer.c')
| -rw-r--r-- | kernel/cgroup_freezer.c | 70 |
1 files changed, 35 insertions, 35 deletions
diff --git a/kernel/cgroup_freezer.c b/kernel/cgroup_freezer.c index e9505695449..fb249e2bcad 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,25 +177,31 @@ 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) |
| 186 | { | 184 | { |
| 187 | struct freezer *freezer; | 185 | struct freezer *freezer; |
| 188 | 186 | ||
| 189 | task_lock(task); | 187 | /* |
| 188 | * No lock is needed, since the task isn't on tasklist yet, | ||
| 189 | * so it can't be moved to another cgroup, which means the | ||
| 190 | * freezer won't be removed and will be valid during this | ||
| 191 | * function call. | ||
| 192 | */ | ||
| 190 | freezer = task_freezer(task); | 193 | freezer = task_freezer(task); |
| 191 | task_unlock(task); | ||
| 192 | 194 | ||
| 193 | BUG_ON(freezer->state == CGROUP_FROZEN); | 195 | /* |
| 196 | * The root cgroup is non-freezable, so we can skip the | ||
| 197 | * following check. | ||
| 198 | */ | ||
| 199 | if (!freezer->css.cgroup->parent) | ||
| 200 | return; | ||
| 201 | |||
| 194 | spin_lock_irq(&freezer->lock); | 202 | spin_lock_irq(&freezer->lock); |
| 203 | BUG_ON(freezer->state == CGROUP_FROZEN); | ||
| 204 | |||
| 195 | /* Locking avoids race with FREEZING -> THAWED transitions. */ | 205 | /* Locking avoids race with FREEZING -> THAWED transitions. */ |
| 196 | if (freezer->state == CGROUP_FREEZING) | 206 | if (freezer->state == CGROUP_FREEZING) |
| 197 | freeze_task(task, true); | 207 | freeze_task(task, true); |
| @@ -276,25 +286,18 @@ static int try_to_freeze_cgroup(struct cgroup *cgroup, struct freezer *freezer) | |||
| 276 | return num_cant_freeze_now ? -EBUSY : 0; | 286 | return num_cant_freeze_now ? -EBUSY : 0; |
| 277 | } | 287 | } |
| 278 | 288 | ||
| 279 | static int unfreeze_cgroup(struct cgroup *cgroup, struct freezer *freezer) | 289 | static void unfreeze_cgroup(struct cgroup *cgroup, struct freezer *freezer) |
| 280 | { | 290 | { |
| 281 | struct cgroup_iter it; | 291 | struct cgroup_iter it; |
| 282 | struct task_struct *task; | 292 | struct task_struct *task; |
| 283 | 293 | ||
| 284 | cgroup_iter_start(cgroup, &it); | 294 | cgroup_iter_start(cgroup, &it); |
| 285 | while ((task = cgroup_iter_next(cgroup, &it))) { | 295 | while ((task = cgroup_iter_next(cgroup, &it))) { |
| 286 | int do_wake; | 296 | 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 | } | 297 | } |
| 294 | cgroup_iter_end(cgroup, &it); | 298 | cgroup_iter_end(cgroup, &it); |
| 295 | freezer->state = CGROUP_THAWED; | ||
| 296 | 299 | ||
| 297 | return 0; | 300 | freezer->state = CGROUP_THAWED; |
| 298 | } | 301 | } |
| 299 | 302 | ||
| 300 | static int freezer_change_state(struct cgroup *cgroup, | 303 | static int freezer_change_state(struct cgroup *cgroup, |
| @@ -304,27 +307,22 @@ static int freezer_change_state(struct cgroup *cgroup, | |||
| 304 | int retval = 0; | 307 | int retval = 0; |
| 305 | 308 | ||
| 306 | freezer = cgroup_freezer(cgroup); | 309 | freezer = cgroup_freezer(cgroup); |
| 310 | |||
| 307 | spin_lock_irq(&freezer->lock); | 311 | spin_lock_irq(&freezer->lock); |
| 312 | |||
| 308 | update_freezer_state(cgroup, freezer); | 313 | update_freezer_state(cgroup, freezer); |
| 309 | if (goal_state == freezer->state) | 314 | if (goal_state == freezer->state) |
| 310 | goto out; | 315 | goto out; |
| 311 | switch (freezer->state) { | 316 | |
| 317 | switch (goal_state) { | ||
| 312 | case CGROUP_THAWED: | 318 | case CGROUP_THAWED: |
| 313 | retval = try_to_freeze_cgroup(cgroup, freezer); | 319 | unfreeze_cgroup(cgroup, freezer); |
| 314 | break; | 320 | 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: | 321 | case CGROUP_FROZEN: |
| 324 | retval = unfreeze_cgroup(cgroup, freezer); | 322 | retval = try_to_freeze_cgroup(cgroup, freezer); |
| 325 | break; | 323 | break; |
| 326 | default: | 324 | default: |
| 327 | break; | 325 | BUG(); |
| 328 | } | 326 | } |
| 329 | out: | 327 | out: |
| 330 | spin_unlock_irq(&freezer->lock); | 328 | spin_unlock_irq(&freezer->lock); |
| @@ -344,7 +342,7 @@ static int freezer_write(struct cgroup *cgroup, | |||
| 344 | else if (strcmp(buffer, freezer_state_strs[CGROUP_FROZEN]) == 0) | 342 | else if (strcmp(buffer, freezer_state_strs[CGROUP_FROZEN]) == 0) |
| 345 | goal_state = CGROUP_FROZEN; | 343 | goal_state = CGROUP_FROZEN; |
| 346 | else | 344 | else |
| 347 | return -EIO; | 345 | return -EINVAL; |
| 348 | 346 | ||
| 349 | if (!cgroup_lock_live_group(cgroup)) | 347 | if (!cgroup_lock_live_group(cgroup)) |
| 350 | return -ENODEV; | 348 | return -ENODEV; |
| @@ -363,6 +361,8 @@ static struct cftype files[] = { | |||
| 363 | 361 | ||
| 364 | static int freezer_populate(struct cgroup_subsys *ss, struct cgroup *cgroup) | 362 | static int freezer_populate(struct cgroup_subsys *ss, struct cgroup *cgroup) |
| 365 | { | 363 | { |
| 364 | if (!cgroup->parent) | ||
| 365 | return 0; | ||
| 366 | return cgroup_add_files(cgroup, ss, files, ARRAY_SIZE(files)); | 366 | return cgroup_add_files(cgroup, ss, files, ARRAY_SIZE(files)); |
| 367 | } | 367 | } |
| 368 | 368 | ||
