使用O_DIRECT时lio_listio()报EIO,求支持DIO的批量同步IO替代函数
解决O_DIRECT下lio_listio()返回EIO的问题及替代方案
首先需要明确:POSIX的lio_listio()本身是支持O_DIRECT的,你遇到的EIO错误大概率不是函数不支持DIO,而是违反了O_DIRECT的强制对齐要求。
先排查EIO的根本原因
使用O_DIRECT时,以下三个参数必须严格与文件系统的块大小(可通过stat的st_blksize字段获取)对齐:
- 缓冲区地址:
aiocb.aio_buf必须是块大小的整数倍,建议用posix_memalign()分配缓冲区,而非malloc() - 文件偏移:
aiocb.aio_offset必须是块大小的整数倍 - 读写长度:
aiocb.aio_nbytes必须是块大小的整数倍
如果以上任意一项不满足,内核就会返回EIO错误,和lio_listio()本身无关。
若需替代方案(支持DIO且批量等待完成)
如果确认对齐没问题仍有异常,或者确实需要替代API,可以使用Linux原生AIO(区别于POSIX AIO)的io_submit() + io_getevents()组合,它天生支持O_DIRECT,且能批量提交IO请求并等待全部完成:
基本使用流程
- 初始化IO上下文:
io_context_t ctx = 0; io_setup(MAX_IO_EVENTS, &ctx); - 构造多个
iocb结构(对应每个IO请求):struct iocb cb[NUM_REQUESTS]; struct iocb *cbs[NUM_REQUESTS]; for (int i = 0; i < NUM_REQUESTS; i++) { io_prep_pread(&cb[i], fd, buf[i], size[i], offset[i]); // 写请求替换为io_prep_pwrite cbs[i] = &cb[i]; } - 批量提交请求:
long ret = io_submit(ctx, NUM_REQUESTS, cbs); - 等待所有请求完成:
struct io_event events[NUM_REQUESTS]; long completed = io_getevents(ctx, NUM_REQUESTS, NUM_REQUESTS, events, NULL); - 清理IO上下文:
io_destroy(ctx);
注意:Linux原生AIO的API不属于POSIX标准,仅在Linux系统可用,其iocb结构与POSIX的aiocb不兼容。
内容的提问来源于stack exchange,提问作者mhsquare
相关产品推荐
相关产品推荐

