see https://github.com/checkpoint-restore/criu/issues/1696 and https://github.com/checkpoint-restore/criu/pull/1706
251 lines
5.8 KiB
Diff
251 lines
5.8 KiB
Diff
From f76aa4ade354649e3291b5e7274c368740b05417 Mon Sep 17 00:00:00 2001
|
|
From: bb-cat <ningyu9@huawei.com>
|
|
Date: Wed, 2 Mar 2022 15:05:34 +0800
|
|
Subject: [PATCH 14/16] zdtm: add rseq transition test for amd64 Signed-off-by:
|
|
Alexander Mikhalitsyn <alexander.mikhalitsyn@virtuozzo.com>
|
|
|
|
---
|
|
test/zdtm/transition/Makefile | 1 +
|
|
test/zdtm/transition/rseq01.c | 208 +++++++++++++++++++
|
|
test/zdtm/transition/rseq01.desc | 1 +
|
|
3 files changed, 210 insertions(+)
|
|
create mode 100644 test/zdtm/transition/rseq01.c
|
|
create mode 100644 test/zdtm/transition/rseq01.desc
|
|
|
|
diff --git a/test/zdtm/transition/Makefile b/test/zdtm/transition/Makefile
|
|
index 9388157..fae4e27 100644
|
|
--- a/test/zdtm/transition/Makefile
|
|
+++ b/test/zdtm/transition/Makefile
|
|
@@ -23,6 +23,7 @@ TST_NOFILE = \
|
|
lazy-thp \
|
|
pid_reuse \
|
|
pidfd_store_sk \
|
|
+ rseq01 \
|
|
|
|
|
|
TST_FILE = \
|
|
diff --git a/test/zdtm/transition/rseq01.c b/test/zdtm/transition/rseq01.c
|
|
new file mode 100644
|
|
index 0000000..5fac5a6
|
|
--- /dev/null
|
|
+++ b/test/zdtm/transition/rseq01.c
|
|
@@ -0,0 +1,208 @@
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+#include <unistd.h>
|
|
+#include <signal.h>
|
|
+#include <string.h>
|
|
+
|
|
+#include <sys/types.h>
|
|
+#include <sys/wait.h>
|
|
+#include <sys/stat.h>
|
|
+#include <sys/mman.h>
|
|
+#include <fcntl.h>
|
|
+#include <pthread.h>
|
|
+#include <syscall.h>
|
|
+
|
|
+#include "zdtmtst.h"
|
|
+
|
|
+#ifdef __has_include
|
|
+# if __has_include ("sys/rseq.h")
|
|
+# include <sys/rseq.h>
|
|
+# endif
|
|
+#endif
|
|
+
|
|
+#if defined(__x86_64__)
|
|
+
|
|
+#if defined(__x86_64__) && defined(RSEQ_SIG)
|
|
+static inline void *thread_pointer(void)
|
|
+{
|
|
+ void *result;
|
|
+ asm("mov %%fs:0, %0" : "=r"(result));
|
|
+ return result;
|
|
+}
|
|
+
|
|
+static inline void unregister_old_rseq(void)
|
|
+{
|
|
+ /* unregister rseq */
|
|
+ syscall(__NR_rseq, (void *)((char *)thread_pointer() + __rseq_offset), __rseq_size, 1, RSEQ_SIG);
|
|
+}
|
|
+#else
|
|
+static inline void unregister_old_rseq(void)
|
|
+{
|
|
+}
|
|
+#endif
|
|
+
|
|
+const char *test_doc = "rseq() transition test";
|
|
+const char *test_author = "Alexander Mikhalitsyn <alexander.mikhalitsyn@virtuozzo.com>";
|
|
+
|
|
+/* parts of code borrowed from https://www.efficios.com/blog/2019/02/08/linux-restartable-sequences/ */
|
|
+
|
|
+/* some useful definitions from kernel uapi */
|
|
+#ifndef RSEQ_SIG
|
|
+
|
|
+enum rseq_flags {
|
|
+ RSEQ_FLAG_UNREGISTER = (1 << 0),
|
|
+};
|
|
+
|
|
+struct rseq {
|
|
+ uint32_t cpu_id_start;
|
|
+ uint32_t cpu_id;
|
|
+ uint64_t rseq_cs;
|
|
+ uint32_t flags;
|
|
+} __attribute__((aligned(4 * sizeof(uint64_t))));
|
|
+
|
|
+#define RSEQ_SIG 0x53053053
|
|
+
|
|
+#endif
|
|
+
|
|
+#ifndef __NR_rseq
|
|
+#define __NR_rseq 334
|
|
+#endif
|
|
+/* EOF */
|
|
+
|
|
+static volatile struct rseq *rseq_ptr;
|
|
+static __thread volatile struct rseq __rseq_abi;
|
|
+
|
|
+static int sys_rseq(volatile struct rseq *rseq_abi, uint32_t rseq_len, int flags, uint32_t sig)
|
|
+{
|
|
+ return syscall(__NR_rseq, rseq_abi, rseq_len, flags, sig);
|
|
+}
|
|
+
|
|
+static void register_thread(void)
|
|
+{
|
|
+ int rc;
|
|
+ unregister_old_rseq();
|
|
+ rc = sys_rseq(rseq_ptr, sizeof(struct rseq), 0, RSEQ_SIG);
|
|
+ if (rc) {
|
|
+ fail("Failed to register rseq");
|
|
+ exit(1);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void check_thread(void)
|
|
+{
|
|
+ int rc;
|
|
+ rc = sys_rseq(rseq_ptr, sizeof(struct rseq), 0, RSEQ_SIG);
|
|
+ if (!(rc && errno == EBUSY)) {
|
|
+ fail("Failed to check rseq %d", rc);
|
|
+ exit(1);
|
|
+ }
|
|
+}
|
|
+
|
|
+#define RSEQ_ACCESS_ONCE(x) (*(__volatile__ __typeof__(x) *)&(x))
|
|
+
|
|
+static int rseq_addv(intptr_t *v, intptr_t count, int cpu)
|
|
+{
|
|
+ double a = 10000000000000000.0;
|
|
+ double b = -1;
|
|
+ /*test_msg("enter %f %f\n", a, b);*/
|
|
+
|
|
+ /* clang-format off */
|
|
+ __asm__ __volatile__ goto(
|
|
+ ".pushsection __rseq_table, \"aw\"\n\t"
|
|
+ ".balign 32\n\t"
|
|
+ "cs_obj:\n\t"
|
|
+ /* version, flags */
|
|
+ ".long 0, 0\n\t"
|
|
+ /* start_ip, post_commit_offset, abort_ip */
|
|
+ ".quad 1f, (2f-1f), 4f\n\t"
|
|
+ ".popsection\n\t"
|
|
+ "1:\n\t"
|
|
+ "leaq cs_obj(%%rip), %%rax\n\t"
|
|
+ "movq %%rax, %[rseq_cs]\n\t"
|
|
+ "cmpl %[cpu_id], %[current_cpu_id]\n\t"
|
|
+ "jnz 4f\n\t"
|
|
+ "addq %[count], %[v]\n\t" /* final store */
|
|
+ "mov $10000000, %%rcx\n\t"
|
|
+ "fldl %[x]\n\t" /* we have st clobbered */
|
|
+ "5:\n\t"
|
|
+ "fsqrt\n\t" /* heavy instruction */
|
|
+ "dec %%rcx\n\t"
|
|
+ "jnz 5b\n\t"
|
|
+ "fstpl %[y]\n\t"
|
|
+ "2:\n\t"
|
|
+ ".pushsection __rseq_failure, \"ax\"\n\t"
|
|
+ /* Disassembler-friendly signature: nopl <sig>(%rip). */
|
|
+ ".byte 0x0f, 0xb9, 0x3d\n\t"
|
|
+ ".long 0x53053053\n\t" /* RSEQ_FLAGS */
|
|
+ "4:\n\t"
|
|
+ /*"fstpl %[y]\n\t"*/
|
|
+ "jmp %l[abort]\n\t"
|
|
+ /*"jmp 1b\n\t"*/
|
|
+ ".popsection\n\t"
|
|
+ : /* gcc asm goto does not allow outputs */
|
|
+ : [cpu_id] "r" (cpu),
|
|
+ [current_cpu_id] "m" (rseq_ptr->cpu_id),
|
|
+ [rseq_cs] "m" (rseq_ptr->rseq_cs),
|
|
+ /* final store input */
|
|
+ [v] "m" (*v),
|
|
+ [count] "er" (count),
|
|
+ [x] "m" (a),
|
|
+ [y] "m" (b)
|
|
+ : "memory", "cc", "rax", "rcx", "st"
|
|
+ : abort
|
|
+ );
|
|
+ /* clang-format on */
|
|
+ /*test_msg("exit %f %f\n", a, b);*/
|
|
+ return 0;
|
|
+abort:
|
|
+ /*test_msg("abort %f %f\n", a, b);*/
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+int main(int argc, char *argv[])
|
|
+{
|
|
+ int cpu = 0;
|
|
+ int ret;
|
|
+ intptr_t *cpu_data;
|
|
+ long nr_cpus;
|
|
+
|
|
+ rseq_ptr = &__rseq_abi;
|
|
+ memset((void *)rseq_ptr, 0, sizeof(struct rseq));
|
|
+
|
|
+ test_init(argc, argv);
|
|
+ nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
|
|
+
|
|
+ cpu_data = calloc(nr_cpus, sizeof(*cpu_data));
|
|
+ if (!cpu_data) {
|
|
+ fail("calloc");
|
|
+ exit(EXIT_FAILURE);
|
|
+ }
|
|
+ register_thread();
|
|
+
|
|
+ test_daemon();
|
|
+
|
|
+ while (test_go()) {
|
|
+ cpu = RSEQ_ACCESS_ONCE(rseq_ptr->cpu_id_start);
|
|
+ ret = rseq_addv(&cpu_data[cpu], 2, cpu);
|
|
+ if (ret)
|
|
+ fail("Failed to increment per-cpu counter");
|
|
+ }
|
|
+
|
|
+ test_waitsig();
|
|
+
|
|
+ check_thread();
|
|
+ pass();
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+#else
|
|
+
|
|
+int main(int argc, char *argv[])
|
|
+{
|
|
+ test_init(argc, argv);
|
|
+ skip("Unsupported arch");
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+#endif
|
|
diff --git a/test/zdtm/transition/rseq01.desc b/test/zdtm/transition/rseq01.desc
|
|
new file mode 100644
|
|
index 0000000..0324fa3
|
|
--- /dev/null
|
|
+++ b/test/zdtm/transition/rseq01.desc
|
|
@@ -0,0 +1 @@
|
|
+{'flavor': 'h', 'arch': 'x86_64', 'feature': 'get_rseq_conf'}
|
|
--
|
|
2.30.0
|
|
|