From: Ricardo Branco <rbranco@suse.de>
To: ltp@lists.linux.it
Subject: [LTP] [PATCH v4 2/2] userfaultfd: Add new test using UFFDIO_CONTINUE
Date: Wed, 1 Apr 2026 23:03:34 +0200 [thread overview]
Message-ID: <20260401210338.485029-2-rbranco@suse.de> (raw)
In-Reply-To: <20260401210338.485029-1-rbranco@suse.de>
Add test to exercise UFFDIO_CONTINUE on a shared-memory mapping with
UFFD_PAGEFAULT_FLAG_MINOR. The test populates a memfd-backed page,
drops only the PTEs with MADV_DONTNEED, verifies that the resulting
fault is reported as MINOR, updates the page cache from the handler
thread, and resumes execution with UFFDIO_CONTINUE.
Signed-off-by: Ricardo Branco <rbranco@suse.de>
---
include/lapi/userfaultfd.h | 1 +
runtest/syscalls | 1 +
.../kernel/syscalls/userfaultfd/.gitignore | 1 +
.../kernel/syscalls/userfaultfd/Makefile | 1 +
.../syscalls/userfaultfd/userfaultfd07.c | 152 ++++++++++++++++++
5 files changed, 156 insertions(+)
create mode 100644 testcases/kernel/syscalls/userfaultfd/userfaultfd07.c
diff --git a/include/lapi/userfaultfd.h b/include/lapi/userfaultfd.h
index aab3890b7..c05b8dbf5 100644
--- a/include/lapi/userfaultfd.h
+++ b/include/lapi/userfaultfd.h
@@ -171,6 +171,7 @@ struct uffdio_zeropage {
#ifndef UFFD_PAGEFAULT_FLAG_MINOR
#define UFFD_FEATURE_MINOR_HUGETLBFS (1<<9)
#define UFFDIO_REGISTER_MODE_MINOR ((__u64)1<<2)
+#define UFFD_PAGEFAULT_FLAG_MINOR (1<<2)
#define _UFFDIO_CONTINUE (0x07)
#define UFFDIO_CONTINUE _IOWR(UFFDIO, _UFFDIO_CONTINUE, \
diff --git a/runtest/syscalls b/runtest/syscalls
index 6ba0227a8..534140f42 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -1780,6 +1780,7 @@ userfaultfd03 userfaultfd03
userfaultfd04 userfaultfd04
userfaultfd05 userfaultfd05
userfaultfd06 userfaultfd06
+userfaultfd07 userfaultfd07
ustat01 ustat01
ustat02 ustat02
diff --git a/testcases/kernel/syscalls/userfaultfd/.gitignore b/testcases/kernel/syscalls/userfaultfd/.gitignore
index bc32fdf3b..3478a162e 100644
--- a/testcases/kernel/syscalls/userfaultfd/.gitignore
+++ b/testcases/kernel/syscalls/userfaultfd/.gitignore
@@ -4,3 +4,4 @@
/userfaultfd04
/userfaultfd05
/userfaultfd06
+/userfaultfd07
diff --git a/testcases/kernel/syscalls/userfaultfd/Makefile b/testcases/kernel/syscalls/userfaultfd/Makefile
index 3252e47df..257249e88 100644
--- a/testcases/kernel/syscalls/userfaultfd/Makefile
+++ b/testcases/kernel/syscalls/userfaultfd/Makefile
@@ -17,3 +17,4 @@ userfaultfd03: CFLAGS += -pthread
userfaultfd04: CFLAGS += -pthread
userfaultfd05: CFLAGS += -pthread
userfaultfd06: CFLAGS += -pthread
+userfaultfd07: CFLAGS += -pthread
diff --git a/testcases/kernel/syscalls/userfaultfd/userfaultfd07.c b/testcases/kernel/syscalls/userfaultfd/userfaultfd07.c
new file mode 100644
index 000000000..96b273262
--- /dev/null
+++ b/testcases/kernel/syscalls/userfaultfd/userfaultfd07.c
@@ -0,0 +1,152 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2026 SUSE LLC
+ * Author: Ricardo Branco <rbranco@suse.com>
+ */
+
+/*\
+ * Force a pagefault event and handle it using :manpage:`userfaultfd(2)`
+ * from a different thread testing UFFDIO_CONTINUE.
+ */
+
+#include "config.h"
+#include <poll.h>
+#include <unistd.h>
+#include "tst_test.h"
+#include "tst_safe_macros.h"
+#include "tst_safe_prw.h"
+#include "tst_safe_pthread.h"
+#include "lapi/memfd.h"
+#include "lapi/userfaultfd.h"
+#include "lapi/syscalls.h"
+
+static long page_size;
+static char *page;
+static int uffd = -1;
+static int memfd = -1;
+
+static void set_pages(void)
+{
+ char ch = 'A';
+
+ page_size = SAFE_SYSCONF(_SC_PAGE_SIZE);
+
+ memfd = sys_memfd_create("ltp-uffd-continue", MFD_CLOEXEC);
+ if (memfd < 0)
+ tst_brk(TBROK | TERRNO, "memfd_create failed");
+
+ SAFE_FTRUNCATE(memfd, page_size);
+
+ /*
+ * Populate page cache so that after MADV_DONTNEED the next access
+ * can generate a MINOR fault rather than a MISSING fault.
+ */
+ SAFE_PWRITE(1, memfd, &ch, 1, 0);
+
+ page = SAFE_MMAP(NULL, page_size, PROT_READ, MAP_SHARED, memfd, 0);
+}
+
+static void reset_pages(void)
+{
+ if (page) {
+ SAFE_MUNMAP(page, page_size);
+ page = NULL;
+ }
+
+ if (memfd != -1)
+ SAFE_CLOSE(memfd);
+
+ if (uffd != -1)
+ SAFE_CLOSE(uffd);
+}
+
+static void *handle_thread(void *arg LTP_ATTRIBUTE_UNUSED)
+{
+ static struct uffd_msg msg;
+ struct uffdio_continue uffdio_continue = {};
+ struct pollfd pollfd;
+ int nready;
+ char z = 'Z';
+
+ 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(TFAIL, "Received unexpected UFFD_EVENT %d", msg.event);
+
+ if (!(msg.arg.pagefault.flags & UFFD_PAGEFAULT_FLAG_MINOR)) {
+ tst_brk(TBROK, "expected MINOR fault, got flags=0x%llx",
+ (unsigned long long)msg.arg.pagefault.flags);
+ }
+
+ /* Update the shmem page in page cache before resuming the fault. */
+ SAFE_PWRITE(1, memfd, &z, 1, 0);
+
+ uffdio_continue.range.start =
+ msg.arg.pagefault.address & ~((unsigned long)page_size - 1);
+ uffdio_continue.range.len = page_size;
+
+ SAFE_IOCTL(uffd, UFFDIO_CONTINUE, &uffdio_continue);
+
+ SAFE_CLOSE(uffd);
+ return NULL;
+}
+
+static void run(void)
+{
+ pthread_t thr;
+ struct uffdio_api uffdio_api = {};
+ struct uffdio_register uffdio_register;
+
+ set_pages();
+
+ uffd = SAFE_USERFAULTFD(O_CLOEXEC | O_NONBLOCK, true);
+
+ uffdio_api.api = UFFD_API;
+ uffdio_api.features = UFFD_FEATURE_MINOR_SHMEM;
+
+ SAFE_IOCTL(uffd, UFFDIO_API, &uffdio_api);
+
+ if (!(uffdio_api.features & UFFD_FEATURE_MINOR_SHMEM))
+ tst_brk(TCONF, "UFFD_FEATURE_MINOR_SHMEM not supported");
+
+ uffdio_register.range.start = (unsigned long) page;
+ uffdio_register.range.len = page_size;
+ uffdio_register.mode = UFFDIO_REGISTER_MODE_MINOR;
+
+ SAFE_IOCTL(uffd, UFFDIO_REGISTER, &uffdio_register);
+
+ /*
+ * Drop PTEs while retaining the cached shmem page so the next access
+ * faults in MINOR mode.
+ */
+ if (madvise(page, page_size, MADV_DONTNEED) < 0)
+ tst_brk(TBROK | TERRNO, "madvise MADV_DONTNEED failed");
+
+ SAFE_PTHREAD_CREATE(&thr, NULL, (void *) handle_thread, NULL);
+
+ char c = page[0];
+
+ if (c == 'Z')
+ tst_res(TPASS, "Pagefault handled via UFFDIO_CONTINUE");
+ else
+ tst_res(TFAIL, "pagefault not handled via UFFDIO_CONTINUE, got '%c'", c);
+
+ SAFE_PTHREAD_JOIN(thr, NULL);
+ reset_pages();
+}
+
+static struct tst_test test = {
+ .test_all = run,
+ /*
+ * UFFDIO_CONTINUE is available since 5.13 but
+ * UFFD_FEATURE_MINOR_SHMEM appeared in 5.14
+ */
+ .min_kver = "5.14",
+ .cleanup = reset_pages,
+};
--
2.53.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
next prev parent reply other threads:[~2026-04-01 21:04 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-31 22:03 [LTP] [PATCH v3] userfaultfd: Add new test using UFFDIO_CONTINUE Ricardo Branco
2026-04-01 21:03 ` [LTP] [PATCH v4 1/2] memfd_create: move sys_memfd_create() to lapi/memfd.h Ricardo Branco
2026-04-01 21:03 ` Ricardo Branco [this message]
2026-04-09 14:15 ` [LTP] [PATCH v4 2/2] userfaultfd: Add new test using UFFDIO_CONTINUE Andrea Cervesato via ltp
2026-04-09 14:51 ` Andrea Cervesato via ltp
2026-04-09 15:19 ` [LTP] [PATCH v5 1/2] memfd_create: move sys_memfd_create() to lapi/memfd.h Ricardo Branco
2026-04-09 15:19 ` [LTP] [PATCH v5 2/2] userfaultfd: Add new test using UFFDIO_CONTINUE Ricardo Branco
2026-04-11 9:47 ` [LTP] [PATCH v6 1/2] memfd_create: move sys_memfd_create() to lapi/memfd.h Ricardo Branco
2026-04-11 9:47 ` [LTP] [PATCH v6 2/2] userfaultfd: Add new test using UFFDIO_CONTINUE Ricardo Branco
2026-04-29 14:35 ` Andrea Cervesato via ltp
2026-04-29 14:37 ` Andrea Cervesato via ltp
2026-05-05 14:12 ` Cyril Hrubis
2026-05-05 14:28 ` Ricardo Branco
2026-05-05 14:50 ` Cyril Hrubis
2026-04-11 10:44 ` [LTP] memfd_create: move sys_memfd_create() to lapi/memfd.h acervesato
2026-05-05 12:24 ` Cyril Hrubis
2026-05-05 12:22 ` [LTP] [PATCH v6 1/2] " Cyril Hrubis
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260401210338.485029-2-rbranco@suse.de \
--to=rbranco@suse.de \
--cc=ltp@lists.linux.it \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.