PB_migrate,
        PB_migrate_end = PB_migrate + PB_migratetype_bits - 1,
                        /* 3 bits required for migrate types */
-       PB_migrate_skip,/* If set the block is skipped by compaction */
+       PB_compact_skip,/* If set the block is skipped by compaction */
 
        /*
         * Assume the bits will always align on a word. If this assumption
         * changes then get/set pageblock needs updating.
         */
-       NR_PAGEBLOCK_BITS
+       __NR_PAGEBLOCK_BITS
 };
 
+#define NR_PAGEBLOCK_BITS (roundup_pow_of_two(__NR_PAGEBLOCK_BITS))
+
+#define MIGRATETYPE_MASK ((1UL << (PB_migrate_end + 1)) - 1)
+
 #if defined(CONFIG_HUGETLB_PAGE)
 
 #ifdef CONFIG_HUGETLB_PAGE_SIZE_VARIABLE
 /* Forward declaration */
 struct page;
 
-unsigned long get_pfnblock_flags_mask(const struct page *page,
-                               unsigned long pfn,
-                               unsigned long mask);
-
-void set_pfnblock_flags_mask(struct page *page,
-                               unsigned long flags,
-                               unsigned long pfn,
-                               unsigned long mask);
+enum migratetype get_pfnblock_migratetype(const struct page *page,
+                                         unsigned long pfn);
+bool get_pfnblock_bit(const struct page *page, unsigned long pfn,
+                     enum pageblock_bits pb_bit);
+void set_pfnblock_bit(const struct page *page, unsigned long pfn,
+                     enum pageblock_bits pb_bit);
+void clear_pfnblock_bit(const struct page *page, unsigned long pfn,
+                       enum pageblock_bits pb_bit);
 
 /* Declarations for getting and setting flags. See mm/page_alloc.c */
 #ifdef CONFIG_COMPACTION
 #define get_pageblock_skip(page) \
-       get_pfnblock_flags_mask(page, page_to_pfn(page),        \
-                       (1 << (PB_migrate_skip)))
+       get_pfnblock_bit(page, page_to_pfn(page), PB_compact_skip)
 #define clear_pageblock_skip(page) \
-       set_pfnblock_flags_mask(page, 0, page_to_pfn(page),     \
-                       (1 << PB_migrate_skip))
+       clear_pfnblock_bit(page, page_to_pfn(page), PB_compact_skip)
 #define set_pageblock_skip(page) \
-       set_pfnblock_flags_mask(page, (1 << PB_migrate_skip),   \
-                       page_to_pfn(page),                      \
-                       (1 << PB_migrate_skip))
+       set_pfnblock_bit(page, page_to_pfn(page), PB_compact_skip)
 #else
 static inline bool get_pageblock_skip(struct page *page)
 {
 
        return (pfn >> pageblock_order) * NR_PAGEBLOCK_BITS;
 }
 
+static __always_inline bool is_standalone_pb_bit(enum pageblock_bits pb_bit)
+{
+       return pb_bit > PB_migrate_end && pb_bit < __NR_PAGEBLOCK_BITS;
+}
+
+static __always_inline void
+get_pfnblock_bitmap_bitidx(const struct page *page, unsigned long pfn,
+                          unsigned long **bitmap_word, unsigned long *bitidx)
+{
+       unsigned long *bitmap;
+       unsigned long word_bitidx;
+
+       BUILD_BUG_ON(NR_PAGEBLOCK_BITS != 4);
+       BUILD_BUG_ON(MIGRATE_TYPES > (1 << PB_migratetype_bits));
+       VM_BUG_ON_PAGE(!zone_spans_pfn(page_zone(page), pfn), page);
+
+       bitmap = get_pageblock_bitmap(page, pfn);
+       *bitidx = pfn_to_bitidx(page, pfn);
+       word_bitidx = *bitidx / BITS_PER_LONG;
+       *bitidx &= (BITS_PER_LONG - 1);
+       *bitmap_word = &bitmap[word_bitidx];
+}
+
+
 /**
- * get_pfnblock_flags_mask - Return the requested group of flags for the pageblock_nr_pages block of pages
+ * __get_pfnblock_flags_mask - Return the requested group of flags for
+ * a pageblock_nr_pages block of pages
  * @page: The page within the block of interest
  * @pfn: The target page frame number
  * @mask: mask of bits that the caller is interested in
  *
  * Return: pageblock_bits flags
  */
-unsigned long get_pfnblock_flags_mask(const struct page *page,
-                                       unsigned long pfn, unsigned long mask)
+static unsigned long __get_pfnblock_flags_mask(const struct page *page,
+                                              unsigned long pfn,
+                                              unsigned long mask)
 {
-       unsigned long *bitmap;
-       unsigned long bitidx, word_bitidx;
+       unsigned long *bitmap_word;
+       unsigned long bitidx;
        unsigned long word;
 
-       bitmap = get_pageblock_bitmap(page, pfn);
-       bitidx = pfn_to_bitidx(page, pfn);
-       word_bitidx = bitidx / BITS_PER_LONG;
-       bitidx &= (BITS_PER_LONG-1);
+       get_pfnblock_bitmap_bitidx(page, pfn, &bitmap_word, &bitidx);
        /*
-        * This races, without locks, with set_pfnblock_flags_mask(). Ensure
+        * This races, without locks, with set_pfnblock_migratetype(). Ensure
         * a consistent read of the memory array, so that results, even though
         * racy, are not corrupted.
         */
-       word = READ_ONCE(bitmap[word_bitidx]);
+       word = READ_ONCE(*bitmap_word);
        return (word >> bitidx) & mask;
 }
 
-static __always_inline int get_pfnblock_migratetype(const struct page *page,
-                                       unsigned long pfn)
+/**
+ * get_pfnblock_bit - Check if a standalone bit of a pageblock is set
+ * @page: The page within the block of interest
+ * @pfn: The target page frame number
+ * @pb_bit: pageblock bit to check
+ *
+ * Return: true if the bit is set, otherwise false
+ */
+bool get_pfnblock_bit(const struct page *page, unsigned long pfn,
+                     enum pageblock_bits pb_bit)
 {
-       return get_pfnblock_flags_mask(page, pfn, MIGRATETYPE_MASK);
+       unsigned long *bitmap_word;
+       unsigned long bitidx;
+
+       if (WARN_ON_ONCE(!is_standalone_pb_bit(pb_bit)))
+               return false;
+
+       get_pfnblock_bitmap_bitidx(page, pfn, &bitmap_word, &bitidx);
+
+       return test_bit(bitidx + pb_bit, bitmap_word);
 }
 
 /**
- * set_pfnblock_flags_mask - Set the requested group of flags for a pageblock_nr_pages block of pages
+ * get_pfnblock_migratetype - Return the migratetype of a pageblock
+ * @page: The page within the block of interest
+ * @pfn: The target page frame number
+ *
+ * Return: The migratetype of the pageblock
+ *
+ * Use get_pfnblock_migratetype() if caller already has both @page and @pfn
+ * to save a call to page_to_pfn().
+ */
+__always_inline enum migratetype
+get_pfnblock_migratetype(const struct page *page, unsigned long pfn)
+{
+       return __get_pfnblock_flags_mask(page, pfn, MIGRATETYPE_MASK);
+}
+
+/**
+ * __set_pfnblock_flags_mask - Set the requested group of flags for
+ * a pageblock_nr_pages block of pages
  * @page: The page within the block of interest
- * @flags: The flags to set
  * @pfn: The target page frame number
+ * @flags: The flags to set
  * @mask: mask of bits that the caller is interested in
  */
-void set_pfnblock_flags_mask(struct page *page, unsigned long flags,
-                                       unsigned long pfn,
-                                       unsigned long mask)
+static void __set_pfnblock_flags_mask(struct page *page, unsigned long pfn,
+                                     unsigned long flags, unsigned long mask)
 {
-       unsigned long *bitmap;
-       unsigned long bitidx, word_bitidx;
+       unsigned long *bitmap_word;
+       unsigned long bitidx;
        unsigned long word;
 
-       BUILD_BUG_ON(NR_PAGEBLOCK_BITS != 4);
-       BUILD_BUG_ON(MIGRATE_TYPES > (1 << PB_migratetype_bits));
-
-       bitmap = get_pageblock_bitmap(page, pfn);
-       bitidx = pfn_to_bitidx(page, pfn);
-       word_bitidx = bitidx / BITS_PER_LONG;
-       bitidx &= (BITS_PER_LONG-1);
-
-       VM_BUG_ON_PAGE(!zone_spans_pfn(page_zone(page), pfn), page);
+       get_pfnblock_bitmap_bitidx(page, pfn, &bitmap_word, &bitidx);
 
        mask <<= bitidx;
        flags <<= bitidx;
 
-       word = READ_ONCE(bitmap[word_bitidx]);
+       word = READ_ONCE(*bitmap_word);
        do {
-       } while (!try_cmpxchg(&bitmap[word_bitidx], &word, (word & ~mask) | flags));
+       } while (!try_cmpxchg(bitmap_word, &word, (word & ~mask) | flags));
+}
+
+/**
+ * set_pfnblock_bit - Set a standalone bit of a pageblock
+ * @page: The page within the block of interest
+ * @pfn: The target page frame number
+ * @pb_bit: pageblock bit to set
+ */
+void set_pfnblock_bit(const struct page *page, unsigned long pfn,
+                     enum pageblock_bits pb_bit)
+{
+       unsigned long *bitmap_word;
+       unsigned long bitidx;
+
+       if (WARN_ON_ONCE(!is_standalone_pb_bit(pb_bit)))
+               return;
+
+       get_pfnblock_bitmap_bitidx(page, pfn, &bitmap_word, &bitidx);
+
+       set_bit(bitidx + pb_bit, bitmap_word);
 }
 
-void set_pageblock_migratetype(struct page *page, int migratetype)
+/**
+ * clear_pfnblock_bit - Clear a standalone bit of a pageblock
+ * @page: The page within the block of interest
+ * @pfn: The target page frame number
+ * @pb_bit: pageblock bit to clear
+ */
+void clear_pfnblock_bit(const struct page *page, unsigned long pfn,
+                       enum pageblock_bits pb_bit)
+{
+       unsigned long *bitmap_word;
+       unsigned long bitidx;
+
+       if (WARN_ON_ONCE(!is_standalone_pb_bit(pb_bit)))
+               return;
+
+       get_pfnblock_bitmap_bitidx(page, pfn, &bitmap_word, &bitidx);
+
+       clear_bit(bitidx + pb_bit, bitmap_word);
+}
+
+/**
+ * set_pageblock_migratetype - Set the migratetype of a pageblock
+ * @page: The page within the block of interest
+ * @migratetype: migratetype to set
+ */
+__always_inline void set_pageblock_migratetype(struct page *page,
+                                              enum migratetype migratetype)
 {
        if (unlikely(page_group_by_mobility_disabled &&
                     migratetype < MIGRATE_PCPTYPES))
                migratetype = MIGRATE_UNMOVABLE;
 
-       set_pfnblock_flags_mask(page, (unsigned long)migratetype,
-                               page_to_pfn(page), MIGRATETYPE_MASK);
+       __set_pfnblock_flags_mask(page, page_to_pfn(page),
+                                 (unsigned long)migratetype, MIGRATETYPE_MASK);
 }
 
 #ifdef CONFIG_DEBUG_VM
        int nr_pages = 1 << order;
 
        VM_WARN_ONCE(get_pageblock_migratetype(page) != migratetype,
-                    "page type is %lu, passed migratetype is %d (nr=%d)\n",
+                    "page type is %d, passed migratetype is %d (nr=%d)\n",
                     get_pageblock_migratetype(page), migratetype, nr_pages);
 
        if (tail)
 
        /* Free page moving can fail, so it happens before the type update */
        VM_WARN_ONCE(get_pageblock_migratetype(page) != old_mt,
-                    "page type is %lu, passed migratetype is %d (nr=%d)\n",
+                    "page type is %d, passed migratetype is %d (nr=%d)\n",
                     get_pageblock_migratetype(page), old_mt, nr_pages);
 
        list_move_tail(&page->buddy_list, &area->free_list[new_mt]);
        int nr_pages = 1 << order;
 
         VM_WARN_ONCE(get_pageblock_migratetype(page) != migratetype,
-                    "page type is %lu, passed migratetype is %d (nr=%d)\n",
+                    "page type is %d, passed migratetype is %d (nr=%d)\n",
                     get_pageblock_migratetype(page), migratetype, nr_pages);
 
        /* clear reported state and update reported page count */
 
 /*
  * Do not instrument rmqueue() with KMSAN. This function may call
- * __msan_poison_alloca() through a call to set_pfnblock_flags_mask().
+ * __msan_poison_alloca() through a call to set_pfnblock_migratetype().
  * If __msan_poison_alloca() attempts to allocate pages for the stack depot, it
  * may call rmqueue() again, which will result in a deadlock.
  */