public inbox for io-uring@vger.kernel.org
 help / color / mirror / Atom feed
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


      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