本页目录
NVMe 与存储
覆盖: NVMe 协议 (SQ/CQ/PRP/SGL) → Linux NVMe 驱动 → NVMe multipath → NVMe-oF → SCSI 子系统 (sd/sr) → device mapper (dm-crypt/LVM/dm-thin) → Bcache/dm-cache 内核版本: 3.3 ~ 6.x
NVMe 协议基础
队列模型
NVMe 使用 PCIe + 环形队列模型,替代 AHCI 的固定深度命令槽:
每对 SQ (Submission Queue) + CQ (Completion Queue) 构成一个 I/O 通道
SQ: 主机 → 控制器 (host 写, 控制器读)
CQ: 控制器 → 主机 (控制器写, host 读)
多队列优势:
- 每个 CPU 核独享 SQ/CQ → 零锁竞争
- 最大支持 64K 队列, 每队列 64K 命令 → 极高的并行度
- 中断: MSI-X per-CQ → 每个队列独立中断 → IRQ affinity 天然绑核
命令格式
// include/linux/nvme.h
;
PRP vs SGL:
- PRP: 简单链表,每个 entry 指向一个物理页面。最多 2 个内联 + PRP list。适合小 IO
- SGL: 通用 scatter-gather 列表,支持任意长度的段。NVMe 1.2+ / NVMe-oF 必需
Doorbell 机制
提交命令:
1. host 写 NVMe command 到 SQ entry (环形缓冲区)
2. host 写 SQ Tail Doorbell (MMIO 写, 通知控制器有新命令)
3. 控制器取命令 → 执行 → DMA 数据 → 写 CQ entry
4. 控制器发 MSI-X 中断
5. host 写 CQ Head Doorbell (通知控制器 CQ entry 已消费)
整个流程: 1 次 MMIO 写提交, 0 次 MMIO 读 (CQ 在 host DDR 中)
对比 AHCI: 每次提交需要多轮 MMIO 读 (读 PxCI 等寄存器)
→ NVMe 延迟低 3~5x
Linux NVMe 驱动
驱动分层
// drivers/nvme/host/
// nvme-core.c: 协议实现 (admin queue, IO queue, identify, abort, ...)
// nvme.h: 数据结构 (nvme_command, nvme_completion)
// pci.c: PCIe 传输层 (MMIO doorbell, MSI-X, PRP mapping)
// fabrics.c: NVMe-oF 传输层 (TCP/RDMA/FC)
队列初始化流程
queue_rq: 提交路径 (热路径)
// drivers/nvme/host/pci.c
static blk_status_t
// 中断: nvme_irq()
// → nvme_process_cq() → 遍历 CQ entries
// → nvme_handle_completion() → blk_mq_complete_request()
// → mq_ops->complete() → end_that_request_last()
NVMe Multipath
// drivers/nvme/host/multipath.c
// 同一 namespace 可经由多条 I/O 路径访问:
// - NVMe-oF: 同一 subsystem 下多个 controller
// - PCIe: 双端口 NVMe 硬盘
// nvme-core 自动聚合同一 ns 的多个路径为一个 block device
// IO 调度:
// 默认 round-robin (ANA: Asymmetric Namespace Access)
// 优化路径: I/O policy knob
NVMe-oF (NVMe over Fabrics)
将 NVMe 协议扩展到网络:
NVMe/TCP: 标准 TCP 传输 (最通用)
NVMe/RDMA: InfiniBand/RoCE (最低延迟, ~10μs)
NVMe/FC: 光纤通道 (数据中心传统栈)
Linux 实现:
target (server): drivers/nvme/target/ + nvmet-tcp/nvmet-rdma
host: drivers/nvme/host/fabrics.c + nvme_tcp/nvme_rdma
SCSI 子系统
// drivers/scsi/
// 三层架构:
// Upper Level: sd (磁盘), sr (光驱), st (磁带)
// Mid Level: 通用命令构造, 错误恢复 (eh_*)
// Lower Level: 厂商 HBA 驱动
//
// 关键结构:
// scsi_cmnd: 一条 SCSI 命令
// scsi_host_template: HBA 驱动注册的操作
// queuecommand(): 提交 SCSI 命令 → HBA
// 5.x+ SCSI 默认使用 blk-mq (scsi_mod.use_blk_mq=1)
// 将 SCSI tag 映射到 blk-mq tag → 统一队列管理
Device Mapper: 块设备虚拟化
// drivers/md/
// Device Mapper (DM) 框架允许创建虚拟块设备:
// 常用 DM target:
// dm-linear: 线性映射 (LVM 的基础)
// dm-crypt: 块设备加密 (LUKS)
// dm-thin: 精简置备 (thin provisioning)
// dm-cache: SSD 缓存 HDD (dm-cache / dm-writecache)
// dm-raid: MD RAID 不再开发, DM RAID 接替
// dm-multipath: 多路径 IO (SAN)
// CRYPT (dm-crypt):
// 密钥: LUKS header on disk → 含加密算法, key slots, PBKDF
// 数据路径: bio → encrypt/decrypt per sector → 提交到下层设备
Bcache: SSD 缓存 HDD
// drivers/md/bcache/
// Bcache 将 SSD 作为 HDD 的读/写缓存
//
// 缓存模式:
// writeback: 写入先到 SSD → 异步回写 HDD (高性能, 断电风险)
// writethrough: 写入同时到 SSD 和 HDD (安全, 但写性能受限)
// writearound: 写入绕过 SSD 直接到 HDD (SSD 仅用于读)
// 内核 6.x 原生支持 bcache (主线合入)
调试与观测
# NVMe 驱动信息
# NVMe 命令级追踪
# SMART 数据
# 关键指标: temperature, percentage_used (寿命), media_errors
# DM 设备
# Bcache
# SCSI 层追踪
参考与延伸
- 源码:
drivers/nvme/host/pci.c(PCIe NVMe 驱动),drivers/nvme/target/(NVMe-oF),drivers/scsi/,drivers/md/,drivers/md/bcache/ - NVMe 规范: nvmexpress.org (base spec 1.4c/2.0)
- 内核文档:
Documentation/nvme/,Documentation/device-mapper/ - LWN: "The Linux NVMe driver", "Bcache design"
关键词: NVMe, SQ/CQ, doorbell, PRP, SGL, blk-mq, nvme_queue_rq, NVMe-oF, SCSI, device mapper, dm-crypt, Bcache