From: "Thomas Weißschuh" <linux@weissschuh.net>
To: Jordan Richards <jordanrichards@google.com>
Cc: Pasha Tatashin <pasha.tatashin@soleen.com>,
Mike Rapoport <rppt@kernel.org>,
Pratyush Yadav <pratyush@kernel.org>,
Shuah Khan <shuah@kernel.org>, Willy Tarreau <w@1wt.eu>,
Jason Miu <jasonmiu@google.com>,
David Matlack <dmatlack@google.com>,
linux-mm@kvack.org, linux-kernel@vger.kernel.org,
linux-kselftest@vger.kernel.org
Subject: Re: [PATCH v3 1/2] tools/nolibc: add ftruncate()
Date: Tue, 3 Mar 2026 08:09:33 +0100 [thread overview]
Message-ID: <c65fdf06-2f69-4c81-be21-a14229eaf1b6@t-8ch.de> (raw)
In-Reply-To: <20260303010039.2969125-2-jordanrichards@google.com>
Hi Jordan,
On 2026-03-03 01:00:38+0000, Jordan Richards wrote:
> On architectures with 32-bit longs, call the compat syscall
> __NR_ftruncate64. As off_t is 64-bit it must be split into 2 registers.
> Unlike llseek() which passes the high and low parts in explicitly named
> arguments, the order here is endian independent.
>
> Some architectures (arm, mips, ppc) require this pair of registers to
> be aligned to an even register, so add custom sys_ftruncate64 wrappers
> for those.
>
> A test case for ftruncate is added which validates negative length or
> invalid fd return the appropriate error, and checks the length is
> correct on success.
Thanks, this all looks good in general.
In nolibc-next we renamed all the my_syscall*() functions to
__nolibc_syscall*(), merging this patch through the liveupdate tree
will lead to semantic conflicts.
I see different ways to handle this:
* An an immutable branch to merge into the liveupdate tree
* Split up the series
* Use raw syscall(__NR_ftruncate) in the liveupdate
selftests, as it is sufficient for that.
* Merge the nolibc bits through the nolibc tree.
* Next cycle, switch to proper nolibc ftruncate().
* Let Linus handle the conflict when merging the tree.
There are some nitpicks inline, but we can also fix those up when
applying the patch.
> Signed-off-by: Jordan Richards <jordanrichards@google.com>
> ---
> tools/include/nolibc/arch-arm.h | 11 +++++
> tools/include/nolibc/arch-mips.h | 11 +++++
> tools/include/nolibc/arch-powerpc.h | 11 +++++
> tools/include/nolibc/unistd.h | 35 ++++++++++++++
> tools/testing/selftests/nolibc/nolibc-test.c | 51 ++++++++++++++++++++
> 5 files changed, 119 insertions(+)
>
> diff --git a/tools/include/nolibc/arch-arm.h b/tools/include/nolibc/arch-arm.h
> index 251c42579028..ed65fb674e61 100644
> --- a/tools/include/nolibc/arch-arm.h
> +++ b/tools/include/nolibc/arch-arm.h
> @@ -6,9 +6,11 @@
>
> #ifndef _NOLIBC_ARCH_ARM_H
> #define _NOLIBC_ARCH_ARM_H
Nit: keep an empty line after the include guards.
> +#include <linux/unistd.h>
> #include "compiler.h"
> #include "crt.h"
> +#include "std.h"
>
> /* Syscalls for ARM in ARM or Thumb modes :
> * - registers are 32-bit
> @@ -196,4 +198,13 @@ void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _s
> }
> #endif /* NOLIBC_NO_RUNTIME */
>
> +#ifdef __NR_ftruncate64
Should be unnecessary.
> +static __attribute__((unused))
> +int sys_ftruncate64(int fd, uint32_t length0, uint32_t length1)
> +{
> + return my_syscall4(__NR_ftruncate64, fd, 0, length0, length1);
> +}
> +#define sys_ftruncate64 sys_ftruncate64
> +#endif
> +
> #endif /* _NOLIBC_ARCH_ARM_H */
> diff --git a/tools/include/nolibc/arch-mips.h b/tools/include/nolibc/arch-mips.h
> index a72506ceec6b..26d044004ec6 100644
> --- a/tools/include/nolibc/arch-mips.h
> +++ b/tools/include/nolibc/arch-mips.h
> @@ -6,9 +6,11 @@
>
> #ifndef _NOLIBC_ARCH_MIPS_H
> #define _NOLIBC_ARCH_MIPS_H
Also an empty line.
> +#include <linux/unistd.h>
> #include "compiler.h"
> #include "crt.h"
> +#include "std.h"
>
> #if !defined(_ABIO32) && !defined(_ABIN32) && !defined(_ABI64)
> #error Unsupported MIPS ABI
> @@ -269,4 +271,13 @@ void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector __
> }
> #endif /* NOLIBC_NO_RUNTIME */
>
> +#ifdef __NR_ftruncate64
> +static __attribute__((unused))
> +int sys_ftruncate64(int fd, uint32_t length0, uint32_t length1)
> +{
> + return my_syscall4(__NR_ftruncate64, fd, 0, length0, length1);
> +}
> +#define sys_ftruncate64 sys_ftruncate64
> +#endif
> +
> #endif /* _NOLIBC_ARCH_MIPS_H */
> diff --git a/tools/include/nolibc/arch-powerpc.h b/tools/include/nolibc/arch-powerpc.h
> index e0c7e0b81f7c..71829cb027e8 100644
> --- a/tools/include/nolibc/arch-powerpc.h
> +++ b/tools/include/nolibc/arch-powerpc.h
> @@ -6,9 +6,11 @@
>
> #ifndef _NOLIBC_ARCH_POWERPC_H
> #define _NOLIBC_ARCH_POWERPC_H
> +#include <linux/unistd.h>
>
> #include "compiler.h"
> #include "crt.h"
> +#include "std.h"
>
> /* Syscalls for PowerPC :
> * - stack is 16-byte aligned
> @@ -218,4 +220,13 @@ void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _s
> }
> #endif /* NOLIBC_NO_RUNTIME */
>
> +#ifdef __NR_ftruncate64
> +static __attribute__((unused))
> +int sys_ftruncate64(int fd, uint32_t length0, uint32_t length1)
> +{
> + return my_syscall4(__NR_ftruncate64, fd, 0, length0, length1);
> +}
> +#define sys_ftruncate64 sys_ftruncate64
> +#endif
> +
> #endif /* _NOLIBC_ARCH_POWERPC_H */
> diff --git a/tools/include/nolibc/unistd.h b/tools/include/nolibc/unistd.h
> index bb5e80f3f05d..85ac253f9189 100644
> --- a/tools/include/nolibc/unistd.h
> +++ b/tools/include/nolibc/unistd.h
> @@ -48,6 +48,41 @@ int access(const char *path, int amode)
> return faccessat(AT_FDCWD, path, amode, 0);
> }
>
> +#if !defined(sys_ftruncate64) && defined(__NR_ftruncate64)
> +static __attribute__((unused))
> +int sys_ftruncate64(int fd, uint32_t length0, uint32_t length1)
> +{
> +
Nit: Spurious empty line.
> + return my_syscall3(__NR_ftruncate64, fd, length0, length1);
> +}
> +#define sys_ftruncate64 sys_ftruncate64
> +#endif
> +
> +static __attribute__((unused))
> +int sys_ftruncate(int fd, off_t length)
> +{
> +#ifdef sys_ftruncate64
> + union {
> + off_t length;
> + struct {
> + uint32_t length0;
> + uint32_t length1;
> + };
> + } arg;
> +
> + arg.length = length;
> +
> + return sys_ftruncate64(fd, arg.length0, arg.length1);
> +#else
> + return my_syscall2(__NR_ftruncate, fd, length);
> +#endif
> +}
> +
> +static __attribute__((unused))
> +int ftruncate(int fd, off_t length)
> +{
> + return __sysret(sys_ftruncate(fd, length));
> +}
>
> static __attribute__((unused))
> int msleep(unsigned int msecs)
> diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c
> index 1b9d3b2e2491..6a84dfbb4b73 100644
> --- a/tools/testing/selftests/nolibc/nolibc-test.c
> +++ b/tools/testing/selftests/nolibc/nolibc-test.c
> @@ -969,6 +969,56 @@ int test_fork(enum fork_type type)
> }
> }
>
> +int test_ftruncate(void)
> +{
> + int ret;
> + int fd;
> + struct stat stat_buf;
> + const char *filename = "/tmp/ftruncate_test";
> +
> + ret = ftruncate(-1, 0);
> + if (ret != -1 || errno != EBADF) {
> + errno = EINVAL;
> + return __LINE__;
> + }
> +
> + fd = open(filename, O_RDWR | O_CREAT);
Missing the mode argument.
O_TMPFILE would make things easier.
> + if (fd == -1)
> + return __LINE__;
> +
> + ret = ftruncate(fd, -1);
> + if (ret != -1 || errno != EINVAL) {
> + if (ret == 0)
> + errno = EINVAL;
> + ret = __LINE__;
> + goto end;
> + }
> +
> + ret = ftruncate(fd, 42);
> + if (ret != 0) {
> + ret = __LINE__;
> + goto end;
> + }
> +
> + ret = fstat(fd, &stat_buf);
> + if (ret != 0) {
> + ret = __LINE__;
> + goto end;
> + }
> +
> + if (stat_buf.st_size != 42) {
> + errno = EINVAL;
> + ret = stat_buf.st_size;
> + goto end;
> + }
Could you also add a variant which tests that 64-bit values work correctly?
> +
> +end:
> + close(fd);
> + unlink(filename);
> +
> + return ret;
> +}
> +
> int test_stat_timestamps(void)
> {
> struct stat st;
> @@ -1406,6 +1456,7 @@ int run_syscall(int min, int max)
> CASE_TEST(file_stream); EXPECT_SYSZR(1, test_file_stream()); break;
> CASE_TEST(file_stream_wsr); EXPECT_SYSZR(1, test_file_stream_wsr()); break;
> CASE_TEST(fork); EXPECT_SYSZR(1, test_fork(FORK_STANDARD)); break;
> + CASE_TEST(ftruncate); EXPECT_SYSZR(1, test_ftruncate()); break;
> CASE_TEST(getdents64_root); EXPECT_SYSNE(1, test_getdents64("/"), -1); break;
> CASE_TEST(getdents64_null); EXPECT_SYSER(1, test_getdents64("/dev/null"), -1, ENOTDIR); break;
> CASE_TEST(directories); EXPECT_SYSZR(proc, test_dirent()); break;
> --
> 2.53.0.473.g4a7958ca14-goog
>
next prev parent reply other threads:[~2026-03-03 7:09 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-03 1:00 [PATCH v3 0/2] selftests/liveupdate: add end to end test infrastructure and scripts Jordan Richards
2026-03-03 1:00 ` [PATCH v3 1/2] tools/nolibc: add ftruncate() Jordan Richards
2026-03-03 7:09 ` Thomas Weißschuh [this message]
2026-03-03 1:00 ` [PATCH v3 2/2] selftests/liveupdate: add end to end test infrastructure and scripts Jordan Richards
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=c65fdf06-2f69-4c81-be21-a14229eaf1b6@t-8ch.de \
--to=linux@weissschuh.net \
--cc=dmatlack@google.com \
--cc=jasonmiu@google.com \
--cc=jordanrichards@google.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=pasha.tatashin@soleen.com \
--cc=pratyush@kernel.org \
--cc=rppt@kernel.org \
--cc=shuah@kernel.org \
--cc=w@1wt.eu \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox