IORING_SETUP_SQPOLL遇Bad file descriptor及io_uring_enter未定义引用
io_uring SQPOLL模式开发问题排查
核心问题现象
- 配置启用
IORING_SETUP_SQPOLL内核侧轮询参数后,调用io_uring_cqe_get_data(cqe)接口返回Bad file descriptor类错误,对照io_uring官方文档中内核侧轮询章节的说明,判断需要补充SQ线程休眠唤醒的处理流程 - 按照文档指引补充对应代码后,gcc编译抛出
undefined reference to 'io_uring_enter'链接错误
开发环境基线
- 操作系统:Ubuntu 18.04.5 LTS
- 内核版本:5.4.0-62-generic
- 关联参考测试用例:公开gist仓库中的io_uring测试代码
参考补充的唤醒逻辑
/* 填充新的SQE提交条目 */ add_more_io(); /* * 若轮询SQ线程已进入休眠,需主动触发系统调用让内核感知新提交的IO */ if ((*sqring->flags) & IORING_SQ_NEED_WAKEUP) io_uring_enter(ring_fd, to_submit, to_wait, IORING_ENTER_SQ_WAKEUP);
排查解决思路
- 链接错误的根本原因:
io_uring_enter是内核实现的系统调用,glibc在2.32版本才内置对应的用户态封装,当前Ubuntu18.04自带的glibc版本为2.27,不存在该符号的封装定义,直接调用必然触发链接失败。5.4版本的内核已经完整支持io_uring_enter系统调用,无需依赖系统glibc提供的封装,可通过syscall()方法直接触发对应系统调用,替换原有直接调用io_uring_enter的代码即可解决链接问题 Bad file descriptor报错的触发根源:SQPOLL模式下内核的专用轮询线程若因为空闲超时进入休眠,用户侧新提交的SQE会因为没有轮询线程及时扫描环形队列而无法被感知,长期元数据偏移会导致环形队列状态不同步,最终在获取CQE时拿到无效的上下文信息,触发文件描述符类的错误- 唤醒流程的校验要求:必须在每次填充完新增SQE后,检查用户态与内核态共享的SQ环形队列
flags字段,若检测到IORING_SQ_NEED_WAKEUP标志置位,必须主动携带IORING_ENTER_SQ_WAKEUP参数触发系统调用唤醒内核轮询线程,否则会出现环状态不同步的各类运行异常 - 开发依赖注意事项:Ubuntu18.04系统源默认提供的liburing库版本过旧,既没有匹配5.4内核的能力,也缺少对应的接口封装,开发时可选择手动编译匹配对应内核版本的liburing源码做静态链接,或自行封装所需的io_uring系列系统调用,避免依赖版本不匹配触发符号找不到的问题
内容的提问来源于stack exchange,提问作者Alberto Pires
相关产品推荐
相关产品推荐

