NVME磁盘驱动中blk_rq_map_user函数的作用及映射实现机制是什么
blk_rq_map_user核心作用
它的核心功能是将用户态传入的虚拟地址缓冲区,合法关联到块层的IO请求(struct request)上,让块设备驱动可以安全访问用户缓冲区的数据,同时满足硬件DMA操作的地址稳定性要求。它和mmap的逻辑完全不同:mmap是将内核/设备地址映射到用户虚拟地址空间供用户访问,而blk_rq_map_user是反向处理用户已分配的地址,为硬件访问用户内存做准备。
映射实现完整流程
顺着你提到的调用链,每一步的作用非常清晰:
入口
blk_rq_map_user接收参数
拿到用户态的__user类型地址指针ubuffer、缓冲区长度、读写方向等基础参数后,首先会做初步的参数合法性校验,避免非法地址传入。调用
import_single_range做地址校验
这一步会验证传入的用户虚拟地址范围是否真的属于当前进程的用户地址空间,有没有越界,读写权限是否和当前IO请求匹配(比如写磁盘请求对应的用户缓冲区必须有可读权限),校验通过后将地址范围封装成iovec结构,再转换成iov_iter迭代器,方便后续按页处理内存。调用
blk_rq_map_user_iov完成核心映射
这是映射逻辑的核心,分为几个关键步骤:- 先给当前
struct request分配对应的struct bio结构,bio是块层描述IO操作的基本单元,用来存储IO对应的内存页集合。 - 调用
get_user_pages_fast()遍历用户虚拟地址范围,把这段地址对应的物理页全部锁定。锁页的核心作用是防止这些页被操作系统换出到swap,保证后续DMA操作过程中,页的物理地址始终稳定,不会出现访问失效的问题。 - 把锁定的物理页逐个添加到bio的页向量
bio->bi_io_vec中,同时记录每一页在用户地址中的偏移、有效数据长度,设置bio的读写方向、对应块设备等参数。 - 最后把构造完成的bio挂到传入的
struct request上,后续块层调度、驱动处理请求时,直接从request中获取bio即可操作对应的内存。
- 先给当前
补充说明
你之前猜测磁盘需要物理地址是正确的,NVMe驱动处理这个request的时候,会从bio中取出已经锁定的物理页,再根据系统IOMMU配置生成DMA地址,之后就可以发给NVMe控制器执行读写操作。请求处理完成后,块层会自动解锁之前锁定的物理页,如果是读请求还会做缓存刷新,保证用户态可以读到最新的数据。
内容的提问来源于stack exchange,提问作者Fra93
相关产品推荐
相关产品推荐

