1457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 28174f150SMatt Helsley /* 38174f150SMatt Helsley * kernel/freezer.c - Function to freeze a process 48174f150SMatt Helsley * 58174f150SMatt Helsley * Originally from kernel/power/process.c 68174f150SMatt Helsley */ 78174f150SMatt Helsley 88174f150SMatt Helsley #include <linux/interrupt.h> 98174f150SMatt Helsley #include <linux/suspend.h> 109984de1aSPaul Gortmaker #include <linux/export.h> 118174f150SMatt Helsley #include <linux/syscalls.h> 128174f150SMatt Helsley #include <linux/freezer.h> 138a32c441STejun Heo #include <linux/kthread.h> 148174f150SMatt Helsley 15a3201227STejun Heo /* total number of freezing conditions in effect */ 16*f5d39b02SPeter Zijlstra DEFINE_STATIC_KEY_FALSE(freezer_active); 17*f5d39b02SPeter Zijlstra EXPORT_SYMBOL(freezer_active); 18a3201227STejun Heo 19*f5d39b02SPeter Zijlstra /* 20*f5d39b02SPeter Zijlstra * indicate whether PM freezing is in effect, protected by 2155f2503cSPingfan Liu * system_transition_mutex 2255f2503cSPingfan Liu */ 23a3201227STejun Heo bool pm_freezing; 24a3201227STejun Heo bool pm_nosig_freezing; 25a3201227STejun Heo 260c9af092STejun Heo /* protects freezing and frozen transitions */ 270c9af092STejun Heo static DEFINE_SPINLOCK(freezer_lock); 288174f150SMatt Helsley 29a3201227STejun Heo /** 30a3201227STejun Heo * freezing_slow_path - slow path for testing whether a task needs to be frozen 31a3201227STejun Heo * @p: task to be tested 32a3201227STejun Heo * 33*f5d39b02SPeter Zijlstra * This function is called by freezing() if freezer_active isn't zero 34a3201227STejun Heo * and tests whether @p needs to enter and stay in frozen state. Can be 35a3201227STejun Heo * called under any context. The freezers are responsible for ensuring the 36a3201227STejun Heo * target tasks see the updated state. 37a3201227STejun Heo */ 38a3201227STejun Heo bool freezing_slow_path(struct task_struct *p) 39a3201227STejun Heo { 402b44c4dbSColin Cross if (p->flags & (PF_NOFREEZE | PF_SUSPEND_TASK)) 41a3201227STejun Heo return false; 42a3201227STejun Heo 43a34c80a7SMichal Hocko if (test_tsk_thread_flag(p, TIF_MEMDIE)) 4451fae6daSCong Wang return false; 4551fae6daSCong Wang 46a3201227STejun Heo if (pm_nosig_freezing || cgroup_freezing(p)) 47a3201227STejun Heo return true; 48a3201227STejun Heo 4934b087e4STejun Heo if (pm_freezing && !(p->flags & PF_KTHREAD)) 50a3201227STejun Heo return true; 51a3201227STejun Heo 52a3201227STejun Heo return false; 53a3201227STejun Heo } 54a3201227STejun Heo EXPORT_SYMBOL(freezing_slow_path); 55a3201227STejun Heo 56*f5d39b02SPeter Zijlstra bool frozen(struct task_struct *p) 57*f5d39b02SPeter Zijlstra { 58*f5d39b02SPeter Zijlstra return READ_ONCE(p->__state) & TASK_FROZEN; 59*f5d39b02SPeter Zijlstra } 60*f5d39b02SPeter Zijlstra 618174f150SMatt Helsley /* Refrigerator is place where frozen processes are stored :-). */ 628a32c441STejun Heo bool __refrigerator(bool check_kthr_stop) 638174f150SMatt Helsley { 64*f5d39b02SPeter Zijlstra unsigned int state = get_current_state(); 65a0acae0eSTejun Heo bool was_frozen = false; 668174f150SMatt Helsley 678174f150SMatt Helsley pr_debug("%s entered refrigerator\n", current->comm); 688174f150SMatt Helsley 69*f5d39b02SPeter Zijlstra WARN_ON_ONCE(state && !(state & TASK_NORMAL)); 70*f5d39b02SPeter Zijlstra 718174f150SMatt Helsley for (;;) { 72*f5d39b02SPeter Zijlstra bool freeze; 73*f5d39b02SPeter Zijlstra 74*f5d39b02SPeter Zijlstra set_current_state(TASK_FROZEN); 755ece3eaeSTejun Heo 765ece3eaeSTejun Heo spin_lock_irq(&freezer_lock); 77*f5d39b02SPeter Zijlstra freeze = freezing(current) && !(check_kthr_stop && kthread_should_stop()); 785ece3eaeSTejun Heo spin_unlock_irq(&freezer_lock); 795ece3eaeSTejun Heo 80*f5d39b02SPeter Zijlstra if (!freeze) 818174f150SMatt Helsley break; 82*f5d39b02SPeter Zijlstra 83a0acae0eSTejun Heo was_frozen = true; 848174f150SMatt Helsley schedule(); 858174f150SMatt Helsley } 86*f5d39b02SPeter Zijlstra __set_current_state(TASK_RUNNING); 876301cb95SThomas Gleixner 888174f150SMatt Helsley pr_debug("%s left refrigerator\n", current->comm); 8950fb4f7fSTejun Heo 90a0acae0eSTejun Heo return was_frozen; 918174f150SMatt Helsley } 92a0acae0eSTejun Heo EXPORT_SYMBOL(__refrigerator); 938174f150SMatt Helsley 948174f150SMatt Helsley static void fake_signal_wake_up(struct task_struct *p) 958174f150SMatt Helsley { 968174f150SMatt Helsley unsigned long flags; 978174f150SMatt Helsley 9837ad8acaSTejun Heo if (lock_task_sighand(p, &flags)) { 99d6cc7685STejun Heo signal_wake_up(p, 0); 10037ad8acaSTejun Heo unlock_task_sighand(p, &flags); 10137ad8acaSTejun Heo } 1028174f150SMatt Helsley } 1038174f150SMatt Helsley 104*f5d39b02SPeter Zijlstra static int __set_task_frozen(struct task_struct *p, void *arg) 105*f5d39b02SPeter Zijlstra { 106*f5d39b02SPeter Zijlstra unsigned int state = READ_ONCE(p->__state); 107*f5d39b02SPeter Zijlstra 108*f5d39b02SPeter Zijlstra if (p->on_rq) 109*f5d39b02SPeter Zijlstra return 0; 110*f5d39b02SPeter Zijlstra 111*f5d39b02SPeter Zijlstra if (p != current && task_curr(p)) 112*f5d39b02SPeter Zijlstra return 0; 113*f5d39b02SPeter Zijlstra 114*f5d39b02SPeter Zijlstra if (!(state & (TASK_FREEZABLE | __TASK_STOPPED | __TASK_TRACED))) 115*f5d39b02SPeter Zijlstra return 0; 116*f5d39b02SPeter Zijlstra 117*f5d39b02SPeter Zijlstra /* 118*f5d39b02SPeter Zijlstra * Only TASK_NORMAL can be augmented with TASK_FREEZABLE, since they 119*f5d39b02SPeter Zijlstra * can suffer spurious wakeups. 120*f5d39b02SPeter Zijlstra */ 121*f5d39b02SPeter Zijlstra if (state & TASK_FREEZABLE) 122*f5d39b02SPeter Zijlstra WARN_ON_ONCE(!(state & TASK_NORMAL)); 123*f5d39b02SPeter Zijlstra 124*f5d39b02SPeter Zijlstra #ifdef CONFIG_LOCKDEP 125*f5d39b02SPeter Zijlstra /* 126*f5d39b02SPeter Zijlstra * It's dangerous to freeze with locks held; there be dragons there. 127*f5d39b02SPeter Zijlstra */ 128*f5d39b02SPeter Zijlstra if (!(state & __TASK_FREEZABLE_UNSAFE)) 129*f5d39b02SPeter Zijlstra WARN_ON_ONCE(debug_locks && p->lockdep_depth); 130*f5d39b02SPeter Zijlstra #endif 131*f5d39b02SPeter Zijlstra 132*f5d39b02SPeter Zijlstra WRITE_ONCE(p->__state, TASK_FROZEN); 133*f5d39b02SPeter Zijlstra return TASK_FROZEN; 134*f5d39b02SPeter Zijlstra } 135*f5d39b02SPeter Zijlstra 136*f5d39b02SPeter Zijlstra static bool __freeze_task(struct task_struct *p) 137*f5d39b02SPeter Zijlstra { 138*f5d39b02SPeter Zijlstra /* TASK_FREEZABLE|TASK_STOPPED|TASK_TRACED -> TASK_FROZEN */ 139*f5d39b02SPeter Zijlstra return task_call_func(p, __set_task_frozen, NULL); 140*f5d39b02SPeter Zijlstra } 141*f5d39b02SPeter Zijlstra 1428174f150SMatt Helsley /** 1438174f150SMatt Helsley * freeze_task - send a freeze request to given task 1448174f150SMatt Helsley * @p: task to send the request to 1458174f150SMatt Helsley * 14637f08be1SMarcos Paulo de Souza * If @p is freezing, the freeze request is sent either by sending a fake 14737f08be1SMarcos Paulo de Souza * signal (if it's not a kernel thread) or waking it up (if it's a kernel 14837f08be1SMarcos Paulo de Souza * thread). 149839e3407STejun Heo * 150839e3407STejun Heo * RETURNS: 151839e3407STejun Heo * %false, if @p is not freezing or already frozen; %true, otherwise 1528174f150SMatt Helsley */ 153839e3407STejun Heo bool freeze_task(struct task_struct *p) 1548174f150SMatt Helsley { 1550c9af092STejun Heo unsigned long flags; 1568174f150SMatt Helsley 1570c9af092STejun Heo spin_lock_irqsave(&freezer_lock, flags); 158*f5d39b02SPeter Zijlstra if (!freezing(p) || frozen(p) || __freeze_task(p)) { 159a3201227STejun Heo spin_unlock_irqrestore(&freezer_lock, flags); 160a3201227STejun Heo return false; 161a3201227STejun Heo } 1628174f150SMatt Helsley 163d3dc04cdSJens Axboe if (!(p->flags & PF_KTHREAD)) 1648174f150SMatt Helsley fake_signal_wake_up(p); 1655d8f72b5SOleg Nesterov else 166*f5d39b02SPeter Zijlstra wake_up_state(p, TASK_NORMAL); 167a3201227STejun Heo 1680c9af092STejun Heo spin_unlock_irqrestore(&freezer_lock, flags); 169a3201227STejun Heo return true; 1708174f150SMatt Helsley } 1718174f150SMatt Helsley 172*f5d39b02SPeter Zijlstra /* 173*f5d39b02SPeter Zijlstra * The special task states (TASK_STOPPED, TASK_TRACED) keep their canonical 174*f5d39b02SPeter Zijlstra * state in p->jobctl. If either of them got a wakeup that was missed because 175*f5d39b02SPeter Zijlstra * TASK_FROZEN, then their canonical state reflects that and the below will 176*f5d39b02SPeter Zijlstra * refuse to restore the special state and instead issue the wakeup. 177*f5d39b02SPeter Zijlstra */ 178*f5d39b02SPeter Zijlstra static int __set_task_special(struct task_struct *p, void *arg) 179*f5d39b02SPeter Zijlstra { 180*f5d39b02SPeter Zijlstra unsigned int state = 0; 181*f5d39b02SPeter Zijlstra 182*f5d39b02SPeter Zijlstra if (p->jobctl & JOBCTL_TRACED) 183*f5d39b02SPeter Zijlstra state = TASK_TRACED; 184*f5d39b02SPeter Zijlstra 185*f5d39b02SPeter Zijlstra else if (p->jobctl & JOBCTL_STOPPED) 186*f5d39b02SPeter Zijlstra state = TASK_STOPPED; 187*f5d39b02SPeter Zijlstra 188*f5d39b02SPeter Zijlstra if (state) 189*f5d39b02SPeter Zijlstra WRITE_ONCE(p->__state, state); 190*f5d39b02SPeter Zijlstra 191*f5d39b02SPeter Zijlstra return state; 192*f5d39b02SPeter Zijlstra } 193*f5d39b02SPeter Zijlstra 194a5be2d0dSTejun Heo void __thaw_task(struct task_struct *p) 195dc52ddc0SMatt Helsley { 196*f5d39b02SPeter Zijlstra unsigned long flags, flags2; 197a5be2d0dSTejun Heo 1980c9af092STejun Heo spin_lock_irqsave(&freezer_lock, flags); 199*f5d39b02SPeter Zijlstra if (WARN_ON_ONCE(freezing(p))) 200*f5d39b02SPeter Zijlstra goto unlock; 201*f5d39b02SPeter Zijlstra 202*f5d39b02SPeter Zijlstra if (lock_task_sighand(p, &flags2)) { 203*f5d39b02SPeter Zijlstra /* TASK_FROZEN -> TASK_{STOPPED,TRACED} */ 204*f5d39b02SPeter Zijlstra bool ret = task_call_func(p, __set_task_special, NULL); 205*f5d39b02SPeter Zijlstra unlock_task_sighand(p, &flags2); 206*f5d39b02SPeter Zijlstra if (ret) 207*f5d39b02SPeter Zijlstra goto unlock; 208*f5d39b02SPeter Zijlstra } 209*f5d39b02SPeter Zijlstra 210*f5d39b02SPeter Zijlstra wake_up_state(p, TASK_FROZEN); 211*f5d39b02SPeter Zijlstra unlock: 2120c9af092STejun Heo spin_unlock_irqrestore(&freezer_lock, flags); 213dc52ddc0SMatt Helsley } 21496ee6d85STejun Heo 21596ee6d85STejun Heo /** 21634b087e4STejun Heo * set_freezable - make %current freezable 21796ee6d85STejun Heo * 21896ee6d85STejun Heo * Mark %current freezable and enter refrigerator if necessary. 21996ee6d85STejun Heo */ 22034b087e4STejun Heo bool set_freezable(void) 22196ee6d85STejun Heo { 22296ee6d85STejun Heo might_sleep(); 22396ee6d85STejun Heo 22496ee6d85STejun Heo /* 22596ee6d85STejun Heo * Modify flags while holding freezer_lock. This ensures the 22696ee6d85STejun Heo * freezer notices that we aren't frozen yet or the freezing 22796ee6d85STejun Heo * condition is visible to try_to_freeze() below. 22896ee6d85STejun Heo */ 22996ee6d85STejun Heo spin_lock_irq(&freezer_lock); 23096ee6d85STejun Heo current->flags &= ~PF_NOFREEZE; 23196ee6d85STejun Heo spin_unlock_irq(&freezer_lock); 23296ee6d85STejun Heo 23396ee6d85STejun Heo return try_to_freeze(); 23496ee6d85STejun Heo } 23534b087e4STejun Heo EXPORT_SYMBOL(set_freezable); 236