From: Patrick Mochel Below is a patch that should fix the problem. The problem was due to the fact that I removed the kernel_fpu_end() call from kernel/power/swsusp.c::swsusp_suspend(). kernel_fpu_end() disables preempt, which causes any subsequent schedule() to trigger that BUG(). I apologize for this regression. The patch needs a bit more explanation, because I didn't simply replace the call. Doing so would be a layering violation of the structure of the code. kernel_fpu_end() is called by save_processor_state(), which is called by swsusp_arch_suspend(). We should be calling it from the same chain, and we shouldn't be calling a function from generic code that is defined on only two architectures. I modified swsusp_arch_suspend() to unconditionally call restore_processor_state() when exiting, which provides the same layering. However, it is still too late WRT to the other things that swsusp_suspend() was doing (resuming drivers and writing the image). Since those are unrelated to snapshotting memory, I divorced them from the function. swsusp_save() now is the function that is responsible for snapshoting memory, while swsusp_write() is responsible for writing the image, only. The resulting code is cleaner and more streamlined. It behaves as predicted locally. Please try it and report whether or not it works for you. Andrew, please apply this to -test4-mm5. I realize I said I would not touch swsusp any more, and this patch may become irrelevant in the future. But, it fixes a real bug now. 25-akpm/arch/i386/power/swsusp.S | 2 - 25-akpm/kernel/power/disk.c | 28 +++++++++++------------- 25-akpm/kernel/power/main.c | 9 +++---- 25-akpm/kernel/power/swsusp.c | 44 +++++++++++++++------------------------ 4 files changed, 36 insertions(+), 47 deletions(-) diff -puN arch/i386/power/swsusp.S~swsusp-fpu-fix arch/i386/power/swsusp.S --- 25/arch/i386/power/swsusp.S~swsusp-fpu-fix Thu Sep 4 13:16:18 2003 +++ 25-akpm/arch/i386/power/swsusp.S Thu Sep 4 13:16:18 2003 @@ -76,10 +76,10 @@ ENTRY(swsusp_arch_suspend) movl saved_context_edx, %edx movl saved_context_esi, %esi movl saved_context_edi, %edi - call restore_processor_state pushl saved_context_eflags ; popfl call swsusp_resume .L1449: + call restore_processor_state popl %ebx ret diff -puN kernel/power/disk.c~swsusp-fpu-fix kernel/power/disk.c --- 25/kernel/power/disk.c~swsusp-fpu-fix Thu Sep 4 13:16:18 2003 +++ 25-akpm/kernel/power/disk.c Thu Sep 4 13:16:18 2003 @@ -163,27 +163,27 @@ int pm_suspend_disk(void) pr_debug("PM: snapshotting memory.\n"); in_suspend = 1; - local_irq_disable(); if ((error = swsusp_save())) goto Done; - pr_debug("PM: writing image.\n"); + if (in_suspend) { + pr_debug("PM: writing image.\n"); - /* - * FIXME: Leftover from swsusp. Are they necessary? - */ - mb(); - barrier(); - - error = swsusp_write(); - if (!error && in_suspend) { - error = power_down(pm_disk_mode); - pr_debug("PM: Power down failed.\n"); + /* + * FIXME: Leftover from swsusp. Are they necessary? + */ + mb(); + barrier(); + + error = swsusp_write(); + if (!error) { + error = power_down(pm_disk_mode); + pr_debug("PM: Power down failed.\n"); + } } else pr_debug("PM: Image restored successfully.\n"); swsusp_free(); Done: - local_irq_enable(); finish(); return error; } @@ -217,7 +217,6 @@ static int pm_resume(void) barrier(); mb(); - local_irq_disable(); /* FIXME: The following (comment and mdelay()) are from swsusp. * Are they really necessary? @@ -231,7 +230,6 @@ static int pm_resume(void) pr_debug("PM: Restoring saved image.\n"); swsusp_restore(); - local_irq_enable(); pr_debug("PM: Restore failed, recovering.n"); finish(); Free: diff -puN kernel/power/main.c~swsusp-fpu-fix kernel/power/main.c --- 25/kernel/power/main.c~swsusp-fpu-fix Thu Sep 4 13:16:18 2003 +++ 25-akpm/kernel/power/main.c Thu Sep 4 13:16:18 2003 @@ -73,15 +73,14 @@ static int suspend_prepare(u32 state) goto Finish; return 0; - Done: - pm_restore_console(); - return error; + Finish: if (pm_ops->finish) pm_ops->finish(state); Thaw: thaw_processes(); - goto Done; + pm_restore_console(); + return error; } @@ -94,9 +93,9 @@ static int suspend_enter(u32 state) if ((error = device_power_down(state))) goto Done; error = pm_ops->enter(state); - local_irq_restore(flags); device_power_up(); Done: + local_irq_restore(flags); return error; } diff -puN kernel/power/swsusp.c~swsusp-fpu-fix kernel/power/swsusp.c --- 25/kernel/power/swsusp.c~swsusp-fpu-fix Thu Sep 4 13:16:18 2003 +++ 25-akpm/kernel/power/swsusp.c Thu Sep 4 13:16:18 2003 @@ -416,11 +416,12 @@ static suspend_pagedir_t *create_suspend } -static int suspend_prepare_image(void) +int swsusp_suspend(void) { struct sysinfo i; unsigned int nr_needed_pages = 0; + read_swapfiles(); drain_local_pages(); pagedir_nosave = NULL; @@ -486,12 +487,10 @@ static int suspend_prepare_image(void) static int suspend_save_image(void) { int error; - local_irq_enable(); device_resume(); lock_swapdevices(); error = write_suspend_image(); lock_swapdevices(); - local_irq_disable(); return error; } @@ -515,35 +514,17 @@ int swsusp_resume(void) if (!resume) { save_processor_state(); SAVE_REGISTERS - swsusp_suspend(); - return; + return swsusp_suspend(); } GO_TO_SWAPPER_PAGE_TABLES COPY_PAGES_BACK RESTORE_REGISTERS restore_processor_state(); - swsusp_resume(); + return swsusp_resume(); */ -int swsusp_suspend(void) -{ - int error; - read_swapfiles(); - error = suspend_prepare_image(); - if (!error) - error = suspend_save_image(); - if (error) { - printk(KERN_EMERG "%sSuspend failed, trying to recover...\n", - name_suspend); - barrier(); - mb(); - mdelay(1000); - } - return error; -} - /* More restore stuff */ /* FIXME: Why not memcpy(to, from, 1<