aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorJoerg Roedel <jroedel@suse.de>2014-07-21 06:26:57 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-07-28 19:47:43 -0400
commitf469f02dc6fa67f6c6a7d91400d08b9339147aed (patch)
tree9b8cfa282dd89323c9b7e63f33da3792751c0a41 /kernel
parent58c256a3a37ea7ff9456978659b927678be6df85 (diff)
PM / Hibernate: Create a Radix-Tree to store memory bitmap
This patch adds the code to allocate and build the radix tree to store the memory bitmap. The old data structure is left in place until the radix tree implementation is finished. Signed-off-by: Joerg Roedel <jroedel@suse.de> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/power/snapshot.c223
1 files changed, 222 insertions, 1 deletions
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index 1ea328aafdc9..5a0eafdbac79 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -248,11 +248,24 @@ static void *chain_alloc(struct chain_allocator *ca, unsigned int size)
248 * information is stored (in the form of a block of bitmap) 248 * information is stored (in the form of a block of bitmap)
249 * It also contains the pfns that correspond to the start and end of 249 * It also contains the pfns that correspond to the start and end of
250 * the represented memory area. 250 * the represented memory area.
251 *
252 * The memory bitmap is organized as a radix tree to guarantee fast random
253 * access to the bits. There is one radix tree for each zone (as returned
254 * from create_mem_extents).
255 *
256 * One radix tree is represented by one struct mem_zone_bm_rtree. There are
257 * two linked lists for the nodes of the tree, one for the inner nodes and
258 * one for the leave nodes. The linked leave nodes are used for fast linear
259 * access of the memory bitmap.
260 *
261 * The struct rtree_node represents one node of the radix tree.
251 */ 262 */
252 263
253#define BM_END_OF_MAP (~0UL) 264#define BM_END_OF_MAP (~0UL)
254 265
255#define BM_BITS_PER_BLOCK (PAGE_SIZE * BITS_PER_BYTE) 266#define BM_BITS_PER_BLOCK (PAGE_SIZE * BITS_PER_BYTE)
267#define BM_BLOCK_SHIFT (PAGE_SHIFT + 3)
268#define BM_BLOCK_MASK ((1UL << BM_BLOCK_SHIFT) - 1)
256 269
257struct bm_block { 270struct bm_block {
258 struct list_head hook; /* hook into a list of bitmap blocks */ 271 struct list_head hook; /* hook into a list of bitmap blocks */
@@ -266,6 +279,31 @@ static inline unsigned long bm_block_bits(struct bm_block *bb)
266 return bb->end_pfn - bb->start_pfn; 279 return bb->end_pfn - bb->start_pfn;
267} 280}
268 281
282/*
283 * struct rtree_node is a wrapper struct to link the nodes
284 * of the rtree together for easy linear iteration over
285 * bits and easy freeing
286 */
287struct rtree_node {
288 struct list_head list;
289 unsigned long *data;
290};
291
292/*
293 * struct mem_zone_bm_rtree represents a bitmap used for one
294 * populated memory zone.
295 */
296struct mem_zone_bm_rtree {
297 struct list_head list; /* Link Zones together */
298 struct list_head nodes; /* Radix Tree inner nodes */
299 struct list_head leaves; /* Radix Tree leaves */
300 unsigned long start_pfn; /* Zone start page frame */
301 unsigned long end_pfn; /* Zone end page frame + 1 */
302 struct rtree_node *rtree; /* Radix Tree Root */
303 int levels; /* Number of Radix Tree Levels */
304 unsigned int blocks; /* Number of Bitmap Blocks */
305};
306
269/* strcut bm_position is used for browsing memory bitmaps */ 307/* strcut bm_position is used for browsing memory bitmaps */
270 308
271struct bm_position { 309struct bm_position {
@@ -274,6 +312,7 @@ struct bm_position {
274}; 312};
275 313
276struct memory_bitmap { 314struct memory_bitmap {
315 struct list_head zones;
277 struct list_head blocks; /* list of bitmap blocks */ 316 struct list_head blocks; /* list of bitmap blocks */
278 struct linked_page *p_list; /* list of pages used to store zone 317 struct linked_page *p_list; /* list of pages used to store zone
279 * bitmap objects and bitmap block 318 * bitmap objects and bitmap block
@@ -284,6 +323,166 @@ struct memory_bitmap {
284 323
285/* Functions that operate on memory bitmaps */ 324/* Functions that operate on memory bitmaps */
286 325
326#define BM_ENTRIES_PER_LEVEL (PAGE_SIZE / sizeof(unsigned long))
327#if BITS_PER_LONG == 32
328#define BM_RTREE_LEVEL_SHIFT (PAGE_SHIFT - 2)
329#else
330#define BM_RTREE_LEVEL_SHIFT (PAGE_SHIFT - 3)
331#endif
332#define BM_RTREE_LEVEL_MASK ((1UL << BM_RTREE_LEVEL_SHIFT) - 1)
333
334/*
335 * alloc_rtree_node - Allocate a new node and add it to the radix tree.
336 *
337 * This function is used to allocate inner nodes as well as the
338 * leave nodes of the radix tree. It also adds the node to the
339 * corresponding linked list passed in by the *list parameter.
340 */
341static struct rtree_node *alloc_rtree_node(gfp_t gfp_mask, int safe_needed,
342 struct chain_allocator *ca,
343 struct list_head *list)
344{
345 struct rtree_node *node;
346
347 node = chain_alloc(ca, sizeof(struct rtree_node));
348 if (!node)
349 return NULL;
350
351 node->data = get_image_page(gfp_mask, safe_needed);
352 if (!node->data)
353 return NULL;
354
355 list_add_tail(&node->list, list);
356
357 return node;
358}
359
360/*
361 * add_rtree_block - Add a new leave node to the radix tree
362 *
363 * The leave nodes need to be allocated in order to keep the leaves
364 * linked list in order. This is guaranteed by the zone->blocks
365 * counter.
366 */
367static int add_rtree_block(struct mem_zone_bm_rtree *zone, gfp_t gfp_mask,
368 int safe_needed, struct chain_allocator *ca)
369{
370 struct rtree_node *node, *block, **dst;
371 unsigned int levels_needed, block_nr;
372 int i;
373
374 block_nr = zone->blocks;
375 levels_needed = 0;
376
377 /* How many levels do we need for this block nr? */
378 while (block_nr) {
379 levels_needed += 1;
380 block_nr >>= BM_RTREE_LEVEL_SHIFT;
381 }
382
383 /* Make sure the rtree has enough levels */
384 for (i = zone->levels; i < levels_needed; i++) {
385 node = alloc_rtree_node(gfp_mask, safe_needed, ca,
386 &zone->nodes);
387 if (!node)
388 return -ENOMEM;
389
390 node->data[0] = (unsigned long)zone->rtree;
391 zone->rtree = node;
392 zone->levels += 1;
393 }
394
395 /* Allocate new block */
396 block = alloc_rtree_node(gfp_mask, safe_needed, ca, &zone->leaves);
397 if (!block)
398 return -ENOMEM;
399
400 /* Now walk the rtree to insert the block */
401 node = zone->rtree;
402 dst = &zone->rtree;
403 block_nr = zone->blocks;
404 for (i = zone->levels; i > 0; i--) {
405 int index;
406
407 if (!node) {
408 node = alloc_rtree_node(gfp_mask, safe_needed, ca,
409 &zone->nodes);
410 if (!node)
411 return -ENOMEM;
412 *dst = node;
413 }
414
415 index = block_nr >> ((i - 1) * BM_RTREE_LEVEL_SHIFT);
416 index &= BM_RTREE_LEVEL_MASK;
417 dst = (struct rtree_node **)&((*dst)->data[index]);
418 node = *dst;
419 }
420
421 zone->blocks += 1;
422 *dst = block;
423
424 return 0;
425}
426
427static void free_zone_bm_rtree(struct mem_zone_bm_rtree *zone,
428 int clear_nosave_free);
429
430/*
431 * create_zone_bm_rtree - create a radix tree for one zone
432 *
433 * Allocated the mem_zone_bm_rtree structure and initializes it.
434 * This function also allocated and builds the radix tree for the
435 * zone.
436 */
437static struct mem_zone_bm_rtree *
438create_zone_bm_rtree(gfp_t gfp_mask, int safe_needed,
439 struct chain_allocator *ca,
440 unsigned long start, unsigned long end)
441{
442 struct mem_zone_bm_rtree *zone;
443 unsigned int i, nr_blocks;
444 unsigned long pages;
445
446 pages = end - start;
447 zone = chain_alloc(ca, sizeof(struct mem_zone_bm_rtree));
448 if (!zone)
449 return NULL;
450
451 INIT_LIST_HEAD(&zone->nodes);
452 INIT_LIST_HEAD(&zone->leaves);
453 zone->start_pfn = start;
454 zone->end_pfn = end;
455 nr_blocks = DIV_ROUND_UP(pages, BM_BITS_PER_BLOCK);
456
457 for (i = 0; i < nr_blocks; i++) {
458 if (add_rtree_block(zone, gfp_mask, safe_needed, ca)) {
459 free_zone_bm_rtree(zone, PG_UNSAFE_CLEAR);
460 return NULL;
461 }
462 }
463
464 return zone;
465}
466
467/*
468 * free_zone_bm_rtree - Free the memory of the radix tree
469 *
470 * Free all node pages of the radix tree. The mem_zone_bm_rtree
471 * structure itself is not freed here nor are the rtree_node
472 * structs.
473 */
474static void free_zone_bm_rtree(struct mem_zone_bm_rtree *zone,
475 int clear_nosave_free)
476{
477 struct rtree_node *node;
478
479 list_for_each_entry(node, &zone->nodes, list)
480 free_image_page(node->data, clear_nosave_free);
481
482 list_for_each_entry(node, &zone->leaves, list)
483 free_image_page(node->data, clear_nosave_free);
484}
485
287static void memory_bm_position_reset(struct memory_bitmap *bm) 486static void memory_bm_position_reset(struct memory_bitmap *bm)
288{ 487{
289 bm->cur.block = list_entry(bm->blocks.next, struct bm_block, hook); 488 bm->cur.block = list_entry(bm->blocks.next, struct bm_block, hook);
@@ -408,12 +607,14 @@ memory_bm_create(struct memory_bitmap *bm, gfp_t gfp_mask, int safe_needed)
408 607
409 chain_init(&ca, gfp_mask, safe_needed); 608 chain_init(&ca, gfp_mask, safe_needed);
410 INIT_LIST_HEAD(&bm->blocks); 609 INIT_LIST_HEAD(&bm->blocks);
610 INIT_LIST_HEAD(&bm->zones);
411 611
412 error = create_mem_extents(&mem_extents, gfp_mask); 612 error = create_mem_extents(&mem_extents, gfp_mask);
413 if (error) 613 if (error)
414 return error; 614 return error;
415 615
416 list_for_each_entry(ext, &mem_extents, hook) { 616 list_for_each_entry(ext, &mem_extents, hook) {
617 struct mem_zone_bm_rtree *zone;
417 struct bm_block *bb; 618 struct bm_block *bb;
418 unsigned long pfn = ext->start; 619 unsigned long pfn = ext->start;
419 unsigned long pages = ext->end - ext->start; 620 unsigned long pages = ext->end - ext->start;
@@ -441,6 +642,12 @@ memory_bm_create(struct memory_bitmap *bm, gfp_t gfp_mask, int safe_needed)
441 } 642 }
442 bb->end_pfn = pfn; 643 bb->end_pfn = pfn;
443 } 644 }
645
646 zone = create_zone_bm_rtree(gfp_mask, safe_needed, &ca,
647 ext->start, ext->end);
648 if (!zone)
649 goto Error;
650 list_add_tail(&zone->list, &bm->zones);
444 } 651 }
445 652
446 bm->p_list = ca.chain; 653 bm->p_list = ca.chain;
@@ -460,14 +667,19 @@ memory_bm_create(struct memory_bitmap *bm, gfp_t gfp_mask, int safe_needed)
460 */ 667 */
461static void memory_bm_free(struct memory_bitmap *bm, int clear_nosave_free) 668static void memory_bm_free(struct memory_bitmap *bm, int clear_nosave_free)
462{ 669{
670 struct mem_zone_bm_rtree *zone;
463 struct bm_block *bb; 671 struct bm_block *bb;
464 672
465 list_for_each_entry(bb, &bm->blocks, hook) 673 list_for_each_entry(bb, &bm->blocks, hook)
466 if (bb->data) 674 if (bb->data)
467 free_image_page(bb->data, clear_nosave_free); 675 free_image_page(bb->data, clear_nosave_free);
468 676
677 list_for_each_entry(zone, &bm->zones, list)
678 free_zone_bm_rtree(zone, clear_nosave_free);
679
469 free_list_of_pages(bm->p_list, clear_nosave_free); 680 free_list_of_pages(bm->p_list, clear_nosave_free);
470 681
682 INIT_LIST_HEAD(&bm->zones);
471 INIT_LIST_HEAD(&bm->blocks); 683 INIT_LIST_HEAD(&bm->blocks);
472} 684}
473 685
@@ -816,12 +1028,21 @@ void free_basic_memory_bitmaps(void)
816 1028
817unsigned int snapshot_additional_pages(struct zone *zone) 1029unsigned int snapshot_additional_pages(struct zone *zone)
818{ 1030{
1031 unsigned int rtree, nodes;
819 unsigned int res; 1032 unsigned int res;
820 1033
821 res = DIV_ROUND_UP(zone->spanned_pages, BM_BITS_PER_BLOCK); 1034 res = DIV_ROUND_UP(zone->spanned_pages, BM_BITS_PER_BLOCK);
822 res += DIV_ROUND_UP(res * sizeof(struct bm_block), 1035 res += DIV_ROUND_UP(res * sizeof(struct bm_block),
823 LINKED_PAGE_DATA_SIZE); 1036 LINKED_PAGE_DATA_SIZE);
824 return 2 * res; 1037 rtree = nodes = DIV_ROUND_UP(zone->spanned_pages, BM_BITS_PER_BLOCK);
1038 rtree += DIV_ROUND_UP(rtree * sizeof(struct rtree_node),
1039 LINKED_PAGE_DATA_SIZE);
1040 while (nodes > 1) {
1041 nodes = DIV_ROUND_UP(nodes, BM_ENTRIES_PER_LEVEL);
1042 rtree += nodes;
1043 }
1044
1045 return 2 * (res + rtree);
825} 1046}
826 1047
827#ifdef CONFIG_HIGHMEM 1048#ifdef CONFIG_HIGHMEM