Btrfs 提供以下命令来验证数据完整性/校验和:
btrfs scrub start <path>|<device>
btrfs check --check-data-csum
然而,据我所知,这些总是验证所有的文件系统;该path
参数用于识别设备上的文件系统,而不是文件系统内的文件/目录。
现在,我有一个 3TB 的 Btrfs 文件系统。清理它需要几个小时。有时我需要确保只有某些文件/目录尚未受到 bitrot 的影响 — 例如,在使用 *.iso 安装映像或恢复备份之前。如何使用 Btrfs— 无需再为每个文件保留手动哈希文件?
我知道 Btrfs 不存储单个文件的校验和 — 它存储的是数据块。在这种情况下,我正在寻找一个命令/工具,它可以识别用于存储某些文件/目录的所有块并仅验证这些块。
我在某处读到过 Btrfs 据称可以验证校验和读。也就是说,如果文件已经发生位腐烂,则读取文件会失败或类似情况。是这样吗?
答案1
答案是:简单尝试读取整个文件。如果读取的内容与校验和不同,则会出现输入/输出错误。所以是的,Btrfs 确实在读取时验证了校验和!
为了找到这个答案,我做了以下测试:
- 分配一个 1 Gb 文件作为块设备来测试 Btrfs 分区,将其挂载为循环设备并在其上格式化 Btrfs;
- 创建一个虚拟的 800 Mb 文件,其中包含中间已知的唯一字节序列(
token1
); - 将文件写入Btrfs并记录其sha256以供日后参考;
- 卸载并修补块设备文件,以便更改一个字节。为此,我们用
sed
-replace 替换;token1
token2
- 再次挂载并尝试获取 Btrfs 上 800 Mb 文件的 sha256。请参阅输入/输出错误;
- 卸载,重新补丁,挂载并查看 800 Mb 文件是否再次可读,并且 sha256 与步骤 3 中相同;
- 利润!
脚本如下:
#!/bin/bash
f="btrfstestblockdevicefile"
ft="btrfstestfile"
loop="/dev/loop0"
mount_dir="btrfstestdir"
size="1g"
token1="36bbf48aa6645646fbaa7f25b64224fb3399ad40bc706c79bb8276096e3c9e8f"
token2="36bbf48aa6645646fbaa7f25b64224fb4399ad40bc706c79bb8276096e3c9e8f"
f_mount() {
echo "Mounting..." && \
sudo losetup $loop $f && \
if ! [[ -z $1 ]] ; then
sudo mkfs.btrfs -q $loop
fi
mkdir $mount_dir && \
sudo mount $loop $mount_dir
}
f_umount() {
echo "Unmounting..." && \
sudo umount $loop && \
sudo rmdir $mount_dir && \
sudo losetup -d $loop
}
echo "Allocating file for test block device..." && \
fallocate -l $size $f && \
f_mount 1 && \
echo "Generating test file..." && \
dd if=/dev/urandom of="${ft}1" bs=1M count=400 status=none && \
echo $token1 > "${ft}2" && \
dd if=/dev/urandom of="${ft}3" bs=1M count=400 status=none && \
sudo sh -c "cat ${ft}1 ${ft}2 ${ft}3 > ${mount_dir}/${ft}" && \
rm "${ft}1" "${ft}2" "${ft}3" && \
echo "Calculating original hash of the file..." && \
sha256sum "${mount_dir}/${ft}" && \
f_umount && \
echo "Patching the file in the block device file..." && \
sed -i "s/${token1}/${token2}/g" $f && sync && \
f_mount && \
echo "Trying to read the file..." && \
sha256sum "${mount_dir}/${ft}"
echo "OK, unmount, patch back and try again..." && \
f_umount && \
sed -i "s/${token2}/${token1}/g" $f && sync && \
f_mount && \
sha256sum "${mount_dir}/${ft}" && \
echo "Yay, Btrfs rules! Cleaning up..." && \
f_umount && \
rm $f && \
echo "All clear!"
正如预期,mkfs.btrfs
用 创建非校验和文件系统(例如mkfs.ext4
)替换可以读取损坏的文件。当然,它的 sha256 与未损坏的文件不同。