Kernel 5.4下使用io_uring写入文件失败,始终返回EINVAL
问题:io_uring写入文件返回EINVAL错误(Kernel 5.4.0-150)
环境信息
- 平台:x86_64
- 系统:Ubuntu Bionic(18.04)
- 内核版本:5.4.0-150(LTS)
- liburing版本:2.4
问题描述
编写了一个简单的io_uring文件写入程序,但执行后cqe->res始终返回-22(EINVAL)。尝试使用页对齐缓冲区后问题依旧,且因组织政策无法升级内核,想确认write SQE在Kernel 5.4中是否可用,以及可能的解决方向。
测试代码
#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.%d\n",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: %d\n",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: %d\n",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: %d\n",ret); } // Process the completed write request if (cqe->res < 0) { printf("cqe->res = %d\n",cqe->res); } else { printf("Success\n"); } // 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%02x\n" "sqe->flags = 0x%08x\n" "sqe->ioprio = %d\n" "sqe->fd = %d\n" "sqe->off = %lld\n" "sqe->addr = 0x%016llu\n" "sqe->len = %d\n" "sqe->rw_flags = %d\n" "sqe->buf_index = %d\n" "sqe->personality = %d\n" "sqe->file_index = %d\n" "sqe->addr3 = %lld\n" "sqe->__pad2[0] = %lld\n\n", 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]); }
运行输出
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
解答
核心原因
Kernel 5.4.0-150完全支持基本的io_uring write操作,问题出在liburing版本与内核版本不兼容:
- liburing 2.4是为较新内核(5.10+)设计的,默认会使用Kernel 5.4不支持的新opcode(你输出中的
0x17对应IORING_OP_WRITE_FIXED,该操作需要注册固定缓冲区,而你未做相关配置),导致内核返回EINVAL错误。
解决办法
方法1:降级liburing到兼容版本
将liburing降级到1.x系列(如1.10)或0.x系列,这些版本默认使用Kernel 5.4支持的旧版opcode和接口,无需修改代码即可正常工作。
方法2:手动构造兼容的SQE(无需降级liburing)
如果无法降级liburing,可跳过io_uring_prep_write函数,手动构造符合Kernel 5.4要求的SQE,强制使用原生的IORING_OP_WRITE(opcode为0x01):
修改代码中设置write操作的部分:
// 替换原来的io_uring_prep_write调用 memset(sqe, 0, sizeof(*sqe)); sqe->opcode = IORING_OP_WRITE; // Kernel 5.4支持的基础write操作码 sqe->fd = fd; sqe->addr = (unsigned long long)buf; sqe->len = strlen(buf); sqe->off = 0;
额外验证点
- 确保内核已开启
CONFIG_IO_URING配置(你的环境中io_uring_queue_init成功,说明已开启); - 保持缓冲区的页对齐(你已通过
posix_memalign实现,无需调整); - 打开文件的参数无问题(当前的
O_WRONLY | O_TRUNC | O_CREAT是合理的)。
内容的提问来源于stack exchange,提问作者Chris Z
相关产品推荐
相关产品推荐

