From: "Zi Yan" <ziy@nvidia.com>
To: "Fang Xieyan" <fangxy@xiaopeng.com>,
"Andrew Morton" <akpm@linux-foundation.org>,
"David Hildenbrand" <david@kernel.org>,
"Matthew Wilcox" <willy@infradead.org>, "Jan Kara" <jack@suse.cz>,
"Hugh Dickins" <hughd@google.com>,
"Carlos Maiolino" <cem@kernel.org>,
"Pankaj Raghav" <p.raghav@samsung.com>
Cc: "Baolin Wang" <baolin.wang@linux.alibaba.com>,
"Liam R . Howlett" <liam@infradead.org>,
"Nico Pache" <nico.pache@linux.dev>,
"Ryan Roberts" <ryan.roberts@arm.com>,
"Dev Jain" <dev.jain@arm.com>, "Barry Song" <baohua@kernel.org>,
"Lance Yang" <lance.yang@linux.dev>,
"Usama Arif" <usama.arif@linux.dev>,
"Kiryl Shutsemau" <kas@kernel.org>,
"Lorenzo Stoakes" <ljs@kernel.org>,
"Vlastimil Babka" <vbabka@kernel.org>,
"Mike Rapoport" <rppt@kernel.org>,
"Suren Baghdasaryan" <surenb@google.com>,
"Michal Hocko" <mhocko@suse.com>,
"Muchun Song" <muchun.song@linux.dev>,
"Kairui Song" <kasong@tencent.com>, <linux-mm@kvack.org>,
<linux-kernel@vger.kernel.org>, <linux-fsdevel@vger.kernel.org>,
<linux-xfs@vger.kernel.org>
Subject: Re: [RFC PATCH 0/3] mm: enable filesystem page-cache large folios without THP
Date: Mon, 09 Nov 2026 23:01:46 -0500 [thread overview]
Message-ID: <DMR8CJLIMPDY.2NOHDSE107FBK@nvidia.com> (raw)
In-Reply-To: <20261110035205.3036-1-fangxy@xiaopeng.com>
+Pankaj, since he was working on this[1].
[1] https://lore.kernel.org/all/20251206030858.1418814-1-p.raghav@samsung.com/
On Mon Nov 9, 2026 at 10:52 PM EST, Fang Xieyan wrote:
> This series makes filesystem page-cache large folios work on kernels
> built with CONFIG_TRANSPARENT_HUGEPAGE=n, and keeps them splittable
> there.
>
> 1. Why this is needed
>
> TRANSPARENT_HUGEPAGE depends on !PREEMPT_RT (mm/Kconfig), so a
> PREEMPT_RT kernel always has THP off. Today that also removes
> file-backed large folios entirely: the helpers that split them live in
> mm/huge_memory.c under CONFIG_TRANSPARENT_HUGEPAGE, and the order
> accessors in include/linux/pagemap.h short-circuit to "no large
> folios" when THP is off, so every filesystem that opts in silently
> ends up with order-0 folios.
>
> The consequence is not only throughput. XFS allows block sizes up to
> 64K and fs/xfs/xfs_super.c refuses to mount anything larger than
> mapping_max_folio_size_supported(). With THP=n that helper reports
> PAGE_SIZE, so a 64K-block filesystem cannot be mounted at all:
>
> XFS (vda): block size (65536 bytes) not supported; Only block size (4096) or less is supported
>
> There is no degraded mode to fall back to, because a block has to fit
> in a single page-cache folio - which is why
> fs/xfs/libxfs/xfs_ialloc.c derives min_folio_order from
> sb_blocklog - PAGE_SHIFT. Either page-cache large folios work without
> THP, or the filesystem is unusable.
>
> 2. What the series does
>
> The anon and file split helpers were already separated by Kairui
> Song's "mm/huge_memory: clean up and decouple the anon and file split
> helpers" (v6 04/17, in mm-unstable); that is the base this series
> starts from.
>
> 1/3 moves the folio-splitting implementation out of mm/huge_memory.c
> into mm/folio_split.c without changing any behaviour. The new object
> is still built by CONFIG_TRANSPARENT_HUGEPAGE, so a THP build keeps
> exactly the code it had before; a pure move is also the easiest thing
> to rebase on top of further churn in this area.
>
> 2/3 builds that object for CONFIG_LARGE_FOLIO instead, and drops the
> anon, PMD and khugepaged dependencies a file-only build cannot have.
> The symbol comes from Matthew Wilcox's "[PATCH v9 12/15]"; if that
> series is in first, this patch shrinks to its Kconfig default and the
> accessors it already rewrites.
>
> 3/3 enables filesystem page-cache large folios when THP is off. It
> lifts the compile-time short circuits in pagemap.h for
> mapping_max_folio_size_supported(), mapping_set_folio_order_range(),
> mapping_max_folio_order() and mapping_min_folio_order().
> PREFERRED_MAX_PAGECACHE_ORDER is left alone: an LF-only build keeps
> the existing cap of order 8 instead of following HPAGE_PMD_ORDER.
> Without THP such folios cannot be PMD-mapped, so raising the ceiling
> would mainly increase the maximum page-cache allocation size. The
> changelog has the arm64 64K-page arithmetic, which is a calculation
> and not a measurement.
>
> The split side is not rewritten: truncate, migration and memory-failure
> already call the helpers outside any THP ifdef, so with 2/3 in place
> they simply stop resolving to the -EINVAL stubs once 3/3 turns
> allocation on. madvise is inside a THP ifdef and does not take part.
>
> 3/3 also makes the XFS mount failure above say why it failed: when
> CONFIG_LARGE_FOLIO is not set, the warning now names the missing
> option instead of only reporting the block size as unsupported. With
> LF=y the added warning is compiled out completely.
>
> 3. Testing
>
> Six configurations build clean as full kernels, bzImage and the
> vmlinux link included, with no new warnings: A (THP=y), B (THP=n,
> LF=y), C (B plus HUGETLBFS), D (THP=n, LF=n), and RT-B and RT-C with
> PREEMPT_RT=y. The PREEMPT_RT configurations were build-tested only.
> No runtime PREEMPT_RT stress test or livelock validation was
> performed.
>
> THP=y is unchanged: the .text sections of mm/filemap.o,
> mm/readahead.o and mm/shmem.o are byte-identical before and after the
> series (md5 equal, 45896, 7139 and 35314 bytes). With THP=n and LF=n
> mm/filemap.o and mm/readahead.o stay identical (44584 and 6259 bytes)
> and every function in mm/shmem.o keeps its size; the only difference
> there is one dead argument load that the folded-out
> mapping_set_large_folios() call leaves behind, so the section keeps
> its 29778 bytes while its md5 does not match.
>
> In the new LF=y, THP=n configuration mm/shmem.o keeps its size as well,
> 48 bytes shorter at 29730. That difference is not from 3/3: 40 of the
> bytes are shmem_writeout(), which shrinks because 2/3 turns
> split_folio_to_list() from an inline -EINVAL stub into a real call, and
> the other 8 are the padding in front of the following function; the
> same 29730 bytes appear with 2/3 alone, and 3/3's own shmem hunk
> changes no function size. The new call is unreachable in this
> configuration anyway, since shmem_alloc_and_add_folio() still forces
> order 0 without THP.
>
> Where the generated code really changes is the allocation policy:
> mm/readahead.o grows by 880 bytes of .text (6259 to 7139) and
> mm/filemap.o by 134 (44584 to 44718). nm -u mm/folio_split.o lists no
> anon, pmd or khugepaged symbols.
>
> Runtime, x86_64, 4K pages, THP=n, QEMU/KVM, on a 64K-block XFS image
> (mkfs.xfs -b size=64k -s size=4k), with kprobes on
> filemap_alloc_folio, filemap_add_folio and __folio_split:
>
> - writing 64M: 84 allocations - 59 at order-8, 5 at order-7, 5 at
> order-6, 5 at order-5, 10 at order-4, i.e. exactly 64M;
> - reading the same 64M back after drop_caches: 72 allocations,
> 62 at order-8, 1 at order-7, 5 at order-6, 4 at order-4;
> - truncating 1M to 700K: one __folio_split, landing at order-4,
> which is the min_folio_order XFS asked for; order-0 never appears
> in any of the three phases;
> - tmpfs writing 32M: 8192 shmem_alloc_folio calls, all order-0;
> - shmem write vs F_SEAL_GROW, reproducible as: memfd_create(),
> ftruncate() to exactly 4096 bytes, F_ADD_SEALS with F_SEAL_GROW,
> then a single pwrite() of 8192 bytes at offset 0, comparing the
> syscall's return value. It returns 4096, the same as the
> pre-series THP=n kernel. A THP=y kernel returns -EPERM here, and
> so did the LF-only build before shmem's mapping was put back
> behind THP; that -EPERM is pre-existing behaviour of THP kernels,
> this series neither introduces it nor extends it to other
> configurations.
>
> Same image on the pre-series kernel, for reference: it fails to mount
> with -ENOSYS before any of the above can run. The whole probe was
> re-run on the final revision of the series with identical numbers.
>
> 4. What this turns on for existing filesystems
>
> LF=y makes the existing opt-in take effect for every filesystem that
> already asks for large folios, and that list is not ext4 only: ext4,
> xfs, btrfs, f2fs, fuse, afs, erofs, nfs, cifs and zonefs all call
> mapping_set_folio_order_range() or mapping_set_large_folios() from
> their inode or superblock setup, unconditionally, today. Those paths
> run on any THP=y kernel; the new configuration is only THP=n with
> LF=y. With THP off the ceiling is PREFERRED_MAX_PAGECACHE_ORDER,
> which stays at order 8.
>
> On the tested 4K-page configuration, 4K-block ext4 gets min order 0
> and max order 8, while 64K-block XFS gets min order 4. Btrfs derives
> both ends from the mkfs sectorsize and nodesize. A THP=y kernel keeps
> the order-9 ceiling (HPAGE_PMD_ORDER) it has today on 4K pages.
>
> shmem keeps its THP dependency: its mapping is only marked large-folio
> capable when THP is enabled, because shmem_alloc_and_add_folio() still
> forces orders to zero without it. This matters beyond cosmetics.
> generic_perform_write() sizes its write chunk from
> mapping_max_folio_size() and passes that length to ->write_begin()
> before clamping it to folio_size(), and shmem_write_begin() rejects
> pos + len > i_size for F_SEAL_GROW. On a 4K memfd sealed with
> F_SEAL_GROW, an 8K write at offset 0 returns 4096 on the pre-series
> THP=n kernel and -EPERM on a THP=y kernel; advertising order 8 while
> allocating order 0 reproduced the -EPERM on an LF-only build. Tying
> shmem's policy to LARGE_FOLIO means the allocation, swap and split
> sides together, which is a separate series.
>
> 5. What is not covered
>
> Since PREEMPT_RT is the motivation, the RT side needs to be explicit.
> The freeze-to-xarray-update window in __folio_freeze_split_file() is
> the fourth freeze site named by Matthew Wilcox in the RT livelock
> thread started by Dong Hui
> (<c2ff0c66422c4e2d869499a1186ff0ae@xiaomi.com>):
>
> There's also __folio_freeze_split_file(). I know PREEMPT_RT
> disables TRANSPARENT_HUGEPAGE at the moment, but hopefully that
> restriction will be lifted.
>
> This series does not fix that problem and does not claim to be
> RT-safe. It only makes a code path that already exists on THP kernels
> reachable in a configuration that has no THP, which is the same
> exposure Kairui described in 06/17 as "should be fixed generically".
> One detail that may matter if a reader-side fix is chosen: the
> function already holds the xarray lock until the folio is no longer
> frozen and visible, since folio_ref_unfreeze() happens before
> xas_unlock_irq(), so a generic fix of that shape would cover this path
> without touching it.
>
> Also not tested here: the migration, memory-failure and madvise split
> entries at runtime (only truncate was exercised end to end), arm64
> with 64K pages, nommu, KASAN and lockdep, xfstests, and the btrfs
> order range.
>
> 6. Questions
>
> (a) Non-THP split accounting. count_mthp_stat() is a no-op without
> THP, so in an LF-only build a file split updates no counter at all and
> THP_SPLIT_PAGE does not even appear in /proc/vmstat. I have a
> follow-up patch that gives the file path its own counter. Would you
> rather see a new vmstat item, an existing one reused, or nothing?
>
> (b) Should XFS select LARGE_FOLIO itself? Three lines of
> "select LARGE_FOLIO if MMU" in fs/xfs/Kconfig make 64K-block XFS
> mountable on a THP=n kernel with no manual configuration; I built such
> a kernel and mounted the 64K image. The cost is mm/folio_split.o: 3.2K
> of .text in a THP=n build, code that every THP=y build already carries,
> paid also by XFS builds that will never use a block size above the page
> size. Kconfig cannot express "only when a 64K filesystem is mounted".
> I left it out because it changes default coverage for a decision XFS
> maintainers should make, but I can add it as 4/4 if that is preferred.
>
> Comments welcome.
>
> Fang Xieyan (3):
> mm: move folio split code into mm/folio_split.c
> mm: build file-backed folio splitting with CONFIG_LARGE_FOLIO
> mm: enable filesystem page-cache large folios without THP
>
> MAINTAINERS | 1 +
> fs/xfs/xfs_super.c | 2 +
> include/linux/huge_mm.h | 60 ++-
> include/linux/page-flags.h | 5 +-
> include/linux/pagemap.h | 17 +-
> mm/Kconfig | 19 +
> mm/Makefile | 1 +
> mm/folio_split.c | 969 +++++++++++++++++++++++++++++++++++++
> mm/huge_memory.c | 920 -----------------------------------
> mm/internal.h | 1 +
> mm/shmem.c | 11 +-
> 11 files changed, 1054 insertions(+), 952 deletions(-)
> create mode 100644 mm/folio_split.c
>
>
> base-commit: b024a51b0184b1efb6f55b11aaf7b15a490a6307
--
Best Regards,
Yan, Zi
next prev parent reply other threads:[~2026-11-10 4:02 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-10 3:52 [RFC PATCH 0/3] mm: enable filesystem page-cache large folios without THP Fang Xieyan
2026-11-10 3:52 ` [RFC PATCH 1/3] mm: move folio split code into mm/folio_split.c Fang Xieyan
2026-11-11 3:52 ` sashiko-bot
2026-11-10 3:52 ` [RFC PATCH 2/3] mm: build file-backed folio splitting with CONFIG_LARGE_FOLIO Fang Xieyan
2026-11-10 3:52 ` [RFC PATCH 3/3] mm: enable filesystem page-cache large folios without THP Fang Xieyan
2026-11-10 21:09 ` Michal Hocko
2026-11-11 3:52 ` sashiko-bot
2026-11-10 4:01 ` Zi Yan [this message]
2026-11-10 4:10 ` [RFC PATCH 0/3] " Zi Yan
2026-11-10 4:11 ` Zi Yan
2026-11-11 7:22 ` David Hildenbrand (Arm)
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=DMR8CJLIMPDY.2NOHDSE107FBK@nvidia.com \
--to=ziy@nvidia.com \
--cc=akpm@linux-foundation.org \
--cc=baohua@kernel.org \
--cc=baolin.wang@linux.alibaba.com \
--cc=cem@kernel.org \
--cc=david@kernel.org \
--cc=dev.jain@arm.com \
--cc=fangxy@xiaopeng.com \
--cc=hughd@google.com \
--cc=jack@suse.cz \
--cc=kas@kernel.org \
--cc=kasong@tencent.com \
--cc=lance.yang@linux.dev \
--cc=liam@infradead.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=linux-xfs@vger.kernel.org \
--cc=ljs@kernel.org \
--cc=mhocko@suse.com \
--cc=muchun.song@linux.dev \
--cc=nico.pache@linux.dev \
--cc=p.raghav@samsung.com \
--cc=rppt@kernel.org \
--cc=ryan.roberts@arm.com \
--cc=surenb@google.com \
--cc=usama.arif@linux.dev \
--cc=vbabka@kernel.org \
--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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.