From: Gabriel Krisman Bertazi <krisman@suse.de>
To: axboe@kernel.dk
Cc: io-uring@vger.kernel.org, Gabriel Krisman Bertazi <krisman@suse.de>
Subject: [PATCH liburing 2/2] mmap.t: Introduce IORING_OP_MMAP test case
Date: Thu, 29 Jan 2026 17:12:36 -0500 [thread overview]
Message-ID: <20260129221236.898135-3-krisman@suse.de> (raw)
In-Reply-To: <20260129221236.898135-1-krisman@suse.de>
Signed-off-by: Gabriel Krisman Bertazi <krisman@suse.de>
---
test/Makefile | 1 +
test/mmap.c | 372 ++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 373 insertions(+)
create mode 100644 test/mmap.c
diff --git a/test/Makefile b/test/Makefile
index 64862f34..8fe56ae4 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -141,6 +141,7 @@ test_srcs := \
link_drain.c \
link-timeout.c \
linked-defer-close.c \
+ mmap.c \
madvise.c \
min-timeout.c \
min-timeout-wait.c \
diff --git a/test/mmap.c b/test/mmap.c
new file mode 100644
index 00000000..b0ec326b
--- /dev/null
+++ b/test/mmap.c
@@ -0,0 +1,372 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Description: test mmap operation
+ *
+ */
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include "liburing.h"
+#include "helpers.h"
+
+static bool check_hugetlb()
+{
+ /* Cheap (to implement) check whether can mmap a 2MB hugetlb
+ * page.
+ */
+ void *x = mmap(NULL, 2*1024*1024,
+ PROT_READ|PROT_WRITE,
+ MAP_PRIVATE|MAP_ANONYMOUS|MAP_HUGETLB|MAP_HUGE_2MB,
+ -1, 0);
+ if (x == (void*)-1) {
+ munmap(x, 2*1024*1024);
+ return false;
+ }
+ munmap(x, 2*1024*1024);
+ return true;
+}
+
+static unsigned char buf[BUFSIZ];
+#define MAGIC_CHAR 0xf3
+
+const char *func;
+int pos;
+#define CATCH_FAULT(x) (func = __func__, pos=__LINE__, x)
+
+static void do_sigsev(int sig, siginfo_t *si, void *unused)
+{
+ printf("SIGSEGV on 0x%lx (%s:%d). OP_MMAP likely broken\n",
+ (long) si->si_addr, func, pos);
+ exit(T_EXIT_FAIL);
+}
+
+int create_memfd(int size, int flags)
+{
+ int fd;
+ int remain = size;
+ int ret;
+ char path[10];
+ static int i = 0;
+
+ /* just a unique name for each call */
+ snprintf(path, 10, "t%d", i++);
+
+ if (size % sizeof(int)) {
+ printf("memfd bad size %d\n", size);
+ return -1;
+ }
+ fd = memfd_create(path, flags);
+ if (!fd) {
+ printf("memfd %d\n", fd);
+ return -1;
+ }
+ if (ftruncate(fd, size)) {
+ fprintf(stderr, "ftruncate");
+ return -1;
+ }
+ while (remain > 0) {
+ ret = write(fd, buf, MIN(size,BUFSIZ));
+ if (ret < 0) {
+ fprintf(stderr, "write");
+ return -1;
+ }
+ remain -= ret;
+ }
+ return fd;
+}
+
+int uring_mmap(struct io_uring *ring, int sqe_flags,
+ int fd, struct io_uring_mmap_desc *descs,
+ int nr_descs, int flags)
+{
+ struct io_uring_sqe *sqe = io_uring_get_sqe(ring);
+ struct io_uring_cqe *cqe;
+ int ret;
+
+ io_uring_prep_mmap(sqe, fd, descs, nr_descs, flags);
+ sqe->flags |= sqe_flags;
+ io_uring_submit(ring);
+ io_uring_wait_cqe(ring, &cqe);
+
+ ret = cqe->res;
+ io_uring_cqe_seen(ring, cqe);
+ return ret;
+}
+
+int test_map_file(struct io_uring *ring, unsigned int ring_flags)
+{
+ int fd, ret;
+ struct io_uring_mmap_desc desc = {
+ .addr = NULL,
+ .len = BUFSIZ,
+ .pgoff = 0,
+ .prot = (PROT_READ|PROT_WRITE),
+ .flags = MAP_PRIVATE
+ };
+
+ fd = create_memfd(BUFSIZ, 0);
+ if (fd < 0) {
+ return T_EXIT_SKIP;
+ }
+
+ ret = uring_mmap(ring, 0, fd, &desc, 1, 0);
+ if (ret != 1) {
+ fprintf(stderr, "mmap at %s:%d failed. got %d",
+ func, __LINE__, ret);
+ return T_EXIT_FAIL;
+ }
+
+ if ((long long) desc.addr <= 0) {
+ fprintf(stderr, "bad desc.addr fail %lld\n",
+ (long long)desc.addr);
+ return T_EXIT_FAIL;
+ }
+
+ if (CATCH_FAULT(memcmp(desc.addr, buf, BUFSIZ))) {
+ fprintf(stderr, "check_buf fail\n");
+ return T_EXIT_FAIL;
+ }
+ if (munmap(desc.addr, BUFSIZ)) {
+ fprintf(stderr, "unmap fail\n");
+ return T_EXIT_FAIL;
+ }
+ /* same, with a fixed file. */
+ desc.addr = NULL;
+ if (io_uring_register_files(ring, &fd, 1)) {
+ fprintf(stderr, "register fail\n");
+ return T_EXIT_FAIL;
+ }
+
+ ret = uring_mmap(ring, IOSQE_FIXED_FILE, 0, &desc, 1, 0);
+ if (ret != 1) {
+ fprintf(stderr, "mmap at %s:%d failed. got %d",
+ func, __LINE__, ret);
+ return T_EXIT_FAIL;
+ }
+
+ if ((long long)(desc.addr) < 0) {
+ fprintf(stderr, "bad desc.addr fail %lld\n",
+ (long long)desc.addr);
+ return T_EXIT_FAIL;
+ }
+
+ if (CATCH_FAULT(memcmp(desc.addr, buf, BUFSIZ))) {
+ fprintf(stderr, "check_buf fail\n");
+ return T_EXIT_FAIL;
+ }
+ return 0;
+}
+
+int test_map_anon(struct io_uring *ring, unsigned int ring_flags)
+{
+ struct io_uring_mmap_desc descs[4];
+ void *addrs[4];
+ int ret;
+
+ for (int i = 0 ; i < 4; i++) {
+ descs[i].addr = NULL;
+ descs[i].len = 1024;
+ descs[i].pgoff = 0;
+ descs[i].prot = (PROT_READ|PROT_WRITE);
+ descs[i].flags = MAP_PRIVATE;
+ }
+
+ ret = uring_mmap(ring, 0, -1, descs, 4, MAP_ANONYMOUS);
+ if (ret != 4) {
+ fprintf(stderr, "mmap at %s:%d failed. got %d\n",
+ __func__, __LINE__, ret);
+ return T_EXIT_FAIL;
+ }
+
+ for (int i = 0 ; i < 4; i++) {
+
+ if ((long long)(descs[i].addr) < 0) {
+ fprintf(stderr, "bad desc.addr fail %lld\n",
+ (long long)descs[i].addr);
+ return T_EXIT_FAIL;
+ }
+
+ /* Ensure it is mapped. SIGSEV on error */
+ CATCH_FAULT(*((char*)descs[i].addr) = MAGIC_CHAR);
+ munmap((char*)descs[i].addr, 1024);
+ }
+
+ /* reuse the addr from the first test to verify MAP_FIXED. We
+ * know the region is free since we just unmapped it.
+ */
+ for (int i = 0 ; i < 4; i++) {
+ addrs[i] = descs[i].addr;
+ descs[i].flags |= MAP_FIXED;
+ }
+
+ ret = uring_mmap(ring, 0, -1, descs, 4, MAP_ANONYMOUS);
+ if (ret != 4) {
+ fprintf(stderr, "mmap at %s:%d failed. got %d\n",
+ __func__, __LINE__, ret);
+ return T_EXIT_FAIL;
+ }
+
+ for (int i = 0 ; i < 4; i++) {
+ /* Ensure it is mapped. SIGSEV on error */
+ CATCH_FAULT(*((char*)descs[i].addr) = MAGIC_CHAR);
+
+ if (descs[i].addr != addrs[i]) {
+ fprintf(stderr, "MAP_FIXED failed");
+ return T_EXIT_FAIL;
+ }
+ }
+ return 0;
+}
+
+int test_map_anon_hugetlb(struct io_uring *ring, unsigned int ring_flags)
+{
+ struct io_uring_mmap_desc desc = {
+ .addr = NULL,
+ .len = 1*1024*1024,
+ .pgoff = 0,
+ .prot = (PROT_READ|PROT_WRITE),
+ .flags = MAP_PRIVATE|MAP_HUGE_2MB,
+ };
+ int ret;
+
+ ret = uring_mmap(ring, 0, -1, &desc, 1,
+ MAP_ANONYMOUS|MAP_HUGETLB);
+ if (ret != 1) {
+ fprintf(stderr, "mmap at %s:%d failed. got %d\n",
+ __func__, __LINE__, ret);
+ return T_EXIT_FAIL;
+ }
+
+ if ((long long)(desc.addr) < 0) {
+ fprintf(stderr, "bad desc.addr fail %lld\n",
+ (long long)desc.addr);
+ return T_EXIT_FAIL;
+ }
+
+ /* Ensure it is mapped. SIGSEV on error */
+ CATCH_FAULT(*((char*)desc.addr) = MAGIC_CHAR);
+ return 0;
+}
+
+
+int test_weird(struct io_uring *ring, unsigned int ring_flags)
+{
+ struct io_uring_mmap_desc desc;
+ int ret, fd = create_memfd(BUFSIZ, 0);
+ if (fd < 0) {
+ return T_EXIT_SKIP;
+ }
+
+ desc.addr = NULL;
+ desc.len = 1024;
+ desc.pgoff = 0;
+ desc.prot = (PROT_READ|PROT_WRITE);
+ desc.flags = MAP_PRIVATE;
+
+ /* This is wrong because attempt MAP_ANONYMOUS with fd. It
+ * fails early, because bad flag is on SQE.
+ */
+ ret = uring_mmap(ring, 0, fd, &desc, 1, MAP_ANONYMOUS);
+ if (ret != -EINVAL) {
+ fprintf(stderr, "mmap at %s:%d failed. got %d",
+ __func__, __LINE__, ret);
+ return T_EXIT_FAIL;
+ }
+
+ /* This is wrong because attempt MAP_ANONYMOUS with fd. It
+ * fails late, because bad flag is on desc.
+ */
+ desc.flags = MAP_PRIVATE|MAP_ANONYMOUS;
+ ret = uring_mmap(ring, 0, fd, &desc, 1, 0);
+ if (ret != 1) {
+ fprintf(stderr, "mmap at %s:%d failed. got %d",
+ __func__, __LINE__, ret);
+ return T_EXIT_FAIL;
+ }
+
+ if ((long long) desc.addr != -EINVAL) {
+ printf("mmap ANONYMOUS with fd should have failed %lx\n",
+ (uintptr_t)desc.addr);
+ }
+
+ /* This is wrong because we can't have MAP_HUGETLB in the
+ * descriptor. It fails late, because bad flag is on desc.
+ */
+ desc.flags = MAP_PRIVATE|MAP_HUGETLB;
+ ret = uring_mmap(ring, 0, fd, &desc, 1, 0);
+ if (ret != 1) {
+ fprintf(stderr, "mmap at %s:%d failed. got %d",
+ __func__, __LINE__, ret);
+ return T_EXIT_FAIL;
+ }
+
+ if ((long long) desc.addr != -EINVAL) {
+ printf("mmap ANONYMOUS with fd should have failed %lx\n",
+ (uintptr_t)desc.addr);
+ }
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ struct io_uring_probe *probe;
+ struct io_uring ring;
+ int ret = 0;
+ struct sigaction sa;
+ bool has_hugetlb = check_hugetlb();
+
+ sa.sa_flags = SA_SIGINFO;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_sigaction = do_sigsev;
+ if (sigaction(SIGSEGV, &sa, NULL) == -1) {
+ fprintf(stderr,
+ "failed to register signal handle. continuing.");
+ }
+ memset(buf, MAGIC_CHAR, BUFSIZ);
+
+ probe = io_uring_get_probe();
+ if (!probe)
+ return T_EXIT_SKIP;
+ if (!io_uring_opcode_supported(probe, IORING_OP_MMAP))
+ return T_EXIT_SKIP;
+
+ ret = t_create_ring(10, &ring, IORING_SETUP_SUBMIT_ALL);
+ if (ret < 0) {
+ fprintf(stderr, "queue_init: %s\n",
+ strerror(-ret));
+ return T_SETUP_SKIP;
+ }
+
+ ret |= test_map_anon(&ring, 0);
+ if (ret) {
+ fprintf(stderr, "test_map_anon failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ ret |= test_map_file(&ring, 0);
+ if (ret) {
+ fprintf(stderr, "test_map_file failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ if (has_hugetlb) {
+ ret |= test_map_anon_hugetlb(&ring, 0);
+ if (ret) {
+ fprintf(stderr, "test_map_file failed\n");
+ return T_EXIT_FAIL;
+ }
+ }
+
+ ret |= test_weird(&ring, 0);
+ if (ret) {
+ fprintf(stderr, "test_map_weird failed\n");
+ }
+
+ return ret;
+}
--
2.52.0
prev parent reply other threads:[~2026-01-29 22:12 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-01-29 22:12 [PATCH liburing 0/2] liburing mmap support Gabriel Krisman Bertazi
2026-01-29 22:12 ` [PATCH liburing 1/2] liburing: Add support to IORING_OP_MMAP Gabriel Krisman Bertazi
2026-01-29 22:12 ` Gabriel Krisman Bertazi [this message]
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=20260129221236.898135-3-krisman@suse.de \
--to=krisman@suse.de \
--cc=axboe@kernel.dk \
--cc=io-uring@vger.kernel.org \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox