>> >> My brain is a bit slow after digging through this series. >> >> We identify shmem, for example, through shmem_vm_ops/shmem_anon_vm_ops. >> >> So naturally I am wondering: couldn't we do something similar to identify >> that? >> Like, checking for zero_fops? > > We don't assign vm_ops for a MAP_PRIVATE-/dev/zero mapping. So that won't > work. > > We could expose zero->f_ops but then it's literally in drivers/char/ and > that's > just weird to expose in mm.h or whatever.
Thinking out loud: could we use a dummy (empty) vm_ops? We'd place it in mm.h (zero_vm_ops) and just use it in drivers/char/. See below. > > I'm giving a really minimal possible thing to export, which is the > DEVZERO_MINOR > number which avoids all kinds of weirdness like that. No driver stuff > exported, > just a number :) MEM_MAJOR is already available. > > So I think it's the least bad choice in this one, very very specific scenario. I'd hope we find something cleaner than the DEVZERO_MINOR thingy. Something slightly cleaned up chloppedi-schlop on top of mm-unstable. vma tests seems to still work, but I haven't boot-tested this. >From 3cdc1d205a8e10dedd99b21a5f4f3f570ba24469 Mon Sep 17 00:00:00 2001 From: "David Hildenbrand (Arm)" <[email protected]> Date: Wed, 12 Aug 2026 19:13:32 +0200 Subject: [PATCH] tmp Signed-off-by: David Hildenbrand (Arm) <[email protected]> --- drivers/char/mem.c | 5 +++-- include/linux/mm.h | 4 +--- mm/init-mm.c | 1 + mm/vma.c | 10 +-------- mm/vma_internal.h | 1 - tools/testing/vma/include/dup.h | 38 +-------------------------------- tools/testing/vma/shared.c | 1 + tools/testing/vma/tests/mmap.c | 10 +++------ 8 files changed, 11 insertions(+), 59 deletions(-) diff --git a/drivers/char/mem.c b/drivers/char/mem.c index dcfd896b733d8..147568c65c1be 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -506,7 +506,8 @@ static int mmap_zero_prepare(struct vm_area_desc *desc) if (vma_desc_test(desc, VMA_SHARED_BIT)) return shmem_zero_setup_desc(desc); - /* MAP_PRIVATE semantics are taken care for us by core mm. */ + /* Indicate MAP_PRIVATE mappings, so core mm can do the right thing. */ + desc->vm_ops = &zero_vm_ops; return 0; } @@ -694,7 +695,7 @@ static const struct memdev { #ifdef CONFIG_DEVPORT [4] = { "port", &port_fops, 0, 0 }, #endif - [DEVZERO_MINOR] = { "zero", &zero_fops, FMODE_NOWAIT, 0666 }, + [5] = { "zero", &zero_fops, FMODE_NOWAIT, 0666 }, [7] = { "full", &full_fops, 0, 0666 }, [8] = { "random", &random_fops, FMODE_NOWAIT, 0666 }, [9] = { "urandom", &urandom_fops, FMODE_NOWAIT, 0666 }, diff --git a/include/linux/mm.h b/include/linux/mm.h index f940d20551d53..29f13cc6b52a2 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -740,9 +740,6 @@ static inline bool fault_flag_allow_retry_first(enum fault_flag flags) { FAULT_FLAG_INTERRUPTIBLE, "INTERRUPTIBLE" }, \ { FAULT_FLAG_VMA_LOCK, "VMA_LOCK" } -/* /dev/zero minor device number. Special due to MAP_PRIVATE semantics. */ -#define DEVZERO_MINOR 5 - /* * vm_fault is filled by the pagefault handler and passed to the vma's * ->fault function. The vma's ->fault is responsible for returning a bitmask @@ -990,6 +987,7 @@ static inline void mm_flags_clear_all(struct mm_struct *mm) } extern const struct vm_operations_struct vma_dummy_vm_ops; +extern const struct vm_operations_struct zero_vm_ops; static inline void vma_init(struct vm_area_struct *vma, struct mm_struct *mm) { diff --git a/mm/init-mm.c b/mm/init-mm.c index 3e792aad76261..2030f8e47a98a 100644 --- a/mm/init-mm.c +++ b/mm/init-mm.c @@ -18,6 +18,7 @@ #endif const struct vm_operations_struct vma_dummy_vm_ops; +const struct vm_operations_struct zero_vm_ops; /* * For dynamically allocated mm_structs, there is a dynamically sized cpumask diff --git a/mm/vma.c b/mm/vma.c index e7c8b6cb8347e..4f9b78791daf9 100644 --- a/mm/vma.c +++ b/mm/vma.c @@ -2623,15 +2623,7 @@ static int __mmap_new_file_vma(struct mmap_state *map, static bool map_is_dev_zero(const struct mmap_state *map) { - const struct file *file = map->file; - struct inode *inode; - - if (!file) - return false; - inode = file_inode(file); - if (!S_ISCHR(inode->i_mode)) - return false; - return imajor(inode) == MEM_MAJOR && iminor(inode) == DEVZERO_MINOR; + return map->vm_ops == &zero_vm_ops; } static void map_set_anon(struct mmap_state *map) diff --git a/mm/vma_internal.h b/mm/vma_internal.h index 385c0ab137774..4d300e7bbaf4c 100644 --- a/mm/vma_internal.h +++ b/mm/vma_internal.h @@ -23,7 +23,6 @@ #include <linux/ksm.h> #include <linux/khugepaged.h> #include <linux/list.h> -#include <linux/major.h> #include <linux/maple_tree.h> #include <linux/mempolicy.h> #include <linux/mm.h> diff --git a/tools/testing/vma/include/dup.h b/tools/testing/vma/include/dup.h index 41203b1c2323d..8457fabf53452 100644 --- a/tools/testing/vma/include/dup.h +++ b/tools/testing/vma/include/dup.h @@ -7,6 +7,7 @@ struct vm_area_struct; static inline void vma_start_write(struct vm_area_struct *vma); extern const struct vm_operations_struct vma_dummy_vm_ops; +extern const struct vm_operations_struct zero_vm_ops; extern unsigned long stack_guard_gap; extern const struct vm_operations_struct vma_dummy_vm_ops; extern unsigned long rlimit(unsigned int limit); @@ -15,21 +16,6 @@ struct task_struct *get_current(void); #define MMF_HAS_MDWE 28 #define current get_current() -#define MINORBITS 20 -#define MINORMASK ((1U << MINORBITS) - 1) - -#define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS)) -#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK)) -#define MKDEV(ma, mi) (((ma) << MINORBITS) | (mi)) - -#define S_IFMT 00170000 -#define S_IFCHR 0020000 - -#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) - -#define MEM_MAJOR 1 -#define DEVZERO_MINOR 5 - /* * Define the task command name length as enum, then it can be visible to * BPF programs. @@ -38,8 +24,6 @@ enum { TASK_COMM_LEN = 16, }; -typedef unsigned short umode_t; - /* PARTIALLY implemented types. */ struct mm_struct { struct maple_tree mm_mt; @@ -62,10 +46,6 @@ struct address_space { unsigned long flags; atomic_t i_mmap_writable; }; -struct inode { - umode_t i_mode; - dev_t i_rdev; -}; struct file_operations { int (*mmap)(struct file *, struct vm_area_struct *); int (*mmap_prepare)(struct vm_area_desc *); @@ -73,7 +53,6 @@ struct file_operations { struct file { struct address_space *f_mapping; const struct file_operations *f_op; - struct inode *f_inode; }; struct anon_vma_chain { struct anon_vma *anon_vma; @@ -1665,18 +1644,3 @@ static inline pgoff_t linear_anon_page_index(const struct vm_area_struct *vma, return pgoff; } - -static inline struct inode *file_inode(const struct file *f) -{ - return f->f_inode; -} - -static inline unsigned iminor(const struct inode *inode) -{ - return MINOR(inode->i_rdev); -} - -static inline unsigned imajor(const struct inode *inode) -{ - return MAJOR(inode->i_rdev); -} diff --git a/tools/testing/vma/shared.c b/tools/testing/vma/shared.c index 4a39c9d504896..46d8d2e96bd71 100644 --- a/tools/testing/vma/shared.c +++ b/tools/testing/vma/shared.c @@ -9,6 +9,7 @@ unsigned long dac_mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR; unsigned long stack_guard_gap = 256UL<<PAGE_SHIFT; const struct vm_operations_struct vma_dummy_vm_ops; +const struct vm_operations_struct zero_vm_ops; struct anon_vma dummy_anon_vma; struct task_struct __current; diff --git a/tools/testing/vma/tests/mmap.c b/tools/testing/vma/tests/mmap.c index ebe01362e530c..a63069d34a5a8 100644 --- a/tools/testing/vma/tests/mmap.c +++ b/tools/testing/vma/tests/mmap.c @@ -45,8 +45,9 @@ static bool test_mmap_region_basic(void) return true; } -static int dummy_mmap_prepare(struct vm_area_desc *desc) +static int zero_mmap_prepare(struct vm_area_desc *desc) { + desc->vm_ops = &zero_vm_ops; return 0; } @@ -55,14 +56,9 @@ static bool test_pure_anon_dev_zero(void) const vma_flags_t vma_flags = mk_vma_flags(VMA_READ_BIT, VMA_WRITE_BIT, VMA_MAYREAD_BIT, VMA_MAYWRITE_BIT); const struct file_operations f_op = { - .mmap_prepare = dummy_mmap_prepare, - }; - struct inode inode = { - .i_mode = S_IFCHR, - .i_rdev = MKDEV(MEM_MAJOR, DEVZERO_MINOR), + .mmap_prepare = zero_mmap_prepare, }; struct file file = { - .f_inode = &inode, .f_op = &f_op, }; struct mm_struct mm = {}; -- 2.43.0 -- Cheers, David
