13d0407baSopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
23d0407baSopenharmony_ci/* Freezer declarations */
33d0407baSopenharmony_ci
43d0407baSopenharmony_ci#ifndef FREEZER_H_INCLUDED
53d0407baSopenharmony_ci#define FREEZER_H_INCLUDED
63d0407baSopenharmony_ci
73d0407baSopenharmony_ci#include <linux/debug_locks.h>
83d0407baSopenharmony_ci#include <linux/sched.h>
93d0407baSopenharmony_ci#include <linux/wait.h>
103d0407baSopenharmony_ci#include <linux/atomic.h>
113d0407baSopenharmony_ci
123d0407baSopenharmony_ci#ifdef CONFIG_FREEZER
133d0407baSopenharmony_ciextern atomic_t system_freezing_cnt; /* nr of freezing conds in effect */
143d0407baSopenharmony_ciextern bool pm_freezing;             /* PM freezing in effect */
153d0407baSopenharmony_ciextern bool pm_nosig_freezing;       /* PM nosig freezing in effect */
163d0407baSopenharmony_ci
173d0407baSopenharmony_ci/*
183d0407baSopenharmony_ci * Timeout for stopping processes
193d0407baSopenharmony_ci */
203d0407baSopenharmony_ciextern unsigned int freeze_timeout_msecs;
213d0407baSopenharmony_ci
223d0407baSopenharmony_ci/*
233d0407baSopenharmony_ci * Check if a process has been frozen
243d0407baSopenharmony_ci */
253d0407baSopenharmony_cistatic inline bool frozen(struct task_struct *p)
263d0407baSopenharmony_ci{
273d0407baSopenharmony_ci    return p->flags & PF_FROZEN;
283d0407baSopenharmony_ci}
293d0407baSopenharmony_ci
303d0407baSopenharmony_cistatic inline bool frozen_or_skipped(struct task_struct *p)
313d0407baSopenharmony_ci{
323d0407baSopenharmony_ci    return p->flags & (PF_FROZEN | PF_FREEZER_SKIP);
333d0407baSopenharmony_ci}
343d0407baSopenharmony_ci
353d0407baSopenharmony_ciextern bool freezing_slow_path(struct task_struct *p);
363d0407baSopenharmony_ci
373d0407baSopenharmony_ci/*
383d0407baSopenharmony_ci * Check if there is a request to freeze a process
393d0407baSopenharmony_ci */
403d0407baSopenharmony_cistatic inline bool freezing(struct task_struct *p)
413d0407baSopenharmony_ci{
423d0407baSopenharmony_ci    if (likely(!atomic_read(&system_freezing_cnt))) {
433d0407baSopenharmony_ci        return false;
443d0407baSopenharmony_ci    }
453d0407baSopenharmony_ci    return freezing_slow_path(p);
463d0407baSopenharmony_ci}
473d0407baSopenharmony_ci
483d0407baSopenharmony_ci/* Takes and releases task alloc lock using task_lock() */
493d0407baSopenharmony_ciextern void __thaw_task(struct task_struct *t);
503d0407baSopenharmony_ci
513d0407baSopenharmony_ciextern bool __refrigerator(bool check_kthr_stop);
523d0407baSopenharmony_ciextern int freeze_processes(void);
533d0407baSopenharmony_ciextern int freeze_kernel_threads(void);
543d0407baSopenharmony_ciextern void thaw_processes(void);
553d0407baSopenharmony_ciextern void thaw_kernel_threads(void);
563d0407baSopenharmony_ci
573d0407baSopenharmony_ci/*
583d0407baSopenharmony_ci * DO NOT ADD ANY NEW CALLERS OF THIS FUNCTION
593d0407baSopenharmony_ci * If try_to_freeze causes a lockdep warning it means the caller may deadlock
603d0407baSopenharmony_ci */
613d0407baSopenharmony_cistatic inline bool try_to_freeze_unsafe(void)
623d0407baSopenharmony_ci{
633d0407baSopenharmony_ci    might_sleep();
643d0407baSopenharmony_ci    if (likely(!freezing(current))) {
653d0407baSopenharmony_ci        return false;
663d0407baSopenharmony_ci    }
673d0407baSopenharmony_ci    return __refrigerator(false);
683d0407baSopenharmony_ci}
693d0407baSopenharmony_ci
703d0407baSopenharmony_cistatic inline bool try_to_freeze(void)
713d0407baSopenharmony_ci{
723d0407baSopenharmony_ci    if (!(current->flags & PF_NOFREEZE)) {
733d0407baSopenharmony_ci        debug_check_no_locks_held();
743d0407baSopenharmony_ci    }
753d0407baSopenharmony_ci    return try_to_freeze_unsafe();
763d0407baSopenharmony_ci}
773d0407baSopenharmony_ci
783d0407baSopenharmony_ciextern bool freeze_task(struct task_struct *p);
793d0407baSopenharmony_ciextern bool set_freezable(void);
803d0407baSopenharmony_ci
813d0407baSopenharmony_ci#ifdef CONFIG_CGROUP_FREEZER
823d0407baSopenharmony_ciextern bool cgroup_freezing(struct task_struct *task);
833d0407baSopenharmony_ci#else  /* !CONFIG_CGROUP_FREEZER */
843d0407baSopenharmony_cistatic inline bool cgroup_freezing(struct task_struct *task)
853d0407baSopenharmony_ci{
863d0407baSopenharmony_ci    return false;
873d0407baSopenharmony_ci}
883d0407baSopenharmony_ci#endif /* !CONFIG_CGROUP_FREEZER */
893d0407baSopenharmony_ci
903d0407baSopenharmony_ci/*
913d0407baSopenharmony_ci * The PF_FREEZER_SKIP flag should be set by a vfork parent right before it
923d0407baSopenharmony_ci * calls wait_for_completion(&vfork) and reset right after it returns from this
933d0407baSopenharmony_ci * function.  Next, the parent should call try_to_freeze() to freeze itself
943d0407baSopenharmony_ci * appropriately in case the child has exited before the freezing of tasks is
953d0407baSopenharmony_ci * complete.  However, we don't want kernel threads to be frozen in unexpected
963d0407baSopenharmony_ci * places, so we allow them to block freeze_processes() instead or to set
973d0407baSopenharmony_ci * PF_NOFREEZE if needed. Fortunately, in the ____call_usermodehelper() case the
983d0407baSopenharmony_ci * parent won't really block freeze_processes(), since ____call_usermodehelper()
993d0407baSopenharmony_ci * (the child) does a little before exec/exit and it can't be frozen before
1003d0407baSopenharmony_ci * waking up the parent.
1013d0407baSopenharmony_ci */
1023d0407baSopenharmony_ci
1033d0407baSopenharmony_ci/**
1043d0407baSopenharmony_ci * freezer_do_not_count - tell freezer to ignore %current
1053d0407baSopenharmony_ci *
1063d0407baSopenharmony_ci * Tell freezers to ignore the current task when determining whether the
1073d0407baSopenharmony_ci * target frozen state is reached.  IOW, the current task will be
1083d0407baSopenharmony_ci * considered frozen enough by freezers.
1093d0407baSopenharmony_ci *
1103d0407baSopenharmony_ci * The caller shouldn't do anything which isn't allowed for a frozen task
1113d0407baSopenharmony_ci * until freezer_cont() is called.  Usually, freezer[_do_not]_count() pair
1123d0407baSopenharmony_ci * wrap a scheduling operation and nothing much else.
1133d0407baSopenharmony_ci */
1143d0407baSopenharmony_cistatic inline void freezer_do_not_count(void)
1153d0407baSopenharmony_ci{
1163d0407baSopenharmony_ci    current->flags |= PF_FREEZER_SKIP;
1173d0407baSopenharmony_ci}
1183d0407baSopenharmony_ci
1193d0407baSopenharmony_ci/**
1203d0407baSopenharmony_ci * freezer_count - tell freezer to stop ignoring %current
1213d0407baSopenharmony_ci *
1223d0407baSopenharmony_ci * Undo freezer_do_not_count().  It tells freezers that %current should be
1233d0407baSopenharmony_ci * considered again and tries to freeze if freezing condition is already in
1243d0407baSopenharmony_ci * effect.
1253d0407baSopenharmony_ci */
1263d0407baSopenharmony_cistatic inline void freezer_count(void)
1273d0407baSopenharmony_ci{
1283d0407baSopenharmony_ci    current->flags &= ~PF_FREEZER_SKIP;
1293d0407baSopenharmony_ci    /*
1303d0407baSopenharmony_ci     * If freezing is in progress, the following paired with smp_mb()
1313d0407baSopenharmony_ci     * in freezer_should_skip() ensures that either we see %true
1323d0407baSopenharmony_ci     * freezing() or freezer_should_skip() sees !PF_FREEZER_SKIP.
1333d0407baSopenharmony_ci     */
1343d0407baSopenharmony_ci    smp_mb();
1353d0407baSopenharmony_ci    try_to_freeze();
1363d0407baSopenharmony_ci}
1373d0407baSopenharmony_ci
1383d0407baSopenharmony_ci/* DO NOT ADD ANY NEW CALLERS OF THIS FUNCTION */
1393d0407baSopenharmony_cistatic inline void freezer_count_unsafe(void)
1403d0407baSopenharmony_ci{
1413d0407baSopenharmony_ci    current->flags &= ~PF_FREEZER_SKIP;
1423d0407baSopenharmony_ci    smp_mb();
1433d0407baSopenharmony_ci    try_to_freeze_unsafe();
1443d0407baSopenharmony_ci}
1453d0407baSopenharmony_ci
1463d0407baSopenharmony_ci/**
1473d0407baSopenharmony_ci * freezer_should_skip - whether to skip a task when determining frozen
1483d0407baSopenharmony_ci *             state is reached
1493d0407baSopenharmony_ci * @p: task in quesion
1503d0407baSopenharmony_ci *
1513d0407baSopenharmony_ci * This function is used by freezers after establishing %true freezing() to
1523d0407baSopenharmony_ci * test whether a task should be skipped when determining the target frozen
1533d0407baSopenharmony_ci * state is reached.  IOW, if this function returns %true, @p is considered
1543d0407baSopenharmony_ci * frozen enough.
1553d0407baSopenharmony_ci */
1563d0407baSopenharmony_cistatic inline bool freezer_should_skip(struct task_struct *p)
1573d0407baSopenharmony_ci{
1583d0407baSopenharmony_ci    /*
1593d0407baSopenharmony_ci     * The following smp_mb() paired with the one in freezer_count()
1603d0407baSopenharmony_ci     * ensures that either freezer_count() sees %true freezing() or we
1613d0407baSopenharmony_ci     * see cleared %PF_FREEZER_SKIP and return %false.  This makes it
1623d0407baSopenharmony_ci     * impossible for a task to slip frozen state testing after
1633d0407baSopenharmony_ci     * clearing %PF_FREEZER_SKIP.
1643d0407baSopenharmony_ci     */
1653d0407baSopenharmony_ci    smp_mb();
1663d0407baSopenharmony_ci    return p->flags & PF_FREEZER_SKIP;
1673d0407baSopenharmony_ci}
1683d0407baSopenharmony_ci
1693d0407baSopenharmony_ci/*
1703d0407baSopenharmony_ci * These functions are intended to be used whenever you want allow a sleeping
1713d0407baSopenharmony_ci * task to be frozen. Note that neither return any clear indication of
1723d0407baSopenharmony_ci * whether a freeze event happened while in this function.
1733d0407baSopenharmony_ci */
1743d0407baSopenharmony_ci
1753d0407baSopenharmony_ci/* Like schedule(), but should not block the freezer. */
1763d0407baSopenharmony_cistatic inline void freezable_schedule(void)
1773d0407baSopenharmony_ci{
1783d0407baSopenharmony_ci    freezer_do_not_count();
1793d0407baSopenharmony_ci    schedule();
1803d0407baSopenharmony_ci    freezer_count();
1813d0407baSopenharmony_ci}
1823d0407baSopenharmony_ci
1833d0407baSopenharmony_ci/* DO NOT ADD ANY NEW CALLERS OF THIS FUNCTION */
1843d0407baSopenharmony_cistatic inline void freezable_schedule_unsafe(void)
1853d0407baSopenharmony_ci{
1863d0407baSopenharmony_ci    freezer_do_not_count();
1873d0407baSopenharmony_ci    schedule();
1883d0407baSopenharmony_ci    freezer_count_unsafe();
1893d0407baSopenharmony_ci}
1903d0407baSopenharmony_ci
1913d0407baSopenharmony_ci/*
1923d0407baSopenharmony_ci * Like schedule_timeout(), but should not block the freezer.  Do not
1933d0407baSopenharmony_ci * call this with locks held.
1943d0407baSopenharmony_ci */
1953d0407baSopenharmony_cistatic inline long freezable_schedule_timeout(long timeout)
1963d0407baSopenharmony_ci{
1973d0407baSopenharmony_ci    long __retval;
1983d0407baSopenharmony_ci    freezer_do_not_count();
1993d0407baSopenharmony_ci    __retval = schedule_timeout(timeout);
2003d0407baSopenharmony_ci    freezer_count();
2013d0407baSopenharmony_ci    return __retval;
2023d0407baSopenharmony_ci}
2033d0407baSopenharmony_ci
2043d0407baSopenharmony_ci/*
2053d0407baSopenharmony_ci * Like schedule_timeout_interruptible(), but should not block the freezer.  Do not
2063d0407baSopenharmony_ci * call this with locks held.
2073d0407baSopenharmony_ci */
2083d0407baSopenharmony_cistatic inline long freezable_schedule_timeout_interruptible(long timeout)
2093d0407baSopenharmony_ci{
2103d0407baSopenharmony_ci    long __retval;
2113d0407baSopenharmony_ci    freezer_do_not_count();
2123d0407baSopenharmony_ci    __retval = schedule_timeout_interruptible(timeout);
2133d0407baSopenharmony_ci    freezer_count();
2143d0407baSopenharmony_ci    return __retval;
2153d0407baSopenharmony_ci}
2163d0407baSopenharmony_ci
2173d0407baSopenharmony_ci/* DO NOT ADD ANY NEW CALLERS OF THIS FUNCTION */
2183d0407baSopenharmony_cistatic inline long freezable_schedule_timeout_interruptible_unsafe(long timeout)
2193d0407baSopenharmony_ci{
2203d0407baSopenharmony_ci    long __retval;
2213d0407baSopenharmony_ci
2223d0407baSopenharmony_ci    freezer_do_not_count();
2233d0407baSopenharmony_ci    __retval = schedule_timeout_interruptible(timeout);
2243d0407baSopenharmony_ci    freezer_count_unsafe();
2253d0407baSopenharmony_ci    return __retval;
2263d0407baSopenharmony_ci}
2273d0407baSopenharmony_ci
2283d0407baSopenharmony_ci/* Like schedule_timeout_killable(), but should not block the freezer. */
2293d0407baSopenharmony_cistatic inline long freezable_schedule_timeout_killable(long timeout)
2303d0407baSopenharmony_ci{
2313d0407baSopenharmony_ci    long __retval;
2323d0407baSopenharmony_ci    freezer_do_not_count();
2333d0407baSopenharmony_ci    __retval = schedule_timeout_killable(timeout);
2343d0407baSopenharmony_ci    freezer_count();
2353d0407baSopenharmony_ci    return __retval;
2363d0407baSopenharmony_ci}
2373d0407baSopenharmony_ci
2383d0407baSopenharmony_ci/* DO NOT ADD ANY NEW CALLERS OF THIS FUNCTION */
2393d0407baSopenharmony_cistatic inline long freezable_schedule_timeout_killable_unsafe(long timeout)
2403d0407baSopenharmony_ci{
2413d0407baSopenharmony_ci    long __retval;
2423d0407baSopenharmony_ci    freezer_do_not_count();
2433d0407baSopenharmony_ci    __retval = schedule_timeout_killable(timeout);
2443d0407baSopenharmony_ci    freezer_count_unsafe();
2453d0407baSopenharmony_ci    return __retval;
2463d0407baSopenharmony_ci}
2473d0407baSopenharmony_ci
2483d0407baSopenharmony_ci/*
2493d0407baSopenharmony_ci * Like schedule_hrtimeout_range(), but should not block the freezer.  Do not
2503d0407baSopenharmony_ci * call this with locks held.
2513d0407baSopenharmony_ci */
2523d0407baSopenharmony_cistatic inline int freezable_schedule_hrtimeout_range(ktime_t *expires, u64 delta, const enum hrtimer_mode mode)
2533d0407baSopenharmony_ci{
2543d0407baSopenharmony_ci    int __retval;
2553d0407baSopenharmony_ci    freezer_do_not_count();
2563d0407baSopenharmony_ci    __retval = schedule_hrtimeout_range(expires, delta, mode);
2573d0407baSopenharmony_ci    freezer_count();
2583d0407baSopenharmony_ci    return __retval;
2593d0407baSopenharmony_ci}
2603d0407baSopenharmony_ci
2613d0407baSopenharmony_ci/*
2623d0407baSopenharmony_ci * Freezer-friendly wrappers around wait_event_interruptible(),
2633d0407baSopenharmony_ci * wait_event_killable() and wait_event_interruptible_timeout(), originally
2643d0407baSopenharmony_ci * defined in <linux/wait.h>
2653d0407baSopenharmony_ci */
2663d0407baSopenharmony_ci
2673d0407baSopenharmony_ci/* DO NOT ADD ANY NEW CALLERS OF THIS FUNCTION */
2683d0407baSopenharmony_ci#define wait_event_freezekillable_unsafe(wq, condition)                                                                \
2693d0407baSopenharmony_ci    ( {                                                                                                                \
2703d0407baSopenharmony_ci        int __retval;                                                                                                  \
2713d0407baSopenharmony_ci        freezer_do_not_count();                                                                                        \
2723d0407baSopenharmony_ci        __retval = wait_event_killable(wq, (condition));                                                               \
2733d0407baSopenharmony_ci        freezer_count_unsafe();                                                                                        \
2743d0407baSopenharmony_ci        __retval;                                                                                                      \
2753d0407baSopenharmony_ci    })
2763d0407baSopenharmony_ci
2773d0407baSopenharmony_ci#else /* !CONFIG_FREEZER */
2783d0407baSopenharmony_cistatic inline bool frozen(struct task_struct *p)
2793d0407baSopenharmony_ci{
2803d0407baSopenharmony_ci    return false;
2813d0407baSopenharmony_ci}
2823d0407baSopenharmony_cistatic inline bool frozen_or_skipped(struct task_struct *p)
2833d0407baSopenharmony_ci{
2843d0407baSopenharmony_ci    return false;
2853d0407baSopenharmony_ci}
2863d0407baSopenharmony_cistatic inline bool freezing(struct task_struct *p)
2873d0407baSopenharmony_ci{
2883d0407baSopenharmony_ci    return false;
2893d0407baSopenharmony_ci}
2903d0407baSopenharmony_cistatic inline void __thaw_task(struct task_struct *t)
2913d0407baSopenharmony_ci{
2923d0407baSopenharmony_ci}
2933d0407baSopenharmony_ci
2943d0407baSopenharmony_cistatic inline bool __refrigerator(bool check_kthr_stop)
2953d0407baSopenharmony_ci{
2963d0407baSopenharmony_ci    return false;
2973d0407baSopenharmony_ci}
2983d0407baSopenharmony_cistatic inline int freeze_processes(void)
2993d0407baSopenharmony_ci{
3003d0407baSopenharmony_ci    return -ENOSYS;
3013d0407baSopenharmony_ci}
3023d0407baSopenharmony_cistatic inline int freeze_kernel_threads(void)
3033d0407baSopenharmony_ci{
3043d0407baSopenharmony_ci    return -ENOSYS;
3053d0407baSopenharmony_ci}
3063d0407baSopenharmony_cistatic inline void thaw_processes(void)
3073d0407baSopenharmony_ci{
3083d0407baSopenharmony_ci}
3093d0407baSopenharmony_cistatic inline void thaw_kernel_threads(void)
3103d0407baSopenharmony_ci{
3113d0407baSopenharmony_ci}
3123d0407baSopenharmony_ci
3133d0407baSopenharmony_cistatic inline bool try_to_freeze_nowarn(void)
3143d0407baSopenharmony_ci{
3153d0407baSopenharmony_ci    return false;
3163d0407baSopenharmony_ci}
3173d0407baSopenharmony_cistatic inline bool try_to_freeze(void)
3183d0407baSopenharmony_ci{
3193d0407baSopenharmony_ci    return false;
3203d0407baSopenharmony_ci}
3213d0407baSopenharmony_ci
3223d0407baSopenharmony_cistatic inline void freezer_do_not_count(void)
3233d0407baSopenharmony_ci{
3243d0407baSopenharmony_ci}
3253d0407baSopenharmony_cistatic inline void freezer_count(void)
3263d0407baSopenharmony_ci{
3273d0407baSopenharmony_ci}
3283d0407baSopenharmony_cistatic inline int freezer_should_skip(struct task_struct *p)
3293d0407baSopenharmony_ci{
3303d0407baSopenharmony_ci    return 0;
3313d0407baSopenharmony_ci}
3323d0407baSopenharmony_cistatic inline void set_freezable(void)
3333d0407baSopenharmony_ci{
3343d0407baSopenharmony_ci}
3353d0407baSopenharmony_ci
3363d0407baSopenharmony_ci#define freezable_schedule() schedule()
3373d0407baSopenharmony_ci
3383d0407baSopenharmony_ci#define freezable_schedule_unsafe() schedule()
3393d0407baSopenharmony_ci
3403d0407baSopenharmony_ci#define freezable_schedule_timeout(timeout) schedule_timeout(timeout)
3413d0407baSopenharmony_ci
3423d0407baSopenharmony_ci#define freezable_schedule_timeout_interruptible(timeout) schedule_timeout_interruptible(timeout)
3433d0407baSopenharmony_ci
3443d0407baSopenharmony_ci#define freezable_schedule_timeout_interruptible_unsafe(timeout) schedule_timeout_interruptible(timeout)
3453d0407baSopenharmony_ci
3463d0407baSopenharmony_ci#define freezable_schedule_timeout_killable(timeout) schedule_timeout_killable(timeout)
3473d0407baSopenharmony_ci
3483d0407baSopenharmony_ci#define freezable_schedule_timeout_killable_unsafe(timeout) schedule_timeout_killable(timeout)
3493d0407baSopenharmony_ci
3503d0407baSopenharmony_ci#define freezable_schedule_hrtimeout_range(expires, delta, mode) schedule_hrtimeout_range(expires, delta, mode)
3513d0407baSopenharmony_ci
3523d0407baSopenharmony_ci#define wait_event_freezekillable_unsafe(wq, condition) wait_event_killable(wq, condition)
3533d0407baSopenharmony_ci
3543d0407baSopenharmony_ci#endif /* !CONFIG_FREEZER */
3553d0407baSopenharmony_ci
3563d0407baSopenharmony_ci#endif /* FREEZER_H_INCLUDED */
357