diff options
Diffstat (limited to 'kernel/cgroup_freezer.c')
-rw-r--r-- | kernel/cgroup_freezer.c | 77 |
1 files changed, 32 insertions, 45 deletions
diff --git a/kernel/cgroup_freezer.c b/kernel/cgroup_freezer.c index 213c0351dad8..fc0646b78a64 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 */ |
@@ -167,13 +166,17 @@ static bool is_task_frozen_enough(struct task_struct *task) | |||
167 | */ | 166 | */ |
168 | static int freezer_can_attach(struct cgroup_subsys *ss, | 167 | static int freezer_can_attach(struct cgroup_subsys *ss, |
169 | struct cgroup *new_cgroup, | 168 | struct cgroup *new_cgroup, |
170 | struct task_struct *task) | 169 | struct cgroup_taskset *tset) |
171 | { | 170 | { |
172 | struct freezer *freezer; | 171 | struct freezer *freezer; |
172 | struct task_struct *task; | ||
173 | 173 | ||
174 | /* | 174 | /* |
175 | * Anything frozen can't move or be moved to/from. | 175 | * Anything frozen can't move or be moved to/from. |
176 | */ | 176 | */ |
177 | cgroup_taskset_for_each(task, new_cgroup, tset) | ||
178 | if (cgroup_freezing(task)) | ||
179 | return -EBUSY; | ||
177 | 180 | ||
178 | freezer = cgroup_freezer(new_cgroup); | 181 | freezer = cgroup_freezer(new_cgroup); |
179 | if (freezer->state != CGROUP_THAWED) | 182 | if (freezer->state != CGROUP_THAWED) |
@@ -182,17 +185,6 @@ static int freezer_can_attach(struct cgroup_subsys *ss, | |||
182 | return 0; | 185 | return 0; |
183 | } | 186 | } |
184 | 187 | ||
185 | static int freezer_can_attach_task(struct cgroup *cgrp, struct task_struct *tsk) | ||
186 | { | ||
187 | rcu_read_lock(); | ||
188 | if (__cgroup_freezing_or_frozen(tsk)) { | ||
189 | rcu_read_unlock(); | ||
190 | return -EBUSY; | ||
191 | } | ||
192 | rcu_read_unlock(); | ||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | static void freezer_fork(struct cgroup_subsys *ss, struct task_struct *task) | 188 | static void freezer_fork(struct cgroup_subsys *ss, struct task_struct *task) |
197 | { | 189 | { |
198 | struct freezer *freezer; | 190 | struct freezer *freezer; |
@@ -220,7 +212,7 @@ static void freezer_fork(struct cgroup_subsys *ss, struct task_struct *task) | |||
220 | 212 | ||
221 | /* Locking avoids race with FREEZING -> THAWED transitions. */ | 213 | /* Locking avoids race with FREEZING -> THAWED transitions. */ |
222 | if (freezer->state == CGROUP_FREEZING) | 214 | if (freezer->state == CGROUP_FREEZING) |
223 | freeze_task(task, true); | 215 | freeze_task(task); |
224 | spin_unlock_irq(&freezer->lock); | 216 | spin_unlock_irq(&freezer->lock); |
225 | } | 217 | } |
226 | 218 | ||
@@ -238,7 +230,7 @@ static void update_if_frozen(struct cgroup *cgroup, | |||
238 | cgroup_iter_start(cgroup, &it); | 230 | cgroup_iter_start(cgroup, &it); |
239 | while ((task = cgroup_iter_next(cgroup, &it))) { | 231 | while ((task = cgroup_iter_next(cgroup, &it))) { |
240 | ntotal++; | 232 | ntotal++; |
241 | if (is_task_frozen_enough(task)) | 233 | if (freezing(task) && is_task_frozen_enough(task)) |
242 | nfrozen++; | 234 | nfrozen++; |
243 | } | 235 | } |
244 | 236 | ||
@@ -286,10 +278,9 @@ static int try_to_freeze_cgroup(struct cgroup *cgroup, struct freezer *freezer) | |||
286 | struct task_struct *task; | 278 | struct task_struct *task; |
287 | unsigned int num_cant_freeze_now = 0; | 279 | unsigned int num_cant_freeze_now = 0; |
288 | 280 | ||
289 | freezer->state = CGROUP_FREEZING; | ||
290 | cgroup_iter_start(cgroup, &it); | 281 | cgroup_iter_start(cgroup, &it); |
291 | while ((task = cgroup_iter_next(cgroup, &it))) { | 282 | while ((task = cgroup_iter_next(cgroup, &it))) { |
292 | if (!freeze_task(task, true)) | 283 | if (!freeze_task(task)) |
293 | continue; | 284 | continue; |
294 | if (is_task_frozen_enough(task)) | 285 | if (is_task_frozen_enough(task)) |
295 | continue; | 286 | continue; |
@@ -307,12 +298,9 @@ static void unfreeze_cgroup(struct cgroup *cgroup, struct freezer *freezer) | |||
307 | struct task_struct *task; | 298 | struct task_struct *task; |
308 | 299 | ||
309 | cgroup_iter_start(cgroup, &it); | 300 | cgroup_iter_start(cgroup, &it); |
310 | while ((task = cgroup_iter_next(cgroup, &it))) { | 301 | while ((task = cgroup_iter_next(cgroup, &it))) |
311 | thaw_process(task); | 302 | __thaw_task(task); |
312 | } | ||
313 | cgroup_iter_end(cgroup, &it); | 303 | cgroup_iter_end(cgroup, &it); |
314 | |||
315 | freezer->state = CGROUP_THAWED; | ||
316 | } | 304 | } |
317 | 305 | ||
318 | static int freezer_change_state(struct cgroup *cgroup, | 306 | static int freezer_change_state(struct cgroup *cgroup, |
@@ -326,20 +314,24 @@ static int freezer_change_state(struct cgroup *cgroup, | |||
326 | spin_lock_irq(&freezer->lock); | 314 | spin_lock_irq(&freezer->lock); |
327 | 315 | ||
328 | update_if_frozen(cgroup, freezer); | 316 | update_if_frozen(cgroup, freezer); |
329 | if (goal_state == freezer->state) | ||
330 | goto out; | ||
331 | 317 | ||
332 | switch (goal_state) { | 318 | switch (goal_state) { |
333 | case CGROUP_THAWED: | 319 | case CGROUP_THAWED: |
320 | if (freezer->state != CGROUP_THAWED) | ||
321 | atomic_dec(&system_freezing_cnt); | ||
322 | freezer->state = CGROUP_THAWED; | ||
334 | unfreeze_cgroup(cgroup, freezer); | 323 | unfreeze_cgroup(cgroup, freezer); |
335 | break; | 324 | break; |
336 | case CGROUP_FROZEN: | 325 | case CGROUP_FROZEN: |
326 | if (freezer->state == CGROUP_THAWED) | ||
327 | atomic_inc(&system_freezing_cnt); | ||
328 | freezer->state = CGROUP_FREEZING; | ||
337 | retval = try_to_freeze_cgroup(cgroup, freezer); | 329 | retval = try_to_freeze_cgroup(cgroup, freezer); |
338 | break; | 330 | break; |
339 | default: | 331 | default: |
340 | BUG(); | 332 | BUG(); |
341 | } | 333 | } |
342 | out: | 334 | |
343 | spin_unlock_irq(&freezer->lock); | 335 | spin_unlock_irq(&freezer->lock); |
344 | 336 | ||
345 | return retval; | 337 | return retval; |
@@ -388,10 +380,5 @@ struct cgroup_subsys freezer_subsys = { | |||
388 | .populate = freezer_populate, | 380 | .populate = freezer_populate, |
389 | .subsys_id = freezer_subsys_id, | 381 | .subsys_id = freezer_subsys_id, |
390 | .can_attach = freezer_can_attach, | 382 | .can_attach = freezer_can_attach, |
391 | .can_attach_task = freezer_can_attach_task, | ||
392 | .pre_attach = NULL, | ||
393 | .attach_task = NULL, | ||
394 | .attach = NULL, | ||
395 | .fork = freezer_fork, | 383 | .fork = freezer_fork, |
396 | .exit = NULL, | ||
397 | }; | 384 | }; |