From: Pavel Machek software_suspend() can fail for quite a lot of reasons (for example not enough swapspace). However current interface returned void, so you could not propagate error back to userland. This fixes it. Plus __read_suspend_image() is only done during init time, so we might as well mark it __init. --- include/linux/suspend.h | 26 +++++++++++++++++++------- kernel/power/swsusp.c | 35 +++++++++++++++++------------------ kernel/sys.c | 8 +++----- 3 files changed, 39 insertions(+), 30 deletions(-) diff -puN include/linux/suspend.h~swsusp-software_suspend-retval-fix include/linux/suspend.h --- 25/include/linux/suspend.h~swsusp-software_suspend-retval-fix 2004-01-20 21:32:38.000000000 -0800 +++ 25-akpm/include/linux/suspend.h 2004-01-20 21:32:38.000000000 -0800 @@ -42,31 +42,43 @@ extern int shrink_mem(void); /* mm/page_alloc.c */ extern void drain_local_pages(void); +/* kernel/power/swsusp.c */ +extern int software_suspend(void); + extern unsigned int nr_copy_pages __nosavedata; extern suspend_pagedir_t *pagedir_nosave __nosavedata; -#endif /* CONFIG_PM */ - -#ifdef CONFIG_SOFTWARE_SUSPEND - -extern unsigned char software_suspend_enabled; -extern void software_suspend(void); #else /* CONFIG_SOFTWARE_SUSPEND */ -static inline void software_suspend(void) +static inline int software_suspend(void) { printk("Warning: fake suspend called\n"); + return -EPERM; } +#define software_resume() do { } while(0) #endif /* CONFIG_SOFTWARE_SUSPEND */ #ifdef CONFIG_PM extern void refrigerator(unsigned long); +extern int freeze_processes(void); +extern void thaw_processes(void); + +extern int pm_prepare_console(void); +extern void pm_restore_console(void); #else static inline void refrigerator(unsigned long flag) { } +static inline int freeze_processes(void) +{ + return 0; +} +static inline void thaw_processes(void) +{ + +} #endif /* CONFIG_PM */ #endif /* _LINUX_SWSUSP_H */ diff -puN kernel/power/swsusp.c~swsusp-software_suspend-retval-fix kernel/power/swsusp.c --- 25/kernel/power/swsusp.c~swsusp-software_suspend-retval-fix 2004-01-20 21:32:38.000000000 -0800 +++ 25-akpm/kernel/power/swsusp.c 2004-01-20 21:32:38.000000000 -0800 @@ -677,11 +677,22 @@ void do_magic_suspend_2(void) mark_swapfiles(((swp_entry_t) {0}), MARK_SWAP_RESUME); } -static void do_software_suspend(void) +/* + * This is main interface to the outside world. It needs to be + * called from process context. + */ +int software_suspend(void) { + int res; + if (!software_suspend_enabled) + return -EAGAIN; + + software_suspend_enabled = 0; + might_sleep(); + if (arch_prepare_suspend()) { printk("%sArchitecture failed to prepare\n", name_suspend); - return; + return -EPERM; } if (pm_prepare_console()) printk( "%sCan't allocate a console... proceeding\n", name_suspend); @@ -711,24 +722,12 @@ static void do_software_suspend(void) */ do_magic(0); thaw_processes(); - } + } else + res = -EBUSY; software_suspend_enabled = 1; MDELAY(1000); pm_restore_console(); -} - -/* - * This is main interface to the outside world. It needs to be - * called from process context. - */ -void software_suspend(void) -{ - if(!software_suspend_enabled) - return; - - software_suspend_enabled = 0; - might_sleep(); - do_software_suspend(); + return res; } /* More restore stuff */ @@ -898,7 +897,7 @@ static int bdev_write_page(struct block_ extern dev_t __init name_to_dev_t(const char *line); -static int __read_suspend_image(struct block_device *bdev, union diskpage *cur, int noresume) +static int __init __read_suspend_image(struct block_device *bdev, union diskpage *cur, int noresume) { swp_entry_t next; int i, nr_pgdir_pages; diff -puN kernel/sys.c~swsusp-software_suspend-retval-fix kernel/sys.c --- 25/kernel/sys.c~swsusp-software_suspend-retval-fix 2004-01-20 21:32:38.000000000 -0800 +++ 25-akpm/kernel/sys.c 2004-01-20 21:32:38.000000000 -0800 @@ -475,13 +475,11 @@ asmlinkage long sys_reboot(int magic1, i #ifdef CONFIG_SOFTWARE_SUSPEND case LINUX_REBOOT_CMD_SW_SUSPEND: - if (!software_suspend_enabled) { + { + int ret = software_suspend(); unlock_kernel(); - return -EAGAIN; + return ret; } - software_suspend(); - do_exit(0); - break; #endif default: _