Blame view

kernel/cgroup_freezer.c 12.5 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
   */
eb95419b0   Tejun Heo   cgroup: pass arou...
143
144
  static void freezer_attach(struct cgroup_subsys_state *new_css,
  			   struct cgroup_taskset *tset)
dc52ddc0e   Matt Helsley   container freezer...
145
  {
eb95419b0   Tejun Heo   cgroup: pass arou...
146
  	struct freezer *freezer = css_freezer(new_css);
bb9d97b6d   Tejun Heo   cgroup: don't use...
147
  	struct task_struct *task;
ef9fe980c   Tejun Heo   cgroup_freezer: i...
148
  	bool clear_frozen = false;
957a4eeaf   Matt Helsley   container freezer...
149

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

80a6a2cf3   Li Zefan   freezer_cg: remov...
152
  	/*
eb95419b0   Tejun Heo   cgroup: pass arou...
153
  	 * Make the new tasks conform to the current state of @new_css.
8755ade68   Tejun Heo   cgroup_freezer: a...
154
155
156
157
  	 * 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...
158
  	 * Tasks in @tset are on @new_css but may not conform to its
8755ade68   Tejun Heo   cgroup_freezer: a...
159
160
  	 * 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...
161
  	 */
924f0d9a2   Tejun Heo   cgroup: drop @ski...
162
  	cgroup_taskset_for_each(task, tset) {
d6a2fe134   Tejun Heo   cgroup_freezer: m...
163
  		if (!(freezer->state & CGROUP_FREEZING)) {
8755ade68   Tejun Heo   cgroup_freezer: a...
164
165
166
  			__thaw_task(task);
  		} else {
  			freeze_task(task);
d6a2fe134   Tejun Heo   cgroup_freezer: m...
167
  			freezer->state &= ~CGROUP_FROZEN;
ef9fe980c   Tejun Heo   cgroup_freezer: i...
168
  			clear_frozen = true;
8755ade68   Tejun Heo   cgroup_freezer: a...
169
170
  		}
  	}
dc52ddc0e   Matt Helsley   container freezer...
171

e5ced8ebb   Tejun Heo   cgroup_freezer: r...
172
  	/* propagate FROZEN clearing upwards */
ef9fe980c   Tejun Heo   cgroup_freezer: i...
173
  	while (clear_frozen && (freezer = parent_freezer(freezer))) {
ef9fe980c   Tejun Heo   cgroup_freezer: i...
174
175
  		freezer->state &= ~CGROUP_FROZEN;
  		clear_frozen = freezer->state & CGROUP_FREEZING;
ef9fe980c   Tejun Heo   cgroup_freezer: i...
176
  	}
e5ced8ebb   Tejun Heo   cgroup_freezer: r...
177
178
  
  	mutex_unlock(&freezer_mutex);
f780bdb7c   Ben Blum   cgroups: add per-...
179
  }
a60bed296   Tejun Heo   cgroup_freezer: d...
180
181
182
183
184
185
186
187
188
189
  /**
   * 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.
   */
761b3ef50   Li Zefan   cgroup: remove cg...
190
  static void freezer_fork(struct task_struct *task)
dc52ddc0e   Matt Helsley   container freezer...
191
192
  {
  	struct freezer *freezer;
3b1b3f6e5   Li Zefan   freezer_cg: disab...
193
  	/*
a60bed296   Tejun Heo   cgroup_freezer: d...
194
195
196
197
198
  	 * 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...
199
  	 */
e5ced8ebb   Tejun Heo   cgroup_freezer: r...
200
201
  	if (task_css_is_root(task, freezer_cgrp_id))
  		return;
3b1b3f6e5   Li Zefan   freezer_cg: disab...
202

e5ced8ebb   Tejun Heo   cgroup_freezer: r...
203
204
205
206
207
  	mutex_lock(&freezer_mutex);
  	rcu_read_lock();
  
  	freezer = task_freezer(task);
  	if (freezer->state & CGROUP_FREEZING)
839e3407d   Tejun Heo   freezer: remove u...
208
  		freeze_task(task);
e5ced8ebb   Tejun Heo   cgroup_freezer: r...
209

5edee61ed   Tejun Heo   cgroup: cgroup_su...
210
  	rcu_read_unlock();
e5ced8ebb   Tejun Heo   cgroup_freezer: r...
211
  	mutex_unlock(&freezer_mutex);
dc52ddc0e   Matt Helsley   container freezer...
212
  }
ef9fe980c   Tejun Heo   cgroup_freezer: i...
213
214
  /**
   * update_if_frozen - update whether a cgroup finished freezing
182446d08   Tejun Heo   cgroup: pass arou...
215
   * @css: css of interest
ef9fe980c   Tejun Heo   cgroup_freezer: i...
216
217
218
219
220
221
222
223
   *
   * 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...
224
225
   *
   * Task states and freezer state might disagree while tasks are being
182446d08   Tejun Heo   cgroup: pass arou...
226
   * migrated into or out of @css, so we can't verify task states against
ead5c4737   Tejun Heo   cgroup_freezer: d...
227
   * @freezer state here.  See freezer_attach() for details.
dc52ddc0e   Matt Helsley   container freezer...
228
   */
182446d08   Tejun Heo   cgroup: pass arou...
229
  static void update_if_frozen(struct cgroup_subsys_state *css)
dc52ddc0e   Matt Helsley   container freezer...
230
  {
182446d08   Tejun Heo   cgroup: pass arou...
231
  	struct freezer *freezer = css_freezer(css);
492eb21b9   Tejun Heo   cgroup: make hier...
232
  	struct cgroup_subsys_state *pos;
72ec70299   Tejun Heo   cgroup: make task...
233
  	struct css_task_iter it;
dc52ddc0e   Matt Helsley   container freezer...
234
  	struct task_struct *task;
b4d18311d   Tejun Heo   cgroup_freezer: p...
235

e5ced8ebb   Tejun Heo   cgroup_freezer: r...
236
  	lockdep_assert_held(&freezer_mutex);
ef9fe980c   Tejun Heo   cgroup_freezer: i...
237

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

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

72ec70299   Tejun Heo   cgroup: make task...
258
  	while ((task = css_task_iter_next(&it))) {
3c426d5e1   Tejun Heo   cgroup_freezer: d...
259
  		if (freezing(task)) {
3c426d5e1   Tejun Heo   cgroup_freezer: d...
260
261
262
263
264
265
  			/*
  			 * 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...
266
  			if (!frozen(task) && !freezer_should_skip(task))
ef9fe980c   Tejun Heo   cgroup_freezer: i...
267
  				goto out_iter_end;
3c426d5e1   Tejun Heo   cgroup_freezer: d...
268
  		}
dc52ddc0e   Matt Helsley   container freezer...
269
  	}
d6a2fe134   Tejun Heo   cgroup_freezer: m...
270
  	freezer->state |= CGROUP_FROZEN;
ef9fe980c   Tejun Heo   cgroup_freezer: i...
271
  out_iter_end:
72ec70299   Tejun Heo   cgroup: make task...
272
  	css_task_iter_end(&it);
dc52ddc0e   Matt Helsley   container freezer...
273
  }
2da8ca822   Tejun Heo   cgroup: replace c...
274
  static int freezer_read(struct seq_file *m, void *v)
dc52ddc0e   Matt Helsley   container freezer...
275
  {
2da8ca822   Tejun Heo   cgroup: replace c...
276
  	struct cgroup_subsys_state *css = seq_css(m), *pos;
dc52ddc0e   Matt Helsley   container freezer...
277

e5ced8ebb   Tejun Heo   cgroup_freezer: r...
278
  	mutex_lock(&freezer_mutex);
ef9fe980c   Tejun Heo   cgroup_freezer: i...
279
  	rcu_read_lock();
dc52ddc0e   Matt Helsley   container freezer...
280

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

e5ced8ebb   Tejun Heo   cgroup_freezer: r...
288
289
290
  		rcu_read_lock();
  		css_put(pos);
  	}
ef9fe980c   Tejun Heo   cgroup_freezer: i...
291
  	rcu_read_unlock();
e5ced8ebb   Tejun Heo   cgroup_freezer: r...
292
  	mutex_unlock(&freezer_mutex);
ef9fe980c   Tejun Heo   cgroup_freezer: i...
293

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

72ec70299   Tejun Heo   cgroup: make task...
304
305
  	css_task_iter_start(&freezer->css, &it);
  	while ((task = css_task_iter_next(&it)))
51f246ed9   Tejun Heo   cgroup_freezer: m...
306
  		freeze_task(task);
72ec70299   Tejun Heo   cgroup: make task...
307
  	css_task_iter_end(&it);
dc52ddc0e   Matt Helsley   container freezer...
308
  }
bcd66c894   Tejun Heo   cgroup_freezer: t...
309
  static void unfreeze_cgroup(struct freezer *freezer)
dc52ddc0e   Matt Helsley   container freezer...
310
  {
72ec70299   Tejun Heo   cgroup: make task...
311
  	struct css_task_iter it;
dc52ddc0e   Matt Helsley   container freezer...
312
  	struct task_struct *task;
72ec70299   Tejun Heo   cgroup: make task...
313
314
  	css_task_iter_start(&freezer->css, &it);
  	while ((task = css_task_iter_next(&it)))
a5be2d0d1   Tejun Heo   freezer: rename t...
315
  		__thaw_task(task);
72ec70299   Tejun Heo   cgroup: make task...
316
  	css_task_iter_end(&it);
dc52ddc0e   Matt Helsley   container freezer...
317
  }
04a4ec325   Tejun Heo   cgroup_freezer: p...
318
319
320
321
  /**
   * 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...
322
323
324
325
   * @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...
326
   */
a22521806   Tejun Heo   cgroup_freezer: i...
327
328
  static void freezer_apply_state(struct freezer *freezer, bool freeze,
  				unsigned int state)
dc52ddc0e   Matt Helsley   container freezer...
329
  {
ead5c4737   Tejun Heo   cgroup_freezer: d...
330
  	/* also synchronizes against task migration, see freezer_attach() */
e5ced8ebb   Tejun Heo   cgroup_freezer: r...
331
  	lockdep_assert_held(&freezer_mutex);
51308ee59   Li Zefan   freezer_cg: simpl...
332

5300a9b34   Tejun Heo   cgroup_freezer: a...
333
334
  	if (!(freezer->state & CGROUP_FREEZER_ONLINE))
  		return;
04a4ec325   Tejun Heo   cgroup_freezer: p...
335
  	if (freeze) {
d6a2fe134   Tejun Heo   cgroup_freezer: m...
336
  		if (!(freezer->state & CGROUP_FREEZING))
a3201227f   Tejun Heo   freezer: make fre...
337
  			atomic_inc(&system_freezing_cnt);
a22521806   Tejun Heo   cgroup_freezer: i...
338
  		freezer->state |= state;
bcd66c894   Tejun Heo   cgroup_freezer: t...
339
  		freeze_cgroup(freezer);
04a4ec325   Tejun Heo   cgroup_freezer: p...
340
  	} else {
a22521806   Tejun Heo   cgroup_freezer: i...
341
342
343
344
345
346
347
348
349
350
  		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...
351
  	}
04a4ec325   Tejun Heo   cgroup_freezer: p...
352
  }
22b4e111f   Tejun Heo   cgroup_freezer: p...
353

04a4ec325   Tejun Heo   cgroup_freezer: p...
354
355
356
357
358
  /**
   * 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...
359
360
   * Freeze or thaw @freezer according to @freeze.  The operations are
   * recursive - all descendants of @freezer will be affected.
04a4ec325   Tejun Heo   cgroup_freezer: p...
361
362
363
   */
  static void freezer_change_state(struct freezer *freezer, bool freeze)
  {
492eb21b9   Tejun Heo   cgroup: make hier...
364
  	struct cgroup_subsys_state *pos;
ef9fe980c   Tejun Heo   cgroup_freezer: i...
365

ef9fe980c   Tejun Heo   cgroup_freezer: i...
366
367
368
369
370
  	/*
  	 * 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...
371
  	mutex_lock(&freezer_mutex);
ef9fe980c   Tejun Heo   cgroup_freezer: i...
372
  	rcu_read_lock();
492eb21b9   Tejun Heo   cgroup: make hier...
373
374
  	css_for_each_descendant_pre(pos, &freezer->css) {
  		struct freezer *pos_f = css_freezer(pos);
ef9fe980c   Tejun Heo   cgroup_freezer: i...
375
  		struct freezer *parent = parent_freezer(pos_f);
ec903c0c8   Tejun Heo   cgroup: rename cs...
376
  		if (!css_tryget_online(pos))
e5ced8ebb   Tejun Heo   cgroup_freezer: r...
377
378
  			continue;
  		rcu_read_unlock();
bd8815a6d   Tejun Heo   cgroup: make css_...
379

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

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

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

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