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

Gre*_*ake 7 filesystems checksum btrfs data-integrity

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

btrfs scrub start <path>|<device>
btrfs check --check-data-csum
Run Code Online (Sandbox Code Playgroud)

但是,AFAIK 总是验证整个文件系统;的path参数是识别设备的文件系统内,而不是文件/目录上一个文件系统。

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

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

我在某处读到 Btrfs 据称会在 read 上验证校验和。也就是说,如果一个文件已经位腐烂,读取它就会失败或类似的事情。是这种情况吗?

Gre*_*ake 8

答案是:只需尝试读取整个文件。如果它读取的内容与校验和的内容不同,则会出现Input/output error。所以是的,Btrfs 确实在读取时验证校验和!

为了找出这个答案,我进行了以下测试:

  1. 分配一个1Gb的文件作为测试Btrfs分区的块设备,挂载为loop设备,并在其上格式化Btrfs;
  2. 创建一个 800 Mb 的虚拟文件,在中间 ( token1)包含一个已知的唯一字节序列;
  3. 将文件写入Btrfs并记录其sha256以备后用;
  4. 卸载并修补块设备文件,以便更改一个字节。对于这一点,我们sed-replacetoken1token2;
  5. 再次挂载并尝试在 Btrfs 上获取 800 Mb 文件的 sha256。请参阅输入/输出错误;
  6. 卸载,patch back,mount,再次看到800Mb的文件可读,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!"
Run Code Online (Sandbox Code Playgroud)

正如预期的那样,替换mkfs.btrfs为非校验和文件系统(例如mkfs.ext4)允许读取损坏的文件。当然,它的 sha256 与未损坏的不同。