Skip to content

Commit 9daa401

Browse files
userfaultfd: Add test for UFFDIO_MOVE
Signed-off-by: Ricardo Branco <[email protected]>
1 parent bb13c18 commit 9daa401

File tree

4 files changed

+122
-0
lines changed

4 files changed

+122
-0
lines changed

runtest/syscalls

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1770,6 +1770,7 @@ umount2_01 umount2_01
17701770
umount2_02 umount2_02
17711771

17721772
userfaultfd01 userfaultfd01
1773+
userfaultfd02 userfaultfd02
17731774

17741775
ustat01 ustat01
17751776
ustat02 ustat02
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
/userfaultfd01
2+
/userfaultfd02

testcases/kernel/syscalls/userfaultfd/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ include $(top_srcdir)/include/mk/testcases.mk
1212
include $(top_srcdir)/include/mk/generic_leaf_target.mk
1313

1414
userfaultfd01: CFLAGS += -pthread
15+
userfaultfd02: CFLAGS += -pthread
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
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+
8+
/*\
9+
* Force a pagefault event and handle it using :man2:`userfaultfd`
10+
* from a different thread using UFFDIO_MOVE
11+
*/
12+
13+
#include "config.h"
14+
#include <poll.h>
15+
#include "tst_test.h"
16+
#include "tst_safe_macros.h"
17+
#include "tst_safe_pthread.h"
18+
#include "lapi/userfaultfd.h"
19+
20+
static int page_size;
21+
static char *page;
22+
static void *move_page;
23+
static int uffd;
24+
25+
static int sys_userfaultfd(int flags)
26+
{
27+
return tst_syscall(__NR_userfaultfd, flags);
28+
}
29+
30+
static void set_pages(void)
31+
{
32+
page_size = sysconf(_SC_PAGE_SIZE);
33+
page = SAFE_MMAP(NULL, page_size, PROT_READ | PROT_WRITE,
34+
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
35+
move_page = SAFE_MMAP(NULL, page_size, PROT_READ | PROT_WRITE,
36+
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
37+
}
38+
39+
static void handle_thread(void)
40+
{
41+
static struct uffd_msg msg;
42+
struct uffdio_move uffdio_move;
43+
44+
struct pollfd pollfd;
45+
int nready;
46+
47+
pollfd.fd = uffd;
48+
pollfd.events = POLLIN;
49+
nready = poll(&pollfd, 1, -1);
50+
if (nready == -1)
51+
tst_brk(TBROK | TERRNO, "Error on poll");
52+
53+
SAFE_READ(1, uffd, &msg, sizeof(msg));
54+
55+
if (msg.event != UFFD_EVENT_PAGEFAULT)
56+
tst_brk(TBROK | TERRNO, "Received unexpected UFFD_EVENT");
57+
58+
memset(move_page, 'X', page_size);
59+
60+
uffdio_move.src = (unsigned long) move_page;
61+
62+
uffdio_move.dst = (unsigned long) msg.arg.pagefault.address
63+
& ~(page_size - 1);
64+
uffdio_move.len = page_size;
65+
uffdio_move.mode = 0;
66+
uffdio_move.move = 0;
67+
SAFE_IOCTL(uffd, UFFDIO_MOVE, &uffdio_move);
68+
69+
close(uffd);
70+
}
71+
72+
static void run(void)
73+
{
74+
pthread_t thr;
75+
struct uffdio_api uffdio_api;
76+
struct uffdio_register uffdio_register;
77+
78+
set_pages();
79+
80+
TEST(sys_userfaultfd(O_CLOEXEC | O_NONBLOCK));
81+
82+
if (TST_RET == -1) {
83+
if (TST_ERR == EPERM) {
84+
tst_res(TCONF, "Hint: check /proc/sys/vm/unprivileged_userfaultfd");
85+
tst_brk(TCONF | TTERRNO,
86+
"userfaultfd() requires CAP_SYS_PTRACE on this system");
87+
} else
88+
tst_brk(TBROK | TTERRNO,
89+
"Could not create userfault file descriptor");
90+
}
91+
92+
uffd = TST_RET;
93+
uffdio_api.api = UFFD_API;
94+
uffdio_api.features = 0;
95+
SAFE_IOCTL(uffd, UFFDIO_API, &uffdio_api);
96+
97+
uffdio_register.range.start = (unsigned long) page;
98+
uffdio_register.range.len = page_size;
99+
uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING;
100+
101+
SAFE_IOCTL(uffd, UFFDIO_REGISTER, &uffdio_register);
102+
103+
SAFE_PTHREAD_CREATE(&thr, NULL,
104+
(void * (*)(void *)) handle_thread, NULL);
105+
106+
char c = page[0xf];
107+
108+
if (c == 'X')
109+
tst_res(TPASS, "Pagefault handled via UFFDIO_MOVE");
110+
else
111+
tst_res(TFAIL, "Pagefault not handled via UFFDIO_MOVE");
112+
113+
SAFE_PTHREAD_JOIN(thr, NULL);
114+
}
115+
116+
static struct tst_test test = {
117+
.test_all = run,
118+
.min_kver = "6.8",
119+
};

0 commit comments

Comments
 (0)