使用io_uring_enter遇EBADF错误,已确认文件描述符正确性
问题排查与修复
核心问题分析
你的代码存在两个关键错误,直接导致io_uring_enter返回EBADF:
1. io_uring_enter系统调用参数不完整
io_uring_enter系统调用需要6个参数,你的代码只传了5个,栈上的随机垃圾值被当作最后一个参数sigsz传入内核。内核校验参数时发现异常,返回了看似文件描述符错误的EBADF(实际是参数非法导致的误报)。看strace里的最后一个参数68719476736,这明显是无效的栈随机值,验证了这一点。
2. 标志位滥用
REQ_F_FORCE_ASYNC是提交IO请求时的请求标志,不是io_uring_enter系统调用的flags参数。把它和IORING_ENTER_GETEVENTS混合传入属于参数错误。
额外问题:逻辑无意义
你的代码在没有提交任何IO请求的情况下就调用io_uring_enter获取事件,即使参数正确,这个调用也没有实际作用,甚至会阻塞或返回错误。
修复后的代码
#define _GNU_SOURCE #include <stdio.h> #include <liburing.h> #include <pthread.h> #include <string.h> #include <errno.h> #define __NR_io_uring_setup 425 #define __NR_io_uring_enter 426 #define __NR_io_uring_register 427 #define QUEUE_DEPTH 2 int uring_setup(unsigned int entries, unsigned int flags) { struct io_uring_params p; memset(&p, 0, sizeof(p)); p.flags = flags; int fd = syscall(__NR_io_uring_setup, entries, &p); if (fd == -1) { perror("io_uring_setup failed"); } return fd; } int uring_enter(int fd, unsigned int to_submit, unsigned int min_complete, unsigned int flags) { // 传入完整的6个参数,sig设为NULL,sigsz设为0 return syscall(__NR_io_uring_enter, fd, to_submit, min_complete, flags, NULL, 0); } int main() { int fd = uring_setup(QUEUE_DEPTH, IORING_SETUP_IOPOLL); if (fd == -1) { return 1; } printf("fd: %d\n", fd); // 注意:要获取事件需先提交请求,这里演示参数正确的调用(无事件会阻塞,按Ctrl+C终止) int ret = uring_enter(fd, 0, 1, IORING_ENTER_GETEVENTS); if (ret == -1) { perror("io_uring_enter failed"); } else { printf("uring_enter: %d\n", ret); } return 0; }
额外说明
- IORING_SETUP_IOPOLL的限制:这个标志要求内核支持IO轮询,且对应文件系统/设备支持polled IO。如果环境不支持,
io_uring_setup会报错,建议先去掉这个标志测试基础功能,再逐步添加。 - 正确的io_uring使用流程:实际开发中需要:
- 调用
io_uring_setup获取fd - 映射提交队列和完成队列到用户空间
- 构造IO请求并加入提交队列
- 调用
io_uring_enter提交请求或获取完成事件
- 调用
- 建议使用liburing库:手动调用系统调用极易出错,官方的
liburing库封装了所有底层细节,能避免这类参数问题。
内容的提问来源于stack exchange,提问作者BitFriends
相关产品推荐
相关产品推荐

