From: Hajime Tazaki <thehajime@gmail.com>
To: linux-mm@kvack.org
Cc: geert@linux-m68k.org, daniel@thingy.jp,
Hajime Tazaki <thehajime@gmail.com>,
Arnd Bergmann <arnd@arndb.de>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
"Matthew Wilcox (Oracle)" <willy@infradead.org>,
Jan Kara <jack@suse.cz>,
Andrew Morton <akpm@linux-foundation.org>,
"Liam R. Howlett" <liam@infradead.org>,
Lorenzo Stoakes <ljs@kernel.org>,
Vlastimil Babka <vbabka@kernel.org>, Jann Horn <jannh@google.com>,
Pedro Falcato <pfalcato@suse.de>,
linux-fsdevel@vger.kernel.org
Subject: [RFC PATCH 3/6] mm: nommu: fix an issue on map request to /dev/zero
Date: Thu, 13 Aug 2026 15:33:58 +0900 [thread overview]
Message-ID: <20260813063401.1786548-4-thehajime@gmail.com> (raw)
In-Reply-To: <20260813063401.1786548-1-thehajime@gmail.com>
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
next prev parent reply other threads:[~2026-08-13 6:34 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
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 [this message]
2026-08-13 12:19 ` [RFC PATCH 3/6] mm: nommu: fix an issue on map request to /dev/zero 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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260813063401.1786548-4-thehajime@gmail.com \
--to=thehajime@gmail.com \
--cc=akpm@linux-foundation.org \
--cc=arnd@arndb.de \
--cc=daniel@thingy.jp \
--cc=geert@linux-m68k.org \
--cc=gregkh@linuxfoundation.org \
--cc=jack@suse.cz \
--cc=jannh@google.com \
--cc=liam@infradead.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=ljs@kernel.org \
--cc=pfalcato@suse.de \
--cc=vbabka@kernel.org \
--cc=willy@infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.