Blame view

kernel/cgroup_freezer.c 12.9 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>
ef9fe980c   Tejun Heo   cgroup_freezer: i...
23
24
25
26
27
28
29
  /*
   * 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...
30
  enum freezer_state_flags {
5300a9b34   Tejun Heo   cgroup_freezer: a...
31
  	CGROUP_FREEZER_ONLINE	= (1 << 0), /* freezer is fully online */
a22521806   Tejun Heo   cgroup_freezer: i...
32
33
  	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...
34
  	CGROUP_FROZEN		= (1 << 3), /* this and its descendants frozen */
a22521806   Tejun Heo   cgroup_freezer: i...
35
36
37
  
  	/* mask for all FREEZING flags */
  	CGROUP_FREEZING		= CGROUP_FREEZING_SELF | CGROUP_FREEZING_PARENT,
dc52ddc0e   Matt Helsley   container freezer...
38
39
40
  };
  
  struct freezer {
bcd66c894   Tejun Heo   cgroup_freezer: t...
41
  	struct cgroup_subsys_state	css;
d6a2fe134   Tejun Heo   cgroup_freezer: m...
42
  	unsigned int			state;
bcd66c894   Tejun Heo   cgroup_freezer: t...
43
  	spinlock_t			lock;
dc52ddc0e   Matt Helsley   container freezer...
44
  };
bcd66c894   Tejun Heo   cgroup_freezer: t...
45
  static inline struct freezer *cgroup_freezer(struct cgroup *cgroup)
dc52ddc0e   Matt Helsley   container freezer...
46
  {
bcd66c894   Tejun Heo   cgroup_freezer: t...
47
48
  	return container_of(cgroup_subsys_state(cgroup, freezer_subsys_id),
  			    struct freezer, css);
dc52ddc0e   Matt Helsley   container freezer...
49
50
51
52
53
54
55
  }
  
  static inline struct freezer *task_freezer(struct task_struct *task)
  {
  	return container_of(task_subsys_state(task, freezer_subsys_id),
  			    struct freezer, css);
  }
ef9fe980c   Tejun Heo   cgroup_freezer: i...
56
57
58
59
60
61
62
63
  static struct freezer *parent_freezer(struct freezer *freezer)
  {
  	struct cgroup *pcg = freezer->css.cgroup->parent;
  
  	if (pcg)
  		return cgroup_freezer(pcg);
  	return NULL;
  }
22b4e111f   Tejun Heo   cgroup_freezer: p...
64
  bool cgroup_freezing(struct task_struct *task)
dc52ddc0e   Matt Helsley   container freezer...
65
  {
22b4e111f   Tejun Heo   cgroup_freezer: p...
66
  	bool ret;
dc52ddc0e   Matt Helsley   container freezer...
67

22b4e111f   Tejun Heo   cgroup_freezer: p...
68
  	rcu_read_lock();
d6a2fe134   Tejun Heo   cgroup_freezer: m...
69
  	ret = task_freezer(task)->state & CGROUP_FREEZING;
22b4e111f   Tejun Heo   cgroup_freezer: p...
70
71
72
  	rcu_read_unlock();
  
  	return ret;
dc52ddc0e   Matt Helsley   container freezer...
73
74
75
76
77
78
  }
  
  /*
   * cgroups_write_string() limits the size of freezer state strings to
   * CGROUP_LOCAL_BUFFER_SIZE
   */
d6a2fe134   Tejun Heo   cgroup_freezer: m...
79
80
81
82
83
84
85
  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...
86
  };
dc52ddc0e   Matt Helsley   container freezer...
87
  struct cgroup_subsys freezer_subsys;
92fb97487   Tejun Heo   cgroup: rename ->...
88
  static struct cgroup_subsys_state *freezer_css_alloc(struct cgroup *cgroup)
dc52ddc0e   Matt Helsley   container freezer...
89
90
91
92
93
94
95
96
  {
  	struct freezer *freezer;
  
  	freezer = kzalloc(sizeof(struct freezer), GFP_KERNEL);
  	if (!freezer)
  		return ERR_PTR(-ENOMEM);
  
  	spin_lock_init(&freezer->lock);
dc52ddc0e   Matt Helsley   container freezer...
97
98
  	return &freezer->css;
  }
5300a9b34   Tejun Heo   cgroup_freezer: a...
99
  /**
92fb97487   Tejun Heo   cgroup: rename ->...
100
   * freezer_css_online - commit creation of a freezer cgroup
5300a9b34   Tejun Heo   cgroup_freezer: a...
101
102
   * @cgroup: cgroup being created
   *
ef9fe980c   Tejun Heo   cgroup_freezer: i...
103
104
105
   * We're committing to creation of @cgroup.  Mark it online and inherit
   * parent's freezing state while holding both parent's and our
   * freezer->lock.
5300a9b34   Tejun Heo   cgroup_freezer: a...
106
   */
92fb97487   Tejun Heo   cgroup: rename ->...
107
  static int freezer_css_online(struct cgroup *cgroup)
dc52ddc0e   Matt Helsley   container freezer...
108
  {
a3201227f   Tejun Heo   freezer: make fre...
109
  	struct freezer *freezer = cgroup_freezer(cgroup);
ef9fe980c   Tejun Heo   cgroup_freezer: i...
110
111
112
113
114
115
116
117
118
119
  	struct freezer *parent = parent_freezer(freezer);
  
  	/*
  	 * The following double locking and freezing state inheritance
  	 * guarantee that @cgroup can never escape ancestors' freezing
  	 * states.  See cgroup_for_each_descendant_pre() for details.
  	 */
  	if (parent)
  		spin_lock_irq(&parent->lock);
  	spin_lock_nested(&freezer->lock, SINGLE_DEPTH_NESTING);
a3201227f   Tejun Heo   freezer: make fre...
120

5300a9b34   Tejun Heo   cgroup_freezer: a...
121
  	freezer->state |= CGROUP_FREEZER_ONLINE;
ef9fe980c   Tejun Heo   cgroup_freezer: i...
122
123
124
125
126
127
128
129
130
  
  	if (parent && (parent->state & CGROUP_FREEZING)) {
  		freezer->state |= CGROUP_FREEZING_PARENT | CGROUP_FROZEN;
  		atomic_inc(&system_freezing_cnt);
  	}
  
  	spin_unlock(&freezer->lock);
  	if (parent)
  		spin_unlock_irq(&parent->lock);
b1929db42   Tejun Heo   cgroup: allow ->p...
131
132
  
  	return 0;
5300a9b34   Tejun Heo   cgroup_freezer: a...
133
134
135
  }
  
  /**
92fb97487   Tejun Heo   cgroup: rename ->...
136
   * freezer_css_offline - initiate destruction of @cgroup
5300a9b34   Tejun Heo   cgroup_freezer: a...
137
138
139
140
141
   * @cgroup: cgroup being destroyed
   *
   * @cgroup is going away.  Mark it dead and decrement system_freezing_count
   * if it was holding one.
   */
92fb97487   Tejun Heo   cgroup: rename ->...
142
  static void freezer_css_offline(struct cgroup *cgroup)
5300a9b34   Tejun Heo   cgroup_freezer: a...
143
144
145
146
  {
  	struct freezer *freezer = cgroup_freezer(cgroup);
  
  	spin_lock_irq(&freezer->lock);
d6a2fe134   Tejun Heo   cgroup_freezer: m...
147
  	if (freezer->state & CGROUP_FREEZING)
a3201227f   Tejun Heo   freezer: make fre...
148
  		atomic_dec(&system_freezing_cnt);
5300a9b34   Tejun Heo   cgroup_freezer: a...
149
150
151
152
153
  
  	freezer->state = 0;
  
  	spin_unlock_irq(&freezer->lock);
  }
92fb97487   Tejun Heo   cgroup: rename ->...
154
  static void freezer_css_free(struct cgroup *cgroup)
5300a9b34   Tejun Heo   cgroup_freezer: a...
155
156
  {
  	kfree(cgroup_freezer(cgroup));
dc52ddc0e   Matt Helsley   container freezer...
157
  }
957a4eeaf   Matt Helsley   container freezer...
158
  /*
ead5c4737   Tejun Heo   cgroup_freezer: d...
159
160
161
162
163
164
165
   * 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...
166
   */
8755ade68   Tejun Heo   cgroup_freezer: a...
167
  static void freezer_attach(struct cgroup *new_cgrp, struct cgroup_taskset *tset)
dc52ddc0e   Matt Helsley   container freezer...
168
  {
8755ade68   Tejun Heo   cgroup_freezer: a...
169
  	struct freezer *freezer = cgroup_freezer(new_cgrp);
bb9d97b6d   Tejun Heo   cgroup: don't use...
170
  	struct task_struct *task;
ef9fe980c   Tejun Heo   cgroup_freezer: i...
171
  	bool clear_frozen = false;
957a4eeaf   Matt Helsley   container freezer...
172

8755ade68   Tejun Heo   cgroup_freezer: a...
173
  	spin_lock_irq(&freezer->lock);
80a6a2cf3   Li Zefan   freezer_cg: remov...
174
  	/*
8755ade68   Tejun Heo   cgroup_freezer: a...
175
176
177
178
179
180
181
182
  	 * Make the new tasks conform to the current state of @new_cgrp.
  	 * 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.
  	 *
  	 * Tasks in @tset are on @new_cgrp but may not conform to its
  	 * 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...
183
  	 */
8755ade68   Tejun Heo   cgroup_freezer: a...
184
  	cgroup_taskset_for_each(task, new_cgrp, tset) {
d6a2fe134   Tejun Heo   cgroup_freezer: m...
185
  		if (!(freezer->state & CGROUP_FREEZING)) {
8755ade68   Tejun Heo   cgroup_freezer: a...
186
187
188
  			__thaw_task(task);
  		} else {
  			freeze_task(task);
d6a2fe134   Tejun Heo   cgroup_freezer: m...
189
  			freezer->state &= ~CGROUP_FROZEN;
ef9fe980c   Tejun Heo   cgroup_freezer: i...
190
  			clear_frozen = true;
8755ade68   Tejun Heo   cgroup_freezer: a...
191
192
  		}
  	}
dc52ddc0e   Matt Helsley   container freezer...
193

8755ade68   Tejun Heo   cgroup_freezer: a...
194
  	spin_unlock_irq(&freezer->lock);
ef9fe980c   Tejun Heo   cgroup_freezer: i...
195
196
197
198
199
200
201
202
203
204
205
206
207
208
  
  	/*
  	 * Propagate FROZEN clearing upwards.  We may race with
  	 * update_if_frozen(), but as long as both work bottom-up, either
  	 * update_if_frozen() sees child's FROZEN cleared or we clear the
  	 * parent's FROZEN later.  No parent w/ !FROZEN children can be
  	 * left FROZEN.
  	 */
  	while (clear_frozen && (freezer = parent_freezer(freezer))) {
  		spin_lock_irq(&freezer->lock);
  		freezer->state &= ~CGROUP_FROZEN;
  		clear_frozen = freezer->state & CGROUP_FREEZING;
  		spin_unlock_irq(&freezer->lock);
  	}
f780bdb7c   Ben Blum   cgroups: add per-...
209
  }
761b3ef50   Li Zefan   cgroup: remove cg...
210
  static void freezer_fork(struct task_struct *task)
dc52ddc0e   Matt Helsley   container freezer...
211
212
  {
  	struct freezer *freezer;
8b46f8808   Paul E. McKenney   rcu: Fix RCU lock...
213
  	rcu_read_lock();
dc52ddc0e   Matt Helsley   container freezer...
214
  	freezer = task_freezer(task);
dc52ddc0e   Matt Helsley   container freezer...
215

3b1b3f6e5   Li Zefan   freezer_cg: disab...
216
217
218
219
220
  	/*
  	 * The root cgroup is non-freezable, so we can skip the
  	 * following check.
  	 */
  	if (!freezer->css.cgroup->parent)
5edee61ed   Tejun Heo   cgroup: cgroup_su...
221
  		goto out;
3b1b3f6e5   Li Zefan   freezer_cg: disab...
222

dc52ddc0e   Matt Helsley   container freezer...
223
  	spin_lock_irq(&freezer->lock);
d6a2fe134   Tejun Heo   cgroup_freezer: m...
224
  	if (freezer->state & CGROUP_FREEZING)
839e3407d   Tejun Heo   freezer: remove u...
225
  		freeze_task(task);
dc52ddc0e   Matt Helsley   container freezer...
226
  	spin_unlock_irq(&freezer->lock);
5edee61ed   Tejun Heo   cgroup: cgroup_su...
227
228
  out:
  	rcu_read_unlock();
dc52ddc0e   Matt Helsley   container freezer...
229
  }
ef9fe980c   Tejun Heo   cgroup_freezer: i...
230
231
232
233
234
235
236
237
238
239
240
  /**
   * update_if_frozen - update whether a cgroup finished freezing
   * @cgroup: cgroup of interest
   *
   * 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...
241
242
   *
   * Task states and freezer state might disagree while tasks are being
ead5c4737   Tejun Heo   cgroup_freezer: d...
243
244
   * migrated into or out of @cgroup, so we can't verify task states against
   * @freezer state here.  See freezer_attach() for details.
dc52ddc0e   Matt Helsley   container freezer...
245
   */
ef9fe980c   Tejun Heo   cgroup_freezer: i...
246
  static void update_if_frozen(struct cgroup *cgroup)
dc52ddc0e   Matt Helsley   container freezer...
247
  {
ef9fe980c   Tejun Heo   cgroup_freezer: i...
248
249
  	struct freezer *freezer = cgroup_freezer(cgroup);
  	struct cgroup *pos;
dc52ddc0e   Matt Helsley   container freezer...
250
251
  	struct cgroup_iter it;
  	struct task_struct *task;
b4d18311d   Tejun Heo   cgroup_freezer: p...
252

ef9fe980c   Tejun Heo   cgroup_freezer: i...
253
254
255
  	WARN_ON_ONCE(!rcu_read_lock_held());
  
  	spin_lock_irq(&freezer->lock);
d6a2fe134   Tejun Heo   cgroup_freezer: m...
256
257
  	if (!(freezer->state & CGROUP_FREEZING) ||
  	    (freezer->state & CGROUP_FROZEN))
ef9fe980c   Tejun Heo   cgroup_freezer: i...
258
259
260
261
262
  		goto out_unlock;
  
  	/* are all (live) children frozen? */
  	cgroup_for_each_child(pos, cgroup) {
  		struct freezer *child = cgroup_freezer(pos);
dc52ddc0e   Matt Helsley   container freezer...
263

ef9fe980c   Tejun Heo   cgroup_freezer: i...
264
265
266
267
268
269
  		if ((child->state & CGROUP_FREEZER_ONLINE) &&
  		    !(child->state & CGROUP_FROZEN))
  			goto out_unlock;
  	}
  
  	/* are all tasks frozen? */
dc52ddc0e   Matt Helsley   container freezer...
270
  	cgroup_iter_start(cgroup, &it);
b4d18311d   Tejun Heo   cgroup_freezer: p...
271

dc52ddc0e   Matt Helsley   container freezer...
272
  	while ((task = cgroup_iter_next(cgroup, &it))) {
3c426d5e1   Tejun Heo   cgroup_freezer: d...
273
  		if (freezing(task)) {
3c426d5e1   Tejun Heo   cgroup_freezer: d...
274
275
276
277
278
279
  			/*
  			 * 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...
280
  			if (!frozen(task) && !freezer_should_skip(task))
ef9fe980c   Tejun Heo   cgroup_freezer: i...
281
  				goto out_iter_end;
3c426d5e1   Tejun Heo   cgroup_freezer: d...
282
  		}
dc52ddc0e   Matt Helsley   container freezer...
283
  	}
d6a2fe134   Tejun Heo   cgroup_freezer: m...
284
  	freezer->state |= CGROUP_FROZEN;
ef9fe980c   Tejun Heo   cgroup_freezer: i...
285
  out_iter_end:
dc52ddc0e   Matt Helsley   container freezer...
286
  	cgroup_iter_end(cgroup, &it);
ef9fe980c   Tejun Heo   cgroup_freezer: i...
287
288
  out_unlock:
  	spin_unlock_irq(&freezer->lock);
dc52ddc0e   Matt Helsley   container freezer...
289
290
291
292
293
  }
  
  static int freezer_read(struct cgroup *cgroup, struct cftype *cft,
  			struct seq_file *m)
  {
ef9fe980c   Tejun Heo   cgroup_freezer: i...
294
  	struct cgroup *pos;
dc52ddc0e   Matt Helsley   container freezer...
295

ef9fe980c   Tejun Heo   cgroup_freezer: i...
296
  	rcu_read_lock();
dc52ddc0e   Matt Helsley   container freezer...
297

ef9fe980c   Tejun Heo   cgroup_freezer: i...
298
299
300
301
302
303
304
305
  	/* update states bottom-up */
  	cgroup_for_each_descendant_post(pos, cgroup)
  		update_if_frozen(pos);
  	update_if_frozen(cgroup);
  
  	rcu_read_unlock();
  
  	seq_puts(m, freezer_state_strs(cgroup_freezer(cgroup)->state));
dc52ddc0e   Matt Helsley   container freezer...
306
307
308
309
  	seq_putc(m, '
  ');
  	return 0;
  }
bcd66c894   Tejun Heo   cgroup_freezer: t...
310
  static void freeze_cgroup(struct freezer *freezer)
dc52ddc0e   Matt Helsley   container freezer...
311
  {
bcd66c894   Tejun Heo   cgroup_freezer: t...
312
  	struct cgroup *cgroup = freezer->css.cgroup;
dc52ddc0e   Matt Helsley   container freezer...
313
314
  	struct cgroup_iter it;
  	struct task_struct *task;
dc52ddc0e   Matt Helsley   container freezer...
315

dc52ddc0e   Matt Helsley   container freezer...
316
  	cgroup_iter_start(cgroup, &it);
51f246ed9   Tejun Heo   cgroup_freezer: m...
317
318
  	while ((task = cgroup_iter_next(cgroup, &it)))
  		freeze_task(task);
dc52ddc0e   Matt Helsley   container freezer...
319
  	cgroup_iter_end(cgroup, &it);
dc52ddc0e   Matt Helsley   container freezer...
320
  }
bcd66c894   Tejun Heo   cgroup_freezer: t...
321
  static void unfreeze_cgroup(struct freezer *freezer)
dc52ddc0e   Matt Helsley   container freezer...
322
  {
bcd66c894   Tejun Heo   cgroup_freezer: t...
323
  	struct cgroup *cgroup = freezer->css.cgroup;
dc52ddc0e   Matt Helsley   container freezer...
324
325
326
327
  	struct cgroup_iter it;
  	struct task_struct *task;
  
  	cgroup_iter_start(cgroup, &it);
a5be2d0d1   Tejun Heo   freezer: rename t...
328
329
  	while ((task = cgroup_iter_next(cgroup, &it)))
  		__thaw_task(task);
dc52ddc0e   Matt Helsley   container freezer...
330
  	cgroup_iter_end(cgroup, &it);
dc52ddc0e   Matt Helsley   container freezer...
331
  }
04a4ec325   Tejun Heo   cgroup_freezer: p...
332
333
334
335
  /**
   * 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...
336
337
338
339
   * @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...
340
   */
a22521806   Tejun Heo   cgroup_freezer: i...
341
342
  static void freezer_apply_state(struct freezer *freezer, bool freeze,
  				unsigned int state)
dc52ddc0e   Matt Helsley   container freezer...
343
  {
ead5c4737   Tejun Heo   cgroup_freezer: d...
344
  	/* also synchronizes against task migration, see freezer_attach() */
04a4ec325   Tejun Heo   cgroup_freezer: p...
345
  	lockdep_assert_held(&freezer->lock);
51308ee59   Li Zefan   freezer_cg: simpl...
346

5300a9b34   Tejun Heo   cgroup_freezer: a...
347
348
  	if (!(freezer->state & CGROUP_FREEZER_ONLINE))
  		return;
04a4ec325   Tejun Heo   cgroup_freezer: p...
349
  	if (freeze) {
d6a2fe134   Tejun Heo   cgroup_freezer: m...
350
  		if (!(freezer->state & CGROUP_FREEZING))
a3201227f   Tejun Heo   freezer: make fre...
351
  			atomic_inc(&system_freezing_cnt);
a22521806   Tejun Heo   cgroup_freezer: i...
352
  		freezer->state |= state;
bcd66c894   Tejun Heo   cgroup_freezer: t...
353
  		freeze_cgroup(freezer);
04a4ec325   Tejun Heo   cgroup_freezer: p...
354
  	} else {
a22521806   Tejun Heo   cgroup_freezer: i...
355
356
357
358
359
360
361
362
363
364
  		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...
365
  	}
04a4ec325   Tejun Heo   cgroup_freezer: p...
366
  }
22b4e111f   Tejun Heo   cgroup_freezer: p...
367

04a4ec325   Tejun Heo   cgroup_freezer: p...
368
369
370
371
372
  /**
   * 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...
373
374
   * Freeze or thaw @freezer according to @freeze.  The operations are
   * recursive - all descendants of @freezer will be affected.
04a4ec325   Tejun Heo   cgroup_freezer: p...
375
376
377
   */
  static void freezer_change_state(struct freezer *freezer, bool freeze)
  {
ef9fe980c   Tejun Heo   cgroup_freezer: i...
378
  	struct cgroup *pos;
04a4ec325   Tejun Heo   cgroup_freezer: p...
379
380
  	/* update @freezer */
  	spin_lock_irq(&freezer->lock);
a22521806   Tejun Heo   cgroup_freezer: i...
381
  	freezer_apply_state(freezer, freeze, CGROUP_FREEZING_SELF);
dc52ddc0e   Matt Helsley   container freezer...
382
  	spin_unlock_irq(&freezer->lock);
ef9fe980c   Tejun Heo   cgroup_freezer: i...
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
  
  	/*
  	 * Update all its descendants in pre-order traversal.  Each
  	 * descendant will try to inherit its parent's FREEZING state as
  	 * CGROUP_FREEZING_PARENT.
  	 */
  	rcu_read_lock();
  	cgroup_for_each_descendant_pre(pos, freezer->css.cgroup) {
  		struct freezer *pos_f = cgroup_freezer(pos);
  		struct freezer *parent = parent_freezer(pos_f);
  
  		/*
  		 * Our update to @parent->state is already visible which is
  		 * all we need.  No need to lock @parent.  For more info on
  		 * synchronization, see freezer_post_create().
  		 */
  		spin_lock_irq(&pos_f->lock);
  		freezer_apply_state(pos_f, parent->state & CGROUP_FREEZING,
  				    CGROUP_FREEZING_PARENT);
  		spin_unlock_irq(&pos_f->lock);
  	}
  	rcu_read_unlock();
dc52ddc0e   Matt Helsley   container freezer...
405
  }
bcd66c894   Tejun Heo   cgroup_freezer: t...
406
  static int freezer_write(struct cgroup *cgroup, struct cftype *cft,
dc52ddc0e   Matt Helsley   container freezer...
407
408
  			 const char *buffer)
  {
04a4ec325   Tejun Heo   cgroup_freezer: p...
409
  	bool freeze;
dc52ddc0e   Matt Helsley   container freezer...
410

d6a2fe134   Tejun Heo   cgroup_freezer: m...
411
  	if (strcmp(buffer, freezer_state_strs(0)) == 0)
04a4ec325   Tejun Heo   cgroup_freezer: p...
412
  		freeze = false;
d6a2fe134   Tejun Heo   cgroup_freezer: m...
413
  	else if (strcmp(buffer, freezer_state_strs(CGROUP_FROZEN)) == 0)
04a4ec325   Tejun Heo   cgroup_freezer: p...
414
  		freeze = true;
dc52ddc0e   Matt Helsley   container freezer...
415
  	else
3b1b3f6e5   Li Zefan   freezer_cg: disab...
416
  		return -EINVAL;
dc52ddc0e   Matt Helsley   container freezer...
417

04a4ec325   Tejun Heo   cgroup_freezer: p...
418
  	freezer_change_state(cgroup_freezer(cgroup), freeze);
51f246ed9   Tejun Heo   cgroup_freezer: m...
419
  	return 0;
dc52ddc0e   Matt Helsley   container freezer...
420
  }
a22521806   Tejun Heo   cgroup_freezer: i...
421
422
423
424
425
426
427
428
429
430
431
432
433
  static u64 freezer_self_freezing_read(struct cgroup *cgroup, struct cftype *cft)
  {
  	struct freezer *freezer = cgroup_freezer(cgroup);
  
  	return (bool)(freezer->state & CGROUP_FREEZING_SELF);
  }
  
  static u64 freezer_parent_freezing_read(struct cgroup *cgroup, struct cftype *cft)
  {
  	struct freezer *freezer = cgroup_freezer(cgroup);
  
  	return (bool)(freezer->state & CGROUP_FREEZING_PARENT);
  }
dc52ddc0e   Matt Helsley   container freezer...
434
435
436
  static struct cftype files[] = {
  	{
  		.name = "state",
4baf6e332   Tejun Heo   cgroup: convert a...
437
  		.flags = CFTYPE_NOT_ON_ROOT,
dc52ddc0e   Matt Helsley   container freezer...
438
439
440
  		.read_seq_string = freezer_read,
  		.write_string = freezer_write,
  	},
a22521806   Tejun Heo   cgroup_freezer: i...
441
442
443
444
445
446
447
448
449
450
  	{
  		.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...
451
  	{ }	/* terminate */
dc52ddc0e   Matt Helsley   container freezer...
452
  };
dc52ddc0e   Matt Helsley   container freezer...
453
454
  struct cgroup_subsys freezer_subsys = {
  	.name		= "freezer",
92fb97487   Tejun Heo   cgroup: rename ->...
455
456
457
458
  	.css_alloc	= freezer_css_alloc,
  	.css_online	= freezer_css_online,
  	.css_offline	= freezer_css_offline,
  	.css_free	= freezer_css_free,
dc52ddc0e   Matt Helsley   container freezer...
459
  	.subsys_id	= freezer_subsys_id,
8755ade68   Tejun Heo   cgroup_freezer: a...
460
  	.attach		= freezer_attach,
dc52ddc0e   Matt Helsley   container freezer...
461
  	.fork		= freezer_fork,
4baf6e332   Tejun Heo   cgroup: convert a...
462
  	.base_cftypes	= files,
dc52ddc0e   Matt Helsley   container freezer...
463
  };