NVMe 协议学习笔记

一、Linux NVMe 驱动中的限流:

为了防止 SQ 和 CQ 队列溢出,驱动中基于 tag 实现了一套 IO 限流策略:

  1. NVMe 驱动在初始化时会调用 blk_mq_init_queue 创建用于容纳 request 的 queue,对于每个 queue Linux 驱动中可以为其指定一种用于调度 request 的 elevator 算法(通常包括 kyber、mq-deadline 以及 bfq),算法是通过 blk_mq_init_sched 初始化的,其中指定了 queue 中的 nr_requests 用于限制可容纳的最大请求。
    ![](/images/nvme-协议学习笔记/Untitled 1.png)
  2. 此后其会根据 nr_requests 值去创建一系列 blk_mq_tags 以及 request用于后续发送消息。
  3. 在 Linux Block 层创建新的 request 时会通过 blk_mq_get_tag 来判断软件队列 tag 是否有剩余,如果有剩余则下发 IO 到软件缓冲队列中,如果无剩余则循环 sleep 等待。
    ![](/images/nvme-协议学习笔记/Untitled 2.png)
    另外初始化完成后,调度算法会定期的去处理软件缓冲队列,将其中的 request 派发到对应的硬件队列中,具体是通过 blk_mq_dispatch_rq_list 进行派发的,此处通过 __blk_mq_get_driver_tag 判断硬件队列 tag 是否有剩余来进行限流。
    ![](/images/nvme-协议学习笔记/Untitled 3.png)
  4. 如果通过了限流,其就会调用 queue_rq 将其放入到 nvme 的队列中,并写 sq tail doorbell 通知 NVMe 驱动。

可以参考:

https://docs.kernel.org/block/blk-mq.html

https://blog.csdn.net/hu1610552336/article/details/111464548

https://blog.csdn.net/zhuzongpeng/article/details/127604503?ops_request_misc=%7B%22request%5Fid%22%3A%22170366806016800188527427%22%2C%22scm%22%3A%2220140713.130102334.pc%5Fblog.%22%7D&request_id=170366806016800188527427&biz_id=0

二、NVMe 中的 SQ 和 CQ:

他们队列是初始化在主机内存中的,因此控制器是只写的,而他们的寄存器则是初始化在控制器中的,因此主机是只读的。于是需要特殊的通信逻辑,对于 SQ 来讲,主机通过写 SQTD 寄存器来告知控制器有新的 SQE,但它不能读取 SQHD,因此 Head 是通过控制器写的每一个 CQE 中的 SQHP 字段来上报的。而对于 CQ 来讲,主机可以通过写 CQHD 来告知控制器消费到了哪里,而 Tail 则是由控制器发送 CQE 时的 Phase 字段来确定的,CQ 第一轮会被写 1,第二轮就被写 0,循环往复,主机通过检查 CQE 的 Phase 字段是否被翻转就可以知道 Tail 的位置了。

![](/images/nvme-协议学习笔记/Untitled 4.png)

http://www.ssdfans.com/?p=8139

三、虚拟机重启时 NVMe 的逻辑:

流程:

  1. Linux 驱动下令删除所有的 IO Queue。
  2. Linux 驱动更新 cc.shn 通知驱动 shutdown,SPDK 关闭所有剩余的 io queue,并调用 disable_ctrlr
  3. Qemu 通过 vfio_user 下发 VFIO_USER_DEVICE_RESET 指令,SPDK 调用vnvmf_ctrlr_reset ,清理 SDBL注意根据代码注释这里可能缺少一些逻辑。
  4. 分配一系列用于 dma 的内存。
  5. Qemu 再次下发VFIO_USER_DEVICE_RESET 指令。
  6. Qemu 清理 cc 寄存器,获取vs、cap寄存器,设置 aqa acq asq 等,并触发 SPDK 调用 enable_ctrlr
  7. Qemu 创建 Admin Queue 和一个 IO Queue,之后销毁。
  8. Linux 进入启动阶段,驱动开始读取寄存器,获取 vs、cap。驱动清空 cc 寄存器,设置 aqa acq asq 等寄存器。
  9. 更新 cc 寄存器,SPDK 调用 enable_ctrlr

四、PRP & SGL

![](/images/nvme-协议学习笔记/Untitled 5.png)

![](/images/nvme-协议学习笔记/Untitled 6.png)

https://blog.csdn.net/sinat_43629962/article/details/123991166

五、PersistentReservation

http://www.ssdfans.com/?p=97147

参考

https://github.com/andyBrake/andyBrake.github.io/blob/master/doc/nvme_express.md