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