Commit b99fa574 authored by Andrey Vagin's avatar Andrey Vagin Committed by Pavel Emelyanov

zdtm: add transition test for memory

This test does a few operation in a loop
* create a mapping with random flags
* touch a few pages in a new mapping, if it's writable

This test has two processes. The second process goes a predefined value
of steps behind the first one. When we need to check the result, we stop
the first process, wait until the second process come to the same point
and compare these processes. The processes are dumped in different
states, but at the end both processes must be in the same state.

bash -x test/zdtm.sh -s -i 5 -r transition/maps007
...
(00.743662) Error (page-read.c:107): Missing 139773474525184 in parent pagemap, current iov: base=7f1f8c4cf000,len=4096
(00.743696) Error (page-xfer.c:523): Hole 0x7f1f8c4c5000/4096 not found in parent
(00.744196) Error (mem.c:331): Can't dump page with parasite
(00.758201) Error (cr-dump.c:1828): Dumping FAILED.
Signed-off-by: 's avatarAndrey Vagin <avagin@openvz.org>
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent 04b64035
......@@ -12,6 +12,7 @@ TST_NOFILE = \
fork \
fork2 \
thread-bomb \
maps007 \
TST_FILE = \
file_read \
......
#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 (1 << 20)
#define MEM_SIZE (1 << 29)
#define PAGE_SIZE 4096
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 {
uint32_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;
atomic_set(&shm->delta, v);
futex_set(&shm->stop, 0);
child = fork();
if (child < 0) {
err("fork");
return 1;
}
if (child)
test_daemon();
while (test_go()) {
void *ret;
unsigned long size;
int prot = PROT_NONE;
if (child) {
atomic_inc(&shm->delta);
} else {
if (!futex_get(&shm->stop))
/* MAX_DELTA steps behind the parent */
while (atomic_get(&shm->delta) < MAX_DELTA);
else if (atomic_get(&shm->delta) == 0)
break;
atomic_dec(&shm->delta);
}
count++;
p = start + ((lrand48() * PAGE_SIZE) % MEM_SIZE);
size = (lrand48() * PAGE_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) {
err("%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();
}
}
err("count %d", count);
if (child == 0) {
futex_set_and_wake(&shm->stop, 2);
test_waitsig();
} else {
int readable = 0;
/* stop the child */
futex_set(&shm->stop, 1);
/* 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) {
err("%p %d %d", p, lret, rret);
goto err;
}
if (lret < 0)
continue;
readable++;
if (memcmp(rbuf, lbuf, PAGE_SIZE)) {
err("%p", p);
goto err;
}
}
err("readable %d", readable);
kill(child, SIGTRAP);
wait(NULL);
pass();
}
return 0;
err:
kill(child, SIGKILL);
return 1;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment