From ef3fb8c37b7c397d4f874b7afceda7e48fd9a461 Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Tue, 21 Jan 2025 10:43:44 +0100 Subject: [PATCH 1/5] lkl tools: use 64-bit lkl_sys_nanosleep on 32-bit builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the always-64-bit __lkl__kernel_timespec struct for lkl_sys_nanosleep calls and rewrite the lkl_sys_nanosleep_time32 wrapper to use __lkl__NR_clock_nanosleep_time64 on 32-bit builds. This fixes the following -Wincompatible-pointer-types errors: lib/fs.c:287:43: error: passing argument 1 of ‘lkl_sys_nanosleep_time32’ from incompatible pointer type [-Wincompatible-pointer-types] 287 | lkl_sys_nanosleep((struct __lkl__kernel_timespec *)&ts, | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | struct __lkl__kernel_timespec * In file included from tools/lkl//include/lkl_host.h:9, from lib/fs.c:5: tools/lkl//include/lkl.h:68:65: note: expected ‘struct lkl_timespec *’ but argument is of type ‘struct __lkl__kernel_timespec *’ 68 | static inline int lkl_sys_nanosleep_time32(struct lkl_timespec *rqtp, | ~~~~~~~~~~~~~~~~~~~~~^~~~ make[1]: *** [tools/build/Makefile.build:98: tools/lkl/lib/fs.o] Error 1 Signed-off-by: David Disseldorp --- tools/lkl/cptofs.c | 4 ++-- tools/lkl/include/lkl.h | 9 ++++----- tools/lkl/lib/fs.c | 5 ++--- tools/lkl/tests/boot.c | 7 ++++--- tools/lkl/tests/net-test.c | 4 ++-- 5 files changed, 14 insertions(+), 15 deletions(-) diff --git a/tools/lkl/cptofs.c b/tools/lkl/cptofs.c index cf34ab212c52f4..7b22a7ba4a1c27 100644 --- a/tools/lkl/cptofs.c +++ b/tools/lkl/cptofs.c @@ -684,11 +684,11 @@ int main(int argc, char **argv) if (ret == 0) break; if (ret == -EBUSY) { - struct lkl_timespec ts = { + struct __lkl__kernel_timespec ts = { .tv_sec = 1, .tv_nsec = 0, }; - lkl_sys_nanosleep((struct __lkl__kernel_timespec *)&ts, NULL); + lkl_sys_nanosleep(&ts, NULL); continue; } else if (ret < 0) { fprintf(stderr, "cannot remount mount disk read-only: %s\n", lkl_strerror(ret)); diff --git a/tools/lkl/include/lkl.h b/tools/lkl/include/lkl.h index 6abc2a698c7331..9af4da9d955b32 100644 --- a/tools/lkl/include/lkl.h +++ b/tools/lkl/include/lkl.h @@ -64,13 +64,12 @@ static inline int lkl_sys_fstatfs(unsigned int fd, struct lkl_statfs *buf) return lkl_sys_fstatfs64(fd, sizeof(*buf), buf); } -#define lkl_sys_nanosleep lkl_sys_nanosleep_time32 -static inline int lkl_sys_nanosleep_time32(struct lkl_timespec *rqtp, - struct lkl_timespec *rmtp) +static inline int lkl_sys_nanosleep(struct __lkl__kernel_timespec *rqtp, + struct __lkl__kernel_timespec *rmtp) { - long p[6] = {(long)rqtp, (long)rmtp, 0, 0, 0, 0}; + long p[6] = {LKL_CLOCK_MONOTONIC, 0, (long)rqtp, (long)rmtp, 0}; - return lkl_syscall(__lkl__NR_nanosleep, p); + return lkl_syscall(__lkl__NR_clock_nanosleep_time64, p); } #endif diff --git a/tools/lkl/lib/fs.c b/tools/lkl/lib/fs.c index 9fefa1f5c542a7..8bd8092fd355a7 100644 --- a/tools/lkl/lib/fs.c +++ b/tools/lkl/lib/fs.c @@ -275,7 +275,7 @@ long lkl_mount_dev(unsigned int disk_id, unsigned int part, long lkl_umount_timeout(char *path, int flags, long timeout_ms) { long incr = 10000000; /* 10 ms */ - struct lkl_timespec ts = { + struct __lkl__kernel_timespec ts = { .tv_sec = 0, .tv_nsec = incr, }; @@ -284,8 +284,7 @@ long lkl_umount_timeout(char *path, int flags, long timeout_ms) do { err = lkl_sys_umount(path, flags); if (err == -LKL_EBUSY) { - lkl_sys_nanosleep((struct __lkl__kernel_timespec *)&ts, - NULL); + lkl_sys_nanosleep(&ts, NULL); timeout_ms -= incr / 1000000; } } while (err == -LKL_EBUSY && timeout_ms > 0); diff --git a/tools/lkl/tests/boot.c b/tools/lkl/tests/boot.c index ec6096a76a56fe..1aafde024b40a2 100644 --- a/tools/lkl/tests/boot.c +++ b/tools/lkl/tests/boot.c @@ -27,7 +27,7 @@ #define sleep_ns 87654321 int lkl_test_nanosleep(void) { - struct lkl_timespec ts = { + struct __lkl__kernel_timespec ts = { .tv_sec = 0, .tv_nsec = sleep_ns, }; @@ -36,13 +36,14 @@ int lkl_test_nanosleep(void) long ret; clock_gettime(CLOCK_MONOTONIC, &start); - ret = lkl_sys_nanosleep((struct __lkl__kernel_timespec *)&ts, NULL); + ret = lkl_sys_nanosleep(&ts, NULL); clock_gettime(CLOCK_MONOTONIC, &stop); delta = 1e9*(stop.tv_sec - start.tv_sec) + (stop.tv_nsec - start.tv_nsec); - lkl_test_logf("sleep %ld, expected sleep %d\n", delta, sleep_ns); + lkl_test_logf("sleep %ld (ret=%ld), expected sleep %d\n", + delta, ret, sleep_ns); if (ret == 0 && delta > sleep_ns * 0.9) return TEST_SUCCESS; diff --git a/tools/lkl/tests/net-test.c b/tools/lkl/tests/net-test.c index e5406304380713..4d73a3f15b4c1c 100644 --- a/tools/lkl/tests/net-test.c +++ b/tools/lkl/tests/net-test.c @@ -86,12 +86,12 @@ in_cksum(const u_short *addr, register int len, u_short csum) static int lkl_test_sleep(void) { - struct lkl_timespec ts = { + struct __lkl__kernel_timespec ts = { .tv_sec = cla.sleep, }; int ret; - ret = lkl_sys_nanosleep((struct __lkl__kernel_timespec *)&ts, NULL); + ret = lkl_sys_nanosleep(&ts, NULL); if (ret < 0) { lkl_test_logf("nanosleep error: %s\n", lkl_strerror(ret)); return TEST_FAILURE; From 4348d61e006096e63e7dab90561f51def01aff30 Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Tue, 28 Jan 2025 14:43:22 +0100 Subject: [PATCH 2/5] lkl tools: fix some -Wincompatible-pointer-types errors Explicitly cast between unsigned long and size_t for malloc, memcpy and memset. Signed-off-by: David Disseldorp --- tools/lkl/lib/posix-host.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/tools/lkl/lib/posix-host.c b/tools/lkl/lib/posix-host.c index 5b45924d470c65..5387ce3f6987d6 100644 --- a/tools/lkl/lib/posix-host.c +++ b/tools/lkl/lib/posix-host.c @@ -521,6 +521,21 @@ static void *lkl_shmem_mmap(void *addr, unsigned long pg_off, } #endif // LKL_HOST_CONFIG_MMU +static void *posix_malloc(unsigned long size) +{ + return malloc((size_t)size); +} + +static void *posix_memcpy(void *dest, const void *src, unsigned long n) +{ + return memcpy(dest, src, (size_t)n); +} + +static void *posix_memset(void *s, int c, unsigned long n) +{ + return memset(s, c, (size_t)n); +} + struct lkl_host_operations lkl_host_ops = { .panic = panic, .thread_create = thread_create, @@ -547,7 +562,7 @@ struct lkl_host_operations lkl_host_ops = { .timer_set_oneshot = timer_set_oneshot, .timer_free = timer_free, .print = print, - .mem_alloc = malloc, + .mem_alloc = posix_malloc, .mem_free = free, .page_alloc = page_alloc, .page_free = page_free, @@ -557,8 +572,8 @@ struct lkl_host_operations lkl_host_ops = { .gettid = _gettid, .jmp_buf_set = jmp_buf_set, .jmp_buf_longjmp = jmp_buf_longjmp, - .memcpy = memcpy, - .memset = memset, + .memcpy = posix_memcpy, + .memset = posix_memset, .mmap = lkl_mmap, .munmap = lkl_munmap, #ifdef LKL_HOST_CONFIG_MMU From 75fd3b6e7417bdca244aaa792ab7b44e51cdd6db Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Mon, 3 Feb 2025 06:42:20 +0100 Subject: [PATCH 3/5] lkl cptofs: handle stat errors earlier Don't bother parsing the results if the initial stat call failed. Signed-off-by: David Disseldorp --- tools/lkl/cptofs.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tools/lkl/cptofs.c b/tools/lkl/cptofs.c index 7b22a7ba4a1c27..a84b459e27475d 100644 --- a/tools/lkl/cptofs.c +++ b/tools/lkl/cptofs.c @@ -263,6 +263,9 @@ static int stat_src(const char *path, unsigned int *type, unsigned int *mode, if (cptofs) { ret = lstat(path, &stat); + if (ret) + goto err_out; + if (type) *type = stat.st_mode & S_IFMT; if (mode) @@ -279,6 +282,9 @@ static int stat_src(const char *path, unsigned int *type, unsigned int *mode, } } else { ret = lkl_sys_lstat(path, &lkl_stat); + if (ret) + goto err_out; + if (type) *type = lkl_stat.st_mode & S_IFMT; if (mode) @@ -295,6 +301,7 @@ static int stat_src(const char *path, unsigned int *type, unsigned int *mode, } } +err_out: if (ret) fprintf(stderr, "fsimg lstat(%s) error: %s\n", path, cptofs ? strerror(errno) : lkl_strerror(ret)); @@ -430,6 +437,8 @@ static int do_entry(const char *_src, const char *_dst, const char *name, uid_t snprintf(dst, sizeof(dst), "%s/%s", _dst, name); ret = stat_src(src, &type, &mode, NULL, &mtime, &atime); + if (ret) + goto err_out; switch (type) { case S_IFREG: @@ -472,6 +481,7 @@ static int do_entry(const char *_src, const char *_dst, const char *name, uid_t } } +err_out: if (ret) printf("error processing entry %s, aborting\n", src); From ab1c2d0c6fa4a5eb5e125e42d178b9b0117c2d18 Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Tue, 4 Feb 2025 01:35:28 +0100 Subject: [PATCH 4/5] lkl: rework broken lkl_sys_select timeval conversion max_time is incorrect for both 8-byte and 4-byte time_t sizes. It should be 0x7fffffffffffffff on 64-bit arches instead of 0x7fe. Given that we will (in the next commit) be casting from a (long x 2) lkl_timeval to a (long long x 2) __lkl__kernel_timespec, I think we can ignore overflow and match the nolibc conversion logic. Link: https://github.com/lkl/linux/issues/557 Fixes: 780bdc7a6612 ("lkl: follow up fixes after 4.17 merge") Signed-off-by: David Disseldorp --- tools/lkl/include/lkl.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/tools/lkl/include/lkl.h b/tools/lkl/include/lkl.h index 9af4da9d955b32..2546450cff1c2e 100644 --- a/tools/lkl/include/lkl.h +++ b/tools/lkl/include/lkl.h @@ -277,17 +277,13 @@ static inline long lkl_sys_select(int n, lkl_fd_set *rfds, lkl_fd_set *wfds, { long data[2] = { 0, _LKL_NSIG/8 }; struct lkl_timespec ts; - lkl_time_t extra_secs; - const lkl_time_t max_time = ((1ULL<<8)*sizeof(time_t)-1)-1; if (tv) { if (tv->tv_sec < 0 || tv->tv_usec < 0) return -LKL_EINVAL; - extra_secs = tv->tv_usec / 1000000; - ts.tv_nsec = tv->tv_usec % 1000000 * 1000; - ts.tv_sec = extra_secs > max_time - tv->tv_sec ? - max_time : tv->tv_sec + extra_secs; + ts.tv_sec = tv->tv_sec; + ts.tv_nsec = tv->tv_usec * 1000; } return lkl_sys_pselect6(n, rfds, wfds, efds, tv ? (struct __lkl__kernel_timespec *)&ts : 0, data); From 0692c1e05031ac61758d22a14417b50ab81732e2 Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Mon, 3 Feb 2025 13:14:47 +0100 Subject: [PATCH 5/5] lkl: fix 32-bit timespec casts On 32-bit architectures, struct lkl_timespec is 2*sizeof(long) while __lkl__kernel_timespec is 2*sizeof(long long); casting these pointer types is unsafe. Fixes: 3d4047ac9aae ("lkl: follow up fixes after v5.1 merge (y2038)") Signed-off-by: David Disseldorp --- tools/lkl/cptofs.c | 30 ++++++++++++++++-------------- tools/lkl/include/lkl.h | 19 +++++++++++-------- tools/lkl/lklfuse.c | 20 ++++++++------------ 3 files changed, 35 insertions(+), 34 deletions(-) diff --git a/tools/lkl/cptofs.c b/tools/lkl/cptofs.c index a84b459e27475d..007f0ec85b99ff 100644 --- a/tools/lkl/cptofs.c +++ b/tools/lkl/cptofs.c @@ -463,22 +463,24 @@ static int do_entry(const char *_src, const char *_dst, const char *name, uid_t printf("skipping %s: unsupported entry type %d\n", src, type); } - if (!ret) { - if (cptofs) { - struct lkl_timespec lkl_ts[] = { atime, mtime }; + if (ret) + goto err_out; - ret = lkl_sys_utimensat(LKL_AT_FDCWD, dst, - (struct __lkl__kernel_timespec - *)lkl_ts, - LKL_AT_SYMLINK_NOFOLLOW); - } else { - struct timespec ts[] = { - { .tv_sec = atime.tv_sec, .tv_nsec = atime.tv_nsec, }, - { .tv_sec = mtime.tv_sec, .tv_nsec = mtime.tv_nsec, }, - }; + if (cptofs) { + struct __lkl__kernel_timespec lkl_ts[] = { + { .tv_sec = atime.tv_sec, .tv_nsec = atime.tv_nsec, }, + { .tv_sec = mtime.tv_sec, .tv_nsec = mtime.tv_nsec, }, + }; - ret = utimensat(AT_FDCWD, dst, ts, AT_SYMLINK_NOFOLLOW); - } + ret = lkl_sys_utimensat(LKL_AT_FDCWD, dst, lkl_ts, + LKL_AT_SYMLINK_NOFOLLOW); + } else { + struct timespec ts[] = { + { .tv_sec = atime.tv_sec, .tv_nsec = atime.tv_nsec, }, + { .tv_sec = mtime.tv_sec, .tv_nsec = mtime.tv_nsec, }, + }; + + ret = utimensat(AT_FDCWD, dst, ts, AT_SYMLINK_NOFOLLOW); } err_out: diff --git a/tools/lkl/include/lkl.h b/tools/lkl/include/lkl.h index 2546450cff1c2e..cd905556c07f48 100644 --- a/tools/lkl/include/lkl.h +++ b/tools/lkl/include/lkl.h @@ -276,7 +276,7 @@ static inline long lkl_sys_select(int n, lkl_fd_set *rfds, lkl_fd_set *wfds, lkl_fd_set *efds, struct lkl_timeval *tv) { long data[2] = { 0, _LKL_NSIG/8 }; - struct lkl_timespec ts; + struct __lkl__kernel_timespec ts; if (tv) { if (tv->tv_sec < 0 || tv->tv_usec < 0) @@ -285,8 +285,7 @@ static inline long lkl_sys_select(int n, lkl_fd_set *rfds, lkl_fd_set *wfds, ts.tv_sec = tv->tv_sec; ts.tv_nsec = tv->tv_usec * 1000; } - return lkl_sys_pselect6(n, rfds, wfds, efds, tv ? - (struct __lkl__kernel_timespec *)&ts : 0, data); + return lkl_sys_pselect6(n, rfds, wfds, efds, tv ? &ts : 0, data); } #endif @@ -296,11 +295,15 @@ static inline long lkl_sys_select(int n, lkl_fd_set *rfds, lkl_fd_set *wfds, */ static inline long lkl_sys_poll(struct lkl_pollfd *fds, int n, int timeout) { - return lkl_sys_ppoll(fds, n, timeout >= 0 ? - (struct __lkl__kernel_timespec *) - &((struct lkl_timespec){ .tv_sec = timeout/1000, - .tv_nsec = timeout%1000*1000000 }) : 0, - 0, _LKL_NSIG/8); + struct __lkl__kernel_timespec ts; + + if (timeout >= 0) + ts = (struct __lkl__kernel_timespec){ + .tv_sec = timeout / 1000, + .tv_nsec = timeout % 1000 * 1000000, + }; + + return lkl_sys_ppoll(fds, n, timeout >= 0 ? &ts : 0, 0, _LKL_NSIG/8); } #endif diff --git a/tools/lkl/lklfuse.c b/tools/lkl/lklfuse.c index d71b4b0df6efba..faa704b4285198 100644 --- a/tools/lkl/lklfuse.c +++ b/tools/lkl/lklfuse.c @@ -503,19 +503,16 @@ static int lklfuse_utimens(const char *path, const struct timespec tv[2], struct fuse_file_info *fi) { int ret; - struct lkl_timespec ts[2] = { + struct __lkl__kernel_timespec ts[2] = { { .tv_sec = tv[0].tv_sec, .tv_nsec = tv[0].tv_nsec }, { .tv_sec = tv[1].tv_sec, .tv_nsec = tv[1].tv_nsec }, }; if (fi) - ret = lkl_sys_utimensat(fi->fh, NULL, - (struct __lkl__kernel_timespec *)ts, - 0); + ret = lkl_sys_utimensat(fi->fh, NULL, ts, 0); else - ret = lkl_sys_utimensat(-1, path, - (struct __lkl__kernel_timespec *)ts, - LKL_AT_SYMLINK_NOFOLLOW); + ret = lkl_sys_utimensat(-1, path, ts, LKL_AT_SYMLINK_NOFOLLOW); + return ret; } @@ -686,7 +683,7 @@ static int start_lkl(void) long ret; char mpoint[32]; struct timespec walltime; - struct lkl_timespec ts; + struct __lkl__kernel_timespec ts; int mount_flags = 0; char remaining_mopts[4096] = { 0 }; @@ -709,10 +706,9 @@ static int start_lkl(void) if (ret < 0) goto out_halt; - ts = (struct lkl_timespec){ .tv_sec = walltime.tv_sec, - .tv_nsec = walltime.tv_nsec }; - ret = lkl_sys_clock_settime(LKL_CLOCK_REALTIME, - (struct __lkl__kernel_timespec *)&ts); + ts = (struct __lkl__kernel_timespec){ .tv_sec = walltime.tv_sec, + .tv_nsec = walltime.tv_nsec }; + ret = lkl_sys_clock_settime(LKL_CLOCK_REALTIME, &ts); if (ret < 0) { fprintf(stderr, "lkl_sys_clock_settime() failed: %s\n", lkl_strerror(ret));