summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-11-05 12:32:29 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2026-11-05 12:32:29 -0800
commitafd661f6a26438c407bd9928ea16e80c14b121d9 (patch)
tree6ecd7744905f3e3949e4b5f07deb5bf79ff0fdfc /include
parent05441d697f7f9a927264f4058cbbc6a03dfcac9d (diff)
parent19eab4cf787c917bfb7615460933e4ae894af65b (diff)
Merge tag 'mm-hotfixes-stable-2026-11-04-20-02' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
Pull MM fixes from Andrew Morton: - "mm: avoid losing atomic VMA flags" (Lorenzo Stoakes): Preserve guard-page and soft-dirty state across VMA changes. Prevent fork and THP collapse from losing guard markers, and keep changes visible to applications which track modified memory. - "MAINTAINERS: MM updates" (David Hildenbrand): Start routing more MM components through mm/core.git and add Zi Yan as a THP co-maintainer. Update component coverage and integration branches as part of the transition to separate MM component trees. - "mm/hugetlb: fix mremap bugs" (Li Zhe): Fix hugetlb mremap deadlocks and truncated move lengths. Prevent userfaultfd poison markers from affecting other processes through shared hugetlb page tables. - "MAINTAINERS updates for page and slab allocators" (Vlastimil Babka): Add Johannes Weiner as a page allocator co-maintainer and update page and slab allocator entries for their component trees and integration through mm/linux. - "mm/damon: fix three race bugs in sysfs and core" (SJ Park): Serialize DAMOS tuning updates and stop monitoring contexts from sharing mutable state. Avoid interference between concurrent DAMON instances and incorrect auto-tuning. - "mm: page_alloc: fix reserve access for non-blocking requests" (Johannes Weiner): Stop ordinary non-blocking allocations from consuming reserves or bypassing watermarks. Avoid severe allocation stalls under memory pressure and preserve reserves for requests entitled to use them. - "mm/cma: accept memory of CMA areas reserved with memblock_reserve()" (Mike Rapoport): Accept memory in fixed-address and multi-range CMA reservations. Prevent fatal accesses to these pages in TDX and SEV-SNP guests. - Summary of singletons in this merge: Several fixes address crashes and unsafe memory access. Failed THP collapse now flushes stale translations before releasing pages which another collapse can free. A truncation race with MADV_DONTNEED could remove still-mapped shmem pages and hit a kernel BUG. Large-folio page-table scans no longer wrap addresses and crash near address-space boundaries. Hugetlb vmemmap optimization no longer causes write faults from racing reference-count operations. Memory-cgroup teardown is also protected against reclaim work accessing released state. KSM now preserves userfaultfd protection during merging and unmerging, and retains soft-dirty information needed by incremental memory dumpers. Reads of /proc/PID/maps and related files no longer omit continuously mapped ranges during concurrent VMA changes. There are also fixes for expanding mixed mappings with mremap() and querying NUMA placement with tagged addresses. Swapoff checks for signals while processing large address spaces and shmem files, so it can be interrupted without holding up suspend until the whole object is read. Costly allocations with cheap smaller-order fallbacks avoid direct reclaim and compaction. Reported arm64 PostgreSQL tests improved from 58,602 to 157,246 transactions per second with defrag_mode disabled; this addresses a buffered-write regression under fragmentation. Background reclaim can recover on the highest-numbered memory node after it has given up, and 32-bit writeback threshold calculations no longer overflow and assign incorrect dirty-memory limits. * tag 'mm-hotfixes-stable-2026-11-04-20-02' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm: (43 commits) MAINTAINERS: move SLAB ALLOCATOR under MEMORY MANAGEMENT MAINTAINERS: add Johannes as the page allocator co-maintainer MAINTAINERS: route more MM changes through mm/core.git MAINTAINERS: rename and move MEMORY HOT(UN)PLUG MAINTAINERS: add missing files to MM component sections MAINTAINERS: sort entries in MM sections MAINTAINERS: add Zi Yan as co-maintainer for MEMORY MANAGEMENT - THP MAINTAINERS: TMPFS (SHMEM FILESYSTEM) updates MAINTAINERS: mention for-next branch in MEMORY MANAGEMENT - MEMORY MAP mm: memcontrol: fix NULL pointer deref and UAF from high_work_func() on dying memcg mm/cma: accept memory of CMA areas reserved at a fixed address mm/cma: accept memory of multi-range CMA areas mm/page_alloc: avoid direct reclaim and compaction for costly __GFP_NORETRY allocations mm: page_alloc: remove ALLOC_NON_BLOCK from ALLOC_RESERVES mm: page_alloc: do not give all non-blocking requests reserve access mm/hugetlb_vmemmap: map the shared tail page writable fs/proc/task_mmu: fix missed VMAs when reading /proc/PID/maps and friends selftests/mm: fix khugepaged_race build with older glibc mm/vma: update VMA iterator state on error in new VMA merge mm/migrate: snapshot the source nid before the misplaced migration ...
Diffstat (limited to 'include')
-rw-r--r--include/linux/damon.h10
-rw-r--r--include/linux/hugetlb.h15
-rw-r--r--include/linux/mm.h166
-rw-r--r--include/linux/mmap_lock.h22
-rw-r--r--include/linux/userfaultfd_k.h16
5 files changed, 123 insertions, 106 deletions
diff --git a/include/linux/damon.h b/include/linux/damon.h
index 63050eb2206a..380f9cf6ddd8 100644
--- a/include/linux/damon.h
+++ b/include/linux/damon.h
@@ -958,6 +958,16 @@ struct damon_ctx {
/* @rnd_state: Per-ctx PRNG state for damon_rand(). */
struct rnd_state rnd_state;
+ /*
+ * number of regions after last merge. Read kdamond_split_regions()
+ * for more details.
+ */
+ unsigned long last_nr_regions;
+ /*
+ * number of damon_split_some_regions() invocations for this context.
+ * Read damon_split_some_regions() for more details.
+ */
+ unsigned long region_split_rotation;
};
/* Get a random number in [@l, @r) using @ctx's lockless PRNG. */
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
index 5029c7241863..58f755e70e96 100644
--- a/include/linux/hugetlb.h
+++ b/include/linux/hugetlb.h
@@ -121,10 +121,9 @@ void hugepage_put_subpool(struct hugepage_subpool *spool);
void hugetlb_dup_vma_private(struct vm_area_struct *vma);
void clear_vma_resv_huge_pages(struct vm_area_struct *vma);
-int move_hugetlb_page_tables(struct vm_area_struct *vma,
- struct vm_area_struct *new_vma,
- unsigned long old_addr, unsigned long new_addr,
- unsigned long len);
+unsigned long move_hugetlb_page_tables(struct vm_area_struct *vma,
+ struct vm_area_struct *new_vma, unsigned long old_addr,
+ unsigned long new_addr, unsigned long len);
int copy_hugetlb_page_range(struct mm_struct *, struct mm_struct *,
struct vm_area_struct *, struct vm_area_struct *);
void unmap_hugepage_range(struct vm_area_struct *,
@@ -338,11 +337,9 @@ static inline int copy_hugetlb_page_range(struct mm_struct *dst,
return 0;
}
-static inline int move_hugetlb_page_tables(struct vm_area_struct *vma,
- struct vm_area_struct *new_vma,
- unsigned long old_addr,
- unsigned long new_addr,
- unsigned long len)
+static inline unsigned long move_hugetlb_page_tables(struct vm_area_struct *vma,
+ struct vm_area_struct *new_vma, unsigned long old_addr,
+ unsigned long new_addr, unsigned long len)
{
BUG();
return 0;
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 9f167950926a..6af3b7008f1a 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -602,7 +602,7 @@ enum {
#define VMA_LOCKED_MASK mk_vma_flags(VMA_LOCKED_BIT, VMA_LOCKONFAULT_BIT)
/* These flags can be updated atomically via VMA/mmap read lock. */
-#define VM_ATOMIC_SET_ALLOWED VM_MAYBE_GUARD
+#define VMA_ATOMIC_SET_ALLOWED mk_vma_flags(VMA_MAYBE_GUARD_BIT)
/* Arch-specific flags to clear when updating VM flags on protection change */
#ifndef VM_ARCH_CLEAR
@@ -987,22 +987,6 @@ static inline void vm_flags_reset(struct vm_area_struct *vma,
vm_flags_init(vma, flags);
}
-static inline void vma_flags_reset_once(struct vm_area_struct *vma,
- vma_flags_t *flags)
-{
- const unsigned long word = flags->__vma_flags[0];
-
- /* It is assumed only the first system word must be written once. */
- vma_flags_overwrite_word_once(&vma->flags, word);
- /* The remainder can be copied normally. */
- if (NUM_VMA_FLAG_BITS > BITS_PER_LONG) {
- unsigned long *dst = &vma->flags.__vma_flags[1];
- const unsigned long *src = &flags->__vma_flags[1];
-
- bitmap_copy(dst, src, NUM_VMA_FLAG_BITS - BITS_PER_LONG);
- }
-}
-
static inline void vm_flags_set(struct vm_area_struct *vma,
vm_flags_t flags)
{
@@ -1039,48 +1023,6 @@ static inline void vm_flags_mod(struct vm_area_struct *vma,
__vm_flags_mod(vma, set, clear);
}
-static __always_inline bool __vma_atomic_valid_flag(struct vm_area_struct *vma,
- vma_flag_t bit)
-{
- const vm_flags_t mask = BIT((__force int)bit);
-
- /* Only specific flags are permitted */
- if (WARN_ON_ONCE(!(mask & VM_ATOMIC_SET_ALLOWED)))
- return false;
-
- return true;
-}
-
-/*
- * Set VMA flag atomically. Requires only VMA/mmap read lock. Only specific
- * valid flags are allowed to do this.
- */
-static __always_inline void vma_set_atomic_flag(struct vm_area_struct *vma,
- vma_flag_t bit)
-{
- unsigned long *bitmap = vma->flags.__vma_flags;
-
- vma_assert_stabilised(vma);
- if (__vma_atomic_valid_flag(vma, bit))
- set_bit((__force int)bit, bitmap);
-}
-
-/*
- * Test for VMA flag atomically. Requires no locks. Only specific valid flags
- * are allowed to do this.
- *
- * This is necessarily racey, so callers must ensure that serialisation is
- * achieved through some other means, or that races are permissible.
- */
-static __always_inline bool vma_test_atomic_flag(struct vm_area_struct *vma,
- vma_flag_t bit)
-{
- if (__vma_atomic_valid_flag(vma, bit))
- return test_bit((__force int)bit, &vma->vm_flags);
-
- return false;
-}
-
/* Set an individual VMA flag in flags, non-atomically. */
static __always_inline void vma_flags_set_flag(vma_flags_t *flags,
vma_flag_t bit)
@@ -1302,35 +1244,25 @@ static __always_inline vma_flags_t vma_flags_diff_pair(const vma_flags_t *flags,
return dst;
}
-/* Determine if flags and flags_other have precisely the same flags set. */
+/*
+ * Determine if flags and flags_other have precisely the same flags set,
+ * excluding atomic VMA flags.
+ */
static __always_inline bool vma_flags_same_pair(const vma_flags_t *flags,
- const vma_flags_t *flags_other)
+ const vma_flags_t *flags_other)
{
- const unsigned long *bitmap = flags->__vma_flags;
- const unsigned long *bitmap_other = flags_other->__vma_flags;
-
- return bitmap_equal(bitmap, bitmap_other, NUM_VMA_FLAG_BITS);
-}
+ vma_flags_t diff = vma_flags_diff_pair(flags, flags_other);
-/* Determine if flags and flags_other have precisely the same flags set. */
-static __always_inline bool vma_flags_same_mask(const vma_flags_t *flags,
- vma_flags_t flags_other)
-{
- const unsigned long *bitmap = flags->__vma_flags;
- const unsigned long *bitmap_other = flags_other.__vma_flags;
+ /*
+ * Atomic VMA flags may be set concurrently under the VMA read lock, so
+ * are disregarded for equality testing purposes.
+ */
+ vma_flags_clear_mask(&diff, VMA_ATOMIC_SET_ALLOWED);
- return bitmap_equal(bitmap, bitmap_other, NUM_VMA_FLAG_BITS);
+ return vma_flags_empty(&diff);
}
/*
- * Helper macro to determine if only the specific flags are set, e.g.:
- *
- * if (vma_flags_same(&flags, VMA_WRITE_BIT) { ... }
- */
-#define vma_flags_same(flags, ...) \
- vma_flags_same_mask(flags, mk_vma_flags(__VA_ARGS__))
-
-/*
* Test whether a specific flag in the VMA is set, e.g.:
*
* if (vma_test(vma, VMA_READ_BIT)) { ... }
@@ -1436,6 +1368,78 @@ static __always_inline void vma_clear_flags_mask(struct vm_area_struct *vma,
#define vma_clear_flags(vma, ...) \
vma_clear_flags_mask(vma, mk_vma_flags(__VA_ARGS__))
+static __always_inline bool __vma_atomic_valid_flag(struct vm_area_struct *vma,
+ vma_flag_t bit)
+{
+ const vma_flags_t mask = VMA_ATOMIC_SET_ALLOWED;
+
+ /* Is this flag allowed to be set atomically? */
+ if (WARN_ON_ONCE(!vma_flags_test(&mask, bit)))
+ return false;
+
+ return true;
+}
+
+/*
+ * Set VMA flag atomically. Requires only VMA/mmap read lock. Only specific
+ * valid flags are allowed to do this.
+ */
+static __always_inline void vma_set_atomic_flag(struct vm_area_struct *vma,
+ vma_flag_t bit)
+{
+ unsigned long *bitmap = vma->flags.__vma_flags;
+
+ vma_assert_stabilised(vma);
+ if (__vma_atomic_valid_flag(vma, bit))
+ set_bit((__force int)bit, bitmap);
+}
+
+/*
+ * Test for VMA flag atomically. Requires no locks. Only specific valid flags
+ * are allowed to do this.
+ *
+ * This is necessarily racey, so callers must ensure that serialisation is
+ * achieved through some other means, or that races are permissible.
+ */
+static __always_inline bool vma_test_atomic_flag(struct vm_area_struct *vma,
+ vma_flag_t bit)
+{
+ if (__vma_atomic_valid_flag(vma, bit))
+ return test_bit((__force int)bit, &vma->vm_flags);
+
+ return false;
+}
+
+/*
+ * Overwrite the VMA's flags with new ones, preserving atomic VMA flags in the
+ * process. The write is done once and once only.
+ */
+static inline void vma_overwrite_flags(struct vm_area_struct *vma,
+ vma_flags_t new_flags)
+{
+ vma_flags_t atomic;
+
+ vma_assert_write_locked(vma);
+
+ /*
+ * Preserve the VMA's atomic flags, which are kept stable by the VMA
+ * write lock.
+ */
+ atomic = vma_flags_and_mask(&vma->flags, VMA_ATOMIC_SET_ALLOWED);
+ vma_flags_clear_mask(&new_flags, VMA_ATOMIC_SET_ALLOWED);
+ vma_flags_set_mask(&new_flags, atomic);
+
+ /* It is assumed only the first system word must be written once. */
+ vma_flags_overwrite_word_once(&vma->flags, new_flags.__vma_flags[0]);
+ /* The remainder can be copied normally. */
+ if (NUM_VMA_FLAG_BITS > BITS_PER_LONG) {
+ unsigned long *dst = &vma->flags.__vma_flags[1];
+ const unsigned long *src = &new_flags.__vma_flags[1];
+
+ bitmap_copy(dst, src, NUM_VMA_FLAG_BITS - BITS_PER_LONG);
+ }
+}
+
/*
* Test whether a specific VMA flag is set in a VMA descriptor, e.g.:
*
diff --git a/include/linux/mmap_lock.h b/include/linux/mmap_lock.h
index 11b3ffef3966..9ccbbcbd7aca 100644
--- a/include/linux/mmap_lock.h
+++ b/include/linux/mmap_lock.h
@@ -17,6 +17,13 @@ extern int rcuwait_wake_up(struct rcuwait *w);
#define MMAP_LOCK_INITIALIZER(name) \
.mmap_lock = __RWSEM_INITIALIZER((name).mmap_lock),
+/* Tie a VMA iterator to mm write lock state at iterator initialisation. */
+struct vma_rcu_iter {
+ struct mm_struct *mm;
+ struct vma_iterator *vmi;
+ unsigned int mm_wr_seq;
+};
+
DECLARE_TRACEPOINT(mmap_lock_start_locking);
DECLARE_TRACEPOINT(mmap_lock_acquire_returned);
DECLARE_TRACEPOINT(mmap_lock_released);
@@ -509,6 +516,16 @@ static inline void vma_mark_detached(struct vm_area_struct *vma)
struct vm_area_struct *lock_vma_under_rcu(struct mm_struct *mm,
unsigned long address);
+static inline void vma_rcu_iter_init(struct vma_rcu_iter *rvmi,
+ struct mm_struct *mm, struct vma_iterator *vmi,
+ unsigned long addr)
+{
+ vma_iter_init(vmi, mm, addr);
+ rvmi->mm = mm;
+ rvmi->vmi = vmi;
+ rvmi->mm_wr_seq = UINT_MAX; /* Start odd so changed by default. */
+}
+
/*
* Locks next vma pointed by the iterator. Confirms the locked vma has not
* been modified and will retry under mmap_lock protection if modification
@@ -516,9 +533,8 @@ struct vm_area_struct *lock_vma_under_rcu(struct mm_struct *mm,
* Returns either a valid locked VMA, NULL if no more VMAs or -EINTR if the
* process was interrupted.
*/
-struct vm_area_struct *lock_next_vma(struct mm_struct *mm,
- struct vma_iterator *iter,
- unsigned long address);
+struct vm_area_struct *lock_next_vma(struct vma_rcu_iter *rvmi,
+ unsigned long from_addr);
static inline void vma_assert_can_modify(struct vm_area_struct *vma)
{
diff --git a/include/linux/userfaultfd_k.h b/include/linux/userfaultfd_k.h
index a14b8a9ffb7b..ebd86677b052 100644
--- a/include/linux/userfaultfd_k.h
+++ b/include/linux/userfaultfd_k.h
@@ -168,22 +168,12 @@ static inline bool is_mergeable_vm_userfaultfd_ctx(struct vm_area_struct *vma,
}
/*
- * Never enable huge pmd sharing on some uffd registered vmas:
- *
- * - VM_UFFD_WP and VM_UFFD_RWP VMAs, because the write protect / access
- * tracking information is per pgtable entry.
- *
- * - VM_UFFD_MINOR VMAs, because otherwise we would never get minor faults for
- * VMAs which share huge pmds. (If you have two mappings to the same
- * underlying pages, and fault in the non-UFFD-registered one with a write,
- * with huge pmd sharing this would *also* setup the second UFFD-registered
- * mapping, and we'd not get minor faults.)
+ * Never enable huge pmd sharing on userfaultfd registered VMAs, because
+ * userfaultfd state can be tracked per VMA or per page table entry.
*/
static inline bool uffd_disable_huge_pmd_share(struct vm_area_struct *vma)
{
- return vma_test_any_mask(vma,
- mk_vma_flags_from_masks(VMA_UFFD_WP, VMA_UFFD_RWP,
- VMA_UFFD_MINOR));
+ return vma->vm_userfaultfd_ctx.ctx;
}
/*