diff options
Diffstat (limited to 'kernel/cgroup_freezer.c')
-rw-r--r-- | kernel/cgroup_freezer.c | 63 |
1 files changed, 28 insertions, 35 deletions
diff --git a/kernel/cgroup_freezer.c b/kernel/cgroup_freezer.c index 213c0351dad8..fcb93fca782d 100644 --- a/kernel/cgroup_freezer.c +++ b/kernel/cgroup_freezer.c | |||
@@ -48,19 +48,17 @@ static inline struct freezer *task_freezer(struct task_struct *task) | |||
48 | struct freezer, css); | 48 | struct freezer, css); |
49 | } | 49 | } |
50 | 50 | ||
51 | static inline int __cgroup_freezing_or_frozen(struct task_struct *task) | 51 | bool cgroup_freezing(struct task_struct *task) |
52 | { | 52 | { |
53 | enum freezer_state state = task_freezer(task)->state; | 53 | enum freezer_state state; |
54 | return (state == CGROUP_FREEZING) || (state == CGROUP_FROZEN); | 54 | bool ret; |
55 | } | ||
56 | 55 | ||
57 | int cgroup_freezing_or_frozen(struct task_struct *task) | 56 | rcu_read_lock(); |
58 | { | 57 | state = task_freezer(task)->state; |
59 | int result; | 58 | ret = state == CGROUP_FREEZING || state == CGROUP_FROZEN; |
60 | task_lock(task); | 59 | rcu_read_unlock(); |
61 | result = __cgroup_freezing_or_frozen(task); | 60 | |
62 | task_unlock(task); | 61 | return ret; |
63 | return result; | ||
64 | } | 62 | } |
65 | 63 | ||
66 | /* | 64 | /* |
@@ -102,9 +100,6 @@ struct cgroup_subsys freezer_subsys; | |||
102 | * freezer_can_attach(): | 100 | * freezer_can_attach(): |
103 | * cgroup_mutex (held by caller of can_attach) | 101 | * cgroup_mutex (held by caller of can_attach) |
104 | * | 102 | * |
105 | * cgroup_freezing_or_frozen(): | ||
106 | * task->alloc_lock (to get task's cgroup) | ||
107 | * | ||
108 | * freezer_fork() (preserving fork() performance means can't take cgroup_mutex): | 103 | * freezer_fork() (preserving fork() performance means can't take cgroup_mutex): |
109 | * freezer->lock | 104 | * freezer->lock |
110 | * sighand->siglock (if the cgroup is freezing) | 105 | * sighand->siglock (if the cgroup is freezing) |
@@ -130,7 +125,7 @@ struct cgroup_subsys freezer_subsys; | |||
130 | * write_lock css_set_lock (cgroup iterator start) | 125 | * write_lock css_set_lock (cgroup iterator start) |
131 | * task->alloc_lock | 126 | * task->alloc_lock |
132 | * read_lock css_set_lock (cgroup iterator start) | 127 | * read_lock css_set_lock (cgroup iterator start) |
133 | * task->alloc_lock (inside thaw_process(), prevents race with refrigerator()) | 128 | * task->alloc_lock (inside __thaw_task(), prevents race with refrigerator()) |
134 | * sighand->siglock | 129 | * sighand->siglock |
135 | */ | 130 | */ |
136 | static struct cgroup_subsys_state *freezer_create(struct cgroup_subsys *ss, | 131 | static struct cgroup_subsys_state *freezer_create(struct cgroup_subsys *ss, |
@@ -150,7 +145,11 @@ static struct cgroup_subsys_state *freezer_create(struct cgroup_subsys *ss, | |||
150 | static void freezer_destroy(struct cgroup_subsys *ss, | 145 | static void freezer_destroy(struct cgroup_subsys *ss, |
151 | struct cgroup *cgroup) | 146 | struct cgroup *cgroup) |
152 | { | 147 | { |
153 | kfree(cgroup_freezer(cgroup)); | 148 | struct freezer *freezer = cgroup_freezer(cgroup); |
149 | |||
150 | if (freezer->state != CGROUP_THAWED) | ||
151 | atomic_dec(&system_freezing_cnt); | ||
152 | kfree(freezer); | ||
154 | } | 153 | } |
155 | 154 | ||
156 | /* task is frozen or will freeze immediately when next it gets woken */ | 155 | /* task is frozen or will freeze immediately when next it gets woken */ |
@@ -184,13 +183,7 @@ static int freezer_can_attach(struct cgroup_subsys *ss, | |||
184 | 183 | ||
185 | static int freezer_can_attach_task(struct cgroup *cgrp, struct task_struct *tsk) | 184 | static int freezer_can_attach_task(struct cgroup *cgrp, struct task_struct *tsk) |
186 | { | 185 | { |
187 | rcu_read_lock(); | 186 | return cgroup_freezing(tsk) ? -EBUSY : 0; |
188 | if (__cgroup_freezing_or_frozen(tsk)) { | ||
189 | rcu_read_unlock(); | ||
190 | return -EBUSY; | ||
191 | } | ||
192 | rcu_read_unlock(); | ||
193 | return 0; | ||
194 | } | 187 | } |
195 | 188 | ||
196 | static void freezer_fork(struct cgroup_subsys *ss, struct task_struct *task) | 189 | static void freezer_fork(struct cgroup_subsys *ss, struct task_struct *task) |
@@ -220,7 +213,7 @@ static void freezer_fork(struct cgroup_subsys *ss, struct task_struct *task) | |||
220 | 213 | ||
221 | /* Locking avoids race with FREEZING -> THAWED transitions. */ | 214 | /* Locking avoids race with FREEZING -> THAWED transitions. */ |
222 | if (freezer->state == CGROUP_FREEZING) | 215 | if (freezer->state == CGROUP_FREEZING) |
223 | freeze_task(task, true); | 216 | freeze_task(task); |
224 | spin_unlock_irq(&freezer->lock); | 217 | spin_unlock_irq(&freezer->lock); |
225 | } | 218 | } |
226 | 219 | ||
@@ -238,7 +231,7 @@ static void update_if_frozen(struct cgroup *cgroup, | |||
238 | cgroup_iter_start(cgroup, &it); | 231 | cgroup_iter_start(cgroup, &it); |
239 | while ((task = cgroup_iter_next(cgroup, &it))) { | 232 | while ((task = cgroup_iter_next(cgroup, &it))) { |
240 | ntotal++; | 233 | ntotal++; |
241 | if (is_task_frozen_enough(task)) | 234 | if (freezing(task) && is_task_frozen_enough(task)) |
242 | nfrozen++; | 235 | nfrozen++; |
243 | } | 236 | } |
244 | 237 | ||
@@ -286,10 +279,9 @@ static int try_to_freeze_cgroup(struct cgroup *cgroup, struct freezer *freezer) | |||
286 | struct task_struct *task; | 279 | struct task_struct *task; |
287 | unsigned int num_cant_freeze_now = 0; | 280 | unsigned int num_cant_freeze_now = 0; |
288 | 281 | ||
289 | freezer->state = CGROUP_FREEZING; | ||
290 | cgroup_iter_start(cgroup, &it); | 282 | cgroup_iter_start(cgroup, &it); |
291 | while ((task = cgroup_iter_next(cgroup, &it))) { | 283 | while ((task = cgroup_iter_next(cgroup, &it))) { |
292 | if (!freeze_task(task, true)) | 284 | if (!freeze_task(task)) |
293 | continue; | 285 | continue; |
294 | if (is_task_frozen_enough(task)) | 286 | if (is_task_frozen_enough(task)) |
295 | continue; | 287 | continue; |
@@ -307,12 +299,9 @@ static void unfreeze_cgroup(struct cgroup *cgroup, struct freezer *freezer) | |||
307 | struct task_struct *task; | 299 | struct task_struct *task; |
308 | 300 | ||
309 | cgroup_iter_start(cgroup, &it); | 301 | cgroup_iter_start(cgroup, &it); |
310 | while ((task = cgroup_iter_next(cgroup, &it))) { | 302 | while ((task = cgroup_iter_next(cgroup, &it))) |
311 | thaw_process(task); | 303 | __thaw_task(task); |
312 | } | ||
313 | cgroup_iter_end(cgroup, &it); | 304 | cgroup_iter_end(cgroup, &it); |
314 | |||
315 | freezer->state = CGROUP_THAWED; | ||
316 | } | 305 | } |
317 | 306 | ||
318 | static int freezer_change_state(struct cgroup *cgroup, | 307 | static int freezer_change_state(struct cgroup *cgroup, |
@@ -326,20 +315,24 @@ static int freezer_change_state(struct cgroup *cgroup, | |||
326 | spin_lock_irq(&freezer->lock); | 315 | spin_lock_irq(&freezer->lock); |
327 | 316 | ||
328 | update_if_frozen(cgroup, freezer); | 317 | update_if_frozen(cgroup, freezer); |
329 | if (goal_state == freezer->state) | ||
330 | goto out; | ||
331 | 318 | ||
332 | switch (goal_state) { | 319 | switch (goal_state) { |
333 | case CGROUP_THAWED: | 320 | case CGROUP_THAWED: |
321 | if (freezer->state != CGROUP_THAWED) | ||
322 | atomic_dec(&system_freezing_cnt); | ||
323 | freezer->state = CGROUP_THAWED; | ||
334 | unfreeze_cgroup(cgroup, freezer); | 324 | unfreeze_cgroup(cgroup, freezer); |
335 | break; | 325 | break; |
336 | case CGROUP_FROZEN: | 326 | case CGROUP_FROZEN: |
327 | if (freezer->state == CGROUP_THAWED) | ||
328 | atomic_inc(&system_freezing_cnt); | ||
329 | freezer->state = CGROUP_FREEZING; | ||
337 | retval = try_to_freeze_cgroup(cgroup, freezer); | 330 | retval = try_to_freeze_cgroup(cgroup, freezer); |
338 | break; | 331 | break; |
339 | default: | 332 | default: |
340 | BUG(); | 333 | BUG(); |
341 | } | 334 | } |
342 | out: | 335 | |
343 | spin_unlock_irq(&freezer->lock); | 336 | spin_unlock_irq(&freezer->lock); |
344 | 337 | ||
345 | return retval; | 338 | return retval; |