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
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.
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.