diff options
Diffstat (limited to 'kernel/cgroup_freezer.c')
| -rw-r--r-- | kernel/cgroup_freezer.c | 72 |
1 files changed, 32 insertions, 40 deletions
diff --git a/kernel/cgroup_freezer.c b/kernel/cgroup_freezer.c index ce71ed53e88f..e7bebb7c6c38 100644 --- a/kernel/cgroup_freezer.c +++ b/kernel/cgroup_freezer.c | |||
| @@ -48,20 +48,19 @@ static inline struct freezer *task_freezer(struct task_struct *task) | |||
| 48 | struct freezer, css); | 48 | struct freezer, css); |
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | int cgroup_freezing_or_frozen(struct task_struct *task) | 51 | static inline int __cgroup_freezing_or_frozen(struct task_struct *task) |
| 52 | { | 52 | { |
| 53 | struct freezer *freezer; | 53 | enum freezer_state state = task_freezer(task)->state; |
| 54 | enum freezer_state state; | 54 | return (state == CGROUP_FREEZING) || (state == CGROUP_FROZEN); |
| 55 | } | ||
| 55 | 56 | ||
| 57 | int cgroup_freezing_or_frozen(struct task_struct *task) | ||
| 58 | { | ||
| 59 | int result; | ||
| 56 | task_lock(task); | 60 | task_lock(task); |
| 57 | freezer = task_freezer(task); | 61 | result = __cgroup_freezing_or_frozen(task); |
| 58 | if (!freezer->css.cgroup->parent) | ||
| 59 | state = CGROUP_THAWED; /* root cgroup can't be frozen */ | ||
| 60 | else | ||
| 61 | state = freezer->state; | ||
| 62 | task_unlock(task); | 62 | task_unlock(task); |
| 63 | 63 | return result; | |
| 64 | return (state == CGROUP_FREEZING) || (state == CGROUP_FROZEN); | ||
| 65 | } | 64 | } |
| 66 | 65 | ||
| 67 | /* | 66 | /* |
| @@ -154,13 +153,6 @@ static void freezer_destroy(struct cgroup_subsys *ss, | |||
| 154 | kfree(cgroup_freezer(cgroup)); | 153 | kfree(cgroup_freezer(cgroup)); |
| 155 | } | 154 | } |
| 156 | 155 | ||
| 157 | /* Task is frozen or will freeze immediately when next it gets woken */ | ||
| 158 | static bool is_task_frozen_enough(struct task_struct *task) | ||
| 159 | { | ||
| 160 | return frozen(task) || | ||
| 161 | (task_is_stopped_or_traced(task) && freezing(task)); | ||
| 162 | } | ||
| 163 | |||
| 164 | /* | 156 | /* |
| 165 | * The call to cgroup_lock() in the freezer.state write method prevents | 157 | * The call to cgroup_lock() in the freezer.state write method prevents |
| 166 | * a write to that file racing against an attach, and hence the | 158 | * a write to that file racing against an attach, and hence the |
| @@ -174,24 +166,25 @@ static int freezer_can_attach(struct cgroup_subsys *ss, | |||
| 174 | 166 | ||
| 175 | /* | 167 | /* |
| 176 | * Anything frozen can't move or be moved to/from. | 168 | * Anything frozen can't move or be moved to/from. |
| 177 | * | ||
| 178 | * Since orig_freezer->state == FROZEN means that @task has been | ||
| 179 | * frozen, so it's sufficient to check the latter condition. | ||
| 180 | */ | 169 | */ |
| 181 | 170 | ||
| 182 | if (is_task_frozen_enough(task)) | 171 | freezer = cgroup_freezer(new_cgroup); |
| 172 | if (freezer->state != CGROUP_THAWED) | ||
| 183 | return -EBUSY; | 173 | return -EBUSY; |
| 184 | 174 | ||
| 185 | freezer = cgroup_freezer(new_cgroup); | 175 | rcu_read_lock(); |
| 186 | if (freezer->state == CGROUP_FROZEN) | 176 | if (__cgroup_freezing_or_frozen(task)) { |
| 177 | rcu_read_unlock(); | ||
| 187 | return -EBUSY; | 178 | return -EBUSY; |
| 179 | } | ||
| 180 | rcu_read_unlock(); | ||
| 188 | 181 | ||
| 189 | if (threadgroup) { | 182 | if (threadgroup) { |
| 190 | struct task_struct *c; | 183 | struct task_struct *c; |
| 191 | 184 | ||
| 192 | rcu_read_lock(); | 185 | rcu_read_lock(); |
| 193 | list_for_each_entry_rcu(c, &task->thread_group, thread_group) { | 186 | list_for_each_entry_rcu(c, &task->thread_group, thread_group) { |
| 194 | if (is_task_frozen_enough(c)) { | 187 | if (__cgroup_freezing_or_frozen(c)) { |
| 195 | rcu_read_unlock(); | 188 | rcu_read_unlock(); |
| 196 | return -EBUSY; | 189 | return -EBUSY; |
| 197 | } | 190 | } |
| @@ -236,31 +229,30 @@ static void freezer_fork(struct cgroup_subsys *ss, struct task_struct *task) | |||
| 236 | /* | 229 | /* |
| 237 | * caller must hold freezer->lock | 230 | * caller must hold freezer->lock |
| 238 | */ | 231 | */ |
| 239 | static void update_freezer_state(struct cgroup *cgroup, | 232 | static void update_if_frozen(struct cgroup *cgroup, |
| 240 | struct freezer *freezer) | 233 | struct freezer *freezer) |
| 241 | { | 234 | { |
| 242 | struct cgroup_iter it; | 235 | struct cgroup_iter it; |
| 243 | struct task_struct *task; | 236 | struct task_struct *task; |
| 244 | unsigned int nfrozen = 0, ntotal = 0; | 237 | unsigned int nfrozen = 0, ntotal = 0; |
| 238 | enum freezer_state old_state = freezer->state; | ||
| 245 | 239 | ||
| 246 | cgroup_iter_start(cgroup, &it); | 240 | cgroup_iter_start(cgroup, &it); |
| 247 | while ((task = cgroup_iter_next(cgroup, &it))) { | 241 | while ((task = cgroup_iter_next(cgroup, &it))) { |
| 248 | ntotal++; | 242 | ntotal++; |
| 249 | if (is_task_frozen_enough(task)) | 243 | if (frozen(task)) |
| 250 | nfrozen++; | 244 | nfrozen++; |
| 251 | } | 245 | } |
| 252 | 246 | ||
| 253 | /* | 247 | if (old_state == CGROUP_THAWED) { |
| 254 | * Transition to FROZEN when no new tasks can be added ensures | 248 | BUG_ON(nfrozen > 0); |
| 255 | * that we never exist in the FROZEN state while there are unfrozen | 249 | } else if (old_state == CGROUP_FREEZING) { |
| 256 | * tasks. | 250 | if (nfrozen == ntotal) |
| 257 | */ | 251 | freezer->state = CGROUP_FROZEN; |
| 258 | if (nfrozen == ntotal) | 252 | } else { /* old_state == CGROUP_FROZEN */ |
| 259 | freezer->state = CGROUP_FROZEN; | 253 | BUG_ON(nfrozen != ntotal); |
| 260 | else if (nfrozen > 0) | 254 | } |
| 261 | freezer->state = CGROUP_FREEZING; | 255 | |
| 262 | else | ||
| 263 | freezer->state = CGROUP_THAWED; | ||
| 264 | cgroup_iter_end(cgroup, &it); | 256 | cgroup_iter_end(cgroup, &it); |
| 265 | } | 257 | } |
| 266 | 258 | ||
| @@ -279,7 +271,7 @@ static int freezer_read(struct cgroup *cgroup, struct cftype *cft, | |||
| 279 | if (state == CGROUP_FREEZING) { | 271 | if (state == CGROUP_FREEZING) { |
| 280 | /* We change from FREEZING to FROZEN lazily if the cgroup was | 272 | /* We change from FREEZING to FROZEN lazily if the cgroup was |
| 281 | * only partially frozen when we exitted write. */ | 273 | * only partially frozen when we exitted write. */ |
| 282 | update_freezer_state(cgroup, freezer); | 274 | update_if_frozen(cgroup, freezer); |
| 283 | state = freezer->state; | 275 | state = freezer->state; |
| 284 | } | 276 | } |
| 285 | spin_unlock_irq(&freezer->lock); | 277 | spin_unlock_irq(&freezer->lock); |
| @@ -301,7 +293,7 @@ static int try_to_freeze_cgroup(struct cgroup *cgroup, struct freezer *freezer) | |||
| 301 | while ((task = cgroup_iter_next(cgroup, &it))) { | 293 | while ((task = cgroup_iter_next(cgroup, &it))) { |
| 302 | if (!freeze_task(task, true)) | 294 | if (!freeze_task(task, true)) |
| 303 | continue; | 295 | continue; |
| 304 | if (is_task_frozen_enough(task)) | 296 | if (frozen(task)) |
| 305 | continue; | 297 | continue; |
| 306 | if (!freezing(task) && !freezer_should_skip(task)) | 298 | if (!freezing(task) && !freezer_should_skip(task)) |
| 307 | num_cant_freeze_now++; | 299 | num_cant_freeze_now++; |
| @@ -335,7 +327,7 @@ static int freezer_change_state(struct cgroup *cgroup, | |||
| 335 | 327 | ||
| 336 | spin_lock_irq(&freezer->lock); | 328 | spin_lock_irq(&freezer->lock); |
| 337 | 329 | ||
| 338 | update_freezer_state(cgroup, freezer); | 330 | update_if_frozen(cgroup, freezer); |
| 339 | if (goal_state == freezer->state) | 331 | if (goal_state == freezer->state) |
| 340 | goto out; | 332 | goto out; |
| 341 | 333 | ||
