From: Nigel Cunningham <nigel@tuxonice.net>
To: "Rafael J. Wysocki" <rjw@sisk.pl>,
Linux PM <linux-pm@lists.linux-foundation.org>,
LKML <linux-kernel@vger.kernel.org>,
TuxOnIce-devel <tuxonice-devel@tuxonice.net>
Subject: [PATCH 07/22] Hibernation: Generic extents support.
Date: Sat, 25 Sep 2010 14:16:49 +1000 [thread overview]
Message-ID: <1285388224-10012-8-git-send-email-nigel@tuxonice.net> (raw)
In-Reply-To: <1285388224-10012-1-git-send-email-nigel@tuxonice.net>
Separate out the extent storage and manipulation into a separate
file and make them more generic, so we can also use extents for
recording what sectors are used and (later) support multiple
storage devices more easily.
Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
---
kernel/power/Makefile | 2 +-
kernel/power/extents.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++++
kernel/power/extents.h | 35 +++++++++++++
kernel/power/swap.c | 117 +++++---------------------------------------
4 files changed, 175 insertions(+), 104 deletions(-)
create mode 100644 kernel/power/extents.c
create mode 100644 kernel/power/extents.h
diff --git a/kernel/power/Makefile b/kernel/power/Makefile
index f9063c6..df24cab 100644
--- a/kernel/power/Makefile
+++ b/kernel/power/Makefile
@@ -9,7 +9,7 @@ obj-$(CONFIG_FREEZER) += process.o
obj-$(CONFIG_SUSPEND) += suspend.o
obj-$(CONFIG_PM_TEST_SUSPEND) += suspend_test.o
obj-$(CONFIG_HIBERNATION) += hibernate.o snapshot.o swap.o user.o \
- block_io.o
+ block_io.o extents.o
obj-$(CONFIG_SUSPEND_NVS) += nvs.o
obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o
diff --git a/kernel/power/extents.c b/kernel/power/extents.c
new file mode 100644
index 0000000..172322d
--- /dev/null
+++ b/kernel/power/extents.c
@@ -0,0 +1,125 @@
+/*
+ * linux/kernel/power/extents.c
+ *
+ * This file provides functions for storing and using a series of
+ * extents.
+ *
+ * Copyright (C) 1998,2001-2005 Pavel Machek <pavel@suse.cz>
+ * Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl>
+ * Copyright (C) 2010 Nigel Cunningham <nigel@tuxonice.net>
+ *
+ * This file is released under the GPLv2.
+ *
+ */
+
+#include <linux/slab.h>
+#include "extents.h"
+
+int hib_extents_empty(struct hib_extent_state *pos)
+{
+ return RB_EMPTY_ROOT(&pos->root);
+}
+
+void hib_reset_extent_pos(struct hib_extent_state *pos)
+{
+ if (hib_extents_empty(pos))
+ return;
+
+ pos->node = rb_first(&pos->root);
+
+ if (!pos->node) {
+ pos->cur_ext = NULL;
+ pos->offset = 0;
+ return;
+ }
+
+ pos->cur_ext = container_of(pos->node, struct hib_extent, node);
+ pos->offset = pos->cur_ext->start;
+}
+
+unsigned long hib_extent_current(struct hib_extent_state *pos)
+{
+ return (pos->node) ? pos->offset : 0;
+}
+
+unsigned long hib_extent_next(struct hib_extent_state *pos)
+{
+ if (!pos->node)
+ return 0;
+
+ if (pos->cur_ext->end >= pos->offset)
+ return pos->offset++;
+
+ pos->node = rb_next(pos->node);
+ if (!pos->node)
+ return 0;
+
+ pos->cur_ext = container_of(pos->node, struct hib_extent, node);
+ pos->offset = pos->cur_ext->start;
+ return pos->offset;
+}
+
+int hib_extents_insert(struct hib_extent_state *pos, unsigned long value)
+{
+ struct rb_node **new = &(pos->root.rb_node);
+ struct rb_node *parent = NULL;
+ struct hib_extent *ext;
+
+ /* Figure out where to put the new node */
+ while (*new) {
+ ext = container_of(*new, struct hib_extent, node);
+ parent = *new;
+ if (value < ext->start) {
+ /* Try to merge */
+ if (value == ext->start - 1) {
+ ext->start--;
+ return 0;
+ }
+ new = &((*new)->rb_left);
+ } else if (value > ext->end) {
+ /* Try to merge */
+ if (value == ext->end + 1) {
+ ext->end++;
+ return 0;
+ }
+ new = &((*new)->rb_right);
+ } else {
+ /* It already is in the tree */
+ return -EINVAL;
+ }
+ }
+ /* Add the new node and rebalance the tree. */
+ ext = kzalloc(sizeof(struct hib_extent), GFP_KERNEL);
+ if (!ext)
+ return -ENOMEM;
+
+ ext->start = value;
+ ext->end = value;
+ rb_link_node(&ext->node, parent, new);
+ rb_insert_color(&ext->node, &pos->root);
+ pos->num_extents++;
+ return 0;
+}
+
+/**
+ * free_all_swap_pages - free swap pages allocated for saving image data.
+ * It also frees the extents used to register which swap entres had been
+ * allocated.
+ */
+
+void hib_extents_clear(struct hib_extent_state *pos)
+{
+ struct rb_node *node;
+
+ if (hib_extents_empty(pos))
+ return;
+
+ while ((node = pos->root.rb_node)) {
+ struct hib_extent *ext;
+
+ ext = container_of(node, struct hib_extent, node);
+ rb_erase(node, &pos->root);
+ pos->num_extents--;
+ kfree(ext);
+ }
+}
diff --git a/kernel/power/extents.h b/kernel/power/extents.h
new file mode 100644
index 0000000..0b69b8e
--- /dev/null
+++ b/kernel/power/extents.h
@@ -0,0 +1,35 @@
+/*
+ * linux/kernel/power/extents.h
+ *
+ * Copyright (C) 2010 Nigel Cunningham <nigel@tuxonice.net>
+ *
+ * This file is released under the GPLv2.
+ *
+ */
+
+#include <linux/rbtree.h>
+
+struct hib_extent {
+ struct rb_node node;
+ unsigned long start;
+ unsigned long end;
+};
+
+struct hib_extent_state {
+ /* Tree */
+ struct rb_root root;
+ int num_extents;
+
+ /* Current position */
+ struct rb_node *node;
+ struct hib_extent *cur_ext;
+ unsigned long offset;
+};
+
+
+void hib_reset_extent_pos(struct hib_extent_state *pos);
+unsigned long hib_extent_current(struct hib_extent_state *pos);
+unsigned long hib_extent_next(struct hib_extent_state *pos);
+int hib_extents_insert(struct hib_extent_state *pos, unsigned long value);
+void hib_extents_clear(struct hib_extent_state *pos);
+int hib_extents_empty(struct hib_extent_state *pos);
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index 2ef2bad..da2439d 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -23,9 +23,9 @@
#include <linux/swap.h>
#include <linux/swapops.h>
#include <linux/pm.h>
-#include <linux/slab.h>
#include "power.h"
+#include "extents.h"
#define SWSUSP_SIG "S1SUSPEND"
@@ -76,97 +76,14 @@ struct swsusp_header {
static struct swsusp_header *swsusp_header;
-/**
- * The following functions are used for tracing the allocated
- * swap pages, so that they can be freed in case of an error.
- */
-
-struct swsusp_extent {
- struct rb_node node;
- unsigned long start;
- unsigned long end;
-};
-
-static struct rb_root swsusp_extents = RB_ROOT;
-
-struct storage_position {
- struct rb_node *node;
- struct swsusp_extent *cur_ext;
- unsigned long offset;
-};
-
-static struct storage_position pos;
-
-static void reset_storage_pos(void)
-{
- pos.node = rb_first(&swsusp_extents);
-
- if (!pos.node) {
- pos.cur_ext = NULL;
- pos.offset = 0;
- return;
- }
-
- pos.cur_ext = container_of(pos.node, struct swsusp_extent, node);
- pos.offset = pos.cur_ext->start;
-}
+static struct hib_extent_state swap_extents;
static sector_t next_swapdev_block(void)
{
- if (!pos.node)
- return 0;
-
- if (pos.cur_ext->end >= pos.offset)
- return pos.offset++;
-
- pos.node = rb_next(pos.node);
- if (!pos.node)
- return 0;
-
- pos.cur_ext = container_of(pos.node, struct swsusp_extent, node);
- pos.offset = pos.cur_ext->start;
- return pos.offset;
-}
-
-static int swsusp_extents_insert(unsigned long swap_offset)
-{
- struct rb_node **new = &(swsusp_extents.rb_node);
- struct rb_node *parent = NULL;
- struct swsusp_extent *ext;
-
- /* Figure out where to put the new node */
- while (*new) {
- ext = container_of(*new, struct swsusp_extent, node);
- parent = *new;
- if (swap_offset < ext->start) {
- /* Try to merge */
- if (swap_offset == ext->start - 1) {
- ext->start--;
- return 0;
- }
- new = &((*new)->rb_left);
- } else if (swap_offset > ext->end) {
- /* Try to merge */
- if (swap_offset == ext->end + 1) {
- ext->end++;
- return 0;
- }
- new = &((*new)->rb_right);
- } else {
- /* It already is in the tree */
- return -EINVAL;
- }
- }
- /* Add the new node and rebalance the tree. */
- ext = kzalloc(sizeof(struct swsusp_extent), GFP_KERNEL);
- if (!ext)
- return -ENOMEM;
-
- ext->start = swap_offset;
- ext->end = swap_offset;
- rb_link_node(&ext->node, parent, new);
- rb_insert_color(&ext->node, &swsusp_extents);
- return 0;
+ unsigned long res = hib_extent_next(&swap_extents);
+ if (res)
+ res = swapdev_block(root_swap, res);
+ return res;
}
/**
@@ -180,7 +97,7 @@ sector_t alloc_swapdev_block(int swap)
offset = swp_offset(get_swap_page_of_type(swap));
if (offset) {
- if (swsusp_extents_insert(offset))
+ if (hib_extents_insert(&swap_extents, offset))
swap_free(swp_entry(swap, offset));
else
return swapdev_block(swap, offset);
@@ -224,7 +141,7 @@ static int allocate_swap(unsigned int nr_pages)
return 0;
}
- reset_storage_pos();
+ hib_reset_extent_pos(&swap_extents);
return 1;
}
@@ -236,24 +153,18 @@ static int allocate_swap(unsigned int nr_pages)
void free_all_swap_pages(int swap)
{
- struct rb_node *node;
-
- while ((node = swsusp_extents.rb_node)) {
- struct swsusp_extent *ext;
- unsigned long offset;
+ unsigned long offset;
- ext = container_of(node, struct swsusp_extent, node);
- rb_erase(node, &swsusp_extents);
- for (offset = ext->start; offset <= ext->end; offset++)
- swap_free(swp_entry(swap, offset));
+ hib_reset_extent_pos(&swap_extents);
+ while ((offset = hib_extent_next(&swap_extents)))
+ swap_free(swp_entry(swap, offset));
- kfree(ext);
- }
+ hib_extents_clear(&swap_extents);
}
int swsusp_swap_in_use(void)
{
- return (swsusp_extents.rb_node != NULL);
+ return (!hib_extents_empty(&swap_extents));
}
/*
--
1.7.0.4
next prev parent reply other threads:[~2010-09-25 4:17 UTC|newest]
Thread overview: 38+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-09-25 4:16 Nigel's current for-rafael queue Nigel Cunningham
2010-09-25 4:16 ` [PATCH 01/22] Record & display i/o speed post resume Nigel Cunningham
2010-09-25 4:16 ` [PATCH 02/22] Hibernation: Swap iteration functions Nigel Cunningham
2010-09-25 4:16 ` [PATCH 03/22] Hibernation: Move root_swap declaration Nigel Cunningham
2010-09-25 4:16 ` [PATCH 04/22] Hibernation: Add mass swap allocation routine Nigel Cunningham
2010-09-25 4:16 ` [PATCH 05/22] Hibernation: Switch to preallocating swap Nigel Cunningham
2010-09-25 21:24 ` Rafael J. Wysocki
2010-09-25 21:32 ` Nigel Cunningham
2010-09-25 22:22 ` Rafael J. Wysocki
2010-09-25 4:16 ` [PATCH 06/22] Hiberation: Fix speed display Nigel Cunningham
2010-09-25 4:16 ` Nigel Cunningham [this message]
2010-09-25 4:16 ` [PATCH 08/22] Hibernation: Iterate over sectors not swap entries Nigel Cunningham
2010-09-25 4:16 ` [PATCH 09/22] Hibernation: Stop passing swap_map_handle struct Nigel Cunningham
2010-09-25 4:16 ` [PATCH 10/22] Hibernation: Stop passing bio_chain around Nigel Cunningham
2010-09-25 4:16 ` [PATCH 11/22] Hibernation: Move block i/o fns to block_io.c Nigel Cunningham
2010-09-25 4:16 ` [PATCH 12/22] Hibernation: Partial page I/O support Nigel Cunningham
2010-09-25 4:16 ` [PATCH 13/22] Hibernation: Extent save/load routines Nigel Cunningham
2010-09-25 22:12 ` Rafael J. Wysocki
2010-09-25 4:16 ` [PATCH 14/22] Hibernation: Store block extents at start of image Nigel Cunningham
2010-09-25 4:16 ` [PATCH 15/22] Hibernation: Use block extents for reading image Nigel Cunningham
2010-09-25 4:16 ` [PATCH 16/22] Remove first_sector from swap_map_handle Nigel Cunningham
2010-09-25 4:16 ` [PATCH 17/22] Hibernation: Replace bio chain Nigel Cunningham
2010-09-25 4:17 ` [PATCH 18/22] Hibernation: Remove swap_map_pages Nigel Cunningham
2010-09-25 4:17 ` [PATCH 19/22] Hibernation: Remove wait_on_bio_chain result Nigel Cunningham
2010-09-25 4:17 ` [PATCH 20/22] Hibernation: Prepare for handle.cur removal Nigel Cunningham
2010-09-25 4:17 ` [PATCH 21/22] Hibernation: Remove swap_map structure Nigel Cunningham
2010-09-25 4:17 ` [PATCH 22/22] Hibernation: Remove now-empty routines Nigel Cunningham
2010-09-25 15:04 ` [linux-pm] Nigel's current for-rafael queue Martin Steigerwald
2010-09-25 21:21 ` Nigel Cunningham
2010-09-25 22:19 ` Rafael J. Wysocki
2010-09-25 22:33 ` Nigel Cunningham
2010-09-25 22:36 ` Rafael J. Wysocki
2010-09-28 10:34 ` [TuxOnIce-devel] " Martin Steigerwald
2010-09-30 7:52 ` unable to handle paging request at resume (was: Re: [TuxOnIce-devel] Nigel's current for-rafael queue) Martin Steigerwald
2010-10-02 16:51 ` [linux-pm] " Martin Steigerwald
2010-09-28 19:45 ` [TuxOnIce-devel] Nigel's current for-rafael queue Martin Steigerwald
2010-09-28 21:25 ` Nigel Cunningham
2010-09-30 7:56 ` Martin Steigerwald
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1285388224-10012-8-git-send-email-nigel@tuxonice.net \
--to=nigel@tuxonice.net \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pm@lists.linux-foundation.org \
--cc=rjw@sisk.pl \
--cc=tuxonice-devel@tuxonice.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).