Re: [PATCH] ramfs: nommu: fix error rollback and reader races in ramfs_nommu_expand_for_mapping()

From: Hajime Tazaki

Date: Mon Jul 13 2026 - 15:51:56 EST



Hello Daniel,

thanks for cc-ing me for the patch.

On Mon, 13 Jul 2026 13:57:00 +0200,
Daniel Palmer wrote:
>
> ramfs_nommu_expand_for_mapping() sets the new i_size before it has
> allocated or inserted any of the contiguous backing pages.
>
> If alloc_pages() or add_to_page_cache_lru() fails, the inode is left
> with an inflated i_size and possibly a partial run of pages. As
> ramfs_nommu_setattr() treats a truncate to the current i_size as a
> no-op, the expansion cannot be retried and shared mmap() of the file
> fails with -ENOSYS.
>
> Setting i_size early also races with lockless readers: buffered reads
> and splice do not take i_rwsem, so once the new size is visible a
> concurrent read can instantiate a zero-filled folio, making the
> expansion's add_to_page_cache_lru() fail with -EEXIST.
>
> Fix this by taking mapping->invalidate_lock around the insertion,
> evicting any stray folios first, and only publishing i_size once
> every page is in place.
>
> On failure, after freeing the pages that were allocated but
> not inserted truncate the mapping back to empty so already inserted
> pages are also disposed of.
>
> Fixes: 642fb4d1f1dd ("[PATCH] NOMMU: Provide shared-writable mmap support on ramfs")
> Reported-by: Sashiko <sashiko-bot@xxxxxxxxxx>
> Closes: https://sashiko.dev/#/message/20260523130445.1101818-1-daniel%40thingy.jp
> Assisted-by: Claude:claude-5-fable # expanded my fix to address the reader race etc.
> Signed-off-by: Daniel Palmer <daniel@xxxxxxxxx>
> ---

I have tested this patch in addition to your previous patch
(20260523130445.1101818-1-daniel@xxxxxxxxx) over LTP test with my
local nommu-revert patchset.

I run the following test (which I have never looked at thus doesn't
have much knowledge about the test itself).

https://github.com/linux-test-project/ltp/blob/master/testcases/kernel/syscalls/memfd_create/memfd_create01.c

without first patch, it indeed returns EFBIG on memfe_createfd()
syscall. applying both patches with this test gives me still failure
with the following messages:

```
/__w/linux/linux/lib/tst_test.c:2060: TINFO: LTP version: 20260529
/__w/linux/linux/lib/tst_test.c:2063: TINFO: Tested kernel: 7.1.0-rc1-gfd4e5701bb02-dirty #1 Mon Jul 13 18:17:11 UTC 2026 um(nommu)/x86_64
/__w/linux/linux/lib/tst_kconfig.c:90: TINFO: Parsing kernel config &#x27;/proc/config.gz&#x27;
/__w/linux/linux/lib/tst_test.c:1880: TINFO: Overall timeout per run is 0h 05m 24s
/__w/linux/linux/testcases/kernel/syscalls/memfd_create/memfd_create01.c:241: TINFO: Basic tests + set/get seals
/__w/linux/linux/testcases/kernel/syscalls/memfd_create/memfd_create01.c:243: TPASS: memfd_create(ltp_memfd_create01, 2) succeeded
/__w/linux/linux/testcases/kernel/syscalls/memfd_create/memfd_create01.c:243: TPASS: ftruncate(3, 8192) succeeded
/__w/linux/linux/testcases/kernel/syscalls/memfd_create/memfd_create_common.c:212: TBROK: fcntl(3,F_GET_SEALS,...) failed: EINVAL (22)

Summary:
passed 2
failed 0
broken 1
skipped 0
warnings 0
```

which fails at the location below (in memfd_create_common.c#L207)

int ret = SAFE_FCNTL((fd), F_GET_SEALS);

so fcntl(fd, F_GET_SEALS) always fails with nommu due to lack of
support of CONFIG_SHMEM and CONFIG_HUGETLBFS.


``` mm/memfd.c (in kernel)
static unsigned int *memfd_file_seals_ptr(struct file *file)
{
if (shmem_file(file))
return &SHMEM_I(file_inode(file))->seals;

#ifdef CONFIG_HUGETLBFS
if (is_file_hugepages(file))
return &HUGETLBFS_I(file_inode(file))->seals;
#endif

return NULL;
}
```

so I was wondering if it is still interesting to support the syscall
(memfd_createfd) on nommu even the fcntl always fails.

My test is used on riscv-nommu (buildroot) and UML + !MMU, which gives
me the same results.

-- Hajime