Skip to contentSkip to conversation

FAILED: patch "[PATCH] mm/vma: predicate setting mmap_prepare VMA fields on new vma" failed to apply to 6.18-stable tree

PATCH New [email protected] 2 participants 6 messages Oct 3 – Oct 4

Subsystems (3)
lore
Share & tools
lore

[email protected]

author maintainer
#0 lore raw

The 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
index 9f0a0acf694a..6cde67883fb0 100644
@@ -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);
maintainer
#1 lore raw

PATCH 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.

Cc Alexander Gordeev <[email protected]>
Cc Al Viro <[email protected]>
Cc Andreas Larsson <[email protected]>
Cc Andrey Konovalov <[email protected]>
Cc Arnd Bergmann <[email protected]>
Cc Baolin Wang <[email protected]>
Cc Baoquan He <[email protected]>
Cc Chatre, Reinette <[email protected]>
Cc Christian Borntraeger <[email protected]>
Cc Christian Brauner <[email protected]>
Cc Dan Williams <[email protected]>
Cc Dave Jiang <[email protected]>
Cc Dave Martin <[email protected]>
Cc Dave Young <[email protected]>
Cc David Hildenbrand <[email protected]>
Cc David S. Miller <[email protected]>
Cc Dmitriy Vyukov <[email protected]>
Cc Greg Kroah-Hartman <[email protected]>
Cc Guo Ren <[email protected]>
Cc Heiko Carstens <[email protected]>
Cc Hugh Dickins <[email protected]>
Cc James Morse <[email protected]>
Cc Jan Kara <[email protected]>
Cc Jann Horn <[email protected]>
Cc Jonathan Corbet <[email protected]>
Cc Kevin Tian <[email protected]>
Cc Konstantin Komarov <[email protected]>
Cc Liam Howlett <[email protected]>
Cc "Luck, Tony" <[email protected]>
Cc Matthew Wilcox (Oracle) <[email protected]>
Cc Michal Hocko <[email protected]>
Cc Mike Rapoport <[email protected]>
Cc Muchun Song <[email protected]>
Cc Nicolas Pitre <[email protected]>
Cc Oscar Salvador <[email protected]>
Cc Pedro Falcato <[email protected]>
Cc Robin Murohy <[email protected]>
Cc Sumanth Korikkar <[email protected]>
Cc Suren Baghdasaryan <[email protected]>
Cc Sven Schnelle <[email protected]>
Cc Thomas Bogendoerfer <[email protected]>
Cc "Uladzislau Rezki (Sony)" <[email protected]>
Cc Vasily Gorbik <[email protected]>
Cc Vishal Verma <[email protected]>
Cc Vivek Goyal <[email protected]>
Cc Vlastimil Babka <[email protected]>
Cc Will Deacon <[email protected]>

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
index 5beb18b0610b0..74657c264c1ae 100644
@@ -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
index 4c7ea8b893ab7..9d5ee6ac913ad 100644
@@ -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
maintainer
#2 lore raw

PATCH 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().

Cc Alexander Gordeev <[email protected]>
Cc Al Viro <[email protected]>
Cc Andreas Larsson <[email protected]>
Cc Andrey Konovalov <[email protected]>
Cc Arnd Bergmann <[email protected]>
Cc Baolin Wang <[email protected]>
Cc Baoquan He <[email protected]>
Cc Chatre, Reinette <[email protected]>
Cc Christian Borntraeger <[email protected]>
Cc Christian Brauner <[email protected]>
Cc Dan Williams <[email protected]>
Cc Dave Jiang <[email protected]>
Cc Dave Martin <[email protected]>
Cc Dave Young <[email protected]>
Cc David S. Miller <[email protected]>
Cc Dmitriy Vyukov <[email protected]>
Cc Greg Kroah-Hartman <[email protected]>
Cc Guo Ren <[email protected]>
Cc Heiko Carstens <[email protected]>
Cc Hugh Dickins <[email protected]>
Cc James Morse <[email protected]>
Cc Jan Kara <[email protected]>
Cc Jann Horn <[email protected]>
Cc Jonathan Corbet <[email protected]>
Cc Kevin Tian <[email protected]>
Cc Konstantin Komarov <[email protected]>
Cc Liam Howlett <[email protected]>
Cc "Luck, Tony" <[email protected]>
Cc Matthew Wilcox (Oracle) <[email protected]>
Cc Michal Hocko <[email protected]>
Cc Mike Rapoport <[email protected]>
Cc Muchun Song <[email protected]>
Cc Nicolas Pitre <[email protected]>
Cc Oscar Salvador <[email protected]>
Cc Robin Murohy <[email protected]>
Cc Sumanth Korikkar <[email protected]>
Cc Suren Baghdasaryan <[email protected]>
Cc Sven Schnelle <[email protected]>
Cc Thomas Bogendoerfer <[email protected]>
Cc "Uladzislau Rezki (Sony)" <[email protected]>
Cc Vasily Gorbik <[email protected]>
Cc Vishal Verma <[email protected]>
Cc Vivek Goyal <[email protected]>
Cc Vlastimil Babka <[email protected]>
Cc Will Deacon <[email protected]>

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
index 74657c264c1ae..5d19adbb63a56 100644
@@ -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
maintainer
#3 lore raw

PATCH 3/5 mm: add remap_pfn_range_prepare(), remap_pfn_range_complete()

In reply to Sasha Levin

From: 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.

Cc Alexander Gordeev <[email protected]>
Cc Al Viro <[email protected]>
Cc Andreas Larsson <[email protected]>
Cc Andrey Konovalov <[email protected]>
Cc Arnd Bergmann <[email protected]>
Cc Baolin Wang <[email protected]>
Cc Baoquan He <[email protected]>
Cc Chatre, Reinette <[email protected]>
Cc Christian Borntraeger <[email protected]>
Cc Christian Brauner <[email protected]>
Cc Dan Williams <[email protected]>
Cc Dave Jiang <[email protected]>
Cc Dave Martin <[email protected]>
Cc Dave Young <[email protected]>
Cc David Hildenbrand <[email protected]>
Cc David S. Miller <[email protected]>
Cc Dmitriy Vyukov <[email protected]>
Cc Greg Kroah-Hartman <[email protected]>
Cc Guo Ren <[email protected]>
Cc Heiko Carstens <[email protected]>
Cc Hugh Dickins <[email protected]>
Cc James Morse <[email protected]>
Cc Jan Kara <[email protected]>
Cc Jann Horn <[email protected]>
Cc Jonathan Corbet <[email protected]>
Cc Kevin Tian <[email protected]>
Cc Konstantin Komarov <[email protected]>
Cc Liam Howlett <[email protected]>
Cc "Luck, Tony" <[email protected]>
Cc Matthew Wilcox (Oracle) <[email protected]>
Cc Michal Hocko <[email protected]>
Cc Mike Rapoport <[email protected]>
Cc Muchun Song <[email protected]>
Cc Nicolas Pitre <[email protected]>
Cc Oscar Salvador <[email protected]>
Cc Robin Murohy <[email protected]>
Cc Sumanth Korikkar <[email protected]>
Cc Suren Baghdasaryan <[email protected]>
Cc Sven Schnelle <[email protected]>
Cc Thomas Bogendoerfer <[email protected]>
Cc "Uladzislau Rezki (Sony)" <[email protected]>
Cc Vasily Gorbik <[email protected]>
Cc Vishal Verma <[email protected]>
Cc Vivek Goyal <[email protected]>
Cc Vlastimil Babka <[email protected]>
Cc Will Deacon <[email protected]>

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
index 2c0503bbcc190..4d0770d4ae0f8 100644
@@ -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
index ef42eee87c7be..2f2466390d1a9 100644
@@ -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
maintainer
#4 lore raw

PATCH 4/5 mm: abstract io_remap_pfn_range() based on PFN

In reply to Sasha Levin

From: 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.

Cc Alexander Gordeev <[email protected]>
Cc Al Viro <[email protected]>
Cc Andreas Larsson <[email protected]>
Cc Andrey Konovalov <[email protected]>
Cc Arnd Bergmann <[email protected]>
Cc Baolin Wang <[email protected]>
Cc Baoquan He <[email protected]>
Cc Chatre, Reinette <[email protected]>
Cc Christian Borntraeger <[email protected]>
Cc Christian Brauner <[email protected]>
Cc Dan Williams <[email protected]>
Cc Dave Jiang <[email protected]>
Cc Dave Martin <[email protected]>
Cc Dave Young <[email protected]>
Cc David Hildenbrand <[email protected]>
Cc David S. Miller <[email protected]>
Cc Dmitriy Vyukov <[email protected]>
Cc Greg Kroah-Hartman <[email protected]>
Cc Guo Ren <[email protected]>
Cc Heiko Carstens <[email protected]>
Cc Hugh Dickins <[email protected]>
Cc James Morse <[email protected]>
Cc Jan Kara <[email protected]>
Cc Jann Horn <[email protected]>
Cc Jonathan Corbet <[email protected]>
Cc Kevin Tian <[email protected]>
Cc Konstantin Komarov <[email protected]>
Cc Liam Howlett <[email protected]>
Cc "Luck, Tony" <[email protected]>
Cc Matthew Wilcox (Oracle) <[email protected]>
Cc Michal Hocko <[email protected]>
Cc Mike Rapoport <[email protected]>
Cc Muchun Song <[email protected]>
Cc Nicolas Pitre <[email protected]>
Cc Oscar Salvador <[email protected]>
Cc Pedro Falcato <[email protected]>
Cc Robin Murohy <[email protected]>
Cc Sumanth Korikkar <[email protected]>
Cc Suren Baghdasaryan <[email protected]>
Cc Sven Schnelle <[email protected]>
Cc Thomas Bogendoerfer <[email protected]>
Cc "Uladzislau Rezki (Sony)" <[email protected]>
Cc Vasily Gorbik <[email protected]>
Cc Vishal Verma <[email protected]>
Cc Vivek Goyal <[email protected]>
Cc Vlastimil Babka <[email protected]>
Cc Will Deacon <[email protected]>

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
index 5a394be09c35b..d606afbabce19 100644
@@ -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
index a7a6d31a7a414..c35b4f809d512 100644
@@ -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
index ae73ecf4c41aa..9c06a612d33a7 100644
@@ -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
index f1538a48484ac..a9f802d1dd64f 100644
@@ -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
index 64b85ff9c7662..615f460c50af4 100644
@@ -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_pfn
 
 static inline unsigned long __untagged_addr(unsigned long start)
 {
include/linux/mm.h +14 -5
index 4d0770d4ae0f8..26414ebbd9fb9 100644
@@ -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
maintainer
#5 lore raw

PATCH 5/5 mm/vma: predicate setting mmap_prepare VMA fields on new vma alloc

In reply to Sasha Levin

From: "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
index 5d19adbb63a56..d4e85c252563b 100644
@@ -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