Commit d98c0893b0

Igor Anić <igor.anic@gmail.com>
2025-02-28 21:36:02
io_uring: probe capabilities function
ring.get_probe returns io_uring_probe which can be use to probe capabilities of the current running kernel. Ref: https://unixism.net/loti/ref-liburing/supported_caps.html https://github.com/axboe/liburing/blob/e1003e496e66f9b0ae06674869795edf772d5500/src/setup.c#L454
1 parent 85e2074
Changed files (2)
lib
lib/std/os/linux/IoUring.zig
@@ -1272,6 +1272,16 @@ pub fn unregister_buffers(self: *IoUring) !void {
     }
 }
 
+/// Returns a io_uring_probe which is used to probe the capabilities of the
+/// io_uring subsystem of the running kernel. The io_uring_probe contains the
+/// list of supported operations.
+pub fn get_probe(self: *IoUring) !linux.io_uring_probe {
+    var probe = mem.zeroInit(linux.io_uring_probe, .{});
+    const res = linux.io_uring_register(self.fd, .REGISTER_PROBE, &probe, probe.ops.len);
+    try handle_register_buf_ring_result(res);
+    return probe;
+}
+
 fn handle_registration_result(res: usize) !void {
     switch (linux.E.init(res)) {
         .SUCCESS => {},
@@ -4355,9 +4365,7 @@ test "copy_cqes with wrapping sq.cqes buffer" {
     }
 }
 
-test "bind" {
-    try skipKernelLessThan(.{ .major = 6, .minor = 11, .patch = 0 });
-
+test "bind/listen/connect" {
     var ring = IoUring.init(4, 0) catch |err| switch (err) {
         error.SystemOutdated => return error.SkipZigTest,
         error.PermissionDenied => return error.SkipZigTest,
@@ -4365,6 +4373,10 @@ test "bind" {
     };
     defer ring.deinit();
 
+    const probe = ring.get_probe() catch return error.SkipZigTest;
+    // LISTEN is higher required operation
+    if (!probe.is_supported(.LISTEN)) return error.SkipZigTest;
+
     var addr = net.Address.initIp4([4]u8{ 127, 0, 0, 1 }, 0);
     const proto: u32 = if (addr.any.family == linux.AF.UNIX) 0 else linux.IPPROTO.TCP;
 
lib/std/os/linux.zig
@@ -6138,26 +6138,28 @@ pub const IO_URING_OP_SUPPORTED = 1 << 0;
 
 pub const io_uring_probe_op = extern struct {
     op: IORING_OP,
-
     resv: u8,
-
-    /// IO_URING_OP_* flags
-    flags: u16,
-
+    flags: u16, // IO_URING_OP_* flags
     resv2: u32,
+
+    pub fn is_supported(self: @This()) bool {
+        return self.flags & IO_URING_OP_SUPPORTED != 0;
+    }
 };
 
 pub const io_uring_probe = extern struct {
-    /// last opcode supported
-    last_op: IORING_OP,
-
-    /// Number of io_uring_probe_op following
-    ops_len: u8,
-
+    last_op: IORING_OP, // last opcode supported
+    ops_len: u8, // length of ops[] array below
     resv: u16,
     resv2: [3]u32,
+    ops: [256]io_uring_probe_op,
 
-    // Followed by up to `ops_len` io_uring_probe_op structures
+    pub fn is_supported(self: @This(), op: IORING_OP) bool {
+        const i = @intFromEnum(op);
+        if (i > @intFromEnum(self.last_op) or i >= self.ops_len)
+            return false;
+        return self.ops[i].is_supported();
+    }
 };
 
 pub const io_uring_restriction = extern struct {