F2FS是三星专为NAND Flash存储设备设计的一个linux文件系统。
1. 基于LFS(Log-structured File System)类型,使用copy-on-write策略直接写到新的数据块(异地更新),避免等待block擦除的开销,解决了需要先擦后写的问题;
2. append-only的日志写策略,将随机写转化成顺序写,极大的提升了随机写的性能。同时也相当于在文件系统层天然做了磨损均衡,避免对某个块频繁擦除导致被“写穿”。
设备使用率较高场景下,寻找可用日志时间较长,转成threaded logging策略。
3. LFS维护一个大的日志区域,F2FS则根据冷热数据的访问差异,维护了6个日志区域,
- NODE HOT 区域:目录的NODE结构,因为切换目录等操作都会频繁使用到。
- NODE WARM区域:一般文件的NODE结构,需要对文件读写才会使用到,因此不像目录的NODE结构使用频繁。
- NODE COLD区域:间接寻址的NODE,对于非常大的文件,会通过间接寻址才能找到数据所在的区域,但是一般而言很少有超级大的文件,因此访问最不频繁。
- DATA HOT 区域:目录的DATA结构,因为切换目录等操作都会频繁使用到,需要从DATA读取文件名等信息。
- DATA WARM 区域:一般文件数据,正常的IO产生的DATA都属于这一类型。
- DATA COLD 区域:不频繁修改的数据。多媒体(多为只读文件),搬移数据块(如GC产生读写的数据,gc会挑热度最低的数据),或者用户指定的只读文件。
冷热数据分离同步写入,根据数据的“age”进行选择或者最小开销原则,提高回收效率;
4. 借鉴数据库Checkpoint的实现,前滚和后滚恢复保证一致性。
系统需要保证一致性时(例如:sync操作),则会触发一次写Checkpoint,会将当前的系统状态(主要是管理数据)完整写入到Checkpoint区域。在发生意外掉电时,f2fs会根据最新的Checkpoint内容来还原系统状态,这个流程就是后滚恢复。
前滚恢复,在写入普通文件时,很多时候只需要对特定文件进行一致性操作,而系统中的其他数据则不关注,如果每次都写入一次Checkpoint,未免太过耗时。所以在写入普通文件时,只需要确保该文件的管理数据落盘即可,并通过特殊的标记,记录其状态,在恢复流程中,根据写入的数据可以恢复到掉电前的状态。
分为为了互为备份,如果本次写入的是CP #0,那么下次写入的是CP #1。每次写CP的时候都带有一个版本号,表示第几次写CP。在后滚恢复流程中,首先判断哪个CP可用,如果两个都可用,则根据版本号选择最新的那个。
在写CP的时候,需要先写入f2fs_checkpoint结构体,然后写入其他内容,最后保证前面内容都写入后,再写入一个f2fs_checkpoint结构体,这样的目的是为了可以判断该CP是否可用。如果两个f2fs_checkpoint结构体内容对不上(主要是版本号),则表示该CP损坏,不能用来恢复数据。
5. 解决雪崩问题(LFS异地更新的引发直接或间接node以及inode和inode map的一系列修改)
由于使用直接地址为索引,A1 -> B1 -> C1 ->D1的索引树中,数据块D1被修改后,由于COW的策略,新数据会写入到新地址D2。C1中对应的地址改成D2也会形成C2。A1、B1、C1管理块递归修改。
f2fs -- NAT表负责做地址翻译,避免直接索引地址。A1中存的是B1的id号,同样B1索引的是C1的id号,只有C1直接索引D1的地址,所以当D1被修改后,只需要额外修改C1的和NAT表中C1的地址索引(注:NAT表的修改是就地更新,也就是先擦除后写入),由于C1的id号保持不变,所以A1、B1的内容保持不变,这样就减少了因连锁反应引起的修改。
F2FS根据存储介质划分为6个区域,前5个区域称为元数据区域用来维持F2FS的一致性,而最后是保存数据的主要区域。
Node只支持OPU(outplace update,异地