Blame view

kernel/cgroup_freezer.c 12.4 KB
dc52ddc0e   Matt Helsley   container freezer...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  /*
   * cgroup_freezer.c -  control group freezer subsystem
   *
   * Copyright IBM Corporation, 2007
   *
   * Author : Cedric Le Goater <clg@fr.ibm.com>
   *
   * This program is free software; you can redistribute it and/or modify it
   * under the terms of version 2.1 of the GNU Lesser General Public License
   * as published by the Free Software Foundation.
   *
   * This program is distributed in the hope that it would be useful, but
   * WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
   */
9984de1a5   Paul Gortmaker   kernel: Map most ...
16
  #include <linux/export.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
17
  #include <linux/slab.h>
dc52ddc0e   Matt Helsley   container freezer...
18
19
20
21
22
  #include <linux/cgroup.h>
  #include <linux/fs.h>
  #include <linux/uaccess.h>
  #include <linux/freezer.h>
  #include <linux/seq_file.h>
e5ced8ebb   Tejun Heo   cgroup_freezer: r...
23
  #include <linux/mutex.h>
dc52ddc0e   Matt Helsley   container freezer...
24

ef9fe980c   Tejun Heo   cgroup_freezer: i...
25
26
27
28
29
30
31
  /*
   * A cgroup is freezing if any FREEZING flags are set.  FREEZING_SELF is
   * set if "FROZEN" is written to freezer.state cgroupfs file, and cleared
   * for "THAWED".  FREEZING_PARENT is set if the parent freezer is FREEZING
   * for whatever reason.  IOW, a cgroup has FREEZING_PARENT set if one of
   * its ancestors has FREEZING_SELF set.
   */
d6a2fe134   Tejun Heo   cgroup_freezer: m...
32
  enum freezer_state_flags {
5300a9b34   Tejun Heo   cgroup_freezer: a...
33
  	CGROUP_FREEZER_ONLINE	= (1 << 0), /* freezer is fully online */
a22521806   Tejun Heo   cgroup_freezer: i...
34
35
  	CGROUP_FREEZING_SELF	= (1 << 1), /* this freezer is freezing */
  	CGROUP_FREEZING_PARENT	= (1 << 2), /* the parent freezer is freezing */
d6a2fe134   Tejun Heo   cgroup_freezer: m...
36
  	CGROUP_FROZEN		= (1 << 3), /* this and its descendants frozen */
a22521806   Tejun Heo   cgroup_freezer: i...
37
38
39
  
  	/* mask for all FREEZING flags */
  	CGROUP_FREEZING		= CGROUP_FREEZING_SELF | CGROUP_FREEZING_PARENT,
dc52ddc0e   Matt Helsley   container freezer...
40
41
42
  };
  
  struct freezer {
bcd66c894   Tejun Heo   cgroup_freezer: t...
43
  	struct cgroup_subsys_state	css;
d6a2fe134   Tejun Heo   cgroup_freezer: m...
44
  	unsigned int			state;
dc52ddc0e   Matt Helsley   container freezer...
45
  };
e5ced8ebb   Tejun Heo   cgroup_freezer: r...
46
  static DEFINE_MUTEX(freezer_mutex);
a7c6d554a   Tejun Heo   cgroup: add/updat...
47
48
49
50
  static inline struct freezer *css_freezer(struct cgroup_subsys_state *css)
  {
  	return css ? container_of(css, struct freezer, css) : NULL;
  }
dc52ddc0e   Matt Helsley   container freezer...
51
52
  static inline struct freezer *task_freezer(struct task_struct *task)
  {
073219e99   Tejun Heo   cgroup: clean up ...
53
  	return css_freezer(task_css(task, freezer_cgrp_id));
dc52ddc0e   Matt Helsley   container freezer...
54
  }
ef9fe980c   Tejun Heo   cgroup_freezer: i...
55
56
  static struct freezer *parent_freezer(struct freezer *freezer)
  {
5c9d535b8   Tejun Heo   cgroup: remove cs...
57
  	return css_freezer(freezer->css.parent);
ef9fe980c   Tejun Heo   cgroup_freezer: i...
58
  }
22b4e111f   Tejun Heo   cgroup_freezer: p...
59
  bool cgroup_freezing(struct task_struct *task)
dc52ddc0e   Matt Helsley   container freezer...
60
  {
22b4e111f   Tejun Heo   cgroup_freezer: p...
61
  	bool ret;
dc52ddc0e   Matt Helsley   container freezer...
62

22b4e111f   Tejun Heo   cgroup_freezer: p...
63
  	rcu_read_lock();
d6a2fe134   Tejun Heo   cgroup_freezer: m...
64
  	ret = task_freezer(task)->state & CGROUP_FREEZING;
22b4e111f   Tejun Heo   cgroup_freezer: p...
65
66
67
  	rcu_read_unlock();
  
  	return ret;
dc52ddc0e   Matt Helsley   container freezer...
68
  }
d6a2fe134   Tejun Heo   cgroup_freezer: m...
69
70
71
72
73
74
75
  static const char *freezer_state_strs(unsigned int state)
  {
  	if (state & CGROUP_FROZEN)
  		return "FROZEN";
  	if (state & CGROUP_FREEZING)
  		return "FREEZING";
  	return "THAWED";
dc52ddc0e   Matt Helsley   container freezer...
76
  };
eb95419b0   Tejun Heo   cgroup: pass arou...
77
78
  static struct cgroup_subsys_state *
  freezer_css_alloc(struct cgroup_subsys_state *parent_css)
dc52ddc0e   Matt Helsley   container freezer...
79
80
81
82
83
84
  {
  	struct freezer *freezer;
  
  	freezer = kzalloc(sizeof(struct freezer), GFP_KERNEL);
  	if (!freezer)
  		return ERR_PTR(-ENOMEM);
dc52ddc0e   Matt Helsley   container freezer...
85
86
  	return &freezer->css;
  }
5300a9b34   Tejun Heo   cgroup_freezer: a...
87
  /**
eb95419b0   Tejun Heo   cgroup: pass arou...
88
89
   * freezer_css_online - commit creation of a freezer css
   * @css: css being created
5300a9b34   Tejun Heo   cgroup_freezer: a...
90
   *
eb95419b0   Tejun Heo   cgroup: pass arou...
91
   * We're committing to creation of @css.  Mark it online and inherit
ef9fe980c   Tejun Heo   cgroup_freezer: i...
92
93
   * parent's freezing state while holding both parent's and our
   * freezer->lock.
5300a9b34   Tejun Heo   cgroup_freezer: a...
94
   */
eb95419b0   Tejun Heo   cgroup: pass arou...
95
  static int freezer_css_online(struct cgroup_subsys_state *css)
dc52ddc0e   Matt Helsley   container freezer...
96
  {
eb95419b0   Tejun Heo   cgroup: pass arou...
97
  	struct freezer *freezer = css_freezer(css);
ef9fe980c   Tejun Heo   cgroup_freezer: i...
98
  	struct freezer *parent = parent_freezer(freezer);
e5ced8ebb   Tejun Heo   cgroup_freezer: r...
99
  	mutex_lock(&freezer_mutex);
a3201227f   Tejun Heo   freezer: make fre...
100

5300a9b34   Tejun Heo   cgroup_freezer: a...
101
  	freezer->state |= CGROUP_FREEZER_ONLINE;
ef9fe980c   Tejun Heo   cgroup_freezer: i...
102
103
104
105
106
  
  	if (parent && (parent->state & CGROUP_FREEZING)) {
  		freezer->state |= CGROUP_FREEZING_PARENT | CGROUP_FROZEN;
  		atomic_inc(&system_freezing_cnt);
  	}
e5ced8ebb   Tejun Heo   cgroup_freezer: r...
107
  	mutex_unlock(&freezer_mutex);
b1929db42   Tejun Heo   cgroup: allow ->p...
108
  	return 0;
5300a9b34   Tejun Heo   cgroup_freezer: a...
109
110
111
  }
  
  /**
eb95419b0   Tejun Heo   cgroup: pass arou...
112
113
   * freezer_css_offline - initiate destruction of a freezer css
   * @css: css being destroyed
5300a9b34   Tejun Heo   cgroup_freezer: a...
114
   *
eb95419b0   Tejun Heo   cgroup: pass arou...
115
116
   * @css is going away.  Mark it dead and decrement system_freezing_count if
   * it was holding one.
5300a9b34   Tejun Heo   cgroup_freezer: a...
117
   */
eb95419b0   Tejun Heo   cgroup: pass arou...
118
  static void freezer_css_offline(struct cgroup_subsys_state *css)
5300a9b34   Tejun Heo   cgroup_freezer: a...
119
  {
eb95419b0   Tejun Heo   cgroup: pass arou...
120
  	struct freezer *freezer = css_freezer(css);
5300a9b34   Tejun Heo   cgroup_freezer: a...
121

e5ced8ebb   Tejun Heo   cgroup_freezer: r...
122
  	mutex_lock(&freezer_mutex);
5300a9b34   Tejun Heo   cgroup_freezer: a...
123

d6a2fe134   Tejun Heo   cgroup_freezer: m...
124
  	if (freezer->state & CGROUP_FREEZING)
a3201227f   Tejun Heo   freezer: make fre...
125
  		atomic_dec(&system_freezing_cnt);
5300a9b34   Tejun Heo   cgroup_freezer: a...
126
127
  
  	freezer->state = 0;
e5ced8ebb   Tejun Heo   cgroup_freezer: r...
128
  	mutex_unlock(&freezer_mutex);
5300a9b34   Tejun Heo   cgroup_freezer: a...
129
  }
eb95419b0   Tejun Heo   cgroup: pass arou...
130
  static void freezer_css_free(struct cgroup_subsys_state *css)
5300a9b34   Tejun Heo   cgroup_freezer: a...
131
  {
eb95419b0   Tejun Heo   cgroup: pass arou...
132
  	kfree(css_freezer(css));
dc52ddc0e   Matt Helsley   container freezer...
133
  }
957a4eeaf   Matt Helsley   container freezer...
134
  /*
ead5c4737   Tejun Heo   cgroup_freezer: d...
135
136
137
138
139
140
141
   * Tasks can be migrated into a different freezer anytime regardless of its
   * current state.  freezer_attach() is responsible for making new tasks
   * conform to the current state.
   *
   * Freezer state changes and task migration are synchronized via
   * @freezer->lock.  freezer_attach() makes the new tasks conform to the
   * current state and all following state changes can see the new tasks.
957a4eeaf   Matt Helsley   container freezer...
142
   */
1f7dd3e5a   Tejun Heo   cgroup: fix handl...
143
  static void freezer_attach(struct cgroup_taskset *tset)
dc52ddc0e   Matt Helsley   container freezer...
144
  {
bb9d97b6d   Tejun Heo   cgroup: don't use...
145
  	struct task_struct *task;
1f7dd3e5a   Tejun Heo   cgroup: fix handl...
146
  	struct cgroup_subsys_state *new_css;
957a4eeaf   Matt Helsley   container freezer...
147

e5ced8ebb   Tejun Heo   cgroup_freezer: r...
148
  	mutex_lock(&freezer_mutex);
8755ade68   Tejun Heo   cgroup_freezer: a...
149

80a6a2cf3   Li Zefan   freezer_cg: remov...
150
  	/*
eb95419b0   Tejun Heo   cgroup: pass arou...
151
  	 * Make the new tasks conform to the current state of @new_css.
8755ade68   Tejun Heo   cgroup_freezer: a...
152
153
154
155
  	 * For simplicity, when migrating any task to a FROZEN cgroup, we
  	 * revert it to FREEZING and let update_if_frozen() determine the
  	 * correct state later.
  	 *
eb95419b0   Tejun Heo   cgroup: pass arou...
156
  	 * Tasks in @tset are on @new_css but may not conform to its
8755ade68   Tejun Heo   cgroup_freezer: a...
157
158
  	 * current state before executing the following - !frozen tasks may
  	 * be visible in a FROZEN cgroup and frozen tasks in a THAWED one.
80a6a2cf3   Li Zefan   freezer_cg: remov...
159
  	 */
1f7dd3e5a   Tejun Heo   cgroup: fix handl...
160
  	cgroup_taskset_for_each(task, new_css, tset) {
599c963a0   Tejun Heo   cgroup_freezer: s...
161
  		struct freezer *freezer = css_freezer(new_css);
d6a2fe134   Tejun Heo   cgroup_freezer: m...
162
  		if (!(freezer->state & CGROUP_FREEZING)) {
8755ade68   Tejun Heo   cgroup_freezer: a...
163
164
165
  			__thaw_task(task);
  		} else {
  			freeze_task(task);
599c963a0   Tejun Heo   cgroup_freezer: s...
166
167
168
169
170
  			/* clear FROZEN and propagate upwards */
  			while (freezer && (freezer->state & CGROUP_FROZEN)) {
  				freezer->state &= ~CGROUP_FROZEN;
  				freezer = parent_freezer(freezer);
  			}
8755ade68   Tejun Heo   cgroup_freezer: a...
171
172
  		}
  	}
dc52ddc0e   Matt Helsley   container freezer...
173

e5ced8ebb   Tejun Heo   cgroup_freezer: r...
174
  	mutex_unlock(&freezer_mutex);
f780bdb7c   Ben Blum   cgroups: add per-...
175
  }
a60bed296   Tejun Heo   cgroup_freezer: d...
176
177
178
179
180
181
182
183
184
185
  /**
   * freezer_fork - cgroup post fork callback
   * @task: a task which has just been forked
   *
   * @task has just been created and should conform to the current state of
   * the cgroup_freezer it belongs to.  This function may race against
   * freezer_attach().  Losing to freezer_attach() means that we don't have
   * to do anything as freezer_attach() will put @task into the appropriate
   * state.
   */
b53202e63   Oleg Nesterov   cgroup: kill cgrp...
186
  static void freezer_fork(struct task_struct *task)
dc52ddc0e   Matt Helsley   container freezer...
187
188
  {
  	struct freezer *freezer;
3b1b3f6e5   Li Zefan   freezer_cg: disab...
189
  	/*
a60bed296   Tejun Heo   cgroup_freezer: d...
190
191
192
193
194
  	 * The root cgroup is non-freezable, so we can skip locking the
  	 * freezer.  This is safe regardless of race with task migration.
  	 * If we didn't race or won, skipping is obviously the right thing
  	 * to do.  If we lost and root is the new cgroup, noop is still the
  	 * right thing to do.
3b1b3f6e5   Li Zefan   freezer_cg: disab...
195
  	 */
e5ced8ebb   Tejun Heo   cgroup_freezer: r...
196
197
  	if (task_css_is_root(task, freezer_cgrp_id))
  		return;
3b1b3f6e5   Li Zefan   freezer_cg: disab...
198

e5ced8ebb   Tejun Heo   cgroup_freezer: r...
199
200
201
202
203
  	mutex_lock(&freezer_mutex);
  	rcu_read_lock();
  
  	freezer = task_freezer(task);
  	if (freezer->state & CGROUP_FREEZING)
839e3407d   Tejun Heo   freezer: remove u...
204
  		freeze_task(task);
e5ced8ebb   Tejun Heo   cgroup_freezer: r...
205

5edee61ed   Tejun Heo   cgroup: cgroup_su...
206
  	rcu_read_unlock();
e5ced8ebb   Tejun Heo   cgroup_freezer: r...
207
  	mutex_unlock(&freezer_mutex);
dc52ddc0e   Matt Helsley   container freezer...
208
  }
ef9fe980c   Tejun Heo   cgroup_freezer: i...
209
210
  /**
   * update_if_frozen - update whether a cgroup finished freezing
182446d08   Tejun Heo   cgroup: pass arou...
211
   * @css: css of interest
ef9fe980c   Tejun Heo   cgroup_freezer: i...
212
213
214
215
216
217
218
219
   *
   * Once FREEZING is initiated, transition to FROZEN is lazily updated by
   * calling this function.  If the current state is FREEZING but not FROZEN,
   * this function checks whether all tasks of this cgroup and the descendant
   * cgroups finished freezing and, if so, sets FROZEN.
   *
   * The caller is responsible for grabbing RCU read lock and calling
   * update_if_frozen() on all descendants prior to invoking this function.
b4d18311d   Tejun Heo   cgroup_freezer: p...
220
221
   *
   * Task states and freezer state might disagree while tasks are being
182446d08   Tejun Heo   cgroup: pass arou...
222
   * migrated into or out of @css, so we can't verify task states against
ead5c4737   Tejun Heo   cgroup_freezer: d...
223
   * @freezer state here.  See freezer_attach() for details.
dc52ddc0e   Matt Helsley   container freezer...
224
   */
182446d08   Tejun Heo   cgroup: pass arou...
225
  static void update_if_frozen(struct cgroup_subsys_state *css)
dc52ddc0e   Matt Helsley   container freezer...
226
  {
182446d08   Tejun Heo   cgroup: pass arou...
227
  	struct freezer *freezer = css_freezer(css);
492eb21b9   Tejun Heo   cgroup: make hier...
228
  	struct cgroup_subsys_state *pos;
72ec70299   Tejun Heo   cgroup: make task...
229
  	struct css_task_iter it;
dc52ddc0e   Matt Helsley   container freezer...
230
  	struct task_struct *task;
b4d18311d   Tejun Heo   cgroup_freezer: p...
231

e5ced8ebb   Tejun Heo   cgroup_freezer: r...
232
  	lockdep_assert_held(&freezer_mutex);
ef9fe980c   Tejun Heo   cgroup_freezer: i...
233

d6a2fe134   Tejun Heo   cgroup_freezer: m...
234
235
  	if (!(freezer->state & CGROUP_FREEZING) ||
  	    (freezer->state & CGROUP_FROZEN))
e5ced8ebb   Tejun Heo   cgroup_freezer: r...
236
  		return;
ef9fe980c   Tejun Heo   cgroup_freezer: i...
237
238
  
  	/* are all (live) children frozen? */
e5ced8ebb   Tejun Heo   cgroup_freezer: r...
239
  	rcu_read_lock();
492eb21b9   Tejun Heo   cgroup: make hier...
240
241
  	css_for_each_child(pos, css) {
  		struct freezer *child = css_freezer(pos);
dc52ddc0e   Matt Helsley   container freezer...
242

ef9fe980c   Tejun Heo   cgroup_freezer: i...
243
  		if ((child->state & CGROUP_FREEZER_ONLINE) &&
36e9d2ebc   Tejun Heo   cgroup: fix rcu_r...
244
245
  		    !(child->state & CGROUP_FROZEN)) {
  			rcu_read_unlock();
e5ced8ebb   Tejun Heo   cgroup_freezer: r...
246
  			return;
36e9d2ebc   Tejun Heo   cgroup: fix rcu_r...
247
  		}
ef9fe980c   Tejun Heo   cgroup_freezer: i...
248
  	}
e5ced8ebb   Tejun Heo   cgroup_freezer: r...
249
  	rcu_read_unlock();
ef9fe980c   Tejun Heo   cgroup_freezer: i...
250
251
  
  	/* are all tasks frozen? */
72ec70299   Tejun Heo   cgroup: make task...
252
  	css_task_iter_start(css, &it);
b4d18311d   Tejun Heo   cgroup_freezer: p...
253

72ec70299   Tejun Heo   cgroup: make task...
254
  	while ((task = css_task_iter_next(&it))) {
3c426d5e1   Tejun Heo   cgroup_freezer: d...
255
  		if (freezing(task)) {
3c426d5e1   Tejun Heo   cgroup_freezer: d...
256
257
258
259
260
261
  			/*
  			 * freezer_should_skip() indicates that the task
  			 * should be skipped when determining freezing
  			 * completion.  Consider it frozen in addition to
  			 * the usual frozen condition.
  			 */
5d8f72b55   Oleg Nesterov   freezer: change p...
262
  			if (!frozen(task) && !freezer_should_skip(task))
ef9fe980c   Tejun Heo   cgroup_freezer: i...
263
  				goto out_iter_end;
3c426d5e1   Tejun Heo   cgroup_freezer: d...
264
  		}
dc52ddc0e   Matt Helsley   container freezer...
265
  	}
d6a2fe134   Tejun Heo   cgroup_freezer: m...
266
  	freezer->state |= CGROUP_FROZEN;
ef9fe980c   Tejun Heo   cgroup_freezer: i...
267
  out_iter_end:
72ec70299   Tejun Heo   cgroup: make task...
268
  	css_task_iter_end(&it);
dc52ddc0e   Matt Helsley   container freezer...
269
  }
2da8ca822   Tejun Heo   cgroup: replace c...
270
  static int freezer_read(struct seq_file *m, void *v)
dc52ddc0e   Matt Helsley   container freezer...
271
  {
2da8ca822   Tejun Heo   cgroup: replace c...
272
  	struct cgroup_subsys_state *css = seq_css(m), *pos;
dc52ddc0e   Matt Helsley   container freezer...
273

e5ced8ebb   Tejun Heo   cgroup_freezer: r...
274
  	mutex_lock(&freezer_mutex);
ef9fe980c   Tejun Heo   cgroup_freezer: i...
275
  	rcu_read_lock();
dc52ddc0e   Matt Helsley   container freezer...
276

ef9fe980c   Tejun Heo   cgroup_freezer: i...
277
  	/* update states bottom-up */
e5ced8ebb   Tejun Heo   cgroup_freezer: r...
278
  	css_for_each_descendant_post(pos, css) {
ec903c0c8   Tejun Heo   cgroup: rename cs...
279
  		if (!css_tryget_online(pos))
e5ced8ebb   Tejun Heo   cgroup_freezer: r...
280
281
  			continue;
  		rcu_read_unlock();
492eb21b9   Tejun Heo   cgroup: make hier...
282
  		update_if_frozen(pos);
ef9fe980c   Tejun Heo   cgroup_freezer: i...
283

e5ced8ebb   Tejun Heo   cgroup_freezer: r...
284
285
286
  		rcu_read_lock();
  		css_put(pos);
  	}
ef9fe980c   Tejun Heo   cgroup_freezer: i...
287
  	rcu_read_unlock();
e5ced8ebb   Tejun Heo   cgroup_freezer: r...
288
  	mutex_unlock(&freezer_mutex);
ef9fe980c   Tejun Heo   cgroup_freezer: i...
289

182446d08   Tejun Heo   cgroup: pass arou...
290
  	seq_puts(m, freezer_state_strs(css_freezer(css)->state));
dc52ddc0e   Matt Helsley   container freezer...
291
292
293
294
  	seq_putc(m, '
  ');
  	return 0;
  }
bcd66c894   Tejun Heo   cgroup_freezer: t...
295
  static void freeze_cgroup(struct freezer *freezer)
dc52ddc0e   Matt Helsley   container freezer...
296
  {
72ec70299   Tejun Heo   cgroup: make task...
297
  	struct css_task_iter it;
dc52ddc0e   Matt Helsley   container freezer...
298
  	struct task_struct *task;
dc52ddc0e   Matt Helsley   container freezer...
299

72ec70299   Tejun Heo   cgroup: make task...
300
301
  	css_task_iter_start(&freezer->css, &it);
  	while ((task = css_task_iter_next(&it)))
51f246ed9   Tejun Heo   cgroup_freezer: m...
302
  		freeze_task(task);
72ec70299   Tejun Heo   cgroup: make task...
303
  	css_task_iter_end(&it);
dc52ddc0e   Matt Helsley   container freezer...
304
  }
bcd66c894   Tejun Heo   cgroup_freezer: t...
305
  static void unfreeze_cgroup(struct freezer *freezer)
dc52ddc0e   Matt Helsley   container freezer...
306
  {
72ec70299   Tejun Heo   cgroup: make task...
307
  	struct css_task_iter it;
dc52ddc0e   Matt Helsley   container freezer...
308
  	struct task_struct *task;
72ec70299   Tejun Heo   cgroup: make task...
309
310
  	css_task_iter_start(&freezer->css, &it);
  	while ((task = css_task_iter_next(&it)))
a5be2d0d1   Tejun Heo   freezer: rename t...
311
  		__thaw_task(task);
72ec70299   Tejun Heo   cgroup: make task...
312
  	css_task_iter_end(&it);
dc52ddc0e   Matt Helsley   container freezer...
313
  }
04a4ec325   Tejun Heo   cgroup_freezer: p...
314
315
316
317
  /**
   * freezer_apply_state - apply state change to a single cgroup_freezer
   * @freezer: freezer to apply state change to
   * @freeze: whether to freeze or unfreeze
a22521806   Tejun Heo   cgroup_freezer: i...
318
319
320
321
   * @state: CGROUP_FREEZING_* flag to set or clear
   *
   * Set or clear @state on @cgroup according to @freeze, and perform
   * freezing or thawing as necessary.
04a4ec325   Tejun Heo   cgroup_freezer: p...
322
   */
a22521806   Tejun Heo   cgroup_freezer: i...
323
324
  static void freezer_apply_state(struct freezer *freezer, bool freeze,
  				unsigned int state)
dc52ddc0e   Matt Helsley   container freezer...
325
  {
ead5c4737   Tejun Heo   cgroup_freezer: d...
326
  	/* also synchronizes against task migration, see freezer_attach() */
e5ced8ebb   Tejun Heo   cgroup_freezer: r...
327
  	lockdep_assert_held(&freezer_mutex);
51308ee59   Li Zefan   freezer_cg: simpl...
328

5300a9b34   Tejun Heo   cgroup_freezer: a...
329
330
  	if (!(freezer->state & CGROUP_FREEZER_ONLINE))
  		return;
04a4ec325   Tejun Heo   cgroup_freezer: p...
331
  	if (freeze) {
d6a2fe134   Tejun Heo   cgroup_freezer: m...
332
  		if (!(freezer->state & CGROUP_FREEZING))
a3201227f   Tejun Heo   freezer: make fre...
333
  			atomic_inc(&system_freezing_cnt);
a22521806   Tejun Heo   cgroup_freezer: i...
334
  		freezer->state |= state;
bcd66c894   Tejun Heo   cgroup_freezer: t...
335
  		freeze_cgroup(freezer);
04a4ec325   Tejun Heo   cgroup_freezer: p...
336
  	} else {
a22521806   Tejun Heo   cgroup_freezer: i...
337
338
339
340
341
342
343
344
345
346
  		bool was_freezing = freezer->state & CGROUP_FREEZING;
  
  		freezer->state &= ~state;
  
  		if (!(freezer->state & CGROUP_FREEZING)) {
  			if (was_freezing)
  				atomic_dec(&system_freezing_cnt);
  			freezer->state &= ~CGROUP_FROZEN;
  			unfreeze_cgroup(freezer);
  		}
dc52ddc0e   Matt Helsley   container freezer...
347
  	}
04a4ec325   Tejun Heo   cgroup_freezer: p...
348
  }
22b4e111f   Tejun Heo   cgroup_freezer: p...
349

04a4ec325   Tejun Heo   cgroup_freezer: p...
350
351
352
353
354
  /**
   * freezer_change_state - change the freezing state of a cgroup_freezer
   * @freezer: freezer of interest
   * @freeze: whether to freeze or thaw
   *
ef9fe980c   Tejun Heo   cgroup_freezer: i...
355
356
   * Freeze or thaw @freezer according to @freeze.  The operations are
   * recursive - all descendants of @freezer will be affected.
04a4ec325   Tejun Heo   cgroup_freezer: p...
357
358
359
   */
  static void freezer_change_state(struct freezer *freezer, bool freeze)
  {
492eb21b9   Tejun Heo   cgroup: make hier...
360
  	struct cgroup_subsys_state *pos;
ef9fe980c   Tejun Heo   cgroup_freezer: i...
361

ef9fe980c   Tejun Heo   cgroup_freezer: i...
362
363
364
365
366
  	/*
  	 * Update all its descendants in pre-order traversal.  Each
  	 * descendant will try to inherit its parent's FREEZING state as
  	 * CGROUP_FREEZING_PARENT.
  	 */
e5ced8ebb   Tejun Heo   cgroup_freezer: r...
367
  	mutex_lock(&freezer_mutex);
ef9fe980c   Tejun Heo   cgroup_freezer: i...
368
  	rcu_read_lock();
492eb21b9   Tejun Heo   cgroup: make hier...
369
370
  	css_for_each_descendant_pre(pos, &freezer->css) {
  		struct freezer *pos_f = css_freezer(pos);
ef9fe980c   Tejun Heo   cgroup_freezer: i...
371
  		struct freezer *parent = parent_freezer(pos_f);
ec903c0c8   Tejun Heo   cgroup: rename cs...
372
  		if (!css_tryget_online(pos))
e5ced8ebb   Tejun Heo   cgroup_freezer: r...
373
374
  			continue;
  		rcu_read_unlock();
bd8815a6d   Tejun Heo   cgroup: make css_...
375

e5ced8ebb   Tejun Heo   cgroup_freezer: r...
376
  		if (pos_f == freezer)
bd8815a6d   Tejun Heo   cgroup: make css_...
377
378
  			freezer_apply_state(pos_f, freeze,
  					    CGROUP_FREEZING_SELF);
e5ced8ebb   Tejun Heo   cgroup_freezer: r...
379
  		else
bd8815a6d   Tejun Heo   cgroup: make css_...
380
381
382
  			freezer_apply_state(pos_f,
  					    parent->state & CGROUP_FREEZING,
  					    CGROUP_FREEZING_PARENT);
bd8815a6d   Tejun Heo   cgroup: make css_...
383

e5ced8ebb   Tejun Heo   cgroup_freezer: r...
384
385
  		rcu_read_lock();
  		css_put(pos);
ef9fe980c   Tejun Heo   cgroup_freezer: i...
386
387
  	}
  	rcu_read_unlock();
e5ced8ebb   Tejun Heo   cgroup_freezer: r...
388
  	mutex_unlock(&freezer_mutex);
dc52ddc0e   Matt Helsley   container freezer...
389
  }
451af504d   Tejun Heo   cgroup: replace c...
390
391
  static ssize_t freezer_write(struct kernfs_open_file *of,
  			     char *buf, size_t nbytes, loff_t off)
dc52ddc0e   Matt Helsley   container freezer...
392
  {
04a4ec325   Tejun Heo   cgroup_freezer: p...
393
  	bool freeze;
dc52ddc0e   Matt Helsley   container freezer...
394

451af504d   Tejun Heo   cgroup: replace c...
395
396
397
  	buf = strstrip(buf);
  
  	if (strcmp(buf, freezer_state_strs(0)) == 0)
04a4ec325   Tejun Heo   cgroup_freezer: p...
398
  		freeze = false;
451af504d   Tejun Heo   cgroup: replace c...
399
  	else if (strcmp(buf, freezer_state_strs(CGROUP_FROZEN)) == 0)
04a4ec325   Tejun Heo   cgroup_freezer: p...
400
  		freeze = true;
dc52ddc0e   Matt Helsley   container freezer...
401
  	else
3b1b3f6e5   Li Zefan   freezer_cg: disab...
402
  		return -EINVAL;
dc52ddc0e   Matt Helsley   container freezer...
403

451af504d   Tejun Heo   cgroup: replace c...
404
405
  	freezer_change_state(css_freezer(of_css(of)), freeze);
  	return nbytes;
dc52ddc0e   Matt Helsley   container freezer...
406
  }
182446d08   Tejun Heo   cgroup: pass arou...
407
408
  static u64 freezer_self_freezing_read(struct cgroup_subsys_state *css,
  				      struct cftype *cft)
a22521806   Tejun Heo   cgroup_freezer: i...
409
  {
182446d08   Tejun Heo   cgroup: pass arou...
410
  	struct freezer *freezer = css_freezer(css);
a22521806   Tejun Heo   cgroup_freezer: i...
411
412
413
  
  	return (bool)(freezer->state & CGROUP_FREEZING_SELF);
  }
182446d08   Tejun Heo   cgroup: pass arou...
414
415
  static u64 freezer_parent_freezing_read(struct cgroup_subsys_state *css,
  					struct cftype *cft)
a22521806   Tejun Heo   cgroup_freezer: i...
416
  {
182446d08   Tejun Heo   cgroup: pass arou...
417
  	struct freezer *freezer = css_freezer(css);
a22521806   Tejun Heo   cgroup_freezer: i...
418
419
420
  
  	return (bool)(freezer->state & CGROUP_FREEZING_PARENT);
  }
dc52ddc0e   Matt Helsley   container freezer...
421
422
423
  static struct cftype files[] = {
  	{
  		.name = "state",
4baf6e332   Tejun Heo   cgroup: convert a...
424
  		.flags = CFTYPE_NOT_ON_ROOT,
2da8ca822   Tejun Heo   cgroup: replace c...
425
  		.seq_show = freezer_read,
451af504d   Tejun Heo   cgroup: replace c...
426
  		.write = freezer_write,
dc52ddc0e   Matt Helsley   container freezer...
427
  	},
a22521806   Tejun Heo   cgroup_freezer: i...
428
429
430
431
432
433
434
435
436
437
  	{
  		.name = "self_freezing",
  		.flags = CFTYPE_NOT_ON_ROOT,
  		.read_u64 = freezer_self_freezing_read,
  	},
  	{
  		.name = "parent_freezing",
  		.flags = CFTYPE_NOT_ON_ROOT,
  		.read_u64 = freezer_parent_freezing_read,
  	},
4baf6e332   Tejun Heo   cgroup: convert a...
438
  	{ }	/* terminate */
dc52ddc0e   Matt Helsley   container freezer...
439
  };
073219e99   Tejun Heo   cgroup: clean up ...
440
  struct cgroup_subsys freezer_cgrp_subsys = {
92fb97487   Tejun Heo   cgroup: rename ->...
441
442
443
444
  	.css_alloc	= freezer_css_alloc,
  	.css_online	= freezer_css_online,
  	.css_offline	= freezer_css_offline,
  	.css_free	= freezer_css_free,
8755ade68   Tejun Heo   cgroup_freezer: a...
445
  	.attach		= freezer_attach,
dc52ddc0e   Matt Helsley   container freezer...
446
  	.fork		= freezer_fork,
5577964e6   Tejun Heo   cgroup: rename cg...
447
  	.legacy_cftypes	= files,
dc52ddc0e   Matt Helsley   container freezer...
448
  };