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); |
