From c261145abd2461f921ac44ad70c28778dda710f4 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Thu, 21 Jan 2021 08:20:23 +0100 Subject: [PATCH 01/10] tools/nolibc: Add the definition for dup() This commit adds the dup() function, which was omitted when sys_dup() was defined. This is a port of nolibc's upstream commit 47cc42a79c92 to the Linux kernel. Fixes: 66b6f755ad45 ("rcutorture: Import a copy of nolibc") Tested-by: Valentin Schneider Tested-by: Mark Rutland [arm64] Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/nolibc.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h index e61d36cd4e50..3115c6467d10 100644 --- a/tools/include/nolibc/nolibc.h +++ b/tools/include/nolibc/nolibc.h @@ -1852,6 +1852,18 @@ int close(int fd) return ret; } +static __attribute__((unused)) +int dup(int fd) +{ + int ret = sys_dup(fd); + + if (ret < 0) { + SET_ERRNO(-ret); + ret = -1; + } + return ret; +} + static __attribute__((unused)) int dup2(int old, int new) { From 79f220e56dc85739aa5462fa8a1abd4a44f002e0 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Thu, 21 Jan 2021 08:20:24 +0100 Subject: [PATCH 02/10] tools/nolibc: Make dup2() rely on dup3() when available A recent boot failure on 5.4-rc3 on arm64 revealed that sys_dup2() is not available and that only sys_dup3() is implemented. This commit detects this and falls back to sys_dup3() when available. This is a port of nolibc's upstream commit fd5272ec2c66 to the Linux kernel. Tested-by: Valentin Schneider Tested-by: Mark Rutland [arm64] Signed-off-by: Willy Tarreau Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/nolibc.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h index 3115c6467d10..5fda4d844054 100644 --- a/tools/include/nolibc/nolibc.h +++ b/tools/include/nolibc/nolibc.h @@ -1502,10 +1502,22 @@ int sys_dup(int fd) return my_syscall1(__NR_dup, fd); } +#ifdef __NR_dup3 +static __attribute__((unused)) +int sys_dup3(int old, int new, int flags) +{ + return my_syscall3(__NR_dup3, old, new, flags); +} +#endif + static __attribute__((unused)) int sys_dup2(int old, int new) { +#ifdef __NR_dup3 + return my_syscall3(__NR_dup3, old, new, 0); +#else return my_syscall2(__NR_dup2, old, new); +#endif } static __attribute__((unused)) @@ -1876,6 +1888,20 @@ int dup2(int old, int new) return ret; } +#ifdef __NR_dup3 +static __attribute__((unused)) +int dup3(int old, int new, int flags) +{ + int ret = sys_dup3(old, new, flags); + + if (ret < 0) { + SET_ERRNO(-ret); + ret = -1; + } + return ret; +} +#endif + static __attribute__((unused)) int execve(const char *filename, char *const argv[], char *const envp[]) { From c0c7c103756fee25aadfd5c36f7b86e318f9abb4 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Thu, 21 Jan 2021 08:20:25 +0100 Subject: [PATCH 03/10] tools/nolibc: Make getpgrp() fall back to getpgid(0) The getpgrp() syscall is not implemented on arm64, so this commit instead uses getpgid(0) when getpgrp() is not available. This is a port of nolibc's upstream commit 2379f25073f9 to the Linux kernel. Fixes: 66b6f755ad45 ("rcutorture: Import a copy of nolibc") Tested-by: Valentin Schneider Tested-by: Mark Rutland [arm64] Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/nolibc.h | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h index 5fda4d844054..9209da89044a 100644 --- a/tools/include/nolibc/nolibc.h +++ b/tools/include/nolibc/nolibc.h @@ -1544,10 +1544,16 @@ int sys_getdents64(int fd, struct linux_dirent64 *dirp, int count) return my_syscall3(__NR_getdents64, fd, dirp, count); } +static __attribute__((unused)) +pid_t sys_getpgid(pid_t pid) +{ + return my_syscall1(__NR_getpgid, pid); +} + static __attribute__((unused)) pid_t sys_getpgrp(void) { - return my_syscall0(__NR_getpgrp); + return sys_getpgid(0); } static __attribute__((unused)) @@ -1950,6 +1956,18 @@ int getdents64(int fd, struct linux_dirent64 *dirp, int count) return ret; } +static __attribute__((unused)) +pid_t getpgid(pid_t pid) +{ + pid_t ret = sys_getpgid(pid); + + if (ret < 0) { + SET_ERRNO(-ret); + ret = -1; + } + return ret; +} + static __attribute__((unused)) pid_t getpgrp(void) { From be60ca41fbaa93bc8f92b24e34d8cc62af41300d Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Thu, 21 Jan 2021 08:20:26 +0100 Subject: [PATCH 04/10] tools/nolibc: Implement fork() based on clone() Some archs such as arm64 do not have fork() and have to use clone() instead. This commit therefore makes fork() use clone() when available. This requires including signal.h to get the definition of SIGCHLD. This is a port of nolibc's upstream commit d2dc42fd6149 to the Linux kernel. Fixes: 66b6f755ad45 ("rcutorture: Import a copy of nolibc") Tested-by: Valentin Schneider Tested-by: Mark Rutland [arm64] Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/nolibc.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h index 9209da89044a..fdd5524e0e54 100644 --- a/tools/include/nolibc/nolibc.h +++ b/tools/include/nolibc/nolibc.h @@ -271,6 +271,8 @@ struct stat { #define WEXITSTATUS(status) (((status) & 0xff00) >> 8) #define WIFEXITED(status) (((status) & 0x7f) == 0) +/* for SIGCHLD */ +#include /* Below comes the architecture-specific code. For each architecture, we have * the syscall declarations and the _start code definition. This is the only @@ -1529,7 +1531,15 @@ int sys_execve(const char *filename, char *const argv[], char *const envp[]) static __attribute__((unused)) pid_t sys_fork(void) { +#ifdef __NR_clone + /* note: some archs only have clone() and not fork(). Different archs + * have a different API, but most archs have the flags on first arg and + * will not use the rest with no other flag. + */ + return my_syscall5(__NR_clone, SIGCHLD, 0, 0, 0, 0); +#else return my_syscall0(__NR_fork); +#endif } static __attribute__((unused)) From 5b1c827ca3b349801e2faff4185118cfa74f94c6 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Thu, 21 Jan 2021 08:20:27 +0100 Subject: [PATCH 05/10] tools/nolibc: Implement poll() based on ppoll() Some architectures like arm64 do not implement poll() and have to use ppoll() instead. This commit therefore makes poll() use ppoll() when available. This is a port of nolibc's upstream commit 800f75c13ede to the Linux kernel. Fixes: 66b6f755ad45 ("rcutorture: Import a copy of nolibc") Tested-by: Valentin Schneider Tested-by: Mark Rutland [arm64] Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/nolibc.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h index fdd5524e0e54..833693faf53c 100644 --- a/tools/include/nolibc/nolibc.h +++ b/tools/include/nolibc/nolibc.h @@ -1652,7 +1652,17 @@ int sys_pivot_root(const char *new, const char *old) static __attribute__((unused)) int sys_poll(struct pollfd *fds, int nfds, int timeout) { +#if defined(__NR_ppoll) + struct timespec t; + + if (timeout >= 0) { + t.tv_sec = timeout / 1000; + t.tv_nsec = (timeout % 1000) * 1000000; + } + return my_syscall4(__NR_ppoll, fds, nfds, (timeout >= 0) ? &t : NULL, NULL); +#else return my_syscall3(__NR_poll, fds, nfds, timeout); +#endif } static __attribute__((unused)) From 70ca7aea50a27f03aa7e4cc6ee68940d13cbcd17 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Thu, 21 Jan 2021 08:20:28 +0100 Subject: [PATCH 06/10] tools/nolibc: Get timeval, timespec and timezone from linux/time.h The definitions of timeval(), timespec() and timezone() conflict with linux/time.h when building, so this commit takes them directly from linux/time.h. This is a port of nolibc's upstream commit dc45f5426b0c to the Linux kernel. Fixes: 66b6f755ad45 ("rcutorture: Import a copy of nolibc") Tested-by: Valentin Schneider Tested-by: Mark Rutland [arm64] Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/nolibc.h | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h index 833693faf53c..611d9d15899d 100644 --- a/tools/include/nolibc/nolibc.h +++ b/tools/include/nolibc/nolibc.h @@ -94,6 +94,7 @@ #include #include #include +#include #define NOLIBC @@ -152,24 +153,6 @@ struct pollfd { short int revents; }; -/* for select() */ -struct timeval { - long tv_sec; - long tv_usec; -}; - -/* for pselect() */ -struct timespec { - long tv_sec; - long tv_nsec; -}; - -/* for gettimeofday() */ -struct timezone { - int tz_minuteswest; - int tz_dsttime; -}; - /* for getdents64() */ struct linux_dirent64 { uint64_t d_ino; From f65d7117785cb8ab04f1af55909807c7eb9ed30b Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Thu, 21 Jan 2021 08:20:29 +0100 Subject: [PATCH 07/10] tools/nolibc: Remove incorrect definitions of __ARCH_WANT_* The __ARCH_WANT_* definitions were added in order to support aarch64 when it was missing some syscall definitions (including __NR_dup2, __NR_fork, and __NR_getpgrp), but these __ARCH_WANT_* definitions were actually wrong because these syscalls do not exist on this platform. Defining these resulted in exposing invalid definitions, resulting in failures on aarch64. The missing syscalls were since implemented based on the newer ones (__NR_dup3, __NR_clone, __NR_getpgid) so these incorrect __ARCH_WANT_* definitions are no longer needed. Thanks to Mark Rutland for spotting this incorrect analysis and explaining why it was wrong. This is a port of nolibc's upstream commit 00b1b0d9b2a4 to the Linux kernel. Reported-by: Mark Rutland Link: https://lore.kernel.org/lkml/20210119153147.GA5083@paulmck-ThinkPad-P72 Tested-by: Valentin Schneider Tested-by: Mark Rutland [arm64] Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/nolibc.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h index 611d9d15899d..475d956ed1d6 100644 --- a/tools/include/nolibc/nolibc.h +++ b/tools/include/nolibc/nolibc.h @@ -81,14 +81,6 @@ * */ -/* Some archs (at least aarch64) don't expose the regular syscalls anymore by - * default, either because they have an "_at" replacement, or because there are - * more modern alternatives. For now we'd rather still use them. - */ -#define __ARCH_WANT_SYSCALL_NO_AT -#define __ARCH_WANT_SYSCALL_NO_FLAGS -#define __ARCH_WANT_SYSCALL_DEPRECATED - #include #include #include From 35635d7fa689492ca9edb1d949f1805f074ecf1a Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Thu, 21 Jan 2021 08:20:30 +0100 Subject: [PATCH 08/10] tools/nolibc: Emit detailed error for missing alternate syscall number definitions Some syscalls can be implemented from different __NR_* variants. For example, sys_dup2() can be implemented based on __NR_dup3 or __NR_dup2. In this case it is useful to mention both alternatives in error messages when neither are detected. This information will help the user search for the right one (e.g __NR_dup3) instead of just the fallback (__NR_dup2) which might not exist on the platform. This is a port of nolibc's upstream commit a21080d2ba41 to the Linux kernel. Suggested-by: Mark Rutland Link: https://lore.kernel.org/lkml/20210120145447.GC77728@C02TD0UTHF1T.local/ Tested-by: Valentin Schneider Tested-by: Mark Rutland [arm64] Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/nolibc.h | 52 ++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h index 475d956ed1d6..618acad6c932 100644 --- a/tools/include/nolibc/nolibc.h +++ b/tools/include/nolibc/nolibc.h @@ -1446,8 +1446,10 @@ int sys_chmod(const char *path, mode_t mode) { #ifdef __NR_fchmodat return my_syscall4(__NR_fchmodat, AT_FDCWD, path, mode, 0); -#else +#elif defined(__NR_chmod) return my_syscall2(__NR_chmod, path, mode); +#else +#error Neither __NR_fchmodat nor __NR_chmod defined, cannot implement sys_chmod() #endif } @@ -1456,8 +1458,10 @@ int sys_chown(const char *path, uid_t owner, gid_t group) { #ifdef __NR_fchownat return my_syscall5(__NR_fchownat, AT_FDCWD, path, owner, group, 0); -#else +#elif defined(__NR_chown) return my_syscall3(__NR_chown, path, owner, group); +#else +#error Neither __NR_fchownat nor __NR_chown defined, cannot implement sys_chown() #endif } @@ -1492,8 +1496,10 @@ int sys_dup2(int old, int new) { #ifdef __NR_dup3 return my_syscall3(__NR_dup3, old, new, 0); -#else +#elif defined(__NR_dup2) return my_syscall2(__NR_dup2, old, new); +#else +#error Neither __NR_dup3 nor __NR_dup2 defined, cannot implement sys_dup2() #endif } @@ -1512,8 +1518,10 @@ pid_t sys_fork(void) * will not use the rest with no other flag. */ return my_syscall5(__NR_clone, SIGCHLD, 0, 0, 0, 0); -#else +#elif defined(__NR_fork) return my_syscall0(__NR_fork); +#else +#error Neither __NR_clone nor __NR_fork defined, cannot implement sys_fork() #endif } @@ -1570,8 +1578,10 @@ int sys_link(const char *old, const char *new) { #ifdef __NR_linkat return my_syscall5(__NR_linkat, AT_FDCWD, old, AT_FDCWD, new, 0); -#else +#elif defined(__NR_link) return my_syscall2(__NR_link, old, new); +#else +#error Neither __NR_linkat nor __NR_link defined, cannot implement sys_link() #endif } @@ -1586,8 +1596,10 @@ int sys_mkdir(const char *path, mode_t mode) { #ifdef __NR_mkdirat return my_syscall3(__NR_mkdirat, AT_FDCWD, path, mode); -#else +#elif defined(__NR_mkdir) return my_syscall2(__NR_mkdir, path, mode); +#else +#error Neither __NR_mkdirat nor __NR_mkdir defined, cannot implement sys_mkdir() #endif } @@ -1596,8 +1608,10 @@ long sys_mknod(const char *path, mode_t mode, dev_t dev) { #ifdef __NR_mknodat return my_syscall4(__NR_mknodat, AT_FDCWD, path, mode, dev); -#else +#elif defined(__NR_mknod) return my_syscall3(__NR_mknod, path, mode, dev); +#else +#error Neither __NR_mknodat nor __NR_mknod defined, cannot implement sys_mknod() #endif } @@ -1613,8 +1627,10 @@ int sys_open(const char *path, int flags, mode_t mode) { #ifdef __NR_openat return my_syscall4(__NR_openat, AT_FDCWD, path, flags, mode); -#else +#elif defined(__NR_open) return my_syscall3(__NR_open, path, flags, mode); +#else +#error Neither __NR_openat nor __NR_open defined, cannot implement sys_open() #endif } @@ -1635,8 +1651,10 @@ int sys_poll(struct pollfd *fds, int nfds, int timeout) t.tv_nsec = (timeout % 1000) * 1000000; } return my_syscall4(__NR_ppoll, fds, nfds, (timeout >= 0) ? &t : NULL, NULL); -#else +#elif defined(__NR_poll) return my_syscall3(__NR_poll, fds, nfds, timeout); +#else +#error Neither __NR_ppoll nor __NR_poll defined, cannot implement sys_poll() #endif } @@ -1676,11 +1694,13 @@ int sys_select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeva t.tv_nsec = timeout->tv_usec * 1000; } return my_syscall6(__NR_pselect6, nfds, rfds, wfds, efds, timeout ? &t : NULL, NULL); -#else +#elif defined(__NR__newselect) || defined(__NR_select) #ifndef __NR__newselect #define __NR__newselect __NR_select #endif return my_syscall5(__NR__newselect, nfds, rfds, wfds, efds, timeout); +#else +#error None of __NR_select, __NR_pselect6, nor __NR__newselect defined, cannot implement sys_select() #endif } @@ -1705,8 +1725,10 @@ int sys_stat(const char *path, struct stat *buf) #ifdef __NR_newfstatat /* only solution for arm64 */ ret = my_syscall4(__NR_newfstatat, AT_FDCWD, path, &stat, 0); -#else +#elif defined(__NR_stat) ret = my_syscall2(__NR_stat, path, &stat); +#else +#error Neither __NR_newfstatat nor __NR_stat defined, cannot implement sys_stat() #endif buf->st_dev = stat.st_dev; buf->st_ino = stat.st_ino; @@ -1730,8 +1752,10 @@ int sys_symlink(const char *old, const char *new) { #ifdef __NR_symlinkat return my_syscall3(__NR_symlinkat, old, AT_FDCWD, new); -#else +#elif defined(__NR_symlink) return my_syscall2(__NR_symlink, old, new); +#else +#error Neither __NR_symlinkat nor __NR_symlink defined, cannot implement sys_symlink() #endif } @@ -1752,8 +1776,10 @@ int sys_unlink(const char *path) { #ifdef __NR_unlinkat return my_syscall3(__NR_unlinkat, AT_FDCWD, path, 0); -#else +#elif defined(__NR_unlink) return my_syscall1(__NR_unlink, path); +#else +#error Neither __NR_unlinkat nor __NR_unlink defined, cannot implement sys_unlink() #endif } From 3c6ce7a5363723a05bfe3ee03a8d4a9b66841ae4 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Thu, 21 Jan 2021 08:20:31 +0100 Subject: [PATCH 09/10] tools/nolibc: Fix position of -lgcc in the documented example The documentation header in the nolibc.h file provides an example command line, but it places the -lgcc argument before the source files, which can fail with libgcc.a (e.g. on ARM when uidiv is needed). This commit therefore moves the -lgcc to the end of the command line, hopefully before this example leaks into makefiles. This is a port of nolibc's upstream commit b5e282089223 to the Linux kernel. Fixes: 66b6f755ad45 ("rcutorture: Import a copy of nolibc") Tested-by: Valentin Schneider Tested-by: Mark Rutland [arm64] Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/nolibc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h index 618acad6c932..8b7a9830dd22 100644 --- a/tools/include/nolibc/nolibc.h +++ b/tools/include/nolibc/nolibc.h @@ -71,7 +71,7 @@ * * A simple static executable may be built this way : * $ gcc -fno-asynchronous-unwind-tables -fno-ident -s -Os -nostdlib \ - * -static -include nolibc.h -lgcc -o hello hello.c + * -static -include nolibc.h -o hello hello.c -lgcc * * A very useful calling convention table may be found here : * http://man7.org/linux/man-pages/man2/syscall.2.html From 26cec81415b1b2a2e8e36ef0b24cf5f26467aa61 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Thu, 21 Jan 2021 08:48:08 +0100 Subject: [PATCH 10/10] tools/rcutorture: Fix position of -lgcc in mkinitrd.sh The -lgcc command-line argument is placed poorly in the build options, which can result in build failures, for exapmle, on ARM when uidiv() is required. This commit therefore places the -lgcc argument after the source files. Fixes: b94ec36896da ("rcutorture: Make use of nolibc when available") Tested-by: Valentin Schneider Tested-by: Mark Rutland [arm64] Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/testing/selftests/rcutorture/bin/mkinitrd.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/rcutorture/bin/mkinitrd.sh b/tools/testing/selftests/rcutorture/bin/mkinitrd.sh index 38e424d2392c..70d62fd0d31d 100755 --- a/tools/testing/selftests/rcutorture/bin/mkinitrd.sh +++ b/tools/testing/selftests/rcutorture/bin/mkinitrd.sh @@ -70,7 +70,7 @@ if echo -e "#if __x86_64__||__i386__||__i486__||__i586__||__i686__" \ # architecture supported by nolibc ${CROSS_COMPILE}gcc -fno-asynchronous-unwind-tables -fno-ident \ -nostdlib -include ../../../../include/nolibc/nolibc.h \ - -lgcc -s -static -Os -o init init.c + -s -static -Os -o init init.c -lgcc else ${CROSS_COMPILE}gcc -s -static -Os -o init init.c fi