ZFS 池破坏实验
作者:みんみん
最后更新于 2022-12-08
引言
ZFS 文件系统本身就内置了校验和机制,在读取数据时会实时检查校验和与数据的完整性,确保数据没有损坏。
执行命令 zpool scrub 后,会读取所有已写入的数据部分并与校验和进行一致性检查。如果在 scrub 过程中发现了错误,在具有冗余结构(如镜像或 RAID-Z 等)的情况下,错误会被自动修复。
在这里,我们将实验性地修改 ZFS 管理范围外的数据,故意制造校验和不一致的情况,以引发数据错误。
本实验在 FreeBSD 上进行,但如果是在 Ubuntu 等 Linux 系统上的 ZFS,虽然分区创建和磁盘设备名称可能会有所不同,但 ZFS 操作的命令是相同的。
为实验磁盘创建分区
首先,创建实验用的 ZFS 池。我们将在 USB 磁盘 da1 上进行实验。
准备一块带 GPT 标签的磁盘。
$ gpart create -s gpt da1创建一个 4GB 的分区。
$ gpart add -t freebsd-zfs -a 4k -s 4g -l ttt da1检查创建的分区。
$ gpart show da1
=> 40 312581728 da1 GPT (149G)
40 8388608 1 freebsd-zfs (4.0G)
8388648 304193120 - free - (145G)
$ gpart show -l da1
=> 40 312581728 da1 GPT (149G)
40 8388608 1 ttt (4.0G)
8388648 304193120 - free - (145G)创建 ZFS 池
通常情况下,为了节省磁盘空间,当创建 ZFS 池时会使用 -O compression=lz4 等选项启用压缩功能,但本次实验为了写入零数据而没有启用压缩选项。因为启用压缩后,数据压缩会导致数据大小无法被实际写入。
检查创建的 ZFS 池。
写入虚拟数据
Scrub 只会检查已经写入的数据部分的完整性。为了破坏已写入的数据,我们将首先创建一个内容为零的文件。
进入 ZFS 池内的目录。
使用 dd 命令从 /dev/zero 读取虚拟数据(即零数据)并填充整个池。
可以看到,池已被填满。此处我们显式使用 -b 选项以便查看块数。
故意破坏数据以制造不一致
池已填满后,我们将故意制造 ZFS 校验和错误。由于通过 ZFS 进行的修改无法破坏数据,我们将从 ZFS 管理外部向磁盘写入垃圾数据。
首先导出池。
接着在相关分区的适当位置写入一个块的垃圾数据。
检查是否损坏
导入池并尝试读取之前创建的文件
如上所示,发生了错误。池的状态如下,乍一看似乎没有错误。
尝试执行 scrub。
等待 scrub 完成后,使用 status 进行确认。
可以看到,CKSUM 发生了错误。实际损坏的文件可以通过选项 -v 进行确认。
重新读取 /ztest/dummy 时,错误依旧存在。
修复损坏部分并确认
接下来,通过重新写 0 来恢复损坏的部分。
这应该已经将数据恢复到原状态,再次尝试读取。
如上所示,读取成功且没有错误。虽然 zpool status 中的错误信息依然存在,但 CKSUM 的错误计数已经变为 0。
重新执行 scrub
scrub 完成后,检查池的状态。
如上所示,错误已消失。
最后更新于
这有帮助吗?