[CRIU] [PATCH] test: add basic test for uffd events
Mike Rapoport
rppt at linux.vnet.ibm.com
Wed Feb 8 04:13:58 PST 2017
The lazy-pages daemon have to properly track changes to virtual memory
layout of the restored process. The test verifies that lazy-pages daemon
properly reacts to fork(), exit(), madvise(MADV_DONTNEED) and mremap()
events.
Currently, no zdtm tests would generate UFFD_EVENT_{REMAP,REMOVE}.
Signed-off-by: Mike Rapoport <rppt at linux.vnet.ibm.com>
---
test/zdtm/static/Makefile | 1 +
test/zdtm/static/uffd-events.c | 188 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 189 insertions(+)
create mode 100644 test/zdtm/static/uffd-events.c
diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile
index c24ee8f..080a7b8 100644
--- a/test/zdtm/static/Makefile
+++ b/test/zdtm/static/Makefile
@@ -172,6 +172,7 @@ TST_NOFILE := \
macvlan \
cr_veth \
sock_peercred \
+ uffd-events \
# jobctl00 \
ifneq ($(SRCARCH),arm)
diff --git a/test/zdtm/static/uffd-events.c b/test/zdtm/static/uffd-events.c
new file mode 100644
index 0000000..9939c86
--- /dev/null
+++ b/test/zdtm/static/uffd-events.c
@@ -0,0 +1,188 @@
+#define _GNU_SOURCE
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <linux/limits.h>
+#include "zdtmtst.h"
+
+const char *test_doc = "Test uffd events";
+const char *test_author = "Mike Rapoport <rppt at linux.vnet.ibm.com>";
+
+#define NR_MAPS 5
+#define MAP_SIZE (1 << 20)
+
+static void *map[NR_MAPS];
+
+static int create_mappings(void)
+{
+ uint32_t crc;
+ int i;
+
+ for (i = 0; i < NR_MAPS; i++) {
+ map[i] = mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE,
+ MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+ if (map[i] == MAP_FAILED) {
+ fail("mmap failed");
+ return 1;
+ }
+
+ crc = i;
+ datagen(map[i], MAP_SIZE, &crc);
+ }
+
+ return 0;
+}
+
+static int verify_zeroes(void *m)
+{
+ int i;
+
+ for (i = 0; i < MAP_SIZE; i += PAGE_SIZE) {
+ char *p = m + i;
+ if (*p != 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+static int check_madv_dn(int idx)
+{
+ void *m = map[idx];
+
+ if (madvise(m, MAP_SIZE, MADV_DONTNEED)) {
+ fail("madvise failed");
+ return 1;
+ }
+
+ if (verify_zeroes(m)) {
+ fail("not zero");
+ return 1;
+ }
+
+ return 0;
+}
+
+static int check_mremap_grow(int idx)
+{
+ void *m = map[idx];
+ uint32_t crc = idx;
+
+ m = mremap(m, MAP_SIZE, MAP_SIZE * 2, MREMAP_MAYMOVE);
+ if (m == MAP_FAILED) {
+ fail("mremap failed");
+ return 1;
+ }
+
+ if (datachk(m, MAP_SIZE, &crc)) {
+ fail("Mem corrupted");
+ return 1;
+ }
+
+ /* the new part of the mapping should be filled with zeroes */
+ m += MAP_SIZE;
+ if (verify_zeroes(m)) {
+ fail("not zeroes");
+ return 1;
+ }
+
+ return 0;
+}
+
+static int check_swapped_mappings(int idx)
+{
+ uint32_t crc = idx;
+ void *m1 = map[idx];
+ void *m2 = map[idx + 1];
+ void *p = map[0];
+
+ p = mremap(m1, MAP_SIZE, MAP_SIZE, MREMAP_MAYMOVE | MREMAP_FIXED, p);
+ if (p == MAP_FAILED) {
+ fail("mremap failed");
+ return 1;
+ }
+
+ m1 = mremap(m2, MAP_SIZE, MAP_SIZE, MREMAP_MAYMOVE | MREMAP_FIXED, m1);
+ if (m1 == MAP_FAILED) {
+ fail("mremap failed");
+ return 1;
+ }
+
+ m2 = mremap(p, MAP_SIZE, MAP_SIZE, MREMAP_MAYMOVE | MREMAP_FIXED, m2);
+ if (m2 == MAP_FAILED) {
+ fail("mremap failed");
+ return 1;
+ }
+
+ if (datachk(m2, MAP_SIZE, &crc)) {
+ fail("Mem corrupted");
+ return 1;
+ }
+
+ crc = idx + 1;
+ if (datachk(m1, MAP_SIZE, &crc)) {
+ fail("Mem corrupted");
+ return 1;
+ }
+
+ return 0;
+}
+
+int main(int argc, char ** argv)
+{
+ uint32_t crc;
+ int pid;
+
+ test_init(argc, argv);
+
+ if (create_mappings())
+ return -1;
+
+ test_daemon();
+ test_waitsig();
+
+ /* run some page faults */
+ crc = 0;
+ if (datachk(map[0], MAP_SIZE, &crc)) {
+ fail("Mem corrupted");
+ return 1;
+ }
+
+ pid = fork();
+ if (pid < 0) {
+ fail("Can't fork");
+ return 1;
+ }
+
+ /* check madvise(MADV_DONTNEED) */
+ if (check_madv_dn(1))
+ return 1;
+
+ /* check growing mremap */
+ if (check_mremap_grow(2))
+ return 1;
+
+ /* check swapped mappings */
+ if (check_swapped_mappings(3))
+ return 1;
+
+ if (pid) {
+ int status;
+
+ waitpid(-1, &status, 0);
+ if (status) {
+ fail("child failed");
+ return status;
+ }
+ }
+
+ pass();
+ return 0;
+}
--
1.9.1
More information about the CRIU
mailing list