]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
selftests/rseq: Make registration flexible for legacy and optimized mode
authorThomas Gleixner <tglx@kernel.org>
Sun, 26 Apr 2026 16:13:54 +0000 (18:13 +0200)
committerPeter Zijlstra <peterz@infradead.org>
Tue, 5 May 2026 14:03:11 +0000 (16:03 +0200)
rseq_register_current_thread() either uses the glibc registered RSEQ region
or registers it's own region with the legacy size of 32 bytes.

That worked so far, but becomes a problem when the kernel implements a
distinction between legacy and performance optimized behavior based on the
registration size as that does not allow to test both modes with the self
test suite.

Add two arguments to the function. One to enforce that the registration is
not using libc provided mode and one to tell the registration to use the
legacy size and not the kernel advertised size.

Rename it and make the original one a inline wrapper which preserves the
existing behavior.

Fixes: 566d8015f7ee ("rseq: Avoid CPU/MM CID updates when no event pending")
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Dmitry Vyukov <dvyukov@google.com>
Tested-by: Dmitry Vyukov <dvyukov@google.com>
Link: https://patch.msgid.link/20260428224427.677889423%40kernel.org
Cc: stable@vger.kernel.org
tools/testing/selftests/rseq/rseq-abi.h
tools/testing/selftests/rseq/rseq.c
tools/testing/selftests/rseq/rseq.h

index ecef315204b271f50bccf8f2a847986357fd6f2e..5f4ea2152c2fd88660b28fad81fc4dc12e644b0d 100644 (file)
@@ -191,10 +191,15 @@ struct rseq_abi {
         */
        struct rseq_abi_slice_ctrl slice_ctrl;
 
+       /*
+        * Place holder to push the size above 32 bytes.
+        */
+       __u8 __reserved;
+
        /*
         * Flexible array member at end of structure, after last feature field.
         */
        char end[];
-} __attribute__((aligned(4 * sizeof(__u64))));
+} __attribute__((aligned(256)));
 
 #endif /* _RSEQ_ABI_H */
index a736727b83c1eb0219f0da40ce1c39b93d925aad..be0d0a97031ef2214bca5b3a87f718fea7f78d82 100644 (file)
@@ -56,6 +56,7 @@ ptrdiff_t rseq_offset;
  * unsuccessful.
  */
 unsigned int rseq_size = -1U;
+static unsigned int rseq_alloc_size;
 
 /* Flags used during rseq registration.  */
 unsigned int rseq_flags;
@@ -115,29 +116,17 @@ bool rseq_available(void)
        }
 }
 
-/* The rseq areas need to be at least 32 bytes. */
-static
-unsigned int get_rseq_min_alloc_size(void)
-{
-       unsigned int alloc_size = rseq_size;
-
-       if (alloc_size < ORIG_RSEQ_ALLOC_SIZE)
-               alloc_size = ORIG_RSEQ_ALLOC_SIZE;
-       return alloc_size;
-}
-
 /*
  * Return the feature size supported by the kernel.
  *
  * Depending on the value returned by getauxval(AT_RSEQ_FEATURE_SIZE):
  *
- * 0:   Return ORIG_RSEQ_FEATURE_SIZE (20)
+ *   0: Return ORIG_RSEQ_FEATURE_SIZE (20)
  * > 0: Return the value from getauxval(AT_RSEQ_FEATURE_SIZE).
  *
  * It should never return a value below ORIG_RSEQ_FEATURE_SIZE.
  */
-static
-unsigned int get_rseq_kernel_feature_size(void)
+static unsigned int get_rseq_kernel_feature_size(void)
 {
        unsigned long auxv_rseq_feature_size, auxv_rseq_align;
 
@@ -152,15 +141,24 @@ unsigned int get_rseq_kernel_feature_size(void)
                return ORIG_RSEQ_FEATURE_SIZE;
 }
 
-int rseq_register_current_thread(void)
+int __rseq_register_current_thread(bool nolibc, bool legacy)
 {
+       unsigned int size;
        int rc;
 
        if (!rseq_ownership) {
                /* Treat libc's ownership as a successful registration. */
-               return 0;
+               return nolibc ? -EBUSY : 0;
        }
-       rc = sys_rseq(&__rseq.abi, get_rseq_min_alloc_size(), 0, RSEQ_SIG);
+
+       /* The minimal allocation size is 32, which is the legacy allocation size */
+       size = get_rseq_kernel_feature_size();
+       if (legacy || size < ORIG_RSEQ_ALLOC_SIZE)
+               rseq_alloc_size = ORIG_RSEQ_ALLOC_SIZE;
+       else
+               rseq_alloc_size = size;
+
+       rc = sys_rseq(&__rseq.abi, rseq_alloc_size, 0, RSEQ_SIG);
        if (rc) {
                /*
                 * After at least one thread has registered successfully
@@ -179,9 +177,8 @@ int rseq_register_current_thread(void)
         * The first thread to register sets the rseq_size to mimic the libc
         * behavior.
         */
-       if (RSEQ_READ_ONCE(rseq_size) == 0) {
-               RSEQ_WRITE_ONCE(rseq_size, get_rseq_kernel_feature_size());
-       }
+       if (RSEQ_READ_ONCE(rseq_size) == 0)
+               RSEQ_WRITE_ONCE(rseq_size, size);
 
        return 0;
 }
@@ -194,7 +191,7 @@ int rseq_unregister_current_thread(void)
                /* Treat libc's ownership as a successful unregistration. */
                return 0;
        }
-       rc = sys_rseq(&__rseq.abi, get_rseq_min_alloc_size(), RSEQ_ABI_FLAG_UNREGISTER, RSEQ_SIG);
+       rc = sys_rseq(&__rseq.abi, rseq_alloc_size, RSEQ_ABI_FLAG_UNREGISTER, RSEQ_SIG);
        if (rc)
                return -1;
        return 0;
index f51a5fdb044431585cbc57b6ae07fa2f59aefe23..c62ebb9290c0100cf08adf43404c70c000edb0ae 100644 (file)
@@ -8,6 +8,7 @@
 #ifndef RSEQ_H
 #define RSEQ_H
 
+#include <assert.h>
 #include <stdint.h>
 #include <stdbool.h>
 #include <pthread.h>
@@ -142,7 +143,12 @@ static inline struct rseq_abi *rseq_get_abi(void)
  * succeed. A restartable sequence executed from a non-registered
  * thread will always fail.
  */
-int rseq_register_current_thread(void);
+int __rseq_register_current_thread(bool nolibc, bool legacy);
+
+static inline int rseq_register_current_thread(void)
+{
+       return __rseq_register_current_thread(false, false);
+}
 
 /*
  * Unregister rseq for current thread.