From bb8295ae4f1224db2236fdd3134912e093ed20d9 Mon Sep 17 00:00:00 2001
From: bb-cat <ningyu9@huawei.com>
Date: Wed, 2 Mar 2022 15:10:24 +0800
Subject: [PATCH 16/16] zdtm: add rseq02 transition test with NO_RESTART CS
 flag Signed-off-by: Alexander Mikhalitsyn
 <alexander.mikhalitsyn@virtuozzo.com>

---
 test/zdtm/transition/Makefile    |  2 +
 test/zdtm/transition/rseq01.c    | 61 +++++++++++++++++++-
 test/zdtm/transition/rseq02.c    |  1 +
 test/zdtm/transition/rseq02.desc |  1 +
 4 files changed, 63 insertions(+), 2 deletions(-)
 create mode 120000 test/zdtm/transition/rseq02.c
 create mode 120000 test/zdtm/transition/rseq02.desc

diff --git a/test/zdtm/transition/Makefile b/test/zdtm/transition/Makefile
index fae4e27..378a4fc 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 NOABORT
 
 %: %.sh
 	cp $< $@
diff --git a/test/zdtm/transition/rseq01.c b/test/zdtm/transition/rseq01.c
index 5fac5a6..25e1d61 100644
--- a/test/zdtm/transition/rseq01.c
+++ b/test/zdtm/transition/rseq01.c
@@ -53,6 +53,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;
@@ -104,6 +116,7 @@ static int rseq_addv(intptr_t *v, intptr_t count, int cpu)
 {
 	double a = 10000000000000000.0;
 	double b = -1;
+	uint64_t rseq_cs1, rseq_cs2;
 	/*test_msg("enter %f %f\n", a, b);*/
 
 	/* clang-format off */
@@ -129,6 +142,9 @@ static int rseq_addv(intptr_t *v, intptr_t count, int cpu)
 		"dec %%rcx\n\t"
 		"jnz 5b\n\t"
 		"fstpl %[y]\n\t"
+		"movq %%rax, %[rseq_cs_check2]\n\t"
+		"movq %[rseq_cs], %%rax\n\t"
+		"movq %%rax, %[rseq_cs_check1]\n\t"
 		"2:\n\t"
 		".pushsection __rseq_failure, \"ax\"\n\t"
 		/* Disassembler-friendly signature: nopl <sig>(%rip). */
@@ -143,6 +159,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),
@@ -153,8 +171,20 @@ static int rseq_addv(intptr_t *v, intptr_t count, int cpu)
 	);
 	/* clang-format on */
 	/*test_msg("exit %f %f\n", a, b);*/
+	test_msg("%lx %lx\n", rseq_cs1, rseq_cs2);
+	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 wasn't restored it correctly.
+		 * That's a bug picture.
+		 */
+		return -1;
+	}
 	return 0;
 abort:
+	test_msg("%lx %lx\n", rseq_cs1, rseq_cs2);
 	/*test_msg("abort %f %f\n", a, b);*/
 	return -1;
 }
@@ -177,21 +207,48 @@ 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/master/kernel/rseq.c#L192
+	 */
+#ifdef NOABORT
+	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);
-		if (ret)
+#ifndef NOABORT
+		/* just ignore abort */
+		ret = 0;
+#else
+		if (ret) {
 			fail("Failed to increment per-cpu counter");
+			break;
+		} else {
+			//test_msg("cpu_data[%d] == %ld\n", cpu, (long int)cpu_data[cpu]);
+		}
+#endif
 	}
 
 	test_waitsig();
 
 	check_thread();
-	pass();
+
+	if (ret)
+		fail();
+	else
+		pass();
 
 	return 0;
 }
diff --git a/test/zdtm/transition/rseq02.c b/test/zdtm/transition/rseq02.c
new file mode 120000
index 0000000..d564917
--- /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 0000000..b888f0d
--- /dev/null
+++ b/test/zdtm/transition/rseq02.desc
@@ -0,0 +1 @@
+rseq01.desc
\ No newline at end of file
-- 
2.30.0

