mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 00/46] mm: various (urgent?) fixes
@ 2026-10-26 23:17 David Hildenbrand (Arm)
  2026-10-26 23:17 ` [PATCH 01/46] mm/mglru: don't use stack pointers when walking PUD and PMD tables David Hildenbrand (Arm)
                   ` (45 more replies)
  0 siblings, 46 replies; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:17 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, Josef Bacik, stable, David Hildenbrand (Arm),
	Chris Mason

Another set of fixes from the current batch that focuses on all core-mm
things that won't be sent out separately by others. I decided to bundle
these together as they are all over the place.

I have some hugetlb stuff in the works which is pretty horrible
(code wise ;) ), that I will send out once ready. Plus some
low-prio migrate_device oddities + two core-mm things that need more
thought.

This is the biggest set of patches coming from me, so don't be
scared ;)

Once more, some of the stuff is more urgent than others. No fixes are
crazy big and most are easy to review.

The majority are again fixes from Anthropic that I cleaned up or reworked.
While doing that, I found a bunch of other issues and tried to fix them
somewhat cleanly.

I gave it at least some basic testing on x86-64; more testing will be
highly appreciated.

This is based on akpm/mm-stable.

As with the shmem fixes, please prioritize review of these fixes, I want
to get fixes for the issues in a timely manner upstream.

Thanks to everyone helping out with moving the flood of fixes forward :)

---
Chris Mason (11):
      mm/huge_memory: fix truncate racing with PMD zapping
      mm/huge_memory: fix zapping migration entries for device-private THPs
      mm/khugepaged: preserve dirty bits when collapsing PTE-mapped THPs
      mm/gup: fix clearing folios in memfd_pin_folios()
      mm/gup: fix out-of-bounds write for nr_pages == 0 in GUP-fast
      mm/mmu_notifier: set ->mm only after mmgrab()
      mm/memory: reject remote COW faults on PFN mappings
      mm: fix unkillable fault loop on MAP_DROPPABLE memory
      mm: fix deadlock of mremap() against UFFDIO_MOVE
      mm/ksm: check large swap-cache folios before mapping them
      mm/vma: call ->may_split() before a partial merge

David Hildenbrand (Arm) (20):
      fork: take mmap_lock before copying mm_struct
      mm/memfd: check for real shmem inodes before accessing shmem state
      mm/truncate: look again if a folio left the mapping
      mm/filemap: finish fault cleanup before dropping the fault lock
      mm/rmap: handle device-exclusive entries in folio_referenced_one()
      mm/huge_memory: fix list corruption when deferred_split_scan() races with deferred_split_folio()
      mm/huge_memory: properly handle refcounted PUD mappings on fork
      mm/khugepaged: check if PTE table is empty in try_collapse_pte_mapped_thp()
      mm/gup: recheck the PUD under PTL in follow_pud_mask()
      mm/gup: check for overflow when converting nr_pages to bytes in GUP-fast
      mm/userfaultfd: write-lock the VMA before waking waiters when unregistering
      mm/userfaultfd: wake waiters when registration modes are removed
      mm/mremap: use pudp_huge_get_and_clear() when moving huge PUDs
      mm/mremap: recheck PUDs under the page table lock
      mm/madvise: fix data loss from MADV_FREE on a KSM page
      mm/ksm: reset the unstable trees of all nodes
      mm/ksm: fix use of a freed anon_vma at swap-in
      mm/huge_memory: split huge PUDs when adjusting VMA boundaries
      mm/vma: don't leak the charge for stack growth
      mm/memory-tiers: unregister empty tiers outside memory_tier_lock

Josef Bacik (14):
      mm/mglru: don't use stack pointers when walking PUD and PMD tables
      mm/memfd: make f_pos accesses atomic
      mm/filemap: read mapping->a_ops->free_folio under i_lock
      mm/filemap: don't lose a folio lock wakeup to a signal
      mm/huge_memory: fix livelock on device private folio
      mm/khugepaged: always recheck the pmd in try_collapse_pte_mapped_thp()
      mm/khugepaged: fix PMD table lock leak in try_collapse_pte_mapped_thp()
      mm/userfaultfd: wake all waiters on unregister
      mm/mmu_gather: fix flushing ranges with 4 GiB or larger
      mm/mmu_notifier: finish non-blocking interval invalidation on error
      mm/mremap: fix moving PUD leaves
      mm/memory_hotplug: avoid races in pfn_to_online_page() with dying pgmap
      mm: fix unmap_mapping_range() beyond 4 GiB on 32-bit
      fs/proc/task_mmu: refuse addresses beyond 32 bits on 32bit

Rik van Riel (1):
      mm/cma: don't release CMA pages still in use

 fs/proc/task_mmu.c            |   6 ++
 include/asm-generic/tlb.h     |   3 +-
 include/linux/huge_mm.h       |   5 +-
 include/linux/ksm.h           |   6 +-
 include/linux/memremap.h      |   6 ++
 include/linux/mmu_notifier.h  |   3 +-
 include/linux/shmem_fs.h      |   6 ++
 include/linux/userfaultfd_k.h |   2 -
 kernel/fork.c                 |  20 ++++--
 mm/cma.c                      |  10 ++-
 mm/filemap.c                  |  88 ++++++++++++-------------
 mm/gup.c                      |  53 ++++++++++-----
 mm/huge_memory.c              | 149 ++++++++++++++++++++++++++++++------------
 mm/hugetlb.c                  |  14 +---
 mm/internal.h                 |  28 ++++++++
 mm/khugepaged.c               |  77 +++++++++++-----------
 mm/ksm.c                      |  56 ++++++++++++----
 mm/madvise.c                  |   9 +++
 mm/memfd.c                    |  10 ++-
 mm/memfd_luo.c                |   2 +-
 mm/memory-tiers.c             |  29 ++++----
 mm/memory.c                   |  30 ++++++---
 mm/memory_hotplug.c           |  13 ++--
 mm/memremap.c                 |  13 ++++
 mm/mmap.c                     |   8 +--
 mm/mmu_notifier.c             |  24 +++++--
 mm/mremap.c                   | 103 +++++++++++++----------------
 mm/nommu.c                    |   2 +-
 mm/rmap.c                     |  23 +++++--
 mm/shmem.c                    |   5 ++
 mm/swapfile.c                 |   3 +-
 mm/truncate.c                 |  17 ++++-
 mm/userfaultfd.c              |  72 ++++++++++----------
 mm/util.c                     |  13 ++++
 mm/vma.c                      |  24 +++++--
 mm/vmscan.c                   |   4 +-
 36 files changed, 588 insertions(+), 348 deletions(-)

---

base-commit: 183895979c441e52dbd651b388553b09eaa35cfa

change-id: 20261021-fixes_core-bdf638faf023

--

Cheers,

David


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 01/46] mm/mglru: don't use stack pointers when walking PUD and PMD tables
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
@ 2026-10-26 23:17 ` David Hildenbrand (Arm)
  2026-10-27  1:32   ` Rik van Riel
                     ` (4 more replies)
  2026-10-26 23:17 ` [PATCH 02/46] fork: take mmap_lock before copying mm_struct David Hildenbrand (Arm)
                   ` (44 subsequent siblings)
  45 siblings, 5 replies; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:17 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, Josef Bacik, stable, David Hildenbrand (Arm)

From: Josef Bacik <josef@toxicpanda.com>

MGLRU passes stack copies of page-table entries in walk_pud_range() and
walk_pmd_range() when walking to the next level. These copies can become
stale when khugepaged or MADV_DONTNEED (CONFIG_PT_RECLAIM) removes a PTE
table concurrently.

This pattern dates back to commit bd74fdaea146 ("mm: multi-gen LRU:
support page table walks"). Likely, earlier locking masked the latent
bug. Later changes exposed it: commit 1d65b771bc08 ("mm/khugepaged:
retract_page_tables() without mmap or vma lock") allowed concurrent
retraction, and commit cf4a65539c13 ("memcg-v1: no need for memcg locking
for MGLRU") dropped the walker's outer RCU protection.

The fix is simple, so just fix the original commit so we don't have to
speculate. To fix it, pass the actual PMD/PUD pointers. This restores the
RCU-protected lookup and validation against the live PMD. Note that the PUD
handling is required as well to handle folded page tables correctly in all
cases.

Fix generated by an LLM and sent by Josef Bacik in private.

Fixes: bd74fdaea146 ("mm: multi-gen LRU: support page table walks")
Cc: stable@vger.kernel.org
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
[ david: handle walk_pud_range() as well, clarify+simplify description,
         adjust Fixes: ]
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 mm/vmscan.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/mm/vmscan.c b/mm/vmscan.c
index 9959ca158ce83..6a1af9b92349f 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -3911,7 +3911,7 @@ static void walk_pmd_range(pud_t *pud, unsigned long start, unsigned long end,
 
 		walk->mm_stats[MM_NONLEAF_FOUND]++;
 
-		if (!walk_pte_range(&val, addr, next, args))
+		if (!walk_pte_range(pmd + i, addr, next, args))
 			continue;
 
 		walk->mm_stats[MM_NONLEAF_ADDED]++;
@@ -3947,7 +3947,7 @@ static int walk_pud_range(p4d_t *p4d, unsigned long start, unsigned long end,
 		if (!pud_present(val) || WARN_ON_ONCE(pud_leaf(val)))
 			continue;
 
-		walk_pmd_range(&val, addr, next, args);
+		walk_pmd_range(pud + i, addr, next, args);
 
 		if (need_resched() || walk->batched >= MAX_LRU_BATCH) {
 			end = (addr | ~PUD_MASK) + 1;

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 02/46] fork: take mmap_lock before copying mm_struct
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
  2026-10-26 23:17 ` [PATCH 01/46] mm/mglru: don't use stack pointers when walking PUD and PMD tables David Hildenbrand (Arm)
@ 2026-10-26 23:17 ` David Hildenbrand (Arm)
  2026-10-27  1:38   ` Rik van Riel
                     ` (3 more replies)
  2026-10-26 23:17 ` [PATCH 03/46] mm/memfd: check for real shmem inodes before accessing shmem state David Hildenbrand (Arm)
                   ` (43 subsequent siblings)
  45 siblings, 4 replies; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:17 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, stable, Josef Bacik, David Hildenbrand (Arm)

dup_mm() copies the parent's mm_struct before dup_mmap() takes the
mmap_lock. A concurrent brk() can leave the child with a stale mm->brk
and newer heap mappings, causing later brk() requests to fail.

Other operations (e.g., PR_SET_MM) on the parent's mm_struct can similarly
cause inconsistencies.

As a simple and robust fix, grab the parent's mmap_lock earlier. This
way we don't need to update individual mm fields in dup_mmap() and
keep missing ones. Stop updating the 4 existing members (total_vm, data_vm,
exec_vm, stack_vm), as that is now no longer required.

Keep releasing the parent's mmap_lock in dup_mmap(), before
userfaultfd completion, to avoid moving the userfaultfd handling into the
caller. This should get cleaned up later.

Move uprobe_start_dup_mmap() to preserve the lock ordering.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Reported-by: Josef Bacik <josef@toxicpanda.com>
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 kernel/fork.c | 20 ++++++++++++++------
 mm/mmap.c     |  8 +-------
 mm/nommu.c    |  2 +-
 3 files changed, 16 insertions(+), 14 deletions(-)

diff --git a/kernel/fork.c b/kernel/fork.c
index 22eaf5fb844d0..c8948cadccf71 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1532,12 +1532,19 @@ static struct mm_struct *dup_mm(struct task_struct *tsk,
 	if (!mm)
 		goto fail_nomem;
 
+	uprobe_start_dup_mmap();
+	if (mmap_write_lock_killable(oldmm)) {
+		free_mm(mm);
+		goto fail_uprobe;
+	}
+
 	memcpy(mm, oldmm, sizeof(*mm));
 
-	if (!mm_init(mm, tsk))
-		goto fail_nomem;
+	if (!mm_init(mm, tsk)) {
+		mmap_write_unlock(oldmm);
+		goto fail_uprobe;
+	}
 
-	uprobe_start_dup_mmap();
 	err = dup_mmap(mm, oldmm);
 	if (err)
 		goto free_pt;
@@ -1556,9 +1563,10 @@ static struct mm_struct *dup_mm(struct task_struct *tsk,
 	mm->binfmt = NULL;
 	mm_init_owner(mm, NULL);
 	mmput(mm);
-	if (err)
-		uprobe_end_dup_mmap();
-
+	if (!err)
+		return NULL;
+fail_uprobe:
+	uprobe_end_dup_mmap();
 fail_nomem:
 	return NULL;
 }
diff --git a/mm/mmap.c b/mm/mmap.c
index 148ba01c03739..7618e72766a52 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1713,8 +1713,7 @@ __latent_entropy int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
 	LIST_HEAD(uf);
 	VMA_ITERATOR(vmi, mm, 0);
 
-	if (mmap_write_lock_killable(oldmm))
-		return -EINTR;
+	mmap_assert_write_locked(oldmm);
 	flush_cache_dup_mm(oldmm);
 	uprobe_dup_mmap(oldmm, mm);
 	/*
@@ -1725,11 +1724,6 @@ __latent_entropy int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
 	/* No ordering required: file already has been exposed. */
 	dup_mm_exe_file(mm, oldmm);
 
-	mm->total_vm = oldmm->total_vm;
-	mm->data_vm = oldmm->data_vm;
-	mm->exec_vm = oldmm->exec_vm;
-	mm->stack_vm = oldmm->stack_vm;
-
 	/* Use __mt_dup() to efficiently build an identical maple tree. */
 	retval = __mt_dup(&oldmm->mm_mt, &mm->mm_mt, GFP_KERNEL);
 	if (unlikely(retval))
diff --git a/mm/nommu.c b/mm/nommu.c
index ed44510e37707..6e0f9c7da2364 100644
--- a/mm/nommu.c
+++ b/mm/nommu.c
@@ -1926,7 +1926,7 @@ subsys_initcall(init_admin_reserve);
 
 int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
 {
-	mmap_write_lock(oldmm);
+	mmap_assert_write_locked(oldmm);
 	dup_mm_exe_file(mm, oldmm);
 	mmap_write_unlock(oldmm);
 	return 0;

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 03/46] mm/memfd: check for real shmem inodes before accessing shmem state
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
  2026-10-26 23:17 ` [PATCH 01/46] mm/mglru: don't use stack pointers when walking PUD and PMD tables David Hildenbrand (Arm)
  2026-10-26 23:17 ` [PATCH 02/46] fork: take mmap_lock before copying mm_struct David Hildenbrand (Arm)
@ 2026-10-26 23:17 ` David Hildenbrand (Arm)
  2026-10-27  2:04   ` Rik van Riel
  2026-10-27  8:13   ` Mike Rapoport
  2026-10-26 23:17 ` [PATCH 04/46] mm/memfd: make f_pos accesses atomic David Hildenbrand (Arm)
                   ` (42 subsequent siblings)
  45 siblings, 2 replies; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:17 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, stable, Chris Mason, David Hildenbrand (Arm)

shmem_file() only checks a file's backing mapping. That mapping can belong
to another file, as with a Coda file backed by a tmpfs container after
mmap(). It does not establish that file_inode(file) is a shmem inode.

Seal handling and memfd preservation use this check before accessing
shmem inode state, so they can access an inode of the wrong type.

Add file_inode_is_shmem() to check the inode's file operations in both
paths. This identifies regular shmem inodes, including those used by
memfds and ordinary tmpfs files, independently of wrapper file operations.

Fixes: c49fcfcda8b5 ("mm/shmem: update file sealing comments and file checking")
Fixes: b3749f174d68 ("mm: memfd_luo: allow preserving memfd")
Cc: stable@vger.kernel.org
Reported-by: Chris Mason <mason@kernel.org>
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 include/linux/shmem_fs.h | 6 ++++++
 mm/memfd.c               | 8 +++++---
 mm/memfd_luo.c           | 2 +-
 mm/shmem.c               | 5 +++++
 4 files changed, 17 insertions(+), 4 deletions(-)

diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h
index a7c7a96a7cbf9..2ceca7993e4f5 100644
--- a/include/linux/shmem_fs.h
+++ b/include/linux/shmem_fs.h
@@ -117,8 +117,14 @@ extern unsigned long shmem_get_unmapped_area(struct file *, unsigned long addr,
 		unsigned long len, unsigned long pgoff, unsigned long flags);
 extern int shmem_lock(struct file *file, int lock, struct ucounts *ucounts);
 #ifdef CONFIG_SHMEM
+bool file_inode_is_shmem(const struct inode *inode);
 bool shmem_mapping(const struct address_space *mapping);
 #else
+static inline bool file_inode_is_shmem(const struct inode *inode)
+{
+	return false;
+}
+
 static inline bool shmem_mapping(const struct address_space *mapping)
 {
 	return false;
diff --git a/mm/memfd.c b/mm/memfd.c
index 0f6fff004f5e4..7d2da23157003 100644
--- a/mm/memfd.c
+++ b/mm/memfd.c
@@ -211,12 +211,14 @@ static int memfd_wait_for_pins(struct address_space *mapping)
 
 static unsigned int *memfd_file_seals_ptr(struct file *file)
 {
-	if (shmem_file(file))
-		return &SHMEM_I(file_inode(file))->seals;
+	struct inode *inode = file_inode(file);
+
+	if (file_inode_is_shmem(inode))
+		return &SHMEM_I(inode)->seals;
 
 #ifdef CONFIG_HUGETLBFS
 	if (is_file_hugepages(file))
-		return &HUGETLBFS_I(file_inode(file))->seals;
+		return &HUGETLBFS_I(inode)->seals;
 #endif
 
 	return NULL;
diff --git a/mm/memfd_luo.c b/mm/memfd_luo.c
index 59de210bee5f9..c0811407ce397 100644
--- a/mm/memfd_luo.c
+++ b/mm/memfd_luo.c
@@ -582,7 +582,7 @@ static bool memfd_luo_can_preserve(struct liveupdate_file_handler *handler,
 {
 	struct inode *inode = file_inode(file);
 
-	return shmem_file(file) && !inode->i_nlink;
+	return file_inode_is_shmem(inode) && !inode->i_nlink;
 }
 
 static unsigned long memfd_luo_get_id(struct file *file)
diff --git a/mm/shmem.c b/mm/shmem.c
index fadf23f9e21ed..0d41aac125df9 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -275,6 +275,11 @@ static const struct vm_operations_struct shmem_vm_ops;
 static const struct vm_operations_struct shmem_anon_vm_ops;
 static struct file_system_type shmem_fs_type;
 
+bool file_inode_is_shmem(const struct inode *inode)
+{
+	return inode->i_fop == &shmem_file_operations;
+}
+
 bool shmem_mapping(const struct address_space *mapping)
 {
 	return mapping->a_ops == &shmem_aops;

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 04/46] mm/memfd: make f_pos accesses atomic
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (2 preceding siblings ...)
  2026-10-26 23:17 ` [PATCH 03/46] mm/memfd: check for real shmem inodes before accessing shmem state David Hildenbrand (Arm)
@ 2026-10-26 23:17 ` David Hildenbrand (Arm)
  2026-10-27  2:06   ` Rik van Riel
                     ` (4 more replies)
  2026-10-26 23:17 ` [PATCH 05/46] mm/truncate: look again if a folio left the mapping David Hildenbrand (Arm)
                   ` (41 subsequent siblings)
  45 siblings, 5 replies; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:17 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, Josef Bacik, stable, David Hildenbrand (Arm)

From: Josef Bacik <josef@toxicpanda.com>

Commit 9c225f2655e3 ("vfs: atomic f_pos accesses as per POSIX") made
read(), write() and lseek() on a shared open file description of a regular
file serialize on ->f_pos_lock.  The flag that asks for it,
FMODE_ATOMIC_POS, is set in do_dentry_open().  A memfd is a regular file
too, but its struct file comes from alloc_file_pseudo() and never passes
through do_dentry_open(), so it does not get the flag:

  CPU0                                CPU1
  write(memfd, "a", 1)                write(memfd, "b", 1)
    pos = file->f_pos  (= 0)
                                        pos = file->f_pos  (= 0)
    vfs_write(..., &pos)
                                        vfs_write(..., &pos)
    file->f_pos = pos  (= 1)
                                        file->f_pos = pos  (= 1)

One of the two bytes is overwritten.  Two threads writing 100000 bytes
each, one at a time, to a memfd end up with a file that is far shorter than
200000 bytes, while the same program on a tmpfs file never loses a byte.

Set the flag when the memfd is created.  As for any other regular file the
lock is only taken if the file is reachable in more than one way, and
nothing a memfd does in read or write waits for another operation on the
same file.  This cannot be done for all alloc_file_pseudo() files: anon
inode files such as eventfd are S_IFREG as well, and a blocked read holding
->f_pos_lock would lock out the write that is supposed to wake it.

Fix generated by an LLM and sent by Josef Bacik in private.

Fixes: 9183df25fe7b ("shm: add memfd_create() syscall")
Cc: stable@vger.kernel.org
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
[ david: minor description tweaks ]
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 mm/memfd.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/mm/memfd.c b/mm/memfd.c
index 7d2da23157003..6f5fbce74f21e 100644
--- a/mm/memfd.c
+++ b/mm/memfd.c
@@ -484,6 +484,8 @@ struct file *memfd_alloc_file(const char *name, unsigned int flags)
 	}
 
 	file->f_mode |= FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE;
+	/* a regular file like any other: POSIX.1-2008/SUSv4 Section XSI 2.9.7 */
+	file->f_mode |= FMODE_ATOMIC_POS;
 	file->f_flags |= O_LARGEFILE;
 
 	if (flags & MFD_NOEXEC_SEAL) {

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 05/46] mm/truncate: look again if a folio left the mapping
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (3 preceding siblings ...)
  2026-10-26 23:17 ` [PATCH 04/46] mm/memfd: make f_pos accesses atomic David Hildenbrand (Arm)
@ 2026-10-26 23:17 ` David Hildenbrand (Arm)
  2026-10-27  2:17   ` Rik van Riel
  2026-10-26 23:17 ` [PATCH 06/46] mm/filemap: read mapping->a_ops->free_folio under i_lock David Hildenbrand (Arm)
                   ` (40 subsequent siblings)
  45 siblings, 1 reply; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:17 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, stable, Josef Bacik, David Hildenbrand (Arm)

invalidate_inode_pages2_range() skips a folio which no longer belongs to
the mapping by the time it has got the folio lock, on the assumption
that somebody else has removed it from the page cache. But the folio may
have been replaced, and then there is a new folio with the same data at
that index.

For most cases, like folio migration, that is impossible. However,
collapse_file() only checks the refcount of the old folios, under the
i_pages lock, and relies on their folio locks from there on. That works for
users which repeat the lookup when they find folio->mapping changed.
The following scenario is, however, possible:

  CPU0 pwrite(O_DIRECT)               CPU1 collapse_file()
  kiocb_invalidate_pages()
                                      read the folio (old data), lock it
                                      refcount check
  the write completes                 copy to new_folio
  kiocb_invalidate_post_direct_write()
    find_get_entries() -> old folio
    folio_lock() ...                  xas_store(new_folio)
                                      folio->mapping = NULL
                                      folio_unlock(folio)
    folio->mapping != mapping
      -> continue

In that scenario, the collapsed folio with the data from before the write
stays in the page cache after the write has returned.

This used to be impossible, as khugepaged only collapsed files that nobody
had open for writing.

Restart the lookup at that index, like shmem_undo_range() does. The same
problem seems to exist in truncate_inode_pages_range() as well when
truncate_inode_folio() fails, so handle it there as well.

Fixes: 1b6444331beb ("mm/khugepaged: enable clean pagecache folio collapse for writable files")
Cc: stable@vger.kernel.org
Reported-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 mm/truncate.c | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/mm/truncate.c b/mm/truncate.c
index 733d2713a875a..6d8c0ec4623fe 100644
--- a/mm/truncate.c
+++ b/mm/truncate.c
@@ -499,7 +499,15 @@ void truncate_inode_pages_range(struct address_space *mapping,
 			folio_lock(folio);
 			VM_BUG_ON_FOLIO(!folio_contains(folio, indices[i]), folio);
 			folio_wait_writeback(folio);
-			truncate_inode_folio(mapping, folio);
+			if (truncate_inode_folio(mapping, folio)) {
+				folio_unlock(folio);
+				/*
+				 * Folio might have been replaced: look it up
+				 * again.
+				 */
+				index = indices[i];
+				break;
+			}
 			folio_unlock(folio);
 		}
 		truncate_folio_batch_exceptionals(mapping, &fbatch, indices);
@@ -760,7 +768,12 @@ int invalidate_inode_pages2_range(struct address_space *mapping,
 			folio_lock(folio);
 			if (unlikely(folio->mapping != mapping)) {
 				folio_unlock(folio);
-				continue;
+				/*
+				 * Folio might have been replaced: look up
+				 * again.
+				 */
+				index = indices[i];
+				break;
 			}
 			VM_BUG_ON_FOLIO(!folio_contains(folio, indices[i]), folio);
 			folio_wait_writeback(folio);

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 06/46] mm/filemap: read mapping->a_ops->free_folio under i_lock
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (4 preceding siblings ...)
  2026-10-26 23:17 ` [PATCH 05/46] mm/truncate: look again if a folio left the mapping David Hildenbrand (Arm)
@ 2026-10-26 23:17 ` David Hildenbrand (Arm)
  2026-10-27  2:43   ` Rik van Riel
  2026-10-26 23:17 ` [PATCH 07/46] mm/filemap: don't lose a folio lock wakeup to a signal David Hildenbrand (Arm)
                   ` (39 subsequent siblings)
  45 siblings, 1 reply; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:17 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, Josef Bacik, stable, David Hildenbrand (Arm)

From: Josef Bacik <josef@toxicpanda.com>

memory_failure() -> ... -> filemap_remove_folio() can read mapping->a_ops
after the inode has been freed. Once the folio is deleted from the
pagecache it no longer pins the mapping, so after i_lock is dropped
e.g., a concurrent final iput() can evict and free the inode before
filemap_free_folio() looks up mapping->a_ops->free_folio.

Most callers hold a reference on the inode, but not all.

Documentation/filesystems/vfs.rst explicitly states that ->free_folio()
must not assume the original address_space mapping still exists.

Fix it by loading ->free_folio while i_lock is still held, similar to
what folio_unmap_invalidate() does.

Inline filemap_free_folio() into its remaining caller such that
delete_from_page_cache_batch() also just loads the callback before
dropping the i_lock.

The bug was found by code inspection and has not been reproduced.

Fix generated by an LLM and sent by Josef Bacik in private.

Fixes: 59c66c5f8c4f ("mm: factor out page cache page freeing into a separate function")
Cc: stable@vger.kernel.org
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
[ david: get rid of filemap_free_folio() entirely; improve patch description ]
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 mm/filemap.c | 29 ++++++++++++++---------------
 1 file changed, 14 insertions(+), 15 deletions(-)

diff --git a/mm/filemap.c b/mm/filemap.c
index b74bc1e5015c6..906b013c11eb3 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -227,18 +227,6 @@ void __filemap_remove_folio(struct folio *folio, void *shadow)
 	page_cache_delete(mapping, folio, shadow);
 }
 
-static void filemap_free_folio(const struct address_space *mapping,
-		struct folio *folio)
-{
-	void (*free_folio)(struct folio *);
-
-	free_folio = mapping->a_ops->free_folio;
-	if (free_folio)
-		free_folio(folio);
-
-	folio_put_refs(folio, folio_nr_pages(folio));
-}
-
 /**
  * filemap_remove_folio - Remove folio from page cache.
  * @folio: The folio.
@@ -250,6 +238,7 @@ static void filemap_free_folio(const struct address_space *mapping,
 void filemap_remove_folio(struct folio *folio)
 {
 	struct address_space *mapping = folio->mapping;
+	void (*free_folio)(struct folio *folio);
 
 	BUG_ON(!folio_test_locked(folio));
 	spin_lock(&mapping->host->i_lock);
@@ -258,9 +247,12 @@ void filemap_remove_folio(struct folio *folio)
 	xa_unlock_irq(&mapping->i_pages);
 	if (mapping_shrinkable(mapping))
 		inode_lru_list_add(mapping->host);
+	free_folio = mapping->a_ops->free_folio;
 	spin_unlock(&mapping->host->i_lock);
 
-	filemap_free_folio(mapping, folio);
+	if (free_folio)
+		free_folio(folio);
+	folio_put_refs(folio, folio_nr_pages(folio));
 }
 
 /*
@@ -320,6 +312,7 @@ static void page_cache_delete_batch(struct address_space *mapping,
 void delete_from_page_cache_batch(struct address_space *mapping,
 				  struct folio_batch *fbatch)
 {
+	void (*free_folio)(struct folio *folio);
 	int i;
 
 	if (!folio_batch_count(fbatch))
@@ -337,10 +330,16 @@ void delete_from_page_cache_batch(struct address_space *mapping,
 	xa_unlock_irq(&mapping->i_pages);
 	if (mapping_shrinkable(mapping))
 		inode_lru_list_add(mapping->host);
+	free_folio = mapping->a_ops->free_folio;
 	spin_unlock(&mapping->host->i_lock);
 
-	for (i = 0; i < folio_batch_count(fbatch); i++)
-		filemap_free_folio(mapping, fbatch->folios[i]);
+	for (i = 0; i < folio_batch_count(fbatch); i++) {
+		struct folio *folio = fbatch->folios[i];
+
+		if (free_folio)
+			free_folio(folio);
+		folio_put_refs(folio, folio_nr_pages(folio));
+	}
 }
 
 int filemap_check_errors(struct address_space *mapping)

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 07/46] mm/filemap: don't lose a folio lock wakeup to a signal
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (5 preceding siblings ...)
  2026-10-26 23:17 ` [PATCH 06/46] mm/filemap: read mapping->a_ops->free_folio under i_lock David Hildenbrand (Arm)
@ 2026-10-26 23:17 ` David Hildenbrand (Arm)
  2026-10-27  3:03   ` Rik van Riel
  2026-10-26 23:17 ` [PATCH 08/46] mm/filemap: finish fault cleanup before dropping the fault lock David Hildenbrand (Arm)
                   ` (38 subsequent siblings)
  45 siblings, 1 reply; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:17 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, Josef Bacik, stable, David Hildenbrand (Arm)

From: Josef Bacik <josef@toxicpanda.com>

An exclusive waiter in folio_wait_bit_common() can leave the wait loop
because of a fatal signal, then be woken by folio_unlock() before
finish_wait(). If the waker did not hand over the lock, the waiter returns
-EINTR without trying to acquire it.

folio_wake_bit() stops after waking the first exclusive waiter, so this
loses the wakeup and can leave other waiters asleep indefinitely on an
unlocked folio.

After finish_wait(), let a waiter woken without a lock handoff try once
more to acquire the lock. If successful, return success so the caller's
eventual unlock wakes the next waiter. Otherwise, the current lock owner
will do so.

Fix generated by an LLM and sent by Josef Bacik in private.

Fixes: 5ef64cc8987a ("mm: allow a controlled amount of unfairness in the page lock")
Cc: stable@vger.kernel.org
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
[ david: clarify and simplify comment + description ]
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 mm/filemap.c | 18 +++++++++++++++---
 1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/mm/filemap.c b/mm/filemap.c
index 906b013c11eb3..6b5e1d866a9e0 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -1373,10 +1373,22 @@ static inline int folio_wait_bit_common(struct folio *folio, int bit_nr,
 	 * return value based on that state without races.
 	 *
 	 * Also note that WQ_FLAG_WOKEN is sufficient for a non-exclusive
-	 * waiter, but an exclusive one requires WQ_FLAG_DONE.
+	 * waiter, but an exclusive one must also acquire the bit.
 	 */
-	if (behavior == EXCLUSIVE)
-		return wait->flags & WQ_FLAG_DONE ? 0 : -EINTR;
+	if (behavior == EXCLUSIVE) {
+		if (wait->flags & WQ_FLAG_DONE)
+			return 0;
+		/*
+		 * We might have just been woken up and the waker will not
+		 * wake up anybody else. If we ignore that now, the remaining
+		 * waiters may not get woken up: take the bit now if it is
+		 * still free.
+		 */
+		if ((wait->flags & WQ_FLAG_WOKEN) &&
+		    !test_and_set_bit(bit_nr, folio_flags(folio, 0)))
+			return 0;
+		return -EINTR;
+	}
 
 	return wait->flags & WQ_FLAG_WOKEN ? 0 : -EINTR;
 }

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 08/46] mm/filemap: finish fault cleanup before dropping the fault lock
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (6 preceding siblings ...)
  2026-10-26 23:17 ` [PATCH 07/46] mm/filemap: don't lose a folio lock wakeup to a signal David Hildenbrand (Arm)
@ 2026-10-26 23:17 ` David Hildenbrand (Arm)
  2026-10-26 23:17 ` [PATCH 09/46] mm/rmap: handle device-exclusive entries in folio_referenced_one() David Hildenbrand (Arm)
                   ` (37 subsequent siblings)
  45 siblings, 0 replies; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:17 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, stable, Chris Mason, David Hildenbrand (Arm)

On a retried fault, a fatal signal interrupting the folio lock wait
makes lock_folio_maybe_drop_mmap() drop the fault lock without pinning
the file. However, filemap_fault() may still need to release
mapping->invalidate_lock. A concurrent munmap() can release the last
file reference and free the mapping before that unlock.

Defer dropping the fault lock to filemap_fault()'s retry cleanup, after
releasing invalidate_lock. If the fault lock was already dropped for
I/O, release the existing file reference instead. Keep the fault lock
held for FAULT_FLAG_RETRY_NOWAIT as before.

Fixes: 730633f0b7f9 ("mm: Protect operations adding pages to page cache with invalidate_lock")
Cc: stable@vger.kernel.org
Reported-by: Chris Mason <mason@kernel.org>
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 mm/filemap.c | 37 +++++++++++++------------------------
 1 file changed, 13 insertions(+), 24 deletions(-)

diff --git a/mm/filemap.c b/mm/filemap.c
index 6b5e1d866a9e0..b04be64a5069f 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -3308,11 +3308,11 @@ loff_t mapping_seek_hole_data(struct address_space *mapping, loff_t start,
  * @folio - the folio to lock.
  * @fpin - the pointer to the file we may pin (or is already pinned).
  *
- * This works similar to lock_folio_or_retry in that it can drop the
- * mmap_lock.  It differs in that it actually returns the folio locked
- * if it returns 1 and 0 if it couldn't lock the folio.  If we did have
- * to drop the mmap_lock then fpin will point to the pinned file and
- * needs to be fput()'ed at a later point.
+ * Returns 1 with the folio locked, or 0 if locking failed.
+ *
+ * On both entry and return, a non-NULL *fpin means the fault lock has
+ * already been dropped and the caller must eventually fput() the file.
+ * Otherwise the fault lock is still held, including on failure.
  */
 static int lock_folio_maybe_drop_mmap(struct vm_fault *vmf, struct folio *folio,
 				     struct file **fpin)
@@ -3329,21 +3329,9 @@ static int lock_folio_maybe_drop_mmap(struct vm_fault *vmf, struct folio *folio,
 		return 0;
 
 	*fpin = maybe_unlock_mmap_for_io(vmf, *fpin);
-	if (vmf->flags & FAULT_FLAG_KILLABLE) {
-		if (__folio_lock_killable(folio)) {
-			/*
-			 * We didn't have the right flags to drop the
-			 * fault lock, but all fault_handlers only check
-			 * for fatal signals if we return VM_FAULT_RETRY,
-			 * so we need to drop the fault lock here and
-			 * return 0 if we don't have a fpin.
-			 */
-			if (*fpin == NULL)
-				release_fault_lock(vmf);
-			return 0;
-		}
-	} else
-		__folio_lock(folio);
+	if (vmf->flags & FAULT_FLAG_KILLABLE)
+		return !__folio_lock_killable(folio);
+	__folio_lock(folio);
 
 	return 1;
 }
@@ -3572,7 +3560,7 @@ static vm_fault_t filemap_fault_recheck_pte_none(struct vm_fault *vmf)
  * vma->vm_mm->mmap_lock must be held on entry.
  *
  * If our return value has VM_FAULT_RETRY set, it's because the mmap_lock
- * may be dropped before doing I/O or by lock_folio_maybe_drop_mmap().
+ * may be dropped before doing I/O or when aborting an interrupted wait.
  *
  * If our return value does not have VM_FAULT_RETRY set, the mmap_lock
  * has not been released.
@@ -3728,9 +3716,8 @@ vm_fault_t filemap_fault(struct vm_fault *vmf)
 
 out_retry:
 	/*
-	 * We dropped the mmap_lock, we need to return to the fault handler to
-	 * re-find the vma and come back and find our hopefully still populated
-	 * page.
+	 * With fpin set, the fault lock was already dropped. Otherwise it is
+	 * still held. Release invalidate_lock before dropping either protection.
 	 */
 	if (!IS_ERR(folio))
 		folio_put(folio);
@@ -3738,6 +3725,8 @@ vm_fault_t filemap_fault(struct vm_fault *vmf)
 		filemap_invalidate_unlock_shared(mapping);
 	if (fpin)
 		fput(fpin);
+	else if (!(vmf->flags & FAULT_FLAG_RETRY_NOWAIT))
+		release_fault_lock(vmf);
 	return ret | VM_FAULT_RETRY;
 }
 EXPORT_SYMBOL(filemap_fault);

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 09/46] mm/rmap: handle device-exclusive entries in folio_referenced_one()
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (7 preceding siblings ...)
  2026-10-26 23:17 ` [PATCH 08/46] mm/filemap: finish fault cleanup before dropping the fault lock David Hildenbrand (Arm)
@ 2026-10-26 23:17 ` David Hildenbrand (Arm)
  2026-10-26 23:17 ` [PATCH 10/46] mm/huge_memory: fix list corruption when deferred_split_scan() races with deferred_split_folio() David Hildenbrand (Arm)
                   ` (36 subsequent siblings)
  45 siblings, 0 replies; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:17 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, stable, Josef Bacik, David Hildenbrand (Arm)

page_vma_mapped_walk() can return non-present device-exclusive entries,
but folio_referenced_one() passes them to PTE young-bit accessors that
require present PTEs.

We must neither call clear_flush_young_ptes_notify() nor
folio_pte_batch() with non-present entries. For example, clearing the
young bit on non-present PTEs can corrupt the entry: on arm64
PTE_AF overlaps the swap type, so clearing it turns a device-exclusive
entry into an ordinary swap entry.

folio_pte_batch() will VM_WARN_ON_FOLIO.

Apply the same approach as the previous fixes to e.g., damon_ptep_mkold():
treat these entries as old from the CPU's perspective and obtain their
young state through the MMU notifier.

Skip PTE batching and MGLRU look-around for non-present entries, and
don't modify non-present PTEs.

Fixes: b756a3b5e7ea ("mm: device exclusive memory access")
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Cc: stable@vger.kernel.org
Reported-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 mm/rmap.c | 23 +++++++++++++++++++----
 1 file changed, 19 insertions(+), 4 deletions(-)

diff --git a/mm/rmap.c b/mm/rmap.c
index 1131b76bbbc28..0faef46806e5c 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -924,6 +924,7 @@ static bool folio_referenced_one(struct folio *folio,
 	DEFINE_FOLIO_VMA_WALK(pvmw, folio, vma, address, 0);
 	int ptes = 0, referenced = 0;
 	unsigned int nr;
+	pte_t pteval;
 
 	while (page_vma_mapped_walk(&pvmw)) {
 		address = pvmw.address;
@@ -968,10 +969,12 @@ static bool folio_referenced_one(struct folio *folio,
 			return false;
 		}
 
-		if (pvmw.pte && folio_test_large(folio)) {
+		if (pvmw.pte)
+			pteval = ptep_get(pvmw.pte);
+
+		if (pvmw.pte && pte_present(pteval) && folio_test_large(folio)) {
 			const unsigned long end_addr = pmd_addr_end(address, vma->vm_end);
 			const unsigned int max_nr = (end_addr - address) >> PAGE_SHIFT;
-			pte_t pteval = ptep_get(pvmw.pte);
 
 			nr = folio_pte_batch(folio, pvmw.pte, pteval, max_nr);
 		}
@@ -981,11 +984,23 @@ static bool folio_referenced_one(struct folio *folio,
 		 * are. —they could be on active/inactive lists or on MGLRU. So the
 		 * simplest approach is to disable this look-around optimization.
 		 */
-		if (lru_gen_enabled() && !lru_gen_switching() && pvmw.pte) {
+		if (lru_gen_enabled() && !lru_gen_switching() && pvmw.pte &&
+		    pte_present(pteval)) {
 			if (lru_gen_look_around(&pvmw, nr))
 				referenced++;
 		} else if (pvmw.pte) {
-			if (clear_flush_young_ptes_notify(vma, address, pvmw.pte, nr))
+			bool young = false;
+
+			/*
+			 * PFN swap PTEs, such as device-exclusive ones, that
+			 * actually map pages are "old" from a CPU perspective.
+			 * The MMU notifier takes care of any device aspects.
+			 */
+			if (pte_present(pteval))
+				young = clear_flush_young_ptes(vma, address, pvmw.pte, nr);
+			young |= mmu_notifier_clear_flush_young(vma->vm_mm, address,
+								address + nr * PAGE_SIZE);
+			if (young)
 				referenced++;
 		} else if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) {
 			if (pmdp_clear_flush_young_notify(vma, address,

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 10/46] mm/huge_memory: fix list corruption when deferred_split_scan() races with deferred_split_folio()
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (8 preceding siblings ...)
  2026-10-26 23:17 ` [PATCH 09/46] mm/rmap: handle device-exclusive entries in folio_referenced_one() David Hildenbrand (Arm)
@ 2026-10-26 23:17 ` David Hildenbrand (Arm)
  2026-10-26 23:17 ` [PATCH 11/46] mm/huge_memory: properly handle refcounted PUD mappings on fork David Hildenbrand (Arm)
                   ` (35 subsequent siblings)
  45 siblings, 0 replies; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:17 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, stable, Josef Bacik, David Hildenbrand (Arm)

Since the deferred split queue became a list_lru, the isolate callback
moves the folios it took a reference on to an on-stack list, linked
through folio->_deferred_list, and deferred_split_scan() takes them off
that list with list_del_init() without holding the list_lru lock.

deferred_split_folio() does not know about the on-stack list. It only
holds the list_lru lock when it looks at the same list_head, and it can
run for such a folio: a THP is queued when it is mapped, as a candidate
for the underused check, and is queued "again" when a part of it gets
unmapped:

  CPU0 deferred_split_scan()          CPU1 deferred_split_folio()
  list_del_init(&folio->_deferred_list)
    next->prev = prev
    prev->next = next
    entry->next = entry
                                      list_lru_lock_irqsave()
                                      folio_set_partially_mapped()
                                      __list_lru_add()
                                        list_empty(item)  -> true
                                        list_add_tail(item, &l->list)
                                          item->next = &l->list
                                          item->prev = tail
    entry->prev = entry

The folio now sits on the list_lru with ->prev pointing to itself. The
next removal leaves the neighbours pointing to it, and they still do so
after the folio has been freed. With CONFIG_DEBUG_LIST:

  list_del corruption. prev->next should be ffd4000000270090, but was
  ffd4000000278090. (prev=ffd4000000270090)

Fix it by grabbing the lock around list_del_init() so
deferred_split_folio() cannot race with it.

Fixes: fafaeceb89a5 ("mm: switch deferred split shrinker to list_lru")
Cc: stable@vger.kernel.org
Reported-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 mm/huge_memory.c | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index bd44d58e86845..4c0194af9016d 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -4522,8 +4522,7 @@ int split_folio_to_list(struct folio *folio, struct list_head *list)
  *
  * It is unsafe to call folio_unqueue_deferred_split() until folio refcount is
  * zero: because even when the list_lru lock is held, a non-empty
- * _deferred_list might be in use on deferred_split_scan()'s unlocked
- * on-stack list.
+ * _deferred_list might be in use on deferred_split_scan()'s on-stack list.
  *
  * The list_lru sublist is determined by folio's memcg: it is therefore
  * important to unqueue deferred split before changing folio memcg.
@@ -4665,10 +4664,22 @@ static unsigned long deferred_split_scan(struct shrinker *shrink,
 					    deferred_split_isolate, &dispose);
 
 	list_for_each_entry_safe(folio, next, &dispose, _deferred_list) {
+		struct mem_cgroup *memcg;
+		struct list_lru_one *lru;
 		bool did_split = false;
 		bool underused = false;
 
+		/*
+		 * Sync with deferred_split_folio(), which can requeue the
+		 * folio once list_empty() is true, and sets PG_partially_mapped.
+		 */
+		rcu_read_lock();
+		memcg = folio_memcg(folio);
+		lru = list_lru_lock_irq(&deferred_split_lru, folio_nid(folio),
+					&memcg);
 		list_del_init(&folio->_deferred_list);
+		list_lru_unlock_irq(lru);
+		rcu_read_unlock();
 
 		if (!folio_test_partially_mapped(folio)) {
 			/*

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 11/46] mm/huge_memory: properly handle refcounted PUD mappings on fork
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (9 preceding siblings ...)
  2026-10-26 23:17 ` [PATCH 10/46] mm/huge_memory: fix list corruption when deferred_split_scan() races with deferred_split_folio() David Hildenbrand (Arm)
@ 2026-10-26 23:17 ` David Hildenbrand (Arm)
  2026-10-26 23:17 ` [PATCH 12/46] mm/huge_memory: fix livelock on device private folio David Hildenbrand (Arm)
                   ` (34 subsequent siblings)
  45 siblings, 0 replies; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:17 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, stable, David Hildenbrand (Arm)

copy_huge_pud() copies device-DAX entries without taking a folio reference
or updating mapcounts and the child's RSS.

For example, MADV_GUARD_INSTALL sets VM_MAYBE_GUARD on a device-DAX VMA,
forcing copy_page_range() to traverse the whole VMA on fork. Any remaining
huge PUDs are then copied without accounting for the new mappings.
Unmapping them in the child decrements accounting that was never added.

Use vm_normal_page_pud() to identify refcounted mappings. Take a folio
reference and add the child's PUD rmap and RSS accounting before installing
the copied entry. Pass src and dst VMAs consistently instead of src and
dst MM. Move the TODO.

Fixes: aed877c2b4257 ("device/dax: properly refcount device dax pages when mapping")
Cc: stable@vger.kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 include/linux/huge_mm.h |  5 ++---
 mm/huge_memory.c        | 27 +++++++++++++++++++--------
 mm/memory.c             |  4 +---
 3 files changed, 22 insertions(+), 14 deletions(-)

diff --git a/include/linux/huge_mm.h b/include/linux/huge_mm.h
index c745f7ad22987..fac05120ab774 100644
--- a/include/linux/huge_mm.h
+++ b/include/linux/huge_mm.h
@@ -12,9 +12,8 @@ int copy_huge_pmd(struct mm_struct *dst_mm, struct mm_struct *src_mm,
 		  pmd_t *dst_pmd, pmd_t *src_pmd, unsigned long addr,
 		  struct vm_area_struct *dst_vma, struct vm_area_struct *src_vma);
 bool huge_pmd_set_accessed(struct vm_fault *vmf);
-int copy_huge_pud(struct mm_struct *dst_mm, struct mm_struct *src_mm,
-		  pud_t *dst_pud, pud_t *src_pud, unsigned long addr,
-		  struct vm_area_struct *vma);
+int copy_huge_pud(struct vm_area_struct *dst_vma, struct vm_area_struct *src_vma,
+		pud_t *dst_pud, pud_t *src_pud, unsigned long addr);
 
 #ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD
 void huge_pud_set_accessed(struct vm_fault *vmf, pud_t orig_pud);
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 4c0194af9016d..283c4bc8b927c 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -2072,11 +2072,13 @@ void touch_pud(struct vm_area_struct *vma, unsigned long addr,
 		update_mmu_cache_pud(vma, addr, pud);
 }
 
-int copy_huge_pud(struct mm_struct *dst_mm, struct mm_struct *src_mm,
-		  pud_t *dst_pud, pud_t *src_pud, unsigned long addr,
-		  struct vm_area_struct *vma)
+int copy_huge_pud(struct vm_area_struct *dst_vma, struct vm_area_struct *src_vma,
+		pud_t *dst_pud, pud_t *src_pud, unsigned long addr)
 {
+	struct mm_struct *dst_mm = dst_vma->vm_mm;
+	struct mm_struct *src_mm = src_vma->vm_mm;
 	spinlock_t *dst_ptl, *src_ptl;
+	struct page *page;
 	pud_t pud;
 	int ret;
 
@@ -2089,11 +2091,20 @@ int copy_huge_pud(struct mm_struct *dst_mm, struct mm_struct *src_mm,
 	if (unlikely(!pud_trans_huge(pud)))
 		goto out_unlock;
 
-	/*
-	 * TODO: once we support anonymous pages, use
-	 * folio_try_dup_anon_rmap_*() and split if duplicating fails.
-	 */
-	if (vma_is_cow_mapping(vma) && pud_write(pud)) {
+	page = vm_normal_page_pud(src_vma, addr, pud);
+	if (page) {
+		struct folio *folio = page_folio(page);
+
+		folio_get(folio);
+		/*
+		 * TODO: once we support anonymous pages, use
+		 * folio_try_dup_anon_rmap_*() and split if duplicating fails.
+		 */
+		folio_add_file_rmap_pud(folio, page, dst_vma);
+		add_mm_counter(dst_mm, mm_counter_file(folio), HPAGE_PUD_NR);
+	}
+
+	if (vma_is_cow_mapping(src_vma) && pud_write(pud)) {
 		pudp_set_wrprotect(src_mm, addr, src_pud);
 		pud = pud_wrprotect(pud);
 	}
diff --git a/mm/memory.c b/mm/memory.c
index 5d6d695675bce..0f4db5080e371 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -1463,7 +1463,6 @@ copy_pud_range(struct vm_area_struct *dst_vma, struct vm_area_struct *src_vma,
 	       unsigned long end)
 {
 	struct mm_struct *dst_mm = dst_vma->vm_mm;
-	struct mm_struct *src_mm = src_vma->vm_mm;
 	pud_t *src_pud, *dst_pud;
 	unsigned long next;
 
@@ -1477,8 +1476,7 @@ copy_pud_range(struct vm_area_struct *dst_vma, struct vm_area_struct *src_vma,
 			int err;
 
 			VM_BUG_ON_VMA(next-addr != HPAGE_PUD_SIZE, src_vma);
-			err = copy_huge_pud(dst_mm, src_mm,
-					    dst_pud, src_pud, addr, src_vma);
+			err = copy_huge_pud(dst_vma, src_vma, dst_pud, src_pud, addr);
 			if (err == -ENOMEM)
 				return -ENOMEM;
 			if (!err)

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 12/46] mm/huge_memory: fix livelock on device private folio
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (10 preceding siblings ...)
  2026-10-26 23:17 ` [PATCH 11/46] mm/huge_memory: properly handle refcounted PUD mappings on fork David Hildenbrand (Arm)
@ 2026-10-26 23:17 ` David Hildenbrand (Arm)
  2026-10-26 23:17 ` [PATCH 13/46] mm/huge_memory: fix truncate racing with PMD zapping David Hildenbrand (Arm)
                   ` (33 subsequent siblings)
  45 siblings, 0 replies; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:17 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, Josef Bacik, David Hildenbrand (Arm)

From: Josef Bacik <josef@toxicpanda.com>

If do_huge_pmd_device_private() cannot lock the folio, it simply returns
to try again on the next fault.

Just like we did in commit b570f37a2ce4 ("mm: Fix a hmm_range_fault()
livelock / starvation problem"), let's wait for the softleaf entry,
which will drop the PTL and wait until the folio was unlocked. This is
precisely what we do in do_swap_page() with device-private folios. This
avoids possibly livelocking.

Update softleaf_entry_wait_on_locked() documentation to clarify that
device-private entries wait until the folio is unlocked.

There seems to be no compelling reason to backport this to stable
kernels unless we actually see problems there.

Fix generated by an LLM and sent by Josef Bacik in private.

Fixes: 4964099163d0 ("mm/memory/fault: add THP fault handling for zone device private pages")
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
[ david: simplify patch description, fixup softleaf_entry_wait_on_locked description]
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 mm/filemap.c     | 4 ++--
 mm/huge_memory.c | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/mm/filemap.c b/mm/filemap.c
index b04be64a5069f..e85a4114d2ecc 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -1395,8 +1395,8 @@ static inline int folio_wait_bit_common(struct folio *folio, int bit_nr,
 
 #ifdef CONFIG_MIGRATION
 /**
- * softleaf_entry_wait_on_locked - Wait for a migration entry or
- * device_private entry to be removed.
+ * softleaf_entry_wait_on_locked - Wait for a migration entry to be removed
+ * or a device-private folio in a device-private entry to get unlocked.
  * @entry: migration or device_private swap entry.
  * @ptl: already locked ptl. This function will drop the lock.
  *
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 283c4bc8b927c..2b31a425c7a32 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -1500,7 +1500,7 @@ vm_fault_t do_huge_pmd_device_private(struct vm_fault *vmf)
 		folio_unlock(folio);
 		folio_put(folio);
 	} else {
-		spin_unlock(ptl);
+		softleaf_entry_wait_on_locked(entry, ptl);
 	}
 
 	return ret;

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 13/46] mm/huge_memory: fix truncate racing with PMD zapping
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (11 preceding siblings ...)
  2026-10-26 23:17 ` [PATCH 12/46] mm/huge_memory: fix livelock on device private folio David Hildenbrand (Arm)
@ 2026-10-26 23:17 ` David Hildenbrand (Arm)
  2026-10-26 23:17 ` [PATCH 14/46] mm/huge_memory: fix zapping migration entries for device-private THPs David Hildenbrand (Arm)
                   ` (32 subsequent siblings)
  45 siblings, 0 replies; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:17 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, Chris Mason, stable, David Hildenbrand (Arm)

From: Chris Mason <mason@kernel.org>

zap_huge_pmd_folio() removes the rmap before calling folio_mark_dirty().
If this was the last mapping, truncation can skip unmapping the folio
and proceed without waiting for the PMD lock, racing with dirtying.

ifs_set_range_dirty() can oops if MADV_DONTNEED races with
ftruncate() on XFS, when we get the folio set dirty after it was found
to not be mapped anymore.

Move folio_mark_dirty() and folio_mark_accessed() before rmap removal,
matching the PTE zap path. This keeps the folio mapped while updating
its state, so truncation must wait for the page table lock.

Fix generated by an LLM and sent by Chris Mason in private.

Fixes: fe6cf984939d ("mm/huge_memory: transfer the pmd dirty bit to the folio on zap")
Cc: stable@vger.kernel.org
Signed-off-by: Chris Mason <mason@kernel.org>
[ david: simplify comment and description ]
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 mm/huge_memory.c | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 2b31a425c7a32..eda020dd6e33f 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -2495,6 +2495,14 @@ static void zap_huge_pmd_folio(struct mm_struct *mm, struct vm_area_struct *vma,
 {
 	const bool is_device_private = folio_is_device_private(folio);
 
+	/* Transfer young+dirty while the folio is still mapped. */
+	if (is_present && !folio_test_anon(folio)) {
+		if (pmd_dirty(pmdval))
+			folio_mark_dirty(folio);
+		if (pmd_young(pmdval) && likely(vma_has_recency(vma)))
+			folio_mark_accessed(folio);
+	}
+
 	/* Present and device private folios are rmappable. */
 	if (is_present || is_device_private)
 		folio_remove_rmap_pmd(folio, &folio->page, vma);
@@ -2504,12 +2512,6 @@ static void zap_huge_pmd_folio(struct mm_struct *mm, struct vm_area_struct *vma,
 	} else {
 		add_mm_counter(mm, mm_counter_file(folio),
 			       -HPAGE_PMD_NR);
-
-		if (is_present && pmd_dirty(pmdval))
-			folio_mark_dirty(folio);
-		if (is_present && pmd_young(pmdval) &&
-		    likely(vma_has_recency(vma)))
-			folio_mark_accessed(folio);
 	}
 
 	/* Device private folios are pinned. */

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 14/46] mm/huge_memory: fix zapping migration entries for device-private THPs
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (12 preceding siblings ...)
  2026-10-26 23:17 ` [PATCH 13/46] mm/huge_memory: fix truncate racing with PMD zapping David Hildenbrand (Arm)
@ 2026-10-26 23:17 ` David Hildenbrand (Arm)
  2026-10-26 23:17 ` [PATCH 15/46] mm/khugepaged: always recheck the pmd in try_collapse_pte_mapped_thp() David Hildenbrand (Arm)
                   ` (31 subsequent siblings)
  45 siblings, 0 replies; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:17 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, Chris Mason, stable, David Hildenbrand (Arm)

From: Chris Mason <mason@kernel.org>

A PMD migration entry can refer to a device-private folio.
zap_huge_pmd_folio() checks the folio type instead of the entry type,
so it treats such a migration entry as a device-private entry.

Installing the migration entry already removed the reverse mapping and
dropped the mapping reference. Zapping it must not repeat those
operations. Concurrent MADV_DONTNEED during migration back to system
memory can trigger this.

Check the PMD entry type using pmd_is_device_private_entry().

Fix generated by an LLM and sent by Chris Mason in private.

Fixes: 368076f52ebe ("mm/huge_memory: add device-private THP support to PMD operations")
Cc: stable@vger.kernel.org
Signed-off-by: Chris Mason <mason@kernel.org>
[ david: simplify description ]
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 mm/huge_memory.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index eda020dd6e33f..1b50cc2b35351 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -2493,7 +2493,7 @@ static inline void zap_deposited_table(struct mm_struct *mm, pmd_t *pmd)
 static void zap_huge_pmd_folio(struct mm_struct *mm, struct vm_area_struct *vma,
 		pmd_t pmdval, struct folio *folio, bool is_present)
 {
-	const bool is_device_private = folio_is_device_private(folio);
+	const bool is_device_private = !is_present && pmd_is_device_private_entry(pmdval);
 
 	/* Transfer young+dirty while the folio is still mapped. */
 	if (is_present && !folio_test_anon(folio)) {

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 15/46] mm/khugepaged: always recheck the pmd in try_collapse_pte_mapped_thp()
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (13 preceding siblings ...)
  2026-10-26 23:17 ` [PATCH 14/46] mm/huge_memory: fix zapping migration entries for device-private THPs David Hildenbrand (Arm)
@ 2026-10-26 23:17 ` David Hildenbrand (Arm)
  2026-10-26 23:17 ` [PATCH 16/46] mm/khugepaged: fix PMD table lock leak " David Hildenbrand (Arm)
                   ` (30 subsequent siblings)
  45 siblings, 0 replies; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:17 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, Josef Bacik, stable, David Hildenbrand (Arm)

From: Josef Bacik <josef@toxicpanda.com>

try_collapse_pte_mapped_thp() drops the PTE lock after it has cleared the
page table, and takes the PMD lock and the PTE lock to remove it.

In between, MADV_DONTNEED with CONFIG_PT_RECLAIM can reclaim the
page table. The pmd_same() check is supposed to handle this, but it is
only done with CONFIG_SPLIT_PTE_PTLOCKS.

Fix it by performing the check unconditionally.

Fix generated by an LLM and sent by Josef Bacik in private.

Fixes: 6375e95f381e ("mm: pgtable: reclaim empty PTE page in madvise(MADV_DONTNEED)")
Cc: stable@vger.kernel.org
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
[ david: adjust description ]
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 mm/khugepaged.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/mm/khugepaged.c b/mm/khugepaged.c
index 4b71d010b2aff..f53c50507c83d 100644
--- a/mm/khugepaged.c
+++ b/mm/khugepaged.c
@@ -2013,12 +2013,11 @@ static enum scan_result try_collapse_pte_mapped_thp(struct mm_struct *mm, unsign
 	/* step 4: remove empty page table */
 	if (!pml) {
 		pml = pmd_lock(mm, pmd);
-		if (ptl != pml) {
+		if (ptl != pml)
 			spin_lock_nested(ptl, SINGLE_DEPTH_NESTING);
-			if (unlikely(!pmd_same(pgt_pmd, pmdp_get_lockless(pmd)))) {
-				flush_tlb_mm(mm);
-				goto unlock;
-			}
+		if (unlikely(!pmd_same(pgt_pmd, pmdp_get_lockless(pmd)))) {
+			flush_tlb_mm(mm);
+			goto unlock;
 		}
 	}
 	pgt_pmd = pmdp_collapse_flush(vma, haddr, pmd);

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 16/46] mm/khugepaged: fix PMD table lock leak in try_collapse_pte_mapped_thp()
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (14 preceding siblings ...)
  2026-10-26 23:17 ` [PATCH 15/46] mm/khugepaged: always recheck the pmd in try_collapse_pte_mapped_thp() David Hildenbrand (Arm)
@ 2026-10-26 23:17 ` David Hildenbrand (Arm)
  2026-10-26 23:17 ` [PATCH 17/46] mm/khugepaged: preserve dirty bits when collapsing PTE-mapped THPs David Hildenbrand (Arm)
                   ` (29 subsequent siblings)
  45 siblings, 0 replies; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:17 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, Josef Bacik, stable, David Hildenbrand (Arm)

From: Josef Bacik <josef@toxicpanda.com>

For a private mapping with userfaultfd, try_collapse_pte_mapped_thp()
takes the PMD table lock before it maps the page table for the second time.
If that (pte_offset_map_rw_nolock) fails, because the page table vanished
in the meantime due to concurrent page table reclaim, it leaves through
the abort label, where the PMD table lock is unlocked if it differs from
PTE table lock.

In case the PMD table lock and the PTE table lock match, which is the
case without CONFIG_SPLIT_PTE_PTLOCKS after pte_offset_map_rw_nolock()
failed, we miss to unlock the PMD table.

To fix it, forget the PTE table lock when we unmap+unlock the PTE table.

Fix generated by an LLM and sent by Josef Bacik in private.

Fixes: 6375e95f381e ("mm: pgtable: reclaim empty PTE page in madvise(MADV_DONTNEED)")
Cc: stable@vger.kernel.org
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
[ david: move the ptl = NULL handling; rewrite description, drop wrong comments ]
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 mm/khugepaged.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/mm/khugepaged.c b/mm/khugepaged.c
index f53c50507c83d..04d9bb21ff524 100644
--- a/mm/khugepaged.c
+++ b/mm/khugepaged.c
@@ -1904,7 +1904,7 @@ static enum scan_result try_collapse_pte_mapped_thp(struct mm_struct *mm, unsign
 
 	result = SCAN_FAIL;
 	start_pte = pte_offset_map_lock(mm, pmd, haddr, &ptl);
-	if (!start_pte)		/* mmap_lock + page lock should prevent this */
+	if (!start_pte)
 		goto drop_folio;
 
 	/* step 1: check all mapped PTEs are to the right huge page */
@@ -1935,6 +1935,7 @@ static enum scan_result try_collapse_pte_mapped_thp(struct mm_struct *mm, unsign
 	}
 
 	pte_unmap_unlock(start_pte, ptl);
+	ptl = NULL;
 	mmu_notifier_range_init(&range, MMU_NOTIFY_CLEAR, 0, mm,
 				haddr, haddr + HPAGE_PMD_SIZE);
 	mmu_notifier_invalidate_range_start(&range);
@@ -1952,7 +1953,7 @@ static enum scan_result try_collapse_pte_mapped_thp(struct mm_struct *mm, unsign
 		pml = pmd_lock(mm, pmd);
 
 	start_pte = pte_offset_map_rw_nolock(mm, pmd, haddr, &pgt_pmd, &ptl);
-	if (!start_pte)		/* mmap_lock + page lock should prevent this */
+	if (!start_pte)
 		goto abort;
 	if (!pml)
 		spin_lock(ptl);

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 17/46] mm/khugepaged: preserve dirty bits when collapsing PTE-mapped THPs
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (15 preceding siblings ...)
  2026-10-26 23:17 ` [PATCH 16/46] mm/khugepaged: fix PMD table lock leak " David Hildenbrand (Arm)
@ 2026-10-26 23:17 ` David Hildenbrand (Arm)
  2026-10-26 23:17 ` [PATCH 18/46] mm/khugepaged: check if PTE table is empty in try_collapse_pte_mapped_thp() David Hildenbrand (Arm)
                   ` (28 subsequent siblings)
  45 siblings, 0 replies; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:17 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, Chris Mason, stable, David Hildenbrand (Arm)

From: Chris Mason <mason@kernel.org>

try_collapse_pte_mapped_thp() clears PTEs without transferring their dirty
bits to the folio. A shmem read fault can map a clean folio writable, so
a later store only dirties the PTE. Losing that dirty bit allows reclaim
to discard modified data.

The assumption that regular files are read-only is also obsolete since
commit 1b6444331bebb ("mm/khugepaged: enable clean pagecache folio collapse
for writable files"). In any case, transferring PTE dirty bits to the folio
when removing mappings (and while the folio is still mapped) is the right
thing to do.

Use get_and_clear_ptes() to collect the dirty bits and mark the folio
dirty before unmapping it. Update the comment.

This was reproduced with shmem using MADV_COLLAPSE followed by
MADV_PAGEOUT.

Fix generated by an LLM and sent by Chris Mason in private.

Fixes: 27e1f8273113 ("khugepaged: enable collapse pmd for pte-mapped THP")
Fixes: 1b6444331bebb ("mm/khugepaged: enable clean pagecache folio collapse for writable files")
Cc: stable@vger.kernel.org
Signed-off-by: Chris Mason <mason@kernel.org>
[ david: adjust comment; simplify description; cover file-thp as well ]
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 mm/khugepaged.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/mm/khugepaged.c b/mm/khugepaged.c
index 04d9bb21ff524..dd17c3dae8006 100644
--- a/mm/khugepaged.c
+++ b/mm/khugepaged.c
@@ -1995,9 +1995,10 @@ static enum scan_result try_collapse_pte_mapped_thp(struct mm_struct *mm, unsign
 		/*
 		 * Must clear entry, or a racing truncate may re-remove it.
 		 * TLB flush can be left until pmdp_collapse_flush() does it.
-		 * PTE dirty? Shmem page is already dirty; file is read-only.
 		 */
-		clear_ptes(mm, addr, pte, nr_batch_ptes);
+		ptent = get_and_clear_ptes(mm, addr, pte, nr_batch_ptes);
+		if (pte_dirty(ptent))
+			folio_mark_dirty(folio);
 		folio_remove_rmap_ptes(folio, page, nr_batch_ptes, vma);
 		nr_mapped_ptes += nr_batch_ptes;
 	}

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 18/46] mm/khugepaged: check if PTE table is empty in try_collapse_pte_mapped_thp()
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (16 preceding siblings ...)
  2026-10-26 23:17 ` [PATCH 17/46] mm/khugepaged: preserve dirty bits when collapsing PTE-mapped THPs David Hildenbrand (Arm)
@ 2026-10-26 23:17 ` David Hildenbrand (Arm)
  2026-10-26 23:17 ` [PATCH 19/46] mm/gup: recheck the PUD under PTL in follow_pud_mask() David Hildenbrand (Arm)
                   ` (27 subsequent siblings)
  45 siblings, 0 replies; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:17 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, David Hildenbrand (Arm)

The existing code is rather horrible and already resulted in bugs in the
past: we special-case UFFD inserting anonymous folios by grabbing the PMD
lock early, but ignore any other markers (guard, poison through uffd) that
could have been inserted into the page table in the meantime, effectively
dropping them.

Let's just unify and simplify the locking: try to grab the PMD table
lock and if that fails, flush the TLB, drop the PTE lock, take PT locks in
the right order and check if the page table is still empty.

We still perform the heavy lifting (zapping the folio ptes) under PTE table
lock only.

Include <linux/hugetlb.h> for now, as x86's flush_tlb_range() macro
depends on hugetlb helpers. This dependency needs a separate cleanup.

Both issues this fixes are rather corner cases. Let's not CC stable for
now.

Fixes: f807123d578d ("mm: allow guard regions in file-backed and read-only mappings")
Fixes: 1043173eb5eb ("mm/khugepaged: collapse_pte_mapped_thp() with mmap_read_lock()")
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 mm/khugepaged.c | 64 ++++++++++++++++++++++++++++-----------------------------
 1 file changed, 31 insertions(+), 33 deletions(-)

diff --git a/mm/khugepaged.c b/mm/khugepaged.c
index dd17c3dae8006..4313abf9cfcb9 100644
--- a/mm/khugepaged.c
+++ b/mm/khugepaged.c
@@ -10,6 +10,7 @@
 #include <linux/mm_inline.h>
 #include <linux/kthread.h>
 #include <linux/khugepaged.h>
+#include <linux/hugetlb.h>
 #include <linux/freezer.h>
 #include <linux/mman.h>
 #include <linux/hashtable.h>
@@ -1832,6 +1833,17 @@ static enum scan_result set_huge_pmd(struct vm_area_struct *vma, unsigned long a
 	return SCAN_SUCCEED;
 }
 
+static bool pte_table_empty(pte_t *pte)
+{
+	int i;
+
+	for (i = 0; i < HPAGE_PMD_NR; i++, pte++) {
+		if (!pte_none(ptep_get(pte)))
+			return false;
+	}
+	return true;
+}
+
 static enum scan_result try_collapse_pte_mapped_thp(struct mm_struct *mm, unsigned long addr,
 		bool install_pmd)
 {
@@ -1935,33 +1947,14 @@ static enum scan_result try_collapse_pte_mapped_thp(struct mm_struct *mm, unsign
 	}
 
 	pte_unmap_unlock(start_pte, ptl);
-	ptl = NULL;
 	mmu_notifier_range_init(&range, MMU_NOTIFY_CLEAR, 0, mm,
 				haddr, haddr + HPAGE_PMD_SIZE);
 	mmu_notifier_invalidate_range_start(&range);
 	notified = true;
 
-	/*
-	 * pmd_lock covers a wider range than ptl, and (if split from mm's
-	 * page_table_lock) ptl nests inside pml. The less time we hold pml,
-	 * the better; but userfaultfd's mfill_atomic_pte() on a private VMA
-	 * inserts a valid as-if-COWed PTE without even looking up page cache.
-	 * So page lock of folio does not protect from it, so we must not drop
-	 * ptl before pgt_pmd is removed, so uffd private needs pml taken now.
-	 */
-	if (userfaultfd_armed(vma) && !(vma->vm_flags & VM_SHARED))
-		pml = pmd_lock(mm, pmd);
-
-	start_pte = pte_offset_map_rw_nolock(mm, pmd, haddr, &pgt_pmd, &ptl);
+	start_pte = pte_offset_map_lock(mm, pmd, haddr, &ptl);
 	if (!start_pte)
 		goto abort;
-	if (!pml)
-		spin_lock(ptl);
-	else if (ptl != pml)
-		spin_lock_nested(ptl, SINGLE_DEPTH_NESTING);
-
-	if (unlikely(!pmd_same(pgt_pmd, pmdp_get_lockless(pmd))))
-		goto abort;
 
 	/* step 2: clear page table and adjust rmap */
 	for (i = 0, addr = haddr, pte = start_pte; i < HPAGE_PMD_NR;
@@ -1992,10 +1985,7 @@ static enum scan_result try_collapse_pte_mapped_thp(struct mm_struct *mm, unsign
 
 		nr_batch_ptes = folio_pte_batch(folio, pte, ptent, max_nr_batch_ptes);
 
-		/*
-		 * Must clear entry, or a racing truncate may re-remove it.
-		 * TLB flush can be left until pmdp_collapse_flush() does it.
-		 */
+		/* Must clear entry, or a racing truncate may re-remove it. */
 		ptent = get_and_clear_ptes(mm, addr, pte, nr_batch_ptes);
 		if (pte_dirty(ptent))
 			folio_mark_dirty(folio);
@@ -2003,25 +1993,33 @@ static enum scan_result try_collapse_pte_mapped_thp(struct mm_struct *mm, unsign
 		nr_mapped_ptes += nr_batch_ptes;
 	}
 
-	if (!pml)
-		spin_unlock(ptl);
-
 	/* step 3: set proper refcount and mm_counters. */
 	if (nr_mapped_ptes) {
 		folio_ref_sub(folio, nr_mapped_ptes);
 		add_mm_counter(mm, mm_counter_file(folio), -nr_mapped_ptes);
 	}
 
-	/* step 4: remove empty page table */
-	if (!pml) {
+	/* step 4: acquire the PMD lock and remove the empty page table */
+	pml = pmd_lockptr(mm, pmd);
+	if (ptl != pml && !spin_trylock(pml)) {
+		/* We must flush before dropping the PTL. */
+		if (nr_mapped_ptes)
+			flush_tlb_range(vma, haddr, end);
+		pte_unmap_unlock(start_pte, ptl);
+		ptl = NULL;
+
 		pml = pmd_lock(mm, pmd);
+		start_pte = pte_offset_map_rw_nolock(mm, pmd, haddr, &pgt_pmd, &ptl);
+		if (!start_pte)
+			goto unlock;
 		if (ptl != pml)
 			spin_lock_nested(ptl, SINGLE_DEPTH_NESTING);
-		if (unlikely(!pmd_same(pgt_pmd, pmdp_get_lockless(pmd)))) {
-			flush_tlb_mm(mm);
+
+		if (!pte_table_empty(start_pte))
 			goto unlock;
-		}
 	}
+
+	/* This also flushes the zapped folio ptes properly. */
 	pgt_pmd = pmdp_collapse_flush(vma, haddr, pmd);
 	pmdp_get_lockless_sync();
 	pte_unmap_unlock(start_pte, ptl);
@@ -2042,7 +2040,7 @@ static enum scan_result try_collapse_pte_mapped_thp(struct mm_struct *mm, unsign
 	goto drop_folio;
 abort:
 	if (nr_mapped_ptes) {
-		flush_tlb_mm(mm);
+		flush_tlb_range(vma, haddr, end);
 		folio_ref_sub(folio, nr_mapped_ptes);
 		add_mm_counter(mm, mm_counter_file(folio), -nr_mapped_ptes);
 	}

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 19/46] mm/gup: recheck the PUD under PTL in follow_pud_mask()
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (17 preceding siblings ...)
  2026-10-26 23:17 ` [PATCH 18/46] mm/khugepaged: check if PTE table is empty in try_collapse_pte_mapped_thp() David Hildenbrand (Arm)
@ 2026-10-26 23:17 ` David Hildenbrand (Arm)
  2026-10-26 23:17 ` [PATCH 20/46] mm/gup: fix clearing folios in memfd_pin_folios() David Hildenbrand (Arm)
                   ` (26 subsequent siblings)
  45 siblings, 0 replies; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:17 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, stable, Josef Bacik, David Hildenbrand (Arm)

follow_pud_mask() reads the PUD without a lock. If it is a leaf, it takes
the lock and calls follow_huge_pud(), which reads the entry again, but
only tests whether it is present.

A leaf can be zapped concurrently and a page fault can fill the empty
entry with a page table.

This currently only applies when device-dax makes use of PUD entries,
and the fault after e.g., MADV_DONTNEED would find THPs to be disabled.

That requires a sequence like

1) Fault in the PUD
2) Disable THP
3) Have GUP race against concurrent MADV_DONTNEED + refault

Which is rather unlikely to happen in practice, which is why we never
received a report about such a problem.

Before commit 1b1676180246 ("mm/gup: handle huge pud for
follow_pud_mask()"), we performed that check in follow_devmap_pud() by
testing for pud_devmap().

Let's fix it by just structuring follow_pud_mask() similar to
follow_pmd_mask(), minus protnone stuff that does not apply and minus
FOLL_SPLIT_PMD handling. That makes it much easier to spot any such
inconsistencies.

Perform the pud_bad() check early in follow_pmd_mask() and just forward
the PUD value. We can drop the pud_present() check in follow_huge_pud(),
just like we have in follow_huge_pmd().

Even though we are performing more changes than strictly necessary, the
fix should be easy to backport.

Fixes: 1b1676180246 ("mm/gup: handle huge pud for follow_pud_mask()")
Cc: stable@vger.kernel.org
Reported-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 mm/gup.c | 32 ++++++++++++++++++--------------
 1 file changed, 18 insertions(+), 14 deletions(-)

diff --git a/mm/gup.c b/mm/gup.c
index f166acf794e30..efc9aa2654625 100644
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -658,9 +658,6 @@ static struct page *follow_huge_pud(struct vm_area_struct *vma,
 
 	assert_spin_locked(pud_lockptr(mm, pudp));
 
-	if (!pud_present(pud))
-		return NULL;
-
 	if ((flags & FOLL_WRITE) &&
 	    !can_follow_write_pud(pud, pfn_to_page(pfn), vma, flags))
 		return NULL;
@@ -896,15 +893,17 @@ static struct page *follow_page_pte(struct vm_area_struct *vma,
 }
 
 static struct page *follow_pmd_mask(struct vm_area_struct *vma,
-				    unsigned long address, pud_t *pudp,
-				    unsigned int flags,
-				    unsigned long *page_mask)
+		unsigned long address, pud_t *pudp, pud_t pud,
+		unsigned int flags, unsigned long *page_mask)
 {
 	pmd_t *pmd, pmdval;
 	spinlock_t *ptl;
 	struct page *page;
 	struct mm_struct *mm = vma->vm_mm;
 
+	if (unlikely(pud_bad(pud)))
+		return no_page_table(vma, flags, address);
+
 	pmd = pmd_offset(pudp, address);
 	pmdval = pmdp_get_lockless(pmd);
 	if (pmd_none(pmdval))
@@ -953,18 +952,23 @@ static struct page *follow_pud_mask(struct vm_area_struct *vma,
 	pud = pudp_get(pudp);
 	if (!pud_present(pud))
 		return no_page_table(vma, flags, address);
-	if (pud_leaf(pud)) {
-		ptl = pud_lock(mm, pudp);
-		page = follow_huge_pud(vma, address, pudp, flags, page_mask);
+	if (!pud_leaf(pud))
+		return follow_pmd_mask(vma, address, pudp, pud, flags, page_mask);
+
+	ptl = pud_lock(mm, pudp);
+	pud = *pudp;
+	if (unlikely(!pud_present(pud))) {
 		spin_unlock(ptl);
-		if (page)
-			return page;
 		return no_page_table(vma, flags, address);
 	}
-	if (unlikely(pud_bad(pud)))
-		return no_page_table(vma, flags, address);
+	if (unlikely(!pud_leaf(pud))) {
+		spin_unlock(ptl);
+		return follow_pmd_mask(vma, address, pudp, pud, flags, page_mask);
+	}
 
-	return follow_pmd_mask(vma, address, pudp, flags, page_mask);
+	page = follow_huge_pud(vma, address, pudp, flags, page_mask);
+	spin_unlock(ptl);
+	return page;
 }
 
 static struct page *follow_p4d_mask(struct vm_area_struct *vma,

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 20/46] mm/gup: fix clearing folios in memfd_pin_folios()
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (18 preceding siblings ...)
  2026-10-26 23:17 ` [PATCH 19/46] mm/gup: recheck the PUD under PTL in follow_pud_mask() David Hildenbrand (Arm)
@ 2026-10-26 23:17 ` David Hildenbrand (Arm)
  2026-10-26 23:17 ` [PATCH 21/46] mm/gup: fix out-of-bounds write for nr_pages == 0 in GUP-fast David Hildenbrand (Arm)
                   ` (25 subsequent siblings)
  45 siblings, 0 replies; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:17 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, Chris Mason, stable, David Hildenbrand (Arm)

From: Chris Mason <mason@kernel.org>

memfd_pin_folios() pins folios obtained directly from the page cache
without checking whether they are uptodate. However, shmem fallocate()
can leave newly allocated folios uncleared and not uptodate. Callers
such as udmabuf can then expose uninitialized memory to userspace.

Clear non-uptodate folios and mark them uptodate under the folio lock
before returning them to the caller.

Fix generated by an LLM and sent by Chris Mason in private.

Fixes: 89c1905d9c14 ("mm/gup: introduce memfd_pin_folios() for pinning memfd folios")
Cc: stable@vger.kernel.org
Signed-off-by: Chris Mason <mason@kernel.org>
[ david: simplify description and comment ]
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 mm/gup.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/mm/gup.c b/mm/gup.c
index efc9aa2654625..47e7ae152cdf1 100644
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -3516,6 +3516,20 @@ long memfd_pin_folios(struct file *memfd, loff_t start, loff_t end,
 					goto err;
 				}
 
+				/*
+				 * fallocate() can leave folios in the
+				 * page cache that were never cleared.
+				 */
+				if (!folio_test_uptodate(folio)) {
+					folio_lock(folio);
+					if (!folio_test_uptodate(folio)) {
+						folio_zero_range(folio, 0, folio_size(folio));
+						flush_dcache_folio(folio);
+						folio_mark_uptodate(folio);
+					}
+					folio_unlock(folio);
+				}
+
 				if (nr_folios == 0)
 					*offset = offset_in_folio(folio, start);
 

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 21/46] mm/gup: fix out-of-bounds write for nr_pages == 0 in GUP-fast
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (19 preceding siblings ...)
  2026-10-26 23:17 ` [PATCH 20/46] mm/gup: fix clearing folios in memfd_pin_folios() David Hildenbrand (Arm)
@ 2026-10-26 23:17 ` David Hildenbrand (Arm)
  2026-10-27  9:37   ` Lorenzo Stoakes (ARM)
  2026-10-27  9:40   ` Muchun Song
  2026-10-26 23:17 ` [PATCH 22/46] mm/gup: check for overflow when converting nr_pages to bytes " David Hildenbrand (Arm)
                   ` (24 subsequent siblings)
  45 siblings, 2 replies; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:17 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, Chris Mason, stable, David Hildenbrand (Arm)

From: Chris Mason <mason@kernel.org>

With nr_pages == 0, GUP-fast still enters its page table walk and can
write past the caller's page array. The old end <= start check caught
empty ranges, but was replaced with an overflow check.

Users such as OrangeFS can pass a zero page count derived from a
userspace-supplied length. So let's return zero for nr_pages == 0 before
starting the walk, just like GUP-slow.

Fix generated by an LLM and sent by Chris Mason in private.

Fixes: c28b1fc70390 ("mm/gup: reorganize internal_get_user_pages_fast()")
Cc: stable@vger.kernel.org
Signed-off-by: Chris Mason <mason@kernel.org>
[ david: simplify description ]
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 mm/gup.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/mm/gup.c b/mm/gup.c
index 47e7ae152cdf1..9906965893431 100644
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -3204,6 +3204,9 @@ static int gup_fast_fallback(unsigned long start, unsigned long nr_pages,
 				       FOLL_PCI_P2PDMA | FOLL_HONOR_NUMA_FAULT)))
 		return -EINVAL;
 
+	if (unlikely(!nr_pages))
+		return 0;
+
 	if (gup_flags & FOLL_PIN)
 		mm_set_has_pinned_flag(current->mm);
 

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 22/46] mm/gup: check for overflow when converting nr_pages to bytes in GUP-fast
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (20 preceding siblings ...)
  2026-10-26 23:17 ` [PATCH 21/46] mm/gup: fix out-of-bounds write for nr_pages == 0 in GUP-fast David Hildenbrand (Arm)
@ 2026-10-26 23:17 ` David Hildenbrand (Arm)
  2026-10-27  9:34   ` Lorenzo Stoakes (ARM)
  2026-10-27  9:44   ` Muchun Song
  2026-10-26 23:17 ` [PATCH 23/46] mm/userfaultfd: write-lock the VMA before waking waiters when unregistering David Hildenbrand (Arm)
                   ` (23 subsequent siblings)
  45 siblings, 2 replies; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:17 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, stable, David Hildenbrand (Arm)

The overflow check in gup_fast_fallback() only covers the addition to
start. The preceding nr_pages << PAGE_SHIFT can already have truncated
the length on 32bit.

Users such as RapidIO's rio_dma_transfer() can derive such page counts
from a 64-bit userspace length.

Let's just check_shl_overflow() to reject any such overflow with
-EOVERFLOW early.

Fixes: c28b1fc70390 ("mm/gup: reorganize internal_get_user_pages_fast()")
Cc: stable@vger.kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 mm/gup.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/mm/gup.c b/mm/gup.c
index 9906965893431..48e1bfe5ab9a9 100644
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -3214,8 +3214,8 @@ static int gup_fast_fallback(unsigned long start, unsigned long nr_pages,
 		might_lock_read(&current->mm->mmap_lock);
 
 	start = untagged_addr(start) & PAGE_MASK;
-	len = nr_pages << PAGE_SHIFT;
-	if (check_add_overflow(start, len, &end))
+	if (check_shl_overflow(nr_pages, PAGE_SHIFT, &len) ||
+	    check_add_overflow(start, len, &end))
 		return -EOVERFLOW;
 	if (end > TASK_SIZE_MAX)
 		return -EFAULT;

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 23/46] mm/userfaultfd: write-lock the VMA before waking waiters when unregistering
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (21 preceding siblings ...)
  2026-10-26 23:17 ` [PATCH 22/46] mm/gup: check for overflow when converting nr_pages to bytes " David Hildenbrand (Arm)
@ 2026-10-26 23:17 ` David Hildenbrand (Arm)
  2026-10-27  8:16   ` Mike Rapoport
  2026-10-27  8:43   ` Lorenzo Stoakes (ARM)
  2026-10-26 23:17 ` [PATCH 24/46] mm/userfaultfd: wake all waiters on unregister David Hildenbrand (Arm)
                   ` (22 subsequent siblings)
  45 siblings, 2 replies; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:17 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, stable, Josef Bacik, David Hildenbrand (Arm)

userfaultfd_unregister() wakes pending missing faults before clearing the
VMA's userfaultfd registration. With per-VMA fault locking, holding
mmap_lock for write does not prevent another fault from queuing after
the wakeup but before userfaultfd_clear_vma() write-locks the VMA. That
waiter can then remain asleep indefinitely.

Call vma_start_write() before waking waiters. Existing fault handlers
queue themselves before dropping the VMA read lock, and new readers are
excluded until mmap_write_unlock().

Fixes: 29a22b9e08d7 ("mm: handle userfaults under VMA lock")
Cc: stable@vger.kernel.org
Reported-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 mm/userfaultfd.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
index 669f71d485d02..7e30b5ff17be1 100644
--- a/mm/userfaultfd.c
+++ b/mm/userfaultfd.c
@@ -3991,6 +3991,9 @@ static int userfaultfd_unregister(struct userfaultfd_ctx *ctx,
 			start = vma->vm_start;
 		vma_end = min(end, vma->vm_end);
 
+		/* Prevent new userfaults from being queued after the wakeup. */
+		vma_start_write(vma);
+
 		if (userfaultfd_missing(vma)) {
 			/*
 			 * Wake any concurrent pending userfault while

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 24/46] mm/userfaultfd: wake all waiters on unregister
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (22 preceding siblings ...)
  2026-10-26 23:17 ` [PATCH 23/46] mm/userfaultfd: write-lock the VMA before waking waiters when unregistering David Hildenbrand (Arm)
@ 2026-10-26 23:17 ` David Hildenbrand (Arm)
  2026-10-27  8:17   ` Mike Rapoport
  2026-10-27  8:36   ` Lorenzo Stoakes (ARM)
  2026-10-26 23:17 ` [PATCH 25/46] mm/userfaultfd: wake waiters when registration modes are removed David Hildenbrand (Arm)
                   ` (21 subsequent siblings)
  45 siblings, 2 replies; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:17 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, Josef Bacik, stable, David Hildenbrand (Arm)

From: Josef Bacik <josef@toxicpanda.com>

UFFDIO_UNREGISTER only wakes pending faults if VM_UFFD_MISSING is set.
Threads waiting on write-protect, minor or RWP faults can therefore remain
asleep after unregistering a range that does not track missing faults.

Wake pending faults regardless of the registration mode so they can retry
without an explicit UFFDIO_WAKE or closing the userfaultfd. This matches
the existing behavior for missing faults, including removing unread fault
messages for the woken waiters.

Fix generated by an LLM and sent by Josef Bacik in private.

Fixes: 63b2d4174c4a ("userfaultfd: wp: add the writeprotect API to userfaultfd ioctl")
Cc: stable@vger.kernel.org
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
[ david: rebase; simplify description ]
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 mm/userfaultfd.c | 22 ++++++++++------------
 1 file changed, 10 insertions(+), 12 deletions(-)

diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
index 7e30b5ff17be1..2122676c4220f 100644
--- a/mm/userfaultfd.c
+++ b/mm/userfaultfd.c
@@ -3977,6 +3977,8 @@ static int userfaultfd_unregister(struct userfaultfd_ctx *ctx,
 
 	ret = 0;
 	for_each_vma_range(vmi, vma, end) {
+		struct userfaultfd_wake_range range;
+
 		cond_resched();
 
 		/* VMA not registered with userfaultfd. */
@@ -3994,18 +3996,14 @@ static int userfaultfd_unregister(struct userfaultfd_ctx *ctx,
 		/* Prevent new userfaults from being queued after the wakeup. */
 		vma_start_write(vma);
 
-		if (userfaultfd_missing(vma)) {
-			/*
-			 * Wake any concurrent pending userfault while
-			 * we unregister, so they will not hang
-			 * permanently and it avoids userland to call
-			 * UFFDIO_WAKE explicitly.
-			 */
-			struct userfaultfd_wake_range range;
-			range.start = start;
-			range.len = vma_end - start;
-			wake_userfault(vma->vm_userfaultfd_ctx.ctx, &range);
-		}
+		/*
+		 * Wake any concurrent pending userfault while we unregister,
+		 * so they will not hang permanently and it avoids userland to
+		 * call UFFDIO_WAKE explicitly.
+		 */
+		range.start = start;
+		range.len = vma_end - start;
+		wake_userfault(ctx, &range);
 
 		vma = userfaultfd_clear_vma(&vmi, prev, vma,
 					    start, vma_end);

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 25/46] mm/userfaultfd: wake waiters when registration modes are removed
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (23 preceding siblings ...)
  2026-10-26 23:17 ` [PATCH 24/46] mm/userfaultfd: wake all waiters on unregister David Hildenbrand (Arm)
@ 2026-10-26 23:17 ` David Hildenbrand (Arm)
  2026-10-27  5:10   ` Gregory Price
                     ` (2 more replies)
  2026-10-26 23:17 ` [PATCH 26/46] mm/mmu_gather: fix flushing ranges with 4 GiB or larger David Hildenbrand (Arm)
                   ` (20 subsequent siblings)
  45 siblings, 3 replies; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:17 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, stable, David Hildenbrand (Arm)

UFFDIO_REGISTER can replace MISSING or MINOR tracking without waking
faults that are already queued. For example, switching an anonymous
range from MISSING to WP leaves a missing-fault waiter asleep until
userspace explicitly wakes it.

When a registration change removes a UFFD mode, wake waiters in the
affected interval after updating the VMA. The VMA is write-locked at
this point, so no new faults can queue under the old modes and woken
threads cannot retry until mmap_write_unlock(). Waiters for retained
modes in the same interval may also wake and refault.

The hang reproduces for MISSING-to-WP and MINOR-to-MISSING transitions,
with both read and unread fault events.

Fixes: 63b2d4174c4a ("userfaultfd: wp: add the writeprotect API to userfaultfd ioctl")
Cc: stable@vger.kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 mm/userfaultfd.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
index 2122676c4220f..710e913c73bfa 100644
--- a/mm/userfaultfd.c
+++ b/mm/userfaultfd.c
@@ -2270,6 +2270,9 @@ static struct vm_area_struct *userfaultfd_clear_vma(struct vma_iterator *vmi,
 	return ret;
 }
 
+static void wake_userfault_range(struct userfaultfd_ctx *ctx,
+		unsigned long start, unsigned long end);
+
 /* Assumes mmap write lock taken, and mm_struct pinned. */
 static int userfaultfd_register_range(struct userfaultfd_ctx *ctx,
 			       struct vm_area_struct *vma,
@@ -2287,6 +2290,8 @@ static int userfaultfd_register_range(struct userfaultfd_ctx *ctx,
 		prev = vma;
 
 	for_each_vma_range(vmi, vma, end) {
+		const bool any_mode_removed = vma->vm_flags & __VM_UFFD_FLAGS & ~vm_flags;
+
 		cond_resched();
 
 		VM_WARN_ON_ONCE(!vma_can_userfault(vma, vm_flags, wp_async));
@@ -2332,6 +2337,10 @@ static int userfaultfd_register_range(struct userfaultfd_ctx *ctx,
 		 */
 		userfaultfd_set_ctx(vma, ctx, vm_flags);
 
+		/* Retry faults for removed modes while the VMA is write-locked. */
+		if (any_mode_removed)
+			wake_userfault_range(ctx, start, vma_end);
+
 		if (vma_is_hugetlb(vma) && uffd_disable_huge_pmd_share(vma))
 			hugetlb_unshare_all_pmds(vma);
 
@@ -3648,6 +3657,17 @@ static __always_inline void wake_userfault(struct userfaultfd_ctx *ctx,
 		__wake_userfault(ctx, range);
 }
 
+static void wake_userfault_range(struct userfaultfd_ctx *ctx,
+		unsigned long start, unsigned long end)
+{
+	struct userfaultfd_wake_range range = {
+		.start = start,
+		.len = end - start,
+	};
+
+	wake_userfault(ctx, &range);
+}
+
 static __always_inline int validate_unaligned_range(
 	struct mm_struct *mm, __u64 start, __u64 len)
 {

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 26/46] mm/mmu_gather: fix flushing ranges with 4 GiB or larger
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (24 preceding siblings ...)
  2026-10-26 23:17 ` [PATCH 25/46] mm/userfaultfd: wake waiters when registration modes are removed David Hildenbrand (Arm)
@ 2026-10-26 23:17 ` David Hildenbrand (Arm)
  2026-10-27  3:06   ` Qi Zheng
                     ` (3 more replies)
  2026-10-26 23:17 ` [PATCH 27/46] mm/mmu_notifier: finish non-blocking interval invalidation on error David Hildenbrand (Arm)
                   ` (19 subsequent siblings)
  45 siblings, 4 replies; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:17 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, Josef Bacik, stable, David Hildenbrand (Arm)

From: Josef Bacik <josef@toxicpanda.com>

__tlb_adjust_range() takes the size of the range which has to be flushed
as an unsigned int. Its callers, tlb_flush_{pte,pmd,pud,p4d}_range(), get
and pass an unsigned long. Consequently, a range that is 4 GiB or larger
gets truncated, possibly to 0.

On arm64 with hugetlb, a 64k kernel can flush 16 GiB hugetlb PMDs, and a
16k kernel can flush 64 GiB PUDs through tlb_unshare_pmd_ptdesc(). So
at least these two scenarios are affected.

Fix it by flushing the proper range instead of the truncated one.

Fix generated by an LLM and sent by Josef Bacik in private.

Fixes: b528e4b6405b ("mm/hugetlb: add tlb_remove_hugetlb_entry for handling hugetlb pages")
Fixes: 8ce720d5bd91 ("mm/hugetlb: fix excessive IPI broadcasts when unsharing PMD tables using mmu_gather")
Cc: stable@vger.kernel.org
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
[ david: use two-tab indent, simplify description ]
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 include/asm-generic/tlb.h | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/include/asm-generic/tlb.h b/include/asm-generic/tlb.h
index fbe1114e9a443..3f4a180b48f3c 100644
--- a/include/asm-generic/tlb.h
+++ b/include/asm-generic/tlb.h
@@ -350,8 +350,7 @@ struct mmu_gather {
 void tlb_flush_mmu(struct mmu_gather *tlb);
 
 static inline void __tlb_adjust_range(struct mmu_gather *tlb,
-				      unsigned long address,
-				      unsigned int range_size)
+		unsigned long address, unsigned long range_size)
 {
 	tlb->start = min(tlb->start, address);
 	tlb->end = max(tlb->end, address + range_size);

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 27/46] mm/mmu_notifier: finish non-blocking interval invalidation on error
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (25 preceding siblings ...)
  2026-10-26 23:17 ` [PATCH 26/46] mm/mmu_gather: fix flushing ranges with 4 GiB or larger David Hildenbrand (Arm)
@ 2026-10-26 23:17 ` David Hildenbrand (Arm)
  2026-10-27  9:33   ` Lorenzo Stoakes (ARM)
  2026-10-26 23:17 ` [PATCH 28/46] mm/mmu_notifier: set ->mm only after mmgrab() David Hildenbrand (Arm)
                   ` (18 subsequent siblings)
  45 siblings, 1 reply; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:17 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, Josef Bacik, stable, David Hildenbrand (Arm)

From: Josef Bacik <josef@toxicpanda.com>

When an ordinary MMU notifier rejects a non-blocking invalidation, the
interval invalidation started beforehand is left unfinished: the caller
skips mmu_notifier_invalidate_range_end(). Subsequent interval notifier
operations can then wait forever.

The only in-tree trigger is nouveau SVM, which uses both notifier types
and rejects non-blocking invalidations. Reaping via the OOM reaper or
process_mrelease() can therefore leave the GPU fault worker stuck,
holding a reference that prevents the dying process's address space
and memory from being freed.

End the interval invalidation when an ordinary notifier fails a
non-blocking invalidation, like mn_itree_invalidate() already does when
an interval notifier fails. Make that handling clearer in the
documentation of mmu_notifier_invalidate_range_start_nonblock().

Fix generated by an LLM and sent by Josef Bacik in private.

Fixes: 99cb252f5e68 ("mm/mmu_notifier: add an interval tree notifier")
Cc: stable@vger.kernel.org
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
[ david: simplify description, update function doc ]
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 include/linux/mmu_notifier.h |  3 ++-
 mm/mmu_notifier.c            | 17 +++++++++++++----
 2 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/include/linux/mmu_notifier.h b/include/linux/mmu_notifier.h
index a11a44eef521e..5db78e5761c5c 100644
--- a/include/linux/mmu_notifier.h
+++ b/include/linux/mmu_notifier.h
@@ -483,7 +483,8 @@ mmu_notifier_invalidate_range_start(struct mmu_notifier_range *range)
 /*
  * This version of mmu_notifier_invalidate_range_start() avoids blocking, but it
  * can return an error if a notifier can't proceed without blocking, in which
- * case you're not allowed to modify PTEs in the specified range.
+ * case you're not allowed to modify PTEs in the specified range or call
+ * mmu_notifier_invalidate_range_end().
  *
  * This is mainly intended for OOM handling.
  */
diff --git a/mm/mmu_notifier.c b/mm/mmu_notifier.c
index df69ba6e797f7..2e20f88e162d7 100644
--- a/mm/mmu_notifier.c
+++ b/mm/mmu_notifier.c
@@ -569,16 +569,25 @@ int __mmu_notifier_invalidate_range_start(struct mmu_notifier_range *range)
 {
 	struct mmu_notifier_subscriptions *subscriptions =
 		range->mm->notifier_subscriptions;
-	int ret;
+	const bool has_itree = subscriptions->has_itree;
+	int ret = 0;
 
-	if (subscriptions->has_itree) {
+	if (has_itree) {
 		ret = mn_itree_invalidate(subscriptions, range);
 		if (ret)
 			return ret;
 	}
 	if (!hlist_empty(&subscriptions->list))
-		return mn_hlist_invalidate_range_start(subscriptions, range);
-	return 0;
+		ret = mn_hlist_invalidate_range_start(subscriptions, range);
+
+	/*
+	 * On error, the non-blocking caller is not allowed to call
+	 * invalidate_range_end(), as in mn_itree_invalidate().
+	 */
+	if (ret && has_itree && !mmu_notifier_range_blockable(range))
+		mn_itree_inv_end(subscriptions);
+
+	return ret;
 }
 
 static void

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 28/46] mm/mmu_notifier: set ->mm only after mmgrab()
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (26 preceding siblings ...)
  2026-10-26 23:17 ` [PATCH 27/46] mm/mmu_notifier: finish non-blocking interval invalidation on error David Hildenbrand (Arm)
@ 2026-10-26 23:17 ` David Hildenbrand (Arm)
  2026-10-27  3:42   ` Gregory Price
  2026-10-27  8:50   ` Lorenzo Stoakes (ARM)
  2026-10-26 23:17 ` [PATCH 29/46] mm/mremap: use pudp_huge_get_and_clear() when moving huge PUDs David Hildenbrand (Arm)
                   ` (17 subsequent siblings)
  45 siblings, 2 replies; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:17 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, Chris Mason, stable, David Hildenbrand (Arm)

From: Chris Mason <mason@kernel.org>

Radeon uses a non-NULL notifier->mm to decide whether to call
mmu_interval_notifier_remove() when freeing a buffer object.
__mmu_interval_notifier_insert() sets ->mm before validating the range,
so a wrapping userptr range can leave ->mm set after insertion fails.
Cleanup then tries to remove an unregistered notifier for which no mm
reference was acquired.

Set ->mm only after mmgrab(), once insertion can no longer fail. While
we could fix radeon's code instead, setting ->mm on success only makes
the code more robust.

Fix generated by an LLM and sent by Chris Mason in private.

Fixes: 3506ff69c3ec ("drm/radeon: use mmu_interval_notifier_insert")
Cc: stable@vger.kernel.org
Signed-off-by: Chris Mason <mason@kernel.org>
[ david: simplify description ]
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 mm/mmu_notifier.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/mm/mmu_notifier.c b/mm/mmu_notifier.c
index 2e20f88e162d7..a7bae5de5fedc 100644
--- a/mm/mmu_notifier.c
+++ b/mm/mmu_notifier.c
@@ -947,7 +947,6 @@ static int __mmu_interval_notifier_insert(
 	struct mmu_notifier_subscriptions *subscriptions, unsigned long start,
 	unsigned long length, const struct mmu_interval_notifier_ops *ops)
 {
-	interval_sub->mm = mm;
 	interval_sub->ops = ops;
 	RB_CLEAR_NODE(&interval_sub->interval_tree.rb);
 	interval_sub->interval_tree.start = start;
@@ -964,8 +963,12 @@ static int __mmu_interval_notifier_insert(
 	if (WARN_ON(atomic_read(&mm->mm_users) <= 0))
 		return -EINVAL;
 
-	/* pairs with mmdrop in mmu_interval_notifier_remove() */
+	/*
+	 * Pairs with mmdrop in mmu_interval_notifier_remove(). Drivers take a
+	 * non-NULL ->mm for "registered", so set it only with the reference.
+	 */
 	mmgrab(mm);
+	interval_sub->mm = mm;
 
 	/*
 	 * If some invalidate_range_start/end region is going on in parallel

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 29/46] mm/mremap: use pudp_huge_get_and_clear() when moving huge PUDs
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (27 preceding siblings ...)
  2026-10-26 23:17 ` [PATCH 28/46] mm/mmu_notifier: set ->mm only after mmgrab() David Hildenbrand (Arm)
@ 2026-10-26 23:17 ` David Hildenbrand (Arm)
  2026-10-26 23:17 ` [PATCH 30/46] mm/mremap: recheck PUDs under the page table lock David Hildenbrand (Arm)
                   ` (16 subsequent siblings)
  45 siblings, 0 replies; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:17 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, stable, David Hildenbrand (Arm)

move_huge_pud() reads the old PUD and clears it in separate operations.
Hardware accessed or dirty updates between those operations can be lost
when the saved entry is installed at the new address.

The raw pud_clear() also bypasses page_table_check_pud_clear(), while
set_pud_at() accounts for the destination mapping. This leaves the
checker counts unbalanced for mappings tracked by page table checking.

To fix it, simply use pudp_huge_get_and_clear().

Fixes: 7d846db7d0e2 ("mm/mremap: convert huge PUD move to separate helper")
Cc: stable@vger.kernel.org
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 mm/mremap.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/mm/mremap.c b/mm/mremap.c
index 0d06d7f37f19a..16e736c72d9cb 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -509,8 +509,7 @@ static bool move_huge_pud(struct pagetable_move_control *pmc,
 		spin_lock_nested(new_ptl, SINGLE_DEPTH_NESTING);
 
 	/* Clear the pud */
-	pud = *old_pud;
-	pud_clear(old_pud);
+	pud = pudp_huge_get_and_clear(mm, pmc->old_addr, old_pud);
 
 	VM_BUG_ON(!pud_none(*new_pud));
 

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 30/46] mm/mremap: recheck PUDs under the page table lock
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (28 preceding siblings ...)
  2026-10-26 23:17 ` [PATCH 29/46] mm/mremap: use pudp_huge_get_and_clear() when moving huge PUDs David Hildenbrand (Arm)
@ 2026-10-26 23:17 ` David Hildenbrand (Arm)
  2026-10-26 23:17 ` [PATCH 31/46] mm/mremap: fix moving PUD leaves David Hildenbrand (Arm)
                   ` (15 subsequent siblings)
  45 siblings, 0 replies; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:17 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, stable, David Hildenbrand (Arm)

Once get_old_pud() is fixed to accept PUD leaves, unmap_mapping_range() can
clear a leaf between the lookup and the move. Holding mmap_lock in write
mode does not prevent this.

If the zap happens before move_page_tables() tests the entry, an empty
PUD can reach move_normal_pud(), where pud_populate() turns it into a
present page table entry. If it happens after the test, move_huge_pud()
can instead try to move an empty entry, triggering CONFIG_DEBUG_VM
warnings on powerpc.

Recheck the source under the page table lock in both helpers. Treat an
empty source in move_normal_pud() as a completed move, and use
__pud_trans_huge_lock() in move_huge_pud().

In the future we should likely have the code lookup a PUD/PMD lockless
once, instead of multiple times, because one of the problematic bits
here is the:

	pud_trans_huge(*old_pud)

Fixes: 0881ace292b6 ("mm/mremap: use pmd/pud_poplulate to update page table entries")
Cc: stable@vger.kernel.org
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 mm/mremap.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/mm/mremap.c b/mm/mremap.c
index 16e736c72d9cb..91f0865f6aeea 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -461,14 +461,18 @@ static bool move_normal_pud(struct pagetable_move_control *pmc,
 	if (new_ptl != old_ptl)
 		spin_lock_nested(new_ptl, SINGLE_DEPTH_NESTING);
 
-	/* Clear the pud */
 	pud = *old_pud;
+	if (unlikely(pud_none(pud)))
+		goto out_unlock;
+
+	/* Clear the pud */
 	pud_clear(old_pud);
 
 	VM_BUG_ON(!pud_none(*new_pud));
 
 	pud_populate(mm, new_pud, pud_pgtable(pud));
 	flush_tlb_range(vma, pmc->old_addr, pmc->old_addr + PUD_SIZE);
+out_unlock:
 	if (new_ptl != old_ptl)
 		spin_unlock(new_ptl);
 	spin_unlock(old_ptl);
@@ -503,7 +507,9 @@ static bool move_huge_pud(struct pagetable_move_control *pmc,
 	 * We don't have to worry about the ordering of src and dst
 	 * ptlocks because exclusive mmap_lock prevents deadlock.
 	 */
-	old_ptl = pud_lock(mm, old_pud);
+	old_ptl = __pud_trans_huge_lock(old_pud, vma);
+	if (unlikely(!old_ptl))
+		return false;
 	new_ptl = pud_lockptr(mm, new_pud);
 	if (new_ptl != old_ptl)
 		spin_lock_nested(new_ptl, SINGLE_DEPTH_NESTING);

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 31/46] mm/mremap: fix moving PUD leaves
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (29 preceding siblings ...)
  2026-10-26 23:17 ` [PATCH 30/46] mm/mremap: recheck PUDs under the page table lock David Hildenbrand (Arm)
@ 2026-10-26 23:17 ` David Hildenbrand (Arm)
  2026-10-26 23:17 ` [PATCH 32/46] mm/memory_hotplug: avoid races in pfn_to_online_page() with dying pgmap David Hildenbrand (Arm)
                   ` (14 subsequent siblings)
  45 siblings, 0 replies; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:17 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, Josef Bacik, stable, David Hildenbrand (Arm)

From: Josef Bacik <josef@toxicpanda.com>

pud_none_or_clear_bad() only really works on page tables. PUD leaves
confuse the check and make us clear the page table entry and print a
warning.

Since commit aed877c2b4257 ("device/dax: properly refcount device dax pages
when mapping"), this also leaks device-DAX folio references, mapcounts
and RSS accounting, resulting in "Bad rss-counter state" warnings on exit.

Allow PUD leaves in get_old_pud(). If a PUD leaf cannot be moved as a
whole or the move fails, split it. This unmaps it with proper accounting
instead of treating the leaf entry as a PMD table.

Keep using pud_trans_huge() for now, in the future this code should be
cleaned up to just check for PUD leaves.

Fix generated by an LLM and sent by Josef Bacik in private.

Fixes: a00cc7d9dd93 ("mm, x86: add support for PUD-sized transparent hugepages")
Cc: stable@vger.kernel.org
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
[ david: fallthrough after splitting ]
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 mm/mremap.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/mm/mremap.c b/mm/mremap.c
index 91f0865f6aeea..1237718848f5c 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -87,7 +87,7 @@ static pud_t *get_old_pud(struct mm_struct *mm, unsigned long addr)
 		return NULL;
 
 	pud = pud_offset(p4d, addr);
-	if (pud_none_or_clear_bad(pud))
+	if (!pud_trans_huge(*pud) && pud_none_or_clear_bad(pud))
 		return NULL;
 
 	return pud;
@@ -847,11 +847,10 @@ unsigned long move_page_tables(struct pagetable_move_control *pmc)
 		if (!new_pud)
 			break;
 		if (pud_trans_huge(*old_pud)) {
-			if (extent == HPAGE_PUD_SIZE) {
-				move_pgt_entry(pmc, HPAGE_PUD, old_pud, new_pud);
-				/* We ignore and continue on error? */
+			if (extent == HPAGE_PUD_SIZE &&
+			    move_pgt_entry(pmc, HPAGE_PUD, old_pud, new_pud))
 				continue;
-			}
+			split_huge_pud(pmc->old, old_pud, pmc->old_addr);
 		} else if (IS_ENABLED(CONFIG_HAVE_MOVE_PUD) && extent == PUD_SIZE) {
 			if (move_pgt_entry(pmc, NORMAL_PUD, old_pud, new_pud))
 				continue;

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 32/46] mm/memory_hotplug: avoid races in pfn_to_online_page() with dying pgmap
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (30 preceding siblings ...)
  2026-10-26 23:17 ` [PATCH 31/46] mm/mremap: fix moving PUD leaves David Hildenbrand (Arm)
@ 2026-10-26 23:17 ` David Hildenbrand (Arm)
  2026-10-26 23:17 ` [PATCH 33/46] mm/madvise: fix data loss from MADV_FREE on a KSM page David Hildenbrand (Arm)
                   ` (13 subsequent siblings)
  45 siblings, 0 replies; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:17 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, Josef Bacik, David Hildenbrand (Arm)

From: Josef Bacik <josef@toxicpanda.com>

If ZONE_DEVICE memory shares a memory section with ordinary memory, the
section is online and the pfns of the device are valid.
pfn_to_online_page() tells them apart by asking get_dev_pagemap() whether
the pfn belongs to a dev_pagemap.

get_dev_pagemap() only returns a dev_pagemap whose reference is alive.
memunmap_pages() kills the reference first, waits until all pages are
idle, and then removes the memmap. During all that time the function
finds nothing, and pfn_to_online_page() hands out the struct pages of the
device as if they were online memory. A pfn walker reads them while they
are poisoned and freed.

The entry in pgmap_array is only deleted after the pages have been
removed. Look at that instead of trying to get a reference.

This is probably not worth CCing stable.

Fix generated by an LLM and sent by Josef Bacik in private.

Fixes: 1f90a3477df3 ("mm: teach pfn_to_online_page() about ZONE_DEVICE section collisions")
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 include/linux/memremap.h |  6 ++++++
 mm/memory_hotplug.c      | 13 +++++--------
 mm/memremap.c            | 13 +++++++++++++
 3 files changed, 24 insertions(+), 8 deletions(-)

diff --git a/include/linux/memremap.h b/include/linux/memremap.h
index e3c2ccf872a8a..b5e5e626c7a59 100644
--- a/include/linux/memremap.h
+++ b/include/linux/memremap.h
@@ -231,6 +231,7 @@ void memunmap_pages(struct dev_pagemap *pgmap);
 void *devm_memremap_pages(struct device *dev, struct dev_pagemap *pgmap);
 void devm_memunmap_pages(struct device *dev, struct dev_pagemap *pgmap);
 struct dev_pagemap *get_dev_pagemap(unsigned long pfn);
+bool pfn_has_dev_pagemap(unsigned long pfn);
 bool pgmap_pfn_valid(struct dev_pagemap *pgmap, unsigned long pfn);
 
 unsigned long memremap_compat_align(void);
@@ -284,6 +285,11 @@ static inline struct dev_pagemap *get_dev_pagemap(unsigned long pfn)
 	return NULL;
 }
 
+static inline bool pfn_has_dev_pagemap(unsigned long pfn)
+{
+	return false;
+}
+
 static inline bool pgmap_pfn_valid(struct dev_pagemap *pgmap, unsigned long pfn)
 {
 	return false;
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index 796af1028ee23..5a972d7a9e478 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -342,7 +342,6 @@ static int check_pfn_span(unsigned long pfn, unsigned long nr_pages)
 struct page *pfn_to_online_page(unsigned long pfn)
 {
 	unsigned long nr = pfn_to_section_nr(pfn);
-	struct dev_pagemap *pgmap;
 	struct mem_section *ms;
 
 	BUILD_BUG_ON(IS_ENABLED(CONFIG_HAVE_ARCH_PFN_VALID));
@@ -363,14 +362,12 @@ struct page *pfn_to_online_page(unsigned long pfn)
 	/*
 	 * Slowpath: when ZONE_DEVICE collides with
 	 * ZONE_{NORMAL,MOVABLE} within the same section some pfns in
-	 * the section may be 'offline' but 'valid'. Only
-	 * get_dev_pagemap() can determine sub-section online status.
+	 * the section may be 'offline' but 'valid'. Only the presence of a
+	 * pgmap can determine sub-section online status: it indicates a
+	 * ZONE_DEVICE offline pfn. That includes a pgmap whose reference has
+	 * been killed, its memmap is about to go away.
 	 */
-	pgmap = get_dev_pagemap(pfn);
-	put_dev_pagemap(pgmap);
-
-	/* The presence of a pgmap indicates ZONE_DEVICE offline pfn */
-	if (pgmap)
+	if (pfn_has_dev_pagemap(pfn))
 		return NULL;
 
 	return pfn_to_page(pfn);
diff --git a/mm/memremap.c b/mm/memremap.c
index accba23aef28c..a1e99a4c55c56 100644
--- a/mm/memremap.c
+++ b/mm/memremap.c
@@ -413,6 +413,19 @@ struct dev_pagemap *get_dev_pagemap(unsigned long pfn)
 }
 EXPORT_SYMBOL_GPL(get_dev_pagemap);
 
+/**
+ * pfn_has_dev_pagemap() - does @pfn belong to a dev_pagemap, dead or alive
+ * @pfn: page frame number to lookup page_map
+ *
+ * In contrast to get_dev_pagemap() this also finds a dev_pagemap which is on
+ * its way out: it is registered before its pages are added, and until they
+ * have been removed.
+ */
+bool pfn_has_dev_pagemap(unsigned long pfn)
+{
+	return xa_load(&pgmap_array, pfn);
+}
+
 void free_zone_device_folio(struct folio *folio)
 {
 	struct dev_pagemap *pgmap = folio->pgmap;

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 33/46] mm/madvise: fix data loss from MADV_FREE on a KSM page
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (31 preceding siblings ...)
  2026-10-26 23:17 ` [PATCH 32/46] mm/memory_hotplug: avoid races in pfn_to_online_page() with dying pgmap David Hildenbrand (Arm)
@ 2026-10-26 23:17 ` David Hildenbrand (Arm)
  2026-10-26 23:17 ` [PATCH 34/46] mm/memory: reject remote COW faults on PFN mappings David Hildenbrand (Arm)
                   ` (12 subsequent siblings)
  45 siblings, 0 replies; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:17 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, stable, Josef Bacik, David Hildenbrand (Arm)

MADV_FREE can clear the dirty flag of a singly mapped KSM folio. The
folio remains in the stable tree and can gain new mappings without being
dirtied again. Once marked lazyfree, reclaim can discard data that those
mappings still need.

KSM always marks a folio dirty when converting it to a KSM folio in
try_to_merge_one_page(). Marking a folio lazyfree clears PG_swapbacked
but leaves PG_dirty unchanged. Preserving PG_dirty makes reclaim restore
PG_swapbacked instead of discarding the folio. This also protects folios
that were already lazyfree when KSM converted them.

Skip KSM folios before clearing their dirty flag, checking under the
folio lock to serialize with KSM conversion.

Fixes: 854e9ed09ded ("mm: support madvise(MADV_FREE)")
Cc: stable@vger.kernel.org
Reported-by: Josef Bacik <josef@toxicpanda.com>
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 mm/madvise.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/mm/madvise.c b/mm/madvise.c
index 75b409e97dbf2..a16e3cb256b7b 100644
--- a/mm/madvise.c
+++ b/mm/madvise.c
@@ -756,6 +756,15 @@ static int madvise_free_pte_range(pmd_t *pmd, unsigned long addr,
 		if (folio_test_swapcache(folio) || folio_test_dirty(folio)) {
 			if (!folio_trylock(folio))
 				continue;
+			/*
+			 * KSM folios can gain new mappings at any time, so we must
+			 * not clear their dirty flag.
+			 */
+			if (folio_test_ksm(folio)) {
+				folio_unlock(folio);
+				continue;
+			}
+
 			/*
 			 * If we have a large folio at this point, we know it is
 			 * fully mapped so if its mapcount is the same as its

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 34/46] mm/memory: reject remote COW faults on PFN mappings
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (32 preceding siblings ...)
  2026-10-26 23:17 ` [PATCH 33/46] mm/madvise: fix data loss from MADV_FREE on a KSM page David Hildenbrand (Arm)
@ 2026-10-26 23:17 ` David Hildenbrand (Arm)
  2026-10-26 23:17 ` [PATCH 35/46] mm: fix unmap_mapping_range() beyond 4 GiB on 32-bit David Hildenbrand (Arm)
                   ` (11 subsequent siblings)
  45 siblings, 0 replies; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:17 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, Chris Mason, stable, David Hildenbrand (Arm)

From: Chris Mason <mason@kernel.org>

When handling a COW fault without a normal source page (PFN mappings),
__wp_page_copy_user() copies from the faulting user address. For remote
faults, this accesses the wrong address space, resulting in wrong data
getting copied.

For example, user_events updates an enable bit in the registering
process's memory. If that memory needs to be faulted in,
user_event_enabler_fault_fixup() calls fixup_user_fault() from a work
item. Placing the enable bit in a private PFN mapping can trigger this
remote COW path.

Reject these faults with VM_FAULT_SIGBUS when the target mm differs from
current->mm: remote faults. Ordinary (non-PFN) mappings are not affected.

The user-address copy dates back to commit 6aab341e0a28 ("mm: re-architect
the VM_UNPAGED logic"); likely, actual ways to get remote faults in
there on COW PFN mappings appeared afterwards. But the fix is simple and
straight forward.

Fix generated by an LLM and sent by Chris Mason in private.

Fixes: 6aab341e0a28 ("mm: re-architect the VM_UNPAGED logic")
Cc: stable@vger.kernel.org
Signed-off-by: Chris Mason <mason@kernel.org>
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
[ david: simplify comment and description ]
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 mm/memory.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/mm/memory.c b/mm/memory.c
index 0f4db5080e371..ec7a1397ab833 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -3761,6 +3761,13 @@ static inline int __wp_page_copy_user(struct page *dst, struct page *src,
 		return 0;
 	}
 
+	/*
+	 * __copy_from_user_inatomic() only works as expected for local faults.
+	 * Reject remote faults.
+	 */
+	if (unlikely(mm != current->mm))
+		return -EFAULT;
+
 	/*
 	 * If the source page was a PFN mapping, we don't have
 	 * a "struct page" for it. We do a best-effort copy by
@@ -4086,6 +4093,8 @@ static vm_fault_t wp_page_copy(struct vm_fault *vmf)
 				folio_put(old_folio);
 
 			delayacct_wpcopy_end();
+			if (err == -EFAULT)
+				return VM_FAULT_SIGBUS;
 			return err == -EHWPOISON ? VM_FAULT_HWPOISON : 0;
 		}
 		kmsan_copy_page_meta(&new_folio->page, vmf->page);

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 35/46] mm: fix unmap_mapping_range() beyond 4 GiB on 32-bit
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (33 preceding siblings ...)
  2026-10-26 23:17 ` [PATCH 34/46] mm/memory: reject remote COW faults on PFN mappings David Hildenbrand (Arm)
@ 2026-10-26 23:17 ` David Hildenbrand (Arm)
  2026-10-26 23:17 ` [PATCH 36/46] mm: fix unkillable fault loop on MAP_DROPPABLE memory David Hildenbrand (Arm)
                   ` (10 subsequent siblings)
  45 siblings, 0 replies; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:17 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, Josef Bacik, stable, David Hildenbrand (Arm)

From: Josef Bacik <josef@toxicpanda.com>

Commit 9eab0421fa94 ("mm: fix unmap_mapping_range high bits shift bug")
made holebegin and holelen unsigned before they are shifted, by casting
them to pgoff_t. That is an unsigned long: on a 32-bit kernel the cast
cuts off the upper half of the two loff_t values, so a hole which begins
at 4 GiB or beyond is taken for one in the first 4 GiB of the file.

truncate_pagecache() passes the new size of the file and asks for private
COWed pages to be unmapped as well. If a file of 6 GiB is truncated to
5 GiB, everything from 1 GiB on is unmapped, and what a process has
written to a private mapping of the range between 1 GiB and 5 GiB is
lost: it reads the contents of the file again.

Where the range has an end, the wrong range is unmapped instead of the
right one. The page cache copes with that, as it unmaps every folio that
it removes. The callers which only have unmap_mapping_range() to get
rid of user mappings do not, for example drm_vma_node_unmap(), whose fake
offsets reach beyond 4 GiB on 32-bit, and revoke_iomem() with physical
addresses of more than 32 bits.

Cast to u64 instead. Nothing changes for 64-bit kernels.

Fix generated by an LLM and sent by Josef Bacik in private.

Fixes: 9eab0421fa94 ("mm: fix unmap_mapping_range high bits shift bug")
Cc: stable@vger.kernel.org
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 mm/memory.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/mm/memory.c b/mm/memory.c
index ec7a1397ab833..5c5f326b8bcbe 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -4649,8 +4649,8 @@ EXPORT_SYMBOL_GPL(unmap_mapping_pages);
 void unmap_mapping_range(struct address_space *mapping,
 		loff_t const holebegin, loff_t const holelen, int even_cows)
 {
-	pgoff_t hba = (pgoff_t)(holebegin) >> PAGE_SHIFT;
-	pgoff_t hlen = ((pgoff_t)(holelen) + PAGE_SIZE - 1) >> PAGE_SHIFT;
+	pgoff_t hba = (u64)holebegin >> PAGE_SHIFT;
+	pgoff_t hlen = ((u64)holelen + PAGE_SIZE - 1) >> PAGE_SHIFT;
 
 	/* Check for overflow. */
 	if (sizeof(holelen) > sizeof(hlen)) {

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 36/46] mm: fix unkillable fault loop on MAP_DROPPABLE memory
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (34 preceding siblings ...)
  2026-10-26 23:17 ` [PATCH 35/46] mm: fix unmap_mapping_range() beyond 4 GiB on 32-bit David Hildenbrand (Arm)
@ 2026-10-26 23:17 ` David Hildenbrand (Arm)
  2026-10-26 23:17 ` [PATCH 37/46] mm: fix deadlock of mremap() against UFFDIO_MOVE David Hildenbrand (Arm)
                   ` (9 subsequent siblings)
  45 siblings, 0 replies; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:17 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, Chris Mason, stable, David Hildenbrand (Arm)

From: Chris Mason <mason@kernel.org>

handle_mm_fault() suppresses VM_FAULT_OOM for VM_DROPPABLE mappings.

For user-mode faults, pending signals are processed before retrying the
access. Kernel-mode faults on user buffers instead return directly to
the faulting instruction.

With persistent allocation failures (esp. memcg limits), a syscall,
such as write(), can therefore loop while not dropping locks.

Only suppress VM_FAULT_OOM when FAULT_FLAG_USER is set, allowing
kernel-mode faults and GUP to fail and signal allocation errors.

Fix generated by an LLM and sent by Chris Mason in private.

Fixes: 9651fcedf7b9 ("mm: add MAP_DROPPABLE for designating always lazily freeable mappings")
Cc: stable@vger.kernel.org
Signed-off-by: Chris Mason <mason@kernel.org>
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
[ david: simplify description ]
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 mm/memory.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/mm/memory.c b/mm/memory.c
index 5c5f326b8bcbe..230a2f4dafa13 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -6957,8 +6957,12 @@ vm_fault_t handle_mm_fault(struct vm_area_struct *vma, unsigned long address,
 
 	lru_gen_exit_fault();
 
-	/* If the mapping is droppable, then errors due to OOM aren't fatal. */
-	if (is_droppable)
+	/*
+	 * If the mapping is droppable, then errors due to OOM aren't fatal: the
+	 * task returns to user mode, handles its signals and tries again. A
+	 * fault from kernel mode has no such return, so it must see the error.
+	 */
+	if (is_droppable && (flags & FAULT_FLAG_USER))
 		ret &= ~VM_FAULT_OOM;
 
 	if (flags & FAULT_FLAG_USER) {

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 37/46] mm: fix deadlock of mremap() against UFFDIO_MOVE
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (35 preceding siblings ...)
  2026-10-26 23:17 ` [PATCH 36/46] mm: fix unkillable fault loop on MAP_DROPPABLE memory David Hildenbrand (Arm)
@ 2026-10-26 23:17 ` David Hildenbrand (Arm)
  2026-10-27  9:23   ` Lorenzo Stoakes (ARM)
  2026-10-27  9:46   ` Muchun Song
  2026-10-26 23:17 ` [PATCH 38/46] mm/ksm: reset the unstable trees of all nodes David Hildenbrand (Arm)
                   ` (8 subsequent siblings)
  45 siblings, 2 replies; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:17 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, Chris Mason, stable, David Hildenbrand (Arm)

From: Chris Mason <mason@kernel.org>

With per-VMA locks, UFFDIO_MOVE can run concurrently with mremap()
on different VMAs in the same mm. Those VMAs can share page tables, so
both operations can acquire the same pair of page-table locks.

UFFDIO_MOVE orders the locks by address, while mremap() takes the source
lock first. These conflicting orders can deadlock; mremap() holding
mmap_lock for writing no longer helps.

Move double_pt_lock() and double_pt_unlock() to mm/internal.h and use
them for all page-table moves in mremap(). Preserve the source entry
checks after acquiring both locks. Remove the comments claiming that
exclusive mmap_lock makes lock ordering irrelevant.

In move_ptes(), make sure to just recheck source and destination PMD
after taking the locks and drop the overly-long comment.

Fix generated by an LLM and sent by Chris Mason in private.

Fixes: 867a43a34ff8 ("userfaultfd: use per-vma locks in userfaultfd operations")
Cc: stable@vger.kernel.org
Signed-off-by: Chris Mason <mason@kernel.org>
[ david: use new helpers consistently; simplify description and comments;
         move_ptes() fixup ]
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 include/linux/userfaultfd_k.h |  2 -
 mm/huge_memory.c              | 19 ++++------
 mm/hugetlb.c                  | 14 ++-----
 mm/internal.h                 | 28 ++++++++++++++
 mm/mremap.c                   | 87 +++++++++++++++++--------------------------
 mm/userfaultfd.c              | 27 --------------
 6 files changed, 72 insertions(+), 105 deletions(-)

diff --git a/include/linux/userfaultfd_k.h b/include/linux/userfaultfd_k.h
index a14b8a9ffb7b1..565e98f342dc8 100644
--- a/include/linux/userfaultfd_k.h
+++ b/include/linux/userfaultfd_k.h
@@ -153,8 +153,6 @@ extern int mrwprotect_range(struct userfaultfd_ctx *ctx, unsigned long start,
 			    unsigned long len, bool enable_rwp);
 
 /* move_pages */
-void double_pt_lock(spinlock_t *ptl1, spinlock_t *ptl2);
-void double_pt_unlock(spinlock_t *ptl1, spinlock_t *ptl2);
 int move_pages_huge_pmd(struct mm_struct *mm, pmd_t *dst_pmd, pmd_t *src_pmd, pmd_t dst_pmdval,
 			struct vm_area_struct *dst_vma,
 			struct vm_area_struct *src_vma,
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 1b50cc2b35351..08e58cda7d37d 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -2645,15 +2645,11 @@ bool move_huge_pmd(struct vm_area_struct *vma, unsigned long old_addr,
 		return false;
 	}
 
-	/*
-	 * We don't have to worry about the ordering of src and dst
-	 * ptlocks because exclusive mmap_lock prevents deadlock.
-	 */
-	old_ptl = __pmd_trans_huge_lock(old_pmd, vma);
-	if (old_ptl) {
-		new_ptl = pmd_lockptr(mm, new_pmd);
-		if (new_ptl != old_ptl)
-			spin_lock_nested(new_ptl, SINGLE_DEPTH_NESTING);
+	old_ptl = pmd_lockptr(mm, old_pmd);
+	new_ptl = pmd_lockptr(mm, new_pmd);
+
+	double_pt_lock(old_ptl, new_ptl);
+	if (likely(pmd_is_huge(*old_pmd))) {
 		pmd = pmdp_huge_get_and_clear(mm, old_addr, old_pmd);
 		if (pmd_present(pmd))
 			force_flush = true;
@@ -2682,11 +2678,10 @@ bool move_huge_pmd(struct vm_area_struct *vma, unsigned long old_addr,
 		set_pmd_at(mm, new_addr, new_pmd, pmd);
 		if (force_flush)
 			flush_pmd_tlb_range(vma, old_addr, old_addr + PMD_SIZE);
-		if (new_ptl != old_ptl)
-			spin_unlock(new_ptl);
-		spin_unlock(old_ptl);
+		double_pt_unlock(old_ptl, new_ptl);
 		return true;
 	}
+	double_pt_unlock(old_ptl, new_ptl);
 	return false;
 }
 
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index da5d04edf7c10..84141527fe73d 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -5153,15 +5153,9 @@ static void move_huge_pte(struct vm_area_struct *vma, unsigned long old_addr,
 	spinlock_t *src_ptl, *dst_ptl;
 	pte_t pte;
 
-	dst_ptl = huge_pte_lock(h, mm, dst_pte);
+	dst_ptl = huge_pte_lockptr(h, mm, dst_pte);
 	src_ptl = huge_pte_lockptr(h, mm, src_pte);
-
-	/*
-	 * We don't have to worry about the ordering of src and dst ptlocks
-	 * because exclusive mmap_lock (or the i_mmap_lock) prevents deadlock.
-	 */
-	if (src_ptl != dst_ptl)
-		spin_lock_nested(src_ptl, SINGLE_DEPTH_NESTING);
+	double_pt_lock(dst_ptl, src_ptl);
 
 	pte = huge_ptep_get_and_clear(mm, old_addr, src_pte, sz);
 
@@ -5190,9 +5184,7 @@ static void move_huge_pte(struct vm_area_struct *vma, unsigned long old_addr,
 		set_huge_pte_at(mm, new_addr, dst_pte, pte, sz);
 	}
 
-	if (src_ptl != dst_ptl)
-		spin_unlock(src_ptl);
-	spin_unlock(dst_ptl);
+	double_pt_unlock(dst_ptl, src_ptl);
 }
 
 int move_hugetlb_page_tables(struct vm_area_struct *vma,
diff --git a/mm/internal.h b/mm/internal.h
index b1b0f29d2216e..7e4d88b2fb02c 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -619,6 +619,34 @@ static inline void force_page_cache_readahead(struct address_space *mapping,
 	force_page_cache_ra(&ractl, nr_to_read);
 }
 
+/*
+ * Take two page table locks at the same level in address order such that
+ * we cannot deadlock.
+ */
+static inline void double_pt_lock(spinlock_t *ptl1, spinlock_t *ptl2)
+	__acquires(ptl1)
+	__acquires(ptl2)
+{
+	if (ptl1 > ptl2)
+		swap(ptl1, ptl2);
+	spin_lock(ptl1);
+	if (ptl1 != ptl2)
+		spin_lock_nested(ptl2, SINGLE_DEPTH_NESTING);
+	else
+		__acquire(ptl2);
+}
+
+static inline void double_pt_unlock(spinlock_t *ptl1, spinlock_t *ptl2)
+	__releases(ptl1)
+	__releases(ptl2)
+{
+	spin_unlock(ptl1);
+	if (ptl1 != ptl2)
+		spin_unlock(ptl2);
+	else
+		__release(ptl2);
+}
+
 unsigned find_lock_entries(struct address_space *mapping, pgoff_t *start,
 		pgoff_t end, struct folio_batch *fbatch, pgoff_t *indices);
 unsigned find_get_entries(struct address_space *mapping, pgoff_t *start,
diff --git a/mm/mremap.c b/mm/mremap.c
index 1237718848f5c..70b7264aa6bf5 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -202,7 +202,7 @@ static int move_ptes(struct pagetable_move_control *pmc,
 	struct mm_struct *mm = vma->vm_mm;
 	pte_t *old_ptep, *new_ptep;
 	pte_t old_pte, pte;
-	pmd_t dummy_pmdval;
+	pmd_t old_pmdval, new_pmdval;
 	spinlock_t *old_ptl, *new_ptl;
 	bool force_flush = false;
 	unsigned long old_addr = pmc->old_addr;
@@ -234,31 +234,30 @@ static int move_ptes(struct pagetable_move_control *pmc,
 	if (pmc->need_rmap_locks)
 		take_rmap_locks(vma);
 
-	/*
-	 * We don't have to worry about the ordering of src and dst
-	 * pte locks because exclusive mmap_lock prevents deadlock.
-	 */
-	old_ptep = pte_offset_map_lock(mm, old_pmd, old_addr, &old_ptl);
+	old_ptep = pte_offset_map_rw_nolock(mm, old_pmd, old_addr, &old_pmdval,
+					    &old_ptl);
 	if (!old_ptep) {
 		err = -EAGAIN;
 		goto out;
 	}
-	/*
-	 * Now new_pte is none, so collapse_scan_file() path can not find
-	 * this by traversing file->f_mapping, so there is no concurrency with
-	 * retract_page_tables(). In addition, we already hold the exclusive
-	 * mmap_lock, so this new_pte page is stable, so there is no need to get
-	 * pmdval and do pmd_same() check.
-	 */
-	new_ptep = pte_offset_map_rw_nolock(mm, new_pmd, new_addr, &dummy_pmdval,
-					   &new_ptl);
+	new_ptep = pte_offset_map_rw_nolock(mm, new_pmd, new_addr, &new_pmdval,
+					    &new_ptl);
 	if (!new_ptep) {
-		pte_unmap_unlock(old_ptep, old_ptl);
+		pte_unmap(old_ptep);
+		err = -EAGAIN;
+		goto out;
+	}
+
+	double_pt_lock(old_ptl, new_ptl);
+	if (unlikely(!pmd_same(old_pmdval, pmdp_get_lockless(old_pmd)) ||
+		     !pmd_same(new_pmdval, pmdp_get_lockless(new_pmd)))) {
+		double_pt_unlock(old_ptl, new_ptl);
+		pte_unmap(new_ptep);
+		pte_unmap(old_ptep);
 		err = -EAGAIN;
 		goto out;
 	}
-	if (new_ptl != old_ptl)
-		spin_lock_nested(new_ptl, SINGLE_DEPTH_NESTING);
+
 	flush_tlb_batched_pending(vma->vm_mm);
 	lazy_mmu_mode_enable();
 
@@ -317,10 +316,9 @@ static int move_ptes(struct pagetable_move_control *pmc,
 	lazy_mmu_mode_disable();
 	if (force_flush)
 		flush_tlb_range(vma, old_end - len, old_end);
-	if (new_ptl != old_ptl)
-		spin_unlock(new_ptl);
+	double_pt_unlock(old_ptl, new_ptl);
 	pte_unmap(new_ptep - 1);
-	pte_unmap_unlock(old_ptep - 1, old_ptl);
+	pte_unmap(old_ptep - 1);
 out:
 	if (pmc->need_rmap_locks)
 		drop_rmap_locks(vma);
@@ -395,14 +393,9 @@ static bool move_normal_pmd(struct pagetable_move_control *pmc,
 	if (WARN_ON_ONCE(!pmd_none(*new_pmd)))
 		return false;
 
-	/*
-	 * We don't have to worry about the ordering of src and dst
-	 * ptlocks because exclusive mmap_lock prevents deadlock.
-	 */
-	old_ptl = pmd_lock(mm, old_pmd);
+	old_ptl = pmd_lockptr(mm, old_pmd);
 	new_ptl = pmd_lockptr(mm, new_pmd);
-	if (new_ptl != old_ptl)
-		spin_lock_nested(new_ptl, SINGLE_DEPTH_NESTING);
+	double_pt_lock(old_ptl, new_ptl);
 
 	pmd = *old_pmd;
 
@@ -418,9 +411,7 @@ static bool move_normal_pmd(struct pagetable_move_control *pmc,
 	pmd_populate(mm, new_pmd, pmd_pgtable(pmd));
 	flush_tlb_range(vma, pmc->old_addr, pmc->old_addr + PMD_SIZE);
 out_unlock:
-	if (new_ptl != old_ptl)
-		spin_unlock(new_ptl);
-	spin_unlock(old_ptl);
+	double_pt_unlock(old_ptl, new_ptl);
 
 	return res;
 }
@@ -452,14 +443,10 @@ static bool move_normal_pud(struct pagetable_move_control *pmc,
 	if (WARN_ON_ONCE(!pud_none(*new_pud)))
 		return false;
 
-	/*
-	 * We don't have to worry about the ordering of src and dst
-	 * ptlocks because exclusive mmap_lock prevents deadlock.
-	 */
-	old_ptl = pud_lock(mm, old_pud);
+	old_ptl = pud_lockptr(mm, old_pud);
 	new_ptl = pud_lockptr(mm, new_pud);
-	if (new_ptl != old_ptl)
-		spin_lock_nested(new_ptl, SINGLE_DEPTH_NESTING);
+
+	double_pt_lock(old_ptl, new_ptl);
 
 	pud = *old_pud;
 	if (unlikely(pud_none(pud)))
@@ -473,9 +460,7 @@ static bool move_normal_pud(struct pagetable_move_control *pmc,
 	pud_populate(mm, new_pud, pud_pgtable(pud));
 	flush_tlb_range(vma, pmc->old_addr, pmc->old_addr + PUD_SIZE);
 out_unlock:
-	if (new_ptl != old_ptl)
-		spin_unlock(new_ptl);
-	spin_unlock(old_ptl);
+	double_pt_unlock(old_ptl, new_ptl);
 
 	return true;
 }
@@ -503,16 +488,14 @@ static bool move_huge_pud(struct pagetable_move_control *pmc,
 	if (WARN_ON_ONCE(!pud_none(*new_pud)))
 		return false;
 
-	/*
-	 * We don't have to worry about the ordering of src and dst
-	 * ptlocks because exclusive mmap_lock prevents deadlock.
-	 */
-	old_ptl = __pud_trans_huge_lock(old_pud, vma);
-	if (unlikely(!old_ptl))
-		return false;
+	old_ptl = pud_lockptr(mm, old_pud);
 	new_ptl = pud_lockptr(mm, new_pud);
-	if (new_ptl != old_ptl)
-		spin_lock_nested(new_ptl, SINGLE_DEPTH_NESTING);
+
+	double_pt_lock(old_ptl, new_ptl);
+	if (unlikely(!pud_trans_huge(*old_pud))) {
+		double_pt_unlock(old_ptl, new_ptl);
+		return false;
+	}
 
 	/* Clear the pud */
 	pud = pudp_huge_get_and_clear(mm, pmc->old_addr, old_pud);
@@ -523,9 +506,7 @@ static bool move_huge_pud(struct pagetable_move_control *pmc,
 	/* mark soft_ditry when we add pud level soft dirty support */
 	set_pud_at(mm, pmc->new_addr, new_pud, pud);
 	flush_pud_tlb_range(vma, pmc->old_addr, pmc->old_addr + HPAGE_PUD_SIZE);
-	if (new_ptl != old_ptl)
-		spin_unlock(new_ptl);
-	spin_unlock(old_ptl);
+	double_pt_unlock(old_ptl, new_ptl);
 
 	return true;
 }
diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
index 710e913c73bfa..76de84510340c 100644
--- a/mm/userfaultfd.c
+++ b/mm/userfaultfd.c
@@ -1206,33 +1206,6 @@ int mrwprotect_range(struct userfaultfd_ctx *ctx, unsigned long start,
 	return 0;
 }
 
-void double_pt_lock(spinlock_t *ptl1,
-		    spinlock_t *ptl2)
-	__acquires(ptl1)
-	__acquires(ptl2)
-{
-	if (ptl1 > ptl2)
-		swap(ptl1, ptl2);
-	/* lock in virtual address order to avoid lock inversion */
-	spin_lock(ptl1);
-	if (ptl1 != ptl2)
-		spin_lock_nested(ptl2, SINGLE_DEPTH_NESTING);
-	else
-		__acquire(ptl2);
-}
-
-void double_pt_unlock(spinlock_t *ptl1,
-		      spinlock_t *ptl2)
-	__releases(ptl1)
-	__releases(ptl2)
-{
-	spin_unlock(ptl1);
-	if (ptl1 != ptl2)
-		spin_unlock(ptl2);
-	else
-		__release(ptl2);
-}
-
 static inline bool is_pte_pages_stable(pte_t *dst_pte, pte_t *src_pte,
 				       pte_t orig_dst_pte, pte_t orig_src_pte,
 				       pmd_t *dst_pmd, pmd_t dst_pmdval)

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 38/46] mm/ksm: reset the unstable trees of all nodes
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (36 preceding siblings ...)
  2026-10-26 23:17 ` [PATCH 37/46] mm: fix deadlock of mremap() against UFFDIO_MOVE David Hildenbrand (Arm)
@ 2026-10-26 23:17 ` David Hildenbrand (Arm)
  2026-10-27  9:14   ` Lorenzo Stoakes (ARM)
  2026-10-26 23:17 ` [PATCH 39/46] mm/ksm: fix use of a freed anon_vma at swap-in David Hildenbrand (Arm)
                   ` (7 subsequent siblings)
  45 siblings, 1 reply; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:17 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, stable, Josef Bacik, David Hildenbrand (Arm)

Each full scan resets ksm_nr_node_ids unstable tree roots. Enabling
merge_across_nodes resets this count to 1, even if per-node roots were
previously allocated.

So when toggling "merge_across_nodes" 0 -> 1 -> 0, a scan that starts
while the setting is 1 and continues after switching back to 0 can
encounter stale unstable tree roots, resulting in UAF.

Only root is allowed to change "merge_across_nodes", and the documented
sequence is: "merge_across_nodes setting can be changed only when there
are no ksm shared pages in the system: set run 2 to unmerge pages first,
then to 1 after changing merge_across_nodes, to remerge according to the
new setting."

Let's fix it by tracking in ksm_nr_node_ids the actual number of
allocated tree roots.

remove_all_stable_nodes() and ksm_check_stable_tree() will now scan
more tree roots (skipping the empty ones), which is harmless.

Fixes: ef53d16cded7 ("ksm: allocate roots when needed")
Cc: stable@vger.kernel.org
Reported-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 mm/ksm.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/mm/ksm.c b/mm/ksm.c
index dbfb8f98b1892..9c51925825cbf 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -475,6 +475,7 @@ static void advisor_stop_scan(void)
 #ifdef CONFIG_NUMA
 /* Zeroed when merging across nodes is not allowed */
 static unsigned int ksm_merge_across_nodes = 1;
+/* Number of allocated stable and unstable tree roots. */
 static int ksm_nr_node_ids = 1;
 #else
 #define ksm_merge_across_nodes	1U
@@ -3636,14 +3637,13 @@ static ssize_t merge_across_nodes_store(struct kobject *kobj,
 			else {
 				root_stable_tree = buf;
 				root_unstable_tree = buf + nr_node_ids;
+				ksm_nr_node_ids = nr_node_ids;
 				/* Stable tree is empty but not the unstable */
 				root_unstable_tree[0] = one_unstable_tree[0];
 			}
 		}
-		if (!err) {
+		if (!err)
 			ksm_merge_across_nodes = knob;
-			ksm_nr_node_ids = knob ? 1 : nr_node_ids;
-		}
 	}
 	mutex_unlock(&ksm_thread_mutex);
 

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 39/46] mm/ksm: fix use of a freed anon_vma at swap-in
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (37 preceding siblings ...)
  2026-10-26 23:17 ` [PATCH 38/46] mm/ksm: reset the unstable trees of all nodes David Hildenbrand (Arm)
@ 2026-10-26 23:17 ` David Hildenbrand (Arm)
  2026-10-26 23:18 ` [PATCH 40/46] mm/ksm: check large swap-cache folios before mapping them David Hildenbrand (Arm)
                   ` (6 subsequent siblings)
  45 siblings, 0 replies; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:17 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, stable, Chris Mason, David Hildenbrand (Arm)

A folio read from a swap slot previously shared by KSM can remain in the
swap cache after the process that first mapped it exits. Its anon_vma
can then be freed, so ksm_might_need_to_copy() must not dereference it
to compare roots.

Doing so can result in some false-positives, resulting in the reverse
mapping missing the new folio mapping, preventing migration and reclaim.

SLAB_TYPESAFE_BY_RCU allows individual anon_vma objects to be reused
immediately after freeing. A stale pointer can then refer to another
anon_vma whose root matches, even though the target VMA is not linked
to that anon_vma.

Move the anonymous rmap compatibility checks into
folio_anon_rmap_compatible(). Keep the page-index check and compare the
folio's anon_vma pointer against the VMA's own anon_vma and root first.

If neither matches, bite the bullet and walk the VMA's anon_vma_chain.
The VMA keeps these anon_vmas alive, and finding a match guarantees that
reverse mapping can find the new mapping.

Lorenzo Stoakes says in a private discussion:

  "This isn't quite equivalent to the existing check.

  Every anon_vma in an anon_vma_chain shares the same root, but if you
  split a VMA then fork both of them like this:

                  VMA A
               /        \         <split>
            VMA B      VMA C
               \        /
        root <- anon_vma 1
               ----^ ^----        <fork>
              /   parent  \
        anon_vma 2   anon_vma 3
             |            |
           VMA D        VMA E

  VMA's D and E both get their own new
  anon_vma's such that:

  VMA D: anon_vma 2 -> anon_vma 1 -> root
  VMA E: anon_vma 3 -> anon_vma 1 -> root

  And if you found a folio referencing anon_vma 2, the existing check:

	anon_vma->root == vma->anon-vma->root

  Would be true for VMA's B, C, D & E.

  However after your change it'd be true for VMA D only, as it's the only
  one with anon_vma 2 in its anon_vma_chain.

  Whether or not that could actually happen in practice... 🙂 I don't
  know.

  [...] after your change it'd be true for VMA D only, as it's the only
  one with anon_vma 2 in its anon_vma_chain. [...] I would [...] say that
  you are making the test stricter but more correct.
"

If this affects performance when KSM was never even involved, we could
just track whether KSM ever merged anything and just skip these checks.

There isn't really a lot we can do otherwise: for mapped folios we might
be able to use folio_get_anon_vma(), but for unmapped folios there really
is no easy way to see if the anon_vma is still valid.

Document the (confusing) lifetime requirements of folio_anon_vma().

Fixes: ba6f0ff3981e ("ksm: fix ksm swapin time optimization")
Cc: stable@vger.kernel.org
Reported-by: Chris Mason <mason@kernel.org>
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 mm/ksm.c  | 36 +++++++++++++++++++++++++++++++-----
 mm/util.c | 13 +++++++++++++
 2 files changed, 44 insertions(+), 5 deletions(-)

diff --git a/mm/ksm.c b/mm/ksm.c
index 9c51925825cbf..e050b1bdf810d 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -3137,11 +3137,40 @@ void __ksm_exit(struct mm_struct *mm)
 	trace_ksm_exit(mm);
 }
 
+static bool folio_anon_rmap_compatible(const struct folio *folio,
+		struct vm_area_struct *vma, unsigned long addr)
+{
+	const struct anon_vma *anon_vma = folio_anon_vma(folio);
+	struct anon_vma_chain *avc;
+
+	VM_WARN_ON_ONCE_FOLIO(!folio_test_locked(folio), folio);
+	VM_WARN_ON_ONCE_FOLIO(folio_test_large(folio), folio);
+	VM_WARN_ON_ONCE_FOLIO(folio_test_ksm(folio), folio);
+	vma_assert_stabilised(vma);
+
+	if (!anon_vma)
+		return true;
+	if (folio->index != linear_anon_page_index(vma, addr))
+		return false;
+
+	/*
+	 * Careful: anon_vma might have been freed, so we cannot safely
+	 * dereference it. Add a fast path before we walk the anon_vma chain.
+	 */
+	if (anon_vma == vma->anon_vma || anon_vma == vma->anon_vma->root)
+		return true;
+
+	list_for_each_entry(avc, &vma->anon_vma_chain, same_vma) {
+		if (avc->anon_vma == anon_vma)
+			return true;
+	}
+	return false;
+}
+
 struct folio *ksm_might_need_to_copy(struct folio *folio,
 			struct vm_area_struct *vma, unsigned long addr)
 {
 	struct page *page = folio_page(folio, 0);
-	struct anon_vma *anon_vma = folio_anon_vma(folio);
 	struct folio *new_folio;
 
 	if (folio_test_large(folio))
@@ -3151,10 +3180,7 @@ struct folio *ksm_might_need_to_copy(struct folio *folio,
 		if (folio_stable_node(folio) &&
 		    !(ksm_run & KSM_RUN_UNMERGE))
 			return folio;	/* no need to copy it */
-	} else if (!anon_vma) {
-		return folio;		/* no need to copy it */
-	} else if (folio->index == linear_anon_page_index(vma, addr) &&
-			anon_vma->root == vma->anon_vma->root) {
+	} else if (folio_anon_rmap_compatible(folio, vma, addr)) {
 		return folio;		/* still no need to copy it */
 	}
 	if (PageHWPoison(page))
diff --git a/mm/util.c b/mm/util.c
index 7f374bb8bf363..67f8fca3b2056 100644
--- a/mm/util.c
+++ b/mm/util.c
@@ -697,6 +697,19 @@ void *vcalloc_noprof(size_t n, size_t size)
 }
 EXPORT_SYMBOL(vcalloc_noprof);
 
+/**
+ * folio_anon_vma - Get a folio's raw anon_vma pointer.
+ * @folio: The folio.
+ *
+ * The returned pointer may be stale for an unmapped folio. The caller
+ * must ensure the anon_vma stays alive before dereferencing it. A folio
+ * reference or lock alone is insufficient; use folio_get_anon_vma() when
+ * the anon_vma's lifetime is not otherwise protected. Note that
+ * folio_get_anon_vma() is only useful for folios that are still mapped.
+ *
+ * Return: The raw anon_vma pointer for an anonymous, non-KSM folio, or
+ * %NULL otherwise.
+ */
 struct anon_vma *folio_anon_vma(const struct folio *folio)
 {
 	unsigned long mapping = (unsigned long)folio->mapping;

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 40/46] mm/ksm: check large swap-cache folios before mapping them
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (38 preceding siblings ...)
  2026-10-26 23:17 ` [PATCH 39/46] mm/ksm: fix use of a freed anon_vma at swap-in David Hildenbrand (Arm)
@ 2026-10-26 23:18 ` David Hildenbrand (Arm)
  2026-10-27  9:00   ` Lorenzo Stoakes (ARM)
  2026-10-26 23:18 ` [PATCH 41/46] mm/vma: call ->may_split() before a partial merge David Hildenbrand (Arm)
                   ` (5 subsequent siblings)
  45 siblings, 1 reply; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:18 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, Chris Mason, stable, David Hildenbrand (Arm)

From: Chris Mason <mason@kernel.org>

KSM folios are always small, but their shared swap slots can be read
back as part of a large folio in the swap cache. ksm_might_need_to_copy()
skips large folios, so another process can map a page with an incompatible
anon_vma or page index. Reverse mapping then cannot find the new
mapping, preventing migration or reclaim.

Apply the same compatibility checks to large folios as to small ones.
Pass the page corresponding to the swap entry and copy only that page
when necessary. In do_swap_page()'s copy path, decrement only that slot's
swap count, because the source swap-cache folio can now be large.

Fix generated by an LLM and sent by Chris Mason in private.

Fixes: f1879e8a0c60 ("mm, swap: never bypass the swap cache even for SWP_SYNCHRONOUS_IO")
Cc: stable@vger.kernel.org
Signed-off-by: Chris Mason <mason@kernel.org>
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 include/linux/ksm.h |  6 +++---
 mm/ksm.c            | 22 ++++++++++++----------
 mm/memory.c         |  5 +++--
 mm/swapfile.c       |  3 ++-
 4 files changed, 20 insertions(+), 16 deletions(-)

diff --git a/include/linux/ksm.h b/include/linux/ksm.h
index d39d0d5483a23..a0d358a1feb63 100644
--- a/include/linux/ksm.h
+++ b/include/linux/ksm.h
@@ -91,8 +91,8 @@ static inline void ksm_exit(struct mm_struct *mm)
  * We'd like to make this conditional on vma->vm_flags & VM_MERGEABLE,
  * but what if the vma was unmerged while the page was swapped out?
  */
-struct folio *ksm_might_need_to_copy(struct folio *folio,
-			struct vm_area_struct *vma, unsigned long addr);
+struct folio *ksm_might_need_to_copy(struct folio *folio, struct page *page,
+		struct vm_area_struct *vma, unsigned long addr);
 
 void rmap_walk_ksm(struct folio *folio, struct rmap_walk_control *rwc);
 void folio_migrate_ksm(struct folio *newfolio, struct folio *folio);
@@ -145,7 +145,7 @@ static inline int ksm_madvise(struct vm_area_struct *vma, unsigned long start,
 }
 
 static inline struct folio *ksm_might_need_to_copy(struct folio *folio,
-			struct vm_area_struct *vma, unsigned long addr)
+		struct page *page, struct vm_area_struct *vma, unsigned long addr)
 {
 	return folio;
 }
diff --git a/mm/ksm.c b/mm/ksm.c
index e050b1bdf810d..e95f6b6723602 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -3138,19 +3138,20 @@ void __ksm_exit(struct mm_struct *mm)
 }
 
 static bool folio_anon_rmap_compatible(const struct folio *folio,
-		struct vm_area_struct *vma, unsigned long addr)
+		const struct page *page, struct vm_area_struct *vma,
+		unsigned long addr)
 {
 	const struct anon_vma *anon_vma = folio_anon_vma(folio);
 	struct anon_vma_chain *avc;
 
 	VM_WARN_ON_ONCE_FOLIO(!folio_test_locked(folio), folio);
-	VM_WARN_ON_ONCE_FOLIO(folio_test_large(folio), folio);
+	VM_WARN_ON_ONCE_FOLIO(page_folio(page) != folio, folio);
 	VM_WARN_ON_ONCE_FOLIO(folio_test_ksm(folio), folio);
 	vma_assert_stabilised(vma);
 
 	if (!anon_vma)
 		return true;
-	if (folio->index != linear_anon_page_index(vma, addr))
+	if (page_pgoff(folio, page) != linear_anon_page_index(vma, addr))
 		return false;
 
 	/*
@@ -3167,20 +3168,21 @@ static bool folio_anon_rmap_compatible(const struct folio *folio,
 	return false;
 }
 
-struct folio *ksm_might_need_to_copy(struct folio *folio,
-			struct vm_area_struct *vma, unsigned long addr)
+struct folio *ksm_might_need_to_copy(struct folio *folio, struct page *page,
+		struct vm_area_struct *vma, unsigned long addr)
 {
-	struct page *page = folio_page(folio, 0);
 	struct folio *new_folio;
 
-	if (folio_test_large(folio))
-		return folio;
-
+	/*
+	 * A KSM folio is small, but the slot that it left behind can be swapped
+	 * in as a part of a large folio by one of the processes that shared it.
+	 * So test, and copy, the page of the slot.
+	 */
 	if (folio_test_ksm(folio)) {
 		if (folio_stable_node(folio) &&
 		    !(ksm_run & KSM_RUN_UNMERGE))
 			return folio;	/* no need to copy it */
-	} else if (folio_anon_rmap_compatible(folio, vma, addr)) {
+	} else if (folio_anon_rmap_compatible(folio, page, vma, addr)) {
 		return folio;		/* still no need to copy it */
 	}
 	if (PageHWPoison(page))
diff --git a/mm/memory.c b/mm/memory.c
index 230a2f4dafa13..be4c05db37d33 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -5096,7 +5096,7 @@ vm_fault_t do_swap_page(struct vm_fault *vmf)
 	 * folio->index of non-ksm folios would be nonlinear inside the
 	 * anon VMA -- the ksm flag is lost on actual swapout.
 	 */
-	folio = ksm_might_need_to_copy(folio, vma, vmf->address);
+	folio = ksm_might_need_to_copy(folio, page, vma, vmf->address);
 	if (unlikely(!folio)) {
 		ret = VM_FAULT_OOM;
 		folio = swapcache;
@@ -5278,7 +5278,8 @@ vm_fault_t do_swap_page(struct vm_fault *vmf)
 	if (unlikely(folio != swapcache)) {
 		folio_add_new_anon_rmap(folio, vma, address, RMAP_EXCLUSIVE);
 		folio_add_lru_vma(folio, vma);
-		folio_put_swap(swapcache, NULL);
+		folio_put_swap(swapcache,
+			       folio_file_page(swapcache, swp_offset(entry)));
 	} else if (!folio_test_anon(folio)) {
 		/*
 		 * We currently only expect !anon folios that are fully
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 254ce86fa923e..71ef9e2efb3a9 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -2514,7 +2514,8 @@ static int unuse_pte(struct vm_area_struct *vma, pmd_t *pmd,
 		return 0;
 
 	swapcache = folio;
-	folio = ksm_might_need_to_copy(folio, vma, addr);
+	folio = ksm_might_need_to_copy(folio,
+				       folio_file_page(folio, swp_offset(entry)), vma, addr);
 	if (unlikely(!folio))
 		return -ENOMEM;
 	else if (unlikely(folio == ERR_PTR(-EHWPOISON))) {

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 41/46] mm/vma: call ->may_split() before a partial merge
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (39 preceding siblings ...)
  2026-10-26 23:18 ` [PATCH 40/46] mm/ksm: check large swap-cache folios before mapping them David Hildenbrand (Arm)
@ 2026-10-26 23:18 ` David Hildenbrand (Arm)
  2026-10-27  3:45   ` Gregory Price
  2026-10-26 23:18 ` [PATCH 42/46] mm/huge_memory: split huge PUDs when adjusting VMA boundaries David Hildenbrand (Arm)
                   ` (4 subsequent siblings)
  45 siblings, 1 reply; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:18 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, Chris Mason, stable, David Hildenbrand (Arm)

From: Chris Mason <mason@kernel.org>

A driver can use the ->may_split() hook to forbid a VMA boundary at
certain addresses.

A device-dax device is a character device that gives raw access to a
range of memory through mmap(). device-dax refuses any address that is not
a multiple of the device's alignment through vm_ops->may_split.

vma_merge_existing_range() can move boundaries, but does not call
vm_ops->may_split.

If a range at the edge of a VMA gets the attributes of the adjacent VMA,
the function moves only that range over to the neighbour: one VMA shrinks
and the other grows. This is a partial merge, and vma_modify() tries it
before any split.

Take a device-dax VMA that lies next to another VMA of the same file.
The user calls mprotect() on the one page of the first VMA that touches
the second VMA, and asks for the protection that the second VMA already
has. The result is a partial merge. It puts the boundary inside a 1 GiB
mapping, which is a single leaf entry at the PUD level.

As part of the merge, the kernel looks for a huge PMD to split at the
new boundary. That code does not expect a PUD leaf:

    vma_merge_existing_range()
      commit_merge()
        vma_adjust_trans_huge()
          split_huge_pmd_address()
            mm_find_pmd()
              treats the PUD leaf as a pointer to a PMD table,
              so the "table" is the device memory that the leaf maps
            __split_huge_pmd()
              reads a PMD that the user wrote to the device memory
              folio_put() on the folio that this PMD names

Bad. While the code must at some point be taught to split PUD entries as
well, the issue here is that we move VMA boundaries such that they are
incompatible with the driver.

Fix this by calling ->may_split() on the address that a partial merge
would move the boundary to, and by abandoning the merge if the driver
refuses. vma_modify() then tries the split, which fails with -EINVAL.

Factor out existing split handling into check_split() and reuse it.

Fix generated by an LLM and sent by Chris Mason in private.

Fixes: 38607c62b34b ("fs/dax: properly refcount fs dax pages")
Cc: stable@vger.kernel.org
Signed-off-by: Chris Mason <mason@kernel.org>
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
[ david: improve description; cleanup the code ]
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 mm/vma.c | 21 ++++++++++++++++-----
 1 file changed, 16 insertions(+), 5 deletions(-)

diff --git a/mm/vma.c b/mm/vma.c
index 1be613044b4a5..acdf00346cda5 100644
--- a/mm/vma.c
+++ b/mm/vma.c
@@ -516,6 +516,15 @@ void unmap_region(struct unmap_desc *unmap)
 	tlb_finish_mmu(&tlb);
 }
 
+static int check_split(struct vm_area_struct *vma, unsigned long addr)
+{
+	if (!vma->vm_ops)
+		return 0;
+	if (!vma->vm_ops->may_split)
+		return 0;
+	return vma->vm_ops->may_split(vma, addr);
+}
+
 /*
  * __split_vma() bypasses sysctl_max_map_count checking.  We use this where it
  * has already been checked or doesn't make sense to fail.
@@ -532,11 +541,9 @@ __split_vma(struct vma_iterator *vmi, struct vm_area_struct *vma,
 	WARN_ON(vma->vm_start >= addr);
 	WARN_ON(vma->vm_end <= addr);
 
-	if (vma->vm_ops && vma->vm_ops->may_split) {
-		err = vma->vm_ops->may_split(vma, addr);
-		if (err)
-			return err;
-	}
+	err = check_split(vma, addr);
+	if (err)
+		return err;
 
 	new = vm_area_dup(vma);
 	if (!new)
@@ -948,6 +955,10 @@ static __must_check struct vm_area_struct *vma_merge_existing_range(
 	if (vmg->__remove_middle && !can_merge_remove_vma(middle))
 		return NULL;
 
+	/* If middle isn't removed then it's resized, i.e. splits. */
+	if (!vmg->__remove_middle && check_split(middle, left_side ? end : start))
+		return NULL;
+
 	/*
 	 * If we merge both VMAs, then next is also deleted. This implies
 	 * merge_will_delete_vma also.

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 42/46] mm/huge_memory: split huge PUDs when adjusting VMA boundaries
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (40 preceding siblings ...)
  2026-10-26 23:18 ` [PATCH 41/46] mm/vma: call ->may_split() before a partial merge David Hildenbrand (Arm)
@ 2026-10-26 23:18 ` David Hildenbrand (Arm)
  2026-10-26 23:18 ` [PATCH 43/46] mm/vma: don't leak the charge for stack growth David Hildenbrand (Arm)
                   ` (3 subsequent siblings)
  45 siblings, 0 replies; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:18 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, stable, David Hildenbrand (Arm)

PFN mappings such as VFIO PCI BAR mappings can use PUD leaves while
allowing VMA splits at page granularity. However, vma_adjust_trans_huge()
only handles PMDs.

After faulting a writable PUD-sized VFIO BAR mapping, changing its first
page to read-only with mprotect() makes the PMD walk treat the PUD leaf
as a PMD table. Applying MADV_DONTFORK to the first PMD-sized chunk leaves
the PUD spanning two VMAs: the PMD-aligned boundary skips splitting.

Walk the page tables once at each adjusted boundary and split a huge
PUD or PMD leaf as needed. Handle PUD leaves even when the boundary is
PMD-aligned.

Fixes: f9e54c3a2f5b7 ("vfio/pci: implement huge_fault support")
Cc: stable@vger.kernel.org
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 mm/huge_memory.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 60 insertions(+), 10 deletions(-)

diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 08e58cda7d37d..d090642ac8c2b 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -3503,16 +3503,66 @@ void split_huge_pmd_address(struct vm_area_struct *vma, unsigned long address,
 	__split_huge_pmd(vma, pmd, address, freeze);
 }
 
-static inline void split_huge_pmd_if_needed(struct vm_area_struct *vma, unsigned long address)
+static bool pud_split_required(const struct vm_area_struct *vma,
+		unsigned long address)
 {
+	if (!IS_ENABLED(CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD))
+		return false;
+	if (IS_ALIGNED(address, HPAGE_PUD_SIZE))
+		return false;
 	/*
-	 * If the new address isn't hpage aligned and it could previously
-	 * contain an hugepage: check if we need to split an huge pmd.
+	 * Only selected VMAs support mapping PUDs for now. Lift the
+	 * restriction once this changes.
 	 */
-	if (!IS_ALIGNED(address, HPAGE_PMD_SIZE) &&
-	    range_in_vma(vma, ALIGN_DOWN(address, HPAGE_PMD_SIZE),
-			 ALIGN(address, HPAGE_PMD_SIZE)))
-		split_huge_pmd_address(vma, address, false);
+	if (!vma_is_dax(vma) && !vma_test_any(vma, VMA_PFNMAP_BIT, VMA_MIXEDMAP_BIT))
+		return false;
+	return range_in_vma(vma, ALIGN_DOWN(address, HPAGE_PUD_SIZE),
+			    ALIGN(address, HPAGE_PUD_SIZE));
+}
+
+static bool pmd_split_required(const struct vm_area_struct *vma,
+		unsigned long address)
+{
+	if (IS_ALIGNED(address, HPAGE_PMD_SIZE))
+		return false;
+
+	return range_in_vma(vma, ALIGN_DOWN(address, HPAGE_PMD_SIZE),
+			    ALIGN(address, HPAGE_PMD_SIZE));
+}
+
+static void split_huge_leaf(struct vm_area_struct *vma,
+		unsigned long address)
+{
+	const bool split_pud = pud_split_required(vma, address);
+	const bool split_pmd = pmd_split_required(vma, address);
+	pgd_t *pgd;
+	p4d_t *p4d;
+	pud_t *pud;
+	pmd_t *pmd;
+
+	/*
+	 * mmap, VMA and rmap write locks protect the walk; the split helpers
+	 * take the page table locks.
+	 */
+	if (!split_pud && !split_pmd)
+		return;
+
+	pgd = pgd_offset(vma->vm_mm, address);
+	if (!pgd_present(*pgd))
+		return;
+
+	p4d = p4d_offset(pgd, address);
+	if (!p4d_present(*p4d))
+		return;
+
+	pud = pud_offset(p4d, address);
+	if (split_pud && pud_leaf(*pud))
+		__split_huge_pud(vma, pud, address);
+	if (!split_pmd || !pud_present(*pud))
+		return;
+
+	pmd = pmd_offset(pud, address);
+	__split_huge_pmd(vma, pmd, address, false);
 }
 
 void vma_adjust_trans_huge(struct vm_area_struct *vma,
@@ -3521,14 +3571,14 @@ void vma_adjust_trans_huge(struct vm_area_struct *vma,
 			   struct vm_area_struct *next)
 {
 	/* Check if we need to split start first. */
-	split_huge_pmd_if_needed(vma, start);
+	split_huge_leaf(vma, start);
 
 	/* Check if we need to split end next. */
-	split_huge_pmd_if_needed(vma, end);
+	split_huge_leaf(vma, end);
 
 	/* If we're incrementing next->vm_start, we might need to split it. */
 	if (next)
-		split_huge_pmd_if_needed(next, end);
+		split_huge_leaf(next, end);
 }
 
 /*

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 43/46] mm/vma: don't leak the charge for stack growth
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (41 preceding siblings ...)
  2026-10-26 23:18 ` [PATCH 42/46] mm/huge_memory: split huge PUDs when adjusting VMA boundaries David Hildenbrand (Arm)
@ 2026-10-26 23:18 ` David Hildenbrand (Arm)
  2026-10-26 23:18 ` [PATCH 44/46] mm/cma: don't release CMA pages still in use David Hildenbrand (Arm)
                   ` (2 subsequent siblings)
  45 siblings, 0 replies; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:18 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, stable, Josef Bacik, David Hildenbrand (Arm)

acct_stack_growth() charges stack expansion even without VM_ACCOUNT.
This can happen for read-only or MAP_NORESERVE mappings created with
MAP_GROWSDOWN. Unmapping these VMAs does not release the charge, leaking
Committed_AS.

Only check and charge growth for VM_ACCOUNT VMAs, matching mremap().
Unaccounted growth skips the overcommit check while remaining subject
to the other stack-growth limits.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Reported-by: Josef Bacik <josef@toxicpanda.com>
Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 mm/vma.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/mm/vma.c b/mm/vma.c
index acdf00346cda5..695d0be85ac86 100644
--- a/mm/vma.c
+++ b/mm/vma.c
@@ -3391,7 +3391,8 @@ static int acct_stack_growth(struct vm_area_struct *vma,
 	 * Overcommit..  This must be the final test, as it will
 	 * update security statistics.
 	 */
-	if (security_vm_enough_memory_mm(mm, grow))
+	if (vma_test(vma, VMA_ACCOUNT_BIT) &&
+	    security_vm_enough_memory_mm(mm, grow))
 		return -ENOMEM;
 
 	return 0;

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 44/46] mm/cma: don't release CMA pages still in use
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (42 preceding siblings ...)
  2026-10-26 23:18 ` [PATCH 43/46] mm/vma: don't leak the charge for stack growth David Hildenbrand (Arm)
@ 2026-10-26 23:18 ` David Hildenbrand (Arm)
  2026-10-27  8:55   ` Lorenzo Stoakes (ARM)
  2026-10-27  9:48   ` Muchun Song
  2026-10-26 23:18 ` [PATCH 45/46] mm/memory-tiers: unregister empty tiers outside memory_tier_lock David Hildenbrand (Arm)
  2026-10-26 23:18 ` [PATCH 46/46] fs/proc/task_mmu: refuse addresses beyond 32 bits on 32bit David Hildenbrand (Arm)
  45 siblings, 2 replies; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:18 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, stable, David Hildenbrand (Arm)

From: Rik van Riel <riel@surriel.com>

When a driver calls dma_free_contiguous() before quiescing DMA, the
page might still have a reference from the device.
put_page_testzero() there returns false, WARN fires, but the code proceeds
to free_contig_frozen_range() putting a live page onto buddy and clearing
the bitmap. A subsequent allocation can hand the same PFN to a new
owner while the original holder still references it.

A concurrent put_page() that drops the last reference between the
testzero loop and free_contig_frozen_range() can double-queue the page
via page->lru, corrupting buddy lists.

Avoid the corruption by not freeing a CMA region if any of the
pages inside are still in use.

Make it explicit in the warning that the driver allowed a leak.

While at it, use page_ref_freeze() to make the semantics clearer and
switch to pr_warn_ratelimited().

Fixes: 9bda131c6093 ("mm: cma: add cma_alloc_frozen{_compound}()")
Cc: stable@vger.kernel.org
Signed-off-by: Rik van Riel <riel@surriel.com>
Link: https://patch.msgid.link/20260811132045.5f114772@fangorn
[ david: use page_ref_freeze() + pr_warn_ratelimited() ]
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 mm/cma.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/mm/cma.c b/mm/cma.c
index a10ea37a261da..871f95c9ae9f0 100644
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -1020,7 +1020,7 @@ bool cma_release(struct cma *cma, const struct page *pages,
 		 unsigned long count)
 {
 	struct cma_memrange *cmr;
-	unsigned long ret = 0;
+	unsigned long leaked = 0;
 	unsigned long i, pfn;
 
 	cmr = find_cma_memrange(cma, pages, count);
@@ -1029,9 +1029,13 @@ bool cma_release(struct cma *cma, const struct page *pages,
 
 	pfn = page_to_pfn(pages);
 	for (i = 0; i < count; i++, pfn++)
-		ret += !put_page_testzero(pfn_to_page(pfn));
+		leaked += !page_ref_freeze(pfn_to_page(pfn), 1);
 
-	WARN(ret, "%lu pages are still in use!\n", ret);
+	if (leaked) {
+		pr_warn_ratelimited("%lu pages are still in use, not freeing CMA region!\n",
+				   leaked);
+		return true;
+	}
 
 	__cma_release_frozen(cma, cmr, pages, count);
 

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 45/46] mm/memory-tiers: unregister empty tiers outside memory_tier_lock
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (43 preceding siblings ...)
  2026-10-26 23:18 ` [PATCH 44/46] mm/cma: don't release CMA pages still in use David Hildenbrand (Arm)
@ 2026-10-26 23:18 ` David Hildenbrand (Arm)
  2026-10-26 23:18 ` [PATCH 46/46] fs/proc/task_mmu: refuse addresses beyond 32 bits on 32bit David Hildenbrand (Arm)
  45 siblings, 0 replies; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:18 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, stable, Josef Bacik, David Hildenbrand (Arm)

When offlining a node's last memory empties its tier,
clear_node_memory_tier() calls device_unregister() while holding
memory_tier_lock. A concurrent sysfs read can hold a kernfs active
reference and block in nodelist_show() on that mutex. device_unregister()
then waits in kernfs_drain() for the read to finish and release its active
reference, while the reader waits for the offlining task to release the
mutex.

Return the node's former tier from clear_node_memory_tier(), making the
helper more similar to set_node_memory_tier(), which also returns a
memory_tier pointer. Let the caller unlink an empty tier under
memory_tier_lock before rebuilding demotion targets, then unregister its
device after dropping the lock.

Fixes: 9832fb87834e ("mm/demotion: expose memory tier details via sysfs")
Cc: stable@vger.kernel.org
Reported-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 mm/memory-tiers.c | 29 +++++++++++++----------------
 1 file changed, 13 insertions(+), 16 deletions(-)

diff --git a/mm/memory-tiers.c b/mm/memory-tiers.c
index 25e121851b586..8eda313cf6192 100644
--- a/mm/memory-tiers.c
+++ b/mm/memory-tiers.c
@@ -572,21 +572,14 @@ static struct memory_tier *set_node_memory_tier(int node)
 	return memtier;
 }
 
-static void destroy_memory_tier(struct memory_tier *memtier)
+static struct memory_tier *clear_node_memory_tier(int node)
 {
-	list_del(&memtier->list);
-	device_unregister(&memtier->dev);
-}
-
-static bool clear_node_memory_tier(int node)
-{
-	bool cleared = false;
 	pg_data_t *pgdat;
 	struct memory_tier *memtier;
 
 	pgdat = NODE_DATA(node);
 	if (!pgdat)
-		return false;
+		return NULL;
 
 	/*
 	 * Make sure that anybody looking at NODE_DATA who finds
@@ -604,14 +597,10 @@ static bool clear_node_memory_tier(int node)
 		synchronize_rcu();
 		memtype = node_memory_types[node].memtype;
 		node_clear(node, memtype->nodes);
-		if (nodes_empty(memtype->nodes)) {
+		if (nodes_empty(memtype->nodes))
 			list_del_init(&memtype->tier_sibling);
-			if (list_empty(&memtier->memory_types))
-				destroy_memory_tier(memtier);
-		}
-		cleared = true;
 	}
-	return cleared;
+	return memtier;
 }
 
 static void release_memtype(struct kref *kref)
@@ -884,13 +873,21 @@ static int __meminit memtier_hotplug_callback(struct notifier_block *self,
 {
 	struct memory_tier *memtier;
 	struct node_notify *nn = _arg;
+	bool empty = false;
 
 	switch (action) {
 	case NODE_REMOVED_LAST_MEMORY:
 		mutex_lock(&memory_tier_lock);
-		if (clear_node_memory_tier(nn->nid))
+		memtier = clear_node_memory_tier(nn->nid);
+		if (memtier) {
+			empty = list_empty(&memtier->memory_types);
+			if (empty)
+				list_del(&memtier->list);
 			establish_demotion_targets();
+		}
 		mutex_unlock(&memory_tier_lock);
+		if (empty)
+			device_unregister(&memtier->dev);
 		break;
 	case NODE_ADDED_FIRST_MEMORY:
 		mutex_lock(&memory_tier_lock);

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* [PATCH 46/46] fs/proc/task_mmu: refuse addresses beyond 32 bits on 32bit
  2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
                   ` (44 preceding siblings ...)
  2026-10-26 23:18 ` [PATCH 45/46] mm/memory-tiers: unregister empty tiers outside memory_tier_lock David Hildenbrand (Arm)
@ 2026-10-26 23:18 ` David Hildenbrand (Arm)
  45 siblings, 0 replies; 93+ messages in thread
From: David Hildenbrand (Arm) @ 2026-10-26 23:18 UTC (permalink / raw)
  To: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, Josef Bacik, David Hildenbrand (Arm)

From: Josef Bacik <josef@toxicpanda.com>

The addresses in struct pm_scan_arg are 64 bits wide.  The first thing
pagemap_scan_get_args() does with them is to cast them to unsigned
long.  On a 32-bit kernel the upper half is dropped without a word:
PAGEMAP_SCAN of 0x100001000-0x100002000 scans, and with
PM_SCAN_WP_MATCHING write-protects, 0x1000-0x2000, stores the result
at the lower half of vec, and reports success.

Return -EFAULT, as for other addresses outside of the address space.

This is probably not worth CCing stable.

Fix generated by an LLM and sent by Josef Bacik in private.

Fixes: 52526ca7fdb9 ("fs/proc/task_mmu: implement IOCTL to get and optionally clear info about PTEs")
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
 fs/proc/task_mmu.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 7452b695fdaec..762b6dbb81e4a 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -3032,6 +3032,12 @@ static int pagemap_scan_get_args(struct pm_scan_arg *arg,
 	     arg->category_anyof_mask | arg->return_mask) & ~PM_SCAN_CATEGORIES)
 		return -EINVAL;
 
+	/* Don't cut 64-bit numbers down to addresses that happen to work. */
+	if (arg->start != (unsigned long)arg->start ||
+	    arg->end != (unsigned long)arg->end ||
+	    arg->vec != (unsigned long)arg->vec)
+		return -EFAULT;
+
 	arg->start = untagged_addr((unsigned long)arg->start);
 	arg->end = untagged_addr((unsigned long)arg->end);
 	arg->vec = untagged_addr((unsigned long)arg->vec);

-- 
2.43.0


^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 01/46] mm/mglru: don't use stack pointers when walking PUD and PMD tables
  2026-10-26 23:17 ` [PATCH 01/46] mm/mglru: don't use stack pointers when walking PUD and PMD tables David Hildenbrand (Arm)
@ 2026-10-27  1:32   ` Rik van Riel
  2026-10-27  3:05   ` Qi Zheng
                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 93+ messages in thread
From: Rik van Riel @ 2026-10-27  1:32 UTC (permalink / raw)
  To: David Hildenbrand (Arm),
	Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Harry Yoo, Alistair Popple,
	Nico Pache, Ryan Roberts, Dev Jain, Usama Arif, Kiryl Shutsemau,
	Matthew Brost, John Hubbard, Peter Xu, Will Deacon,
	Aneesh Kumar K.V, Nick Piggin, Oscar Salvador, Minchan Kim,
	Muchun Song, Xu Xin, Chengming Zhou, Chris Li, Kemeng Shi,
	Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn, Rakie Kim,
	Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, Josef Bacik, stable

On Tue, 2026-10-27 at 00:17 +0100, David Hildenbrand (Arm) wrote:
> From: Josef Bacik <josef@toxicpanda.com>
> 

> The fix is simple, so just fix the original commit so we don't have
> to
> speculate. To fix it, pass the actual PMD/PUD pointers. This restores
> the
> RCU-protected lookup and validation against the live PMD. Note that
> the PUD
> handling is required as well to handle folded page tables correctly
> in all
> cases.
> 
> Fix generated by an LLM and sent by Josef Bacik in private.
> 
> Fixes: bd74fdaea146 ("mm: multi-gen LRU: support page table walks")
> Cc: stable@vger.kernel.org
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>
> [ david: handle walk_pud_range() as well, clarify+simplify
> description,
>          adjust Fixes: ]
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
> 
Reviewed-by: Rik van Riel <riel@surriel.com>

-- 
All Rights Reversed.

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 02/46] fork: take mmap_lock before copying mm_struct
  2026-10-26 23:17 ` [PATCH 02/46] fork: take mmap_lock before copying mm_struct David Hildenbrand (Arm)
@ 2026-10-27  1:38   ` Rik van Riel
  2026-10-27  8:18   ` Vlastimil Babka (SUSE)
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 93+ messages in thread
From: Rik van Riel @ 2026-10-27  1:38 UTC (permalink / raw)
  To: David Hildenbrand (Arm),
	Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Harry Yoo, Alistair Popple,
	Nico Pache, Ryan Roberts, Dev Jain, Usama Arif, Kiryl Shutsemau,
	Matthew Brost, John Hubbard, Peter Xu, Will Deacon,
	Aneesh Kumar K.V, Nick Piggin, Oscar Salvador, Minchan Kim,
	Muchun Song, Xu Xin, Chengming Zhou, Chris Li, Kemeng Shi,
	Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn, Rakie Kim,
	Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, stable, Josef Bacik

On Tue, 2026-10-27 at 00:17 +0100, David Hildenbrand (Arm) wrote:
> 
> Move uprobe_start_dup_mmap() to preserve the lock ordering.
> 
> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Cc: stable@vger.kernel.org
> Reported-by: Josef Bacik <josef@toxicpanda.com>
> Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>

Reviewed-by: Rik van Riel <riel@surriel.com>

-- 
All Rights Reversed.

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 03/46] mm/memfd: check for real shmem inodes before accessing shmem state
  2026-10-26 23:17 ` [PATCH 03/46] mm/memfd: check for real shmem inodes before accessing shmem state David Hildenbrand (Arm)
@ 2026-10-27  2:04   ` Rik van Riel
  2026-10-27  8:13   ` Mike Rapoport
  1 sibling, 0 replies; 93+ messages in thread
From: Rik van Riel @ 2026-10-27  2:04 UTC (permalink / raw)
  To: David Hildenbrand (Arm),
	Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Harry Yoo, Alistair Popple,
	Nico Pache, Ryan Roberts, Dev Jain, Usama Arif, Kiryl Shutsemau,
	Matthew Brost, John Hubbard, Peter Xu, Will Deacon,
	Aneesh Kumar K.V, Nick Piggin, Oscar Salvador, Minchan Kim,
	Muchun Song, Xu Xin, Chengming Zhou, Chris Li, Kemeng Shi,
	Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn, Rakie Kim,
	Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, stable, Chris Mason

On Tue, 2026-10-27 at 00:17 +0100, David Hildenbrand (Arm) wrote:
> shmem_file() only checks a file's backing mapping. That mapping can
> belong
> to another file, as with a Coda file backed by a tmpfs container
> after
> mmap(). It does not establish that file_inode(file) is a shmem inode.
> 
> Seal handling and memfd preservation use this check before accessing
> shmem inode state, so they can access an inode of the wrong type.
> 
> Add file_inode_is_shmem() to check the inode's file operations in
> both
> paths. This identifies regular shmem inodes, including those used by
> memfds and ordinary tmpfs files, independently of wrapper file
> operations.
> 
> Fixes: c49fcfcda8b5 ("mm/shmem: update file sealing comments and file
> checking")
> Fixes: b3749f174d68 ("mm: memfd_luo: allow preserving memfd")
> Cc: stable@vger.kernel.org
> Reported-by: Chris Mason <mason@kernel.org>
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>

Reviewed-by: Rik van Riel <riel@surriel.com>

-- 
All Rights Reversed.

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 04/46] mm/memfd: make f_pos accesses atomic
  2026-10-26 23:17 ` [PATCH 04/46] mm/memfd: make f_pos accesses atomic David Hildenbrand (Arm)
@ 2026-10-27  2:06   ` Rik van Riel
  2026-10-27  3:34   ` Gregory Price
                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 93+ messages in thread
From: Rik van Riel @ 2026-10-27  2:06 UTC (permalink / raw)
  To: David Hildenbrand (Arm),
	Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Harry Yoo, Alistair Popple,
	Nico Pache, Ryan Roberts, Dev Jain, Usama Arif, Kiryl Shutsemau,
	Matthew Brost, John Hubbard, Peter Xu, Will Deacon,
	Aneesh Kumar K.V, Nick Piggin, Oscar Salvador, Minchan Kim,
	Muchun Song, Xu Xin, Chengming Zhou, Chris Li, Kemeng Shi,
	Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn, Rakie Kim,
	Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, Josef Bacik, stable

On Tue, 2026-10-27 at 00:17 +0100, David Hildenbrand (Arm) wrote:
> From: Josef Bacik <josef@toxicpanda.com>
> 
> 
> Set the flag when the memfd is created.  As for any other regular
> file the
> lock is only taken if the file is reachable in more than one way, and
> nothing a memfd does in read or write waits for another operation on
> the
> same file.  This cannot be done for all alloc_file_pseudo() files:
> anon
> inode files such as eventfd are S_IFREG as well, and a blocked read
> holding
> ->f_pos_lock would lock out the write that is supposed to wake it.
> 
> Fix generated by an LLM and sent by Josef Bacik in private.
> 
> Fixes: 9183df25fe7b ("shm: add memfd_create() syscall")
> Cc: stable@vger.kernel.org
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>
> [ david: minor description tweaks ]
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>

Reviewed-by: Rik van Riel <riel@surriel.com>

-- 
All Rights Reversed.

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 05/46] mm/truncate: look again if a folio left the mapping
  2026-10-26 23:17 ` [PATCH 05/46] mm/truncate: look again if a folio left the mapping David Hildenbrand (Arm)
@ 2026-10-27  2:17   ` Rik van Riel
  0 siblings, 0 replies; 93+ messages in thread
From: Rik van Riel @ 2026-10-27  2:17 UTC (permalink / raw)
  To: David Hildenbrand (Arm),
	Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Harry Yoo, Alistair Popple,
	Nico Pache, Ryan Roberts, Dev Jain, Usama Arif, Kiryl Shutsemau,
	Matthew Brost, John Hubbard, Peter Xu, Will Deacon,
	Aneesh Kumar K.V, Nick Piggin, Oscar Salvador, Minchan Kim,
	Muchun Song, Xu Xin, Chengming Zhou, Chris Li, Kemeng Shi,
	Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn, Rakie Kim,
	Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, stable, Josef Bacik

On Tue, 2026-10-27 at 00:17 +0100, David Hildenbrand (Arm) wrote:
> 
> In that scenario, the collapsed folio with the data from before the
> write
> stays in the page cache after the write has returned.
> 
> This used to be impossible, as khugepaged only collapsed files that
> nobody
> had open for writing.
> 
> Restart the lookup at that index, like shmem_undo_range() does. The
> same
> problem seems to exist in truncate_inode_pages_range() as well when
> truncate_inode_folio() fails, so handle it there as well.
> 
> Fixes: 1b6444331beb ("mm/khugepaged: enable clean pagecache folio
> collapse for writable files")
> Cc: stable@vger.kernel.org
> Reported-by: Josef Bacik <josef@toxicpanda.com>
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>

Reviewed-by: Rik van Riel <riel@surriel.com>

-- 
All Rights Reversed.

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 06/46] mm/filemap: read mapping->a_ops->free_folio under i_lock
  2026-10-26 23:17 ` [PATCH 06/46] mm/filemap: read mapping->a_ops->free_folio under i_lock David Hildenbrand (Arm)
@ 2026-10-27  2:43   ` Rik van Riel
  0 siblings, 0 replies; 93+ messages in thread
From: Rik van Riel @ 2026-10-27  2:43 UTC (permalink / raw)
  To: David Hildenbrand (Arm),
	Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Harry Yoo, Alistair Popple,
	Nico Pache, Ryan Roberts, Dev Jain, Usama Arif, Kiryl Shutsemau,
	Matthew Brost, John Hubbard, Peter Xu, Will Deacon,
	Aneesh Kumar K.V, Nick Piggin, Oscar Salvador, Minchan Kim,
	Muchun Song, Xu Xin, Chengming Zhou, Chris Li, Kemeng Shi,
	Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn, Rakie Kim,
	Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, Josef Bacik, stable

On Tue, 2026-10-27 at 00:17 +0100, David Hildenbrand (Arm) wrote:
> From: Josef Bacik <josef@toxicpanda.com>
> 
> The bug was found by code inspection and has not been reproduced.
> 
I can't say I'm surprised ;)

I see clues that a most bunch of these issues
occasionally happen in our (rather large) fleet, 
but not this one.

> Fix generated by an LLM and sent by Josef Bacik in private.
> 
> Fixes: 59c66c5f8c4f ("mm: factor out page cache page freeing into a
> separate function")
> Cc: stable@vger.kernel.org
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>
> [ david: get rid of filemap_free_folio() entirely; improve patch
> description ]
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
> 

Reviewed-by: Rik van Riel <riel@surriel.com>

-- 
All Rights Reversed.

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 07/46] mm/filemap: don't lose a folio lock wakeup to a signal
  2026-10-26 23:17 ` [PATCH 07/46] mm/filemap: don't lose a folio lock wakeup to a signal David Hildenbrand (Arm)
@ 2026-10-27  3:03   ` Rik van Riel
  0 siblings, 0 replies; 93+ messages in thread
From: Rik van Riel @ 2026-10-27  3:03 UTC (permalink / raw)
  To: David Hildenbrand (Arm),
	Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Harry Yoo, Alistair Popple,
	Nico Pache, Ryan Roberts, Dev Jain, Usama Arif, Kiryl Shutsemau,
	Matthew Brost, John Hubbard, Peter Xu, Will Deacon,
	Aneesh Kumar K.V, Nick Piggin, Oscar Salvador, Minchan Kim,
	Muchun Song, Xu Xin, Chengming Zhou, Chris Li, Kemeng Shi,
	Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn, Rakie Kim,
	Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, Josef Bacik, stable

On Tue, 2026-10-27 at 00:17 +0100, David Hildenbrand (Arm) wrote:
> From: Josef Bacik <josef@toxicpanda.com>
> 
> An exclusive waiter in folio_wait_bit_common() can leave the wait
> loop
> because of a fatal signal, then be woken by folio_unlock() before
> finish_wait(). If the waker did not hand over the lock, the waiter
> returns
> -EINTR without trying to acquire it.
> 
> folio_wake_bit() stops after waking the first exclusive waiter, so
> this
> loses the wakeup and can leave other waiters asleep indefinitely on
> an
> unlocked folio.
> 
> After finish_wait(), let a waiter woken without a lock handoff try
> once
> more to acquire the lock. If successful, return success so the
> caller's
> eventual unlock wakes the next waiter. Otherwise, the current lock
> owner
> will do so.
> 
> Fix generated by an LLM and sent by Josef Bacik in private.
> 
> Fixes: 5ef64cc8987a ("mm: allow a controlled amount of unfairness in
> the page lock")
> Cc: stable@vger.kernel.org
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>
> [ david: clarify and simplify comment + description ]
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>

Reviewed-by: Rik van Riel <riel@surriel.com>

-- 
All Rights Reversed.

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 01/46] mm/mglru: don't use stack pointers when walking PUD and PMD tables
  2026-10-26 23:17 ` [PATCH 01/46] mm/mglru: don't use stack pointers when walking PUD and PMD tables David Hildenbrand (Arm)
  2026-10-27  1:32   ` Rik van Riel
@ 2026-10-27  3:05   ` Qi Zheng
  2026-10-27  7:20   ` Dev Jain
                     ` (2 subsequent siblings)
  4 siblings, 0 replies; 93+ messages in thread
From: Qi Zheng @ 2026-10-27  3:05 UTC (permalink / raw)
  To: David Hildenbrand (Arm),
	Andrew Morton, Johannes Weiner, Michal Hocko, Shakeel Butt,
	Lorenzo Stoakes, Kairui Song, Barry Song, Axel Rasmussen,
	Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang, Liam R. Howlett,
	Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
	Kees Cook, Peter Zijlstra, Jann Horn, Pedro Falcato,
	Hugh Dickins, Pasha Tatashin, Pratyush Yadav,
	Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, Josef Bacik, stable



On 10/27/26 7:17 AM, David Hildenbrand (Arm) wrote:
> From: Josef Bacik <josef@toxicpanda.com>
> 
> MGLRU passes stack copies of page-table entries in walk_pud_range() and
> walk_pmd_range() when walking to the next level. These copies can become
> stale when khugepaged or MADV_DONTNEED (CONFIG_PT_RECLAIM) removes a PTE
> table concurrently.
> 
> This pattern dates back to commit bd74fdaea146 ("mm: multi-gen LRU:
> support page table walks"). Likely, earlier locking masked the latent
> bug. Later changes exposed it: commit 1d65b771bc08 ("mm/khugepaged:
> retract_page_tables() without mmap or vma lock") allowed concurrent
> retraction, and commit cf4a65539c13 ("memcg-v1: no need for memcg locking
> for MGLRU") dropped the walker's outer RCU protection.
> 
> The fix is simple, so just fix the original commit so we don't have to
> speculate. To fix it, pass the actual PMD/PUD pointers. This restores the
> RCU-protected lookup and validation against the live PMD. Note that the PUD
> handling is required as well to handle folded page tables correctly in all
> cases.
> 
> Fix generated by an LLM and sent by Josef Bacik in private.
> 
> Fixes: bd74fdaea146 ("mm: multi-gen LRU: support page table walks")
> Cc: stable@vger.kernel.org
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>
> [ david: handle walk_pud_range() as well, clarify+simplify description,
>           adjust Fixes: ]
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
> ---
>   mm/vmscan.c | 4 ++--
>   1 file changed, 2 insertions(+), 2 deletions(-)

Reviewed-by: Qi Zheng <qi.zheng@linux.dev>

Thanks,
Qi


^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 26/46] mm/mmu_gather: fix flushing ranges with 4 GiB or larger
  2026-10-26 23:17 ` [PATCH 26/46] mm/mmu_gather: fix flushing ranges with 4 GiB or larger David Hildenbrand (Arm)
@ 2026-10-27  3:06   ` Qi Zheng
  2026-10-27  3:40   ` Gregory Price
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 93+ messages in thread
From: Qi Zheng @ 2026-10-27  3:06 UTC (permalink / raw)
  To: David Hildenbrand (Arm),
	Andrew Morton, Johannes Weiner, Michal Hocko, Shakeel Butt,
	Lorenzo Stoakes, Kairui Song, Barry Song, Axel Rasmussen,
	Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang, Liam R. Howlett,
	Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
	Kees Cook, Peter Zijlstra, Jann Horn, Pedro Falcato,
	Hugh Dickins, Pasha Tatashin, Pratyush Yadav,
	Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, Josef Bacik, stable



On 10/27/26 7:17 AM, David Hildenbrand (Arm) wrote:
> From: Josef Bacik <josef@toxicpanda.com>
> 
> __tlb_adjust_range() takes the size of the range which has to be flushed
> as an unsigned int. Its callers, tlb_flush_{pte,pmd,pud,p4d}_range(), get
> and pass an unsigned long. Consequently, a range that is 4 GiB or larger
> gets truncated, possibly to 0.
> 
> On arm64 with hugetlb, a 64k kernel can flush 16 GiB hugetlb PMDs, and a
> 16k kernel can flush 64 GiB PUDs through tlb_unshare_pmd_ptdesc(). So
> at least these two scenarios are affected.
> 
> Fix it by flushing the proper range instead of the truncated one.
> 
> Fix generated by an LLM and sent by Josef Bacik in private.
> 
> Fixes: b528e4b6405b ("mm/hugetlb: add tlb_remove_hugetlb_entry for handling hugetlb pages")
> Fixes: 8ce720d5bd91 ("mm/hugetlb: fix excessive IPI broadcasts when unsharing PMD tables using mmu_gather")
> Cc: stable@vger.kernel.org
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>
> Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
> [ david: use two-tab indent, simplify description ]
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
> ---
>   include/asm-generic/tlb.h | 3 +--
>   1 file changed, 1 insertion(+), 2 deletions(-)
> 
> diff --git a/include/asm-generic/tlb.h b/include/asm-generic/tlb.h
> index fbe1114e9a443..3f4a180b48f3c 100644
> --- a/include/asm-generic/tlb.h
> +++ b/include/asm-generic/tlb.h
> @@ -350,8 +350,7 @@ struct mmu_gather {
>   void tlb_flush_mmu(struct mmu_gather *tlb);
>   
>   static inline void __tlb_adjust_range(struct mmu_gather *tlb,
> -				      unsigned long address,
> -				      unsigned int range_size)
> +		unsigned long address, unsigned long range_size)
>   {
>   	tlb->start = min(tlb->start, address);
>   	tlb->end = max(tlb->end, address + range_size);

Reviewed-by: Qi Zheng <qi.zheng@linux.dev>

Thanks,
Qi

> 


^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 04/46] mm/memfd: make f_pos accesses atomic
  2026-10-26 23:17 ` [PATCH 04/46] mm/memfd: make f_pos accesses atomic David Hildenbrand (Arm)
  2026-10-27  2:06   ` Rik van Riel
@ 2026-10-27  3:34   ` Gregory Price
  2026-10-27  8:44     ` Lorenzo Stoakes (ARM)
  2026-10-27  8:15   ` Mike Rapoport
                     ` (2 subsequent siblings)
  4 siblings, 1 reply; 93+ messages in thread
From: Gregory Price @ 2026-10-27  3:34 UTC (permalink / raw)
  To: David Hildenbrand (Arm)
  Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe, linux-mm, linux-kernel,
	kexec, linux-fsdevel, linux-arch, linux-cxl, Josef Bacik, stable

On 2026-10-27 00:17 +0100, David Hildenbrand (Arm) wrote:
> From: Josef Bacik <josef@toxicpanda.com>
> 
> Commit 9c225f2655e3 ("vfs: atomic f_pos accesses as per POSIX") made
> read(), write() and lseek() on a shared open file description of a regular
> file serialize on ->f_pos_lock.  The flag that asks for it,
> FMODE_ATOMIC_POS, is set in do_dentry_open().  A memfd is a regular file
> too, but its struct file comes from alloc_file_pseudo() and never passes
> through do_dentry_open(), so it does not get the flag:
> 
... snip ...
> 
> Fixes: 9183df25fe7b ("shm: add memfd_create() syscall")
> Cc: stable@vger.kernel.org
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>
> [ david: minor description tweaks ]
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>

Reviewed-by: Gregory Price (Meta) <gourry@gourry.net>
Tested-by: Gregory Price (Meta) <gourry@gourry.net>

This one arguably should have at least a trivial selftest.

Test attatched
-- >8 --
From: Gregory Price <gourry@gourry.net>
Subject: [PATCH] selftests/memfd: test shared file position atomicity

Without FMODE_ATOMIC_POS, concurrent reads or writes on a shared memfd
can use the same file position. Two writers can overwrite each other's
records:

    CPU 1                         CPU 2
    pos = file->f_pos
                                  pos = file->f_pos
    write a record at pos
                                  write a record at pos
    file->f_pos = pos + size
                                  file->f_pos = pos + size

Add separate shared-read and shared-write tests using the kselftest
harness. Check the final offset, file size and exactly-once record delivery
rather than requiring a particular interleaving.

Signed-off-by: Gregory Price (Meta) <gourry@gourry.net>
---
 tools/testing/selftests/memfd/.gitignore  |   1 +
 tools/testing/selftests/memfd/Makefile    |   3 +-
 tools/testing/selftests/memfd/memfd_pos.c | 136 ++++++++++++++++++++++
 3 files changed, 139 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/memfd/memfd_pos.c

diff --git a/tools/testing/selftests/memfd/.gitignore b/tools/testing/selftests/memfd/.gitignore
index dd9a051f608e2..574ab97ebd982 100644
--- a/tools/testing/selftests/memfd/.gitignore
+++ b/tools/testing/selftests/memfd/.gitignore
@@ -2,4 +2,5 @@
 fuse_mnt
 fuse_test
 memfd_test
+memfd_pos
 memfd-test-file
diff --git a/tools/testing/selftests/memfd/Makefile b/tools/testing/selftests/memfd/Makefile
index 163b6f68631c4..67a95c34541cd 100644
--- a/tools/testing/selftests/memfd/Makefile
+++ b/tools/testing/selftests/memfd/Makefile
@@ -2,7 +2,7 @@
 CFLAGS += -D_FILE_OFFSET_BITS=64
 CFLAGS += $(KHDR_INCLUDES)
 
-TEST_GEN_PROGS := memfd_test
+TEST_GEN_PROGS := memfd_test memfd_pos
 TEST_PROGS := run_fuse_test.sh run_hugetlbfs_test.sh
 TEST_GEN_FILES := fuse_test fuse_mnt
 
@@ -22,6 +22,7 @@ include ../lib.mk
 
 $(OUTPUT)/fuse_mnt: LDLIBS += $(VAR_LDLIBS)
 
+$(OUTPUT)/memfd_pos: LDLIBS += -pthread
 $(OUTPUT)/memfd_test: memfd_test.c common.c
 $(OUTPUT)/fuse_test: fuse_test.c common.c
 
diff --git a/tools/testing/selftests/memfd/memfd_pos.c b/tools/testing/selftests/memfd/memfd_pos.c
new file mode 100644
index 0000000000000..5f3749d13f561
--- /dev/null
+++ b/tools/testing/selftests/memfd/memfd_pos.c
@@ -0,0 +1,136 @@
+// SPDX-License-Identifier: GPL-2.0
+#define _GNU_SOURCE
+#include <errno.h>
+#include <pthread.h>
+#include <stdatomic.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "../kselftest_harness.h"
+
+#define THREADS 4
+#define RECORDS 16384
+#define TOTAL (THREADS * RECORDS)
+
+struct worker {
+	int fd;
+	unsigned int id;
+	bool reading;
+	pthread_barrier_t *barrier;
+	atomic_uint *seen;
+	int error;
+};
+
+static void *transfer(void *arg)
+{
+	struct worker *w = arg;
+	unsigned int i;
+
+	pthread_barrier_wait(w->barrier);
+	for (i = 0; i < RECORDS; i++) {
+		uint32_t value = w->id * RECORDS + i;
+		ssize_t n;
+
+		do {
+			n = w->reading ? read(w->fd, &value, sizeof(value)) :
+				write(w->fd, &value, sizeof(value));
+		} while (n < 0 && errno == EINTR);
+		if (n != sizeof(value) || value >= TOTAL) {
+			w->error = 1;
+			break;
+		}
+		if (w->reading)
+			atomic_fetch_add(&w->seen[value], 1);
+	}
+	return NULL;
+}
+
+FIXTURE(memfd_pos) {
+	int fd;
+	atomic_uint *seen;
+};
+
+FIXTURE_SETUP(memfd_pos)
+{
+	self->fd = memfd_create("position", MFD_CLOEXEC);
+	if (self->fd < 0 && errno == ENOSYS)
+		SKIP(return, "memfd_create unavailable");
+	ASSERT_GE(self->fd, 0);
+	self->seen = calloc(TOTAL, sizeof(*self->seen));
+	ASSERT_NE(self->seen, NULL);
+	for (unsigned int i = 0; i < TOTAL; i++)
+		atomic_init(&self->seen[i], 0);
+}
+
+FIXTURE_TEARDOWN(memfd_pos)
+{
+	close(self->fd);
+	free(self->seen);
+}
+
+static int run_workers(int fd, bool reading, atomic_uint *seen)
+{
+	pthread_barrier_t barrier;
+	pthread_t threads[THREADS];
+	struct worker workers[THREADS];
+	int ret = 0;
+	unsigned int i;
+
+	if (pthread_barrier_init(&barrier, NULL, THREADS))
+		return 1;
+	for (i = 0; i < THREADS; i++) {
+		workers[i] = (struct worker) {
+			.fd = fd, .id = i, .reading = reading,
+			.barrier = &barrier, .seen = seen,
+		};
+		/* The harness isolates this test in a child; abort on setup failure. */
+		if (pthread_create(&threads[i], NULL, transfer, &workers[i]))
+			abort();
+	}
+	for (i = 0; i < THREADS; i++) {
+		if (pthread_join(threads[i], NULL) || workers[i].error)
+			ret = 1;
+	}
+	pthread_barrier_destroy(&barrier);
+	return ret;
+}
+
+/* Concurrent writes sharing an open file description must not overlap. */
+TEST_F(memfd_pos, shared_write)
+{
+	struct stat st;
+	uint32_t value;
+	unsigned int i;
+
+	ASSERT_EQ(run_workers(self->fd, false, self->seen), 0);
+	ASSERT_EQ(fstat(self->fd, &st), 0);
+	ASSERT_EQ(st.st_size, (off_t)(TOTAL * sizeof(value)));
+	ASSERT_EQ(lseek(self->fd, 0, SEEK_CUR), st.st_size);
+	ASSERT_EQ(lseek(self->fd, 0, SEEK_SET), 0);
+	for (i = 0; i < TOTAL; i++) {
+		ASSERT_EQ(read(self->fd, &value, sizeof(value)), sizeof(value));
+		ASSERT_LT(value, TOTAL);
+		atomic_fetch_add(&self->seen[value], 1);
+	}
+	for (i = 0; i < TOTAL; i++)
+		ASSERT_EQ(atomic_load(&self->seen[i]), 1);
+}
+
+/* Concurrent reads must consume every record exactly once. */
+TEST_F(memfd_pos, shared_read)
+{
+	uint32_t i;
+
+	for (i = 0; i < TOTAL; i++)
+		ASSERT_EQ(write(self->fd, &i, sizeof(i)), sizeof(i));
+	ASSERT_EQ(lseek(self->fd, 0, SEEK_SET), 0);
+	ASSERT_EQ(run_workers(self->fd, true, self->seen), 0);
+	ASSERT_EQ(lseek(self->fd, 0, SEEK_CUR), (off_t)(TOTAL * sizeof(i)));
+	for (i = 0; i < TOTAL; i++)
+		ASSERT_EQ(atomic_load(&self->seen[i]), 1);
+}
+
+TEST_HARNESS_MAIN

-- 
Gregory Price <gourry@gourry.net>

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 26/46] mm/mmu_gather: fix flushing ranges with 4 GiB or larger
  2026-10-26 23:17 ` [PATCH 26/46] mm/mmu_gather: fix flushing ranges with 4 GiB or larger David Hildenbrand (Arm)
  2026-10-27  3:06   ` Qi Zheng
@ 2026-10-27  3:40   ` Gregory Price
  2026-10-27  7:35   ` Dev Jain
  2026-10-27  9:50   ` Muchun Song
  3 siblings, 0 replies; 93+ messages in thread
From: Gregory Price @ 2026-10-27  3:40 UTC (permalink / raw)
  To: David Hildenbrand (Arm)
  Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe, linux-mm, linux-kernel,
	kexec, linux-fsdevel, linux-arch, linux-cxl, Josef Bacik, stable

On 2026-10-27 00:17 +0100, David Hildenbrand (Arm) wrote:
> From: Josef Bacik <josef@toxicpanda.com>
> 
> __tlb_adjust_range() takes the size of the range which has to be flushed
> as an unsigned int. Its callers, tlb_flush_{pte,pmd,pud,p4d}_range(), get
> and pass an unsigned long. Consequently, a range that is 4 GiB or larger
> gets truncated, possibly to 0.
> 
> On arm64 with hugetlb, a 64k kernel can flush 16 GiB hugetlb PMDs, and a
> 16k kernel can flush 64 GiB PUDs through tlb_unshare_pmd_ptdesc(). So
> at least these two scenarios are affected.
> 
> Fix it by flushing the proper range instead of the truncated one.
> 
> Fix generated by an LLM and sent by Josef Bacik in private.
> 
> Fixes: b528e4b6405b ("mm/hugetlb: add tlb_remove_hugetlb_entry for handling hugetlb pages")
> Fixes: 8ce720d5bd91 ("mm/hugetlb: fix excessive IPI broadcasts when unsharing PMD tables using mmu_gather")
> Cc: stable@vger.kernel.org
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>
> Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
> [ david: use two-tab indent, simplify description ]
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>

Reviewed-by: Gregory Price (Meta) <gourry@gourry.net>
Tested-by: Gregory Price (Meta) <gourry@gourry.net>

-- 
Gregory Price <gourry@gourry.net>

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 28/46] mm/mmu_notifier: set ->mm only after mmgrab()
  2026-10-26 23:17 ` [PATCH 28/46] mm/mmu_notifier: set ->mm only after mmgrab() David Hildenbrand (Arm)
@ 2026-10-27  3:42   ` Gregory Price
  2026-10-27  8:50   ` Lorenzo Stoakes (ARM)
  1 sibling, 0 replies; 93+ messages in thread
From: Gregory Price @ 2026-10-27  3:42 UTC (permalink / raw)
  To: David Hildenbrand (Arm)
  Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe, linux-mm, linux-kernel,
	kexec, linux-fsdevel, linux-arch, linux-cxl, Chris Mason, stable

On 2026-10-27 00:17 +0100, David Hildenbrand (Arm) wrote:
> From: Chris Mason <mason@kernel.org>
> 
> Radeon uses a non-NULL notifier->mm to decide whether to call
> mmu_interval_notifier_remove() when freeing a buffer object.
> __mmu_interval_notifier_insert() sets ->mm before validating the range,
> so a wrapping userptr range can leave ->mm set after insertion fails.
> Cleanup then tries to remove an unregistered notifier for which no mm
> reference was acquired.
> 
> Set ->mm only after mmgrab(), once insertion can no longer fail. While
> we could fix radeon's code instead, setting ->mm on success only makes
> the code more robust.
> 
> Fix generated by an LLM and sent by Chris Mason in private.
> 
> Fixes: 3506ff69c3ec ("drm/radeon: use mmu_interval_notifier_insert")
> Cc: stable@vger.kernel.org
> Signed-off-by: Chris Mason <mason@kernel.org>
> [ david: simplify description ]
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>

Reviewed-by: Gregory Price (Meta) <gourry@gourry.net>
Tested-by: Gregory Price (Meta) <gourry@gourry.net>

-- 
Gregory Price <gourry@gourry.net>

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 41/46] mm/vma: call ->may_split() before a partial merge
  2026-10-26 23:18 ` [PATCH 41/46] mm/vma: call ->may_split() before a partial merge David Hildenbrand (Arm)
@ 2026-10-27  3:45   ` Gregory Price
  0 siblings, 0 replies; 93+ messages in thread
From: Gregory Price @ 2026-10-27  3:45 UTC (permalink / raw)
  To: David Hildenbrand (Arm)
  Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe, linux-mm, linux-kernel,
	kexec, linux-fsdevel, linux-arch, linux-cxl, Chris Mason, stable

On 2026-10-27 00:18 +0100, David Hildenbrand (Arm) wrote:
> From: Chris Mason <mason@kernel.org>
> 
> A driver can use the ->may_split() hook to forbid a VMA boundary at
> certain addresses.
> 
... snip ...
> 
> Fixes: 38607c62b34b ("fs/dax: properly refcount fs dax pages")
> Cc: stable@vger.kernel.org
> Signed-off-by: Chris Mason <mason@kernel.org>
> Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
> [ david: improve description; cleanup the code ]
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>

Reviewed-by: Gregory Price (Meta) <gourry@gourry.net>
Tested-by: Gregory Price (Meta) <gourry@gourry.net>

Attached a vma unit test I used to test this

-- >8 --
From: Gregory Price <gourry@gourry.net>
Subject: [PATCH] tools/testing/vma: test may_split during partial merges

A partial VMA merge moves a boundary just as a split does, so it must
consult the driver's may_split callback. Removing an entire VMA during a
merge needs no split check.

Exercise permitted and rejected partial merges in both directions through
vma_modify_flags(). Check the callback address and resulting boundaries,
including unchanged boundaries on rejection. Also check that a full merge
succeeds without calling a rejecting may_split callback.

Signed-off-by: Gregory Price (Meta) <gourry@gourry.net>
---
 tools/testing/vma/tests/merge.c | 87 +++++++++++++++++++++++++++++++++
 1 file changed, 87 insertions(+)

diff --git a/tools/testing/vma/tests/merge.c b/tools/testing/vma/tests/merge.c
index b26f1a66a1707..fcc052be15601 100644
--- a/tools/testing/vma/tests/merge.c
+++ b/tools/testing/vma/tests/merge.c
@@ -1488,8 +1488,95 @@ static bool test_expand_only_mode(void)
 	return true;
 }
 
+static unsigned long split_checked_addr;
+static unsigned int split_checks;
+static bool split_allowed;
+
+static int merge_may_split(struct vm_area_struct *vma, unsigned long addr)
+{
+	split_checked_addr = addr;
+	split_checks++;
+	return split_allowed ? 0 : -EINVAL;
+}
+
+static const struct vm_operations_struct merge_split_ops = {
+	.may_split = merge_may_split,
+};
+
+static bool check_partial_merge_split(bool left_edge, bool allow)
+{
+	struct mm_struct mm = {};
+	vma_flags_t left_flags = mk_vma_flags(VMA_READ_BIT, VMA_MAYREAD_BIT,
+					      VMA_MAYWRITE_BIT);
+	vma_flags_t right_flags = mk_vma_flags(VMA_READ_BIT, VMA_WRITE_BIT,
+					       VMA_MAYREAD_BIT, VMA_MAYWRITE_BIT);
+	struct vm_area_struct *left = alloc_and_link_vma(&mm, 0x1000, 0x3000,
+							1, left_flags);
+	struct vm_area_struct *right = alloc_and_link_vma(&mm, 0x3000, 0x5000,
+							 3, right_flags);
+	struct vm_area_struct *middle = left_edge ? right : left;
+	unsigned long start = left_edge ? 0x3000 : 0x2000;
+	unsigned long end = left_edge ? 0x4000 : 0x3000;
+	vma_flags_t flags = left_edge ? left_flags : right_flags;
+	struct vm_area_struct *result;
+	VMA_ITERATOR(vmi, &mm, start);
+
+	left->vm_ops = &merge_split_ops;
+	right->vm_ops = &merge_split_ops;
+	split_checks = 0;
+	split_allowed = allow;
+	result = vma_modify_flags(&vmi, left, middle, start, end, &flags);
+	ASSERT_TRUE(split_checks > 0);
+	ASSERT_EQ(split_checked_addr, left_edge ? end : start);
+	if (allow) {
+		ASSERT_EQ(result, left_edge ? left : right);
+		ASSERT_EQ(left->vm_end, left_edge ? end : start);
+		ASSERT_EQ(right->vm_start, left_edge ? end : start);
+	} else {
+		ASSERT_EQ(PTR_ERR(result), -EINVAL);
+		ASSERT_EQ(left->vm_end, 0x3000);
+		ASSERT_EQ(right->vm_start, 0x3000);
+		ASSERT_EQ(mm.map_count, 2);
+	}
+	cleanup_mm(&mm, &vmi);
+	return true;
+}
+
+static bool test_partial_merge_may_split(void)
+{
+	ASSERT_TRUE(check_partial_merge_split(true, false));
+	ASSERT_TRUE(check_partial_merge_split(false, false));
+	ASSERT_TRUE(check_partial_merge_split(true, true));
+	ASSERT_TRUE(check_partial_merge_split(false, true));
+	return true;
+}
+
+static bool test_full_merge_no_split(void)
+{
+	struct mm_struct mm = {};
+	vma_flags_t flags = mk_vma_flags(VMA_READ_BIT, VMA_MAYREAD_BIT);
+	struct vm_area_struct *left = alloc_and_link_vma(&mm, 0x1000, 0x3000,
+							1, flags);
+	struct vm_area_struct *right = alloc_and_link_vma(&mm, 0x3000, 0x5000,
+							 3, flags);
+	VMA_ITERATOR(vmi, &mm, 0x3000);
+
+	left->vm_ops = &merge_split_ops;
+	right->vm_ops = &merge_split_ops;
+	split_checks = 0;
+	split_allowed = false;
+	ASSERT_EQ(vma_modify_flags(&vmi, left, right, 0x3000, 0x5000, &flags), left);
+	ASSERT_EQ(split_checks, 0);
+	ASSERT_EQ(left->vm_start, 0x1000);
+	ASSERT_EQ(left->vm_end, 0x5000);
+	cleanup_mm(&mm, &vmi);
+	return true;
+}
+
 static void run_merge_tests(int *num_tests, int *num_fail)
 {
+	TEST(partial_merge_may_split);
+	TEST(full_merge_no_split);
 	/* Very simple tests to kick the tyres. */
 	TEST(simple_merge);
 	TEST(simple_modify);

-- 
Gregory Price <gourry@gourry.net>

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 25/46] mm/userfaultfd: wake waiters when registration modes are removed
  2026-10-26 23:17 ` [PATCH 25/46] mm/userfaultfd: wake waiters when registration modes are removed David Hildenbrand (Arm)
@ 2026-10-27  5:10   ` Gregory Price
  2026-10-27  8:24     ` Lorenzo Stoakes (ARM)
  2026-10-27  8:21   ` Mike Rapoport
  2026-10-27  8:31   ` Lorenzo Stoakes (ARM)
  2 siblings, 1 reply; 93+ messages in thread
From: Gregory Price @ 2026-10-27  5:10 UTC (permalink / raw)
  To: David Hildenbrand (Arm)
  Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe, linux-mm, linux-kernel,
	kexec, linux-fsdevel, linux-arch, linux-cxl, stable

On 2026-10-27 00:17 +0100, David Hildenbrand (Arm) wrote:
> UFFDIO_REGISTER can replace MISSING or MINOR tracking without waking
> faults that are already queued. For example, switching an anonymous
> range from MISSING to WP leaves a missing-fault waiter asleep until
> userspace explicitly wakes it.
> 
> When a registration change removes a UFFD mode, wake waiters in the
> affected interval after updating the VMA. The VMA is write-locked at
> this point, so no new faults can queue under the old modes and woken
> threads cannot retry until mmap_write_unlock(). Waiters for retained
> modes in the same interval may also wake and refault.
> 
> The hang reproduces for MISSING-to-WP and MINOR-to-MISSING transitions,
> with both read and unread fault events.
> 
> Fixes: 63b2d4174c4a ("userfaultfd: wp: add the writeprotect API to userfaultfd ioctl")
> Cc: stable@vger.kernel.org
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>

Reviewed-by: Gregory Price (Meta) <gourry@gourry.net>
Tested-by: Gregory Price (Meta) <gourry@gourry.net>

Two additional automated reviews independently confirmed a similar
pre-existing issue and generated the same patch (below).

Sashiko filed this as a pre-existing:
https://sashiko.dev/#/map/217050

But this seems directly related to your patch here, so it might be worth
squashing this in:

> diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
> index 2122676c4220f..710e913c73bfa 100644
> --- a/mm/userfaultfd.c
> +++ b/mm/userfaultfd.c

[ ... ]

> @@ -2287,6 +2290,8 @@ static int userfaultfd_register_range(struct userfaultfd_ctx *ctx,
> 		prev = vma;
> 
> 	for_each_vma_range(vmi, vma, end) {
> +		const bool any_mode_removed = vma->vm_flags & __VM_UFFD_FLAGS & ~vm_flags;
> +
> 		cond_resched();
> 
> 		VM_WARN_ON_ONCE(!vma_can_userfault(vma, vm_flags, wp_async));

Could the pre-existing no-op check also require an exact mode match?
It currently does this later in userfaultfd_register_range():

        if (vma->vm_userfaultfd_ctx.ctx == ctx &&
            vma_test_all_mask(vma, vma_flags))
                goto skip;

Registering MISSING|WP, then requesting WP alone, takes this branch.
It leaves missing tracking enabled and bypasses the new wake. A writer
started after the replacement ioctl returns still queues a missing fault.
A writer already waiting before replacement also stays asleep.

Both cases time out on the base and on the full series. Replacing the
predicate with

        (vma->vm_flags & __VM_UFFD_FLAGS) == vm_flags

makes both pass with this series. On the base that change fixes only the
fresh-fault case; the already-pending case still needs this patch's wake.
Would a separate fix for the mode comparison make sense alongside this
patch? This is not introduced by the series.

-- >8 --
From: Gregory Price <gourry@gourry.net>
Subject: [PATCH] mm/userfaultfd: compare exact registration modes before skipping

Changing registration from MISSING|WP to WP returns success but leaves
MISSING enabled. The no-op check sees that WP is already set and skips
the update, so later accesses to missing pages still wait for userspace.

Skip the update only when the current and requested UFFD modes match
exactly.

Fixes: 63b2d4174c4a ("userfaultfd: wp: add the writeprotect API to userfaultfd ioctl")
Cc: stable@vger.kernel.org
Signed-off-by: Gregory Price (Meta) <gourry@gourry.net>
---
 mm/userfaultfd.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
index 669f71d485d02..0a28130cebc99 100644
--- a/mm/userfaultfd.c
+++ b/mm/userfaultfd.c
@@ -2299,7 +2299,7 @@ static int userfaultfd_register_range(struct userfaultfd_ctx *ctx,
 		 * userfaultfd and with the right tracking mode too.
 		 */
 		if (vma->vm_userfaultfd_ctx.ctx == ctx &&
-		    vma_test_all_mask(vma, vma_flags))
+		    (vma->vm_flags & __VM_UFFD_FLAGS) == vm_flags)
 			goto skip;
 
 		/*

-- 
Gregory Price <gourry@gourry.net>

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 01/46] mm/mglru: don't use stack pointers when walking PUD and PMD tables
  2026-10-26 23:17 ` [PATCH 01/46] mm/mglru: don't use stack pointers when walking PUD and PMD tables David Hildenbrand (Arm)
  2026-10-27  1:32   ` Rik van Riel
  2026-10-27  3:05   ` Qi Zheng
@ 2026-10-27  7:20   ` Dev Jain
  2026-10-27  8:06   ` Lorenzo Stoakes (ARM)
  2026-10-27 10:22   ` Kairui Song
  4 siblings, 0 replies; 93+ messages in thread
From: Dev Jain @ 2026-10-27  7:20 UTC (permalink / raw)
  To: David Hildenbrand (Arm),
	Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, Josef Bacik, stable



On 27/10/26 4:47 am, David Hildenbrand (Arm) wrote:
> From: Josef Bacik <josef@toxicpanda.com>
> 
> MGLRU passes stack copies of page-table entries in walk_pud_range() and
> walk_pmd_range() when walking to the next level. These copies can become
> stale when khugepaged or MADV_DONTNEED (CONFIG_PT_RECLAIM) removes a PTE
> table concurrently.
> 
> This pattern dates back to commit bd74fdaea146 ("mm: multi-gen LRU:
> support page table walks"). Likely, earlier locking masked the latent
> bug. Later changes exposed it: commit 1d65b771bc08 ("mm/khugepaged:
> retract_page_tables() without mmap or vma lock") allowed concurrent
> retraction, and commit cf4a65539c13 ("memcg-v1: no need for memcg locking
> for MGLRU") dropped the walker's outer RCU protection.
> 
> The fix is simple, so just fix the original commit so we don't have to
> speculate. To fix it, pass the actual PMD/PUD pointers. This restores the
> RCU-protected lookup and validation against the live PMD. Note that the PUD
> handling is required as well to handle folded page tables correctly in all
> cases.
> 
> Fix generated by an LLM and sent by Josef Bacik in private.
> 
> Fixes: bd74fdaea146 ("mm: multi-gen LRU: support page table walks")
> Cc: stable@vger.kernel.org
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>
> [ david: handle walk_pud_range() as well, clarify+simplify description,
>          adjust Fixes: ]
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
> ---

Reviewed-by: Dev Jain <dev.jain@arm.com>


>  mm/vmscan.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/mm/vmscan.c b/mm/vmscan.c
> index 9959ca158ce83..6a1af9b92349f 100644
> --- a/mm/vmscan.c
> +++ b/mm/vmscan.c
> @@ -3911,7 +3911,7 @@ static void walk_pmd_range(pud_t *pud, unsigned long start, unsigned long end,
>  
>  		walk->mm_stats[MM_NONLEAF_FOUND]++;
>  
> -		if (!walk_pte_range(&val, addr, next, args))
> +		if (!walk_pte_range(pmd + i, addr, next, args))
>  			continue;
>  
>  		walk->mm_stats[MM_NONLEAF_ADDED]++;
> @@ -3947,7 +3947,7 @@ static int walk_pud_range(p4d_t *p4d, unsigned long start, unsigned long end,
>  		if (!pud_present(val) || WARN_ON_ONCE(pud_leaf(val)))
>  			continue;
>  
> -		walk_pmd_range(&val, addr, next, args);
> +		walk_pmd_range(pud + i, addr, next, args);
>  
>  		if (need_resched() || walk->batched >= MAX_LRU_BATCH) {
>  			end = (addr | ~PUD_MASK) + 1;
> 


^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 26/46] mm/mmu_gather: fix flushing ranges with 4 GiB or larger
  2026-10-26 23:17 ` [PATCH 26/46] mm/mmu_gather: fix flushing ranges with 4 GiB or larger David Hildenbrand (Arm)
  2026-10-27  3:06   ` Qi Zheng
  2026-10-27  3:40   ` Gregory Price
@ 2026-10-27  7:35   ` Dev Jain
  2026-10-27  9:50   ` Muchun Song
  3 siblings, 0 replies; 93+ messages in thread
From: Dev Jain @ 2026-10-27  7:35 UTC (permalink / raw)
  To: David Hildenbrand (Arm),
	Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, Josef Bacik, stable



On 27/10/26 4:47 am, David Hildenbrand (Arm) wrote:
> From: Josef Bacik <josef@toxicpanda.com>
> 
> __tlb_adjust_range() takes the size of the range which has to be flushed
> as an unsigned int. Its callers, tlb_flush_{pte,pmd,pud,p4d}_range(), get
> and pass an unsigned long. Consequently, a range that is 4 GiB or larger
> gets truncated, possibly to 0.
> 
> On arm64 with hugetlb, a 64k kernel can flush 16 GiB hugetlb PMDs, and a

Nit: this wasn't obvious to me. Better expressed as:
"a 64K kernel can have 16 GiB hugepage mapped contiguously at the PMD level"


> 16k kernel can flush 64 GiB PUDs through tlb_unshare_pmd_ptdesc(). So
> at least these two scenarios are affected.
> 
> Fix it by flushing the proper range instead of the truncated one.

Nit: after reading this I thought you are passing some other parameter now.
But that is just a type change.


> 
> Fix generated by an LLM and sent by Josef Bacik in private.
> 
> Fixes: b528e4b6405b ("mm/hugetlb: add tlb_remove_hugetlb_entry for handling hugetlb pages")
> Fixes: 8ce720d5bd91 ("mm/hugetlb: fix excessive IPI broadcasts when unsharing PMD tables using mmu_gather")
> Cc: stable@vger.kernel.org
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>
> Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
> [ david: use two-tab indent, simplify description ]
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
> ---

Reviewed-by: Dev Jain <dev.jain@arm.com>


>  include/asm-generic/tlb.h | 3 +--
>  1 file changed, 1 insertion(+), 2 deletions(-)
> 
> diff --git a/include/asm-generic/tlb.h b/include/asm-generic/tlb.h
> index fbe1114e9a443..3f4a180b48f3c 100644
> --- a/include/asm-generic/tlb.h
> +++ b/include/asm-generic/tlb.h
> @@ -350,8 +350,7 @@ struct mmu_gather {
>  void tlb_flush_mmu(struct mmu_gather *tlb);
>  
>  static inline void __tlb_adjust_range(struct mmu_gather *tlb,
> -				      unsigned long address,
> -				      unsigned int range_size)
> +		unsigned long address, unsigned long range_size)
>  {
>  	tlb->start = min(tlb->start, address);
>  	tlb->end = max(tlb->end, address + range_size);
> 


^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 01/46] mm/mglru: don't use stack pointers when walking PUD and PMD tables
  2026-10-26 23:17 ` [PATCH 01/46] mm/mglru: don't use stack pointers when walking PUD and PMD tables David Hildenbrand (Arm)
                     ` (2 preceding siblings ...)
  2026-10-27  7:20   ` Dev Jain
@ 2026-10-27  8:06   ` Lorenzo Stoakes (ARM)
  2026-10-27 10:22   ` Kairui Song
  4 siblings, 0 replies; 93+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-10-27  8:06 UTC (permalink / raw)
  To: David Hildenbrand (Arm)
  Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Kairui Song, Barry Song, Axel Rasmussen,
	Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang, Liam R. Howlett,
	Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
	Kees Cook, Peter Zijlstra, Jann Horn, Pedro Falcato,
	Hugh Dickins, Pasha Tatashin, Pratyush Yadav,
	Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe, linux-mm, linux-kernel,
	kexec, linux-fsdevel, linux-arch, linux-cxl, Josef Bacik, stable

On Tue, Oct 27, 2026 at 12:17:21AM +0100, David Hildenbrand (Arm) wrote:
> From: Josef Bacik <josef@toxicpanda.com>
>
> MGLRU passes stack copies of page-table entries in walk_pud_range() and
> walk_pmd_range() when walking to the next level. These copies can become
> stale when khugepaged or MADV_DONTNEED (CONFIG_PT_RECLAIM) removes a PTE
> table concurrently.
>
> This pattern dates back to commit bd74fdaea146 ("mm: multi-gen LRU:
> support page table walks"). Likely, earlier locking masked the latent
> bug. Later changes exposed it: commit 1d65b771bc08 ("mm/khugepaged:
> retract_page_tables() without mmap or vma lock") allowed concurrent
> retraction, and commit cf4a65539c13 ("memcg-v1: no need for memcg locking
> for MGLRU") dropped the walker's outer RCU protection.
>
> The fix is simple, so just fix the original commit so we don't have to
> speculate. To fix it, pass the actual PMD/PUD pointers. This restores the
> RCU-protected lookup and validation against the live PMD. Note that the PUD
> handling is required as well to handle folded page tables correctly in all
> cases.
>
> Fix generated by an LLM and sent by Josef Bacik in private.
>
> Fixes: bd74fdaea146 ("mm: multi-gen LRU: support page table walks")
> Cc: stable@vger.kernel.org
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>
> [ david: handle walk_pud_range() as well, clarify+simplify description,
>          adjust Fixes: ]
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
> ---

God, terrible. And why does MGLRU feel it needs its own independent page
walking mechanism?... the whole thing feels like NIH syndrome writ large.

Anyway, rant aside:

Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>

>  mm/vmscan.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/mm/vmscan.c b/mm/vmscan.c
> index 9959ca158ce83..6a1af9b92349f 100644
> --- a/mm/vmscan.c
> +++ b/mm/vmscan.c
> @@ -3911,7 +3911,7 @@ static void walk_pmd_range(pud_t *pud, unsigned long start, unsigned long end,
>
>  		walk->mm_stats[MM_NONLEAF_FOUND]++;
>
> -		if (!walk_pte_range(&val, addr, next, args))
> +		if (!walk_pte_range(pmd + i, addr, next, args))
>  			continue;
>
>  		walk->mm_stats[MM_NONLEAF_ADDED]++;
> @@ -3947,7 +3947,7 @@ static int walk_pud_range(p4d_t *p4d, unsigned long start, unsigned long end,
>  		if (!pud_present(val) || WARN_ON_ONCE(pud_leaf(val)))
>  			continue;
>
> -		walk_pmd_range(&val, addr, next, args);
> +		walk_pmd_range(pud + i, addr, next, args);
>
>  		if (need_resched() || walk->batched >= MAX_LRU_BATCH) {
>  			end = (addr | ~PUD_MASK) + 1;
>
> --
> 2.43.0
>

--
Cheers, Lorenzo

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 03/46] mm/memfd: check for real shmem inodes before accessing shmem state
  2026-10-26 23:17 ` [PATCH 03/46] mm/memfd: check for real shmem inodes before accessing shmem state David Hildenbrand (Arm)
  2026-10-27  2:04   ` Rik van Riel
@ 2026-10-27  8:13   ` Mike Rapoport
  1 sibling, 0 replies; 93+ messages in thread
From: Mike Rapoport @ 2026-10-27  8:13 UTC (permalink / raw)
  To: David Hildenbrand (Arm)
  Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Suren Baghdasaryan,
	Michal Hocko, Kees Cook, Peter Zijlstra, Jann Horn,
	Pedro Falcato, Hugh Dickins, Pasha Tatashin, Pratyush Yadav,
	Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe, linux-mm, linux-kernel,
	kexec, linux-fsdevel, linux-arch, linux-cxl, stable, Chris Mason

On Tue, Oct 27, 2026 at 12:17:23AM +0100, David Hildenbrand (Arm) wrote:
> shmem_file() only checks a file's backing mapping. That mapping can belong
> to another file, as with a Coda file backed by a tmpfs container after
> mmap(). It does not establish that file_inode(file) is a shmem inode.
> 
> Seal handling and memfd preservation use this check before accessing
> shmem inode state, so they can access an inode of the wrong type.
> 
> Add file_inode_is_shmem() to check the inode's file operations in both
> paths. This identifies regular shmem inodes, including those used by
> memfds and ordinary tmpfs files, independently of wrapper file operations.
> 
> Fixes: c49fcfcda8b5 ("mm/shmem: update file sealing comments and file checking")
> Fixes: b3749f174d68 ("mm: memfd_luo: allow preserving memfd")
> Cc: stable@vger.kernel.org
> Reported-by: Chris Mason <mason@kernel.org>
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>

Reviewed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>

With a small nit below

> ---
>  include/linux/shmem_fs.h | 6 ++++++
>  mm/memfd.c               | 8 +++++---
>  mm/memfd_luo.c           | 2 +-
>  mm/shmem.c               | 5 +++++
>  4 files changed, 17 insertions(+), 4 deletions(-)
> 
> diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h
> index a7c7a96a7cbf9..2ceca7993e4f5 100644
> --- a/include/linux/shmem_fs.h
> +++ b/include/linux/shmem_fs.h
> @@ -117,8 +117,14 @@ extern unsigned long shmem_get_unmapped_area(struct file *, unsigned long addr,
>  		unsigned long len, unsigned long pgoff, unsigned long flags);
>  extern int shmem_lock(struct file *file, int lock, struct ucounts *ucounts);
>  #ifdef CONFIG_SHMEM
> +bool file_inode_is_shmem(const struct inode *inode);

Do we really need the file_ prefix in this name?

>  bool shmem_mapping(const struct address_space *mapping);

-- 
Sincerely yours,
Mike.

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 04/46] mm/memfd: make f_pos accesses atomic
  2026-10-26 23:17 ` [PATCH 04/46] mm/memfd: make f_pos accesses atomic David Hildenbrand (Arm)
  2026-10-27  2:06   ` Rik van Riel
  2026-10-27  3:34   ` Gregory Price
@ 2026-10-27  8:15   ` Mike Rapoport
  2026-10-27  8:46   ` Lorenzo Stoakes (ARM)
  2026-10-27 10:39   ` Pedro Falcato
  4 siblings, 0 replies; 93+ messages in thread
From: Mike Rapoport @ 2026-10-27  8:15 UTC (permalink / raw)
  To: David Hildenbrand (Arm)
  Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Suren Baghdasaryan,
	Michal Hocko, Kees Cook, Peter Zijlstra, Jann Horn,
	Pedro Falcato, Hugh Dickins, Pasha Tatashin, Pratyush Yadav,
	Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe, linux-mm, linux-kernel,
	kexec, linux-fsdevel, linux-arch, linux-cxl, Josef Bacik, stable

On Tue, Oct 27, 2026 at 12:17:24AM +0100, David Hildenbrand (Arm) wrote:
> From: Josef Bacik <josef@toxicpanda.com>
> 
> Commit 9c225f2655e3 ("vfs: atomic f_pos accesses as per POSIX") made
> read(), write() and lseek() on a shared open file description of a regular
> file serialize on ->f_pos_lock.  The flag that asks for it,
> FMODE_ATOMIC_POS, is set in do_dentry_open().  A memfd is a regular file
> too, but its struct file comes from alloc_file_pseudo() and never passes
> through do_dentry_open(), so it does not get the flag:
> 
>   CPU0                                CPU1
>   write(memfd, "a", 1)                write(memfd, "b", 1)
>     pos = file->f_pos  (= 0)
>                                         pos = file->f_pos  (= 0)
>     vfs_write(..., &pos)
>                                         vfs_write(..., &pos)
>     file->f_pos = pos  (= 1)
>                                         file->f_pos = pos  (= 1)
> 
> One of the two bytes is overwritten.  Two threads writing 100000 bytes
> each, one at a time, to a memfd end up with a file that is far shorter than
> 200000 bytes, while the same program on a tmpfs file never loses a byte.
> 
> Set the flag when the memfd is created.  As for any other regular file the
> lock is only taken if the file is reachable in more than one way, and
> nothing a memfd does in read or write waits for another operation on the
> same file.  This cannot be done for all alloc_file_pseudo() files: anon
> inode files such as eventfd are S_IFREG as well, and a blocked read holding
> ->f_pos_lock would lock out the write that is supposed to wake it.
> 
> Fix generated by an LLM and sent by Josef Bacik in private.
> 
> Fixes: 9183df25fe7b ("shm: add memfd_create() syscall")
> Cc: stable@vger.kernel.org
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>
> [ david: minor description tweaks ]
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>

Reviewed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>

> ---
>  mm/memfd.c | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/mm/memfd.c b/mm/memfd.c
> index 7d2da23157003..6f5fbce74f21e 100644
> --- a/mm/memfd.c
> +++ b/mm/memfd.c
> @@ -484,6 +484,8 @@ struct file *memfd_alloc_file(const char *name, unsigned int flags)
>  	}
>  
>  	file->f_mode |= FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE;
> +	/* a regular file like any other: POSIX.1-2008/SUSv4 Section XSI 2.9.7 */
> +	file->f_mode |= FMODE_ATOMIC_POS;
>  	file->f_flags |= O_LARGEFILE;
>  
>  	if (flags & MFD_NOEXEC_SEAL) {
> 
> -- 
> 2.43.0
> 

-- 
Sincerely yours,
Mike.

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 23/46] mm/userfaultfd: write-lock the VMA before waking waiters when unregistering
  2026-10-26 23:17 ` [PATCH 23/46] mm/userfaultfd: write-lock the VMA before waking waiters when unregistering David Hildenbrand (Arm)
@ 2026-10-27  8:16   ` Mike Rapoport
  2026-10-27  8:43   ` Lorenzo Stoakes (ARM)
  1 sibling, 0 replies; 93+ messages in thread
From: Mike Rapoport @ 2026-10-27  8:16 UTC (permalink / raw)
  To: David Hildenbrand (Arm)
  Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Suren Baghdasaryan,
	Michal Hocko, Kees Cook, Peter Zijlstra, Jann Horn,
	Pedro Falcato, Hugh Dickins, Pasha Tatashin, Pratyush Yadav,
	Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe, linux-mm, linux-kernel,
	kexec, linux-fsdevel, linux-arch, linux-cxl, stable, Josef Bacik

On Tue, Oct 27, 2026 at 12:17:43AM +0100, David Hildenbrand (Arm) wrote:
> userfaultfd_unregister() wakes pending missing faults before clearing the
> VMA's userfaultfd registration. With per-VMA fault locking, holding
> mmap_lock for write does not prevent another fault from queuing after
> the wakeup but before userfaultfd_clear_vma() write-locks the VMA. That
> waiter can then remain asleep indefinitely.
> 
> Call vma_start_write() before waking waiters. Existing fault handlers
> queue themselves before dropping the VMA read lock, and new readers are
> excluded until mmap_write_unlock().
> 
> Fixes: 29a22b9e08d7 ("mm: handle userfaults under VMA lock")
> Cc: stable@vger.kernel.org
> Reported-by: Josef Bacik <josef@toxicpanda.com>
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>

Reviewed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>

> ---
>  mm/userfaultfd.c | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
> index 669f71d485d02..7e30b5ff17be1 100644
> --- a/mm/userfaultfd.c
> +++ b/mm/userfaultfd.c
> @@ -3991,6 +3991,9 @@ static int userfaultfd_unregister(struct userfaultfd_ctx *ctx,
>  			start = vma->vm_start;
>  		vma_end = min(end, vma->vm_end);
>  
> +		/* Prevent new userfaults from being queued after the wakeup. */
> +		vma_start_write(vma);
> +
>  		if (userfaultfd_missing(vma)) {
>  			/*
>  			 * Wake any concurrent pending userfault while
> 
> -- 
> 2.43.0
> 

-- 
Sincerely yours,
Mike.

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 24/46] mm/userfaultfd: wake all waiters on unregister
  2026-10-26 23:17 ` [PATCH 24/46] mm/userfaultfd: wake all waiters on unregister David Hildenbrand (Arm)
@ 2026-10-27  8:17   ` Mike Rapoport
  2026-10-27  8:36   ` Lorenzo Stoakes (ARM)
  1 sibling, 0 replies; 93+ messages in thread
From: Mike Rapoport @ 2026-10-27  8:17 UTC (permalink / raw)
  To: David Hildenbrand (Arm)
  Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Suren Baghdasaryan,
	Michal Hocko, Kees Cook, Peter Zijlstra, Jann Horn,
	Pedro Falcato, Hugh Dickins, Pasha Tatashin, Pratyush Yadav,
	Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe, linux-mm, linux-kernel,
	kexec, linux-fsdevel, linux-arch, linux-cxl, Josef Bacik, stable

On Tue, Oct 27, 2026 at 12:17:44AM +0100, David Hildenbrand (Arm) wrote:
> From: Josef Bacik <josef@toxicpanda.com>
> 
> UFFDIO_UNREGISTER only wakes pending faults if VM_UFFD_MISSING is set.
> Threads waiting on write-protect, minor or RWP faults can therefore remain
> asleep after unregistering a range that does not track missing faults.
> 
> Wake pending faults regardless of the registration mode so they can retry
> without an explicit UFFDIO_WAKE or closing the userfaultfd. This matches
> the existing behavior for missing faults, including removing unread fault
> messages for the woken waiters.
> 
> Fix generated by an LLM and sent by Josef Bacik in private.
> 
> Fixes: 63b2d4174c4a ("userfaultfd: wp: add the writeprotect API to userfaultfd ioctl")
> Cc: stable@vger.kernel.org
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>
> [ david: rebase; simplify description ]
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>

Reviewed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>

> ---
>  mm/userfaultfd.c | 22 ++++++++++------------
>  1 file changed, 10 insertions(+), 12 deletions(-)
> 
> diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
> index 7e30b5ff17be1..2122676c4220f 100644
> --- a/mm/userfaultfd.c
> +++ b/mm/userfaultfd.c
> @@ -3977,6 +3977,8 @@ static int userfaultfd_unregister(struct userfaultfd_ctx *ctx,
>  
>  	ret = 0;
>  	for_each_vma_range(vmi, vma, end) {
> +		struct userfaultfd_wake_range range;
> +
>  		cond_resched();
>  
>  		/* VMA not registered with userfaultfd. */
> @@ -3994,18 +3996,14 @@ static int userfaultfd_unregister(struct userfaultfd_ctx *ctx,
>  		/* Prevent new userfaults from being queued after the wakeup. */
>  		vma_start_write(vma);
>  
> -		if (userfaultfd_missing(vma)) {
> -			/*
> -			 * Wake any concurrent pending userfault while
> -			 * we unregister, so they will not hang
> -			 * permanently and it avoids userland to call
> -			 * UFFDIO_WAKE explicitly.
> -			 */
> -			struct userfaultfd_wake_range range;
> -			range.start = start;
> -			range.len = vma_end - start;
> -			wake_userfault(vma->vm_userfaultfd_ctx.ctx, &range);
> -		}
> +		/*
> +		 * Wake any concurrent pending userfault while we unregister,
> +		 * so they will not hang permanently and it avoids userland to
> +		 * call UFFDIO_WAKE explicitly.
> +		 */
> +		range.start = start;
> +		range.len = vma_end - start;
> +		wake_userfault(ctx, &range);
>  
>  		vma = userfaultfd_clear_vma(&vmi, prev, vma,
>  					    start, vma_end);
> 
> -- 
> 2.43.0
> 

-- 
Sincerely yours,
Mike.

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 02/46] fork: take mmap_lock before copying mm_struct
  2026-10-26 23:17 ` [PATCH 02/46] fork: take mmap_lock before copying mm_struct David Hildenbrand (Arm)
  2026-10-27  1:38   ` Rik van Riel
@ 2026-10-27  8:18   ` Vlastimil Babka (SUSE)
  2026-10-27  9:45   ` Barry Song
  2026-10-27 10:38   ` Pedro Falcato
  3 siblings, 0 replies; 93+ messages in thread
From: Vlastimil Babka (SUSE) @ 2026-10-27  8:18 UTC (permalink / raw)
  To: David Hildenbrand (Arm),
	Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
	Kees Cook, Peter Zijlstra, Jann Horn, Pedro Falcato,
	Hugh Dickins, Pasha Tatashin, Pratyush Yadav,
	Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe
  Cc: linux-mm, linux-kernel, kexec, linux-fsdevel, linux-arch,
	linux-cxl, stable, Josef Bacik

On 10/27/26 00:17, David Hildenbrand (Arm) wrote:
> dup_mm() copies the parent's mm_struct before dup_mmap() takes the
> mmap_lock. A concurrent brk() can leave the child with a stale mm->brk
> and newer heap mappings, causing later brk() requests to fail.
> 
> Other operations (e.g., PR_SET_MM) on the parent's mm_struct can similarly
> cause inconsistencies.
> 
> As a simple and robust fix, grab the parent's mmap_lock earlier. This
> way we don't need to update individual mm fields in dup_mmap() and
> keep missing ones. Stop updating the 4 existing members (total_vm, data_vm,
> exec_vm, stack_vm), as that is now no longer required.
> 
> Keep releasing the parent's mmap_lock in dup_mmap(), before
> userfaultfd completion, to avoid moving the userfaultfd handling into the
> caller. This should get cleaned up later.
> 
> Move uprobe_start_dup_mmap() to preserve the lock ordering.
> 
> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Cc: stable@vger.kernel.org
> Reported-by: Josef Bacik <josef@toxicpanda.com>
> Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>

Reviewed-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>

> ---
>  kernel/fork.c | 20 ++++++++++++++------
>  mm/mmap.c     |  8 +-------
>  mm/nommu.c    |  2 +-
>  3 files changed, 16 insertions(+), 14 deletions(-)
> 
> diff --git a/kernel/fork.c b/kernel/fork.c
> index 22eaf5fb844d0..c8948cadccf71 100644
> --- a/kernel/fork.c
> +++ b/kernel/fork.c
> @@ -1532,12 +1532,19 @@ static struct mm_struct *dup_mm(struct task_struct *tsk,
>  	if (!mm)
>  		goto fail_nomem;
>  
> +	uprobe_start_dup_mmap();
> +	if (mmap_write_lock_killable(oldmm)) {
> +		free_mm(mm);
> +		goto fail_uprobe;
> +	}
> +
>  	memcpy(mm, oldmm, sizeof(*mm));
>  
> -	if (!mm_init(mm, tsk))
> -		goto fail_nomem;
> +	if (!mm_init(mm, tsk)) {
> +		mmap_write_unlock(oldmm);
> +		goto fail_uprobe;
> +	}
>  
> -	uprobe_start_dup_mmap();
>  	err = dup_mmap(mm, oldmm);
>  	if (err)
>  		goto free_pt;
> @@ -1556,9 +1563,10 @@ static struct mm_struct *dup_mm(struct task_struct *tsk,
>  	mm->binfmt = NULL;
>  	mm_init_owner(mm, NULL);
>  	mmput(mm);
> -	if (err)
> -		uprobe_end_dup_mmap();
> -
> +	if (!err)
> +		return NULL;
> +fail_uprobe:
> +	uprobe_end_dup_mmap();
>  fail_nomem:
>  	return NULL;
>  }
> diff --git a/mm/mmap.c b/mm/mmap.c
> index 148ba01c03739..7618e72766a52 100644
> --- a/mm/mmap.c
> +++ b/mm/mmap.c
> @@ -1713,8 +1713,7 @@ __latent_entropy int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
>  	LIST_HEAD(uf);
>  	VMA_ITERATOR(vmi, mm, 0);
>  
> -	if (mmap_write_lock_killable(oldmm))
> -		return -EINTR;
> +	mmap_assert_write_locked(oldmm);
>  	flush_cache_dup_mm(oldmm);
>  	uprobe_dup_mmap(oldmm, mm);
>  	/*
> @@ -1725,11 +1724,6 @@ __latent_entropy int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
>  	/* No ordering required: file already has been exposed. */
>  	dup_mm_exe_file(mm, oldmm);
>  
> -	mm->total_vm = oldmm->total_vm;
> -	mm->data_vm = oldmm->data_vm;
> -	mm->exec_vm = oldmm->exec_vm;
> -	mm->stack_vm = oldmm->stack_vm;
> -
>  	/* Use __mt_dup() to efficiently build an identical maple tree. */
>  	retval = __mt_dup(&oldmm->mm_mt, &mm->mm_mt, GFP_KERNEL);
>  	if (unlikely(retval))
> diff --git a/mm/nommu.c b/mm/nommu.c
> index ed44510e37707..6e0f9c7da2364 100644
> --- a/mm/nommu.c
> +++ b/mm/nommu.c
> @@ -1926,7 +1926,7 @@ subsys_initcall(init_admin_reserve);
>  
>  int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
>  {
> -	mmap_write_lock(oldmm);
> +	mmap_assert_write_locked(oldmm);
>  	dup_mm_exe_file(mm, oldmm);
>  	mmap_write_unlock(oldmm);
>  	return 0;
> 


^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 25/46] mm/userfaultfd: wake waiters when registration modes are removed
  2026-10-26 23:17 ` [PATCH 25/46] mm/userfaultfd: wake waiters when registration modes are removed David Hildenbrand (Arm)
  2026-10-27  5:10   ` Gregory Price
@ 2026-10-27  8:21   ` Mike Rapoport
  2026-10-27  8:31   ` Lorenzo Stoakes (ARM)
  2 siblings, 0 replies; 93+ messages in thread
From: Mike Rapoport @ 2026-10-27  8:21 UTC (permalink / raw)
  To: David Hildenbrand (Arm)
  Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Suren Baghdasaryan,
	Michal Hocko, Kees Cook, Peter Zijlstra, Jann Horn,
	Pedro Falcato, Hugh Dickins, Pasha Tatashin, Pratyush Yadav,
	Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe, linux-mm, linux-kernel,
	kexec, linux-fsdevel, linux-arch, linux-cxl, stable

On Tue, Oct 27, 2026 at 12:17:45AM +0100, David Hildenbrand (Arm) wrote:
> UFFDIO_REGISTER can replace MISSING or MINOR tracking without waking
> faults that are already queued. For example, switching an anonymous
> range from MISSING to WP leaves a missing-fault waiter asleep until
> userspace explicitly wakes it.
> 
> When a registration change removes a UFFD mode, wake waiters in the
> affected interval after updating the VMA. The VMA is write-locked at
> this point, so no new faults can queue under the old modes and woken
> threads cannot retry until mmap_write_unlock(). Waiters for retained
> modes in the same interval may also wake and refault.
> 
> The hang reproduces for MISSING-to-WP and MINOR-to-MISSING transitions,
> with both read and unread fault events.
> 
> Fixes: 63b2d4174c4a ("userfaultfd: wp: add the writeprotect API to userfaultfd ioctl")
> Cc: stable@vger.kernel.org
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>

Reviewed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>

> ---
>  mm/userfaultfd.c | 20 ++++++++++++++++++++
>  1 file changed, 20 insertions(+)

-- 
Sincerely yours,
Mike.

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 25/46] mm/userfaultfd: wake waiters when registration modes are removed
  2026-10-27  5:10   ` Gregory Price
@ 2026-10-27  8:24     ` Lorenzo Stoakes (ARM)
  0 siblings, 0 replies; 93+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-10-27  8:24 UTC (permalink / raw)
  To: Gregory Price
  Cc: David Hildenbrand (Arm),
	Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Kairui Song, Barry Song, Axel Rasmussen,
	Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang, Liam R. Howlett,
	Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
	Kees Cook, Peter Zijlstra, Jann Horn, Pedro Falcato,
	Hugh Dickins, Pasha Tatashin, Pratyush Yadav,
	Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Joshua Hahn, Rakie Kim,
	Ying Huang, Jason Gunthorpe, linux-mm, linux-kernel, kexec,
	linux-fsdevel, linux-arch, linux-cxl, stable

On Mon, Oct 26, 2026 at 10:10:24PM -0700, Gregory Price wrote:
> From: Gregory Price <gourry@gourry.net>
> Subject: [PATCH] mm/userfaultfd: compare exact registration modes before skipping
>
> Changing registration from MISSING|WP to WP returns success but leaves
> MISSING enabled. The no-op check sees that WP is already set and skips
> the update, so later accesses to missing pages still wait for userspace.
>
> Skip the update only when the current and requested UFFD modes match
> exactly.
>
> Fixes: 63b2d4174c4a ("userfaultfd: wp: add the writeprotect API to userfaultfd ioctl")
> Cc: stable@vger.kernel.org
> Signed-off-by: Gregory Price (Meta) <gourry@gourry.net>
> ---
>  mm/userfaultfd.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
> index 669f71d485d02..0a28130cebc99 100644
> --- a/mm/userfaultfd.c
> +++ b/mm/userfaultfd.c
> @@ -2299,7 +2299,7 @@ static int userfaultfd_register_range(struct userfaultfd_ctx *ctx,
>  		 * userfaultfd and with the right tracking mode too.
>  		 */
>  		if (vma->vm_userfaultfd_ctx.ctx == ctx &&
> -		    vma_test_all_mask(vma, vma_flags))
> +		    (vma->vm_flags & __VM_UFFD_FLAGS) == vm_flags)

Would be better not to regress to the legacy API. I realise we don't use it for
backported fixes in general, but this patch obviously won't apply to older
versions anyway, so we should use the correct API now, and this for older
versions.

I'll add a better predicate probably to do this in one go, but for the fix,
I put the correct patch below.


>  			goto skip;
>
>  		/*
>
> --
> Gregory Price <gourry@gourry.net>

diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
index 777bf122d32a..c71cb9179913 100644
--- a/mm/userfaultfd.c
+++ b/mm/userfaultfd.c
@@ -2288,6 +2288,9 @@ static int userfaultfd_register_range(struct userfaultfd_ctx *ctx,
 		prev = vma;

 	for_each_vma_range(vmi, vma, end) {
+		const vma_flags_t curr_vma_flags =
+			vma_flags_and_mask(&vma->flags, __VMA_UFFD_FLAGS);
+
 		cond_resched();

 		VM_WARN_ON_ONCE(!vma_can_userfault(vma, vm_flags, wp_async));
@@ -2300,7 +2303,7 @@ static int userfaultfd_register_range(struct userfaultfd_ctx *ctx,
 		 * userfaultfd and with the right tracking mode too.
 		 */
 		if (vma->vm_userfaultfd_ctx.ctx == ctx &&
-		    vma_test_all_mask(vma, vma_flags))
+		    vma_flags_same_pair(&curr_vma_flags, &vma_flags))
 			goto skip;

 		/*

--
Cheers, Lorenzo

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 25/46] mm/userfaultfd: wake waiters when registration modes are removed
  2026-10-26 23:17 ` [PATCH 25/46] mm/userfaultfd: wake waiters when registration modes are removed David Hildenbrand (Arm)
  2026-10-27  5:10   ` Gregory Price
  2026-10-27  8:21   ` Mike Rapoport
@ 2026-10-27  8:31   ` Lorenzo Stoakes (ARM)
  2 siblings, 0 replies; 93+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-10-27  8:31 UTC (permalink / raw)
  To: David Hildenbrand (Arm)
  Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Kairui Song, Barry Song, Axel Rasmussen,
	Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang, Liam R. Howlett,
	Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
	Kees Cook, Peter Zijlstra, Jann Horn, Pedro Falcato,
	Hugh Dickins, Pasha Tatashin, Pratyush Yadav,
	Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe, linux-mm, linux-kernel,
	kexec, linux-fsdevel, linux-arch, linux-cxl, stable

On Tue, Oct 27, 2026 at 12:17:45AM +0100, David Hildenbrand (Arm) wrote:
> UFFDIO_REGISTER can replace MISSING or MINOR tracking without waking
> faults that are already queued. For example, switching an anonymous
> range from MISSING to WP leaves a missing-fault waiter asleep until
> userspace explicitly wakes it.

I assume this is something people basically never do because you'd think it'd be
a pretty obvious bug report right?

>
> When a registration change removes a UFFD mode, wake waiters in the
> affected interval after updating the VMA. The VMA is write-locked at
> this point, so no new faults can queue under the old modes and woken
> threads cannot retry until mmap_write_unlock(). Waiters for retained
> modes in the same interval may also wake and refault.

Oh good lord.

>
> The hang reproduces for MISSING-to-WP and MINOR-to-MISSING transitions,
> with both read and unread fault events.
>
> Fixes: 63b2d4174c4a ("userfaultfd: wp: add the writeprotect API to userfaultfd ioctl")
> Cc: stable@vger.kernel.org
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>

In the words of Metallica, the more I see, the less, the less I believe...

Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>

> ---
>  mm/userfaultfd.c | 20 ++++++++++++++++++++
>  1 file changed, 20 insertions(+)
>
> diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
> index 2122676c4220f..710e913c73bfa 100644
> --- a/mm/userfaultfd.c
> +++ b/mm/userfaultfd.c
> @@ -2270,6 +2270,9 @@ static struct vm_area_struct *userfaultfd_clear_vma(struct vma_iterator *vmi,
>  	return ret;
>  }
>
> +static void wake_userfault_range(struct userfaultfd_ctx *ctx,
> +		unsigned long start, unsigned long end);
> +
>  /* Assumes mmap write lock taken, and mm_struct pinned. */
>  static int userfaultfd_register_range(struct userfaultfd_ctx *ctx,
>  			       struct vm_area_struct *vma,
> @@ -2287,6 +2290,8 @@ static int userfaultfd_register_range(struct userfaultfd_ctx *ctx,
>  		prev = vma;
>
>  	for_each_vma_range(vmi, vma, end) {
> +		const bool any_mode_removed = vma->vm_flags & __VM_UFFD_FLAGS & ~vm_flags;
> +
>  		cond_resched();
>
>  		VM_WARN_ON_ONCE(!vma_can_userfault(vma, vm_flags, wp_async));
> @@ -2332,6 +2337,10 @@ static int userfaultfd_register_range(struct userfaultfd_ctx *ctx,
>  		 */
>  		userfaultfd_set_ctx(vma, ctx, vm_flags);
>
> +		/* Retry faults for removed modes while the VMA is write-locked. */
> +		if (any_mode_removed)
> +			wake_userfault_range(ctx, start, vma_end);
> +
>  		if (vma_is_hugetlb(vma) && uffd_disable_huge_pmd_share(vma))
>  			hugetlb_unshare_all_pmds(vma);
>
> @@ -3648,6 +3657,17 @@ static __always_inline void wake_userfault(struct userfaultfd_ctx *ctx,
>  		__wake_userfault(ctx, range);
>  }
>
> +static void wake_userfault_range(struct userfaultfd_ctx *ctx,
> +		unsigned long start, unsigned long end)
> +{
> +	struct userfaultfd_wake_range range = {
> +		.start = start,
> +		.len = end - start,
> +	};
> +
> +	wake_userfault(ctx, &range);
> +}
> +
>  static __always_inline int validate_unaligned_range(
>  	struct mm_struct *mm, __u64 start, __u64 len)
>  {
>
> --
> 2.43.0
>

--
Cheers, Lorenzo

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 24/46] mm/userfaultfd: wake all waiters on unregister
  2026-10-26 23:17 ` [PATCH 24/46] mm/userfaultfd: wake all waiters on unregister David Hildenbrand (Arm)
  2026-10-27  8:17   ` Mike Rapoport
@ 2026-10-27  8:36   ` Lorenzo Stoakes (ARM)
  1 sibling, 0 replies; 93+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-10-27  8:36 UTC (permalink / raw)
  To: David Hildenbrand (Arm)
  Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Kairui Song, Barry Song, Axel Rasmussen,
	Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang, Liam R. Howlett,
	Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
	Kees Cook, Peter Zijlstra, Jann Horn, Pedro Falcato,
	Hugh Dickins, Pasha Tatashin, Pratyush Yadav,
	Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe, linux-mm, linux-kernel,
	kexec, linux-fsdevel, linux-arch, linux-cxl, Josef Bacik, stable

On Tue, Oct 27, 2026 at 12:17:44AM +0100, David Hildenbrand (Arm) wrote:
> From: Josef Bacik <josef@toxicpanda.com>
>
> UFFDIO_UNREGISTER only wakes pending faults if VM_UFFD_MISSING is set.
> Threads waiting on write-protect, minor or RWP faults can therefore remain
> asleep after unregistering a range that does not track missing faults.
>
> Wake pending faults regardless of the registration mode so they can retry
> without an explicit UFFDIO_WAKE or closing the userfaultfd. This matches
> the existing behavior for missing faults, including removing unread fault
> messages for the woken waiters.
>
> Fix generated by an LLM and sent by Josef Bacik in private.
>
> Fixes: 63b2d4174c4a ("userfaultfd: wp: add the writeprotect API to userfaultfd ioctl")
> Cc: stable@vger.kernel.org
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>
> [ david: rebase; simplify description ]
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>

Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>

> ---
>  mm/userfaultfd.c | 22 ++++++++++------------
>  1 file changed, 10 insertions(+), 12 deletions(-)
>
> diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
> index 7e30b5ff17be1..2122676c4220f 100644
> --- a/mm/userfaultfd.c
> +++ b/mm/userfaultfd.c
> @@ -3977,6 +3977,8 @@ static int userfaultfd_unregister(struct userfaultfd_ctx *ctx,
>
>  	ret = 0;
>  	for_each_vma_range(vmi, vma, end) {
> +		struct userfaultfd_wake_range range;
> +
>  		cond_resched();
>
>  		/* VMA not registered with userfaultfd. */
> @@ -3994,18 +3996,14 @@ static int userfaultfd_unregister(struct userfaultfd_ctx *ctx,
>  		/* Prevent new userfaults from being queued after the wakeup. */
>  		vma_start_write(vma);
>
> -		if (userfaultfd_missing(vma)) {
> -			/*
> -			 * Wake any concurrent pending userfault while
> -			 * we unregister, so they will not hang
> -			 * permanently and it avoids userland to call
> -			 * UFFDIO_WAKE explicitly.
> -			 */
> -			struct userfaultfd_wake_range range;
> -			range.start = start;
> -			range.len = vma_end - start;
> -			wake_userfault(vma->vm_userfaultfd_ctx.ctx, &range);
> -		}
> +		/*
> +		 * Wake any concurrent pending userfault while we unregister,
> +		 * so they will not hang permanently and it avoids userland to
> +		 * call UFFDIO_WAKE explicitly.
> +		 */
> +		range.start = start;
> +		range.len = vma_end - start;
> +		wake_userfault(ctx, &range);
>
>  		vma = userfaultfd_clear_vma(&vmi, prev, vma,
>  					    start, vma_end);
>
> --
> 2.43.0
>

--
Cheers, Lorenzo

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 23/46] mm/userfaultfd: write-lock the VMA before waking waiters when unregistering
  2026-10-26 23:17 ` [PATCH 23/46] mm/userfaultfd: write-lock the VMA before waking waiters when unregistering David Hildenbrand (Arm)
  2026-10-27  8:16   ` Mike Rapoport
@ 2026-10-27  8:43   ` Lorenzo Stoakes (ARM)
  1 sibling, 0 replies; 93+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-10-27  8:43 UTC (permalink / raw)
  To: David Hildenbrand (Arm)
  Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Kairui Song, Barry Song, Axel Rasmussen,
	Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang, Liam R. Howlett,
	Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
	Kees Cook, Peter Zijlstra, Jann Horn, Pedro Falcato,
	Hugh Dickins, Pasha Tatashin, Pratyush Yadav,
	Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe, linux-mm, linux-kernel,
	kexec, linux-fsdevel, linux-arch, linux-cxl, stable, Josef Bacik

On Tue, Oct 27, 2026 at 12:17:43AM +0100, David Hildenbrand (Arm) wrote:
> userfaultfd_unregister() wakes pending missing faults before clearing the
> VMA's userfaultfd registration. With per-VMA fault locking, holding
> mmap_lock for write does not prevent another fault from queuing after
> the wakeup but before userfaultfd_clear_vma() write-locks the VMA. That
> waiter can then remain asleep indefinitely.

Oof.

I guess userfaultfd_clear_vma() only implicitly takes the VMA write lock via
vma_modify_flags_uffd().

>
> Call vma_start_write() before waking waiters. Existing fault handlers
> queue themselves before dropping the VMA read lock, and new readers are
> excluded until mmap_write_unlock().

Clearly an oversight from the VMA locks work. I guess was always a Herculean
task to catch every single point at which there is an implicit assumption that
mmap write lock ~ readers (esp. faults) excluded.

>
> Fixes: 29a22b9e08d7 ("mm: handle userfaults under VMA lock")
> Cc: stable@vger.kernel.org
> Reported-by: Josef Bacik <josef@toxicpanda.com>
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>

Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>

> ---
>  mm/userfaultfd.c | 3 +++
>  1 file changed, 3 insertions(+)
>
> diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
> index 669f71d485d02..7e30b5ff17be1 100644
> --- a/mm/userfaultfd.c
> +++ b/mm/userfaultfd.c
> @@ -3991,6 +3991,9 @@ static int userfaultfd_unregister(struct userfaultfd_ctx *ctx,
>  			start = vma->vm_start;
>  		vma_end = min(end, vma->vm_end);
>
> +		/* Prevent new userfaults from being queued after the wakeup. */
> +		vma_start_write(vma);
> +
>  		if (userfaultfd_missing(vma)) {
>  			/*
>  			 * Wake any concurrent pending userfault while
>
> --
> 2.43.0
>

--
Cheers, Lorenzo

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 04/46] mm/memfd: make f_pos accesses atomic
  2026-10-27  3:34   ` Gregory Price
@ 2026-10-27  8:44     ` Lorenzo Stoakes (ARM)
  0 siblings, 0 replies; 93+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-10-27  8:44 UTC (permalink / raw)
  To: Gregory Price
  Cc: David Hildenbrand (Arm),
	Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Kairui Song, Barry Song, Axel Rasmussen,
	Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang, Liam R. Howlett,
	Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
	Kees Cook, Peter Zijlstra, Jann Horn, Pedro Falcato,
	Hugh Dickins, Pasha Tatashin, Pratyush Yadav,
	Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Joshua Hahn, Rakie Kim,
	Ying Huang, Jason Gunthorpe, linux-mm, linux-kernel, kexec,
	linux-fsdevel, linux-arch, linux-cxl, Josef Bacik, stable

On Mon, Oct 26, 2026 at 08:34:28PM -0700, Gregory Price wrote:
> This one arguably should have at least a trivial selftest.

Generally, we don't include tests with fixes. So these things have to be a
follow up.

--
Cheers, Lorenzo

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 04/46] mm/memfd: make f_pos accesses atomic
  2026-10-26 23:17 ` [PATCH 04/46] mm/memfd: make f_pos accesses atomic David Hildenbrand (Arm)
                     ` (2 preceding siblings ...)
  2026-10-27  8:15   ` Mike Rapoport
@ 2026-10-27  8:46   ` Lorenzo Stoakes (ARM)
  2026-10-27 10:39   ` Pedro Falcato
  4 siblings, 0 replies; 93+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-10-27  8:46 UTC (permalink / raw)
  To: David Hildenbrand (Arm)
  Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Kairui Song, Barry Song, Axel Rasmussen,
	Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang, Liam R. Howlett,
	Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
	Kees Cook, Peter Zijlstra, Jann Horn, Pedro Falcato,
	Hugh Dickins, Pasha Tatashin, Pratyush Yadav,
	Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe, linux-mm, linux-kernel,
	kexec, linux-fsdevel, linux-arch, linux-cxl, Josef Bacik, stable

On Tue, Oct 27, 2026 at 12:17:24AM +0100, David Hildenbrand (Arm) wrote:
> From: Josef Bacik <josef@toxicpanda.com>
>
> Commit 9c225f2655e3 ("vfs: atomic f_pos accesses as per POSIX") made
> read(), write() and lseek() on a shared open file description of a regular
> file serialize on ->f_pos_lock.  The flag that asks for it,
> FMODE_ATOMIC_POS, is set in do_dentry_open().  A memfd is a regular file
> too, but its struct file comes from alloc_file_pseudo() and never passes
> through do_dentry_open(), so it does not get the flag:
>
>   CPU0                                CPU1
>   write(memfd, "a", 1)                write(memfd, "b", 1)
>     pos = file->f_pos  (= 0)
>                                         pos = file->f_pos  (= 0)
>     vfs_write(..., &pos)
>                                         vfs_write(..., &pos)
>     file->f_pos = pos  (= 1)
>                                         file->f_pos = pos  (= 1)
>
> One of the two bytes is overwritten.  Two threads writing 100000 bytes
> each, one at a time, to a memfd end up with a file that is far shorter than
> 200000 bytes, while the same program on a tmpfs file never loses a byte.
>
> Set the flag when the memfd is created.  As for any other regular file the
> lock is only taken if the file is reachable in more than one way, and
> nothing a memfd does in read or write waits for another operation on the
> same file.  This cannot be done for all alloc_file_pseudo() files: anon
> inode files such as eventfd are S_IFREG as well, and a blocked read holding
> ->f_pos_lock would lock out the write that is supposed to wake it.
>
> Fix generated by an LLM and sent by Josef Bacik in private.
>
> Fixes: 9183df25fe7b ("shm: add memfd_create() syscall")
> Cc: stable@vger.kernel.org
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>
> [ david: minor description tweaks ]
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>

Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>

> ---
>  mm/memfd.c | 2 ++
>  1 file changed, 2 insertions(+)
>
> diff --git a/mm/memfd.c b/mm/memfd.c
> index 7d2da23157003..6f5fbce74f21e 100644
> --- a/mm/memfd.c
> +++ b/mm/memfd.c
> @@ -484,6 +484,8 @@ struct file *memfd_alloc_file(const char *name, unsigned int flags)
>  	}
>
>  	file->f_mode |= FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE;
> +	/* a regular file like any other: POSIX.1-2008/SUSv4 Section XSI 2.9.7 */
> +	file->f_mode |= FMODE_ATOMIC_POS;
>  	file->f_flags |= O_LARGEFILE;
>
>  	if (flags & MFD_NOEXEC_SEAL) {
>
> --
> 2.43.0
>

--
Cheers, Lorenzo

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 28/46] mm/mmu_notifier: set ->mm only after mmgrab()
  2026-10-26 23:17 ` [PATCH 28/46] mm/mmu_notifier: set ->mm only after mmgrab() David Hildenbrand (Arm)
  2026-10-27  3:42   ` Gregory Price
@ 2026-10-27  8:50   ` Lorenzo Stoakes (ARM)
  1 sibling, 0 replies; 93+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-10-27  8:50 UTC (permalink / raw)
  To: David Hildenbrand (Arm)
  Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Kairui Song, Barry Song, Axel Rasmussen,
	Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang, Liam R. Howlett,
	Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
	Kees Cook, Peter Zijlstra, Jann Horn, Pedro Falcato,
	Hugh Dickins, Pasha Tatashin, Pratyush Yadav,
	Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe, linux-mm, linux-kernel,
	kexec, linux-fsdevel, linux-arch, linux-cxl, Chris Mason, stable

On Tue, Oct 27, 2026 at 12:17:48AM +0100, David Hildenbrand (Arm) wrote:
> From: Chris Mason <mason@kernel.org>
>
> Radeon uses a non-NULL notifier->mm to decide whether to call
> mmu_interval_notifier_remove() when freeing a buffer object.
> __mmu_interval_notifier_insert() sets ->mm before validating the range,
> so a wrapping userptr range can leave ->mm set after insertion fails.
> Cleanup then tries to remove an unregistered notifier for which no mm
> reference was acquired.
>
> Set ->mm only after mmgrab(), once insertion can no longer fail. While
> we could fix radeon's code instead, setting ->mm on success only makes
> the code more robust.
>
> Fix generated by an LLM and sent by Chris Mason in private.
>
> Fixes: 3506ff69c3ec ("drm/radeon: use mmu_interval_notifier_insert")
> Cc: stable@vger.kernel.org
> Signed-off-by: Chris Mason <mason@kernel.org>
> [ david: simplify description ]
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>

Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>

> ---
>  mm/mmu_notifier.c | 7 +++++--
>  1 file changed, 5 insertions(+), 2 deletions(-)
>
> diff --git a/mm/mmu_notifier.c b/mm/mmu_notifier.c
> index 2e20f88e162d7..a7bae5de5fedc 100644
> --- a/mm/mmu_notifier.c
> +++ b/mm/mmu_notifier.c
> @@ -947,7 +947,6 @@ static int __mmu_interval_notifier_insert(
>  	struct mmu_notifier_subscriptions *subscriptions, unsigned long start,
>  	unsigned long length, const struct mmu_interval_notifier_ops *ops)
>  {
> -	interval_sub->mm = mm;
>  	interval_sub->ops = ops;
>  	RB_CLEAR_NODE(&interval_sub->interval_tree.rb);
>  	interval_sub->interval_tree.start = start;
> @@ -964,8 +963,12 @@ static int __mmu_interval_notifier_insert(
>  	if (WARN_ON(atomic_read(&mm->mm_users) <= 0))
>  		return -EINVAL;
>
> -	/* pairs with mmdrop in mmu_interval_notifier_remove() */
> +	/*
> +	 * Pairs with mmdrop in mmu_interval_notifier_remove(). Drivers take a
> +	 * non-NULL ->mm for "registered", so set it only with the reference.
> +	 */
>  	mmgrab(mm);
> +	interval_sub->mm = mm;
>
>  	/*
>  	 * If some invalidate_range_start/end region is going on in parallel
>
> --
> 2.43.0
>

--
Cheers, Lorenzo

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 44/46] mm/cma: don't release CMA pages still in use
  2026-10-26 23:18 ` [PATCH 44/46] mm/cma: don't release CMA pages still in use David Hildenbrand (Arm)
@ 2026-10-27  8:55   ` Lorenzo Stoakes (ARM)
  2026-10-27  9:48   ` Muchun Song
  1 sibling, 0 replies; 93+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-10-27  8:55 UTC (permalink / raw)
  To: David Hildenbrand (Arm)
  Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Kairui Song, Barry Song, Axel Rasmussen,
	Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang, Liam R. Howlett,
	Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
	Kees Cook, Peter Zijlstra, Jann Horn, Pedro Falcato,
	Hugh Dickins, Pasha Tatashin, Pratyush Yadav,
	Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe, linux-mm, linux-kernel,
	kexec, linux-fsdevel, linux-arch, linux-cxl, stable

On Tue, Oct 27, 2026 at 12:18:04AM +0100, David Hildenbrand (Arm) wrote:
> From: Rik van Riel <riel@surriel.com>
>
> When a driver calls dma_free_contiguous() before quiescing DMA, the
> page might still have a reference from the device.
> put_page_testzero() there returns false, WARN fires, but the code proceeds
> to free_contig_frozen_range() putting a live page onto buddy and clearing
> the bitmap. A subsequent allocation can hand the same PFN to a new
> owner while the original holder still references it.
>
> A concurrent put_page() that drops the last reference between the
> testzero loop and free_contig_frozen_range() can double-queue the page
> via page->lru, corrupting buddy lists.
>
> Avoid the corruption by not freeing a CMA region if any of the
> pages inside are still in use.
>
> Make it explicit in the warning that the driver allowed a leak.
>
> While at it, use page_ref_freeze() to make the semantics clearer and
> switch to pr_warn_ratelimited().
>
> Fixes: 9bda131c6093 ("mm: cma: add cma_alloc_frozen{_compound}()")
> Cc: stable@vger.kernel.org
> Signed-off-by: Rik van Riel <riel@surriel.com>
> Link: https://patch.msgid.link/20260811132045.5f114772@fangorn
> [ david: use page_ref_freeze() + pr_warn_ratelimited() ]
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>

Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>

> ---
>  mm/cma.c | 10 +++++++---
>  1 file changed, 7 insertions(+), 3 deletions(-)
>
> diff --git a/mm/cma.c b/mm/cma.c
> index a10ea37a261da..871f95c9ae9f0 100644
> --- a/mm/cma.c
> +++ b/mm/cma.c
> @@ -1020,7 +1020,7 @@ bool cma_release(struct cma *cma, const struct page *pages,
>  		 unsigned long count)
>  {
>  	struct cma_memrange *cmr;
> -	unsigned long ret = 0;
> +	unsigned long leaked = 0;
>  	unsigned long i, pfn;
>
>  	cmr = find_cma_memrange(cma, pages, count);
> @@ -1029,9 +1029,13 @@ bool cma_release(struct cma *cma, const struct page *pages,
>
>  	pfn = page_to_pfn(pages);
>  	for (i = 0; i < count; i++, pfn++)
> -		ret += !put_page_testzero(pfn_to_page(pfn));
> +		leaked += !page_ref_freeze(pfn_to_page(pfn), 1);
>
> -	WARN(ret, "%lu pages are still in use!\n", ret);
> +	if (leaked) {
> +		pr_warn_ratelimited("%lu pages are still in use, not freeing CMA region!\n",
> +				   leaked);
> +		return true;
> +	}
>
>  	__cma_release_frozen(cma, cmr, pages, count);
>
>
> --
> 2.43.0
>

--
Cheers, Lorenzo

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 40/46] mm/ksm: check large swap-cache folios before mapping them
  2026-10-26 23:18 ` [PATCH 40/46] mm/ksm: check large swap-cache folios before mapping them David Hildenbrand (Arm)
@ 2026-10-27  9:00   ` Lorenzo Stoakes (ARM)
  0 siblings, 0 replies; 93+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-10-27  9:00 UTC (permalink / raw)
  To: David Hildenbrand (Arm)
  Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Kairui Song, Barry Song, Axel Rasmussen,
	Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang, Liam R. Howlett,
	Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
	Kees Cook, Peter Zijlstra, Jann Horn, Pedro Falcato,
	Hugh Dickins, Pasha Tatashin, Pratyush Yadav,
	Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe, linux-mm, linux-kernel,
	kexec, linux-fsdevel, linux-arch, linux-cxl, Chris Mason, stable

On Tue, Oct 27, 2026 at 12:18:00AM +0100, David Hildenbrand (Arm) wrote:
> From: Chris Mason <mason@kernel.org>
>
> KSM folios are always small, but their shared swap slots can be read
> back as part of a large folio in the swap cache. ksm_might_need_to_copy()
> skips large folios, so another process can map a page with an incompatible
> anon_vma or page index. Reverse mapping then cannot find the new
> mapping, preventing migration or reclaim.
>
> Apply the same compatibility checks to large folios as to small ones.
> Pass the page corresponding to the swap entry and copy only that page
> when necessary. In do_swap_page()'s copy path, decrement only that slot's
> swap count, because the source swap-cache folio can now be large.
>
> Fix generated by an LLM and sent by Chris Mason in private.
>
> Fixes: f1879e8a0c60 ("mm, swap: never bypass the swap cache even for SWP_SYNCHRONOUS_IO")
> Cc: stable@vger.kernel.org
> Signed-off-by: Chris Mason <mason@kernel.org>
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>

As reviewed off-list :)

All very, very horrifying, but I convinced myself that swapped-in large folios
containing previously-order-0 KSM pages _are_ real and _can_ hurt you...

Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>

> ---
>  include/linux/ksm.h |  6 +++---
>  mm/ksm.c            | 22 ++++++++++++----------
>  mm/memory.c         |  5 +++--
>  mm/swapfile.c       |  3 ++-
>  4 files changed, 20 insertions(+), 16 deletions(-)
>
> diff --git a/include/linux/ksm.h b/include/linux/ksm.h
> index d39d0d5483a23..a0d358a1feb63 100644
> --- a/include/linux/ksm.h
> +++ b/include/linux/ksm.h
> @@ -91,8 +91,8 @@ static inline void ksm_exit(struct mm_struct *mm)
>   * We'd like to make this conditional on vma->vm_flags & VM_MERGEABLE,
>   * but what if the vma was unmerged while the page was swapped out?
>   */
> -struct folio *ksm_might_need_to_copy(struct folio *folio,
> -			struct vm_area_struct *vma, unsigned long addr);
> +struct folio *ksm_might_need_to_copy(struct folio *folio, struct page *page,
> +		struct vm_area_struct *vma, unsigned long addr);
>
>  void rmap_walk_ksm(struct folio *folio, struct rmap_walk_control *rwc);
>  void folio_migrate_ksm(struct folio *newfolio, struct folio *folio);
> @@ -145,7 +145,7 @@ static inline int ksm_madvise(struct vm_area_struct *vma, unsigned long start,
>  }
>
>  static inline struct folio *ksm_might_need_to_copy(struct folio *folio,
> -			struct vm_area_struct *vma, unsigned long addr)
> +		struct page *page, struct vm_area_struct *vma, unsigned long addr)
>  {
>  	return folio;
>  }
> diff --git a/mm/ksm.c b/mm/ksm.c
> index e050b1bdf810d..e95f6b6723602 100644
> --- a/mm/ksm.c
> +++ b/mm/ksm.c
> @@ -3138,19 +3138,20 @@ void __ksm_exit(struct mm_struct *mm)
>  }
>
>  static bool folio_anon_rmap_compatible(const struct folio *folio,
> -		struct vm_area_struct *vma, unsigned long addr)
> +		const struct page *page, struct vm_area_struct *vma,
> +		unsigned long addr)
>  {
>  	const struct anon_vma *anon_vma = folio_anon_vma(folio);
>  	struct anon_vma_chain *avc;
>
>  	VM_WARN_ON_ONCE_FOLIO(!folio_test_locked(folio), folio);
> -	VM_WARN_ON_ONCE_FOLIO(folio_test_large(folio), folio);
> +	VM_WARN_ON_ONCE_FOLIO(page_folio(page) != folio, folio);
>  	VM_WARN_ON_ONCE_FOLIO(folio_test_ksm(folio), folio);
>  	vma_assert_stabilised(vma);
>
>  	if (!anon_vma)
>  		return true;
> -	if (folio->index != linear_anon_page_index(vma, addr))
> +	if (page_pgoff(folio, page) != linear_anon_page_index(vma, addr))
>  		return false;
>
>  	/*
> @@ -3167,20 +3168,21 @@ static bool folio_anon_rmap_compatible(const struct folio *folio,
>  	return false;
>  }
>
> -struct folio *ksm_might_need_to_copy(struct folio *folio,
> -			struct vm_area_struct *vma, unsigned long addr)
> +struct folio *ksm_might_need_to_copy(struct folio *folio, struct page *page,
> +		struct vm_area_struct *vma, unsigned long addr)
>  {
> -	struct page *page = folio_page(folio, 0);
>  	struct folio *new_folio;
>
> -	if (folio_test_large(folio))
> -		return folio;
> -
> +	/*
> +	 * A KSM folio is small, but the slot that it left behind can be swapped
> +	 * in as a part of a large folio by one of the processes that shared it.
> +	 * So test, and copy, the page of the slot.
> +	 */
>  	if (folio_test_ksm(folio)) {
>  		if (folio_stable_node(folio) &&
>  		    !(ksm_run & KSM_RUN_UNMERGE))
>  			return folio;	/* no need to copy it */
> -	} else if (folio_anon_rmap_compatible(folio, vma, addr)) {
> +	} else if (folio_anon_rmap_compatible(folio, page, vma, addr)) {
>  		return folio;		/* still no need to copy it */
>  	}
>  	if (PageHWPoison(page))
> diff --git a/mm/memory.c b/mm/memory.c
> index 230a2f4dafa13..be4c05db37d33 100644
> --- a/mm/memory.c
> +++ b/mm/memory.c
> @@ -5096,7 +5096,7 @@ vm_fault_t do_swap_page(struct vm_fault *vmf)
>  	 * folio->index of non-ksm folios would be nonlinear inside the
>  	 * anon VMA -- the ksm flag is lost on actual swapout.
>  	 */
> -	folio = ksm_might_need_to_copy(folio, vma, vmf->address);
> +	folio = ksm_might_need_to_copy(folio, page, vma, vmf->address);
>  	if (unlikely(!folio)) {
>  		ret = VM_FAULT_OOM;
>  		folio = swapcache;
> @@ -5278,7 +5278,8 @@ vm_fault_t do_swap_page(struct vm_fault *vmf)
>  	if (unlikely(folio != swapcache)) {
>  		folio_add_new_anon_rmap(folio, vma, address, RMAP_EXCLUSIVE);
>  		folio_add_lru_vma(folio, vma);
> -		folio_put_swap(swapcache, NULL);
> +		folio_put_swap(swapcache,
> +			       folio_file_page(swapcache, swp_offset(entry)));
>  	} else if (!folio_test_anon(folio)) {
>  		/*
>  		 * We currently only expect !anon folios that are fully
> diff --git a/mm/swapfile.c b/mm/swapfile.c
> index 254ce86fa923e..71ef9e2efb3a9 100644
> --- a/mm/swapfile.c
> +++ b/mm/swapfile.c
> @@ -2514,7 +2514,8 @@ static int unuse_pte(struct vm_area_struct *vma, pmd_t *pmd,
>  		return 0;
>
>  	swapcache = folio;
> -	folio = ksm_might_need_to_copy(folio, vma, addr);
> +	folio = ksm_might_need_to_copy(folio,
> +				       folio_file_page(folio, swp_offset(entry)), vma, addr);
>  	if (unlikely(!folio))
>  		return -ENOMEM;
>  	else if (unlikely(folio == ERR_PTR(-EHWPOISON))) {
>
> --
> 2.43.0
>

--
Cheers, Lorenzo

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 38/46] mm/ksm: reset the unstable trees of all nodes
  2026-10-26 23:17 ` [PATCH 38/46] mm/ksm: reset the unstable trees of all nodes David Hildenbrand (Arm)
@ 2026-10-27  9:14   ` Lorenzo Stoakes (ARM)
  0 siblings, 0 replies; 93+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-10-27  9:14 UTC (permalink / raw)
  To: David Hildenbrand (Arm)
  Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Kairui Song, Barry Song, Axel Rasmussen,
	Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang, Liam R. Howlett,
	Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
	Kees Cook, Peter Zijlstra, Jann Horn, Pedro Falcato,
	Hugh Dickins, Pasha Tatashin, Pratyush Yadav,
	Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe, linux-mm, linux-kernel,
	kexec, linux-fsdevel, linux-arch, linux-cxl, stable, Josef Bacik

On Tue, Oct 27, 2026 at 12:17:58AM +0100, David Hildenbrand (Arm) wrote:
> Each full scan resets ksm_nr_node_ids unstable tree roots. Enabling
> merge_across_nodes resets this count to 1, even if per-node roots were
> previously allocated.
>
> So when toggling "merge_across_nodes" 0 -> 1 -> 0, a scan that starts
> while the setting is 1 and continues after switching back to 0 can
> encounter stale unstable tree roots, resulting in UAF.
>
> Only root is allowed to change "merge_across_nodes", and the documented
> sequence is: "merge_across_nodes setting can be changed only when there
> are no ksm shared pages in the system: set run 2 to unmerge pages first,
> then to 1 after changing merge_across_nodes, to remerge according to the
> new setting."
>
> Let's fix it by tracking in ksm_nr_node_ids the actual number of
> allocated tree roots.
>
> remove_all_stable_nodes() and ksm_check_stable_tree() will now scan
> more tree roots (skipping the empty ones), which is harmless.
>
> Fixes: ef53d16cded7 ("ksm: allocate roots when needed")
> Cc: stable@vger.kernel.org
> Reported-by: Josef Bacik <josef@toxicpanda.com>
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>

Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>

> ---
>  mm/ksm.c | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/mm/ksm.c b/mm/ksm.c
> index dbfb8f98b1892..9c51925825cbf 100644
> --- a/mm/ksm.c
> +++ b/mm/ksm.c
> @@ -475,6 +475,7 @@ static void advisor_stop_scan(void)
>  #ifdef CONFIG_NUMA
>  /* Zeroed when merging across nodes is not allowed */
>  static unsigned int ksm_merge_across_nodes = 1;
> +/* Number of allocated stable and unstable tree roots. */
>  static int ksm_nr_node_ids = 1;
>  #else
>  #define ksm_merge_across_nodes	1U
> @@ -3636,14 +3637,13 @@ static ssize_t merge_across_nodes_store(struct kobject *kobj,
>  			else {
>  				root_stable_tree = buf;
>  				root_unstable_tree = buf + nr_node_ids;
> +				ksm_nr_node_ids = nr_node_ids;
>  				/* Stable tree is empty but not the unstable */
>  				root_unstable_tree[0] = one_unstable_tree[0];
>  			}
>  		}
> -		if (!err) {
> +		if (!err)
>  			ksm_merge_across_nodes = knob;
> -			ksm_nr_node_ids = knob ? 1 : nr_node_ids;
> -		}
>  	}
>  	mutex_unlock(&ksm_thread_mutex);
>
>
> --
> 2.43.0
>

--
Cheers, Lorenzo

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 37/46] mm: fix deadlock of mremap() against UFFDIO_MOVE
  2026-10-26 23:17 ` [PATCH 37/46] mm: fix deadlock of mremap() against UFFDIO_MOVE David Hildenbrand (Arm)
@ 2026-10-27  9:23   ` Lorenzo Stoakes (ARM)
  2026-10-27  9:46   ` Muchun Song
  1 sibling, 0 replies; 93+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-10-27  9:23 UTC (permalink / raw)
  To: David Hildenbrand (Arm)
  Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Kairui Song, Barry Song, Axel Rasmussen,
	Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang, Liam R. Howlett,
	Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
	Kees Cook, Peter Zijlstra, Jann Horn, Pedro Falcato,
	Hugh Dickins, Pasha Tatashin, Pratyush Yadav,
	Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe, linux-mm, linux-kernel,
	kexec, linux-fsdevel, linux-arch, linux-cxl, Chris Mason, stable

On Tue, Oct 27, 2026 at 12:17:57AM +0100, David Hildenbrand (Arm) wrote:
> From: Chris Mason <mason@kernel.org>
>
> With per-VMA locks, UFFDIO_MOVE can run concurrently with mremap()
> on different VMAs in the same mm. Those VMAs can share page tables, so
> both operations can acquire the same pair of page-table locks.
>
> UFFDIO_MOVE orders the locks by address, while mremap() takes the source
> lock first. These conflicting orders can deadlock; mremap() holding
> mmap_lock for writing no longer helps.
>
> Move double_pt_lock() and double_pt_unlock() to mm/internal.h and use
> them for all page-table moves in mremap(). Preserve the source entry
> checks after acquiring both locks. Remove the comments claiming that
> exclusive mmap_lock makes lock ordering irrelevant.
>
> In move_ptes(), make sure to just recheck source and destination PMD
> after taking the locks and drop the overly-long comment.
>
> Fix generated by an LLM and sent by Chris Mason in private.
>
> Fixes: 867a43a34ff8 ("userfaultfd: use per-vma locks in userfaultfd operations")
> Cc: stable@vger.kernel.org
> Signed-off-by: Chris Mason <mason@kernel.org>
> [ david: use new helpers consistently; simplify description and comments;
>          move_ptes() fixup ]
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>

OK nice, reviewed off-list and this revision looks correct + covers all
cases, so:

Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>

> ---
>  include/linux/userfaultfd_k.h |  2 -
>  mm/huge_memory.c              | 19 ++++------
>  mm/hugetlb.c                  | 14 ++-----
>  mm/internal.h                 | 28 ++++++++++++++
>  mm/mremap.c                   | 87 +++++++++++++++++--------------------------
>  mm/userfaultfd.c              | 27 --------------
>  6 files changed, 72 insertions(+), 105 deletions(-)
>
> diff --git a/include/linux/userfaultfd_k.h b/include/linux/userfaultfd_k.h
> index a14b8a9ffb7b1..565e98f342dc8 100644
> --- a/include/linux/userfaultfd_k.h
> +++ b/include/linux/userfaultfd_k.h
> @@ -153,8 +153,6 @@ extern int mrwprotect_range(struct userfaultfd_ctx *ctx, unsigned long start,
>  			    unsigned long len, bool enable_rwp);
>
>  /* move_pages */
> -void double_pt_lock(spinlock_t *ptl1, spinlock_t *ptl2);
> -void double_pt_unlock(spinlock_t *ptl1, spinlock_t *ptl2);
>  int move_pages_huge_pmd(struct mm_struct *mm, pmd_t *dst_pmd, pmd_t *src_pmd, pmd_t dst_pmdval,
>  			struct vm_area_struct *dst_vma,
>  			struct vm_area_struct *src_vma,
> diff --git a/mm/huge_memory.c b/mm/huge_memory.c
> index 1b50cc2b35351..08e58cda7d37d 100644
> --- a/mm/huge_memory.c
> +++ b/mm/huge_memory.c
> @@ -2645,15 +2645,11 @@ bool move_huge_pmd(struct vm_area_struct *vma, unsigned long old_addr,
>  		return false;
>  	}
>
> -	/*
> -	 * We don't have to worry about the ordering of src and dst
> -	 * ptlocks because exclusive mmap_lock prevents deadlock.
> -	 */
> -	old_ptl = __pmd_trans_huge_lock(old_pmd, vma);
> -	if (old_ptl) {
> -		new_ptl = pmd_lockptr(mm, new_pmd);
> -		if (new_ptl != old_ptl)
> -			spin_lock_nested(new_ptl, SINGLE_DEPTH_NESTING);
> +	old_ptl = pmd_lockptr(mm, old_pmd);
> +	new_ptl = pmd_lockptr(mm, new_pmd);
> +
> +	double_pt_lock(old_ptl, new_ptl);
> +	if (likely(pmd_is_huge(*old_pmd))) {
>  		pmd = pmdp_huge_get_and_clear(mm, old_addr, old_pmd);
>  		if (pmd_present(pmd))
>  			force_flush = true;
> @@ -2682,11 +2678,10 @@ bool move_huge_pmd(struct vm_area_struct *vma, unsigned long old_addr,
>  		set_pmd_at(mm, new_addr, new_pmd, pmd);
>  		if (force_flush)
>  			flush_pmd_tlb_range(vma, old_addr, old_addr + PMD_SIZE);
> -		if (new_ptl != old_ptl)
> -			spin_unlock(new_ptl);
> -		spin_unlock(old_ptl);
> +		double_pt_unlock(old_ptl, new_ptl);
>  		return true;
>  	}
> +	double_pt_unlock(old_ptl, new_ptl);
>  	return false;
>  }
>
> diff --git a/mm/hugetlb.c b/mm/hugetlb.c
> index da5d04edf7c10..84141527fe73d 100644
> --- a/mm/hugetlb.c
> +++ b/mm/hugetlb.c
> @@ -5153,15 +5153,9 @@ static void move_huge_pte(struct vm_area_struct *vma, unsigned long old_addr,
>  	spinlock_t *src_ptl, *dst_ptl;
>  	pte_t pte;
>
> -	dst_ptl = huge_pte_lock(h, mm, dst_pte);
> +	dst_ptl = huge_pte_lockptr(h, mm, dst_pte);
>  	src_ptl = huge_pte_lockptr(h, mm, src_pte);
> -
> -	/*
> -	 * We don't have to worry about the ordering of src and dst ptlocks
> -	 * because exclusive mmap_lock (or the i_mmap_lock) prevents deadlock.
> -	 */
> -	if (src_ptl != dst_ptl)
> -		spin_lock_nested(src_ptl, SINGLE_DEPTH_NESTING);
> +	double_pt_lock(dst_ptl, src_ptl);
>
>  	pte = huge_ptep_get_and_clear(mm, old_addr, src_pte, sz);
>
> @@ -5190,9 +5184,7 @@ static void move_huge_pte(struct vm_area_struct *vma, unsigned long old_addr,
>  		set_huge_pte_at(mm, new_addr, dst_pte, pte, sz);
>  	}
>
> -	if (src_ptl != dst_ptl)
> -		spin_unlock(src_ptl);
> -	spin_unlock(dst_ptl);
> +	double_pt_unlock(dst_ptl, src_ptl);
>  }
>
>  int move_hugetlb_page_tables(struct vm_area_struct *vma,
> diff --git a/mm/internal.h b/mm/internal.h
> index b1b0f29d2216e..7e4d88b2fb02c 100644
> --- a/mm/internal.h
> +++ b/mm/internal.h
> @@ -619,6 +619,34 @@ static inline void force_page_cache_readahead(struct address_space *mapping,
>  	force_page_cache_ra(&ractl, nr_to_read);
>  }
>
> +/*
> + * Take two page table locks at the same level in address order such that
> + * we cannot deadlock.
> + */
> +static inline void double_pt_lock(spinlock_t *ptl1, spinlock_t *ptl2)
> +	__acquires(ptl1)
> +	__acquires(ptl2)
> +{
> +	if (ptl1 > ptl2)
> +		swap(ptl1, ptl2);
> +	spin_lock(ptl1);
> +	if (ptl1 != ptl2)
> +		spin_lock_nested(ptl2, SINGLE_DEPTH_NESTING);
> +	else
> +		__acquire(ptl2);
> +}
> +
> +static inline void double_pt_unlock(spinlock_t *ptl1, spinlock_t *ptl2)
> +	__releases(ptl1)
> +	__releases(ptl2)
> +{
> +	spin_unlock(ptl1);
> +	if (ptl1 != ptl2)
> +		spin_unlock(ptl2);
> +	else
> +		__release(ptl2);
> +}
> +
>  unsigned find_lock_entries(struct address_space *mapping, pgoff_t *start,
>  		pgoff_t end, struct folio_batch *fbatch, pgoff_t *indices);
>  unsigned find_get_entries(struct address_space *mapping, pgoff_t *start,
> diff --git a/mm/mremap.c b/mm/mremap.c
> index 1237718848f5c..70b7264aa6bf5 100644
> --- a/mm/mremap.c
> +++ b/mm/mremap.c
> @@ -202,7 +202,7 @@ static int move_ptes(struct pagetable_move_control *pmc,
>  	struct mm_struct *mm = vma->vm_mm;
>  	pte_t *old_ptep, *new_ptep;
>  	pte_t old_pte, pte;
> -	pmd_t dummy_pmdval;
> +	pmd_t old_pmdval, new_pmdval;
>  	spinlock_t *old_ptl, *new_ptl;
>  	bool force_flush = false;
>  	unsigned long old_addr = pmc->old_addr;
> @@ -234,31 +234,30 @@ static int move_ptes(struct pagetable_move_control *pmc,
>  	if (pmc->need_rmap_locks)
>  		take_rmap_locks(vma);
>
> -	/*
> -	 * We don't have to worry about the ordering of src and dst
> -	 * pte locks because exclusive mmap_lock prevents deadlock.
> -	 */
> -	old_ptep = pte_offset_map_lock(mm, old_pmd, old_addr, &old_ptl);
> +	old_ptep = pte_offset_map_rw_nolock(mm, old_pmd, old_addr, &old_pmdval,
> +					    &old_ptl);
>  	if (!old_ptep) {
>  		err = -EAGAIN;
>  		goto out;
>  	}
> -	/*
> -	 * Now new_pte is none, so collapse_scan_file() path can not find
> -	 * this by traversing file->f_mapping, so there is no concurrency with
> -	 * retract_page_tables(). In addition, we already hold the exclusive
> -	 * mmap_lock, so this new_pte page is stable, so there is no need to get
> -	 * pmdval and do pmd_same() check.
> -	 */
> -	new_ptep = pte_offset_map_rw_nolock(mm, new_pmd, new_addr, &dummy_pmdval,
> -					   &new_ptl);
> +	new_ptep = pte_offset_map_rw_nolock(mm, new_pmd, new_addr, &new_pmdval,
> +					    &new_ptl);
>  	if (!new_ptep) {
> -		pte_unmap_unlock(old_ptep, old_ptl);
> +		pte_unmap(old_ptep);
> +		err = -EAGAIN;
> +		goto out;
> +	}
> +
> +	double_pt_lock(old_ptl, new_ptl);
> +	if (unlikely(!pmd_same(old_pmdval, pmdp_get_lockless(old_pmd)) ||
> +		     !pmd_same(new_pmdval, pmdp_get_lockless(new_pmd)))) {
> +		double_pt_unlock(old_ptl, new_ptl);
> +		pte_unmap(new_ptep);
> +		pte_unmap(old_ptep);
>  		err = -EAGAIN;
>  		goto out;
>  	}
> -	if (new_ptl != old_ptl)
> -		spin_lock_nested(new_ptl, SINGLE_DEPTH_NESTING);
> +
>  	flush_tlb_batched_pending(vma->vm_mm);
>  	lazy_mmu_mode_enable();
>
> @@ -317,10 +316,9 @@ static int move_ptes(struct pagetable_move_control *pmc,
>  	lazy_mmu_mode_disable();
>  	if (force_flush)
>  		flush_tlb_range(vma, old_end - len, old_end);
> -	if (new_ptl != old_ptl)
> -		spin_unlock(new_ptl);
> +	double_pt_unlock(old_ptl, new_ptl);
>  	pte_unmap(new_ptep - 1);
> -	pte_unmap_unlock(old_ptep - 1, old_ptl);
> +	pte_unmap(old_ptep - 1);
>  out:
>  	if (pmc->need_rmap_locks)
>  		drop_rmap_locks(vma);
> @@ -395,14 +393,9 @@ static bool move_normal_pmd(struct pagetable_move_control *pmc,
>  	if (WARN_ON_ONCE(!pmd_none(*new_pmd)))
>  		return false;
>
> -	/*
> -	 * We don't have to worry about the ordering of src and dst
> -	 * ptlocks because exclusive mmap_lock prevents deadlock.
> -	 */
> -	old_ptl = pmd_lock(mm, old_pmd);
> +	old_ptl = pmd_lockptr(mm, old_pmd);
>  	new_ptl = pmd_lockptr(mm, new_pmd);
> -	if (new_ptl != old_ptl)
> -		spin_lock_nested(new_ptl, SINGLE_DEPTH_NESTING);
> +	double_pt_lock(old_ptl, new_ptl);
>
>  	pmd = *old_pmd;
>
> @@ -418,9 +411,7 @@ static bool move_normal_pmd(struct pagetable_move_control *pmc,
>  	pmd_populate(mm, new_pmd, pmd_pgtable(pmd));
>  	flush_tlb_range(vma, pmc->old_addr, pmc->old_addr + PMD_SIZE);
>  out_unlock:
> -	if (new_ptl != old_ptl)
> -		spin_unlock(new_ptl);
> -	spin_unlock(old_ptl);
> +	double_pt_unlock(old_ptl, new_ptl);
>
>  	return res;
>  }
> @@ -452,14 +443,10 @@ static bool move_normal_pud(struct pagetable_move_control *pmc,
>  	if (WARN_ON_ONCE(!pud_none(*new_pud)))
>  		return false;
>
> -	/*
> -	 * We don't have to worry about the ordering of src and dst
> -	 * ptlocks because exclusive mmap_lock prevents deadlock.
> -	 */
> -	old_ptl = pud_lock(mm, old_pud);
> +	old_ptl = pud_lockptr(mm, old_pud);
>  	new_ptl = pud_lockptr(mm, new_pud);
> -	if (new_ptl != old_ptl)
> -		spin_lock_nested(new_ptl, SINGLE_DEPTH_NESTING);
> +
> +	double_pt_lock(old_ptl, new_ptl);
>
>  	pud = *old_pud;
>  	if (unlikely(pud_none(pud)))
> @@ -473,9 +460,7 @@ static bool move_normal_pud(struct pagetable_move_control *pmc,
>  	pud_populate(mm, new_pud, pud_pgtable(pud));
>  	flush_tlb_range(vma, pmc->old_addr, pmc->old_addr + PUD_SIZE);
>  out_unlock:
> -	if (new_ptl != old_ptl)
> -		spin_unlock(new_ptl);
> -	spin_unlock(old_ptl);
> +	double_pt_unlock(old_ptl, new_ptl);
>
>  	return true;
>  }
> @@ -503,16 +488,14 @@ static bool move_huge_pud(struct pagetable_move_control *pmc,
>  	if (WARN_ON_ONCE(!pud_none(*new_pud)))
>  		return false;
>
> -	/*
> -	 * We don't have to worry about the ordering of src and dst
> -	 * ptlocks because exclusive mmap_lock prevents deadlock.
> -	 */
> -	old_ptl = __pud_trans_huge_lock(old_pud, vma);
> -	if (unlikely(!old_ptl))
> -		return false;
> +	old_ptl = pud_lockptr(mm, old_pud);
>  	new_ptl = pud_lockptr(mm, new_pud);
> -	if (new_ptl != old_ptl)
> -		spin_lock_nested(new_ptl, SINGLE_DEPTH_NESTING);
> +
> +	double_pt_lock(old_ptl, new_ptl);
> +	if (unlikely(!pud_trans_huge(*old_pud))) {
> +		double_pt_unlock(old_ptl, new_ptl);
> +		return false;
> +	}
>
>  	/* Clear the pud */
>  	pud = pudp_huge_get_and_clear(mm, pmc->old_addr, old_pud);
> @@ -523,9 +506,7 @@ static bool move_huge_pud(struct pagetable_move_control *pmc,
>  	/* mark soft_ditry when we add pud level soft dirty support */
>  	set_pud_at(mm, pmc->new_addr, new_pud, pud);
>  	flush_pud_tlb_range(vma, pmc->old_addr, pmc->old_addr + HPAGE_PUD_SIZE);
> -	if (new_ptl != old_ptl)
> -		spin_unlock(new_ptl);
> -	spin_unlock(old_ptl);
> +	double_pt_unlock(old_ptl, new_ptl);
>
>  	return true;
>  }
> diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
> index 710e913c73bfa..76de84510340c 100644
> --- a/mm/userfaultfd.c
> +++ b/mm/userfaultfd.c
> @@ -1206,33 +1206,6 @@ int mrwprotect_range(struct userfaultfd_ctx *ctx, unsigned long start,
>  	return 0;
>  }
>
> -void double_pt_lock(spinlock_t *ptl1,
> -		    spinlock_t *ptl2)
> -	__acquires(ptl1)
> -	__acquires(ptl2)
> -{
> -	if (ptl1 > ptl2)
> -		swap(ptl1, ptl2);
> -	/* lock in virtual address order to avoid lock inversion */
> -	spin_lock(ptl1);
> -	if (ptl1 != ptl2)
> -		spin_lock_nested(ptl2, SINGLE_DEPTH_NESTING);
> -	else
> -		__acquire(ptl2);
> -}
> -
> -void double_pt_unlock(spinlock_t *ptl1,
> -		      spinlock_t *ptl2)
> -	__releases(ptl1)
> -	__releases(ptl2)
> -{
> -	spin_unlock(ptl1);
> -	if (ptl1 != ptl2)
> -		spin_unlock(ptl2);
> -	else
> -		__release(ptl2);
> -}
> -
>  static inline bool is_pte_pages_stable(pte_t *dst_pte, pte_t *src_pte,
>  				       pte_t orig_dst_pte, pte_t orig_src_pte,
>  				       pmd_t *dst_pmd, pmd_t dst_pmdval)
>
> --
> 2.43.0
>

--
Cheers, Lorenzo

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 27/46] mm/mmu_notifier: finish non-blocking interval invalidation on error
  2026-10-26 23:17 ` [PATCH 27/46] mm/mmu_notifier: finish non-blocking interval invalidation on error David Hildenbrand (Arm)
@ 2026-10-27  9:33   ` Lorenzo Stoakes (ARM)
  0 siblings, 0 replies; 93+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-10-27  9:33 UTC (permalink / raw)
  To: David Hildenbrand (Arm)
  Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Kairui Song, Barry Song, Axel Rasmussen,
	Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang, Liam R. Howlett,
	Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
	Kees Cook, Peter Zijlstra, Jann Horn, Pedro Falcato,
	Hugh Dickins, Pasha Tatashin, Pratyush Yadav,
	Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe, linux-mm, linux-kernel,
	kexec, linux-fsdevel, linux-arch, linux-cxl, Josef Bacik, stable

On Tue, Oct 27, 2026 at 12:17:47AM +0100, David Hildenbrand (Arm) wrote:
> From: Josef Bacik <josef@toxicpanda.com>
>
> When an ordinary MMU notifier rejects a non-blocking invalidation, the
> interval invalidation started beforehand is left unfinished: the caller
> skips mmu_notifier_invalidate_range_end(). Subsequent interval notifier
> operations can then wait forever.
>
> The only in-tree trigger is nouveau SVM, which uses both notifier types
> and rejects non-blocking invalidations. Reaping via the OOM reaper or
> process_mrelease() can therefore leave the GPU fault worker stuck,
> holding a reference that prevents the dying process's address space
> and memory from being freed.
>
> End the interval invalidation when an ordinary notifier fails a
> non-blocking invalidation, like mn_itree_invalidate() already does when
> an interval notifier fails. Make that handling clearer in the
> documentation of mmu_notifier_invalidate_range_start_nonblock().
>
> Fix generated by an LLM and sent by Josef Bacik in private.
>
> Fixes: 99cb252f5e68 ("mm/mmu_notifier: add an interval tree notifier")
> Cc: stable@vger.kernel.org
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>
> [ david: simplify description, update function doc ]
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>

Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>

> ---
>  include/linux/mmu_notifier.h |  3 ++-
>  mm/mmu_notifier.c            | 17 +++++++++++++----
>  2 files changed, 15 insertions(+), 5 deletions(-)
>
> diff --git a/include/linux/mmu_notifier.h b/include/linux/mmu_notifier.h
> index a11a44eef521e..5db78e5761c5c 100644
> --- a/include/linux/mmu_notifier.h
> +++ b/include/linux/mmu_notifier.h
> @@ -483,7 +483,8 @@ mmu_notifier_invalidate_range_start(struct mmu_notifier_range *range)
>  /*
>   * This version of mmu_notifier_invalidate_range_start() avoids blocking, but it
>   * can return an error if a notifier can't proceed without blocking, in which
> - * case you're not allowed to modify PTEs in the specified range.
> + * case you're not allowed to modify PTEs in the specified range or call
> + * mmu_notifier_invalidate_range_end().
>   *
>   * This is mainly intended for OOM handling.
>   */
> diff --git a/mm/mmu_notifier.c b/mm/mmu_notifier.c
> index df69ba6e797f7..2e20f88e162d7 100644
> --- a/mm/mmu_notifier.c
> +++ b/mm/mmu_notifier.c
> @@ -569,16 +569,25 @@ int __mmu_notifier_invalidate_range_start(struct mmu_notifier_range *range)
>  {
>  	struct mmu_notifier_subscriptions *subscriptions =
>  		range->mm->notifier_subscriptions;
> -	int ret;
> +	const bool has_itree = subscriptions->has_itree;
> +	int ret = 0;
>
> -	if (subscriptions->has_itree) {
> +	if (has_itree) {
>  		ret = mn_itree_invalidate(subscriptions, range);
>  		if (ret)
>  			return ret;
>  	}
>  	if (!hlist_empty(&subscriptions->list))
> -		return mn_hlist_invalidate_range_start(subscriptions, range);
> -	return 0;
> +		ret = mn_hlist_invalidate_range_start(subscriptions, range);
> +
> +	/*
> +	 * On error, the non-blocking caller is not allowed to call
> +	 * invalidate_range_end(), as in mn_itree_invalidate().
> +	 */
> +	if (ret && has_itree && !mmu_notifier_range_blockable(range))
> +		mn_itree_inv_end(subscriptions);
> +
> +	return ret;
>  }
>
>  static void
>
> --
> 2.43.0
>

--
Cheers, Lorenzo

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 22/46] mm/gup: check for overflow when converting nr_pages to bytes in GUP-fast
  2026-10-26 23:17 ` [PATCH 22/46] mm/gup: check for overflow when converting nr_pages to bytes " David Hildenbrand (Arm)
@ 2026-10-27  9:34   ` Lorenzo Stoakes (ARM)
  2026-10-27  9:44   ` Muchun Song
  1 sibling, 0 replies; 93+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-10-27  9:34 UTC (permalink / raw)
  To: David Hildenbrand (Arm)
  Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Kairui Song, Barry Song, Axel Rasmussen,
	Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang, Liam R. Howlett,
	Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
	Kees Cook, Peter Zijlstra, Jann Horn, Pedro Falcato,
	Hugh Dickins, Pasha Tatashin, Pratyush Yadav,
	Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe, linux-mm, linux-kernel,
	kexec, linux-fsdevel, linux-arch, linux-cxl, stable

On Tue, Oct 27, 2026 at 12:17:42AM +0100, David Hildenbrand (Arm) wrote:
> The overflow check in gup_fast_fallback() only covers the addition to
> start. The preceding nr_pages << PAGE_SHIFT can already have truncated
> the length on 32bit.

Insert rant about 32-bit kernels here :)

>
> Users such as RapidIO's rio_dma_transfer() can derive such page counts
> from a 64-bit userspace length.
>
> Let's just check_shl_overflow() to reject any such overflow with
> -EOVERFLOW early.
>
> Fixes: c28b1fc70390 ("mm/gup: reorganize internal_get_user_pages_fast()")
> Cc: stable@vger.kernel.org
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>

Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>

> ---
>  mm/gup.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/mm/gup.c b/mm/gup.c
> index 9906965893431..48e1bfe5ab9a9 100644
> --- a/mm/gup.c
> +++ b/mm/gup.c
> @@ -3214,8 +3214,8 @@ static int gup_fast_fallback(unsigned long start, unsigned long nr_pages,
>  		might_lock_read(&current->mm->mmap_lock);
>
>  	start = untagged_addr(start) & PAGE_MASK;
> -	len = nr_pages << PAGE_SHIFT;
> -	if (check_add_overflow(start, len, &end))
> +	if (check_shl_overflow(nr_pages, PAGE_SHIFT, &len) ||
> +	    check_add_overflow(start, len, &end))
>  		return -EOVERFLOW;
>  	if (end > TASK_SIZE_MAX)
>  		return -EFAULT;
>
> --
> 2.43.0
>

--
Cheers, Lorenzo

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 21/46] mm/gup: fix out-of-bounds write for nr_pages == 0 in GUP-fast
  2026-10-26 23:17 ` [PATCH 21/46] mm/gup: fix out-of-bounds write for nr_pages == 0 in GUP-fast David Hildenbrand (Arm)
@ 2026-10-27  9:37   ` Lorenzo Stoakes (ARM)
  2026-10-27  9:40   ` Muchun Song
  1 sibling, 0 replies; 93+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-10-27  9:37 UTC (permalink / raw)
  To: David Hildenbrand (Arm)
  Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Kairui Song, Barry Song, Axel Rasmussen,
	Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang, Liam R. Howlett,
	Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
	Kees Cook, Peter Zijlstra, Jann Horn, Pedro Falcato,
	Hugh Dickins, Pasha Tatashin, Pratyush Yadav,
	Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe, linux-mm, linux-kernel,
	kexec, linux-fsdevel, linux-arch, linux-cxl, Chris Mason, stable

On Tue, Oct 27, 2026 at 12:17:41AM +0100, David Hildenbrand (Arm) wrote:
> From: Chris Mason <mason@kernel.org>
>
> With nr_pages == 0, GUP-fast still enters its page table walk and can
> write past the caller's page array. The old end <= start check caught
> empty ranges, but was replaced with an overflow check.
>
> Users such as OrangeFS can pass a zero page count derived from a
> userspace-supplied length. So let's return zero for nr_pages == 0 before
> starting the walk, just like GUP-slow.
>
> Fix generated by an LLM and sent by Chris Mason in private.
>
> Fixes: c28b1fc70390 ("mm/gup: reorganize internal_get_user_pages_fast()")
> Cc: stable@vger.kernel.org
> Signed-off-by: Chris Mason <mason@kernel.org>
> [ david: simplify description ]
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>

LGTM so:

Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>

> ---
>  mm/gup.c | 3 +++
>  1 file changed, 3 insertions(+)
>
> diff --git a/mm/gup.c b/mm/gup.c
> index 47e7ae152cdf1..9906965893431 100644
> --- a/mm/gup.c
> +++ b/mm/gup.c
> @@ -3204,6 +3204,9 @@ static int gup_fast_fallback(unsigned long start, unsigned long nr_pages,
>  				       FOLL_PCI_P2PDMA | FOLL_HONOR_NUMA_FAULT)))
>  		return -EINVAL;
>
> +	if (unlikely(!nr_pages))
> +		return 0;
> +
>  	if (gup_flags & FOLL_PIN)
>  		mm_set_has_pinned_flag(current->mm);
>
>
> --
> 2.43.0
>

--
Cheers, Lorenzo

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 21/46] mm/gup: fix out-of-bounds write for nr_pages == 0 in GUP-fast
  2026-10-26 23:17 ` [PATCH 21/46] mm/gup: fix out-of-bounds write for nr_pages == 0 in GUP-fast David Hildenbrand (Arm)
  2026-10-27  9:37   ` Lorenzo Stoakes (ARM)
@ 2026-10-27  9:40   ` Muchun Song
  1 sibling, 0 replies; 93+ messages in thread
From: Muchun Song @ 2026-10-27  9:40 UTC (permalink / raw)
  To: David Hildenbrand (Arm)
  Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Xu Xin, Chengming Zhou, Chris Li, Kemeng Shi,
	Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn, Rakie Kim,
	Ying Huang, Jason Gunthorpe, linux-mm, linux-kernel, kexec,
	linux-fsdevel, linux-arch, linux-cxl, Chris Mason, stable



> On Oct 27, 2026, at 07:17, David Hildenbrand (Arm) <david@kernel.org> wrote:
> 
> From: Chris Mason <mason@kernel.org>
> 
> With nr_pages == 0, GUP-fast still enters its page table walk and can
> write past the caller's page array. The old end <= start check caught
> empty ranges, but was replaced with an overflow check.
> 
> Users such as OrangeFS can pass a zero page count derived from a
> userspace-supplied length. So let's return zero for nr_pages == 0 before
> starting the walk, just like GUP-slow.
> 
> Fix generated by an LLM and sent by Chris Mason in private.
> 
> Fixes: c28b1fc70390 ("mm/gup: reorganize internal_get_user_pages_fast()")
> Cc: stable@vger.kernel.org
> Signed-off-by: Chris Mason <mason@kernel.org>
> [ david: simplify description ]
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>

Acked-by: Muchun Song <muchun.song@linux.dev>

Thanks.


^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 22/46] mm/gup: check for overflow when converting nr_pages to bytes in GUP-fast
  2026-10-26 23:17 ` [PATCH 22/46] mm/gup: check for overflow when converting nr_pages to bytes " David Hildenbrand (Arm)
  2026-10-27  9:34   ` Lorenzo Stoakes (ARM)
@ 2026-10-27  9:44   ` Muchun Song
  1 sibling, 0 replies; 93+ messages in thread
From: Muchun Song @ 2026-10-27  9:44 UTC (permalink / raw)
  To: David Hildenbrand (Arm)
  Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Xu Xin, Chengming Zhou, Chris Li, Kemeng Shi,
	Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn, Rakie Kim,
	Ying Huang, Jason Gunthorpe, linux-mm, linux-kernel, kexec,
	linux-fsdevel, linux-arch, linux-cxl, stable



> On Oct 27, 2026, at 07:17, David Hildenbrand (Arm) <david@kernel.org> wrote:
> 
> The overflow check in gup_fast_fallback() only covers the addition to
> start. The preceding nr_pages << PAGE_SHIFT can already have truncated
> the length on 32bit.
> 
> Users such as RapidIO's rio_dma_transfer() can derive such page counts
> from a 64-bit userspace length.
> 
> Let's just check_shl_overflow() to reject any such overflow with
> -EOVERFLOW early.
> 
> Fixes: c28b1fc70390 ("mm/gup: reorganize internal_get_user_pages_fast()")
> Cc: stable@vger.kernel.org
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>

Acked-by: Muchun Song <muchun.song@linux.dev>

Thanks.


^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 02/46] fork: take mmap_lock before copying mm_struct
  2026-10-26 23:17 ` [PATCH 02/46] fork: take mmap_lock before copying mm_struct David Hildenbrand (Arm)
  2026-10-27  1:38   ` Rik van Riel
  2026-10-27  8:18   ` Vlastimil Babka (SUSE)
@ 2026-10-27  9:45   ` Barry Song
  2026-10-27 10:38   ` Pedro Falcato
  3 siblings, 0 replies; 93+ messages in thread
From: Barry Song @ 2026-10-27  9:45 UTC (permalink / raw)
  To: David Hildenbrand (Arm)
  Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Axel Rasmussen,
	Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang, Liam R. Howlett,
	Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
	Kees Cook, Peter Zijlstra, Jann Horn, Pedro Falcato,
	Hugh Dickins, Pasha Tatashin, Pratyush Yadav,
	Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe, linux-mm, linux-kernel,
	kexec, linux-fsdevel, linux-arch, linux-cxl, stable, Josef Bacik

On Tue, Oct 27, 2026 at 7:18 AM David Hildenbrand (Arm)
<david@kernel.org> wrote:
>
> dup_mm() copies the parent's mm_struct before dup_mmap() takes the
> mmap_lock. A concurrent brk() can leave the child with a stale mm->brk
> and newer heap mappings, causing later brk() requests to fail.
>
> Other operations (e.g., PR_SET_MM) on the parent's mm_struct can similarly
> cause inconsistencies.
>
> As a simple and robust fix, grab the parent's mmap_lock earlier. This
> way we don't need to update individual mm fields in dup_mmap() and
> keep missing ones. Stop updating the 4 existing members (total_vm, data_vm,
> exec_vm, stack_vm), as that is now no longer required.
>
> Keep releasing the parent's mmap_lock in dup_mmap(), before
> userfaultfd completion, to avoid moving the userfaultfd handling into the
> caller. This should get cleaned up later.
>
> Move uprobe_start_dup_mmap() to preserve the lock ordering.
>
> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Cc: stable@vger.kernel.org
> Reported-by: Josef Bacik <josef@toxicpanda.com>
> Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
> ---

Reviewed-by: Barry Song <baohua@kernel.org>

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 37/46] mm: fix deadlock of mremap() against UFFDIO_MOVE
  2026-10-26 23:17 ` [PATCH 37/46] mm: fix deadlock of mremap() against UFFDIO_MOVE David Hildenbrand (Arm)
  2026-10-27  9:23   ` Lorenzo Stoakes (ARM)
@ 2026-10-27  9:46   ` Muchun Song
  1 sibling, 0 replies; 93+ messages in thread
From: Muchun Song @ 2026-10-27  9:46 UTC (permalink / raw)
  To: David Hildenbrand (Arm)
  Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Xu Xin, Chengming Zhou, Chris Li, Kemeng Shi,
	Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn, Rakie Kim,
	Ying Huang, Jason Gunthorpe, linux-mm, linux-kernel, kexec,
	linux-fsdevel, linux-arch, linux-cxl, Chris Mason, stable



> On Oct 27, 2026, at 07:17, David Hildenbrand (Arm) <david@kernel.org> wrote:
> 
> From: Chris Mason <mason@kernel.org>
> 
> With per-VMA locks, UFFDIO_MOVE can run concurrently with mremap()
> on different VMAs in the same mm. Those VMAs can share page tables, so
> both operations can acquire the same pair of page-table locks.
> 
> UFFDIO_MOVE orders the locks by address, while mremap() takes the source
> lock first. These conflicting orders can deadlock; mremap() holding
> mmap_lock for writing no longer helps.
> 
> Move double_pt_lock() and double_pt_unlock() to mm/internal.h and use
> them for all page-table moves in mremap(). Preserve the source entry
> checks after acquiring both locks. Remove the comments claiming that
> exclusive mmap_lock makes lock ordering irrelevant.
> 
> In move_ptes(), make sure to just recheck source and destination PMD
> after taking the locks and drop the overly-long comment.
> 
> Fix generated by an LLM and sent by Chris Mason in private.
> 
> Fixes: 867a43a34ff8 ("userfaultfd: use per-vma locks in userfaultfd operations")
> Cc: stable@vger.kernel.org
> Signed-off-by: Chris Mason <mason@kernel.org>
> [ david: use new helpers consistently; simplify description and comments;
>         move_ptes() fixup ]
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>

Acked-by: Muchun Song <muchun.song@linux.dev>

Thanks.


^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 44/46] mm/cma: don't release CMA pages still in use
  2026-10-26 23:18 ` [PATCH 44/46] mm/cma: don't release CMA pages still in use David Hildenbrand (Arm)
  2026-10-27  8:55   ` Lorenzo Stoakes (ARM)
@ 2026-10-27  9:48   ` Muchun Song
  1 sibling, 0 replies; 93+ messages in thread
From: Muchun Song @ 2026-10-27  9:48 UTC (permalink / raw)
  To: David Hildenbrand (Arm)
  Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Xu Xin, Chengming Zhou, Chris Li, Kemeng Shi,
	Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn, Rakie Kim,
	Ying Huang, Jason Gunthorpe, linux-mm, linux-kernel, kexec,
	linux-fsdevel, linux-arch, linux-cxl, stable



> On Oct 27, 2026, at 07:18, David Hildenbrand (Arm) <david@kernel.org> wrote:
> 
> From: Rik van Riel <riel@surriel.com>
> 
> When a driver calls dma_free_contiguous() before quiescing DMA, the
> page might still have a reference from the device.
> put_page_testzero() there returns false, WARN fires, but the code proceeds
> to free_contig_frozen_range() putting a live page onto buddy and clearing
> the bitmap. A subsequent allocation can hand the same PFN to a new
> owner while the original holder still references it.
> 
> A concurrent put_page() that drops the last reference between the
> testzero loop and free_contig_frozen_range() can double-queue the page
> via page->lru, corrupting buddy lists.
> 
> Avoid the corruption by not freeing a CMA region if any of the
> pages inside are still in use.
> 
> Make it explicit in the warning that the driver allowed a leak.
> 
> While at it, use page_ref_freeze() to make the semantics clearer and
> switch to pr_warn_ratelimited().
> 
> Fixes: 9bda131c6093 ("mm: cma: add cma_alloc_frozen{_compound}()")
> Cc: stable@vger.kernel.org
> Signed-off-by: Rik van Riel <riel@surriel.com>
> Link: https://patch.msgid.link/20260811132045.5f114772@fangorn
> [ david: use page_ref_freeze() + pr_warn_ratelimited() ]
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>

Acked-by: Muchun Song <muchun.song@linux.dev>

Thanks


^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 26/46] mm/mmu_gather: fix flushing ranges with 4 GiB or larger
  2026-10-26 23:17 ` [PATCH 26/46] mm/mmu_gather: fix flushing ranges with 4 GiB or larger David Hildenbrand (Arm)
                     ` (2 preceding siblings ...)
  2026-10-27  7:35   ` Dev Jain
@ 2026-10-27  9:50   ` Muchun Song
  3 siblings, 0 replies; 93+ messages in thread
From: Muchun Song @ 2026-10-27  9:50 UTC (permalink / raw)
  To: David Hildenbrand (Arm)
  Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Pedro Falcato, Hugh Dickins, Pasha Tatashin,
	Pratyush Yadav, Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Xu Xin, Chengming Zhou, Chris Li, Kemeng Shi,
	Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn, Rakie Kim,
	Ying Huang, Jason Gunthorpe, linux-mm, linux-kernel, kexec,
	linux-fsdevel, linux-arch, linux-cxl, Josef Bacik, stable



> On Oct 27, 2026, at 07:17, David Hildenbrand (Arm) <david@kernel.org> wrote:
> 
> From: Josef Bacik <josef@toxicpanda.com>
> 
> __tlb_adjust_range() takes the size of the range which has to be flushed
> as an unsigned int. Its callers, tlb_flush_{pte,pmd,pud,p4d}_range(), get
> and pass an unsigned long. Consequently, a range that is 4 GiB or larger
> gets truncated, possibly to 0.
> 
> On arm64 with hugetlb, a 64k kernel can flush 16 GiB hugetlb PMDs, and a
> 16k kernel can flush 64 GiB PUDs through tlb_unshare_pmd_ptdesc(). So
> at least these two scenarios are affected.
> 
> Fix it by flushing the proper range instead of the truncated one.
> 
> Fix generated by an LLM and sent by Josef Bacik in private.
> 
> Fixes: b528e4b6405b ("mm/hugetlb: add tlb_remove_hugetlb_entry for handling hugetlb pages")
> Fixes: 8ce720d5bd91 ("mm/hugetlb: fix excessive IPI broadcasts when unsharing PMD tables using mmu_gather")
> Cc: stable@vger.kernel.org
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>
> Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
> [ david: use two-tab indent, simplify description ]
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>

Reviewed-by: Muchun Song <muchun.song@linux.dev>

Thanks.


^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 01/46] mm/mglru: don't use stack pointers when walking PUD and PMD tables
  2026-10-26 23:17 ` [PATCH 01/46] mm/mglru: don't use stack pointers when walking PUD and PMD tables David Hildenbrand (Arm)
                     ` (3 preceding siblings ...)
  2026-10-27  8:06   ` Lorenzo Stoakes (ARM)
@ 2026-10-27 10:22   ` Kairui Song
  4 siblings, 0 replies; 93+ messages in thread
From: Kairui Song @ 2026-10-27 10:22 UTC (permalink / raw)
  To: David Hildenbrand (Arm)
  Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Barry Song, Axel Rasmussen,
	Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang, Liam R. Howlett,
	Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
	Kees Cook, Peter Zijlstra, Jann Horn, Pedro Falcato,
	Hugh Dickins, Pasha Tatashin, Pratyush Yadav,
	Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe, linux-mm, linux-kernel,
	kexec, linux-fsdevel, linux-arch, linux-cxl, Josef Bacik, stable

On Tue, Oct 27, 2026 at 7:18 AM David Hildenbrand (Arm)
<david@kernel.org> wrote:
>
> From: Josef Bacik <josef@toxicpanda.com>
>
> MGLRU passes stack copies of page-table entries in walk_pud_range() and
> walk_pmd_range() when walking to the next level. These copies can become
> stale when khugepaged or MADV_DONTNEED (CONFIG_PT_RECLAIM) removes a PTE
> table concurrently.
>
> This pattern dates back to commit bd74fdaea146 ("mm: multi-gen LRU:
> support page table walks"). Likely, earlier locking masked the latent
> bug. Later changes exposed it: commit 1d65b771bc08 ("mm/khugepaged:
> retract_page_tables() without mmap or vma lock") allowed concurrent
> retraction, and commit cf4a65539c13 ("memcg-v1: no need for memcg locking
> for MGLRU") dropped the walker's outer RCU protection.
>
> The fix is simple, so just fix the original commit so we don't have to
> speculate. To fix it, pass the actual PMD/PUD pointers. This restores the
> RCU-protected lookup and validation against the live PMD. Note that the PUD
> handling is required as well to handle folded page tables correctly in all
> cases.
>
> Fix generated by an LLM and sent by Josef Bacik in private.
>
> Fixes: bd74fdaea146 ("mm: multi-gen LRU: support page table walks")
> Cc: stable@vger.kernel.org
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>
> [ david: handle walk_pud_range() as well, clarify+simplify description,
>          adjust Fixes: ]
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
> ---
>  mm/vmscan.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
>

Reviewed-by: Kairui Song <kasong@tencent.com>

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 02/46] fork: take mmap_lock before copying mm_struct
  2026-10-26 23:17 ` [PATCH 02/46] fork: take mmap_lock before copying mm_struct David Hildenbrand (Arm)
                     ` (2 preceding siblings ...)
  2026-10-27  9:45   ` Barry Song
@ 2026-10-27 10:38   ` Pedro Falcato
  3 siblings, 0 replies; 93+ messages in thread
From: Pedro Falcato @ 2026-10-27 10:38 UTC (permalink / raw)
  To: David Hildenbrand (Arm)
  Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Hugh Dickins, Pasha Tatashin, Pratyush Yadav,
	Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe, linux-mm, linux-kernel,
	kexec, linux-fsdevel, linux-arch, linux-cxl, stable, Josef Bacik

On Tue, Oct 27, 2026 at 12:17:22AM +0100, David Hildenbrand (Arm) wrote:
> dup_mm() copies the parent's mm_struct before dup_mmap() takes the
> mmap_lock. A concurrent brk() can leave the child with a stale mm->brk
> and newer heap mappings, causing later brk() requests to fail.
> 
> Other operations (e.g., PR_SET_MM) on the parent's mm_struct can similarly
> cause inconsistencies.
> 
> As a simple and robust fix, grab the parent's mmap_lock earlier. This
> way we don't need to update individual mm fields in dup_mmap() and
> keep missing ones. Stop updating the 4 existing members (total_vm, data_vm,
> exec_vm, stack_vm), as that is now no longer required.
> 
> Keep releasing the parent's mmap_lock in dup_mmap(), before
> userfaultfd completion, to avoid moving the userfaultfd handling into the
> caller. This should get cleaned up later.
> 
> Move uprobe_start_dup_mmap() to preserve the lock ordering.
> 
> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Cc: stable@vger.kernel.org
> Reported-by: Josef Bacik <josef@toxicpanda.com>
> Reviewed-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>

Reviewed-by: Pedro Falcato <pfalcato@suse.de>

FWIW, strictly speaking malloc() isn't usable in a forked
(multi-threaded) child, but glibc/musl provide this in a best-effort way.

-- 
Pedro

^ permalink raw reply	[flat|nested] 93+ messages in thread

* Re: [PATCH 04/46] mm/memfd: make f_pos accesses atomic
  2026-10-26 23:17 ` [PATCH 04/46] mm/memfd: make f_pos accesses atomic David Hildenbrand (Arm)
                     ` (3 preceding siblings ...)
  2026-10-27  8:46   ` Lorenzo Stoakes (ARM)
@ 2026-10-27 10:39   ` Pedro Falcato
  4 siblings, 0 replies; 93+ messages in thread
From: Pedro Falcato @ 2026-10-27 10:39 UTC (permalink / raw)
  To: David Hildenbrand (Arm)
  Cc: Andrew Morton, Johannes Weiner, Michal Hocko, Qi Zheng,
	Shakeel Butt, Lorenzo Stoakes, Kairui Song, Barry Song,
	Axel Rasmussen, Yuanchu Xie, Wei Xu, Baoquan He, Baolin Wang,
	Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Kees Cook, Peter Zijlstra,
	Jann Horn, Hugh Dickins, Pasha Tatashin, Pratyush Yadav,
	Matthew Wilcox (Oracle),
	Jan Kara, Zi Yan, Lance Yang, Rik van Riel, Harry Yoo,
	Alistair Popple, Nico Pache, Ryan Roberts, Dev Jain, Usama Arif,
	Kiryl Shutsemau, Matthew Brost, John Hubbard, Peter Xu,
	Will Deacon, Aneesh Kumar K.V, Nick Piggin, Oscar Salvador,
	Minchan Kim, Muchun Song, Xu Xin, Chengming Zhou, Chris Li,
	Kemeng Shi, Nhat Pham, Youngjun Park, Gregory Price, Joshua Hahn,
	Rakie Kim, Ying Huang, Jason Gunthorpe, linux-mm, linux-kernel,
	kexec, linux-fsdevel, linux-arch, linux-cxl, Josef Bacik, stable

On Tue, Oct 27, 2026 at 12:17:24AM +0100, David Hildenbrand (Arm) wrote:
> From: Josef Bacik <josef@toxicpanda.com>
> 
> Commit 9c225f2655e3 ("vfs: atomic f_pos accesses as per POSIX") made
> read(), write() and lseek() on a shared open file description of a regular
> file serialize on ->f_pos_lock.  The flag that asks for it,
> FMODE_ATOMIC_POS, is set in do_dentry_open().  A memfd is a regular file
> too, but its struct file comes from alloc_file_pseudo() and never passes
> through do_dentry_open(), so it does not get the flag:
> 
>   CPU0                                CPU1
>   write(memfd, "a", 1)                write(memfd, "b", 1)
>     pos = file->f_pos  (= 0)
>                                         pos = file->f_pos  (= 0)
>     vfs_write(..., &pos)
>                                         vfs_write(..., &pos)
>     file->f_pos = pos  (= 1)
>                                         file->f_pos = pos  (= 1)
> 
> One of the two bytes is overwritten.  Two threads writing 100000 bytes
> each, one at a time, to a memfd end up with a file that is far shorter than
> 200000 bytes, while the same program on a tmpfs file never loses a byte.
> 
> Set the flag when the memfd is created.  As for any other regular file the
> lock is only taken if the file is reachable in more than one way, and
> nothing a memfd does in read or write waits for another operation on the
> same file.  This cannot be done for all alloc_file_pseudo() files: anon
> inode files such as eventfd are S_IFREG as well, and a blocked read holding
> ->f_pos_lock would lock out the write that is supposed to wake it.
> 
> Fix generated by an LLM and sent by Josef Bacik in private.
> 
> Fixes: 9183df25fe7b ("shm: add memfd_create() syscall")
> Cc: stable@vger.kernel.org
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>
> [ david: minor description tweaks ]
> Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>

Reviewed-by: Pedro Falcato <pfalcato@suse.de> 

-- 
Pedro

^ permalink raw reply	[flat|nested] 93+ messages in thread

end of thread, other threads:[~2026-10-27 10:39 UTC | newest]

Thread overview: 93+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-26 23:17 [PATCH 00/46] mm: various (urgent?) fixes David Hildenbrand (Arm)
2026-10-26 23:17 ` [PATCH 01/46] mm/mglru: don't use stack pointers when walking PUD and PMD tables David Hildenbrand (Arm)
2026-10-27  1:32   ` Rik van Riel
2026-10-27  3:05   ` Qi Zheng
2026-10-27  7:20   ` Dev Jain
2026-10-27  8:06   ` Lorenzo Stoakes (ARM)
2026-10-27 10:22   ` Kairui Song
2026-10-26 23:17 ` [PATCH 02/46] fork: take mmap_lock before copying mm_struct David Hildenbrand (Arm)
2026-10-27  1:38   ` Rik van Riel
2026-10-27  8:18   ` Vlastimil Babka (SUSE)
2026-10-27  9:45   ` Barry Song
2026-10-27 10:38   ` Pedro Falcato
2026-10-26 23:17 ` [PATCH 03/46] mm/memfd: check for real shmem inodes before accessing shmem state David Hildenbrand (Arm)
2026-10-27  2:04   ` Rik van Riel
2026-10-27  8:13   ` Mike Rapoport
2026-10-26 23:17 ` [PATCH 04/46] mm/memfd: make f_pos accesses atomic David Hildenbrand (Arm)
2026-10-27  2:06   ` Rik van Riel
2026-10-27  3:34   ` Gregory Price
2026-10-27  8:44     ` Lorenzo Stoakes (ARM)
2026-10-27  8:15   ` Mike Rapoport
2026-10-27  8:46   ` Lorenzo Stoakes (ARM)
2026-10-27 10:39   ` Pedro Falcato
2026-10-26 23:17 ` [PATCH 05/46] mm/truncate: look again if a folio left the mapping David Hildenbrand (Arm)
2026-10-27  2:17   ` Rik van Riel
2026-10-26 23:17 ` [PATCH 06/46] mm/filemap: read mapping->a_ops->free_folio under i_lock David Hildenbrand (Arm)
2026-10-27  2:43   ` Rik van Riel
2026-10-26 23:17 ` [PATCH 07/46] mm/filemap: don't lose a folio lock wakeup to a signal David Hildenbrand (Arm)
2026-10-27  3:03   ` Rik van Riel
2026-10-26 23:17 ` [PATCH 08/46] mm/filemap: finish fault cleanup before dropping the fault lock David Hildenbrand (Arm)
2026-10-26 23:17 ` [PATCH 09/46] mm/rmap: handle device-exclusive entries in folio_referenced_one() David Hildenbrand (Arm)
2026-10-26 23:17 ` [PATCH 10/46] mm/huge_memory: fix list corruption when deferred_split_scan() races with deferred_split_folio() David Hildenbrand (Arm)
2026-10-26 23:17 ` [PATCH 11/46] mm/huge_memory: properly handle refcounted PUD mappings on fork David Hildenbrand (Arm)
2026-10-26 23:17 ` [PATCH 12/46] mm/huge_memory: fix livelock on device private folio David Hildenbrand (Arm)
2026-10-26 23:17 ` [PATCH 13/46] mm/huge_memory: fix truncate racing with PMD zapping David Hildenbrand (Arm)
2026-10-26 23:17 ` [PATCH 14/46] mm/huge_memory: fix zapping migration entries for device-private THPs David Hildenbrand (Arm)
2026-10-26 23:17 ` [PATCH 15/46] mm/khugepaged: always recheck the pmd in try_collapse_pte_mapped_thp() David Hildenbrand (Arm)
2026-10-26 23:17 ` [PATCH 16/46] mm/khugepaged: fix PMD table lock leak " David Hildenbrand (Arm)
2026-10-26 23:17 ` [PATCH 17/46] mm/khugepaged: preserve dirty bits when collapsing PTE-mapped THPs David Hildenbrand (Arm)
2026-10-26 23:17 ` [PATCH 18/46] mm/khugepaged: check if PTE table is empty in try_collapse_pte_mapped_thp() David Hildenbrand (Arm)
2026-10-26 23:17 ` [PATCH 19/46] mm/gup: recheck the PUD under PTL in follow_pud_mask() David Hildenbrand (Arm)
2026-10-26 23:17 ` [PATCH 20/46] mm/gup: fix clearing folios in memfd_pin_folios() David Hildenbrand (Arm)
2026-10-26 23:17 ` [PATCH 21/46] mm/gup: fix out-of-bounds write for nr_pages == 0 in GUP-fast David Hildenbrand (Arm)
2026-10-27  9:37   ` Lorenzo Stoakes (ARM)
2026-10-27  9:40   ` Muchun Song
2026-10-26 23:17 ` [PATCH 22/46] mm/gup: check for overflow when converting nr_pages to bytes " David Hildenbrand (Arm)
2026-10-27  9:34   ` Lorenzo Stoakes (ARM)
2026-10-27  9:44   ` Muchun Song
2026-10-26 23:17 ` [PATCH 23/46] mm/userfaultfd: write-lock the VMA before waking waiters when unregistering David Hildenbrand (Arm)
2026-10-27  8:16   ` Mike Rapoport
2026-10-27  8:43   ` Lorenzo Stoakes (ARM)
2026-10-26 23:17 ` [PATCH 24/46] mm/userfaultfd: wake all waiters on unregister David Hildenbrand (Arm)
2026-10-27  8:17   ` Mike Rapoport
2026-10-27  8:36   ` Lorenzo Stoakes (ARM)
2026-10-26 23:17 ` [PATCH 25/46] mm/userfaultfd: wake waiters when registration modes are removed David Hildenbrand (Arm)
2026-10-27  5:10   ` Gregory Price
2026-10-27  8:24     ` Lorenzo Stoakes (ARM)
2026-10-27  8:21   ` Mike Rapoport
2026-10-27  8:31   ` Lorenzo Stoakes (ARM)
2026-10-26 23:17 ` [PATCH 26/46] mm/mmu_gather: fix flushing ranges with 4 GiB or larger David Hildenbrand (Arm)
2026-10-27  3:06   ` Qi Zheng
2026-10-27  3:40   ` Gregory Price
2026-10-27  7:35   ` Dev Jain
2026-10-27  9:50   ` Muchun Song
2026-10-26 23:17 ` [PATCH 27/46] mm/mmu_notifier: finish non-blocking interval invalidation on error David Hildenbrand (Arm)
2026-10-27  9:33   ` Lorenzo Stoakes (ARM)
2026-10-26 23:17 ` [PATCH 28/46] mm/mmu_notifier: set ->mm only after mmgrab() David Hildenbrand (Arm)
2026-10-27  3:42   ` Gregory Price
2026-10-27  8:50   ` Lorenzo Stoakes (ARM)
2026-10-26 23:17 ` [PATCH 29/46] mm/mremap: use pudp_huge_get_and_clear() when moving huge PUDs David Hildenbrand (Arm)
2026-10-26 23:17 ` [PATCH 30/46] mm/mremap: recheck PUDs under the page table lock David Hildenbrand (Arm)
2026-10-26 23:17 ` [PATCH 31/46] mm/mremap: fix moving PUD leaves David Hildenbrand (Arm)
2026-10-26 23:17 ` [PATCH 32/46] mm/memory_hotplug: avoid races in pfn_to_online_page() with dying pgmap David Hildenbrand (Arm)
2026-10-26 23:17 ` [PATCH 33/46] mm/madvise: fix data loss from MADV_FREE on a KSM page David Hildenbrand (Arm)
2026-10-26 23:17 ` [PATCH 34/46] mm/memory: reject remote COW faults on PFN mappings David Hildenbrand (Arm)
2026-10-26 23:17 ` [PATCH 35/46] mm: fix unmap_mapping_range() beyond 4 GiB on 32-bit David Hildenbrand (Arm)
2026-10-26 23:17 ` [PATCH 36/46] mm: fix unkillable fault loop on MAP_DROPPABLE memory David Hildenbrand (Arm)
2026-10-26 23:17 ` [PATCH 37/46] mm: fix deadlock of mremap() against UFFDIO_MOVE David Hildenbrand (Arm)
2026-10-27  9:23   ` Lorenzo Stoakes (ARM)
2026-10-27  9:46   ` Muchun Song
2026-10-26 23:17 ` [PATCH 38/46] mm/ksm: reset the unstable trees of all nodes David Hildenbrand (Arm)
2026-10-27  9:14   ` Lorenzo Stoakes (ARM)
2026-10-26 23:17 ` [PATCH 39/46] mm/ksm: fix use of a freed anon_vma at swap-in David Hildenbrand (Arm)
2026-10-26 23:18 ` [PATCH 40/46] mm/ksm: check large swap-cache folios before mapping them David Hildenbrand (Arm)
2026-10-27  9:00   ` Lorenzo Stoakes (ARM)
2026-10-26 23:18 ` [PATCH 41/46] mm/vma: call ->may_split() before a partial merge David Hildenbrand (Arm)
2026-10-27  3:45   ` Gregory Price
2026-10-26 23:18 ` [PATCH 42/46] mm/huge_memory: split huge PUDs when adjusting VMA boundaries David Hildenbrand (Arm)
2026-10-26 23:18 ` [PATCH 43/46] mm/vma: don't leak the charge for stack growth David Hildenbrand (Arm)
2026-10-26 23:18 ` [PATCH 44/46] mm/cma: don't release CMA pages still in use David Hildenbrand (Arm)
2026-10-27  8:55   ` Lorenzo Stoakes (ARM)
2026-10-27  9:48   ` Muchun Song
2026-10-26 23:18 ` [PATCH 45/46] mm/memory-tiers: unregister empty tiers outside memory_tier_lock David Hildenbrand (Arm)
2026-10-26 23:18 ` [PATCH 46/46] fs/proc/task_mmu: refuse addresses beyond 32 bits on 32bit David Hildenbrand (Arm)

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®