All of lore.kernel.org
 help / color / mirror / Atom feed
* Nigel's current for-rafael queue
@ 2010-06-02 12:18 Nigel Cunningham
  2010-06-02 12:19 ` [PATCH 01/21] Hibernation: Swap iteration functions Nigel Cunningham
                   ` (43 more replies)
  0 siblings, 44 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:18 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Hi all.

Here is my current patch queue.

Taken together, the patches implement the separation of low level
block i/o into a separate file, switch from using swap_map_pages
to extents stores prior to the 'header' page and implement fully
asynchronous (rather than batched I/O). I have only run it under
VMware so far, but would estimate a doubling in speed due to the
async i/o.

Looking at Jiri's patches, there is definitely some overlap, but
more in terms of lines in the code than direction of effort (with
the exception of separating swap out). He has covered areas for
improvement that I was going to do, just not yet.

Jiri, unless you object, I'm going to seek to apply your patches
on top of what I've done. Does that sound okay?

Nigel


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

* [PATCH 01/21] Hibernation: Swap iteration functions.
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
  2010-06-02 12:19 ` [PATCH 01/21] Hibernation: Swap iteration functions Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-06-02 12:19 ` [PATCH 02/21] Hibernation: Move root_swap declaration Nigel Cunningham
                   ` (41 subsequent siblings)
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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 b0bb217..829f7b4 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -86,6 +86,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] 60+ messages in thread

* [PATCH 01/21] Hibernation: Swap iteration functions.
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-06-02 12:19 ` Nigel Cunningham
                   ` (42 subsequent siblings)
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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 b0bb217..829f7b4 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -86,6 +86,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] 60+ messages in thread

* [PATCH 02/21] Hibernation: Move root_swap declaration.
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
                   ` (2 preceding siblings ...)
  2010-06-02 12:19 ` [PATCH 02/21] Hibernation: Move root_swap declaration Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-06-02 12:19 ` [PATCH 03/21] Hibernation: Add mass swap allocation routine Nigel Cunningham
                   ` (39 subsequent siblings)
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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 829f7b4..e555b6c 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 - 20 - sizeof(sector_t) - sizeof(int)];
 	sector_t image;
@@ -217,7 +219,6 @@ int swsusp_swap_in_use(void)
  * General things
  */
 
-static unsigned short root_swap = 0xffff;
 struct block_device *hib_resume_bdev;
 
 /*
-- 
1.7.0.4


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

* [PATCH 02/21] Hibernation: Move root_swap declaration.
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
  2010-06-02 12:19 ` [PATCH 01/21] Hibernation: Swap iteration functions Nigel Cunningham
  2010-06-02 12:19 ` Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-06-02 12:19 ` Nigel Cunningham
                   ` (40 subsequent siblings)
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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 829f7b4..e555b6c 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 - 20 - sizeof(sector_t) - sizeof(int)];
 	sector_t image;
@@ -217,7 +219,6 @@ int swsusp_swap_in_use(void)
  * General things
  */
 
-static unsigned short root_swap = 0xffff;
 struct block_device *hib_resume_bdev;
 
 /*
-- 
1.7.0.4

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

* [PATCH 03/21] Hibernation: Add mass swap allocation routine
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
                   ` (3 preceding siblings ...)
  2010-06-02 12:19 ` Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-06-02 12:19 ` Nigel Cunningham
                   ` (38 subsequent siblings)
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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 e555b6c..550c1ed 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -187,6 +187,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 entres had been
-- 
1.7.0.4


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

* [PATCH 03/21] Hibernation: Add mass swap allocation routine
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
                   ` (4 preceding siblings ...)
  2010-06-02 12:19 ` [PATCH 03/21] Hibernation: Add mass swap allocation routine Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-06-02 12:19 ` [PATCH 04/21] Hibernation: Switch to preallocating swap Nigel Cunningham
                   ` (37 subsequent siblings)
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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 e555b6c..550c1ed 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -187,6 +187,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 entres had been
-- 
1.7.0.4

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

* [PATCH 04/21] Hibernation: Switch to preallocating swap.
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
                   ` (6 preceding siblings ...)
  2010-06-02 12:19 ` [PATCH 04/21] Hibernation: Switch to preallocating swap Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-06-02 12:19 ` [PATCH 05/21] Hiberation: Fix speed display Nigel Cunningham
                   ` (35 subsequent siblings)
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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 550c1ed..ff2fc15 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -201,6 +201,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 entres had been
  *	allocated.
@@ -321,7 +348,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;
 
@@ -337,7 +364,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;
@@ -360,7 +392,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;
@@ -369,7 +401,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;
@@ -458,21 +490,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
  *
@@ -491,16 +508,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] 60+ messages in thread

* [PATCH 04/21] Hibernation: Switch to preallocating swap.
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
                   ` (5 preceding siblings ...)
  2010-06-02 12:19 ` Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-06-02 12:19 ` Nigel Cunningham
                   ` (36 subsequent siblings)
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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 550c1ed..ff2fc15 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -201,6 +201,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 entres had been
  *	allocated.
@@ -321,7 +348,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;
 
@@ -337,7 +364,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;
@@ -360,7 +392,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;
@@ -369,7 +401,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;
@@ -458,21 +490,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
  *
@@ -491,16 +508,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] 60+ messages in thread

* [PATCH 05/21] Hiberation: Fix speed display.
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
                   ` (7 preceding siblings ...)
  2010-06-02 12:19 ` Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-06-02 12:19 ` Nigel Cunningham
                   ` (34 subsequent siblings)
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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 ff2fc15..1e6e5b6 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -485,7 +485,7 @@ 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");
+	swsusp_show_speed(&start, &stop, nr_pages, "Wrote");
 	return ret;
 }
 
-- 
1.7.0.4


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

* [PATCH 05/21] Hiberation: Fix speed display.
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
                   ` (8 preceding siblings ...)
  2010-06-02 12:19 ` [PATCH 05/21] Hiberation: Fix speed display Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-06-02 12:19 ` [PATCH 06/21] Hibernation: Generic extents support Nigel Cunningham
                   ` (33 subsequent siblings)
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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 ff2fc15..1e6e5b6 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -485,7 +485,7 @@ 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");
+	swsusp_show_speed(&start, &stop, nr_pages, "Wrote");
 	return ret;
 }
 
-- 
1.7.0.4

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

* [PATCH 06/21] Hibernation: Generic extents support.
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
                   ` (10 preceding siblings ...)
  2010-06-02 12:19 ` [PATCH 06/21] Hibernation: Generic extents support Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-06-02 12:19 ` [PATCH 07/21] Hibernation: Iterate over sectors not swap entries Nigel Cunningham
                   ` (31 subsequent siblings)
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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 524e058..eac3541 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_HIBERNATION_NVS)	+= hibernate_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 1e6e5b6..15cbe70 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"
 
@@ -75,97 +75,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;
 }
 
 /**
@@ -179,7 +96,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);
@@ -223,7 +140,7 @@ static int allocate_swap(unsigned int nr_pages)
 		return 0;
 	}
 
-	reset_storage_pos();
+	hib_reset_extent_pos(&swap_extents);
 	return 1;
 }
 
@@ -235,24 +152,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] 60+ messages in thread

* [PATCH 06/21] Hibernation: Generic extents support.
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
                   ` (9 preceding siblings ...)
  2010-06-02 12:19 ` Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-06-02 12:19 ` Nigel Cunningham
                   ` (32 subsequent siblings)
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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 524e058..eac3541 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_HIBERNATION_NVS)	+= hibernate_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 1e6e5b6..15cbe70 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"
 
@@ -75,97 +75,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;
 }
 
 /**
@@ -179,7 +96,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);
@@ -223,7 +140,7 @@ static int allocate_swap(unsigned int nr_pages)
 		return 0;
 	}
 
-	reset_storage_pos();
+	hib_reset_extent_pos(&swap_extents);
 	return 1;
 }
 
@@ -235,24 +152,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] 60+ messages in thread

* [PATCH 07/21] Hibernation: Iterate over sectors not swap entries.
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
                   ` (11 preceding siblings ...)
  2010-06-02 12:19 ` Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-06-02 12:19 ` Nigel Cunningham
                   ` (30 subsequent siblings)
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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 15cbe70..d87f663 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -76,14 +76,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
@@ -92,14 +85,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;
 }
@@ -140,7 +135,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;
 }
 
@@ -280,7 +275,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;
@@ -303,7 +298,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;
@@ -312,7 +307,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] 60+ messages in thread

* [PATCH 07/21] Hibernation: Iterate over sectors not swap entries.
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
                   ` (12 preceding siblings ...)
  2010-06-02 12:19 ` [PATCH 07/21] Hibernation: Iterate over sectors not swap entries Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-06-02 12:19 ` [PATCH 08/21] Hibernation: Stop passing swap_map_handle struct Nigel Cunningham
                   ` (29 subsequent siblings)
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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 15cbe70..d87f663 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -76,14 +76,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
@@ -92,14 +85,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;
 }
@@ -140,7 +135,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;
 }
 
@@ -280,7 +275,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;
@@ -303,7 +298,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;
@@ -312,7 +307,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] 60+ messages in thread

* [PATCH 08/21] Hibernation: Stop passing swap_map_handle struct
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
                   ` (14 preceding siblings ...)
  2010-06-02 12:19 ` [PATCH 08/21] Hibernation: Stop passing swap_map_handle struct Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-06-02 12:19 ` [PATCH 09/21] Hibernation: Stop passing bio_chain around Nigel Cunningham
                   ` (27 subsequent siblings)
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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 d87f663..a038755 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 {
@@ -171,7 +173,7 @@ struct block_device *hib_resume_bdev;
  * Saving part
  */
 
-static int mark_swapfiles(struct swap_map_handle *handle, unsigned int flags)
+static int mark_swapfiles(unsigned int flags)
 {
 	int error;
 
@@ -180,7 +182,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->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);
@@ -247,14 +249,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;
 
@@ -265,8 +267,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;
 	}
@@ -275,74 +277,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;
@@ -352,8 +352,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;
@@ -376,7 +375,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))
@@ -407,14 +406,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;
@@ -428,11 +426,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;
 }
 
@@ -441,15 +439,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;
 
@@ -458,48 +455,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;
 }
@@ -510,9 +506,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;
@@ -534,7 +528,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)
@@ -569,7 +563,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;
 
@@ -578,14 +571,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] 60+ messages in thread

* [PATCH 08/21] Hibernation: Stop passing swap_map_handle struct
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
                   ` (13 preceding siblings ...)
  2010-06-02 12:19 ` Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-06-02 12:19 ` Nigel Cunningham
                   ` (28 subsequent siblings)
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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 d87f663..a038755 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 {
@@ -171,7 +173,7 @@ struct block_device *hib_resume_bdev;
  * Saving part
  */
 
-static int mark_swapfiles(struct swap_map_handle *handle, unsigned int flags)
+static int mark_swapfiles(unsigned int flags)
 {
 	int error;
 
@@ -180,7 +182,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->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);
@@ -247,14 +249,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;
 
@@ -265,8 +267,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;
 	}
@@ -275,74 +277,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;
@@ -352,8 +352,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;
@@ -376,7 +375,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))
@@ -407,14 +406,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;
@@ -428,11 +426,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;
 }
 
@@ -441,15 +439,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;
 
@@ -458,48 +455,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;
 }
@@ -510,9 +506,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;
@@ -534,7 +528,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)
@@ -569,7 +563,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;
 
@@ -578,14 +571,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] 60+ messages in thread

* [PATCH 09/21] Hibernation: Stop passing bio_chain around
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
                   ` (15 preceding siblings ...)
  2010-06-02 12:19 ` Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-06-02 12:19 ` Nigel Cunningham
                   ` (26 subsequent siblings)
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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 97024fd..c353d64 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 | (1 << BIO_RW_SYNCIO) | (1 << BIO_RW_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 006270f..9a046cd 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -145,11 +145,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 a038755..45f89dc 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -177,7 +177,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);
@@ -185,7 +185,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;
@@ -224,29 +224,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)
@@ -292,7 +292,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;
@@ -300,19 +300,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);
@@ -326,7 +326,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;
 }
@@ -359,7 +359,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;
 
@@ -369,20 +368,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;
@@ -426,7 +424,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:
@@ -459,7 +457,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;
@@ -468,7 +466,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;
@@ -478,17 +476,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;
 }
@@ -512,7 +510,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;
 
@@ -522,24 +519,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;
@@ -575,7 +571,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();
@@ -600,7 +596,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;
 
@@ -608,7 +604,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] 60+ messages in thread

* [PATCH 09/21] Hibernation: Stop passing bio_chain around
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
                   ` (16 preceding siblings ...)
  2010-06-02 12:19 ` [PATCH 09/21] Hibernation: Stop passing bio_chain around Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-06-02 12:19 ` [PATCH 10/21] Hibernation: Move block i/o fns to block_io.c Nigel Cunningham
                   ` (25 subsequent siblings)
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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 97024fd..c353d64 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 | (1 << BIO_RW_SYNCIO) | (1 << BIO_RW_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 006270f..9a046cd 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -145,11 +145,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 a038755..45f89dc 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -177,7 +177,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);
@@ -185,7 +185,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;
@@ -224,29 +224,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)
@@ -292,7 +292,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;
@@ -300,19 +300,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);
@@ -326,7 +326,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;
 }
@@ -359,7 +359,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;
 
@@ -369,20 +368,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;
@@ -426,7 +424,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:
@@ -459,7 +457,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;
@@ -468,7 +466,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;
@@ -478,17 +476,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;
 }
@@ -512,7 +510,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;
 
@@ -522,24 +519,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;
@@ -575,7 +571,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();
@@ -600,7 +596,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;
 
@@ -608,7 +604,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] 60+ messages in thread

* [PATCH 10/21] Hibernation: Move block i/o fns to block_io.c
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
                   ` (18 preceding siblings ...)
  2010-06-02 12:19 ` [PATCH 10/21] Hibernation: Move block i/o fns to block_io.c Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-06-02 12:19 ` [PATCH 11/21] Hibernation: Partial page I/O support Nigel Cunningham
                   ` (23 subsequent siblings)
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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 c353d64..c449db2 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 45f89dc..b4ab6a2 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_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;
-
 static unsigned short root_swap = 0xffff;
 
 struct swsusp_header {
@@ -78,7 +43,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
@@ -126,7 +91,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)
@@ -182,7 +147,7 @@ static int mark_swapfiles(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->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);
@@ -220,42 +185,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;
@@ -267,70 +196,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) {
@@ -432,65 +310,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();
@@ -567,7 +386,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] 60+ messages in thread

* [PATCH 10/21] Hibernation: Move block i/o fns to block_io.c
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
                   ` (17 preceding siblings ...)
  2010-06-02 12:19 ` Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-06-02 12:19 ` Nigel Cunningham
                   ` (24 subsequent siblings)
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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 c353d64..c449db2 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 45f89dc..b4ab6a2 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_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;
-
 static unsigned short root_swap = 0xffff;
 
 struct swsusp_header {
@@ -78,7 +43,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
@@ -126,7 +91,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)
@@ -182,7 +147,7 @@ static int mark_swapfiles(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->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);
@@ -220,42 +185,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;
@@ -267,70 +196,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) {
@@ -432,65 +310,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();
@@ -567,7 +386,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] 60+ messages in thread

* [PATCH 11/21] Hibernation: Partial page I/O support.
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
                   ` (19 preceding siblings ...)
  2010-06-02 12:19 ` Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-06-02 12:19 ` Nigel Cunningham
                   ` (22 subsequent siblings)
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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 c449db2..0e57776 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] 60+ messages in thread

* [PATCH 11/21] Hibernation: Partial page I/O support.
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
                   ` (20 preceding siblings ...)
  2010-06-02 12:19 ` [PATCH 11/21] Hibernation: Partial page I/O support Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-06-02 12:19 ` [PATCH 12/21] Hibernation: Extent save/load routines Nigel Cunningham
                   ` (21 subsequent siblings)
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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 c449db2..0e57776 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] 60+ messages in thread

* [PATCH 12/21] Hibernation: Extent save/load routines.
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
                   ` (22 preceding siblings ...)
  2010-06-02 12:19 ` [PATCH 12/21] Hibernation: Extent save/load routines Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-06-02 12:19 ` [PATCH 13/21] Hibernation: Store block extents at start of image Nigel Cunningham
                   ` (19 subsequent siblings)
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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] 60+ messages in thread

* [PATCH 12/21] Hibernation: Extent save/load routines.
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
                   ` (21 preceding siblings ...)
  2010-06-02 12:19 ` Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-06-02 12:19 ` Nigel Cunningham
                   ` (20 subsequent siblings)
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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] 60+ messages in thread

* [PATCH 13/21] Hibernation: Store block extents at start of image
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
                   ` (23 preceding siblings ...)
  2010-06-02 12:19 ` Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-06-02 12:19 ` Nigel Cunningham
                   ` (18 subsequent siblings)
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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 0e57776..7fabb0c 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] 60+ messages in thread

* [PATCH 13/21] Hibernation: Store block extents at start of image
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
                   ` (24 preceding siblings ...)
  2010-06-02 12:19 ` [PATCH 13/21] Hibernation: Store block extents at start of image Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-06-02 12:19 ` [PATCH 14/21] Hibernation: Use block extents for reading image Nigel Cunningham
                   ` (17 subsequent siblings)
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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 0e57776..7fabb0c 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] 60+ messages in thread

* [PATCH 14/21] Hibernation: Use block extents for reading image
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
                   ` (26 preceding siblings ...)
  2010-06-02 12:19 ` [PATCH 14/21] Hibernation: Use block extents for reading image Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-06-02 12:19 ` [PATCH 15/21] Remove first_sector from swap_map_handle Nigel Cunningham
                   ` (15 subsequent siblings)
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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 7fabb0c..6745e77 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] 60+ messages in thread

* [PATCH 14/21] Hibernation: Use block extents for reading image
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
                   ` (25 preceding siblings ...)
  2010-06-02 12:19 ` Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-06-02 12:19 ` Nigel Cunningham
                   ` (16 subsequent siblings)
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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 7fabb0c..6745e77 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] 60+ messages in thread

* [PATCH 15/21] Remove first_sector from swap_map_handle
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
                   ` (28 preceding siblings ...)
  2010-06-02 12:19 ` [PATCH 15/21] Remove first_sector from swap_map_handle Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-06-02 12:19 ` [PATCH 16/21] Hibernation: Replace bio chain Nigel Cunningham
                   ` (13 subsequent siblings)
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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 6745e77..9028f74 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] 60+ messages in thread

* [PATCH 15/21] Remove first_sector from swap_map_handle
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
                   ` (27 preceding siblings ...)
  2010-06-02 12:19 ` Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-06-02 12:19 ` Nigel Cunningham
                   ` (14 subsequent siblings)
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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 6745e77..9028f74 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] 60+ messages in thread

* [PATCH 16/21] Hibernation: Replace bio chain
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
                   ` (30 preceding siblings ...)
  2010-06-02 12:19 ` [PATCH 16/21] Hibernation: Replace bio chain Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-06-02 12:19 ` [PATCH 17/21] Hibernation: Remove swap_map_pages Nigel Cunningham
                   ` (11 subsequent siblings)
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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 9028f74..c9569e5 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] 60+ messages in thread

* [PATCH 16/21] Hibernation: Replace bio chain
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
                   ` (29 preceding siblings ...)
  2010-06-02 12:19 ` Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-06-02 12:19 ` Nigel Cunningham
                   ` (12 subsequent siblings)
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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 9028f74..c9569e5 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] 60+ messages in thread

* [PATCH 17/21] Hibernation: Remove swap_map_pages
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
                   ` (31 preceding siblings ...)
  2010-06-02 12:19 ` Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-06-02 12:19 ` Nigel Cunningham
                   ` (10 subsequent siblings)
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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 c9569e5..66cdc5a 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] 60+ messages in thread

* [PATCH 17/21] Hibernation: Remove swap_map_pages
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
                   ` (32 preceding siblings ...)
  2010-06-02 12:19 ` [PATCH 17/21] Hibernation: Remove swap_map_pages Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-06-02 12:19 ` [PATCH 18/21] Hibernation: Remove wait_on_bio_chain result Nigel Cunningham
                   ` (9 subsequent siblings)
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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 c9569e5..66cdc5a 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] 60+ messages in thread

* [PATCH 18/21] Hibernation: Remove wait_on_bio_chain result
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
                   ` (34 preceding siblings ...)
  2010-06-02 12:19 ` [PATCH 18/21] Hibernation: Remove wait_on_bio_chain result Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-06-02 12:19 ` [PATCH 19/21] Hibernation: Prepare for handle.cur removal Nigel Cunningham
                   ` (7 subsequent siblings)
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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 66cdc5a..c71c7c3 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 9a046cd..4c21388 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -147,7 +147,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 b4ab6a2..e477310 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -236,7 +236,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;
 
@@ -258,11 +257,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");
@@ -329,7 +326,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;
 
 	printk(KERN_INFO "PM: Loading image data pages (%u pages) ...     ",
@@ -347,17 +343,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] 60+ messages in thread

* [PATCH 18/21] Hibernation: Remove wait_on_bio_chain result
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
                   ` (33 preceding siblings ...)
  2010-06-02 12:19 ` Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-06-02 12:19 ` Nigel Cunningham
                   ` (8 subsequent siblings)
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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 66cdc5a..c71c7c3 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 9a046cd..4c21388 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -147,7 +147,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 b4ab6a2..e477310 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -236,7 +236,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;
 
@@ -258,11 +257,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");
@@ -329,7 +326,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;
 
 	printk(KERN_INFO "PM: Loading image data pages (%u pages) ...     ",
@@ -347,17 +343,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] 60+ messages in thread

* [PATCH 19/21] Hibernation: Prepare for handle.cur removal
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
                   ` (35 preceding siblings ...)
  2010-06-02 12:19 ` Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-06-02 12:19 ` Nigel Cunningham
                   ` (6 subsequent siblings)
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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 c71c7c3..dd71ef2 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] 60+ messages in thread

* [PATCH 19/21] Hibernation: Prepare for handle.cur removal
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
                   ` (36 preceding siblings ...)
  2010-06-02 12:19 ` [PATCH 19/21] Hibernation: Prepare for handle.cur removal Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-06-02 12:19 ` [PATCH 20/21] Hibernation: Remove swap_map structure Nigel Cunningham
                   ` (5 subsequent siblings)
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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 c71c7c3..dd71ef2 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] 60+ messages in thread

* [PATCH 20/21] Hibernation: Remove swap_map structure
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
                   ` (37 preceding siblings ...)
  2010-06-02 12:19 ` Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-06-02 12:19 ` Nigel Cunningham
                   ` (4 subsequent siblings)
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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 dd71ef2..5c791c0 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] 60+ messages in thread

* [PATCH 20/21] Hibernation: Remove swap_map structure
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
                   ` (38 preceding siblings ...)
  2010-06-02 12:19 ` [PATCH 20/21] Hibernation: Remove swap_map structure Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-06-02 12:19 ` [PATCH 21/21] Hibernation: Remove now-empty routines Nigel Cunningham
                   ` (3 subsequent siblings)
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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 dd71ef2..5c791c0 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] 60+ messages in thread

* [PATCH 21/21] Hibernation: Remove now-empty routines.
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
                   ` (39 preceding siblings ...)
  2010-06-02 12:19 ` Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-06-02 12:19 ` Nigel Cunningham
                   ` (2 subsequent siblings)
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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 5c791c0..d02013a 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 e477310..8763baa 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -220,7 +220,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;
@@ -307,13 +306,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
@@ -390,7 +382,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] 60+ messages in thread

* [PATCH 21/21] Hibernation: Remove now-empty routines.
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
                   ` (40 preceding siblings ...)
  2010-06-02 12:19 ` [PATCH 21/21] Hibernation: Remove now-empty routines Nigel Cunningham
@ 2010-06-02 12:19 ` Nigel Cunningham
  2010-08-03  6:55 ` Nigel's current for-rafael queue Pavel Machek
  2010-08-03  6:55 ` Pavel Machek
  43 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:19 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 5c791c0..d02013a 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 e477310..8763baa 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -220,7 +220,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;
@@ -307,13 +306,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
@@ -390,7 +382,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] 60+ messages in thread

* Re: Nigel's current for-rafael queue
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
                   ` (42 preceding siblings ...)
  2010-08-03  6:55 ` Nigel's current for-rafael queue Pavel Machek
@ 2010-08-03  6:55 ` Pavel Machek
  2010-08-03  7:00   ` Nigel Cunningham
  2010-08-03  7:00   ` Nigel Cunningham
  43 siblings, 2 replies; 60+ messages in thread
From: Pavel Machek @ 2010-08-03  6:55 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

On Wed 2010-06-02 22:18:59, Nigel Cunningham wrote:
> Hi all.
> 
> Here is my current patch queue.
> 
> Taken together, the patches implement the separation of low level
> block i/o into a separate file, switch from using swap_map_pages
> to extents stores prior to the 'header' page and implement fully
> asynchronous (rather than batched I/O). I have only run it under
> VMware so far, but would estimate a doubling in speed due to the
> async i/o.

Do you have any numbers from real hw? Could similar speedup be
accomplished by just increasing the batch size?
							Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

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

* Re: Nigel's current for-rafael queue
  2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
                   ` (41 preceding siblings ...)
  2010-06-02 12:19 ` Nigel Cunningham
@ 2010-08-03  6:55 ` Pavel Machek
  2010-08-03  6:55 ` Pavel Machek
  43 siblings, 0 replies; 60+ messages in thread
From: Pavel Machek @ 2010-08-03  6:55 UTC (permalink / raw)
  To: Nigel Cunningham; +Cc: Linux PM, LKML, TuxOnIce-devel

On Wed 2010-06-02 22:18:59, Nigel Cunningham wrote:
> Hi all.
> 
> Here is my current patch queue.
> 
> Taken together, the patches implement the separation of low level
> block i/o into a separate file, switch from using swap_map_pages
> to extents stores prior to the 'header' page and implement fully
> asynchronous (rather than batched I/O). I have only run it under
> VMware so far, but would estimate a doubling in speed due to the
> async i/o.

Do you have any numbers from real hw? Could similar speedup be
accomplished by just increasing the batch size?
							Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

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

* Re: Nigel's current for-rafael queue
  2010-08-03  6:55 ` Pavel Machek
  2010-08-03  7:00   ` Nigel Cunningham
@ 2010-08-03  7:00   ` Nigel Cunningham
  1 sibling, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-08-03  7:00 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Hi.

On 03/08/10 16:55, Pavel Machek wrote:
> On Wed 2010-06-02 22:18:59, Nigel Cunningham wrote:
>> Hi all.
>>
>> Here is my current patch queue.
>>
>> Taken together, the patches implement the separation of low level
>> block i/o into a separate file, switch from using swap_map_pages
>> to extents stores prior to the 'header' page and implement fully
>> asynchronous (rather than batched I/O). I have only run it under
>> VMware so far, but would estimate a doubling in speed due to the
>> async i/o.
>
> Do you have any numbers from real hw? Could similar speedup be
> accomplished by just increasing the batch size?

Yeah. I've been thinking I should really prepend a patch that lets you 
get the stats post-resume - unless you guys have some trick to enable 
you to read them that I haven't noticed yet :)

Nigel

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

* Re: Nigel's current for-rafael queue
  2010-08-03  6:55 ` Pavel Machek
@ 2010-08-03  7:00   ` Nigel Cunningham
  2010-08-03  7:00   ` Nigel Cunningham
  1 sibling, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-08-03  7:00 UTC (permalink / raw)
  To: Pavel Machek; +Cc: Linux PM, LKML, TuxOnIce-devel

Hi.

On 03/08/10 16:55, Pavel Machek wrote:
> On Wed 2010-06-02 22:18:59, Nigel Cunningham wrote:
>> Hi all.
>>
>> Here is my current patch queue.
>>
>> Taken together, the patches implement the separation of low level
>> block i/o into a separate file, switch from using swap_map_pages
>> to extents stores prior to the 'header' page and implement fully
>> asynchronous (rather than batched I/O). I have only run it under
>> VMware so far, but would estimate a doubling in speed due to the
>> async i/o.
>
> Do you have any numbers from real hw? Could similar speedup be
> accomplished by just increasing the batch size?

Yeah. I've been thinking I should really prepend a patch that lets you 
get the stats post-resume - unless you guys have some trick to enable 
you to read them that I haven't noticed yet :)

Nigel

^ permalink raw reply	[flat|nested] 60+ 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; 60+ 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] 60+ 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; 60+ 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] 60+ 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; 60+ 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] 60+ 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; 60+ 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] 60+ messages in thread

* Re: Nigel's current for-rafael queue
  2010-09-25  4:16 Nigel Cunningham
                   ` (2 preceding siblings ...)
  2010-09-25 15:04 ` [linux-pm] " Martin Steigerwald
@ 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:19 ` Rafael J. Wysocki
  4 siblings, 2 replies; 60+ 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] 60+ messages in thread

* Re: Nigel's current for-rafael queue
  2010-09-25  4:16 Nigel Cunningham
                   ` (3 preceding siblings ...)
  2010-09-25 22:19 ` Rafael J. Wysocki
@ 2010-09-25 22:19 ` Rafael J. Wysocki
  4 siblings, 0 replies; 60+ 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] 60+ messages in thread

* Re: Nigel's current for-rafael queue
  2010-09-25 15:04 ` [linux-pm] " Martin Steigerwald
@ 2010-09-25 21:21   ` Nigel Cunningham
  0 siblings, 0 replies; 60+ 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] 60+ messages in thread

* Re: Nigel's current for-rafael queue
  2010-09-25  4:16 Nigel Cunningham
@ 2010-09-25 15:04 ` Martin Steigerwald
  2010-09-25 15:04 ` Martin Steigerwald
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 60+ 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] 60+ messages in thread

* Re: Nigel's current for-rafael queue
  2010-09-25  4:16 Nigel Cunningham
  2010-09-25 15:04 ` Martin Steigerwald
@ 2010-09-25 15:04 ` Martin Steigerwald
  2010-09-25 15:04 ` [linux-pm] " Martin Steigerwald
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 60+ 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] 60+ messages in thread

* Nigel's current for-rafael queue
@ 2010-09-25  4:16 Nigel Cunningham
  2010-09-25 15:04 ` Martin Steigerwald
                   ` (4 more replies)
  0 siblings, 5 replies; 60+ 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] 60+ messages in thread

* Nigel's current for-rafael queue
@ 2010-09-25  4:16 Nigel Cunningham
  0 siblings, 0 replies; 60+ 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] 60+ messages in thread

* Nigel's current for-rafael queue
@ 2010-06-02 12:18 Nigel Cunningham
  0 siblings, 0 replies; 60+ messages in thread
From: Nigel Cunningham @ 2010-06-02 12:18 UTC (permalink / raw)
  To: Rafael J. Wysocki, Linux PM, LKML, TuxOnIce-devel

Hi all.

Here is my current patch queue.

Taken together, the patches implement the separation of low level
block i/o into a separate file, switch from using swap_map_pages
to extents stores prior to the 'header' page and implement fully
asynchronous (rather than batched I/O). I have only run it under
VMware so far, but would estimate a doubling in speed due to the
async i/o.

Looking at Jiri's patches, there is definitely some overlap, but
more in terms of lines in the code than direction of effort (with
the exception of separating swap out). He has covered areas for
improvement that I was going to do, just not yet.

Jiri, unless you object, I'm going to seek to apply your patches
on top of what I've done. Does that sound okay?

Nigel

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

* Nigel's current for-rafael queue
@ 2010-05-28 11:14 nigel
  0 siblings, 0 replies; 60+ messages in thread
From: nigel @ 2010-05-28 11:14 UTC (permalink / raw)
  To: Linux PM

I've done some more work today. Here's an updated copy of the patches
in my queue. As you'll see, I'm focussing on the low level i/o. These
patches split out the more generic bio functions to block_io.c, leaving
swap.c with just the swap specific functions (and, at the moment, the
highlevel i/o routines). In doing this, I'm setting up a foundation
for getting rid of the swap_map pages (I'll instead store extents in
the image header), and through that for doing fully asynchronous I/O,
which should give some speed increase. The changes also lay the groundwork
for support for multiple swap devices and non-swap at a later stage.

Regards,

Nigel

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

end of thread, other threads:[~2010-09-25 22:37 UTC | newest]

Thread overview: 60+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-06-02 12:18 Nigel's current for-rafael queue Nigel Cunningham
2010-06-02 12:19 ` [PATCH 01/21] Hibernation: Swap iteration functions Nigel Cunningham
2010-06-02 12:19 ` Nigel Cunningham
2010-06-02 12:19 ` [PATCH 02/21] Hibernation: Move root_swap declaration Nigel Cunningham
2010-06-02 12:19 ` Nigel Cunningham
2010-06-02 12:19 ` [PATCH 03/21] Hibernation: Add mass swap allocation routine Nigel Cunningham
2010-06-02 12:19 ` Nigel Cunningham
2010-06-02 12:19 ` [PATCH 04/21] Hibernation: Switch to preallocating swap Nigel Cunningham
2010-06-02 12:19 ` Nigel Cunningham
2010-06-02 12:19 ` [PATCH 05/21] Hiberation: Fix speed display Nigel Cunningham
2010-06-02 12:19 ` Nigel Cunningham
2010-06-02 12:19 ` [PATCH 06/21] Hibernation: Generic extents support Nigel Cunningham
2010-06-02 12:19 ` Nigel Cunningham
2010-06-02 12:19 ` [PATCH 07/21] Hibernation: Iterate over sectors not swap entries Nigel Cunningham
2010-06-02 12:19 ` Nigel Cunningham
2010-06-02 12:19 ` [PATCH 08/21] Hibernation: Stop passing swap_map_handle struct Nigel Cunningham
2010-06-02 12:19 ` Nigel Cunningham
2010-06-02 12:19 ` [PATCH 09/21] Hibernation: Stop passing bio_chain around Nigel Cunningham
2010-06-02 12:19 ` Nigel Cunningham
2010-06-02 12:19 ` [PATCH 10/21] Hibernation: Move block i/o fns to block_io.c Nigel Cunningham
2010-06-02 12:19 ` Nigel Cunningham
2010-06-02 12:19 ` [PATCH 11/21] Hibernation: Partial page I/O support Nigel Cunningham
2010-06-02 12:19 ` Nigel Cunningham
2010-06-02 12:19 ` [PATCH 12/21] Hibernation: Extent save/load routines Nigel Cunningham
2010-06-02 12:19 ` Nigel Cunningham
2010-06-02 12:19 ` [PATCH 13/21] Hibernation: Store block extents at start of image Nigel Cunningham
2010-06-02 12:19 ` Nigel Cunningham
2010-06-02 12:19 ` [PATCH 14/21] Hibernation: Use block extents for reading image Nigel Cunningham
2010-06-02 12:19 ` Nigel Cunningham
2010-06-02 12:19 ` [PATCH 15/21] Remove first_sector from swap_map_handle Nigel Cunningham
2010-06-02 12:19 ` Nigel Cunningham
2010-06-02 12:19 ` [PATCH 16/21] Hibernation: Replace bio chain Nigel Cunningham
2010-06-02 12:19 ` Nigel Cunningham
2010-06-02 12:19 ` [PATCH 17/21] Hibernation: Remove swap_map_pages Nigel Cunningham
2010-06-02 12:19 ` Nigel Cunningham
2010-06-02 12:19 ` [PATCH 18/21] Hibernation: Remove wait_on_bio_chain result Nigel Cunningham
2010-06-02 12:19 ` Nigel Cunningham
2010-06-02 12:19 ` [PATCH 19/21] Hibernation: Prepare for handle.cur removal Nigel Cunningham
2010-06-02 12:19 ` Nigel Cunningham
2010-06-02 12:19 ` [PATCH 20/21] Hibernation: Remove swap_map structure Nigel Cunningham
2010-06-02 12:19 ` Nigel Cunningham
2010-06-02 12:19 ` [PATCH 21/21] Hibernation: Remove now-empty routines Nigel Cunningham
2010-06-02 12:19 ` Nigel Cunningham
2010-08-03  6:55 ` Nigel's current for-rafael queue Pavel Machek
2010-08-03  6:55 ` Pavel Machek
2010-08-03  7:00   ` Nigel Cunningham
2010-08-03  7:00   ` Nigel Cunningham
  -- strict thread matches above, loose matches on Subject: below --
2010-09-25  4:16 Nigel Cunningham
2010-09-25 15:04 ` Martin Steigerwald
2010-09-25 15:04 ` Martin Steigerwald
2010-09-25 15:04 ` [linux-pm] " Martin Steigerwald
2010-09-25 21:21   ` Nigel Cunningham
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-25 22:19 ` Rafael J. Wysocki
2010-09-25  4:16 Nigel Cunningham
2010-06-02 12:18 Nigel Cunningham
2010-05-28 11:14 nigel

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.