summarylogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.SRCINFO20
-rw-r--r--PKGBUILD10
-rw-r--r--futex-wait-multiple-5.2.1.patch400
3 files changed, 417 insertions, 13 deletions
diff --git a/.SRCINFO b/.SRCINFO
index 19e671c728cf..b6793739e153 100644
--- a/.SRCINFO
+++ b/.SRCINFO
@@ -1,6 +1,6 @@
# Generated by mksrcinfo v8
-# Sun Oct 27 03:05:53 UTC 2019
-pkgbase = linux
+# Sun Oct 27 03:07:11 UTC 2019
+pkgbase = linux-fsync
pkgver = 5.3.7.arch1
pkgrel = 2
url = https://git.archlinux.org/linux.git/log/?h=v5.3.7-arch1
@@ -22,25 +22,27 @@ pkgbase = linux
source = 60-linux.hook
source = 90-linux.hook
source = linux.preset
+ source = futex-wait-multiple-5.2.1.patch
sha256sums = SKIP
sha256sums = e6d2df92f3079c740ca2cafd7e8b34b5dd43832d292284c2dc133d47600d1f29
sha256sums = 452b8d4d71e1565ca91b1bebb280693549222ef51c47ba8964e411b2d461699c
sha256sums = c043f3033bb781e2688794a59f6d1f7ed49ef9b13eb77ff9a425df33a244a636
sha256sums = ad6344badc91ad0630caacde83f7f9b97276f80d26a20619a87952be65492c65
+ sha256sums = b8a9225b4b5cbabac26398d11cc26566e4407d150dacb92f3411c9bb8cc23942
-pkgname = linux
- pkgdesc = The Linux kernel and modules
+pkgname = linux-fsync
+ pkgdesc = The Linux-fsync kernel and modules, including the futex-wait-multiple patchset for testing with Proton fsync
install = linux.install
depends = coreutils
depends = kmod
depends = initramfs
optdepends = crda: to set the correct wireless channels of your country
optdepends = linux-firmware: firmware images needed for some devices
- backup = etc/mkinitcpio.d/linux.preset
+ backup = etc/mkinitcpio.d/linux-fsync.preset
-pkgname = linux-headers
- pkgdesc = Header files and scripts for building modules for Linux kernel
+pkgname = linux-fsync-headers
+ pkgdesc = Header files and scripts for building modules for Linux-fsync kernel
-pkgname = linux-docs
- pkgdesc = Kernel hackers manual - HTML documentation that comes with the Linux kernel
+pkgname = linux-fsync-docs
+ pkgdesc = Kernel hackers manual - HTML documentation that comes with the Linux-fsync kernel
diff --git a/PKGBUILD b/PKGBUILD
index cf9ecf9a6ed6..3517db97ecaa 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -2,8 +2,8 @@
# Maintainer: Tobias Powalowski <tpowa@archlinux.org>
# Contributor: Thomas Baechler <thomas@archlinux.org>
-pkgbase=linux # Build stock -ARCH kernel
-#pkgbase=linux-custom # Build kernel with a different name
+#pkgbase=linux # Build stock -ARCH kernel
+pkgbase=linux-fsync # Build kernel with a different name
_srcver=5.3.7-arch1
pkgver=${_srcver//-/.}
pkgrel=2
@@ -22,6 +22,7 @@ source=(
60-linux.hook # pacman hook for depmod
90-linux.hook # pacman hook for initramfs regeneration
linux.preset # standard config files for mkinitcpio ramdisk
+ futex-wait-multiple-5.2.1.patch # futex-wait-multiple patchset w/opcode 31 for proton-4.11+ testing (aka fsync)
)
validpgpkeys=(
'ABAF11C65A2970B130ABE3C479BE3E4300411886' # Linus Torvalds
@@ -32,7 +33,8 @@ sha256sums=('SKIP'
'e6d2df92f3079c740ca2cafd7e8b34b5dd43832d292284c2dc133d47600d1f29'
'452b8d4d71e1565ca91b1bebb280693549222ef51c47ba8964e411b2d461699c'
'c043f3033bb781e2688794a59f6d1f7ed49ef9b13eb77ff9a425df33a244a636'
- 'ad6344badc91ad0630caacde83f7f9b97276f80d26a20619a87952be65492c65')
+ 'ad6344badc91ad0630caacde83f7f9b97276f80d26a20619a87952be65492c65'
+ 'b8a9225b4b5cbabac26398d11cc26566e4407d150dacb92f3411c9bb8cc23942')
_kernelname=${pkgbase#linux}
: ${_kernelname:=-ARCH}
@@ -72,7 +74,7 @@ build() {
}
_package() {
- pkgdesc="The ${pkgbase/linux/Linux} kernel and modules"
+ pkgdesc="The ${pkgbase/linux/Linux} kernel and modules, including the futex-wait-multiple patchset for testing with Proton fsync"
depends=(coreutils kmod initramfs)
optdepends=('crda: to set the correct wireless channels of your country'
'linux-firmware: firmware images needed for some devices')
diff --git a/futex-wait-multiple-5.2.1.patch b/futex-wait-multiple-5.2.1.patch
new file mode 100644
index 000000000000..d87407ded488
--- /dev/null
+++ b/futex-wait-multiple-5.2.1.patch
@@ -0,0 +1,400 @@
+From 18e885f4d416b8bcfa310f566956276dad5ce4d7 Mon Sep 17 00:00:00 2001
+From: John Schoenick <johns@valvesoftware.com>
+Date: Mon, 22 Jul 2019 17:06:17 -0700
+Subject: [PATCH] Squashed futex-wait-multiple patchset onto stable release
+ v5.2.1
+
+Includes opcode 31 patch for testing with proton-4.11+
+
+Squashed commit of the following:
+
+commit b0396eea1ad67904d96da55996b17cefc97b0a1c
+Author: Gabriel Krisman Bertazi <krisman@collabora.com>
+Date: Wed Jul 17 14:28:26 2019 -0400
+
+ futex: Change WAIT_MULTIPLE opcode to 31
+
+ Signed-off-by: Gabriel Krisman Bertazi <krisman@collabora.com>
+
+commit bac93e6b84a9fd7114e6ec0ab6bca4d54fafc941
+Author: Gabriel Krisman Bertazi <krisman@collabora.com>
+Date: Mon Jul 8 09:44:09 2019 -0400
+
+ futex: Implement FUTEX_WAIT_MULTIPLE
+
+ This is a new futex operation to allow a thread to wait on several
+ futexes at the same time, and wake up on any of them. In a sense, it
+ implements one of the features that was supported by pooling on the old
+ FUTEX_FD interface.
+
+ My use case for this feature lies in Wine, where we want to implement a
+ similar function available in Windows, mainly for event handling. The
+ wine folks have an implementation of the userspace side using eventfd,
+ but it suffers from bad performance, as shown in the measurements below.
+
+ Technically, the old FUTEX_WAIT implementation can be easily
+ reimplemented using do_futex_wait_multiple, with a count one, and I have
+ a patch demonstrating how it works. I'm not proposing it, since futex
+ is such a tricky code, that I'd be more confortable to have
+ FUTEX_WAIT_MULTIPLE running upstream for a couple development cycles,
+ before considering modifying FUTEX_WAIT.
+
+ This was tested using three mechanisms:
+
+ 1) By reimplementing FUTEX_WAIT in terms of FUTEX_WAIT_MULTIPLE and
+ running 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 thread, event handling setup.
+
+ 3) By running the Wine fsync implementation and executing multi-threaded
+ applications, in particular modern games on top of the implementation.
+
+ Signed-off-by: Zebediah Figura <z.figura12@gmail.com>
+ Signed-off-by: Steven Noonan <steven@valvesoftware.com>
+ Signed-off-by: Pierre-Loup A. Griffais <pgriffais@valvesoftware.com>
+ Signed-off-by: Gabriel Krisman Bertazi <krisman@collabora.com>
+
+commit f7817683081a4bb0dea6e8c0c090c9a4e35901bc
+Author: Gabriel Krisman Bertazi <krisman@collabora.com>
+Date: Fri Jul 12 14:16:20 2019 -0400
+
+ futex: Split key setup from key queue locking and read
+
+ split the futex key setup from the queue locking and key reading. This
+ is usefull to support the setup of multiple keys at the same time, like
+ what is done in futex_requeue() and what will be done for the
+ FUTEX_WAIT_MULTIPLE command.
+
+ Signed-off-by: Gabriel Krisman Bertazi <krisman@collabora.com>
+---
+ include/uapi/linux/futex.h | 7 ++
+ kernel/futex.c | 214 ++++++++++++++++++++++++++++++++-----
+ 2 files changed, 196 insertions(+), 25 deletions(-)
+
+diff --git a/include/uapi/linux/futex.h b/include/uapi/linux/futex.h
+index a89eb0accd5e..c34e52e0f787 100644
+--- a/include/uapi/linux/futex.h
++++ b/include/uapi/linux/futex.h
+@@ -21,6 +21,7 @@
+ #define FUTEX_WAKE_BITSET 10
+ #define FUTEX_WAIT_REQUEUE_PI 11
+ #define FUTEX_CMP_REQUEUE_PI 12
++#define FUTEX_WAIT_MULTIPLE 31
+
+ #define FUTEX_PRIVATE_FLAG 128
+ #define FUTEX_CLOCK_REALTIME 256
+@@ -150,4 +151,10 @@ struct robust_list_head {
+ (((op & 0xf) << 28) | ((cmp & 0xf) << 24) \
+ | ((oparg & 0xfff) << 12) | (cmparg & 0xfff))
+
++struct futex_wait_block {
++ __u32 __user *uaddr;
++ __u32 val;
++ __u32 bitset;
++};
++
+ #endif /* _UAPI_LINUX_FUTEX_H */
+diff --git a/kernel/futex.c b/kernel/futex.c
+index 4b5b468c58b6..5c1c2e2c3aeb 100644
+--- a/kernel/futex.c
++++ b/kernel/futex.c
+@@ -183,6 +183,7 @@ static int __read_mostly futex_cmpxchg_enabled;
+ #endif
+ #define FLAGS_CLOCKRT 0x02
+ #define FLAGS_HAS_TIMEOUT 0x04
++#define FLAGS_WAKE_MULTIPLE 0x08
+
+ /*
+ * Priority Inheritance state:
+@@ -2600,6 +2601,39 @@ static void futex_wait_queue_me(struct futex_hash_bucket *hb, struct futex_q *q,
+ __set_current_state(TASK_RUNNING);
+ }
+
++static int __futex_wait_setup(u32 __user *uaddr, u32 val, unsigned int flags,
++ struct futex_q *q, struct futex_hash_bucket **hb)
++{
++
++ u32 uval;
++ int ret;
++
++retry_private:
++ *hb = queue_lock(q);
++
++ ret = get_futex_value_locked(&uval, uaddr);
++
++ if (ret) {
++ queue_unlock(*hb);
++
++ ret = get_user(uval, uaddr);
++ if (ret)
++ return ret;
++
++ if (!(flags & FLAGS_SHARED))
++ goto retry_private;
++
++ return 1;
++ }
++
++ if (uval != val) {
++ queue_unlock(*hb);
++ ret = -EWOULDBLOCK;
++ }
++
++ return ret;
++}
++
+ /**
+ * futex_wait_setup() - Prepare to wait on a futex
+ * @uaddr: the futex userspace address
+@@ -2620,7 +2654,6 @@ static void futex_wait_queue_me(struct futex_hash_bucket *hb, struct futex_q *q,
+ static int futex_wait_setup(u32 __user *uaddr, u32 val, unsigned int flags,
+ struct futex_q *q, struct futex_hash_bucket **hb)
+ {
+- u32 uval;
+ int ret;
+
+ /*
+@@ -2641,38 +2674,161 @@ static int futex_wait_setup(u32 __user *uaddr, u32 val, unsigned int flags,
+ * absorb a wakeup if *uaddr does not match the desired values
+ * while the syscall executes.
+ */
+-retry:
+- ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &q->key, FUTEX_READ);
+- if (unlikely(ret != 0))
+- return ret;
++ do {
++ ret = get_futex_key(uaddr, flags & FLAGS_SHARED,
++ &q->key, FUTEX_READ);
++ if (unlikely(ret != 0))
++ return ret;
+
+-retry_private:
+- *hb = queue_lock(q);
++ ret = __futex_wait_setup(uaddr, val, flags, q, hb);
+
+- ret = get_futex_value_locked(&uval, uaddr);
+-
+- if (ret) {
+- queue_unlock(*hb);
+-
+- ret = get_user(uval, uaddr);
++ /* Drop key reference if retry or error. */
+ if (ret)
++ put_futex_key(&q->key);
++ } while (ret > 0);
++
++ return ret;
++}
++
++static int do_futex_wait_multiple(struct futex_wait_block *wb,
++ u32 count, unsigned int flags,
++ ktime_t *abs_time)
++{
++
++ struct hrtimer_sleeper timeout, *to;
++ struct futex_hash_bucket *hb;
++ struct futex_q *qs = NULL;
++ int ret;
++ int i;
++
++ qs = kcalloc(count, sizeof(struct futex_q), GFP_KERNEL);
++ if (!qs)
++ return -ENOMEM;
++
++ to = futex_setup_timer(abs_time, &timeout, flags,
++ current->timer_slack_ns);
++ retry:
++ for (i = 0; i < count; i++) {
++ qs[i].key = FUTEX_KEY_INIT;
++ qs[i].bitset = wb[i].bitset;
++
++ ret = get_futex_key(wb[i].uaddr, flags & FLAGS_SHARED,
++ &qs[i].key, FUTEX_READ);
++ if (unlikely(ret != 0)) {
++ for (--i; i >= 0; i--)
++ put_futex_key(&qs[i].key);
+ goto out;
++ }
++ }
++
++ set_current_state(TASK_INTERRUPTIBLE);
++
++ for (i = 0; i < count; i++) {
++ ret = __futex_wait_setup(wb[i].uaddr, wb[i].val,
++ flags, &qs[i], &hb);
++ if (ret) {
++ /* Drop the failed key directly. keys 0..(i-1)
++ * will be put by unqueue_me. */
++ put_futex_key(&qs[i].key);
++
++ /* Undo the partial work we did. */
++ for (--i; i >= 0; i--)
++ unqueue_me(&qs[i]);
++
++ __set_current_state(TASK_RUNNING);
++ if (ret > 0)
++ goto retry;
++ goto out;
++ }
++
++ /* We can't hold to the bucket lock when dealing with
++ * the next futex. Queue ourselves now so we can unlock
++ * it before moving on. */
++ queue_me(&qs[i], hb);
++ }
++
++ if (to)
++ hrtimer_start_expires(&to->timer, HRTIMER_MODE_ABS);
++
++ /* There is no easy to way to check if we are wake already on
++ * multiple futexes without waking through each one of them. So
++ * just sleep and let the scheduler handle it.
++ */
++ if (!to || to->task)
++ freezable_schedule();
++
++ __set_current_state(TASK_RUNNING);
++
++ ret = -ETIMEDOUT;
++ /* If we were woken (and unqueued), we succeeded. */
++ for (i = 0; i < count; i++)
++ if (!unqueue_me(&qs[i]))
++ ret = i;
++
++ /* Succeed wakeup */
++ if (ret >= 0)
++ goto out;
+
+- if (!(flags & FLAGS_SHARED))
+- goto retry_private;
++ /* Woken by triggered timeout */
++ if (to && !to->task)
++ goto out;
+
+- put_futex_key(&q->key);
++ /*
++ * We expect signal_pending(current), but we might be the
++ * victim of a spurious wakeup as well.
++ */
++ if (!signal_pending(current))
+ goto retry;
++
++ ret = -ERESTARTSYS;
++ if (!abs_time)
++ goto out;
++
++ ret = -ERESTART_RESTARTBLOCK;
++ out:
++ if (to) {
++ hrtimer_cancel(&to->timer);
++ destroy_hrtimer_on_stack(&to->timer);
+ }
+
+- if (uval != val) {
+- queue_unlock(*hb);
+- ret = -EWOULDBLOCK;
++ kfree(qs);
++ return ret;
++}
++
++static int futex_wait_multiple(u32 __user *uaddr, unsigned int flags,
++ u32 count, ktime_t *abs_time)
++{
++ struct futex_wait_block *wb;
++ struct restart_block *restart;
++ int ret;
++
++ if (!count)
++ return -EINVAL;
++
++ wb = kcalloc(count, sizeof(struct futex_wait_block), GFP_KERNEL);
++ if (!wb)
++ return -ENOMEM;
++
++ if (copy_from_user(wb, uaddr,
++ count * sizeof(struct futex_wait_block))) {
++ ret = -EFAULT;
++ goto out;
++ }
++
++ ret = do_futex_wait_multiple(wb, count, flags, abs_time);
++
++ if (ret == -ERESTART_RESTARTBLOCK) {
++ restart = &current->restart_block;
++ restart->fn = futex_wait_restart;
++ restart->futex.uaddr = uaddr;
++ restart->futex.val = count;
++ restart->futex.time = *abs_time;
++ restart->futex.flags = (flags | FLAGS_HAS_TIMEOUT |
++ FLAGS_WAKE_MULTIPLE);
+ }
+
+ out:
+- if (ret)
+- put_futex_key(&q->key);
++ kfree(wb);
+ return ret;
+ }
+
+@@ -2762,6 +2918,10 @@ static long futex_wait_restart(struct restart_block *restart)
+ }
+ restart->fn = do_no_restart_syscall;
+
++ if (restart->futex.flags & FLAGS_WAKE_MULTIPLE)
++ return (long)futex_wait_multiple(uaddr, restart->futex.flags,
++ restart->futex.val, tp);
++
+ return (long)futex_wait(uaddr, restart->futex.flags,
+ restart->futex.val, tp, restart->futex.bitset);
+ }
+@@ -3658,6 +3818,8 @@ long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
+ uaddr2);
+ case FUTEX_CMP_REQUEUE_PI:
+ return futex_requeue(uaddr, flags, uaddr2, val, val2, &val3, 1);
++ case FUTEX_WAIT_MULTIPLE:
++ return futex_wait_multiple(uaddr, flags, val, timeout);
+ }
+ return -ENOSYS;
+ }
+@@ -3674,7 +3836,8 @@ SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,
+
+ if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI ||
+ cmd == FUTEX_WAIT_BITSET ||
+- cmd == FUTEX_WAIT_REQUEUE_PI)) {
++ cmd == FUTEX_WAIT_REQUEUE_PI ||
++ cmd == FUTEX_WAIT_MULTIPLE)) {
+ if (unlikely(should_fail_futex(!(op & FUTEX_PRIVATE_FLAG))))
+ return -EFAULT;
+ if (get_timespec64(&ts, utime))
+@@ -3683,7 +3846,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;
+ }
+@@ -3867,14 +4030,15 @@ SYSCALL_DEFINE6(futex_time32, u32 __user *, uaddr, int, op, u32, val,
+
+ if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI ||
+ cmd == FUTEX_WAIT_BITSET ||
+- cmd == FUTEX_WAIT_REQUEUE_PI)) {
++ cmd == FUTEX_WAIT_REQUEUE_PI ||
++ cmd == FUTEX_WAIT_MULTIPLE)) {
+ if (get_old_timespec32(&ts, utime))
+ return -EFAULT;
+ if (!timespec64_valid(&ts))
+ 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;
+ }
+--
+2.22.0
+