From: "Lorenzo Stoakes (ARM)" <ljs@kernel.org>
To: stable@vger.kernel.org
Subject: [PATCH 6.12.y] mm/huge_memory: bypass THP tuneables for huge pfnmap mappings
Date: Tue, 20 Oct 2026 10:42:30 +0100 [thread overview]
Message-ID: <20261020094231.759650-1-ljs@kernel.org> (raw)
In-Reply-To: <2026092200-parchment-pursuable-481f@gregkh>
The sysfs THP tuneables at /sys/kernel/mm/transparent_huge_pages/ rather
confusingly only control the behaviour of THP in some instances.
They are not applicable to MADV_COLLAPSE operations, nor to DAX mappings.
Long-term, THP is predicated upon compaction being able to obtain large
folios to populate THP ranges.
However, vm_normal_folio() returns NULL for PFN map mappings, thus their
reference count is maintained by the driver, not core mm.
As a consequence, the folios are not subject to reclaim nor compaction, so
are not truly part of the THP mechanism at all.
However, since commit 5dd40721f147 ("mm: allow THP orders for PFNMAPs")
introduced the ability to establish huge PFN maps, they have been subject
to THP tuneables.
This is incorrect - if a huge PFN map is available (defined by
vma->vm_ops->huge_fault being non-NULL for a VM_PFNMAP VMA), then it
should be mapped huge upon fault-in.
Correct this by explicitly checking for this while ensuring that smaps
continues to accurately report THPeligible statistics.
While here, abstract the entire file-backed THP check in
vma_can_map_huge_file(), with sensible separation of logic into helper
functions.
Failing to map huge PFN maps has resulted in significant real-world
performance degradation, see links for details.
[ziy@nvidia.com: rename some functions]
Link: https://lore.kernel.org/DL1HIHWYJ7TB.1CY76SJS0V03L@nvidia.com
Fixes: 5dd40721f147 ("mm: allow THP orders for PFNMAPs")
Signed-off-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Signed-off-by: Zi Yan <ziy@nvidia.com>
Reported-by: Cedric Le Goater <clg@redhat.com>
Closes: https://lore.kernel.org/linux-mm/20260805055544.1568534-1-clg@redhat.com/
Reported-by: Saravanan D <saravanand@crusoe.ai>
Closes: https://lore.kernel.org/linux-mm/20260821070520.25759-1-saravanand@crusoe.ai/
Reviewed-by: Zi Yan <ziy@nvidia.com>
Tested-by: Saravanan D <saravanand@crusoe.ai>
Tested-by: Lance Yang <lance.yang@linux.dev>
Reviewed-by: SJ Park <sj@kernel.org>
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
(cherry picked from commit e384abeb559d10d6505aec053ede9368d81d4c71)
[ ljs - Converted to tva_flags, made file_thp_enabled() const in huge_mm.h
+ other smaller changes. Updated commit msg to reflect. ]
Signed-off-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
---
include/linux/huge_mm.h | 2 +-
mm/huge_memory.c | 79 ++++++++++++++++++++++++++++++-----------
2 files changed, 59 insertions(+), 22 deletions(-)
diff --git a/include/linux/huge_mm.h b/include/linux/huge_mm.h
index bd34b70dd0cf..10e41e8b1634 100644
--- a/include/linux/huge_mm.h
+++ b/include/linux/huge_mm.h
@@ -254,7 +254,7 @@ static inline unsigned long thp_vma_suitable_orders(struct vm_area_struct *vma,
return orders;
}
-static inline bool file_thp_enabled(struct vm_area_struct *vma)
+static inline bool file_thp_enabled(const struct vm_area_struct *vma)
{
struct inode *inode;
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 1a76a21724d4..2a7f42b8ca33 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -86,6 +86,62 @@ unsigned long huge_anon_orders_madvise __read_mostly;
unsigned long huge_anon_orders_inherit __read_mostly;
static bool anon_orders_configured __initdata;
+static bool vma_file_bypass_thp_tuneables(const struct vm_area_struct *vma,
+ unsigned long tva_flags)
+{
+ const bool has_huge_fault = vma->vm_ops->huge_fault;
+
+ /* MADV_COLLAPSE ignores tuneables. */
+ if (!(tva_flags & TVA_ENFORCE_SYSFS))
+ return true;
+ /* Huge PFN mappings are uncompactable so the policy doesn't apply. */
+ if ((vma->vm_flags & VM_PFNMAP) && has_huge_fault)
+ return true;
+ return false;
+}
+
+static bool vma_file_allow_thp_tuneables(vm_flags_t vm_flags)
+{
+ /* THP=always? */
+ if (hugepage_global_always())
+ return true;
+ /* THP=madvise and marked MADV_HUGEPAGE? */
+ if (hugepage_global_enabled() && (vm_flags & VM_HUGEPAGE))
+ return true;
+ return false;
+}
+
+static bool vma_file_check_thp_tuneables(const struct vm_area_struct *vma,
+ vm_flags_t vm_flags, unsigned long tva_flags)
+{
+ return vma_file_bypass_thp_tuneables(vma, tva_flags) ||
+ vma_file_allow_thp_tuneables(vm_flags);
+}
+
+static bool vma_can_map_huge_file(const struct vm_area_struct *vma,
+ vm_flags_t vm_flags, unsigned long tva_flags)
+{
+ const bool has_huge_fault = vma->vm_ops->huge_fault;
+
+ /*
+ * Enforce THP collapse requirements as necessary. Anonymous vmas
+ * were already handled in thp_vma_allowable_orders().
+ */
+ if (!vma_file_check_thp_tuneables(vma, vm_flags, tva_flags))
+ return false;
+
+ /*
+ * Trust that ->huge_fault() handlers know what they are doing
+ * in fault path.
+ */
+ if (tva_flags & TVA_IN_PF)
+ return has_huge_fault;
+ if ((tva_flags & TVA_SMAPS) && has_huge_fault)
+ return true;
+ /* Only regular file is valid in collapse path. */
+ return file_thp_enabled(vma);
+}
+
unsigned long __thp_vma_allowable_orders(struct vm_area_struct *vma,
unsigned long vm_flags,
unsigned long tva_flags,
@@ -158,27 +214,8 @@ unsigned long __thp_vma_allowable_orders(struct vm_area_struct *vma,
vma, vma->vm_pgoff, 0,
!enforce_sysfs);
- if (!vma_is_anonymous(vma)) {
- /*
- * Enforce sysfs THP requirements as necessary. Anonymous vmas
- * were already handled in thp_vma_allowable_orders().
- */
- if (enforce_sysfs &&
- (!hugepage_global_enabled() || (!(vm_flags & VM_HUGEPAGE) &&
- !hugepage_global_always())))
- return 0;
-
- /*
- * Trust that ->huge_fault() handlers know what they are doing
- * in fault path.
- */
- if (((in_pf || smaps)) && vma->vm_ops->huge_fault)
- return orders;
- /* Only regular file is valid in collapse path */
- if (((!in_pf || smaps)) && file_thp_enabled(vma))
- return orders;
- return 0;
- }
+ if (!vma_is_anonymous(vma))
+ return vma_can_map_huge_file(vma, vm_flags, tva_flags) ? orders : 0;
if (vma_is_temporary_stack(vma))
return 0;
--
2.56.0
next prev parent reply other threads:[~2026-10-20 9:42 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-22 9:37 FAILED: patch "[PATCH] mm/huge_memory: bypass THP tuneables for huge pfnmap mappings" failed to apply to 6.12-stable tree gregkh
2026-10-20 9:42 ` Lorenzo Stoakes (ARM) [this message]
2026-10-22 2:03 ` [PATCH 6.12.y] mm/huge_memory: bypass THP tuneables for huge pfnmap mappings Sasha Levin
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=20261020094231.759650-1-ljs@kernel.org \
--to=ljs@kernel.org \
--cc=stable@vger.kernel.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.