diff options
author | Rafael J. Wysocki <rjw@sisk.pl> | 2006-03-23 06:00:04 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-03-23 10:38:08 -0500 |
commit | 02aaeb9b952f30b1ad6284d5d45be02030f679db (patch) | |
tree | 6577fcc544d34fbc9951be5dc1089ac227440573 /kernel | |
parent | 6e1819d615f24ce0726a7d0bd3dd0152d7b21654 (diff) |
[PATCH] swsusp: freeze user space processes first
Allow swsusp to freeze processes successfully under heavy load by freezing
userspace processes before kernel threads.
[Thanks to Nigel Cunningham <nigel@suspend2.net> for suggesting the
way to go.]
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Acked-by: Pavel Machek <pavel@suse.cz>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/power/disk.c | 1 | ||||
-rw-r--r-- | kernel/power/process.c | 61 | ||||
-rw-r--r-- | kernel/power/user.c | 1 |
3 files changed, 46 insertions, 17 deletions
diff --git a/kernel/power/disk.c b/kernel/power/disk.c index 4bd68f482f2b..81d4d982f3f0 100644 --- a/kernel/power/disk.c +++ b/kernel/power/disk.c | |||
@@ -72,7 +72,6 @@ static int prepare_processes(void) | |||
72 | int error; | 72 | int error; |
73 | 73 | ||
74 | pm_prepare_console(); | 74 | pm_prepare_console(); |
75 | sys_sync(); | ||
76 | disable_nonboot_cpus(); | 75 | disable_nonboot_cpus(); |
77 | 76 | ||
78 | if (freeze_processes()) { | 77 | if (freeze_processes()) { |
diff --git a/kernel/power/process.c b/kernel/power/process.c index 02a1b3a9fa90..8ac7c35fad77 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c | |||
@@ -12,11 +12,12 @@ | |||
12 | #include <linux/interrupt.h> | 12 | #include <linux/interrupt.h> |
13 | #include <linux/suspend.h> | 13 | #include <linux/suspend.h> |
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/syscalls.h> | ||
15 | 16 | ||
16 | /* | 17 | /* |
17 | * Timeout for stopping processes | 18 | * Timeout for stopping processes |
18 | */ | 19 | */ |
19 | #define TIMEOUT (6 * HZ) | 20 | #define TIMEOUT (20 * HZ) |
20 | 21 | ||
21 | 22 | ||
22 | static inline int freezeable(struct task_struct * p) | 23 | static inline int freezeable(struct task_struct * p) |
@@ -54,38 +55,62 @@ void refrigerator(void) | |||
54 | current->state = save; | 55 | current->state = save; |
55 | } | 56 | } |
56 | 57 | ||
58 | static inline void freeze_process(struct task_struct *p) | ||
59 | { | ||
60 | unsigned long flags; | ||
61 | |||
62 | if (!freezing(p)) { | ||
63 | freeze(p); | ||
64 | spin_lock_irqsave(&p->sighand->siglock, flags); | ||
65 | signal_wake_up(p, 0); | ||
66 | spin_unlock_irqrestore(&p->sighand->siglock, flags); | ||
67 | } | ||
68 | } | ||
69 | |||
57 | /* 0 = success, else # of processes that we failed to stop */ | 70 | /* 0 = success, else # of processes that we failed to stop */ |
58 | int freeze_processes(void) | 71 | int freeze_processes(void) |
59 | { | 72 | { |
60 | int todo; | 73 | int todo, nr_user, user_frozen; |
61 | unsigned long start_time; | 74 | unsigned long start_time; |
62 | struct task_struct *g, *p; | 75 | struct task_struct *g, *p; |
63 | unsigned long flags; | 76 | unsigned long flags; |
64 | 77 | ||
65 | printk( "Stopping tasks: " ); | 78 | printk( "Stopping tasks: " ); |
66 | start_time = jiffies; | 79 | start_time = jiffies; |
80 | user_frozen = 0; | ||
67 | do { | 81 | do { |
68 | todo = 0; | 82 | nr_user = todo = 0; |
69 | read_lock(&tasklist_lock); | 83 | read_lock(&tasklist_lock); |
70 | do_each_thread(g, p) { | 84 | do_each_thread(g, p) { |
71 | if (!freezeable(p)) | 85 | if (!freezeable(p)) |
72 | continue; | 86 | continue; |
73 | if (frozen(p)) | 87 | if (frozen(p)) |
74 | continue; | 88 | continue; |
75 | 89 | if (p->mm && !(p->flags & PF_BORROWED_MM)) { | |
76 | freeze(p); | 90 | /* The task is a user-space one. |
77 | spin_lock_irqsave(&p->sighand->siglock, flags); | 91 | * Freeze it unless there's a vfork completion |
78 | signal_wake_up(p, 0); | 92 | * pending |
79 | spin_unlock_irqrestore(&p->sighand->siglock, flags); | 93 | */ |
80 | todo++; | 94 | if (!p->vfork_done) |
95 | freeze_process(p); | ||
96 | nr_user++; | ||
97 | } else { | ||
98 | /* Freeze only if the user space is frozen */ | ||
99 | if (user_frozen) | ||
100 | freeze_process(p); | ||
101 | todo++; | ||
102 | } | ||
81 | } while_each_thread(g, p); | 103 | } while_each_thread(g, p); |
82 | read_unlock(&tasklist_lock); | 104 | read_unlock(&tasklist_lock); |
105 | todo += nr_user; | ||
106 | if (!user_frozen && !nr_user) { | ||
107 | sys_sync(); | ||
108 | start_time = jiffies; | ||
109 | } | ||
110 | user_frozen = !nr_user; | ||
83 | yield(); /* Yield is okay here */ | 111 | yield(); /* Yield is okay here */ |
84 | if (todo && time_after(jiffies, start_time + TIMEOUT)) { | 112 | if (todo && time_after(jiffies, start_time + TIMEOUT)) |
85 | printk( "\n" ); | ||
86 | printk(KERN_ERR " stopping tasks timed out (%d tasks remaining)\n", todo ); | ||
87 | break; | 113 | break; |
88 | } | ||
89 | } while(todo); | 114 | } while(todo); |
90 | 115 | ||
91 | /* This does not unfreeze processes that are already frozen | 116 | /* This does not unfreeze processes that are already frozen |
@@ -94,8 +119,14 @@ int freeze_processes(void) | |||
94 | * but it cleans up leftover PF_FREEZE requests. | 119 | * but it cleans up leftover PF_FREEZE requests. |
95 | */ | 120 | */ |
96 | if (todo) { | 121 | if (todo) { |
122 | printk( "\n" ); | ||
123 | printk(KERN_ERR " stopping tasks timed out " | ||
124 | "after %d seconds (%d tasks remaining):\n", | ||
125 | TIMEOUT / HZ, todo); | ||
97 | read_lock(&tasklist_lock); | 126 | read_lock(&tasklist_lock); |
98 | do_each_thread(g, p) | 127 | do_each_thread(g, p) { |
128 | if (freezeable(p) && !frozen(p)) | ||
129 | printk(KERN_ERR " %s\n", p->comm); | ||
99 | if (freezing(p)) { | 130 | if (freezing(p)) { |
100 | pr_debug(" clean up: %s\n", p->comm); | 131 | pr_debug(" clean up: %s\n", p->comm); |
101 | p->flags &= ~PF_FREEZE; | 132 | p->flags &= ~PF_FREEZE; |
@@ -103,7 +134,7 @@ int freeze_processes(void) | |||
103 | recalc_sigpending_tsk(p); | 134 | recalc_sigpending_tsk(p); |
104 | spin_unlock_irqrestore(&p->sighand->siglock, flags); | 135 | spin_unlock_irqrestore(&p->sighand->siglock, flags); |
105 | } | 136 | } |
106 | while_each_thread(g, p); | 137 | } while_each_thread(g, p); |
107 | read_unlock(&tasklist_lock); | 138 | read_unlock(&tasklist_lock); |
108 | return todo; | 139 | return todo; |
109 | } | 140 | } |
diff --git a/kernel/power/user.c b/kernel/power/user.c index 8cabc405ca10..a97406b86ef3 100644 --- a/kernel/power/user.c +++ b/kernel/power/user.c | |||
@@ -138,7 +138,6 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp, | |||
138 | case SNAPSHOT_FREEZE: | 138 | case SNAPSHOT_FREEZE: |
139 | if (data->frozen) | 139 | if (data->frozen) |
140 | break; | 140 | break; |
141 | sys_sync(); | ||
142 | down(&pm_sem); | 141 | down(&pm_sem); |
143 | pm_prepare_console(); | 142 | pm_prepare_console(); |
144 | disable_nonboot_cpus(); | 143 | disable_nonboot_cpus(); |