diff options
Diffstat (limited to 'kernel/power/swsusp.c')
-rw-r--r-- | kernel/power/swsusp.c | 159 |
1 files changed, 75 insertions, 84 deletions
diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c index 016504ccfccf..ae46506e2137 100644 --- a/kernel/power/swsusp.c +++ b/kernel/power/swsusp.c | |||
@@ -708,24 +708,28 @@ static void count_data_pages(void) | |||
708 | } | 708 | } |
709 | } | 709 | } |
710 | 710 | ||
711 | |||
712 | static void copy_data_pages(void) | 711 | static void copy_data_pages(void) |
713 | { | 712 | { |
714 | struct zone *zone; | 713 | struct zone *zone; |
715 | unsigned long zone_pfn; | 714 | unsigned long zone_pfn; |
716 | struct pbe * pbe = pagedir_nosave; | 715 | struct pbe *pbe = pagedir_nosave, *p; |
717 | 716 | ||
718 | pr_debug("copy_data_pages(): pages to copy: %d\n", nr_copy_pages); | 717 | pr_debug("copy_data_pages(): pages to copy: %d\n", nr_copy_pages); |
719 | for_each_zone (zone) { | 718 | for_each_zone (zone) { |
720 | if (is_highmem(zone)) | 719 | if (is_highmem(zone)) |
721 | continue; | 720 | continue; |
722 | mark_free_pages(zone); | 721 | mark_free_pages(zone); |
722 | /* This is necessary for swsusp_free() */ | ||
723 | for_each_pb_page (p, pagedir_nosave) | ||
724 | SetPageNosaveFree(virt_to_page(p)); | ||
725 | for_each_pbe(p, pagedir_nosave) | ||
726 | SetPageNosaveFree(virt_to_page(p->address)); | ||
723 | for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) { | 727 | for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) { |
724 | if (saveable(zone, &zone_pfn)) { | 728 | if (saveable(zone, &zone_pfn)) { |
725 | struct page * page; | 729 | struct page * page; |
726 | page = pfn_to_page(zone_pfn + zone->zone_start_pfn); | 730 | page = pfn_to_page(zone_pfn + zone->zone_start_pfn); |
727 | BUG_ON(!pbe); | 731 | BUG_ON(!pbe); |
728 | pbe->orig_address = (long) page_address(page); | 732 | pbe->orig_address = (unsigned long)page_address(page); |
729 | /* copy_page is not usable for copying task structs. */ | 733 | /* copy_page is not usable for copying task structs. */ |
730 | memcpy((void *)pbe->address, (void *)pbe->orig_address, PAGE_SIZE); | 734 | memcpy((void *)pbe->address, (void *)pbe->orig_address, PAGE_SIZE); |
731 | pbe = pbe->next; | 735 | pbe = pbe->next; |
@@ -737,15 +741,6 @@ static void copy_data_pages(void) | |||
737 | 741 | ||
738 | 742 | ||
739 | /** | 743 | /** |
740 | * calc_nr - Determine the number of pages needed for a pbe list. | ||
741 | */ | ||
742 | |||
743 | static int calc_nr(int nr_copy) | ||
744 | { | ||
745 | return nr_copy + (nr_copy+PBES_PER_PAGE-2)/(PBES_PER_PAGE-1); | ||
746 | } | ||
747 | |||
748 | /** | ||
749 | * free_pagedir - free pages allocated with alloc_pagedir() | 744 | * free_pagedir - free pages allocated with alloc_pagedir() |
750 | */ | 745 | */ |
751 | 746 | ||
@@ -755,6 +750,8 @@ static inline void free_pagedir(struct pbe *pblist) | |||
755 | 750 | ||
756 | while (pblist) { | 751 | while (pblist) { |
757 | pbe = (pblist + PB_PAGE_SKIP)->next; | 752 | pbe = (pblist + PB_PAGE_SKIP)->next; |
753 | ClearPageNosave(virt_to_page(pblist)); | ||
754 | ClearPageNosaveFree(virt_to_page(pblist)); | ||
758 | free_page((unsigned long)pblist); | 755 | free_page((unsigned long)pblist); |
759 | pblist = pbe; | 756 | pblist = pbe; |
760 | } | 757 | } |
@@ -800,6 +797,16 @@ static void create_pbe_list(struct pbe *pblist, unsigned nr_pages) | |||
800 | pr_debug("create_pbe_list(): initialized %d PBEs\n", num); | 797 | pr_debug("create_pbe_list(): initialized %d PBEs\n", num); |
801 | } | 798 | } |
802 | 799 | ||
800 | static void *alloc_image_page(void) | ||
801 | { | ||
802 | void *res = (void *)get_zeroed_page(GFP_ATOMIC | __GFP_COLD); | ||
803 | if (res) { | ||
804 | SetPageNosave(virt_to_page(res)); | ||
805 | SetPageNosaveFree(virt_to_page(res)); | ||
806 | } | ||
807 | return res; | ||
808 | } | ||
809 | |||
803 | /** | 810 | /** |
804 | * alloc_pagedir - Allocate the page directory. | 811 | * alloc_pagedir - Allocate the page directory. |
805 | * | 812 | * |
@@ -822,11 +829,11 @@ static struct pbe * alloc_pagedir(unsigned nr_pages) | |||
822 | return NULL; | 829 | return NULL; |
823 | 830 | ||
824 | pr_debug("alloc_pagedir(): nr_pages = %d\n", nr_pages); | 831 | pr_debug("alloc_pagedir(): nr_pages = %d\n", nr_pages); |
825 | pblist = (struct pbe *)get_zeroed_page(GFP_ATOMIC | __GFP_COLD); | 832 | pblist = (struct pbe *)alloc_image_page(); |
826 | for (pbe = pblist, num = PBES_PER_PAGE; pbe && num < nr_pages; | 833 | for (pbe = pblist, num = PBES_PER_PAGE; pbe && num < nr_pages; |
827 | pbe = pbe->next, num += PBES_PER_PAGE) { | 834 | pbe = pbe->next, num += PBES_PER_PAGE) { |
828 | pbe += PB_PAGE_SKIP; | 835 | pbe += PB_PAGE_SKIP; |
829 | pbe->next = (struct pbe *)get_zeroed_page(GFP_ATOMIC | __GFP_COLD); | 836 | pbe->next = (struct pbe *)alloc_image_page(); |
830 | } | 837 | } |
831 | if (!pbe) { /* get_zeroed_page() failed */ | 838 | if (!pbe) { /* get_zeroed_page() failed */ |
832 | free_pagedir(pblist); | 839 | free_pagedir(pblist); |
@@ -836,52 +843,30 @@ static struct pbe * alloc_pagedir(unsigned nr_pages) | |||
836 | } | 843 | } |
837 | 844 | ||
838 | /** | 845 | /** |
839 | * free_image_pages - Free pages allocated for snapshot | 846 | * Free pages we allocated for suspend. Suspend pages are alocated |
847 | * before atomic copy, so we need to free them after resume. | ||
840 | */ | 848 | */ |
841 | 849 | ||
842 | static void free_image_pages(void) | 850 | void swsusp_free(void) |
843 | { | 851 | { |
844 | struct pbe * p; | 852 | struct zone *zone; |
853 | unsigned long zone_pfn; | ||
845 | 854 | ||
846 | for_each_pbe (p, pagedir_save) { | 855 | for_each_zone(zone) { |
847 | if (p->address) { | 856 | for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) |
848 | ClearPageNosave(virt_to_page(p->address)); | 857 | if (pfn_valid(zone_pfn + zone->zone_start_pfn)) { |
849 | free_page(p->address); | 858 | struct page * page; |
850 | p->address = 0; | 859 | page = pfn_to_page(zone_pfn + zone->zone_start_pfn); |
851 | } | 860 | if (PageNosave(page) && PageNosaveFree(page)) { |
861 | ClearPageNosave(page); | ||
862 | ClearPageNosaveFree(page); | ||
863 | free_page((long) page_address(page)); | ||
864 | } | ||
865 | } | ||
852 | } | 866 | } |
853 | } | 867 | } |
854 | 868 | ||
855 | /** | 869 | /** |
856 | * alloc_image_pages - Allocate pages for the snapshot. | ||
857 | */ | ||
858 | |||
859 | static int alloc_image_pages(void) | ||
860 | { | ||
861 | struct pbe * p; | ||
862 | |||
863 | for_each_pbe (p, pagedir_save) { | ||
864 | p->address = get_zeroed_page(GFP_ATOMIC | __GFP_COLD); | ||
865 | if (!p->address) | ||
866 | return -ENOMEM; | ||
867 | SetPageNosave(virt_to_page(p->address)); | ||
868 | } | ||
869 | return 0; | ||
870 | } | ||
871 | |||
872 | /* Free pages we allocated for suspend. Suspend pages are alocated | ||
873 | * before atomic copy, so we need to free them after resume. | ||
874 | */ | ||
875 | void swsusp_free(void) | ||
876 | { | ||
877 | BUG_ON(PageNosave(virt_to_page(pagedir_save))); | ||
878 | BUG_ON(PageNosaveFree(virt_to_page(pagedir_save))); | ||
879 | free_image_pages(); | ||
880 | free_pagedir(pagedir_save); | ||
881 | } | ||
882 | |||
883 | |||
884 | /** | ||
885 | * enough_free_mem - Make sure we enough free memory to snapshot. | 870 | * enough_free_mem - Make sure we enough free memory to snapshot. |
886 | * | 871 | * |
887 | * Returns TRUE or FALSE after checking the number of available | 872 | * Returns TRUE or FALSE after checking the number of available |
@@ -890,12 +875,9 @@ void swsusp_free(void) | |||
890 | 875 | ||
891 | static int enough_free_mem(void) | 876 | static int enough_free_mem(void) |
892 | { | 877 | { |
893 | if (nr_free_pages() < (nr_copy_pages + PAGES_FOR_IO)) { | 878 | pr_debug("swsusp: available memory: %u pages\n", nr_free_pages()); |
894 | pr_debug("swsusp: Not enough free pages: Have %d\n", | 879 | return nr_free_pages() > (nr_copy_pages + PAGES_FOR_IO + |
895 | nr_free_pages()); | 880 | nr_copy_pages/PBES_PER_PAGE + !!(nr_copy_pages%PBES_PER_PAGE)); |
896 | return 0; | ||
897 | } | ||
898 | return 1; | ||
899 | } | 881 | } |
900 | 882 | ||
901 | 883 | ||
@@ -914,33 +896,16 @@ static int enough_swap(void) | |||
914 | struct sysinfo i; | 896 | struct sysinfo i; |
915 | 897 | ||
916 | si_swapinfo(&i); | 898 | si_swapinfo(&i); |
917 | if (i.freeswap < (nr_copy_pages + PAGES_FOR_IO)) { | 899 | pr_debug("swsusp: available swap: %lu pages\n", i.freeswap); |
918 | pr_debug("swsusp: Not enough swap. Need %ld\n",i.freeswap); | 900 | return i.freeswap > (nr_copy_pages + PAGES_FOR_IO + |
919 | return 0; | 901 | nr_copy_pages/PBES_PER_PAGE + !!(nr_copy_pages%PBES_PER_PAGE)); |
920 | } | ||
921 | return 1; | ||
922 | } | 902 | } |
923 | 903 | ||
924 | static int swsusp_alloc(void) | 904 | static int swsusp_alloc(void) |
925 | { | 905 | { |
926 | int error; | 906 | struct pbe * p; |
927 | 907 | ||
928 | pagedir_nosave = NULL; | 908 | pagedir_nosave = NULL; |
929 | nr_copy_pages = calc_nr(nr_copy_pages); | ||
930 | nr_copy_pages_check = nr_copy_pages; | ||
931 | |||
932 | pr_debug("suspend: (pages needed: %d + %d free: %d)\n", | ||
933 | nr_copy_pages, PAGES_FOR_IO, nr_free_pages()); | ||
934 | |||
935 | if (!enough_free_mem()) | ||
936 | return -ENOMEM; | ||
937 | |||
938 | if (!enough_swap()) | ||
939 | return -ENOSPC; | ||
940 | |||
941 | if (MAX_PBES < nr_copy_pages / PBES_PER_PAGE + | ||
942 | !!(nr_copy_pages % PBES_PER_PAGE)) | ||
943 | return -ENOSPC; | ||
944 | 909 | ||
945 | if (!(pagedir_save = alloc_pagedir(nr_copy_pages))) { | 910 | if (!(pagedir_save = alloc_pagedir(nr_copy_pages))) { |
946 | printk(KERN_ERR "suspend: Allocating pagedir failed.\n"); | 911 | printk(KERN_ERR "suspend: Allocating pagedir failed.\n"); |
@@ -948,10 +913,14 @@ static int swsusp_alloc(void) | |||
948 | } | 913 | } |
949 | create_pbe_list(pagedir_save, nr_copy_pages); | 914 | create_pbe_list(pagedir_save, nr_copy_pages); |
950 | pagedir_nosave = pagedir_save; | 915 | pagedir_nosave = pagedir_save; |
951 | if ((error = alloc_image_pages())) { | 916 | |
952 | printk(KERN_ERR "suspend: Allocating image pages failed.\n"); | 917 | for_each_pbe (p, pagedir_save) { |
953 | swsusp_free(); | 918 | p->address = (unsigned long)alloc_image_page(); |
954 | return error; | 919 | if (!p->address) { |
920 | printk(KERN_ERR "suspend: Allocating image pages failed.\n"); | ||
921 | swsusp_free(); | ||
922 | return -ENOMEM; | ||
923 | } | ||
955 | } | 924 | } |
956 | 925 | ||
957 | return 0; | 926 | return 0; |
@@ -963,7 +932,7 @@ static int suspend_prepare_image(void) | |||
963 | 932 | ||
964 | pr_debug("swsusp: critical section: \n"); | 933 | pr_debug("swsusp: critical section: \n"); |
965 | if (save_highmem()) { | 934 | if (save_highmem()) { |
966 | printk(KERN_CRIT "Suspend machine: Not enough free pages for highmem\n"); | 935 | printk(KERN_CRIT "swsusp: Not enough free pages for highmem\n"); |
967 | restore_highmem(); | 936 | restore_highmem(); |
968 | return -ENOMEM; | 937 | return -ENOMEM; |
969 | } | 938 | } |
@@ -971,6 +940,28 @@ static int suspend_prepare_image(void) | |||
971 | drain_local_pages(); | 940 | drain_local_pages(); |
972 | count_data_pages(); | 941 | count_data_pages(); |
973 | printk("swsusp: Need to copy %u pages\n", nr_copy_pages); | 942 | printk("swsusp: Need to copy %u pages\n", nr_copy_pages); |
943 | nr_copy_pages_check = nr_copy_pages; | ||
944 | |||
945 | pr_debug("swsusp: pages needed: %u + %lu + %u, free: %u\n", | ||
946 | nr_copy_pages, | ||
947 | nr_copy_pages/PBES_PER_PAGE + !!(nr_copy_pages%PBES_PER_PAGE), | ||
948 | PAGES_FOR_IO, nr_free_pages()); | ||
949 | |||
950 | if (!enough_free_mem()) { | ||
951 | printk(KERN_ERR "swsusp: Not enough free memory\n"); | ||
952 | return -ENOMEM; | ||
953 | } | ||
954 | |||
955 | if (MAX_PBES < nr_copy_pages / PBES_PER_PAGE + | ||
956 | !!(nr_copy_pages % PBES_PER_PAGE)) { | ||
957 | printk(KERN_ERR "swsusp: Too many image pages\n"); | ||
958 | return -ENOSPC; | ||
959 | } | ||
960 | |||
961 | if (!enough_swap()) { | ||
962 | printk(KERN_ERR "swsusp: Not enough free swap\n"); | ||
963 | return -ENOSPC; | ||
964 | } | ||
974 | 965 | ||
975 | error = swsusp_alloc(); | 966 | error = swsusp_alloc(); |
976 | if (error) | 967 | if (error) |