summaryrefslogtreecommitdiff
path: root/SOURCES/futex2.patch
diff options
context:
space:
mode:
authorJan200101 <sentrycraft123@gmail.com>2021-01-15 00:10:49 +0100
committerJan200101 <sentrycraft123@gmail.com>2021-01-15 00:10:49 +0100
commit3814de27892f88d7bee46f434d386ada761fd4ba (patch)
tree0470c6d559ec46201e695664cfaef60ea541f4df /SOURCES/futex2.patch
parentd6cbdaa78bfe1ecf6aa6a95e743bcba390a2ae93 (diff)
downloadkernel-fsync-3814de27892f88d7bee46f434d386ada761fd4ba.tar.gz
kernel-fsync-3814de27892f88d7bee46f434d386ada761fd4ba.zip
kernel 5.10.6
Diffstat (limited to 'SOURCES/futex2.patch')
-rw-r--r--SOURCES/futex2.patch6056
1 files changed, 1172 insertions, 4884 deletions
diff --git a/SOURCES/futex2.patch b/SOURCES/futex2.patch
index bae4138..1bc4486 100644
--- a/SOURCES/futex2.patch
+++ b/SOURCES/futex2.patch
@@ -1,7 +1,7 @@
-From ada1f13b98e86cb7ac4140c4976c3d165006d995 Mon Sep 17 00:00:00 2001
+From 14a106cc87e6d03169ac8c7ea030e3d7fac2dfe4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9=20Almeida?= <andrealmeid@collabora.com>
Date: Wed, 5 Aug 2020 12:40:26 -0300
-Subject: [PATCH 01/13] futex2: Add new futex interface
+Subject: [PATCH 1/9] futex2: Add new futex interface
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
@@ -10,25 +10,28 @@ Initial implementation for futex2. Support only private u32 wait/wake, with
timeout (monotonic and realtime clocks).
Signed-off-by: André Almeida <andrealmeid@collabora.com>
+Signed-off-by: Jan200101 <sentrycraft123@gmail.com>
---
- MAINTAINERS | 2 +-
- arch/x86/entry/syscalls/syscall_32.tbl | 2 +
- arch/x86/entry/syscalls/syscall_64.tbl | 2 +
- include/linux/syscalls.h | 7 +
- include/uapi/asm-generic/unistd.h | 8 +-
- include/uapi/linux/futex.h | 40 ++
- init/Kconfig | 7 +
- kernel/Makefile | 1 +
- kernel/futex2.c | 484 +++++++++++++++++++++++++
- kernel/sys_ni.c | 4 +
- 10 files changed, 555 insertions(+), 2 deletions(-)
+ MAINTAINERS | 2 +-
+ arch/x86/entry/syscalls/syscall_32.tbl | 2 +
+ arch/x86/entry/syscalls/syscall_64.tbl | 2 +
+ include/linux/syscalls.h | 7 +
+ include/uapi/asm-generic/unistd.h | 8 +-
+ include/uapi/linux/futex.h | 40 ++
+ init/Kconfig | 7 +
+ kernel/Makefile | 1 +
+ kernel/futex2.c | 484 ++++++++++++++++++
+ kernel/sys_ni.c | 4 +
+ tools/include/uapi/asm-generic/unistd.h | 9 +-
+ .../arch/x86/entry/syscalls/syscall_64.tbl | 2 +
+ 12 files changed, 565 insertions(+), 3 deletions(-)
create mode 100644 kernel/futex2.c
diff --git a/MAINTAINERS b/MAINTAINERS
-index 867157311dc8..0c425f74ed88 100644
+index 2daa6ee67..855d38511 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
-@@ -7214,7 +7214,7 @@ F: Documentation/locking/*futex*
+@@ -7259,7 +7259,7 @@ F: Documentation/locking/*futex*
F: include/asm-generic/futex.h
F: include/linux/futex.h
F: include/uapi/linux/futex.h
@@ -38,30 +41,30 @@ index 867157311dc8..0c425f74ed88 100644
F: tools/testing/selftests/futex/
diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl
-index 9d1102873666..955322962964 100644
+index 0d0667a9f..83a75ff39 100644
--- a/arch/x86/entry/syscalls/syscall_32.tbl
+++ b/arch/x86/entry/syscalls/syscall_32.tbl
-@@ -444,3 +444,5 @@
- 437 i386 openat2 sys_openat2
+@@ -445,3 +445,5 @@
438 i386 pidfd_getfd sys_pidfd_getfd
439 i386 faccessat2 sys_faccessat2
-+440 i386 futex_wait sys_futex_wait
-+441 i386 futex_wake sys_futex_wake
+ 440 i386 process_madvise sys_process_madvise
++441 i386 futex_wait sys_futex_wait
++442 i386 futex_wake sys_futex_wake
diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl
-index f30d6ae9a688..4133bfe96891 100644
+index 379819244..6658fd63c 100644
--- a/arch/x86/entry/syscalls/syscall_64.tbl
+++ b/arch/x86/entry/syscalls/syscall_64.tbl
-@@ -361,6 +361,8 @@
- 437 common openat2 sys_openat2
+@@ -362,6 +362,8 @@
438 common pidfd_getfd sys_pidfd_getfd
439 common faccessat2 sys_faccessat2
-+440 common futex_wait sys_futex_wait
-+441 common futex_wake sys_futex_wake
+ 440 common process_madvise sys_process_madvise
++441 common futex_wait sys_futex_wait
++442 common futex_wake sys_futex_wake
#
- # x32-specific system call numbers start at 512 to avoid cache impact
+ # Due to a historical design error, certain syscalls are numbered differently
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
-index 75ac7f8ae93c..38c3a87dbfc2 100644
+index 37bea07c1..b6b77cf2b 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -589,6 +589,13 @@ asmlinkage long sys_get_robust_list(int pid,
@@ -79,27 +82,27 @@ index 75ac7f8ae93c..38c3a87dbfc2 100644
asmlinkage long sys_nanosleep(struct __kernel_timespec __user *rqtp,
struct __kernel_timespec __user *rmtp);
diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h
-index 995b36c2ea7d..80567ade774a 100644
+index 205631898..ae47d6a9e 100644
--- a/include/uapi/asm-generic/unistd.h
+++ b/include/uapi/asm-generic/unistd.h
-@@ -860,8 +860,14 @@ __SYSCALL(__NR_pidfd_getfd, sys_pidfd_getfd)
- #define __NR_faccessat2 439
- __SYSCALL(__NR_faccessat2, sys_faccessat2)
+@@ -860,8 +860,14 @@ __SYSCALL(__NR_faccessat2, sys_faccessat2)
+ #define __NR_process_madvise 440
+ __SYSCALL(__NR_process_madvise, sys_process_madvise)
-+#define __NR_futex_wait 440
++#define __NR_futex_wait 441
+__SYSCALL(__NR_futex_wait, sys_futex_wait)
+
-+#define __NR_futex_wake 441
++#define __NR_futex_wake 442
+__SYSCALL(__NR_futex_wake, sys_futex_wake)
+
#undef __NR_syscalls
--#define __NR_syscalls 440
-+#define __NR_syscalls 442
+-#define __NR_syscalls 441
++#define __NR_syscalls 443
/*
* 32 bit systems traditionally used different
diff --git a/include/uapi/linux/futex.h b/include/uapi/linux/futex.h
-index a89eb0accd5e..35a5bf1cd41b 100644
+index a89eb0acc..35a5bf1cd 100644
--- a/include/uapi/linux/futex.h
+++ b/include/uapi/linux/futex.h
@@ -41,6 +41,46 @@
@@ -150,7 +153,7 @@ index a89eb0accd5e..35a5bf1cd41b 100644
* Support for robust futexes: the kernel cleans up held futexes at
* thread exit time.
diff --git a/init/Kconfig b/init/Kconfig
-index 2a5df1cf838c..440f21f5c3d8 100644
+index 02d13ae27..1264687ea 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1522,6 +1522,13 @@ config FUTEX
@@ -168,10 +171,10 @@ index 2a5df1cf838c..440f21f5c3d8 100644
bool
depends on FUTEX && RT_MUTEXES
diff --git a/kernel/Makefile b/kernel/Makefile
-index 9a20016d4900..51ea9bc647bf 100644
+index af601b9bd..bb7f33986 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
-@@ -57,6 +57,7 @@ obj-$(CONFIG_PROFILING) += profile.o
+@@ -54,6 +54,7 @@ obj-$(CONFIG_PROFILING) += profile.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-y += time/
obj-$(CONFIG_FUTEX) += futex.o
@@ -181,7 +184,7 @@ index 9a20016d4900..51ea9bc647bf 100644
ifneq ($(CONFIG_SMP),y)
diff --git a/kernel/futex2.c b/kernel/futex2.c
new file mode 100644
-index 000000000000..107b80a466d0
+index 000000000..107b80a46
--- /dev/null
+++ b/kernel/futex2.c
@@ -0,0 +1,484 @@
@@ -670,7 +673,7 @@ index 000000000000..107b80a466d0
+}
+core_initcall(futex2_init);
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
-index 4d59775ea79c..10049bc56c24 100644
+index f27ac94d5..35ff743b1 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -148,6 +148,10 @@ COND_SYSCALL_COMPAT(set_robust_list);
@@ -684,13 +687,48 @@ index 4d59775ea79c..10049bc56c24 100644
/* kernel/hrtimer.c */
/* kernel/itimer.c */
+diff --git a/tools/include/uapi/asm-generic/unistd.h b/tools/include/uapi/asm-generic/unistd.h
+index 205631898..cd79f94e0 100644
+--- a/tools/include/uapi/asm-generic/unistd.h
++++ b/tools/include/uapi/asm-generic/unistd.h
+@@ -860,8 +860,15 @@ __SYSCALL(__NR_faccessat2, sys_faccessat2)
+ #define __NR_process_madvise 440
+ __SYSCALL(__NR_process_madvise, sys_process_madvise)
+
++#define __NR_futex_wait 441
++__SYSCALL(__NR_futex_wait, sys_futex_wait)
++
++#define __NR_futex_wake 442
++__SYSCALL(__NR_futex_wake, sys_futex_wake)
++
+ #undef __NR_syscalls
+-#define __NR_syscalls 441
++#define __NR_syscalls 443
++
+
+ /*
+ * 32 bit systems traditionally used different
+diff --git a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl
+index 379819244..47de3bf93 100644
+--- a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl
++++ b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl
+@@ -362,6 +362,8 @@
+ 438 common pidfd_getfd sys_pidfd_getfd
+ 439 common faccessat2 sys_faccessat2
+ 440 common process_madvise sys_process_madvise
++441 common futex_wait sys_futex_wait
++442 common futex_wake sys_futex_wake
+
+ #
+ # Due to a historical design error, certain syscalls are numbered differently
--
-2.28.0
+2.29.2
+
-From 08110d54945541dd186a7dabeef58be08011dde7 Mon Sep 17 00:00:00 2001
+From d71973d99efb1e2fd2542ea4d4b45b0e03e45b9c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9=20Almeida?= <andrealmeid@collabora.com>
Date: Thu, 15 Oct 2020 17:15:57 -0300
-Subject: [PATCH 02/13] futex2: Add suport for vectorized wait
+Subject: [PATCH 2/9] futex2: Add suport for vectorized wait
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
@@ -698,54 +736,57 @@ Content-Transfer-Encoding: 8bit
Add support to wait on multiple futexes
Signed-off-by: André Almeida <andrealmeid@collabora.com>
+Signed-off-by: Jan200101 <sentrycraft123@gmail.com>
---
- arch/x86/entry/syscalls/syscall_32.tbl | 1 +
- arch/x86/entry/syscalls/syscall_64.tbl | 1 +
- include/uapi/asm-generic/unistd.h | 5 +-
- kernel/futex2.c | 430 +++++++++++++++++--------
- kernel/sys_ni.c | 1 +
- 5 files changed, 304 insertions(+), 134 deletions(-)
+ arch/x86/entry/syscalls/syscall_32.tbl | 1 +
+ arch/x86/entry/syscalls/syscall_64.tbl | 1 +
+ include/uapi/asm-generic/unistd.h | 5 +-
+ kernel/futex2.c | 430 ++++++++++++------
+ kernel/sys_ni.c | 1 +
+ tools/include/uapi/asm-generic/unistd.h | 5 +-
+ .../arch/x86/entry/syscalls/syscall_64.tbl | 1 +
+ 7 files changed, 309 insertions(+), 135 deletions(-)
diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl
-index 955322962964..c844c0cbf0e5 100644
+index 83a75ff39..65734d5e1 100644
--- a/arch/x86/entry/syscalls/syscall_32.tbl
+++ b/arch/x86/entry/syscalls/syscall_32.tbl
-@@ -446,3 +446,4 @@
- 439 i386 faccessat2 sys_faccessat2
- 440 i386 futex_wait sys_futex_wait
- 441 i386 futex_wake sys_futex_wake
-+442 i386 futex_waitv sys_futex_waitv
+@@ -447,3 +447,4 @@
+ 440 i386 process_madvise sys_process_madvise
+ 441 i386 futex_wait sys_futex_wait
+ 442 i386 futex_wake sys_futex_wake
++443 i386 futex_waitv sys_futex_waitv
diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl
-index 4133bfe96891..0901c26c6786 100644
+index 6658fd63c..f30811b56 100644
--- a/arch/x86/entry/syscalls/syscall_64.tbl
+++ b/arch/x86/entry/syscalls/syscall_64.tbl
-@@ -363,6 +363,7 @@
- 439 common faccessat2 sys_faccessat2
- 440 common futex_wait sys_futex_wait
- 441 common futex_wake sys_futex_wake
-+442 common futex_waitv sys_futex_waitv
+@@ -364,6 +364,7 @@
+ 440 common process_madvise sys_process_madvise
+ 441 common futex_wait sys_futex_wait
+ 442 common futex_wake sys_futex_wake
++443 common futex_waitv sys_futex_waitv
#
- # x32-specific system call numbers start at 512 to avoid cache impact
+ # Due to a historical design error, certain syscalls are numbered differently
diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h
-index 80567ade774a..d7ebbed0a18c 100644
+index ae47d6a9e..81a90b697 100644
--- a/include/uapi/asm-generic/unistd.h
+++ b/include/uapi/asm-generic/unistd.h
@@ -866,8 +866,11 @@ __SYSCALL(__NR_futex_wait, sys_futex_wait)
- #define __NR_futex_wake 441
+ #define __NR_futex_wake 442
__SYSCALL(__NR_futex_wake, sys_futex_wake)
-+#define __NR_futex_waitv 442
++#define __NR_futex_waitv 443
+__SYSCALL(__NR_futex_waitv, sys_futex_waitv)
+
#undef __NR_syscalls
--#define __NR_syscalls 442
-+#define __NR_syscalls 443
+-#define __NR_syscalls 443
++#define __NR_syscalls 444
/*
* 32 bit systems traditionally used different
diff --git a/kernel/futex2.c b/kernel/futex2.c
-index 107b80a466d0..4b782b5ef615 100644
+index 107b80a46..4b782b5ef 100644
--- a/kernel/futex2.c
+++ b/kernel/futex2.c
@@ -48,14 +48,25 @@ struct futex_bucket {
@@ -1286,7 +1327,7 @@ index 107b80a466d0..4b782b5ef615 100644
get_task_struct(task);
list_del_init_careful(&aux->list);
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
-index 10049bc56c24..3e1a713d3e57 100644
+index 35ff743b1..1898e7340 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -151,6 +151,7 @@ COND_SYSCALL_COMPAT(get_robust_list);
@@ -1297,13 +1338,431 @@ index 10049bc56c24..3e1a713d3e57 100644
/* kernel/hrtimer.c */
+diff --git a/tools/include/uapi/asm-generic/unistd.h b/tools/include/uapi/asm-generic/unistd.h
+index cd79f94e0..7de33be59 100644
+--- a/tools/include/uapi/asm-generic/unistd.h
++++ b/tools/include/uapi/asm-generic/unistd.h
+@@ -866,8 +866,11 @@ __SYSCALL(__NR_futex_wait, sys_futex_wait)
+ #define __NR_futex_wake 442
+ __SYSCALL(__NR_futex_wake, sys_futex_wake)
+
++#define __NR_futex_waitv 443
++__SYSCALL(__NR_futex_waitv, sys_futex_waitv)
++
+ #undef __NR_syscalls
+-#define __NR_syscalls 443
++#define __NR_syscalls 444
+
+
+ /*
+diff --git a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl
+index 47de3bf93..bd47f368f 100644
+--- a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl
++++ b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl
+@@ -364,6 +364,7 @@
+ 440 common process_madvise sys_process_madvise
+ 441 common futex_wait sys_futex_wait
+ 442 common futex_wake sys_futex_wake
++443 common futex_waitv sys_futex_waitv
+
+ #
+ # Due to a historical design error, certain syscalls are numbered differently
+--
+2.29.2
+
+
+From 24681616a5432f7680f934abf335a9ab9a1eaf1e Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Andr=C3=A9=20Almeida?= <andrealmeid@collabora.com>
+Date: Thu, 15 Oct 2020 18:06:40 -0300
+Subject: [PATCH 3/9] futex2: Add support for shared futexes
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add support for shared futexes for cross-process resources.
+
+Signed-off-by: André Almeida <andrealmeid@collabora.com>
+Signed-off-by: Jan200101 <sentrycraft123@gmail.com>
+---
+ kernel/futex2.c | 187 ++++++++++++++++++++++++++++++++++++++++++------
+ 1 file changed, 165 insertions(+), 22 deletions(-)
+
+diff --git a/kernel/futex2.c b/kernel/futex2.c
+index 4b782b5ef..5ddb9922d 100644
+--- a/kernel/futex2.c
++++ b/kernel/futex2.c
+@@ -6,7 +6,9 @@
+ */
+
+ #include <linux/freezer.h>
++#include <linux/hugetlb.h>
+ #include <linux/jhash.h>
++#include <linux/pagemap.h>
+ #include <linux/sched/wake_q.h>
+ #include <linux/spinlock.h>
+ #include <linux/syscalls.h>
+@@ -15,6 +17,7 @@
+
+ /**
+ * struct futex_waiter - List entry for a waiter
++ * @uaddr: Memory address of userspace futex
+ * @key.address: Memory address of userspace futex
+ * @key.mm: Pointer to memory management struct of this process
+ * @key: Stores information that uniquely identify a futex
+@@ -25,9 +28,11 @@
+ * @index: Index of waiter in futexv list
+ */
+ struct futex_waiter {
++ uintptr_t uaddr;
+ struct futex_key {
+ uintptr_t address;
+ struct mm_struct *mm;
++ unsigned long int offset;
+ } key;
+ struct list_head list;
+ unsigned int val;
+@@ -125,16 +130,116 @@ static inline int bucket_get_waiters(struct futex_bucket *bucket)
+ #endif
+ }
+
++static u64 get_inode_sequence_number(struct inode *inode)
++{
++ static atomic64_t i_seq;
++ u64 old;
++
++ /* Does the inode already have a sequence number? */
++ old = atomic64_read(&inode->i_sequence);
++ if (likely(old))
++ return old;
++
++ for (;;) {
++ u64 new = atomic64_add_return(1, &i_seq);
++ if (WARN_ON_ONCE(!new))
++ continue;
++
++ old = atomic64_cmpxchg_relaxed(&inode->i_sequence, 0, new);
++ if (old)
++ return old;
++ return new;
++ }
++}
++
++#define FUT_OFF_INODE 1 /* We set bit 0 if key has a reference on inode */
++#define FUT_OFF_MMSHARED 2 /* We set bit 1 if key has a reference on mm */
++
++static int futex_get_shared_key(uintptr_t address, struct mm_struct *mm,
++ struct futex_key *key)
++{
++ int err;
++ struct page *page, *tail;
++ struct address_space *mapping;
++
++again:
++ err = get_user_pages_fast(address, 1, 0, &page);
++
++ if (err < 0)
++ return err;
++ else
++ err = 0;
++
++
++ tail = page;
++ page = compound_head(page);
++ mapping = READ_ONCE(page->mapping);
++
++
++ if (unlikely(!mapping)) {
++ int shmem_swizzled;
++
++ lock_page(page);
++ shmem_swizzled = PageSwapCache(page) || page->mapping;
++ unlock_page(page);
++ put_page(page);
++
++ if (shmem_swizzled)
++ goto again;
++
++ return -EFAULT;
++ }
++
++ if (PageAnon(page)) {
++
++ key->mm = mm;
++ key->address = address;
++
++ key->offset |= FUT_OFF_MMSHARED;
++
++ } else {
++ struct inode *inode;
++
++ rcu_read_lock();
++
++ if (READ_ONCE(page->mapping) != mapping) {
++ rcu_read_unlock();
++ put_page(page);
++
++ goto again;
++ }
++
++ inode = READ_ONCE(mapping->host);
++ if (!inode) {
++ rcu_read_unlock();
++ put_page(page);
++
++ goto again;
++ }
++
++ key->address = get_inode_sequence_number(inode);
++ key->mm = (struct mm_struct *) basepage_index(tail);
++ key->offset |= FUT_OFF_INODE;
++
++ rcu_read_unlock();
++ }
++
++ put_page(page);
++ return err;
++}
++
+ /**
+ * futex_get_bucket - Check if the user address is valid, prepare internal
+ * data and calculate the hash
+ * @uaddr: futex user address
+ * @key: data that uniquely identifies a futex
++ * @shared: is this a shared futex?
+ *
+ * Return: address of bucket on success, error code otherwise
+ */
+ static struct futex_bucket *futex_get_bucket(void __user *uaddr,
+- struct futex_key *key)
++ struct futex_key *key,
++ bool shared)
+ {
+ uintptr_t address = (uintptr_t) uaddr;
+ u32 hash_key;
+@@ -145,8 +250,15 @@ static struct futex_bucket *futex_get_bucket(void __user *uaddr,
+ if (unlikely(!access_ok(address, sizeof(u32))))
+ return ERR_PTR(-EFAULT);
+
+- key->address = address;
+- key->mm = current->mm;
++ key->offset = address % PAGE_SIZE;
++ address -= key->offset;
++
++ if (!shared) {
++ key->address = address;
++ key->mm = current->mm;
++ } else {
++ futex_get_shared_key(address, current->mm, key);
++ }
+
+ /* Generate hash key for this futex using uaddr and current->mm */
+ hash_key = jhash2((u32 *) key, sizeof(*key) / sizeof(u32), 0);
+@@ -275,9 +387,10 @@ static int futex_dequeue_multiple(struct futexv *futexv, unsigned int nr)
+ * Return: 0 on success, error code otherwise
+ */
+ static int futex_enqueue(struct futexv *futexv, unsigned int nr_futexes,
+- unsigned int *awaken)
++ int *awaken)
+ {
+ int i, ret;
++ bool shared, retry = false;
+ u32 uval, *uaddr, val;
+ struct futex_bucket *bucket;
+
+@@ -285,8 +398,18 @@ static int futex_enqueue(struct futexv *futexv, unsigned int nr_futexes,
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ for (i = 0; i < nr_futexes; i++) {
+- uaddr = (u32 * __user) futexv->objects[i].key.address;
++ uaddr = (u32 * __user) futexv->objects[i].uaddr;
+ val = (u32) futexv->objects[i].val;
++ shared = (futexv->objects[i].flags & FUTEX_SHARED_FLAG) ? true : false;
++
++ if (shared && retry) {
++ futexv->objects[i].bucket =
++ futex_get_bucket((void *) uaddr,
++ &futexv->objects[i].key, true);
++ if (IS_ERR(futexv->objects[i].bucket))
++ return PTR_ERR(futexv->objects[i].bucket);
++ }
++
+ bucket = futexv->objects[i].bucket;
+
+ bucket_inc_waiters(bucket);
+@@ -301,24 +424,32 @@ static int futex_enqueue(struct futexv *futexv, unsigned int nr_futexes,
+ __set_current_state(TASK_RUNNING);
+ *awaken = futex_dequeue_multiple(futexv, i);
+
++ if (shared) {
++ retry = true;
++ goto retry;
++ }
++
+ if (__get_user(uval, uaddr))
+ return -EFAULT;
+
+ if (*awaken >= 0)
+- return 0;
++ return 1;
+
++ retry = true;
+ goto retry;
+ }
+
+ if (uval != val) {
+ spin_unlock(&bucket->lock);
+
++
+ bucket_dec_waiters(bucket);
+ __set_current_state(TASK_RUNNING);
+ *awaken = futex_dequeue_multiple(futexv, i);
+
+- if (*awaken >= 0)
+- return 0;
++ if (*awaken >= 0) {
++ return 1;
++ }
+
+ return -EWOULDBLOCK;
+ }
+@@ -336,19 +467,18 @@ static int __futex_wait(struct futexv *futexv,
+ struct hrtimer_sleeper *timeout)
+ {
+ int ret;
+- unsigned int awaken = -1;
+
+- while (1) {
+- ret = futex_enqueue(futexv, nr_futexes, &awaken);
+
+- if (ret < 0)
+- break;
++ while (1) {
++ int awaken = -1;
+
+- if (awaken <= 0) {
+- return awaken;
++ ret = futex_enqueue(futexv, nr_futexes, &awaken);
++ if (ret) {
++ if (awaken >= 0)
++ return awaken;
++ return ret;
+ }
+
+-
+ /* Before sleeping, check if someone was woken */
+ if (!futexv->hint && (!timeout || timeout->task))
+ freezable_schedule();
+@@ -419,6 +549,7 @@ static int futex_wait(struct futexv *futexv, unsigned int nr_futexes,
+ hrtimer_sleeper_start_expires(timeout, HRTIMER_MODE_ABS);
+ }
+
++
+ ret = __futex_wait(futexv, nr_futexes, timo ? timeout : NULL);
+
+
+@@ -438,9 +569,10 @@ static int futex_wait(struct futexv *futexv, unsigned int nr_futexes,
+ SYSCALL_DEFINE4(futex_wait, void __user *, uaddr, unsigned int, val,
+ unsigned int, flags, struct __kernel_timespec __user *, timo)
+ {
++ bool shared = (flags & FUTEX_SHARED_FLAG) ? true : false;
+ unsigned int size = flags & FUTEX_SIZE_MASK;
+- struct hrtimer_sleeper timeout;
+ struct futex_single_waiter wait_single;
++ struct hrtimer_sleeper timeout;
+ struct futex_waiter *waiter;
+ struct futexv *futexv;
+ int ret;
+@@ -452,6 +584,7 @@ SYSCALL_DEFINE4(futex_wait, void __user *, uaddr, unsigned int, val,
+ waiter = &wait_single.waiter;
+ waiter->index = 0;
+ waiter->val = val;
++ waiter->uaddr = (uintptr_t) uaddr;
+
+ INIT_LIST_HEAD(&waiter->list);
+
+@@ -462,11 +595,14 @@ SYSCALL_DEFINE4(futex_wait, void __user *, uaddr, unsigned int, val,
+ return -EINVAL;
+
+ /* Get an unlocked hash bucket */
+- waiter->bucket = futex_get_bucket(uaddr, &waiter->key);
+- if (IS_ERR(waiter->bucket))
++ waiter->bucket = futex_get_bucket(uaddr, &waiter->key, shared);
++ if (IS_ERR(waiter->bucket)) {
+ return PTR_ERR(waiter->bucket);
++ }
+
+ ret = futex_wait(futexv, 1, timo, &timeout, flags);
++ if (ret > 0)
++ ret = 0;
+
+ return ret;
+ }
+@@ -486,8 +622,10 @@ static int futex_parse_waitv(struct futexv *futexv,
+ struct futex_waitv waitv;
+ unsigned int i;
+ struct futex_bucket *bucket;
++ bool shared;
+
+ for (i = 0; i < nr_futexes; i++) {
++
+ if (copy_from_user(&waitv, &uwaitv[i], sizeof(waitv)))
+ return -EFAULT;
+
+@@ -495,8 +633,10 @@ static int futex_parse_waitv(struct futexv *futexv,
+ (waitv.flags & FUTEX_SIZE_MASK) != FUTEX_32)
+ return -EINVAL;
+
++ shared = (waitv.flags & FUTEX_SHARED_FLAG) ? true : false;
++
+ bucket = futex_get_bucket(waitv.uaddr,
+- &futexv->objects[i].key);
++ &futexv->objects[i].key, shared);
+ if (IS_ERR(bucket))
+ return PTR_ERR(bucket);
+
+@@ -505,6 +645,7 @@ static int futex_parse_waitv(struct futexv *futexv,
+ futexv->objects[i].flags = waitv.flags;
+ futexv->objects[i].index = i;
+ INIT_LIST_HEAD(&futexv->objects[i].list);
++ futexv->objects[i].uaddr = (uintptr_t) waitv.uaddr;
+ }
+
+ return 0;
+@@ -573,6 +714,7 @@ static struct futexv *futex_get_parent(uintptr_t waiter, u8 index)
+ SYSCALL_DEFINE3(futex_wake, void __user *, uaddr, unsigned int, nr_wake,
+ unsigned int, flags)
+ {
++ bool shared = (flags & FUTEX_SHARED_FLAG) ? true : false;
+ unsigned int size = flags & FUTEX_SIZE_MASK;
+ struct futex_waiter waiter, *aux, *tmp;
+ struct futex_bucket *bucket;
+@@ -586,7 +728,7 @@ SYSCALL_DEFINE3(futex_wake, void __user *, uaddr, unsigned int, nr_wake,
+ if (size != FUTEX_32)
+ return -EINVAL;
+
+- bucket = futex_get_bucket(uaddr, &waiter.key);
++ bucket = futex_get_bucket(uaddr, &waiter.key, shared);
+ if (IS_ERR(bucket))
+ return PTR_ERR(bucket);
+
+@@ -599,7 +741,8 @@ SYSCALL_DEFINE3(futex_wake, void __user *, uaddr, unsigned int, nr_wake,
+ break;
+
+ if (waiter.key.address == aux->key.address &&
+- waiter.key.mm == aux->key.mm) {
++ waiter.key.mm == aux->key.mm &&
++ waiter.key.offset == aux->key.offset) {
+ struct futexv *parent =
+ futex_get_parent((uintptr_t) aux, aux->index);
+
--
-2.28.0
+2.29.2
-From d8120d2ee1729a6933a606a6720f3e3116e4f699 Mon Sep 17 00:00:00 2001
+
+From ce3ae4bd9f98763fda07f315c1f239c4aaef4b5e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9=20Almeida?= <andrealmeid@collabora.com>
Date: Thu, 9 Jul 2020 11:34:40 -0300
-Subject: [PATCH 03/13] selftests: futex: Add futex2 wake/wait test
+Subject: [PATCH 4/9] selftests: futex: Add futex2 wake/wait test
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
@@ -1315,38 +1774,32 @@ temporary workaround that implements the required types and calls the
appropriated syscalls, since futex2 doesn't supports 32 bit sized time.
Signed-off-by: André Almeida <andrealmeid@collabora.com>
+Signed-off-by: Jan200101 <sentrycraft123@gmail.com>
---
- tools/include/uapi/asm-generic/unistd.h | 7 +-
+ tools/include/uapi/asm-generic/unistd.h | 1 -
.../selftests/futex/functional/.gitignore | 1 +
.../selftests/futex/functional/Makefile | 4 +-
- .../selftests/futex/functional/futex2_wait.c | 111 ++++++++++++++++++
+ .../selftests/futex/functional/futex2_wait.c | 148 ++++++++++++++++++
.../testing/selftests/futex/functional/run.sh | 3 +
- .../selftests/futex/include/futex2test.h | 77 ++++++++++++
- 6 files changed, 201 insertions(+), 2 deletions(-)
+ .../selftests/futex/include/futex2test.h | 77 +++++++++
+ 6 files changed, 232 insertions(+), 2 deletions(-)
create mode 100644 tools/testing/selftests/futex/functional/futex2_wait.c
create mode 100644 tools/testing/selftests/futex/include/futex2test.h
diff --git a/tools/include/uapi/asm-generic/unistd.h b/tools/include/uapi/asm-generic/unistd.h
-index 995b36c2ea7d..dd457de21bad 100644
+index 7de33be59..81a90b697 100644
--- a/tools/include/uapi/asm-generic/unistd.h
+++ b/tools/include/uapi/asm-generic/unistd.h
-@@ -860,8 +860,13 @@ __SYSCALL(__NR_pidfd_getfd, sys_pidfd_getfd)
- #define __NR_faccessat2 439
- __SYSCALL(__NR_faccessat2, sys_faccessat2)
-
-+#define __NR_futex_wait 440
-+__SYSCALL(__NR_futex_wait, sys_futex_wait)
-+#define __NR_futex_wake 441
-+__SYSCALL(__NR_futex_wake, sys_futex_wake)
-+
+@@ -872,7 +872,6 @@ __SYSCALL(__NR_futex_waitv, sys_futex_waitv)
#undef __NR_syscalls
--#define __NR_syscalls 440
-+#define __NR_syscalls 442
+ #define __NR_syscalls 444
+-
/*
* 32 bit systems traditionally used different
+ * syscalls for off_t and loff_t arguments, while
diff --git a/tools/testing/selftests/futex/functional/.gitignore b/tools/testing/selftests/futex/functional/.gitignore
-index 0efcd494daab..d61f1df94360 100644
+index 0efcd494d..d61f1df94 100644
--- a/tools/testing/selftests/futex/functional/.gitignore
+++ b/tools/testing/selftests/futex/functional/.gitignore
@@ -6,3 +6,4 @@ futex_wait_private_mapped_file
@@ -1355,7 +1808,7 @@ index 0efcd494daab..d61f1df94360 100644
futex_wait_wouldblock
+futex2_wait
diff --git a/tools/testing/selftests/futex/functional/Makefile b/tools/testing/selftests/futex/functional/Makefile
-index 23207829ec75..7142a94a7ac3 100644
+index 23207829e..7142a94a7 100644
--- a/tools/testing/selftests/futex/functional/Makefile
+++ b/tools/testing/selftests/futex/functional/Makefile
@@ -5,6 +5,7 @@ LDLIBS := -lpthread -lrt
@@ -1378,10 +1831,10 @@ index 23207829ec75..7142a94a7ac3 100644
diff --git a/tools/testing/selftests/futex/functional/futex2_wait.c b/tools/testing/selftests/futex/functional/futex2_wait.c
new file mode 100644
-index 000000000000..752ed26803b3
+index 000000000..0646a24b7
--- /dev/null
+++ b/tools/testing/selftests/futex/functional/futex2_wait.c
-@@ -0,0 +1,111 @@
+@@ -0,0 +1,148 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/******************************************************************************
+ *
@@ -1406,13 +1859,14 @@ index 000000000000..752ed26803b3
+#include <string.h>
+#include <time.h>
+#include <pthread.h>
++#include <sys/shm.h>
+#include "futex2test.h"
+#include "logging.h"
+
-+#define TEST_NAME "futex-wait-wouldblock"
++#define TEST_NAME "futex2-wait"
+#define timeout_ns 30000000
+#define WAKE_WAIT_US 10000
-+futex_t f1 = FUTEX_INITIALIZER;
++futex_t *f1;
+
+void usage(char *prog)
+{
@@ -1426,6 +1880,9 @@ index 000000000000..752ed26803b3
+void *waiterfn(void *arg)
+{
+ struct timespec64 to64;
++ unsigned int flags = 0;
++ if (arg)
++ flags = *((unsigned int *) arg);
+
+ /* setting absolute timeout for futex2 */
+ if (gettime64(CLOCK_MONOTONIC, &to64))
@@ -1438,7 +1895,7 @@ index 000000000000..752ed26803b3
+ to64.tv_nsec -= 1000000000;
+ }
+
-+ if (futex2_wait(&f1, f1, FUTEX_PRIVATE_FLAG | FUTEX_32, &to64))
++ if (futex2_wait(f1, *f1, FUTEX_32 | flags, &to64))
+ printf("waiter failed errno %d\n", errno);
+
+ return NULL;
@@ -1447,8 +1904,11 @@ index 000000000000..752ed26803b3
+int main(int argc, char *argv[])
+{
+ pthread_t waiter;
++ unsigned int flags = FUTEX_SHARED_FLAG;
+ int res, ret = RET_PASS;
+ int c;
++ futex_t f_private = 0;
++ f1 = &f_private;
+
+ while ((c = getopt(argc, argv, "cht:v:")) != -1) {
+ switch (c) {
@@ -1468,33 +1928,63 @@ index 000000000000..752ed26803b3
+ }
+
+ ksft_print_header();
-+ ksft_set_plan(1);
-+ ksft_print_msg("%s: Test FUTEX_WAIT\n",
++ ksft_set_plan(2);
++ ksft_print_msg("%s: Test FUTEX2_WAIT\n",
+ basename(argv[0]));
+
-+ info("Calling futex_wait on f1: %u @ %p with val=%u\n", f1, &f1, f1);
++ info("Calling private futex2_wait on f1: %u @ %p with val=%u\n", *f1, f1, *f1);
+
+ if (pthread_create(&waiter, NULL, waiterfn, NULL))
+ error("pthread_create failed\n", errno);
+
+ usleep(WAKE_WAIT_US);
+
-+ info("Calling futex2_wake on f1: %u @ %p with val=%u\n", f1, &f1, f1);
-+ res = futex2_wake(&f1, 1, FUTEX_PRIVATE_FLAG | FUTEX_32);
++ info("Calling private futex2_wake on f1: %u @ %p with val=%u\n", *f1, f1, *f1);
++ res = futex2_wake(f1, 1, FUTEX_32);
++ if (res != 1) {
++ ksft_test_result_fail("futex2_wake private returned: %d %s\n",
++ res ? errno : res,
++ res ? strerror(errno) : "");
++ ret = RET_FAIL;
++ } else {
++ ksft_test_result_pass("futex2_wake private succeeds\n");
++ }
++
++ int shm_id = shmget(IPC_PRIVATE, 4096, IPC_CREAT | 0666);
++ if (shm_id < 0) {
++ perror("shmget");
++ exit(1);
++ }
++
++ unsigned int *shared_data = shmat(shm_id, NULL, 0);
++ *shared_data = 0;
++ f1 = shared_data;
++
++ info("Calling shared futex2_wait on f1: %u @ %p with val=%u\n", *f1, f1, *f1);
++
++ if (pthread_create(&waiter, NULL, waiterfn, &flags))
++ error("pthread_create failed\n", errno);
++
++ usleep(WAKE_WAIT_US);
++
++ info("Calling shared futex2_wake on f1: %u @ %p with val=%u\n", *f1, f1, *f1);
++ res = futex2_wake(f1, 1, FUTEX_32 | FUTEX_SHARED_FLAG);
+ if (res != 1) {
-+ ksft_test_result_fail("futex2_wake returned: %d %s\n",
++ ksft_test_result_fail("futex2_wake shared returned: %d %s\n",
+ res ? errno : res,
+ res ? strerror(errno) : "");
+ ret = RET_FAIL;
+ } else {
-+ ksft_test_result_pass("futex2_wake wouldblock succeeds\n");
++ ksft_test_result_pass("futex2_wake shared succeeds\n");
+ }
+
++ shmdt(shared_data);
++
+ ksft_print_cnts();
+ return ret;
+}
diff --git a/tools/testing/selftests/futex/functional/run.sh b/tools/testing/selftests/futex/functional/run.sh
-index 1acb6ace1680..3730159c865a 100755
+index 1acb6ace1..3730159c8 100755
--- a/tools/testing/selftests/futex/functional/run.sh
+++ b/tools/testing/selftests/futex/functional/run.sh
@@ -73,3 +73,6 @@ echo
@@ -1506,7 +1996,7 @@ index 1acb6ace1680..3730159c865a 100755
+./futex2_wait $COLOR
diff --git a/tools/testing/selftests/futex/include/futex2test.h b/tools/testing/selftests/futex/include/futex2test.h
new file mode 100644
-index 000000000000..807b8b57fe61
+index 000000000..807b8b57f
--- /dev/null
+++ b/tools/testing/selftests/futex/include/futex2test.h
@@ -0,0 +1,77 @@
@@ -1588,12 +2078,13 @@ index 000000000000..807b8b57fe61
+ return syscall(__NR_futex_wake, uaddr, nr, flags);
+}
--
-2.28.0
+2.29.2
+
-From d4a7ca72f276b2e337eaedcbbe58a2782e0e7d3b Mon Sep 17 00:00:00 2001
+From 1e0349f5a81a43cdb50d9a97812194df6d937b69 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9=20Almeida?= <andrealmeid@collabora.com>
Date: Thu, 9 Jul 2020 11:36:14 -0300
-Subject: [PATCH 04/13] selftests: futex: Add futex2 timeout test
+Subject: [PATCH 5/9] selftests: futex: Add futex2 timeout test
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
@@ -1602,12 +2093,13 @@ Adapt existing futex wait timeout file to test the same mechanism for
futex2.
Signed-off-by: André Almeida <andrealmeid@collabora.com>
+Signed-off-by: Jan200101 <sentrycraft123@gmail.com>
---
- .../futex/functional/futex_wait_timeout.c | 38 ++++++++++++++-----
- 1 file changed, 29 insertions(+), 9 deletions(-)
+ .../futex/functional/futex_wait_timeout.c | 58 ++++++++++++++++---
+ 1 file changed, 49 insertions(+), 9 deletions(-)
diff --git a/tools/testing/selftests/futex/functional/futex_wait_timeout.c b/tools/testing/selftests/futex/functional/futex_wait_timeout.c
-index ee55e6d389a3..d2e7ae18985b 100644
+index ee55e6d38..245670e44 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 @@
@@ -1637,12 +2129,12 @@ index ee55e6d389a3..d2e7ae18985b 100644
int res, ret = RET_PASS;
int c;
-@@ -65,22 +67,40 @@ int main(int argc, char *argv[])
+@@ -65,22 +67,60 @@ int main(int argc, char *argv[])
}
ksft_print_header();
- ksft_set_plan(1);
-+ ksft_set_plan(2);
++ ksft_set_plan(3);
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);
@@ -1661,7 +2153,7 @@ index ee55e6d389a3..d2e7ae18985b 100644
+ ksft_test_result_pass("futex_wait timeout succeeds\n");
+ }
+
-+ /* setting absolute timeout for futex2 */
++ /* setting absolute monotonic timeout for futex2 */
+ if (gettime64(CLOCK_MONOTONIC, &to64))
+ error("gettime64 failed\n", errno);
+
@@ -1673,12 +2165,32 @@ index ee55e6d389a3..d2e7ae18985b 100644
+ }
+
+ info("Calling futex2_wait on f1: %u @ %p\n", f1, &f1);
-+ res = futex2_wait(&f1, f1, FUTEX_PRIVATE_FLAG | FUTEX_32, &to64);
++ res = futex2_wait(&f1, f1, FUTEX_32, &to64);
+ if (!res || errno != ETIMEDOUT) {
-+ ksft_test_result_fail("futex2_wait returned %d\n", ret < 0 ? errno : ret);
++ ksft_test_result_fail("futex2_wait monotonic returned %d\n", ret < 0 ? errno : ret);
++ ret = RET_FAIL;
++ } else {
++ ksft_test_result_pass("futex2_wait monotonic timeout succeeds\n");
++ }
++
++ /* setting absolute realtime timeout for futex2 */
++ if (gettime64(CLOCK_REALTIME, &to64))
++ error("gettime64 failed\n", errno);
++
++ to64.tv_nsec += timeout_ns;
++
++ if (to64.tv_nsec >= 1000000000) {
++ to64.tv_sec++;
++ to64.tv_nsec -= 1000000000;
++ }
++
++ info("Calling futex2_wait on f1: %u @ %p\n", f1, &f1);
++ res = futex2_wait(&f1, f1, FUTEX_32 | FUTEX_CLOCK_REALTIME, &to64);
++ if (!res || errno != ETIMEDOUT) {
++ ksft_test_result_fail("futex2_wait realtime returned %d\n", ret < 0 ? errno : ret);
ret = RET_FAIL;
+ } else {
-+ ksft_test_result_pass("futex2_wait timeout succeeds\n");
++ ksft_test_result_pass("futex2_wait realtime timeout succeeds\n");
}
- print_result(TEST_NAME, ret);
@@ -1686,12 +2198,13 @@ index ee55e6d389a3..d2e7ae18985b 100644
return ret;
}
--
-2.28.0
+2.29.2
+
-From 6d2252d43d36a5eb2b9170351128007e27f47737 Mon Sep 17 00:00:00 2001
+From 298120f6e3a758cd03e26a104f5ce60a88501b7f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9=20Almeida?= <andrealmeid@collabora.com>
Date: Thu, 9 Jul 2020 11:37:42 -0300
-Subject: [PATCH 05/13] selftests: futex: Add futex2 wouldblock test
+Subject: [PATCH 6/9] selftests: futex: Add futex2 wouldblock test
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
@@ -1700,12 +2213,13 @@ Adapt existing futex wait wouldblock file to test the same mechanism for
futex2.
Signed-off-by: André Almeida <andrealmeid@collabora.com>
+Signed-off-by: Jan200101 <sentrycraft123@gmail.com>
---
.../futex/functional/futex_wait_wouldblock.c | 33 ++++++++++++++++---
1 file changed, 29 insertions(+), 4 deletions(-)
diff --git a/tools/testing/selftests/futex/functional/futex_wait_wouldblock.c b/tools/testing/selftests/futex/functional/futex_wait_wouldblock.c
-index 0ae390ff8164..8187f0754cd2 100644
+index 0ae390ff8..1f72e5928 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 @@
@@ -1766,7 +2280,7 @@ index 0ae390ff8164..8187f0754cd2 100644
+ }
+
+ info("Calling futex2_wait on f1: %u @ %p with val=%u\n", f1, &f1, f1+1);
-+ res = futex2_wait(&f1, f1+1, FUTEX_PRIVATE_FLAG | FUTEX_32, &to64);
++ res = futex2_wait(&f1, f1+1, FUTEX_32, &to64);
+ if (!res || errno != EWOULDBLOCK) {
+ ksft_test_result_fail("futex2_wait returned: %d %s\n",
+ res ? errno : res, res ? strerror(errno) : "");
@@ -1779,4919 +2293,693 @@ index 0ae390ff8164..8187f0754cd2 100644
return ret;
}
--
-2.28.0
+2.29.2
-From 6b35a09be663f5a844e089f1ddd370137832e7a7 Mon Sep 17 00:00:00 2001
+
+From 05c697a239aad5e8608c6acf0da9239cac5f7a2e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9=20Almeida?= <andrealmeid@collabora.com>
-Date: Wed, 14 Oct 2020 16:10:09 -0300
-Subject: [PATCH 06/13] DONOTMERGE: futex: Add a clone of futex implementation
+Date: Tue, 8 Dec 2020 18:47:31 -0300
+Subject: [PATCH 7/9] selftests: futex: Add futex2 waitv test
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
-For comparative performance tests between the original futex and the new
-futex2 interface, create a clone of the current futex. In that way, we
-can have a fair comparison, since the futex2 table will be empty with no
-contention for the bucket locks. Since futex is widely used in the host
-system, the performance tests could get misleading results by the tests
-competing with the system for resources.
-
Signed-off-by: André Almeida <andrealmeid@collabora.com>
+Signed-off-by: Jan200101 <sentrycraft123@gmail.com>
---
- arch/x86/entry/syscalls/syscall_32.tbl | 1 +
- arch/x86/entry/syscalls/syscall_64.tbl | 1 +
- include/linux/syscalls.h | 3 +
- include/uapi/asm-generic/unistd.h | 5 +-
- kernel/Makefile | 1 +
- kernel/futex1.c | 3384 +++++++++++++++++
- kernel/sys_ni.c | 2 +
- tools/arch/x86/include/asm/unistd_64.h | 12 +
- tools/include/uapi/asm-generic/unistd.h | 6 +-
- .../arch/x86/entry/syscalls/syscall_64.tbl | 3 +
- tools/perf/bench/futex.h | 23 +-
- 11 files changed, 3438 insertions(+), 3 deletions(-)
- create mode 100644 kernel/futex1.c
+ .../selftests/futex/functional/.gitignore | 1 +
+ .../selftests/futex/functional/Makefile | 3 +-
+ .../selftests/futex/functional/futex2_waitv.c | 156 ++++++++++++++++++
+ .../testing/selftests/futex/functional/run.sh | 3 +
+ .../selftests/futex/include/futex2test.h | 25 ++-
+ 5 files changed, 183 insertions(+), 5 deletions(-)
+ create mode 100644 tools/testing/selftests/futex/functional/futex2_waitv.c
-diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl
-index c844c0cbf0e5..820fa53ccf75 100644
---- a/arch/x86/entry/syscalls/syscall_32.tbl
-+++ b/arch/x86/entry/syscalls/syscall_32.tbl
-@@ -447,3 +447,4 @@
- 440 i386 futex_wait sys_futex_wait
- 441 i386 futex_wake sys_futex_wake
- 442 i386 futex_waitv sys_futex_waitv
-+443 i386 futex1 sys_futex1
-diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl
-index 0901c26c6786..99795136cb98 100644
---- a/arch/x86/entry/syscalls/syscall_64.tbl
-+++ b/arch/x86/entry/syscalls/syscall_64.tbl
-@@ -364,6 +364,7 @@
- 440 common futex_wait sys_futex_wait
- 441 common futex_wake sys_futex_wake
- 442 common futex_waitv sys_futex_waitv
-+443 common futex1 sys_futex1
-
- #
- # x32-specific system call numbers start at 512 to avoid cache impact
-diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
-index 38c3a87dbfc2..0351f6ad09a9 100644
---- a/include/linux/syscalls.h
-+++ b/include/linux/syscalls.h
-@@ -596,6 +596,9 @@ asmlinkage long sys_futex_wait(void __user *uaddr, unsigned long val,
- asmlinkage long sys_futex_wake(void __user *uaddr, unsigned long nr_wake,
- unsigned long flags);
-
-+asmlinkage long sys_futex1(void __user *uaddr, unsigned long nr_wake,
-+ unsigned long flags);
-+
- /* kernel/hrtimer.c */
- asmlinkage long sys_nanosleep(struct __kernel_timespec __user *rqtp,
- struct __kernel_timespec __user *rmtp);
-diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h
-index d7ebbed0a18c..e3ba6cb1f76d 100644
---- a/include/uapi/asm-generic/unistd.h
-+++ b/include/uapi/asm-generic/unistd.h
-@@ -869,8 +869,11 @@ __SYSCALL(__NR_futex_wake, sys_futex_wake)
- #define __NR_futex_waitv 442
- __SYSCALL(__NR_futex_waitv, sys_futex_waitv)
+diff --git a/tools/testing/selftests/futex/functional/.gitignore b/tools/testing/selftests/futex/functional/.gitignore
+index d61f1df94..d0b8f637b 100644
+--- a/tools/testing/selftests/futex/functional/.gitignore
++++ b/tools/testing/selftests/futex/functional/.gitignore
+@@ -7,3 +7,4 @@ futex_wait_timeout
+ futex_wait_uninitialized_heap
+ futex_wait_wouldblock
+ futex2_wait
++futex2_waitv
+diff --git a/tools/testing/selftests/futex/functional/Makefile b/tools/testing/selftests/futex/functional/Makefile
+index 7142a94a7..b857b9450 100644
+--- a/tools/testing/selftests/futex/functional/Makefile
++++ b/tools/testing/selftests/futex/functional/Makefile
+@@ -16,7 +16,8 @@ TEST_GEN_FILES := \
+ futex_requeue_pi_mismatched_ops \
+ futex_wait_uninitialized_heap \
+ futex_wait_private_mapped_file \
+- futex2_wait
++ futex2_wait \
++ futex2_waitv
-+#define __NR_futex1 443
-+__SYSCALL(__NR_futex1, sys_futex1)
-+
- #undef __NR_syscalls
--#define __NR_syscalls 443
-+#define __NR_syscalls 444
+ TEST_PROGS := run.sh
- /*
- * 32 bit systems traditionally used different
-diff --git a/kernel/Makefile b/kernel/Makefile
-index 51ea9bc647bf..0fe55a8cb9e2 100644
---- a/kernel/Makefile
-+++ b/kernel/Makefile
-@@ -57,6 +57,7 @@ obj-$(CONFIG_PROFILING) += profile.o
- obj-$(CONFIG_STACKTRACE) += stacktrace.o
- obj-y += time/
- obj-$(CONFIG_FUTEX) += futex.o
-+obj-$(CONFIG_FUTEX2) += futex1.o
- obj-$(CONFIG_FUTEX2) += futex2.o
- obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
- obj-$(CONFIG_SMP) += smp.o
-diff --git a/kernel/futex1.c b/kernel/futex1.c
+diff --git a/tools/testing/selftests/futex/functional/futex2_waitv.c b/tools/testing/selftests/futex/functional/futex2_waitv.c
new file mode 100644
-index 000000000000..4f7bf312fefd
+index 000000000..d4b116651
--- /dev/null
-+++ b/kernel/futex1.c
-@@ -0,0 +1,3384 @@
++++ b/tools/testing/selftests/futex/functional/futex2_waitv.c
+@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
-+/*
-+ * Fast Userspace Mutexes (which I call "Futexes!").
-+ * (C) Rusty Russell, IBM 2002
-+ *
-+ * Generalized futexes, futex requeueing, misc fixes by Ingo Molnar
-+ * (C) Copyright 2003 Red Hat Inc, All Rights Reserved
-+ *
-+ * Removed page pinning, fix privately mapped COW pages and other cleanups
-+ * (C) Copyright 2003, 2004 Jamie Lokier
-+ *
-+ * Robust futex support started by Ingo Molnar
-+ * (C) Copyright 2006 Red Hat Inc, All Rights Reserved
-+ * Thanks to Thomas Gleixner for suggestions, analysis and fixes.
-+ *
-+ * PI-futex support started by Ingo Molnar and Thomas Gleixner
-+ * Copyright (C) 2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
-+ * Copyright (C) 2006 Timesys Corp., Thomas Gleixner <tglx@timesys.com>
-+ *
-+ * PRIVATE futexes by Eric Dumazet
-+ * Copyright (C) 2007 Eric Dumazet <dada1@cosmosbay.com>
-+ *
-+ * Requeue-PI support by Darren Hart <dvhltc@us.ibm.com>
-+ * Copyright (C) IBM Corporation, 2009
-+ * Thanks to Thomas Gleixner for conceptual design and careful reviews.
-+ *
-+ * Thanks to Ben LaHaise for yelling "hashed waitqueues" loudly
-+ * enough at me, Linus for the original (flawed) idea, Matthew
-+ * Kirkwood for proof-of-concept implementation.
-+ *
-+ * "The futexes are also cursed."
-+ * "But they come in a choice of three flavours!"
-+ */
-+#include <linux/compat.h>
-+#include <linux/jhash.h>
-+#include <linux/pagemap.h>
-+#include <linux/syscalls.h>
-+#include <linux/hugetlb.h>
-+#include <linux/freezer.h>
-+#include <linux/memblock.h>
-+#include <linux/fault-inject.h>
-+
-+#include <asm/futex.h>
-+
-+#include "locking/rtmutex_common.h"
-+
-+/*
-+ * READ this before attempting to hack on futexes!
-+ *
-+ * Basic futex operation and ordering guarantees
-+ * =============================================
-+ *
-+ * The waiter reads the futex value in user space and calls
-+ * futex_wait(). This function computes the hash bucket and acquires
-+ * the hash bucket lock. After that it reads the futex user space value
-+ * again and verifies that the data has not changed. If it has not changed
-+ * it enqueues itself into the hash bucket, releases the hash bucket lock
-+ * and schedules.
-+ *
-+ * The waker side modifies the user space value of the futex and calls
-+ * futex_wake(). This function computes the hash bucket and acquires the
-+ * hash bucket lock. Then it looks for waiters on that futex in the hash
-+ * bucket and wakes them.
-+ *
-+ * In futex wake up scenarios where no tasks are blocked on a futex, taking
-+ * the hb spinlock can be avoided and simply return. In order for this
-+ * optimization to work, ordering guarantees must exist so that the waiter
-+ * being added to the list is acknowledged when the list is concurrently being
-+ * checked by the waker, avoiding scenarios like the following:
-+ *
-+ * CPU 0 CPU 1
-+ * val = *futex;
-+ * sys_futex(WAIT, futex, val);
-+ * futex_wait(futex, val);
-+ * uval = *futex;
-+ * *futex = newval;
-+ * sys_futex(WAKE, futex);
-+ * futex_wake(futex);
-+ * if (queue_empty())
-+ * return;
-+ * if (uval == val)
-+ * lock(hash_bucket(futex));
-+ * queue();
-+ * unlock(hash_bucket(futex));
-+ * schedule();
-+ *
-+ * This would cause the waiter on CPU 0 to wait forever because it
-+ * missed the transition of the user space value from val to newval
-+ * and the waker did not find the waiter in the hash bucket queue.
-+ *
-+ * The correct serialization ensures that a waiter either observes
-+ * the changed user space value before blocking or is woken by a
-+ * concurrent waker:
-+ *
-+ * CPU 0 CPU 1
-+ * val = *futex;
-+ * sys_futex(WAIT, futex, val);
-+ * futex_wait(futex, val);
-+ *
-+ * waiters++; (a)
-+ * smp_mb(); (A) <-- paired with -.
-+ * |
-+ * lock(hash_bucket(futex)); |
-+ * |
-+ * uval = *futex; |
-+ * | *futex = newval;
-+ * | sys_futex(WAKE, futex);
-+ * | futex_wake(futex);
-+ * |
-+ * `--------> smp_mb(); (B)
-+ * if (uval == val)
-+ * queue();
-+ * unlock(hash_bucket(futex));
-+ * schedule(); if (waiters)
-+ * lock(hash_bucket(futex));
-+ * else wake_waiters(futex);
-+ * waiters--; (b) unlock(hash_bucket(futex));
-+ *
-+ * Where (A) orders the waiters increment and the futex value read through
-+ * atomic operations (see hb_waiters_inc) and where (B) orders the write
-+ * to futex and the waiters read (see hb_waiters_pending()).
-+ *
-+ * This yields the following case (where X:=waiters, Y:=futex):
-+ *
-+ * X = Y = 0
-+ *
-+ * w[X]=1 w[Y]=1
-+ * MB MB
-+ * r[Y]=y r[X]=x
-+ *
-+ * Which guarantees that x==0 && y==0 is impossible; which translates back into
-+ * the guarantee that we cannot both miss the futex variable change and the
-+ * enqueue.
-+ *
-+ * Note that a new waiter is accounted for in (a) even when it is possible that
-+ * the wait call can return error, in which case we backtrack from it in (b).
-+ * Refer to the comment in queue_lock().
-+ *
-+ * Similarly, in order to account for waiters being requeued on another
-+ * address we always increment the waiters for the destination bucket before
-+ * acquiring the lock. It then decrements them again after releasing it -
-+ * the code that actually moves the futex(es) between hash buckets (requeue_futex)
-+ * will do the additional required waiter count housekeeping. This is done for
-+ * double_lock_hb() and double_unlock_hb(), respectively.
-+ */
-+
-+#ifdef CONFIG_HAVE_FUTEX_CMPXCHG
-+#define futex_cmpxchg_enabled 1
-+#else
-+static int __read_mostly futex_cmpxchg_enabled;
-+#endif
-+
-+/*
-+ * Futex flags used to encode options to functions and preserve them across
-+ * restarts.
-+ */
-+#ifdef CONFIG_MMU
-+# define FLAGS_SHARED 0x01
-+#else
-+/*
-+ * NOMMU does not have per process address space. Let the compiler optimize
-+ * code away.
-+ */
-+# define FLAGS_SHARED 0x00
-+#endif
-+#define FLAGS_CLOCKRT 0x02
-+#define FLAGS_HAS_TIMEOUT 0x04
-+
-+/*
-+ * Priority Inheritance state:
-+ */
-+struct futex_pi_state {
-+ /*
-+ * list of 'owned' pi_state instances - these have to be
-+ * cleaned up in do_exit() if the task exits prematurely:
-+ */
-+ struct list_head list;
-+
-+ /*
-+ * The PI object:
-+ */
-+ struct rt_mutex pi_mutex;
-+
-+ struct task_struct *owner;
-+ refcount_t refcount;
-+
-+ union futex_key key;
-+} __randomize_layout;
-+
-+/**
-+ * struct futex_q - The hashed futex queue entry, one per waiting task
-+ * @list: priority-sorted list of tasks waiting on this futex
-+ * @task: the task waiting on the futex
-+ * @lock_ptr: the hash bucket lock
-+ * @key: the key the futex is hashed on
-+ * @pi_state: optional priority inheritance 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
-+ *
-+ * 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).
++/******************************************************************************
+ *
-+ * A futex_q has a woken state, just like tasks have TASK_RUNNING.
-+ * It is considered woken when plist_node_empty(&q->list) || q->lock_ptr == 0.
-+ * The order of wakeup is always to make the first condition true, then
-+ * the second.
++ * Copyright Collabora Ltd., 2020
+ *
-+ * PI futexes are typically woken before they are removed from the hash list via
-+ * the rt_mutex code. See unqueue_me_pi().
-+ */
-+struct futex_q {
-+ struct plist_node list;
-+
-+ struct task_struct *task;
-+ spinlock_t *lock_ptr;
-+ union futex_key key;
-+ struct futex_pi_state *pi_state;
-+ struct rt_mutex_waiter *rt_waiter;
-+ union futex_key *requeue_pi_key;
-+ u32 bitset;
-+} __randomize_layout;
-+
-+static const struct futex_q futex_q_init = {
-+ /* list gets initialized in queue_me()*/
-+ .key = FUTEX_KEY_INIT,
-+ .bitset = FUTEX_BITSET_MATCH_ANY
-+};
-+
-+/*
-+ * Hash buckets are shared by all the futex_keys that hash to the same
-+ * location. Each key may have multiple futex_q structures, one for each task
-+ * waiting on a futex.
-+ */
-+struct futex_hash_bucket {
-+ atomic_t waiters;
-+ spinlock_t lock;
-+ struct plist_head chain;
-+} ____cacheline_aligned_in_smp;
-+
-+/*
-+ * The base of the bucket array and its size are always used together
-+ * (after initialization only in hash_futex()), so ensure that they
-+ * reside in the same cacheline.
-+ */
-+static struct {
-+ struct futex_hash_bucket *queues;
-+ unsigned long hashsize;
-+} __futex_data __read_mostly __aligned(2*sizeof(long));
-+#define futex_queues (__futex_data.queues)
-+#define futex_hashsize (__futex_data.hashsize)
-+
-+
-+/*
-+ * Fault injections for futexes.
-+ */
-+#ifdef CONFIG_FAIL_FUTEX
-+
-+static struct {
-+ struct fault_attr attr;
-+
-+ bool ignore_private;
-+} fail_futex = {
-+ .attr = FAULT_ATTR_INITIALIZER,
-+ .ignore_private = false,
-+};
-+
-+static int __init setup_fail_futex(char *str)
-+{
-+ return setup_fault_attr(&fail_futex.attr, str);
-+}
-+__setup("fail_futex=", setup_fail_futex);
-+
-+static bool should_fail_futex(bool fshared)
-+{
-+ if (fail_futex.ignore_private && !fshared)
-+ return false;
-+
-+ return should_fail(&fail_futex.attr, 1);
-+}
-+
-+#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
-+
-+static int __init fail_futex_debugfs(void)
-+{
-+ umode_t mode = S_IFREG | S_IRUSR | S_IWUSR;
-+ struct dentry *dir;
-+
-+ dir = fault_create_debugfs_attr("fail_futex", NULL,
-+ &fail_futex.attr);
-+ if (IS_ERR(dir))
-+ return PTR_ERR(dir);
-+
-+ debugfs_create_bool("ignore-private", mode, dir,
-+ &fail_futex.ignore_private);
-+ return 0;
-+}
-+
-+late_initcall(fail_futex_debugfs);
-+
-+#endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */
-+
-+#else
-+static inline bool should_fail_futex(bool fshared)
-+{
-+ return false;
-+}
-+#endif /* CONFIG_FAIL_FUTEX */
-+
-+/*
-+ * Reflects a new waiter being added to the waitqueue.
-+ */
-+static inline void hb_waiters_inc(struct futex_hash_bucket *hb)
-+{
-+#ifdef CONFIG_SMP
-+ atomic_inc(&hb->waiters);
-+ /*
-+ * Full barrier (A), see the ordering comment above.
-+ */
-+ smp_mb__after_atomic();
-+#endif
-+}
-+
-+/*
-+ * Reflects a waiter being removed from the waitqueue by wakeup
-+ * paths.
-+ */
-+static inline void hb_waiters_dec(struct futex_hash_bucket *hb)
-+{
-+#ifdef CONFIG_SMP
-+ atomic_dec(&hb->waiters);
-+#endif
-+}
-+
-+static inline int hb_waiters_pending(struct futex_hash_bucket *hb)
-+{
-+#ifdef CONFIG_SMP
-+ /*
-+ * Full barrier (B), see the ordering comment above.
-+ */
-+ smp_mb();
-+ return atomic_read(&hb->waiters);
-+#else
-+ return 1;
-+#endif
-+}
-+
-+/**
-+ * hash_futex - Return the hash bucket in the global hash
-+ * @key: Pointer to the futex key for which the hash is calculated
++ * DESCRIPTION
++ * Test waitv/wake mechanism of futex2, using 32bit sized futexes.
+ *
-+ * We hash on the keys returned from get_futex_key (see below) and return the
-+ * corresponding hash bucket in the global hash.
-+ */
-+static struct futex_hash_bucket *hash_futex(union futex_key *key)
-+{
-+ u32 hash = jhash2((u32 *)key, offsetof(typeof(*key), both.offset) / 4,
-+ key->both.offset);
-+
-+ return &futex_queues[hash & (futex_hashsize - 1)];
-+}
-+
-+
-+/**
-+ * match_futex - Check whether two futex keys are equal
-+ * @key1: Pointer to key1
-+ * @key2: Pointer to key2
++ * AUTHOR
++ * André Almeida <andrealmeid@collabora.com>
+ *
-+ * Return 1 if two futex_keys are equal, 0 otherwise.
-+ */
-+static inline int match_futex(union futex_key *key1, union futex_key *key2)
-+{
-+ return (key1 && key2
-+ && key1->both.word == key2->both.word
-+ && key1->both.ptr == key2->both.ptr
-+ && key1->both.offset == key2->both.offset);
-+}
-+
-+enum futex_access {
-+ FUTEX_READ,
-+ FUTEX_WRITE
-+};
-+
-+/**
-+ * futex_setup_timer - set up the sleeping hrtimer.
-+ * @time: ptr to the given timeout value
-+ * @timeout: the hrtimer_sleeper structure to be set up
-+ * @flags: futex flags
-+ * @range_ns: optional range in ns
++ * HISTORY
++ * 2020-Jul-9: Initial version by André <andrealmeid@collabora.com>
+ *
-+ * Return: Initialized hrtimer_sleeper structure or NULL if no timeout
-+ * value given
-+ */
-+static inline struct hrtimer_sleeper *
-+futex_setup_timer(ktime_t *time, struct hrtimer_sleeper *timeout,
-+ int flags, u64 range_ns)
-+{
-+ if (!time)
-+ return NULL;
++ *****************************************************************************/
+
-+ hrtimer_init_sleeper_on_stack(timeout, (flags & FLAGS_CLOCKRT) ?
-+ CLOCK_REALTIME : CLOCK_MONOTONIC,
-+ HRTIMER_MODE_ABS);
-+ /*
-+ * If range_ns is 0, calling hrtimer_set_expires_range_ns() is
-+ * effectively the same as calling hrtimer_set_expires().
-+ */
-+ hrtimer_set_expires_range_ns(&timeout->timer, *time, range_ns);
++#include <errno.h>
++#include <error.h>
++#include <getopt.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <time.h>
++#include <pthread.h>
++#include <sys/shm.h>
++#include "futex2test.h"
++#include "logging.h"
+
-+ return timeout;
-+}
++#define TEST_NAME "futex2-wait"
++#define timeout_ns 1000000000
++#define WAKE_WAIT_US 10000
++#define NR_FUTEXES 30
++struct futex_waitv waitv[NR_FUTEXES];
++u_int32_t futexes[NR_FUTEXES] = {0};
+
-+/*
-+ * Generate a machine wide unique identifier for this inode.
-+ *
-+ * This relies on u64 not wrapping in the life-time of the machine; which with
-+ * 1ns resolution means almost 585 years.
-+ *
-+ * This further relies on the fact that a well formed program will not unmap
-+ * the file while it has a (shared) futex waiting on it. This mapping will have
-+ * a file reference which pins the mount and inode.
-+ *
-+ * If for some reason an inode gets evicted and read back in again, it will get
-+ * a new sequence number and will _NOT_ match, even though it is the exact same
-+ * file.
-+ *
-+ * It is important that match_futex() will never have a false-positive, esp.
-+ * for PI futexes that can mess up the state. The above argues that false-negatives
-+ * are only possible for malformed programs.
-+ */
-+static u64 get_inode_sequence_number(struct inode *inode)
++void usage(char *prog)
+{
-+ static atomic64_t i_seq;
-+ u64 old;
-+
-+ /* Does the inode already have a sequence number? */
-+ old = atomic64_read(&inode->i_sequence);
-+ if (likely(old))
-+ return old;
-+
-+ for (;;) {
-+ u64 new = atomic64_add_return(1, &i_seq);
-+ if (WARN_ON_ONCE(!new))
-+ continue;
-+
-+ old = atomic64_cmpxchg_relaxed(&inode->i_sequence, 0, new);
-+ if (old)
-+ return old;
-+ return new;
-+ }
++ 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);
+}
+
-+/**
-+ * get_futex_key() - Get parameters which are the keys for a futex
-+ * @uaddr: virtual address of the futex
-+ * @fshared: false for a PROCESS_PRIVATE futex, true for PROCESS_SHARED
-+ * @key: address where result is stored.
-+ * @rw: mapping needs to be read/write (values: FUTEX_READ,
-+ * FUTEX_WRITE)
-+ *
-+ * Return: a negative error code or 0
-+ *
-+ * The key words are stored in @key on success.
-+ *
-+ * For shared mappings (when @fshared), the key is:
-+ *
-+ * ( inode->i_sequence, page->index, offset_within_page )
-+ *
-+ * [ also see get_inode_sequence_number() ]
-+ *
-+ * For private mappings (or when !@fshared), the key is:
-+ *
-+ * ( current->mm, address, 0 )
-+ *
-+ * This allows (cross process, where applicable) identification of the futex
-+ * without keeping the page pinned for the duration of the FUTEX_WAIT.
-+ *
-+ * lock_page() might sleep, the caller should not hold a spinlock.
-+ */
-+static int get_futex_key(u32 __user *uaddr, bool fshared, union futex_key *key,
-+ enum futex_access rw)
++void *waiterfn(void *arg)
+{
-+ unsigned long address = (unsigned long)uaddr;
-+ struct mm_struct *mm = current->mm;
-+ struct page *page, *tail;
-+ struct address_space *mapping;
-+ int err, ro = 0;
-+
-+ /*
-+ * The futex address must be "naturally" aligned.
-+ */
-+ key->both.offset = address % PAGE_SIZE;
-+ if (unlikely((address % sizeof(u32)) != 0))
-+ return -EINVAL;
-+ address -= key->both.offset;
-+
-+ if (unlikely(!access_ok(uaddr, sizeof(u32))))
-+ return -EFAULT;
-+
-+ if (unlikely(should_fail_futex(fshared)))
-+ return -EFAULT;
-+
-+ /*
-+ * PROCESS_PRIVATE futexes are fast.
-+ * As the mm cannot disappear under us and the 'key' only needs
-+ * virtual address, we dont even have to find the underlying vma.
-+ * Note : We do have to check 'uaddr' is a valid user address,
-+ * but access_ok() should be faster than find_vma()
-+ */
-+ if (!fshared) {
-+ key->private.mm = mm;
-+ key->private.address = address;
-+ return 0;
-+ }
-+
-+again:
-+ /* Ignore any VERIFY_READ mapping (futex common case) */
-+ if (unlikely(should_fail_futex(true)))
-+ return -EFAULT;
-+
-+ err = get_user_pages_fast(address, 1, FOLL_WRITE, &page);
-+ /*
-+ * If write access is not required (eg. FUTEX_WAIT), try
-+ * and get read-only access.
-+ */
-+ if (err == -EFAULT && rw == FUTEX_READ) {
-+ err = get_user_pages_fast(address, 1, 0, &page);
-+ ro = 1;
-+ }
-+ if (err < 0)
-+ return err;
-+ else
-+ err = 0;
-+
-+ /*
-+ * The treatment of mapping from this point on is critical. The page
-+ * lock protects many things but in this context the page lock
-+ * stabilizes mapping, prevents inode freeing in the shared
-+ * file-backed region case and guards against movement to swap cache.
-+ *
-+ * Strictly speaking the page lock is not needed in all cases being
-+ * considered here and page lock forces unnecessarily serialization
-+ * From this point on, mapping will be re-verified if necessary and
-+ * page lock will be acquired only if it is unavoidable
-+ *
-+ * Mapping checks require the head page for any compound page so the
-+ * head page and mapping is looked up now. For anonymous pages, it
-+ * does not matter if the page splits in the future as the key is
-+ * based on the address. For filesystem-backed pages, the tail is
-+ * required as the index of the page determines the key. For
-+ * base pages, there is no tail page and tail == page.
-+ */
-+ tail = page;
-+ page = compound_head(page);
-+ mapping = READ_ONCE(page->mapping);
-+
-+ /*
-+ * If page->mapping is NULL, then it cannot be a PageAnon
-+ * page; but it might be the ZERO_PAGE or in the gate area or
-+ * in a special mapping (all cases which we are happy to fail);
-+ * or it may have been a good file page when get_user_pages_fast
-+ * found it, but truncated or holepunched or subjected to
-+ * invalidate_complete_page2 before we got the page lock (also
-+ * cases which we are happy to fail). And we hold a reference,
-+ * so refcount care in invalidate_complete_page's remove_mapping
-+ * prevents drop_caches from setting mapping to NULL beneath us.
-+ *
-+ * The case we do have to guard against is when memory pressure made
-+ * shmem_writepage move it from filecache to swapcache beneath us:
-+ * an unlikely race, but we do need to retry for page->mapping.
-+ */
-+ if (unlikely(!mapping)) {
-+ int shmem_swizzled;
-+
-+ /*
-+ * Page lock is required to identify which special case above
-+ * applies. If this is really a shmem page then the page lock
-+ * will prevent unexpected transitions.
-+ */
-+ lock_page(page);
-+ shmem_swizzled = PageSwapCache(page) || page->mapping;
-+ unlock_page(page);
-+ put_page(page);
-+
-+ if (shmem_swizzled)
-+ goto again;
-+
-+ return -EFAULT;
-+ }
-+
-+ /*
-+ * Private mappings are handled in a simple way.
-+ *
-+ * If the futex key is stored on an anonymous page, then the associated
-+ * object is the mm which is implicitly pinned by the calling process.
-+ *
-+ * NOTE: When userspace waits on a MAP_SHARED mapping, even if
-+ * it's a read-only handle, it's expected that futexes attach to
-+ * the object not the particular process.
-+ */
-+ if (PageAnon(page)) {
-+ /*
-+ * A RO anonymous page will never change and thus doesn't make
-+ * sense for futex operations.
-+ */
-+ if (unlikely(should_fail_futex(true)) || ro) {
-+ err = -EFAULT;
-+ goto out;
-+ }
-+
-+ key->both.offset |= FUT_OFF_MMSHARED; /* ref taken on mm */
-+ key->private.mm = mm;
-+ key->private.address = address;
-+
-+ } else {
-+ struct inode *inode;
-+
-+ /*
-+ * The associated futex object in this case is the inode and
-+ * the page->mapping must be traversed. Ordinarily this should
-+ * be stabilised under page lock but it's not strictly
-+ * necessary in this case as we just want to pin the inode, not
-+ * update the radix tree or anything like that.
-+ *
-+ * The RCU read lock is taken as the inode is finally freed
-+ * under RCU. If the mapping still matches expectations then the
-+ * mapping->host can be safely accessed as being a valid inode.
-+ */
-+ rcu_read_lock();
-+
-+ if (READ_ONCE(page->mapping) != mapping) {
-+ rcu_read_unlock();
-+ put_page(page);
-+
-+ goto again;
-+ }
++ struct timespec64 to64;
++ int res;
+
-+ inode = READ_ONCE(mapping->host);
-+ if (!inode) {
-+ rcu_read_unlock();
-+ put_page(page);
++ /* setting absolute timeout for futex2 */
++ if (gettime64(CLOCK_MONOTONIC, &to64))
++ error("gettime64 failed\n", errno);
+
-+ goto again;
-+ }
++ to64.tv_sec++;
+
-+ key->both.offset |= FUT_OFF_INODE; /* inode-based key */
-+ key->shared.i_seq = get_inode_sequence_number(inode);
-+ key->shared.pgoff = basepage_index(tail);
-+ rcu_read_unlock();
++ res = futex2_waitv(waitv, NR_FUTEXES, 0, &to64);
++ if (res < 0) {
++ printf("waiter failed errno %d %s\n",
++ res ? errno : res,
++ res ? strerror(errno) : "");
+ }
+
-+out:
-+ put_page(page);
-+ return err;
-+}
-+
-+/**
-+ * fault_in_user_writeable() - Fault in user address and verify RW access
-+ * @uaddr: pointer to faulting user space address
-+ *
-+ * Slow path to fixup the fault we just took in the atomic write
-+ * access to @uaddr.
-+ *
-+ * We have no generic implementation of a non-destructive write to the
-+ * user address. We know that we faulted in the atomic pagefault
-+ * disabled section so we can as well avoid the #PF overhead by
-+ * calling get_user_pages() right away.
-+ */
-+static int fault_in_user_writeable(u32 __user *uaddr)
-+{
-+ struct mm_struct *mm = current->mm;
-+ int ret;
-+
-+ mmap_read_lock(mm);
-+ ret = fixup_user_fault(mm, (unsigned long)uaddr,
-+ FAULT_FLAG_WRITE, NULL);
-+ mmap_read_unlock(mm);
-+
-+ return ret < 0 ? ret : 0;
-+}
-+
-+/**
-+ * futex_top_waiter() - Return the highest priority waiter on a futex
-+ * @hb: the hash bucket the futex_q's reside in
-+ * @key: the futex key (to distinguish it from other futex futex_q's)
-+ *
-+ * Must be called with the hb lock held.
-+ */
-+static struct futex_q *futex_top_waiter(struct futex_hash_bucket *hb,
-+ union futex_key *key)
-+{
-+ struct futex_q *this;
-+
-+ plist_for_each_entry(this, &hb->chain, list) {
-+ if (match_futex(&this->key, key))
-+ return this;
-+ }
+ return NULL;
+}
+
-+static int cmpxchg_futex_value_locked(u32 *curval, u32 __user *uaddr,
-+ u32 uval, u32 newval)
-+{
-+ int ret;
-+
-+ pagefault_disable();
-+ ret = futex_atomic_cmpxchg_inatomic(curval, uaddr, uval, newval);
-+ pagefault_enable();
-+
-+ return ret;
-+}
-+
-+static int get_futex_value_locked(u32 *dest, u32 __user *from)
-+{
-+ int ret;
-+
-+ pagefault_disable();
-+ ret = __get_user(*dest, from);
-+ pagefault_enable();
-+
-+ return ret ? -EFAULT : 0;
-+}
-+
-+
-+/*
-+ * PI code:
-+ */
-+static int refill_pi_state_cache(void)
-+{
-+ struct futex_pi_state *pi_state;
-+
-+ if (likely(current->pi_state_cache))
-+ return 0;
-+
-+ pi_state = kzalloc(sizeof(*pi_state), GFP_KERNEL);
-+
-+ if (!pi_state)
-+ return -ENOMEM;
-+
-+ INIT_LIST_HEAD(&pi_state->list);
-+ /* pi_mutex gets initialized later */
-+ pi_state->owner = NULL;
-+ refcount_set(&pi_state->refcount, 1);
-+ pi_state->key = FUTEX_KEY_INIT;
-+
-+ current->pi_state_cache = pi_state;
-+
-+ return 0;
-+}
-+
-+static struct futex_pi_state *alloc_pi_state(void)
-+{
-+ struct futex_pi_state *pi_state = current->pi_state_cache;
-+
-+ WARN_ON(!pi_state);
-+ current->pi_state_cache = NULL;
-+
-+ return pi_state;
-+}
-+
-+static void get_pi_state(struct futex_pi_state *pi_state)
-+{
-+ WARN_ON_ONCE(!refcount_inc_not_zero(&pi_state->refcount));
-+}
-+
-+/*
-+ * Drops a reference to the pi_state object and frees or caches it
-+ * when the last reference is gone.
-+ */
-+static void put_pi_state(struct futex_pi_state *pi_state)
-+{
-+ if (!pi_state)
-+ return;
-+
-+ if (!refcount_dec_and_test(&pi_state->refcount))
-+ return;
-+
-+ /*
-+ * If pi_state->owner is NULL, the owner is most probably dying
-+ * and has cleaned up the pi_state already
-+ */
-+ if (pi_state->owner) {
-+ struct task_struct *owner;
-+
-+ raw_spin_lock_irq(&pi_state->pi_mutex.wait_lock);
-+ owner = pi_state->owner;
-+ if (owner) {
-+ raw_spin_lock(&owner->pi_lock);
-+ list_del_init(&pi_state->list);
-+ raw_spin_unlock(&owner->pi_lock);
-+ }
-+ rt_mutex_proxy_unlock(&pi_state->pi_mutex, owner);
-+ raw_spin_unlock_irq(&pi_state->pi_mutex.wait_lock);
-+ }
-+
-+ if (current->pi_state_cache) {
-+ kfree(pi_state);
-+ } else {
-+ /*
-+ * pi_state->list is already empty.
-+ * clear pi_state->owner.
-+ * refcount is at 0 - put it back to 1.
-+ */
-+ pi_state->owner = NULL;
-+ refcount_set(&pi_state->refcount, 1);
-+ current->pi_state_cache = pi_state;
-+ }
-+}
-+
-+/*
-+ * We need to check the following states:
-+ *
-+ * Waiter | pi_state | pi->owner | uTID | uODIED | ?
-+ *
-+ * [1] NULL | --- | --- | 0 | 0/1 | Valid
-+ * [2] NULL | --- | --- | >0 | 0/1 | Valid
-+ *
-+ * [3] Found | NULL | -- | Any | 0/1 | Invalid
-+ *
-+ * [4] Found | Found | NULL | 0 | 1 | Valid
-+ * [5] Found | Found | NULL | >0 | 1 | Invalid
-+ *
-+ * [6] Found | Found | task | 0 | 1 | Valid
-+ *
-+ * [7] Found | Found | NULL | Any | 0 | Invalid
-+ *
-+ * [8] Found | Found | task | ==taskTID | 0/1 | Valid
-+ * [9] Found | Found | task | 0 | 0 | Invalid
-+ * [10] Found | Found | task | !=taskTID | 0/1 | Invalid
-+ *
-+ * [1] Indicates that the kernel can acquire the futex atomically. We
-+ * came came here due to a stale FUTEX_WAITERS/FUTEX_OWNER_DIED bit.
-+ *
-+ * [2] Valid, if TID does not belong to a kernel thread. If no matching
-+ * thread is found then it indicates that the owner TID has died.
-+ *
-+ * [3] Invalid. The waiter is queued on a non PI futex
-+ *
-+ * [4] Valid state after exit_robust_list(), which sets the user space
-+ * value to FUTEX_WAITERS | FUTEX_OWNER_DIED.
-+ *
-+ * [5] The user space value got manipulated between exit_robust_list()
-+ * and exit_pi_state_list()
-+ *
-+ * [6] Valid state after exit_pi_state_list() which sets the new owner in
-+ * the pi_state but cannot access the user space value.
-+ *
-+ * [7] pi_state->owner can only be NULL when the OWNER_DIED bit is set.
-+ *
-+ * [8] Owner and user space value match
-+ *
-+ * [9] There is no transient state which sets the user space TID to 0
-+ * except exit_robust_list(), but this is indicated by the
-+ * FUTEX_OWNER_DIED bit. See [4]
-+ *
-+ * [10] There is no transient state which leaves owner and user space
-+ * TID out of sync.
-+ *
-+ *
-+ * Serialization and lifetime rules:
-+ *
-+ * hb->lock:
-+ *
-+ * hb -> futex_q, relation
-+ * futex_q -> pi_state, relation
-+ *
-+ * (cannot be raw because hb can contain arbitrary amount
-+ * of futex_q's)
-+ *
-+ * pi_mutex->wait_lock:
-+ *
-+ * {uval, pi_state}
-+ *
-+ * (and pi_mutex 'obviously')
-+ *
-+ * p->pi_lock:
-+ *
-+ * p->pi_state_list -> pi_state->list, relation
-+ *
-+ * pi_state->refcount:
-+ *
-+ * pi_state lifetime
-+ *
-+ *
-+ * Lock order:
-+ *
-+ * hb->lock
-+ * pi_mutex->wait_lock
-+ * p->pi_lock
-+ *
-+ */
-+
-+/*
-+ * Validate that the existing waiter has a pi_state and sanity check
-+ * the pi_state against the user space value. If correct, attach to
-+ * it.
-+ */
-+static int attach_to_pi_state(u32 __user *uaddr, u32 uval,
-+ struct futex_pi_state *pi_state,
-+ struct futex_pi_state **ps)
-+{
-+ pid_t pid = uval & FUTEX_TID_MASK;
-+ u32 uval2;
-+ int ret;
-+
-+ /*
-+ * Userspace might have messed up non-PI and PI futexes [3]
-+ */
-+ if (unlikely(!pi_state))
-+ return -EINVAL;
-+
-+ /*
-+ * We get here with hb->lock held, and having found a
-+ * futex_top_waiter(). This means that futex_lock_pi() of said futex_q
-+ * has dropped the hb->lock in between queue_me() and unqueue_me_pi(),
-+ * which in turn means that futex_lock_pi() still has a reference on
-+ * our pi_state.
-+ *
-+ * The waiter holding a reference on @pi_state also protects against
-+ * the unlocked put_pi_state() in futex_unlock_pi(), futex_lock_pi()
-+ * and futex_wait_requeue_pi() as it cannot go to 0 and consequently
-+ * free pi_state before we can take a reference ourselves.
-+ */
-+ WARN_ON(!refcount_read(&pi_state->refcount));
-+
-+ /*
-+ * Now that we have a pi_state, we can acquire wait_lock
-+ * and do the state validation.
-+ */
-+ raw_spin_lock_irq(&pi_state->pi_mutex.wait_lock);
-+
-+ /*
-+ * Since {uval, pi_state} is serialized by wait_lock, and our current
-+ * uval was read without holding it, it can have changed. Verify it
-+ * still is what we expect it to be, otherwise retry the entire
-+ * operation.
-+ */
-+ if (get_futex_value_locked(&uval2, uaddr))
-+ goto out_efault;
-+
-+ if (uval != uval2)
-+ goto out_eagain;
-+
-+ /*
-+ * Handle the owner died case:
-+ */
-+ if (uval & FUTEX_OWNER_DIED) {
-+ /*
-+ * exit_pi_state_list sets owner to NULL and wakes the
-+ * topmost waiter. The task which acquires the
-+ * pi_state->rt_mutex will fixup owner.
-+ */
-+ if (!pi_state->owner) {
-+ /*
-+ * No pi state owner, but the user space TID
-+ * is not 0. Inconsistent state. [5]
-+ */
-+ if (pid)
-+ goto out_einval;
-+ /*
-+ * Take a ref on the state and return success. [4]
-+ */
-+ goto out_attach;
-+ }
-+
-+ /*
-+ * If TID is 0, then either the dying owner has not
-+ * yet executed exit_pi_state_list() or some waiter
-+ * acquired the rtmutex in the pi state, but did not
-+ * yet fixup the TID in user space.
-+ *
-+ * Take a ref on the state and return success. [6]
-+ */
-+ if (!pid)
-+ goto out_attach;
-+ } else {
-+ /*
-+ * If the owner died bit is not set, then the pi_state
-+ * must have an owner. [7]
-+ */
-+ if (!pi_state->owner)
-+ goto out_einval;
-+ }
-+
-+ /*
-+ * Bail out if user space manipulated the futex value. If pi
-+ * state exists then the owner TID must be the same as the
-+ * user space TID. [9/10]
-+ */
-+ if (pid != task_pid_vnr(pi_state->owner))
-+ goto out_einval;
-+
-+out_attach:
-+ get_pi_state(pi_state);
-+ raw_spin_unlock_irq(&pi_state->pi_mutex.wait_lock);
-+ *ps = pi_state;
-+ return 0;
-+
-+out_einval:
-+ ret = -EINVAL;
-+ goto out_error;
-+
-+out_eagain:
-+ ret = -EAGAIN;
-+ goto out_error;
-+
-+out_efault:
-+ ret = -EFAULT;
-+ goto out_error;
-+
-+out_error:
-+ raw_spin_unlock_irq(&pi_state->pi_mutex.wait_lock);
-+ return ret;
-+}
-+
-+/**
-+ * wait_for_owner_exiting - Block until the owner has exited
-+ * @ret: owner's current futex lock status
-+ * @exiting: Pointer to the exiting task
-+ *
-+ * Caller must hold a refcount on @exiting.
-+ */
-+static void wait_for_owner_exiting(int ret, struct task_struct *exiting)
-+{
-+ if (ret != -EBUSY) {
-+ WARN_ON_ONCE(exiting);
-+ return;
-+ }
-+
-+ if (WARN_ON_ONCE(ret == -EBUSY && !exiting))
-+ return;
-+
-+ mutex_lock(&exiting->futex_exit_mutex);
-+ /*
-+ * No point in doing state checking here. If the waiter got here
-+ * while the task was in exec()->exec_futex_release() then it can
-+ * have any FUTEX_STATE_* value when the waiter has acquired the
-+ * mutex. OK, if running, EXITING or DEAD if it reached exit()
-+ * already. Highly unlikely and not a problem. Just one more round
-+ * through the futex maze.
-+ */
-+ mutex_unlock(&exiting->futex_exit_mutex);
-+
-+ put_task_struct(exiting);
-+}
-+
-+static int handle_exit_race(u32 __user *uaddr, u32 uval,
-+ struct task_struct *tsk)
-+{
-+ u32 uval2;
-+
-+ /*
-+ * If the futex exit state is not yet FUTEX_STATE_DEAD, tell the
-+ * caller that the alleged owner is busy.
-+ */
-+ if (tsk && tsk->futex_state != FUTEX_STATE_DEAD)
-+ return -EBUSY;
-+
-+ /*
-+ * Reread the user space value to handle the following situation:
-+ *
-+ * CPU0 CPU1
-+ *
-+ * sys_exit() sys_futex()
-+ * do_exit() futex_lock_pi()
-+ * futex_lock_pi_atomic()
-+ * exit_signals(tsk) No waiters:
-+ * tsk->flags |= PF_EXITING; *uaddr == 0x00000PID
-+ * mm_release(tsk) Set waiter bit
-+ * exit_robust_list(tsk) { *uaddr = 0x80000PID;
-+ * Set owner died attach_to_pi_owner() {
-+ * *uaddr = 0xC0000000; tsk = get_task(PID);
-+ * } if (!tsk->flags & PF_EXITING) {
-+ * ... attach();
-+ * tsk->futex_state = } else {
-+ * FUTEX_STATE_DEAD; if (tsk->futex_state !=
-+ * FUTEX_STATE_DEAD)
-+ * return -EAGAIN;
-+ * return -ESRCH; <--- FAIL
-+ * }
-+ *
-+ * Returning ESRCH unconditionally is wrong here because the
-+ * user space value has been changed by the exiting task.
-+ *
-+ * The same logic applies to the case where the exiting task is
-+ * already gone.
-+ */
-+ if (get_futex_value_locked(&uval2, uaddr))
-+ return -EFAULT;
-+
-+ /* If the user space value has changed, try again. */
-+ if (uval2 != uval)
-+ return -EAGAIN;
-+
-+ /*
-+ * The exiting task did not have a robust list, the robust list was
-+ * corrupted or the user space value in *uaddr is simply bogus.
-+ * Give up and tell user space.
-+ */
-+ return -ESRCH;
-+}
-+
-+/*
-+ * Lookup the task for the TID provided from user space and attach to
-+ * it after doing proper sanity checks.
-+ */
-+static int attach_to_pi_owner(u32 __user *uaddr, u32 uval, union futex_key *key,
-+ struct futex_pi_state **ps,
-+ struct task_struct **exiting)
-+{
-+ pid_t pid = uval & FUTEX_TID_MASK;
-+ struct futex_pi_state *pi_state;
-+ struct task_struct *p;
-+
-+ /*
-+ * We are the first waiter - try to look up the real owner and attach
-+ * the new pi_state to it, but bail out when TID = 0 [1]
-+ *
-+ * The !pid check is paranoid. None of the call sites should end up
-+ * with pid == 0, but better safe than sorry. Let the caller retry
-+ */
-+ if (!pid)
-+ return -EAGAIN;
-+ p = find_get_task_by_vpid(pid);
-+ if (!p)
-+ return handle_exit_race(uaddr, uval, NULL);
-+
-+ if (unlikely(p->flags & PF_KTHREAD)) {
-+ put_task_struct(p);
-+ return -EPERM;
-+ }
-+
-+ /*
-+ * We need to look at the task state to figure out, whether the
-+ * task is exiting. To protect against the change of the task state
-+ * in futex_exit_release(), we do this protected by p->pi_lock:
-+ */
-+ raw_spin_lock_irq(&p->pi_lock);
-+ if (unlikely(p->futex_state != FUTEX_STATE_OK)) {
-+ /*
-+ * The task is on the way out. When the futex state is
-+ * FUTEX_STATE_DEAD, we know that the task has finished
-+ * the cleanup:
-+ */
-+ int ret = handle_exit_race(uaddr, uval, p);
-+
-+ raw_spin_unlock_irq(&p->pi_lock);
-+ /*
-+ * If the owner task is between FUTEX_STATE_EXITING and
-+ * FUTEX_STATE_DEAD then store the task pointer and keep
-+ * the reference on the task struct. The calling code will
-+ * drop all locks, wait for the task to reach
-+ * FUTEX_STATE_DEAD and then drop the refcount. This is
-+ * required to prevent a live lock when the current task
-+ * preempted the exiting task between the two states.
-+ */
-+ if (ret == -EBUSY)
-+ *exiting = p;
-+ else
-+ put_task_struct(p);
-+ return ret;
-+ }
-+
-+ /*
-+ * No existing pi state. First waiter. [2]
-+ *
-+ * This creates pi_state, we have hb->lock held, this means nothing can
-+ * observe this state, wait_lock is irrelevant.
-+ */
-+ pi_state = alloc_pi_state();
-+
-+ /*
-+ * Initialize the pi_mutex in locked state and make @p
-+ * the owner of it:
-+ */
-+ rt_mutex_init_proxy_locked(&pi_state->pi_mutex, p);
-+
-+ /* Store the key for possible exit cleanups: */
-+ pi_state->key = *key;
-+
-+ WARN_ON(!list_empty(&pi_state->list));
-+ list_add(&pi_state->list, &p->pi_state_list);
-+ /*
-+ * Assignment without holding pi_state->pi_mutex.wait_lock is safe
-+ * because there is no concurrency as the object is not published yet.
-+ */
-+ pi_state->owner = p;
-+ raw_spin_unlock_irq(&p->pi_lock);
-+
-+ put_task_struct(p);
-+
-+ *ps = pi_state;
-+
-+ return 0;
-+}
-+
-+static int lookup_pi_state(u32 __user *uaddr, u32 uval,
-+ struct futex_hash_bucket *hb,
-+ union futex_key *key, struct futex_pi_state **ps,
-+ struct task_struct **exiting)
-+{
-+ struct futex_q *top_waiter = futex_top_waiter(hb, key);
-+
-+ /*
-+ * If there is a waiter on that futex, validate it and
-+ * attach to the pi_state when the validation succeeds.
-+ */
-+ if (top_waiter)
-+ return attach_to_pi_state(uaddr, uval, top_waiter->pi_state, ps);
-+
-+ /*
-+ * We are the first waiter - try to look up the owner based on
-+ * @uval and attach to it.
-+ */
-+ return attach_to_pi_owner(uaddr, uval, key, ps, exiting);
-+}
-+
-+static int lock_pi_update_atomic(u32 __user *uaddr, u32 uval, u32 newval)
-+{
-+ int err;
-+ u32 curval;
-+
-+ if (unlikely(should_fail_futex(true)))
-+ return -EFAULT;
-+
-+ err = cmpxchg_futex_value_locked(&curval, uaddr, uval, newval);
-+ if (unlikely(err))
-+ return err;
-+
-+ /* If user space value changed, let the caller retry */
-+ return curval != uval ? -EAGAIN : 0;
-+}
-+
-+/**
-+ * futex_lock_pi_atomic() - Atomic work required to acquire a pi aware futex
-+ * @uaddr: the pi futex user address
-+ * @hb: the pi futex hash bucket
-+ * @key: the futex key associated with uaddr and hb
-+ * @ps: the pi_state pointer where we store the result of the
-+ * lookup
-+ * @task: the task to perform the atomic lock work for. This will
-+ * be "current" except in the case of requeue pi.
-+ * @exiting: Pointer to store the task pointer of the owner task
-+ * which is in the middle of exiting
-+ * @set_waiters: force setting the FUTEX_WAITERS bit (1) or not (0)
-+ *
-+ * Return:
-+ * - 0 - ready to wait;
-+ * - 1 - acquired the lock;
-+ * - <0 - error
-+ *
-+ * The hb->lock and futex_key refs shall be held by the caller.
-+ *
-+ * @exiting is only set when the return value is -EBUSY. If so, this holds
-+ * a refcount on the exiting task on return and the caller needs to drop it
-+ * after waiting for the exit to complete.
-+ */
-+static int futex_lock_pi_atomic(u32 __user *uaddr, struct futex_hash_bucket *hb,
-+ union futex_key *key,
-+ struct futex_pi_state **ps,
-+ struct task_struct *task,
-+ struct task_struct **exiting,
-+ int set_waiters)
-+{
-+ u32 uval, newval, vpid = task_pid_vnr(task);
-+ struct futex_q *top_waiter;
-+ int ret;
-+
-+ /*
-+ * Read the user space value first so we can validate a few
-+ * things before proceeding further.
-+ */
-+ if (get_futex_value_locked(&uval, uaddr))
-+ return -EFAULT;
-+
-+ if (unlikely(should_fail_futex(true)))
-+ return -EFAULT;
-+
-+ /*
-+ * Detect deadlocks.
-+ */
-+ if ((unlikely((uval & FUTEX_TID_MASK) == vpid)))
-+ return -EDEADLK;
-+
-+ if ((unlikely(should_fail_futex(true))))
-+ return -EDEADLK;
-+
-+ /*
-+ * Lookup existing state first. If it exists, try to attach to
-+ * its pi_state.
-+ */
-+ top_waiter = futex_top_waiter(hb, key);
-+ if (top_waiter)
-+ return attach_to_pi_state(uaddr, uval, top_waiter->pi_state, ps);
-+
-+ /*
-+ * No waiter and user TID is 0. We are here because the
-+ * waiters or the owner died bit is set or called from
-+ * requeue_cmp_pi or for whatever reason something took the
-+ * syscall.
-+ */
-+ if (!(uval & FUTEX_TID_MASK)) {
-+ /*
-+ * We take over the futex. No other waiters and the user space
-+ * TID is 0. We preserve the owner died bit.
-+ */
-+ newval = uval & FUTEX_OWNER_DIED;
-+ newval |= vpid;
-+
-+ /* The futex requeue_pi code can enforce the waiters bit */
-+ if (set_waiters)
-+ newval |= FUTEX_WAITERS;
-+
-+ ret = lock_pi_update_atomic(uaddr, uval, newval);
-+ /* If the take over worked, return 1 */
-+ return ret < 0 ? ret : 1;
-+ }
-+
-+ /*
-+ * First waiter. Set the waiters bit before attaching ourself to
-+ * the owner. If owner tries to unlock, it will be forced into
-+ * the kernel and blocked on hb->lock.
-+ */
-+ newval = uval | FUTEX_WAITERS;
-+ ret = lock_pi_update_atomic(uaddr, uval, newval);
-+ if (ret)
-+ return ret;
-+ /*
-+ * If the update of the user space value succeeded, we try to
-+ * attach to the owner. If that fails, no harm done, we only
-+ * set the FUTEX_WAITERS bit in the user space variable.
-+ */
-+ return attach_to_pi_owner(uaddr, newval, key, ps, exiting);
-+}
-+
-+/**
-+ * __unqueue_futex() - Remove the futex_q from its futex_hash_bucket
-+ * @q: The futex_q to unqueue
-+ *
-+ * The q->lock_ptr must not be NULL and must be held by the caller.
-+ */
-+static void __unqueue_futex(struct futex_q *q)
-+{
-+ struct futex_hash_bucket *hb;
-+
-+ if (WARN_ON_SMP(!q->lock_ptr) || WARN_ON(plist_node_empty(&q->list)))
-+ return;
-+ lockdep_assert_held(q->lock_ptr);
-+
-+ hb = container_of(q->lock_ptr, struct futex_hash_bucket, lock);
-+ plist_del(&q->list, &hb->chain);
-+ hb_waiters_dec(hb);
-+}
-+
-+/*
-+ * The hash bucket lock must be held when this is called.
-+ * Afterwards, the futex_q must not be accessed. Callers
-+ * must ensure to later call wake_up_q() for the actual
-+ * wakeups to occur.
-+ */
-+static void mark_wake_futex(struct wake_q_head *wake_q, struct futex_q *q)
-+{
-+ struct task_struct *p = q->task;
-+
-+ if (WARN(q->pi_state || q->rt_waiter, "refusing to wake PI futex\n"))
-+ return;
-+
-+ get_task_struct(p);
-+ __unqueue_futex(q);
-+ /*
-+ * The waiting task can free the futex_q as soon as q->lock_ptr = NULL
-+ * is written, without taking any locks. This is possible in the event
-+ * of a spurious wakeup, for example. A memory barrier is required here
-+ * to prevent the following store to lock_ptr from getting ahead of the
-+ * plist_del in __unqueue_futex().
-+ */
-+ smp_store_release(&q->lock_ptr, NULL);
-+
-+ /*
-+ * Queue the task for later wakeup for after we've released
-+ * the hb->lock.
-+ */
-+ wake_q_add_safe(wake_q, p);
-+}
-+
-+/*
-+ * Caller must hold a reference on @pi_state.
-+ */
-+static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_pi_state *pi_state)
-+{
-+ u32 curval, newval;
-+ struct task_struct *new_owner;
-+ bool postunlock = false;
-+ DEFINE_WAKE_Q(wake_q);
-+ int ret = 0;
-+
-+ new_owner = rt_mutex_next_owner(&pi_state->pi_mutex);
-+ if (WARN_ON_ONCE(!new_owner)) {
-+ /*
-+ * As per the comment in futex_unlock_pi() this should not happen.
-+ *
-+ * When this happens, give up our locks and try again, giving
-+ * the futex_lock_pi() instance time to complete, either by
-+ * waiting on the rtmutex or removing itself from the futex
-+ * queue.
-+ */
-+ ret = -EAGAIN;
-+ goto out_unlock;
-+ }
-+
-+ /*
-+ * We pass it to the next owner. The WAITERS bit is always kept
-+ * enabled while there is PI state around. We cleanup the owner
-+ * died bit, because we are the owner.
-+ */
-+ newval = FUTEX_WAITERS | task_pid_vnr(new_owner);
-+
-+ if (unlikely(should_fail_futex(true)))
-+ ret = -EFAULT;
-+
-+ ret = cmpxchg_futex_value_locked(&curval, uaddr, uval, newval);
-+ if (!ret && (curval != uval)) {
-+ /*
-+ * If a unconditional UNLOCK_PI operation (user space did not
-+ * try the TID->0 transition) raced with a waiter setting the
-+ * FUTEX_WAITERS flag between get_user() and locking the hash
-+ * bucket lock, retry the operation.
-+ */
-+ if ((FUTEX_TID_MASK & curval) == uval)
-+ ret = -EAGAIN;
-+ else
-+ ret = -EINVAL;
-+ }
-+
-+ if (ret)
-+ goto out_unlock;
-+
-+ /*
-+ * This is a point of no return; once we modify the uval there is no
-+ * going back and subsequent operations must not fail.
-+ */
-+
-+ raw_spin_lock(&pi_state->owner->pi_lock);
-+ WARN_ON(list_empty(&pi_state->list));
-+ list_del_init(&pi_state->list);
-+ raw_spin_unlock(&pi_state->owner->pi_lock);
-+
-+ raw_spin_lock(&new_owner->pi_lock);
-+ WARN_ON(!list_empty(&pi_state->list));
-+ list_add(&pi_state->list, &new_owner->pi_state_list);
-+ pi_state->owner = new_owner;
-+ raw_spin_unlock(&new_owner->pi_lock);
-+
-+ postunlock = __rt_mutex_futex_unlock(&pi_state->pi_mutex, &wake_q);
-+
-+out_unlock:
-+ raw_spin_unlock_irq(&pi_state->pi_mutex.wait_lock);
-+
-+ if (postunlock)
-+ rt_mutex_postunlock(&wake_q);
-+
-+ return ret;
-+}
-+
-+/*
-+ * Express the locking dependencies for lockdep:
-+ */
-+static inline void
-+double_lock_hb(struct futex_hash_bucket *hb1, struct futex_hash_bucket *hb2)
-+{
-+ if (hb1 <= hb2) {
-+ spin_lock(&hb1->lock);
-+ if (hb1 < hb2)
-+ spin_lock_nested(&hb2->lock, SINGLE_DEPTH_NESTING);
-+ } else { /* hb1 > hb2 */
-+ spin_lock(&hb2->lock);
-+ spin_lock_nested(&hb1->lock, SINGLE_DEPTH_NESTING);
-+ }
-+}
-+
-+static inline void
-+double_unlock_hb(struct futex_hash_bucket *hb1, struct futex_hash_bucket *hb2)
-+{
-+ spin_unlock(&hb1->lock);
-+ if (hb1 != hb2)
-+ spin_unlock(&hb2->lock);
-+}
-+
-+/*
-+ * Wake up waiters matching bitset queued on this futex (uaddr).
-+ */
-+static int
-+futex_wake(u32 __user *uaddr, unsigned int flags, int nr_wake, u32 bitset)
-+{
-+ struct futex_hash_bucket *hb;
-+ struct futex_q *this, *next;
-+ union futex_key key = FUTEX_KEY_INIT;
-+ int ret;
-+ DEFINE_WAKE_Q(wake_q);
-+
-+ if (!bitset)
-+ return -EINVAL;
-+
-+ ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key, FUTEX_READ);
-+ if (unlikely(ret != 0))
-+ return ret;
-+
-+ hb = hash_futex(&key);
-+
-+ /* Make sure we really have tasks to wakeup */
-+ if (!hb_waiters_pending(hb))
-+ return ret;
-+
-+ spin_lock(&hb->lock);
-+
-+ plist_for_each_entry_safe(this, next, &hb->chain, list) {
-+ if (match_futex (&this->key, &key)) {
-+ if (this->pi_state || this->rt_waiter) {
-+ ret = -EINVAL;
-+ break;
-+ }
-+
-+ /* Check if one of the bits is set in both bitsets */
-+ if (!(this->bitset & bitset))
-+ continue;
-+
-+ mark_wake_futex(&wake_q, this);
-+ if (++ret >= nr_wake)
-+ break;
-+ }
-+ }
-+
-+ spin_unlock(&hb->lock);
-+ wake_up_q(&wake_q);
-+ return ret;
-+}
-+
-+static int futex_atomic_op_inuser(unsigned int encoded_op, u32 __user *uaddr)
-+{
-+ unsigned int op = (encoded_op & 0x70000000) >> 28;
-+ unsigned int cmp = (encoded_op & 0x0f000000) >> 24;
-+ int oparg = sign_extend32((encoded_op & 0x00fff000) >> 12, 11);
-+ int cmparg = sign_extend32(encoded_op & 0x00000fff, 11);
-+ int oldval, ret;
-+
-+ if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) {
-+ if (oparg < 0 || oparg > 31) {
-+ char comm[sizeof(current->comm)];
-+ /*
-+ * kill this print and return -EINVAL when userspace
-+ * is sane again
-+ */
-+ pr_info_ratelimited("futex_wake_op: %s tries to shift op by %d; fix this program\n",
-+ get_task_comm(comm, current), oparg);
-+ oparg &= 31;
-+ }
-+ oparg = 1 << oparg;
-+ }
-+
-+ pagefault_disable();
-+ ret = arch_futex_atomic_op_inuser(op, oparg, &oldval, uaddr);
-+ pagefault_enable();
-+ if (ret)
-+ return ret;
-+
-+ switch (cmp) {
-+ case FUTEX_OP_CMP_EQ:
-+ return oldval == cmparg;
-+ case FUTEX_OP_CMP_NE:
-+ return oldval != cmparg;
-+ case FUTEX_OP_CMP_LT:
-+ return oldval < cmparg;
-+ case FUTEX_OP_CMP_GE:
-+ return oldval >= cmparg;
-+ case FUTEX_OP_CMP_LE:
-+ return oldval <= cmparg;
-+ case FUTEX_OP_CMP_GT:
-+ return oldval > cmparg;
-+ default:
-+ return -ENOSYS;
-+ }
-+}
-+
-+/*
-+ * Wake up all waiters hashed on the physical page that is mapped
-+ * to this virtual address:
-+ */
-+static int
-+futex_wake_op(u32 __user *uaddr1, unsigned int flags, u32 __user *uaddr2,
-+ int nr_wake, int nr_wake2, int op)
-+{
-+ union futex_key key1 = FUTEX_KEY_INIT, key2 = FUTEX_KEY_INIT;
-+ struct futex_hash_bucket *hb1, *hb2;
-+ struct futex_q *this, *next;
-+ int ret, op_ret;
-+ DEFINE_WAKE_Q(wake_q);
-+
-+retry:
-+ ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1, FUTEX_READ);
-+ if (unlikely(ret != 0))
-+ return ret;
-+ ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2, FUTEX_WRITE);
-+ if (unlikely(ret != 0))
-+ return ret;
-+
-+ hb1 = hash_futex(&key1);
-+ hb2 = hash_futex(&key2);
-+
-+retry_private:
-+ double_lock_hb(hb1, hb2);
-+ op_ret = futex_atomic_op_inuser(op, uaddr2);
-+ if (unlikely(op_ret < 0)) {
-+ double_unlock_hb(hb1, hb2);
-+
-+ if (!IS_ENABLED(CONFIG_MMU) ||
-+ unlikely(op_ret != -EFAULT && op_ret != -EAGAIN)) {
-+ /*
-+ * we don't get EFAULT from MMU faults if we don't have
-+ * an MMU, but we might get them from range checking
-+ */
-+ ret = op_ret;
-+ return ret;
-+ }
-+
-+ if (op_ret == -EFAULT) {
-+ ret = fault_in_user_writeable(uaddr2);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ if (!(flags & FLAGS_SHARED)) {
-+ cond_resched();
-+ goto retry_private;
-+ }
-+
-+ cond_resched();
-+ goto retry;
-+ }
-+
-+ plist_for_each_entry_safe(this, next, &hb1->chain, list) {
-+ if (match_futex (&this->key, &key1)) {
-+ if (this->pi_state || this->rt_waiter) {
-+ ret = -EINVAL;
-+ goto out_unlock;
-+ }
-+ mark_wake_futex(&wake_q, this);
-+ if (++ret >= nr_wake)
-+ break;
-+ }
-+ }
-+
-+ if (op_ret > 0) {
-+ op_ret = 0;
-+ plist_for_each_entry_safe(this, next, &hb2->chain, list) {
-+ if (match_futex (&this->key, &key2)) {
-+ if (this->pi_state || this->rt_waiter) {
-+ ret = -EINVAL;
-+ goto out_unlock;
-+ }
-+ mark_wake_futex(&wake_q, this);
-+ if (++op_ret >= nr_wake2)
-+ break;
-+ }
-+ }
-+ ret += op_ret;
-+ }
-+
-+out_unlock:
-+ double_unlock_hb(hb1, hb2);
-+ wake_up_q(&wake_q);
-+ return ret;
-+}
-+
-+/**
-+ * requeue_futex() - Requeue a futex_q from one hb to another
-+ * @q: the futex_q to requeue
-+ * @hb1: the source hash_bucket
-+ * @hb2: the target hash_bucket
-+ * @key2: the new key for the requeued futex_q
-+ */
-+static inline
-+void requeue_futex(struct futex_q *q, struct futex_hash_bucket *hb1,
-+ struct futex_hash_bucket *hb2, union futex_key *key2)
-+{
-+
-+ /*
-+ * If key1 and key2 hash to the same bucket, no need to
-+ * requeue.
-+ */
-+ if (likely(&hb1->chain != &hb2->chain)) {
-+ plist_del(&q->list, &hb1->chain);
-+ hb_waiters_dec(hb1);
-+ hb_waiters_inc(hb2);
-+ plist_add(&q->list, &hb2->chain);
-+ q->lock_ptr = &hb2->lock;
-+ }
-+ q->key = *key2;
-+}
-+
-+/**
-+ * requeue_pi_wake_futex() - Wake a task that acquired the lock during requeue
-+ * @q: the futex_q
-+ * @key: the key of the requeue target futex
-+ * @hb: the hash_bucket of the requeue target futex
-+ *
-+ * During futex_requeue, with requeue_pi=1, it is possible to acquire the
-+ * target futex if it is uncontended or via a lock steal. Set the futex_q key
-+ * to the requeue target futex so the waiter can detect the wakeup on the right
-+ * futex, but remove it from the hb and NULL the rt_waiter so it can detect
-+ * atomic lock acquisition. Set the q->lock_ptr to the requeue target hb->lock
-+ * to protect access to the pi_state to fixup the owner later. Must be called
-+ * with both q->lock_ptr and hb->lock held.
-+ */
-+static inline
-+void requeue_pi_wake_futex(struct futex_q *q, union futex_key *key,
-+ struct futex_hash_bucket *hb)
-+{
-+ q->key = *key;
-+
-+ __unqueue_futex(q);
-+
-+ WARN_ON(!q->rt_waiter);
-+ q->rt_waiter = NULL;
-+
-+ q->lock_ptr = &hb->lock;
-+
-+ wake_up_state(q->task, TASK_NORMAL);
-+}
-+
-+/**
-+ * futex_proxy_trylock_atomic() - Attempt an atomic lock for the top waiter
-+ * @pifutex: the user address of the to futex
-+ * @hb1: the from futex hash bucket, must be locked by the caller
-+ * @hb2: the to futex hash bucket, must be locked by the caller
-+ * @key1: the from futex key
-+ * @key2: the to futex key
-+ * @ps: address to store the pi_state pointer
-+ * @exiting: Pointer to store the task pointer of the owner task
-+ * which is in the middle of exiting
-+ * @set_waiters: force setting the FUTEX_WAITERS bit (1) or not (0)
-+ *
-+ * Try and get the lock on behalf of the top waiter if we can do it atomically.
-+ * Wake the top waiter if we succeed. If the caller specified set_waiters,
-+ * then direct futex_lock_pi_atomic() to force setting the FUTEX_WAITERS bit.
-+ * hb1 and hb2 must be held by the caller.
-+ *
-+ * @exiting is only set when the return value is -EBUSY. If so, this holds
-+ * a refcount on the exiting task on return and the caller needs to drop it
-+ * after waiting for the exit to complete.
-+ *
-+ * Return:
-+ * - 0 - failed to acquire the lock atomically;
-+ * - >0 - acquired the lock, return value is vpid of the top_waiter
-+ * - <0 - error
-+ */
-+static int
-+futex_proxy_trylock_atomic(u32 __user *pifutex, struct futex_hash_bucket *hb1,
-+ struct futex_hash_bucket *hb2, union futex_key *key1,
-+ union futex_key *key2, struct futex_pi_state **ps,
-+ struct task_struct **exiting, int set_waiters)
-+{
-+ struct futex_q *top_waiter = NULL;
-+ u32 curval;
-+ int ret, vpid;
-+
-+ if (get_futex_value_locked(&curval, pifutex))
-+ return -EFAULT;
-+
-+ if (unlikely(should_fail_futex(true)))
-+ return -EFAULT;
-+
-+ /*
-+ * Find the top_waiter and determine if there are additional waiters.
-+ * If the caller intends to requeue more than 1 waiter to pifutex,
-+ * force futex_lock_pi_atomic() to set the FUTEX_WAITERS bit now,
-+ * as we have means to handle the possible fault. If not, don't set
-+ * the bit unecessarily as it will force the subsequent unlock to enter
-+ * the kernel.
-+ */
-+ top_waiter = futex_top_waiter(hb1, key1);
-+
-+ /* There are no waiters, nothing for us to do. */
-+ if (!top_waiter)
-+ return 0;
-+
-+ /* Ensure we requeue to the expected futex. */
-+ if (!match_futex(top_waiter->requeue_pi_key, key2))
-+ return -EINVAL;
-+
-+ /*
-+ * Try to take the lock for top_waiter. Set the FUTEX_WAITERS bit in
-+ * the contended case or if set_waiters is 1. The pi_state is returned
-+ * in ps in contended cases.
-+ */
-+ vpid = task_pid_vnr(top_waiter->task);
-+ ret = futex_lock_pi_atomic(pifutex, hb2, key2, ps, top_waiter->task,
-+ exiting, set_waiters);
-+ if (ret == 1) {
-+ requeue_pi_wake_futex(top_waiter, key2, hb2);
-+ return vpid;
-+ }
-+ return ret;
-+}
-+
-+/**
-+ * futex_requeue() - Requeue waiters from uaddr1 to uaddr2
-+ * @uaddr1: source futex user address
-+ * @flags: futex flags (FLAGS_SHARED, etc.)
-+ * @uaddr2: target futex user address
-+ * @nr_wake: number of waiters to wake (must be 1 for requeue_pi)
-+ * @nr_requeue: number of waiters to requeue (0-INT_MAX)
-+ * @cmpval: @uaddr1 expected value (or %NULL)
-+ * @requeue_pi: if we are attempting to requeue from a non-pi futex to a
-+ * pi futex (pi to pi requeue is not supported)
-+ *
-+ * Requeue waiters on uaddr1 to uaddr2. In the requeue_pi case, try to acquire
-+ * uaddr2 atomically on behalf of the top waiter.
-+ *
-+ * Return:
-+ * - >=0 - on success, the number of tasks requeued or woken;
-+ * - <0 - on error
-+ */
-+static int futex_requeue(u32 __user *uaddr1, unsigned int flags,
-+ u32 __user *uaddr2, int nr_wake, int nr_requeue,
-+ u32 *cmpval, int requeue_pi)
++int main(int argc, char *argv[])
+{
-+ union futex_key key1 = FUTEX_KEY_INIT, key2 = FUTEX_KEY_INIT;
-+ int task_count = 0, ret;
-+ struct futex_pi_state *pi_state = NULL;
-+ struct futex_hash_bucket *hb1, *hb2;
-+ struct futex_q *this, *next;
-+ DEFINE_WAKE_Q(wake_q);
-+
-+ if (nr_wake < 0 || nr_requeue < 0)
-+ return -EINVAL;
-+
-+ /*
-+ * When PI not supported: return -ENOSYS if requeue_pi is true,
-+ * consequently the compiler knows requeue_pi is always false past
-+ * this point which will optimize away all the conditional code
-+ * further down.
-+ */
-+ if (!IS_ENABLED(CONFIG_FUTEX_PI) && requeue_pi)
-+ return -ENOSYS;
-+
-+ if (requeue_pi) {
-+ /*
-+ * Requeue PI only works on two distinct uaddrs. This
-+ * check is only valid for private futexes. See below.
-+ */
-+ if (uaddr1 == uaddr2)
-+ return -EINVAL;
-+
-+ /*
-+ * requeue_pi requires a pi_state, try to allocate it now
-+ * without any locks in case it fails.
-+ */
-+ if (refill_pi_state_cache())
-+ return -ENOMEM;
-+ /*
-+ * requeue_pi must wake as many tasks as it can, up to nr_wake
-+ * + nr_requeue, since it acquires the rt_mutex prior to
-+ * returning to userspace, so as to not leave the rt_mutex with
-+ * waiters and no owner. However, second and third wake-ups
-+ * cannot be predicted as they involve race conditions with the
-+ * first wake and a fault while looking up the pi_state. Both
-+ * pthread_cond_signal() and pthread_cond_broadcast() should
-+ * use nr_wake=1.
-+ */
-+ if (nr_wake != 1)
-+ return -EINVAL;
-+ }
-+
-+retry:
-+ ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1, FUTEX_READ);
-+ if (unlikely(ret != 0))
-+ return ret;
-+ ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2,
-+ requeue_pi ? FUTEX_WRITE : FUTEX_READ);
-+ if (unlikely(ret != 0))
-+ return ret;
-+
-+ /*
-+ * The check above which compares uaddrs is not sufficient for
-+ * shared futexes. We need to compare the keys:
-+ */
-+ if (requeue_pi && match_futex(&key1, &key2))
-+ return -EINVAL;
-+
-+ hb1 = hash_futex(&key1);
-+ hb2 = hash_futex(&key2);
-+
-+retry_private:
-+ hb_waiters_inc(hb2);
-+ double_lock_hb(hb1, hb2);
-+
-+ if (likely(cmpval != NULL)) {
-+ u32 curval;
-+
-+ ret = get_futex_value_locked(&curval, uaddr1);
-+
-+ if (unlikely(ret)) {
-+ double_unlock_hb(hb1, hb2);
-+ hb_waiters_dec(hb2);
-+
-+ ret = get_user(curval, uaddr1);
-+ if (ret)
-+ return ret;
-+
-+ if (!(flags & FLAGS_SHARED))
-+ goto retry_private;
-+
-+ goto retry;
-+ }
-+ if (curval != *cmpval) {
-+ ret = -EAGAIN;
-+ goto out_unlock;
-+ }
-+ }
-+
-+ if (requeue_pi && (task_count - nr_wake < nr_requeue)) {
-+ struct task_struct *exiting = NULL;
-+
-+ /*
-+ * Attempt to acquire uaddr2 and wake the top waiter. If we
-+ * intend to requeue waiters, force setting the FUTEX_WAITERS
-+ * bit. We force this here where we are able to easily handle
-+ * faults rather in the requeue loop below.
-+ */
-+ ret = futex_proxy_trylock_atomic(uaddr2, hb1, hb2, &key1,
-+ &key2, &pi_state,
-+ &exiting, nr_requeue);
-+
-+ /*
-+ * At this point the top_waiter has either taken uaddr2 or is
-+ * waiting on it. If the former, then the pi_state will not
-+ * exist yet, look it up one more time to ensure we have a
-+ * reference to it. If the lock was taken, ret contains the
-+ * vpid of the top waiter task.
-+ * If the lock was not taken, we have pi_state and an initial
-+ * refcount on it. In case of an error we have nothing.
-+ */
-+ if (ret > 0) {
-+ WARN_ON(pi_state);
-+ task_count++;
-+ /*
-+ * If we acquired the lock, then the user space value
-+ * of uaddr2 should be vpid. It cannot be changed by
-+ * the top waiter as it is blocked on hb2 lock if it
-+ * tries to do so. If something fiddled with it behind
-+ * our back the pi state lookup might unearth it. So
-+ * we rather use the known value than rereading and
-+ * handing potential crap to lookup_pi_state.
-+ *
-+ * If that call succeeds then we have pi_state and an
-+ * initial refcount on it.
-+ */
-+ ret = lookup_pi_state(uaddr2, ret, hb2, &key2,
-+ &pi_state, &exiting);
-+ }
-+
-+ switch (ret) {
-+ case 0:
-+ /* We hold a reference on the pi state. */
-+ break;
-+
-+ /* If the above failed, then pi_state is NULL */
-+ case -EFAULT:
-+ double_unlock_hb(hb1, hb2);
-+ hb_waiters_dec(hb2);
-+ ret = fault_in_user_writeable(uaddr2);
-+ if (!ret)
-+ goto retry;
-+ return ret;
-+ case -EBUSY:
-+ case -EAGAIN:
-+ /*
-+ * Two reasons for this:
-+ * - EBUSY: Owner is exiting and we just wait for the
-+ * exit to complete.
-+ * - EAGAIN: The user space value changed.
-+ */
-+ double_unlock_hb(hb1, hb2);
-+ hb_waiters_dec(hb2);
-+ /*
-+ * Handle the case where the owner is in the middle of
-+ * exiting. Wait for the exit to complete otherwise
-+ * this task might loop forever, aka. live lock.
-+ */
-+ wait_for_owner_exiting(ret, exiting);
-+ cond_resched();
-+ goto retry;
-+ default:
-+ goto out_unlock;
-+ }
-+ }
-+
-+ plist_for_each_entry_safe(this, next, &hb1->chain, list) {
-+ if (task_count - nr_wake >= nr_requeue)
-+ break;
-+
-+ if (!match_futex(&this->key, &key1))
-+ continue;
-+
-+ /*
-+ * FUTEX_WAIT_REQEUE_PI and FUTEX_CMP_REQUEUE_PI should always
-+ * be paired with each other and no other futex ops.
-+ *
-+ * We should never be requeueing a futex_q with a pi_state,
-+ * which is awaiting a futex_unlock_pi().
-+ */
-+ if ((requeue_pi && !this->rt_waiter) ||
-+ (!requeue_pi && this->rt_waiter) ||
-+ this->pi_state) {
-+ ret = -EINVAL;
-+ break;
-+ }
-+
-+ /*
-+ * Wake nr_wake waiters. For requeue_pi, if we acquired the
-+ * lock, we already woke the top_waiter. If not, it will be
-+ * woken by futex_unlock_pi().
-+ */
-+ if (++task_count <= nr_wake && !requeue_pi) {
-+ mark_wake_futex(&wake_q, this);
-+ continue;
-+ }
++ pthread_t waiter;
++ int res, ret = RET_PASS;
++ int c, i;
+
-+ /* Ensure we requeue to the expected futex for requeue_pi. */
-+ if (requeue_pi && !match_futex(this->requeue_pi_key, &key2)) {
-+ ret = -EINVAL;
++ while ((c = getopt(argc, argv, "cht:v:")) != -1) {
++ switch (c) {
++ case 'c':
++ log_color(1);
+ break;
-+ }
-+
-+ /*
-+ * Requeue nr_requeue waiters and possibly one more in the case
-+ * of requeue_pi if we couldn't acquire the lock atomically.
-+ */
-+ if (requeue_pi) {
-+ /*
-+ * Prepare the waiter to take the rt_mutex. Take a
-+ * refcount on the pi_state and store the pointer in
-+ * the futex_q object of the waiter.
-+ */
-+ get_pi_state(pi_state);
-+ this->pi_state = pi_state;
-+ ret = rt_mutex_start_proxy_lock(&pi_state->pi_mutex,
-+ this->rt_waiter,
-+ this->task);
-+ if (ret == 1) {
-+ /*
-+ * We got the lock. We do neither drop the
-+ * refcount on pi_state nor clear
-+ * this->pi_state because the waiter needs the
-+ * pi_state for cleaning up the user space
-+ * value. It will drop the refcount after
-+ * doing so.
-+ */
-+ requeue_pi_wake_futex(this, &key2, hb2);
-+ continue;
-+ } else if (ret) {
-+ /*
-+ * rt_mutex_start_proxy_lock() detected a
-+ * potential deadlock when we tried to queue
-+ * that waiter. Drop the pi_state reference
-+ * which we took above and remove the pointer
-+ * to the state from the waiters futex_q
-+ * object.
-+ */
-+ this->pi_state = NULL;
-+ put_pi_state(pi_state);
-+ /*
-+ * We stop queueing more waiters and let user
-+ * space deal with the mess.
-+ */
-+ break;
-+ }
-+ }
-+ requeue_futex(this, hb1, hb2, &key2);
-+ }
-+
-+ /*
-+ * We took an extra initial reference to the pi_state either
-+ * in futex_proxy_trylock_atomic() or in lookup_pi_state(). We
-+ * need to drop it here again.
-+ */
-+ put_pi_state(pi_state);
-+
-+out_unlock:
-+ double_unlock_hb(hb1, hb2);
-+ wake_up_q(&wake_q);
-+ hb_waiters_dec(hb2);
-+ return ret ? ret : task_count;
-+}
-+
-+/* The key must be already stored in q->key. */
-+static inline struct futex_hash_bucket *queue_lock(struct futex_q *q)
-+ __acquires(&hb->lock)
-+{
-+ struct futex_hash_bucket *hb;
-+
-+ hb = hash_futex(&q->key);
-+
-+ /*
-+ * Increment the counter before taking the lock so that
-+ * a potential waker won't miss a to-be-slept task that is
-+ * waiting for the spinlock. This is safe as all queue_lock()
-+ * users end up calling queue_me(). Similarly, for housekeeping,
-+ * decrement the counter at queue_unlock() when some error has
-+ * occurred and we don't end up adding the task to the list.
-+ */
-+ hb_waiters_inc(hb); /* implies smp_mb(); (A) */
-+
-+ q->lock_ptr = &hb->lock;
-+
-+ spin_lock(&hb->lock);
-+ return hb;
-+}
-+
-+static inline void
-+queue_unlock(struct futex_hash_bucket *hb)
-+ __releases(&hb->lock)
-+{
-+ spin_unlock(&hb->lock);
-+ hb_waiters_dec(hb);
-+}
-+
-+static inline void __queue_me(struct futex_q *q, struct futex_hash_bucket *hb)
-+{
-+ int prio;
-+
-+ /*
-+ * The priority used to register this element is
-+ * - either the real thread-priority for the real-time threads
-+ * (i.e. threads with a priority lower than MAX_RT_PRIO)
-+ * - or MAX_RT_PRIO for non-RT threads.
-+ * Thus, all RT-threads are woken first in priority order, and
-+ * the others are woken last, in FIFO order.
-+ */
-+ prio = min(current->normal_prio, MAX_RT_PRIO);
-+
-+ plist_node_init(&q->list, prio);
-+ plist_add(&q->list, &hb->chain);
-+ q->task = current;
-+}
-+
-+/**
-+ * queue_me() - Enqueue the futex_q on the futex_hash_bucket
-+ * @q: The futex_q to enqueue
-+ * @hb: The destination hash bucket
-+ *
-+ * The hb->lock must be held by the caller, and is released here. A call to
-+ * queue_me() is typically paired with exactly one call to unqueue_me(). The
-+ * exceptions involve the PI related operations, which may use unqueue_me_pi()
-+ * or nothing if the unqueue is done as part of the wake process and the unqueue
-+ * state is implicit in the state of woken task (see futex_wait_requeue_pi() for
-+ * an example).
-+ */
-+static inline void queue_me(struct futex_q *q, struct futex_hash_bucket *hb)
-+ __releases(&hb->lock)
-+{
-+ __queue_me(q, hb);
-+ spin_unlock(&hb->lock);
-+}
-+
-+/**
-+ * unqueue_me() - Remove the futex_q from its futex_hash_bucket
-+ * @q: The futex_q to unqueue
-+ *
-+ * The q->lock_ptr must not be held by the caller. A call to unqueue_me() must
-+ * be paired with exactly one earlier call to queue_me().
-+ *
-+ * Return:
-+ * - 1 - if the futex_q was still queued (and we removed unqueued it);
-+ * - 0 - if the futex_q was already removed by the waking thread
-+ */
-+static int unqueue_me(struct futex_q *q)
-+{
-+ spinlock_t *lock_ptr;
-+ int ret = 0;
-+
-+ /* In the common case we don't take the spinlock, which is nice. */
-+retry:
-+ /*
-+ * q->lock_ptr can change between this read and the following spin_lock.
-+ * Use READ_ONCE to forbid the compiler from reloading q->lock_ptr and
-+ * optimizing lock_ptr out of the logic below.
-+ */
-+ lock_ptr = READ_ONCE(q->lock_ptr);
-+ if (lock_ptr != NULL) {
-+ spin_lock(lock_ptr);
-+ /*
-+ * q->lock_ptr can change between reading it and
-+ * spin_lock(), causing us to take the wrong lock. This
-+ * corrects the race condition.
-+ *
-+ * Reasoning goes like this: if we have the wrong lock,
-+ * q->lock_ptr must have changed (maybe several times)
-+ * between reading it and the spin_lock(). It can
-+ * change again after the spin_lock() but only if it was
-+ * already changed before the spin_lock(). It cannot,
-+ * however, change back to the original value. Therefore
-+ * we can detect whether we acquired the correct lock.
-+ */
-+ if (unlikely(lock_ptr != q->lock_ptr)) {
-+ spin_unlock(lock_ptr);
-+ goto retry;
-+ }
-+ __unqueue_futex(q);
-+
-+ BUG_ON(q->pi_state);
-+
-+ spin_unlock(lock_ptr);
-+ ret = 1;
-+ }
-+
-+ return ret;
-+}
-+
-+/*
-+ * 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
-+ * and dropped here.
-+ */
-+static void unqueue_me_pi(struct futex_q *q)
-+ __releases(q->lock_ptr)
-+{
-+ __unqueue_futex(q);
-+
-+ BUG_ON(!q->pi_state);
-+ put_pi_state(q->pi_state);
-+ q->pi_state = NULL;
-+
-+ spin_unlock(q->lock_ptr);
-+}
-+
-+static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
-+ struct task_struct *argowner)
-+{
-+ struct futex_pi_state *pi_state = q->pi_state;
-+ u32 uval, curval, newval;
-+ struct task_struct *oldowner, *newowner;
-+ u32 newtid;
-+ int ret, err = 0;
-+
-+ lockdep_assert_held(q->lock_ptr);
-+
-+ raw_spin_lock_irq(&pi_state->pi_mutex.wait_lock);
-+
-+ oldowner = pi_state->owner;
-+
-+ /*
-+ * We are here because either:
-+ *
-+ * - we stole the lock and pi_state->owner needs updating to reflect
-+ * that (@argowner == current),
-+ *
-+ * or:
-+ *
-+ * - someone stole our lock and we need to fix things to point to the
-+ * new owner (@argowner == NULL).
-+ *
-+ * Either way, we have to replace the TID in the user space variable.
-+ * This must be atomic as we have to preserve the owner died bit here.
-+ *
-+ * Note: We write the user space value _before_ changing the pi_state
-+ * because we can fault here. Imagine swapped out pages or a fork
-+ * that marked all the anonymous memory readonly for cow.
-+ *
-+ * Modifying pi_state _before_ the user space value would leave the
-+ * pi_state in an inconsistent state when we fault here, because we
-+ * need to drop the locks to handle the fault. This might be observed
-+ * in the PID check in lookup_pi_state.
-+ */
-+retry:
-+ if (!argowner) {
-+ if (oldowner != current) {
-+ /*
-+ * We raced against a concurrent self; things are
-+ * already fixed up. Nothing to do.
-+ */
-+ ret = 0;
-+ goto out_unlock;
-+ }
-+
-+ if (__rt_mutex_futex_trylock(&pi_state->pi_mutex)) {
-+ /* We got the lock after all, nothing to fix. */
-+ ret = 0;
-+ goto out_unlock;
-+ }
-+
-+ /*
-+ * Since we just failed the trylock; there must be an owner.
-+ */
-+ newowner = rt_mutex_owner(&pi_state->pi_mutex);
-+ BUG_ON(!newowner);
-+ } else {
-+ WARN_ON_ONCE(argowner != current);
-+ if (oldowner == current) {
-+ /*
-+ * We raced against a concurrent self; things are
-+ * already fixed up. Nothing to do.
-+ */
-+ ret = 0;
-+ goto out_unlock;
-+ }
-+ newowner = argowner;
-+ }
-+
-+ newtid = task_pid_vnr(newowner) | FUTEX_WAITERS;
-+ /* Owner died? */
-+ if (!pi_state->owner)
-+ newtid |= FUTEX_OWNER_DIED;
-+
-+ err = get_futex_value_locked(&uval, uaddr);
-+ if (err)
-+ goto handle_err;
-+
-+ for (;;) {
-+ newval = (uval & FUTEX_OWNER_DIED) | newtid;
-+
-+ err = cmpxchg_futex_value_locked(&curval, uaddr, uval, newval);
-+ if (err)
-+ goto handle_err;
-+
-+ if (curval == uval)
++ case 'h':
++ usage(basename(argv[0]));
++ exit(0);
++ case 'v':
++ log_verbosity(atoi(optarg));
+ break;
-+ uval = curval;
-+ }
-+
-+ /*
-+ * We fixed up user space. Now we need to fix the pi_state
-+ * itself.
-+ */
-+ if (pi_state->owner != NULL) {
-+ raw_spin_lock(&pi_state->owner->pi_lock);
-+ WARN_ON(list_empty(&pi_state->list));
-+ list_del_init(&pi_state->list);
-+ raw_spin_unlock(&pi_state->owner->pi_lock);
-+ }
-+
-+ pi_state->owner = newowner;
-+
-+ raw_spin_lock(&newowner->pi_lock);
-+ WARN_ON(!list_empty(&pi_state->list));
-+ list_add(&pi_state->list, &newowner->pi_state_list);
-+ raw_spin_unlock(&newowner->pi_lock);
-+ raw_spin_unlock_irq(&pi_state->pi_mutex.wait_lock);
-+
-+ return 0;
-+
-+ /*
-+ * In order to reschedule or handle a page fault, we need to drop the
-+ * locks here. In the case of a fault, this gives the other task
-+ * (either the highest priority waiter itself or the task which stole
-+ * the rtmutex) the chance to try the fixup of the pi_state. So once we
-+ * are back from handling the fault we need to check the pi_state after
-+ * reacquiring the locks and before trying to do another fixup. When
-+ * the fixup has been done already we simply return.
-+ *
-+ * Note: we hold both hb->lock and pi_mutex->wait_lock. We can safely
-+ * drop hb->lock since the caller owns the hb -> futex_q relation.
-+ * Dropping the pi_mutex->wait_lock requires the state revalidate.
-+ */
-+handle_err:
-+ raw_spin_unlock_irq(&pi_state->pi_mutex.wait_lock);
-+ spin_unlock(q->lock_ptr);
-+
-+ switch (err) {
-+ case -EFAULT:
-+ ret = fault_in_user_writeable(uaddr);
-+ break;
-+
-+ case -EAGAIN:
-+ cond_resched();
-+ ret = 0;
-+ break;
-+
-+ default:
-+ WARN_ON_ONCE(1);
-+ ret = err;
-+ break;
-+ }
-+
-+ spin_lock(q->lock_ptr);
-+ raw_spin_lock_irq(&pi_state->pi_mutex.wait_lock);
-+
-+ /*
-+ * Check if someone else fixed it for us:
-+ */
-+ if (pi_state->owner != oldowner) {
-+ ret = 0;
-+ goto out_unlock;
-+ }
-+
-+ if (ret)
-+ goto out_unlock;
-+
-+ goto retry;
-+
-+out_unlock:
-+ raw_spin_unlock_irq(&pi_state->pi_mutex.wait_lock);
-+ return ret;
-+}
-+
-+static long futex_wait_restart(struct restart_block *restart);
-+
-+/**
-+ * fixup_owner() - Post lock pi_state and corner case management
-+ * @uaddr: user address of the futex
-+ * @q: futex_q (contains pi_state and access to the rt_mutex)
-+ * @locked: if the attempt to take the rt_mutex succeeded (1) or not (0)
-+ *
-+ * After attempting to lock an rt_mutex, this function is called to cleanup
-+ * the pi_state owner as well as handle race conditions that may allow us to
-+ * acquire the lock. Must be called with the hb lock held.
-+ *
-+ * Return:
-+ * - 1 - success, lock taken;
-+ * - 0 - success, lock not taken;
-+ * - <0 - on error (-EFAULT)
-+ */
-+static int fixup_owner(u32 __user *uaddr, struct futex_q *q, int locked)
-+{
-+ int ret = 0;
-+
-+ if (locked) {
-+ /*
-+ * Got the lock. We might not be the anticipated owner if we
-+ * did a lock-steal - fix up the PI-state in that case:
-+ *
-+ * Speculative pi_state->owner read (we don't hold wait_lock);
-+ * since we own the lock pi_state->owner == current is the
-+ * stable state, anything else needs more attention.
-+ */
-+ if (q->pi_state->owner != current)
-+ ret = fixup_pi_state_owner(uaddr, q, current);
-+ return ret ? ret : locked;
-+ }
-+
-+ /*
-+ * If we didn't get the lock; check if anybody stole it from us. In
-+ * that case, we need to fix up the uval to point to them instead of
-+ * us, otherwise bad things happen. [10]
-+ *
-+ * Another speculative read; pi_state->owner == current is unstable
-+ * but needs our attention.
-+ */
-+ if (q->pi_state->owner == current) {
-+ ret = fixup_pi_state_owner(uaddr, q, NULL);
-+ return ret;
-+ }
-+
-+ /*
-+ * Paranoia check. If we did not take the lock, then we should not be
-+ * the owner of the rt_mutex.
-+ */
-+ if (rt_mutex_owner(&q->pi_state->pi_mutex) == current) {
-+ printk(KERN_ERR "fixup_owner: ret = %d pi-mutex: %p "
-+ "pi-state %p\n", ret,
-+ q->pi_state->pi_mutex.owner,
-+ q->pi_state->owner);
-+ }
-+
-+ return ret;
-+}
-+
-+/**
-+ * futex_wait_queue_me() - queue_me() and wait for wakeup, timeout, or signal
-+ * @hb: the futex hash bucket, must be locked by the caller
-+ * @q: the futex_q to queue up on
-+ * @timeout: the prepared hrtimer_sleeper, or null for no timeout
-+ */
-+static void futex_wait_queue_me(struct futex_hash_bucket *hb, struct futex_q *q,
-+ struct hrtimer_sleeper *timeout)
-+{
-+ /*
-+ * The task state is guaranteed to be set before another task can
-+ * wake it. set_current_state() is implemented using smp_store_mb() and
-+ * queue_me() calls spin_unlock() upon completion, both serializing
-+ * access to the hash list and forcing another memory barrier.
-+ */
-+ set_current_state(TASK_INTERRUPTIBLE);
-+ queue_me(q, hb);
-+
-+ /* Arm the timer */
-+ if (timeout)
-+ hrtimer_sleeper_start_expires(timeout, HRTIMER_MODE_ABS);
-+
-+ /*
-+ * If we have been removed from the hash list, then another task
-+ * has tried to wake us, and we can skip the call to schedule().
-+ */
-+ if (likely(!plist_node_empty(&q->list))) {
-+ /*
-+ * If the timer has already expired, current will already be
-+ * flagged for rescheduling. Only call schedule if there
-+ * is no timeout, or if it has yet to expire.
-+ */
-+ if (!timeout || timeout->task)
-+ freezable_schedule();
-+ }
-+ __set_current_state(TASK_RUNNING);
-+}
-+
-+/**
-+ * futex_wait_setup() - Prepare to wait on a futex
-+ * @uaddr: the futex userspace address
-+ * @val: the expected value
-+ * @flags: futex flags (FLAGS_SHARED, etc.)
-+ * @q: the associated futex_q
-+ * @hb: storage for hash_bucket pointer to be returned to caller
-+ *
-+ * Setup the futex_q and locate the hash_bucket. Get the futex value and
-+ * compare it with the expected value. Handle atomic faults internally.
-+ * Return with the hb lock held and a q.key reference on success, and unlocked
-+ * with no q.key reference on failure.
-+ *
-+ * Return:
-+ * - 0 - uaddr contains val and hb has been locked;
-+ * - <1 - -EFAULT or -EWOULDBLOCK (uaddr does not contain val) and hb is unlocked
-+ */
-+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;
-+
-+ /*
-+ * Access the page AFTER the hash-bucket is locked.
-+ * Order is important:
-+ *
-+ * Userspace waiter: val = var; if (cond(val)) futex_wait(&var, val);
-+ * Userspace waker: if (cond(var)) { var = new; futex_wake(&var); }
-+ *
-+ * The basic logical guarantee of a futex is that it blocks ONLY
-+ * if cond(var) is known to be true at the time of blocking, for
-+ * any cond. If we locked the hash-bucket after testing *uaddr, that
-+ * would open a race condition where we could block indefinitely with
-+ * cond(var) false, which would violate the guarantee.
-+ *
-+ * On the other hand, we insert q and release the hash-bucket only
-+ * after testing *uaddr. This guarantees that futex_wait() will NOT
-+ * 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;
-+
-+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;
-+
-+ goto retry;
-+ }
-+
-+ if (uval != val) {
-+ queue_unlock(*hb);
-+ ret = -EWOULDBLOCK;
-+ }
-+
-+ return ret;
-+}
-+
-+static int futex_wait(u32 __user *uaddr, unsigned int flags, u32 val,
-+ ktime_t *abs_time, u32 bitset)
-+{
-+ struct hrtimer_sleeper timeout, *to;
-+ struct restart_block *restart;
-+ struct futex_hash_bucket *hb;
-+ struct futex_q q = futex_q_init;
-+ int ret;
-+
-+ if (!bitset)
-+ return -EINVAL;
-+ q.bitset = bitset;
-+
-+ to = futex_setup_timer(abs_time, &timeout, flags,
-+ current->timer_slack_ns);
-+retry:
-+ /*
-+ * Prepare to wait on uaddr. On success, holds hb lock and increments
-+ * q.key refs.
-+ */
-+ ret = futex_wait_setup(uaddr, val, flags, &q, &hb);
-+ if (ret)
-+ goto out;
-+
-+ /* queue_me and wait for wakeup, timeout, or a signal. */
-+ futex_wait_queue_me(hb, &q, to);
-+
-+ /* If we were woken (and unqueued), we succeeded, whatever. */
-+ ret = 0;
-+ /* unqueue_me() drops q.key ref */
-+ if (!unqueue_me(&q))
-+ goto out;
-+ ret = -ETIMEDOUT;
-+ if (to && !to->task)
-+ goto out;
-+
-+ /*
-+ * 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;
-+
-+ restart = &current->restart_block;
-+ restart->fn = futex_wait_restart;
-+ restart->futex.uaddr = uaddr;
-+ restart->futex.val = val;
-+ restart->futex.time = *abs_time;
-+ restart->futex.bitset = bitset;
-+ restart->futex.flags = flags | FLAGS_HAS_TIMEOUT;
-+
-+ ret = -ERESTART_RESTARTBLOCK;
-+
-+out:
-+ if (to) {
-+ hrtimer_cancel(&to->timer);
-+ destroy_hrtimer_on_stack(&to->timer);
-+ }
-+ return ret;
-+}
-+
-+
-+static long futex_wait_restart(struct restart_block *restart)
-+{
-+ u32 __user *uaddr = restart->futex.uaddr;
-+ ktime_t t, *tp = NULL;
-+
-+ if (restart->futex.flags & FLAGS_HAS_TIMEOUT) {
-+ t = restart->futex.time;
-+ tp = &t;
-+ }
-+ restart->fn = do_no_restart_syscall;
-+
-+ return (long)futex_wait(uaddr, restart->futex.flags,
-+ restart->futex.val, tp, restart->futex.bitset);
-+}
-+
-+
-+/*
-+ * Userspace tried a 0 -> TID atomic transition of the futex value
-+ * and failed. The kernel side here does the whole locking operation:
-+ * if there are waiters then it will block as a consequence of relying
-+ * on rt-mutexes, it does PI, etc. (Due to races the kernel might see
-+ * a 0 value of the futex too.).
-+ *
-+ * Also serves as futex trylock_pi()'ing, and due semantics.
-+ */
-+static int futex_lock_pi(u32 __user *uaddr, unsigned int flags,
-+ ktime_t *time, int trylock)
-+{
-+ struct hrtimer_sleeper timeout, *to;
-+ struct futex_pi_state *pi_state = NULL;
-+ struct task_struct *exiting = NULL;
-+ struct rt_mutex_waiter rt_waiter;
-+ struct futex_hash_bucket *hb;
-+ struct futex_q q = futex_q_init;
-+ int res, ret;
-+
-+ if (!IS_ENABLED(CONFIG_FUTEX_PI))
-+ return -ENOSYS;
-+
-+ if (refill_pi_state_cache())
-+ return -ENOMEM;
-+
-+ to = futex_setup_timer(time, &timeout, FLAGS_CLOCKRT, 0);
-+
-+retry:
-+ ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &q.key, FUTEX_WRITE);
-+ if (unlikely(ret != 0))
-+ goto out;
-+
-+retry_private:
-+ hb = queue_lock(&q);
-+
-+ ret = futex_lock_pi_atomic(uaddr, hb, &q.key, &q.pi_state, current,
-+ &exiting, 0);
-+ if (unlikely(ret)) {
-+ /*
-+ * Atomic work succeeded and we got the lock,
-+ * or failed. Either way, we do _not_ block.
-+ */
-+ switch (ret) {
-+ case 1:
-+ /* We got the lock. */
-+ ret = 0;
-+ goto out_unlock_put_key;
-+ case -EFAULT:
-+ goto uaddr_faulted;
-+ case -EBUSY:
-+ case -EAGAIN:
-+ /*
-+ * Two reasons for this:
-+ * - EBUSY: Task is exiting and we just wait for the
-+ * exit to complete.
-+ * - EAGAIN: The user space value changed.
-+ */
-+ queue_unlock(hb);
-+ /*
-+ * Handle the case where the owner is in the middle of
-+ * exiting. Wait for the exit to complete otherwise
-+ * this task might loop forever, aka. live lock.
-+ */
-+ wait_for_owner_exiting(ret, exiting);
-+ cond_resched();
-+ goto retry;
+ default:
-+ goto out_unlock_put_key;
++ usage(basename(argv[0]));
++ exit(1);
+ }
+ }
+
-+ WARN_ON(!q.pi_state);
-+
-+ /*
-+ * Only actually queue now that the atomic ops are done:
-+ */
-+ __queue_me(&q, hb);
-+
-+ if (trylock) {
-+ ret = rt_mutex_futex_trylock(&q.pi_state->pi_mutex);
-+ /* Fixup the trylock return value: */
-+ ret = ret ? 0 : -EWOULDBLOCK;
-+ goto no_block;
-+ }
-+
-+ rt_mutex_init_waiter(&rt_waiter);
-+
-+ /*
-+ * On PREEMPT_RT_FULL, when hb->lock becomes an rt_mutex, we must not
-+ * hold it while doing rt_mutex_start_proxy(), because then it will
-+ * include hb->lock in the blocking chain, even through we'll not in
-+ * fact hold it while blocking. This will lead it to report -EDEADLK
-+ * and BUG when futex_unlock_pi() interleaves with this.
-+ *
-+ * Therefore acquire wait_lock while holding hb->lock, but drop the
-+ * latter before calling __rt_mutex_start_proxy_lock(). This
-+ * interleaves with futex_unlock_pi() -- which does a similar lock
-+ * handoff -- such that the latter can observe the futex_q::pi_state
-+ * before __rt_mutex_start_proxy_lock() is done.
-+ */
-+ raw_spin_lock_irq(&q.pi_state->pi_mutex.wait_lock);
-+ spin_unlock(q.lock_ptr);
-+ /*
-+ * __rt_mutex_start_proxy_lock() unconditionally enqueues the @rt_waiter
-+ * such that futex_unlock_pi() is guaranteed to observe the waiter when
-+ * it sees the futex_q::pi_state.
-+ */
-+ ret = __rt_mutex_start_proxy_lock(&q.pi_state->pi_mutex, &rt_waiter, current);
-+ raw_spin_unlock_irq(&q.pi_state->pi_mutex.wait_lock);
-+
-+ if (ret) {
-+ if (ret == 1)
-+ ret = 0;
-+ goto cleanup;
-+ }
-+
-+ if (unlikely(to))
-+ hrtimer_sleeper_start_expires(to, HRTIMER_MODE_ABS);
-+
-+ ret = rt_mutex_wait_proxy_lock(&q.pi_state->pi_mutex, to, &rt_waiter);
-+
-+cleanup:
-+ spin_lock(q.lock_ptr);
-+ /*
-+ * If we failed to acquire the lock (deadlock/signal/timeout), we must
-+ * first acquire the hb->lock before removing the lock from the
-+ * rt_mutex waitqueue, such that we can keep the hb and rt_mutex wait
-+ * lists consistent.
-+ *
-+ * In particular; it is important that futex_unlock_pi() can not
-+ * observe this inconsistency.
-+ */
-+ if (ret && !rt_mutex_cleanup_proxy_lock(&q.pi_state->pi_mutex, &rt_waiter))
-+ ret = 0;
-+
-+no_block:
-+ /*
-+ * Fixup the pi_state owner and possibly acquire the lock if we
-+ * haven't already.
-+ */
-+ res = fixup_owner(uaddr, &q, !ret);
-+ /*
-+ * If fixup_owner() returned an error, proprogate that. If it acquired
-+ * the lock, clear our -ETIMEDOUT or -EINTR.
-+ */
-+ if (res)
-+ ret = (res < 0) ? res : 0;
-+
-+ /*
-+ * If fixup_owner() faulted and was unable to handle the fault, unlock
-+ * it and return the fault to userspace.
-+ */
-+ if (ret && (rt_mutex_owner(&q.pi_state->pi_mutex) == current)) {
-+ pi_state = q.pi_state;
-+ get_pi_state(pi_state);
-+ }
-+
-+ /* Unqueue and drop the lock */
-+ unqueue_me_pi(&q);
-+
-+ if (pi_state) {
-+ rt_mutex_futex_unlock(&pi_state->pi_mutex);
-+ put_pi_state(pi_state);
-+ }
-+
-+ goto out;
-+
-+out_unlock_put_key:
-+ queue_unlock(hb);
++ ksft_print_header();
++ ksft_set_plan(2);
++ ksft_print_msg("%s: Test FUTEX2_WAITV\n",
++ basename(argv[0]));
+
-+out:
-+ if (to) {
-+ hrtimer_cancel(&to->timer);
-+ destroy_hrtimer_on_stack(&to->timer);
++ //info("Calling private futex2_wait on f1: %u @ %p with val=%u\n", *f1, f1, *f1);
++
++ for (i = 0; i < NR_FUTEXES; i++) {
++ waitv[i].uaddr = &futexes[i];
++ waitv[i].flags = FUTEX_32;
++ waitv[i].val = 0;
+ }
-+ return ret != -EINTR ? ret : -ERESTARTNOINTR;
-+
-+uaddr_faulted:
-+ queue_unlock(hb);
-+
-+ ret = fault_in_user_writeable(uaddr);
-+ if (ret)
-+ goto out;
-+
-+ if (!(flags & FLAGS_SHARED))
-+ goto retry_private;
+
-+ goto retry;
-+}
-+
-+/*
-+ * Userspace attempted a TID -> 0 atomic transition, and failed.
-+ * This is the in-kernel slowpath: we look up the PI state (if any),
-+ * and do the rt-mutex unlock.
-+ */
-+static int futex_unlock_pi(u32 __user *uaddr, unsigned int flags)
-+{
-+ u32 curval, uval, vpid = task_pid_vnr(current);
-+ union futex_key key = FUTEX_KEY_INIT;
-+ struct futex_hash_bucket *hb;
-+ struct futex_q *top_waiter;
-+ int ret;
-+
-+ if (!IS_ENABLED(CONFIG_FUTEX_PI))
-+ return -ENOSYS;
-+
-+retry:
-+ if (get_user(uval, uaddr))
-+ return -EFAULT;
-+ /*
-+ * We release only a lock we actually own:
-+ */
-+ if ((uval & FUTEX_TID_MASK) != vpid)
-+ return -EPERM;
-+
-+ ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key, FUTEX_WRITE);
-+ if (ret)
-+ return ret;
-+
-+ hb = hash_futex(&key);
-+ spin_lock(&hb->lock);
-+
-+ /*
-+ * Check waiters first. We do not trust user space values at
-+ * all and we at least want to know if user space fiddled
-+ * with the futex value instead of blindly unlocking.
-+ */
-+ top_waiter = futex_top_waiter(hb, &key);
-+ if (top_waiter) {
-+ struct futex_pi_state *pi_state = top_waiter->pi_state;
-+
-+ ret = -EINVAL;
-+ if (!pi_state)
-+ goto out_unlock;
-+
-+ /*
-+ * If current does not own the pi_state then the futex is
-+ * inconsistent and user space fiddled with the futex value.
-+ */
-+ if (pi_state->owner != current)
-+ goto out_unlock;
-+
-+ get_pi_state(pi_state);
-+ /*
-+ * By taking wait_lock while still holding hb->lock, we ensure
-+ * there is no point where we hold neither; and therefore
-+ * wake_futex_pi() must observe a state consistent with what we
-+ * observed.
-+ *
-+ * In particular; this forces __rt_mutex_start_proxy() to
-+ * complete such that we're guaranteed to observe the
-+ * rt_waiter. Also see the WARN in wake_futex_pi().
-+ */
-+ raw_spin_lock_irq(&pi_state->pi_mutex.wait_lock);
-+ spin_unlock(&hb->lock);
-+
-+ /* drops pi_state->pi_mutex.wait_lock */
-+ ret = wake_futex_pi(uaddr, uval, pi_state);
++ if (pthread_create(&waiter, NULL, waiterfn, NULL))
++ error("pthread_create failed\n", errno);
+
-+ put_pi_state(pi_state);
++ usleep(WAKE_WAIT_US);
+
-+ /*
-+ * Success, we're done! No tricky corner cases.
-+ */
-+ if (!ret)
-+ goto out_putkey;
-+ /*
-+ * The atomic access to the futex value generated a
-+ * pagefault, so retry the user-access and the wakeup:
-+ */
-+ if (ret == -EFAULT)
-+ goto pi_faulted;
-+ /*
-+ * A unconditional UNLOCK_PI op raced against a waiter
-+ * setting the FUTEX_WAITERS bit. Try again.
-+ */
-+ if (ret == -EAGAIN)
-+ goto pi_retry;
-+ /*
-+ * wake_futex_pi has detected invalid state. Tell user
-+ * space.
-+ */
-+ goto out_putkey;
++ // info("Calling private futex2_wake on f1: %u @ %p with val=%u\n", *f1, f1, *f1);
++ res = futex2_wake(waitv[NR_FUTEXES - 1].uaddr, 1, FUTEX_32);
++ if (res != 1) {
++ ksft_test_result_fail("futex2_wake private returned: %d %s\n",
++ res ? errno : res,
++ res ? strerror(errno) : "");
++ ret = RET_FAIL;
++ } else {
++ ksft_test_result_pass("futex2_waitv private succeeds\n");
+ }
+
-+ /*
-+ * We have no kernel internal state, i.e. no waiters in the
-+ * kernel. Waiters which are about to queue themselves are stuck
-+ * on hb->lock. So we can safely ignore them. We do neither
-+ * preserve the WAITERS bit not the OWNER_DIED one. We are the
-+ * owner.
-+ */
-+ if ((ret = cmpxchg_futex_value_locked(&curval, uaddr, uval, 0))) {
-+ spin_unlock(&hb->lock);
-+ switch (ret) {
-+ case -EFAULT:
-+ goto pi_faulted;
-+
-+ case -EAGAIN:
-+ goto pi_retry;
-+
-+ default:
-+ WARN_ON_ONCE(1);
-+ goto out_putkey;
++ for (i = 0; i < NR_FUTEXES; i++) {
++ int shm_id = shmget(IPC_PRIVATE, 4096, IPC_CREAT | 0666);
++ if (shm_id < 0) {
++ perror("shmget");
++ exit(1);
+ }
-+ }
-+
-+ /*
-+ * If uval has changed, let user space handle it.
-+ */
-+ ret = (curval == uval) ? 0 : -EAGAIN;
-+
-+out_unlock:
-+ spin_unlock(&hb->lock);
-+out_putkey:
-+ return ret;
-+
-+pi_retry:
-+ cond_resched();
-+ goto retry;
-+
-+pi_faulted:
-+
-+ ret = fault_in_user_writeable(uaddr);
-+ if (!ret)
-+ goto retry;
-+
-+ return ret;
-+}
-+
-+/**
-+ * handle_early_requeue_pi_wakeup() - Detect early wakeup on the initial futex
-+ * @hb: the hash_bucket futex_q was original enqueued on
-+ * @q: the futex_q woken while waiting to be requeued
-+ * @key2: the futex_key of the requeue target futex
-+ * @timeout: the timeout associated with the wait (NULL if none)
-+ *
-+ * Detect if the task was woken on the initial futex as opposed to the requeue
-+ * target futex. If so, determine if it was a timeout or a signal that caused
-+ * the wakeup and return the appropriate error code to the caller. Must be
-+ * called with the hb lock held.
-+ *
-+ * Return:
-+ * - 0 = no early wakeup detected;
-+ * - <0 = -ETIMEDOUT or -ERESTARTNOINTR
-+ */
-+static inline
-+int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb,
-+ struct futex_q *q, union futex_key *key2,
-+ struct hrtimer_sleeper *timeout)
-+{
-+ int ret = 0;
-+
-+ /*
-+ * With the hb lock held, we avoid races while we process the wakeup.
-+ * We only need to hold hb (and not hb2) to ensure atomicity as the
-+ * wakeup code can't change q.key from uaddr to uaddr2 if we hold hb.
-+ * It can't be requeued from uaddr2 to something else since we don't
-+ * support a PI aware source futex for requeue.
-+ */
-+ if (!match_futex(&q->key, key2)) {
-+ WARN_ON(q->lock_ptr && (&hb->lock != q->lock_ptr));
-+ /*
-+ * We were woken prior to requeue by a timeout or a signal.
-+ * Unqueue the futex_q and determine which it was.
-+ */
-+ plist_del(&q->list, &hb->chain);
-+ hb_waiters_dec(hb);
-+
-+ /* Handle spurious wakeups gracefully */
-+ ret = -EWOULDBLOCK;
-+ if (timeout && !timeout->task)
-+ ret = -ETIMEDOUT;
-+ else if (signal_pending(current))
-+ ret = -ERESTARTNOINTR;
-+ }
-+ return ret;
-+}
-+
-+/**
-+ * futex_wait_requeue_pi() - Wait on uaddr and take uaddr2
-+ * @uaddr: the futex we initially wait on (non-pi)
-+ * @flags: futex flags (FLAGS_SHARED, FLAGS_CLOCKRT, etc.), they must be
-+ * the same type, no requeueing from private to shared, etc.
-+ * @val: the expected value of uaddr
-+ * @abs_time: absolute timeout
-+ * @bitset: 32 bit wakeup bitset set by userspace, defaults to all
-+ * @uaddr2: the pi futex we will take prior to returning to user-space
-+ *
-+ * The caller will wait on uaddr and will be requeued by futex_requeue() to
-+ * uaddr2 which must be PI aware and unique from uaddr. Normal wakeup will wake
-+ * on uaddr2 and complete the acquisition of the rt_mutex prior to returning to
-+ * userspace. This ensures the rt_mutex maintains an owner when it has waiters;
-+ * without one, the pi logic would not know which task to boost/deboost, if
-+ * there was a need to.
-+ *
-+ * We call schedule in futex_wait_queue_me() when we enqueue and return there
-+ * via the following--
-+ * 1) wakeup on uaddr2 after an atomic lock acquisition by futex_requeue()
-+ * 2) wakeup on uaddr2 after a requeue
-+ * 3) signal
-+ * 4) timeout
-+ *
-+ * If 3, cleanup and return -ERESTARTNOINTR.
-+ *
-+ * If 2, we may then block on trying to take the rt_mutex and return via:
-+ * 5) successful lock
-+ * 6) signal
-+ * 7) timeout
-+ * 8) other lock acquisition failure
-+ *
-+ * If 6, return -EWOULDBLOCK (restarting the syscall would do the same).
-+ *
-+ * If 4 or 7, we cleanup and return with -ETIMEDOUT.
-+ *
-+ * Return:
-+ * - 0 - On success;
-+ * - <0 - On error
-+ */
-+static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
-+ u32 val, ktime_t *abs_time, u32 bitset,
-+ u32 __user *uaddr2)
-+{
-+ struct hrtimer_sleeper timeout, *to;
-+ struct futex_pi_state *pi_state = NULL;
-+ struct rt_mutex_waiter rt_waiter;
-+ struct futex_hash_bucket *hb;
-+ union futex_key key2 = FUTEX_KEY_INIT;
-+ struct futex_q q = futex_q_init;
-+ int res, ret;
-+
-+ if (!IS_ENABLED(CONFIG_FUTEX_PI))
-+ return -ENOSYS;
-+
-+ if (uaddr == uaddr2)
-+ return -EINVAL;
-+
-+ if (!bitset)
-+ return -EINVAL;
+
-+ to = futex_setup_timer(abs_time, &timeout, flags,
-+ current->timer_slack_ns);
-+
-+ /*
-+ * The waiter is allocated on our stack, manipulated by the requeue
-+ * code while we sleep on uaddr.
-+ */
-+ rt_mutex_init_waiter(&rt_waiter);
-+
-+ ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2, FUTEX_WRITE);
-+ if (unlikely(ret != 0))
-+ goto out;
-+
-+ q.bitset = bitset;
-+ q.rt_waiter = &rt_waiter;
-+ q.requeue_pi_key = &key2;
-+
-+ /*
-+ * Prepare to wait on uaddr. On success, increments q.key (key1) ref
-+ * count.
-+ */
-+ ret = futex_wait_setup(uaddr, val, flags, &q, &hb);
-+ if (ret)
-+ goto out;
++ unsigned int *shared_data = shmat(shm_id, NULL, 0);
++ *shared_data = 0;
+
-+ /*
-+ * The check above which compares uaddrs is not sufficient for
-+ * shared futexes. We need to compare the keys:
-+ */
-+ if (match_futex(&q.key, &key2)) {
-+ queue_unlock(hb);
-+ ret = -EINVAL;
-+ goto out;
++ waitv[i].uaddr = shared_data;
++ waitv[i].flags = FUTEX_32 | FUTEX_SHARED_FLAG;
++ waitv[i].val = 0;
+ }
+
-+ /* Queue the futex_q, drop the hb lock, wait for wakeup. */
-+ futex_wait_queue_me(hb, &q, to);
++ //info("Calling shared futex2_wait on f1: %u @ %p with val=%u\n", *f1, f1, *f1);
+
-+ spin_lock(&hb->lock);
-+ ret = handle_early_requeue_pi_wakeup(hb, &q, &key2, to);
-+ spin_unlock(&hb->lock);
-+ if (ret)
-+ goto out;
++ if (pthread_create(&waiter, NULL, waiterfn, NULL))
++ error("pthread_create failed\n", errno);
+
-+ /*
-+ * In order for us to be here, we know our q.key == key2, and since
-+ * we took the hb->lock above, we also know that futex_requeue() has
-+ * completed and we no longer have to concern ourselves with a wakeup
-+ * race with the atomic proxy lock acquisition by the requeue code. The
-+ * futex_requeue dropped our key1 reference and incremented our key2
-+ * reference count.
-+ */
++ usleep(WAKE_WAIT_US);
+
-+ /* Check if the requeue code acquired the second futex for us. */
-+ if (!q.rt_waiter) {
-+ /*
-+ * Got the lock. We might not be the anticipated owner if we
-+ * did a lock-steal - fix up the PI-state in that case.
-+ */
-+ if (q.pi_state && (q.pi_state->owner != current)) {
-+ spin_lock(q.lock_ptr);
-+ ret = fixup_pi_state_owner(uaddr2, &q, current);
-+ if (ret && rt_mutex_owner(&q.pi_state->pi_mutex) == current) {
-+ pi_state = q.pi_state;
-+ get_pi_state(pi_state);
-+ }
-+ /*
-+ * Drop the reference to the pi state which
-+ * the requeue_pi() code acquired for us.
-+ */
-+ put_pi_state(q.pi_state);
-+ spin_unlock(q.lock_ptr);
-+ }
++ // info("Calling shared futex2_wake on f1: %u @ %p with val=%u\n", *f1, f1, *f1);
++ res = futex2_wake(waitv[NR_FUTEXES - 1].uaddr, 1, FUTEX_32 | FUTEX_SHARED_FLAG);
++ if (res != 1) {
++ ksft_test_result_fail("futex2_wake shared returned: %d %s\n",
++ res ? errno : res,
++ res ? strerror(errno) : "");
++ ret = RET_FAIL;
+ } else {
-+ struct rt_mutex *pi_mutex;
-+
-+ /*
-+ * We have been woken up by futex_unlock_pi(), a timeout, or a
-+ * signal. futex_unlock_pi() will not destroy the lock_ptr nor
-+ * the pi_state.
-+ */
-+ WARN_ON(!q.pi_state);
-+ pi_mutex = &q.pi_state->pi_mutex;
-+ ret = rt_mutex_wait_proxy_lock(pi_mutex, to, &rt_waiter);
-+
-+ spin_lock(q.lock_ptr);
-+ if (ret && !rt_mutex_cleanup_proxy_lock(pi_mutex, &rt_waiter))
-+ ret = 0;
-+
-+ debug_rt_mutex_free_waiter(&rt_waiter);
-+ /*
-+ * Fixup the pi_state owner and possibly acquire the lock if we
-+ * haven't already.
-+ */
-+ res = fixup_owner(uaddr2, &q, !ret);
-+ /*
-+ * If fixup_owner() returned an error, proprogate that. If it
-+ * acquired the lock, clear -ETIMEDOUT or -EINTR.
-+ */
-+ if (res)
-+ ret = (res < 0) ? res : 0;
-+
-+ /*
-+ * If fixup_pi_state_owner() faulted and was unable to handle
-+ * the fault, unlock the rt_mutex and return the fault to
-+ * userspace.
-+ */
-+ if (ret && rt_mutex_owner(&q.pi_state->pi_mutex) == current) {
-+ pi_state = q.pi_state;
-+ get_pi_state(pi_state);
-+ }
-+
-+ /* Unqueue and drop the lock. */
-+ unqueue_me_pi(&q);
-+ }
-+
-+ if (pi_state) {
-+ rt_mutex_futex_unlock(&pi_state->pi_mutex);
-+ put_pi_state(pi_state);
++ ksft_test_result_pass("futex2_wake shared succeeds\n");
+ }
+
-+ if (ret == -EINTR) {
-+ /*
-+ * We've already been requeued, but cannot restart by calling
-+ * futex_lock_pi() directly. We could restart this syscall, but
-+ * it would detect that the user space "val" changed and return
-+ * -EWOULDBLOCK. Save the overhead of the restart and return
-+ * -EWOULDBLOCK directly.
-+ */
-+ ret = -EWOULDBLOCK;
-+ }
++ for (i = 0; i < NR_FUTEXES; i++)
++ shmdt(waitv[i].uaddr);
+
-+out:
-+ if (to) {
-+ hrtimer_cancel(&to->timer);
-+ destroy_hrtimer_on_stack(&to->timer);
-+ }
++ ksft_print_cnts();
+ return ret;
+}
-+
-+static long do_futex1(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
-+ u32 __user *uaddr2, u32 val2, u32 val3)
-+{
-+ int cmd = op & FUTEX_CMD_MASK;
-+ unsigned int flags = 0;
-+
-+ if (!(op & FUTEX_PRIVATE_FLAG))
-+ flags |= FLAGS_SHARED;
-+
-+ if (op & FUTEX_CLOCK_REALTIME) {
-+ flags |= FLAGS_CLOCKRT;
-+ if (cmd != FUTEX_WAIT && cmd != FUTEX_WAIT_BITSET && \
-+ cmd != FUTEX_WAIT_REQUEUE_PI)
-+ return -ENOSYS;
-+ }
-+
-+ switch (cmd) {
-+ case FUTEX_LOCK_PI:
-+ case FUTEX_UNLOCK_PI:
-+ case FUTEX_TRYLOCK_PI:
-+ case FUTEX_WAIT_REQUEUE_PI:
-+ case FUTEX_CMP_REQUEUE_PI:
-+ if (!futex_cmpxchg_enabled)
-+ return -ENOSYS;
-+ }
-+
-+ switch (cmd) {
-+ case FUTEX_WAIT:
-+ val3 = FUTEX_BITSET_MATCH_ANY;
-+ fallthrough;
-+ case FUTEX_WAIT_BITSET:
-+ return futex_wait(uaddr, flags, val, timeout, val3);
-+ case FUTEX_WAKE:
-+ val3 = FUTEX_BITSET_MATCH_ANY;
-+ fallthrough;
-+ case FUTEX_WAKE_BITSET:
-+ return futex_wake(uaddr, flags, val, val3);
-+ case FUTEX_REQUEUE:
-+ return futex_requeue(uaddr, flags, uaddr2, val, val2, NULL, 0);
-+ case FUTEX_CMP_REQUEUE:
-+ return futex_requeue(uaddr, flags, uaddr2, val, val2, &val3, 0);
-+ case FUTEX_WAKE_OP:
-+ return futex_wake_op(uaddr, flags, uaddr2, val, val2, val3);
-+ case FUTEX_LOCK_PI:
-+ return futex_lock_pi(uaddr, flags, timeout, 0);
-+ case FUTEX_UNLOCK_PI:
-+ return futex_unlock_pi(uaddr, flags);
-+ case FUTEX_TRYLOCK_PI:
-+ return futex_lock_pi(uaddr, flags, NULL, 1);
-+ case FUTEX_WAIT_REQUEUE_PI:
-+ val3 = FUTEX_BITSET_MATCH_ANY;
-+ return futex_wait_requeue_pi(uaddr, flags, val, timeout, val3,
-+ uaddr2);
-+ case FUTEX_CMP_REQUEUE_PI:
-+ return futex_requeue(uaddr, flags, uaddr2, val, val2, &val3, 1);
-+ }
-+ return -ENOSYS;
-+}
-+
-+
-+SYSCALL_DEFINE6(futex1, u32 __user *, uaddr, int, op, u32, val,
-+ struct __kernel_timespec __user *, utime, u32 __user *, uaddr2,
-+ u32, val3)
-+{
-+ struct timespec64 ts;
-+ ktime_t t, *tp = NULL;
-+ u32 val2 = 0;
-+ int cmd = op & FUTEX_CMD_MASK;
-+
-+ if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI ||
-+ cmd == FUTEX_WAIT_BITSET ||
-+ cmd == FUTEX_WAIT_REQUEUE_PI)) {
-+ if (unlikely(should_fail_futex(!(op & FUTEX_PRIVATE_FLAG))))
-+ return -EFAULT;
-+ if (get_timespec64(&ts, utime))
-+ return -EFAULT;
-+ if (!timespec64_valid(&ts))
-+ return -EINVAL;
-+
-+ t = timespec64_to_ktime(ts);
-+ if (cmd == FUTEX_WAIT)
-+ t = ktime_add_safe(ktime_get(), t);
-+ tp = &t;
-+ }
-+ /*
-+ * requeue parameter in 'utime' if cmd == FUTEX_*_REQUEUE_*.
-+ * number of waiters to wake in 'utime' if cmd == FUTEX_WAKE_OP.
-+ */
-+ if (cmd == FUTEX_REQUEUE || cmd == FUTEX_CMP_REQUEUE ||
-+ cmd == FUTEX_CMP_REQUEUE_PI || cmd == FUTEX_WAKE_OP)
-+ val2 = (u32) (unsigned long) utime;
-+
-+ return do_futex1(uaddr, op, val, tp, uaddr2, val2, val3);
-+}
-+
-+static void __init futex_detect_cmpxchg(void)
-+{
-+#ifndef CONFIG_HAVE_FUTEX_CMPXCHG
-+ u32 curval;
-+
-+ /*
-+ * This will fail and we want it. Some arch implementations do
-+ * runtime detection of the futex_atomic_cmpxchg_inatomic()
-+ * functionality. We want to know that before we call in any
-+ * of the complex code paths. Also we want to prevent
-+ * registration of robust lists in that case. NULL is
-+ * guaranteed to fault and we get -EFAULT on functional
-+ * implementation, the non-functional ones will return
-+ * -ENOSYS.
-+ */
-+ if (cmpxchg_futex_value_locked(&curval, NULL, 0, 0) == -EFAULT)
-+ futex_cmpxchg_enabled = 1;
-+#endif
-+}
-+
-+static int __init futex_init(void)
-+{
-+ unsigned int futex_shift;
-+ unsigned long i;
-+
-+#if CONFIG_BASE_SMALL
-+ futex_hashsize = 16;
-+#else
-+ futex_hashsize = roundup_pow_of_two(256 * num_possible_cpus());
-+#endif
-+
-+ futex_queues = alloc_large_system_hash("futex1", sizeof(*futex_queues),
-+ futex_hashsize, 0,
-+ futex_hashsize < 256 ? HASH_SMALL : 0,
-+ &futex_shift, NULL,
-+ futex_hashsize, futex_hashsize);
-+ futex_hashsize = 1UL << futex_shift;
-+
-+ futex_detect_cmpxchg();
-+
-+ for (i = 0; i < futex_hashsize; i++) {
-+ atomic_set(&futex_queues[i].waiters, 0);
-+ plist_head_init(&futex_queues[i].chain);
-+ spin_lock_init(&futex_queues[i].lock);
-+ }
-+
-+ return 0;
-+}
-+core_initcall(futex_init);
-diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
-index 3e1a713d3e57..b53a24a99a14 100644
---- a/kernel/sys_ni.c
-+++ b/kernel/sys_ni.c
-@@ -153,6 +153,8 @@ COND_SYSCALL(futex_wait);
- COND_SYSCALL(futex_wake);
- COND_SYSCALL(futex_waitv);
+diff --git a/tools/testing/selftests/futex/functional/run.sh b/tools/testing/selftests/futex/functional/run.sh
+index 3730159c8..18b3883d7 100755
+--- a/tools/testing/selftests/futex/functional/run.sh
++++ b/tools/testing/selftests/futex/functional/run.sh
+@@ -76,3 +76,6 @@ echo
-+COND_SYSCALL(futex1);
+ echo
+ ./futex2_wait $COLOR
+
- /* kernel/hrtimer.c */
-
- /* kernel/itimer.c */
-diff --git a/tools/arch/x86/include/asm/unistd_64.h b/tools/arch/x86/include/asm/unistd_64.h
-index 4205ed4158bf..43de5a59ac1c 100644
---- a/tools/arch/x86/include/asm/unistd_64.h
-+++ b/tools/arch/x86/include/asm/unistd_64.h
-@@ -17,3 +17,15 @@
- #ifndef __NR_setns
- #define __NR_setns 308
++echo
++./futex2_waitv $COLOR
+diff --git a/tools/testing/selftests/futex/include/futex2test.h b/tools/testing/selftests/futex/include/futex2test.h
+index 807b8b57f..10be0c504 100644
+--- a/tools/testing/selftests/futex/include/futex2test.h
++++ b/tools/testing/selftests/futex/include/futex2test.h
+@@ -27,10 +27,18 @@
+ #ifndef FUTEX_32
+ #define FUTEX_32 2
#endif
+-#ifdef __x86_64__
+-# ifndef FUTEX_64
+-# define FUTEX_64 3
+-# endif
+
-+#ifndef __NR_futex_wait
-+#define __NR_futex_wait 440
-+#endif
-+
-+#ifndef __NR_futex_wake
-+#define __NR_futex_wake 441
-+#endif
-+
-+#ifndef __NR_futex1
-+#define __NR_futex1 442
++#ifndef FUTEX_SHARED_FLAG
++#define FUTEX_SHARED_FLAG 8
+#endif
-diff --git a/tools/include/uapi/asm-generic/unistd.h b/tools/include/uapi/asm-generic/unistd.h
-index dd457de21bad..f737eaeecbb6 100644
---- a/tools/include/uapi/asm-generic/unistd.h
-+++ b/tools/include/uapi/asm-generic/unistd.h
-@@ -862,11 +862,15 @@ __SYSCALL(__NR_faccessat2, sys_faccessat2)
-
- #define __NR_futex_wait 440
- __SYSCALL(__NR_futex_wait, sys_futex_wait)
-+
- #define __NR_futex_wake 441
- __SYSCALL(__NR_futex_wake, sys_futex_wake)
-
-+#define __NR_futex1 442
-+__SYSCALL(__NR_futex1, sys_futex1)
+
- #undef __NR_syscalls
--#define __NR_syscalls 442
-+#define __NR_syscalls 443
++#ifndef FUTEX_WAITV_MAX
++#define FUTEX_WAITV_MAX 128
++struct futex_waitv {
++ void *uaddr;
++ unsigned int val;
++ unsigned int flags;
++};
+ #endif
/*
- * 32 bit systems traditionally used different
-diff --git a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl
-index f30d6ae9a688..1a516b081207 100644
---- a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl
-+++ b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl
-@@ -361,6 +361,9 @@
- 437 common openat2 sys_openat2
- 438 common pidfd_getfd sys_pidfd_getfd
- 439 common faccessat2 sys_faccessat2
-+440 common futex_wait sys_futex_wait
-+441 common futex_wake sys_futex_wake
-+442 common futex1 sys_futex1
-
- #
- # x32-specific system call numbers start at 512 to avoid cache impact
-diff --git a/tools/perf/bench/futex.h b/tools/perf/bench/futex.h
-index 31b53cc7d5bc..baf6a0d077ac 100644
---- a/tools/perf/bench/futex.h
-+++ b/tools/perf/bench/futex.h
-@@ -8,10 +8,14 @@
- #ifndef _FUTEX_H
- #define _FUTEX_H
-
-+//#define FUTEX1 0
-+#define UNUSED(x) (void)(x)
-+
- #include <unistd.h>
- #include <sys/syscall.h>
- #include <sys/types.h>
- #include <linux/futex.h>
-+#include <linux/unistd.h>
-
- /**
- * futex() - SYS_futex syscall wrapper
-@@ -34,7 +38,13 @@
- * like-named arguments in the following wrappers except where noted below.
- */
- #define futex(uaddr, op, val, timeout, uaddr2, val3, opflags) \
-- syscall(SYS_futex, uaddr, op | opflags, val, timeout, uaddr2, val3)
-+ syscall(__NR_futex1, uaddr, op | opflags, val, timeout, uaddr2, val3)
-+
-+#define futex2_wake(uaddr, nr, flags) \
-+ syscall(__NR_futex_wake, uaddr, nr, flags | FUTEX_32)
-+
-+#define futex2_wait(uaddr, val, flags, timeout) \
-+ syscall(__NR_futex_wait, uaddr, val, flags | FUTEX_32, timeout)
-
- /**
- * futex_wait() - block on uaddr with optional timeout
-@@ -43,7 +53,13 @@
- static inline int
- futex_wait(u_int32_t *uaddr, u_int32_t val, struct timespec *timeout, int opflags)
- {
-+#ifdef FUTEX1
- return futex(uaddr, FUTEX_WAIT, val, timeout, NULL, 0, opflags);
-+#else
-+ UNUSED(timeout);
-+ UNUSED(opflags);
-+ return futex2_wait(uaddr, val, 0, NULL);
-+#endif
- }
-
- /**
-@@ -53,7 +69,12 @@ futex_wait(u_int32_t *uaddr, u_int32_t val, struct timespec *timeout, int opflag
- static inline int
- futex_wake(u_int32_t *uaddr, int nr_wake, int opflags)
+@@ -75,3 +83,12 @@ static inline int futex2_wake(volatile void *uaddr, unsigned int nr, unsigned lo
{
-+#ifdef FUTEX1
- return futex(uaddr, FUTEX_WAKE, nr_wake, NULL, NULL, 0, opflags);
-+#else
-+ UNUSED(opflags);
-+ return futex2_wake(uaddr, nr_wake, 0);
-+#endif
+ return syscall(__NR_futex_wake, uaddr, nr, flags);
}
-
- /**
++
++/*
++ * wait for uaddr if (*uaddr == val)
++ */
++static inline int futex2_waitv(volatile struct futex_waitv *waiters, unsigned long nr_waiters,
++ unsigned long flags, struct timespec64 *timo)
++{
++ return syscall(__NR_futex_waitv, waiters, nr_waiters, flags, timo);
++}
--
-2.28.0
+2.29.2
+
-From 2f5e38a4191ac6fd5040435f6a41433add3711a6 Mon Sep 17 00:00:00 2001
+From 9358bbdf929a90bc144d13e002fed8f4223d3178 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9=20Almeida?= <andrealmeid@collabora.com>
-Date: Thu, 15 Oct 2020 18:06:40 -0300
-Subject: [PATCH 07/13] futex2: Add support for shared futexes
+Date: Fri, 4 Dec 2020 19:12:23 -0300
+Subject: [PATCH 8/9] futex2: Add sysfs entry for syscall numbers
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
-Add support for shared futexes for cross-process resources.
-
Signed-off-by: André Almeida <andrealmeid@collabora.com>
+Signed-off-by: Jan200101 <sentrycraft123@gmail.com>
---
- kernel/futex2.c | 169 +++++++++++++++++++++++++++++++++++++++++-------
- 1 file changed, 146 insertions(+), 23 deletions(-)
+ kernel/futex2.c | 42 ++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 42 insertions(+)
diff --git a/kernel/futex2.c b/kernel/futex2.c
-index 4b782b5ef615..ae743ddf223e 100644
+index 5ddb9922d..58cd8a868 100644
--- a/kernel/futex2.c
+++ b/kernel/futex2.c
-@@ -6,7 +6,9 @@
- */
-
- #include <linux/freezer.h>
-+#include <linux/hugetlb.h>
- #include <linux/jhash.h>
-+#include <linux/pagemap.h>
- #include <linux/sched/wake_q.h>
- #include <linux/spinlock.h>
- #include <linux/syscalls.h>
-@@ -15,6 +17,7 @@
-
- /**
- * struct futex_waiter - List entry for a waiter
-+ * @uaddr: Memory address of userspace futex
- * @key.address: Memory address of userspace futex
- * @key.mm: Pointer to memory management struct of this process
- * @key: Stores information that uniquely identify a futex
-@@ -25,6 +28,7 @@
- * @index: Index of waiter in futexv list
- */
- struct futex_waiter {
-+ uintptr_t uaddr;
- struct futex_key {
- uintptr_t address;
- struct mm_struct *mm;
-@@ -125,16 +129,109 @@ static inline int bucket_get_waiters(struct futex_bucket *bucket)
- #endif
+@@ -762,6 +762,48 @@ SYSCALL_DEFINE3(futex_wake, void __user *, uaddr, unsigned int, nr_wake,
+ return ret;
}
-+static u64 get_inode_sequence_number(struct inode *inode)
++static ssize_t wait_show(struct kobject *kobj, struct kobj_attribute *attr,
++ char *buf)
+{
-+ static atomic64_t i_seq;
-+ u64 old;
-+
-+ /* Does the inode already have a sequence number? */
-+ old = atomic64_read(&inode->i_sequence);
-+ if (likely(old))
-+ return old;
-+
-+ for (;;) {
-+ u64 new = atomic64_add_return(1, &i_seq);
-+ if (WARN_ON_ONCE(!new))
-+ continue;
++ return sprintf(buf, "%u\n", __NR_futex_wait);
+
-+ old = atomic64_cmpxchg_relaxed(&inode->i_sequence, 0, new);
-+ if (old)
-+ return old;
-+ return new;
-+ }
+}
++static struct kobj_attribute futex2_wait_attr = __ATTR_RO(wait);
+
-+static int futex_get_shared_key(uintptr_t address, struct mm_struct *mm,
-+ struct futex_key *key)
++static ssize_t wake_show(struct kobject *kobj, struct kobj_attribute *attr,
++ char *buf)
+{
-+ int err;
-+ struct page *page, *tail;
-+ struct address_space *mapping;
-+
-+again:
-+ err = get_user_pages_fast(address, 1, 0, &page);
-+
-+ if (err < 0)
-+ return err;
-+ else
-+ err = 0;
-+
-+
-+ tail = page;
-+ page = compound_head(page);
-+ mapping = READ_ONCE(page->mapping);
-+
-+
-+ if (unlikely(!mapping)) {
-+ int shmem_swizzled;
-+
-+ lock_page(page);
-+ shmem_swizzled = PageSwapCache(page) || page->mapping;
-+ unlock_page(page);
-+ put_page(page);
-+
-+ if (shmem_swizzled)
-+ goto again;
-+
-+ return -EFAULT;
-+ }
-+
-+ if (PageAnon(page)) {
-+
-+ key->mm = mm;
-+ key->address = address;
-+
-+ } else {
-+ struct inode *inode;
-+
-+ rcu_read_lock();
-+
-+ if (READ_ONCE(page->mapping) != mapping) {
-+ rcu_read_unlock();
-+ put_page(page);
-+
-+ goto again;
-+ }
-+
-+ inode = READ_ONCE(mapping->host);
-+ if (!inode) {
-+ rcu_read_unlock();
-+ put_page(page);
-+
-+ goto again;
-+ }
-+
-+ key->address = get_inode_sequence_number(inode);
-+ key->mm = (struct mm_struct *) basepage_index(tail);
-+ rcu_read_unlock();
-+ }
++ return sprintf(buf, "%u\n", __NR_futex_wake);
+
-+ put_page(page);
-+ return err;
+}
++static struct kobj_attribute futex2_wake_attr = __ATTR_RO(wake);
+
- /**
- * futex_get_bucket - Check if the user address is valid, prepare internal
- * data and calculate the hash
- * @uaddr: futex user address
- * @key: data that uniquely identifies a futex
-+ * @shared: is this a shared futex?
- *
- * Return: address of bucket on success, error code otherwise
- */
- static struct futex_bucket *futex_get_bucket(void __user *uaddr,
-- struct futex_key *key)
-+ struct futex_key *key,
-+ bool shared)
- {
- uintptr_t address = (uintptr_t) uaddr;
- u32 hash_key;
-@@ -145,8 +242,12 @@ static struct futex_bucket *futex_get_bucket(void __user *uaddr,
- if (unlikely(!access_ok(address, sizeof(u32))))
- return ERR_PTR(-EFAULT);
-
-- key->address = address;
-- key->mm = current->mm;
-+ if (!shared) {
-+ key->address = address;
-+ key->mm = current->mm;
-+ } else {
-+ futex_get_shared_key(address, current->mm, key);
-+ }
-
- /* Generate hash key for this futex using uaddr and current->mm */
- hash_key = jhash2((u32 *) key, sizeof(*key) / sizeof(u32), 0);
-@@ -275,9 +376,10 @@ static int futex_dequeue_multiple(struct futexv *futexv, unsigned int nr)
- * Return: 0 on success, error code otherwise
- */
- static int futex_enqueue(struct futexv *futexv, unsigned int nr_futexes,
-- unsigned int *awaken)
-+ int *awaken)
- {
- int i, ret;
-+ bool shared;
- u32 uval, *uaddr, val;
- struct futex_bucket *bucket;
-
-@@ -285,9 +387,13 @@ static int futex_enqueue(struct futexv *futexv, unsigned int nr_futexes,
- set_current_state(TASK_INTERRUPTIBLE);
-
- for (i = 0; i < nr_futexes; i++) {
-- uaddr = (u32 * __user) futexv->objects[i].key.address;
-+ uaddr = (u32 * __user) futexv->objects[i].uaddr;
- val = (u32) futexv->objects[i].val;
-- bucket = futexv->objects[i].bucket;
-+ shared = (futexv->objects[i].flags & FUTEX_SHARED_FLAG) ? true : false;
-+ if (shared)
-+ bucket = futex_get_bucket((void *) uaddr, &futexv->objects[i].key, true);
-+ else
-+ bucket = futexv->objects[i].bucket;
-
- bucket_inc_waiters(bucket);
- spin_lock(&bucket->lock);
-@@ -301,11 +407,14 @@ static int futex_enqueue(struct futexv *futexv, unsigned int nr_futexes,
- __set_current_state(TASK_RUNNING);
- *awaken = futex_dequeue_multiple(futexv, i);
-
-+ if (shared)
-+ goto retry;
++static ssize_t waitv_show(struct kobject *kobj, struct kobj_attribute *attr,
++ char *buf)
++{
++ return sprintf(buf, "%u\n", __NR_futex_waitv);
+
- if (__get_user(uval, uaddr))
- return -EFAULT;
-
- if (*awaken >= 0)
-- return 0;
-+ return 1;
-
- goto retry;
- }
-@@ -313,12 +422,14 @@ static int futex_enqueue(struct futexv *futexv, unsigned int nr_futexes,
- if (uval != val) {
- spin_unlock(&bucket->lock);
-
++}
++static struct kobj_attribute futex2_waitv_attr = __ATTR_RO(waitv);
+
- bucket_dec_waiters(bucket);
- __set_current_state(TASK_RUNNING);
- *awaken = futex_dequeue_multiple(futexv, i);
-
-- if (*awaken >= 0)
-- return 0;
-+ if (*awaken >= 0) {
-+ return 1;
-+ }
-
- return -EWOULDBLOCK;
- }
-@@ -336,19 +447,18 @@ static int __futex_wait(struct futexv *futexv,
- struct hrtimer_sleeper *timeout)
- {
- int ret;
-- unsigned int awaken = -1;
-
-- while (1) {
-- ret = futex_enqueue(futexv, nr_futexes, &awaken);
-
-- if (ret < 0)
-- break;
-+ while (1) {
-+ int awaken = -1;
-
-- if (awaken <= 0) {
-- return awaken;
-+ ret = futex_enqueue(futexv, nr_futexes, &awaken);
-+ if (ret) {
-+ if (awaken >= 0)
-+ return awaken;
-+ return ret;
- }
-
--
- /* Before sleeping, check if someone was woken */
- if (!futexv->hint && (!timeout || timeout->task))
- freezable_schedule();
-@@ -419,6 +529,7 @@ static int futex_wait(struct futexv *futexv, unsigned int nr_futexes,
- hrtimer_sleeper_start_expires(timeout, HRTIMER_MODE_ABS);
- }
-
++static struct attribute *futex2_sysfs_attrs[] = {
++ &futex2_wait_attr.attr,
++ &futex2_wake_attr.attr,
++ &futex2_waitv_attr.attr,
++ NULL,
++};
+
- ret = __futex_wait(futexv, nr_futexes, timo ? timeout : NULL);
-
-
-@@ -438,9 +549,10 @@ static int futex_wait(struct futexv *futexv, unsigned int nr_futexes,
- SYSCALL_DEFINE4(futex_wait, void __user *, uaddr, unsigned int, val,
- unsigned int, flags, struct __kernel_timespec __user *, timo)
- {
-+ bool shared = (flags & FUTEX_SHARED_FLAG) ? true : false;
- unsigned int size = flags & FUTEX_SIZE_MASK;
-- struct hrtimer_sleeper timeout;
- struct futex_single_waiter wait_single;
-+ struct hrtimer_sleeper timeout;
- struct futex_waiter *waiter;
- struct futexv *futexv;
- int ret;
-@@ -452,6 +564,7 @@ SYSCALL_DEFINE4(futex_wait, void __user *, uaddr, unsigned int, val,
- waiter = &wait_single.waiter;
- waiter->index = 0;
- waiter->val = val;
-+ waiter->uaddr = (uintptr_t) uaddr;
-
- INIT_LIST_HEAD(&waiter->list);
-
-@@ -462,11 +575,14 @@ SYSCALL_DEFINE4(futex_wait, void __user *, uaddr, unsigned int, val,
- return -EINVAL;
-
- /* Get an unlocked hash bucket */
-- waiter->bucket = futex_get_bucket(uaddr, &waiter->key);
-- if (IS_ERR(waiter->bucket))
-+ waiter->bucket = futex_get_bucket(uaddr, &waiter->key, shared);
-+ if (IS_ERR(waiter->bucket)) {
- return PTR_ERR(waiter->bucket);
-+ }
-
- ret = futex_wait(futexv, 1, timo, &timeout, flags);
-+ if (ret > 0)
-+ ret = 0;
-
- return ret;
- }
-@@ -486,8 +602,10 @@ static int futex_parse_waitv(struct futexv *futexv,
- struct futex_waitv waitv;
- unsigned int i;
- struct futex_bucket *bucket;
-+ bool shared;
-
- for (i = 0; i < nr_futexes; i++) {
++static const struct attribute_group futex2_sysfs_attr_group = {
++ .attrs = futex2_sysfs_attrs,
++ .name = "futex2",
++};
+
- if (copy_from_user(&waitv, &uwaitv[i], sizeof(waitv)))
- return -EFAULT;
-
-@@ -495,8 +613,10 @@ static int futex_parse_waitv(struct futexv *futexv,
- (waitv.flags & FUTEX_SIZE_MASK) != FUTEX_32)
- return -EINVAL;
-
-+ shared = (waitv.flags & FUTEX_SHARED_FLAG) ? true : false;
++static int __init futex2_sysfs_init(void)
++{
++ return sysfs_create_group(kernel_kobj, &futex2_sysfs_attr_group);
++}
++subsys_initcall(futex2_sysfs_init);
+
- bucket = futex_get_bucket(waitv.uaddr,
-- &futexv->objects[i].key);
-+ &futexv->objects[i].key, shared);
- if (IS_ERR(bucket))
- return PTR_ERR(bucket);
-
-@@ -505,6 +625,7 @@ static int futex_parse_waitv(struct futexv *futexv,
- futexv->objects[i].flags = waitv.flags;
- futexv->objects[i].index = i;
- INIT_LIST_HEAD(&futexv->objects[i].list);
-+ futexv->objects[i].uaddr = (uintptr_t) waitv.uaddr;
- }
-
- return 0;
-@@ -573,6 +694,7 @@ static struct futexv *futex_get_parent(uintptr_t waiter, u8 index)
- SYSCALL_DEFINE3(futex_wake, void __user *, uaddr, unsigned int, nr_wake,
- unsigned int, flags)
+ static int __init futex2_init(void)
{
-+ bool shared = (flags & FUTEX_SHARED_FLAG) ? true : false;
- unsigned int size = flags & FUTEX_SIZE_MASK;
- struct futex_waiter waiter, *aux, *tmp;
- struct futex_bucket *bucket;
-@@ -586,9 +708,10 @@ SYSCALL_DEFINE3(futex_wake, void __user *, uaddr, unsigned int, nr_wake,
- if (size != FUTEX_32)
- return -EINVAL;
-
-- bucket = futex_get_bucket(uaddr, &waiter.key);
-- if (IS_ERR(bucket))
-+ bucket = futex_get_bucket(uaddr, &waiter.key, shared);
-+ if (IS_ERR(bucket)) {
- return PTR_ERR(bucket);
-+ }
-
- if (!bucket_get_waiters(bucket))
- return 0;
+ int i;
--
-2.28.0
+2.29.2
-From 909eb056421668b5d42f8c4dfa92339851a43dd8 Mon Sep 17 00:00:00 2001
-From: Gabriel Krisman Bertazi <krisman@collabora.com>
-Date: Mon, 2 Nov 2020 18:41:38 -0500
-Subject: [PATCH 08/13] Revert "futex: Remove needless goto's"
-This reverts commit d7c5ed73b19c4640426d9c106f70ec2cb532034d.
----
- kernel/futex.c | 40 ++++++++++++++++++++++++----------------
- 1 file changed, 24 insertions(+), 16 deletions(-)
-
-diff --git a/kernel/futex.c b/kernel/futex.c
-index 6c00c0952313..a671d371b11f 100644
---- a/kernel/futex.c
-+++ b/kernel/futex.c
-@@ -1593,13 +1593,13 @@ futex_wake(u32 __user *uaddr, unsigned int flags, int nr_wake, u32 bitset)
-
- ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key, FUTEX_READ);
- if (unlikely(ret != 0))
-- return ret;
-+ goto out;
-
- hb = hash_futex(&key);
-
- /* Make sure we really have tasks to wakeup */
- if (!hb_waiters_pending(hb))
-- return ret;
-+ goto out;
-
- spin_lock(&hb->lock);
-
-@@ -1622,6 +1622,7 @@ futex_wake(u32 __user *uaddr, unsigned int flags, int nr_wake, u32 bitset)
-
- spin_unlock(&hb->lock);
- wake_up_q(&wake_q);
-+out:
- return ret;
- }
-
-@@ -1688,10 +1689,10 @@ futex_wake_op(u32 __user *uaddr1, unsigned int flags, u32 __user *uaddr2,
- retry:
- ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1, FUTEX_READ);
- if (unlikely(ret != 0))
-- return ret;
-+ goto out;
- ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2, FUTEX_WRITE);
- if (unlikely(ret != 0))
-- return ret;
-+ goto out;
-
- hb1 = hash_futex(&key1);
- hb2 = hash_futex(&key2);
-@@ -1709,13 +1710,13 @@ futex_wake_op(u32 __user *uaddr1, unsigned int flags, u32 __user *uaddr2,
- * an MMU, but we might get them from range checking
- */
- ret = op_ret;
-- return ret;
-+ goto out;
- }
-
- if (op_ret == -EFAULT) {
- ret = fault_in_user_writeable(uaddr2);
- if (ret)
-- return ret;
-+ goto out;
- }
-
- if (!(flags & FLAGS_SHARED)) {
-@@ -1758,6 +1759,7 @@ futex_wake_op(u32 __user *uaddr1, unsigned int flags, u32 __user *uaddr2,
- out_unlock:
- double_unlock_hb(hb1, hb2);
- wake_up_q(&wake_q);
-+out:
- return ret;
- }
-
-@@ -1964,18 +1966,20 @@ static int futex_requeue(u32 __user *uaddr1, unsigned int flags,
- retry:
- ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1, FUTEX_READ);
- if (unlikely(ret != 0))
-- return ret;
-+ goto out;
- ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2,
- requeue_pi ? FUTEX_WRITE : FUTEX_READ);
- if (unlikely(ret != 0))
-- return ret;
-+ goto out;
-
- /*
- * The check above which compares uaddrs is not sufficient for
- * shared futexes. We need to compare the keys:
- */
-- if (requeue_pi && match_futex(&key1, &key2))
-- return -EINVAL;
-+ if (requeue_pi && match_futex(&key1, &key2)) {
-+ ret = -EINVAL;
-+ goto out;
-+ }
-
- hb1 = hash_futex(&key1);
- hb2 = hash_futex(&key2);
-@@ -1995,7 +1999,7 @@ static int futex_requeue(u32 __user *uaddr1, unsigned int flags,
-
- ret = get_user(curval, uaddr1);
- if (ret)
-- return ret;
-+ goto out;
-
- if (!(flags & FLAGS_SHARED))
- goto retry_private;
-@@ -2061,7 +2065,7 @@ static int futex_requeue(u32 __user *uaddr1, unsigned int flags,
- ret = fault_in_user_writeable(uaddr2);
- if (!ret)
- goto retry;
-- return ret;
-+ goto out;
- case -EBUSY:
- case -EAGAIN:
- /*
-@@ -2180,6 +2184,8 @@ static int futex_requeue(u32 __user *uaddr1, unsigned int flags,
- double_unlock_hb(hb1, hb2);
- wake_up_q(&wake_q);
- hb_waiters_dec(hb2);
-+
-+out:
- return ret ? ret : task_count;
- }
-
-@@ -2537,7 +2543,7 @@ static int fixup_owner(u32 __user *uaddr, struct futex_q *q, int locked)
- */
- if (q->pi_state->owner != current)
- ret = fixup_pi_state_owner(uaddr, q, current);
-- return ret ? ret : locked;
-+ goto out;
- }
-
- /*
-@@ -2550,7 +2556,7 @@ static int fixup_owner(u32 __user *uaddr, struct futex_q *q, int locked)
- */
- if (q->pi_state->owner == current) {
- ret = fixup_pi_state_owner(uaddr, q, NULL);
-- return ret;
-+ goto out;
- }
-
- /*
-@@ -2564,7 +2570,8 @@ static int fixup_owner(u32 __user *uaddr, struct futex_q *q, int locked)
- q->pi_state->owner);
- }
-
-- return ret;
-+out:
-+ return ret ? ret : locked;
- }
-
- /**
-@@ -2661,7 +2668,7 @@ static int futex_wait_setup(u32 __user *uaddr, u32 val, unsigned int flags,
-
- ret = get_user(uval, uaddr);
- if (ret)
-- return ret;
-+ goto out;
-
- if (!(flags & FLAGS_SHARED))
- goto retry_private;
-@@ -2674,6 +2681,7 @@ static int futex_wait_setup(u32 __user *uaddr, u32 val, unsigned int flags,
- ret = -EWOULDBLOCK;
- }
-
-+out:
- return ret;
- }
-
---
-2.28.0
+From f7b1c9a2ad05933e559ef78bc7753b2fac1698fd Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Andr=C3=A9=20Almeida?= <andrealmeid@collabora.com>
+Date: Tue, 5 Jan 2021 15:44:02 -0300
+Subject: [PATCH 9/9] perf bench: Add futex2 benchmark tests
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
-From fee513186b69c4a65534fd790545877974ef17d3 Mon Sep 17 00:00:00 2001
-From: Gabriel Krisman Bertazi <krisman@collabora.com>
-Date: Mon, 2 Nov 2020 18:41:54 -0500
-Subject: [PATCH 09/13] Revert "futex: Remove put_futex_key()"
+Port existing futex infrastructure to use futex2 calls.
-This reverts commit 9180bd467f9abdb44afde650d07e3b9dd66d837c.
+Signed-off-by: André Almeida <andrealmeid@collabora.com>
+Signed-off-by: Jan200101 <sentrycraft123@gmail.com>
---
- kernel/futex.c | 61 ++++++++++++++++++++++++++++++++++++++++----------
- 1 file changed, 49 insertions(+), 12 deletions(-)
+ tools/arch/x86/include/asm/unistd_64.h | 8 +++++
+ tools/perf/bench/bench.h | 3 ++
+ tools/perf/bench/futex-hash.c | 24 ++++++++++++---
+ tools/perf/bench/futex-wake-parallel.c | 41 ++++++++++++++++++++++----
+ tools/perf/bench/futex-wake.c | 36 ++++++++++++++++++----
+ tools/perf/bench/futex.h | 17 +++++++++++
+ tools/perf/builtin-bench.c | 17 ++++++++---
+ 7 files changed, 127 insertions(+), 19 deletions(-)
-diff --git a/kernel/futex.c b/kernel/futex.c
-index a671d371b11f..647de692c874 100644
---- a/kernel/futex.c
-+++ b/kernel/futex.c
-@@ -661,6 +661,10 @@ static int get_futex_key(u32 __user *uaddr, bool fshared, union futex_key *key,
- return err;
- }
-
-+static inline void put_futex_key(union futex_key *key)
-+{
-+}
+diff --git a/tools/arch/x86/include/asm/unistd_64.h b/tools/arch/x86/include/asm/unistd_64.h
+index 4205ed415..151a41ceb 100644
+--- a/tools/arch/x86/include/asm/unistd_64.h
++++ b/tools/arch/x86/include/asm/unistd_64.h
+@@ -17,3 +17,11 @@
+ #ifndef __NR_setns
+ #define __NR_setns 308
+ #endif
+
- /**
- * fault_in_user_writeable() - Fault in user address and verify RW access
- * @uaddr: pointer to faulting user space address
-@@ -1599,7 +1603,7 @@ futex_wake(u32 __user *uaddr, unsigned int flags, int nr_wake, u32 bitset)
-
- /* Make sure we really have tasks to wakeup */
- if (!hb_waiters_pending(hb))
-- goto out;
-+ goto out_put_key;
-
- spin_lock(&hb->lock);
-
-@@ -1622,6 +1626,8 @@ futex_wake(u32 __user *uaddr, unsigned int flags, int nr_wake, u32 bitset)
-
- spin_unlock(&hb->lock);
- wake_up_q(&wake_q);
-+out_put_key:
-+ put_futex_key(&key);
- out:
- return ret;
- }
-@@ -1692,7 +1698,7 @@ futex_wake_op(u32 __user *uaddr1, unsigned int flags, u32 __user *uaddr2,
- goto out;
- ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2, FUTEX_WRITE);
- if (unlikely(ret != 0))
-- goto out;
-+ goto out_put_key1;
-
- hb1 = hash_futex(&key1);
- hb2 = hash_futex(&key2);
-@@ -1710,13 +1716,13 @@ futex_wake_op(u32 __user *uaddr1, unsigned int flags, u32 __user *uaddr2,
- * an MMU, but we might get them from range checking
- */
- ret = op_ret;
-- goto out;
-+ goto out_put_keys;
- }
-
- if (op_ret == -EFAULT) {
- ret = fault_in_user_writeable(uaddr2);
- if (ret)
-- goto out;
-+ goto out_put_keys;
- }
-
- if (!(flags & FLAGS_SHARED)) {
-@@ -1724,6 +1730,8 @@ futex_wake_op(u32 __user *uaddr1, unsigned int flags, u32 __user *uaddr2,
- goto retry_private;
- }
-
-+ put_futex_key(&key2);
-+ put_futex_key(&key1);
- cond_resched();
- goto retry;
- }
-@@ -1759,6 +1767,10 @@ futex_wake_op(u32 __user *uaddr1, unsigned int flags, u32 __user *uaddr2,
- out_unlock:
- double_unlock_hb(hb1, hb2);
- wake_up_q(&wake_q);
-+out_put_keys:
-+ put_futex_key(&key2);
-+out_put_key1:
-+ put_futex_key(&key1);
- out:
- return ret;
- }
-@@ -1970,7 +1982,7 @@ static int futex_requeue(u32 __user *uaddr1, unsigned int flags,
- ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2,
- requeue_pi ? FUTEX_WRITE : FUTEX_READ);
- if (unlikely(ret != 0))
-- goto out;
-+ goto out_put_key1;
-
- /*
- * The check above which compares uaddrs is not sufficient for
-@@ -1978,7 +1990,7 @@ static int futex_requeue(u32 __user *uaddr1, unsigned int flags,
- */
- if (requeue_pi && match_futex(&key1, &key2)) {
- ret = -EINVAL;
-- goto out;
-+ goto out_put_keys;
- }
-
- hb1 = hash_futex(&key1);
-@@ -1999,11 +2011,13 @@ static int futex_requeue(u32 __user *uaddr1, unsigned int flags,
-
- ret = get_user(curval, uaddr1);
- if (ret)
-- goto out;
-+ goto out_put_keys;
-
- if (!(flags & FLAGS_SHARED))
- goto retry_private;
-
-+ put_futex_key(&key2);
-+ put_futex_key(&key1);
- goto retry;
- }
- if (curval != *cmpval) {
-@@ -2062,6 +2076,8 @@ static int futex_requeue(u32 __user *uaddr1, unsigned int flags,
- case -EFAULT:
- double_unlock_hb(hb1, hb2);
- hb_waiters_dec(hb2);
-+ put_futex_key(&key2);
-+ put_futex_key(&key1);
- ret = fault_in_user_writeable(uaddr2);
- if (!ret)
- goto retry;
-@@ -2076,6 +2092,8 @@ static int futex_requeue(u32 __user *uaddr1, unsigned int flags,
++#ifndef __NR_futex_wait
++# define __NR_futex_wait 441
++#endif
++
++#ifndef __NR_futex_wake
++# define __NR_futex_wake 442
++#endif
+diff --git a/tools/perf/bench/bench.h b/tools/perf/bench/bench.h
+index eac36afab..f6f881a05 100644
+--- a/tools/perf/bench/bench.h
++++ b/tools/perf/bench/bench.h
+@@ -38,8 +38,11 @@ int bench_mem_memcpy(int argc, const char **argv);
+ int bench_mem_memset(int argc, const char **argv);
+ int bench_mem_find_bit(int argc, const char **argv);
+ int bench_futex_hash(int argc, const char **argv);
++int bench_futex2_hash(int argc, const char **argv);
+ int bench_futex_wake(int argc, const char **argv);
++int bench_futex2_wake(int argc, const char **argv);
+ int bench_futex_wake_parallel(int argc, const char **argv);
++int bench_futex2_wake_parallel(int argc, const char **argv);
+ int bench_futex_requeue(int argc, const char **argv);
+ /* pi futexes */
+ int bench_futex_lock_pi(int argc, const char **argv);
+diff --git a/tools/perf/bench/futex-hash.c b/tools/perf/bench/futex-hash.c
+index 915bf3da7..72921c22b 100644
+--- a/tools/perf/bench/futex-hash.c
++++ b/tools/perf/bench/futex-hash.c
+@@ -34,7 +34,7 @@ static unsigned int nthreads = 0;
+ static unsigned int nsecs = 10;
+ /* amount of futexes per thread */
+ static unsigned int nfutexes = 1024;
+-static bool fshared = false, done = false, silent = false;
++static bool fshared = false, done = false, silent = false, futex2 = false;
+ static int futex_flag = 0;
+
+ struct timeval bench__start, bench__end, bench__runtime;
+@@ -86,7 +86,10 @@ static void *workerfn(void *arg)
+ * such as internal waitqueue handling, thus enlarging
+ * the critical region protected by hb->lock.
*/
- double_unlock_hb(hb1, hb2);
- hb_waiters_dec(hb2);
-+ put_futex_key(&key2);
-+ put_futex_key(&key1);
- /*
- * Handle the case where the owner is in the middle of
- * exiting. Wait for the exit to complete otherwise
-@@ -2185,6 +2203,10 @@ static int futex_requeue(u32 __user *uaddr1, unsigned int flags,
- wake_up_q(&wake_q);
- hb_waiters_dec(hb2);
-
-+out_put_keys:
-+ put_futex_key(&key2);
-+out_put_key1:
-+ put_futex_key(&key1);
- out:
- return ret ? ret : task_count;
- }
-@@ -2673,6 +2695,7 @@ static int futex_wait_setup(u32 __user *uaddr, u32 val, unsigned int flags,
- if (!(flags & FLAGS_SHARED))
- goto retry_private;
-
-+ put_futex_key(&q->key);
- goto retry;
- }
-
-@@ -2682,6 +2705,8 @@ static int futex_wait_setup(u32 __user *uaddr, u32 val, unsigned int flags,
- }
-
- out:
-+ if (ret)
-+ put_futex_key(&q->key);
- return ret;
+- ret = futex_wait(&w->futex[i], 1234, NULL, futex_flag);
++ if (!futex2)
++ ret = futex_wait(&w->futex[i], 1234, NULL, futex_flag);
++ else
++ ret = futex2_wait(&w->futex[i], 1234, futex_flag, NULL);
+ if (!silent &&
+ (!ret || errno != EAGAIN || errno != EWOULDBLOCK))
+ warn("Non-expected futex return call");
+@@ -117,7 +120,7 @@ static void print_summary(void)
+ (int)bench__runtime.tv_sec);
}
-@@ -2826,6 +2851,7 @@ static int futex_lock_pi(u32 __user *uaddr, unsigned int flags,
- * - EAGAIN: The user space value changed.
- */
- queue_unlock(hb);
-+ put_futex_key(&q.key);
- /*
- * Handle the case where the owner is in the middle of
- * exiting. Wait for the exit to complete otherwise
-@@ -2933,11 +2959,13 @@ static int futex_lock_pi(u32 __user *uaddr, unsigned int flags,
- put_pi_state(pi_state);
- }
-
-- goto out;
-+ goto out_put_key;
-
- out_unlock_put_key:
- queue_unlock(hb);
-
-+out_put_key:
-+ put_futex_key(&q.key);
- out:
- if (to) {
- hrtimer_cancel(&to->timer);
-@@ -2950,11 +2978,12 @@ static int futex_lock_pi(u32 __user *uaddr, unsigned int flags,
-
- ret = fault_in_user_writeable(uaddr);
- if (ret)
-- goto out;
-+ goto out_put_key;
-
- if (!(flags & FLAGS_SHARED))
- goto retry_private;
-
-+ put_futex_key(&q.key);
- goto retry;
+-int bench_futex_hash(int argc, const char **argv)
++static int bench_futex_hash_common(int argc, const char **argv)
+ {
+ int ret = 0;
+ cpu_set_t cpuset;
+@@ -149,7 +152,9 @@ int bench_futex_hash(int argc, const char **argv)
+ if (!worker)
+ goto errmem;
+
+- if (!fshared)
++ if (futex2)
++ futex_flag = FUTEX_32 | (fshared * FUTEX_SHARED_FLAG);
++ else if (!fshared)
+ futex_flag = FUTEX_PRIVATE_FLAG;
+
+ printf("Run summary [PID %d]: %d threads, each operating on %d [%s] futexes for %d secs.\n\n",
+@@ -229,3 +234,14 @@ int bench_futex_hash(int argc, const char **argv)
+ errmem:
+ err(EXIT_FAILURE, "calloc");
}
-
-@@ -3083,13 +3112,16 @@ static int futex_unlock_pi(u32 __user *uaddr, unsigned int flags)
- out_unlock:
- spin_unlock(&hb->lock);
- out_putkey:
-+ put_futex_key(&key);
- return ret;
-
- pi_retry:
-+ put_futex_key(&key);
- cond_resched();
- goto retry;
-
- pi_faulted:
-+ put_futex_key(&key);
-
- ret = fault_in_user_writeable(uaddr);
- if (!ret)
-@@ -3231,7 +3263,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
- */
- ret = futex_wait_setup(uaddr, val, flags, &q, &hb);
- if (ret)
-- goto out;
-+ goto out_key2;
-
- /*
- * The check above which compares uaddrs is not sufficient for
-@@ -3240,7 +3272,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
- if (match_futex(&q.key, &key2)) {
- queue_unlock(hb);
- ret = -EINVAL;
-- goto out;
-+ goto out_put_keys;
- }
-
- /* Queue the futex_q, drop the hb lock, wait for wakeup. */
-@@ -3250,7 +3282,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
- ret = handle_early_requeue_pi_wakeup(hb, &q, &key2, to);
- spin_unlock(&hb->lock);
- if (ret)
-- goto out;
-+ goto out_put_keys;
-
- /*
- * In order for us to be here, we know our q.key == key2, and since
-@@ -3340,6 +3372,11 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
- ret = -EWOULDBLOCK;
- }
-
-+out_put_keys:
-+ put_futex_key(&q.key);
-+out_key2:
-+ put_futex_key(&key2);
+
- out:
- if (to) {
- hrtimer_cancel(&to->timer);
---
-2.28.0
-
-From 3b1489448a277fc1c34ca12e859193c3a7f3446c Mon Sep 17 00:00:00 2001
-From: Gabriel Krisman Bertazi <krisman@collabora.com>
-Date: Fri, 12 Jul 2019 14:16:20 -0400
-Subject: [PATCH 10/13] 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>
----
- kernel/futex.c | 71 +++++++++++++++++++++++++++++---------------------
- 1 file changed, 42 insertions(+), 29 deletions(-)
-
-diff --git a/kernel/futex.c b/kernel/futex.c
-index 647de692c874..f05349def492 100644
---- a/kernel/futex.c
-+++ b/kernel/futex.c
-@@ -2634,6 +2634,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)
++int bench_futex_hash(int argc, const char **argv)
+{
++ return bench_futex_hash_common(argc, argv);
++}
+
-+ 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;
-+ }
++int bench_futex2_hash(int argc, const char **argv)
++{
++ futex2 = true;
++ return bench_futex_hash_common(argc, argv);
++}
+diff --git a/tools/perf/bench/futex-wake-parallel.c b/tools/perf/bench/futex-wake-parallel.c
+index cd2b81a84..540104538 100644
+--- a/tools/perf/bench/futex-wake-parallel.c
++++ b/tools/perf/bench/futex-wake-parallel.c
+@@ -17,6 +17,12 @@ int bench_futex_wake_parallel(int argc __maybe_unused, const char **argv __maybe
+ pr_err("%s: pthread_barrier_t unavailable, disabling this test...\n", __func__);
+ return 0;
+ }
+
-+ return ret;
++int bench_futex2_wake_parallel(int argc __maybe_unused, const char **argv __maybe_unused)
++{
++ pr_err("%s: pthread_barrier_t unavailable, disabling this test...\n", __func__);
++ return 0;
+}
+ #else /* HAVE_PTHREAD_BARRIER */
+ /* For the CLR_() macros */
+ #include <string.h>
+@@ -48,7 +54,7 @@ static unsigned int nwakes = 1;
+ static u_int32_t futex = 0;
+
+ static pthread_t *blocked_worker;
+-static bool done = false, silent = false, fshared = false;
++static bool done = false, silent = false, fshared = false, futex2 = false;
+ static unsigned int nblocked_threads = 0, nwaking_threads = 0;
+ static pthread_mutex_t thread_lock;
+ static pthread_cond_t thread_parent, thread_worker;
+@@ -79,7 +85,11 @@ static void *waking_workerfn(void *arg)
+
+ gettimeofday(&start, NULL);
+
+- waker->nwoken = futex_wake(&futex, nwakes, futex_flag);
++ if (!futex2)
++ waker->nwoken = futex_wake(&futex, nwakes, futex_flag);
++ else
++ waker->nwoken = futex2_wake(&futex, nwakes, futex_flag);
+
- /**
- * futex_wait_setup() - Prepare to wait on a futex
- * @uaddr: the futex userspace address
-@@ -2654,7 +2687,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;
-
- /*
-@@ -2675,38 +2707,19 @@ 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;
--
--retry_private:
-- *hb = queue_lock(q);
-+ do {
-+ ret = get_futex_key(uaddr, flags & FLAGS_SHARED,
-+ &q->key, FUTEX_READ);
-+ if (unlikely(ret != 0))
-+ return ret;
+ if (waker->nwoken != nwakes)
+ warnx("couldn't wakeup all tasks (%d/%d)",
+ waker->nwoken, nwakes);
+@@ -130,8 +140,13 @@ static void *blocked_workerfn(void *arg __maybe_unused)
+ pthread_mutex_unlock(&thread_lock);
-- ret = get_futex_value_locked(&uval, uaddr);
-+ ret = __futex_wait_setup(uaddr, val, flags, q, hb);
+ while (1) { /* handle spurious wakeups */
+- if (futex_wait(&futex, 0, NULL, futex_flag) != EINTR)
+- break;
++ if (!futex2) {
++ if (futex_wait(&futex, 0, NULL, futex_flag) != EINTR)
++ break;
++ } else {
++ if (futex2_wait(&futex, 0, futex_flag, NULL) != EINTR)
++ break;
++ }
+ }
-- if (ret) {
-- queue_unlock(*hb);
--
-- ret = get_user(uval, uaddr);
-+ /* Drop key reference if retry or error. */
- if (ret)
-- goto out;
-+ put_futex_key(&q->key);
-+ } while (ret > 0);
-
-- if (!(flags & FLAGS_SHARED))
-- goto retry_private;
--
-- put_futex_key(&q->key);
-- goto retry;
-- }
--
-- if (uval != val) {
-- queue_unlock(*hb);
-- ret = -EWOULDBLOCK;
-- }
--
--out:
-- if (ret)
-- put_futex_key(&q->key);
- return ret;
+ pthread_exit(NULL);
+@@ -218,7 +233,7 @@ static void toggle_done(int sig __maybe_unused,
+ done = true;
}
---
-2.28.0
-
-From 539862895e53b9a774f3a2271d1e7db57879d0d7 Mon Sep 17 00:00:00 2001
-From: Gabriel Krisman Bertazi <krisman@collabora.com>
-Date: Mon, 8 Jul 2019 09:44:09 -0400
-Subject: [PATCH 11/13] 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>
----
- include/uapi/linux/futex.h | 7 ++
- kernel/futex.c | 159 ++++++++++++++++++++++++++++++++++++-
- 2 files changed, 162 insertions(+), 4 deletions(-)
-
-diff --git a/include/uapi/linux/futex.h b/include/uapi/linux/futex.h
-index 35a5bf1cd41b..aefb0b83b784 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 13
-
- #define FUTEX_PRIVATE_FLAG 128
- #define FUTEX_CLOCK_REALTIME 256
-@@ -190,4 +191,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 f05349def492..775f780a96c4 100644
---- a/kernel/futex.c
-+++ b/kernel/futex.c
-@@ -166,6 +166,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:
-@@ -2723,6 +2724,148 @@ static int futex_wait_setup(u32 __user *uaddr, u32 val, unsigned int flags,
+-int bench_futex_wake_parallel(int argc, const char **argv)
++static int bench_futex_wake_parallel_common(int argc, const char **argv)
+ {
+ int ret = 0;
+ unsigned int i, j;
+@@ -262,7 +277,9 @@ int bench_futex_wake_parallel(int argc, const char **argv)
+ if (!blocked_worker)
+ err(EXIT_FAILURE, "calloc");
+
+- if (!fshared)
++ if (futex2)
++ futex_flag = FUTEX_32 | (fshared * FUTEX_SHARED_FLAG);
++ else if (!fshared)
+ futex_flag = FUTEX_PRIVATE_FLAG;
+
+ printf("Run summary [PID %d]: blocking on %d threads (at [%s] "
+@@ -322,4 +339,16 @@ int bench_futex_wake_parallel(int argc, const char **argv)
+ free(blocked_worker);
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;
-+
-+ /* Woken by triggered timeout */
-+ if (to && !to->task)
-+ goto out;
-+
-+ /*
-+ * 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);
-+ }
-+
-+ kfree(qs);
-+ return ret;
++int bench_futex_wake_parallel(int argc, const char **argv)
++{
++ return bench_futex_wake_parallel_common(argc, argv);
+}
+
-+static int futex_wait_multiple(u32 __user *uaddr, unsigned int flags,
-+ u32 count, ktime_t *abs_time)
++int bench_futex2_wake_parallel(int argc, const char **argv)
+{
-+ 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:
-+ kfree(wb);
-+ return ret;
++ futex2 = true;
++ return bench_futex_wake_parallel_common(argc, argv);
+}
+
- static int futex_wait(u32 __user *uaddr, unsigned int flags, u32 val,
- ktime_t *abs_time, u32 bitset)
- {
-@@ -2800,6 +2943,10 @@ static long futex_wait_restart(struct restart_block *restart)
- }
- restart->fn = do_no_restart_syscall;
+ #endif /* HAVE_PTHREAD_BARRIER */
+diff --git a/tools/perf/bench/futex-wake.c b/tools/perf/bench/futex-wake.c
+index 2dfcef3e3..b98b84e7b 100644
+--- a/tools/perf/bench/futex-wake.c
++++ b/tools/perf/bench/futex-wake.c
+@@ -46,6 +46,9 @@ static struct stats waketime_stats, wakeup_stats;
+ static unsigned int threads_starting, nthreads = 0;
+ static int futex_flag = 0;
-+ if (restart->futex.flags & FLAGS_WAKE_MULTIPLE)
-+ return (long)futex_wait_multiple(uaddr, restart->futex.flags,
-+ restart->futex.val, tp);
++/* Should we use futex2 API? */
++static bool futex2 = false;
+
- return (long)futex_wait(uaddr, restart->futex.flags,
- restart->futex.val, tp, restart->futex.bitset);
- }
-@@ -3843,6 +3990,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);
+ static const struct option options[] = {
+ OPT_UINTEGER('t', "threads", &nthreads, "Specify amount of threads"),
+ OPT_UINTEGER('w', "nwakes", &nwakes, "Specify amount of threads to wake at once"),
+@@ -69,8 +72,13 @@ static void *workerfn(void *arg __maybe_unused)
+ pthread_mutex_unlock(&thread_lock);
+
+ while (1) {
+- if (futex_wait(&futex1, 0, NULL, futex_flag) != EINTR)
+- break;
++ if (!futex2) {
++ if (futex_wait(&futex1, 0, NULL, futex_flag) != EINTR)
++ break;
++ } else {
++ if (futex2_wait(&futex1, 0, futex_flag, NULL) != EINTR)
++ break;
++ }
}
- return -ENOSYS;
+
+ pthread_exit(NULL);
+@@ -118,7 +126,7 @@ static void toggle_done(int sig __maybe_unused,
+ done = true;
}
-@@ -3859,7 +4008,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))
-@@ -3868,7 +4018,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);
- else if (!(op & FUTEX_CLOCK_REALTIME))
- t = timens_ktime_to_host(CLOCK_MONOTONIC, t);
-@@ -4055,14 +4205,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;
+-int bench_futex_wake(int argc, const char **argv)
++static int bench_futex_wake_common(int argc, const char **argv)
+ {
+ int ret = 0;
+ unsigned int i, j;
+@@ -148,7 +156,9 @@ int bench_futex_wake(int argc, const char **argv)
+ if (!worker)
+ err(EXIT_FAILURE, "calloc");
+
+- if (!fshared)
++ if (futex2)
++ futex_flag = FUTEX_32 | (fshared * FUTEX_SHARED_FLAG);
++ else if (!fshared)
+ futex_flag = FUTEX_PRIVATE_FLAG;
+
+ printf("Run summary [PID %d]: blocking on %d threads (at [%s] futex %p), "
+@@ -181,8 +191,13 @@ int bench_futex_wake(int argc, const char **argv)
+ /* Ok, all threads are patiently blocked, start waking folks up */
+ gettimeofday(&start, NULL);
+ while (nwoken != nthreads)
+- nwoken += futex_wake(&futex1, nwakes, futex_flag);
++ if (!futex2) {
++ nwoken += futex_wake(&futex1, nwakes, futex_flag);
++ } else {
++ nwoken += futex2_wake(&futex1, nwakes, futex_flag);
++ }
+ gettimeofday(&end, NULL);
++
+ timersub(&end, &start, &runtime);
- 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 (!(op & FUTEX_CLOCK_REALTIME))
- t = timens_ktime_to_host(CLOCK_MONOTONIC, t);
---
-2.28.0
-
-From f56b85af005d46e9ef920a6728e61f7c47cf561e Mon Sep 17 00:00:00 2001
-From: Gabriel Krisman Bertazi <krisman@collabora.com>
-Date: Mon, 2 Nov 2020 18:50:26 -0500
-Subject: [PATCH 12/13] futex: Change WAIT_MULTIPLE opcode to 31
-
-Signed-off-by: Gabriel Krisman Bertazi <krisman@collabora.com>
----
- include/uapi/linux/futex.h | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/include/uapi/linux/futex.h b/include/uapi/linux/futex.h
-index aefb0b83b784..fe2b67ac0c5e 100644
---- a/include/uapi/linux/futex.h
-+++ b/include/uapi/linux/futex.h
-@@ -21,7 +21,7 @@
- #define FUTEX_WAKE_BITSET 10
- #define FUTEX_WAIT_REQUEUE_PI 11
- #define FUTEX_CMP_REQUEUE_PI 12
--#define FUTEX_WAIT_MULTIPLE 13
-+#define FUTEX_WAIT_MULTIPLE 31
-
- #define FUTEX_PRIVATE_FLAG 128
- #define FUTEX_CLOCK_REALTIME 256
---
-2.28.0
-
-From 022e2f888a50fb8d062e26bc385abf02c0be84a3 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Andr=C3=A9=20Almeida?= <andrealmeid@collabora.com>
-Date: Mon, 16 Nov 2020 21:22:21 -0300
-Subject: [PATCH 13/13] futex2: Add sysfs entry for syscall numbers
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-Signed-off-by: André Almeida <andrealmeid@collabora.com>
----
- kernel/futex2.c | 42 ++++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 42 insertions(+)
-
-diff --git a/kernel/futex2.c b/kernel/futex2.c
-index ae743ddf223e..4bdff8bfc78d 100644
---- a/kernel/futex2.c
-+++ b/kernel/futex2.c
-@@ -742,6 +742,48 @@ SYSCALL_DEFINE3(futex_wake, void __user *, uaddr, unsigned int, nr_wake,
+ update_stats(&wakeup_stats, nwoken);
+@@ -212,3 +227,14 @@ int bench_futex_wake(int argc, const char **argv)
+ free(worker);
return ret;
}
-
-+static ssize_t wait_show(struct kobject *kobj, struct kobj_attribute *attr,
-+ char *buf)
-+{
-+ return sprintf(buf, "%u\n", __NR_futex_wait);
+
++int bench_futex_wake(int argc, const char **argv)
++{
++ return bench_futex_wake_common(argc, argv);
+}
-+static struct kobj_attribute futex2_wait_attr = __ATTR_RO(wait);
+
-+static ssize_t wake_show(struct kobject *kobj, struct kobj_attribute *attr,
-+ char *buf)
++int bench_futex2_wake(int argc, const char **argv)
+{
-+ return sprintf(buf, "%u\n", __NR_futex_wake);
-+
++ futex2 = true;
++ return bench_futex_wake_common(argc, argv);
+}
-+static struct kobj_attribute futex2_wake_attr = __ATTR_RO(wake);
+diff --git a/tools/perf/bench/futex.h b/tools/perf/bench/futex.h
+index 31b53cc7d..5111799b5 100644
+--- a/tools/perf/bench/futex.h
++++ b/tools/perf/bench/futex.h
+@@ -86,4 +86,21 @@ futex_cmp_requeue(u_int32_t *uaddr, u_int32_t val, u_int32_t *uaddr2, int nr_wak
+ return futex(uaddr, FUTEX_CMP_REQUEUE, nr_wake, nr_requeue, uaddr2,
+ val, opflags);
+ }
+
-+static ssize_t waitv_show(struct kobject *kobj, struct kobj_attribute *attr,
-+ char *buf)
++/*
++ * wait for uaddr if (*uaddr == val)
++ */
++static inline int futex2_wait(volatile void *uaddr, unsigned long val,
++ unsigned long flags, struct timespec *timo)
+{
-+ return sprintf(buf, "%u\n", __NR_futex_waitv);
-+
++ return syscall(__NR_futex_wait, uaddr, val, flags, timo);
+}
-+static struct kobj_attribute futex2_waitv_attr = __ATTR_RO(waitv);
-+
-+static struct attribute *futex2_sysfs_attrs[] = {
-+ &futex2_wait_attr.attr,
-+ &futex2_wake_attr.attr,
-+ &futex2_waitv_attr.attr,
-+ NULL,
-+};
-+
-+static const struct attribute_group futex2_sysfs_attr_group = {
-+ .attrs = futex2_sysfs_attrs,
-+ .name = "futex2",
-+};
+
-+static int __init futex2_sysfs_init(void)
++/*
++ * wake nr futexes waiting for uaddr
++ */
++static inline int futex2_wake(volatile void *uaddr, unsigned int nr, unsigned long flags)
+{
-+ return sysfs_create_group(kernel_kobj, &futex2_sysfs_attr_group);
++ return syscall(__NR_futex_wake, uaddr, nr, flags);
+}
-+subsys_initcall(futex2_sysfs_init);
+ #endif /* _FUTEX_H */
+diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c
+index 62a7b7420..200ecacad 100644
+--- a/tools/perf/builtin-bench.c
++++ b/tools/perf/builtin-bench.c
+@@ -12,10 +12,11 @@
+ *
+ * sched ... scheduler and IPC performance
+ * syscall ... System call performance
+- * mem ... memory access performance
+- * numa ... NUMA scheduling and MM performance
+- * futex ... Futex performance
+- * epoll ... Event poll performance
++ * mem ... memory access performance
++ * numa ... NUMA scheduling and MM performance
++ * futex ... Futex performance
++ * futex2 ... Futex2 performance
++ * epoll ... Event poll performance
+ */
+ #include <subcmd/parse-options.h>
+ #include "builtin.h"
+@@ -75,6 +76,13 @@ static struct bench futex_benchmarks[] = {
+ { NULL, NULL, NULL }
+ };
+
++static struct bench futex2_benchmarks[] = {
++ { "hash", "Benchmark for futex2 hash table", bench_futex2_hash },
++ { "wake", "Benchmark for futex2 wake calls", bench_futex2_wake },
++ { "wake-parallel", "Benchmark for parallel futex2 wake calls", bench_futex2_wake_parallel },
++ { NULL, NULL, NULL }
++};
+
- static int __init futex2_init(void)
- {
- int i;
+ #ifdef HAVE_EVENTFD_SUPPORT
+ static struct bench epoll_benchmarks[] = {
+ { "wait", "Benchmark epoll concurrent epoll_waits", bench_epoll_wait },
+@@ -105,6 +113,7 @@ static struct collection collections[] = {
+ { "numa", "NUMA scheduling and MM benchmarks", numa_benchmarks },
+ #endif
+ {"futex", "Futex stressing benchmarks", futex_benchmarks },
++ {"futex2", "Futex2 stressing benchmarks", futex2_benchmarks },
+ #ifdef HAVE_EVENTFD_SUPPORT
+ {"epoll", "Epoll stressing benchmarks", epoll_benchmarks },
+ #endif
--
-2.28.0
+2.29.2