没错,这是李连杰在《中南海保镖》中的一张剧照。剧情已经很模糊,准备晚上回去怀旧一下。今天用这张图开始,是因为接下来,我们要说的话题就是NVMe中端到端数据保护功能,看看NVMe中的保镖是怎样为我们的数据保驾护航的。
我们需要保护的是数据。Host与SSD之间,数据传输的最小单元是逻辑块(Logical Block,LB),每个逻辑块大小可以是512/520/1024/2048/4096字节等,Host在格式化SSD的时候,逻辑块大小就确定了,以后两者就按这个逻辑块大小进行数据交互。
数据从Host到NVM(Non-Volatile Memory,目前一般是闪存,后面我就用闪存来代表NVM),首先要经过PCIe传输到SSD的Controller,然后Controller把数据写入到闪存;反过来,Host想从闪存上读取数据,首先SSD Controller从闪存上获得数据,然后经过PCIe把数据传送给Host。
Host与SSD之间,数据在PCIe上传输的时候,由于信道噪声的存在(说白了就是存在干扰),可能导致数据出错;另外,在SSD内部,Controller与闪存之间,数据也可能发生错误。路途凶险。为确保Host与闪存之间数据的完整性,即Host写入到闪存的数据与最初Host写的数据一致,以及Host读到的数据与最初从闪存上读上来的数据一致,NVMe提供了一个端到端数据保护功能。
除了逻辑块数据本身,NVMe还允许每个逻辑块带个助理,叫做元数据(Meta Data)。这个助理的职责,NVMe虽然没有明确的要求,但如果数据需要保护,NVMe要求这个助理必须能充当保镖的角色。
元数据有两种存在方式,一种是作为逻辑块数据的扩展,和逻辑块数据放一起存放,这是贴身保镖:
另外一种方式就是逻辑块数据放在一起,元数据单独放在别处。虽不是贴身保护,但保镖在附近时刻注意着主人的安全,属非贴身保镖:
贴身保护与否,我们不关心形式,我们只关心元数据是如何保护逻辑块数据的。NVMe要求每个逻辑块数据的保镖配备下面这把武器:
其中的”Guard”是16比特的CRC (Cyclic Redundancy Check),它是逻辑块数据算出来的;”Application Tag”和”Reference Tag”包含该数据块的逻辑地址(LBA)等信息。CRC校验能够检测出数据是否有错,后者则是保证数据不会出现张冠李戴的问题,比如我LBA X使用了LBA Y的数据,这种情况往往是SSD固件Bug导致的。Anyway,NVMe能帮你发现这个问题。
佩了保镖的数据看起来就是下面这个样子(以512字节的数据块为例):
在Host与SSD数据传输过程中,NVMe可以让每个逻辑块数据都带上保镖,也可以让他们不带保镖,也可以在某个治安差的地方把保镖带上,然后在治安环境好的地方不用保镖。
Host往SSD写入数据,不带保镖:
什么情况下可以不带保镖?
如果你普通人一个,完全没有必要配保镖,原因有:1. 你请不起保镖;2. 谁有空来伤害你呢?3. 太平盛世。
如果是无关紧要的数据(如小电影),完全没有必要进行端到端的保护,毕竟数据保护需要传输额外的数据 (每个逻辑数据块需要至少额外8字节的数据保护信息,有效带宽减少),还需要SSD做额外的数据完整性校验(耗时,性能变差),最关键的是PCIe通道上,其数据天然就能受到保护。怎么说?
对每个TLP来说,其中有个Digest域,就是对HDR和Data进行数据保护的,本质就是CRC。这个Digest是可选的。如果使能了Digest,数据在PCIe上传输是毫无风险的,因为有便衣警察保护,在NVMe层完全没有必要进行额外的数据保护。
当然,它不能发现数据张冠李戴的问题。
Host往SSD写入数据,全程带上保镖的情况:
红色PI,Protection Information,就是传说中的保镖。NVMe居然给数据配这么一个大红显眼的保镖,我也算是服了。
Host数据通过PCIe传输到SSD Controller之间,按理来说数据已经受到PCIe的保护,但PCIe保镖也有可能不在情况,那就是TLP中Digest域可能不存在,这是PCIe允许的。这个时候,如果要保证在PCIe上数据传输的可靠性,就需要NVMe自带保镖。数据到达SSD Controller时,SSD Controller会重新计算逻辑块数据的CRC,与保镖的CRC比较,如果两者匹配,说明数据传输是没有问题的;否则,数据就是有问题的,这个时候,SSD Controller就会给Host报错。
除了CRC校验,还要检测有没有张冠李戴的问题,通过检测Reference Tag 和Application Tag,看看这个没有CRC问题的数据是不是该笔Host写命令对应的数据,如果不匹配,同样需要向Host报错。
如果数据检测没有问题,SSD Controller会把逻辑块数据和PI一同写入闪存中。这个PI一同写入到闪存中有什么意义呢?在读的时候有意义。
SSD Controller读闪存的时候,会对读上来的数据进行CRC校验,如果写入的时候带有PI,这个时候就能检测出读上来的数据是否正确,从而决定这个数据要不要传给Host。有人要说,对闪存来说,数据不是受ECC保护吗?为什么还要额外进行数据校验?没错,写入到闪存中的数据是受ECC保护,这个没有问题,但在SSD内部,数据从Controller到闪存之间,一般都要经过DRAM或者SRAM,在之前SSD Controller写入到闪存,或者这个时候从闪存读数据到SSD Controller,可能就会发生比特翻转之类的小概率事件,从而导致数据不正确。如果在NVMe层再做个CRC保护,这类数据错误就能被发现了。
除了数据在SSD内发生反转,由于固件问题,或者别的原因,还是会出现数据张冠李戴的问题:数据虽然没有CRC错误,但是它不是我们想要的数据。因此,还需要做Reference Tag和Application Tag检测。
SSD Controller通过PCIe把数据传给Host,Host端也会对数据进行校验,看SSD返回过来的数据是否有错。
Host往SSD写入数据,半程带保镖的情况:
这种情况,Host与Controller端之间是没有数据保护,因为PCIe已经能提供数据完整性保证了(TLP中的Digest使能)。但在SSD内部,Controller到闪存之间,由于乱七八糟的原因(数据反转,LBA数据不匹配),存在数据错误的可能,NVMe要求SSD Controller在把数据写入到闪存前,计算好数据的PI,然后把数据和PI一同写入到闪存。
SSD Controller读闪存的时候,会对读上来的数据进行PI校验,如果没有问题,剥除PI,然后把逻辑块数据返回给Host;如果校验失败,说明数据存在问题,SSD需要向Host报错。如下图所示:
数据端到端保护是NVMe的一个特色,其本质就是在数据块当中加入CRC和数据块对应的LBA等冗余信息,SSD Controller或者Host端利用这个这些信息进行数据校验,然后根据校验结果执行相应的操作。加入这些检错信息的好处是能让Host与SSD Controller及时发现数据错误,副作用就是:
-
每个数据块需要额外的至少8字节的数据保护信息,有效带宽减少:数据块大小越小,带宽影响越大。
-
SSD Controller需要做数据校验,影响性能。
但是,我觉得这二个副作用的影响是微乎其微的,跟数据安全性相比,这又算得了什么呢?