mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
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:10:06 -0500	[thread overview]
Message-ID: <DMR8IXC61XST.3GFDCM6FZ5OCM@nvidia.com> (raw)
In-Reply-To: <DMR8CJLIMPDY.2NOHDSE107FBK@nvidia.com>

+Luiz, since he is working on "mm: thp: always enable mTHP support"[2].

[2] https://lore.kernel.org/all/cover.1789695931.git.luizcap@redhat.com/

On Mon Nov 9, 2026 at 11:01 PM EST, Zi Yan wrote:
> +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


  reply	other threads:[~2026-11-10  4:10 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-10  3:52 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-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  4:01 ` [RFC PATCH 0/3] " Zi Yan
2026-11-10  4:10   ` Zi Yan [this message]
2026-11-10  4:11     ` Zi Yan

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=DMR8IXC61XST.3GFDCM6FZ5OCM@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®