2092 lines
54 KiB
Diff
2092 lines
54 KiB
Diff
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
|
||
|