块设备 I/O:从 submit_bio 到blk_mq queue_rq 的请求路径

发布时间:2026/10/25 11:17:45
块设备 I/O:从 submit_bio 到blk_mq queue_rq 的请求路径 磁盘有节点但读写挂死、iostat里 await 飙高、自写驱动probe成功却无 I/O问题常在bio → request → mq 硬件队列的衔接而不是文件系统本身。本文沿submit_bio→blk_mq_submit_bio→queue_rq→ complete走通主路径便于对照 blktrace 与驱动回调排障。源码锚点路径作用include/linux/blkdev.hstruct gendisk、block_device_operations、submit_bio*include/linux/blk-mq.hstruct blk_mq_ops、blk_mq_tag_setblock/blk-core.csubmit_bio/ 通用提交流程block/blk-mq.cmq 分发、queue_rq调用block/genhd.cdevice_add_disk/ 磁盘注册include/linux/bio.hstruct bio扇区与生物向量关键回调头文件/* include/linux/blkdev.h */structblock_device_operations{blk_qc_t(*submit_bio)(structbio*bio);int(*open)(structblock_device*,fmode_t);void(*release)(structgendisk*,fmode_t);structmodule*owner;/* … */};/* include/linux/blk-mq.h */structblk_mq_ops{blk_status_t(*queue_rq)(structblk_mq_hw_ctx*,conststructblk_mq_queue_data*);void(*complete)(structrequest*);/* timeout / poll / commit_rqs … */};现代驱动注册骨架概念/* 1) 准备 tag_set mq ops 2) 分配 gendisk/queue 3) device_add_disk */set.opsmy_mq_ops;set.nr_hw_queuesn;set.queue_depthdepth;set.numa_nodeNUMA_NO_NODE;blk_mq_alloc_tag_set(set);/* 具体分配 API 随内核版本演进blk_mq_alloc_disk / blk_alloc_disk 等 以你树中 block/ 与 Documentation/block 为准 */disk-fopsmy_fops;disk-private_datamy_data;device_add_disk(parent,disk,NULL);调用链用户态 read/write / 页缓存回写 / fs → 生成 bio或走 iomap/buffered 路径汇聚为 bio → submit_bio(bio) /* block/blk-core.c 一带 */ → 若 disk 使用 mq → blk_mq_submit_bio → 合并/调度策略电梯/插件随配置 → blk_mq_get_tag 构造 request → hctx-queue_rq 或 ops-queue_rq → 驱动把请求提交给硬件/仿真后端 → I/O 完成blk_mq_complete_request / ops-complete → bio_endio → 唤醒等待者 / 结束页缓存写回打开与容量open(/dev/sdX) / 分区扫描 → bdev open → disk-fops-open若实现 → /sys/block/disk/size、队列参数决定可寻址范围与并发重点知识1. bio 是通用 I/O 货币request 是队列侧封装文件系统/页缓存不直接碰硬件它们提交bio。块层把 bio 映射为request再由blk_mq_ops.queue_rq下发。自写驱动若只实现了字符式read而没有挂上队列块节点不会按预期工作。2. mq 的核心是queue_rq 完成路径成对queue_rq返回BLK_STS_OK表示已接受错误用BLK_STS_*。忘记在中断/线程里blk_mq_complete_request表现就是 await 永远涨、进程 D 状态。超时走ops-timeout。3. 容量、逻辑块大小、队列深度必须自洽lsblk-tcat/sys/block/dev/queue/logical_block_sizecat/sys/block/dev/queue/nr_requestscat/sys/block/dev/size# 512B 扇区数历史接口语义# 追踪sudoblktrace-d/dev/dev-o-|blkparse-i- iostat-x1扇区/页不对齐的O_DIRECT、错误的max_hw_sectors会导致 EIO 或性能断崖。4. 注册与生命周期device_add_disk之后才会出现/dev与 sysfs。卸载必须先摘 I/O冻结队列、del_gendisk、释放 tag set避免还在飞的 request 访问已释放私有数据。5. 设计意图与踩坑意图用统一块层屏蔽 NVMe/SCSI/virtio 差异mq 按硬件队列扩展多核提交。坑在queue_rq里长时间阻塞应快速提交完成放 softirq/线程。坑完成路径漏blk_mq_complete_request或重复 complete。坑分区表/容量在revalidate前就对外可见用户态读到旧 size。坑只测缓冲 I/O未用O_DIRECT/dd oflagdirect验证驱动本身。Checklist能指出submit_bio→queue_rq→complete的文件级路径ls /sys/block/dev/存在size与驱动上报容量一致queue_rq与完成/超时回调成对无永久 D 状态读进程logical_block_size/max_sectors与硬件或仿真后端匹配iostat/blktrace能看到请求下发与完成而非只在 FS 层空转卸载路径先停 I/O 再del_gendisk无 UAF

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询