• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/cgroup.h>
3 #include <linux/sched.h>
4 #include <linux/sched/task.h>
5 #include <linux/sched/signal.h>
6 
7 #include "cgroup-internal.h"
8 
9 #include <trace/events/cgroup.h>
10 #include <trace/hooks/dtask.h>
11 
12 /*
13  * Propagate the cgroup frozen state upwards by the cgroup tree.
14  */
cgroup_propagate_frozen(struct cgroup * cgrp,bool frozen)15 static void cgroup_propagate_frozen(struct cgroup *cgrp, bool frozen)
16 {
17 	int desc = 1;
18 
19 	/*
20 	 * If the new state is frozen, some freezing ancestor cgroups may change
21 	 * their state too, depending on if all their descendants are frozen.
22 	 *
23 	 * Otherwise, all ancestor cgroups are forced into the non-frozen state.
24 	 */
25 	while ((cgrp = cgroup_parent(cgrp))) {
26 		if (frozen) {
27 			cgrp->freezer.nr_frozen_descendants += desc;
28 			if (!test_bit(CGRP_FROZEN, &cgrp->flags) &&
29 			    test_bit(CGRP_FREEZE, &cgrp->flags) &&
30 			    cgrp->freezer.nr_frozen_descendants ==
31 			    cgrp->nr_descendants) {
32 				set_bit(CGRP_FROZEN, &cgrp->flags);
33 				cgroup_file_notify(&cgrp->events_file);
34 				TRACE_CGROUP_PATH(notify_frozen, cgrp, 1);
35 				desc++;
36 			}
37 		} else {
38 			cgrp->freezer.nr_frozen_descendants -= desc;
39 			if (test_bit(CGRP_FROZEN, &cgrp->flags)) {
40 				clear_bit(CGRP_FROZEN, &cgrp->flags);
41 				cgroup_file_notify(&cgrp->events_file);
42 				TRACE_CGROUP_PATH(notify_frozen, cgrp, 0);
43 				desc++;
44 			}
45 		}
46 	}
47 }
48 
49 /*
50  * Revisit the cgroup frozen state.
51  * Checks if the cgroup is really frozen and perform all state transitions.
52  */
cgroup_update_frozen(struct cgroup * cgrp)53 void cgroup_update_frozen(struct cgroup *cgrp)
54 {
55 	bool frozen;
56 
57 	lockdep_assert_held(&css_set_lock);
58 
59 	/*
60 	 * If the cgroup has to be frozen (CGRP_FREEZE bit set),
61 	 * and all tasks are frozen and/or stopped, let's consider
62 	 * the cgroup frozen. Otherwise it's not frozen.
63 	 */
64 	frozen = test_bit(CGRP_FREEZE, &cgrp->flags) &&
65 		cgrp->freezer.nr_frozen_tasks == __cgroup_task_count(cgrp);
66 
67 	if (frozen) {
68 		/* Already there? */
69 		if (test_bit(CGRP_FROZEN, &cgrp->flags))
70 			return;
71 
72 		set_bit(CGRP_FROZEN, &cgrp->flags);
73 	} else {
74 		/* Already there? */
75 		if (!test_bit(CGRP_FROZEN, &cgrp->flags))
76 			return;
77 
78 		clear_bit(CGRP_FROZEN, &cgrp->flags);
79 	}
80 	cgroup_file_notify(&cgrp->events_file);
81 	TRACE_CGROUP_PATH(notify_frozen, cgrp, frozen);
82 
83 	/* Update the state of ancestor cgroups. */
84 	cgroup_propagate_frozen(cgrp, frozen);
85 }
86 
87 /*
88  * Increment cgroup's nr_frozen_tasks.
89  */
cgroup_inc_frozen_cnt(struct cgroup * cgrp)90 static void cgroup_inc_frozen_cnt(struct cgroup *cgrp)
91 {
92 	cgrp->freezer.nr_frozen_tasks++;
93 }
94 
95 /*
96  * Decrement cgroup's nr_frozen_tasks.
97  */
cgroup_dec_frozen_cnt(struct cgroup * cgrp)98 static void cgroup_dec_frozen_cnt(struct cgroup *cgrp)
99 {
100 	cgrp->freezer.nr_frozen_tasks--;
101 	WARN_ON_ONCE(cgrp->freezer.nr_frozen_tasks < 0);
102 }
103 
104 /*
105  * Enter frozen/stopped state, if not yet there. Update cgroup's counters,
106  * and revisit the state of the cgroup, if necessary.
107  */
cgroup_enter_frozen(void)108 void cgroup_enter_frozen(void)
109 {
110 	struct cgroup *cgrp;
111 
112 	if (current->frozen)
113 		return;
114 
115 	spin_lock_irq(&css_set_lock);
116 	current->frozen = true;
117 	cgrp = task_dfl_cgroup(current);
118 	cgroup_inc_frozen_cnt(cgrp);
119 	cgroup_update_frozen(cgrp);
120 	spin_unlock_irq(&css_set_lock);
121 }
122 
123 /*
124  * Conditionally leave frozen/stopped state. Update cgroup's counters,
125  * and revisit the state of the cgroup, if necessary.
126  *
127  * If always_leave is not set, and the cgroup is freezing,
128  * we're racing with the cgroup freezing. In this case, we don't
129  * drop the frozen counter to avoid a transient switch to
130  * the unfrozen state.
131  */
cgroup_leave_frozen(bool always_leave)132 void cgroup_leave_frozen(bool always_leave)
133 {
134 	struct cgroup *cgrp;
135 
136 	spin_lock_irq(&css_set_lock);
137 	cgrp = task_dfl_cgroup(current);
138 	if (always_leave || !test_bit(CGRP_FREEZE, &cgrp->flags)) {
139 		cgroup_dec_frozen_cnt(cgrp);
140 		cgroup_update_frozen(cgrp);
141 		WARN_ON_ONCE(!current->frozen);
142 		current->frozen = false;
143 	} else if (!(current->jobctl & JOBCTL_TRAP_FREEZE)) {
144 		spin_lock(&current->sighand->siglock);
145 		current->jobctl |= JOBCTL_TRAP_FREEZE;
146 		set_thread_flag(TIF_SIGPENDING);
147 		spin_unlock(&current->sighand->siglock);
148 	}
149 	spin_unlock_irq(&css_set_lock);
150 }
151 
152 /*
153  * Freeze or unfreeze the task by setting or clearing the JOBCTL_TRAP_FREEZE
154  * jobctl bit.
155  */
cgroup_freeze_task(struct task_struct * task,bool freeze)156 static void cgroup_freeze_task(struct task_struct *task, bool freeze)
157 {
158 	unsigned long flags;
159 	bool wake = true;
160 
161 	/* If the task is about to die, don't bother with freezing it. */
162 	if (!lock_task_sighand(task, &flags))
163 		return;
164 
165 	trace_android_vh_freeze_whether_wake(task, &wake);
166 	if (freeze) {
167 		task->jobctl |= JOBCTL_TRAP_FREEZE;
168 		if (wake)
169 			signal_wake_up(task, false);
170 	} else {
171 		task->jobctl &= ~JOBCTL_TRAP_FREEZE;
172 		if (wake)
173 			wake_up_process(task);
174 	}
175 
176 	unlock_task_sighand(task, &flags);
177 }
178 
179 /*
180  * Freeze or unfreeze all tasks in the given cgroup.
181  */
cgroup_do_freeze(struct cgroup * cgrp,bool freeze)182 static void cgroup_do_freeze(struct cgroup *cgrp, bool freeze)
183 {
184 	struct css_task_iter it;
185 	struct task_struct *task;
186 
187 	lockdep_assert_held(&cgroup_mutex);
188 
189 	spin_lock_irq(&css_set_lock);
190 	if (freeze)
191 		set_bit(CGRP_FREEZE, &cgrp->flags);
192 	else
193 		clear_bit(CGRP_FREEZE, &cgrp->flags);
194 	spin_unlock_irq(&css_set_lock);
195 
196 	if (freeze)
197 		TRACE_CGROUP_PATH(freeze, cgrp);
198 	else
199 		TRACE_CGROUP_PATH(unfreeze, cgrp);
200 
201 	css_task_iter_start(&cgrp->self, 0, &it);
202 	while ((task = css_task_iter_next(&it))) {
203 		/*
204 		 * Ignore kernel threads here. Freezing cgroups containing
205 		 * kthreads isn't supported.
206 		 */
207 		if (task->flags & PF_KTHREAD)
208 			continue;
209 		cgroup_freeze_task(task, freeze);
210 	}
211 	css_task_iter_end(&it);
212 
213 	/*
214 	 * Cgroup state should be revisited here to cover empty leaf cgroups
215 	 * and cgroups which descendants are already in the desired state.
216 	 */
217 	spin_lock_irq(&css_set_lock);
218 	if (cgrp->nr_descendants == cgrp->freezer.nr_frozen_descendants)
219 		cgroup_update_frozen(cgrp);
220 	spin_unlock_irq(&css_set_lock);
221 }
222 
223 /*
224  * Adjust the task state (freeze or unfreeze) and revisit the state of
225  * source and destination cgroups.
226  */
cgroup_freezer_migrate_task(struct task_struct * task,struct cgroup * src,struct cgroup * dst)227 void cgroup_freezer_migrate_task(struct task_struct *task,
228 				 struct cgroup *src, struct cgroup *dst)
229 {
230 	lockdep_assert_held(&css_set_lock);
231 
232 	/*
233 	 * Kernel threads are not supposed to be frozen at all.
234 	 */
235 	if (task->flags & PF_KTHREAD)
236 		return;
237 
238 	/*
239 	 * It's not necessary to do changes if both of the src and dst cgroups
240 	 * are not freezing and task is not frozen.
241 	 */
242 	if (!test_bit(CGRP_FREEZE, &src->flags) &&
243 	    !test_bit(CGRP_FREEZE, &dst->flags) &&
244 	    !task->frozen)
245 		return;
246 
247 	/*
248 	 * Adjust counters of freezing and frozen tasks.
249 	 * Note, that if the task is frozen, but the destination cgroup is not
250 	 * frozen, we bump both counters to keep them balanced.
251 	 */
252 	if (task->frozen) {
253 		cgroup_inc_frozen_cnt(dst);
254 		cgroup_dec_frozen_cnt(src);
255 	}
256 	cgroup_update_frozen(dst);
257 	cgroup_update_frozen(src);
258 
259 	/*
260 	 * Force the task to the desired state.
261 	 */
262 	cgroup_freeze_task(task, test_bit(CGRP_FREEZE, &dst->flags));
263 }
264 
cgroup_freeze(struct cgroup * cgrp,bool freeze)265 void cgroup_freeze(struct cgroup *cgrp, bool freeze)
266 {
267 	struct cgroup_subsys_state *css;
268 	struct cgroup *dsct;
269 	bool applied = false;
270 
271 	lockdep_assert_held(&cgroup_mutex);
272 
273 	/*
274 	 * Nothing changed? Just exit.
275 	 */
276 	if (cgrp->freezer.freeze == freeze)
277 		return;
278 
279 	cgrp->freezer.freeze = freeze;
280 
281 	/*
282 	 * Propagate changes downwards the cgroup tree.
283 	 */
284 	css_for_each_descendant_pre(css, &cgrp->self) {
285 		dsct = css->cgroup;
286 
287 		if (cgroup_is_dead(dsct))
288 			continue;
289 
290 		if (freeze) {
291 			dsct->freezer.e_freeze++;
292 			/*
293 			 * Already frozen because of ancestor's settings?
294 			 */
295 			if (dsct->freezer.e_freeze > 1)
296 				continue;
297 		} else {
298 			dsct->freezer.e_freeze--;
299 			/*
300 			 * Still frozen because of ancestor's settings?
301 			 */
302 			if (dsct->freezer.e_freeze > 0)
303 				continue;
304 
305 			WARN_ON_ONCE(dsct->freezer.e_freeze < 0);
306 		}
307 
308 		/*
309 		 * Do change actual state: freeze or unfreeze.
310 		 */
311 		cgroup_do_freeze(dsct, freeze);
312 		applied = true;
313 	}
314 
315 	/*
316 	 * Even if the actual state hasn't changed, let's notify a user.
317 	 * The state can be enforced by an ancestor cgroup: the cgroup
318 	 * can already be in the desired state or it can be locked in the
319 	 * opposite state, so that the transition will never happen.
320 	 * In both cases it's better to notify a user, that there is
321 	 * nothing to wait for.
322 	 */
323 	if (!applied) {
324 		TRACE_CGROUP_PATH(notify_frozen, cgrp,
325 				  test_bit(CGRP_FROZEN, &cgrp->flags));
326 		cgroup_file_notify(&cgrp->events_file);
327 	}
328 }
329