lkml.org 
[lkml]   [2005]   [Jul]   [5]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Subject[PATCH] [34/48] Suspend2 2.1.9.8 for 2.6.12: 610-extent.patch
    Date
    From
    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 <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-2005 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 "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 majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

    \
     
     \ /
      Last update: 2005-07-06 06:03    [W:5.177 / U:0.216 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site