F2FS重要数据结构详解之struct dirty_seglist_info
struct f2fs_sm_info
是f2fs的重要数据结构之一,维护了 segment 在内存中的元数据信息,关于许多博客已经介绍,这里不多赘述,这里主要介绍struct f2fs_sm_info
内部的另一个重要数据结构struct f2fs_sm_info
。
struct f2fs_sm_info {
…
struct dirty_seglist_info *dirty_info; /* dirty segment information */
…
};
数据结构分析
struct f2fs_sm_info
主要维护了文件系统的脏segment信息,包括 dirty 和 prefree,具体数据结构如下:
struct dirty_seglist_info {
const struct victim_selection *v_ops; /* victim selction operation */
unsigned long *dirty_segmap[NR_DIRTY_TYPE];
struct mutex seglist_lock; /* lock for segment bitmaps */
int nr_dirty[NR_DIRTY_TYPE]; /* # of dirty segments */
unsigned long *victim_secmap; /* background GC victims */
};
1. 第一个成员记录了选择 victim 的策略,即一个回调函数,用于选择 victim
/* victim selection function for cleaning and SSR */
struct victim_selection {
int (*get_victim)(struct f2fs_sb_info *, unsigned int *, int, int, char);
}
2. 第二个成员维护了 NR_DIRTY_TYPE(8)张位图
/* Notice: The order of dirty type is same with CURSEG_XXX in f2fs.h */
enum dirty_type {
DIRTY_HOT_DATA, /* dirty segments assigned as hot data logs */
DIRTY_WARM_DATA, /* dirty segments assigned as warm data logs */
DIRTY_COLD_DATA, /* dirty segments assigned as cold data logs */
DIRTY_HOT_NODE, /* dirty segments assigned as hot node logs */
DIRTY_WARM_NODE, /* dirty segments assigned as warm node logs */
DIRTY_COLD_NODE, /* dirty segments assigned as cold node logs */
DIRTY, /* to count # of dirty segments */
PRE, /* to count # of entirely obsolete segments */
NR_DIRTY_TYPE
};
3. 第四个成员记录了8种 dirty segment 的数量
相关函数分析
1 /*
2 * Should not occur error such as -ENOMEM.
3 * Adding dirty entry into seglist is not critical operation.
4 * If a given segment is one of current working segments, it won't be added.
5 *
6 * 如果这个seg中有效block数等于0,把这个segment归为prefree,在prefree位图上将segno的位置置位
7 * 然后在dirty位图上将segno的位置取消置位
8 * 如果这个seg中有效block数等于512,把这个segment归为valid,在dirty位图上将segno的位置取消置位
9 * 如果这个seg中有效block数介于0~512之间,把这个segment归为dirty,在dirty位图上将segno的位置置位
10 *
11 * 所以总的来说,这个函数的目的是分情况将segment置脏
12 */
13 static void locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno)
14 {
15 struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
16 unsigned short valid_blocks;
17
18 if (segno == NULL_SEGNO || IS_CURSEG(sbi, segno))
19 return;
20
21 mutex_lock(&dirty_i->seglist_lock);
22
23 valid_blocks = get_valid_blocks(sbi, segno, 0);
24
25 if (valid_blocks == 0) {
26 __locate_dirty_segment(sbi, segno, PRE);
27 __remove_dirty_segment(sbi, segno, DIRTY);
28 } else if (valid_blocks < sbi->blocks_per_seg) {
29 __locate_dirty_segment(sbi, segno, DIRTY);
30 } else {
31 /* Recovery routine with SSR needs this */
32 __remove_dirty_segment(sbi, segno, DIRTY);
33 }
34
35 mutex_unlock(&dirty_i->seglist_lock);
36 }
37
38
39 // dirty_seglist_info 维护的位图中,将dirty_type类型的位图上将segno对应的位置置位
40 static void __locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno, enum dirty_type dirty_type)
41 {
42 struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
43
44 /* need not be added */
45 if (IS_CURSEG(sbi, segno))
46 return;
47
48 if (!test_and_set_bit(segno, dirty_i->dirty_segmap[dirty_type]))
49 dirty_i->nr_dirty[dirty_type]++;
50
51 if (dirty_type == DIRTY) {
52 struct seg_entry *sentry = get_seg_entry(sbi, segno);
53 enum dirty_type t = sentry->type;
54
55 if (unlikely(t >= DIRTY)) {
56 f2fs_bug_on(sbi, 1);
57 return;
58 }
59 if (!test_and_set_bit(segno, dirty_i->dirty_segmap[t]))
60 dirty_i->nr_dirty[t]++;
61 }
62 }
63
64 // dirty_seglist_info 维护的位图中,将dirty_type类型的位图上将segno对应的位置取消置位
65 static void __remove_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno, enum dirty_type dirty_type)
66 {
67 struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
68
69 if (test_and_clear_bit(segno, dirty_i->dirty_segmap[dirty_type]))
70 dirty_i->nr_dirty[dirty_type]--;
71
72 if (dirty_type == DIRTY) {
73 struct seg_entry *sentry = get_seg_entry(sbi, segno);
74 enum dirty_type t = sentry->type;
75
76 if (test_and_clear_bit(segno, dirty_i->dirty_segmap[t]))
77 dirty_i->nr_dirty[t]--;
78
79 if (get_valid_blocks(sbi, segno, sbi->segs_per_sec) == 0)
80 clear_bit(GET_SECNO(sbi, segno),
81 dirty_i->victim_secmap);
82 }
83 }