diff -ruN 1924/fs/jbd/journal.c 1925/fs/jbd/journal.c --- 1924/fs/jbd/journal.c 2003-04-25 10:09:06.000000000 +1200 +++ 1925/fs/jbd/journal.c 2003-04-25 11:31:16.000000000 +1200 @@ -249,15 +249,15 @@ } wake_up(&journal->j_wait_done_commit); - if (current->flags & PF_FREEZE) { /* The simpler the better. Flushing journal isn't a - good idea, because that depends on threads that - may be already stopped. */ + interruptible_sleep_on(&journal->j_wait_commit); + + /* kjournald gets refrigerated before other kernel threads. freeze_processes + * will wait until it enters the fridge before freezing other threads */ + if (current->flags & PF_FREEZE) { jbd_debug(1, "Now suspending kjournald\n"); refrigerator(PF_IOTHREAD); jbd_debug(1, "Resuming kjournald\n"); - } else /* we assume on resume that commits are already there, - so we don't sleep */ - interruptible_sleep_on(&journal->j_wait_commit); + } jbd_debug(1, "kjournald wakes\n"); diff -ruN 1924/include/linux/suspend-debug.h 1925/include/linux/suspend-debug.h --- 1924/include/linux/suspend-debug.h 2003-04-25 10:09:06.000000000 +1200 +++ 1925/include/linux/suspend-debug.h 2003-04-25 12:05:09.000000000 +1200 @@ -6,7 +6,7 @@ #define name_suspend "Suspend Machine: " #define name_resume "Resume Machine: " -#define swsusp_version "beta 19-24" +#define swsusp_version "beta 19-25" #define name_swsusp "Swsusp " swsusp_version ": " #define console_suspend " S U S P E N D T O D I S K " /* Same length to ensure one overwrites the other */ #define console_resume "R E S U M E F R O M D I S K" @@ -30,12 +30,12 @@ #define SUSPEND_VERBOSE 0x4 #define SUSPEND_SLOW 0x8 #define SUSPEND_BEEP 0x10 +#define SUSPEND_MEMORY 0x20 /* fourth status register */ #define STAGE_FREEZER 0x1 #define STAGE_EAT_MEMORY 0x2 #define STAGE_MARK_PAGESET2 0x4 #define STAGE_WRITE_PAGESETS 0x8 -#define STAGE_FREE_PAGES 0x10 extern void printnolog(int restartline, const char *fmt, ...); diff -ruN 1924/include/linux/suspend.h 1925/include/linux/suspend.h --- 1924/include/linux/suspend.h 2003-04-25 10:09:06.000000000 +1200 +++ 1925/include/linux/suspend.h 2003-04-25 11:56:37.000000000 +1200 @@ -108,6 +108,7 @@ #define register_suspend_notifier(a) do { } while(0) #define unregister_suspend_notifier(a) do { } while(0) #define refrigerator(a) do { BUG(); } while(0) +#define TASK_SUSPENDED(p) (0) #endif #endif /* _LINUX_SWSUSP_H */ diff -ruN 1924/kernel/suspend.c 1925/kernel/suspend.c --- 1924/kernel/suspend.c 2003-04-25 10:09:06.000000000 +1200 +++ 1925/kernel/suspend.c 2003-04-25 12:32:34.000000000 +1200 @@ -239,28 +239,6 @@ static int abort_requested = 0; void printnolog(int restartline, const char *fmt, ...); // |= 0x2 is the flag that we are aborting the process. -#if 0 -#define abort_suspend(f, a...) do { \ - if (!SUSPEND_ABORTING) { \ - if (!abort_requested) { \ - int was_locked = (spin_is_locked(&suspend_pagedir_lock)); \ - if (was_locked) \ - spin_unlock_irq(&suspend_pagedir_lock); \ - printk("\n"); \ - printk(f, ## a); \ - beepERR; \ - printk("Waiting for you to press and release SHIFT before continuing.\n"); \ - while (!(shift_state & (1 << KG_SHIFT))) \ - schedule(); \ - while ((shift_state & (1 << KG_SHIFT))) \ - schedule(); \ - if (was_locked) \ - spin_lock_irq(&suspend_pagedir_lock); \ - } \ - swsusp_state[0] |= 0x2; \ - } \ -} while(0) -#endif void abort_suspend(const char *fmt, ...) { @@ -280,9 +258,9 @@ beepERR; printk("Waiting for you to press and release SHIFT before continuing.\n"); while (!(shift_state & (1 << KG_SHIFT))) - schedule(); + yield(); while ((shift_state & (1 << KG_SHIFT))) - schedule(); + yield(); if (was_locked) spin_lock_irq(&suspend_pagedir_lock); } @@ -314,13 +292,13 @@ try_to_free_buffers(bh->b_page, __GFP_FAST); \ free_suspend_cache_page(last_suspend_cache_page); -#define PRINTFREEMEM(desn) PRINTK(SUSPEND_VERBOSE, "Free memory %s: %d.\n", desn, nr_free_pages()) +#define PRINTFREEMEM(desn) PRINTK(SUSPEND_MEMORY, "Free memory %s: %d.\n", desn, nr_free_pages()) #define PANIC(f, a...) panic(f, ## a) static struct sysinfo swapinfo; static unsigned long copybuff = 0; -#define NUM_SYNC_WRITES 1 +#define NUM_SYNC_WRITES 4 struct io_info { union p_diskpage buffer; struct page * cache_page; @@ -664,7 +642,7 @@ PRINTNOLOG(SUSPEND_VERBOSE, 1, "Pausing %s.\n", SUSPEND_PAUSE ? "enabled" : "disabled"); while ((shift_state & (1 << KG_SHIFT))) - schedule(); + yield(); toggled = 1; } if (SUSPEND_PAUSE && (!toggled) && (pause)) { /* Don't pause if just toggled */ @@ -678,9 +656,9 @@ console_print(" ", 1); printk("Waiting for you to press and release SHIFT before continuing.\n"); while (!(shift_state & (1 << KG_SHIFT))) - schedule(); + yield(); while ((shift_state & (1 << KG_SHIFT))) - schedule(); + yield(); /* If pressing ALT, toggle ABORTING flag */ if ((!SUSPEND_ABORTING) && (!now_resuming)) { if ((shift_state & (1 << KG_ALT))) { @@ -720,21 +698,22 @@ suspended. We probably do not care). */ processesfrozen++; + PRINTNOLOG(SUSPEND_VERBOSE, 0, "%s frozen.\n", current->comm); if (flag) flush_signals(current); /* We have signaled a kernel thread, which isn't normal behaviour and that may lead to 100%CPU sucking because those threads just don't manage signals. */ current->flags |= PF_FROZEN; - schedule(); /* Won't return until suspend_task is set to 0 again */ - current->flags &= ~PF_FROZEN; current->flags &= ~PF_FREEZE; + while (current->flags & PF_FROZEN) + yield(); } /* 0 = success, else # of processes that we failed to stop */ static int freeze_processes(void) { - int todo, start_time; + int todo, start_time, journalthreadstodo, journalthreadsdone = 0; struct task_struct *p; processestofreeze = 0; @@ -743,15 +722,15 @@ PRINTNOLOG(SUSPEND_VERBOSE, 1, name_suspend "Stopping tasks\n" ); prepare_status("Freezing processes..."); - suspend_task = current->pid; - start_time = jiffies; do { todo = 0; + journalthreadstodo = 0; read_lock(&tasklist_lock); PRINTNOLOG(SUSPEND_VERBOSE, 1, ""); for_each_task(p) { unsigned long flags; + int isjournalthread = !strcmp(p->comm, "kjournald"); if (p->flags & PF_IOTHREAD) { continue; } @@ -761,18 +740,26 @@ if (p->flags & PF_FROZEN) { continue; } + todo++; + if (isjournalthread) + journalthreadstodo++; + if ((!journalthreadsdone) && (!isjournalthread)) + continue; /* FIXME: smp problem here: we may not access other process' flags without locking */ p->flags |= PF_FREEZE; - PRINTNOLOG(SUSPEND_VERBOSE, 0, "[%s]", p->comm); + PRINTNOLOG(SUSPEND_VERBOSE, 0, "Signalling %s.\n", p->comm); spin_lock_irqsave(&p->sigmask_lock, flags); signal_wake_up(p); spin_unlock_irqrestore(&p->sigmask_lock, flags); - todo++; + } + if ((!journalthreadsdone) && (!journalthreadstodo)) { + PRINTNOLOG(SUSPEND_VERBOSE, 0, "Journalling threads done.\n", p->comm); + journalthreadsdone = 1; } read_unlock(&tasklist_lock); if (processestofreeze == 0) { - PRINTNOLOG(SUSPEND_VERBOSE, 1, "%d processes to be frozen.\n", todo); + PRINTNOLOG(SUSPEND_VERBOSE, 0, "%d processes to be frozen.\n", todo); processestofreeze = todo; } yield(); @@ -793,11 +780,12 @@ } return todo; } - if (processestofreeze) // Don't update when enter fridge b/c requires process to acquire suspend console. + if (processestofreeze) update_status(processestofreeze - processesfrozen , processestofreeze, NULL); - //PRINTK(SUSPEND_VERBOSE, "----\n"); } while(processestofreeze > processesfrozen); + suspend_task = current->pid; + check_shift_keys(1); return 0; @@ -805,8 +793,12 @@ static void thaw_processes(void) { + struct task_struct *p; PRINTNOLOG(SUSPEND_VERBOSE, 1, name_resume "Restarting tasks\n"); suspend_task = 0; + for_each_task(p) { + p->flags &= ~PF_FROZEN; + } } /* @@ -1175,12 +1167,12 @@ /* Submit previous buffer for writing */ entry = swap_pbe->swap_address; - syncnow = ((!((thisswap + 1)%NUM_SYNC_WRITES)) || (ret == Z_STREAM_END)); + syncnow = (!((thisswap + 1)%NUM_SYNC_WRITES)); ret2 = start_rw_swap_page_nofree(WRITE, entry, cur[thisswap%NUM_SYNC_WRITES], syncnow); if (ret2) abort_and_exit("Failed writing page to swap. Error number was %d.\n", ret); if (syncnow) { - for (j=0; j < ((thisswap%NUM_SYNC_WRITES)+1); j++) + for (j=0; j < NUM_SYNC_WRITES; j++) finish_rw_swap_page_nofree(WRITE, cur[j]); } @@ -1215,15 +1207,14 @@ copy_page((char *) cur[i%NUM_SYNC_WRITES].buffer.address, virt); kunmap(pbe->address); - syncnow = ((!((i + 1)%NUM_SYNC_WRITES)) || ((i+1) == size)); + syncnow = (!((i + 1)%NUM_SYNC_WRITES)); ret = start_rw_swap_page_nofree(WRITE, entry, cur[i%NUM_SYNC_WRITES], syncnow); if (ret) abort_and_exit("Failed writing page to swap. Error number was %d.\n", ret); - if ((!((i + 1)%NUM_SYNC_WRITES)) || ((i + 1) == size)) { - for (j=0; j < ((i%NUM_SYNC_WRITES)+1); j++) { + if (!((i + 1)%NUM_SYNC_WRITES)) { + for (j=0; j < NUM_SYNC_WRITES; j++) finish_rw_swap_page_nofree(WRITE, cur[j]); - } } #endif check_shift_keys(0); @@ -1241,8 +1232,12 @@ PRINTK(SUSPEND_DEBUG, "|\n"); write_pageset_free_buffers: for (i = 0; i< NUM_SYNC_WRITES; i++) - if (cur[i].buffer.address) + if (cur[i].buffer.address) { + /* If page_count != 1, must have unflushed buffers */ + if (page_count(virt_to_page(cur[i].buffer.address)) != 1) + finish_rw_swap_page_nofree(WRITE, cur[i]); free_pages(cur[i].buffer.address, 0); + } drivers_suspend(); #ifdef CONFIG_SOFTWARE_SUSPEND_COMPRESSION @@ -1920,7 +1915,7 @@ #define RAM_TO_SUSPEND (pagedir1_size + 1 + pagedir2_size + 1 + MAX((pageset1_size - pageset2_sizelow), 0) + PAGES_FOR_IO) #define RAM_TO_RESUME ((pageset1_size + pagedir1_size + 1) * 2 + 8 + PAGES_FOR_IO + (long) max_mapnr - orig_mem_free) -static inline int amount_needed(void) +static int amount_needed(void) { return (MAX(MAX(MAX(RAM_TO_SUSPEND, RAM_TO_RESUME) - max_mapnr, SWAP_NEEDED - swapinfo.freeswap), @@ -2605,6 +2600,7 @@ PRINTK(SUSPEND_DEBUG, "-- AT START OF DO_MAGIC_SUSPEND_2 --\n"); PRINTK(SUSPEND_VERBOSE,"-- read_swapfiles()\n"); read_swapfiles(); + PRINTFREEMEM("after read_swapfiles()"); if (!save_image()) suspend_power_down (); @@ -2626,7 +2622,7 @@ static void do_software_suspend(void) { - unsigned long flags; + unsigned long flags = 0; int result; PRINTFREEMEM("at start of do_software_suspend"); @@ -2639,39 +2635,56 @@ abort_requested = 0; suspend_swap_bh = NULL; last_suspend_cache_page = NULL; + + /* Suspend console switch (if necessary) */ if (prepare_suspend_console()) printk(name_suspend "Can't allocate a console... proceeding\n"); + PRINTFREEMEM("after preparing suspend_console"); beepOK; /* first beep */ - /* Order is significant. - * We set up the nosavemap first so all maps are recorded as nosave. - */ - PRINTK(SUSPEND_DEBUG, "Allocating nosavemap\n"); + + /* Allocate bitmaps for suspend page flags */ + PRINTK(SUSPEND_DEBUG, "Allocating inusemap\n"); if (allocatemap(&inusemap)) return; + PRINTFREEMEM("after allocating inusemap"); if (allocatemap(&pageset2map)) { freemap(&inusemap); return; } - - PRINTFREEMEM("after allocating bitmaps"); - // Tasks allowed to run while eating memory. + PRINTFREEMEM("after allocating pageset2 map"); + + /* Free up memory if necessary */ PRINTK(SUSPEND_VERBOSE, "Eating memory.\n"); eat_memory(); if (SUSPEND_ABORTING) goto out; PRINTFREEMEM("after eating memory"); - prepare_status("Getting io_request lock..."); - spin_lock_irqsave(&io_request_lock, flags); + + /* Sync data */ prepare_status("Syncing data..."); PRINTK(SUSPEND_VERBOSE, "Calling sys_sync.\n"); sys_sync(); + yield(); + PRINTFREEMEM("after calling sys_sync"); + + /* Stop I/O */ + prepare_status("Getting io_request lock..."); + spin_lock_irqsave(&io_request_lock, flags); + PRINTFREEMEM("spin_lock io_request_lock"); + + /* Freeze processes */ #ifdef CONFIG_SOFTWARE_SUSPEND_DEBUG currentstage = STAGE_FREEZER; #endif prepare_status("Calling prepare_suspend_processes..."); result = prepare_suspend_processes(); + + /* Restart I/O */ + PRINTFREEMEM("after suspending processes"); spin_unlock_irqrestore(&io_request_lock, flags); + + /* Check all processes stopped */ if (result) { prepare_status("Failed to freeze all processes!"); PRINTK(SUSPEND_VERBOSE, "Failed to freeze all processes.\n"); @@ -2679,7 +2692,10 @@ if (result || SUSPEND_ABORTING) { goto out; } + + /* Release memory that has been eaten */ free_grabbed_memory(); + beepOK; /* second beep */ if (!SUSPEND_ABORTING) { @@ -2691,6 +2707,7 @@ PRINTK(SUSPEND_VERBOSE, name_suspend "Syncing disks before copy\n" ); prepare_status("Syncing disks..."); do_suspend_sync(); + PRINTFREEMEM("after syncing disks"); if (drivers_suspend()==0) { prepare_status("Starting low level suspend..."); do_suspend_lowlevel(0); @@ -2702,9 +2719,15 @@ display_debug_info(); out: + PRINTFREEMEM("at 'out'"); free_grabbed_memory(); - freemap(&inusemap); - freemap(&pageset2map); + PRINTFREEMEM("after freeing grabbed memory"); + if (pageset2map) + freemap(&pageset2map); + PRINTFREEMEM("after freeing pageset2 map"); + if (inusemap) + freemap(&inusemap); + PRINTFREEMEM("after freeing inuse map"); thaw_processes(); MDELAY(1000); @@ -2745,7 +2768,7 @@ { swsusp_state[0] = 1; while(SUSPEND_PENDING) { - schedule(); + yield(); if (suspend_task) refrigerator(PF_REFRIGERATE); } @@ -2907,13 +2930,13 @@ printk(KERN_ERR "BIG FAT WARNING: if you continue booting with this kernel, be sure to mkswap your swap partition. Otherwise, you may severely damage your filesystem on next reboot with the kernel that wrote the resume image."); printk(KERN_ERR "Press SHIFT to reboot or CONTROL to continue booting with this kernel\n"); while (!(shift_state & ((1 << KG_SHIFT) | (1 << KG_CTRL)))) - schedule(); + yield(); if (shift_state & (1 << KG_SHIFT)) machine_restart(NULL); printk(KERN_ERR "ARE YOU SURE: Unless you really know what you're doing just reboot on the correct kernel or use the noresume boot option."); printk(KERN_ERR "Press SHIFT to reboot or CONTROL to continue booting with this kernel\n"); while (!(shift_state & ((1 << KG_SHIFT) | (1 << KG_CTRL)))) - schedule(); + yield(); if (shift_state & (1 << KG_SHIFT)) machine_restart(NULL); return -EPERM; diff -ruN 1924/mm/page_alloc.c 1925/mm/page_alloc.c --- 1924/mm/page_alloc.c 2003-04-25 10:09:06.000000000 +1200 +++ 1925/mm/page_alloc.c 2003-04-25 12:06:07.000000000 +1200 @@ -100,7 +100,7 @@ if (page->buffers) BUG(); if (page->mapping) { - printk("pagebug: %lx\n",page); + printk("pagebug: %p\n",page); BUG(); } if (!VALID_PAGE(page))