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"[EMAIL PROTECTED] 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 <[EMAIL PROTECTED]> 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 [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to