FAILED: patch "[PATCH] mm/huge_memory: bypass THP tuneables for huge pfnmap mappings" failed to apply to 6.18-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 6.18-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.18.y
git checkout FETCH_HEAD
git cherry-pick -x e384abeb559d10d6505aec053ede9368d81d4c71
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026092210-parabola-undercut-a08b@gregkh' --subject-prefix 'PATCH 6.18.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From e384abeb559d10d6505aec053ede9368d81d4c71 Mon Sep 17 00:00:00 2001
From: "Lorenzo Stoakes (ARM)" <[email protected]>
Date: Thu, 27 Aug 2026 20:55:57 +0100
Subject: [PATCH] mm/huge_memory: bypass THP tuneables for huge pfnmap mappings
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 VMA_PFNMAP_BIT 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.
Note that drm_gem_shmem_mmap() and panthor_gem_mmap() establish huge PFN maps of shmem folios, however they are marked unevictable in drm_gem_get_pages(), and in any case would fail the reference check in __remove_mapping() even if they weren't.
Failing to map huge PFN maps has resulted in significant real-world performance degradation, see links for details.
mm/huge_memory.c +64 -22
@@ -92,7 +92,7 @@ unsigned long huge_anon_orders_madvise __read_mostly;unsigned long huge_anon_orders_inherit__read_mostly ;static bool anon_orders_configured__initdata ; -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;
@@ -118,6 +118,67 @@ static bool vma_is_special_huge(const struct vm_area_struct *vma)return vma_test_any (vma,VMA_PFNMAP_BIT ,VMA_MIXEDMAP_BIT ); } +static bool vma_file_bypass_thp_tuneables (const struct vm_area_struct *vma, +enum tva_type type) +{ +const bool has_huge_fault = vma->vm_ops->huge_fault; + +/* MADV_COLLAPSE ignores tuneables. */ +if (type ==TVA_FORCED_COLLAPSE ) +return true; +/* Huge PFN mappings are uncompactable so the policy doesn't apply. */ +if (vma_test (vma,VMA_PFNMAP_BIT ) && 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,enum tva_type type) +{ +return vma_file_bypass_thp_tuneables (vma, type) || +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,enum tva_type type) +{ +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, type)) +return false; + +switch (type) { +case TVA_PAGEFAULT : +/* +* Trust that ->huge_fault() handlers know what they are doing +* in fault path. +*/ +return has_huge_fault; +case TVA_SMAPS : +if (has_huge_fault) +return true; + fallthrough; +default : +/* Only regular file is valid in collapse path. */ +return file_thp_enabled (vma); + } +} + unsigned long __thp_vma_allowable_orders(struct vm_area_struct *vma, vm_flags_t vm_flags, enum tva_type type,
@@ -190,27 +251,8 @@ unsigned long __thp_vma_allowable_orders(struct vm_area_struct *vma, vma,vma_start_pgoff (vma),0 , forced_collapse); -if (!vma_is_anonymous (vma)) { -/* -* Enforce THP collapse requirements as necessary. Anonymous vmas -* were already handled in thp_vma_allowable_orders(). -*/ -if (!forced_collapse && - (!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, type) ? orders :0 ;if (vma_is_temporary_stack (vma))return 0 ;
Sasha Levin
maintainerPATCH 1/2 mm: move vma_kernel_pagesize() from hugetlb to mm.h
From: "David Hildenbrand (Arm)" <[email protected]>
[ Upstream commit 341ffe82a7a3a1e0756b58999405b6df0c2b3e8d ]
Patch series "mm: move vma_(kernel|mmu)_pagesize() out of hugetlb.c", v2.
Looking into vma_(kernel|mmu)_pagesize(), I realized that there is one scenario where DAX would not do the right thing when the kernel is not compiled with hugetlb support.
Without hugetlb support, vma_(kernel|mmu)_pagesize() will always return PAGE_SIZE instead of using the ->pagesize() result provided by dax-device code.
Fix that by moving vma_kernel_pagesize() to core MM code, where it belongs. I don't think this is stable material, but am not 100% sure.
Also, move vma_mmu_pagesize() while at it. Remove the unnecessary hugetlb.h inclusion from KVM code.
This patch (of 4):
In the past, only hugetlb had special "vma_kernel_pagesize()" requirements, so it provided its own implementation.
In commit 05ea88608d4e ("mm, hugetlbfs: introduce ->pagesize() to vm_operations_struct") we generalized that approach by providing a vm_ops->pagesize() callback to be used by device-dax.
Once device-dax started using that callback in commit c1d53b92b95c ("device-dax: implement ->pagesize() for smaps to report MMUPageSize") it was missed that CONFIG_DEV_DAX does not depend on hugetlb support.
So building a kernel with CONFIG_DEV_DAX but without CONFIG_HUGETLBFS would not pick up that value.
Fix it by moving vma_kernel_pagesize() to mm.h, providing only a single implementation. While at it, improve the kerneldoc a bit.
Ideally, we'd move vma_mmu_pagesize() as well to the header. However, its __weak symbol might be overwritten by a PPC variant in hugetlb code. So let's leave it in there for now, as it really only matters for some hugetlb oddities.
This was found by code inspection.
Stable-dep-of: e384abeb559d ("mm/huge_memory: bypass THP tuneables for huge pfnmap mappings")
--- include/linux/hugetlb.h | 7 ------- include/linux/mm.h | 20 ++++++++++++++++++++ mm/hugetlb.c | 17 ----------------- 3 files changed, 20 insertions(+), 24 deletions(-)
include/linux/hugetlb.h +0 -7
@@ -767,8 +767,6 @@ static inline unsigned long huge_page_size(const struct hstate *h)return (unsigned long )PAGE_SIZE << h->order; } -extern unsigned long vma_kernel_pagesize (struct vm_area_struct *vma); -extern unsigned long vma_mmu_pagesize (struct vm_area_struct *vma);static inline unsigned long huge_page_mask (struct hstate *h)
@@ -1184,11 +1182,6 @@ static inline unsigned long huge_page_mask(struct hstate *h)return PAGE_MASK ; } -static inline unsigned long vma_kernel_pagesize (struct vm_area_struct *vma) -{ -return PAGE_SIZE ; -} -static inline unsigned long vma_mmu_pagesize (struct vm_area_struct *vma) {return PAGE_SIZE ;
include/linux/mm.h +20 -0
@@ -1020,6 +1020,26 @@ static inline bool vma_is_shared_maywrite(const struct vm_area_struct *vma)return is_shared_maywrite (vma->vm_flags); } +/** +* vma_kernel_pagesize - Default page size granularity for this VMA. +* @vma: The user mapping. +* +* The kernel page size specifies in which granularity VMA modifications +* can be performed. Folios in this VMA will be aligned to, and at least +* the size of the number of bytes returned by this function. +* +* The default kernel page size is not affected by Transparent Huge Pages +* being in effect. +* +* Return: The default page size granularity for this VMA. +*/ +static inline unsigned long vma_kernel_pagesize (struct vm_area_struct *vma) +{ +if (unlikely (vma->vm_ops && vma->vm_ops->pagesize)) +return vma->vm_ops->pagesize (vma); +return PAGE_SIZE ; +} +static inline struct vm_area_struct *vma_find (struct vma_iterator *vmi,unsigned long max) {
mm/hugetlb.c +0 -17
@@ -1027,23 +1027,6 @@ static pgoff_t vma_hugecache_offset(struct hstate *h, (vma->vm_pgoff >>huge_page_order (h)); } -/** -* vma_kernel_pagesize - Page size granularity for this VMA. -* @vma: The user mapping. -* -* Folios in this VMA will be aligned to, and at least the size of the -* number of bytes returned by this function. -* -* Return: The default size of the folios allocated when backing a VMA. -*/ -unsigned long vma_kernel_pagesize (struct vm_area_struct *vma) -{ -if (vma->vm_ops && vma->vm_ops->pagesize) -return vma->vm_ops->pagesize (vma); -return PAGE_SIZE ; -} -EXPORT_SYMBOL_GPL (vma_kernel_pagesize); -/* * Return the page size being used by the MMU to back a VMA. In the majority * of cases, the page size used by the kernel matches the MMU size. On
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/2 mm/huge_memory: bypass THP tuneables for huge pfnmap mappings
From: "Lorenzo Stoakes (ARM)" <[email protected]>
[ Upstream commit e384abeb559d10d6505aec053ede9368d81d4c71 ]
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 VMA_PFNMAP_BIT 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.
Note that drm_gem_shmem_mmap() and panthor_gem_mmap() establish huge PFN maps of shmem folios, however they are marked unevictable in drm_gem_get_pages(), and in any case would fail the reference check in __remove_mapping() even if they weren't.
Failing to map huge PFN maps has resulted in significant real-world performance degradation, see links for details.
--- mm/huge_memory.c | 86 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 64 insertions(+), 22 deletions(-)
mm/huge_memory.c +64 -22
@@ -84,7 +84,7 @@ unsigned long huge_anon_orders_madvise __read_mostly;unsigned long huge_anon_orders_inherit__read_mostly ;static bool anon_orders_configured__initdata ; -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;
@@ -102,6 +102,67 @@ static inline bool file_thp_enabled(struct vm_area_struct *vma)return !inode_is_open_for_write (inode) &&S_ISREG (inode->i_mode); } +static bool vma_file_bypass_thp_tuneables (const struct vm_area_struct *vma, +enum tva_type type) +{ +const bool has_huge_fault = vma->vm_ops->huge_fault; + +/* MADV_COLLAPSE ignores tuneables. */ +if (type ==TVA_FORCED_COLLAPSE ) +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,enum tva_type type) +{ +return vma_file_bypass_thp_tuneables (vma, type) || +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,enum tva_type type) +{ +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, type)) +return false; + +switch (type) { +case TVA_PAGEFAULT : +/* +* Trust that ->huge_fault() handlers know what they are doing +* in fault path. +*/ +return has_huge_fault; +case TVA_SMAPS : +if (has_huge_fault) +return true; + fallthrough; +default : +/* Only regular file is valid in collapse path. */ +return file_thp_enabled (vma); + } +} + unsigned long __thp_vma_allowable_orders(struct vm_area_struct *vma, vm_flags_t vm_flags, enum tva_type type,
@@ -174,27 +235,8 @@ unsigned long __thp_vma_allowable_orders(struct vm_area_struct *vma, vma, vma->vm_pgoff,0 , forced_collapse); -if (!vma_is_anonymous (vma)) { -/* -* Enforce THP collapse requirements as necessary. Anonymous vmas -* were already handled in thp_vma_allowable_orders(). -*/ -if (!forced_collapse && - (!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, type) ? orders :0 ;if (vma_is_temporary_stack (vma))return 0 ;
Signature · 1 line
2.53.0