[PATCH] [34/48] Suspend2 2.1.9.8 for 2.6.12: 610-extent.patch

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



diff -ruNp 611-io.patch-old/kernel/power/suspend2_core/io.c 611-io.patch-new/kernel/power/suspend2_core/io.c
--- 611-io.patch-old/kernel/power/suspend2_core/io.c	1970-01-01 10:00:00.000000000 +1000
+++ 611-io.patch-new/kernel/power/suspend2_core/io.c	2005-07-05 23:48:59.000000000 +1000
@@ -0,0 +1,1006 @@
+/*
+ * kernel/power/io.c
+ *
+ * Copyright (C) 1998-2001 Gabor Kuti <[email protected]>
+ * Copyright (C) 1998,2001,2002 Pavel Machek <[email protected]>
+ * Copyright (C) 2002-2003 Florent Chabaud <[email protected]>
+ * Copyright (C) 2002-2005 Nigel Cunningham <[email protected]>
+ *
+ * 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 "version.h"
+#include "plugins.h"
+#include "pageflags.h"
+#include "io.h"
+#include "ui.h"
+#include "suspend2_common.h"
+#include "suspend.h"
+
+/* attempt_to_parse_resume_device
+ *
+ * Can we suspend, using the current resume2= parameter?
+ */
+void attempt_to_parse_resume_device(void)
+{
+	struct list_head *writer;
+	struct suspend_plugin_ops * this_writer;
+	int result = 0;
+
+	active_writer = NULL;
+	clear_suspend_state(SUSPEND_RESUME_DEVICE_OK);
+	set_suspend_state(SUSPEND_DISABLED);
+	CLEAR_RESULT_STATE(SUSPEND_ABORTED);
+
+	if (!num_writers) {
+		printk(name_suspend "No writers have been registered. Suspending will be disabled.\n");
+		return;
+	}
+	
+	if (!resume2_file[0]) {
+		printk(name_suspend "Resume2 parameter is empty. Suspending will be disabled.\n");
+		return;
+	}
+
+	list_for_each(writer, &suspend_writers) {
+		this_writer = list_entry(writer, struct suspend_plugin_ops,
+				ops.writer.writer_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->ops.writer.parse_image_location(
+				resume2_file, (num_writers == 1));
+
+		switch (result) {
+			case -EINVAL:
+				/* 
+				 * For this writer, but not a valid 
+				 * configuration. Error already printed.
+				 */
+
+				return;
+
+			case 0:
+				/*
+				 * For this writer and valid.
+				 */
+
+				active_writer = this_writer;
+
+				set_suspend_state(SUSPEND_RESUME_DEVICE_OK);
+				clear_suspend_state(SUSPEND_DISABLED);
+				printk(name_suspend "Suspending enabled.\n");
+
+				return;
+		}
+	}
+	printk(name_suspend "No matching enabled writer found. Suspending disabled.\n");
+}
+
+/* suspend2_cleanup_finished_io
+ *
+ * Description:	Very simple helper function to save #including all the
+ * 		suspend code in fs/buffer.c and anywhere else we might
+ * 		want to wait on suspend I/O in future.
+ */
+
+void suspend2_cleanup_finished_io(void)
+{
+	active_writer->ops.writer.wait_on_io(0);
+}
+
+/* noresume_reset_plugins
+ *
+ * Description:	When we read the start of an image, plugins (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_plugins(void)
+{
+	struct suspend_plugin_ops * this_filter;
+	
+	list_for_each_entry(this_filter, &suspend_filters, ops.filter.filter_list) {
+		if (this_filter->ops.filter.noresume_reset)
+			this_filter->ops.filter.noresume_reset();
+	}
+
+	if (active_writer && active_writer->ops.writer.noresume_reset)
+		active_writer->ops.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 = suspend2_orig_mem_free;
+	strncpy(sh->machine, system_utsname.machine, 65);
+	strncpy(sh->version, system_utsname.version, 65);
+	sh->num_cpus = num_online_cpus();
+	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;
+	for (i = 0; i < 4; i++)
+		sh->io_time[i/2][i%2] =
+		       suspend_io_time[i/2][i%2];
+}
+
+/* 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 nextupdate = 0, size, ret = 0, i, base = 0;
+	int barmax = pagedir1.pageset_size + pagedir2.pageset_size;
+	int start_time, end_time, pc, step = 1;
+	long error = 0;
+	struct suspend_plugin_ops * this_plugin, * first_filter = get_next_filter(NULL);
+	dyn_pageflags_t *pageflags;
+	int current_page_index = -1;
+
+	size = pagedir->pageset_size;
+	if (!size)
+		return 0;
+
+	if (whichtowrite == 1) {
+		suspend2_prepare_status(1, 0, "Writing kernel & process data...");
+		base = pagedir2.pageset_size;
+		if (TEST_ACTION_STATE(SUSPEND_TEST_FILTER_SPEED))
+			pageflags = &pageset1_map;
+		else
+			pageflags = &pageset1_copy_map;
+	} else {
+		suspend2_prepare_status(1, 1, "Writing caches...");
+		pageflags = &pageset2_map;
+		bytes_in = bytes_out = 0;
+	}	
+	
+	start_time = jiffies;
+
+	/* Initialise page transformers */
+	list_for_each_entry(this_plugin, &suspend_filters, ops.filter.filter_list) {
+		if (this_plugin->disabled)
+			continue;
+		if (this_plugin->write_init)
+			if (this_plugin->write_init(whichtowrite)) {
+				SET_RESULT_STATE(SUSPEND_ABORTED);
+				goto write_pageset_free_buffers;
+			}
+	}
+
+	/* Initialise writer */
+	active_writer->write_init(whichtowrite);
+
+	/* Initialise other plugins */
+	list_for_each_entry(this_plugin, &suspend_plugins, plugin_list) {
+		if (this_plugin->disabled)
+			continue;
+		if ((this_plugin->type == FILTER_PLUGIN) ||
+		    (this_plugin->type == WRITER_PLUGIN))
+			continue;
+		if (this_plugin->write_init)
+			if (this_plugin->write_init(whichtowrite)) {
+				SET_RESULT_STATE(SUSPEND_ABORTED);
+				goto write_pageset_free_buffers;
+			}
+	}
+
+	current_page_index = __get_next_bit_on(*pageflags, -1);
+
+	pc = size / 5;
+
+	/* Write the data */
+	for (i=0; i<size; i++) {
+		int was_mapped = 0;
+		struct page * page = pfn_to_page(current_page_index);
+
+		/* Status update */
+		if ((i+base) >= nextupdate)
+			nextupdate = suspend2_update_status(i + base, barmax, 
+				" %d/%d MB ", MB(base+i+1), MB(barmax));
+
+		if ((i + 1) == pc) {
+			printk("%d%%...", 20 * step);
+			step++;
+			pc = size * step / 5;
+		}
+
+		/* Write */
+		was_mapped = suspend_map_kernel_page(page, 1);
+		ret = first_filter->ops.filter.write_chunk(page);
+		if (!was_mapped)
+			suspend_map_kernel_page(page, 0);
+
+		if (ret) {
+			printk("Write chunk returned %d.\n", ret);
+			abort_suspend("Failed to write a chunk of the "
+					"image.");
+			error = -1;
+			goto write_pageset_free_buffers;
+		}
+
+		/* Interactivity */
+		check_shift_keys(0, NULL);
+
+		if (TEST_RESULT_STATE(SUSPEND_ABORTED)) {
+			abort_suspend("Aborting as requested.");
+			error = -1;
+			goto write_pageset_free_buffers;
+		}
+
+		/* Prepare next */
+		current_page_index = __get_next_bit_on(*pageflags, current_page_index);
+	}
+
+	printk("done.\n");
+
+	suspend2_update_status(base+size, barmax, " %d/%d MB ",
+			MB(base+size), MB(barmax));
+
+write_pageset_free_buffers:
+	
+	/* Cleanup other plugins */
+	list_for_each_entry(this_plugin, &suspend_plugins, plugin_list) {
+		if (this_plugin->disabled)
+			continue;
+		if ((this_plugin->type == FILTER_PLUGIN) ||
+		    (this_plugin->type == WRITER_PLUGIN))
+			continue;
+		if (this_plugin->write_cleanup)
+			this_plugin->write_cleanup();
+	}
+
+	/* Flush data and cleanup */
+	list_for_each_entry(this_plugin, &suspend_filters, ops.filter.filter_list) {
+		if (this_plugin->disabled)
+			continue;
+		if (this_plugin->write_cleanup)
+			this_plugin->write_cleanup();
+	}
+	active_writer->write_cleanup();
+
+	/* Statistics */
+	end_time = jiffies;
+	
+	if ((end_time - start_time) && (!TEST_RESULT_STATE(SUSPEND_ABORTED))) {
+		suspend_io_time[0][0] += size,
+		suspend_io_time[0][1] += (end_time - start_time);
+	}
+
+	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 nextupdate = 0, result = 0, base = 0;
+	int start_time, end_time, finish_at = pagedir->pageset_size;
+	int barmax = pagedir1.pageset_size + pagedir2.pageset_size;
+	int i, pc, step = 1;
+	struct suspend_plugin_ops * this_plugin, * first_filter = get_next_filter(NULL);
+	dyn_pageflags_t *pageflags;
+	int current_page_index;
+
+	if (whichtoread == 1) {
+		suspend2_prepare_status(1, 1, "Reading kernel & process data...");
+		pageflags = &pageset1_copy_map;
+	} else {
+		suspend2_prepare_status(1, 0, "Reading caches...");
+		if (overwrittenpagesonly)
+			barmax = finish_at = min(pageset1_size, pageset2_size);
+		else {
+			base = pagedir1.pageset_size;
+		}
+		pageflags = &pageset2_map;
+	}	
+	
+	start_time=jiffies;
+
+	/* Initialise page transformers */
+	list_for_each_entry(this_plugin, &suspend_filters, ops.filter.filter_list) {
+		if (this_plugin->disabled)
+			continue;
+		if (this_plugin->read_init && 
+				this_plugin->read_init(whichtoread)) {
+			abort_suspend("Failed to initialise a filter.");
+			result = 1;
+			goto read_pageset_free_buffers;
+		}
+	}
+
+	/* Initialise writer */
+	if (active_writer->read_init(whichtoread)) {
+		abort_suspend("Failed to initialise the writer."); 
+		result = 1;
+		goto read_pageset_free_buffers;
+	}
+
+	/* Initialise other plugins */
+	list_for_each_entry(this_plugin, &suspend_plugins, plugin_list) {
+		if (this_plugin->disabled)
+			continue;
+		if ((this_plugin->type == FILTER_PLUGIN) ||
+		    (this_plugin->type == WRITER_PLUGIN))
+			continue;
+		if (this_plugin->read_init)
+			if (this_plugin->read_init(whichtoread)) {
+				SET_RESULT_STATE(SUSPEND_ABORTED);
+				goto read_pageset_free_buffers;
+			}
+	}
+
+	current_page_index = __get_next_bit_on(*pageflags, -1);
+
+	pc = finish_at / 5;
+
+	/* Read the pages */
+	for (i=0; i< finish_at; i++) {
+		int was_mapped = 0;
+		struct page * page = pfn_to_page(current_page_index);
+
+		/* Status */
+		if ((i+base) >= nextupdate)
+			nextupdate = suspend2_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;
+		}
+		
+		was_mapped = suspend_map_kernel_page(page, 1);
+		result = first_filter->ops.filter.read_chunk(page, SUSPEND_ASYNC);
+		if (!was_mapped)
+			suspend_map_kernel_page(page, 0);
+
+		if (result) {
+			panic("Failed to read chunk %d/%d of the image. (%d)",
+					i, finish_at, result);
+			goto read_pageset_free_buffers;
+		}
+
+		/* Interactivity*/
+		check_shift_keys(0, NULL);
+
+		/* Prepare next */
+		current_page_index = __get_next_bit_on(*pageflags, current_page_index);
+	}
+
+	printk("done.\n");
+
+	suspend2_update_status(base+finish_at, barmax, " %d/%d MB ",
+			MB(base+finish_at), MB(barmax));
+
+read_pageset_free_buffers:
+
+	/* Cleanup other plugins */
+	list_for_each_entry(this_plugin, &suspend_plugins, plugin_list) {
+		if (this_plugin->disabled)
+			continue;
+		if ((this_plugin->type == FILTER_PLUGIN) ||
+		    (this_plugin->type == WRITER_PLUGIN))
+			continue;
+		if (this_plugin->read_cleanup)
+			this_plugin->read_cleanup();
+	}
+
+	/* Finish I/O, flush data and cleanup reads. */
+	list_for_each_entry(this_plugin, &suspend_filters, ops.filter.filter_list) {
+		if (this_plugin->disabled)
+			continue;
+		if (this_plugin->read_cleanup &&
+				this_plugin->read_cleanup()) {
+			abort_suspend("Failed to cleanup a filter.");
+			result = 1;
+		}
+	}
+
+	if (active_writer->read_cleanup()) {
+		abort_suspend("Failed to cleanup the writer.");
+		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;
+}
+
+/* write_plugin_configs()
+ *
+ * Description:	Store the configuration for each plugin in the image header.
+ * Returns:	Int: Zero on success, Error value otherwise.
+ */
+static int write_plugin_configs(void)
+{
+	struct suspend_plugin_ops * this_plugin;
+	char * buffer = (char *) get_zeroed_page(GFP_ATOMIC);
+	int len, index = 1;
+	struct plugin_header plugin_header;
+
+	if (!buffer) {
+		printk("Failed to allocate a buffer for saving "
+				"plugin configuration info.\n");
+		return -ENOMEM;
+	}
+		
+	/* 
+	 * We have to know which data goes with which plugin, so we at
+	 * least write a length of zero for a plugin. Note that we are
+	 * also assuming every plugin's config data takes <= PAGE_SIZE.
+	 */
+
+	/* For each plugin (in registration order) */
+	list_for_each_entry(this_plugin, &suspend_plugins, plugin_list) {
+
+		/* Get the data from the plugin */
+		len = 0;
+		if (this_plugin->save_config_info)
+			len = this_plugin->save_config_info(buffer);
+
+		/* Save the details of the plugin */
+		plugin_header.disabled = this_plugin->disabled;
+		plugin_header.type = this_plugin->type;
+		plugin_header.index = index++;
+		strncpy(plugin_header.name, this_plugin->name, 
+					sizeof(plugin_header.name));
+		active_writer->ops.writer.write_header_chunk(
+				(char *) &plugin_header,
+				sizeof(plugin_header));
+
+		/* Save the size of the data and any data returned */
+		active_writer->ops.writer.write_header_chunk((char *) &len,
+				sizeof(int));
+		if (len)
+			active_writer->ops.writer.write_header_chunk(
+					buffer, len);
+	}
+
+	/* Write a blank header to terminate the list */
+	plugin_header.name[0] = '\0';
+	active_writer->ops.writer.write_header_chunk(
+			(char *) &plugin_header,
+			sizeof(plugin_header));
+
+	free_pages((unsigned long) buffer, 0);
+	return 0;
+}
+
+/* read_plugin_configs()
+ *
+ * Description:	Reload plugin configurations from the image header.
+ * Returns:	Int. Zero on success, error value otherwise.
+ */
+
+static int read_plugin_configs(void)
+{
+	struct suspend_plugin_ops * this_plugin;
+	char * buffer = (char *) get_zeroed_page(GFP_ATOMIC);
+	int len, result = 0;
+	struct plugin_header plugin_header;
+
+	if (!buffer) {
+		printk("Failed to allocate a buffer for reloading plugin "
+				"configuration info.\n");
+		return -ENOMEM;
+	}
+		
+	/* All plugins are initially disabled. That way, if we have a plugin
+	 * 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_plugin, &suspend_plugins, plugin_list)
+		this_plugin->disabled = 1;
+	
+	/* Get the first plugin header */
+	result = active_writer->ops.writer.read_header_chunk(
+			(char *) &plugin_header, sizeof(plugin_header));
+	if (!result) {
+		printk("Failed to read the next plugin header.\n");
+		free_pages((unsigned long) buffer, 0);
+		return -EINVAL;
+	}
+
+	/* For each plugin (in registration order) */
+	while (plugin_header.name[0]) {
+		
+		/* Find the plugin */
+		this_plugin = find_plugin_given_name(plugin_header.name);
+		
+		if (!this_plugin) {
+			/* 
+			 * Is it used? Only need to worry about filters. The active
+			 * writer must be loaded!
+			 */
+			if ((!plugin_header.disabled) &&
+			    (plugin_header.type == FILTER_PLUGIN)) {
+				suspend_early_boot_message(1, SUSPEND_CONTINUE_REQ,
+					"It looks like we need plugin %s for "
+					"reading the image but it hasn't been "
+					"registered.\n",
+					plugin_header.name);
+				if (!(test_suspend_state(SUSPEND_CONTINUE_REQ))) {
+					active_writer->ops.writer.invalidate_image();
+					result = -EINVAL;
+					noresume_reset_plugins();
+					free_pages((unsigned long) buffer, 0);
+					return -EINVAL;
+				}
+			} else
+				printk("Plugin %s configuration data found, but the plugin "
+					"hasn't registered. Looks like it was disabled, so "
+					"we're ignoring it's data.",
+					plugin_header.name);
+		}
+		
+		/* Get the length of the data (if any) */
+		result = active_writer->ops.writer.read_header_chunk(
+				(char *) &len, sizeof(int));
+		if (!result) {
+			printk("Failed to read the length of the plugin %s's"
+					" configuration data.\n",
+					plugin_header.name);
+			free_pages((unsigned long) buffer, 0);
+			return -EINVAL;
+		}
+
+		/* Read any data and pass to the plugin (if we found one) */
+		if (len) {
+			active_writer->ops.writer.read_header_chunk(buffer, len);
+			if (this_plugin) {
+				if (!this_plugin->save_config_info) {
+					printk("Huh? Plugin %s appears to have a "
+						"save_config_info, but not a "
+						"load_config_info function!\n",
+						this_plugin->name);
+				} else
+					this_plugin->load_config_info(buffer, len);
+			}
+		}
+
+		if (this_plugin) {
+			/* Now move this plugin to the tail of its lists. This will put it
+			 * in order. Any new plugins 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_plugin_tail(this_plugin);
+
+			/* 
+			 * We apply the disabled state; plugins don't need to save whether they
+			 * were disabled and if they do, we override them anyway.
+			 */
+			this_plugin->disabled = plugin_header.disabled;
+		}
+
+		/* Get the next plugin header */
+		result = active_writer->ops.writer.read_header_chunk(
+				(char *) &plugin_header, sizeof(plugin_header));
+
+		if (!result) {
+			printk("Failed to read the next plugin header.\n");
+			free_pages((unsigned long) buffer, 0);
+			return -EINVAL;
+		}
+
+	}
+
+	free_pages((unsigned long) buffer, 0);
+	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 = active_writer->ops.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);
+	active_writer->ops.writer.write_header_chunk(header_buffer,
+			sizeof(struct suspend_header));
+
+	free_pages((unsigned long) header_buffer, 0);
+
+	/* Write plugin configurations */
+	if ((ret = write_plugin_configs())) {
+		abort_suspend("Failed to write plugin configs.");
+		goto write_image_header_abort;
+	}
+
+	save_dyn_pageflags(pageset1_map);
+
+	if ((ret = active_writer->ops.writer.serialise_extents())) {
+		abort_suspend("Active writer's prepare_save_extents "
+				"function failed.");
+		goto write_image_header_abort;
+	}
+
+	/* Flush data and let writer cleanup */
+	if (active_writer->ops.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");
+	suspend2_update_status(total, total, NULL);
+
+	return 0;
+
+write_image_header_abort:
+	active_writer->ops.writer.write_header_cleanup();
+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 int sanity_check(struct suspend_header *sh)
+{
+	if (sh->version_code != LINUX_VERSION_CODE)
+		return suspend_early_boot_message(1, SUSPEND_CONTINUE_REQ,
+				"Incorrect kernel version");
+	
+	if (sh->num_physpages != num_physpages)
+		return suspend_early_boot_message(1, SUSPEND_CONTINUE_REQ,
+				"Incorrect memory size");
+
+	if (strncmp(sh->machine, system_utsname.machine, 65))
+		return suspend_early_boot_message(1, SUSPEND_CONTINUE_REQ,
+				"Incorrect machine type");
+
+	if (strncmp(sh->version, system_utsname.version, 65))
+		return suspend_early_boot_message(1, SUSPEND_CONTINUE_REQ,
+			      "Incorrect version");
+
+	if (sh->num_cpus != num_online_cpus())
+		return suspend_early_boot_message(1, SUSPEND_CONTINUE_REQ,  
+				"Incorrect number of cpus");
+
+	if (sh->page_size != PAGE_SIZE)
+		return suspend_early_boot_message(1, SUSPEND_CONTINUE_REQ,
+				"Incorrect PAGE_SIZE");
+
+	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);
+	struct suspend_header * suspend_header;
+
+	if (!header_buffer)
+		return -ENOMEM;
+	
+	/* Check for an image */
+	if (!(result = active_writer->ops.writer.image_exists())) {
+		result = -ENODATA;
+		noresume_reset_plugins();
+		goto out;
+	}
+
+	/* Check for noresume command line option */
+	if (test_suspend_state(SUSPEND_NORESUME_SPECIFIED)) {
+		active_writer->ops.writer.invalidate_image();
+		result = -EINVAL;
+		noresume_reset_plugins();
+		goto out;
+	}
+
+#ifdef CONFIG_SOFTWARE_SUSPEND_CHECK_RESUME_SAFE
+	/* Check whether we've got filesystems mounted that make
+	 * resuming unsafe */
+
+	suspend_check_mounts();
+
+	if (!test_suspend_state(SUSPEND_CONTINUE_REQ)) {
+		active_writer->ops.writer.invalidate_image();
+		result = -EINVAL;
+		noresume_reset_plugins();
+		goto out;
+	}
+
+	clear_suspend_state(SUSPEND_CONTINUE_REQ);
+#endif
+
+	/* 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))) {
+			active_writer->ops.writer.invalidate_image();
+			result = -EINVAL;
+			noresume_reset_plugins();
+			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 or set up
+	 * a network connection here.
+	 * 
+	 * 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 = active_writer->ops.writer.read_header_init())) {
+		noresume_reset_plugins();
+		goto out;
+	}
+	
+	/* Read suspend header */
+	if ((result = active_writer->ops.writer.read_header_chunk(
+			header_buffer, sizeof(struct suspend_header))) < 0) {
+		noresume_reset_plugins();
+		goto out;
+	}
+	
+	suspend_header = (struct suspend_header *) header_buffer;
+
+	/*
+	 * NB: This call may also result in a reboot rather than returning.
+	 */
+
+	if (sanity_check(suspend_header)) { /* Is this the same machine? */
+		active_writer->ops.writer.invalidate_image();
+		result = -EINVAL;
+		noresume_reset_plugins();
+		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.
+	 */
+	
+	suspend2_orig_mem_free = suspend_header->orig_mem_free;
+	memcpy((char *) &pagedir1,
+		(char *) &suspend_header->pagedir, sizeof(pagedir1));
+	suspend_result = suspend_header->param0;
+	if (!test_suspend_state(SUSPEND_ACT_USED))
+		suspend_action = suspend_header->param1;
+	if (!test_suspend_state(SUSPEND_DBG_USED))
+		suspend_debug_state = suspend_header->param2;
+	if (!test_suspend_state(SUSPEND_LVL_USED))
+		suspend_default_console_level = 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];
+
+	set_suspend_state(SUSPEND_NOW_RESUMING);
+
+	/* Read plugin configurations */
+	if ((result = read_plugin_configs())) {
+		noresume_reset_plugins();
+		pagedir1.pageset_size =
+			pagedir2.pageset_size = 0;
+		goto out;
+	}
+
+	suspend2_prepare_console();
+
+	check_shift_keys(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 */
+	suspend_allocate_dyn_pageflags(&pageset1_map);
+	load_dyn_pageflags(pageset1_map);
+
+	/* Relocate it so that it's not overwritten while we're using it to
+	 * copy the original contents back */
+	relocate_dyn_pageflags(&pageset1_map);
+	
+	suspend_allocate_dyn_pageflags(&pageset1_copy_map);
+	relocate_dyn_pageflags(&pageset1_copy_map);
+
+	/* Read extent pages */
+	if ((result = active_writer->ops.writer.load_extents())) {
+		noresume_reset_plugins();
+		abort_suspend("Active writer's load_extents "
+				"function failed.");
+		goto out;
+	}
+
+	/* Clean up after reading the header */
+	if ((result = active_writer->ops.writer.read_header_cleanup())) {
+		noresume_reset_plugins();
+		goto out;
+	}
+
+	check_shift_keys(1, "About to read pagedir.");
+
+	/* 
+	 * Get the addresses of pages into which we will load the kernel to
+	 * be copied back
+	 */
+	if (suspend2_get_pageset1_load_addresses()) {
+		result = -ENOMEM;
+		noresume_reset_plugins();
+		goto out;
+	}
+
+	/* Read the original kernel back */
+	check_shift_keys(1, "About to read pageset 1.");
+
+	if (read_pageset(&pagedir1, 1, 0)) {
+		suspend2_prepare_status(1, 1, "Failed to read pageset 1.");
+		result = -EPERM;
+		noresume_reset_plugins();
+		goto out;
+	}
+
+	check_shift_keys(1, "About to restore original kernel.");
+	result = 0;
+
+	if (active_writer->ops.writer.mark_resume_attempted)
+		active_writer->ops.writer.mark_resume_attempted();
+
+out:
+	free_pages((unsigned long) header_buffer, 0);
+	return result;
+}
+
+/* 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;
+}
+
+/* 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 (!pageset2_size)
+		return 0;
+
+	result = read_pageset(&pagedir2, 2, overwrittenpagesonly);
+
+	suspend2_update_status(100, 100, NULL);
+	check_shift_keys(1, "Pagedir 2 read.");
+
+	return result;
+}
diff -ruNp 611-io.patch-old/kernel/power/suspend2_core/io.h 611-io.patch-new/kernel/power/suspend2_core/io.h
--- 611-io.patch-old/kernel/power/suspend2_core/io.h	1970-01-01 10:00:00.000000000 +1000
+++ 611-io.patch-new/kernel/power/suspend2_core/io.h	2005-07-04 23:14:19.000000000 +1000
@@ -0,0 +1,44 @@
+/*
+ * kernel/power/io.h
+ */
+
+#include "pagedir.h"
+
+/* Non-plugin 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];
+	
+	/* Implementation specific variables */
+#ifdef KERNEL_POWER_SWSUSP_C
+	suspend_pagedir_t *suspend_pagedir;
+	unsigned int num_pbes;
+#else
+	struct pagedir pagedir;
+#endif
+};
+
+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 void attempt_to_parse_resume_device(void);
+extern dev_t name_to_dev_t(char *line);
+extern __nosavedata unsigned long bytes_in, bytes_out;
+

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]
  Powered by Linux