diff options
author | Alexander Mikhalitsyn <alexander.mikhalitsyn@virtuozzo.com> | 2022-02-23 23:20:29 +0300 |
---|---|---|
committer | Andrei Vagin <avagin@gmail.com> | 2022-04-29 03:53:52 +0300 |
commit | db9ec13616625f98db95b00438a370f8a660bfee (patch) | |
tree | f19c89d56209d5eaeeaee49361767c611a6f0ff8 | |
parent | 1e0bed3d692b4a368924a21aa4555a27cc9ab9d6 (diff) |
zdtm: add rseq02 transition test with NO_RESTART CS flag
Signed-off-by: Alexander Mikhalitsyn <alexander.mikhalitsyn@virtuozzo.com>
-rw-r--r-- | test/zdtm/transition/Makefile | 2 | ||||
-rw-r--r-- | test/zdtm/transition/rseq01.c | 47 | ||||
l--------- | test/zdtm/transition/rseq02.c | 1 | ||||
l--------- | test/zdtm/transition/rseq02.desc | 1 |
4 files changed, 51 insertions, 0 deletions
diff --git a/test/zdtm/transition/Makefile b/test/zdtm/transition/Makefile index fae4e27b3..98440f4e2 100644 --- a/test/zdtm/transition/Makefile +++ b/test/zdtm/transition/Makefile @@ -24,6 +24,7 @@ TST_NOFILE = \ pid_reuse \ pidfd_store_sk \ rseq01 \ + rseq02 \ TST_FILE = \ @@ -82,6 +83,7 @@ ptrace: LDFLAGS += -pthread fork2: CFLAGS += -D FORK2 thread-bomb.o: CFLAGS += -pthread thread-bomb: LDFLAGS += -pthread +rseq02: CFLAGS += -D NORESTART %: %.sh cp $< $@ diff --git a/test/zdtm/transition/rseq01.c b/test/zdtm/transition/rseq01.c index 7a22854a3..b6d470785 100644 --- a/test/zdtm/transition/rseq01.c +++ b/test/zdtm/transition/rseq01.c @@ -58,6 +58,18 @@ enum rseq_flags { RSEQ_FLAG_UNREGISTER = (1 << 0), }; +enum rseq_cs_flags_bit { + RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT_BIT = 0, + RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL_BIT = 1, + RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE_BIT = 2, +}; + +enum rseq_cs_flags { + RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT = (1U << RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT_BIT), + RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL = (1U << RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL_BIT), + RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE = (1U << RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE_BIT), +}; + struct rseq { uint32_t cpu_id_start; uint32_t cpu_id; @@ -111,6 +123,7 @@ static int rseq_addv(intptr_t *v, intptr_t count, int cpu) { double a = 10000000000000000.0; double b = -1; + uint64_t rseq_cs1 = 0, rseq_cs2 = 0; /* clang-format off */ __asm__ __volatile__ goto( @@ -134,6 +147,9 @@ static int rseq_addv(intptr_t *v, intptr_t count, int cpu) "fsqrt\n\t" /* heavy instruction */ "dec %%rcx\n\t" "jnz 5b\n\t" + "movq %%rax, %[rseq_cs_check2]\n\t" + "movq %[rseq_cs], %%rax\n\t" + "movq %%rax, %[rseq_cs_check1]\n\t" "fstpl %[y]\n\t" "2:\n\t" ".pushsection __rseq_failure, \"ax\"\n\t" @@ -149,6 +165,8 @@ static int rseq_addv(intptr_t *v, intptr_t count, int cpu) : [cpu_id] "r" (cpu), [current_cpu_id] "m" (rseq_ptr->cpu_id), [rseq_cs] "m" (rseq_ptr->rseq_cs), + [rseq_cs_check1] "m" (rseq_cs1), + [rseq_cs_check2] "m" (rseq_cs2), /* final store input */ [v] "m" (*v), [count] "er" (count), @@ -159,9 +177,22 @@ static int rseq_addv(intptr_t *v, intptr_t count, int cpu) ); /* clang-format on */ rseq_after_asm_goto(); + test_msg("exit %lx %lx %f %f\n", rseq_cs1, rseq_cs2, a, b); + if (rseq_cs1 != rseq_cs2) { + /* + * It means that we finished critical section + * *normally* (haven't jumped to abort) but the kernel had cleaned up + * rseq_ptr->rseq_cs before we left critical section + * and CRIU didn't restore it correctly. + * That's a bug picture. + */ + return -1; + } + return 0; abort: rseq_after_asm_goto(); + test_msg("abort %lx %lx %f %f\n", rseq_cs1, rseq_cs2, a, b); return -1; } @@ -183,16 +214,32 @@ int main(int argc, char *argv[]) fail("calloc"); exit(EXIT_FAILURE); } + register_thread(); + /* + * We want to test that RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL + * is handled properly by CRIU, but that flag can be used + * only with all another flags set. + * Please, refer to + * https://github.com/torvalds/linux/blob/ce522ba9/kernel/rseq.c#L192 + */ +#ifdef NORESTART + rseq_ptr->flags = RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT | RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL | + RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE; +#endif + test_daemon(); while (test_go()) { cpu = RSEQ_ACCESS_ONCE(rseq_ptr->cpu_id_start); ret = rseq_addv(&cpu_data[cpu], 2, cpu); +/* NORESTART is NOT set */ +#ifndef NORESTART /* just ignore abort */ ret = 0; +#endif if (ret) break; diff --git a/test/zdtm/transition/rseq02.c b/test/zdtm/transition/rseq02.c new file mode 120000 index 000000000..d56491719 --- /dev/null +++ b/test/zdtm/transition/rseq02.c @@ -0,0 +1 @@ +rseq01.c
\ No newline at end of file diff --git a/test/zdtm/transition/rseq02.desc b/test/zdtm/transition/rseq02.desc new file mode 120000 index 000000000..b888f0da7 --- /dev/null +++ b/test/zdtm/transition/rseq02.desc @@ -0,0 +1 @@ +rseq01.desc
\ No newline at end of file |