Linux-mm Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 0/6] fix nommu mmap and add nommu kselftests
@ 2026-08-13  6:33 Hajime Tazaki
  2026-08-13  6:33 ` [RFC PATCH 1/6] mm: nommu: fix do_mremap() to correctly update internal states Hajime Tazaki
                   ` (5 more replies)
  0 siblings, 6 replies; 19+ messages in thread
From: Hajime Tazaki @ 2026-08-13  6:33 UTC (permalink / raw)
  To: linux-mm; +Cc: geert, daniel, Hajime Tazaki

This patchset fixes several issues on nommu mmap, munmap, and mremap
syscalls and add test cases on kselftests framework, which currently not
runnable on nommu platform.

Fixes for nommu is to correctly handle error cases when vma shrink
happens, and add calling .mmap_prepare callback on private mapping
requests to fix the issue which we cannot MAP_PRIVATE /dev/zero file.

One thing that I'd like to broadly ask you (thus this marks as RFC) is:
this fix contains a dirty check of /dev/zero using device type number.
Since mmap_zero_prepare() should be called before actual mapping, but
some of the .mmap_prepare handler should be called _after_
determine_vm_flags() as the .mmap_prepare handler checks the shared
flags, we cannot use vma_is_anonymous() in determine_vm_flags() to
check the file is /dev/zero or not.  So we introduced
is_file_anonymous() for that purpose, which I'd like to ask your inputs.

And we add test cases to introduce kselftest for nommu platforms.

Currently there are several issues if we wish to run kselftests on nommu
targets:

- it cannot compile/build test binaries because the current files mainly
  assume to build with glibc,
- some of the tests are not able to run on nommu targets as there are no
  fork(2) syscall.

The first issue can be avoided if we can build static PIE binaries (if
targets support it), but in our case (build on ubuntu/glibc and run on
alpine/musl-libc), it fails to invoke due to lack of the GNU ifunc
mechanism.  Thus, we need to cross-compile with musl toolchain, which
needs to be solved the first issue.

The second issue can be simply avoided, at a glance, by globally
replacing the symbol `fork` with `vfork`, which is available on nommu
targets.  Especially the test harness helper (kselftest_harness.h) uses
fork(2).  But the issue is not simple: for instance, in vfork(2) case
parent process has to wait until children has done jobs, parent and
children share the memory and children may corrupt parent memory which
is never happened with fork(2) syscall.  `timeout` command used in
`runner.sh` never works for nommu platform as it uses fork(2).

Additionally, the lack of test cases for nommu environment will (or
already) become serious issues to maintain the codebase in the future.
The test cases is implemented based on the document
(Documentation/admin-guide/mm/nommu-mmap.rst).  The test programs is
implemented with the assist of LLM.

So, for the first step, nommu targets only support low-level API of
kselftests (kselftest.h), and not supporting the harness tests since it
uses fork(2) syscall.  This partially address the second issue; in the
future we can refactor the harness test framework to be able to run with
vfork(2) syscall but this is not the part of this patchset.

Hajime Tazaki (6):
  mm: nommu: fix do_mremap() to correctly update internal states
  mm: nommu: use vma_is_anonymous() to check if vmas are anonymous
  mm: nommu: fix an issue on map request to /dev/zero
  selftests: fix build errors on alpine linux
  selftests: run tests on nommu architecture
  selftests/mm: add nommu mmap and mremap behavior tests

 Documentation/dev-tools/kselftest.rst         |  12 +
 drivers/char/mem.c                            |   5 +-
 mm/filemap.c                                  |   6 +-
 mm/nommu.c                                    | 235 ++++++-
 tools/testing/selftests/kselftest.h           |  43 ++
 tools/testing/selftests/kselftest/runner.sh   |   9 +-
 tools/testing/selftests/kselftest_harness.h   |   4 +
 tools/testing/selftests/lib.mk                |  10 +-
 tools/testing/selftests/mm/Makefile           |   3 +
 tools/testing/selftests/mm/hugetlb_dio.c      |   8 +-
 tools/testing/selftests/mm/mdwe_test.c        |   4 +-
 tools/testing/selftests/mm/nommu_mmap_test.c  | 294 +++++++++
 .../testing/selftests/mm/nommu_mremap_test.c  | 583 ++++++++++++++++++
 13 files changed, 1174 insertions(+), 42 deletions(-)
 create mode 100644 tools/testing/selftests/mm/nommu_mmap_test.c
 create mode 100644 tools/testing/selftests/mm/nommu_mremap_test.c

-- 
2.43.0



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

* [RFC PATCH 1/6] mm: nommu: fix do_mremap() to correctly update internal states
  2026-08-13  6:33 [RFC PATCH 0/6] fix nommu mmap and add nommu kselftests Hajime Tazaki
@ 2026-08-13  6:33 ` Hajime Tazaki
  2026-08-13  6:33 ` [RFC PATCH 2/6] mm: nommu: use vma_is_anonymous() to check if vmas are anonymous Hajime Tazaki
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 19+ messages in thread
From: Hajime Tazaki @ 2026-08-13  6:33 UTC (permalink / raw)
  To: linux-mm
  Cc: geert, daniel, Hajime Tazaki, Andrew Morton, Liam R. Howlett,
	Lorenzo Stoakes, Vlastimil Babka, Jann Horn, Pedro Falcato

When shrinking a VMA via mremap, the bounds are modified directly:
mm/nommu.c:do_mremap() {
    ...
    vma->vm_end = vma->vm_start + new_len;
    ...
}
This shrinks the VMA without updating its bounds in the maple tree.
If the maple tree (mm->mm_mt) still contains the old bounds, a user
process could access the freed portion. The stale maple tree would
incorrectly return the shrunk VMA for an address past its new vm_end.

This commit fixes this issue by calling vmi_shrink_vma() when shrink
happens.  Additionally, if a file-backed, non-anonymous map is to be
shrunk, it reports -EINVAL like do_munmap() does.

Moreover, to maintain i_mmap interval tree, two functions,
add_vma_to_mapping() and remove_vma_from_mapping(), are decoupled from
setup_vma_to_mm() and cleanup_vma_from_mm() respectively.

Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: "Liam R. Howlett" <liam@infradead.org>
Cc: Lorenzo Stoakes <ljs@kernel.org>
Cc: Vlastimil Babka <vbabka@kernel.org>
Cc: Jann Horn <jannh@google.com>
Cc: Pedro Falcato <pfalcato@suse.de>
Cc: linux-mm@kvack.org
Closes: https://sashiko.dev/#/patchset/20260702012546.665383-1-thehajime@gmail.com
Closes: https://sashiko.dev/#/patchset/20260710021028.892645-1-thehajime%40gmail.com
Signed-off-by: Hajime Tazaki <thehajime@gmail.com>

--

v1 -> v2:
- handle error when vmi_shrink_vma() failed (reported by Sashiko)
- prevents mremap() with being shrunk for file-backed one like munmap()
- consider i_mmap updates on shrink/expand by calling newly decoupled
  functions, add_vma_to_mapping()/remove_vma_from_mapping()

v1: https://lore.kernel.org/linux-mm/20260710021028.892645-1-thehajime@gmail.com/
---
 mm/nommu.c | 147 ++++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 124 insertions(+), 23 deletions(-)

diff --git a/mm/nommu.c b/mm/nommu.c
index ed3934bc2de4..89444ee2aca6 100644
--- a/mm/nommu.c
+++ b/mm/nommu.c
@@ -559,36 +559,51 @@ static void put_nommu_region(struct vm_region *region)
 	__put_nommu_region(region);
 }
 
+static void add_vma_to_mapping(struct vm_area_struct *vma)
+{
+	struct address_space *mapping;
+
+	if (!vma->vm_file)
+		return;
+
+	mapping = vma->vm_file->f_mapping;
+	i_mmap_lock_write(mapping);
+	flush_dcache_mmap_lock(mapping);
+	vma_interval_tree_insert(vma, &mapping->i_mmap);
+	flush_dcache_mmap_unlock(mapping);
+	i_mmap_unlock_write(mapping);
+}
+
+static void remove_vma_from_mapping(struct vm_area_struct *vma)
+{
+	struct address_space *mapping;
+
+	if (!vma->vm_file)
+		return;
+
+	mapping = vma->vm_file->f_mapping;
+	i_mmap_lock_write(mapping);
+	flush_dcache_mmap_lock(mapping);
+	vma_interval_tree_remove(vma, &mapping->i_mmap);
+	flush_dcache_mmap_unlock(mapping);
+	i_mmap_unlock_write(mapping);
+}
+
 static void setup_vma_to_mm(struct vm_area_struct *vma, struct mm_struct *mm)
 {
 	vma->vm_mm = mm;
 
 	/* add the VMA to the mapping */
-	if (vma->vm_file) {
-		struct address_space *mapping = vma->vm_file->f_mapping;
-
-		i_mmap_lock_write(mapping);
-		flush_dcache_mmap_lock(mapping);
-		vma_interval_tree_insert(vma, &mapping->i_mmap);
-		flush_dcache_mmap_unlock(mapping);
-		i_mmap_unlock_write(mapping);
-	}
+	if (vma->vm_file)
+		add_vma_to_mapping(vma);
 }
 
 static void cleanup_vma_from_mm(struct vm_area_struct *vma)
 {
 	vma->vm_mm->map_count--;
 	/* remove the VMA from the mapping */
-	if (vma->vm_file) {
-		struct address_space *mapping;
-		mapping = vma->vm_file->f_mapping;
-
-		i_mmap_lock_write(mapping);
-		flush_dcache_mmap_lock(mapping);
-		vma_interval_tree_remove(vma, &mapping->i_mmap);
-		flush_dcache_mmap_unlock(mapping);
-		i_mmap_unlock_write(mapping);
-	}
+	if (vma->vm_file)
+		remove_vma_from_mapping(vma);
 }
 
 /*
@@ -1351,6 +1366,8 @@ static int split_vma(struct vma_iterator *vmi, struct vm_area_struct *vma,
 	if (new->vm_ops && new->vm_ops->open)
 		new->vm_ops->open(new);
 
+	remove_vma_from_mapping(vma);
+
 	down_write(&nommu_region_sem);
 	delete_nommu_region(vma->vm_region);
 	if (new_below) {
@@ -1364,6 +1381,11 @@ static int split_vma(struct vma_iterator *vmi, struct vm_area_struct *vma,
 	add_nommu_region(new->vm_region);
 	up_write(&nommu_region_sem);
 
+	if (new->vm_file) {
+		vma->vm_file = get_file(vma->vm_file);
+		new->vm_file = get_file(new->vm_file);
+	}
+
 	setup_vma_to_mm(vma, mm);
 	setup_vma_to_mm(new, mm);
 	vma_iter_store_new(vmi, new);
@@ -1386,16 +1408,20 @@ static int vmi_shrink_vma(struct vma_iterator *vmi,
 		      unsigned long from, unsigned long to)
 {
 	struct vm_region *region;
+	bool has_mapping = !!vma->vm_file;
+
+	if (has_mapping)
+		remove_vma_from_mapping(vma);
 
 	/* adjust the VMA's pointers, which may reposition it in the MM's tree
 	 * and list */
 	if (from > vma->vm_start) {
 		if (vma_iter_clear_gfp(vmi, from, vma->vm_end, GFP_KERNEL))
-			return -ENOMEM;
+			goto restore_mapping;
 		vma->vm_end = from;
 	} else {
 		if (vma_iter_clear_gfp(vmi, vma->vm_start, to, GFP_KERNEL))
-			return -ENOMEM;
+			goto restore_mapping;
 		vma->vm_start = to;
 	}
 
@@ -1415,7 +1441,15 @@ static int vmi_shrink_vma(struct vma_iterator *vmi,
 	up_write(&nommu_region_sem);
 
 	free_page_series(from, to);
+	if (has_mapping)
+		add_vma_to_mapping(vma);
+
 	return 0;
+
+restore_mapping:
+	if (has_mapping)
+		add_vma_to_mapping(vma);
+	return -ENOMEM;
 }
 
 /*
@@ -1544,6 +1578,9 @@ static unsigned long do_mremap(unsigned long addr,
 			unsigned long flags, unsigned long new_addr)
 {
 	struct vm_area_struct *vma;
+	int ret;
+
+	VMA_ITERATOR(vmi, current->mm, addr);
 
 	/* insanity checks first */
 	old_len = PAGE_ALIGN(old_len);
@@ -1567,11 +1604,75 @@ static unsigned long do_mremap(unsigned long addr,
 	if (is_nommu_shared_mapping(vma->vm_flags))
 		return (unsigned long) -EPERM;
 
-	if (new_len > vma->vm_region->vm_end - vma->vm_region->vm_start)
+	/* vm_region->vm_top != vm_region->vm_end when sysctl_nr_trim_pages is 0 (default: 1) */
+	if (new_len > vma->vm_region->vm_top - vma->vm_region->vm_start)
 		return (unsigned long) -ENOMEM;
 
 	/* all checks complete - do it */
-	vma->vm_end = vma->vm_start + new_len;
+	if (new_len == old_len)
+		return vma->vm_start;
+
+	/* shrink only happens addr + new_len and old_len are in different pages */
+	if (new_len < old_len) {
+		/* like do_munmap(), we're allowed to shrink an anonymous VMA but not
+		 * a file-backed one
+		 */
+		if (vma->vm_file)
+			return (unsigned long) -EINVAL;
+
+		/* vmi_shrink_vma() needs from/to pointers to be removed,
+		 * (mainly used in munmap) so, specify them.
+		 */
+		ret = vmi_shrink_vma(&vmi, vma, addr + new_len, addr + old_len);
+		if (ret < 0)
+			return (unsigned long) ret;
+	} else {
+		/* growth path: grow up to vm_top should be handled here. */
+		unsigned long old_end = vma->vm_end;
+		unsigned long end = vma->vm_start + new_len;
+		unsigned long grow_len = end - old_end;
+
+		/*
+		 * Initialize the newly exposed portion before making it visible
+		 * through the VMA or i_mmap.
+		 */
+
+		/* read contents of extended map from file, or zero-filled if !vm_file */
+		if (vma->vm_file) {
+			loff_t fpos;
+
+			fpos = (loff_t)vma->vm_pgoff << PAGE_SHIFT;
+			fpos += old_end - vma->vm_start;
+
+			ret = nommu_read_iter(vma->vm_file, (void *)old_end,
+					      grow_len, &fpos);
+			if (ret < 0)
+				return (unsigned long)ret;
+
+			if (ret < grow_len)
+				memset((char *)old_end + ret, 0, grow_len - ret);
+		} else {
+			memset((void *)old_end, 0, grow_len);
+		}
+
+		/* The backing contents are ready. Now update the VMA bookkeeping. */
+		remove_vma_from_mapping(vma);
+
+		vma->vm_end = end;
+		ret = vma_iter_store_gfp(&vmi, vma, GFP_KERNEL);
+		if (ret) {
+			vma->vm_end = old_end;
+			add_vma_to_mapping(vma);
+			return (unsigned long)ret;
+		}
+
+		/* vm_top remains unchanged; only the logical end grows. */
+		down_write(&nommu_region_sem);
+		vma->vm_region->vm_end = end;
+		up_write(&nommu_region_sem);
+
+		add_vma_to_mapping(vma);
+	}
 	return vma->vm_start;
 }
 
-- 
2.43.0



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

* [RFC PATCH 2/6] mm: nommu: use vma_is_anonymous() to check if vmas are anonymous
  2026-08-13  6:33 [RFC PATCH 0/6] fix nommu mmap and add nommu kselftests Hajime Tazaki
  2026-08-13  6:33 ` [RFC PATCH 1/6] mm: nommu: fix do_mremap() to correctly update internal states Hajime Tazaki
@ 2026-08-13  6:33 ` Hajime Tazaki
  2026-08-13  6:33 ` [RFC PATCH 3/6] mm: nommu: fix an issue on map request to /dev/zero Hajime Tazaki
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 19+ messages in thread
From: Hajime Tazaki @ 2026-08-13  6:33 UTC (permalink / raw)
  To: linux-mm
  Cc: geert, daniel, Hajime Tazaki, Andrew Morton, Liam R. Howlett,
	Lorenzo Stoakes, Vlastimil Babka, Jann Horn, Pedro Falcato

Private file mappings (like those from /dev/zero) can have vma->vm_file
set but remain structurally anonymous since they lack vm_ops. Testing
vma->vm_file instead of vma_is_anonymous(vma) might cause mremap to
return a spurious -EINVAL when userspace attempts to shrink these
mappings.

This commit fixes this issue by using vma_is_anonymous() instead of
testing vma->vm_file to address the case of /dev/zero.

Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: "Liam R. Howlett" <liam@infradead.org>
Cc: Lorenzo Stoakes <ljs@kernel.org>
Cc: Vlastimil Babka <vbabka@kernel.org>
Cc: Jann Horn <jannh@google.com>
Cc: Pedro Falcato <pfalcato@suse.de>
Cc: linux-mm@kvack.org
Closes: https://sashiko.dev/#/patchset/20260710054648.924005-1-thehajime%40gmail.com
Signed-off-by: Hajime Tazaki <thehajime@gmail.com>
---
 mm/nommu.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/mm/nommu.c b/mm/nommu.c
index 89444ee2aca6..e40990e15831 100644
--- a/mm/nommu.c
+++ b/mm/nommu.c
@@ -1196,7 +1196,7 @@ unsigned long do_mmap(struct file *file,
 	add_nommu_region(region);
 
 	/* clear anonymous mappings that don't ask for uninitialized data */
-	if (!vma->vm_file &&
+	if (vma_is_anonymous(vma) &&
 	    (!IS_ENABLED(CONFIG_MMAP_ALLOW_UNINITIALIZED) ||
 	     !(flags & MAP_UNINITIALIZED)))
 		memset((void *)region->vm_start, 0,
@@ -1328,7 +1328,7 @@ static int split_vma(struct vma_iterator *vmi, struct vm_area_struct *vma,
 
 	/* we're only permitted to split anonymous regions (these should have
 	 * only a single usage on the region) */
-	if (vma->vm_file)
+	if (!vma_is_anonymous(vma))
 		return -ENOMEM;
 
 	mm = vma->vm_mm;
@@ -1484,7 +1484,7 @@ int do_munmap(struct mm_struct *mm, unsigned long start, size_t len, struct list
 	}
 
 	/* we're allowed to split an anonymous VMA but not a file-backed one */
-	if (vma->vm_file) {
+	if (!vma_is_anonymous(vma)) {
 		do {
 			if (start > vma->vm_start)
 				return -EINVAL;
@@ -1617,7 +1617,7 @@ static unsigned long do_mremap(unsigned long addr,
 		/* like do_munmap(), we're allowed to shrink an anonymous VMA but not
 		 * a file-backed one
 		 */
-		if (vma->vm_file)
+		if (!vma_is_anonymous(vma))
 			return (unsigned long) -EINVAL;
 
 		/* vmi_shrink_vma() needs from/to pointers to be removed,
-- 
2.43.0



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

* [RFC PATCH 3/6] mm: nommu: fix an issue on map request to /dev/zero
  2026-08-13  6:33 [RFC PATCH 0/6] fix nommu mmap and add nommu kselftests Hajime Tazaki
  2026-08-13  6:33 ` [RFC PATCH 1/6] mm: nommu: fix do_mremap() to correctly update internal states Hajime Tazaki
  2026-08-13  6:33 ` [RFC PATCH 2/6] mm: nommu: use vma_is_anonymous() to check if vmas are anonymous Hajime Tazaki
@ 2026-08-13  6:33 ` Hajime Tazaki
  2026-08-13 12:19   ` Greg Kroah-Hartman
  2026-08-13  6:33 ` [RFC PATCH 4/6] selftests: fix build errors on alpine linux Hajime Tazaki
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 19+ messages in thread
From: Hajime Tazaki @ 2026-08-13  6:33 UTC (permalink / raw)
  To: linux-mm
  Cc: geert, daniel, Hajime Tazaki, Arnd Bergmann, Greg Kroah-Hartman,
	Matthew Wilcox (Oracle), Jan Kara, Andrew Morton, Liam R. Howlett,
	Lorenzo Stoakes, Vlastimil Babka, Jann Horn, Pedro Falcato,
	linux-fsdevel

Upon a private file mapping request to /dev/zero, it calls
kernel_read() in do_mmap_private(), getting a failure with the message
like: "kernel reads not supported for file /dev/zero", which is because
zero_fops defined in drivers/char/mem.c has both .read and .read_iter
definitions.

Even fixing this issue, the map request to /dev/zero works fine without
errors but the allocated vma isn't marked with anonymous because
mmap_zero_prepare() isn't called under nommu platform, resulting
vma_desc_set_anonymous() isn't called either.

This commit fixes those issues by:
1) use vfs_iter_read() instead to avoid failure at kernel_read()
2) calls .mmap_prepare on private mapping in do_mmap() so that required
   preparations are done even in private mapping.

Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: "Matthew Wilcox (Oracle)" <willy@infradead.org>
Cc: Jan Kara <jack@suse.cz>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: "Liam R. Howlett" <liam@infradead.org>
Cc: Lorenzo Stoakes <ljs@kernel.org>
Cc: Vlastimil Babka <vbabka@kernel.org>
Cc: Jann Horn <jannh@google.com>
Cc: Pedro Falcato <pfalcato@suse.de>
Cc: linux-fsdevel@vger.kernel.org
Cc: linux-mm@kvack.org (open list:PAGE CACHE)
Fixes: 4d03e3cc5982 ("fs: don't allow kernel reads and writes without iter ops")
Assisted-by: cubic.dev:unspecified
Signed-off-by: Hajime Tazaki <thehajime@gmail.com>
---
 drivers/char/mem.c |  5 ++-
 mm/filemap.c       |  6 ++--
 mm/nommu.c         | 84 ++++++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 87 insertions(+), 8 deletions(-)

diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 63253d1de5d7..dba24d0a7b33 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -500,11 +500,10 @@ static ssize_t read_zero(struct file *file, char __user *buf,
 
 static int mmap_zero_prepare(struct vm_area_desc *desc)
 {
-#ifndef CONFIG_MMU
-	return -ENOSYS;
-#endif
+#ifdef CONFIG_MMU
 	if (vma_desc_test(desc, VMA_SHARED_BIT))
 		return shmem_zero_setup_desc(desc);
+#endif
 
 	/*
 	 * This is a highly unique situation where we mark a MAP_PRIVATE mapping
diff --git a/mm/filemap.c b/mm/filemap.c
index d721986d5f46..cf02faad86aa 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -4077,7 +4077,7 @@ int generic_file_mmap(struct file *file, struct vm_area_struct *vma)
 }
 int generic_file_mmap_prepare(struct vm_area_desc *desc)
 {
-	return -ENOSYS;
+	return 0;
 }
 int generic_file_readonly_mmap(struct file *file, struct vm_area_struct *vma)
 {
@@ -4085,7 +4085,9 @@ int generic_file_readonly_mmap(struct file *file, struct vm_area_struct *vma)
 }
 int generic_file_readonly_mmap_prepare(struct vm_area_desc *desc)
 {
-	return -ENOSYS;
+	if (is_shared_maywrite(&desc->vma_flags))
+		return -EINVAL;
+	return generic_file_mmap_prepare(desc);
 }
 #endif /* CONFIG_MMU */
 
diff --git a/mm/nommu.c b/mm/nommu.c
index e40990e15831..a29a53c1c80a 100644
--- a/mm/nommu.c
+++ b/mm/nommu.c
@@ -37,6 +37,7 @@
 
 #include <linux/uaccess.h>
 #include <linux/uio.h>
+#include <linux/major.h>
 #include <asm/tlb.h>
 #include <asm/tlbflush.h>
 #include <asm/mmu_context.h>
@@ -856,6 +857,22 @@ static int validate_mmap_request(struct file *file,
 	return 0;
 }
 
+static int is_file_anonymous(struct file *file)
+{
+	if (!file)
+		return 1;
+
+	if (file->f_path.dentry && file->f_path.dentry->d_inode) {
+		struct inode *inode = file->f_path.dentry->d_inode;
+		/* if the device is /dev/zero */
+		if (S_ISCHR(inode->i_mode) &&
+		    imajor(inode) == MEM_MAJOR && iminor(inode) == 5)
+			return 1;
+	}
+
+	return 0;
+}
+
 /*
  * we've determined that we can make the mapping, now translate what we
  * now know into VMA flags
@@ -869,7 +886,11 @@ static vm_flags_t determine_vm_flags(struct file *file,
 
 	vm_flags = calc_vm_prot_bits(prot, 0) | calc_vm_flag_bits(file, flags);
 
-	if (!file) {
+	/* private and file mapping will be marked anonymous later (do_mmap_private()).
+	 * and /dev/zero is marked by them at .mmap_prepare,
+	 * which should be _before_ this point.
+	 */
+	if (is_file_anonymous(file)) {
 		/*
 		 * MAP_ANONYMOUS. MAP_SHARED is mapped to MAP_PRIVATE, because
 		 * there is no fork().
@@ -923,6 +944,29 @@ static int do_mmap_shared_file(struct vm_area_struct *vma)
 	return -ENODEV;
 }
 
+static ssize_t nommu_read_iter(struct file *file, void *buf,
+			       size_t count, loff_t *pos)
+{
+	struct iov_iter iter;
+	ssize_t ret;
+	size_t done = 0;
+
+	while (done < count) {
+		struct kvec iov = {
+			.iov_base = buf + done,
+			.iov_len = min_t(size_t, count - done, MAX_RW_COUNT),
+		};
+
+		iov_iter_kvec(&iter, ITER_DEST, &iov, 1, iov.iov_len);
+		ret = vfs_iter_read(file, &iter, pos, 0);
+		if (ret <= 0)
+			return done ? done : ret;
+		done += ret;
+	}
+
+	return done;
+}
+
 /*
  * set up a private mapping or an anonymous shared mapping
  */
@@ -993,7 +1037,7 @@ static int do_mmap_private(struct vm_area_struct *vma,
 		fpos = vma->vm_pgoff;
 		fpos <<= PAGE_SHIFT;
 
-		ret = kernel_read(vma->vm_file, base, len, &fpos);
+		ret = nommu_read_iter(vma->vm_file, base, len, &fpos);
 		if (ret < 0)
 			goto error_free;
 
@@ -1080,6 +1124,28 @@ unsigned long do_mmap(struct file *file,
 		vma->vm_file = get_file(file);
 	}
 
+	/* call mmap_prepare function if any */
+	if (!(flags & MAP_SHARED) && !(capabilities & NOMMU_MAP_DIRECT) &&
+	    (vma->vm_file && vma->vm_file->f_op->mmap_prepare)) {
+		struct vm_area_desc desc;
+
+		vma->vm_start = addr;
+		vma->vm_end = addr + len;
+
+		compat_set_desc_from_vma(&desc, vma->vm_file, vma);
+		ret = vma->vm_file->f_op->mmap_prepare(&desc);
+		/* private ramfs/romfs mappings fails with -ENOSYS so,
+		 * fall back to copied mapping.
+		 */
+		if (ret && ret != -ENOSYS)
+			goto error_mmap_prepare;
+
+		ret = __compat_vma_mmap(&desc, vma);
+		if (ret)
+			goto error_mmap_prepare;
+	}
+
+
 	down_write(&nommu_region_sem);
 
 	/* if we want to share, we need to check for regions created by other
@@ -1196,7 +1262,7 @@ unsigned long do_mmap(struct file *file,
 	add_nommu_region(region);
 
 	/* clear anonymous mappings that don't ask for uninitialized data */
-	if (vma_is_anonymous(vma) &&
+	if (is_file_anonymous(vma->vm_file) &&
 	    (!IS_ENABLED(CONFIG_MMAP_ALLOW_UNINITIALIZED) ||
 	     !(flags & MAP_UNINITIALIZED)))
 		memset((void *)region->vm_start, 0,
@@ -1247,6 +1313,18 @@ unsigned long do_mmap(struct file *file,
 	ret = -EINVAL;
 	goto error;
 
+error_mmap_prepare:
+	if (region->vm_file)
+		fput(region->vm_file);
+	kmem_cache_free(vm_region_jar, region);
+	if (vma->vm_file)
+		fput(vma->vm_file);
+	vm_area_free(vma);
+
+	pr_warn("mmap_prepare failed for %lu byte allocation from process %d\n",
+			len, current->pid);
+	return ret;
+
 error_getting_vma:
 	kmem_cache_free(vm_region_jar, region);
 	pr_warn("Allocation of vma for %lu byte allocation from process %d failed\n",
-- 
2.43.0



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

* [RFC PATCH 4/6] selftests: fix build errors on alpine linux
  2026-08-13  6:33 [RFC PATCH 0/6] fix nommu mmap and add nommu kselftests Hajime Tazaki
                   ` (2 preceding siblings ...)
  2026-08-13  6:33 ` [RFC PATCH 3/6] mm: nommu: fix an issue on map request to /dev/zero Hajime Tazaki
@ 2026-08-13  6:33 ` Hajime Tazaki
  2026-08-13  6:34 ` [RFC PATCH 5/6] selftests: run tests on nommu architecture Hajime Tazaki
  2026-08-13  6:34 ` [RFC PATCH 6/6] selftests/mm: add nommu mmap and mremap behavior tests Hajime Tazaki
  5 siblings, 0 replies; 19+ messages in thread
From: Hajime Tazaki @ 2026-08-13  6:33 UTC (permalink / raw)
  To: linux-mm
  Cc: geert, daniel, Hajime Tazaki, Shuah Khan, Andrew Morton,
	David Hildenbrand, Lorenzo Stoakes, Liam R. Howlett,
	Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
	linux-kselftest, linux-um

Some nommu architectures only work on Alpine Linux, which doesn't use
glibc for the standard library.  It uses musl-libc and is implemented in
a different way as glibc, resulting build failures.

This commit fixes this issue by adding missing definitions. The fixes
are now only covered to TARGETS=mm which was tested for the moment;
future contributions are needed to fully build/execute tests on nommu
platforms.

Cc: Shuah Khan <shuah@kernel.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: David Hildenbrand <david@kernel.org>
Cc: Lorenzo Stoakes <ljs@kernel.org>
Cc: "Liam R. Howlett" <liam@infradead.org>
Cc: Vlastimil Babka <vbabka@kernel.org>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Michal Hocko <mhocko@suse.com>
Cc: linux-kselftest@vger.kernel.org
Cc: linux-mm@kvack.org
Cc: linux-um@lists.infradead.org
Signed-off-by: Hajime Tazaki <thehajime@gmail.com>
---
 tools/testing/selftests/kselftest.h      | 43 ++++++++++++++++++++++++
 tools/testing/selftests/lib.mk           |  2 +-
 tools/testing/selftests/mm/hugetlb_dio.c |  8 ++---
 tools/testing/selftests/mm/mdwe_test.c   |  4 +--
 4 files changed, 50 insertions(+), 7 deletions(-)

diff --git a/tools/testing/selftests/kselftest.h b/tools/testing/selftests/kselftest.h
index ae18c491ae53..ac21bf3d802e 100644
--- a/tools/testing/selftests/kselftest.h
+++ b/tools/testing/selftests/kselftest.h
@@ -58,6 +58,7 @@
 #include <string.h>
 #include <stdio.h>
 #include <sys/utsname.h>
+#include <stdint.h>
 #endif
 
 #ifndef ARRAY_SIZE
@@ -81,6 +82,48 @@
 #endif
 #endif /* end arch */
 
+#if !defined(NOLIBC) && !defined(__GLIBC__)
+#ifdef __LP64__
+typedef int64_t __fsword_t;
+#else
+typedef int32_t __fsword_t;
+#endif
+
+/*
+ * for a workaround to avoid struct conflict under
+ * musl-libc (<sys/prctl.h> v.s. <linux/prctl.h>)
+ */
+#include <sys/prctl.h>
+#ifndef _LINUX_PRCTL_H
+#define _LINUX_PRCTL_H
+#endif
+
+#ifndef PR_SET_MDWE
+#define PR_SET_MDWE 65
+#endif
+
+#ifndef PR_MDWE_REFUSE_EXEC_GAIN
+#define PR_MDWE_REFUSE_EXEC_GAIN (1UL << 0)
+#endif
+
+#ifndef PR_MDWE_NO_INHERIT
+#define PR_MDWE_NO_INHERIT (1UL << 1)
+#endif
+
+#ifndef PR_GET_MDWE
+#define PR_GET_MDWE 66
+#endif
+
+#ifndef PR_SET_MEMORY_MERGE
+#define PR_SET_MEMORY_MERGE 67
+#endif
+
+#ifndef PR_GET_MEMORY_MERGE
+#define PR_GET_MEMORY_MERGE 68
+#endif
+
+#endif
+
 /* define kselftest exit codes */
 #define KSFT_PASS  0
 #define KSFT_FAIL  1
diff --git a/tools/testing/selftests/lib.mk b/tools/testing/selftests/lib.mk
index f02cc8a2e4ae..2cc819006424 100644
--- a/tools/testing/selftests/lib.mk
+++ b/tools/testing/selftests/lib.mk
@@ -197,7 +197,7 @@ clean: $(if $(TEST_GEN_MODS_DIR),clean_mods_dir)
 	$(CLEAN)
 
 # Build with _GNU_SOURCE by default
-CFLAGS += -D_GNU_SOURCE=
+CFLAGS += -D_GNU_SOURCE= -D_LARGEFILE64_SOURCE
 
 # Additional include paths needed by kselftest.h and local headers
 CFLAGS += -I${top_srcdir}/tools/testing/selftests
diff --git a/tools/testing/selftests/mm/hugetlb_dio.c b/tools/testing/selftests/mm/hugetlb_dio.c
index fb4600570e13..aee6be530ccb 100644
--- a/tools/testing/selftests/mm/hugetlb_dio.c
+++ b/tools/testing/selftests/mm/hugetlb_dio.c
@@ -22,12 +22,9 @@
 #include "kselftest.h"
 #include "hugepage_settings.h"
 
-#ifndef STATX_DIOALIGN
-#define STATX_DIOALIGN		0x00002000U
-#endif
-
 static int get_dio_alignment(int fd)
 {
+#ifdef STATX_DIOALIGN
 	struct statx stx;
 	int ret;
 
@@ -43,6 +40,9 @@ static int get_dio_alignment(int fd)
 		return 1;
 
 	return stx.stx_dio_offset_align;
+#else
+	return -1;
+#endif
 }
 
 static bool check_dio_alignment(unsigned int start_off,
diff --git a/tools/testing/selftests/mm/mdwe_test.c b/tools/testing/selftests/mm/mdwe_test.c
index 647779653da0..031c79ed067e 100644
--- a/tools/testing/selftests/mm/mdwe_test.c
+++ b/tools/testing/selftests/mm/mdwe_test.c
@@ -1,5 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 
+#include "kselftest_harness.h"
+
 #ifdef __aarch64__
 #include <asm/hwcap.h>
 #endif
@@ -14,8 +16,6 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
-#include "kselftest_harness.h"
-
 #ifndef __aarch64__
 # define PROT_BTI	0
 #endif
-- 
2.43.0



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

* [RFC PATCH 5/6] selftests: run tests on nommu architecture
  2026-08-13  6:33 [RFC PATCH 0/6] fix nommu mmap and add nommu kselftests Hajime Tazaki
                   ` (3 preceding siblings ...)
  2026-08-13  6:33 ` [RFC PATCH 4/6] selftests: fix build errors on alpine linux Hajime Tazaki
@ 2026-08-13  6:34 ` Hajime Tazaki
  2026-08-13  6:34 ` [RFC PATCH 6/6] selftests/mm: add nommu mmap and mremap behavior tests Hajime Tazaki
  5 siblings, 0 replies; 19+ messages in thread
From: Hajime Tazaki @ 2026-08-13  6:34 UTC (permalink / raw)
  To: linux-mm
  Cc: geert, daniel, Hajime Tazaki, Shuah Khan, Kees Cook,
	Andy Lutomirski, Will Drewry, Mark Brown, Brendan Jackman,
	Hangbin Liu, Ricardo B. Marliere, linux-kselftest, linux-um

Architectures lacks MMU doesn't support fork(2) syscall and only
vfork(2) is available with limitations.  Thus, we cannot run kselftest
on nommu architecture as is.

This commit addresses this issue with the following changes:

- on build stage, add -DCONFIG_NOMMU to CFLAGS when NOMMU=1 variable
  added to the build/make argument.
- on test run stage, avoid calling timeout command when NOMMU=1 variable
  added to environmental variable, since timeout command uses fork
  syscall which nommu platform doesn't support.
- kselftest_harness.h warns if the file is include when building for
  NOMMU platform, as there is no fork(2) syscall.
- replace "cd -" use as it is not available a shell supported on nommu
  (e.g., busybox hush), use cd "$OLDDIR" instead.
- describe the difference of nommu tests in the document.

So command line to build/execute tests for nommu should be like below:

 $ make ARCH=um NOMMU=1 O=build kselftest
 $ make ARCH=um NOMMU=1 -C tools/testing/selftests/mm run_tests
 $ NOMMU=1 /tmp/kselftest_install/run_kselftest.sh -s -c mm

Cc: Shuah Khan <shuah@kernel.org>
Cc: Kees Cook <kees@kernel.org>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Will Drewry <wad@chromium.org>
Cc: Mark Brown <broonie@kernel.org>
Cc: Brendan Jackman <jackmanb@google.com>
Cc: Hangbin Liu <liuhangbin@gmail.com>
Cc: "Ricardo B. Marliere" <rbm@suse.com>
Cc: linux-kselftest@vger.kernel.org
Cc: linux-um@lists.infradead.org
Signed-off-by: Hajime Tazaki <thehajime@gmail.com>
---
 Documentation/dev-tools/kselftest.rst       | 12 ++++++++++++
 tools/testing/selftests/kselftest/runner.sh |  9 +++++++--
 tools/testing/selftests/kselftest_harness.h |  4 ++++
 tools/testing/selftests/lib.mk              |  8 ++++++++
 4 files changed, 31 insertions(+), 2 deletions(-)

diff --git a/Documentation/dev-tools/kselftest.rst b/Documentation/dev-tools/kselftest.rst
index 64c0ec7428a2..800b2b688aff 100644
--- a/Documentation/dev-tools/kselftest.rst
+++ b/Documentation/dev-tools/kselftest.rst
@@ -230,6 +230,18 @@ section::
 
 .. _tar's auto-compress: https://www.gnu.org/software/tar/manual/html_node/gzip.html#auto_002dcompress
 
+Build and test on nommu target
+==============================
+
+If you (cross-)build kselftests for nommu targets, or run tests on nommu targets, use
+``NOMMU=1`` as a make variable/environment setting to tell build system to do the additional
+checks.  These nommu targets may differ in several ways, such as not supporting fork(2) or
+using musl or another libc.  Set this variable to apply the necessary build and test adjustments.
+
+  $ make ARCH=um NOMMU=1 O=build kselftest
+  $ make ARCH=um NOMMU=1 -C tools/testing/selftests/mm run_tests
+  $ NOMMU=1 /tmp/kselftest_install/run_kselftest.sh -s -c mm
+
 Contributing new tests
 ======================
 
diff --git a/tools/testing/selftests/kselftest/runner.sh b/tools/testing/selftests/kselftest/runner.sh
index 311811dc55a0..7287d8290b6c 100644
--- a/tools/testing/selftests/kselftest/runner.sh
+++ b/tools/testing/selftests/kselftest/runner.sh
@@ -38,8 +38,12 @@ tap_prefix()
 
 tap_timeout()
 {
+	# nommu doesn't support timeout command (missing fork(2))
+	if [ "$NOMMU" = "1" ] ; then
+		echo "timeout isn't supported for nommu"
+		$1
 	# Make sure tests will time out if utility is available.
-	if [ -x /usr/bin/timeout ] ; then
+	elif [ -x /usr/bin/timeout ] ; then
 		/usr/bin/timeout --foreground "$kselftest_timeout" \
 			/usr/bin/timeout "$kselftest_timeout" $1
 	else
@@ -130,6 +134,7 @@ run_one()
 				return $KSFT_FAIL
 			fi
 		fi
+		OLDDIR=$(pwd)
 		cd `dirname $TEST` > /dev/null
 		(((( tap_timeout "$cmd" 2>&1; echo $? >&3) |
 			tap_prefix >&4) 3>&1) |
@@ -147,7 +152,7 @@ run_one()
 		*)
 			ktap_test_fail "$TEST_HDR_MSG # exit=$rc";;
 		esac
-		cd - >/dev/null
+		cd "$OLDDIR" >/dev/null
 	fi
 
 	return $rc
diff --git a/tools/testing/selftests/kselftest_harness.h b/tools/testing/selftests/kselftest_harness.h
index 261e4df94d9d..8eee7b14f824 100644
--- a/tools/testing/selftests/kselftest_harness.h
+++ b/tools/testing/selftests/kselftest_harness.h
@@ -1274,6 +1274,10 @@ static int test_harness_run(int argc, char **argv)
 	unsigned int count = 0;
 	unsigned int pass_count = 0;
 
+#ifdef CONFIG_NOMMU
+	ksft_print_msg("harness test doesn't support on NOMMU architecture (no fork(2)).\n");
+	return KSFT_SKIP;
+#endif /* CONFIG_NOMMU */
 	ret = test_harness_argv_check(argc, argv);
 	if (ret != KSFT_PASS)
 		return ret;
diff --git a/tools/testing/selftests/lib.mk b/tools/testing/selftests/lib.mk
index 2cc819006424..4734b5ce613f 100644
--- a/tools/testing/selftests/lib.mk
+++ b/tools/testing/selftests/lib.mk
@@ -97,6 +97,14 @@ TEST_GEN_PROGS := $(patsubst %,$(OUTPUT)/%,$(TEST_GEN_PROGS))
 TEST_GEN_PROGS_EXTENDED := $(patsubst %,$(OUTPUT)/%,$(TEST_GEN_PROGS_EXTENDED))
 TEST_GEN_FILES := $(patsubst %,$(OUTPUT)/%,$(TEST_GEN_FILES))
 
+# detect if users request NOMMU build or not
+# User can set NOMMU to 1 to build/test for NOMMU platforms
+NOMMU ?= 0
+ifeq ($(NOMMU),1)
+CFLAGS += -DCONFIG_NOMMU
+export NOMMU
+endif
+
 all: $(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED) $(TEST_GEN_FILES) \
 	$(if $(TEST_GEN_MODS_DIR),gen_mods_dir)
 
-- 
2.43.0



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

* [RFC PATCH 6/6] selftests/mm: add nommu mmap and mremap behavior tests
  2026-08-13  6:33 [RFC PATCH 0/6] fix nommu mmap and add nommu kselftests Hajime Tazaki
                   ` (4 preceding siblings ...)
  2026-08-13  6:34 ` [RFC PATCH 5/6] selftests: run tests on nommu architecture Hajime Tazaki
@ 2026-08-13  6:34 ` Hajime Tazaki
  5 siblings, 0 replies; 19+ messages in thread
From: Hajime Tazaki @ 2026-08-13  6:34 UTC (permalink / raw)
  To: linux-mm
  Cc: geert, daniel, Hajime Tazaki, Andrew Morton, David Hildenbrand,
	Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Shuah Khan, linux-kselftest,
	linux-um

Introduce a kselftest utility to validate memory mapping capabilities
under nommu kernels, aligned with
Documentation/admin-guide/mm/nommu-mmap.rst.

The test implements basic checks into a generic architecture-agnostic
test matrix applicable across nommu targets. It evaluates:

1. MAP_FIXED allocation rejections.
2. Standard MAP_PRIVATE and MAP_ANONYMOUS allocation resilience.
3. MAP_UNINITIALIZED allocations via optional kernel configurations.
4. Regular file mappings via standard filesystem storage.
5. Memory-backed file mapping with /dev/zero
6. Block device subsystem mappings (gracefully skipping if node is
   missing).
7. Shared vs Private backing discrepancies under nommu conditions.
8. mremap limits, ensuring non-expandable restrictions behave properly.

Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: David Hildenbrand <david@kernel.org>
Cc: Lorenzo Stoakes <ljs@kernel.org>
Cc: "Liam R. Howlett" <liam@infradead.org>
Cc: Vlastimil Babka <vbabka@kernel.org>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Shuah Khan <shuah@kernel.org>
Cc: linux-kselftest@vger.kernel.org
Cc: linux-mm@kvack.org
Cc: linux-um@lists.infradead.org
Assisted-by: Gemini:Pro [AI_Reviewer] [Sashiko_Linter]
Assisted-by: cubic.dev:unspecified
Signed-off-by: Hajime Tazaki <thehajime@gmail.com>
---
 tools/testing/selftests/mm/Makefile           |   3 +
 tools/testing/selftests/mm/nommu_mmap_test.c  | 294 +++++++++
 .../testing/selftests/mm/nommu_mremap_test.c  | 583 ++++++++++++++++++
 3 files changed, 880 insertions(+)
 create mode 100644 tools/testing/selftests/mm/nommu_mmap_test.c
 create mode 100644 tools/testing/selftests/mm/nommu_mremap_test.c

diff --git a/tools/testing/selftests/mm/Makefile b/tools/testing/selftests/mm/Makefile
index e6df968f0971..3986ae7d75bc 100644
--- a/tools/testing/selftests/mm/Makefile
+++ b/tools/testing/selftests/mm/Makefile
@@ -185,6 +185,9 @@ TEST_FILES += run_vmtests.sh
 # required by charge_reserved_hugetlb.sh
 TEST_FILES += write_hugetlb_memory.sh
 
+TEST_GEN_PROGS += nommu_mmap_test
+TEST_GEN_PROGS += nommu_mremap_test
+
 include ../lib.mk
 
 $(TEST_GEN_PROGS): vm_util.c hugepage_settings.c
diff --git a/tools/testing/selftests/mm/nommu_mmap_test.c b/tools/testing/selftests/mm/nommu_mmap_test.c
new file mode 100644
index 000000000000..50ce385967f4
--- /dev/null
+++ b/tools/testing/selftests/mm/nommu_mmap_test.c
@@ -0,0 +1,294 @@
+// SPDX-License-Identifier: GPL-2.0
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <limits.h>
+#include "../kselftest.h"
+
+#include <sys/vfs.h>
+#ifndef RAMFS_MAGIC
+#define RAMFS_MAGIC 0x858458f6
+#endif
+
+#ifndef MAP_UNINITIALIZED
+#define MAP_UNINITIALIZED 0x4000000
+#endif
+
+static size_t ps;
+
+struct test_case_t {
+	const char *name;
+	const char *pathname;
+	int open_flags;
+	int mmap_prot;
+	int mmap_flags;
+	int exp_err;
+	int (*resolve_exp_err)(const char *path);
+};
+
+static int get_shm_expected_error(const char *path)
+{
+	struct statfs fs;
+
+	if (statfs(path, &fs) == 0) {
+		if (fs.f_type == RAMFS_MAGIC)
+			return 0; /* ramfs succeed with contiguous memory */
+	}
+	 /* hostfs, etc returns ENODEV due to lack of contiguous allocation */
+	return ENODEV;
+}
+
+static struct test_case_t test_cases[] = {
+	{
+		"Anonymous private allocation",
+		NULL,
+		O_CREAT | O_RDWR | O_EXCL,
+		PROT_READ | PROT_WRITE,
+		MAP_ANONYMOUS | MAP_PRIVATE,
+		0,
+		NULL,
+	},
+	{
+		"Non-anonymous private file mapping (rw-)",
+		"/tmp/ksft.nommu-reg-XXXXXX",
+		O_CREAT | O_RDWR | O_EXCL,
+		PROT_READ | PROT_WRITE,
+		MAP_PRIVATE,
+		0,
+		0,
+	},
+	{
+		"Non-anonymous private file mapping (r--)",
+		"/tmp/ksft.nommu-reg-XXXXXX",
+		O_CREAT | O_RDWR | O_EXCL,
+		PROT_READ,
+		MAP_PRIVATE,
+		0,
+		0,
+	},
+	{
+		"Non-anonymous shared file mapping (rw-)",
+		"/tmp/ksft.nommu-shm-XXXXXX",
+		O_CREAT | O_RDWR | O_EXCL,
+		PROT_READ | PROT_WRITE,
+		MAP_SHARED,
+		0,
+#ifdef CONFIG_NOMMU
+		get_shm_expected_error,
+#else
+		0,
+#endif
+	},
+	{
+		"Non-anonymous shared file mapping (r--)",
+		"/tmp/ksft.nommu-shm-XXXXXX",
+		O_CREAT | O_RDWR | O_EXCL,
+		PROT_READ,
+		MAP_SHARED,
+		0,
+#ifdef CONFIG_NOMMU
+		get_shm_expected_error,
+#else
+		0,
+#endif
+	},
+	{
+		"Memory-backed private storage via /dev/zero",
+		"/dev/zero",
+		O_RDONLY,
+		PROT_READ,
+		MAP_PRIVATE,
+		0,
+		NULL,
+	},
+	{
+		"Memory-backed storage via /dev/zero (MAP_SHARED)",
+		"/dev/zero",
+		O_RDONLY,
+		PROT_READ,
+		MAP_SHARED,
+#ifdef CONFIG_NOMMU
+		ENODEV,
+#else
+		0,
+#endif
+		NULL,
+	},
+	{
+		"Block device volatile node mapping",
+		"/dev/loop0",
+		O_RDWR,
+		PROT_READ | PROT_WRITE,
+		MAP_PRIVATE,
+		0,
+		NULL,
+	}
+};
+
+static int run_mapping_matrix_test(struct test_case_t *tcase)
+{
+	int fd;
+	void *ptr;
+	char path_buf[PATH_MAX];
+	int rc = KSFT_PASS;
+	int expected_error;
+
+	ksft_print_msg("[RUN] Testing: %s\n", tcase->name);
+
+	if (tcase->pathname == NULL) {
+		fd = -1;
+	} else if (strstr(tcase->pathname, "XXXXXX")) {
+		strncpy(path_buf, tcase->pathname, sizeof(path_buf) - 1);
+		path_buf[sizeof(path_buf) - 1] = '\0';
+		fd = mkstemp(path_buf);
+		if (fd < 0) {
+			ksft_test_result_skip("Failed to setup temp node: %s\n",
+					      tcase->pathname);
+			return KSFT_SKIP;
+		}
+		if (ftruncate(fd, ps) != 0) {
+			ksft_test_result_fail("ftruncate failed for: %s\n",
+					      tcase->pathname);
+			close(fd);
+			unlink(path_buf);
+			return KSFT_FAIL;
+		}
+	} else {
+		fd = open(tcase->pathname, tcase->open_flags, 0600);
+		if (fd < 0) {
+			ksft_test_result_skip("Device node not accessible: %s\n",
+				       tcase->pathname);
+			return KSFT_SKIP;
+		}
+	}
+
+	expected_error = tcase->exp_err;
+	if (tcase->resolve_exp_err && fd >= 0)
+		expected_error = tcase->resolve_exp_err(path_buf);
+
+	ptr = mmap(NULL, ps, tcase->mmap_prot, tcase->mmap_flags, fd, 0);
+
+	if (expected_error != 0) {
+		if (ptr != MAP_FAILED) {
+			ksft_test_result_fail("%s: mmap unexpectedly succeeded (exp error %d)\n",
+					      tcase->name, expected_error);
+			munmap(ptr, ps);
+			rc = KSFT_FAIL;
+			goto cleanup;
+		}
+		if (errno != expected_error) {
+			ksft_test_result_fail("%s: mmap failed with %d (%s), but expected %d\n",
+					      tcase->name, errno, strerror(errno), expected_error);
+			rc = KSFT_FAIL;
+			goto cleanup;
+		}
+		ksft_test_result_pass("%s: Correctly rejected with expected error %s(%d)\n",
+				      tcase->name, strerror(expected_error), expected_error);
+		rc = KSFT_PASS;
+		goto cleanup;
+	}
+
+	if (ptr == MAP_FAILED) {
+		ksft_test_result_fail("%s: mmap failed unexpectedly: %s\n",
+				      tcase->name, strerror(errno));
+		rc = KSFT_FAIL;
+		goto cleanup;
+	}
+
+	ksft_test_result_pass("%s: mmap validation successfully passed\n", tcase->name);
+	munmap(ptr, ps);
+
+cleanup:
+	if (fd >= 0) {
+		close(fd);
+		if (tcase->pathname && strstr(tcase->pathname, "XXXXXX"))
+			unlink(path_buf);
+	}
+	return rc;
+}
+
+static int test_map_fixed(void)
+{
+	void *ptr = mmap((void *)(ps * 100), ps, PROT_READ | PROT_WRITE,
+			 MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
+
+	ksft_print_msg("[RUN] Testing MAP_FIXED behavior\n");
+
+#ifdef CONFIG_NOMMU
+	if (ptr == MAP_FAILED && (errno == ENODEV || errno == EINVAL)) {
+		ksft_test_result_pass("MAP_FIXED correctly rejected under nommu\n");
+		return KSFT_PASS;
+	}
+	if (ptr != MAP_FAILED) {
+		ksft_test_result_fail("MAP_FIXED unexpectedly allowed under nommu\n");
+		munmap(ptr, ps);
+		return KSFT_FAIL;
+	}
+	ksft_test_result_fail("MAP_FIXED failed under NOMMU: %s\n",
+			      strerror(errno));
+	return KSFT_FAIL;
+#else
+	if (ptr != MAP_FAILED) {
+		ksft_test_result_pass("MAP_FIXED successfully allocated under MMU\n");
+		munmap(ptr, ps);
+		return KSFT_PASS;
+	}
+	ksft_test_result_fail("MAP_FIXED failed allocation under MMU\n");
+	return KSFT_FAIL;
+#endif
+}
+
+static int test_uninit(void)
+{
+	void *ptr = mmap(NULL, ps, PROT_READ | PROT_WRITE,
+			 MAP_PRIVATE | MAP_ANONYMOUS | MAP_UNINITIALIZED, -1, 0);
+
+	ksft_print_msg("[RUN] Testing MAP_UNINITIALIZED behavior\n");
+
+	if (ptr == MAP_FAILED) {
+		ksft_test_result_skip("MAP_UNINITIALIZED not supported by kernel config\n");
+		return KSFT_SKIP;
+	}
+
+	ksft_test_result_pass("MAP_UNINITIALIZED allocation successful\n");
+	munmap(ptr, ps);
+	return KSFT_PASS;
+}
+
+int main(int argc, char **argv)
+{
+	int result = KSFT_PASS;
+	int i, rc;
+
+	ps = sysconf(_SC_PAGESIZE);
+	ksft_print_header();
+	ksft_set_plan(ARRAY_SIZE(test_cases) + 2);
+
+#ifdef CONFIG_NOMMU
+	ksft_print_msg("Running strict MMAP test criteria under nommu architecture\n");
+#else
+	ksft_print_msg("Running MMAP test criteria under MMU architecture\n");
+#endif
+
+	if (test_map_fixed() == KSFT_FAIL)
+		result = KSFT_FAIL;
+
+	if (test_uninit() == KSFT_FAIL)
+		result = KSFT_FAIL;
+
+	for (i = 0; i < (int)ARRAY_SIZE(test_cases); i++) {
+		rc = run_mapping_matrix_test(&test_cases[i]);
+		if (rc == KSFT_FAIL)
+			result = KSFT_FAIL;
+	}
+
+	if (result == KSFT_PASS)
+		ksft_finished();
+
+	ksft_exit_fail();
+}
diff --git a/tools/testing/selftests/mm/nommu_mremap_test.c b/tools/testing/selftests/mm/nommu_mremap_test.c
new file mode 100644
index 000000000000..b1b8a4e64b55
--- /dev/null
+++ b/tools/testing/selftests/mm/nommu_mremap_test.c
@@ -0,0 +1,583 @@
+// SPDX-License-Identifier: GPL-2.0
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <limits.h>
+#include "../kselftest.h"
+
+#include <sys/vfs.h>
+#ifndef RAMFS_MAGIC
+#define RAMFS_MAGIC 0x858458f6
+#endif
+
+static size_t ps;
+
+static long get_fs_type(const char *path)
+{
+	struct statfs fs;
+
+	if (statfs(path, &fs) == 0)
+		return fs.f_type;
+
+	return 0;
+}
+
+/* return original value if succeed */
+static int set_nr_trim_pages(const char *value)
+{
+	int fd, orig_value;
+	ssize_t len, written, read_len;
+	char orig_buf[32];
+
+	fd = open("/proc/sys/vm/nr_trim_pages", O_RDWR);
+	if (fd < 0)
+		return -errno;
+
+	read_len = read(fd, orig_buf, sizeof(orig_buf) - 1);
+	if (read_len < 0) {
+		close(fd);
+		return -errno;
+	}
+	if (read_len == 0) {
+		close(fd);
+		return -EIO;
+	}
+
+	orig_buf[read_len] = '\0';
+	orig_value = atoi(orig_buf);
+
+	if (lseek(fd, 0, SEEK_SET) < 0) {
+		close(fd);
+		return -errno;
+	}
+
+	len = strlen(value);
+	written = write(fd, value, len);
+	close(fd);
+
+	if (written != len)
+		return written < 0 ? -errno : -EIO;
+
+	return orig_value >= 0 ? orig_value : -EINVAL;
+}
+
+static void munmap_shrink_test(void)
+{
+	void *addr;
+
+	/* munmap shrink test */
+	for (int i = 0; i < 4; i++) {
+		addr = mmap(NULL, ps * 4, PROT_READ | PROT_WRITE,
+			    MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+		if (addr == MAP_FAILED) {
+			ksft_test_result_fail("mmap failed: %s(%d)\n", strerror(errno), errno);
+			return;
+		}
+		if (munmap(addr + ps * i, ps) != 0) {
+			ksft_test_result_fail("memory %p isn't unmapped at %p\n",
+					      addr, addr + ps * i);
+			for (int j = 0; j < 4; j++)
+				munmap((char *)addr + j * ps, ps);
+			return;
+		}
+
+		if (i == 0) {
+			if (munmap(addr +  ps, ps * 3))
+				goto error;
+		} else if (i == 1) {
+			if (munmap(addr, ps) || munmap(addr + (ps * 2), ps * 2))
+				goto error;
+		} else if (i == 2) {
+			if (munmap(addr, ps * 2) || munmap(addr + (ps * 3), ps))
+				goto error;
+		} else if (i == 3) {
+			if (munmap(addr, ps * 3))
+				goto error;
+		}
+	}
+
+	ksft_test_result_pass("%s success\n", __func__);
+	return;
+error:
+	for (int j = 0; j < 4; j++)
+		munmap((char *)addr + j * ps, ps);
+	ksft_test_result_fail("%s clean up failures\n", __func__);
+}
+
+static size_t page_align(size_t len)
+{
+	return (len + ps - 1) / ps * ps;
+}
+
+static void mremap_shrink_test(void)
+{
+	void *addr, *addr2;
+	size_t current_len;
+	size_t old_len, new_len;
+	struct param {
+		size_t old;
+		size_t new;
+	} params[] = {
+		/* should not happen any shrink */
+		{ .old = ps * 4 - 1, .new = ps * 4 - 2 },
+		/* should not happen any shrink */
+		{ .old = ps * 4 - 1, .new = ps * 4 },
+		{ .old = ps * 4, .new = ps * 2 },
+		/* should not happen any shrink */
+		{ .old = ps * 2, .new = ps * 2 - 2 },
+		{ .old = ps * 2 - 2, .new = ps * 1 },
+	};
+
+	/* mremap shrink test */
+	current_len = page_align(ps * 4 - 1);
+	addr = mmap(NULL, ps * 4 - 1, PROT_READ | PROT_WRITE,
+		    MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+	if (addr == MAP_FAILED) {
+		ksft_test_result_fail("mmap failed: %s(%d)\n", strerror(errno), errno);
+		return;
+	}
+
+	for (int i = 0; i < ARRAY_SIZE(params); i++) {
+		old_len = page_align(params[i].old);
+		new_len = page_align(params[i].new);
+		addr2 = mremap(addr, old_len, new_len, MREMAP_MAYMOVE);
+		if (addr2 == MAP_FAILED) {
+			ksft_test_result_fail("memory %p isn't remapped at %p\n", addr, addr2);
+			munmap(addr, old_len);
+			return;
+		}
+
+		addr = addr2;
+		current_len = new_len;
+	}
+
+	if (munmap(addr, current_len)) {
+		ksft_test_result_fail("%s cleanup failed: %s\n",
+				      __func__, strerror(errno));
+		return;
+	}
+	ksft_test_result_pass("%s success\n", __func__);
+}
+
+static void zero_middle_munmap_test(void)
+{
+	int fd = -1;
+	void *addr = MAP_FAILED;
+	void *addr2 = MAP_FAILED;
+	int left_mapped = 0;
+	int right_mapped = 0;
+	int ret;
+	bool addr2_middle_unmapped = false;
+
+	ksft_print_msg("[RUN] Testing middle munmap of private /dev/zero mappings\n");
+
+	fd = open("/dev/zero", O_RDONLY);
+	if (fd < 0) {
+		ksft_test_result_skip("Unable to open /dev/zero: %s\n",
+				      strerror(errno));
+		return;
+	}
+
+	addr = mmap(NULL, ps * 3, PROT_READ | PROT_WRITE,
+		    MAP_PRIVATE, fd, 0);
+	close(fd);
+	fd = -1;
+	if (addr == MAP_FAILED) {
+		ksft_test_result_fail("Initial /dev/zero mmap failed: %s\n",
+				      strerror(errno));
+		return;
+	}
+
+	left_mapped = 1;
+	right_mapped = 1;
+
+	/*
+	 * Split one private /dev/zero VMA in the middle. On nommu, the
+	 * VMA still has vm_file set even though it is semantically
+	 * anonymous.
+	 */
+	ret = munmap((char *)addr + ps, ps);
+	if (ret) {
+		ksft_test_result_fail("Middle munmap failed: %s\n",
+				      strerror(errno));
+		munmap(addr, ps * 3);
+		left_mapped = 0;
+		right_mapped = 0;
+		goto out;
+	}
+
+	/*
+	 * Access both remaining VMAs so a stale VMA interval cannot remain
+	 * hidden behind the unmapped hole.
+	 */
+	((volatile unsigned char *)addr)[0] = 0x5a;
+	((volatile unsigned char *)addr + 2 * ps)[0] = 0xa5;
+
+	/*
+	 * Repeat the operation on another mapping of the same inode. This
+	 * exercises insertion and removal in /dev/zero's i_mmap interval
+	 * tree after the first split.
+	 */
+	fd = open("/dev/zero", O_RDONLY);
+	if (fd < 0) {
+		ksft_test_result_fail("Reopening /dev/zero failed: %s\n",
+				      strerror(errno));
+		goto out;
+	}
+
+	addr2 = mmap(NULL, ps * 3, PROT_READ | PROT_WRITE,
+		     MAP_PRIVATE, fd, 0);
+	close(fd);
+	fd = -1;
+	if (addr2 == MAP_FAILED) {
+		ksft_test_result_fail("Second /dev/zero mmap failed: %s\n",
+				      strerror(errno));
+		goto out;
+	}
+
+	ret = munmap((char *)addr2 + ps, ps);
+	if (ret) {
+		ksft_test_result_fail("Second middle munmap failed: %s\n",
+				      strerror(errno));
+		goto out;
+	}
+	addr2_middle_unmapped = true;
+
+	if (munmap(addr, ps)) {
+		ksft_test_result_fail("Left VMA munmap failed: %s\n",
+				      strerror(errno));
+		goto out;
+	}
+	left_mapped = 0;
+
+	if (munmap((char *)addr + 2 * ps, ps)) {
+		ksft_test_result_fail("Right VMA munmap failed: %s\n",
+				      strerror(errno));
+		goto out;
+	}
+	right_mapped = 0;
+
+	if (munmap(addr2, ps)) {
+		ksft_test_result_fail("Second left VMA munmap failed: %s\n",
+				      strerror(errno));
+		goto out;
+	}
+
+	if (munmap((char *)addr2 + 2 * ps, ps)) {
+		ksft_test_result_fail("Second right VMA munmap failed: %s\n",
+				      strerror(errno));
+		goto out;
+	}
+	addr2 = MAP_FAILED;
+
+	ksft_test_result_pass("%s success\n", __func__);
+
+out:
+	if (fd >= 0)
+		close(fd);
+	if (left_mapped)
+		munmap(addr, ps);
+	if (right_mapped)
+		munmap((char *)addr + 2 * ps, ps);
+	if (addr2 != MAP_FAILED) {
+		if (addr2_middle_unmapped) {
+			munmap(addr2, ps);
+			munmap((char *)addr2 + 2 * ps, ps);
+		} else {
+			/* The middle munmap failed, so all three pages remain mapped. */
+			munmap(addr2, ps * 3);
+		}
+	}
+}
+
+static int get_shared_writable_file_expected_error(const char *path)
+{
+	if (get_fs_type(path) == RAMFS_MAGIC)
+		return EPERM; /* ramfs failed */
+
+	return 0;
+}
+
+static int pre_conf_trim_page(void)
+{
+	return set_nr_trim_pages("0\n");
+}
+
+static int post_conf_trim_page(int value)
+{
+	char buf[32];
+
+	if (snprintf(buf, sizeof(buf), "%d\n", value) < 0)
+		return -EIO;
+
+	return set_nr_trim_pages(buf);
+}
+
+struct mremap_case_t {
+	const char *name;
+	const char *pathname;
+	int open_flags;
+	int mmap_prot;
+	int mmap_flags;
+	int exp_err;
+	int (*resolve_exp_err)(const char *path);
+	unsigned int old_pages;
+	unsigned int new_pages;
+	int (*pre_hook)(void);
+	int (*post_hook)(int value);
+};
+
+static struct mremap_case_t mremap_cases[] = {
+	{
+		.name = "anonymous shrink (r--)",
+		.pathname = NULL,
+		.open_flags = O_CREAT | O_RDWR | O_EXCL,
+		.mmap_prot = PROT_READ,
+		.mmap_flags = MAP_ANONYMOUS | MAP_PRIVATE,
+		.exp_err = 0,
+		.resolve_exp_err = 0,
+	},
+	{
+		.name = "shared file shrink (r--)",
+		.pathname = "/tmp/ksft.nommu-remap-XXXXXX",
+		.open_flags = O_CREAT | O_RDWR | O_EXCL,
+		.mmap_prot = PROT_READ,
+		.mmap_flags = MAP_SHARED,
+		.exp_err = 0,
+#ifdef CONFIG_NOMMU
+		.resolve_exp_err = get_shared_writable_file_expected_error,
+#else
+		.resolve_exp_err = 0,
+#endif
+	},
+	{
+		.name = "zero device shrink (r--)",
+		.pathname = "/dev/zero",
+		.open_flags = O_RDONLY,
+		.mmap_prot = PROT_READ,
+		.mmap_flags = MAP_PRIVATE,
+		.exp_err = 0,
+		.resolve_exp_err = 0,
+	},
+	{
+		.name = "private file unchanged length (r-)",
+		.pathname = "/tmp/ksft.nommu-remap-XXXXXX",
+		.open_flags = O_CREAT | O_RDWR | O_EXCL,
+		.mmap_prot = PROT_READ,
+		.mmap_flags = MAP_PRIVATE,
+#ifdef CONFIG_NOMMU
+		.exp_err = EPERM,
+#else
+		.exp_err = 0,
+#endif
+		.resolve_exp_err = 0,
+		.old_pages = 4,
+		.new_pages = 4,
+	},
+	{
+		.name = "private file unchanged length (rw-)",
+		.pathname = "/tmp/ksft.nommu-remap-XXXXXX",
+		.open_flags = O_CREAT | O_RDWR | O_EXCL,
+		.mmap_prot = PROT_READ | PROT_WRITE,
+		.mmap_flags = MAP_PRIVATE,
+		.exp_err = 0,
+		.resolve_exp_err = 0,
+		.old_pages = 4,
+		.new_pages = 4,
+	},
+	{
+		.name = "private file growth (r-)",
+		.pathname = "/tmp/ksft.nommu-remap-XXXXXX",
+		.open_flags = O_CREAT | O_RDWR | O_EXCL,
+		.mmap_prot = PROT_READ,
+		.mmap_flags = MAP_PRIVATE,
+#ifdef CONFIG_NOMMU
+		.exp_err = EPERM,
+#else
+		.exp_err = 0,
+#endif
+		.resolve_exp_err = 0,
+		.old_pages = 4,
+		.new_pages = 8,
+	},
+	{
+		.name = "private file growth with reserved capacity (rw-)",
+		.pathname = "/tmp/ksft.nommu-remap-XXXXXX",
+		.open_flags = O_CREAT | O_RDWR | O_EXCL,
+		.mmap_prot = PROT_READ | PROT_WRITE,
+		.mmap_flags = MAP_PRIVATE,
+		.exp_err = 0,
+		.resolve_exp_err = 0,
+		.old_pages = 3,
+		.new_pages = 4,
+#ifdef CONFIG_NOMMU
+		.pre_hook = pre_conf_trim_page,
+		.post_hook = post_conf_trim_page,
+#endif
+	},
+	{
+		.name = "private file growth (rw-)",
+		.pathname = "/tmp/ksft.nommu-remap-XXXXXX",
+		.open_flags = O_CREAT | O_RDWR | O_EXCL,
+		.mmap_prot = PROT_READ | PROT_WRITE,
+		.mmap_flags = MAP_PRIVATE,
+#ifdef CONFIG_NOMMU
+		.exp_err = ENOMEM,
+#else
+		.exp_err = 0,
+#endif
+		.resolve_exp_err = 0,
+		.old_pages = 4,
+		.new_pages = 8,
+	},
+};
+
+static int run_mremap_test(struct mremap_case_t *tcase)
+{
+	int fd = -1;
+	void *addr, *addr2;
+	char pb[PATH_MAX];
+	int rc = KSFT_PASS;
+	int expected_error;
+	unsigned int old_pages = tcase->old_pages ?: 4;
+	unsigned int new_pages = tcase->new_pages ?: 2;
+	unsigned int file_pages = old_pages > new_pages ?
+				  old_pages : new_pages;
+	int orig_nr_trip_pages = -1;
+
+	ksft_print_msg("[RUN] Testing mremap: %s\n", tcase->name);
+
+	if (tcase->pathname && strstr(tcase->pathname, "XXXXXX")) {
+		strncpy(pb, tcase->pathname, sizeof(pb) - 1);
+		pb[sizeof(pb) - 1] = '\0';
+		fd = mkstemp(pb);
+		if (fd < 0) {
+			ksft_test_result_skip("Failed to setup file backing\n");
+			return KSFT_SKIP;
+		}
+		if (ftruncate(fd, ps * file_pages) != 0) {
+			ksft_test_result_fail("Failed to setup file backing\n");
+			close(fd);
+			unlink(pb);
+			return KSFT_FAIL;
+		}
+
+		if ((tcase->mmap_flags & MAP_SHARED) && get_fs_type(pb) != RAMFS_MAGIC) {
+			ksft_test_result_skip("Skip the test under non-ramfs filesystem (%s)\n",
+					      pb);
+			close(fd);
+			unlink(pb);
+			return KSFT_SKIP;
+		}
+	} else if (tcase->pathname) {
+		fd = open(tcase->pathname, tcase->open_flags, 0600);
+		if (fd < 0) {
+			ksft_test_result_skip("Backing node not accessible\n");
+			return KSFT_SKIP;
+		}
+
+		if ((tcase->mmap_flags & MAP_SHARED) &&
+		    get_fs_type(tcase->pathname) != RAMFS_MAGIC) {
+			ksft_test_result_skip("Skip the test under non-ramfs filesystem (%s)\n",
+					      tcase->pathname);
+			close(fd);
+			return KSFT_SKIP;
+		}
+	}
+
+	if (tcase->pre_hook) {
+		orig_nr_trip_pages = tcase->pre_hook();
+		if (orig_nr_trip_pages < 0) {
+			ksft_print_msg("pre-hook failed %s(%d)\n",
+					    strerror(errno), errno);
+			rc = KSFT_FAIL;
+			goto out;
+		}
+	}
+
+	addr = mmap(NULL, ps * old_pages, tcase->mmap_prot,
+		    tcase->mmap_flags, fd, 0);
+	if (addr == MAP_FAILED) {
+		ksft_print_msg("mmap mapping failed %s(%d)\n", strerror(errno), errno);
+		rc = KSFT_FAIL;
+		goto out;
+	}
+
+	expected_error = tcase->exp_err;
+	if (tcase->resolve_exp_err && fd >= 0)
+		expected_error = tcase->resolve_exp_err(pb);
+
+	addr2 = mremap(addr, ps * old_pages, ps * new_pages,
+		       MREMAP_MAYMOVE);
+
+	if (expected_error != 0) {
+		if (addr2 != MAP_FAILED || errno != expected_error) {
+			ksft_print_msg("Expected error %d, got %s(%d)\n",
+				       expected_error, strerror(errno), errno);
+			rc = KSFT_FAIL;
+		} else {
+			ksft_print_msg("%s/%s: Handled expected error path (errno=%d)\n",
+				       __func__, tcase->name, expected_error);
+		}
+	} else if (addr2 == MAP_FAILED) {
+		ksft_print_msg("mremap shrink failed unexpectedly: %s\n",
+			       strerror(errno));
+		rc = KSFT_FAIL;
+	} else {
+		ksft_print_msg("%s/%s step successful\n", __func__, tcase->name);
+	}
+
+	/* clean up */
+	if (munmap(addr2 == MAP_FAILED ? addr : addr2,
+		   addr2 == MAP_FAILED ? ps * old_pages : ps * new_pages)) {
+		ksft_print_msg("munmap failed: %s\n", strerror(errno));
+		rc = KSFT_FAIL;
+	}
+
+out:
+	if (fd >= 0) {
+		close(fd);
+		if (tcase->pathname && strstr(tcase->pathname, "XXXXXX"))
+			unlink(pb);
+	}
+
+	if (tcase->post_hook) {
+		if (tcase->post_hook(orig_nr_trip_pages) < 0) {
+			ksft_print_msg("post-hook failed %s(%d)\n",
+				       strerror(errno), errno);
+			rc = KSFT_FAIL;
+		}
+	}
+
+	ksft_test_result_report(rc, "%s:%s\n", __func__, tcase->name);
+	return rc;
+}
+
+int main(int argc, char **argv)
+{
+	int res = KSFT_PASS;
+	int i;
+
+	ps = sysconf(_SC_PAGESIZE);
+	ksft_print_header();
+	ksft_set_plan(ARRAY_SIZE(mremap_cases) + 3);
+
+	munmap_shrink_test();
+	mremap_shrink_test();
+	zero_middle_munmap_test();
+
+	for (i = 0; i < (int)ARRAY_SIZE(mremap_cases); i++) {
+		if (run_mremap_test(&mremap_cases[i]) == KSFT_FAIL)
+			res = KSFT_FAIL;
+	}
+
+	if (res == KSFT_PASS)
+		ksft_finished();
+
+	ksft_exit_fail();
+}
-- 
2.43.0



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

* Re: [RFC PATCH 3/6] mm: nommu: fix an issue on map request to /dev/zero
  2026-08-13  6:33 ` [RFC PATCH 3/6] mm: nommu: fix an issue on map request to /dev/zero Hajime Tazaki
@ 2026-08-13 12:19   ` Greg Kroah-Hartman
  2026-08-13 12:43     ` Daniel Palmer
  2026-08-13 13:22     ` Matthew Wilcox
  0 siblings, 2 replies; 19+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-13 12:19 UTC (permalink / raw)
  To: Hajime Tazaki
  Cc: linux-mm, geert, daniel, Arnd Bergmann, Matthew Wilcox (Oracle),
	Jan Kara, Andrew Morton, Liam R. Howlett, Lorenzo Stoakes,
	Vlastimil Babka, Jann Horn, Pedro Falcato, linux-fsdevel

On Thu, Aug 13, 2026 at 03:33:58PM +0900, Hajime Tazaki wrote:
> Upon a private file mapping request to /dev/zero, it calls
> kernel_read() in do_mmap_private(), getting a failure with the message
> like: "kernel reads not supported for file /dev/zero", which is because
> zero_fops defined in drivers/char/mem.c has both .read and .read_iter
> definitions.

Do you actually use a no-mmu system?

> Even fixing this issue, the map request to /dev/zero works fine without
> errors but the allocated vma isn't marked with anonymous because
> mmap_zero_prepare() isn't called under nommu platform, resulting
> vma_desc_set_anonymous() isn't called either.
> 
> This commit fixes those issues by:
> 1) use vfs_iter_read() instead to avoid failure at kernel_read()
> 2) calls .mmap_prepare on private mapping in do_mmap() so that required
>    preparations are done even in private mapping.
> 
> Cc: Arnd Bergmann <arnd@arndb.de>
> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> Cc: "Matthew Wilcox (Oracle)" <willy@infradead.org>
> Cc: Jan Kara <jack@suse.cz>
> Cc: Andrew Morton <akpm@linux-foundation.org>
> Cc: "Liam R. Howlett" <liam@infradead.org>
> Cc: Lorenzo Stoakes <ljs@kernel.org>
> Cc: Vlastimil Babka <vbabka@kernel.org>
> Cc: Jann Horn <jannh@google.com>
> Cc: Pedro Falcato <pfalcato@suse.de>
> Cc: linux-fsdevel@vger.kernel.org
> Cc: linux-mm@kvack.org (open list:PAGE CACHE)
> Fixes: 4d03e3cc5982 ("fs: don't allow kernel reads and writes without iter ops")

Given the age of this issue, I don't think anyone uses no-mmu systems
anymore :(



> Assisted-by: cubic.dev:unspecified
> Signed-off-by: Hajime Tazaki <thehajime@gmail.com>
> ---
>  drivers/char/mem.c |  5 ++-
>  mm/filemap.c       |  6 ++--
>  mm/nommu.c         | 84 ++++++++++++++++++++++++++++++++++++++++++++--
>  3 files changed, 87 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/char/mem.c b/drivers/char/mem.c
> index 63253d1de5d7..dba24d0a7b33 100644
> --- a/drivers/char/mem.c
> +++ b/drivers/char/mem.c
> @@ -500,11 +500,10 @@ static ssize_t read_zero(struct file *file, char __user *buf,
>  
>  static int mmap_zero_prepare(struct vm_area_desc *desc)
>  {
> -#ifndef CONFIG_MMU
> -	return -ENOSYS;
> -#endif
> +#ifdef CONFIG_MMU
>  	if (vma_desc_test(desc, VMA_SHARED_BIT))
>  		return shmem_zero_setup_desc(desc);
> +#endif
>  
>  	/*
>  	 * This is a highly unique situation where we mark a MAP_PRIVATE mapping
> diff --git a/mm/filemap.c b/mm/filemap.c
> index d721986d5f46..cf02faad86aa 100644
> --- a/mm/filemap.c
> +++ b/mm/filemap.c
> @@ -4077,7 +4077,7 @@ int generic_file_mmap(struct file *file, struct vm_area_struct *vma)
>  }
>  int generic_file_mmap_prepare(struct vm_area_desc *desc)
>  {
> -	return -ENOSYS;
> +	return 0;
>  }
>  int generic_file_readonly_mmap(struct file *file, struct vm_area_struct *vma)
>  {
> @@ -4085,7 +4085,9 @@ int generic_file_readonly_mmap(struct file *file, struct vm_area_struct *vma)
>  }
>  int generic_file_readonly_mmap_prepare(struct vm_area_desc *desc)
>  {
> -	return -ENOSYS;
> +	if (is_shared_maywrite(&desc->vma_flags))
> +		return -EINVAL;
> +	return generic_file_mmap_prepare(desc);
>  }
>  #endif /* CONFIG_MMU */
>  
> diff --git a/mm/nommu.c b/mm/nommu.c
> index e40990e15831..a29a53c1c80a 100644
> --- a/mm/nommu.c
> +++ b/mm/nommu.c
> @@ -37,6 +37,7 @@
>  
>  #include <linux/uaccess.h>
>  #include <linux/uio.h>
> +#include <linux/major.h>
>  #include <asm/tlb.h>
>  #include <asm/tlbflush.h>
>  #include <asm/mmu_context.h>
> @@ -856,6 +857,22 @@ static int validate_mmap_request(struct file *file,
>  	return 0;
>  }
>  
> +static int is_file_anonymous(struct file *file)
> +{
> +	if (!file)
> +		return 1;
> +
> +	if (file->f_path.dentry && file->f_path.dentry->d_inode) {
> +		struct inode *inode = file->f_path.dentry->d_inode;
> +		/* if the device is /dev/zero */
> +		if (S_ISCHR(inode->i_mode) &&
> +		    imajor(inode) == MEM_MAJOR && iminor(inode) == 5)
> +			return 1;
> +	}
> +
> +	return 0;
> +}
> +
>  /*
>   * we've determined that we can make the mapping, now translate what we
>   * now know into VMA flags
> @@ -869,7 +886,11 @@ static vm_flags_t determine_vm_flags(struct file *file,
>  
>  	vm_flags = calc_vm_prot_bits(prot, 0) | calc_vm_flag_bits(file, flags);
>  
> -	if (!file) {
> +	/* private and file mapping will be marked anonymous later (do_mmap_private()).
> +	 * and /dev/zero is marked by them at .mmap_prepare,
> +	 * which should be _before_ this point.
> +	 */

Wrong coding style for the comment, which is very typical of
LLM-generated stuff.  Always rewrite the output of these tools to
actually be sane.

thanks,

greg k-h


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

* Re: [RFC PATCH 3/6] mm: nommu: fix an issue on map request to /dev/zero
  2026-08-13 12:19   ` Greg Kroah-Hartman
@ 2026-08-13 12:43     ` Daniel Palmer
  2026-08-13 13:29       ` Lorenzo Stoakes (ARM)
  2026-08-13 14:02       ` Greg Kroah-Hartman
  2026-08-13 13:22     ` Matthew Wilcox
  1 sibling, 2 replies; 19+ messages in thread
From: Daniel Palmer @ 2026-08-13 12:43 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Hajime Tazaki, linux-mm, geert, Arnd Bergmann,
	Matthew Wilcox (Oracle), Jan Kara, Andrew Morton, Liam R. Howlett,
	Lorenzo Stoakes, Vlastimil Babka, Jann Horn, Pedro Falcato,
	linux-fsdevel

Hi Greg,

On Thu, 13 Aug 2026 at 21:26, Greg Kroah-Hartman
<gregkh@linuxfoundation.org> wrote:

> Given the age of this issue, I don't think anyone uses no-mmu systems
> anymore :(

There are a few of us using it for hobby stuff[0][1] and there are
apparently people using it for actual commercial stuff.
There was a session about this at LPC 2025...

One of the big problems for nommu seems to be that everyone is
convinced it is completely unused and totally broken. :)

Cheers,

Daniel

0 - Really good example(s) of the 68000 port
https://github.com/crmaykish/mackerel-68k
1 - https://github.com/LinuxMD/linuxmd my version of the 68000 code
with devicetree like those fancy ARM things running on a sega
megadrive.


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

* Re: [RFC PATCH 3/6] mm: nommu: fix an issue on map request to /dev/zero
  2026-08-13 12:19   ` Greg Kroah-Hartman
  2026-08-13 12:43     ` Daniel Palmer
@ 2026-08-13 13:22     ` Matthew Wilcox
  2026-08-13 13:32       ` Lorenzo Stoakes (ARM)
  2026-08-13 14:04       ` Greg Kroah-Hartman
  1 sibling, 2 replies; 19+ messages in thread
From: Matthew Wilcox @ 2026-08-13 13:22 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Hajime Tazaki, linux-mm, geert, daniel, Arnd Bergmann, Jan Kara,
	Andrew Morton, Liam R. Howlett, Lorenzo Stoakes, Vlastimil Babka,
	Jann Horn, Pedro Falcato, linux-fsdevel

On Thu, Aug 13, 2026 at 09:19:47PM +0900, Greg Kroah-Hartman wrote:
> On Thu, Aug 13, 2026 at 03:33:58PM +0900, Hajime Tazaki wrote:
> > Upon a private file mapping request to /dev/zero, it calls
> > kernel_read() in do_mmap_private(), getting a failure with the message
> > like: "kernel reads not supported for file /dev/zero", which is because
> > zero_fops defined in drivers/char/mem.c has both .read and .read_iter
> > definitions.
> 
> Do you actually use a no-mmu system?

If you look at Hajime's contributions, you'll see they're far from an AI
slopper.

https://lore.kernel.org/linux-mm/?q=hajime+tazaki

> > @@ -869,7 +886,11 @@ static vm_flags_t determine_vm_flags(struct file *file,
> >  
> >  	vm_flags = calc_vm_prot_bits(prot, 0) | calc_vm_flag_bits(file, flags);
> >  
> > -	if (!file) {
> > +	/* private and file mapping will be marked anonymous later (do_mmap_private()).
> > +	 * and /dev/zero is marked by them at .mmap_prepare,
> > +	 * which should be _before_ this point.
> > +	 */
> 
> Wrong coding style for the comment, which is very typical of
> LLM-generated stuff.  Always rewrite the output of these tools to
> actually be sane.

A lot of humans write comments like this too.  Indeed, it used to be
the preferred style for net/


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

* Re: [RFC PATCH 3/6] mm: nommu: fix an issue on map request to /dev/zero
  2026-08-13 12:43     ` Daniel Palmer
@ 2026-08-13 13:29       ` Lorenzo Stoakes (ARM)
  2026-08-13 13:51         ` Daniel Palmer
  2026-08-13 14:02       ` Greg Kroah-Hartman
  1 sibling, 1 reply; 19+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-08-13 13:29 UTC (permalink / raw)
  To: Daniel Palmer
  Cc: Greg Kroah-Hartman, Hajime Tazaki, linux-mm, geert, Arnd Bergmann,
	Matthew Wilcox (Oracle), Jan Kara, Andrew Morton, Liam R. Howlett,
	Vlastimil Babka, Jann Horn, Pedro Falcato, linux-fsdevel

On Thu, Aug 13, 2026 at 09:43:37PM +0900, Daniel Palmer wrote:
> Hi Greg,
>
> On Thu, 13 Aug 2026 at 21:26, Greg Kroah-Hartman
> <gregkh@linuxfoundation.org> wrote:
>
> > Given the age of this issue, I don't think anyone uses no-mmu systems
> > anymore :(
>
> There are a few of us using it for hobby stuff[0][1] and there are
> apparently people using it for actual commercial stuff.
> There was a session about this at LPC 2025...
>
> One of the big problems for nommu seems to be that everyone is
> convinced it is completely unused and totally broken. :)

No, the issue is that nobody seems to do any testing or contribute any code
aside from at least Hajime (thanks Haijme :), and possibly others (forgive me if
I am missing people's names here!)

There's been situtions where nommu has been broken for a year and _nobody
noticed_.

And yet whenever nommu comes up people always seem to pop up and say how
important it is, then mention a talk etc.

Well if it's important, test it. Test the tip kernel. Report bugs. Contribute
code. Any or all of it :)

Meanwhile we in mm have to _constantly_ fix stuff up in nommu because it's a
total mess and has real maintenance overhead.

Having to account for legacy systems that make no sense in 2026 when you're
trying to make improvements to systems people use, or not being able to do
certain things, really grates after a while.

I mean if you don't believe me git log mm/nommu.c. This overhead reason is why I
now co-maintain it.

So I'm honestly a bit tired of people popping up when the whole 'why nommu'
thing comes up, then disappearing when there's work to be done.

In general - it's not really for those not doing the work to dictate terms to
those who do, IMO.

So while I appreciate you confirming there are users (yes we know :) frankly
that's not the question. The question is - why isn't a downstream kernel enough
for you?

Last time I brought this up I basically got radio silence, a couple times before
that I was told 'nommu has no maintenance overhead and is perfectly good code
and we have products' by somebody who contributes little to nothing in terms of
code and nothing no testing.

So bah humbug.

AFAIC it needs to go and we should never have allowed risc v to add a new nommu
arch.

>
> Cheers,
>
> Daniel
>
> 0 - Really good example(s) of the 68000 port
> https://github.com/crmaykish/mackerel-68k
> 1 - https://github.com/LinuxMD/linuxmd my version of the 68000 code
> with devicetree like those fancy ARM things running on a sega
> megadrive.

--
Cheers, Lorenzo


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

* Re: [RFC PATCH 3/6] mm: nommu: fix an issue on map request to /dev/zero
  2026-08-13 13:22     ` Matthew Wilcox
@ 2026-08-13 13:32       ` Lorenzo Stoakes (ARM)
  2026-08-13 13:43         ` Lorenzo Stoakes (ARM)
  2026-08-13 14:04       ` Greg Kroah-Hartman
  1 sibling, 1 reply; 19+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-08-13 13:32 UTC (permalink / raw)
  To: Matthew Wilcox
  Cc: Greg Kroah-Hartman, Hajime Tazaki, linux-mm, geert, daniel,
	Arnd Bergmann, Jan Kara, Andrew Morton, Liam R. Howlett,
	Vlastimil Babka, Jann Horn, Pedro Falcato, linux-fsdevel

On Thu, Aug 13, 2026 at 02:22:03PM +0100, Matthew Wilcox wrote:
> On Thu, Aug 13, 2026 at 09:19:47PM +0900, Greg Kroah-Hartman wrote:
> > On Thu, Aug 13, 2026 at 03:33:58PM +0900, Hajime Tazaki wrote:
> > > Upon a private file mapping request to /dev/zero, it calls
> > > kernel_read() in do_mmap_private(), getting a failure with the message
> > > like: "kernel reads not supported for file /dev/zero", which is because
> > > zero_fops defined in drivers/char/mem.c has both .read and .read_iter
> > > definitions.
> >
> > Do you actually use a no-mmu system?
>
> If you look at Hajime's contributions, you'll see they're far from an AI
> slopper.
>
> https://lore.kernel.org/linux-mm/?q=hajime+tazaki
>
> > > @@ -869,7 +886,11 @@ static vm_flags_t determine_vm_flags(struct file *file,
> > >
> > >  	vm_flags = calc_vm_prot_bits(prot, 0) | calc_vm_flag_bits(file, flags);
> > >
> > > -	if (!file) {
> > > +	/* private and file mapping will be marked anonymous later (do_mmap_private()).
> > > +	 * and /dev/zero is marked by them at .mmap_prepare,
> > > +	 * which should be _before_ this point.
> > > +	 */
> >
> > Wrong coding style for the comment, which is very typical of
> > LLM-generated stuff.  Always rewrite the output of these tools to
> > actually be sane.
>
> A lot of humans write comments like this too.  Indeed, it used to be
> the preferred style for net/

Yeah Hajime is one of the good guys and I don't think he's a schlopper.

(I do want to review his series, as usual time is against me :)

I do agree with Greg however that nommu is something we should get rid of. See
my other reply here.

Am frankly fed up with people telling us that nommu really matters and giving
talks at conferences but contributing nothing (apart from Hajime, who deserves
respect for walking the walk on that!)

If nommu can be broken for a year with nobody noticing, then maybe it's time to
see if anybody notices us removing it too.

Sadly I think Linus won't share this opinion but as co-maintainer of mm/nommu.c
this is my perspective ;)

--
Cheers, Lorenzo


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

* Re: [RFC PATCH 3/6] mm: nommu: fix an issue on map request to /dev/zero
  2026-08-13 13:32       ` Lorenzo Stoakes (ARM)
@ 2026-08-13 13:43         ` Lorenzo Stoakes (ARM)
  0 siblings, 0 replies; 19+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-08-13 13:43 UTC (permalink / raw)
  To: Matthew Wilcox
  Cc: Greg Kroah-Hartman, Hajime Tazaki, linux-mm, geert, daniel,
	Arnd Bergmann, Jan Kara, Andrew Morton, Liam R. Howlett,
	Vlastimil Babka, Jann Horn, Pedro Falcato, linux-fsdevel

On Thu, Aug 13, 2026 at 02:32:27PM +0100, Lorenzo Stoakes (ARM) wrote:
> I do agree with Greg however that nommu is something we should get rid of. See
> my other reply here.

Sorry this was an overreach - Greg didn't say that :)

I mean Greg asked if anybody uses nommu, the answer is yes, but the real
question I think is 'is anybody using a very recent kernel who couldn't either
use an older one or maintain a downstream kernel'.

And to that I think the answer is absolutely not.

And if the answer were yes - you must surely be a company with a product
(security concerns on a nommu system is a debatable concept) - and then you need
to put up or shut up IMO.

--
Cheers, Lorenzo


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

* Re: [RFC PATCH 3/6] mm: nommu: fix an issue on map request to /dev/zero
  2026-08-13 13:29       ` Lorenzo Stoakes (ARM)
@ 2026-08-13 13:51         ` Daniel Palmer
  2026-08-13 13:58           ` Lorenzo Stoakes (ARM)
  2026-08-13 14:06           ` Greg Kroah-Hartman
  0 siblings, 2 replies; 19+ messages in thread
From: Daniel Palmer @ 2026-08-13 13:51 UTC (permalink / raw)
  To: Lorenzo Stoakes (ARM)
  Cc: Greg Kroah-Hartman, Hajime Tazaki, linux-mm, geert, Arnd Bergmann,
	Matthew Wilcox (Oracle), Jan Kara, Andrew Morton, Liam R. Howlett,
	Vlastimil Babka, Jann Horn, Pedro Falcato, linux-fsdevel

HI Lorenzo,

On Thu, 13 Aug 2026 at 22:30, Lorenzo Stoakes (ARM) <ljs@kernel.org> wrote:
> > One of the big problems for nommu seems to be that everyone is
> > convinced it is completely unused and totally broken. :)
>
> No, the issue is that nobody seems to do any testing or contribute any code
> aside from at least Hajime (thanks Haijme :), and possibly others (forgive me if
> I am missing people's names here!)

> There's been situtions where nommu has been broken for a year and _nobody
> noticed_.
>
> And yet whenever nommu comes up people always seem to pop up and say how
> important it is, then mention a talk etc.

It also broke sometime around LPC 2025, I spotted it, reported it..
and told the people in the room at LPC for the nommu talk that it was
borken and maybe they should take a look. :)
I think I maybe even told Tazaki-san in person that it was currently
broken in the hall outside of the session.

> Well if it's important, test it. Test the tip kernel. Report bugs. Contribute
> code. Any or all of it :)

I rebase my 68000 tree on mainline regularly and make sure it still
works. That's how I noticed and reported the above bug.
I have a bunch of stuff that claude fable found, validated with QEMU
and then I checked on real hardware but I'm not sure how to send that
without it getting instantly marked as slop. :(

Cheers,

Daniel


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

* Re: [RFC PATCH 3/6] mm: nommu: fix an issue on map request to /dev/zero
  2026-08-13 13:51         ` Daniel Palmer
@ 2026-08-13 13:58           ` Lorenzo Stoakes (ARM)
  2026-08-13 14:06           ` Greg Kroah-Hartman
  1 sibling, 0 replies; 19+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-08-13 13:58 UTC (permalink / raw)
  To: Daniel Palmer
  Cc: Greg Kroah-Hartman, Hajime Tazaki, linux-mm, geert, Arnd Bergmann,
	Matthew Wilcox (Oracle), Jan Kara, Andrew Morton, Liam R. Howlett,
	Vlastimil Babka, Jann Horn, Pedro Falcato, linux-fsdevel

On Thu, Aug 13, 2026 at 10:51:39PM +0900, Daniel Palmer wrote:
> HI Lorenzo,
>
> On Thu, 13 Aug 2026 at 22:30, Lorenzo Stoakes (ARM) <ljs@kernel.org> wrote:
> > > One of the big problems for nommu seems to be that everyone is
> > > convinced it is completely unused and totally broken. :)
> >
> > No, the issue is that nobody seems to do any testing or contribute any code
> > aside from at least Hajime (thanks Haijme :), and possibly others (forgive me if
> > I am missing people's names here!)
>
> > There's been situtions where nommu has been broken for a year and _nobody
> > noticed_.
> >
> > And yet whenever nommu comes up people always seem to pop up and say how
> > important it is, then mention a talk etc.
>
> It also broke sometime around LPC 2025, I spotted it, reported it..
> and told the people in the room at LPC for the nommu talk that it was
> borken and maybe they should take a look. :)
> I think I maybe even told Tazaki-san in person that it was currently
> broken in the hall outside of the session.

OK this is what I like to hear :) please report it on-list.

If you do:

$ scripts/get_maintainer.pl mm/nommu.c

And send reports to all people/lists listed it'd be appreciated!

The grumpiness is not the usual mm reception, and certainly not that to bug
reports/patches.

>
> > Well if it's important, test it. Test the tip kernel. Report bugs. Contribute
> > code. Any or all of it :)
>
> I rebase my 68000 tree on mainline regularly and make sure it still
> works. That's how I noticed and reported the above bug.
> I have a bunch of stuff that claude fable found, validated with QEMU
> and then I checked on real hardware but I'm not sure how to send that
> without it getting instantly marked as slop. :(

If you check on real hardware and confirm the bug that's not slop that's a
legitimate bug!

I'd ask that you do a human pass over anything produced and rewrite any of the
insane paragraphs it comes up with and then check to make sure it's all valid
first.

And if you can come up with a patch (please human-written though using AI to
help is absolutely fine - I do the same) all the more better.

>
> Cheers,
>
> Daniel

--
Cheers, Lorenzo


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

* Re: [RFC PATCH 3/6] mm: nommu: fix an issue on map request to /dev/zero
  2026-08-13 12:43     ` Daniel Palmer
  2026-08-13 13:29       ` Lorenzo Stoakes (ARM)
@ 2026-08-13 14:02       ` Greg Kroah-Hartman
  2026-08-13 14:10         ` Lorenzo Stoakes (ARM)
  1 sibling, 1 reply; 19+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-13 14:02 UTC (permalink / raw)
  To: Daniel Palmer
  Cc: Hajime Tazaki, linux-mm, geert, Arnd Bergmann,
	Matthew Wilcox (Oracle), Jan Kara, Andrew Morton, Liam R. Howlett,
	Lorenzo Stoakes, Vlastimil Babka, Jann Horn, Pedro Falcato,
	linux-fsdevel

On Thu, Aug 13, 2026 at 09:43:37PM +0900, Daniel Palmer wrote:
> Hi Greg,
> 
> On Thu, 13 Aug 2026 at 21:26, Greg Kroah-Hartman
> <gregkh@linuxfoundation.org> wrote:
> 
> > Given the age of this issue, I don't think anyone uses no-mmu systems
> > anymore :(
> 
> There are a few of us using it for hobby stuff[0][1] and there are
> apparently people using it for actual commercial stuff.
> There was a session about this at LPC 2025...

This patch is fixing a very obvious issue that showed up in the 5.10
kernel, which was released in December 2020.

So I think the fact that no one has reported it before now means that no
one is actually using it :)

thanks,

greg k-h


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

* Re: [RFC PATCH 3/6] mm: nommu: fix an issue on map request to /dev/zero
  2026-08-13 13:22     ` Matthew Wilcox
  2026-08-13 13:32       ` Lorenzo Stoakes (ARM)
@ 2026-08-13 14:04       ` Greg Kroah-Hartman
  1 sibling, 0 replies; 19+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-13 14:04 UTC (permalink / raw)
  To: Matthew Wilcox
  Cc: Hajime Tazaki, linux-mm, geert, daniel, Arnd Bergmann, Jan Kara,
	Andrew Morton, Liam R. Howlett, Lorenzo Stoakes, Vlastimil Babka,
	Jann Horn, Pedro Falcato, linux-fsdevel

On Thu, Aug 13, 2026 at 02:22:03PM +0100, Matthew Wilcox wrote:
> On Thu, Aug 13, 2026 at 09:19:47PM +0900, Greg Kroah-Hartman wrote:
> > On Thu, Aug 13, 2026 at 03:33:58PM +0900, Hajime Tazaki wrote:
> > > Upon a private file mapping request to /dev/zero, it calls
> > > kernel_read() in do_mmap_private(), getting a failure with the message
> > > like: "kernel reads not supported for file /dev/zero", which is because
> > > zero_fops defined in drivers/char/mem.c has both .read and .read_iter
> > > definitions.
> > 
> > Do you actually use a no-mmu system?
> 
> If you look at Hajime's contributions, you'll see they're far from an AI
> slopper.
> 
> https://lore.kernel.org/linux-mm/?q=hajime+tazaki

That's not what I asked at all.

This patch is fixing /dev/zero which was broken in 2020 for these
systems.  I think my question was a legit one, I was not casting
aspersions about any slop here in any way.

> > > @@ -869,7 +886,11 @@ static vm_flags_t determine_vm_flags(struct file *file,
> > >  
> > >  	vm_flags = calc_vm_prot_bits(prot, 0) | calc_vm_flag_bits(file, flags);
> > >  
> > > -	if (!file) {
> > > +	/* private and file mapping will be marked anonymous later (do_mmap_private()).
> > > +	 * and /dev/zero is marked by them at .mmap_prepare,
> > > +	 * which should be _before_ this point.
> > > +	 */
> > 
> > Wrong coding style for the comment, which is very typical of
> > LLM-generated stuff.  Always rewrite the output of these tools to
> > actually be sane.
> 
> A lot of humans write comments like this too.  Indeed, it used to be
> the preferred style for net/

Yes, but it's not for anything outside of net/

thanks,

greg k-h


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

* Re: [RFC PATCH 3/6] mm: nommu: fix an issue on map request to /dev/zero
  2026-08-13 13:51         ` Daniel Palmer
  2026-08-13 13:58           ` Lorenzo Stoakes (ARM)
@ 2026-08-13 14:06           ` Greg Kroah-Hartman
  1 sibling, 0 replies; 19+ messages in thread
From: Greg Kroah-Hartman @ 2026-08-13 14:06 UTC (permalink / raw)
  To: Daniel Palmer
  Cc: Lorenzo Stoakes (ARM), Hajime Tazaki, linux-mm, geert,
	Arnd Bergmann, Matthew Wilcox (Oracle), Jan Kara, Andrew Morton,
	Liam R. Howlett, Vlastimil Babka, Jann Horn, Pedro Falcato,
	linux-fsdevel

On Thu, Aug 13, 2026 at 10:51:39PM +0900, Daniel Palmer wrote:
> HI Lorenzo,
> 
> On Thu, 13 Aug 2026 at 22:30, Lorenzo Stoakes (ARM) <ljs@kernel.org> wrote:
> > > One of the big problems for nommu seems to be that everyone is
> > > convinced it is completely unused and totally broken. :)
> >
> > No, the issue is that nobody seems to do any testing or contribute any code
> > aside from at least Hajime (thanks Haijme :), and possibly others (forgive me if
> > I am missing people's names here!)
> 
> > There's been situtions where nommu has been broken for a year and _nobody
> > noticed_.
> >
> > And yet whenever nommu comes up people always seem to pop up and say how
> > important it is, then mention a talk etc.
> 
> It also broke sometime around LPC 2025, I spotted it, reported it..
> and told the people in the room at LPC for the nommu talk that it was
> borken and maybe they should take a look. :)
> I think I maybe even told Tazaki-san in person that it was currently
> broken in the hall outside of the session.
> 
> > Well if it's important, test it. Test the tip kernel. Report bugs. Contribute
> > code. Any or all of it :)
> 
> I rebase my 68000 tree on mainline regularly and make sure it still
> works. That's how I noticed and reported the above bug.
> I have a bunch of stuff that claude fable found, validated with QEMU
> and then I checked on real hardware but I'm not sure how to send that
> without it getting instantly marked as slop. :(

I didn't say anything about slop here, and in fact, _I_ have fixed up an
io_uring nommu bug in the past, using LLM tooling.  I am not objecting
to the use of that tool here at all, I am only commenting on the fact
that this bug has been present since 2020 without anyone noticing before
now, which implies a severe lack of users.

Heck, the out-of-tree ia64 developers report things faster than this :)

thanks,

greg k-h


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

* Re: [RFC PATCH 3/6] mm: nommu: fix an issue on map request to /dev/zero
  2026-08-13 14:02       ` Greg Kroah-Hartman
@ 2026-08-13 14:10         ` Lorenzo Stoakes (ARM)
  0 siblings, 0 replies; 19+ messages in thread
From: Lorenzo Stoakes (ARM) @ 2026-08-13 14:10 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Daniel Palmer, Hajime Tazaki, linux-mm, geert, Arnd Bergmann,
	Matthew Wilcox (Oracle), Jan Kara, Andrew Morton, Liam R. Howlett,
	Vlastimil Babka, Jann Horn, Pedro Falcato, linux-fsdevel,
	Christoph Hellwig

+cc Christoph

On Thu, Aug 13, 2026 at 11:02:18PM +0900, Greg Kroah-Hartman wrote:
> On Thu, Aug 13, 2026 at 09:43:37PM +0900, Daniel Palmer wrote:
> > Hi Greg,
> >
> > On Thu, 13 Aug 2026 at 21:26, Greg Kroah-Hartman
> > <gregkh@linuxfoundation.org> wrote:
> >
> > > Given the age of this issue, I don't think anyone uses no-mmu systems
> > > anymore :(
> >
> > There are a few of us using it for hobby stuff[0][1] and there are
> > apparently people using it for actual commercial stuff.
> > There was a session about this at LPC 2025...
>
> This patch is fixing a very obvious issue that showed up in the 5.10
> kernel, which was released in December 2020.
>
> So I think the fact that no one has reported it before now means that no
> one is actually using it :)

Maybe Christoph has a view on this?

I brought this up a couple years ago and he claimed there are commerical
products which use the latest long-term stable kernel (6.18 at the time of
writing).

See https://lore.kernel.org/linux-mm/20241122123833.GA26432@lst.de/

Christoph - can you explain why none of these vendors encountered any of these
bugs or breakages?

If they are doing fixes that are downstream only, then that argues against
upstream nommu.

If they are not, in fact, using long term stable kernels, that argues against
upstream nommu.

The fact they seem to be assigning zero resource to upstream also argues against
upstream nommu.

nommu continues to be a ongoing burden for core mm that interferes with work on
real architectures on a fairly regularly basis, which argues against upstream
nommu.

I'm curious to learn what the arguments _for_ upstream nommu are?

>
> thanks,
>
> greg k-h

--
Cheers, Lorenzo


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

end of thread, other threads:[~2026-08-13 14:11 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-13  6:33 [RFC PATCH 0/6] fix nommu mmap and add nommu kselftests Hajime Tazaki
2026-08-13  6:33 ` [RFC PATCH 1/6] mm: nommu: fix do_mremap() to correctly update internal states Hajime Tazaki
2026-08-13  6:33 ` [RFC PATCH 2/6] mm: nommu: use vma_is_anonymous() to check if vmas are anonymous Hajime Tazaki
2026-08-13  6:33 ` [RFC PATCH 3/6] mm: nommu: fix an issue on map request to /dev/zero Hajime Tazaki
2026-08-13 12:19   ` Greg Kroah-Hartman
2026-08-13 12:43     ` Daniel Palmer
2026-08-13 13:29       ` Lorenzo Stoakes (ARM)
2026-08-13 13:51         ` Daniel Palmer
2026-08-13 13:58           ` Lorenzo Stoakes (ARM)
2026-08-13 14:06           ` Greg Kroah-Hartman
2026-08-13 14:02       ` Greg Kroah-Hartman
2026-08-13 14:10         ` Lorenzo Stoakes (ARM)
2026-08-13 13:22     ` Matthew Wilcox
2026-08-13 13:32       ` Lorenzo Stoakes (ARM)
2026-08-13 13:43         ` Lorenzo Stoakes (ARM)
2026-08-13 14:04       ` Greg Kroah-Hartman
2026-08-13  6:33 ` [RFC PATCH 4/6] selftests: fix build errors on alpine linux Hajime Tazaki
2026-08-13  6:34 ` [RFC PATCH 5/6] selftests: run tests on nommu architecture Hajime Tazaki
2026-08-13  6:34 ` [RFC PATCH 6/6] selftests/mm: add nommu mmap and mremap behavior tests Hajime Tazaki

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