]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
mm: abstract reading sysctl_max_map_count, and READ_ONCE()
authorLorenzo Stoakes (Oracle) <ljs@kernel.org>
Wed, 11 Mar 2026 17:24:37 +0000 (17:24 +0000)
committerAndrew Morton <akpm@linux-foundation.org>
Sun, 5 Apr 2026 20:53:28 +0000 (13:53 -0700)
Concurrent reads and writes of sysctl_max_map_count are possible, so we
should READ_ONCE() and WRITE_ONCE().

The sysctl procfs logic already enforces WRITE_ONCE(), so abstract the
read side with get_sysctl_max_map_count().

While we're here, also move the field to mm/internal.h and add the getter
there since only mm interacts with it, there's no need for anybody else to
have access.

Finally, update the VMA userland tests to reflect the change.

Link: https://lkml.kernel.org/r/0715259eb37cbdfde4f9e5db92a20ec7110a1ce5.1773249037.git.ljs@kernel.org
Signed-off-by: Lorenzo Stoakes (Oracle) <ljs@kernel.org>
Reviewed-by: Pedro Falcato <pfalcato@suse.de>
Cc: Jann Horn <jannh@google.com>
Cc: Jianzhou Zhao <luckd0g@163.com>
Cc: Liam Howlett <liam.howlett@oracle.com>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Oscar Salvador <osalvador@suse.de>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Vlastimil Babka <vbabka@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
include/linux/mm.h
mm/internal.h
mm/mmap.c
mm/mremap.c
mm/nommu.c
mm/vma.c
tools/testing/vma/include/custom.h
tools/testing/vma/include/dup.h
tools/testing/vma/main.c

index efb8be5d259cc8ae4fcb1075c2beb0fcb786e3fb..25ba5816e02bc73a2ea99c7aa42c44b83465d1c2 100644 (file)
@@ -207,8 +207,6 @@ static inline void __mm_zero_struct_page(struct page *page)
 #define MAPCOUNT_ELF_CORE_MARGIN       (5)
 #define DEFAULT_MAX_MAP_COUNT  (USHRT_MAX - MAPCOUNT_ELF_CORE_MARGIN)
 
-extern int sysctl_max_map_count;
-
 extern unsigned long sysctl_user_reserve_kbytes;
 extern unsigned long sysctl_admin_reserve_kbytes;
 
index f50a0376b87e81b8ea76f19c060113b672baa164..62d80fd37ae1fbfbe90e3731f1ef81c79650d8fd 100644 (file)
@@ -1863,4 +1863,10 @@ static inline int pmdp_test_and_clear_young_notify(struct vm_area_struct *vma,
 
 #endif /* CONFIG_MMU_NOTIFIER */
 
+extern int sysctl_max_map_count;
+static inline int get_sysctl_max_map_count(void)
+{
+       return READ_ONCE(sysctl_max_map_count);
+}
+
 #endif /* __MM_INTERNAL_H */
index 843160946aa5f481c33c6cb98a59443cc4c9d436..79544d8934111d9e75e570204aeaaab728ebba0c 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -375,7 +375,7 @@ unsigned long do_mmap(struct file *file, unsigned long addr,
                return -EOVERFLOW;
 
        /* Too many mappings? */
-       if (mm->map_count > sysctl_max_map_count)
+       if (mm->map_count > get_sysctl_max_map_count())
                return -ENOMEM;
 
        /*
index e8c3021dd841f190d139dfd85aa0905869ad0e8a..ba6c690f6c1baa82d9b8aaa9294c340f5e694028 100644 (file)
@@ -1045,7 +1045,7 @@ static unsigned long prep_move_vma(struct vma_remap_struct *vrm)
         * which may not merge, then (if MREMAP_DONTUNMAP is not set) unmap the
         * source, which may split, causing a net increase of 2 mappings.
         */
-       if (current->mm->map_count + 2 > sysctl_max_map_count)
+       if (current->mm->map_count + 2 > get_sysctl_max_map_count())
                return -ENOMEM;
 
        if (vma->vm_ops && vma->vm_ops->may_split) {
@@ -1813,7 +1813,7 @@ static unsigned long check_mremap_params(struct vma_remap_struct *vrm)
         * net increased map count of 2. In move_vma() we check for headroom of
         * 2 additional mappings, so check early to avoid bailing out then.
         */
-       if (current->mm->map_count + 4 > sysctl_max_map_count)
+       if (current->mm->map_count + 4 > get_sysctl_max_map_count())
                return -ENOMEM;
 
        return 0;
index c3a23b082adb94e2fcb91bbd3c604ac09291c849..ed3934bc2de48305fde8f89f8379a0b0cd3fe44f 100644 (file)
@@ -1317,7 +1317,7 @@ static int split_vma(struct vma_iterator *vmi, struct vm_area_struct *vma,
                return -ENOMEM;
 
        mm = vma->vm_mm;
-       if (mm->map_count >= sysctl_max_map_count)
+       if (mm->map_count >= get_sysctl_max_map_count())
                return -ENOMEM;
 
        region = kmem_cache_alloc(vm_region_jar, GFP_KERNEL);
index b7055c264b5d3fbfeb0c2232ec1e3573c7248137..4d21e7d8e93c47053c8367bcf11db1f0471cb4ed 100644 (file)
--- a/mm/vma.c
+++ b/mm/vma.c
@@ -590,7 +590,7 @@ out_free_vma:
 static int split_vma(struct vma_iterator *vmi, struct vm_area_struct *vma,
                     unsigned long addr, int new_below)
 {
-       if (vma->vm_mm->map_count >= sysctl_max_map_count)
+       if (vma->vm_mm->map_count >= get_sysctl_max_map_count())
                return -ENOMEM;
 
        return __split_vma(vmi, vma, addr, new_below);
@@ -1394,7 +1394,7 @@ static int vms_gather_munmap_vmas(struct vma_munmap_struct *vms,
                 * its limit temporarily, to help free resources as expected.
                 */
                if (vms->end < vms->vma->vm_end &&
-                   vms->vma->vm_mm->map_count >= sysctl_max_map_count) {
+                   vms->vma->vm_mm->map_count >= get_sysctl_max_map_count()) {
                        error = -ENOMEM;
                        goto map_count_exceeded;
                }
@@ -2868,7 +2868,7 @@ int do_brk_flags(struct vma_iterator *vmi, struct vm_area_struct *vma,
        if (!may_expand_vm(mm, vm_flags, len >> PAGE_SHIFT))
                return -ENOMEM;
 
-       if (mm->map_count > sysctl_max_map_count)
+       if (mm->map_count > get_sysctl_max_map_count())
                return -ENOMEM;
 
        if (security_vm_enough_memory_mm(mm, len >> PAGE_SHIFT))
index 7150e09122b27fa76cfdc2527e45ee9e545a6568..6c62a38a2f6f6bf2b746b3adf6c4bfa401611320 100644 (file)
@@ -21,9 +21,6 @@ extern unsigned long dac_mmap_min_addr;
 #define VM_BUG_ON(_expr) (BUG_ON(_expr))
 #define VM_BUG_ON_VMA(_expr, _vma) (BUG_ON(_expr))
 
-/* We hardcode this for now. */
-#define sysctl_max_map_count 0x1000000UL
-
 #define TASK_SIZE ((1ul << 47)-PAGE_SIZE)
 
 /*
index 5eb313beb43dea7ae8fc35dd7b5d00ccf4cbd0bb..8865ffe046d8122d148c756c4b54a488295ae6c7 100644 (file)
@@ -419,6 +419,9 @@ struct vma_iterator {
 
 #define EMPTY_VMA_FLAGS ((vma_flags_t){ })
 
+#define MAPCOUNT_ELF_CORE_MARGIN       (5)
+#define DEFAULT_MAX_MAP_COUNT  (USHRT_MAX - MAPCOUNT_ELF_CORE_MARGIN)
+
 /* What action should be taken after an .mmap_prepare call is complete? */
 enum mmap_action_type {
        MMAP_NOTHING,           /* Mapping is complete, no further action. */
@@ -1342,3 +1345,9 @@ static inline void vma_set_file(struct vm_area_struct *vma, struct file *file)
        swap(vma->vm_file, file);
        fput(file);
 }
+
+extern int sysctl_max_map_count;
+static inline int get_sysctl_max_map_count(void)
+{
+       return READ_ONCE(sysctl_max_map_count);
+}
index 49b09e97a51ffa0d03fd037635bca1e991a6b56e..18338f5d29e00d04e0d02fa1d0a18ce1971e5f2e 100644 (file)
@@ -14,6 +14,8 @@
 #include "tests/mmap.c"
 #include "tests/vma.c"
 
+int sysctl_max_map_count __read_mostly = DEFAULT_MAX_MAP_COUNT;
+
 /* Helper functions which utilise static kernel functions. */
 
 struct vm_area_struct *merge_existing(struct vma_merge_struct *vmg)