diff mbox series

io_uring-writev: open output file through io_uring

Message ID 20260831080223.124050-1-frezidok1@gmail.com
State New
Headers show
Series io_uring-writev: open output file through io_uring | expand

Commit Message

Dmitry Sakhonchik Aug. 31, 2026, 8:02 a.m. UTC
From: Dmitry Sakhonchik <frezidok1@gmail.com>

The existing test creates the output file with open(), which ends up
using openat() and is therefore intercepted by pseudo before the actual
io_uring write operation happens.

Use IORING_OP_OPENAT to create the output file through io_uring as well.
This makes the test successfully bypass pseudo

io-uring-writev.bb: wrynose doesn't support "S = ${WORKDIR}" anymore, fix it

[YOCTO #15244]

Signed-off-by: Dmitry Sakhonchik <frezidok1@gmail.com>
---
 .../recipes-test/io-uring/io-uring-writev.bb  |  2 +-
 .../io-uring-writev/io-uring-writev.c         | 98 ++++++++++++++++---
 2 files changed, 88 insertions(+), 12 deletions(-)
diff mbox series

Patch

diff --git a/meta-selftest/recipes-test/io-uring/io-uring-writev.bb b/meta-selftest/recipes-test/io-uring/io-uring-writev.bb
index 8b2ca6005b..f5de317429 100644
--- a/meta-selftest/recipes-test/io-uring/io-uring-writev.bb
+++ b/meta-selftest/recipes-test/io-uring/io-uring-writev.bb
@@ -5,7 +5,7 @@  LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda
 
 SRC_URI = "file://io-uring-writev.c"
 
-S = "${WORKDIR}"
+S = "${UNPACKDIR}"
 
 do_compile() {
 	${BUILD_CC} io-uring-writev.c -o io-uring-writev
diff --git a/meta-selftest/recipes-test/io-uring/io-uring-writev/io-uring-writev.c b/meta-selftest/recipes-test/io-uring/io-uring-writev/io-uring-writev.c
index a5e4253b7a..54f49fa481 100644
--- a/meta-selftest/recipes-test/io-uring/io-uring-writev/io-uring-writev.c
+++ b/meta-selftest/recipes-test/io-uring/io-uring-writev/io-uring-writev.c
@@ -20,10 +20,13 @@ 
 /* If your compilation fails because the header file below is missing,
  * your kernel is probably too old to support io_uring.
  * */
+#include <errno.h>
+#include <stdbool.h>
 #include <linux/io_uring.h>
 
 #define QUEUE_DEPTH 1
 #define BLOCK_SZ    1024
+#define OPEN_TAG    1
 
 /* This is x86 specific */
 #define read_barrier()  __asm__ __volatile__("":::"memory")
@@ -101,6 +104,79 @@  off_t get_file_size(int fd) {
     return -1;
 }
 
+int open_with_uring(const char* path, struct submitter *s) {
+    struct app_io_sq_ring *sring = &s->sq_ring;
+    struct app_io_cq_ring *cring = &s->cq_ring;
+
+    // Get position of the next SQE
+    unsigned tail = *sring->tail;
+    read_barrier();
+    unsigned index = tail & *sring->ring_mask;
+    unsigned next_tail = tail + 1;
+    struct io_uring_sqe *sqe = &s->sqes[index];
+
+    // Prepare SQE
+    memset(sqe, 0, sizeof(*sqe));
+    sqe->opcode = IORING_OP_OPENAT;
+    sqe->fd = AT_FDCWD;
+    sqe->addr = (unsigned long)path;
+    sqe->open_flags = O_WRONLY | O_CREAT;
+    sqe->len = 0666;
+    sqe->user_data = OPEN_TAG;
+
+    // Add prepared sqe to the submission queue
+    sring->array[index] = index;
+
+    // Update the tail so the kernel can see it
+    tail = next_tail;
+    if(*sring->tail != tail) {
+        write_barrier();
+        *sring->tail = tail;
+    }
+
+    //Tell the kernel to process events in SQ
+    int ret =  io_uring_enter(s->ring_fd, 1,1,
+            IORING_ENTER_GETEVENTS);
+    if(ret < 0) {
+        perror("io_uring_enter");
+        return -1;
+    }
+
+    //Now we need to read the output from kernel from the CQ
+    while (true) {
+        unsigned head = *cring->head;
+        tail = *cring->tail;
+        read_barrier();
+
+        if (head == tail) {
+            /*  It means the buffer is empty.
+             *  If we are here, then something went wrong and
+             *  kernel didn't return CQE with user_data == OPEN_TAG for some reason
+             */
+            fprintf(stderr, "open_with_uring error: kernel didn't return fd");
+            return -1;
+        }
+
+        index = head & *cring->ring_mask;
+        struct io_uring_cqe *cqe = &cring->cqes[index];
+
+        unsigned long long tag = cqe->user_data;
+        int res = cqe->res;
+
+        write_barrier();
+        *cring->head = head + 1;
+
+        if (tag == OPEN_TAG) {
+            if (res < 0) {
+                errno = -res;
+                perror("IORING_OP_OPENAT");
+                return -1;
+            }
+            return res;
+        }
+    }
+}
+
 /*
  * io_uring requires a lot of setup which looks pretty hairy, but isn't all
  * that difficult to understand. Because of all this boilerplate code,
@@ -155,7 +231,7 @@  int app_setup_uring(struct submitter *s) {
     /* Map in the submission and completion queue ring buffers.
      * Older kernels only map in the submission queue, though.
      * */
-    sq_ptr = mmap(0, sring_sz, PROT_READ | PROT_WRITE, 
+    sq_ptr = mmap(0, sring_sz, PROT_READ | PROT_WRITE,
             MAP_SHARED | MAP_POPULATE,
             s->ring_fd, IORING_OFF_SQ_RING);
     if (sq_ptr == MAP_FAILED) {
@@ -167,7 +243,7 @@  int app_setup_uring(struct submitter *s) {
         cq_ptr = sq_ptr;
     } else {
         /* Map in the completion queue ring buffer in older kernels separately */
-        cq_ptr = mmap(0, cring_sz, PROT_READ | PROT_WRITE, 
+        cq_ptr = mmap(0, cring_sz, PROT_READ | PROT_WRITE,
                 MAP_SHARED | MAP_POPULATE,
                 s->ring_fd, IORING_OFF_CQ_RING);
         if (cq_ptr == MAP_FAILED) {
@@ -266,8 +342,8 @@  void read_from_cq(struct submitter *s) {
 int submit_to_sq(char *file_path, struct submitter *s) {
     struct file_info *fi;
 
-    int file_fd = open(file_path, O_WRONLY|O_CREAT, 0666);
-    if (file_fd < 0 ) {
+    int file_fd = open_with_uring(file_path, s);
+    if (file_fd < 0) {
         perror("open");
         return 1;
     }
@@ -317,7 +393,7 @@  int submit_to_sq(char *file_path, struct submitter *s) {
     */
     fi->iovecs[current_block].iov_len = bytes_remaining;
     fi->iovecs[current_block].iov_base = bark;
-    
+
 
     /* Add our submission queue entry to the tail of the SQE ring buffer */
     next_tail = tail = *sring->tail;
@@ -336,7 +412,7 @@  int submit_to_sq(char *file_path, struct submitter *s) {
     tail = next_tail;
 
     /* Update the tail so the kernel can see it. */
-    if(*sring->tail != tail) {
+    if (*sring->tail != tail) {
         *sring->tail = tail;
         write_barrier();
     }
@@ -347,9 +423,9 @@  int submit_to_sq(char *file_path, struct submitter *s) {
      * io_uring_enter() call to wait until min_complete events (the 3rd param)
      * complete.
      * */
-    int ret =  io_uring_enter(s->ring_fd, 1,1,
-            IORING_ENTER_GETEVENTS);
-    if(ret < 0) {
+    int ret = io_uring_enter(s->ring_fd, 1, 1,
+                             IORING_ENTER_GETEVENTS);
+    if (ret < 0) {
         perror("io_uring_enter");
         return 1;
     }
@@ -372,13 +448,13 @@  int main(int argc, char *argv[]) {
     }
     memset(s, 0, sizeof(*s));
 
-    if(app_setup_uring(s)) {
+    if (app_setup_uring(s)) {
         fprintf(stderr, "Unable to setup uring!\n");
         return 1;
     }
 
     for (int i = 1; i < argc; i++) {
-        if(submit_to_sq(argv[i], s)) {
+        if (submit_to_sq(argv[i], s)) {
             fprintf(stderr, "Error writting file\n");
             return 1;
         }