summaryrefslogtreecommitdiff
path: root/SOURCES/fsync.patch
diff options
context:
space:
mode:
Diffstat (limited to 'SOURCES/fsync.patch')
-rw-r--r--SOURCES/fsync.patch521
1 files changed, 105 insertions, 416 deletions
diff --git a/SOURCES/fsync.patch b/SOURCES/fsync.patch
index 01c86d8..ef1446c 100644
--- a/SOURCES/fsync.patch
+++ b/SOURCES/fsync.patch
@@ -1,10 +1,79 @@
-From f7f49141a5dbe9c99d78196b58c44307fb2e6be3 Mon Sep 17 00:00:00 2001
-From: Tk-Glitch <ti3nou@gmail.com>
-Date: Mon, 20 Apr 2020 14:09:11 +0200
-Subject: Import Fsync v3 patchset - Squashed from https://gitlab.collabora.com/tonyk/linux/-/commits/futex-proton-v3
+From 7b5df0248ce255ef5b7204d65a7b3783ebb76a3d Mon Sep 17 00:00:00 2001
+From: Gabriel Krisman Bertazi <krisman@collabora.com>
+Date: Fri, 13 Dec 2019 11:08:02 -0300
+Subject: [PATCH 1/2] futex: Implement mechanism to wait on any of several
+ futexes
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This is a new futex operation, called FUTEX_WAIT_MULTIPLE, which allows
+a thread to wait on several futexes at the same time, and be awoken by
+any of them. In a sense, it implements one of the features that was
+supported by pooling on the old FUTEX_FD interface.
+
+The use case lies in the Wine implementation of the Windows NT interface
+WaitMultipleObjects. This Windows API function allows a thread to sleep
+waiting on the first of a set of event sources (mutexes, timers, signal,
+console input, etc) to signal. Considering this is a primitive
+synchronization operation for Windows applications, being able to quickly
+signal events on the producer side, and quickly go to sleep on the
+consumer side is essential for good performance of those running over Wine.
+
+Wine developers have an implementation that uses eventfd, but it suffers
+from FD exhaustion (there is applications that go to the order of
+multi-milion FDs), and higher CPU utilization than this new operation.
+
+The futex list is passed as an array of `struct futex_wait_block`
+(pointer, value, bitset) to the kernel, which will enqueue all of them
+and sleep if none was already triggered. It returns a hint of which
+futex caused the wake up event to userspace, but the hint doesn't
+guarantee that is the only futex triggered. Before calling the syscall
+again, userspace should traverse the list, trying to re-acquire any of
+the other futexes, to prevent an immediate -EWOULDBLOCK return code from
+the kernel.
+
+This was tested using three mechanisms:
+
+1) By reimplementing FUTEX_WAIT in terms of FUTEX_WAIT_MULTIPLE and
+running the unmodified tools/testing/selftests/futex and a full linux
+distro on top of this kernel.
+
+2) By an example code that exercises the FUTEX_WAIT_MULTIPLE path on a
+multi-threaded, event-handling setup.
+
+3) By running the Wine fsync implementation and executing multi-threaded
+applications, in particular modern games, on top of this implementation.
+
+Changes were tested for the following ABIs: x86_64, i386 and x32.
+Support for x32 applications is not implemented since it would
+take a major rework adding a new entry point and splitting the current
+futex 64 entry point in two and we can't change the current x32 syscall
+number without breaking user space compatibility.
+
+CC: Steven Rostedt <rostedt@goodmis.org>
+Cc: Richard Yao <ryao@gentoo.org>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Co-developed-by: Zebediah Figura <z.figura12@gmail.com>
+Signed-off-by: Zebediah Figura <z.figura12@gmail.com>
+Co-developed-by: Steven Noonan <steven@valvesoftware.com>
+Signed-off-by: Steven Noonan <steven@valvesoftware.com>
+Co-developed-by: Pierre-Loup A. Griffais <pgriffais@valvesoftware.com>
+Signed-off-by: Pierre-Loup A. Griffais <pgriffais@valvesoftware.com>
+Signed-off-by: Gabriel Krisman Bertazi <krisman@collabora.com>
+[Added compatibility code]
+Co-developed-by: André Almeida <andrealmeid@collabora.com>
+Signed-off-by: André Almeida <andrealmeid@collabora.com>
+
+Adjusted for v5.9: Removed `put_futex_key` calls.
+---
+ include/uapi/linux/futex.h | 20 +++
+ kernel/futex.c | 352 ++++++++++++++++++++++++++++++++++++-
+ 2 files changed, 370 insertions(+), 2 deletions(-)
diff --git a/include/uapi/linux/futex.h b/include/uapi/linux/futex.h
-index a89eb0accd5e2ee527be1e3e11b1117ff5bf94b4..580001e89c6caed57dd8b3cb491d65dce846caff 100644
+index a89eb0accd5e2..580001e89c6ca 100644
--- a/include/uapi/linux/futex.h
+++ b/include/uapi/linux/futex.h
@@ -21,6 +21,7 @@
@@ -47,10 +116,10 @@ index a89eb0accd5e2ee527be1e3e11b1117ff5bf94b4..580001e89c6caed57dd8b3cb491d65dc
+
#endif /* _UAPI_LINUX_FUTEX_H */
diff --git a/kernel/futex.c b/kernel/futex.c
-index 0cf84c8664f207c574325b899ef2e57f01295a94..58cf9eb2b851b4858e29b5ef4114a29a92e676ba 100644
+index a5876694a60eb..6f4bea76df460 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
-@@ -215,6 +215,8 @@ struct futex_pi_state {
+@@ -197,6 +197,8 @@ struct futex_pi_state {
* @rt_waiter: rt_waiter storage for use with requeue_pi
* @requeue_pi_key: the requeue_pi target futex key
* @bitset: bitset for the optional bitmasked wakeup
@@ -59,7 +128,7 @@ index 0cf84c8664f207c574325b899ef2e57f01295a94..58cf9eb2b851b4858e29b5ef4114a29a
*
* We use this hashed waitqueue, instead of a normal wait_queue_entry_t, so
* we can wake only the relevant ones (hashed queues may be shared).
-@@ -237,6 +239,8 @@ struct futex_q {
+@@ -219,6 +221,8 @@ struct futex_q {
struct rt_mutex_waiter *rt_waiter;
union futex_key *requeue_pi_key;
u32 bitset;
@@ -68,7 +137,7 @@ index 0cf84c8664f207c574325b899ef2e57f01295a94..58cf9eb2b851b4858e29b5ef4114a29a
} __randomize_layout;
static const struct futex_q futex_q_init = {
-@@ -2420,6 +2424,29 @@ static int unqueue_me(struct futex_q *q)
+@@ -2304,6 +2308,29 @@ static int unqueue_me(struct futex_q *q)
return ret;
}
@@ -98,7 +167,7 @@ index 0cf84c8664f207c574325b899ef2e57f01295a94..58cf9eb2b851b4858e29b5ef4114a29a
/*
* PI futexes can not be requeued and must remove themself from the
* hash bucket. The hash bucket lock (i.e. lock_ptr) is held on entry
-@@ -2783,6 +2810,211 @@ static int futex_wait_setup(u32 __user *uaddr, u32 val, unsigned int flags,
+@@ -2662,6 +2689,205 @@ static int futex_wait_setup(u32 __user *uaddr, u32 val, unsigned int flags,
return ret;
}
@@ -143,8 +212,6 @@ index 0cf84c8664f207c574325b899ef2e57f01295a94..58cf9eb2b851b4858e29b5ef4114a29a
+ ret = get_futex_key(qs[i].uaddr, flags & FLAGS_SHARED,
+ &qs[i].key, FUTEX_READ);
+ if (unlikely(ret)) {
-+ for (--i; i >= 0; i--)
-+ put_futex_key(&qs[i].key);
+ return ret;
+ }
+ }
@@ -172,8 +239,6 @@ index 0cf84c8664f207c574325b899ef2e57f01295a94..58cf9eb2b851b4858e29b5ef4114a29a
+ * Keys 0..(i-1) are implicitly put
+ * on unqueue_multiple.
+ */
-+ put_futex_key(&q->key);
-+
+ *awaken = unqueue_multiple(qs, i);
+
+ __set_current_state(TASK_RUNNING);
@@ -202,8 +267,6 @@ index 0cf84c8664f207c574325b899ef2e57f01295a94..58cf9eb2b851b4858e29b5ef4114a29a
+ if (uval != q->uval) {
+ queue_unlock(hb);
+
-+ put_futex_key(&qs[i].key);
-+
+ /*
+ * If something was already awaken, we can
+ * safely ignore the error and succeed.
@@ -310,7 +373,7 @@ index 0cf84c8664f207c574325b899ef2e57f01295a94..58cf9eb2b851b4858e29b5ef4114a29a
static int futex_wait(u32 __user *uaddr, unsigned int flags, u32 val,
ktime_t *abs_time, u32 bitset)
{
-@@ -3907,6 +4139,43 @@ long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
+@@ -3774,6 +4000,43 @@ long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
return -ENOSYS;
}
@@ -354,7 +417,7 @@ index 0cf84c8664f207c574325b899ef2e57f01295a94..58cf9eb2b851b4858e29b5ef4114a29a
SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,
struct __kernel_timespec __user *, utime, u32 __user *, uaddr2,
-@@ -3919,7 +4188,8 @@ SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,
+@@ -3786,7 +4049,8 @@ SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,
if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI ||
cmd == FUTEX_WAIT_BITSET ||
@@ -364,7 +427,7 @@ index 0cf84c8664f207c574325b899ef2e57f01295a94..58cf9eb2b851b4858e29b5ef4114a29a
if (unlikely(should_fail_futex(!(op & FUTEX_PRIVATE_FLAG))))
return -EFAULT;
if (get_timespec64(&ts, utime))
-@@ -3940,6 +4210,25 @@ SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,
+@@ -3807,6 +4071,25 @@ SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,
cmd == FUTEX_CMP_REQUEUE_PI || cmd == FUTEX_WAKE_OP)
val2 = (u32) (unsigned long) utime;
@@ -390,7 +453,7 @@ index 0cf84c8664f207c574325b899ef2e57f01295a94..58cf9eb2b851b4858e29b5ef4114a29a
return do_futex(uaddr, op, val, tp, uaddr2, val2, val3);
}
-@@ -4102,6 +4391,57 @@ COMPAT_SYSCALL_DEFINE3(get_robust_list, int, pid,
+@@ -3969,6 +4252,57 @@ COMPAT_SYSCALL_DEFINE3(get_robust_list, int, pid,
#endif /* CONFIG_COMPAT */
#ifdef CONFIG_COMPAT_32BIT_TIME
@@ -448,7 +511,7 @@ index 0cf84c8664f207c574325b899ef2e57f01295a94..58cf9eb2b851b4858e29b5ef4114a29a
SYSCALL_DEFINE6(futex_time32, u32 __user *, uaddr, int, op, u32, val,
struct old_timespec32 __user *, utime, u32 __user *, uaddr2,
u32, val3)
-@@ -4113,7 +4453,8 @@ SYSCALL_DEFINE6(futex_time32, u32 __user *, uaddr, int, op, u32, val,
+@@ -3980,7 +4314,8 @@ SYSCALL_DEFINE6(futex_time32, u32 __user *, uaddr, int, op, u32, val,
if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI ||
cmd == FUTEX_WAIT_BITSET ||
@@ -458,7 +521,7 @@ index 0cf84c8664f207c574325b899ef2e57f01295a94..58cf9eb2b851b4858e29b5ef4114a29a
if (get_old_timespec32(&ts, utime))
return -EFAULT;
if (!timespec64_valid(&ts))
-@@ -4128,6 +4469,19 @@ SYSCALL_DEFINE6(futex_time32, u32 __user *, uaddr, int, op, u32, val,
+@@ -3995,6 +4330,19 @@ SYSCALL_DEFINE6(futex_time32, u32 __user *, uaddr, int, op, u32, val,
cmd == FUTEX_CMP_REQUEUE_PI || cmd == FUTEX_WAKE_OP)
val2 = (int) (unsigned long) utime;
@@ -478,393 +541,19 @@ index 0cf84c8664f207c574325b899ef2e57f01295a94..58cf9eb2b851b4858e29b5ef4114a29a
return do_futex(uaddr, op, val, tp, uaddr2, val2, val3);
}
#endif /* CONFIG_COMPAT_32BIT_TIME */
-diff --git a/tools/testing/selftests/futex/functional/futex_wait_timeout.c b/tools/testing/selftests/futex/functional/futex_wait_timeout.c
-index ee55e6d389a3f053194435342c4e471dc7cf8786..2a63e1c2cfb6407a5988233217cff2e52787bc66 100644
---- a/tools/testing/selftests/futex/functional/futex_wait_timeout.c
-+++ b/tools/testing/selftests/futex/functional/futex_wait_timeout.c
-@@ -11,6 +11,7 @@
- *
- * HISTORY
- * 2009-Nov-6: Initial version by Darren Hart <dvhart@linux.intel.com>
-+ * 2019-Dec-13: Add WAIT_MULTIPLE test by Krisman <krisman@collabora.com>
- *
- *****************************************************************************/
-
-@@ -41,6 +42,8 @@ int main(int argc, char *argv[])
- {
- futex_t f1 = FUTEX_INITIALIZER;
- struct timespec to;
-+ time_t secs;
-+ struct futex_wait_block fwb = {&f1, f1, 0};
- int res, ret = RET_PASS;
- int c;
-
-@@ -65,7 +68,7 @@ int main(int argc, char *argv[])
- }
-
- ksft_print_header();
-- ksft_set_plan(1);
-+ ksft_set_plan(2);
- ksft_print_msg("%s: Block on a futex and wait for timeout\n",
- basename(argv[0]));
- ksft_print_msg("\tArguments: timeout=%ldns\n", timeout_ns);
-@@ -79,8 +82,39 @@ int main(int argc, char *argv[])
- if (!res || errno != ETIMEDOUT) {
- fail("futex_wait returned %d\n", ret < 0 ? errno : ret);
- ret = RET_FAIL;
-+ } else
-+ ksft_test_result_pass("futex_wait timeout succeeds\n");
-+
-+ info("Calling futex_wait_multiple on f1: %u @ %p\n", f1, &f1);
-+
-+ /* Setup absolute time */
-+ ret = clock_gettime(CLOCK_REALTIME, &to);
-+ secs = (to.tv_nsec + timeout_ns) / 1000000000;
-+ to.tv_nsec = ((int64_t)to.tv_nsec + timeout_ns) % 1000000000;
-+ to.tv_sec += secs;
-+ info("to.tv_sec = %ld\n", to.tv_sec);
-+ info("to.tv_nsec = %ld\n", to.tv_nsec);
-+
-+ res = futex_wait_multiple(&fwb, 1, &to,
-+ FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME);
-+
-+#ifdef __ILP32__
-+ if (res == -1 && errno == ENOSYS) {
-+ ksft_test_result_skip("futex_wait_multiple not supported at x32\n");
-+ } else {
-+ ksft_test_result_fail("futex_wait_multiple returned %d\n",
-+ res < 0 ? errno : res);
-+ ret = RET_FAIL;
- }
-+#else
-+ if (!res || errno != ETIMEDOUT) {
-+ ksft_test_result_fail("futex_wait_multiple returned %d\n",
-+ res < 0 ? errno : res);
-+ ret = RET_FAIL;
-+ } else
-+ ksft_test_result_pass("futex_wait_multiple timeout succeeds\n");
-+#endif /* __ILP32__ */
-
-- print_result(TEST_NAME, ret);
-+ ksft_print_cnts();
- return ret;
- }
-diff --git a/tools/testing/selftests/futex/include/futextest.h b/tools/testing/selftests/futex/include/futextest.h
-index ddbcfc9b7bac4aebb5bac2f249e26ecfd948aa84..bb103bef4557012ef9a389ca74c868e4476a8a31 100644
---- a/tools/testing/selftests/futex/include/futextest.h
-+++ b/tools/testing/selftests/futex/include/futextest.h
-@@ -38,6 +38,14 @@ typedef volatile u_int32_t futex_t;
- #ifndef FUTEX_CMP_REQUEUE_PI
- #define FUTEX_CMP_REQUEUE_PI 12
- #endif
-+#ifndef FUTEX_WAIT_MULTIPLE
-+#define FUTEX_WAIT_MULTIPLE 13
-+struct futex_wait_block {
-+ futex_t *uaddr;
-+ futex_t val;
-+ __u32 bitset;
-+};
-+#endif
- #ifndef FUTEX_WAIT_REQUEUE_PI_PRIVATE
- #define FUTEX_WAIT_REQUEUE_PI_PRIVATE (FUTEX_WAIT_REQUEUE_PI | \
- FUTEX_PRIVATE_FLAG)
-@@ -80,6 +88,20 @@ futex_wait(futex_t *uaddr, futex_t val, struct timespec *timeout, int opflags)
- return futex(uaddr, FUTEX_WAIT, val, timeout, NULL, 0, opflags);
- }
-
-+/**
-+ * futex_wait_multiple() - block on several futexes with optional timeout
-+ * @fwb: wait block user space address
-+ * @count: number of entities at fwb
-+ * @timeout: absolute timeout
-+ */
-+static inline int
-+futex_wait_multiple(struct futex_wait_block *fwb, int count,
-+ struct timespec *timeout, int opflags)
-+{
-+ return futex(fwb, FUTEX_WAIT_MULTIPLE, count, timeout, NULL, 0,
-+ opflags);
-+}
-+
- /**
- * futex_wake() - wake one or more tasks blocked on uaddr
- * @nr_wake: wake up to this many tasks
-diff --git a/tools/testing/selftests/futex/functional/futex_wait_wouldblock.c b/tools/testing/selftests/futex/functional/futex_wait_wouldblock.c
-index 0ae390ff816449c88d0bb655a26eb014382c2b4f..bcbac042992d447e0bc9ef5fefe94e875de310f2 100644
---- a/tools/testing/selftests/futex/functional/futex_wait_wouldblock.c
-+++ b/tools/testing/selftests/futex/functional/futex_wait_wouldblock.c
-@@ -12,6 +12,7 @@
- *
- * HISTORY
- * 2009-Nov-14: Initial version by Gowrishankar <gowrishankar.m@in.ibm.com>
-+ * 2019-Dec-13: Add WAIT_MULTIPLE test by Krisman <krisman@collabora.com>
- *
- *****************************************************************************/
-
-@@ -40,6 +41,7 @@ int main(int argc, char *argv[])
- {
- struct timespec to = {.tv_sec = 0, .tv_nsec = timeout_ns};
- futex_t f1 = FUTEX_INITIALIZER;
-+ struct futex_wait_block fwb = {&f1, f1+1, 0};
- int res, ret = RET_PASS;
- int c;
-
-@@ -61,7 +63,7 @@ int main(int argc, char *argv[])
- }
-
- ksft_print_header();
-- ksft_set_plan(1);
-+ ksft_set_plan(2);
- ksft_print_msg("%s: Test the unexpected futex value in FUTEX_WAIT\n",
- basename(argv[0]));
-
-@@ -71,8 +73,30 @@ int main(int argc, char *argv[])
- fail("futex_wait returned: %d %s\n",
- res ? errno : res, res ? strerror(errno) : "");
- ret = RET_FAIL;
-+ } else
-+ ksft_test_result_pass("futex_wait wouldblock succeeds\n");
-+
-+ info("Calling futex_wait_multiple on f1: %u @ %p with val=%u\n",
-+ f1, &f1, f1+1);
-+ res = futex_wait_multiple(&fwb, 1, NULL, FUTEX_PRIVATE_FLAG);
-+
-+#ifdef __ILP32__
-+ if (res != -1 || errno != ENOSYS) {
-+ ksft_test_result_fail("futex_wait_multiple returned %d\n",
-+ res < 0 ? errno : res);
-+ ret = RET_FAIL;
-+ } else {
-+ ksft_test_result_skip("futex_wait_multiple not supported at x32\n");
-+ }
-+#else
-+ if (!res || errno != EWOULDBLOCK) {
-+ ksft_test_result_fail("futex_wait_multiple returned %d\n",
-+ res < 0 ? errno : res);
-+ ret = RET_FAIL;
- }
-+ ksft_test_result_pass("futex_wait_multiple wouldblock succeeds\n");
-+#endif /* __ILP32__ */
-
-- print_result(TEST_NAME, ret);
-+ ksft_print_cnts();
- return ret;
- }
-diff --git a/tools/testing/selftests/futex/functional/.gitignore b/tools/testing/selftests/futex/functional/.gitignore
-index a09f570619023750f558c84004aff166b4337d72..4660128a545edb04a17cc6bd9760931c1386122f 100644
---- a/tools/testing/selftests/futex/functional/.gitignore
-+++ b/tools/testing/selftests/futex/functional/.gitignore
-@@ -5,3 +5,4 @@ futex_wait_private_mapped_file
- futex_wait_timeout
- futex_wait_uninitialized_heap
- futex_wait_wouldblock
-+futex_wait_multiple
-diff --git a/tools/testing/selftests/futex/functional/Makefile b/tools/testing/selftests/futex/functional/Makefile
-index 30996306cabcfe89a47977643e529b122893bb7e..75f9fface11fa3c90c1bdb9a49b3ea51291afd58 100644
---- a/tools/testing/selftests/futex/functional/Makefile
-+++ b/tools/testing/selftests/futex/functional/Makefile
-@@ -14,7 +14,8 @@ TEST_GEN_FILES := \
- futex_requeue_pi_signal_restart \
- futex_requeue_pi_mismatched_ops \
- futex_wait_uninitialized_heap \
-- futex_wait_private_mapped_file
-+ futex_wait_private_mapped_file \
-+ futex_wait_multiple
-
- TEST_PROGS := run.sh
-
-diff --git a/tools/testing/selftests/futex/functional/futex_wait_multiple.c b/tools/testing/selftests/futex/functional/futex_wait_multiple.c
-new file mode 100644
-index 0000000000000000000000000000000000000000..b48422e79f42edba1653bb0bd2a4c4fd98d2d48d
---- /dev/null
-+++ b/tools/testing/selftests/futex/functional/futex_wait_multiple.c
-@@ -0,0 +1,173 @@
-+// SPDX-License-Identifier: GPL-2.0-or-later
-+/******************************************************************************
-+ *
-+ * Copyright © Collabora, Ltd., 2019
-+ *
-+ * DESCRIPTION
-+ * Test basic semantics of FUTEX_WAIT_MULTIPLE
-+ *
-+ * AUTHOR
-+ * Gabriel Krisman Bertazi <krisman@collabora.com>
-+ *
-+ * HISTORY
-+ * 2019-Dec-13: Initial version by Krisman <krisman@collabora.com>
-+ *
-+ *****************************************************************************/
-+
-+#include <errno.h>
-+#include <getopt.h>
-+#include <stdio.h>
-+#include <stdlib.h>
-+#include <string.h>
-+#include <time.h>
-+#include <pthread.h>
-+#include "futextest.h"
-+#include "logging.h"
-+
-+#define TEST_NAME "futex-wait-multiple"
-+#define timeout_ns 100000
-+#define MAX_COUNT 128
-+#define WAKE_WAIT_US 3000000
-+
-+int ret = RET_PASS;
-+char *progname;
-+futex_t f[MAX_COUNT] = {0};
-+struct futex_wait_block fwb[MAX_COUNT];
-+
-+void usage(char *prog)
-+{
-+ printf("Usage: %s\n", prog);
-+ printf(" -c Use color\n");
-+ printf(" -h Display this help message\n");
-+ printf(" -v L Verbosity level: %d=QUIET %d=CRITICAL %d=INFO\n",
-+ VQUIET, VCRITICAL, VINFO);
-+}
-+
-+void test_count_overflow(void)
-+{
-+ futex_t f = FUTEX_INITIALIZER;
-+ struct futex_wait_block fwb[MAX_COUNT+1];
-+ int res, i;
-+
-+ ksft_print_msg("%s: Test a too big number of futexes\n", progname);
-+
-+ for (i = 0; i < MAX_COUNT+1; i++) {
-+ fwb[i].uaddr = &f;
-+ fwb[i].val = f;
-+ fwb[i].bitset = 0;
-+ }
-+
-+ res = futex_wait_multiple(fwb, MAX_COUNT+1, NULL, FUTEX_PRIVATE_FLAG);
-+
-+#ifdef __ILP32__
-+ if (res != -1 || errno != ENOSYS) {
-+ ksft_test_result_fail("futex_wait_multiple returned %d\n",
-+ res < 0 ? errno : res);
-+ ret = RET_FAIL;
-+ } else {
-+ ksft_test_result_skip("futex_wait_multiple not supported at x32\n");
-+ }
-+#else
-+ if (res != -1 || errno != EINVAL) {
-+ ksft_test_result_fail("futex_wait_multiple returned %d\n",
-+ res < 0 ? errno : res);
-+ ret = RET_FAIL;
-+ } else {
-+ ksft_test_result_pass("futex_wait_multiple count overflow succeed\n");
-+ }
-+
-+#endif /* __ILP32__ */
-+}
-+
-+void *waiterfn(void *arg)
-+{
-+ int res;
-+
-+ res = futex_wait_multiple(fwb, MAX_COUNT, NULL, FUTEX_PRIVATE_FLAG);
-+
-+#ifdef __ILP32__
-+ if (res != -1 || errno != ENOSYS) {
-+ ksft_test_result_fail("futex_wait_multiple returned %d\n",
-+ res < 0 ? errno : res);
-+ ret = RET_FAIL;
-+ } else {
-+ ksft_test_result_skip("futex_wait_multiple not supported at x32\n");
-+ }
-+#else
-+ if (res < 0)
-+ ksft_print_msg("waiter failed %d\n", res);
-+
-+ info("futex_wait_multiple: Got hint futex %d was freed\n", res);
-+#endif /* __ILP32__ */
-+
-+ return NULL;
-+}
-+
-+void test_fwb_wakeup(void)
-+{
-+ int res, i;
-+ pthread_t waiter;
-+
-+ ksft_print_msg("%s: Test wake up in a list of futex\n", progname);
-+
-+ for (i = 0; i < MAX_COUNT; i++) {
-+ fwb[i].uaddr = &f[i];
-+ fwb[i].val = f[i];
-+ fwb[i].bitset = 0xffffffff;
-+ }
-+
-+ res = pthread_create(&waiter, NULL, waiterfn, NULL);
-+ if (res) {
-+ ksft_test_result_fail("Creating waiting thread failed");
-+ ksft_exit_fail();
-+ }
-+
-+ usleep(WAKE_WAIT_US);
-+ res = futex_wake(&(f[MAX_COUNT-1]), 1, FUTEX_PRIVATE_FLAG);
-+ if (res != 1) {
-+ ksft_test_result_fail("Failed to wake thread res=%d\n", res);
-+ ksft_exit_fail();
-+ }
-+
-+ pthread_join(waiter, NULL);
-+ ksft_test_result_pass("%s succeed\n", __func__);
-+}
-+
-+int main(int argc, char *argv[])
-+{
-+ int c;
-+
-+ while ((c = getopt(argc, argv, "cht:v:")) != -1) {
-+ switch (c) {
-+ case 'c':
-+ log_color(1);
-+ break;
-+ case 'h':
-+ usage(basename(argv[0]));
-+ exit(0);
-+ case 'v':
-+ log_verbosity(atoi(optarg));
-+ break;
-+ default:
-+ usage(basename(argv[0]));
-+ exit(1);
-+ }
-+ }
-+
-+ progname = basename(argv[0]);
-+
-+ ksft_print_header();
-+ ksft_set_plan(2);
-+
-+ test_count_overflow();
-+
-+#ifdef __ILP32__
-+ // if it's a 32x binary, there's no futex to wakeup
-+ ksft_test_result_skip("futex_wait_multiple not supported at x32\n");
-+#else
-+ test_fwb_wakeup();
-+#endif /* __ILP32__ */
-+
-+ ksft_print_cnts();
-+ return ret;
-+}
-diff --git a/tools/testing/selftests/futex/functional/run.sh b/tools/testing/selftests/futex/functional/run.sh
-index 1acb6ace1680e8f3d6b3ee2dc528c19ddfdb018e..a8be94f28ff78b4879d2d19bca5d9b0fcb26c1f8 100755
---- a/tools/testing/selftests/futex/functional/run.sh
-+++ b/tools/testing/selftests/futex/functional/run.sh
-@@ -73,3 +73,6 @@ echo
- echo
- ./futex_wait_uninitialized_heap $COLOR
- ./futex_wait_private_mapped_file $COLOR
-+
-+echo
-+./futex_wait_multiple $COLOR
+
+From ccdddb50d330d2ee1a4d2cbfdd27bdd7fb10eec3 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Andr=C3=A9=20Almeida?= <andrealmeid@collabora.com>
+Date: Fri, 7 Feb 2020 23:28:02 -0300
+Subject: [PATCH 2/2] futex: Add Proton compatibility code
+
+---
+ include/uapi/linux/futex.h | 2 +-
+ kernel/futex.c | 5 +++--
+ 2 files changed, 4 insertions(+), 3 deletions(-)
+
diff --git a/include/uapi/linux/futex.h b/include/uapi/linux/futex.h
-index 580001e89c6caed57dd8b3cb491d65dce846caff..a3e760886b8e7e74285fdcf2caaaa6f66ad16675 100644
+index 580001e..a3e7608 100644
--- a/include/uapi/linux/futex.h
+++ b/include/uapi/linux/futex.h
@@ -21,7 +21,7 @@
@@ -877,19 +566,19 @@ index 580001e89c6caed57dd8b3cb491d65dce846caff..a3e760886b8e7e74285fdcf2caaaa6f6
#define FUTEX_PRIVATE_FLAG 128
#define FUTEX_CLOCK_REALTIME 256
diff --git a/kernel/futex.c b/kernel/futex.c
-index 58cf9eb2b851b4858e29b5ef4114a29a92e676ba..e0bb628a5e1988dcc9ae5442a4259edc229d578d 100644
+index caba751..84c520c 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
-@@ -4198,7 +4198,7 @@ SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,
+@@ -4074,7 +4074,7 @@ SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,
return -EINVAL;
t = timespec64_to_ktime(ts);
- if (cmd == FUTEX_WAIT)
+ if (cmd == FUTEX_WAIT || cmd == FUTEX_WAIT_MULTIPLE)
t = ktime_add_safe(ktime_get(), t);
- tp = &t;
- }
-@@ -4399,6 +4399,7 @@ COMPAT_SYSCALL_DEFINE3(get_robust_list, int, pid,
+ else if (!(op & FUTEX_CLOCK_REALTIME))
+ t = timens_ktime_to_host(CLOCK_MONOTONIC, t);
+@@ -4277,6 +4277,7 @@ COMPAT_SYSCALL_DEFINE3(get_robust_list, int, pid,
*/
struct compat_futex_wait_block {
compat_uptr_t uaddr;
@@ -897,12 +586,12 @@ index 58cf9eb2b851b4858e29b5ef4114a29a92e676ba..e0bb628a5e1988dcc9ae5442a4259edc
__u32 val;
__u32 bitset;
};
-@@ -4461,7 +4462,7 @@ SYSCALL_DEFINE6(futex_time32, u32 __user *, uaddr, int, op, u32, val,
+@@ -4339,7 +4340,7 @@ SYSCALL_DEFINE6(futex_time32, u32 __user *, uaddr, int, op, u32, val,
return -EINVAL;
t = timespec64_to_ktime(ts);
- if (cmd == FUTEX_WAIT)
+ if (cmd == FUTEX_WAIT || cmd == FUTEX_WAIT_MULTIPLE)
t = ktime_add_safe(ktime_get(), t);
- tp = &t;
- }
+ else if (!(op & FUTEX_CLOCK_REALTIME))
+ t = timens_ktime_to_host(CLOCK_MONOTONIC, t);