f2fs学习笔记 - 3. F2FS文件系统布局

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的信息

参考文档

  1. https://blog.csdn.net/frank_zyp/article/details/96474245
    F2FS文件系统二 实验分析f2fs文件系统
  2. 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结构
    附录
  • 5
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
f2fs文件系统调用主要涉及以下几个组件和函数: 1. 文件系统类型定义:在f2fs文件系统中,通过定义一个file_system_type结构体来表示文件系统类型。其中包括了文件系统的名称、挂载函数、卸载函数等信息。在f2fs中,文件系统类型定义如下: static struct file_system_type f2fs_fs_type = { .owner = THIS_MODULE, .name = "f2fs", .mount = f2fs_mount, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, }; 2. 挂载函数:f2fs_mount函数是用来将块设备挂载成f2fs文件系统的函数。它是通过调用mount_bdev函数来实现的。具体的挂载过程包括了填充f2fs super block信息等操作。在f2fs中,挂载函数定义如下: static struct dentry *f2fs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { return mount_bdev(fs_type, flags, dev_name, data, f2fs_fill_super); } 3. 填充super block信息:f2fs_fill_super函数用来填充f2fs文件系统的super block信息。它会读取块设备上的super block数据,并将其解析为内存中的数据结构。在f2fs中,填充super block信息的函数定义如下: static int f2fs_fill_super(struct super_block *sb, void *data, int silent) { // 填充super block信息的具体实现 } 通过以上组件和函数,f2fs文件系统可以被调用和使用。当用户在用户空间执行mount操作时,会回调到文件系统类型中定义的mount函数,即f2fs_mount函数。在f2fs_mount函数中,会调用mount_bdev函数来实现具体的挂载过程,包括填充super block信息等操作。最终,f2fs文件系统就可以被成功挂载和使用。 #### 引用[.reference_title] - *1* [f2fs学习笔记 - 4. f2fs文件系统组件说明](https://blog.csdn.net/jasonactions/article/details/122417105)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [f2fs学习四: f2fs文件系统挂载](https://blog.csdn.net/guozhidixian/article/details/115498708)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值