diff options
| -rw-r--r-- | kernel/power/snapshot.c | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 0b7f93498077..802f2415408e 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c | |||
| @@ -309,6 +309,11 @@ struct mem_zone_bm_rtree { | |||
| 309 | struct bm_position { | 309 | struct bm_position { |
| 310 | struct bm_block *block; | 310 | struct bm_block *block; |
| 311 | int bit; | 311 | int bit; |
| 312 | |||
| 313 | struct mem_zone_bm_rtree *zone; | ||
| 314 | struct rtree_node *node; | ||
| 315 | unsigned long node_pfn; | ||
| 316 | int node_bit; | ||
| 312 | }; | 317 | }; |
| 313 | 318 | ||
| 314 | struct memory_bitmap { | 319 | struct memory_bitmap { |
| @@ -487,6 +492,13 @@ static void memory_bm_position_reset(struct memory_bitmap *bm) | |||
| 487 | { | 492 | { |
| 488 | bm->cur.block = list_entry(bm->blocks.next, struct bm_block, hook); | 493 | bm->cur.block = list_entry(bm->blocks.next, struct bm_block, hook); |
| 489 | bm->cur.bit = 0; | 494 | bm->cur.bit = 0; |
| 495 | |||
| 496 | bm->cur.zone = list_entry(bm->zones.next, struct mem_zone_bm_rtree, | ||
| 497 | list); | ||
| 498 | bm->cur.node = list_entry(bm->cur.zone->leaves.next, | ||
| 499 | struct rtree_node, list); | ||
| 500 | bm->cur.node_pfn = 0; | ||
| 501 | bm->cur.node_bit = 0; | ||
| 490 | } | 502 | } |
| 491 | 503 | ||
| 492 | static void memory_bm_free(struct memory_bitmap *bm, int clear_nosave_free); | 504 | static void memory_bm_free(struct memory_bitmap *bm, int clear_nosave_free); |
| @@ -734,6 +746,11 @@ static int memory_rtree_find_bit(struct memory_bitmap *bm, unsigned long pfn, | |||
| 734 | struct rtree_node *node; | 746 | struct rtree_node *node; |
| 735 | int i, block_nr; | 747 | int i, block_nr; |
| 736 | 748 | ||
| 749 | zone = bm->cur.zone; | ||
| 750 | |||
| 751 | if (pfn >= zone->start_pfn && pfn < zone->end_pfn) | ||
| 752 | goto zone_found; | ||
| 753 | |||
| 737 | zone = NULL; | 754 | zone = NULL; |
| 738 | 755 | ||
| 739 | /* Find the right zone */ | 756 | /* Find the right zone */ |
| @@ -747,10 +764,16 @@ static int memory_rtree_find_bit(struct memory_bitmap *bm, unsigned long pfn, | |||
| 747 | if (!zone) | 764 | if (!zone) |
| 748 | return -EFAULT; | 765 | return -EFAULT; |
| 749 | 766 | ||
| 767 | zone_found: | ||
| 750 | /* | 768 | /* |
| 751 | * We have a zone. Now walk the radix tree to find the leave | 769 | * We have a zone. Now walk the radix tree to find the leave |
| 752 | * node for our pfn. | 770 | * node for our pfn. |
| 753 | */ | 771 | */ |
| 772 | |||
| 773 | node = bm->cur.node; | ||
| 774 | if (((pfn - zone->start_pfn) & ~BM_BLOCK_MASK) == bm->cur.node_pfn) | ||
| 775 | goto node_found; | ||
| 776 | |||
| 754 | node = zone->rtree; | 777 | node = zone->rtree; |
| 755 | block_nr = (pfn - zone->start_pfn) >> BM_BLOCK_SHIFT; | 778 | block_nr = (pfn - zone->start_pfn) >> BM_BLOCK_SHIFT; |
| 756 | 779 | ||
| @@ -763,6 +786,12 @@ static int memory_rtree_find_bit(struct memory_bitmap *bm, unsigned long pfn, | |||
| 763 | node = (struct rtree_node *)node->data[index]; | 786 | node = (struct rtree_node *)node->data[index]; |
| 764 | } | 787 | } |
| 765 | 788 | ||
| 789 | node_found: | ||
| 790 | /* Update last position */ | ||
| 791 | bm->cur.zone = zone; | ||
| 792 | bm->cur.node = node; | ||
| 793 | bm->cur.node_pfn = (pfn - zone->start_pfn) & ~BM_BLOCK_MASK; | ||
| 794 | |||
| 766 | /* Set return values */ | 795 | /* Set return values */ |
| 767 | *addr = node->data; | 796 | *addr = node->data; |
| 768 | *bit_nr = (pfn - zone->start_pfn) & BM_BLOCK_MASK; | 797 | *bit_nr = (pfn - zone->start_pfn) & BM_BLOCK_MASK; |
| @@ -860,11 +889,16 @@ static bool memory_bm_pfn_present(struct memory_bitmap *bm, unsigned long pfn) | |||
| 860 | * this function. | 889 | * this function. |
| 861 | */ | 890 | */ |
| 862 | 891 | ||
| 892 | static unsigned long memory_bm_rtree_next_pfn(struct memory_bitmap *bm); | ||
| 893 | |||
| 863 | static unsigned long memory_bm_next_pfn(struct memory_bitmap *bm) | 894 | static unsigned long memory_bm_next_pfn(struct memory_bitmap *bm) |
| 864 | { | 895 | { |
| 896 | unsigned long rtree_pfn; | ||
| 865 | struct bm_block *bb; | 897 | struct bm_block *bb; |
| 866 | int bit; | 898 | int bit; |
| 867 | 899 | ||
| 900 | rtree_pfn = memory_bm_rtree_next_pfn(bm); | ||
| 901 | |||
| 868 | bb = bm->cur.block; | 902 | bb = bm->cur.block; |
| 869 | do { | 903 | do { |
| 870 | bit = bm->cur.bit; | 904 | bit = bm->cur.bit; |
| @@ -878,13 +912,77 @@ static unsigned long memory_bm_next_pfn(struct memory_bitmap *bm) | |||
| 878 | } while (&bb->hook != &bm->blocks); | 912 | } while (&bb->hook != &bm->blocks); |
| 879 | 913 | ||
| 880 | memory_bm_position_reset(bm); | 914 | memory_bm_position_reset(bm); |
| 915 | WARN_ON_ONCE(rtree_pfn != BM_END_OF_MAP); | ||
| 881 | return BM_END_OF_MAP; | 916 | return BM_END_OF_MAP; |
| 882 | 917 | ||
| 883 | Return_pfn: | 918 | Return_pfn: |
| 919 | WARN_ON_ONCE(bb->start_pfn + bit != rtree_pfn); | ||
| 884 | bm->cur.bit = bit + 1; | 920 | bm->cur.bit = bit + 1; |
| 885 | return bb->start_pfn + bit; | 921 | return bb->start_pfn + bit; |
| 886 | } | 922 | } |
| 887 | 923 | ||
| 924 | /* | ||
| 925 | * rtree_next_node - Jumps to the next leave node | ||
| 926 | * | ||
| 927 | * Sets the position to the beginning of the next node in the | ||
| 928 | * memory bitmap. This is either the next node in the current | ||
| 929 | * zone's radix tree or the first node in the radix tree of the | ||
| 930 | * next zone. | ||
| 931 | * | ||
| 932 | * Returns true if there is a next node, false otherwise. | ||
| 933 | */ | ||
| 934 | static bool rtree_next_node(struct memory_bitmap *bm) | ||
| 935 | { | ||
| 936 | bm->cur.node = list_entry(bm->cur.node->list.next, | ||
| 937 | struct rtree_node, list); | ||
| 938 | if (&bm->cur.node->list != &bm->cur.zone->leaves) { | ||
| 939 | bm->cur.node_pfn += BM_BITS_PER_BLOCK; | ||
| 940 | bm->cur.node_bit = 0; | ||
| 941 | return true; | ||
| 942 | } | ||
| 943 | |||
| 944 | /* No more nodes, goto next zone */ | ||
| 945 | bm->cur.zone = list_entry(bm->cur.zone->list.next, | ||
| 946 | struct mem_zone_bm_rtree, list); | ||
| 947 | if (&bm->cur.zone->list != &bm->zones) { | ||
| 948 | bm->cur.node = list_entry(bm->cur.zone->leaves.next, | ||
| 949 | struct rtree_node, list); | ||
| 950 | bm->cur.node_pfn = 0; | ||
| 951 | bm->cur.node_bit = 0; | ||
| 952 | return true; | ||
| 953 | } | ||
| 954 | |||
| 955 | /* No more zones */ | ||
| 956 | return false; | ||
| 957 | } | ||
| 958 | |||
| 959 | /* | ||
| 960 | * memory_bm_rtree_next_pfn - Find the next set bit | ||
| 961 | * | ||
| 962 | * Starting from the last returned position this function searches | ||
| 963 | * for the next set bit in the memory bitmap and returns its | ||
| 964 | * number. If no more bit is set BM_END_OF_MAP is returned. | ||
| 965 | */ | ||
| 966 | static unsigned long memory_bm_rtree_next_pfn(struct memory_bitmap *bm) | ||
| 967 | { | ||
| 968 | unsigned long bits, pfn, pages; | ||
| 969 | int bit; | ||
| 970 | |||
| 971 | do { | ||
| 972 | pages = bm->cur.zone->end_pfn - bm->cur.zone->start_pfn; | ||
| 973 | bits = min(pages - bm->cur.node_pfn, BM_BITS_PER_BLOCK); | ||
| 974 | bit = find_next_bit(bm->cur.node->data, bits, | ||
| 975 | bm->cur.node_bit); | ||
| 976 | if (bit < bits) { | ||
| 977 | pfn = bm->cur.zone->start_pfn + bm->cur.node_pfn + bit; | ||
| 978 | bm->cur.node_bit = bit + 1; | ||
| 979 | return pfn; | ||
| 980 | } | ||
| 981 | } while (rtree_next_node(bm)); | ||
| 982 | |||
| 983 | return BM_END_OF_MAP; | ||
| 984 | } | ||
| 985 | |||
| 888 | /** | 986 | /** |
| 889 | * This structure represents a range of page frames the contents of which | 987 | * This structure represents a range of page frames the contents of which |
| 890 | * should not be saved during the suspend. | 988 | * should not be saved during the suspend. |
