Skip to contentSkip to conversation

tmpfs/ramfs: Let memfd_create() work on nommu

PATCH Applied Daniel Palmer 3 participants 4 messages May 23 – Jul 8

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 tmpfs/ramfs: Let memfd_create() work on nommu

Currently trying to use memfd_create() on nommu returns an error with errno set to EFBIG. The manpage memfd_create() doesn't have EFBIG as a possible error value.

Doing some digging this is coming from 0 getting passed as newsize to ramfs_nommu_expand_for_mapping() and that getting into get_order() and there "The result is undefined if the size is 0".

Whatever comes out of get_order() is then used in the following logic and that results in the EFBIG that causes the syscall to fail and the errno in userspace.

If newsize is 0 there is nothing to do so just return.

Roughly tested on m68k nommu by creating a process, creating an memfd, forking another process, mmap()ing the memfd in the child, writing into the mapping, then mmap()ing in the parent and checking that the right data is there.

---

Really not sure if this is correct. It works for me but on nommu a lot of things just work because there is no MMU to shout about badness.

Maybe shashiko will say this is a dumb patch and explain the proper fix. :)

Also I had almost no idea who to send this to from the output of get_maintainer.pl.

 fs/ramfs/file-nommu.c | 3 +++
 1 file changed, 3 insertions(+)
fs/ramfs/file-nommu.c +3 -0
index 2f79bcb89d2e..fb471bf88ab7 100644
@@ -69,6 +69,9 @@ int ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize)
 	gfp_t gfp = mapping_gfp_mask(inode->i_mapping);
 
 	/* make various checks */
+	if (!newsize)
+		return 0;
+
 	order = get_order(newsize);
 	if (unlikely(order > MAX_PAGE_ORDER))
 		return -EFBIG;
Signature · 1 line
2.53.0
Acked-by on v1 1/1
#1 lore raw

+cc Liam

Quoted 12 lines · Daniel Palmer

Currently trying to use memfd_create() on nommu returns an error with errno set to EFBIG. The manpage memfd_create() doesn't have EFBIG as a possible error value.

Doing some digging this is coming from 0 getting passed as newsize to ramfs_nommu_expand_for_mapping() and that getting into get_order() and there "The result is undefined if the size is 0".

Whatever comes out of get_order() is then used in the following logic and that results in the EFBIG that causes the syscall to fail and the errno in userspace.

Quoted 8 lines

If newsize is 0 there is nothing to do so just return.

Roughly tested on m68k nommu by creating a process, creating an memfd, forking another process, mmap()ing the memfd in the child, writing into the mapping, then mmap()ing in the parent and checking that the right data is there.

I don't really have the setup to check it, but I don't see a problem with this so:

Quoted 5 lines

---

Really not sure if this is correct. It works for me but on nommu a lot of things just work because there is no MMU to shout about badness.

:)

Quoted 3 lines

Maybe shashiko will say this is a dumb patch and explain the proper fix. :)

No see below I think this is correct.

Quoted 3 lines

Also I had almost no idea who to send this to from the output of get_maintainer.pl.

Yeah this file doesn't really belong anywhere... the mm bits of nommu are (ostensibly :P) maintained by me and Liam though.

Quoted 9 lines
 fs/ramfs/file-nommu.c | 3 +++
 1 file changed, 3 insertions(+)
fs/ramfs/file-nommu.c +0 -0
index 2f79bcb89d2e..fb471bf88ab7 100644

fs/ramfs/file-nommu.c int ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize) · line 74

Quoted 6 lines
fs/ramfs/file-nommu.c +3 -0
@@ -69,6 +69,9 @@ int ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize)
 	gfp_t gfp = mapping_gfp_mask(inode->i_mapping);
 
 	/* make various checks */
+	if (!newsize)
+		return 0;
+

Hmm yeah get_order() literally says the result is undefined if you input 0, and it bizarrely returns BITS_PER_LONG - PAGE_SHIFT in that case.

So this isn't correctly handling 0 size at all.

Also in the case of a mmu, this function collapses to a stub that just returns 0 and the rest of __shmem_file_setup() runs fine if size == 0.

So yeah this is probably right!

Quoted 8 lines
fs/ramfs/file-nommu.c +0 -1
 	order = get_order(newsize);
 	if (unlikely(order > MAX_PAGE_ORDER))
 		return -EFBIG;
--

2.53.0

Cheers, Lorenzo

maintainer
#2 lore raw
In reply to Daniel Palmer
Quoted 12 lines · On Sat, 23 May 2026 22:04:45 +0900 Daniel Palmer <[email protected]> wrote:

Currently trying to use memfd_create() on nommu returns an error with errno set to EFBIG. The manpage memfd_create() doesn't have EFBIG as a possible error value.

Doing some digging this is coming from 0 getting passed as newsize to ramfs_nommu_expand_for_mapping() and that getting into get_order() and there "The result is undefined if the size is 0".

Whatever comes out of get_order() is then used in the following logic and that results in the EFBIG that causes the syscall to fail and the errno in userspace.

Quoted 7 lines

If newsize is 0 there is nothing to do so just return.

Roughly tested on m68k nommu by creating a process, creating an memfd, forking another process, mmap()ing the memfd in the child, writing into the mapping, then mmap()ing in the parent and checking that the right data is there.

Old patch, older code. Thanks.

Quoted 6 lines

Really not sure if this is correct. It works for me but on nommu a lot of things just work because there is no MMU to shout about badness.

Maybe shashiko will say this is a dumb patch and explain the proper fix. :)

Sashiko had no complaints but it seems to have found some unrelated bugs:

	https://sashiko.dev/#/patchset/[email protected]

(tmpfs calls "ramfs_nommu" code. Who knew?)

Quoted 2 lines

Also I had almost no idea who to send this to from the output of get_maintainer.pl.

I suspect most would prefer it's someone else, but this is viro/brauner stuff, if anyone)

fs/ramfs/file-nommu.c int ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize) · line 77

Quoted 12 lines
fs/ramfs/file-nommu.c +3 -0
@@ -69,6 +69,9 @@ int ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize)
 	gfp_t gfp = mapping_gfp_mask(inode->i_mapping);
 
 	/* make various checks */
+	if (!newsize)
+		return 0;
+
 	order = get_order(newsize);
 	if (unlikely(order > MAX_PAGE_ORDER))
 		return -EFBIG;

Oh well, thanks, I'll toss it onto the pile and see what happens.

#3 lore raw

Hi Andrew,

Quoted 4 lines · Andrew Morton

Sashiko had no complaints but it seems to have found some unrelated bugs:

        https://sashiko.dev/#/patchset/[email protected]

I took a look at this, made my own fix, fed it to fable check/clean it up and it seems to think after its fixes the sashiko reported issues will be corrected.
I asked fable if it thought there was anything else major in the same file and there are a few minor things but apparently the bugs sashiko reported are the major issues.

Once I've tested it a bit more I'll send it.

Thanks,

Daniel