F2FS源码分析系列文章
主目录
一、文件系统布局以及元数据结构
二、文件数据的存储以及读写
三、文件与目录的创建以及删除(未完成)
四、垃圾回收机制
五、数据恢复机制
- 数据恢复的原理以及方式
- 后滚恢复和Checkpoint的作用与实现
- 前滚恢复和Recovery的作用与实现(未完成)
六、重要数据结构或者函数的分析
F2FS文件系统的数据恢复
数据恢复的简介
F2FS数据恢复的核心结构是Checkpoint结构,它保存了很多元数据用于维护系统一致性。数据恢复方式有两种,分别是后滚恢复(Roll-Back Recovery),前滚恢复(Roll-Forward Recovery)。
Checkpoint的作用
从F2FS的磁盘布局可以了解到,F2FS有一个元数据区域,用于集中管理磁盘所有的block的信息,因此F2FS使用了检查点(checkpointing)机制去维护文件系统的恢复点(recovery point),这个恢复点用于在系统突然崩溃的时候,元数据区域依然能够正确地将数据重新读取出来。因此保证元数据区域的有效性以及恢复性。当F2FS需要通过 fsync
或 umount
等命令对系统进行同步的时候,F2FS会触发一次Checkpoint机制,它会完成以下的工作:
- 页缓存的脏node和dentry block会刷写回到磁盘;
- 挂起系统其他的写行为,如create,unlink,mkdir;
- 将系统的meta data,如NAT、SIT、SSA的数据写回磁盘;
- 更新checkpoint的状态,包括checkpoint的版本,NAT和SIT的bitmaps以及journals,SSA,Orphan inode
后滚恢复-Roll-Back Recovery
当遇到突然失去电源等情况,F2FS会回滚到最近的Checkpoint点中。为了保持一个稳定可用的Checkpoint(防止Chcekpoint在创建或者更新的时候宕机),F2FS维护了两个Checkpoint。如果一个Checkpoint在header和footer包含可以区分的内容,那么F2FS就会认为是可用的,可以使用这个Checkpoint,否则就会被丢弃掉。
与之相似,每一个Checkpoint都包含一份NAT bitmap和SIT bitmap,用于管理NAT Blocks和SIT Blocks。F2FS会选择其中一组Checkpoint数据进行更新,然后标记为最新。
如果有少量的NAT和SIT entries被频繁更新,可能会导致频繁大量的IO读写。因此F2FS在Checkpoint使用了SIT journals和NAT journals去缓存一些频繁更改。通过这种方式可以减少CP和读写的Overheads。
在F2FS进行挂载的时候,F2FS需要根据Headers和footers找到合适的可用的Checkpoint,如果两个Checkpoint都是可用的,那么F2FS会挑选version最新的Checkpoint进行恢复。在F2FS得到可用的Checkpoint之后,就会检查是否存在Orphan Inodes,如果找到了orphan inode,就会truncate它们的所有数据。然后,F2FS会根据SIT Blocks和NAT Blocks的bitmap恢复meata data和建立映射表。
前滚恢复-Roll-Forward Recovery(原理需要继续探究)
应用程序常常会调用fsync完成一些同步性的请求,为了满足这个同步性的请求,一个简单的方法是每次调用fsync都写一次Checkpoint。然而,由于Checkpoint需要同时写入大量与调用fsync的应用程序无关的node、 dentry block等数据,因此这是一个大开销的操作,会影响到手机的流畅性。
因此,F2FS使用了高效的前滚恢复方式以优化fsync的性能。核心的概念是只写入data block和direct node到磁盘,但是而不写入其他元数据。F2FS具体实现是在fsync操作完成之后,给每一个相关的direct node加上一个特殊的标记位。当系统后滚恢复到了一个稳定的Checkpoint后,F2FS会选择性地(通过标记位)通过前滚恢复恢复一些已经fsync到磁盘,但是没有被元数据索引的一些数据。
一个典型的场景是:当完成一次写操作后,需要更新node page和data block,然后执行fsync,node page以及data block在submit bio后就完成了数据写入磁盘。此时需要注意的是nat bitmap是在checkpoit的地方更新的,优化后的fsync,不会每一次fsync都会执行checkpoint。但是如果在checkpoint之前出现了宕机,虽然node page和data page本身已经写入了磁盘,但是丢失了nat bitmap,因此无法索引这些已经写入磁盘的node page和data page,这时就要利用前滚恢复机制,重新建立索引。
前滚恢复的原理如下:
假设上一次稳定的Checkpoint的日志位置是N
- F2FS收集了日志位置是N+n的,含有特殊标记位的direct node block,这些block之间组成一个list用于表示node information,其中n表示上一次稳定的Checkpoint之后写入了多少个block。
- 通过这个list中的node information,系统将距离上一次稳定的Checkpoint最靠近的被更新的node block(日志位置是N-n),载入到cache当中。
- 比较日志位置是N-n和N+n的数据是否一致,如果不一致则使用N+n的数据覆盖已经缓存的N-n的node block,然后标记为脏。
- 执行写Checkpoint流程,刷新元数据。