diff options
-rw-r--r-- | include/linux/suspend.h | 33 | ||||
-rw-r--r-- | kernel/power/snapshot.c | 48 | ||||
-rw-r--r-- | mm/page_alloc.c | 6 |
3 files changed, 61 insertions, 26 deletions
diff --git a/include/linux/suspend.h b/include/linux/suspend.h index bf99bd49f8ef..a45b9f514492 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h | |||
@@ -8,6 +8,7 @@ | |||
8 | #include <linux/notifier.h> | 8 | #include <linux/notifier.h> |
9 | #include <linux/init.h> | 9 | #include <linux/init.h> |
10 | #include <linux/pm.h> | 10 | #include <linux/pm.h> |
11 | #include <linux/mm.h> | ||
11 | 12 | ||
12 | /* struct pbe is used for creating lists of pages that should be restored | 13 | /* struct pbe is used for creating lists of pages that should be restored |
13 | * atomically during the resume from disk, because the page frames they have | 14 | * atomically during the resume from disk, because the page frames they have |
@@ -49,6 +50,38 @@ void __save_processor_state(struct saved_context *ctxt); | |||
49 | void __restore_processor_state(struct saved_context *ctxt); | 50 | void __restore_processor_state(struct saved_context *ctxt); |
50 | unsigned long get_safe_page(gfp_t gfp_mask); | 51 | unsigned long get_safe_page(gfp_t gfp_mask); |
51 | 52 | ||
53 | /* Page management functions for the software suspend (swsusp) */ | ||
54 | |||
55 | static inline void swsusp_set_page_forbidden(struct page *page) | ||
56 | { | ||
57 | SetPageNosave(page); | ||
58 | } | ||
59 | |||
60 | static inline int swsusp_page_is_forbidden(struct page *page) | ||
61 | { | ||
62 | return PageNosave(page); | ||
63 | } | ||
64 | |||
65 | static inline void swsusp_unset_page_forbidden(struct page *page) | ||
66 | { | ||
67 | ClearPageNosave(page); | ||
68 | } | ||
69 | |||
70 | static inline void swsusp_set_page_free(struct page *page) | ||
71 | { | ||
72 | SetPageNosaveFree(page); | ||
73 | } | ||
74 | |||
75 | static inline int swsusp_page_is_free(struct page *page) | ||
76 | { | ||
77 | return PageNosaveFree(page); | ||
78 | } | ||
79 | |||
80 | static inline void swsusp_unset_page_free(struct page *page) | ||
81 | { | ||
82 | ClearPageNosaveFree(page); | ||
83 | } | ||
84 | |||
52 | /* | 85 | /* |
53 | * XXX: We try to keep some more pages free so that I/O operations succeed | 86 | * XXX: We try to keep some more pages free so that I/O operations succeed |
54 | * without paging. Might this be more? | 87 | * without paging. Might this be more? |
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 704c25a3ffec..48fc7a35571b 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c | |||
@@ -67,15 +67,15 @@ static void *get_image_page(gfp_t gfp_mask, int safe_needed) | |||
67 | 67 | ||
68 | res = (void *)get_zeroed_page(gfp_mask); | 68 | res = (void *)get_zeroed_page(gfp_mask); |
69 | if (safe_needed) | 69 | if (safe_needed) |
70 | while (res && PageNosaveFree(virt_to_page(res))) { | 70 | while (res && swsusp_page_is_free(virt_to_page(res))) { |
71 | /* The page is unsafe, mark it for swsusp_free() */ | 71 | /* The page is unsafe, mark it for swsusp_free() */ |
72 | SetPageNosave(virt_to_page(res)); | 72 | swsusp_set_page_forbidden(virt_to_page(res)); |
73 | allocated_unsafe_pages++; | 73 | allocated_unsafe_pages++; |
74 | res = (void *)get_zeroed_page(gfp_mask); | 74 | res = (void *)get_zeroed_page(gfp_mask); |
75 | } | 75 | } |
76 | if (res) { | 76 | if (res) { |
77 | SetPageNosave(virt_to_page(res)); | 77 | swsusp_set_page_forbidden(virt_to_page(res)); |
78 | SetPageNosaveFree(virt_to_page(res)); | 78 | swsusp_set_page_free(virt_to_page(res)); |
79 | } | 79 | } |
80 | return res; | 80 | return res; |
81 | } | 81 | } |
@@ -91,8 +91,8 @@ static struct page *alloc_image_page(gfp_t gfp_mask) | |||
91 | 91 | ||
92 | page = alloc_page(gfp_mask); | 92 | page = alloc_page(gfp_mask); |
93 | if (page) { | 93 | if (page) { |
94 | SetPageNosave(page); | 94 | swsusp_set_page_forbidden(page); |
95 | SetPageNosaveFree(page); | 95 | swsusp_set_page_free(page); |
96 | } | 96 | } |
97 | return page; | 97 | return page; |
98 | } | 98 | } |
@@ -110,9 +110,9 @@ static inline void free_image_page(void *addr, int clear_nosave_free) | |||
110 | 110 | ||
111 | page = virt_to_page(addr); | 111 | page = virt_to_page(addr); |
112 | 112 | ||
113 | ClearPageNosave(page); | 113 | swsusp_unset_page_forbidden(page); |
114 | if (clear_nosave_free) | 114 | if (clear_nosave_free) |
115 | ClearPageNosaveFree(page); | 115 | swsusp_unset_page_free(page); |
116 | 116 | ||
117 | __free_page(page); | 117 | __free_page(page); |
118 | } | 118 | } |
@@ -615,7 +615,8 @@ static struct page *saveable_highmem_page(unsigned long pfn) | |||
615 | 615 | ||
616 | BUG_ON(!PageHighMem(page)); | 616 | BUG_ON(!PageHighMem(page)); |
617 | 617 | ||
618 | if (PageNosave(page) || PageReserved(page) || PageNosaveFree(page)) | 618 | if (swsusp_page_is_forbidden(page) || swsusp_page_is_free(page) || |
619 | PageReserved(page)) | ||
619 | return NULL; | 620 | return NULL; |
620 | 621 | ||
621 | return page; | 622 | return page; |
@@ -670,7 +671,7 @@ static struct page *saveable_page(unsigned long pfn) | |||
670 | 671 | ||
671 | BUG_ON(PageHighMem(page)); | 672 | BUG_ON(PageHighMem(page)); |
672 | 673 | ||
673 | if (PageNosave(page) || PageNosaveFree(page)) | 674 | if (swsusp_page_is_forbidden(page) || swsusp_page_is_free(page)) |
674 | return NULL; | 675 | return NULL; |
675 | 676 | ||
676 | if (PageReserved(page) && pfn_is_nosave(pfn)) | 677 | if (PageReserved(page) && pfn_is_nosave(pfn)) |
@@ -810,9 +811,10 @@ void swsusp_free(void) | |||
810 | if (pfn_valid(pfn)) { | 811 | if (pfn_valid(pfn)) { |
811 | struct page *page = pfn_to_page(pfn); | 812 | struct page *page = pfn_to_page(pfn); |
812 | 813 | ||
813 | if (PageNosave(page) && PageNosaveFree(page)) { | 814 | if (swsusp_page_is_forbidden(page) && |
814 | ClearPageNosave(page); | 815 | swsusp_page_is_free(page)) { |
815 | ClearPageNosaveFree(page); | 816 | swsusp_unset_page_forbidden(page); |
817 | swsusp_unset_page_free(page); | ||
816 | __free_page(page); | 818 | __free_page(page); |
817 | } | 819 | } |
818 | } | 820 | } |
@@ -1135,7 +1137,7 @@ static int mark_unsafe_pages(struct memory_bitmap *bm) | |||
1135 | max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages; | 1137 | max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages; |
1136 | for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++) | 1138 | for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++) |
1137 | if (pfn_valid(pfn)) | 1139 | if (pfn_valid(pfn)) |
1138 | ClearPageNosaveFree(pfn_to_page(pfn)); | 1140 | swsusp_unset_page_free(pfn_to_page(pfn)); |
1139 | } | 1141 | } |
1140 | 1142 | ||
1141 | /* Mark pages that correspond to the "original" pfns as "unsafe" */ | 1143 | /* Mark pages that correspond to the "original" pfns as "unsafe" */ |
@@ -1144,7 +1146,7 @@ static int mark_unsafe_pages(struct memory_bitmap *bm) | |||
1144 | pfn = memory_bm_next_pfn(bm); | 1146 | pfn = memory_bm_next_pfn(bm); |
1145 | if (likely(pfn != BM_END_OF_MAP)) { | 1147 | if (likely(pfn != BM_END_OF_MAP)) { |
1146 | if (likely(pfn_valid(pfn))) | 1148 | if (likely(pfn_valid(pfn))) |
1147 | SetPageNosaveFree(pfn_to_page(pfn)); | 1149 | swsusp_set_page_free(pfn_to_page(pfn)); |
1148 | else | 1150 | else |
1149 | return -EFAULT; | 1151 | return -EFAULT; |
1150 | } | 1152 | } |
@@ -1310,14 +1312,14 @@ prepare_highmem_image(struct memory_bitmap *bm, unsigned int *nr_highmem_p) | |||
1310 | struct page *page; | 1312 | struct page *page; |
1311 | 1313 | ||
1312 | page = alloc_page(__GFP_HIGHMEM); | 1314 | page = alloc_page(__GFP_HIGHMEM); |
1313 | if (!PageNosaveFree(page)) { | 1315 | if (!swsusp_page_is_free(page)) { |
1314 | /* The page is "safe", set its bit the bitmap */ | 1316 | /* The page is "safe", set its bit the bitmap */ |
1315 | memory_bm_set_bit(bm, page_to_pfn(page)); | 1317 | memory_bm_set_bit(bm, page_to_pfn(page)); |
1316 | safe_highmem_pages++; | 1318 | safe_highmem_pages++; |
1317 | } | 1319 | } |
1318 | /* Mark the page as allocated */ | 1320 | /* Mark the page as allocated */ |
1319 | SetPageNosave(page); | 1321 | swsusp_set_page_forbidden(page); |
1320 | SetPageNosaveFree(page); | 1322 | swsusp_set_page_free(page); |
1321 | } | 1323 | } |
1322 | memory_bm_position_reset(bm); | 1324 | memory_bm_position_reset(bm); |
1323 | safe_highmem_bm = bm; | 1325 | safe_highmem_bm = bm; |
@@ -1349,7 +1351,7 @@ get_highmem_page_buffer(struct page *page, struct chain_allocator *ca) | |||
1349 | struct highmem_pbe *pbe; | 1351 | struct highmem_pbe *pbe; |
1350 | void *kaddr; | 1352 | void *kaddr; |
1351 | 1353 | ||
1352 | if (PageNosave(page) && PageNosaveFree(page)) { | 1354 | if (swsusp_page_is_forbidden(page) && swsusp_page_is_free(page)) { |
1353 | /* We have allocated the "original" page frame and we can | 1355 | /* We have allocated the "original" page frame and we can |
1354 | * use it directly to store the loaded page. | 1356 | * use it directly to store the loaded page. |
1355 | */ | 1357 | */ |
@@ -1511,14 +1513,14 @@ prepare_image(struct memory_bitmap *new_bm, struct memory_bitmap *bm) | |||
1511 | error = -ENOMEM; | 1513 | error = -ENOMEM; |
1512 | goto Free; | 1514 | goto Free; |
1513 | } | 1515 | } |
1514 | if (!PageNosaveFree(virt_to_page(lp))) { | 1516 | if (!swsusp_page_is_free(virt_to_page(lp))) { |
1515 | /* The page is "safe", add it to the list */ | 1517 | /* The page is "safe", add it to the list */ |
1516 | lp->next = safe_pages_list; | 1518 | lp->next = safe_pages_list; |
1517 | safe_pages_list = lp; | 1519 | safe_pages_list = lp; |
1518 | } | 1520 | } |
1519 | /* Mark the page as allocated */ | 1521 | /* Mark the page as allocated */ |
1520 | SetPageNosave(virt_to_page(lp)); | 1522 | swsusp_set_page_forbidden(virt_to_page(lp)); |
1521 | SetPageNosaveFree(virt_to_page(lp)); | 1523 | swsusp_set_page_free(virt_to_page(lp)); |
1522 | nr_pages--; | 1524 | nr_pages--; |
1523 | } | 1525 | } |
1524 | /* Free the reserved safe pages so that chain_alloc() can use them */ | 1526 | /* Free the reserved safe pages so that chain_alloc() can use them */ |
@@ -1547,7 +1549,7 @@ static void *get_buffer(struct memory_bitmap *bm, struct chain_allocator *ca) | |||
1547 | if (PageHighMem(page)) | 1549 | if (PageHighMem(page)) |
1548 | return get_highmem_page_buffer(page, ca); | 1550 | return get_highmem_page_buffer(page, ca); |
1549 | 1551 | ||
1550 | if (PageNosave(page) && PageNosaveFree(page)) | 1552 | if (swsusp_page_is_forbidden(page) && swsusp_page_is_free(page)) |
1551 | /* We have allocated the "original" page frame and we can | 1553 | /* We have allocated the "original" page frame and we can |
1552 | * use it directly to store the loaded page. | 1554 | * use it directly to store the loaded page. |
1553 | */ | 1555 | */ |
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 36d713e216e8..59164313167f 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -775,8 +775,8 @@ void mark_free_pages(struct zone *zone) | |||
775 | if (pfn_valid(pfn)) { | 775 | if (pfn_valid(pfn)) { |
776 | struct page *page = pfn_to_page(pfn); | 776 | struct page *page = pfn_to_page(pfn); |
777 | 777 | ||
778 | if (!PageNosave(page)) | 778 | if (!swsusp_page_is_forbidden(page)) |
779 | ClearPageNosaveFree(page); | 779 | swsusp_unset_page_free(page); |
780 | } | 780 | } |
781 | 781 | ||
782 | for (order = MAX_ORDER - 1; order >= 0; --order) | 782 | for (order = MAX_ORDER - 1; order >= 0; --order) |
@@ -785,7 +785,7 @@ void mark_free_pages(struct zone *zone) | |||
785 | 785 | ||
786 | pfn = page_to_pfn(list_entry(curr, struct page, lru)); | 786 | pfn = page_to_pfn(list_entry(curr, struct page, lru)); |
787 | for (i = 0; i < (1UL << order); i++) | 787 | for (i = 0; i < (1UL << order); i++) |
788 | SetPageNosaveFree(pfn_to_page(pfn + i)); | 788 | swsusp_set_page_free(pfn_to_page(pfn + i)); |
789 | } | 789 | } |
790 | 790 | ||
791 | spin_unlock_irqrestore(&zone->lock, flags); | 791 | spin_unlock_irqrestore(&zone->lock, flags); |