Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

rseq/selftests: Use __rseq_handled symbol to coexist with glibc

In order to integrate rseq into user-space applications, expose a
__rseq_handled symbol so many rseq users can be linked into the same
application (e.g. librseq and glibc).

The __rseq_refcount TLS variable is static to the librseq library. It
ensures that rseq syscall registration/unregistration happens only for
the most early/late caller to rseq_{,un}register_current_thread for each
thread, thus ensuring that rseq is registered across the lifetime of all
rseq users for a given thread.

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
CC: Shuah Khan <shuah@kernel.org>
CC: Carlos O'Donell <carlos@redhat.com>
CC: Florian Weimer <fweimer@redhat.com>
CC: Joseph Myers <joseph@codesourcery.com>
CC: Szabolcs Nagy <szabolcs.nagy@arm.com>
CC: Thomas Gleixner <tglx@linutronix.de>
CC: Ben Maurer <bmaurer@fb.com>
CC: Peter Zijlstra <peterz@infradead.org>
CC: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
CC: Boqun Feng <boqun.feng@gmail.com>
CC: Will Deacon <will.deacon@arm.com>
CC: Dave Watson <davejwatson@fb.com>
CC: Paul Turner <pjt@google.com>
CC: linux-api@vger.kernel.org
Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>

authored by

Mathieu Desnoyers and committed by
Shuah Khan
5b0c308a a3e3131f

+48 -8
+47 -8
tools/testing/selftests/rseq/rseq.c
··· 25 25 #include <syscall.h> 26 26 #include <assert.h> 27 27 #include <signal.h> 28 + #include <limits.h> 28 29 29 30 #include "rseq.h" 30 31 31 32 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) 32 33 33 - __attribute__((tls_model("initial-exec"))) __thread 34 - volatile struct rseq __rseq_abi = { 34 + __thread volatile struct rseq __rseq_abi = { 35 35 .cpu_id = RSEQ_CPU_ID_UNINITIALIZED, 36 36 }; 37 37 38 - static __attribute__((tls_model("initial-exec"))) __thread 39 - volatile int refcount; 38 + /* 39 + * Shared with other libraries. This library may take rseq ownership if it is 40 + * still 0 when executing the library constructor. Set to 1 by library 41 + * constructor when handling rseq. Set to 0 in destructor if handling rseq. 42 + */ 43 + int __rseq_handled; 44 + 45 + /* Whether this library have ownership of rseq registration. */ 46 + static int rseq_ownership; 47 + 48 + static __thread volatile uint32_t __rseq_refcount; 40 49 41 50 static void signal_off_save(sigset_t *oldset) 42 51 { ··· 78 69 int rc, ret = 0; 79 70 sigset_t oldset; 80 71 72 + if (!rseq_ownership) 73 + return 0; 81 74 signal_off_save(&oldset); 82 - if (refcount++) 75 + if (__rseq_refcount == UINT_MAX) { 76 + ret = -1; 77 + goto end; 78 + } 79 + if (__rseq_refcount++) 83 80 goto end; 84 81 rc = sys_rseq(&__rseq_abi, sizeof(struct rseq), 0, RSEQ_SIG); 85 82 if (!rc) { ··· 93 78 goto end; 94 79 } 95 80 if (errno != EBUSY) 96 - __rseq_abi.cpu_id = -2; 81 + __rseq_abi.cpu_id = RSEQ_CPU_ID_REGISTRATION_FAILED; 97 82 ret = -1; 98 - refcount--; 83 + __rseq_refcount--; 99 84 end: 100 85 signal_restore(oldset); 101 86 return ret; ··· 106 91 int rc, ret = 0; 107 92 sigset_t oldset; 108 93 94 + if (!rseq_ownership) 95 + return 0; 109 96 signal_off_save(&oldset); 110 - if (--refcount) 97 + if (!__rseq_refcount) { 98 + ret = -1; 99 + goto end; 100 + } 101 + if (--__rseq_refcount) 111 102 goto end; 112 103 rc = sys_rseq(&__rseq_abi, sizeof(struct rseq), 113 104 RSEQ_FLAG_UNREGISTER, RSEQ_SIG); 114 105 if (!rc) 115 106 goto end; 107 + __rseq_refcount = 1; 116 108 ret = -1; 117 109 end: 118 110 signal_restore(oldset); ··· 136 114 abort(); 137 115 } 138 116 return cpu; 117 + } 118 + 119 + void __attribute__((constructor)) rseq_init(void) 120 + { 121 + /* Check whether rseq is handled by another library. */ 122 + if (__rseq_handled) 123 + return; 124 + __rseq_handled = 1; 125 + rseq_ownership = 1; 126 + } 127 + 128 + void __attribute__((destructor)) rseq_fini(void) 129 + { 130 + if (!rseq_ownership) 131 + return; 132 + __rseq_handled = 0; 133 + rseq_ownership = 0; 139 134 }
+1
tools/testing/selftests/rseq/rseq.h
··· 44 44 #endif 45 45 46 46 extern __thread volatile struct rseq __rseq_abi; 47 + extern int __rseq_handled; 47 48 48 49 #define rseq_likely(x) __builtin_expect(!!(x), 1) 49 50 #define rseq_unlikely(x) __builtin_expect(!!(x), 0)