2025年【文件系统】 F2FS文件系统学习

【文件系统】 F2FS文件系统学习一 基本介绍 1 F2FS History F2FS Flash Friendly File System 是专门为 Nand Flash 设计的一个日志型文件系统 于 2012 年 12 月合入 Linux3 8 内核 Google 也在 2018 年 Android P 将其吸收到安卓原生版本中

大家好,我是讯享网,很高兴认识大家。

一、基本介绍

1、F2FS History

        F2FS(Flash Friendly File System)是专门为Nand Flash设计的一个日志型文件系统,于2012年12月合入Linux3.8内核,Google也在2018年(Android P)将其吸收到安卓原生版本中,使所有使用安卓的厂商受益

2、F2FS特点

        F2FS可以极大程度上避免碎片产生,相对于传统日志型文件系统,F2FS在wandering tree和gc方面,有一定的优化,可以复用离散的数据页写入数据,显著减少GC带来的卡顿

wandering tree:在文件更新时,指向文件的DIrect Pointer由于数据异地更新,也会随之更新 ,同时指向这个DIrect Pointer的Indirect Pointer也会更新,然后保存这个Indirect Pointer的inode、inode blockmap等结构也需要更新,这样会导致频繁的metadata更新

3、为什么需要F2FS

        Nand Flash在更新某个位置的值时,必须先擦除,才能写入新的内容,如果在频繁写入的场景,都需要消耗大量的时间进行擦除,导致整体性能下降。F2FS基于LFS型文件系统,解决了先擦后写的问题,当需要更新某个块时,会重新申请一个未使用的快,将数据写到新的块上,并更新相应的管理数据,这样就避免等待block擦除的开销,并且可以将随机写转化为顺序写,提升性能

        不仅仅是提升性能,对写放大也有所降低,这是因为如果按照先擦后写,就会导致某个块频繁被删除,导致写穿寿命到期,成为坏块,而F2FS使用append-only logging策略,按顺序写入数据,天然的在文件系统层做了磨损均衡,延长了设备使用寿命


讯享网

        此外,F2FS支持冷热Node/Data分流,将不经常变动的数据写入冷分区,将经常需要变动的数据写入到热分区,这样在器件回收数据块时,可以根据数据块的冷热进行选择,提高回收效率

二、F2FS 数据结构

1、F2FS Layout

        F2FS磁盘布局如下图所示,它考虑了闪存感知和低清理成本

闪存感知:指文件系统匹配闪存物理特性

        (a)superblock metadata放在一起,且是头部,提高局部性和并行性

        (b)main area起始地址对对齐zoned大小,考虑了FTL工作特性

        (c)以section为单位进行文件系统GC

低清理成本:使用Multi-Stream logging实现冷热数据分流

(a)F2FS将整个磁盘划分为若干segment,每个大小为2MB

(b)目前zone,section,segment都是1:1:1的关系,zone的大小与物理设备有关

(c)除superblock外,其他area都有多个segment

(d)1个segment包含512个block,1个block大小为4KB

 (1) SuperBlock

        该区域占一个segment(2MB),包含两个f2fs_super_block数据结构,每个占用4KB。

struct f2fs_super_block { __le32 magic; /* Magic Number */ __le16 major_ver; /* Major Version */ __le16 minor_ver; /* Minor Version */ __le32 log_sectorsize; /* log2 sector size in bytes */ __le32 log_sectors_per_block; /* log2 # of sectors per block */ __le32 log_blocksize; /* log2 block size in bytes */ __le32 log_blocks_per_seg; /* log2 # of blocks per segment */ __le32 segs_per_sec; /* # of segments per section */ __le32 secs_per_zone; /* # of sections per zone */ __le32 checksum_offset; /* checksum offset inside super block */ __le64 block_count; /* total # of user blocks */ __le32 section_count; /* total # of sections */ __le32 segment_count; /* total # of segments */ __le32 segment_count_ckpt; /* # of segments for checkpoint */ __le32 segment_count_sit; /* # of segments for SIT */ __le32 segment_count_nat; /* # of segments for NAT */ __le32 segment_count_ssa; /* # of segments for SSA */ __le32 segment_count_main; /* # of segments for main area */ __le32 segment0_blkaddr; /* start block address of segment 0 */ __le32 cp_blkaddr; /* start block address of checkpoint */ __le32 sit_blkaddr; /* start block address of SIT */ __le32 nat_blkaddr; /* start block address of NAT */ __le32 ssa_blkaddr; /* start block address of SSA */ __le32 main_blkaddr; /* start block address of main area */ __le32 root_ino; /* root inode number */ __le32 node_ino; /* node inode number */ __le32 meta_ino; /* meta inode number */ __u8 uuid[16]; /* 128-bit uuid for volume */ __le16 volume_name[MAX_VOLUME_NAME]; /* volume name */ __le32 extension_count; /* # of extensions below */ __u8 extension_list[F2FS_MAX_EXTENSION][F2FS_EXTENSION_LEN];/* extension array */ __le32 cp_payload; __u8 version[VERSION_LEN]; /* the kernel version */ __u8 init_version[VERSION_LEN]; /* the initial kernel version */ __le32 feature; /* defined features */ __u8 encryption_level; /* versioning level for encryption */ __u8 encrypt_pw_salt[16]; /* Salt used for string2key algorithm */ struct f2fs_device devs[MAX_DEVICES]; /* device list */ __le32 qf_ino[F2FS_MAX_QUOTAS]; /* quota inode numbers */ __u8 hot_ext_count; /* # of hot file extension */ __le16 s_encoding; /* Filename charset encoding */ __le16 s_encoding_flags; /* Filename charset encoding flags */ __u8 s_stop_reason[MAX_STOP_REASON]; /* stop checkpoint reason */ __u8 s_errors[MAX_F2FS_ERRORS]; /* reason of image corrupts */ __u8 reserved[258]; /* valid reserved region */ __le32 crc; /* checksum of superblock */ } __packed;

讯享网

        SuperBlock的内容在格式化时候就被确定,通常不会被修改,为了更好的适配VFS层,放在磁盘第一个扇区。它的主要作用是记录整个文件系统的分区信息,包括总的block的数量、已使用的block数量、各区的起始地址、F2FS的默认参数、支持的特性等。在F2FS挂载时,内存会创建一个f2fs_sb_info结构从superblock中读取相关数据。

        为了避免文件系统崩溃,它具有2个备份,如果#0损坏,则使用#1恢复,

 (2) CheckPoint

        该区域占2个segment(4MB),记录了上次卸载F2FS时刻,系统的block、node的分配状态,用于下次挂载F2FS时,恢复整个系统的block,node分配状态,主要作用就是为了保持数据一致性

讯享网struct f2fs_checkpoint { __le64 checkpoint_ver; /* checkpoint block version number */ __le64 user_block_count; /* # of user blocks */ __le64 valid_block_count; /* # of valid blocks in main area */ __le32 rsvd_segment_count; /* # of reserved segments for gc */ __le32 overprov_segment_count; /* # of overprovision segments */ __le32 free_segment_count; /* # of free segments in main area */ /* information of current node segments */ __le32 cur_node_segno[MAX_ACTIVE_NODE_LOGS]; __le16 cur_node_blkoff[MAX_ACTIVE_NODE_LOGS]; /* information of current data segments */ __le32 cur_data_segno[MAX_ACTIVE_DATA_LOGS]; __le16 cur_data_blkoff[MAX_ACTIVE_DATA_LOGS]; __le32 ckpt_flags; /* Flags : umount and journal_present */ __le32 cp_pack_total_block_count; /* total # of one cp pack */ __le32 cp_pack_start_sum; /* start block number of data summary */ __le32 valid_node_count; /* Total number of valid nodes */ __le32 valid_inode_count; /* Total number of valid inodes */ __le32 next_free_nid; /* Next free node number */ __le32 sit_ver_bitmap_bytesize; /* Default value 64 */ __le32 nat_ver_bitmap_bytesize; /* Default value 256 */ __le32 checksum_offset; /* checksum offset inside cp block */ __le64 elapsed_time; /* mounted time */ /* allocation type of current segment */ unsigned char alloc_type[MAX_ACTIVE_LOGS]; /* SIT and NAT version bitmap */ unsigned char sit_nat_version_bitmap[]; } __packed;

        在运行中,F2FS会定期将当前分配状态写入CheckPoint区域,采用“乒乓操作”,如上次写入的是cp#0,下次就会写入cp#1,在此数据结构中有一个checkpoint_ver用来记录版本,如果两个cp都能用,则会选择最新的那个

        CheckPoint一般只在F2FS启动时候被读取,用于数据恢复,在运行过程中大部分都是被写,用于记录恢复信息。当F2FS需要通过fsync或umount等命令对系统同步时,F2FS会触发一次CheckPoint机制,主要完成以下工作

a.页缓存的脏node和dentry block会刷写回到磁盘; b.挂起系统其他的写行为,如create,unlink,mkdir; c.将系统的meta data,如NAT、SIT、SSA的数据写回磁盘; d.更新checkpoint的状态,包括checkpoint的版本,NAT和SIT的bitmaps以及journals,SSA,Orphan inode
 (3) SIT

        SIT(Segment Information Table)区域记录了Main area中各个segment的详细信息,例如该segment中Valid 以及修改时间等,配合GC流程的选择策略,它的大小由Main Area所占用的segment数量确定的

讯享网struct f2fs_sm_info { struct sit_info *sit_info; /* whole segment information */ struct free_segmap_info *free_info; /* free segment information */ struct dirty_seglist_info *dirty_info; /* dirty segment information */ struct curseg_info *curseg_array; /* active segment information */ struct f2fs_rwsem curseg_lock; /* for preventing curseg change */ block_t seg0_blkaddr; /* block address of 0'th segment */ block_t main_blkaddr; /* start block address of main area */ block_t ssa_blkaddr; /* start block address of SSA area */ unsigned int segment_count; /* total # of segments */ unsigned int main_segments; /* # of segments in main area */ unsigned int reserved_segments; /* # of reserved segments */ unsigned int additional_reserved_segments;/* reserved segs for IO align feature */ unsigned int ovp_segments; /* # of overprovision segments */ /* a threshold to reclaim prefree segments */ unsigned int rec_prefree_segments; struct list_head sit_entry_set; /* sit entry set list */ unsigned int ipu_policy; /* in-place-update policy */ unsigned int min_ipu_util; /* in-place-update threshold */ unsigned int min_fsync_blocks; /* threshold for fsync */ unsigned int min_seq_blocks; /* threshold for sequential blocks */ unsigned int min_hot_blocks; /* threshold for hot block allocation */ unsigned int min_ssr_sections; /* threshold to trigger SSR allocation */ /* for flush command control */ struct flush_cmd_control *fcc_info; /* for discard command control */ struct discard_cmd_control *dcc_info; };
 (4) NAT

        NAT(Segment Information Table)区域记录了node id 与真实地址的关系,其本质是一个中间层,通过该区域,可以避免索引地址,而是索引id号(每个node都有一个nid),NAT的主要作用就是将nid翻译成Main Area中的地址信息,之前的wandering tree问题也是利用了这个区域解决的

        在传统的 LFS中,由于使用直接地址索引,当某个数据块被修改后,导致该数据块的管理块递归修改。例如,在A1 -> B1 -> C1 ->D1的索引树中

a.当D1被修改后,会写入新地址D2 b.而C1索引的是D1的地址,此时该地址是invalid的,所以需要更新C1中存储的值,写入C2 c.以此类推,直到A1被写入A2快中,这就是滚雪球效应,修改一个数据引起连锁反应 A1、B1、C1---管理快 D1---数据块

        引起此问题的根因是采用直接地址作为索引,F2FS解决该问题的思路是引入一个中间层,即NAT表,负责做地址翻译,避免直接索引地址

讯享网a.A1中存储B1的id号,B1存储C1的id号 b.C1直接索引D1的地址 c.当D1被修改后,只需要修改C1和NAT表中C1的地址索引即可(NAT表是inplace更新,先擦后写) d.由于C1的id号保持不变,所以A1和B1都不需要修改 

struct f2fs_nm_info { block_t nat_blkaddr; /* base disk address of NAT */ nid_t max_nid; /* maximum possible node ids */ nid_t available_nids; /* # of available node ids */ nid_t next_scan_nid; /* the next nid to be scanned */ nid_t max_rf_node_blocks; /* max # of nodes for recovery */ unsigned int ram_thresh; /* control the memory footprint */ unsigned int ra_nid_pages; /* # of nid pages to be readaheaded */ unsigned int dirty_nats_ratio; /* control dirty nats ratio threshold */ /* NAT cache management */ struct radix_tree_root nat_root;/* root of the nat entry cache */ struct radix_tree_root nat_set_root;/* root of the nat set cache */ struct f2fs_rwsem nat_tree_lock; /* protect nat entry tree */ struct list_head nat_entries; /* cached nat entry list (clean) */ spinlock_t nat_list_lock; /* protect clean nat entry list */ unsigned int nat_cnt[MAX_NAT_STATE]; /* the # of cached nat entries */ unsigned int nat_blocks; /* # of nat blocks */ /* free node ids management */ struct radix_tree_root free_nid_root;/* root of the free_nid cache */ struct list_head free_nid_list; /* list for free nids excluding preallocated nids */ unsigned int nid_cnt[MAX_NID_STATE]; /* the number of free node id */ spinlock_t nid_list_lock; /* protect nid lists ops */ struct mutex build_lock; /* lock for build free nids */ unsigned char free_nid_bitmap; unsigned char *nat_block_bitmap; unsigned short *free_nid_count; /* free nid count of NAT block */ /* for checkpoint */ char *nat_bitmap; /* NAT bitmap pointer */ unsigned int nat_bits_blocks; /* # of nat bits blocks */ unsigned char *nat_bits; /* NAT bits blocks */ unsigned char *full_nat_bits; /* full NAT pages */ unsigned char *empty_nat_bits; /* empty NAT pages */ #ifdef CONFIG_F2FS_CHECK_FS char *nat_bitmap_mir; /* NAT bitmap mirror */ #endif int bitmap_size; /* bitmap size */ };
 (5) SSA

        SSA(Segment Summary Area)区域主要保存了journal(SIT/NAT临时的修改信息)以及summary(记录逻辑地址和物理地址关系的结构),这个区域主要用于反向索引, 记录了block所属的node信息

讯享网/* 4KB-sized summary block structure */ struct f2fs_summary_block { struct f2fs_summary entries[ENTRIES_IN_SUM]; struct f2fs_journal journal; struct summary_footer footer; } __packed; 
 (6) Main Area

        在Main Area中的一个Segment,要么存储的是Node数据,要么存储的是data数据,不能既存node又存data

【参考博客】

[1] [论文阅读] F2FS: A New Filesystem for Flash Storage | Caturra's Blog 

[2]  f2fs文件系统(一)总体介绍 - 知乎

小讯
上一篇 2025-02-27 13:05
下一篇 2025-02-16 20:56

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/127412.html