android13/external/ltp/testcases/kernel/syscalls/userfaultfd/userfaultfd01.c

130 lines
2.8 KiB
C

// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2019 SUSE LLC
* Author: Christian Amann <camann@suse.com>
*
* Test userfaultfd
*
* Force a pagefault event and handle it using userfaultfd
* from a different thread
*/
#include "config.h"
#include "tst_test.h"
#ifdef HAVE_LINUX_USERFAULTFD_H
#include <linux/userfaultfd.h>
#include <poll.h>
#include "tst_safe_macros.h"
#include "tst_safe_pthread.h"
#include "lapi/syscalls.h"
static int page_size;
static char *page;
static void *copy_page;
static int uffd;
static int sys_userfaultfd(int flags)
{
return tst_syscall(__NR_userfaultfd, flags);
}
static void set_pages(void)
{
page_size = sysconf(_SC_PAGE_SIZE);
page = SAFE_MMAP(NULL, page_size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
copy_page = SAFE_MMAP(NULL, page_size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
}
static void handle_thread(void)
{
static struct uffd_msg msg;
struct uffdio_copy uffdio_copy;
struct pollfd pollfd;
int nready;
pollfd.fd = uffd;
pollfd.events = POLLIN;
nready = poll(&pollfd, 1, -1);
if (nready == -1)
tst_brk(TBROK | TERRNO,
"Error on poll");
SAFE_READ(1, uffd, &msg, sizeof(msg));
if (msg.event != UFFD_EVENT_PAGEFAULT)
tst_brk(TBROK | TERRNO,
"Received unexpected UFFD_EVENT");
memset(copy_page, 'X', page_size);
uffdio_copy.src = (unsigned long) copy_page;
uffdio_copy.dst = (unsigned long) msg.arg.pagefault.address
& ~(page_size - 1);
uffdio_copy.len = page_size;
uffdio_copy.mode = 0;
uffdio_copy.copy = 0;
SAFE_IOCTL(uffd, UFFDIO_COPY, &uffdio_copy);
close(uffd);
}
static void run(void)
{
pthread_t thr;
struct uffdio_api uffdio_api;
struct uffdio_register uffdio_register;
set_pages();
TEST(sys_userfaultfd(O_CLOEXEC | O_NONBLOCK));
if (TST_RET == -1) {
if (TST_ERR == EPERM) {
tst_res(TCONF, "Hint: check /proc/sys/vm/unprivileged_userfaultfd");
tst_brk(TCONF | TTERRNO,
"userfaultfd() requires CAP_SYS_PTRACE on this system");
} else
tst_brk(TBROK | TTERRNO,
"Could not create userfault file descriptor");
}
uffd = TST_RET;
uffdio_api.api = UFFD_API;
uffdio_api.features = 0;
SAFE_IOCTL(uffd, UFFDIO_API, &uffdio_api);
uffdio_register.range.start = (unsigned long) page;
uffdio_register.range.len = page_size;
uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING;
SAFE_IOCTL(uffd, UFFDIO_REGISTER, &uffdio_register);
SAFE_PTHREAD_CREATE(&thr, NULL,
(void * (*)(void *)) handle_thread, NULL);
char c = page[0xf];
if (c == 'X')
tst_res(TPASS, "Pagefault handled!");
else
tst_res(TFAIL, "Pagefault not handled!");
SAFE_PTHREAD_JOIN(thr, NULL);
}
static struct tst_test test = {
.test_all = run,
.min_kver = "4.3",
.timeout = 20
};
#else
TST_TEST_TCONF("This system does not provide userfaultfd support");
#endif