Work NVMe协议
文章目录
- 1. SQ/CQ 存放在主机内存还是盘内存?
- 2. 队列数量上限
- 3. 队列深度上限
- 4. 如何修改队列数量与深度
- (1)**nvme-cli 一键重建(最简单)**
- (2)**SET FEATURES (Feature ID=0x07) 动态调队列数**
- (3)**手动 CREATE/DELETE IO QUEUE(用户态 passthru)**
- 小结
1. SQ/CQ 存放在主机内存还是盘内存?
- Admin SQ/CQ 与 I/O SQ/CQ 均放在 主机内存(Host Memory)。
主机在初始化时按队列个数与深度一次性开辟连续(或 PRP/List 描述)内存,SSD 通过 PCIe 读/写这些内存区域完成取指与回写完成信息。
2. 队列数量上限
队列类型 | 数量上限 | 备注 |
---|---|---|
Admin SQ/CQ | 1 对 | 固定,不能增减 |
I/O SQ/CQ | 65 535 对(64 K - 1) | 理论值;实际受限于 SSD 控制器、主机内存、在线 CPU 数 |
注:一条 I/O CQ 可被多条 I/O SQ 共享(多对一),也可一对一。
3. 队列深度上限
队列类型 | 深度范围 | 最大深度 |
---|---|---|
Admin SQ/CQ | 2–4 096 | 4 096 |
I/O SQ/CQ | 2–65 536 | 65 536(64 K) |
深度值在创建队列时以 “队列条目数 - 1” 形式填入命令字段。
4. 如何修改队列数量与深度
NVMe 规范把“队列数”与“深度”都当成 控制器特性,需通过 Admin 命令 在初始化阶段设定;Linux 下常用三种途径:
(1)nvme-cli 一键重建(最简单)
# 先卸载块设备
echo 1 > /sys/block/nvme0n1/device/remove
# 重新加载,指定队列数与深度
modprobe -r nvme && modprobe nvme nr_io_queues=16 io_queue_depth=1024
nr_io_queues
:I/O SQ 数量(会等量生成 CQ)io_queue_depth
:每条 I/O SQ 的深度
值不能超过 Identify 控制器返回的
MQES
字段。
(2)SET FEATURES (Feature ID=0x07) 动态调队列数
struct nvme_command c = {0};
c.features.opcode = nvme_admin_set_features;
c.features.fid = 0x07; // Number of Queues
c.features.dword11 = (nr_cq << 16) | nr_sq;
__nvme_submit_sync_cmd(ctrl->admin_q, &c, &result, NULL, 0);
- 控制器返回实际能接受的 sq/cq 数量,驱动随后据此创建。
(3)手动 CREATE/DELETE IO QUEUE(用户态 passthru)
# 1. 创建完成队列
nvme admin-passthru /dev/nvme0 -o 0x05 --cdw10=$((qs-1)) --cdw11=1 --cdw12=0 --cdw15=0 \--data-len=0 --namespace-id=0# 2. 创建提交队列
nvme admin-passthru /dev/nvme0 -o 0x01 --cdw10=$((qs-1)) --cdw11=1 --cdw12=0 --cdw15=0 \--data-len=0 --namespace-id=0
0x05
= Create I/O CQ;0x01
= Create I/O SQqs
= 期望深度(填 “深度 - 1”)- 顺序必须 先 CQ 后 SQ。
小结
- SQ/CQ 100% 在主机内存;SSD 只保存 Doorbell 寄存器。
- 理论可建 64 K 对 I/O 队列、单队列深度 64 K;实际值用
nvme id-ctrl
查看MQES
/MAXQ
. - 数量/深度可通过 内核模块参数、SET FEATURES 或 手动 Admin 命令 在初始化阶段调整;运行后想改需先删队列再重建。