Flash Translation Layer 如何存储映射数据、不可用块和超级块?
Posted
技术标签:
【中文标题】Flash Translation Layer 如何存储映射数据、不可用块和超级块?【英文标题】:How does Flash Translation Layer store mapping data, unusable block and super block? 【发布时间】:2021-08-29 11:12:42 【问题描述】:ftl
有非flash的私有存储空间吗?
如果不是,ftl
如何在避免wear leveling
的同时存储这些元数据。
其实我不知道ftl
中是否有超级块,但是如果要定位映射数据和物理地址变化频繁的不可用块,可能需要某个物理地址。这个物理地址上的内容肯定会经常变化,如何避免这个物理地址的磨损均衡?
【问题讨论】:
【参考方案1】:这个问题有很多可能的解决方案,并且它与驱动器用来存储其数据的数据表示非常交织在一起,所以我相信它会因驱动器/制造商而有很大不同。我将概述一种可行的通用方法。
假设您设计了一个 FTL,它维护多个固定大小、仅附加的“日志”,并且为简单起见,我们始终有一个所有写入都附加到的“活动”日志。如果用户发出随机写入,则活动日志中 LBA 的顺序也将是随机的。当活动日志填满分配给它的所有空间时,它会被“冻结”,我们将活动日志切换到闪存中其他地方的一些空日志。随着冻结日志中的数据变得陈旧,我们最终需要通过将任何仍然引用的块复制到不同的日志来对其进行垃圾收集,然后再擦除原始日志,以便可以将其重新用于新的写入。
现在,对于每次写入日志,到目前为止,我们界面中的任何内容都不需要块恰好为 4KiB(或其他),因此您可以在数据中附加一个小标题,告诉您它的 LBA 是什么,也许其他一些元数据——写入序列号,以便您可以判断它是否是块的最新副本,并且可能是用于读取完整性检查的校验和。写入完成后,您会使用已更新 LBA 的新位置(SSD 内的 RAM,显然不是计算机主 CPU 的 RAM)更新地图的内存中副本。
如果 FTL 崩溃或断电,您可以通过读取所有日志中的所有标题来重建映射。缺点是扫描日志会扩展O(number of logs * number of blocks per log)
,因此您可以以某种方式对其进行优化:
O(number of logs * (log_2(number of blocks per log) + number of blocks that need to be scanned))
您如何知道何时停止扫描?要么你认识到你读取的块中的所有数据都是 1,因为那部分日志还没有被写入,要么你认识到校验和和数据不匹配。
小幅优化:在干净关机期间,始终将地图写入闪存,这样二分查找+扫描只需要在崩溃或不干净关机时进行。
到目前为止,这大大降低了您需要编写地图的频率,但对于使用寿命很长的驱动器而言,将其覆盖到固定位置仍然可能过于频繁。为了解决这个问题,我们必须在我们写地图的地方循环:
最简单的解决方案是指定一小组 X 特殊日志来存储所有地图数据并像循环缓冲区一样写入它们,其中选择 X 以使地图更新持续到设备的预期生命周期。要在启动时在日志中查找最新的映射,您需要在这些日志中进行二进制搜索以找到最后写入的映射。所以开机=O(X * log_2(number of maps per log) + runtime to scan the other logs if unclean shutdown)
。
可能是一种更优化的解决方案(但可能更复杂),将映射直接写入发生更新的日志中。然后你需要一些方法来找到映射在启动时的位置——最明显的方法是将映射写入每个活动日志的开头,或者你可以通过在块中添加反向指针来允许任意映射写入指向日志中最新地图的标题。
另一方面,完整的地图刷新可能会很昂贵,如果它干扰用户 IO 的性能,会增加尾部延迟 - 允许增量更新会更好吗?那时您开始考虑使用诸如日志结构合并 (LSM) 树之类的东西来存储您的地图,这样每次增量写入都非常小,您可以分摊整个地图写入成本。
很明显,这个解释遗漏了许多微小的细节,但希望这足以让你开始。 :-)
【讨论】:
以上是关于Flash Translation Layer 如何存储映射数据、不可用块和超级块?的主要内容,如果未能解决你的问题,请参考以下文章
ass translation python(ass字幕文件半自动平移时间轴py脚本)