Skip to content

Commit 7336cf2

Browse files
userfaultfd: Add test using /dev/userfaultfd instead of syscall
Signed-off-by: Ricardo Branco <[email protected]>
1 parent df452c8 commit 7336cf2

File tree

4 files changed

+132
-0
lines changed

4 files changed

+132
-0
lines changed

runtest/syscalls

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1772,6 +1772,7 @@ umount2_02 umount2_02
17721772
userfaultfd01 userfaultfd01
17731773
userfaultfd02 userfaultfd02
17741774
userfaultfd03 userfaultfd03
1775+
userfaultfd04 userfaultfd04
17751776

17761777
ustat01 ustat01
17771778
ustat02 ustat02
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
/userfaultfd01
22
/userfaultfd02
33
/userfaultfd03
4+
/userfaultfd04

testcases/kernel/syscalls/userfaultfd/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@ include $(top_srcdir)/include/mk/generic_leaf_target.mk
1414
userfaultfd01: CFLAGS += -pthread
1515
userfaultfd02: CFLAGS += -pthread
1616
userfaultfd03: CFLAGS += -pthread
17+
userfaultfd04: CFLAGS += -pthread
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
/*
3+
* Copyright (c) 2025 SUSE LLC
4+
* Author: Christian Amann <[email protected]>
5+
* Author: Ricardo Branco <[email protected]>
6+
*
7+
* Test userfaultfd via /dev/userfaultfd
8+
*
9+
* Force a pagefault event and handle it using userfaultfd
10+
* from a different thread
11+
*/
12+
13+
#include "config.h"
14+
#include "tst_test.h"
15+
16+
#include <poll.h>
17+
18+
#include "tst_safe_macros.h"
19+
#include "tst_safe_pthread.h"
20+
#include "lapi/userfaultfd.h"
21+
22+
static int page_size;
23+
static char *page;
24+
static void *copy_page;
25+
static int uffd;
26+
27+
static int open_userfaultfd(int flags)
28+
{
29+
int fd, fd2;
30+
31+
fd = SAFE_OPEN("/dev/userfaultfd", O_RDWR);
32+
33+
fd2 = SAFE_IOCTL(fd, USERFAULTFD_IOC_NEW, flags);
34+
35+
SAFE_CLOSE(fd);
36+
37+
return fd2;
38+
}
39+
40+
static void set_pages(void)
41+
{
42+
page_size = sysconf(_SC_PAGE_SIZE);
43+
page = SAFE_MMAP(NULL, page_size, PROT_READ | PROT_WRITE,
44+
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
45+
copy_page = SAFE_MMAP(NULL, page_size, PROT_READ | PROT_WRITE,
46+
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
47+
}
48+
49+
static void handle_thread(void)
50+
{
51+
static struct uffd_msg msg;
52+
struct uffdio_copy uffdio_copy;
53+
54+
struct pollfd pollfd;
55+
int nready;
56+
57+
pollfd.fd = uffd;
58+
pollfd.events = POLLIN;
59+
nready = poll(&pollfd, 1, -1);
60+
if (nready == -1)
61+
tst_brk(TBROK | TERRNO,
62+
"Error on poll");
63+
64+
SAFE_READ(1, uffd, &msg, sizeof(msg));
65+
66+
if (msg.event != UFFD_EVENT_PAGEFAULT)
67+
tst_brk(TBROK | TERRNO,
68+
"Received unexpected UFFD_EVENT");
69+
70+
memset(copy_page, 'X', page_size);
71+
72+
uffdio_copy.src = (unsigned long) copy_page;
73+
74+
uffdio_copy.dst = (unsigned long) msg.arg.pagefault.address
75+
& ~(page_size - 1);
76+
uffdio_copy.len = page_size;
77+
uffdio_copy.mode = 0;
78+
uffdio_copy.copy = 0;
79+
SAFE_IOCTL(uffd, UFFDIO_COPY, &uffdio_copy);
80+
81+
close(uffd);
82+
}
83+
84+
static void run(void)
85+
{
86+
pthread_t thr;
87+
struct uffdio_api uffdio_api;
88+
struct uffdio_register uffdio_register;
89+
90+
set_pages();
91+
92+
TEST(open_userfaultfd(O_CLOEXEC | O_NONBLOCK));
93+
94+
if (TST_RET == -1) {
95+
if (TST_ERR == EPERM) {
96+
tst_brk(TCONF, "Hint: check /dev/userfaultfd permissions");
97+
} else
98+
tst_brk(TBROK | TTERRNO,
99+
"Could not create userfault file descriptor");
100+
}
101+
102+
uffd = TST_RET;
103+
uffdio_api.api = UFFD_API;
104+
uffdio_api.features = 0;
105+
SAFE_IOCTL(uffd, UFFDIO_API, &uffdio_api);
106+
107+
uffdio_register.range.start = (unsigned long) page;
108+
uffdio_register.range.len = page_size;
109+
uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING;
110+
111+
SAFE_IOCTL(uffd, UFFDIO_REGISTER, &uffdio_register);
112+
113+
SAFE_PTHREAD_CREATE(&thr, NULL,
114+
(void * (*)(void *)) handle_thread, NULL);
115+
116+
char c = page[0xf];
117+
118+
if (c == 'X')
119+
tst_res(TPASS, "Pagefault handled via /dev/userfaultfd");
120+
else
121+
tst_res(TFAIL, "Pagefault not handled via /dev/userfaultfd");
122+
123+
SAFE_PTHREAD_JOIN(thr, NULL);
124+
}
125+
126+
static struct tst_test test = {
127+
.test_all = run,
128+
.min_kver = "5.11",
129+
};

0 commit comments

Comments
 (0)