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