From: Zi Yan <ziy@nvidia.com>
To: Jason Gunthorpe <jgg@nvidia.com>,
David Hildenbrand <david@kernel.org>,
Matthew Wilcox <willy@infradead.org>
Cc: Alistair Popple <apopple@nvidia.com>,
Balbir Singh <balbirs@nvidia.com>,
Andrew Morton <akpm@linux-foundation.org>,
Lorenzo Stoakes <lorenzo.stoakes@oracle.com>,
"Liam R. Howlett" <Liam.Howlett@oracle.com>,
Vlastimil Babka <vbabka@suse.cz>, Mike Rapoport <rppt@kernel.org>,
Suren Baghdasaryan <surenb@google.com>,
Michal Hocko <mhocko@suse.com>, Jens Axboe <axboe@kernel.dk>,
Zi Yan <ziy@nvidia.com>,
Baolin Wang <baolin.wang@linux.alibaba.com>,
Nico Pache <npache@redhat.com>,
Ryan Roberts <ryan.roberts@arm.com>, Dev Jain <dev.jain@arm.com>,
Barry Song <baohua@kernel.org>, Lance Yang <lance.yang@linux.dev>,
Muchun Song <muchun.song@linux.dev>,
Oscar Salvador <osalvador@suse.de>,
Brendan Jackman <jackmanb@google.com>,
Johannes Weiner <hannes@cmpxchg.org>,
linux-mm@kvack.org, linux-kernel@vger.kernel.org,
io-uring@vger.kernel.org
Subject: [RFC PATCH 5/5] mm: code separation for compound page and folio
Date: Thu, 29 Jan 2026 22:48:18 -0500 [thread overview]
Message-ID: <20260130034818.472804-6-ziy@nvidia.com> (raw)
In-Reply-To: <20260130034818.472804-1-ziy@nvidia.com>
A compound page is not a folio. Using struct folio in prep_compound_head()
causes confusion, since the input page is not a folio. The compound page to
folio conversion happens in page_rmappable_folio(). So move folio code from
prep_compound_head() to page_rmappable_folio().
After the change, a compound page no longer has the following folio field
set:
1. folio->_nr_pages,
2. folio->_large_mapcount,
3. folio->_nr_pages_mapped,
4. folio->_mm_ids,
5. folio->_mm_id_mapcount,
6. folio->_pincount,
7. folio->_entire_mapcount,
8. folio->_deferred_list.
The page freeing path for compound pages does not need to check these
fields and now just checks ->mapping == TAIL_MAPPING for all subpages.
So free_tail_page_prepare() has a new large_rmappable input to distinguish
between a compound page and a folio.
Signed-off-by: Zi Yan <ziy@nvidia.com>
---
mm/hugetlb.c | 2 +-
mm/internal.h | 44 ++++++++++++++++++++++++++------------------
mm/mm_init.c | 2 +-
mm/page_alloc.c | 23 ++++++++++++++++++-----
4 files changed, 46 insertions(+), 25 deletions(-)
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 7466c7bf41a1..231c91c3d93b 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -3204,7 +3204,7 @@ static void __init hugetlb_folio_init_vmemmap(struct folio *folio,
ret = folio_ref_freeze(folio, 1);
VM_BUG_ON(!ret);
hugetlb_folio_init_tail_vmemmap(folio, 1, nr_pages);
- prep_compound_head(&folio->page, huge_page_order(h));
+ set_compound_order(&folio->page, huge_page_order(h));
}
static bool __init hugetlb_bootmem_page_prehvo(struct huge_bootmem_page *m)
diff --git a/mm/internal.h b/mm/internal.h
index 8bb22fb9a0e1..4d72e915d623 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -854,30 +854,38 @@ static inline struct folio *page_rmappable_folio(struct page *page)
{
struct folio *folio = (struct folio *)page;
- if (folio && folio_test_large(folio))
+ if (folio && folio_test_large(folio)) {
+ unsigned int order = compound_order(page);
+
+#ifdef NR_PAGES_IN_LARGE_FOLIO
+ folio->_nr_pages = 1U << order;
+#endif
+ atomic_set(&folio->_large_mapcount, -1);
+ if (IS_ENABLED(CONFIG_PAGE_MAPCOUNT))
+ atomic_set(&folio->_nr_pages_mapped, 0);
+ if (IS_ENABLED(CONFIG_MM_ID)) {
+ folio->_mm_ids = 0;
+ folio->_mm_id_mapcount[0] = -1;
+ folio->_mm_id_mapcount[1] = -1;
+ }
+ if (IS_ENABLED(CONFIG_64BIT) || order > 1) {
+ atomic_set(&folio->_pincount, 0);
+ atomic_set(&folio->_entire_mapcount, -1);
+ }
+ if (order > 1)
+ INIT_LIST_HEAD(&folio->_deferred_list);
folio_set_large_rmappable(folio);
+ }
return folio;
}
-static inline void prep_compound_head(struct page *page, unsigned int order)
+static inline void set_compound_order(struct page *page, unsigned int order)
{
- struct folio *folio = (struct folio *)page;
+ if (WARN_ON_ONCE(!order || !PageHead(page)))
+ return;
+ VM_WARN_ON_ONCE(order > MAX_FOLIO_ORDER);
- folio_set_order(folio, order);
- atomic_set(&folio->_large_mapcount, -1);
- if (IS_ENABLED(CONFIG_PAGE_MAPCOUNT))
- atomic_set(&folio->_nr_pages_mapped, 0);
- if (IS_ENABLED(CONFIG_MM_ID)) {
- folio->_mm_ids = 0;
- folio->_mm_id_mapcount[0] = -1;
- folio->_mm_id_mapcount[1] = -1;
- }
- if (IS_ENABLED(CONFIG_64BIT) || order > 1) {
- atomic_set(&folio->_pincount, 0);
- atomic_set(&folio->_entire_mapcount, -1);
- }
- if (order > 1)
- INIT_LIST_HEAD(&folio->_deferred_list);
+ page[1].flags.f = (page[1].flags.f & ~0xffUL) | order;
}
static inline void prep_compound_tail(struct page *head, int tail_idx)
diff --git a/mm/mm_init.c b/mm/mm_init.c
index 1a29a719af58..23a42a4af77b 100644
--- a/mm/mm_init.c
+++ b/mm/mm_init.c
@@ -1102,7 +1102,7 @@ static void __ref memmap_init_compound(struct page *head,
prep_compound_tail(head, pfn - head_pfn);
set_page_count(page, 0);
}
- prep_compound_head(head, order);
+ set_compound_order(head, order);
}
void __ref memmap_init_zone_device(struct zone *zone,
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index e4104973e22f..2194a6b3a062 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -746,7 +746,7 @@ void prep_compound_page(struct page *page, unsigned int order)
for (i = 1; i < nr_pages; i++)
prep_compound_tail(page, i);
- prep_compound_head(page, order);
+ set_compound_order(page, order);
}
static inline void set_buddy_order(struct page *page, unsigned int order)
@@ -1126,7 +1126,8 @@ static inline bool is_check_pages_enabled(void)
return static_branch_unlikely(&check_pages_enabled);
}
-static int free_tail_page_prepare(struct page *head_page, struct page *page)
+static int free_tail_page_prepare(struct page *head_page, struct page *page,
+ bool large_rmappable)
{
struct folio *folio = (struct folio *)head_page;
int ret = 1;
@@ -1141,6 +1142,13 @@ static int free_tail_page_prepare(struct page *head_page, struct page *page)
ret = 0;
goto out;
}
+ if (!large_rmappable) {
+ if (page->mapping != TAIL_MAPPING) {
+ bad_page(page, "corrupted mapping in compound page's tail page");
+ goto out;
+ }
+ goto skip_rmappable_checks;
+ }
switch (page - head_page) {
case 1:
/* the first tail page: these may be in place of ->mapping */
@@ -1198,11 +1206,12 @@ static int free_tail_page_prepare(struct page *head_page, struct page *page)
fallthrough;
default:
if (page->mapping != TAIL_MAPPING) {
- bad_page(page, "corrupted mapping in tail page");
+ bad_page(page, "corrupted mapping in folio's tail page");
goto out;
}
break;
}
+skip_rmappable_checks:
if (unlikely(!PageTail(page))) {
bad_page(page, "PageTail not set");
goto out;
@@ -1392,17 +1401,21 @@ __always_inline bool free_pages_prepare(struct page *page,
* avoid checking PageCompound for order-0 pages.
*/
if (unlikely(order)) {
+ bool large_rmappable = false;
int i;
if (compound) {
+ large_rmappable = folio_test_large_rmappable(folio);
+ /* clear compound order */
page[1].flags.f &= ~PAGE_FLAGS_SECOND;
#ifdef NR_PAGES_IN_LARGE_FOLIO
- folio->_nr_pages = 0;
+ if (large_rmappable)
+ folio->_nr_pages = 0;
#endif
}
for (i = 1; i < (1 << order); i++) {
if (compound)
- bad += free_tail_page_prepare(page, page + i);
+ bad += free_tail_page_prepare(page, page + i, large_rmappable);
if (is_check_pages_enabled()) {
if (free_page_is_bad(page + i)) {
bad++;
--
2.51.0
next prev parent reply other threads:[~2026-01-30 3:52 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-01-30 3:48 [RFC PATCH 0/5] Separate compound page from folio Zi Yan
2026-01-30 3:48 ` [RFC PATCH 1/5] io_uring: allocate folio in io_mem_alloc_compound() and function rename Zi Yan
2026-01-30 3:48 ` [RFC PATCH 2/5] mm/huge_memory: use page_rmappable_folio() to convert after-split folios Zi Yan
2026-01-30 3:48 ` [RFC PATCH 3/5] mm/hugetlb: set large_rmappable on hugetlb and avoid deferred_list handling Zi Yan
2026-01-30 3:48 ` [RFC PATCH 4/5] mm: only use struct page in compound_nr() and compound_order() Zi Yan
2026-01-30 3:48 ` Zi Yan [this message]
2026-01-30 8:15 ` [syzbot ci] Re: Separate compound page from folio syzbot ci
2026-01-30 16:39 ` [syzbot ci] " Zi Yan
2026-01-30 16:41 ` syzbot ci
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260130034818.472804-6-ziy@nvidia.com \
--to=ziy@nvidia.com \
--cc=Liam.Howlett@oracle.com \
--cc=akpm@linux-foundation.org \
--cc=apopple@nvidia.com \
--cc=axboe@kernel.dk \
--cc=balbirs@nvidia.com \
--cc=baohua@kernel.org \
--cc=baolin.wang@linux.alibaba.com \
--cc=david@kernel.org \
--cc=dev.jain@arm.com \
--cc=hannes@cmpxchg.org \
--cc=io-uring@vger.kernel.org \
--cc=jackmanb@google.com \
--cc=jgg@nvidia.com \
--cc=lance.yang@linux.dev \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=lorenzo.stoakes@oracle.com \
--cc=mhocko@suse.com \
--cc=muchun.song@linux.dev \
--cc=npache@redhat.com \
--cc=osalvador@suse.de \
--cc=rppt@kernel.org \
--cc=ryan.roberts@arm.com \
--cc=surenb@google.com \
--cc=vbabka@suse.cz \
--cc=willy@infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox