diff options
Diffstat (limited to 'kernel/power/swsusp.c')
-rw-r--r-- | kernel/power/swsusp.c | 131 |
1 files changed, 53 insertions, 78 deletions
diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c index 90b3b68dee3..f2bc71b9fe8 100644 --- a/kernel/power/swsusp.c +++ b/kernel/power/swsusp.c @@ -10,12 +10,12 @@ * This file is released under the GPLv2. * * I'd like to thank the following people for their work: - * + * * Pavel Machek <pavel@ucw.cz>: * Modifications, defectiveness pointing, being with me at the very beginning, * suspend to swap space, stop all tasks. Port to 2.4.18-ac and 2.5.17. * - * Steve Doddi <dirk@loth.demon.co.uk>: + * Steve Doddi <dirk@loth.demon.co.uk>: * Support the possibility of hardware state restoring. * * Raph <grey.havens@earthling.net>: @@ -63,6 +63,7 @@ #include <linux/console.h> #include <linux/highmem.h> #include <linux/bio.h> +#include <linux/mount.h> #include <asm/uaccess.h> #include <asm/mmu_context.h> @@ -81,14 +82,14 @@ static int nr_copy_pages_check; extern char resume_file[]; /* Local variables that should not be affected by save */ -unsigned int nr_copy_pages __nosavedata = 0; +static unsigned int nr_copy_pages __nosavedata = 0; /* Suspend pagedir is allocated before final copy, therefore it - must be freed after resume + must be freed after resume Warning: this is evil. There are actually two pagedirs at time of resume. One is "pagedir_save", which is empty frame allocated at - time of suspend, that must be freed. Second is "pagedir_nosave", + time of suspend, that must be freed. Second is "pagedir_nosave", allocated at time of resume, that travels through memory not to collide with anything. @@ -132,7 +133,7 @@ static int mark_swapfiles(swp_entry_t prev) { int error; - rw_swap_page_sync(READ, + rw_swap_page_sync(READ, swp_entry(root_swap, 0), virt_to_page((unsigned long)&swsusp_header)); if (!memcmp("SWAP-SPACE",swsusp_header.sig, 10) || @@ -140,7 +141,7 @@ static int mark_swapfiles(swp_entry_t prev) memcpy(swsusp_header.orig_sig,swsusp_header.sig, 10); memcpy(swsusp_header.sig,SWSUSP_SIG, 10); swsusp_header.swsusp_info = prev; - error = rw_swap_page_sync(WRITE, + error = rw_swap_page_sync(WRITE, swp_entry(root_swap, 0), virt_to_page((unsigned long) &swsusp_header)); @@ -174,22 +175,22 @@ static int is_resume_device(const struct swap_info_struct *swap_info) static int swsusp_swap_check(void) /* This is called before saving image */ { int i, len; - + len=strlen(resume_file); root_swap = 0xFFFF; - + swap_list_lock(); - for(i=0; i<MAX_SWAPFILES; i++) { + for (i=0; i<MAX_SWAPFILES; i++) { if (swap_info[i].flags == 0) { swapfile_used[i]=SWAPFILE_UNUSED; } else { - if(!len) { + if (!len) { printk(KERN_WARNING "resume= option should be used to set suspend device" ); - if(root_swap == 0xFFFF) { + if (root_swap == 0xFFFF) { swapfile_used[i] = SWAPFILE_SUSPEND; root_swap = i; } else - swapfile_used[i] = SWAPFILE_IGNORED; + swapfile_used[i] = SWAPFILE_IGNORED; } else { /* we ignore all swap devices that are not the resume_file */ if (is_resume_device(&swap_info[i])) { @@ -209,15 +210,15 @@ static int swsusp_swap_check(void) /* This is called before saving image */ * This is called after saving image so modification * will be lost after resume... and that's what we want. * we make the device unusable. A new call to - * lock_swapdevices can unlock the devices. + * lock_swapdevices can unlock the devices. */ static void lock_swapdevices(void) { int i; swap_list_lock(); - for(i = 0; i< MAX_SWAPFILES; i++) - if(swapfile_used[i] == SWAPFILE_IGNORED) { + for (i = 0; i< MAX_SWAPFILES; i++) + if (swapfile_used[i] == SWAPFILE_IGNORED) { swap_info[i].flags ^= 0xFF; } swap_list_unlock(); @@ -229,7 +230,7 @@ static void lock_swapdevices(void) * @loc: Place to store the entry we used. * * Allocate a new swap entry and 'sync' it. Note we discard -EIO - * errors. That is an artifact left over from swsusp. It did not + * errors. That is an artifact left over from swsusp. It did not * check the return of rw_swap_page_sync() at all, since most pages * written back to swap would return -EIO. * This is a partial improvement, since we will at least return other @@ -241,7 +242,7 @@ static int write_page(unsigned long addr, swp_entry_t * loc) int error = 0; entry = get_swap_page(); - if (swp_offset(entry) && + if (swp_offset(entry) && swapfile_used[swp_type(entry)] == SWAPFILE_SUSPEND) { error = rw_swap_page_sync(WRITE, entry, virt_to_page(addr)); @@ -257,7 +258,7 @@ static int write_page(unsigned long addr, swp_entry_t * loc) /** * data_free - Free the swap entries used by the saved image. * - * Walk the list of used swap entries and free each one. + * Walk the list of used swap entries and free each one. * This is only used for cleanup when suspend fails. */ static void data_free(void) @@ -290,7 +291,7 @@ static int data_write(void) mod = 1; printk( "Writing data to swap (%d pages)... ", nr_copy_pages ); - for_each_pbe(p, pagedir_nosave) { + for_each_pbe (p, pagedir_nosave) { if (!(i%mod)) printk( "\b\b\b\b%3d%%", i / mod ); if ((error = write_page(p->address, &(p->swap_address)))) @@ -335,7 +336,7 @@ static int close_swap(void) dump_info(); error = write_page((unsigned long)&swsusp_info, &entry); - if (!error) { + if (!error) { printk( "S" ); error = mark_swapfiles(entry); printk( "|\n" ); @@ -370,7 +371,7 @@ static int write_pagedir(void) struct pbe * pbe; printk( "Writing pagedir..."); - for_each_pb_page(pbe, pagedir_nosave) { + for_each_pb_page (pbe, pagedir_nosave) { if ((error = write_page((unsigned long)pbe, &swsusp_info.pagedir[n++]))) return error; } @@ -472,7 +473,7 @@ static int save_highmem(void) int res = 0; pr_debug("swsusp: Saving Highmem\n"); - for_each_zone(zone) { + for_each_zone (zone) { if (is_highmem(zone)) res = save_highmem_zone(zone); if (res) @@ -547,7 +548,7 @@ static void count_data_pages(void) nr_copy_pages = 0; - for_each_zone(zone) { + for_each_zone (zone) { if (is_highmem(zone)) continue; mark_free_pages(zone); @@ -562,9 +563,9 @@ static void copy_data_pages(void) struct zone *zone; unsigned long zone_pfn; struct pbe * pbe = pagedir_nosave; - + pr_debug("copy_data_pages(): pages to copy: %d\n", nr_copy_pages); - for_each_zone(zone) { + for_each_zone (zone) { if (is_highmem(zone)) continue; mark_free_pages(zone); @@ -702,7 +703,7 @@ static void free_image_pages(void) { struct pbe * p; - for_each_pbe(p, pagedir_save) { + for_each_pbe (p, pagedir_save) { if (p->address) { ClearPageNosave(virt_to_page(p->address)); free_page(p->address); @@ -719,7 +720,7 @@ static int alloc_image_pages(void) { struct pbe * p; - for_each_pbe(p, pagedir_save) { + for_each_pbe (p, pagedir_save) { p->address = get_zeroed_page(GFP_ATOMIC | __GFP_COLD); if (!p->address) return -ENOMEM; @@ -740,7 +741,7 @@ void swsusp_free(void) /** * enough_free_mem - Make sure we enough free memory to snapshot. * - * Returns TRUE or FALSE after checking the number of available + * Returns TRUE or FALSE after checking the number of available * free pages. */ @@ -758,11 +759,11 @@ static int enough_free_mem(void) /** * enough_swap - Make sure we have enough swap to save the image. * - * Returns TRUE or FALSE after checking the total amount of swap + * Returns TRUE or FALSE after checking the total amount of swap * space avaiable. * * FIXME: si_swapinfo(&i) returns all swap devices information. - * We should only consider resume_device. + * We should only consider resume_device. */ static int enough_swap(void) @@ -781,18 +782,18 @@ static int swsusp_alloc(void) { int error; + pagedir_nosave = NULL; + nr_copy_pages = calc_nr(nr_copy_pages); + pr_debug("suspend: (pages needed: %d + %d free: %d)\n", nr_copy_pages, PAGES_FOR_IO, nr_free_pages()); - pagedir_nosave = NULL; if (!enough_free_mem()) return -ENOMEM; if (!enough_swap()) return -ENOSPC; - nr_copy_pages = calc_nr(nr_copy_pages); - if (!(pagedir_save = alloc_pagedir(nr_copy_pages))) { printk(KERN_ERR "suspend: Allocating pagedir failed.\n"); return -ENOMEM; @@ -827,8 +828,8 @@ static int suspend_prepare_image(void) error = swsusp_alloc(); if (error) return error; - - /* During allocating of suspend pagedir, new cold pages may appear. + + /* During allocating of suspend pagedir, new cold pages may appear. * Kill them. */ drain_local_pages(); @@ -869,13 +870,6 @@ extern asmlinkage int swsusp_arch_resume(void); asmlinkage int swsusp_save(void) { - int error = 0; - - if ((error = swsusp_swap_check())) { - printk(KERN_ERR "swsusp: FATAL: cannot find swap device, try " - "swapon -a!\n"); - return error; - } return suspend_prepare_image(); } @@ -892,14 +886,20 @@ int swsusp_suspend(void) * at resume time, and evil weirdness ensues. */ if ((error = device_power_down(PMSG_FREEZE))) { - printk(KERN_ERR "Some devices failed to power down, aborting suspend\n"); local_irq_enable(); - swsusp_free(); return error; } + + if ((error = swsusp_swap_check())) { + printk(KERN_ERR "swsusp: FATAL: cannot find swap device, try " + "swapon -a!\n"); + local_irq_enable(); + return error; + } + save_processor_state(); if ((error = swsusp_arch_suspend())) - swsusp_free(); + printk("Error %d suspending\n", error); /* Restore control flow magically appears here */ restore_processor_state(); BUG_ON (nr_copy_pages_check != nr_copy_pages); @@ -929,21 +929,6 @@ int swsusp_resume(void) return error; } -/* More restore stuff */ - -/* - * Returns true if given address/order collides with any orig_address - */ -static int does_collide_order(unsigned long addr, int order) -{ - int i; - - for (i=0; i < (1<<order); i++) - if (!PageNosaveFree(virt_to_page(addr + i * PAGE_SIZE))) - return 1; - return 0; -} - /** * On resume, for storing the PBE list and the image, * we can only use memory pages that do not conflict with the pages @@ -973,7 +958,7 @@ static unsigned long get_usable_page(unsigned gfp_mask) unsigned long m; m = get_zeroed_page(gfp_mask); - while (does_collide_order(m, 0)) { + while (!PageNosaveFree(virt_to_page(m))) { eat_page((void *)m); m = get_zeroed_page(gfp_mask); if (!m) @@ -1045,7 +1030,7 @@ static struct pbe * swsusp_pagedir_relocate(struct pbe *pblist) /* Set page flags */ - for_each_zone(zone) { + for_each_zone (zone) { for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) SetPageNosaveFree(pfn_to_page(zone_pfn + zone->zone_start_pfn)); @@ -1061,7 +1046,7 @@ static struct pbe * swsusp_pagedir_relocate(struct pbe *pblist) /* Relocate colliding pages */ for_each_pb_page (pbpage, pblist) { - if (does_collide_order((unsigned long)pbpage, 0)) { + if (!PageNosaveFree(virt_to_page((unsigned long)pbpage))) { m = (void *)get_usable_page(GFP_ATOMIC | __GFP_COLD); if (!m) { error = -ENOMEM; @@ -1181,9 +1166,9 @@ static int bio_write_page(pgoff_t page_off, void * page) static const char * sanity_check(void) { dump_info(); - if(swsusp_info.version_code != LINUX_VERSION_CODE) + if (swsusp_info.version_code != LINUX_VERSION_CODE) return "kernel version"; - if(swsusp_info.num_physpages != num_physpages) + if (swsusp_info.num_physpages != num_physpages) return "memory size"; if (strcmp(swsusp_info.uts.sysname,system_utsname.sysname)) return "system type"; @@ -1193,8 +1178,10 @@ static const char * sanity_check(void) return "version"; if (strcmp(swsusp_info.uts.machine,system_utsname.machine)) return "machine"; +#if 0 if(swsusp_info.cpus != num_online_cpus()) return "number of cpus"; +#endif return NULL; } @@ -1274,8 +1261,6 @@ static int data_read(struct pbe *pblist) return error; } -extern dev_t name_to_dev_t(const char *line); - /** * read_pagedir - Read page backup list pages from swap */ @@ -1369,16 +1354,6 @@ int swsusp_check(void) { int error; - if (!swsusp_resume_device) { - if (!strlen(resume_file)) - return -ENOENT; - swsusp_resume_device = name_to_dev_t(resume_file); - pr_debug("swsusp: Resume From Partition %s\n", resume_file); - } else { - pr_debug("swsusp: Resume From Partition %d:%d\n", - MAJOR(swsusp_resume_device), MINOR(swsusp_resume_device)); - } - resume_bdev = open_by_devnum(swsusp_resume_device, FMODE_READ); if (!IS_ERR(resume_bdev)) { set_blocksize(resume_bdev, PAGE_SIZE); |