diff options
Diffstat (limited to 'kernel/power/swap.c')
-rw-r--r-- | kernel/power/swap.c | 270 |
1 files changed, 180 insertions, 90 deletions
diff --git a/kernel/power/swap.c b/kernel/power/swap.c index f1dd146bd64d..9b2ee5344dee 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/device.h> | 22 | #include <linux/device.h> |
23 | #include <linux/buffer_head.h> | 23 | #include <linux/buffer_head.h> |
24 | #include <linux/bio.h> | 24 | #include <linux/bio.h> |
25 | #include <linux/blkdev.h> | ||
25 | #include <linux/swap.h> | 26 | #include <linux/swap.h> |
26 | #include <linux/swapops.h> | 27 | #include <linux/swapops.h> |
27 | #include <linux/pm.h> | 28 | #include <linux/pm.h> |
@@ -49,18 +50,16 @@ static int mark_swapfiles(swp_entry_t start) | |||
49 | { | 50 | { |
50 | int error; | 51 | int error; |
51 | 52 | ||
52 | rw_swap_page_sync(READ, | 53 | rw_swap_page_sync(READ, swp_entry(root_swap, 0), |
53 | swp_entry(root_swap, 0), | 54 | virt_to_page((unsigned long)&swsusp_header), NULL); |
54 | virt_to_page((unsigned long)&swsusp_header)); | ||
55 | if (!memcmp("SWAP-SPACE",swsusp_header.sig, 10) || | 55 | if (!memcmp("SWAP-SPACE",swsusp_header.sig, 10) || |
56 | !memcmp("SWAPSPACE2",swsusp_header.sig, 10)) { | 56 | !memcmp("SWAPSPACE2",swsusp_header.sig, 10)) { |
57 | memcpy(swsusp_header.orig_sig,swsusp_header.sig, 10); | 57 | memcpy(swsusp_header.orig_sig,swsusp_header.sig, 10); |
58 | memcpy(swsusp_header.sig,SWSUSP_SIG, 10); | 58 | memcpy(swsusp_header.sig,SWSUSP_SIG, 10); |
59 | swsusp_header.image = start; | 59 | swsusp_header.image = start; |
60 | error = rw_swap_page_sync(WRITE, | 60 | error = rw_swap_page_sync(WRITE, swp_entry(root_swap, 0), |
61 | swp_entry(root_swap, 0), | 61 | virt_to_page((unsigned long)&swsusp_header), |
62 | virt_to_page((unsigned long) | 62 | NULL); |
63 | &swsusp_header)); | ||
64 | } else { | 63 | } else { |
65 | pr_debug("swsusp: Partition is not swap space.\n"); | 64 | pr_debug("swsusp: Partition is not swap space.\n"); |
66 | error = -ENODEV; | 65 | error = -ENODEV; |
@@ -88,16 +87,37 @@ static int swsusp_swap_check(void) /* This is called before saving image */ | |||
88 | * write_page - Write one page to given swap location. | 87 | * write_page - Write one page to given swap location. |
89 | * @buf: Address we're writing. | 88 | * @buf: Address we're writing. |
90 | * @offset: Offset of the swap page we're writing to. | 89 | * @offset: Offset of the swap page we're writing to. |
90 | * @bio_chain: Link the next write BIO here | ||
91 | */ | 91 | */ |
92 | 92 | ||
93 | static int write_page(void *buf, unsigned long offset) | 93 | static int write_page(void *buf, unsigned long offset, struct bio **bio_chain) |
94 | { | 94 | { |
95 | swp_entry_t entry; | 95 | swp_entry_t entry; |
96 | int error = -ENOSPC; | 96 | int error = -ENOSPC; |
97 | 97 | ||
98 | if (offset) { | 98 | if (offset) { |
99 | struct page *page = virt_to_page(buf); | ||
100 | |||
101 | if (bio_chain) { | ||
102 | /* | ||
103 | * Whether or not we successfully allocated a copy page, | ||
104 | * we take a ref on the page here. It gets undone in | ||
105 | * wait_on_bio_chain(). | ||
106 | */ | ||
107 | struct page *page_copy; | ||
108 | page_copy = alloc_page(GFP_ATOMIC); | ||
109 | if (page_copy == NULL) { | ||
110 | WARN_ON_ONCE(1); | ||
111 | bio_chain = NULL; /* Go synchronous */ | ||
112 | get_page(page); | ||
113 | } else { | ||
114 | memcpy(page_address(page_copy), | ||
115 | page_address(page), PAGE_SIZE); | ||
116 | page = page_copy; | ||
117 | } | ||
118 | } | ||
99 | entry = swp_entry(root_swap, offset); | 119 | entry = swp_entry(root_swap, offset); |
100 | error = rw_swap_page_sync(WRITE, entry, virt_to_page(buf)); | 120 | error = rw_swap_page_sync(WRITE, entry, page, bio_chain); |
101 | } | 121 | } |
102 | return error; | 122 | return error; |
103 | } | 123 | } |
@@ -146,6 +166,26 @@ static void release_swap_writer(struct swap_map_handle *handle) | |||
146 | handle->bitmap = NULL; | 166 | handle->bitmap = NULL; |
147 | } | 167 | } |
148 | 168 | ||
169 | static void show_speed(struct timeval *start, struct timeval *stop, | ||
170 | unsigned nr_pages, char *msg) | ||
171 | { | ||
172 | s64 elapsed_centisecs64; | ||
173 | int centisecs; | ||
174 | int k; | ||
175 | int kps; | ||
176 | |||
177 | elapsed_centisecs64 = timeval_to_ns(stop) - timeval_to_ns(start); | ||
178 | do_div(elapsed_centisecs64, NSEC_PER_SEC / 100); | ||
179 | centisecs = elapsed_centisecs64; | ||
180 | if (centisecs == 0) | ||
181 | centisecs = 1; /* avoid div-by-zero */ | ||
182 | k = nr_pages * (PAGE_SIZE / 1024); | ||
183 | kps = (k * 100) / centisecs; | ||
184 | printk("%s %d kbytes in %d.%02d seconds (%d.%02d MB/s)\n", msg, k, | ||
185 | centisecs / 100, centisecs % 100, | ||
186 | kps / 1000, (kps % 1000) / 10); | ||
187 | } | ||
188 | |||
149 | static int get_swap_writer(struct swap_map_handle *handle) | 189 | static int get_swap_writer(struct swap_map_handle *handle) |
150 | { | 190 | { |
151 | handle->cur = (struct swap_map_page *)get_zeroed_page(GFP_KERNEL); | 191 | handle->cur = (struct swap_map_page *)get_zeroed_page(GFP_KERNEL); |
@@ -165,37 +205,70 @@ static int get_swap_writer(struct swap_map_handle *handle) | |||
165 | return 0; | 205 | return 0; |
166 | } | 206 | } |
167 | 207 | ||
168 | static int swap_write_page(struct swap_map_handle *handle, void *buf) | 208 | static int wait_on_bio_chain(struct bio **bio_chain) |
169 | { | 209 | { |
170 | int error; | 210 | struct bio *bio; |
211 | struct bio *next_bio; | ||
212 | int ret = 0; | ||
213 | |||
214 | if (bio_chain == NULL) | ||
215 | return 0; | ||
216 | |||
217 | bio = *bio_chain; | ||
218 | if (bio == NULL) | ||
219 | return 0; | ||
220 | while (bio) { | ||
221 | struct page *page; | ||
222 | |||
223 | next_bio = bio->bi_private; | ||
224 | page = bio->bi_io_vec[0].bv_page; | ||
225 | wait_on_page_locked(page); | ||
226 | if (!PageUptodate(page) || PageError(page)) | ||
227 | ret = -EIO; | ||
228 | put_page(page); | ||
229 | bio_put(bio); | ||
230 | bio = next_bio; | ||
231 | } | ||
232 | *bio_chain = NULL; | ||
233 | return ret; | ||
234 | } | ||
235 | |||
236 | static int swap_write_page(struct swap_map_handle *handle, void *buf, | ||
237 | struct bio **bio_chain) | ||
238 | { | ||
239 | int error = 0; | ||
171 | unsigned long offset; | 240 | unsigned long offset; |
172 | 241 | ||
173 | if (!handle->cur) | 242 | if (!handle->cur) |
174 | return -EINVAL; | 243 | return -EINVAL; |
175 | offset = alloc_swap_page(root_swap, handle->bitmap); | 244 | offset = alloc_swap_page(root_swap, handle->bitmap); |
176 | error = write_page(buf, offset); | 245 | error = write_page(buf, offset, bio_chain); |
177 | if (error) | 246 | if (error) |
178 | return error; | 247 | return error; |
179 | handle->cur->entries[handle->k++] = offset; | 248 | handle->cur->entries[handle->k++] = offset; |
180 | if (handle->k >= MAP_PAGE_ENTRIES) { | 249 | if (handle->k >= MAP_PAGE_ENTRIES) { |
250 | error = wait_on_bio_chain(bio_chain); | ||
251 | if (error) | ||
252 | goto out; | ||
181 | offset = alloc_swap_page(root_swap, handle->bitmap); | 253 | offset = alloc_swap_page(root_swap, handle->bitmap); |
182 | if (!offset) | 254 | if (!offset) |
183 | return -ENOSPC; | 255 | return -ENOSPC; |
184 | handle->cur->next_swap = offset; | 256 | handle->cur->next_swap = offset; |
185 | error = write_page(handle->cur, handle->cur_swap); | 257 | error = write_page(handle->cur, handle->cur_swap, NULL); |
186 | if (error) | 258 | if (error) |
187 | return error; | 259 | goto out; |
188 | memset(handle->cur, 0, PAGE_SIZE); | 260 | memset(handle->cur, 0, PAGE_SIZE); |
189 | handle->cur_swap = offset; | 261 | handle->cur_swap = offset; |
190 | handle->k = 0; | 262 | handle->k = 0; |
191 | } | 263 | } |
192 | return 0; | 264 | out: |
265 | return error; | ||
193 | } | 266 | } |
194 | 267 | ||
195 | static int flush_swap_writer(struct swap_map_handle *handle) | 268 | static int flush_swap_writer(struct swap_map_handle *handle) |
196 | { | 269 | { |
197 | if (handle->cur && handle->cur_swap) | 270 | if (handle->cur && handle->cur_swap) |
198 | return write_page(handle->cur, handle->cur_swap); | 271 | return write_page(handle->cur, handle->cur_swap, NULL); |
199 | else | 272 | else |
200 | return -EINVAL; | 273 | return -EINVAL; |
201 | } | 274 | } |
@@ -206,21 +279,29 @@ static int flush_swap_writer(struct swap_map_handle *handle) | |||
206 | 279 | ||
207 | static int save_image(struct swap_map_handle *handle, | 280 | static int save_image(struct swap_map_handle *handle, |
208 | struct snapshot_handle *snapshot, | 281 | struct snapshot_handle *snapshot, |
209 | unsigned int nr_pages) | 282 | unsigned int nr_to_write) |
210 | { | 283 | { |
211 | unsigned int m; | 284 | unsigned int m; |
212 | int ret; | 285 | int ret; |
213 | int error = 0; | 286 | int error = 0; |
287 | int nr_pages; | ||
288 | int err2; | ||
289 | struct bio *bio; | ||
290 | struct timeval start; | ||
291 | struct timeval stop; | ||
214 | 292 | ||
215 | printk("Saving image data pages (%u pages) ... ", nr_pages); | 293 | printk("Saving image data pages (%u pages) ... ", nr_to_write); |
216 | m = nr_pages / 100; | 294 | m = nr_to_write / 100; |
217 | if (!m) | 295 | if (!m) |
218 | m = 1; | 296 | m = 1; |
219 | nr_pages = 0; | 297 | nr_pages = 0; |
298 | bio = NULL; | ||
299 | do_gettimeofday(&start); | ||
220 | do { | 300 | do { |
221 | ret = snapshot_read_next(snapshot, PAGE_SIZE); | 301 | ret = snapshot_read_next(snapshot, PAGE_SIZE); |
222 | if (ret > 0) { | 302 | if (ret > 0) { |
223 | error = swap_write_page(handle, data_of(*snapshot)); | 303 | error = swap_write_page(handle, data_of(*snapshot), |
304 | &bio); | ||
224 | if (error) | 305 | if (error) |
225 | break; | 306 | break; |
226 | if (!(nr_pages % m)) | 307 | if (!(nr_pages % m)) |
@@ -228,8 +309,13 @@ static int save_image(struct swap_map_handle *handle, | |||
228 | nr_pages++; | 309 | nr_pages++; |
229 | } | 310 | } |
230 | } while (ret > 0); | 311 | } while (ret > 0); |
312 | err2 = wait_on_bio_chain(&bio); | ||
313 | do_gettimeofday(&stop); | ||
314 | if (!error) | ||
315 | error = err2; | ||
231 | if (!error) | 316 | if (!error) |
232 | printk("\b\b\b\bdone\n"); | 317 | printk("\b\b\b\bdone\n"); |
318 | show_speed(&start, &stop, nr_to_write, "Wrote"); | ||
233 | return error; | 319 | return error; |
234 | } | 320 | } |
235 | 321 | ||
@@ -245,8 +331,7 @@ static int enough_swap(unsigned int nr_pages) | |||
245 | unsigned int free_swap = count_swap_pages(root_swap, 1); | 331 | unsigned int free_swap = count_swap_pages(root_swap, 1); |
246 | 332 | ||
247 | pr_debug("swsusp: free swap pages: %u\n", free_swap); | 333 | pr_debug("swsusp: free swap pages: %u\n", free_swap); |
248 | return free_swap > (nr_pages + PAGES_FOR_IO + | 334 | return free_swap > nr_pages + PAGES_FOR_IO; |
249 | (nr_pages + PBES_PER_PAGE - 1) / PBES_PER_PAGE); | ||
250 | } | 335 | } |
251 | 336 | ||
252 | /** | 337 | /** |
@@ -266,7 +351,8 @@ int swsusp_write(void) | |||
266 | int error; | 351 | int error; |
267 | 352 | ||
268 | if ((error = swsusp_swap_check())) { | 353 | if ((error = swsusp_swap_check())) { |
269 | printk(KERN_ERR "swsusp: Cannot find swap device, try swapon -a.\n"); | 354 | printk(KERN_ERR "swsusp: Cannot find swap device, try " |
355 | "swapon -a.\n"); | ||
270 | return error; | 356 | return error; |
271 | } | 357 | } |
272 | memset(&snapshot, 0, sizeof(struct snapshot_handle)); | 358 | memset(&snapshot, 0, sizeof(struct snapshot_handle)); |
@@ -281,7 +367,7 @@ int swsusp_write(void) | |||
281 | error = get_swap_writer(&handle); | 367 | error = get_swap_writer(&handle); |
282 | if (!error) { | 368 | if (!error) { |
283 | unsigned long start = handle.cur_swap; | 369 | unsigned long start = handle.cur_swap; |
284 | error = swap_write_page(&handle, header); | 370 | error = swap_write_page(&handle, header, NULL); |
285 | if (!error) | 371 | if (!error) |
286 | error = save_image(&handle, &snapshot, | 372 | error = save_image(&handle, &snapshot, |
287 | header->pages - 1); | 373 | header->pages - 1); |
@@ -298,27 +384,6 @@ int swsusp_write(void) | |||
298 | return error; | 384 | return error; |
299 | } | 385 | } |
300 | 386 | ||
301 | /* | ||
302 | * Using bio to read from swap. | ||
303 | * This code requires a bit more work than just using buffer heads | ||
304 | * but, it is the recommended way for 2.5/2.6. | ||
305 | * The following are to signal the beginning and end of I/O. Bios | ||
306 | * finish asynchronously, while we want them to happen synchronously. | ||
307 | * A simple atomic_t, and a wait loop take care of this problem. | ||
308 | */ | ||
309 | |||
310 | static atomic_t io_done = ATOMIC_INIT(0); | ||
311 | |||
312 | static int end_io(struct bio *bio, unsigned int num, int err) | ||
313 | { | ||
314 | if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) { | ||
315 | printk(KERN_ERR "I/O error reading swsusp image.\n"); | ||
316 | return -EIO; | ||
317 | } | ||
318 | atomic_set(&io_done, 0); | ||
319 | return 0; | ||
320 | } | ||
321 | |||
322 | static struct block_device *resume_bdev; | 387 | static struct block_device *resume_bdev; |
323 | 388 | ||
324 | /** | 389 | /** |
@@ -326,15 +391,15 @@ static struct block_device *resume_bdev; | |||
326 | * @rw: READ or WRITE. | 391 | * @rw: READ or WRITE. |
327 | * @off physical offset of page. | 392 | * @off physical offset of page. |
328 | * @page: page we're reading or writing. | 393 | * @page: page we're reading or writing. |
394 | * @bio_chain: list of pending biod (for async reading) | ||
329 | * | 395 | * |
330 | * Straight from the textbook - allocate and initialize the bio. | 396 | * Straight from the textbook - allocate and initialize the bio. |
331 | * If we're writing, make sure the page is marked as dirty. | 397 | * If we're reading, make sure the page is marked as dirty. |
332 | * Then submit it and wait. | 398 | * Then submit it and, if @bio_chain == NULL, wait. |
333 | */ | 399 | */ |
334 | 400 | static int submit(int rw, pgoff_t page_off, struct page *page, | |
335 | static int submit(int rw, pgoff_t page_off, void *page) | 401 | struct bio **bio_chain) |
336 | { | 402 | { |
337 | int error = 0; | ||
338 | struct bio *bio; | 403 | struct bio *bio; |
339 | 404 | ||
340 | bio = bio_alloc(GFP_ATOMIC, 1); | 405 | bio = bio_alloc(GFP_ATOMIC, 1); |
@@ -342,33 +407,40 @@ static int submit(int rw, pgoff_t page_off, void *page) | |||
342 | return -ENOMEM; | 407 | return -ENOMEM; |
343 | bio->bi_sector = page_off * (PAGE_SIZE >> 9); | 408 | bio->bi_sector = page_off * (PAGE_SIZE >> 9); |
344 | bio->bi_bdev = resume_bdev; | 409 | bio->bi_bdev = resume_bdev; |
345 | bio->bi_end_io = end_io; | 410 | bio->bi_end_io = end_swap_bio_read; |
346 | 411 | ||
347 | if (bio_add_page(bio, virt_to_page(page), PAGE_SIZE, 0) < PAGE_SIZE) { | 412 | if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) { |
348 | printk("swsusp: ERROR: adding page to bio at %ld\n",page_off); | 413 | printk("swsusp: ERROR: adding page to bio at %ld\n", page_off); |
349 | error = -EFAULT; | 414 | bio_put(bio); |
350 | goto Done; | 415 | return -EFAULT; |
351 | } | 416 | } |
352 | 417 | ||
353 | atomic_set(&io_done, 1); | 418 | lock_page(page); |
354 | submit_bio(rw | (1 << BIO_RW_SYNC), bio); | 419 | bio_get(bio); |
355 | while (atomic_read(&io_done)) | 420 | |
356 | yield(); | 421 | if (bio_chain == NULL) { |
357 | if (rw == READ) | 422 | submit_bio(rw | (1 << BIO_RW_SYNC), bio); |
358 | bio_set_pages_dirty(bio); | 423 | wait_on_page_locked(page); |
359 | Done: | 424 | if (rw == READ) |
360 | bio_put(bio); | 425 | bio_set_pages_dirty(bio); |
361 | return error; | 426 | bio_put(bio); |
427 | } else { | ||
428 | get_page(page); | ||
429 | bio->bi_private = *bio_chain; | ||
430 | *bio_chain = bio; | ||
431 | submit_bio(rw | (1 << BIO_RW_SYNC), bio); | ||
432 | } | ||
433 | return 0; | ||
362 | } | 434 | } |
363 | 435 | ||
364 | static int bio_read_page(pgoff_t page_off, void *page) | 436 | static int bio_read_page(pgoff_t page_off, void *addr, struct bio **bio_chain) |
365 | { | 437 | { |
366 | return submit(READ, page_off, page); | 438 | return submit(READ, page_off, virt_to_page(addr), bio_chain); |
367 | } | 439 | } |
368 | 440 | ||
369 | static int bio_write_page(pgoff_t page_off, void *page) | 441 | static int bio_write_page(pgoff_t page_off, void *addr) |
370 | { | 442 | { |
371 | return submit(WRITE, page_off, page); | 443 | return submit(WRITE, page_off, virt_to_page(addr), NULL); |
372 | } | 444 | } |
373 | 445 | ||
374 | /** | 446 | /** |
@@ -393,7 +465,7 @@ static int get_swap_reader(struct swap_map_handle *handle, | |||
393 | handle->cur = (struct swap_map_page *)get_zeroed_page(GFP_ATOMIC); | 465 | handle->cur = (struct swap_map_page *)get_zeroed_page(GFP_ATOMIC); |
394 | if (!handle->cur) | 466 | if (!handle->cur) |
395 | return -ENOMEM; | 467 | return -ENOMEM; |
396 | error = bio_read_page(swp_offset(start), handle->cur); | 468 | error = bio_read_page(swp_offset(start), handle->cur, NULL); |
397 | if (error) { | 469 | if (error) { |
398 | release_swap_reader(handle); | 470 | release_swap_reader(handle); |
399 | return error; | 471 | return error; |
@@ -402,7 +474,8 @@ static int get_swap_reader(struct swap_map_handle *handle, | |||
402 | return 0; | 474 | return 0; |
403 | } | 475 | } |
404 | 476 | ||
405 | static int swap_read_page(struct swap_map_handle *handle, void *buf) | 477 | static int swap_read_page(struct swap_map_handle *handle, void *buf, |
478 | struct bio **bio_chain) | ||
406 | { | 479 | { |
407 | unsigned long offset; | 480 | unsigned long offset; |
408 | int error; | 481 | int error; |
@@ -412,16 +485,17 @@ static int swap_read_page(struct swap_map_handle *handle, void *buf) | |||
412 | offset = handle->cur->entries[handle->k]; | 485 | offset = handle->cur->entries[handle->k]; |
413 | if (!offset) | 486 | if (!offset) |
414 | return -EFAULT; | 487 | return -EFAULT; |
415 | error = bio_read_page(offset, buf); | 488 | error = bio_read_page(offset, buf, bio_chain); |
416 | if (error) | 489 | if (error) |
417 | return error; | 490 | return error; |
418 | if (++handle->k >= MAP_PAGE_ENTRIES) { | 491 | if (++handle->k >= MAP_PAGE_ENTRIES) { |
492 | error = wait_on_bio_chain(bio_chain); | ||
419 | handle->k = 0; | 493 | handle->k = 0; |
420 | offset = handle->cur->next_swap; | 494 | offset = handle->cur->next_swap; |
421 | if (!offset) | 495 | if (!offset) |
422 | release_swap_reader(handle); | 496 | release_swap_reader(handle); |
423 | else | 497 | else if (!error) |
424 | error = bio_read_page(offset, handle->cur); | 498 | error = bio_read_page(offset, handle->cur, NULL); |
425 | } | 499 | } |
426 | return error; | 500 | return error; |
427 | } | 501 | } |
@@ -434,33 +508,49 @@ static int swap_read_page(struct swap_map_handle *handle, void *buf) | |||
434 | 508 | ||
435 | static int load_image(struct swap_map_handle *handle, | 509 | static int load_image(struct swap_map_handle *handle, |
436 | struct snapshot_handle *snapshot, | 510 | struct snapshot_handle *snapshot, |
437 | unsigned int nr_pages) | 511 | unsigned int nr_to_read) |
438 | { | 512 | { |
439 | unsigned int m; | 513 | unsigned int m; |
440 | int ret; | ||
441 | int error = 0; | 514 | int error = 0; |
515 | struct timeval start; | ||
516 | struct timeval stop; | ||
517 | struct bio *bio; | ||
518 | int err2; | ||
519 | unsigned nr_pages; | ||
442 | 520 | ||
443 | printk("Loading image data pages (%u pages) ... ", nr_pages); | 521 | printk("Loading image data pages (%u pages) ... ", nr_to_read); |
444 | m = nr_pages / 100; | 522 | m = nr_to_read / 100; |
445 | if (!m) | 523 | if (!m) |
446 | m = 1; | 524 | m = 1; |
447 | nr_pages = 0; | 525 | nr_pages = 0; |
448 | do { | 526 | bio = NULL; |
449 | ret = snapshot_write_next(snapshot, PAGE_SIZE); | 527 | do_gettimeofday(&start); |
450 | if (ret > 0) { | 528 | for ( ; ; ) { |
451 | error = swap_read_page(handle, data_of(*snapshot)); | 529 | error = snapshot_write_next(snapshot, PAGE_SIZE); |
452 | if (error) | 530 | if (error <= 0) |
453 | break; | 531 | break; |
454 | if (!(nr_pages % m)) | 532 | error = swap_read_page(handle, data_of(*snapshot), &bio); |
455 | printk("\b\b\b\b%3d%%", nr_pages / m); | 533 | if (error) |
456 | nr_pages++; | 534 | break; |
457 | } | 535 | if (snapshot->sync_read) |
458 | } while (ret > 0); | 536 | error = wait_on_bio_chain(&bio); |
537 | if (error) | ||
538 | break; | ||
539 | if (!(nr_pages % m)) | ||
540 | printk("\b\b\b\b%3d%%", nr_pages / m); | ||
541 | nr_pages++; | ||
542 | } | ||
543 | err2 = wait_on_bio_chain(&bio); | ||
544 | do_gettimeofday(&stop); | ||
545 | if (!error) | ||
546 | error = err2; | ||
459 | if (!error) { | 547 | if (!error) { |
460 | printk("\b\b\b\bdone\n"); | 548 | printk("\b\b\b\bdone\n"); |
549 | snapshot_free_unused_memory(snapshot); | ||
461 | if (!snapshot_image_loaded(snapshot)) | 550 | if (!snapshot_image_loaded(snapshot)) |
462 | error = -ENODATA; | 551 | error = -ENODATA; |
463 | } | 552 | } |
553 | show_speed(&start, &stop, nr_to_read, "Read"); | ||
464 | return error; | 554 | return error; |
465 | } | 555 | } |
466 | 556 | ||
@@ -483,7 +573,7 @@ int swsusp_read(void) | |||
483 | header = (struct swsusp_info *)data_of(snapshot); | 573 | header = (struct swsusp_info *)data_of(snapshot); |
484 | error = get_swap_reader(&handle, swsusp_header.image); | 574 | error = get_swap_reader(&handle, swsusp_header.image); |
485 | if (!error) | 575 | if (!error) |
486 | error = swap_read_page(&handle, header); | 576 | error = swap_read_page(&handle, header, NULL); |
487 | if (!error) | 577 | if (!error) |
488 | error = load_image(&handle, &snapshot, header->pages - 1); | 578 | error = load_image(&handle, &snapshot, header->pages - 1); |
489 | release_swap_reader(&handle); | 579 | release_swap_reader(&handle); |
@@ -509,7 +599,7 @@ int swsusp_check(void) | |||
509 | if (!IS_ERR(resume_bdev)) { | 599 | if (!IS_ERR(resume_bdev)) { |
510 | set_blocksize(resume_bdev, PAGE_SIZE); | 600 | set_blocksize(resume_bdev, PAGE_SIZE); |
511 | memset(&swsusp_header, 0, sizeof(swsusp_header)); | 601 | memset(&swsusp_header, 0, sizeof(swsusp_header)); |
512 | if ((error = bio_read_page(0, &swsusp_header))) | 602 | if ((error = bio_read_page(0, &swsusp_header, NULL))) |
513 | return error; | 603 | return error; |
514 | if (!memcmp(SWSUSP_SIG, swsusp_header.sig, 10)) { | 604 | if (!memcmp(SWSUSP_SIG, swsusp_header.sig, 10)) { |
515 | memcpy(swsusp_header.sig, swsusp_header.orig_sig, 10); | 605 | memcpy(swsusp_header.sig, swsusp_header.orig_sig, 10); |