forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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: Bojan Smojver <[email protected]> Signed-off-by: Rafael J. Wysocki <[email protected]>
- Loading branch information
Showing
1 changed file
with
38 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,7 @@ | |
* | ||
* Copyright (C) 1998,2001-2005 Pavel Machek <[email protected]> | ||
* Copyright (C) 2006 Rafael J. Wysocki <[email protected]> | ||
* Copyright (C) 2010 Bojan Smojver <[email protected]> | ||
* | ||
* This file is released under the GPLv2. | ||
* | ||
|
@@ -753,30 +754,43 @@ static int load_image_lzo(struct swap_map_handle *handle, | |
{ | ||
unsigned int m; | ||
int error = 0; | ||
struct bio *bio; | ||
struct timeval start; | ||
struct timeval stop; | ||
unsigned nr_pages; | ||
size_t off, unc_len, cmp_len; | ||
unsigned char *unc, *cmp, *page; | ||
size_t i, off, unc_len, cmp_len; | ||
unsigned char *unc, *cmp, *page[LZO_CMP_PAGES]; | ||
|
||
page = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH); | ||
if (!page) { | ||
printk(KERN_ERR "PM: Failed to allocate LZO page\n"); | ||
return -ENOMEM; | ||
for (i = 0; i < LZO_CMP_PAGES; i++) { | ||
page[i] = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH); | ||
if (!page[i]) { | ||
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); | ||
if (!unc) { | ||
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; | ||
} | ||
|
||
cmp = vmalloc(LZO_CMP_SIZE); | ||
if (!cmp) { | ||
printk(KERN_ERR "PM: Failed to allocate LZO compressed\n"); | ||
|
||
vfree(unc); | ||
free_page((unsigned long)page); | ||
for (i = 0; i < LZO_CMP_PAGES; i++) | ||
free_page((unsigned long)page[i]); | ||
|
||
return -ENOMEM; | ||
} | ||
|
||
|
@@ -787,32 +801,40 @@ static int load_image_lzo(struct swap_map_handle *handle, | |
if (!m) | ||
m = 1; | ||
nr_pages = 0; | ||
bio = NULL; | ||
do_gettimeofday(&start); | ||
|
||
error = snapshot_write_next(snapshot); | ||
if (error <= 0) | ||
goto out_finish; | ||
|
||
for (;;) { | ||
error = swap_read_page(handle, page, NULL); /* sync */ | ||
error = swap_read_page(handle, page[0], NULL); /* sync */ | ||
if (error) | ||
break; | ||
|
||
cmp_len = *(size_t *)page; | ||
cmp_len = *(size_t *)page[0]; | ||
if (unlikely(!cmp_len || | ||
cmp_len > lzo1x_worst_compress(LZO_UNC_SIZE))) { | ||
printk(KERN_ERR "PM: Invalid LZO compressed length\n"); | ||
error = -1; | ||
break; | ||
} | ||
|
||
memcpy(cmp, page, PAGE_SIZE); | ||
for (off = PAGE_SIZE; off < LZO_HEADER + cmp_len; off += PAGE_SIZE) { | ||
error = swap_read_page(handle, page, NULL); /* sync */ | ||
for (off = PAGE_SIZE, i = 1; | ||
off < LZO_HEADER + cmp_len; off += PAGE_SIZE, i++) { | ||
error = swap_read_page(handle, page[i], &bio); | ||
if (error) | ||
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; | ||
|
@@ -857,7 +879,8 @@ static int load_image_lzo(struct swap_map_handle *handle, | |
|
||
vfree(cmp); | ||
vfree(unc); | ||
free_page((unsigned long)page); | ||
for (i = 0; i < LZO_CMP_PAGES; i++) | ||
free_page((unsigned long)page[i]); | ||
|
||
return error; | ||
} | ||
|