skip to Main Content

I am attempting to make a simple program to write to a file using kernel 5.4.0-150 and Ubuntu Bionic (18.04) on an x86_64 platform. No matter what I do, cqe->res always fails with EINVAL. I have no idea what parameter could possibly be wrong.

Do write SQE’s work with kernel 5.4? (This machine is running 5.4 as it was advertised to be an LTS kernel).

#include <stdio.h>
#include <liburing.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

void dump_sqe(struct io_uring_sqe *sqe);

int main() {
    // Initialize the io_uring structure and create a ring buffer and completion events
    struct io_uring ring;
    void* buf;
    int fd;
    
    printf("Using liburing %d.%dn",IO_URING_VERSION_MAJOR,IO_URING_VERSION_MINOR);
    
    int ret = io_uring_queue_init(16, &ring, 0);
    if (ret < 0) {
      printf("io_uring_queue_init: %dn",ret);
    }

    if((fd = open("./temp.txt", O_WRONLY | O_TRUNC | O_CREAT, 0644)) < 0)
       perror("open");

    // Set up the write operation
    struct io_uring_sqe *sqe = io_uring_get_sqe(&ring);

    posix_memalign(&buf,4096,4096);
    strcpy(buf,"Hello, world!n");

    io_uring_prep_write(sqe, fd, buf, strlen(buf), 0);
    dump_sqe(sqe);
    
    // Submit the write request to the kernel
    ret = io_uring_submit(&ring);
    if (ret < 0) {
      printf("io_uring_submit: %dn",ret);
    }

    // Wait for the completion of the write request
    struct io_uring_cqe *cqe;
    ret = io_uring_wait_cqe(&ring, &cqe);
    if (ret < 0) {
      printf("io_uring_wait_cqe: %dn",ret);
    }

    // Process the completed write request
    if (cqe->res < 0) {
      printf("cqe->res = %dn",cqe->res);
    } else {
      printf("Successn");
    }

    // Clean up
    io_uring_cqe_seen(&ring, cqe);
    io_uring_queue_exit(&ring);
    return 0;
}

void dump_sqe(struct io_uring_sqe *sqe)
{
  printf("sqe->opcode = 0x%02xn"
     "sqe->flags = 0x%08xn"
     "sqe->ioprio = %dn"
     "sqe->fd = %dn"
     "sqe->off = %lldn"
     "sqe->addr = 0x%016llun"
     "sqe->len = %dn"
     "sqe->rw_flags = %dn"
     "sqe->buf_index = %dn"
     "sqe->personality = %dn"
     "sqe->file_index = %dn"
     "sqe->addr3 = %lldn"
     "sqe->__pad2[0] = %lldnn",
     sqe->opcode,
     sqe->flags,
     sqe->ioprio,
     sqe->fd,
     sqe->off,
     sqe->addr,
     sqe->len,
     sqe->rw_flags,
     sqe->buf_index,
     sqe->personality,
     sqe->file_index,
     sqe->addr3,
     sqe->__pad2[0]);
}

Running the code above generates the following:

Using liburing 2.4
sqe->opcode = 0x17
sqe->flags = 0x00000000
sqe->ioprio = 0
sqe->fd = 4
sqe->off = 0
sqe->addr = 0x0094870066995200
sqe->len = 14
sqe->rw_flags = 0
sqe->buf_index = 0
sqe->personality = 0
sqe->file_index = 0
sqe->addr3 = 0
sqe->__pad2[0] = 0

cqe->res = -22

Have I done something wrong, or is there a specific kernel version where writes start to work? I used a page aligned buffer, thinking that might be the problem, but this did not make any difference.

Can anyone suggest something else to try? Unfortunately I can’t upgrade the kernel on this machine due to organizational policy restrictions.

2

Answers


  1. Chosen as BEST ANSWER

    I have found the answer to this problem. io_uring opcode IORING_OP_READ (0x16) and IORING_OP_WRITE (0x17) did not appear in the Linux kernel until version 5.6.

    To use io_uring in version 5.4, you may only use io_uring_prep_readv/io_uring_prep_writev, and the length must be an integral multiple of 512 bytes.

    Thank you everyone for your assistance.


  2. A quick look …

    You’re using STDOUT_FILENO. This is shown by: sqe->fd = 1

    From: https://man.archlinux.org/man/io_uring_setup.2.en

    It [seems to] state that the fd must either be opened with O_DIRECT and/or must be a storage device.

    So, I don’t think you can use stdout.

    For testing [at least], try opening a file or /dev device.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search