* [PATCH v2 0/2] nolibc: Add fallocate()
@ 2026-04-17 11:26 Daniel Palmer
2026-04-17 11:26 ` [PATCH v2 1/2] tools/nolibc: fcntl: " Daniel Palmer
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Daniel Palmer @ 2026-04-17 11:26 UTC (permalink / raw)
To: w, linux; +Cc: linux-kernel, Daniel Palmer
While poking around with my "static PIE for nommu" series I found
I needed fallocate(). Implementing it turned out a bit more
interesting than I thought it would be due to how the offset and
size need to be passed on 32bit machines.
I have ran the tests on m68k, arm, arm64, riscv[32|64], x86_64,
i386, x32 (v2: + lots of mips, ppc..) . I probably missed something,
maybe there is a better way to do this. Maybe it can't actually
pass an offset or size >4GB on x32? (v2: I think this is good now)
v2:
- Addressed Thomas' comments
- Trial and error'd a test for the arguments being passed correctly.
Hopefully someone smarter than I am can tell if it actually works.
Daniel Palmer (2):
tools/nolibc: fcntl: Add fallocate()
selftests/nolibc: Add a very basic test for fallocate()
tools/include/nolibc/arch-mips.h | 11 ++++
tools/include/nolibc/fcntl.h | 32 +++++++++++
tools/include/nolibc/sys.h | 8 +++
tools/testing/selftests/nolibc/nolibc-test.c | 58 ++++++++++++++++++++
4 files changed, 109 insertions(+)
--
2.51.0
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v2 1/2] tools/nolibc: fcntl: Add fallocate()
2026-04-17 11:26 [PATCH v2 0/2] nolibc: Add fallocate() Daniel Palmer
@ 2026-04-17 11:26 ` Daniel Palmer
2026-04-17 11:26 ` [PATCH v2 2/2] selftests/nolibc: Add a very basic test for fallocate() Daniel Palmer
2026-04-27 20:01 ` [PATCH v2 0/2] nolibc: Add fallocate() Thomas Weißschuh
2 siblings, 0 replies; 4+ messages in thread
From: Daniel Palmer @ 2026-04-17 11:26 UTC (permalink / raw)
To: w, linux; +Cc: linux-kernel, Daniel Palmer
Add fallocate(). Some special care is needed to put the
offset and size into the syscall parameters for 32bit
machines, x32, and mipsn32.
For x32 we can just check if the kernel long size is the
same as off_t and use the same path as x86_64.
For mipsn32 we override the generic version and provide
one that does the right thing.
Signed-off-by: Daniel Palmer <daniel@thingy.jp>
---
tools/include/nolibc/arch-mips.h | 11 +++++++++++
tools/include/nolibc/fcntl.h | 32 ++++++++++++++++++++++++++++++++
tools/include/nolibc/sys.h | 8 ++++++++
3 files changed, 51 insertions(+)
diff --git a/tools/include/nolibc/arch-mips.h b/tools/include/nolibc/arch-mips.h
index bb9d580ea1b1..2c5cda632911 100644
--- a/tools/include/nolibc/arch-mips.h
+++ b/tools/include/nolibc/arch-mips.h
@@ -6,6 +6,7 @@
#ifndef _NOLIBC_ARCH_MIPS_H
#define _NOLIBC_ARCH_MIPS_H
+#include <linux/unistd.h>
#include "compiler.h"
#include "crt.h"
@@ -252,6 +253,16 @@
_arg4 ? -_num : _num; \
})
+/* The generic version of this will split offset and size for _ABIN32,
+ * override it and do the right thing here.
+ */
+static __attribute__((unused))
+int _sys_fallocate(int fd, int mode, off_t offset, off_t size)
+{
+ return __nolibc_syscall4(__NR_fallocate, fd, mode, offset, size);
+}
+#define _sys_fallocate _sys_fallocate
+
#endif /* _ABIO32 */
#ifndef NOLIBC_NO_RUNTIME
diff --git a/tools/include/nolibc/fcntl.h b/tools/include/nolibc/fcntl.h
index ed2f5553c65a..e65be2f84cbd 100644
--- a/tools/include/nolibc/fcntl.h
+++ b/tools/include/nolibc/fcntl.h
@@ -14,6 +14,9 @@
#include "types.h"
#include "sys.h"
+/* For fallocate() modes */
+#include <linux/falloc.h>
+
/*
* int openat(int dirfd, const char *path, int flags[, mode_t mode]);
*/
@@ -66,4 +69,33 @@ int open(const char *path, int flags, ...)
return __sysret(_sys_open(path, flags, mode));
}
+/*
+ * int fallocate(int fd, int mode, off_t offset, off_t size);
+ */
+
+#if !defined(_sys_fallocate)
+static __attribute__((unused))
+int _sys_fallocate(int fd, int mode, off_t offset, off_t size)
+{
+ /*
+ * For 32 bit machines __kernel_long_t will be 4, off_t will be 8
+ * and we need to split it for 64 machines we can use the values as-is
+ */
+ const bool offsetsz_two_args = sizeof(__kernel_long_t) != sizeof(off_t);
+
+ if (offsetsz_two_args)
+ return __nolibc_syscall6(__NR_fallocate, fd, mode,
+ __NOLIBC_LLARGPART(offset, 0), __NOLIBC_LLARGPART(offset, 1),
+ __NOLIBC_LLARGPART(size, 0), __NOLIBC_LLARGPART(size, 1));
+ else
+ return __nolibc_syscall4(__NR_fallocate, fd, mode, offset, size);
+}
+#endif
+
+static __attribute__((unused))
+int fallocate(int fd, int mode, off_t offset, off_t size)
+{
+ return __sysret(_sys_fallocate(fd, mode, offset, size));
+}
+
#endif /* _NOLIBC_FCNTL_H */
diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h
index 6335fd51f07f..4f4491af9426 100644
--- a/tools/include/nolibc/sys.h
+++ b/tools/include/nolibc/sys.h
@@ -29,6 +29,14 @@
#include "stdarg.h"
#include "types.h"
+/*
+ * Helper for 32bit machines where a 64bit syscall arg needs to be split into
+ * two 32bit parts while making sure the order of the low/high parts are correct
+ * for the endian:
+ * __NOLIBC_LLARGPART(x, 0), __NOLIBC_LLARGPART(x, 1)
+ */
+#define __NOLIBC_LLARGPART(_arg, _part) \
+ (((union { long long ll; long l[2]; }) { .ll = _arg }).l[_part])
/* Syscall return helper: takes the syscall value in argument and checks for an
* error in it. This may only be used with signed returns (int or long), but
--
2.51.0
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v2 2/2] selftests/nolibc: Add a very basic test for fallocate()
2026-04-17 11:26 [PATCH v2 0/2] nolibc: Add fallocate() Daniel Palmer
2026-04-17 11:26 ` [PATCH v2 1/2] tools/nolibc: fcntl: " Daniel Palmer
@ 2026-04-17 11:26 ` Daniel Palmer
2026-04-27 20:01 ` [PATCH v2 0/2] nolibc: Add fallocate() Thomas Weißschuh
2 siblings, 0 replies; 4+ messages in thread
From: Daniel Palmer @ 2026-04-17 11:26 UTC (permalink / raw)
To: w, linux; +Cc: linux-kernel, Daniel Palmer
1: Create a tmp file, fallocate() to make it a bit bigger, check the
size is what was expected.
2: Try to fallocate() (1 << 28),
3: Try to fallocate() (1 << 60), this causes a EFBIG
Signed-off-by: Daniel Palmer <daniel@thingy.jp>
---
tools/testing/selftests/nolibc/nolibc-test.c | 58 ++++++++++++++++++++
1 file changed, 58 insertions(+)
diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c
index d3c4facb54c0..6dcc2f631c3e 100644
--- a/tools/testing/selftests/nolibc/nolibc-test.c
+++ b/tools/testing/selftests/nolibc/nolibc-test.c
@@ -896,6 +896,63 @@ int test_getpagesize(void)
return !c;
}
+int test_fallocate(void)
+{
+ struct stat st;
+ int fd, r;
+
+ /* Create a new tmp file */
+ fd = open("/tmp", O_TMPFILE | O_RDWR, 0644);
+ if (fd == -1)
+ return -1;
+
+ /* Expand it to 42 bytes */
+ r = fallocate(fd, 0, 0, 42);
+ if (r)
+ goto close_tmpfile;
+
+ /* Get the new stat */
+ r = fstat(fd, &st);
+ if (r)
+ goto close_tmpfile;
+
+ /* It should be 42 bytes long */
+ if (st.st_size != 42) {
+ r = -1;
+ goto close_tmpfile;
+ }
+
+ /* Now try to allocate 256MiB, this shouldn't fail
+ */
+ r = fallocate(fd, 0, 0, (1ll << 28));
+ if (r)
+ goto close_tmpfile;
+
+ /* Check that a massive size that happens to be the
+ * opposite endian version of the above. This should
+ * returns an error and errno = EFBIG indicating the
+ * value was passed correctly but the kernel rejected
+ * it.
+ */
+ r = fallocate(fd, 0, 0, (1ll << (28 + 32)));
+ if (r != -1) {
+ r = -1;
+ goto close_tmpfile;
+ }
+ if (errno != EFBIG) {
+ r = -1;
+ goto close_tmpfile;
+ }
+
+ /* Test passed */
+ r = 0;
+
+close_tmpfile:
+ close(fd);
+
+ return r;
+}
+
int test_file_stream(void)
{
FILE *f;
@@ -1442,6 +1499,7 @@ int run_syscall(int min, int max)
CASE_TEST(dup3_0); tmp = dup3(0, 100, 0); EXPECT_SYSNE(1, tmp, -1); close(tmp); break;
CASE_TEST(dup3_m1); tmp = dup3(-1, 100, 0); EXPECT_SYSER(1, tmp, -1, EBADF); if (tmp != -1) close(tmp); break;
CASE_TEST(execve_root); EXPECT_SYSER(1, execve("/", (char*[]){ [0] = "/", [1] = NULL }, NULL), -1, EACCES); break;
+ CASE_TEST(fallocate); EXPECT_SYSZR(1, test_fallocate()); break;
CASE_TEST(fchdir_stdin); EXPECT_SYSER(1, fchdir(STDIN_FILENO), -1, ENOTDIR); break;
CASE_TEST(fchdir_badfd); EXPECT_SYSER(1, fchdir(-1), -1, EBADF); break;
CASE_TEST(file_stream); EXPECT_SYSZR(1, test_file_stream()); break;
--
2.51.0
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH v2 0/2] nolibc: Add fallocate()
2026-04-17 11:26 [PATCH v2 0/2] nolibc: Add fallocate() Daniel Palmer
2026-04-17 11:26 ` [PATCH v2 1/2] tools/nolibc: fcntl: " Daniel Palmer
2026-04-17 11:26 ` [PATCH v2 2/2] selftests/nolibc: Add a very basic test for fallocate() Daniel Palmer
@ 2026-04-27 20:01 ` Thomas Weißschuh
2 siblings, 0 replies; 4+ messages in thread
From: Thomas Weißschuh @ 2026-04-27 20:01 UTC (permalink / raw)
To: Daniel Palmer; +Cc: w, linux-kernel
Hi Daniel,
On 2026-04-17 20:26:20+0900, Daniel Palmer wrote:
> While poking around with my "static PIE for nommu" series I found
> I needed fallocate(). Implementing it turned out a bit more
> interesting than I thought it would be due to how the offset and
> size need to be passed on 32bit machines.
>
> I have ran the tests on m68k, arm, arm64, riscv[32|64], x86_64,
> i386, x32 (v2: + lots of mips, ppc..) . I probably missed something,
> maybe there is a better way to do this. Maybe it can't actually
> pass an offset or size >4GB on x32? (v2: I think this is good now)
>
> v2:
> - Addressed Thomas' comments
> - Trial and error'd a test for the arguments being passed correctly.
> Hopefully someone smarter than I am can tell if it actually works.
>
> Daniel Palmer (2):
> tools/nolibc: fcntl: Add fallocate()
> selftests/nolibc: Add a very basic test for fallocate()
Could you rebase the series on latest nolibc/for-next?
Now that the large file support has landed this should make more sense.
> tools/include/nolibc/arch-mips.h | 11 ++++
> tools/include/nolibc/fcntl.h | 32 +++++++++++
> tools/include/nolibc/sys.h | 8 +++
> tools/testing/selftests/nolibc/nolibc-test.c | 58 ++++++++++++++++++++
> 4 files changed, 109 insertions(+)
>
> --
> 2.51.0
>
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-04-27 20:02 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-04-17 11:26 [PATCH v2 0/2] nolibc: Add fallocate() Daniel Palmer
2026-04-17 11:26 ` [PATCH v2 1/2] tools/nolibc: fcntl: " Daniel Palmer
2026-04-17 11:26 ` [PATCH v2 2/2] selftests/nolibc: Add a very basic test for fallocate() Daniel Palmer
2026-04-27 20:01 ` [PATCH v2 0/2] nolibc: Add fallocate() Thomas Weißschuh
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Powered by JetHome