diff options
-rw-r--r-- | include/linux/freezer.h | 33 | ||||
-rw-r--r-- | kernel/cgroup_freezer.c | 10 | ||||
-rw-r--r-- | kernel/fork.c | 1 | ||||
-rw-r--r-- | kernel/freezer.c | 62 | ||||
-rw-r--r-- | kernel/power/process.c | 15 |
5 files changed, 72 insertions, 49 deletions
diff --git a/include/linux/freezer.h b/include/linux/freezer.h index b2b4abc5a739..8e29f2b7ce11 100644 --- a/include/linux/freezer.h +++ b/include/linux/freezer.h | |||
@@ -5,8 +5,13 @@ | |||
5 | 5 | ||
6 | #include <linux/sched.h> | 6 | #include <linux/sched.h> |
7 | #include <linux/wait.h> | 7 | #include <linux/wait.h> |
8 | #include <linux/atomic.h> | ||
8 | 9 | ||
9 | #ifdef CONFIG_FREEZER | 10 | #ifdef CONFIG_FREEZER |
11 | extern atomic_t system_freezing_cnt; /* nr of freezing conds in effect */ | ||
12 | extern bool pm_freezing; /* PM freezing in effect */ | ||
13 | extern bool pm_nosig_freezing; /* PM nosig freezing in effect */ | ||
14 | |||
10 | /* | 15 | /* |
11 | * Check if a process has been frozen | 16 | * Check if a process has been frozen |
12 | */ | 17 | */ |
@@ -15,28 +20,16 @@ static inline int frozen(struct task_struct *p) | |||
15 | return p->flags & PF_FROZEN; | 20 | return p->flags & PF_FROZEN; |
16 | } | 21 | } |
17 | 22 | ||
18 | /* | 23 | extern bool freezing_slow_path(struct task_struct *p); |
19 | * Check if there is a request to freeze a process | ||
20 | */ | ||
21 | static inline int freezing(struct task_struct *p) | ||
22 | { | ||
23 | return test_tsk_thread_flag(p, TIF_FREEZE); | ||
24 | } | ||
25 | 24 | ||
26 | /* | 25 | /* |
27 | * Request that a process be frozen | 26 | * Check if there is a request to freeze a process |
28 | */ | ||
29 | static inline void set_freeze_flag(struct task_struct *p) | ||
30 | { | ||
31 | set_tsk_thread_flag(p, TIF_FREEZE); | ||
32 | } | ||
33 | |||
34 | /* | ||
35 | * Sometimes we may need to cancel the previous 'freeze' request | ||
36 | */ | 27 | */ |
37 | static inline void clear_freeze_flag(struct task_struct *p) | 28 | static inline bool freezing(struct task_struct *p) |
38 | { | 29 | { |
39 | clear_tsk_thread_flag(p, TIF_FREEZE); | 30 | if (likely(!atomic_read(&system_freezing_cnt))) |
31 | return false; | ||
32 | return freezing_slow_path(p); | ||
40 | } | 33 | } |
41 | 34 | ||
42 | static inline bool should_send_signal(struct task_struct *p) | 35 | static inline bool should_send_signal(struct task_struct *p) |
@@ -174,9 +167,7 @@ static inline void set_freezable_with_signal(void) | |||
174 | }) | 167 | }) |
175 | #else /* !CONFIG_FREEZER */ | 168 | #else /* !CONFIG_FREEZER */ |
176 | static inline int frozen(struct task_struct *p) { return 0; } | 169 | static inline int frozen(struct task_struct *p) { return 0; } |
177 | static inline int freezing(struct task_struct *p) { return 0; } | 170 | static inline bool freezing(struct task_struct *p) { return false; } |
178 | static inline void set_freeze_flag(struct task_struct *p) {} | ||
179 | static inline void clear_freeze_flag(struct task_struct *p) {} | ||
180 | 171 | ||
181 | static inline bool __refrigerator(bool check_kthr_stop) { return false; } | 172 | static inline bool __refrigerator(bool check_kthr_stop) { return false; } |
182 | static inline int freeze_processes(void) { return -ENOSYS; } | 173 | static inline int freeze_processes(void) { return -ENOSYS; } |
diff --git a/kernel/cgroup_freezer.c b/kernel/cgroup_freezer.c index e6a1b8d1b8bc..2327ad11725f 100644 --- a/kernel/cgroup_freezer.c +++ b/kernel/cgroup_freezer.c | |||
@@ -145,7 +145,11 @@ static struct cgroup_subsys_state *freezer_create(struct cgroup_subsys *ss, | |||
145 | static void freezer_destroy(struct cgroup_subsys *ss, | 145 | static void freezer_destroy(struct cgroup_subsys *ss, |
146 | struct cgroup *cgroup) | 146 | struct cgroup *cgroup) |
147 | { | 147 | { |
148 | kfree(cgroup_freezer(cgroup)); | 148 | struct freezer *freezer = cgroup_freezer(cgroup); |
149 | |||
150 | if (freezer->state != CGROUP_THAWED) | ||
151 | atomic_dec(&system_freezing_cnt); | ||
152 | kfree(freezer); | ||
149 | } | 153 | } |
150 | 154 | ||
151 | /* | 155 | /* |
@@ -307,10 +311,14 @@ static int freezer_change_state(struct cgroup *cgroup, | |||
307 | 311 | ||
308 | switch (goal_state) { | 312 | switch (goal_state) { |
309 | case CGROUP_THAWED: | 313 | case CGROUP_THAWED: |
314 | if (freezer->state != CGROUP_THAWED) | ||
315 | atomic_dec(&system_freezing_cnt); | ||
310 | freezer->state = CGROUP_THAWED; | 316 | freezer->state = CGROUP_THAWED; |
311 | unfreeze_cgroup(cgroup, freezer); | 317 | unfreeze_cgroup(cgroup, freezer); |
312 | break; | 318 | break; |
313 | case CGROUP_FROZEN: | 319 | case CGROUP_FROZEN: |
320 | if (freezer->state == CGROUP_THAWED) | ||
321 | atomic_inc(&system_freezing_cnt); | ||
314 | freezer->state = CGROUP_FREEZING; | 322 | freezer->state = CGROUP_FREEZING; |
315 | retval = try_to_freeze_cgroup(cgroup, freezer); | 323 | retval = try_to_freeze_cgroup(cgroup, freezer); |
316 | break; | 324 | break; |
diff --git a/kernel/fork.c b/kernel/fork.c index ba0d17261329..d53316e88d9d 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -997,7 +997,6 @@ static void copy_flags(unsigned long clone_flags, struct task_struct *p) | |||
997 | new_flags |= PF_FORKNOEXEC; | 997 | new_flags |= PF_FORKNOEXEC; |
998 | new_flags |= PF_STARTING; | 998 | new_flags |= PF_STARTING; |
999 | p->flags = new_flags; | 999 | p->flags = new_flags; |
1000 | clear_freeze_flag(p); | ||
1001 | } | 1000 | } |
1002 | 1001 | ||
1003 | SYSCALL_DEFINE1(set_tid_address, int __user *, tidptr) | 1002 | SYSCALL_DEFINE1(set_tid_address, int __user *, tidptr) |
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 */ | ||
15 | atomic_t system_freezing_cnt = ATOMIC_INIT(0); | ||
16 | EXPORT_SYMBOL(system_freezing_cnt); | ||
17 | |||
18 | /* indicate whether PM freezing is in effect, protected by pm_mutex */ | ||
19 | bool pm_freezing; | ||
20 | bool pm_nosig_freezing; | ||
21 | |||
14 | /* protects freezing and frozen transitions */ | 22 | /* protects freezing and frozen transitions */ |
15 | static DEFINE_SPINLOCK(freezer_lock); | 23 | static 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 | */ | ||
34 | bool 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 | } | ||
47 | EXPORT_SYMBOL(freezing_slow_path); | ||
48 | |||
17 | /* Refrigerator is place where frozen processes are stored :-). */ | 49 | /* Refrigerator is place where frozen processes are stored :-). */ |
18 | bool __refrigerator(bool check_kthr_stop) | 50 | bool __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); |
30 | repeat: | 62 | repeat: |
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) | |||
99 | bool freeze_task(struct task_struct *p, bool sig_only) | 125 | bool 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 | |
127 | out_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 | ||
132 | void __thaw_task(struct task_struct *p) | 151 | void __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 { |
diff --git a/kernel/power/process.c b/kernel/power/process.c index 9f6f5c755cfa..0beb51e1dec9 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c | |||
@@ -101,7 +101,7 @@ static int try_to_freeze_tasks(bool sig_only) | |||
101 | read_lock(&tasklist_lock); | 101 | read_lock(&tasklist_lock); |
102 | do_each_thread(g, p) { | 102 | do_each_thread(g, p) { |
103 | if (!wakeup && !freezer_should_skip(p) && | 103 | if (!wakeup && !freezer_should_skip(p) && |
104 | freezing(p) && !frozen(p)) | 104 | p != current && freezing(p) && !frozen(p)) |
105 | sched_show_task(p); | 105 | sched_show_task(p); |
106 | } while_each_thread(g, p); | 106 | } while_each_thread(g, p); |
107 | read_unlock(&tasklist_lock); | 107 | read_unlock(&tasklist_lock); |
@@ -122,7 +122,11 @@ int freeze_processes(void) | |||
122 | { | 122 | { |
123 | int error; | 123 | int error; |
124 | 124 | ||
125 | if (!pm_freezing) | ||
126 | atomic_inc(&system_freezing_cnt); | ||
127 | |||
125 | printk("Freezing user space processes ... "); | 128 | printk("Freezing user space processes ... "); |
129 | pm_freezing = true; | ||
126 | error = try_to_freeze_tasks(true); | 130 | error = try_to_freeze_tasks(true); |
127 | if (!error) { | 131 | if (!error) { |
128 | printk("done."); | 132 | printk("done."); |
@@ -146,6 +150,7 @@ int freeze_kernel_threads(void) | |||
146 | int error; | 150 | int error; |
147 | 151 | ||
148 | printk("Freezing remaining freezable tasks ... "); | 152 | printk("Freezing remaining freezable tasks ... "); |
153 | pm_nosig_freezing = true; | ||
149 | error = try_to_freeze_tasks(false); | 154 | error = try_to_freeze_tasks(false); |
150 | if (!error) | 155 | if (!error) |
151 | printk("done."); | 156 | printk("done."); |
@@ -162,6 +167,11 @@ void thaw_processes(void) | |||
162 | { | 167 | { |
163 | struct task_struct *g, *p; | 168 | struct task_struct *g, *p; |
164 | 169 | ||
170 | if (pm_freezing) | ||
171 | atomic_dec(&system_freezing_cnt); | ||
172 | pm_freezing = false; | ||
173 | pm_nosig_freezing = false; | ||
174 | |||
165 | oom_killer_enable(); | 175 | oom_killer_enable(); |
166 | 176 | ||
167 | printk("Restarting tasks ... "); | 177 | printk("Restarting tasks ... "); |
@@ -170,9 +180,6 @@ void thaw_processes(void) | |||
170 | 180 | ||
171 | read_lock(&tasklist_lock); | 181 | read_lock(&tasklist_lock); |
172 | do_each_thread(g, p) { | 182 | do_each_thread(g, p) { |
173 | if (cgroup_freezing(p)) | ||
174 | continue; | ||
175 | |||
176 | __thaw_task(p); | 183 | __thaw_task(p); |
177 | } while_each_thread(g, p); | 184 | } while_each_thread(g, p); |
178 | read_unlock(&tasklist_lock); | 185 | read_unlock(&tasklist_lock); |