ssc*_*ssc 46 freebsd zfs data-recovery
我在 zpool 中有几 TB 的非常有价值的个人数据,由于数据损坏,我无法访问这些数据。该池最初是在 2009 年左右在 FreeBSD 7.2 系统上建立的,该系统在 Ubuntu 8.04 系统之上的 VMWare 虚拟机内运行。FreeBSD VM 仍然可用并且运行良好,只有主机操作系统现在已更改为 Debian 6。通过 VMWare 通用 SCSI 设备,来宾 VM 可以访问硬盘驱动器,总共 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 \
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
Run Code Online (Sandbox Code Playgroud)
几周前我可以进入游泳池。从那时起,我不得不更换主机的几乎所有硬件并安装多个主机操作系统。
我怀疑这些操作系统安装中的一个向 500GB 驱动器中的一个(第一个?)写入了引导加载程序(或其他)并破坏了一些 zpool 元数据(或其他)-“或其他”意味着这只是一个非常模糊的想法而那个主题并不是我的强项......
有很多关于 ZFS 的网站、博客、邮件列表等。我在这里发布这个问题,希望它可以帮助我收集足够的信息,以采取一种理智、结构化、可控、知情、知识渊博的方法来取回我的数据——并希望能帮助处于相同情况的其他人。
在 Google 上搜索“zfs recovery”时的第一个搜索结果是Solaris ZFS Administration Guide 中的ZFS Troubleshooting and Data Recovery一章。在第一个ZFS 故障模式部分,它在“损坏的 ZFS 数据”段落中说:
数据损坏始终是永久性的,在修复过程中需要特别考虑。即使底层设备被修复或更换,原始数据也将永远丢失。
有点令人沮丧。
然而,第二个谷歌搜索结果是Max Bruning 的博客,在那里,我读到
最近,有人向我发送了一封电子邮件,该人在 10 TB ZFS 池中存储了 15 年的视频和音乐,在断电后出现故障。不幸的是,他没有备份。他在 FreeBSD 7 上使用 ZFS 版本 6 [...] 在花了大约 1 周检查磁盘上的数据后,我基本上能够恢复所有数据。
和
至于 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.
Run Code Online (Sandbox Code Playgroud)
此外,Ben Rockwood 发布了一篇详细的文章,并且有一段Max Bruning 在 2008 年 6 月 28 日在布拉格举行的 Open Solaris 开发者大会上谈论它(和 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
Run Code Online (Sandbox Code Playgroud)
我想最后会出现“无效参数”错误是因为 zpool01 实际上并不存在:它不会发生在工作的 zpool02 上,但似乎也没有任何进一步的输出......
好的,在这个阶段,最好在文章变得太长之前发布这个。
也许有人可以给我一些关于如何从这里向前推进的建议,在我等待回复的同时,我会观看视频,查看上面 zdb 输出的详细信息,阅读 Bens 文章并尝试弄清楚是什么什么...
20110806-1600+1000
我想我已经找到了根本原因:Max Bruning 非常友好地回复了我的一封电子邮件,要求输出zdb -lll. 在池的“好”raidz1 一半中的 4 个硬盘驱动器中的任何一个上,输出类似于我上面发布的内容。但是,在“损坏”一半的 4 个驱动器中的前 3 个上,zdb报告failed to unpack label标签 2 和 3。池中的第四个驱动器似乎没问题,zdb显示所有标签。
谷歌搜索该错误消息带来了这篇文章。从对该帖子的第一个回复:
使用 ZFS,每个物理 vdev 上有 4 个相同的标签,在这种情况下是单个硬盘驱动器。vdev 的开头为 L0/L1,vdev 的结尾为 L2/L3。
池中的所有 8 个驱动器均为同一型号,希捷 Barracuda 500GB。但是,我确实记得我用 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
Run Code Online (Sandbox Code Playgroud)
我确实记得所有驱动器的大小都相同。现在查看驱动器,它表明其中三个驱动器的大小发生了变化,它们缩小了 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)
Run Code Online (Sandbox Code Playgroud)
因此,从外观上看,它不是“将引导加载程序写入一个驱动器”的操作系统安装之一(正如我之前假设的那样),它实际上是新主板(华硕 P8P67 LE)创建了一个 2 MB主机三个驱动器末尾的受保护区域弄乱了我的 ZFS 元数据。
为什么它没有在所有驱动器上创建 HPA?我相信这是因为 HPA 创建仅在较旧的驱动器上完成,该错误稍后由希捷硬盘驱动器 BIOS 更新修复:当整个事件在几周前开始时,我运行希捷的SeaTools以检查是否存在驱动器出现任何物理问题(仍在旧硬件上),我收到一条消息,告诉我我的某些驱动器需要更新 BIOS。由于我现在正在尝试重现该消息的确切详细信息以及固件更新下载的链接,似乎由于主板创建了 HPA,因此两个 SeaTools DOS 版本都无法检测到有问题的硬盘驱动器 - 快速invalid partition或类似的当他们开始时闪烁,就是这样。具有讽刺意味的是,他们确实找到了一组三星驱动器。
(我跳过了在非联网系统上的 FreeDOS shell 中的痛苦、耗时且最终毫无结果的细节。)最后,我在一台单独的机器上安装了 Windows 7,以便运行 SeaTools Windows版本 1.2.0.5。关于 DOS SeaTools 的最后一句话:不要费心尝试独立启动它们 - 相反,花几分钟时间制作一个带有超棒的Ultimate Boot CD的可启动 U 盘- 除了 DOS SeaTools 之外,它还为您提供了许多其他功能有用的工具。
启动时,Windows 版 SeaTools 会显示此对话框:

这些链接指向序列号检查器(出于某种原因受验证码保护 - 我的为“侵入性用户”)和有关固件更新的知识库文章。可能还有特定于硬盘驱动器模型和一些下载的进一步链接,但我暂时不会遵循该路径:
我不会急于一次更新三个驱动器的固件,这些驱动器已经截断了分区并且是损坏的存储池的一部分。那是自找麻烦。对于初学者来说,固件更新很可能无法撤消 - 这可能会无可挽回地破坏我取回数据的机会。
因此,我接下来要做的第一件事就是对驱动器进行映像并处理副本,因此如果出现任何问题,可以返回原件。这可能会引入额外的复杂性,因为 ZFS 可能会注意到驱动器被交换(通过驱动器序列号或另一个 UUID 或其他方式),即使它是位精确的 dd 副本到相同的硬盘驱动器模型。此外,zpool 甚至没有上线。男孩,这可能会变得棘手。
然而,另一种选择是使用原件并保留镜像驱动器作为备份,但是当原件出现问题时,我可能会遇到上述复杂性。呐,不好。
为了清除三个硬盘驱动器,这些硬盘驱动器将用作损坏池中存在错误 BIOS 的三个驱动器的映像替代品,我需要为现在在那里的东西创建一些存储空间,所以我将深入挖掘硬件盒并从一些旧驱动器组装一个临时 zpool - 我也可以用它来测试 ZFS 如何处理交换 dd 驱动器。
这可能需要一段时间...
20111213-1930+1100
这确实需要一段时间。我花了几个月的时间在我的桌子上放着几个打开的电脑机箱,里面挂着各种数量的硬盘驱动器,还戴着耳塞睡了几个晚上,因为我无法在睡觉前关闭机器,因为它正在运行一些冗长的关键操作. 然而,我终于胜利了!:-) 我在这个过程中也学到了很多东西,我想在这里与处于类似情况的任何人分享这些知识。
这篇文章已经比 ZFS 文件服务器停止运行的任何人有时间阅读的时间长得多,所以我将在这里详细介绍,并在下面进一步创建一个包含基本发现的答案。
我在过时的硬件盒中深入挖掘,以组装足够的存储空间,将这些东西从有缺陷的驱动器镜像到的单个 500GB 驱动器上移走。我还必须从他们的 USB 盒中取出一些硬盘驱动器,以便我可以直接通过 SATA 连接它们。还有一些不相关的问题,当我将它们重新投入使用时,一些旧驱动器开始出现故障,需要更换 zpool,但我会跳过这一点。
提示:在某个阶段,总共涉及大约 30 个硬盘驱动器。有了这么多硬件,将它们正确堆叠是一个巨大的帮助;电缆松动或硬盘驱动器从您的办公桌上掉下来肯定无济于事,并且可能会进一步损害您的数据完整性。
我花了几分钟制作了一些临时的硬纸板硬盘装置,这确实有助于保持排序:

具有讽刺意味的是,当我第一次连接旧驱动器时,我意识到那里有一个旧的 zpool,我必须创建一个旧版本的 zpool 来测试一些旧版本的数据,但不是所有丢失的个人数据,所以虽然数据丢失是有所减少,这意味着额外的文件来回移动。
最后,我将有问题的驱动器镜像到备份驱动器,将它们用于 zpool 并断开原始驱动器的连接。备份驱动器具有更新的固件,至少 SeaTools 不会报告任何所需的固件更新。我用一个简单的 dd 从一个设备到另一个设备进行了镜像,例如
sudo dd if=/dev/sda of=/dev/sde
Run Code Online (Sandbox Code Playgroud)
我相信 ZFS 确实注意到了硬件变化(通过某些硬盘 UUID 或其他方式),但似乎并不在意。
然而,zpool 仍处于相同状态,副本不足/数据损坏。
正如前面提到的HPA 维基百科文章中提到的,当 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
...
Run Code Online (Sandbox Code Playgroud)
所以问题显然是新主板在驱动器的末尾创建了一个几兆字节的 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.
...
Run Code Online (Sandbox Code Playgroud)
就我而言,HPA 是这样删除的:
user@host:~$ sudo hdparm -Np976773168 /dev/sde
/dev/sde:
setting max visible sectors to 976773168 (permanent)
max sectors = 976773168/976773168, HPA is disabled
Run Code Online (Sandbox Code Playgroud)
对于其他带有 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.
Run Code Online (Sandbox Code Playgroud)
之后,我重新启动了最初创建 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
Run Code Online (Sandbox Code Playgroud)
最后,在我看来,ZFS 池非常非常难以杀死。创建该系统的 Sun 人员完全有理由称其为文件系统中的最后一句话。尊重!
ssc*_*ssc 24
问题是新主板的 BIOS 在某些驱动器上创建了一个主机保护区 (HPA),这是 OEM 用于系统恢复目的的一小部分,通常位于硬盘驱动器的末端。
ZFS 维护 4 个带有分区元信息的标签,HPA 防止 ZFS 看到上面的两个标签。
解决方案:启动 Linux,使用 hdparm 检查并删除 HPA。要非常小心,这很容易永久破坏您的数据。有关详细信息,请参阅文章和 hdparm 手册页(参数 -N)。
这个问题不仅出现在新主板上,我在将驱动器连接到 SAS 控制器卡时也遇到了类似的问题。解决方法是一样的。
我建议您做的第一件事是使用命令获取更多硬盘驱动器并制作您拥有的 8 个驱动器的副本,其中包含您的数据dd。这样,如果在您尝试恢复它们的过程中最终使情况变得更糟,您仍然可以回到这个基线。
我以前做过这个,有时我不需要它,但我确实需要它的时候使它完全值得付出努力。
没有网络就不要工作。
| 归档时间: |
|
| 查看次数: |
12634 次 |
| 最近记录: |