Linux内核vfs_read函数中read与read_iter调用的区别是什么
read 与 read_iter 调用的核心差异、适用场景及设计区别 1. 接口定义与入参差异
两者都是struct file_operations里的读回调接口,核心签名差异如下:
- 传统
read回调签名:ssize_t (*read) (struct file *filp, char __user *buf, size_t count, loff_t *ppos);
入参是拆分的独立字段:直接传递用户态缓冲区指针buf、读取长度count、文件偏移指针ppos,强制绑定当前进程的上下文。 read_iter回调签名:ssize_t (*read_iter) (struct kiocb *iocb, struct iov_iter *iter);
入参用两个封装结构体传递所有IO信息:struct kiocb封装IO控制属性:包含文件指针、偏移量、IO优先级、异步标识、IO完成回调等所有控制信息struct iov_iter封装缓冲区信息:可以原生支持单个/多个不连续缓冲区,同时兼容用户态、内核态地址空间,不需要区分缓冲区来源。
2. 适用场景区别
read适用场景:- 仅需要支持同步阻塞读、没有高性能IO需求的简单字符设备、旧版文件系统
- 仅需要处理单个连续用户态缓冲区的读取请求,不需要支持readv、异步IO等特性的场景
- 是Linux 2.6之前就存在的遗留接口,兼容性更好,旧驱动基本都用该接口实现
read_iter适用场景:- 需要支持异步IO(AIO、io_uring)的场景,是目前内核所有异步读请求的唯一入口
- 需要支持分散聚集IO(对应readv、preadv等系统调用)的场景,不需要内核中间层做缓冲区拼接,开销更低
- 需要支持直接IO(O_DIRECT)、内核态发起读请求的场景,
iov_iter可以无缝对接内核态缓冲区,不需要额外的地址空间转换 - 高性能存储相关的驱动、文件系统(如ext4、XFS、NVMe驱动)目前都默认基于
read_iter实现读逻辑
3. 设计层面的核心区别
- 扩展性差异:
read是面向单一简单场景的瘦接口,参数固定,后续新增IO特性必须修改回调签名,兼容性差;read_iter用结构体封装所有IO属性,新增特性只需要扩展kiocb或iov_iter的字段,不需要改动回调接口,扩展性更强。 - IO模型支持差异:
read本质只能支持同步阻塞IO,所有操作必须在当前调用进程上下文完成,无法返回未完成状态;read_iter支持返回-EIOCBQUEUED标识IO已经异步提交,不需要阻塞当前调用者,是内核高性能异步IO框架的基础。 - 缓冲区适配差异:
read仅能处理用户态单个连续缓冲区,VFS层要支持readv这类多缓冲区请求时,必须额外做多次回调调用或者临时缓冲区拼接,额外开销大;read_iter的iov_iter原生兼容多缓冲区向量、用户/内核态地址空间,VFS层不需要做额外转换即可直接传递给底层实现,性能更高。
另外补充VFS层的当前实现逻辑:vfs_read会优先判断对应文件的f_op有没有实现read_iter,如果有就会把普通read系统调用的参数封装为kiocb和iov_iter后调用read_iter,只有未实现read_iter的才会回退到传统read回调,新开发的驱动和文件系统都推荐优先实现read_iter。
内容的提问来源于stack exchange,提问作者Divija Gogineni
相关产品推荐
相关产品推荐

