[prev in list] [next in list] [prev in thread] [next in thread] 

List:       linux-kernel
Subject:    swsusp: fix realtime processes, work around random memory corruption with DMA, do not trigger oom-ki
From:       Pavel Machek <pavel () suse ! cz>
Date:       2001-09-30 19:23:31
[Download RAW message or body]

Hi!

Yep, it fixes all of above.

Most "interesting" is stuff that prevents usb controller from
scribling over memory. cli() and msleep(1000) should do the trick ;-).

Also you can now trigger it by echo 4 > /proc/acpi/sleep. Usefull for
testing.

							Pavel
PS: (Patch is relative to my 2.4.10 port, which I mailed just about
everywhere.)



--- /elf/big/2.4.10-swsusp.2/drivers/acpi/ospm/system/sm_osl.c	Sun Sep 23 23:05:21 2001
+++ linux-swsusp/drivers/acpi/ospm/system/sm_osl.c	Sun Sep 30 12:04:00 2001
@@ -140,7 +140,10 @@
 	if (system->states[value] != TRUE)
 		return -EINVAL;
 	
-	sm_osl_suspend(value);
+	if (value != ACPI_S4)
+		sm_osl_suspend(value);
+	else
+		software_suspend();
 	
 	return (count);
 }
@@ -685,6 +688,9 @@
 	 */
 	if (state == ACPI_S2 || state == ACPI_S3) {
 #ifdef DONT_USE_UNTIL_LOWLEVEL_CODE_EXISTS
+		/* That && trick is *not going to work*. Read gcc
+		   specs. That explicitely says: jumping from other
+		   function is *not allowed*. */ 
 		wakeup_address = acpi_save_state_mem((unsigned long)&&acpi_sleep_done);
 
 		if (!wakeup_address) goto acpi_sleep_done;
@@ -692,11 +698,12 @@
 		acpi_set_firmware_waking_vector(
 			(ACPI_PHYSICAL_ADDRESS)wakeup_address);
 #endif
-	} else if (state == ACPI_S4)
+	} else if (state == ACPI_S4) {
 #ifdef DONT_USE_UNTIL_LOWLEVEL_CODE_EXISTS
 		if (acpi_save_state_disk((unsigned long)&&acpi_sleep_done)) 
-			goto acpi_sleep_done;
+			goto acpi_sleep_done
 #endif
+	}
 
 	/* set status, since acpi_enter_sleep_state won't return unless something
 	 * goes wrong, or it's just S1.
diff -urN -x .dep* -x .hdep* -x *.[oas] -x *~ -x #* -x *CVS* -x *.orig -x *.rej -x *.old -x .menu* -x asm \
-x local.h -x System.map -x autoconf.h -x compile.h -x version.h -x .version -x defkeymap.c -x \
uni_hash.tbl -x zImage -x vmlinux -x vmlinuz -x TAGS -x bootsect -x *RCS* -x conmakehash -x map -x build \
-x build -x configure -x *target* -x *.flags -x *.bak /elf/big/2.4.10-swsusp.2/kernel/swsusp.c \
                linux-swsusp/kernel/swsusp.c
--- /elf/big/2.4.10-swsusp.2/kernel/swsusp.c	Sat Sep 29 10:34:23 2001
+++ linux-swsusp/kernel/swsusp.c	Sun Sep 30 21:04:02 2001
@@ -222,6 +222,12 @@
 /* Refrigerator is place where frozen processes are stored :-). */
 void refrigerator(void)
 {
+#define CORRECT
+	/* You need correct to work with real-time processes.
+	   OTOH, this way one process may see (via /proc/) some other
+	   process in stopped state (and thereby discovered we were
+	   suspended. We probably do not care. 
+	 */
 #ifdef CORRECT
 	long save;
 	save = current->state;
@@ -708,7 +714,7 @@
 	void **c= eaten_memory, *m;
 
 	printk("Eating pages ");
-	while ((m = (void *) get_free_page(GFP_HIGHMEM))) {
+	while ((m = (void *) get_free_page(GFP_HIGHUSER))) {
 		memset(m, 0, PAGE_SIZE);
 		eaten_memory = m;
 		if (!(i%5000))
@@ -749,6 +755,10 @@
 	pages = shrink_mem();
 	PRINTS( "Freed pages: %u\n", pages );
 #endif
+#if 1
+	eat_memory();
+	free_memory();
+#endif
 	/* No need to invalidate any vfsmnt list -- they will be valid after resume, anyway.
 	 *
 	 * We sync here -- so you have consistent filesystem state when things go wrong.
@@ -942,8 +952,13 @@
 #ifdef CONFIG_SMP_DISABLED
 	prepare_suspend_smp ();
 #endif
-	eat_memory();
-	free_memory();
+
+#if 0
+	printk("Freeing memory: ");
+	while (try_to_free_pages(&contig_page_data.node_zones[ZONE_HIGHMEM], GFP_KSWAPD, 0))
+		printk(".");
+	printk("\n");
+#endif
 
 	spin_lock(&suspend_lock);
 	PRINTP( "Test local var: %08lx\n", local_var);
@@ -977,6 +992,11 @@
 	/* Critical section here: noone should touch memory from now */
 	spin_lock_irq(&suspend_pagedir_lock);	/* Done to disable interrupts */ 
 
+	printk( "Waiting for disks to settle down...\n");
+	mdelay(1000);	/* We do not want some readahead with DMA to corrupt our memory, right?
+			   Do it with disabled interrupts for best effect. That way, if some
+			   driver scheduled DMA, we have good chance for DMA to finish ;-). */
+
 	/* This works, because loop and loop2 are nosavedata */
 	for (loop=0; loop < nr_copy_pages; loop++) {
 		/* You may not call something (like copy_page) here:
@@ -1399,8 +1419,6 @@
 	error = 0;
 
 resume_read_error:
-	printk("Error resuming\n");
-	mdelay(1000);
 	switch (error) {
 		case 0:
 			PRINTR("Reading resume file was successful\n");
@@ -1416,9 +1434,9 @@
 		default:
 			printk( "%sError %d resuming\n", name_resume, error );
 	}
+	mdelay(1000);
 	set_fs(orig_fs);
-	set_blocksize(dev, blksize);	/* FIXME: There's something very strange: even after successfull resume,
-					   old blocksize seems to be set. Ouch?! */
+	set_blocksize(dev, blksize);
 	MDELAY(1000);
 	if (different_kernel)
 		panic("Sorry Pavel... I like my filesystem too much.");

-- 
I'm pavel@ucw.cz. "In my country we have almost anarchy and I don't care."
Panos Katsaloulis describing me w.r.t. patents at discuss@linmodems.org
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic