diff options
-rw-r--r-- | include/linux/freezer.h | 48 | ||||
-rw-r--r-- | include/linux/sched.h | 1 | ||||
-rw-r--r-- | kernel/fork.c | 3 | ||||
-rw-r--r-- | kernel/power/process.c | 29 |
4 files changed, 59 insertions, 22 deletions
diff --git a/include/linux/freezer.h b/include/linux/freezer.h index db5423eae24d..c9435252e8e4 100644 --- a/include/linux/freezer.h +++ b/include/linux/freezer.h | |||
@@ -81,7 +81,49 @@ static inline int try_to_freeze(void) | |||
81 | return 0; | 81 | return 0; |
82 | } | 82 | } |
83 | 83 | ||
84 | extern void thaw_some_processes(int all); | 84 | /* |
85 | * The PF_FREEZER_SKIP flag should be set by a vfork parent right before it | ||
86 | * calls wait_for_completion(&vfork) and reset right after it returns from this | ||
87 | * function. Next, the parent should call try_to_freeze() to freeze itself | ||
88 | * appropriately in case the child has exited before the freezing of tasks is | ||
89 | * complete. However, we don't want kernel threads to be frozen in unexpected | ||
90 | * places, so we allow them to block freeze_processes() instead or to set | ||
91 | * PF_NOFREEZE if needed and PF_FREEZER_SKIP is only set for userland vfork | ||
92 | * parents. Fortunately, in the ____call_usermodehelper() case the parent won't | ||
93 | * really block freeze_processes(), since ____call_usermodehelper() (the child) | ||
94 | * does a little before exec/exit and it can't be frozen before waking up the | ||
95 | * parent. | ||
96 | */ | ||
97 | |||
98 | /* | ||
99 | * If the current task is a user space one, tell the freezer not to count it as | ||
100 | * freezable. | ||
101 | */ | ||
102 | static inline void freezer_do_not_count(void) | ||
103 | { | ||
104 | if (current->mm) | ||
105 | current->flags |= PF_FREEZER_SKIP; | ||
106 | } | ||
107 | |||
108 | /* | ||
109 | * If the current task is a user space one, tell the freezer to count it as | ||
110 | * freezable again and try to freeze it. | ||
111 | */ | ||
112 | static inline void freezer_count(void) | ||
113 | { | ||
114 | if (current->mm) { | ||
115 | current->flags &= ~PF_FREEZER_SKIP; | ||
116 | try_to_freeze(); | ||
117 | } | ||
118 | } | ||
119 | |||
120 | /* | ||
121 | * Check if the task should be counted as freezeable by the freezer | ||
122 | */ | ||
123 | static inline int freezer_should_skip(struct task_struct *p) | ||
124 | { | ||
125 | return !!(p->flags & PF_FREEZER_SKIP); | ||
126 | } | ||
85 | 127 | ||
86 | #else | 128 | #else |
87 | static inline int frozen(struct task_struct *p) { return 0; } | 129 | static inline int frozen(struct task_struct *p) { return 0; } |
@@ -96,5 +138,7 @@ static inline void thaw_processes(void) {} | |||
96 | 138 | ||
97 | static inline int try_to_freeze(void) { return 0; } | 139 | static inline int try_to_freeze(void) { return 0; } |
98 | 140 | ||
99 | 141 | static inline void freezer_do_not_count(void) {} | |
142 | static inline void freezer_count(void) {} | ||
143 | static inline int freezer_should_skip(struct task_struct *p) { return 0; } | ||
100 | #endif | 144 | #endif |
diff --git a/include/linux/sched.h b/include/linux/sched.h index a81897e2a244..870b75e348ab 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -1182,6 +1182,7 @@ static inline void put_task_struct(struct task_struct *t) | |||
1182 | #define PF_SPREAD_SLAB 0x02000000 /* Spread some slab caches over cpuset */ | 1182 | #define PF_SPREAD_SLAB 0x02000000 /* Spread some slab caches over cpuset */ |
1183 | #define PF_MEMPOLICY 0x10000000 /* Non-default NUMA mempolicy */ | 1183 | #define PF_MEMPOLICY 0x10000000 /* Non-default NUMA mempolicy */ |
1184 | #define PF_MUTEX_TESTER 0x20000000 /* Thread belongs to the rt mutex tester */ | 1184 | #define PF_MUTEX_TESTER 0x20000000 /* Thread belongs to the rt mutex tester */ |
1185 | #define PF_FREEZER_SKIP 0x40000000 /* Freezer should not count it as freezeable */ | ||
1185 | 1186 | ||
1186 | /* | 1187 | /* |
1187 | * Only the _current_ task can read/write to tsk->flags, but other | 1188 | * Only the _current_ task can read/write to tsk->flags, but other |
diff --git a/kernel/fork.c b/kernel/fork.c index 87069cfc18a1..73ad5cda1bcd 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -45,6 +45,7 @@ | |||
45 | #include <linux/acct.h> | 45 | #include <linux/acct.h> |
46 | #include <linux/tsacct_kern.h> | 46 | #include <linux/tsacct_kern.h> |
47 | #include <linux/cn_proc.h> | 47 | #include <linux/cn_proc.h> |
48 | #include <linux/freezer.h> | ||
48 | #include <linux/delayacct.h> | 49 | #include <linux/delayacct.h> |
49 | #include <linux/taskstats_kern.h> | 50 | #include <linux/taskstats_kern.h> |
50 | #include <linux/random.h> | 51 | #include <linux/random.h> |
@@ -1405,7 +1406,9 @@ long do_fork(unsigned long clone_flags, | |||
1405 | } | 1406 | } |
1406 | 1407 | ||
1407 | if (clone_flags & CLONE_VFORK) { | 1408 | if (clone_flags & CLONE_VFORK) { |
1409 | freezer_do_not_count(); | ||
1408 | wait_for_completion(&vfork); | 1410 | wait_for_completion(&vfork); |
1411 | freezer_count(); | ||
1409 | if (unlikely (current->ptrace & PT_TRACE_VFORK_DONE)) { | 1412 | if (unlikely (current->ptrace & PT_TRACE_VFORK_DONE)) { |
1410 | current->ptrace_message = nr; | 1413 | current->ptrace_message = nr; |
1411 | ptrace_notify ((PTRACE_EVENT_VFORK_DONE << 8) | SIGTRAP); | 1414 | ptrace_notify ((PTRACE_EVENT_VFORK_DONE << 8) | SIGTRAP); |
diff --git a/kernel/power/process.c b/kernel/power/process.c index 02e490e311eb..eefca8581fa0 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c | |||
@@ -120,22 +120,12 @@ static unsigned int try_to_freeze_tasks(int freeze_user_space) | |||
120 | cancel_freezing(p); | 120 | cancel_freezing(p); |
121 | continue; | 121 | continue; |
122 | } | 122 | } |
123 | if (is_user_space(p)) { | 123 | if (is_user_space(p) == !freeze_user_space) |
124 | if (!freeze_user_space) | 124 | continue; |
125 | continue; | 125 | |
126 | 126 | freeze_process(p); | |
127 | /* Freeze the task unless there is a vfork | 127 | if (!freezer_should_skip(p)) |
128 | * completion pending | 128 | todo++; |
129 | */ | ||
130 | if (!p->vfork_done) | ||
131 | freeze_process(p); | ||
132 | } else { | ||
133 | if (freeze_user_space) | ||
134 | continue; | ||
135 | |||
136 | freeze_process(p); | ||
137 | } | ||
138 | todo++; | ||
139 | } while_each_thread(g, p); | 129 | } while_each_thread(g, p); |
140 | read_unlock(&tasklist_lock); | 130 | read_unlock(&tasklist_lock); |
141 | yield(); /* Yield is okay here */ | 131 | yield(); /* Yield is okay here */ |
@@ -161,7 +151,8 @@ static unsigned int try_to_freeze_tasks(int freeze_user_space) | |||
161 | continue; | 151 | continue; |
162 | 152 | ||
163 | task_lock(p); | 153 | task_lock(p); |
164 | if (freezeable(p) && !frozen(p)) | 154 | if (freezeable(p) && !frozen(p) && |
155 | !freezer_should_skip(p)) | ||
165 | printk(KERN_ERR " %s\n", p->comm); | 156 | printk(KERN_ERR " %s\n", p->comm); |
166 | 157 | ||
167 | cancel_freezing(p); | 158 | cancel_freezing(p); |
@@ -210,9 +201,7 @@ static void thaw_tasks(int thaw_user_space) | |||
210 | if (is_user_space(p) == !thaw_user_space) | 201 | if (is_user_space(p) == !thaw_user_space) |
211 | continue; | 202 | continue; |
212 | 203 | ||
213 | if (!thaw_process(p)) | 204 | thaw_process(p); |
214 | printk(KERN_WARNING " Strange, %s not stopped\n", | ||
215 | p->comm ); | ||
216 | } while_each_thread(g, p); | 205 | } while_each_thread(g, p); |
217 | read_unlock(&tasklist_lock); | 206 | read_unlock(&tasklist_lock); |
218 | } | 207 | } |