|
@@ -642,49 +642,56 @@ PAGEFLAG_FALSE(DoubleMap)
|
|
|
#endif
|
|
|
|
|
|
/*
|
|
|
- * For pages that are never mapped to userspace, page->mapcount may be
|
|
|
- * used for storing extra information about page type. Any value used
|
|
|
- * for this purpose must be <= -2, but it's better start not too close
|
|
|
- * to -2 so that an underflow of the page_mapcount() won't be mistaken
|
|
|
- * for a special page.
|
|
|
+ * For pages that are never mapped to userspace (and aren't PageSlab),
|
|
|
+ * page_type may be used. Because it is initialised to -1, we invert the
|
|
|
+ * sense of the bit, so __SetPageFoo *clears* the bit used for PageFoo, and
|
|
|
+ * __ClearPageFoo *sets* the bit used for PageFoo. We reserve a few high and
|
|
|
+ * low bits so that an underflow or overflow of page_mapcount() won't be
|
|
|
+ * mistaken for a page type value.
|
|
|
*/
|
|
|
-#define PAGE_MAPCOUNT_OPS(uname, lname) \
|
|
|
+
|
|
|
+#define PAGE_TYPE_BASE 0xf0000000
|
|
|
+/* Reserve 0x0000007f to catch underflows of page_mapcount */
|
|
|
+#define PG_buddy 0x00000080
|
|
|
+#define PG_balloon 0x00000100
|
|
|
+#define PG_kmemcg 0x00000200
|
|
|
+
|
|
|
+#define PageType(page, flag) \
|
|
|
+ ((page->page_type & (PAGE_TYPE_BASE | flag)) == PAGE_TYPE_BASE)
|
|
|
+
|
|
|
+#define PAGE_TYPE_OPS(uname, lname) \
|
|
|
static __always_inline int Page##uname(struct page *page) \
|
|
|
{ \
|
|
|
- return atomic_read(&page->_mapcount) == \
|
|
|
- PAGE_##lname##_MAPCOUNT_VALUE; \
|
|
|
+ return PageType(page, PG_##lname); \
|
|
|
} \
|
|
|
static __always_inline void __SetPage##uname(struct page *page) \
|
|
|
{ \
|
|
|
- VM_BUG_ON_PAGE(atomic_read(&page->_mapcount) != -1, page); \
|
|
|
- atomic_set(&page->_mapcount, PAGE_##lname##_MAPCOUNT_VALUE); \
|
|
|
+ VM_BUG_ON_PAGE(!PageType(page, 0), page); \
|
|
|
+ page->page_type &= ~PG_##lname; \
|
|
|
} \
|
|
|
static __always_inline void __ClearPage##uname(struct page *page) \
|
|
|
{ \
|
|
|
VM_BUG_ON_PAGE(!Page##uname(page), page); \
|
|
|
- atomic_set(&page->_mapcount, -1); \
|
|
|
+ page->page_type |= PG_##lname; \
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * PageBuddy() indicate that the page is free and in the buddy system
|
|
|
+ * PageBuddy() indicates that the page is free and in the buddy system
|
|
|
* (see mm/page_alloc.c).
|
|
|
*/
|
|
|
-#define PAGE_BUDDY_MAPCOUNT_VALUE (-128)
|
|
|
-PAGE_MAPCOUNT_OPS(Buddy, BUDDY)
|
|
|
+PAGE_TYPE_OPS(Buddy, buddy)
|
|
|
|
|
|
/*
|
|
|
- * PageBalloon() is set on pages that are on the balloon page list
|
|
|
+ * PageBalloon() is true for pages that are on the balloon page list
|
|
|
* (see mm/balloon_compaction.c).
|
|
|
*/
|
|
|
-#define PAGE_BALLOON_MAPCOUNT_VALUE (-256)
|
|
|
-PAGE_MAPCOUNT_OPS(Balloon, BALLOON)
|
|
|
+PAGE_TYPE_OPS(Balloon, balloon)
|
|
|
|
|
|
/*
|
|
|
* If kmemcg is enabled, the buddy allocator will set PageKmemcg() on
|
|
|
* pages allocated with __GFP_ACCOUNT. It gets cleared on page free.
|
|
|
*/
|
|
|
-#define PAGE_KMEMCG_MAPCOUNT_VALUE (-512)
|
|
|
-PAGE_MAPCOUNT_OPS(Kmemcg, KMEMCG)
|
|
|
+PAGE_TYPE_OPS(Kmemcg, kmemcg)
|
|
|
|
|
|
extern bool is_free_buddy_page(struct page *page);
|
|
|
|