从单个旧镜像恢复/导入 ZFS 池

Ath*_*ius 7 linux zfs data-recovery

前几天我在处理 ZFS 池时犯了几个严重错误(同时在修复错误时误读了一些在线建议)并意外地“创建”了一个名为backup. (是的,我-f在它抱怨后使用了这个选项。现在我知道再也不要这样做了。)

无论如何,几个月前我碰巧从同一个池中取出了第三个镜像驱动器,因为它变老了,我不想等待它开始出现故障。所以,我想我可以交换这个驱动器并用它来恢复池。(我只是错过了过去几个月的备份,这主要是这个池的用途。)

但是,我似乎无法使用这个旧驱动器导入池。起初,我认为这可能与backup我不小心创建(然后销毁)的新池的名称冲突有关。但即使尝试通过 GUID 导入,我也一无所获。

这是 zdb -l /dev/sdb1 (这是第三个驱动器)的输出

------------------------------------
LABEL 0
------------------------------------
    version: 5000
    name: 'backup'
    state: 0
    txg: 0
    pool_guid: 3936176493905234028
    errata: 0
    hostid: 8323329
    hostname: [omitted]
    top_guid: 14695910886267065742
    guid: 17986383713788026938
    vdev_children: 1
    vdev_tree:
        type: 'mirror'
        id: 0
        guid: 14695910886267065742
        whole_disk: 0
        metaslab_array: 34
        metaslab_shift: 33
        ashift: 12
        asize: 1000197324800
        is_log: 0
        create_txg: 4
        children[0]:
            type: 'disk'
            id: 0
            guid: 17914838236907067293
            path: '/dev/sdd1'
            whole_disk: 0
            DTL: 143
            create_txg: 4
        children[1]:
            type: 'disk'
            id: 1
            guid: 17986383713788026938
            path: '/dev/sdb1'
            whole_disk: 0
            DTL: 141
        children[2]:
            type: 'disk'
            id: 2
            guid: 1683783279473519399
            path: '/dev/sdc1'
            whole_disk: 0
            DTL: 145
            create_txg: 4
    features_for_read:
        com.delphix:hole_birth
        com.delphix:embedded_data
    create_txg: 0
    labels = 0 1 2 3 
Run Code Online (Sandbox Code Playgroud)

因此,根据 zdb 的说法,驱动器上的驱动器和池数据似乎完好无损。但是,导入池(即使使用-f和/或-F)只会得到“无法导入...没有可用的池”错误。我也尝试在上述信息中使用各种 GUID(因为我不确定 GUID 是否是相关的),但是这些命令(例如,zpool import 3936176493905234028)除了“没有可用的池”消息之外没有任何其他信息。

自从删除该驱动器后,我已经安装了新版本的 Linux 操作系统,因此我认为使用zpool.cache我设法从旧操作系统恢复的旧文件可能会有所作为。但命令 zpool import -c zpool.cache只是给出:

  pool: backup
     id: 3936176493905234028
  state: UNAVAIL
 status: One or more devices contains corrupted data.
 action: The pool cannot be imported due to damaged devices or data.
   see: http://zfsonlinux.org/msg/ZFS-8000-5E
 config:

    backup      UNAVAIL  insufficient replicas
      mirror-0  UNAVAIL  insufficient replicas
        sdd1    FAULTED  corrupted data
        sdc1    FAULTED  corrupted data
Run Code Online (Sandbox Code Playgroud)

这有点在意料之中。这些是池被我的 create 命令覆盖的两个磁盘。但是,sdb1 没有被列为那里的潜在驱动器——可能是因为我在取出磁盘后将它从池中删除了。尽管如此,我认为我在 sdb1 上有一个完整的旧镜像数据副本,zdb 同意。为什么不导入?

还有什么可以尝试的建议吗?要运行的其他诊断命令?


注意:我尝试在 Server Fault 上询问这个问题(有关我的情况的更多详细信息,请参阅链接),但我没有得到任何反馈,并意识到特定的 Linux 实现可能对找出解决此问题的方法很重要。我真诚地感谢任何建议或建议。


更新:我想我可能已经发现了问题。我以为我在发出detach命令之前已经删除了备用驱动器。事实上,我仍然看到标签信息(当其他在线来源似乎表明detach破坏了池元数据时)似乎证实了这一点。我注意到我可以简单地输入zdb -l backup和获取标签信息(并使用 获取超级块信息-u),因此即使没有明确指向设备,zfs 似乎也能看到池。它只是出于某种原因不想导入它。

但是,我不再确定detach状态。我遇到了这个关于从分离的镜像中恢复 ZFS 池的旧线程,它对txg零值进行了神秘的引用。其他地方也有提到 uberblocks 在detach.

好吧,我的矿backup池中的 uberblock确实列出了txg = 0(而我在其他地方拥有的活跃 zpool 在该领域中有大量数字,而不是零)。虽然有一个现有的超级块,但只有一个,其他的都backup被列为“无效”。不幸的是,我似乎无法在zdb网上轻松找到任何有关任何内容的文档。

我认为这意味着备用的第三个驱动器已分离?谁能证实我的解释?但是,如果驱动器数据在其他方面完好无损,有没有办法从中恢复?虽然网上的一些建议表明分离的镜像在不重新同步的情况下是不可恢复的,我上面链接的线程有 Solaris 的代码,它似乎做了一个相当简单的功能来欺骗标签认为 uberblock 是好的。进一步探查后,我发现该实用程序的 Solaris 版本仅在三年前才更新

假设我的理解是正确的并且我的第三个镜像已分离,我可以在 Linux 中尝试类似的 uberblock 标签修复吗?尝试重写 Solaris 代码以将其移植到 Linux 是我唯一的选择吗?(我不确定我能做到这一点。)

老实说,鉴于在线多次引用此类场景,我对 ZFS 缺乏合理的数据恢复工具感到惊讶。似乎终于有一些针对常见问题的基本数据恢复选项(包括恢复由create命令覆盖的池的可能性;这似乎对我不起作用),但除此之外- Solaris 的关闭脚本,我看不到任何处理分离设备的内容。令人非常沮丧的是,ZFS 池可能无法导入的原因至少有十几种(有时是很容易恢复的琐碎事情),而且几乎没有进行故障排除、正确的错误代码或文档。

同样,任何帮助、想法或建议将不胜感激。 即使有人可以推荐一个更好的地方来询问这个问题,我也会非常感激。

UPDATE2:也有可能该设备只是offline按照我想的那样放置。我读过很多帖子,说离线设备最终也可能无法作为单个镜像导入。而且由于元数据和 zdb 输出对于 ZFS 的记录很差,我真的不知道如何在不阅读数千行源代码的情况下确定 uberblock 和标签数据的含义。

Ath*_*ius 3

好吧,我已经很接近了,并且认为我已经找到了康复之路。由于我还没有收到其他人的建议,所以我将发布到目前为止我学到的东西。

概括:

  • 有一个未维护的、非官方支持的labelfix实用程序,用于修复某些类型的损坏(和脱机/分离)ZFS 卷上的标签,可用于使不可导入的池变得可导入。
  • 在执行任何操作之前,请务必克隆旧的备用设备,并且仅对克隆进行操作。
  • 如果您遇到问题中所述的情况,有两个同名的池(由于错误create或其他错误),请确保仅插入要恢复的特定池的设备。
  • 此外,删除可能曾经与您要恢复的池关联但出现故障的任何设备。(即使您认为您已经完全破坏了任何其他池并断开了这些设备的关联,这也适用。恢复工具将尝试将旧池的碎片拼凑在一起,并可能读取旧标签/超级块以以不可预测的方式组合设备和数据。)

更多细节:

似乎有一种方法可以从 Linux 上的 zpool 恢复脱机和分离的驱动器。用户 jjwhitney 创建了我在问题中提到的labelfix 实用程序的端口,最初由 Jeff Bonwick(ZFS 的发明者)在大约 12 年前编写。由于我无法理解的原因,该实用程序尚未合并到 ZFS 版本中,尽管当由于标签无效而导致导入失败时,它允许恢复完整池的数据。(关于这个问题的一些讨论在这里。)

(旁注:这个过程让我意识到一件事是,ZFS 恢复工具严重缺乏,如果没有始终运行的数据的完整备份,任何人都不应该使用此文件系统进行任何操作。并且不要依赖于旧的镜像除非您确定它是可导入的,否则将硬盘放在您的衣柜中作为最后机会的备份。当 ZFS 合作时,ZFS 显然非常擅长维护数据完整性,但非常脆弱。当它损坏时 - 或者您做了一些小但愚蠢的事情 - - 即使完好无损,您的数据也可能完全无法访问和读取。)

无论如何,labelfix 实用程序已经 5 年没有更新了,因此它不能使用现代 ZFS 库文件进行编译。幸运的是,我仍然安装了原始操作系统版本,并且可以启动到该版本,然后下载Linux 上的旧 ZFS源代码包,并使用它来获取适当的 ZFS 库并在系统上构建环境,一切仍然有效。(我开始调整 labelfix 实用程序以尝试使用现代 ZFS 库,但这似乎有点危险,因为我对需要修复以对应当前代码库的所有内部结构了解甚少。更容易在其上构建它旧版本。)

看哪,labelfix立即轻松地将我设备上的标签重写为zpool import至少可以解释的内容!

我应该说,ddrescue在尝试执行任何操作之前,我曾经从原始驱动器复制整个内容。我强烈建议这样做,因为可能会犯错误,就像我所做的那样。我不小心写的原始池被命名为backup,因此zdb开始看到不同backup池的多个版本,并且无法弄清楚为什么所有元数据都不匹配。我必须调整vdev_validate_skip=1ZFS 内核模块才能导入池,但随后只是导入了较新的 backup池(不是我想要的池)。请注意,即使我指定了我想要的驱动器的确切路径,也会发生这种情况import:当使用此方法强制导入时,它似乎完全忽略了我的规范,并使用与未在列表中列出的设备完全不同的配置。命令。

幸运的是,我已经对驱动器进行了另一个克隆,因此我可以尝试另一次运行。然而,labelfix它也很聪明,似乎可以读取当前的驱动器配置,因此它发现我有两个旧驱动器,其中第一个backup池中的“数据已损坏”。不幸的是,腐败意味着“固定”标签不仅将池列为DEGRADED而且也FAULTED将其列为“无法” import

此时我意识到我只需拔掉所有旧驱动器并在系统中完全没有它们的情况下工作,以避免破坏恢复尝试。不幸的是,labelfix似乎只能修复一次,所以我现在要克隆该驱动器的#3(当前正在从我的第一个备份克隆进行复制)。一旦克隆过程完成,我将labelfix在没有任何其他旧驱动器存在的情况下运行,并希望我能获得一个DEGRADED可以使用的池import

  • 我只是想向将来遇到此问题的任何人指出,尽管 labelfix 实用程序似乎确实在 zdb 和 zpool import 命令可以看到的内容方面做了一些事情,但我从未能够成功导入驱动器。然而,ZFS 恢复实用程序只需花费约 50 美元即可轻松快速、轻松地找到所有文件。所有数据似乎都完好无损。遗憾的是,ZFS 中没有内置基本功能来在导入失败时访问完整且未损坏的数据。 (2认同)