Date: Fri, 17 Jun 2022 19:31:49 GMT From: Dmitry Chagin <dchagin@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org Subject: git: 75ed1704e388 - stable/13 - linux(4): Implement futex_time64 system call. Message-ID: <202206171931.25HJVnZR007636@gitrepo.freebsd.org>
next in thread | raw e-mail | index | archive | help
The branch stable/13 has been updated by dchagin: URL: https://cgit.FreeBSD.org/src/commit/?id=75ed1704e3880bfa9adac7271233fa75131cc968 commit 75ed1704e3880bfa9adac7271233fa75131cc968 Author: Dmitry Chagin <dchagin@FreeBSD.org> AuthorDate: 2021-06-10 11:27:06 +0000 Commit: Dmitry Chagin <dchagin@FreeBSD.org> CommitDate: 2022-06-17 19:30:15 +0000 linux(4): Implement futex_time64 system call. MFC after: 2 weeks (cherry picked from commit 2e46d0c3d983ccd603b9bcfb318c37404b0dbc7f) --- sys/amd64/linux32/linux32_dummy_machdep.c | 1 - sys/amd64/linux32/syscalls.master | 9 +- sys/compat/linux/linux_futex.c | 218 ++++++++++++++++++------------ sys/compat/linux/linux_futex.h | 3 + sys/i386/linux/linux_dummy_machdep.c | 1 - sys/i386/linux/syscalls.master | 9 +- 6 files changed, 153 insertions(+), 88 deletions(-) diff --git a/sys/amd64/linux32/linux32_dummy_machdep.c b/sys/amd64/linux32/linux32_dummy_machdep.c index 041156bd514b..bfb4ff71e0b1 100644 --- a/sys/amd64/linux32/linux32_dummy_machdep.c +++ b/sys/amd64/linux32/linux32_dummy_machdep.c @@ -80,5 +80,4 @@ DUMMY(mq_timedsend_time64); DUMMY(mq_timedreceive_time64); DUMMY(semtimedop_time64); DUMMY(rt_sigtimedwait_time64); -DUMMY(futex_time64); DUMMY(sched_rr_get_interval_time64); diff --git a/sys/amd64/linux32/syscalls.master b/sys/amd64/linux32/syscalls.master index 03523f45ced6..bf2778bb91fd 100644 --- a/sys/amd64/linux32/syscalls.master +++ b/sys/amd64/linux32/syscalls.master @@ -2415,7 +2415,14 @@ int linux_rt_sigtimedwait_time64(void); } 422 AUE_NULL STD { - int linux_futex_time64(void); + int linux_sys_futex_time64( + uint32_t *uaddr, + l_int op, + uint32_t val, + struct l_timespec64 *timeout, + uint32_t *uaddr2, + uint32_t val3 + ); } 423 AUE_NULL STD { int linux_sched_rr_get_interval_time64(void); diff --git a/sys/compat/linux/linux_futex.c b/sys/compat/linux/linux_futex.c index 11836e93d71c..6d4c31a8a6df 100644 --- a/sys/compat/linux/linux_futex.c +++ b/sys/compat/linux/linux_futex.c @@ -117,29 +117,29 @@ LIN_SDT_PROBE_DEFINE4(futex, futex_atomic_op, decoded_op, "int", "int", "int", LIN_SDT_PROBE_DEFINE0(futex, futex_atomic_op, missing_access_check); LIN_SDT_PROBE_DEFINE1(futex, futex_atomic_op, unimplemented_op, "int"); LIN_SDT_PROBE_DEFINE1(futex, futex_atomic_op, unimplemented_cmp, "int"); -LIN_SDT_PROBE_DEFINE0(futex, linux_sys_futex, unimplemented_clockswitch); -LIN_SDT_PROBE_DEFINE1(futex, linux_sys_futex, copyin_error, "int"); -LIN_SDT_PROBE_DEFINE0(futex, linux_sys_futex, invalid_cmp_requeue_use); -LIN_SDT_PROBE_DEFINE3(futex, linux_sys_futex, debug_wait, "uint32_t *", +LIN_SDT_PROBE_DEFINE0(futex, linux_futex, unimplemented_clockswitch); +LIN_SDT_PROBE_DEFINE1(futex, linux_futex, copyin_error, "int"); +LIN_SDT_PROBE_DEFINE0(futex, linux_futex, invalid_cmp_requeue_use); +LIN_SDT_PROBE_DEFINE3(futex, linux_futex, debug_wait, "uint32_t *", "uint32_t", "uint32_t"); -LIN_SDT_PROBE_DEFINE4(futex, linux_sys_futex, debug_wait_value_neq, +LIN_SDT_PROBE_DEFINE4(futex, linux_futex, debug_wait_value_neq, "uint32_t *", "uint32_t", "int", "uint32_t"); -LIN_SDT_PROBE_DEFINE3(futex, linux_sys_futex, debug_wake, "uint32_t *", +LIN_SDT_PROBE_DEFINE3(futex, linux_futex, debug_wake, "uint32_t *", "uint32_t", "uint32_t"); -LIN_SDT_PROBE_DEFINE5(futex, linux_sys_futex, debug_cmp_requeue, "uint32_t *", +LIN_SDT_PROBE_DEFINE5(futex, linux_futex, debug_cmp_requeue, "uint32_t *", "uint32_t", "uint32_t", "uint32_t *", "struct l_timespec *"); -LIN_SDT_PROBE_DEFINE2(futex, linux_sys_futex, debug_cmp_requeue_value_neq, +LIN_SDT_PROBE_DEFINE2(futex, linux_futex, debug_cmp_requeue_value_neq, "uint32_t", "int"); -LIN_SDT_PROBE_DEFINE5(futex, linux_sys_futex, debug_wake_op, "uint32_t *", +LIN_SDT_PROBE_DEFINE5(futex, linux_futex, debug_wake_op, "uint32_t *", "int", "uint32_t", "uint32_t *", "uint32_t"); -LIN_SDT_PROBE_DEFINE0(futex, linux_sys_futex, unhandled_efault); -LIN_SDT_PROBE_DEFINE0(futex, linux_sys_futex, unimplemented_lock_pi); -LIN_SDT_PROBE_DEFINE0(futex, linux_sys_futex, unimplemented_unlock_pi); -LIN_SDT_PROBE_DEFINE0(futex, linux_sys_futex, unimplemented_trylock_pi); -LIN_SDT_PROBE_DEFINE0(futex, linux_sys_futex, deprecated_requeue); -LIN_SDT_PROBE_DEFINE0(futex, linux_sys_futex, unimplemented_wait_requeue_pi); -LIN_SDT_PROBE_DEFINE0(futex, linux_sys_futex, unimplemented_cmp_requeue_pi); -LIN_SDT_PROBE_DEFINE1(futex, linux_sys_futex, unknown_operation, "int"); +LIN_SDT_PROBE_DEFINE0(futex, linux_futex, unhandled_efault); +LIN_SDT_PROBE_DEFINE0(futex, linux_futex, unimplemented_lock_pi); +LIN_SDT_PROBE_DEFINE0(futex, linux_futex, unimplemented_unlock_pi); +LIN_SDT_PROBE_DEFINE0(futex, linux_futex, unimplemented_trylock_pi); +LIN_SDT_PROBE_DEFINE0(futex, linux_futex, deprecated_requeue); +LIN_SDT_PROBE_DEFINE0(futex, linux_futex, unimplemented_wait_requeue_pi); +LIN_SDT_PROBE_DEFINE0(futex, linux_futex, unimplemented_cmp_requeue_pi); +LIN_SDT_PROBE_DEFINE1(futex, linux_futex, unknown_operation, "int"); LIN_SDT_PROBE_DEFINE0(futex, linux_set_robust_list, size_error); LIN_SDT_PROBE_DEFINE1(futex, linux_get_robust_list, copyout_error, "int"); LIN_SDT_PROBE_DEFINE1(futex, handle_futex_death, copyin_error, "int"); @@ -215,8 +215,6 @@ static int futex_get(uint32_t *, struct waiting_proc **, struct futex **, static int futex_sleep(struct futex *, struct waiting_proc *, struct timespec *); static int futex_wake(struct futex *, int, uint32_t); static int futex_requeue(struct futex *, int, struct futex *, int); -static int futex_copyin_timeout(int, struct l_timespec *, int, - struct timespec *); static int futex_wait(struct futex *, struct waiting_proc *, struct timespec *, uint32_t); static void futex_lock(struct futex *); @@ -227,30 +225,17 @@ static int handle_futex_death(struct linux_emuldata *, uint32_t *, static int fetch_robust_entry(struct linux_robust_list **, struct linux_robust_list **, unsigned int *); -static int -futex_copyin_timeout(int op, struct l_timespec *luts, int clockrt, - struct timespec *ts) -{ - struct l_timespec lts; - struct timespec kts; - int error; - - error = copyin(luts, <s, sizeof(lts)); - if (error) - return (error); +struct linux_futex_args { + uint32_t *uaddr; + int32_t op; + uint32_t val; + struct timespec *ts; + uint32_t *uaddr2; + uint32_t val3; + struct timespec kts; +}; - error = linux_to_native_timespec(ts, <s); - if (error) - return (error); - if (clockrt) { - nanotime(&kts); - timespecsub(ts, &kts, ts); - } else if (op == LINUX_FUTEX_WAIT_BITSET) { - nanouptime(&kts); - timespecsub(ts, &kts, ts); - } - return (error); -} +static int linux_futex(struct thread *, struct linux_futex_args *); static void futex_put(struct futex *f, struct waiting_proc *wp) @@ -430,19 +415,17 @@ futex_unlock(struct futex *f) static int futex_sleep(struct futex *f, struct waiting_proc *wp, struct timespec *ts) { - struct timespec uts; sbintime_t sbt, prec, tmp; time_t over; int error; FUTEX_ASSERT_LOCKED(f); if (ts != NULL) { - uts = *ts; - if (uts.tv_sec > INT32_MAX / 2) { - over = uts.tv_sec - INT32_MAX / 2; - uts.tv_sec -= over; + if (ts->tv_sec > INT32_MAX / 2) { + over = ts->tv_sec - INT32_MAX / 2; + ts->tv_sec -= over; } - tmp = tstosbt(uts); + tmp = tstosbt(*ts); if (TIMESEL(&sbt, tmp)) sbt += tc_tick_sbt; sbt += tmp; @@ -655,14 +638,14 @@ futex_atomic_op(struct thread *td, int encoded_op, uint32_t *uaddr) return (ret); } -int -linux_sys_futex(struct thread *td, struct linux_sys_futex_args *args) +static int +linux_futex(struct thread *td, struct linux_futex_args *args) { int clockrt, nrwake, nrrequeue, op_ret, ret; struct linux_pemuldata *pem; struct waiting_proc *wp; struct futex *f, *f2; - struct timespec uts, *ts; + struct timespec kts; int error, save; uint32_t flags, val; @@ -682,7 +665,7 @@ linux_sys_futex(struct thread *td, struct linux_sys_futex_args *args) args->op = args->op & ~LINUX_FUTEX_CLOCK_REALTIME; if (clockrt && args->op != LINUX_FUTEX_WAIT_BITSET && args->op != LINUX_FUTEX_WAIT_REQUEUE_PI) { - LIN_SDT_PROBE0(futex, linux_sys_futex, + LIN_SDT_PROBE0(futex, linux_futex, unimplemented_clockswitch); return (ENOSYS); } @@ -696,22 +679,20 @@ linux_sys_futex(struct thread *td, struct linux_sys_futex_args *args) /* FALLTHROUGH */ case LINUX_FUTEX_WAIT_BITSET: - LIN_SDT_PROBE3(futex, linux_sys_futex, debug_wait, args->uaddr, + LIN_SDT_PROBE3(futex, linux_futex, debug_wait, args->uaddr, args->val, args->val3); LINUX_CTR3(sys_futex, "WAIT uaddr %p val 0x%x bitset 0x%x", args->uaddr, args->val, args->val3); - if (args->timeout != NULL) { - error = futex_copyin_timeout(args->op, args->timeout, - clockrt, &uts); - if (error) { - LIN_SDT_PROBE1(futex, linux_sys_futex, copyin_error, - error); - return (error); + if (args->ts != NULL) { + if (clockrt) { + nanotime(&kts); + timespecsub(args->ts, &kts, args->ts); + } else if (args->op == LINUX_FUTEX_WAIT_BITSET) { + nanouptime(&kts); + timespecsub(args->ts, &kts, args->ts); } - ts = &uts; - } else - ts = NULL; + } retry0: error = futex_get(args->uaddr, &wp, &f, @@ -725,14 +706,14 @@ retry0: error = copyin(args->uaddr, &val, sizeof(val)); if (error == 0) goto retry0; - LIN_SDT_PROBE1(futex, linux_sys_futex, copyin_error, + LIN_SDT_PROBE1(futex, linux_futex, copyin_error, error); LINUX_CTR1(sys_futex, "WAIT copyin failed %d", error); return (error); } if (val != args->val) { - LIN_SDT_PROBE4(futex, linux_sys_futex, + LIN_SDT_PROBE4(futex, linux_futex, debug_wait_value_neq, args->uaddr, args->val, val, args->val3); LINUX_CTR3(sys_futex, @@ -742,7 +723,7 @@ retry0: return (EWOULDBLOCK); } - error = futex_wait(f, wp, ts, args->val3); + error = futex_wait(f, wp, args->ts, args->val3); break; case LINUX_FUTEX_WAKE: @@ -750,7 +731,7 @@ retry0: /* FALLTHROUGH */ case LINUX_FUTEX_WAKE_BITSET: - LIN_SDT_PROBE3(futex, linux_sys_futex, debug_wake, args->uaddr, + LIN_SDT_PROBE3(futex, linux_futex, debug_wake, args->uaddr, args->val, args->val3); LINUX_CTR3(sys_futex, "WAKE uaddr %p nrwake 0x%x bitset 0x%x", args->uaddr, args->val, args->val3); @@ -769,25 +750,25 @@ retry0: break; case LINUX_FUTEX_CMP_REQUEUE: - LIN_SDT_PROBE5(futex, linux_sys_futex, debug_cmp_requeue, + LIN_SDT_PROBE5(futex, linux_futex, debug_cmp_requeue, args->uaddr, args->val, args->val3, args->uaddr2, - args->timeout); + args->ts); LINUX_CTR5(sys_futex, "CMP_REQUEUE uaddr %p " "nrwake 0x%x uval 0x%x uaddr2 %p nrequeue 0x%x", args->uaddr, args->val, args->val3, args->uaddr2, - args->timeout); + args->ts); /* * Linux allows this, we would not, it is an incorrect * usage of declared ABI, so return EINVAL. */ if (args->uaddr == args->uaddr2) { - LIN_SDT_PROBE0(futex, linux_sys_futex, + LIN_SDT_PROBE0(futex, linux_futex, invalid_cmp_requeue_use); return (EINVAL); } - nrrequeue = (int)(unsigned long)args->timeout; + nrrequeue = (int)(unsigned long)args->ts; nrwake = args->val; /* * Sanity check to prevent signed integer overflow, @@ -823,14 +804,14 @@ retry1: error = copyin(args->uaddr, &val, sizeof(val)); if (error == 0) goto retry1; - LIN_SDT_PROBE1(futex, linux_sys_futex, copyin_error, + LIN_SDT_PROBE1(futex, linux_futex, copyin_error, error); LINUX_CTR1(sys_futex, "CMP_REQUEUE copyin failed %d", error); return (error); } if (val != args->val3) { - LIN_SDT_PROBE2(futex, linux_sys_futex, + LIN_SDT_PROBE2(futex, linux_futex, debug_cmp_requeue_value_neq, args->val, val); LINUX_CTR2(sys_futex, "CMP_REQUEUE val 0x%x != uval 0x%x", args->val, val); @@ -845,12 +826,12 @@ retry1: break; case LINUX_FUTEX_WAKE_OP: - LIN_SDT_PROBE5(futex, linux_sys_futex, debug_wake_op, + LIN_SDT_PROBE5(futex, linux_futex, debug_wake_op, args->uaddr, args->op, args->val, args->uaddr2, args->val3); LINUX_CTR5(sys_futex, "WAKE_OP " "uaddr %p nrwake 0x%x uaddr2 %p op 0x%x nrwake2 0x%x", args->uaddr, args->val, args->uaddr2, args->val3, - args->timeout); + args->ts); if (args->uaddr == args->uaddr2) return (EINVAL); @@ -893,7 +874,7 @@ retry2: if (op_ret > 0) { op_ret = 0; - nrwake = (int)(unsigned long)args->timeout; + nrwake = (int)(unsigned long)args->ts; if (f2 != NULL) op_ret += futex_wake(f2, nrwake, args->val3); @@ -913,7 +894,7 @@ retry2: if ((pem->flags & LINUX_XUNSUP_FUTEXPIOP) == 0) { linux_msg(td, "unsupported FUTEX_LOCK_PI"); pem->flags |= LINUX_XUNSUP_FUTEXPIOP; - LIN_SDT_PROBE0(futex, linux_sys_futex, + LIN_SDT_PROBE0(futex, linux_futex, unimplemented_lock_pi); } return (ENOSYS); @@ -924,7 +905,7 @@ retry2: if ((pem->flags & LINUX_XUNSUP_FUTEXPIOP) == 0) { linux_msg(td, "unsupported FUTEX_UNLOCK_PI"); pem->flags |= LINUX_XUNSUP_FUTEXPIOP; - LIN_SDT_PROBE0(futex, linux_sys_futex, + LIN_SDT_PROBE0(futex, linux_futex, unimplemented_unlock_pi); } return (ENOSYS); @@ -935,7 +916,7 @@ retry2: if ((pem->flags & LINUX_XUNSUP_FUTEXPIOP) == 0) { linux_msg(td, "unsupported FUTEX_TRYLOCK_PI"); pem->flags |= LINUX_XUNSUP_FUTEXPIOP; - LIN_SDT_PROBE0(futex, linux_sys_futex, + LIN_SDT_PROBE0(futex, linux_futex, unimplemented_trylock_pi); } return (ENOSYS); @@ -951,7 +932,7 @@ retry2: if ((pem->flags & LINUX_XDEPR_REQUEUEOP) == 0) { linux_msg(td, "unsupported FUTEX_REQUEUE"); pem->flags |= LINUX_XDEPR_REQUEUEOP; - LIN_SDT_PROBE0(futex, linux_sys_futex, + LIN_SDT_PROBE0(futex, linux_futex, deprecated_requeue); } return (EINVAL); @@ -962,7 +943,7 @@ retry2: if ((pem->flags & LINUX_XUNSUP_FUTEXPIOP) == 0) { linux_msg(td, "unsupported FUTEX_WAIT_REQUEUE_PI"); pem->flags |= LINUX_XUNSUP_FUTEXPIOP; - LIN_SDT_PROBE0(futex, linux_sys_futex, + LIN_SDT_PROBE0(futex, linux_futex, unimplemented_wait_requeue_pi); } return (ENOSYS); @@ -973,14 +954,14 @@ retry2: if ((pem->flags & LINUX_XUNSUP_FUTEXPIOP) == 0) { linux_msg(td, "unsupported FUTEX_CMP_REQUEUE_PI"); pem->flags |= LINUX_XUNSUP_FUTEXPIOP; - LIN_SDT_PROBE0(futex, linux_sys_futex, + LIN_SDT_PROBE0(futex, linux_futex, unimplemented_cmp_requeue_pi); } return (ENOSYS); default: linux_msg(td, "unsupported futex op %d", args->op); - LIN_SDT_PROBE1(futex, linux_sys_futex, unknown_operation, + LIN_SDT_PROBE1(futex, linux_futex, unknown_operation, args->op); return (ENOSYS); } @@ -988,6 +969,75 @@ retry2: return (error); } +int +linux_sys_futex(struct thread *td, struct linux_sys_futex_args *args) +{ + struct linux_futex_args fargs = { + .uaddr = args->uaddr, + .op = args->op, + .val = args->val, + .ts = NULL, + .uaddr2 = args->uaddr2, + .val3 = args->val3, + }; + struct l_timespec lts; + int error; + + switch (args->op & LINUX_FUTEX_CMD_MASK) { + case LINUX_FUTEX_WAIT: + case LINUX_FUTEX_WAIT_BITSET: + if (args->timeout != NULL) { + error = copyin(args->timeout, <s, sizeof(lts)); + if (error != 0) + return (error); + error = linux_to_native_timespec(&fargs.kts, <s); + if (error != 0) + return (error); + fargs.ts = &fargs.kts; + } + break; + default: + fargs.ts = PTRIN(args->timeout); + } + return (linux_futex(td, &fargs)); +} + +#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) +int +linux_sys_futex_time64(struct thread *td, + struct linux_sys_futex_time64_args *args) +{ + struct linux_futex_args fargs = { + .uaddr = args->uaddr, + .op = args->op, + .val = args->val, + .ts = NULL, + .uaddr2 = args->uaddr2, + .val3 = args->val3, + }; + struct l_timespec64 lts; + int error; + + switch (args->op & LINUX_FUTEX_CMD_MASK) { + case LINUX_FUTEX_WAIT: + case LINUX_FUTEX_WAIT_BITSET: + if (args->timeout != NULL) { + error = copyin(args->timeout, <s, sizeof(lts)); + if (error != 0) + return (error); + error = linux_to_native_timespec64(&fargs.kts, <s); + if (error != 0) + return (error); + fargs.ts = &fargs.kts; + } + break; + default: + fargs.ts = PTRIN(args->timeout); + } + return (linux_futex(td, &fargs)); +} +#endif + int linux_set_robust_list(struct thread *td, struct linux_set_robust_list_args *args) { diff --git a/sys/compat/linux/linux_futex.h b/sys/compat/linux/linux_futex.h index bf546538c981..6ea873d98411 100644 --- a/sys/compat/linux/linux_futex.h +++ b/sys/compat/linux/linux_futex.h @@ -55,6 +55,9 @@ #define LINUX_FUTEX_PRIVATE_FLAG 128 #define LINUX_FUTEX_CLOCK_REALTIME 256 +#define LINUX_FUTEX_CMD_MASK ~(LINUX_FUTEX_PRIVATE_FLAG | \ + LINUX_FUTEX_CLOCK_REALTIME) + #define FUTEX_OP_SET 0 /* *(int *)UADDR2 = OPARG; */ #define FUTEX_OP_ADD 1 /* *(int *)UADDR2 += OPARG; */ #define FUTEX_OP_OR 2 /* *(int *)UADDR2 |= OPARG; */ diff --git a/sys/i386/linux/linux_dummy_machdep.c b/sys/i386/linux/linux_dummy_machdep.c index f679e090c7c1..78503b9453ee 100644 --- a/sys/i386/linux/linux_dummy_machdep.c +++ b/sys/i386/linux/linux_dummy_machdep.c @@ -82,5 +82,4 @@ DUMMY(mq_timedsend_time64); DUMMY(mq_timedreceive_time64); DUMMY(semtimedop_time64); DUMMY(rt_sigtimedwait_time64); -DUMMY(futex_time64); DUMMY(sched_rr_get_interval_time64); diff --git a/sys/i386/linux/syscalls.master b/sys/i386/linux/syscalls.master index a60129ccdaa9..d78f000530e3 100644 --- a/sys/i386/linux/syscalls.master +++ b/sys/i386/linux/syscalls.master @@ -2433,7 +2433,14 @@ int linux_rt_sigtimedwait_time64(void); } 422 AUE_NULL STD { - int linux_futex_time64(void); + int linux_sys_futex_time64( + uint32_t *uaddr, + l_int op, + uint32_t val, + struct l_timespec64 *timeout, + uint32_t *uaddr2, + uint32_t val3 + ); } 423 AUE_NULL STD { int linux_sched_rr_get_interval_time64(void);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202206171931.25HJVnZR007636>