FTL 如何处理 TRIM 请求?当闪存驱动器不支持 TRIM 请求时,它们如何工作?

FTL 如何处理 TRIM 请求?当闪存驱动器不支持 TRIM 请求时,它们如何工作?

(从 StackOverflow 上的一个问题中移出。TL;DR:我想知道现代闪存驱动器和 SSD(例如,三星 T5 似乎不支持 TRIM)如何处理已删除的数据。他们有没有办法检测某些数据是否真的被删除,或者他们是否保留了这些数据?当/如果它们磨损均衡时,写入放大问题有多严重,有什么办法可以解决这个问题?我可以通过用 0xFF 清除所有(未使用的)LBA 来“刷新”驱动器,以便对该部分闪存的新写入不需要擦除(因为否则你会覆盖可能包含 0-->1 转换的先前数据并触发额外的擦除,而且同一个块上可能存在多个 LBA,所以可能会触发多个 LBA)?我知道这比 TRIM 更糟糕,但因为它没有修剪...)

不久之前,我问过以下关于用 1 而不是 0 填充驱动器的问题: 如何用 1 代替 0 填充闪存驱动器 在这篇文章中,我得到的答案是,这与 TRIM 不同,而且比 TRIM 更糟糕。虽然后者对我来说是有意义的(将擦除排队以供稍后/重新分配与强制擦除,再加上较低级别的方法可能更加优化,因为磨损均衡计数没有改变),但我不清楚它会产生什么影响,也不清楚驱动器在没有 TRIM 支持的情况下如何工作。


我隐约知道 FTL(闪存转换层)在存储驱动器中的工作方式的高级细节,但我无法在其中找到有关写入放大细节的信息。没有 TRIM 的驱动器如何工作?有没有办法延长这些驱动器的使用寿命?

假设我有一个驱动器,每个块的块大小为几页(据我所知,是所有页面)。如果我更改文件中的某些数据,则会导致更新一个页面(或其中几个页面)(我将跳过“Flash 使用虚拟逻辑块并且没有逻辑块”的论点,只是假装每个页面都映射到一个或多个页面,但完整的 LBA 可能小于一个块)。

如果该页面包含任何变为 1 的 0,则必须先擦除整个块,然后才能写入数据(我不在乎这是否是更改数据所在的原始块。如果传入页面将 0 设置为 1,则必须擦除某个块)。由于还有其他页面未更改(假设这是文件的末尾,或者它是碎片化的),它们也会被复制回该块。

现在,事情变得模糊了。FTL 可以将页面重新映射到该块中的其他位置,或完全映射到其他块。我认为,为了系统映射表的使用寿命(它也必须存储在该闪存芯片中,尽管是更持久的部分),这种操作不会太频繁,因此大多数情况下它可能会被写回到同一个块。

麻烦的是,这种擦除周期会损坏闪存,因此最好将更改的数据写入预先擦除的块,以提高速度并避免对其他页面进行编程(从而让它们可以用于更多实际更改的数据)。这可能需要更新系统映射表以确定该页面的去向,因此我不确定如何存储这些数据,以便映射表不会在闪存本身磨损之前磨损*。

这里有两个选项。一个是驱动器支持 TRIM。这让计算机说:“我不使用这些 LBA,所以你可以将它们标记为垃圾收集。”因此,一旦该块被擦除,驱动器就可以跳过写回相应的 TRIMmed 页面,并且可以使用它来存储更​​改的页面而无需稍后擦除。或者它可能会将任何剩余的有效页面移出到某个空槽,并擦除整个块以备后用。这是有道理的。

所有不支持 TRIM 的 USB 拇指驱动器都让我感到困惑。因此,驱动器不知道您刚刚删除的文件内容实际上无效(因为文件系统只会删除指向该数据的指针)。所以我可以假设它最终要么没有剩余的空白页,要么为此使用保留区域。如果页面发生更改,它必须将所有页面复制回该块(或至少将它们重新映射到类似的 LBA),因为它无法知道该块是否包含数据。我认为其中一个驱动器会逐渐充满垃圾数据,因为每次使用 LBA 时,驱动器都无法知道它是否仍在使用中。如果它被覆盖并重新映射,也许可以对旧页面进行一些处理,但它大多无法合并释放的页面。这也意味着,如果它不使用保留区域作为临时空间,它将耗尽空间,因为它最终认为所有页面/LBA 都已被使用(在驱动器中(重新)写入了足够多的垃圾或文件系统在任何时候都已填满之后),并且无法判断文件的“内容”页面是否真的在使用中。这会导致写入放大,因为块中过去从已删除的文件中遗留下来的任何随机内容都会在更改时一次又一次地写回,而不是让空白空间用于磨损均衡或重新映射。然后,这将迫使任何磨损均衡将目标块的内容复制到原始块中,以免丢失,从而导致额外的写入和更短的使用寿命(此外,它无法有效使用“已擦除”的页面,或者根本无法使用,导致更改时必然擦除)。

因此,我假设用 1 写入驱动器(例如,使用 dd,或者只是对文件进行分类)会将所有单元覆盖为理想的擦除状态,以便写入。我可以猜测,由于所有单元都被覆盖,因此可以进行重新映射,但驱动器仍然无法判断所有内容的新值是否对整个文件系统真正重要,因此必须继续保留并报告它(尽管任何重新映射或使用这些已擦除页面都会立即可用,而无需进一步擦除)。因此,用零覆盖可能很糟糕,因为可见块中任何剩余的、尚未重用的页面都必须保持编程为零(并且每次写入时都需要擦除,这给我们留下了之前的“没有擦除页面”问题)。

但是,如果我用 0xff 覆盖,那么每当重新映射将页面移入其中或文件系统使用该 LBA 时,这些页面都会被删除。这难道不应该是清除闪存驱动器的最佳方法吗(如果它不支持 TRIM)?当然,这仍然不如 TRIM 那么好,但对于不支持它的驱动器,最好的选择是什么?完全不管它们?用零覆盖?用一覆盖?可能通过仅覆盖空白处,也许通过创建具有统一内容的大文件(我想这不如直接覆盖未使用的 LBA 的工具,但我不确定那会是什么或是否存在这样的工具)?

*我知道至少有一系列 SSD 确实发生过这种情况。这有些道理(也让我很担心,因为这种故障​​模式是无法检测到的,而且我不知道它有多罕见),但我不明白为什么小而频繁的写入比大而频繁的写入更容易发生这种情况。平均而言,更改的块/页面/任何东西的数量相同,所以重新映射行为不应该也等同吗?或者这是因为映射表的每个块都存储了多个 LBA 到页面的映射,所以批量写入也会让它们同时更改?

相关内容