f2fs_super_block:
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
默认值是9,是512=2^9的幂数,是格式化工具的默认配置
*/
__le32 log_sectors_per_block;
/*
log2 # of sectors per block
默认值是3是8=2^3,也是格式化工具的默认配置
*/
__le32 log_blocksize;
/*
//log2 block size in bytes
该值由log_sectorsize+log_sectors_per_block=12,即9(512=2^9)+3(8=2^3)=12
*/
__le32 log_blocks_per_seg;
/*
//log2 # of blocks per segment
默认值是9,是512=2^9的幂数,是格式化工具的默认配置
*/
__le32 segs_per_sec;
/*
//# of segments per section
目前是1
*/
__le32 secs_per_zone;
/*
//# of sections per zone
目前是1
*/
__le32 checksum_offset;
/*
//checksum offset inside super block
目前是0
*/
__le64 block_count;
/*
//total # of user blocks //
block_count=(该分区大小/log_sectorsize(=512))>>log_sectors_per_block,相当于该分区有多少个page(page=4096)
*/
__le32 section_count;
/*
total # of sections
section_count = segment_count - ( segment_count_ckpt+segment_count_sit+segment_count_nat+segment_count_ssa )
*/
__le32 segment_count;
/*
//total # of segments
segment_count=(该分区大小-zone_align_start_offset)/ segment_size_bytes
一个segment=512*block_size=512*4096=2M
*/
__le32 segment_count_ckpt;
/*
# of segments for checkpoint
默认是2
*/
__le32 segment_count_sit;
/*
# of segments for SIT
segment_count_sit = sit_segments * 2;
#define SIZE_ALIGN(val, size) ((val) + (size) - 1) / (size)
#define SEG_ALIGN(blks) SIZE_ALIGN(blks, c.blks_per_seg)
#define SIT_ENTRY_PER_BLOCK (PAGE_CACHE_SIZE / sizeof(struct f2fs_sit_entry)) =55
//一个block可以存放55个struct f2fs_sit_entry,一个struct f2fs_sit_entry可以描述512个blcok也就是一个segment,所以这个公式计算出来的是总共segment_count需要多少个block去存放struct f2fs_sit_entry
blocks_for_sit = SIZE_ALIGN(get_sb(segment_count), SIT_ENTRY_PER_BLOCK);
//获得存储blocks_for_sit个block , 需要多少个segment
sit_segments = SEG_ALIGN(blocks_for_sit);
//由于需要一个备份所以*2
segment_count_sit = sit_segments * 2;
*/
__le32 segment_count_nat;
/*
# of segments for NAT
#define SIZE_ALIGN(val, size) ((val) + (size) - 1) / (size)
#define SEG_ALIGN(blks) SIZE_ALIGN(blks, c.blks_per_seg)
#define NAT_ENTRY_PER_BLOCK (PAGE_CACHE_SIZE / sizeof(struct f2fs_nat_entry)) = 455
//总segment_count segment个数 减去 已经被ckpt和sit占用的segment 就获得了总的还剩可用block个数
total_valid_blks_available = (segment_count - (segment_count_ckpt + segment_count_sit)) * c.blks_per_seg;
//一个block可以存放NAT_ENTRY_PER_BLOCK(455)个struct f2fs_nat_entry,而一个struct f2fs_nat_entry可以描述一个block的地址和属于哪个ino,
//那么这个公式计算的就是描述total_valid_blks_available个block需要多少个block去存储struct f2fs_nat_entry
blocks_for_nat = SIZE_ALIGN(total_valid_blks_available,NAT_ENTRY_PER_BLOCK);
//转换为多少个segment,*2需要备份
segment_count_nat=SEG_ALIGN(blocks_for_nat) * 2;
*/
__le32 segment_count_ssa;
/*
# of segments for SSA
//剩余可用block总数
total_valid_blks_available = (segment_count - (segment_count_ckpt + segment_count_sit + segment_count_nat)) * c.blks_per_seg;
//存放SSA需要多少个block
blocks_for_ssa = total_valid_blks_available / c.blks_per_seg + 1;
//转换为segment
segment_count_ssa = SEG_ALIGN(blocks_for_ssa);
*/
__le32 segment_count_main;
/*
# of segments for main area
segment_count_main = section_count * segs_per_sec,一般情况下等于section_count
*/
__le32 segment0_blkaddr;
/*
//start block address of segment 0//
segment0_blkaddr = zone_align_start_offset / blk_size_bytes;
blk_size_bytes=4096;
F2FS_BLKSIZE=4096;
目前c.start_sector=0,c.sector_size=512;
zone_size_bytes = blk_size_bytes * c.secs_per_zone * c.segs_per_sec * c.blks_per_seg=4096*1*1*512;
zone_align_start_offset = (c.start_sector * c.sector_size +2 * F2FS_BLKSIZE + zone_size_bytes - 1) /zone_size_bytes * zone_size_bytes -c.start_sector * c.sector_size;
zone_align_start_offset=4096*512;
segment0_blkaddr = 512 = 0x200;
*/
__le32 cp_blkaddr;
/*
start block address of checkpoint
cp_blkaddr= segment0_blkaddr
*/
__le32 sit_blkaddr;
/*
//start block address of SIT
sit_blkaddr = segment0_blkaddr + segment_count_ckpt * blks_per_seg=512 + 2 * 512 = 0x600
*/
__le32 nat_blkaddr;
/*
start block address of NAT
nat_blkaddr = sit_blkaddr + segment_count_sit * blks_per_seg = 0x600 + 2 * 512 = 0xA00
*/
__le32 ssa_blkaddr;
/*
start block address of SSA
ssa_blkaddr = nat_blkaddr + segment_count_nat * c.blks_per_seg = 0xA00 + 2 * 512 = 0xE00
*/
__le32 main_blkaddr;
/*
start block address of main area
total_meta_zones=segment_count_ckpt+segment_count_sit+segment_count_nat+segment_count_ssa,即元数据segment总和
main_blkaddr=segment0_blkaddr + total_meta_zones *c.segs_per_zone * c.blks_per_seg;
*/
__le32 root_ino;
/*
root inode number
默认值是3
*/
__le32 node_ino;
/*
node inode number
默认值是1
*/
__le32 meta_ino;
/*
meta inode number
默认值是2
*/
__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][8]; /* extension array */
__le32 cp_payload;
/*
目前是0 ,用来扩展ckpt , 当分区非常大的时候
*/
__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 reserved[315]; /* valid reserved region */
} __attribute__((packed));
SIT初始化生成:
int f2fs_format_device(void)
{
//初始化、计算、填充struct f2fs_super_block成员
err= f2fs_prepare_super_block();
//是否支持trim
err = f2fs_trim_devices();
//把sit区域填充0
err = f2fs_init_sit_area();
//把nat区域填充0
err = f2fs_init_nat_area();
err = f2fs_create_root_dir();
err = f2fs_write_check_point_pack();
err = f2fs_write_super_block();
return err;
}
f2fs_prepare_super_block():
static inline double get_best_overprovision(struct f2fs_super_block *sb)
{
double reserved, ovp, candidate, end, diff, space;
double max_ovp = 0, max_space = 0;
if (get_sb(segment_count_main) < 256) {
candidate = 10;
end = 95;
diff = 5;
} else {
candidate = 0.01;
end = 10;
diff = 0.01;
}
for (; candidate <= end; candidate += diff) {
reserved = (2 * (100 / candidate + 1) + 6) *get_sb(segs_per_sec);
ovp = (get_sb(segment_count_main) - reserved) * candidate / 100;
space = get_sb(segment_count_main) - reserved - ovp;
if (max_space < space) {
max_space = space;
max_ovp = candidate;
}
}
return max_ovp;
}
static int f2fs_create_root_dir(void)
{
/*
创建根inode,并初始化
struct f2fs_node *raw_node = calloc(F2FS_BLKSIZE, 1);
raw_node->footer.nid = sb->root_ino;
raw_node->footer.ino = sb->root_ino;
//计算下一个block地址
raw_node->footer.next_blkaddr = cpu_to_le32(get_sb(main_blkaddr) +c.cur_seg[CURSEG_HOT_NODE] *c.blks_per_seg + 1);
....
//计算root note数组存储地址
data_blk_nor = get_sb(main_blkaddr) + c.cur_seg[CURSEG_HOT_DATA] * c.blks_per_seg;
raw_node->i.i_addr[get_extra_isize(raw_node)] = cpu_to_le32(data_blk_nor);
....
//计算root inode存储偏移位置
main_area_node_seg_blk_offset = get_sb(main_blkaddr);
main_area_node_seg_blk_offset += c.cur_seg[CURSEG_HOT_NODE] *c.blks_per_seg;
偏移main_area_node_seg_blk_offset大小,以一个page大小把struct f2fs_node写入磁盘
dev_write_block(raw_node, main_area_node_seg_blk_offset);
*/
err = f2fs_write_root_inode();
//类似root inode 创建qf inode 并初始化 写入磁盘指定位置
err = f2fs_write_qf_inode(qtype);
/*
创建struct f2fs_nat_block 并初始化 写入磁盘指定位置
struct f2fs_nat_block *nat_blk = calloc(F2FS_BLKSIZE, 1);
/* update root */
//前面已经初始化并写入磁盘了,所以block_addr位置已经固定了
nat_blk->entries[get_sb(root_ino)].block_addr = cpu_to_le32(get_sb(main_blkaddr) +c.cur_seg[CURSEG_HOT_NODE] * c.blks_per_seg);
nat_blk->entries[get_sb(root_ino)].ino = sb->root_ino;
/* update node nat */
nat_blk->entries[get_sb(node_ino)].block_addr = cpu_to_le32(1);
nat_blk->entries[get_sb(node_ino)].ino = sb->node_ino;
/* update meta nat */
nat_blk->entries[get_sb(meta_ino)].block_addr = cpu_to_le32(1);
nat_blk->entries[get_sb(meta_ino)].ino = sb->meta_ino;
nat_seg_blk_offset = get_sb(nat_blkaddr);
//指定位置写入struct f2fs_nat_block
dev_write_block(nat_blk, nat_seg_blk_offset);
*/
err = f2fs_update_nat_root();
/*
创建根目录项‘.’ 和 ‘..’,并初始化 写入磁盘指定位置
struct f2fs_dentry_block * dent_blk = calloc(F2FS_BLKSIZE, 1);
dent_blk->dentry[0].hash_code = 0;
dent_blk->dentry[0].ino = sb->root_ino;
dent_blk->dentry[0].name_len = cpu_to_le16(1);
dent_blk->dentry[0].file_type = F2FS_FT_DIR;
memcpy(dent_blk->filename[0], ".", 1);
dent_blk->dentry[1].hash_code = 0;
dent_blk->dentry[1].ino = sb->root_ino;
dent_blk->dentry[1].name_len = cpu_to_le16(2);
dent_blk->dentry[1].file_type = F2FS_FT_DIR;
memcpy(dent_blk->filename[1], "..", 2);
/* bitmap for . and .. */
//设置位图
test_and_set_bit_le(0, dent_blk->dentry_bitmap);
test_and_set_bit_le(1, dent_blk->dentry_bitmap);
//计算写入位置
data_blk_offset = get_sb(main_blkaddr);
data_blk_offset += c.cur_seg[CURSEG_HOT_DATA] * c.blks_per_seg;
dev_write_block(dent_blk, data_blk_offset);
*/
err = f2fs_add_default_dentry_root();
}
static int f2fs_write_check_point_pack(void)
{
//分配struct f2fs_checkpoint , 并初始化 ,写入指定位置
struct f2fs_checkpoint *cp = calloc(F2FS_BLKSIZE, 1);
//设置版本号 用于恢复
cp->checkpoint_ver = cpu_to_le64(rand() | 0x1);
//设置node 、 data 的segment number
set_cp(cur_node_segno[0], c.cur_seg[CURSEG_HOT_NODE]);
set_cp(cur_node_segno[1], c.cur_seg[CURSEG_WARM_NODE]);
set_cp(cur_node_segno[2], c.cur_seg[CURSEG_COLD_NODE]);
set_cp(cur_data_segno[0], c.cur_seg[CURSEG_HOT_DATA]);
set_cp(cur_data_segno[1], c.cur_seg[CURSEG_WARM_DATA]);
set_cp(cur_data_segno[2], c.cur_seg[CURSEG_COLD_DATA]);
for (i = 3; i < MAX_ACTIVE_NODE_LOGS; i++)
{
set_cp(cur_node_segno[i], 0xffffffff);
set_cp(cur_data_segno[i], 0xffffffff);
}
//设置node 、 data的block offset 地址
set_cp(cur_node_blkoff[0], 1 + quota_inum);
set_cp(cur_data_blkoff[0], 1 + quota_dnum);
//设置有效的block数量
set_cp(valid_block_count, 2 + quota_inum + quota_dnum);
//设置保留的segment数量
set_cp(rsvd_segment_count, c.reserved_segments);
//设置预留的segment数量
set_cp(overprov_segment_count, (get_sb(segment_count_main) - get_cp(rsvd_segment_count)) * c.overprovision / 100);
set_cp(overprov_segment_count, get_cp(overprov_segment_count) +get_cp(rsvd_segment_count));
/* main segments - reserved segments - (node + data segments) */
set_cp(free_segment_count, get_sb(segment_count_main) - 6);
set_cp(user_block_count, ((get_cp(free_segment_count) + 6 -get_cp(overprov_segment_count)) * c.blks_per_seg));
/* cp page (2), data summaries (1), node summaries (3) */
set_cp(cp_pack_total_block_count, 6 + get_sb(cp_payload));
//设置ckpt flag
set_cp(ckpt_flags, flags);
set_cp(cp_pack_start_sum, 1 + get_sb(cp_payload));
set_cp(valid_node_count, 1 + quota_inum);
set_cp(valid_inode_count, 1 + quota_inum);
set_cp(next_free_nid, get_sb(root_ino) + 1 + quota_inum);
//segment_count_sit或者segment_count_nat数量的segment 需要多少bit位来表示,并换算为byte
set_cp(sit_ver_bitmap_bytesize, ((get_sb(segment_count_sit) / 2) << get_sb(log_blocks_per_seg)) / 8);
set_cp(nat_ver_bitmap_bytesize, ((get_sb(segment_count_nat) / 2) << get_sb(log_blocks_per_seg)) / 8);
set_cp(checksum_offset, CHECKSUM_OFFSET);
//计算cp写入位置
cp_seg_blk = get_sb(segment0_blkaddr);
//cp page 1
//指定位置写入struct f2fs_checkpoint
dev_write_block(cp, cp_seg_blk);
/* Prepare and write Segment summary for HOT/WARM/COLD DATA
*
* The structure of compact summary
* +-------------------+
* | nat_journal |
* +-------------------+
* | sit_journal |
* +-------------------+
* | hot data summary |
* +-------------------+
* | warm data summary |
* +-------------------+
* | cold data summary |
* +-------------------+
*/
memset(sum, 0, sizeof(struct f2fs_summary_block));
SET_SUM_TYPE((&sum->footer), SUM_TYPE_DATA);
//nat for root
journal = &sum->journal;
journal->n_nats = cpu_to_le16(1 + quota_inum);
journal->nat_j.entries[0].nid = sb->root_ino;
journal->nat_j.entries[0].ne.version = 0;
journal->nat_j.entries[0].ne.ino = sb->root_ino;
journal->nat_j.entries[0].ne.block_addr = cpu_to_le32(get_sb(main_blkaddr) +get_cp(cur_node_segno[0]) * c.blks_per_seg);
memset(sum, 0, sizeof(struct f2fs_summary_block));
/* inode sit for root */
journal->n_sits = cpu_to_le16(6);
journal->sit_j.entries[0].segno = cp->cur_node_segno[0];
journal->sit_j.entries[0].se.vblocks = cpu_to_le16((CURSEG_HOT_NODE << 10) | (1 + quota_inum));
f2fs_set_bit(0, (char *)journal->sit_j.entries[0].se.valid_map);
for (i = 1; i <= quota_inum; i++)
f2fs_set_bit(i, (char *)journal->sit_j.entries[0].se.valid_map);
journal->sit_j.entries[1].segno = cp->cur_node_segno[1];
journal->sit_j.entries[1].se.vblocks = cpu_to_le16((CURSEG_WARM_NODE << 10));
journal->sit_j.entries[2].segno = cp->cur_node_segno[2];
journal->sit_j.entries[2].se.vblocks = cpu_to_le16((CURSEG_COLD_NODE << 10));
/* data sit for root */
journal->sit_j.entries[3].segno = cp->cur_data_segno[0];
journal->sit_j.entries[3].se.vblocks = cpu_to_le16((CURSEG_HOT_DATA << 10) | (1 + quota_dnum));
f2fs_set_bit(0, (char *)journal->sit_j.entries[3].se.valid_map);
for (i = 1; i <= quota_dnum; i++)
f2fs_set_bit(i, (char *)journal->sit_j.entries[3].se.valid_map);
journal->sit_j.entries[4].segno = cp->cur_data_segno[1];
journal->sit_j.entries[4].se.vblocks = cpu_to_le16((CURSEG_WARM_DATA << 10));
journal->sit_j.entries[5].segno = cp->cur_data_segno[2];
journal->sit_j.entries[5].se.vblocks = cpu_to_le16((CURSEG_COLD_DATA << 10));
memcpy(sum_compact_p, &journal->n_sits, SUM_JOURNAL_SIZE);
sum_compact_p += SUM_JOURNAL_SIZE;
/* hot data summary */
sum_entry = (struct f2fs_summary *)sum_compact_p;
sum_entry->nid = sb->root_ino;
sum_entry->ofs_in_node = 0;
dev_write_block(sum_compact, cp_seg_blk);
/* Prepare and write Segment summary for HOT_NODE */
memset(sum, 0, sizeof(struct f2fs_summary_block));
SET_SUM_TYPE((&sum->footer), SUM_TYPE_NODE);
sum->entries[0].nid = sb->root_ino;
sum->entries[0].ofs_in_node = 0;
dev_write_block(sum, cp_seg_blk);
/* Fill segment summary for WARM_NODE to zero. */
memset(sum, 0, sizeof(struct f2fs_summary_block));
SET_SUM_TYPE((&sum->footer), SUM_TYPE_NODE);
dev_write_block(sum, cp_seg_blk);
/* Fill segment summary for COLD_NODE to zero. */
memset(sum, 0, sizeof(struct f2fs_summary_block));
SET_SUM_TYPE((&sum->footer), SUM_TYPE_NODE);
dev_write_block(sum, cp_seg_blk);
/* cp page2 */
dev_write_block(cp, cp_seg_blk);
/* write NAT bits, if possible */
for (i = 0; i < nat_bits_blocks; i++)
dev_write_block(nat_bits + i *F2FS_BLKSIZE, cp_seg_blk + i);
/* cp page 1 of check point pack 2
* Initiatialize other checkpoint pack with version zero
*/
cp->checkpoint_ver = 0;
cp_seg_blk = get_sb(segment0_blkaddr) + c.blks_per_seg;
dev_write_block(cp, cp_seg_blk);
/* cp page 2 of check point pack 2 */
cp_seg_blk += (le32_to_cpu(cp->cp_pack_total_block_count) -get_sb(cp_payload) - 1);
dev_write_block(cp, cp_seg_blk);
}
#define F2FS_SUPER_OFFSET 1024 /* byte-size offset */
static int f2fs_write_super_block(void)
{
u_int8_t *zero_buff;
zero_buff = calloc(F2FS_BLKSIZE, 1);
memcpy(zero_buff + F2FS_SUPER_OFFSET, sb, sizeof(*sb));
for (index = 0; index < 2; index++)
dev_write_block(zero_buff, index);
}