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/