summaryrefslogtreecommitdiff
path: root/kernel/suspend.c
diff options
context:
space:
mode:
authorPavel Machek <pavel@ucw.cz>2002-07-14 04:08:19 -0700
committerLinus Torvalds <torvalds@home.transmeta.com>2002-07-14 04:08:19 -0700
commitea7d406d353ae3a7bae320d4978fde8ac4e2d569 (patch)
tree747128e262e8c7a86e311a81392d99e8f67ad50f /kernel/suspend.c
parente80e317bb5914a425bb99317eb29aba352852458 (diff)
[PATCH] suspend-to-disk: cleanup printks(), rearrange reading
I'd like Florent credited -- he is maintaining 2.4.X version and helping with development. Kill warnings by rearranging code / adding prototypes. Enable using separate console (so user sees progress and X suspend/resume works properly), forward-port of updates from Florent and stop using own PRINTK stuff (mostly). Reading now primarily uses block_device(), this should enable more cleanups. Fixed double free on error path.
Diffstat (limited to 'kernel/suspend.c')
-rw-r--r--kernel/suspend.c347
1 files changed, 173 insertions, 174 deletions
diff --git a/kernel/suspend.c b/kernel/suspend.c
index f4f389c566b4..926717ef0256 100644
--- a/kernel/suspend.c
+++ b/kernel/suspend.c
@@ -69,7 +69,7 @@ extern void signal_wake_up(struct task_struct *t);
unsigned char software_suspend_enabled = 0;
-/* #define SUSPEND_CONSOLE (MAX_NR_CONSOLES-1) */
+#define SUSPEND_CONSOLE (MAX_NR_CONSOLES-1)
/* With SUSPEND_CONSOLE defined, it suspend looks *really* cool, but
we probably do not take enough locks for switching consoles, etc,
so bad things might happen.
@@ -97,7 +97,7 @@ spinlock_t suspend_pagedir_lock __nosavedata = SPIN_LOCK_UNLOCKED;
/* Variables to be preserved over suspend */
static int new_loglevel = 7;
static int orig_loglevel = 0;
-static int orig_fgconsole;
+static int orig_fgconsole, orig_kmsg;
static int pagedir_order_check;
static int nr_copy_pages_check;
@@ -139,32 +139,23 @@ union diskpage {
*/
#define PAGES_FOR_IO 512
-static const char *name_suspend = "Suspend Machine: ";
-static const char *name_resume = "Resume Machine: ";
+static const char name_suspend[] = "Suspend Machine: ";
+static const char name_resume[] = "Resume Machine: ";
/*
* Debug
*/
-#define DEBUG_DEFAULT 1
+#undef DEBUG_DEFAULT
#undef DEBUG_PROCESS
#undef DEBUG_SLOW
#define TEST_SWSUSP 1 /* Set to 1 to reboot instead of halt machine after suspension */
#ifdef DEBUG_DEFAULT
-#define PRINTD(func, f, a...) \
- do { \
- printk("%s", func); \
- printk(f, ## a); \
- } while(0)
-#define PRINTS(f, a...) PRINTD(name_suspend, f, ## a)
-#define PRINTR(f, a...) PRINTD(name_resume, f, ## a)
-#define PRINTK(f, a...) printk(f, ## a)
+# define PRINTK(f, a...) printk(f, ## a)
#else
-#define PRINTD(func, f, a...)
-#define PRINTS(f, a...)
-#define PRINTR(f, a...)
-#define PRINTK(f, a...)
+# define PRINTK(f, a...)
#endif
+
#ifdef DEBUG_SLOW
#define MDELAY(a) mdelay(a)
#else
@@ -195,8 +186,8 @@ void refrigerator(unsigned long flag)
long save;
save = current->state;
current->state = TASK_STOPPED;
-// PRINTK("%s entered refrigerator\n", current->comm);
- printk(":");
+ PRINTK("%s entered refrigerator\n", current->comm);
+ printk("=");
current->flags &= ~PF_FREEZE;
if (flag)
flush_signals(current); /* We have signaled a kernel thread, which isn't normal behaviour
@@ -205,8 +196,7 @@ void refrigerator(unsigned long flag)
current->flags |= PF_FROZEN;
while (current->flags & PF_FROZEN)
schedule();
-// PRINTK("%s left refrigerator\n", current->comm);
- printk(":");
+ PRINTK("%s left refrigerator\n", current->comm);
current->state = save;
}
@@ -216,8 +206,7 @@ int freeze_processes(void)
int todo, start_time;
struct task_struct *p;
- PRINTS( "Waiting for tasks to stop... " );
-
+ printk( "Stopping tasks: " );
start_time = jiffies;
do {
todo = 0;
@@ -239,13 +228,13 @@ int freeze_processes(void)
read_unlock(&tasklist_lock);
yield();
if (time_after(jiffies, start_time + TIMEOUT)) {
- PRINTK( "\n" );
+ printk( "\n" );
printk(KERN_ERR " stopping tasks failed (%d tasks remaining)\n", todo );
return todo;
}
} while(todo);
- PRINTK( " ok\n" );
+ printk( "|\n" );
return 0;
}
@@ -253,7 +242,7 @@ void thaw_processes(void)
{
struct task_struct *p;
- PRINTR( "Restarting tasks..." );
+ printk( "Restarting tasks..." );
read_lock(&tasklist_lock);
for_each_task(p) {
INTERESTING(p);
@@ -264,7 +253,7 @@ void thaw_processes(void)
wake_up_process(p);
}
read_unlock(&tasklist_lock);
- PRINTK( " done\n" );
+ printk( " done\n" );
MDELAY(500);
}
@@ -284,8 +273,7 @@ static __inline__ int fill_suspend_header(struct suspend_header *sh)
sh->num_cpus = num_online_cpus();
sh->page_size = PAGE_SIZE;
sh->suspend_pagedir = pagedir_nosave;
- if (pagedir_save != pagedir_nosave)
- panic("Must not happen");
+ BUG_ON (pagedir_save != pagedir_nosave);
sh->num_pbes = nr_copy_pages;
/* TODO: needed? mounted fs' last mounted date comparison
* [so they haven't been mounted since last suspend.
@@ -376,7 +364,7 @@ static void read_swapfiles(void) /* This is called before saving image */
root_swap = i;
} else {
#if 0
- PRINTS( "device %s (%x != %x) ignored\n", swap_info[i].swap_file->d_name.name, swap_info[i].swap_device, resume_device );
+ printk( "Resume: device %s (%x != %x) ignored\n", swap_info[i].swap_file->d_name.name, swap_info[i].swap_device, resume_device );
#endif
swapfile_used[i] = SWAPFILE_IGNORED;
}
@@ -409,14 +397,14 @@ static int write_suspend_image(void)
unsigned long address;
struct page *page;
- PRINTS( "Writing data to swap (%d pages): ", nr_copy_pages );
+ printk( "Writing data to swap (%d pages): ", nr_copy_pages );
for (i=0; i<nr_copy_pages; i++) {
if (!(i%100))
- PRINTK( "." );
+ printk( "." );
if (!(entry = get_swap_page()).val)
panic("\nNot enough swapspace when writing data" );
- if(swapfile_used[swp_type(entry)] != SWAPFILE_SUSPEND)
+ if (swapfile_used[swp_type(entry)] != SWAPFILE_SUSPEND)
panic("\nPage %d: not enough swapspace on suspend device", i );
address = (pagedir_nosave+i)->address;
@@ -424,13 +412,12 @@ static int write_suspend_image(void)
rw_swap_page_sync(WRITE, entry, page);
(pagedir_nosave+i)->swap_address = entry;
}
- PRINTK(" done\n");
- PRINTS( "Writing pagedir (%d pages): ", nr_pgdir_pages);
+ printk( "|\n" );
+ printk( "Writing pagedir (%d pages): ", nr_pgdir_pages);
for (i=0; i<nr_pgdir_pages; i++) {
cur = (union diskpage *)((char *) pagedir_nosave)+i;
- if ((char *) cur != (((char *) pagedir_nosave) + i*PAGE_SIZE))
- panic("Something is of wrong size");
- PRINTK( "." );
+ BUG_ON ((char *) cur != (((char *) pagedir_nosave) + i*PAGE_SIZE));
+ printk( "." );
if (!(entry = get_swap_page()).val) {
printk(KERN_CRIT "Not enough swapspace when writing pgdir\n" );
panic("Don't know how to recover");
@@ -439,30 +426,26 @@ static int write_suspend_image(void)
}
if(swapfile_used[swp_type(entry)] != SWAPFILE_SUSPEND)
- panic("\nNot enough swapspace for pagedir on suspend device" );
+ panic("\nNot enough swapspace for pagedir on suspend device" );
+
+ BUG_ON (sizeof(swp_entry_t) != sizeof(long));
+ BUG_ON (PAGE_SIZE % sizeof(struct pbe));
- if (sizeof(swp_entry_t) != sizeof(long))
- panic("I need swp_entry_t to be sizeof long, otherwise next assignment could damage pagedir");
- if (PAGE_SIZE % sizeof(struct pbe))
- panic("I need PAGE_SIZE to be integer multiple of struct pbe, otherwise next assignment could damage pagedir");
cur->link.next = prev;
page = virt_to_page((unsigned long)cur);
rw_swap_page_sync(WRITE, entry, page);
prev = entry;
}
- PRINTK(", header");
- if (sizeof(struct suspend_header) > PAGE_SIZE-sizeof(swp_entry_t))
- panic("sizeof(struct suspend_header) too big: %d",
- sizeof(struct suspend_header));
- if (sizeof(union diskpage) != PAGE_SIZE)
- panic("union diskpage has bad size");
+ printk("H");
+ BUG_ON (sizeof(struct suspend_header) > PAGE_SIZE-sizeof(swp_entry_t));
+ BUG_ON (sizeof(union diskpage) != PAGE_SIZE);
if (!(entry = get_swap_page()).val)
panic( "\nNot enough swapspace when writing header" );
- if(swapfile_used[swp_type(entry)] != SWAPFILE_SUSPEND)
- panic("\nNot enough swapspace for header on suspend device" );
+ if (swapfile_used[swp_type(entry)] != SWAPFILE_SUSPEND)
+ panic("\nNot enough swapspace for header on suspend device" );
cur = (void *) buffer;
- if(fill_suspend_header(&cur->sh))
+ if (fill_suspend_header(&cur->sh))
panic("\nOut of memory while writing header");
cur->link.next = prev;
@@ -471,13 +454,9 @@ static int write_suspend_image(void)
rw_swap_page_sync(WRITE, entry, page);
prev = entry;
- PRINTK( ", signature" );
-#if 0
- if (swp_type(entry) != 0)
- panic("Need just one swapfile");
-#endif
+ printk( "S" );
mark_swapfiles(prev, MARK_SWAP_SUSPEND);
- PRINTK( ", done\n" );
+ printk( "|\n" );
MDELAY(1000);
free_page((unsigned long) buffer);
@@ -493,20 +472,19 @@ static int count_and_copy_data_pages(struct pbe *pagedir_p)
if (max_mapnr != num_physpages)
panic("mapnr is not expected");
- for(loop = 0; loop < max_mapnr; loop++) {
- if(PageHighMem(mem_map+loop))
- panic("No highmem for me, sorry.");
- if(!PageReserved(mem_map+loop)) {
- if(PageNosave(mem_map+loop))
+ for (loop = 0; loop < max_mapnr; loop++) {
+ if (PageHighMem(mem_map+loop))
+ panic("Swsusp not supported on highmem boxes. Send 1GB of RAM to <pavel@ucw.cz> and try again ;-).");
+ if (!PageReserved(mem_map+loop)) {
+ if (PageNosave(mem_map+loop))
continue;
- if((chunk_size=is_head_of_free_region(mem_map+loop))!=0) {
+ if ((chunk_size=is_head_of_free_region(mem_map+loop))!=0) {
loop += chunk_size - 1;
continue;
}
- } else if(PageReserved(mem_map+loop)) {
- if(PageNosave(mem_map+loop))
- panic("What?");
+ } else if (PageReserved(mem_map+loop)) {
+ BUG_ON (PageNosave(mem_map+loop));
/*
* Just copy whole code segment. Hopefully it is not that big.
@@ -514,15 +492,15 @@ static int count_and_copy_data_pages(struct pbe *pagedir_p)
if (ADDRESS(loop) >= (unsigned long)
&__nosave_begin && ADDRESS(loop) <
(unsigned long)&__nosave_end) {
- printk("[nosave]");
+ PRINTK("[nosave %x]", ADDRESS(loop));
continue;
}
/* Hmm, perhaps copying all reserved pages is not too healthy as they may contain
critical bios data? */
- } else panic("No third thing should be possible");
+ } else BUG();
nr_copy_pages++;
- if(pagedir_p) {
+ if (pagedir_p) {
pagedir_p->orig_address = ADDRESS(loop);
copy_page(pagedir_p->address, pagedir_p->orig_address);
pagedir_p++;
@@ -539,10 +517,10 @@ static void free_suspend_pagedir(unsigned long this_pagedir)
(PAGE_SIZE << pagedir_order);
for(i=0; i < num_physpages; i++, page++) {
- if(!TestClearPageNosave(page))
+ if (!TestClearPageNosave(page))
continue;
- if(ADDRESS(i) >= this_pagedir && ADDRESS(i) < this_pagedir_end)
+ if (ADDRESS(i) >= this_pagedir && ADDRESS(i) < this_pagedir_end)
continue; /* old pagedir gets freed in one */
free_page(ADDRESS(i));
@@ -570,7 +548,6 @@ static suspend_pagedir_t *create_suspend_pagedir(int nr_copy_pages)
while(nr_copy_pages--) {
p->address = get_free_page(GFP_ATOMIC);
if(!p->address) {
- panic("oom");
free_suspend_pagedir((unsigned long) pagedir);
return NULL;
}
@@ -596,9 +573,11 @@ static int prepare_suspend_console(void)
set_console (SUSPEND_CONSOLE);
if(vt_waitactive(SUSPEND_CONSOLE)) {
- PRINTS("Bummer. Can't switch VCs.");
+ PRINTK("Bummer. Can't switch VCs.");
return 1;
}
+ orig_kmsg = kmsg_redirect;
+ kmsg_redirect = SUSPEND_CONSOLE;
#endif
#endif
return 0;
@@ -615,14 +594,12 @@ static void restore_console(void)
static int prepare_suspend_processes(void)
{
- PRINTS( "Stopping processes\n" );
- MDELAY(1000);
if (freeze_processes()) {
- PRINTS( "Not all processes stopped!\n" );
+ printk( KERN_ERR "Suspend failed: Not all processes stopped!\n" );
thaw_processes();
return 1;
}
- do_suspend_sync();
+ sys_sync();
return 0;
}
@@ -633,10 +610,10 @@ static int prepare_suspend_processes(void)
*/
static void free_some_memory(void)
{
- PRINTS("Freeing memory: ");
+ printk("Freeing memory: ");
while (try_to_free_pages(&contig_page_data.node_zones[ZONE_HIGHMEM], GFP_KSWAPD, 0))
printk(".");
- printk("\n");
+ printk("|\n");
}
/* Make disk drivers accept operations, again */
@@ -669,9 +646,11 @@ static int drivers_suspend(void)
#define RESUME_ALL_PHASES (RESUME_PHASE1 | RESUME_PHASE2)
static void drivers_resume(int flags)
{
- device_resume(RESUME_ENABLE);
- device_resume(RESUME_RESTORE_STATE);
- if(flags & RESUME_PHASE2) {
+ if (flags & RESUME_PHASE1) {
+ device_resume(RESUME_ENABLE);
+ device_resume(RESUME_RESTORE_STATE);
+ }
+ if (flags & RESUME_PHASE2) {
if(pm_suspend_state) {
if(pm_send_all(PM_RESUME,(void *)0))
printk(KERN_WARNING "Problem while sending resume event\n");
@@ -691,11 +670,11 @@ static int suspend_save_image(void)
unsigned int nr_needed_pages = 0;
pagedir_nosave = NULL;
- PRINTS( "/critical section: Counting pages to copy" );
+ printk( "/critical section: Counting pages to copy" );
nr_copy_pages = count_and_copy_data_pages(NULL);
nr_needed_pages = nr_copy_pages + PAGES_FOR_IO;
- PRINTK(" (pages needed: %d+%d=%d free: %d)\n",nr_copy_pages,PAGES_FOR_IO,nr_needed_pages,nr_free_pages());
+ printk(" (pages needed: %d+%d=%d free: %d)\n",nr_copy_pages,PAGES_FOR_IO,nr_needed_pages,nr_free_pages());
if(nr_free_pages() < nr_needed_pages) {
printk(KERN_CRIT "%sCouldn't get enough free pages, on %d pages short\n",
name_suspend, nr_needed_pages-nr_free_pages());
@@ -724,7 +703,7 @@ static int suspend_save_image(void)
pagedir_order_check = pagedir_order;
if (nr_copy_pages != count_and_copy_data_pages(pagedir_nosave)) /* copy */
- panic("Count and copy returned another count than when counting?\n");
+ BUG();
/*
* End of critical section. From now on, we can write to memory,
@@ -735,14 +714,12 @@ static int suspend_save_image(void)
*/
drivers_unsuspend();
spin_unlock_irq(&suspend_pagedir_lock);
- PRINTS( "critical section/: done (%d pages copied)\n", nr_copy_pages );
+ printk( "critical section/: done (%d pages copied)\n", nr_copy_pages );
lock_swapdevices();
write_suspend_image();
lock_swapdevices(); /* This will unlock ignored swap devices since writing is finished */
- /* Image is saved, call sync & restart machine */
- PRINTS( "Syncing disks\n" );
/* It is important _NOT_ to umount filesystems at this point. We want
* them synced (in case something goes wrong) but we DO not want to mark
* filesystem clean: it is not. (And it does not matter, if we resume
@@ -754,9 +731,9 @@ static int suspend_save_image(void)
void suspend_power_down(void)
{
C_A_D = 0;
- printk(KERN_EMERG "%sTrying to power down.\n", name_suspend);
+ printk(KERN_EMERG "%s%s Trying to power down.\n", name_suspend, TEST_SWSUSP ? "Disable TEST_SWSUSP. NOT ": "");
#ifdef CONFIG_VT
- printk(KERN_EMERG "shift_state: %04x\n", shift_state);
+ PRINTK(KERN_EMERG "shift_state: %04x\n", shift_state);
mdelay(1000);
if (TEST_SWSUSP ^ (!!(shift_state & (1 << KG_CTRL))))
machine_restart(NULL);
@@ -783,7 +760,7 @@ void do_magic_resume_1(void)
mb();
spin_lock_irq(&suspend_pagedir_lock); /* Done to disable interrupts */
- printk( "Waiting for DMAs to settle down...\n");
+ PRINTK( "Waiting for DMAs to settle down...\n");
mdelay(1000); /* We do not want some readahead with DMA to corrupt our memory, right?
Do it with disabled interrupts for best effect. That way, if some
driver scheduled DMA, we have good chance for DMA to finish ;-). */
@@ -791,12 +768,10 @@ void do_magic_resume_1(void)
void do_magic_resume_2(void)
{
- if (nr_copy_pages_check != nr_copy_pages)
- panic("nr_copy_pages changed?!");
- if (pagedir_order_check != pagedir_order)
- panic("pagedir_order changed?!");
+ BUG_ON (nr_copy_pages_check != nr_copy_pages);
+ BUG_ON (pagedir_order_check != pagedir_order);
- PRINTR( "Freeing prev allocated pagedir\n" );
+ PRINTK( "Freeing prev allocated pagedir\n" );
free_suspend_pagedir((unsigned long) pagedir_save);
__flush_tlb_global(); /* Even mappings of "global" things (vmalloc) need to be fixed */
drivers_resume(RESUME_ALL_PHASES);
@@ -824,7 +799,7 @@ void do_magic_suspend_2(void)
if (!suspend_save_image())
suspend_power_down(); /* FIXME: if suspend_power_down is commented out, console is lost after few suspends ?! */
- printk(KERN_WARNING "%sSuspend failed, trying to recover...\n", name_suspend);
+ printk(KERN_EMERG "%sSuspend failed, trying to recover...\n", name_suspend);
MDELAY(1000); /* So user can wait and report us messages if armageddon comes :-) */
barrier();
@@ -837,7 +812,7 @@ void do_magic_suspend_2(void)
drivers_resume(RESUME_PHASE1);
spin_unlock_irq(&suspend_pagedir_lock);
mark_swapfiles(((swp_entry_t) {0}), MARK_SWAP_RESUME);
- printk(KERN_WARNING "%sLeaving do_magic_suspend_2...\n", name_suspend);
+ PRINTK(KERN_WARNING "%sLeaving do_magic_suspend_2...\n", name_suspend);
}
/*
@@ -849,7 +824,7 @@ void do_software_suspend(void)
{
arch_prepare_suspend();
if (prepare_suspend_console())
- printk( "Can't allocate a console... proceeding\n");
+ printk( "%sCan't allocate a console... proceeding\n", name_suspend);
if (!prepare_suspend_processes()) {
free_some_memory();
@@ -858,11 +833,11 @@ void do_software_suspend(void)
* We sync here -- so you have consistent filesystem state when things go wrong.
* -- so that noone writes to disk after we do atomic copy of data.
*/
- PRINTS("Syncing disks before copy\n");
+ PRINTK("Syncing disks before copy\n");
do_suspend_sync();
if(drivers_suspend()==0)
do_magic(0); /* This function returns after machine woken up from resume */
- PRINTR("Restarting processes...\n");
+ PRINTK("Restarting processes...\n");
thaw_processes();
}
software_suspend_enabled = 1;
@@ -950,6 +925,8 @@ static int relocate_pagedir(void)
void **eaten_memory = NULL;
void **c = eaten_memory, *m, *f;
+ printk("Relocating pagedir");
+
if(!does_collide_order(old_pagedir, (unsigned long)old_pagedir, pagedir_order)) {
printk("not neccessary\n");
return 0;
@@ -979,7 +956,7 @@ static int relocate_pagedir(void)
if (f)
free_pages((unsigned long)f, pagedir_order);
}
- printk("okay\n");
+ printk("|\n");
return 0;
}
@@ -1011,19 +988,10 @@ static int sanity_check(struct suspend_header *sh)
return 0;
}
-static int bdev_read_page(kdev_t dev, long pos, void *buf)
+static int bdev_read_page(struct block_device *bdev, long pos, void *buf)
{
struct buffer_head *bh;
- struct block_device *bdev;
-
- if (pos%PAGE_SIZE) panic("Sorry, dave, I can't let you do that!\n");
- bdev = bdget(kdev_t_to_nr(dev));
- blkdev_get(bdev, FMODE_READ, O_RDONLY, BDEV_RAW);
- if (!bdev) {
- printk("No block device for %s\n", __bdevname(dev));
- BUG();
- }
- set_blocksize(bdev, PAGE_SIZE);
+ BUG_ON (pos%PAGE_SIZE);
bh = __bread(bdev, pos/PAGE_SIZE, PAGE_SIZE);
if (!bh || (!bh->b_data)) {
return -1;
@@ -1031,44 +999,48 @@ static int bdev_read_page(kdev_t dev, long pos, void *buf)
memcpy(buf, bh->b_data, PAGE_SIZE); /* FIXME: may need kmap() */
BUG_ON(!buffer_uptodate(bh));
brelse(bh);
- blkdev_put(bdev, BDEV_RAW);
return 0;
}
+static int bdev_write_page(struct block_device *bdev, long pos, void *buf)
+{
+ struct buffer_head *bh;
+#if 0
+ BUG_ON (pos%PAGE_SIZE);
+ bh = __bread(bdev, pos/PAGE_SIZE, PAGE_SIZE);
+ if (!bh || (!bh->b_data)) {
+ return -1;
+ }
+ memcpy(bh->b_data, buf, PAGE_SIZE); /* FIXME: may need kmap() */
+ BUG_ON(!buffer_uptodate(bh));
+ generic_make_request(WRITE, bh);
+ if (!buffer_uptodate(bh))
+ printk(KERN_CRIT "%sWarning %s: Fixing swap signatures unsuccessful...\n", name_resume, resume_file);
+ wait_on_buffer(bh);
+ brelse(bh);
+ return 0;
+#endif
+ printk(KERN_CRIT "%sWarning %s: Fixing swap signatures unimplemented...\n", name_resume, resume_file);
+}
+
extern kdev_t __init name_to_kdev_t(const char *line);
-static int resume_try_to_read(const char * specialfile, int noresume)
+static int __read_suspend_image(struct block_device *bdev, union diskpage *cur, int noresume)
{
- union diskpage *cur;
swp_entry_t next;
- int i, nr_pgdir_pages, error;
- int blksize = 0;
-
- resume_device = name_to_kdev_t(specialfile);
- cur = (void *) get_free_page(GFP_ATOMIC);
- if (!cur) {
- printk( "%sNot enough memory?\n", name_resume );
- error = -ENOMEM;
- goto resume_read_error;
- }
+ int i, nr_pgdir_pages;
- printk("Resuming from device %x\n", kdev_t_to_nr(resume_device));
-
-#define READTO(pos, ptr) \
- if (bdev_read_page(resume_device, pos, ptr)) { error = -EIO; goto resume_read_error; }
#define PREPARENEXT \
{ next = cur->link.next; \
next.val = swp_offset(next) * PAGE_SIZE; \
}
- error = -EIO;
- READTO(0, cur);
+ if (bdev_read_page(bdev, 0, cur)) return -EIO;
if ((!memcmp("SWAP-SPACE",cur->swh.magic.magic,10)) ||
(!memcmp("SWAPSPACE2",cur->swh.magic.magic,10))) {
printk(KERN_ERR "%sThis is normal swap space\n", name_resume );
- error = -EINVAL;
- goto resume_read_error;
+ return -EINVAL;
}
PREPARENEXT; /* We have to read next position before we overwrite it */
@@ -1080,18 +1052,26 @@ static int resume_try_to_read(const char * specialfile, int noresume)
else {
panic("%sUnable to find suspended-data signature (%.10s - misspelled?\n",
name_resume, cur->swh.magic.magic);
+ /* We want to panic even with noresume -- we certainly don't want to add
+ out signature into your ext2 filesystem ;-) */
+ }
+ if(noresume) {
+ /* We don't do a sanity check here: we want to restore the swap
+ whatever version of kernel made the suspend image;
+ We need to write swap, but swap is *not* enabled so
+ we must write the device directly */
+ printk("%s: Fixing swap signatures %s...\n", name_resume, resume_file);
+ bdev_write_page(bdev, 0, cur);
}
+
+ if (prepare_suspend_console())
+ printk("%sCan't allocate a console... proceeding\n", name_resume);
printk( "%sSignature found, resuming\n", name_resume );
MDELAY(1000);
- READTO(next.val, cur);
-
- error = -EPERM;
- if (sanity_check(&cur->sh))
- goto resume_read_error;
-
- /* Probably this is the same machine */
-
+ if (bdev_read_page(bdev, next.val, cur)) return -EIO;
+ if (sanity_check(&cur->sh)) /* Is this same machine? */
+ return -EPERM;
PREPARENEXT;
pagedir_save = cur->sh.suspend_pagedir;
@@ -1099,64 +1079,82 @@ static int resume_try_to_read(const char * specialfile, int noresume)
nr_pgdir_pages = SUSPEND_PD_PAGES(nr_copy_pages);
pagedir_order = get_bitmask_order(nr_pgdir_pages);
- error = -ENOMEM;
- free_page((unsigned long) cur);
pagedir_nosave = (suspend_pagedir_t *)__get_free_pages(GFP_ATOMIC, pagedir_order);
- if(!pagedir_nosave)
- goto resume_read_error;
+ if (!pagedir_nosave)
+ return -ENOMEM;
- PRINTR( "%sReading pagedir, ", name_resume );
+ PRINTK( "%sReading pagedir, ", name_resume );
/* We get pages in reverse order of saving! */
- error=-EIO;
for (i=nr_pgdir_pages-1; i>=0; i--) {
- if (!next.val)
- panic( "Preliminary end of suspended data?" );
+ BUG_ON (!next.val);
cur = (union diskpage *)((char *) pagedir_nosave)+i;
- READTO(next.val, cur);
+ if (bdev_read_page(bdev, next.val, cur)) return -EIO;
PREPARENEXT;
}
- if (next.val)
- panic( "Suspended data too long?" );
+ BUG_ON (next.val);
- printk("Relocating pagedir");
- if((error=relocate_pagedir())!=0)
- goto resume_read_error;
- if((error=check_pagedir())!=0)
- goto resume_read_error;
+ if (relocate_pagedir())
+ return -ENOMEM;
+ if (check_pagedir())
+ return -ENOMEM;
- PRINTK( "image data (%d pages): ", nr_copy_pages );
- error = -EIO;
+ printk( "Reading image data (%d pages): ", nr_copy_pages );
for(i=0; i < nr_copy_pages; i++) {
swp_entry_t swap_address = (pagedir_nosave+i)->swap_address;
if (!(i%100))
- PRINTK( "." );
- next.val = swp_offset(swap_address) * PAGE_SIZE;
+ printk( "." );
/* You do not need to check for overlaps...
... check_pagedir already did this work */
- READTO(next.val, (char *)((pagedir_nosave+i)->address));
+ if (bdev_read_page(bdev, swp_offset(swap_address) * PAGE_SIZE, (char *)((pagedir_nosave+i)->address)))
+ return -EIO;
}
- PRINTK( " done\n" );
- error = 0;
+ printk( "|\n" );
+ return 0;
+}
-resume_read_error:
+static int read_suspend_image(const char * specialfile, int noresume)
+{
+ union diskpage *cur;
+ unsigned long scratch_page = 0;
+ int error;
+
+ resume_device = name_to_kdev_t(specialfile);
+ scratch_page = get_free_page(GFP_ATOMIC);
+ cur = (void *) scratch_page;
+ if (cur) {
+ struct block_device *bdev;
+ printk("Resuming from device %s\n", __bdevname(resume_device));
+ bdev = bdget(kdev_t_to_nr(resume_device));
+ if (!bdev) {
+ printk("No such block device ?!\n");
+ BUG();
+ }
+ blkdev_get(bdev, FMODE_READ, O_RDONLY, BDEV_RAW);
+ set_blocksize(bdev, PAGE_SIZE);
+ error = __read_suspend_image(bdev, cur, noresume);
+ blkdev_put(bdev, BDEV_RAW);
+ } else error = -ENOMEM;
+
+ if (scratch_page)
+ free_page(scratch_page);
switch (error) {
case 0:
- PRINTR("Reading resume file was successful\n");
+ PRINTK("Reading resume file was successful\n");
break;
case -EINVAL:
break;
case -EIO:
printk( "%sI/O error\n", name_resume);
- panic("Wanted to resume but it did not work\n");
break;
case -ENOENT:
printk( "%s%s: No such file or directory\n", name_resume, specialfile);
- panic("Wanted to resume but it did not work\n");
+ break;
+ case -ENOMEM:
+ printk( "%sNot enough memory\n", name_resume);
break;
default:
printk( "%sError %d resuming\n", name_resume, error );
- panic("Wanted to resume but it did not work\n");
}
MDELAY(1000);
return error;
@@ -1180,7 +1178,8 @@ void software_resume(void)
printk( "%s", name_resume );
if(resume_status == NORESUME) {
- /* FIXME: Signature should be restored here */
+ if(resume_file[0])
+ read_suspend_image(resume_file, 1);
printk( "disabled\n" );
return;
}
@@ -1190,12 +1189,12 @@ void software_resume(void)
console_loglevel = new_loglevel;
if(!resume_file[0] && resume_status == RESUME_SPECIFIED) {
- printk( "nowhere to resume from\n" );
+ printk( "suspension device unspecified\n" );
return;
}
printk( "resuming from %s\n", resume_file);
- if(resume_try_to_read(resume_file, 0))
+ if(read_suspend_image(resume_file, 0))
goto read_failure;
do_magic(1);
panic("This never returns");