diff options
Diffstat (limited to 'kernel/power/swap.c')
| -rw-r--r-- | kernel/power/swap.c | 300 |
1 files changed, 288 insertions, 12 deletions
diff --git a/kernel/power/swap.c b/kernel/power/swap.c index e6a5bdf61a37..916eaa790399 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c | |||
| @@ -24,10 +24,12 @@ | |||
| 24 | #include <linux/swapops.h> | 24 | #include <linux/swapops.h> |
| 25 | #include <linux/pm.h> | 25 | #include <linux/pm.h> |
| 26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
| 27 | #include <linux/lzo.h> | ||
| 28 | #include <linux/vmalloc.h> | ||
| 27 | 29 | ||
| 28 | #include "power.h" | 30 | #include "power.h" |
| 29 | 31 | ||
| 30 | #define SWSUSP_SIG "S1SUSPEND" | 32 | #define HIBERNATE_SIG "LINHIB0001" |
| 31 | 33 | ||
| 32 | /* | 34 | /* |
| 33 | * The swap map is a data structure used for keeping track of each page | 35 | * The swap map is a data structure used for keeping track of each page |
| @@ -193,7 +195,7 @@ static int mark_swapfiles(struct swap_map_handle *handle, unsigned int flags) | |||
| 193 | if (!memcmp("SWAP-SPACE",swsusp_header->sig, 10) || | 195 | if (!memcmp("SWAP-SPACE",swsusp_header->sig, 10) || |
| 194 | !memcmp("SWAPSPACE2",swsusp_header->sig, 10)) { | 196 | !memcmp("SWAPSPACE2",swsusp_header->sig, 10)) { |
| 195 | memcpy(swsusp_header->orig_sig,swsusp_header->sig, 10); | 197 | memcpy(swsusp_header->orig_sig,swsusp_header->sig, 10); |
| 196 | memcpy(swsusp_header->sig,SWSUSP_SIG, 10); | 198 | memcpy(swsusp_header->sig, HIBERNATE_SIG, 10); |
| 197 | swsusp_header->image = handle->first_sector; | 199 | swsusp_header->image = handle->first_sector; |
| 198 | swsusp_header->flags = flags; | 200 | swsusp_header->flags = flags; |
| 199 | error = hib_bio_write_page(swsusp_resume_block, | 201 | error = hib_bio_write_page(swsusp_resume_block, |
| @@ -357,6 +359,18 @@ static int swap_writer_finish(struct swap_map_handle *handle, | |||
| 357 | return error; | 359 | return error; |
| 358 | } | 360 | } |
| 359 | 361 | ||
| 362 | /* We need to remember how much compressed data we need to read. */ | ||
| 363 | #define LZO_HEADER sizeof(size_t) | ||
| 364 | |||
| 365 | /* Number of pages/bytes we'll compress at one time. */ | ||
| 366 | #define LZO_UNC_PAGES 32 | ||
| 367 | #define LZO_UNC_SIZE (LZO_UNC_PAGES * PAGE_SIZE) | ||
| 368 | |||
| 369 | /* Number of pages/bytes we need for compressed data (worst case). */ | ||
| 370 | #define LZO_CMP_PAGES DIV_ROUND_UP(lzo1x_worst_compress(LZO_UNC_SIZE) + \ | ||
| 371 | LZO_HEADER, PAGE_SIZE) | ||
| 372 | #define LZO_CMP_SIZE (LZO_CMP_PAGES * PAGE_SIZE) | ||
| 373 | |||
| 360 | /** | 374 | /** |
| 361 | * save_image - save the suspend image data | 375 | * save_image - save the suspend image data |
| 362 | */ | 376 | */ |
| @@ -404,6 +418,137 @@ static int save_image(struct swap_map_handle *handle, | |||
| 404 | return ret; | 418 | return ret; |
| 405 | } | 419 | } |
| 406 | 420 | ||
| 421 | |||
| 422 | /** | ||
| 423 | * save_image_lzo - Save the suspend image data compressed with LZO. | ||
| 424 | * @handle: Swap mam handle to use for saving the image. | ||
| 425 | * @snapshot: Image to read data from. | ||
| 426 | * @nr_to_write: Number of pages to save. | ||
| 427 | */ | ||
| 428 | static int save_image_lzo(struct swap_map_handle *handle, | ||
| 429 | struct snapshot_handle *snapshot, | ||
| 430 | unsigned int nr_to_write) | ||
| 431 | { | ||
| 432 | unsigned int m; | ||
| 433 | int ret = 0; | ||
| 434 | int nr_pages; | ||
| 435 | int err2; | ||
| 436 | struct bio *bio; | ||
| 437 | struct timeval start; | ||
| 438 | struct timeval stop; | ||
| 439 | size_t off, unc_len, cmp_len; | ||
| 440 | unsigned char *unc, *cmp, *wrk, *page; | ||
| 441 | |||
| 442 | page = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH); | ||
| 443 | if (!page) { | ||
| 444 | printk(KERN_ERR "PM: Failed to allocate LZO page\n"); | ||
| 445 | return -ENOMEM; | ||
| 446 | } | ||
| 447 | |||
| 448 | wrk = vmalloc(LZO1X_1_MEM_COMPRESS); | ||
| 449 | if (!wrk) { | ||
| 450 | printk(KERN_ERR "PM: Failed to allocate LZO workspace\n"); | ||
| 451 | free_page((unsigned long)page); | ||
| 452 | return -ENOMEM; | ||
| 453 | } | ||
| 454 | |||
| 455 | unc = vmalloc(LZO_UNC_SIZE); | ||
| 456 | if (!unc) { | ||
| 457 | printk(KERN_ERR "PM: Failed to allocate LZO uncompressed\n"); | ||
| 458 | vfree(wrk); | ||
| 459 | free_page((unsigned long)page); | ||
| 460 | return -ENOMEM; | ||
| 461 | } | ||
| 462 | |||
| 463 | cmp = vmalloc(LZO_CMP_SIZE); | ||
| 464 | if (!cmp) { | ||
| 465 | printk(KERN_ERR "PM: Failed to allocate LZO compressed\n"); | ||
| 466 | vfree(unc); | ||
| 467 | vfree(wrk); | ||
| 468 | free_page((unsigned long)page); | ||
| 469 | return -ENOMEM; | ||
| 470 | } | ||
| 471 | |||
| 472 | printk(KERN_INFO | ||
| 473 | "PM: Compressing and saving image data (%u pages) ... ", | ||
| 474 | nr_to_write); | ||
| 475 | m = nr_to_write / 100; | ||
| 476 | if (!m) | ||
| 477 | m = 1; | ||
| 478 | nr_pages = 0; | ||
| 479 | bio = NULL; | ||
| 480 | do_gettimeofday(&start); | ||
| 481 | for (;;) { | ||
| 482 | for (off = 0; off < LZO_UNC_SIZE; off += PAGE_SIZE) { | ||
| 483 | ret = snapshot_read_next(snapshot); | ||
| 484 | if (ret < 0) | ||
| 485 | goto out_finish; | ||
| 486 | |||
| 487 | if (!ret) | ||
| 488 | break; | ||
| 489 | |||
| 490 | memcpy(unc + off, data_of(*snapshot), PAGE_SIZE); | ||
| 491 | |||
| 492 | if (!(nr_pages % m)) | ||
| 493 | printk(KERN_CONT "\b\b\b\b%3d%%", nr_pages / m); | ||
| 494 | nr_pages++; | ||
| 495 | } | ||
| 496 | |||
| 497 | if (!off) | ||
| 498 | break; | ||
| 499 | |||
| 500 | unc_len = off; | ||
| 501 | ret = lzo1x_1_compress(unc, unc_len, | ||
| 502 | cmp + LZO_HEADER, &cmp_len, wrk); | ||
| 503 | if (ret < 0) { | ||
| 504 | printk(KERN_ERR "PM: LZO compression failed\n"); | ||
| 505 | break; | ||
| 506 | } | ||
| 507 | |||
| 508 | if (unlikely(!cmp_len || | ||
| 509 | cmp_len > lzo1x_worst_compress(unc_len))) { | ||
| 510 | printk(KERN_ERR "PM: Invalid LZO compressed length\n"); | ||
| 511 | ret = -1; | ||
| 512 | break; | ||
| 513 | } | ||
| 514 | |||
| 515 | *(size_t *)cmp = cmp_len; | ||
| 516 | |||
| 517 | /* | ||
| 518 | * Given we are writing one page at a time to disk, we copy | ||
| 519 | * that much from the buffer, although the last bit will likely | ||
| 520 | * be smaller than full page. This is OK - we saved the length | ||
| 521 | * of the compressed data, so any garbage at the end will be | ||
| 522 | * discarded when we read it. | ||
| 523 | */ | ||
| 524 | for (off = 0; off < LZO_HEADER + cmp_len; off += PAGE_SIZE) { | ||
| 525 | memcpy(page, cmp + off, PAGE_SIZE); | ||
| 526 | |||
| 527 | ret = swap_write_page(handle, page, &bio); | ||
| 528 | if (ret) | ||
| 529 | goto out_finish; | ||
| 530 | } | ||
| 531 | } | ||
| 532 | |||
| 533 | out_finish: | ||
| 534 | err2 = hib_wait_on_bio_chain(&bio); | ||
| 535 | do_gettimeofday(&stop); | ||
| 536 | if (!ret) | ||
| 537 | ret = err2; | ||
| 538 | if (!ret) | ||
| 539 | printk(KERN_CONT "\b\b\b\bdone\n"); | ||
| 540 | else | ||
| 541 | printk(KERN_CONT "\n"); | ||
| 542 | swsusp_show_speed(&start, &stop, nr_to_write, "Wrote"); | ||
| 543 | |||
| 544 | vfree(cmp); | ||
| 545 | vfree(unc); | ||
| 546 | vfree(wrk); | ||
| 547 | free_page((unsigned long)page); | ||
| 548 | |||
| 549 | return ret; | ||
| 550 | } | ||
| 551 | |||
| 407 | /** | 552 | /** |
| 408 | * enough_swap - Make sure we have enough swap to save the image. | 553 | * enough_swap - Make sure we have enough swap to save the image. |
| 409 | * | 554 | * |
| @@ -411,12 +556,16 @@ static int save_image(struct swap_map_handle *handle, | |||
| 411 | * space avaiable from the resume partition. | 556 | * space avaiable from the resume partition. |
| 412 | */ | 557 | */ |
| 413 | 558 | ||
| 414 | static int enough_swap(unsigned int nr_pages) | 559 | static int enough_swap(unsigned int nr_pages, unsigned int flags) |
| 415 | { | 560 | { |
| 416 | unsigned int free_swap = count_swap_pages(root_swap, 1); | 561 | unsigned int free_swap = count_swap_pages(root_swap, 1); |
| 562 | unsigned int required; | ||
| 417 | 563 | ||
| 418 | pr_debug("PM: Free swap pages: %u\n", free_swap); | 564 | pr_debug("PM: Free swap pages: %u\n", free_swap); |
| 419 | return free_swap > nr_pages + PAGES_FOR_IO; | 565 | |
| 566 | required = PAGES_FOR_IO + ((flags & SF_NOCOMPRESS_MODE) ? | ||
| 567 | nr_pages : (nr_pages * LZO_CMP_PAGES) / LZO_UNC_PAGES + 1); | ||
| 568 | return free_swap > required; | ||
| 420 | } | 569 | } |
| 421 | 570 | ||
| 422 | /** | 571 | /** |
| @@ -443,7 +592,7 @@ int swsusp_write(unsigned int flags) | |||
| 443 | printk(KERN_ERR "PM: Cannot get swap writer\n"); | 592 | printk(KERN_ERR "PM: Cannot get swap writer\n"); |
| 444 | return error; | 593 | return error; |
| 445 | } | 594 | } |
| 446 | if (!enough_swap(pages)) { | 595 | if (!enough_swap(pages, flags)) { |
| 447 | printk(KERN_ERR "PM: Not enough free swap\n"); | 596 | printk(KERN_ERR "PM: Not enough free swap\n"); |
| 448 | error = -ENOSPC; | 597 | error = -ENOSPC; |
| 449 | goto out_finish; | 598 | goto out_finish; |
| @@ -458,8 +607,11 @@ int swsusp_write(unsigned int flags) | |||
| 458 | } | 607 | } |
| 459 | header = (struct swsusp_info *)data_of(snapshot); | 608 | header = (struct swsusp_info *)data_of(snapshot); |
| 460 | error = swap_write_page(&handle, header, NULL); | 609 | error = swap_write_page(&handle, header, NULL); |
| 461 | if (!error) | 610 | if (!error) { |
| 462 | error = save_image(&handle, &snapshot, pages - 1); | 611 | error = (flags & SF_NOCOMPRESS_MODE) ? |
| 612 | save_image(&handle, &snapshot, pages - 1) : | ||
| 613 | save_image_lzo(&handle, &snapshot, pages - 1); | ||
| 614 | } | ||
| 463 | out_finish: | 615 | out_finish: |
| 464 | error = swap_writer_finish(&handle, flags, error); | 616 | error = swap_writer_finish(&handle, flags, error); |
| 465 | return error; | 617 | return error; |
| @@ -590,6 +742,127 @@ static int load_image(struct swap_map_handle *handle, | |||
| 590 | } | 742 | } |
| 591 | 743 | ||
| 592 | /** | 744 | /** |
| 745 | * load_image_lzo - Load compressed image data and decompress them with LZO. | ||
| 746 | * @handle: Swap map handle to use for loading data. | ||
| 747 | * @snapshot: Image to copy uncompressed data into. | ||
| 748 | * @nr_to_read: Number of pages to load. | ||
| 749 | */ | ||
| 750 | static int load_image_lzo(struct swap_map_handle *handle, | ||
| 751 | struct snapshot_handle *snapshot, | ||
| 752 | unsigned int nr_to_read) | ||
| 753 | { | ||
| 754 | unsigned int m; | ||
| 755 | int error = 0; | ||
| 756 | struct timeval start; | ||
| 757 | struct timeval stop; | ||
| 758 | unsigned nr_pages; | ||
| 759 | size_t off, unc_len, cmp_len; | ||
| 760 | unsigned char *unc, *cmp, *page; | ||
| 761 | |||
| 762 | page = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH); | ||
| 763 | if (!page) { | ||
| 764 | printk(KERN_ERR "PM: Failed to allocate LZO page\n"); | ||
| 765 | return -ENOMEM; | ||
| 766 | } | ||
| 767 | |||
| 768 | unc = vmalloc(LZO_UNC_SIZE); | ||
| 769 | if (!unc) { | ||
| 770 | printk(KERN_ERR "PM: Failed to allocate LZO uncompressed\n"); | ||
| 771 | free_page((unsigned long)page); | ||
| 772 | return -ENOMEM; | ||
| 773 | } | ||
| 774 | |||
| 775 | cmp = vmalloc(LZO_CMP_SIZE); | ||
| 776 | if (!cmp) { | ||
| 777 | printk(KERN_ERR "PM: Failed to allocate LZO compressed\n"); | ||
| 778 | vfree(unc); | ||
| 779 | free_page((unsigned long)page); | ||
| 780 | return -ENOMEM; | ||
| 781 | } | ||
| 782 | |||
| 783 | printk(KERN_INFO | ||
| 784 | "PM: Loading and decompressing image data (%u pages) ... ", | ||
| 785 | nr_to_read); | ||
| 786 | m = nr_to_read / 100; | ||
| 787 | if (!m) | ||
| 788 | m = 1; | ||
| 789 | nr_pages = 0; | ||
| 790 | do_gettimeofday(&start); | ||
| 791 | |||
| 792 | error = snapshot_write_next(snapshot); | ||
| 793 | if (error <= 0) | ||
| 794 | goto out_finish; | ||
| 795 | |||
| 796 | for (;;) { | ||
| 797 | error = swap_read_page(handle, page, NULL); /* sync */ | ||
| 798 | if (error) | ||
| 799 | break; | ||
| 800 | |||
| 801 | cmp_len = *(size_t *)page; | ||
| 802 | if (unlikely(!cmp_len || | ||
| 803 | cmp_len > lzo1x_worst_compress(LZO_UNC_SIZE))) { | ||
| 804 | printk(KERN_ERR "PM: Invalid LZO compressed length\n"); | ||
| 805 | error = -1; | ||
| 806 | break; | ||
| 807 | } | ||
| 808 | |||
| 809 | memcpy(cmp, page, PAGE_SIZE); | ||
| 810 | for (off = PAGE_SIZE; off < LZO_HEADER + cmp_len; off += PAGE_SIZE) { | ||
| 811 | error = swap_read_page(handle, page, NULL); /* sync */ | ||
| 812 | if (error) | ||
| 813 | goto out_finish; | ||
| 814 | |||
| 815 | memcpy(cmp + off, page, PAGE_SIZE); | ||
| 816 | } | ||
| 817 | |||
| 818 | unc_len = LZO_UNC_SIZE; | ||
| 819 | error = lzo1x_decompress_safe(cmp + LZO_HEADER, cmp_len, | ||
| 820 | unc, &unc_len); | ||
| 821 | if (error < 0) { | ||
| 822 | printk(KERN_ERR "PM: LZO decompression failed\n"); | ||
| 823 | break; | ||
| 824 | } | ||
| 825 | |||
| 826 | if (unlikely(!unc_len || | ||
| 827 | unc_len > LZO_UNC_SIZE || | ||
| 828 | unc_len & (PAGE_SIZE - 1))) { | ||
| 829 | printk(KERN_ERR "PM: Invalid LZO uncompressed length\n"); | ||
| 830 | error = -1; | ||
| 831 | break; | ||
| 832 | } | ||
| 833 | |||
| 834 | for (off = 0; off < unc_len; off += PAGE_SIZE) { | ||
| 835 | memcpy(data_of(*snapshot), unc + off, PAGE_SIZE); | ||
| 836 | |||
| 837 | if (!(nr_pages % m)) | ||
| 838 | printk("\b\b\b\b%3d%%", nr_pages / m); | ||
| 839 | nr_pages++; | ||
| 840 | |||
| 841 | error = snapshot_write_next(snapshot); | ||
| 842 | if (error <= 0) | ||
| 843 | goto out_finish; | ||
| 844 | } | ||
| 845 | } | ||
| 846 | |||
| 847 | out_finish: | ||
| 848 | do_gettimeofday(&stop); | ||
| 849 | if (!error) { | ||
| 850 | printk("\b\b\b\bdone\n"); | ||
| 851 | snapshot_write_finalize(snapshot); | ||
| 852 | if (!snapshot_image_loaded(snapshot)) | ||
| 853 | error = -ENODATA; | ||
| 854 | } else | ||
| 855 | printk("\n"); | ||
| 856 | swsusp_show_speed(&start, &stop, nr_to_read, "Read"); | ||
| 857 | |||
| 858 | vfree(cmp); | ||
| 859 | vfree(unc); | ||
| 860 | free_page((unsigned long)page); | ||
| 861 | |||
| 862 | return error; | ||
| 863 | } | ||
| 864 | |||
| 865 | /** | ||
| 593 | * swsusp_read - read the hibernation image. | 866 | * swsusp_read - read the hibernation image. |
| 594 | * @flags_p: flags passed by the "frozen" kernel in the image header should | 867 | * @flags_p: flags passed by the "frozen" kernel in the image header should |
| 595 | * be written into this memeory location | 868 | * be written into this memeory location |
| @@ -612,8 +885,11 @@ int swsusp_read(unsigned int *flags_p) | |||
| 612 | goto end; | 885 | goto end; |
| 613 | if (!error) | 886 | if (!error) |
| 614 | error = swap_read_page(&handle, header, NULL); | 887 | error = swap_read_page(&handle, header, NULL); |
| 615 | if (!error) | 888 | if (!error) { |
| 616 | error = load_image(&handle, &snapshot, header->pages - 1); | 889 | error = (*flags_p & SF_NOCOMPRESS_MODE) ? |
| 890 | load_image(&handle, &snapshot, header->pages - 1) : | ||
| 891 | load_image_lzo(&handle, &snapshot, header->pages - 1); | ||
| 892 | } | ||
| 617 | swap_reader_finish(&handle); | 893 | swap_reader_finish(&handle); |
| 618 | end: | 894 | end: |
| 619 | if (!error) | 895 | if (!error) |
| @@ -640,7 +916,7 @@ int swsusp_check(void) | |||
| 640 | if (error) | 916 | if (error) |
| 641 | goto put; | 917 | goto put; |
| 642 | 918 | ||
| 643 | if (!memcmp(SWSUSP_SIG, swsusp_header->sig, 10)) { | 919 | if (!memcmp(HIBERNATE_SIG, swsusp_header->sig, 10)) { |
| 644 | memcpy(swsusp_header->sig, swsusp_header->orig_sig, 10); | 920 | memcpy(swsusp_header->sig, swsusp_header->orig_sig, 10); |
| 645 | /* Reset swap signature now */ | 921 | /* Reset swap signature now */ |
| 646 | error = hib_bio_write_page(swsusp_resume_block, | 922 | error = hib_bio_write_page(swsusp_resume_block, |
| @@ -653,13 +929,13 @@ put: | |||
| 653 | if (error) | 929 | if (error) |
| 654 | blkdev_put(hib_resume_bdev, FMODE_READ); | 930 | blkdev_put(hib_resume_bdev, FMODE_READ); |
| 655 | else | 931 | else |
| 656 | pr_debug("PM: Signature found, resuming\n"); | 932 | pr_debug("PM: Image signature found, resuming\n"); |
| 657 | } else { | 933 | } else { |
| 658 | error = PTR_ERR(hib_resume_bdev); | 934 | error = PTR_ERR(hib_resume_bdev); |
| 659 | } | 935 | } |
| 660 | 936 | ||
| 661 | if (error) | 937 | if (error) |
| 662 | pr_debug("PM: Error %d checking image file\n", error); | 938 | pr_debug("PM: Image not found (code %d)\n", error); |
| 663 | 939 | ||
| 664 | return error; | 940 | return error; |
| 665 | } | 941 | } |
