mirror of
https://github.com/checkpoint-restore/criu.git
synced 2026-01-23 02:14:37 +00:00
zdtm: add transition/rseq01 test for amd64
Signed-off-by: Alexander Mikhalitsyn <alexander.mikhalitsyn@virtuozzo.com>
This commit is contained in:
parent
2d3354e7b6
commit
064e9925a0
3 changed files with 227 additions and 0 deletions
|
|
@ -23,6 +23,7 @@ TST_NOFILE = \
|
|||
lazy-thp \
|
||||
pid_reuse \
|
||||
pidfd_store_sk \
|
||||
rseq01 \
|
||||
|
||||
|
||||
TST_FILE = \
|
||||
|
|
|
|||
225
test/zdtm/transition/rseq01.c
Normal file
225
test/zdtm/transition/rseq01.c
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
#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>";
|
||||
/*
|
||||
* Thanks to Mathieu Desnoyers <mathieu.desnoyers@efficios.com> (rseq author)
|
||||
* who helped me with review and debugging the problem on the Alpine Linux.
|
||||
*
|
||||
* 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))
|
||||
|
||||
#define rseq_after_asm_goto() asm volatile("" : : : "memory")
|
||||
|
||||
static int rseq_addv(intptr_t *v, intptr_t count, int cpu)
|
||||
{
|
||||
double a = 10000000000000000.0;
|
||||
double b = -1;
|
||||
|
||||
/* 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"
|
||||
"fldl %[x]\n\t" /* we have st clobbered */
|
||||
"leaq cs_obj(%%rip), %%rax\n\t"
|
||||
"1:\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"
|
||||
"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 */
|
||||
rseq_after_asm_goto();
|
||||
return 0;
|
||||
abort:
|
||||
rseq_after_asm_goto();
|
||||
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);
|
||||
|
||||
/* just ignore abort */
|
||||
ret = 0;
|
||||
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
||||
test_waitsig();
|
||||
|
||||
check_thread();
|
||||
|
||||
if (ret)
|
||||
fail();
|
||||
else
|
||||
pass();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* #if defined(__x86_64__) */
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
test_init(argc, argv);
|
||||
skip("Unsupported arch");
|
||||
test_daemon();
|
||||
test_waitsig();
|
||||
pass();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* #if defined(__x86_64__) */
|
||||
1
test/zdtm/transition/rseq01.desc
Normal file
1
test/zdtm/transition/rseq01.desc
Normal file
|
|
@ -0,0 +1 @@
|
|||
{'flavor': 'h', 'arch': 'x86_64', 'feature': 'get_rseq_conf'}
|
||||
Loading…
Add table
Add a link
Reference in a new issue