1/* Freezer declarations */
2
3#ifndef FREEZER_H_INCLUDED
4#define FREEZER_H_INCLUDED
5
6#include <linux/debug_locks.h>
7#include <linux/sched.h>
8#include <linux/wait.h>
9#include <linux/atomic.h>
10
11#ifdef CONFIG_FREEZER
12extern atomic_t system_freezing_cnt;	/* nr of freezing conds in effect */
13extern bool pm_freezing;		/* PM freezing in effect */
14extern bool pm_nosig_freezing;		/* PM nosig freezing in effect */
15
16/*
17 * Timeout for stopping processes
18 */
19extern unsigned int freeze_timeout_msecs;
20
21/*
22 * Check if a process has been frozen
23 */
24static inline bool frozen(struct task_struct *p)
25{
26	return p->flags & PF_FROZEN;
27}
28
29extern bool freezing_slow_path(struct task_struct *p);
30
31/*
32 * Check if there is a request to freeze a process
33 */
34static inline bool freezing(struct task_struct *p)
35{
36	if (likely(!atomic_read(&system_freezing_cnt)))
37		return false;
38	return freezing_slow_path(p);
39}
40
41/* Takes and releases task alloc lock using task_lock() */
42extern void __thaw_task(struct task_struct *t);
43
44extern bool __refrigerator(bool check_kthr_stop);
45extern int freeze_processes(void);
46extern int freeze_kernel_threads(void);
47extern void thaw_processes(void);
48extern void thaw_kernel_threads(void);
49
50/*
51 * DO NOT ADD ANY NEW CALLERS OF THIS FUNCTION
52 * If try_to_freeze causes a lockdep warning it means the caller may deadlock
53 */
54static inline bool try_to_freeze_unsafe(void)
55{
56	might_sleep();
57	if (likely(!freezing(current)))
58		return false;
59	return __refrigerator(false);
60}
61
62static inline bool try_to_freeze(void)
63{
64	if (!(current->flags & PF_NOFREEZE))
65		debug_check_no_locks_held();
66	return try_to_freeze_unsafe();
67}
68
69extern bool freeze_task(struct task_struct *p);
70extern bool set_freezable(void);
71
72#ifdef CONFIG_CGROUP_FREEZER
73extern bool cgroup_freezing(struct task_struct *task);
74#else /* !CONFIG_CGROUP_FREEZER */
75static inline bool cgroup_freezing(struct task_struct *task)
76{
77	return false;
78}
79#endif /* !CONFIG_CGROUP_FREEZER */
80
81/*
82 * The PF_FREEZER_SKIP flag should be set by a vfork parent right before it
83 * calls wait_for_completion(&vfork) and reset right after it returns from this
84 * function.  Next, the parent should call try_to_freeze() to freeze itself
85 * appropriately in case the child has exited before the freezing of tasks is
86 * complete.  However, we don't want kernel threads to be frozen in unexpected
87 * places, so we allow them to block freeze_processes() instead or to set
88 * PF_NOFREEZE if needed. Fortunately, in the ____call_usermodehelper() case the
89 * parent won't really block freeze_processes(), since ____call_usermodehelper()
90 * (the child) does a little before exec/exit and it can't be frozen before
91 * waking up the parent.
92 */
93
94
95/**
96 * freezer_do_not_count - tell freezer to ignore %current
97 *
98 * Tell freezers to ignore the current task when determining whether the
99 * target frozen state is reached.  IOW, the current task will be
100 * considered frozen enough by freezers.
101 *
102 * The caller shouldn't do anything which isn't allowed for a frozen task
103 * until freezer_cont() is called.  Usually, freezer[_do_not]_count() pair
104 * wrap a scheduling operation and nothing much else.
105 */
106static inline void freezer_do_not_count(void)
107{
108	current->flags |= PF_FREEZER_SKIP;
109}
110
111/**
112 * freezer_count - tell freezer to stop ignoring %current
113 *
114 * Undo freezer_do_not_count().  It tells freezers that %current should be
115 * considered again and tries to freeze if freezing condition is already in
116 * effect.
117 */
118static inline void freezer_count(void)
119{
120	current->flags &= ~PF_FREEZER_SKIP;
121	/*
122	 * If freezing is in progress, the following paired with smp_mb()
123	 * in freezer_should_skip() ensures that either we see %true
124	 * freezing() or freezer_should_skip() sees !PF_FREEZER_SKIP.
125	 */
126	smp_mb();
127	try_to_freeze();
128}
129
130/* DO NOT ADD ANY NEW CALLERS OF THIS FUNCTION */
131static inline void freezer_count_unsafe(void)
132{
133	current->flags &= ~PF_FREEZER_SKIP;
134	smp_mb();
135	try_to_freeze_unsafe();
136}
137
138/**
139 * freezer_should_skip - whether to skip a task when determining frozen
140 *			 state is reached
141 * @p: task in quesion
142 *
143 * This function is used by freezers after establishing %true freezing() to
144 * test whether a task should be skipped when determining the target frozen
145 * state is reached.  IOW, if this function returns %true, @p is considered
146 * frozen enough.
147 */
148static inline bool freezer_should_skip(struct task_struct *p)
149{
150	/*
151	 * The following smp_mb() paired with the one in freezer_count()
152	 * ensures that either freezer_count() sees %true freezing() or we
153	 * see cleared %PF_FREEZER_SKIP and return %false.  This makes it
154	 * impossible for a task to slip frozen state testing after
155	 * clearing %PF_FREEZER_SKIP.
156	 */
157	smp_mb();
158	return p->flags & PF_FREEZER_SKIP;
159}
160
161/*
162 * These functions are intended to be used whenever you want allow a sleeping
163 * task to be frozen. Note that neither return any clear indication of
164 * whether a freeze event happened while in this function.
165 */
166
167/* Like schedule(), but should not block the freezer. */
168static inline void freezable_schedule(void)
169{
170	freezer_do_not_count();
171	schedule();
172	freezer_count();
173}
174
175/* DO NOT ADD ANY NEW CALLERS OF THIS FUNCTION */
176static inline void freezable_schedule_unsafe(void)
177{
178	freezer_do_not_count();
179	schedule();
180	freezer_count_unsafe();
181}
182
183/*
184 * Like freezable_schedule_timeout(), but should not block the freezer.  Do not
185 * call this with locks held.
186 */
187static inline long freezable_schedule_timeout(long timeout)
188{
189	long __retval;
190	freezer_do_not_count();
191	__retval = schedule_timeout(timeout);
192	freezer_count();
193	return __retval;
194}
195
196/*
197 * Like schedule_timeout_interruptible(), but should not block the freezer.  Do not
198 * call this with locks held.
199 */
200static inline long freezable_schedule_timeout_interruptible(long timeout)
201{
202	long __retval;
203	freezer_do_not_count();
204	__retval = schedule_timeout_interruptible(timeout);
205	freezer_count();
206	return __retval;
207}
208
209/* Like schedule_timeout_killable(), but should not block the freezer. */
210static inline long freezable_schedule_timeout_killable(long timeout)
211{
212	long __retval;
213	freezer_do_not_count();
214	__retval = schedule_timeout_killable(timeout);
215	freezer_count();
216	return __retval;
217}
218
219/* DO NOT ADD ANY NEW CALLERS OF THIS FUNCTION */
220static inline long freezable_schedule_timeout_killable_unsafe(long timeout)
221{
222	long __retval;
223	freezer_do_not_count();
224	__retval = schedule_timeout_killable(timeout);
225	freezer_count_unsafe();
226	return __retval;
227}
228
229/*
230 * Like schedule_hrtimeout_range(), but should not block the freezer.  Do not
231 * call this with locks held.
232 */
233static inline int freezable_schedule_hrtimeout_range(ktime_t *expires,
234		unsigned long delta, const enum hrtimer_mode mode)
235{
236	int __retval;
237	freezer_do_not_count();
238	__retval = schedule_hrtimeout_range(expires, delta, mode);
239	freezer_count();
240	return __retval;
241}
242
243/*
244 * Freezer-friendly wrappers around wait_event_interruptible(),
245 * wait_event_killable() and wait_event_interruptible_timeout(), originally
246 * defined in <linux/wait.h>
247 */
248
249/* DO NOT ADD ANY NEW CALLERS OF THIS FUNCTION */
250#define wait_event_freezekillable_unsafe(wq, condition)			\
251({									\
252	int __retval;							\
253	freezer_do_not_count();						\
254	__retval = wait_event_killable(wq, (condition));		\
255	freezer_count_unsafe();						\
256	__retval;							\
257})
258
259#else /* !CONFIG_FREEZER */
260static inline bool frozen(struct task_struct *p) { return false; }
261static inline bool freezing(struct task_struct *p) { return false; }
262static inline void __thaw_task(struct task_struct *t) {}
263
264static inline bool __refrigerator(bool check_kthr_stop) { return false; }
265static inline int freeze_processes(void) { return -ENOSYS; }
266static inline int freeze_kernel_threads(void) { return -ENOSYS; }
267static inline void thaw_processes(void) {}
268static inline void thaw_kernel_threads(void) {}
269
270static inline bool try_to_freeze_nowarn(void) { return false; }
271static inline bool try_to_freeze(void) { return false; }
272
273static inline void freezer_do_not_count(void) {}
274static inline void freezer_count(void) {}
275static inline int freezer_should_skip(struct task_struct *p) { return 0; }
276static inline void set_freezable(void) {}
277
278#define freezable_schedule()  schedule()
279
280#define freezable_schedule_unsafe()  schedule()
281
282#define freezable_schedule_timeout(timeout)  schedule_timeout(timeout)
283
284#define freezable_schedule_timeout_interruptible(timeout)		\
285	schedule_timeout_interruptible(timeout)
286
287#define freezable_schedule_timeout_killable(timeout)			\
288	schedule_timeout_killable(timeout)
289
290#define freezable_schedule_timeout_killable_unsafe(timeout)		\
291	schedule_timeout_killable(timeout)
292
293#define freezable_schedule_hrtimeout_range(expires, delta, mode)	\
294	schedule_hrtimeout_range(expires, delta, mode)
295
296#define wait_event_freezekillable_unsafe(wq, condition)			\
297		wait_event_killable(wq, condition)
298
299#endif /* !CONFIG_FREEZER */
300
301#endif	/* FREEZER_H_INCLUDED */
302