summaryrefslogtreecommitdiff
path: root/SOURCES/fsync.patch
diff options
context:
space:
mode:
Diffstat (limited to 'SOURCES/fsync.patch')
-rw-r--r--SOURCES/fsync.patch165
1 files changed, 165 insertions, 0 deletions
diff --git a/SOURCES/fsync.patch b/SOURCES/fsync.patch
new file mode 100644
index 0000000..7fa3fef
--- /dev/null
+++ b/SOURCES/fsync.patch
@@ -0,0 +1,165 @@
+From b70e738f08403950aa3053c36b98c6b0eeb0eb90 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Andr=C3=A9=20Almeida?= <andrealmeid@collabora.com>
+Date: Mon, 25 Oct 2021 09:49:42 -0300
+Subject: [PATCH] futex: Add entry point for FUTEX_WAIT_MULTIPLE (opcode 31)
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add an option to wait on multiple futexes using the old interface, that
+uses opcode 31 through futex() syscall. Do that by just translation the
+old interface to use the new code. This allows old and stable versions
+of Proton to still use fsync in new kernel releases.
+
+Signed-off-by: André Almeida <andrealmeid@collabora.com>
+---
+ include/uapi/linux/futex.h | 12 ++++++
+ kernel/futex.c | 75 +++++++++++++++++++++++++++++++++++++-
+ 2 files changed, 86 insertions(+), 1 deletion(-)
+
+diff --git a/include/uapi/linux/futex.h b/include/uapi/linux/futex.h
+index 2a06b99f9803..417c5d89b745 100644
+--- a/include/uapi/linux/futex.h
++++ b/include/uapi/linux/futex.h
+@@ -22,6 +22,7 @@
+ #define FUTEX_WAIT_REQUEUE_PI 11
+ #define FUTEX_CMP_REQUEUE_PI 12
+ #define FUTEX_LOCK_PI2 13
++#define FUTEX_WAIT_MULTIPLE 31
+
+ #define FUTEX_PRIVATE_FLAG 128
+ #define FUTEX_CLOCK_REALTIME 256
+@@ -68,6 +69,17 @@ struct futex_waitv {
+ __u32 __reserved;
+ };
+
++/**
++ * struct futex_wait_block - Block of futexes to be waited for
++ * @uaddr: User address of the futex
++ * @val: Futex value expected by userspace
++ * @bitset: Bitset for the optional bitmasked wakeup
++ */
++struct futex_wait_block {
++ __u32 __user *uaddr;
++ __u32 val;
++ __u32 bitset;
++};
+
+ /*
+ * Support for robust futexes: the kernel cleans up held futexes at
+diff --git a/kernel/futex.c b/kernel/futex.c
+index 4a9e7ce3714a..c3f2e65afab8 100644
+--- a/kernel/futex.c
++++ b/kernel/futex.c
+@@ -4012,6 +4012,7 @@ static __always_inline bool futex_cmd_has_timeout(u32 cmd)
+ case FUTEX_LOCK_PI2:
+ case FUTEX_WAIT_BITSET:
+ case FUTEX_WAIT_REQUEUE_PI:
++ case FUTEX_WAIT_MULTIPLE:
+ return true;
+ }
+ return false;
+@@ -4024,13 +4025,79 @@ futex_init_timeout(u32 cmd, u32 op, struct timespec64 *ts, ktime_t *t)
+ 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);
+ else if (cmd != FUTEX_LOCK_PI && !(op & FUTEX_CLOCK_REALTIME))
+ *t = timens_ktime_to_host(CLOCK_MONOTONIC, *t);
+ return 0;
+ }
+
++/**
++ * futex_read_wait_block - Read an array of futex_wait_block from userspace
++ * @uaddr: Userspace address of the block
++ * @count: Number of blocks to be read
++ *
++ * This function creates and allocate an array of futex_q (we zero it to
++ * initialize the fields) and then, for each futex_wait_block element from
++ * userspace, fill a futex_q element with proper values.
++ */
++inline struct futex_vector *futex_read_wait_block(u32 __user *uaddr, u32 count)
++{
++ unsigned int i;
++ struct futex_vector *futexv;
++ struct futex_wait_block fwb;
++ struct futex_wait_block __user *entry =
++ (struct futex_wait_block __user *)uaddr;
++
++ if (!count || count > FUTEX_WAITV_MAX)
++ return ERR_PTR(-EINVAL);
++
++ futexv = kcalloc(count, sizeof(*futexv), GFP_KERNEL);
++ if (!futexv)
++ return ERR_PTR(-ENOMEM);
++
++ for (i = 0; i < count; i++) {
++ if (copy_from_user(&fwb, &entry[i], sizeof(fwb))) {
++ kfree(futexv);
++ return ERR_PTR(-EFAULT);
++ }
++
++ futexv[i].w.flags = FUTEX_32;
++ futexv[i].w.val = fwb.val;
++ futexv[i].w.uaddr = (uintptr_t) (fwb.uaddr);
++ futexv[i].q = futex_q_init;
++ }
++
++ return futexv;
++}
++
++int futex_wait_multiple(struct futex_vector *vs, unsigned int count,
++ struct hrtimer_sleeper *to);
++
++int futex_opcode_31(ktime_t *abs_time, u32 __user *uaddr, int count)
++{
++ int ret;
++ struct futex_vector *vs;
++ struct hrtimer_sleeper *to = NULL, timeout;
++
++ to = futex_setup_timer(abs_time, &timeout, 0, 0);
++
++ vs = futex_read_wait_block(uaddr, count);
++
++ if (IS_ERR(vs))
++ return PTR_ERR(vs);
++
++ ret = futex_wait_multiple(vs, count, abs_time ? to : NULL);
++ kfree(vs);
++
++ if (to) {
++ hrtimer_cancel(&to->timer);
++ destroy_hrtimer_on_stack(&to->timer);
++ }
++
++ return ret;
++}
++
+ SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,
+ const struct __kernel_timespec __user *, utime,
+ u32 __user *, uaddr2, u32, val3)
+@@ -4050,6 +4117,9 @@ SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,
+ tp = &t;
+ }
+
++ if (cmd == FUTEX_WAIT_MULTIPLE)
++ return futex_opcode_31(tp, uaddr, val);
++
+ return do_futex(uaddr, op, val, tp, uaddr2, (unsigned long)utime, val3);
+ }
+
+@@ -4551,6 +4621,9 @@ SYSCALL_DEFINE6(futex_time32, u32 __user *, uaddr, int, op, u32, val,
+ tp = &t;
+ }
+
++ if (cmd == FUTEX_WAIT_MULTIPLE)
++ return futex_opcode_31(tp, uaddr, val);
++
+ return do_futex(uaddr, op, val, tp, uaddr2, (unsigned long)utime, val3);
+ }
+ #endif /* CONFIG_COMPAT_32BIT_TIME */
+--
+2.33.1
+