linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [Suspend2][ 00/19] Highlevel I/O routines.
@ 2006-06-26 22:35 Nigel Cunningham
  2006-06-26 22:36 ` [Suspend2][ 01/19] [Suspend2] Core io.c header Nigel Cunningham
                   ` (18 more replies)
  0 siblings, 19 replies; 20+ messages in thread
From: Nigel Cunningham @ 2006-06-26 22:35 UTC (permalink / raw)
  To: linux-kernel


Add the core's routines for doing I/O. These are the high
level routines for reading and writing the image proper
and header.

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

* [Suspend2][ 01/19] [Suspend2] Core io.c header.
  2006-06-26 22:35 [Suspend2][ 00/19] Highlevel I/O routines Nigel Cunningham
@ 2006-06-26 22:36 ` Nigel Cunningham
  2006-06-26 22:36 ` [Suspend2][ 02/19] [Suspend2] Attempt to parse resume device Nigel Cunningham
                   ` (17 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: Nigel Cunningham @ 2006-06-26 22:36 UTC (permalink / raw)
  To: linux-kernel

Add the header and #includes for kernel/power/io.c.

Signed-off-by: Nigel Cunningham <nigel@suspend2.net>

 kernel/power/io.c |   31 +++++++++++++++++++++++++++++++
 1 files changed, 31 insertions(+), 0 deletions(-)

diff --git a/kernel/power/io.c b/kernel/power/io.c
new file mode 100644
index 0000000..df0ec8d
--- /dev/null
+++ b/kernel/power/io.c
@@ -0,0 +1,31 @@
+/*
+ * kernel/power/io.c
+ *
+ * Copyright (C) 1998-2001 Gabor Kuti <seasons@fornax.hu>
+ * Copyright (C) 1998,2001,2002 Pavel Machek <pavel@suse.cz>
+ * Copyright (C) 2002-2003 Florent Chabaud <fchabaud@free.fr>
+ * Copyright (C) 2002-2006 Nigel Cunningham <nigel@suspend2.net>
+ *
+ * This file is released under the GPLv2.
+ *
+ * It contains high level IO routines for suspending.
+ *
+ */
+
+#include <linux/suspend.h>
+#include <linux/version.h>
+#include <linux/utsname.h>
+#include <linux/mount.h>
+#include <linux/suspend2.h>
+
+#include "version.h"
+#include "modules.h"
+#include "pageflags.h"
+#include "io.h"
+#include "ui.h"
+#include "suspend2_common.h"
+#include "suspend2.h"
+#include "storage.h"
+#include "prepare_image.h"
+#include "extent.h"
+

--
Nigel Cunningham		nigel at suspend2 dot net

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

* [Suspend2][ 02/19] [Suspend2] Attempt to parse resume device.
  2006-06-26 22:35 [Suspend2][ 00/19] Highlevel I/O routines Nigel Cunningham
  2006-06-26 22:36 ` [Suspend2][ 01/19] [Suspend2] Core io.c header Nigel Cunningham
@ 2006-06-26 22:36 ` Nigel Cunningham
  2006-06-26 22:36 ` [Suspend2][ 03/19] [Suspend2] Attempt to parse resume device (wrapped) Nigel Cunningham
                   ` (16 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: Nigel Cunningham @ 2006-06-26 22:36 UTC (permalink / raw)
  To: linux-kernel

Add core routine that attempts to parse the resume2= parameter by asking
each enabled writer whether it considers the resume2= value to have
provided it with a usable configuration. If a driver returns success,
it is made the active writer and the 'we-can-try-to-resume' flag is set.

Signed-off-by: Nigel Cunningham <nigel@suspend2.net>

 kernel/power/io.c |   75 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 75 insertions(+), 0 deletions(-)

diff --git a/kernel/power/io.c b/kernel/power/io.c
index df0ec8d..52f538d 100644
--- a/kernel/power/io.c
+++ b/kernel/power/io.c
@@ -29,3 +29,78 @@
 #include "prepare_image.h"
 #include "extent.h"
 
+/* suspend_attempt_to_parse_resume_device
+ *
+ * Can we suspend, using the current resume2= parameter?
+ */
+int suspend_attempt_to_parse_resume_device(void)
+{
+	struct list_head *writer;
+	struct suspend_module_ops *this_writer;
+	int result, returning = 0;
+
+	if (suspend_activate_storage(0))
+		return 0;
+
+	suspend_active_writer = NULL;
+	clear_suspend_state(SUSPEND_RESUME_DEVICE_OK);
+	clear_suspend_state(SUSPEND_CAN_RESUME);
+	clear_result_state(SUSPEND_ABORTED);
+
+	if (!suspend_num_writers) {
+		printk(name_suspend "No writers have been registered. Suspending will be disabled.\n");
+		goto cleanup;
+	}
+	
+	if (!resume2_file[0]) {
+		printk(name_suspend "Resume2 parameter is empty. Suspending will be disabled.\n");
+		goto cleanup;
+	}
+
+	list_for_each(writer, &suspend_writers) {
+		this_writer = list_entry(writer, struct suspend_module_ops, type_list);
+
+		/* 
+		 * Not sure why you'd want to disable a writer, but
+		 * we should honour the flag if we're providing it
+		 */
+		if (this_writer->disabled) {
+			printk(name_suspend
+					"Writer '%s' is disabled. Ignoring it.\n",
+					this_writer->name);
+			continue;
+		}
+
+		result = this_writer->parse_sig_location(
+				resume2_file, (suspend_num_writers == 1));
+
+		switch (result) {
+			case -EINVAL:
+				/* 
+				 * For this writer, but not a valid 
+				 * configuration. Error already printed.
+				 */
+
+				goto cleanup;
+
+			case 0:
+				/*
+				 * For this writer and valid.
+				 */
+
+				suspend_active_writer = this_writer;
+
+				set_suspend_state(SUSPEND_RESUME_DEVICE_OK);
+				set_suspend_state(SUSPEND_CAN_RESUME);
+				printk(name_suspend "Resuming enabled.\n");
+
+				returning = 1;
+				goto cleanup;
+		}
+	}
+	printk(name_suspend "No matching enabled writer found. Resuming disabled.\n");
+cleanup:
+	suspend_deactivate_storage(0);
+	return returning;
+}
+

--
Nigel Cunningham		nigel at suspend2 dot net

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

* [Suspend2][ 03/19] [Suspend2] Attempt to parse resume device (wrapped).
  2006-06-26 22:35 [Suspend2][ 00/19] Highlevel I/O routines Nigel Cunningham
  2006-06-26 22:36 ` [Suspend2][ 01/19] [Suspend2] Core io.c header Nigel Cunningham
  2006-06-26 22:36 ` [Suspend2][ 02/19] [Suspend2] Attempt to parse resume device Nigel Cunningham
@ 2006-06-26 22:36 ` Nigel Cunningham
  2006-06-26 22:36 ` [Suspend2][ 04/19] [Suspend2] Reset modules after invalidating an image Nigel Cunningham
                   ` (15 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: Nigel Cunningham @ 2006-06-26 22:36 UTC (permalink / raw)
  To: linux-kernel

Add a version that attempts to parse the resume2= parameter, but wraps the
call in calls to enable and disable any storage (such as network storage)
configured via the userspace storage manager.

Signed-off-by: Nigel Cunningham <nigel@suspend2.net>

 kernel/power/io.c |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/kernel/power/io.c b/kernel/power/io.c
index 52f538d..bfe4468 100644
--- a/kernel/power/io.c
+++ b/kernel/power/io.c
@@ -104,3 +104,10 @@ cleanup:
 	return returning;
 }
 
+void attempt_to_parse_resume_device2(void)
+{
+	suspend_prepare_usm();
+	suspend_attempt_to_parse_resume_device();
+	suspend_cleanup_usm();
+}
+

--
Nigel Cunningham		nigel at suspend2 dot net

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

* [Suspend2][ 04/19] [Suspend2] Reset modules after invalidating an image.
  2006-06-26 22:35 [Suspend2][ 00/19] Highlevel I/O routines Nigel Cunningham
                   ` (2 preceding siblings ...)
  2006-06-26 22:36 ` [Suspend2][ 03/19] [Suspend2] Attempt to parse resume device (wrapped) Nigel Cunningham
@ 2006-06-26 22:36 ` Nigel Cunningham
  2006-06-26 22:36 ` [Suspend2][ 05/19] [Suspend2] Fill the suspend header fields Nigel Cunningham
                   ` (14 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: Nigel Cunningham @ 2006-06-26 22:36 UTC (permalink / raw)
  To: linux-kernel

Reset modules after using them to read an image header and invalidate it,
when the user puts noresume2 on the command line.

Signed-off-by: Nigel Cunningham <nigel@suspend2.net>

 kernel/power/io.c |   20 ++++++++++++++++++++
 1 files changed, 20 insertions(+), 0 deletions(-)

diff --git a/kernel/power/io.c b/kernel/power/io.c
index bfe4468..5c0acdd 100644
--- a/kernel/power/io.c
+++ b/kernel/power/io.c
@@ -111,3 +111,23 @@ void attempt_to_parse_resume_device2(voi
 	suspend_cleanup_usm();
 }
 
+/* noresume_reset_modules
+ *
+ * Description:	When we read the start of an image, modules (and especially the
+ * 		active writer) might need to reset data structures if we decide
+ * 		to invalidate the image rather than resuming from it.
+ */
+
+static void noresume_reset_modules(void)
+{
+	struct suspend_module_ops *this_filter;
+	
+	list_for_each_entry(this_filter, &suspend_filters, type_list) {
+		if (this_filter->noresume_reset)
+			this_filter->noresume_reset();
+	}
+
+	if (suspend_active_writer && suspend_active_writer->noresume_reset)
+		suspend_active_writer->noresume_reset();
+}
+

--
Nigel Cunningham		nigel at suspend2 dot net

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

* [Suspend2][ 05/19] [Suspend2] Fill the suspend header fields.
  2006-06-26 22:35 [Suspend2][ 00/19] Highlevel I/O routines Nigel Cunningham
                   ` (3 preceding siblings ...)
  2006-06-26 22:36 ` [Suspend2][ 04/19] [Suspend2] Reset modules after invalidating an image Nigel Cunningham
@ 2006-06-26 22:36 ` Nigel Cunningham
  2006-06-26 22:36 ` [Suspend2][ 06/19] [Suspend2] Initialise modules before doing I/O Nigel Cunningham
                   ` (13 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: Nigel Cunningham @ 2006-06-26 22:36 UTC (permalink / raw)
  To: linux-kernel

Store the image metadata in the suspend header data structure.

Signed-off-by: Nigel Cunningham <nigel@suspend2.net>

 kernel/power/io.c |   30 ++++++++++++++++++++++++++++++
 1 files changed, 30 insertions(+), 0 deletions(-)

diff --git a/kernel/power/io.c b/kernel/power/io.c
index 5c0acdd..b3a997f 100644
--- a/kernel/power/io.c
+++ b/kernel/power/io.c
@@ -131,3 +131,33 @@ static void noresume_reset_modules(void)
 		suspend_active_writer->noresume_reset();
 }
 
+/* fill_suspend_header()
+ * 
+ * Description:	Fill the suspend header structure.
+ * Arguments:	struct suspend_header: Header data structure to be filled.
+ */
+
+static void fill_suspend_header(struct suspend_header *sh)
+{
+	int i;
+	
+	memset((char *)sh, 0, sizeof(*sh));
+
+	sh->version_code = LINUX_VERSION_CODE;
+	sh->num_physpages = num_physpages;
+	sh->orig_mem_free = suspend_orig_mem_free;
+	strncpy(sh->machine, system_utsname.machine, 65);
+	strncpy(sh->version, system_utsname.version, 65);
+	sh->page_size = PAGE_SIZE;
+	sh->pagedir = pagedir1;
+	sh->pageset_2_size = pagedir2.pageset_size;
+	sh->param0 = suspend_result;
+	sh->param1 = suspend_action;
+	sh->param2 = suspend_debug_state;
+	sh->param3 = console_loglevel;
+	sh->root_fs = current->fs->rootmnt->mnt_sb->s_dev;
+	for (i = 0; i < 4; i++)
+		sh->io_time[i/2][i%2] =
+		       suspend_io_time[i/2][i%2];
+}
+

--
Nigel Cunningham		nigel at suspend2 dot net

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

* [Suspend2][ 06/19] [Suspend2] Initialise modules before doing I/O.
  2006-06-26 22:35 [Suspend2][ 00/19] Highlevel I/O routines Nigel Cunningham
                   ` (4 preceding siblings ...)
  2006-06-26 22:36 ` [Suspend2][ 05/19] [Suspend2] Fill the suspend header fields Nigel Cunningham
@ 2006-06-26 22:36 ` Nigel Cunningham
  2006-06-26 22:36 ` [Suspend2][ 07/19] [Suspend2] Cleanup modules after doing I/O on a portion of the image Nigel Cunningham
                   ` (12 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: Nigel Cunningham @ 2006-06-26 22:36 UTC (permalink / raw)
  To: linux-kernel

Add a routine to initialise modules in preparation for reading or writing a
portion of the image proper (not used for the header).

Signed-off-by: Nigel Cunningham <nigel@suspend2.net>

 kernel/power/io.c |   45 +++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 45 insertions(+), 0 deletions(-)

diff --git a/kernel/power/io.c b/kernel/power/io.c
index b3a997f..401789d 100644
--- a/kernel/power/io.c
+++ b/kernel/power/io.c
@@ -161,3 +161,48 @@ static void fill_suspend_header(struct s
 		       suspend_io_time[i/2][i%2];
 }
 
+/*
+ * rw_init_modules
+ *
+ * Iterate over modules, preparing the ones that will be used to read or write
+ * data.
+ */
+static int rw_init_modules(int rw, int which)
+{
+	struct suspend_module_ops *this_module;
+	/* Initialise page transformers */
+	list_for_each_entry(this_module, &suspend_filters, type_list) {
+		if (this_module->disabled)
+			continue;
+		if (this_module->rw_init &&
+		     	this_module->rw_init(rw, which)) {
+			abort_suspend("Failed to initialise the %s filter.",
+				this_module->name);
+				return 1;
+		}
+	}
+
+	/* Initialise writer */
+	if (suspend_active_writer->rw_init(rw, which)) {
+		abort_suspend("Failed to initialise the writer."); 
+		if (!rw)
+			suspend_active_writer->invalidate_image();
+		return 1;
+	}
+
+	/* Initialise other modules */
+	list_for_each_entry(this_module, &suspend_modules, module_list) {
+		if (this_module->disabled)
+			continue;
+		if ((this_module->type == FILTER_MODULE) ||
+		    (this_module->type == WRITER_MODULE))
+			continue;
+		if (this_module->rw_init && this_module->rw_init(rw, which)) {
+				set_result_state(SUSPEND_ABORTED);
+				return 1;
+			}
+	}
+
+	return 0;
+}
+

--
Nigel Cunningham		nigel at suspend2 dot net

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

* [Suspend2][ 07/19] [Suspend2] Cleanup modules after doing I/O on a portion of the image.
  2006-06-26 22:35 [Suspend2][ 00/19] Highlevel I/O routines Nigel Cunningham
                   ` (5 preceding siblings ...)
  2006-06-26 22:36 ` [Suspend2][ 06/19] [Suspend2] Initialise modules before doing I/O Nigel Cunningham
@ 2006-06-26 22:36 ` Nigel Cunningham
  2006-06-26 22:36 ` [Suspend2][ 08/19] [Suspend2] I/O main loop Nigel Cunningham
                   ` (11 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: Nigel Cunningham @ 2006-06-26 22:36 UTC (permalink / raw)
  To: linux-kernel

Flush any pending I/O (writes only), and cleanup modules using in doing the
I/O.

Signed-off-by: Nigel Cunningham <nigel@suspend2.net>

 kernel/power/io.c |   35 +++++++++++++++++++++++++++++++++++
 1 files changed, 35 insertions(+), 0 deletions(-)

diff --git a/kernel/power/io.c b/kernel/power/io.c
index 401789d..be13f42 100644
--- a/kernel/power/io.c
+++ b/kernel/power/io.c
@@ -206,3 +206,38 @@ static int rw_init_modules(int rw, int w
 	return 0;
 }
 
+/*
+ * rw_cleanup_modules
+ *
+ * Cleanup components after reading or writing a set of pages.
+ * Only the writer may fail.
+ */
+static int rw_cleanup_modules(int rw)
+{
+	struct suspend_module_ops *this_module;
+	int result = 0;
+
+	/* Cleanup other modules */
+	list_for_each_entry(this_module, &suspend_modules, module_list) {
+		if (this_module->disabled)
+			continue;
+		if ((this_module->type == FILTER_MODULE) ||
+		    (this_module->type == WRITER_MODULE))
+			continue;
+		if (this_module->rw_cleanup)
+			result |= this_module->rw_cleanup(rw);
+	}
+
+	/* Flush data and cleanup */
+	list_for_each_entry(this_module, &suspend_filters, type_list) {
+		if (this_module->disabled)
+			continue;
+		if (this_module->rw_cleanup)
+			result |= this_module->rw_cleanup(rw);
+	}
+
+	result |= suspend_active_writer->rw_cleanup(rw);
+
+	return result;
+}
+

--
Nigel Cunningham		nigel at suspend2 dot net

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

* [Suspend2][ 08/19] [Suspend2] I/O main loop.
  2006-06-26 22:35 [Suspend2][ 00/19] Highlevel I/O routines Nigel Cunningham
                   ` (6 preceding siblings ...)
  2006-06-26 22:36 ` [Suspend2][ 07/19] [Suspend2] Cleanup modules after doing I/O on a portion of the image Nigel Cunningham
@ 2006-06-26 22:36 ` Nigel Cunningham
  2006-06-26 22:36 ` [Suspend2][ 09/19] [Suspend2] Write a pageset Nigel Cunningham
                   ` (10 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: Nigel Cunningham @ 2006-06-26 22:36 UTC (permalink / raw)
  To: linux-kernel

Main I/O loop in the core of Suspend2. Submits pages for I/O to the first
plugin in the pipeline and sends status updates to any userui component.

Signed-off-by: Nigel Cunningham <nigel@suspend2.net>

 kernel/power/io.c |   65 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 65 insertions(+), 0 deletions(-)

diff --git a/kernel/power/io.c b/kernel/power/io.c
index be13f42..f237231 100644
--- a/kernel/power/io.c
+++ b/kernel/power/io.c
@@ -241,3 +241,68 @@ static int rw_cleanup_modules(int rw)
 	return result;
 }
 
+/*
+ * do_rw_loop
+ *
+ * The main I/O loop for reading or writing pages.
+ */
+static int do_rw_loop(int write, int finish_at, dyn_pageflags_t *pageflags,
+		int base, int barmax)
+{
+	int current_page_index = -1, pc, step = 1, nextupdate = 0, i;
+	int result;
+	struct suspend_module_ops *first_filter = suspend_get_next_filter(NULL);
+
+	current_page_index = get_next_bit_on(*pageflags, -1);
+
+	pc = finish_at / 5;
+
+	/* Read the pages */
+	for (i=0; i< finish_at; i++) {
+		struct page *page = pfn_to_page(current_page_index);
+
+		/* Status */
+		if ((i+base) >= nextupdate)
+			nextupdate = suspend_update_status(i+base, barmax,
+				" %d/%d MB ", MB(base+i+1), MB(barmax));
+
+		if ((i + 1) == pc) {
+			printk("%d%%...", 20 * step);
+			step++;
+			pc = finish_at * step / 5;
+		}
+		
+		if (write)
+			result = first_filter->write_chunk(page);
+		else
+			result = first_filter->read_chunk(page, SUSPEND_ASYNC);
+
+		if (result) {
+			if (write) {
+				printk("Write chunk returned %d.\n", result);
+				abort_suspend("Failed to write a chunk of the "
+					"image.");
+				return result;
+			} else
+				panic("Failed to read chunk %d/%d of the image. (%d)",
+					i, finish_at, result);
+		}
+
+		/* Interactivity*/
+		suspend_cond_pause(0, NULL);
+
+		if (test_result_state(SUSPEND_ABORTED) && write)
+			return 1;
+
+		/* Prepare next */
+		current_page_index = get_next_bit_on(*pageflags,
+				current_page_index);
+	}
+
+	printk("done.\n");
+
+	suspend_update_status(base + finish_at, barmax, " %d/%d MB ",
+			MB(base + finish_at), MB(barmax));
+	return 0;
+}
+

--
Nigel Cunningham		nigel at suspend2 dot net

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

* [Suspend2][ 09/19] [Suspend2] Write a pageset.
  2006-06-26 22:35 [Suspend2][ 00/19] Highlevel I/O routines Nigel Cunningham
                   ` (7 preceding siblings ...)
  2006-06-26 22:36 ` [Suspend2][ 08/19] [Suspend2] I/O main loop Nigel Cunningham
@ 2006-06-26 22:36 ` Nigel Cunningham
  2006-06-26 22:36 ` [Suspend2][ 10/19] [Suspend2] Read a portion of the image from storage Nigel Cunningham
                   ` (9 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: Nigel Cunningham @ 2006-06-26 22:36 UTC (permalink / raw)
  To: linux-kernel

Write a set of pages to storage, also recording the time taken.

Signed-off-by: Nigel Cunningham <nigel@suspend2.net>

 kernel/power/io.c |   58 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 58 insertions(+), 0 deletions(-)

diff --git a/kernel/power/io.c b/kernel/power/io.c
index f237231..fd20324 100644
--- a/kernel/power/io.c
+++ b/kernel/power/io.c
@@ -306,3 +306,61 @@ static int do_rw_loop(int write, int fin
 	return 0;
 }
 
+/* write_pageset()
+ *
+ * Description:	Write a pageset to disk.
+ * Arguments:	pagedir:	Pointer to the pagedir to be saved.
+ * 		whichtowrite:	Controls what debugging output is printed.
+ * Returns:	Zero on success or -1 on failure.
+ */
+
+int write_pageset(struct pagedir *pagedir, int whichtowrite)
+{
+	int finish_at, base = 0, start_time, end_time;
+	int barmax = pagedir1.pageset_size + pagedir2.pageset_size;
+	long error = 0;
+	dyn_pageflags_t *pageflags;
+
+	/* 
+	 * Even if there is nothing to read or write, the writer
+	 * may need the init/cleanup for it's housekeeping.  (eg:
+	 * Pageset1 may start where pageset2 ends when writing).
+	 */
+	finish_at = pagedir->pageset_size;
+
+	if (whichtowrite == 1) {
+		suspend_prepare_status(DONT_CLEAR_BAR,
+				"Writing kernel & process data...");
+		base = pagedir2.pageset_size;
+		if (test_action_state(SUSPEND_TEST_FILTER_SPEED) ||
+		    test_action_state(SUSPEND_TEST_BIO))
+			pageflags = &pageset1_map;
+		else
+			pageflags = &pageset1_copy_map;
+	} else {
+		suspend_prepare_status(CLEAR_BAR, "Writing caches...");
+		pageflags = &pageset2_map;
+		bytes_in = bytes_out = 0;
+	}	
+	
+	start_time = jiffies;
+
+	if (!rw_init_modules(1, whichtowrite))
+		error = do_rw_loop(1, finish_at, pageflags, base, barmax);
+
+	if (rw_cleanup_modules(WRITE)) {
+		abort_suspend("Failed to cleanup after writing.");
+		error = 1;
+	}
+
+	/* Statistics */
+	end_time = jiffies;
+	
+	if ((end_time - start_time) && (!test_result_state(SUSPEND_ABORTED))) {
+		suspend_io_time[0][0] += finish_at,
+		suspend_io_time[0][1] += (end_time - start_time);
+	}
+
+	return error;
+}
+

--
Nigel Cunningham		nigel at suspend2 dot net

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

* [Suspend2][ 10/19] [Suspend2] Read a portion of the image from storage.
  2006-06-26 22:35 [Suspend2][ 00/19] Highlevel I/O routines Nigel Cunningham
                   ` (8 preceding siblings ...)
  2006-06-26 22:36 ` [Suspend2][ 09/19] [Suspend2] Write a pageset Nigel Cunningham
@ 2006-06-26 22:36 ` Nigel Cunningham
  2006-06-26 22:36 ` [Suspend2][ 11/19] [Suspend2] Write module configurations in an image header Nigel Cunningham
                   ` (8 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: Nigel Cunningham @ 2006-06-26 22:36 UTC (permalink / raw)
  To: linux-kernel

Read a set of pages from storage. The portion will normally be the same
size as was written, but may be smaller if suspending is being aborted or
the user suspended to ram instead of powering off.

Signed-off-by: Nigel Cunningham <nigel@suspend2.net>

 kernel/power/io.c |   57 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 57 insertions(+), 0 deletions(-)

diff --git a/kernel/power/io.c b/kernel/power/io.c
index fd20324..dade1fc 100644
--- a/kernel/power/io.c
+++ b/kernel/power/io.c
@@ -364,3 +364,60 @@ int write_pageset(struct pagedir *pagedi
 	return error;
 }
 
+/* read_pageset()
+ *
+ * Description:	Read a pageset from disk.
+ * Arguments:	pagedir:	Pointer to the pagedir to be saved.
+ * 		whichtowrite:	Controls what debugging output is printed.
+ * 		overwrittenpagesonly: Whether to read the whole pageset or
+ * 		only part.
+ * Returns:	Zero on success or -1 on failure.
+ */
+
+static int read_pageset(struct pagedir *pagedir, int whichtoread,
+		int overwrittenpagesonly)
+{
+	int result = 0, base = 0, start_time, end_time;
+	int finish_at = pagedir->pageset_size;
+	int barmax = pagedir1.pageset_size + pagedir2.pageset_size;
+	dyn_pageflags_t *pageflags;
+
+	if (whichtoread == 1) {
+		suspend_prepare_status(CLEAR_BAR,
+				"Reading kernel & process data...");
+		pageflags = &pageset1_copy_map;
+	} else {
+		suspend_prepare_status(DONT_CLEAR_BAR, "Reading caches...");
+		if (overwrittenpagesonly)
+			barmax = finish_at = min(pagedir1.pageset_size, 
+						 pagedir2.pageset_size);
+		else {
+			base = pagedir1.pageset_size;
+		}
+		pageflags = &pageset2_map;
+	}	
+	
+	start_time = jiffies;
+
+	if (rw_init_modules(0, whichtoread)) {
+		suspend_active_writer->invalidate_image();
+		result = 1;
+	} else
+		result = do_rw_loop(0, finish_at, pageflags, base, barmax);
+
+	if (rw_cleanup_modules(READ)) {
+		abort_suspend("Failed to cleanup after reading.");
+		result = 1;
+	}
+
+	/* Statistics */
+	end_time=jiffies;
+
+	if ((end_time - start_time) && (!test_result_state(SUSPEND_ABORTED))) {
+		suspend_io_time[1][0] += finish_at,
+		suspend_io_time[1][1] += (end_time - start_time);
+	}
+
+	return result;
+}
+

--
Nigel Cunningham		nigel at suspend2 dot net

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

* [Suspend2][ 11/19] [Suspend2] Write module configurations in an image header.
  2006-06-26 22:35 [Suspend2][ 00/19] Highlevel I/O routines Nigel Cunningham
                   ` (9 preceding siblings ...)
  2006-06-26 22:36 ` [Suspend2][ 10/19] [Suspend2] Read a portion of the image from storage Nigel Cunningham
@ 2006-06-26 22:36 ` Nigel Cunningham
  2006-06-26 22:36 ` [Suspend2][ 12/19] [Suspend2] Read module configs from " Nigel Cunningham
                   ` (7 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: Nigel Cunningham @ 2006-06-26 22:36 UTC (permalink / raw)
  To: linux-kernel

Write the configuration of each module used to the image header.

Signed-off-by: Nigel Cunningham <nigel@suspend2.net>

 kernel/power/io.c |   67 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 67 insertions(+), 0 deletions(-)

diff --git a/kernel/power/io.c b/kernel/power/io.c
index dade1fc..a0aabd1 100644
--- a/kernel/power/io.c
+++ b/kernel/power/io.c
@@ -421,3 +421,70 @@ static int read_pageset(struct pagedir *
 	return result;
 }
 
+/* write_module_configs()
+ *
+ * Description:	Store the configuration for each module in the image header.
+ * Returns:	Int: Zero on success, Error value otherwise.
+ */
+static int write_module_configs(void)
+{
+	struct suspend_module_ops *this_module;
+	char *buffer = (char *) get_zeroed_page(GFP_ATOMIC);
+	int len, index = 1;
+	struct suspend_module_header suspend_module_header;
+
+	if (!buffer) {
+		printk("Failed to allocate a buffer for saving "
+				"module configuration info.\n");
+		return -ENOMEM;
+	}
+		
+	/* 
+	 * We have to know which data goes with which module, so we at
+	 * least write a length of zero for a module. Note that we are
+	 * also assuming every module's config data takes <= PAGE_SIZE.
+	 */
+
+	/* For each module (in registration order) */
+	list_for_each_entry(this_module, &suspend_modules, module_list) {
+		if (this_module->disabled || !this_module->storage_needed ||
+		    (this_module->type == WRITER_MODULE &&
+		     suspend_active_writer != this_module))
+			continue;
+
+		/* Get the data from the module */
+		len = 0;
+		if (this_module->save_config_info)
+			len = this_module->save_config_info(buffer);
+
+		/* Save the details of the module */
+		suspend_module_header.disabled = this_module->disabled;
+		suspend_module_header.type = this_module->type;
+		suspend_module_header.index = index++;
+		strncpy(suspend_module_header.name, this_module->name, 
+					sizeof(suspend_module_header.name));
+		suspend_active_writer->rw_header_chunk(WRITE,
+				this_module,
+				(char *) &suspend_module_header,
+				sizeof(suspend_module_header));
+
+		/* Save the size of the data and any data returned */
+		suspend_active_writer->rw_header_chunk(WRITE,
+				this_module,
+				(char *) &len, sizeof(int));
+		if (len)
+			suspend_active_writer->rw_header_chunk(
+				WRITE, this_module, buffer, len);
+	}
+
+	/* Write a blank header to terminate the list */
+	suspend_module_header.name[0] = '\0';
+	suspend_active_writer->rw_header_chunk(WRITE, 
+			NULL,
+			(char *) &suspend_module_header,
+			sizeof(suspend_module_header));
+
+	free_page((unsigned long) buffer);
+	return 0;
+}
+

--
Nigel Cunningham		nigel at suspend2 dot net

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

* [Suspend2][ 12/19] [Suspend2] Read module configs from an image header.
  2006-06-26 22:35 [Suspend2][ 00/19] Highlevel I/O routines Nigel Cunningham
                   ` (10 preceding siblings ...)
  2006-06-26 22:36 ` [Suspend2][ 11/19] [Suspend2] Write module configurations in an image header Nigel Cunningham
@ 2006-06-26 22:36 ` Nigel Cunningham
  2006-06-26 22:36 ` [Suspend2][ 13/19] [Suspend2] Write " Nigel Cunningham
                   ` (6 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: Nigel Cunningham @ 2006-06-26 22:36 UTC (permalink / raw)
  To: linux-kernel

Read the configurations used when writing the image, prior to loading the
data. Modules which are loaded now, and weren't when we suspended are
disabled. If a module which is needed is not available, we complain and
abort resuming. When built as modules, support for (say) encryption and
compression can end up loaded in the wrong order. We therefore also reorder
the modules to match the order used when suspending.

Signed-off-by: Nigel Cunningham <nigel@suspend2.net>

 kernel/power/io.c |  126 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 126 insertions(+), 0 deletions(-)

diff --git a/kernel/power/io.c b/kernel/power/io.c
index a0aabd1..b179c50 100644
--- a/kernel/power/io.c
+++ b/kernel/power/io.c
@@ -488,3 +488,129 @@ static int write_module_configs(void)
 	return 0;
 }
 
+/* read_module_configs()
+ *
+ * Description:	Reload module configurations from the image header.
+ * Returns:	Int. Zero on success, error value otherwise.
+ */
+
+static int read_module_configs(void)
+{
+	struct suspend_module_ops *this_module;
+	char *buffer = (char *) get_zeroed_page(GFP_ATOMIC);
+	int len, result = 0;
+	struct suspend_module_header suspend_module_header;
+
+	if (!buffer) {
+		printk("Failed to allocate a buffer for reloading module "
+				"configuration info.\n");
+		return -ENOMEM;
+	}
+		
+	/* All modules are initially disabled. That way, if we have a module
+	 * loaded now that wasn't loaded when we suspended, it won't be used
+	 * in trying to read the data.
+	 */
+	list_for_each_entry(this_module, &suspend_modules, module_list)
+		this_module->disabled = 1;
+	
+	/* Get the first module header */
+	result = suspend_active_writer->rw_header_chunk(READ, NULL,
+			(char *) &suspend_module_header, sizeof(suspend_module_header));
+	if (!result) {
+		printk("Failed to read the next module header.\n");
+		free_page((unsigned long) buffer);
+		return -EINVAL;
+	}
+
+	/* For each module (in registration order) */
+	while (suspend_module_header.name[0]) {
+
+		/* Find the module */
+		this_module = suspend_find_module_given_name(suspend_module_header.name);
+
+		if (!this_module) {
+			/* 
+			 * Is it used? Only need to worry about filters. The active
+			 * writer must be loaded!
+			 */
+			if (!suspend_module_header.disabled) {
+				suspend_early_boot_message(1, SUSPEND_CONTINUE_REQ,
+					"It looks like we need module %s for "
+					"reading the image but it hasn't been "
+					"registered.\n",
+					suspend_module_header.name);
+				if (!(test_suspend_state(SUSPEND_CONTINUE_REQ))) {
+					suspend_active_writer->invalidate_image();
+					free_page((unsigned long) buffer);
+					return -EINVAL;
+				}
+			} else
+				printk("Module %s configuration data found, but the module "
+					"hasn't registered. Looks like it was disabled, so "
+					"we're ignoring it's data.",
+					suspend_module_header.name);
+		}
+		
+		/* Get the length of the data (if any) */
+		result = suspend_active_writer->rw_header_chunk(READ, NULL,
+				(char *) &len, sizeof(int));
+		if (!result) {
+			printk("Failed to read the length of the module %s's"
+					" configuration data.\n",
+					suspend_module_header.name);
+			free_page((unsigned long) buffer);
+			return -EINVAL;
+		}
+
+		/* Read any data and pass to the module (if we found one) */
+		if (len) {
+			suspend_active_writer->rw_header_chunk(READ, NULL,
+					buffer, len);
+			if (this_module) {
+				if (!this_module->save_config_info) {
+					printk("Huh? Module %s appears to have "
+						"a save_config_info, but not a "
+						"load_config_info function!\n",
+						this_module->name);
+				} else
+					this_module->load_config_info(buffer, len);
+			}
+		}
+
+		if (this_module) {
+			/* Now move this module to the tail of its lists. This
+			 * will put it in order. Any new modules will end up at
+			 * the top of the lists. They should have been set to
+			 * disabled when loaded (people will normally not edit
+			 * an initrd to load a new module and then suspend
+			 * without using it!).
+			 */
+
+			suspend_move_module_tail(this_module);
+
+			/* 
+			 * We apply the disabled state; modules don't need to
+			 * save whether they were disabled and if they do, we
+			 * override them anyway.
+			 */
+			this_module->disabled = suspend_module_header.disabled;
+		}
+
+		/* Get the next module header */
+		result = suspend_active_writer->rw_header_chunk(READ, NULL,
+				(char *) &suspend_module_header,
+				sizeof(suspend_module_header));
+
+		if (!result) {
+			printk("Failed to read the next module header.\n");
+			free_page((unsigned long) buffer);
+			return -EINVAL;
+		}
+
+	}
+
+	free_page((unsigned long) buffer);
+	return 0;
+}
+

--
Nigel Cunningham		nigel at suspend2 dot net

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

* [Suspend2][ 13/19] [Suspend2] Write image header.
  2006-06-26 22:35 [Suspend2][ 00/19] Highlevel I/O routines Nigel Cunningham
                   ` (11 preceding siblings ...)
  2006-06-26 22:36 ` [Suspend2][ 12/19] [Suspend2] Read module configs from " Nigel Cunningham
@ 2006-06-26 22:36 ` Nigel Cunningham
  2006-06-26 22:36 ` [Suspend2][ 14/19] [Suspend2] Sanity check " Nigel Cunningham
                   ` (5 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: Nigel Cunningham @ 2006-06-26 22:36 UTC (permalink / raw)
  To: linux-kernel

Write the header of an image to storage.

Signed-off-by: Nigel Cunningham <nigel@suspend2.net>

 kernel/power/io.c |   62 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 62 insertions(+), 0 deletions(-)

diff --git a/kernel/power/io.c b/kernel/power/io.c
index b179c50..d7c48e0 100644
--- a/kernel/power/io.c
+++ b/kernel/power/io.c
@@ -614,3 +614,65 @@ static int read_module_configs(void)
 	return 0;
 }
 
+/* write_image_header()
+ *
+ * Description:	Write the image header after write the image proper.
+ * Returns:	Int. Zero on success or -1 on failure.
+ */
+
+int write_image_header(void)
+{
+	int ret;
+	int total = pagedir1.pageset_size + pagedir2.pageset_size+2;
+	char *header_buffer = NULL;
+
+	/* Now prepare to write the header */
+	if ((ret = suspend_active_writer->write_header_init())) {
+		abort_suspend("Active writer's write_header_init"
+				" function failed.");
+		goto write_image_header_abort;
+	}
+
+	/* Get a buffer */
+	header_buffer = (char *) get_zeroed_page(GFP_ATOMIC);
+	if (!header_buffer) {
+		abort_suspend("Out of memory when trying to get page "
+				"for header!");
+		goto write_image_header_abort;
+	}
+
+	/* Write suspend header */
+	fill_suspend_header((struct suspend_header *) header_buffer);
+	suspend_active_writer->rw_header_chunk(WRITE, NULL,
+			header_buffer, sizeof(struct suspend_header));
+
+	free_page((unsigned long) header_buffer);
+
+	/* Write module configurations */
+	if ((ret = write_module_configs())) {
+		abort_suspend("Failed to write module configs.");
+		goto write_image_header_abort;
+	}
+
+	save_dyn_pageflags(pageset1_map);
+
+	/* Flush data and let writer cleanup */
+	if (suspend_active_writer->write_header_cleanup()) {
+		abort_suspend("Failed to cleanup writing header.");
+		goto write_image_header_abort_no_cleanup;
+	}
+
+	if (test_result_state(SUSPEND_ABORTED))
+		goto write_image_header_abort_no_cleanup;
+
+	suspend_message(SUSPEND_IO, SUSPEND_VERBOSE, 1, "|\n");
+	suspend_update_status(total, total, NULL);
+
+	return 0;
+
+write_image_header_abort:
+	suspend_active_writer->write_header_cleanup();
+write_image_header_abort_no_cleanup:
+	return -1;
+}
+

--
Nigel Cunningham		nigel at suspend2 dot net

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

* [Suspend2][ 14/19] [Suspend2] Sanity check image header.
  2006-06-26 22:35 [Suspend2][ 00/19] Highlevel I/O routines Nigel Cunningham
                   ` (12 preceding siblings ...)
  2006-06-26 22:36 ` [Suspend2][ 13/19] [Suspend2] Write " Nigel Cunningham
@ 2006-06-26 22:36 ` Nigel Cunningham
  2006-06-26 22:36 ` [Suspend2][ 15/19] [Suspend2] Core of code for reading pageset1 Nigel Cunningham
                   ` (4 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: Nigel Cunningham @ 2006-06-26 22:36 UTC (permalink / raw)
  To: linux-kernel

Check that an image header matches the currently running kernel, and return
either a string describing the problem, or NULL.

Signed-off-by: Nigel Cunningham <nigel@suspend2.net>

 kernel/power/io.c |   39 +++++++++++++++++++++++++++++++++++++++
 1 files changed, 39 insertions(+), 0 deletions(-)

diff --git a/kernel/power/io.c b/kernel/power/io.c
index d7c48e0..8c9c284 100644
--- a/kernel/power/io.c
+++ b/kernel/power/io.c
@@ -676,3 +676,42 @@ write_image_header_abort_no_cleanup:
 	return -1;
 }
 
+/* sanity_check()
+ *
+ * Description:	Perform a few checks, seeking to ensure that the kernel being
+ * 		booted matches the one suspended. They need to match so we can
+ * 		be _sure_ things will work. It is not absolutely impossible for
+ * 		resuming from a different kernel to work, just not assured.
+ * Arguments:	Struct suspend_header. The header which was saved at suspend
+ * 		time.
+ */
+static char *sanity_check(struct suspend_header *sh)
+{
+	if (sh->version_code != LINUX_VERSION_CODE)
+		return "Incorrect kernel version.";
+	
+	if (sh->num_physpages != num_physpages)
+		return "Incorrect memory size.";
+
+	if (strncmp(sh->machine, system_utsname.machine, 65))
+		return "Incorrect machine type.";
+
+	if (strncmp(sh->version, system_utsname.version, 65))
+		return "Right kernel version but wrong build number.";
+
+	if (sh->page_size != PAGE_SIZE)
+		return "Incorrect PAGE_SIZE.";
+
+	if (!test_suspend_state(SUSPEND_IGNORE_ROOTFS)) {
+		const struct super_block *sb;
+		list_for_each_entry(sb, &super_blocks, s_list) {
+			if ((!(sb->s_flags & MS_RDONLY)) &&
+			    (sb->s_type->fs_flags & FS_REQUIRES_DEV))
+				return "Device backed fs has been mounted "
+					"rw prior to resume."; 
+		}
+	}
+
+	return 0;
+}
+

--
Nigel Cunningham		nigel at suspend2 dot net

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

* [Suspend2][ 15/19] [Suspend2] Core of code for reading pageset1.
  2006-06-26 22:35 [Suspend2][ 00/19] Highlevel I/O routines Nigel Cunningham
                   ` (13 preceding siblings ...)
  2006-06-26 22:36 ` [Suspend2][ 14/19] [Suspend2] Sanity check " Nigel Cunningham
@ 2006-06-26 22:36 ` Nigel Cunningham
  2006-06-26 22:36 ` [Suspend2][ 16/19] [Suspend2] Read pageset1 Nigel Cunningham
                   ` (3 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: Nigel Cunningham @ 2006-06-26 22:36 UTC (permalink / raw)
  To: linux-kernel

Core code for reading pageset1, which checks that an image exists, that we
haven't been told not to resume (noresume2) and that the user wants to try
again if we've tried before. Once these tests are passed, we start to read
the image header, checking that the sanity checks are passed, and then the
image proper.

Signed-off-by: Nigel Cunningham <nigel@suspend2.net>

 kernel/power/io.c |  183 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 183 insertions(+), 0 deletions(-)

diff --git a/kernel/power/io.c b/kernel/power/io.c
index 8c9c284..35fb081 100644
--- a/kernel/power/io.c
+++ b/kernel/power/io.c
@@ -715,3 +715,186 @@ static char *sanity_check(struct suspend
 	return 0;
 }
 
+/* __read_pageset1
+ *
+ * Description:	Test for the existence of an image and attempt to load it.
+ * Returns:	Int. Zero if image found and pageset1 successfully loaded.
+ * 		Error if no image found or loaded.
+ */
+static int __read_pageset1(void)
+{			
+	int i, result = 0;
+	char *header_buffer = (char *) get_zeroed_page(GFP_ATOMIC),
+	     *sanity_error = NULL;
+	struct suspend_header *suspend_header;
+
+	if (!header_buffer)
+		return -ENOMEM;
+	
+	/* Check for an image */
+	if (!(result = suspend_active_writer->image_exists())) {
+		result = -ENODATA;
+		noresume_reset_modules();
+		goto out;
+	}
+
+	/* Check for noresume command line option */
+	if (test_suspend_state(SUSPEND_NORESUME_SPECIFIED)) {
+		suspend_active_writer->invalidate_image();
+		result = -EINVAL;
+		noresume_reset_modules();
+		goto out;
+	}
+
+	/* Check whether we've resumed before */
+	if (test_suspend_state(SUSPEND_RESUMED_BEFORE)) {
+		int resumed_before_default = 0;
+		if (test_suspend_state(SUSPEND_RETRY_RESUME))
+			resumed_before_default = SUSPEND_CONTINUE_REQ;
+		suspend_early_boot_message(1, resumed_before_default, NULL);
+		clear_suspend_state(SUSPEND_RETRY_RESUME);
+		if (!(test_suspend_state(SUSPEND_CONTINUE_REQ))) {
+			suspend_active_writer->invalidate_image();
+			result = -EINVAL;
+			noresume_reset_modules();
+			goto out;
+		}
+	}
+
+	clear_suspend_state(SUSPEND_CONTINUE_REQ);
+
+	/* 
+	 * Prepare the active writer for reading the image header. The
+	 * activate writer might read its own configuration.
+	 * 
+	 * NB: This call may never return because there might be a signature
+	 * for a different image such that we warn the user and they choose
+	 * to reboot. (If the device ids look erroneous (2.4 vs 2.6) or the
+	 * location of the image might be unavailable if it was stored on a
+	 * network connection.
+	 */
+
+	if ((result = suspend_active_writer->read_header_init())) {
+		noresume_reset_modules();
+		goto out;
+	}
+	
+	/* Read suspend header */
+	if ((result = suspend_active_writer->rw_header_chunk(READ, NULL,
+			header_buffer, sizeof(struct suspend_header))) < 0) {
+		noresume_reset_modules();
+		goto out;
+	}
+	
+	suspend_header = (struct suspend_header *) header_buffer;
+
+	/*
+	 * NB: This call may also result in a reboot rather than returning.
+	 */
+
+	if ((sanity_error = sanity_check(suspend_header)) &&
+	    suspend_early_boot_message(1, SUSPEND_CONTINUE_REQ, sanity_error)) {
+		suspend_active_writer->invalidate_image();
+		result = -EINVAL;
+		noresume_reset_modules();
+		goto out;
+	}
+
+	/*
+	 * We have an image and it looks like it will load okay.
+	 */
+
+	/* Get metadata from header. Don't override commandline parameters.
+	 *
+	 * We don't need to save the image size limit because it's not used
+	 * during resume and will be restored with the image anyway.
+	 */
+	
+	suspend_orig_mem_free = suspend_header->orig_mem_free;
+	memcpy((char *) &pagedir1,
+		(char *) &suspend_header->pagedir, sizeof(pagedir1));
+	suspend_result = suspend_header->param0;
+	suspend_action = suspend_header->param1;
+	suspend_debug_state = suspend_header->param2;
+	console_loglevel = suspend_header->param3;
+	clear_suspend_state(SUSPEND_IGNORE_LOGLEVEL);
+	pagedir2.pageset_size = suspend_header->pageset_2_size;
+	for (i = 0; i < 4; i++)
+		suspend_io_time[i/2][i%2] =
+			suspend_header->io_time[i/2][i%2];
+
+	/* Read module configurations */
+	if ((result = read_module_configs())) {
+		noresume_reset_modules();
+		pagedir1.pageset_size =
+			pagedir2.pageset_size = 0;
+		goto out;
+	}
+
+	suspend_prepare_console();
+
+	suspend_cond_pause(1, "About to read original pageset1 locations.");
+
+	/*
+	 * Read original pageset1 locations. These are the addresses we can't
+	 * use for the data to be restored.
+	 */
+
+	allocate_dyn_pageflags(&pageset1_map);
+	load_dyn_pageflags(pageset1_map);
+
+	set_suspend_state(SUSPEND_NOW_RESUMING);
+
+	/* Relocate it so that it's not overwritten while we're using it to
+	 * copy the original contents back */
+	relocate_dyn_pageflags(&pageset1_map);
+	
+	allocate_dyn_pageflags(&pageset1_copy_map);
+	relocate_dyn_pageflags(&pageset1_copy_map);
+
+	/* Clean up after reading the header */
+	if ((result = suspend_active_writer->read_header_cleanup())) {
+		noresume_reset_modules();
+		goto out_reset_console;
+	}
+
+	suspend_cond_pause(1, "About to read pagedir.");
+
+	/* 
+	 * Get the addresses of pages into which we will load the kernel to
+	 * be copied back
+	 */
+	if (suspend_get_pageset1_load_addresses()) {
+		result = -ENOMEM;
+		noresume_reset_modules();
+		goto out_reset_console;
+	}
+
+	/* Read the original kernel back */
+	suspend_cond_pause(1, "About to read pageset 1.");
+
+	if (read_pageset(&pagedir1, 1, 0)) {
+		suspend_prepare_status(CLEAR_BAR, "Failed to read pageset 1.");
+		result = -EPERM;
+		noresume_reset_modules();
+		goto out_reset_console;
+	}
+
+	suspend_cond_pause(1, "About to restore original kernel.");
+	result = 0;
+
+	if (!test_action_state(SUSPEND_KEEP_IMAGE) &&
+	    suspend_active_writer->mark_resume_attempted)
+		suspend_active_writer->mark_resume_attempted();
+
+out:
+	free_page((unsigned long) header_buffer);
+	return result;
+
+out_reset_console:
+	free_dyn_pageflags(&pageset1_map);
+	free_dyn_pageflags(&pageset1_copy_map);
+	suspend_cleanup_console();
+	goto out;
+}
+

--
Nigel Cunningham		nigel at suspend2 dot net

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

* [Suspend2][ 16/19] [Suspend2] Read pageset1.
  2006-06-26 22:35 [Suspend2][ 00/19] Highlevel I/O routines Nigel Cunningham
                   ` (14 preceding siblings ...)
  2006-06-26 22:36 ` [Suspend2][ 15/19] [Suspend2] Core of code for reading pageset1 Nigel Cunningham
@ 2006-06-26 22:36 ` Nigel Cunningham
  2006-06-26 22:36 ` [Suspend2][ 17/19] [Suspend2] Get image_exists data Nigel Cunningham
                   ` (2 subsequent siblings)
  18 siblings, 0 replies; 20+ messages in thread
From: Nigel Cunningham @ 2006-06-26 22:36 UTC (permalink / raw)
  To: linux-kernel

Call the __read_pageset1() function, report any errors and return the
result.

Signed-off-by: Nigel Cunningham <nigel@suspend2.net>

 kernel/power/io.c |   35 +++++++++++++++++++++++++++++++++++
 1 files changed, 35 insertions(+), 0 deletions(-)

diff --git a/kernel/power/io.c b/kernel/power/io.c
index 35fb081..79cf54f 100644
--- a/kernel/power/io.c
+++ b/kernel/power/io.c
@@ -898,3 +898,38 @@ out_reset_console:
 	goto out;
 }
 
+/* read_pageset1()
+ *
+ * Description:	Attempt to read the header and pageset1 of a suspend image.
+ * 		Handle the outcome, complaining where appropriate.
+ */
+
+int read_pageset1(void)
+{
+	int error;
+
+	error = __read_pageset1();
+
+	switch (error) {
+		case 0:
+		case -ENODATA:
+		case -EINVAL:	/* non fatal error */
+			return error;
+		case -EIO:
+			printk(KERN_CRIT name_suspend "I/O error\n");
+			break;
+		case -ENOENT:
+			printk(KERN_CRIT name_suspend "No such file or directory\n");
+			break;
+		case -EPERM:
+			printk(KERN_CRIT name_suspend "Sanity check error\n");
+			break;
+		default:
+			printk(KERN_CRIT name_suspend "Error %d resuming\n",
+					error);
+			break;
+	}
+	abort_suspend("Error %d in read_pageset1",error);
+	return error;
+}
+

--
Nigel Cunningham		nigel at suspend2 dot net

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

* [Suspend2][ 17/19] [Suspend2] Get image_exists data.
  2006-06-26 22:35 [Suspend2][ 00/19] Highlevel I/O routines Nigel Cunningham
                   ` (15 preceding siblings ...)
  2006-06-26 22:36 ` [Suspend2][ 16/19] [Suspend2] Read pageset1 Nigel Cunningham
@ 2006-06-26 22:36 ` Nigel Cunningham
  2006-06-26 22:36 ` [Suspend2][ 18/19] [Suspend2] Read pageset2 Nigel Cunningham
  2006-06-26 22:37 ` [Suspend2][ 19/19] [Suspend2] I/O header file Nigel Cunningham
  18 siblings, 0 replies; 20+ messages in thread
From: Nigel Cunningham @ 2006-06-26 22:36 UTC (permalink / raw)
  To: linux-kernel

Get information for the image_exists proc entry.

Signed-off-by: Nigel Cunningham <nigel@suspend2.net>

 kernel/power/io.c |   38 ++++++++++++++++++++++++++++++++++++++
 1 files changed, 38 insertions(+), 0 deletions(-)

diff --git a/kernel/power/io.c b/kernel/power/io.c
index 79cf54f..cd99bd8 100644
--- a/kernel/power/io.c
+++ b/kernel/power/io.c
@@ -933,3 +933,41 @@ int read_pageset1(void)
 	return error;
 }
 
+/*
+ * get_have_image_data()
+ */
+char *get_have_image_data(void)
+{
+	char *output_buffer = (char *) get_zeroed_page(GFP_ATOMIC);
+	struct suspend_header *suspend_header;
+
+	if (!output_buffer) {
+		printk("Output buffer null.\n");
+		return NULL;
+	}
+
+	/* Check for an image */
+	if (!suspend_active_writer->image_exists() ||
+	    suspend_active_writer->read_header_init() ||
+	    suspend_active_writer->rw_header_chunk(READ, NULL,
+			output_buffer, sizeof(struct suspend_header)) !=
+	    		sizeof(struct suspend_header)) {
+		sprintf(output_buffer, "0\n");
+		goto out;
+	}
+
+	suspend_header = (struct suspend_header *) output_buffer;
+
+	sprintf(output_buffer, "1\n%s\n%s\n",
+			suspend_header->machine,
+			suspend_header->version);
+
+	/* Check whether we've resumed before */
+	if (test_suspend_state(SUSPEND_RESUMED_BEFORE))
+		strcat(output_buffer, "Resumed before.\n");
+
+out:
+	noresume_reset_modules();
+	return output_buffer;
+}
+

--
Nigel Cunningham		nigel at suspend2 dot net

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

* [Suspend2][ 18/19] [Suspend2] Read pageset2.
  2006-06-26 22:35 [Suspend2][ 00/19] Highlevel I/O routines Nigel Cunningham
                   ` (16 preceding siblings ...)
  2006-06-26 22:36 ` [Suspend2][ 17/19] [Suspend2] Get image_exists data Nigel Cunningham
@ 2006-06-26 22:36 ` Nigel Cunningham
  2006-06-26 22:37 ` [Suspend2][ 19/19] [Suspend2] I/O header file Nigel Cunningham
  18 siblings, 0 replies; 20+ messages in thread
From: Nigel Cunningham @ 2006-06-26 22:36 UTC (permalink / raw)
  To: linux-kernel

(Re)read pageset2 data when cancelling a suspend after the atomic copy,
or when resuming.

Signed-off-by: Nigel Cunningham <nigel@suspend2.net>

 kernel/power/io.c |   24 ++++++++++++++++++++++++
 1 files changed, 24 insertions(+), 0 deletions(-)

diff --git a/kernel/power/io.c b/kernel/power/io.c
index cd99bd8..6a8badf 100644
--- a/kernel/power/io.c
+++ b/kernel/power/io.c
@@ -971,3 +971,27 @@ out:
 	return output_buffer;
 }
 
+/* read_pageset2()
+ *
+ * Description:	Read in part or all of pageset2 of an image, depending upon
+ * 		whether we are suspending and have only overwritten a portion
+ * 		with pageset1 pages, or are resuming and need to read them 
+ * 		all.
+ * Arguments:	Int. Boolean. Read only pages which would have been
+ * 		overwritten by pageset1?
+ * Returns:	Int. Zero if no error, otherwise the error value.
+ */
+int read_pageset2(int overwrittenpagesonly)
+{
+	int result = 0;
+
+	if (!pagedir2.pageset_size)
+		return 0;
+
+	result = read_pageset(&pagedir2, 2, overwrittenpagesonly);
+
+	suspend_update_status(100, 100, NULL);
+	suspend_cond_pause(1, "Pagedir 2 read.");
+
+	return result;
+}

--
Nigel Cunningham		nigel at suspend2 dot net

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

* [Suspend2][ 19/19] [Suspend2] I/O header file.
  2006-06-26 22:35 [Suspend2][ 00/19] Highlevel I/O routines Nigel Cunningham
                   ` (17 preceding siblings ...)
  2006-06-26 22:36 ` [Suspend2][ 18/19] [Suspend2] Read pageset2 Nigel Cunningham
@ 2006-06-26 22:37 ` Nigel Cunningham
  18 siblings, 0 replies; 20+ messages in thread
From: Nigel Cunningham @ 2006-06-26 22:37 UTC (permalink / raw)
  To: linux-kernel

Header file for core I/O functions.

Signed-off-by: Nigel Cunningham <nigel@suspend2.net>

 kernel/power/io.h |   46 ++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 46 insertions(+), 0 deletions(-)

diff --git a/kernel/power/io.h b/kernel/power/io.h
new file mode 100644
index 0000000..55df2ed
--- /dev/null
+++ b/kernel/power/io.h
@@ -0,0 +1,46 @@
+/*
+ * kernel/power/io.h
+ *
+ * Copyright (C) 2005-2006 Nigel Cunningham <nigel@suspend2.net>
+ *
+ * This file is released under the GPLv2.
+ *
+ * It contains high level IO routines for suspending.
+ *
+ */
+
+#include "pagedir.h"
+
+/* Non-module data saved in our image header */
+struct suspend_header {
+	u32 version_code;
+	unsigned long num_physpages;
+	unsigned long orig_mem_free;
+	char machine[65];
+	char version[65];
+	int num_cpus;
+	int page_size;
+	int pageset_2_size;
+	int param0;
+	int param1;
+	int param2;
+	int param3;
+	int progress0;
+	int progress1;
+	int progress2;
+	int progress3;
+	int io_time[2][2];
+	struct pagedir pagedir;
+	dev_t root_fs;
+};
+
+extern int write_pageset(struct pagedir *pagedir, int whichtowrite);
+extern int write_image_header(void);
+extern int read_pageset1(void);
+extern int read_pageset2(int overwrittenpagesonly);
+
+extern int suspend_attempt_to_parse_resume_device(void);
+extern void attempt_to_parse_resume_device2(void);
+extern dev_t name_to_dev_t(char *line);
+extern __nosavedata unsigned long bytes_in, bytes_out;
+extern char *get_have_image_data(void);

--
Nigel Cunningham		nigel at suspend2 dot net

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

end of thread, other threads:[~2006-06-26 23:27 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-06-26 22:35 [Suspend2][ 00/19] Highlevel I/O routines Nigel Cunningham
2006-06-26 22:36 ` [Suspend2][ 01/19] [Suspend2] Core io.c header Nigel Cunningham
2006-06-26 22:36 ` [Suspend2][ 02/19] [Suspend2] Attempt to parse resume device Nigel Cunningham
2006-06-26 22:36 ` [Suspend2][ 03/19] [Suspend2] Attempt to parse resume device (wrapped) Nigel Cunningham
2006-06-26 22:36 ` [Suspend2][ 04/19] [Suspend2] Reset modules after invalidating an image Nigel Cunningham
2006-06-26 22:36 ` [Suspend2][ 05/19] [Suspend2] Fill the suspend header fields Nigel Cunningham
2006-06-26 22:36 ` [Suspend2][ 06/19] [Suspend2] Initialise modules before doing I/O Nigel Cunningham
2006-06-26 22:36 ` [Suspend2][ 07/19] [Suspend2] Cleanup modules after doing I/O on a portion of the image Nigel Cunningham
2006-06-26 22:36 ` [Suspend2][ 08/19] [Suspend2] I/O main loop Nigel Cunningham
2006-06-26 22:36 ` [Suspend2][ 09/19] [Suspend2] Write a pageset Nigel Cunningham
2006-06-26 22:36 ` [Suspend2][ 10/19] [Suspend2] Read a portion of the image from storage Nigel Cunningham
2006-06-26 22:36 ` [Suspend2][ 11/19] [Suspend2] Write module configurations in an image header Nigel Cunningham
2006-06-26 22:36 ` [Suspend2][ 12/19] [Suspend2] Read module configs from " Nigel Cunningham
2006-06-26 22:36 ` [Suspend2][ 13/19] [Suspend2] Write " Nigel Cunningham
2006-06-26 22:36 ` [Suspend2][ 14/19] [Suspend2] Sanity check " Nigel Cunningham
2006-06-26 22:36 ` [Suspend2][ 15/19] [Suspend2] Core of code for reading pageset1 Nigel Cunningham
2006-06-26 22:36 ` [Suspend2][ 16/19] [Suspend2] Read pageset1 Nigel Cunningham
2006-06-26 22:36 ` [Suspend2][ 17/19] [Suspend2] Get image_exists data Nigel Cunningham
2006-06-26 22:36 ` [Suspend2][ 18/19] [Suspend2] Read pageset2 Nigel Cunningham
2006-06-26 22:37 ` [Suspend2][ 19/19] [Suspend2] I/O header file Nigel Cunningham

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).