Since pm_ops->finish() has to be called after enable_nonboot_cpus() and before device_resume(), from the userland interface perspective it should be treated as a part of the atomic suspend and resume operations. For this reason we need two additional ioctls to be called instead of ATOMIC_SNAPSHOT and ATOMIC_RESTORE, respectively, when the platform suspend mode is to be used. Signed-off-by: Rafael J. Wysocki <rjw at sisk.pl> --- kernel/power/power.h | 4 ++ kernel/power/user.c | 71 +++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 64 insertions(+), 11 deletions(-) Index: linux-2.6.19-rc6-mm1/kernel/power/power.h =================================================================== --- linux-2.6.19-rc6-mm1.orig/kernel/power/power.h +++ linux-2.6.19-rc6-mm1/kernel/power/power.h @@ -133,7 +133,9 @@ struct resume_swap_area { #define SNAPSHOT_PMOPS _IOW(SNAPSHOT_IOC_MAGIC, 12, unsigned int) #define SNAPSHOT_SET_SWAP_AREA _IOW(SNAPSHOT_IOC_MAGIC, 13, \ struct resume_swap_area) -#define SNAPSHOT_IOC_MAXNR 13 +#define SNAPSHOT_PLATFORM_SNAPSHOT _IOW(SNAPSHOT_IOC_MAGIC, 14, unsigned int) +#define SNAPSHOT_PLATFORM_RESTORE _IO(SNAPSHOT_IOC_MAGIC, 15) +#define SNAPSHOT_IOC_MAXNR 15 #define PMOPS_PREPARE 1 #define PMOPS_ENTER 2 Index: linux-2.6.19-rc6-mm1/kernel/power/user.c =================================================================== --- linux-2.6.19-rc6-mm1.orig/kernel/power/user.c +++ linux-2.6.19-rc6-mm1/kernel/power/user.c @@ -122,7 +122,23 @@ static ssize_t snapshot_write(struct fil return res; } -static int snapshot_suspend(void) +static inline int platform_prepare(void) +{ + int error = 0; + + if (pm_ops && pm_ops->prepare) + error = pm_ops->prepare(PM_SUSPEND_DISK); + + return error; +} + +static inline void platform_finish(void) +{ + if (pm_ops && pm_ops->finish) + pm_ops->finish(PM_SUSPEND_DISK); +} + +static int snapshot_suspend(int platform_mode) { int error; @@ -132,6 +148,11 @@ static int snapshot_suspend(void) if (error) goto Finish; + if (platform_mode) { + error = platform_prepare(); + if (error) + goto Finish; + } suspend_console(); error = device_suspend(PMSG_FREEZE); if (error) @@ -144,6 +165,9 @@ static int snapshot_suspend(void) } enable_nonboot_cpus(); Resume_devices: + if (platform_mode) + platform_finish(); + device_resume(); resume_console(); Finish: @@ -151,12 +175,17 @@ static int snapshot_suspend(void) return error; } -static int snapshot_restore(void) +static int snapshot_restore(int platform_mode) { int error; mutex_lock(&pm_mutex); pm_prepare_console(); + if (platform_mode) { + error = platform_prepare(); + if (error) + goto Finish; + } suspend_console(); error = device_suspend(PMSG_PRETHAW); if (error) @@ -168,8 +197,12 @@ static int snapshot_restore(void) enable_nonboot_cpus(); Resume_devices: + if (platform_mode) + platform_finish(); + device_resume(); resume_console(); + Finish: pm_restore_console(); mutex_unlock(&pm_mutex); return error; @@ -221,7 +254,7 @@ static int snapshot_ioctl(struct inode * error = -EPERM; break; } - error = snapshot_suspend(); + error = snapshot_suspend(0); if (!error) error = put_user(in_suspend, (unsigned int __user *)arg); if (!error) @@ -235,7 +268,7 @@ static int snapshot_ioctl(struct inode * error = -EPERM; break; } - error = snapshot_restore(); + error = snapshot_restore(0); break; case SNAPSHOT_FREE: @@ -345,9 +378,7 @@ static int snapshot_ioctl(struct inode * switch (arg) { case PMOPS_PREPARE: - if (pm_ops->prepare) { - error = pm_ops->prepare(PM_SUSPEND_DISK); - } + error = platform_prepare(); break; case PMOPS_ENTER: @@ -356,9 +387,7 @@ static int snapshot_ioctl(struct inode * break; case PMOPS_FINISH: - if (pm_ops && pm_ops->finish) { - pm_ops->finish(PM_SUSPEND_DISK); - } + platform_finish(); break; default: @@ -399,6 +428,28 @@ static int snapshot_ioctl(struct inode * } break; + case SNAPSHOT_PLATFORM_SNAPSHOT: + if (data->mode != O_RDONLY || !data->frozen || data->ready) { + error = -EPERM; + break; + } + error = snapshot_suspend(1); + if (!error) + error = put_user(in_suspend, (unsigned int __user *)arg); + if (!error) + data->ready = 1; + break; + + case SNAPSHOT_PLATFORM_RESTORE: + snapshot_write_finalize(&data->handle); + if (data->mode != O_WRONLY || !data->frozen || + !snapshot_image_loaded(&data->handle)) { + error = -EPERM; + break; + } + error = snapshot_restore(1); + break; + default: error = -ENOTTY;