目录
1.前言
本文采用F2FS初始版本为例说明F2FS的文件系统布局,并通过f2fs-tools来探究如何通过文件的inode号来获取文件的内容。
采用如下的方法制作f2fs镜像,大小为128M
dd if=/dev/zero of=f2fs.img bs=4k count=32768
分别创建了如下几个文件
ubuntu@VM-0-9-ubuntu:/mnt$ ls -i
5 a.c 6 b.jpg 7 c.txt 4 fstab
版本号:
F2FS: 上传kernel3.7主线内核的初始版本(包含前16个patch)
F2FS-tools: mkfs.f2fs Ver: 1.1.0 (2013-10-17)
2.F2FS布局说明
如上为f2fs文件系统总体布局图。
2.1. super block(block 0x0 ~ block 0x1ff)
super block主要定义segment, sector, block的大小及数目,以及各个区域(CP, SIT, NAT, SSA,MAIN)的偏移地址和大小, 同时定义了root inode
super block偏移为0x400 (1024),也就是从0x400的位置开始存放1st super block的内容,从0x1400开始存放2nd super block的内容
如下为所制作的f2fs.img镜像super block各成员变量的打印:
- magic:0xf2f52010
- major_ver:0x1
- minor_ver:0x1
- log_sectorsize:0x9
每个sector大小为512B,sector相当于闪存flash中一个page的大小 - log_sectors_per_block:0x3
每个block有8个sector - log_blocksize:0xc(12)
每个block的大小为4k, block相当于闪存flash中一个block的大小 - log_blocks_per_seg:0x9
每个segment的有512个block - segs_per_sec:0x1
- secs_per_zone:0x1
- checksum_offset:0x0
- block_count:32768
也就是32K个block,每个blck为4k, 一共是128M
通过制作的镜像大小为128M, 也就是0x7FFFFFF个字节,与此处的block_count完全吻合,说明f2fs对block_count的统计不仅包含了main area,还包含了元数据部分 - section_count:0x38(56)
统计section的数目,只包含main区域,为56 * 512个block, 每个block大小为4k
因此大小为112M,而镜像为128M,说明有一部分是没有统计进section count的,之所以比segment count的数目少7个segment,是因为没有统计cp,sit,nat,ssa,而只统计了main area区域 - segment_count:0x3f(63)
统计secment的数目,没有统计sb区域,为63 * 512个block, 每个block大小为4K
因此大小为126M,而镜像为128M,与镜像大小相差2M,,说明有一个segment没有统计进segment count的, 从下面的cp_blkaddr为0x200可以得出相差的这1个segment正是superblock的大小. 与 section_count的统计数相比多了7个segment,这7个segment分别是如下的cp, sit, nat, ssa所占用的segment,说明segment count统计时连这些区域也统计进入了 - segment_count_ckpt:2
checkpoint占用2个segment - segment_count_sit:2
sit占用了两个segment - segment_count_nat:2
nat占用了两个segment - segment_count_ssa:1
ssa占用了1个segment - segment_count_main:0x38(56)
main area的segment数目 - segment0_blkaddr:0x200
第一个segment的地址,第一个segment为CP区域的第一个segment - cp_blkaddr:0x200
cp区域的第一个block的地址,从这里可以看出super block占用了1个segment,也就是512个block, 5124k1024=0x200000 - sit_blkaddr:0x600
- nat_blkaddr:0xa00
- ssa_blkaddr:0xe00
- main_blkaddr:0x1000
- root_ino:3
- node_ino:1
- meta_ino:2
- uuid:
- volume_name:
- extension_count:0x17
2.2 CP(block 0x200 ~ block 0x5ff)
如上为cp block的总体布局,分为两种:nomal mode和compact mode.通过镜像可知,本文创建的镜像的CP为compact mode
ckpt_flags的值是5,通过ckpt_flags & CP_COMPACT_SUM_FLAG的值也可以知道,它就是compact mode.
cp区域主要包含两个cp pack,每个cp pack占据一个segment。
cp page1
如上即为第一个cp page1,相关打印如下,主要描述了main area的可用的block总数,有效block数目,over provision segment预留数目,以及其它的cp元数据总体信息。
===information of raw checkpoint=
-
checkpoint_ver:66
-
user_block_count:4096
4096/512=8个segment,而main area有56个segment,其它48个segment为overprovision segment -
valid_block_count:6
-
rsvd_segment_count:0x30(48)
保留了48个segment -
overprov_segment_count:0x30(48)
-
free_segment_count:0x32(50)
-
----cur_node_segno----
0x00000037
0x00000036
0x00000035 -
----cur_node_blkoff----
0x00000006
0x0000000C
0x00000000 -
----cur_data_segno----
0x00000034
0x00000001
0x00000000| -
----cur_data_blkoff----
0x00000005
0x00000003
0x00000001 -
ckpt_flags:0x5
-
cp_pack_total_block_count:0x6
-
cp_pack_start_sum:0x1
-
valid_node_count:0x5
-
valid_inode_count:0x5
-
next_free_nid:0x8
-
sit_ver_bitmap_bytesize:0x40
-
nat_ver_bitmap_bytesize:0x40
-
checksum_offset:0xffc
-
elapsed_time:40
-
allocation type of current segment
0x00000000|0x00000000|0x00000000|0x00000000|0x00000000|0x00000000|0x00000000|
0x00000000|0x00000000|0x00000000|0x00000000|0x00000000|0x00000000|0x00000000|
0x00000000|0x00000000| -
sit_nat_version_bitmap:0x0
nat journal
主要保存了每个文件的node address table entry
如上为cp的nat journal区域,主要保存了每个文件的nat entry,nat entry的结构如下所示:
struct nat_journal_entry {
__le32 nid;
struct f2fs_nat_entry ne;
} __packed;
struct f2fs_nat_entry {
__u8 version; /* latest version of cached nat entry */
__le32 ino; /* inode number */
__le32 block_addr; /* block address */
} __packed;
可以看到创建的a.c,b.jpg, c.txt,fstab几个文件的nat entry信息就位于此区域,而没有位于NAT区。
ubuntu@VM-0-9-ubuntu:~/qemu/rootfs$dump.f2fs -n 0~-1 f2fs.img
ubuntu@VM-0-9-ubuntu:~/qemu/rootfs$ cat dump_nat
nid: 3 ino: 3 offset: 0 blkaddr: 32261 pack:1
nid: 4 ino: 4 offset: 0 blkaddr: 31751 pack:1
nid: 5 ino: 5 offset: 0 blkaddr: 31753 pack:1
nid: 6 ino: 6 offset: 0 blkaddr: 31754 pack:1
nid: 7 ino: 7 offset: 0 blkaddr: 31755 pack:1
sit journal
保存了每个segment
如上为cp的sit journal区域, sit entry的结构如下:
struct sit_journal_entry {
__le32 segno;
struct f2fs_sit_entry se;
} __packed;
struct f2fs_sit_entry {
__le16 vblocks; /* reference above */
__u8 valid_map[SIT_VBLOCK_MAP_SIZE]; /* bitmap for valid blocks */
__le64 mtime; /* segment age for cleaning */
} __packed;
data summary
见第二个checkpoint的data summary
current hot node summary
current warm node summary
current cold node summary
cp page2
2nd checkpoint
data summary主要描述了current data segment 的每一个block, 相关数据结构如下:
/* a summary entry for a 4KB-sized block in a segment */
struct f2fs_summary {
__le32 nid; /* parent node id */
union {
__u8 reserved[3];
struct {
__u8 version; /* node version number */
/* 所描述的data block地址位于node block的索引 */
__le16 ofs_in_node; /* block index in parent node */
} __packed;
};
} __packed;
2.3 SIT(block 0x600 ~ block 0x9ff)
struct f2fs_sit_entry {
__le16 vblocks; /* reference above */
__u8 valid_map[SIT_VBLOCK_MAP_SIZE]; /* bitmap for valid blocks */
__le64 mtime; /* segment age for cleaning */
} __packed;
ubuntu@VM-0-9-ubuntu:~/qemu/rootfs$ cat dump_sit
segment_type(0:HD, 1:WD, 2:CD, 3:HN, 4:WN, 5:CN)
segno: 0 vblocks: 1 seg_type:2 sit_pack:2
80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
segno: 1 vblocks: 3 seg_type:1 sit_pack:2
e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
segno: 2 vblocks: 0 seg_type:0 sit_pack:2
segno: 3 vblocks: 0 seg_type:0 sit_pack:2
segno: 4 vblocks: 0 seg_type:0 sit_pack:2
segno: 5 vblocks: 0 seg_type:0 sit_pack:2
segno: 6 vblocks: 0 seg_type:0 sit_pack:2
segno: 7 vblocks: 0 seg_type:0 sit_pack:2
segno: 8 vblocks: 0 seg_type:0 sit_pack:2
segno: 9 vblocks: 0 seg_type:0 sit_pack:2
segno: 10 vblocks: 0 seg_type:0 sit_pack:2
segno: 11 vblocks: 0 seg_type:0 sit_pack:2
segno: 12 vblocks: 0 seg_type:0 sit_pack:2
segno: 13 vblocks: 0 seg_type:0 sit_pack:2
segno: 14 vblocks: 0 seg_type:0 sit_pack:2
segno: 15 vblocks: 0 seg_type:0 sit_pack:2
segno: 16 vblocks: 0 seg_type:0 sit_pack:2
segno: 17 vblocks: 0 seg_type:0 sit_pack:2
segno: 18 vblocks: 0 seg_type:0 sit_pack:2
segno: 19 vblocks: 0 seg_type:0 sit_pack:2
segno: 20 vblocks: 0 seg_type:0 sit_pack:2
segno: 21 vblocks: 0 seg_type:0 sit_pack:2
segno: 22 vblocks: 0 seg_type:0 sit_pack:2
segno: 23 vblocks: 0 seg_type:0 sit_pack:2
segno: 24 vblocks: 0 seg_type:0 sit_pack:2
segno: 25 vblocks: 0 seg_type:0 sit_pack:2
segno: 26 vblocks: 0 seg_type:0 sit_pack:2
segno: 27 vblocks: 0 seg_type:0 sit_pack:2
segno: 28 vblocks: 0 seg_type:0 sit_pack:2
segno: 29 vblocks: 0 seg_type:0 sit_pack:2
segno: 30 vblocks: 0 seg_type:0 sit_pack:2
segno: 31 vblocks: 0 seg_type:0 sit_pack:2
segno: 32 vblocks: 0 seg_type:0 sit_pack:2
segno: 33 vblocks: 0 seg_type:0 sit_pack:2
segno: 34 vblocks: 0 seg_type:0 sit_pack:2
segno: 35 vblocks: 0 seg_type:0 sit_pack:2
segno: 36 vblocks: 0 seg_type:0 sit_pack:2
segno: 37 vblocks: 0 seg_type:0 sit_pack:2
segno: 38 vblocks: 0 seg_type:0 sit_pack:2
segno: 39 vblocks: 0 seg_type:0 sit_pack:2
segno: 40 vblocks: 0 seg_type:0 sit_pack:2
segno: 41 vblocks: 0 seg_type:0 sit_pack:2
segno: 42 vblocks: 0 seg_type:0 sit_pack:2
segno: 43 vblocks: 0 seg_type:0 sit_pack:2
segno: 44 vblocks: 0 seg_type:0 sit_pack:2
segno: 45 vblocks: 0 seg_type:0 sit_pack:2
segno: 46 vblocks: 0 seg_type:0 sit_pack:2
segno: 47 vblocks: 0 seg_type:0 sit_pack:2
segno: 48 vblocks: 0 seg_type:0 sit_pack:2
segno: 49 vblocks: 0 seg_type:0 sit_pack:2
segno: 50 vblocks: 0 seg_type:0 sit_pack:2
segno: 51 vblocks: 0 seg_type:0 sit_pack:2
segno: 52 vblocks: 1 seg_type:0 sit_pack:2
08 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
segno: 53 vblocks: 0 seg_type:5 sit_pack:2
segno: 54 vblocks: 4 seg_type:4 sit_pack:2
01 70 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
segno: 55 vblocks: 1 seg_type:3 sit_pack:2
04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
valid_blocks:[0xa] valid_segs:5 free_segs:51
2.4 NAT(block 0xa00~0xdff)
struct f2fs_nat_entry {
__u8 version; /* latest version of cached nat entry */
__le32 ino; /* inode number */
__le32 block_addr; /* block address */
} __packed;
2.5 SSA(block 0xe00 ~ block 0xfff)
ubuntu@VM-0-9-ubuntu:~/test$ dump.f2fs -a 0~-1 f2fs.img
ubuntu@VM-0-9-ubuntu:~/test$ cat dump_ssa
可以打印出每个segment中每个block所属的node id
2.6 main area(block 0x1000 ~)
data block
node block
以fstab文件的node 4为例
从下面的inode信息中可以看出1122的ino号对应的i_addr为0x1000~0x100a,正是上面的内容
3. 调试
3.1 查看文件的inode号
ubuntu@VM-0-9-ubuntu:/mnt$ ls -i
5 a.c 6 b.jpg 7 c.txt 4 fstab
以fstab为例,如何找到它的inode号?
由superblock的如下打印信息:
root_ino:3
node_ino:1
meta_ino:2
可知root目录的inode号为3,通过CP的nat journal区可知其位于node block的块号为0x7e05(32261)
找到0x7e05的root node block,找到其i_addr[0]
其中存储的就是root目录的data block块号0x7804
通过相应的hash算法就可以查到文件名fstab对应的inode号为4
3.2 根据文件的inode号找到文件的data块
通过3.1可以找到文件名对应的inode号4,然后通过查CP的nat journal区域可以知道其位于node block块号为0x7c07
继续查看node block0x7c07, 找到i_addr[0],其中存储的就是data block块号
0x1200块号的内容为:
3.3 查看inode状态
以ino=4(fstab)为例,通过如下命令可以查看inode的状态
ubuntu@VM-0-9-ubuntu:~/qemu/rootfs$ sudo dump.f2fs -i 4 f2fs.img
Info: Segments per section = 1
Info: Sections per zone = 1
Info: sector size = 512
Info: total sectors = 262144 (128 MB)
Info: MKFS version
""
Info: FSCK version
from "Linux version 4.15.0-88-generic (buildd@lgw01-amd64-036) (gcc version 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04.1)) #88-Ubuntu SMP Tue Feb 11 20:11:34 UTC 2020"
to "Linux version 4.15.0-88-generic (buildd@lgw01-amd64-036) (gcc version 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04.1)) #88-Ubuntu SMP Tue Feb 11 20:11:34 UTC 2020"
Info: superblock features = 0 :
Info: superblock encrypt level = 0, salt = 00000000000000000000000000000000
Info: total FS sectors = 262144 (128 MB)
Info: CKPT version = 3
[print_node_info: 276] Node ID [0x4:4] is inode
i_mode [0x 81a4 : 33188]
i_advise [0x 0 : 0]
i_uid [0x 0 : 0]
i_gid [0x 0 : 0]
i_links [0x 1 : 1]
i_size [0x 127 : 295]
i_blocks [0x 2 : 2]
i_atime [0x5efc3b84 : 1593588612]
i_atime_nsec [0x 1312d00 : 20000000]
i_ctime [0x5efc3b84 : 1593588612]
i_ctime_nsec [0x 2625a00 : 40000000]
i_mtime [0x5efc3b84 : 1593588612]
i_mtime_nsec [0x 2625a00 : 40000000]
i_generation [0xb5863313 : 3045470995]
i_current_depth [0x 1 : 1]
i_xattr_nid [0x 0 : 0]
i_flags [0x 0 : 0]
i_inline [0x 0 : 0]
i_pino [0x 3 : 3]
i_dir_level [0x 0 : 0]
i_namelen [0x 5 : 5]
i_name [fstab]
i_ext: fofs:0 blkaddr:1200 len:1
i_addr[ofs] [0x 1200 : 4608]
i_addr[ofs + 1] [0x 0 : 0]
i_addr[ofs + 2] [0x 0 : 0]
i_addr[ofs + 3] [0x 0 : 0]
i_nid[0] [0x 0 : 0]
i_nid[1] [0x 0 : 0]
i_nid[2] [0x 0 : 0]
i_nid[3] [0x 0 : 0]
i_nid[4] [0x 0 : 0]
Do you want to dump this file into ./lost_found/? [Y/N] Y
Info: checkpoint state = 5 : compacted_summary unmount
Done.
Do you want to dump this file into ./lost_found/? [Y/N]提示是否dump这个文件,选择Y会在./lost_found目录看到这个文件的内容
4的ino号对应的i_addr为0x1200,正是上面fstab文件的内容,通过
dump.f2fs -b 0x1200 f2fs.img 可以查看,直接查看镜像的0x1200块号也可以查看到
3.4 查看block
查看上节中的fstab的0x1200的 block
ubuntu@VM-0-9-ubuntu:~/qemu/rootfs$ sudo dump.f2fs -b 0x1200 f2fs.img
== Dump data from block address ==
FS Userdata Area: Data block from 0x1200
- Direct node block : id = 0x4 from 0x7c07
- Inode block : id = 0x4 from 0x7c07
- File name : fstab
- File size : 295 (bytes)
- Data offset : 0x0 (4KB), 0 (bytes)
Info: checkpoint state = 5 : compacted_summary unmount
Done.
查看0x1200 block的信息,可以看到它就是fstab的信息
参考文档
- https://blog.csdn.net/frank_zyp/article/details/96474245
F2FS文件系统二 实验分析f2fs文件系统 - https://blog.csdn.net/u011649400/article/details/94588971?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522159339311919195239862414%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=159339311919195239862414&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduend~default-3-94588971.ecpm_v1_rank_business_v1&utm_term=f2fs+checkpoint
F2FS源码分析-1.3 [F2FS 元数据布局部分] Checkpoint结构
附录