freezer: rename thaw_process() to __thaw_task() and simplify the implementation
[firefly-linux-kernel-4.4.55.git] / kernel / freezer.c
1 /*
2  * kernel/freezer.c - Function to freeze a process
3  *
4  * Originally from kernel/power/process.c
5  */
6
7 #include <linux/interrupt.h>
8 #include <linux/suspend.h>
9 #include <linux/export.h>
10 #include <linux/syscalls.h>
11 #include <linux/freezer.h>
12 #include <linux/kthread.h>
13
14 /*
15  * freezing is complete, mark current process as frozen
16  */
17 static inline void frozen_process(void)
18 {
19         if (!unlikely(current->flags & PF_NOFREEZE)) {
20                 current->flags |= PF_FROZEN;
21                 smp_wmb();
22         }
23         clear_freeze_flag(current);
24 }
25
26 /* Refrigerator is place where frozen processes are stored :-). */
27 bool __refrigerator(bool check_kthr_stop)
28 {
29         /* Hmm, should we be allowed to suspend when there are realtime
30            processes around? */
31         bool was_frozen = false;
32         long save;
33
34         task_lock(current);
35         if (freezing(current)) {
36                 frozen_process();
37                 task_unlock(current);
38         } else {
39                 task_unlock(current);
40                 return was_frozen;
41         }
42         save = current->state;
43         pr_debug("%s entered refrigerator\n", current->comm);
44
45         spin_lock_irq(&current->sighand->siglock);
46         recalc_sigpending(); /* We sent fake signal, clean it up */
47         spin_unlock_irq(&current->sighand->siglock);
48
49         /* prevent accounting of that task to load */
50         current->flags |= PF_FREEZING;
51
52         for (;;) {
53                 set_current_state(TASK_UNINTERRUPTIBLE);
54                 if (!frozen(current) ||
55                     (check_kthr_stop && kthread_should_stop()))
56                         break;
57                 was_frozen = true;
58                 schedule();
59         }
60
61         /* Remove the accounting blocker */
62         current->flags &= ~PF_FREEZING;
63
64         pr_debug("%s left refrigerator\n", current->comm);
65
66         /*
67          * Restore saved task state before returning.  The mb'd version
68          * needs to be used; otherwise, it might silently break
69          * synchronization which depends on ordered task state change.
70          */
71         set_current_state(save);
72
73         return was_frozen;
74 }
75 EXPORT_SYMBOL(__refrigerator);
76
77 static void fake_signal_wake_up(struct task_struct *p)
78 {
79         unsigned long flags;
80
81         spin_lock_irqsave(&p->sighand->siglock, flags);
82         signal_wake_up(p, 0);
83         spin_unlock_irqrestore(&p->sighand->siglock, flags);
84 }
85
86 /**
87  *      freeze_task - send a freeze request to given task
88  *      @p: task to send the request to
89  *      @sig_only: if set, the request will only be sent if the task has the
90  *              PF_FREEZER_NOSIG flag unset
91  *      Return value: 'false', if @sig_only is set and the task has
92  *              PF_FREEZER_NOSIG set or the task is frozen, 'true', otherwise
93  *
94  *      The freeze request is sent by setting the tasks's TIF_FREEZE flag and
95  *      either sending a fake signal to it or waking it up, depending on whether
96  *      or not it has PF_FREEZER_NOSIG set.  If @sig_only is set and the task
97  *      has PF_FREEZER_NOSIG set (ie. it is a typical kernel thread), its
98  *      TIF_FREEZE flag will not be set.
99  */
100 bool freeze_task(struct task_struct *p, bool sig_only)
101 {
102         /*
103          * We first check if the task is freezing and next if it has already
104          * been frozen to avoid the race with frozen_process() which first marks
105          * the task as frozen and next clears its TIF_FREEZE.
106          */
107         if (!freezing(p)) {
108                 smp_rmb();
109                 if (frozen(p))
110                         return false;
111
112                 if (!sig_only || should_send_signal(p))
113                         set_freeze_flag(p);
114                 else
115                         return false;
116         }
117
118         if (should_send_signal(p)) {
119                 fake_signal_wake_up(p);
120                 /*
121                  * fake_signal_wake_up() goes through p's scheduler
122                  * lock and guarantees that TASK_STOPPED/TRACED ->
123                  * TASK_RUNNING transition can't race with task state
124                  * testing in try_to_freeze_tasks().
125                  */
126         } else if (sig_only) {
127                 return false;
128         } else {
129                 wake_up_state(p, TASK_INTERRUPTIBLE);
130         }
131
132         return true;
133 }
134
135 void cancel_freezing(struct task_struct *p)
136 {
137         unsigned long flags;
138
139         if (freezing(p)) {
140                 pr_debug("  clean up: %s\n", p->comm);
141                 clear_freeze_flag(p);
142                 spin_lock_irqsave(&p->sighand->siglock, flags);
143                 recalc_sigpending_and_wake(p);
144                 spin_unlock_irqrestore(&p->sighand->siglock, flags);
145         }
146 }
147
148 /*
149  * Wake up a frozen task
150  *
151  * task_lock() is needed to prevent the race with refrigerator() which may
152  * occur if the freezing of tasks fails.  Namely, without the lock, if the
153  * freezing of tasks failed, thaw_tasks() might have run before a task in
154  * refrigerator() could call frozen_process(), in which case the task would be
155  * frozen and no one would thaw it.
156  */
157 void __thaw_task(struct task_struct *p)
158 {
159         bool was_frozen;
160
161         task_lock(p);
162         was_frozen = frozen(p);
163         if (was_frozen)
164                 p->flags &= ~PF_FROZEN;
165         else
166                 clear_freeze_flag(p);
167         task_unlock(p);
168
169         if (was_frozen)
170                 wake_up_process(p);
171 }