summaryrefslogtreecommitdiff
path: root/integrationtests/cmd/ioworkload/scenario_iouring.go
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-02-21 22:03:57 +0200
committerPaul Buetow <paul@buetow.org>2026-02-21 22:03:57 +0200
commit3ec3c117bb280a377fea1a3eef84a70e2a3d4150 (patch)
treeb017e330eeaa1cafe95d2a730675b46342afd92a /integrationtests/cmd/ioworkload/scenario_iouring.go
parent311b827599251d8d68526293815e8d4dcba632c8 (diff)
Split ioworkload scenarios.go into per-category files
Split the 2494-line scenarios.go monolith into 14 focused files by syscall category: open, readwrite, close, dup, fcntl, rename, link, unlink, dir, stat, sync, truncate, iouring, plus the slimmed-down scenarios.go containing only the registry map, makeTempDir, and crash. Extracted rawLink, rawSymlink, rawReadlink helpers in scenario_link.go to reduce code duplication in linkBasic. Task: #349 (Go best practices: split oversized scenarios file) Amp-Thread-ID: https://ampcode.com/threads/T-019c81c6-e1b6-747a-9144-40f6be997e60 Co-authored-by: Amp <amp@ampcode.com>
Diffstat (limited to 'integrationtests/cmd/ioworkload/scenario_iouring.go')
-rw-r--r--integrationtests/cmd/ioworkload/scenario_iouring.go129
1 files changed, 129 insertions, 0 deletions
diff --git a/integrationtests/cmd/ioworkload/scenario_iouring.go b/integrationtests/cmd/ioworkload/scenario_iouring.go
new file mode 100644
index 0000000..b1aac4e
--- /dev/null
+++ b/integrationtests/cmd/ioworkload/scenario_iouring.go
@@ -0,0 +1,129 @@
+package main
+
+import (
+ "fmt"
+ "runtime"
+ "syscall"
+ "unsafe"
+)
+
+const (
+ sysIoUringSetup = 425
+ sysIoUringEnter = 426
+ sysIoUringRegister = 427
+
+ // io_uring_params struct size: 10 x uint32 + io_sqring_offsets(40) + io_cqring_offsets(40) = 120 bytes.
+ ioUringParamsSize = 120
+
+ ioringRegisterProbe = 8 // IORING_REGISTER_PROBE
+)
+
+// iouringSetup creates an io_uring instance via io_uring_setup(2) and closes the fd.
+func iouringSetup() error {
+ fd, err := ioUringSetupRing(1)
+ if err != nil {
+ return err
+ }
+ return syscall.Close(fd)
+}
+
+// iouringEnter creates an io_uring instance, then calls io_uring_enter(2)
+// with zero submissions/completions to exercise the enter tracepoint.
+func iouringEnter() error {
+ fd, err := ioUringSetupRing(1)
+ if err != nil {
+ return err
+ }
+ defer syscall.Close(fd)
+
+ _, _, errno := syscall.Syscall6(
+ sysIoUringEnter,
+ uintptr(fd),
+ 0, // to_submit
+ 0, // min_complete
+ 0, // flags
+ 0, // sig
+ 0, // sz
+ )
+ if errno != 0 {
+ return fmt.Errorf("io_uring_enter: %w", errno)
+ }
+ return nil
+}
+
+// iouringRegister creates an io_uring instance, then calls io_uring_register(2)
+// with IORING_REGISTER_PROBE to exercise the register tracepoint.
+func iouringRegister() error {
+ fd, err := ioUringSetupRing(1)
+ if err != nil {
+ return err
+ }
+ defer syscall.Close(fd)
+
+ // io_uring_probe header is 16 bytes; we don't need probe_op entries.
+ var probeBuf [16]byte
+ _, _, errno := syscall.Syscall6(
+ sysIoUringRegister,
+ uintptr(fd),
+ ioringRegisterProbe,
+ uintptr(unsafe.Pointer(&probeBuf[0])),
+ 0, // nr_args (0 ops requested)
+ 0, 0,
+ )
+ runtime.KeepAlive(probeBuf)
+ if errno != 0 {
+ return fmt.Errorf("io_uring_register: %w", errno)
+ }
+ return nil
+}
+
+// iouringEnterEbadf calls io_uring_enter on an invalid fd.
+// The syscall fails with EBADF, but ior captures the enter_io_uring_enter tracepoint.
+func iouringEnterEbadf() error {
+ _, _, errno := syscall.Syscall6(
+ sysIoUringEnter,
+ 99999, // invalid fd
+ 0, // to_submit
+ 0, // min_complete
+ 0, // flags
+ 0, // sig
+ 0, // sz
+ )
+ if errno == 0 {
+ return fmt.Errorf("expected EBADF, but io_uring_enter succeeded")
+ }
+ return nil
+}
+
+// iouringRegisterEbadf calls io_uring_register on an invalid fd.
+// The syscall fails with EBADF, but ior captures the enter_io_uring_register tracepoint.
+func iouringRegisterEbadf() error {
+ _, _, errno := syscall.Syscall6(
+ sysIoUringRegister,
+ 99999, // invalid fd
+ ioringRegisterProbe,
+ 0, // arg (NULL)
+ 0, // nr_args
+ 0, 0,
+ )
+ if errno == 0 {
+ return fmt.Errorf("expected EBADF, but io_uring_register succeeded")
+ }
+ return nil
+}
+
+// ioUringSetupRing calls io_uring_setup(2) and returns the ring fd.
+func ioUringSetupRing(entries uint32) (int, error) {
+ var params [ioUringParamsSize]byte
+ fd, _, errno := syscall.Syscall(
+ sysIoUringSetup,
+ uintptr(entries),
+ uintptr(unsafe.Pointer(&params[0])),
+ 0,
+ )
+ runtime.KeepAlive(params)
+ if errno != 0 {
+ return 0, fmt.Errorf("io_uring_setup: %w", errno)
+ }
+ return int(fd), nil
+}