Skip to content

Commit 6e292b9

Browse files
Matthew Wilcoxtorvalds
authored andcommitted
mm: split page_type out from _mapcount
We're already using a union of many fields here, so stop abusing the _mapcount and make page_type its own field. That implies renaming some of the machinery that creates PageBuddy, PageBalloon and PageKmemcg; bring back the PG_buddy, PG_balloon and PG_kmemcg names. As suggested by Kirill, make page_type a bitmask. Because it starts out life as -1 (thanks to sharing the storage with _mapcount), setting a page flag means clearing the appropriate bit. This gives us space for probably twenty or so extra bits (depending how paranoid we want to be about _mapcount underflow). Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Matthew Wilcox <[email protected]> Acked-by: Kirill A. Shutemov <[email protected]> Acked-by: Vlastimil Babka <[email protected]> Cc: Christoph Lameter <[email protected]> Cc: Dave Hansen <[email protected]> Cc: Jérôme Glisse <[email protected]> Cc: Lai Jiangshan <[email protected]> Cc: Martin Schwidefsky <[email protected]> Cc: Pekka Enberg <[email protected]> Cc: Randy Dunlap <[email protected]> Cc: Andrey Ryabinin <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 620b4e9 commit 6e292b9

File tree

5 files changed

+43
-35
lines changed

5 files changed

+43
-35
lines changed

include/linux/mm_types.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,14 @@ struct page {
9696
};
9797

9898
union {
99+
/*
100+
* If the page is neither PageSlab nor mappable to userspace,
101+
* the value stored here may help determine what this page
102+
* is used for. See page-flags.h for a list of page types
103+
* which are currently stored here.
104+
*/
105+
unsigned int page_type;
106+
99107
_slub_counter_t counters;
100108
unsigned int active; /* SLAB */
101109
struct { /* SLUB */
@@ -109,11 +117,6 @@ struct page {
109117
/*
110118
* Count of ptes mapped in mms, to show when
111119
* page is mapped & limit reverse map searches.
112-
*
113-
* Extra information about page type may be
114-
* stored here for pages that are never mapped,
115-
* in which case the value MUST BE <= -2.
116-
* See page-flags.h for more details.
117120
*/
118121
atomic_t _mapcount;
119122

include/linux/page-flags.h

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -642,49 +642,56 @@ PAGEFLAG_FALSE(DoubleMap)
642642
#endif
643643

644644
/*
645-
* For pages that are never mapped to userspace, page->mapcount may be
646-
* used for storing extra information about page type. Any value used
647-
* for this purpose must be <= -2, but it's better start not too close
648-
* to -2 so that an underflow of the page_mapcount() won't be mistaken
649-
* for a special page.
645+
* For pages that are never mapped to userspace (and aren't PageSlab),
646+
* page_type may be used. Because it is initialised to -1, we invert the
647+
* sense of the bit, so __SetPageFoo *clears* the bit used for PageFoo, and
648+
* __ClearPageFoo *sets* the bit used for PageFoo. We reserve a few high and
649+
* low bits so that an underflow or overflow of page_mapcount() won't be
650+
* mistaken for a page type value.
650651
*/
651-
#define PAGE_MAPCOUNT_OPS(uname, lname) \
652+
653+
#define PAGE_TYPE_BASE 0xf0000000
654+
/* Reserve 0x0000007f to catch underflows of page_mapcount */
655+
#define PG_buddy 0x00000080
656+
#define PG_balloon 0x00000100
657+
#define PG_kmemcg 0x00000200
658+
659+
#define PageType(page, flag) \
660+
((page->page_type & (PAGE_TYPE_BASE | flag)) == PAGE_TYPE_BASE)
661+
662+
#define PAGE_TYPE_OPS(uname, lname) \
652663
static __always_inline int Page##uname(struct page *page) \
653664
{ \
654-
return atomic_read(&page->_mapcount) == \
655-
PAGE_##lname##_MAPCOUNT_VALUE; \
665+
return PageType(page, PG_##lname); \
656666
} \
657667
static __always_inline void __SetPage##uname(struct page *page) \
658668
{ \
659-
VM_BUG_ON_PAGE(atomic_read(&page->_mapcount) != -1, page); \
660-
atomic_set(&page->_mapcount, PAGE_##lname##_MAPCOUNT_VALUE); \
669+
VM_BUG_ON_PAGE(!PageType(page, 0), page); \
670+
page->page_type &= ~PG_##lname; \
661671
} \
662672
static __always_inline void __ClearPage##uname(struct page *page) \
663673
{ \
664674
VM_BUG_ON_PAGE(!Page##uname(page), page); \
665-
atomic_set(&page->_mapcount, -1); \
675+
page->page_type |= PG_##lname; \
666676
}
667677

668678
/*
669-
* PageBuddy() indicate that the page is free and in the buddy system
679+
* PageBuddy() indicates that the page is free and in the buddy system
670680
* (see mm/page_alloc.c).
671681
*/
672-
#define PAGE_BUDDY_MAPCOUNT_VALUE (-128)
673-
PAGE_MAPCOUNT_OPS(Buddy, BUDDY)
682+
PAGE_TYPE_OPS(Buddy, buddy)
674683

675684
/*
676-
* PageBalloon() is set on pages that are on the balloon page list
685+
* PageBalloon() is true for pages that are on the balloon page list
677686
* (see mm/balloon_compaction.c).
678687
*/
679-
#define PAGE_BALLOON_MAPCOUNT_VALUE (-256)
680-
PAGE_MAPCOUNT_OPS(Balloon, BALLOON)
688+
PAGE_TYPE_OPS(Balloon, balloon)
681689

682690
/*
683691
* If kmemcg is enabled, the buddy allocator will set PageKmemcg() on
684692
* pages allocated with __GFP_ACCOUNT. It gets cleared on page free.
685693
*/
686-
#define PAGE_KMEMCG_MAPCOUNT_VALUE (-512)
687-
PAGE_MAPCOUNT_OPS(Kmemcg, KMEMCG)
694+
PAGE_TYPE_OPS(Kmemcg, kmemcg)
688695

689696
extern bool is_free_buddy_page(struct page *page);
690697

kernel/crash_core.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,7 @@ static int __init crash_save_vmcoreinfo_init(void)
460460
VMCOREINFO_NUMBER(PG_hwpoison);
461461
#endif
462462
VMCOREINFO_NUMBER(PG_head_mask);
463+
#define PAGE_BUDDY_MAPCOUNT_VALUE (~PG_buddy)
463464
VMCOREINFO_NUMBER(PAGE_BUDDY_MAPCOUNT_VALUE);
464465
#ifdef CONFIG_HUGETLB_PAGE
465466
VMCOREINFO_NUMBER(HUGETLB_PAGE_DTOR);

mm/page_alloc.c

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -705,16 +705,14 @@ static inline void rmv_page_order(struct page *page)
705705

706706
/*
707707
* This function checks whether a page is free && is the buddy
708-
* we can do coalesce a page and its buddy if
708+
* we can coalesce a page and its buddy if
709709
* (a) the buddy is not in a hole (check before calling!) &&
710710
* (b) the buddy is in the buddy system &&
711711
* (c) a page and its buddy have the same order &&
712712
* (d) a page and its buddy are in the same zone.
713713
*
714-
* For recording whether a page is in the buddy system, we set ->_mapcount
715-
* PAGE_BUDDY_MAPCOUNT_VALUE.
716-
* Setting, clearing, and testing _mapcount PAGE_BUDDY_MAPCOUNT_VALUE is
717-
* serialized by zone->lock.
714+
* For recording whether a page is in the buddy system, we set PageBuddy.
715+
* Setting, clearing, and testing PageBuddy is serialized by zone->lock.
718716
*
719717
* For recording page's order, we use page_private(page).
720718
*/
@@ -759,9 +757,8 @@ static inline int page_is_buddy(struct page *page, struct page *buddy,
759757
* as necessary, plus some accounting needed to play nicely with other
760758
* parts of the VM system.
761759
* At each level, we keep a list of pages, which are heads of continuous
762-
* free pages of length of (1 << order) and marked with _mapcount
763-
* PAGE_BUDDY_MAPCOUNT_VALUE. Page's order is recorded in page_private(page)
764-
* field.
760+
* free pages of length of (1 << order) and marked with PageBuddy.
761+
* Page's order is recorded in page_private(page) field.
765762
* So when we are allocating or freeing one, we can derive the state of the
766763
* other. That is, if we allocate a small block, and both were
767764
* free, the remainder of the region must be split into blocks.

scripts/tags.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -179,9 +179,9 @@ regex_c=(
179179
'/\<CLEARPAGEFLAG_NOOP(\([[:alnum:]_]*\).*/ClearPage\1/'
180180
'/\<__CLEARPAGEFLAG_NOOP(\([[:alnum:]_]*\).*/__ClearPage\1/'
181181
'/\<TESTCLEARFLAG_FALSE(\([[:alnum:]_]*\).*/TestClearPage\1/'
182-
'/^PAGE_MAPCOUNT_OPS(\([[:alnum:]_]*\).*/Page\1/'
183-
'/^PAGE_MAPCOUNT_OPS(\([[:alnum:]_]*\).*/__SetPage\1/'
184-
'/^PAGE_MAPCOUNT_OPS(\([[:alnum:]_]*\).*/__ClearPage\1/'
182+
'/^PAGE_TYPE_OPS(\([[:alnum:]_]*\).*/Page\1/'
183+
'/^PAGE_TYPE_OPS(\([[:alnum:]_]*\).*/__SetPage\1/'
184+
'/^PAGE_TYPE_OPS(\([[:alnum:]_]*\).*/__ClearPage\1/'
185185
'/^TASK_PFA_TEST([^,]*, *\([[:alnum:]_]*\))/task_\1/'
186186
'/^TASK_PFA_SET([^,]*, *\([[:alnum:]_]*\))/task_set_\1/'
187187
'/^TASK_PFA_CLEAR([^,]*, *\([[:alnum:]_]*\))/task_clear_\1/'

0 commit comments

Comments
 (0)