0%

f2fs扩容操作源码解析

  • f2fs扩容操作源码解析

源代码分析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
//f2fs的扩容操作
int f2fs_resize(struct f2fs_sb_info *sbi)
{
//首先获取现有super block的信息
struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi);
//创建新的super block
struct f2fs_super_block new_sb_raw;
//指向新的super block
struct f2fs_super_block *new_sb = &new_sb_raw;
//分别记录结束的块地址,以及旧的和新的main区域的大小
block_t end_blkaddr, old_main_blkaddr, new_main_blkaddr;
unsigned int offset;
unsigned int offset_seg = 0;
int err = -1;

/* flush NAT/SIT journal entries */
//保证数据一致性
flush_journal_entries(sbi);
//把更新后的super block信息复制到新的super block中
memcpy(new_sb, F2FS_RAW_SUPER(sbi), sizeof(*new_sb));
if (get_new_sb(new_sb))
return -1;

/* check nat availability */
//检查NAT表,分别获取了当前的nat大小和扩容后的nat大小
if (get_sb(segment_count_nat) > get_newsb(segment_count_nat)) {
//否则需要收缩nat表
err = shrink_nats(sbi, new_sb);
if (err) {
MSG(0, "\tError: Failed to shrink NATs\n");
return err;
}
}
//分别打印出新旧super block信息
print_raw_sb_info(sb);
print_raw_sb_info(new_sb);

//获取旧的main area的起始地址信息
old_main_blkaddr = get_sb(main_blkaddr);
new_main_blkaddr = get_newsb(main_blkaddr);

//计算新旧main area的地址差值
offset = new_main_blkaddr - old_main_blkaddr;
//log_block_per_seg代表了一个segment包含的block数对2取对数的结果,这里计算出整个文件系统结束的地址
end_blkaddr = (get_sb(segment_count_main) <<
get_sb(log_blocks_per_seg)) + get_sb(main_blkaddr);
//重试标志
err = -EAGAIN;
//如果扩容后的main area的起始地址比当前文件系统结束的地址要小,那么会发生少量的数据迁移就可以完成扩容操作
if (new_main_blkaddr < end_blkaddr) {
err = f2fs_defragment(sbi, old_main_blkaddr, offset,
new_main_blkaddr, 0);
if (!err)
offset_seg = offset >> get_sb(log_blocks_per_seg);
MSG(0, "Try to do defragement: %s\n", err ? "Skip": "Done");
}
/* move whole data region */
//如果不是上述的情况,就得直接发生整体的数据迁移操作,先迁移main area区域,再迁移元数据部分
if (err)
migrate_main(sbi, offset);

migrate_ssa(sbi, new_sb, offset_seg);
migrate_nat(sbi, new_sb);
migrate_sit(sbi, new_sb, offset_seg);
rebuild_checkpoint(sbi, new_sb, offset_seg);
rebuild_superblock(new_sb);
return 0;
}