Skip to content

Commit 4996fc5

Browse files
davidhildenbrandakpm00
authored andcommitted
mm: let _folio_nr_pages overlay memcg_data in first tail page
Let's free up some more of the "unconditionally available on 64BIT" space in order-1 folios by letting _folio_nr_pages overlay memcg_data in the first tail page (second folio page). Consequently, we have the optimization now whenever we have CONFIG_MEMCG, independent of 64BIT. We have to make sure that page->memcg on tail pages does not return "surprises". page_memcg_check() already properly refuses PageTail(). Let's do that earlier in print_page_owner_memcg() to avoid printing wrong "Slab cache page" information. No other code should touch that field on tail pages of compound pages. Reset the "_nr_pages" to 0 when splitting folios, or when freeing them back to the buddy (to avoid false page->memcg_data "bad page" reports). Note that in __split_huge_page(), folio_nr_pages() would stop working already as soon as we start messing with the subpages. Most kernel configs should have at least CONFIG_MEMCG enabled, even if disabled at runtime. 64byte "struct memmap" is what we usually have on 64BIT. While at it, rename "_folio_nr_pages" to "_nr_pages". Hopefully memdescs / dynamically allocating "strut folio" in the future will further clean this up, e.g., making _nr_pages available in all configs and maybe even in small folios. Doing that should be fairly easy on top of this change. [[email protected]: make "make htmldoc" happy] Link: https://lkml.kernel.org/r/[email protected] Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: David Hildenbrand <[email protected]> Reviewed-by: Kirill A. Shutemov <[email protected]> Cc: Andy Lutomirks^H^Hski <[email protected]> Cc: Borislav Betkov <[email protected]> Cc: Dave Hansen <[email protected]> Cc: Ingo Molnar <[email protected]> Cc: Jann Horn <[email protected]> Cc: Johannes Weiner <[email protected]> Cc: Jonathan Corbet <[email protected]> Cc: Lance Yang <[email protected]> Cc: Liam Howlett <[email protected]> Cc: Lorenzo Stoakes <[email protected]> Cc: Matthew Wilcow (Oracle) <[email protected]> Cc: Michal Koutn <[email protected]> Cc: Muchun Song <[email protected]> Cc: tejun heo <[email protected]> Cc: Thomas Gleixner <[email protected]> Cc: Vlastimil Babka <[email protected]> Cc: Zefan Li <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent 1ea5212 commit 4996fc5

File tree

6 files changed

+42
-14
lines changed

6 files changed

+42
-14
lines changed

include/linux/mm.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1199,10 +1199,10 @@ static inline unsigned int folio_large_order(const struct folio *folio)
11991199
return folio->_flags_1 & 0xff;
12001200
}
12011201

1202-
#ifdef CONFIG_64BIT
1202+
#ifdef NR_PAGES_IN_LARGE_FOLIO
12031203
static inline long folio_large_nr_pages(const struct folio *folio)
12041204
{
1205-
return folio->_folio_nr_pages;
1205+
return folio->_nr_pages;
12061206
}
12071207
#else
12081208
static inline long folio_large_nr_pages(const struct folio *folio)

include/linux/mm_types.h

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,11 @@ typedef struct {
287287
unsigned long val;
288288
} swp_entry_t;
289289

290+
#if defined(CONFIG_MEMCG) || defined(CONFIG_SLAB_OBJ_EXT)
291+
/* We have some extra room after the refcount in tail pages. */
292+
#define NR_PAGES_IN_LARGE_FOLIO
293+
#endif
294+
290295
/**
291296
* struct folio - Represents a contiguous set of bytes.
292297
* @flags: Identical to the page flags.
@@ -312,7 +317,7 @@ typedef struct {
312317
* @_large_mapcount: Do not use directly, call folio_mapcount().
313318
* @_nr_pages_mapped: Do not use outside of rmap and debug code.
314319
* @_pincount: Do not use directly, call folio_maybe_dma_pinned().
315-
* @_folio_nr_pages: Do not use directly, call folio_nr_pages().
320+
* @_nr_pages: Do not use directly, call folio_nr_pages().
316321
* @_hugetlb_subpool: Do not use directly, use accessor in hugetlb.h.
317322
* @_hugetlb_cgroup: Do not use directly, use accessor in hugetlb_cgroup.h.
318323
* @_hugetlb_cgroup_rsvd: Do not use directly, use accessor in hugetlb_cgroup.h.
@@ -376,14 +381,23 @@ struct folio {
376381
struct {
377382
unsigned long _flags_1;
378383
unsigned long _head_1;
384+
union {
385+
struct {
379386
/* public: */
380-
atomic_t _large_mapcount;
381-
atomic_t _entire_mapcount;
382-
atomic_t _nr_pages_mapped;
383-
atomic_t _pincount;
384-
#ifdef CONFIG_64BIT
385-
unsigned int _folio_nr_pages;
386-
#endif
387+
atomic_t _large_mapcount;
388+
atomic_t _entire_mapcount;
389+
atomic_t _nr_pages_mapped;
390+
atomic_t _pincount;
391+
/* private: the union with struct page is transitional */
392+
};
393+
unsigned long _usable_1[4];
394+
};
395+
atomic_t _mapcount_1;
396+
atomic_t _refcount_1;
397+
/* public: */
398+
#ifdef NR_PAGES_IN_LARGE_FOLIO
399+
unsigned int _nr_pages;
400+
#endif /* NR_PAGES_IN_LARGE_FOLIO */
387401
/* private: the union with struct page is transitional */
388402
};
389403
struct page __page_1;
@@ -435,6 +449,8 @@ FOLIO_MATCH(_last_cpupid, _last_cpupid);
435449
offsetof(struct page, pg) + sizeof(struct page))
436450
FOLIO_MATCH(flags, _flags_1);
437451
FOLIO_MATCH(compound_head, _head_1);
452+
FOLIO_MATCH(_mapcount, _mapcount_1);
453+
FOLIO_MATCH(_refcount, _refcount_1);
438454
#undef FOLIO_MATCH
439455
#define FOLIO_MATCH(pg, fl) \
440456
static_assert(offsetof(struct folio, fl) == \

mm/huge_memory.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3399,6 +3399,14 @@ static void __split_huge_page(struct page *page, struct list_head *list,
33993399
int order = folio_order(folio);
34003400
unsigned int nr = 1 << order;
34013401

3402+
/*
3403+
* Reset any memcg data overlay in the tail pages. folio_nr_pages()
3404+
* is unreliable after this point.
3405+
*/
3406+
#ifdef NR_PAGES_IN_LARGE_FOLIO
3407+
folio->_nr_pages = 0;
3408+
#endif
3409+
34023410
/* complete memcg works before add pages to LRU */
34033411
split_page_memcg(head, order, new_order);
34043412

mm/internal.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -725,8 +725,8 @@ static inline void folio_set_order(struct folio *folio, unsigned int order)
725725
return;
726726

727727
folio->_flags_1 = (folio->_flags_1 & ~0xffUL) | order;
728-
#ifdef CONFIG_64BIT
729-
folio->_folio_nr_pages = 1U << order;
728+
#ifdef NR_PAGES_IN_LARGE_FOLIO
729+
folio->_nr_pages = 1U << order;
730730
#endif
731731
}
732732

mm/page_alloc.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1174,8 +1174,12 @@ __always_inline bool free_pages_prepare(struct page *page,
11741174
if (unlikely(order)) {
11751175
int i;
11761176

1177-
if (compound)
1177+
if (compound) {
11781178
page[1].flags &= ~PAGE_FLAGS_SECOND;
1179+
#ifdef NR_PAGES_IN_LARGE_FOLIO
1180+
folio->_nr_pages = 0;
1181+
#endif
1182+
}
11791183
for (i = 1; i < (1 << order); i++) {
11801184
if (compound)
11811185
bad += free_tail_page_prepare(page, page + i);

mm/page_owner.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -507,7 +507,7 @@ static inline int print_page_owner_memcg(char *kbuf, size_t count, int ret,
507507

508508
rcu_read_lock();
509509
memcg_data = READ_ONCE(page->memcg_data);
510-
if (!memcg_data)
510+
if (!memcg_data || PageTail(page))
511511
goto out_unlock;
512512

513513
if (memcg_data & MEMCG_DATA_OBJEXTS)

0 commit comments

Comments
 (0)