public inbox for linux-pm@vger.kernel.org
 help / color / mirror / Atom feed
* [RFC][PATCH -mm][Experimental] swsusp: freeze userspace processes first
@ 2006-02-01  0:41 Rafael J. Wysocki
  2006-02-01 10:55 ` Pavel Machek
  2006-02-01 11:47 ` Pavel Machek
  0 siblings, 2 replies; 15+ messages in thread
From: Rafael J. Wysocki @ 2006-02-01  0:41 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Nigel Cunningham, Linux PM

[-- Attachment #1: Type: text/plain, Size: 6342 bytes --]

Hi,

This is an experimantal patch aimed at the "unable to freeze processes under
load" problem.

On my box the 2.6.16-rc1-mm4 kernel with this patch applied survives the
"dd if=/dev/hda of=/dev/null" test.

Please have a look.

Greetings,
Rafael


Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>

 include/linux/kmod.h    |    3 ++
 include/linux/suspend.h |    4 +++
 kernel/kmod.c           |   23 +++++++++++++++++
 kernel/power/process.c  |   62 +++++++++++++++++++++++++++++++++++++++++-------
 4 files changed, 83 insertions(+), 9 deletions(-)

Index: linux-2.6.16-rc1-mm4/kernel/power/process.c
===================================================================
--- linux-2.6.16-rc1-mm4.orig/kernel/power/process.c	2006-01-31 23:45:59.000000000 +0100
+++ linux-2.6.16-rc1-mm4/kernel/power/process.c	2006-02-01 01:12:14.000000000 +0100
@@ -12,12 +12,19 @@
 #include <linux/interrupt.h>
 #include <linux/suspend.h>
 #include <linux/module.h>
+#include <linux/kmod.h>
+#include <linux/mutex.h>
 
 /* 
  * Timeout for stopping processes
  */
 #define TIMEOUT	(6 * HZ)
 
+/* This is used to disable usermodehelper invocations while
+ * freeze_processes() is being executed
+ */
+int freezing_processes;
+DEFINE_MUTEX(freezer_lock);
 
 static inline int freezeable(struct task_struct * p)
 {
@@ -54,40 +61,77 @@ void refrigerator(void)
 	current->state = save;
 }
 
+static inline void freeze_process(struct task_struct *p)
+{
+	unsigned long flags;
+
+	freeze(p);
+	spin_lock_irqsave(&p->sighand->siglock, flags);
+	signal_wake_up(p, 0);
+	spin_unlock_irqrestore(&p->sighand->siglock, flags);
+}
+
 /* 0 = success, else # of processes that we failed to stop */
 int freeze_processes(void)
 {
-	int todo;
+	int todo, nr_kernel, nr_user, user_frozen;
 	unsigned long start_time;
 	struct task_struct *g, *p;
 	unsigned long flags;
 
+	mutex_lock(&freezer_lock);
+	freezing_processes = 1;
+	mutex_unlock(&freezer_lock);
+	while (atomic_read(&usermodehelper_waiting))
+		schedule();
+
 	printk( "Stopping tasks: " );
 	start_time = jiffies;
+	user_frozen = 0;
 	do {
-		todo = 0;
+		nr_kernel = 0;
+		nr_user = 0;
 		read_lock(&tasklist_lock);
 		do_each_thread(g, p) {
 			if (!freezeable(p))
 				continue;
 			if (frozen(p))
 				continue;
-
-			freeze(p);
-			spin_lock_irqsave(&p->sighand->siglock, flags);
-			signal_wake_up(p, 0);
-			spin_unlock_irqrestore(&p->sighand->siglock, flags);
-			todo++;
+			if (p->mm) {
+				/* The task is a user-space one. Freeze it */
+				printk("  freezing %s\n", p->comm);
+				freeze_process(p);
+				nr_user++;
+			} else {
+				/* Freeze only if the user space is frozen */
+				if (user_frozen) {
+					printk("  freezing [%s]\n", p->comm);
+					freeze_process(p);
+				}
+				nr_kernel++;
+			}
 		} while_each_thread(g, p);
 		read_unlock(&tasklist_lock);
+		user_frozen = !nr_user;
+		todo = nr_user + nr_kernel;
 		yield();			/* Yield is okay here */
 		if (todo && time_after(jiffies, start_time + TIMEOUT)) {
 			printk( "\n" );
-			printk(KERN_ERR " stopping tasks timed out (%d tasks remaining)\n", todo );
+			printk(KERN_ERR " stopping tasks timed out "
+				"after %d seconds (%d tasks remaining):\n",
+				TIMEOUT / HZ, todo);
+			do_each_thread(g, p) {
+				if (freezeable(p) && !frozen(p))
+					printk(KERN_ERR "  %s\n", p->comm);
+			} while_each_thread(g, p);
 			break;
 		}
 	} while(todo);
 
+	mutex_lock(&freezer_lock);
+	freezing_processes = 0;
+	mutex_unlock(&freezer_lock);
+
 	/* This does not unfreeze processes that are already frozen
 	 * (we have slightly ugly calling convention in that respect,
 	 * and caller must call thaw_processes() if something fails),
Index: linux-2.6.16-rc1-mm4/kernel/kmod.c
===================================================================
--- linux-2.6.16-rc1-mm4.orig/kernel/kmod.c	2006-01-31 23:45:59.000000000 +0100
+++ linux-2.6.16-rc1-mm4/kernel/kmod.c	2006-02-01 00:20:10.000000000 +0100
@@ -36,6 +36,8 @@
 #include <linux/mount.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/suspend.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 
 extern int max_threads;
@@ -216,6 +218,10 @@ static void __call_usermodehelper(void *
 		complete(sub_info->complete);
 }
 
+#ifdef CONFIG_SOFTWARE_SUSPEND
+atomic_t usermodehelper_waiting = ATOMIC_INIT(0);
+#endif
+
 /**
  * call_usermodehelper_keys - start a usermode application
  * @path: pathname for the application
@@ -249,11 +255,28 @@ int call_usermodehelper_keys(char *path,
 	if (!khelper_wq)
 		return -EBUSY;
 
+#ifdef CONFIG_SOFTWARE_SUSPEND
+	mutex_lock(&freezer_lock);
+	if (freezing_processes) {
+		mutex_unlock(&freezer_lock);
+		return 0;
+	}
+	if (wait)
+		atomic_inc(&usermodehelper_waiting);
+	mutex_unlock(&freezer_lock);
+#endif
+
 	if (path[0] == '\0')
 		return 0;
 
 	queue_work(khelper_wq, &work);
 	wait_for_completion(&done);
+
+#ifdef CONFIG_SOFTWARE_SUSPEND
+	if (wait)
+		atomic_dec(&usermodehelper_waiting);
+#endif
+
 	return sub_info.retval;
 }
 EXPORT_SYMBOL(call_usermodehelper_keys);
Index: linux-2.6.16-rc1-mm4/include/linux/suspend.h
===================================================================
--- linux-2.6.16-rc1-mm4.orig/include/linux/suspend.h	2006-01-31 23:45:59.000000000 +0100
+++ linux-2.6.16-rc1-mm4/include/linux/suspend.h	2006-02-01 00:20:20.000000000 +0100
@@ -40,6 +40,10 @@ extern void drain_local_pages(void);
 extern void mark_free_pages(struct zone *zone);
 
 #ifdef CONFIG_PM
+struct mutex;
+extern struct mutex freezer_lock;
+extern int freezing_processes;
+
 /* kernel/power/swsusp.c */
 extern int software_suspend(void);
 
Index: linux-2.6.16-rc1-mm4/include/linux/kmod.h
===================================================================
--- linux-2.6.16-rc1-mm4.orig/include/linux/kmod.h	2006-01-31 23:45:59.000000000 +0100
+++ linux-2.6.16-rc1-mm4/include/linux/kmod.h	2006-02-01 00:06:19.000000000 +0100
@@ -23,6 +23,7 @@
 #include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/compiler.h>
+#include <asm/atomic.h>
 
 #define KMOD_PATH_LEN 256
 
@@ -36,6 +37,8 @@ static inline int request_module(const c
 
 #define try_then_request_module(x, mod...) ((x) ?: (request_module(mod), (x)))
 
+extern atomic_t usermodehelper_waiting;
+
 struct key;
 extern int call_usermodehelper_keys(char *path, char *argv[], char *envp[],
 				    struct key *session_keyring, int wait);

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC][PATCH -mm][Experimental] swsusp: freeze userspace processes first
  2006-02-01  0:41 [RFC][PATCH -mm][Experimental] swsusp: freeze userspace processes first Rafael J. Wysocki
@ 2006-02-01 10:55 ` Pavel Machek
  2006-02-01 11:18   ` Nigel Cunningham
  2006-02-01 20:13   ` Rafael J. Wysocki
  2006-02-01 11:47 ` Pavel Machek
  1 sibling, 2 replies; 15+ messages in thread
From: Pavel Machek @ 2006-02-01 10:55 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: Nigel Cunningham, Linux PM

[-- Attachment #1: Type: text/plain, Size: 661 bytes --]

Hi!

> This is an experimantal patch aimed at the "unable to freeze processes under
> load" problem.
> 
> On my box the 2.6.16-rc1-mm4 kernel with this patch applied survives the
> "dd if=/dev/hda of=/dev/null" test.

What filesystem? ext2 vs. ext3 is very different. I can fix ext2 by
just upping the timeout. ext3 is harder, because of the journalling
thread. Maybe I'll take the sledgehammer approach and just freeze all
the user tasks first... I tried to do the "small" approach and just
fix the journalling code...

I'm not sure what problem the usermodehelper code is trying to
solve... why are usermodehelpers special?
								Pavel


-- 
Thanks, Sharp!

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC][PATCH -mm][Experimental] swsusp: freeze userspace processes first
  2006-02-01 10:55 ` Pavel Machek
@ 2006-02-01 11:18   ` Nigel Cunningham
  2006-02-01 20:13   ` Rafael J. Wysocki
  1 sibling, 0 replies; 15+ messages in thread
From: Nigel Cunningham @ 2006-02-01 11:18 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Linux PM


[-- Attachment #1.1: Type: text/plain, Size: 1008 bytes --]

Hi.

On Wednesday 01 February 2006 20:55, Pavel Machek wrote:
> Hi!
>
> > This is an experimantal patch aimed at the "unable to freeze processes
> > under load" problem.
> >
> > On my box the 2.6.16-rc1-mm4 kernel with this patch applied survives the
> > "dd if=/dev/hda of=/dev/null" test.
>
> What filesystem? ext2 vs. ext3 is very different. I can fix ext2 by
> just upping the timeout. ext3 is harder, because of the journalling
> thread. Maybe I'll take the sledgehammer approach and just freeze all
> the user tasks first... I tried to do the "small" approach and just
> fix the journalling code...
>
> I'm not sure what problem the usermodehelper code is trying to
> solve... why are usermodehelpers special?

This is related to the 'Hotplug events during sleep transition' thread from 
the PM list from December.

Regards,

Nigel


-- 
See our web page for Howtos, FAQs, the Wiki and mailing list info.
http://www.suspend2.net                IRC: #suspend2 on Freenode

[-- Attachment #1.2: Type: application/pgp-signature, Size: 189 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC][PATCH -mm][Experimental] swsusp: freeze userspace processes first
  2006-02-01  0:41 [RFC][PATCH -mm][Experimental] swsusp: freeze userspace processes first Rafael J. Wysocki
  2006-02-01 10:55 ` Pavel Machek
@ 2006-02-01 11:47 ` Pavel Machek
  2006-02-01 12:24   ` Nigel Cunningham
  2006-02-01 22:19   ` Rafael J. Wysocki
  1 sibling, 2 replies; 15+ messages in thread
From: Pavel Machek @ 2006-02-01 11:47 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: Nigel Cunningham, Linux PM

[-- Attachment #1: Type: text/plain, Size: 4038 bytes --]

Hi!

> This is an experimantal patch aimed at the "unable to freeze processes under
> load" problem.
> 
> On my box the 2.6.16-rc1-mm4 kernel with this patch applied survives the
> "dd if=/dev/hda of=/dev/null" test.
> 
> Please have a look.

It makes it better (well, I used my own, simpler variant, but that
should not matter; patch is attached). I now can't reproduce hangs
with simple stress testing, but running kernel make alongside that
makes it hang sometimes. Example of non-frozen gcc:

gcc           D EEE06A70     0  1750   1749  1751
(NOTLB)
df85df38 00000046 bf878130 eee06a70 00004111 eee06a70 eee06a70
003d0900
       00000000 c0137cf5 df85c000 00000000 c058ada2 c012503e ef2c915c
ef2c9030
       c1c0b480 7c3b8500 003d0927 df85c000 00000a98 7c3b8500 003d0927
c0770800
Call Trace:
 [<c0137cf5>] attach_pid+0x25/0xb0
 [<c058ada2>] _write_unlock_irq+0x12/0x30
 [<c012503e>] copy_process+0xe5e/0x11b0
 [<c0588f74>] wait_for_completion+0x94/0xd0
 [<c0121690>] default_wake_function+0x0/0x10
 [<c01254d9>] do_fork+0x149/0x210
 [<c0101218>] sys_vfork+0x28/0x30
 [<c0103231>] syscall_call+0x7/0xb

...maybe solving this would solve journalling problems, too? It is
similar AFAICT.
								Pavel

diff --git a/kernel/power/disk.c b/kernel/power/disk.c
index e24446f..90d6c1a 100644
--- a/kernel/power/disk.c
+++ b/kernel/power/disk.c
@@ -87,7 +87,6 @@ static int prepare_processes(void)
 	int error;
 
 	pm_prepare_console();
-	sys_sync();
 	disable_nonboot_cpus();
 
 	if (freeze_processes()) {
diff --git a/kernel/power/process.c b/kernel/power/process.c
index 02a1b3a..bd16e44 100644
--- a/kernel/power/process.c
+++ b/kernel/power/process.c
@@ -16,7 +16,7 @@
 /* 
  * Timeout for stopping processes
  */
-#define TIMEOUT	(6 * HZ)
+#define TIMEOUT	(60 * HZ)
 
 
 static inline int freezeable(struct task_struct * p)
@@ -54,32 +54,53 @@ void refrigerator(void)
 	current->state = save;
 }
 
+static void freeze_process(struct task_struct *p)
+{
+       unsigned long flags;
+
+       freeze(p);
+       spin_lock_irqsave(&p->sighand->siglock, flags);
+       signal_wake_up(p, 0);
+       spin_unlock_irqrestore(&p->sighand->siglock, flags);
+}
+
 /* 0 = success, else # of processes that we failed to stop */
 int freeze_processes(void)
 {
-	int todo;
+	int todo, user_frozen, nr_user;
 	unsigned long start_time;
 	struct task_struct *g, *p;
 	unsigned long flags;
 
 	printk( "Stopping tasks: " );
 	start_time = jiffies;
+	user_frozen = 0;
 	do {
-		todo = 0;
+		nr_user = todo = 0;
 		read_lock(&tasklist_lock);
 		do_each_thread(g, p) {
 			if (!freezeable(p))
 				continue;
 			if (frozen(p))
 				continue;
-
-			freeze(p);
-			spin_lock_irqsave(&p->sighand->siglock, flags);
-			signal_wake_up(p, 0);
-			spin_unlock_irqrestore(&p->sighand->siglock, flags);
-			todo++;
+			if (p->mm) {
+				/* The task is a user-space one. Freeze it */
+				freeze_process(p);
+				todo++;
+				nr_user++;
+			} else {
+				/* Freeze only if the user space is frozen */
+				if (user_frozen)
+					freeze_process(p);
+				todo++;
+			}
 		} while_each_thread(g, p);
 		read_unlock(&tasklist_lock);
+		if (!user_frozen && !nr_user) {
+			printk("sync");
+			sys_sync();
+		}
+		user_frozen = !nr_user;
 		yield();			/* Yield is okay here */
 		if (todo && time_after(jiffies, start_time + TIMEOUT)) {
 			printk( "\n" );
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index 41f6636..c9c293f 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -80,7 +80,7 @@ static int save_highmem_zone(struct zone
 		void *kaddr;
 		unsigned long pfn = zone_pfn + zone->zone_start_pfn;
 
-		if (!(pfn%1000))
+		if (!(pfn%10000))
 			printk(".");
 		if (!pfn_valid(pfn))
 			continue;
@@ -121,13 +121,14 @@ int save_highmem(void)
 	struct zone *zone;
 	int res = 0;
 
-	pr_debug("swsusp: Saving Highmem\n");
+	pr_debug("swsusp: Saving Highmem");
 	for_each_zone (zone) {
 		if (is_highmem(zone))
 			res = save_highmem_zone(zone);
 		if (res)
 			return res;
 	}
+	printk("\n");
 	return 0;
 }
 

-- 
Thanks, Sharp!

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [RFC][PATCH -mm][Experimental] swsusp: freeze userspace processes first
  2006-02-01 11:47 ` Pavel Machek
@ 2006-02-01 12:24   ` Nigel Cunningham
  2006-02-01 12:49     ` Pavel Machek
  2006-02-01 22:19   ` Rafael J. Wysocki
  1 sibling, 1 reply; 15+ messages in thread
From: Nigel Cunningham @ 2006-02-01 12:24 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Linux PM


[-- Attachment #1.1: Type: text/plain, Size: 2322 bytes --]

Hi.

On Wednesday 01 February 2006 21:47, Pavel Machek wrote:
> Hi!
>
> > This is an experimantal patch aimed at the "unable to freeze processes
> > under load" problem.
> >
> > On my box the 2.6.16-rc1-mm4 kernel with this patch applied survives the
> > "dd if=/dev/hda of=/dev/null" test.
> >
> > Please have a look.
>
> It makes it better (well, I used my own, simpler variant, but that
> should not matter; patch is attached). I now can't reproduce hangs
> with simple stress testing, but running kernel make alongside that
> makes it hang sometimes. Example of non-frozen gcc:
>
> gcc           D EEE06A70     0  1750   1749  1751
> (NOTLB)
> df85df38 00000046 bf878130 eee06a70 00004111 eee06a70 eee06a70
> 003d0900
>        00000000 c0137cf5 df85c000 00000000 c058ada2 c012503e ef2c915c
> ef2c9030
>        c1c0b480 7c3b8500 003d0927 df85c000 00000a98 7c3b8500 003d0927
> c0770800
> Call Trace:
>  [<c0137cf5>] attach_pid+0x25/0xb0
>  [<c058ada2>] _write_unlock_irq+0x12/0x30
>  [<c012503e>] copy_process+0xe5e/0x11b0
>  [<c0588f74>] wait_for_completion+0x94/0xd0
>  [<c0121690>] default_wake_function+0x0/0x10
>  [<c01254d9>] do_fork+0x149/0x210
>  [<c0101218>] sys_vfork+0x28/0x30
>  [<c0103231>] syscall_call+0x7/0xb
>
> ...maybe solving this would solve journalling problems, too? It is
> similar AFAICT.

What exactly is the journalling problem?

>
> diff --git a/kernel/power/disk.c b/kernel/power/disk.c
> index e24446f..90d6c1a 100644
> --- a/kernel/power/disk.c
> +++ b/kernel/power/disk.c
> @@ -87,7 +87,6 @@ static int prepare_processes(void)
>  	int error;
>
>  	pm_prepare_console();
> -	sys_sync();
>  	disable_nonboot_cpus();
>
>  	if (freeze_processes()) {

That will help speed up freezing, but it won't help the integrity of your data 
if you don't resume.

> diff --git a/kernel/power/process.c b/kernel/power/process.c
> index 02a1b3a..bd16e44 100644
> --- a/kernel/power/process.c
> +++ b/kernel/power/process.c
> @@ -16,7 +16,7 @@
>  /*
>   * Timeout for stopping processes
>   */
> -#define TIMEOUT	(6 * HZ)
> +#define TIMEOUT	(60 * HZ)

You're kidding, right?

Regards,

Nigel
-- 
See our web page for Howtos, FAQs, the Wiki and mailing list info.
http://www.suspend2.net                IRC: #suspend2 on Freenode

[-- Attachment #1.2: Type: application/pgp-signature, Size: 189 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC][PATCH -mm][Experimental] swsusp: freeze userspace processes first
  2006-02-01 12:24   ` Nigel Cunningham
@ 2006-02-01 12:49     ` Pavel Machek
  2006-02-01 21:41       ` Nigel Cunningham
  2006-02-01 23:57       ` Rafael J. Wysocki
  0 siblings, 2 replies; 15+ messages in thread
From: Pavel Machek @ 2006-02-01 12:49 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: Linux PM

[-- Attachment #1: Type: text/plain, Size: 2185 bytes --]

Hi!

> > > This is an experimantal patch aimed at the "unable to freeze processes
> > > under load" problem.
> > >
> > > On my box the 2.6.16-rc1-mm4 kernel with this patch applied survives the
> > > "dd if=/dev/hda of=/dev/null" test.
> > >
> > > Please have a look.
> >
> > It makes it better (well, I used my own, simpler variant, but that
> > should not matter; patch is attached). I now can't reproduce hangs
> > with simple stress testing, but running kernel make alongside that
> > makes it hang sometimes. Example of non-frozen gcc:
> >
> > gcc           D EEE06A70     0  1750   1749  1751
> > (NOTLB)
> > df85df38 00000046 bf878130 eee06a70 00004111 eee06a70 eee06a70
> > 003d0900
> >        00000000 c0137cf5 df85c000 00000000 c058ada2 c012503e ef2c915c
> > ef2c9030
> >        c1c0b480 7c3b8500 003d0927 df85c000 00000a98 7c3b8500 003d0927
> > c0770800
> > Call Trace:
> >  [<c0137cf5>] attach_pid+0x25/0xb0
> >  [<c058ada2>] _write_unlock_irq+0x12/0x30
> >  [<c012503e>] copy_process+0xe5e/0x11b0
> >  [<c0588f74>] wait_for_completion+0x94/0xd0
> >  [<c0121690>] default_wake_function+0x0/0x10
> >  [<c01254d9>] do_fork+0x149/0x210
> >  [<c0101218>] sys_vfork+0x28/0x30
> >  [<c0103231>] syscall_call+0x7/0xb
> >
> > ...maybe solving this would solve journalling problems, too? It is
> > similar AFAICT.
> 
> What exactly is the journalling problem?

Hangs by freezing everything at same time only happen with journalling
filesystems; there kjournald needs to be running if we want user
threads to be stoppable.

> > @@ -87,7 +87,6 @@ static int prepare_processes(void)
> >  	int error;
> >
> >  	pm_prepare_console();
> > -	sys_sync();
> >  	disable_nonboot_cpus();
> >
> >  	if (freeze_processes()) {
> 
> That will help speed up freezing, but it won't help the integrity of your data 
> if you don't resume.

See the patch better; it is now done between freezing userspace and
kernel threads.

> >  /*
> >   * Timeout for stopping processes
> >   */
> > -#define TIMEOUT	(6 * HZ)
> > +#define TIMEOUT	(60 * HZ)
> 
> You're kidding, right?

sync takes long time... and 6 seconds were not enough to deliver
signals on highly-loaded ext2.
							Pavel

-- 
Thanks, Sharp!

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC][PATCH -mm][Experimental] swsusp: freeze userspace processes first
  2006-02-01 10:55 ` Pavel Machek
  2006-02-01 11:18   ` Nigel Cunningham
@ 2006-02-01 20:13   ` Rafael J. Wysocki
  1 sibling, 0 replies; 15+ messages in thread
From: Rafael J. Wysocki @ 2006-02-01 20:13 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Nigel Cunningham, Linux PM

Hi,

[Sorry, I was unable to respond earlier.]

On Wednesday 01 February 2006 11:55, Pavel Machek wrote:
> > This is an experimantal patch aimed at the "unable to freeze processes under
> > load" problem.
> > 
> > On my box the 2.6.16-rc1-mm4 kernel with this patch applied survives the
> > "dd if=/dev/hda of=/dev/null" test.
> 
> What filesystem? ext2 vs. ext3 is very different.

Just the entire disk.

> I can fix ext2 by 
> just upping the timeout. ext3 is harder, because of the journalling
> thread. Maybe I'll take the sledgehammer approach and just freeze all
> the user tasks first... I tried to do the "small" approach and just
> fix the journalling code...
> 
> I'm not sure what problem the usermodehelper code is trying to
> solve... why are usermodehelpers special?

They may be waited for uninterruptilby, so we can get an unfreezable proces
if we freeze one of them.

Actually I think I made a mistake here, since call_usermodehelper_keys()
should return -EBUSY rather than 0 when freezing_processes is non-zero
(if we return 0, the caller gets confused, because it assumes the call has
happend and has been successful, which is wrong).

Greetings,
Rafael

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC][PATCH -mm][Experimental] swsusp: freeze userspace processes first
  2006-02-01 12:49     ` Pavel Machek
@ 2006-02-01 21:41       ` Nigel Cunningham
  2006-02-01 23:57       ` Rafael J. Wysocki
  1 sibling, 0 replies; 15+ messages in thread
From: Nigel Cunningham @ 2006-02-01 21:41 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Linux PM


[-- Attachment #1.1: Type: text/plain, Size: 3114 bytes --]

Hi.

On Wednesday 01 February 2006 22:49, Pavel Machek wrote:
> Hi!
>
> > > > This is an experimantal patch aimed at the "unable to freeze
> > > > processes under load" problem.
> > > >
> > > > On my box the 2.6.16-rc1-mm4 kernel with this patch applied survives
> > > > the "dd if=/dev/hda of=/dev/null" test.
> > > >
> > > > Please have a look.
> > >
> > > It makes it better (well, I used my own, simpler variant, but that
> > > should not matter; patch is attached). I now can't reproduce hangs
> > > with simple stress testing, but running kernel make alongside that
> > > makes it hang sometimes. Example of non-frozen gcc:
> > >
> > > gcc           D EEE06A70     0  1750   1749  1751
> > > (NOTLB)
> > > df85df38 00000046 bf878130 eee06a70 00004111 eee06a70 eee06a70
> > > 003d0900
> > >        00000000 c0137cf5 df85c000 00000000 c058ada2 c012503e ef2c915c
> > > ef2c9030
> > >        c1c0b480 7c3b8500 003d0927 df85c000 00000a98 7c3b8500 003d0927
> > > c0770800
> > > Call Trace:
> > >  [<c0137cf5>] attach_pid+0x25/0xb0
> > >  [<c058ada2>] _write_unlock_irq+0x12/0x30
> > >  [<c012503e>] copy_process+0xe5e/0x11b0
> > >  [<c0588f74>] wait_for_completion+0x94/0xd0
> > >  [<c0121690>] default_wake_function+0x0/0x10
> > >  [<c01254d9>] do_fork+0x149/0x210
> > >  [<c0101218>] sys_vfork+0x28/0x30
> > >  [<c0103231>] syscall_call+0x7/0xb
> > >
> > > ...maybe solving this would solve journalling problems, too? It is
> > > similar AFAICT.
> >
> > What exactly is the journalling problem?
>
> Hangs by freezing everything at same time only happen with journalling
> filesystems; there kjournald needs to be running if we want user
> threads to be stoppable.

Ah. Right. That should be fixed by doing the kernelspace threads after the 
usespace ones (as I believe you're now doing?). I have seen XFS still 
submitting I/O after the sys_sync is finished (it apparently treats sys_sync 
as a weak and useless indication that it should think about considering 
flushing a buffer or two). That's why I'm now using bdev freezing instead of 
sys_sync.

> > > @@ -87,7 +87,6 @@ static int prepare_processes(void)
> > >  	int error;
> > >
> > >  	pm_prepare_console();
> > > -	sys_sync();
> > >  	disable_nonboot_cpus();
> > >
> > >  	if (freeze_processes()) {
> >
> > That will help speed up freezing, but it won't help the integrity of your
> > data if you don't resume.
>
> See the patch better; it is now done between freezing userspace and
> kernel threads.

Ah. So I see. Sorry.

> > >  /*
> > >   * Timeout for stopping processes
> > >   */
> > > -#define TIMEOUT	(6 * HZ)
> > > +#define TIMEOUT	(60 * HZ)
> >
> > You're kidding, right?
>
> sync takes long time... and 6 seconds were not enough to deliver
> signals on highly-loaded ext2.

I'm using a timeout per step. Perhaps you could try that approach? 1 minute is 
an awfully long time to wait if you do hang.

Regards,

Nigel
-- 
See our web page for Howtos, FAQs, the Wiki and mailing list info.
http://www.suspend2.net                IRC: #suspend2 on Freenode

[-- Attachment #1.2: Type: application/pgp-signature, Size: 189 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC][PATCH -mm][Experimental] swsusp: freeze userspace processes first
  2006-02-01 11:47 ` Pavel Machek
  2006-02-01 12:24   ` Nigel Cunningham
@ 2006-02-01 22:19   ` Rafael J. Wysocki
  1 sibling, 0 replies; 15+ messages in thread
From: Rafael J. Wysocki @ 2006-02-01 22:19 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Nigel Cunningham, Linux PM

Hi,

On Wednesday 01 February 2006 12:47, Pavel Machek wrote:
> > This is an experimantal patch aimed at the "unable to freeze processes under
> > load" problem.
> > 
> > On my box the 2.6.16-rc1-mm4 kernel with this patch applied survives the
> > "dd if=/dev/hda of=/dev/null" test.
> > 
> > Please have a look.
> 
> It makes it better (well, I used my own, simpler variant, but that
> should not matter; patch is attached). I now can't reproduce hangs
> with simple stress testing,

This means the direction is right ...

> but running kernel make alongside that 
> makes it hang sometimes.

... but there still is a race here.

> Example of non-frozen gcc: 
> 
> gcc           D EEE06A70     0  1750   1749  1751
> (NOTLB)
> df85df38 00000046 bf878130 eee06a70 00004111 eee06a70 eee06a70
> 003d0900
>        00000000 c0137cf5 df85c000 00000000 c058ada2 c012503e ef2c915c
> ef2c9030
>        c1c0b480 7c3b8500 003d0927 df85c000 00000a98 7c3b8500 003d0927
> c0770800
> Call Trace:
>  [<c0137cf5>] attach_pid+0x25/0xb0
>  [<c058ada2>] _write_unlock_irq+0x12/0x30
>  [<c012503e>] copy_process+0xe5e/0x11b0
>  [<c0588f74>] wait_for_completion+0x94/0xd0
>  [<c0121690>] default_wake_function+0x0/0x10
>  [<c01254d9>] do_fork+0x149/0x210
>  [<c0101218>] sys_vfork+0x28/0x30
>  [<c0103231>] syscall_call+0x7/0xb

[I'm trying to understand this trace, but with not much success, so far.
Apparently sys_vfork() calls do_fork() which calls copy_process(),
which calls attach_pid().  But what default_wake_function() and
wait_for_completion() are doing here?  And where it got stuck, actually?]

I think the problem is related to the kernel make using fork() heavily.
Namely, if the parent process uses CLONE_VFORK, it will wait for the
vfork completion.  Now if the child process is frozen _before_
it completes the vfork completion, the parent will be unfreezeable.

> ...maybe solving this would solve journalling problems, too? It is
> similar AFAICT.

There's a chance, I think. ;-)

> diff --git a/kernel/power/disk.c b/kernel/power/disk.c
> index e24446f..90d6c1a 100644
> --- a/kernel/power/disk.c
> +++ b/kernel/power/disk.c
> @@ -87,7 +87,6 @@ static int prepare_processes(void)
>  	int error;
>  
>  	pm_prepare_console();
> -	sys_sync();
>  	disable_nonboot_cpus();
>  
>  	if (freeze_processes()) {
> diff --git a/kernel/power/process.c b/kernel/power/process.c
> index 02a1b3a..bd16e44 100644
> --- a/kernel/power/process.c
> +++ b/kernel/power/process.c
> @@ -16,7 +16,7 @@
>  /* 
>   * Timeout for stopping processes
>   */
> -#define TIMEOUT	(6 * HZ)
> +#define TIMEOUT	(60 * HZ)
>  
>  
>  static inline int freezeable(struct task_struct * p)
> @@ -54,32 +54,53 @@ void refrigerator(void)
>  	current->state = save;
>  }
>  
> +static void freeze_process(struct task_struct *p)
> +{
> +       unsigned long flags;
> +
> +       freeze(p);
> +       spin_lock_irqsave(&p->sighand->siglock, flags);
> +       signal_wake_up(p, 0);
> +       spin_unlock_irqrestore(&p->sighand->siglock, flags);
> +}
> +
>  /* 0 = success, else # of processes that we failed to stop */
>  int freeze_processes(void)
>  {
> -	int todo;
> +	int todo, user_frozen, nr_user;
>  	unsigned long start_time;
>  	struct task_struct *g, *p;
>  	unsigned long flags;
>  
>  	printk( "Stopping tasks: " );
>  	start_time = jiffies;
> +	user_frozen = 0;
>  	do {
> -		todo = 0;
> +		nr_user = todo = 0;
>  		read_lock(&tasklist_lock);
>  		do_each_thread(g, p) {
>  			if (!freezeable(p))
>  				continue;
>  			if (frozen(p))
>  				continue;
> -
> -			freeze(p);
> -			spin_lock_irqsave(&p->sighand->siglock, flags);
> -			signal_wake_up(p, 0);
> -			spin_unlock_irqrestore(&p->sighand->siglock, flags);
> -			todo++;
> +			if (p->mm) {

This one is too simplistic, it appears.  We should lock the task to check its mm
and there may be kernel threads with non-null mm (they have the
PF_BORROWED_MM flag set though, so we have to check this too).

> +				/* The task is a user-space one. Freeze it */
> +				freeze_process(p);
> +				todo++;

I think you can drop this ...

> +				nr_user++;
> +			} else {
> +				/* Freeze only if the user space is frozen */
> +				if (user_frozen)
> +					freeze_process(p);
> +				todo++;
> +			}
>  		} while_each_thread(g, p);
>  		read_unlock(&tasklist_lock);

... if you do

 +		todo += nr_user;
> +		if (!user_frozen && !nr_user) {
> +			printk("sync");
> +			sys_sync();
> +		}
> +		user_frozen = !nr_user;
>  		yield();			/* Yield is okay here */
>  		if (todo && time_after(jiffies, start_time + TIMEOUT)) {
>  			printk( "\n" );
}-- debugging stuff snipped --{

Greetings,
Rafael 

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC][PATCH -mm][Experimental] swsusp: freeze userspace processes first
  2006-02-01 12:49     ` Pavel Machek
  2006-02-01 21:41       ` Nigel Cunningham
@ 2006-02-01 23:57       ` Rafael J. Wysocki
  2006-02-02 13:55         ` Rafael J. Wysocki
  1 sibling, 1 reply; 15+ messages in thread
From: Rafael J. Wysocki @ 2006-02-01 23:57 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Nigel Cunningham, Linux PM

Hi,

On Wednesday 01 February 2006 13:49, Pavel Machek wrote:
> > > > This is an experimantal patch aimed at the "unable to freeze processes
> > > > under load" problem.
> > > >
}-- snip --{
> > >  /*
> > >   * Timeout for stopping processes
> > >   */
> > > -#define TIMEOUT	(6 * HZ)
> > > +#define TIMEOUT	(60 * HZ)
> > 
> > You're kidding, right?
> 
> sync takes long time... and 6 seconds were not enough to deliver
> signals on highly-loaded ext2.

The appended modified version of the original patch solves the timeout vs sync
problem. ;-)

Seriously speaking I have incoroprated your changes (extended to the userland
interface) and made some fixes (the usermodehelper-related part is still
there, for completness).

Greetings,
Rafael


Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>

 include/linux/suspend.h |    6 +++
 kernel/kmod.c           |   19 ++++++++++++
 kernel/power/disk.c     |    1 
 kernel/power/process.c  |   74 ++++++++++++++++++++++++++++++++++++++----------
 kernel/power/user.c     |    1 
 5 files changed, 85 insertions(+), 16 deletions(-)

Index: linux-2.6.16-rc1-mm4/kernel/power/process.c
===================================================================
--- linux-2.6.16-rc1-mm4.orig/kernel/power/process.c
+++ linux-2.6.16-rc1-mm4/kernel/power/process.c
@@ -12,12 +12,20 @@
 #include <linux/interrupt.h>
 #include <linux/suspend.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/syscalls.h>
 
 /* 
  * Timeout for stopping processes
  */
 #define TIMEOUT	(6 * HZ)
 
+/* This is used to disable usermodehelper invocations while
+ * freeze_processes() is being executed
+ */
+DEFINE_MUTEX(freezer_lock);
+int freezing_processes;
+atomic_t usermodehelper_waiting = ATOMIC_INIT(0);
 
 static inline int freezeable(struct task_struct * p)
 {
@@ -54,48 +62,86 @@ void refrigerator(void)
 	current->state = save;
 }
 
+static inline void freeze_process(struct task_struct *p)
+{
+	unsigned long flags;
+
+	freeze(p);
+	spin_lock_irqsave(&p->sighand->siglock, flags);
+	signal_wake_up(p, 0);
+	spin_unlock_irqrestore(&p->sighand->siglock, flags);
+}
+
 /* 0 = success, else # of processes that we failed to stop */
 int freeze_processes(void)
 {
-	int todo;
+	int todo, nr_user, user_frozen;
 	unsigned long start_time;
 	struct task_struct *g, *p;
 	unsigned long flags;
 
+	mutex_lock(&freezer_lock);
+	freezing_processes = 1;
+	mutex_unlock(&freezer_lock);
+	while (atomic_read(&usermodehelper_waiting))
+		schedule();
+
 	printk( "Stopping tasks: " );
 	start_time = jiffies;
+	user_frozen = 0;
 	do {
-		todo = 0;
+		nr_user = todo = 0;
 		read_lock(&tasklist_lock);
 		do_each_thread(g, p) {
 			if (!freezeable(p))
 				continue;
 			if (frozen(p))
 				continue;
-
-			freeze(p);
-			spin_lock_irqsave(&p->sighand->siglock, flags);
-			signal_wake_up(p, 0);
-			spin_unlock_irqrestore(&p->sighand->siglock, flags);
-			todo++;
+			if (p->mm && !(p->flags & PF_BORROWED_MM)) {
+				/* The task is a user-space one.
+				 * Freeze it unless there's a vfork completion
+				 * pending
+				 */
+				if (!p->vfork_done)
+					freeze_process(p);
+				nr_user++;
+			} else {
+				/* Freeze only if the user space is frozen */
+				if (user_frozen)
+					freeze_process(p);
+				todo++;
+			}
 		} while_each_thread(g, p);
 		read_unlock(&tasklist_lock);
+		todo += nr_user;
+		if (!user_frozen && !nr_user) {
+			sys_sync();
+			start_time = jiffies;
+		}
+		user_frozen = !nr_user;
 		yield();			/* Yield is okay here */
-		if (todo && time_after(jiffies, start_time + TIMEOUT)) {
-			printk( "\n" );
-			printk(KERN_ERR " stopping tasks timed out (%d tasks remaining)\n", todo );
+		if (todo && time_after(jiffies, start_time + TIMEOUT))
 			break;
-		}
 	} while(todo);
 
+	mutex_lock(&freezer_lock);
+	freezing_processes = 0;
+	mutex_unlock(&freezer_lock);
+
 	/* This does not unfreeze processes that are already frozen
 	 * (we have slightly ugly calling convention in that respect,
 	 * and caller must call thaw_processes() if something fails),
 	 * but it cleans up leftover PF_FREEZE requests.
 	 */
 	if (todo) {
+		printk( "\n" );
+		printk(KERN_ERR " stopping tasks timed out "
+			"after %d seconds (%d tasks remaining):\n",
+			TIMEOUT / HZ, todo);
 		read_lock(&tasklist_lock);
-		do_each_thread(g, p)
+		do_each_thread(g, p) {
+			if (freezeable(p) && !frozen(p))
+				printk(KERN_ERR "  %s\n", p->comm);
 			if (freezing(p)) {
 				pr_debug("  clean up: %s\n", p->comm);
 				p->flags &= ~PF_FREEZE;
@@ -103,7 +149,7 @@ int freeze_processes(void)
 				recalc_sigpending_tsk(p);
 				spin_unlock_irqrestore(&p->sighand->siglock, flags);
 			}
-		while_each_thread(g, p);
+		} while_each_thread(g, p);
 		read_unlock(&tasklist_lock);
 		return todo;
 	}
Index: linux-2.6.16-rc1-mm4/kernel/kmod.c
===================================================================
--- linux-2.6.16-rc1-mm4.orig/kernel/kmod.c
+++ linux-2.6.16-rc1-mm4/kernel/kmod.c
@@ -36,6 +36,8 @@
 #include <linux/mount.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/suspend.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 
 extern int max_threads;
@@ -249,11 +251,28 @@ int call_usermodehelper_keys(char *path,
 	if (!khelper_wq)
 		return -EBUSY;
 
+#ifdef CONFIG_PM
+	mutex_lock(&freezer_lock);
+	if (freezing_processes) {
+		mutex_unlock(&freezer_lock);
+		return -EBUSY;
+	}
+	if (wait)
+		atomic_inc(&usermodehelper_waiting);
+	mutex_unlock(&freezer_lock);
+#endif
+
 	if (path[0] == '\0')
 		return 0;
 
 	queue_work(khelper_wq, &work);
 	wait_for_completion(&done);
+
+#ifdef CONFIG_PM
+	if (wait)
+		atomic_dec(&usermodehelper_waiting);
+#endif
+
 	return sub_info.retval;
 }
 EXPORT_SYMBOL(call_usermodehelper_keys);
Index: linux-2.6.16-rc1-mm4/include/linux/suspend.h
===================================================================
--- linux-2.6.16-rc1-mm4.orig/include/linux/suspend.h
+++ linux-2.6.16-rc1-mm4/include/linux/suspend.h
@@ -9,6 +9,7 @@
 #include <linux/config.h>
 #include <linux/init.h>
 #include <linux/pm.h>
+#include <asm/atomic.h>
 
 /* page backup entry */
 typedef struct pbe {
@@ -40,6 +41,11 @@ extern void drain_local_pages(void);
 extern void mark_free_pages(struct zone *zone);
 
 #ifdef CONFIG_PM
+struct mutex;
+extern struct mutex freezer_lock;
+extern int freezing_processes;
+extern atomic_t usermodehelper_waiting;
+
 /* kernel/power/swsusp.c */
 extern int software_suspend(void);
 
Index: linux-2.6.16-rc1-mm4/kernel/power/disk.c
===================================================================
--- linux-2.6.16-rc1-mm4.orig/kernel/power/disk.c
+++ linux-2.6.16-rc1-mm4/kernel/power/disk.c
@@ -73,7 +73,6 @@ static int prepare_processes(void)
 	int error;
 
 	pm_prepare_console();
-	sys_sync();
 	disable_nonboot_cpus();
 
 	if (freeze_processes()) {
Index: linux-2.6.16-rc1-mm4/kernel/power/user.c
===================================================================
--- linux-2.6.16-rc1-mm4.orig/kernel/power/user.c
+++ linux-2.6.16-rc1-mm4/kernel/power/user.c
@@ -137,7 +137,6 @@ static int snapshot_ioctl(struct inode *
 	case SNAPSHOT_FREEZE:
 		if (data->frozen)
 			break;
-		sys_sync();
 		down(&pm_sem);
 		pm_prepare_console();
 		disable_nonboot_cpus();

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Re: [RFC][PATCH -mm][Experimental] swsusp: freeze userspace processes first
  2006-02-01 23:57       ` Rafael J. Wysocki
@ 2006-02-02 13:55         ` Rafael J. Wysocki
  2006-02-02 15:08           ` Pavel Machek
  0 siblings, 1 reply; 15+ messages in thread
From: Rafael J. Wysocki @ 2006-02-02 13:55 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Nigel Cunningham, Linux PM

Hi,

On Thursday 02 February 2006 00:57, Rafael J. Wysocki wrote:
> On Wednesday 01 February 2006 13:49, Pavel Machek wrote:
> > > > > This is an experimantal patch aimed at the "unable to freeze processes
> > > > > under load" problem.
> > > > >
> }-- snip --{
> > > >  /*
> > > >   * Timeout for stopping processes
> > > >   */
> > > > -#define TIMEOUT	(6 * HZ)
> > > > +#define TIMEOUT	(60 * HZ)
> > > 
> > > You're kidding, right?
> > 
> > sync takes long time... and 6 seconds were not enough to deliver
> > signals on highly-loaded ext2.
> 
> The appended modified version of the original patch solves the timeout vs sync
> problem. ;-)
> 
> Seriously speaking I have incoroprated your changes (extended to the userland
> interface) and made some fixes (the usermodehelper-related part is still
> there, for completness).
}-- snip --{  
> +	mutex_lock(&freezer_lock);
> +	freezing_processes = 1;
> +	mutex_unlock(&freezer_lock);
> +	while (atomic_read(&usermodehelper_waiting))
> +		schedule();

That requires a timeout in case we have a user mode helper in the D state.
The corrected patch is appended.

BTW, it contains a change that may help solve the unfreezeable gcc problem
that has appeared in your tests.  Could you please try it or tell me what I
should do to reproduce the problem?

Rafael


Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>

 include/linux/suspend.h |    6 +++
 kernel/kmod.c           |   19 +++++++++++
 kernel/power/disk.c     |    1 
 kernel/power/process.c  |   81 +++++++++++++++++++++++++++++++++++++++---------
 kernel/power/user.c     |    1 
 5 files changed, 92 insertions(+), 16 deletions(-)

Index: linux-2.6.16-rc1-mm4/kernel/power/process.c
===================================================================
--- linux-2.6.16-rc1-mm4.orig/kernel/power/process.c
+++ linux-2.6.16-rc1-mm4/kernel/power/process.c
@@ -12,12 +12,20 @@
 #include <linux/interrupt.h>
 #include <linux/suspend.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/syscalls.h>
 
 /* 
  * Timeout for stopping processes
  */
 #define TIMEOUT	(6 * HZ)
 
+/* This is used to disable usermodehelper invocations while
+ * freeze_processes() is being executed
+ */
+DEFINE_MUTEX(freezer_lock);
+int freezing_processes;
+atomic_t usermodehelper_waiting = ATOMIC_INIT(0);
 
 static inline int freezeable(struct task_struct * p)
 {
@@ -54,48 +62,93 @@ void refrigerator(void)
 	current->state = save;
 }
 
+static inline void freeze_process(struct task_struct *p)
+{
+	unsigned long flags;
+
+	freeze(p);
+	spin_lock_irqsave(&p->sighand->siglock, flags);
+	signal_wake_up(p, 0);
+	spin_unlock_irqrestore(&p->sighand->siglock, flags);
+}
+
 /* 0 = success, else # of processes that we failed to stop */
 int freeze_processes(void)
 {
-	int todo;
+	int todo, nr_user, user_frozen;
 	unsigned long start_time;
 	struct task_struct *g, *p;
 	unsigned long flags;
 
+	start_time = jiffies;
+	mutex_lock(&freezer_lock);
+	freezing_processes = 1;
+	mutex_unlock(&freezer_lock);
+	while (atomic_read(&usermodehelper_waiting)) {
+		if (time_after(jiffies, start_time + TIMEOUT)) {
+			printk(KERN_ERR "Unable to freeze tasks because of "
+				"active user mode helpers\n");
+			return -EBUSY;
+		}
+		schedule();
+	}
+
 	printk( "Stopping tasks: " );
 	start_time = jiffies;
+	user_frozen = 0;
 	do {
-		todo = 0;
+		nr_user = todo = 0;
 		read_lock(&tasklist_lock);
 		do_each_thread(g, p) {
 			if (!freezeable(p))
 				continue;
 			if (frozen(p))
 				continue;
-
-			freeze(p);
-			spin_lock_irqsave(&p->sighand->siglock, flags);
-			signal_wake_up(p, 0);
-			spin_unlock_irqrestore(&p->sighand->siglock, flags);
-			todo++;
+			if (p->mm && !(p->flags & PF_BORROWED_MM)) {
+				/* The task is a user-space one.
+				 * Freeze it unless there's a vfork completion
+				 * pending
+				 */
+				if (!p->vfork_done)
+					freeze_process(p);
+				nr_user++;
+			} else {
+				/* Freeze only if the user space is frozen */
+				if (user_frozen)
+					freeze_process(p);
+				todo++;
+			}
 		} while_each_thread(g, p);
 		read_unlock(&tasklist_lock);
+		todo += nr_user;
+		if (!user_frozen && !nr_user) {
+			sys_sync();
+			start_time = jiffies;
+		}
+		user_frozen = !nr_user;
 		yield();			/* Yield is okay here */
-		if (todo && time_after(jiffies, start_time + TIMEOUT)) {
-			printk( "\n" );
-			printk(KERN_ERR " stopping tasks timed out (%d tasks remaining)\n", todo );
+		if (todo && time_after(jiffies, start_time + TIMEOUT))
 			break;
-		}
 	} while(todo);
 
+	mutex_lock(&freezer_lock);
+	freezing_processes = 0;
+	mutex_unlock(&freezer_lock);
+
 	/* This does not unfreeze processes that are already frozen
 	 * (we have slightly ugly calling convention in that respect,
 	 * and caller must call thaw_processes() if something fails),
 	 * but it cleans up leftover PF_FREEZE requests.
 	 */
 	if (todo) {
+		printk( "\n" );
+		printk(KERN_ERR " stopping tasks timed out "
+			"after %d seconds (%d tasks remaining):\n",
+			TIMEOUT / HZ, todo);
 		read_lock(&tasklist_lock);
-		do_each_thread(g, p)
+		do_each_thread(g, p) {
+			if (freezeable(p) && !frozen(p))
+				printk(KERN_ERR "  %s\n", p->comm);
 			if (freezing(p)) {
 				pr_debug("  clean up: %s\n", p->comm);
 				p->flags &= ~PF_FREEZE;
@@ -103,7 +156,7 @@ int freeze_processes(void)
 				recalc_sigpending_tsk(p);
 				spin_unlock_irqrestore(&p->sighand->siglock, flags);
 			}
-		while_each_thread(g, p);
+		} while_each_thread(g, p);
 		read_unlock(&tasklist_lock);
 		return todo;
 	}
Index: linux-2.6.16-rc1-mm4/kernel/kmod.c
===================================================================
--- linux-2.6.16-rc1-mm4.orig/kernel/kmod.c
+++ linux-2.6.16-rc1-mm4/kernel/kmod.c
@@ -36,6 +36,8 @@
 #include <linux/mount.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/suspend.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 
 extern int max_threads;
@@ -249,11 +251,28 @@ int call_usermodehelper_keys(char *path,
 	if (!khelper_wq)
 		return -EBUSY;
 
+#ifdef CONFIG_PM
+	mutex_lock(&freezer_lock);
+	if (freezing_processes) {
+		mutex_unlock(&freezer_lock);
+		return -EBUSY;
+	}
+	if (wait)
+		atomic_inc(&usermodehelper_waiting);
+	mutex_unlock(&freezer_lock);
+#endif
+
 	if (path[0] == '\0')
 		return 0;
 
 	queue_work(khelper_wq, &work);
 	wait_for_completion(&done);
+
+#ifdef CONFIG_PM
+	if (wait)
+		atomic_dec(&usermodehelper_waiting);
+#endif
+
 	return sub_info.retval;
 }
 EXPORT_SYMBOL(call_usermodehelper_keys);
Index: linux-2.6.16-rc1-mm4/include/linux/suspend.h
===================================================================
--- linux-2.6.16-rc1-mm4.orig/include/linux/suspend.h
+++ linux-2.6.16-rc1-mm4/include/linux/suspend.h
@@ -9,6 +9,7 @@
 #include <linux/config.h>
 #include <linux/init.h>
 #include <linux/pm.h>
+#include <asm/atomic.h>
 
 /* page backup entry */
 typedef struct pbe {
@@ -40,6 +41,11 @@ extern void drain_local_pages(void);
 extern void mark_free_pages(struct zone *zone);
 
 #ifdef CONFIG_PM
+struct mutex;
+extern struct mutex freezer_lock;
+extern int freezing_processes;
+extern atomic_t usermodehelper_waiting;
+
 /* kernel/power/swsusp.c */
 extern int software_suspend(void);
 
Index: linux-2.6.16-rc1-mm4/kernel/power/disk.c
===================================================================
--- linux-2.6.16-rc1-mm4.orig/kernel/power/disk.c
+++ linux-2.6.16-rc1-mm4/kernel/power/disk.c
@@ -73,7 +73,6 @@ static int prepare_processes(void)
 	int error;
 
 	pm_prepare_console();
-	sys_sync();
 	disable_nonboot_cpus();
 
 	if (freeze_processes()) {
Index: linux-2.6.16-rc1-mm4/kernel/power/user.c
===================================================================
--- linux-2.6.16-rc1-mm4.orig/kernel/power/user.c
+++ linux-2.6.16-rc1-mm4/kernel/power/user.c
@@ -137,7 +137,6 @@ static int snapshot_ioctl(struct inode *
 	case SNAPSHOT_FREEZE:
 		if (data->frozen)
 			break;
-		sys_sync();
 		down(&pm_sem);
 		pm_prepare_console();
 		disable_nonboot_cpus();

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Re: [RFC][PATCH -mm][Experimental] swsusp: freeze userspace processes first
  2006-02-02 13:55         ` Rafael J. Wysocki
@ 2006-02-02 15:08           ` Pavel Machek
  2006-02-02 18:32             ` Rafael J. Wysocki
  0 siblings, 1 reply; 15+ messages in thread
From: Pavel Machek @ 2006-02-02 15:08 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: Nigel Cunningham, Linux PM

[-- Attachment #1: Type: text/plain, Size: 472 bytes --]

Hi!

> That requires a timeout in case we have a user mode helper in the D state.
> The corrected patch is appended.
> 
> BTW, it contains a change that may help solve the unfreezeable gcc problem
> that has appeared in your tests.  Could you please try it or tell me what I
> should do to reproduce the problem?

I'm away from real macine just now... I could reproduce it with
Nigel's "stress ..." command, then trying to build kernel.

								Pavel

-- 
Thanks, Sharp!

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Re: [RFC][PATCH -mm][Experimental] swsusp: freeze userspace processes first
  2006-02-02 15:08           ` Pavel Machek
@ 2006-02-02 18:32             ` Rafael J. Wysocki
  2006-02-04 21:26               ` Pavel Machek
  0 siblings, 1 reply; 15+ messages in thread
From: Rafael J. Wysocki @ 2006-02-02 18:32 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Nigel Cunningham, Linux PM

Hi,

On Thursday 02 February 2006 16:08, Pavel Machek wrote:
> > That requires a timeout in case we have a user mode helper in the D state.
> > The corrected patch is appended.
> > 
> > BTW, it contains a change that may help solve the unfreezeable gcc problem
> > that has appeared in your tests.  Could you please try it or tell me what I
> > should do to reproduce the problem?
> 
> I'm away from real macine just now... I could reproduce it with
> Nigel's "stress ..." command, then trying to build kernel.

OK, I did the following:
1) run "swapoff -a"
2) run kernel make on one vt,
3) run "stress -d 5 --hdd-bytes 100M -i 5 -c 5" on another vt,
4) run "for f in 1 2 3 4 5 6 7 8 9 10; do echo disk > /sys/power/state ; sleep 5; done" on the 3rd vt.

Appended is the version of the patch that has freezed processes in 10 attempts
out of 10 (please note the "if (!freezing(p))" in freeze_process() ;-)).

Still freezing the userspace processes may take more that 15 secs under such
a load on my box, so the timeout is set to 20 sec (probably overkill for any
sane real-life situation).

Greetings,
Rafael


Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>

 include/linux/suspend.h |    6 +++
 kernel/kmod.c           |   19 ++++++++++
 kernel/power/disk.c     |    1 
 kernel/power/process.c  |   85 +++++++++++++++++++++++++++++++++++++++---------
 kernel/power/user.c     |    1 
 5 files changed, 95 insertions(+), 17 deletions(-)

Index: linux-2.6.16-rc1-mm4/kernel/power/process.c
===================================================================
--- linux-2.6.16-rc1-mm4.orig/kernel/power/process.c
+++ linux-2.6.16-rc1-mm4/kernel/power/process.c
@@ -12,12 +12,20 @@
 #include <linux/interrupt.h>
 #include <linux/suspend.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/syscalls.h>
 
 /* 
  * Timeout for stopping processes
  */
-#define TIMEOUT	(6 * HZ)
+#define TIMEOUT	(20 * HZ)
 
+/* This is used to disable usermodehelper invocations while
+ * freeze_processes() is being executed
+ */
+DEFINE_MUTEX(freezer_lock);
+int freezing_processes;
+atomic_t usermodehelper_waiting = ATOMIC_INIT(0);
 
 static inline int freezeable(struct task_struct * p)
 {
@@ -54,48 +62,95 @@ void refrigerator(void)
 	current->state = save;
 }
 
+static inline void freeze_process(struct task_struct *p)
+{
+	unsigned long flags;
+
+	if (!freezing(p)) {
+		freeze(p);
+		spin_lock_irqsave(&p->sighand->siglock, flags);
+		signal_wake_up(p, 0);
+		spin_unlock_irqrestore(&p->sighand->siglock, flags);
+	}
+}
+
 /* 0 = success, else # of processes that we failed to stop */
 int freeze_processes(void)
 {
-	int todo;
+	int todo, nr_user, user_frozen;
 	unsigned long start_time;
 	struct task_struct *g, *p;
 	unsigned long flags;
 
+	start_time = jiffies;
+	mutex_lock(&freezer_lock);
+	freezing_processes = 1;
+	mutex_unlock(&freezer_lock);
+	while (atomic_read(&usermodehelper_waiting)) {
+		if (time_after(jiffies, start_time + TIMEOUT)) {
+			printk(KERN_ERR "Unable to freeze tasks because of "
+				"active user mode helpers\n");
+			return -EBUSY;
+		}
+		schedule();
+	}
+
 	printk( "Stopping tasks: " );
 	start_time = jiffies;
+	user_frozen = 0;
 	do {
-		todo = 0;
+		nr_user = todo = 0;
 		read_lock(&tasklist_lock);
 		do_each_thread(g, p) {
 			if (!freezeable(p))
 				continue;
 			if (frozen(p))
 				continue;
-
-			freeze(p);
-			spin_lock_irqsave(&p->sighand->siglock, flags);
-			signal_wake_up(p, 0);
-			spin_unlock_irqrestore(&p->sighand->siglock, flags);
-			todo++;
+			if (p->mm && !(p->flags & PF_BORROWED_MM)) {
+				/* The task is a user-space one.
+				 * Freeze it unless there's a vfork completion
+				 * pending
+				 */
+				if (!p->vfork_done)
+					freeze_process(p);
+				nr_user++;
+			} else {
+				/* Freeze only if the user space is frozen */
+				if (user_frozen)
+					freeze_process(p);
+				todo++;
+			}
 		} while_each_thread(g, p);
 		read_unlock(&tasklist_lock);
+		todo += nr_user;
+		if (!user_frozen && !nr_user) {
+			sys_sync();
+			start_time = jiffies;
+		}
+		user_frozen = !nr_user;
 		yield();			/* Yield is okay here */
-		if (todo && time_after(jiffies, start_time + TIMEOUT)) {
-			printk( "\n" );
-			printk(KERN_ERR " stopping tasks timed out (%d tasks remaining)\n", todo );
+		if (todo && time_after(jiffies, start_time + TIMEOUT))
 			break;
-		}
 	} while(todo);
 
+	mutex_lock(&freezer_lock);
+	freezing_processes = 0;
+	mutex_unlock(&freezer_lock);
+
 	/* This does not unfreeze processes that are already frozen
 	 * (we have slightly ugly calling convention in that respect,
 	 * and caller must call thaw_processes() if something fails),
 	 * but it cleans up leftover PF_FREEZE requests.
 	 */
 	if (todo) {
+		printk( "\n" );
+		printk(KERN_ERR " stopping tasks timed out "
+			"after %d seconds (%d tasks remaining):\n",
+			TIMEOUT / HZ, todo);
 		read_lock(&tasklist_lock);
-		do_each_thread(g, p)
+		do_each_thread(g, p) {
+			if (freezeable(p) && !frozen(p))
+				printk(KERN_ERR "  %s\n", p->comm);
 			if (freezing(p)) {
 				pr_debug("  clean up: %s\n", p->comm);
 				p->flags &= ~PF_FREEZE;
@@ -103,7 +158,7 @@ int freeze_processes(void)
 				recalc_sigpending_tsk(p);
 				spin_unlock_irqrestore(&p->sighand->siglock, flags);
 			}
-		while_each_thread(g, p);
+		} while_each_thread(g, p);
 		read_unlock(&tasklist_lock);
 		return todo;
 	}
Index: linux-2.6.16-rc1-mm4/kernel/kmod.c
===================================================================
--- linux-2.6.16-rc1-mm4.orig/kernel/kmod.c
+++ linux-2.6.16-rc1-mm4/kernel/kmod.c
@@ -36,6 +36,8 @@
 #include <linux/mount.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/suspend.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 
 extern int max_threads;
@@ -249,11 +251,28 @@ int call_usermodehelper_keys(char *path,
 	if (!khelper_wq)
 		return -EBUSY;
 
+#ifdef CONFIG_PM
+	mutex_lock(&freezer_lock);
+	if (freezing_processes) {
+		mutex_unlock(&freezer_lock);
+		return -EBUSY;
+	}
+	if (wait)
+		atomic_inc(&usermodehelper_waiting);
+	mutex_unlock(&freezer_lock);
+#endif
+
 	if (path[0] == '\0')
 		return 0;
 
 	queue_work(khelper_wq, &work);
 	wait_for_completion(&done);
+
+#ifdef CONFIG_PM
+	if (wait)
+		atomic_dec(&usermodehelper_waiting);
+#endif
+
 	return sub_info.retval;
 }
 EXPORT_SYMBOL(call_usermodehelper_keys);
Index: linux-2.6.16-rc1-mm4/include/linux/suspend.h
===================================================================
--- linux-2.6.16-rc1-mm4.orig/include/linux/suspend.h
+++ linux-2.6.16-rc1-mm4/include/linux/suspend.h
@@ -9,6 +9,7 @@
 #include <linux/config.h>
 #include <linux/init.h>
 #include <linux/pm.h>
+#include <asm/atomic.h>
 
 /* page backup entry */
 typedef struct pbe {
@@ -40,6 +41,11 @@ extern void drain_local_pages(void);
 extern void mark_free_pages(struct zone *zone);
 
 #ifdef CONFIG_PM
+struct mutex;
+extern struct mutex freezer_lock;
+extern int freezing_processes;
+extern atomic_t usermodehelper_waiting;
+
 /* kernel/power/swsusp.c */
 extern int software_suspend(void);
 
Index: linux-2.6.16-rc1-mm4/kernel/power/disk.c
===================================================================
--- linux-2.6.16-rc1-mm4.orig/kernel/power/disk.c
+++ linux-2.6.16-rc1-mm4/kernel/power/disk.c
@@ -73,7 +73,6 @@ static int prepare_processes(void)
 	int error;
 
 	pm_prepare_console();
-	sys_sync();
 	disable_nonboot_cpus();
 
 	if (freeze_processes()) {
Index: linux-2.6.16-rc1-mm4/kernel/power/user.c
===================================================================
--- linux-2.6.16-rc1-mm4.orig/kernel/power/user.c
+++ linux-2.6.16-rc1-mm4/kernel/power/user.c
@@ -137,7 +137,6 @@ static int snapshot_ioctl(struct inode *
 	case SNAPSHOT_FREEZE:
 		if (data->frozen)
 			break;
-		sys_sync();
 		down(&pm_sem);
 		pm_prepare_console();
 		disable_nonboot_cpus();

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Re: [RFC][PATCH -mm][Experimental] swsusp: freeze userspace processes first
  2006-02-02 18:32             ` Rafael J. Wysocki
@ 2006-02-04 21:26               ` Pavel Machek
  2006-02-04 21:47                 ` Rafael J. Wysocki
  0 siblings, 1 reply; 15+ messages in thread
From: Pavel Machek @ 2006-02-04 21:26 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: Nigel Cunningham, Linux PM

[-- Attachment #1: Type: text/plain, Size: 1265 bytes --]

Hi!

> > > That requires a timeout in case we have a user mode helper in the D state.
> > > The corrected patch is appended.
> > > 
> > > BTW, it contains a change that may help solve the unfreezeable gcc problem
> > > that has appeared in your tests.  Could you please try it or tell me what I
> > > should do to reproduce the problem?
> > 
> > I'm away from real macine just now... I could reproduce it with
> > Nigel's "stress ..." command, then trying to build kernel.
> 
> OK, I did the following:
> 1) run "swapoff -a"
> 2) run kernel make on one vt,
> 3) run "stress -d 5 --hdd-bytes 100M -i 5 -c 5" on another vt,
> 4) run "for f in 1 2 3 4 5 6 7 8 9 10; do echo disk > /sys/power/state ; sleep 5; done" on the 3rd vt.
> 
> Appended is the version of the patch that has freezed processes in 10 attempts
> out of 10 (please note the "if (!freezing(p))" in freeze_process() ;-)).
> 
> Still freezing the userspace processes may take more that 15 secs under such
> a load on my box, so the timeout is set to 20 sec (probably overkill for any
> sane real-life situation).

You have my ACK on freezer parts, but please reserve usermode helper
parts for separate patch. Is there simple way to demonstrate usermode
helper problem?
								Pavel
-- 
Thanks, Sharp!

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Re: [RFC][PATCH -mm][Experimental] swsusp: freeze userspace processes first
  2006-02-04 21:26               ` Pavel Machek
@ 2006-02-04 21:47                 ` Rafael J. Wysocki
  0 siblings, 0 replies; 15+ messages in thread
From: Rafael J. Wysocki @ 2006-02-04 21:47 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Nigel Cunningham, Linux PM

Hi,

On Saturday 04 February 2006 22:26, Pavel Machek wrote:
> > > > That requires a timeout in case we have a user mode helper in the D state.
> > > > The corrected patch is appended.
> > > > 
> > > > BTW, it contains a change that may help solve the unfreezeable gcc problem
> > > > that has appeared in your tests.  Could you please try it or tell me what I
> > > > should do to reproduce the problem?
> > > 
> > > I'm away from real macine just now... I could reproduce it with
> > > Nigel's "stress ..." command, then trying to build kernel.
> > 
> > OK, I did the following:
> > 1) run "swapoff -a"
> > 2) run kernel make on one vt,
> > 3) run "stress -d 5 --hdd-bytes 100M -i 5 -c 5" on another vt,
> > 4) run "for f in 1 2 3 4 5 6 7 8 9 10; do echo disk > /sys/power/state ; sleep 5; done" on the 3rd vt.
> > 
> > Appended is the version of the patch that has freezed processes in 10 attempts
> > out of 10 (please note the "if (!freezing(p))" in freeze_process() ;-)).
> > 
> > Still freezing the userspace processes may take more that 15 secs under such
> > a load on my box, so the timeout is set to 20 sec (probably overkill for any
> > sane real-life situation).
> 
> You have my ACK on freezer parts, but please reserve usermode helper
> parts for separate patch.

OK, I'll remove the usermodehelper-related part for now.  If we have a test
case, I'll think of it again.

> Is there simple way to demonstrate usermode helper problem?

Not that I know of.  Probably I am overly paranoid wrt that.

Greetings,
Rafael

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2006-02-04 21:47 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-02-01  0:41 [RFC][PATCH -mm][Experimental] swsusp: freeze userspace processes first Rafael J. Wysocki
2006-02-01 10:55 ` Pavel Machek
2006-02-01 11:18   ` Nigel Cunningham
2006-02-01 20:13   ` Rafael J. Wysocki
2006-02-01 11:47 ` Pavel Machek
2006-02-01 12:24   ` Nigel Cunningham
2006-02-01 12:49     ` Pavel Machek
2006-02-01 21:41       ` Nigel Cunningham
2006-02-01 23:57       ` Rafael J. Wysocki
2006-02-02 13:55         ` Rafael J. Wysocki
2006-02-02 15:08           ` Pavel Machek
2006-02-02 18:32             ` Rafael J. Wysocki
2006-02-04 21:26               ` Pavel Machek
2006-02-04 21:47                 ` Rafael J. Wysocki
2006-02-01 22:19   ` Rafael J. Wysocki

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox