Skip to content

Commit 9c74448

Browse files
committed
PM / hibernate: Do not free preallocated safe pages during image restore
The core image restoration code preallocates some safe pages (ie. pages that weren't used by the image kernel before hibernation) for future use before allocating the bulk of memory for loading the image data. Those safe pages are then freed so they can be allocated again (with the memory management subsystem's help). That's done to ensure that there will be enough safe pages for temporary data structures needed during image restoration. However, it is not really necessary to free those pages after they have been allocated. They can be added to the (global) list of safe pages right away and then picked up from there when needed without freeing. That reduces the overhead related to using safe pages, especially in the arch-specific code, so modify the code accordingly. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
1 parent 7b776af commit 9c74448

File tree

1 file changed

+38
-28
lines changed

1 file changed

+38
-28
lines changed

kernel/power/snapshot.c

Lines changed: 38 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,22 @@ void __init hibernate_image_size_init(void)
7474
*/
7575
struct pbe *restore_pblist;
7676

77+
/* struct linked_page is used to build chains of pages */
78+
79+
#define LINKED_PAGE_DATA_SIZE (PAGE_SIZE - sizeof(void *))
80+
81+
struct linked_page {
82+
struct linked_page *next;
83+
char data[LINKED_PAGE_DATA_SIZE];
84+
} __packed;
85+
86+
/*
87+
* List of "safe" pages (ie. pages that were not used by the image kernel
88+
* before hibernation) that may be used as temporary storage for image kernel
89+
* memory contents.
90+
*/
91+
static struct linked_page *safe_pages_list;
92+
7793
/* Pointer to an auxiliary buffer (1 page) */
7894
static void *buffer;
7995

@@ -113,9 +129,21 @@ static void *get_image_page(gfp_t gfp_mask, int safe_needed)
113129
return res;
114130
}
115131

132+
static void *__get_safe_page(gfp_t gfp_mask)
133+
{
134+
if (safe_pages_list) {
135+
void *ret = safe_pages_list;
136+
137+
safe_pages_list = safe_pages_list->next;
138+
memset(ret, 0, PAGE_SIZE);
139+
return ret;
140+
}
141+
return get_image_page(gfp_mask, PG_SAFE);
142+
}
143+
116144
unsigned long get_safe_page(gfp_t gfp_mask)
117145
{
118-
return (unsigned long)get_image_page(gfp_mask, PG_SAFE);
146+
return (unsigned long)__get_safe_page(gfp_mask);
119147
}
120148

121149
static struct page *alloc_image_page(gfp_t gfp_mask)
@@ -150,15 +178,6 @@ static inline void free_image_page(void *addr, int clear_nosave_free)
150178
__free_page(page);
151179
}
152180

153-
/* struct linked_page is used to build chains of pages */
154-
155-
#define LINKED_PAGE_DATA_SIZE (PAGE_SIZE - sizeof(void *))
156-
157-
struct linked_page {
158-
struct linked_page *next;
159-
char data[LINKED_PAGE_DATA_SIZE];
160-
} __packed;
161-
162181
static inline void
163182
free_list_of_pages(struct linked_page *list, int clear_page_nosave)
164183
{
@@ -208,7 +227,8 @@ static void *chain_alloc(struct chain_allocator *ca, unsigned int size)
208227
if (LINKED_PAGE_DATA_SIZE - ca->used_space < size) {
209228
struct linked_page *lp;
210229

211-
lp = get_image_page(ca->gfp_mask, ca->safe_needed);
230+
lp = ca->safe_needed ? __get_safe_page(ca->gfp_mask) :
231+
get_image_page(ca->gfp_mask, PG_ANY);
212232
if (!lp)
213233
return NULL;
214234

@@ -2104,11 +2124,6 @@ static int unpack_orig_pfns(unsigned long *buf, struct memory_bitmap *bm)
21042124
return 0;
21052125
}
21062126

2107-
/* List of "safe" pages that may be used to store data loaded from the suspend
2108-
* image
2109-
*/
2110-
static struct linked_page *safe_pages_list;
2111-
21122127
#ifdef CONFIG_HIGHMEM
21132128
/* struct highmem_pbe is used for creating the list of highmem pages that
21142129
* should be restored atomically during the resume from disk, because the page
@@ -2334,7 +2349,7 @@ static int
23342349
prepare_image(struct memory_bitmap *new_bm, struct memory_bitmap *bm)
23352350
{
23362351
unsigned int nr_pages, nr_highmem;
2337-
struct linked_page *sp_list, *lp;
2352+
struct linked_page *lp;
23382353
int error;
23392354

23402355
/* If there is no highmem, the buffer will not be necessary */
@@ -2362,9 +2377,9 @@ prepare_image(struct memory_bitmap *new_bm, struct memory_bitmap *bm)
23622377
* NOTE: This way we make sure there will be enough safe pages for the
23632378
* chain_alloc() in get_buffer(). It is a bit wasteful, but
23642379
* nr_copy_pages cannot be greater than 50% of the memory anyway.
2380+
*
2381+
* nr_copy_pages cannot be less than allocated_unsafe_pages too.
23652382
*/
2366-
sp_list = NULL;
2367-
/* nr_copy_pages cannot be lesser than allocated_unsafe_pages */
23682383
nr_pages = nr_copy_pages - nr_highmem - allocated_unsafe_pages;
23692384
nr_pages = DIV_ROUND_UP(nr_pages, PBES_PER_LINKED_PAGE);
23702385
while (nr_pages > 0) {
@@ -2373,12 +2388,11 @@ prepare_image(struct memory_bitmap *new_bm, struct memory_bitmap *bm)
23732388
error = -ENOMEM;
23742389
goto Free;
23752390
}
2376-
lp->next = sp_list;
2377-
sp_list = lp;
2391+
lp->next = safe_pages_list;
2392+
safe_pages_list = lp;
23782393
nr_pages--;
23792394
}
23802395
/* Preallocate memory for the image */
2381-
safe_pages_list = NULL;
23822396
nr_pages = nr_copy_pages - nr_highmem - allocated_unsafe_pages;
23832397
while (nr_pages > 0) {
23842398
lp = (struct linked_page *)get_zeroed_page(GFP_ATOMIC);
@@ -2396,12 +2410,6 @@ prepare_image(struct memory_bitmap *new_bm, struct memory_bitmap *bm)
23962410
swsusp_set_page_free(virt_to_page(lp));
23972411
nr_pages--;
23982412
}
2399-
/* Free the reserved safe pages so that chain_alloc() can use them */
2400-
while (sp_list) {
2401-
lp = sp_list->next;
2402-
free_image_page(sp_list, PG_UNSAFE_CLEAR);
2403-
sp_list = lp;
2404-
}
24052413
return 0;
24062414

24072415
Free:
@@ -2491,6 +2499,8 @@ int snapshot_write_next(struct snapshot_handle *handle)
24912499
if (error)
24922500
return error;
24932501

2502+
safe_pages_list = NULL;
2503+
24942504
error = memory_bm_create(&copy_bm, GFP_ATOMIC, PG_ANY);
24952505
if (error)
24962506
return error;

0 commit comments

Comments
 (0)