From: Nico Pache <npache@redhat.com>
To: vincentfu@gmail.com, axboe@kernel.dk, fio@vger.kernel.org
Cc: jvozar@redhat.com, jjurca@redhat.com, jhladky@redhat.com,
peterx@redhat.com, spetrovi@redhat.com, npache@redhat.com,
david@kernel.org
Subject: [PATCH v3 1/2] page_fault: add mmap-backed ioengine for anonymous faults
Date: Tue, 7 Apr 2026 19:20:02 -0600 [thread overview]
Message-ID: <20260408012004.198115-2-npache@redhat.com> (raw)
In-Reply-To: <20260408012004.198115-1-npache@redhat.com>
Introduce a new ioengine that mmaps anonymous memory and copies data
on read/write to trigger page faults. This allows us to leverage FIOs
powerful framework for MM related testing, and will ideally allow us to
quickly expand testing, by leveraging previously FS related fio scripts.
Signed-off-by: Nico Pache <npache@redhat.com>
---
Makefile | 2 +-
engines/page_fault.c | 125 ++++++++++++++++++++++++++++++++++++++++
examples/page_fault.fio | 60 +++++++++++++++++++
3 files changed, 186 insertions(+), 1 deletion(-)
create mode 100644 engines/page_fault.c
create mode 100644 examples/page_fault.fio
diff --git a/Makefile b/Makefile
index 0337e8fe..099e2f94 100644
--- a/Makefile
+++ b/Makefile
@@ -57,7 +57,7 @@ SOURCE := $(sort $(patsubst $(SRCDIR)/%,%,$(wildcard $(SRCDIR)/crc/*.c)) \
smalloc.c filehash.c profile.c debug.c engines/cpu.c \
engines/mmap.c engines/sync.c engines/null.c engines/net.c \
engines/ftruncate.c engines/fileoperations.c \
- engines/exec.c \
+ engines/exec.c engines/page_fault.c \
server.c client.c iolog.c backend.c libfio.c flow.c cconv.c \
gettime-thread.c helpers.c json.c idletime.c td_error.c \
profiles/tiobench.c profiles/act.c io_u_queue.c filelock.c \
diff --git a/engines/page_fault.c b/engines/page_fault.c
new file mode 100644
index 00000000..31e5177c
--- /dev/null
+++ b/engines/page_fault.c
@@ -0,0 +1,125 @@
+/*
+ * page_fault engine
+ *
+ * IO engine that reads/writes directly to/from anonymous memory
+ * by triggering page faults.
+ */
+#include "fio.h"
+#include "ioengines.h"
+#include <sys/mman.h>
+
+struct fio_page_fault_data {
+ void *mmap_ptr;
+ size_t mmap_sz;
+};
+
+static int fio_page_fault_init(struct thread_data *td)
+{
+ size_t total_io_size;
+ struct fio_page_fault_data *fpd;
+
+ if (td->o.nr_files > 1) {
+ log_err("fio: page_fault ioengine does not support multiple files\n");
+ return 1;
+ }
+
+ if (td->o.start_offset != 0) {
+ log_err("fio: page_fault engine does not support start_offset\n");
+ return 1;
+ }
+
+ fpd = calloc(1, sizeof(*fpd));
+ if (!fpd)
+ return 1;
+
+ total_io_size = td->o.size;
+ fpd->mmap_sz = total_io_size;
+ fpd->mmap_ptr = mmap(NULL, total_io_size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (fpd->mmap_ptr == MAP_FAILED) {
+ free(fpd);
+ return 1;
+ }
+
+ td->io_ops_data = fpd;
+ return 0;
+}
+
+static enum fio_q_status fio_page_fault_queue(struct thread_data *td,
+ struct io_u *io_u)
+{
+ void *mmap_head;
+ struct fio_page_fault_data *fpd = td->io_ops_data;
+ if (!fpd) {
+ io_u->error = EINVAL;
+ return FIO_Q_COMPLETED;
+ }
+
+ if (io_u->offset + io_u->buflen > fpd->mmap_sz) {
+ io_u->error = EINVAL;
+ return FIO_Q_COMPLETED;
+ }
+
+ mmap_head = fpd->mmap_ptr + io_u->offset;
+ switch (io_u->ddir) {
+ case DDIR_READ:
+ memcpy(io_u->xfer_buf, mmap_head, io_u->buflen);
+ break;
+ case DDIR_WRITE:
+ memcpy(mmap_head, io_u->xfer_buf, io_u->buflen);
+ break;
+ case DDIR_SYNC:
+ case DDIR_DATASYNC:
+ case DDIR_SYNC_FILE_RANGE:
+ case DDIR_SYNCFS:
+ break;
+ default:
+ io_u->error = EINVAL;
+ break;
+ }
+
+ return FIO_Q_COMPLETED;
+}
+
+static int fio_page_fault_open_file(struct thread_data *td, struct fio_file *f)
+{
+ return 0;
+}
+
+static int fio_page_fault_close_file(struct thread_data *td, struct fio_file *f)
+{
+ return 0;
+}
+
+static void fio_page_fault_cleanup(struct thread_data *td)
+{
+ struct fio_page_fault_data *fpd = td->io_ops_data;
+
+ if (!fpd)
+ return;
+ if (fpd->mmap_ptr && fpd->mmap_sz)
+ munmap(fpd->mmap_ptr, fpd->mmap_sz);
+ free(fpd);
+}
+
+static struct ioengine_ops ioengine = {
+ .name = "page_fault",
+ .version = FIO_IOOPS_VERSION,
+ .init = fio_page_fault_init,
+ .cleanup = fio_page_fault_cleanup,
+ .queue = fio_page_fault_queue,
+ .open_file = fio_page_fault_open_file,
+ .close_file = fio_page_fault_close_file,
+ .get_file_size = generic_get_file_size,
+ .flags = FIO_SYNCIO | FIO_NOEXTEND | FIO_DISKLESSIO,
+};
+
+static void fio_init fio_page_fault_register(void)
+{
+ register_ioengine(&ioengine);
+}
+
+static void fio_exit fio_page_fault_unregister(void)
+{
+ unregister_ioengine(&ioengine);
+}
\ No newline at end of file
diff --git a/examples/page_fault.fio b/examples/page_fault.fio
new file mode 100644
index 00000000..4a49fb7d
--- /dev/null
+++ b/examples/page_fault.fio
@@ -0,0 +1,60 @@
+[global]
+stonewall
+ioengine=page_fault
+size=5*1024*1024*$mb_memory/8 # 5/8 of the memory
+bs=$pagesize
+
+[page_fault_write]
+rw=write
+
+[page_fault_mixed]
+rw=randrw
+rwmixread=50
+
+[page_fault_process_storm]
+size=8*1024*$pagesize
+rw=randrw
+rwmixread=50
+numjobs=$ncpus
+
+[page_fault_mthp]
+bsrange=16k-1M
+blockalign=2M
+rw=write
+
+[page_fault_seq_read]
+rw=read
+
+[page_fault_rand_read]
+rw=randread
+
+[page_fault_rand_write]
+rw=randwrite
+
+[page_fault_warm]
+rw=randrw
+rwmixread=50
+loops=3
+
+[page_fault_read_heavy]
+rw=randrw
+rwmixread=90
+
+[page_fault_write_heavy]
+rw=randrw
+rwmixread=10
+
+[page_fault_large_block]
+bs=2M
+blockalign=2M
+rw=write
+
+[page_fault_cache_hot]
+size=64*$pagesize
+rw=randrw
+rwmixread=50
+loops=100
+
+[page_fault_pressure]
+size=7*1024*1024*$mb_memory/8 # 7/8 of the memory
+rw=write
--
2.53.0
next prev parent reply other threads:[~2026-04-08 1:20 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-08 1:20 [PATCH v3 0/2] page_fault: add mmap-backed ioengine for anonymous faults Nico Pache
2026-04-08 1:20 ` Nico Pache [this message]
2026-04-08 1:20 ` [PATCH v3 2/2] Documentation: update the documentation to include the page_fault engine Nico Pache
2026-04-08 2:01 ` [PATCH v3 0/2] page_fault: add mmap-backed ioengine for anonymous faults Jens Axboe
2026-04-08 13:21 ` Nico Pache
2026-04-08 4:12 ` fiotestbot
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=20260408012004.198115-2-npache@redhat.com \
--to=npache@redhat.com \
--cc=axboe@kernel.dk \
--cc=david@kernel.org \
--cc=fio@vger.kernel.org \
--cc=jhladky@redhat.com \
--cc=jjurca@redhat.com \
--cc=jvozar@redhat.com \
--cc=peterx@redhat.com \
--cc=spetrovi@redhat.com \
--cc=vincentfu@gmail.com \
/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