You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 04:18:09