aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoerg Roedel <jroedel@suse.de>2014-07-21 06:26:59 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-07-28 19:47:44 -0400
commit3a20cb1779616ebcaade393cc9beac0e03cbffef (patch)
treef4552ea9a73fc2f055a6f23e4926faa9bbb28c04
parent07a338236fdcd6caf41541dcdf879f5758020ab1 (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.c98
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 {
309struct bm_position { 309struct 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
314struct memory_bitmap { 319struct 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
492static void memory_bm_free(struct memory_bitmap *bm, int clear_nosave_free); 504static 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
767zone_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
789node_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
892static unsigned long memory_bm_rtree_next_pfn(struct memory_bitmap *bm);
893
863static unsigned long memory_bm_next_pfn(struct memory_bitmap *bm) 894static 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 */
934static 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 */
966static 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.