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