diff options
| -rw-r--r-- | include/linux/suspend.h | 9 | ||||
| -rw-r--r-- | kernel/power/power.h | 11 | ||||
| -rw-r--r-- | kernel/power/snapshot.c | 416 | ||||
| -rw-r--r-- | kernel/power/swap.c | 4 | ||||
| -rw-r--r-- | kernel/power/user.c | 1 |
5 files changed, 186 insertions, 255 deletions
diff --git a/include/linux/suspend.h b/include/linux/suspend.h index c11cacf1a13b..b1237f16ecde 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h | |||
| @@ -16,15 +16,6 @@ struct pbe { | |||
| 16 | struct pbe *next; | 16 | struct pbe *next; |
| 17 | }; | 17 | }; |
| 18 | 18 | ||
| 19 | #define for_each_pbe(pbe, pblist) \ | ||
| 20 | for (pbe = pblist ; pbe ; pbe = pbe->next) | ||
| 21 | |||
| 22 | #define PBES_PER_PAGE (PAGE_SIZE/sizeof(struct pbe)) | ||
| 23 | #define PB_PAGE_SKIP (PBES_PER_PAGE-1) | ||
| 24 | |||
| 25 | #define for_each_pb_page(pbe, pblist) \ | ||
| 26 | for (pbe = pblist ; pbe ; pbe = (pbe+PB_PAGE_SKIP)->next) | ||
| 27 | |||
| 28 | /* mm/page_alloc.c */ | 19 | /* mm/page_alloc.c */ |
| 29 | extern void drain_local_pages(void); | 20 | extern void drain_local_pages(void); |
| 30 | extern void mark_free_pages(struct zone *zone); | 21 | extern void mark_free_pages(struct zone *zone); |
diff --git a/kernel/power/power.h b/kernel/power/power.h index 6e9e2acc34f8..bfe999f7b272 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h | |||
| @@ -81,16 +81,6 @@ struct snapshot_handle { | |||
| 81 | unsigned int prev; /* number of the block of PAGE_SIZE bytes that | 81 | unsigned int prev; /* number of the block of PAGE_SIZE bytes that |
| 82 | * was the current one previously | 82 | * was the current one previously |
| 83 | */ | 83 | */ |
| 84 | struct pbe *pbe; /* PBE that corresponds to 'buffer' */ | ||
| 85 | struct pbe *last_pbe; /* When the image is restored (eg. read | ||
| 86 | * from disk) we can store some image | ||
| 87 | * data directly in the page frames | ||
| 88 | * in which they were before suspend. | ||
| 89 | * In such a case the PBEs that | ||
| 90 | * correspond to them will be unused. | ||
| 91 | * This is the last PBE, so far, that | ||
| 92 | * does not correspond to such data. | ||
| 93 | */ | ||
| 94 | void *buffer; /* address of the block to read from | 84 | void *buffer; /* address of the block to read from |
| 95 | * or write to | 85 | * or write to |
| 96 | */ | 86 | */ |
| @@ -113,6 +103,7 @@ extern unsigned int snapshot_additional_pages(struct zone *zone); | |||
| 113 | extern int snapshot_read_next(struct snapshot_handle *handle, size_t count); | 103 | extern int snapshot_read_next(struct snapshot_handle *handle, size_t count); |
| 114 | extern int snapshot_write_next(struct snapshot_handle *handle, size_t count); | 104 | extern int snapshot_write_next(struct snapshot_handle *handle, size_t count); |
| 115 | extern int snapshot_image_loaded(struct snapshot_handle *handle); | 105 | extern int snapshot_image_loaded(struct snapshot_handle *handle); |
| 106 | extern void snapshot_free_unused_memory(struct snapshot_handle *handle); | ||
| 116 | 107 | ||
| 117 | #define SNAPSHOT_IOC_MAGIC '3' | 108 | #define SNAPSHOT_IOC_MAGIC '3' |
| 118 | #define SNAPSHOT_FREEZE _IO(SNAPSHOT_IOC_MAGIC, 1) | 109 | #define SNAPSHOT_FREEZE _IO(SNAPSHOT_IOC_MAGIC, 1) |
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 852e0df41719..1b84313cbab5 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c | |||
| @@ -39,7 +39,7 @@ struct pbe *restore_pblist; | |||
| 39 | 39 | ||
| 40 | static unsigned int nr_copy_pages; | 40 | static unsigned int nr_copy_pages; |
| 41 | static unsigned int nr_meta_pages; | 41 | static unsigned int nr_meta_pages; |
| 42 | static unsigned long *buffer; | 42 | static void *buffer; |
| 43 | 43 | ||
| 44 | #ifdef CONFIG_HIGHMEM | 44 | #ifdef CONFIG_HIGHMEM |
| 45 | unsigned int count_highmem_pages(void) | 45 | unsigned int count_highmem_pages(void) |
| @@ -172,7 +172,7 @@ static inline int restore_highmem(void) {return 0;} | |||
| 172 | #define PG_UNSAFE_CLEAR 1 | 172 | #define PG_UNSAFE_CLEAR 1 |
| 173 | #define PG_UNSAFE_KEEP 0 | 173 | #define PG_UNSAFE_KEEP 0 |
| 174 | 174 | ||
| 175 | static unsigned int unsafe_pages; | 175 | static unsigned int allocated_unsafe_pages; |
| 176 | 176 | ||
| 177 | static void *alloc_image_page(gfp_t gfp_mask, int safe_needed) | 177 | static void *alloc_image_page(gfp_t gfp_mask, int safe_needed) |
| 178 | { | 178 | { |
| @@ -183,7 +183,7 @@ static void *alloc_image_page(gfp_t gfp_mask, int safe_needed) | |||
| 183 | while (res && PageNosaveFree(virt_to_page(res))) { | 183 | while (res && PageNosaveFree(virt_to_page(res))) { |
| 184 | /* The page is unsafe, mark it for swsusp_free() */ | 184 | /* The page is unsafe, mark it for swsusp_free() */ |
| 185 | SetPageNosave(virt_to_page(res)); | 185 | SetPageNosave(virt_to_page(res)); |
| 186 | unsafe_pages++; | 186 | allocated_unsafe_pages++; |
| 187 | res = (void *)get_zeroed_page(gfp_mask); | 187 | res = (void *)get_zeroed_page(gfp_mask); |
| 188 | } | 188 | } |
| 189 | if (res) { | 189 | if (res) { |
| @@ -772,101 +772,10 @@ copy_data_pages(struct memory_bitmap *copy_bm, struct memory_bitmap *orig_bm) | |||
| 772 | } | 772 | } |
| 773 | 773 | ||
| 774 | /** | 774 | /** |
| 775 | * free_pagedir - free pages allocated with alloc_pagedir() | 775 | * swsusp_free - free pages allocated for the suspend. |
| 776 | */ | ||
| 777 | |||
| 778 | static void free_pagedir(struct pbe *pblist, int clear_nosave_free) | ||
| 779 | { | ||
| 780 | struct pbe *pbe; | ||
| 781 | |||
| 782 | while (pblist) { | ||
| 783 | pbe = (pblist + PB_PAGE_SKIP)->next; | ||
| 784 | free_image_page(pblist, clear_nosave_free); | ||
| 785 | pblist = pbe; | ||
| 786 | } | ||
| 787 | } | ||
| 788 | |||
| 789 | /** | ||
| 790 | * fill_pb_page - Create a list of PBEs on a given memory page | ||
| 791 | */ | ||
| 792 | |||
| 793 | static inline void fill_pb_page(struct pbe *pbpage, unsigned int n) | ||
| 794 | { | ||
| 795 | struct pbe *p; | ||
| 796 | |||
| 797 | p = pbpage; | ||
| 798 | pbpage += n - 1; | ||
| 799 | do | ||
| 800 | p->next = p + 1; | ||
| 801 | while (++p < pbpage); | ||
| 802 | } | ||
| 803 | |||
| 804 | /** | ||
| 805 | * create_pbe_list - Create a list of PBEs on top of a given chain | ||
| 806 | * of memory pages allocated with alloc_pagedir() | ||
| 807 | * | 776 | * |
| 808 | * This function assumes that pages allocated by alloc_image_page() will | 777 | * Suspend pages are alocated before the atomic copy is made, so we |
| 809 | * always be zeroed. | 778 | * need to release them after the resume. |
| 810 | */ | ||
| 811 | |||
| 812 | static inline void create_pbe_list(struct pbe *pblist, unsigned int nr_pages) | ||
| 813 | { | ||
| 814 | struct pbe *pbpage; | ||
| 815 | unsigned int num = PBES_PER_PAGE; | ||
| 816 | |||
| 817 | for_each_pb_page (pbpage, pblist) { | ||
| 818 | if (num >= nr_pages) | ||
| 819 | break; | ||
| 820 | |||
| 821 | fill_pb_page(pbpage, PBES_PER_PAGE); | ||
| 822 | num += PBES_PER_PAGE; | ||
| 823 | } | ||
| 824 | if (pbpage) { | ||
| 825 | num -= PBES_PER_PAGE; | ||
| 826 | fill_pb_page(pbpage, nr_pages - num); | ||
| 827 | } | ||
| 828 | } | ||
| 829 | |||
| 830 | /** | ||
| 831 | * alloc_pagedir - Allocate the page directory. | ||
| 832 | * | ||
| 833 | * First, determine exactly how many pages we need and | ||
| 834 | * allocate them. | ||
| 835 | * | ||
| 836 | * We arrange the pages in a chain: each page is an array of PBES_PER_PAGE | ||
| 837 | * struct pbe elements (pbes) and the last element in the page points | ||
| 838 | * to the next page. | ||
| 839 | * | ||
| 840 | * On each page we set up a list of struct_pbe elements. | ||
| 841 | */ | ||
| 842 | |||
| 843 | static struct pbe *alloc_pagedir(unsigned int nr_pages, gfp_t gfp_mask, | ||
| 844 | int safe_needed) | ||
| 845 | { | ||
| 846 | unsigned int num; | ||
| 847 | struct pbe *pblist, *pbe; | ||
| 848 | |||
| 849 | if (!nr_pages) | ||
| 850 | return NULL; | ||
| 851 | |||
| 852 | pblist = alloc_image_page(gfp_mask, safe_needed); | ||
| 853 | pbe = pblist; | ||
| 854 | for (num = PBES_PER_PAGE; num < nr_pages; num += PBES_PER_PAGE) { | ||
| 855 | if (!pbe) { | ||
| 856 | free_pagedir(pblist, PG_UNSAFE_CLEAR); | ||
| 857 | return NULL; | ||
| 858 | } | ||
| 859 | pbe += PB_PAGE_SKIP; | ||
| 860 | pbe->next = alloc_image_page(gfp_mask, safe_needed); | ||
| 861 | pbe = pbe->next; | ||
| 862 | } | ||
| 863 | create_pbe_list(pblist, nr_pages); | ||
| 864 | return pblist; | ||
| 865 | } | ||
| 866 | |||
| 867 | /** | ||
| 868 | * Free pages we allocated for suspend. Suspend pages are alocated | ||
| 869 | * before atomic copy, so we need to free them after resume. | ||
| 870 | */ | 779 | */ |
| 871 | 780 | ||
| 872 | void swsusp_free(void) | 781 | void swsusp_free(void) |
| @@ -904,14 +813,18 @@ void swsusp_free(void) | |||
| 904 | static int enough_free_mem(unsigned int nr_pages) | 813 | static int enough_free_mem(unsigned int nr_pages) |
| 905 | { | 814 | { |
| 906 | struct zone *zone; | 815 | struct zone *zone; |
| 907 | unsigned int n = 0; | 816 | unsigned int free = 0, meta = 0; |
| 908 | 817 | ||
| 909 | for_each_zone (zone) | 818 | for_each_zone (zone) |
| 910 | if (!is_highmem(zone)) | 819 | if (!is_highmem(zone)) { |
| 911 | n += zone->free_pages; | 820 | free += zone->free_pages; |
| 912 | pr_debug("swsusp: available memory: %u pages\n", n); | 821 | meta += snapshot_additional_pages(zone); |
| 913 | return n > (nr_pages + PAGES_FOR_IO + | 822 | } |
| 914 | (nr_pages + PBES_PER_PAGE - 1) / PBES_PER_PAGE); | 823 | |
| 824 | pr_debug("swsusp: pages needed: %u + %u + %u, available pages: %u\n", | ||
| 825 | nr_pages, PAGES_FOR_IO, meta, free); | ||
| 826 | |||
| 827 | return free > nr_pages + PAGES_FOR_IO + meta; | ||
| 915 | } | 828 | } |
| 916 | 829 | ||
| 917 | static int | 830 | static int |
| @@ -961,11 +874,6 @@ asmlinkage int swsusp_save(void) | |||
| 961 | nr_pages = count_data_pages(); | 874 | nr_pages = count_data_pages(); |
| 962 | printk("swsusp: Need to copy %u pages\n", nr_pages); | 875 | printk("swsusp: Need to copy %u pages\n", nr_pages); |
| 963 | 876 | ||
| 964 | pr_debug("swsusp: pages needed: %u + %lu + %u, free: %u\n", | ||
| 965 | nr_pages, | ||
| 966 | (nr_pages + PBES_PER_PAGE - 1) / PBES_PER_PAGE, | ||
| 967 | PAGES_FOR_IO, nr_free_pages()); | ||
| 968 | |||
| 969 | if (!enough_free_mem(nr_pages)) { | 877 | if (!enough_free_mem(nr_pages)) { |
| 970 | printk(KERN_ERR "swsusp: Not enough free memory\n"); | 878 | printk(KERN_ERR "swsusp: Not enough free memory\n"); |
| 971 | return -ENOMEM; | 879 | return -ENOMEM; |
| @@ -1007,22 +915,19 @@ static void init_header(struct swsusp_info *info) | |||
| 1007 | } | 915 | } |
| 1008 | 916 | ||
| 1009 | /** | 917 | /** |
| 1010 | * pack_addresses - the addresses corresponding to pfns found in the | 918 | * pack_pfns - pfns corresponding to the set bits found in the bitmap @bm |
| 1011 | * bitmap @bm are stored in the array @buf[] (1 page) | 919 | * are stored in the array @buf[] (1 page at a time) |
| 1012 | */ | 920 | */ |
| 1013 | 921 | ||
| 1014 | static inline void | 922 | static inline void |
| 1015 | pack_addresses(unsigned long *buf, struct memory_bitmap *bm) | 923 | pack_pfns(unsigned long *buf, struct memory_bitmap *bm) |
| 1016 | { | 924 | { |
| 1017 | int j; | 925 | int j; |
| 1018 | 926 | ||
| 1019 | for (j = 0; j < PAGE_SIZE / sizeof(long); j++) { | 927 | for (j = 0; j < PAGE_SIZE / sizeof(long); j++) { |
| 1020 | unsigned long pfn = memory_bm_next_pfn(bm); | 928 | buf[j] = memory_bm_next_pfn(bm); |
| 1021 | 929 | if (unlikely(buf[j] == BM_END_OF_MAP)) | |
| 1022 | if (unlikely(pfn == BM_END_OF_MAP)) | ||
| 1023 | break; | 930 | break; |
| 1024 | |||
| 1025 | buf[j] = (unsigned long)page_address(pfn_to_page(pfn)); | ||
| 1026 | } | 931 | } |
| 1027 | } | 932 | } |
| 1028 | 933 | ||
| @@ -1068,7 +973,7 @@ int snapshot_read_next(struct snapshot_handle *handle, size_t count) | |||
| 1068 | if (handle->prev < handle->cur) { | 973 | if (handle->prev < handle->cur) { |
| 1069 | if (handle->cur <= nr_meta_pages) { | 974 | if (handle->cur <= nr_meta_pages) { |
| 1070 | memset(buffer, 0, PAGE_SIZE); | 975 | memset(buffer, 0, PAGE_SIZE); |
| 1071 | pack_addresses(buffer, &orig_bm); | 976 | pack_pfns(buffer, &orig_bm); |
| 1072 | } else { | 977 | } else { |
| 1073 | unsigned long pfn = memory_bm_next_pfn(©_bm); | 978 | unsigned long pfn = memory_bm_next_pfn(©_bm); |
| 1074 | 979 | ||
| @@ -1094,14 +999,10 @@ int snapshot_read_next(struct snapshot_handle *handle, size_t count) | |||
| 1094 | * had been used before suspend | 999 | * had been used before suspend |
| 1095 | */ | 1000 | */ |
| 1096 | 1001 | ||
| 1097 | static int mark_unsafe_pages(struct pbe *pblist) | 1002 | static int mark_unsafe_pages(struct memory_bitmap *bm) |
| 1098 | { | 1003 | { |
| 1099 | struct zone *zone; | 1004 | struct zone *zone; |
| 1100 | unsigned long pfn, max_zone_pfn; | 1005 | unsigned long pfn, max_zone_pfn; |
| 1101 | struct pbe *p; | ||
| 1102 | |||
| 1103 | if (!pblist) /* a sanity check */ | ||
| 1104 | return -EINVAL; | ||
| 1105 | 1006 | ||
| 1106 | /* Clear page flags */ | 1007 | /* Clear page flags */ |
| 1107 | for_each_zone (zone) { | 1008 | for_each_zone (zone) { |
| @@ -1111,30 +1012,37 @@ static int mark_unsafe_pages(struct pbe *pblist) | |||
| 1111 | ClearPageNosaveFree(pfn_to_page(pfn)); | 1012 | ClearPageNosaveFree(pfn_to_page(pfn)); |
| 1112 | } | 1013 | } |
| 1113 | 1014 | ||
| 1114 | /* Mark orig addresses */ | 1015 | /* Mark pages that correspond to the "original" pfns as "unsafe" */ |
| 1115 | for_each_pbe (p, pblist) { | 1016 | memory_bm_position_reset(bm); |
| 1116 | if (virt_addr_valid(p->orig_address)) | 1017 | do { |
| 1117 | SetPageNosaveFree(virt_to_page(p->orig_address)); | 1018 | pfn = memory_bm_next_pfn(bm); |
| 1118 | else | 1019 | if (likely(pfn != BM_END_OF_MAP)) { |
| 1119 | return -EFAULT; | 1020 | if (likely(pfn_valid(pfn))) |
| 1120 | } | 1021 | SetPageNosaveFree(pfn_to_page(pfn)); |
| 1022 | else | ||
| 1023 | return -EFAULT; | ||
| 1024 | } | ||
| 1025 | } while (pfn != BM_END_OF_MAP); | ||
| 1121 | 1026 | ||
| 1122 | unsafe_pages = 0; | 1027 | allocated_unsafe_pages = 0; |
| 1123 | 1028 | ||
| 1124 | return 0; | 1029 | return 0; |
| 1125 | } | 1030 | } |
| 1126 | 1031 | ||
| 1127 | static void copy_page_backup_list(struct pbe *dst, struct pbe *src) | 1032 | static void |
| 1033 | duplicate_memory_bitmap(struct memory_bitmap *dst, struct memory_bitmap *src) | ||
| 1128 | { | 1034 | { |
| 1129 | /* We assume both lists contain the same number of elements */ | 1035 | unsigned long pfn; |
| 1130 | while (src) { | 1036 | |
| 1131 | dst->orig_address = src->orig_address; | 1037 | memory_bm_position_reset(src); |
| 1132 | dst = dst->next; | 1038 | pfn = memory_bm_next_pfn(src); |
| 1133 | src = src->next; | 1039 | while (pfn != BM_END_OF_MAP) { |
| 1040 | memory_bm_set_bit(dst, pfn); | ||
| 1041 | pfn = memory_bm_next_pfn(src); | ||
| 1134 | } | 1042 | } |
| 1135 | } | 1043 | } |
| 1136 | 1044 | ||
| 1137 | static int check_header(struct swsusp_info *info) | 1045 | static inline int check_header(struct swsusp_info *info) |
| 1138 | { | 1046 | { |
| 1139 | char *reason = NULL; | 1047 | char *reason = NULL; |
| 1140 | 1048 | ||
| @@ -1161,19 +1069,14 @@ static int check_header(struct swsusp_info *info) | |||
| 1161 | * load header - check the image header and copy data from it | 1069 | * load header - check the image header and copy data from it |
| 1162 | */ | 1070 | */ |
| 1163 | 1071 | ||
| 1164 | static int load_header(struct snapshot_handle *handle, | 1072 | static int |
| 1165 | struct swsusp_info *info) | 1073 | load_header(struct swsusp_info *info) |
| 1166 | { | 1074 | { |
| 1167 | int error; | 1075 | int error; |
| 1168 | struct pbe *pblist; | ||
| 1169 | 1076 | ||
| 1077 | restore_pblist = NULL; | ||
| 1170 | error = check_header(info); | 1078 | error = check_header(info); |
| 1171 | if (!error) { | 1079 | if (!error) { |
| 1172 | pblist = alloc_pagedir(info->image_pages, GFP_ATOMIC, PG_ANY); | ||
| 1173 | if (!pblist) | ||
| 1174 | return -ENOMEM; | ||
| 1175 | restore_pblist = pblist; | ||
| 1176 | handle->pbe = pblist; | ||
| 1177 | nr_copy_pages = info->image_pages; | 1080 | nr_copy_pages = info->image_pages; |
| 1178 | nr_meta_pages = info->pages - info->image_pages - 1; | 1081 | nr_meta_pages = info->pages - info->image_pages - 1; |
| 1179 | } | 1082 | } |
| @@ -1181,108 +1084,137 @@ static int load_header(struct snapshot_handle *handle, | |||
| 1181 | } | 1084 | } |
| 1182 | 1085 | ||
| 1183 | /** | 1086 | /** |
| 1184 | * unpack_orig_addresses - copy the elements of @buf[] (1 page) to | 1087 | * unpack_orig_pfns - for each element of @buf[] (1 page at a time) set |
| 1185 | * the PBEs in the list starting at @pbe | 1088 | * the corresponding bit in the memory bitmap @bm |
| 1186 | */ | 1089 | */ |
| 1187 | 1090 | ||
| 1188 | static inline struct pbe *unpack_orig_addresses(unsigned long *buf, | 1091 | static inline void |
| 1189 | struct pbe *pbe) | 1092 | unpack_orig_pfns(unsigned long *buf, struct memory_bitmap *bm) |
| 1190 | { | 1093 | { |
| 1191 | int j; | 1094 | int j; |
| 1192 | 1095 | ||
| 1193 | for (j = 0; j < PAGE_SIZE / sizeof(long) && pbe; j++) { | 1096 | for (j = 0; j < PAGE_SIZE / sizeof(long); j++) { |
| 1194 | pbe->orig_address = buf[j]; | 1097 | if (unlikely(buf[j] == BM_END_OF_MAP)) |
| 1195 | pbe = pbe->next; | 1098 | break; |
| 1099 | |||
| 1100 | memory_bm_set_bit(bm, buf[j]); | ||
| 1196 | } | 1101 | } |
| 1197 | return pbe; | ||
| 1198 | } | 1102 | } |
| 1199 | 1103 | ||
| 1200 | /** | 1104 | /** |
| 1201 | * prepare_image - use metadata contained in the PBE list | 1105 | * prepare_image - use the memory bitmap @bm to mark the pages that will |
| 1202 | * pointed to by restore_pblist to mark the pages that will | 1106 | * be overwritten in the process of restoring the system memory state |
| 1203 | * be overwritten in the process of restoring the system | 1107 | * from the suspend image ("unsafe" pages) and allocate memory for the |
| 1204 | * memory state from the image ("unsafe" pages) and allocate | 1108 | * image. |
| 1205 | * memory for the image | ||
| 1206 | * | 1109 | * |
| 1207 | * The idea is to allocate the PBE list first and then | 1110 | * The idea is to allocate a new memory bitmap first and then allocate |
| 1208 | * allocate as many pages as it's needed for the image data, | 1111 | * as many pages as needed for the image data, but not to assign these |
| 1209 | * but not to assign these pages to the PBEs initially. | 1112 | * pages to specific tasks initially. Instead, we just mark them as |
| 1210 | * Instead, we just mark them as allocated and create a list | 1113 | * allocated and create a list of "safe" pages that will be used later. |
| 1211 | * of "safe" which will be used later | ||
| 1212 | */ | 1114 | */ |
| 1213 | 1115 | ||
| 1214 | static struct linked_page *safe_pages; | 1116 | #define PBES_PER_LINKED_PAGE (LINKED_PAGE_DATA_SIZE / sizeof(struct pbe)) |
| 1117 | |||
| 1118 | static struct linked_page *safe_pages_list; | ||
| 1215 | 1119 | ||
| 1216 | static int prepare_image(struct snapshot_handle *handle) | 1120 | static int |
| 1121 | prepare_image(struct memory_bitmap *new_bm, struct memory_bitmap *bm) | ||
| 1217 | { | 1122 | { |
| 1218 | int error = 0; | 1123 | unsigned int nr_pages; |
| 1219 | unsigned int nr_pages = nr_copy_pages; | 1124 | struct linked_page *sp_list, *lp; |
| 1220 | struct pbe *p, *pblist = NULL; | 1125 | int error; |
| 1221 | 1126 | ||
| 1222 | p = restore_pblist; | 1127 | error = mark_unsafe_pages(bm); |
| 1223 | error = mark_unsafe_pages(p); | 1128 | if (error) |
| 1224 | if (!error) { | 1129 | goto Free; |
| 1225 | pblist = alloc_pagedir(nr_pages, GFP_ATOMIC, PG_SAFE); | 1130 | |
| 1226 | if (pblist) | 1131 | error = memory_bm_create(new_bm, GFP_ATOMIC, PG_SAFE); |
| 1227 | copy_page_backup_list(pblist, p); | 1132 | if (error) |
| 1228 | free_pagedir(p, PG_UNSAFE_KEEP); | 1133 | goto Free; |
| 1229 | if (!pblist) | 1134 | |
| 1135 | duplicate_memory_bitmap(new_bm, bm); | ||
| 1136 | memory_bm_free(bm, PG_UNSAFE_KEEP); | ||
| 1137 | /* Reserve some safe pages for potential later use. | ||
| 1138 | * | ||
| 1139 | * NOTE: This way we make sure there will be enough safe pages for the | ||
| 1140 | * chain_alloc() in get_buffer(). It is a bit wasteful, but | ||
| 1141 | * nr_copy_pages cannot be greater than 50% of the memory anyway. | ||
| 1142 | */ | ||
| 1143 | sp_list = NULL; | ||
| 1144 | /* nr_copy_pages cannot be lesser than allocated_unsafe_pages */ | ||
| 1145 | nr_pages = nr_copy_pages - allocated_unsafe_pages; | ||
| 1146 | nr_pages = DIV_ROUND_UP(nr_pages, PBES_PER_LINKED_PAGE); | ||
| 1147 | while (nr_pages > 0) { | ||
| 1148 | lp = alloc_image_page(GFP_ATOMIC, PG_SAFE); | ||
| 1149 | if (!lp) { | ||
| 1230 | error = -ENOMEM; | 1150 | error = -ENOMEM; |
| 1151 | goto Free; | ||
| 1152 | } | ||
| 1153 | lp->next = sp_list; | ||
| 1154 | sp_list = lp; | ||
| 1155 | nr_pages--; | ||
| 1231 | } | 1156 | } |
| 1232 | safe_pages = NULL; | 1157 | /* Preallocate memory for the image */ |
| 1233 | if (!error && nr_pages > unsafe_pages) { | 1158 | safe_pages_list = NULL; |
| 1234 | nr_pages -= unsafe_pages; | 1159 | nr_pages = nr_copy_pages - allocated_unsafe_pages; |
| 1235 | while (nr_pages--) { | 1160 | while (nr_pages > 0) { |
| 1236 | struct linked_page *ptr; | 1161 | lp = (struct linked_page *)get_zeroed_page(GFP_ATOMIC); |
| 1237 | 1162 | if (!lp) { | |
| 1238 | ptr = (void *)get_zeroed_page(GFP_ATOMIC); | 1163 | error = -ENOMEM; |
| 1239 | if (!ptr) { | 1164 | goto Free; |
| 1240 | error = -ENOMEM; | 1165 | } |
| 1241 | break; | 1166 | if (!PageNosaveFree(virt_to_page(lp))) { |
| 1242 | } | 1167 | /* The page is "safe", add it to the list */ |
| 1243 | if (!PageNosaveFree(virt_to_page(ptr))) { | 1168 | lp->next = safe_pages_list; |
| 1244 | /* The page is "safe", add it to the list */ | 1169 | safe_pages_list = lp; |
| 1245 | ptr->next = safe_pages; | ||
| 1246 | safe_pages = ptr; | ||
| 1247 | } | ||
| 1248 | /* Mark the page as allocated */ | ||
| 1249 | SetPageNosave(virt_to_page(ptr)); | ||
| 1250 | SetPageNosaveFree(virt_to_page(ptr)); | ||
| 1251 | } | 1170 | } |
| 1171 | /* Mark the page as allocated */ | ||
| 1172 | SetPageNosave(virt_to_page(lp)); | ||
| 1173 | SetPageNosaveFree(virt_to_page(lp)); | ||
| 1174 | nr_pages--; | ||
| 1252 | } | 1175 | } |
| 1253 | if (!error) { | 1176 | /* Free the reserved safe pages so that chain_alloc() can use them */ |
| 1254 | restore_pblist = pblist; | 1177 | while (sp_list) { |
| 1255 | } else { | 1178 | lp = sp_list->next; |
| 1256 | handle->pbe = NULL; | 1179 | free_image_page(sp_list, PG_UNSAFE_CLEAR); |
| 1257 | swsusp_free(); | 1180 | sp_list = lp; |
| 1258 | } | 1181 | } |
| 1182 | return 0; | ||
| 1183 | |||
| 1184 | Free: | ||
| 1185 | swsusp_free(); | ||
| 1259 | return error; | 1186 | return error; |
| 1260 | } | 1187 | } |
| 1261 | 1188 | ||
| 1262 | static void *get_buffer(struct snapshot_handle *handle) | 1189 | /** |
| 1190 | * get_buffer - compute the address that snapshot_write_next() should | ||
| 1191 | * set for its caller to write to. | ||
| 1192 | */ | ||
| 1193 | |||
| 1194 | static void *get_buffer(struct memory_bitmap *bm, struct chain_allocator *ca) | ||
| 1263 | { | 1195 | { |
| 1264 | struct pbe *pbe = handle->pbe, *last = handle->last_pbe; | 1196 | struct pbe *pbe; |
| 1265 | struct page *page = virt_to_page(pbe->orig_address); | 1197 | struct page *page = pfn_to_page(memory_bm_next_pfn(bm)); |
| 1266 | 1198 | ||
| 1267 | if (PageNosave(page) && PageNosaveFree(page)) { | 1199 | if (PageNosave(page) && PageNosaveFree(page)) |
| 1268 | /* | 1200 | /* We have allocated the "original" page frame and we can |
| 1269 | * We have allocated the "original" page frame and we can | 1201 | * use it directly to store the loaded page. |
| 1270 | * use it directly to store the read page | ||
| 1271 | */ | 1202 | */ |
| 1272 | pbe->address = 0; | 1203 | return page_address(page); |
| 1273 | if (last && last->next) | 1204 | |
| 1274 | last->next = NULL; | 1205 | /* The "original" page frame has not been allocated and we have to |
| 1275 | return (void *)pbe->orig_address; | 1206 | * use a "safe" page frame to store the loaded page. |
| 1276 | } | ||
| 1277 | /* | ||
| 1278 | * The "original" page frame has not been allocated and we have to | ||
| 1279 | * use a "safe" page frame to store the read page | ||
| 1280 | */ | 1207 | */ |
| 1281 | pbe->address = (unsigned long)safe_pages; | 1208 | pbe = chain_alloc(ca, sizeof(struct pbe)); |
| 1282 | safe_pages = safe_pages->next; | 1209 | if (!pbe) { |
| 1283 | if (last) | 1210 | swsusp_free(); |
| 1284 | last->next = pbe; | 1211 | return NULL; |
| 1285 | handle->last_pbe = pbe; | 1212 | } |
| 1213 | pbe->orig_address = (unsigned long)page_address(page); | ||
| 1214 | pbe->address = (unsigned long)safe_pages_list; | ||
| 1215 | safe_pages_list = safe_pages_list->next; | ||
| 1216 | pbe->next = restore_pblist; | ||
| 1217 | restore_pblist = pbe; | ||
| 1286 | return (void *)pbe->address; | 1218 | return (void *)pbe->address; |
| 1287 | } | 1219 | } |
| 1288 | 1220 | ||
| @@ -1310,10 +1242,13 @@ static void *get_buffer(struct snapshot_handle *handle) | |||
| 1310 | 1242 | ||
| 1311 | int snapshot_write_next(struct snapshot_handle *handle, size_t count) | 1243 | int snapshot_write_next(struct snapshot_handle *handle, size_t count) |
| 1312 | { | 1244 | { |
| 1245 | static struct chain_allocator ca; | ||
| 1313 | int error = 0; | 1246 | int error = 0; |
| 1314 | 1247 | ||
| 1248 | /* Check if we have already loaded the entire image */ | ||
| 1315 | if (handle->prev && handle->cur > nr_meta_pages + nr_copy_pages) | 1249 | if (handle->prev && handle->cur > nr_meta_pages + nr_copy_pages) |
| 1316 | return 0; | 1250 | return 0; |
| 1251 | |||
| 1317 | if (!buffer) { | 1252 | if (!buffer) { |
| 1318 | /* This makes the buffer be freed by swsusp_free() */ | 1253 | /* This makes the buffer be freed by swsusp_free() */ |
| 1319 | buffer = alloc_image_page(GFP_ATOMIC, PG_ANY); | 1254 | buffer = alloc_image_page(GFP_ATOMIC, PG_ANY); |
| @@ -1324,26 +1259,32 @@ int snapshot_write_next(struct snapshot_handle *handle, size_t count) | |||
| 1324 | handle->buffer = buffer; | 1259 | handle->buffer = buffer; |
| 1325 | handle->sync_read = 1; | 1260 | handle->sync_read = 1; |
| 1326 | if (handle->prev < handle->cur) { | 1261 | if (handle->prev < handle->cur) { |
| 1327 | if (!handle->prev) { | 1262 | if (handle->prev == 0) { |
| 1328 | error = load_header(handle, | 1263 | error = load_header(buffer); |
| 1329 | (struct swsusp_info *)buffer); | 1264 | if (error) |
| 1265 | return error; | ||
| 1266 | |||
| 1267 | error = memory_bm_create(©_bm, GFP_ATOMIC, PG_ANY); | ||
| 1330 | if (error) | 1268 | if (error) |
| 1331 | return error; | 1269 | return error; |
| 1270 | |||
| 1332 | } else if (handle->prev <= nr_meta_pages) { | 1271 | } else if (handle->prev <= nr_meta_pages) { |
| 1333 | handle->pbe = unpack_orig_addresses(buffer, | 1272 | unpack_orig_pfns(buffer, ©_bm); |
| 1334 | handle->pbe); | 1273 | if (handle->prev == nr_meta_pages) { |
| 1335 | if (!handle->pbe) { | 1274 | error = prepare_image(&orig_bm, ©_bm); |
| 1336 | error = prepare_image(handle); | ||
| 1337 | if (error) | 1275 | if (error) |
| 1338 | return error; | 1276 | return error; |
| 1339 | handle->pbe = restore_pblist; | 1277 | |
| 1340 | handle->last_pbe = NULL; | 1278 | chain_init(&ca, GFP_ATOMIC, PG_SAFE); |
| 1341 | handle->buffer = get_buffer(handle); | 1279 | memory_bm_position_reset(&orig_bm); |
| 1280 | restore_pblist = NULL; | ||
| 1281 | handle->buffer = get_buffer(&orig_bm, &ca); | ||
| 1342 | handle->sync_read = 0; | 1282 | handle->sync_read = 0; |
| 1283 | if (!handle->buffer) | ||
| 1284 | return -ENOMEM; | ||
| 1343 | } | 1285 | } |
| 1344 | } else { | 1286 | } else { |
| 1345 | handle->pbe = handle->pbe->next; | 1287 | handle->buffer = get_buffer(&orig_bm, &ca); |
| 1346 | handle->buffer = get_buffer(handle); | ||
| 1347 | handle->sync_read = 0; | 1288 | handle->sync_read = 0; |
| 1348 | } | 1289 | } |
| 1349 | handle->prev = handle->cur; | 1290 | handle->prev = handle->cur; |
| @@ -1362,6 +1303,13 @@ int snapshot_write_next(struct snapshot_handle *handle, size_t count) | |||
| 1362 | 1303 | ||
| 1363 | int snapshot_image_loaded(struct snapshot_handle *handle) | 1304 | int snapshot_image_loaded(struct snapshot_handle *handle) |
| 1364 | { | 1305 | { |
| 1365 | return !(!handle->pbe || handle->pbe->next || !nr_copy_pages || | 1306 | return !(!nr_copy_pages || |
| 1366 | handle->cur <= nr_meta_pages + nr_copy_pages); | 1307 | handle->cur <= nr_meta_pages + nr_copy_pages); |
| 1308 | } | ||
| 1309 | |||
| 1310 | void snapshot_free_unused_memory(struct snapshot_handle *handle) | ||
| 1311 | { | ||
| 1312 | /* Free only if we have loaded the image entirely */ | ||
| 1313 | if (handle->prev && handle->cur > nr_meta_pages + nr_copy_pages) | ||
| 1314 | memory_bm_free(&orig_bm, PG_UNSAFE_CLEAR); | ||
| 1367 | } | 1315 | } |
diff --git a/kernel/power/swap.c b/kernel/power/swap.c index 8309d20b2563..9b2ee5344dee 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c | |||
| @@ -331,8 +331,7 @@ static int enough_swap(unsigned int nr_pages) | |||
| 331 | unsigned int free_swap = count_swap_pages(root_swap, 1); | 331 | unsigned int free_swap = count_swap_pages(root_swap, 1); |
| 332 | 332 | ||
| 333 | pr_debug("swsusp: free swap pages: %u\n", free_swap); | 333 | pr_debug("swsusp: free swap pages: %u\n", free_swap); |
| 334 | return free_swap > (nr_pages + PAGES_FOR_IO + | 334 | return free_swap > nr_pages + PAGES_FOR_IO; |
| 335 | (nr_pages + PBES_PER_PAGE - 1) / PBES_PER_PAGE); | ||
| 336 | } | 335 | } |
| 337 | 336 | ||
| 338 | /** | 337 | /** |
| @@ -547,6 +546,7 @@ static int load_image(struct swap_map_handle *handle, | |||
| 547 | error = err2; | 546 | error = err2; |
| 548 | if (!error) { | 547 | if (!error) { |
| 549 | printk("\b\b\b\bdone\n"); | 548 | printk("\b\b\b\bdone\n"); |
| 549 | snapshot_free_unused_memory(snapshot); | ||
| 550 | if (!snapshot_image_loaded(snapshot)) | 550 | if (!snapshot_image_loaded(snapshot)) |
| 551 | error = -ENODATA; | 551 | error = -ENODATA; |
| 552 | } | 552 | } |
diff --git a/kernel/power/user.c b/kernel/power/user.c index 0ef5e4ba39e5..2e4499f3e4d9 100644 --- a/kernel/power/user.c +++ b/kernel/power/user.c | |||
| @@ -193,6 +193,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp, | |||
| 193 | error = -EPERM; | 193 | error = -EPERM; |
| 194 | break; | 194 | break; |
| 195 | } | 195 | } |
| 196 | snapshot_free_unused_memory(&data->handle); | ||
| 196 | down(&pm_sem); | 197 | down(&pm_sem); |
| 197 | pm_prepare_console(); | 198 | pm_prepare_console(); |
| 198 | error = device_suspend(PMSG_FREEZE); | 199 | error = device_suspend(PMSG_FREEZE); |
