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。

<think>我们正在讨论F2FS文件系统的头部检查方法。用户已经给出了几个引用,其中提到了F2FS相关的工具和注意事项。根据引用,我们可以知道: 引用[3]提到了fsck.f2fs工具,它是用来检查F2FS格式分区一致性的工具,并且可以检查文件系统元数据。 另外,引用[2]提到了要让Linux内核加载f2fs,并安装f2fs-tools工具。 因此,检查F2FS文件系统镜像头部的方法,我们可以使用以下步骤: 1. 确保系统支持F2FS文件系统,即已安装f2fs-tools。 2. 使用fsck.f2fs工具来检查镜像文件。虽然fsck.f2fs主要用于检查一致性,但它也会输出文件系统的超级信息,也就是头部信息。 3. 也可以使用dump.f2fs工具(同样属于f2fs-tools)来直接导出文件系统的元数据信息,包括超级(也就是头部)的内容。 具体方法: a. 使用fsck.f2fs查看镜像信息: 命令:`fsck.f2fs -i /path/to/image` 注意:`-i`选项用于显示文件系统信息,包括超级的内容。 b. 使用dump.f2fs查看镜像的超级信息: 命令:`dump.f2fs /path/to/image` 该命令会输出大量的元数据信息,其中第一部分就是超级(Superblock)的内容。 另外,我们也可以使用hexdump等工具直接查看镜像的原始头部,但需要知道F2FS超级的具体结构。F2FS的超级位于分区的第二个扇区(即1024字节处),第一个扇区是MBR或保留扇区。因此,我们可以用hexdump查看偏移1024字节开始的内容。 命令示例: 查看头部1024字节(即超级所在位置): `hexdump -C -s 1024 -n 1024 /path/to/image` 但是,使用f2fs-tools提供的工具会更加直观,因为它们会解析结构并显示出来。 因此,推荐使用fsck.f2fs和dump.f2fs。 步骤总结: 1. 安装f2fs-tools: 在Debian/Ubuntu上:`sudo apt install f2fs-tools` 2. 使用fsck.f2fs查看头部信息(超级): ```bash fsck.f2fs -i image_file ``` 输出示例: ``` Info: Segments per section = 1 Info: Sections per zone = 1 Info: sector size = 512 Info: total sectors = 8388608 (4096 MB) Info: MKFS version "Linux version 4.19.0-6-amd64 (debian-kernel@lists.debian.org) (gcc version 8.3.0 (Debian 8.3.0-6)) #1 SMP Debian 4.19.67-2+deb10u2 (2019-11-11)" Info: FSCK version from "f2fs-tools v1.10.0" [FSCK] Unreachable nat entries [0x0 ] [0x0 ] ...(其他信息) ``` 注意:`-i`选项会显示超级中的基本信息,但不显示所有字段。 3. 使用dump.f2fs查看更详细的超级信息: ```bash dump.f2fs image_file ``` 输出会包含超级的详细字段,如: ``` [Superblock] 1024 0x0000: 10 f0 00 00 10 00 00 00 00 00 00 00 00 20 00 00 ............. .. 0x0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ ...(后续还有很多) ``` 注意:dump.f2fs会以十六进制和ASCII形式显示整个元数据区域,其中包括超级、检查点、段摘要等信息。超级位于最前面。 4. 如果只想查看超级部分,可以结合grep(但由于输出是二进制解析,可能不太好直接grep),所以通常我们会查看输出的第一部分,即标记为[Superblock]的部分。 另外,我们还可以使用以下命令来查看超级的结构化信息(需要知道超级在镜像中的偏移,通常是1024字节): `dd if=image_file bs=1024 skip=1 count=1 | hexdump -C` 不过,还是推荐使用f2fs-tools中的工具。 注意事项: - 操作时确保镜像文件没有被挂载,否则可能会损坏。 - 镜像文件必须是完整的F2FS文件系统镜像,如果镜像包含分区表(例如整个磁盘镜像),则需要先定位到F2FS分区的起始位置,然后使用偏移量。可以使用`fdisk -l image_file`查看分区布局,然后用`dd`提取分区。 例如,如果镜像中F2FS分区从2048扇区开始(每个扇区512字节),那么偏移量就是2048*512=1048576字节。然后我们可以用: `dd if=image_file bs=4096 skip=$((1048576/4096)) count=1 | dump.f2fs -` 但dump.f2fs不支持从标准输入读取?查看帮助:dump.f2fs需要文件路径,所以我们可以这样: 先提取分区到一个临时文件,再用dump.f2fs查看。 但是,如果镜像就是纯净的F2FS文件系统(没有分区表),那么直接使用即可。 总结回答: 查看F2FS文件系统镜像头部(即超级)的方法: 1. 使用`fsck.f2fs -i`查看基本信息。 2. 使用`dump.f2fs`查看详细的超级信息(十六进制形式)。 根据引用[3],我们还可以使用`fsck.f2fs`进行一致性检查,但默认不修复。 因此,在回答中,我们将提供这两种方法。 另外,我们也可以提到使用`file`命令来识别文件系统类型,但它可能不会显示详细头部信息: `file image_file` 输出可能是:`image_file: Linux F2FS filesystem (lzo compression) (large files)` 但这不是查看头部,而是识别类型。 所以,回答将包括: - 安装f2fs-tools - 使用fsck.f2fs -i - 使用dump.f2fs 最后,生成相关问题。 </think>### F2FS文件系统头检查方法 F2FS(Flash-Friendly File System)是专为闪存设备优化的文件系统,其头部信息存储在**超级(Superblock)**中。以下是检查F2FS镜像头部的具体方法,基于您提供的引用信息: --- ### ✅ 方法一:使用 `dump.f2fs` 工具(推荐) **步骤**: 1. 安装F2FS工具包: ```bash sudo apt install f2fs-tools # Debian/Ubuntu ``` 2. 查看镜像超级信息: ```bash dump.f2fs /path/to/f2fs.img | head -n 100 # 显示前100行(含超级) ``` **关键输出字段**: - `magic`: F2FS魔数(`0xF2F52010`) - `block_size`: 大小(通常4KB) - `sector_size`: 扇区大小(通常512B) - `segment_count`: 段数量 - `cp_blkaddr`: 检查点位置 - `root_ino`: 根目录的inode号[^3] --- ### ✅ 方法二:使用 `fsck.f2fs` 工具 **适用场景**:检查镜像完整性和头部一致性 ```bash fsck.f2fs -d 2 /path/to/f2fs.img # -d 2显示调试信息 ``` **输出解析**: - 校验超级签名和关键元数据 - 报告镜像格式版本(如"F2FS v1.x") - 检测头部损坏情况(如`[FSCK] Unreachable nat entries`)[^3] --- ### ✅ 方法三:十六进制直接查看(低级检查) **步骤**: 1. F2FS超级位于**1024字节偏移处**: ```bash hexdump -C -s 1024 -n 512 /path/to/f2fs.img ``` 2. **关键字节位置**: - `0x000-0x003`: 魔数 `10 20 F5 F2` - `0x014-0x017`: 日志起始地址 - `0x040-0x043`: 总段数(大端序) ```hex 00000400 f2 f5 20 10 01 00 00 00 00 00 00 00 00 00 04 00 |.. .............| 00000410 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| ``` --- ### ✅ 方法四:结合分区工具(带分区表的镜像) 若镜像是完整磁盘(含分区表): ```bash fdisk -l /path/to/disk.img # 定位F2FS分区偏移 dump.f2fs -o $((偏移量*512)) /path/to/disk.img # 跳转到分区头部 ``` --- ### 📌 注意事项 1. **内核支持**:检查前确保系统加载F2FS: ```bash lsmod | grep f2fs # 确认模加载[^2] ``` 2. **数据安全**:操作前备份镜像,避免意外写入[^1] 3. **启动问题**:若检查发现头部损坏,需重新格式化为F2FS: ```bash mkfs.f2fs -f /dev/sdX # 强制格式化[^1] ``` --- ### 🌟 示例输出解析 ```bash $ dump.f2fs test.img [Superblock] 1024 magic: 0xf2f52010 block_size: 4096 # 大小4KB sector_size: 512 # 扇区大小512B segment_count: 16384 # 总段数 cp_blkaddr: 2 # 检查点位于2 [Checkpoint] 4096 checkpoint_ver: 1 ... ``` 这表明镜像头部完整且符合F2FS规范[^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值