NVMe的Queue与命名空间
本文属于《 NVMe协议基础系列教程》之一,欢迎查看其它文章。
1 概述
NVM Express (NVMe)是一个寄存器级接口,用来实现主机软件与非易失性存储器子系统通信。该接口针对企业和客户端固态驱动器进行了优化,通常附加到PCI Express接口。该接口的目标是在客户端和企业系统中使用。
此外,该规范还定义了一个用于NVM子系统的标准命令集。
2 操作原理
NVM Express是一种可扩展的主机控制器接口,旨在满足利用基于PCI Express的固态驱动器的企业和客户端系统的需求。
该接口提供了优化的命令提交和完成路径。它支持多达65,535个I/O队列,每个l/O队列最多可执行64K个未完成命令,从而支持并行操作。此外,还增加了对许多Enterprise功能的支持,例如端到端数据保护(与T10 DIF和SNIA DIX标准兼容)、增强的错误报告和虚拟化。
该接口具有以下关键属性:
- 不需要在命令提交或完成路径中,读取不可缓存或MMIO寄存器。
- 在命令提交路径中,最多需要一个MMIO寄存器写入。
- 支持多达65535个I/O队列,每个I/O队列最多支持64K未完成命令。
- 优先级与每个I/O队列相关联,具有良好定义的仲裁机制。
- 完成4KB读请求的所有信息都包含在64B命令本身中,从而确保高效的小I/O操作。
- 高效和精简的命令集。
- 支持MSI/MSI- x和中断聚合。
- 支持多个命名空间。
- 有效支持I/O虚拟化架构,如SR-IOV。
- 健壮的错误报告和管理能力。
- 支持多路径I/O和命名空间共享。
本规范定义了一组精简的寄存器,其功能包括:
- 控制器capabilities指示
- 控制器故障Status(命令状态直接通过CQ处理)
- Admin Queue配置(I/O Queue配置通过Admin commands处理)
- Doorbell寄存器,可扩展提交队列和完成队列的数量
NVM Express控制器与单个PCI Function相关联。控制器支持的capabilities在Controller Capabilities (CAP) register中指明,并作为Controller和Namespace数据结构的一部分,被Identify命令返回。
- Identify Controller数据结构,表示应用于整个控制器的capabilities和settings。
- Identify Namespace数据结构,表示特定于特殊命名空间的capabilities和settings。
2.1 Queue基本原理
NVMe使用循环队列(Queue)传递消息,例如命令和命令完成通知。Queue可以位于主机PCle内存中的任何位置。
- 通常,Queue位于主机内存中;
- Queue可以由连续的物理内存块或可选的物理内存块组成不连续的物理内存页集(由PRP列表定义);
- Queue由一组固定大小的元素组成。
Queue本质上,是具有固定大小的环形缓冲区,其逻辑视图和物理视图,如下所示:
Tail
- 指向下一个空闲元素;
- 如果将一个元素添加到tail所指向的元素中,则tail将加1,以指向下一个空闲元素。
Head
- 如果队列不为空,则指向下一个要删除的条目;
- 如果一个元素从head所指向的元素中被移除,那么head的值会加1,指向下一个元素。
Queue Size(可用)
- 队列中的条目数- 1
- 最小大小为2,I/O Queue最大值为64K,Admin Queue的最大值为4K
Queue Empty
- Head == Tail
Queue Full
- Head == Tail + 1 mod Of Queue Entries.
2.2 Admin与I/O Queue
Queue按Command划分,有2种类型,即:
-
Admin Queue
它是为了控制器管理和控制而存在的,通常用于配置I/O Queue和控制器/特性管理。
此Queue对应Admin Command Set,也就是说,只有属于Admin Command Set的命令才能提交到Admin Submission Queue。
每个NVMe控制器有一个Admin Queue,每个Admin Queue最多有4K个元素。 -
I/O Queue
用于提交/完成IO命令。
此Queue对应IO Command Set,也就是说,只有属于IO Command Set的命令才能提交到I/O Submission Queue。
每个NVMe控制器最多64K个I/O Queue,每个I/O Queue最多64K个元素。
2.3 Submission与Completion Queue
Queue按功能划分,也有2种类型,即:
-
Submission Queue(SQ)
用于从主机向NVMe控制器,提交命令,以供控制器执行;通过SQ ID识别。 -
Completion Queue(CQ)
用于从NVMe控制器向主机,为完成的命令,返回执行结果状态;通过CQ ID识别。对于每个Completion Queue,可以有一个独立的MSI-X中断。
因此,对于Admin Command Set,就有Admin Submission Queue和Admin Completion Queue。
对于IO Command Set,就有I/O Submission Queue和I/O Completion Queue。
我们捋一捋,其实一共就这4种Queue,他们的含义,如下所示:
- Admin Submission Queue
向NVMe控制器提交管理类命令,供控制器执行。 - Admin Completion Queue
向主机返回管理类命令,执行结果状态。 - I/O Submission Queue
向NVMe控制器提交IO命令,供控制器执行。 - I/O Completion Queue
向主机返回IO命令,执行结果状态。
2.4 Submission与Completion Queue对应关系
NVM Express基于成对的Submission和Completion Queue机制。
- 命令由host软件放入提交队列。
- Completions由控制器放置到相关的完成队列中。
- 多个提交队列可能使用同一个完成队列。
- 提交队列和完成队列在主机内存中分配。
一对Admin Submission Queue和Admin Completion Queue是为了控制器管理和控制而存在的(例如,I/O Submission Queue和I/O Completion Queue的创建和删除,中止命令等),只有属于Admin Command Set的命令才能提交到Admin Submission Queue。
I/O命令集与I/O队列成对一起使用。本规范定义了一个I/O命令集,命名为NVM命令集。主机选择一个I/O命令集用于所有I/O queue对。
Host软件创建队列,可以达到控制器支持的最大队列数。通常,创建的命令队列数量取决于系统配置和预期的工作负载。
例如,在一个基于4个核心处理器的系统上,每个核心可能有一个queue对,以避免锁定并确保在适当的处理器核心的缓存中创建数据结构。
图1,提供了queue对机制的图形表示,显示了Submission Queues和Completion Queues之间的1:1映射。
图2,展示了一个例子,多个I/O Submission Queues利用了Core B上相同的I/O Completion Queues。
图1和图2显示了Admin Submission Queue和Admin Completion Queue之间总是存在1:1的映射。
- Submission Queue (SQ)
Submission Queue (SQ)是一个具有固定槽大小的环形缓冲区,Host软件使用它来提交命令供控制器执行。当有1到n个新命令需要执行时,Host软件更新相应的SQ Tail doorbell register。当有新的doorbell register写入时,之前的SQ Tail值在控制器中被覆盖。控制器从Submission Queue中按顺序获取SQ条目,但是,它可以以任何顺序执行这些命令。
每个Submission Queue条目都是一个命令,命令大小为64字节。主机内存中用于数据传输的物理内存位置是使用Physical Region Page(PRP)项或Scatter Gather Lists指定的。每个命令可以包括两个PRP条目或一个Scatter Gather List (SGL)段。如果描述数据缓冲区需要两个以上的PRP项,则提供一个指向PRP链表的指针,该链表描述了PRP项的列表。如果需要多个SGL段来描述数据缓冲区,则SGL段提供一个指向下一个SGL段的指针。
- Completion Queue(CQ)
Completion Queue(CQ)是一个具有固定槽大小的环形缓冲区,用于为完成的命令投递状态。一个完成的命令,由SQ标识符和命令标识符(由Host软件分配)的组合,唯一地标识。多个提交队列可以关联到一个完成队列。当单个工作线程通过一个完成队列处理所有命令完成时,即使这些命令来自多个提交队列,也可以使用此功能。在处理完最后一个空闲completion queue项之后,Host软件会更新CQ Head指针。在completion queue项中定义了一个Phase位,表示该项是否在未查询寄存器的情况下新发布。这使主机软件能够确定新条目是否作为前一轮或当前轮完成通知的一部分发布。具体来说,每一轮通过Completion Queue条目,控制器反转Phase位。
3 多路径I/O和命名空间共享
多路径I/O和命名空间共享,都要求NVM子系统包含两个或多个控制器。
两台或多台主机对共享命名空间的并发访问,需要主机之间进行某种形式的协调。用于协调这些主机的过程,NVMe协议规范未进行约定。
- 多路径I/O,是指一台主机和一个命名空间之间有两条或多条完全独立的物理PCI Express路径。
- 命名空间共享,是指两台或更多主机使用不同的NVM Express控制器访问一个公共共享的命名空间的能力。
3.1 1Port+1Controller
图3,显示了一个NVM子系统,它包含一个NVM Express控制器和一个PCI Express端口。由于这是一个单一Function的PCI Express设备,NVM Express控制器应该与PCI Function 0相关联。一个控制器可以支持多个命名空间。
图3中的控制器,支持NS A和NS B两个命名空间,与每个控制器命名空间相关联的是命名空间ID,分别标记为NSID 1和NSID 2,由控制器用于引用特定的命名空间。
命名空间ID,不同于命名空间本身,它是主机和控制器用于在命令中,指定特定命名空间的句柄。控制器的命名空间id到命名空间的映射,NVMe规范未做约定。
在本例中,命名空间ID 1与NS A相关联,命名空间ID 2与NS B相关联。这两个命名空间都是控制器私有的,本配置不支持多路径I/O,也不支持命名空间共享。
3.2 1Port+2Controller
图4,显示了一个多Function NVM子系统,其中一个PCI Express端口包含两个控制器,一个控制器关联PCI Function 0,另一个控制器关联PCI Function 1。每个控制器,支持单个私有命名空间和对共享命名空间B的访问。在所有访问特定共享命名空间的控制器中,命名空间ID必须相同。在本例中,两个控制器使用命名空间ID 2,访问共享命名空间B。
每个控制器都有一个唯一的Identify Controller数据结构,每个命名空间都有一个唯一的Identify Namespace数据结构。
访问共享命名空间的控制器,返回与该共享命名空间相关联的Identify Namespace数据结构(即,访问同一个共享命名空间的所有控制器,都返回相同的数据结构内容)。在Identify Namespace数据结构中,EUI64 (IEEE Extended Unique Identifier, IEEE扩展唯一标识符)字段是一个全局唯一的名称,与命名空间本身相关,可用于确定是否有两个或多个控制器访问同一个共享命名空间。
与共享命名空间关联的控制器,可以并发地操作该命名空间。各个控制器执行的操作,在命令提交到的控制器的写原子性级别上,是原子到共享命名空间的。共享命名空间的控制器之间,不要求写原子性级别相同。如果,在发送给访问共享命名空间的不同控制器的命令之间,存在任何顺序要求,则需要宿主软件或相关应用程序,来强制执行这些顺序要求。
3.3 2Port+2Controller
图5,说明了具有两个PCI Express端口的NVM子系统,每个端口都有一个相关的控制器。两个控制器,都映射到对应端口的PCI Function 0。在这个例子中,每个PCI Express端口都是完全独立的,并且有自己的PCI Express基本复位和参考时钟输入。端口复位,只影响该端口关联的控制器,对其他控制器、共享命名空间和其他控制器对共享命名空间的操作没有影响。这个例子的Function行为,在其他方面与图4所示的相同。
图5中显示的两个端口,可能与相同的Root Complex或不同的Root Complex相关联,并且可能用于实现多路径I/O和I/O共享体系结构。系统级别的体系结构方面和PCI Express fabric中多个端口的使用,不在NVMe规范约定范围。
3.4 SR-IOV
图6,展示了一个支持单根I/O虚拟化(SR-IOV)的NVM子系统,它具有一个物理Function和四个虚拟Function。NVM Express控制器与每个虚拟Function相关联,每个控制器都有一个私有命名空间,并可以访问所有控制器共享的命名空间,命名为NS E。本例中控制器的行为,与本节中其他示例的行为类似。
本节提供的示例,旨在说明概念,并不打算列举所有可能的配置。例如,NVM子系统可能包含多个PCI Express端口,每个端口都支持SR-IOV。