Commit 8eae2ee8 authored by Mike Rapoport's avatar Mike Rapoport Committed by Andrei Vagin

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: 's avatarMike Rapoport <rppt@linux.vnet.ibm.com>
Signed-off-by: 's avatarPavel Emelyanov <xemul@virtuozzo.com>
parent de01e0d3
...@@ -172,6 +172,7 @@ TST_NOFILE := \ ...@@ -172,6 +172,7 @@ TST_NOFILE := \
cr_veth \ cr_veth \
sock_peercred \ sock_peercred \
s390x_mmap_high \ s390x_mmap_high \
uffd-events \
# jobctl00 \ # jobctl00 \
include ../Makefile.inc include ../Makefile.inc
......
#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;
}
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