mirror of
https://github.com/checkpoint-restore/criu.git
synced 2026-07-23 01:59:04 +00:00
test: add basic test for uffd events
The lazy-pages daemon have to properly track changes to virtual memory
layout of the restored process. The test verifies that lazy-pages daemon
properly reacts to fork(), exit(), madvise(MADV_DONTNEED) and mremap()
events.
Currently, no zdtm tests would generate UFFD_EVENT_{REMAP,REMOVE}.
Signed-off-by: Mike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: Pavel Emelyanov <xemul@virtuozzo.com>
This commit is contained in:
parent
de01e0d3dc
commit
8eae2ee844
2 changed files with 189 additions and 0 deletions
|
|
@ -172,6 +172,7 @@ TST_NOFILE := \
|
|||
cr_veth \
|
||||
sock_peercred \
|
||||
s390x_mmap_high \
|
||||
uffd-events \
|
||||
# jobctl00 \
|
||||
|
||||
include ../Makefile.inc
|
||||
|
|
|
|||
188
test/zdtm/static/uffd-events.c
Normal file
188
test/zdtm/static/uffd-events.c
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
#define _GNU_SOURCE
|
||||
#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"
|
||||
|
||||
const char *test_doc = "Test uffd events";
|
||||
const char *test_author = "Mike Rapoport <rppt@linux.vnet.ibm.com>";
|
||||
|
||||
#define NR_MAPS 5
|
||||
#define MAP_SIZE (1 << 20)
|
||||
|
||||
static void *map[NR_MAPS];
|
||||
|
||||
static int create_mappings(void)
|
||||
{
|
||||
uint32_t crc;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NR_MAPS; i++) {
|
||||
map[i] = mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
||||
if (map[i] == MAP_FAILED) {
|
||||
fail("mmap failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
crc = i;
|
||||
datagen(map[i], MAP_SIZE, &crc);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int verify_zeroes(void *m)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAP_SIZE; i += PAGE_SIZE) {
|
||||
char *p = m + i;
|
||||
if (*p != 0)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_madv_dn(int idx)
|
||||
{
|
||||
void *m = map[idx];
|
||||
|
||||
if (madvise(m, MAP_SIZE, MADV_DONTNEED)) {
|
||||
fail("madvise failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (verify_zeroes(m)) {
|
||||
fail("not zero");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_mremap_grow(int idx)
|
||||
{
|
||||
void *m = map[idx];
|
||||
uint32_t crc = idx;
|
||||
|
||||
m = mremap(m, MAP_SIZE, MAP_SIZE * 2, MREMAP_MAYMOVE);
|
||||
if (m == MAP_FAILED) {
|
||||
fail("mremap failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (datachk(m, MAP_SIZE, &crc)) {
|
||||
fail("Mem corrupted");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* the new part of the mapping should be filled with zeroes */
|
||||
m += MAP_SIZE;
|
||||
if (verify_zeroes(m)) {
|
||||
fail("not zeroes");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_swapped_mappings(int idx)
|
||||
{
|
||||
uint32_t crc = idx;
|
||||
void *m1 = map[idx];
|
||||
void *m2 = map[idx + 1];
|
||||
void *p = map[0];
|
||||
|
||||
p = mremap(m1, MAP_SIZE, MAP_SIZE, MREMAP_MAYMOVE | MREMAP_FIXED, p);
|
||||
if (p == MAP_FAILED) {
|
||||
fail("mremap failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
m1 = mremap(m2, MAP_SIZE, MAP_SIZE, MREMAP_MAYMOVE | MREMAP_FIXED, m1);
|
||||
if (m1 == MAP_FAILED) {
|
||||
fail("mremap failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
m2 = mremap(p, MAP_SIZE, MAP_SIZE, MREMAP_MAYMOVE | MREMAP_FIXED, m2);
|
||||
if (m2 == MAP_FAILED) {
|
||||
fail("mremap failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (datachk(m2, MAP_SIZE, &crc)) {
|
||||
fail("Mem corrupted");
|
||||
return 1;
|
||||
}
|
||||
|
||||
crc = idx + 1;
|
||||
if (datachk(m1, MAP_SIZE, &crc)) {
|
||||
fail("Mem corrupted");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
uint32_t crc;
|
||||
int pid;
|
||||
|
||||
test_init(argc, argv);
|
||||
|
||||
if (create_mappings())
|
||||
return -1;
|
||||
|
||||
test_daemon();
|
||||
test_waitsig();
|
||||
|
||||
/* run some page faults */
|
||||
crc = 0;
|
||||
if (datachk(map[0], MAP_SIZE, &crc)) {
|
||||
fail("Mem corrupted");
|
||||
return 1;
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
fail("Can't fork");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* check madvise(MADV_DONTNEED) */
|
||||
if (check_madv_dn(1))
|
||||
return 1;
|
||||
|
||||
/* check growing mremap */
|
||||
if (check_mremap_grow(2))
|
||||
return 1;
|
||||
|
||||
/* check swapped mappings */
|
||||
if (check_swapped_mappings(3))
|
||||
return 1;
|
||||
|
||||
if (pid) {
|
||||
int status;
|
||||
|
||||
waitpid(-1, &status, 0);
|
||||
if (status) {
|
||||
fail("child failed");
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
pass();
|
||||
return 0;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue