ZFS 会默默覆盖后续的镜像设备,并且不附带任何日志?

ZFS 会默默覆盖后续的镜像设备,并且不附带任何日志?

给定两个镜像驱动器:

  • /dev/loop1zfs1.img
  • /dev/loop2zfs2.img

zfs2.img如果驱动器包含不同的数据,即使副本更新zfs2.img包含额外文件,ZFS 始终默默地使用 的状态zfs1.img,并且覆写所有文件zfs2.img

在这种情况下,最有利的行为是列出所有有冲突的副本并让用户(或管理员)决定。

ZFS 被设计为一个智能文件系统,可以在最少的用户干预下自动执行恢复。但是,ZFS 至少应该留下其操作的日志,尤其是当它决定删除文件时。我搜索了很多次,但没有找到关于此类日志的提及。

重现步骤:

  1. 创建一个简单的镜子。
  2. 将一个公共文件写入两个驱动器,然后导出。
  3. 卸载zfs2.img;仅用 导入zfs1.img,修改公共文件,写入新文件,导出。
  4. 挂载zfs2.img、卸载zfs1.img;只用 导入zfs2.img、修改普通文件、写入新文件二、导出。

在这个阶段:

  • zfs1.img包含通用文件的自身版本和新文件的版本。
  • zfs2.img包含通用文件的一个自己的版本,以及新文件二。通用文件的版本zfs2.img较新。zfs2.img还包含一个额外的新文件二。

继续复现:

  1. 挂载zfs1.img;使用zfs1.imgzfs2.img挂载导入,注意 的版本和文件zfs1.img显示在文件系统中。 的版本和文件zfs2.img不可用。导出。

  2. 挂载zfs2.img、卸载zfs1.img;只导入zfs2.img,注意版本和新文件两个zfs2.img被默默覆盖。 出口。

问题现已重现。尽管 中的版本zfs2.img较新,并且 中有较新的文件zfs2.img,但两者都被覆盖,且没有任何错误消息。

我仍然找不到任何提及此问题的日志。

附加步骤:如果第一个驱动器被替换为空白驱动器,ZFS 不会像通常预期的那样用空白驱动器 1 覆盖驱动器 2。相反,空白驱动器 1 会用驱动器 2 中的数据填充:

  1. 创建一个新的空白驱动器,导入,用新创建的驱动器替换丢失的驱动器一。导出。

重现代码:

(1)创建一个简单的镜子。

print_status() {
printf -- 'vvvvvvvvvvvvvvvvvvvvvvvvvvvv\n'
ls -Al /zpool_test/ ; cat /zpool_test/* ; echo ; losetup ; zpool list -v ; zpool status -v
printf -- '^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n'
}

printf '(1) : Create mirror\n'
tmpdir=$(mktemp -d)
cd "${tmpdir}"
truncate -s 100M "${tmpdir}/zfs1.img"
truncate -s 100M "${tmpdir}/zfs2.img"
loop1=$(losetup -f --show "${tmpdir}/zfs1.img")
loop2=$(losetup -f --show "${tmpdir}/zfs2.img")

/sbin/modprobe zfs

zpool create zpool_test mirror "${loop1}" "${loop2}"

(2)将公共文件写入两个驱动器。

printf '(2) : Write common to both\n'
echo 'common' > /zpool_test/file_common
print_status
zpool export zpool_test

(3)仅在驱动器一中:修改公用文件 & 添加新文件。

printf '(3) : Modify & Add only to one\n'
losetup -d "${loop2}"
zpool import zpool_test
echo 'append one' >> /zpool_test/file_common
echo 'new one' > /zpool_test/file_new_1
print_status
zpool export zpool_test

(4)仅在驱动器二中:修改公用文件 & 添加新文件二。

printf '(4) : Modify & Add only to two\n'
loop2=$(losetup -f --show "${tmpdir}/zfs2.img")
losetup -d "${loop1}"
zpool import zpool_test
echo 'append two' >> /zpool_test/file_common
echo 'new two' > /zpool_test/file_new_2
print_status
zpool export zpool_test

(5)导入两者。仅显示中的版本和文件zfs1.img

printf '(5) : import both one and two\n'
loop1=$(losetup -f --show "${tmpdir}/zfs1.img")
zpool import zpool_test
print_status
zpool export zpool_test

(6)仅导入两个。检查zfs2.img被默默覆盖,没有任何日志。

printf '(6) : import only two\n'
losetup -d "${loop1}"
zpool import zpool_test
print_status
zpool export zpool_test

(7)如果将驱动器一替换为空白驱动器,则空白驱动器将被覆盖。

printf '(7) : if one is replaced with blank\n'
truncate -s 100M "${tmpdir}/zfs_new_1.img"
loop4=$(losetup --show /dev/loop4 "${tmpdir}/zfs_new_1.img")
zpool import zpool_test
zpool replace zpool_test /dev/loop1 /dev/loop4
sleep 1
print_status
zpool export zpool_test

最后但同样重要的一点是,还提供了方便的清理脚本:

zpool import zpool_test
zpool destroy zpool_test
# losetup -d "${loop1}" "${loop2}"
losetup -d "${loop2}" "${loop4}"
rm -rf "${tmpdir}"

相关内容