[PATCH] Preserve hibenate-system-image on startup

From: Hiroyuki Machida
Date: Sun Jul 17 2005 - 01:27:24 EST



We are now investigating fast startup/shutdown using
2.6 kernel PM functions.

An attached patch enables kernel to preserve system image
on startup, to implement "Snapshot boot".Majordomo@xxxxxxxxxxxxxxx wrote:
Conventionally system image will be broken after startup.

Snapshot boot uses un-hibernate from a permanent system image for
startup. During shutdown, does a conventional shutdown without
saving a system image.

We'll explain concept and initial work at OLS. So if you have
interest, we can talk with you at Ottawa.

Thanks,
Hiroyuki Machida

---

This patch enables preserving swsuspend system image over boot cycle,
against 2.6.12

Signed-off-by: Hiroyui Machida <machida@xxxxxxxxxx> for CELF

-----------------
Index: alp-linux--dev-2-6-12--1.7/kernel/power/Kconfig
===================================================================
--- alp-linux--dev-2-6-12--1.7.orig/kernel/power/Kconfig 2005-07-15 14:59:20.000000000 -0400
+++ alp-linux--dev-2-6-12--1.7/kernel/power/Kconfig 2005-07-16 00:43:31.420000000 -0400
@@ -84,6 +84,20 @@
suspended image to. It will simply pick the first available swap
device.

+config PRESERVE_SWSUSP_IMAGE
+ bool "Preserve swsuspend image"
+ depends on SOFTWARE_SUSPEND
+ default n
+ ---help---
+ Useally boot with swsup destories the swsusp image.
+ This function enables to preserve swsup image over boot cycle.
+ Default behavior is not chaged even this configuration turned on.
+
+ To preseve swsusp image, specify following option to command line;
+
+ prsv-img
+
+
config DEFERRED_RESUME
bool "Deferred resume"
depends on PM
Index: alp-linux--dev-2-6-12--1.7/kernel/power/disk.c
===================================================================
--- alp-linux--dev-2-6-12--1.7.orig/kernel/power/disk.c 2005-07-16 00:43:02.990000000 -0400
+++ alp-linux--dev-2-6-12--1.7/kernel/power/disk.c 2005-07-16 01:01:42.220000000 -0400
@@ -29,10 +29,29 @@
extern void swsusp_close(void);
extern int swsusp_resume(void);
extern int swsusp_free(void);
+extern void dump_pagedir_nosave(void);
#ifdef CONFIG_SAFE_SUSPEND
extern int suspend_remount(void);
extern int resume_remount(void);
#endif
+#ifdef CONFIG_PRESERVE_SWSUSP_IMAGE
+extern int preserve_swsusp_image;
+extern dev_t swsusp_resume_device_nosave __nosavedata;
+extern int swsusp_swap_rdonly(dev_t);
+extern int swsusp_swap_off(dev_t);
+#else
+#define preserve_swsusp_image 0
+#define swsusp_resume_device_nosave 0
+static inline int swsusp_swap_rdonly(dev_t dev)
+{
+ return 0;
+}
+static inline int swsusp_swap_off(dev_t dev)
+{
+ return 0;
+}
+#endif
+


static int noresume = 0;
@@ -135,6 +154,26 @@
pm_restore_console();
}

+#ifdef CONFIG_PRESERVE_SWSUSP_IMAGE
+void finish_in_resume(void)
+{
+ device_resume();
+ platform_finish();
+ enable_nonboot_cpus();
+ thaw_processes();
+ if (preserve_swsusp_image) {
+ swsusp_swap_off(swsusp_resume_device_nosave);
+ }
+ pm_restore_console();
+}
+#else
+void finish_in_resume(void)
+{
+ finish();
+}
+#endif
+
+
extern atomic_t on_suspend; /* See refrigerator() */

static int prepare_processes(void)
@@ -234,8 +273,15 @@
error = swsusp_write();
if (!error)
power_down(pm_disk_mode);
- } else
+ } else {
pr_debug("PM: Image restored successfully.\n");
+ if (preserve_swsusp_image) {
+ swsusp_swap_rdonly(swsusp_resume_device_nosave);
+ }
+ swsusp_free();
+ finish_in_resume();
+ return 0;
+ }
swsusp_free();
Done:
finish();
Index: alp-linux--dev-2-6-12--1.7/kernel/power/swsusp.c
===================================================================
--- alp-linux--dev-2-6-12--1.7.orig/kernel/power/swsusp.c 2005-07-16 00:43:03.000000000 -0400
+++ alp-linux--dev-2-6-12--1.7/kernel/power/swsusp.c 2005-07-16 00:56:22.170000000 -0400
@@ -128,6 +128,11 @@

static struct swsusp_info swsusp_info;

+#ifdef CONFIG_PRESERVE_SWSUSP_IMAGE
+dev_t swsusp_resume_device_nosave __nosavedata;
+struct swsusp_header swsusp_header_nosave __nosavedata ;
+#endif
+
/*
* XXX: We try to keep some more pages free so that I/O operations succeed
* without paging. Might this be more?
@@ -139,6 +144,24 @@
#define PAGES_FOR_IO 512
#endif

+#ifdef CONFIG_PRESERVE_SWSUSP_IMAGE
+int preserve_swsusp_image=0;
+static int __init preserve_swsusp_image_setup(char *str)
+{
+ if (*str)
+ return 0;
+ preserve_swsusp_image = 1;
+ return 1;
+}
+#else
+static int __init preserve_swsusp_image_setup(char *str)
+{
+ return 0;
+}
+#endif
+
+__setup("prsv-img", preserve_swsusp_image_setup);
+
/*
* Saving part...
*/
@@ -1250,6 +1273,53 @@
return error;
}

+#ifdef CONFIG_PRESERVE_SWSUSP_IMAGE
+/**
+ * mark_swapfiles - Revert swap signature
+ *
+ * Assumed that swsusp_header holds correct data
+ * and rw_swap_page_sync() works
+ */
+int mark_swsusp(dev_t dev)
+{
+ int error;
+
+ resume_bdev = open_by_devnum(dev, FMODE_WRITE);
+ if (!IS_ERR(resume_bdev)) {
+ set_blocksize(resume_bdev, PAGE_SIZE);
+ error = bio_write_page(0, &swsusp_header_nosave);
+ blkdev_put(resume_bdev);
+ } else
+ error = PTR_ERR(resume_bdev);
+
+ if (!error)
+ pr_debug("swsusp: Mark swsusp again\n");
+ else
+ pr_debug("swsusp: Error %d marking swsusp\n", error);
+ return error;
+}
+
+inline static void update_swsusp_header(void)
+{
+ swsusp_header_nosave=swsusp_header;
+}
+
+inline static void update_swsusp_device(void)
+{
+ swsusp_resume_device_nosave = swsusp_resume_device;
+}
+#else
+inline static void update_swsusp_header(void)
+{
+ ;
+}
+
+inline static void update_swsusp_device(void)
+{
+ ;
+}
+#endif
+
static int check_sig(void)
{
int error;
@@ -1258,6 +1328,7 @@
if ((error = bio_read_page(0, &swsusp_header)))
return error;
if (!memcmp(SWSUSP_SIG, swsusp_header.sig, 10)) {
+ update_swsusp_header();
memcpy(swsusp_header.sig, swsusp_header.orig_sig, 10);

/*
@@ -1412,6 +1483,7 @@
pr_debug("swsusp: Resume From Partition %d:%d\n",
MAJOR(swsusp_resume_device), MINOR(swsusp_resume_device));
}
+ update_swsusp_device();

resume_bdev = open_by_devnum(swsusp_resume_device, FMODE_READ);
if (!IS_ERR(resume_bdev)) {
Index: alp-linux--dev-2-6-12--1.7/mm/swapfile.c
===================================================================
--- alp-linux--dev-2-6-12--1.7.orig/mm/swapfile.c 2005-07-15 10:34:54.000000000 -0400
+++ alp-linux--dev-2-6-12--1.7/mm/swapfile.c 2005-07-16 00:43:31.000000000 -0400
@@ -1065,6 +1065,186 @@
}
#endif

+#ifdef CONFIG_PRESERVE_SWSUSP_IMAGE
+extern int mark_swsusp(dev_t);
+
+#ifdef DEBUG
+extern void cons_write(char *);
+
+#undef pr_debug
+#define pr_debug(fmt,arg...) \
+ do { \
+ char __cw_buf[64]; \
+ __cw_buf[63]='\0'; \
+ snprintf(__cw_buf, 63, fmt,##arg); \
+ cons_write(__cw_buf); \
+ } while (0)
+#endif /*DEBUG*/
+
+/**
+ * find_swapdev_info - Find swap block device info, currently used
+ *
+ */
+
+static struct swap_info_struct *find_swapdev_info(dev_t dev,
+ int *p_prev, int *p_type)
+{
+ int prev, type;
+ struct inode *inode;
+ struct swap_info_struct * si = NULL;
+
+ prev = -1;
+ for (type = swap_list.head; type >= 0; type = swap_info[type].next) {
+ si = swap_info + type;
+ pr_debug("P:0x%8.8x, TYPE:0x%8.8x\n", (int)si, type);
+ if (si->flags & SWP_USED) {
+ inode = si->swap_file->f_mapping->host;
+ if (S_ISBLK(inode->i_mode)) {
+ pr_debug("INODE: 0x%8.8x:0x%8.8x\n",
+ dev,
+ MKDEV(imajor(inode), iminor(inode)));
+ if (dev == MKDEV(imajor(inode), iminor(inode)))
+ break;
+ }
+ }
+ prev = type;
+ }
+
+ if (type<0) {
+ si = 0;
+ }
+ *p_type = type;
+ *p_prev = prev;
+ return si;
+}
+
+/**
+ * swsusp_swap_rdonly - Find Swap device for swsusp and mark ReadOnly
+ *
+ */
+int swsusp_swap_rdonly(dev_t resume_dev)
+{
+ struct swap_info_struct * si = NULL;
+ int prev;
+ int type;
+ int found=0;
+
+ swap_list_lock();
+
+ si = find_swapdev_info(resume_dev, &prev, &type);
+ if (si) {
+ si->flags &= ~SWP_WRITEOK;
+ found = 1;
+ }
+ swap_list_unlock();
+ return found;
+
+}
+
+/**
+ * swsusp_swpoff - Turn off swap and set signature for swsusp image
+ *
+ */
+int swsusp_swap_off(dev_t resume_dev)
+{
+ struct swap_info_struct * si = NULL;
+ unsigned short *swap_map;
+ int i;
+ int type, prev;
+ struct block_device *bdev;
+ int err = 0;
+
+ swap_list_lock();
+
+ si = find_swapdev_info(resume_dev, &prev, &type);
+
+ /* swap area for swsusp image is not writable */
+ if ((!si) || (si->flags & SWP_WRITEOK)) {
+ err = -EINVAL;
+ swap_list_unlock();
+ goto out;
+ }
+
+ if (!security_vm_enough_memory(si->pages)) {
+ vm_unacct_memory(si->pages);
+ } else {
+ err = -ENOMEM;
+ si->flags |= SWP_WRITEOK;
+ swap_list_unlock();
+ goto out;
+ }
+
+ pr_debug("swsusp_swapoff:inuse_pages:%ld\n", si->inuse_pages);
+ pr_debug("swsusp_swapoff:pages:%d\n", si->pages);
+ if (prev < 0) {
+ swap_list.head = si->next;
+ } else {
+ swap_info[prev].next = si->next;
+ }
+ if (type == swap_list.next) {
+ /* just pick something that's safe... */
+ swap_list.next = swap_list.head;
+ }
+ nr_swap_pages -= si->pages;
+ total_swap_pages -= si->pages;
+ bdev = I_BDEV(si->swap_file->f_mapping->host);
+ swap_list_unlock();
+
+ current->flags |= PF_SWAPOFF;
+ err = try_to_unuse(type);
+ current->flags &= ~PF_SWAPOFF;
+
+ /* wait for any unplug function to finish */
+ down_write(&swap_unplug_sem);
+ up_write(&swap_unplug_sem);
+
+ if (err) {
+ pr_debug("swsusp_swapoff:err:%d\n", err);
+ /* re-insert swap space back into swap_list */
+ swap_list_lock();
+ for (prev = -1, i = swap_list.head; i >= 0; prev = i, i = swap_info[i].next)
+ if (si->prio >= swap_info[i].prio)
+ break;
+ si->next = i;
+ if (prev < 0)
+ swap_list.head = swap_list.next = si - swap_info;
+ else
+ swap_info[prev].next = si - swap_info;
+ nr_swap_pages += si->pages;
+ total_swap_pages += si->pages;
+ si->flags |= SWP_WRITEOK;
+ swap_list_unlock();
+ goto out;
+ }
+
+ down(&swapon_sem);
+ swap_list_lock();
+ drain_mmlist();
+ swap_device_lock(si);
+ si->swap_file = NULL;
+ si->max = 0;
+ swap_map = si->swap_map;
+ si->swap_map = NULL;
+ si->flags = 0;
+ destroy_swap_extents(si);
+ swap_device_unlock(si);
+ swap_list_unlock();
+ up(&swapon_sem);
+ vfree(swap_map);
+
+ /* set SWSUSP signature, again */
+ mark_swsusp(resume_dev);
+
+ /* release device */
+ set_blocksize(bdev, si->old_block_size);
+ bd_release(bdev);
+ err = 0;
+
+out:
+ return err;
+}
+#endif /*CONFIG_PRESERVE_SWSUSP_IMAGE*/
+
asmlinkage long sys_swapoff(const char __user * specialfile)
{
struct swap_info_struct * p = NULL;
---




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