All of lore.kernel.org
 help / color / mirror / Atom feed
* Nigel's current for-rafael queue
@ 2010-09-25  4:16 Nigel Cunningham
  2010-09-25  4:16 ` [PATCH 01/22] Record & display i/o speed post resume Nigel Cunningham
                   ` (55 more replies)
  0 siblings, 56 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Hi Rafael.

Please find attached a slightly updated version of the patchset I sent
a few months ago. The main change is that I've prepended and additional
patch which lets the user see the speed at which the image is being
read and written. This is accomplished by recording the MB/s in a single
byte in the image header, and using a couple of __nosavedata variables
to get the data back through the atomic restore. I realise the char limits
us to 255MB/s at the moment. In future patches, I intend to address this
by storing the data in a 'proper' image header (it's a real problem -
TuxOnIce reads and writes on the same set up at speeds around 250MB/s).

Results on my Dell XPS M1530, which has an SSD hard drive are:

With just patch 1 applied:
Attempt 1: Write 74MB/s; Read 52MB/s
Attempt 2: Write 68MB/s; Read 52MB/s
Attempt 3: Write 73MB/s; Read 53MB/s

With the whole sequence:
Attempt 1: Write 181MB/s; Read 52MB/s
Attempt 2: Write 156MB/s; Read 53MB/s
Attempt 3: Write 160MB/s; Read 52MB/s

Regards,

Nigel


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

* [PATCH 01/22] Record & display i/o speed post resume.
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
@ 2010-09-25  4:16 ` Nigel Cunningham
  2010-09-25  4:16 ` Nigel Cunningham
                   ` (54 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Record the speed at which the image is written and read, and
display it to the user post-resume.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/hibernate.c |   11 ++++++++++-
 kernel/power/power.h     |    4 +++-
 kernel/power/swap.c      |   14 +++++++++++---
 3 files changed, 24 insertions(+), 5 deletions(-)

diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
index 8dc31e0..8cd0bbc 100644
--- a/kernel/power/hibernate.c
+++ b/kernel/power/hibernate.c
@@ -211,7 +211,7 @@ static void platform_recover(int platform_mode)
  *	@msg -		introductory message to print
  */
 
-void swsusp_show_speed(struct timeval *start, struct timeval *stop,
+int swsusp_show_speed(struct timeval *start, struct timeval *stop,
 			unsigned nr_pages, char *msg)
 {
 	s64 elapsed_centisecs64;
@@ -230,6 +230,7 @@ void swsusp_show_speed(struct timeval *start, struct timeval *stop,
 			msg, k,
 			centisecs / 100, centisecs % 100,
 			kps / 1000, (kps % 1000) / 10);
+	return kps / 1000;
 }
 
 /**
@@ -645,6 +646,14 @@ int hibernate(void)
 			power_down();
 	} else {
 		pr_debug("PM: Image restored successfully.\n");
+		if (write_speed)
+			pr_debug("PM: Image written at %u MB/s.\n",
+					(u8) write_speed);
+		write_speed = 0;
+		if (read_speed)
+			pr_debug("PM: Image read at %u MB/s.\n",
+					(u8) read_speed);
+		read_speed = 0;
 	}
 
  Thaw:
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 006270f..67b6896 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -49,6 +49,8 @@ static inline char *check_image_kernel(struct swsusp_info *info)
 extern int hibernation_snapshot(int platform_mode);
 extern int hibernation_restore(int platform_mode);
 extern int hibernation_platform_enter(void);
+
+extern char __nosavedata write_speed, read_speed;
 #endif
 
 extern int pfn_is_nosave(unsigned long);
@@ -153,7 +155,7 @@ extern int hib_wait_on_bio_chain(struct bio **bio_chain);
 
 struct timeval;
 /* kernel/power/swsusp.c */
-extern void swsusp_show_speed(struct timeval *, struct timeval *,
+extern int swsusp_show_speed(struct timeval *, struct timeval *,
 				unsigned int, char *);
 
 #ifdef CONFIG_SUSPEND
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index e6a5bdf..728f85b 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -64,7 +64,8 @@ struct swap_map_handle {
 };
 
 struct swsusp_header {
-	char reserved[PAGE_SIZE - 20 - sizeof(sector_t) - sizeof(int)];
+	char reserved[PAGE_SIZE - 21 - sizeof(sector_t) - sizeof(int)];
+	char write_speed;
 	sector_t image;
 	unsigned int flags;	/* Flags to pass to the "boot" kernel */
 	char	orig_sig[10];
@@ -180,6 +181,7 @@ int swsusp_swap_in_use(void)
 
 static unsigned short root_swap = 0xffff;
 struct block_device *hib_resume_bdev;
+char __nosavedata write_speed, read_speed;
 
 /*
  * Saving part
@@ -194,6 +196,7 @@ static int mark_swapfiles(struct swap_map_handle *handle, unsigned int flags)
 	    !memcmp("SWAPSPACE2",swsusp_header->sig, 10)) {
 		memcpy(swsusp_header->orig_sig,swsusp_header->sig, 10);
 		memcpy(swsusp_header->sig,SWSUSP_SIG, 10);
+		swsusp_header->write_speed = write_speed;
 		swsusp_header->image = handle->first_sector;
 		swsusp_header->flags = flags;
 		error = hib_bio_write_page(swsusp_resume_block,
@@ -372,6 +375,7 @@ static int save_image(struct swap_map_handle *handle,
 	struct bio *bio;
 	struct timeval start;
 	struct timeval stop;
+	int mps;
 
 	printk(KERN_INFO "PM: Saving image data pages (%u pages) ...     ",
 		nr_to_write);
@@ -400,7 +404,8 @@ static int save_image(struct swap_map_handle *handle,
 		printk(KERN_CONT "\b\b\b\bdone\n");
 	else
 		printk(KERN_CONT "\n");
-	swsusp_show_speed(&start, &stop, nr_to_write, "Wrote");
+	mps = swsusp_show_speed(&start, &stop, nr_to_write, "Wrote");
+	write_speed = (mps < 256) ? (char) mps : 0;
 	return ret;
 }
 
@@ -550,6 +555,7 @@ static int load_image(struct swap_map_handle *handle,
 	struct bio *bio;
 	int err2;
 	unsigned nr_pages;
+	int mps;
 
 	printk(KERN_INFO "PM: Loading image data pages (%u pages) ...     ",
 		nr_to_read);
@@ -585,7 +591,8 @@ static int load_image(struct swap_map_handle *handle,
 			error = -ENODATA;
 	} else
 		printk("\n");
-	swsusp_show_speed(&start, &stop, nr_to_read, "Read");
+	mps = swsusp_show_speed(&start, &stop, nr_to_read, "Read");
+	read_speed = (mps < 256) ? mps : 0;
 	return error;
 }
 
@@ -641,6 +648,7 @@ int swsusp_check(void)
 			goto put;
 
 		if (!memcmp(SWSUSP_SIG, swsusp_header->sig, 10)) {
+			write_speed = swsusp_header->write_speed;
 			memcpy(swsusp_header->sig, swsusp_header->orig_sig, 10);
 			/* Reset swap signature now */
 			error = hib_bio_write_page(swsusp_resume_block,
-- 
1.7.0.4


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

* [PATCH 01/22] Record & display i/o speed post resume.
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
  2010-09-25  4:16 ` [PATCH 01/22] Record & display i/o speed post resume Nigel Cunningham
@ 2010-09-25  4:16 ` Nigel Cunningham
  2010-09-25  4:16 ` [PATCH 02/22] Hibernation: Swap iteration functions Nigel Cunningham
                   ` (53 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Record the speed at which the image is written and read, and
display it to the user post-resume.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/hibernate.c |   11 ++++++++++-
 kernel/power/power.h     |    4 +++-
 kernel/power/swap.c      |   14 +++++++++++---
 3 files changed, 24 insertions(+), 5 deletions(-)

diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
index 8dc31e0..8cd0bbc 100644
--- a/kernel/power/hibernate.c
+++ b/kernel/power/hibernate.c
@@ -211,7 +211,7 @@ static void platform_recover(int platform_mode)
  *	@msg -		introductory message to print
  */
 
-void swsusp_show_speed(struct timeval *start, struct timeval *stop,
+int swsusp_show_speed(struct timeval *start, struct timeval *stop,
 			unsigned nr_pages, char *msg)
 {
 	s64 elapsed_centisecs64;
@@ -230,6 +230,7 @@ void swsusp_show_speed(struct timeval *start, struct timeval *stop,
 			msg, k,
 			centisecs / 100, centisecs % 100,
 			kps / 1000, (kps % 1000) / 10);
+	return kps / 1000;
 }
 
 /**
@@ -645,6 +646,14 @@ int hibernate(void)
 			power_down();
 	} else {
 		pr_debug("PM: Image restored successfully.\n");
+		if (write_speed)
+			pr_debug("PM: Image written at %u MB/s.\n",
+					(u8) write_speed);
+		write_speed = 0;
+		if (read_speed)
+			pr_debug("PM: Image read at %u MB/s.\n",
+					(u8) read_speed);
+		read_speed = 0;
 	}
 
  Thaw:
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 006270f..67b6896 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -49,6 +49,8 @@ static inline char *check_image_kernel(struct swsusp_info *info)
 extern int hibernation_snapshot(int platform_mode);
 extern int hibernation_restore(int platform_mode);
 extern int hibernation_platform_enter(void);
+
+extern char __nosavedata write_speed, read_speed;
 #endif
 
 extern int pfn_is_nosave(unsigned long);
@@ -153,7 +155,7 @@ extern int hib_wait_on_bio_chain(struct bio **bio_chain);
 
 struct timeval;
 /* kernel/power/swsusp.c */
-extern void swsusp_show_speed(struct timeval *, struct timeval *,
+extern int swsusp_show_speed(struct timeval *, struct timeval *,
 				unsigned int, char *);
 
 #ifdef CONFIG_SUSPEND
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index e6a5bdf..728f85b 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -64,7 +64,8 @@ struct swap_map_handle {
 };
 
 struct swsusp_header {
-	char reserved[PAGE_SIZE - 20 - sizeof(sector_t) - sizeof(int)];
+	char reserved[PAGE_SIZE - 21 - sizeof(sector_t) - sizeof(int)];
+	char write_speed;
 	sector_t image;
 	unsigned int flags;	/* Flags to pass to the "boot" kernel */
 	char	orig_sig[10];
@@ -180,6 +181,7 @@ int swsusp_swap_in_use(void)
 
 static unsigned short root_swap = 0xffff;
 struct block_device *hib_resume_bdev;
+char __nosavedata write_speed, read_speed;
 
 /*
  * Saving part
@@ -194,6 +196,7 @@ static int mark_swapfiles(struct swap_map_handle *handle, unsigned int flags)
 	    !memcmp("SWAPSPACE2",swsusp_header->sig, 10)) {
 		memcpy(swsusp_header->orig_sig,swsusp_header->sig, 10);
 		memcpy(swsusp_header->sig,SWSUSP_SIG, 10);
+		swsusp_header->write_speed = write_speed;
 		swsusp_header->image = handle->first_sector;
 		swsusp_header->flags = flags;
 		error = hib_bio_write_page(swsusp_resume_block,
@@ -372,6 +375,7 @@ static int save_image(struct swap_map_handle *handle,
 	struct bio *bio;
 	struct timeval start;
 	struct timeval stop;
+	int mps;
 
 	printk(KERN_INFO "PM: Saving image data pages (%u pages) ...     ",
 		nr_to_write);
@@ -400,7 +404,8 @@ static int save_image(struct swap_map_handle *handle,
 		printk(KERN_CONT "\b\b\b\bdone\n");
 	else
 		printk(KERN_CONT "\n");
-	swsusp_show_speed(&start, &stop, nr_to_write, "Wrote");
+	mps = swsusp_show_speed(&start, &stop, nr_to_write, "Wrote");
+	write_speed = (mps < 256) ? (char) mps : 0;
 	return ret;
 }
 
@@ -550,6 +555,7 @@ static int load_image(struct swap_map_handle *handle,
 	struct bio *bio;
 	int err2;
 	unsigned nr_pages;
+	int mps;
 
 	printk(KERN_INFO "PM: Loading image data pages (%u pages) ...     ",
 		nr_to_read);
@@ -585,7 +591,8 @@ static int load_image(struct swap_map_handle *handle,
 			error = -ENODATA;
 	} else
 		printk("\n");
-	swsusp_show_speed(&start, &stop, nr_to_read, "Read");
+	mps = swsusp_show_speed(&start, &stop, nr_to_read, "Read");
+	read_speed = (mps < 256) ? mps : 0;
 	return error;
 }
 
@@ -641,6 +648,7 @@ int swsusp_check(void)
 			goto put;
 
 		if (!memcmp(SWSUSP_SIG, swsusp_header->sig, 10)) {
+			write_speed = swsusp_header->write_speed;
 			memcpy(swsusp_header->sig, swsusp_header->orig_sig, 10);
 			/* Reset swap signature now */
 			error = hib_bio_write_page(swsusp_resume_block,
-- 
1.7.0.4

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

* [PATCH 02/22] Hibernation: Swap iteration functions.
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
  2010-09-25  4:16 ` [PATCH 01/22] Record & display i/o speed post resume Nigel Cunningham
  2010-09-25  4:16 ` Nigel Cunningham
@ 2010-09-25  4:16 ` Nigel Cunningham
  2010-09-25  4:16 ` Nigel Cunningham
                   ` (52 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Add the data structure 'storage_position' and routines that allow
a caller to iterate over swap in sector order. Note that calling
reset_storage_pos only resets the position. next_swapdev_block
must also be called to get the address of the first (and subsequent
sectors).

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/swap.c |   39 +++++++++++++++++++++++++++++++++++++++
 1 files changed, 39 insertions(+), 0 deletions(-)

diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index 728f85b..d53417b 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -87,6 +87,45 @@ struct swsusp_extent {
 
 static struct rb_root swsusp_extents = RB_ROOT;
 
+struct storage_position {
+	struct rb_node *node;
+	struct swsusp_extent *cur_ext;
+	unsigned long offset;
+};
+
+static struct storage_position pos;
+
+static void reset_storage_pos(void)
+{
+	pos.node = rb_first(&swsusp_extents);
+
+	if (!pos.node) {
+		pos.cur_ext = NULL;
+		pos.offset = 0;
+		return;
+	}
+
+	pos.cur_ext = container_of(pos.node, struct swsusp_extent, node);
+	pos.offset = pos.cur_ext->start;
+}
+
+static sector_t next_swapdev_block(void)
+{
+	if (!pos.node)
+		return 0;
+
+	if (pos.cur_ext->end >= pos.offset)
+		return pos.offset++;
+
+	pos.node = rb_next(pos.node);
+	if (!pos.node)
+		return 0;
+
+	pos.cur_ext = container_of(pos.node, struct swsusp_extent, node);
+	pos.offset = pos.cur_ext->start;
+	return pos.offset;
+}
+
 static int swsusp_extents_insert(unsigned long swap_offset)
 {
 	struct rb_node **new = &(swsusp_extents.rb_node);
-- 
1.7.0.4


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

* [PATCH 02/22] Hibernation: Swap iteration functions.
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (2 preceding siblings ...)
  2010-09-25  4:16 ` [PATCH 02/22] Hibernation: Swap iteration functions Nigel Cunningham
@ 2010-09-25  4:16 ` Nigel Cunningham
  2010-09-25  4:16 ` [PATCH 03/22] Hibernation: Move root_swap declaration Nigel Cunningham
                   ` (51 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Add the data structure 'storage_position' and routines that allow
a caller to iterate over swap in sector order. Note that calling
reset_storage_pos only resets the position. next_swapdev_block
must also be called to get the address of the first (and subsequent
sectors).

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/swap.c |   39 +++++++++++++++++++++++++++++++++++++++
 1 files changed, 39 insertions(+), 0 deletions(-)

diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index 728f85b..d53417b 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -87,6 +87,45 @@ struct swsusp_extent {
 
 static struct rb_root swsusp_extents = RB_ROOT;
 
+struct storage_position {
+	struct rb_node *node;
+	struct swsusp_extent *cur_ext;
+	unsigned long offset;
+};
+
+static struct storage_position pos;
+
+static void reset_storage_pos(void)
+{
+	pos.node = rb_first(&swsusp_extents);
+
+	if (!pos.node) {
+		pos.cur_ext = NULL;
+		pos.offset = 0;
+		return;
+	}
+
+	pos.cur_ext = container_of(pos.node, struct swsusp_extent, node);
+	pos.offset = pos.cur_ext->start;
+}
+
+static sector_t next_swapdev_block(void)
+{
+	if (!pos.node)
+		return 0;
+
+	if (pos.cur_ext->end >= pos.offset)
+		return pos.offset++;
+
+	pos.node = rb_next(pos.node);
+	if (!pos.node)
+		return 0;
+
+	pos.cur_ext = container_of(pos.node, struct swsusp_extent, node);
+	pos.offset = pos.cur_ext->start;
+	return pos.offset;
+}
+
 static int swsusp_extents_insert(unsigned long swap_offset)
 {
 	struct rb_node **new = &(swsusp_extents.rb_node);
-- 
1.7.0.4

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

* [PATCH 03/22] Hibernation: Move root_swap declaration.
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (3 preceding siblings ...)
  2010-09-25  4:16 ` Nigel Cunningham
@ 2010-09-25  4:16 ` Nigel Cunningham
  2010-09-25  4:16 ` Nigel Cunningham
                   ` (50 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Move the declaration of root_swap in preparation for the
next patch.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/swap.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index d53417b..587f851 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -63,6 +63,8 @@ struct swap_map_handle {
 	unsigned int k;
 };
 
+static unsigned short root_swap = 0xffff;
+
 struct swsusp_header {
 	char reserved[PAGE_SIZE - 21 - sizeof(sector_t) - sizeof(int)];
 	char write_speed;
@@ -218,7 +220,6 @@ int swsusp_swap_in_use(void)
  * General things
  */
 
-static unsigned short root_swap = 0xffff;
 struct block_device *hib_resume_bdev;
 char __nosavedata write_speed, read_speed;
 
-- 
1.7.0.4


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

* [PATCH 03/22] Hibernation: Move root_swap declaration.
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (4 preceding siblings ...)
  2010-09-25  4:16 ` [PATCH 03/22] Hibernation: Move root_swap declaration Nigel Cunningham
@ 2010-09-25  4:16 ` Nigel Cunningham
  2010-09-25  4:16 ` [PATCH 04/22] Hibernation: Add mass swap allocation routine Nigel Cunningham
                   ` (49 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Move the declaration of root_swap in preparation for the
next patch.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/swap.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index d53417b..587f851 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -63,6 +63,8 @@ struct swap_map_handle {
 	unsigned int k;
 };
 
+static unsigned short root_swap = 0xffff;
+
 struct swsusp_header {
 	char reserved[PAGE_SIZE - 21 - sizeof(sector_t) - sizeof(int)];
 	char write_speed;
@@ -218,7 +220,6 @@ int swsusp_swap_in_use(void)
  * General things
  */
 
-static unsigned short root_swap = 0xffff;
 struct block_device *hib_resume_bdev;
 char __nosavedata write_speed, read_speed;
 
-- 
1.7.0.4

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

* [PATCH 04/22] Hibernation: Add mass swap allocation routine
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (7 preceding siblings ...)
  2010-09-25  4:16 ` Nigel Cunningham
@ 2010-09-25  4:16 ` Nigel Cunningham
  2010-09-25  4:16 ` [PATCH 05/22] Hibernation: Switch to preallocating swap Nigel Cunningham
                   ` (46 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Add a routine to allocate swap from a device en masse. This is only
for use by the in-kernel implementation, not uswsusp.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/swap.c |   13 +++++++++++++
 1 files changed, 13 insertions(+), 0 deletions(-)

diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index 587f851..cebf91c 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -188,6 +188,19 @@ sector_t alloc_swapdev_block(int swap)
 	return 0;
 }
 
+int alloc_swapdev_blocks(int needed)
+{
+	int i;
+
+	for (i = 0; i < needed; i++) {
+		sector_t res = alloc_swapdev_block(root_swap);
+		if (!res)
+			break;
+	}
+
+	return i;
+}
+
 /**
  *	free_all_swap_pages - free swap pages allocated for saving image data.
  *	It also frees the extents used to register which swap entries had been
-- 
1.7.0.4


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

* [PATCH 04/22] Hibernation: Add mass swap allocation routine
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (6 preceding siblings ...)
  2010-09-25  4:16 ` [PATCH 04/22] Hibernation: Add mass swap allocation routine Nigel Cunningham
@ 2010-09-25  4:16 ` Nigel Cunningham
  2010-09-25  4:16 ` Nigel Cunningham
                   ` (47 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Add a routine to allocate swap from a device en masse. This is only
for use by the in-kernel implementation, not uswsusp.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/swap.c |   13 +++++++++++++
 1 files changed, 13 insertions(+), 0 deletions(-)

diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index 587f851..cebf91c 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -188,6 +188,19 @@ sector_t alloc_swapdev_block(int swap)
 	return 0;
 }
 
+int alloc_swapdev_blocks(int needed)
+{
+	int i;
+
+	for (i = 0; i < needed; i++) {
+		sector_t res = alloc_swapdev_block(root_swap);
+		if (!res)
+			break;
+	}
+
+	return i;
+}
+
 /**
  *	free_all_swap_pages - free swap pages allocated for saving image data.
  *	It also frees the extents used to register which swap entries had been
-- 
1.7.0.4

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

* [PATCH 04/22] Hibernation: Add mass swap allocation routine
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (5 preceding siblings ...)
  2010-09-25  4:16 ` Nigel Cunningham
@ 2010-09-25  4:16 ` Nigel Cunningham
  2010-09-25  4:16 ` Nigel Cunningham
                   ` (48 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Add a routine to allocate swap from a device en masse. This is only
for use by the in-kernel implementation, not uswsusp.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/swap.c |   13 +++++++++++++
 1 files changed, 13 insertions(+), 0 deletions(-)

diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index 587f851..cebf91c 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -188,6 +188,19 @@ sector_t alloc_swapdev_block(int swap)
 	return 0;
 }
 
+int alloc_swapdev_blocks(int needed)
+{
+	int i;
+
+	for (i = 0; i < needed; i++) {
+		sector_t res = alloc_swapdev_block(root_swap);
+		if (!res)
+			break;
+	}
+
+	return i;
+}
+
 /**
  *	free_all_swap_pages - free swap pages allocated for saving image data.
  *	It also frees the extents used to register which swap entries had been
-- 
1.7.0.4


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

* [PATCH 05/22] Hibernation: Switch to preallocating swap.
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (8 preceding siblings ...)
  2010-09-25  4:16 ` Nigel Cunningham
@ 2010-09-25  4:16 ` Nigel Cunningham
  2010-09-25 21:24   ` Rafael J. Wysocki
                     ` (2 more replies)
  2010-09-25  4:16 ` Nigel Cunningham
                   ` (45 subsequent siblings)
  55 siblings, 3 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Switch from allocating swap as the image is written to allocating
storage prior to writing the image.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/swap.c |   62 ++++++++++++++++++++++++++++++--------------------
 1 files changed, 37 insertions(+), 25 deletions(-)

diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index cebf91c..bebd2cf 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -202,6 +202,33 @@ int alloc_swapdev_blocks(int needed)
 }
 
 /**
+ *	allocate_swap - Allocate enough swap to save the image.
+ *
+ *	Calculates the number of swap pages actually needed and seeks
+ *	to allocate that many from the resume partition. Returns TRUE
+ *	or FALSE to indicate whether we got enough storage.
+ */
+
+static int allocate_swap(unsigned int nr_pages)
+{
+	unsigned int free_swap = count_swap_pages(root_swap, 1);
+
+	nr_pages += DIV_ROUND_UP(nr_pages, MAP_PAGE_ENTRIES);
+
+	pr_debug("PM: Free swap pages: %u\n", free_swap);
+	if (free_swap < nr_pages)
+		return 0;
+
+	if (alloc_swapdev_blocks(nr_pages) < nr_pages) {
+		free_all_swap_pages(root_swap);
+		return 0;
+	}
+
+	reset_storage_pos();
+	return 1;
+}
+
+/**
  *	free_all_swap_pages - free swap pages allocated for saving image data.
  *	It also frees the extents used to register which swap entries had been
  *	allocated.
@@ -324,7 +351,7 @@ static void release_swap_writer(struct swap_map_handle *handle)
 	handle->cur = NULL;
 }
 
-static int get_swap_writer(struct swap_map_handle *handle)
+static int get_swap_writer(struct swap_map_handle *handle, unsigned long pages)
 {
 	int ret;
 
@@ -340,7 +367,12 @@ static int get_swap_writer(struct swap_map_handle *handle)
 		ret = -ENOMEM;
 		goto err_close;
 	}
-	handle->cur_swap = alloc_swapdev_block(root_swap);
+	if (!allocate_swap(pages)) {
+		printk(KERN_ERR "PM: Not enough free swap\n");
+		ret = -ENOSPC;
+		goto err_close;
+	}
+	handle->cur_swap = next_swapdev_block();
 	if (!handle->cur_swap) {
 		ret = -ENOSPC;
 		goto err_rel;
@@ -363,7 +395,7 @@ static int swap_write_page(struct swap_map_handle *handle, void *buf,
 
 	if (!handle->cur)
 		return -EINVAL;
-	offset = alloc_swapdev_block(root_swap);
+	offset = next_swapdev_block();
 	error = write_page(buf, offset, bio_chain);
 	if (error)
 		return error;
@@ -372,7 +404,7 @@ static int swap_write_page(struct swap_map_handle *handle, void *buf,
 		error = hib_wait_on_bio_chain(bio_chain);
 		if (error)
 			goto out;
-		offset = alloc_swapdev_block(root_swap);
+		offset = next_swapdev_block();
 		if (!offset)
 			return -ENOSPC;
 		handle->cur->next_swap = offset;
@@ -463,21 +495,6 @@ static int save_image(struct swap_map_handle *handle,
 }
 
 /**
- *	enough_swap - Make sure we have enough swap to save the image.
- *
- *	Returns TRUE or FALSE after checking the total amount of swap
- *	space avaiable from the resume partition.
- */
-
-static int enough_swap(unsigned int nr_pages)
-{
-	unsigned int free_swap = count_swap_pages(root_swap, 1);
-
-	pr_debug("PM: Free swap pages: %u\n", free_swap);
-	return free_swap > nr_pages + PAGES_FOR_IO;
-}
-
-/**
  *	swsusp_write - Write entire image and metadata.
  *	@flags: flags to pass to the "boot" kernel in the image header
  *
@@ -496,16 +513,11 @@ int swsusp_write(unsigned int flags)
 	int error;
 
 	pages = snapshot_get_image_size();
-	error = get_swap_writer(&handle);
+	error = get_swap_writer(&handle, pages);
 	if (error) {
 		printk(KERN_ERR "PM: Cannot get swap writer\n");
 		return error;
 	}
-	if (!enough_swap(pages)) {
-		printk(KERN_ERR "PM: Not enough free swap\n");
-		error = -ENOSPC;
-		goto out_finish;
-	}
 	memset(&snapshot, 0, sizeof(struct snapshot_handle));
 	error = snapshot_read_next(&snapshot);
 	if (error < PAGE_SIZE) {
-- 
1.7.0.4


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

* [PATCH 05/22] Hibernation: Switch to preallocating swap.
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (9 preceding siblings ...)
  2010-09-25  4:16 ` [PATCH 05/22] Hibernation: Switch to preallocating swap Nigel Cunningham
@ 2010-09-25  4:16 ` Nigel Cunningham
  2010-09-25  4:16 ` [PATCH 06/22] Hiberation: Fix speed display Nigel Cunningham
                   ` (44 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Switch from allocating swap as the image is written to allocating
storage prior to writing the image.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/swap.c |   62 ++++++++++++++++++++++++++++++--------------------
 1 files changed, 37 insertions(+), 25 deletions(-)

diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index cebf91c..bebd2cf 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -202,6 +202,33 @@ int alloc_swapdev_blocks(int needed)
 }
 
 /**
+ *	allocate_swap - Allocate enough swap to save the image.
+ *
+ *	Calculates the number of swap pages actually needed and seeks
+ *	to allocate that many from the resume partition. Returns TRUE
+ *	or FALSE to indicate whether we got enough storage.
+ */
+
+static int allocate_swap(unsigned int nr_pages)
+{
+	unsigned int free_swap = count_swap_pages(root_swap, 1);
+
+	nr_pages += DIV_ROUND_UP(nr_pages, MAP_PAGE_ENTRIES);
+
+	pr_debug("PM: Free swap pages: %u\n", free_swap);
+	if (free_swap < nr_pages)
+		return 0;
+
+	if (alloc_swapdev_blocks(nr_pages) < nr_pages) {
+		free_all_swap_pages(root_swap);
+		return 0;
+	}
+
+	reset_storage_pos();
+	return 1;
+}
+
+/**
  *	free_all_swap_pages - free swap pages allocated for saving image data.
  *	It also frees the extents used to register which swap entries had been
  *	allocated.
@@ -324,7 +351,7 @@ static void release_swap_writer(struct swap_map_handle *handle)
 	handle->cur = NULL;
 }
 
-static int get_swap_writer(struct swap_map_handle *handle)
+static int get_swap_writer(struct swap_map_handle *handle, unsigned long pages)
 {
 	int ret;
 
@@ -340,7 +367,12 @@ static int get_swap_writer(struct swap_map_handle *handle)
 		ret = -ENOMEM;
 		goto err_close;
 	}
-	handle->cur_swap = alloc_swapdev_block(root_swap);
+	if (!allocate_swap(pages)) {
+		printk(KERN_ERR "PM: Not enough free swap\n");
+		ret = -ENOSPC;
+		goto err_close;
+	}
+	handle->cur_swap = next_swapdev_block();
 	if (!handle->cur_swap) {
 		ret = -ENOSPC;
 		goto err_rel;
@@ -363,7 +395,7 @@ static int swap_write_page(struct swap_map_handle *handle, void *buf,
 
 	if (!handle->cur)
 		return -EINVAL;
-	offset = alloc_swapdev_block(root_swap);
+	offset = next_swapdev_block();
 	error = write_page(buf, offset, bio_chain);
 	if (error)
 		return error;
@@ -372,7 +404,7 @@ static int swap_write_page(struct swap_map_handle *handle, void *buf,
 		error = hib_wait_on_bio_chain(bio_chain);
 		if (error)
 			goto out;
-		offset = alloc_swapdev_block(root_swap);
+		offset = next_swapdev_block();
 		if (!offset)
 			return -ENOSPC;
 		handle->cur->next_swap = offset;
@@ -463,21 +495,6 @@ static int save_image(struct swap_map_handle *handle,
 }
 
 /**
- *	enough_swap - Make sure we have enough swap to save the image.
- *
- *	Returns TRUE or FALSE after checking the total amount of swap
- *	space avaiable from the resume partition.
- */
-
-static int enough_swap(unsigned int nr_pages)
-{
-	unsigned int free_swap = count_swap_pages(root_swap, 1);
-
-	pr_debug("PM: Free swap pages: %u\n", free_swap);
-	return free_swap > nr_pages + PAGES_FOR_IO;
-}
-
-/**
  *	swsusp_write - Write entire image and metadata.
  *	@flags: flags to pass to the "boot" kernel in the image header
  *
@@ -496,16 +513,11 @@ int swsusp_write(unsigned int flags)
 	int error;
 
 	pages = snapshot_get_image_size();
-	error = get_swap_writer(&handle);
+	error = get_swap_writer(&handle, pages);
 	if (error) {
 		printk(KERN_ERR "PM: Cannot get swap writer\n");
 		return error;
 	}
-	if (!enough_swap(pages)) {
-		printk(KERN_ERR "PM: Not enough free swap\n");
-		error = -ENOSPC;
-		goto out_finish;
-	}
 	memset(&snapshot, 0, sizeof(struct snapshot_handle));
 	error = snapshot_read_next(&snapshot);
 	if (error < PAGE_SIZE) {
-- 
1.7.0.4

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

* [PATCH 06/22] Hiberation: Fix speed display.
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (10 preceding siblings ...)
  2010-09-25  4:16 ` Nigel Cunningham
@ 2010-09-25  4:16 ` Nigel Cunningham
  2010-09-25  4:16 ` Nigel Cunningham
                   ` (43 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Correct the situation where, if an error occurs while writing an image,
the speed display still uses the number of pages that should have been
written, rather than the number of pages that were written.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/swap.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index bebd2cf..2ef2bad 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -489,7 +489,7 @@ static int save_image(struct swap_map_handle *handle,
 		printk(KERN_CONT "\b\b\b\bdone\n");
 	else
 		printk(KERN_CONT "\n");
-	mps = swsusp_show_speed(&start, &stop, nr_to_write, "Wrote");
+	mps = swsusp_show_speed(&start, &stop, nr_pages, "Wrote");
 	write_speed = (mps < 256) ? (char) mps : 0;
 	return ret;
 }
-- 
1.7.0.4


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

* [PATCH 06/22] Hiberation: Fix speed display.
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (11 preceding siblings ...)
  2010-09-25  4:16 ` [PATCH 06/22] Hiberation: Fix speed display Nigel Cunningham
@ 2010-09-25  4:16 ` Nigel Cunningham
  2010-09-25  4:16 ` [PATCH 07/22] Hibernation: Generic extents support Nigel Cunningham
                   ` (42 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Correct the situation where, if an error occurs while writing an image,
the speed display still uses the number of pages that should have been
written, rather than the number of pages that were written.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/swap.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index bebd2cf..2ef2bad 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -489,7 +489,7 @@ static int save_image(struct swap_map_handle *handle,
 		printk(KERN_CONT "\b\b\b\bdone\n");
 	else
 		printk(KERN_CONT "\n");
-	mps = swsusp_show_speed(&start, &stop, nr_to_write, "Wrote");
+	mps = swsusp_show_speed(&start, &stop, nr_pages, "Wrote");
 	write_speed = (mps < 256) ? (char) mps : 0;
 	return ret;
 }
-- 
1.7.0.4

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

* [PATCH 07/22] Hibernation: Generic extents support.
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (13 preceding siblings ...)
  2010-09-25  4:16 ` [PATCH 07/22] Hibernation: Generic extents support Nigel Cunningham
@ 2010-09-25  4:16 ` Nigel Cunningham
  2010-09-25  4:16 ` Nigel Cunningham
                   ` (40 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Separate out the extent storage and manipulation into a separate
file and make them more generic, so we can also use extents for
recording what sectors are used and (later) support multiple
storage devices more easily.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/Makefile  |    2 +-
 kernel/power/extents.c |  125 ++++++++++++++++++++++++++++++++++++++++++++++++
 kernel/power/extents.h |   35 +++++++++++++
 kernel/power/swap.c    |  117 +++++---------------------------------------
 4 files changed, 175 insertions(+), 104 deletions(-)
 create mode 100644 kernel/power/extents.c
 create mode 100644 kernel/power/extents.h

diff --git a/kernel/power/Makefile b/kernel/power/Makefile
index f9063c6..df24cab 100644
--- a/kernel/power/Makefile
+++ b/kernel/power/Makefile
@@ -9,7 +9,7 @@ obj-$(CONFIG_FREEZER)		+= process.o
 obj-$(CONFIG_SUSPEND)		+= suspend.o
 obj-$(CONFIG_PM_TEST_SUSPEND)	+= suspend_test.o
 obj-$(CONFIG_HIBERNATION)	+= hibernate.o snapshot.o swap.o user.o \
-				   block_io.o
+				   block_io.o extents.o
 obj-$(CONFIG_SUSPEND_NVS)	+= nvs.o
 
 obj-$(CONFIG_MAGIC_SYSRQ)	+= poweroff.o
diff --git a/kernel/power/extents.c b/kernel/power/extents.c
new file mode 100644
index 0000000..172322d
--- /dev/null
+++ b/kernel/power/extents.c
@@ -0,0 +1,125 @@
+/*
+ * linux/kernel/power/extents.c
+ *
+ * This file provides functions for storing and using a series of
+ * extents.
+ *
+ * Copyright (C) 1998,2001-2005 Pavel Machek <pavel@suse.cz>
+ * Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl>
+ * Copyright (C) 2010 Nigel Cunningham <nigel@tuxonice.net>
+ *
+ * This file is released under the GPLv2.
+ *
+ */
+
+#include <linux/slab.h>
+#include "extents.h"
+
+int hib_extents_empty(struct hib_extent_state *pos)
+{
+	return RB_EMPTY_ROOT(&pos->root);
+}
+
+void hib_reset_extent_pos(struct hib_extent_state *pos)
+{
+	if (hib_extents_empty(pos))
+		return;
+
+	pos->node = rb_first(&pos->root);
+
+	if (!pos->node) {
+		pos->cur_ext = NULL;
+		pos->offset = 0;
+		return;
+	}
+
+	pos->cur_ext = container_of(pos->node, struct hib_extent, node);
+	pos->offset = pos->cur_ext->start;
+}
+
+unsigned long hib_extent_current(struct hib_extent_state *pos)
+{
+	return (pos->node) ? pos->offset : 0;
+}
+
+unsigned long hib_extent_next(struct hib_extent_state *pos)
+{
+	if (!pos->node)
+		return 0;
+
+	if (pos->cur_ext->end >= pos->offset)
+		return pos->offset++;
+
+	pos->node = rb_next(pos->node);
+	if (!pos->node)
+		return 0;
+
+	pos->cur_ext = container_of(pos->node, struct hib_extent, node);
+	pos->offset = pos->cur_ext->start;
+	return pos->offset;
+}
+
+int hib_extents_insert(struct hib_extent_state *pos, unsigned long value)
+{
+	struct rb_node **new = &(pos->root.rb_node);
+	struct rb_node *parent = NULL;
+	struct hib_extent *ext;
+
+	/* Figure out where to put the new node */
+	while (*new) {
+		ext = container_of(*new, struct hib_extent, node);
+		parent = *new;
+		if (value < ext->start) {
+			/* Try to merge */
+			if (value == ext->start - 1) {
+				ext->start--;
+				return 0;
+			}
+			new = &((*new)->rb_left);
+		} else if (value > ext->end) {
+			/* Try to merge */
+			if (value == ext->end + 1) {
+				ext->end++;
+				return 0;
+			}
+			new = &((*new)->rb_right);
+		} else {
+			/* It already is in the tree */
+			return -EINVAL;
+		}
+	}
+	/* Add the new node and rebalance the tree. */
+	ext = kzalloc(sizeof(struct hib_extent), GFP_KERNEL);
+	if (!ext)
+		return -ENOMEM;
+
+	ext->start = value;
+	ext->end = value;
+	rb_link_node(&ext->node, parent, new);
+	rb_insert_color(&ext->node, &pos->root);
+	pos->num_extents++;
+	return 0;
+}
+
+/**
+ *	free_all_swap_pages - free swap pages allocated for saving image data.
+ *	It also frees the extents used to register which swap entres had been
+ *	allocated.
+ */
+
+void hib_extents_clear(struct hib_extent_state *pos)
+{
+	struct rb_node *node;
+
+	if (hib_extents_empty(pos))
+		return;
+
+	while ((node = pos->root.rb_node)) {
+		struct hib_extent *ext;
+
+		ext = container_of(node, struct hib_extent, node);
+		rb_erase(node, &pos->root);
+		pos->num_extents--;
+		kfree(ext);
+	}
+}
diff --git a/kernel/power/extents.h b/kernel/power/extents.h
new file mode 100644
index 0000000..0b69b8e
--- /dev/null
+++ b/kernel/power/extents.h
@@ -0,0 +1,35 @@
+/*
+ * linux/kernel/power/extents.h
+ *
+ * Copyright (C) 2010 Nigel Cunningham <nigel@tuxonice.net>
+ *
+ * This file is released under the GPLv2.
+ *
+ */
+
+#include <linux/rbtree.h>
+
+struct hib_extent {
+	struct rb_node node;
+	unsigned long start;
+	unsigned long end;
+};
+
+struct hib_extent_state {
+	/* Tree */
+	struct rb_root root;
+	int num_extents;
+
+	/* Current position */
+	struct rb_node *node;
+	struct hib_extent *cur_ext;
+	unsigned long offset;
+};
+
+
+void hib_reset_extent_pos(struct hib_extent_state *pos);
+unsigned long hib_extent_current(struct hib_extent_state *pos);
+unsigned long hib_extent_next(struct hib_extent_state *pos);
+int hib_extents_insert(struct hib_extent_state *pos, unsigned long value);
+void hib_extents_clear(struct hib_extent_state *pos);
+int hib_extents_empty(struct hib_extent_state *pos);
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index 2ef2bad..da2439d 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -23,9 +23,9 @@
 #include <linux/swap.h>
 #include <linux/swapops.h>
 #include <linux/pm.h>
-#include <linux/slab.h>
 
 #include "power.h"
+#include "extents.h"
 
 #define SWSUSP_SIG	"S1SUSPEND"
 
@@ -76,97 +76,14 @@ struct swsusp_header {
 
 static struct swsusp_header *swsusp_header;
 
-/**
- *	The following functions are used for tracing the allocated
- *	swap pages, so that they can be freed in case of an error.
- */
-
-struct swsusp_extent {
-	struct rb_node node;
-	unsigned long start;
-	unsigned long end;
-};
-
-static struct rb_root swsusp_extents = RB_ROOT;
-
-struct storage_position {
-	struct rb_node *node;
-	struct swsusp_extent *cur_ext;
-	unsigned long offset;
-};
-
-static struct storage_position pos;
-
-static void reset_storage_pos(void)
-{
-	pos.node = rb_first(&swsusp_extents);
-
-	if (!pos.node) {
-		pos.cur_ext = NULL;
-		pos.offset = 0;
-		return;
-	}
-
-	pos.cur_ext = container_of(pos.node, struct swsusp_extent, node);
-	pos.offset = pos.cur_ext->start;
-}
+static struct hib_extent_state swap_extents;
 
 static sector_t next_swapdev_block(void)
 {
-	if (!pos.node)
-		return 0;
-
-	if (pos.cur_ext->end >= pos.offset)
-		return pos.offset++;
-
-	pos.node = rb_next(pos.node);
-	if (!pos.node)
-		return 0;
-
-	pos.cur_ext = container_of(pos.node, struct swsusp_extent, node);
-	pos.offset = pos.cur_ext->start;
-	return pos.offset;
-}
-
-static int swsusp_extents_insert(unsigned long swap_offset)
-{
-	struct rb_node **new = &(swsusp_extents.rb_node);
-	struct rb_node *parent = NULL;
-	struct swsusp_extent *ext;
-
-	/* Figure out where to put the new node */
-	while (*new) {
-		ext = container_of(*new, struct swsusp_extent, node);
-		parent = *new;
-		if (swap_offset < ext->start) {
-			/* Try to merge */
-			if (swap_offset == ext->start - 1) {
-				ext->start--;
-				return 0;
-			}
-			new = &((*new)->rb_left);
-		} else if (swap_offset > ext->end) {
-			/* Try to merge */
-			if (swap_offset == ext->end + 1) {
-				ext->end++;
-				return 0;
-			}
-			new = &((*new)->rb_right);
-		} else {
-			/* It already is in the tree */
-			return -EINVAL;
-		}
-	}
-	/* Add the new node and rebalance the tree. */
-	ext = kzalloc(sizeof(struct swsusp_extent), GFP_KERNEL);
-	if (!ext)
-		return -ENOMEM;
-
-	ext->start = swap_offset;
-	ext->end = swap_offset;
-	rb_link_node(&ext->node, parent, new);
-	rb_insert_color(&ext->node, &swsusp_extents);
-	return 0;
+	unsigned long res = hib_extent_next(&swap_extents);
+	if (res)
+		res = swapdev_block(root_swap, res);
+	return res;
 }
 
 /**
@@ -180,7 +97,7 @@ sector_t alloc_swapdev_block(int swap)
 
 	offset = swp_offset(get_swap_page_of_type(swap));
 	if (offset) {
-		if (swsusp_extents_insert(offset))
+		if (hib_extents_insert(&swap_extents, offset))
 			swap_free(swp_entry(swap, offset));
 		else
 			return swapdev_block(swap, offset);
@@ -224,7 +141,7 @@ static int allocate_swap(unsigned int nr_pages)
 		return 0;
 	}
 
-	reset_storage_pos();
+	hib_reset_extent_pos(&swap_extents);
 	return 1;
 }
 
@@ -236,24 +153,18 @@ static int allocate_swap(unsigned int nr_pages)
 
 void free_all_swap_pages(int swap)
 {
-	struct rb_node *node;
-
-	while ((node = swsusp_extents.rb_node)) {
-		struct swsusp_extent *ext;
-		unsigned long offset;
+	unsigned long offset;
 
-		ext = container_of(node, struct swsusp_extent, node);
-		rb_erase(node, &swsusp_extents);
-		for (offset = ext->start; offset <= ext->end; offset++)
-			swap_free(swp_entry(swap, offset));
+	hib_reset_extent_pos(&swap_extents);
+	while ((offset = hib_extent_next(&swap_extents)))
+		swap_free(swp_entry(swap, offset));
 
-		kfree(ext);
-	}
+	hib_extents_clear(&swap_extents);
 }
 
 int swsusp_swap_in_use(void)
 {
-	return (swsusp_extents.rb_node != NULL);
+	return (!hib_extents_empty(&swap_extents));
 }
 
 /*
-- 
1.7.0.4


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

* [PATCH 07/22] Hibernation: Generic extents support.
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (14 preceding siblings ...)
  2010-09-25  4:16 ` Nigel Cunningham
@ 2010-09-25  4:16 ` Nigel Cunningham
  2010-09-25  4:16 ` [PATCH 08/22] Hibernation: Iterate over sectors not swap entries Nigel Cunningham
                   ` (39 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Separate out the extent storage and manipulation into a separate
file and make them more generic, so we can also use extents for
recording what sectors are used and (later) support multiple
storage devices more easily.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/Makefile  |    2 +-
 kernel/power/extents.c |  125 ++++++++++++++++++++++++++++++++++++++++++++++++
 kernel/power/extents.h |   35 +++++++++++++
 kernel/power/swap.c    |  117 +++++---------------------------------------
 4 files changed, 175 insertions(+), 104 deletions(-)
 create mode 100644 kernel/power/extents.c
 create mode 100644 kernel/power/extents.h

diff --git a/kernel/power/Makefile b/kernel/power/Makefile
index f9063c6..df24cab 100644
--- a/kernel/power/Makefile
+++ b/kernel/power/Makefile
@@ -9,7 +9,7 @@ obj-$(CONFIG_FREEZER)		+= process.o
 obj-$(CONFIG_SUSPEND)		+= suspend.o
 obj-$(CONFIG_PM_TEST_SUSPEND)	+= suspend_test.o
 obj-$(CONFIG_HIBERNATION)	+= hibernate.o snapshot.o swap.o user.o \
-				   block_io.o
+				   block_io.o extents.o
 obj-$(CONFIG_SUSPEND_NVS)	+= nvs.o
 
 obj-$(CONFIG_MAGIC_SYSRQ)	+= poweroff.o
diff --git a/kernel/power/extents.c b/kernel/power/extents.c
new file mode 100644
index 0000000..172322d
--- /dev/null
+++ b/kernel/power/extents.c
@@ -0,0 +1,125 @@
+/*
+ * linux/kernel/power/extents.c
+ *
+ * This file provides functions for storing and using a series of
+ * extents.
+ *
+ * Copyright (C) 1998,2001-2005 Pavel Machek <pavel@suse.cz>
+ * Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl>
+ * Copyright (C) 2010 Nigel Cunningham <nigel@tuxonice.net>
+ *
+ * This file is released under the GPLv2.
+ *
+ */
+
+#include <linux/slab.h>
+#include "extents.h"
+
+int hib_extents_empty(struct hib_extent_state *pos)
+{
+	return RB_EMPTY_ROOT(&pos->root);
+}
+
+void hib_reset_extent_pos(struct hib_extent_state *pos)
+{
+	if (hib_extents_empty(pos))
+		return;
+
+	pos->node = rb_first(&pos->root);
+
+	if (!pos->node) {
+		pos->cur_ext = NULL;
+		pos->offset = 0;
+		return;
+	}
+
+	pos->cur_ext = container_of(pos->node, struct hib_extent, node);
+	pos->offset = pos->cur_ext->start;
+}
+
+unsigned long hib_extent_current(struct hib_extent_state *pos)
+{
+	return (pos->node) ? pos->offset : 0;
+}
+
+unsigned long hib_extent_next(struct hib_extent_state *pos)
+{
+	if (!pos->node)
+		return 0;
+
+	if (pos->cur_ext->end >= pos->offset)
+		return pos->offset++;
+
+	pos->node = rb_next(pos->node);
+	if (!pos->node)
+		return 0;
+
+	pos->cur_ext = container_of(pos->node, struct hib_extent, node);
+	pos->offset = pos->cur_ext->start;
+	return pos->offset;
+}
+
+int hib_extents_insert(struct hib_extent_state *pos, unsigned long value)
+{
+	struct rb_node **new = &(pos->root.rb_node);
+	struct rb_node *parent = NULL;
+	struct hib_extent *ext;
+
+	/* Figure out where to put the new node */
+	while (*new) {
+		ext = container_of(*new, struct hib_extent, node);
+		parent = *new;
+		if (value < ext->start) {
+			/* Try to merge */
+			if (value == ext->start - 1) {
+				ext->start--;
+				return 0;
+			}
+			new = &((*new)->rb_left);
+		} else if (value > ext->end) {
+			/* Try to merge */
+			if (value == ext->end + 1) {
+				ext->end++;
+				return 0;
+			}
+			new = &((*new)->rb_right);
+		} else {
+			/* It already is in the tree */
+			return -EINVAL;
+		}
+	}
+	/* Add the new node and rebalance the tree. */
+	ext = kzalloc(sizeof(struct hib_extent), GFP_KERNEL);
+	if (!ext)
+		return -ENOMEM;
+
+	ext->start = value;
+	ext->end = value;
+	rb_link_node(&ext->node, parent, new);
+	rb_insert_color(&ext->node, &pos->root);
+	pos->num_extents++;
+	return 0;
+}
+
+/**
+ *	free_all_swap_pages - free swap pages allocated for saving image data.
+ *	It also frees the extents used to register which swap entres had been
+ *	allocated.
+ */
+
+void hib_extents_clear(struct hib_extent_state *pos)
+{
+	struct rb_node *node;
+
+	if (hib_extents_empty(pos))
+		return;
+
+	while ((node = pos->root.rb_node)) {
+		struct hib_extent *ext;
+
+		ext = container_of(node, struct hib_extent, node);
+		rb_erase(node, &pos->root);
+		pos->num_extents--;
+		kfree(ext);
+	}
+}
diff --git a/kernel/power/extents.h b/kernel/power/extents.h
new file mode 100644
index 0000000..0b69b8e
--- /dev/null
+++ b/kernel/power/extents.h
@@ -0,0 +1,35 @@
+/*
+ * linux/kernel/power/extents.h
+ *
+ * Copyright (C) 2010 Nigel Cunningham <nigel@tuxonice.net>
+ *
+ * This file is released under the GPLv2.
+ *
+ */
+
+#include <linux/rbtree.h>
+
+struct hib_extent {
+	struct rb_node node;
+	unsigned long start;
+	unsigned long end;
+};
+
+struct hib_extent_state {
+	/* Tree */
+	struct rb_root root;
+	int num_extents;
+
+	/* Current position */
+	struct rb_node *node;
+	struct hib_extent *cur_ext;
+	unsigned long offset;
+};
+
+
+void hib_reset_extent_pos(struct hib_extent_state *pos);
+unsigned long hib_extent_current(struct hib_extent_state *pos);
+unsigned long hib_extent_next(struct hib_extent_state *pos);
+int hib_extents_insert(struct hib_extent_state *pos, unsigned long value);
+void hib_extents_clear(struct hib_extent_state *pos);
+int hib_extents_empty(struct hib_extent_state *pos);
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index 2ef2bad..da2439d 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -23,9 +23,9 @@
 #include <linux/swap.h>
 #include <linux/swapops.h>
 #include <linux/pm.h>
-#include <linux/slab.h>
 
 #include "power.h"
+#include "extents.h"
 
 #define SWSUSP_SIG	"S1SUSPEND"
 
@@ -76,97 +76,14 @@ struct swsusp_header {
 
 static struct swsusp_header *swsusp_header;
 
-/**
- *	The following functions are used for tracing the allocated
- *	swap pages, so that they can be freed in case of an error.
- */
-
-struct swsusp_extent {
-	struct rb_node node;
-	unsigned long start;
-	unsigned long end;
-};
-
-static struct rb_root swsusp_extents = RB_ROOT;
-
-struct storage_position {
-	struct rb_node *node;
-	struct swsusp_extent *cur_ext;
-	unsigned long offset;
-};
-
-static struct storage_position pos;
-
-static void reset_storage_pos(void)
-{
-	pos.node = rb_first(&swsusp_extents);
-
-	if (!pos.node) {
-		pos.cur_ext = NULL;
-		pos.offset = 0;
-		return;
-	}
-
-	pos.cur_ext = container_of(pos.node, struct swsusp_extent, node);
-	pos.offset = pos.cur_ext->start;
-}
+static struct hib_extent_state swap_extents;
 
 static sector_t next_swapdev_block(void)
 {
-	if (!pos.node)
-		return 0;
-
-	if (pos.cur_ext->end >= pos.offset)
-		return pos.offset++;
-
-	pos.node = rb_next(pos.node);
-	if (!pos.node)
-		return 0;
-
-	pos.cur_ext = container_of(pos.node, struct swsusp_extent, node);
-	pos.offset = pos.cur_ext->start;
-	return pos.offset;
-}
-
-static int swsusp_extents_insert(unsigned long swap_offset)
-{
-	struct rb_node **new = &(swsusp_extents.rb_node);
-	struct rb_node *parent = NULL;
-	struct swsusp_extent *ext;
-
-	/* Figure out where to put the new node */
-	while (*new) {
-		ext = container_of(*new, struct swsusp_extent, node);
-		parent = *new;
-		if (swap_offset < ext->start) {
-			/* Try to merge */
-			if (swap_offset == ext->start - 1) {
-				ext->start--;
-				return 0;
-			}
-			new = &((*new)->rb_left);
-		} else if (swap_offset > ext->end) {
-			/* Try to merge */
-			if (swap_offset == ext->end + 1) {
-				ext->end++;
-				return 0;
-			}
-			new = &((*new)->rb_right);
-		} else {
-			/* It already is in the tree */
-			return -EINVAL;
-		}
-	}
-	/* Add the new node and rebalance the tree. */
-	ext = kzalloc(sizeof(struct swsusp_extent), GFP_KERNEL);
-	if (!ext)
-		return -ENOMEM;
-
-	ext->start = swap_offset;
-	ext->end = swap_offset;
-	rb_link_node(&ext->node, parent, new);
-	rb_insert_color(&ext->node, &swsusp_extents);
-	return 0;
+	unsigned long res = hib_extent_next(&swap_extents);
+	if (res)
+		res = swapdev_block(root_swap, res);
+	return res;
 }
 
 /**
@@ -180,7 +97,7 @@ sector_t alloc_swapdev_block(int swap)
 
 	offset = swp_offset(get_swap_page_of_type(swap));
 	if (offset) {
-		if (swsusp_extents_insert(offset))
+		if (hib_extents_insert(&swap_extents, offset))
 			swap_free(swp_entry(swap, offset));
 		else
 			return swapdev_block(swap, offset);
@@ -224,7 +141,7 @@ static int allocate_swap(unsigned int nr_pages)
 		return 0;
 	}
 
-	reset_storage_pos();
+	hib_reset_extent_pos(&swap_extents);
 	return 1;
 }
 
@@ -236,24 +153,18 @@ static int allocate_swap(unsigned int nr_pages)
 
 void free_all_swap_pages(int swap)
 {
-	struct rb_node *node;
-
-	while ((node = swsusp_extents.rb_node)) {
-		struct swsusp_extent *ext;
-		unsigned long offset;
+	unsigned long offset;
 
-		ext = container_of(node, struct swsusp_extent, node);
-		rb_erase(node, &swsusp_extents);
-		for (offset = ext->start; offset <= ext->end; offset++)
-			swap_free(swp_entry(swap, offset));
+	hib_reset_extent_pos(&swap_extents);
+	while ((offset = hib_extent_next(&swap_extents)))
+		swap_free(swp_entry(swap, offset));
 
-		kfree(ext);
-	}
+	hib_extents_clear(&swap_extents);
 }
 
 int swsusp_swap_in_use(void)
 {
-	return (swsusp_extents.rb_node != NULL);
+	return (!hib_extents_empty(&swap_extents));
 }
 
 /*
-- 
1.7.0.4

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

* [PATCH 07/22] Hibernation: Generic extents support.
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (12 preceding siblings ...)
  2010-09-25  4:16 ` Nigel Cunningham
@ 2010-09-25  4:16 ` Nigel Cunningham
  2010-09-25  4:16 ` Nigel Cunningham
                   ` (41 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Separate out the extent storage and manipulation into a separate
file and make them more generic, so we can also use extents for
recording what sectors are used and (later) support multiple
storage devices more easily.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/Makefile  |    2 +-
 kernel/power/extents.c |  125 ++++++++++++++++++++++++++++++++++++++++++++++++
 kernel/power/extents.h |   35 +++++++++++++
 kernel/power/swap.c    |  117 +++++---------------------------------------
 4 files changed, 175 insertions(+), 104 deletions(-)
 create mode 100644 kernel/power/extents.c
 create mode 100644 kernel/power/extents.h

diff --git a/kernel/power/Makefile b/kernel/power/Makefile
index f9063c6..df24cab 100644
--- a/kernel/power/Makefile
+++ b/kernel/power/Makefile
@@ -9,7 +9,7 @@ obj-$(CONFIG_FREEZER)		+= process.o
 obj-$(CONFIG_SUSPEND)		+= suspend.o
 obj-$(CONFIG_PM_TEST_SUSPEND)	+= suspend_test.o
 obj-$(CONFIG_HIBERNATION)	+= hibernate.o snapshot.o swap.o user.o \
-				   block_io.o
+				   block_io.o extents.o
 obj-$(CONFIG_SUSPEND_NVS)	+= nvs.o
 
 obj-$(CONFIG_MAGIC_SYSRQ)	+= poweroff.o
diff --git a/kernel/power/extents.c b/kernel/power/extents.c
new file mode 100644
index 0000000..172322d
--- /dev/null
+++ b/kernel/power/extents.c
@@ -0,0 +1,125 @@
+/*
+ * linux/kernel/power/extents.c
+ *
+ * This file provides functions for storing and using a series of
+ * extents.
+ *
+ * Copyright (C) 1998,2001-2005 Pavel Machek <pavel@suse.cz>
+ * Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl>
+ * Copyright (C) 2010 Nigel Cunningham <nigel@tuxonice.net>
+ *
+ * This file is released under the GPLv2.
+ *
+ */
+
+#include <linux/slab.h>
+#include "extents.h"
+
+int hib_extents_empty(struct hib_extent_state *pos)
+{
+	return RB_EMPTY_ROOT(&pos->root);
+}
+
+void hib_reset_extent_pos(struct hib_extent_state *pos)
+{
+	if (hib_extents_empty(pos))
+		return;
+
+	pos->node = rb_first(&pos->root);
+
+	if (!pos->node) {
+		pos->cur_ext = NULL;
+		pos->offset = 0;
+		return;
+	}
+
+	pos->cur_ext = container_of(pos->node, struct hib_extent, node);
+	pos->offset = pos->cur_ext->start;
+}
+
+unsigned long hib_extent_current(struct hib_extent_state *pos)
+{
+	return (pos->node) ? pos->offset : 0;
+}
+
+unsigned long hib_extent_next(struct hib_extent_state *pos)
+{
+	if (!pos->node)
+		return 0;
+
+	if (pos->cur_ext->end >= pos->offset)
+		return pos->offset++;
+
+	pos->node = rb_next(pos->node);
+	if (!pos->node)
+		return 0;
+
+	pos->cur_ext = container_of(pos->node, struct hib_extent, node);
+	pos->offset = pos->cur_ext->start;
+	return pos->offset;
+}
+
+int hib_extents_insert(struct hib_extent_state *pos, unsigned long value)
+{
+	struct rb_node **new = &(pos->root.rb_node);
+	struct rb_node *parent = NULL;
+	struct hib_extent *ext;
+
+	/* Figure out where to put the new node */
+	while (*new) {
+		ext = container_of(*new, struct hib_extent, node);
+		parent = *new;
+		if (value < ext->start) {
+			/* Try to merge */
+			if (value == ext->start - 1) {
+				ext->start--;
+				return 0;
+			}
+			new = &((*new)->rb_left);
+		} else if (value > ext->end) {
+			/* Try to merge */
+			if (value == ext->end + 1) {
+				ext->end++;
+				return 0;
+			}
+			new = &((*new)->rb_right);
+		} else {
+			/* It already is in the tree */
+			return -EINVAL;
+		}
+	}
+	/* Add the new node and rebalance the tree. */
+	ext = kzalloc(sizeof(struct hib_extent), GFP_KERNEL);
+	if (!ext)
+		return -ENOMEM;
+
+	ext->start = value;
+	ext->end = value;
+	rb_link_node(&ext->node, parent, new);
+	rb_insert_color(&ext->node, &pos->root);
+	pos->num_extents++;
+	return 0;
+}
+
+/**
+ *	free_all_swap_pages - free swap pages allocated for saving image data.
+ *	It also frees the extents used to register which swap entres had been
+ *	allocated.
+ */
+
+void hib_extents_clear(struct hib_extent_state *pos)
+{
+	struct rb_node *node;
+
+	if (hib_extents_empty(pos))
+		return;
+
+	while ((node = pos->root.rb_node)) {
+		struct hib_extent *ext;
+
+		ext = container_of(node, struct hib_extent, node);
+		rb_erase(node, &pos->root);
+		pos->num_extents--;
+		kfree(ext);
+	}
+}
diff --git a/kernel/power/extents.h b/kernel/power/extents.h
new file mode 100644
index 0000000..0b69b8e
--- /dev/null
+++ b/kernel/power/extents.h
@@ -0,0 +1,35 @@
+/*
+ * linux/kernel/power/extents.h
+ *
+ * Copyright (C) 2010 Nigel Cunningham <nigel@tuxonice.net>
+ *
+ * This file is released under the GPLv2.
+ *
+ */
+
+#include <linux/rbtree.h>
+
+struct hib_extent {
+	struct rb_node node;
+	unsigned long start;
+	unsigned long end;
+};
+
+struct hib_extent_state {
+	/* Tree */
+	struct rb_root root;
+	int num_extents;
+
+	/* Current position */
+	struct rb_node *node;
+	struct hib_extent *cur_ext;
+	unsigned long offset;
+};
+
+
+void hib_reset_extent_pos(struct hib_extent_state *pos);
+unsigned long hib_extent_current(struct hib_extent_state *pos);
+unsigned long hib_extent_next(struct hib_extent_state *pos);
+int hib_extents_insert(struct hib_extent_state *pos, unsigned long value);
+void hib_extents_clear(struct hib_extent_state *pos);
+int hib_extents_empty(struct hib_extent_state *pos);
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index 2ef2bad..da2439d 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -23,9 +23,9 @@
 #include <linux/swap.h>
 #include <linux/swapops.h>
 #include <linux/pm.h>
-#include <linux/slab.h>
 
 #include "power.h"
+#include "extents.h"
 
 #define SWSUSP_SIG	"S1SUSPEND"
 
@@ -76,97 +76,14 @@ struct swsusp_header {
 
 static struct swsusp_header *swsusp_header;
 
-/**
- *	The following functions are used for tracing the allocated
- *	swap pages, so that they can be freed in case of an error.
- */
-
-struct swsusp_extent {
-	struct rb_node node;
-	unsigned long start;
-	unsigned long end;
-};
-
-static struct rb_root swsusp_extents = RB_ROOT;
-
-struct storage_position {
-	struct rb_node *node;
-	struct swsusp_extent *cur_ext;
-	unsigned long offset;
-};
-
-static struct storage_position pos;
-
-static void reset_storage_pos(void)
-{
-	pos.node = rb_first(&swsusp_extents);
-
-	if (!pos.node) {
-		pos.cur_ext = NULL;
-		pos.offset = 0;
-		return;
-	}
-
-	pos.cur_ext = container_of(pos.node, struct swsusp_extent, node);
-	pos.offset = pos.cur_ext->start;
-}
+static struct hib_extent_state swap_extents;
 
 static sector_t next_swapdev_block(void)
 {
-	if (!pos.node)
-		return 0;
-
-	if (pos.cur_ext->end >= pos.offset)
-		return pos.offset++;
-
-	pos.node = rb_next(pos.node);
-	if (!pos.node)
-		return 0;
-
-	pos.cur_ext = container_of(pos.node, struct swsusp_extent, node);
-	pos.offset = pos.cur_ext->start;
-	return pos.offset;
-}
-
-static int swsusp_extents_insert(unsigned long swap_offset)
-{
-	struct rb_node **new = &(swsusp_extents.rb_node);
-	struct rb_node *parent = NULL;
-	struct swsusp_extent *ext;
-
-	/* Figure out where to put the new node */
-	while (*new) {
-		ext = container_of(*new, struct swsusp_extent, node);
-		parent = *new;
-		if (swap_offset < ext->start) {
-			/* Try to merge */
-			if (swap_offset == ext->start - 1) {
-				ext->start--;
-				return 0;
-			}
-			new = &((*new)->rb_left);
-		} else if (swap_offset > ext->end) {
-			/* Try to merge */
-			if (swap_offset == ext->end + 1) {
-				ext->end++;
-				return 0;
-			}
-			new = &((*new)->rb_right);
-		} else {
-			/* It already is in the tree */
-			return -EINVAL;
-		}
-	}
-	/* Add the new node and rebalance the tree. */
-	ext = kzalloc(sizeof(struct swsusp_extent), GFP_KERNEL);
-	if (!ext)
-		return -ENOMEM;
-
-	ext->start = swap_offset;
-	ext->end = swap_offset;
-	rb_link_node(&ext->node, parent, new);
-	rb_insert_color(&ext->node, &swsusp_extents);
-	return 0;
+	unsigned long res = hib_extent_next(&swap_extents);
+	if (res)
+		res = swapdev_block(root_swap, res);
+	return res;
 }
 
 /**
@@ -180,7 +97,7 @@ sector_t alloc_swapdev_block(int swap)
 
 	offset = swp_offset(get_swap_page_of_type(swap));
 	if (offset) {
-		if (swsusp_extents_insert(offset))
+		if (hib_extents_insert(&swap_extents, offset))
 			swap_free(swp_entry(swap, offset));
 		else
 			return swapdev_block(swap, offset);
@@ -224,7 +141,7 @@ static int allocate_swap(unsigned int nr_pages)
 		return 0;
 	}
 
-	reset_storage_pos();
+	hib_reset_extent_pos(&swap_extents);
 	return 1;
 }
 
@@ -236,24 +153,18 @@ static int allocate_swap(unsigned int nr_pages)
 
 void free_all_swap_pages(int swap)
 {
-	struct rb_node *node;
-
-	while ((node = swsusp_extents.rb_node)) {
-		struct swsusp_extent *ext;
-		unsigned long offset;
+	unsigned long offset;
 
-		ext = container_of(node, struct swsusp_extent, node);
-		rb_erase(node, &swsusp_extents);
-		for (offset = ext->start; offset <= ext->end; offset++)
-			swap_free(swp_entry(swap, offset));
+	hib_reset_extent_pos(&swap_extents);
+	while ((offset = hib_extent_next(&swap_extents)))
+		swap_free(swp_entry(swap, offset));
 
-		kfree(ext);
-	}
+	hib_extents_clear(&swap_extents);
 }
 
 int swsusp_swap_in_use(void)
 {
-	return (swsusp_extents.rb_node != NULL);
+	return (!hib_extents_empty(&swap_extents));
 }
 
 /*
-- 
1.7.0.4


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

* [PATCH 08/22] Hibernation: Iterate over sectors not swap entries.
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (15 preceding siblings ...)
  2010-09-25  4:16 ` Nigel Cunningham
@ 2010-09-25  4:16 ` Nigel Cunningham
  2010-09-25  4:16 ` Nigel Cunningham
                   ` (38 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Record sectors in extents when allocating storage, and use the
sector numbers instead of swap offsets as we write the image. If
we then store these sector extents at the start of the image (as
following patches will do), we can drop the index pages that are
interspersed with the image, do fully asynchronous I/O (which
should give a speed boost) and perhaps also remove some of the
duplication in the paths for reading and writing pages.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/swap.c |   25 ++++++++++---------------
 1 files changed, 10 insertions(+), 15 deletions(-)

diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index da2439d..0c87522 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -77,14 +77,7 @@ struct swsusp_header {
 static struct swsusp_header *swsusp_header;
 
 static struct hib_extent_state swap_extents;
-
-static sector_t next_swapdev_block(void)
-{
-	unsigned long res = hib_extent_next(&swap_extents);
-	if (res)
-		res = swapdev_block(root_swap, res);
-	return res;
-}
+static struct hib_extent_state sector_extents;
 
 /**
  *	alloc_swapdev_block - allocate a swap page and register that it has
@@ -93,14 +86,16 @@ static sector_t next_swapdev_block(void)
 
 sector_t alloc_swapdev_block(int swap)
 {
-	unsigned long offset;
+	unsigned long offset, sector;
 
 	offset = swp_offset(get_swap_page_of_type(swap));
 	if (offset) {
-		if (hib_extents_insert(&swap_extents, offset))
+		sector = swapdev_block(swap, offset);
+		if (hib_extents_insert(&swap_extents, offset) ||
+		    hib_extents_insert(&sector_extents, sector))
 			swap_free(swp_entry(swap, offset));
 		else
-			return swapdev_block(swap, offset);
+			return sector;
 	}
 	return 0;
 }
@@ -141,7 +136,7 @@ static int allocate_swap(unsigned int nr_pages)
 		return 0;
 	}
 
-	hib_reset_extent_pos(&swap_extents);
+	hib_reset_extent_pos(&sector_extents);
 	return 1;
 }
 
@@ -283,7 +278,7 @@ static int get_swap_writer(struct swap_map_handle *handle, unsigned long pages)
 		ret = -ENOSPC;
 		goto err_close;
 	}
-	handle->cur_swap = next_swapdev_block();
+	handle->cur_swap = hib_extent_next(&sector_extents);
 	if (!handle->cur_swap) {
 		ret = -ENOSPC;
 		goto err_rel;
@@ -306,7 +301,7 @@ static int swap_write_page(struct swap_map_handle *handle, void *buf,
 
 	if (!handle->cur)
 		return -EINVAL;
-	offset = next_swapdev_block();
+	offset = hib_extent_next(&sector_extents);
 	error = write_page(buf, offset, bio_chain);
 	if (error)
 		return error;
@@ -315,7 +310,7 @@ static int swap_write_page(struct swap_map_handle *handle, void *buf,
 		error = hib_wait_on_bio_chain(bio_chain);
 		if (error)
 			goto out;
-		offset = next_swapdev_block();
+		offset = hib_extent_next(&sector_extents);
 		if (!offset)
 			return -ENOSPC;
 		handle->cur->next_swap = offset;
-- 
1.7.0.4


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

* [PATCH 08/22] Hibernation: Iterate over sectors not swap entries.
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (16 preceding siblings ...)
  2010-09-25  4:16 ` [PATCH 08/22] Hibernation: Iterate over sectors not swap entries Nigel Cunningham
@ 2010-09-25  4:16 ` Nigel Cunningham
  2010-09-25  4:16 ` [PATCH 09/22] Hibernation: Stop passing swap_map_handle struct Nigel Cunningham
                   ` (37 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Record sectors in extents when allocating storage, and use the
sector numbers instead of swap offsets as we write the image. If
we then store these sector extents at the start of the image (as
following patches will do), we can drop the index pages that are
interspersed with the image, do fully asynchronous I/O (which
should give a speed boost) and perhaps also remove some of the
duplication in the paths for reading and writing pages.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/swap.c |   25 ++++++++++---------------
 1 files changed, 10 insertions(+), 15 deletions(-)

diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index da2439d..0c87522 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -77,14 +77,7 @@ struct swsusp_header {
 static struct swsusp_header *swsusp_header;
 
 static struct hib_extent_state swap_extents;
-
-static sector_t next_swapdev_block(void)
-{
-	unsigned long res = hib_extent_next(&swap_extents);
-	if (res)
-		res = swapdev_block(root_swap, res);
-	return res;
-}
+static struct hib_extent_state sector_extents;
 
 /**
  *	alloc_swapdev_block - allocate a swap page and register that it has
@@ -93,14 +86,16 @@ static sector_t next_swapdev_block(void)
 
 sector_t alloc_swapdev_block(int swap)
 {
-	unsigned long offset;
+	unsigned long offset, sector;
 
 	offset = swp_offset(get_swap_page_of_type(swap));
 	if (offset) {
-		if (hib_extents_insert(&swap_extents, offset))
+		sector = swapdev_block(swap, offset);
+		if (hib_extents_insert(&swap_extents, offset) ||
+		    hib_extents_insert(&sector_extents, sector))
 			swap_free(swp_entry(swap, offset));
 		else
-			return swapdev_block(swap, offset);
+			return sector;
 	}
 	return 0;
 }
@@ -141,7 +136,7 @@ static int allocate_swap(unsigned int nr_pages)
 		return 0;
 	}
 
-	hib_reset_extent_pos(&swap_extents);
+	hib_reset_extent_pos(&sector_extents);
 	return 1;
 }
 
@@ -283,7 +278,7 @@ static int get_swap_writer(struct swap_map_handle *handle, unsigned long pages)
 		ret = -ENOSPC;
 		goto err_close;
 	}
-	handle->cur_swap = next_swapdev_block();
+	handle->cur_swap = hib_extent_next(&sector_extents);
 	if (!handle->cur_swap) {
 		ret = -ENOSPC;
 		goto err_rel;
@@ -306,7 +301,7 @@ static int swap_write_page(struct swap_map_handle *handle, void *buf,
 
 	if (!handle->cur)
 		return -EINVAL;
-	offset = next_swapdev_block();
+	offset = hib_extent_next(&sector_extents);
 	error = write_page(buf, offset, bio_chain);
 	if (error)
 		return error;
@@ -315,7 +310,7 @@ static int swap_write_page(struct swap_map_handle *handle, void *buf,
 		error = hib_wait_on_bio_chain(bio_chain);
 		if (error)
 			goto out;
-		offset = next_swapdev_block();
+		offset = hib_extent_next(&sector_extents);
 		if (!offset)
 			return -ENOSPC;
 		handle->cur->next_swap = offset;
-- 
1.7.0.4

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

* [PATCH 09/22] Hibernation: Stop passing swap_map_handle struct
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (17 preceding siblings ...)
  2010-09-25  4:16 ` Nigel Cunningham
@ 2010-09-25  4:16 ` Nigel Cunningham
  2010-09-25  4:16 ` Nigel Cunningham
                   ` (36 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Stop passing the swap_map_handle struct around. It's a local (to the
file) variable and continuing to pass it around will create ugliness
as I work to disentangle swap specific functions from block i/o and
put them in separate files.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/swap.c |  135 ++++++++++++++++++++++++---------------------------
 1 files changed, 64 insertions(+), 71 deletions(-)

diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index 0c87522..1df890f 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -63,6 +63,8 @@ struct swap_map_handle {
 	unsigned int k;
 };
 
+static struct swap_map_handle handle;
+
 static unsigned short root_swap = 0xffff;
 
 struct swsusp_header {
@@ -173,7 +175,7 @@ char __nosavedata write_speed, read_speed;
  * Saving part
  */
 
-static int mark_swapfiles(struct swap_map_handle *handle, unsigned int flags)
+static int mark_swapfiles(unsigned int flags)
 {
 	int error;
 
@@ -183,7 +185,7 @@ static int mark_swapfiles(struct swap_map_handle *handle, unsigned int flags)
 		memcpy(swsusp_header->orig_sig,swsusp_header->sig, 10);
 		memcpy(swsusp_header->sig,SWSUSP_SIG, 10);
 		swsusp_header->write_speed = write_speed;
-		swsusp_header->image = handle->first_sector;
+		swsusp_header->image = handle.first_sector;
 		swsusp_header->flags = flags;
 		error = hib_bio_write_page(swsusp_resume_block,
 					swsusp_header, NULL);
@@ -250,14 +252,14 @@ static int write_page(void *buf, sector_t offset, struct bio **bio_chain)
 	return hib_bio_write_page(offset, src, bio_chain);
 }
 
-static void release_swap_writer(struct swap_map_handle *handle)
+static void release_swap_writer(void)
 {
-	if (handle->cur)
-		free_page((unsigned long)handle->cur);
-	handle->cur = NULL;
+	if (handle.cur)
+		free_page((unsigned long)handle.cur);
+	handle.cur = NULL;
 }
 
-static int get_swap_writer(struct swap_map_handle *handle, unsigned long pages)
+static int get_swap_writer(unsigned long pages)
 {
 	int ret;
 
@@ -268,8 +270,8 @@ static int get_swap_writer(struct swap_map_handle *handle, unsigned long pages)
 					"swapon -a.\n");
 		return ret;
 	}
-	handle->cur = (struct swap_map_page *)get_zeroed_page(GFP_KERNEL);
-	if (!handle->cur) {
+	handle.cur = (struct swap_map_page *)get_zeroed_page(GFP_KERNEL);
+	if (!handle.cur) {
 		ret = -ENOMEM;
 		goto err_close;
 	}
@@ -278,74 +280,72 @@ static int get_swap_writer(struct swap_map_handle *handle, unsigned long pages)
 		ret = -ENOSPC;
 		goto err_close;
 	}
-	handle->cur_swap = hib_extent_next(&sector_extents);
-	if (!handle->cur_swap) {
+	handle.cur_swap = hib_extent_next(&sector_extents);
+	if (!handle.cur_swap) {
 		ret = -ENOSPC;
 		goto err_rel;
 	}
-	handle->k = 0;
-	handle->first_sector = handle->cur_swap;
+	handle.k = 0;
+	handle.first_sector = handle.cur_swap;
 	return 0;
 err_rel:
-	release_swap_writer(handle);
+	release_swap_writer();
 err_close:
 	swsusp_close(FMODE_WRITE);
 	return ret;
 }
 
-static int swap_write_page(struct swap_map_handle *handle, void *buf,
-				struct bio **bio_chain)
+static int swap_write_page(void *buf, struct bio **bio_chain)
 {
 	int error = 0;
 	sector_t offset;
 
-	if (!handle->cur)
+	if (!handle.cur)
 		return -EINVAL;
 	offset = hib_extent_next(&sector_extents);
 	error = write_page(buf, offset, bio_chain);
 	if (error)
 		return error;
-	handle->cur->entries[handle->k++] = offset;
-	if (handle->k >= MAP_PAGE_ENTRIES) {
+	handle.cur->entries[handle.k++] = offset;
+	if (handle.k >= MAP_PAGE_ENTRIES) {
 		error = hib_wait_on_bio_chain(bio_chain);
 		if (error)
 			goto out;
 		offset = hib_extent_next(&sector_extents);
 		if (!offset)
 			return -ENOSPC;
-		handle->cur->next_swap = offset;
-		error = write_page(handle->cur, handle->cur_swap, NULL);
+		handle.cur->next_swap = offset;
+		error = write_page(handle.cur, handle.cur_swap, NULL);
 		if (error)
 			goto out;
-		memset(handle->cur, 0, PAGE_SIZE);
-		handle->cur_swap = offset;
-		handle->k = 0;
+		memset(handle.cur, 0, PAGE_SIZE);
+		handle.cur_swap = offset;
+		handle.k = 0;
 	}
  out:
 	return error;
 }
 
-static int flush_swap_writer(struct swap_map_handle *handle)
+static int flush_swap_writer(void)
 {
-	if (handle->cur && handle->cur_swap)
-		return write_page(handle->cur, handle->cur_swap, NULL);
+	if (handle.cur && handle.cur_swap)
+		return write_page(handle.cur, handle.cur_swap, NULL);
 	else
 		return -EINVAL;
 }
 
-static int swap_writer_finish(struct swap_map_handle *handle,
-		unsigned int flags, int error)
+static int swap_writer_finish(unsigned int flags, int error)
 {
 	if (!error) {
-		flush_swap_writer(handle);
+		flush_swap_writer();
 		printk(KERN_INFO "PM: S");
-		error = mark_swapfiles(handle, flags);
+		error = mark_swapfiles(flags);
 		printk("|\n");
 	}
 
 	if (error)
 		free_all_swap_pages(root_swap);
-	release_swap_writer(handle);
+	release_swap_writer();
 	swsusp_close(FMODE_WRITE);
 
 	return error;
@@ -355,8 +355,7 @@ static int swap_writer_finish(struct swap_map_handle *handle,
  *	save_image - save the suspend image data
  */
 
-static int save_image(struct swap_map_handle *handle,
-                      struct snapshot_handle *snapshot,
+static int save_image(struct snapshot_handle *snapshot,
                       unsigned int nr_to_write)
 {
 	unsigned int m;
@@ -380,7 +379,7 @@ static int save_image(struct swap_map_handle *handle,
 		ret = snapshot_read_next(snapshot);
 		if (ret <= 0)
 			break;
-		ret = swap_write_page(handle, data_of(*snapshot), &bio);
+		ret = swap_write_page(data_of(*snapshot), &bio);
 		if (ret)
 			break;
 		if (!(nr_pages % m))
@@ -412,14 +411,13 @@ static int save_image(struct swap_map_handle *handle,
 
 int swsusp_write(unsigned int flags)
 {
-	struct swap_map_handle handle;
 	struct snapshot_handle snapshot;
 	struct swsusp_info *header;
 	unsigned long pages;
 	int error;
 
 	pages = snapshot_get_image_size();
-	error = get_swap_writer(&handle, pages);
+	error = get_swap_writer(pages);
 	if (error) {
 		printk(KERN_ERR "PM: Cannot get swap writer\n");
 		return error;
@@ -433,11 +431,11 @@ int swsusp_write(unsigned int flags)
 		goto out_finish;
 	}
 	header = (struct swsusp_info *)data_of(snapshot);
-	error = swap_write_page(&handle, header, NULL);
+	error = swap_write_page(header, NULL);
 	if (!error)
-		error = save_image(&handle, &snapshot, pages - 1);
+		error = save_image(&snapshot, pages - 1);
 out_finish:
-	error = swap_writer_finish(&handle, flags, error);
+	error = swap_writer_finish(flags, error);
 	return error;
 }
 
@@ -446,15 +444,14 @@ out_finish:
  *	in a file-alike way
  */
 
-static void release_swap_reader(struct swap_map_handle *handle)
+static void release_swap_reader(void)
 {
-	if (handle->cur)
-		free_page((unsigned long)handle->cur);
-	handle->cur = NULL;
+	if (handle.cur)
+		free_page((unsigned long)handle.cur);
+	handle.cur = NULL;
 }
 
-static int get_swap_reader(struct swap_map_handle *handle,
-		unsigned int *flags_p)
+static int get_swap_reader(unsigned int *flags_p)
 {
 	int error;
 
@@ -463,48 +460,47 @@ static int get_swap_reader(struct swap_map_handle *handle,
 	if (!swsusp_header->image) /* how can this happen? */
 		return -EINVAL;
 
-	handle->cur = (struct swap_map_page *)get_zeroed_page(__GFP_WAIT | __GFP_HIGH);
-	if (!handle->cur)
+	handle.cur = (struct swap_map_page *)get_zeroed_page(__GFP_WAIT | __GFP_HIGH);
+	if (!handle.cur)
 		return -ENOMEM;
 
-	error = hib_bio_read_page(swsusp_header->image, handle->cur, NULL);
+	error = hib_bio_read_page(swsusp_header->image, handle.cur, NULL);
 	if (error) {
-		release_swap_reader(handle);
+		release_swap_reader();
 		return error;
 	}
-	handle->k = 0;
+	handle.k = 0;
 	return 0;
 }
 
-static int swap_read_page(struct swap_map_handle *handle, void *buf,
-				struct bio **bio_chain)
+static int swap_read_page(void *buf, struct bio **bio_chain)
 {
 	sector_t offset;
 	int error;
 
-	if (!handle->cur)
+	if (!handle.cur)
 		return -EINVAL;
-	offset = handle->cur->entries[handle->k];
+	offset = handle.cur->entries[handle.k];
 	if (!offset)
 		return -EFAULT;
 	error = hib_bio_read_page(offset, buf, bio_chain);
 	if (error)
 		return error;
-	if (++handle->k >= MAP_PAGE_ENTRIES) {
+	if (++handle.k >= MAP_PAGE_ENTRIES) {
 		error = hib_wait_on_bio_chain(bio_chain);
-		handle->k = 0;
-		offset = handle->cur->next_swap;
+		handle.k = 0;
+		offset = handle.cur->next_swap;
 		if (!offset)
-			release_swap_reader(handle);
+			release_swap_reader();
 		else if (!error)
-			error = hib_bio_read_page(offset, handle->cur, NULL);
+			error = hib_bio_read_page(offset, handle.cur, NULL);
 	}
 	return error;
 }
 
-static int swap_reader_finish(struct swap_map_handle *handle)
+static int swap_reader_finish(void)
 {
-	release_swap_reader(handle);
+	release_swap_reader();
 
 	return 0;
 }
@@ -515,9 +511,7 @@ static int swap_reader_finish(struct swap_map_handle *handle)
  *	(assume there are @nr_pages pages to load)
  */
 
-static int load_image(struct swap_map_handle *handle,
-                      struct snapshot_handle *snapshot,
-                      unsigned int nr_to_read)
+static int load_image(struct snapshot_handle *snapshot, unsigned int nr_to_read)
 {
 	unsigned int m;
 	int error = 0;
@@ -540,7 +534,7 @@ static int load_image(struct swap_map_handle *handle,
 		error = snapshot_write_next(snapshot);
 		if (error <= 0)
 			break;
-		error = swap_read_page(handle, data_of(*snapshot), &bio);
+		error = swap_read_page(data_of(*snapshot), &bio);
 		if (error)
 			break;
 		if (snapshot->sync_read)
@@ -576,7 +570,6 @@ static int load_image(struct swap_map_handle *handle,
 int swsusp_read(unsigned int *flags_p)
 {
 	int error;
-	struct swap_map_handle handle;
 	struct snapshot_handle snapshot;
 	struct swsusp_info *header;
 
@@ -585,14 +578,14 @@ int swsusp_read(unsigned int *flags_p)
 	if (error < PAGE_SIZE)
 		return error < 0 ? error : -EFAULT;
 	header = (struct swsusp_info *)data_of(snapshot);
-	error = get_swap_reader(&handle, flags_p);
+	error = get_swap_reader(flags_p);
 	if (error)
 		goto end;
 	if (!error)
-		error = swap_read_page(&handle, header, NULL);
+		error = swap_read_page(header, NULL);
 	if (!error)
-		error = load_image(&handle, &snapshot, header->pages - 1);
-	swap_reader_finish(&handle);
+		error = load_image(&snapshot, header->pages - 1);
+	swap_reader_finish();
 end:
 	if (!error)
 		pr_debug("PM: Image successfully loaded\n");
-- 
1.7.0.4


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

* [PATCH 09/22] Hibernation: Stop passing swap_map_handle struct
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (18 preceding siblings ...)
  2010-09-25  4:16 ` [PATCH 09/22] Hibernation: Stop passing swap_map_handle struct Nigel Cunningham
@ 2010-09-25  4:16 ` Nigel Cunningham
  2010-09-25  4:16 ` [PATCH 10/22] Hibernation: Stop passing bio_chain around Nigel Cunningham
                   ` (35 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Stop passing the swap_map_handle struct around. It's a local (to the
file) variable and continuing to pass it around will create ugliness
as I work to disentangle swap specific functions from block i/o and
put them in separate files.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/swap.c |  135 ++++++++++++++++++++++++---------------------------
 1 files changed, 64 insertions(+), 71 deletions(-)

diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index 0c87522..1df890f 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -63,6 +63,8 @@ struct swap_map_handle {
 	unsigned int k;
 };
 
+static struct swap_map_handle handle;
+
 static unsigned short root_swap = 0xffff;
 
 struct swsusp_header {
@@ -173,7 +175,7 @@ char __nosavedata write_speed, read_speed;
  * Saving part
  */
 
-static int mark_swapfiles(struct swap_map_handle *handle, unsigned int flags)
+static int mark_swapfiles(unsigned int flags)
 {
 	int error;
 
@@ -183,7 +185,7 @@ static int mark_swapfiles(struct swap_map_handle *handle, unsigned int flags)
 		memcpy(swsusp_header->orig_sig,swsusp_header->sig, 10);
 		memcpy(swsusp_header->sig,SWSUSP_SIG, 10);
 		swsusp_header->write_speed = write_speed;
-		swsusp_header->image = handle->first_sector;
+		swsusp_header->image = handle.first_sector;
 		swsusp_header->flags = flags;
 		error = hib_bio_write_page(swsusp_resume_block,
 					swsusp_header, NULL);
@@ -250,14 +252,14 @@ static int write_page(void *buf, sector_t offset, struct bio **bio_chain)
 	return hib_bio_write_page(offset, src, bio_chain);
 }
 
-static void release_swap_writer(struct swap_map_handle *handle)
+static void release_swap_writer(void)
 {
-	if (handle->cur)
-		free_page((unsigned long)handle->cur);
-	handle->cur = NULL;
+	if (handle.cur)
+		free_page((unsigned long)handle.cur);
+	handle.cur = NULL;
 }
 
-static int get_swap_writer(struct swap_map_handle *handle, unsigned long pages)
+static int get_swap_writer(unsigned long pages)
 {
 	int ret;
 
@@ -268,8 +270,8 @@ static int get_swap_writer(struct swap_map_handle *handle, unsigned long pages)
 					"swapon -a.\n");
 		return ret;
 	}
-	handle->cur = (struct swap_map_page *)get_zeroed_page(GFP_KERNEL);
-	if (!handle->cur) {
+	handle.cur = (struct swap_map_page *)get_zeroed_page(GFP_KERNEL);
+	if (!handle.cur) {
 		ret = -ENOMEM;
 		goto err_close;
 	}
@@ -278,74 +280,72 @@ static int get_swap_writer(struct swap_map_handle *handle, unsigned long pages)
 		ret = -ENOSPC;
 		goto err_close;
 	}
-	handle->cur_swap = hib_extent_next(&sector_extents);
-	if (!handle->cur_swap) {
+	handle.cur_swap = hib_extent_next(&sector_extents);
+	if (!handle.cur_swap) {
 		ret = -ENOSPC;
 		goto err_rel;
 	}
-	handle->k = 0;
-	handle->first_sector = handle->cur_swap;
+	handle.k = 0;
+	handle.first_sector = handle.cur_swap;
 	return 0;
 err_rel:
-	release_swap_writer(handle);
+	release_swap_writer();
 err_close:
 	swsusp_close(FMODE_WRITE);
 	return ret;
 }
 
-static int swap_write_page(struct swap_map_handle *handle, void *buf,
-				struct bio **bio_chain)
+static int swap_write_page(void *buf, struct bio **bio_chain)
 {
 	int error = 0;
 	sector_t offset;
 
-	if (!handle->cur)
+	if (!handle.cur)
 		return -EINVAL;
 	offset = hib_extent_next(&sector_extents);
 	error = write_page(buf, offset, bio_chain);
 	if (error)
 		return error;
-	handle->cur->entries[handle->k++] = offset;
-	if (handle->k >= MAP_PAGE_ENTRIES) {
+	handle.cur->entries[handle.k++] = offset;
+	if (handle.k >= MAP_PAGE_ENTRIES) {
 		error = hib_wait_on_bio_chain(bio_chain);
 		if (error)
 			goto out;
 		offset = hib_extent_next(&sector_extents);
 		if (!offset)
 			return -ENOSPC;
-		handle->cur->next_swap = offset;
-		error = write_page(handle->cur, handle->cur_swap, NULL);
+		handle.cur->next_swap = offset;
+		error = write_page(handle.cur, handle.cur_swap, NULL);
 		if (error)
 			goto out;
-		memset(handle->cur, 0, PAGE_SIZE);
-		handle->cur_swap = offset;
-		handle->k = 0;
+		memset(handle.cur, 0, PAGE_SIZE);
+		handle.cur_swap = offset;
+		handle.k = 0;
 	}
  out:
 	return error;
 }
 
-static int flush_swap_writer(struct swap_map_handle *handle)
+static int flush_swap_writer(void)
 {
-	if (handle->cur && handle->cur_swap)
-		return write_page(handle->cur, handle->cur_swap, NULL);
+	if (handle.cur && handle.cur_swap)
+		return write_page(handle.cur, handle.cur_swap, NULL);
 	else
 		return -EINVAL;
 }
 
-static int swap_writer_finish(struct swap_map_handle *handle,
-		unsigned int flags, int error)
+static int swap_writer_finish(unsigned int flags, int error)
 {
 	if (!error) {
-		flush_swap_writer(handle);
+		flush_swap_writer();
 		printk(KERN_INFO "PM: S");
-		error = mark_swapfiles(handle, flags);
+		error = mark_swapfiles(flags);
 		printk("|\n");
 	}
 
 	if (error)
 		free_all_swap_pages(root_swap);
-	release_swap_writer(handle);
+	release_swap_writer();
 	swsusp_close(FMODE_WRITE);
 
 	return error;
@@ -355,8 +355,7 @@ static int swap_writer_finish(struct swap_map_handle *handle,
  *	save_image - save the suspend image data
  */
 
-static int save_image(struct swap_map_handle *handle,
-                      struct snapshot_handle *snapshot,
+static int save_image(struct snapshot_handle *snapshot,
                       unsigned int nr_to_write)
 {
 	unsigned int m;
@@ -380,7 +379,7 @@ static int save_image(struct swap_map_handle *handle,
 		ret = snapshot_read_next(snapshot);
 		if (ret <= 0)
 			break;
-		ret = swap_write_page(handle, data_of(*snapshot), &bio);
+		ret = swap_write_page(data_of(*snapshot), &bio);
 		if (ret)
 			break;
 		if (!(nr_pages % m))
@@ -412,14 +411,13 @@ static int save_image(struct swap_map_handle *handle,
 
 int swsusp_write(unsigned int flags)
 {
-	struct swap_map_handle handle;
 	struct snapshot_handle snapshot;
 	struct swsusp_info *header;
 	unsigned long pages;
 	int error;
 
 	pages = snapshot_get_image_size();
-	error = get_swap_writer(&handle, pages);
+	error = get_swap_writer(pages);
 	if (error) {
 		printk(KERN_ERR "PM: Cannot get swap writer\n");
 		return error;
@@ -433,11 +431,11 @@ int swsusp_write(unsigned int flags)
 		goto out_finish;
 	}
 	header = (struct swsusp_info *)data_of(snapshot);
-	error = swap_write_page(&handle, header, NULL);
+	error = swap_write_page(header, NULL);
 	if (!error)
-		error = save_image(&handle, &snapshot, pages - 1);
+		error = save_image(&snapshot, pages - 1);
 out_finish:
-	error = swap_writer_finish(&handle, flags, error);
+	error = swap_writer_finish(flags, error);
 	return error;
 }
 
@@ -446,15 +444,14 @@ out_finish:
  *	in a file-alike way
  */
 
-static void release_swap_reader(struct swap_map_handle *handle)
+static void release_swap_reader(void)
 {
-	if (handle->cur)
-		free_page((unsigned long)handle->cur);
-	handle->cur = NULL;
+	if (handle.cur)
+		free_page((unsigned long)handle.cur);
+	handle.cur = NULL;
 }
 
-static int get_swap_reader(struct swap_map_handle *handle,
-		unsigned int *flags_p)
+static int get_swap_reader(unsigned int *flags_p)
 {
 	int error;
 
@@ -463,48 +460,47 @@ static int get_swap_reader(struct swap_map_handle *handle,
 	if (!swsusp_header->image) /* how can this happen? */
 		return -EINVAL;
 
-	handle->cur = (struct swap_map_page *)get_zeroed_page(__GFP_WAIT | __GFP_HIGH);
-	if (!handle->cur)
+	handle.cur = (struct swap_map_page *)get_zeroed_page(__GFP_WAIT | __GFP_HIGH);
+	if (!handle.cur)
 		return -ENOMEM;
 
-	error = hib_bio_read_page(swsusp_header->image, handle->cur, NULL);
+	error = hib_bio_read_page(swsusp_header->image, handle.cur, NULL);
 	if (error) {
-		release_swap_reader(handle);
+		release_swap_reader();
 		return error;
 	}
-	handle->k = 0;
+	handle.k = 0;
 	return 0;
 }
 
-static int swap_read_page(struct swap_map_handle *handle, void *buf,
-				struct bio **bio_chain)
+static int swap_read_page(void *buf, struct bio **bio_chain)
 {
 	sector_t offset;
 	int error;
 
-	if (!handle->cur)
+	if (!handle.cur)
 		return -EINVAL;
-	offset = handle->cur->entries[handle->k];
+	offset = handle.cur->entries[handle.k];
 	if (!offset)
 		return -EFAULT;
 	error = hib_bio_read_page(offset, buf, bio_chain);
 	if (error)
 		return error;
-	if (++handle->k >= MAP_PAGE_ENTRIES) {
+	if (++handle.k >= MAP_PAGE_ENTRIES) {
 		error = hib_wait_on_bio_chain(bio_chain);
-		handle->k = 0;
-		offset = handle->cur->next_swap;
+		handle.k = 0;
+		offset = handle.cur->next_swap;
 		if (!offset)
-			release_swap_reader(handle);
+			release_swap_reader();
 		else if (!error)
-			error = hib_bio_read_page(offset, handle->cur, NULL);
+			error = hib_bio_read_page(offset, handle.cur, NULL);
 	}
 	return error;
 }
 
-static int swap_reader_finish(struct swap_map_handle *handle)
+static int swap_reader_finish(void)
 {
-	release_swap_reader(handle);
+	release_swap_reader();
 
 	return 0;
 }
@@ -515,9 +511,7 @@ static int swap_reader_finish(struct swap_map_handle *handle)
  *	(assume there are @nr_pages pages to load)
  */
 
-static int load_image(struct swap_map_handle *handle,
-                      struct snapshot_handle *snapshot,
-                      unsigned int nr_to_read)
+static int load_image(struct snapshot_handle *snapshot, unsigned int nr_to_read)
 {
 	unsigned int m;
 	int error = 0;
@@ -540,7 +534,7 @@ static int load_image(struct swap_map_handle *handle,
 		error = snapshot_write_next(snapshot);
 		if (error <= 0)
 			break;
-		error = swap_read_page(handle, data_of(*snapshot), &bio);
+		error = swap_read_page(data_of(*snapshot), &bio);
 		if (error)
 			break;
 		if (snapshot->sync_read)
@@ -576,7 +570,6 @@ static int load_image(struct swap_map_handle *handle,
 int swsusp_read(unsigned int *flags_p)
 {
 	int error;
-	struct swap_map_handle handle;
 	struct snapshot_handle snapshot;
 	struct swsusp_info *header;
 
@@ -585,14 +578,14 @@ int swsusp_read(unsigned int *flags_p)
 	if (error < PAGE_SIZE)
 		return error < 0 ? error : -EFAULT;
 	header = (struct swsusp_info *)data_of(snapshot);
-	error = get_swap_reader(&handle, flags_p);
+	error = get_swap_reader(flags_p);
 	if (error)
 		goto end;
 	if (!error)
-		error = swap_read_page(&handle, header, NULL);
+		error = swap_read_page(header, NULL);
 	if (!error)
-		error = load_image(&handle, &snapshot, header->pages - 1);
-	swap_reader_finish(&handle);
+		error = load_image(&snapshot, header->pages - 1);
+	swap_reader_finish();
 end:
 	if (!error)
 		pr_debug("PM: Image successfully loaded\n");
-- 
1.7.0.4

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

* [PATCH 10/22] Hibernation: Stop passing bio_chain around
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (19 preceding siblings ...)
  2010-09-25  4:16 ` Nigel Cunningham
@ 2010-09-25  4:16 ` Nigel Cunningham
  2010-09-25  4:16 ` Nigel Cunningham
                   ` (34 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Stop using the struct bio **bio_chain as a means of tracking
outstanding i/o and signalling when we want synchronous i/o.
Instead, keep a bio_chain in the block_io code and use a flag
to explicitly request synchronous I/O.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/block_io.c |   27 +++++++++++-----------
 kernel/power/power.h    |    8 ++----
 kernel/power/swap.c     |   56 +++++++++++++++++++++-------------------------
 3 files changed, 43 insertions(+), 48 deletions(-)

diff --git a/kernel/power/block_io.c b/kernel/power/block_io.c
index 83bbc7c..aa239a2 100644
--- a/kernel/power/block_io.c
+++ b/kernel/power/block_io.c
@@ -14,6 +14,8 @@
 
 #include "power.h"
 
+static struct bio *bio_chain;
+
 /**
  *	submit - submit BIO request.
  *	@rw:	READ or WRITE.
@@ -26,7 +28,7 @@
  *	Then submit it and, if @bio_chain == NULL, wait.
  */
 static int submit(int rw, struct block_device *bdev, sector_t sector,
-		struct page *page, struct bio **bio_chain)
+		struct page *page, int sync)
 {
 	const int bio_rw = rw | REQ_SYNC | REQ_UNPLUG;
 	struct bio *bio;
@@ -46,7 +48,7 @@ static int submit(int rw, struct block_device *bdev, sector_t sector,
 	lock_page(page);
 	bio_get(bio);
 
-	if (bio_chain == NULL) {
+	if (sync) {
 		submit_bio(bio_rw, bio);
 		wait_on_page_locked(page);
 		if (rw == READ)
@@ -55,26 +57,26 @@ static int submit(int rw, struct block_device *bdev, sector_t sector,
 	} else {
 		if (rw == READ)
 			get_page(page);	/* These pages are freed later */
-		bio->bi_private = *bio_chain;
-		*bio_chain = bio;
+		bio->bi_private = bio_chain;
+		bio_chain = bio;
 		submit_bio(bio_rw, bio);
 	}
 	return 0;
 }
 
-int hib_bio_read_page(pgoff_t page_off, void *addr, struct bio **bio_chain)
+int hib_bio_read_page(pgoff_t page_off, void *addr, int sync)
 {
 	return submit(READ, hib_resume_bdev, page_off * (PAGE_SIZE >> 9),
-			virt_to_page(addr), bio_chain);
+			virt_to_page(addr), sync);
 }
 
-int hib_bio_write_page(pgoff_t page_off, void *addr, struct bio **bio_chain)
+int hib_bio_write_page(pgoff_t page_off, void *addr, int sync)
 {
 	return submit(WRITE, hib_resume_bdev, page_off * (PAGE_SIZE >> 9),
-			virt_to_page(addr), bio_chain);
+			virt_to_page(addr), sync);
 }
 
-int hib_wait_on_bio_chain(struct bio **bio_chain)
+int hib_wait_on_bio_chain(void)
 {
 	struct bio *bio;
 	struct bio *next_bio;
@@ -83,9 +85,8 @@ int hib_wait_on_bio_chain(struct bio **bio_chain)
 	if (bio_chain == NULL)
 		return 0;
 
-	bio = *bio_chain;
-	if (bio == NULL)
-		return 0;
+	bio = bio_chain;
+
 	while (bio) {
 		struct page *page;
 
@@ -98,6 +99,6 @@ int hib_wait_on_bio_chain(struct bio **bio_chain)
 		bio_put(bio);
 		bio = next_bio;
 	}
-	*bio_chain = NULL;
+	bio_chain = NULL;
 	return ret;
 }
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 67b6896..1750f64 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -147,11 +147,9 @@ extern void swsusp_close(fmode_t);
 /* kernel/power/block_io.c */
 extern struct block_device *hib_resume_bdev;
 
-extern int hib_bio_read_page(pgoff_t page_off, void *addr,
-		struct bio **bio_chain);
-extern int hib_bio_write_page(pgoff_t page_off, void *addr,
-		struct bio **bio_chain);
-extern int hib_wait_on_bio_chain(struct bio **bio_chain);
+extern int hib_bio_read_page(pgoff_t page_off, void *addr, int sync);
+extern int hib_bio_write_page(pgoff_t page_off, void *addr, int sync);
+extern int hib_wait_on_bio_chain(void);
 
 struct timeval;
 /* kernel/power/swsusp.c */
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index 1df890f..a881086 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -179,7 +179,7 @@ static int mark_swapfiles(unsigned int flags)
 {
 	int error;
 
-	hib_bio_read_page(swsusp_resume_block, swsusp_header, NULL);
+	hib_bio_read_page(swsusp_resume_block, swsusp_header, 1);
 	if (!memcmp("SWAP-SPACE",swsusp_header->sig, 10) ||
 	    !memcmp("SWAPSPACE2",swsusp_header->sig, 10)) {
 		memcpy(swsusp_header->orig_sig,swsusp_header->sig, 10);
@@ -188,7 +188,7 @@ static int mark_swapfiles(unsigned int flags)
 		swsusp_header->image = handle.first_sector;
 		swsusp_header->flags = flags;
 		error = hib_bio_write_page(swsusp_resume_block,
-					swsusp_header, NULL);
+					swsusp_header, 1);
 	} else {
 		printk(KERN_ERR "PM: Swap header not found!\n");
 		error = -ENODEV;
@@ -227,29 +227,29 @@ static int swsusp_swap_check(void)
  *	write_page - Write one page to given swap location.
  *	@buf:		Address we're writing.
  *	@offset:	Offset of the swap page we're writing to.
- *	@bio_chain:	Link the next write BIO here
+ *	@sync:		Whether to force synchronous i/o.
  */
 
-static int write_page(void *buf, sector_t offset, struct bio **bio_chain)
+static int write_page(void *buf, sector_t offset, int sync)
 {
 	void *src;
 
 	if (!offset)
 		return -ENOSPC;
 
-	if (bio_chain) {
+	if (!sync) {
 		src = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH);
 		if (src) {
 			memcpy(src, buf, PAGE_SIZE);
 		} else {
 			WARN_ON_ONCE(1);
-			bio_chain = NULL;	/* Go synchronous */
+			sync = 1;	/* Go synchronous */
 			src = buf;
 		}
 	} else {
 		src = buf;
 	}
-	return hib_bio_write_page(offset, src, bio_chain);
+	return hib_bio_write_page(offset, src, sync);
 }
 
 static void release_swap_writer(void)
@@ -295,7 +295,7 @@ err_close:
 	return ret;
 }
 
-static int swap_write_page(void *buf, struct bio **bio_chain)
+static int swap_write_page(void *buf, int sync)
 {
 	int error = 0;
 	sector_t offset;
@@ -303,19 +303,19 @@ static int swap_write_page(void *buf, struct bio **bio_chain)
 	if (!handle.cur)
 		return -EINVAL;
 	offset = hib_extent_next(&sector_extents);
-	error = write_page(buf, offset, bio_chain);
+	error = write_page(buf, offset, sync);
 	if (error)
 		return error;
 	handle.cur->entries[handle.k++] = offset;
 	if (handle.k >= MAP_PAGE_ENTRIES) {
-		error = hib_wait_on_bio_chain(bio_chain);
+		error = hib_wait_on_bio_chain();
 		if (error)
 			goto out;
 		offset = hib_extent_next(&sector_extents);
 		if (!offset)
 			return -ENOSPC;
 		handle.cur->next_swap = offset;
-		error = write_page(handle.cur, handle.cur_swap, NULL);
+		error = write_page(handle.cur, handle.cur_swap, 1);
 		if (error)
 			goto out;
 		memset(handle.cur, 0, PAGE_SIZE);
@@ -329,7 +329,7 @@ static int swap_write_page(void *buf, struct bio **bio_chain)
 static int flush_swap_writer(void)
 {
 	if (handle.cur && handle.cur_swap)
-		return write_page(handle.cur, handle.cur_swap, NULL);
+		return write_page(handle.cur, handle.cur_swap, 1);
 	else
 		return -EINVAL;
 }
@@ -362,7 +362,6 @@ static int save_image(struct snapshot_handle *snapshot,
 	int ret;
 	int nr_pages;
 	int err2;
-	struct bio *bio;
 	struct timeval start;
 	struct timeval stop;
 	int mps;
@@ -373,20 +372,19 @@ static int save_image(struct snapshot_handle *snapshot,
 	if (!m)
 		m = 1;
 	nr_pages = 0;
-	bio = NULL;
 	do_gettimeofday(&start);
 	while (1) {
 		ret = snapshot_read_next(snapshot);
 		if (ret <= 0)
 			break;
-		ret = swap_write_page(data_of(*snapshot), &bio);
+		ret = swap_write_page(data_of(*snapshot), 0);
 		if (ret)
 			break;
 		if (!(nr_pages % m))
 			printk(KERN_CONT "\b\b\b\b%3d%%", nr_pages / m);
 		nr_pages++;
 	}
-	err2 = hib_wait_on_bio_chain(&bio);
+	err2 = hib_wait_on_bio_chain();
 	do_gettimeofday(&stop);
 	if (!ret)
 		ret = err2;
@@ -431,7 +429,7 @@ int swsusp_write(unsigned int flags)
 		goto out_finish;
 	}
 	header = (struct swsusp_info *)data_of(snapshot);
-	error = swap_write_page(header, NULL);
+	error = swap_write_page(header, 1);
 	if (!error)
 		error = save_image(&snapshot, pages - 1);
 out_finish:
@@ -464,7 +462,7 @@ static int get_swap_reader(unsigned int *flags_p)
 	if (!handle.cur)
 		return -ENOMEM;
 
-	error = hib_bio_read_page(swsusp_header->image, handle.cur, NULL);
+	error = hib_bio_read_page(swsusp_header->image, handle.cur, 1);
 	if (error) {
 		release_swap_reader();
 		return error;
@@ -473,7 +471,7 @@ static int get_swap_reader(unsigned int *flags_p)
 	return 0;
 }
 
-static int swap_read_page(void *buf, struct bio **bio_chain)
+static int swap_read_page(void *buf, int sync)
 {
 	sector_t offset;
 	int error;
@@ -483,17 +481,17 @@ static int swap_read_page(void *buf, struct bio **bio_chain)
 	offset = handle.cur->entries[handle.k];
 	if (!offset)
 		return -EFAULT;
-	error = hib_bio_read_page(offset, buf, bio_chain);
+	error = hib_bio_read_page(offset, buf, sync);
 	if (error)
 		return error;
 	if (++handle.k >= MAP_PAGE_ENTRIES) {
-		error = hib_wait_on_bio_chain(bio_chain);
+		error = hib_wait_on_bio_chain();
 		handle.k = 0;
 		offset = handle.cur->next_swap;
 		if (!offset)
 			release_swap_reader();
 		else if (!error)
-			error = hib_bio_read_page(offset, handle.cur, NULL);
+			error = hib_bio_read_page(offset, handle.cur, 1);
 	}
 	return error;
 }
@@ -517,7 +515,6 @@ static int load_image(struct snapshot_handle *snapshot, unsigned int nr_to_read)
 	int error = 0;
 	struct timeval start;
 	struct timeval stop;
-	struct bio *bio;
 	int err2;
 	unsigned nr_pages;
 	int mps;
@@ -528,24 +525,23 @@ static int load_image(struct snapshot_handle *snapshot, unsigned int nr_to_read)
 	if (!m)
 		m = 1;
 	nr_pages = 0;
-	bio = NULL;
 	do_gettimeofday(&start);
 	for ( ; ; ) {
 		error = snapshot_write_next(snapshot);
 		if (error <= 0)
 			break;
-		error = swap_read_page(data_of(*snapshot), &bio);
+		error = swap_read_page(data_of(*snapshot), 0);
 		if (error)
 			break;
 		if (snapshot->sync_read)
-			error = hib_wait_on_bio_chain(&bio);
+			error = hib_wait_on_bio_chain();
 		if (error)
 			break;
 		if (!(nr_pages % m))
 			printk("\b\b\b\b%3d%%", nr_pages / m);
 		nr_pages++;
 	}
-	err2 = hib_wait_on_bio_chain(&bio);
+	err2 = hib_wait_on_bio_chain();
 	do_gettimeofday(&stop);
 	if (!error)
 		error = err2;
@@ -582,7 +578,7 @@ int swsusp_read(unsigned int *flags_p)
 	if (error)
 		goto end;
 	if (!error)
-		error = swap_read_page(header, NULL);
+		error = swap_read_page(header, 1);
 	if (!error)
 		error = load_image(&snapshot, header->pages - 1);
 	swap_reader_finish();
@@ -607,7 +603,7 @@ int swsusp_check(void)
 		set_blocksize(hib_resume_bdev, PAGE_SIZE);
 		memset(swsusp_header, 0, PAGE_SIZE);
 		error = hib_bio_read_page(swsusp_resume_block,
-					swsusp_header, NULL);
+					swsusp_header, 1);
 		if (error)
 			goto put;
 
@@ -616,7 +612,7 @@ int swsusp_check(void)
 			memcpy(swsusp_header->sig, swsusp_header->orig_sig, 10);
 			/* Reset swap signature now */
 			error = hib_bio_write_page(swsusp_resume_block,
-						swsusp_header, NULL);
+						swsusp_header, 1);
 		} else {
 			error = -EINVAL;
 		}
-- 
1.7.0.4


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

* [PATCH 10/22] Hibernation: Stop passing bio_chain around
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (20 preceding siblings ...)
  2010-09-25  4:16 ` [PATCH 10/22] Hibernation: Stop passing bio_chain around Nigel Cunningham
@ 2010-09-25  4:16 ` Nigel Cunningham
  2010-09-25  4:16 ` [PATCH 11/22] Hibernation: Move block i/o fns to block_io.c Nigel Cunningham
                   ` (33 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Stop using the struct bio **bio_chain as a means of tracking
outstanding i/o and signalling when we want synchronous i/o.
Instead, keep a bio_chain in the block_io code and use a flag
to explicitly request synchronous I/O.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/block_io.c |   27 +++++++++++-----------
 kernel/power/power.h    |    8 ++----
 kernel/power/swap.c     |   56 +++++++++++++++++++++-------------------------
 3 files changed, 43 insertions(+), 48 deletions(-)

diff --git a/kernel/power/block_io.c b/kernel/power/block_io.c
index 83bbc7c..aa239a2 100644
--- a/kernel/power/block_io.c
+++ b/kernel/power/block_io.c
@@ -14,6 +14,8 @@
 
 #include "power.h"
 
+static struct bio *bio_chain;
+
 /**
  *	submit - submit BIO request.
  *	@rw:	READ or WRITE.
@@ -26,7 +28,7 @@
  *	Then submit it and, if @bio_chain == NULL, wait.
  */
 static int submit(int rw, struct block_device *bdev, sector_t sector,
-		struct page *page, struct bio **bio_chain)
+		struct page *page, int sync)
 {
 	const int bio_rw = rw | REQ_SYNC | REQ_UNPLUG;
 	struct bio *bio;
@@ -46,7 +48,7 @@ static int submit(int rw, struct block_device *bdev, sector_t sector,
 	lock_page(page);
 	bio_get(bio);
 
-	if (bio_chain == NULL) {
+	if (sync) {
 		submit_bio(bio_rw, bio);
 		wait_on_page_locked(page);
 		if (rw == READ)
@@ -55,26 +57,26 @@ static int submit(int rw, struct block_device *bdev, sector_t sector,
 	} else {
 		if (rw == READ)
 			get_page(page);	/* These pages are freed later */
-		bio->bi_private = *bio_chain;
-		*bio_chain = bio;
+		bio->bi_private = bio_chain;
+		bio_chain = bio;
 		submit_bio(bio_rw, bio);
 	}
 	return 0;
 }
 
-int hib_bio_read_page(pgoff_t page_off, void *addr, struct bio **bio_chain)
+int hib_bio_read_page(pgoff_t page_off, void *addr, int sync)
 {
 	return submit(READ, hib_resume_bdev, page_off * (PAGE_SIZE >> 9),
-			virt_to_page(addr), bio_chain);
+			virt_to_page(addr), sync);
 }
 
-int hib_bio_write_page(pgoff_t page_off, void *addr, struct bio **bio_chain)
+int hib_bio_write_page(pgoff_t page_off, void *addr, int sync)
 {
 	return submit(WRITE, hib_resume_bdev, page_off * (PAGE_SIZE >> 9),
-			virt_to_page(addr), bio_chain);
+			virt_to_page(addr), sync);
 }
 
-int hib_wait_on_bio_chain(struct bio **bio_chain)
+int hib_wait_on_bio_chain(void)
 {
 	struct bio *bio;
 	struct bio *next_bio;
@@ -83,9 +85,8 @@ int hib_wait_on_bio_chain(struct bio **bio_chain)
 	if (bio_chain == NULL)
 		return 0;
 
-	bio = *bio_chain;
-	if (bio == NULL)
-		return 0;
+	bio = bio_chain;
+
 	while (bio) {
 		struct page *page;
 
@@ -98,6 +99,6 @@ int hib_wait_on_bio_chain(struct bio **bio_chain)
 		bio_put(bio);
 		bio = next_bio;
 	}
-	*bio_chain = NULL;
+	bio_chain = NULL;
 	return ret;
 }
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 67b6896..1750f64 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -147,11 +147,9 @@ extern void swsusp_close(fmode_t);
 /* kernel/power/block_io.c */
 extern struct block_device *hib_resume_bdev;
 
-extern int hib_bio_read_page(pgoff_t page_off, void *addr,
-		struct bio **bio_chain);
-extern int hib_bio_write_page(pgoff_t page_off, void *addr,
-		struct bio **bio_chain);
-extern int hib_wait_on_bio_chain(struct bio **bio_chain);
+extern int hib_bio_read_page(pgoff_t page_off, void *addr, int sync);
+extern int hib_bio_write_page(pgoff_t page_off, void *addr, int sync);
+extern int hib_wait_on_bio_chain(void);
 
 struct timeval;
 /* kernel/power/swsusp.c */
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index 1df890f..a881086 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -179,7 +179,7 @@ static int mark_swapfiles(unsigned int flags)
 {
 	int error;
 
-	hib_bio_read_page(swsusp_resume_block, swsusp_header, NULL);
+	hib_bio_read_page(swsusp_resume_block, swsusp_header, 1);
 	if (!memcmp("SWAP-SPACE",swsusp_header->sig, 10) ||
 	    !memcmp("SWAPSPACE2",swsusp_header->sig, 10)) {
 		memcpy(swsusp_header->orig_sig,swsusp_header->sig, 10);
@@ -188,7 +188,7 @@ static int mark_swapfiles(unsigned int flags)
 		swsusp_header->image = handle.first_sector;
 		swsusp_header->flags = flags;
 		error = hib_bio_write_page(swsusp_resume_block,
-					swsusp_header, NULL);
+					swsusp_header, 1);
 	} else {
 		printk(KERN_ERR "PM: Swap header not found!\n");
 		error = -ENODEV;
@@ -227,29 +227,29 @@ static int swsusp_swap_check(void)
  *	write_page - Write one page to given swap location.
  *	@buf:		Address we're writing.
  *	@offset:	Offset of the swap page we're writing to.
- *	@bio_chain:	Link the next write BIO here
+ *	@sync:		Whether to force synchronous i/o.
  */
 
-static int write_page(void *buf, sector_t offset, struct bio **bio_chain)
+static int write_page(void *buf, sector_t offset, int sync)
 {
 	void *src;
 
 	if (!offset)
 		return -ENOSPC;
 
-	if (bio_chain) {
+	if (!sync) {
 		src = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH);
 		if (src) {
 			memcpy(src, buf, PAGE_SIZE);
 		} else {
 			WARN_ON_ONCE(1);
-			bio_chain = NULL;	/* Go synchronous */
+			sync = 1;	/* Go synchronous */
 			src = buf;
 		}
 	} else {
 		src = buf;
 	}
-	return hib_bio_write_page(offset, src, bio_chain);
+	return hib_bio_write_page(offset, src, sync);
 }
 
 static void release_swap_writer(void)
@@ -295,7 +295,7 @@ err_close:
 	return ret;
 }
 
-static int swap_write_page(void *buf, struct bio **bio_chain)
+static int swap_write_page(void *buf, int sync)
 {
 	int error = 0;
 	sector_t offset;
@@ -303,19 +303,19 @@ static int swap_write_page(void *buf, struct bio **bio_chain)
 	if (!handle.cur)
 		return -EINVAL;
 	offset = hib_extent_next(&sector_extents);
-	error = write_page(buf, offset, bio_chain);
+	error = write_page(buf, offset, sync);
 	if (error)
 		return error;
 	handle.cur->entries[handle.k++] = offset;
 	if (handle.k >= MAP_PAGE_ENTRIES) {
-		error = hib_wait_on_bio_chain(bio_chain);
+		error = hib_wait_on_bio_chain();
 		if (error)
 			goto out;
 		offset = hib_extent_next(&sector_extents);
 		if (!offset)
 			return -ENOSPC;
 		handle.cur->next_swap = offset;
-		error = write_page(handle.cur, handle.cur_swap, NULL);
+		error = write_page(handle.cur, handle.cur_swap, 1);
 		if (error)
 			goto out;
 		memset(handle.cur, 0, PAGE_SIZE);
@@ -329,7 +329,7 @@ static int swap_write_page(void *buf, struct bio **bio_chain)
 static int flush_swap_writer(void)
 {
 	if (handle.cur && handle.cur_swap)
-		return write_page(handle.cur, handle.cur_swap, NULL);
+		return write_page(handle.cur, handle.cur_swap, 1);
 	else
 		return -EINVAL;
 }
@@ -362,7 +362,6 @@ static int save_image(struct snapshot_handle *snapshot,
 	int ret;
 	int nr_pages;
 	int err2;
-	struct bio *bio;
 	struct timeval start;
 	struct timeval stop;
 	int mps;
@@ -373,20 +372,19 @@ static int save_image(struct snapshot_handle *snapshot,
 	if (!m)
 		m = 1;
 	nr_pages = 0;
-	bio = NULL;
 	do_gettimeofday(&start);
 	while (1) {
 		ret = snapshot_read_next(snapshot);
 		if (ret <= 0)
 			break;
-		ret = swap_write_page(data_of(*snapshot), &bio);
+		ret = swap_write_page(data_of(*snapshot), 0);
 		if (ret)
 			break;
 		if (!(nr_pages % m))
 			printk(KERN_CONT "\b\b\b\b%3d%%", nr_pages / m);
 		nr_pages++;
 	}
-	err2 = hib_wait_on_bio_chain(&bio);
+	err2 = hib_wait_on_bio_chain();
 	do_gettimeofday(&stop);
 	if (!ret)
 		ret = err2;
@@ -431,7 +429,7 @@ int swsusp_write(unsigned int flags)
 		goto out_finish;
 	}
 	header = (struct swsusp_info *)data_of(snapshot);
-	error = swap_write_page(header, NULL);
+	error = swap_write_page(header, 1);
 	if (!error)
 		error = save_image(&snapshot, pages - 1);
 out_finish:
@@ -464,7 +462,7 @@ static int get_swap_reader(unsigned int *flags_p)
 	if (!handle.cur)
 		return -ENOMEM;
 
-	error = hib_bio_read_page(swsusp_header->image, handle.cur, NULL);
+	error = hib_bio_read_page(swsusp_header->image, handle.cur, 1);
 	if (error) {
 		release_swap_reader();
 		return error;
@@ -473,7 +471,7 @@ static int get_swap_reader(unsigned int *flags_p)
 	return 0;
 }
 
-static int swap_read_page(void *buf, struct bio **bio_chain)
+static int swap_read_page(void *buf, int sync)
 {
 	sector_t offset;
 	int error;
@@ -483,17 +481,17 @@ static int swap_read_page(void *buf, struct bio **bio_chain)
 	offset = handle.cur->entries[handle.k];
 	if (!offset)
 		return -EFAULT;
-	error = hib_bio_read_page(offset, buf, bio_chain);
+	error = hib_bio_read_page(offset, buf, sync);
 	if (error)
 		return error;
 	if (++handle.k >= MAP_PAGE_ENTRIES) {
-		error = hib_wait_on_bio_chain(bio_chain);
+		error = hib_wait_on_bio_chain();
 		handle.k = 0;
 		offset = handle.cur->next_swap;
 		if (!offset)
 			release_swap_reader();
 		else if (!error)
-			error = hib_bio_read_page(offset, handle.cur, NULL);
+			error = hib_bio_read_page(offset, handle.cur, 1);
 	}
 	return error;
 }
@@ -517,7 +515,6 @@ static int load_image(struct snapshot_handle *snapshot, unsigned int nr_to_read)
 	int error = 0;
 	struct timeval start;
 	struct timeval stop;
-	struct bio *bio;
 	int err2;
 	unsigned nr_pages;
 	int mps;
@@ -528,24 +525,23 @@ static int load_image(struct snapshot_handle *snapshot, unsigned int nr_to_read)
 	if (!m)
 		m = 1;
 	nr_pages = 0;
-	bio = NULL;
 	do_gettimeofday(&start);
 	for ( ; ; ) {
 		error = snapshot_write_next(snapshot);
 		if (error <= 0)
 			break;
-		error = swap_read_page(data_of(*snapshot), &bio);
+		error = swap_read_page(data_of(*snapshot), 0);
 		if (error)
 			break;
 		if (snapshot->sync_read)
-			error = hib_wait_on_bio_chain(&bio);
+			error = hib_wait_on_bio_chain();
 		if (error)
 			break;
 		if (!(nr_pages % m))
 			printk("\b\b\b\b%3d%%", nr_pages / m);
 		nr_pages++;
 	}
-	err2 = hib_wait_on_bio_chain(&bio);
+	err2 = hib_wait_on_bio_chain();
 	do_gettimeofday(&stop);
 	if (!error)
 		error = err2;
@@ -582,7 +578,7 @@ int swsusp_read(unsigned int *flags_p)
 	if (error)
 		goto end;
 	if (!error)
-		error = swap_read_page(header, NULL);
+		error = swap_read_page(header, 1);
 	if (!error)
 		error = load_image(&snapshot, header->pages - 1);
 	swap_reader_finish();
@@ -607,7 +603,7 @@ int swsusp_check(void)
 		set_blocksize(hib_resume_bdev, PAGE_SIZE);
 		memset(swsusp_header, 0, PAGE_SIZE);
 		error = hib_bio_read_page(swsusp_resume_block,
-					swsusp_header, NULL);
+					swsusp_header, 1);
 		if (error)
 			goto put;
 
@@ -616,7 +612,7 @@ int swsusp_check(void)
 			memcpy(swsusp_header->sig, swsusp_header->orig_sig, 10);
 			/* Reset swap signature now */
 			error = hib_bio_write_page(swsusp_resume_block,
-						swsusp_header, NULL);
+						swsusp_header, 1);
 		} else {
 			error = -EINVAL;
 		}
-- 
1.7.0.4

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

* [PATCH 11/22] Hibernation: Move block i/o fns to block_io.c
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (22 preceding siblings ...)
  2010-09-25  4:16 ` [PATCH 11/22] Hibernation: Move block i/o fns to block_io.c Nigel Cunningham
@ 2010-09-25  4:16 ` Nigel Cunningham
  2010-09-25  4:16 ` [PATCH 12/22] Hibernation: Partial page I/O support Nigel Cunningham
                   ` (31 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Move the functions that specifically deal with submitting I/O
to block_io.c. This helps us in working towards having a clean
separation between swap specific functions (which will be all
that will be in swap.c eventually) and low level block i/o
functions (block_io.c) that are/will be agnostic with regard to
the source of the storage. The block_io.c functions will thus
also be useable when support for storing an image in a generic
file (non swap) is added later.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/block_io.c |  199 ++++++++++++++++++++++++++++++++++++++++++++++
 kernel/power/block_io.h |   23 ++++++
 kernel/power/swap.c     |  202 +++--------------------------------------------
 3 files changed, 235 insertions(+), 189 deletions(-)
 create mode 100644 kernel/power/block_io.h

diff --git a/kernel/power/block_io.c b/kernel/power/block_io.c
index aa239a2..5edcb08 100644
--- a/kernel/power/block_io.c
+++ b/kernel/power/block_io.c
@@ -13,6 +13,7 @@
 #include <linux/swap.h>
 
 #include "power.h"
+#include "extents.h"
 
 static struct bio *bio_chain;
 
@@ -102,3 +103,201 @@ int hib_wait_on_bio_chain(void)
 	bio_chain = NULL;
 	return ret;
 }
+
+/*
+ *	The swap map is a data structure used for keeping track of each page
+ *	written to a swap partition.  It consists of many swap_map_page
+ *	structures that contain each an array of MAP_PAGE_SIZE swap entries.
+ *	These structures are stored on the swap and linked together with the
+ *	help of the .next_swap member.
+ *
+ *	The swap map is created during suspend.  The swap map pages are
+ *	allocated and populated one at a time, so we only need one memory
+ *	page to set up the entire structure.
+ *
+ *	During resume we also only need to use one swap_map_page structure
+ *	at a time.
+ */
+
+#define MAP_PAGE_ENTRIES	(PAGE_SIZE / sizeof(sector_t) - 1)
+
+struct swap_map_page {
+	sector_t entries[MAP_PAGE_ENTRIES];
+	sector_t next_swap;
+};
+
+/**
+ *	The swap_map_handle structure is used for handling swap in
+ *	a file-alike way
+ */
+
+struct swap_map_handle {
+	struct swap_map_page *cur;
+	sector_t cur_swap;
+	sector_t first_sector;
+	unsigned int k;
+};
+
+static struct swap_map_handle handle;
+
+extern struct hib_extent_state sector_extents;
+
+/* Calculate the overhead needed for storing n pages */
+unsigned int hib_bio_overhead(unsigned int nr_pages)
+{
+	return DIV_ROUND_UP(nr_pages, MAP_PAGE_ENTRIES);
+}
+
+/* Get the first sector of the image proper, for storing in the signature */
+sector_t hib_get_first_sector(void)
+{
+	return handle.first_sector;
+}
+
+/**
+ *	write_page - Write one page to given swap location.
+ *	@buf:		Address we're writing.
+ *	@offset:	Offset of the swap page we're writing to.
+ *	@sync:		Whether to force synchronous i/o.
+ */
+
+static int write_page(void *buf, sector_t offset, int sync)
+{
+	void *src;
+
+	if (!offset)
+		return -ENOSPC;
+
+	if (!sync) {
+		src = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH);
+		if (src) {
+			memcpy(src, buf, PAGE_SIZE);
+		} else {
+			WARN_ON_ONCE(1);
+			sync = 1;	/* Go synchronous */
+			src = buf;
+		}
+	} else {
+		src = buf;
+	}
+	return hib_bio_write_page(offset, src, sync);
+}
+
+void release_swap_writer(void)
+{
+	if (handle.cur)
+		free_page((unsigned long)handle.cur);
+	handle.cur = NULL;
+}
+
+int hib_bio_prepare_write(void)
+{
+	handle.cur = (struct swap_map_page *)get_zeroed_page(GFP_KERNEL);
+
+	if (!handle.cur)
+		return -ENOMEM;
+
+	handle.cur_swap = hib_extent_next(&sector_extents);
+
+	if (!handle.cur_swap) {
+		release_swap_writer();
+		return -ENOSPC;
+	}
+
+	handle.k = 0;
+	handle.first_sector = handle.cur_swap;
+	return 0;
+}
+
+int swap_write_page(void *buf, int sync)
+{
+	int error = 0;
+	sector_t offset;
+
+	if (!handle.cur)
+		return -EINVAL;
+	offset = hib_extent_next(&sector_extents);
+	error = write_page(buf, offset, sync);
+	if (error)
+		return error;
+	handle.cur->entries[handle.k++] = offset;
+	if (handle.k >= MAP_PAGE_ENTRIES) {
+		error = hib_wait_on_bio_chain();
+		if (error)
+			goto out;
+		offset = hib_extent_next(&sector_extents);
+		if (!offset)
+			return -ENOSPC;
+		handle.cur->next_swap = offset;
+		error = write_page(handle.cur, handle.cur_swap, 1);
+		if (error)
+			goto out;
+		memset(handle.cur, 0, PAGE_SIZE);
+		handle.cur_swap = offset;
+		handle.k = 0;
+	}
+ out:
+	return error;
+}
+
+int flush_swap_writer(void)
+{
+	if (handle.cur && handle.cur_swap)
+		return write_page(handle.cur, handle.cur_swap, 1);
+	else
+		return -EINVAL;
+}
+
+/**
+ *	The following functions allow us to read data using a swap map
+ *	in a file-alike way
+ */
+
+void release_swap_reader(void)
+{
+	if (handle.cur)
+		free_page((unsigned long)handle.cur);
+	handle.cur = NULL;
+}
+
+int get_swap_reader(unsigned int *flags_p, sector_t first_page)
+{
+	int error;
+
+	handle.cur = (struct swap_map_page *)get_zeroed_page(__GFP_WAIT | __GFP_HIGH);
+	if (!handle.cur)
+		return -ENOMEM;
+
+	error = hib_bio_read_page(first_page, handle.cur, 1);
+	if (error) {
+		release_swap_reader();
+		return error;
+	}
+	handle.k = 0;
+	return 0;
+}
+
+int swap_read_page(void *buf, int sync)
+{
+	sector_t offset;
+	int error;
+
+	if (!handle.cur)
+		return -EINVAL;
+	offset = handle.cur->entries[handle.k];
+	if (!offset)
+		return -EFAULT;
+	error = hib_bio_read_page(offset, buf, sync);
+	if (error)
+		return error;
+	if (++handle.k >= MAP_PAGE_ENTRIES) {
+		error = hib_wait_on_bio_chain();
+		handle.k = 0;
+		offset = handle.cur->next_swap;
+		if (!offset)
+			release_swap_reader();
+		else if (!error)
+			error = hib_bio_read_page(offset, handle.cur, 1);
+	}
+	return error;
+}
diff --git a/kernel/power/block_io.h b/kernel/power/block_io.h
new file mode 100644
index 0000000..2f91d6d
--- /dev/null
+++ b/kernel/power/block_io.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 1998,2001-2005 Pavel Machek <pavel@ucw.cz>
+ * Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl>
+ * Copyright (C) 2010 Nigel Cunningham <nigel@tuxonice.net>
+ *
+ * This file is released under the GPLv2.
+ */
+
+/* Low level routines */
+int hib_bio_read_page(pgoff_t page_off, void *addr, int sync);
+int hib_bio_write_page(pgoff_t page_off, void *addr, int sync);
+int hib_wait_on_bio_chain(void);
+
+unsigned int hib_bio_overhead(unsigned int nr_pages);
+sector_t hib_get_first_sector(void);
+extern struct hib_extent_state sector_extents;
+void release_swap_writer(void);
+int hib_bio_prepare_write(void);
+int flush_swap_writer(void);
+int swap_write_page(void *buf, int sync);
+int get_swap_reader(unsigned int *flags_p, sector_t first_page);
+void release_swap_reader(void);
+int swap_read_page(void *buf, int sync);
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index a881086..d217a6f 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -26,45 +26,10 @@
 
 #include "power.h"
 #include "extents.h"
+#include "block_io.h"
 
 #define SWSUSP_SIG	"S1SUSPEND"
 
-/*
- *	The swap map is a data structure used for keeping track of each page
- *	written to a swap partition.  It consists of many swap_map_page
- *	structures that contain each an array of MAP_PAGE_ENTRIES swap entries.
- *	These structures are stored on the swap and linked together with the
- *	help of the .next_swap member.
- *
- *	The swap map is created during suspend.  The swap map pages are
- *	allocated and populated one at a time, so we only need one memory
- *	page to set up the entire structure.
- *
- *	During resume we also only need to use one swap_map_page structure
- *	at a time.
- */
-
-#define MAP_PAGE_ENTRIES	(PAGE_SIZE / sizeof(sector_t) - 1)
-
-struct swap_map_page {
-	sector_t entries[MAP_PAGE_ENTRIES];
-	sector_t next_swap;
-};
-
-/**
- *	The swap_map_handle structure is used for handling swap in
- *	a file-alike way
- */
-
-struct swap_map_handle {
-	struct swap_map_page *cur;
-	sector_t cur_swap;
-	sector_t first_sector;
-	unsigned int k;
-};
-
-static struct swap_map_handle handle;
-
 static unsigned short root_swap = 0xffff;
 
 struct swsusp_header {
@@ -79,7 +44,7 @@ struct swsusp_header {
 static struct swsusp_header *swsusp_header;
 
 static struct hib_extent_state swap_extents;
-static struct hib_extent_state sector_extents;
+struct hib_extent_state sector_extents;
 
 /**
  *	alloc_swapdev_block - allocate a swap page and register that it has
@@ -127,7 +92,7 @@ static int allocate_swap(unsigned int nr_pages)
 {
 	unsigned int free_swap = count_swap_pages(root_swap, 1);
 
-	nr_pages += DIV_ROUND_UP(nr_pages, MAP_PAGE_ENTRIES);
+	nr_pages += hib_bio_overhead(nr_pages);
 
 	pr_debug("PM: Free swap pages: %u\n", free_swap);
 	if (free_swap < nr_pages)
@@ -185,7 +150,7 @@ static int mark_swapfiles(unsigned int flags)
 		memcpy(swsusp_header->orig_sig,swsusp_header->sig, 10);
 		memcpy(swsusp_header->sig,SWSUSP_SIG, 10);
 		swsusp_header->write_speed = write_speed;
-		swsusp_header->image = handle.first_sector;
+		swsusp_header->image = hib_get_first_sector();
 		swsusp_header->flags = flags;
 		error = hib_bio_write_page(swsusp_resume_block,
 					swsusp_header, 1);
@@ -223,42 +188,6 @@ static int swsusp_swap_check(void)
 	return res;
 }
 
-/**
- *	write_page - Write one page to given swap location.
- *	@buf:		Address we're writing.
- *	@offset:	Offset of the swap page we're writing to.
- *	@sync:		Whether to force synchronous i/o.
- */
-
-static int write_page(void *buf, sector_t offset, int sync)
-{
-	void *src;
-
-	if (!offset)
-		return -ENOSPC;
-
-	if (!sync) {
-		src = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH);
-		if (src) {
-			memcpy(src, buf, PAGE_SIZE);
-		} else {
-			WARN_ON_ONCE(1);
-			sync = 1;	/* Go synchronous */
-			src = buf;
-		}
-	} else {
-		src = buf;
-	}
-	return hib_bio_write_page(offset, src, sync);
-}
-
-static void release_swap_writer(void)
-{
-	if (handle.cur)
-		free_page((unsigned long)handle.cur);
-	handle.cur = NULL;
-}
-
 static int get_swap_writer(unsigned long pages)
 {
 	int ret;
@@ -270,70 +199,19 @@ static int get_swap_writer(unsigned long pages)
 					"swapon -a.\n");
 		return ret;
 	}
-	handle.cur = (struct swap_map_page *)get_zeroed_page(GFP_KERNEL);
-	if (!handle.cur) {
-		ret = -ENOMEM;
-		goto err_close;
-	}
 	if (!allocate_swap(pages)) {
 		printk(KERN_ERR "PM: Not enough free swap\n");
 		ret = -ENOSPC;
 		goto err_close;
 	}
-	handle.cur_swap = hib_extent_next(&sector_extents);
-	if (!handle.cur_swap) {
-		ret = -ENOSPC;
-		goto err_rel;
-	}
-	handle.k = 0;
-	handle.first_sector = handle.cur_swap;
-	return 0;
-err_rel:
-	release_swap_writer();
+	ret = hib_bio_prepare_write();
+	if (!ret)
+		return 0;
 err_close:
 	swsusp_close(FMODE_WRITE);
 	return ret;
 }
 
-static int swap_write_page(void *buf, int sync)
-{
-	int error = 0;
-	sector_t offset;
-
-	if (!handle.cur)
-		return -EINVAL;
-	offset = hib_extent_next(&sector_extents);
-	error = write_page(buf, offset, sync);
-	if (error)
-		return error;
-	handle.cur->entries[handle.k++] = offset;
-	if (handle.k >= MAP_PAGE_ENTRIES) {
-		error = hib_wait_on_bio_chain();
-		if (error)
-			goto out;
-		offset = hib_extent_next(&sector_extents);
-		if (!offset)
-			return -ENOSPC;
-		handle.cur->next_swap = offset;
-		error = write_page(handle.cur, handle.cur_swap, 1);
-		if (error)
-			goto out;
-		memset(handle.cur, 0, PAGE_SIZE);
-		handle.cur_swap = offset;
-		handle.k = 0;
-	}
- out:
-	return error;
-}
-
-static int flush_swap_writer(void)
-{
-	if (handle.cur && handle.cur_swap)
-		return write_page(handle.cur, handle.cur_swap, 1);
-	else
-		return -EINVAL;
-}
-
 static int swap_writer_finish(unsigned int flags, int error)
 {
 	if (!error) {
@@ -437,65 +315,6 @@ out_finish:
 	return error;
 }
 
-/**
- *	The following functions allow us to read data using a swap map
- *	in a file-alike way
- */
-
-static void release_swap_reader(void)
-{
-	if (handle.cur)
-		free_page((unsigned long)handle.cur);
-	handle.cur = NULL;
-}
-
-static int get_swap_reader(unsigned int *flags_p)
-{
-	int error;
-
-	*flags_p = swsusp_header->flags;
-
-	if (!swsusp_header->image) /* how can this happen? */
-		return -EINVAL;
-
-	handle.cur = (struct swap_map_page *)get_zeroed_page(__GFP_WAIT | __GFP_HIGH);
-	if (!handle.cur)
-		return -ENOMEM;
-
-	error = hib_bio_read_page(swsusp_header->image, handle.cur, 1);
-	if (error) {
-		release_swap_reader();
-		return error;
-	}
-	handle.k = 0;
-	return 0;
-}
-
-static int swap_read_page(void *buf, int sync)
-{
-	sector_t offset;
-	int error;
-
-	if (!handle.cur)
-		return -EINVAL;
-	offset = handle.cur->entries[handle.k];
-	if (!offset)
-		return -EFAULT;
-	error = hib_bio_read_page(offset, buf, sync);
-	if (error)
-		return error;
-	if (++handle.k >= MAP_PAGE_ENTRIES) {
-		error = hib_wait_on_bio_chain();
-		handle.k = 0;
-		offset = handle.cur->next_swap;
-		if (!offset)
-			release_swap_reader();
-		else if (!error)
-			error = hib_bio_read_page(offset, handle.cur, 1);
-	}
-	return error;
-}
-
 static int swap_reader_finish(void)
 {
 	release_swap_reader();
@@ -574,7 +393,12 @@ int swsusp_read(unsigned int *flags_p)
 	if (error < PAGE_SIZE)
 		return error < 0 ? error : -EFAULT;
 	header = (struct swsusp_info *)data_of(snapshot);
-	error = get_swap_reader(flags_p);
+	*flags_p = swsusp_header->flags;
+	if (!swsusp_header->image) { /* how can this happen? */
+		error = -EINVAL;
+		goto end;
+	}
+	error = get_swap_reader(flags_p, swsusp_header->image);
 	if (error)
 		goto end;
 	if (!error)
-- 
1.7.0.4


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

* [PATCH 11/22] Hibernation: Move block i/o fns to block_io.c
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (21 preceding siblings ...)
  2010-09-25  4:16 ` Nigel Cunningham
@ 2010-09-25  4:16 ` Nigel Cunningham
  2010-09-25  4:16 ` Nigel Cunningham
                   ` (32 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Move the functions that specifically deal with submitting I/O
to block_io.c. This helps us in working towards having a clean
separation between swap specific functions (which will be all
that will be in swap.c eventually) and low level block i/o
functions (block_io.c) that are/will be agnostic with regard to
the source of the storage. The block_io.c functions will thus
also be useable when support for storing an image in a generic
file (non swap) is added later.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/block_io.c |  199 ++++++++++++++++++++++++++++++++++++++++++++++
 kernel/power/block_io.h |   23 ++++++
 kernel/power/swap.c     |  202 +++--------------------------------------------
 3 files changed, 235 insertions(+), 189 deletions(-)
 create mode 100644 kernel/power/block_io.h

diff --git a/kernel/power/block_io.c b/kernel/power/block_io.c
index aa239a2..5edcb08 100644
--- a/kernel/power/block_io.c
+++ b/kernel/power/block_io.c
@@ -13,6 +13,7 @@
 #include <linux/swap.h>
 
 #include "power.h"
+#include "extents.h"
 
 static struct bio *bio_chain;
 
@@ -102,3 +103,201 @@ int hib_wait_on_bio_chain(void)
 	bio_chain = NULL;
 	return ret;
 }
+
+/*
+ *	The swap map is a data structure used for keeping track of each page
+ *	written to a swap partition.  It consists of many swap_map_page
+ *	structures that contain each an array of MAP_PAGE_SIZE swap entries.
+ *	These structures are stored on the swap and linked together with the
+ *	help of the .next_swap member.
+ *
+ *	The swap map is created during suspend.  The swap map pages are
+ *	allocated and populated one at a time, so we only need one memory
+ *	page to set up the entire structure.
+ *
+ *	During resume we also only need to use one swap_map_page structure
+ *	at a time.
+ */
+
+#define MAP_PAGE_ENTRIES	(PAGE_SIZE / sizeof(sector_t) - 1)
+
+struct swap_map_page {
+	sector_t entries[MAP_PAGE_ENTRIES];
+	sector_t next_swap;
+};
+
+/**
+ *	The swap_map_handle structure is used for handling swap in
+ *	a file-alike way
+ */
+
+struct swap_map_handle {
+	struct swap_map_page *cur;
+	sector_t cur_swap;
+	sector_t first_sector;
+	unsigned int k;
+};
+
+static struct swap_map_handle handle;
+
+extern struct hib_extent_state sector_extents;
+
+/* Calculate the overhead needed for storing n pages */
+unsigned int hib_bio_overhead(unsigned int nr_pages)
+{
+	return DIV_ROUND_UP(nr_pages, MAP_PAGE_ENTRIES);
+}
+
+/* Get the first sector of the image proper, for storing in the signature */
+sector_t hib_get_first_sector(void)
+{
+	return handle.first_sector;
+}
+
+/**
+ *	write_page - Write one page to given swap location.
+ *	@buf:		Address we're writing.
+ *	@offset:	Offset of the swap page we're writing to.
+ *	@sync:		Whether to force synchronous i/o.
+ */
+
+static int write_page(void *buf, sector_t offset, int sync)
+{
+	void *src;
+
+	if (!offset)
+		return -ENOSPC;
+
+	if (!sync) {
+		src = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH);
+		if (src) {
+			memcpy(src, buf, PAGE_SIZE);
+		} else {
+			WARN_ON_ONCE(1);
+			sync = 1;	/* Go synchronous */
+			src = buf;
+		}
+	} else {
+		src = buf;
+	}
+	return hib_bio_write_page(offset, src, sync);
+}
+
+void release_swap_writer(void)
+{
+	if (handle.cur)
+		free_page((unsigned long)handle.cur);
+	handle.cur = NULL;
+}
+
+int hib_bio_prepare_write(void)
+{
+	handle.cur = (struct swap_map_page *)get_zeroed_page(GFP_KERNEL);
+
+	if (!handle.cur)
+		return -ENOMEM;
+
+	handle.cur_swap = hib_extent_next(&sector_extents);
+
+	if (!handle.cur_swap) {
+		release_swap_writer();
+		return -ENOSPC;
+	}
+
+	handle.k = 0;
+	handle.first_sector = handle.cur_swap;
+	return 0;
+}
+
+int swap_write_page(void *buf, int sync)
+{
+	int error = 0;
+	sector_t offset;
+
+	if (!handle.cur)
+		return -EINVAL;
+	offset = hib_extent_next(&sector_extents);
+	error = write_page(buf, offset, sync);
+	if (error)
+		return error;
+	handle.cur->entries[handle.k++] = offset;
+	if (handle.k >= MAP_PAGE_ENTRIES) {
+		error = hib_wait_on_bio_chain();
+		if (error)
+			goto out;
+		offset = hib_extent_next(&sector_extents);
+		if (!offset)
+			return -ENOSPC;
+		handle.cur->next_swap = offset;
+		error = write_page(handle.cur, handle.cur_swap, 1);
+		if (error)
+			goto out;
+		memset(handle.cur, 0, PAGE_SIZE);
+		handle.cur_swap = offset;
+		handle.k = 0;
+	}
+ out:
+	return error;
+}
+
+int flush_swap_writer(void)
+{
+	if (handle.cur && handle.cur_swap)
+		return write_page(handle.cur, handle.cur_swap, 1);
+	else
+		return -EINVAL;
+}
+
+/**
+ *	The following functions allow us to read data using a swap map
+ *	in a file-alike way
+ */
+
+void release_swap_reader(void)
+{
+	if (handle.cur)
+		free_page((unsigned long)handle.cur);
+	handle.cur = NULL;
+}
+
+int get_swap_reader(unsigned int *flags_p, sector_t first_page)
+{
+	int error;
+
+	handle.cur = (struct swap_map_page *)get_zeroed_page(__GFP_WAIT | __GFP_HIGH);
+	if (!handle.cur)
+		return -ENOMEM;
+
+	error = hib_bio_read_page(first_page, handle.cur, 1);
+	if (error) {
+		release_swap_reader();
+		return error;
+	}
+	handle.k = 0;
+	return 0;
+}
+
+int swap_read_page(void *buf, int sync)
+{
+	sector_t offset;
+	int error;
+
+	if (!handle.cur)
+		return -EINVAL;
+	offset = handle.cur->entries[handle.k];
+	if (!offset)
+		return -EFAULT;
+	error = hib_bio_read_page(offset, buf, sync);
+	if (error)
+		return error;
+	if (++handle.k >= MAP_PAGE_ENTRIES) {
+		error = hib_wait_on_bio_chain();
+		handle.k = 0;
+		offset = handle.cur->next_swap;
+		if (!offset)
+			release_swap_reader();
+		else if (!error)
+			error = hib_bio_read_page(offset, handle.cur, 1);
+	}
+	return error;
+}
diff --git a/kernel/power/block_io.h b/kernel/power/block_io.h
new file mode 100644
index 0000000..2f91d6d
--- /dev/null
+++ b/kernel/power/block_io.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 1998,2001-2005 Pavel Machek <pavel@ucw.cz>
+ * Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl>
+ * Copyright (C) 2010 Nigel Cunningham <nigel@tuxonice.net>
+ *
+ * This file is released under the GPLv2.
+ */
+
+/* Low level routines */
+int hib_bio_read_page(pgoff_t page_off, void *addr, int sync);
+int hib_bio_write_page(pgoff_t page_off, void *addr, int sync);
+int hib_wait_on_bio_chain(void);
+
+unsigned int hib_bio_overhead(unsigned int nr_pages);
+sector_t hib_get_first_sector(void);
+extern struct hib_extent_state sector_extents;
+void release_swap_writer(void);
+int hib_bio_prepare_write(void);
+int flush_swap_writer(void);
+int swap_write_page(void *buf, int sync);
+int get_swap_reader(unsigned int *flags_p, sector_t first_page);
+void release_swap_reader(void);
+int swap_read_page(void *buf, int sync);
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index a881086..d217a6f 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -26,45 +26,10 @@
 
 #include "power.h"
 #include "extents.h"
+#include "block_io.h"
 
 #define SWSUSP_SIG	"S1SUSPEND"
 
-/*
- *	The swap map is a data structure used for keeping track of each page
- *	written to a swap partition.  It consists of many swap_map_page
- *	structures that contain each an array of MAP_PAGE_ENTRIES swap entries.
- *	These structures are stored on the swap and linked together with the
- *	help of the .next_swap member.
- *
- *	The swap map is created during suspend.  The swap map pages are
- *	allocated and populated one at a time, so we only need one memory
- *	page to set up the entire structure.
- *
- *	During resume we also only need to use one swap_map_page structure
- *	at a time.
- */
-
-#define MAP_PAGE_ENTRIES	(PAGE_SIZE / sizeof(sector_t) - 1)
-
-struct swap_map_page {
-	sector_t entries[MAP_PAGE_ENTRIES];
-	sector_t next_swap;
-};
-
-/**
- *	The swap_map_handle structure is used for handling swap in
- *	a file-alike way
- */
-
-struct swap_map_handle {
-	struct swap_map_page *cur;
-	sector_t cur_swap;
-	sector_t first_sector;
-	unsigned int k;
-};
-
-static struct swap_map_handle handle;
-
 static unsigned short root_swap = 0xffff;
 
 struct swsusp_header {
@@ -79,7 +44,7 @@ struct swsusp_header {
 static struct swsusp_header *swsusp_header;
 
 static struct hib_extent_state swap_extents;
-static struct hib_extent_state sector_extents;
+struct hib_extent_state sector_extents;
 
 /**
  *	alloc_swapdev_block - allocate a swap page and register that it has
@@ -127,7 +92,7 @@ static int allocate_swap(unsigned int nr_pages)
 {
 	unsigned int free_swap = count_swap_pages(root_swap, 1);
 
-	nr_pages += DIV_ROUND_UP(nr_pages, MAP_PAGE_ENTRIES);
+	nr_pages += hib_bio_overhead(nr_pages);
 
 	pr_debug("PM: Free swap pages: %u\n", free_swap);
 	if (free_swap < nr_pages)
@@ -185,7 +150,7 @@ static int mark_swapfiles(unsigned int flags)
 		memcpy(swsusp_header->orig_sig,swsusp_header->sig, 10);
 		memcpy(swsusp_header->sig,SWSUSP_SIG, 10);
 		swsusp_header->write_speed = write_speed;
-		swsusp_header->image = handle.first_sector;
+		swsusp_header->image = hib_get_first_sector();
 		swsusp_header->flags = flags;
 		error = hib_bio_write_page(swsusp_resume_block,
 					swsusp_header, 1);
@@ -223,42 +188,6 @@ static int swsusp_swap_check(void)
 	return res;
 }
 
-/**
- *	write_page - Write one page to given swap location.
- *	@buf:		Address we're writing.
- *	@offset:	Offset of the swap page we're writing to.
- *	@sync:		Whether to force synchronous i/o.
- */
-
-static int write_page(void *buf, sector_t offset, int sync)
-{
-	void *src;
-
-	if (!offset)
-		return -ENOSPC;
-
-	if (!sync) {
-		src = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH);
-		if (src) {
-			memcpy(src, buf, PAGE_SIZE);
-		} else {
-			WARN_ON_ONCE(1);
-			sync = 1;	/* Go synchronous */
-			src = buf;
-		}
-	} else {
-		src = buf;
-	}
-	return hib_bio_write_page(offset, src, sync);
-}
-
-static void release_swap_writer(void)
-{
-	if (handle.cur)
-		free_page((unsigned long)handle.cur);
-	handle.cur = NULL;
-}
-
 static int get_swap_writer(unsigned long pages)
 {
 	int ret;
@@ -270,70 +199,19 @@ static int get_swap_writer(unsigned long pages)
 					"swapon -a.\n");
 		return ret;
 	}
-	handle.cur = (struct swap_map_page *)get_zeroed_page(GFP_KERNEL);
-	if (!handle.cur) {
-		ret = -ENOMEM;
-		goto err_close;
-	}
 	if (!allocate_swap(pages)) {
 		printk(KERN_ERR "PM: Not enough free swap\n");
 		ret = -ENOSPC;
 		goto err_close;
 	}
-	handle.cur_swap = hib_extent_next(&sector_extents);
-	if (!handle.cur_swap) {
-		ret = -ENOSPC;
-		goto err_rel;
-	}
-	handle.k = 0;
-	handle.first_sector = handle.cur_swap;
-	return 0;
-err_rel:
-	release_swap_writer();
+	ret = hib_bio_prepare_write();
+	if (!ret)
+		return 0;
 err_close:
 	swsusp_close(FMODE_WRITE);
 	return ret;
 }
 
-static int swap_write_page(void *buf, int sync)
-{
-	int error = 0;
-	sector_t offset;
-
-	if (!handle.cur)
-		return -EINVAL;
-	offset = hib_extent_next(&sector_extents);
-	error = write_page(buf, offset, sync);
-	if (error)
-		return error;
-	handle.cur->entries[handle.k++] = offset;
-	if (handle.k >= MAP_PAGE_ENTRIES) {
-		error = hib_wait_on_bio_chain();
-		if (error)
-			goto out;
-		offset = hib_extent_next(&sector_extents);
-		if (!offset)
-			return -ENOSPC;
-		handle.cur->next_swap = offset;
-		error = write_page(handle.cur, handle.cur_swap, 1);
-		if (error)
-			goto out;
-		memset(handle.cur, 0, PAGE_SIZE);
-		handle.cur_swap = offset;
-		handle.k = 0;
-	}
- out:
-	return error;
-}
-
-static int flush_swap_writer(void)
-{
-	if (handle.cur && handle.cur_swap)
-		return write_page(handle.cur, handle.cur_swap, 1);
-	else
-		return -EINVAL;
-}
-
 static int swap_writer_finish(unsigned int flags, int error)
 {
 	if (!error) {
@@ -437,65 +315,6 @@ out_finish:
 	return error;
 }
 
-/**
- *	The following functions allow us to read data using a swap map
- *	in a file-alike way
- */
-
-static void release_swap_reader(void)
-{
-	if (handle.cur)
-		free_page((unsigned long)handle.cur);
-	handle.cur = NULL;
-}
-
-static int get_swap_reader(unsigned int *flags_p)
-{
-	int error;
-
-	*flags_p = swsusp_header->flags;
-
-	if (!swsusp_header->image) /* how can this happen? */
-		return -EINVAL;
-
-	handle.cur = (struct swap_map_page *)get_zeroed_page(__GFP_WAIT | __GFP_HIGH);
-	if (!handle.cur)
-		return -ENOMEM;
-
-	error = hib_bio_read_page(swsusp_header->image, handle.cur, 1);
-	if (error) {
-		release_swap_reader();
-		return error;
-	}
-	handle.k = 0;
-	return 0;
-}
-
-static int swap_read_page(void *buf, int sync)
-{
-	sector_t offset;
-	int error;
-
-	if (!handle.cur)
-		return -EINVAL;
-	offset = handle.cur->entries[handle.k];
-	if (!offset)
-		return -EFAULT;
-	error = hib_bio_read_page(offset, buf, sync);
-	if (error)
-		return error;
-	if (++handle.k >= MAP_PAGE_ENTRIES) {
-		error = hib_wait_on_bio_chain();
-		handle.k = 0;
-		offset = handle.cur->next_swap;
-		if (!offset)
-			release_swap_reader();
-		else if (!error)
-			error = hib_bio_read_page(offset, handle.cur, 1);
-	}
-	return error;
-}
-
 static int swap_reader_finish(void)
 {
 	release_swap_reader();
@@ -574,7 +393,12 @@ int swsusp_read(unsigned int *flags_p)
 	if (error < PAGE_SIZE)
 		return error < 0 ? error : -EFAULT;
 	header = (struct swsusp_info *)data_of(snapshot);
-	error = get_swap_reader(flags_p);
+	*flags_p = swsusp_header->flags;
+	if (!swsusp_header->image) { /* how can this happen? */
+		error = -EINVAL;
+		goto end;
+	}
+	error = get_swap_reader(flags_p, swsusp_header->image);
 	if (error)
 		goto end;
 	if (!error)
-- 
1.7.0.4

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

* [PATCH 12/22] Hibernation: Partial page I/O support.
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (23 preceding siblings ...)
  2010-09-25  4:16 ` Nigel Cunningham
@ 2010-09-25  4:16 ` Nigel Cunningham
  2010-09-25  4:16 ` Nigel Cunningham
                   ` (30 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Add functions that can be used for coalescing and splitting buffers
that are smaller than PAGE_SIZE. These functions provide no method
of determining where the boundaries of the smaller buffers are to
be found - that is the caller's problem.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/block_io.c |   90 +++++++++++++++++++++++++++++++++++++++++++++++
 kernel/power/block_io.h |    4 ++
 2 files changed, 94 insertions(+), 0 deletions(-)

diff --git a/kernel/power/block_io.c b/kernel/power/block_io.c
index 5edcb08..bf6129b 100644
--- a/kernel/power/block_io.c
+++ b/kernel/power/block_io.c
@@ -17,6 +17,11 @@
 
 static struct bio *bio_chain;
 
+static char *hib_ppio_buffer;
+static int hib_ppio_buffer_posn;
+int hib_prepare_buffer(void);
+void hib_free_buffer(void);
+
 /**
  *	submit - submit BIO request.
  *	@rw:	READ or WRITE.
@@ -301,3 +306,88 @@ int swap_read_page(void *buf, int sync)
 	}
 	return error;
 }
+
+/* Part Page I/O functions */
+static char *hib_ppio_buffer;
+static int hib_ppio_buffer_posn;
+
+int hib_prepare_buffer(void)
+{
+	hib_ppio_buffer = (char *)__get_free_page(__GFP_WAIT);
+	hib_ppio_buffer_posn = 0;
+	return hib_ppio_buffer ? 0 : -ENOMEM;
+}
+
+void hib_free_buffer(void)
+{
+	if (!hib_ppio_buffer)
+		return;
+
+	free_page((unsigned long) hib_ppio_buffer);
+	hib_ppio_buffer = NULL;
+}
+
+int hib_flush_write_buffer(void)
+{
+	return hib_ppio_buffer_posn ? swap_write_page(hib_ppio_buffer, 0) : 0;
+}
+
+int hib_write_buffer(char *buffer, int buffer_size)
+{
+	int bytes_left = buffer_size, result = 0;
+
+	while (bytes_left) {
+		char *from = buffer + buffer_size - bytes_left;
+		char *to = hib_ppio_buffer + hib_ppio_buffer_posn;
+		int capacity = PAGE_SIZE - hib_ppio_buffer_posn;
+
+		if (bytes_left <= capacity) {
+			memcpy(to, from, bytes_left);
+			hib_ppio_buffer_posn += bytes_left;
+			return 0;
+		}
+
+		/* Complete this page and start a new one */
+		memcpy(to, from, capacity);
+		bytes_left -= capacity;
+
+		result = swap_write_page(hib_ppio_buffer, 0);
+		if (result)
+			return result;
+
+		hib_ppio_buffer_posn = 0;
+	}
+
+	return 0;
+}
+
+int hib_read_buffer(char *buffer, int buffer_size)
+{
+	int bytes_left = buffer_size, result = 0;
+
+	while (bytes_left) {
+		char *to = buffer + buffer_size - bytes_left;
+		char *from = hib_ppio_buffer + hib_ppio_buffer_posn;
+		int capacity = PAGE_SIZE - hib_ppio_buffer_posn;
+
+		if (bytes_left <= capacity) {
+			memcpy(to, from, bytes_left);
+			hib_ppio_buffer_posn += bytes_left;
+			return 0;
+		}
+
+		/* Complete this page and start a new one */
+		memcpy(to, from, capacity);
+		bytes_left -= capacity;
+
+		result = swap_read_page(hib_ppio_buffer, 1);
+		if (result) {
+			printk("swap_read_page returned %d.\n", result);
+			return result;
+		}
+
+		hib_ppio_buffer_posn = 0;
+	}
+
+	return 0;
+}
diff --git a/kernel/power/block_io.h b/kernel/power/block_io.h
index 2f91d6d..ac378c5 100644
--- a/kernel/power/block_io.h
+++ b/kernel/power/block_io.h
@@ -21,3 +21,7 @@ int swap_write_page(void *buf, int sync);
 int get_swap_reader(unsigned int *flags_p, sector_t first_page);
 void release_swap_reader(void);
 int swap_read_page(void *buf, int sync);
+int hib_flush_write_buffer(void);
+
+int hib_write_buffer(char *buffer, int len);
+int hib_read_buffer(char *buffer, int len);
-- 
1.7.0.4


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

* [PATCH 12/22] Hibernation: Partial page I/O support.
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (24 preceding siblings ...)
  2010-09-25  4:16 ` [PATCH 12/22] Hibernation: Partial page I/O support Nigel Cunningham
@ 2010-09-25  4:16 ` Nigel Cunningham
  2010-09-25  4:16 ` Nigel Cunningham
                   ` (29 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Add functions that can be used for coalescing and splitting buffers
that are smaller than PAGE_SIZE. These functions provide no method
of determining where the boundaries of the smaller buffers are to
be found - that is the caller's problem.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/block_io.c |   90 +++++++++++++++++++++++++++++++++++++++++++++++
 kernel/power/block_io.h |    4 ++
 2 files changed, 94 insertions(+), 0 deletions(-)

diff --git a/kernel/power/block_io.c b/kernel/power/block_io.c
index 5edcb08..bf6129b 100644
--- a/kernel/power/block_io.c
+++ b/kernel/power/block_io.c
@@ -17,6 +17,11 @@
 
 static struct bio *bio_chain;
 
+static char *hib_ppio_buffer;
+static int hib_ppio_buffer_posn;
+int hib_prepare_buffer(void);
+void hib_free_buffer(void);
+
 /**
  *	submit - submit BIO request.
  *	@rw:	READ or WRITE.
@@ -301,3 +306,88 @@ int swap_read_page(void *buf, int sync)
 	}
 	return error;
 }
+
+/* Part Page I/O functions */
+static char *hib_ppio_buffer;
+static int hib_ppio_buffer_posn;
+
+int hib_prepare_buffer(void)
+{
+	hib_ppio_buffer = (char *)__get_free_page(__GFP_WAIT);
+	hib_ppio_buffer_posn = 0;
+	return hib_ppio_buffer ? 0 : -ENOMEM;
+}
+
+void hib_free_buffer(void)
+{
+	if (!hib_ppio_buffer)
+		return;
+
+	free_page((unsigned long) hib_ppio_buffer);
+	hib_ppio_buffer = NULL;
+}
+
+int hib_flush_write_buffer(void)
+{
+	return hib_ppio_buffer_posn ? swap_write_page(hib_ppio_buffer, 0) : 0;
+}
+
+int hib_write_buffer(char *buffer, int buffer_size)
+{
+	int bytes_left = buffer_size, result = 0;
+
+	while (bytes_left) {
+		char *from = buffer + buffer_size - bytes_left;
+		char *to = hib_ppio_buffer + hib_ppio_buffer_posn;
+		int capacity = PAGE_SIZE - hib_ppio_buffer_posn;
+
+		if (bytes_left <= capacity) {
+			memcpy(to, from, bytes_left);
+			hib_ppio_buffer_posn += bytes_left;
+			return 0;
+		}
+
+		/* Complete this page and start a new one */
+		memcpy(to, from, capacity);
+		bytes_left -= capacity;
+
+		result = swap_write_page(hib_ppio_buffer, 0);
+		if (result)
+			return result;
+
+		hib_ppio_buffer_posn = 0;
+	}
+
+	return 0;
+}
+
+int hib_read_buffer(char *buffer, int buffer_size)
+{
+	int bytes_left = buffer_size, result = 0;
+
+	while (bytes_left) {
+		char *to = buffer + buffer_size - bytes_left;
+		char *from = hib_ppio_buffer + hib_ppio_buffer_posn;
+		int capacity = PAGE_SIZE - hib_ppio_buffer_posn;
+
+		if (bytes_left <= capacity) {
+			memcpy(to, from, bytes_left);
+			hib_ppio_buffer_posn += bytes_left;
+			return 0;
+		}
+
+		/* Complete this page and start a new one */
+		memcpy(to, from, capacity);
+		bytes_left -= capacity;
+
+		result = swap_read_page(hib_ppio_buffer, 1);
+		if (result) {
+			printk("swap_read_page returned %d.\n", result);
+			return result;
+		}
+
+		hib_ppio_buffer_posn = 0;
+	}
+
+	return 0;
+}
diff --git a/kernel/power/block_io.h b/kernel/power/block_io.h
index 2f91d6d..ac378c5 100644
--- a/kernel/power/block_io.h
+++ b/kernel/power/block_io.h
@@ -21,3 +21,7 @@ int swap_write_page(void *buf, int sync);
 int get_swap_reader(unsigned int *flags_p, sector_t first_page);
 void release_swap_reader(void);
 int swap_read_page(void *buf, int sync);
+int hib_flush_write_buffer(void);
+
+int hib_write_buffer(char *buffer, int len);
+int hib_read_buffer(char *buffer, int len);
-- 
1.7.0.4

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

* [PATCH 12/22] Hibernation: Partial page I/O support.
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (25 preceding siblings ...)
  2010-09-25  4:16 ` Nigel Cunningham
@ 2010-09-25  4:16 ` Nigel Cunningham
  2010-09-25  4:16 ` [PATCH 13/22] Hibernation: Extent save/load routines Nigel Cunningham
                   ` (28 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Add functions that can be used for coalescing and splitting buffers
that are smaller than PAGE_SIZE. These functions provide no method
of determining where the boundaries of the smaller buffers are to
be found - that is the caller's problem.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/block_io.c |   90 +++++++++++++++++++++++++++++++++++++++++++++++
 kernel/power/block_io.h |    4 ++
 2 files changed, 94 insertions(+), 0 deletions(-)

diff --git a/kernel/power/block_io.c b/kernel/power/block_io.c
index 5edcb08..bf6129b 100644
--- a/kernel/power/block_io.c
+++ b/kernel/power/block_io.c
@@ -17,6 +17,11 @@
 
 static struct bio *bio_chain;
 
+static char *hib_ppio_buffer;
+static int hib_ppio_buffer_posn;
+int hib_prepare_buffer(void);
+void hib_free_buffer(void);
+
 /**
  *	submit - submit BIO request.
  *	@rw:	READ or WRITE.
@@ -301,3 +306,88 @@ int swap_read_page(void *buf, int sync)
 	}
 	return error;
 }
+
+/* Part Page I/O functions */
+static char *hib_ppio_buffer;
+static int hib_ppio_buffer_posn;
+
+int hib_prepare_buffer(void)
+{
+	hib_ppio_buffer = (char *)__get_free_page(__GFP_WAIT);
+	hib_ppio_buffer_posn = 0;
+	return hib_ppio_buffer ? 0 : -ENOMEM;
+}
+
+void hib_free_buffer(void)
+{
+	if (!hib_ppio_buffer)
+		return;
+
+	free_page((unsigned long) hib_ppio_buffer);
+	hib_ppio_buffer = NULL;
+}
+
+int hib_flush_write_buffer(void)
+{
+	return hib_ppio_buffer_posn ? swap_write_page(hib_ppio_buffer, 0) : 0;
+}
+
+int hib_write_buffer(char *buffer, int buffer_size)
+{
+	int bytes_left = buffer_size, result = 0;
+
+	while (bytes_left) {
+		char *from = buffer + buffer_size - bytes_left;
+		char *to = hib_ppio_buffer + hib_ppio_buffer_posn;
+		int capacity = PAGE_SIZE - hib_ppio_buffer_posn;
+
+		if (bytes_left <= capacity) {
+			memcpy(to, from, bytes_left);
+			hib_ppio_buffer_posn += bytes_left;
+			return 0;
+		}
+
+		/* Complete this page and start a new one */
+		memcpy(to, from, capacity);
+		bytes_left -= capacity;
+
+		result = swap_write_page(hib_ppio_buffer, 0);
+		if (result)
+			return result;
+
+		hib_ppio_buffer_posn = 0;
+	}
+
+	return 0;
+}
+
+int hib_read_buffer(char *buffer, int buffer_size)
+{
+	int bytes_left = buffer_size, result = 0;
+
+	while (bytes_left) {
+		char *to = buffer + buffer_size - bytes_left;
+		char *from = hib_ppio_buffer + hib_ppio_buffer_posn;
+		int capacity = PAGE_SIZE - hib_ppio_buffer_posn;
+
+		if (bytes_left <= capacity) {
+			memcpy(to, from, bytes_left);
+			hib_ppio_buffer_posn += bytes_left;
+			return 0;
+		}
+
+		/* Complete this page and start a new one */
+		memcpy(to, from, capacity);
+		bytes_left -= capacity;
+
+		result = swap_read_page(hib_ppio_buffer, 1);
+		if (result) {
+			printk("swap_read_page returned %d.\n", result);
+			return result;
+		}
+
+		hib_ppio_buffer_posn = 0;
+	}
+
+	return 0;
+}
diff --git a/kernel/power/block_io.h b/kernel/power/block_io.h
index 2f91d6d..ac378c5 100644
--- a/kernel/power/block_io.h
+++ b/kernel/power/block_io.h
@@ -21,3 +21,7 @@ int swap_write_page(void *buf, int sync);
 int get_swap_reader(unsigned int *flags_p, sector_t first_page);
 void release_swap_reader(void);
 int swap_read_page(void *buf, int sync);
+int hib_flush_write_buffer(void);
+
+int hib_write_buffer(char *buffer, int len);
+int hib_read_buffer(char *buffer, int len);
-- 
1.7.0.4


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

* [PATCH 13/22] Hibernation: Extent save/load routines.
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (26 preceding siblings ...)
  2010-09-25  4:16 ` Nigel Cunningham
@ 2010-09-25  4:16 ` Nigel Cunningham
  2010-09-25 22:12   ` Rafael J. Wysocki
  2010-09-25 22:12   ` Rafael J. Wysocki
  2010-09-25  4:16 ` Nigel Cunningham
                   ` (27 subsequent siblings)
  55 siblings, 2 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Add routines for saving and reloading a chain of extents. This will
be used to store the block extents in the image header, rather than
in swap map pages.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/extents.c |   75 ++++++++++++++++++++++++++++++++++++++++++++++++
 kernel/power/extents.h |    5 +++
 2 files changed, 80 insertions(+), 0 deletions(-)

diff --git a/kernel/power/extents.c b/kernel/power/extents.c
index 172322d..75d2fb4 100644
--- a/kernel/power/extents.c
+++ b/kernel/power/extents.c
@@ -14,6 +14,7 @@
 
 #include <linux/slab.h>
 #include "extents.h"
+#include "block_io.h"
 
 int hib_extents_empty(struct hib_extent_state *pos)
 {
@@ -123,3 +124,77 @@ void hib_extents_clear(struct hib_extent_state *pos)
 		kfree(ext);
 	}
 }
+
+int hib_extents_storage_needed(struct hib_extent_state *pos)
+{
+	return sizeof(int) + pos->num_extents * 2 * sizeof(unsigned long);
+}
+
+int hib_extents_store(struct hib_extent_state *pos)
+{
+	struct rb_node *node;
+	struct hib_extent *ext;
+	int ret = hib_write_buffer((char *) &pos->num_extents, sizeof(int));
+
+	if (hib_extents_empty(pos))
+		return 0;
+
+	node = rb_first(&pos->root);
+	while (node) {
+		ext = container_of(node, struct hib_extent, node);
+		ret = hib_write_buffer((char *) &ext->start,
+				2 * sizeof(unsigned long));
+		if (ret)
+			return ret;
+		node = rb_next(node);
+	}
+
+	return 0;
+}
+
+int hib_extents_load(struct hib_extent_state *pos, int bootstrap)
+{
+	struct rb_node **new = &(pos->root.rb_node);
+	struct rb_node *parent = NULL;
+	struct hib_extent *existing, *adding;
+	int i;
+	int ret = hib_read_buffer((char *) &pos->num_extents, sizeof(int));
+
+	if (!pos->num_extents)
+		return 0;
+
+	for (i = 0; i < pos->num_extents; i++) {
+		adding = kzalloc(sizeof(struct hib_extent), GFP_KERNEL);
+		if (!adding)
+			return -ENOMEM;
+
+		ret = hib_read_buffer((char *) &adding->start,
+				2 * sizeof(unsigned long));
+		if (ret)
+			return ret;
+
+		/*
+		 * No need for some of the checks from inserting above -
+		 * they were done when preparing the image.
+		 */
+		while (*new) {
+			existing = container_of(*new, struct hib_extent, node);
+			parent = *new;
+			if (adding->end < existing->start)
+				new = &((*new)->rb_left);
+			else
+				new = &((*new)->rb_right);
+		}
+		rb_link_node(&adding->node, parent, new);
+		rb_insert_color(&adding->node, &pos->root);
+
+		if (bootstrap && !i) {
+			hib_reset_extent_pos(&sector_extents);
+
+			/* We have already read the first page */
+			hib_extent_next(&sector_extents);
+		}
+	}
+
+	return 0;
+}
diff --git a/kernel/power/extents.h b/kernel/power/extents.h
index 0b69b8e..4288f9e 100644
--- a/kernel/power/extents.h
+++ b/kernel/power/extents.h
@@ -33,3 +33,8 @@ unsigned long hib_extent_next(struct hib_extent_state *pos);
 int hib_extents_insert(struct hib_extent_state *pos, unsigned long value);
 void hib_extents_clear(struct hib_extent_state *pos);
 int hib_extents_empty(struct hib_extent_state *pos);
+
+/* Serialisation support */
+int hib_extents_storage_needed(struct hib_extent_state *pos);
+int hib_extents_store(struct hib_extent_state *pos);
+int hib_extents_load(struct hib_extent_state *pos, int bootstrap);
-- 
1.7.0.4


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

* [PATCH 13/22] Hibernation: Extent save/load routines.
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (27 preceding siblings ...)
  2010-09-25  4:16 ` [PATCH 13/22] Hibernation: Extent save/load routines Nigel Cunningham
@ 2010-09-25  4:16 ` Nigel Cunningham
  2010-09-25  4:16 ` [PATCH 14/22] Hibernation: Store block extents at start of image Nigel Cunningham
                   ` (26 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Add routines for saving and reloading a chain of extents. This will
be used to store the block extents in the image header, rather than
in swap map pages.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/extents.c |   75 ++++++++++++++++++++++++++++++++++++++++++++++++
 kernel/power/extents.h |    5 +++
 2 files changed, 80 insertions(+), 0 deletions(-)

diff --git a/kernel/power/extents.c b/kernel/power/extents.c
index 172322d..75d2fb4 100644
--- a/kernel/power/extents.c
+++ b/kernel/power/extents.c
@@ -14,6 +14,7 @@
 
 #include <linux/slab.h>
 #include "extents.h"
+#include "block_io.h"
 
 int hib_extents_empty(struct hib_extent_state *pos)
 {
@@ -123,3 +124,77 @@ void hib_extents_clear(struct hib_extent_state *pos)
 		kfree(ext);
 	}
 }
+
+int hib_extents_storage_needed(struct hib_extent_state *pos)
+{
+	return sizeof(int) + pos->num_extents * 2 * sizeof(unsigned long);
+}
+
+int hib_extents_store(struct hib_extent_state *pos)
+{
+	struct rb_node *node;
+	struct hib_extent *ext;
+	int ret = hib_write_buffer((char *) &pos->num_extents, sizeof(int));
+
+	if (hib_extents_empty(pos))
+		return 0;
+
+	node = rb_first(&pos->root);
+	while (node) {
+		ext = container_of(node, struct hib_extent, node);
+		ret = hib_write_buffer((char *) &ext->start,
+				2 * sizeof(unsigned long));
+		if (ret)
+			return ret;
+		node = rb_next(node);
+	}
+
+	return 0;
+}
+
+int hib_extents_load(struct hib_extent_state *pos, int bootstrap)
+{
+	struct rb_node **new = &(pos->root.rb_node);
+	struct rb_node *parent = NULL;
+	struct hib_extent *existing, *adding;
+	int i;
+	int ret = hib_read_buffer((char *) &pos->num_extents, sizeof(int));
+
+	if (!pos->num_extents)
+		return 0;
+
+	for (i = 0; i < pos->num_extents; i++) {
+		adding = kzalloc(sizeof(struct hib_extent), GFP_KERNEL);
+		if (!adding)
+			return -ENOMEM;
+
+		ret = hib_read_buffer((char *) &adding->start,
+				2 * sizeof(unsigned long));
+		if (ret)
+			return ret;
+
+		/*
+		 * No need for some of the checks from inserting above -
+		 * they were done when preparing the image.
+		 */
+		while (*new) {
+			existing = container_of(*new, struct hib_extent, node);
+			parent = *new;
+			if (adding->end < existing->start)
+				new = &((*new)->rb_left);
+			else
+				new = &((*new)->rb_right);
+		}
+		rb_link_node(&adding->node, parent, new);
+		rb_insert_color(&adding->node, &pos->root);
+
+		if (bootstrap && !i) {
+			hib_reset_extent_pos(&sector_extents);
+
+			/* We have already read the first page */
+			hib_extent_next(&sector_extents);
+		}
+	}
+
+	return 0;
+}
diff --git a/kernel/power/extents.h b/kernel/power/extents.h
index 0b69b8e..4288f9e 100644
--- a/kernel/power/extents.h
+++ b/kernel/power/extents.h
@@ -33,3 +33,8 @@ unsigned long hib_extent_next(struct hib_extent_state *pos);
 int hib_extents_insert(struct hib_extent_state *pos, unsigned long value);
 void hib_extents_clear(struct hib_extent_state *pos);
 int hib_extents_empty(struct hib_extent_state *pos);
+
+/* Serialisation support */
+int hib_extents_storage_needed(struct hib_extent_state *pos);
+int hib_extents_store(struct hib_extent_state *pos);
+int hib_extents_load(struct hib_extent_state *pos, int bootstrap);
-- 
1.7.0.4

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

* [PATCH 14/22] Hibernation: Store block extents at start of image
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (29 preceding siblings ...)
  2010-09-25  4:16 ` [PATCH 14/22] Hibernation: Store block extents at start of image Nigel Cunningham
@ 2010-09-25  4:16 ` Nigel Cunningham
  2010-09-25  4:16 ` [PATCH 15/22] Hibernation: Use block extents for reading image Nigel Cunningham
                   ` (24 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

This patch adds support for storing the list of extents being
used at the start of the image, prior to the header, in
preparation for switching from using swap map pages to these
extents, then removing the swap map pages.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/block_io.c |   59 ++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 51 insertions(+), 8 deletions(-)

diff --git a/kernel/power/block_io.c b/kernel/power/block_io.c
index bf6129b..89601d3 100644
--- a/kernel/power/block_io.c
+++ b/kernel/power/block_io.c
@@ -14,6 +14,7 @@
 
 #include "power.h"
 #include "extents.h"
+#include "block_io.h"
 
 static struct bio *bio_chain;
 
@@ -150,7 +151,9 @@ extern struct hib_extent_state sector_extents;
 /* Calculate the overhead needed for storing n pages */
 unsigned int hib_bio_overhead(unsigned int nr_pages)
 {
-	return DIV_ROUND_UP(nr_pages, MAP_PAGE_ENTRIES);
+	return DIV_ROUND_UP(nr_pages, MAP_PAGE_ENTRIES) +
+	       DIV_ROUND_UP(hib_extents_storage_needed(&sector_extents),
+			PAGE_SIZE);
 }
 
 /* Get the first sector of the image proper, for storing in the signature */
@@ -197,21 +200,34 @@ void release_swap_writer(void)
 
 int hib_bio_prepare_write(void)
 {
+	int result, result2;
+
 	handle.cur = (struct swap_map_page *)get_zeroed_page(GFP_KERNEL);
 
 	if (!handle.cur)
 		return -ENOMEM;
 
-	handle.cur_swap = hib_extent_next(&sector_extents);
-
-	if (!handle.cur_swap) {
+	result = hib_prepare_buffer();
+	if (result) {
 		release_swap_writer();
-		return -ENOSPC;
+		return result;
 	}
 
+	handle.first_sector = hib_extent_current(&sector_extents);
+
+	result = hib_extents_store(&sector_extents);
+	result2 = hib_flush_write_buffer();
+
+	handle.cur_swap = hib_extent_next(&sector_extents);
 	handle.k = 0;
-	handle.first_sector = handle.cur_swap;
-	return 0;
+
+	if (!handle.cur_swap)
+		result = -ENOSPC;
+
+	if (result || result2)
+		release_swap_writer();
+
+	return result ? result : result2;
 }
 
 int swap_write_page(void *buf, int sync)
@@ -268,6 +284,7 @@ void release_swap_reader(void)
 int get_swap_reader(unsigned int *flags_p, sector_t first_page)
 {
 	int error;
+	sector_t offset;
 
 	handle.cur = (struct swap_map_page *)get_zeroed_page(__GFP_WAIT | __GFP_HIGH);
 	if (!handle.cur)
@@ -278,8 +295,34 @@ int get_swap_reader(unsigned int *flags_p, sector_t first_page)
 		release_swap_reader();
 		return error;
 	}
+
+	error = hib_prepare_buffer();
+	if (error) {
+		release_swap_reader();
+		return error;
+	}
+
 	handle.k = 0;
-	return 0;
+
+	/* Bootstrap reading the extents */
+	memcpy(hib_ppio_buffer, handle.cur, PAGE_SIZE);
+	error = hib_extents_load(&sector_extents, 1);
+
+	if (error) {
+		release_swap_reader();
+		return error;
+	}
+
+	offset = hib_extent_next(&sector_extents);
+
+	/* Now read the first swap_map_page */
+	error = hib_bio_read_page(offset, handle.cur, 1);
+	if (error) {
+		release_swap_reader();
+		return error;
+	}
+
+	return error;
 }
 
 int swap_read_page(void *buf, int sync)
-- 
1.7.0.4


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

* [PATCH 14/22] Hibernation: Store block extents at start of image
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (28 preceding siblings ...)
  2010-09-25  4:16 ` Nigel Cunningham
@ 2010-09-25  4:16 ` Nigel Cunningham
  2010-09-25  4:16 ` Nigel Cunningham
                   ` (25 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

This patch adds support for storing the list of extents being
used at the start of the image, prior to the header, in
preparation for switching from using swap map pages to these
extents, then removing the swap map pages.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/block_io.c |   59 ++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 51 insertions(+), 8 deletions(-)

diff --git a/kernel/power/block_io.c b/kernel/power/block_io.c
index bf6129b..89601d3 100644
--- a/kernel/power/block_io.c
+++ b/kernel/power/block_io.c
@@ -14,6 +14,7 @@
 
 #include "power.h"
 #include "extents.h"
+#include "block_io.h"
 
 static struct bio *bio_chain;
 
@@ -150,7 +151,9 @@ extern struct hib_extent_state sector_extents;
 /* Calculate the overhead needed for storing n pages */
 unsigned int hib_bio_overhead(unsigned int nr_pages)
 {
-	return DIV_ROUND_UP(nr_pages, MAP_PAGE_ENTRIES);
+	return DIV_ROUND_UP(nr_pages, MAP_PAGE_ENTRIES) +
+	       DIV_ROUND_UP(hib_extents_storage_needed(&sector_extents),
+			PAGE_SIZE);
 }
 
 /* Get the first sector of the image proper, for storing in the signature */
@@ -197,21 +200,34 @@ void release_swap_writer(void)
 
 int hib_bio_prepare_write(void)
 {
+	int result, result2;
+
 	handle.cur = (struct swap_map_page *)get_zeroed_page(GFP_KERNEL);
 
 	if (!handle.cur)
 		return -ENOMEM;
 
-	handle.cur_swap = hib_extent_next(&sector_extents);
-
-	if (!handle.cur_swap) {
+	result = hib_prepare_buffer();
+	if (result) {
 		release_swap_writer();
-		return -ENOSPC;
+		return result;
 	}
 
+	handle.first_sector = hib_extent_current(&sector_extents);
+
+	result = hib_extents_store(&sector_extents);
+	result2 = hib_flush_write_buffer();
+
+	handle.cur_swap = hib_extent_next(&sector_extents);
 	handle.k = 0;
-	handle.first_sector = handle.cur_swap;
-	return 0;
+
+	if (!handle.cur_swap)
+		result = -ENOSPC;
+
+	if (result || result2)
+		release_swap_writer();
+
+	return result ? result : result2;
 }
 
 int swap_write_page(void *buf, int sync)
@@ -268,6 +284,7 @@ void release_swap_reader(void)
 int get_swap_reader(unsigned int *flags_p, sector_t first_page)
 {
 	int error;
+	sector_t offset;
 
 	handle.cur = (struct swap_map_page *)get_zeroed_page(__GFP_WAIT | __GFP_HIGH);
 	if (!handle.cur)
@@ -278,8 +295,34 @@ int get_swap_reader(unsigned int *flags_p, sector_t first_page)
 		release_swap_reader();
 		return error;
 	}
+
+	error = hib_prepare_buffer();
+	if (error) {
+		release_swap_reader();
+		return error;
+	}
+
 	handle.k = 0;
-	return 0;
+
+	/* Bootstrap reading the extents */
+	memcpy(hib_ppio_buffer, handle.cur, PAGE_SIZE);
+	error = hib_extents_load(&sector_extents, 1);
+
+	if (error) {
+		release_swap_reader();
+		return error;
+	}
+
+	offset = hib_extent_next(&sector_extents);
+
+	/* Now read the first swap_map_page */
+	error = hib_bio_read_page(offset, handle.cur, 1);
+	if (error) {
+		release_swap_reader();
+		return error;
+	}
+
+	return error;
 }
 
 int swap_read_page(void *buf, int sync)
-- 
1.7.0.4

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

* [PATCH 15/22] Hibernation: Use block extents for reading image
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (31 preceding siblings ...)
  2010-09-25  4:16 ` [PATCH 15/22] Hibernation: Use block extents for reading image Nigel Cunningham
@ 2010-09-25  4:16 ` Nigel Cunningham
  2010-09-25  4:16 ` [PATCH 16/22] Remove first_sector from swap_map_handle Nigel Cunningham
                   ` (22 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Switch from using swap map pages to using block extents for
knowing where the next page needs to be read from.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/block_io.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/kernel/power/block_io.c b/kernel/power/block_io.c
index 89601d3..f2bc044 100644
--- a/kernel/power/block_io.c
+++ b/kernel/power/block_io.c
@@ -332,7 +332,7 @@ int swap_read_page(void *buf, int sync)
 
 	if (!handle.cur)
 		return -EINVAL;
-	offset = handle.cur->entries[handle.k];
+	offset = hib_extent_next(&sector_extents);
 	if (!offset)
 		return -EFAULT;
 	error = hib_bio_read_page(offset, buf, sync);
@@ -341,7 +341,7 @@ int swap_read_page(void *buf, int sync)
 	if (++handle.k >= MAP_PAGE_ENTRIES) {
 		error = hib_wait_on_bio_chain();
 		handle.k = 0;
-		offset = handle.cur->next_swap;
+		offset = hib_extent_next(&sector_extents);
 		if (!offset)
 			release_swap_reader();
 		else if (!error)
-- 
1.7.0.4


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

* [PATCH 15/22] Hibernation: Use block extents for reading image
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (30 preceding siblings ...)
  2010-09-25  4:16 ` Nigel Cunningham
@ 2010-09-25  4:16 ` Nigel Cunningham
  2010-09-25  4:16 ` Nigel Cunningham
                   ` (23 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Switch from using swap map pages to using block extents for
knowing where the next page needs to be read from.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/block_io.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/kernel/power/block_io.c b/kernel/power/block_io.c
index 89601d3..f2bc044 100644
--- a/kernel/power/block_io.c
+++ b/kernel/power/block_io.c
@@ -332,7 +332,7 @@ int swap_read_page(void *buf, int sync)
 
 	if (!handle.cur)
 		return -EINVAL;
-	offset = handle.cur->entries[handle.k];
+	offset = hib_extent_next(&sector_extents);
 	if (!offset)
 		return -EFAULT;
 	error = hib_bio_read_page(offset, buf, sync);
@@ -341,7 +341,7 @@ int swap_read_page(void *buf, int sync)
 	if (++handle.k >= MAP_PAGE_ENTRIES) {
 		error = hib_wait_on_bio_chain();
 		handle.k = 0;
-		offset = handle.cur->next_swap;
+		offset = hib_extent_next(&sector_extents);
 		if (!offset)
 			release_swap_reader();
 		else if (!error)
-- 
1.7.0.4

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

* [PATCH 16/22] Remove first_sector from swap_map_handle
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (32 preceding siblings ...)
  2010-09-25  4:16 ` Nigel Cunningham
@ 2010-09-25  4:16 ` Nigel Cunningham
  2010-09-25  4:16 ` Nigel Cunningham
                   ` (21 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Remove the 'first_sector' variable from the swap_map_handle
struct. It will continue to be used whereas the other members
of the struct will be deleted in a following patch.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/block_io.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/kernel/power/block_io.c b/kernel/power/block_io.c
index f2bc044..e6709db 100644
--- a/kernel/power/block_io.c
+++ b/kernel/power/block_io.c
@@ -140,10 +140,10 @@ struct swap_map_page {
 struct swap_map_handle {
 	struct swap_map_page *cur;
 	sector_t cur_swap;
-	sector_t first_sector;
 	unsigned int k;
 };
 
+static sector_t first_sector;
 static struct swap_map_handle handle;
 
 extern struct hib_extent_state sector_extents;
@@ -159,7 +159,7 @@ unsigned int hib_bio_overhead(unsigned int nr_pages)
 /* Get the first sector of the image proper, for storing in the signature */
 sector_t hib_get_first_sector(void)
 {
-	return handle.first_sector;
+	return first_sector;
 }
 
 /**
@@ -213,7 +213,7 @@ int hib_bio_prepare_write(void)
 		return result;
 	}
 
-	handle.first_sector = hib_extent_current(&sector_extents);
+	first_sector = hib_extent_current(&sector_extents);
 
 	result = hib_extents_store(&sector_extents);
 	result2 = hib_flush_write_buffer();
-- 
1.7.0.4


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

* [PATCH 16/22] Remove first_sector from swap_map_handle
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (33 preceding siblings ...)
  2010-09-25  4:16 ` [PATCH 16/22] Remove first_sector from swap_map_handle Nigel Cunningham
@ 2010-09-25  4:16 ` Nigel Cunningham
  2010-09-25  4:16 ` [PATCH 17/22] Hibernation: Replace bio chain Nigel Cunningham
                   ` (20 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Remove the 'first_sector' variable from the swap_map_handle
struct. It will continue to be used whereas the other members
of the struct will be deleted in a following patch.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/block_io.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/kernel/power/block_io.c b/kernel/power/block_io.c
index f2bc044..e6709db 100644
--- a/kernel/power/block_io.c
+++ b/kernel/power/block_io.c
@@ -140,10 +140,10 @@ struct swap_map_page {
 struct swap_map_handle {
 	struct swap_map_page *cur;
 	sector_t cur_swap;
-	sector_t first_sector;
 	unsigned int k;
 };
 
+static sector_t first_sector;
 static struct swap_map_handle handle;
 
 extern struct hib_extent_state sector_extents;
@@ -159,7 +159,7 @@ unsigned int hib_bio_overhead(unsigned int nr_pages)
 /* Get the first sector of the image proper, for storing in the signature */
 sector_t hib_get_first_sector(void)
 {
-	return handle.first_sector;
+	return first_sector;
 }
 
 /**
@@ -213,7 +213,7 @@ int hib_bio_prepare_write(void)
 		return result;
 	}
 
-	handle.first_sector = hib_extent_current(&sector_extents);
+	first_sector = hib_extent_current(&sector_extents);
 
 	result = hib_extents_store(&sector_extents);
 	result2 = hib_flush_write_buffer();
-- 
1.7.0.4

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

* [PATCH 17/22] Hibernation: Replace bio chain
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (35 preceding siblings ...)
  2010-09-25  4:16 ` [PATCH 17/22] Hibernation: Replace bio chain Nigel Cunningham
@ 2010-09-25  4:16 ` Nigel Cunningham
  2010-09-25  4:17 ` [PATCH 18/22] Hibernation: Remove swap_map_pages Nigel Cunningham
                   ` (18 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Replace the bio_chain concept with:
(1) simple atomic_t recording how many pages are in flight
(2) a wait queue for waiting for all I/O to complete
(3) a custom completion routine that frees bio structs and pages used
    for async writes as they complete, undates the atomic_t and
    wakes any waiters.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/block_io.c |   77 ++++++++++++++++++++++++++++------------------
 1 files changed, 47 insertions(+), 30 deletions(-)

diff --git a/kernel/power/block_io.c b/kernel/power/block_io.c
index e6709db..24b6db5 100644
--- a/kernel/power/block_io.c
+++ b/kernel/power/block_io.c
@@ -16,23 +16,61 @@
 #include "extents.h"
 #include "block_io.h"
 
-static struct bio *bio_chain;
-
 static char *hib_ppio_buffer;
 static int hib_ppio_buffer_posn;
 int hib_prepare_buffer(void);
 void hib_free_buffer(void);
 
+static atomic_t hib_io_in_progress;
+static DECLARE_WAIT_QUEUE_HEAD(num_in_progress_wait);
+
+/**
+ * hib_end_bio - bio completion function.
+ * @bio: bio that has completed.
+ * @err: Error value. Yes, like end_swap_bio_read, we ignore it.
+ *
+ * Function called by the block driver from interrupt context when I/O is
+ * completed. If we were writing the page, we want to free it and will have
+ * set bio->bi_private to the parameter we should use in telling the page
+ * allocation accounting code what the page was allocated for. If we're
+ * reading the page, it will be in the singly linked list made from
+ * page->private pointers.
+ **/
+static void hib_end_bio(struct bio *bio, int err)
+{
+	const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
+	struct page *page = bio->bi_io_vec[0].bv_page;
+
+	if (!uptodate) {
+		SetPageError(page);
+		ClearPageUptodate(page);
+		printk(KERN_ALERT "I/O on swap-device (%u:%u:%Lu)\n",
+				imajor(bio->bi_bdev->bd_inode),
+				iminor(bio->bi_bdev->bd_inode),
+				(unsigned long long)bio->bi_sector);
+	} else {
+		SetPageUptodate(page);
+	}
+	unlock_page(page);
+	bio_put(bio);
+
+	if (bio->bi_private)
+		__free_page(page);
+
+	atomic_dec(&hib_io_in_progress);
+	wake_up(&num_in_progress_wait);
+}
+
 /**
  *	submit - submit BIO request.
  *	@rw:	READ or WRITE.
  *	@off	physical offset of page.
  *	@page:	page we're reading or writing.
- *	@bio_chain: list of pending biod (for async reading)
+ *	@sync:	whether the i/o should be done synchronously
  *
  *	Straight from the textbook - allocate and initialize the bio.
  *	If we're reading, make sure the page is marked as dirty.
- *	Then submit it and, if @bio_chain == NULL, wait.
+ *	Then submit it and, if @sync, wait.
  */
 static int submit(int rw, struct block_device *bdev, sector_t sector,
 		struct page *page, int sync)
@@ -43,7 +81,8 @@ static int submit(int rw, struct block_device *bdev, sector_t sector,
 	bio = bio_alloc(__GFP_WAIT | __GFP_HIGH, 1);
 	bio->bi_sector = sector;
 	bio->bi_bdev = bdev;
-	bio->bi_end_io = end_swap_bio_read;
+	bio->bi_private = (void *) (rw && !sync);
+	bio->bi_end_io = hib_end_bio;
 
 	if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) {
 		printk(KERN_ERR "PM: Adding page to bio failed at %llu\n",
@@ -54,6 +93,7 @@ static int submit(int rw, struct block_device *bdev, sector_t sector,
 
 	lock_page(page);
 	bio_get(bio);
+	atomic_inc(&hib_io_in_progress);
 
 	if (sync) {
 		submit_bio(bio_rw, bio);
@@ -64,8 +104,6 @@ static int submit(int rw, struct block_device *bdev, sector_t sector,
 	} else {
 		if (rw == READ)
 			get_page(page);	/* These pages are freed later */
-		bio->bi_private = bio_chain;
-		bio_chain = bio;
 		submit_bio(bio_rw, bio);
 	}
 	return 0;
@@ -85,29 +123,8 @@ int hib_bio_write_page(pgoff_t page_off, void *addr, int sync)
 
 int hib_wait_on_bio_chain(void)
 {
-	struct bio *bio;
-	struct bio *next_bio;
-	int ret = 0;
-
-	if (bio_chain == NULL)
-		return 0;
-
-	bio = bio_chain;
-
-	while (bio) {
-		struct page *page;
-
-		next_bio = bio->bi_private;
-		page = bio->bi_io_vec[0].bv_page;
-		wait_on_page_locked(page);
-		if (!PageUptodate(page) || PageError(page))
-			ret = -EIO;
-		put_page(page);
-		bio_put(bio);
-		bio = next_bio;
-	}
-	bio_chain = NULL;
-	return ret;
+	wait_event(num_in_progress_wait, !atomic_read(&hib_io_in_progress));
+	return 0;
 }
 
 /*
-- 
1.7.0.4


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

* [PATCH 17/22] Hibernation: Replace bio chain
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (34 preceding siblings ...)
  2010-09-25  4:16 ` Nigel Cunningham
@ 2010-09-25  4:16 ` Nigel Cunningham
  2010-09-25  4:16 ` Nigel Cunningham
                   ` (19 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:16 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Replace the bio_chain concept with:
(1) simple atomic_t recording how many pages are in flight
(2) a wait queue for waiting for all I/O to complete
(3) a custom completion routine that frees bio structs and pages used
    for async writes as they complete, undates the atomic_t and
    wakes any waiters.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/block_io.c |   77 ++++++++++++++++++++++++++++------------------
 1 files changed, 47 insertions(+), 30 deletions(-)

diff --git a/kernel/power/block_io.c b/kernel/power/block_io.c
index e6709db..24b6db5 100644
--- a/kernel/power/block_io.c
+++ b/kernel/power/block_io.c
@@ -16,23 +16,61 @@
 #include "extents.h"
 #include "block_io.h"
 
-static struct bio *bio_chain;
-
 static char *hib_ppio_buffer;
 static int hib_ppio_buffer_posn;
 int hib_prepare_buffer(void);
 void hib_free_buffer(void);
 
+static atomic_t hib_io_in_progress;
+static DECLARE_WAIT_QUEUE_HEAD(num_in_progress_wait);
+
+/**
+ * hib_end_bio - bio completion function.
+ * @bio: bio that has completed.
+ * @err: Error value. Yes, like end_swap_bio_read, we ignore it.
+ *
+ * Function called by the block driver from interrupt context when I/O is
+ * completed. If we were writing the page, we want to free it and will have
+ * set bio->bi_private to the parameter we should use in telling the page
+ * allocation accounting code what the page was allocated for. If we're
+ * reading the page, it will be in the singly linked list made from
+ * page->private pointers.
+ **/
+static void hib_end_bio(struct bio *bio, int err)
+{
+	const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
+	struct page *page = bio->bi_io_vec[0].bv_page;
+
+	if (!uptodate) {
+		SetPageError(page);
+		ClearPageUptodate(page);
+		printk(KERN_ALERT "I/O on swap-device (%u:%u:%Lu)\n",
+				imajor(bio->bi_bdev->bd_inode),
+				iminor(bio->bi_bdev->bd_inode),
+				(unsigned long long)bio->bi_sector);
+	} else {
+		SetPageUptodate(page);
+	}
+	unlock_page(page);
+	bio_put(bio);
+
+	if (bio->bi_private)
+		__free_page(page);
+
+	atomic_dec(&hib_io_in_progress);
+	wake_up(&num_in_progress_wait);
+}
+
 /**
  *	submit - submit BIO request.
  *	@rw:	READ or WRITE.
  *	@off	physical offset of page.
  *	@page:	page we're reading or writing.
- *	@bio_chain: list of pending biod (for async reading)
+ *	@sync:	whether the i/o should be done synchronously
  *
  *	Straight from the textbook - allocate and initialize the bio.
  *	If we're reading, make sure the page is marked as dirty.
- *	Then submit it and, if @bio_chain == NULL, wait.
+ *	Then submit it and, if @sync, wait.
  */
 static int submit(int rw, struct block_device *bdev, sector_t sector,
 		struct page *page, int sync)
@@ -43,7 +81,8 @@ static int submit(int rw, struct block_device *bdev, sector_t sector,
 	bio = bio_alloc(__GFP_WAIT | __GFP_HIGH, 1);
 	bio->bi_sector = sector;
 	bio->bi_bdev = bdev;
-	bio->bi_end_io = end_swap_bio_read;
+	bio->bi_private = (void *) (rw && !sync);
+	bio->bi_end_io = hib_end_bio;
 
 	if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) {
 		printk(KERN_ERR "PM: Adding page to bio failed at %llu\n",
@@ -54,6 +93,7 @@ static int submit(int rw, struct block_device *bdev, sector_t sector,
 
 	lock_page(page);
 	bio_get(bio);
+	atomic_inc(&hib_io_in_progress);
 
 	if (sync) {
 		submit_bio(bio_rw, bio);
@@ -64,8 +104,6 @@ static int submit(int rw, struct block_device *bdev, sector_t sector,
 	} else {
 		if (rw == READ)
 			get_page(page);	/* These pages are freed later */
-		bio->bi_private = bio_chain;
-		bio_chain = bio;
 		submit_bio(bio_rw, bio);
 	}
 	return 0;
@@ -85,29 +123,8 @@ int hib_bio_write_page(pgoff_t page_off, void *addr, int sync)
 
 int hib_wait_on_bio_chain(void)
 {
-	struct bio *bio;
-	struct bio *next_bio;
-	int ret = 0;
-
-	if (bio_chain == NULL)
-		return 0;
-
-	bio = bio_chain;
-
-	while (bio) {
-		struct page *page;
-
-		next_bio = bio->bi_private;
-		page = bio->bi_io_vec[0].bv_page;
-		wait_on_page_locked(page);
-		if (!PageUptodate(page) || PageError(page))
-			ret = -EIO;
-		put_page(page);
-		bio_put(bio);
-		bio = next_bio;
-	}
-	bio_chain = NULL;
-	return ret;
+	wait_event(num_in_progress_wait, !atomic_read(&hib_io_in_progress));
+	return 0;
 }
 
 /*
-- 
1.7.0.4

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

* [PATCH 18/22] Hibernation: Remove swap_map_pages
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (36 preceding siblings ...)
  2010-09-25  4:16 ` Nigel Cunningham
@ 2010-09-25  4:17 ` Nigel Cunningham
  2010-09-25  4:17 ` Nigel Cunningham
                   ` (17 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:17 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Stop storing swap_map pages in the image. This removes the need
for a wait_on_bio_chain every MAP_PAGE_ENTRIES pages and thus
allows the whole image to be written using async I/O.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/block_io.c |   61 +++-------------------------------------------
 1 files changed, 4 insertions(+), 57 deletions(-)

diff --git a/kernel/power/block_io.c b/kernel/power/block_io.c
index 24b6db5..b068b5a 100644
--- a/kernel/power/block_io.c
+++ b/kernel/power/block_io.c
@@ -156,7 +156,6 @@ struct swap_map_page {
 
 struct swap_map_handle {
 	struct swap_map_page *cur;
-	sector_t cur_swap;
 	unsigned int k;
 };
 
@@ -168,8 +167,7 @@ extern struct hib_extent_state sector_extents;
 /* Calculate the overhead needed for storing n pages */
 unsigned int hib_bio_overhead(unsigned int nr_pages)
 {
-	return DIV_ROUND_UP(nr_pages, MAP_PAGE_ENTRIES) +
-	       DIV_ROUND_UP(hib_extents_storage_needed(&sector_extents),
+	return DIV_ROUND_UP(hib_extents_storage_needed(&sector_extents),
 			PAGE_SIZE);
 }
 
@@ -235,12 +233,8 @@ int hib_bio_prepare_write(void)
 	result = hib_extents_store(&sector_extents);
 	result2 = hib_flush_write_buffer();
 
-	handle.cur_swap = hib_extent_next(&sector_extents);
 	handle.k = 0;
 
-	if (!handle.cur_swap)
-		result = -ENOSPC;
-
 	if (result || result2)
 		release_swap_writer();
 
@@ -249,41 +243,17 @@ int hib_bio_prepare_write(void)
 
 int swap_write_page(void *buf, int sync)
 {
-	int error = 0;
 	sector_t offset;
 
 	if (!handle.cur)
 		return -EINVAL;
 	offset = hib_extent_next(&sector_extents);
-	error = write_page(buf, offset, sync);
-	if (error)
-		return error;
-	handle.cur->entries[handle.k++] = offset;
-	if (handle.k >= MAP_PAGE_ENTRIES) {
-		error = hib_wait_on_bio_chain();
-		if (error)
-			goto out;
-		offset = hib_extent_next(&sector_extents);
-		if (!offset)
-			return -ENOSPC;
-		handle.cur->next_swap = offset;
-		error = write_page(handle.cur, handle.cur_swap, 1);
-		if (error)
-			goto out;
-		memset(handle.cur, 0, PAGE_SIZE);
-		handle.cur_swap = offset;
-		handle.k = 0;
-	}
- out:
-	return error;
+	return write_page(buf, offset, sync);
 }
 
 int flush_swap_writer(void)
 {
-	if (handle.cur && handle.cur_swap)
-		return write_page(handle.cur, handle.cur_swap, 1);
-	else
-		return -EINVAL;
+	return hib_wait_on_bio_chain();
 }
 
 /**
@@ -301,7 +271,6 @@ void release_swap_reader(void)
 int get_swap_reader(unsigned int *flags_p, sector_t first_page)
 {
 	int error;
-	sector_t offset;
 
 	handle.cur = (struct swap_map_page *)get_zeroed_page(__GFP_WAIT | __GFP_HIGH);
 	if (!handle.cur)
@@ -330,41 +299,19 @@ int get_swap_reader(unsigned int *flags_p, sector_t first_page)
 		return error;
 	}
 
-	offset = hib_extent_next(&sector_extents);
-
-	/* Now read the first swap_map_page */
-	error = hib_bio_read_page(offset, handle.cur, 1);
-	if (error) {
-		release_swap_reader();
-		return error;
-	}
-
 	return error;
 }
 
 int swap_read_page(void *buf, int sync)
 {
 	sector_t offset;
-	int error;
 
 	if (!handle.cur)
 		return -EINVAL;
 	offset = hib_extent_next(&sector_extents);
 	if (!offset)
 		return -EFAULT;
-	error = hib_bio_read_page(offset, buf, sync);
-	if (error)
-		return error;
-	if (++handle.k >= MAP_PAGE_ENTRIES) {
-		error = hib_wait_on_bio_chain();
-		handle.k = 0;
-		offset = hib_extent_next(&sector_extents);
-		if (!offset)
-			release_swap_reader();
-		else if (!error)
-			error = hib_bio_read_page(offset, handle.cur, 1);
-	}
-	return error;
+	return hib_bio_read_page(offset, buf, sync);
 }
 
 /* Part Page I/O functions */
-- 
1.7.0.4


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

* [PATCH 18/22] Hibernation: Remove swap_map_pages
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (37 preceding siblings ...)
  2010-09-25  4:17 ` [PATCH 18/22] Hibernation: Remove swap_map_pages Nigel Cunningham
@ 2010-09-25  4:17 ` Nigel Cunningham
  2010-09-25  4:17 ` [PATCH 19/22] Hibernation: Remove wait_on_bio_chain result Nigel Cunningham
                   ` (16 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:17 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Stop storing swap_map pages in the image. This removes the need
for a wait_on_bio_chain every MAP_PAGE_ENTRIES pages and thus
allows the whole image to be written using async I/O.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/block_io.c |   61 +++-------------------------------------------
 1 files changed, 4 insertions(+), 57 deletions(-)

diff --git a/kernel/power/block_io.c b/kernel/power/block_io.c
index 24b6db5..b068b5a 100644
--- a/kernel/power/block_io.c
+++ b/kernel/power/block_io.c
@@ -156,7 +156,6 @@ struct swap_map_page {
 
 struct swap_map_handle {
 	struct swap_map_page *cur;
-	sector_t cur_swap;
 	unsigned int k;
 };
 
@@ -168,8 +167,7 @@ extern struct hib_extent_state sector_extents;
 /* Calculate the overhead needed for storing n pages */
 unsigned int hib_bio_overhead(unsigned int nr_pages)
 {
-	return DIV_ROUND_UP(nr_pages, MAP_PAGE_ENTRIES) +
-	       DIV_ROUND_UP(hib_extents_storage_needed(&sector_extents),
+	return DIV_ROUND_UP(hib_extents_storage_needed(&sector_extents),
 			PAGE_SIZE);
 }
 
@@ -235,12 +233,8 @@ int hib_bio_prepare_write(void)
 	result = hib_extents_store(&sector_extents);
 	result2 = hib_flush_write_buffer();
 
-	handle.cur_swap = hib_extent_next(&sector_extents);
 	handle.k = 0;
 
-	if (!handle.cur_swap)
-		result = -ENOSPC;
-
 	if (result || result2)
 		release_swap_writer();
 
@@ -249,41 +243,17 @@ int hib_bio_prepare_write(void)
 
 int swap_write_page(void *buf, int sync)
 {
-	int error = 0;
 	sector_t offset;
 
 	if (!handle.cur)
 		return -EINVAL;
 	offset = hib_extent_next(&sector_extents);
-	error = write_page(buf, offset, sync);
-	if (error)
-		return error;
-	handle.cur->entries[handle.k++] = offset;
-	if (handle.k >= MAP_PAGE_ENTRIES) {
-		error = hib_wait_on_bio_chain();
-		if (error)
-			goto out;
-		offset = hib_extent_next(&sector_extents);
-		if (!offset)
-			return -ENOSPC;
-		handle.cur->next_swap = offset;
-		error = write_page(handle.cur, handle.cur_swap, 1);
-		if (error)
-			goto out;
-		memset(handle.cur, 0, PAGE_SIZE);
-		handle.cur_swap = offset;
-		handle.k = 0;
-	}
- out:
-	return error;
+	return write_page(buf, offset, sync);
 }
 
 int flush_swap_writer(void)
 {
-	if (handle.cur && handle.cur_swap)
-		return write_page(handle.cur, handle.cur_swap, 1);
-	else
-		return -EINVAL;
+	return hib_wait_on_bio_chain();
 }
 
 /**
@@ -301,7 +271,6 @@ void release_swap_reader(void)
 int get_swap_reader(unsigned int *flags_p, sector_t first_page)
 {
 	int error;
-	sector_t offset;
 
 	handle.cur = (struct swap_map_page *)get_zeroed_page(__GFP_WAIT | __GFP_HIGH);
 	if (!handle.cur)
@@ -330,41 +299,19 @@ int get_swap_reader(unsigned int *flags_p, sector_t first_page)
 		return error;
 	}
 
-	offset = hib_extent_next(&sector_extents);
-
-	/* Now read the first swap_map_page */
-	error = hib_bio_read_page(offset, handle.cur, 1);
-	if (error) {
-		release_swap_reader();
-		return error;
-	}
-
 	return error;
 }
 
 int swap_read_page(void *buf, int sync)
 {
 	sector_t offset;
-	int error;
 
 	if (!handle.cur)
 		return -EINVAL;
 	offset = hib_extent_next(&sector_extents);
 	if (!offset)
 		return -EFAULT;
-	error = hib_bio_read_page(offset, buf, sync);
-	if (error)
-		return error;
-	if (++handle.k >= MAP_PAGE_ENTRIES) {
-		error = hib_wait_on_bio_chain();
-		handle.k = 0;
-		offset = hib_extent_next(&sector_extents);
-		if (!offset)
-			release_swap_reader();
-		else if (!error)
-			error = hib_bio_read_page(offset, handle.cur, 1);
-	}
-	return error;
+	return hib_bio_read_page(offset, buf, sync);
 }
 
 /* Part Page I/O functions */
-- 
1.7.0.4

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

* [PATCH 19/22] Hibernation: Remove wait_on_bio_chain result
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (38 preceding siblings ...)
  2010-09-25  4:17 ` Nigel Cunningham
@ 2010-09-25  4:17 ` Nigel Cunningham
  2010-09-25  4:17 ` Nigel Cunningham
                   ` (15 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:17 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

wait_on_bio_chain can't fail - make the result void instead
of int.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/block_io.c |    6 +++---
 kernel/power/block_io.h |    2 +-
 kernel/power/power.h    |    2 +-
 kernel/power/swap.c     |   14 +++-----------
 4 files changed, 8 insertions(+), 16 deletions(-)

diff --git a/kernel/power/block_io.c b/kernel/power/block_io.c
index b068b5a..c154a92 100644
--- a/kernel/power/block_io.c
+++ b/kernel/power/block_io.c
@@ -121,10 +121,9 @@ int hib_bio_write_page(pgoff_t page_off, void *addr, int sync)
 			virt_to_page(addr), sync);
 }
 
-int hib_wait_on_bio_chain(void)
+void hib_wait_on_bio_chain(void)
 {
 	wait_event(num_in_progress_wait, !atomic_read(&hib_io_in_progress));
-	return 0;
 }
 
 /*
@@ -253,7 +252,8 @@ int swap_write_page(void *buf, int sync)
 
 int flush_swap_writer(void)
 {
-	return hib_wait_on_bio_chain();
+	hib_wait_on_bio_chain();
+	return 0;
 }
 
 /**
diff --git a/kernel/power/block_io.h b/kernel/power/block_io.h
index ac378c5..1482060 100644
--- a/kernel/power/block_io.h
+++ b/kernel/power/block_io.h
@@ -9,7 +9,7 @@
 /* Low level routines */
 int hib_bio_read_page(pgoff_t page_off, void *addr, int sync);
 int hib_bio_write_page(pgoff_t page_off, void *addr, int sync);
-int hib_wait_on_bio_chain(void);
+void hib_wait_on_bio_chain(void);
 
 unsigned int hib_bio_overhead(unsigned int nr_pages);
 sector_t hib_get_first_sector(void);
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 1750f64..a9a6093 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -149,7 +149,7 @@ extern struct block_device *hib_resume_bdev;
 
 extern int hib_bio_read_page(pgoff_t page_off, void *addr, int sync);
 extern int hib_bio_write_page(pgoff_t page_off, void *addr, int sync);
-extern int hib_wait_on_bio_chain(void);
+extern void hib_wait_on_bio_chain(void);
 
 struct timeval;
 /* kernel/power/swsusp.c */
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index d217a6f..d3e5939 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -239,7 +239,6 @@ static int save_image(struct snapshot_handle *snapshot,
 	unsigned int m;
 	int ret;
 	int nr_pages;
-	int err2;
 	struct timeval start;
 	struct timeval stop;
 	int mps;
@@ -262,11 +261,9 @@ static int save_image(struct snapshot_handle *snapshot,
 			printk(KERN_CONT "\b\b\b\b%3d%%", nr_pages / m);
 		nr_pages++;
 	}
-	err2 = hib_wait_on_bio_chain();
+	hib_wait_on_bio_chain();
 	do_gettimeofday(&stop);
 	if (!ret)
-		ret = err2;
-	if (!ret)
 		printk(KERN_CONT "\b\b\b\bdone\n");
 	else
 		printk(KERN_CONT "\n");
@@ -334,7 +331,6 @@ static int load_image(struct snapshot_handle *snapshot, unsigned int nr_to_read)
 	int error = 0;
 	struct timeval start;
 	struct timeval stop;
-	int err2;
 	unsigned nr_pages;
 	int mps;
 
@@ -353,17 +349,13 @@ static int load_image(struct snapshot_handle *snapshot, unsigned int nr_to_read)
 		if (error)
 			break;
 		if (snapshot->sync_read)
-			error = hib_wait_on_bio_chain();
-		if (error)
-			break;
+			hib_wait_on_bio_chain();
 		if (!(nr_pages % m))
 			printk("\b\b\b\b%3d%%", nr_pages / m);
 		nr_pages++;
 	}
-	err2 = hib_wait_on_bio_chain();
+	hib_wait_on_bio_chain();
 	do_gettimeofday(&stop);
-	if (!error)
-		error = err2;
 	if (!error) {
 		printk("\b\b\b\bdone\n");
 		snapshot_write_finalize(snapshot);
-- 
1.7.0.4


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

* [PATCH 19/22] Hibernation: Remove wait_on_bio_chain result
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (39 preceding siblings ...)
  2010-09-25  4:17 ` [PATCH 19/22] Hibernation: Remove wait_on_bio_chain result Nigel Cunningham
@ 2010-09-25  4:17 ` Nigel Cunningham
  2010-09-25  4:17 ` [PATCH 20/22] Hibernation: Prepare for handle.cur removal Nigel Cunningham
                   ` (14 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:17 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

wait_on_bio_chain can't fail - make the result void instead
of int.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/block_io.c |    6 +++---
 kernel/power/block_io.h |    2 +-
 kernel/power/power.h    |    2 +-
 kernel/power/swap.c     |   14 +++-----------
 4 files changed, 8 insertions(+), 16 deletions(-)

diff --git a/kernel/power/block_io.c b/kernel/power/block_io.c
index b068b5a..c154a92 100644
--- a/kernel/power/block_io.c
+++ b/kernel/power/block_io.c
@@ -121,10 +121,9 @@ int hib_bio_write_page(pgoff_t page_off, void *addr, int sync)
 			virt_to_page(addr), sync);
 }
 
-int hib_wait_on_bio_chain(void)
+void hib_wait_on_bio_chain(void)
 {
 	wait_event(num_in_progress_wait, !atomic_read(&hib_io_in_progress));
-	return 0;
 }
 
 /*
@@ -253,7 +252,8 @@ int swap_write_page(void *buf, int sync)
 
 int flush_swap_writer(void)
 {
-	return hib_wait_on_bio_chain();
+	hib_wait_on_bio_chain();
+	return 0;
 }
 
 /**
diff --git a/kernel/power/block_io.h b/kernel/power/block_io.h
index ac378c5..1482060 100644
--- a/kernel/power/block_io.h
+++ b/kernel/power/block_io.h
@@ -9,7 +9,7 @@
 /* Low level routines */
 int hib_bio_read_page(pgoff_t page_off, void *addr, int sync);
 int hib_bio_write_page(pgoff_t page_off, void *addr, int sync);
-int hib_wait_on_bio_chain(void);
+void hib_wait_on_bio_chain(void);
 
 unsigned int hib_bio_overhead(unsigned int nr_pages);
 sector_t hib_get_first_sector(void);
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 1750f64..a9a6093 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -149,7 +149,7 @@ extern struct block_device *hib_resume_bdev;
 
 extern int hib_bio_read_page(pgoff_t page_off, void *addr, int sync);
 extern int hib_bio_write_page(pgoff_t page_off, void *addr, int sync);
-extern int hib_wait_on_bio_chain(void);
+extern void hib_wait_on_bio_chain(void);
 
 struct timeval;
 /* kernel/power/swsusp.c */
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index d217a6f..d3e5939 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -239,7 +239,6 @@ static int save_image(struct snapshot_handle *snapshot,
 	unsigned int m;
 	int ret;
 	int nr_pages;
-	int err2;
 	struct timeval start;
 	struct timeval stop;
 	int mps;
@@ -262,11 +261,9 @@ static int save_image(struct snapshot_handle *snapshot,
 			printk(KERN_CONT "\b\b\b\b%3d%%", nr_pages / m);
 		nr_pages++;
 	}
-	err2 = hib_wait_on_bio_chain();
+	hib_wait_on_bio_chain();
 	do_gettimeofday(&stop);
 	if (!ret)
-		ret = err2;
-	if (!ret)
 		printk(KERN_CONT "\b\b\b\bdone\n");
 	else
 		printk(KERN_CONT "\n");
@@ -334,7 +331,6 @@ static int load_image(struct snapshot_handle *snapshot, unsigned int nr_to_read)
 	int error = 0;
 	struct timeval start;
 	struct timeval stop;
-	int err2;
 	unsigned nr_pages;
 	int mps;
 
@@ -353,17 +349,13 @@ static int load_image(struct snapshot_handle *snapshot, unsigned int nr_to_read)
 		if (error)
 			break;
 		if (snapshot->sync_read)
-			error = hib_wait_on_bio_chain();
-		if (error)
-			break;
+			hib_wait_on_bio_chain();
 		if (!(nr_pages % m))
 			printk("\b\b\b\b%3d%%", nr_pages / m);
 		nr_pages++;
 	}
-	err2 = hib_wait_on_bio_chain();
+	hib_wait_on_bio_chain();
 	do_gettimeofday(&stop);
-	if (!error)
-		error = err2;
 	if (!error) {
 		printk("\b\b\b\bdone\n");
 		snapshot_write_finalize(snapshot);
-- 
1.7.0.4

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

* [PATCH 20/22] Hibernation: Prepare for handle.cur removal
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (40 preceding siblings ...)
  2010-09-25  4:17 ` Nigel Cunningham
@ 2010-09-25  4:17 ` Nigel Cunningham
  2010-09-25  4:17 ` Nigel Cunningham
                   ` (13 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:17 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Prepare for the removal of handle.cur by stopping using
it in get_swap_reader.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/block_io.c |   10 +++++-----
 1 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/kernel/power/block_io.c b/kernel/power/block_io.c
index c154a92..4f46878 100644
--- a/kernel/power/block_io.c
+++ b/kernel/power/block_io.c
@@ -276,29 +276,29 @@ int get_swap_reader(unsigned int *flags_p, sector_t first_page)
 	if (!handle.cur)
 		return -ENOMEM;
 
-	error = hib_bio_read_page(first_page, handle.cur, 1);
+	error = hib_prepare_buffer();
 	if (error) {
 		release_swap_reader();
 		return error;
 	}
 
-	error = hib_prepare_buffer();
+	/* Bootstrap reading the extents */
+	error = hib_bio_read_page(first_page, hib_ppio_buffer, 1);
 	if (error) {
 		release_swap_reader();
+		hib_free_buffer();
 		return error;
 	}
 
 	handle.k = 0;
 
-	/* Bootstrap reading the extents */
-	memcpy(hib_ppio_buffer, handle.cur, PAGE_SIZE);
 	error = hib_extents_load(&sector_extents, 1);
 
 	if (error) {
 		release_swap_reader();
-		return error;
 	}
 
+	hib_free_buffer();
 	return error;
 }
 
-- 
1.7.0.4


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

* [PATCH 20/22] Hibernation: Prepare for handle.cur removal
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (41 preceding siblings ...)
  2010-09-25  4:17 ` [PATCH 20/22] Hibernation: Prepare for handle.cur removal Nigel Cunningham
@ 2010-09-25  4:17 ` Nigel Cunningham
  2010-09-25  4:17 ` [PATCH 21/22] Hibernation: Remove swap_map structure Nigel Cunningham
                   ` (12 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:17 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Prepare for the removal of handle.cur by stopping using
it in get_swap_reader.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/block_io.c |   10 +++++-----
 1 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/kernel/power/block_io.c b/kernel/power/block_io.c
index c154a92..4f46878 100644
--- a/kernel/power/block_io.c
+++ b/kernel/power/block_io.c
@@ -276,29 +276,29 @@ int get_swap_reader(unsigned int *flags_p, sector_t first_page)
 	if (!handle.cur)
 		return -ENOMEM;
 
-	error = hib_bio_read_page(first_page, handle.cur, 1);
+	error = hib_prepare_buffer();
 	if (error) {
 		release_swap_reader();
 		return error;
 	}
 
-	error = hib_prepare_buffer();
+	/* Bootstrap reading the extents */
+	error = hib_bio_read_page(first_page, hib_ppio_buffer, 1);
 	if (error) {
 		release_swap_reader();
+		hib_free_buffer();
 		return error;
 	}
 
 	handle.k = 0;
 
-	/* Bootstrap reading the extents */
-	memcpy(hib_ppio_buffer, handle.cur, PAGE_SIZE);
 	error = hib_extents_load(&sector_extents, 1);
 
 	if (error) {
 		release_swap_reader();
-		return error;
 	}
 
+	hib_free_buffer();
 	return error;
 }
 
-- 
1.7.0.4

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

* [PATCH 21/22] Hibernation: Remove swap_map structure
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (43 preceding siblings ...)
  2010-09-25  4:17 ` [PATCH 21/22] Hibernation: Remove swap_map structure Nigel Cunningham
@ 2010-09-25  4:17 ` Nigel Cunningham
  2010-09-25  4:17 ` [PATCH 22/22] Hibernation: Remove now-empty routines Nigel Cunningham
                   ` (10 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:17 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Remove the now unused swap_map structure and associated
swap_map_handle.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/block_io.c |   56 -----------------------------------------------
 1 files changed, 0 insertions(+), 56 deletions(-)

diff --git a/kernel/power/block_io.c b/kernel/power/block_io.c
index 4f46878..f452650 100644
--- a/kernel/power/block_io.c
+++ b/kernel/power/block_io.c
@@ -126,40 +126,7 @@ void hib_wait_on_bio_chain(void)
 	wait_event(num_in_progress_wait, !atomic_read(&hib_io_in_progress));
 }
 
-/*
- *	The swap map is a data structure used for keeping track of each page
- *	written to a swap partition.  It consists of many swap_map_page
- *	structures that contain each an array of MAP_PAGE_SIZE swap entries.
- *	These structures are stored on the swap and linked together with the
- *	help of the .next_swap member.
- *
- *	The swap map is created during suspend.  The swap map pages are
- *	allocated and populated one at a time, so we only need one memory
- *	page to set up the entire structure.
- *
- *	During resume we also only need to use one swap_map_page structure
- *	at a time.
- */
-
-#define MAP_PAGE_ENTRIES	(PAGE_SIZE / sizeof(sector_t) - 1)
-
-struct swap_map_page {
-	sector_t entries[MAP_PAGE_ENTRIES];
-	sector_t next_swap;
-};
-
-/**
- *	The swap_map_handle structure is used for handling swap in
- *	a file-alike way
- */
-
-struct swap_map_handle {
-	struct swap_map_page *cur;
-	unsigned int k;
-};
-
 static sector_t first_sector;
-static struct swap_map_handle handle;
 
 extern struct hib_extent_state sector_extents;
 
@@ -207,20 +174,12 @@ static int write_page(void *buf, sector_t offset, int sync)
 
 void release_swap_writer(void)
 {
-	if (handle.cur)
-		free_page((unsigned long)handle.cur);
-	handle.cur = NULL;
 }
 
 int hib_bio_prepare_write(void)
 {
 	int result, result2;
 
-	handle.cur = (struct swap_map_page *)get_zeroed_page(GFP_KERNEL);
-
-	if (!handle.cur)
-		return -ENOMEM;
-
 	result = hib_prepare_buffer();
 	if (result) {
 		release_swap_writer();
@@ -232,8 +191,6 @@ int hib_bio_prepare_write(void)
 	result = hib_extents_store(&sector_extents);
 	result2 = hib_flush_write_buffer();
 
-	handle.k = 0;
-
 	if (result || result2)
 		release_swap_writer();
 
@@ -244,8 +201,6 @@ int swap_write_page(void *buf, int sync)
 {
 	sector_t offset;
 
-	if (!handle.cur)
-		return -EINVAL;
 	offset = hib_extent_next(&sector_extents);
 	return write_page(buf, offset, sync);
 }
@@ -263,19 +218,12 @@ int flush_swap_writer(void)
 
 void release_swap_reader(void)
 {
-	if (handle.cur)
-		free_page((unsigned long)handle.cur);
-	handle.cur = NULL;
 }
 
 int get_swap_reader(unsigned int *flags_p, sector_t first_page)
 {
 	int error;
 
-	handle.cur = (struct swap_map_page *)get_zeroed_page(__GFP_WAIT | __GFP_HIGH);
-	if (!handle.cur)
-		return -ENOMEM;
-
 	error = hib_prepare_buffer();
 	if (error) {
 		release_swap_reader();
@@ -290,8 +238,6 @@ int get_swap_reader(unsigned int *flags_p, sector_t first_page)
 		return error;
 	}
 
-	handle.k = 0;
-
 	error = hib_extents_load(&sector_extents, 1);
 
 	if (error) {
@@ -306,8 +252,6 @@ int swap_read_page(void *buf, int sync)
 {
 	sector_t offset;
 
-	if (!handle.cur)
-		return -EINVAL;
 	offset = hib_extent_next(&sector_extents);
 	if (!offset)
 		return -EFAULT;
-- 
1.7.0.4


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

* [PATCH 21/22] Hibernation: Remove swap_map structure
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (42 preceding siblings ...)
  2010-09-25  4:17 ` Nigel Cunningham
@ 2010-09-25  4:17 ` Nigel Cunningham
  2010-09-25  4:17 ` Nigel Cunningham
                   ` (11 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:17 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Remove the now unused swap_map structure and associated
swap_map_handle.

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/block_io.c |   56 -----------------------------------------------
 1 files changed, 0 insertions(+), 56 deletions(-)

diff --git a/kernel/power/block_io.c b/kernel/power/block_io.c
index 4f46878..f452650 100644
--- a/kernel/power/block_io.c
+++ b/kernel/power/block_io.c
@@ -126,40 +126,7 @@ void hib_wait_on_bio_chain(void)
 	wait_event(num_in_progress_wait, !atomic_read(&hib_io_in_progress));
 }
 
-/*
- *	The swap map is a data structure used for keeping track of each page
- *	written to a swap partition.  It consists of many swap_map_page
- *	structures that contain each an array of MAP_PAGE_SIZE swap entries.
- *	These structures are stored on the swap and linked together with the
- *	help of the .next_swap member.
- *
- *	The swap map is created during suspend.  The swap map pages are
- *	allocated and populated one at a time, so we only need one memory
- *	page to set up the entire structure.
- *
- *	During resume we also only need to use one swap_map_page structure
- *	at a time.
- */
-
-#define MAP_PAGE_ENTRIES	(PAGE_SIZE / sizeof(sector_t) - 1)
-
-struct swap_map_page {
-	sector_t entries[MAP_PAGE_ENTRIES];
-	sector_t next_swap;
-};
-
-/**
- *	The swap_map_handle structure is used for handling swap in
- *	a file-alike way
- */
-
-struct swap_map_handle {
-	struct swap_map_page *cur;
-	unsigned int k;
-};
-
 static sector_t first_sector;
-static struct swap_map_handle handle;
 
 extern struct hib_extent_state sector_extents;
 
@@ -207,20 +174,12 @@ static int write_page(void *buf, sector_t offset, int sync)
 
 void release_swap_writer(void)
 {
-	if (handle.cur)
-		free_page((unsigned long)handle.cur);
-	handle.cur = NULL;
 }
 
 int hib_bio_prepare_write(void)
 {
 	int result, result2;
 
-	handle.cur = (struct swap_map_page *)get_zeroed_page(GFP_KERNEL);
-
-	if (!handle.cur)
-		return -ENOMEM;
-
 	result = hib_prepare_buffer();
 	if (result) {
 		release_swap_writer();
@@ -232,8 +191,6 @@ int hib_bio_prepare_write(void)
 	result = hib_extents_store(&sector_extents);
 	result2 = hib_flush_write_buffer();
 
-	handle.k = 0;
-
 	if (result || result2)
 		release_swap_writer();
 
@@ -244,8 +201,6 @@ int swap_write_page(void *buf, int sync)
 {
 	sector_t offset;
 
-	if (!handle.cur)
-		return -EINVAL;
 	offset = hib_extent_next(&sector_extents);
 	return write_page(buf, offset, sync);
 }
@@ -263,19 +218,12 @@ int flush_swap_writer(void)
 
 void release_swap_reader(void)
 {
-	if (handle.cur)
-		free_page((unsigned long)handle.cur);
-	handle.cur = NULL;
 }
 
 int get_swap_reader(unsigned int *flags_p, sector_t first_page)
 {
 	int error;
 
-	handle.cur = (struct swap_map_page *)get_zeroed_page(__GFP_WAIT | __GFP_HIGH);
-	if (!handle.cur)
-		return -ENOMEM;
-
 	error = hib_prepare_buffer();
 	if (error) {
 		release_swap_reader();
@@ -290,8 +238,6 @@ int get_swap_reader(unsigned int *flags_p, sector_t first_page)
 		return error;
 	}
 
-	handle.k = 0;
-
 	error = hib_extents_load(&sector_extents, 1);
 
 	if (error) {
@@ -306,8 +252,6 @@ int swap_read_page(void *buf, int sync)
 {
 	sector_t offset;
 
-	if (!handle.cur)
-		return -EINVAL;
 	offset = hib_extent_next(&sector_extents);
 	if (!offset)
 		return -EFAULT;
-- 
1.7.0.4

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

* [PATCH 22/22] Hibernation: Remove now-empty routines.
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (45 preceding siblings ...)
  2010-09-25  4:17 ` [PATCH 22/22] Hibernation: Remove now-empty routines Nigel Cunningham
@ 2010-09-25  4:17 ` Nigel Cunningham
  2010-09-25 15:04 ` [linux-pm] Nigel's current for-rafael queue Martin Steigerwald
                   ` (8 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:17 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

release_swap_writer and release_swap_reader are now empty functions.
Remove them and clean up callers (including swap_reader_finish, which
just called release_swap_reader).

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/block_io.c |   36 ++++--------------------------------
 kernel/power/block_io.h |    2 --
 kernel/power/swap.c     |    9 ---------
 3 files changed, 4 insertions(+), 43 deletions(-)

diff --git a/kernel/power/block_io.c b/kernel/power/block_io.c
index f452650..fc2e05d 100644
--- a/kernel/power/block_io.c
+++ b/kernel/power/block_io.c
@@ -172,28 +172,19 @@ static int write_page(void *buf, sector_t offset, int sync)
 	return hib_bio_write_page(offset, src, sync);
 }
 
-void release_swap_writer(void)
-{
-}
-
 int hib_bio_prepare_write(void)
 {
 	int result, result2;
 
 	result = hib_prepare_buffer();
-	if (result) {
-		release_swap_writer();
+	if (result)
 		return result;
-	}
 
 	first_sector = hib_extent_current(&sector_extents);
 
 	result = hib_extents_store(&sector_extents);
 	result2 = hib_flush_write_buffer();
 
-	if (result || result2)
-		release_swap_writer();
-
 	return result ? result : result2;
 }
 
@@ -211,38 +202,19 @@ int flush_swap_writer(void)
 	return 0;
 }
 
-/**
- *	The following functions allow us to read data using a swap map
- *	in a file-alike way
- */
-
-void release_swap_reader(void)
-{
-}
-
 int get_swap_reader(unsigned int *flags_p, sector_t first_page)
 {
 	int error;
 
 	error = hib_prepare_buffer();
-	if (error) {
-		release_swap_reader();
+	if (error)
 		return error;
-	}
 
 	/* Bootstrap reading the extents */
 	error = hib_bio_read_page(first_page, hib_ppio_buffer, 1);
-	if (error) {
-		release_swap_reader();
-		hib_free_buffer();
-		return error;
-	}
 
-	error = hib_extents_load(&sector_extents, 1);
-
-	if (error) {
-		release_swap_reader();
-	}
+	if (!error)
+		error = hib_extents_load(&sector_extents, 1);
 
 	hib_free_buffer();
 	return error;
diff --git a/kernel/power/block_io.h b/kernel/power/block_io.h
index 1482060..228fe58 100644
--- a/kernel/power/block_io.h
+++ b/kernel/power/block_io.h
@@ -14,12 +14,10 @@ void hib_wait_on_bio_chain(void);
 unsigned int hib_bio_overhead(unsigned int nr_pages);
 sector_t hib_get_first_sector(void);
 extern struct hib_extent_state sector_extents;
-void release_swap_writer(void);
 int hib_bio_prepare_write(void);
 int flush_swap_writer(void);
 int swap_write_page(void *buf, int sync);
 int get_swap_reader(unsigned int *flags_p, sector_t first_page);
-void release_swap_reader(void);
 int swap_read_page(void *buf, int sync);
 int hib_flush_write_buffer(void);
 
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index d3e5939..5669f92 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -223,7 +223,6 @@ static int swap_writer_finish(unsigned int flags, int error)
 
 	if (error)
 		free_all_swap_pages(root_swap);
-	release_swap_writer();
 	swsusp_close(FMODE_WRITE);
 
 	return error;
@@ -312,13 +311,6 @@ out_finish:
 	return error;
 }
 
-static int swap_reader_finish(void)
-{
-	release_swap_reader();
-
-	return 0;
-}
-
 /**
  *	load_image - load the image using the swap map handle
  *	@handle and the snapshot handle @snapshot
@@ -397,7 +389,6 @@ int swsusp_read(unsigned int *flags_p)
 		error = swap_read_page(header, 1);
 	if (!error)
 		error = load_image(&snapshot, header->pages - 1);
-	swap_reader_finish();
 end:
 	if (!error)
 		pr_debug("PM: Image successfully loaded\n");
-- 
1.7.0.4


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

* [PATCH 22/22] Hibernation: Remove now-empty routines.
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (44 preceding siblings ...)
  2010-09-25  4:17 ` Nigel Cunningham
@ 2010-09-25  4:17 ` Nigel Cunningham
  2010-09-25  4:17 ` Nigel Cunningham
                   ` (9 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25  4:17 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

release_swap_writer and release_swap_reader are now empty functions.
Remove them and clean up callers (including swap_reader_finish, which
just called release_swap_reader).

Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
 kernel/power/block_io.c |   36 ++++--------------------------------
 kernel/power/block_io.h |    2 --
 kernel/power/swap.c     |    9 ---------
 3 files changed, 4 insertions(+), 43 deletions(-)

diff --git a/kernel/power/block_io.c b/kernel/power/block_io.c
index f452650..fc2e05d 100644
--- a/kernel/power/block_io.c
+++ b/kernel/power/block_io.c
@@ -172,28 +172,19 @@ static int write_page(void *buf, sector_t offset, int sync)
 	return hib_bio_write_page(offset, src, sync);
 }
 
-void release_swap_writer(void)
-{
-}
-
 int hib_bio_prepare_write(void)
 {
 	int result, result2;
 
 	result = hib_prepare_buffer();
-	if (result) {
-		release_swap_writer();
+	if (result)
 		return result;
-	}
 
 	first_sector = hib_extent_current(&sector_extents);
 
 	result = hib_extents_store(&sector_extents);
 	result2 = hib_flush_write_buffer();
 
-	if (result || result2)
-		release_swap_writer();
-
 	return result ? result : result2;
 }
 
@@ -211,38 +202,19 @@ int flush_swap_writer(void)
 	return 0;
 }
 
-/**
- *	The following functions allow us to read data using a swap map
- *	in a file-alike way
- */
-
-void release_swap_reader(void)
-{
-}
-
 int get_swap_reader(unsigned int *flags_p, sector_t first_page)
 {
 	int error;
 
 	error = hib_prepare_buffer();
-	if (error) {
-		release_swap_reader();
+	if (error)
 		return error;
-	}
 
 	/* Bootstrap reading the extents */
 	error = hib_bio_read_page(first_page, hib_ppio_buffer, 1);
-	if (error) {
-		release_swap_reader();
-		hib_free_buffer();
-		return error;
-	}
 
-	error = hib_extents_load(&sector_extents, 1);
-
-	if (error) {
-		release_swap_reader();
-	}
+	if (!error)
+		error = hib_extents_load(&sector_extents, 1);
 
 	hib_free_buffer();
 	return error;
diff --git a/kernel/power/block_io.h b/kernel/power/block_io.h
index 1482060..228fe58 100644
--- a/kernel/power/block_io.h
+++ b/kernel/power/block_io.h
@@ -14,12 +14,10 @@ void hib_wait_on_bio_chain(void);
 unsigned int hib_bio_overhead(unsigned int nr_pages);
 sector_t hib_get_first_sector(void);
 extern struct hib_extent_state sector_extents;
-void release_swap_writer(void);
 int hib_bio_prepare_write(void);
 int flush_swap_writer(void);
 int swap_write_page(void *buf, int sync);
 int get_swap_reader(unsigned int *flags_p, sector_t first_page);
-void release_swap_reader(void);
 int swap_read_page(void *buf, int sync);
 int hib_flush_write_buffer(void);
 
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index d3e5939..5669f92 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -223,7 +223,6 @@ static int swap_writer_finish(unsigned int flags, int error)
 
 	if (error)
 		free_all_swap_pages(root_swap);
-	release_swap_writer();
 	swsusp_close(FMODE_WRITE);
 
 	return error;
@@ -312,13 +311,6 @@ out_finish:
 	return error;
 }
 
-static int swap_reader_finish(void)
-{
-	release_swap_reader();
-
-	return 0;
-}
-
 /**
  *	load_image - load the image using the swap map handle
  *	@handle and the snapshot handle @snapshot
@@ -397,7 +389,6 @@ int swsusp_read(unsigned int *flags_p)
 		error = swap_read_page(header, 1);
 	if (!error)
 		error = load_image(&snapshot, header->pages - 1);
-	swap_reader_finish();
 end:
 	if (!error)
 		pr_debug("PM: Image successfully loaded\n");
-- 
1.7.0.4

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

* Re: [linux-pm] Nigel's current for-rafael queue
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (46 preceding siblings ...)
  2010-09-25  4:17 ` Nigel Cunningham
@ 2010-09-25 15:04 ` Martin Steigerwald
  2010-09-25 21:21   ` Nigel Cunningham
  2010-09-25 21:21   ` Nigel Cunningham
  2010-09-25 15:04 ` Martin Steigerwald
                   ` (7 subsequent siblings)
  55 siblings, 2 replies; 80+ messages in thread
From: Martin Steigerwald @ 2010-09-25 15:04 UTC (permalink / raw)
  To: linux-pm; +Cc: Nigel Cunningham, Rafael J. Wysocki, LKML, TuxOnIce-devel

[-- Attachment #1: Type: Text/Plain, Size: 1069 bytes --]

Am Samstag 25 September 2010 schrieb Nigel Cunningham:
> Hi Rafael.

Hi Nigel,
 
> Please find attached a slightly updated version of the patchset I sent
> a few months ago. The main change is that I've prepended and additional
> patch which lets the user see the speed at which the image is being
> read and written. This is accomplished by recording the MB/s in a
> single byte in the image header, and using a couple of __nosavedata
> variables to get the data back through the atomic restore. I realise
> the char limits us to 255MB/s at the moment. In future patches, I
> intend to address this by storing the data in a 'proper' image header
> (it's a real problem - TuxOnIce reads and writes on the same set up at
> speeds around 250MB/s).

I like to help by testing these. Is it sufficient to check out your latest 
tuxonice tree, checkout branch for-rafael and switch the hibernate script 
to TryMethod disk.conf?

Thanks,
-- 
Martin 'Helios' Steigerwald - http://www.Lichtvoll.de
GPG: 03B0 0D6C 0040 0710 4AFA  B82F 991B EAAC A599 84C7

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

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

* Re: Nigel's current for-rafael queue
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (48 preceding siblings ...)
  2010-09-25 15:04 ` Martin Steigerwald
@ 2010-09-25 15:04 ` Martin Steigerwald
  2010-09-25 22:19 ` Rafael J. Wysocki
                   ` (5 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Martin Steigerwald @ 2010-09-25 15:04 UTC (permalink / raw)
  To: linux-pm; +Cc: LKML, TuxOnIce-devel


[-- Attachment #1.1: Type: Text/Plain, Size: 1069 bytes --]

Am Samstag 25 September 2010 schrieb Nigel Cunningham:
> Hi Rafael.

Hi Nigel,
 
> Please find attached a slightly updated version of the patchset I sent
> a few months ago. The main change is that I've prepended and additional
> patch which lets the user see the speed at which the image is being
> read and written. This is accomplished by recording the MB/s in a
> single byte in the image header, and using a couple of __nosavedata
> variables to get the data back through the atomic restore. I realise
> the char limits us to 255MB/s at the moment. In future patches, I
> intend to address this by storing the data in a 'proper' image header
> (it's a real problem - TuxOnIce reads and writes on the same set up at
> speeds around 250MB/s).

I like to help by testing these. Is it sufficient to check out your latest 
tuxonice tree, checkout branch for-rafael and switch the hibernate script 
to TryMethod disk.conf?

Thanks,
-- 
Martin 'Helios' Steigerwald - http://www.Lichtvoll.de
GPG: 03B0 0D6C 0040 0710 4AFA  B82F 991B EAAC A599 84C7

[-- Attachment #1.2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

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



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

* Re: Nigel's current for-rafael queue
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (47 preceding siblings ...)
  2010-09-25 15:04 ` [linux-pm] Nigel's current for-rafael queue Martin Steigerwald
@ 2010-09-25 15:04 ` Martin Steigerwald
  2010-09-25 15:04 ` Martin Steigerwald
                   ` (6 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Martin Steigerwald @ 2010-09-25 15:04 UTC (permalink / raw)
  To: linux-pm; +Cc: LKML, TuxOnIce-devel


[-- Attachment #1.1: Type: Text/Plain, Size: 1069 bytes --]

Am Samstag 25 September 2010 schrieb Nigel Cunningham:
> Hi Rafael.

Hi Nigel,
 
> Please find attached a slightly updated version of the patchset I sent
> a few months ago. The main change is that I've prepended and additional
> patch which lets the user see the speed at which the image is being
> read and written. This is accomplished by recording the MB/s in a
> single byte in the image header, and using a couple of __nosavedata
> variables to get the data back through the atomic restore. I realise
> the char limits us to 255MB/s at the moment. In future patches, I
> intend to address this by storing the data in a 'proper' image header
> (it's a real problem - TuxOnIce reads and writes on the same set up at
> speeds around 250MB/s).

I like to help by testing these. Is it sufficient to check out your latest 
tuxonice tree, checkout branch for-rafael and switch the hibernate script 
to TryMethod disk.conf?

Thanks,
-- 
Martin 'Helios' Steigerwald - http://www.Lichtvoll.de
GPG: 03B0 0D6C 0040 0710 4AFA  B82F 991B EAAC A599 84C7

[-- Attachment #1.2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

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



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

* Re: [linux-pm] Nigel's current for-rafael queue
  2010-09-25 15:04 ` [linux-pm] Nigel's current for-rafael queue Martin Steigerwald
@ 2010-09-25 21:21   ` Nigel Cunningham
  2010-09-25 21:21   ` Nigel Cunningham
  1 sibling, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25 21:21 UTC (permalink / raw)
  To: Martin Steigerwald; +Cc: linux-pm, Rafael J. Wysocki, LKML, TuxOnIce-devel

Hi again.

(I know from your more recent email that you already know the answer to 
this, but others might be interested so I'll reply anyway).

On 26/09/10 01:04, Martin Steigerwald wrote:
> Am Samstag 25 September 2010 schrieb Nigel Cunningham:
>> Hi Rafael.
>
> Hi Nigel,
>
>> Please find attached a slightly updated version of the patchset I sent
>> a few months ago. The main change is that I've prepended and additional
>> patch which lets the user see the speed at which the image is being
>> read and written. This is accomplished by recording the MB/s in a
>> single byte in the image header, and using a couple of __nosavedata
>> variables to get the data back through the atomic restore. I realise
>> the char limits us to 255MB/s at the moment. In future patches, I
>> intend to address this by storing the data in a 'proper' image header
>> (it's a real problem - TuxOnIce reads and writes on the same set up at
>> speeds around 250MB/s).
>
> I like to help by testing these. Is it sufficient to check out your latest
> tuxonice tree, checkout branch for-rafael and switch the hibernate script
> to TryMethod disk.conf?

Yes, that should be sufficient. You do need to be aware (as I said in 
the other reply) that I'm treating this branch like a temporary branch, 
so it's getting rebased and having little modifications made to it. 
Pulling will therefore sometimes require the use of the force option.

Regards,

Nigel

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

* Re: Nigel's current for-rafael queue
  2010-09-25 15:04 ` [linux-pm] Nigel's current for-rafael queue Martin Steigerwald
  2010-09-25 21:21   ` Nigel Cunningham
@ 2010-09-25 21:21   ` Nigel Cunningham
  1 sibling, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25 21:21 UTC (permalink / raw)
  To: Martin Steigerwald; +Cc: linux-pm, LKML, TuxOnIce-devel

Hi again.

(I know from your more recent email that you already know the answer to 
this, but others might be interested so I'll reply anyway).

On 26/09/10 01:04, Martin Steigerwald wrote:
> Am Samstag 25 September 2010 schrieb Nigel Cunningham:
>> Hi Rafael.
>
> Hi Nigel,
>
>> Please find attached a slightly updated version of the patchset I sent
>> a few months ago. The main change is that I've prepended and additional
>> patch which lets the user see the speed at which the image is being
>> read and written. This is accomplished by recording the MB/s in a
>> single byte in the image header, and using a couple of __nosavedata
>> variables to get the data back through the atomic restore. I realise
>> the char limits us to 255MB/s at the moment. In future patches, I
>> intend to address this by storing the data in a 'proper' image header
>> (it's a real problem - TuxOnIce reads and writes on the same set up at
>> speeds around 250MB/s).
>
> I like to help by testing these. Is it sufficient to check out your latest
> tuxonice tree, checkout branch for-rafael and switch the hibernate script
> to TryMethod disk.conf?

Yes, that should be sufficient. You do need to be aware (as I said in 
the other reply) that I'm treating this branch like a temporary branch, 
so it's getting rebased and having little modifications made to it. 
Pulling will therefore sometimes require the use of the force option.

Regards,

Nigel

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

* Re: [PATCH 05/22] Hibernation: Switch to preallocating swap.
  2010-09-25  4:16 ` [PATCH 05/22] Hibernation: Switch to preallocating swap Nigel Cunningham
@ 2010-09-25 21:24   ` Rafael J. Wysocki
  2010-09-25 21:32     ` Nigel Cunningham
  2010-09-25 21:32     ` Nigel Cunningham
  2010-09-25 21:24   ` Rafael J. Wysocki
  2010-09-25 21:24   ` Rafael J. Wysocki
  2 siblings, 2 replies; 80+ messages in thread
From: Rafael J. Wysocki @ 2010-09-25 21:24 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: Linux PM, LKML, TuxOnIce-devel

On Saturday, September 25, 2010, Nigel Cunningham wrote:
> Switch from allocating swap as the image is written to allocating
> storage prior to writing the image.

Hmm, I think I know what the patch does, but I don't really understand the
changelog.  Care to explain/fix?

Thanks,
Rafael


> Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
> ---
>  kernel/power/swap.c |   62 ++++++++++++++++++++++++++++++--------------------
>  1 files changed, 37 insertions(+), 25 deletions(-)
> 
> diff --git a/kernel/power/swap.c b/kernel/power/swap.c
> index cebf91c..bebd2cf 100644
> --- a/kernel/power/swap.c
> +++ b/kernel/power/swap.c
> @@ -202,6 +202,33 @@ int alloc_swapdev_blocks(int needed)
>  }
>  
>  /**
> + *	allocate_swap - Allocate enough swap to save the image.
> + *
> + *	Calculates the number of swap pages actually needed and seeks
> + *	to allocate that many from the resume partition. Returns TRUE
> + *	or FALSE to indicate whether we got enough storage.
> + */
> +
> +static int allocate_swap(unsigned int nr_pages)
> +{
> +	unsigned int free_swap = count_swap_pages(root_swap, 1);
> +
> +	nr_pages += DIV_ROUND_UP(nr_pages, MAP_PAGE_ENTRIES);
> +
> +	pr_debug("PM: Free swap pages: %u\n", free_swap);
> +	if (free_swap < nr_pages)
> +		return 0;
> +
> +	if (alloc_swapdev_blocks(nr_pages) < nr_pages) {
> +		free_all_swap_pages(root_swap);
> +		return 0;
> +	}
> +
> +	reset_storage_pos();
> +	return 1;
> +}
> +
> +/**
>   *	free_all_swap_pages - free swap pages allocated for saving image data.
>   *	It also frees the extents used to register which swap entries had been
>   *	allocated.
> @@ -324,7 +351,7 @@ static void release_swap_writer(struct swap_map_handle *handle)
>  	handle->cur = NULL;
>  }
>  
> -static int get_swap_writer(struct swap_map_handle *handle)
> +static int get_swap_writer(struct swap_map_handle *handle, unsigned long pages)
>  {
>  	int ret;
>  
> @@ -340,7 +367,12 @@ static int get_swap_writer(struct swap_map_handle *handle)
>  		ret = -ENOMEM;
>  		goto err_close;
>  	}
> -	handle->cur_swap = alloc_swapdev_block(root_swap);
> +	if (!allocate_swap(pages)) {
> +		printk(KERN_ERR "PM: Not enough free swap\n");
> +		ret = -ENOSPC;
> +		goto err_close;
> +	}
> +	handle->cur_swap = next_swapdev_block();
>  	if (!handle->cur_swap) {
>  		ret = -ENOSPC;
>  		goto err_rel;
> @@ -363,7 +395,7 @@ static int swap_write_page(struct swap_map_handle *handle, void *buf,
>  
>  	if (!handle->cur)
>  		return -EINVAL;
> -	offset = alloc_swapdev_block(root_swap);
> +	offset = next_swapdev_block();
>  	error = write_page(buf, offset, bio_chain);
>  	if (error)
>  		return error;
> @@ -372,7 +404,7 @@ static int swap_write_page(struct swap_map_handle *handle, void *buf,
>  		error = hib_wait_on_bio_chain(bio_chain);
>  		if (error)
>  			goto out;
> -		offset = alloc_swapdev_block(root_swap);
> +		offset = next_swapdev_block();
>  		if (!offset)
>  			return -ENOSPC;
>  		handle->cur->next_swap = offset;
> @@ -463,21 +495,6 @@ static int save_image(struct swap_map_handle *handle,
>  }
>  
>  /**
> - *	enough_swap - Make sure we have enough swap to save the image.
> - *
> - *	Returns TRUE or FALSE after checking the total amount of swap
> - *	space avaiable from the resume partition.
> - */
> -
> -static int enough_swap(unsigned int nr_pages)
> -{
> -	unsigned int free_swap = count_swap_pages(root_swap, 1);
> -
> -	pr_debug("PM: Free swap pages: %u\n", free_swap);
> -	return free_swap > nr_pages + PAGES_FOR_IO;
> -}
> -
> -/**
>   *	swsusp_write - Write entire image and metadata.
>   *	@flags: flags to pass to the "boot" kernel in the image header
>   *
> @@ -496,16 +513,11 @@ int swsusp_write(unsigned int flags)
>  	int error;
>  
>  	pages = snapshot_get_image_size();
> -	error = get_swap_writer(&handle);
> +	error = get_swap_writer(&handle, pages);
>  	if (error) {
>  		printk(KERN_ERR "PM: Cannot get swap writer\n");
>  		return error;
>  	}
> -	if (!enough_swap(pages)) {
> -		printk(KERN_ERR "PM: Not enough free swap\n");
> -		error = -ENOSPC;
> -		goto out_finish;
> -	}
>  	memset(&snapshot, 0, sizeof(struct snapshot_handle));
>  	error = snapshot_read_next(&snapshot);
>  	if (error < PAGE_SIZE) {
> 


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

* Re: [PATCH 05/22] Hibernation: Switch to preallocating swap.
  2010-09-25  4:16 ` [PATCH 05/22] Hibernation: Switch to preallocating swap Nigel Cunningham
  2010-09-25 21:24   ` Rafael J. Wysocki
  2010-09-25 21:24   ` Rafael J. Wysocki
@ 2010-09-25 21:24   ` Rafael J. Wysocki
  2 siblings, 0 replies; 80+ messages in thread
From: Rafael J. Wysocki @ 2010-09-25 21:24 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: Linux PM, LKML, TuxOnIce-devel

On Saturday, September 25, 2010, Nigel Cunningham wrote:
> Switch from allocating swap as the image is written to allocating
> storage prior to writing the image.

Hmm, I think I know what the patch does, but I don't really understand the
changelog.  Care to explain/fix?

Thanks,
Rafael


> Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
> ---
>  kernel/power/swap.c |   62 ++++++++++++++++++++++++++++++--------------------
>  1 files changed, 37 insertions(+), 25 deletions(-)
> 
> diff --git a/kernel/power/swap.c b/kernel/power/swap.c
> index cebf91c..bebd2cf 100644
> --- a/kernel/power/swap.c
> +++ b/kernel/power/swap.c
> @@ -202,6 +202,33 @@ int alloc_swapdev_blocks(int needed)
>  }
>  
>  /**
> + *	allocate_swap - Allocate enough swap to save the image.
> + *
> + *	Calculates the number of swap pages actually needed and seeks
> + *	to allocate that many from the resume partition. Returns TRUE
> + *	or FALSE to indicate whether we got enough storage.
> + */
> +
> +static int allocate_swap(unsigned int nr_pages)
> +{
> +	unsigned int free_swap = count_swap_pages(root_swap, 1);
> +
> +	nr_pages += DIV_ROUND_UP(nr_pages, MAP_PAGE_ENTRIES);
> +
> +	pr_debug("PM: Free swap pages: %u\n", free_swap);
> +	if (free_swap < nr_pages)
> +		return 0;
> +
> +	if (alloc_swapdev_blocks(nr_pages) < nr_pages) {
> +		free_all_swap_pages(root_swap);
> +		return 0;
> +	}
> +
> +	reset_storage_pos();
> +	return 1;
> +}
> +
> +/**
>   *	free_all_swap_pages - free swap pages allocated for saving image data.
>   *	It also frees the extents used to register which swap entries had been
>   *	allocated.
> @@ -324,7 +351,7 @@ static void release_swap_writer(struct swap_map_handle *handle)
>  	handle->cur = NULL;
>  }
>  
> -static int get_swap_writer(struct swap_map_handle *handle)
> +static int get_swap_writer(struct swap_map_handle *handle, unsigned long pages)
>  {
>  	int ret;
>  
> @@ -340,7 +367,12 @@ static int get_swap_writer(struct swap_map_handle *handle)
>  		ret = -ENOMEM;
>  		goto err_close;
>  	}
> -	handle->cur_swap = alloc_swapdev_block(root_swap);
> +	if (!allocate_swap(pages)) {
> +		printk(KERN_ERR "PM: Not enough free swap\n");
> +		ret = -ENOSPC;
> +		goto err_close;
> +	}
> +	handle->cur_swap = next_swapdev_block();
>  	if (!handle->cur_swap) {
>  		ret = -ENOSPC;
>  		goto err_rel;
> @@ -363,7 +395,7 @@ static int swap_write_page(struct swap_map_handle *handle, void *buf,
>  
>  	if (!handle->cur)
>  		return -EINVAL;
> -	offset = alloc_swapdev_block(root_swap);
> +	offset = next_swapdev_block();
>  	error = write_page(buf, offset, bio_chain);
>  	if (error)
>  		return error;
> @@ -372,7 +404,7 @@ static int swap_write_page(struct swap_map_handle *handle, void *buf,
>  		error = hib_wait_on_bio_chain(bio_chain);
>  		if (error)
>  			goto out;
> -		offset = alloc_swapdev_block(root_swap);
> +		offset = next_swapdev_block();
>  		if (!offset)
>  			return -ENOSPC;
>  		handle->cur->next_swap = offset;
> @@ -463,21 +495,6 @@ static int save_image(struct swap_map_handle *handle,
>  }
>  
>  /**
> - *	enough_swap - Make sure we have enough swap to save the image.
> - *
> - *	Returns TRUE or FALSE after checking the total amount of swap
> - *	space avaiable from the resume partition.
> - */
> -
> -static int enough_swap(unsigned int nr_pages)
> -{
> -	unsigned int free_swap = count_swap_pages(root_swap, 1);
> -
> -	pr_debug("PM: Free swap pages: %u\n", free_swap);
> -	return free_swap > nr_pages + PAGES_FOR_IO;
> -}
> -
> -/**
>   *	swsusp_write - Write entire image and metadata.
>   *	@flags: flags to pass to the "boot" kernel in the image header
>   *
> @@ -496,16 +513,11 @@ int swsusp_write(unsigned int flags)
>  	int error;
>  
>  	pages = snapshot_get_image_size();
> -	error = get_swap_writer(&handle);
> +	error = get_swap_writer(&handle, pages);
>  	if (error) {
>  		printk(KERN_ERR "PM: Cannot get swap writer\n");
>  		return error;
>  	}
> -	if (!enough_swap(pages)) {
> -		printk(KERN_ERR "PM: Not enough free swap\n");
> -		error = -ENOSPC;
> -		goto out_finish;
> -	}
>  	memset(&snapshot, 0, sizeof(struct snapshot_handle));
>  	error = snapshot_read_next(&snapshot);
>  	if (error < PAGE_SIZE) {
> 

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

* Re: [PATCH 05/22] Hibernation: Switch to preallocating swap.
  2010-09-25  4:16 ` [PATCH 05/22] Hibernation: Switch to preallocating swap Nigel Cunningham
  2010-09-25 21:24   ` Rafael J. Wysocki
@ 2010-09-25 21:24   ` Rafael J. Wysocki
  2010-09-25 21:24   ` Rafael J. Wysocki
  2 siblings, 0 replies; 80+ messages in thread
From: Rafael J. Wysocki @ 2010-09-25 21:24 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: Linux PM, LKML, TuxOnIce-devel

On Saturday, September 25, 2010, Nigel Cunningham wrote:
> Switch from allocating swap as the image is written to allocating
> storage prior to writing the image.

Hmm, I think I know what the patch does, but I don't really understand the
changelog.  Care to explain/fix?

Thanks,
Rafael


> Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
> ---
>  kernel/power/swap.c |   62 ++++++++++++++++++++++++++++++--------------------
>  1 files changed, 37 insertions(+), 25 deletions(-)
> 
> diff --git a/kernel/power/swap.c b/kernel/power/swap.c
> index cebf91c..bebd2cf 100644
> --- a/kernel/power/swap.c
> +++ b/kernel/power/swap.c
> @@ -202,6 +202,33 @@ int alloc_swapdev_blocks(int needed)
>  }
>  
>  /**
> + *	allocate_swap - Allocate enough swap to save the image.
> + *
> + *	Calculates the number of swap pages actually needed and seeks
> + *	to allocate that many from the resume partition. Returns TRUE
> + *	or FALSE to indicate whether we got enough storage.
> + */
> +
> +static int allocate_swap(unsigned int nr_pages)
> +{
> +	unsigned int free_swap = count_swap_pages(root_swap, 1);
> +
> +	nr_pages += DIV_ROUND_UP(nr_pages, MAP_PAGE_ENTRIES);
> +
> +	pr_debug("PM: Free swap pages: %u\n", free_swap);
> +	if (free_swap < nr_pages)
> +		return 0;
> +
> +	if (alloc_swapdev_blocks(nr_pages) < nr_pages) {
> +		free_all_swap_pages(root_swap);
> +		return 0;
> +	}
> +
> +	reset_storage_pos();
> +	return 1;
> +}
> +
> +/**
>   *	free_all_swap_pages - free swap pages allocated for saving image data.
>   *	It also frees the extents used to register which swap entries had been
>   *	allocated.
> @@ -324,7 +351,7 @@ static void release_swap_writer(struct swap_map_handle *handle)
>  	handle->cur = NULL;
>  }
>  
> -static int get_swap_writer(struct swap_map_handle *handle)
> +static int get_swap_writer(struct swap_map_handle *handle, unsigned long pages)
>  {
>  	int ret;
>  
> @@ -340,7 +367,12 @@ static int get_swap_writer(struct swap_map_handle *handle)
>  		ret = -ENOMEM;
>  		goto err_close;
>  	}
> -	handle->cur_swap = alloc_swapdev_block(root_swap);
> +	if (!allocate_swap(pages)) {
> +		printk(KERN_ERR "PM: Not enough free swap\n");
> +		ret = -ENOSPC;
> +		goto err_close;
> +	}
> +	handle->cur_swap = next_swapdev_block();
>  	if (!handle->cur_swap) {
>  		ret = -ENOSPC;
>  		goto err_rel;
> @@ -363,7 +395,7 @@ static int swap_write_page(struct swap_map_handle *handle, void *buf,
>  
>  	if (!handle->cur)
>  		return -EINVAL;
> -	offset = alloc_swapdev_block(root_swap);
> +	offset = next_swapdev_block();
>  	error = write_page(buf, offset, bio_chain);
>  	if (error)
>  		return error;
> @@ -372,7 +404,7 @@ static int swap_write_page(struct swap_map_handle *handle, void *buf,
>  		error = hib_wait_on_bio_chain(bio_chain);
>  		if (error)
>  			goto out;
> -		offset = alloc_swapdev_block(root_swap);
> +		offset = next_swapdev_block();
>  		if (!offset)
>  			return -ENOSPC;
>  		handle->cur->next_swap = offset;
> @@ -463,21 +495,6 @@ static int save_image(struct swap_map_handle *handle,
>  }
>  
>  /**
> - *	enough_swap - Make sure we have enough swap to save the image.
> - *
> - *	Returns TRUE or FALSE after checking the total amount of swap
> - *	space avaiable from the resume partition.
> - */
> -
> -static int enough_swap(unsigned int nr_pages)
> -{
> -	unsigned int free_swap = count_swap_pages(root_swap, 1);
> -
> -	pr_debug("PM: Free swap pages: %u\n", free_swap);
> -	return free_swap > nr_pages + PAGES_FOR_IO;
> -}
> -
> -/**
>   *	swsusp_write - Write entire image and metadata.
>   *	@flags: flags to pass to the "boot" kernel in the image header
>   *
> @@ -496,16 +513,11 @@ int swsusp_write(unsigned int flags)
>  	int error;
>  
>  	pages = snapshot_get_image_size();
> -	error = get_swap_writer(&handle);
> +	error = get_swap_writer(&handle, pages);
>  	if (error) {
>  		printk(KERN_ERR "PM: Cannot get swap writer\n");
>  		return error;
>  	}
> -	if (!enough_swap(pages)) {
> -		printk(KERN_ERR "PM: Not enough free swap\n");
> -		error = -ENOSPC;
> -		goto out_finish;
> -	}
>  	memset(&snapshot, 0, sizeof(struct snapshot_handle));
>  	error = snapshot_read_next(&snapshot);
>  	if (error < PAGE_SIZE) {
> 


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

* Re: [PATCH 05/22] Hibernation: Switch to preallocating swap.
  2010-09-25 21:24   ` Rafael J. Wysocki
  2010-09-25 21:32     ` Nigel Cunningham
@ 2010-09-25 21:32     ` Nigel Cunningham
  2010-09-25 22:22       ` Rafael J. Wysocki
  2010-09-25 22:22       ` Rafael J. Wysocki
  1 sibling, 2 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25 21:32 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: Linux PM, LKML, TuxOnIce-devel

Morning.

On 26/09/10 07:24, Rafael J. Wysocki wrote:
> On Saturday, September 25, 2010, Nigel Cunningham wrote:
>> Switch from allocating swap as the image is written to allocating
>> storage prior to writing the image.
>
> Hmm, I think I know what the patch does, but I don't really understand the
> changelog.  Care to explain/fix?

Sure. I was a little terse, wasn't I? :)

Prior to this patch, we allocated swap as we were writing the image. 
This patch changes things so that we instead allocate all the swap we'll 
need prior to starting to write the image. It lays groundwork for later 
patches that switch from doing I/O in batches.

Regards,

Nigel

> Thanks,
> Rafael
>
>
>> Signed-off-by: Nigel Cunningham<nigel@tuxonice.net>
>> ---
>>   kernel/power/swap.c |   62 ++++++++++++++++++++++++++++++--------------------
>>   1 files changed, 37 insertions(+), 25 deletions(-)
>>
>> diff --git a/kernel/power/swap.c b/kernel/power/swap.c
>> index cebf91c..bebd2cf 100644
>> --- a/kernel/power/swap.c
>> +++ b/kernel/power/swap.c
>> @@ -202,6 +202,33 @@ int alloc_swapdev_blocks(int needed)
>>   }
>>
>>   /**
>> + *	allocate_swap - Allocate enough swap to save the image.
>> + *
>> + *	Calculates the number of swap pages actually needed and seeks
>> + *	to allocate that many from the resume partition. Returns TRUE
>> + *	or FALSE to indicate whether we got enough storage.
>> + */
>> +
>> +static int allocate_swap(unsigned int nr_pages)
>> +{
>> +	unsigned int free_swap = count_swap_pages(root_swap, 1);
>> +
>> +	nr_pages += DIV_ROUND_UP(nr_pages, MAP_PAGE_ENTRIES);
>> +
>> +	pr_debug("PM: Free swap pages: %u\n", free_swap);
>> +	if (free_swap<  nr_pages)
>> +		return 0;
>> +
>> +	if (alloc_swapdev_blocks(nr_pages)<  nr_pages) {
>> +		free_all_swap_pages(root_swap);
>> +		return 0;
>> +	}
>> +
>> +	reset_storage_pos();
>> +	return 1;
>> +}
>> +
>> +/**
>>    *	free_all_swap_pages - free swap pages allocated for saving image data.
>>    *	It also frees the extents used to register which swap entries had been
>>    *	allocated.
>> @@ -324,7 +351,7 @@ static void release_swap_writer(struct swap_map_handle *handle)
>>   	handle->cur = NULL;
>>   }
>>
>> -static int get_swap_writer(struct swap_map_handle *handle)
>> +static int get_swap_writer(struct swap_map_handle *handle, unsigned long pages)
>>   {
>>   	int ret;
>>
>> @@ -340,7 +367,12 @@ static int get_swap_writer(struct swap_map_handle *handle)
>>   		ret = -ENOMEM;
>>   		goto err_close;
>>   	}
>> -	handle->cur_swap = alloc_swapdev_block(root_swap);
>> +	if (!allocate_swap(pages)) {
>> +		printk(KERN_ERR "PM: Not enough free swap\n");
>> +		ret = -ENOSPC;
>> +		goto err_close;
>> +	}
>> +	handle->cur_swap = next_swapdev_block();
>>   	if (!handle->cur_swap) {
>>   		ret = -ENOSPC;
>>   		goto err_rel;
>> @@ -363,7 +395,7 @@ static int swap_write_page(struct swap_map_handle *handle, void *buf,
>>
>>   	if (!handle->cur)
>>   		return -EINVAL;
>> -	offset = alloc_swapdev_block(root_swap);
>> +	offset = next_swapdev_block();
>>   	error = write_page(buf, offset, bio_chain);
>>   	if (error)
>>   		return error;
>> @@ -372,7 +404,7 @@ static int swap_write_page(struct swap_map_handle *handle, void *buf,
>>   		error = hib_wait_on_bio_chain(bio_chain);
>>   		if (error)
>>   			goto out;
>> -		offset = alloc_swapdev_block(root_swap);
>> +		offset = next_swapdev_block();
>>   		if (!offset)
>>   			return -ENOSPC;
>>   		handle->cur->next_swap = offset;
>> @@ -463,21 +495,6 @@ static int save_image(struct swap_map_handle *handle,
>>   }
>>
>>   /**
>> - *	enough_swap - Make sure we have enough swap to save the image.
>> - *
>> - *	Returns TRUE or FALSE after checking the total amount of swap
>> - *	space avaiable from the resume partition.
>> - */
>> -
>> -static int enough_swap(unsigned int nr_pages)
>> -{
>> -	unsigned int free_swap = count_swap_pages(root_swap, 1);
>> -
>> -	pr_debug("PM: Free swap pages: %u\n", free_swap);
>> -	return free_swap>  nr_pages + PAGES_FOR_IO;
>> -}
>> -
>> -/**
>>    *	swsusp_write - Write entire image and metadata.
>>    *	@flags: flags to pass to the "boot" kernel in the image header
>>    *
>> @@ -496,16 +513,11 @@ int swsusp_write(unsigned int flags)
>>   	int error;
>>
>>   	pages = snapshot_get_image_size();
>> -	error = get_swap_writer(&handle);
>> +	error = get_swap_writer(&handle, pages);
>>   	if (error) {
>>   		printk(KERN_ERR "PM: Cannot get swap writer\n");
>>   		return error;
>>   	}
>> -	if (!enough_swap(pages)) {
>> -		printk(KERN_ERR "PM: Not enough free swap\n");
>> -		error = -ENOSPC;
>> -		goto out_finish;
>> -	}
>>   	memset(&snapshot, 0, sizeof(struct snapshot_handle));
>>   	error = snapshot_read_next(&snapshot);
>>   	if (error<  PAGE_SIZE) {
>>
>
>


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

* Re: [PATCH 05/22] Hibernation: Switch to preallocating swap.
  2010-09-25 21:24   ` Rafael J. Wysocki
@ 2010-09-25 21:32     ` Nigel Cunningham
  2010-09-25 21:32     ` Nigel Cunningham
  1 sibling, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25 21:32 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: Linux PM, LKML, TuxOnIce-devel

Morning.

On 26/09/10 07:24, Rafael J. Wysocki wrote:
> On Saturday, September 25, 2010, Nigel Cunningham wrote:
>> Switch from allocating swap as the image is written to allocating
>> storage prior to writing the image.
>
> Hmm, I think I know what the patch does, but I don't really understand the
> changelog.  Care to explain/fix?

Sure. I was a little terse, wasn't I? :)

Prior to this patch, we allocated swap as we were writing the image. 
This patch changes things so that we instead allocate all the swap we'll 
need prior to starting to write the image. It lays groundwork for later 
patches that switch from doing I/O in batches.

Regards,

Nigel

> Thanks,
> Rafael
>
>
>> Signed-off-by: Nigel Cunningham<nigel@tuxonice.net>
>> ---
>>   kernel/power/swap.c |   62 ++++++++++++++++++++++++++++++--------------------
>>   1 files changed, 37 insertions(+), 25 deletions(-)
>>
>> diff --git a/kernel/power/swap.c b/kernel/power/swap.c
>> index cebf91c..bebd2cf 100644
>> --- a/kernel/power/swap.c
>> +++ b/kernel/power/swap.c
>> @@ -202,6 +202,33 @@ int alloc_swapdev_blocks(int needed)
>>   }
>>
>>   /**
>> + *	allocate_swap - Allocate enough swap to save the image.
>> + *
>> + *	Calculates the number of swap pages actually needed and seeks
>> + *	to allocate that many from the resume partition. Returns TRUE
>> + *	or FALSE to indicate whether we got enough storage.
>> + */
>> +
>> +static int allocate_swap(unsigned int nr_pages)
>> +{
>> +	unsigned int free_swap = count_swap_pages(root_swap, 1);
>> +
>> +	nr_pages += DIV_ROUND_UP(nr_pages, MAP_PAGE_ENTRIES);
>> +
>> +	pr_debug("PM: Free swap pages: %u\n", free_swap);
>> +	if (free_swap<  nr_pages)
>> +		return 0;
>> +
>> +	if (alloc_swapdev_blocks(nr_pages)<  nr_pages) {
>> +		free_all_swap_pages(root_swap);
>> +		return 0;
>> +	}
>> +
>> +	reset_storage_pos();
>> +	return 1;
>> +}
>> +
>> +/**
>>    *	free_all_swap_pages - free swap pages allocated for saving image data.
>>    *	It also frees the extents used to register which swap entries had been
>>    *	allocated.
>> @@ -324,7 +351,7 @@ static void release_swap_writer(struct swap_map_handle *handle)
>>   	handle->cur = NULL;
>>   }
>>
>> -static int get_swap_writer(struct swap_map_handle *handle)
>> +static int get_swap_writer(struct swap_map_handle *handle, unsigned long pages)
>>   {
>>   	int ret;
>>
>> @@ -340,7 +367,12 @@ static int get_swap_writer(struct swap_map_handle *handle)
>>   		ret = -ENOMEM;
>>   		goto err_close;
>>   	}
>> -	handle->cur_swap = alloc_swapdev_block(root_swap);
>> +	if (!allocate_swap(pages)) {
>> +		printk(KERN_ERR "PM: Not enough free swap\n");
>> +		ret = -ENOSPC;
>> +		goto err_close;
>> +	}
>> +	handle->cur_swap = next_swapdev_block();
>>   	if (!handle->cur_swap) {
>>   		ret = -ENOSPC;
>>   		goto err_rel;
>> @@ -363,7 +395,7 @@ static int swap_write_page(struct swap_map_handle *handle, void *buf,
>>
>>   	if (!handle->cur)
>>   		return -EINVAL;
>> -	offset = alloc_swapdev_block(root_swap);
>> +	offset = next_swapdev_block();
>>   	error = write_page(buf, offset, bio_chain);
>>   	if (error)
>>   		return error;
>> @@ -372,7 +404,7 @@ static int swap_write_page(struct swap_map_handle *handle, void *buf,
>>   		error = hib_wait_on_bio_chain(bio_chain);
>>   		if (error)
>>   			goto out;
>> -		offset = alloc_swapdev_block(root_swap);
>> +		offset = next_swapdev_block();
>>   		if (!offset)
>>   			return -ENOSPC;
>>   		handle->cur->next_swap = offset;
>> @@ -463,21 +495,6 @@ static int save_image(struct swap_map_handle *handle,
>>   }
>>
>>   /**
>> - *	enough_swap - Make sure we have enough swap to save the image.
>> - *
>> - *	Returns TRUE or FALSE after checking the total amount of swap
>> - *	space avaiable from the resume partition.
>> - */
>> -
>> -static int enough_swap(unsigned int nr_pages)
>> -{
>> -	unsigned int free_swap = count_swap_pages(root_swap, 1);
>> -
>> -	pr_debug("PM: Free swap pages: %u\n", free_swap);
>> -	return free_swap>  nr_pages + PAGES_FOR_IO;
>> -}
>> -
>> -/**
>>    *	swsusp_write - Write entire image and metadata.
>>    *	@flags: flags to pass to the "boot" kernel in the image header
>>    *
>> @@ -496,16 +513,11 @@ int swsusp_write(unsigned int flags)
>>   	int error;
>>
>>   	pages = snapshot_get_image_size();
>> -	error = get_swap_writer(&handle);
>> +	error = get_swap_writer(&handle, pages);
>>   	if (error) {
>>   		printk(KERN_ERR "PM: Cannot get swap writer\n");
>>   		return error;
>>   	}
>> -	if (!enough_swap(pages)) {
>> -		printk(KERN_ERR "PM: Not enough free swap\n");
>> -		error = -ENOSPC;
>> -		goto out_finish;
>> -	}
>>   	memset(&snapshot, 0, sizeof(struct snapshot_handle));
>>   	error = snapshot_read_next(&snapshot);
>>   	if (error<  PAGE_SIZE) {
>>
>
>

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

* Re: [PATCH 13/22] Hibernation: Extent save/load routines.
  2010-09-25  4:16 ` [PATCH 13/22] Hibernation: Extent save/load routines Nigel Cunningham
@ 2010-09-25 22:12   ` Rafael J. Wysocki
  2010-09-25 22:12   ` Rafael J. Wysocki
  1 sibling, 0 replies; 80+ messages in thread
From: Rafael J. Wysocki @ 2010-09-25 22:12 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: Linux PM, LKML, TuxOnIce-devel

On Saturday, September 25, 2010, Nigel Cunningham wrote:
> Add routines for saving and reloading a chain of extents. This will
> be used to store the block extents in the image header, rather than
> in swap map pages.
> 
> Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>

Well, I guess it would be better to move these functions to the patch where
they are used for the first time.

Thanks,
Rafael


> ---
>  kernel/power/extents.c |   75 ++++++++++++++++++++++++++++++++++++++++++++++++
>  kernel/power/extents.h |    5 +++
>  2 files changed, 80 insertions(+), 0 deletions(-)
> 
> diff --git a/kernel/power/extents.c b/kernel/power/extents.c
> index 172322d..75d2fb4 100644
> --- a/kernel/power/extents.c
> +++ b/kernel/power/extents.c
> @@ -14,6 +14,7 @@
>  
>  #include <linux/slab.h>
>  #include "extents.h"
> +#include "block_io.h"
>  
>  int hib_extents_empty(struct hib_extent_state *pos)
>  {
> @@ -123,3 +124,77 @@ void hib_extents_clear(struct hib_extent_state *pos)
>  		kfree(ext);
>  	}
>  }
> +
> +int hib_extents_storage_needed(struct hib_extent_state *pos)
> +{
> +	return sizeof(int) + pos->num_extents * 2 * sizeof(unsigned long);
> +}
> +
> +int hib_extents_store(struct hib_extent_state *pos)
> +{
> +	struct rb_node *node;
> +	struct hib_extent *ext;
> +	int ret = hib_write_buffer((char *) &pos->num_extents, sizeof(int));
> +
> +	if (hib_extents_empty(pos))
> +		return 0;
> +
> +	node = rb_first(&pos->root);
> +	while (node) {
> +		ext = container_of(node, struct hib_extent, node);
> +		ret = hib_write_buffer((char *) &ext->start,
> +				2 * sizeof(unsigned long));
> +		if (ret)
> +			return ret;
> +		node = rb_next(node);
> +	}
> +
> +	return 0;
> +}
> +
> +int hib_extents_load(struct hib_extent_state *pos, int bootstrap)
> +{
> +	struct rb_node **new = &(pos->root.rb_node);
> +	struct rb_node *parent = NULL;
> +	struct hib_extent *existing, *adding;
> +	int i;
> +	int ret = hib_read_buffer((char *) &pos->num_extents, sizeof(int));
> +
> +	if (!pos->num_extents)
> +		return 0;
> +
> +	for (i = 0; i < pos->num_extents; i++) {
> +		adding = kzalloc(sizeof(struct hib_extent), GFP_KERNEL);
> +		if (!adding)
> +			return -ENOMEM;
> +
> +		ret = hib_read_buffer((char *) &adding->start,
> +				2 * sizeof(unsigned long));
> +		if (ret)
> +			return ret;
> +
> +		/*
> +		 * No need for some of the checks from inserting above -
> +		 * they were done when preparing the image.
> +		 */
> +		while (*new) {
> +			existing = container_of(*new, struct hib_extent, node);
> +			parent = *new;
> +			if (adding->end < existing->start)
> +				new = &((*new)->rb_left);
> +			else
> +				new = &((*new)->rb_right);
> +		}
> +		rb_link_node(&adding->node, parent, new);
> +		rb_insert_color(&adding->node, &pos->root);
> +
> +		if (bootstrap && !i) {
> +			hib_reset_extent_pos(&sector_extents);
> +
> +			/* We have already read the first page */
> +			hib_extent_next(&sector_extents);
> +		}
> +	}
> +
> +	return 0;
> +}
> diff --git a/kernel/power/extents.h b/kernel/power/extents.h
> index 0b69b8e..4288f9e 100644
> --- a/kernel/power/extents.h
> +++ b/kernel/power/extents.h
> @@ -33,3 +33,8 @@ unsigned long hib_extent_next(struct hib_extent_state *pos);
>  int hib_extents_insert(struct hib_extent_state *pos, unsigned long value);
>  void hib_extents_clear(struct hib_extent_state *pos);
>  int hib_extents_empty(struct hib_extent_state *pos);
> +
> +/* Serialisation support */
> +int hib_extents_storage_needed(struct hib_extent_state *pos);
> +int hib_extents_store(struct hib_extent_state *pos);
> +int hib_extents_load(struct hib_extent_state *pos, int bootstrap);
> 


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

* Re: [PATCH 13/22] Hibernation: Extent save/load routines.
  2010-09-25  4:16 ` [PATCH 13/22] Hibernation: Extent save/load routines Nigel Cunningham
  2010-09-25 22:12   ` Rafael J. Wysocki
@ 2010-09-25 22:12   ` Rafael J. Wysocki
  1 sibling, 0 replies; 80+ messages in thread
From: Rafael J. Wysocki @ 2010-09-25 22:12 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: Linux PM, LKML, TuxOnIce-devel

On Saturday, September 25, 2010, Nigel Cunningham wrote:
> Add routines for saving and reloading a chain of extents. This will
> be used to store the block extents in the image header, rather than
> in swap map pages.
> 
> Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>

Well, I guess it would be better to move these functions to the patch where
they are used for the first time.

Thanks,
Rafael


> ---
>  kernel/power/extents.c |   75 ++++++++++++++++++++++++++++++++++++++++++++++++
>  kernel/power/extents.h |    5 +++
>  2 files changed, 80 insertions(+), 0 deletions(-)
> 
> diff --git a/kernel/power/extents.c b/kernel/power/extents.c
> index 172322d..75d2fb4 100644
> --- a/kernel/power/extents.c
> +++ b/kernel/power/extents.c
> @@ -14,6 +14,7 @@
>  
>  #include <linux/slab.h>
>  #include "extents.h"
> +#include "block_io.h"
>  
>  int hib_extents_empty(struct hib_extent_state *pos)
>  {
> @@ -123,3 +124,77 @@ void hib_extents_clear(struct hib_extent_state *pos)
>  		kfree(ext);
>  	}
>  }
> +
> +int hib_extents_storage_needed(struct hib_extent_state *pos)
> +{
> +	return sizeof(int) + pos->num_extents * 2 * sizeof(unsigned long);
> +}
> +
> +int hib_extents_store(struct hib_extent_state *pos)
> +{
> +	struct rb_node *node;
> +	struct hib_extent *ext;
> +	int ret = hib_write_buffer((char *) &pos->num_extents, sizeof(int));
> +
> +	if (hib_extents_empty(pos))
> +		return 0;
> +
> +	node = rb_first(&pos->root);
> +	while (node) {
> +		ext = container_of(node, struct hib_extent, node);
> +		ret = hib_write_buffer((char *) &ext->start,
> +				2 * sizeof(unsigned long));
> +		if (ret)
> +			return ret;
> +		node = rb_next(node);
> +	}
> +
> +	return 0;
> +}
> +
> +int hib_extents_load(struct hib_extent_state *pos, int bootstrap)
> +{
> +	struct rb_node **new = &(pos->root.rb_node);
> +	struct rb_node *parent = NULL;
> +	struct hib_extent *existing, *adding;
> +	int i;
> +	int ret = hib_read_buffer((char *) &pos->num_extents, sizeof(int));
> +
> +	if (!pos->num_extents)
> +		return 0;
> +
> +	for (i = 0; i < pos->num_extents; i++) {
> +		adding = kzalloc(sizeof(struct hib_extent), GFP_KERNEL);
> +		if (!adding)
> +			return -ENOMEM;
> +
> +		ret = hib_read_buffer((char *) &adding->start,
> +				2 * sizeof(unsigned long));
> +		if (ret)
> +			return ret;
> +
> +		/*
> +		 * No need for some of the checks from inserting above -
> +		 * they were done when preparing the image.
> +		 */
> +		while (*new) {
> +			existing = container_of(*new, struct hib_extent, node);
> +			parent = *new;
> +			if (adding->end < existing->start)
> +				new = &((*new)->rb_left);
> +			else
> +				new = &((*new)->rb_right);
> +		}
> +		rb_link_node(&adding->node, parent, new);
> +		rb_insert_color(&adding->node, &pos->root);
> +
> +		if (bootstrap && !i) {
> +			hib_reset_extent_pos(&sector_extents);
> +
> +			/* We have already read the first page */
> +			hib_extent_next(&sector_extents);
> +		}
> +	}
> +
> +	return 0;
> +}
> diff --git a/kernel/power/extents.h b/kernel/power/extents.h
> index 0b69b8e..4288f9e 100644
> --- a/kernel/power/extents.h
> +++ b/kernel/power/extents.h
> @@ -33,3 +33,8 @@ unsigned long hib_extent_next(struct hib_extent_state *pos);
>  int hib_extents_insert(struct hib_extent_state *pos, unsigned long value);
>  void hib_extents_clear(struct hib_extent_state *pos);
>  int hib_extents_empty(struct hib_extent_state *pos);
> +
> +/* Serialisation support */
> +int hib_extents_storage_needed(struct hib_extent_state *pos);
> +int hib_extents_store(struct hib_extent_state *pos);
> +int hib_extents_load(struct hib_extent_state *pos, int bootstrap);
> 

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

* Re: Nigel's current for-rafael queue
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (50 preceding siblings ...)
  2010-09-25 22:19 ` Rafael J. Wysocki
@ 2010-09-25 22:19 ` Rafael J. Wysocki
  2010-09-25 22:33   ` Nigel Cunningham
  2010-09-25 22:33   ` Nigel Cunningham
  2010-09-28 10:34 ` [TuxOnIce-devel] " Martin Steigerwald
                   ` (3 subsequent siblings)
  55 siblings, 2 replies; 80+ messages in thread
From: Rafael J. Wysocki @ 2010-09-25 22:19 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: Linux PM, LKML, TuxOnIce-devel

On Saturday, September 25, 2010, Nigel Cunningham wrote:
> Hi Rafael.

Hi Nigel,

> Please find attached a slightly updated version of the patchset I sent
> a few months ago. The main change is that I've prepended and additional
> patch which lets the user see the speed at which the image is being
> read and written. This is accomplished by recording the MB/s in a single
> byte in the image header, and using a couple of __nosavedata variables
> to get the data back through the atomic restore. I realise the char limits
> us to 255MB/s at the moment. In future patches, I intend to address this
> by storing the data in a 'proper' image header (it's a real problem -
> TuxOnIce reads and writes on the same set up at speeds around 250MB/s).
> 
> Results on my Dell XPS M1530, which has an SSD hard drive are:
> 
> With just patch 1 applied:
> Attempt 1: Write 74MB/s; Read 52MB/s
> Attempt 2: Write 68MB/s; Read 52MB/s
> Attempt 3: Write 73MB/s; Read 53MB/s
> 
> With the whole sequence:
> Attempt 1: Write 181MB/s; Read 52MB/s
> Attempt 2: Write 156MB/s; Read 53MB/s
> Attempt 3: Write 160MB/s; Read 52MB/s

Thanks for the patches, they look like a real improvement to me.

I only had a couple of minor comments, sent separately in replies to individual
patches.  I'd like to push this series for 2.6.37, if the comments are
addressed timely.

Best regards,
Rafael

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

* Re: Nigel's current for-rafael queue
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (49 preceding siblings ...)
  2010-09-25 15:04 ` Martin Steigerwald
@ 2010-09-25 22:19 ` Rafael J. Wysocki
  2010-09-25 22:19 ` Rafael J. Wysocki
                   ` (4 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Rafael J. Wysocki @ 2010-09-25 22:19 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: Linux PM, LKML, TuxOnIce-devel

On Saturday, September 25, 2010, Nigel Cunningham wrote:
> Hi Rafael.

Hi Nigel,

> Please find attached a slightly updated version of the patchset I sent
> a few months ago. The main change is that I've prepended and additional
> patch which lets the user see the speed at which the image is being
> read and written. This is accomplished by recording the MB/s in a single
> byte in the image header, and using a couple of __nosavedata variables
> to get the data back through the atomic restore. I realise the char limits
> us to 255MB/s at the moment. In future patches, I intend to address this
> by storing the data in a 'proper' image header (it's a real problem -
> TuxOnIce reads and writes on the same set up at speeds around 250MB/s).
> 
> Results on my Dell XPS M1530, which has an SSD hard drive are:
> 
> With just patch 1 applied:
> Attempt 1: Write 74MB/s; Read 52MB/s
> Attempt 2: Write 68MB/s; Read 52MB/s
> Attempt 3: Write 73MB/s; Read 53MB/s
> 
> With the whole sequence:
> Attempt 1: Write 181MB/s; Read 52MB/s
> Attempt 2: Write 156MB/s; Read 53MB/s
> Attempt 3: Write 160MB/s; Read 52MB/s

Thanks for the patches, they look like a real improvement to me.

I only had a couple of minor comments, sent separately in replies to individual
patches.  I'd like to push this series for 2.6.37, if the comments are
addressed timely.

Best regards,
Rafael

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

* Re: [PATCH 05/22] Hibernation: Switch to preallocating swap.
  2010-09-25 21:32     ` Nigel Cunningham
@ 2010-09-25 22:22       ` Rafael J. Wysocki
  2010-09-25 22:22       ` Rafael J. Wysocki
  1 sibling, 0 replies; 80+ messages in thread
From: Rafael J. Wysocki @ 2010-09-25 22:22 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: Linux PM, LKML, TuxOnIce-devel

On Saturday, September 25, 2010, Nigel Cunningham wrote:
> Morning.
> 
> On 26/09/10 07:24, Rafael J. Wysocki wrote:
> > On Saturday, September 25, 2010, Nigel Cunningham wrote:
> >> Switch from allocating swap as the image is written to allocating
> >> storage prior to writing the image.
> >
> > Hmm, I think I know what the patch does, but I don't really understand the
> > changelog.  Care to explain/fix?
> 
> Sure. I was a little terse, wasn't I? :)
> 
> Prior to this patch, we allocated swap as we were writing the image. 
> This patch changes things so that we instead allocate all the swap we'll 
> need prior to starting to write the image. It lays groundwork for later 
> patches that switch from doing I/O in batches.

Good.  I'll use the above as a replacement changelog if you don't mind.

Thanks,
Rafael

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

* Re: [PATCH 05/22] Hibernation: Switch to preallocating swap.
  2010-09-25 21:32     ` Nigel Cunningham
  2010-09-25 22:22       ` Rafael J. Wysocki
@ 2010-09-25 22:22       ` Rafael J. Wysocki
  1 sibling, 0 replies; 80+ messages in thread
From: Rafael J. Wysocki @ 2010-09-25 22:22 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: Linux PM, LKML, TuxOnIce-devel

On Saturday, September 25, 2010, Nigel Cunningham wrote:
> Morning.
> 
> On 26/09/10 07:24, Rafael J. Wysocki wrote:
> > On Saturday, September 25, 2010, Nigel Cunningham wrote:
> >> Switch from allocating swap as the image is written to allocating
> >> storage prior to writing the image.
> >
> > Hmm, I think I know what the patch does, but I don't really understand the
> > changelog.  Care to explain/fix?
> 
> Sure. I was a little terse, wasn't I? :)
> 
> Prior to this patch, we allocated swap as we were writing the image. 
> This patch changes things so that we instead allocate all the swap we'll 
> need prior to starting to write the image. It lays groundwork for later 
> patches that switch from doing I/O in batches.

Good.  I'll use the above as a replacement changelog if you don't mind.

Thanks,
Rafael

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

* Re: Nigel's current for-rafael queue
  2010-09-25 22:19 ` Rafael J. Wysocki
  2010-09-25 22:33   ` Nigel Cunningham
@ 2010-09-25 22:33   ` Nigel Cunningham
  2010-09-25 22:36     ` Rafael J. Wysocki
  2010-09-25 22:36     ` Rafael J. Wysocki
  1 sibling, 2 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25 22:33 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: Linux PM, LKML, TuxOnIce-devel

Hi.

On 26/09/10 08:19, Rafael J. Wysocki wrote:
> On Saturday, September 25, 2010, Nigel Cunningham wrote:
>> Hi Rafael.
>
> Hi Nigel,
>
>> Please find attached a slightly updated version of the patchset I sent
>> a few months ago. The main change is that I've prepended and additional
>> patch which lets the user see the speed at which the image is being
>> read and written. This is accomplished by recording the MB/s in a single
>> byte in the image header, and using a couple of __nosavedata variables
>> to get the data back through the atomic restore. I realise the char limits
>> us to 255MB/s at the moment. In future patches, I intend to address this
>> by storing the data in a 'proper' image header (it's a real problem -
>> TuxOnIce reads and writes on the same set up at speeds around 250MB/s).
>>
>> Results on my Dell XPS M1530, which has an SSD hard drive are:
>>
>> With just patch 1 applied:
>> Attempt 1: Write 74MB/s; Read 52MB/s
>> Attempt 2: Write 68MB/s; Read 52MB/s
>> Attempt 3: Write 73MB/s; Read 53MB/s
>>
>> With the whole sequence:
>> Attempt 1: Write 181MB/s; Read 52MB/s
>> Attempt 2: Write 156MB/s; Read 53MB/s
>> Attempt 3: Write 160MB/s; Read 52MB/s
>
> Thanks for the patches, they look like a real improvement to me.
>
> I only had a couple of minor comments, sent separately in replies to individual
> patches.  I'd like to push this series for 2.6.37, if the comments are
> addressed timely.

Okay. I'll update the patches. You can pull from

git://git.kernel.org/pub/scm/linux/kernel/git/nigelc/tuxonice-head.git#for-rafael

if you want.

I'll apply your suggestions/comments to the versions there. I'll also 
checkout what's going on with Martin's machine and hopefully apply 
whatever fix is needed there too. Will keep you up to date with any changes.

Regards,

Nigel

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

* Re: Nigel's current for-rafael queue
  2010-09-25 22:19 ` Rafael J. Wysocki
@ 2010-09-25 22:33   ` Nigel Cunningham
  2010-09-25 22:33   ` Nigel Cunningham
  1 sibling, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-25 22:33 UTC (permalink / raw)
  To: Rafael J. Wysocki; +Cc: Linux PM, LKML, TuxOnIce-devel

Hi.

On 26/09/10 08:19, Rafael J. Wysocki wrote:
> On Saturday, September 25, 2010, Nigel Cunningham wrote:
>> Hi Rafael.
>
> Hi Nigel,
>
>> Please find attached a slightly updated version of the patchset I sent
>> a few months ago. The main change is that I've prepended and additional
>> patch which lets the user see the speed at which the image is being
>> read and written. This is accomplished by recording the MB/s in a single
>> byte in the image header, and using a couple of __nosavedata variables
>> to get the data back through the atomic restore. I realise the char limits
>> us to 255MB/s at the moment. In future patches, I intend to address this
>> by storing the data in a 'proper' image header (it's a real problem -
>> TuxOnIce reads and writes on the same set up at speeds around 250MB/s).
>>
>> Results on my Dell XPS M1530, which has an SSD hard drive are:
>>
>> With just patch 1 applied:
>> Attempt 1: Write 74MB/s; Read 52MB/s
>> Attempt 2: Write 68MB/s; Read 52MB/s
>> Attempt 3: Write 73MB/s; Read 53MB/s
>>
>> With the whole sequence:
>> Attempt 1: Write 181MB/s; Read 52MB/s
>> Attempt 2: Write 156MB/s; Read 53MB/s
>> Attempt 3: Write 160MB/s; Read 52MB/s
>
> Thanks for the patches, they look like a real improvement to me.
>
> I only had a couple of minor comments, sent separately in replies to individual
> patches.  I'd like to push this series for 2.6.37, if the comments are
> addressed timely.

Okay. I'll update the patches. You can pull from

git://git.kernel.org/pub/scm/linux/kernel/git/nigelc/tuxonice-head.git#for-rafael

if you want.

I'll apply your suggestions/comments to the versions there. I'll also 
checkout what's going on with Martin's machine and hopefully apply 
whatever fix is needed there too. Will keep you up to date with any changes.

Regards,

Nigel

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

* Re: Nigel's current for-rafael queue
  2010-09-25 22:33   ` Nigel Cunningham
  2010-09-25 22:36     ` Rafael J. Wysocki
@ 2010-09-25 22:36     ` Rafael J. Wysocki
  1 sibling, 0 replies; 80+ messages in thread
From: Rafael J. Wysocki @ 2010-09-25 22:36 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: Linux PM, LKML, TuxOnIce-devel

On Sunday, September 26, 2010, Nigel Cunningham wrote:
> Hi.
> 
> On 26/09/10 08:19, Rafael J. Wysocki wrote:
> > On Saturday, September 25, 2010, Nigel Cunningham wrote:
> >> Hi Rafael.
> >
> > Hi Nigel,
> >
> >> Please find attached a slightly updated version of the patchset I sent
> >> a few months ago. The main change is that I've prepended and additional
> >> patch which lets the user see the speed at which the image is being
> >> read and written. This is accomplished by recording the MB/s in a single
> >> byte in the image header, and using a couple of __nosavedata variables
> >> to get the data back through the atomic restore. I realise the char limits
> >> us to 255MB/s at the moment. In future patches, I intend to address this
> >> by storing the data in a 'proper' image header (it's a real problem -
> >> TuxOnIce reads and writes on the same set up at speeds around 250MB/s).
> >>
> >> Results on my Dell XPS M1530, which has an SSD hard drive are:
> >>
> >> With just patch 1 applied:
> >> Attempt 1: Write 74MB/s; Read 52MB/s
> >> Attempt 2: Write 68MB/s; Read 52MB/s
> >> Attempt 3: Write 73MB/s; Read 53MB/s
> >>
> >> With the whole sequence:
> >> Attempt 1: Write 181MB/s; Read 52MB/s
> >> Attempt 2: Write 156MB/s; Read 53MB/s
> >> Attempt 3: Write 160MB/s; Read 52MB/s
> >
> > Thanks for the patches, they look like a real improvement to me.
> >
> > I only had a couple of minor comments, sent separately in replies to individual
> > patches.  I'd like to push this series for 2.6.37, if the comments are
> > addressed timely.
> 
> Okay. I'll update the patches. You can pull from
> 
> git://git.kernel.org/pub/scm/linux/kernel/git/nigelc/tuxonice-head.git#for-rafael
> 
> if you want.

I'd rather apply them individually for now, I may want to change subjects
etc. here and there.

> I'll apply your suggestions/comments to the versions there. I'll also 
> checkout what's going on with Martin's machine and hopefully apply 
> whatever fix is needed there too. Will keep you up to date with any changes.

OK, thanks.

At this point I think it'll be sufficient to combine patches 13 and 14 and send
me the result.

Best,
Rafael

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

* Re: Nigel's current for-rafael queue
  2010-09-25 22:33   ` Nigel Cunningham
@ 2010-09-25 22:36     ` Rafael J. Wysocki
  2010-09-25 22:36     ` Rafael J. Wysocki
  1 sibling, 0 replies; 80+ messages in thread
From: Rafael J. Wysocki @ 2010-09-25 22:36 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: Linux PM, LKML, TuxOnIce-devel

On Sunday, September 26, 2010, Nigel Cunningham wrote:
> Hi.
> 
> On 26/09/10 08:19, Rafael J. Wysocki wrote:
> > On Saturday, September 25, 2010, Nigel Cunningham wrote:
> >> Hi Rafael.
> >
> > Hi Nigel,
> >
> >> Please find attached a slightly updated version of the patchset I sent
> >> a few months ago. The main change is that I've prepended and additional
> >> patch which lets the user see the speed at which the image is being
> >> read and written. This is accomplished by recording the MB/s in a single
> >> byte in the image header, and using a couple of __nosavedata variables
> >> to get the data back through the atomic restore. I realise the char limits
> >> us to 255MB/s at the moment. In future patches, I intend to address this
> >> by storing the data in a 'proper' image header (it's a real problem -
> >> TuxOnIce reads and writes on the same set up at speeds around 250MB/s).
> >>
> >> Results on my Dell XPS M1530, which has an SSD hard drive are:
> >>
> >> With just patch 1 applied:
> >> Attempt 1: Write 74MB/s; Read 52MB/s
> >> Attempt 2: Write 68MB/s; Read 52MB/s
> >> Attempt 3: Write 73MB/s; Read 53MB/s
> >>
> >> With the whole sequence:
> >> Attempt 1: Write 181MB/s; Read 52MB/s
> >> Attempt 2: Write 156MB/s; Read 53MB/s
> >> Attempt 3: Write 160MB/s; Read 52MB/s
> >
> > Thanks for the patches, they look like a real improvement to me.
> >
> > I only had a couple of minor comments, sent separately in replies to individual
> > patches.  I'd like to push this series for 2.6.37, if the comments are
> > addressed timely.
> 
> Okay. I'll update the patches. You can pull from
> 
> git://git.kernel.org/pub/scm/linux/kernel/git/nigelc/tuxonice-head.git#for-rafael
> 
> if you want.

I'd rather apply them individually for now, I may want to change subjects
etc. here and there.

> I'll apply your suggestions/comments to the versions there. I'll also 
> checkout what's going on with Martin's machine and hopefully apply 
> whatever fix is needed there too. Will keep you up to date with any changes.

OK, thanks.

At this point I think it'll be sufficient to combine patches 13 and 14 and send
me the result.

Best,
Rafael

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

* Re: [TuxOnIce-devel] Nigel's current for-rafael queue
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (52 preceding siblings ...)
  2010-09-28 10:34 ` [TuxOnIce-devel] " Martin Steigerwald
@ 2010-09-28 10:34 ` Martin Steigerwald
  2010-09-30  7:52   ` unable to handle paging request at resume (was: Re: [TuxOnIce-devel] Nigel's current for-rafael queue) Martin Steigerwald
  2010-09-30  7:52   ` Martin Steigerwald
  2010-09-28 19:45 ` [TuxOnIce-devel] Nigel's current for-rafael queue Martin Steigerwald
  2010-09-28 19:45 ` Martin Steigerwald
  55 siblings, 2 replies; 80+ messages in thread
From: Martin Steigerwald @ 2010-09-28 10:34 UTC (permalink / raw)
  To: tuxonice-devel
  Cc: Nigel Cunningham, Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

[-- Attachment #1: Type: Text/Plain, Size: 3004 bytes --]

Am Samstag 25 September 2010 schrieb Nigel Cunningham:
> Hi Rafael.
> 
> Please find attached a slightly updated version of the patchset I sent
> a few months ago. The main change is that I've prepended and additional
> patch which lets the user see the speed at which the image is being
> read and written. This is accomplished by recording the MB/s in a
> single byte in the image header, and using a couple of __nosavedata
> variables to get the data back through the atomic restore. I realise
> the char limits us to 255MB/s at the moment. In future patches, I
> intend to address this by storing the data in a 'proper' image header
> (it's a real problem - TuxOnIce reads and writes on the same set up at
> speeds around 250MB/s).
> 
> Results on my Dell XPS M1530, which has an SSD hard drive are:
> 
> With just patch 1 applied:
> Attempt 1: Write 74MB/s; Read 52MB/s
> Attempt 2: Write 68MB/s; Read 52MB/s
> Attempt 3: Write 73MB/s; Read 53MB/s
> 
> With the whole sequence:
> Attempt 1: Write 181MB/s; Read 52MB/s
> Attempt 2: Write 156MB/s; Read 53MB/s
> Attempt 3: Write 160MB/s; Read 52MB/s

Is doesn't get much stabler than 

shambhala:~> grep "PM: Image.*at " /var/log/syslog
Sep 28 11:32:06 shambhala kernel: PM: Image written at 63 MB/s.
Sep 28 11:32:06 shambhala kernel: PM: Image read at 32 MB/s.
Sep 28 11:35:00 shambhala kernel: PM: Image written at 65 MB/s.
Sep 28 11:35:00 shambhala kernel: PM: Image read at 32 MB/s.
Sep 28 11:38:43 shambhala kernel: PM: Image written at 65 MB/s.
Sep 28 11:38:43 shambhala kernel: PM: Image read at 33 MB/s.
Sep 28 11:41:15 shambhala kernel: PM: Image written at 66 MB/s.
Sep 28 11:41:15 shambhala kernel: PM: Image read at 33 MB/s.
Sep 28 11:42:57 shambhala kernel: PM: Image written at 66 MB/s.
Sep 28 11:42:57 shambhala kernel: PM: Image read at 34 MB/s.
Sep 28 11:45:16 shambhala kernel: PM: Image written at 66 MB/s.
Sep 28 11:45:16 shambhala kernel: PM: Image read at 34 MB/s.
Sep 28 12:19:21 shambhala kernel: PM: Image written at 66 MB/s.
Sep 28 12:19:21 shambhala kernel: PM: Image read at 35 MB/s.
Sep 28 12:21:35 shambhala kernel: PM: Image written at 65 MB/s.
Sep 28 12:21:35 shambhala kernel: PM: Image read at 35 MB/s.
Sep 28 12:23:18 shambhala kernel: PM: Image written at 65 MB/s.
Sep 28 12:23:18 shambhala kernel: PM: Image read at 35 MB/s.
Sep 28 12:25:23 shambhala kernel: PM: Image written at 64 MB/s.
Sep 28 12:25:23 shambhala kernel: PM: Image read at 36 MB/s.
Sep 28 12:26:55 shambhala kernel: PM: Image written at 65 MB/s.
Sep 28 12:26:55 shambhala kernel: PM: Image read at 37 MB/s.
Sep 28 12:28:28 shambhala kernel: PM: Image written at 65 MB/s.
Sep 28 12:28:28 shambhala kernel: PM: Image read at 37 MB/s.

many attempts.

So - without readahead patch for now -

Tested-By: Martin Steigerwald <Martin@Lichtvoll.de>

on 2.6.36-rc5.

Thanks,
-- 
Martin 'Helios' Steigerwald - http://www.Lichtvoll.de
GPG: 03B0 0D6C 0040 0710 4AFA  B82F 991B EAAC A599 84C7

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

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

* Re: [TuxOnIce-devel] Nigel's current for-rafael queue
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (51 preceding siblings ...)
  2010-09-25 22:19 ` Rafael J. Wysocki
@ 2010-09-28 10:34 ` Martin Steigerwald
  2010-09-28 10:34 ` Martin Steigerwald
                   ` (2 subsequent siblings)
  55 siblings, 0 replies; 80+ messages in thread
From: Martin Steigerwald @ 2010-09-28 10:34 UTC (permalink / raw)
  Cc: Linux PM, LKML, TuxOnIce-devel


[-- Attachment #1.1: Type: Text/Plain, Size: 3004 bytes --]

Am Samstag 25 September 2010 schrieb Nigel Cunningham:
> Hi Rafael.
> 
> Please find attached a slightly updated version of the patchset I sent
> a few months ago. The main change is that I've prepended and additional
> patch which lets the user see the speed at which the image is being
> read and written. This is accomplished by recording the MB/s in a
> single byte in the image header, and using a couple of __nosavedata
> variables to get the data back through the atomic restore. I realise
> the char limits us to 255MB/s at the moment. In future patches, I
> intend to address this by storing the data in a 'proper' image header
> (it's a real problem - TuxOnIce reads and writes on the same set up at
> speeds around 250MB/s).
> 
> Results on my Dell XPS M1530, which has an SSD hard drive are:
> 
> With just patch 1 applied:
> Attempt 1: Write 74MB/s; Read 52MB/s
> Attempt 2: Write 68MB/s; Read 52MB/s
> Attempt 3: Write 73MB/s; Read 53MB/s
> 
> With the whole sequence:
> Attempt 1: Write 181MB/s; Read 52MB/s
> Attempt 2: Write 156MB/s; Read 53MB/s
> Attempt 3: Write 160MB/s; Read 52MB/s

Is doesn't get much stabler than 

shambhala:~> grep "PM: Image.*at " /var/log/syslog
Sep 28 11:32:06 shambhala kernel: PM: Image written at 63 MB/s.
Sep 28 11:32:06 shambhala kernel: PM: Image read at 32 MB/s.
Sep 28 11:35:00 shambhala kernel: PM: Image written at 65 MB/s.
Sep 28 11:35:00 shambhala kernel: PM: Image read at 32 MB/s.
Sep 28 11:38:43 shambhala kernel: PM: Image written at 65 MB/s.
Sep 28 11:38:43 shambhala kernel: PM: Image read at 33 MB/s.
Sep 28 11:41:15 shambhala kernel: PM: Image written at 66 MB/s.
Sep 28 11:41:15 shambhala kernel: PM: Image read at 33 MB/s.
Sep 28 11:42:57 shambhala kernel: PM: Image written at 66 MB/s.
Sep 28 11:42:57 shambhala kernel: PM: Image read at 34 MB/s.
Sep 28 11:45:16 shambhala kernel: PM: Image written at 66 MB/s.
Sep 28 11:45:16 shambhala kernel: PM: Image read at 34 MB/s.
Sep 28 12:19:21 shambhala kernel: PM: Image written at 66 MB/s.
Sep 28 12:19:21 shambhala kernel: PM: Image read at 35 MB/s.
Sep 28 12:21:35 shambhala kernel: PM: Image written at 65 MB/s.
Sep 28 12:21:35 shambhala kernel: PM: Image read at 35 MB/s.
Sep 28 12:23:18 shambhala kernel: PM: Image written at 65 MB/s.
Sep 28 12:23:18 shambhala kernel: PM: Image read at 35 MB/s.
Sep 28 12:25:23 shambhala kernel: PM: Image written at 64 MB/s.
Sep 28 12:25:23 shambhala kernel: PM: Image read at 36 MB/s.
Sep 28 12:26:55 shambhala kernel: PM: Image written at 65 MB/s.
Sep 28 12:26:55 shambhala kernel: PM: Image read at 37 MB/s.
Sep 28 12:28:28 shambhala kernel: PM: Image written at 65 MB/s.
Sep 28 12:28:28 shambhala kernel: PM: Image read at 37 MB/s.

many attempts.

So - without readahead patch for now -

Tested-By: Martin Steigerwald <Martin@Lichtvoll.de>

on 2.6.36-rc5.

Thanks,
-- 
Martin 'Helios' Steigerwald - http://www.Lichtvoll.de
GPG: 03B0 0D6C 0040 0710 4AFA  B82F 991B EAAC A599 84C7

[-- Attachment #1.2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

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



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

* Re: [TuxOnIce-devel] Nigel's current for-rafael queue
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (54 preceding siblings ...)
  2010-09-28 19:45 ` [TuxOnIce-devel] Nigel's current for-rafael queue Martin Steigerwald
@ 2010-09-28 19:45 ` Martin Steigerwald
  2010-09-28 21:25   ` Nigel Cunningham
  2010-09-28 21:25   ` Nigel Cunningham
  55 siblings, 2 replies; 80+ messages in thread
From: Martin Steigerwald @ 2010-09-28 19:45 UTC (permalink / raw)
  To: tuxonice-devel
  Cc: Nigel Cunningham, Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

[-- Attachment #1: Type: Text/Plain, Size: 1726 bytes --]

Am Samstag 25 September 2010 schrieb Nigel Cunningham:
> Hi Rafael.

Hi Nigel,

> Please find attached a slightly updated version of the patchset I sent
> a few months ago. The main change is that I've prepended and additional
> patch which lets the user see the speed at which the image is being
> read and written. This is accomplished by recording the MB/s in a
> single byte in the image header, and using a couple of __nosavedata
> variables to get the data back through the atomic restore. I realise
> the char limits us to 255MB/s at the moment. In future patches, I
> intend to address this by storing the data in a 'proper' image header
> (it's a real problem - TuxOnIce reads and writes on the same set up at
> speeds around 250MB/s).
> 
> Results on my Dell XPS M1530, which has an SSD hard drive are:

I found one issue with this patchset or more precise I think with the 
state of in-kernel-suspend before:

I accidentally booted a kernel without your patches and it didn't seem to 
stop on the hibernation image from the kernel with your patches. Well I 
let my laptop unattended for a little while, so when there has been a 
(short) timeout, I might have missed that message.

I lost a hibernation image this way which caused successful journal replay 
on my Ext4 filesystems. 

Does a kernel without your patches offer to reboot into the correct kernel, 
then it finds a hibernation image from a kernel with your patches?

If not, I think for the future it should give a warning with a quite high 
timeout, and offer to reboot into the right kernel.

Ciao,
-- 
Martin 'Helios' Steigerwald - http://www.Lichtvoll.de
GPG: 03B0 0D6C 0040 0710 4AFA  B82F 991B EAAC A599 84C7

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

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

* Re: [TuxOnIce-devel] Nigel's current for-rafael queue
  2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
                   ` (53 preceding siblings ...)
  2010-09-28 10:34 ` Martin Steigerwald
@ 2010-09-28 19:45 ` Martin Steigerwald
  2010-09-28 19:45 ` Martin Steigerwald
  55 siblings, 0 replies; 80+ messages in thread
From: Martin Steigerwald @ 2010-09-28 19:45 UTC (permalink / raw)
  Cc: Linux PM, LKML, TuxOnIce-devel


[-- Attachment #1.1: Type: Text/Plain, Size: 1726 bytes --]

Am Samstag 25 September 2010 schrieb Nigel Cunningham:
> Hi Rafael.

Hi Nigel,

> Please find attached a slightly updated version of the patchset I sent
> a few months ago. The main change is that I've prepended and additional
> patch which lets the user see the speed at which the image is being
> read and written. This is accomplished by recording the MB/s in a
> single byte in the image header, and using a couple of __nosavedata
> variables to get the data back through the atomic restore. I realise
> the char limits us to 255MB/s at the moment. In future patches, I
> intend to address this by storing the data in a 'proper' image header
> (it's a real problem - TuxOnIce reads and writes on the same set up at
> speeds around 250MB/s).
> 
> Results on my Dell XPS M1530, which has an SSD hard drive are:

I found one issue with this patchset or more precise I think with the 
state of in-kernel-suspend before:

I accidentally booted a kernel without your patches and it didn't seem to 
stop on the hibernation image from the kernel with your patches. Well I 
let my laptop unattended for a little while, so when there has been a 
(short) timeout, I might have missed that message.

I lost a hibernation image this way which caused successful journal replay 
on my Ext4 filesystems. 

Does a kernel without your patches offer to reboot into the correct kernel, 
then it finds a hibernation image from a kernel with your patches?

If not, I think for the future it should give a warning with a quite high 
timeout, and offer to reboot into the right kernel.

Ciao,
-- 
Martin 'Helios' Steigerwald - http://www.Lichtvoll.de
GPG: 03B0 0D6C 0040 0710 4AFA  B82F 991B EAAC A599 84C7

[-- Attachment #1.2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

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



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

* Re: [TuxOnIce-devel] Nigel's current for-rafael queue
  2010-09-28 19:45 ` Martin Steigerwald
  2010-09-28 21:25   ` Nigel Cunningham
@ 2010-09-28 21:25   ` Nigel Cunningham
  2010-09-30  7:56     ` Martin Steigerwald
  2010-09-30  7:56     ` Martin Steigerwald
  1 sibling, 2 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-28 21:25 UTC (permalink / raw)
  To: Martin Steigerwald
  Cc: tuxonice-devel, Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Hi Martin.

On 29/09/10 05:45, Martin Steigerwald wrote:
> Am Samstag 25 September 2010 schrieb Nigel Cunningham:
>> Hi Rafael.
>
> Hi Nigel,
>
>> Please find attached a slightly updated version of the patchset I sent
>> a few months ago. The main change is that I've prepended and additional
>> patch which lets the user see the speed at which the image is being
>> read and written. This is accomplished by recording the MB/s in a
>> single byte in the image header, and using a couple of __nosavedata
>> variables to get the data back through the atomic restore. I realise
>> the char limits us to 255MB/s at the moment. In future patches, I
>> intend to address this by storing the data in a 'proper' image header
>> (it's a real problem - TuxOnIce reads and writes on the same set up at
>> speeds around 250MB/s).
>>
>> Results on my Dell XPS M1530, which has an SSD hard drive are:
>
> I found one issue with this patchset or more precise I think with the
> state of in-kernel-suspend before:
>
> I accidentally booted a kernel without your patches and it didn't seem to
> stop on the hibernation image from the kernel with your patches. Well I
> let my laptop unattended for a little while, so when there has been a
> (short) timeout, I might have missed that message.
>
> I lost a hibernation image this way which caused successful journal replay
> on my Ext4 filesystems.
>
> Does a kernel without your patches offer to reboot into the correct kernel,
> then it finds a hibernation image from a kernel with your patches?
>
> If not, I think for the future it should give a warning with a quite high
> timeout, and offer to reboot into the right kernel.

My patches only focus on the I/O code in swsusp at the moment. I know 
there are still tons of things from TuxOnIce that could be put into 
swsusp, but at the moment I'm just focusing on I/O code.

The answer at the moment is therefore "I'm sorry, but if you're going to 
try out this code, you're going to have to live without some of 
TuxOnIce's nice features until I can split them into nice little 
patches, and start trying to persuade Rafael they're a good idea to merge."

Sorry!

Nigel

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

* Re: [TuxOnIce-devel] Nigel's current for-rafael queue
  2010-09-28 19:45 ` Martin Steigerwald
@ 2010-09-28 21:25   ` Nigel Cunningham
  2010-09-28 21:25   ` Nigel Cunningham
  1 sibling, 0 replies; 80+ messages in thread
From: Nigel Cunningham @ 2010-09-28 21:25 UTC (permalink / raw)
  To: Martin Steigerwald; +Cc: Linux PM, TuxOnIce-devel, LKML

Hi Martin.

On 29/09/10 05:45, Martin Steigerwald wrote:
> Am Samstag 25 September 2010 schrieb Nigel Cunningham:
>> Hi Rafael.
>
> Hi Nigel,
>
>> Please find attached a slightly updated version of the patchset I sent
>> a few months ago. The main change is that I've prepended and additional
>> patch which lets the user see the speed at which the image is being
>> read and written. This is accomplished by recording the MB/s in a
>> single byte in the image header, and using a couple of __nosavedata
>> variables to get the data back through the atomic restore. I realise
>> the char limits us to 255MB/s at the moment. In future patches, I
>> intend to address this by storing the data in a 'proper' image header
>> (it's a real problem - TuxOnIce reads and writes on the same set up at
>> speeds around 250MB/s).
>>
>> Results on my Dell XPS M1530, which has an SSD hard drive are:
>
> I found one issue with this patchset or more precise I think with the
> state of in-kernel-suspend before:
>
> I accidentally booted a kernel without your patches and it didn't seem to
> stop on the hibernation image from the kernel with your patches. Well I
> let my laptop unattended for a little while, so when there has been a
> (short) timeout, I might have missed that message.
>
> I lost a hibernation image this way which caused successful journal replay
> on my Ext4 filesystems.
>
> Does a kernel without your patches offer to reboot into the correct kernel,
> then it finds a hibernation image from a kernel with your patches?
>
> If not, I think for the future it should give a warning with a quite high
> timeout, and offer to reboot into the right kernel.

My patches only focus on the I/O code in swsusp at the moment. I know 
there are still tons of things from TuxOnIce that could be put into 
swsusp, but at the moment I'm just focusing on I/O code.

The answer at the moment is therefore "I'm sorry, but if you're going to 
try out this code, you're going to have to live without some of 
TuxOnIce's nice features until I can split them into nice little 
patches, and start trying to persuade Rafael they're a good idea to merge."

Sorry!

Nigel

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

* unable to handle paging request at resume (was: Re: [TuxOnIce-devel] Nigel's current for-rafael queue)
  2010-09-28 10:34 ` Martin Steigerwald
@ 2010-09-30  7:52   ` Martin Steigerwald
  2010-10-02 16:51     ` Martin Steigerwald
  2010-10-02 16:51     ` [linux-pm] " Martin Steigerwald
  2010-09-30  7:52   ` Martin Steigerwald
  1 sibling, 2 replies; 80+ messages in thread
From: Martin Steigerwald @ 2010-09-30  7:52 UTC (permalink / raw)
  To: TuxOnIce-devel; +Cc: Rafael J. Wysocki, Linux PM, LKML

[-- Attachment #1: Type: Text/Plain, Size: 7619 bytes --]

Hi Nigel and Rafael,

Am Dienstag 28 September 2010 schrieb Martin Steigerwald:
> Am Samstag 25 September 2010 schrieb Nigel Cunningham:
> > Hi Rafael.
> > 
> > Please find attached a slightly updated version of the patchset I
> > sent a few months ago. The main change is that I've prepended and
> > additional patch which lets the user see the speed at which the
> > image is being read and written. This is accomplished by recording
> > the MB/s in a single byte in the image header, and using a couple of
> > __nosavedata variables to get the data back through the atomic
> > restore. I realise the char limits us to 255MB/s at the moment. In
> > future patches, I intend to address this by storing the data in a
> > 'proper' image header (it's a real problem - TuxOnIce reads and
> > writes on the same set up at speeds around 250MB/s).
> > 
> > Results on my Dell XPS M1530, which has an SSD hard drive are:
> > 
> > With just patch 1 applied:
> > Attempt 1: Write 74MB/s; Read 52MB/s
> > Attempt 2: Write 68MB/s; Read 52MB/s
> > Attempt 3: Write 73MB/s; Read 53MB/s
> > 
> > With the whole sequence:
> > Attempt 1: Write 181MB/s; Read 52MB/s
> > Attempt 2: Write 156MB/s; Read 53MB/s
> > Attempt 3: Write 160MB/s; Read 52MB/s
> 
> Is doesn't get much stabler than
> 
> shambhala:~> grep "PM: Image.*at " /var/log/syslog
> Sep 28 11:32:06 shambhala kernel: PM: Image written at 63 MB/s.
> Sep 28 11:32:06 shambhala kernel: PM: Image read at 32 MB/s.
> Sep 28 11:35:00 shambhala kernel: PM: Image written at 65 MB/s.
> Sep 28 11:35:00 shambhala kernel: PM: Image read at 32 MB/s.
> Sep 28 11:38:43 shambhala kernel: PM: Image written at 65 MB/s.
> Sep 28 11:38:43 shambhala kernel: PM: Image read at 33 MB/s.
> Sep 28 11:41:15 shambhala kernel: PM: Image written at 66 MB/s.
> Sep 28 11:41:15 shambhala kernel: PM: Image read at 33 MB/s.
> Sep 28 11:42:57 shambhala kernel: PM: Image written at 66 MB/s.
> Sep 28 11:42:57 shambhala kernel: PM: Image read at 34 MB/s.
> Sep 28 11:45:16 shambhala kernel: PM: Image written at 66 MB/s.
> Sep 28 11:45:16 shambhala kernel: PM: Image read at 34 MB/s.
> Sep 28 12:19:21 shambhala kernel: PM: Image written at 66 MB/s.
> Sep 28 12:19:21 shambhala kernel: PM: Image read at 35 MB/s.
> Sep 28 12:21:35 shambhala kernel: PM: Image written at 65 MB/s.
> Sep 28 12:21:35 shambhala kernel: PM: Image read at 35 MB/s.
> Sep 28 12:23:18 shambhala kernel: PM: Image written at 65 MB/s.
> Sep 28 12:23:18 shambhala kernel: PM: Image read at 35 MB/s.
> Sep 28 12:25:23 shambhala kernel: PM: Image written at 64 MB/s.
> Sep 28 12:25:23 shambhala kernel: PM: Image read at 36 MB/s.
> Sep 28 12:26:55 shambhala kernel: PM: Image written at 65 MB/s.
> Sep 28 12:26:55 shambhala kernel: PM: Image read at 37 MB/s.
> Sep 28 12:28:28 shambhala kernel: PM: Image written at 65 MB/s.
> Sep 28 12:28:28 shambhala kernel: PM: Image read at 37 MB/s.
> 
> many attempts.
> 
> So - without readahead patch for now -
> 
> Tested-By: Martin Steigerwald <Martin@Lichtvoll.de>
> 
> on 2.6.36-rc5.

Well probably it couldn't get more stable than that, but it was able to 
get more unstable:

This morning I got a unable to handle paging request after switching on my 
kernel suspended ThinkPad T42. With exactly that kernel with all of 
Nigel's patches except for the readahead one.

http://martin-steigerwald.de/tmp/suspend-patches/unable-to-handle-paging-
request-at-resume/

IMG_3897.JPG  is what I saw first. IMG_3900.JPG came after I pressed the 
power button to swich off the machine in order to cold reboot it. As I left 
the machine unattended during resume, I did not see what happened before 
this.

On the next attempt the laptop just rebootet instead of trying to resume 
from the saved image again.

I grepped stuff in syslog and found that it seemed to have been able to 
write some stuff into syslog prior to the trace:

Sep 30 00:00:34 shambhala kernel: PM: Marking nosave pages: 
000000000009f000 - 0000000000100000
Sep 30 00:00:34 shambhala kernel: PM: Basic memory bitmaps created
Sep 30 00:00:34 shambhala kernel: PM: Syncing filesystems ... done.
Sep 30 09:13:34 shambhala kernel: Freezing user space processes ... 
00:02:00.0: restoring config space at offset
 0x1 (was 0x2100107, writing 0x2100007)
Sep 30 09:13:34 shambhala kernel: yenta_cardbus 0000:02:00.1: restoring 
config space at offset 0xf (was 0x3c0020
b, writing 0x5c0020b)
Sep 30 09:13:34 shambhala kernel: yenta_cardbus 0000:02:00.1: restoring 
config space at offset 0x3 (was 0x824008
, writing 0x82a810)
Sep 30 09:13:34 shambhala kernel: yenta_cardbus 0000:02:00.1: restoring 
config space at offset 0x1 (was 0x210010
7, writing 0x2100007)
Sep 30 09:13:34 shambhala kernel: e1000 0000:02:01.0: BAR 0: set to [mem 
0xc0220000-0xc023ffff] (PCI address [0x
c0220000-0xc023ffff]
Sep 30 09:13:34 shambhala kernel: e1000 0000:02:01.0: BAR 1: set to [mem 
0xc0200000-0xc020ffff] (PCI address [0x
c0200000-0xc020ffff]
Sep 30 09:13:34 shambhala kernel: e1000 0000:02:01.0: BAR 2: set to [io  
0x8000-0x803f] (PCI address [0x8000-0x8
03f]
Sep 30 09:13:34 shambhala kernel: e1000 0000:02:01.0: restoring config 
space at offset 0xf (was 0xff0100, writin
g 0xff010b)
Sep 30 09:13:34 shambhala kernel: e1000 0000:02:01.0: restoring config 
space at offset 0x3 (was 0x0, writing 0x4
008)
Sep 30 09:13:34 shambhala kernel: e1000 0000:02:01.0: restoring config 
space at offset 0x1 (was 0x2300000, writi
ng 0x2300117)
Sep 30 09:13:34 shambhala kernel: PM: early restore of devices complete 
after 31.408 msecs
Sep 30 09:13:34 shambhala kernel: BUG: Bad page state in process echo  
pfn:73302
Sep 30 09:13:34 shambhala kernel: page:c24d8040 count:0 mapcount:1 
mapping:(null) index:0x9bf5
Sep 30 09:13:34 shambhala kernel: page flags: 0x80100078(uptodate|dirty|
lru|active|swapbacked)
Sep 30 09:13:34 shambhala kernel: Pid: 18599, comm: echo Not tainted 
2.6.36-rc5-tp42-hiber-wri-accel-vmembase-0-
00133-g3394a84-dirty #1
Sep 30 09:13:34 shambhala kernel: Call Trace:
Sep 30 09:13:34 shambhala kernel: [<c10ac8d3>] bad_page+0x83/0xd0
Sep 30 09:13:34 shambhala kernel: [<c10ad541>] 
free_pages_prepare+0x131/0x170
Sep 30 09:13:34 shambhala kernel: [<c10aef98>] 
free_hot_cold_page+0x28/0x140
Sep 30 09:13:34 shambhala kernel: [<c10af0e5>] __free_pages+0x35/0x40
Sep 30 09:13:34 shambhala kernel: [<c10727e6>] swsusp_free+0xa6/0x100
Sep 30 09:13:34 shambhala kernel: [<c10719f3>] 
hibernation_snapshot+0x123/0x290
Sep 30 09:13:34 shambhala kernel: [<c1070b76>] ? 
freeze_processes+0x56/0xa0
Sep 30 09:13:34 shambhala kernel: [<c1071c45>] hibernate+0xe5/0x210
Sep 30 09:13:34 shambhala kernel: [<c10704f0>] ? state_store+0x0/0xb0
Sep 30 09:13:34 shambhala kernel: [<c1070596>] state_store+0xa6/0xb0
Sep 30 09:13:34 shambhala kernSep 30 09:25:08 shambhala kernel: imklog 
4.6.4, log source = /proc/kmsg started.

Maybe this is a 2.6.36-rc5 bug instead of a bug in your patches, I can't 
tell.

Hope this helps. Topmost priority has finally finishing my tax returns for 
now, so I don't like to invest much time into it in the next two days.

After that I might try a new kernel, so if you have any suggestions on 
what to try, feel free to share them with me.

Please tell me when you like to have this reported into 
bugzilla.kernel.org! I'd prefer to report stuff there, instead of storing 
attachment on a temporary location onto my server.

Thanks,
-- 
Martin 'Helios' Steigerwald - http://www.Lichtvoll.de
GPG: 03B0 0D6C 0040 0710 4AFA  B82F 991B EAAC A599 84C7

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

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

* unable to handle paging request at resume (was: Re: [TuxOnIce-devel] Nigel's current for-rafael queue)
  2010-09-28 10:34 ` Martin Steigerwald
  2010-09-30  7:52   ` unable to handle paging request at resume (was: Re: [TuxOnIce-devel] Nigel's current for-rafael queue) Martin Steigerwald
@ 2010-09-30  7:52   ` Martin Steigerwald
  1 sibling, 0 replies; 80+ messages in thread
From: Martin Steigerwald @ 2010-09-30  7:52 UTC (permalink / raw)
  To: TuxOnIce-devel; +Cc: Linux PM, LKML


[-- Attachment #1.1: Type: Text/Plain, Size: 7619 bytes --]

Hi Nigel and Rafael,

Am Dienstag 28 September 2010 schrieb Martin Steigerwald:
> Am Samstag 25 September 2010 schrieb Nigel Cunningham:
> > Hi Rafael.
> > 
> > Please find attached a slightly updated version of the patchset I
> > sent a few months ago. The main change is that I've prepended and
> > additional patch which lets the user see the speed at which the
> > image is being read and written. This is accomplished by recording
> > the MB/s in a single byte in the image header, and using a couple of
> > __nosavedata variables to get the data back through the atomic
> > restore. I realise the char limits us to 255MB/s at the moment. In
> > future patches, I intend to address this by storing the data in a
> > 'proper' image header (it's a real problem - TuxOnIce reads and
> > writes on the same set up at speeds around 250MB/s).
> > 
> > Results on my Dell XPS M1530, which has an SSD hard drive are:
> > 
> > With just patch 1 applied:
> > Attempt 1: Write 74MB/s; Read 52MB/s
> > Attempt 2: Write 68MB/s; Read 52MB/s
> > Attempt 3: Write 73MB/s; Read 53MB/s
> > 
> > With the whole sequence:
> > Attempt 1: Write 181MB/s; Read 52MB/s
> > Attempt 2: Write 156MB/s; Read 53MB/s
> > Attempt 3: Write 160MB/s; Read 52MB/s
> 
> Is doesn't get much stabler than
> 
> shambhala:~> grep "PM: Image.*at " /var/log/syslog
> Sep 28 11:32:06 shambhala kernel: PM: Image written at 63 MB/s.
> Sep 28 11:32:06 shambhala kernel: PM: Image read at 32 MB/s.
> Sep 28 11:35:00 shambhala kernel: PM: Image written at 65 MB/s.
> Sep 28 11:35:00 shambhala kernel: PM: Image read at 32 MB/s.
> Sep 28 11:38:43 shambhala kernel: PM: Image written at 65 MB/s.
> Sep 28 11:38:43 shambhala kernel: PM: Image read at 33 MB/s.
> Sep 28 11:41:15 shambhala kernel: PM: Image written at 66 MB/s.
> Sep 28 11:41:15 shambhala kernel: PM: Image read at 33 MB/s.
> Sep 28 11:42:57 shambhala kernel: PM: Image written at 66 MB/s.
> Sep 28 11:42:57 shambhala kernel: PM: Image read at 34 MB/s.
> Sep 28 11:45:16 shambhala kernel: PM: Image written at 66 MB/s.
> Sep 28 11:45:16 shambhala kernel: PM: Image read at 34 MB/s.
> Sep 28 12:19:21 shambhala kernel: PM: Image written at 66 MB/s.
> Sep 28 12:19:21 shambhala kernel: PM: Image read at 35 MB/s.
> Sep 28 12:21:35 shambhala kernel: PM: Image written at 65 MB/s.
> Sep 28 12:21:35 shambhala kernel: PM: Image read at 35 MB/s.
> Sep 28 12:23:18 shambhala kernel: PM: Image written at 65 MB/s.
> Sep 28 12:23:18 shambhala kernel: PM: Image read at 35 MB/s.
> Sep 28 12:25:23 shambhala kernel: PM: Image written at 64 MB/s.
> Sep 28 12:25:23 shambhala kernel: PM: Image read at 36 MB/s.
> Sep 28 12:26:55 shambhala kernel: PM: Image written at 65 MB/s.
> Sep 28 12:26:55 shambhala kernel: PM: Image read at 37 MB/s.
> Sep 28 12:28:28 shambhala kernel: PM: Image written at 65 MB/s.
> Sep 28 12:28:28 shambhala kernel: PM: Image read at 37 MB/s.
> 
> many attempts.
> 
> So - without readahead patch for now -
> 
> Tested-By: Martin Steigerwald <Martin@Lichtvoll.de>
> 
> on 2.6.36-rc5.

Well probably it couldn't get more stable than that, but it was able to 
get more unstable:

This morning I got a unable to handle paging request after switching on my 
kernel suspended ThinkPad T42. With exactly that kernel with all of 
Nigel's patches except for the readahead one.

http://martin-steigerwald.de/tmp/suspend-patches/unable-to-handle-paging-
request-at-resume/

IMG_3897.JPG  is what I saw first. IMG_3900.JPG came after I pressed the 
power button to swich off the machine in order to cold reboot it. As I left 
the machine unattended during resume, I did not see what happened before 
this.

On the next attempt the laptop just rebootet instead of trying to resume 
from the saved image again.

I grepped stuff in syslog and found that it seemed to have been able to 
write some stuff into syslog prior to the trace:

Sep 30 00:00:34 shambhala kernel: PM: Marking nosave pages: 
000000000009f000 - 0000000000100000
Sep 30 00:00:34 shambhala kernel: PM: Basic memory bitmaps created
Sep 30 00:00:34 shambhala kernel: PM: Syncing filesystems ... done.
Sep 30 09:13:34 shambhala kernel: Freezing user space processes ... 
00:02:00.0: restoring config space at offset
 0x1 (was 0x2100107, writing 0x2100007)
Sep 30 09:13:34 shambhala kernel: yenta_cardbus 0000:02:00.1: restoring 
config space at offset 0xf (was 0x3c0020
b, writing 0x5c0020b)
Sep 30 09:13:34 shambhala kernel: yenta_cardbus 0000:02:00.1: restoring 
config space at offset 0x3 (was 0x824008
, writing 0x82a810)
Sep 30 09:13:34 shambhala kernel: yenta_cardbus 0000:02:00.1: restoring 
config space at offset 0x1 (was 0x210010
7, writing 0x2100007)
Sep 30 09:13:34 shambhala kernel: e1000 0000:02:01.0: BAR 0: set to [mem 
0xc0220000-0xc023ffff] (PCI address [0x
c0220000-0xc023ffff]
Sep 30 09:13:34 shambhala kernel: e1000 0000:02:01.0: BAR 1: set to [mem 
0xc0200000-0xc020ffff] (PCI address [0x
c0200000-0xc020ffff]
Sep 30 09:13:34 shambhala kernel: e1000 0000:02:01.0: BAR 2: set to [io  
0x8000-0x803f] (PCI address [0x8000-0x8
03f]
Sep 30 09:13:34 shambhala kernel: e1000 0000:02:01.0: restoring config 
space at offset 0xf (was 0xff0100, writin
g 0xff010b)
Sep 30 09:13:34 shambhala kernel: e1000 0000:02:01.0: restoring config 
space at offset 0x3 (was 0x0, writing 0x4
008)
Sep 30 09:13:34 shambhala kernel: e1000 0000:02:01.0: restoring config 
space at offset 0x1 (was 0x2300000, writi
ng 0x2300117)
Sep 30 09:13:34 shambhala kernel: PM: early restore of devices complete 
after 31.408 msecs
Sep 30 09:13:34 shambhala kernel: BUG: Bad page state in process echo  
pfn:73302
Sep 30 09:13:34 shambhala kernel: page:c24d8040 count:0 mapcount:1 
mapping:(null) index:0x9bf5
Sep 30 09:13:34 shambhala kernel: page flags: 0x80100078(uptodate|dirty|
lru|active|swapbacked)
Sep 30 09:13:34 shambhala kernel: Pid: 18599, comm: echo Not tainted 
2.6.36-rc5-tp42-hiber-wri-accel-vmembase-0-
00133-g3394a84-dirty #1
Sep 30 09:13:34 shambhala kernel: Call Trace:
Sep 30 09:13:34 shambhala kernel: [<c10ac8d3>] bad_page+0x83/0xd0
Sep 30 09:13:34 shambhala kernel: [<c10ad541>] 
free_pages_prepare+0x131/0x170
Sep 30 09:13:34 shambhala kernel: [<c10aef98>] 
free_hot_cold_page+0x28/0x140
Sep 30 09:13:34 shambhala kernel: [<c10af0e5>] __free_pages+0x35/0x40
Sep 30 09:13:34 shambhala kernel: [<c10727e6>] swsusp_free+0xa6/0x100
Sep 30 09:13:34 shambhala kernel: [<c10719f3>] 
hibernation_snapshot+0x123/0x290
Sep 30 09:13:34 shambhala kernel: [<c1070b76>] ? 
freeze_processes+0x56/0xa0
Sep 30 09:13:34 shambhala kernel: [<c1071c45>] hibernate+0xe5/0x210
Sep 30 09:13:34 shambhala kernel: [<c10704f0>] ? state_store+0x0/0xb0
Sep 30 09:13:34 shambhala kernel: [<c1070596>] state_store+0xa6/0xb0
Sep 30 09:13:34 shambhala kernSep 30 09:25:08 shambhala kernel: imklog 
4.6.4, log source = /proc/kmsg started.

Maybe this is a 2.6.36-rc5 bug instead of a bug in your patches, I can't 
tell.

Hope this helps. Topmost priority has finally finishing my tax returns for 
now, so I don't like to invest much time into it in the next two days.

After that I might try a new kernel, so if you have any suggestions on 
what to try, feel free to share them with me.

Please tell me when you like to have this reported into 
bugzilla.kernel.org! I'd prefer to report stuff there, instead of storing 
attachment on a temporary location onto my server.

Thanks,
-- 
Martin 'Helios' Steigerwald - http://www.Lichtvoll.de
GPG: 03B0 0D6C 0040 0710 4AFA  B82F 991B EAAC A599 84C7

[-- Attachment #1.2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

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



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

* Re: [TuxOnIce-devel] Nigel's current for-rafael queue
  2010-09-28 21:25   ` Nigel Cunningham
  2010-09-30  7:56     ` Martin Steigerwald
@ 2010-09-30  7:56     ` Martin Steigerwald
  1 sibling, 0 replies; 80+ messages in thread
From: Martin Steigerwald @ 2010-09-30  7:56 UTC (permalink / raw)
  To: Nigel Cunningham
  Cc: tuxonice-devel, Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

[-- Attachment #1: Type: Text/Plain, Size: 3237 bytes --]

Am Dienstag 28 September 2010 schrieb Nigel Cunningham:
> Hi Martin.

Hi Nigel.

> On 29/09/10 05:45, Martin Steigerwald wrote:
> > Am Samstag 25 September 2010 schrieb Nigel Cunningham:
> >> Hi Rafael.
> > 
> > Hi Nigel,
> > 
> >> Please find attached a slightly updated version of the patchset I
> >> sent a few months ago. The main change is that I've prepended and
> >> additional patch which lets the user see the speed at which the
> >> image is being read and written. This is accomplished by recording
> >> the MB/s in a single byte in the image header, and using a couple
> >> of __nosavedata variables to get the data back through the atomic
> >> restore. I realise the char limits us to 255MB/s at the moment. In
> >> future patches, I intend to address this by storing the data in a
> >> 'proper' image header (it's a real problem - TuxOnIce reads and
> >> writes on the same set up at speeds around 250MB/s).
> > 
> >> Results on my Dell XPS M1530, which has an SSD hard drive are:
> > I found one issue with this patchset or more precise I think with the
> > state of in-kernel-suspend before:
> > 
> > I accidentally booted a kernel without your patches and it didn't
> > seem to stop on the hibernation image from the kernel with your
> > patches. Well I let my laptop unattended for a little while, so when
> > there has been a (short) timeout, I might have missed that message.
> > 
> > I lost a hibernation image this way which caused successful journal
> > replay on my Ext4 filesystems.
> > 
> > Does a kernel without your patches offer to reboot into the correct
> > kernel, then it finds a hibernation image from a kernel with your
> > patches?
> > 
> > If not, I think for the future it should give a warning with a quite
> > high timeout, and offer to reboot into the right kernel.
> 
> My patches only focus on the I/O code in swsusp at the moment. I know
> there are still tons of things from TuxOnIce that could be put into
> swsusp, but at the moment I'm just focusing on I/O code.
> 
> The answer at the moment is therefore "I'm sorry, but if you're going
> to try out this code, you're going to have to live without some of
> TuxOnIce's nice features until I can split them into nice little
> patches, and start trying to persuade Rafael they're a good idea to
> merge."
> 
> Sorry!

No problem. I wasn't aware that in kernel suspend does not have any checks 
like that, cause TuxOnIce and Userspace Software Suspend both have them. 
Thus I thought, that the check somehow did not trigger while it should. 
But if no check was in there, this is no problem with your patches.

I try to avoid booting from kernels without your patches when I suspend 
from one with your patches by making sure that the kernel with your 
patches is the first in grub menu ;).

I think a check should go in as soon as possible tough. Cause anything 
else just asks for filesystem corruption. I still have a "sync" in my pre 
hibernate script that calls the hibernate script. And Ext4 is good at 
recovering from journals. But still...

Ciao,
-- 
Martin 'Helios' Steigerwald - http://www.Lichtvoll.de
GPG: 03B0 0D6C 0040 0710 4AFA  B82F 991B EAAC A599 84C7

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

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

* Re: [TuxOnIce-devel] Nigel's current for-rafael queue
  2010-09-28 21:25   ` Nigel Cunningham
@ 2010-09-30  7:56     ` Martin Steigerwald
  2010-09-30  7:56     ` Martin Steigerwald
  1 sibling, 0 replies; 80+ messages in thread
From: Martin Steigerwald @ 2010-09-30  7:56 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: Linux PM, TuxOnIce-devel, LKML


[-- Attachment #1.1: Type: Text/Plain, Size: 3237 bytes --]

Am Dienstag 28 September 2010 schrieb Nigel Cunningham:
> Hi Martin.

Hi Nigel.

> On 29/09/10 05:45, Martin Steigerwald wrote:
> > Am Samstag 25 September 2010 schrieb Nigel Cunningham:
> >> Hi Rafael.
> > 
> > Hi Nigel,
> > 
> >> Please find attached a slightly updated version of the patchset I
> >> sent a few months ago. The main change is that I've prepended and
> >> additional patch which lets the user see the speed at which the
> >> image is being read and written. This is accomplished by recording
> >> the MB/s in a single byte in the image header, and using a couple
> >> of __nosavedata variables to get the data back through the atomic
> >> restore. I realise the char limits us to 255MB/s at the moment. In
> >> future patches, I intend to address this by storing the data in a
> >> 'proper' image header (it's a real problem - TuxOnIce reads and
> >> writes on the same set up at speeds around 250MB/s).
> > 
> >> Results on my Dell XPS M1530, which has an SSD hard drive are:
> > I found one issue with this patchset or more precise I think with the
> > state of in-kernel-suspend before:
> > 
> > I accidentally booted a kernel without your patches and it didn't
> > seem to stop on the hibernation image from the kernel with your
> > patches. Well I let my laptop unattended for a little while, so when
> > there has been a (short) timeout, I might have missed that message.
> > 
> > I lost a hibernation image this way which caused successful journal
> > replay on my Ext4 filesystems.
> > 
> > Does a kernel without your patches offer to reboot into the correct
> > kernel, then it finds a hibernation image from a kernel with your
> > patches?
> > 
> > If not, I think for the future it should give a warning with a quite
> > high timeout, and offer to reboot into the right kernel.
> 
> My patches only focus on the I/O code in swsusp at the moment. I know
> there are still tons of things from TuxOnIce that could be put into
> swsusp, but at the moment I'm just focusing on I/O code.
> 
> The answer at the moment is therefore "I'm sorry, but if you're going
> to try out this code, you're going to have to live without some of
> TuxOnIce's nice features until I can split them into nice little
> patches, and start trying to persuade Rafael they're a good idea to
> merge."
> 
> Sorry!

No problem. I wasn't aware that in kernel suspend does not have any checks 
like that, cause TuxOnIce and Userspace Software Suspend both have them. 
Thus I thought, that the check somehow did not trigger while it should. 
But if no check was in there, this is no problem with your patches.

I try to avoid booting from kernels without your patches when I suspend 
from one with your patches by making sure that the kernel with your 
patches is the first in grub menu ;).

I think a check should go in as soon as possible tough. Cause anything 
else just asks for filesystem corruption. I still have a "sync" in my pre 
hibernate script that calls the hibernate script. And Ext4 is good at 
recovering from journals. But still...

Ciao,
-- 
Martin 'Helios' Steigerwald - http://www.Lichtvoll.de
GPG: 03B0 0D6C 0040 0710 4AFA  B82F 991B EAAC A599 84C7

[-- Attachment #1.2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

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



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

* Re: [linux-pm] unable to handle paging request at resume (was: Re: [TuxOnIce-devel] Nigel's current for-rafael queue)
  2010-09-30  7:52   ` unable to handle paging request at resume (was: Re: [TuxOnIce-devel] Nigel's current for-rafael queue) Martin Steigerwald
  2010-10-02 16:51     ` Martin Steigerwald
@ 2010-10-02 16:51     ` Martin Steigerwald
  1 sibling, 0 replies; 80+ messages in thread
From: Martin Steigerwald @ 2010-10-02 16:51 UTC (permalink / raw)
  To: linux-pm; +Cc: TuxOnIce-devel, LKML, Nigel Cunningham

[-- Attachment #1: Type: Text/Plain, Size: 7495 bytes --]

Am Donnerstag 30 September 2010 schrieb Martin Steigerwald:
> Hi Nigel and Rafael,
> 
> Am Dienstag 28 September 2010 schrieb Martin Steigerwald:
> > Am Samstag 25 September 2010 schrieb Nigel Cunningham:
> > > Hi Rafael.
> > > 
> > > Please find attached a slightly updated version of the patchset I
> > > sent a few months ago. The main change is that I've prepended and
> > > additional patch which lets the user see the speed at which the
> > > image is being read and written. This is accomplished by recording
> > > the MB/s in a single byte in the image header, and using a couple
> > > of __nosavedata variables to get the data back through the atomic
> > > restore. I realise the char limits us to 255MB/s at the moment. In
> > > future patches, I intend to address this by storing the data in a
> > > 'proper' image header (it's a real problem - TuxOnIce reads and
> > > writes on the same set up at speeds around 250MB/s).
> > > 
> > > Results on my Dell XPS M1530, which has an SSD hard drive are:
> > > 
> > > With just patch 1 applied:
> > > Attempt 1: Write 74MB/s; Read 52MB/s
> > > Attempt 2: Write 68MB/s; Read 52MB/s
> > > Attempt 3: Write 73MB/s; Read 53MB/s
> > > 
> > > With the whole sequence:
> > > Attempt 1: Write 181MB/s; Read 52MB/s
> > > Attempt 2: Write 156MB/s; Read 53MB/s
> > > Attempt 3: Write 160MB/s; Read 52MB/s
> > 
> > Is doesn't get much stabler than
> > 
> > shambhala:~> grep "PM: Image.*at " /var/log/syslog
> > Sep 28 11:32:06 shambhala kernel: PM: Image written at 63 MB/s.
> > Sep 28 11:32:06 shambhala kernel: PM: Image read at 32 MB/s.
> > Sep 28 11:35:00 shambhala kernel: PM: Image written at 65 MB/s.
> > Sep 28 11:35:00 shambhala kernel: PM: Image read at 32 MB/s.
> > Sep 28 11:38:43 shambhala kernel: PM: Image written at 65 MB/s.
> > Sep 28 11:38:43 shambhala kernel: PM: Image read at 33 MB/s.
> > Sep 28 11:41:15 shambhala kernel: PM: Image written at 66 MB/s.
> > Sep 28 11:41:15 shambhala kernel: PM: Image read at 33 MB/s.
> > Sep 28 11:42:57 shambhala kernel: PM: Image written at 66 MB/s.
> > Sep 28 11:42:57 shambhala kernel: PM: Image read at 34 MB/s.
> > Sep 28 11:45:16 shambhala kernel: PM: Image written at 66 MB/s.
> > Sep 28 11:45:16 shambhala kernel: PM: Image read at 34 MB/s.
> > Sep 28 12:19:21 shambhala kernel: PM: Image written at 66 MB/s.
> > Sep 28 12:19:21 shambhala kernel: PM: Image read at 35 MB/s.
> > Sep 28 12:21:35 shambhala kernel: PM: Image written at 65 MB/s.
> > Sep 28 12:21:35 shambhala kernel: PM: Image read at 35 MB/s.
> > Sep 28 12:23:18 shambhala kernel: PM: Image written at 65 MB/s.
> > Sep 28 12:23:18 shambhala kernel: PM: Image read at 35 MB/s.
> > Sep 28 12:25:23 shambhala kernel: PM: Image written at 64 MB/s.
> > Sep 28 12:25:23 shambhala kernel: PM: Image read at 36 MB/s.
> > Sep 28 12:26:55 shambhala kernel: PM: Image written at 65 MB/s.
> > Sep 28 12:26:55 shambhala kernel: PM: Image read at 37 MB/s.
> > Sep 28 12:28:28 shambhala kernel: PM: Image written at 65 MB/s.
> > Sep 28 12:28:28 shambhala kernel: PM: Image read at 37 MB/s.
> > 
> > many attempts.
> > 
> > So - without readahead patch for now -
> > 
> > Tested-By: Martin Steigerwald <Martin@Lichtvoll.de>
> > 
> > on 2.6.36-rc5.
> 
> Well probably it couldn't get more stable than that, but it was able to
> get more unstable:
> 
> This morning I got a unable to handle paging request after switching on
> my kernel suspended ThinkPad T42. With exactly that kernel with all of
> Nigel's patches except for the readahead one.
> 
> http://martin-steigerwald.de/tmp/suspend-patches/unable-to-handle-pagin
> g- request-at-resume/
> 
> IMG_3897.JPG  is what I saw first. IMG_3900.JPG came after I pressed
> the power button to swich off the machine in order to cold reboot it.
> As I left the machine unattended during resume, I did not see what
> happened before this.
> 
> On the next attempt the laptop just rebootet instead of trying to
> resume from the saved image again.
> 
> I grepped stuff in syslog and found that it seemed to have been able to
> write some stuff into syslog prior to the trace:
> 
> Sep 30 00:00:34 shambhala kernel: PM: Marking nosave pages:
> 000000000009f000 - 0000000000100000
> Sep 30 00:00:34 shambhala kernel: PM: Basic memory bitmaps created
> Sep 30 00:00:34 shambhala kernel: PM: Syncing filesystems ... done.
> Sep 30 09:13:34 shambhala kernel: Freezing user space processes ...
> 00:02:00.0: restoring config space at offset
>  0x1 (was 0x2100107, writing 0x2100007)
> Sep 30 09:13:34 shambhala kernel: yenta_cardbus 0000:02:00.1: restoring
> config space at offset 0xf (was 0x3c0020
> b, writing 0x5c0020b)
> Sep 30 09:13:34 shambhala kernel: yenta_cardbus 0000:02:00.1: restoring
> config space at offset 0x3 (was 0x824008
> , writing 0x82a810)
> Sep 30 09:13:34 shambhala kernel: yenta_cardbus 0000:02:00.1: restoring
> config space at offset 0x1 (was 0x210010
> 7, writing 0x2100007)
> Sep 30 09:13:34 shambhala kernel: e1000 0000:02:01.0: BAR 0: set to
> [mem 0xc0220000-0xc023ffff] (PCI address [0x
> c0220000-0xc023ffff]
> Sep 30 09:13:34 shambhala kernel: e1000 0000:02:01.0: BAR 1: set to
> [mem 0xc0200000-0xc020ffff] (PCI address [0x
> c0200000-0xc020ffff]
> Sep 30 09:13:34 shambhala kernel: e1000 0000:02:01.0: BAR 2: set to [io
> 0x8000-0x803f] (PCI address [0x8000-0x8
> 03f]
> Sep 30 09:13:34 shambhala kernel: e1000 0000:02:01.0: restoring config
> space at offset 0xf (was 0xff0100, writin
> g 0xff010b)
> Sep 30 09:13:34 shambhala kernel: e1000 0000:02:01.0: restoring config
> space at offset 0x3 (was 0x0, writing 0x4
> 008)
> Sep 30 09:13:34 shambhala kernel: e1000 0000:02:01.0: restoring config
> space at offset 0x1 (was 0x2300000, writi
> ng 0x2300117)
> Sep 30 09:13:34 shambhala kernel: PM: early restore of devices complete
> after 31.408 msecs
> Sep 30 09:13:34 shambhala kernel: BUG: Bad page state in process echo
> pfn:73302
> Sep 30 09:13:34 shambhala kernel: page:c24d8040 count:0 mapcount:1
> mapping:(null) index:0x9bf5
> Sep 30 09:13:34 shambhala kernel: page flags:
> 0x80100078(uptodate|dirty| lru|active|swapbacked)
> Sep 30 09:13:34 shambhala kernel: Pid: 18599, comm: echo Not tainted
> 2.6.36-rc5-tp42-hiber-wri-accel-vmembase-0-
> 00133-g3394a84-dirty #1
> Sep 30 09:13:34 shambhala kernel: Call Trace:
> Sep 30 09:13:34 shambhala kernel: [<c10ac8d3>] bad_page+0x83/0xd0
> Sep 30 09:13:34 shambhala kernel: [<c10ad541>]
> free_pages_prepare+0x131/0x170
> Sep 30 09:13:34 shambhala kernel: [<c10aef98>]
> free_hot_cold_page+0x28/0x140
> Sep 30 09:13:34 shambhala kernel: [<c10af0e5>] __free_pages+0x35/0x40
> Sep 30 09:13:34 shambhala kernel: [<c10727e6>] swsusp_free+0xa6/0x100
> Sep 30 09:13:34 shambhala kernel: [<c10719f3>]
> hibernation_snapshot+0x123/0x290
> Sep 30 09:13:34 shambhala kernel: [<c1070b76>] ?
> freeze_processes+0x56/0xa0
> Sep 30 09:13:34 shambhala kernel: [<c1071c45>] hibernate+0xe5/0x210
> Sep 30 09:13:34 shambhala kernel: [<c10704f0>] ? state_store+0x0/0xb0
> Sep 30 09:13:34 shambhala kernel: [<c1070596>] state_store+0xa6/0xb0
> Sep 30 09:13:34 shambhala kernSep 30 09:25:08 shambhala kernel: imklog
> 4.6.4, log source = /proc/kmsg started.

I didn't see this one again so far.

Still I wonder what that might have been. Any hints?

Ciao,
-- 
Martin 'Helios' Steigerwald - http://www.Lichtvoll.de
GPG: 03B0 0D6C 0040 0710 4AFA  B82F 991B EAAC A599 84C7

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

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

* Re: unable to handle paging request at resume (was: Re: [TuxOnIce-devel] Nigel's current for-rafael queue)
  2010-09-30  7:52   ` unable to handle paging request at resume (was: Re: [TuxOnIce-devel] Nigel's current for-rafael queue) Martin Steigerwald
@ 2010-10-02 16:51     ` Martin Steigerwald
  2010-10-02 16:51     ` [linux-pm] " Martin Steigerwald
  1 sibling, 0 replies; 80+ messages in thread
From: Martin Steigerwald @ 2010-10-02 16:51 UTC (permalink / raw)
  To: linux-pm; +Cc: Nigel Cunningham, TuxOnIce-devel, LKML


[-- Attachment #1.1: Type: Text/Plain, Size: 7495 bytes --]

Am Donnerstag 30 September 2010 schrieb Martin Steigerwald:
> Hi Nigel and Rafael,
> 
> Am Dienstag 28 September 2010 schrieb Martin Steigerwald:
> > Am Samstag 25 September 2010 schrieb Nigel Cunningham:
> > > Hi Rafael.
> > > 
> > > Please find attached a slightly updated version of the patchset I
> > > sent a few months ago. The main change is that I've prepended and
> > > additional patch which lets the user see the speed at which the
> > > image is being read and written. This is accomplished by recording
> > > the MB/s in a single byte in the image header, and using a couple
> > > of __nosavedata variables to get the data back through the atomic
> > > restore. I realise the char limits us to 255MB/s at the moment. In
> > > future patches, I intend to address this by storing the data in a
> > > 'proper' image header (it's a real problem - TuxOnIce reads and
> > > writes on the same set up at speeds around 250MB/s).
> > > 
> > > Results on my Dell XPS M1530, which has an SSD hard drive are:
> > > 
> > > With just patch 1 applied:
> > > Attempt 1: Write 74MB/s; Read 52MB/s
> > > Attempt 2: Write 68MB/s; Read 52MB/s
> > > Attempt 3: Write 73MB/s; Read 53MB/s
> > > 
> > > With the whole sequence:
> > > Attempt 1: Write 181MB/s; Read 52MB/s
> > > Attempt 2: Write 156MB/s; Read 53MB/s
> > > Attempt 3: Write 160MB/s; Read 52MB/s
> > 
> > Is doesn't get much stabler than
> > 
> > shambhala:~> grep "PM: Image.*at " /var/log/syslog
> > Sep 28 11:32:06 shambhala kernel: PM: Image written at 63 MB/s.
> > Sep 28 11:32:06 shambhala kernel: PM: Image read at 32 MB/s.
> > Sep 28 11:35:00 shambhala kernel: PM: Image written at 65 MB/s.
> > Sep 28 11:35:00 shambhala kernel: PM: Image read at 32 MB/s.
> > Sep 28 11:38:43 shambhala kernel: PM: Image written at 65 MB/s.
> > Sep 28 11:38:43 shambhala kernel: PM: Image read at 33 MB/s.
> > Sep 28 11:41:15 shambhala kernel: PM: Image written at 66 MB/s.
> > Sep 28 11:41:15 shambhala kernel: PM: Image read at 33 MB/s.
> > Sep 28 11:42:57 shambhala kernel: PM: Image written at 66 MB/s.
> > Sep 28 11:42:57 shambhala kernel: PM: Image read at 34 MB/s.
> > Sep 28 11:45:16 shambhala kernel: PM: Image written at 66 MB/s.
> > Sep 28 11:45:16 shambhala kernel: PM: Image read at 34 MB/s.
> > Sep 28 12:19:21 shambhala kernel: PM: Image written at 66 MB/s.
> > Sep 28 12:19:21 shambhala kernel: PM: Image read at 35 MB/s.
> > Sep 28 12:21:35 shambhala kernel: PM: Image written at 65 MB/s.
> > Sep 28 12:21:35 shambhala kernel: PM: Image read at 35 MB/s.
> > Sep 28 12:23:18 shambhala kernel: PM: Image written at 65 MB/s.
> > Sep 28 12:23:18 shambhala kernel: PM: Image read at 35 MB/s.
> > Sep 28 12:25:23 shambhala kernel: PM: Image written at 64 MB/s.
> > Sep 28 12:25:23 shambhala kernel: PM: Image read at 36 MB/s.
> > Sep 28 12:26:55 shambhala kernel: PM: Image written at 65 MB/s.
> > Sep 28 12:26:55 shambhala kernel: PM: Image read at 37 MB/s.
> > Sep 28 12:28:28 shambhala kernel: PM: Image written at 65 MB/s.
> > Sep 28 12:28:28 shambhala kernel: PM: Image read at 37 MB/s.
> > 
> > many attempts.
> > 
> > So - without readahead patch for now -
> > 
> > Tested-By: Martin Steigerwald <Martin@Lichtvoll.de>
> > 
> > on 2.6.36-rc5.
> 
> Well probably it couldn't get more stable than that, but it was able to
> get more unstable:
> 
> This morning I got a unable to handle paging request after switching on
> my kernel suspended ThinkPad T42. With exactly that kernel with all of
> Nigel's patches except for the readahead one.
> 
> http://martin-steigerwald.de/tmp/suspend-patches/unable-to-handle-pagin
> g- request-at-resume/
> 
> IMG_3897.JPG  is what I saw first. IMG_3900.JPG came after I pressed
> the power button to swich off the machine in order to cold reboot it.
> As I left the machine unattended during resume, I did not see what
> happened before this.
> 
> On the next attempt the laptop just rebootet instead of trying to
> resume from the saved image again.
> 
> I grepped stuff in syslog and found that it seemed to have been able to
> write some stuff into syslog prior to the trace:
> 
> Sep 30 00:00:34 shambhala kernel: PM: Marking nosave pages:
> 000000000009f000 - 0000000000100000
> Sep 30 00:00:34 shambhala kernel: PM: Basic memory bitmaps created
> Sep 30 00:00:34 shambhala kernel: PM: Syncing filesystems ... done.
> Sep 30 09:13:34 shambhala kernel: Freezing user space processes ...
> 00:02:00.0: restoring config space at offset
>  0x1 (was 0x2100107, writing 0x2100007)
> Sep 30 09:13:34 shambhala kernel: yenta_cardbus 0000:02:00.1: restoring
> config space at offset 0xf (was 0x3c0020
> b, writing 0x5c0020b)
> Sep 30 09:13:34 shambhala kernel: yenta_cardbus 0000:02:00.1: restoring
> config space at offset 0x3 (was 0x824008
> , writing 0x82a810)
> Sep 30 09:13:34 shambhala kernel: yenta_cardbus 0000:02:00.1: restoring
> config space at offset 0x1 (was 0x210010
> 7, writing 0x2100007)
> Sep 30 09:13:34 shambhala kernel: e1000 0000:02:01.0: BAR 0: set to
> [mem 0xc0220000-0xc023ffff] (PCI address [0x
> c0220000-0xc023ffff]
> Sep 30 09:13:34 shambhala kernel: e1000 0000:02:01.0: BAR 1: set to
> [mem 0xc0200000-0xc020ffff] (PCI address [0x
> c0200000-0xc020ffff]
> Sep 30 09:13:34 shambhala kernel: e1000 0000:02:01.0: BAR 2: set to [io
> 0x8000-0x803f] (PCI address [0x8000-0x8
> 03f]
> Sep 30 09:13:34 shambhala kernel: e1000 0000:02:01.0: restoring config
> space at offset 0xf (was 0xff0100, writin
> g 0xff010b)
> Sep 30 09:13:34 shambhala kernel: e1000 0000:02:01.0: restoring config
> space at offset 0x3 (was 0x0, writing 0x4
> 008)
> Sep 30 09:13:34 shambhala kernel: e1000 0000:02:01.0: restoring config
> space at offset 0x1 (was 0x2300000, writi
> ng 0x2300117)
> Sep 30 09:13:34 shambhala kernel: PM: early restore of devices complete
> after 31.408 msecs
> Sep 30 09:13:34 shambhala kernel: BUG: Bad page state in process echo
> pfn:73302
> Sep 30 09:13:34 shambhala kernel: page:c24d8040 count:0 mapcount:1
> mapping:(null) index:0x9bf5
> Sep 30 09:13:34 shambhala kernel: page flags:
> 0x80100078(uptodate|dirty| lru|active|swapbacked)
> Sep 30 09:13:34 shambhala kernel: Pid: 18599, comm: echo Not tainted
> 2.6.36-rc5-tp42-hiber-wri-accel-vmembase-0-
> 00133-g3394a84-dirty #1
> Sep 30 09:13:34 shambhala kernel: Call Trace:
> Sep 30 09:13:34 shambhala kernel: [<c10ac8d3>] bad_page+0x83/0xd0
> Sep 30 09:13:34 shambhala kernel: [<c10ad541>]
> free_pages_prepare+0x131/0x170
> Sep 30 09:13:34 shambhala kernel: [<c10aef98>]
> free_hot_cold_page+0x28/0x140
> Sep 30 09:13:34 shambhala kernel: [<c10af0e5>] __free_pages+0x35/0x40
> Sep 30 09:13:34 shambhala kernel: [<c10727e6>] swsusp_free+0xa6/0x100
> Sep 30 09:13:34 shambhala kernel: [<c10719f3>]
> hibernation_snapshot+0x123/0x290
> Sep 30 09:13:34 shambhala kernel: [<c1070b76>] ?
> freeze_processes+0x56/0xa0
> Sep 30 09:13:34 shambhala kernel: [<c1071c45>] hibernate+0xe5/0x210
> Sep 30 09:13:34 shambhala kernel: [<c10704f0>] ? state_store+0x0/0xb0
> Sep 30 09:13:34 shambhala kernel: [<c1070596>] state_store+0xa6/0xb0
> Sep 30 09:13:34 shambhala kernSep 30 09:25:08 shambhala kernel: imklog
> 4.6.4, log source = /proc/kmsg started.

I didn't see this one again so far.

Still I wonder what that might have been. Any hints?

Ciao,
-- 
Martin 'Helios' Steigerwald - http://www.Lichtvoll.de
GPG: 03B0 0D6C 0040 0710 4AFA  B82F 991B EAAC A599 84C7

[-- Attachment #1.2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

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



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

end of thread, other threads:[~2010-10-02 16:51 UTC | newest]

Thread overview: 80+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-09-25  4:16 Nigel's current for-rafael queue Nigel Cunningham
2010-09-25  4:16 ` [PATCH 01/22] Record & display i/o speed post resume Nigel Cunningham
2010-09-25  4:16 ` Nigel Cunningham
2010-09-25  4:16 ` [PATCH 02/22] Hibernation: Swap iteration functions Nigel Cunningham
2010-09-25  4:16 ` Nigel Cunningham
2010-09-25  4:16 ` [PATCH 03/22] Hibernation: Move root_swap declaration Nigel Cunningham
2010-09-25  4:16 ` Nigel Cunningham
2010-09-25  4:16 ` [PATCH 04/22] Hibernation: Add mass swap allocation routine Nigel Cunningham
2010-09-25  4:16 ` Nigel Cunningham
2010-09-25  4:16 ` Nigel Cunningham
2010-09-25  4:16 ` [PATCH 05/22] Hibernation: Switch to preallocating swap Nigel Cunningham
2010-09-25 21:24   ` Rafael J. Wysocki
2010-09-25 21:32     ` Nigel Cunningham
2010-09-25 21:32     ` Nigel Cunningham
2010-09-25 22:22       ` Rafael J. Wysocki
2010-09-25 22:22       ` Rafael J. Wysocki
2010-09-25 21:24   ` Rafael J. Wysocki
2010-09-25 21:24   ` Rafael J. Wysocki
2010-09-25  4:16 ` Nigel Cunningham
2010-09-25  4:16 ` [PATCH 06/22] Hiberation: Fix speed display Nigel Cunningham
2010-09-25  4:16 ` Nigel Cunningham
2010-09-25  4:16 ` [PATCH 07/22] Hibernation: Generic extents support Nigel Cunningham
2010-09-25  4:16 ` Nigel Cunningham
2010-09-25  4:16 ` Nigel Cunningham
2010-09-25  4:16 ` [PATCH 08/22] Hibernation: Iterate over sectors not swap entries Nigel Cunningham
2010-09-25  4:16 ` Nigel Cunningham
2010-09-25  4:16 ` [PATCH 09/22] Hibernation: Stop passing swap_map_handle struct Nigel Cunningham
2010-09-25  4:16 ` Nigel Cunningham
2010-09-25  4:16 ` [PATCH 10/22] Hibernation: Stop passing bio_chain around Nigel Cunningham
2010-09-25  4:16 ` Nigel Cunningham
2010-09-25  4:16 ` [PATCH 11/22] Hibernation: Move block i/o fns to block_io.c Nigel Cunningham
2010-09-25  4:16 ` Nigel Cunningham
2010-09-25  4:16 ` [PATCH 12/22] Hibernation: Partial page I/O support Nigel Cunningham
2010-09-25  4:16 ` Nigel Cunningham
2010-09-25  4:16 ` Nigel Cunningham
2010-09-25  4:16 ` [PATCH 13/22] Hibernation: Extent save/load routines Nigel Cunningham
2010-09-25 22:12   ` Rafael J. Wysocki
2010-09-25 22:12   ` Rafael J. Wysocki
2010-09-25  4:16 ` Nigel Cunningham
2010-09-25  4:16 ` [PATCH 14/22] Hibernation: Store block extents at start of image Nigel Cunningham
2010-09-25  4:16 ` Nigel Cunningham
2010-09-25  4:16 ` [PATCH 15/22] Hibernation: Use block extents for reading image Nigel Cunningham
2010-09-25  4:16 ` Nigel Cunningham
2010-09-25  4:16 ` [PATCH 16/22] Remove first_sector from swap_map_handle Nigel Cunningham
2010-09-25  4:16 ` Nigel Cunningham
2010-09-25  4:16 ` [PATCH 17/22] Hibernation: Replace bio chain Nigel Cunningham
2010-09-25  4:16 ` Nigel Cunningham
2010-09-25  4:17 ` [PATCH 18/22] Hibernation: Remove swap_map_pages Nigel Cunningham
2010-09-25  4:17 ` Nigel Cunningham
2010-09-25  4:17 ` [PATCH 19/22] Hibernation: Remove wait_on_bio_chain result Nigel Cunningham
2010-09-25  4:17 ` Nigel Cunningham
2010-09-25  4:17 ` [PATCH 20/22] Hibernation: Prepare for handle.cur removal Nigel Cunningham
2010-09-25  4:17 ` Nigel Cunningham
2010-09-25  4:17 ` [PATCH 21/22] Hibernation: Remove swap_map structure Nigel Cunningham
2010-09-25  4:17 ` Nigel Cunningham
2010-09-25  4:17 ` [PATCH 22/22] Hibernation: Remove now-empty routines Nigel Cunningham
2010-09-25  4:17 ` Nigel Cunningham
2010-09-25 15:04 ` [linux-pm] Nigel's current for-rafael queue Martin Steigerwald
2010-09-25 21:21   ` Nigel Cunningham
2010-09-25 21:21   ` Nigel Cunningham
2010-09-25 15:04 ` Martin Steigerwald
2010-09-25 15:04 ` Martin Steigerwald
2010-09-25 22:19 ` Rafael J. Wysocki
2010-09-25 22:19 ` Rafael J. Wysocki
2010-09-25 22:33   ` Nigel Cunningham
2010-09-25 22:33   ` Nigel Cunningham
2010-09-25 22:36     ` Rafael J. Wysocki
2010-09-25 22:36     ` Rafael J. Wysocki
2010-09-28 10:34 ` [TuxOnIce-devel] " Martin Steigerwald
2010-09-28 10:34 ` Martin Steigerwald
2010-09-30  7:52   ` unable to handle paging request at resume (was: Re: [TuxOnIce-devel] Nigel's current for-rafael queue) Martin Steigerwald
2010-10-02 16:51     ` Martin Steigerwald
2010-10-02 16:51     ` [linux-pm] " Martin Steigerwald
2010-09-30  7:52   ` Martin Steigerwald
2010-09-28 19:45 ` [TuxOnIce-devel] Nigel's current for-rafael queue Martin Steigerwald
2010-09-28 19:45 ` Martin Steigerwald
2010-09-28 21:25   ` Nigel Cunningham
2010-09-28 21:25   ` Nigel Cunningham
2010-09-30  7:56     ` Martin Steigerwald
2010-09-30  7:56     ` Martin Steigerwald

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.