FAILED: patch "[PATCH] mm/vma: predicate setting mmap_prepare VMA fields on new vma" 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 976d5e0ddac885b0219252f004f6c561c344df9d
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026100329-jaws-trash-1c19@gregkh' --subject-prefix 'PATCH 6.18.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 976d5e0ddac885b0219252f004f6c561c344df9d Mon Sep 17 00:00:00 2001
From: "Lorenzo Stoakes (ARM)" <[email protected]>
Date: Wed, 23 Sep 2026 18:45:41 +0100
Subject: [PATCH] mm/vma: predicate setting mmap_prepare VMA fields on new vma
alloc
It only makes sense to manipulate VMA fields if a new VMA was allocated, rather than merged.
VMA merging does not compare vm_ops or vm_private_data, so a merged VMA keeps its own, which is also what the legacy f_op->mmap path does since it never touches an existing VMA.
Currently, these fields will get overwritten by whatever state is established in the mmap_prepare hook, and if the VMA was merged, vm_ops->mapped will not have been called, so this could destructively clear existing state without replacing it with anything valid.
There is an implicit requirement that vm_private_data and vm_ops are fungible across VMAs which means that losing the 'new' state is fine.
However in this case the 'old' state is being overwritten by potentially invalid 'new' state, so this must be rectified.
Additionally constify have_mmap_prepare while here.
All existing in-tree users either derive state from the file or are unmergeable due to VMA flags, so this has no direct impact.
mm/vma.c +2 -2
@@ -2849,7 +2849,7 @@ static unsigned long __mmap_region(struct file *file, unsigned long addr, {struct mm_struct *mm = current->mm;struct vm_area_struct *vma =NULL ; -bool have_mmap_prepare = file && file->f_op->mmap_prepare; +const bool have_mmap_prepare = file && file->f_op->mmap_prepare;VMA_ITERATOR (vmi, mm, addr);const pgoff_t anon_pgoff = addr >>PAGE_SHIFT ;MMAP_STATE (map, mm, &vmi, addr, len, pgoff, anon_pgoff, vma_flags, file);
@@ -2892,7 +2892,7 @@ static unsigned long __mmap_region(struct file *file, unsigned long addr, allocated_new = true; } -if (have_mmap_prepare) +if (have_mmap_prepare && allocated_new)set_vma_user_defined_fields (vma, &map);__mmap_complete (&map, vma);
Sasha Levin
maintainerPATCH 1/5 mm/vma: remove unused function, make internal functions static
From: Lorenzo Stoakes <[email protected]>
[ Upstream commit cf1d98f44d056d7114554beb78665c20d1ed244a ]
unlink_file_vma() is not used by anything, so remove it.
vma_link() and vma_link_file() are only used within mm/vma.c, so make them static.
Stable-dep-of: 976d5e0ddac8 ("mm/vma: predicate setting mmap_prepare VMA fields on new vma alloc")
--- mm/vma.c | 21 ++------------------- mm/vma.h | 6 ------ 2 files changed, 2 insertions(+), 25 deletions(-)
mm/vma.c +2 -19
@@ -1800,24 +1800,7 @@ void unlink_file_vma_batch_final(struct unlink_vma_file_batch *vb)unlink_file_vma_batch_process (vb); } -/* -* Unlink a file-based vm structure from its interval tree, to hide -* vma from rmap and vmtruncate before freeing its page tables. -*/ -void unlink_file_vma (struct vm_area_struct *vma) -{ -struct file *file = vma->vm_file; - -if (file) { -struct address_space *mapping = file->f_mapping; - -i_mmap_lock_write (mapping); -__remove_shared_vm_struct (vma, mapping); -i_mmap_unlock_write (mapping); - } -} - -void vma_link_file (struct vm_area_struct *vma) +static void vma_link_file (struct vm_area_struct *vma) {struct file *file = vma->vm_file;struct address_space *mapping;
@@ -1830,7 +1813,7 @@ void vma_link_file(struct vm_area_struct *vma) } } -int vma_link (struct mm_struct *mm,struct vm_area_struct *vma) +static int vma_link (struct mm_struct *mm,struct vm_area_struct *vma) {VMA_ITERATOR (vmi, mm,0 );
mm/vma.h +0 -6
@@ -381,12 +381,6 @@ void unlink_file_vma_batch_final(struct unlink_vma_file_batch *vb);void unlink_file_vma_batch_add (struct unlink_vma_file_batch *vb,struct vm_area_struct *vma); -void unlink_file_vma (struct vm_area_struct *vma); - -void vma_link_file (struct vm_area_struct *vma); - -int vma_link (struct mm_struct *mm,struct vm_area_struct *vma); -struct vm_area_struct *copy_vma (struct vm_area_struct **vmap,unsigned long addr,unsigned long len,pgoff_t pgoff,bool *need_rmap_locks);
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/5 mm/vma: rename __mmap_prepare() function to avoid confusion
From: Lorenzo Stoakes <[email protected]>
[ Upstream commit 2bcd9207dedc585bae33ad7b337f2232a8a11da8 ]
Now we have the f_op->mmap_prepare() hook, having a static function called __mmap_prepare() that has nothing to do with it is confusing, so rename the function to __mmap_setup().
Preserve the separate setup and callback error paths so a failed callback still undoes memory accounting.
Record whether merging found a VMA and use that result to select new VMA allocation. This preserves existing behavior while providing the allocated_new flag needed by the follow-up change to user-defined fields. Move the error declaration below the mapping state to avoid a conflict with the follow-up const qualifier change.
Stable-dep-of: 976d5e0ddac8 ("mm/vma: predicate setting mmap_prepare VMA fields on new vma alloc")
--- mm/vma.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-)
mm/vma.c +8 -6
@@ -2365,7 +2365,7 @@ static void update_ksm_flags(struct mmap_state *map) }/* -* __mmap_prepare() - Prepare to gather any overlapping VMAs that need to be +* __mmap_setup() - Prepare to gather any overlapping VMAs that need to be * unmapped once the map operation is completed, check limits, account mapping * and clean up any pre-existing VMAs. *
@@ -2374,7 +2374,7 @@ static void update_ksm_flags(struct mmap_state *map)* * Returns: 0 on success, error code otherwise. */ -static int __mmap_prepare (struct mmap_state *map,struct list_head *uf) +static int __mmap_setup (struct mmap_state *map,struct list_head *uf) {int error;struct vma_iterator *vmi = map->vmi;
@@ -2676,14 +2676,15 @@ static unsigned long __mmap_region(struct file *file, unsigned long addr, {struct mm_struct *mm = current->mm;struct vm_area_struct *vma =NULL ; -int error;bool have_mmap_prepare = file && file->f_op->mmap_prepare;VMA_ITERATOR (vmi, mm, addr);MMAP_STATE (map, mm, &vmi, addr, len, pgoff, vm_flags, file); +bool allocated_new; +int error; map.check_ksm_early =can_set_ksm_flags_early (&map); - error =__mmap_prepare (&map, uf); + error =__mmap_setup (&map, uf);if (error) goto abort_munmap;if (have_mmap_prepare)
@@ -2702,7 +2703,8 @@ static unsigned long __mmap_region(struct file *file, unsigned long addr, }/* ...but if we can't, allocate a new VMA. */ -if (!vma) { + allocated_new = !vma; +if (allocated_new) { error =__mmap_new_vma (&map, &vma);if (error) goto unacct_error;
@@ -2715,7 +2717,7 @@ static unsigned long __mmap_region(struct file *file, unsigned long addr,return addr; -/* Accounting was done by __mmap_prepare(). */ +/* Accounting was done by __mmap_setup(). */ unacct_error:if (map.charged)vm_unacct_memory (map.charged);
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 3/5 mm: add remap_pfn_range_prepare(), remap_pfn_range_complete()
In reply to Sasha LevinFrom: Lorenzo Stoakes <[email protected]>
[ Upstream commit 51e38e7d40d617965504f4dcba569ecf9302f245 ]
We need the ability to split PFN remap between updating the VMA and performing the actual remap, in order to do away with the legacy f_op->mmap hook.
To do so, update the PFN remap code to provide shared logic, and also make remap_pfn_range_notrack() static, as its one user, io_mapping_map_user() was removed in commit 9a4f90e24661 ("mm: remove mm/io-mapping.c").
Then, introduce remap_pfn_range_prepare(), which accepts VMA descriptor and PFN parameters, and remap_pfn_range_complete() which accepts the same parameters as remap_pfn_rangte().
remap_pfn_range_prepare() will set the cow vma->vm_pgoff if necessary, so it must be supplied with a correct PFN to do so.
While we're here, also clean up the duplicated #ifdef __HAVE_PFNMAP_TRACKING check and put into a single #ifdef/#else block.
We keep these internal to mm as they should only be used by internal helpers.
Stable-dep-of: 976d5e0ddac8 ("mm/vma: predicate setting mmap_prepare VMA fields on new vma alloc")
--- include/linux/mm.h | 22 ++++++-- mm/internal.h | 4 ++ mm/memory.c | 132 ++++++++++++++++++++++++++++++--------------- 3 files changed, 110 insertions(+), 48 deletions(-)
include/linux/mm.h +18 -4
@@ -492,6 +492,21 @@ extern unsigned int kobjsize(const void *objp);*/ #define VM_SPECIAL (VM_IO | VM_DONTEXPAND | VM_PFNMAP | VM_MIXEDMAP) +/* +* Physically remapped pages are special. Tell the +* rest of the world about it: +* VM_IO tells people not to look at these pages +* (accesses can have side effects). +* VM_PFNMAP tells the core MM that the base pages are just +* raw PFN mappings, and do not have a "struct page" associated +* with them. +* VM_DONTEXPAND +* Disable vma merging and expanding with mremap(). +* VM_DONTDUMP +* Omit vma from core dump, even when VM_IO turned off. +*/ +#define VM_REMAP_FLAGS (VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP) +/* This mask prevents VMA from being scanned with khugepaged */ #define VM_NO_KHUGEPAGED (VM_SPECIAL | VM_HUGETLB)
@@ -3782,10 +3797,9 @@ unsigned long change_prot_numa(struct vm_area_struct *vma,struct vm_area_struct *find_extend_vma_locked (struct mm_struct *,unsigned long addr); -int remap_pfn_range (struct vm_area_struct *,unsigned long addr, -unsigned long pfn,unsigned long size,pgprot_t ); -int remap_pfn_range_notrack (struct vm_area_struct *vma,unsigned long addr, -unsigned long pfn,unsigned long size,pgprot_t prot); +int remap_pfn_range (struct vm_area_struct *vma,unsigned long addr, +unsigned long pfn,unsigned long size,pgprot_t pgprot); +int vm_insert_page (struct vm_area_struct *,unsigned long addr,struct page *);int vm_insert_pages (struct vm_area_struct *vma,unsigned long addr,struct page **pages,unsigned long *num);
mm/internal.h +4 -0
@@ -1666,4 +1666,8 @@ static inline bool reclaim_pt_is_enabled(unsigned long start, unsigned long end,void dup_mm_exe_file (struct mm_struct *mm,struct mm_struct *oldmm);int dup_mmap (struct mm_struct *mm,struct mm_struct *oldmm); +void remap_pfn_range_prepare (struct vm_area_desc *desc,unsigned long pfn); +int remap_pfn_range_complete (struct vm_area_struct *vma,unsigned long addr, +unsigned long pfn,unsigned long size,pgprot_t pgprot); +#endif /* __MM_INTERNAL_H */
mm/memory.c +88 -44
170 lines not on this page · raw message
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 4/5 mm: abstract io_remap_pfn_range() based on PFN
In reply to Sasha LevinFrom: Lorenzo Stoakes <[email protected]>
[ Upstream commit c707a68f9468e4ef4a3546b636a9dd088fe7b7f1 ]
The only instances in which we customise this function are ones in which we customise the PFN used.
Instances where architectures were not passing the pgprot value through pgprot_decrypted() are ones where pgprot_decrypted() was a no-op anyway, so we can simply always pass pgprot through this function.
Use this fact to simplify the use of io_remap_pfn_range(), by abstracting the PFN via io_remap_pfn_range_pfn() and using this instead of providing a general io_remap_pfn_range() function per-architecture.
Stable-dep-of: 976d5e0ddac8 ("mm/vma: predicate setting mmap_prepare VMA fields on new vma alloc")
--- arch/csky/include/asm/pgtable.h | 3 --- arch/mips/alchemy/common/setup.c | 9 +++++---- arch/mips/include/asm/pgtable.h | 5 ++--- arch/sparc/include/asm/pgtable_32.h | 12 ++++-------- arch/sparc/include/asm/pgtable_64.h | 12 ++++-------- include/linux/mm.h | 19 ++++++++++++++----- 6 files changed, 29 insertions(+), 31 deletions(-)
arch/csky/include/asm/pgtable.h +0 -3
@@ -263,7 +263,4 @@ void update_mmu_cache_range(struct vm_fault *vmf, struct vm_area_struct *vma,#define update_mmu_cache (vma, addr, ptep) \ update_mmu_cache_range(NULL, vma, addr, ptep, 1) -#define io_remap_pfn_range (vma, vaddr, pfn, size, prot) \ - remap_pfn_range(vma, vaddr, pfn, size, prot) -#endif /* __ASM_CSKY_PGTABLE_H */
arch/mips/alchemy/common/setup.c +5 -4
@@ -94,12 +94,13 @@ phys_addr_t fixup_bigphys_addr(phys_addr_t phys_addr, phys_addr_t size) return phys_addr; } -int io_remap_pfn_range (struct vm_area_struct *vma,unsigned long vaddr, -unsigned long pfn,unsigned long size,pgprot_t prot) +static inline unsigned long io_remap_pfn_range_pfn (unsigned long pfn, +unsigned long size) {phys_addr_t phys_addr =fixup_bigphys_addr (pfn <<PAGE_SHIFT , size); -return remap_pfn_range (vma, vaddr, phys_addr >>PAGE_SHIFT , size, prot); +return phys_addr >>PAGE_SHIFT ; } -EXPORT_SYMBOL (io_remap_pfn_range); +EXPORT_SYMBOL (io_remap_pfn_range_pfn); +#endif /* CONFIG_MIPS_FIXUP_BIGPHYS_ADDR */
arch/mips/include/asm/pgtable.h +2 -3
@@ -604,9 +604,8 @@ static inline void update_mmu_cache_pmd(struct vm_area_struct *vma,*/ #ifdef CONFIG_MIPS_FIXUP_BIGPHYS_ADDR phys_addr_t fixup_bigphys_addr (phys_addr_t addr,phys_addr_t size); -int io_remap_pfn_range (struct vm_area_struct *vma,unsigned long vaddr, -unsigned long pfn,unsigned long size,pgprot_t prot); -#define io_remap_pfn_range io_remap_pfn_range +unsigned long io_remap_pfn_range_pfn (unsigned long pfn,unsigned long size); +#define io_remap_pfn_range_pfn io_remap_pfn_range_pfn#else #define fixup_bigphys_addr (addr, size) (addr)#endif /* CONFIG_MIPS_FIXUP_BIGPHYS_ADDR */
arch/sparc/include/asm/pgtable_32.h +4 -8
@@ -395,12 +395,8 @@ __get_iospace (unsigned long addr)#define GET_IOSPACE (pfn) (pfn >> (BITS_PER_LONG - 4))#define GET_PFN (pfn) (pfn & 0x0fffffffUL) -int remap_pfn_range (struct vm_area_struct *,unsigned long ,unsigned long , -unsigned long ,pgprot_t ); - -static inline int io_remap_pfn_range (struct vm_area_struct *vma, -unsigned long from,unsigned long pfn, -unsigned long size,pgprot_t prot) +static inline unsigned long io_remap_pfn_range_pfn (unsigned long pfn, +unsigned long size) {unsigned long long offset, space, phys_base;
@@ -408,9 +404,9 @@ static inline int io_remap_pfn_range(struct vm_area_struct *vma, space =GET_IOSPACE (pfn); phys_base = offset | (space <<32ULL ); -return remap_pfn_range (vma, from, phys_base >>PAGE_SHIFT , size, prot); +return phys_base >>PAGE_SHIFT ; } -#define io_remap_pfn_range io_remap_pfn_range +#define io_remap_pfn_range_pfn io_remap_pfn_range_pfn#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS#define ptep_set_access_flags (__vma, __address, __ptep, __entry, __dirty) \
arch/sparc/include/asm/pgtable_64.h +4 -8
@@ -1048,9 +1048,6 @@ int page_in_phys_avail(unsigned long paddr);#define GET_IOSPACE (pfn) (pfn >> (BITS_PER_LONG - 4))#define GET_PFN (pfn) (pfn & 0x0fffffffffffffffUL) -int remap_pfn_range (struct vm_area_struct *,unsigned long ,unsigned long , -unsigned long ,pgprot_t ); -void adi_restore_tags (struct mm_struct *mm,struct vm_area_struct *vma,unsigned long addr,pte_t pte);
@@ -1084,9 +1081,8 @@ static inline int arch_unmap_one(struct mm_struct *mm,return 0 ; } -static inline int io_remap_pfn_range (struct vm_area_struct *vma, -unsigned long from,unsigned long pfn, -unsigned long size,pgprot_t prot) +static inline unsigned long io_remap_pfn_range_pfn (unsigned long pfn, +unsigned long size) {unsigned long offset =GET_PFN (pfn) <<PAGE_SHIFT ;int space =GET_IOSPACE (pfn);
@@ -1094,9 +1090,9 @@ static inline int io_remap_pfn_range(struct vm_area_struct *vma, phys_base = offset | (((unsigned long ) space) <<32UL ); -return remap_pfn_range (vma, from, phys_base >>PAGE_SHIFT , size, prot); +return phys_base >>PAGE_SHIFT ; } -#define io_remap_pfn_range io_remap_pfn_range +#define io_remap_pfn_range_pfn io_remap_pfn_range_pfnstatic inline unsigned long __untagged_addr (unsigned long start) {
include/linux/mm.h +14 -5
@@ -3832,15 +3832,24 @@ static inline vm_fault_t vmf_insert_page(struct vm_area_struct *vma,return VM_FAULT_NOPAGE ; } -#ifndef io_remap_pfn_range -static inline int io_remap_pfn_range (struct vm_area_struct *vma, -unsigned long addr,unsigned long pfn, -unsigned long size,pgprot_t prot) +#ifndef io_remap_pfn_range_pfn +static inline unsigned long io_remap_pfn_range_pfn (unsigned long pfn, +unsigned long size) { -return remap_pfn_range (vma, addr, pfn, size,pgprot_decrypted (prot)); +return pfn; }#endif +static inline int io_remap_pfn_range (struct vm_area_struct *vma, +unsigned long addr,unsigned long orig_pfn, +unsigned long size,pgprot_t orig_prot) +{ +const unsigned long pfn =io_remap_pfn_range_pfn (orig_pfn, size); +const pgprot_t prot =pgprot_decrypted (orig_prot); + +return remap_pfn_range (vma, addr, pfn, size, prot); +} +static inline vm_fault_t vmf_error (int err) {if (err == -ENOMEM )
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 5/5 mm/vma: predicate setting mmap_prepare VMA fields on new vma alloc
In reply to Sasha LevinFrom: "Lorenzo Stoakes (ARM)" <[email protected]>
[ Upstream commit 976d5e0ddac885b0219252f004f6c561c344df9d ]
It only makes sense to manipulate VMA fields if a new VMA was allocated, rather than merged.
VMA merging does not compare vm_ops or vm_private_data, so a merged VMA keeps its own, which is also what the legacy f_op->mmap path does since it never touches an existing VMA.
Currently, these fields will get overwritten by whatever state is established in the mmap_prepare hook, and if the VMA was merged, vm_ops->mapped will not have been called, so this could destructively clear existing state without replacing it with anything valid.
There is an implicit requirement that vm_private_data and vm_ops are fungible across VMAs which means that losing the 'new' state is fine.
However in this case the 'old' state is being overwritten by potentially invalid 'new' state, so this must be rectified.
Additionally constify have_mmap_prepare while here.
All existing in-tree users either derive state from the file or are unmergeable due to VMA flags, so this has no direct impact.
--- mm/vma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
mm/vma.c +2 -2
@@ -2676,7 +2676,7 @@ static unsigned long __mmap_region(struct file *file, unsigned long addr, {struct mm_struct *mm = current->mm;struct vm_area_struct *vma =NULL ; -bool have_mmap_prepare = file && file->f_op->mmap_prepare; +const bool have_mmap_prepare = file && file->f_op->mmap_prepare;VMA_ITERATOR (vmi, mm, addr);MMAP_STATE (map, mm, &vmi, addr, len, pgoff, vm_flags, file);bool allocated_new;
@@ -2710,7 +2710,7 @@ static unsigned long __mmap_region(struct file *file, unsigned long addr, goto unacct_error; } -if (have_mmap_prepare) +if (have_mmap_prepare && allocated_new)set_vma_user_defined_fields (vma, &map);__mmap_complete (&map, vma);
Signature · 1 line
2.53.0