[CRIU] [PATCH] zdtm: add transition test for memory

Andrey Vagin avagin at openvz.org
Tue Jan 28 07:10:34 PST 2014


This test does a few operation in a loop
* create a mapping with random flags
* touch a few pages in a new mapping, if it's writable

This test has two processes. The second process goes a predefined value
of steps behind the first one. When we need to check the result, we stop
the first process, wait until the second process come to the same point
and compare these processes. The processes are dumped in different
states, but at the end both processes must be in the same state.

bash -x test/zdtm.sh -s -i 5 -r transition/maps007
...
(00.743662) Error (page-read.c:107): Missing 139773474525184 in parent pagemap, current iov: base=7f1f8c4cf000,len=4096
(00.743696) Error (page-xfer.c:523): Hole 0x7f1f8c4c5000/4096 not found in parent
(00.744196) Error (mem.c:331): Can't dump page with parasite
(00.758201) Error (cr-dump.c:1828): Dumping FAILED.

Signed-off-by: Andrey Vagin <avagin at openvz.org>
---
 test/zdtm/live/transition/Makefile  |   1 +
 test/zdtm/live/transition/maps007.c | 163 ++++++++++++++++++++++++++++++++++++
 2 files changed, 164 insertions(+)
 create mode 100644 test/zdtm/live/transition/maps007.c

diff --git a/test/zdtm/live/transition/Makefile b/test/zdtm/live/transition/Makefile
index 1a39e5e..a4d0127 100644
--- a/test/zdtm/live/transition/Makefile
+++ b/test/zdtm/live/transition/Makefile
@@ -12,6 +12,7 @@ TST_NOFILE	=	\
 		fork		\
 		fork2		\
 		thread-bomb	\
+		maps007		\
 
 TST_FILE	=	\
 		file_read	\
diff --git a/test/zdtm/live/transition/maps007.c b/test/zdtm/live/transition/maps007.c
new file mode 100644
index 0000000..94122f0
--- /dev/null
+++ b/test/zdtm/live/transition/maps007.c
@@ -0,0 +1,163 @@
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <sys/uio.h>
+#include <asm/unistd.h>
+
+#include "zdtmtst.h"
+#include "lock.h"
+
+#define MAP_SIZE (1 << 20)
+#define MEM_SIZE (1 << 29)
+#define PAGE_SIZE 4096
+
+const char *test_doc	= "create random mappings and touch memory";
+
+int sys_process_vm_readv(pid_t pid, void *addr, void *buf, int size)
+{
+	struct iovec lvec = {.iov_base = buf, .iov_len = size };
+	struct iovec rvec = {.iov_base = addr, .iov_len = size };
+	/* workaround bug in glibc with sixth argument of syscall */
+	char nop[PAGE_SIZE];
+
+	memset(nop, 0, sizeof(nop));
+
+	return syscall(__NR_process_vm_readv, pid, &lvec, 1, &rvec, 1, 0);
+}
+
+/* The child follows the parents two steps behind. */
+#define MAX_DELTA 1000
+int main(int argc, char **argv)
+{
+	void *start, *end, *p;
+	pid_t child;
+	struct {
+		uint32_t delta;
+		futex_t stop;
+	} *shm;
+	uint32_t v;
+	unsigned long long count = 0;
+	int i;
+
+	test_init(argc, argv);
+
+	/* shared memory for synchronization */
+	shm = mmap(NULL, PAGE_SIZE, PROT_WRITE | PROT_READ, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
+	if (shm == MAP_FAILED)
+		return -1;
+
+	/* allocate workspace */
+	start = mmap(NULL, MEM_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+	if (start == MAP_FAILED)
+		return -1;
+
+	test_msg("%p-%p\n", start, start + MEM_SIZE);
+
+	end = start + MEM_SIZE;
+
+	v = 0;
+	atomic_set(&shm->delta, v);
+	futex_set(&shm->stop, 0);
+
+	child = fork();
+	if (child < 0) {
+		err("fork");
+		return 1;
+	}
+
+	if (child)
+		test_daemon();
+
+	while (test_go()) {
+		void *ret;
+		unsigned long size;
+		int prot = PROT_NONE;
+
+		if (child) {
+			atomic_inc(&shm->delta);
+		} else {
+			if (!futex_get(&shm->stop))
+				/* MAX_DELTA steps behind the parent */
+				while (atomic_get(&shm->delta) < MAX_DELTA);
+			else if (atomic_get(&shm->delta) == 0)
+				break;
+			atomic_dec(&shm->delta);
+		}
+
+		count++;
+
+		p = start + ((lrand48() * PAGE_SIZE) % MEM_SIZE);
+		size = (lrand48() * PAGE_SIZE) % (end - p);
+		size %= MAP_SIZE;
+		if (size == 0)
+			size = PAGE_SIZE;
+
+		if (lrand48() % 2)
+			prot |= PROT_READ;
+		if (lrand48() % 2)
+			prot |= PROT_EXEC;
+		if (lrand48() % 2)
+			prot |= PROT_WRITE;
+
+		ret = mmap(p, size, prot, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
+		if (ret == MAP_FAILED) {
+			err("%p-%p", p, p + size);
+			goto err;
+		}
+
+		if (!(prot & PROT_WRITE))
+			continue;
+
+		for (i = 0; i < lrand48() % 50; i++) {
+			char *t = p + (lrand48() * PAGE_SIZE) % (size);
+			t[0] = lrand48();
+		}
+	}
+	err("count %d", count);
+
+	if (child == 0) {
+		futex_set_and_wake(&shm->stop, 2);
+		test_waitsig();
+	} else {
+		int readable = 0;
+
+		/* stop the child */
+		futex_set(&shm->stop, 1);
+		/* wait until the child will be in the same point */
+		futex_wait_until(&shm->stop, 2);
+
+		/* check that child and parent have the identical content of memory */
+		for (p = start; p < end; p += PAGE_SIZE) {
+			char rbuf[PAGE_SIZE], lbuf[PAGE_SIZE];
+			int rret, lret;
+
+			lret = sys_process_vm_readv(getpid(), p, lbuf, PAGE_SIZE);
+			rret = sys_process_vm_readv(child, p, rbuf, PAGE_SIZE);
+			if (rret != lret) {
+				err("%p %d %d", p, lret, rret);
+				goto err;
+			}
+			if (lret < 0)
+				continue;
+			readable++;
+			if (memcmp(rbuf, lbuf, PAGE_SIZE)) {
+				err("%p", p);
+				goto err;
+			}
+		}
+		err("readable %d", readable);
+		kill(child, SIGTRAP);
+		wait(NULL);
+		pass();
+	}
+
+	return 0;
+err:
+	kill(child, SIGKILL);
+	return 1;
+}
-- 
1.8.3.1



More information about the CRIU mailing list