From f6ed21ac83ffed8b79601c90377739a3ab0265d6 Mon Sep 17 00:00:00 2001 From: Dmitry Skvortsov Date: Thu, 4 Nov 2021 03:14:27 +0300 Subject: [PATCH] linux513/514/515-tkg: Add Fsync1 support on top of futex_waitv patches. (#345) 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. source: https://gitlab.collabora.com/tonyk/linux/-/commit/b70e738f08403950aa3053c36b98c6b0eeb0eb90 --- PKGBUILD | 10 +- linux-tkg-config/prepare | 2 +- .../0007-v5.13-fsync1_via_futex_waitv.patch | 165 ++++++++++++++++++ .../0007-v5.14-fsync1_via_futex_waitv.patch | 165 ++++++++++++++++++ .../0007-v5.15-fsync1_via_futex_waitv.patch | 165 ++++++++++++++++++ 5 files changed, 502 insertions(+), 5 deletions(-) create mode 100644 linux-tkg-patches/5.13/0007-v5.13-fsync1_via_futex_waitv.patch create mode 100644 linux-tkg-patches/5.14/0007-v5.14-fsync1_via_futex_waitv.patch create mode 100644 linux-tkg-patches/5.15/0007-v5.15-fsync1_via_futex_waitv.patch diff --git a/PKGBUILD b/PKGBUILD index a3154bf..671d28a 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -501,6 +501,7 @@ case $_basever in 0007-v5.13-fsync.patch 0007-v5.13-futex2_interface.patch 0007-v5.13-futex_waitv.patch + 0007-v5.13-fsync1_via_futex_waitv.patch 0007-v5.13-winesync.patch 0008-5.13-bcachefs.patch 0009-glitched-ondemand-bmq.patch @@ -532,6 +533,7 @@ case $_basever in '89d837bfea3515504b1c99fc881ebdc4f15e2999558127a263e795fc69408a39' '9ec679871cba674cf876ba836cde969296ae5034bcc10e1ec39b372e6e07aab0' '0e3473c19e5513bee886f03cf2476f746d8b5b2fbc0841c9d60d609b16a97c14' + 'f5ed3062543074472172e30f3db4baa1e292b50e11c1c19e2511b71b28ac7e48' '034d12a73b507133da2c69a34d61efd2f6b6618549650aa26d748142d22002e1' 'b0004bc559653fd8719b8adcfa1ead1075db3425d30d7d7adb8cbc6296386a8f' '9fad4a40449e09522899955762c8928ae17f4cdaa16e01239fd12592e9d58177' @@ -561,9 +563,9 @@ case $_basever in 0005-glitched-pds.patch 0006-add-acs-overrides_iommu.patch 0007-v5.14-fsync.patch - 0007-v5.14-fsync-waitvcompat.patch 0007-v5.14-futex2_interface.patch 0007-v5.14-futex_waitv.patch + 0007-v5.14-fsync1_via_futex_waitv.patch 0007-v5.14-winesync.patch #0008-5.14-bcachefs.patch 0009-glitched-ondemand-bmq.patch @@ -589,9 +591,9 @@ case $_basever in 'fca63d15ca4502aebd73e76d7499b243d2c03db71ff5ab0bf5cf268b2e576320' '19661ec0d39f9663452b34433214c755179894528bf73a42f6ba52ccf572832a' 'aa67e81a27d9062e463594acb91eca6dd13388f23cbe53ca56298f9dba61cc10' - 'ee97a751e9b3d2b7ea1707b807ab775cd6f4c392a5efaa475d24d16202518a6a' 'efe5e21706fdf64559ead866c85a5d88c5c3f743d814410df3810ca61cc5b966' '5742277f41f22bf29fa9742562946b8a01377f8a22adb42ceed3607541c1d5b6' + '5bd2e13d3c70abe4efefa1c4374a5d3801fece087f093ce6a8ca5b8466dc1f20' '034d12a73b507133da2c69a34d61efd2f6b6618549650aa26d748142d22002e1' '9fad4a40449e09522899955762c8928ae17f4cdaa16e01239fd12592e9d58177' 'a557b342111849a5f920bbe1c129f3ff1fc1eff62c6bd6685e0972fc88e39911' @@ -619,8 +621,8 @@ case $_basever in 0005-glitched-pds.patch 0006-add-acs-overrides_iommu.patch 0007-v5.15-fsync.patch - 0007-v5.15-fsync-waitvcompat.patch 0007-v5.15-futex_waitv.patch + 0007-v5.15-fsync1_via_futex_waitv.patch 0007-v5.15-winesync.patch #0008-5.14-bcachefs.patch 0009-glitched-ondemand-bmq.patch @@ -646,8 +648,8 @@ case $_basever in 'fca63d15ca4502aebd73e76d7499b243d2c03db71ff5ab0bf5cf268b2e576320' '19661ec0d39f9663452b34433214c755179894528bf73a42f6ba52ccf572832a' '6c4f0099896f69e56ebd8c9eac266ac8ad993acecd50945e0e84ef6f95f9ddca' - 'd6753a5d95a422eeb443edc04dee67512de8408aac1231e8f2e8ff9e000ad48e' 'c8f7c50d9b1418ba22b5ca735c47111a162be416109714d26a674162e5b2cb97' + '63a2ddf7ca9d3922f4eac3ac66bc37ffb10ad8b18b3e596832d3faa66b93dfa6' '034d12a73b507133da2c69a34d61efd2f6b6618549650aa26d748142d22002e1' '9fad4a40449e09522899955762c8928ae17f4cdaa16e01239fd12592e9d58177' 'a557b342111849a5f920bbe1c129f3ff1fc1eff62c6bd6685e0972fc88e39911' diff --git a/linux-tkg-config/prepare b/linux-tkg-config/prepare index b65cbde..fabf4d3 100644 --- a/linux-tkg-config/prepare +++ b/linux-tkg-config/prepare @@ -1170,7 +1170,7 @@ CONFIG_DEBUG_INFO_BTF_MODULES=y\r # fsync support if [[ "$CONDITION9" =~ [yY] ]] || [ "$_futex_waitv" = "true" ]; then - tkgpatch="$srcdir/0007-v${_basekernel}-fsync-waitvcompat.patch" + tkgpatch="$srcdir/0007-v${_basekernel}-fsync1_via_futex_waitv.patch" else tkgpatch="$srcdir/0007-v${_basekernel}-fsync.patch" fi diff --git a/linux-tkg-patches/5.13/0007-v5.13-fsync1_via_futex_waitv.patch b/linux-tkg-patches/5.13/0007-v5.13-fsync1_via_futex_waitv.patch new file mode 100644 index 0000000..dd150f3 --- /dev/null +++ b/linux-tkg-patches/5.13/0007-v5.13-fsync1_via_futex_waitv.patch @@ -0,0 +1,165 @@ +From b70e738f08403950aa3053c36b98c6b0eeb0eb90 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Andr=C3=A9=20Almeida?= +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 +--- + 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 1666f5e4b837..e1616d5b845b 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 +@@ -66,6 +67,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 d7dc0bd9379c..29ae2e20e024 100644 +--- a/kernel/futex.c ++++ b/kernel/futex.c +@@ -3775,6 +3775,7 @@ static __always_inline bool futex_cmd_has_timeout(u32 cmd) + case FUTEX_LOCK_PI: + case FUTEX_WAIT_BITSET: + case FUTEX_WAIT_REQUEUE_PI: ++ case FUTEX_WAIT_MULTIPLE: + return true; + } + return false; +@@ -3787,13 +3788,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) +@@ -3813,6 +3880,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); + } + +@@ -4314,6 +4384,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 */ +-- +GitLab + diff --git a/linux-tkg-patches/5.14/0007-v5.14-fsync1_via_futex_waitv.patch b/linux-tkg-patches/5.14/0007-v5.14-fsync1_via_futex_waitv.patch new file mode 100644 index 0000000..88c86c2 --- /dev/null +++ b/linux-tkg-patches/5.14/0007-v5.14-fsync1_via_futex_waitv.patch @@ -0,0 +1,165 @@ +From b70e738f08403950aa3053c36b98c6b0eeb0eb90 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Andr=C3=A9=20Almeida?= +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 +--- + 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 3c060c859a43..27f23a2ba8c0 100644 +--- a/kernel/futex.c ++++ b/kernel/futex.c +@@ -3778,6 +3778,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; +@@ -3790,13 +3791,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) +@@ -3816,6 +3883,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); + } + +@@ -4317,6 +4387,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 + diff --git a/linux-tkg-patches/5.15/0007-v5.15-fsync1_via_futex_waitv.patch b/linux-tkg-patches/5.15/0007-v5.15-fsync1_via_futex_waitv.patch new file mode 100644 index 0000000..7fa3fef --- /dev/null +++ b/linux-tkg-patches/5.15/0007-v5.15-fsync1_via_futex_waitv.patch @@ -0,0 +1,165 @@ +From b70e738f08403950aa3053c36b98c6b0eeb0eb90 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Andr=C3=A9=20Almeida?= +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 +--- + 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 +