Le 25/08/2020 à 16:23, Laurent Vivier a écrit : > Le 25/08/2020 à 09:18, Laurent Vivier a écrit : >> Le 25/08/2020 à 00:30, Filip Bozuta a écrit : >>> This patch introduces functionality for following time64 syscalls: >>> >>> *utimensat_time64() >>> >>> int utimensat(int dirfd, const char *pathname, >>> const struct timespec times[2], int flags); >>> -- change file timestamps with nanosecond precision -- >>> man page: https://man7.org/linux/man-pages/man2/utimensat.2.html >>> >>> *semtimedop_time64() >>> >>> int semtimedop(int semid, struct sembuf *sops, size_t nsops, >>> const struct timespec *timeout); >>> -- System V semaphore operations -- >>> man page: https://www.man7.org/linux/man-pages/man2/semtimedop.2.html >>> >>> Implementation notes: >>> >>> Syscall 'utimensat_time64()' is implemented in similar way as its >>> regular variants only difference being that time64 converting function >>> is used to convert values of 'struct timespec' between host and target >>> ('target_to_host_timespec64()'). >>> >>> For syscall 'semtimedop_time64()' and additional argument is added >>> in function 'do_semtimedop()' through which the aproppriate 'struct >>> timespec' >>> converting function is called (false for regular >>> target_to_host_timespec() >>> and true for target_to_host_timespec64()). For 'do_ipc()' a >>> check was added as that additional argument: 'TARGET_ABI_BITS == 64'. >>> >>> Signed-off-by: Filip Bozuta <filip.boz...@syrmia.com> >>> Reviewed-by: Laurent Vivier <laur...@vivier.eu> >>> --- >>> linux-user/syscall.c | 60 ++++++++++++++++++++++++++++++++++++-------- >>> 1 file changed, 50 insertions(+), 10 deletions(-) >>> >>> diff --git a/linux-user/syscall.c b/linux-user/syscall.c >>> index fc6a6e32e4..4d460af744 100644 >>> --- a/linux-user/syscall.c >>> +++ b/linux-user/syscall.c >>> @@ -1253,7 +1253,8 @@ static inline abi_long target_to_host_timespec(struct >>> timespec *host_ts, >>> #endif >>> >>> #if defined(TARGET_NR_clock_settime64) || defined(TARGET_NR_futex_time64) >>> || \ >>> - defined(TARGET_NR_pselect6_time64) || defined(TARGET_NR_ppoll_time64) >>> + defined(TARGET_NR_pselect6_time64) || defined(TARGET_NR_ppoll_time64) >>> || \ >>> + defined(TARGET_NR_utimensat_time64) || >>> defined(TARGET_NR_semtimedop_time64) >>> static inline abi_long target_to_host_timespec64(struct timespec *host_ts, >>> abi_ulong target_addr) >>> { >>> @@ -4117,7 +4118,7 @@ static inline abi_long target_to_host_sembuf(struct >>> sembuf *host_sembuf, >>> } >>> >>> #if defined(TARGET_NR_ipc) || defined(TARGET_NR_semop) || \ >>> - defined(TARGET_NR_semtimedop) >>> + defined(TARGET_NR_semtimedop) || defined(TARGET_NR_semtimedop_time64) >>> >>> /* >>> * This macro is required to handle the s390 variants, which passes the >>> @@ -4134,7 +4135,7 @@ static inline abi_long target_to_host_sembuf(struct >>> sembuf *host_sembuf, >>> static inline abi_long do_semtimedop(int semid, >>> abi_long ptr, >>> unsigned nsops, >>> - abi_long timeout) >>> + abi_long timeout, bool time64) >>> { >>> struct sembuf sops[nsops]; >>> struct timespec ts, *pts = NULL; >>> @@ -4142,8 +4143,14 @@ static inline abi_long do_semtimedop(int semid, >>> >>> if (timeout) { >>> pts = &ts; >>> - if (target_to_host_timespec(pts, timeout)) { >>> - return -TARGET_EFAULT; >>> + if (time64) { >>> + if (target_to_host_timespec64(pts, timeout)) { >>> + return -TARGET_EFAULT; >>> + } >>> + } else { >>> + if (target_to_host_timespec(pts, timeout)) { >>> + return -TARGET_EFAULT; >>> + } >>> } >>> } >>> >>> @@ -4657,7 +4664,7 @@ static abi_long do_ipc(CPUArchState *cpu_env, >>> >>> switch (call) { >>> case IPCOP_semop: >>> - ret = do_semtimedop(first, ptr, second, 0); >>> + ret = do_semtimedop(first, ptr, second, 0, false); >>> break; >>> case IPCOP_semtimedop: >>> /* >>> @@ -4667,9 +4674,9 @@ static abi_long do_ipc(CPUArchState *cpu_env, >>> * to a struct timespec where the generic variant uses fifth parameter. >>> */ >>> #if defined(TARGET_S390X) >>> - ret = do_semtimedop(first, ptr, second, third); >>> + ret = do_semtimedop(first, ptr, second, third, TARGET_ABI_BITS == >>> 64); >>> #else >>> - ret = do_semtimedop(first, ptr, second, fifth); >>> + ret = do_semtimedop(first, ptr, second, fifth, TARGET_ABI_BITS == >>> 64); >>> #endif >>> break; >>> >>> @@ -9887,11 +9894,15 @@ static abi_long do_syscall1(void *cpu_env, int num, >>> abi_long arg1, >>> #endif >>> #ifdef TARGET_NR_semop >>> case TARGET_NR_semop: >>> - return do_semtimedop(arg1, arg2, arg3, 0); >>> + return do_semtimedop(arg1, arg2, arg3, 0, false); >>> #endif >>> #ifdef TARGET_NR_semtimedop >>> case TARGET_NR_semtimedop: >>> - return do_semtimedop(arg1, arg2, arg3, arg4); >>> + return do_semtimedop(arg1, arg2, arg3, arg4, false); >>> +#endif >>> +#ifdef TARGET_NR_semtimedop_time64 >>> + case TARGET_NR_semtimedop_time64: >>> + return do_semtimedop(arg1, arg2, arg3, arg4, true); >>> #endif >>> #ifdef TARGET_NR_semctl >>> case TARGET_NR_semctl: >>> @@ -11938,6 +11949,35 @@ static abi_long do_syscall1(void *cpu_env, int >>> num, abi_long arg1, >>> } >>> return ret; >>> #endif >>> +#ifdef TARGET_NR_utimensat_time64 >>> + case TARGET_NR_utimensat_time64: >>> + { >>> + struct timespec *tsp, ts[2]; >>> + if (!arg3) { >>> + tsp = NULL; >>> + } else { >>> + if (target_to_host_timespec64(ts, arg3)) { >>> + return -TARGET_EFAULT; >>> + } >>> + if (target_to_host_timespec64(ts + 1, arg3 + >>> + sizeof(struct >>> target__kernel_timespec))) { >>> + return -TARGET_EFAULT; >>> + } >>> + tsp = ts; >>> + } >>> + if (!arg2) >>> + ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4)); >>> + else { >>> + p = lock_user_string(arg2); >>> + if (!p) { >>> + return -TARGET_EFAULT; >>> + } >>> + ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4)); >>> + unlock_user(p, arg2, 0); >>> + } >>> + } >>> + return ret; >>> +#endif >>> #ifdef TARGET_NR_futex >>> case TARGET_NR_futex: >>> return do_futex(arg1, arg2, arg3, arg4, arg5, arg6); >>> >> >> Applied to my linux-user-for-5.2 branch. > > I have removed it from my queue because the "TARGET_NR_utimensat_time64" > part breaks something (at least with sh4/sid on x86_64): > > $ touch a > $ cp -p a b > /usr/bin/cp: preserving times for 'b': Invalid argument
In fact, on sh4, he timespec64 conversion is broken for all syscalls. tv_sec is ok but tv_nsec is totally corrupted (as it would be only a 32bit value). Thanks, Laurent