aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/freezer.h48
-rw-r--r--include/linux/sched.h1
-rw-r--r--kernel/fork.c3
-rw-r--r--kernel/power/process.c29
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
84extern 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 */
102static 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 */
112static 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 */
123static inline int freezer_should_skip(struct task_struct *p)
124{
125 return !!(p->flags & PF_FREEZER_SKIP);
126}
85 127
86#else 128#else
87static inline int frozen(struct task_struct *p) { return 0; } 129static inline int frozen(struct task_struct *p) { return 0; }
@@ -96,5 +138,7 @@ static inline void thaw_processes(void) {}
96 138
97static inline int try_to_freeze(void) { return 0; } 139static inline int try_to_freeze(void) { return 0; }
98 140
99 141static inline void freezer_do_not_count(void) {}
142static inline void freezer_count(void) {}
143static 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}