diff options
author | Eric Paris <eparis@redhat.com> | 2013-11-22 18:57:08 -0500 |
---|---|---|
committer | Eric Paris <eparis@redhat.com> | 2013-11-22 18:57:54 -0500 |
commit | fc582aef7dcc27a7120cf232c1e76c569c7b6eab (patch) | |
tree | 7d275dd4ceab6067b91e9a25a5f6338b425fbccd /kernel/cgroup_freezer.c | |
parent | 9175c9d2aed528800175ef81c90569d00d23f9be (diff) | |
parent | 5e01dc7b26d9f24f39abace5da98ccbd6a5ceb52 (diff) |
Merge tag 'v3.12'
Linux 3.12
Conflicts:
fs/exec.c
Diffstat (limited to 'kernel/cgroup_freezer.c')
-rw-r--r-- | kernel/cgroup_freezer.c | 155 |
1 files changed, 77 insertions, 78 deletions
diff --git a/kernel/cgroup_freezer.c b/kernel/cgroup_freezer.c index 75dda1ea5026..f0ff64d0ebaa 100644 --- a/kernel/cgroup_freezer.c +++ b/kernel/cgroup_freezer.c | |||
@@ -45,25 +45,19 @@ struct freezer { | |||
45 | spinlock_t lock; | 45 | spinlock_t lock; |
46 | }; | 46 | }; |
47 | 47 | ||
48 | static inline struct freezer *cgroup_freezer(struct cgroup *cgroup) | 48 | static inline struct freezer *css_freezer(struct cgroup_subsys_state *css) |
49 | { | 49 | { |
50 | return container_of(cgroup_subsys_state(cgroup, freezer_subsys_id), | 50 | return css ? container_of(css, struct freezer, css) : NULL; |
51 | struct freezer, css); | ||
52 | } | 51 | } |
53 | 52 | ||
54 | static inline struct freezer *task_freezer(struct task_struct *task) | 53 | static inline struct freezer *task_freezer(struct task_struct *task) |
55 | { | 54 | { |
56 | return container_of(task_subsys_state(task, freezer_subsys_id), | 55 | return css_freezer(task_css(task, freezer_subsys_id)); |
57 | struct freezer, css); | ||
58 | } | 56 | } |
59 | 57 | ||
60 | static struct freezer *parent_freezer(struct freezer *freezer) | 58 | static struct freezer *parent_freezer(struct freezer *freezer) |
61 | { | 59 | { |
62 | struct cgroup *pcg = freezer->css.cgroup->parent; | 60 | return css_freezer(css_parent(&freezer->css)); |
63 | |||
64 | if (pcg) | ||
65 | return cgroup_freezer(pcg); | ||
66 | return NULL; | ||
67 | } | 61 | } |
68 | 62 | ||
69 | bool cgroup_freezing(struct task_struct *task) | 63 | bool cgroup_freezing(struct task_struct *task) |
@@ -92,7 +86,8 @@ static const char *freezer_state_strs(unsigned int state) | |||
92 | 86 | ||
93 | struct cgroup_subsys freezer_subsys; | 87 | struct cgroup_subsys freezer_subsys; |
94 | 88 | ||
95 | static struct cgroup_subsys_state *freezer_css_alloc(struct cgroup *cgroup) | 89 | static struct cgroup_subsys_state * |
90 | freezer_css_alloc(struct cgroup_subsys_state *parent_css) | ||
96 | { | 91 | { |
97 | struct freezer *freezer; | 92 | struct freezer *freezer; |
98 | 93 | ||
@@ -105,22 +100,22 @@ static struct cgroup_subsys_state *freezer_css_alloc(struct cgroup *cgroup) | |||
105 | } | 100 | } |
106 | 101 | ||
107 | /** | 102 | /** |
108 | * freezer_css_online - commit creation of a freezer cgroup | 103 | * freezer_css_online - commit creation of a freezer css |
109 | * @cgroup: cgroup being created | 104 | * @css: css being created |
110 | * | 105 | * |
111 | * We're committing to creation of @cgroup. Mark it online and inherit | 106 | * We're committing to creation of @css. Mark it online and inherit |
112 | * parent's freezing state while holding both parent's and our | 107 | * parent's freezing state while holding both parent's and our |
113 | * freezer->lock. | 108 | * freezer->lock. |
114 | */ | 109 | */ |
115 | static int freezer_css_online(struct cgroup *cgroup) | 110 | static int freezer_css_online(struct cgroup_subsys_state *css) |
116 | { | 111 | { |
117 | struct freezer *freezer = cgroup_freezer(cgroup); | 112 | struct freezer *freezer = css_freezer(css); |
118 | struct freezer *parent = parent_freezer(freezer); | 113 | struct freezer *parent = parent_freezer(freezer); |
119 | 114 | ||
120 | /* | 115 | /* |
121 | * The following double locking and freezing state inheritance | 116 | * The following double locking and freezing state inheritance |
122 | * guarantee that @cgroup can never escape ancestors' freezing | 117 | * guarantee that @cgroup can never escape ancestors' freezing |
123 | * states. See cgroup_for_each_descendant_pre() for details. | 118 | * states. See css_for_each_descendant_pre() for details. |
124 | */ | 119 | */ |
125 | if (parent) | 120 | if (parent) |
126 | spin_lock_irq(&parent->lock); | 121 | spin_lock_irq(&parent->lock); |
@@ -141,15 +136,15 @@ static int freezer_css_online(struct cgroup *cgroup) | |||
141 | } | 136 | } |
142 | 137 | ||
143 | /** | 138 | /** |
144 | * freezer_css_offline - initiate destruction of @cgroup | 139 | * freezer_css_offline - initiate destruction of a freezer css |
145 | * @cgroup: cgroup being destroyed | 140 | * @css: css being destroyed |
146 | * | 141 | * |
147 | * @cgroup is going away. Mark it dead and decrement system_freezing_count | 142 | * @css is going away. Mark it dead and decrement system_freezing_count if |
148 | * if it was holding one. | 143 | * it was holding one. |
149 | */ | 144 | */ |
150 | static void freezer_css_offline(struct cgroup *cgroup) | 145 | static void freezer_css_offline(struct cgroup_subsys_state *css) |
151 | { | 146 | { |
152 | struct freezer *freezer = cgroup_freezer(cgroup); | 147 | struct freezer *freezer = css_freezer(css); |
153 | 148 | ||
154 | spin_lock_irq(&freezer->lock); | 149 | spin_lock_irq(&freezer->lock); |
155 | 150 | ||
@@ -161,9 +156,9 @@ static void freezer_css_offline(struct cgroup *cgroup) | |||
161 | spin_unlock_irq(&freezer->lock); | 156 | spin_unlock_irq(&freezer->lock); |
162 | } | 157 | } |
163 | 158 | ||
164 | static void freezer_css_free(struct cgroup *cgroup) | 159 | static void freezer_css_free(struct cgroup_subsys_state *css) |
165 | { | 160 | { |
166 | kfree(cgroup_freezer(cgroup)); | 161 | kfree(css_freezer(css)); |
167 | } | 162 | } |
168 | 163 | ||
169 | /* | 164 | /* |
@@ -175,25 +170,26 @@ static void freezer_css_free(struct cgroup *cgroup) | |||
175 | * @freezer->lock. freezer_attach() makes the new tasks conform to the | 170 | * @freezer->lock. freezer_attach() makes the new tasks conform to the |
176 | * current state and all following state changes can see the new tasks. | 171 | * current state and all following state changes can see the new tasks. |
177 | */ | 172 | */ |
178 | static void freezer_attach(struct cgroup *new_cgrp, struct cgroup_taskset *tset) | 173 | static void freezer_attach(struct cgroup_subsys_state *new_css, |
174 | struct cgroup_taskset *tset) | ||
179 | { | 175 | { |
180 | struct freezer *freezer = cgroup_freezer(new_cgrp); | 176 | struct freezer *freezer = css_freezer(new_css); |
181 | struct task_struct *task; | 177 | struct task_struct *task; |
182 | bool clear_frozen = false; | 178 | bool clear_frozen = false; |
183 | 179 | ||
184 | spin_lock_irq(&freezer->lock); | 180 | spin_lock_irq(&freezer->lock); |
185 | 181 | ||
186 | /* | 182 | /* |
187 | * Make the new tasks conform to the current state of @new_cgrp. | 183 | * Make the new tasks conform to the current state of @new_css. |
188 | * For simplicity, when migrating any task to a FROZEN cgroup, we | 184 | * For simplicity, when migrating any task to a FROZEN cgroup, we |
189 | * revert it to FREEZING and let update_if_frozen() determine the | 185 | * revert it to FREEZING and let update_if_frozen() determine the |
190 | * correct state later. | 186 | * correct state later. |
191 | * | 187 | * |
192 | * Tasks in @tset are on @new_cgrp but may not conform to its | 188 | * Tasks in @tset are on @new_css but may not conform to its |
193 | * current state before executing the following - !frozen tasks may | 189 | * current state before executing the following - !frozen tasks may |
194 | * be visible in a FROZEN cgroup and frozen tasks in a THAWED one. | 190 | * be visible in a FROZEN cgroup and frozen tasks in a THAWED one. |
195 | */ | 191 | */ |
196 | cgroup_taskset_for_each(task, new_cgrp, tset) { | 192 | cgroup_taskset_for_each(task, new_css, tset) { |
197 | if (!(freezer->state & CGROUP_FREEZING)) { | 193 | if (!(freezer->state & CGROUP_FREEZING)) { |
198 | __thaw_task(task); | 194 | __thaw_task(task); |
199 | } else { | 195 | } else { |
@@ -231,7 +227,7 @@ static void freezer_fork(struct task_struct *task) | |||
231 | * The root cgroup is non-freezable, so we can skip the | 227 | * The root cgroup is non-freezable, so we can skip the |
232 | * following check. | 228 | * following check. |
233 | */ | 229 | */ |
234 | if (!freezer->css.cgroup->parent) | 230 | if (!parent_freezer(freezer)) |
235 | goto out; | 231 | goto out; |
236 | 232 | ||
237 | spin_lock_irq(&freezer->lock); | 233 | spin_lock_irq(&freezer->lock); |
@@ -244,7 +240,7 @@ out: | |||
244 | 240 | ||
245 | /** | 241 | /** |
246 | * update_if_frozen - update whether a cgroup finished freezing | 242 | * update_if_frozen - update whether a cgroup finished freezing |
247 | * @cgroup: cgroup of interest | 243 | * @css: css of interest |
248 | * | 244 | * |
249 | * Once FREEZING is initiated, transition to FROZEN is lazily updated by | 245 | * Once FREEZING is initiated, transition to FROZEN is lazily updated by |
250 | * calling this function. If the current state is FREEZING but not FROZEN, | 246 | * calling this function. If the current state is FREEZING but not FROZEN, |
@@ -255,14 +251,14 @@ out: | |||
255 | * update_if_frozen() on all descendants prior to invoking this function. | 251 | * update_if_frozen() on all descendants prior to invoking this function. |
256 | * | 252 | * |
257 | * Task states and freezer state might disagree while tasks are being | 253 | * Task states and freezer state might disagree while tasks are being |
258 | * migrated into or out of @cgroup, so we can't verify task states against | 254 | * migrated into or out of @css, so we can't verify task states against |
259 | * @freezer state here. See freezer_attach() for details. | 255 | * @freezer state here. See freezer_attach() for details. |
260 | */ | 256 | */ |
261 | static void update_if_frozen(struct cgroup *cgroup) | 257 | static void update_if_frozen(struct cgroup_subsys_state *css) |
262 | { | 258 | { |
263 | struct freezer *freezer = cgroup_freezer(cgroup); | 259 | struct freezer *freezer = css_freezer(css); |
264 | struct cgroup *pos; | 260 | struct cgroup_subsys_state *pos; |
265 | struct cgroup_iter it; | 261 | struct css_task_iter it; |
266 | struct task_struct *task; | 262 | struct task_struct *task; |
267 | 263 | ||
268 | WARN_ON_ONCE(!rcu_read_lock_held()); | 264 | WARN_ON_ONCE(!rcu_read_lock_held()); |
@@ -274,8 +270,8 @@ static void update_if_frozen(struct cgroup *cgroup) | |||
274 | goto out_unlock; | 270 | goto out_unlock; |
275 | 271 | ||
276 | /* are all (live) children frozen? */ | 272 | /* are all (live) children frozen? */ |
277 | cgroup_for_each_child(pos, cgroup) { | 273 | css_for_each_child(pos, css) { |
278 | struct freezer *child = cgroup_freezer(pos); | 274 | struct freezer *child = css_freezer(pos); |
279 | 275 | ||
280 | if ((child->state & CGROUP_FREEZER_ONLINE) && | 276 | if ((child->state & CGROUP_FREEZER_ONLINE) && |
281 | !(child->state & CGROUP_FROZEN)) | 277 | !(child->state & CGROUP_FROZEN)) |
@@ -283,9 +279,9 @@ static void update_if_frozen(struct cgroup *cgroup) | |||
283 | } | 279 | } |
284 | 280 | ||
285 | /* are all tasks frozen? */ | 281 | /* are all tasks frozen? */ |
286 | cgroup_iter_start(cgroup, &it); | 282 | css_task_iter_start(css, &it); |
287 | 283 | ||
288 | while ((task = cgroup_iter_next(cgroup, &it))) { | 284 | while ((task = css_task_iter_next(&it))) { |
289 | if (freezing(task)) { | 285 | if (freezing(task)) { |
290 | /* | 286 | /* |
291 | * freezer_should_skip() indicates that the task | 287 | * freezer_should_skip() indicates that the task |
@@ -300,52 +296,49 @@ static void update_if_frozen(struct cgroup *cgroup) | |||
300 | 296 | ||
301 | freezer->state |= CGROUP_FROZEN; | 297 | freezer->state |= CGROUP_FROZEN; |
302 | out_iter_end: | 298 | out_iter_end: |
303 | cgroup_iter_end(cgroup, &it); | 299 | css_task_iter_end(&it); |
304 | out_unlock: | 300 | out_unlock: |
305 | spin_unlock_irq(&freezer->lock); | 301 | spin_unlock_irq(&freezer->lock); |
306 | } | 302 | } |
307 | 303 | ||
308 | static int freezer_read(struct cgroup *cgroup, struct cftype *cft, | 304 | static int freezer_read(struct cgroup_subsys_state *css, struct cftype *cft, |
309 | struct seq_file *m) | 305 | struct seq_file *m) |
310 | { | 306 | { |
311 | struct cgroup *pos; | 307 | struct cgroup_subsys_state *pos; |
312 | 308 | ||
313 | rcu_read_lock(); | 309 | rcu_read_lock(); |
314 | 310 | ||
315 | /* update states bottom-up */ | 311 | /* update states bottom-up */ |
316 | cgroup_for_each_descendant_post(pos, cgroup) | 312 | css_for_each_descendant_post(pos, css) |
317 | update_if_frozen(pos); | 313 | update_if_frozen(pos); |
318 | update_if_frozen(cgroup); | ||
319 | 314 | ||
320 | rcu_read_unlock(); | 315 | rcu_read_unlock(); |
321 | 316 | ||
322 | seq_puts(m, freezer_state_strs(cgroup_freezer(cgroup)->state)); | 317 | seq_puts(m, freezer_state_strs(css_freezer(css)->state)); |
323 | seq_putc(m, '\n'); | 318 | seq_putc(m, '\n'); |
324 | return 0; | 319 | return 0; |
325 | } | 320 | } |
326 | 321 | ||
327 | static void freeze_cgroup(struct freezer *freezer) | 322 | static void freeze_cgroup(struct freezer *freezer) |
328 | { | 323 | { |
329 | struct cgroup *cgroup = freezer->css.cgroup; | 324 | struct css_task_iter it; |
330 | struct cgroup_iter it; | ||
331 | struct task_struct *task; | 325 | struct task_struct *task; |
332 | 326 | ||
333 | cgroup_iter_start(cgroup, &it); | 327 | css_task_iter_start(&freezer->css, &it); |
334 | while ((task = cgroup_iter_next(cgroup, &it))) | 328 | while ((task = css_task_iter_next(&it))) |
335 | freeze_task(task); | 329 | freeze_task(task); |
336 | cgroup_iter_end(cgroup, &it); | 330 | css_task_iter_end(&it); |
337 | } | 331 | } |
338 | 332 | ||
339 | static void unfreeze_cgroup(struct freezer *freezer) | 333 | static void unfreeze_cgroup(struct freezer *freezer) |
340 | { | 334 | { |
341 | struct cgroup *cgroup = freezer->css.cgroup; | 335 | struct css_task_iter it; |
342 | struct cgroup_iter it; | ||
343 | struct task_struct *task; | 336 | struct task_struct *task; |
344 | 337 | ||
345 | cgroup_iter_start(cgroup, &it); | 338 | css_task_iter_start(&freezer->css, &it); |
346 | while ((task = cgroup_iter_next(cgroup, &it))) | 339 | while ((task = css_task_iter_next(&it))) |
347 | __thaw_task(task); | 340 | __thaw_task(task); |
348 | cgroup_iter_end(cgroup, &it); | 341 | css_task_iter_end(&it); |
349 | } | 342 | } |
350 | 343 | ||
351 | /** | 344 | /** |
@@ -395,12 +388,7 @@ static void freezer_apply_state(struct freezer *freezer, bool freeze, | |||
395 | */ | 388 | */ |
396 | static void freezer_change_state(struct freezer *freezer, bool freeze) | 389 | static void freezer_change_state(struct freezer *freezer, bool freeze) |
397 | { | 390 | { |
398 | struct cgroup *pos; | 391 | struct cgroup_subsys_state *pos; |
399 | |||
400 | /* update @freezer */ | ||
401 | spin_lock_irq(&freezer->lock); | ||
402 | freezer_apply_state(freezer, freeze, CGROUP_FREEZING_SELF); | ||
403 | spin_unlock_irq(&freezer->lock); | ||
404 | 392 | ||
405 | /* | 393 | /* |
406 | * Update all its descendants in pre-order traversal. Each | 394 | * Update all its descendants in pre-order traversal. Each |
@@ -408,24 +396,33 @@ static void freezer_change_state(struct freezer *freezer, bool freeze) | |||
408 | * CGROUP_FREEZING_PARENT. | 396 | * CGROUP_FREEZING_PARENT. |
409 | */ | 397 | */ |
410 | rcu_read_lock(); | 398 | rcu_read_lock(); |
411 | cgroup_for_each_descendant_pre(pos, freezer->css.cgroup) { | 399 | css_for_each_descendant_pre(pos, &freezer->css) { |
412 | struct freezer *pos_f = cgroup_freezer(pos); | 400 | struct freezer *pos_f = css_freezer(pos); |
413 | struct freezer *parent = parent_freezer(pos_f); | 401 | struct freezer *parent = parent_freezer(pos_f); |
414 | 402 | ||
415 | /* | ||
416 | * Our update to @parent->state is already visible which is | ||
417 | * all we need. No need to lock @parent. For more info on | ||
418 | * synchronization, see freezer_post_create(). | ||
419 | */ | ||
420 | spin_lock_irq(&pos_f->lock); | 403 | spin_lock_irq(&pos_f->lock); |
421 | freezer_apply_state(pos_f, parent->state & CGROUP_FREEZING, | 404 | |
422 | CGROUP_FREEZING_PARENT); | 405 | if (pos_f == freezer) { |
406 | freezer_apply_state(pos_f, freeze, | ||
407 | CGROUP_FREEZING_SELF); | ||
408 | } else { | ||
409 | /* | ||
410 | * Our update to @parent->state is already visible | ||
411 | * which is all we need. No need to lock @parent. | ||
412 | * For more info on synchronization, see | ||
413 | * freezer_post_create(). | ||
414 | */ | ||
415 | freezer_apply_state(pos_f, | ||
416 | parent->state & CGROUP_FREEZING, | ||
417 | CGROUP_FREEZING_PARENT); | ||
418 | } | ||
419 | |||
423 | spin_unlock_irq(&pos_f->lock); | 420 | spin_unlock_irq(&pos_f->lock); |
424 | } | 421 | } |
425 | rcu_read_unlock(); | 422 | rcu_read_unlock(); |
426 | } | 423 | } |
427 | 424 | ||
428 | static int freezer_write(struct cgroup *cgroup, struct cftype *cft, | 425 | static int freezer_write(struct cgroup_subsys_state *css, struct cftype *cft, |
429 | const char *buffer) | 426 | const char *buffer) |
430 | { | 427 | { |
431 | bool freeze; | 428 | bool freeze; |
@@ -437,20 +434,22 @@ static int freezer_write(struct cgroup *cgroup, struct cftype *cft, | |||
437 | else | 434 | else |
438 | return -EINVAL; | 435 | return -EINVAL; |
439 | 436 | ||
440 | freezer_change_state(cgroup_freezer(cgroup), freeze); | 437 | freezer_change_state(css_freezer(css), freeze); |
441 | return 0; | 438 | return 0; |
442 | } | 439 | } |
443 | 440 | ||
444 | static u64 freezer_self_freezing_read(struct cgroup *cgroup, struct cftype *cft) | 441 | static u64 freezer_self_freezing_read(struct cgroup_subsys_state *css, |
442 | struct cftype *cft) | ||
445 | { | 443 | { |
446 | struct freezer *freezer = cgroup_freezer(cgroup); | 444 | struct freezer *freezer = css_freezer(css); |
447 | 445 | ||
448 | return (bool)(freezer->state & CGROUP_FREEZING_SELF); | 446 | return (bool)(freezer->state & CGROUP_FREEZING_SELF); |
449 | } | 447 | } |
450 | 448 | ||
451 | static u64 freezer_parent_freezing_read(struct cgroup *cgroup, struct cftype *cft) | 449 | static u64 freezer_parent_freezing_read(struct cgroup_subsys_state *css, |
450 | struct cftype *cft) | ||
452 | { | 451 | { |
453 | struct freezer *freezer = cgroup_freezer(cgroup); | 452 | struct freezer *freezer = css_freezer(css); |
454 | 453 | ||
455 | return (bool)(freezer->state & CGROUP_FREEZING_PARENT); | 454 | return (bool)(freezer->state & CGROUP_FREEZING_PARENT); |
456 | } | 455 | } |