aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/freezer.c
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2011-11-21 15:32:25 -0500
committerTejun Heo <tj@kernel.org>2011-11-21 15:32:25 -0500
commita3201227f803ad7fd43180c5195dbe5a2bf998aa (patch)
tree1845ba06346f8a8772fe1c90f8960bd1a430d05c /kernel/freezer.c
parent22b4e111fa01a1147aa562ceaf18a752a928ef4e (diff)
freezer: make freezing() test freeze conditions in effect instead of TIF_FREEZE
Using TIF_FREEZE for freezing worked when there was only single freezing condition (the PM one); however, now there is also the cgroup_freezer and single bit flag is getting clumsy. thaw_processes() is already testing whether cgroup freezing in in effect to avoid thawing tasks which were frozen by both PM and cgroup freezers. This is racy (nothing prevents race against cgroup freezing) and fragile. A much simpler way is to test actual freeze conditions from freezing() - ie. directly test whether PM or cgroup freezing is in effect. This patch adds variables to indicate whether and what type of freezing conditions are in effect and reimplements freezing() such that it directly tests whether any of the two freezing conditions is active and the task should freeze. On fast path, freezing() is still very cheap - it only tests system_freezing_cnt. This makes the clumsy dancing aroung TIF_FREEZE unnecessary and freeze/thaw operations more usual - updating state variables for the new state and nudging target tasks so that they notice the new state and comply. As long as the nudging happens after state update, it's race-free. * This allows use of freezing() in freeze_task(). Replace the open coded tests with freezing(). * p != current test is added to warning printing conditions in try_to_freeze_tasks() failure path. This is necessary as freezing() is now true for the task which initiated freezing too. -v2: Oleg pointed out that re-freezing FROZEN cgroup could increment system_freezing_cnt. Fixed. Signed-off-by: Tejun Heo <tj@kernel.org> Acked-by: Paul Menage <paul@paulmenage.org> (for the cgroup portions)
Diffstat (limited to 'kernel/freezer.c')
-rw-r--r--kernel/freezer.c62
1 files changed, 40 insertions, 22 deletions
diff --git a/kernel/freezer.c b/kernel/freezer.c
index 11e32d419dec..f53cd5aa5b2e 100644
--- a/kernel/freezer.c
+++ b/kernel/freezer.c
@@ -11,9 +11,41 @@
11#include <linux/freezer.h> 11#include <linux/freezer.h>
12#include <linux/kthread.h> 12#include <linux/kthread.h>
13 13
14/* total number of freezing conditions in effect */
15atomic_t system_freezing_cnt = ATOMIC_INIT(0);
16EXPORT_SYMBOL(system_freezing_cnt);
17
18/* indicate whether PM freezing is in effect, protected by pm_mutex */
19bool pm_freezing;
20bool pm_nosig_freezing;
21
14/* protects freezing and frozen transitions */ 22/* protects freezing and frozen transitions */
15static DEFINE_SPINLOCK(freezer_lock); 23static DEFINE_SPINLOCK(freezer_lock);
16 24
25/**
26 * freezing_slow_path - slow path for testing whether a task needs to be frozen
27 * @p: task to be tested
28 *
29 * This function is called by freezing() if system_freezing_cnt isn't zero
30 * and tests whether @p needs to enter and stay in frozen state. Can be
31 * called under any context. The freezers are responsible for ensuring the
32 * target tasks see the updated state.
33 */
34bool freezing_slow_path(struct task_struct *p)
35{
36 if (p->flags & PF_NOFREEZE)
37 return false;
38
39 if (pm_nosig_freezing || cgroup_freezing(p))
40 return true;
41
42 if (pm_freezing && !(p->flags & PF_FREEZER_NOSIG))
43 return true;
44
45 return false;
46}
47EXPORT_SYMBOL(freezing_slow_path);
48
17/* Refrigerator is place where frozen processes are stored :-). */ 49/* Refrigerator is place where frozen processes are stored :-). */
18bool __refrigerator(bool check_kthr_stop) 50bool __refrigerator(bool check_kthr_stop)
19{ 51{
@@ -23,17 +55,11 @@ bool __refrigerator(bool check_kthr_stop)
23 long save; 55 long save;
24 56
25 /* 57 /*
26 * Enter FROZEN. If NOFREEZE, schedule immediate thawing by 58 * No point in checking freezing() again - the caller already did.
27 * clearing freezing. 59 * Proceed to enter FROZEN.
28 */ 60 */
29 spin_lock_irq(&freezer_lock); 61 spin_lock_irq(&freezer_lock);
30repeat: 62repeat:
31 if (!freezing(current)) {
32 spin_unlock_irq(&freezer_lock);
33 return was_frozen;
34 }
35 if (current->flags & PF_NOFREEZE)
36 clear_freeze_flag(current);
37 current->flags |= PF_FROZEN; 63 current->flags |= PF_FROZEN;
38 spin_unlock_irq(&freezer_lock); 64 spin_unlock_irq(&freezer_lock);
39 65
@@ -99,18 +125,12 @@ static void fake_signal_wake_up(struct task_struct *p)
99bool freeze_task(struct task_struct *p, bool sig_only) 125bool freeze_task(struct task_struct *p, bool sig_only)
100{ 126{
101 unsigned long flags; 127 unsigned long flags;
102 bool ret = false;
103 128
104 spin_lock_irqsave(&freezer_lock, flags); 129 spin_lock_irqsave(&freezer_lock, flags);
105 130 if (!freezing(p) || frozen(p)) {
106 if ((p->flags & PF_NOFREEZE) || 131 spin_unlock_irqrestore(&freezer_lock, flags);
107 (sig_only && !should_send_signal(p))) 132 return false;
108 goto out_unlock; 133 }
109
110 if (frozen(p))
111 goto out_unlock;
112
113 set_freeze_flag(p);
114 134
115 if (should_send_signal(p)) { 135 if (should_send_signal(p)) {
116 fake_signal_wake_up(p); 136 fake_signal_wake_up(p);
@@ -123,10 +143,9 @@ bool freeze_task(struct task_struct *p, bool sig_only)
123 } else { 143 } else {
124 wake_up_state(p, TASK_INTERRUPTIBLE); 144 wake_up_state(p, TASK_INTERRUPTIBLE);
125 } 145 }
126 ret = true; 146
127out_unlock:
128 spin_unlock_irqrestore(&freezer_lock, flags); 147 spin_unlock_irqrestore(&freezer_lock, flags);
129 return ret; 148 return true;
130} 149}
131 150
132void __thaw_task(struct task_struct *p) 151void __thaw_task(struct task_struct *p)
@@ -143,7 +162,6 @@ void __thaw_task(struct task_struct *p)
143 * avoid leaving dangling TIF_SIGPENDING behind. 162 * avoid leaving dangling TIF_SIGPENDING behind.
144 */ 163 */
145 spin_lock_irqsave(&freezer_lock, flags); 164 spin_lock_irqsave(&freezer_lock, flags);
146 clear_freeze_flag(p);
147 if (frozen(p)) { 165 if (frozen(p)) {
148 wake_up_process(p); 166 wake_up_process(p);
149 } else { 167 } else {