f2fs系列文章gc

本文深入探讨了f2fs文件系统的垃圾回收(gc)过程,包括选择section、数据迁移等步骤。f2fs_gc函数主要判断是否满足gc条件,并通过get_victim_by_default选择合适的section进行gc。do_garbage_collect负责实际的数据迁移,涉及node_segment和data_segment的处理,确保有效数据的正确迁移。

    这篇文章将讲述f2fs的gc,其主要的步骤应该是分为两步,首先select一个合适的section,然后将section中的数据全部迁移。

 

    f2fs_gc:这个函数主要有两个函数调用gc线程和f2fs_balance_fs。首先检查super_block是否设置MS_ACTIVE,也就是super_block处于活动状态(目前不知道什么个状态),如果设置了就不做gc了。然后再检查是否设置了CP_ERROR_FLAG(这个表示文件系统的没有稳定的cp pack),如果设置了,也是不做gc了。如果此时是BG_GC并且已经没有足够的section了,那么将gc_type设置成FG_GC。如果这种情况下,没有废弃的prefree segment并且调用get_victim函数也没有获得section,但是还有足够的section,那么此时不需做write_checkpoint,其他情况下都要进行write_checkpoint并且选择的segno被设置成NULL_SEGNO。接着检查调用get_victim_by_default来选择victim section来进行垃圾回收。然后就调用do_garbage_collect对选择的section进行数据的迁移。如果是BG_GC进入的f2fs_gc,这个时候还需要检查有没有足够的section,如果没有的话,继续回去进行新一轮的回收,另外如果此时的gc_type是FG_GC,那么进行write_checkpoint操作。

int f2fs_gc(struct f2fs_sb_info *sbi, bool sync)
{
	unsigned int segno;
	int gc_type = sync ? FG_GC : BG_GC;
	int sec_freed = 0;
	int ret = -EINVAL;
	struct cp_control cpc;
	struct gc_inode_list gc_list = {
		.ilist = LIST_HEAD_INIT(gc_list.ilist),
		.iroot = RADIX_TREE_INIT(GFP_NOFS),
	};

	cpc.reason = __get_cp_reason(sbi);
gc_more:
	segno = NULL_SEGNO;

	if (unlikely(!(sbi->sb->s_flags & MS_ACTIVE)))
		goto stop;
	if (unlikely(f2fs_cp_error(sbi))) {
		ret = -EIO;
		goto stop;
	}

	if (gc_type == BG_GC && has_not_enough_free_secs(sbi, sec_freed, 0)) {
		gc_type = FG_GC;
		if (__get_victim(sbi, &segno, gc_type) || prefree_segments(sbi)) {
			ret = write_checkpoint(sbi, &cpc);
			if (ret)
				goto stop;
			segno = NULL_SEGNO;
		} else if (has_not_enough_free_secs(sbi, 0, 0)) {
			ret = write_checkpoint(sbi, &cpc);
			if (ret)
				goto stop;
		}
	}

	if (segno == NULL_SEGNO && !__get_victim(sbi, &segno, gc_type))
		goto stop;
	ret = 0;

	if (do_garbage_collect(sbi, segno, &gc_list, gc_type) &&
			gc_type == FG_GC)
		sec_freed++;

	if (gc_type == FG_GC)
		sbi->cur_victim_sec = NULL_SEGNO;

	if (!sync) {
		if (has_not_enough_free_secs(sbi, sec_freed, 0))
			goto gc_more;

		if (gc_type == FG_GC)
			ret = write_checkpoint(sbi, &cpc);
	}
stop:
	mutex_unlock(&sbi->gc_mutex);

	put_gc_inode(&gc_list);

	if (sync)
		ret = sec_freed ? 0 : -EAGAIN;
	return ret;
}

    get_victim_by_default:首先初始化选择过程中使用到的数据结构victim_sel_policy,先说一下其字段的含义:alloc_mode,可以取值LFS和SSR,选择过程中这两种的处理模式是不同的。gc_mode这个是计算cost的算法,取值GC_CB和GC_GREEDY。dirty_segmap是记录dirty的segment的位图,选择过程中需要在dirty的segment的section中选择。max_search表示查找过程中的最多的segment的数量,实际就是上述位图的dirty的segment的数量。offset表示在便利过程中的当前的查找偏移。ofs_unit表示在查找过程中每次查找跨越的单元,SSR是以1个segment为单元,LFS是以1个section为单元。min_cost记录查找过程中的最小cost。min_segno记录的是查找过程中最小cost所对应的segno。

struct victim_sel_policy {
	int alloc_mode;	
	int gc_mode;
	unsigned long *dirty_segmap;
	unsigned int max_search;
	unsigned int offset;
	unsigned int ofs_unit;
	unsigned int min_cost;
	unsigned int min_segno;
};

    所以其初始化时通过函数select_policy完成的。然后检查是不是以LSF并且是FG_GC的方式进行select,如果是就直接使用之前BG_GC选择过的GC(这样选择的section其有效块数比较少,具体原因不清楚)。如果对应的segno不是NULL_SEGNO,那就找到了。否则需要跟其他的一样对所有的有脏的segment的section进行计算cost,然后选择出最小的cost作为最后的结果。可能是为了均匀的原因,这个遍历不是从头开始的,而是从上次的选择开始的,然后遍历整个循环。首先通过函数find_next_bit在dirty_segmap

<think>嗯,用户想了解F2FS文件系统中discard和垃圾回收(GC)的工作原理或优化方法。我需要参考提供的引用材料,但要注意这些引用并非全部直接相关,需要准确提取有用信息。从引用[1]中看到F2FS支持冷热数据分流,这个特性与GC效率相关。引用[2]详细描述了checkpoint过程涉及刷新脏页和节点,这对理解GC的触发机制有帮助。引用[3]是关于containerd配置的,与当前问题无关可以忽略。用户的核心需求是discard和GC机制详解。需要组织清晰的解释结构:先分别说明discard和GC的概念,再解释它们如何协同工作,最后补充优化方法。技术细节要准确,比如discard的异步处理、GC的触发阈值、冷热数据区分等关键点都需要涵盖。特别注意用户要求的中文回答和LaTeX格式。所有公式要用$...$或$$...$$规范表达,比如写回收效率公式时要用$E=\frac{V_{valid}}{V_{total}}$这样的格式。还要在最后生成相关问题帮助用户深入理解。考虑到用户可能是文件系统开发者或存储研究人员,回答需要保持专业深度,但也要避免过于晦涩。可以结合F2FS特有的设计如日志结构、Node/Data分离等特性来解释其GC机制的优势。</think>### F2FS Discard与垃圾回收(GC)机制详解 #### 一、Discard机制 **作用**:通知SSD控制器释放无效数据占用的物理块,提升写入效率和延长寿命。 **工作流程**: 1. **异步处理**:文件删除/截断时,F2FS将无效数据块加入`discard队列`,不阻塞I/O 2. **粒度优化**: - 小范围无效块:合并为`discard命令`(默认4MB) - 大段连续无效块:直接发送`TRIM指令` 3. **策略控制**:通过`/sys/fs/f2fs/<disk>/discard_granularity`调整粒度 #### 二、垃圾回收(GC)机制 **触发条件**: - 空间不足时(前台GC) - 定期后台清理(默认`gc_worker`线程每5分钟运行) - 空闲时段(利用`idle time GC`) **核心过程**: 1. **选择策略**: - **贪心算法**:选择有效块最少的段 - **成本效益算法**:平衡段中有效块比例与迁移开销 - 公式:$Cost = \frac{1 + u}{2u} \times v$($u$: 段利用率, $v$: 有效块数) 2. **数据迁移**: - 读取目标段的有效数据块 - 写入新分配的段(日志结构写入) - 更新元数据(Node/Data映射) 3. **段释放**:原段标记为空闲供写入 #### 三、冷热数据优化[^1] ```mermaid graph LR A[数据分类] --> B(热数据:频繁修改) A --> C(冷数据:长期不变) B --> D[分配到热区段] C --> E[分配到冷区段] F[GC选择] --> G[优先回收热区段] ``` - **冷热分离**:减少有效块迁移量,冷数据段GC开销更低 - **回收效率**:$E = \frac{V_{valid}}{V_{total}}$(冷数据段$E$值通常更低) #### 四、协同工作机制 1. **GC与Discard联动**: - GC完成后自动触发Discard释放物理块 - 避免SSD主控误读无效数据为有效 2. **Checkpoint屏障**[^2]: - GC执行前调用`block_operations()`冻结文件操作 - 确保数据一致性: ```c // 刷新脏页示例(引用[2]) if (get_pages(sbi, F2FS_DIRTY_NODES)) { err = f2fs_sync_node_pages(sbi, &wbc, false, FS_CP_NODE_IO); } ``` #### 五、优化方法 1. **自适应GC**:根据SSD性能动态调整GC线程优先级 2. **并行GC**:多线程迁移不同区段的有效块 3. **Discard合并**:延迟处理以聚合更多无效块 4. **冷热识别强化**:基于访问频率动态调整数据分类
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值