diff options
author | Joerg Roedel <jroedel@suse.de> | 2014-07-21 06:26:59 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2014-07-28 19:47:44 -0400 |
commit | 3a20cb1779616ebcaade393cc9beac0e03cbffef (patch) | |
tree | f4552ea9a73fc2f055a6f23e4926faa9bbb28c04 | |
parent | 07a338236fdcd6caf41541dcdf879f5758020ab1 (diff) |
PM / Hibernate: Implement position keeping in radix tree
Add code to remember the last position that was requested in
the radix tree. Use it as a cache for faster linear walking
of the bitmap in the memory_bm_rtree_next_pfn() function
which is also added with this patch.
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.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. |