All of lore.kernel.org
 help / color / mirror / Atom feed
From: Nigel Cunningham <ncunningham@linuxmail.org>
To: Linux Kernel Mailing List <linux-kernel@vger.kernel.org>
Subject: Suspend 2 merge: 42/51: Suspend.c
Date: Thu, 25 Nov 2004 00:01:34 +1100	[thread overview]
Message-ID: <1101299659.5805.367.camel@desktop.cunninghams> (raw)
In-Reply-To: <1101292194.5805.180.camel@desktop.cunninghams>

Here's the heart of the core :> (No, that's not a typo).

- Device suspend/resume calls
- Power down
- Highest level routine
- all_settings proc entry handling


diff -ruN 832-suspend-old/kernel/power/suspend.c 832-suspend-new/kernel/power/suspend.c
--- 832-suspend-old/kernel/power/suspend.c	1970-01-01 10:00:00.000000000 +1000
+++ 832-suspend-new/kernel/power/suspend.c	2004-11-21 20:00:10.000000000 +1100
@@ -0,0 +1,2019 @@
+/*
+ * kernel/power/suspend2.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-2004 Nigel Cunningham <ncunningham@linuxmail.org>
+ *
+ * This file is released under the GPLv2.
+ *
+ * This file is to realize architecture-independent
+ * machine suspend feature using pretty near only high-level routines
+ *
+ * We'd like to thank the following people for their work:
+ * 
+ * Pavel Machek <pavel@ucw.cz>:
+ * Modifications, defectiveness pointing, being with Gabor at the very beginning,
+ * suspend to swap space, stop all tasks. Port to 2.4.18-ac and 2.5.17.
+ *
+ * Steve Doddi <dirk@loth.demon.co.uk>: 
+ * Support the possibility of hardware state restoring.
+ *
+ * Raph <grey.havens@earthling.net>:
+ * Support for preserving states of network devices and virtual console
+ * (including X and svgatextmode)
+ *
+ * Kurt Garloff <garloff@suse.de>:
+ * Straightened the critical function in order to prevent compilers from
+ * playing tricks with local variables.
+ *
+ * Andreas Mohr <a.mohr@mailto.de>
+ *
+ * Alex Badea <vampire@go.ro>:
+ * Fixed runaway init
+ *
+ * Jeff Snyder <je4d@pobox.com>
+ * ACPI patch
+ *
+ * Nathan Friess <natmanz@shaw.ca>
+ * Some patches.
+ *
+ * Michael Frank <mhf@linuxmail.org>
+ * Extensive testing and help with improving stability.
+ *
+ * Variable definitions which are needed if PM is enabled but 
+ * SOFTWARE_SUSPEND is disabled are found near the top of process.c.
+ */
+
+#define SUSPEND_MAIN_C
+//#define DEBUG_DEVICE_TREE
+
+#include <linux/suspend.h>
+#include <linux/reboot.h>
+#include <linux/module.h>
+#include <linux/console.h>
+#include <linux/version.h>
+#include <linux/device.h>
+#include <linux/highmem.h>
+#include <asm/uaccess.h>
+
+#include "suspend.h"
+#include "block_io.h"
+#include "plugins.h"
+#include "proc.h"
+#include "pageflags.h"
+
+#ifdef  CONFIG_X86
+#include <asm/i387.h> /* for kernel_fpu_end */
+#endif
+
+static unsigned long suspend_powerdown_method = 5; /* S5 = off */
+static int suspend_acpi_state_used = 0;
+
+static u32 pm_disk_mode_save;
+struct partial_device_tree * suspend_device_tree;
+EXPORT_SYMBOL(suspend_device_tree);
+
+#ifdef CONFIG_SMP
+static void ensure_on_processor_zero(void)
+{
+	set_cpus_allowed(current, cpumask_of_cpu(0));
+	BUG_ON(smp_processor_id() != 0);
+}
+#else
+#define ensure_on_processor_zero() do { } while(0)
+#endif
+
+#ifdef CONFIG_ACPI
+extern u32 acpi_leave_sleep_state (u8 sleep_state);
+#endif
+
+#ifdef DEBUG_DEVICE_TREE
+#include "../../drivers/base/power/power.h"
+#include <linux/device.h>
+
+void display_device_tree(struct partial_device_tree * tree, char * header)
+{
+	struct device * dev;
+
+	if (header)
+		printk(header);
+	printk(" === Tree %p ===\n\n", tree);
+
+	printk(" -- Active\n");
+	list_for_each_entry(dev, &tree->dpm_active, power.entry) {
+		printk("   %p->%p", dev, dev->parent);
+		printk(" %s\n", dev->kobj.k_name ? dev->kobj.k_name : "<null>");
+	}
+	printk("\n -- DPM Off\n");
+	list_for_each_entry(dev, &tree->dpm_off, power.entry) {
+		printk("   %p->%p", dev, dev->parent);
+		printk(" %s\n", dev->kobj.k_name ? dev->kobj.k_name : "<null>");
+	}
+	
+	printk("\n -- DPM Off IRQ\n");
+	list_for_each_entry(dev, &tree->dpm_off_irq, power.entry) {
+		printk("   %p->%p", dev, dev->parent);
+		printk(" %s\n", dev->kobj.k_name ? dev->kobj.k_name : "<null>");
+	}
+	printk("\n--- Done ---\n");
+}
+#else
+#define display_device_tree(tree, header) do { } while(0)
+#endif
+
+/*	suspend_drivers_resume
+ *	@stage - One of...
+ */
+
+enum {
+	SUSPEND_DRIVERS_USED_DEVICES_IRQS_DISABLED,
+	SUSPEND_DRIVERS_USED_DEVICES_IRQS_ENABLED,
+	SUSPEND_DRIVERS_UNUSED_DEVICES_IRQS_DISABLED,
+	SUSPEND_DRIVERS_UNUSED_DEVICES_IRQS_ENABLED,
+	SUSPEND_DRIVERS_PRE_POWERDOWN,
+};
+
+void suspend_drivers_resume(int stage)
+{
+	switch (stage) {
+		case SUSPEND_DRIVERS_USED_DEVICES_IRQS_DISABLED:
+			BUG_ON(!irqs_disabled());
+			if (!TEST_ACTION_STATE(SUSPEND_DISABLE_SYSDEV_SUPPORT))
+				sysdev_resume();
+			dpm_power_up_tree(suspend_device_tree);
+			break;
+
+		case SUSPEND_DRIVERS_USED_DEVICES_IRQS_ENABLED:
+			BUG_ON(irqs_disabled());
+			display_device_tree(suspend_device_tree,
+				"suspend_drivers_resume stage 1.");
+			device_resume_tree(suspend_device_tree);
+			display_device_tree(suspend_device_tree,
+				"Post resume tree call.");
+			break;
+
+		case SUSPEND_DRIVERS_UNUSED_DEVICES_IRQS_DISABLED:
+			BUG_ON(!irqs_disabled());
+			display_device_tree(&default_device_tree,
+				"suspend_drivers_resume stage 2.\n");
+			dpm_power_up_tree(&default_device_tree);
+			break;
+
+		case SUSPEND_DRIVERS_UNUSED_DEVICES_IRQS_ENABLED:
+			BUG_ON(irqs_disabled());
+			device_resume_tree(&default_device_tree);
+			display_device_tree(&default_device_tree,
+				"Post power up.\n");
+#ifdef CONFIG_ACPI
+			if (suspend_acpi_state_used)
+				acpi_leave_sleep_state(suspend_acpi_state_used);
+#endif
+			display_device_tree(&default_device_tree,
+				"suspend_drivers_resume stage 3.\n");
+			device_resume_tree(&default_device_tree);
+			display_device_tree(&default_device_tree,
+				"Post resume default device tree.\n");
+#ifdef CONFIG_ACPI
+			if (suspend_acpi_state_used &&
+				pm_ops && pm_ops->finish)
+				pm_ops->finish(suspend_acpi_state_used);
+#endif
+			break;
+	}
+}
+
+/*	suspend_drivers_suspend
+ *	@stage - one of:
+ *		1: Power down drivers not used in writing the image
+ *		2: Quiesce drivers used in writing the image
+ *		   (prior to making atomic copy)
+ *		3: Power down drivers used in writing the image and
+ *		   enter the suspend mode if configured to do so.
+ *
+ */
+static int suspend_drivers_suspend(int stage)
+{
+	int result = 0;
+
+	switch (stage) {
+		case SUSPEND_DRIVERS_UNUSED_DEVICES_IRQS_DISABLED:
+			BUG_ON(!irqs_disabled());
+			if (!result)
+				result = device_power_down_tree(
+					PM_SUSPEND_DISK, &default_device_tree);
+			display_device_tree(&default_device_tree,
+				"Post suspend power down device tree.\n");
+			break;
+
+		case SUSPEND_DRIVERS_UNUSED_DEVICES_IRQS_ENABLED:
+			BUG_ON(irqs_disabled());
+			display_device_tree(&default_device_tree,
+				"suspend_drivers_suspend stage 1.\n");
+			result = device_suspend_tree(
+					PM_SUSPEND_DISK, &default_device_tree);
+			break;
+
+		case SUSPEND_DRIVERS_USED_DEVICES_IRQS_DISABLED:
+			BUG_ON(!irqs_disabled());
+			result = device_power_down_tree(PM_SUSPEND_DISK, suspend_device_tree);
+			if (!TEST_ACTION_STATE(SUSPEND_DISABLE_SYSDEV_SUPPORT))
+				sysdev_suspend(PM_SUSPEND_DISK);
+			break;
+
+		case SUSPEND_DRIVERS_USED_DEVICES_IRQS_ENABLED:
+			BUG_ON(irqs_disabled());
+			display_device_tree(suspend_device_tree,
+				"suspend_drivers_suspend stage 2.\n");
+			result = device_suspend_tree(
+					PM_SUSPEND_DISK, suspend_device_tree);
+			display_device_tree(suspend_device_tree,
+				"Post suspend device tree.\n");
+			break;
+
+		case SUSPEND_DRIVERS_PRE_POWERDOWN: /* Power down system */
+			BUG_ON(irqs_disabled());
+			display_device_tree(suspend_device_tree,
+				"suspend_drivers_suspend stage 3.\n");
+
+			result = device_suspend_tree(
+				PM_SUSPEND_DISK, suspend_device_tree);
+			break;
+	}
+	return result;
+}
+
+#ifdef CONFIG_SOFTWARE_SUSPEND_DEBUG
+void show_pcp_lists(void)
+{
+	int cpu, temperature;
+	struct zone *zone;
+
+	for_each_zone(zone) {
+		printk("%s per-cpu:", zone->name);
+
+		if (!zone->present_pages) {
+			printk(" empty\n");
+			continue;
+		} else
+			printk("\n");
+
+		for (cpu = 0; cpu < NR_CPUS; ++cpu) {
+			struct per_cpu_pageset *pageset;
+
+			if (!cpu_possible(cpu))
+				continue;
+
+			pageset = zone->pageset + cpu;
+
+			for (temperature = 0; temperature < 2; temperature++)
+				printk("cpu %d %s: low %d, high %d, batch %d, count %d.\n",
+					cpu,
+					temperature ? "cold" : "hot",
+					pageset->pcp[temperature].low,
+					pageset->pcp[temperature].high,
+					pageset->pcp[temperature].batch,
+					pageset->pcp[temperature].count);
+		}
+	}
+}
+#else
+#define show_pcp_lists() do { } while(0)
+#endif
+
+/* -------------------------------------------------------------------------- */
+
+static int suspend_version_specific_initialise(void)
+{
+	struct class * class;
+	struct class_device * class_dev;
+
+	suspend_save_avenrun();
+
+	PRINTFREEMEM("after draining local pages");
+	suspend_store_free_mem(SUSPEND_FREE_DRAIN_PCP, 0);
+
+	if (TEST_DEBUG_STATE(SUSPEND_FREEZER))
+		show_pcp_lists();
+
+	if (pm_ops) {
+		pm_disk_mode_save = pm_ops->pm_disk_mode;
+		pm_ops->pm_disk_mode = PM_DISK_PLATFORM;
+	}
+			
+	BUG_ON(suspend_device_tree);
+	suspend_device_tree = device_create_tree();
+	if (IS_ERR(suspend_device_tree)) {
+		suspend_device_tree = NULL;
+		return -ENOMEM;
+	}
+
+	/* Now check for graphics class devices, so we can keep the display on while suspending */
+	class = class_find("graphics");
+	if (class) {
+		list_for_each_entry(class_dev, &class->children, node)
+			device_switch_trees(class_dev->dev, suspend_device_tree);
+		class_put(class);
+	}
+	return 0;
+}
+
+static void suspend_version_specific_cleanup(void)
+{
+	suspend_restore_avenrun();
+
+	if (pm_ops) pm_ops->pm_disk_mode = pm_disk_mode_save;
+			
+	if (suspend_device_tree) {
+		device_merge_tree(suspend_device_tree, &default_device_tree);
+		device_destroy_tree(suspend_device_tree);
+		display_device_tree(&default_device_tree,
+			" ==== POST DEVICE MERGE TREE ====\n");
+		suspend_device_tree = NULL;
+	}
+}
+/* Variables to be preserved over suspend */
+int pageset1_sizelow = 0, pageset2_sizelow = 0;
+
+unsigned long orig_mem_free = 0;
+
+extern void do_suspend2_lowlevel(int resume);
+extern unsigned long header_storage_for_plugins(void);
+extern int suspend_initialise_plugin_lists(void);
+extern void suspend_relinquish_console(void);
+extern volatile int suspend_io_time[2][2];
+void empty_suspend_memory_pool(void);
+int read_primary_suspend_image(void);
+extern void display_nosave_pages(void);
+extern int num_writers;
+
+extern void suspend_console_proc_init(void);
+extern void suspend_console_proc_exit(void);
+extern int suspend2_prepare_console(void);
+extern void suspend2_cleanup_console(void);
+
+unsigned long * in_use_map = NULL;
+unsigned long * pageset2_map = NULL;
+unsigned long * checksum_map = NULL;
+#ifdef CONFIG_DEBUG_PAGEALLOC
+unsigned long * unmap_map = NULL;
+#endif
+
+char * debug_info_buffer;
+
+int image_size_limit = 0;
+int max_async_ios = 128;
+
+/* Pagedir.c */
+extern void copy_pageset1(void);
+extern int allocate_local_pageflags(unsigned long ** pagemap, int setnosave);
+extern void free_pagedir(struct pagedir * p);
+extern int free_local_pageflags(unsigned long ** pagemap);
+
+/* Prepare_image.c */
+
+extern int prepare_image(void);
+
+unsigned long forced_ps1_size = 0, forced_ps2_size = 0;
+
+/* proc.c */
+extern int suspend_cleanup_proc(void);
+
+extern int suspend2_register_core(struct suspend2_core_ops * ops_pointer);
+extern void suspend2_unregister_core(void);
+
+#ifdef CONFIG_SOFTWARE_SUSPEND_DEBUG
+
+int suspend_free_mem_values[MAX_FREEMEM_SLOTS][2];
+/* These should match the enumerated type in suspend.h */
+static char * suspend_free_mem_descns[MAX_FREEMEM_SLOTS] = {
+	"Start/End      ", /* 0 */
+	"Console Allocn ",
+	"Drain pcp      ",
+	"InUse map      ",
+	"PS2 map        ",
+	"Checksum map   ", /* 5 */
+	"Reload pages   ",
+	"Init plugins   ",
+	"Memory pool    ",
+	"Freezer        ",
+	"Eat Memory     ", /* 10 */
+	"Syncing        ",
+	"Grabbed Memory ",
+	"Range Pages    ",
+	"Extra PD1 pages",
+	"Writer storage ", /* 15 */
+	"Header storage ",
+	"Checksum pages ",
+	"KStat data     ",
+	"Debug Info     ",
+	"Remove Image   ", /* 20 */
+	"I/O            ",
+	"I/O info       ",
+	"Start one      ",
+};
+
+/* store_free_mem
+ */
+
+
+void suspend_store_free_mem(int slot, int side)
+{
+	static int last_free_mem;
+	int this_free_mem = real_nr_free_pages() + suspend_amount_grabbed +
+			suspend_memory_pool_level(0);
+	int i;
+
+	BUG_ON(slot >= MAX_FREEMEM_SLOTS);
+
+	suspend_message(SUSPEND_MEMORY, SUSPEND_HIGH, 0,
+			"Last free mem was %d. Is now %d. ",
+			last_free_mem, this_free_mem);
+
+	if (slot == 0) {
+		if (!side)
+			for (i = 1; i < MAX_FREEMEM_SLOTS; i++) {
+				suspend_free_mem_values[i][0] = 0;
+				suspend_free_mem_values[i][1] = 0;
+			}
+		suspend_free_mem_values[slot][side] = this_free_mem;
+	} else
+		suspend_free_mem_values[slot][side] += this_free_mem - last_free_mem;
+	last_free_mem = this_free_mem;
+	suspend_message(SUSPEND_MEMORY, SUSPEND_HIGH, 0,
+		"%s value %d now %d.\n",
+		suspend_free_mem_descns[slot],
+		side,
+		suspend_free_mem_values[slot][side]);
+}
+
+/*
+ * display_free_mem
+ */
+static void display_free_mem(void)
+{
+	int i;
+
+
+	if (!TEST_DEBUG_STATE(SUSPEND_MEMORY))
+		return;
+	
+	suspend_message(SUSPEND_MEMORY, SUSPEND_HIGH, 0,
+		"Start:       %7d    End: %7d.\n",
+		suspend_free_mem_values[0][0],
+		suspend_free_mem_values[0][1]);
+	
+	for (i = 1; i < MAX_FREEMEM_SLOTS; i++)
+		if (suspend_free_mem_values[i][0] + suspend_free_mem_values[i][1])
+			suspend_message(SUSPEND_MEMORY, SUSPEND_HIGH, 0,
+				"%s %7d         %7d.\n",
+				suspend_free_mem_descns[i],
+				suspend_free_mem_values[i][0],
+				suspend_free_mem_values[i][1]);
+}
+#endif
+
+/*
+ * save_image
+ * Result code (int): Zero on success, non zero on failure.
+ * Functionality    : High level routine which performs the steps necessary
+ *                    to prepare and save the image after preparatory steps
+ *                    have been taken.
+ * Key Assumptions  : Processes frozen, sufficient memory available, drivers
+ *                    suspended.
+ * Called from      : do_suspend2_suspend_2
+ */
+extern struct pageset_sizes_result recalculate_stats(void);
+extern int write_pageset(struct pagedir * pagedir, int whichtowrite);
+extern int write_image_header(void);
+extern int read_secondary_pagedir(int overwrittenpagesonly);
+
+static int save_image(void)
+{
+	int temp_result;
+
+	if (RAM_TO_SUSPEND > max_mapnr) {
+		prepare_status(1, 1,
+			"Couldn't get enough free pages, on %ld pages short",
+			 RAM_TO_SUSPEND - max_mapnr);
+		goto abort_saving;
+	}
+	
+	suspend_message(SUSPEND_ANY_SECTION, SUSPEND_LOW, 1,
+		" - Final values: %d and %d.\n",
+		pageset1_size, 
+		pageset2_size);
+
+	/* Suspend devices we're not going to use in writing the image */
+	if (active_writer && active_writer->dpm_set_devices)
+		active_writer->dpm_set_devices();
+	suspend_drivers_suspend(SUSPEND_DRIVERS_UNUSED_DEVICES_IRQS_ENABLED);
+	local_irq_disable();
+	suspend_drivers_suspend(SUSPEND_DRIVERS_UNUSED_DEVICES_IRQS_DISABLED);
+	local_irq_enable();
+
+	check_shift_keys(1, "About to write pagedir2.");
+
+	temp_result = write_pageset(&pagedir2, 2);
+	
+	check_shift_keys(1, "About to copy pageset 1.");
+
+	if (temp_result == -1 || TEST_RESULT_STATE(SUSPEND_ABORTED))
+		goto abort_saving;
+
+	prepare_status(1, 0, "Doing atomic copy...");
+	
+	do_suspend2_lowlevel(0);
+
+	return 0;
+abort_saving:
+	suspend_drivers_resume(SUSPEND_DRIVERS_UNUSED_DEVICES_IRQS_ENABLED);
+	local_irq_disable();
+	suspend_drivers_resume(SUSPEND_DRIVERS_UNUSED_DEVICES_IRQS_DISABLED);
+	local_irq_enable();
+
+	return -1;		
+}
+
+int save_image_part1(void)
+{
+	int temp_result;
+	
+	suspend_map_atomic_copy_pages();
+
+	suspend_checksum_calculate_checksums();
+	
+	BUG_ON(!irqs_disabled());
+
+	if (!TEST_ACTION_STATE(SUSPEND_TEST_FILTER_SPEED))
+		copy_pageset1();
+
+	/*
+	 *  ----   FROM HERE ON, NEED TO REREAD PAGESET2 IF ABORTING!!! -----
+	 *  
+	 */
+	
+	suspend_unmap_atomic_copy_pages();
+
+	/* 
+	 * Other processors have waited for me to make the atomic copy of the 
+	 * kernel
+	 */
+
+	smp_continue();
+	
+#ifdef CONFIG_X86
+	kernel_fpu_end();
+#endif
+
+#ifdef CONFIG_PREEMPT
+	preempt_enable_no_resched();
+#endif
+
+	suspend_drivers_resume(SUSPEND_DRIVERS_USED_DEVICES_IRQS_DISABLED);
+	
+	local_irq_enable();
+	suspend_drivers_resume(SUSPEND_DRIVERS_USED_DEVICES_IRQS_ENABLED);
+
+	update_status(pageset2_size, pageset1_size + pageset2_size, NULL);
+	
+	if (TEST_RESULT_STATE(SUSPEND_ABORTED))
+		goto abort_reloading_pagedir_two;
+
+	check_shift_keys(1, "About to write pageset1.");
+
+	/*
+	 * End of critical section.
+	 */
+	
+	suspend_message(SUSPEND_ANY_SECTION, SUSPEND_LOW, 1,
+			"-- Writing pageset1\n");
+
+	temp_result = write_pageset(&pagedir1, 1);
+
+	if (TEST_ACTION_STATE(SUSPEND_TEST_FILTER_SPEED)) {
+		/* We didn't overwrite any memory, so no reread needs to be done. */
+		return -1;
+	}
+
+	if (temp_result == -1 || TEST_RESULT_STATE(SUSPEND_ABORTED))
+		goto abort_reloading_pagedir_two;
+
+	check_shift_keys(1, "About to write header.");
+
+	if (TEST_RESULT_STATE(SUSPEND_ABORTED))
+		goto abort_reloading_pagedir_two;
+
+	temp_result = write_image_header();
+
+	if (temp_result || (TEST_RESULT_STATE(SUSPEND_ABORTED)))
+		goto abort_reloading_pagedir_two;
+
+	check_shift_keys(1, "About to power down or reboot.");
+
+	return 0;
+
+abort_reloading_pagedir_two:
+	temp_result = read_secondary_pagedir(1);
+
+	/* If that failed, we're sunk. Panic! */
+	if (temp_result)
+		panic("Attempt to reload pagedir 2 while aborting "
+				"a suspend failed.");
+
+	return -1;		
+
+}
+
+static void suspend_power_off(void)
+{
+	sys_reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
+			LINUX_REBOOT_CMD_POWER_OFF, NULL);
+
+	prepare_status(1, 0, "Probably not capable for powerdown.");
+	while (1)
+		cpu_relax();
+	/* NOTREACHED */
+}
+
+static void suspend_enter_acpi_state(u32 state)
+{
+	suspend_acpi_state_used = state;
+
+	if (pm_ops && pm_ops->prepare) {
+		if (!pm_ops->prepare(state)) {
+			if (pm_ops && pm_ops->enter)
+				pm_ops->enter(state);
+			else 
+				printk("Failed to enter state.\n");
+		} else
+			printk("Prepare ops failed.\n");
+	} else
+		printk("No prepare ops.\n");
+}
+
+/*
+ * suspend_power_down
+ * Functionality   : Powers down or reboots the computer once the image
+ *                   has been written to disk.
+ * Key Assumptions : Able to reboot/power down via code called or that
+ *                   the warning emitted if the calls fail will be visible
+ *                   to the user (ie printk resumes devices).
+ * Called From     : do_suspend2_suspend_2
+ */
+
+extern asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd,
+	       void * arg);
+extern void apm_power_off(void);
+
+void suspend_power_down(void)
+{
+	if (TEST_ACTION_STATE(SUSPEND_REBOOT)) {
+		prepare_status(1, 0, "Ready to reboot.");
+		sys_reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
+				LINUX_REBOOT_CMD_RESTART, NULL);
+	}
+
+	suspend_drivers_suspend(SUSPEND_DRIVERS_PRE_POWERDOWN);
+
+	if (suspend_powerdown_method == 3) {
+		prepare_status(1, 0, "Seeking to suspend-to-ram.");
+		suspend_enter_acpi_state(PM_SUSPEND_MEM);
+		prepare_status(1, 0, "Entering S3 failed. Using normal powerdown.");
+	} else if (suspend_powerdown_method == 4) {
+		prepare_status(1, 0, "Seeking to enter ACPI suspend-to-disk state.");
+		suspend_enter_acpi_state(PM_SUSPEND_DISK);
+		prepare_status(1, 0, "Entering S4 failed. Using normal powerdown.");
+	} else
+		prepare_status(1, 0, "Powering down.");
+	
+	/* 
+	 * FIXME: At resume, we'll still think we used S4 if we tried it.
+	 * Does it matter?
+	 */
+	suspend_acpi_state_used = 0;
+	suspend_power_off();
+}
+
+/*
+ * do_suspend2_resume_1
+ * Functionality   : Preparatory steps for copying the original kernel back.
+ * Called From     : do_suspend2_lowlevel
+ */
+
+static void do_suspend2_resume_1(void)
+{
+	suspend_message(SUSPEND_ANY_SECTION, SUSPEND_LOW, 1,
+			name_suspend "About to copy pageset1 back...\n");
+
+	if (active_writer && active_writer->dpm_set_devices)
+		active_writer->dpm_set_devices();
+	
+	suspend_drivers_suspend(SUSPEND_DRIVERS_USED_DEVICES_IRQS_ENABLED);
+	suspend_drivers_suspend(SUSPEND_DRIVERS_UNUSED_DEVICES_IRQS_ENABLED);
+	local_irq_disable(); /* irqs might have been re-enabled on us */
+	suspend_drivers_suspend(SUSPEND_DRIVERS_USED_DEVICES_IRQS_DISABLED);
+	local_irq_disable();
+	suspend_drivers_suspend(SUSPEND_DRIVERS_UNUSED_DEVICES_IRQS_DISABLED);
+	local_irq_enable();
+
+	suspend_map_atomic_copy_pages();
+
+	/* Get other cpus ready to restore their original contexts */
+	smp_suspend();
+
+	local_irq_disable();
+
+#ifdef CONFIG_PREEMPT
+	preempt_disable();
+#endif
+
+	barrier();
+	mb();
+
+	MDELAY(2000);
+}
+
+/*
+ * do_suspend2_resume_2
+ * Functionality   : Steps taken after copying back the original kernel at
+ *                   resume.
+ * Key Assumptions : Will be able to read back secondary pagedir (if 
+ *                   applicable).
+ * Called From     : do_suspend2_lowlevel
+ */
+
+static void do_suspend2_resume_2(void)
+{
+	set_suspend_state(SUSPEND_NOW_RESUMING);
+	set_suspend_state(SUSPEND_PAGESET2_NOT_LOADED);
+
+	suspend_unmap_atomic_copy_pages();
+
+#ifdef CONFIG_PREEMPT
+	preempt_enable();
+#endif
+
+	local_irq_disable();
+	suspend_drivers_resume(SUSPEND_DRIVERS_USED_DEVICES_IRQS_DISABLED);
+	local_irq_enable();
+
+	suspend_drivers_resume(SUSPEND_DRIVERS_USED_DEVICES_IRQS_ENABLED);
+
+	suspend_post_restore_redraw();
+
+	check_shift_keys(1, "About to reload secondary pagedir.");
+
+	read_secondary_pagedir(0);
+	clear_suspend_state(SUSPEND_PAGESET2_NOT_LOADED);
+	
+	suspend_checksum_print_differences();
+
+	prepare_status(0, 0, "Cleaning up...");
+
+	clear_suspend_state(SUSPEND_USE_MEMORY_POOL);
+	
+	local_irq_disable();
+	suspend_drivers_resume(SUSPEND_DRIVERS_UNUSED_DEVICES_IRQS_DISABLED);
+	local_irq_enable();
+	suspend_drivers_resume(SUSPEND_DRIVERS_UNUSED_DEVICES_IRQS_ENABLED);
+}
+
+/*
+ * do_suspend2_suspend_1
+ * Functionality   : Steps taken prior to saving CPU state and the image
+ *                   itself.
+ * Called From     : do_suspend2_lowlevel
+ */
+
+static void do_suspend2_suspend_1(void)
+{
+	/* Save other cpu contexts */
+	smp_suspend();
+
+	suspend_drivers_suspend(SUSPEND_DRIVERS_USED_DEVICES_IRQS_ENABLED);
+
+	mb();
+	barrier();
+
+#ifdef CONFIG_PREEMPT
+	preempt_disable();
+#endif
+	local_irq_disable();
+	suspend_drivers_suspend(SUSPEND_DRIVERS_USED_DEVICES_IRQS_DISABLED);
+}
+
+/*
+ * do_suspend2_suspend_2
+ * Functionality   : Steps taken after saving CPU state to save the
+ *                   image and powerdown/reboot or recover on failure.
+ * Key Assumptions : save_image returns zero on success; otherwise we need to
+ *                   clean up and exit. The state on exiting this routine 
+ *                   should be essentially the same as if we have suspended,
+ *                   resumed and reached the end of do_suspend2_resume_2.
+ * Called From     : do_suspend2_lowlevel
+ */
+static void do_suspend2_suspend_2(void)
+{
+	if (!save_image_part1())
+		suspend_power_down();
+
+	if (!TEST_RESULT_STATE(SUSPEND_ABORT_REQUESTED) &&
+	    !TEST_ACTION_STATE(SUSPEND_TEST_FILTER_SPEED) &&
+	    suspend_powerdown_method != 3)
+		printk(KERN_EMERG name_suspend
+			"Suspend failed, trying to recover...\n");
+	MDELAY(1000);
+
+	local_irq_disable();
+	suspend_drivers_resume(SUSPEND_DRIVERS_UNUSED_DEVICES_IRQS_DISABLED);
+	local_irq_enable();
+	suspend_drivers_resume(SUSPEND_DRIVERS_UNUSED_DEVICES_IRQS_ENABLED);
+
+	barrier();
+	mb();
+}
+
+static inline void lru_check_page(struct page * page)
+{
+	if (!PageLRU(page))
+		printk("Page %p/%p in inactivelist but not marked LRU.\n",
+			page, page_address(page));
+}
+
+/* get_debug_info
+ * Functionality:	Store debug info in a buffer.
+ * Called from:		suspend_try_suspend.
+ */
+
+#define SNPRINTF(a...) 	len += suspend_snprintf(debug_info_buffer + len, \
+		PAGE_SIZE - len - 1, ## a)
+
+static int get_suspend_debug_info(void)
+{
+	int len = 0;
+	if (!debug_info_buffer) {
+		debug_info_buffer = (char *) get_zeroed_page(GFP_ATOMIC);
+		if (!debug_info_buffer) {
+			printk("Error! Unable to allocate buffer for"
+					"software suspend debug info.\n");
+			return 0;
+		}
+	}
+
+	SNPRINTF("Please include the following information in bug reports:\n");
+	SNPRINTF("- SUSPEND core   : %s\n", SUSPEND_CORE_VERSION);
+	SNPRINTF("- Kernel Version : %s\n", UTS_RELEASE);
+	SNPRINTF("- Compiler vers. : %d.%d\n", __GNUC__, __GNUC_MINOR__);
+#ifdef CONFIG_MODULES
+	SNPRINTF("- Modules loaded : ");
+	{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+		struct module *this_mod;
+		extern struct module *module_list;
+		this_mod = module_list;
+		while (this_mod) {
+			if (this_mod->name)
+				SNPRINTF("%s ", this_mod->name);
+			this_mod = this_mod->next;
+		}
+#else
+		extern int print_module_list_to_buffer(char * buffer, int size);
+		len+= print_module_list_to_buffer(debug_info_buffer + len,
+				PAGE_SIZE - len - 1);
+#endif
+	}
+	SNPRINTF("\n");
+#else
+	SNPRINTF("- No module support.\n");
+#endif
+	SNPRINTF("- Attempt number : %d\n", nr_suspends);
+	if (num_range_pages)
+		SNPRINTF("- Pageset sizes  : %d (%d low) and %d (%d low).\n",
+			pagedir1.lastpageset_size, 
+			pageset1_sizelow,
+			pagedir2.lastpageset_size, 
+			pageset2_sizelow);
+#ifdef CONFIG_SOFTWARE_SUSPEND_DEBUG
+	SNPRINTF("- Parameters     : %ld %ld %ld %d %d %d %ld\n",
+			suspend_result,
+			suspend_action,
+			suspend_debug_state,
+			suspend_default_console_level,
+			image_size_limit,
+			max_async_ios,
+			suspend_powerdown_method);
+#else
+	SNPRINTF("- Parameters     : %ld %ld %d %d %ld\n",
+			suspend_result,
+			suspend_action,
+			image_size_limit,
+			max_async_ios,
+			suspend_powerdown_method);
+#endif
+	if (num_range_pages)
+		SNPRINTF("- Calculations   : Image size: %lu. "
+			"Ram to suspend: %ld.\n",
+			STORAGE_NEEDED(1), RAM_TO_SUSPEND);
+	SNPRINTF("- Limits         : %lu pages RAM. Initial boot: %lu.\n",
+		max_mapnr, orig_mem_free);
+	SNPRINTF("- Overall expected compression percentage: %d.\n",
+			100 - expected_compression_ratio());
+	len+= print_plugin_debug_info(debug_info_buffer + len, 
+			PAGE_SIZE - len - 1);
+#ifdef CONFIG_SOFTWARE_SUSPEND_DEBUG
+	SNPRINTF("- Debugging compiled in.\n");
+#endif
+#ifdef CONFIG_PREEMPT
+	SNPRINTF("- Preemptive kernel.\n");
+#endif
+#ifdef CONFIG_SMP
+	SNPRINTF("- SMP kernel.\n");
+#endif
+#ifdef CONFIG_HIGHMEM
+	SNPRINTF("- Highmem Support.\n");
+#endif
+	if (num_range_pages)
+		SNPRINTF("- Max ranges used: %d ranges in %d pages.\n",
+			max_ranges_used, num_range_pages);
+	if (suspend_io_time[0][1]) {
+		SNPRINTF("- I/O speed: Write %d MB/s",
+			(MB((unsigned long) suspend_io_time[0][0]) * HZ /
+			 suspend_io_time[0][1]));
+		if (suspend_io_time[1][1])
+			SNPRINTF(", Read %d MB/s",
+				(MB((unsigned long) suspend_io_time[1][0]) * HZ /
+				 suspend_io_time[1][1]));
+		SNPRINTF(".\n");
+	}
+	else if (num_range_pages)
+		SNPRINTF("- Suspend cancelled. No I/O speed stats.\n");
+
+	return len;
+}
+
+extern int PageInPagedir(struct pagedir * p, struct page * page);
+static unsigned long display_metadata_page;
+
+static char * state_string[3] = { "Source", "Destination", "Dest/Allocd" };
+
+void __display_metadata_state(int pagedir, int state)
+{
+	int i;
+
+	if (!state)
+		return;
+
+	printk("[ Pagedir %d:", pagedir);
+	for (i=0; i < 3; i++)
+		if (state & (1 << i))
+			printk("%s ", state_string[i]);
+	printk("]");
+}
+
+void display_metadata_state(struct page * page)
+{
+	__display_metadata_state(1, PageInPagedir(&pagedir1, page));
+	__display_metadata_state(2, PageInPagedir(&pagedir2, page));
+	if (PageNosave(page))
+		printk("[ NoSave ]");
+	if (PageReserved(page))
+		printk("[ Reserved ]");
+	if (PageHighMem(page))
+		printk("[ Highmem ]");
+}
+
+void proc_display_metadata_state(void)
+{
+	printk("Page number %lu. Struct page at %p, virt address %p:",
+			display_metadata_page,
+			mem_map + display_metadata_page,
+			page_address(mem_map + display_metadata_page));
+	display_metadata_state(mem_map + display_metadata_page);
+	printk("\n");
+}
+
+/*
+ * debuginfo_read_proc
+ * Functionality   : Displays information that may be helpful in debugging
+ *                   software suspend.
+ */
+int debuginfo_read_proc(char * page, char ** start, off_t off, int count,
+		int *eof, void *data)
+{
+	int info_len, copy_len;
+
+	initialise_suspend_plugins();
+	info_len = get_suspend_debug_info();
+	cleanup_suspend_plugins();
+
+	copy_len = min(info_len - (int) off, count);
+	if (copy_len < 0)
+		copy_len = 0;
+
+	if (copy_len) {
+		memcpy(page, debug_info_buffer + off, copy_len);
+		*start = page;
+	} 
+
+	if (copy_len + off == info_len)
+		*eof = 1;
+
+	free_pages((unsigned long) debug_info_buffer, 0);
+	debug_info_buffer = NULL;
+	return copy_len;
+}
+
+static int get_suspend_debug_info(void);
+
+static int allocate_bitmaps(void)
+{
+	suspend_message(SUSPEND_MEMORY, SUSPEND_VERBOSE, 1,
+			"Allocating in_use_map\n");
+	if (allocate_local_pageflags(&in_use_map, 1))
+		return 1;
+	
+	suspend_store_free_mem(SUSPEND_FREE_IN_USE_MAP, 0);
+	PRINTFREEMEM("after allocating in_use_map");
+	
+	if (allocate_local_pageflags(&pageset2_map, 1))
+		return 1;
+
+	suspend_store_free_mem(SUSPEND_FREE_PS2_MAP, 0);
+	PRINTFREEMEM("after allocating pageset2 map");
+	
+#ifdef CONFIG_DEBUG_PAGEALLOC
+	if (allocate_local_pageflags(&unmap_map, 1))
+		return 1;
+
+	suspend_store_free_mem(SUSPEND_FREE_UNMAP_MAP, 0);
+	PRINTFREEMEM("after allocating unmap map");
+#endif	
+	
+	suspend_store_free_mem(4, 0);
+	
+	return 0;
+}
+
+static void free_metadata(void)
+{
+	put_rangepages_list();
+
+	free_ranges();
+	suspend_store_free_mem(SUSPEND_FREE_RANGE_PAGES, 1);
+	PRINTFREEMEM("after freeing ranges");
+
+	free_local_pageflags(&pageset2_map);
+	PRINTFREEMEM("after freeing pageset2 map");
+	suspend_store_free_mem(SUSPEND_FREE_PS2_MAP, 1);
+
+	free_local_pageflags(&in_use_map);
+	PRINTFREEMEM("after freeing inuse map");
+	suspend_store_free_mem(SUSPEND_FREE_IN_USE_MAP, 1);
+}
+
+/*
+ * software_suspend_pending
+ * Functionality   : First level of code for software suspend invocations.
+ *                   Stores and restores load averages (to avoid a spike),
+ *                   allocates bitmaps, freezes processes and eats memory
+ *                   as required before suspending drivers and invoking
+ *                   the 'low level' code to save the state to disk.
+ *                   By the time we return from do_suspend2_lowlevel, we
+ *                   have either failed to save the image or successfully
+ *                   suspended and reloaded the image. The difference can
+ *                   be discerned by checking SUSPEND_ABORTED.
+ * Called From     : 
+ */
+
+extern void free_pageset_size_bloat(void);
+
+void do_activate(void)
+{
+	int i;
+
+        /* Suspend always runs on processor 0 */ 
+	ensure_on_processor_zero();
+
+	display_nosave_pages();
+
+#ifdef CONFIG_SOFTWARE_SUSPEND_KEEP_IMAGE
+	if (TEST_RESULT_STATE(SUSPEND_KEPT_IMAGE)) {
+		if (TEST_ACTION_STATE(SUSPEND_KEEP_IMAGE)) {
+			printk("Image already stored:"
+				" powering down immediately.");
+			suspend_power_down();
+			return;	/* It might now, but just in case we're using S3*/
+		} else {
+			printk("Invalidating previous image.\n");
+			active_writer->ops.writer.invalidate_image();
+		}
+	}
+#endif
+
+	printk(name_suspend "Initiating a software suspend cycle.\n");
+	set_suspend_state(SUSPEND_RUNNING);
+
+	max_ranges_used = 0;
+	nr_suspends++;
+	clear_suspend_state(SUSPEND_NOW_RESUMING);
+	
+	suspend_io_time[0][0] = suspend_io_time[0][1] = suspend_io_time[1][0] =
+		suspend_io_time[1][1] = 0;
+
+	PRINTFREEMEM("at start of do_activate");
+	suspend_store_free_mem(SUSPEND_FREE_BASE, 0);
+
+	suspend2_prepare_console();
+
+	free_metadata();	/* We might have kept it */
+
+	if (suspend_version_specific_initialise())
+		goto out;
+
+	if (allocate_bitmaps())
+		goto out;
+	
+	PRINTFREEMEM("after allocating bitmaps");
+
+	display_nosave_pages();
+
+	set_chain_names(&pagedir1);
+	set_chain_names(&pagedir2);
+
+	if (initialise_suspend_plugins())
+		goto out;
+
+	PRINTFREEMEM("after initialising plugins");
+	suspend_store_free_mem(SUSPEND_FREE_INIT_PLUGINS, 0);
+
+	/* Free up memory if necessary */
+	suspend_message(SUSPEND_ANY_SECTION, SUSPEND_VERBOSE, 1,
+			"Preparing image.\n");
+	if (prepare_image() || TEST_RESULT_STATE(SUSPEND_ABORTED))
+		goto out;
+
+	PRINTFREEMEM("after preparing image");
+
+	if (TEST_ACTION_STATE(SUSPEND_FREEZER_TEST))
+		goto out;
+
+	display_nosave_pages();
+
+	if (!TEST_RESULT_STATE(SUSPEND_ABORTED)) {
+		prepare_status(1, 0, "Starting to save the image..");
+		save_image();
+	}
+	
+out:
+	free_pageset_size_bloat();
+
+	PRINTFREEMEM("at 'out'");
+
+	i = get_suspend_debug_info();
+
+	suspend_store_free_mem(SUSPEND_FREE_DEBUG_INFO, 0);
+
+	clear_suspend_state(SUSPEND_USE_MEMORY_POOL);
+
+	free_pagedir(&pagedir2);
+	PRINTFREEMEM("after freeing pagedir 1");
+	free_pagedir(&pagedir1);
+	PRINTFREEMEM("after freeing pagedir 2");
+	
+#ifdef CONFIG_SOFTWARE_SUSPEND_KEEP_IMAGE
+	if (TEST_ACTION_STATE(SUSPEND_KEEP_IMAGE) &&
+	    !TEST_ACTION_STATE(SUSPEND_ABORTED)) {
+		suspend_message(SUSPEND_ANY_SECTION, SUSPEND_LOW, 1,
+			name_suspend "Not invalidating the image due "
+			"to Keep Image being enabled.\n");
+		SET_RESULT_STATE(SUSPEND_KEPT_IMAGE);
+	} else
+#endif
+		active_writer->ops.writer.invalidate_image();
+
+	empty_suspend_memory_pool();
+	PRINTFREEMEM("after freeing memory pool");
+	suspend_store_free_mem(SUSPEND_FREE_MEM_POOL, 1);
+
+	if (!TEST_ACTION_STATE(SUSPEND_KEEP_METADATA))
+		free_metadata();
+
+#ifdef CONFIG_DEBUG_PAGE_ALLOC
+	free_local_pageflags(&unmap_map);
+	PRINTFREEMEM("after freeing unmap map");
+	suspend_store_free_mem(SUSPEND_UNMAP_MAP, 1);
+#endif
+
+	if (debug_info_buffer) {
+		/* Printk can only handle 1023 bytes, including
+		 * its level mangling. */
+		for (i = 0; i < 3; i++)
+			printk("%s", debug_info_buffer + (1023 * i));
+		free_pages((unsigned long) debug_info_buffer, 0);
+		debug_info_buffer = NULL;
+	}
+
+	PRINTFREEMEM("after freeing debug info buffer");
+	suspend_store_free_mem(SUSPEND_FREE_DEBUG_INFO, 1);
+	
+	cleanup_suspend_plugins();
+
+	PRINTFREEMEM("after cleaning up suspend plugins");
+	suspend_store_free_mem(SUSPEND_FREE_INIT_PLUGINS, 1);
+	
+	suspend_version_specific_cleanup();
+
+	display_nosave_pages();
+
+	thaw_processes(FREEZER_ALL_THREADS);
+
+	PRINTFREEMEM("after thawing processes");
+	suspend_store_free_mem(SUSPEND_FREE_FREEZER, 1);
+
+	suspend_store_free_mem(SUSPEND_FREE_BASE, 1);
+#ifdef CONFIG_SOFTWARE_SUSPEND_DEBUG
+	display_free_mem();
+#endif
+
+	clear_suspend_state(SUSPEND_RUNNING);
+	PRINTFREEMEM("at end of do_activate");
+#ifdef CONFIG_PREEMPT
+#endif
+	suspend2_cleanup_console();
+
+}
+
+int attempt_to_parse_resume_device(void)
+{
+	struct list_head *writer;
+	struct suspend_plugin_ops * this_writer;
+	int result = 0;
+	mm_segment_t oldfs;
+
+	oldfs = get_fs(); set_fs(KERNEL_DS);
+
+	active_writer = NULL;
+	clear_suspend_state(SUSPEND_RESUME_DEVICE_OK);
+	set_suspend_state(SUSPEND_DISABLED);
+
+	if (!num_writers) {
+		printk(name_suspend "No writers have been registered.\n");
+		goto out;
+	}
+	
+	if (!resume2_file[0]) {
+		result = -EINVAL;
+		goto out;
+	}
+
+	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
+				 */
+
+				printk(name_suspend
+					"Not able to successfully parse this "
+					"resume device. Suspending disabled.\n");
+				goto out;
+
+			case 0:
+				/*
+				 * For this writer and valid.
+				 */
+
+				active_writer = this_writer;
+
+				/* We may not have any filters compiled in */
+
+				set_suspend_state(SUSPEND_RESUME_DEVICE_OK);
+				clear_suspend_state(SUSPEND_DISABLED);
+				printk(name_suspend "Suspending enabled.\n");
+				goto out;
+
+			case 1:
+				/*
+				 * Not for this writer. Try the next one.
+				 */
+
+				break;
+		}
+	}
+	printk(name_suspend "No matching writer found. Suspending disabled.\n");
+	result = -EINVAL;
+out:
+	clear_suspend_state(SUSPEND_RUNNING);
+	set_fs(oldfs);
+	return result;
+}
+
+/* 
+ * 
+ */
+
+static void __suspend2_verify_checksums(void)
+{
+	if (checksum_plugin)
+		checksum_plugin->ops.checksum.check_checksums();
+}
+
+#define ALL_SETTINGS_VERSION 2
+
+/*
+ * suspend_write_compat_proc.
+ *
+ * This entry allows all of the settings to be set at once. 
+ * It was originally for compatibility with pre- /proc/suspend
+ * versions, but has been retained because it makes saving and
+ * restoring the configuration simpler.
+ */
+static int suspend_write_compat_proc(struct file *file, const char * buffer,
+		unsigned long count, void * data)
+{
+	char * buf1 = (char *) get_zeroed_page(GFP_ATOMIC), *curbuf, *lastbuf;
+	char * buf2 = (char *) get_zeroed_page(GFP_ATOMIC); 
+	int i, file_offset = 0, used_size = 0, reparse_resume_device = 0;
+	unsigned long nextval;
+	struct suspend_plugin_ops * plugin;
+	struct plugin_header * plugin_header = NULL;
+
+	if ((!buf1) || (!buf2))
+		return -ENOMEM;
+
+	while (file_offset < count) {
+		int length = count - file_offset;
+		if (length > (PAGE_SIZE - used_size))
+			length = PAGE_SIZE - used_size;
+
+		if (copy_from_user(buf1 + used_size, buffer + file_offset, length))
+			return -EFAULT;
+
+		curbuf = buf1;
+
+		if (!file_offset) {
+			/* Integers first */
+			for (i = 0; i < 8; i++) {
+				if (!*curbuf)
+					break;
+				lastbuf = curbuf;
+				nextval = simple_strtoul(curbuf, &curbuf, 0);
+				if (curbuf == lastbuf)
+					break;
+				switch (i) {
+					case 0:
+						if (nextval != ALL_SETTINGS_VERSION) {
+							printk("Error loading saved settings. This data is for version %ld, but kernel module uses format %d.\n",
+									nextval, ALL_SETTINGS_VERSION);
+							goto out;
+						}
+					case 1:
+						suspend_result = nextval;
+						break;
+					case 2:
+						suspend_action = nextval;
+						break;
+					case 3:
+#ifdef CONFIG_SOFTWARE_SUSPEND_DEBUG
+						suspend_debug_state = nextval;
+#endif
+						break;
+					case 4:
+						suspend_default_console_level = nextval;
+#ifndef CONFIG_SOFTWARE_SUSPEND_DEBUG
+						if (suspend_default_console_level > 1)
+							suspend_default_console_level = 1;
+#endif
+						break;
+					case 5:
+						image_size_limit = nextval;
+						break;
+					case 6:
+						max_async_ios = nextval;
+						if (max_async_ios > MAX_READAHEAD)
+							max_async_ios = MAX_READAHEAD;
+						if (max_async_ios < 1)
+							max_async_ios = 1;
+						break;
+					case 7:
+#ifdef CONFIG_ACPI
+						suspend_powerdown_method = nextval;
+						if (suspend_powerdown_method < 3)
+							suspend_powerdown_method = 3;
+						if (suspend_powerdown_method > 5)
+#endif
+							suspend_powerdown_method = 5;
+						break;
+				}
+
+				curbuf++;
+				while (*curbuf == ' ')
+					curbuf++;
+			}
+
+			if (count <= (curbuf - buf1))
+				goto out;
+			else {
+				list_for_each_entry(plugin, &suspend_plugins, plugin_list)
+					plugin->disabled = 1;
+			}
+		}
+
+		if (((unsigned long) curbuf  & ~PAGE_MASK) + sizeof(plugin_header) > PAGE_SIZE)
+			goto shift_buffer;
+		
+		/* Plugins */
+		plugin_header = (struct plugin_header *) curbuf;
+
+		if (((unsigned long) curbuf & ~PAGE_MASK) + sizeof(plugin_header) + plugin_header->data_length  > PAGE_SIZE)
+			goto shift_buffer;
+		
+		if (plugin_header->magic != 0xADEDC0DE) {
+			printk("Bad plugin data magic.\n");
+			break;
+		}
+
+		plugin = find_plugin_given_name(plugin_header->name);
+
+		if (plugin) {	/* May validly have config saved for a plugin not now loaded */
+			if ((plugin->type == WRITER_PLUGIN) &&
+			    ((!active_writer && plugin->disabled && !plugin_header->disabled) ||
+			     (active_writer == plugin && plugin_header->disabled)))
+				reparse_resume_device = 1;
+			plugin->disabled = plugin_header->disabled;
+			if (plugin_header->data_length)
+				plugin->load_config_info(curbuf + sizeof(struct plugin_header), 
+						plugin_header->data_length);
+		} else
+			printk("Data for plugin %s not used because not currently loaded.\n", plugin_header->name);
+
+		curbuf += sizeof(struct plugin_header) + plugin_header->data_length;
+
+shift_buffer:
+		if (!(curbuf - buf1))
+			break;
+
+		file_offset += curbuf - buf1;
+		
+		used_size = PAGE_SIZE + buf1 - curbuf;
+		memcpy(buf2, curbuf, used_size);
+		memcpy(buf1, buf2, used_size);
+	}
+out:
+	free_pages((unsigned long) buf1, 0);
+	free_pages((unsigned long) buf2, 0);
+	
+	if (reparse_resume_device) {
+		printk("Active writer disabled or no active writer and one or more just enabled. Reparsing resume device.\n");
+		attempt_to_parse_resume_device();
+	}
+	
+	return count;
+}
+
+/*
+ * suspend_read_compat_proc.
+ *
+ * Like it's _write_ sibling, this entry allows all of the settings
+ * to be read at once.
+ * It too was originally for compatibility with pre- /proc/suspend
+ * versions, but has been retained because it makes saving and
+ * restoring the configuration simpler.
+ */
+static int suspend_read_compat_proc(char * page, char ** start, off_t off, int count,
+		int *eof, void *data)
+{
+	struct suspend_plugin_ops * this_plugin;
+	char * buffer = (char *) get_zeroed_page(GFP_ATOMIC);
+	int index = 1, file_pos = 0, page_offset = 0, len;
+	int copy_len = 0;
+	struct plugin_header plugin_header;
+
+	if (!buffer) {
+		printk("Failed to allocate a buffer for getting "
+				"plugin configuration info.\n");
+		return -ENOMEM;
+	}
+		
+	plugin_header.magic = 0xADEDC0DE;
+
+	len = sprintf(buffer, "%d %ld %ld %ld %d %d %d %ld\n",
+			ALL_SETTINGS_VERSION,
+			suspend_result,
+			suspend_action,
+			suspend_debug_state,
+			suspend_default_console_level,
+			image_size_limit,
+			max_async_ios,
+			suspend_powerdown_method);
+
+	if (len >= off) {
+		copy_len = (len < off + count) ? len - off : count - off;
+		memcpy(page, buffer + off, copy_len);
+		page_offset+= copy_len;
+	}
+
+	file_pos += len;
+
+	/* 
+	 * 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 */
+		if (this_plugin->save_config_info) {
+			plugin_header.data_length = this_plugin->save_config_info(buffer);
+		} else
+			plugin_header.data_length = 0;
+
+		if (file_pos > (off + count)) {
+			file_pos += sizeof(struct plugin_header) + plugin_header.data_length;
+			continue;
+		}
+
+		len = 0;
+		if ((file_pos + sizeof(struct plugin_header) >= off) &&
+		    (file_pos < (off + count))) {
+
+			/* Save the details of the plugin */
+			memcpy(plugin_header.name, this_plugin->name, 
+					SUSPEND_MAX_PLUGIN_NAME_LENGTH);
+			plugin_header.disabled = this_plugin->disabled;
+			plugin_header.type = this_plugin->type;
+			plugin_header.index = index++;
+			
+			copy_len = sizeof(struct plugin_header);
+
+			if (copy_len + page_offset > count)
+				copy_len = count - page_offset;
+
+			memcpy(page + page_offset,
+				 ((char *) &plugin_header) + off + page_offset - file_pos,
+				 copy_len);	 
+
+			page_offset += copy_len;
+		}
+
+		file_pos += sizeof(struct plugin_header);
+
+		if (plugin_header.data_length && (file_pos >= off) && (file_pos < (off + count))) {
+			copy_len = plugin_header.data_length;
+
+			if (copy_len + page_offset > count + off)
+				copy_len = count - page_offset;
+			
+			memcpy(page + page_offset,
+				 buffer,
+				 copy_len);	 
+
+			page_offset += copy_len;
+
+		}
+
+		file_pos += plugin_header.data_length;
+		
+	}
+	free_pages((unsigned long) buffer, 0);
+	if (page_offset < count)
+		*eof = 1;
+	return page_offset;
+}
+
+extern int initialise_suspend_plugins(void);
+extern void cleanup_suspend_plugins(void);
+static char suspend_core_version[] = SUSPEND_CORE_VERSION;
+
+static int resume2_write_proc(void)
+{
+	mm_segment_t	oldfs;
+
+	oldfs = get_fs(); set_fs(KERNEL_DS);
+	initialise_suspend_plugins();
+	attempt_to_parse_resume_device();
+	cleanup_suspend_plugins();
+	set_fs(oldfs);
+	return 0;
+}
+
+/*
+ * Core proc entries that aren't built in.
+ *
+ * This array contains entries that are automatically registered at
+ * boot. Plugins and the console code register their own entries separately.
+ */
+
+static struct suspend_proc_data proc_params[] = {
+	{ .filename			= "all_settings",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_CUSTOM,
+	  .data = {
+		  .special = {
+	  		 .read_proc	= suspend_read_compat_proc,
+			 .write_proc	= suspend_write_compat_proc,
+		  }
+	  }
+	},
+
+	{ .filename			= "debug_info",
+	  .permissions			= PROC_READONLY,
+	  .type				= SUSPEND_PROC_DATA_CUSTOM,
+	  .data = {
+		  .special = {
+			  .read_proc	= debuginfo_read_proc,
+		  }
+	  }
+	},
+	
+	{ .filename			= "disable_sysdev_suspend",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_BIT,
+	  .data = {
+		  .bit = {
+			  .bit_vector	= &suspend_action,
+			  .bit		= SUSPEND_DISABLE_SYSDEV_SUPPORT,
+		  }
+	  }
+	},
+
+	{ .filename			= "freeze_timers",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_BIT,
+	  .data = {
+		  .bit = {
+			  .bit_vector	= &suspend_action,
+			  .bit		= SUSPEND_FREEZE_TIMERS,
+		  }
+	  }
+	},
+
+	{ .filename			= "image_size_limit",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_INTEGER,
+	  .data = {
+		  .integer = {
+			  .variable	= &image_size_limit,
+			  .minimum	= -2,
+			  .maximum	= 32767,
+		  }
+	  }
+	},
+
+	{ .filename			= "last_result",
+	  .permissions			= PROC_READONLY,
+	  .type				= SUSPEND_PROC_DATA_UL,
+	  .data = {
+		  .ul = {
+			  .variable	=  &suspend_result,
+		  }
+	  }
+	},
+	
+	{ .filename			= "reboot",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_BIT,
+	  .data = {
+		  .bit = {
+			  .bit_vector	= &suspend_action,
+			  .bit		= SUSPEND_REBOOT,
+		  }
+	  }
+	},
+	  
+	{ .filename			= "resume2",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_STRING,
+	  .data = {
+		  .string = {
+			  .variable	= resume2_file,
+			  .max_length	= 255,
+		  }
+	  },
+	  .write_proc	= resume2_write_proc,
+	},
+
+
+	{ .filename			= "version",
+	  .permissions			= PROC_READONLY,
+	  .type				= SUSPEND_PROC_DATA_STRING,
+	  .data = {
+		  .string = {
+			  .variable	= suspend_core_version,
+		  }
+	  }
+	},
+
+#ifdef CONFIG_SOFTWARE_SUSPEND_DEBUG
+	{ .filename			= "freezer_test",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_BIT,
+	  .data = {
+		  .bit = {
+			  .bit_vector	= &suspend_action,
+			  .bit		= SUSPEND_FREEZER_TEST,
+		  }
+	  }
+	},
+
+	{ .filename			= "keep_metadata",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_BIT,
+	  .data = {
+		  .bit = {
+			  .bit_vector	= &suspend_action,
+			  .bit		= SUSPEND_KEEP_METADATA,
+		  }
+	  }
+	},
+
+	{ .filename			= "test_filter_speed",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_BIT,
+	  .data = {
+		  .bit = {
+			  .bit_vector	= &suspend_action,
+			  .bit		= SUSPEND_TEST_FILTER_SPEED,
+		  }
+	  }
+	},
+
+	{ .filename			= "slow",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_BIT,
+	  .data = {
+		  .bit = {
+			  .bit_vector	= &suspend_action,
+			  .bit		= SUSPEND_SLOW,
+		  }
+	  }
+	},
+	
+	{ .filename			= "display_metadata_page",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_UL,
+	  .data = {
+		  .ul = {
+			  .variable	= &display_metadata_page,
+		  }
+	  }
+	},
+#endif
+	  
+	{ .filename			= "forced_pageset1_size",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_UL,
+	  .data = {
+		  .ul = {
+			  .variable	= &forced_ps1_size,
+		  }
+	  }
+	},
+
+	{ .filename			= "forced_pageset2_size",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_UL,
+	  .data = {
+		  .ul = {
+			  .variable	= &forced_ps2_size,
+		  }
+	  }
+	},
+
+#if defined(CONFIG_ACPI)
+	{ .filename			= "powerdown_method",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_UL,
+	  .data = {
+		  .ul = {
+			  .variable	= &suspend_powerdown_method,
+			  .minimum	= 3,
+			  .maximum	= 5,
+		  }
+	  }
+	},
+#endif
+
+#ifdef CONFIG_SOFTWARE_SUSPEND_KEEP_IMAGE
+	{ .filename			= "keep_image",
+	  .permissions			= PROC_RW,
+	  .type				= SUSPEND_PROC_DATA_BIT,
+	  .data = {
+		  .bit = {
+			  .bit_vector	= &suspend_action,
+			  .bit		= SUSPEND_KEEP_IMAGE,
+		  }
+	  }
+	},
+#endif
+};
+
+extern int debuginfo_read_proc(char * page, char ** start, off_t off, int count,
+		int *eof, void *data);
+
+/*
+ * Called from init kernel_thread.
+ * We check if we have an image and if so we try to resume.
+ * We also start ksuspendd if configuration looks right.
+ */
+
+extern int freeze_processes(int no_progress);
+
+static int do_resume(void)
+{
+	int ret = 0;
+	int read_image_result = 0;
+
+	/* Suspend always runs on processor 0 */
+	ensure_on_processor_zero();
+
+	if (sizeof(swp_entry_t) != sizeof(long)) {
+		printk(KERN_WARNING name_suspend
+			"The size of swp_entry_t != size of long. "
+			"Please report this!\n");
+		return ret;
+	}
+	
+	set_suspend_state(SUSPEND_RUNNING);
+
+	if (!resume2_file[0])
+		printk(KERN_WARNING name_suspend
+			"You need to use a resume2= command line parameter to "
+			"tell Software Suspend 2 where to look for an image.\n");
+
+	if (!(test_suspend_state(SUSPEND_RESUME_DEVICE_OK)))
+		attempt_to_parse_resume_device();
+
+	if (!(test_suspend_state(SUSPEND_RESUME_DEVICE_OK))) {
+		/* 
+		 * Without a usable storage device we can do nothing - 
+		 * even if noresume is given
+		 */
+
+		if (!num_writers)
+			printk(KERN_ALERT name_suspend
+				"No writers have been registered.\n");
+		else
+			printk(KERN_ALERT name_suspend
+				"Missing or invalid storage location "
+				"(resume2= parameter). Please correct and "
+				"rerun lilo (or equivalent) before "
+				"suspending.\n");
+		clear_suspend_state(SUSPEND_RUNNING);
+		return ret;
+	}
+
+	/* We enable the possibility of machine suspend */
+	orig_mem_free = real_nr_free_pages();
+
+	suspend_task = current->pid;
+
+	read_image_result = read_primary_suspend_image(); /* non fatal error ignored */
+
+	if (test_suspend_state(SUSPEND_NORESUME_SPECIFIED))
+		printk(KERN_WARNING name_suspend "Resuming disabled as requested.\n");
+
+	if (read_image_result) {
+		suspend_task = 0;
+		clear_suspend_state(SUSPEND_RUNNING);
+		return ret;
+	}
+
+	/* 
+	 * Ensure our suspend device tree is configured (2.6) as
+	 * at suspend time
+	 */
+	
+	suspend_version_specific_initialise();
+
+	freeze_processes(1);
+
+	prepare_status(0, 0,
+		"Copying original kernel back (no status - sensitive!)...");
+	
+	do_suspend2_lowlevel(1);
+	BUG();
+
+	return ret;
+}
+
+extern int suspend_plugin_keypress(unsigned int keycode);
+extern void request_abort_suspend(void);
+extern void schedule_suspend_message(int message_number);
+
+int suspend_keypress(unsigned int keycode)
+{
+	/* These keys work even if no output is enabled.
+	 * (To get this far, we must be suspending or resuming).
+	 */
+	switch (keycode) {
+		case 27:
+			/* Abort suspend */
+			if (TEST_ACTION_STATE(SUSPEND_CAN_CANCEL))
+				request_abort_suspend();
+			break;
+		case 114:
+			/* Otherwise, if R pressed, toggle rebooting */
+			suspend_action ^= (1 << SUSPEND_REBOOT);
+			schedule_suspend_message(2);
+			break;
+		default:
+			return suspend_plugin_keypress(keycode);
+	}
+	return 1;
+}
+
+extern void suspend_early_boot_message_plugins(void);
+extern void cleanup_finished_suspend_io(void);
+
+struct suspend2_core_ops core_ops = {
+	.do_suspend = do_activate,
+	.do_resume = do_resume,
+	.resume1 = do_suspend2_resume_1, 
+	.resume2 = do_suspend2_resume_2, 
+	.suspend1 = do_suspend2_suspend_1, 
+	.suspend2 = do_suspend2_suspend_2, 
+	.free_pool_pages = free_suspend_pool_pages,
+	.get_pool_pages = get_suspend_pool_pages,
+	.get_grabbed_pages = get_grabbed_pages,
+	.cleanup_finished_io = cleanup_finished_suspend_io,
+	.suspend_message = __suspend_message,
+	.update_status = update_status,
+	.prepare_status = prepare_status,
+	.schedule_message = schedule_suspend_message,
+	.early_boot_plugins = suspend_early_boot_message_plugins,
+	.keypress = suspend_keypress,
+	.verify_checksums = __suspend2_verify_checksums,
+};
+
+static struct proc_dir_entry *compat_parent;
+extern void suspend_memory_pool_init(void);
+
+static __init int core_load(void)
+{
+	int i, numfiles = sizeof(proc_params) / sizeof(struct suspend_proc_data);
+
+	if (suspend2_register_core(&core_ops))
+		return -EBUSY;
+
+	printk("Software Suspend Core.\n");
+	for (i=0; i< numfiles; i++)
+		suspend_register_procfile(&proc_params[i]);
+
+	suspend_console_proc_init();
+
+	suspend_memory_pool_init();
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	return 0;
+#else
+	return (!!compat_parent);
+#endif
+}
+
+#ifdef MODULE
+static __exit void core_unload(void)
+{
+	int i, numfiles = sizeof(proc_params) / sizeof(struct suspend_proc_data);
+
+	printk("Software Suspend Core unloading.\n");
+	suspend_console_proc_exit();
+
+	for (i=0; i< numfiles; i++)
+		suspend_unregister_procfile(&proc_params[i]);
+
+	suspend2_unregister_core();
+}
+
+module_init(core_load);
+module_exit(core_unload);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Nigel Cunningham");
+MODULE_DESCRIPTION("Suspend2 core");
+#else
+late_initcall(core_load);
+#endif
+EXPORT_SYMBOL(checksum_map);
+EXPORT_SYMBOL(attempt_to_parse_resume_device);



  parent reply	other threads:[~2004-11-24 13:49 UTC|newest]

Thread overview: 244+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-11-24 12:56 Suspend 2 merge Nigel Cunningham
2004-11-24 12:56 ` Suspend2 merge: 1/51: Device trees Nigel Cunningham
2004-11-24 12:56 ` Suspend2 merge: 2/51: Find class by name Nigel Cunningham
2004-11-24 12:57 ` Suspend 2 merge: 3/51: e820 table support Nigel Cunningham
2004-11-25 16:53   ` Pavel Machek
2004-11-24 12:57 ` Suspend 2 merge: 4/51: Get module list Nigel Cunningham
2004-11-25 16:56   ` Pavel Machek
2004-11-25 21:25     ` Nigel Cunningham
2004-11-25 21:32       ` Pavel Machek
2004-11-24 12:57 ` Suspend 2 merge: 5/51: Workthread freezer support Nigel Cunningham
2004-11-25 16:57   ` Pavel Machek
2004-11-24 12:57 ` Suspend 2 merge: 7/51: Reboot handler hook Nigel Cunningham
2004-11-24 13:07   ` Christoph Hellwig
2004-11-24 20:19     ` Nigel Cunningham
2004-11-25  2:37       ` Nigel Cunningham
2004-11-24 12:57 ` Suspend 2 merge: 8/51: /proc/acpi/sleep hook Nigel Cunningham
2004-11-24 13:13   ` Christoph Hellwig
2004-11-24 12:57 ` Suspend 2 merge: 9/51: init/* changes Nigel Cunningham
2004-11-25 17:07   ` Pavel Machek
2004-11-25 21:36     ` Nigel Cunningham
2004-11-25 21:45       ` Pavel Machek
2004-11-25 21:51         ` Nigel Cunningham
2004-11-25 21:58           ` Pavel Machek
2004-11-25 22:03             ` Nigel Cunningham
2004-11-25 22:30               ` Pavel Machek
2004-11-27  2:14     ` Matthew Garrett
2004-11-27  7:22       ` Pavel Machek
2004-11-27  9:31         ` Herbert Xu
2004-11-27 13:21           ` Matthew Garrett
2004-11-27 16:20             ` Pavel Machek
2004-11-28 22:43             ` Nigel Cunningham
2004-11-24 12:57 ` Suspend 2 merge: 10/51: Exports for suspend built as modules Nigel Cunningham
2004-11-24 13:12   ` Christoph Hellwig
2004-11-24 21:52     ` Nigel Cunningham
2004-11-24 14:44   ` Ingo Molnar
2004-11-24 20:46     ` Nigel Cunningham
2004-11-25 18:07   ` Pavel Machek
2004-11-25 21:40     ` Nigel Cunningham
2004-11-25 21:50       ` Pavel Machek
2004-11-24 12:57 ` Suspend 2 merge: 11/51: Export vt functions Nigel Cunningham
2004-11-24 12:57 ` Suspend 2 merge:L 12/51: Disable OOM killer when suspending Nigel Cunningham
2004-11-25 18:12   ` Pavel Machek
2004-11-25 21:47     ` Nigel Cunningham
2004-11-25 21:54       ` Pavel Machek
2004-11-24 12:57 ` Suspend 2 merge: 13/51: Disable highmem tlb flush for copyback Nigel Cunningham
2004-11-25 18:13   ` Pavel Machek
2004-11-24 12:57 ` Suspend 2 merge: 14/51: Disable page alloc failure message when suspending Nigel Cunningham
2004-11-24 14:15   ` Christoph Hellwig
2004-11-24 20:46     ` Nigel Cunningham
2004-11-24 16:00   ` Dave Hansen
2004-11-24 21:06     ` Nigel Cunningham
2004-11-24 22:25       ` Dave Hansen
2004-11-25 18:15   ` Pavel Machek
2004-11-25 21:49     ` Nigel Cunningham
2004-11-25 21:56       ` Pavel Machek
2004-11-25 22:46         ` Nigel Cunningham
2004-11-25 23:22           ` Pavel Machek
2004-11-24 12:58 ` Suspend 2 merge: 15/51: Disable pdflush during suspend Nigel Cunningham
2004-11-24 12:58 ` Suspend 2 merge: 16/51: Disable cache reaping " Nigel Cunningham
2004-11-25 18:18   ` Pavel Machek
2004-11-25 22:00     ` Nigel Cunningham
2004-11-24 12:58 ` Suspend 2 merge: 17/51: Disable MCE checking " Nigel Cunningham
2004-11-25 18:19   ` Pavel Machek
2004-11-25 22:05     ` Nigel Cunningham
2004-11-25 22:31       ` Pavel Machek
2004-11-25 22:38         ` Nigel Cunningham
2004-11-25 22:45           ` Pavel Machek
2004-11-24 12:58 ` Suspend 2 merge: 18/51: Debug page_alloc support Nigel Cunningham
2004-11-24 16:02   ` Dave Hansen
2004-11-24 20:17     ` Nigel Cunningham
2004-11-24 22:26       ` Dave Hansen
2004-11-25 18:21   ` Pavel Machek
2004-11-25 22:06     ` Nigel Cunningham
2004-11-24 12:58 ` Suspend 2 merge: 19/51: Remove MTRR sysdev support Nigel Cunningham
2004-11-24 16:27   ` Zwane Mwaikambo
2004-11-24 20:17     ` Nigel Cunningham
2004-11-25 18:22   ` Pavel Machek
2004-11-28 22:34     ` Nigel Cunningham
2004-11-24 12:58 ` Suspend 2 merge: 20/51: Timer freezer (experimental) Nigel Cunningham
2004-11-24 12:58 ` Suspend 2 merge: 21/51: Refrigerator upgrade Nigel Cunningham
2004-11-25 18:33   ` Pavel Machek
2004-11-25 22:10     ` Nigel Cunningham
2004-11-25 22:36       ` Pavel Machek
2004-11-25 22:49         ` Nigel Cunningham
2004-11-25 23:25           ` Pavel Machek
2004-11-25 23:49             ` Nigel Cunningham
2004-11-26  0:05               ` Pavel Machek
2004-11-26  0:12                 ` Nigel Cunningham
2004-11-26  0:18                   ` Pavel Machek
2004-11-27 17:18                   ` Pavel Machek
2004-11-26 21:00       ` Christoph Hellwig
2004-11-24 12:58 ` Suspend 2 merge: 22/51: Suspend2 lowlevel code Nigel Cunningham
2004-11-24 16:42   ` Zwane Mwaikambo
2004-11-24 21:20     ` Nigel Cunningham
2004-11-24 21:55       ` Zwane Mwaikambo
2004-11-24 21:56         ` Nigel Cunningham
2004-11-25 18:39   ` Pavel Machek
2004-11-25 22:15     ` Nigel Cunningham
2004-11-25 22:38       ` Pavel Machek
2004-11-24 12:58 ` Suspend 2 merge: 23/51: PPC support Nigel Cunningham
2004-11-25 18:40   ` Pavel Machek
2004-11-25 22:15     ` Nigel Cunningham
2004-11-24 12:59 ` Suspend 2 merge: 24/51: Keyboard and serial console hooks Nigel Cunningham
2004-11-24 13:29   ` Christoph Hellwig
2004-11-24 18:47     ` Yaroslav Rastrigin
2004-11-24 21:38     ` Nigel Cunningham
2004-11-24 21:57     ` Jan Rychter
2004-11-24 23:02       ` Christoph Hellwig
2004-11-25  1:22         ` Jan Rychter
2004-11-25 10:08           ` Christoph Hellwig
2004-11-26 20:21         ` pb
2004-11-25 19:28     ` Pavel Machek
2004-11-28 22:34       ` Nigel Cunningham
2004-11-28 23:39         ` Pavel Machek
2004-11-29 22:15           ` Nigel Cunningham
2004-11-24 12:59 ` Suspend 2 merge: 25/51: Documentation Nigel Cunningham
2004-11-24 12:59 ` Suspend 2 merge: 26/51: Kconfig and makefile Nigel Cunningham
2004-11-24 16:34   ` Roman Zippel
2004-11-24 21:11     ` Nigel Cunningham
2004-11-24 21:46       ` Roman Zippel
2004-11-24 21:53         ` Nigel Cunningham
2004-11-25  2:37     ` Nigel Cunningham
2004-11-24 12:59 ` Suspend 2 merge: 27/51: Block I/O module Nigel Cunningham
2004-11-24 12:59 ` Suspend 2 merge: 28/51: Suspend memory pool hooks Nigel Cunningham
2004-11-25 19:34   ` Pavel Machek
2004-11-24 12:59 ` Suspend 2 merge: 29/51: Clear swapfile bdev in swapoff Nigel Cunningham
2004-11-24 12:59 ` Suspend 2 merge: 30/51: Enable slab alloc fallback to suspend memory pool Nigel Cunningham
2004-11-25 19:36   ` Pavel Machek
2004-11-24 12:59 ` Suspend 2 merge: 31/51: Export tlb flushing Nigel Cunningham
2004-11-24 15:32   ` Martin J. Bligh
2004-11-24 21:04     ` Nigel Cunningham
2004-11-24 12:59 ` Suspend 2 merge: 32/51: Make show task non-static Nigel Cunningham
2004-11-24 12:59 ` Suspend 2 merge: 33/51: More documentation Nigel Cunningham
2004-11-24 13:00 ` Suspend 2 merge: 34/51: Includes Nigel Cunningham
2004-11-24 13:25   ` Christoph Hellwig
2004-11-24 20:17     ` Nigel Cunningham
2004-11-24 23:19       ` Matthew Garrett
2004-11-25  2:43         ` Nigel Cunningham
2004-11-24 13:00 ` Suspend 2 merge: 35/51: Code always built in to the kernel Nigel Cunningham
2004-11-25 23:32   ` Pavel Machek
2004-11-25 23:57     ` Nigel Cunningham
2004-11-26  0:08       ` Pavel Machek
2004-11-26  0:17         ` Nigel Cunningham
2004-11-26  0:23           ` Pavel Machek
2004-11-27  2:19       ` Matthew Garrett
2004-11-28 22:39         ` Nigel Cunningham
2004-11-27  9:00       ` Jan Rychter
2004-11-27 17:22         ` Pavel Machek
2004-11-24 13:00 ` Suspend 2 merge: 36/51: Highlevel I/O routines Nigel Cunningham
2004-11-25 23:36   ` Pavel Machek
2004-11-27  1:39     ` Tomas Carnecky
2004-11-24 13:00 ` Suspend 2 merge: 37/51: Memory pool support Nigel Cunningham
2004-11-25 23:37   ` Pavel Machek
2004-11-24 13:00 ` Suspend 2 merge: 38/51: Page directory support Nigel Cunningham
2004-11-24 13:01 ` Suspend 2 merge: 39/51: Plugins support Nigel Cunningham
2004-11-24 13:01 ` Suspend 2 merge: 40/51: Prepare image Nigel Cunningham
2004-11-24 13:01 ` Suspend 2 merge: 41/51: Ranges (extents) Nigel Cunningham
2004-11-24 13:01 ` Nigel Cunningham [this message]
2004-11-24 16:52   ` Suspend 2 merge: 42/51: Suspend.c Zwane Mwaikambo
2004-11-24 21:23     ` Nigel Cunningham
2004-11-25 23:43   ` Pavel Machek
2004-11-24 13:01 ` Suspend 2 merge: 43/51: Utility functions Nigel Cunningham
2004-11-25 23:46   ` Pavel Machek
2004-11-26  0:04     ` Nigel Cunningham
2004-11-26  0:04       ` Nigel Cunningham
2004-11-27 16:11       ` Dave Hansen
2004-11-27 16:11         ` Dave Hansen
2004-11-28 21:36         ` Nigel Cunningham
2004-11-28 21:36           ` Nigel Cunningham
2004-11-24 13:01 ` Suspend 2 merge: 44/51: Text UI plugin Nigel Cunningham
2004-11-24 13:02 ` Suspend 2 merge: 45/51: Bootsplash support Nigel Cunningham
2004-11-24 13:02 ` Suspend 2 merge: 46/51: LZF support Nigel Cunningham
2004-11-24 23:01   ` Bartlomiej Zolnierkiewicz
2004-11-25  2:38     ` Nigel Cunningham
2004-11-25  6:32       ` hugang
2004-11-25  6:52         ` Dmitry Torokhov
2004-11-25  7:07           ` hugang
2004-11-25 10:10           ` Christoph Hellwig
2004-11-24 13:02 ` Suspend 2 merge: 47/51: GZIP support Nigel Cunningham
2004-11-25 23:50   ` Pavel Machek
2004-11-24 13:02 ` Suspend 2 merge: 48/51: Swapwriter Nigel Cunningham
2004-11-25 23:55   ` Pavel Machek
2004-11-26  0:05     ` Nigel Cunningham
2004-11-24 13:02 ` Suspend 2 merge: 49/51: Checksumming Nigel Cunningham
2004-11-25 23:56   ` Pavel Machek
2004-11-26  0:00     ` Nigel Cunningham
2004-11-26  0:14       ` Pavel Machek
2004-11-29  9:55   ` Rob Landley
2004-11-30  0:24     ` Nigel Cunningham
2004-11-29 23:30       ` Rob Landley
2004-11-30  0:49         ` Nigel Cunningham
2004-11-30 13:07           ` Pavel Machek
2004-11-30 21:45             ` Nigel Cunningham
2004-11-30 13:02     ` Pavel Machek
2004-11-30 13:38       ` Matthew Garrett
2004-11-30 22:38         ` Pavel Machek
2004-12-02 21:31       ` Rob Landley
2004-11-24 13:02 ` Suspend 2 merge: 50/51: Device mapper support Nigel Cunningham
2004-11-25 23:58   ` Pavel Machek
2004-11-26  0:07     ` Nigel Cunningham
2004-12-02 20:40       ` Alasdair G Kergon
2004-12-02 21:04         ` Nigel Cunningham
2004-12-02 21:49           ` Alasdair G Kergon
2004-12-02 22:08             ` Nigel Cunningham
2004-12-03 17:47               ` Alasdair G Kergon
2004-12-03 19:57                 ` Nigel Cunningham
2004-12-03 20:12                   ` Alasdair G Kergon
2004-12-14  0:47                     ` Nigel Cunningham
2004-11-24 13:03 ` Suspend 2 merge: 51/51: Notes Nigel Cunningham
2004-11-26  0:01   ` Pavel Machek
2004-11-26  0:09     ` Nigel Cunningham
2004-11-26  0:24       ` Pavel Machek
2004-11-24 13:03 ` Suspend 2 merge: 6/51 Nigel Cunningham
2004-11-24 13:28 ` Suspend 2 merge Christoph Hellwig
2004-11-24 20:46   ` Nigel Cunningham
2004-11-25 19:20     ` Pavel Machek
2004-11-25 22:34       ` Nigel Cunningham
2004-11-25 23:22         ` Pavel Machek
2004-11-25 23:46           ` Nigel Cunningham
2004-11-26  0:39             ` Pavel Machek
2004-11-26  9:08               ` Nigel Cunningham
2004-11-26 12:38                 ` Pavel Machek
2004-11-26 15:54                   ` Christoph Hellwig
2004-11-26 22:36                     ` Pavel Machek
2004-11-28 22:35                   ` Nigel Cunningham
2004-11-28 23:55                     ` Pavel Machek
2004-11-29  3:20                       ` Nigel Cunningham
2004-11-29 13:03                         ` Pavel Machek
2004-11-30  0:24                           ` Nigel Cunningham
2004-11-30 10:19                             ` Pavel Machek
     [not found]               ` <20041126082109.GA842@hugang.soulinfo.com>
2004-11-26 13:25                 ` Pavel Machek
     [not found]               ` <20041126043203.GA2713@hugang.soulinfo.com>
2004-11-26  9:08                 ` Nigel Cunningham
2004-11-26 13:37                   ` Pavel Machek
2004-11-26 13:31                 ` Pavel Machek
2004-11-28 21:40               ` Nigel Cunningham
2004-11-29  9:34             ` Stefan Seyfried
2004-11-29 22:20               ` Nigel Cunningham
2004-11-29 22:34                 ` Pavel Machek
2004-11-30 12:16                 ` Stefan Seyfried
2004-11-30 21:16                   ` Nigel Cunningham
2004-11-30 22:20                     ` Pavel Machek
2004-12-01  9:27                       ` Nigel Cunningham
2004-12-01 10:08                         ` Pavel Machek
2004-12-01 20:39                           ` Nigel Cunningham

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1101299659.5805.367.camel@desktop.cunninghams \
    --to=ncunningham@linuxmail.org \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.