F2FS之读取最新的checkpoint块

在F2FS文件系统中为了读取最新的CP块给超级块对象中的sbi->ckpt,是调用int get_valid_checkpoint(struct f2fs_sb_info *sbi)函数 。

int get_valid_checkpoint(struct f2fs_sb_info *sbi)
{
	struct f2fs_checkpoint *cp_block;
	struct f2fs_super_block *fsb = sbi->raw_super;//磁盘超级块
	struct page *cp1, *cp2, *cur_page;
	unsigned long blk_size = sbi->blocksize;
	unsigned long long cp1_version = 0, cp2_version = 0;
	unsigned long long cp_start_blk_no;

	sbi->ckpt = kzalloc(blk_size, GFP_KERNEL);
	if (!sbi->ckpt)
		return -ENOMEM;
	/*
	 * Finding out valid cp block involves read both
	 * sets( cp pack1 and cp pack 2)
	 */
	cp_start_blk_no = le32_to_cpu(fsb->cp_blkaddr);//检查点的开始块地址
	cp1 = validate_checkpoint(sbi, cp_start_blk_no, &cp1_version);

	/* The second checkpoint pack should start at the next segment */
	//第二个检查点包应从下一个segment开始
	cp_start_blk_no += 1 << le32_to_cpu(fsb->log_blocks_per_seg);
	cp2 = validate_checkpoint(sbi, cp_start_blk_no, &cp2_version);

	if (cp1 && cp2) {//如果两个检查点都有效,则选择最新的检查点
		if (ver_after(cp2_version, cp1_version))
			cur_page = cp2;
		else
			cur_page = cp1;
	} else if (cp1) {
		cur_page = cp1;
	} else if (cp2) {
		cur_page = cp2;
	} else {
		goto fail_no_cp;
	}

	cp_block = (struct f2fs_checkpoint *)page_address(cur_page);//将最新的CP赋值给CP块
	memcpy(sbi->ckpt, cp_block, blk_size);//将新的CP块赋值给超级块内存对象

	f2fs_put_page(cp1, 1);
	f2fs_put_page(cp2, 1);
	return 0;

fail_no_cp:
	kfree(sbi->ckpt);
	return -EINVAL;
}

分析一下这个函数:首先先给sbi->ckpt创建一个块大小的内存空间。接着从磁盘超级块的fsb->cp_blkaddr中获取磁盘CP的起始地址。然后调用validate_checkpoint(sbi, cp_start_blk_no, &cp1_version)检查第一个CP是否有效 ,该函数会从磁盘中读取对应的f2fs_checkpoint结构(大小为一个块),并判断该CP是否有效,如果有效则返回对应的page,无效则返回null,细节见下面的函数分析。接着将cp_start_blk_no加上一个segment,因为在磁盘上第二个CP在第二个segment,同样调用validate_checkpoint(sbi, cp_start_blk_no, &cp1_version)检查第二个CP是否有效。随后根据两次调用的结果,cp1和cp2判断是否都有返回值,并且根据version的大小选择最新的f2fs_checkpoint。得到最新的f2fs_checkpoint即cur_page后,将cur_page做类型转换后复制到超级块的sbi->ckpt处即可。

下面分析一下上面调用的validate_checkpoint

static struct page *validate_checkpoint(struct f2fs_sb_info *sbi,
				block_t cp_addr, unsigned long long *version)
{
	struct page *cp_page_1, *cp_page_2 = NULL;
	unsigned long blk_size = sbi->blocksize;//块大小
	struct f2fs_checkpoint *cp_block;//磁盘检查点块
	unsigned long long cur_version = 0, pre_version = 0;
	unsigned int crc = 0;
	size_t crc_offset;

	/* Read the 1st cp block in this CP pack */
	cp_page_1 = get_meta_page(sbi, cp_addr);//从磁盘上读取cp_addr处的检查点页

	/* get the version number */
	cp_block = (struct f2fs_checkpoint *)page_address(cp_page_1);//checkpoint块
	crc_offset = le32_to_cpu(cp_block->checksum_offset);//校验和偏移量
	if (crc_offset >= blk_size)
		goto invalid_cp1;

	crc = *(unsigned int *)((unsigned char *)cp_block + crc_offset);//读取CRC校验码值
	if (!f2fs_crc_valid(crc, cp_block, crc_offset))
		goto invalid_cp1;//校验和失效

	pre_version = le64_to_cpu(cp_block->checkpoint_ver);//第一个checkpoint的版本号

	/* Read the 2nd cp block in this CP pack *///cp pack可能是2个segment,第一个cp在第一个块,第2个cp在最后一个块
	cp_addr += le32_to_cpu(cp_block->cp_pack_total_block_count) - 1;//第二个检查点地址为第一个检查点地址加自己占有的块数
	cp_page_2 = get_meta_page(sbi, cp_addr);//从磁盘上读取cp_addr处的检查点页

	cp_block = (struct f2fs_checkpoint *)page_address(cp_page_2);
	crc_offset = le32_to_cpu(cp_block->checksum_offset);
	if (crc_offset >= blk_size)
		goto invalid_cp2;

	crc = *(unsigned int *)((unsigned char *)cp_block + crc_offset);
	if (!f2fs_crc_valid(crc, cp_block, crc_offset))
		goto invalid_cp2;

	cur_version = le64_to_cpu(cp_block->checkpoint_ver);

	if (cur_version == pre_version) {//比较两个检查点的版本号相等否
		*version = cur_version;
		f2fs_put_page(cp_page_2, 1);
		return cp_page_1;
	}
invalid_cp2:
	f2fs_put_page(cp_page_2, 1);
invalid_cp1:
	f2fs_put_page(cp_page_1, 1);
	return NULL;
}

该函数从页缓存中读取有效检查点的块,version为有效的版本号,判断该cp是否有效。首先cp_page_1 = get_meta_page(sbi, cp_addr)从磁盘上读取cp_addr处的检查点页,也就是该CP的第一个f2fs_checkpoint块然后读取他的校验和并判断是否有效,随后获得他的pre_version版本号。随后再来读取该CP的第二个f2fs_checkpoint块,首先获得他的块地址cp_addr += le32_to_cpu(cp_block->cp_pack_total_block_count) - 1;因为第二个f2fs_checkpoint块在CP的最后一个块,随后同理得到第二个f2fs_checkpoint块的版本号。比较两个f2fs_checkpoint块的版本号是否相同,如果相同,则表明该CP有效,并返回第一个f2fs_checkpoint块,否则该CP无效,返回NULL。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值