1. 前言

本文主要从总体的角度来了解f2fs,尝试回答下面的几个问题来靠近它,这几个问题包括:

  • f2fs是什么?
  • 为何引入f2fs?
  • f2fs如何工作?

2. f2fs是什么?

F2FS (Flash Friendly File System) 是专门针对SSD、eMMC、UFS等闪存设备设计的文件系统。基于LFS,同时解决了LFS的一些问题。由三星工程师Jaegeuk Kim于2012年10月发布到Linux社区,并于2012年12月进入Linux 3.8 内核主线,初始 版本包含22个patch。初始版本kernel 3.8(2012年)的代码量为1万多行,22个提交,截止到kernel 5.8-rc2(2020年)的代码量为4万多行,2899个提交。

3. LFS特点

Android f2fs 掉电 安卓f2fs_Android f2fs 掉电

Android f2fs 掉电 安卓f2fs_f2fs_02


LFS最大的特点是以日志的形式将对文件的修改顺序写入磁盘,化随机写入为顺序写入,如上创建文件file1,file2,创建目录dir1,dir2,对于FFS会有10次的随机写入,而对于LFS将以日志的方式一次从内存中写入, 同时也要写入inode map,inode map记录了每个inode所在的block地址,索引为inode号,inode map所在的block地址被记录在F2FS的CP区域。

Flash memory的特点
(1)Out-place 更新 (非in-place更新)
(2)随机写入会增加GC垃圾回收开销
(3)顺序写入速率高于随机写入速率
LFS的特点
(1)Out-place更新
(2)大量的采用顺序写入
因此LFS对Flash memory是友好的文件系统 ,而f2fs基于LFS,因此也是对flash友好的文件系统

LFS的不足:
(1)针对HDD进行优化的文件系统布局
(2)仍然存在Wandering Tree(雪崩)问题
(3)没有进行冷热数据分离
(4)磁盘高利用率的情况下垃圾回收成本高

4. f2fs解决了哪些问题?

采用falsh友好的文件系统布局

Android f2fs 掉电 安卓f2fs_NAT_03


Android f2fs 掉电 安卓f2fs_Android f2fs 掉电_04


Android f2fs 掉电 安卓f2fs_f2fs_05

解决了Wandering Tree(雪崩)问题

Android f2fs 掉电 安卓f2fs_数据_06


传统的LFS索引结构,由于异地更新在修改文件数据时会引发直接或间接node以及inode和inode map的一系列修改,称为wandering tree问题

Android f2fs 掉电 安卓f2fs_文件系统_07


F2FS索引结构,通过引入NAT,保存所有node的信息,间接node不再指向直接node,而是指向NAT区,解决了wandering tree问题

使用Multi-head log,同时将冷热数据分离

Android f2fs 掉电 安卓f2fs_NAT_08


main area分为node block和data block

将node block和data block进行冷热分离

有效减少GC cost

Android f2fs 掉电 安卓f2fs_文件系统_09


node block与data block分离, 冷热数据分离,将不同数据存放到不同的zone中,有利于FTL进行GC垃圾回收,如上图,假设zone对应flash中的一个block,则zone-aware allocation可以做到冷热数据分配到不同的zone,也就分配到不同的flash block中

采用自适应的log方式

Android f2fs 掉电 安卓f2fs_NAT_10

  • Normal logging
    追加式logging,只会向clean segment写入
    如果没有空闲空间,需要执行GC操作
    GC操作会带来随机读和顺序写开销
  • Thread logging
    向dirty的segment写入
    不需要GC操作
    会引起随机写入
  • Normal logging与thread logging的切换
    当空闲空间低于阀值(e.g.k=5% )将采用thread logging,否则采用normal logging

5. f2fs是如何工作的?

f2fs文件读取(/File)

  • Setp 1首先通过superblock获取root inode号(==nid,假设为3),通过NAT获取root inode所在的node block地址
  • Setp 2 通过root inode找到root目录的data block地址
  • Setp 3 通过文件名File遍历每一个entry,找到File对应的inode号,通过inode号(==nid)查NAT
  • Setp 4 通过NAT找到File的inode所在的node block地址,它存储了File的direct node的nid(假设为7)

Android f2fs 掉电 安卓f2fs_f2fs_11

  • Setp 5 通过file的inode找到direct node的nid(假设为7),通过查找NAT,找到direct node的node block地址
  • Setp 6 File的direct node中保存着File的data block的地址,根据这些data block地址就可以读取到File的数据

F2FS GC垃圾回收

  • GC回收分为foreground gc和background gc
    当没有足够空闲的segment(一般是小于reserved segments)时将启动foreground gc
    当系统没有进行IO操作时,将启动background gc thread,回收的时间间隔会根据invalid blocks的多少进行调整
    foreground gc采用greedy算法,只考虑dirty invalid blocks数目; background gc采用cost-benefit算法,还考虑了segment的修改时间
  • Cost-benefit算法
    cost_benefit = (1 - u) / 2u * age
    u: 表示valid block在该section中的比例
    1-u: 表示对这个section进行gc后的收益
    2u: 表示对这个section的GC的开销,读取Valid block(1个u)然后写入到到新的segment(再1个u)
    age: 表示上一次修改距离现在的时间差
    NOTE:cost_benefit值越大表示越值得回收

F2FS checkpoint

Checkpoint执行的操作:

  1. 将page cache中的dirty node和dentry block flush到磁盘;
  2. Suspend冻结文件系统操作,如create,unlink,mkdir等
  3. 文件系统元数据NAT, SIT, SSA写入磁盘各自区域;
  4. 写checkpont pack部分,主要包括:
    Header和footer checkpoint page;
    NAT bitmap和SIT bitmap
    NAT journal和SIT journal
    Active segments的summary blocks
    Orphan blocks

F2FS recovery

Android f2fs 掉电 安卓f2fs_NAT_12


step 1 创建dir1, file1, file2

Android f2fs 掉电 安卓f2fs_Android f2fs 掉电_13


step 2 触发checkpoint,此时数据与元数据保持一致性状态

Android f2fs 掉电 安卓f2fs_Android f2fs 掉电_14


step 3 更新file2, 并将记录file2更新数据块号的new file2 node作fsync mark标记

Android f2fs 掉电 安卓f2fs_Android f2fs 掉电_15


step 4 此时更新的new file2后并没有执行checkpoint,发生了断电,数据和元数据不一致

Android f2fs 掉电 安卓f2fs_Android f2fs 掉电_16


step 5 执行修复,首先通过roll-back,找到最新的稳定的checkpoint pack版本

Android f2fs 掉电 安卓f2fs_Android f2fs 掉电_17


step 6 比较file2 node和new file2 node中所记录的data block块号是否相等,如果不相等将执行roll-forward恢复

Android f2fs 掉电 安卓f2fs_数据_18


step 6 执行新的checkpoint

参考文档

Lee et. al, F2FS: A New File System for Flash Storage, FAST ’15
Linux/Document/filesystems/f2fs.txt
F2FS技术拆解
F2FS源码分析-1.3 [F2FS 元数据布局部分] Checkpoint结构
f2fs系列文章——sit/nat_version_bitmap
http://www.ssdfans.com/?p=5135 greedy和cost-and-benefit
https://github.com/jasonactions/f2fs-initial f2fs初始版本注释