public inbox for io-uring@vger.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 0/5] Separate compound page from folio
@ 2026-01-30  3:48 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
                   ` (5 more replies)
  0 siblings, 6 replies; 9+ messages in thread
From: Zi Yan @ 2026-01-30  3:48 UTC (permalink / raw)
  To: Jason Gunthorpe, David Hildenbrand, Matthew Wilcox
  Cc: Alistair Popple, Balbir Singh, Andrew Morton, Lorenzo Stoakes,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Jens Axboe, Zi Yan, Baolin Wang,
	Nico Pache, Ryan Roberts, Dev Jain, Barry Song, Lance Yang,
	Muchun Song, Oscar Salvador, Brendan Jackman, Johannes Weiner,
	linux-mm, linux-kernel, io-uring

Hi all,

Based on my discussion with Jason about device private folio
reinitialization[1], I realize that the concepts of compound page and folio
are mixed together and confusing, as people think a compound page is equal
to a folio. This is not true, since a compound page means a group of
pages is managed as a whole and it can be something other than a folio,
for example, a slab page. To avoid further confusing people, this
patchset separates compound page from folio by moving any folio related
code out of compound page functions.

The code is on top of mm-new (2026-01-28-20-27) and all mm selftests
passed.

The key change is that a compound page no longer sets:
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.

Since these fields are only used by folios that are rmappable. The code
setting these fields is moved to page_rmappable_folio(). To make the
code move, this patchset also needs to changes several places, where
folio and compound page are used interchangably or unusual folio use:

1. in io_mem_alloc_compound(), a compound page is allocated, but later
   it is mapped via vm_insert_pages() like a rmappable folio;
2. __split_folio_to_order() sets large_rmappable flag directly instead
   of using page_rmappable_folio() for after-split folios;
3. hugetlb unsets large_rmappable to escape deferred_list unqueue
   operation.

At last, the page freeing path is also changed to have different checks
for compound page and folio.

One thing to note is that for compound page, I do not store compound
order in folio->_nr_pages, which overlaps with page[1].memcg_data and
use 1 << compound_order() instead, since I do not want to add a new
union to struct page and compound_nr() is not as widely used as
folio_nr_pages(). But let me know if there is a performance concern for
this.

Comments and suggestions are welcome.



Link: https://lore.kernel.org/all/F7E3DF24-A37B-40A0-A507-CEF4AB76C44D@nvidia.com/ [1]

Zi Yan (5):
  io_uring: allocate folio in io_mem_alloc_compound() and function
    rename
  mm/huge_memory: use page_rmappable_folio() to convert after-split
    folios
  mm/hugetlb: set large_rmappable on hugetlb and avoid deferred_list
    handling
  mm: only use struct page in compound_nr() and compound_order()
  mm: code separation for compound page and folio

 include/linux/mm.h | 12 ++++--------
 io_uring/memmap.c  | 12 ++++++------
 mm/huge_memory.c   |  5 ++---
 mm/hugetlb.c       |  8 ++++----
 mm/hugetlb_cma.c   |  2 +-
 mm/internal.h      | 47 +++++++++++++++++++++++++++-------------------
 mm/mm_init.c       |  2 +-
 mm/page_alloc.c    | 23 ++++++++++++++++++-----
 8 files changed, 64 insertions(+), 47 deletions(-)

-- 
2.51.0


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [RFC PATCH 1/5] io_uring: allocate folio in io_mem_alloc_compound() and function rename
  2026-01-30  3:48 [RFC PATCH 0/5] Separate compound page from folio Zi Yan
@ 2026-01-30  3:48 ` 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
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 9+ messages in thread
From: Zi Yan @ 2026-01-30  3:48 UTC (permalink / raw)
  To: Jason Gunthorpe, David Hildenbrand, Matthew Wilcox
  Cc: Alistair Popple, Balbir Singh, Andrew Morton, Lorenzo Stoakes,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Jens Axboe, Zi Yan, Baolin Wang,
	Nico Pache, Ryan Roberts, Dev Jain, Barry Song, Lance Yang,
	Muchun Song, Oscar Salvador, Brendan Jackman, Johannes Weiner,
	linux-mm, linux-kernel, io-uring

The page allocated in io_mem_alloc_compound() is actually used as a folio
later in io_region_mmap(). So allocate a folio instead of a compound page
and rename io_mem_alloc_compound() to io_mem_alloc_folio().

This prepares for code separation of compound page and folio in a follow-up
commit.

Signed-off-by: Zi Yan <ziy@nvidia.com>
---
 io_uring/memmap.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/io_uring/memmap.c b/io_uring/memmap.c
index 7d3c5eb58480..8ed8a78d71cc 100644
--- a/io_uring/memmap.c
+++ b/io_uring/memmap.c
@@ -15,10 +15,10 @@
 #include "rsrc.h"
 #include "zcrx.h"
 
-static bool io_mem_alloc_compound(struct page **pages, int nr_pages,
+static bool io_mem_alloc_folio(struct page **pages, int nr_pages,
 				  size_t size, gfp_t gfp)
 {
-	struct page *page;
+	struct folio *folio;
 	int i, order;
 
 	order = get_order(size);
@@ -27,12 +27,12 @@ static bool io_mem_alloc_compound(struct page **pages, int nr_pages,
 	else if (order)
 		gfp |= __GFP_COMP;
 
-	page = alloc_pages(gfp, order);
-	if (!page)
+	folio = folio_alloc(gfp, order);
+	if (!folio)
 		return false;
 
 	for (i = 0; i < nr_pages; i++)
-		pages[i] = page + i;
+		pages[i] = folio_page(folio, i);
 
 	return true;
 }
@@ -162,7 +162,7 @@ static int io_region_allocate_pages(struct io_mapped_region *mr,
 	if (!pages)
 		return -ENOMEM;
 
-	if (io_mem_alloc_compound(pages, mr->nr_pages, size, gfp)) {
+	if (io_mem_alloc_folio(pages, mr->nr_pages, size, gfp)) {
 		mr->flags |= IO_REGION_F_SINGLE_REF;
 		goto done;
 	}
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [RFC PATCH 2/5] mm/huge_memory: use page_rmappable_folio() to convert after-split folios
  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 ` 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
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 9+ messages in thread
From: Zi Yan @ 2026-01-30  3:48 UTC (permalink / raw)
  To: Jason Gunthorpe, David Hildenbrand, Matthew Wilcox
  Cc: Alistair Popple, Balbir Singh, Andrew Morton, Lorenzo Stoakes,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Jens Axboe, Zi Yan, Baolin Wang,
	Nico Pache, Ryan Roberts, Dev Jain, Barry Song, Lance Yang,
	Muchun Song, Oscar Salvador, Brendan Jackman, Johannes Weiner,
	linux-mm, linux-kernel, io-uring

Current code uses folio_set_large_rmappable() on after-split folios, but
these folios should be treated as compound pages and converted to folios
with page_rmappable_folio().

This prepares for code separation of compound page and folio in a follow-up
commit.

Signed-off-by: Zi Yan <ziy@nvidia.com>
---
 mm/huge_memory.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 44ff8a648afd..74ba076e3fc0 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -3558,10 +3558,9 @@ static void __split_folio_to_order(struct folio *folio, int old_order,
 		 * which needs correct compound_head().
 		 */
 		clear_compound_head(new_head);
-		if (new_order) {
+		if (new_order)
 			prep_compound_page(new_head, new_order);
-			folio_set_large_rmappable(new_folio);
-		}
+		page_rmappable_folio(new_head);
 
 		if (folio_test_young(folio))
 			folio_set_young(new_folio);
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [RFC PATCH 3/5] mm/hugetlb: set large_rmappable on hugetlb and avoid deferred_list handling
  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 ` Zi Yan
  2026-01-30  3:48 ` [RFC PATCH 4/5] mm: only use struct page in compound_nr() and compound_order() Zi Yan
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 9+ messages in thread
From: Zi Yan @ 2026-01-30  3:48 UTC (permalink / raw)
  To: Jason Gunthorpe, David Hildenbrand, Matthew Wilcox
  Cc: Alistair Popple, Balbir Singh, Andrew Morton, Lorenzo Stoakes,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Jens Axboe, Zi Yan, Baolin Wang,
	Nico Pache, Ryan Roberts, Dev Jain, Barry Song, Lance Yang,
	Muchun Song, Oscar Salvador, Brendan Jackman, Johannes Weiner,
	linux-mm, linux-kernel, io-uring

Commit f708f6970cc9 ("mm/hugetlb: fix kernel NULL pointer dereference when
migrating hugetlb folio") fixed a NULL pointer dereference when
folio_undo_large_rmappable(), now folio_unqueue_deferred_list(), is used on
hugetlb to clear deferred_list. It cleared large_rmappable flag on hugetlb.
hugetlb is rmappable, thus clearing large_rmappable flag looks misleading.
Instead, reject hugetlb in folio_unqueue_deferred_list() to avoid the
issue.

This prepares for code separation of compound page and folio in a follow-up
commit.

Signed-off-by: Zi Yan <ziy@nvidia.com>
---
 mm/hugetlb.c     | 6 +++---
 mm/hugetlb_cma.c | 2 +-
 mm/internal.h    | 3 ++-
 3 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 6e855a32de3d..7466c7bf41a1 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -1422,8 +1422,8 @@ static struct folio *alloc_gigantic_frozen_folio(int order, gfp_t gfp_mask,
 	if (hugetlb_cma_exclusive_alloc())
 		return NULL;
 
-	folio = (struct folio *)alloc_contig_frozen_pages(1 << order, gfp_mask,
-							  nid, nodemask);
+	folio = page_rmappable_folio(alloc_contig_frozen_pages(1 << order, gfp_mask,
+							  nid, nodemask));
 	return folio;
 }
 #else /* !CONFIG_ARCH_HAS_GIGANTIC_PAGE || !CONFIG_CONTIG_ALLOC */
@@ -1859,7 +1859,7 @@ static struct folio *alloc_buddy_frozen_folio(int order, gfp_t gfp_mask,
 	if (alloc_try_hard)
 		gfp_mask |= __GFP_RETRY_MAYFAIL;
 
-	folio = (struct folio *)__alloc_frozen_pages(gfp_mask, order, nid, nmask);
+	folio = page_rmappable_folio(__alloc_frozen_pages(gfp_mask, order, nid, nmask));
 
 	/*
 	 * If we did not specify __GFP_RETRY_MAYFAIL, but still got a
diff --git a/mm/hugetlb_cma.c b/mm/hugetlb_cma.c
index f83ae4998990..4245b5dda4dc 100644
--- a/mm/hugetlb_cma.c
+++ b/mm/hugetlb_cma.c
@@ -51,7 +51,7 @@ struct folio *hugetlb_cma_alloc_frozen_folio(int order, gfp_t gfp_mask,
 	if (!page)
 		return NULL;
 
-	folio = page_folio(page);
+	folio = page_rmappable_folio(page);
 	folio_set_hugetlb_cma(folio);
 	return folio;
 }
diff --git a/mm/internal.h b/mm/internal.h
index d67e8bb75734..8bb22fb9a0e1 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -835,7 +835,8 @@ static inline void folio_set_order(struct folio *folio, unsigned int order)
 bool __folio_unqueue_deferred_split(struct folio *folio);
 static inline bool folio_unqueue_deferred_split(struct folio *folio)
 {
-	if (folio_order(folio) <= 1 || !folio_test_large_rmappable(folio))
+	if (folio_order(folio) <= 1 || !folio_test_large_rmappable(folio) ||
+	    folio_test_hugetlb(folio))
 		return false;
 
 	/*
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [RFC PATCH 4/5] mm: only use struct page in compound_nr() and compound_order()
  2026-01-30  3:48 [RFC PATCH 0/5] Separate compound page from folio Zi Yan
                   ` (2 preceding siblings ...)
  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 ` Zi Yan
  2026-01-30  3:48 ` [RFC PATCH 5/5] mm: code separation for compound page and folio Zi Yan
  2026-01-30  8:15 ` [syzbot ci] Re: Separate compound page from folio syzbot ci
  5 siblings, 0 replies; 9+ messages in thread
From: Zi Yan @ 2026-01-30  3:48 UTC (permalink / raw)
  To: Jason Gunthorpe, David Hildenbrand, Matthew Wilcox
  Cc: Alistair Popple, Balbir Singh, Andrew Morton, Lorenzo Stoakes,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Jens Axboe, Zi Yan, Baolin Wang,
	Nico Pache, Ryan Roberts, Dev Jain, Barry Song, Lance Yang,
	Muchun Song, Oscar Salvador, Brendan Jackman, Johannes Weiner,
	linux-mm, linux-kernel, io-uring

A compound page is not a folio. Using struct folio in compound_nr() and
compound_order() is misleading. Use struct page and refer to the right
subpage of a compound page to set compound page order. compound_nr() is
calculated using compound_order() instead of reading folio->_nr_pages.

Signed-off-by: Zi Yan <ziy@nvidia.com>
---
 include/linux/mm.h | 12 ++++--------
 1 file changed, 4 insertions(+), 8 deletions(-)

diff --git a/include/linux/mm.h b/include/linux/mm.h
index f8a8fd47399c..f1c54d9f4620 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1428,11 +1428,9 @@ static inline unsigned long folio_large_nr_pages(const struct folio *folio)
  */
 static inline unsigned int compound_order(const struct page *page)
 {
-	const struct folio *folio = (struct folio *)page;
-
-	if (!test_bit(PG_head, &folio->flags.f))
+	if (!test_bit(PG_head, &page->flags.f))
 		return 0;
-	return folio_large_order(folio);
+	return page[1].flags.f & 0xffUL;
 }
 
 /**
@@ -2514,11 +2512,9 @@ static inline unsigned long folio_nr_pages(const struct folio *folio)
  */
 static inline unsigned long compound_nr(const struct page *page)
 {
-	const struct folio *folio = (struct folio *)page;
-
-	if (!test_bit(PG_head, &folio->flags.f))
+	if (!test_bit(PG_head, &page->flags.f))
 		return 1;
-	return folio_large_nr_pages(folio);
+	return 1 << compound_order(page);
 }
 
 /**
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [RFC PATCH 5/5] mm: code separation for compound page and folio
  2026-01-30  3:48 [RFC PATCH 0/5] Separate compound page from folio Zi Yan
                   ` (3 preceding siblings ...)
  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
  2026-01-30  8:15 ` [syzbot ci] Re: Separate compound page from folio syzbot ci
  5 siblings, 0 replies; 9+ messages in thread
From: Zi Yan @ 2026-01-30  3:48 UTC (permalink / raw)
  To: Jason Gunthorpe, David Hildenbrand, Matthew Wilcox
  Cc: Alistair Popple, Balbir Singh, Andrew Morton, Lorenzo Stoakes,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Jens Axboe, Zi Yan, Baolin Wang,
	Nico Pache, Ryan Roberts, Dev Jain, Barry Song, Lance Yang,
	Muchun Song, Oscar Salvador, Brendan Jackman, Johannes Weiner,
	linux-mm, linux-kernel, io-uring

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


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [syzbot ci] Re: Separate compound page from folio
  2026-01-30  3:48 [RFC PATCH 0/5] Separate compound page from folio Zi Yan
                   ` (4 preceding siblings ...)
  2026-01-30  3:48 ` [RFC PATCH 5/5] mm: code separation for compound page and folio Zi Yan
@ 2026-01-30  8:15 ` syzbot ci
  2026-01-30 16:39   ` [syzbot ci] " Zi Yan
  5 siblings, 1 reply; 9+ messages in thread
From: syzbot ci @ 2026-01-30  8:15 UTC (permalink / raw)
  To: akpm, apopple, axboe, balbirs, baohua, baolin.wang, david,
	dev.jain, hannes, io-uring, jackmanb, jgg, lance.yang,
	liam.howlett, linux-kernel, linux-mm, lorenzo.stoakes, mhocko,
	muchun.song, npache, osalvador, rppt, ryan.roberts, surenb,
	vbabka, willy, ziy
  Cc: syzbot, syzkaller-bugs

syzbot ci has tested the following series

[v1] Separate compound page from folio
https://lore.kernel.org/all/20260130034818.472804-1-ziy@nvidia.com
* [RFC PATCH 1/5] io_uring: allocate folio in io_mem_alloc_compound() and function rename
* [RFC PATCH 2/5] mm/huge_memory: use page_rmappable_folio() to convert after-split folios
* [RFC PATCH 3/5] mm/hugetlb: set large_rmappable on hugetlb and avoid deferred_list handling
* [RFC PATCH 4/5] mm: only use struct page in compound_nr() and compound_order()
* [RFC PATCH 5/5] mm: code separation for compound page and folio

and found the following issue:
WARNING in __folio_large_mapcount_sanity_checks

Full report is available here:
https://ci.syzbot.org/series/f64f0297-d388-4cfa-b3be-f05819d0ce34

***

WARNING in __folio_large_mapcount_sanity_checks

tree:      mm-new
URL:       https://kernel.googlesource.com/pub/scm/linux/kernel/git/akpm/mm.git
base:      0241748f8b68fc2bf637f4901b9d7ca660d177ca
arch:      amd64
compiler:  Debian clang version 21.1.8 (++20251221033036+2078da43e25a-1~exp1~20251221153213.50), Debian LLD 21.1.8
config:    https://ci.syzbot.org/builds/76dc5ea6-0ff5-410b-8b1f-72e5607a704e/config
C repro:   https://ci.syzbot.org/findings/a308f1d6-69e2-4ebc-80a9-b51d9dc02851/c_repro
syz repro: https://ci.syzbot.org/findings/a308f1d6-69e2-4ebc-80a9-b51d9dc02851/syz_repro

------------[ cut here ]------------
diff > folio_large_nr_pages(folio)
WARNING: ./include/linux/rmap.h:148 at __folio_large_mapcount_sanity_checks+0x499/0x6b0 include/linux/rmap.h:148, CPU#1: syz.0.17/5988
Modules linked in:
CPU: 1 UID: 0 PID: 5988 Comm: syz.0.17 Not tainted syzkaller #0 PREEMPT(full) 
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.2-debian-1.16.2-1 04/01/2014
RIP: 0010:__folio_large_mapcount_sanity_checks+0x499/0x6b0 include/linux/rmap.h:148
Code: 5f 5d e9 4a 4e 64 09 cc e8 84 d8 aa ff 90 0f 0b 90 e9 82 fc ff ff e8 76 d8 aa ff 90 0f 0b 90 e9 8f fc ff ff e8 68 d8 aa ff 90 <0f> 0b 90 e9 b8 fc ff ff e8 5a d8 aa ff 90 0f 0b 90 e9 f2 fc ff ff
RSP: 0018:ffffc900040e72f8 EFLAGS: 00010293
RAX: ffffffff8217c0f8 RBX: ffffea0006ef5c00 RCX: ffff888105fdba80
RDX: 0000000000000000 RSI: 0000000000000001 RDI: 0000000000000000
RBP: 0000000000000001 R08: ffffea0006ef5c07 R09: 1ffffd4000ddeb80
R10: dffffc0000000000 R11: fffff94000ddeb81 R12: 0000000000000001
R13: 0000000000000000 R14: 1ffffd4000ddeb8f R15: ffffea0006ef5c78
FS:  00005555867b3500(0000) GS:ffff8882a9923000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00002000000000c0 CR3: 0000000103ab0000 CR4: 00000000000006f0
Call Trace:
 <TASK>
 folio_add_return_large_mapcount include/linux/rmap.h:184 [inline]
 __folio_add_rmap mm/rmap.c:1377 [inline]
 __folio_add_file_rmap mm/rmap.c:1696 [inline]
 folio_add_file_rmap_ptes+0x4c2/0xe60 mm/rmap.c:1722
 insert_page_into_pte_locked+0x5ab/0x910 mm/memory.c:2378
 insert_page+0x186/0x2d0 mm/memory.c:2398
 packet_mmap+0x360/0x530 net/packet/af_packet.c:4622
 vfs_mmap include/linux/fs.h:2053 [inline]
 mmap_file mm/internal.h:167 [inline]
 __mmap_new_file_vma mm/vma.c:2468 [inline]
 __mmap_new_vma mm/vma.c:2532 [inline]
 __mmap_region mm/vma.c:2759 [inline]
 mmap_region+0x18fe/0x2240 mm/vma.c:2837
 do_mmap+0xc39/0x10c0 mm/mmap.c:559
 vm_mmap_pgoff+0x2c9/0x4f0 mm/util.c:581
 ksys_mmap_pgoff+0x51e/0x760 mm/mmap.c:605
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0xe2/0xf80 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7f5d7399acb9
Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 e8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007ffe9f3eea78 EFLAGS: 00000246 ORIG_RAX: 0000000000000009
RAX: ffffffffffffffda RBX: 00007f5d73c15fa0 RCX: 00007f5d7399acb9
RDX: 0000000000000002 RSI: 0000000000030000 RDI: 0000200000000000
RBP: 00007f5d73a08bf7 R08: 0000000000000003 R09: 0000000000000000
R10: 0000000000000011 R11: 0000000000000246 R12: 0000000000000000
R13: 00007f5d73c15fac R14: 00007f5d73c15fa0 R15: 00007f5d73c15fa0
 </TASK>


***

If these findings have caused you to resend the series or submit a
separate fix, please add the following tag to your commit message:
  Tested-by: syzbot@syzkaller.appspotmail.com

---
This report is generated by a bot. It may contain errors.
syzbot ci engineers can be reached at syzkaller@googlegroups.com.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [syzbot ci] Separate compound page from folio
  2026-01-30  8:15 ` [syzbot ci] Re: Separate compound page from folio syzbot ci
@ 2026-01-30 16:39   ` Zi Yan
  2026-01-30 16:41     ` syzbot ci
  0 siblings, 1 reply; 9+ messages in thread
From: Zi Yan @ 2026-01-30 16:39 UTC (permalink / raw)
  To: syzbot ci
  Cc: akpm, apopple, axboe, balbirs, baohua, baolin.wang, david,
	dev.jain, hannes, io-uring, jackmanb, jgg, lance.yang,
	liam.howlett, linux-kernel, linux-mm, lorenzo.stoakes, mhocko,
	muchun.song, npache, osalvador, rppt, ryan.roberts, surenb,
	vbabka, willy, syzbot, syzkaller-bugs

On 30 Jan 2026, at 3:15, syzbot ci wrote:

> syzbot ci has tested the following series
>
> [v1] Separate compound page from folio
> https://lore.kernel.org/all/20260130034818.472804-1-ziy@nvidia.com
> * [RFC PATCH 1/5] io_uring: allocate folio in io_mem_alloc_compound() and function rename
> * [RFC PATCH 2/5] mm/huge_memory: use page_rmappable_folio() to convert after-split folios
> * [RFC PATCH 3/5] mm/hugetlb: set large_rmappable on hugetlb and avoid deferred_list handling
> * [RFC PATCH 4/5] mm: only use struct page in compound_nr() and compound_order()
> * [RFC PATCH 5/5] mm: code separation for compound page and folio
>
> and found the following issue:
> WARNING in __folio_large_mapcount_sanity_checks
>
> Full report is available here:
> https://ci.syzbot.org/series/f64f0297-d388-4cfa-b3be-f05819d0ce34
>
> ***
>
> WARNING in __folio_large_mapcount_sanity_checks
>
> tree:      mm-new
> URL:       https://kernel.googlesource.com/pub/scm/linux/kernel/git/akpm/mm.git
> base:      0241748f8b68fc2bf637f4901b9d7ca660d177ca
> arch:      amd64
> compiler:  Debian clang version 21.1.8 (++20251221033036+2078da43e25a-1~exp1~20251221153213.50), Debian LLD 21.1.8
> config:    https://ci.syzbot.org/builds/76dc5ea6-0ff5-410b-8b1f-72e5607a704e/config
> C repro:   https://ci.syzbot.org/findings/a308f1d6-69e2-4ebc-80a9-b51d9dc02851/c_repro
> syz repro: https://ci.syzbot.org/findings/a308f1d6-69e2-4ebc-80a9-b51d9dc02851/syz_repro
>
> ------------[ cut here ]------------
> diff > folio_large_nr_pages(folio)
> WARNING: ./include/linux/rmap.h:148 at __folio_large_mapcount_sanity_checks+0x499/0x6b0 include/linux/rmap.h:148, CPU#1: syz.0.17/5988
> Modules linked in:
> CPU: 1 UID: 0 PID: 5988 Comm: syz.0.17 Not tainted syzkaller #0 PREEMPT(full)
> Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.2-debian-1.16.2-1 04/01/2014
> RIP: 0010:__folio_large_mapcount_sanity_checks+0x499/0x6b0 include/linux/rmap.h:148
> Code: 5f 5d e9 4a 4e 64 09 cc e8 84 d8 aa ff 90 0f 0b 90 e9 82 fc ff ff e8 76 d8 aa ff 90 0f 0b 90 e9 8f fc ff ff e8 68 d8 aa ff 90 <0f> 0b 90 e9 b8 fc ff ff e8 5a d8 aa ff 90 0f 0b 90 e9 f2 fc ff ff
> RSP: 0018:ffffc900040e72f8 EFLAGS: 00010293
> RAX: ffffffff8217c0f8 RBX: ffffea0006ef5c00 RCX: ffff888105fdba80
> RDX: 0000000000000000 RSI: 0000000000000001 RDI: 0000000000000000
> RBP: 0000000000000001 R08: ffffea0006ef5c07 R09: 1ffffd4000ddeb80
> R10: dffffc0000000000 R11: fffff94000ddeb81 R12: 0000000000000001
> R13: 0000000000000000 R14: 1ffffd4000ddeb8f R15: ffffea0006ef5c78
> FS:  00005555867b3500(0000) GS:ffff8882a9923000(0000) knlGS:0000000000000000
> CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> CR2: 00002000000000c0 CR3: 0000000103ab0000 CR4: 00000000000006f0
> Call Trace:
>  <TASK>
>  folio_add_return_large_mapcount include/linux/rmap.h:184 [inline]
>  __folio_add_rmap mm/rmap.c:1377 [inline]
>  __folio_add_file_rmap mm/rmap.c:1696 [inline]
>  folio_add_file_rmap_ptes+0x4c2/0xe60 mm/rmap.c:1722
>  insert_page_into_pte_locked+0x5ab/0x910 mm/memory.c:2378
>  insert_page+0x186/0x2d0 mm/memory.c:2398
>  packet_mmap+0x360/0x530 net/packet/af_packet.c:4622
>  vfs_mmap include/linux/fs.h:2053 [inline]
>  mmap_file mm/internal.h:167 [inline]
>  __mmap_new_file_vma mm/vma.c:2468 [inline]
>  __mmap_new_vma mm/vma.c:2532 [inline]
>  __mmap_region mm/vma.c:2759 [inline]
>  mmap_region+0x18fe/0x2240 mm/vma.c:2837
>  do_mmap+0xc39/0x10c0 mm/mmap.c:559
>  vm_mmap_pgoff+0x2c9/0x4f0 mm/util.c:581
>  ksys_mmap_pgoff+0x51e/0x760 mm/mmap.c:605
>  do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
>  do_syscall_64+0xe2/0xf80 arch/x86/entry/syscall_64.c:94
>  entry_SYSCALL_64_after_hwframe+0x77/0x7f
> RIP: 0033:0x7f5d7399acb9
> Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 e8 ff ff ff f7 d8 64 89 01 48
> RSP: 002b:00007ffe9f3eea78 EFLAGS: 00000246 ORIG_RAX: 0000000000000009
> RAX: ffffffffffffffda RBX: 00007f5d73c15fa0 RCX: 00007f5d7399acb9
> RDX: 0000000000000002 RSI: 0000000000030000 RDI: 0000200000000000
> RBP: 00007f5d73a08bf7 R08: 0000000000000003 R09: 0000000000000000
> R10: 0000000000000011 R11: 0000000000000246 R12: 0000000000000000
> R13: 00007f5d73c15fac R14: 00007f5d73c15fa0 R15: 00007f5d73c15fa0
>  </TASK>
>
>
> ***
>
> If these findings have caused you to resend the series or submit a
> separate fix, please add the following tag to your commit message:
>   Tested-by: syzbot@syzkaller.appspotmail.com
>
> ---
> This report is generated by a bot. It may contain errors.
> syzbot ci engineers can be reached at syzkaller@googlegroups.com.

The issue comes from alloc_one_pg_vec_page() in net/packet/af_packet.c.
It allocates a compound page with __GFP_COMP, but latter does vm_insert_page()
in packet_mmap(), using it as a folio.

The fix below is a hack. We will need a get_free_folios() instead.
I will check all __GFP_COMP callers to find out which ones are using it
as a folio and which ones are using it as a compound page. I suspect
most are using it as a folio.


#syz test

diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 2194a6b3a062..90858d20dfbe 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -5311,6 +5311,8 @@ unsigned long get_free_pages_noprof(gfp_t gfp_mask, unsigned int order)
        page = alloc_pages_noprof(gfp_mask & ~__GFP_HIGHMEM, order);
        if (!page)
                return 0;
+       if (gfp_mask & __GFP_COMP)
+               return (unsigned long)folio_address(page_rmappable_folio(page));
        return (unsigned long) page_address(page);
 }
 EXPORT_SYMBOL(get_free_pages_noprof);

Best Regards,
Yan, Zi

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: Re: [syzbot ci] Separate compound page from folio
  2026-01-30 16:39   ` [syzbot ci] " Zi Yan
@ 2026-01-30 16:41     ` syzbot ci
  0 siblings, 0 replies; 9+ messages in thread
From: syzbot ci @ 2026-01-30 16:41 UTC (permalink / raw)
  To: ziy
  Cc: akpm, apopple, axboe, balbirs, baohua, baolin.wang, david,
	dev.jain, hannes, io-uring, jackmanb, jgg, lance.yang,
	liam.howlett, linux-kernel, linux-mm, lorenzo.stoakes, mhocko,
	muchun.song, npache, osalvador, rppt, ryan.roberts, surenb,
	syzbot, syzkaller-bugs, vbabka, willy, ziy


Unknown command


^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2026-01-30 16:41 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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 ` [RFC PATCH 5/5] mm: code separation for compound page and folio Zi Yan
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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox