一、环境准备:
1、ubuntu系统安装f2fs-tools:sudo apt-get install -y f2fs-tools
2、使用系统loop设备进行实践操作:
dd if=/dev/zero of=device bs=4K count=51200 //200M
losetup /dev/loop0 device //寻址可用的loop设备
mkfs.f2fs -l f2fs /dev/loop0 //格式化此loop设备
mount -t f2fs /dev/loop0 ./f2fs_mp //挂载到f2fs_mp文件夹
3、获取挂载初始状态:dd if=/dev/loop0 of=f2fs_test,可以通过UE打开f2fs_test查看。
4、新建如下文件,以及对应的inode:
root@ubuntu:/home/yinpeng/f2fs_mp# ls -i
91 1.c 92 2.txt 87 a.txt 93 bio.c
二、磁盘布局分解:
1、superBlock:
F2FS文件的起始地址向后偏移0x400字节,寻址当前地址为所述超级块SuperBlock的起始地址。
在内存的存储方式是小端存储,有两个superblock如下:
对应的结构体信息如下:
struct f2fs_super_block {
__le32 magic; /* Magic Number */ |
0xF2F52010 |
__le16 major_ver; /* Major Version */ |
0x01 |
__le16 minor_ver; /* Minor Version */ |
0x0B |
__le32 log_sectorsize; /* log2 sector size in bytes */ |
0x09 |
__le32 log_sectors_per_block; /* log2 # of sectors per block */ |
0x03 |
__le32 log_blocksize; /* log2 block size in bytes */ |
0x0C |
__le32 log_blocks_per_seg; /* log2 # of blocks per segment */ |
0x09 |
__le32 segs_per_sec; /* # of segments per section */ |
0x01 |
__le32 secs_per_zone; /* # of sections per zone */ |
0x01 |
__le32 checksum_offset; /* checksum offset inside super block */ |
0x00 |
__le64 block_count; /* total # of user blocks */ |
0xC800 |
__le32 section_count; /* total # of sections */ |
0x5C |
__le32 segment_count; /* total # of segments */ |
0x63 |
__le32 segment_count_ckpt; /* # of segments for checkpoint */ |
0x02 |
__le32 segment_count_sit; /* # of segments for SIT */ |
0x02 |
__le32 segment_count_nat; /* # of segments for NAT */ |
0x02 |
__le32 segment_count_ssa; /* # of segments for SSA */ |
0x01 |
__le32 segment_count_main; /* # of segments for main area */ |
0x5C |
__le32 segment0_blkaddr; /* start block address of segment 0 */ |
0x0200 |
__le32 cp_blkaddr; /* start block address of checkpoint */ |
0x0200 |
__le32 sit_blkaddr; /* start block address of SIT */ |
0x0600 |
__le32 nat_blkaddr; /* start block address of NAT */ |
0x0A00 |
__le32 ssa_blkaddr; /* start block address of SSA */ |
0x0E00 |
__le32 main_blkaddr; /* start block address of main area */ |
0x1000 |
__le32 root_ino; /* root inode number */ |
0x03 |
__le32 node_ino; /* node inode number */ |
0x01 |
__le32 meta_ino; /* meta inode number */ |
0x02 |
__u8 uuid[16]; /* 128-bit uuid for volume */ |
*** |
__le16 volume_name[MAX_VOLUME_NAME]; /* volume name */ |
F2FS |
__le32 extension_count; /* # of extensions below */ |
0X0001B |
__u8 extension_list[F2FS_MAX_EXTENSION][F2FS_EXTENSION_LEN];/* extension array */ |
0x00 |
__le32 cp_payload; |
//0x0 |
__u8 version[VERSION_LEN]; /* the kernel version */ |
//4.9.117+ #4 SMP PREEMPT Sat May 25 01:40:39 CST 2019 |
__u8 init_version[VERSION_LEN]; /* the initial kernel version */ |
//4.9.117+ #4 SMP PREEMPT Sat May 25 01:40:39 CST 2019 |
__le32 feature; /* defined features */ |
//0x0 |
__u8 encryption_level; /* versioning level for encryption */ |
//0x0 |
__u8 encrypt_pw_salt[16]; /* Salt used for string2key algorithm */ |
//0x0 |
struct f2fs_device devs[MAX_DEVICES]; /* device list */ |
//0x0 |
__le32 qf_ino[F2FS_MAX_QUOTAS]; /* quota inode numbers */ |
//0x0 |
__u8 hot_ext_count; /* # of hot file extension */ |
//0x0 |
__u8 reserved[310]; /* valid reserved region */ |
//0x0 |
__le32 crc; /* checksum of superblock */ |
//0x0 |
} __packed;
2、checkpoint:
checkpoint的数量也有两个:
struct f2fs_checkpoint {
__le64 checkpoint_ver; /* checkpoint block version number */ |
0x1052B10E |
__le64 user_block_count; /* # of user blocks */ |
0x7A00 |
__le64 valid_block_count; /* # of valid blocks in main area */ |
0x13 |
__le32 rsvd_segment_count; /* # of reserved segments for gc */ |
0x15 |
__le32 overprov_segment_count; /* # of overprovision segments */ |
0x1F |
__le32 free_segment_count; /* # of free segments in main area */ |
0x56 |
__le32 cur_node_segno[MAX_ACTIVE_NODE_LOGS]; |
0x0.1.2.0xFFFFFFFF.FFFFFFFF.FFFFFFFF.FFFFFFFF.FFFFFFFF |
__le16 cur_node_blkoff[MAX_ACTIVE_NODE_LOGS]; |
0X2F.10.2.0x00. 0x00. 0x00. 0x00. 0x00. 0x00 |
__le32 cur_data_segno[MAX_ACTIVE_DATA_LOGS]; |
0x03. 0x47. 0x16. FFFFFFFF. FFFFFFFF. FFFFFFFF. FFFFFFFF. FFFFFFFF |
__le16 cur_data_blkoff[MAX_ACTIVE_DATA_LOGS]; |
0X85. 0x1AB. 0x00. 0x00. 0x00. 0x00. 0x00. 0x00 |
__le32 ckpt_flags; /* Flags : umount and journal_present */ |
0x01C4 |
__le32 cp_pack_total_block_count; /* total # of one cp pack */ |
0x04 |
__le32 cp_pack_start_sum; /* start block number of data summary */ |
0x01 |
__le32 valid_node_count; /* Total number of valid nodes */ |
0x05 |
__le32 valid_inode_count; /* Total number of valid inodes */ |
0x05 |
__le32 next_free_nid; /* Next free node number */ |
0x61 |
__le32 sit_ver_bitmap_bytesize; /* Default value 64 */ |
0x40 |
__le32 nat_ver_bitmap_bytesize; /* Default value 256 */ |
0x40 |
__le32 checksum_offset; /* checksum offset inside cp block */ |
0x0FF |
__le64 elapsed_time; /* mounted time */ |
0x019289 |
unsigned char alloc_type[MAX_ACTIVE_LOGS]; |
0x00 |
unsigned char sit_nat_version_bitmap[1]; |
0x00 |
} __packed;
3、SIT:
0xC01 >> 10 = 3 type
0xC01 & 0x3FF = 1
/*
* Note that f2fs_sit_entry->vblocks has the following bit-field information.
* [15:10] : allocation type such as CURSEG_XXXX_TYPE
* [9:0] : valid block count
*/
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;
dump.f2fs -s 0~-1 f2fs_test_2
root@ubuntu:/home/yinpeng# cat dump_sit
segment_type(0:HD, 1:WD, 2:CD, 3:HN, 4:WN, 5:CN)
segno: 0 vblocks: 1 seg_type:3 sit_pack:2
//1segment = 512 block
00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 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: 2 seg_type:4 sit_pack:2
用户层的数据从0x100000开始:
1000000 + 1*2MB(segmet size) + (8*5 + 3) * 4Kb(block size) =
0x1000000 + 0x200000 + 0x2B000 = 0x122B000
0x18 = 0x00011000
00 00 00 00 00 18 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 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:5 sit_pack:2
segno: 3 vblocks: 1 seg_type:0 sit_pack:2
0x1000000 + 3 * 2MB + (14*8 + 4) * 4kb = 74000
0x1000000 + 0x600000 + 74000
0x08 = 0x00001000
00 00 00 00 00 00 00 00 00 00 00 00 00 00 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
segno: 4 vblocks: 0 seg_type:1 sit_pack:2
segno: 5 vblocks: 0 seg_type:1 sit_pack:2
从上面的分解,可以看到通过如下流程可以找到DataBlock的地址:
Superblock -> NAT -> inode number -> datablock
4.NAT
struct f2fs_nat_entry {
__u8 version; /* latest version of cached nat entry */
__le32 ino; /* inode number */
__le32 block_addr; /* block address */
} __packed;
struct f2fs_nat_block {
struct f2fs_nat_entry entries[NAT_ENTRY_PER_BLOCK];
} __packed;
dump.f2fs -n 0~-1 f2fs_test_2
root@ubuntu:/home/yinpeng# cat dump_nat
nid: 3 ino: 3 offset: 0 blkaddr: 4111 //0x122A 000 pack:2
nid: 87 ino: 87 offset: 0 blkaddr: 4651 //0x122B pack:2
nid: 91 ino: 91 offset: 0 blkaddr: 4652 //0x122C pack:2
nid: 92 ino: 92 offset: 0 blkaddr: 4653 //0x122D pack:2
nid: 93 ino: 93 offset: 0 blkaddr: 4654 //0x122E pack:2
5、DataBlock:
root@ubuntu:/home/yinpeng# dump.f2fs -a 0~-1 f2fs_test_2
root@ubuntu:/home/yinpeng# cat dump_ssa
/* 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 */
__le16 ofs_in_node; /* block index in parent node */
} __packed;
};
} __packed;
参考博客:
https://blog.csdn.net/SweeNeil/article/details/91897016
作者:frank_zyp
您的支持是对博主最大的鼓励,感谢您的认真阅读。
本文无所谓版权,欢迎转载。