bsr: fix build problem with bsr_class static cleanup
[platform/kernel/linux-rpi.git] / kernel / cgroup / legacy_freezer.c
1 /*
2  * cgroup_freezer.c -  control group freezer subsystem
3  *
4  * Copyright IBM Corporation, 2007
5  *
6  * Author : Cedric Le Goater <clg@fr.ibm.com>
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms of version 2.1 of the GNU Lesser General Public License
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it would be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15  */
16
17 #include <linux/export.h>
18 #include <linux/slab.h>
19 #include <linux/cgroup.h>
20 #include <linux/fs.h>
21 #include <linux/uaccess.h>
22 #include <linux/freezer.h>
23 #include <linux/seq_file.h>
24 #include <linux/mutex.h>
25 #include <linux/cpu.h>
26
27 /*
28  * A cgroup is freezing if any FREEZING flags are set.  FREEZING_SELF is
29  * set if "FROZEN" is written to freezer.state cgroupfs file, and cleared
30  * for "THAWED".  FREEZING_PARENT is set if the parent freezer is FREEZING
31  * for whatever reason.  IOW, a cgroup has FREEZING_PARENT set if one of
32  * its ancestors has FREEZING_SELF set.
33  */
34 enum freezer_state_flags {
35         CGROUP_FREEZER_ONLINE   = (1 << 0), /* freezer is fully online */
36         CGROUP_FREEZING_SELF    = (1 << 1), /* this freezer is freezing */
37         CGROUP_FREEZING_PARENT  = (1 << 2), /* the parent freezer is freezing */
38         CGROUP_FROZEN           = (1 << 3), /* this and its descendants frozen */
39
40         /* mask for all FREEZING flags */
41         CGROUP_FREEZING         = CGROUP_FREEZING_SELF | CGROUP_FREEZING_PARENT,
42 };
43
44 struct freezer {
45         struct cgroup_subsys_state      css;
46         unsigned int                    state;
47 };
48
49 static DEFINE_MUTEX(freezer_mutex);
50
51 static inline struct freezer *css_freezer(struct cgroup_subsys_state *css)
52 {
53         return css ? container_of(css, struct freezer, css) : NULL;
54 }
55
56 static inline struct freezer *task_freezer(struct task_struct *task)
57 {
58         return css_freezer(task_css(task, freezer_cgrp_id));
59 }
60
61 static struct freezer *parent_freezer(struct freezer *freezer)
62 {
63         return css_freezer(freezer->css.parent);
64 }
65
66 bool cgroup_freezing(struct task_struct *task)
67 {
68         bool ret;
69
70         rcu_read_lock();
71         ret = task_freezer(task)->state & CGROUP_FREEZING;
72         rcu_read_unlock();
73
74         return ret;
75 }
76
77 static const char *freezer_state_strs(unsigned int state)
78 {
79         if (state & CGROUP_FROZEN)
80                 return "FROZEN";
81         if (state & CGROUP_FREEZING)
82                 return "FREEZING";
83         return "THAWED";
84 };
85
86 static struct cgroup_subsys_state *
87 freezer_css_alloc(struct cgroup_subsys_state *parent_css)
88 {
89         struct freezer *freezer;
90
91         freezer = kzalloc(sizeof(struct freezer), GFP_KERNEL);
92         if (!freezer)
93                 return ERR_PTR(-ENOMEM);
94
95         return &freezer->css;
96 }
97
98 /**
99  * freezer_css_online - commit creation of a freezer css
100  * @css: css being created
101  *
102  * We're committing to creation of @css.  Mark it online and inherit
103  * parent's freezing state while holding both parent's and our
104  * freezer->lock.
105  */
106 static int freezer_css_online(struct cgroup_subsys_state *css)
107 {
108         struct freezer *freezer = css_freezer(css);
109         struct freezer *parent = parent_freezer(freezer);
110
111         mutex_lock(&freezer_mutex);
112
113         freezer->state |= CGROUP_FREEZER_ONLINE;
114
115         if (parent && (parent->state & CGROUP_FREEZING)) {
116                 freezer->state |= CGROUP_FREEZING_PARENT | CGROUP_FROZEN;
117                 static_branch_inc(&freezer_active);
118         }
119
120         mutex_unlock(&freezer_mutex);
121         return 0;
122 }
123
124 /**
125  * freezer_css_offline - initiate destruction of a freezer css
126  * @css: css being destroyed
127  *
128  * @css is going away.  Mark it dead and decrement system_freezing_count if
129  * it was holding one.
130  */
131 static void freezer_css_offline(struct cgroup_subsys_state *css)
132 {
133         struct freezer *freezer = css_freezer(css);
134
135         mutex_lock(&freezer_mutex);
136
137         if (freezer->state & CGROUP_FREEZING)
138                 static_branch_dec(&freezer_active);
139
140         freezer->state = 0;
141
142         mutex_unlock(&freezer_mutex);
143 }
144
145 static void freezer_css_free(struct cgroup_subsys_state *css)
146 {
147         kfree(css_freezer(css));
148 }
149
150 /*
151  * Tasks can be migrated into a different freezer anytime regardless of its
152  * current state.  freezer_attach() is responsible for making new tasks
153  * conform to the current state.
154  *
155  * Freezer state changes and task migration are synchronized via
156  * @freezer->lock.  freezer_attach() makes the new tasks conform to the
157  * current state and all following state changes can see the new tasks.
158  */
159 static void freezer_attach(struct cgroup_taskset *tset)
160 {
161         struct task_struct *task;
162         struct cgroup_subsys_state *new_css;
163
164         mutex_lock(&freezer_mutex);
165
166         /*
167          * Make the new tasks conform to the current state of @new_css.
168          * For simplicity, when migrating any task to a FROZEN cgroup, we
169          * revert it to FREEZING and let update_if_frozen() determine the
170          * correct state later.
171          *
172          * Tasks in @tset are on @new_css but may not conform to its
173          * current state before executing the following - !frozen tasks may
174          * be visible in a FROZEN cgroup and frozen tasks in a THAWED one.
175          */
176         cgroup_taskset_for_each(task, new_css, tset) {
177                 struct freezer *freezer = css_freezer(new_css);
178
179                 if (!(freezer->state & CGROUP_FREEZING)) {
180                         __thaw_task(task);
181                 } else {
182                         freeze_task(task);
183
184                         /* clear FROZEN and propagate upwards */
185                         while (freezer && (freezer->state & CGROUP_FROZEN)) {
186                                 freezer->state &= ~CGROUP_FROZEN;
187                                 freezer = parent_freezer(freezer);
188                         }
189                 }
190         }
191
192         mutex_unlock(&freezer_mutex);
193 }
194
195 /**
196  * freezer_fork - cgroup post fork callback
197  * @task: a task which has just been forked
198  *
199  * @task has just been created and should conform to the current state of
200  * the cgroup_freezer it belongs to.  This function may race against
201  * freezer_attach().  Losing to freezer_attach() means that we don't have
202  * to do anything as freezer_attach() will put @task into the appropriate
203  * state.
204  */
205 static void freezer_fork(struct task_struct *task)
206 {
207         struct freezer *freezer;
208
209         /*
210          * The root cgroup is non-freezable, so we can skip locking the
211          * freezer.  This is safe regardless of race with task migration.
212          * If we didn't race or won, skipping is obviously the right thing
213          * to do.  If we lost and root is the new cgroup, noop is still the
214          * right thing to do.
215          */
216         if (task_css_is_root(task, freezer_cgrp_id))
217                 return;
218
219         mutex_lock(&freezer_mutex);
220         rcu_read_lock();
221
222         freezer = task_freezer(task);
223         if (freezer->state & CGROUP_FREEZING)
224                 freeze_task(task);
225
226         rcu_read_unlock();
227         mutex_unlock(&freezer_mutex);
228 }
229
230 /**
231  * update_if_frozen - update whether a cgroup finished freezing
232  * @css: css of interest
233  *
234  * Once FREEZING is initiated, transition to FROZEN is lazily updated by
235  * calling this function.  If the current state is FREEZING but not FROZEN,
236  * this function checks whether all tasks of this cgroup and the descendant
237  * cgroups finished freezing and, if so, sets FROZEN.
238  *
239  * The caller is responsible for grabbing RCU read lock and calling
240  * update_if_frozen() on all descendants prior to invoking this function.
241  *
242  * Task states and freezer state might disagree while tasks are being
243  * migrated into or out of @css, so we can't verify task states against
244  * @freezer state here.  See freezer_attach() for details.
245  */
246 static void update_if_frozen(struct cgroup_subsys_state *css)
247 {
248         struct freezer *freezer = css_freezer(css);
249         struct cgroup_subsys_state *pos;
250         struct css_task_iter it;
251         struct task_struct *task;
252
253         lockdep_assert_held(&freezer_mutex);
254
255         if (!(freezer->state & CGROUP_FREEZING) ||
256             (freezer->state & CGROUP_FROZEN))
257                 return;
258
259         /* are all (live) children frozen? */
260         rcu_read_lock();
261         css_for_each_child(pos, css) {
262                 struct freezer *child = css_freezer(pos);
263
264                 if ((child->state & CGROUP_FREEZER_ONLINE) &&
265                     !(child->state & CGROUP_FROZEN)) {
266                         rcu_read_unlock();
267                         return;
268                 }
269         }
270         rcu_read_unlock();
271
272         /* are all tasks frozen? */
273         css_task_iter_start(css, 0, &it);
274
275         while ((task = css_task_iter_next(&it))) {
276                 if (freezing(task) && !frozen(task))
277                         goto out_iter_end;
278         }
279
280         freezer->state |= CGROUP_FROZEN;
281 out_iter_end:
282         css_task_iter_end(&it);
283 }
284
285 static int freezer_read(struct seq_file *m, void *v)
286 {
287         struct cgroup_subsys_state *css = seq_css(m), *pos;
288
289         mutex_lock(&freezer_mutex);
290         rcu_read_lock();
291
292         /* update states bottom-up */
293         css_for_each_descendant_post(pos, css) {
294                 if (!css_tryget_online(pos))
295                         continue;
296                 rcu_read_unlock();
297
298                 update_if_frozen(pos);
299
300                 rcu_read_lock();
301                 css_put(pos);
302         }
303
304         rcu_read_unlock();
305         mutex_unlock(&freezer_mutex);
306
307         seq_puts(m, freezer_state_strs(css_freezer(css)->state));
308         seq_putc(m, '\n');
309         return 0;
310 }
311
312 static void freeze_cgroup(struct freezer *freezer)
313 {
314         struct css_task_iter it;
315         struct task_struct *task;
316
317         css_task_iter_start(&freezer->css, 0, &it);
318         while ((task = css_task_iter_next(&it)))
319                 freeze_task(task);
320         css_task_iter_end(&it);
321 }
322
323 static void unfreeze_cgroup(struct freezer *freezer)
324 {
325         struct css_task_iter it;
326         struct task_struct *task;
327
328         css_task_iter_start(&freezer->css, 0, &it);
329         while ((task = css_task_iter_next(&it)))
330                 __thaw_task(task);
331         css_task_iter_end(&it);
332 }
333
334 /**
335  * freezer_apply_state - apply state change to a single cgroup_freezer
336  * @freezer: freezer to apply state change to
337  * @freeze: whether to freeze or unfreeze
338  * @state: CGROUP_FREEZING_* flag to set or clear
339  *
340  * Set or clear @state on @cgroup according to @freeze, and perform
341  * freezing or thawing as necessary.
342  */
343 static void freezer_apply_state(struct freezer *freezer, bool freeze,
344                                 unsigned int state)
345 {
346         /* also synchronizes against task migration, see freezer_attach() */
347         lockdep_assert_held(&freezer_mutex);
348
349         if (!(freezer->state & CGROUP_FREEZER_ONLINE))
350                 return;
351
352         if (freeze) {
353                 if (!(freezer->state & CGROUP_FREEZING))
354                         static_branch_inc_cpuslocked(&freezer_active);
355                 freezer->state |= state;
356                 freeze_cgroup(freezer);
357         } else {
358                 bool was_freezing = freezer->state & CGROUP_FREEZING;
359
360                 freezer->state &= ~state;
361
362                 if (!(freezer->state & CGROUP_FREEZING)) {
363                         freezer->state &= ~CGROUP_FROZEN;
364                         if (was_freezing)
365                                 static_branch_dec_cpuslocked(&freezer_active);
366                         unfreeze_cgroup(freezer);
367                 }
368         }
369 }
370
371 /**
372  * freezer_change_state - change the freezing state of a cgroup_freezer
373  * @freezer: freezer of interest
374  * @freeze: whether to freeze or thaw
375  *
376  * Freeze or thaw @freezer according to @freeze.  The operations are
377  * recursive - all descendants of @freezer will be affected.
378  */
379 static void freezer_change_state(struct freezer *freezer, bool freeze)
380 {
381         struct cgroup_subsys_state *pos;
382
383         cpus_read_lock();
384         /*
385          * Update all its descendants in pre-order traversal.  Each
386          * descendant will try to inherit its parent's FREEZING state as
387          * CGROUP_FREEZING_PARENT.
388          */
389         mutex_lock(&freezer_mutex);
390         rcu_read_lock();
391         css_for_each_descendant_pre(pos, &freezer->css) {
392                 struct freezer *pos_f = css_freezer(pos);
393                 struct freezer *parent = parent_freezer(pos_f);
394
395                 if (!css_tryget_online(pos))
396                         continue;
397                 rcu_read_unlock();
398
399                 if (pos_f == freezer)
400                         freezer_apply_state(pos_f, freeze,
401                                             CGROUP_FREEZING_SELF);
402                 else
403                         freezer_apply_state(pos_f,
404                                             parent->state & CGROUP_FREEZING,
405                                             CGROUP_FREEZING_PARENT);
406
407                 rcu_read_lock();
408                 css_put(pos);
409         }
410         rcu_read_unlock();
411         mutex_unlock(&freezer_mutex);
412         cpus_read_unlock();
413 }
414
415 static ssize_t freezer_write(struct kernfs_open_file *of,
416                              char *buf, size_t nbytes, loff_t off)
417 {
418         bool freeze;
419
420         buf = strstrip(buf);
421
422         if (strcmp(buf, freezer_state_strs(0)) == 0)
423                 freeze = false;
424         else if (strcmp(buf, freezer_state_strs(CGROUP_FROZEN)) == 0)
425                 freeze = true;
426         else
427                 return -EINVAL;
428
429         freezer_change_state(css_freezer(of_css(of)), freeze);
430         return nbytes;
431 }
432
433 static u64 freezer_self_freezing_read(struct cgroup_subsys_state *css,
434                                       struct cftype *cft)
435 {
436         struct freezer *freezer = css_freezer(css);
437
438         return (bool)(freezer->state & CGROUP_FREEZING_SELF);
439 }
440
441 static u64 freezer_parent_freezing_read(struct cgroup_subsys_state *css,
442                                         struct cftype *cft)
443 {
444         struct freezer *freezer = css_freezer(css);
445
446         return (bool)(freezer->state & CGROUP_FREEZING_PARENT);
447 }
448
449 static struct cftype files[] = {
450         {
451                 .name = "state",
452                 .flags = CFTYPE_NOT_ON_ROOT,
453                 .seq_show = freezer_read,
454                 .write = freezer_write,
455         },
456         {
457                 .name = "self_freezing",
458                 .flags = CFTYPE_NOT_ON_ROOT,
459                 .read_u64 = freezer_self_freezing_read,
460         },
461         {
462                 .name = "parent_freezing",
463                 .flags = CFTYPE_NOT_ON_ROOT,
464                 .read_u64 = freezer_parent_freezing_read,
465         },
466         { }     /* terminate */
467 };
468
469 struct cgroup_subsys freezer_cgrp_subsys = {
470         .css_alloc      = freezer_css_alloc,
471         .css_online     = freezer_css_online,
472         .css_offline    = freezer_css_offline,
473         .css_free       = freezer_css_free,
474         .attach         = freezer_attach,
475         .fork           = freezer_fork,
476         .legacy_cftypes = files,
477 };