1*457c8996SThomas 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 */ 16a3201227STejun Heo atomic_t system_freezing_cnt = ATOMIC_INIT(0); 17a3201227STejun Heo EXPORT_SYMBOL(system_freezing_cnt); 18a3201227STejun Heo 1955f2503cSPingfan Liu /* indicate whether PM freezing is in effect, protected by 2055f2503cSPingfan Liu * system_transition_mutex 2155f2503cSPingfan Liu */ 22a3201227STejun Heo bool pm_freezing; 23a3201227STejun Heo bool pm_nosig_freezing; 24a3201227STejun Heo 2585fbd722STejun Heo /* 2685fbd722STejun Heo * Temporary export for the deadlock workaround in ata_scsi_hotplug(). 2785fbd722STejun Heo * Remove once the hack becomes unnecessary. 2885fbd722STejun Heo */ 2985fbd722STejun Heo EXPORT_SYMBOL_GPL(pm_freezing); 3085fbd722STejun Heo 310c9af092STejun Heo /* protects freezing and frozen transitions */ 320c9af092STejun Heo static DEFINE_SPINLOCK(freezer_lock); 338174f150SMatt Helsley 34a3201227STejun Heo /** 35a3201227STejun Heo * freezing_slow_path - slow path for testing whether a task needs to be frozen 36a3201227STejun Heo * @p: task to be tested 37a3201227STejun Heo * 38a3201227STejun Heo * This function is called by freezing() if system_freezing_cnt isn't zero 39a3201227STejun Heo * and tests whether @p needs to enter and stay in frozen state. Can be 40a3201227STejun Heo * called under any context. The freezers are responsible for ensuring the 41a3201227STejun Heo * target tasks see the updated state. 42a3201227STejun Heo */ 43a3201227STejun Heo bool freezing_slow_path(struct task_struct *p) 44a3201227STejun Heo { 452b44c4dbSColin Cross if (p->flags & (PF_NOFREEZE | PF_SUSPEND_TASK)) 46a3201227STejun Heo return false; 47a3201227STejun Heo 48a34c80a7SMichal Hocko if (test_tsk_thread_flag(p, TIF_MEMDIE)) 4951fae6daSCong Wang return false; 5051fae6daSCong Wang 51a3201227STejun Heo if (pm_nosig_freezing || cgroup_freezing(p)) 52a3201227STejun Heo return true; 53a3201227STejun Heo 5434b087e4STejun Heo if (pm_freezing && !(p->flags & PF_KTHREAD)) 55a3201227STejun Heo return true; 56a3201227STejun Heo 57a3201227STejun Heo return false; 58a3201227STejun Heo } 59a3201227STejun Heo EXPORT_SYMBOL(freezing_slow_path); 60a3201227STejun Heo 618174f150SMatt Helsley /* Refrigerator is place where frozen processes are stored :-). */ 628a32c441STejun Heo bool __refrigerator(bool check_kthr_stop) 638174f150SMatt Helsley { 648174f150SMatt Helsley /* Hmm, should we be allowed to suspend when there are realtime 658174f150SMatt Helsley processes around? */ 66a0acae0eSTejun Heo bool was_frozen = false; 675ece3eaeSTejun Heo long save = current->state; 688174f150SMatt Helsley 698174f150SMatt Helsley pr_debug("%s entered refrigerator\n", current->comm); 708174f150SMatt Helsley 718174f150SMatt Helsley for (;;) { 728174f150SMatt Helsley set_current_state(TASK_UNINTERRUPTIBLE); 735ece3eaeSTejun Heo 745ece3eaeSTejun Heo spin_lock_irq(&freezer_lock); 755ece3eaeSTejun Heo current->flags |= PF_FROZEN; 766907483bSTejun Heo if (!freezing(current) || 778a32c441STejun Heo (check_kthr_stop && kthread_should_stop())) 785ece3eaeSTejun Heo current->flags &= ~PF_FROZEN; 795ece3eaeSTejun Heo spin_unlock_irq(&freezer_lock); 805ece3eaeSTejun Heo 815ece3eaeSTejun Heo if (!(current->flags & PF_FROZEN)) 828174f150SMatt Helsley break; 83a0acae0eSTejun Heo was_frozen = true; 848174f150SMatt Helsley schedule(); 858174f150SMatt Helsley } 866301cb95SThomas Gleixner 878174f150SMatt Helsley pr_debug("%s left refrigerator\n", current->comm); 8850fb4f7fSTejun Heo 8950fb4f7fSTejun Heo /* 9050fb4f7fSTejun Heo * Restore saved task state before returning. The mb'd version 9150fb4f7fSTejun Heo * needs to be used; otherwise, it might silently break 9250fb4f7fSTejun Heo * synchronization which depends on ordered task state change. 9350fb4f7fSTejun Heo */ 9450fb4f7fSTejun Heo set_current_state(save); 95a0acae0eSTejun Heo 96a0acae0eSTejun Heo return was_frozen; 978174f150SMatt Helsley } 98a0acae0eSTejun Heo EXPORT_SYMBOL(__refrigerator); 998174f150SMatt Helsley 1008174f150SMatt Helsley static void fake_signal_wake_up(struct task_struct *p) 1018174f150SMatt Helsley { 1028174f150SMatt Helsley unsigned long flags; 1038174f150SMatt Helsley 10437ad8acaSTejun Heo if (lock_task_sighand(p, &flags)) { 105d6cc7685STejun Heo signal_wake_up(p, 0); 10637ad8acaSTejun Heo unlock_task_sighand(p, &flags); 10737ad8acaSTejun Heo } 1088174f150SMatt Helsley } 1098174f150SMatt Helsley 1108174f150SMatt Helsley /** 1118174f150SMatt Helsley * freeze_task - send a freeze request to given task 1128174f150SMatt Helsley * @p: task to send the request to 1138174f150SMatt Helsley * 11437f08be1SMarcos Paulo de Souza * If @p is freezing, the freeze request is sent either by sending a fake 11537f08be1SMarcos Paulo de Souza * signal (if it's not a kernel thread) or waking it up (if it's a kernel 11637f08be1SMarcos Paulo de Souza * thread). 117839e3407STejun Heo * 118839e3407STejun Heo * RETURNS: 119839e3407STejun Heo * %false, if @p is not freezing or already frozen; %true, otherwise 1208174f150SMatt Helsley */ 121839e3407STejun Heo bool freeze_task(struct task_struct *p) 1228174f150SMatt Helsley { 1230c9af092STejun Heo unsigned long flags; 1248174f150SMatt Helsley 125613f5d13SColin Cross /* 126613f5d13SColin Cross * This check can race with freezer_do_not_count, but worst case that 127613f5d13SColin Cross * will result in an extra wakeup being sent to the task. It does not 128613f5d13SColin Cross * race with freezer_count(), the barriers in freezer_count() and 129613f5d13SColin Cross * freezer_should_skip() ensure that either freezer_count() sees 130613f5d13SColin Cross * freezing == true in try_to_freeze() and freezes, or 131613f5d13SColin Cross * freezer_should_skip() sees !PF_FREEZE_SKIP and freezes the task 132613f5d13SColin Cross * normally. 133613f5d13SColin Cross */ 134613f5d13SColin Cross if (freezer_should_skip(p)) 135613f5d13SColin Cross return false; 136613f5d13SColin Cross 1370c9af092STejun Heo spin_lock_irqsave(&freezer_lock, flags); 138a3201227STejun Heo if (!freezing(p) || frozen(p)) { 139a3201227STejun Heo spin_unlock_irqrestore(&freezer_lock, flags); 140a3201227STejun Heo return false; 141a3201227STejun Heo } 1428174f150SMatt Helsley 1435d8f72b5SOleg Nesterov if (!(p->flags & PF_KTHREAD)) 1448174f150SMatt Helsley fake_signal_wake_up(p); 1455d8f72b5SOleg Nesterov else 1468174f150SMatt Helsley wake_up_state(p, TASK_INTERRUPTIBLE); 147a3201227STejun Heo 1480c9af092STejun Heo spin_unlock_irqrestore(&freezer_lock, flags); 149a3201227STejun Heo return true; 1508174f150SMatt Helsley } 1518174f150SMatt Helsley 152a5be2d0dSTejun Heo void __thaw_task(struct task_struct *p) 153dc52ddc0SMatt Helsley { 1540c9af092STejun Heo unsigned long flags; 155a5be2d0dSTejun Heo 1560c9af092STejun Heo spin_lock_irqsave(&freezer_lock, flags); 15734b087e4STejun Heo if (frozen(p)) 1586907483bSTejun Heo wake_up_process(p); 1590c9af092STejun Heo spin_unlock_irqrestore(&freezer_lock, flags); 160dc52ddc0SMatt Helsley } 16196ee6d85STejun Heo 16296ee6d85STejun Heo /** 16334b087e4STejun Heo * set_freezable - make %current freezable 16496ee6d85STejun Heo * 16596ee6d85STejun Heo * Mark %current freezable and enter refrigerator if necessary. 16696ee6d85STejun Heo */ 16734b087e4STejun Heo bool set_freezable(void) 16896ee6d85STejun Heo { 16996ee6d85STejun Heo might_sleep(); 17096ee6d85STejun Heo 17196ee6d85STejun Heo /* 17296ee6d85STejun Heo * Modify flags while holding freezer_lock. This ensures the 17396ee6d85STejun Heo * freezer notices that we aren't frozen yet or the freezing 17496ee6d85STejun Heo * condition is visible to try_to_freeze() below. 17596ee6d85STejun Heo */ 17696ee6d85STejun Heo spin_lock_irq(&freezer_lock); 17796ee6d85STejun Heo current->flags &= ~PF_NOFREEZE; 17896ee6d85STejun Heo spin_unlock_irq(&freezer_lock); 17996ee6d85STejun Heo 18096ee6d85STejun Heo return try_to_freeze(); 18196ee6d85STejun Heo } 18234b087e4STejun Heo EXPORT_SYMBOL(set_freezable); 183