-
Notifications
You must be signed in to change notification settings - Fork 102
/
futex2.c
82 lines (63 loc) · 1.95 KB
/
futex2.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* futex2 system call interface by André Almeida <andrealmeid@collabora.com>
*
* Copyright 2021 Collabora Ltd.
*/
#include <linux/syscalls.h>
#include <asm/futex.h>
/*
* Set of flags that futex2 operates. If we got something that is not in this
* set, it can be a unsupported futex1 operation like BITSET or PI, so we
* refuse to accept
*/
#define FUTEX2_MASK (FUTEX_SIZE_MASK | FUTEX_SHARED_FLAG | FUTEX_CLOCK_REALTIME)
static long ksys_futex_wait(void __user *uaddr, u64 val, unsigned int flags,
struct __kernel_timespec __user *timo)
{
unsigned int size = flags & FUTEX_SIZE_MASK, futex_flags = 0;
ktime_t *kt = NULL, time;
struct timespec64 ts;
if (flags & ~FUTEX2_MASK)
return -EINVAL;
if (flags & FUTEX_SHARED_FLAG)
futex_flags |= FLAGS_SHARED;
if (flags & FUTEX_CLOCK_REALTIME)
futex_flags |= FLAGS_CLOCKRT;
if (size != FUTEX_32)
return -EINVAL;
if (timo) {
if (get_timespec64(&ts, timo))
return -EFAULT;
if (!timespec64_valid(&ts))
return -EINVAL;
time = timespec64_to_ktime(ts);
kt = &time;
}
return futex_wait(uaddr, futex_flags, val, kt, FUTEX_BITSET_MATCH_ANY);
}
SYSCALL_DEFINE4(futex_wait, void __user *, uaddr, u64, val, unsigned int, flags,
struct __kernel_timespec __user *, timo)
{
return ksys_futex_wait(uaddr, val, flags, timo);
}
#ifdef CONFIG_COMPAT
COMPAT_SYSCALL_DEFINE4(compat_futex_wait, void __user *, uaddr, compat_u64, val,
unsigned int, flags,
struct __kernel_timespec __user *, timo)
{
return ksys_futex_wait(uaddr, val, flags, timo);
}
#endif
SYSCALL_DEFINE3(futex_wake, void __user *, uaddr, unsigned int, nr_wake,
unsigned int, flags)
{
unsigned int size = flags & FUTEX_SIZE_MASK, futex_flags = 0;
if (flags & ~FUTEX2_MASK)
return -EINVAL;
if (flags & FUTEX_SHARED_FLAG)
futex_flags |= FLAGS_SHARED;
if (size != FUTEX_32)
return -EINVAL;
return futex_wake(uaddr, futex_flags, nr_wake, FUTEX_BITSET_MATCH_ANY);
}