Commit b52d040a authored by Patrick Mochel's avatar Patrick Mochel

[Power Mgmt] Consolidate pmdisk and swsusp early swap access.

- Move bio helpers to swsusp.
- Convert swsusp to use them, rathen buffer_heads.
- Expose and fix up calls in pmdisk.
- Clean up swsusp::read_suspend_image() a bit.
parent 6df01ca8
......@@ -279,90 +279,9 @@ static int suspend_save_image(void)
/* More restore stuff */
static struct block_device * resume_bdev;
/**
* Using bio to read from swap.
* This code requires a bit more work than just using buffer heads
* but, it is the recommended way for 2.5/2.6.
* The following are to signal the beginning and end of I/O. Bios
* finish asynchronously, while we want them to happen synchronously.
* A simple atomic_t, and a wait loop take care of this problem.
*/
static atomic_t io_done = ATOMIC_INIT(0);
static void start_io(void)
{
atomic_set(&io_done,1);
}
static int end_io(struct bio * bio, unsigned int num, int err)
{
atomic_set(&io_done,0);
return 0;
}
static void wait_io(void)
{
while(atomic_read(&io_done))
io_schedule();
}
/**
* submit - submit BIO request.
* @rw: READ or WRITE.
* @off physical offset of page.
* @page: page we're reading or writing.
*
* Straight from the textbook - allocate and initialize the bio.
* If we're writing, make sure the page is marked as dirty.
* Then submit it and wait.
*/
static int submit(int rw, pgoff_t page_off, void * page)
{
int error = 0;
struct bio * bio;
bio = bio_alloc(GFP_ATOMIC,1);
if (!bio)
return -ENOMEM;
bio->bi_sector = page_off * (PAGE_SIZE >> 9);
bio_get(bio);
bio->bi_bdev = resume_bdev;
bio->bi_end_io = end_io;
if (bio_add_page(bio, virt_to_page(page), PAGE_SIZE, 0) < PAGE_SIZE) {
printk("pmdisk: ERROR: adding page to bio at %ld\n",page_off);
error = -EFAULT;
goto Done;
}
if (rw == WRITE)
bio_set_pages_dirty(bio);
start_io();
submit_bio(rw | (1 << BIO_RW_SYNC), bio);
wait_io();
Done:
bio_put(bio);
return error;
}
static int
read_page(pgoff_t page_off, void * page)
{
return submit(READ,page_off,page);
}
static int
write_page(pgoff_t page_off, void * page)
{
return submit(WRITE,page_off,page);
}
extern struct block_device * resume_bdev;
extern int bio_read_page(pgoff_t page_off, void * page);
extern int bio_write_page(pgoff_t page_off, void * page);
extern dev_t __init name_to_dev_t(const char *line);
......@@ -372,7 +291,7 @@ static int __init check_sig(void)
int error;
memset(&pmdisk_header,0,sizeof(pmdisk_header));
if ((error = read_page(0,&pmdisk_header)))
if ((error = bio_read_page(0,&pmdisk_header)))
return error;
if (!memcmp(PMDISK_SIG,pmdisk_header.sig,10)) {
memcpy(pmdisk_header.sig,pmdisk_header.orig_sig,10);
......@@ -380,7 +299,7 @@ static int __init check_sig(void)
/*
* Reset swap signature now.
*/
error = write_page(0,&pmdisk_header);
error = bio_write_page(0,&pmdisk_header);
} else {
pr_debug(KERN_ERR "pmdisk: Invalid partition type.\n");
return -EINVAL;
......@@ -424,7 +343,7 @@ static int __init check_header(void)
init_header();
if ((error = read_page(swp_offset(pmdisk_header.pmdisk_info),
if ((error = bio_read_page(swp_offset(pmdisk_header.pmdisk_info),
&pmdisk_info)))
return error;
......@@ -456,7 +375,7 @@ static int __init read_pagedir(void)
for (i = 0; i < n && !error; i++, addr += PAGE_SIZE) {
unsigned long offset = swp_offset(pmdisk_info.pagedir[i]);
if (offset)
error = read_page(offset, (void *)addr);
error = bio_read_page(offset, (void *)addr);
else
error = -EFAULT;
}
......@@ -483,7 +402,7 @@ static int __init read_image_data(void)
for(i = 0, p = pagedir_nosave; i < nr_copy_pages && !error; i++, p++) {
if (!(i%100))
printk( "." );
error = read_page(swp_offset(p->swap_address),
error = bio_read_page(swp_offset(p->swap_address),
(void *)p->address);
}
printk(" %d done.\n",i);
......
......@@ -62,6 +62,7 @@
#include <linux/syscalls.h>
#include <linux/console.h>
#include <linux/highmem.h>
#include <linux/bio.h>
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
......@@ -1114,55 +1115,107 @@ static int sanity_check(struct suspend_header *sh)
return 0;
}
static int bdev_read_page(struct block_device *bdev, long pos, void *buf)
/**
* Using bio to read from swap.
* This code requires a bit more work than just using buffer heads
* but, it is the recommended way for 2.5/2.6.
* The following are to signal the beginning and end of I/O. Bios
* finish asynchronously, while we want them to happen synchronously.
* A simple atomic_t, and a wait loop take care of this problem.
*/
static atomic_t io_done = ATOMIC_INIT(0);
static void start_io(void)
{
struct buffer_head *bh;
BUG_ON (pos%PAGE_SIZE);
bh = __bread(bdev, pos/PAGE_SIZE, PAGE_SIZE);
if (!bh || (!bh->b_data)) {
return -1;
}
memcpy(buf, bh->b_data, PAGE_SIZE); /* FIXME: may need kmap() */
BUG_ON(!buffer_uptodate(bh));
brelse(bh);
atomic_set(&io_done,1);
}
static int end_io(struct bio * bio, unsigned int num, int err)
{
atomic_set(&io_done,0);
return 0;
}
static int bdev_write_page(struct block_device *bdev, long pos, void *buf)
static void wait_io(void)
{
while(atomic_read(&io_done))
io_schedule();
}
struct block_device * resume_bdev;
/**
* submit - submit BIO request.
* @rw: READ or WRITE.
* @off physical offset of page.
* @page: page we're reading or writing.
*
* Straight from the textbook - allocate and initialize the bio.
* If we're writing, make sure the page is marked as dirty.
* Then submit it and wait.
*/
static int submit(int rw, pgoff_t page_off, void * page)
{
#if 0
struct buffer_head *bh;
BUG_ON (pos%PAGE_SIZE);
bh = __bread(bdev, pos/PAGE_SIZE, PAGE_SIZE);
if (!bh || (!bh->b_data)) {
return -1;
int error = 0;
struct bio * bio;
bio = bio_alloc(GFP_ATOMIC,1);
if (!bio)
return -ENOMEM;
bio->bi_sector = page_off * (PAGE_SIZE >> 9);
bio_get(bio);
bio->bi_bdev = resume_bdev;
bio->bi_end_io = end_io;
if (bio_add_page(bio, virt_to_page(page), PAGE_SIZE, 0) < PAGE_SIZE) {
printk("pmdisk: ERROR: adding page to bio at %ld\n",page_off);
error = -EFAULT;
goto Done;
}
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);
return 0;
if (rw == WRITE)
bio_set_pages_dirty(bio);
start_io();
submit_bio(rw | (1 << BIO_RW_SYNC), bio);
wait_io();
Done:
bio_put(bio);
return error;
}
int bio_read_page(pgoff_t page_off, void * page)
{
return submit(READ,page_off,page);
}
int bio_write_page(pgoff_t page_off, void * page)
{
return submit(WRITE,page_off,page);
}
extern dev_t __init name_to_dev_t(const char *line);
static int __init __read_suspend_image(struct block_device *bdev, union diskpage *cur, int noresume)
static int __init __read_suspend_image(int noresume)
{
union diskpage *cur;
swp_entry_t next;
int i, nr_pgdir_pages;
cur = (union diskpage *)get_zeroed_page(GFP_ATOMIC);
if (!cur)
return -ENOMEM;
#define PREPARENEXT \
{ next = cur->link.next; \
next.val = swp_offset(next) * PAGE_SIZE; \
}
if (bdev_read_page(bdev, 0, cur)) return -EIO;
if (bio_read_page(0, cur)) return -EIO;
if ((!memcmp("SWAP-SPACE",cur->swh.magic.magic,10)) ||
(!memcmp("SWAPSPACE2",cur->swh.magic.magic,10))) {
......@@ -1188,13 +1241,13 @@ static int __init __read_suspend_image(struct block_device *bdev, union diskpage
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);
bio_write_page(0, cur);
}
printk( "%sSignature found, resuming\n", name_resume );
MDELAY(1000);
if (bdev_read_page(bdev, next.val, cur)) return -EIO;
if (bio_read_page(next.val, cur)) return -EIO;
if (sanity_check(&cur->sh)) /* Is this same machine? */
return -EPERM;
PREPARENEXT;
......@@ -1214,7 +1267,7 @@ static int __init __read_suspend_image(struct block_device *bdev, union diskpage
for (i=nr_pgdir_pages-1; i>=0; i--) {
BUG_ON (!next.val);
cur = (union diskpage *)((char *) pagedir_nosave)+i;
if (bdev_read_page(bdev, next.val, cur)) return -EIO;
if (bio_read_page(next.val, cur)) return -EIO;
PREPARENEXT;
}
BUG_ON (next.val);
......@@ -1229,7 +1282,7 @@ static int __init __read_suspend_image(struct block_device *bdev, union diskpage
printk( "." );
/* You do not need to check for overlaps...
... check_pagedir already did this work */
if (bdev_read_page(bdev, swp_offset(swap_address) * PAGE_SIZE, (char *)((pagedir_nosave+i)->address)))
if (bio_read_page(swp_offset(swap_address) * PAGE_SIZE, (char *)((pagedir_nosave+i)->address)))
return -EIO;
}
printk( "|\n" );
......@@ -1238,48 +1291,18 @@ static int __init __read_suspend_image(struct block_device *bdev, union diskpage
static int __init read_suspend_image(const char * specialfile, int noresume)
{
union diskpage *cur;
unsigned long scratch_page = 0;
int error;
char b[BDEVNAME_SIZE];
resume_device = name_to_dev_t(specialfile);
scratch_page = get_zeroed_page(GFP_ATOMIC);
cur = (void *) scratch_page;
if (cur) {
struct block_device *bdev;
printk("Resuming from device %s\n",
__bdevname(resume_device, b));
bdev = open_by_devnum(resume_device, FMODE_READ);
if (IS_ERR(bdev)) {
error = PTR_ERR(bdev);
} else {
set_blocksize(bdev, PAGE_SIZE);
error = __read_suspend_image(bdev, cur, noresume);
blkdev_put(bdev);
}
} else error = -ENOMEM;
if (scratch_page)
free_page(scratch_page);
switch (error) {
case 0:
PRINTK("Reading resume file was successful\n");
break;
case -EINVAL:
break;
case -EIO:
printk( "%sI/O error\n", name_resume);
break;
case -ENOENT:
printk( "%s%s: No such file or directory\n", name_resume, specialfile);
break;
case -ENOMEM:
printk( "%sNot enough memory\n", name_resume);
break;
default:
printk( "%sError %d resuming\n", name_resume, error );
}
printk("Resuming from device %s\n", __bdevname(resume_device, b));
resume_bdev = open_by_devnum(resume_device, FMODE_READ);
if (!IS_ERR(resume_bdev)) {
set_blocksize(resume_bdev, PAGE_SIZE);
error = __read_suspend_image(noresume);
blkdev_put(resume_bdev);
} else
error = PTR_ERR(resume_bdev);
MDELAY(1000);
return error;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment