代码拉取完成,页面将自动刷新
同步操作将从 src-openEuler/criu 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
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
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。