如何获取一个文件的 Btrfs 验证校验和?

如何获取一个文件的 Btrfs 验证校验和?

Btrfs 提供以下命令来验证数据完整性/校验和:

btrfs scrub start <path>|<device>
btrfs check --check-data-csum

然而,据我所知,这些总是验证所有的文件系统;该path参数用于识别设备上的文件系统,而不是文件系统内的文件/目录。

现在,我有一个 3TB 的 Btrfs 文件系统。清理它需要几个小时。有时我需要确保只有某些文件/目录尚未受到 bitrot 的影响 — 例如,在使用 *.iso 安装映像或恢复备份之前。如何使用 Btrfs— 无需再为每个文件保留手动哈希文件?

我知道 Btrfs 不存储单个文件的校验和 — 它存储的是数据块。在这种情况下,我正在寻找一个命令/工具,它可以识别用于存储某些文件/目录的所有块并仅验证这些块。

我在某处读到过 Btrfs 据称可以验证校验和。也就是说,如果文件已经发生位腐烂,则读取文件会失败或类似情况。是这样吗?

答案1

答案是:简单尝试读取整个文件。如果读取的内容与校验和不同,则会出现输入/输出错误。所以是的,Btrfs 确实在读取时验证了校验和!

为了找到这个答案,我做了以下测试:

  1. 分配一个 1 Gb 文件作为块设备来测试 Btrfs 分区,将其挂载为循环设备并在其上格式化 Btrfs;
  2. 创建一个虚拟的 800 Mb 文件,其中包含中间已知的唯一字节序列(token1);
  3. 将文件写入Btrfs并记录其sha256以供日后参考;
  4. 卸载并修补块设备文件,以便更改一个字节。为此,我们用sed-replace 替换;token1token2
  5. 再次挂载并尝试获取 Btrfs 上 800 Mb 文件的 sha256。请参阅输入/输出错误;
  6. 卸载,重新补丁,挂载并查看 800 Mb 文件是否再次可读,并且 sha256 与步骤 3 中相同;
  7. 利润!

脚本如下:

#!/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 与未损坏的文件不同。

相关内容