Hi.

We've had this feature in Suspend2 for a couple of years and I can
confirm that the approach works, provided that the on-disk filesystem
remains unchanged throughout this. (Useful mainly for kiosks etc).

This is not to say that I've reviewed the code below for correctness.

Regards,

Nigel

On Sun, 2005-07-17 at 16:26, Hiroyuki Machida wrote:
> 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/
-- 
Evolution.
Enumerate the requirements.
Consider the interdependencies.
Calculate the probabilities.
Be amazed that people believe it happened. 

-
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