diff options
| author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2014-08-05 16:49:45 -0400 |
|---|---|---|
| committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2014-08-05 16:49:45 -0400 |
| commit | ddbe8db147cd0954da93dc6986f4793bcabb3889 (patch) | |
| tree | 0a0d463863ca78b644471132eb3f27ec3405b16d /kernel/power | |
| parent | b14c348e8dabcc7604683cfc44fad7396e8b639a (diff) | |
| parent | 0f7d83e85dbd5bb8032ebed7713edf59670fb074 (diff) | |
Merge branch 'pm-sleep'
* pm-sleep:
PM / Hibernate: Touch Soft Lockup Watchdog in rtree_next_node
PM / Hibernate: Remove the old memory-bitmap implementation
PM / Hibernate: Iterate over set bits instead of PFNs in swsusp_free()
PM / Hibernate: Implement position keeping in radix tree
PM / Hibernate: Add memory_rtree_find_bit function
PM / Hibernate: Create a Radix-Tree to store memory bitmap
PM / sleep: fix kernel-doc warnings in drivers/base/power/main.c
Diffstat (limited to 'kernel/power')
| -rw-r--r-- | kernel/power/snapshot.c | 494 |
1 files changed, 367 insertions, 127 deletions
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 1ea328aafdc9..4fc5c32422b3 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c | |||
| @@ -248,33 +248,61 @@ 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 | ||
| 257 | struct bm_block { | 270 | /* |
| 258 | struct list_head hook; /* hook into a list of bitmap blocks */ | 271 | * struct rtree_node is a wrapper struct to link the nodes |
| 259 | unsigned long start_pfn; /* pfn represented by the first bit */ | 272 | * of the rtree together for easy linear iteration over |
| 260 | unsigned long end_pfn; /* pfn represented by the last bit plus 1 */ | 273 | * bits and easy freeing |
| 261 | unsigned long *data; /* bitmap representing pages */ | 274 | */ |
| 275 | struct rtree_node { | ||
| 276 | struct list_head list; | ||
| 277 | unsigned long *data; | ||
| 262 | }; | 278 | }; |
| 263 | 279 | ||
| 264 | static inline unsigned long bm_block_bits(struct bm_block *bb) | 280 | /* |
| 265 | { | 281 | * struct mem_zone_bm_rtree represents a bitmap used for one |
| 266 | return bb->end_pfn - bb->start_pfn; | 282 | * populated memory zone. |
| 267 | } | 283 | */ |
| 284 | struct mem_zone_bm_rtree { | ||
| 285 | struct list_head list; /* Link Zones together */ | ||
| 286 | struct list_head nodes; /* Radix Tree inner nodes */ | ||
| 287 | struct list_head leaves; /* Radix Tree leaves */ | ||
| 288 | unsigned long start_pfn; /* Zone start page frame */ | ||
| 289 | unsigned long end_pfn; /* Zone end page frame + 1 */ | ||
| 290 | struct rtree_node *rtree; /* Radix Tree Root */ | ||
| 291 | int levels; /* Number of Radix Tree Levels */ | ||
| 292 | unsigned int blocks; /* Number of Bitmap Blocks */ | ||
| 293 | }; | ||
| 268 | 294 | ||
| 269 | /* strcut bm_position is used for browsing memory bitmaps */ | 295 | /* strcut bm_position is used for browsing memory bitmaps */ |
| 270 | 296 | ||
| 271 | struct bm_position { | 297 | struct bm_position { |
| 272 | struct bm_block *block; | 298 | struct mem_zone_bm_rtree *zone; |
| 273 | int bit; | 299 | struct rtree_node *node; |
| 300 | unsigned long node_pfn; | ||
| 301 | int node_bit; | ||
| 274 | }; | 302 | }; |
| 275 | 303 | ||
| 276 | struct memory_bitmap { | 304 | struct memory_bitmap { |
| 277 | struct list_head blocks; /* list of bitmap blocks */ | 305 | struct list_head zones; |
| 278 | struct linked_page *p_list; /* list of pages used to store zone | 306 | struct linked_page *p_list; /* list of pages used to store zone |
| 279 | * bitmap objects and bitmap block | 307 | * bitmap objects and bitmap block |
| 280 | * objects | 308 | * objects |
| @@ -284,38 +312,178 @@ struct memory_bitmap { | |||
| 284 | 312 | ||
| 285 | /* Functions that operate on memory bitmaps */ | 313 | /* Functions that operate on memory bitmaps */ |
| 286 | 314 | ||
| 287 | static void memory_bm_position_reset(struct memory_bitmap *bm) | 315 | #define BM_ENTRIES_PER_LEVEL (PAGE_SIZE / sizeof(unsigned long)) |
| 316 | #if BITS_PER_LONG == 32 | ||
| 317 | #define BM_RTREE_LEVEL_SHIFT (PAGE_SHIFT - 2) | ||
| 318 | #else | ||
| 319 | #define BM_RTREE_LEVEL_SHIFT (PAGE_SHIFT - 3) | ||
| 320 | #endif | ||
| 321 | #define BM_RTREE_LEVEL_MASK ((1UL << BM_RTREE_LEVEL_SHIFT) - 1) | ||
| 322 | |||
| 323 | /* | ||
| 324 | * alloc_rtree_node - Allocate a new node and add it to the radix tree. | ||
| 325 | * | ||
| 326 | * This function is used to allocate inner nodes as well as the | ||
| 327 | * leave nodes of the radix tree. It also adds the node to the | ||
| 328 | * corresponding linked list passed in by the *list parameter. | ||
| 329 | */ | ||
| 330 | static struct rtree_node *alloc_rtree_node(gfp_t gfp_mask, int safe_needed, | ||
| 331 | struct chain_allocator *ca, | ||
| 332 | struct list_head *list) | ||
| 288 | { | 333 | { |
| 289 | bm->cur.block = list_entry(bm->blocks.next, struct bm_block, hook); | 334 | struct rtree_node *node; |
| 290 | bm->cur.bit = 0; | ||
| 291 | } | ||
| 292 | 335 | ||
| 293 | static void memory_bm_free(struct memory_bitmap *bm, int clear_nosave_free); | 336 | node = chain_alloc(ca, sizeof(struct rtree_node)); |
| 337 | if (!node) | ||
| 338 | return NULL; | ||
| 294 | 339 | ||
| 295 | /** | 340 | node->data = get_image_page(gfp_mask, safe_needed); |
| 296 | * create_bm_block_list - create a list of block bitmap objects | 341 | if (!node->data) |
| 297 | * @pages - number of pages to track | 342 | return NULL; |
| 298 | * @list - list to put the allocated blocks into | 343 | |
| 299 | * @ca - chain allocator to be used for allocating memory | 344 | list_add_tail(&node->list, list); |
| 345 | |||
| 346 | return node; | ||
| 347 | } | ||
| 348 | |||
| 349 | /* | ||
| 350 | * add_rtree_block - Add a new leave node to the radix tree | ||
| 351 | * | ||
| 352 | * The leave nodes need to be allocated in order to keep the leaves | ||
| 353 | * linked list in order. This is guaranteed by the zone->blocks | ||
| 354 | * counter. | ||
| 300 | */ | 355 | */ |
| 301 | static int create_bm_block_list(unsigned long pages, | 356 | static int add_rtree_block(struct mem_zone_bm_rtree *zone, gfp_t gfp_mask, |
| 302 | struct list_head *list, | 357 | int safe_needed, struct chain_allocator *ca) |
| 303 | struct chain_allocator *ca) | ||
| 304 | { | 358 | { |
| 305 | unsigned int nr_blocks = DIV_ROUND_UP(pages, BM_BITS_PER_BLOCK); | 359 | struct rtree_node *node, *block, **dst; |
| 360 | unsigned int levels_needed, block_nr; | ||
| 361 | int i; | ||
| 306 | 362 | ||
| 307 | while (nr_blocks-- > 0) { | 363 | block_nr = zone->blocks; |
| 308 | struct bm_block *bb; | 364 | levels_needed = 0; |
| 309 | 365 | ||
| 310 | bb = chain_alloc(ca, sizeof(struct bm_block)); | 366 | /* How many levels do we need for this block nr? */ |
| 311 | if (!bb) | 367 | while (block_nr) { |
| 368 | levels_needed += 1; | ||
| 369 | block_nr >>= BM_RTREE_LEVEL_SHIFT; | ||
| 370 | } | ||
| 371 | |||
| 372 | /* Make sure the rtree has enough levels */ | ||
| 373 | for (i = zone->levels; i < levels_needed; i++) { | ||
| 374 | node = alloc_rtree_node(gfp_mask, safe_needed, ca, | ||
| 375 | &zone->nodes); | ||
| 376 | if (!node) | ||
| 312 | return -ENOMEM; | 377 | return -ENOMEM; |
| 313 | list_add(&bb->hook, list); | 378 | |
| 379 | node->data[0] = (unsigned long)zone->rtree; | ||
| 380 | zone->rtree = node; | ||
| 381 | zone->levels += 1; | ||
| 382 | } | ||
| 383 | |||
| 384 | /* Allocate new block */ | ||
| 385 | block = alloc_rtree_node(gfp_mask, safe_needed, ca, &zone->leaves); | ||
| 386 | if (!block) | ||
| 387 | return -ENOMEM; | ||
| 388 | |||
| 389 | /* Now walk the rtree to insert the block */ | ||
| 390 | node = zone->rtree; | ||
| 391 | dst = &zone->rtree; | ||
| 392 | block_nr = zone->blocks; | ||
| 393 | for (i = zone->levels; i > 0; i--) { | ||
| 394 | int index; | ||
| 395 | |||
| 396 | if (!node) { | ||
| 397 | node = alloc_rtree_node(gfp_mask, safe_needed, ca, | ||
| 398 | &zone->nodes); | ||
| 399 | if (!node) | ||
| 400 | return -ENOMEM; | ||
| 401 | *dst = node; | ||
| 402 | } | ||
| 403 | |||
| 404 | index = block_nr >> ((i - 1) * BM_RTREE_LEVEL_SHIFT); | ||
| 405 | index &= BM_RTREE_LEVEL_MASK; | ||
| 406 | dst = (struct rtree_node **)&((*dst)->data[index]); | ||
| 407 | node = *dst; | ||
| 314 | } | 408 | } |
| 315 | 409 | ||
| 410 | zone->blocks += 1; | ||
| 411 | *dst = block; | ||
| 412 | |||
| 316 | return 0; | 413 | return 0; |
| 317 | } | 414 | } |
| 318 | 415 | ||
| 416 | static void free_zone_bm_rtree(struct mem_zone_bm_rtree *zone, | ||
| 417 | int clear_nosave_free); | ||
| 418 | |||
| 419 | /* | ||
| 420 | * create_zone_bm_rtree - create a radix tree for one zone | ||
| 421 | * | ||
| 422 | * Allocated the mem_zone_bm_rtree structure and initializes it. | ||
| 423 | * This function also allocated and builds the radix tree for the | ||
| 424 | * zone. | ||
| 425 | */ | ||
| 426 | static struct mem_zone_bm_rtree * | ||
| 427 | create_zone_bm_rtree(gfp_t gfp_mask, int safe_needed, | ||
| 428 | struct chain_allocator *ca, | ||
| 429 | unsigned long start, unsigned long end) | ||
| 430 | { | ||
| 431 | struct mem_zone_bm_rtree *zone; | ||
| 432 | unsigned int i, nr_blocks; | ||
| 433 | unsigned long pages; | ||
| 434 | |||
| 435 | pages = end - start; | ||
| 436 | zone = chain_alloc(ca, sizeof(struct mem_zone_bm_rtree)); | ||
| 437 | if (!zone) | ||
| 438 | return NULL; | ||
| 439 | |||
| 440 | INIT_LIST_HEAD(&zone->nodes); | ||
| 441 | INIT_LIST_HEAD(&zone->leaves); | ||
| 442 | zone->start_pfn = start; | ||
| 443 | zone->end_pfn = end; | ||
| 444 | nr_blocks = DIV_ROUND_UP(pages, BM_BITS_PER_BLOCK); | ||
| 445 | |||
| 446 | for (i = 0; i < nr_blocks; i++) { | ||
| 447 | if (add_rtree_block(zone, gfp_mask, safe_needed, ca)) { | ||
| 448 | free_zone_bm_rtree(zone, PG_UNSAFE_CLEAR); | ||
| 449 | return NULL; | ||
| 450 | } | ||
| 451 | } | ||
| 452 | |||
| 453 | return zone; | ||
| 454 | } | ||
| 455 | |||
| 456 | /* | ||
| 457 | * free_zone_bm_rtree - Free the memory of the radix tree | ||
| 458 | * | ||
| 459 | * Free all node pages of the radix tree. The mem_zone_bm_rtree | ||
| 460 | * structure itself is not freed here nor are the rtree_node | ||
| 461 | * structs. | ||
| 462 | */ | ||
| 463 | static void free_zone_bm_rtree(struct mem_zone_bm_rtree *zone, | ||
| 464 | int clear_nosave_free) | ||
| 465 | { | ||
| 466 | struct rtree_node *node; | ||
| 467 | |||
| 468 | list_for_each_entry(node, &zone->nodes, list) | ||
| 469 | free_image_page(node->data, clear_nosave_free); | ||
| 470 | |||
| 471 | list_for_each_entry(node, &zone->leaves, list) | ||
| 472 | free_image_page(node->data, clear_nosave_free); | ||
| 473 | } | ||
| 474 | |||
| 475 | static void memory_bm_position_reset(struct memory_bitmap *bm) | ||
| 476 | { | ||
| 477 | bm->cur.zone = list_entry(bm->zones.next, struct mem_zone_bm_rtree, | ||
| 478 | list); | ||
| 479 | bm->cur.node = list_entry(bm->cur.zone->leaves.next, | ||
| 480 | struct rtree_node, list); | ||
| 481 | bm->cur.node_pfn = 0; | ||
| 482 | bm->cur.node_bit = 0; | ||
| 483 | } | ||
| 484 | |||
| 485 | static void memory_bm_free(struct memory_bitmap *bm, int clear_nosave_free); | ||
| 486 | |||
| 319 | struct mem_extent { | 487 | struct mem_extent { |
| 320 | struct list_head hook; | 488 | struct list_head hook; |
| 321 | unsigned long start; | 489 | unsigned long start; |
| @@ -407,40 +575,22 @@ memory_bm_create(struct memory_bitmap *bm, gfp_t gfp_mask, int safe_needed) | |||
| 407 | int error; | 575 | int error; |
| 408 | 576 | ||
| 409 | chain_init(&ca, gfp_mask, safe_needed); | 577 | chain_init(&ca, gfp_mask, safe_needed); |
| 410 | INIT_LIST_HEAD(&bm->blocks); | 578 | INIT_LIST_HEAD(&bm->zones); |
| 411 | 579 | ||
| 412 | error = create_mem_extents(&mem_extents, gfp_mask); | 580 | error = create_mem_extents(&mem_extents, gfp_mask); |
| 413 | if (error) | 581 | if (error) |
| 414 | return error; | 582 | return error; |
| 415 | 583 | ||
| 416 | list_for_each_entry(ext, &mem_extents, hook) { | 584 | list_for_each_entry(ext, &mem_extents, hook) { |
| 417 | struct bm_block *bb; | 585 | struct mem_zone_bm_rtree *zone; |
| 418 | unsigned long pfn = ext->start; | ||
| 419 | unsigned long pages = ext->end - ext->start; | ||
| 420 | |||
| 421 | bb = list_entry(bm->blocks.prev, struct bm_block, hook); | ||
| 422 | 586 | ||
| 423 | error = create_bm_block_list(pages, bm->blocks.prev, &ca); | 587 | zone = create_zone_bm_rtree(gfp_mask, safe_needed, &ca, |
| 424 | if (error) | 588 | ext->start, ext->end); |
| 589 | if (!zone) { | ||
| 590 | error = -ENOMEM; | ||
| 425 | goto Error; | 591 | goto Error; |
| 426 | |||
| 427 | list_for_each_entry_continue(bb, &bm->blocks, hook) { | ||
| 428 | bb->data = get_image_page(gfp_mask, safe_needed); | ||
| 429 | if (!bb->data) { | ||
| 430 | error = -ENOMEM; | ||
| 431 | goto Error; | ||
| 432 | } | ||
| 433 | |||
| 434 | bb->start_pfn = pfn; | ||
| 435 | if (pages >= BM_BITS_PER_BLOCK) { | ||
| 436 | pfn += BM_BITS_PER_BLOCK; | ||
| 437 | pages -= BM_BITS_PER_BLOCK; | ||
| 438 | } else { | ||
| 439 | /* This is executed only once in the loop */ | ||
| 440 | pfn += pages; | ||
| 441 | } | ||
| 442 | bb->end_pfn = pfn; | ||
| 443 | } | 592 | } |
| 593 | list_add_tail(&zone->list, &bm->zones); | ||
| 444 | } | 594 | } |
| 445 | 595 | ||
| 446 | bm->p_list = ca.chain; | 596 | bm->p_list = ca.chain; |
| @@ -460,51 +610,83 @@ memory_bm_create(struct memory_bitmap *bm, gfp_t gfp_mask, int safe_needed) | |||
| 460 | */ | 610 | */ |
| 461 | static void memory_bm_free(struct memory_bitmap *bm, int clear_nosave_free) | 611 | static void memory_bm_free(struct memory_bitmap *bm, int clear_nosave_free) |
| 462 | { | 612 | { |
| 463 | struct bm_block *bb; | 613 | struct mem_zone_bm_rtree *zone; |
| 464 | 614 | ||
| 465 | list_for_each_entry(bb, &bm->blocks, hook) | 615 | list_for_each_entry(zone, &bm->zones, list) |
| 466 | if (bb->data) | 616 | free_zone_bm_rtree(zone, clear_nosave_free); |
| 467 | free_image_page(bb->data, clear_nosave_free); | ||
| 468 | 617 | ||
| 469 | free_list_of_pages(bm->p_list, clear_nosave_free); | 618 | free_list_of_pages(bm->p_list, clear_nosave_free); |
| 470 | 619 | ||
| 471 | INIT_LIST_HEAD(&bm->blocks); | 620 | INIT_LIST_HEAD(&bm->zones); |
| 472 | } | 621 | } |
| 473 | 622 | ||
| 474 | /** | 623 | /** |
| 475 | * memory_bm_find_bit - find the bit in the bitmap @bm that corresponds | 624 | * memory_bm_find_bit - Find the bit for pfn in the memory |
| 476 | * to given pfn. The cur_zone_bm member of @bm and the cur_block member | 625 | * bitmap |
| 477 | * of @bm->cur_zone_bm are updated. | 626 | * |
| 627 | * Find the bit in the bitmap @bm that corresponds to given pfn. | ||
| 628 | * The cur.zone, cur.block and cur.node_pfn member of @bm are | ||
| 629 | * updated. | ||
| 630 | * It walks the radix tree to find the page which contains the bit for | ||
| 631 | * pfn and returns the bit position in **addr and *bit_nr. | ||
| 478 | */ | 632 | */ |
| 479 | static int memory_bm_find_bit(struct memory_bitmap *bm, unsigned long pfn, | 633 | static int memory_bm_find_bit(struct memory_bitmap *bm, unsigned long pfn, |
| 480 | void **addr, unsigned int *bit_nr) | 634 | void **addr, unsigned int *bit_nr) |
| 481 | { | 635 | { |
| 482 | struct bm_block *bb; | 636 | struct mem_zone_bm_rtree *curr, *zone; |
| 637 | struct rtree_node *node; | ||
| 638 | int i, block_nr; | ||
| 483 | 639 | ||
| 640 | zone = bm->cur.zone; | ||
| 641 | |||
| 642 | if (pfn >= zone->start_pfn && pfn < zone->end_pfn) | ||
| 643 | goto zone_found; | ||
| 644 | |||
| 645 | zone = NULL; | ||
| 646 | |||
| 647 | /* Find the right zone */ | ||
| 648 | list_for_each_entry(curr, &bm->zones, list) { | ||
| 649 | if (pfn >= curr->start_pfn && pfn < curr->end_pfn) { | ||
| 650 | zone = curr; | ||
| 651 | break; | ||
| 652 | } | ||
| 653 | } | ||
| 654 | |||
| 655 | if (!zone) | ||
| 656 | return -EFAULT; | ||
| 657 | |||
| 658 | zone_found: | ||
| 484 | /* | 659 | /* |
| 485 | * Check if the pfn corresponds to the current bitmap block and find | 660 | * We have a zone. Now walk the radix tree to find the leave |
| 486 | * the block where it fits if this is not the case. | 661 | * node for our pfn. |
| 487 | */ | 662 | */ |
| 488 | bb = bm->cur.block; | ||
| 489 | if (pfn < bb->start_pfn) | ||
| 490 | list_for_each_entry_continue_reverse(bb, &bm->blocks, hook) | ||
| 491 | if (pfn >= bb->start_pfn) | ||
| 492 | break; | ||
| 493 | 663 | ||
| 494 | if (pfn >= bb->end_pfn) | 664 | node = bm->cur.node; |
| 495 | list_for_each_entry_continue(bb, &bm->blocks, hook) | 665 | if (((pfn - zone->start_pfn) & ~BM_BLOCK_MASK) == bm->cur.node_pfn) |
| 496 | if (pfn >= bb->start_pfn && pfn < bb->end_pfn) | 666 | goto node_found; |
| 497 | break; | ||
| 498 | 667 | ||
| 499 | if (&bb->hook == &bm->blocks) | 668 | node = zone->rtree; |
| 500 | return -EFAULT; | 669 | block_nr = (pfn - zone->start_pfn) >> BM_BLOCK_SHIFT; |
| 670 | |||
| 671 | for (i = zone->levels; i > 0; i--) { | ||
| 672 | int index; | ||
| 673 | |||
| 674 | index = block_nr >> ((i - 1) * BM_RTREE_LEVEL_SHIFT); | ||
| 675 | index &= BM_RTREE_LEVEL_MASK; | ||
| 676 | BUG_ON(node->data[index] == 0); | ||
| 677 | node = (struct rtree_node *)node->data[index]; | ||
| 678 | } | ||
| 679 | |||
| 680 | node_found: | ||
| 681 | /* Update last position */ | ||
| 682 | bm->cur.zone = zone; | ||
| 683 | bm->cur.node = node; | ||
| 684 | bm->cur.node_pfn = (pfn - zone->start_pfn) & ~BM_BLOCK_MASK; | ||
| 685 | |||
| 686 | /* Set return values */ | ||
| 687 | *addr = node->data; | ||
| 688 | *bit_nr = (pfn - zone->start_pfn) & BM_BLOCK_MASK; | ||
| 501 | 689 | ||
| 502 | /* The block has been found */ | ||
| 503 | bm->cur.block = bb; | ||
| 504 | pfn -= bb->start_pfn; | ||
| 505 | bm->cur.bit = pfn + 1; | ||
| 506 | *bit_nr = pfn; | ||
| 507 | *addr = bb->data; | ||
| 508 | return 0; | 690 | return 0; |
| 509 | } | 691 | } |
| 510 | 692 | ||
| @@ -528,6 +710,7 @@ static int mem_bm_set_bit_check(struct memory_bitmap *bm, unsigned long pfn) | |||
| 528 | error = memory_bm_find_bit(bm, pfn, &addr, &bit); | 710 | error = memory_bm_find_bit(bm, pfn, &addr, &bit); |
| 529 | if (!error) | 711 | if (!error) |
| 530 | set_bit(bit, addr); | 712 | set_bit(bit, addr); |
| 713 | |||
| 531 | return error; | 714 | return error; |
| 532 | } | 715 | } |
| 533 | 716 | ||
| @@ -542,6 +725,14 @@ static void memory_bm_clear_bit(struct memory_bitmap *bm, unsigned long pfn) | |||
| 542 | clear_bit(bit, addr); | 725 | clear_bit(bit, addr); |
| 543 | } | 726 | } |
| 544 | 727 | ||
| 728 | static 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 | |||
| 545 | static int memory_bm_test_bit(struct memory_bitmap *bm, unsigned long pfn) | 736 | static int memory_bm_test_bit(struct memory_bitmap *bm, unsigned long pfn) |
| 546 | { | 737 | { |
| 547 | void *addr; | 738 | void *addr; |
| @@ -561,38 +752,70 @@ static bool memory_bm_pfn_present(struct memory_bitmap *bm, unsigned long pfn) | |||
| 561 | return !memory_bm_find_bit(bm, pfn, &addr, &bit); | 752 | return !memory_bm_find_bit(bm, pfn, &addr, &bit); |
| 562 | } | 753 | } |
| 563 | 754 | ||
| 564 | /** | 755 | /* |
| 565 | * memory_bm_next_pfn - find the pfn that corresponds to the next set bit | 756 | * rtree_next_node - Jumps to the next leave node |
| 566 | * in the bitmap @bm. If the pfn cannot be found, BM_END_OF_MAP is | 757 | * |
| 567 | * returned. | 758 | * Sets the position to the beginning of the next node in the |
| 759 | * memory bitmap. This is either the next node in the current | ||
| 760 | * zone's radix tree or the first node in the radix tree of the | ||
| 761 | * next zone. | ||
| 568 | * | 762 | * |
| 569 | * It is required to run memory_bm_position_reset() before the first call to | 763 | * Returns true if there is a next node, false otherwise. |
| 570 | * this function. | ||
| 571 | */ | 764 | */ |
| 765 | static bool rtree_next_node(struct memory_bitmap *bm) | ||
| 766 | { | ||
| 767 | bm->cur.node = list_entry(bm->cur.node->list.next, | ||
| 768 | struct rtree_node, list); | ||
| 769 | if (&bm->cur.node->list != &bm->cur.zone->leaves) { | ||
| 770 | bm->cur.node_pfn += BM_BITS_PER_BLOCK; | ||
| 771 | bm->cur.node_bit = 0; | ||
| 772 | touch_softlockup_watchdog(); | ||
| 773 | return true; | ||
| 774 | } | ||
| 775 | |||
| 776 | /* No more nodes, goto next zone */ | ||
| 777 | bm->cur.zone = list_entry(bm->cur.zone->list.next, | ||
| 778 | struct mem_zone_bm_rtree, list); | ||
| 779 | if (&bm->cur.zone->list != &bm->zones) { | ||
| 780 | bm->cur.node = list_entry(bm->cur.zone->leaves.next, | ||
| 781 | struct rtree_node, list); | ||
| 782 | bm->cur.node_pfn = 0; | ||
| 783 | bm->cur.node_bit = 0; | ||
| 784 | return true; | ||
| 785 | } | ||
| 572 | 786 | ||
| 787 | /* No more zones */ | ||
| 788 | return false; | ||
| 789 | } | ||
| 790 | |||
| 791 | /** | ||
| 792 | * memory_bm_rtree_next_pfn - Find the next set bit in the bitmap @bm | ||
| 793 | * | ||
| 794 | * Starting from the last returned position this function searches | ||
| 795 | * for the next set bit in the memory bitmap and returns its | ||
| 796 | * number. If no more bit is set BM_END_OF_MAP is returned. | ||
| 797 | * | ||
| 798 | * It is required to run memory_bm_position_reset() before the | ||
| 799 | * first call to this function. | ||
| 800 | */ | ||
| 573 | static unsigned long memory_bm_next_pfn(struct memory_bitmap *bm) | 801 | static unsigned long memory_bm_next_pfn(struct memory_bitmap *bm) |
| 574 | { | 802 | { |
| 575 | struct bm_block *bb; | 803 | unsigned long bits, pfn, pages; |
| 576 | int bit; | 804 | int bit; |
| 577 | 805 | ||
| 578 | bb = bm->cur.block; | ||
| 579 | do { | 806 | do { |
| 580 | bit = bm->cur.bit; | 807 | pages = bm->cur.zone->end_pfn - bm->cur.zone->start_pfn; |
| 581 | bit = find_next_bit(bb->data, bm_block_bits(bb), bit); | 808 | bits = min(pages - bm->cur.node_pfn, BM_BITS_PER_BLOCK); |
| 582 | if (bit < bm_block_bits(bb)) | 809 | bit = find_next_bit(bm->cur.node->data, bits, |
| 583 | goto Return_pfn; | 810 | bm->cur.node_bit); |
| 584 | 811 | if (bit < bits) { | |
| 585 | bb = list_entry(bb->hook.next, struct bm_block, hook); | 812 | pfn = bm->cur.zone->start_pfn + bm->cur.node_pfn + bit; |
| 586 | bm->cur.block = bb; | 813 | bm->cur.node_bit = bit + 1; |
| 587 | bm->cur.bit = 0; | 814 | return pfn; |
| 588 | } while (&bb->hook != &bm->blocks); | 815 | } |
| 816 | } while (rtree_next_node(bm)); | ||
| 589 | 817 | ||
| 590 | memory_bm_position_reset(bm); | ||
| 591 | return BM_END_OF_MAP; | 818 | return BM_END_OF_MAP; |
| 592 | |||
| 593 | Return_pfn: | ||
| 594 | bm->cur.bit = bit + 1; | ||
| 595 | return bb->start_pfn + bit; | ||
| 596 | } | 819 | } |
| 597 | 820 | ||
| 598 | /** | 821 | /** |
| @@ -816,12 +1039,17 @@ void free_basic_memory_bitmaps(void) | |||
| 816 | 1039 | ||
| 817 | unsigned int snapshot_additional_pages(struct zone *zone) | 1040 | unsigned int snapshot_additional_pages(struct zone *zone) |
| 818 | { | 1041 | { |
| 819 | unsigned int res; | 1042 | unsigned int rtree, nodes; |
| 1043 | |||
| 1044 | rtree = nodes = DIV_ROUND_UP(zone->spanned_pages, BM_BITS_PER_BLOCK); | ||
| 1045 | rtree += DIV_ROUND_UP(rtree * sizeof(struct rtree_node), | ||
| 1046 | LINKED_PAGE_DATA_SIZE); | ||
| 1047 | while (nodes > 1) { | ||
| 1048 | nodes = DIV_ROUND_UP(nodes, BM_ENTRIES_PER_LEVEL); | ||
| 1049 | rtree += nodes; | ||
| 1050 | } | ||
| 820 | 1051 | ||
| 821 | res = DIV_ROUND_UP(zone->spanned_pages, BM_BITS_PER_BLOCK); | 1052 | return 2 * rtree; |
| 822 | res += DIV_ROUND_UP(res * sizeof(struct bm_block), | ||
| 823 | LINKED_PAGE_DATA_SIZE); | ||
| 824 | return 2 * res; | ||
| 825 | } | 1053 | } |
| 826 | 1054 | ||
| 827 | #ifdef CONFIG_HIGHMEM | 1055 | #ifdef CONFIG_HIGHMEM |
| @@ -1094,23 +1322,35 @@ static struct memory_bitmap copy_bm; | |||
| 1094 | 1322 | ||
| 1095 | void swsusp_free(void) | 1323 | void swsusp_free(void) |
| 1096 | { | 1324 | { |
| 1097 | struct zone *zone; | 1325 | unsigned long fb_pfn, fr_pfn; |
| 1098 | unsigned long pfn, max_zone_pfn; | ||
| 1099 | 1326 | ||
| 1100 | for_each_populated_zone(zone) { | 1327 | memory_bm_position_reset(forbidden_pages_map); |
| 1101 | max_zone_pfn = zone_end_pfn(zone); | 1328 | memory_bm_position_reset(free_pages_map); |
| 1102 | for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++) | 1329 | |
| 1103 | if (pfn_valid(pfn)) { | 1330 | loop: |
| 1104 | struct page *page = pfn_to_page(pfn); | 1331 | fr_pfn = memory_bm_next_pfn(free_pages_map); |
| 1105 | 1332 | fb_pfn = memory_bm_next_pfn(forbidden_pages_map); | |
| 1106 | if (swsusp_page_is_forbidden(page) && | 1333 | |
| 1107 | swsusp_page_is_free(page)) { | 1334 | /* |
| 1108 | swsusp_unset_page_forbidden(page); | 1335 | * Find the next bit set in both bitmaps. This is guaranteed to |
| 1109 | swsusp_unset_page_free(page); | 1336 | * terminate when fb_pfn == fr_pfn == BM_END_OF_MAP. |
| 1110 | __free_page(page); | 1337 | */ |
| 1111 | } | 1338 | do { |
| 1112 | } | 1339 | if (fb_pfn < fr_pfn) |
| 1340 | fb_pfn = memory_bm_next_pfn(forbidden_pages_map); | ||
| 1341 | if (fr_pfn < fb_pfn) | ||
| 1342 | fr_pfn = memory_bm_next_pfn(free_pages_map); | ||
| 1343 | } while (fb_pfn != fr_pfn); | ||
| 1344 | |||
| 1345 | if (fr_pfn != BM_END_OF_MAP && pfn_valid(fr_pfn)) { | ||
| 1346 | struct page *page = pfn_to_page(fr_pfn); | ||
| 1347 | |||
| 1348 | memory_bm_clear_current(forbidden_pages_map); | ||
| 1349 | memory_bm_clear_current(free_pages_map); | ||
| 1350 | __free_page(page); | ||
| 1351 | goto loop; | ||
| 1113 | } | 1352 | } |
| 1353 | |||
| 1114 | nr_copy_pages = 0; | 1354 | nr_copy_pages = 0; |
| 1115 | nr_meta_pages = 0; | 1355 | nr_meta_pages = 0; |
| 1116 | restore_pblist = NULL; | 1356 | restore_pblist = NULL; |
