映射种类
根据映射粒度的不同,FTL 映射有基于块的映射,有基于页的映射,还有混合映射(Hybrid Mapping)。
块映射
块映射中,以闪存的块为映射粒度,一个用户逻辑块可以映射到任意一个闪存物理块,但是映射前后,每个页在块中的偏移保持不变。由于映射表只需存储块的映射,因此存储映射表所需空间小,但其性能差,尤其是小尺寸数据的写入性能,用户即使只写入一个逻辑页,也需要把整个物理块数据先读出来,然后改变那个逻辑页的数据,最后再整个块写入。块映射有好的连续大尺寸的读写性能,但小尺寸数据的写性能是非常糟糕的。
如上图所示,用户空间被划分成一个个逻辑区域(Region),每个区域和闪存块大小相同。
U盘一般都是采用块映射(U盘使用的存储介质也是闪存,因此也是有FTL的),适合大数据的传输,不适合小尺寸数据的写入。
页映射
页映射中,以闪存的页为映射粒度,一个逻辑页可以映射到任意一个物理页中,因此每一个页都有一个对应的映射关系,如图4-4所示。由于闪存页远比闪存块多,因此需要更多的空间来存储映射表。但它的性能更好,尤其体现在随机写上面。为追求性能,SSD一般都采用页映射。
如上图所示,用户空间被划分成一个个的逻辑区域,每个区域和闪存页大小相同。
实际中逻辑区域大小可能小于闪存页大小,一个闪存页可容纳若干个逻辑区域数据。
混合映射
混合映射是块映射和页映射的结合,
一个逻辑块映射到任意一个物理块,但在块中,每个页的偏移并不是固定不动的,块内采用页映射的方式,一个逻辑块中的逻辑页可以映射到对应物理块中的任意页。因此,它的映射表所需空间以及性能都是介于块映射和页映射之间的。
如上图所示,用户空间划分成一个一个逻辑区域,逻辑区域和闪存块大小相同。每个逻辑块对应着一个闪存块,但逻辑块内部又分成一个个逻辑页,与对应闪存块中的闪存页随意对应。
现在SSD基本都是采用页映射方式。
映射基本原理
户通过LBA(Logical Block Address,逻辑块地址)访问SSD,每个LBA代表着一个逻辑块(大小一般为512B/4KB/8KB……),我们把用户访问SSD的基本单元称为逻辑页(Logical Page)。而在SSD内部,SSD主控是以闪存页为基本单元读写闪存的,我们称闪存页为物理页(Physical Page)。用户每写入一个数据页,SSD主控就会找一个物理页把用户数据写入,SSD内部同时记录了这样一条映射(Map)。有了这样一个映射关系后,下次用户需要读某个逻辑页时,SSD就知道从闪存的哪个位置把数据读取上来,如下图所示:
SSD内部维护了一张逻辑页到物理页地址转换的映射表(Map Table)。用户每写入一个逻辑页,就会产生一个新的映射关系,这个映射关系会加入(第一次写)或者更改(覆盖写)映射表。当读取某个逻辑页时,SSD首先查找映射表中该逻辑页对应的物理页,然后再访问闪存读取相应的用户数据。
由于闪存页和逻辑页大小不同,一般前者大于后者,所以实际上不会是一个逻辑页对应一个物理页,而是若干个逻辑页写在一个物理页中,逻辑页其实是和子物理页一一对应的。
对于绝大多数SSD,我们可以看到上面都有板载DRAM,其主要作用就是存储这张映射表,如图4-7所示。在SSD工作时,全部或绝大部分的映射表都可以放在DRAM上,映射关系可以快速访问。
但有些入门级SSD或者移动存储设备(比如eMMC、UFS),出于成本和功耗考虑,它们采用DRAM-Less设计,即不带DRAM,比如经典的Sandforce主控,它并不支持板载DRAM,那么它的映射表存在哪里呢?它采用二级映射(见图4-8)。一级映射表常驻SRAM,二级映射表小部分缓存在SRAM,大部分都存放在闪存上。
二级表就是L2P(Logical address To Physical address,逻辑地址到物理地址转换)表,它被分成一块一块(Region)的,大部分存储在闪存中,小部分缓存在RAM中。一级表则存储这些块在闪存中的物理地址,由于它不是很大,一般都可以完全放在RAM中。
SSD工作时,对带DRAM的SSD来说,只需要查找DRAM当中的映射表,获取到物理地址后访问闪存便会得到用户数据,这期间只需要访问一次闪存。而对不带DRAM的SSD来说,它首先会查看该逻辑页对应的映射关系是否在SRAM内:如果在,直接根据映射关系读取闪存;如果不在,那么它首先需要把映射关系从闪存中读取出来,然后再根据这个映射关系读取用户数据,这就意味着相比于有DRAM的SSD,它需要读取两次闪存才能把用户数据读取出来,底层有效带宽减小,如下图所示:
下图是不带DRAM的SSD架构
对顺序读来说,映射关系连续,因此一次映射块的读,可以满足很多用户数据的读,也意味着DRAM-less的SSD可以有好的顺序读性能。但对随机读来说,映射关系分散,一次映射关系的加载基本只能满足一个逻辑页的读,因此对随机读来说,需要访问两次闪存才能完成读操作,随机读性能就不是那么理想了。
映射表刷新
映射表在SSD掉电前,是需要把它写入到闪存中去的。下次上电初始化时,需要把它从闪存中部分或全部加载到SSD的缓存(DRAM或者SRAM)中。随着SSD的写入,缓存中的映射表不断增加新的映射关系,为防止异常掉电导致这些新的映射关系丢失,SSD的固件不仅仅只在正常掉电前把这些映射关系刷新到闪存中去,而是在SSD运行过程中,按照一定策略把映射表写进闪存。这样,即使发生异常掉电,丢失的也只是一小部分映射关系,上电时可以较快地重建这些映射关系。
那么,什么时候会触发映射表的写入呢?一般有以下几种情况:
- 新产生的映射关系累积到一定的阈值
- 用户写入的数据量达到一定的阈值
- 闪存写完闪存块的数量达到一定的阈值
- 其他
写入策略一般有: - 全部更新
- 增量更新
全部更新表示的是缓存中映射表(干净的和不干净的)全部写入到闪存,增量更新的意思是只把新产生的(不干净的)映射关系刷入到闪存中去。显然,相比后者,前者需要写入更多的数据量,一方面影响用户写入性能和时延(latency),另一方面增加写放大,但其好处是固件实现简单,不需要去知道哪些映射关系是干净的,哪些是不干净的。