* [PATCH] mm: shmem: fix the strategy for the tmpfs 'huge=' options
@ 2025-09-03 8:54 Baolin Wang
2025-10-21 17:24 ` Kairui Song
0 siblings, 1 reply; 2+ messages in thread
From: Baolin Wang @ 2025-09-03 8:54 UTC (permalink / raw)
To: akpm, hughd
Cc: willy, david, lorenzo.stoakes, ziy, Liam.Howlett, npache,
ryan.roberts, dev.jain, baohua, baolin.wang, linux-mm,
linux-kernel
After commit acd7ccb284b8 ("mm: shmem: add large folio support for tmpfs"),
we have extended tmpfs to allow any sized large folios, rather than just
PMD-sized large folios.
The strategy discussed previously was:
"
Considering that tmpfs already has the 'huge=' option to control the
PMD-sized large folios allocation, we can extend the 'huge=' option to
allow any sized large folios. The semantics of the 'huge=' mount option
are:
huge=never: no any sized large folios
huge=always: any sized large folios
huge=within_size: like 'always' but respect the i_size
huge=advise: like 'always' if requested with madvise()
Note: for tmpfs mmap() faults, due to the lack of a write size hint, still
allocate the PMD-sized huge folios if huge=always/within_size/advise is
set.
Moreover, the 'deny' and 'force' testing options controlled by
'/sys/kernel/mm/transparent_hugepage/shmem_enabled', still retain the same
semantics. The 'deny' can disable any sized large folios for tmpfs, while
the 'force' can enable PMD sized large folios for tmpfs.
"
This means that when tmpfs is mounted with 'huge=always' or 'huge=within_size',
tmpfs will allow getting a highest order hint based on the size of write() and
fallocate() paths. It will then try each allowable large order, rather than
continually attempting to allocate PMD-sized large folios as before.
However, this might break some user scenarios for those who want to use
PMD-sized large folios, such as the i915 driver which did not supply a write
size hint when allocating shmem [1].
Moreover, Hugh also complained that this will cause a regression in userspace
with 'huge=always' or 'huge=within_size'.
So, let's revisit the strategy for tmpfs large page allocation. A simple fix
would be to always try PMD-sized large folios first, and if that fails, fall
back to smaller large folios. This approach differs from the strategy for
large folio allocation used by other file systems, however, tmpfs is somewhat
different from other file systems, as quoted from David's opinion:
"
There were opinions in the past that tmpfs should just behave like any other fs,
and I think that's what we tried to satisfy here: use the write size as an
indication.
I assume there will be workloads where either approach will be beneficial. I also
assume that workloads that use ordinary fs'es could benefit from the same strategy
(start with PMD), while others will clearly not.
"
[1] https://lore.kernel.org/lkml/0d734549d5ed073c80b11601da3abdd5223e1889.1753689802.git.baolin.wang@linux.alibaba.com/
Fixes: acd7ccb284b8 ("mm: shmem: add large folio support for tmpfs")
Signed-off-by: Baolin Wang <baolin.wang@linux.alibaba.com>
---
Changes from RFC:
- Update the commit message.
---
Documentation/admin-guide/mm/transhuge.rst | 6 ++-
mm/shmem.c | 47 +++-------------------
2 files changed, 10 insertions(+), 43 deletions(-)
diff --git a/Documentation/admin-guide/mm/transhuge.rst b/Documentation/admin-guide/mm/transhuge.rst
index a16a04841b96..1654211cc6cf 100644
--- a/Documentation/admin-guide/mm/transhuge.rst
+++ b/Documentation/admin-guide/mm/transhuge.rst
@@ -419,6 +419,8 @@ option: ``huge=``. It can have following values:
always
Attempt to allocate huge pages every time we need a new page;
+ Always try PMD-sized huge pages first, and fall back to smaller-sized
+ huge pages if the PMD-sized huge page allocation fails;
never
Do not allocate huge pages. Note that ``madvise(..., MADV_COLLAPSE)``
@@ -426,7 +428,9 @@ never
is specified everywhere;
within_size
- Only allocate huge page if it will be fully within i_size.
+ Only allocate huge page if it will be fully within i_size;
+ Always try PMD-sized huge pages first, and fall back to smaller-sized
+ huge pages if the PMD-sized huge page allocation fails;
Also respect madvise() hints;
advise
diff --git a/mm/shmem.c b/mm/shmem.c
index 640fecc42f60..85a40a5b3f2b 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -573,42 +573,6 @@ static int shmem_confirm_swap(struct address_space *mapping, pgoff_t index,
static int shmem_huge __read_mostly = SHMEM_HUGE_NEVER;
static int tmpfs_huge __read_mostly = SHMEM_HUGE_NEVER;
-/**
- * shmem_mapping_size_orders - Get allowable folio orders for the given file size.
- * @mapping: Target address_space.
- * @index: The page index.
- * @write_end: end of a write, could extend inode size.
- *
- * This returns huge orders for folios (when supported) based on the file size
- * which the mapping currently allows at the given index. The index is relevant
- * due to alignment considerations the mapping might have. The returned order
- * may be less than the size passed.
- *
- * Return: The orders.
- */
-static inline unsigned int
-shmem_mapping_size_orders(struct address_space *mapping, pgoff_t index, loff_t write_end)
-{
- unsigned int order;
- size_t size;
-
- if (!mapping_large_folio_support(mapping) || !write_end)
- return 0;
-
- /* Calculate the write size based on the write_end */
- size = write_end - (index << PAGE_SHIFT);
- order = filemap_get_order(size);
- if (!order)
- return 0;
-
- /* If we're not aligned, allocate a smaller folio */
- if (index & ((1UL << order) - 1))
- order = __ffs(index);
-
- order = min_t(size_t, order, MAX_PAGECACHE_ORDER);
- return order > 0 ? BIT(order + 1) - 1 : 0;
-}
-
static unsigned int shmem_get_orders_within_size(struct inode *inode,
unsigned long within_size_orders, pgoff_t index,
loff_t write_end)
@@ -655,22 +619,21 @@ static unsigned int shmem_huge_global_enabled(struct inode *inode, pgoff_t index
* For tmpfs mmap()'s huge order, we still use PMD-sized order to
* allocate huge pages due to lack of a write size hint.
*
- * Otherwise, tmpfs will allow getting a highest order hint based on
- * the size of write and fallocate paths, then will try each allowable
- * huge orders.
+ * For tmpfs with 'huge=always' or 'huge=within_size' mount option,
+ * we will always try PMD-sized order first. If that failed, it will
+ * fall back to small large folios.
*/
switch (SHMEM_SB(inode->i_sb)->huge) {
case SHMEM_HUGE_ALWAYS:
if (vma)
return maybe_pmd_order;
- return shmem_mapping_size_orders(inode->i_mapping, index, write_end);
+ return THP_ORDERS_ALL_FILE_DEFAULT;
case SHMEM_HUGE_WITHIN_SIZE:
if (vma)
within_size_orders = maybe_pmd_order;
else
- within_size_orders = shmem_mapping_size_orders(inode->i_mapping,
- index, write_end);
+ within_size_orders = THP_ORDERS_ALL_FILE_DEFAULT;
within_size_orders = shmem_get_orders_within_size(inode, within_size_orders,
index, write_end);
--
2.43.7
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: [PATCH] mm: shmem: fix the strategy for the tmpfs 'huge=' options
2025-09-03 8:54 [PATCH] mm: shmem: fix the strategy for the tmpfs 'huge=' options Baolin Wang
@ 2025-10-21 17:24 ` Kairui Song
0 siblings, 0 replies; 2+ messages in thread
From: Kairui Song @ 2025-10-21 17:24 UTC (permalink / raw)
To: Baolin Wang
Cc: akpm, hughd, willy, david, lorenzo.stoakes, ziy, Liam.Howlett,
npache, ryan.roberts, dev.jain, baohua, linux-mm, linux-kernel
On Wed, Sep 3, 2025 at 4:59 PM Baolin Wang
<baolin.wang@linux.alibaba.com> wrote:
>
> After commit acd7ccb284b8 ("mm: shmem: add large folio support for tmpfs"),
> we have extended tmpfs to allow any sized large folios, rather than just
> PMD-sized large folios.
>
> The strategy discussed previously was:
> "
> Considering that tmpfs already has the 'huge=' option to control the
> PMD-sized large folios allocation, we can extend the 'huge=' option to
> allow any sized large folios. The semantics of the 'huge=' mount option
> are:
>
> huge=never: no any sized large folios
> huge=always: any sized large folios
> huge=within_size: like 'always' but respect the i_size
> huge=advise: like 'always' if requested with madvise()
>
> Note: for tmpfs mmap() faults, due to the lack of a write size hint, still
> allocate the PMD-sized huge folios if huge=always/within_size/advise is
> set.
>
> Moreover, the 'deny' and 'force' testing options controlled by
> '/sys/kernel/mm/transparent_hugepage/shmem_enabled', still retain the same
> semantics. The 'deny' can disable any sized large folios for tmpfs, while
> the 'force' can enable PMD sized large folios for tmpfs.
> "
>
> This means that when tmpfs is mounted with 'huge=always' or 'huge=within_size',
> tmpfs will allow getting a highest order hint based on the size of write() and
> fallocate() paths. It will then try each allowable large order, rather than
> continually attempting to allocate PMD-sized large folios as before.
>
> However, this might break some user scenarios for those who want to use
> PMD-sized large folios, such as the i915 driver which did not supply a write
> size hint when allocating shmem [1].
>
> Moreover, Hugh also complained that this will cause a regression in userspace
> with 'huge=always' or 'huge=within_size'.
>
> So, let's revisit the strategy for tmpfs large page allocation. A simple fix
> would be to always try PMD-sized large folios first, and if that fails, fall
> back to smaller large folios. This approach differs from the strategy for
> large folio allocation used by other file systems, however, tmpfs is somewhat
> different from other file systems, as quoted from David's opinion:
> "
> There were opinions in the past that tmpfs should just behave like any other fs,
> and I think that's what we tried to satisfy here: use the write size as an
> indication.
>
> I assume there will be workloads where either approach will be beneficial. I also
> assume that workloads that use ordinary fs'es could benefit from the same strategy
> (start with PMD), while others will clearly not.
> "
>
> [1] https://lore.kernel.org/lkml/0d734549d5ed073c80b11601da3abdd5223e1889.1753689802.git.baolin.wang@linux.alibaba.com/
> Fixes: acd7ccb284b8 ("mm: shmem: add large folio support for tmpfs")
> Signed-off-by: Baolin Wang <baolin.wang@linux.alibaba.com>
> ---
> Changes from RFC:
> - Update the commit message.
Hi Baolin
I'm seeing userspace errors after this commit. I'm using
"transparent_hugepage_tmpfs=within_size/always" and build kernel test
on top of tmpfs with swap on ZRAM, both within_size / always
results in same failure:
The error I'm seeing is when build the kernel gcc always fail with:
ld: kernel/workqueue.o:(.data..read_mostly+0x28): multiple definition
of `no symbol'; kernel/workqueue.o:(.data..read_mostly+0x30): first
defined here
ld: kernel/workqueue.o:(.data..read_mostly+0x20): multiple definition
of `no symbol'; kernel/workqueue.o:(.data..read_mostly+0x30): first
defined here
ld: kernel/workqueue.o:(.data..read_mostly+0x18): multiple definition
of `no symbol'; kernel/workqueue.o:(.data..read_mostly+0x30): first
defined here
ld: kernel/workqueue.o:(.data..read_mostly+0x10): multiple definition
of `no symbol'; kernel/workqueue.o:(.data..read_mostly+0x30): first
defined here
ld: kernel/workqueue.o:(.data..read_mostly+0x8): multiple definition
of `no symbol'; kernel/workqueue.o:(.data..read_mostly+0x30): first
defined here
ld: kernel/workqueue.o:(.data..read_mostly+0x0): multiple definition
of `no symbol'; kernel/workqueue.o:(.data..read_mostly+0x30): first
defined here
ld: kernel/workqueue.o: in function `no symbol':
:(.text+0x3760): multiple definition of `no symbol';
kernel/workqueue.o:(.data..read_mostly+0x30): first defined here
ld: kernel/workqueue.o: in function `no symbol':
:(.text+0x38c0): multiple definition of `no symbol';
kernel/workqueue.o:(.data..read_mostly+0x30): first defined here
ld: kernel/workqueue.o: in function `no symbol':
... <hundreds of lines of error like this on different files>...
After reverting this commit, the error is gone. I have a very stable
reproduce rate locally with different cgroup / memory pressure with
this patch applied, error logs are basically the same.
I'm still not sure what is causing this, a kernel bug or some
userspace bug is triggered by this. Changing the compiler to clang
then the problem is also gone. Still investigating.
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2025-10-21 17:25 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-09-03 8:54 [PATCH] mm: shmem: fix the strategy for the tmpfs 'huge=' options Baolin Wang
2025-10-21 17:24 ` Kairui Song
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox