aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoerg Roedel <jroedel@suse.de>2014-09-30 07:31:29 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-09-30 15:12:20 -0400
commitfdd64ed54eeba6b8619b36dcc7cb6442f2c6da0c (patch)
treeebaca3059701e9f42eb5455af02f5d5fba83462e
parent905563ff47db35dcb3f69e69d434207270ad1966 (diff)
PM / hibernate: Iterate over set bits instead of PFNs in swsusp_free()
The existing implementation of swsusp_free iterates over all pfns in the system and checks every bit in the two memory bitmaps. This doesn't scale very well with large numbers of pfns, especially when the bitmaps are not populated very densly. Change the algorithm to iterate over the set bits in the bitmaps instead to make it scale better in large memory configurations. Also add a memory_bm_clear_current() helper function that clears the bit for the last position returned from the memory bitmap. This new version adds a !NULL check for the memory bitmaps before they are walked. Not doing so causes a kernel crash when the bitmaps are NULL. Signed-off-by: Joerg Roedel <jroedel@suse.de> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--kernel/power/snapshot.c54
1 files changed, 39 insertions, 15 deletions
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index f1604d8cf489..791a61892bb5 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -725,6 +725,14 @@ static void memory_bm_clear_bit(struct memory_bitmap *bm, unsigned long pfn)
725 clear_bit(bit, addr); 725 clear_bit(bit, addr);
726} 726}
727 727
728static void memory_bm_clear_current(struct memory_bitmap *bm)
729{
730 int bit;
731
732 bit = max(bm->cur.node_bit - 1, 0);
733 clear_bit(bit, bm->cur.node->data);
734}
735
728static int memory_bm_test_bit(struct memory_bitmap *bm, unsigned long pfn) 736static int memory_bm_test_bit(struct memory_bitmap *bm, unsigned long pfn)
729{ 737{
730 void *addr; 738 void *addr;
@@ -1333,23 +1341,39 @@ static struct memory_bitmap copy_bm;
1333 1341
1334void swsusp_free(void) 1342void swsusp_free(void)
1335{ 1343{
1336 struct zone *zone; 1344 unsigned long fb_pfn, fr_pfn;
1337 unsigned long pfn, max_zone_pfn;
1338 1345
1339 for_each_populated_zone(zone) { 1346 if (!forbidden_pages_map || !free_pages_map)
1340 max_zone_pfn = zone_end_pfn(zone); 1347 goto out;
1341 for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++) 1348
1342 if (pfn_valid(pfn)) { 1349 memory_bm_position_reset(forbidden_pages_map);
1343 struct page *page = pfn_to_page(pfn); 1350 memory_bm_position_reset(free_pages_map);
1344 1351
1345 if (swsusp_page_is_forbidden(page) && 1352loop:
1346 swsusp_page_is_free(page)) { 1353 fr_pfn = memory_bm_next_pfn(free_pages_map);
1347 swsusp_unset_page_forbidden(page); 1354 fb_pfn = memory_bm_next_pfn(forbidden_pages_map);
1348 swsusp_unset_page_free(page); 1355
1349 __free_page(page); 1356 /*
1350 } 1357 * Find the next bit set in both bitmaps. This is guaranteed to
1351 } 1358 * terminate when fb_pfn == fr_pfn == BM_END_OF_MAP.
1359 */
1360 do {
1361 if (fb_pfn < fr_pfn)
1362 fb_pfn = memory_bm_next_pfn(forbidden_pages_map);
1363 if (fr_pfn < fb_pfn)
1364 fr_pfn = memory_bm_next_pfn(free_pages_map);
1365 } while (fb_pfn != fr_pfn);
1366
1367 if (fr_pfn != BM_END_OF_MAP && pfn_valid(fr_pfn)) {
1368 struct page *page = pfn_to_page(fr_pfn);
1369
1370 memory_bm_clear_current(forbidden_pages_map);
1371 memory_bm_clear_current(free_pages_map);
1372 __free_page(page);
1373 goto loop;
1352 } 1374 }
1375
1376out:
1353 nr_copy_pages = 0; 1377 nr_copy_pages = 0;
1354 nr_meta_pages = 0; 1378 nr_meta_pages = 0;
1355 restore_pblist = NULL; 1379 restore_pblist = NULL;