diff options
| -rw-r--r-- | kernel/power/snapshot.c | 84 |
1 files changed, 81 insertions, 3 deletions
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 5a0eafdbac79..0b7f93498077 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c | |||
| @@ -720,6 +720,56 @@ static int memory_bm_find_bit(struct memory_bitmap *bm, unsigned long pfn, | |||
| 720 | return 0; | 720 | return 0; |
| 721 | } | 721 | } |
| 722 | 722 | ||
| 723 | /* | ||
| 724 | * memory_rtree_find_bit - Find the bit for pfn in the memory | ||
| 725 | * bitmap | ||
| 726 | * | ||
| 727 | * Walks the radix tree to find the page which contains the bit for | ||
| 728 | * pfn and returns the bit position in **addr and *bit_nr. | ||
| 729 | */ | ||
| 730 | static int memory_rtree_find_bit(struct memory_bitmap *bm, unsigned long pfn, | ||
| 731 | void **addr, unsigned int *bit_nr) | ||
| 732 | { | ||
| 733 | struct mem_zone_bm_rtree *curr, *zone; | ||
| 734 | struct rtree_node *node; | ||
| 735 | int i, block_nr; | ||
| 736 | |||
| 737 | zone = NULL; | ||
| 738 | |||
| 739 | /* Find the right zone */ | ||
| 740 | list_for_each_entry(curr, &bm->zones, list) { | ||
| 741 | if (pfn >= curr->start_pfn && pfn < curr->end_pfn) { | ||
| 742 | zone = curr; | ||
| 743 | break; | ||
| 744 | } | ||
| 745 | } | ||
| 746 | |||
| 747 | if (!zone) | ||
| 748 | return -EFAULT; | ||
| 749 | |||
| 750 | /* | ||
| 751 | * We have a zone. Now walk the radix tree to find the leave | ||
| 752 | * node for our pfn. | ||
| 753 | */ | ||
| 754 | node = zone->rtree; | ||
| 755 | block_nr = (pfn - zone->start_pfn) >> BM_BLOCK_SHIFT; | ||
| 756 | |||
| 757 | for (i = zone->levels; i > 0; i--) { | ||
| 758 | int index; | ||
| 759 | |||
| 760 | index = block_nr >> ((i - 1) * BM_RTREE_LEVEL_SHIFT); | ||
| 761 | index &= BM_RTREE_LEVEL_MASK; | ||
| 762 | BUG_ON(node->data[index] == 0); | ||
| 763 | node = (struct rtree_node *)node->data[index]; | ||
| 764 | } | ||
| 765 | |||
| 766 | /* Set return values */ | ||
| 767 | *addr = node->data; | ||
| 768 | *bit_nr = (pfn - zone->start_pfn) & BM_BLOCK_MASK; | ||
| 769 | |||
| 770 | return 0; | ||
| 771 | } | ||
| 772 | |||
| 723 | static void memory_bm_set_bit(struct memory_bitmap *bm, unsigned long pfn) | 773 | static void memory_bm_set_bit(struct memory_bitmap *bm, unsigned long pfn) |
| 724 | { | 774 | { |
| 725 | void *addr; | 775 | void *addr; |
| @@ -729,6 +779,10 @@ static void memory_bm_set_bit(struct memory_bitmap *bm, unsigned long pfn) | |||
| 729 | error = memory_bm_find_bit(bm, pfn, &addr, &bit); | 779 | error = memory_bm_find_bit(bm, pfn, &addr, &bit); |
| 730 | BUG_ON(error); | 780 | BUG_ON(error); |
| 731 | set_bit(bit, addr); | 781 | set_bit(bit, addr); |
| 782 | |||
| 783 | error = memory_rtree_find_bit(bm, pfn, &addr, &bit); | ||
| 784 | BUG_ON(error); | ||
| 785 | set_bit(bit, addr); | ||
| 732 | } | 786 | } |
| 733 | 787 | ||
| 734 | static int mem_bm_set_bit_check(struct memory_bitmap *bm, unsigned long pfn) | 788 | static int mem_bm_set_bit_check(struct memory_bitmap *bm, unsigned long pfn) |
| @@ -740,6 +794,13 @@ static int mem_bm_set_bit_check(struct memory_bitmap *bm, unsigned long pfn) | |||
| 740 | error = memory_bm_find_bit(bm, pfn, &addr, &bit); | 794 | error = memory_bm_find_bit(bm, pfn, &addr, &bit); |
| 741 | if (!error) | 795 | if (!error) |
| 742 | set_bit(bit, addr); | 796 | set_bit(bit, addr); |
| 797 | else | ||
| 798 | return error; | ||
| 799 | |||
| 800 | error = memory_rtree_find_bit(bm, pfn, &addr, &bit); | ||
| 801 | if (!error) | ||
| 802 | set_bit(bit, addr); | ||
| 803 | |||
| 743 | return error; | 804 | return error; |
| 744 | } | 805 | } |
| 745 | 806 | ||
| @@ -752,25 +813,42 @@ static void memory_bm_clear_bit(struct memory_bitmap *bm, unsigned long pfn) | |||
| 752 | error = memory_bm_find_bit(bm, pfn, &addr, &bit); | 813 | error = memory_bm_find_bit(bm, pfn, &addr, &bit); |
| 753 | BUG_ON(error); | 814 | BUG_ON(error); |
| 754 | clear_bit(bit, addr); | 815 | clear_bit(bit, addr); |
| 816 | |||
| 817 | error = memory_rtree_find_bit(bm, pfn, &addr, &bit); | ||
| 818 | BUG_ON(error); | ||
| 819 | clear_bit(bit, addr); | ||
| 755 | } | 820 | } |
| 756 | 821 | ||
| 757 | static int memory_bm_test_bit(struct memory_bitmap *bm, unsigned long pfn) | 822 | static int memory_bm_test_bit(struct memory_bitmap *bm, unsigned long pfn) |
| 758 | { | 823 | { |
| 759 | void *addr; | 824 | void *addr; |
| 760 | unsigned int bit; | 825 | unsigned int bit; |
| 761 | int error; | 826 | int error, error2; |
| 827 | int v; | ||
| 762 | 828 | ||
| 763 | error = memory_bm_find_bit(bm, pfn, &addr, &bit); | 829 | error = memory_bm_find_bit(bm, pfn, &addr, &bit); |
| 764 | BUG_ON(error); | 830 | BUG_ON(error); |
| 765 | return test_bit(bit, addr); | 831 | v = test_bit(bit, addr); |
| 832 | |||
| 833 | error2 = memory_rtree_find_bit(bm, pfn, &addr, &bit); | ||
| 834 | BUG_ON(error2); | ||
| 835 | |||
| 836 | WARN_ON_ONCE(v != test_bit(bit, addr)); | ||
| 837 | |||
| 838 | return v; | ||
| 766 | } | 839 | } |
| 767 | 840 | ||
| 768 | static bool memory_bm_pfn_present(struct memory_bitmap *bm, unsigned long pfn) | 841 | static bool memory_bm_pfn_present(struct memory_bitmap *bm, unsigned long pfn) |
| 769 | { | 842 | { |
| 770 | void *addr; | 843 | void *addr; |
| 771 | unsigned int bit; | 844 | unsigned int bit; |
| 845 | int present; | ||
| 846 | |||
| 847 | present = !memory_bm_find_bit(bm, pfn, &addr, &bit); | ||
| 848 | |||
| 849 | WARN_ON_ONCE(present != !memory_rtree_find_bit(bm, pfn, &addr, &bit)); | ||
| 772 | 850 | ||
| 773 | return !memory_bm_find_bit(bm, pfn, &addr, &bit); | 851 | return present; |
| 774 | } | 852 | } |
| 775 | 853 | ||
| 776 | /** | 854 | /** |
