aboutsummaryrefslogtreecommitdiffstats
path: root/mm/page_alloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/page_alloc.c')
-rw-r--r--mm/page_alloc.c52
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 */
6031unsigned long get_pageblock_flags_group(struct page *page, 6031unsigned 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 */
6059void set_pageblock_flags_group(struct page *page, unsigned long flags, 6059void 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/*