Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mm/nommu: factor out check for NOMMU shared mappings into is_nommu_shared_mapping()

Patch series "mm/nommu: don't use VM_MAYSHARE for MAP_PRIVATE mappings".

Trying to reduce the confusion around VM_SHARED and VM_MAYSHARE first
requires !CONFIG_MMU to stop using VM_MAYSHARE for MAP_PRIVATE mappings.
CONFIG_MMU only sets VM_MAYSHARE for MAP_SHARED mappings.

This paves the way for further VM_MAYSHARE and VM_SHARED cleanups: for
example, renaming VM_MAYSHARED to VM_MAP_SHARED to make it cleaner what is
actually means.

Let's first get the weird case out of the way and not use VM_MAYSHARE in
MAP_PRIVATE mappings, using a new VM_MAYOVERLAY flag instead.


This patch (of 3):

We want to stop using VM_MAYSHARE in private mappings to pave the way for
clarifying the semantics of VM_MAYSHARE vs. VM_SHARED and reduce the
confusion. While CONFIG_MMU uses VM_MAYSHARE to represent MAP_SHARED,
!CONFIG_MMU also sets VM_MAYSHARE for selected R/O private file mappings
that are an effective overlay of a file mapping.

Let's factor out all relevant VM_MAYSHARE checks in !CONFIG_MMU code into
is_nommu_shared_mapping() first.

Note that whenever VM_SHARED is set, VM_MAYSHARE must be set as well
(unless there is a serious BUG). So there is not need to test for
VM_SHARED manually.

No functional change intended.

Link: https://lkml.kernel.org/r/20230102160856.500584-1-david@redhat.com
Link: https://lkml.kernel.org/r/20230102160856.500584-2-david@redhat.com
Signed-off-by: David Hildenbrand <david@redhat.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: David Hildenbrand <david@redhat.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Nicolas Pitre <nico@fluxnic.net>
Cc: Pavel Begunkov <asml.silence@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

David Hildenbrand and committed by
Andrew Morton
fc4f4be9 da0618c1

+27 -11
+1 -1
drivers/char/mem.c
··· 343 343 /* can't do an in-place private mapping if there's no MMU */ 344 344 static inline int private_mapping_ok(struct vm_area_struct *vma) 345 345 { 346 - return vma->vm_flags & VM_MAYSHARE; 346 + return is_nommu_shared_mapping(vma->vm_flags); 347 347 } 348 348 #else 349 349
+1 -1
fs/cramfs/inode.c
··· 437 437 438 438 static int cramfs_physmem_mmap(struct file *file, struct vm_area_struct *vma) 439 439 { 440 - return vma->vm_flags & (VM_SHARED | VM_MAYSHARE) ? 0 : -ENOSYS; 440 + return is_nommu_shared_mapping(vma->vm_flags) ? 0 : -ENOSYS; 441 441 } 442 442 443 443 static unsigned long cramfs_physmem_get_unmapped_area(struct file *file,
+1 -1
fs/proc/task_nommu.c
··· 38 38 } 39 39 40 40 if (atomic_read(&mm->mm_count) > 1 || 41 - vma->vm_flags & VM_MAYSHARE) { 41 + is_nommu_shared_mapping(vma->vm_flags)) { 42 42 sbytes += size; 43 43 } else { 44 44 bytes += size;
+1 -1
fs/ramfs/file-nommu.c
··· 264 264 */ 265 265 static int ramfs_nommu_mmap(struct file *file, struct vm_area_struct *vma) 266 266 { 267 - if (!(vma->vm_flags & (VM_SHARED | VM_MAYSHARE))) 267 + if (!is_nommu_shared_mapping(vma->vm_flags)) 268 268 return -ENOSYS; 269 269 270 270 file_accessed(file);
+1 -1
fs/romfs/mmap-nommu.c
··· 63 63 */ 64 64 static int romfs_mmap(struct file *file, struct vm_area_struct *vma) 65 65 { 66 - return vma->vm_flags & (VM_SHARED | VM_MAYSHARE) ? 0 : -ENOSYS; 66 + return is_nommu_shared_mapping(vma->vm_flags) ? 0 : -ENOSYS; 67 67 } 68 68 69 69 static unsigned romfs_mmap_capabilities(struct file *file)
+15
include/linux/mm.h
··· 1347 1347 return (flags & (VM_SHARED | VM_MAYWRITE)) == VM_MAYWRITE; 1348 1348 } 1349 1349 1350 + #ifndef CONFIG_MMU 1351 + static inline bool is_nommu_shared_mapping(vm_flags_t flags) 1352 + { 1353 + /* 1354 + * NOMMU shared mappings are ordinary MAP_SHARED mappings and selected 1355 + * R/O MAP_PRIVATE file mappings that are an effective R/O overlay of 1356 + * a file mapping. R/O MAP_PRIVATE mappings might still modify 1357 + * underlying memory if ptrace is active, so this is only possible if 1358 + * ptrace does not apply. Note that there is no mprotect() to upgrade 1359 + * write permissions later. 1360 + */ 1361 + return flags & VM_MAYSHARE; 1362 + } 1363 + #endif 1364 + 1350 1365 #if defined(CONFIG_SPARSEMEM) && !defined(CONFIG_SPARSEMEM_VMEMMAP) 1351 1366 #define SECTION_IN_PAGE_FLAGS 1352 1367 #endif
+1 -1
io_uring/io_uring.c
··· 3206 3206 3207 3207 static int io_uring_mmap(struct file *file, struct vm_area_struct *vma) 3208 3208 { 3209 - return vma->vm_flags & (VM_SHARED | VM_MAYSHARE) ? 0 : -EINVAL; 3209 + return is_nommu_shared_mapping(vma->vm_flags) ? 0 : -EINVAL; 3210 3210 } 3211 3211 3212 3212 static unsigned int io_uring_nommu_mmap_capabilities(struct file *file)
+6 -5
mm/nommu.c
··· 958 958 */ 959 959 if (capabilities & NOMMU_MAP_DIRECT) { 960 960 ret = call_mmap(vma->vm_file, vma); 961 + /* shouldn't return success if we're not sharing */ 962 + if (WARN_ON_ONCE(!is_nommu_shared_mapping(vma->vm_flags))) 963 + ret = -ENOSYS; 961 964 if (ret == 0) { 962 - /* shouldn't return success if we're not sharing */ 963 - BUG_ON(!(vma->vm_flags & VM_MAYSHARE)); 964 965 vma->vm_region->vm_top = vma->vm_region->vm_end; 965 966 return 0; 966 967 } ··· 1107 1106 * these cases, sharing is handled in the driver or filesystem rather 1108 1107 * than here 1109 1108 */ 1110 - if (vm_flags & VM_MAYSHARE) { 1109 + if (is_nommu_shared_mapping(vm_flags)) { 1111 1110 struct vm_region *pregion; 1112 1111 unsigned long pglen, rpglen, pgend, rpgend, start; 1113 1112 ··· 1117 1116 for (rb = rb_first(&nommu_region_tree); rb; rb = rb_next(rb)) { 1118 1117 pregion = rb_entry(rb, struct vm_region, vm_rb); 1119 1118 1120 - if (!(pregion->vm_flags & VM_MAYSHARE)) 1119 + if (!is_nommu_shared_mapping(pregion->vm_flags)) 1121 1120 continue; 1122 1121 1123 1122 /* search for overlapping mappings on the same file */ ··· 1601 1600 if (vma->vm_end != vma->vm_start + old_len) 1602 1601 return (unsigned long) -EFAULT; 1603 1602 1604 - if (vma->vm_flags & VM_MAYSHARE) 1603 + if (is_nommu_shared_mapping(vma->vm_flags)) 1605 1604 return (unsigned long) -EPERM; 1606 1605 1607 1606 if (new_len > vma->vm_region->vm_end - vma->vm_region->vm_start)