FreeBSD上的ZFS:从数据损坏中恢复


44

我在zpool中有几TB非常有价值的个人数据,由于数据损坏,我无法访问这些数据。该池最初是在2009年左右在FreeBSD 7.2系统上建立的,该系统在Ubuntu 8.04系统顶部的VMWare虚拟机中运行。FreeBSD VM仍然可用并且运行良好,现在只有主机OS已更改为Debian6。来宾VM可以通过VMWare通用SCSI设备访问硬盘,共有12个。

有2个游泳池:

  • zpool01:2x 4x 500GB
  • zpool02:1x 4x 160GB

工作的是空的,坏掉的保留所有重要数据:

[user@host~]$ uname -a
FreeBSD host.domain 7.2-RELEASE FreeBSD 7.2-RELEASE #0: \
  Fri May  1 07:18:07 UTC 2009                          \
  root@driscoll.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC  amd64

[user@host ~]$ dmesg | grep ZFS
WARNING: ZFS is considered to be an experimental feature in FreeBSD.
ZFS filesystem version 6
ZFS storage pool version 6

[user@host ~]$ sudo zpool status
  pool: zpool01
 state: UNAVAIL
 scrub: none requested
config:

    NAME        STATE     READ WRITE CKSUM
    zpool01     UNAVAIL      0     0     0  insufficient replicas
      raidz1    UNAVAIL      0     0     0  corrupted data
        da5     ONLINE       0     0     0
        da6     ONLINE       0     0     0
        da7     ONLINE       0     0     0
        da8     ONLINE       0     0     0
      raidz1    ONLINE       0     0     0
        da1     ONLINE       0     0     0
        da2     ONLINE       0     0     0
        da3     ONLINE       0     0     0
        da4     ONLINE       0     0     0

  pool: zpool02
 state: ONLINE
 scrub: none requested
config:

    NAME        STATE     READ WRITE CKSUM
    zpool02     ONLINE       0     0     0
      raidz1    ONLINE       0     0     0
        da9     ONLINE       0     0     0
        da10    ONLINE       0     0     0
        da11    ONLINE       0     0     0
        da12    ONLINE       0     0     0

errors: No known data errors

我几个星期前就能进入游泳池。从那以后,我不得不更换主机的几乎所有硬件,并安装几个主机操作系统。

我的怀疑是,其中一个操作系统安装程序为500GB驱动器中的一个(第一个?)写了一个引导加载程序(或其他内容),并破坏了一些zpool元数据(或其他内容)-“或任何内容”意味着这只是一个非常模糊的想法而这个主题并不完全是我的强项...


关于ZFS,有很多网站,博客,邮件列表等。我在此发布此问题,希望它可以帮助我收集足够的信息,以一种理智,结构化,可控制,知情,知识渊博的方法来取回我的数据,并希望能在相同情况下帮助其他人。


谷歌搜索“ zfs restore”时,第一个搜索结果是《Solaris ZFS管理指南》中的“ ZFS故障排除和数据恢复”一章。在第一个ZFS失败模式部分中,它在“损坏的ZFS数据”段落中说:

数据损坏始终是永久性的,在修复过程中需要特别注意。即使修复或更换了基础设备,原始数据也将永远丢失。

有点令人沮丧。

但是,第二个Google搜索结果是Max Bruning的网络日志,我在那里阅读

最近,有人给我发送了一封电子邮件,该人在一个10TB的ZFS池中存储了15年的视频和音乐,在停电后,它就出现了故障。不幸的是,他没有备份。他在FreeBSD 7上使用ZFS版本6 [...]大约花了一周时间检查了磁盘上的数据之后,我基本上能够还原所有数据。

至于ZFS丢失数据,我对此表示怀疑。我怀疑您的数据在那里,但是您需要找到正确的方法来获取它。

(听起来更像是我想听的东西...)

第一步:到底是什么问题?

我如何诊断为什么zpool确切地报告为已损坏?我看到zdb似乎没有在网络上的任何地方被Sun或Oracle正式记录。从其手册页:

NAME
       zdb - ZFS debugger

SYNOPSIS
       zdb pool

DESCRIPTION
       The  zdb  command is used by support engineers to diagnose failures and
       gather statistics. Since the ZFS file system is  always  consistent  on
       disk  and is self-repairing, zdb should only be run under the direction
       by a support engineer.

       If no arguments are specified, zdb, performs basic  consistency  checks
       on  the pool and associated datasets, and report any problems detected.

       Any options supported by this command are internal to Sun  and  subject
       to change at any time.

此外,在2008年6月28日于布拉格举行的Open Solaris Developer Conference上,Ben Rockwood发表了一篇详细的文章,并提供了一个有关Max Bruning 的视频(和mdb)。

在损坏的zpool上以root身份运行zdb会得到以下输出:

[user@host ~]$ sudo zdb zpool01
    version=6
    name='zpool01'
    state=0
    txg=83216
    pool_guid=16471197341102820829
    hostid=3885370542
    hostname='host.domain'
    vdev_tree
        type='root'
        id=0
        guid=16471197341102820829
        children[0]
                type='raidz'
                id=0
                guid=48739167677596410
                nparity=1
                metaslab_array=14
                metaslab_shift=34
                ashift=9
                asize=2000412475392
                children[0]
                        type='disk'
                        id=0
                        guid=4795262086800816238
                        path='/dev/da5'
                        whole_disk=0
                        DTL=202
                children[1]
                        type='disk'
                        id=1
                        guid=16218262712375173260
                        path='/dev/da6'
                        whole_disk=0
                        DTL=201
                children[2]
                        type='disk'
                        id=2
                        guid=15597847700365748450
                        path='/dev/da7'
                        whole_disk=0
                        DTL=200
                children[3]
                        type='disk'
                        id=3
                        guid=9839399967725049819
                        path='/dev/da8'
                        whole_disk=0
                        DTL=199
        children[1]
                type='raidz'
                id=1
                guid=8910308849729789724
                nparity=1
                metaslab_array=119
                metaslab_shift=34
                ashift=9
                asize=2000412475392
                children[0]
                        type='disk'
                        id=0
                        guid=5438331695267373463
                        path='/dev/da1'
                        whole_disk=0
                        DTL=198
                children[1]
                        type='disk'
                        id=1
                        guid=2722163893739409369
                        path='/dev/da2'
                        whole_disk=0
                        DTL=197
                children[2]
                        type='disk'
                        id=2
                        guid=11729319950433483953
                        path='/dev/da3'
                        whole_disk=0
                        DTL=196
                children[3]
                        type='disk'
                        id=3
                        guid=7885201945644860203
                        path='/dev/da4'
                        whole_disk=0
                        DTL=195
zdb: can't open zpool01: Invalid argument

我想最后会出现“无效参数”错误,因为zpool01实际上并不存在:在工作中的zpool02上不会发生此错误,但是似乎也没有任何进一步的输出...

好的,在此阶段,最好在文章过长之前发布此内容。

也许有人可以给我一些有关如何从此处继续前进的建议,而在我等待回应时,我将观看视频,仔细阅读上面zdb输出的详细信息,阅读Bens文章并尝试找出问题所在。什么...


20110806-1600 + 1000

更新01:

我想我已经找到了根本原因:Max Bruning很友好,可以非常迅速地回复我的电子邮件,要求输出zdb -lll。在“良好” raidz1池的一半中的4个硬盘驱动器中,任何一个输出都类似于我在上面发布的内容。但是,在“损坏的”一半的4个驱动器中的前3个中,zdb报告failed to unpack label标签2和3。池中的第四个驱动器似乎可以,zdb显示所有标签。

谷歌搜索错误消息提出了这篇文章。从对该帖子的第一个回复:

使用ZFS,每个物理vdev上有4个相同的标签,在本例中为单个硬盘。L0 / L1位于vdev的开头,L2 / L3位于vdev的结尾。

池中的所有8个驱动器均具有相同型号Seagate Barracuda 500GB。但是,我确实记得我用4个驱动器启动了该池,然后其中一个驱动器死了,并在保修期内由Seagate更换。后来,我又添加了4个驱动器。因此,驱动器和固件标识符不同:

[user@host ~]$ dmesg | egrep '^da.*?: <'
da0:  <VMware, VMware Virtual S 1.0> Fixed Direct Access SCSI-2 device 
da1:  <ATA ST3500418AS CC37> Fixed Direct Access SCSI-5 device 
da2:  <ATA ST3500418AS CC37> Fixed Direct Access SCSI-5 device 
da3:  <ATA ST3500418AS CC37> Fixed Direct Access SCSI-5 device 
da4:  <ATA ST3500418AS CC37> Fixed Direct Access SCSI-5 device 
da5:  <ATA ST3500320AS SD15> Fixed Direct Access SCSI-5 device 
da6:  <ATA ST3500320AS SD15> Fixed Direct Access SCSI-5 device 
da7:  <ATA ST3500320AS SD15> Fixed Direct Access SCSI-5 device 
da8:  <ATA ST3500418AS CC35> Fixed Direct Access SCSI-5 device 
da9:  <ATA SAMSUNG HM160JC AP10> Fixed Direct Access SCSI-5 device 
da10: <ATA SAMSUNG HM160JC AP10> Fixed Direct Access SCSI-5 device 
da11: <ATA SAMSUNG HM160JC AP10> Fixed Direct Access SCSI-5 device 
da12: <ATA SAMSUNG HM160JC AP10> Fixed Direct Access SCSI-5 device 

我确实记得所有驱动器都具有相同的大小。现在查看驱动器,它表明其中三个的大小已更改,它们缩小了2 MB:

[user@host ~]$ dmesg | egrep '^da.*?: .*?MB '
da0:   10240MB (20971520  512 byte sectors: 255H 63S/T 1305C)
da1:  476940MB (976773168 512 byte sectors: 255H 63S/T 60801C)
da2:  476940MB (976773168 512 byte sectors: 255H 63S/T 60801C)
da3:  476940MB (976773168 512 byte sectors: 255H 63S/T 60801C)
da4:  476940MB (976773168 512 byte sectors: 255H 63S/T 60801C)
da5:  476938MB (976771055 512 byte sectors: 255H 63S/T 60801C) <--
da6:  476938MB (976771055 512 byte sectors: 255H 63S/T 60801C) <--
da7:  476938MB (976771055 512 byte sectors: 255H 63S/T 60801C) <--
da8:  476940MB (976773168 512 byte sectors: 255H 63S/T 60801C)
da9:  152627MB (312581808 512 byte sectors: 255H 63S/T 19457C)
da10: 152627MB (312581808 512 byte sectors: 255H 63S/T 19457C)
da11: 152627MB (312581808 512 byte sectors: 255H 63S/T 19457C)
da12: 152627MB (312581808 512 byte sectors: 255H 63S/T 19457C)

因此,从外观上看,并不是“将引导加载程序写入驱动器之一”的操作系统安装(正如我之前假设的那样),实际上是创建2 MB 主机的新主板(华硕P8P67 LE保护区位于三个驱动器末尾,这弄乱了我的ZFS元数据。

为什么没有在所有驱动器上创建HPA?我相信这是因为HPA的创建仅在较旧的驱动器上完成,而该错误后来由Seagate硬盘BIOS更新修复:当整个事件在几周前开始时,我运行Seagate的SeaTools来检查是否存在驱动器出现任何物理故障(仍在旧硬件上),我收到一条消息,告诉我某些驱动器需要BIOS更新。当我现在尝试重现该消息的确切详细信息以及固件更新下载的链接时,似乎是因为主板创建了HPA,所以两个SeaTools DOS版本都无法检测到相关的硬盘驱动器-快速invalid partition或类似的操作当它们开始闪烁时,就是这样。具有讽刺意味的是,他们确实找到了一组三星驱动器。

(我跳过了在非网络系统上的FreeDOS shell中搞砸的痛苦,耗时且最终毫无结果的细节。)最后,我在单独的计算机上安装了Windows 7,以便运行SeaTools Windows版本1.2.0.5。关于DOS SeaTools的最后一句话:不要费心尝试独立启动它们-而是花几分钟时间,用令人敬畏的Ultimate Boot CD制作可启动USB记忆棒-除了DOS SeaTools之外,它还为您带来了许多其他好处有用的工具。

启动时,SeaTools for Windows将显示以下对话框:

SeaTools固件更新对话框

这些链接指向序列号检查器(由于某种原因受验证码保护,我的身份是“入侵用户”)和有关固件更新的知识库文章。可能还有其他特定于硬盘驱动器型号的链接以及一些下载内容和其他内容,但我暂时不会遵循该路径:

我不会急于一次更新三个具有截断的分区并且属于损坏的存储池的驱动器的固件。那是自找麻烦。对于初学者来说,固件更新很可能无法撤消-这可能无法挽回地破坏了我取回数据的机会。

因此,我接下来要做的第一件事是对驱动器进行映像并处理副本,因此,如果出现任何问题,可以使用原始文档。这可能会带来额外的复杂性,因为ZFS可能会注意到已交换驱动器(通过驱动器序列号或另一个UUID或其他方式),即使它已精确地dd复制到同一硬盘驱动器模型上。而且,zpool甚至没有直播。天哪,这可能会很棘手。

但是,另一个选择是使用原始驱动器并将镜像驱动器作为备份,但是当原始驱动器出现问题时,我可能会遇到上述复杂性。a,不好。

为了清除三个硬盘驱动器,它们将用作损坏池中有故障的BIOS的三个硬盘的映像替代品,我需要为那里的东西创建一些存储空间,因此我将深入研究硬件盒,并从一些旧驱动器组装一个临时zpool-我还可以用它来测试ZFS如何处理交换dd驱动器。

这可能需要一段时间...


20111213-1930 + 1100

更新02:

确实确实需要一段时间。我已经花了几个月的时间在桌上放着几个打开的计算机机箱,上面挂着大量的硬盘驱动器,而且还用耳塞睡了几个晚上,因为我无法在睡觉前关闭机器,因为它正在执行长时间的关键操作。但是,我终于占了上风!:-)在此过程中,我也学到了很多东西,我想在这里为处于类似情况的任何人分享这些知识。

本文已经比ZFS文件服务器无法运行的任何人都有时间阅读,因此,我将在此处进行详细介绍,并在下面的基本发现中提供答案。

我在过时的硬件盒中挖了深深的空间,以组装足够的存储空间,以将物料从单个500GB驱动器上移出,已将有缺陷的驱动器镜像到该驱动器上。我还必须从USB盒中取出一些硬盘驱动器,以便可以直接通过SATA连接它们。当涉及到更多,不相关的问题时,当我将它们重新投入使用并需要替换zpool时,一些旧驱动器开始出现故障,但是我将跳过这一点。

提示:在某个阶段,总共涉及约30个硬盘驱动器。有了那么多的硬件,将它们正确地堆叠起来是极大的帮助。电缆松动或硬盘驱动器从您的桌子上掉下来肯定不会对您有帮助,并可能进一步损害您的数据完整性。

我花了几分钟的时间制作了一些临时的硬纸板硬盘固定装置,这些固定装置确实有助于保持分类:

一些临时存储空间 只是一堆螺丝加上一些纸板 风扇不是完全必需的,堆栈来自早期项目 距离件也不是必需的...

具有讽刺意味的是,当我第一次连接旧驱动器时,我意识到必须使用旧版本的zpool创建一个旧zpool,以便测试其中的一些旧版本,但是并不是所有丢失的个人数据都在丢失,因此,稍微减少一点,这意味着需要额外地来回移动文件。

最后,我将有问题的驱动器镜像到备份驱动器,将其用于zpool,并使原始驱动器断开连接。备份驱动器具有较新的固件,至少SeaTools不报告任何必需的固件更新。我使用一个简单的dd从一个设备镜像到另一个设备,例如

sudo dd if=/dev/sda of=/dev/sde

我相信ZFS确实注意到了硬件更改(通过某些硬盘UUID或其他原因),但似乎并不在意。

但是,zpool仍处于相同状态,副本不足/数据损坏。

如前面提到的HPA Wikipedia文章所述,在Linux启动时报告了主机保护区的存在,可以使用hdparm进行调查。据我所知,在FreeBSD上没有可用的hdparm工具,但是到了此时,无论如何我已经将FreeBSD 8.2和Debian 6.0安装为双引导系统,所以我进入了Linux:

user@host:~$ for i in {a..l}; do sudo hdparm -N /dev/sd$i; done

   ...
/dev/sdd:
 max sectors   = 976773168/976773168, HPA is disabled
/dev/sde:
 max sectors   = 976771055/976773168, HPA is enabled
/dev/sdf:
 max sectors   = 976771055/976773168, HPA is enabled
/dev/sdg:
 max sectors   = 976771055/976773168, HPA is enabled
/dev/sdh:
 max sectors   = 976773168/976773168, HPA is disabled
   ...

因此,问题显然是新主板在驱动器的末端创建了几兆字节的HPA,从而“隐藏”了上面两个ZFS标签,即阻止ZFS看到它们。


涉足HPA似乎是一项危险的业务。在hdparm手册页中,参数-N:

Get/set max visible number of sectors, also known as the Host Protected Area setting.
  ...
To change the current max (VERY DANGEROUS, DATA LOSS IS EXTREMELY LIKELY), a new value
should be provided (in base10) immediately following the -N option.
This value is specified as a count of sectors, rather than the "max sector address"
of the drive. Drives have the concept of a temporary (volatile) setting which is lost on
the next hardware reset, as well as a more permanent (non-volatile) value which survives
resets and power cycles.  By default, -N affects only the temporary (volatile) setting.
To change the permanent (non-volatile) value, prepend a leading p character immediately
before the first digit of the value. Drives are supposed to allow only a single permanent
change per session. A hardware reset (or power cycle) is required before another
permanent -N operation can succeed.
  ...

就我而言,将HPA删除为:

user@host:~$ sudo hdparm -Np976773168 /dev/sde

/dev/sde:
 setting max visible sectors to 976773168 (permanent)
 max sectors   = 976773168/976773168, HPA is disabled

对于具有HPA的其他驱动器,以相同的方式进行。如果驱动器错误或您指定的有关size参数的说法不合理,则hdparm足够聪明,可以得出:

user@host:~$ sudo hdparm -Np976773168 /dev/sdx

/dev/sdx:
 setting max visible sectors to 976773168 (permanent)
Use of -Nnnnnn is VERY DANGEROUS.
You have requested reducing the apparent size of the drive.
This is a BAD idea, and can easily destroy all of the drive's contents.
Please supply the --yes-i-know-what-i-am-doing flag if you really want this.
Program aborted.

之后,我重新启动了最初在其上创建zpool的FreeBSD 7.2虚拟机,并且zpool status再次报告了一个工作池。好极了!:-)

我在虚拟系统上导出了池,然后在主机FreeBSD 8.2系统上重新导入了池。

一些更主要的硬件升级,另一个主板交换,一个ZFS池更新到ZFS 4/15,彻底的清理,现在我的zpool由8x1TB加上8x500GB raidz2部分组成:

[user@host ~]$ sudo zpool status
  pool: zpool
 state: ONLINE
 scrub: none requested
config:

NAME        STATE     READ WRITE CKSUM
zpool       ONLINE       0     0     0
  raidz2    ONLINE       0     0     0
    ad0     ONLINE       0     0     0
    ad1     ONLINE       0     0     0
    ad2     ONLINE       0     0     0
    ad3     ONLINE       0     0     0
    ad8     ONLINE       0     0     0
    ad10    ONLINE       0     0     0
    ad14    ONLINE       0     0     0
    ad16    ONLINE       0     0     0
  raidz2    ONLINE       0     0     0
    da0     ONLINE       0     0     0
    da1     ONLINE       0     0     0
    da2     ONLINE       0     0     0
    da3     ONLINE       0     0     0
    da4     ONLINE       0     0     0
    da5     ONLINE       0     0     0
    da6     ONLINE       0     0     0
    da7     ONLINE       0     0     0

errors: No known data errors

[user@host ~]$ df -h
Filesystem         Size    Used   Avail Capacity  Mounted on
/dev/label/root     29G     13G     14G    49%    /
devfs              1.0K    1.0K      0B   100%    /dev
zpool              8.0T    3.6T    4.5T    44%    /mnt/zpool

最后,在我看来ZFS池非常非常难以杀死。创建该系统的来自Sun的人有充分的理由将其称为文件系统中的最后一句话。尊重!


2
在执行任何操作之前,请对这些驱动器进行映像!如果您的“损坏”数据变得更糟,请对其进行备份。
MikeyB 2011年

是的,这是非常好的一点!这也是为什么我尚未根据进度更新本文的原因-仍在忙于清理替换硬盘...
ssc

Answers:


24

问题在于新主板的BIOS在某些驱动器上创建了一个主机保护区(HPA),OEM将其用于系统恢复的一小部分通常位于硬盘驱动器的末端。

ZFS维护4个带有分区元信息的标签,而HPA阻止ZFS看到前两个标签。

解决方案:引导Linux,使用hdparm检查并删除HPA。请非常小心,这很容易永久破坏您的数据。有关详细信息,请查阅本文和hdparm手册页(参数-N)。

该问题不仅发生在新主板上,而且在将驱动器连接到SAS控制器卡时遇到了类似的问题。解决方法是相同的。


5

我建议您做的第一件事是使用该dd命令获得更多的硬盘驱动器,并使用其中的数据制作8个驱动器的副本。这样,如果尝试恢复它们最终使情况变得更糟,则仍可以返回此基准。

我以前做过,有时候我不需要它,但是我确实需要它,这使它完全值得付出。

没有网络就不要工作。


其实,我建议ddrescuedd。当驱动器正常工作时,它的工作原理并没有太大的不同(但是确实可以为您提供良好的进度指示),但是,如果有任何问题扇区或类似的东西,ddrescue处理这种情况要比dd更好(或者我被告知)。
CVn

2

您似乎正在解决这个问题。如果您需要另一种(可能是较新的)观点,可以尝试使用Solaris 11 Express live CD。那里可能运行着许多新代码(Solaris中的zpool现在是版本31,而您在版本6中),它可能提供更好的恢复可能性。zpool upgrade但是,如果要使池在FreeBSD下可安装,则不要在Solaris下运行。


感谢您的提示!:-)早在2009年左右开始整个ZFS业务时,我就在研究OpenSolaris,但不幸的是,它不支持我使用的控制器-毕竟这是消费级硬件。就在最近,我也看过OpenIndiana,但不确定情况是否已改变。我可能会在某个阶段将控制器升级到SAS,然后考虑迁移。
ssc

我认为OpenIndiana可能值得一新。如果没有别的,他们可能比Oracle更便宜“便宜”的硬件...我推荐实时CD,因为它很容易试用-您也可以在VM中运行它。
雅各布·伯格

1

FreeBSD邮件列表可能是您搜索的一个很好的起点。我记得曾经在FreeBSD-Stable和-Current上看到过类似的请求。但是,根据数据的重要性,您可能希望联系专业的恢复公司,因为篡改无法访问的数据存储池很可能使情况变得更糟。


1

从FreeBSD 10.3升级到11.1后,我遇到了类似的问题,此后zpool出现了故障,即使zdb -lll恢复了所有四个标签都有效,也无法恢复数据。

事实证明,该更新以某种方式触发了Intel存储管理驱动程序从磁盘中创建软RAID镜像(也许已启用,但geom直到更新后才受Intel提供程序支持吗?),并且阻止了ZFS挂载磁盘。

将它们连接到启用了Intel RST引导时间固件的另一台PC上,并禁用软raid(非常重要:两种方法可以破坏软raid,默认的方法是初始化(也称为格式化!)磁盘。您需要选择以下选项:禁用而不用触摸数据),然后让ZFS识别镜像中的第一个磁盘,尽管我没有做任何事情允许它将其余磁盘标识为与机器更新前的磁盘相同。幸运的是,这是一个镜像的zpool,我能够将磁盘拆离并重新连接到有问题的池中,并且重新安装完成而没有任何事件。

旁注:就我而言,hdparm(从实时Ubuntu Server ISO运行)报告说,所有磁盘上的HBA均已禁用,无法提供帮助。


-2

如果这只是某种分区问题,我会dd驱动器分区+ MBR,然后使分区的大小正确...

如果您不格式化分区,则只要没有格式,创建或更改分区表就不会有任何影响(因此您可以回滚!),那么如果插入了新分区,则大多数数据仍可访问在驱动器的末尾,您可能有损坏的文件,在那儿很难写出新的东西,这就是为什么只有格式化(新的mbr,文件表等)后,您才有该技巧的原因

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.