public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* FYI: my current bigdiff
@ 2004-09-09 13:44 Pavel Machek
  2004-09-10  4:13 ` Kevin Fenzi
  2004-09-12  8:54 ` Stefan Schweizer
  0 siblings, 2 replies; 14+ messages in thread
From: Pavel Machek @ 2004-09-09 13:44 UTC (permalink / raw)
  To: kernel list

Hi!

This is my bigdiff. It is not for inclusion (I'll have to split it),
but it contains some usefull code (I believe :-).

Oh, it speeds up swsusp quite a lot.

								Pavel
-- 
When do you have heart between your knees?



--- clean-mm/Documentation/power/swsusp.txt	2004-08-24 09:01:50.000000000 +0200
+++ linux-mm/Documentation/power/swsusp.txt	2004-09-07 21:15:17.000000000 +0200
@@ -20,26 +20,6 @@
 You need to append resume=/dev/your_swap_partition to kernel command
 line. Then you suspend by echo 4 > /proc/acpi/sleep.
 
-Pavel's unreliable guide to swsusp mess
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-There are currently two versions of swap suspend in the kernel, the old
-"Pavel's" version in kernel/power/swsusp.c and the new "Patrick's"
-version in kernel/power/pmdisk.c. They provide the same functionality;
-the old version looks ugly but was tested, while the new version looks
-nicer but did not receive so much testing. echo 4 > /proc/acpi/sleep
-calls the old version, echo disk > /sys/power/state calls the new one.
-
-[In the future, when the new version is stable enough, two things can
-happen:
-
-* the new version is moved into swsusp.c, and swsusp is renamed to swap
-  suspend (Pavel prefers this)
-
-* pmdisk is kept as is and swsusp.c is removed from the kernel]
-
-
-
 Article about goals and implementation of Software Suspend for Linux
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Author: G‚ábor Kuti
@@ -75,10 +55,6 @@
 About the code
 
 Things to implement
-- SMP support. I've done an SMP support but since I don't have access to a kind
-  of this one I cannot test it. Please SMP people test it.  .. Tested it,
-  doesn't work. Had no time to figure out why. There is some mess with
-  interrupts AFAIK..
 - We should only make a copy of data related to kernel segment, since any
   process data won't be changed.
 - Should make more sanity checks. Or are these enough?
@@ -90,11 +66,6 @@
 - We should not free pages at the beginning so aggressively, most of them
   go there anyway..
 
-Drivers that need support
-- pc_keyb -- perhaps we can wait for vojtech's input patches
-- do IDE cdroms need some kind of support?
-- IDE CD-RW -- how to deal with that?
-
 Sleep states summary (thanx, Ducrot)
 ====================================
 
@@ -109,7 +80,8 @@
 echo 4b > /proc/acpi/sleep      # for suspend to disk via s4bios
 
 
-FAQ:
+Frequently Asked Questions
+==========================
 
 Q: well, suspending a server is IMHO a really stupid thing,
 but... (Diego Zuccato):
--- clean-mm/arch/i386/kernel/acpi/wakeup.S	2004-08-24 09:02:23.000000000 +0200
+++ linux-mm/arch/i386/kernel/acpi/wakeup.S	2004-09-07 21:15:17.000000000 +0200
@@ -11,8 +11,23 @@
 #
 # If physical address of wakeup_code is 0x12345, BIOS should call us with
 # cs = 0x1234, eip = 0x05
-# 
+#
 
+#define BEEP \
+	inb	$97, %al; 	\
+	outb	%al, $0x80; 	\
+	movb	$3, %al; 	\
+	outb	%al, $97; 	\
+	outb	%al, $0x80; 	\
+	movb	$-74, %al; 	\
+	outb	%al, $67; 	\
+	outb	%al, $0x80; 	\
+	movb	$-119, %al; 	\
+	outb	%al, $66; 	\
+	outb	%al, $0x80; 	\
+	movb	$15, %al; 	\
+	outb	%al, $66; 
+	
 ALIGN
 	.align	4096
 ENTRY(wakeup_start)
@@ -20,6 +35,7 @@
 	wakeup_code_start = .
 	.code16
 
+	BEEP
  	movw	$0xb800, %ax
 	movw	%ax,%fs
 	movw	$0x0e00 + 'L', %fs:(0x10)
--- clean-mm/arch/i386/power/swsusp.S	2004-09-07 21:12:20.000000000 +0200
+++ linux-mm/arch/i386/power/swsusp.S	2004-09-09 01:28:28.000000000 +0200
@@ -31,7 +31,7 @@
 	movl $swsusp_pg_dir-__PAGE_OFFSET,%ecx
 	movl %ecx,%cr3
 
-	movl	pagedir_nosave,%ebx
+	movl	pagedir_nosave, %ebx
 	xorl	%eax, %eax
 	xorl	%edx, %edx
 	.p2align 4,,7
--- clean-mm/drivers/acpi/fan.c	2004-08-24 09:01:53.000000000 +0200
+++ linux-mm/drivers/acpi/fan.c	2004-09-07 21:15:19.000000000 +0200
@@ -94,10 +94,10 @@
 		goto end;
 
 	if (acpi_bus_get_power(fan->handle, &state))
-		goto end;
-
-	p += sprintf(p, "status:                  %s\n",
-		!state?"on":"off");
+		p += sprintf(p, "status:                  ERROR\n");
+	else
+		p += sprintf(p, "status:                  %s\n",
+			     !state?"on":"off");
 
 end:
 	len = (p - page);
--- clean-mm/drivers/acpi/sleep/proc.c	2004-08-24 09:03:14.000000000 +0200
+++ linux-mm/drivers/acpi/sleep/proc.c	2004-09-07 21:15:19.000000000 +0200
@@ -57,7 +57,8 @@
 	int	error = 0;
 
 	if (count > sizeof(str) - 1)
-		goto Done;
+		return -EIO;
+
 	memset(str,0,sizeof(str));
 	if (copy_from_user(str, buffer, count))
 		return -EFAULT;
@@ -65,17 +66,16 @@
 	/* Check for S4 bios request */
 	if (!strcmp(str,"4b")) {
 		error = acpi_suspend(4);
-		goto Done;
+		return error ? error : count;
 	}
 	state = simple_strtoul(str, NULL, 0);
 #ifdef CONFIG_SOFTWARE_SUSPEND
 	if (state == 4) {
-		software_suspend();
-		goto Done;
+		error = software_suspend();
+		return error ? error : count;
 	}
 #endif
 	error = acpi_suspend(state);
- Done:
 	return error ? error : count;
 }
 
--- clean-mm/drivers/base/power/power.h	2004-08-24 09:01:51.000000000 +0200
+++ linux-mm/drivers/base/power/power.h	2004-09-07 21:15:19.000000000 +0200
@@ -1,5 +1,4 @@
-
-
+/* FIXME: This needs explanation... */
 enum {
 	DEVICE_PM_ON,
 	DEVICE_PM1,
--- clean-mm/drivers/char/keyboard.c	2004-09-07 21:12:22.000000000 +0200
+++ linux-mm/drivers/char/keyboard.c	2004-09-07 21:15:19.000000000 +0200
@@ -1076,6 +1076,23 @@
 		sysrq_down = down;
 		return;
 	}
+	if (test_bit(KEY_LEFTALT, key_down) &&
+	    test_bit(KEY_RIGHTALT, key_down) &&
+	    test_bit(KEY_LEFTSHIFT, key_down) &&
+	    test_bit(KEY_RIGHTSHIFT, key_down) &&
+		down && !rep) {
+		handle_sysrq(kbd_sysrq_xlate[keycode], regs, tty);
+#ifdef CONFIG_KGDB_SYSRQ
+                sysrq_down = 0;        /* in case we miss the "up" event */
+#endif
+		return;
+	}
+
+	if (down)
+		set_bit(keycode, key_down);
+	else
+		clear_bit(keycode, key_down);
+
 	if (sysrq_down && down && !rep) {
 		handle_sysrq(kbd_sysrq_xlate[keycode], regs, tty);
 #ifdef CONFIG_KGDB_SYSRQ
@@ -1111,11 +1128,6 @@
 		raw_mode = 1;
 	}
 
-	if (down)
-		set_bit(keycode, key_down);
-	else
-		clear_bit(keycode, key_down);
-
 	if (rep && (!vc_kbd_mode(kbd, VC_REPEAT) || (tty && 
 		(!L_ECHO(tty) && tty->driver->chars_in_buffer(tty))))) {
 		/*
--- clean-mm/drivers/video/aty/radeon_pm.c	2004-08-24 09:03:18.000000000 +0200
+++ linux-mm/drivers/video/aty/radeon_pm.c	2004-09-07 21:15:20.000000000 +0200
@@ -871,7 +871,8 @@
 	agp_enable(0);
 #endif
 
-	fb_set_suspend(info, 1);
+	if (system_state != SYSTEM_SNAPSHOT)
+		fb_set_suspend(info, 1);
 
 	if (!(info->flags & FBINFO_HWACCEL_DISABLED)) {
 		/* Make sure engine is reset */
@@ -880,12 +881,14 @@
 		radeon_engine_idle();
 	}
 
-	/* Blank display and LCD */
-	radeonfb_blank(VESA_POWERDOWN, info);
-
-	/* Sleep */
-	rinfo->asleep = 1;
-	rinfo->lock_blank = 1;
+	if (system_state != SYSTEM_SNAPSHOT) {
+		/* Blank display and LCD */
+		radeonfb_blank(VESA_POWERDOWN, info);
+
+		/* Sleep */
+		rinfo->asleep = 1;
+		rinfo->lock_blank = 1;
+	}
 
 	/* Suspend the chip to D2 state when supported
 	 */
--- clean-mm/fs/bio.c	2004-09-07 21:12:30.000000000 +0200
+++ linux-mm/fs/bio.c	2004-09-07 21:15:20.000000000 +0200
@@ -143,7 +143,7 @@
 
 	bio = mempool_alloc(bio_pool, gfp_mask);
 	if (unlikely(!bio))
-		goto out;
+		return NULL;
 
 	bio_init(bio);
 
@@ -157,13 +157,11 @@
 noiovec:
 		bio->bi_io_vec = bvl;
 		bio->bi_destructor = bio_destructor;
-out:
 		return bio;
 	}
 
 	mempool_free(bio, bio_pool);
-	bio = NULL;
-	goto out;
+	return NULL;
 }
 
 /**
--- clean-mm/include/linux/page-flags.h	2004-09-07 21:12:33.000000000 +0200
+++ linux-mm/include/linux/page-flags.h	2004-09-07 21:15:21.000000000 +0200
@@ -75,7 +75,7 @@
 #define PG_swapcache		16	/* Swap page: swp_entry_t in private */
 #define PG_mappedtodisk		17	/* Has blocks allocated on-disk */
 #define PG_reclaim		18	/* To be reclaimed asap */
-
+#define PG_nosave_free		19	/* Page is free and should not be written */
 
 /*
  * Global page accounting.  One instance per CPU.  Only unsigned longs are
@@ -278,6 +278,10 @@
 #define ClearPageNosave(page)		clear_bit(PG_nosave, &(page)->flags)
 #define TestClearPageNosave(page)	test_and_clear_bit(PG_nosave, &(page)->flags)
 
+#define PageNosaveFree(page)	test_bit(PG_nosave_free, &(page)->flags)
+#define SetPageNosaveFree(page)	set_bit(PG_nosave_free, &(page)->flags)
+#define ClearPageNosaveFree(page)		clear_bit(PG_nosave_free, &(page)->flags)
+
 #define PageMappedToDisk(page)	test_bit(PG_mappedtodisk, &(page)->flags)
 #define SetPageMappedToDisk(page) set_bit(PG_mappedtodisk, &(page)->flags)
 #define ClearPageMappedToDisk(page) clear_bit(PG_mappedtodisk, &(page)->flags)
--- clean-mm/include/linux/suspend.h	2004-09-07 21:12:33.000000000 +0200
+++ linux-mm/include/linux/suspend.h	2004-09-07 21:15:22.000000000 +0200
@@ -31,6 +31,7 @@
 
 /* mm/page_alloc.c */
 extern void drain_local_pages(void);
+extern void mark_free_pages(struct zone *zone);
 
 /* kernel/power/swsusp.c */
 extern int software_suspend(void);
--- clean-mm/kernel/power/disk.c	2004-09-07 21:12:33.000000000 +0200
+++ linux-mm/kernel/power/disk.c	2004-09-08 22:47:41.000000000 +0200
@@ -71,7 +71,7 @@
 	machine_halt();
 	/* Valid image is on the disk, if we continue we risk serious data corruption
 	   after resume. */
-	printk("Please power me down manually\n");
+	printk(KERN_CRIT "Please power me down manually\n");
 	while(1);
 	return 0;
 }
@@ -91,10 +91,20 @@
 
 static void free_some_memory(void)
 {
-	printk("Freeing memory: ");
-	while (shrink_all_memory(10000))
-		printk(".");
-	printk("|\n");
+	unsigned int i = 0;
+	unsigned int tmp;
+	unsigned long pages = 0;
+	char *p = "-\\|/";
+	
+	printk("Freeing memory...  ");
+	while ((tmp = shrink_all_memory(10000))) {
+		pages += tmp;
+		printk("\b%c", p[i]);
+		i++;
+		if (i > 3)
+			i = 0;
+	}
+	printk("\bdone (%li pages freed)\n", pages);
 }
 
 
@@ -167,6 +177,7 @@
 {
 	int error;
 
+	system_state = SYSTEM_SNAPSHOT;
 	if ((error = prepare()))
 		return error;
 
--- clean-mm/kernel/power/swsusp.c	2004-09-07 21:12:33.000000000 +0200
+++ linux-mm/kernel/power/swsusp.c	2004-09-09 08:56:20.000000000 +0200
@@ -74,11 +74,9 @@
 /* References to section boundaries */
 extern char __nosave_begin, __nosave_end;
 
-extern int is_head_of_free_region(struct page *);
-
 /* Variables to be preserved over suspend */
-int pagedir_order_check;
-int nr_copy_pages_check;
+static int pagedir_order_check;
+static int nr_copy_pages_check;
 
 extern char resume_file[];
 static dev_t resume_device;
@@ -99,8 +97,8 @@
    MMU hardware.
  */
 suspend_pagedir_t *pagedir_nosave __nosavedata = NULL;
-suspend_pagedir_t *pagedir_save;
-int pagedir_order __nosavedata = 0;
+static suspend_pagedir_t *pagedir_save;
+static int pagedir_order __nosavedata = 0;
 
 #define SWSUSP_SIG	"S1SUSPEND"
 
@@ -119,9 +117,6 @@
  */
 #define PAGES_FOR_IO	512
 
-static const char name_suspend[] = "Suspend Machine: ";
-static const char name_resume[] = "Resume Machine: ";
-
 /*
  * Saving part...
  */
@@ -141,10 +136,10 @@
 	rw_swap_page_sync(READ, 
 			  swp_entry(root_swap, 0),
 			  virt_to_page((unsigned long)&swsusp_header));
-	if (!memcmp("SWAP-SPACE",swsusp_header.sig,10) ||
-	    !memcmp("SWAPSPACE2",swsusp_header.sig,10)) {
-		memcpy(swsusp_header.orig_sig,swsusp_header.sig,10);
-		memcpy(swsusp_header.sig,SWSUSP_SIG,10);
+	if (!memcmp("SWAP-SPACE",swsusp_header.sig, 10) ||
+	    !memcmp("SWAPSPACE2",swsusp_header.sig, 10)) {
+		memcpy(swsusp_header.orig_sig,swsusp_header.sig, 10);
+		memcpy(swsusp_header.sig,SWSUSP_SIG, 10);
 		swsusp_header.swsusp_info = prev;
 		error = rw_swap_page_sync(WRITE, 
 					  swp_entry(root_swap, 0),
@@ -265,9 +260,10 @@
 
 
 /**
- *	free_data - Free the swap entries used by the saved image.
+ *	data_free - Free the swap entries used by the saved image.
  *
  *	Walk the list of used swap entries and free each one. 
+ *	This is only used for cleanup when suspend fails.
  */
 
 static void data_free(void)
@@ -287,7 +283,7 @@
 
 
 /**
- *	write_data - Write saved image to swap.
+ *	data_write - Write saved image to swap.
  *
  *	Walk the list of pages in the image and sync each one to swap.
  */
@@ -296,15 +292,19 @@
 {
 	int error = 0;
 	int i;
-
-	printk( "Writing data to swap (%d pages): ", nr_copy_pages );
+	unsigned int mod = nr_copy_pages / 100;
+	
+	if (!mod)
+		mod = 1;
+	
+	printk( "Writing data to swap (%d pages)...     ", nr_copy_pages );
 	for (i = 0; i < nr_copy_pages && !error; i++) {
-		if (!(i%100))
-			printk( "." );
+		if (!(i%mod))
+			printk( "\b\b\b\b%3d%%", i / mod );
 		error = write_page((pagedir_nosave+i)->address,
 					  &((pagedir_nosave+i)->swap_address));
 	}
-	printk(" %d Pages done.\n",i);
+	printk("\b\b\b\bdone\n");
 	return error;
 }
 
@@ -351,15 +351,16 @@
 }
 
 /**
- *	free_pagedir - Free pages used by the page directory.
+ *	free_pagedir_entries - Free pages used by the page directory.
+ *
+ *	This is used during suspend for error recovery.
  */
 
 static void free_pagedir_entries(void)
 {
-	int num = swsusp_info.pagedir_pages;
 	int i;
 
-	for (i = 0; i < num; i++)
+	for (i = 0; i < swsusp_info.pagedir_pages; i++)
 		swap_free(swsusp_info.pagedir[i]);
 }
 
@@ -379,7 +380,7 @@
 	swsusp_info.pagedir_pages = n;
 	printk( "Writing pagedir (%d pages)\n", n);
 	for (i = 0; i < n && !error; i++, addr += PAGE_SIZE)
-		error = write_page(addr,&swsusp_info.pagedir[i]);
+		error = write_page(addr, &swsusp_info.pagedir[i]);
 	return error;
 }
 
@@ -423,12 +424,12 @@
 static int save_highmem_zone(struct zone *zone)
 {
 	unsigned long zone_pfn;
+	mark_free_pages(zone);
 	for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) {
 		struct page *page;
 		struct highmem_page *save;
 		void *kaddr;
 		unsigned long pfn = zone_pfn + zone->zone_start_pfn;
-		int chunk_size;
 
 		if (!(pfn%1000))
 			printk(".");
@@ -445,11 +446,8 @@
 			printk("highmem reserved page?!\n");
 			continue;
 		}
-		if ((chunk_size = is_head_of_free_region(page))) {
-			pfn += chunk_size - 1;
-			zone_pfn += chunk_size - 1;
+		if (PageNosaveFree(page))
 			continue;
-		}
 		save = kmalloc(sizeof(struct highmem_page), GFP_ATOMIC);
 		if (!save)
 			return -ENOMEM;
@@ -528,14 +526,11 @@
 static int saveable(struct zone * zone, unsigned long * zone_pfn)
 {
 	unsigned long pfn = *zone_pfn + zone->zone_start_pfn;
-	unsigned long chunk_size;
 	struct page * page;
 
 	if (!pfn_valid(pfn))
 		return 0;
 
-	if (!(pfn%1000))
-		printk(".");
 	page = pfn_to_page(pfn);
 	BUG_ON(PageReserved(page) && PageNosave(page));
 	if (PageNosave(page))
@@ -544,10 +539,8 @@
 		pr_debug("[nosave pfn 0x%lx]", pfn);
 		return 0;
 	}
-	if ((chunk_size = is_head_of_free_region(page))) {
-		*zone_pfn += chunk_size - 1;
+	if (PageNosaveFree(page))
 		return 0;
-	}
 
 	return 1;
 }
@@ -561,6 +554,7 @@
 
 	for_each_zone(zone) {
 		if (!is_highmem(zone)) {
+			mark_free_pages(zone);
 			for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn)
 				nr_copy_pages += saveable(zone, &zone_pfn);
 		}
@@ -575,50 +569,20 @@
 	struct pbe * pbe = pagedir_nosave;
 	
 	for_each_zone(zone) {
-		if (!is_highmem(zone))
-			for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) {
-				if (saveable(zone, &zone_pfn)) {
-					struct page * page;
-					page = pfn_to_page(zone_pfn + zone->zone_start_pfn);
-					pbe->orig_address = (long) page_address(page);
-					/* copy_page is no usable for copying task structs. */
-					memcpy((void *)pbe->address, (void *)pbe->orig_address, PAGE_SIZE);
-					pbe++;
-				}
-			}
-	}
-}
-
-
-static void free_suspend_pagedir_zone(struct zone *zone, unsigned long pagedir)
-{
-	unsigned long zone_pfn, pagedir_end, pagedir_pfn, pagedir_end_pfn;
-	pagedir_end = pagedir + (PAGE_SIZE << pagedir_order);
-	pagedir_pfn = __pa(pagedir) >> PAGE_SHIFT;
-	pagedir_end_pfn = __pa(pagedir_end) >> PAGE_SHIFT;
-	for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) {
-		struct page *page;
-		unsigned long pfn = zone_pfn + zone->zone_start_pfn;
-		if (!pfn_valid(pfn))
-			continue;
-		page = pfn_to_page(pfn);
-		if (!TestClearPageNosave(page))
-			continue;
-		else if (pfn >= pagedir_pfn && pfn < pagedir_end_pfn)
+		if (is_highmem(zone))
 			continue;
-		__free_page(page);
-	}
-}
-
-void swsusp_free(void)
-{
-	unsigned long p = (unsigned long)pagedir_save;
-	struct zone *zone;
-	for_each_zone(zone) {
-		if (!is_highmem(zone))
-			free_suspend_pagedir_zone(zone, p);
+		mark_free_pages(zone);
+		for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) {
+			if (saveable(zone, &zone_pfn)) {
+				struct page * page;
+				page = pfn_to_page(zone_pfn + zone->zone_start_pfn);
+				pbe->orig_address = (long) page_address(page);
+				/* copy_page is not usable for copying task structs. */
+				memcpy((void *)pbe->address, (void *)pbe->orig_address, PAGE_SIZE);
+				pbe++;
+			}
+		}
 	}
-	free_pages(p, pagedir_order);
 }
 
 
@@ -668,8 +632,8 @@
 /**
  *	alloc_pagedir - Allocate the page directory.
  *
- *	First, determine exactly how many contiguous pages we need, 
- *	allocate them, then mark each 'unsavable'.
+ *	First, determine exactly how many contiguous pages we need and
+ *	allocate them.
  */
 
 static int alloc_pagedir(void)
@@ -684,6 +648,24 @@
 	return 0;
 }
 
+/**
+ *	free_image_pages - Free pages allocated for snapshot
+ */
+
+static void free_image_pages(void)
+{
+	struct pbe * p;
+	int i;
+
+	p = pagedir_save;
+	for (i = 0, p = pagedir_save; i < nr_copy_pages; i++, p++) {
+		if (p->address) {
+			ClearPageNosave(virt_to_page(p->address));
+			free_page(p->address);
+			p->address = 0;
+		}
+	}
+}
 
 /**
  *	alloc_image_pages - Allocate pages for the snapshot.
@@ -697,18 +679,19 @@
 
 	for (i = 0, p = pagedir_save; i < nr_copy_pages; i++, p++) {
 		p->address = get_zeroed_page(GFP_ATOMIC | __GFP_COLD);
-		if(!p->address)
-			goto Error;
+		if (!p->address)
+			return -ENOMEM;
 		SetPageNosave(virt_to_page(p->address));
 	}
 	return 0;
- Error:
-	do { 
-		if (p->address)
-			free_page(p->address);
-		p->address = 0;
-	} while (p-- > pagedir_save);
-	return -ENOMEM;
+}
+
+void swsusp_free(void)
+{
+	BUG_ON(PageNosave(virt_to_page(pagedir_save)));
+	BUG_ON(PageNosaveFree(virt_to_page(pagedir_save)));
+	free_image_pages();
+	free_pages((unsigned long) pagedir_save, pagedir_order);
 }
 
 
@@ -721,7 +704,7 @@
 
 static int enough_free_mem(void)
 {
-	if(nr_free_pages() < (nr_copy_pages + PAGES_FOR_IO)) {
+	if (nr_free_pages() < (nr_copy_pages + PAGES_FOR_IO)) {
 		pr_debug("swsusp: Not enough free pages: Have %d\n",
 			 nr_free_pages());
 		return 0;
@@ -757,7 +740,7 @@
 	int error;
 
 	pr_debug("suspend: (pages needed: %d + %d free: %d)\n",
-		 nr_copy_pages,PAGES_FOR_IO,nr_free_pages());
+		 nr_copy_pages, PAGES_FOR_IO, nr_free_pages());
 
 	pagedir_nosave = NULL;
 	if (!enough_free_mem())
@@ -788,7 +771,7 @@
 
 	pr_debug("swsusp: critical section: \n");
 	if (save_highmem()) {
-		printk(KERN_CRIT "%sNot enough free pages for highmem\n", name_suspend);
+		printk(KERN_CRIT "Suspend machine: Not enough free pages for highmem\n");
 		return -ENOMEM;
 	}
 
@@ -872,6 +855,7 @@
 	
 	/* Even mappings of "global" things (vmalloc) need to be fixed */
 	__flush_tlb_global();
+	wbinvd();	/* Nigel says wbinvd here is good idea... */
 	return 0;
 }
 
@@ -907,8 +891,8 @@
 	int i;
 	unsigned long addre = addr + (PAGE_SIZE<<order);
 	
-	for(i=0; i < nr_copy_pages; i++)
-		if((pagedir+i)->orig_address >= addr &&
+	for (i=0; i < nr_copy_pages; i++)
+		if ((pagedir+i)->orig_address >= addr &&
 			(pagedir+i)->orig_address < addre)
 			return 1;
 
@@ -950,9 +934,9 @@
 
 	printk("Relocating pagedir ");
 
-	if(!does_collide_order(old_pagedir, (unsigned long)old_pagedir, pagedir_order)) {
+	if (!does_collide_order(old_pagedir, (unsigned long)old_pagedir, pagedir_order)) {
 		printk("not necessary\n");
-		return 0;
+		return check_pagedir();
 	}
 
 	while ((m = (void *) __get_free_pages(GFP_ATOMIC, pagedir_order)) != NULL) {
@@ -994,24 +978,14 @@
 
 static atomic_t io_done = ATOMIC_INIT(0);
 
-static void start_io(void)
-{
-	atomic_set(&io_done,1);
-}
-
 static int end_io(struct bio * bio, unsigned int num, int err)
 {
-	atomic_set(&io_done,0);
+	if (!test_bit(BIO_UPTODATE, &bio->bi_flags))
+		panic("I/O error reading memory image");
+	atomic_set(&io_done, 0);
 	return 0;
 }
 
-static void wait_io(void)
-{
-	while(atomic_read(&io_done))
-		io_schedule();
-}
-
-
 static struct block_device * resume_bdev;
 
 /**
@@ -1030,7 +1004,7 @@
 	int error = 0;
 	struct bio * bio;
 
-	bio = bio_alloc(GFP_ATOMIC,1);
+	bio = bio_alloc(GFP_ATOMIC, 1);
 	if (!bio)
 		return -ENOMEM;
 	bio->bi_sector = page_off * (PAGE_SIZE >> 9);
@@ -1046,9 +1020,12 @@
 
 	if (rw == WRITE)
 		bio_set_pages_dirty(bio);
-	start_io();
+
+	atomic_set(&io_done, 1);
 	submit_bio(rw | (1 << BIO_RW_SYNC), bio);
-	wait_io();
+	while (atomic_read(&io_done))
+		yield();
+
  Done:
 	bio_put(bio);
 	return error;
@@ -1056,12 +1033,12 @@
 
 int bio_read_page(pgoff_t page_off, void * page)
 {
-	return submit(READ,page_off,page);
+	return submit(READ, page_off, page);
 }
 
 int bio_write_page(pgoff_t page_off, void * page)
 {
-	return submit(WRITE,page_off,page);
+	return submit(WRITE, page_off, page);
 }
 
 /*
@@ -1104,6 +1081,7 @@
 		return -EPERM;
 	}
 	nr_copy_pages = swsusp_info.image_pages;
+	pagedir_order = get_bitmask_order(SUSPEND_PD_PAGES(nr_copy_pages));
 	return error;
 }
 
@@ -1111,16 +1089,16 @@
 {
 	int error;
 
-	memset(&swsusp_header,0,sizeof(swsusp_header));
-	if ((error = bio_read_page(0,&swsusp_header)))
+	memset(&swsusp_header, 0, sizeof(swsusp_header));
+	if ((error = bio_read_page(0, &swsusp_header)))
 		return error;
-	if (!memcmp(SWSUSP_SIG,swsusp_header.sig,10)) {
-		memcpy(swsusp_header.sig,swsusp_header.orig_sig,10);
+	if (!memcmp(SWSUSP_SIG, swsusp_header.sig, 10)) {
+		memcpy(swsusp_header.sig, swsusp_header.orig_sig, 10);
 
 		/*
 		 * Reset swap signature now.
 		 */
-		error = bio_write_page(0,&swsusp_header);
+		error = bio_write_page(0, &swsusp_header);
 	} else { 
 		pr_debug(KERN_ERR "swsusp: Suspend partition has wrong signature?\n");
 		return -EINVAL;
@@ -1130,17 +1108,6 @@
 	return error;
 }
 
-
-int __init verify(void)
-{
-	int error;
-
-	if (!(error = check_sig()))
-		error = check_header();
-	return error;
-}
-
-
 /**
  *	swsusp_read_data - Read image pages from swap.
  *
@@ -1153,14 +1120,18 @@
 	struct pbe * p;
 	int error;
 	int i;
-
+	int mod = nr_copy_pages / 100;
+	
+	if (!mod)
+		mod = 1;
+	
 	if ((error = swsusp_pagedir_relocate()))
 		return error;
 
-	printk( "Reading image data (%d pages): ", nr_copy_pages );
+	printk( "Reading image data (%d pages):     ", nr_copy_pages );
 	for(i = 0, p = pagedir_nosave; i < nr_copy_pages && !error; i++, p++) {
-		if (!(i%100))
-			printk( "." );
+		if (!(i%mod))
+			printk( "\b\b\b\b%3d%%", i / mod );
 		error = bio_read_page(swp_offset(p->swap_address),
 				  (void *)p->address);
 	}
@@ -1177,9 +1148,7 @@
 	int i, n = swsusp_info.pagedir_pages;
 	int error = 0;
 
-	pagedir_order = get_bitmask_order(n);
-
-	addr =__get_free_pages(GFP_ATOMIC, pagedir_order);
+	addr = __get_free_pages(GFP_ATOMIC, pagedir_order);
 	if (!addr)
 		return -ENOMEM;
 	pagedir_nosave = (struct pbe *)addr;
@@ -1194,7 +1163,7 @@
 			error = -EFAULT;
 	}
 	if (error)
-		free_pages((unsigned long)pagedir_nosave,pagedir_order);
+		free_pages((unsigned long)pagedir_nosave, pagedir_order);
 	return error;
 }
 
@@ -1202,13 +1171,14 @@
 {
 	int error = 0;
 
-	if ((error = verify()))
+	if ((error = check_sig()))
+		return error;
+	if ((error = check_header()))
 		return error;
 	if ((error = read_pagedir()))
 		return error;
-	if ((error = data_read())) {
-		free_pages((unsigned long)pagedir_nosave,pagedir_order);
-	}
+	if ((error = data_read()))
+		free_pages((unsigned long)pagedir_nosave, pagedir_order);
 	return error;
 }
 
--- clean-mm/mm/page_alloc.c	2004-09-07 21:12:33.000000000 +0200
+++ linux-mm/mm/page_alloc.c	2004-09-07 21:15:23.000000000 +0200
@@ -437,26 +437,30 @@
 #endif /* CONFIG_PM || CONFIG_HOTPLUG_CPU */
 
 #ifdef CONFIG_PM
-int is_head_of_free_region(struct page *page)
+
+void mark_free_pages(struct zone *zone)
 {
-        struct zone *zone = page_zone(page);
-        unsigned long flags;
+	unsigned long zone_pfn, flags;
 	int order;
 	struct list_head *curr;
 
-	/*
-	 * Should not matter as we need quiescent system for
-	 * suspend anyway, but...
-	 */
+	if (!zone->spanned_pages)
+		return;
+
 	spin_lock_irqsave(&zone->lock, flags);
+	for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn)
+		ClearPageNosaveFree(pfn_to_page(zone_pfn + zone->zone_start_pfn));
+
 	for (order = MAX_ORDER - 1; order >= 0; --order)
-		list_for_each(curr, &zone->free_area[order].free_list)
-			if (page == list_entry(curr, struct page, lru)) {
-				spin_unlock_irqrestore(&zone->lock, flags);
-				return 1 << order;
-			}
+		list_for_each(curr, &zone->free_area[order].free_list) {
+			unsigned long start_pfn, i;
+
+			start_pfn = page_to_pfn(list_entry(curr, struct page, lru));
+
+			for (i=0; i < (1<<order); i++)
+				SetPageNosaveFree(pfn_to_page(start_pfn+i));
+	}
 	spin_unlock_irqrestore(&zone->lock, flags);
-        return 0;
 }
 
 /*

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

end of thread, other threads:[~2004-09-13 22:06 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-09-09 13:44 FYI: my current bigdiff Pavel Machek
2004-09-10  4:13 ` Kevin Fenzi
2004-09-10  9:44   ` Pavel Machek
2004-09-10 17:27     ` Kevin Fenzi
2004-09-10 22:46   ` Bjorn Helgaas
2004-09-11 16:41     ` Stefan Seyfried
2004-09-11 18:55       ` Kevin Fenzi
2004-09-11 18:50     ` Kevin Fenzi
2004-09-13 22:06   ` Bjorn Helgaas
2004-09-12  8:54 ` Stefan Schweizer
2004-09-12  9:23   ` Stefan Seyfried
2004-09-12  9:32     ` Stefan Schweizer
2004-09-12 11:39       ` Stefan Seyfried
2004-09-12 21:03   ` Pavel Machek

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