我在zpool中有几个非常有价值的个人数据的TB,由于数据损坏而无法访问。 该池最初是在2009年左右在Ubuntu 8.04系统之上的VMWare虚拟机内部运行的FreeBSD 7.2系统中build立起来的。 FreeBSD VM仍然可用并且运行正常,只有主机操作系统已经变成Debian 6.通过VMWare通用SCSI设备可以访问guest虚拟机,总共12个硬盘。
有2个游泳池:
工作的人是空的,破碎的人掌握着所有的重要资料:
[user@host~]$ uname -a FreeBSD host.domain 7.2-RELEASE FreeBSD 7.2-RELEASE #0: \ Fri May 1 07:18:07 UTC 2009 \ [email protected]:/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的网站,博客,邮件列表等。 我在这里发布这个问题,希望能够帮助我收集足够的信息,使我能够获得足够的信息,以获得理智的,结构化的,可控的,知情的,知识丰富的方法来获取我的数据,并希望在相同的情况下帮助其他人。
search“zfs recover”时的第一个search结果是“Solaris ZFSpipe理指南”中的“ ZFS故障排除和数据恢复”一章。 在第一个ZFS故障模式部分,它在“损坏的ZFS数据”段落中说:
数据损坏永远是永久性的,需要在维修时特别考虑。 即使底层设备被修复或更换,原始数据也将永远丢失。
有点令人沮丧。
然而,第二个谷歌search结果是Max Bruning的博客 ,在那里,我读了
最近,我收到了一封电子邮件,这个人有一个15年的video和音乐存储在一个10TB的ZFS池中,在电源故障后出现故障。 他不幸没有备份。 他在FreeBSD 7上使用ZFS版本6 […]花了大约1周时间检查磁盘上的数据,我基本上能够恢复所有的数据。
和
至于ZFS丢失你的数据,我怀疑它。 我怀疑你的数据在那里,但是你需要find正确的方法来处理它。
(这听起来更像是我想听到的东西…)
第一步 :究竟是什么问题?
我怎样才能诊断为什么zpool被报告为损坏? 我看到有一个zdb,它似乎没有被Sun或Oracle正式logging在网上的任何地方。 从其手册页:
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.
另外,Ben Rockwood发表了一篇详细的文章 ,2008年6月28日在布拉格的Open Solaris开发者大会上有一个Max Bruning的video (和mdb)。
在损坏的zpool上以根用户身份运行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上,但似乎没有任何进一步的输出…
好吧,在这个阶段,最好在文章太久之前发表。
也许有人可以给我一些关于如何从这里前进的build议,而当我在等待回应时,我会观看video,通过上面的zdb输出的细节,阅读本文文章,并试图找出什么是什么…
20110806-1600 + 1000
我想我已经find了根本原因:Max Bruning很友善地回复我的电子邮件,要求输出zdb -lll 。 在“good”raidz1池中的4个硬盘驱动器中,输出结果与我在上面发布的类似。 但是,在“损坏”一半的4个驱动器的前3个中, zdb报告failed to unpack label为标签2和3 failed to unpack label 。池中的第四个驱动器似乎正常, zdb显示所有标签。
谷歌search该错误消息提出了这个职位 。 从对这个职位的第一反应:
使用ZFS,在每个物理vdev上有4个相同的标签,在这种情况下是单个硬盘驱动器。 vdev开始时的L0 / L1,vdev结束时的L2 / L3。
希捷Barracuda 500GB硬盘中的所有8个硬盘都是相同的型号。 不过,我记得我用4个驱动器启动了游泳池,其中一个死了,并在希捷的保修期内更换。 之后,我又添加了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
我记得尽pipe所有的驱动器都有相同的大小。 现在看驱动器,显示其中三个已经改变了大小,缩小了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)
所以从外观上来看,它并不是“把一个引导程序写到一个驱动器上”的操作系统安装(就像我以前所想的那样),它实际上是新的主板(一个华硕P8P67 LE ),创build一个2 MB的主机保护区在三个驱动器结束了我的ZFS元数据。
为什么不在所有驱动器上创buildHPA? 我相信这是因为HPA的创build只是在旧驱动器上完成的,后来由希捷硬盘BIOS更新修复了一个错误:几周前当这个事件发生时,我运行了希捷的SeaTools来检查是否存在硬盘的任何物理错误(仍然在旧硬件上),并且我收到一条消息,告诉我有些驱动器需要BIOS更新。 正如我现在试图重现该消息的确切细节和固件更新下载的链接,似乎自主板创buildHPA,SeaTools DOS版本都无法检测有问题的硬盘 – 一个快速invalid partition或当他们开始时类似的闪光,就是这样。 具有讽刺意味的是,他们确实find了一组三星硬盘。
(我跳过了非联网系统上的FreeDOS shell的痛苦,耗时和最终没有成果的细节)。最后,我在一台单独的机器上安装了Windows 7以运行SeaTools Windows版本1.2.0.5。 关于DOS SeaTools的最后一句话:不要试图单独启动它们,而是投入几分钟的时间,用真棒Ultimate Boot CD制作一个可启动的USB存储器 – 除了DOS以外,SeaTools还能为你带来许多其他的有用的工具。
启动时,SeaTools for Windows将显示此对话框:

链接导致序列号检查器 (出于某种原因,由validation码保护 – 我的是“入侵用户”)和关于固件更新的知识库文章 。 有可能进一步链接特定于硬盘驱动器模型和一些下载,什么不是,但我现在不会沿着这条路:
我不会急于更新三个驱动器的固件,一次是截断分区并且是破损的存储池的一部分。 这是在惹麻烦 对于初学者来说,固件更新很可能无法撤销 – 这可能会不可挽回地破坏我获取数据的机会。
因此,接下来我要做的第一件事是形象驱动器,并与副本的工作,所以有一个原始的东西,如果出现任何错误。 这可能会带来额外的复杂性,因为ZFS可能会注意到驱动器被交换(通过驱动器序列号或另一个UUID或其他),即使它是位精确的dd拷贝到相同的硬盘驱动器模型。 此外,zpool甚至没有生活。 男孩,这可能会变得棘手。
然而,另一种select是使用原件并将镜像驱动器作为备份,但是当原件发生错误时,我可能会遇到上述的复杂情况。 Naa,不好。
为了清除三个硬盘,这三个硬盘将作为三个驱动器的映像replace,在破碎的池中有一个错误的BIOS,我需要为现在的东西创build一些存储空间,所以我会深入挖掘硬件盒,并从一些旧的驱动器组装一个临时的zpool – 我也可以用它来testingZFS如何处理交换dd'd驱动器。
这可能需要一段时间…
20111213-1930 + 1100
这确实需要一段时间。 我花了好几个月在桌子上打开了几个打开的电脑机箱,里面挂着不同数量的硬盘,还用耳塞睡了几个晚上,因为在睡觉前我不能closures机器,因为它正在运行一些冗长的关键操作。 然而,我终于战胜了! :-)我也在这个过程中学到了很多东西,我想在这里为处于类似情况的人们分享这些知识。
这篇文章已经比任何一个ZFS文件服务器都没有时间阅读的时间长了,所以我将在这里详细讨论下面的重要发现。
我深入挖掘了过时的硬件盒,组装了足够的存储空间,以便将有缺陷的驱动器映射到的单个500GB驱动器上的东西移出。 我还不得不从他们的USB机箱里掏出一些硬盘,所以我可以直接通过SATA连接它们。 还有一些更不相关的问题,一些旧的驱动器开始失败,当我把它们放回需要zpoolreplace的行动,但我会跳过这一点。
提示:在某个阶段,共有大约30个硬盘参与其中。 有了这么多的硬件,将它们正确堆叠起来是一个巨大的帮助; 电缆松动或硬盘掉落在桌面上肯定无助于此过程,并可能导致数据完整性进一步受损。
我花了几分钟的时间来创build一些转移纸板硬盘驱动器的装置,这确实有助于保持sorting:




具有讽刺意味的是,当我第一次连接旧驱动器时,我意识到在那里我已经创build了一个旧的zpool,用于testing旧版本的一些,但不是所有的个人数据丢失,所以当数据丢失有些减less,这意味着额外的文件来回移动。
最后,我将有问题的驱动器镜像到备份驱动器,将其用于zpool并保留原来的驱动器断开连接。 备份驱动器具有较新的固件,至lessSeaTools不报告任何所需的固件更新。 我做了一个简单的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 ...
所以问题很明显,新主板在驱动器末尾创build了几兆字节的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的驱动器也是如此。 如果你得到错误的驱动器或你指定的大小参数是不合理的,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.
之后,我重新启动了最初创build了zpool的FreeBSD 7.2虚拟机,并且zpool status再次报告了一个工作池。 好极了! 🙂
我在虚拟系统上导出池,并将其重新导入到主机FreeBSD 8.2系统中。
一些更重要的硬件升级,另一个主板交换,一个ZFS池更新到ZFS 4/15,一个彻底的scrubbing,现在我的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创build这个系统的人都有理由把它称为文件系统中的最后一个词。 尊重!
问题是新主板的BIOS在一些驱动器上创build了一个主机保护区(HPA),这是OEM厂商用于系统恢复的一小部分,通常位于硬盘的末端。
ZFS使用分区元信息维护4个标签,HPA阻止ZFS查看上面两个。
解决方法:引导Linux,使用hdparm检查并删除HPA。 要非常小心,这可以很容易地破坏你的数据。 有关详细信息,请参阅文章和hdparm手册页(参数-N)。
这个问题不仅发生在新的主板上,当将驱动器连接到SAS控制器卡时,我遇到了类似的问题。 解决scheme是一样的。
我build议你做的第一件事是获得更多的硬盘驱动器,并使用dd命令将8个驱动器的数据拷贝到它们上。 那样的话,如果在你试图恢复它们的时候最终会让事情变得更糟,你仍然可以回到这个基线。
我以前做过这个,有时候我不需要它,但是我所需要的时间使得它完全值得。
不要没有networking的工作。
你似乎正在解决这个问题。 如果您需要另一个更新的观点,您可以尝试使用Solaris 11 Express live CD。 有可能有很多新的代码运行在那里(Solaris中的zpool现在在版本31,而你在版本6),它可能提供更好的恢复可能性。 不要在Solaris下运行zpool upgrade ,但是如果你想保持池在FreeBSD下的安装。
FreeBSD邮件列表可能是您search的一个很好的起点。 我记得在FreeBSD-Stable和-Current上看过类似的请求。 根据您的数据的重要性,您可能希望联系专业的恢复公司,因为篡改无法访问的数据存储池有可能使事情变得更糟。
如果这只是一个分区问题,我会dd驱动器分区+ MBR,只是使分区正确的大小…
如果你没有格式化一个分区,创build或更改分区表不会影响任何东西(所以你可以回滚!),只要没有格式,那么大部分数据仍然存在/如果插入新分区在驱动器结束时,你可能会在那里有新的东西写的硬盘那里的腐败文件这就是为什么你唯一的好处,直到你格式化(新的MBR,文件表等…)