18174f150SMatt Helsley /* 28174f150SMatt Helsley * kernel/freezer.c - Function to freeze a process 38174f150SMatt Helsley * 48174f150SMatt Helsley * Originally from kernel/power/process.c 58174f150SMatt Helsley */ 68174f150SMatt Helsley 78174f150SMatt Helsley #include <linux/interrupt.h> 88174f150SMatt Helsley #include <linux/suspend.h> 99984de1aSPaul Gortmaker #include <linux/export.h> 108174f150SMatt Helsley #include <linux/syscalls.h> 118174f150SMatt Helsley #include <linux/freezer.h> 128a32c441STejun Heo #include <linux/kthread.h> 138174f150SMatt Helsley 14*a3201227STejun Heo /* total number of freezing conditions in effect */ 15*a3201227STejun Heo atomic_t system_freezing_cnt = ATOMIC_INIT(0); 16*a3201227STejun Heo EXPORT_SYMBOL(system_freezing_cnt); 17*a3201227STejun Heo 18*a3201227STejun Heo /* indicate whether PM freezing is in effect, protected by pm_mutex */ 19*a3201227STejun Heo bool pm_freezing; 20*a3201227STejun Heo bool pm_nosig_freezing; 21*a3201227STejun Heo 220c9af092STejun Heo /* protects freezing and frozen transitions */ 230c9af092STejun Heo static DEFINE_SPINLOCK(freezer_lock); 248174f150SMatt Helsley 25*a3201227STejun Heo /** 26*a3201227STejun Heo * freezing_slow_path - slow path for testing whether a task needs to be frozen 27*a3201227STejun Heo * @p: task to be tested 28*a3201227STejun Heo * 29*a3201227STejun Heo * This function is called by freezing() if system_freezing_cnt isn't zero 30*a3201227STejun Heo * and tests whether @p needs to enter and stay in frozen state. Can be 31*a3201227STejun Heo * called under any context. The freezers are responsible for ensuring the 32*a3201227STejun Heo * target tasks see the updated state. 33*a3201227STejun Heo */ 34*a3201227STejun Heo bool freezing_slow_path(struct task_struct *p) 35*a3201227STejun Heo { 36*a3201227STejun Heo if (p->flags & PF_NOFREEZE) 37*a3201227STejun Heo return false; 38*a3201227STejun Heo 39*a3201227STejun Heo if (pm_nosig_freezing || cgroup_freezing(p)) 40*a3201227STejun Heo return true; 41*a3201227STejun Heo 42*a3201227STejun Heo if (pm_freezing && !(p->flags & PF_FREEZER_NOSIG)) 43*a3201227STejun Heo return true; 44*a3201227STejun Heo 45*a3201227STejun Heo return false; 46*a3201227STejun Heo } 47*a3201227STejun Heo EXPORT_SYMBOL(freezing_slow_path); 48*a3201227STejun Heo 498174f150SMatt Helsley /* Refrigerator is place where frozen processes are stored :-). */ 508a32c441STejun Heo bool __refrigerator(bool check_kthr_stop) 518174f150SMatt Helsley { 528174f150SMatt Helsley /* Hmm, should we be allowed to suspend when there are realtime 538174f150SMatt Helsley processes around? */ 54a0acae0eSTejun Heo bool was_frozen = false; 558174f150SMatt Helsley long save; 568174f150SMatt Helsley 576907483bSTejun Heo /* 58*a3201227STejun Heo * No point in checking freezing() again - the caller already did. 59*a3201227STejun Heo * Proceed to enter FROZEN. 606907483bSTejun Heo */ 610c9af092STejun Heo spin_lock_irq(&freezer_lock); 626907483bSTejun Heo repeat: 636907483bSTejun Heo current->flags |= PF_FROZEN; 640c9af092STejun Heo spin_unlock_irq(&freezer_lock); 650c9af092STejun Heo 668174f150SMatt Helsley save = current->state; 678174f150SMatt Helsley pr_debug("%s entered refrigerator\n", current->comm); 688174f150SMatt Helsley 698174f150SMatt Helsley spin_lock_irq(¤t->sighand->siglock); 708174f150SMatt Helsley recalc_sigpending(); /* We sent fake signal, clean it up */ 718174f150SMatt Helsley spin_unlock_irq(¤t->sighand->siglock); 728174f150SMatt Helsley 738174f150SMatt Helsley for (;;) { 748174f150SMatt Helsley set_current_state(TASK_UNINTERRUPTIBLE); 756907483bSTejun Heo if (!freezing(current) || 768a32c441STejun Heo (check_kthr_stop && kthread_should_stop())) 778174f150SMatt Helsley break; 78a0acae0eSTejun Heo was_frozen = true; 798174f150SMatt Helsley schedule(); 808174f150SMatt Helsley } 816301cb95SThomas Gleixner 826907483bSTejun Heo /* leave FROZEN */ 836907483bSTejun Heo spin_lock_irq(&freezer_lock); 846907483bSTejun Heo if (freezing(current)) 856907483bSTejun Heo goto repeat; 866907483bSTejun Heo current->flags &= ~PF_FROZEN; 876907483bSTejun Heo spin_unlock_irq(&freezer_lock); 886907483bSTejun Heo 898174f150SMatt Helsley pr_debug("%s left refrigerator\n", current->comm); 9050fb4f7fSTejun Heo 9150fb4f7fSTejun Heo /* 9250fb4f7fSTejun Heo * Restore saved task state before returning. The mb'd version 9350fb4f7fSTejun Heo * needs to be used; otherwise, it might silently break 9450fb4f7fSTejun Heo * synchronization which depends on ordered task state change. 9550fb4f7fSTejun Heo */ 9650fb4f7fSTejun Heo set_current_state(save); 97a0acae0eSTejun Heo 98a0acae0eSTejun Heo return was_frozen; 998174f150SMatt Helsley } 100a0acae0eSTejun Heo EXPORT_SYMBOL(__refrigerator); 1018174f150SMatt Helsley 1028174f150SMatt Helsley static void fake_signal_wake_up(struct task_struct *p) 1038174f150SMatt Helsley { 1048174f150SMatt Helsley unsigned long flags; 1058174f150SMatt Helsley 1068174f150SMatt Helsley spin_lock_irqsave(&p->sighand->siglock, flags); 107d6cc7685STejun Heo signal_wake_up(p, 0); 1088174f150SMatt Helsley spin_unlock_irqrestore(&p->sighand->siglock, flags); 1098174f150SMatt Helsley } 1108174f150SMatt Helsley 1118174f150SMatt Helsley /** 1128174f150SMatt Helsley * freeze_task - send a freeze request to given task 1138174f150SMatt Helsley * @p: task to send the request to 1148174f150SMatt Helsley * @sig_only: if set, the request will only be sent if the task has the 1158174f150SMatt Helsley * PF_FREEZER_NOSIG flag unset 1168174f150SMatt Helsley * Return value: 'false', if @sig_only is set and the task has 1178174f150SMatt Helsley * PF_FREEZER_NOSIG set or the task is frozen, 'true', otherwise 1188174f150SMatt Helsley * 1198174f150SMatt Helsley * The freeze request is sent by setting the tasks's TIF_FREEZE flag and 1208174f150SMatt Helsley * either sending a fake signal to it or waking it up, depending on whether 1218174f150SMatt Helsley * or not it has PF_FREEZER_NOSIG set. If @sig_only is set and the task 1228174f150SMatt Helsley * has PF_FREEZER_NOSIG set (ie. it is a typical kernel thread), its 1238174f150SMatt Helsley * TIF_FREEZE flag will not be set. 1248174f150SMatt Helsley */ 1258174f150SMatt Helsley bool freeze_task(struct task_struct *p, bool sig_only) 1268174f150SMatt Helsley { 1270c9af092STejun Heo unsigned long flags; 1288174f150SMatt Helsley 1290c9af092STejun Heo spin_lock_irqsave(&freezer_lock, flags); 130*a3201227STejun Heo if (!freezing(p) || frozen(p)) { 131*a3201227STejun Heo spin_unlock_irqrestore(&freezer_lock, flags); 132*a3201227STejun Heo return false; 133*a3201227STejun Heo } 1348174f150SMatt Helsley 1358174f150SMatt Helsley if (should_send_signal(p)) { 1368174f150SMatt Helsley fake_signal_wake_up(p); 1378cfe400cSTejun Heo /* 1388cfe400cSTejun Heo * fake_signal_wake_up() goes through p's scheduler 1398cfe400cSTejun Heo * lock and guarantees that TASK_STOPPED/TRACED -> 1408cfe400cSTejun Heo * TASK_RUNNING transition can't race with task state 1418cfe400cSTejun Heo * testing in try_to_freeze_tasks(). 1428cfe400cSTejun Heo */ 1438174f150SMatt Helsley } else { 1448174f150SMatt Helsley wake_up_state(p, TASK_INTERRUPTIBLE); 1458174f150SMatt Helsley } 146*a3201227STejun Heo 1470c9af092STejun Heo spin_unlock_irqrestore(&freezer_lock, flags); 148*a3201227STejun Heo return true; 1498174f150SMatt Helsley } 1508174f150SMatt Helsley 151a5be2d0dSTejun Heo void __thaw_task(struct task_struct *p) 152dc52ddc0SMatt Helsley { 1530c9af092STejun Heo unsigned long flags; 154a5be2d0dSTejun Heo 1556907483bSTejun Heo /* 1566907483bSTejun Heo * Clear freezing and kick @p if FROZEN. Clearing is guaranteed to 1576907483bSTejun Heo * be visible to @p as waking up implies wmb. Waking up inside 1586907483bSTejun Heo * freezer_lock also prevents wakeups from leaking outside 1596907483bSTejun Heo * refrigerator. 16003afed8bSTejun Heo * 16103afed8bSTejun Heo * If !FROZEN, @p hasn't reached refrigerator, recalc sigpending to 16203afed8bSTejun Heo * avoid leaving dangling TIF_SIGPENDING behind. 1636907483bSTejun Heo */ 1640c9af092STejun Heo spin_lock_irqsave(&freezer_lock, flags); 16503afed8bSTejun Heo if (frozen(p)) { 1666907483bSTejun Heo wake_up_process(p); 16703afed8bSTejun Heo } else { 16803afed8bSTejun Heo spin_lock(&p->sighand->siglock); 16903afed8bSTejun Heo recalc_sigpending_and_wake(p); 17003afed8bSTejun Heo spin_unlock(&p->sighand->siglock); 17103afed8bSTejun Heo } 1720c9af092STejun Heo spin_unlock_irqrestore(&freezer_lock, flags); 173dc52ddc0SMatt Helsley } 174