futex: Bugfixes and FUTEX_LOCK_PI2
Subsystems (2)
cover futex: Bugfixes and FUTEX_LOCK_PI2
The following series started off looking into supporting selectable clocks for FUTEX_LOCK_PI which is hardcoded to CLOCK_REALTIME and cannot be changed.
On the way I found two bugs related to the timeout handling:
- The allowance for FUTEX_WAIT to use FUTEX_CLOCK_REALTIME is broken and never worked.
- The recent time namespace support wreckaged FUTEX_LOCK_PI timeouts when the task belongs to a namespace which has an CLOCK_MONOTONIC offset.
Both should have been caught by that Gleixner dude when merging them, but it seems he's getting old.
Not having a selectable clock for PI futexes is inconsistent because all other interfaces have it. Unfortunately this was figured out by glibc folks quite some time ago, but nobody told us :(
The nasty hack to support it would be to treat FUTEX_CLOCK_REALTIME inverse for FUTEX_LOCK_PI, but that's a horrible idea. Adding a new flag to the futex op, i.e. FUTEX_CLOCK_MONOTONIC would be possible, but that's yet another variant which makes is harder for libraries to have a consistent clock selection handling.
So I went the way to let FUTEX_LOCK_PI alone and to add FUTEX_LOCK_PI2 which handles the clocks the same way as the other operands.
Thoughts?
The series is also available from git:
git://git.kernel.org/pub/scm/linux/kernel/git/tglx/devel.git futex
Thanks,
tglx
--- include/uapi/linux/futex.h | 1 kernel/futex.c | 89 +++++++++++++++++++++++---------------------- 2 files changed, 47 insertions(+), 43 deletions(-)
PATCH 1/6 Revert 337f13046ff0 ("futex: Allow FUTEX_CLOCK_REALTIME with FUTEX_WAIT op")
The FUTEX_WAIT operand has historically a relative timeout which means that the clock id is irrelevant as relative timeouts on CLOCK_REALTIME are not subject to wall clock changes and therefore are mapped by the kernel to CLOCK_MONOTONIC for simplicity.
If a caller would set FUTEX_CLOCK_REALTIME for FUTEX_WAIT the timeout is still treated relative vs. CLOCK_MONOTONIC and then the wait arms that timeout based on CLOCK_REALTIME which is broken and obviously has never been used or even tested.
Reject any attempt to use FUTEX_CLOCK_REALTIME with FUTEX_WAIT again.
The desired functionality can be achieved with FUTEX_WAIT_BITSET and a FUTEX_BITSET_MATCH_ANY argument.
--- kernel/futex.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
kernel/futex.c +1 -2
@@ -3711,8 +3711,7 @@ long do_futex(u32 __user *uaddr, int op,if (op &FUTEX_CLOCK_REALTIME ) { flags |=FLAGS_CLOCKRT ; -if (cmd !=FUTEX_WAIT && cmd !=FUTEX_WAIT_BITSET && \ - cmd !=FUTEX_WAIT_REQUEUE_PI ) +if (cmd !=FUTEX_WAIT_BITSET && cmd !=FUTEX_WAIT_REQUEUE_PI )return -ENOSYS ; }
[tip: locking/urgent] Revert 337f13046ff0 ("futex: Allow FUTEX_CLOCK_REALTIME with FUTEX_WAIT op")
The following commit has been merged into the locking/urgent branch of tip:
The following commit has been merged into the locking/urgent branch of tip:
Commit-ID: 4fbf5d6837bf81fd7a27d771358f4ee6c4f243f8 Gitweb: https://git.kernel.org/tip/4fbf5d6837bf81fd7a27d771358f4ee6c4f243f8 Author: Thomas Gleixner <[email protected]> AuthorDate: Thu, 22 Apr 2021 21:44:18 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Thu, 06 May 2021 20:12:40 +02:00
Revert 337f13046ff0 ("futex: Allow FUTEX_CLOCK_REALTIME with FUTEX_WAIT op")
The FUTEX_WAIT operand has historically a relative timeout which means that the clock id is irrelevant as relative timeouts on CLOCK_REALTIME are not subject to wall clock changes and therefore are mapped by the kernel to CLOCK_MONOTONIC for simplicity.
If a caller would set FUTEX_CLOCK_REALTIME for FUTEX_WAIT the timeout is still treated relative vs. CLOCK_MONOTONIC and then the wait arms that timeout based on CLOCK_REALTIME which is broken and obviously has never been used or even tested.
Reject any attempt to use FUTEX_CLOCK_REALTIME with FUTEX_WAIT again.
The desired functionality can be achieved with FUTEX_WAIT_BITSET and a FUTEX_BITSET_MATCH_ANY argument.
--- kernel/futex.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
kernel/futex.c +1 -2
@@ -3710,8 +3710,7 @@ long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,if (op &FUTEX_CLOCK_REALTIME ) { flags |=FLAGS_CLOCKRT ; -if (cmd !=FUTEX_WAIT && cmd !=FUTEX_WAIT_BITSET && \ - cmd !=FUTEX_WAIT_REQUEUE_PI ) +if (cmd !=FUTEX_WAIT_BITSET && cmd !=FUTEX_WAIT_REQUEUE_PI )return -ENOSYS ; }
PATCH 2/6 futex: Do not apply time namespace adjustment on FUTEX_LOCK_PI
In reply to Thomas GleixnerFUTEX_LOCK_PI does not require to have the FUTEX_CLOCK_REALTIME bit set because it has been using CLOCK_REALTIME based absolute timeouts forever. Due to that, the time namespace adjustment which is applied when FUTEX_CLOCK_REALTIME is not set, will wrongly take place for FUTEX_LOCK_PI and wreckage the timeout.
Exclude it from that procedure.
--- kernel/futex.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
kernel/futex.c +2 -2
@@ -3781,7 +3781,7 @@ SYSCALL_DEFINE6(futex, u32 __user *, uad t =timespec64_to_ktime (ts);if (cmd ==FUTEX_WAIT ) t =ktime_add_safe (ktime_get (), t); -else if (!(op &FUTEX_CLOCK_REALTIME )) +else if (cmd !=FUTEX_LOCK_PI && !(op &FUTEX_CLOCK_REALTIME )) t =timens_ktime_to_host (CLOCK_MONOTONIC , t); tp = &t; }
@@ -3975,7 +3975,7 @@ SYSCALL_DEFINE6(futex_time32, u32 __user t =timespec64_to_ktime (ts);if (cmd ==FUTEX_WAIT ) t =ktime_add_safe (ktime_get (), t); -else if (!(op &FUTEX_CLOCK_REALTIME )) +else if (cmd !=FUTEX_LOCK_PI && !(op &FUTEX_CLOCK_REALTIME )) t =timens_ktime_to_host (CLOCK_MONOTONIC , t); tp = &t; }
[tip: locking/urgent] futex: Do not apply time namespace adjustment on FUTEX_LOCK_PI
The following commit has been merged into the locking/urgent branch of tip:
The following commit has been merged into the locking/urgent branch of tip:
Commit-ID: cdf78db4070967869e4d027c11f4dd825d8f815a Gitweb: https://git.kernel.org/tip/cdf78db4070967869e4d027c11f4dd825d8f815a Author: Thomas Gleixner <[email protected]> AuthorDate: Thu, 22 Apr 2021 21:44:19 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Thu, 06 May 2021 20:12:40 +02:00
futex: Do not apply time namespace adjustment on FUTEX_LOCK_PI
FUTEX_LOCK_PI does not require to have the FUTEX_CLOCK_REALTIME bit set because it has been using CLOCK_REALTIME based absolute timeouts forever. Due to that, the time namespace adjustment which is applied when FUTEX_CLOCK_REALTIME is not set, will wrongly take place for FUTEX_LOCK_PI and wreckage the timeout.
Exclude it from that procedure.
--- kernel/futex.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
kernel/futex.c +2 -2
@@ -3780,7 +3780,7 @@ SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val, t =timespec64_to_ktime (ts);if (cmd ==FUTEX_WAIT ) t =ktime_add_safe (ktime_get (), t); -else if (!(op &FUTEX_CLOCK_REALTIME )) +else if (cmd !=FUTEX_LOCK_PI && !(op &FUTEX_CLOCK_REALTIME )) t =timens_ktime_to_host (CLOCK_MONOTONIC , t); tp = &t; }
@@ -3974,7 +3974,7 @@ SYSCALL_DEFINE6(futex_time32, u32 __user *, uaddr, int, op, u32, val, t =timespec64_to_ktime (ts);if (cmd ==FUTEX_WAIT ) t =ktime_add_safe (ktime_get (), t); -else if (!(op &FUTEX_CLOCK_REALTIME )) +else if (cmd !=FUTEX_LOCK_PI && !(op &FUTEX_CLOCK_REALTIME )) t =timens_ktime_to_host (CLOCK_MONOTONIC , t); tp = &t; }
PATCH 3/6 futex: Get rid of the val2 conditional dance
In reply to Thomas GleixnerThere is no point in checking which FUTEX operand treats the utime pointer as 'val2' argument because that argument to do_futex() is only used by exactly these operands.
So just handing it in unconditionally is not making any difference, but removes a lot of pointless gunk.
--- kernel/futex.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-)
kernel/futex.c +2 -14
@@ -3765,7 +3765,6 @@ SYSCALL_DEFINE6(futex, u32 __user *, uad {struct timespec64 ts;ktime_t t, *tp =NULL ; -u32 val2 =0 ;int cmd = op &FUTEX_CMD_MASK ; if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI ||
@@ -3785,15 +3784,8 @@ SYSCALL_DEFINE6(futex, u32 __user *, uad t =timens_ktime_to_host (CLOCK_MONOTONIC , t); tp = &t; } -/* -* requeue parameter in 'utime' if cmd == FUTEX_*_REQUEUE_*. -* number of waiters to wake in 'utime' if cmd == FUTEX_WAKE_OP. -*/ -if (cmd ==FUTEX_REQUEUE || cmd ==FUTEX_CMP_REQUEUE || - cmd ==FUTEX_CMP_REQUEUE_PI || cmd ==FUTEX_WAKE_OP ) - val2 = (u32 ) (unsigned long ) utime; -return do_futex (uaddr, op, val, tp, uaddr2, val2, val3); +return do_futex (uaddr, op, val, tp, uaddr2, (unsigned long )utime, val3); }#ifdef CONFIG_COMPAT
@@ -3961,7 +3953,6 @@ SYSCALL_DEFINE6(futex_time32, u32 __user {struct timespec64 ts;ktime_t t, *tp =NULL ; -int val2 =0 ;int cmd = op &FUTEX_CMD_MASK ; if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI ||
@@ -3979,11 +3970,8 @@ SYSCALL_DEFINE6(futex_time32, u32 __user t =timens_ktime_to_host (CLOCK_MONOTONIC , t); tp = &t; } -if (cmd ==FUTEX_REQUEUE || cmd ==FUTEX_CMP_REQUEUE || - cmd ==FUTEX_CMP_REQUEUE_PI || cmd ==FUTEX_WAKE_OP ) - val2 = (int ) (unsigned long ) utime; -return do_futex (uaddr, op, val, tp, uaddr2, val2, val3); +return do_futex (uaddr, op, val, tp, uaddr2, (unsigned long )utime, val3); }#endif /* CONFIG_COMPAT_32BIT_TIME */
Re: [patch 3/6] futex: Get rid of the val2 conditional dance
Hi Thomas,
Às 16:44 de 22/04/21, Thomas Gleixner escreveu:
Quoted 26 lines
There is no point in checking which FUTEX operand treats the utime pointer as 'val2' argument because that argument to
do_futex()is only used by exactly these operands.So just handing it in unconditionally is not making any difference, but removes a lot of pointless gunk.
Signed-off-by Thomas Gleixner <[email protected]>--- kernel/futex.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-)kernel/futex.c +0
-1@@ -3765,7 +3765,6 @@ SYSCALL_DEFINE6(futex, u32 __user *, uad {struct timespec64 ts;ktime_t t, *tp =NULL ; -u32 val2 =0 ;int cmd = op &FUTEX_CMD_MASK ; if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI ||@@ -3785,15 +3784,8 @@ SYSCALL_DEFINE6(futex, u32 __user *, uad t =timens_ktime_to_host (CLOCK_MONOTONIC , t); tp = &t; }
kernel/futex.c SYSCALL_DEFINE6(futex, u32 __user *, uad · line 3788
Quoted 10 lines
kernel/futex.c +1
-8-/* -* requeue parameter in 'utime' if cmd == FUTEX_*_REQUEUE_*. -* number of waiters to wake in 'utime' if cmd == FUTEX_WAKE_OP. -*/ -if (cmd ==FUTEX_REQUEUE || cmd ==FUTEX_CMP_REQUEUE || - cmd ==FUTEX_CMP_REQUEUE_PI || cmd ==FUTEX_WAKE_OP ) - val2 = (u32 ) (unsigned long ) utime; -return do_futex (uaddr, op, val, tp, uaddr2, val2, val3); +return do_futex (uaddr, op, val, tp, uaddr2, (unsigned long )utime, val3);
Given do_futex()'s type signature, I think it makes more sense to cast utime to u32.
Quoted 12 lines
kernel/futex.c +0
-1}#ifdef CONFIG_COMPAT @@ -3961,7 +3953,6 @@ SYSCALL_DEFINE6(futex_time32, u32 __user {struct timespec64 ts;ktime_t t, *tp =NULL ; -int val2 =0 ;int cmd = op &FUTEX_CMD_MASK ; if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI ||
kernel/futex.c SYSCALL_DEFINE6(futex_time32, u32 __user · line 3974
Quoted 9 lines
kernel/futex.c +1
-4@@ -3979,11 +3970,8 @@ SYSCALL_DEFINE6(futex_time32, u32 __user t =timens_ktime_to_host (CLOCK_MONOTONIC , t); tp = &t; } -if (cmd ==FUTEX_REQUEUE || cmd ==FUTEX_CMP_REQUEUE || - cmd ==FUTEX_CMP_REQUEUE_PI || cmd ==FUTEX_WAKE_OP ) - val2 = (int ) (unsigned long ) utime; -return do_futex (uaddr, op, val, tp, uaddr2, val2, val3); +return do_futex (uaddr, op, val, tp, uaddr2, (unsigned long )utime, val3);
Same here.
Quoted 4 lines
kernel/futex.c +0
-0}#endif /* CONFIG_COMPAT_32BIT_TIME */
Re: [patch 3/6] futex: Get rid of the val2 conditional dance
Quoted 6 lines · André Almeida
Review
Quoted 3 lines
(quoted diff) +1
-1- return do_futex(uaddr, op, val, tp, uaddr2, val2, val3); + return do_futex(uaddr, op, val, tp, uaddr2, (unsigned long)utime, val3);Given do_futex()'s type signature, I think it makes more sense to cast utime to u32.
It's a pointer which you better force cast to unsigned long first.
So the explicit thing would be '(u32)(unsigned long) utime' which is what the val2 dance stupidly did with 'int'
val2 = (int) (unsigned long) utime;
But with doing it at function call argument it's implicit, because the
unsigned long to u32 conversion is well defined
while
(u32)ptr
is only well defined on 32bit.
Thanks,
tglx
Re: [patch 3/6] futex: Get rid of the val2 conditional dance
Às 19:34 de 23/04/21, Thomas Gleixner escreveu:
Quoted 17 lines · André Almeida
Quoted 6 lines
Review
Quoted 3 lines
(quoted diff) +1
-1- return do_futex(uaddr, op, val, tp, uaddr2, val2, val3); + return do_futex(uaddr, op, val, tp, uaddr2, (unsigned long)utime, val3);Given do_futex()'s type signature, I think it makes more sense to cast utime to u32.
It's a pointer which you better force cast to unsigned long first.
So the explicit thing would be '(u32)(unsigned long) utime' which is what the val2 dance stupidly did with 'int'
val2 = (int) (unsigned long) utime;But with doing it at function call argument it's implicit, because the
Quoted 8 lines
unsigned long to u32 conversion is well defined
while
(u32)ptris only well defined on 32bit.
I see, thank you for the clarification!
Quoted 4 lines
Thanks,
tglx
[tip: locking/urgent] futex: Get rid of the val2 conditional dance
In reply to Thomas GleixnerThe following commit has been merged into the locking/urgent branch of tip:
The following commit has been merged into the locking/urgent branch of tip:
Commit-ID: b097d5ed33561507eeffc77120a8c16c2f0f2c4c Gitweb: https://git.kernel.org/tip/b097d5ed33561507eeffc77120a8c16c2f0f2c4c Author: Thomas Gleixner <[email protected]> AuthorDate: Thu, 22 Apr 2021 21:44:20 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Thu, 06 May 2021 20:19:04 +02:00
futex: Get rid of the val2 conditional dance
There is no point in checking which FUTEX operand treats the utime pointer as 'val2' argument because that argument to do_futex() is only used by exactly these operands.
So just handing it in unconditionally is not making any difference, but removes a lot of pointless gunk.
--- kernel/futex.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-)
kernel/futex.c +2 -14
@@ -3764,7 +3764,6 @@ SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val, {struct timespec64 ts;ktime_t t, *tp =NULL ; -u32 val2 =0 ;int cmd = op &FUTEX_CMD_MASK ; if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI ||
@@ -3784,15 +3783,8 @@ SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val, t =timens_ktime_to_host (CLOCK_MONOTONIC , t); tp = &t; } -/* -* requeue parameter in 'utime' if cmd == FUTEX_*_REQUEUE_*. -* number of waiters to wake in 'utime' if cmd == FUTEX_WAKE_OP. -*/ -if (cmd ==FUTEX_REQUEUE || cmd ==FUTEX_CMP_REQUEUE || - cmd ==FUTEX_CMP_REQUEUE_PI || cmd ==FUTEX_WAKE_OP ) - val2 = (u32 ) (unsigned long ) utime; -return do_futex (uaddr, op, val, tp, uaddr2, val2, val3); +return do_futex (uaddr, op, val, tp, uaddr2, (unsigned long )utime, val3); }#ifdef CONFIG_COMPAT
@@ -3960,7 +3952,6 @@ SYSCALL_DEFINE6(futex_time32, u32 __user *, uaddr, int, op, u32, val, {struct timespec64 ts;ktime_t t, *tp =NULL ; -int val2 =0 ;int cmd = op &FUTEX_CMD_MASK ; if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI ||
@@ -3978,11 +3969,8 @@ SYSCALL_DEFINE6(futex_time32, u32 __user *, uaddr, int, op, u32, val, t =timens_ktime_to_host (CLOCK_MONOTONIC , t); tp = &t; } -if (cmd ==FUTEX_REQUEUE || cmd ==FUTEX_CMP_REQUEUE || - cmd ==FUTEX_CMP_REQUEUE_PI || cmd ==FUTEX_WAKE_OP ) - val2 = (int ) (unsigned long ) utime; -return do_futex (uaddr, op, val, tp, uaddr2, val2, val3); +return do_futex (uaddr, op, val, tp, uaddr2, (unsigned long )utime, val3); }#endif /* CONFIG_COMPAT_32BIT_TIME */
PATCH 4/6 futex: Make syscall entry points less convoluted
In reply to Thomas GleixnerThe futex and the compat syscall entry points do pretty much the same except for the timespec data types and the corresponding copy from user function.
Split out the rest into inline functions and share the functionality.
--- kernel/futex.c | 63 +++++++++++++++++++++++++++++++++------------------------ 1 file changed, 37 insertions(+), 26 deletions(-)
kernel/futex.c +37 -26
@@ -3758,30 +3758,48 @@ long do_futex(u32 __user *uaddr, int op,return -ENOSYS ; } +static __always_inline bool futex_cmd_has_timeout(u32 cmd) +{ +switch (cmd) { +case FUTEX_WAIT : +case FUTEX_LOCK_PI : +case FUTEX_WAIT_BITSET : +case FUTEX_WAIT_REQUEUE_PI : +return true; + } +return false; +} + +static __always_inline int +futex_init_timeout (u32 cmd,u32 op,struct timespec64 *ts,ktime_t *t) +{ +if (!timespec64_valid (ts)) +return -EINVAL ; + + *t =timespec64_to_ktime (*ts); +if (cmd ==FUTEX_WAIT ) + *t =ktime_add_safe (ktime_get (), *t); +else if (cmd !=FUTEX_LOCK_PI && !(op &FUTEX_CLOCK_REALTIME )) + *t =timens_ktime_to_host (CLOCK_MONOTONIC , *t); +return 0 ; +} SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val, const struct __kernel_timespec __user *, utime, u32 __user *, uaddr2, u32, val3) { -struct timespec64 ts; +int ret, cmd = op &FUTEX_CMD_MASK ;ktime_t t, *tp =NULL ; -int cmd = op &FUTEX_CMD_MASK ; +struct timespec64 ts; -if (utime && (cmd ==FUTEX_WAIT || cmd ==FUTEX_LOCK_PI || - cmd ==FUTEX_WAIT_BITSET || - cmd ==FUTEX_WAIT_REQUEUE_PI )) { +if (utime &&futex_cmd_has_timeout (cmd)) {if (unlikely (should_fail_futex (!(op &FUTEX_PRIVATE_FLAG ))))return -EFAULT ;if (get_timespec64 (&ts, utime))return -EFAULT ; -if (!timespec64_valid (&ts)) -return -EINVAL ; - - t =timespec64_to_ktime (ts); -if (cmd ==FUTEX_WAIT ) - t =ktime_add_safe (ktime_get (), t); -else if (cmd !=FUTEX_LOCK_PI && !(op &FUTEX_CLOCK_REALTIME )) - t =timens_ktime_to_host (CLOCK_MONOTONIC , t); + ret =futex_init_timeout (cmd, op, &ts, &t); +if (ret) +return ret; tp = &t; }
@@ -3951,23 +3969,16 @@ SYSCALL_DEFINE6(futex_time32, u32 __user const struct old_timespec32 __user *, utime, u32 __user *, uaddr2, u32, val3) { - struct timespec64 ts; + int ret, cmd = op & FUTEX_CMD_MASK;ktime_t t, *tp =NULL ; -int cmd = op &FUTEX_CMD_MASK ; +struct timespec64 ts; -if (utime && (cmd ==FUTEX_WAIT || cmd ==FUTEX_LOCK_PI || - cmd ==FUTEX_WAIT_BITSET || - cmd ==FUTEX_WAIT_REQUEUE_PI )) { +if (utime &&futex_cmd_has_timeout (cmd)) {if (get_old_timespec32 (&ts, utime))return -EFAULT ; -if (!timespec64_valid (&ts)) -return -EINVAL ; - - t =timespec64_to_ktime (ts); -if (cmd ==FUTEX_WAIT ) - t =ktime_add_safe (ktime_get (), t); -else if (cmd !=FUTEX_LOCK_PI && !(op &FUTEX_CLOCK_REALTIME )) - t =timens_ktime_to_host (CLOCK_MONOTONIC , t); + ret =futex_init_timeout (cmd, op, &ts, &t); +if (ret) +return ret; tp = &t; }
[tip: locking/urgent] futex: Make syscall entry points less convoluted
The following commit has been merged into the locking/urgent branch of tip:
The following commit has been merged into the locking/urgent branch of tip:
Commit-ID: 51cf94d16860a324e97d1b670d88f1f2b643bc32 Gitweb: https://git.kernel.org/tip/51cf94d16860a324e97d1b670d88f1f2b643bc32 Author: Thomas Gleixner <[email protected]> AuthorDate: Thu, 22 Apr 2021 21:44:21 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Thu, 06 May 2021 20:19:04 +02:00
futex: Make syscall entry points less convoluted
The futex and the compat syscall entry points do pretty much the same except for the timespec data types and the corresponding copy from user function.
Split out the rest into inline functions and share the functionality.
--- kernel/futex.c | 63 ++++++++++++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 26 deletions(-)
kernel/futex.c +37 -26
@@ -3757,30 +3757,48 @@ long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,return -ENOSYS ; } +static __always_inline bool futex_cmd_has_timeout(u32 cmd) +{ +switch (cmd) { +case FUTEX_WAIT : +case FUTEX_LOCK_PI : +case FUTEX_WAIT_BITSET : +case FUTEX_WAIT_REQUEUE_PI : +return true; + } +return false; +} + +static __always_inline int +futex_init_timeout (u32 cmd,u32 op,struct timespec64 *ts,ktime_t *t) +{ +if (!timespec64_valid (ts)) +return -EINVAL ; + + *t =timespec64_to_ktime (*ts); +if (cmd ==FUTEX_WAIT ) + *t =ktime_add_safe (ktime_get (), *t); +else if (cmd !=FUTEX_LOCK_PI && !(op &FUTEX_CLOCK_REALTIME )) + *t =timens_ktime_to_host (CLOCK_MONOTONIC , *t); +return 0 ; +} SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val, const struct __kernel_timespec __user *, utime, u32 __user *, uaddr2, u32, val3) { -struct timespec64 ts; +int ret, cmd = op &FUTEX_CMD_MASK ;ktime_t t, *tp =NULL ; -int cmd = op &FUTEX_CMD_MASK ; +struct timespec64 ts; -if (utime && (cmd ==FUTEX_WAIT || cmd ==FUTEX_LOCK_PI || - cmd ==FUTEX_WAIT_BITSET || - cmd ==FUTEX_WAIT_REQUEUE_PI )) { +if (utime &&futex_cmd_has_timeout (cmd)) {if (unlikely (should_fail_futex (!(op &FUTEX_PRIVATE_FLAG ))))return -EFAULT ;if (get_timespec64 (&ts, utime))return -EFAULT ; -if (!timespec64_valid (&ts)) -return -EINVAL ; - - t =timespec64_to_ktime (ts); -if (cmd ==FUTEX_WAIT ) - t =ktime_add_safe (ktime_get (), t); -else if (cmd !=FUTEX_LOCK_PI && !(op &FUTEX_CLOCK_REALTIME )) - t =timens_ktime_to_host (CLOCK_MONOTONIC , t); + ret =futex_init_timeout (cmd, op, &ts, &t); +if (ret) +return ret; tp = &t; }
@@ -3950,23 +3968,16 @@ SYSCALL_DEFINE6(futex_time32, u32 __user *, uaddr, int, op, u32, val, const struct old_timespec32 __user *, utime, u32 __user *, uaddr2, u32, val3) { - struct timespec64 ts; + int ret, cmd = op & FUTEX_CMD_MASK;ktime_t t, *tp =NULL ; -int cmd = op &FUTEX_CMD_MASK ; +struct timespec64 ts; -if (utime && (cmd ==FUTEX_WAIT || cmd ==FUTEX_LOCK_PI || - cmd ==FUTEX_WAIT_BITSET || - cmd ==FUTEX_WAIT_REQUEUE_PI )) { +if (utime &&futex_cmd_has_timeout (cmd)) {if (get_old_timespec32 (&ts, utime))return -EFAULT ; -if (!timespec64_valid (&ts)) -return -EINVAL ; - - t =timespec64_to_ktime (ts); -if (cmd ==FUTEX_WAIT ) - t =ktime_add_safe (ktime_get (), t); -else if (cmd !=FUTEX_LOCK_PI && !(op &FUTEX_CLOCK_REALTIME )) - t =timens_ktime_to_host (CLOCK_MONOTONIC , t); + ret =futex_init_timeout (cmd, op, &ts, &t); +if (ret) +return ret; tp = &t; }
PATCH 5/6 futex: Prepare futex_lock_pi() for runtime clock selection
In reply to Thomas Gleixnerfutex_lock_pi() is the only futex operation which cannot select the clock for timeouts (CLOCK_MONOTONIC/CLOCK_REALTIME). That's inconsistent and there is no particular reason why this cannot be supported.
This was overlooked when CLOCK_REALTIME_FLAG was introduced and unfortunately not reported when the inconsistency was discovered in glibc.
Prepare the function and enforce the CLOCK_REALTIME_FLAG on FUTEX_LOCK_PI so that a new FUTEX_LOCK_PI2 can implement it correctly.
--- kernel/futex.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
kernel/futex.c +3 -2
@@ -2786,7 +2786,7 @@ static int futex_lock_pi(u32 __user *uadif (refill_pi_state_cache ())return -ENOMEM ; - to =futex_setup_timer (time, &timeout,FLAGS_CLOCKRT ,0 ); + to =futex_setup_timer (time, &timeout, flags,0 ); retry: ret =get_futex_key (uaddr, flags &FLAGS_SHARED , &q.key,FUTEX_WRITE );
@@ -3711,7 +3711,7 @@ long do_futex(u32 __user *uaddr, int op,if (op &FUTEX_CLOCK_REALTIME ) { flags |=FLAGS_CLOCKRT ; -if (cmd !=FUTEX_WAIT_BITSET && cmd !=FUTEX_WAIT_REQUEUE_PI ) +if (cmd !=FUTEX_WAIT_BITSET && cmd !=FUTEX_WAIT_REQUEUE_PI )return -ENOSYS ; }
@@ -3743,6 +3743,7 @@ long do_futex(u32 __user *uaddr, int op,case FUTEX_WAKE_OP :return futex_wake_op (uaddr, flags, uaddr2, val, val2, val3);case FUTEX_LOCK_PI : + flags |=FLAGS_CLOCKRT ;return futex_lock_pi (uaddr, flags, timeout,0 );case FUTEX_UNLOCK_PI :return futex_unlock_pi (uaddr, flags);
Re: [patch 5/6] futex: Prepare futex_lock_pi() for runtime clock selection
Hi Thomas,
Quoted 36 lines
futex_lock_pi()is the only futex operation which cannot select the clock for timeouts (CLOCK_MONOTONIC/CLOCK_REALTIME). That's inconsistent and there is no particular reason why this cannot be supported.This was overlooked when
CLOCK_REALTIME_FLAGwas introduced and unfortunately not reported when the inconsistency was discovered in glibc.Prepare the function and enforce the
CLOCK_REALTIME_FLAGonFUTEX_LOCK_PIso that a newFUTEX_LOCK_PI2can implement it correctly.Reported-by Kurt Kanzenbach <[email protected]>Signed-off-by Thomas Gleixner <[email protected]>--- kernel/futex.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)kernel/futex.c +1
-1@@ -2786,7 +2786,7 @@ static int futex_lock_pi(u32 __user *uadif (refill_pi_state_cache ())return -ENOMEM ; - to =futex_setup_timer (time, &timeout,FLAGS_CLOCKRT ,0 ); + to =futex_setup_timer (time, &timeout, flags,0 ); retry: ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &q.key,
FUTEX_WRITE); @@ -3711,7 +3711,7 @@ long do_futex(u32__user*uaddr, int op,kernel/futex.c +0
-1if (op &FUTEX_CLOCK_REALTIME ) { flags |=FLAGS_CLOCKRT ; - if (cmd != FUTEX_WAIT_BITSET && cmd !=
FUTEX_WAIT_REQUEUE_PI)kernel/futex.c +1
-0+ if (cmd != FUTEX_WAIT_BITSET && cmd !=
Quoted 1 line
FUTEX_WAIT_REQUEUE_PI) return-ENOSYS;
What is the exact change for those two lines above? Looks like some different tab/spaces...
kernel/futex.c long do_futex(u32 __user *uaddr, int op, · line 3749
Quoted 11 lines
kernel/futex.c +0
-0}@@ -3743,6 +3743,7 @@ long do_futex(u32 __user *uaddr, int op,case FUTEX_WAKE_OP : return futex_wake_op(uaddr, flags, uaddr2, val,val2, val3); case
FUTEX_LOCK_PI:kernel/futex.c +1
-0+ flags |=FLAGS_CLOCKRT ;return futex_lock_pi (uaddr, flags, timeout,0 );case FUTEX_UNLOCK_PI :return futex_unlock_pi (uaddr, flags);
Best regards,
Lukasz Majewski
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-59 Fax: (+49)-8142-66989-80 Email: [email protected]
Re: [patch 5/6] futex: Prepare futex_lock_pi() for runtime clock selection
Quoted 4 lines · Lukasz Majewski
Quoted 4 lines
ret = get_futex_key(uaddr, flags &
FLAGS_SHARED, &q.key,FUTEX_WRITE); @@ -3711,7 +3711,7 @@ long do_futex(u32__user*uaddr, int op,
if (op &FUTEX_CLOCK_REALTIME) {
Quoted 8 lines
Quoted 5 lines
(quoted diff) +0
-1flags |= FLAGS_CLOCKRT; - if (cmd != FUTEX_WAIT_BITSET && cmd !=
FUTEX_WAIT_REQUEUE_PI)(quoted diff) +1
-0+ if (cmd != FUTEX_WAIT_BITSET && cmd !=
FUTEX_WAIT_REQUEUE_PI) return-ENOSYS;What is the exact change for those two lines above? Looks like some different tab/spaces...
Oops. Yes. I surely stared at every hunk more than once...
[tip: locking/core] futex: Prepare futex_lock_pi() for runtime clock selection
In reply to Thomas GleixnerThe following commit has been merged into the locking/core branch of tip:
The following commit has been merged into the locking/core branch of tip:
Commit-ID: e112c41341c03d9224a9fc522bdb3539bc849b56 Gitweb: https://git.kernel.org/tip/e112c41341c03d9224a9fc522bdb3539bc849b56 Author: Thomas Gleixner <[email protected]> AuthorDate: Thu, 22 Apr 2021 21:44:22 +02:00 Committer: Peter Zijlstra <[email protected]> CommitterDate: Tue, 22 Jun 2021 16:42:08 +02:00
futex: Prepare futex_lock_pi() for runtime clock selection
futex_lock_pi() is the only futex operation which cannot select the clock for timeouts (CLOCK_MONOTONIC/CLOCK_REALTIME). That's inconsistent and there is no particular reason why this cannot be supported.
This was overlooked when CLOCK_REALTIME_FLAG was introduced and unfortunately not reported when the inconsistency was discovered in glibc.
Prepare the function and enforce the CLOCK_REALTIME_FLAG on FUTEX_LOCK_PI so that a new FUTEX_LOCK_PI2 can implement it correctly.
--- kernel/futex.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
kernel/futex.c +2 -1
@@ -2783,7 +2783,7 @@ static int futex_lock_pi(u32 __user *uaddr, unsigned int flags,if (refill_pi_state_cache ())return -ENOMEM ; - to =futex_setup_timer (time, &timeout,FLAGS_CLOCKRT ,0 ); + to =futex_setup_timer (time, &timeout, flags,0 ); retry: ret =get_futex_key (uaddr, flags &FLAGS_SHARED , &q.key,FUTEX_WRITE );
@@ -3739,6 +3739,7 @@ long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,case FUTEX_WAKE_OP :return futex_wake_op (uaddr, flags, uaddr2, val, val2, val3);case FUTEX_LOCK_PI : + flags |=FLAGS_CLOCKRT ;return futex_lock_pi (uaddr, flags, timeout,0 );case FUTEX_UNLOCK_PI :return futex_unlock_pi (uaddr, flags);
PATCH 6/6 futex: Provide FUTEX_LOCK_PI2 to support clock selection
In reply to Thomas GleixnerThe FUTEX_LOCK_PI futex operand uses a CLOCK_REALTIME based absolute timeout since it was implemented, but it does not require that the FUTEX_CLOCK_REALTIME flag is set, because that was introduced later.
In theory as none of the user space implementations can set the FUTEX_CLOCK_REALTIME flag on this operand, it would be possible to creatively abuse it and make the meaning invers, i.e. select CLOCK_REALTIME when not set and CLOCK_MONOTONIC when set. But that's a nasty hackery.
Another option would be to have a new FUTEX_CLOCK_MONOTONIC flag only for FUTEX_LOCK_PI, but that's also awkward because it does not allow libraries to handle the timeout clock selection consistently.
So provide a new FUTEX_LOCK_PI2 operand which implements the timeout semantics which the other operands use and leave FUTEX_LOCK_PI alone.
--- include/uapi/linux/futex.h | 1 + kernel/futex.c | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-)
include/uapi/linux/futex.h +1 -0
@@ -21,6 +21,7 @@#define FUTEX_WAKE_BITSET 10#define FUTEX_WAIT_REQUEUE_PI 11#define FUTEX_CMP_REQUEUE_PI 12 +#define FUTEX_LOCK_PI2 13#define FUTEX_PRIVATE_FLAG 128#define FUTEX_CLOCK_REALTIME 256
kernel/futex.c +5 -1
@@ -3711,7 +3711,8 @@ long do_futex(u32 __user *uaddr, int op,if (op &FUTEX_CLOCK_REALTIME ) { flags |=FLAGS_CLOCKRT ; -if (cmd !=FUTEX_WAIT_BITSET && cmd !=FUTEX_WAIT_REQUEUE_PI ) +if (cmd !=FUTEX_WAIT_BITSET && cmd !=FUTEX_WAIT_REQUEUE_PI && + cmd !=FUTEX_LOCK_PI2 )return -ENOSYS ; }
@@ -3744,6 +3745,8 @@ long do_futex(u32 __user *uaddr, int op,return futex_wake_op (uaddr, flags, uaddr2, val, val2, val3);case FUTEX_LOCK_PI : flags |=FLAGS_CLOCKRT ; + fallthrough; +case FUTEX_LOCK_PI2 :return futex_lock_pi (uaddr, flags, timeout,0 );case FUTEX_UNLOCK_PI :return futex_unlock_pi (uaddr, flags);
@@ -3764,6 +3767,7 @@ static inline bool futex_cmd_has_timeoutswitch (cmd) {case FUTEX_WAIT :case FUTEX_LOCK_PI : +case FUTEX_LOCK_PI2 :case FUTEX_WAIT_BITSET :case FUTEX_WAIT_REQUEUE_PI :return true;
Re: [patch 6/6] futex: Provide FUTEX_LOCK_PI2 to support clock selection
Hi Thomas,
Às 16:44 de 22/04/21, Thomas Gleixner escreveu:
Quoted 26 lines
The
FUTEX_LOCK_PIfutex operand uses aCLOCK_REALTIMEbased absolute timeout since it was implemented, but it does not require that theFUTEX_CLOCK_REALTIMEflag is set, because that was introduced later.In theory as none of the user space implementations can set the
FUTEX_CLOCK_REALTIMEflag on this operand, it would be possible to creatively abuse it and make the meaning invers, i.e. selectCLOCK_REALTIMEwhen not set andCLOCK_MONOTONICwhen set. But that's a nasty hackery.Another option would be to have a new
FUTEX_CLOCK_MONOTONICflag only forFUTEX_LOCK_PI, but that's also awkward because it does not allow libraries to handle the timeout clock selection consistently.So provide a new
FUTEX_LOCK_PI2operand which implements the timeout semantics which the other operands use and leaveFUTEX_LOCK_PIalone.Reported-by Kurt Kanzenbach <[email protected]>Signed-off-by Thomas Gleixner <[email protected]>--- include/uapi/linux/futex.h | 1 + kernel/futex.c | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-)
include/uapi/linux/futex.h line 27
Quoted 7 lines
include/uapi/linux/futex.h +1
-0@@ -21,6 +21,7 @@#define FUTEX_WAKE_BITSET 10#define FUTEX_WAIT_REQUEUE_PI 11#define FUTEX_CMP_REQUEUE_PI 12 +#define FUTEX_LOCK_PI2 13#define FUTEX_PRIVATE_FLAG 128#define FUTEX_CLOCK_REALTIME 256
To keep consistency with other operations, maybe add a FUTEX_LOCK_PI2_PRIVATE?
kernel/futex.c long do_futex(u32 __user *uaddr, int op, · line 3717
Quoted 11 lines
kernel/futex.c +2
-1@@ -3711,7 +3711,8 @@ long do_futex(u32 __user *uaddr, int op,if (op &FUTEX_CLOCK_REALTIME ) { flags |=FLAGS_CLOCKRT ; -if (cmd !=FUTEX_WAIT_BITSET && cmd !=FUTEX_WAIT_REQUEUE_PI ) +if (cmd !=FUTEX_WAIT_BITSET && cmd !=FUTEX_WAIT_REQUEUE_PI && + cmd !=FUTEX_LOCK_PI2 )return -ENOSYS ; }
As FUTEX_LOCK_PI, FUTEX_LOCK_PI2 also requires FUTEX_CMPXCHG right? Then, add it here:
switch (cmd) {
case FUTEX_LOCK_PI:+ case FUTEX_LOCK_PI2:
case FUTEX_UNLOCK_PI:
case FUTEX_TRYLOCK_PI:
case FUTEX_WAIT_REQUEUE_PI:
case FUTEX_CMP_REQUEUE_PI:
if (!futex_cmpxchg_enabled)
return -ENOSYS;
}
Quoted 12 lines
kernel/futex.c +2
-0@@ -3744,6 +3745,8 @@ long do_futex(u32 __user *uaddr, int op,return futex_wake_op (uaddr, flags, uaddr2, val, val2, val3);case FUTEX_LOCK_PI : flags |=FLAGS_CLOCKRT ; + fallthrough; +case FUTEX_LOCK_PI2 :return futex_lock_pi (uaddr, flags, timeout,0 );case FUTEX_UNLOCK_PI :return futex_unlock_pi (uaddr, flags);
kernel/futex.c static inline bool futex_cmd_has_timeout · line 3773
Quoted 7 lines
kernel/futex.c +1
-0@@ -3764,6 +3767,7 @@ static inline bool futex_cmd_has_timeoutswitch (cmd) {case FUTEX_WAIT :case FUTEX_LOCK_PI : +case FUTEX_LOCK_PI2 :case FUTEX_WAIT_BITSET :case FUTEX_WAIT_REQUEUE_PI :return true;
Thanks,
André
Re: [patch 6/6] futex: Provide FUTEX_LOCK_PI2 to support clock selection
André!
Quoted 11 lines · André Almeida
include/uapi/linux/futex.h line 27
Quoted 8 lines
include/uapi/linux/futex.h +1
-0@@ -21,6 +21,7 @@#define FUTEX_WAKE_BITSET 10#define FUTEX_WAIT_REQUEUE_PI 11#define FUTEX_CMP_REQUEUE_PI 12 +#define FUTEX_LOCK_PI2 13#define FUTEX_PRIVATE_FLAG 128#define FUTEX_CLOCK_REALTIME 256To keep consistency with other operations, maybe add a
FUTEX_LOCK_PI2_PRIVATE?
Good point! Missed that.
Quoted 18 lines
kernel/futex.c long do_futex(u32 __user *uaddr, int op, · line 3717
Quoted 11 lines
kernel/futex.c +2
-1@@ -3711,7 +3711,8 @@ long do_futex(u32 __user *uaddr, int op,if (op &FUTEX_CLOCK_REALTIME ) { flags |=FLAGS_CLOCKRT ; -if (cmd !=FUTEX_WAIT_BITSET && cmd !=FUTEX_WAIT_REQUEUE_PI ) +if (cmd !=FUTEX_WAIT_BITSET && cmd !=FUTEX_WAIT_REQUEUE_PI && + cmd !=FUTEX_LOCK_PI2 )return -ENOSYS ; }As
FUTEX_LOCK_PI,FUTEX_LOCK_PI2also requiresFUTEX_CMPXCHGright? Then, add it here:switch (cmd) { case FUTEX_LOCK_PI:(quoted diff) +1
-0+ case FUTEX_LOCK_PI2:
Quoted 7 lines
case
FUTEX_UNLOCK_PI:
caseFUTEX_TRYLOCK_PI:
caseFUTEX_WAIT_REQUEUE_PI:
caseFUTEX_CMP_REQUEUE_PI:
if (!futex_cmpxchg_enabled)
return-ENOSYS;
}
Indeed. Forgot about that completely.
Thanks for spotting that!
tglx
[tip: locking/core] futex: Provide FUTEX_LOCK_PI2 to support clock selection
In reply to Thomas GleixnerThe following commit has been merged into the locking/core branch of tip:
The following commit has been merged into the locking/core branch of tip:
Commit-ID: bf22a6976897977b0a3f1aeba6823c959fc4fdae Gitweb: https://git.kernel.org/tip/bf22a6976897977b0a3f1aeba6823c959fc4fdae Author: Thomas Gleixner <[email protected]> AuthorDate: Thu, 22 Apr 2021 21:44:23 +02:00 Committer: Peter Zijlstra <[email protected]> CommitterDate: Tue, 22 Jun 2021 16:42:09 +02:00
futex: Provide FUTEX_LOCK_PI2 to support clock selection
The FUTEX_LOCK_PI futex operand uses a CLOCK_REALTIME based absolute timeout since it was implemented, but it does not require that the FUTEX_CLOCK_REALTIME flag is set, because that was introduced later.
In theory as none of the user space implementations can set the FUTEX_CLOCK_REALTIME flag on this operand, it would be possible to creatively abuse it and make the meaning invers, i.e. select CLOCK_REALTIME when not set and CLOCK_MONOTONIC when set. But that's a nasty hackery.
Another option would be to have a new FUTEX_CLOCK_MONOTONIC flag only for FUTEX_LOCK_PI, but that's also awkward because it does not allow libraries to handle the timeout clock selection consistently.
So provide a new FUTEX_LOCK_PI2 operand which implements the timeout semantics which the other operands use and leave FUTEX_LOCK_PI alone.
--- include/uapi/linux/futex.h | 2 ++ kernel/futex.c | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-)
include/uapi/linux/futex.h +2 -0
@@ -21,6 +21,7 @@#define FUTEX_WAKE_BITSET 10#define FUTEX_WAIT_REQUEUE_PI 11#define FUTEX_CMP_REQUEUE_PI 12 +#define FUTEX_LOCK_PI2 13#define FUTEX_PRIVATE_FLAG 128#define FUTEX_CLOCK_REALTIME 256
@@ -32,6 +33,7 @@#define FUTEX_CMP_REQUEUE_PRIVATE (FUTEX_CMP_REQUEUE | FUTEX_PRIVATE_FLAG)#define FUTEX_WAKE_OP_PRIVATE (FUTEX_WAKE_OP | FUTEX_PRIVATE_FLAG)#define FUTEX_LOCK_PI_PRIVATE (FUTEX_LOCK_PI | FUTEX_PRIVATE_FLAG) +#define FUTEX_LOCK_PI2_PRIVATE (FUTEX_LOCK_PI2 | FUTEX_PRIVATE_FLAG)#define FUTEX_UNLOCK_PI_PRIVATE (FUTEX_UNLOCK_PI | FUTEX_PRIVATE_FLAG)#define FUTEX_TRYLOCK_PI_PRIVATE (FUTEX_TRYLOCK_PI | FUTEX_PRIVATE_FLAG)#define FUTEX_WAIT_BITSET_PRIVATE (FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG)
kernel/futex.c +6 -1
@@ -3707,12 +3707,14 @@ long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,if (op &FUTEX_CLOCK_REALTIME ) { flags |=FLAGS_CLOCKRT ; -if (cmd !=FUTEX_WAIT_BITSET && cmd !=FUTEX_WAIT_REQUEUE_PI ) +if (cmd !=FUTEX_WAIT_BITSET && cmd !=FUTEX_WAIT_REQUEUE_PI && + cmd !=FUTEX_LOCK_PI2 )return -ENOSYS ; }switch (cmd) {case FUTEX_LOCK_PI : +case FUTEX_LOCK_PI2 :case FUTEX_UNLOCK_PI :case FUTEX_TRYLOCK_PI :case FUTEX_WAIT_REQUEUE_PI :
@@ -3740,6 +3742,8 @@ long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,return futex_wake_op (uaddr, flags, uaddr2, val, val2, val3);case FUTEX_LOCK_PI : flags |=FLAGS_CLOCKRT ; + fallthrough; +case FUTEX_LOCK_PI2 :return futex_lock_pi (uaddr, flags, timeout,0 );case FUTEX_UNLOCK_PI :return futex_unlock_pi (uaddr, flags);
@@ -3760,6 +3764,7 @@ static __always_inline bool futex_cmd_has_timeout(u32 cmd)switch (cmd) {case FUTEX_WAIT :case FUTEX_LOCK_PI : +case FUTEX_LOCK_PI2 :case FUTEX_WAIT_BITSET :case FUTEX_WAIT_REQUEUE_PI :return true;
Quoted 25 lines · Thomas Gleixner
The following series started off looking into supporting selectable clocks for
FUTEX_LOCK_PIwhich is hardcoded toCLOCK_REALTIMEand cannot be changed.On the way I found two bugs related to the timeout handling:
- The allowance for
FUTEX_WAITto useFUTEX_CLOCK_REALTIMEis broken and never worked.- The recent time namespace support wreckaged
FUTEX_LOCK_PItimeouts when the task belongs to a namespace which has anCLOCK_MONOTONICoffset.Both should have been caught by that Gleixner dude when merging them, but it seems he's getting old.
Not having a selectable clock for PI futexes is inconsistent because all other interfaces have it. Unfortunately this was figured out by glibc folks quite some time ago, but nobody told us :(
The nasty hack to support it would be to treat
FUTEX_CLOCK_REALTIMEinverse forFUTEX_LOCK_PI, but that's a horrible idea. Adding a new flag to the futex op, i.e.FUTEX_CLOCK_MONOTONICwould be possible, but that's yet another variant which makes is harder for libraries to have a consistent clock selection handling.
Quoted 4 lines
So I went the way to let
FUTEX_LOCK_PIalone and to addFUTEX_LOCK_PI2which handles the clocks the same way as the other operands.Thoughts?
With the missing FUTEX_LOCK_PI2 in #6, as spotted by André Almeida, fixed:
It's all somewhat sad, but I don't see any other way out of this. Using LOCK_PI2 will be a fairly horrible pile of hacks on the userspace side of things given they need to first detect it's presence etc., but that seems unavoidable whatever we do :/
Quoted 4 lines · Peter Zijlstra
It's all somewhat sad, but I don't see any other way out of this. Using
LOCK_PI2will be a fairly horrible pile of hacks on the userspace side of things given they need to first detect it's presence etc., but that seems unavoidable whatever we do :/
Well, that's the interesting point. I do have such horrible hacks for glibc, which detect the presence of LOCK_PI2 at run time. However, the glibc has also the notion of kernel features based on the Linux kernel version. Then, it could be detected at compile time. At the end of the day it depends on how this patch set is merged. I was hoping for the glibc folks to share their opinion on this :-).
Thanks,
Kurt