cgroup_freezer: add ->post_create() and ->pre_destroy() and track online state
[firefly-linux-kernel-4.4.55.git] / kernel / cgroup_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
25 enum freezer_state_flags {
26         CGROUP_FREEZER_ONLINE   = (1 << 0), /* freezer is fully online */
27         CGROUP_FREEZING_SELF    = (1 << 1), /* this freezer is freezing */
28         CGROUP_FREEZING_PARENT  = (1 << 2), /* the parent freezer is freezing */
29         CGROUP_FROZEN           = (1 << 3), /* this and its descendants frozen */
30
31         /* mask for all FREEZING flags */
32         CGROUP_FREEZING         = CGROUP_FREEZING_SELF | CGROUP_FREEZING_PARENT,
33 };
34
35 struct freezer {
36         struct cgroup_subsys_state      css;
37         unsigned int                    state;
38         spinlock_t                      lock;
39 };
40
41 static inline struct freezer *cgroup_freezer(struct cgroup *cgroup)
42 {
43         return container_of(cgroup_subsys_state(cgroup, freezer_subsys_id),
44                             struct freezer, css);
45 }
46
47 static inline struct freezer *task_freezer(struct task_struct *task)
48 {
49         return container_of(task_subsys_state(task, freezer_subsys_id),
50                             struct freezer, css);
51 }
52
53 bool cgroup_freezing(struct task_struct *task)
54 {
55         bool ret;
56
57         rcu_read_lock();
58         ret = task_freezer(task)->state & CGROUP_FREEZING;
59         rcu_read_unlock();
60
61         return ret;
62 }
63
64 /*
65  * cgroups_write_string() limits the size of freezer state strings to
66  * CGROUP_LOCAL_BUFFER_SIZE
67  */
68 static const char *freezer_state_strs(unsigned int state)
69 {
70         if (state & CGROUP_FROZEN)
71                 return "FROZEN";
72         if (state & CGROUP_FREEZING)
73                 return "FREEZING";
74         return "THAWED";
75 };
76
77 /*
78  * State diagram
79  * Transitions are caused by userspace writes to the freezer.state file.
80  * The values in parenthesis are state labels. The rest are edge labels.
81  *
82  * (THAWED) --FROZEN--> (FREEZING) --FROZEN--> (FROZEN)
83  *    ^ ^                    |                     |
84  *    | \_______THAWED_______/                     |
85  *    \__________________________THAWED____________/
86  */
87
88 struct cgroup_subsys freezer_subsys;
89
90 static struct cgroup_subsys_state *freezer_create(struct cgroup *cgroup)
91 {
92         struct freezer *freezer;
93
94         freezer = kzalloc(sizeof(struct freezer), GFP_KERNEL);
95         if (!freezer)
96                 return ERR_PTR(-ENOMEM);
97
98         spin_lock_init(&freezer->lock);
99         return &freezer->css;
100 }
101
102 /**
103  * freezer_post_create - commit creation of a freezer cgroup
104  * @cgroup: cgroup being created
105  *
106  * We're committing to creation of @cgroup.  Mark it online.
107  */
108 static void freezer_post_create(struct cgroup *cgroup)
109 {
110         struct freezer *freezer = cgroup_freezer(cgroup);
111
112         spin_lock_irq(&freezer->lock);
113         freezer->state |= CGROUP_FREEZER_ONLINE;
114         spin_unlock_irq(&freezer->lock);
115 }
116
117 /**
118  * freezer_pre_destroy - initiate destruction of @cgroup
119  * @cgroup: cgroup being destroyed
120  *
121  * @cgroup is going away.  Mark it dead and decrement system_freezing_count
122  * if it was holding one.
123  */
124 static void freezer_pre_destroy(struct cgroup *cgroup)
125 {
126         struct freezer *freezer = cgroup_freezer(cgroup);
127
128         spin_lock_irq(&freezer->lock);
129
130         if (freezer->state & CGROUP_FREEZING)
131                 atomic_dec(&system_freezing_cnt);
132
133         freezer->state = 0;
134
135         spin_unlock_irq(&freezer->lock);
136 }
137
138 static void freezer_destroy(struct cgroup *cgroup)
139 {
140         kfree(cgroup_freezer(cgroup));
141 }
142
143 /*
144  * Tasks can be migrated into a different freezer anytime regardless of its
145  * current state.  freezer_attach() is responsible for making new tasks
146  * conform to the current state.
147  *
148  * Freezer state changes and task migration are synchronized via
149  * @freezer->lock.  freezer_attach() makes the new tasks conform to the
150  * current state and all following state changes can see the new tasks.
151  */
152 static void freezer_attach(struct cgroup *new_cgrp, struct cgroup_taskset *tset)
153 {
154         struct freezer *freezer = cgroup_freezer(new_cgrp);
155         struct task_struct *task;
156
157         spin_lock_irq(&freezer->lock);
158
159         /*
160          * Make the new tasks conform to the current state of @new_cgrp.
161          * For simplicity, when migrating any task to a FROZEN cgroup, we
162          * revert it to FREEZING and let update_if_frozen() determine the
163          * correct state later.
164          *
165          * Tasks in @tset are on @new_cgrp but may not conform to its
166          * current state before executing the following - !frozen tasks may
167          * be visible in a FROZEN cgroup and frozen tasks in a THAWED one.
168          */
169         cgroup_taskset_for_each(task, new_cgrp, tset) {
170                 if (!(freezer->state & CGROUP_FREEZING)) {
171                         __thaw_task(task);
172                 } else {
173                         freeze_task(task);
174                         freezer->state &= ~CGROUP_FROZEN;
175                 }
176         }
177
178         spin_unlock_irq(&freezer->lock);
179 }
180
181 static void freezer_fork(struct task_struct *task)
182 {
183         struct freezer *freezer;
184
185         rcu_read_lock();
186         freezer = task_freezer(task);
187
188         /*
189          * The root cgroup is non-freezable, so we can skip the
190          * following check.
191          */
192         if (!freezer->css.cgroup->parent)
193                 goto out;
194
195         spin_lock_irq(&freezer->lock);
196         if (freezer->state & CGROUP_FREEZING)
197                 freeze_task(task);
198         spin_unlock_irq(&freezer->lock);
199 out:
200         rcu_read_unlock();
201 }
202
203 /*
204  * We change from FREEZING to FROZEN lazily if the cgroup was only
205  * partially frozen when we exitted write.  Caller must hold freezer->lock.
206  *
207  * Task states and freezer state might disagree while tasks are being
208  * migrated into or out of @cgroup, so we can't verify task states against
209  * @freezer state here.  See freezer_attach() for details.
210  */
211 static void update_if_frozen(struct freezer *freezer)
212 {
213         struct cgroup *cgroup = freezer->css.cgroup;
214         struct cgroup_iter it;
215         struct task_struct *task;
216
217         if (!(freezer->state & CGROUP_FREEZING) ||
218             (freezer->state & CGROUP_FROZEN))
219                 return;
220
221         cgroup_iter_start(cgroup, &it);
222
223         while ((task = cgroup_iter_next(cgroup, &it))) {
224                 if (freezing(task)) {
225                         /*
226                          * freezer_should_skip() indicates that the task
227                          * should be skipped when determining freezing
228                          * completion.  Consider it frozen in addition to
229                          * the usual frozen condition.
230                          */
231                         if (!frozen(task) && !freezer_should_skip(task))
232                                 goto notyet;
233                 }
234         }
235
236         freezer->state |= CGROUP_FROZEN;
237 notyet:
238         cgroup_iter_end(cgroup, &it);
239 }
240
241 static int freezer_read(struct cgroup *cgroup, struct cftype *cft,
242                         struct seq_file *m)
243 {
244         struct freezer *freezer = cgroup_freezer(cgroup);
245         unsigned int state;
246
247         spin_lock_irq(&freezer->lock);
248         update_if_frozen(freezer);
249         state = freezer->state;
250         spin_unlock_irq(&freezer->lock);
251
252         seq_puts(m, freezer_state_strs(state));
253         seq_putc(m, '\n');
254         return 0;
255 }
256
257 static void freeze_cgroup(struct freezer *freezer)
258 {
259         struct cgroup *cgroup = freezer->css.cgroup;
260         struct cgroup_iter it;
261         struct task_struct *task;
262
263         cgroup_iter_start(cgroup, &it);
264         while ((task = cgroup_iter_next(cgroup, &it)))
265                 freeze_task(task);
266         cgroup_iter_end(cgroup, &it);
267 }
268
269 static void unfreeze_cgroup(struct freezer *freezer)
270 {
271         struct cgroup *cgroup = freezer->css.cgroup;
272         struct cgroup_iter it;
273         struct task_struct *task;
274
275         cgroup_iter_start(cgroup, &it);
276         while ((task = cgroup_iter_next(cgroup, &it)))
277                 __thaw_task(task);
278         cgroup_iter_end(cgroup, &it);
279 }
280
281 /**
282  * freezer_apply_state - apply state change to a single cgroup_freezer
283  * @freezer: freezer to apply state change to
284  * @freeze: whether to freeze or unfreeze
285  * @state: CGROUP_FREEZING_* flag to set or clear
286  *
287  * Set or clear @state on @cgroup according to @freeze, and perform
288  * freezing or thawing as necessary.
289  */
290 static void freezer_apply_state(struct freezer *freezer, bool freeze,
291                                 unsigned int state)
292 {
293         /* also synchronizes against task migration, see freezer_attach() */
294         lockdep_assert_held(&freezer->lock);
295
296         if (!(freezer->state & CGROUP_FREEZER_ONLINE))
297                 return;
298
299         if (freeze) {
300                 if (!(freezer->state & CGROUP_FREEZING))
301                         atomic_inc(&system_freezing_cnt);
302                 freezer->state |= state;
303                 freeze_cgroup(freezer);
304         } else {
305                 bool was_freezing = freezer->state & CGROUP_FREEZING;
306
307                 freezer->state &= ~state;
308
309                 if (!(freezer->state & CGROUP_FREEZING)) {
310                         if (was_freezing)
311                                 atomic_dec(&system_freezing_cnt);
312                         freezer->state &= ~CGROUP_FROZEN;
313                         unfreeze_cgroup(freezer);
314                 }
315         }
316 }
317
318 /**
319  * freezer_change_state - change the freezing state of a cgroup_freezer
320  * @freezer: freezer of interest
321  * @freeze: whether to freeze or thaw
322  *
323  * Freeze or thaw @cgroup according to @freeze.
324  */
325 static void freezer_change_state(struct freezer *freezer, bool freeze)
326 {
327         /* update @freezer */
328         spin_lock_irq(&freezer->lock);
329         freezer_apply_state(freezer, freeze, CGROUP_FREEZING_SELF);
330         spin_unlock_irq(&freezer->lock);
331 }
332
333 static int freezer_write(struct cgroup *cgroup, struct cftype *cft,
334                          const char *buffer)
335 {
336         bool freeze;
337
338         if (strcmp(buffer, freezer_state_strs(0)) == 0)
339                 freeze = false;
340         else if (strcmp(buffer, freezer_state_strs(CGROUP_FROZEN)) == 0)
341                 freeze = true;
342         else
343                 return -EINVAL;
344
345         freezer_change_state(cgroup_freezer(cgroup), freeze);
346         return 0;
347 }
348
349 static u64 freezer_self_freezing_read(struct cgroup *cgroup, struct cftype *cft)
350 {
351         struct freezer *freezer = cgroup_freezer(cgroup);
352
353         return (bool)(freezer->state & CGROUP_FREEZING_SELF);
354 }
355
356 static u64 freezer_parent_freezing_read(struct cgroup *cgroup, struct cftype *cft)
357 {
358         struct freezer *freezer = cgroup_freezer(cgroup);
359
360         return (bool)(freezer->state & CGROUP_FREEZING_PARENT);
361 }
362
363 static struct cftype files[] = {
364         {
365                 .name = "state",
366                 .flags = CFTYPE_NOT_ON_ROOT,
367                 .read_seq_string = freezer_read,
368                 .write_string = freezer_write,
369         },
370         {
371                 .name = "self_freezing",
372                 .flags = CFTYPE_NOT_ON_ROOT,
373                 .read_u64 = freezer_self_freezing_read,
374         },
375         {
376                 .name = "parent_freezing",
377                 .flags = CFTYPE_NOT_ON_ROOT,
378                 .read_u64 = freezer_parent_freezing_read,
379         },
380         { }     /* terminate */
381 };
382
383 struct cgroup_subsys freezer_subsys = {
384         .name           = "freezer",
385         .create         = freezer_create,
386         .post_create    = freezer_post_create,
387         .pre_destroy    = freezer_pre_destroy,
388         .destroy        = freezer_destroy,
389         .subsys_id      = freezer_subsys_id,
390         .attach         = freezer_attach,
391         .fork           = freezer_fork,
392         .base_cftypes   = files,
393
394         /*
395          * freezer subsys doesn't handle hierarchy at all.  Frozen state
396          * should be inherited through the hierarchy - if a parent is
397          * frozen, all its children should be frozen.  Fix it and remove
398          * the following.
399          */
400         .broken_hierarchy = true,
401 };