criu/0063-zdtm-add-pinmem-testcase.patch
fu.lin 9c2b383d61 criu: backport kinds of features/bugfix
Signed-off-by: fu.lin <fulin10@huawei.com>
2022-04-13 17:01:52 +08:00

2092 lines
54 KiB
Diff
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

From 4f9fed183bcfda1285d7e99136ff02e3778012ba Mon Sep 17 00:00:00 2001
From: "fu.lin" <fulin10@huawei.com>
Date: Tue, 25 Jan 2022 19:00:33 +0800
Subject: [PATCH 63/72] zdtm: add pinmem testcase
Signed-off-by: fu.lin <fulin10@huawei.com>
---
test/zdtm.py | 68 ++-
test/zdtm/customization/Makefile | 23 +-
test/zdtm/customization/get_smaps_bits.c | 127 +++++
test/zdtm/customization/get_smaps_bits.h | 6 +
test/zdtm/customization/ipc.desc | 2 +-
test/zdtm/customization/maps00.c | 271 +++++++++++
test/zdtm/customization/maps00.desc | 1 +
test/zdtm/customization/maps007.c | 178 +++++++
test/zdtm/customization/maps007.desc | 1 +
test/zdtm/customization/maps008.c | 514 ++++++++++++++++++++
test/zdtm/customization/maps008.desc | 1 +
test/zdtm/customization/maps01.c | 183 +++++++
test/zdtm/customization/maps01.desc | 1 +
test/zdtm/customization/maps02.c | 111 +++++
test/zdtm/customization/maps02.desc | 1 +
test/zdtm/customization/maps04.c | 57 +++
test/zdtm/customization/maps04.desc | 1 +
test/zdtm/customization/maps05.c | 91 ++++
test/zdtm/customization/maps05.desc | 1 +
test/zdtm/customization/maps06.c | 70 +++
test/zdtm/customization/maps06.desc | 1 +
test/zdtm/customization/maps_file_prot.c | 53 ++
test/zdtm/customization/maps_file_prot.desc | 1 +
test/zdtm_ct.c | 13 +-
24 files changed, 1766 insertions(+), 10 deletions(-)
create mode 100644 test/zdtm/customization/get_smaps_bits.c
create mode 100644 test/zdtm/customization/get_smaps_bits.h
create mode 100644 test/zdtm/customization/maps00.c
create mode 100644 test/zdtm/customization/maps00.desc
create mode 100644 test/zdtm/customization/maps007.c
create mode 100644 test/zdtm/customization/maps007.desc
create mode 100644 test/zdtm/customization/maps008.c
create mode 100644 test/zdtm/customization/maps008.desc
create mode 100644 test/zdtm/customization/maps01.c
create mode 100644 test/zdtm/customization/maps01.desc
create mode 100644 test/zdtm/customization/maps02.c
create mode 100644 test/zdtm/customization/maps02.desc
create mode 100644 test/zdtm/customization/maps04.c
create mode 100644 test/zdtm/customization/maps04.desc
create mode 100644 test/zdtm/customization/maps05.c
create mode 100644 test/zdtm/customization/maps05.desc
create mode 100644 test/zdtm/customization/maps06.c
create mode 100644 test/zdtm/customization/maps06.desc
create mode 100644 test/zdtm/customization/maps_file_prot.c
create mode 100644 test/zdtm/customization/maps_file_prot.desc
diff --git a/test/zdtm.py b/test/zdtm.py
index 1b2c7da..d3b146f 100755
--- a/test/zdtm.py
+++ b/test/zdtm.py
@@ -367,6 +367,9 @@ def test_flag(tdesc, flag):
return flag in tdesc.get('flags', '').split()
+def test_value(tdesc, opt, val):
+ return val in tdesc.get(opt, '').split()
+
#
# Exception thrown when something inside the test goes wrong,
# e.g. test doesn't start, criu returns with non zero code or
@@ -1445,6 +1448,24 @@ class criu:
"check", ["--no-default-config", "-v0", "--feature", feature],
opts['criu_bin']) == 0
+ @staticmethod
+ def check_cmdline(cmdline):
+ with open("/proc/cmdline") as f:
+ bootparams = f.readline().strip().split()
+
+ for arg in cmdline.split():
+ words = [word.strip("'\" ") for word in arg.split('=')]
+ matched = False
+ for param in bootparams:
+ prefix = param.startswith(words[0])
+ if (len(words) == 1 and prefix) \
+ or (len(words) == 2 and prefix and param[len(words[0])+1:] == words[1]):
+ matched = True
+ break
+ if not matched:
+ return True
+ return False
+
@staticmethod
def available():
if not os.access(opts['criu_bin'], os.X_OK):
@@ -1516,6 +1537,11 @@ def cr(cr_api, test, opts):
iters = iter_parm(opts['iters'], 1)
for i in iters[0]:
+ if "--pin-memory" in test.getdopts():
+ print("Clear pin memory space")
+ cmd = [opts["criu_bin"], "clear-pin-memory"]
+ subprocess.run(cmd, shell=False, check=True)
+
pres = iter_parm(opts['pre'], 0)
for p in pres[0]:
if opts['snaps']:
@@ -1965,6 +1991,21 @@ class Launcher:
testline = u"ok %d - %s # SKIP %s" % (self.__runtest, name, reason)
print(testline, file=self.__file_report)
+ def modprobe_pin_memory(self, load):
+ if not load:
+ return
+ else:
+ found = False
+ with open("/proc/modules") as f:
+ for line in f.readlines():
+ if "pin_memory" == line.split()[0]:
+ found = True
+ if not found:
+ subprocess.check_call(["modprobe", "pin_memory"])
+
+ cmd = [opts["criu_bin"], "init-pagemap-read"]
+ subprocess.check_call(cmd, shell=False)
+
def run_test(self, name, desc, flavor):
if len(self.__subs) >= self.__max:
@@ -1972,7 +2013,8 @@ class Launcher:
with open("/proc/sys/kernel/tainted") as taintfd:
taint = taintfd.read()
- if self.__taint != taint:
+ # 0x1000 means the out of tree module has been loaded
+ if self.__taint != taint and (int(self.__taint) | 0x1000) != int(taint):
raise Exception("The kernel is tainted: %r (%r)" %
(taint, self.__taint))
@@ -1997,8 +2039,15 @@ class Launcher:
logf = None
log = None
+ no_pid_ns = test_value(desc, 'opts', '--use-fork-pid')
+ zdtm_no_pid_ns = "1" if no_pid_ns else "0"
+ # load `pin_memory.ko``--pin-memory` option must be used with
+ # `--use-fork-pid`, so don't care `--pin-memory` option
+ self.modprobe_pin_memory(no_pid_ns)
+
sub = subprocess.Popen(["./zdtm_ct", "zdtm.py"],
- env=dict(os.environ, CR_CT_TEST_INFO=arg),
+ env=dict(os.environ, CR_CT_TEST_INFO=arg,
+ ZDTM_NO_PID_NS=zdtm_no_pid_ns),
stdout=log,
stderr=subprocess.STDOUT,
close_fds=True)
@@ -2009,7 +2058,8 @@ class Launcher:
"start": time.time()
}
- if test_flag(desc, 'excl'):
+ # pin memory function don't support concurrency
+ if test_flag(desc, 'excl') or test_value(desc, "opts", "--pin-memory"):
self.wait()
def __wait_one(self, flags):
@@ -2356,6 +2406,12 @@ def run_tests(opts):
launcher.skip(t, "remote lazy pages are not supported")
continue
+ cmdline = tdesc.get('cmdline', '')
+ if cmdline and criu.check_cmdline(cmdline):
+ launcher.skip(
+ t, f"cmdline '{cmdline}' isn't support, or don't set")
+ continue
+
test_flavs = tdesc.get('flavor', 'h ns uns').split()
opts_flavs = (opts['flavor'] or 'h,ns,uns').split(',')
if opts_flavs != ['best']:
@@ -2385,6 +2441,7 @@ def run_tests(opts):
if fail:
sys.exit(1)
+
sti_fmt = "%-40s%-10s%s"
@@ -2664,8 +2721,8 @@ rp.add_argument("--pre-dump-mode",
choices=['splice', 'read'],
default='splice')
rp.add_argument("--kdat",
- help="Path to criu.kdat, default '/run/criu.kdat'",
- default="/run/criu.kdat")
+ help="Path to criu.kdat, default '/run/criu.kdat'",
+ default="/run/criu.kdat")
lp = sp.add_parser("list", help="List tests")
lp.set_defaults(action=list_tests)
@@ -2700,6 +2757,7 @@ if opts['action'] == 'run':
kdat = pathlib.Path(opts['kdat'])
if kdat.exists():
kdat.unlink()
+
for tst in test_classes.values():
tst.available()
diff --git a/test/zdtm/customization/Makefile b/test/zdtm/customization/Makefile
index 563b7b1..82348f2 100644
--- a/test/zdtm/customization/Makefile
+++ b/test/zdtm/customization/Makefile
@@ -3,9 +3,21 @@ LIB := $(LIBDIR)/libzdtmtst.a
LDLIBS += $(LIB)
CPPFLAGS += -I$(LIBDIR)
-TST = \
- ipc
+TST_NOFILE = \
+ ipc \
+ maps01 \
+ maps02 \
+ maps04 \
+ maps05 \
+ maps007 \
+ maps008
+TST_FILE = \
+ maps00 \
+ maps06 \
+ maps_file_prot
+
+TST = $(TST_NOFILE) $(TST_FILE)
SRC = $(TST:%=%.c)
OBJ = $(SRC:%.c=%.o)
DEP = $(SRC:%.c=%.d)
@@ -18,9 +30,12 @@ all: $(TST)
install: all
.PHONY: all install
-$(TST:%=%.pid): %.pid: %
+$(TST_NOFILE:%=%.pid): %.pid: %
$(<D)/$(<F) --pidfile=$@ --outfile=$<.out
+$(TST_FILE:%=%.pid): %.pid: %
+ $(<D)/$(<F) --pidfile=$@ --outfile=$<.out --filename=$<.test
+
%.out: %.pid %
-kill -TERM `cat $<`
@@ -43,6 +58,8 @@ wait_stop:
$(TST): | $(LIB)
+maps02: get_smaps_bits.o
+
%: %.sh
cp $< $@
chmod +x $@
diff --git a/test/zdtm/customization/get_smaps_bits.c b/test/zdtm/customization/get_smaps_bits.c
new file mode 100644
index 0000000..9253f4d
--- /dev/null
+++ b/test/zdtm/customization/get_smaps_bits.c
@@ -0,0 +1,127 @@
+#include <string.h>
+#include <sys/mman.h>
+#include "zdtmtst.h"
+
+#ifndef MAP_HUGETLB
+# define MAP_HUGETLB 0x40000
+#endif
+
+#ifndef MADV_HUGEPAGE
+# define MADV_HUGEPAGE 14
+#endif
+
+#ifndef MADV_NOHUGEPAGE
+# define MADV_NOHUGEPAGE 15
+#endif
+
+#ifndef MADV_DONTDUMP
+# define MADV_DONTDUMP 16
+#endif
+
+static void parse_vmflags(char *buf, unsigned long *flags, unsigned long *madv)
+{
+ char *tok;
+
+ if (!buf[0])
+ return;
+
+ tok = strtok(buf, " \n");
+ if (!tok)
+ return;
+
+#define _vmflag_match(_t, _s) (_t[0] == _s[0] && _t[1] == _s[1])
+
+ do {
+ /* mmap() block */
+ if (_vmflag_match(tok, "gd"))
+ *flags |= MAP_GROWSDOWN;
+ else if (_vmflag_match(tok, "lo"))
+ *flags |= MAP_LOCKED;
+ else if (_vmflag_match(tok, "nr"))
+ *flags |= MAP_NORESERVE;
+ else if (_vmflag_match(tok, "ht"))
+ *flags |= MAP_HUGETLB;
+
+ /* madvise() block */
+ if (_vmflag_match(tok, "sr"))
+ *madv |= (1ul << MADV_SEQUENTIAL);
+ else if (_vmflag_match(tok, "rr"))
+ *madv |= (1ul << MADV_RANDOM);
+ else if (_vmflag_match(tok, "dc"))
+ *madv |= (1ul << MADV_DONTFORK);
+ else if (_vmflag_match(tok, "dd"))
+ *madv |= (1ul << MADV_DONTDUMP);
+ else if (_vmflag_match(tok, "mg"))
+ *madv |= (1ul << MADV_MERGEABLE);
+ else if (_vmflag_match(tok, "hg"))
+ *madv |= (1ul << MADV_HUGEPAGE);
+ else if (_vmflag_match(tok, "nh"))
+ *madv |= (1ul << MADV_NOHUGEPAGE);
+
+ /*
+ * Anything else is just ignored.
+ */
+ } while ((tok = strtok(NULL, " \n")));
+
+#undef _vmflag_match
+}
+
+#define is_hex_digit(c) \
+ (((c) >= '0' && (c) <= '9') || \
+ ((c) >= 'a' && (c) <= 'f') || \
+ ((c) >= 'A' && (c) <= 'F'))
+
+static int is_vma_range_fmt(char *line, unsigned long *start, unsigned long *end)
+{
+ char *p = line;
+ while (*line && is_hex_digit(*line))
+ line++;
+
+ if (*line++ != '-')
+ return 0;
+
+ while (*line && is_hex_digit(*line))
+ line++;
+
+ if (*line++ != ' ')
+ return 0;
+
+ sscanf(p, "%lx-%lx", start, end);
+ return 1;
+}
+
+int get_smaps_bits(unsigned long where, unsigned long *flags, unsigned long *madv)
+{
+ unsigned long start = 0, end = 0;
+ FILE *smaps = NULL;
+ char buf[1024];
+ int found = 0;
+
+ if (!where)
+ return 0;
+
+ smaps = fopen("/proc/self/smaps", "r");
+ if (!smaps) {
+ pr_perror("Can't open smaps");
+ return -1;
+ }
+
+ while (fgets(buf, sizeof(buf), smaps)) {
+ is_vma_range_fmt(buf, &start, &end);
+
+ if (!strncmp(buf, "VmFlags: ", 9) && start == where) {
+ found = 1;
+ parse_vmflags(buf, flags, madv);
+ break;
+ }
+ }
+
+ fclose(smaps);
+
+ if (!found) {
+ pr_perror("VmFlags not found for %lx", where);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/test/zdtm/customization/get_smaps_bits.h b/test/zdtm/customization/get_smaps_bits.h
new file mode 100644
index 0000000..ce1070d
--- /dev/null
+++ b/test/zdtm/customization/get_smaps_bits.h
@@ -0,0 +1,6 @@
+#ifndef ZDTM_GET_SMAPS_BITS_H_
+#define ZDTM_GET_SMAPS_BITS_H_
+
+extern int get_smaps_bits(unsigned long where, unsigned long *flags, unsigned long *madv);
+
+#endif /* ZDTM_GET_SMAPS_BITS_H_ */
diff --git a/test/zdtm/customization/ipc.desc b/test/zdtm/customization/ipc.desc
index 63df42a..4c127a0 100644
--- a/test/zdtm/customization/ipc.desc
+++ b/test/zdtm/customization/ipc.desc
@@ -1 +1 @@
-{'flavor': 'h'}
+{'arch': 'aarch64', 'flavor': 'h'}
diff --git a/test/zdtm/customization/maps00.c b/test/zdtm/customization/maps00.c
new file mode 100644
index 0000000..83533f8
--- /dev/null
+++ b/test/zdtm/customization/maps00.c
@@ -0,0 +1,271 @@
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <setjmp.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "zdtmtst.h"
+
+const char *test_doc = "Create all sorts of maps and compare /proc/pid/maps\n"
+ "before and after migration\n";
+const char *test_author = "Pavel Emelianov <xemul@parallels.com>";
+
+char *filename;
+TEST_OPTION(filename, string, "file name", 1);
+
+const static int map_prots[] = {
+ PROT_NONE,
+ PROT_READ,
+ PROT_READ | PROT_WRITE,
+ PROT_READ | PROT_WRITE | PROT_EXEC,
+};
+#define NUM_MPROTS sizeof(map_prots) / sizeof(int)
+#define RW_PROT(x) ((x) & (PROT_READ | PROT_WRITE))
+#define X_PROT(x) ((x) & PROT_EXEC)
+
+int check_prot(int src_prot, int dst_prot)
+{
+ if (RW_PROT(src_prot) != RW_PROT(dst_prot))
+ return 0;
+ /* If exec bit will be enabled may depend on NX capability of CPUs of
+ * source and destination nodes. In any case, migrated mapping should
+ * not have less permissions than newly created one
+ **
+ * A is a subset of B iff (A & B) == A
+ */
+ return (X_PROT(dst_prot) & X_PROT(src_prot)) == X_PROT(dst_prot);
+}
+
+const static int map_flags[] = {
+ MAP_PRIVATE,
+ MAP_SHARED,
+ MAP_PRIVATE | MAP_ANONYMOUS,
+ MAP_SHARED | MAP_ANONYMOUS
+};
+#define NUM_MFLAGS sizeof(map_flags) / sizeof(int)
+#define NUM_MAPS NUM_MPROTS * NUM_MFLAGS
+#define ONE_MAP_SIZE 0x2000
+
+struct map
+{
+ int prot;
+ int prot_real;
+ int flag;
+ char filename[256];
+ int fd;
+ void *ptr;
+};
+
+static void init_map(struct map *map, int prot_no, int flag_no)
+{
+ map->fd = -1;
+ map->prot = map_prots[prot_no];
+ map->flag = map_flags[flag_no];
+}
+
+static int make_map(struct map *map)
+{
+ uint32_t crc;
+ uint8_t buf[ONE_MAP_SIZE];
+ static int i = 0;
+
+ if (!(map->flag & MAP_ANONYMOUS)) {
+ /* need file */
+ if (snprintf(map->filename, sizeof(map->filename),
+ "%s-%02d", filename, i++) >= sizeof(map->filename)) {
+ pr_perror("filename %s is too long", filename);
+ return -1;
+ }
+
+ map->fd = open(map->filename, O_RDWR | O_CREAT, 0600);
+ if (map->fd < 0) {
+ pr_perror("can't open %s", map->filename);
+ return -1;
+ }
+
+ crc = ~0;
+ datagen(buf, sizeof(buf), &crc);
+ if (write(map->fd, buf, sizeof(buf)) != sizeof(buf)) {
+ pr_perror("failed to write %s", map->filename);
+ return -1;
+ }
+ }
+
+ map->ptr = mmap(NULL, ONE_MAP_SIZE, map->prot, map->flag, map->fd, 0);
+ if (map->ptr == MAP_FAILED) {
+ pr_perror("can't create mapping");
+ return -1;
+ }
+
+ if ((map->flag & MAP_ANONYMOUS) && (map->prot & PROT_WRITE)) {
+ /* can't fill it with data otherwise */
+ crc = ~0;
+ datagen(map->ptr, ONE_MAP_SIZE, &crc);
+ }
+
+ test_msg("map: ptr %p flag %8x prot %8x\n",
+ map->ptr, map->flag, map->prot);
+
+ return 0;
+}
+
+static sigjmp_buf segv_ret; /* we need sig*jmp stuff, otherwise SIGSEGV will reset our handler */
+static void segfault(int signo)
+{
+ siglongjmp(segv_ret, 1);
+}
+
+/*
+ * after test func should be placed check map, because size of test_func
+ * is calculated as (check_map-test_func)
+ */
+int test_func(void)
+{
+ return 1;
+}
+static int check_map(struct map *map)
+{
+ int prot = PROT_WRITE | PROT_READ | PROT_EXEC;
+
+ if (signal(SIGSEGV, segfault) == SIG_ERR)
+ {
+ fail("setting SIGSEGV handler failed: %m\n");
+ return -1;
+ }
+ if (!sigsetjmp(segv_ret, 1))
+ {
+ uint32_t crc = ~0;
+ if (datachk(map->ptr, ONE_MAP_SIZE, &crc)) /* perform read access */
+ if (!(map->flag & MAP_ANONYMOUS) ||
+ (map->prot & PROT_WRITE)) { /* anon maps could only be filled when r/w */
+ fail("CRC mismatch: ptr %p flag %8x prot %8x\n",
+ map->ptr, map->flag, map->prot);
+ return -1;
+ }
+ /* prot |= PROT_READ// need barrier before this line,
+ because compiler change order commands.
+ I finded one method: look at next lines*/
+ } else
+ prot &= PROT_WRITE | !PROT_READ | PROT_EXEC;
+
+ if (signal(SIGSEGV, segfault) == SIG_ERR)
+ {
+ fail("setting SIGSEGV handler failed: %m\n");
+ return -1;
+ }
+
+ if (!sigsetjmp(segv_ret, 1))
+ {
+ * (int *) (map->ptr) = 1234; /* perform write access */
+ } else
+ prot &= !PROT_WRITE | PROT_READ | PROT_EXEC;
+
+ if (signal(SIGSEGV, segfault) == SIG_ERR)
+ {
+ fail("restoring SIGSEGV handler failed: %m\n");
+ return -1;
+ }
+
+ if (!sigsetjmp(segv_ret, 1))
+ {
+ if (map->prot & PROT_WRITE) {
+ memcpy(map->ptr,test_func, ONE_MAP_SIZE);
+ __builtin___clear_cache(map->ptr, map->ptr+ONE_MAP_SIZE);
+ } else {
+ if (!(map->flag & MAP_ANONYMOUS)) {
+ uint8_t funlen = (uint8_t *)check_map - (uint8_t *)test_func;
+ lseek(map->fd,0,SEEK_SET);
+ if (write(map->fd,test_func,funlen)<funlen) {
+ pr_perror("failed to write %s", map->filename);
+ return -1;
+ }
+ }
+ }
+ if (!(map->flag & MAP_ANONYMOUS) || (map->prot & PROT_WRITE)) {
+ /* Function body has been copied into the mapping */
+ ((int (*)(void))map->ptr)(); /* perform exec access */
+ } else {
+ /* No way to copy function body into mapping,
+ * clear exec bit from effective protection
+ */
+ prot &= PROT_WRITE | PROT_READ | !PROT_EXEC;
+ }
+ } else
+ prot &= PROT_WRITE | PROT_READ | !PROT_EXEC;
+
+ if (signal(SIGSEGV, SIG_DFL) == SIG_ERR)
+ {
+ fail("restoring SIGSEGV handler failed: %m\n");
+ return -1;
+ }
+
+ return prot;
+}
+
+static void destroy_map(struct map *map)
+{
+ munmap(map->ptr, ONE_MAP_SIZE);
+
+ if (map->fd >= 0)
+ {
+ close(map->fd);
+ unlink(map->filename);
+ }
+}
+
+
+#define MAPS_LEN 0x10000
+
+int main(int argc, char ** argv)
+{
+ struct map maps[NUM_MAPS] = {}, maps_compare[NUM_MAPS] = {};
+ int i, j, k;
+ test_init(argc, argv);
+
+ k = 0;
+ for (i = 0; i < NUM_MPROTS; i++)
+ for (j = 0; j < NUM_MFLAGS; j++)
+ init_map(maps + k++, i, j);
+
+ for (i = 0; i < NUM_MAPS; i++)
+ if (make_map(maps + i))
+ goto err;
+
+ test_daemon();
+ test_waitsig();
+
+ for (i = 0; i < NUM_MAPS; i++)
+ if ((maps[i].prot_real=check_map(maps + i))<0)
+ goto err;
+ k=0;
+ for (i = 0; i < NUM_MPROTS; i++)
+ for (j = 0; j < NUM_MFLAGS; j++)
+ init_map(maps_compare + k++, i, j);
+ for (i = 0; i < NUM_MAPS; i++)
+ if (make_map(maps_compare+ i))
+ goto err;
+ for (i = 0; i < NUM_MAPS; i++)
+ if ((maps_compare[i].prot_real=check_map(maps_compare + i))<0)
+ goto err;
+ for (i = 0; i< NUM_MAPS; i++)
+ if (!check_prot(maps[i].prot_real, maps_compare[i].prot_real)){
+ fail("protection on %i (flag=%d prot=%d) maps has changed (prot=%d(expected %d))",
+ i, maps[i].flag, maps[i].prot, maps[i].prot_real, maps_compare[i].prot_real);
+ goto err;
+ }
+
+ pass();
+
+ for (i = 0; i < NUM_MAPS; i++) {
+ destroy_map(maps + i);
+ destroy_map(maps_compare + i);
+ }
+ return 0;
+
+err:
+ return 1;
+}
diff --git a/test/zdtm/customization/maps00.desc b/test/zdtm/customization/maps00.desc
new file mode 100644
index 0000000..dad462e
--- /dev/null
+++ b/test/zdtm/customization/maps00.desc
@@ -0,0 +1 @@
+{'arch': 'aarch64', 'flavor': 'h', 'opts': '--pin-memory --use-fork-pid', 'flags': 'suid', 'cmdline': 'pinmemory max_pin_pid_num'}
diff --git a/test/zdtm/customization/maps007.c b/test/zdtm/customization/maps007.c
new file mode 100644
index 0000000..ee5e7c7
--- /dev/null
+++ b/test/zdtm/customization/maps007.c
@@ -0,0 +1,178 @@
+
+#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 (1UL << 20)
+#define MEM_SIZE (1UL << 29)
+
+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 {
+ futex_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;
+ futex_set(&shm->delta, v);
+ futex_set(&shm->stop, 0);
+
+ child = fork();
+ if (child < 0) {
+ pr_perror("fork");
+ return 1;
+ }
+
+ while (1) {
+ void *ret;
+ unsigned long size;
+ int prot = PROT_NONE;
+
+ if (child) {
+ if (!test_go())
+ break;
+ futex_wait_while_gt(&shm->delta, 2 * MAX_DELTA);
+ futex_inc_and_wake(&shm->delta);
+ } else {
+ if (!futex_get(&shm->stop))
+ /* shm->delta must be always bigger than MAX_DELTA */
+ futex_wait_while_lt(&shm->delta, MAX_DELTA + 2);
+ else if (count % 100 == 0)
+ test_msg("count %llu delta %d\n",
+ count, futex_get(&shm->delta)); /* heartbeat */
+
+ if (futex_get(&shm->stop) && atomic_get(&shm->delta.raw) == MAX_DELTA)
+ break;
+ futex_dec_and_wake(&shm->delta);
+ }
+
+ count++;
+ if (child && count == MAX_DELTA + 1)
+ test_daemon();
+
+ p = start + ((lrand48() * PAGE_SIZE) % MEM_SIZE);
+ size = lrand48() * PAGE_SIZE;
+ 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) {
+ pr_perror("%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();
+ }
+ }
+ test_msg("count %llu\n", count);
+
+ if (child == 0) {
+ if (!test_go())
+ pr_perror("unexpected state");
+ futex_set_and_wake(&shm->stop, 2);
+ test_waitsig();
+ return 0;
+ } else {
+ int readable = 0, status = -1;
+
+ /* stop the child */
+ futex_set(&shm->stop, 1);
+ futex_add_and_wake(&shm->delta, MAX_DELTA);
+ /* 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) {
+ pr_perror("%p %d %d", p, lret, rret);
+ goto err;
+ }
+ if (lret < 0)
+ continue;
+ readable++;
+ if (memcmp(rbuf, lbuf, PAGE_SIZE)) {
+ pr_perror("%p", p);
+ goto err;
+ }
+ }
+ test_msg("readable %d\n", readable);
+ kill(child, SIGTERM);
+ wait(&status);
+ if (status != 0) {
+ pr_perror("Non-zero exit code: %d", status);
+ goto err;
+ }
+ pass();
+ }
+
+ return 0;
+err:
+ kill(child, SIGSEGV);
+ *((volatile int *) 0) = 0;
+ return 1;
+}
diff --git a/test/zdtm/customization/maps007.desc b/test/zdtm/customization/maps007.desc
new file mode 100644
index 0000000..9ed7e46
--- /dev/null
+++ b/test/zdtm/customization/maps007.desc
@@ -0,0 +1 @@
+{'arch': 'aarch64', 'opts': '--pin-memory --use-fork-pid', 'flags': 'suid', 'flavor': 'h', 'cmdline': 'pinmemory max_pin_pid_num'}
diff --git a/test/zdtm/customization/maps008.c b/test/zdtm/customization/maps008.c
new file mode 100644
index 0000000..7ed7c10
--- /dev/null
+++ b/test/zdtm/customization/maps008.c
@@ -0,0 +1,514 @@
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <linux/limits.h>
+#include "zdtmtst.h"
+#include "lock.h"
+
+const char *test_doc = "ps tree with anon shared vmas for dedup";
+
+/*
+ * 1. ps tree with non triavial anon shmem vmas is created first.
+ * 2. Each process gets its portion of shmem vmas.
+ * 3. Each process continuously datagens its portion until
+ * criu dump is finished.
+ * 4. Each process datachecks all its shmem portions after restore.
+ * 5. Contents of anon shmem vmas are checked for equality in
+ * different processes.
+ */
+
+typedef int (*proc_func_t)(task_waiter_t *setup_waiter);
+
+static pid_t fork_and_setup(proc_func_t pfunc)
+{
+ task_waiter_t setup_waiter;
+ pid_t pid;
+
+ task_waiter_init(&setup_waiter);
+ pid = test_fork();
+ if (pid < 0) {
+ pr_perror("fork failed");
+ exit(1);
+ }
+
+ if (pid == 0)
+ exit(pfunc(&setup_waiter));
+
+ task_waiter_wait4(&setup_waiter, pid);
+ task_waiter_fini(&setup_waiter);
+ return pid;
+}
+
+static void cont_and_wait_child(pid_t pid)
+{
+ int status;
+
+ kill(pid, SIGTERM);
+ waitpid(pid, &status, 0);
+ if (WIFEXITED(status)) {
+ if (WEXITSTATUS(status))
+ exit(WEXITSTATUS(status));
+ } else
+ exit(1);
+}
+
+static void *mmap_ashmem(size_t size)
+{
+ void *mem = mmap(NULL, size, PROT_WRITE | PROT_READ,
+ MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+ if (mem == MAP_FAILED) {
+ pr_perror("Can't map shmem %zx", size);
+ exit(1);
+ }
+ return mem;
+}
+
+static void *mmap_proc_mem(pid_t pid, unsigned long addr,
+ unsigned long size)
+{
+ int fd;
+ void *mem;
+ char path[PATH_MAX];
+
+ snprintf(path, PATH_MAX, "/proc/%d/map_files/%lx-%lx",
+ (int)pid, addr, addr + size);
+ fd = open(path, O_RDWR);
+ if (fd == -1) {
+ pr_perror("Can't open file %s", path);
+ exit(1);
+ }
+
+ mem = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
+ close(fd);
+ if (mem == MAP_FAILED) {
+ pr_perror("Can't map file %s", path);
+ exit(1);
+ }
+ return mem;
+}
+
+static void check_mem_eq(void *addr1, size_t size1, void *addr2, size_t size2)
+{
+ unsigned long min_size = size1 < size2 ? size1 : size2;
+
+ if (memcmp(addr1, addr2, min_size)) {
+ pr_err("Mem differs %lx %lx %lx", (unsigned long)addr1,
+ (unsigned long)addr2, min_size);
+ exit(1);
+ }
+}
+
+static void xmunmap(void *map, size_t size)
+{
+ if (munmap(map, size)) {
+ pr_err("xmunmap");
+ exit(1);
+ }
+}
+
+static void chk_proc_mem_eq(pid_t pid1, void *addr1, unsigned long size1,
+ pid_t pid2, void *addr2, unsigned long size2)
+{
+ void *map1, *map2;
+
+ map1 = mmap_proc_mem(pid1, (unsigned long)addr1, size1);
+ map2 = mmap_proc_mem(pid2, (unsigned long)addr2, size2);
+ check_mem_eq(map1, size1, map2, size2);
+ xmunmap(map1, size1);
+ xmunmap(map2, size2);
+}
+
+/*
+ * ps tree:
+ * proc1_______________
+ * | | |
+ * proc11___ proc12 proc13
+ * | | |
+ * proc111 proc112 proc131
+ */
+#define PROC_CNT 7
+
+#define PROC1_PGIX 0
+#define PROC11_PGIX 1
+#define PROC12_PGIX 2
+#define PROC13_PGIX 3
+#define PROC111_PGIX 4
+#define PROC112_PGIX 5
+#define PROC131_PGIX 6
+#define ZERO_PGIX 7
+/* unused pgix: 8 */
+#define MEM_PERIOD (9 * PAGE_SIZE)
+
+struct pstree {
+ pid_t proc1;
+ pid_t proc11;
+ pid_t proc12;
+ pid_t proc13;
+ pid_t proc111;
+ pid_t proc112;
+ pid_t proc131;
+};
+struct pstree *pstree;
+
+struct test_sync {
+ futex_t datagen;
+ futex_t datagen_exit_cnt;
+};
+struct test_sync *test_sync;
+
+size_t mem1_size, mem2_size, mem3_size;
+uint8_t *mem1, *mem2, *mem3;
+
+#define CRC_EPOCH_OFFSET (PAGE_SIZE - sizeof(uint32_t))
+
+static void read_each_pg(volatile uint8_t *mem, size_t size, size_t off)
+{
+ if (!mem)
+ return;
+
+ while (off < size) {
+ (mem + off)[0];
+ off += MEM_PERIOD;
+ }
+}
+
+void datagen_each_pg(uint8_t *mem, size_t size, size_t off, uint32_t crc_epoch)
+{
+ if (!mem)
+ return;
+
+ while (futex_get(&test_sync->datagen) && (off < size)) {
+ uint32_t crc = crc_epoch;
+
+ datagen(mem + off, CRC_EPOCH_OFFSET, &crc);
+ *(uint32_t *)(mem + off + CRC_EPOCH_OFFSET) = crc_epoch;
+ off += MEM_PERIOD;
+ }
+}
+
+void datachck_each_pg(uint8_t *mem, size_t size, size_t off)
+{
+ if (!mem)
+ return;
+
+ while (off < size) {
+ uint32_t crc = *(uint32_t *)(mem + off + CRC_EPOCH_OFFSET);
+
+ if (datachk(mem + off, CRC_EPOCH_OFFSET, &crc))
+ exit(1);
+ off += MEM_PERIOD;
+ }
+}
+
+static void mems_read_each_pgix(size_t pgix)
+{
+ const size_t off = pgix * PAGE_SIZE;
+
+ read_each_pg(mem1, mem1_size, off);
+ read_each_pg(mem2, mem2_size, off);
+ read_each_pg(mem3, mem3_size, off);
+}
+
+static void mems_datagen_each_pgix(size_t pgix, uint32_t *crc_epoch)
+{
+ const size_t off = pgix * PAGE_SIZE;
+
+ ++(*crc_epoch);
+ datagen_each_pg(mem1, mem1_size, off, *crc_epoch);
+ datagen_each_pg(mem2, mem2_size, off, *crc_epoch);
+ datagen_each_pg(mem3, mem3_size, off, *crc_epoch);
+}
+
+static void mems_datachck_each_pgix(size_t pgix)
+{
+ const size_t off = pgix * PAGE_SIZE;
+
+ datachck_each_pg(mem1, mem1_size, off);
+ datachck_each_pg(mem2, mem2_size, off);
+ datachck_each_pg(mem3, mem3_size, off);
+}
+
+static int proc131_func(task_waiter_t *setup_waiter)
+{
+ uint32_t crc_epoch = 0;
+
+ pstree->proc131 = getpid();
+ mems_datagen_each_pgix(PROC131_PGIX, &crc_epoch);
+ task_waiter_complete_current(setup_waiter);
+
+ while (futex_get(&test_sync->datagen))
+ mems_datagen_each_pgix(PROC131_PGIX, &crc_epoch);
+ futex_inc_and_wake(&test_sync->datagen_exit_cnt);
+ test_waitsig();
+
+ mems_datachck_each_pgix(PROC131_PGIX);
+ return 0;
+}
+
+static int proc13_func(task_waiter_t *setup_waiter)
+{
+ size_t MEM1_HOLE_START = 2 * MEM_PERIOD;
+ size_t MEM1_HOLE_SIZE = 1 * MEM_PERIOD;
+ uint32_t crc_epoch = 0;
+
+ pstree->proc13 = getpid();
+ xmunmap(mem1 + MEM1_HOLE_START, MEM1_HOLE_SIZE);
+ xmunmap(mem2, mem2_size);
+ xmunmap(mem3, mem3_size);
+ mem2 = mem1 + MEM1_HOLE_START + MEM1_HOLE_SIZE;
+ mem2_size = mem1_size - (mem2 - mem1);
+ mem1_size = MEM1_HOLE_START;
+ mem3 = mmap_ashmem(mem3_size);
+ mems_datagen_each_pgix(PROC13_PGIX, &crc_epoch);
+ fork_and_setup(proc131_func);
+ task_waiter_complete_current(setup_waiter);
+
+ while (futex_get(&test_sync->datagen))
+ mems_datagen_each_pgix(PROC13_PGIX, &crc_epoch);
+ futex_inc_and_wake(&test_sync->datagen_exit_cnt);
+ test_waitsig();
+
+ mems_datachck_each_pgix(PROC13_PGIX);
+
+ chk_proc_mem_eq(pstree->proc13, mem1, mem1_size,
+ pstree->proc131, mem1, mem1_size);
+ chk_proc_mem_eq(pstree->proc13, mem2, mem2_size,
+ pstree->proc131, mem2, mem2_size);
+ chk_proc_mem_eq(pstree->proc13, mem3, mem3_size,
+ pstree->proc131, mem3, mem3_size);
+
+ cont_and_wait_child(pstree->proc131);
+ return 0;
+}
+
+static int proc12_func(task_waiter_t *setup_waiter)
+{
+ uint32_t crc_epoch = 0;
+
+ pstree->proc12 = getpid();
+ mems_datagen_each_pgix(PROC12_PGIX, &crc_epoch);
+ task_waiter_complete_current(setup_waiter);
+
+ while (futex_get(&test_sync->datagen))
+ mems_datagen_each_pgix(PROC12_PGIX, &crc_epoch);
+ futex_inc_and_wake(&test_sync->datagen_exit_cnt);
+ test_waitsig();
+
+ mems_datachck_each_pgix(PROC12_PGIX);
+
+ return 0;
+}
+
+static int proc111_func(task_waiter_t *setup_waiter)
+{
+ uint32_t crc_epoch = 0;
+
+ pstree->proc111 = getpid();
+ mems_datagen_each_pgix(PROC111_PGIX, &crc_epoch);
+ task_waiter_complete_current(setup_waiter);
+
+ while (futex_get(&test_sync->datagen))
+ mems_datagen_each_pgix(PROC111_PGIX, &crc_epoch);
+ futex_inc_and_wake(&test_sync->datagen_exit_cnt);
+ test_waitsig();
+
+ mems_datachck_each_pgix(PROC111_PGIX);
+ return 0;
+}
+
+static int proc112_func(task_waiter_t *setup_waiter)
+{
+ uint32_t crc_epoch = 0;
+
+ pstree->proc112 = getpid();
+ mems_datagen_each_pgix(PROC112_PGIX, &crc_epoch);
+ task_waiter_complete_current(setup_waiter);
+
+ while (futex_get(&test_sync->datagen))
+ mems_datagen_each_pgix(PROC112_PGIX, &crc_epoch);
+ futex_inc_and_wake(&test_sync->datagen_exit_cnt);
+ test_waitsig();
+
+ mems_datachck_each_pgix(PROC112_PGIX);
+ return 0;
+}
+
+static int proc11_func(task_waiter_t *setup_waiter)
+{
+ const size_t MEM3_START_CUT = 1 * MEM_PERIOD;
+ const size_t MEM3_END_CUT = 2 * MEM_PERIOD;
+ void *mem3_old = mem3;
+ size_t mem3_size_old = mem3_size;
+ uint32_t crc_epoch = 0;
+ uint8_t *proc1_mem3;
+
+ pstree->proc11 = getpid();
+ xmunmap(mem3, MEM3_START_CUT);
+ mem3 += MEM3_START_CUT;
+ mem3_size -= MEM3_START_CUT;
+ fork_and_setup(proc111_func);
+ fork_and_setup(proc112_func);
+ xmunmap(mem3 + mem3_size - MEM3_END_CUT, MEM3_END_CUT);
+ mem3_size -= MEM3_END_CUT;
+ mems_datagen_each_pgix(PROC11_PGIX, &crc_epoch);
+ task_waiter_complete_current(setup_waiter);
+
+ while (futex_get(&test_sync->datagen))
+ mems_datagen_each_pgix(PROC11_PGIX, &crc_epoch);
+ futex_inc_and_wake(&test_sync->datagen_exit_cnt);
+ test_waitsig();
+
+ mems_datachck_each_pgix(PROC11_PGIX);
+
+ chk_proc_mem_eq(pstree->proc11, mem1, mem1_size,
+ pstree->proc111, mem1, mem1_size);
+ chk_proc_mem_eq(pstree->proc11, mem1, mem1_size,
+ pstree->proc112, mem1, mem1_size);
+
+ chk_proc_mem_eq(pstree->proc11, mem2, mem2_size,
+ pstree->proc111, mem2, mem2_size);
+ chk_proc_mem_eq(pstree->proc11, mem2, mem2_size,
+ pstree->proc112, mem2, mem2_size);
+
+ chk_proc_mem_eq(pstree->proc11, mem3, mem3_size,
+ pstree->proc111, mem3, mem3_size + MEM3_END_CUT);
+ chk_proc_mem_eq(pstree->proc11, mem3, mem3_size,
+ pstree->proc112, mem3, mem3_size + MEM3_END_CUT);
+
+ proc1_mem3 = mmap_proc_mem(pstree->proc1,
+ (unsigned long)mem3_old, mem3_size_old);
+ check_mem_eq(mem3, mem3_size, proc1_mem3 + MEM3_START_CUT, mem3_size);
+ xmunmap(proc1_mem3, mem3_size_old);
+
+ cont_and_wait_child(pstree->proc111);
+ cont_and_wait_child(pstree->proc112);
+ return 0;
+}
+
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define MB(n) ((n) * (1UL << 20))
+
+static int proc1_func(void)
+{
+ uint32_t crc_epoch = 0;
+ uint8_t *mem2_old = NULL;
+
+ /*
+ * Min mem size:
+ * At least 5 mem periods for mem pages and vma holes.
+ * At least 1 MB mem size not to test on tiny working set.
+ */
+ mem1_size = MEM_PERIOD * MAX(5, MB(1) / MEM_PERIOD + 1);
+ mem2_size = mem1_size * 2;
+ mem3_size = mem2_size * 3;
+
+ futex_set(&test_sync->datagen, 1);
+ pstree->proc1 = getpid();
+ mem1 = mmap_ashmem(mem1_size);
+ mem2 = mmap_ashmem(mem2_size);
+ mem3 = mmap_ashmem(mem3_size);
+ mems_datagen_each_pgix(PROC1_PGIX, &crc_epoch);
+ mems_read_each_pgix(ZERO_PGIX);
+
+ fork_and_setup(proc11_func);
+ fork_and_setup(proc12_func);
+ fork_and_setup(proc13_func);
+
+ xmunmap(mem1, mem1_size);
+ if (mremap(mem2, mem2_size, mem1_size, MREMAP_MAYMOVE | MREMAP_FIXED,
+ mem1) != mem1) {
+ pr_perror("proc1 mem2 remap");
+ exit(1);
+ }
+ mem2_old = mem2;
+ mem2 = NULL;
+
+ test_daemon();
+ while (test_go())
+ mems_datagen_each_pgix(PROC1_PGIX, &crc_epoch);
+ test_waitsig();
+ futex_set(&test_sync->datagen_exit_cnt, 0);
+ futex_set(&test_sync->datagen, 0);
+ futex_wait_while(&test_sync->datagen_exit_cnt, PROC_CNT);
+
+ mems_datachck_each_pgix(PROC1_PGIX);
+
+ chk_proc_mem_eq(pstree->proc1, mem1, mem1_size,
+ pstree->proc11, mem2_old, mem2_size);
+ chk_proc_mem_eq(pstree->proc1, mem1, mem1_size,
+ pstree->proc12, mem2_old, mem2_size);
+
+ chk_proc_mem_eq(pstree->proc1, mem3, mem3_size,
+ pstree->proc12, mem3, mem3_size);
+
+ cont_and_wait_child(pstree->proc11);
+ cont_and_wait_child(pstree->proc12);
+ cont_and_wait_child(pstree->proc13);
+
+ pass();
+ return 0;
+}
+
+static void kill_pstree_from_root(void)
+{
+ if (getpid() != pstree->proc1)
+ return;
+
+ kill(pstree->proc11, SIGKILL);
+ kill(pstree->proc12, SIGKILL);
+ kill(pstree->proc13, SIGKILL);
+ kill(pstree->proc111, SIGKILL);
+ kill(pstree->proc112, SIGKILL);
+ kill(pstree->proc131, SIGKILL);
+}
+
+static void sigchld_hand(int signo, siginfo_t *info, void *ucontext)
+{
+ if (info->si_code != CLD_EXITED)
+ return;
+ if (!info->si_status)
+ return;
+
+ /*
+ * If we are not ps tree root then propagate child error to parent.
+ * If we are ps tree root then also call all
+ * atexit handlers set up by zdtm test framework and this test.
+ * exit() is not async signal safe but it's ok for testing purposes.
+ * exit() usage allows us to use very simple error handling
+ * and pstree killing logic.
+ */
+ exit(info->si_status);
+}
+
+int main(int argc, char **argv)
+{
+ struct sigaction sa = {
+ .sa_sigaction = sigchld_hand,
+ .sa_flags = SA_RESTART | SA_SIGINFO | SA_NOCLDSTOP
+ };
+ sigemptyset(&sa.sa_mask);
+
+ test_init(argc, argv);
+
+ pstree = (struct pstree *)mmap_ashmem(PAGE_SIZE);
+ test_sync = (struct test_sync *)mmap_ashmem(sizeof(*test_sync));
+
+ if (sigaction(SIGCHLD, &sa, NULL)) {
+ pr_perror("SIGCHLD handler setup");
+ exit(1);
+ };
+
+ if (atexit(kill_pstree_from_root)) {
+ pr_err("Can't setup atexit cleanup func");
+ exit(1);
+ }
+ return proc1_func();
+}
diff --git a/test/zdtm/customization/maps008.desc b/test/zdtm/customization/maps008.desc
new file mode 100644
index 0000000..154ef8c
--- /dev/null
+++ b/test/zdtm/customization/maps008.desc
@@ -0,0 +1 @@
+{'arch': 'aarch64', 'opts': '--pin-memory --use-fork-pid', 'flavor': 'h', 'flags': 'suid', 'cmdline': 'pinmemory max_pin_pid_num'}
diff --git a/test/zdtm/customization/maps01.c b/test/zdtm/customization/maps01.c
new file mode 100644
index 0000000..119d7a6
--- /dev/null
+++ b/test/zdtm/customization/maps01.c
@@ -0,0 +1,183 @@
+#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"
+
+#define MEM_SIZE (1LU << 30)
+#define MEM_OFFSET (1LU << 29)
+#define MEM_OFFSET2 (MEM_SIZE - PAGE_SIZE)
+#define MEM_OFFSET3 (20LU * PAGE_SIZE)
+
+const char *test_doc = "Test shared memory";
+const char *test_author = "Andrew Vagin <avagin@openvz.org";
+
+int main(int argc, char ** argv)
+{
+ void *m, *m2, *p, *p2;
+ char path[PATH_MAX];
+ uint32_t crc;
+ pid_t pid = -1;
+ int status, fd;
+ task_waiter_t t;
+
+ test_init(argc, argv);
+
+ task_waiter_init(&t);
+
+ m = mmap(NULL, MEM_SIZE, PROT_WRITE | PROT_READ,
+ MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+
+ if (m == MAP_FAILED) {
+ pr_err("Failed to mmap %lu Mb shared anonymous R/W memory\n",
+ MEM_SIZE >> 20);
+ goto err;
+ }
+
+ p = mmap(NULL, MEM_SIZE, PROT_WRITE | PROT_READ,
+ MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+
+ if (p == MAP_FAILED) {
+ pr_err("Failed to mmap %ld Mb shared anonymous R/W memory\n",
+ MEM_SIZE >> 20);
+ goto err;
+ }
+
+ p2 = mmap(NULL, MEM_OFFSET, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (p2 == MAP_FAILED) {
+ pr_err("Failed to mmap %lu Mb anonymous memory\n",
+ MEM_OFFSET >> 20);
+ goto err;
+ }
+
+ pid = test_fork();
+ if (pid < 0) {
+ pr_err("Fork failed with %d\n", pid);
+ goto err;
+ } else if (pid == 0) {
+ void *p3;
+
+ p3 = mmap(NULL, MEM_OFFSET3, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (p3 == MAP_FAILED) {
+ pr_err("Failed to mmap %lu Mb anonymous R/W memory\n",
+ MEM_OFFSET3 >> 20);
+ goto err;
+ }
+
+ crc = ~0;
+ datagen(m + MEM_OFFSET, PAGE_SIZE, &crc);
+ crc = ~0;
+ datagen(m + MEM_OFFSET2, PAGE_SIZE, &crc);
+ crc = ~0;
+ datagen(p + MEM_OFFSET + MEM_OFFSET3, PAGE_SIZE, &crc);
+ crc = ~0;
+ datagen(p + MEM_OFFSET + 2 * MEM_OFFSET3, PAGE_SIZE, &crc);
+ crc = ~0;
+ datagen(p + MEM_OFFSET3, PAGE_SIZE, &crc);
+ crc = ~0;
+ datagen(p3, PAGE_SIZE, &crc);
+
+ task_waiter_complete(&t, 1);
+
+ test_waitsig();
+
+ crc = ~0;
+ status = datachk(m + MEM_OFFSET, PAGE_SIZE, &crc);
+ if (status)
+ return 1;
+ crc = ~0;
+ status = datachk(m + MEM_OFFSET2, PAGE_SIZE, &crc);
+ if (status)
+ return 1;
+ crc = ~0;
+ status = datachk(m + PAGE_SIZE, PAGE_SIZE, &crc);
+ if (status)
+ return 1;
+ crc = ~0;
+ status = datachk(p + MEM_OFFSET + 2 * MEM_OFFSET3, PAGE_SIZE, &crc);
+ if (status)
+ return 1;
+ crc = ~0;
+ status = datachk(p + MEM_OFFSET3, PAGE_SIZE, &crc);
+ if (status)
+ return 1;
+ crc = ~0;
+ status = datachk(p3, PAGE_SIZE, &crc);
+ if (status)
+ return 1;
+ return 0;
+ }
+ task_waiter_wait4(&t, 1);
+
+ munmap(p, MEM_OFFSET);
+ p2 = mremap(p + MEM_OFFSET, MEM_OFFSET, MEM_OFFSET, MREMAP_FIXED | MREMAP_MAYMOVE, p2);
+ if (p2 == MAP_FAILED)
+ goto err;
+
+ snprintf(path, PATH_MAX, "/proc/self/map_files/%lx-%lx",
+ (unsigned long) m,
+ (unsigned long) m + MEM_SIZE);
+ fd = open(path, O_RDWR);
+ if (fd == -1) {
+ pr_perror("Can't open file %s", path);
+ goto err;
+ }
+
+ m2 = mmap(NULL, PAGE_SIZE, PROT_WRITE | PROT_READ, MAP_SHARED, fd, MEM_OFFSET3);
+ if (m2 == MAP_FAILED) {
+ pr_perror("Can't map file %s", path);
+ goto err;
+ }
+ close(fd);
+
+ munmap(m, PAGE_SIZE);
+ munmap(m + PAGE_SIZE * 10, PAGE_SIZE);
+ munmap(m + MEM_OFFSET2, PAGE_SIZE);
+
+ crc = ~0;
+ datagen(m + PAGE_SIZE, PAGE_SIZE, &crc);
+
+ crc = ~0;
+ datagen(m2, PAGE_SIZE, &crc);
+
+ test_daemon();
+ test_waitsig();
+
+ kill(pid, SIGTERM);
+ wait(&status);
+ if (WIFEXITED(status)) {
+ if (WEXITSTATUS(status))
+ goto err;
+ } else
+ goto err;
+
+ crc = ~0;
+ if (datachk(m + MEM_OFFSET, PAGE_SIZE, &crc))
+ goto err;
+
+ crc = ~0;
+ if (datachk(m2, PAGE_SIZE, &crc))
+ goto err;
+
+ crc = ~0;
+ if (datachk(p2 + MEM_OFFSET3, PAGE_SIZE, &crc))
+ goto err;
+
+ pass();
+
+ return 0;
+err:
+ if (waitpid(-1, NULL, WNOHANG) == 0) {
+ kill(pid, SIGTERM);
+ wait(NULL);
+ }
+ return 1;
+}
diff --git a/test/zdtm/customization/maps01.desc b/test/zdtm/customization/maps01.desc
new file mode 100644
index 0000000..dad462e
--- /dev/null
+++ b/test/zdtm/customization/maps01.desc
@@ -0,0 +1 @@
+{'arch': 'aarch64', 'flavor': 'h', 'opts': '--pin-memory --use-fork-pid', 'flags': 'suid', 'cmdline': 'pinmemory max_pin_pid_num'}
diff --git a/test/zdtm/customization/maps02.c b/test/zdtm/customization/maps02.c
new file mode 100644
index 0000000..eb7c09b
--- /dev/null
+++ b/test/zdtm/customization/maps02.c
@@ -0,0 +1,111 @@
+#include <sys/mman.h>
+#include "zdtmtst.h"
+#include "get_smaps_bits.h"
+
+#ifndef MADV_DONTDUMP
+#define MADV_DONTDUMP 16
+#endif
+
+const char *test_doc = "Test shared memory with advises";
+const char *test_author = "Cyrill Gorcunov <gorcunov@openvz.org>";
+
+struct mmap_data {
+ void *start;
+ unsigned long orig_flags;
+ unsigned long orig_madv;
+ unsigned long new_flags;
+ unsigned long new_madv;
+};
+
+#define MEM_SIZE (8192)
+
+static int alloc_anon_mmap(struct mmap_data *m, int flags, int adv)
+{
+ m->start = mmap(NULL, MEM_SIZE, PROT_READ | PROT_WRITE,
+ flags, -1, 0);
+ if (m->start == MAP_FAILED) {
+ pr_perror("mmap failed");
+ return -1;
+ }
+
+ if (madvise(m->start, MEM_SIZE, adv)) {
+ if (errno == EINVAL) {
+ test_msg("madvise failed, no kernel support\n");
+ munmap(m->start, MEM_SIZE);
+ *m = (struct mmap_data){ };
+ } else {
+ pr_perror("madvise failed");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ struct mmap_data m[5] = { };
+ size_t i;
+
+ test_init(argc, argv);
+
+ test_msg("Alloc growsdown\n");
+ if (alloc_anon_mmap(&m[0], MAP_PRIVATE | MAP_ANONYMOUS, MADV_DONTFORK))
+ return -1;
+
+ test_msg("Alloc locked/sequential\n");
+ if (alloc_anon_mmap(&m[1], MAP_PRIVATE | MAP_ANONYMOUS | MAP_LOCKED, MADV_SEQUENTIAL))
+ return -1;
+
+ test_msg("Alloc noreserve/dontdump\n");
+ if (alloc_anon_mmap(&m[2], MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, MADV_DONTDUMP))
+ return -1;
+
+ test_msg("Alloc hugetlb/hugepage\n");
+ if (alloc_anon_mmap(&m[3], MAP_PRIVATE | MAP_ANONYMOUS, MADV_HUGEPAGE))
+ return -1;
+
+ test_msg("Alloc dontfork/random|mergeable\n");
+ if (alloc_anon_mmap(&m[4], MAP_PRIVATE | MAP_ANONYMOUS, MADV_MERGEABLE))
+ return -1;
+
+ test_msg("Fetch existing flags/adv\n");
+ for (i = 0; i < sizeof(m)/sizeof(m[0]); i++) {
+ if (get_smaps_bits((unsigned long)m[i].start,
+ &m[i].orig_flags,
+ &m[i].orig_madv))
+ return -1;
+ }
+
+ test_daemon();
+ test_waitsig();
+
+ test_msg("Fetch restored flags/adv\n");
+ for (i = 0; i < sizeof(m)/sizeof(m[0]); i++) {
+ if (get_smaps_bits((unsigned long)m[i].start,
+ &m[i].new_flags,
+ &m[i].new_madv))
+ return -1;
+
+ if (m[i].orig_flags != m[i].new_flags) {
+ pr_perror("Flags are changed %lx %lx -> %lx (%zu)",
+ (unsigned long)m[i].start,
+ m[i].orig_flags, m[i].new_flags, i);
+ fail();
+ return -1;
+ }
+
+ if (m[i].orig_madv != m[i].new_madv) {
+ pr_perror("Madvs are changed %lx %lx -> %lx (%zu)",
+ (unsigned long)m[i].start,
+ m[i].orig_madv, m[i].new_madv, i);
+ fail();
+ return -1;
+ }
+
+ }
+
+ pass();
+
+ return 0;
+}
diff --git a/test/zdtm/customization/maps02.desc b/test/zdtm/customization/maps02.desc
new file mode 100644
index 0000000..f14d661
--- /dev/null
+++ b/test/zdtm/customization/maps02.desc
@@ -0,0 +1 @@
+{'arch': 'aarch64', 'opts': '--pin-memory --use-fork-pid', 'flavor': 'h', 'cmdline': 'pinmemory max_pin_pid_num'}
diff --git a/test/zdtm/customization/maps04.c b/test/zdtm/customization/maps04.c
new file mode 100644
index 0000000..780c566
--- /dev/null
+++ b/test/zdtm/customization/maps04.c
@@ -0,0 +1,57 @@
+#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"
+
+#define MEM_SIZE (1L << 29)
+
+const char *test_doc = "Test big mappings";
+const char *test_author = "Andrew Vagin <avagin@openvz.org";
+
+int main(int argc, char ** argv)
+{
+ void *m;
+ uint32_t crc;
+ int i;
+
+ test_init(argc, argv);
+
+ m = mmap(NULL, MEM_SIZE, PROT_WRITE | PROT_READ,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+
+ if (m == MAP_FAILED) {
+ fail();
+ return 1;
+ }
+
+ crc = ~0;
+ datagen(m, MEM_SIZE, &crc);
+
+ for (i = 0; i < MEM_SIZE / (1<<20); i++)
+ if (mprotect(m + (lrand48() * PAGE_SIZE % MEM_SIZE), PAGE_SIZE, PROT_NONE)) {
+ pr_perror("mprotect");
+ return 1;
+ }
+
+ test_daemon();
+ test_waitsig();
+
+ if (mprotect(m, MEM_SIZE, PROT_READ))
+ pr_perror("mprotect");
+
+ crc = ~0;
+ if (datachk(m, MEM_SIZE, &crc))
+ fail("Mem corrupted");
+ else
+ pass();
+
+ return 0;
+}
diff --git a/test/zdtm/customization/maps04.desc b/test/zdtm/customization/maps04.desc
new file mode 100644
index 0000000..2db7603
--- /dev/null
+++ b/test/zdtm/customization/maps04.desc
@@ -0,0 +1 @@
+{'arch': 'aarch64', 'opts': '--pin-memory --use-fork-pid', 'flavor': 'h', 'timeout': '60', 'cmdline': 'pinmemory max_pin_pid_num'}
diff --git a/test/zdtm/customization/maps05.c b/test/zdtm/customization/maps05.c
new file mode 100644
index 0000000..faa09ee
--- /dev/null
+++ b/test/zdtm/customization/maps05.c
@@ -0,0 +1,91 @@
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <setjmp.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "zdtmtst.h"
+
+const char *test_doc = "Create a bunch of small VMAs and test they survive transferring\n";
+const char *test_author = "Cyrill Gorcunov <gorcunov@openvz.org>";
+
+#define NR_MAPS 4096
+
+#define NR_MAPS_1 (NR_MAPS + 0)
+#define NR_MAPS_2 (NR_MAPS + 1)
+
+#define MAPS_SIZE_1 (140 << 10)
+#define MAPS_SIZE_2 (8192)
+
+int main(int argc, char *argv[])
+{
+ void *map[NR_MAPS + 2] = { }, *addr;
+ size_t i, summary;
+
+ test_init(argc, argv);
+
+ summary = NR_MAPS * 2 * 4096 + MAPS_SIZE_1 + MAPS_SIZE_2 + (1 << 20);
+
+ addr = mmap(NULL, summary, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+ if (addr == MAP_FAILED) {
+ pr_perror("Can't mmap");
+ return 1;
+ }
+ munmap(addr, summary);
+
+ for (i = 0; i < NR_MAPS; i++) {
+ map[i] = mmap(i > 0 ? map[i - 1] + 8192 : addr, 4096, PROT_READ | PROT_WRITE,
+ MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+ if (map[i] == MAP_FAILED) {
+ pr_perror("Can't mmap");
+ return 1;
+ } else {
+ /* Dirtify it */
+ int *v = (void *)map[i];
+ *v = i;
+ }
+ }
+
+ map[NR_MAPS_1] = mmap(map[NR_MAPS_1 - 1] + 8192, MAPS_SIZE_1, PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_ANONYMOUS | MAP_PRIVATE | MAP_GROWSDOWN, -1, 0);
+ if (map[NR_MAPS_1] == MAP_FAILED) {
+ pr_perror("Can't mmap");
+ return 1;
+ } else {
+ /* Dirtify it */
+ int *v = (void *)map[NR_MAPS_1];
+ *v = i;
+ test_msg("map-1: %p %p\n", map[NR_MAPS_1], map[NR_MAPS_1] + MAPS_SIZE_1);
+ }
+
+ map[NR_MAPS_2] = mmap(map[NR_MAPS_1] + MAPS_SIZE_1, MAPS_SIZE_2, PROT_READ | PROT_WRITE,
+ MAP_ANONYMOUS | MAP_PRIVATE | MAP_GROWSDOWN, -1, 0);
+ if (map[NR_MAPS_2] == MAP_FAILED) {
+ pr_perror("Can't mmap");
+ return 1;
+ } else {
+ /* Dirtify it */
+ int *v = (void *)map[NR_MAPS_2];
+ *v = i;
+ test_msg("map-2: %p %p\n", map[NR_MAPS_2], map[NR_MAPS_2] + MAPS_SIZE_2);
+ }
+
+ test_daemon();
+ test_waitsig();
+
+ for (i = 0; i < NR_MAPS; i++) {
+ int *v = (void *)map[i];
+
+ if (*v != i) {
+ fail("Data corrupted at page %lu", (unsigned long)i);
+ return 1;
+ }
+ }
+
+ pass();
+ return 0;
+}
diff --git a/test/zdtm/customization/maps05.desc b/test/zdtm/customization/maps05.desc
new file mode 100644
index 0000000..f14d661
--- /dev/null
+++ b/test/zdtm/customization/maps05.desc
@@ -0,0 +1 @@
+{'arch': 'aarch64', 'opts': '--pin-memory --use-fork-pid', 'flavor': 'h', 'cmdline': 'pinmemory max_pin_pid_num'}
diff --git a/test/zdtm/customization/maps06.c b/test/zdtm/customization/maps06.c
new file mode 100644
index 0000000..7480d6b
--- /dev/null
+++ b/test/zdtm/customization/maps06.c
@@ -0,0 +1,70 @@
+#include "zdtmtst.h"
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+const char *test_doc = "Create a lot of file vma-s";
+const char *test_author = "Andrei Vagin <avagin@openvz.org>";
+
+char *filename;
+TEST_OPTION(filename, string, "file name", 1);
+
+int main(int argc, char ** argv)
+{
+ void *start;
+ int fd, i;
+ int ps = sysconf(_SC_PAGESIZE);
+ int test_size;
+
+ test_init(argc, argv);
+
+ fd = open(filename, O_RDWR | O_CREAT, 0666);
+ if (fd < 0)
+ return 1;
+
+ ftruncate(fd, ps);
+
+ if (ps == 0x1000)
+ test_size = 10240;
+ else
+ test_size = 512;
+
+ start = mmap(0, ps * test_size * 4, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
+ if (start == MAP_FAILED)
+ return 1;
+
+ for (i = 0; i < test_size; i++) {
+ int *addr;
+ addr = mmap(start + i * 3 * ps, ps,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_FILE | MAP_FIXED, fd, 0);
+ if (addr == MAP_FAILED)
+ return 1;
+ addr[0] = i * 2;
+ addr = mmap(start + (i * 3 + 1) * ps, ps,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
+ if (addr == MAP_FAILED)
+ return 1;
+ addr[0] = i;
+ }
+
+ test_daemon();
+
+ test_waitsig();
+
+ for (i = 0; i < test_size; i++) {
+ int *addr;
+ addr = start + i * 3 * ps;
+ if (addr[0] != i * 2)
+ fail();
+ addr = start + (i * 3 + 1) * ps;
+ if (addr[0] != i)
+ fail();
+ }
+
+ pass();
+
+ return 0;
+}
diff --git a/test/zdtm/customization/maps06.desc b/test/zdtm/customization/maps06.desc
new file mode 100644
index 0000000..f14d661
--- /dev/null
+++ b/test/zdtm/customization/maps06.desc
@@ -0,0 +1 @@
+{'arch': 'aarch64', 'opts': '--pin-memory --use-fork-pid', 'flavor': 'h', 'cmdline': 'pinmemory max_pin_pid_num'}
diff --git a/test/zdtm/customization/maps_file_prot.c b/test/zdtm/customization/maps_file_prot.c
new file mode 100644
index 0000000..3b28c1f
--- /dev/null
+++ b/test/zdtm/customization/maps_file_prot.c
@@ -0,0 +1,53 @@
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <linux/limits.h>
+#include "zdtmtst.h"
+
+const char *test_doc = "Test mappings of same file with different prot";
+const char *test_author = "Jamie Liu <jamieliu@google.com>";
+
+char *filename;
+TEST_OPTION(filename, string, "file name", 1);
+
+#define die(fmt, arg...) do { pr_perror(fmt, ## arg); return 1; } while (0)
+
+int main(int argc, char ** argv)
+{
+ void *ro_map, *rw_map;
+ int fd;
+
+ test_init(argc, argv);
+
+ fd = open(filename, O_RDWR | O_CREAT, 0644);
+ if (fd < 0)
+ die("open failed");
+ if (ftruncate(fd, 2 * PAGE_SIZE))
+ die("ftruncate failed");
+
+ ro_map = mmap(NULL, 2 * PAGE_SIZE, PROT_READ, MAP_SHARED, fd, 0);
+ if (ro_map == MAP_FAILED)
+ die("mmap failed");
+ rw_map = ro_map + PAGE_SIZE;
+ if (mprotect(rw_map, PAGE_SIZE, PROT_READ | PROT_WRITE))
+ die("mprotect failed");
+
+ close(fd);
+
+ test_daemon();
+ test_waitsig();
+
+ /* Check that rw_map is still writeable */
+ *(volatile char *)rw_map = 1;
+
+ if (mprotect(ro_map, PAGE_SIZE, PROT_READ | PROT_WRITE)) {
+ fail("mprotect after restore failed");
+ return 1;
+ }
+
+ pass();
+ return 0;
+}
diff --git a/test/zdtm/customization/maps_file_prot.desc b/test/zdtm/customization/maps_file_prot.desc
new file mode 100644
index 0000000..0ec4023
--- /dev/null
+++ b/test/zdtm/customization/maps_file_prot.desc
@@ -0,0 +1 @@
+{'arch': 'aarch64', 'opts': '--pin-memory --use-fork-pid', 'flavor': 'h'}
diff --git a/test/zdtm_ct.c b/test/zdtm_ct.c
index e8d45a9..3bbd3a3 100644
--- a/test/zdtm_ct.c
+++ b/test/zdtm_ct.c
@@ -9,6 +9,7 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
+#include <string.h>
#include <sys/utsname.h>
#ifndef CLONE_NEWTIME
@@ -95,13 +96,23 @@ int main(int argc, char **argv)
{
pid_t pid;
int status;
+ char *val = getenv("ZDTM_NO_PID_NS");
+ int flags = CLONE_NEWNS | CLONE_NEWNET | CLONE_NEWIPC;
+
+ /*
+ * Some customizing mechanism don't support pid namespace,
+ * so every customizing feature testcase will set
+ * 'ZDTM_NO_PID_NS' environment value.
+ */
+ if (val == NULL || strcmp(val, "1") != 0)
+ flags |= CLONE_NEWPID;
/*
* pidns is used to avoid conflicts
* mntns is used to mount /proc
* net is used to avoid conflicts of parasite sockets
*/
- if (unshare(CLONE_NEWNS | CLONE_NEWPID | CLONE_NEWNET | CLONE_NEWIPC))
+ if (unshare(flags))
return 1;
pid = fork();
if (pid == 0) {
--
2.34.1