Skip to content

Commit 5694289

Browse files
futex: Flag conversion
Futex has 3 sets of flags: - legacy futex op bits - futex2 flags - internal flags Add a few helpers to convert from the API flags into the internal flags. Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Reviewed-by: Thomas Gleixner <[email protected]> Reviewed-by: André Almeida <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent d6d08d2 commit 5694289

File tree

3 files changed

+71
-20
lines changed

3 files changed

+71
-20
lines changed

kernel/futex/futex.h

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <linux/futex.h>
66
#include <linux/rtmutex.h>
77
#include <linux/sched/wake_q.h>
8+
#include <linux/compat.h>
89

910
#ifdef CONFIG_PREEMPT_RT
1011
#include <linux/rcuwait.h>
@@ -16,17 +17,73 @@
1617
* Futex flags used to encode options to functions and preserve them across
1718
* restarts.
1819
*/
20+
#define FLAGS_SIZE_8 0x00
21+
#define FLAGS_SIZE_16 0x01
22+
#define FLAGS_SIZE_32 0x02
23+
#define FLAGS_SIZE_64 0x03
24+
25+
#define FLAGS_SIZE_MASK 0x03
26+
1927
#ifdef CONFIG_MMU
20-
# define FLAGS_SHARED 0x01
28+
# define FLAGS_SHARED 0x10
2129
#else
2230
/*
2331
* NOMMU does not have per process address space. Let the compiler optimize
2432
* code away.
2533
*/
2634
# define FLAGS_SHARED 0x00
2735
#endif
28-
#define FLAGS_CLOCKRT 0x02
29-
#define FLAGS_HAS_TIMEOUT 0x04
36+
#define FLAGS_CLOCKRT 0x20
37+
#define FLAGS_HAS_TIMEOUT 0x40
38+
#define FLAGS_NUMA 0x80
39+
40+
/* FUTEX_ to FLAGS_ */
41+
static inline unsigned int futex_to_flags(unsigned int op)
42+
{
43+
unsigned int flags = FLAGS_SIZE_32;
44+
45+
if (!(op & FUTEX_PRIVATE_FLAG))
46+
flags |= FLAGS_SHARED;
47+
48+
if (op & FUTEX_CLOCK_REALTIME)
49+
flags |= FLAGS_CLOCKRT;
50+
51+
return flags;
52+
}
53+
54+
/* FUTEX2_ to FLAGS_ */
55+
static inline unsigned int futex2_to_flags(unsigned int flags2)
56+
{
57+
unsigned int flags = flags2 & FUTEX2_SIZE_MASK;
58+
59+
if (!(flags2 & FUTEX2_PRIVATE))
60+
flags |= FLAGS_SHARED;
61+
62+
if (flags2 & FUTEX2_NUMA)
63+
flags |= FLAGS_NUMA;
64+
65+
return flags;
66+
}
67+
68+
static inline unsigned int futex_size(unsigned int flags)
69+
{
70+
return 1 << (flags & FLAGS_SIZE_MASK);
71+
}
72+
73+
static inline bool futex_flags_valid(unsigned int flags)
74+
{
75+
/* Only 64bit futexes for 64bit code */
76+
if (!IS_ENABLED(CONFIG_64BIT) || in_compat_syscall()) {
77+
if ((flags & FLAGS_SIZE_MASK) == FLAGS_SIZE_64)
78+
return false;
79+
}
80+
81+
/* Only 32bit futexes are implemented -- for now */
82+
if ((flags & FLAGS_SIZE_MASK) != FLAGS_SIZE_32)
83+
return false;
84+
85+
return true;
86+
}
3087

3188
#ifdef CONFIG_FAIL_FUTEX
3289
extern bool should_fail_futex(bool fshared);

kernel/futex/syscalls.c

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
// SPDX-License-Identifier: GPL-2.0-or-later
22

3-
#include <linux/compat.h>
43
#include <linux/syscalls.h>
54
#include <linux/time_namespace.h>
65

@@ -85,15 +84,12 @@ SYSCALL_DEFINE3(get_robust_list, int, pid,
8584
long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
8685
u32 __user *uaddr2, u32 val2, u32 val3)
8786
{
87+
unsigned int flags = futex_to_flags(op);
8888
int cmd = op & FUTEX_CMD_MASK;
89-
unsigned int flags = 0;
9089

91-
if (!(op & FUTEX_PRIVATE_FLAG))
92-
flags |= FLAGS_SHARED;
93-
94-
if (op & FUTEX_CLOCK_REALTIME) {
95-
flags |= FLAGS_CLOCKRT;
96-
if (cmd != FUTEX_WAIT_BITSET && cmd != FUTEX_WAIT_REQUEUE_PI &&
90+
if (flags & FLAGS_CLOCKRT) {
91+
if (cmd != FUTEX_WAIT_BITSET &&
92+
cmd != FUTEX_WAIT_REQUEUE_PI &&
9793
cmd != FUTEX_LOCK_PI2)
9894
return -ENOSYS;
9995
}
@@ -201,21 +197,19 @@ static int futex_parse_waitv(struct futex_vector *futexv,
201197
unsigned int i;
202198

203199
for (i = 0; i < nr_futexes; i++) {
200+
unsigned int flags;
201+
204202
if (copy_from_user(&aux, &uwaitv[i], sizeof(aux)))
205203
return -EFAULT;
206204

207205
if ((aux.flags & ~FUTEX2_VALID_MASK) || aux.__reserved)
208206
return -EINVAL;
209207

210-
if (!IS_ENABLED(CONFIG_64BIT) || in_compat_syscall()) {
211-
if ((aux.flags & FUTEX2_SIZE_MASK) == FUTEX2_SIZE_U64)
212-
return -EINVAL;
213-
}
214-
215-
if ((aux.flags & FUTEX2_SIZE_MASK) != FUTEX2_SIZE_U32)
208+
flags = futex2_to_flags(aux.flags);
209+
if (!futex_flags_valid(flags))
216210
return -EINVAL;
217211

218-
futexv[i].w.flags = aux.flags;
212+
futexv[i].w.flags = flags;
219213
futexv[i].w.val = aux.val;
220214
futexv[i].w.uaddr = aux.uaddr;
221215
futexv[i].q = futex_q_init;

kernel/futex/waitwake.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -419,11 +419,11 @@ static int futex_wait_multiple_setup(struct futex_vector *vs, int count, int *wo
419419
*/
420420
retry:
421421
for (i = 0; i < count; i++) {
422-
if ((vs[i].w.flags & FUTEX_PRIVATE_FLAG) && retry)
422+
if (!(vs[i].w.flags & FLAGS_SHARED) && retry)
423423
continue;
424424

425425
ret = get_futex_key(u64_to_user_ptr(vs[i].w.uaddr),
426-
!(vs[i].w.flags & FUTEX_PRIVATE_FLAG),
426+
vs[i].w.flags & FLAGS_SHARED,
427427
&vs[i].q.key, FUTEX_READ);
428428

429429
if (unlikely(ret))

0 commit comments

Comments
 (0)