diff options
Diffstat (limited to 'mm/page_alloc.c')
-rw-r--r-- | mm/page_alloc.c | 52 |
1 files changed, 32 insertions, 20 deletions
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 485932c577e7..6e937809c87a 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -6028,53 +6028,65 @@ static inline int pfn_to_bitidx(struct zone *zone, unsigned long pfn) | |||
6028 | * @end_bitidx: The last bit of interest | 6028 | * @end_bitidx: The last bit of interest |
6029 | * returns pageblock_bits flags | 6029 | * returns pageblock_bits flags |
6030 | */ | 6030 | */ |
6031 | unsigned long get_pageblock_flags_group(struct page *page, | 6031 | unsigned long get_pageblock_flags_mask(struct page *page, |
6032 | int start_bitidx, int end_bitidx) | 6032 | unsigned long end_bitidx, |
6033 | unsigned long mask) | ||
6033 | { | 6034 | { |
6034 | struct zone *zone; | 6035 | struct zone *zone; |
6035 | unsigned long *bitmap; | 6036 | unsigned long *bitmap; |
6036 | unsigned long pfn, bitidx; | 6037 | unsigned long pfn, bitidx, word_bitidx; |
6037 | unsigned long flags = 0; | 6038 | unsigned long word; |
6038 | unsigned long value = 1; | ||
6039 | 6039 | ||
6040 | zone = page_zone(page); | 6040 | zone = page_zone(page); |
6041 | pfn = page_to_pfn(page); | 6041 | pfn = page_to_pfn(page); |
6042 | bitmap = get_pageblock_bitmap(zone, pfn); | 6042 | bitmap = get_pageblock_bitmap(zone, pfn); |
6043 | bitidx = pfn_to_bitidx(zone, pfn); | 6043 | bitidx = pfn_to_bitidx(zone, pfn); |
6044 | word_bitidx = bitidx / BITS_PER_LONG; | ||
6045 | bitidx &= (BITS_PER_LONG-1); | ||
6044 | 6046 | ||
6045 | for (; start_bitidx <= end_bitidx; start_bitidx++, value <<= 1) | 6047 | word = bitmap[word_bitidx]; |
6046 | if (test_bit(bitidx + start_bitidx, bitmap)) | 6048 | bitidx += end_bitidx; |
6047 | flags |= value; | 6049 | return (word >> (BITS_PER_LONG - bitidx - 1)) & mask; |
6048 | |||
6049 | return flags; | ||
6050 | } | 6050 | } |
6051 | 6051 | ||
6052 | /** | 6052 | /** |
6053 | * set_pageblock_flags_group - Set the requested group of flags for a pageblock_nr_pages block of pages | 6053 | * set_pageblock_flags_mask - Set the requested group of flags for a pageblock_nr_pages block of pages |
6054 | * @page: The page within the block of interest | 6054 | * @page: The page within the block of interest |
6055 | * @start_bitidx: The first bit of interest | 6055 | * @start_bitidx: The first bit of interest |
6056 | * @end_bitidx: The last bit of interest | 6056 | * @end_bitidx: The last bit of interest |
6057 | * @flags: The flags to set | 6057 | * @flags: The flags to set |
6058 | */ | 6058 | */ |
6059 | void set_pageblock_flags_group(struct page *page, unsigned long flags, | 6059 | void set_pageblock_flags_mask(struct page *page, unsigned long flags, |
6060 | int start_bitidx, int end_bitidx) | 6060 | unsigned long end_bitidx, |
6061 | unsigned long mask) | ||
6061 | { | 6062 | { |
6062 | struct zone *zone; | 6063 | struct zone *zone; |
6063 | unsigned long *bitmap; | 6064 | unsigned long *bitmap; |
6064 | unsigned long pfn, bitidx; | 6065 | unsigned long pfn, bitidx, word_bitidx; |
6065 | unsigned long value = 1; | 6066 | unsigned long old_word, word; |
6067 | |||
6068 | BUILD_BUG_ON(NR_PAGEBLOCK_BITS != 4); | ||
6066 | 6069 | ||
6067 | zone = page_zone(page); | 6070 | zone = page_zone(page); |
6068 | pfn = page_to_pfn(page); | 6071 | pfn = page_to_pfn(page); |
6069 | bitmap = get_pageblock_bitmap(zone, pfn); | 6072 | bitmap = get_pageblock_bitmap(zone, pfn); |
6070 | bitidx = pfn_to_bitidx(zone, pfn); | 6073 | bitidx = pfn_to_bitidx(zone, pfn); |
6074 | word_bitidx = bitidx / BITS_PER_LONG; | ||
6075 | bitidx &= (BITS_PER_LONG-1); | ||
6076 | |||
6071 | VM_BUG_ON_PAGE(!zone_spans_pfn(zone, pfn), page); | 6077 | VM_BUG_ON_PAGE(!zone_spans_pfn(zone, pfn), page); |
6072 | 6078 | ||
6073 | for (; start_bitidx <= end_bitidx; start_bitidx++, value <<= 1) | 6079 | bitidx += end_bitidx; |
6074 | if (flags & value) | 6080 | mask <<= (BITS_PER_LONG - bitidx - 1); |
6075 | __set_bit(bitidx + start_bitidx, bitmap); | 6081 | flags <<= (BITS_PER_LONG - bitidx - 1); |
6076 | else | 6082 | |
6077 | __clear_bit(bitidx + start_bitidx, bitmap); | 6083 | word = ACCESS_ONCE(bitmap[word_bitidx]); |
6084 | for (;;) { | ||
6085 | old_word = cmpxchg(&bitmap[word_bitidx], word, (word & ~mask) | flags); | ||
6086 | if (word == old_word) | ||
6087 | break; | ||
6088 | word = old_word; | ||
6089 | } | ||
6078 | } | 6090 | } |
6079 | 6091 | ||
6080 | /* | 6092 | /* |