Commit 9f339caf authored by Bojan Smojver's avatar Bojan Smojver Committed by Rafael J. Wysocki

PM / Hibernate: Use async I/O when reading compressed hibernation image

This is a fix for reading LZO compressed image using async I/O.
Essentially, instead of having just one page into which we keep
reading blocks from swap, we allocate enough of them to cover the
largest compressed size and then let block I/O pick them all up. Once
we have them all (and here we wait), we decompress them, as usual.
Obviously, the very first block we still pick up synchronously,
because we need to know the size of the lot before we pick up the
rest.

Also fixed the copyright line, which I've forgotten before.
Signed-off-by: default avatarBojan Smojver <bojan@rexursive.com>
Signed-off-by: default avatarRafael J. Wysocki <rjw@sisk.pl>
parent 698fd6a2
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
* *
* Copyright (C) 1998,2001-2005 Pavel Machek <pavel@ucw.cz> * Copyright (C) 1998,2001-2005 Pavel Machek <pavel@ucw.cz>
* Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl> * Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl>
* Copyright (C) 2010 Bojan Smojver <bojan@rexursive.com>
* *
* This file is released under the GPLv2. * This file is released under the GPLv2.
* *
...@@ -753,30 +754,43 @@ static int load_image_lzo(struct swap_map_handle *handle, ...@@ -753,30 +754,43 @@ static int load_image_lzo(struct swap_map_handle *handle,
{ {
unsigned int m; unsigned int m;
int error = 0; int error = 0;
struct bio *bio;
struct timeval start; struct timeval start;
struct timeval stop; struct timeval stop;
unsigned nr_pages; unsigned nr_pages;
size_t off, unc_len, cmp_len; size_t i, off, unc_len, cmp_len;
unsigned char *unc, *cmp, *page; unsigned char *unc, *cmp, *page[LZO_CMP_PAGES];
page = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH); for (i = 0; i < LZO_CMP_PAGES; i++) {
if (!page) { page[i] = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH);
printk(KERN_ERR "PM: Failed to allocate LZO page\n"); if (!page[i]) {
return -ENOMEM; printk(KERN_ERR "PM: Failed to allocate LZO page\n");
while (i)
free_page((unsigned long)page[--i]);
return -ENOMEM;
}
} }
unc = vmalloc(LZO_UNC_SIZE); unc = vmalloc(LZO_UNC_SIZE);
if (!unc) { if (!unc) {
printk(KERN_ERR "PM: Failed to allocate LZO uncompressed\n"); printk(KERN_ERR "PM: Failed to allocate LZO uncompressed\n");
free_page((unsigned long)page);
for (i = 0; i < LZO_CMP_PAGES; i++)
free_page((unsigned long)page[i]);
return -ENOMEM; return -ENOMEM;
} }
cmp = vmalloc(LZO_CMP_SIZE); cmp = vmalloc(LZO_CMP_SIZE);
if (!cmp) { if (!cmp) {
printk(KERN_ERR "PM: Failed to allocate LZO compressed\n"); printk(KERN_ERR "PM: Failed to allocate LZO compressed\n");
vfree(unc); vfree(unc);
free_page((unsigned long)page); for (i = 0; i < LZO_CMP_PAGES; i++)
free_page((unsigned long)page[i]);
return -ENOMEM; return -ENOMEM;
} }
...@@ -787,6 +801,7 @@ static int load_image_lzo(struct swap_map_handle *handle, ...@@ -787,6 +801,7 @@ static int load_image_lzo(struct swap_map_handle *handle,
if (!m) if (!m)
m = 1; m = 1;
nr_pages = 0; nr_pages = 0;
bio = NULL;
do_gettimeofday(&start); do_gettimeofday(&start);
error = snapshot_write_next(snapshot); error = snapshot_write_next(snapshot);
...@@ -794,11 +809,11 @@ static int load_image_lzo(struct swap_map_handle *handle, ...@@ -794,11 +809,11 @@ static int load_image_lzo(struct swap_map_handle *handle,
goto out_finish; goto out_finish;
for (;;) { for (;;) {
error = swap_read_page(handle, page, NULL); /* sync */ error = swap_read_page(handle, page[0], NULL); /* sync */
if (error) if (error)
break; break;
cmp_len = *(size_t *)page; cmp_len = *(size_t *)page[0];
if (unlikely(!cmp_len || if (unlikely(!cmp_len ||
cmp_len > lzo1x_worst_compress(LZO_UNC_SIZE))) { cmp_len > lzo1x_worst_compress(LZO_UNC_SIZE))) {
printk(KERN_ERR "PM: Invalid LZO compressed length\n"); printk(KERN_ERR "PM: Invalid LZO compressed length\n");
...@@ -806,13 +821,20 @@ static int load_image_lzo(struct swap_map_handle *handle, ...@@ -806,13 +821,20 @@ static int load_image_lzo(struct swap_map_handle *handle,
break; break;
} }
memcpy(cmp, page, PAGE_SIZE); for (off = PAGE_SIZE, i = 1;
for (off = PAGE_SIZE; off < LZO_HEADER + cmp_len; off += PAGE_SIZE) { off < LZO_HEADER + cmp_len; off += PAGE_SIZE, i++) {
error = swap_read_page(handle, page, NULL); /* sync */ error = swap_read_page(handle, page[i], &bio);
if (error) if (error)
goto out_finish; goto out_finish;
}
memcpy(cmp + off, page, PAGE_SIZE); error = hib_wait_on_bio_chain(&bio); /* need all data now */
if (error)
goto out_finish;
for (off = 0, i = 0;
off < LZO_HEADER + cmp_len; off += PAGE_SIZE, i++) {
memcpy(cmp + off, page[i], PAGE_SIZE);
} }
unc_len = LZO_UNC_SIZE; unc_len = LZO_UNC_SIZE;
...@@ -857,7 +879,8 @@ static int load_image_lzo(struct swap_map_handle *handle, ...@@ -857,7 +879,8 @@ static int load_image_lzo(struct swap_map_handle *handle,
vfree(cmp); vfree(cmp);
vfree(unc); vfree(unc);
free_page((unsigned long)page); for (i = 0; i < LZO_CMP_PAGES; i++)
free_page((unsigned long)page[i]);
return error; 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