[CRIU] [PATCH] zdtm: fix cow01 test to fail on system errors
Filipe Brandenburger
filbranden at google.com
Wed May 14 10:21:44 PDT 2014
Add extra troubleshooting messages for errors and failures so that the
output can help troubleshoot the issue.
Make error handling more uniform by using -1 for errors (e.g. opening
files, reading from pagemap, etc.) and 1 for failures (data mismatch,
pages not COWed when expected to be, etc.)
Tested: Ran this test with criu versions known to have problems with COW
and with problems to read from pagemap due to the dumpable flag not
being preserved.
Signed-off-by: Filipe Brandenburger <filbranden at google.com>
---
test/zdtm/live/static/cow01.c | 174 +++++++++++++++++++++++++++---------------
1 file changed, 112 insertions(+), 62 deletions(-)
diff --git a/test/zdtm/live/static/cow01.c b/test/zdtm/live/static/cow01.c
index 65570579829b..78cc13977440 100644
--- a/test/zdtm/live/static/cow01.c
+++ b/test/zdtm/live/static/cow01.c
@@ -40,6 +40,7 @@ struct test_cases {
struct test_case tc[TEST_CASES];
void *addr;
int (*init)(struct test_cases *tcs);
+ char *tname;
};
static int init_cow(struct test_cases *);
@@ -49,40 +50,47 @@ static int init_file(struct test_cases *);
static pid_t child_pid;
+/*
+ * A return code of -1 means an error running the test (e.g. error opening a
+ * file, etc.). A return code of 1 means failure, it means criu was not able
+ * to checkpoint and/or restore the process properly.
+ */
#define EXECUTE_ACTION(func) ({ \
int __ret = 0; \
- __ret += func(&sep_tcs); \
- __ret += func(&cow_tcs); \
- __ret += func(&cow_gd_tcs); \
- __ret += func(&file_tcs); \
+ __ret |= func(&sep_tcs); \
+ __ret |= func(&cow_tcs); \
+ __ret |= func(&cow_gd_tcs); \
+ __ret |= func(&file_tcs); \
__ret; \
})
-struct test_cases cow_tcs = {.init = init_cow},
- sep_tcs = {.init = init_sep},
- file_tcs = {.init = init_file},
- cow_gd_tcs = {.init = init_cow_gd};
+struct test_cases cow_tcs = {.init = init_cow, .tname = "cow_tcs"},
+ sep_tcs = {.init = init_sep, .tname = "sep_tcs"},
+ file_tcs = {.init = init_file, .tname = "file_tcs"},
+ cow_gd_tcs = {.init = init_cow_gd, .tname = "cow_gd_tcs"};
uint32_t zero_crc = ~1;
-static int is_cow(void *addr, pid_t p1, pid_t p2)
+static int is_cow(void *addr, pid_t pid_child, pid_t pid_parent,
+ uint64_t *map_child_ret, uint64_t *map_parent_ret)
{
char buf[PATH_MAX];
unsigned long pfn = (unsigned long) addr / PAGE_SIZE;
- uint64_t map1, map2;
- int fd1, fd2, ret, i;
-
- snprintf(buf, sizeof(buf), "/proc/%d/pagemap", p1);
- fd1 = open(buf, O_RDONLY);
- if (fd1 < 0) {
- err("Unable to open file %s", buf);
+ uint64_t map_child, map_parent;
+ int fd_child, fd_parent, ret, i;
+ off_t lseek_ret;
+
+ snprintf(buf, sizeof(buf), "/proc/%d/pagemap", pid_child);
+ fd_child = open(buf, O_RDONLY);
+ if (fd_child < 0) {
+ err("Unable to open child pagemap file %s", buf);
return -1;
}
- snprintf(buf, sizeof(buf), "/proc/%d/pagemap", p2);
- fd2 = open(buf, O_RDONLY);
- if (fd1 < 0) {
- err("Unable to open file %s", buf);
+ snprintf(buf, sizeof(buf), "/proc/%d/pagemap", pid_parent);
+ fd_parent = open(buf, O_RDONLY);
+ if (fd_parent < 0) {
+ err("Unable to open parent pagemap file %s", buf);
return -1;
}
@@ -91,29 +99,48 @@ static int is_cow(void *addr, pid_t p1, pid_t p2)
* so we should do several iterations.
*/
for (i = 0; i < 10; i++) {
- lseek(fd1, pfn * sizeof(map1), SEEK_SET);
- lseek(fd2, pfn * sizeof(map2), SEEK_SET);
+ lseek_ret = lseek(fd_child, pfn * sizeof(map_child), SEEK_SET);
+ if (lseek_ret == (off_t) -1) {
+ err("Unable to seek child pagemap to virtual addr %#08lx",
+ pfn * PAGE_SIZE);
+ return -1;
+ }
- ret = read(fd1, &map1, sizeof(map1));
- if (ret != sizeof(map1)) {
- err("Unable to read data");
+ lseek_ret = lseek(fd_parent, pfn * sizeof(map_parent), SEEK_SET);
+ if (lseek_ret == (off_t) -1) {
+ err("Unable to seek parent pagemap to virtual addr %#08lx",
+ pfn * PAGE_SIZE);
return -1;
}
- ret = read(fd2, &map2, sizeof(map2));
- if (ret != sizeof(map2)) {
- err("Unable to read data");
+ ret = read(fd_child, &map_child, sizeof(map_child));
+ if (ret != sizeof(map_child)) {
+ err("Unable to read child pagemap at virtual addr %#08lx",
+ pfn * PAGE_SIZE);
return -1;
}
- if (map1 == map2)
+ ret = read(fd_parent, &map_parent, sizeof(map_parent));
+ if (ret != sizeof(map_parent)) {
+ err("Unable to read parent pagemap at virtual addr %#08lx",
+ pfn * PAGE_SIZE);
+ return -1;
+ }
+
+ if (map_child == map_parent)
break;
}
- close(fd1);
- close(fd2);
+ close(fd_child);
+ close(fd_parent);
+
+ if (map_child_ret)
+ *map_child_ret = map_child;
+ if (map_parent_ret)
+ *map_parent_ret = map_parent;
- return map1 == map2;
+ // Return 0 for success, 1 if the pages differ.
+ return map_child != map_parent;
}
static int child_prep(struct test_cases *test_cases)
@@ -148,8 +175,10 @@ static int child_check(struct test_cases *test_cases)
datasum(addr + i * PAGE_SIZE, PAGE_SIZE, &crc);
if (crc != tc->crc_child) {
- fail("%d: %p data mismatch\n", i, addr + i * PAGE_SIZE);
- ret++;
+ errno = 0;
+ fail("%s[%#x]: %p child data mismatch (expected [%04x] got [%04x])",
+ test_cases->tname, i, addr + i * PAGE_SIZE, tc->crc_child, crc);
+ ret |= 1;
}
}
@@ -220,8 +249,10 @@ static int parent_check(struct test_cases *test_cases)
datasum(addr + i * PAGE_SIZE, PAGE_SIZE, &crc);
if (crc != tc->crc_parent) {
- fail("%x: %p data mismatch\n", i, addr + i * PAGE_SIZE);
- ret++;
+ errno = 0;
+ fail("%s[%#x]: %p parent data mismatch (expected [%04x] got [%04x])",
+ test_cases->tname, i, addr + i * PAGE_SIZE, tc->crc_parent, crc);
+ ret |= 1;
}
if (test_cases == &sep_tcs)
@@ -229,11 +260,21 @@ static int parent_check(struct test_cases *test_cases)
if (!tc->a_f_write_child &&
!tc->a_f_write_parent &&
- tc->b_f_write)
- if (!is_cow(addr + i * PAGE_SIZE, child_pid, getpid())) {
- fail("%x: %p is not COW-ed\n", i, addr + i * PAGE_SIZE);
- ret++;
+ tc->b_f_write) {
+ uint64_t map_child, map_parent;
+ int is_cow_ret;
+
+ is_cow_ret = is_cow(addr + i * PAGE_SIZE, child_pid, getpid(),
+ &map_child, &map_parent);
+ ret |= is_cow_ret;
+ if (is_cow_ret == 1) {
+ errno = 0;
+ fail("%s[%#x]: %p is not COW-ed (pagemap of "
+ "child=[%#08lx], parent=[%#08lx])",
+ test_cases->tname, i, addr + i * PAGE_SIZE,
+ map_child, map_parent);
}
+ }
}
return ret;
@@ -248,7 +289,7 @@ static int __init_cow(struct test_cases *tcs, int flags)
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (addr == MAP_FAILED) {
- err("Can't allocate memory\n");
+ err("Can't allocate memory");
return -1;
}
@@ -264,7 +305,7 @@ static int __init_cow(struct test_cases *tcs, int flags)
mmap(addr + PAGE_SIZE * TEST_CASES, PAGE_SIZE, PROT_NONE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED | flags, -1, 0);
- test_msg("cow_addr=%p\n", addr);
+ test_msg("addr[%s]=%p\n", tcs->tname, tcs->addr);
for (i = 0; i < TEST_CASES; i++) {
struct test_case *tc = tcs->tc + i;
tc->crc_parent = zero_crc;
@@ -292,11 +333,11 @@ static int init_sep(struct test_cases *tcs)
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (tcs->addr == MAP_FAILED) {
- err("Can't allocate memory\n");
- return 1;
+ err("Can't allocate memory");
+ return -1;
}
- test_msg("sep_addr=%p\n", tcs->addr);
+ test_msg("addr[%s]=%p\n", tcs->tname, tcs->addr);
for (i = 0; i < TEST_CASES; i++) {
struct test_case *tc = tcs->tc + i;
tc->crc_parent = zero_crc;
@@ -324,7 +365,7 @@ static int init_file(struct test_cases *tcs)
datagen2(buf, sizeof(buf), &crc);
ret = write(fd, buf, sizeof(buf));
if (ret != sizeof(buf)) {
- err("Unable to write data in a test file");
+ err("Unable to write data in test file %s", filename);
return -1;
}
@@ -336,11 +377,11 @@ static int init_file(struct test_cases *tcs)
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_FILE, fd, 0);
if (tcs->addr == MAP_FAILED) {
- err("Can't allocate memory\n");
- return 1;
+ err("Can't allocate memory");
+ return -1;
}
- test_msg("file_addr=%p\n", tcs->addr);
+ test_msg("addr[%s]=%p\n", tcs->tname, tcs->addr);
close(fd);
return 0;
@@ -354,8 +395,8 @@ static int child(task_waiter_t *child_waiter)
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
if (sep_tcs.addr == MAP_FAILED) {
- err("Can't allocate memory\n");
- return 1;
+ err("Can't allocate memory");
+ return -1;
}
EXECUTE_ACTION(child_prep);
@@ -364,15 +405,18 @@ static int child(task_waiter_t *child_waiter)
test_waitsig();
- ret = EXECUTE_ACTION(child_check);
+ ret |= EXECUTE_ACTION(child_check);
- return ret ? -1: 0;
+ // Exit code of child process, so return 2 for a test error, 1 for a
+ // test failure (child_check got mismatched checksums) and 0 for
+ // success.
+ return (ret < 0) ? 2 : (ret != 0);
}
int main(int argc, char ** argv)
{
uint8_t zero_page[PAGE_SIZE];
- int status, err = 0;
+ int status, ret = 0;
task_waiter_t child_waiter;
task_waiter_init(&child_waiter);
@@ -384,11 +428,13 @@ int main(int argc, char ** argv)
test_init(argc, argv);
if (EXECUTE_ACTION(parent_before_fork))
- return 1;
+ return 2;
child_pid = test_fork();
- if (child_pid < 0)
- return -1;
+ if (child_pid < 0) {
+ err("Can't fork");
+ return 2;
+ }
if (child_pid == 0)
return child(&child_waiter);
@@ -401,18 +447,22 @@ int main(int argc, char ** argv)
test_waitsig();
- err = EXECUTE_ACTION(parent_check);
+ ret |= EXECUTE_ACTION(parent_check);
kill(child_pid, SIGTERM);
wait(&status);
unlink(filename);
- if (status)
- return 1;
+ if (WIFEXITED(status) && WEXITSTATUS(status) != 2)
+ ret |= WEXITSTATUS(status);
+ else
+ ret |= -1;
- if (err == 0)
+ if (ret == 0)
pass();
- return 0;
+ // Exit code, so return 2 for a test error, 1 for a test failure and 0
+ // for success.
+ return (ret < 0) ? 2 : (ret != 0);
}
--
1.9.1.423.g4596e3a
More information about the CRIU
mailing list