Linux存储入门:简易数据恢复方案--分区和LVM实战

摘要:以黑箱方式完全依赖工具来进行数据恢复,所需时间和恢复的结果都难以估计。以专家或者专业方式进行数据恢复,技能和成本又太高。那么,数据恢复有没有较为合适的简易方案呢?我们以处理过的实际案例作答。

数据恢复有没有简易方案?

IT工程师一般都知道如何操作和使用文件和目录。但是,对于系统如何构建出、抽象出文件和目录,一般就不熟悉了。至于更下层的概念,可能大家知道最多的就是驱动了。所以,为了规避这点,可行的简易方案之一,就是以黑箱方式使用testdisk等工具,在我们在对底层了解不多甚至一无所知的情况下,进行数据恢复(商业工具,恢复效果估计更好,当然商业工具的价格也更好)。但是,对于工程师而言,多数时候,仅仅以黑箱方式依赖某些工具进行数据恢复是不够的。

数据恢复,经常是突发事故响应中关键而又耗时的一步。多数情况下,工程师往往并非专司数据恢复,操作环境往往是生产环境,趁手工具难以部署,执行操作要遵循种种约束,加之业务中断的压力。这种情形下,工程师很可能还需要推定数据恢复的结果/耗时等信息,提供数据供决策者使用。很明显,如果你准备考验一下自己的细致、耐心、知识和技能,数据恢复将是个不错的课题。当然,有一点是明确的,只是以黑箱方式使用testdisk等工具进行数据恢复,解决以上问题是不可能的。那么,有没有其他简易方案呢?

这里,我们以一个实际的case为例,讨论一下,在只使用UNIX常见工具(dd/grep/strace等)的情况下,如何简单、快捷的恢复数据。

预先准备

工具

我们要用到以下工具

工具功能示例

bc计算器echo'ibase=2^3;i=0107000;ibase=2^3+2;i/512'|bc-l

dd检查或者拷贝磁盘/分区的内容,可以是几个扇区,也可以是几个字节ddif=/dev/sdbbs=1count=64skip=642>/dev/null|od-v-tx1

grep搜索制定字符串

od把二进制内容以ASCII或者16进制显示出来,搭配dd使用可以代替二进制编辑器ddif=/dev/sdbbs=1count=64skip=642>/dev/null|od-v-tx1

strace追踪应用的执行路径和对数据处理的流程straceps

排查和诊断就是数据处理

如果对数据处理了解不多,请参考OSEMN

obtainingdata/获取数据

crubbingdata/清洗数据

exploringdata/探索数据

modelingdata/建模数据

interpretingdata/解释数据

测试环境

使用Virtualbox,基于CentOS/Fedora/debian/Ubuntu搭建Linux实验环境。只需要学会strace工具和如下系统调用,就足以追踪系统如何处理诸如LVM物理卷元数据这样过的问题。

name功能

open打开一个文件,返回一个文件描述符供后续读写操作使用

dup/dup2复制文件描述符

lseek将读写指针移动到指定位置,后续操作从此指定位置读写

close关闭文件描述符

read读操作

数据恢复的原理和流程

什么是元数据?

我们以大家都熟悉的磁盘作为存储设备的例子。

现代操作系统都会在磁盘上建立多个分层结构来管理和控制磁盘。比如,磁盘分区,分区上建立物理卷,物理卷上建立卷组,卷组上建立逻辑卷,逻辑卷上建立文件系统,就是这样的一个例子。如果你不熟悉LVM,请参考LogicalVolumeManager。

这些分层的结构都是很类似的。以磁盘分区为例。所谓分区,以大家最为熟悉的MBR:MasterBootRecord结构为例。其实是第一个扇区记录了各个分区的起始扇区,大小和类型。系统需要时,比如启动过程中,系统只要从磁盘的第一个扇区读取这些数据即能拿到各个分区的数据。

具体看看分区的数据结构。以fdisk为例,分区的数据结构定义为

structdos_partition{

unsignedcharboot_ind;/*0x80-active*/

unsignedcharbh,bs,bc;/*beginCHS*/

unsignedcharsys_ind;

unsignedchareh,es,ec;/*endCHS*/

unsignedcharstart_sect[4];/*分区开始扇区*/

unsignedcharnr_sects[4];/*分区包含的扇区数量*/

}__attribute__((packed));

我们看看具体分区的例子,验证一下数据结构

83F959699634718530504D12DF3A1175

分区使得磁盘上的扇区有了差别。第一个扇区(其实其编号是0),因分区数据记录其上而扮演特殊角色。明显,对系统而言,管理和操作分区实际上就是读写第一扇区上的对应记录而已。

类似分区信息这种系统用以管理某层资源的数据就是元数据。

系统在磁盘上建立的各个分层结构,都有类似分区结构的数据结构。以LVM结构为例,我们可以把磁盘记录和LVM工具报告的数据做一对比。LVM数据的从第2个扇区开始,卷组数据在第8个扇区中,可以用dd命令提取相关扇区来验证LVM的数据结构。

下面是一份完整的LVM元数据信息,有兴趣者可以逐一清点各个对象。

[root@pusf~]#pvdisplay;vgdisplay;lvdisplay

---Physicalvolume---

PVName/dev/sda2

VGNamecl

PVSize39.00GiB/notusable3.00MiB

Allocatableyes

PESize4.00MiB

TotalPE9983

FreePE1

AllocatedPE9982

PVUUIDTIcs1T-Jksu-HKrn-fKqK-QF4K-ao1S-3PVBGI

---Volumegroup---

VGNamecl

SystemID

Formatlvm2

MetadataAreas1

MetadataSequenceNo5

VGAccessread/write

VGStatusresizable

MAXLV0

CurLV2

OpenLV2

MaxPV0

CurPV1

ActPV1

VGSize39.00GiB

PESize4.00MiB

TotalPE9983

AllocPE/Size9982/38.99GiB

FreePE/Size1/4.00MiB

VGUUIDKTVFwl-2QRE-ehf3-3dJb-bIfG-bpn0-8FnH7l

---Logicalvolume---

LVPath/dev/cl/swap

LVNameswap

VGNamecl

LVUUIDKc14dR-vFda-qdWJ-zUYo-lsDl-4oKq-RjjrBb

LVWriteAccessread/write

LVCreationhost,timelocalhost,2017-04-1813:23:08+0800

LVStatusavailable

#open2

LVSize2.00GiB

CurrentLE512

Segments1

Allocationinherit

Readaheadsectorsauto

-currentlysetto8192

Blockdevice253:1

---Logicalvolume---

LVPath/dev/cl/root

LVNameroot

VGNamecl

LVUUIDPWaI2g-t2Kq-h3aa-HgMC-cBp1-FjBp-dmaGeR

LVWriteAccessread/write

LVCreationhost,timelocalhost,2017-04-1813:23:09+0800

LVStatusavailable

#open1

LVSize36.99GiB

CurrentLE9470

Segments1

Allocationinherit

Readaheadsectorsauto

-currentlysetto8192

Blockdevice253:0

[root@pusf~]#ddif=/dev/sda2bs=512count=16skip=12>/dev/null|od-tc

0000000LABELONE001\0\0\0\0\0\0\0

0000020270177251K\0\0\0LVM2001

0000040TIcs1TJksuHKrnfK

0000060qKQF4Kao1S3PVBGI

0000100\0\0360277\t\0\0\0\0\0020\0\0\0\0\0

0000120\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0

0000140\0\0\0\0\0\0\0\0\0020\0\0\0\0\0\0

0000160\0360017\0\0\0\0\0\0\0\0\0\0\0\0\0

0000200\0\0\0\0\0\0\0\0002\0\0\0001\0\0\0

0000220\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0

*

0007000252314344wLVM2x[5A%r

00070200N*>001\0\0\0\0020\0\0\0\0\0\0

0007040\0360017\0\0\0\0\0\0026\0\0\0\0\0\0

0007060027005\0\0\0\0\0\0026G205374\0\0\0\0

0007100\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0

*

0010000cl{\nid="KTVFw

0010020l-2QRE-ehf3-3dJb

0010040-bIfG-bpn0-8FnH7

0010060l"\nseqno=1\nfor

0010100mat="lvm2"\nsta

0010120tus=["RESIZEAB

0010140LE","READ","WR

0010160ITE"]\nflags=[]

0010200\nextent_size=8

0010220192\nmax_lv=0\nm

0010240ax_pv=0\nmetada

0010260ta_copies=0\n\np

0010300hysical_volumes

0010320{\n\npv0{\nid="T

0010340Ics1T-Jksu-HKrn-

0010360fKqK-QF4K-ao1S-3

0010400PVBGI"\ndevice=

0010420"/dev/sda2"\n\nsta

0010440tus=["ALLOCATA

0010460BLE"]\nflags=[]

0010500\ndev_size=8178

00105206880\npe_start=

00105402048\npe_count=

00105609983\n}\n}\n\n\n}\n#G

0010600eneratedbyLVM2

0010620version2.02.16

00106406(2)-RHEL7(2016

0010660-09-28):TueApr

00107001805:23:08201

00107207\n\ncontents="T

0010740extFormatVolum

0010760eGroup"\nversion

0011000=1\n\ndescriptio

0011020n=""\n\ncreation

0011040_host="localho

0011060st"\t#Linuxloca

0011100lhost3.10.0-514

0011120.el7.x86_64#1S

0011140MPTueNov2216

0011160:42:41UTC2016

0011200x86_64\ncreation_

0011220time=149249298

00112408\t#TueApr180

00112605:23:082017\n\n\0\0

0011300\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0

*

0012000cl{\nid="KTVFw

0012020l-2QRE-ehf3-3dJb

0012040-bIfG-bpn0-8FnH7

0012060l"\nseqno=2\nfor

0012100mat="lvm2"\nsta

0012120tus=["RESIZEAB

0012140LE","READ","WR

0012160ITE"]\nflags=[]

0012200\nextent_size=8

0012220192\nmax_lv=0\nm

0012240ax_pv=0\nmetada

0012260ta_copies=0\n\np

0012300hysical_volumes

0012320{\n\npv0{\nid="T

0012340Ics1T-Jksu-HKrn-

0012360fKqK-QF4K-ao1S-3

0012400PVBGI"\ndevice=

0012420"/dev/sda2"\n\nsta

0012440tus=["ALLOCATA

0012460BLE"]\nflags=[]

0012500\ndev_size=8178

00125206880\npe_start=

00125402048\npe_count=

00125609983\n}\n}\n\nlogica

0012600l_volumes{\n\nswa

0012620p{\nid="Kc14dR

0012640-vFda-qdWJ-zUYo-

0012660lsDl-4oKq-RjjrBb

0012700"\nstatus=["REA

0012720D","WRITE","VI

0012740SIBLE"]\nflags=

0012760[]\ncreation_time

0013000=1492492988\ncr

0013020eation_host="l

0013040ocalhost"\nsegmen

0013060t_count=1\n\nseg

0013100ment1{\nstart_ex

0013120tent=0\nextent_

0013140count=512\n\ntyp

0013160e="striped"\nst

0013200ripe_count=1\n\n

0013220stripes=[\n"pv0

0013240",0\n]\n}\n}\n}\n\n}\n

0013260#GeneratedbyL

0013300VM2version2.02

0013320.166(2)-RHEL7(2

0013340016-09-28):Tue

0013360Apr1805:23:08

00134002017\n\ncontents=

0013420"TextFormatVo

0013440lumeGroup"\nvers

0013460ion=1\n\ndescrip

0013500tion=""\n\ncreat

0013520ion_host="loca

0013540lhost"\t#Linuxl

0013560ocalhost3.10.0-

0013600514.el7.x86_64#

00136201SMPTueNov22

001364016:42:41UTC20

001366016x86_64\ncreati

0013700on_time=149249

00137202988\t#TueApr1

0013740805:23:082017\n

0013760\n\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0

0014000cl{\nid="KTVFw

0014020l-2QRE-ehf3-3dJb

0014040-bIfG-bpn0-8FnH7

0014060l"\nseqno=3\nfor

0014100mat="lvm2"\nsta

0014120tus=["RESIZEAB

0014140LE","READ","WR

0014160ITE"]\nflags=[]

0014200\nextent_size=8

0014220192\nmax_lv=0\nm

0014240ax_pv=0\nmetada

0014260ta_copies=0\n\np

0014300hysical_volumes

0014320{\n\npv0{\nid="T

0014340Ics1T-Jksu-HKrn-

0014360fKqK-QF4K-ao1S-3

0014400PVBGI"\ndevice=

0014420"/dev/sda2"\n\nsta

0014440tus=["ALLOCATA

0014460BLE"]\nflags=[]

0014500\ndev_size=8178

00145206880\npe_start=

00145402048\npe_count=

00145609983\n}\n}\n\nlogica

0014600l_volumes{\n\nswa

0014620p{\nid="Kc14dR

0014640-vFda-qdWJ-zUYo-

0014660lsDl-4oKq-RjjrBb

0014700"\nstatus=["REA

0014720D","WRITE","VI

0014740SIBLE"]\nflags=

0014760[]\ncreation_time

0015000=1492492988\ncr

0015020eation_host="l

0015040ocalhost"\nsegmen

0015060t_count=1\n\nseg

0015100ment1{\nstart_ex

0015120tent=0\nextent_

0015140count=512\n\ntyp

0015160e="striped"\nst

0015200ripe_count=1\n\n

0015220stripes=[\n"pv0

0015240",0\n]\n}\n}\n\nroot

0015260{\nid="PWaI2g-

0015300t2Kq-h3aa-HgMC-c

0015320Bp1-FjBp-dmaGeR"

0015340\nstatus=["READ

0015360","WRITE","VIS

0015400IBLE"]\nflags=[

0015420]\ncreation_time

0015440=1492492989\ncre

0015460ation_host="lo

0015500calhost"\nsegment

0015520_count=1\n\nsegm

0015540ent1{\nstart_ext

0015560ent=0\nextent_c

0015600ount=9470\n\ntyp

0015620e="striped"\nst

0015640ripe_count=1\n\n

0015660stripes=[\n"pv0

0015700",512\n]\n}\n}\n}\n\n

0015720}\n#Generatedby

0015740LVM2version2.

001576002.166(2)-RHEL7

0016000(2016-09-28):Tu

0016020eApr1805:23:0

001604092017\n\ncontents

0016060="TextFormat

0016100VolumeGroup"\nve

0016120rsion=1\n\ndescr

0016140iption=""\n\ncre

0016160ation_host="lo

0016200calhost"\t#Linux

0016220localhost3.10.

00162400-514.el7.x86_64

0016260#1SMPTueNov

00163002216:42:41UTC

00163202016x86_64\ncrea

0016340tion_time=1492

0016360492989\t#TueApr

00164001805:23:09201

00164207\n\n\0\0\0\0\0\0\0\0\0\0\0\0\0

0016440\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0

*

0017000cl{\nid="KTVFw

0017020l-2QRE-ehf3-3dJb

0017040-bIfG-bpn0-8FnH7

0017060l"\nseqno=4\nfor

0017100mat="lvm2"\nsta

0017120tus=["RESIZEAB

0017140LE","READ","WR

0017160ITE"]\nflags=[]

0017200\nextent_size=8

0017220192\nmax_lv=0\nm

0017240ax_pv=0\nmetada

0017260ta_copies=0\n\np

0017300hysical_volumes

0017320{\n\npv0{\nid="T

0017340Ics1T-Jksu-HKrn-

0017360fKqK-QF4K-ao1S-3

0017400PVBGI"\ndevice=

0017420"/dev/sda2"\n\nsta

0017440tus=["ALLOCATA

0017460BLE"]\nflags=[]

0017500\ndev_size=8178

00175206880\npe_start=

00175402048\npe_count=

00175609983\n}\n\npv1{\nid

0017600="Rcpo7Z-QIeg-

0017620FGVD-TSZI-soQO-I

0017640gaT-rQwD4Y"\ndevi

0017660ce="/dev/sdb6"

0017700\n\nstatus=["ALL

0017720OCATABLE"]\nflags

0017740=[]\ndev_size=

0017760409601\npe_start

0020000

[root@pusf~]#

元数据和数据:数据损坏分类

系统把磁盘的扇区分成两种来支持分区:第一扇区和所有其他非第一扇区。并且在第一个扇区上记录分区信息,即元数据。而其他非第一扇区则供分区层使用,从磁盘的视角看,其他非第一扇区则是数据部分。我们逐层考察下磁盘、分区和LVM结构

disc_logical_structure_2017_07_09

系统启动时,会逐层读取各层元数据,创建各层数据结构。如果某一层元数据损坏或者丢失,那么系统就没有办法完成创建各层数据结构的任务。这种情况下,从客户角度看,很可能就是数据损坏了。比如,如果你把第一个扇区用\0覆盖一遍,那么系统就识别不到分区内容了。当然这种情况下分区层以上的内容,比如物理卷信息,系统也无法处理了。因此,对于数据恢复任务而言,如果元数据损坏,则修复元数据总是必须的,而且往往是第一步。

当然,如果数据损坏了,即使元数据完好无缺,那么数据也是损坏了。比如,你误删了一个文件,那么,分区结构再完好对于文件被删也于事无补。

基于以上分析,我们可以把数据损坏简单分三类类:元数据损坏、数据损坏或者前面两种损坏类型的混合型损坏。

_2017_07_13

元数据修复可以简易处理

以基于磁盘的分区、LVM以及文件系统为例。分层结构的数据格式都有严格的格式(比如分区的数据结构就是一个C的struct),出现位置也固定(有关分区的元数据记录在第一个扇区的446~462字节之间),而且这些数据结构往往都带有魔数(比如,分区的类型83),而且常用的分层结构,也不外乎分区、LVM以及文件系统等几种。因此,对于元数据以及系统如何处理元数据,我们都容易追踪和检查。因此,可以预期,修复元数据,有简易方案。

原理

如果有数据损坏,那么除非有日志、备份,或者数据本身有逻辑可供使用,否则数据是不能恢复了。比如,通常的文件删除操作,系统只是解除了文件名称和文件内容相关间的联系而已。文件本身的内容还是记录再磁盘上。这种情况下,只要重建文件名称和文件内容间的联系即可恢复文件。

相对而言,简单情形的是元数据损坏。如果只是元数据损坏,而且我们知道正确的元数据。因为元数据操作,不会触及数据部分,因此,我们只要重建元数据部分即可恢复数据。如果涉及到多层,则逐层恢复即可。以分区丢失为例。

比如我们有一块数据盘,整盘我们只是用fdisk分了一个区,现在分区丢失了。这种情形下,只要用fdsik,按照默认情形,重新分区就能恢复分区。

就这种情形,我们给出一个可用的分析流程。

_

症状和初步排查

症状

客户反馈

降配重启后,系统无法启动

排查发现客户一逻辑卷无法挂载导致重启失败。在/etc/fstab中注释掉逻辑卷的挂载配置,系统启动成功。

但是客户的逻辑卷上有重要数据。此逻辑卷在数据盘上,数据盘大小是2TB。此磁盘全部2TB全部分配给一个分区,此分区上创建有LVM结构。

分区数据如下

[root@localhost~]#fdisk-l-u/dev/vdb

Disk/dev/vdb:2199.0GB,2199023255552bytes

5heads,3sectors/track,286331153cylinders,total4294967296sectors

Units=sectorsof1*512=512bytes

Sectorsize(logical/physical):512bytes/512bytes

I/Osize(minimum/optimal):512bytes/512bytes

Diskidentifier:0xde220917

DeviceBootStartEndBlocksIdSystem

/dev/vdb1204842949672942147482623+83Linux

[root@localhost~]#

初步排查

首先确定分区上是否有数据,通过查看一些扇区,我们就会有很大的概率确认这一点。当然也可以逐扇区确认。

逐扇区确认,可以用如下命令办理。假设磁盘是/dev/vdb。

max_sector_to_check=nrsector

foriin$(seq0${max_sector_to_check});doddif=/dev/vdbbs=512count=1skip=${i}2>/dev/null|sha256sum;done|sort-n|uniq;

当然,也可以通过抽样检查来确认。这种方法通常是检查磁盘分区的前面一部分扇区。比如,下面的例子,通过检查前面几十个扇区,我们可以确认磁盘上确有数据。

[root@localhost~]#ddif=/dev/vdb1bs=512count=602>/dev/null|od-tx1

000000000000000000000000000000000000000

*

0007000f9800000f9800100f9800200f9800300

0007020f9800400f9800c00f9800d00f9801800

0007040f9802800f9803e00f9807900f980ab00

0007060f9803801f9806c01f9804504f980b004

0007100f9801a06f980d00cf980841e00000000

000712000000000000000000000000000000000

*

0017000fa800000fa800100fa800200fa800300

0017020fa800400fa800c00fa800d00fa801800

0017040fa802800fa803e00fa807900fa80ab00

0017060fa803801fa806c01fa804504fa80b004

0017100fa801a06fa80d00cfa80841e00000000

001712000000000000000000000000000000000

*

0027000fb800000fb800100fb800200fb800300

0027020fb800400fb800c00fb800d00fb801800

0027040fb802800fb803e00fb807900fb80ab00

0027060fb803801fb806c01fb804504fb80b004

0027100fb801a06fb80d00cfb80841e00000000

002712000000000000000000000000000000000

*

0037000fc800000fc800100fc800200fc800300

0037020fc800400fc800c00fc800d00fc801800

0037040fc802800fc803e00fc807900fc80ab00

0037060fc803801fc806c01fc804504fc80b004

0037100fc801a06fc80d00cfc80841e00000000

003712000000000000000000000000000000000

*

0047000fd800000fd800100fd800200fd800300

0047020fd800400fd800c00fd800d00fd801800

0047040fd802800fd803e00fd807900fd80ab00

0047060fd803801fd806c01fd804504fd80b004

0047100fd801a06fd80d00cfd80841e00000000

004712000000000000000000000000000000000

*

0057000fe800000fe800100fe800200fe800300

0057020fe800400fe800c00fe800d00fe801800

0057040fe802800fe803e00fe807900fe80ab00

0057060fe803801fe806c01fe804504fe80b004

0057100fe801a06fe80d00cfe80841e00000000

005712000000000000000000000000000000000

*

0067000ff800000ff800100ff800200ff800300

0067020ff800400ff800c00ff800d00ff801800

0067040ff802800ff803e00ff807900ff80ab00

0067060ff803801ff806c01ff804504ff80b004

0067100ff801a06ff80d00cff80841e00000000

006712000000000000000000000000000000000

*

0074000

[root@localhost~]#

接下来使用testdisk工具恢复数据。尝试数次,testdisk工具总是在扫描到2%时停滞,处理过程不能继续。

初次恢复尝试

分区还在,但是LVM结构丢失,经检查,由LVM工具链维护的备份数据/etc/lvm/backup/vg_xxxxxx文件还在。因此,这种情形下,按照我们的恢复流程,只要在分区之上,尝试重建LVM和文件系统,应该就可以解决问题。

[root@localhost~]#pvdisplay/dev/vdb

Failedtofinddeviceforphysicalvolume"/dev/vdb".

[root@localhost~]#ls/etc/lvm/backup/vg_xxxxxx

/etc/lvm/backup/vg_xxxxxx

[root@localhost~]#

根据备份数据恢复LVM结构,可以参考RecoveringPhysicalVolumeMetadata。可惜的是,我们第一步就折戟沉沙了。

[root@localhost~]#pvcreate--uuid"X1cHlO-kdFk-RZIM-1L12-qHit-0QA5-C1fZxm"--restorefile/etc/lvm/backup/vg_xxxxxx/dev/vdb1

WARNING:Device/dev/vdb1hassizeof4294965247sectorswhichissmallerthancorrespondingPVsizeof4294966977sectors.Wasdeviceresized?

OneormoredevicesusedasPVsinVGvg_xxxxxxhavechangedsizes.

Can'tinitializephysicalvolume"/dev/vdb1"ofvolumegroup"vg_xxxxxx"without-ff

[root@localhost~]#

看样子,分区的数据有些地方出错了。根据上面命令报错的信息,对比LVM的备份数据和分区数据,很快我们就发现了问题。现有分区记录的其拥有的扇区数目,少于其上LVM卷组记录的扇区数量。

578896DD48DC5D2C4066BFF980F65DF3

问题出在哪里?

因为种种原因,我们不能确认分区信息和LVM备份数据为何不一致。但是,我们可以进一步从磁盘上提取、分析数据。因为有关分区的元数据在(分区在),所以我们进一步检查磁盘上还有没有有关LVM的元数据?这只要使用下面的命令行

ddif=/dev/vdb1bs=512count=1282>/dev/null|od-tc

结果及其结果分析如下

02F56A8A85A2B2B8AD17DD45FFB50C01

所以,磁盘上还有有关LVM的元数据,但是为什么系统没有凭借这些数据构建出LVM结构呢?我们创建一个测试环境,用strace追踪下系统处理LVM物理卷元数据的执行路径。如下命令即可

strace-s512pvdisplay

当然,更好的办法是把strace记录放置到文件中,以备仔细检查

starce-opath_to_strace_log-s512-f-ffpvdisplay

我们组合使用strace和grep命令来确认系统默认的LVM物理卷位置。如果你没有耐心分析下面的数据,请跳过直接看后面的截图

strace-o/tmp/pvdisplay-strace.log-s512pvdisplay

grep-E'^open|^lseek|^read'/tmp/pvdisplay-strace.log

数据清洗结果如下。如果没有耐心分析,请跳过直接看下面的分析截图

[root@localhost~]#grep-E'^open|^lseek|^read|^close'/tmp/pvdisplay-strace.log

close(4)=0

open("/dev/vdb1",O_RDONLY|O_DIRECT|O_NOATIME)=4

close(4)=0

open("/dev/vdb1",O_RDONLY|O_DIRECT|O_NOATIME)=4

lseek(4,21037056,SEEK_SET)=21037056

read(4,"…",512)=512

lseek(4,21118976,SEEK_SET)=21118976

read(4,"…",512)=512

lseek(4,0,SEEK_SET)=0

read(4,"…",512)=512

lseek(4,4096,SEEK_SET)=4096

read(4,"\26\326\216\333LVM2x[5A%r0N*>\1\0\0…",512)=512

close(4)=0

[root@localhost~]#

6CDFD7748A9A3A5C8E24EBB1041903E7

很明显,系统预期LVM元数据是在分区的第8个扇区,但是在需要做数据恢复的磁盘上,LVM的元数据却是在第71个扇区,而分区的起始扇区是2048,因此,LVM数据根本不在分区内。这就是为什么磁盘上还有LVM元数据,系统却没有识别出来LVM的原因。

既然系统是因为有关LVM的元数据所在扇区不对而导致系统无法识别LVM结构,设想通过重新分区,我们把有关LVM元数据调整到分区的第8个扇区。稍加计算,就会发现,只要把分区的起始扇区从第2048个扇区调整到第63个扇区即可。不仅如此,通过调整分区大小,我们同样也解决了磁盘分区扇区数不足的问题

B79CA9B05F3FC37FE7DF5956B124EBCE

数据恢复

较新的fdisk工具,不允许起始扇区小于2048,因此,我们用parted工具来调整分区的起始扇区。

调整过程是先删掉扇区,而后再创建之。而结果正如我们所预期的,分区调整完成,客户的数据立刻恢复了。物理卷、卷组、逻辑卷、文件系统以及数据,都完好无损。

结语

从处理这个实际case可以看出,如果知道如何识别各层元数据,比如分区,LVM和文件系统;能够追踪系统处理各层元数据的逻辑,那么,组合使用UNIX常用的dd、od等工具,足以简单有效的处理元数据损坏的情形,快速恢复数据。如果掌握了常见的系统调用,并且掌握了strace工具,那么对于如何识别元数据以及系统如何处理元数据,完全可以通过简单分析strace输出拿到相应答案。

除了易学、简单、快捷、高效,元数据修复方案还有一个优点,就是可以确保不会破坏数据。这可能是这个方案的最大亮点。

参考

本文提供链接,优先链接内容的严谨与可靠性,而非便利性。如链接无法访问,请按照文字自行检索资料和图书。

1.数据恢复软件列表

2.shred(Unix)

3.使用Linux文件恢复工具

4.如何恢复Linux上删除的文件,第1部分

5.硬盘分区

6.RHEL6LogicalVolumeManagerAdministration

7.Linux文件系统剖析

8.Linuxmanpagesonline

9.元数据

10.Linux文件系统中元数据的加锁机制与组织方式

本文为云栖社区原创内容,未经允许不得转载,如需转载请发送邮件至[email protected];如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件至:[email protected]进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容。

相关推荐