背景:一个关于数据丢失后的恢复问题,在LU中引起热烈的讨论,在相关的讨论帖中,qintl对LVM底层数据结构做了详细而精彩的演讲,受益匪浅。现将qintl主要讲稿内容整理如下,以便大家阅读。
相关讨论帖地址:
http://www.loveunix.com/viewthread.php?tid=76187&extra=page%3D5%26amp%3Bfilter%3Ddigest
http://www.loveunix.com/viewthread.php?tid=75851&highlight=%B6%AA%CA%A7
一个硬盘在AIX系统下系统保留区数据结构,AIX下的Block其实就是512Byte,编号从0开始,跟我们所说的扇区是一样的。以下是我机器上某块盘的信息
|
|
硬盘物理位置,用扇区标记(sec)
|
Readvgda结果(readvgda -s hdisk10)
|
0 sec(开始)
|
lvmid: 1598838349
|
128 sec(开始)
|
*****************************************
|
136 sec(开始)
|
*****************************************
|
2234 sec(开始)
|
|
2242 sec(开始)
|
|
4340 sec(开始)
|
|
4352 sec (物理硬盘第1PP开始)
|
|
硬盘的PVID
一个硬盘要被操作系统正常使用,必须先分配PVID,硬盘的PVID在以后加入某个VG、LV都是要用到的。
分配PVID的过程就像windows下的初始化硬盘操作,就是把硬盘0扇区改写成符合操作系统使用的格式,只改写0扇区,别的地方没有任何改变。
用lspv命令就可以知道哪些硬盘还没有分配PVID,用#chdev -l hdiskX -a pv=yes就可以给硬盘分配PVID,当一个硬盘在操作系统中已经有了PVID,#chdev -l hdiskX -a pv=yes命令不会改变原来的PVID。
如果要修改某块盘的PVID,我们要先清除掉原先的PVID,然后再生成,可以用以下命令:
#chdev -l hdiskX -a pv=clear
#chdev -l hdiskX -a pv=yes
chinadns的Blog有对PVID的详细介绍:
http://blog.chinaunix.net/u/16252/showart_94788.html
我们从底层观察chdev -l hdiskX -a pv=yes对硬盘0扇区的改动:
# lspv
hdisk0 003752149a0b2b91 rootvg
hdisk10 none None
hdisk11 003752146ff979f4 None
hdisk12 003752146ff9a31b None
hdisk10没有分配PVID,我们看看0扇区的十六进制代码:
# lquerypv -h /dev/hdisk10 0 200 (结果:第一列是序号,后4列是十六进制数据)
00000000 C9C2D4C1 00000000 00000000 00000000 |................|
00000010 00000000 00000000 00000000 00000000 |................|
00000020 00000000 00000000 00000000 00000000 |................|
00000030 00000000 00000000 00000000 00000000 |................|
00000040 00000000 00000000 00000000 00000000 |................|
00000050 00000000 00000000 00000000 00000000 |................|
00000060 00000000 00000000 00000000 00000000 |................|
00000070 00000000 00000000 00000000 00000000 |................|
00000080 00000000 00000000 00000000 00000000 |................|
00000090 00000000 00000000 00000000 00000000 |................|
000000A0 00000000 00000000 00000000 00000000 |................|
000000B0 00000000 00000000 00000000 00000000 |................|
000000C0 00000000 00000000 00000000 00000000 |................|
000000D0 00000000 00000000 00000000 00000000 |................|
000000E0 00000000 00000000 00000000 00000000 |................|
000000F0 00000000 00000000 00000000 00000000 |................|
00000100 00000000 00000000 00000000 00000000 |................|
00000110 00000000 00000000 00000000 00000000 |................|
00000120 00000000 00000000 00000000 00000000 |................|
00000130 00000000 00000000 00000000 00000000 |................|
00000140 00000000 00000000 00000000 00000000 |................|
00000150 00000000 00000000 00000000 00000000 |................|
00000160 00000000 00000000 00000000 00000000 |................|
00000170 00000000 00000000 00000000 00000000 |................|
00000180 00000000 00000000 00000000 00000000 |................|
00000190 00000000 00000000 00000000 00000000 |................|
000001A0 00000000 00000000 00000000 00000000 |................|
000001B0 00000000 00000000 00000000 00000000 |................|
000001C0 00000000 00000000 00000000 00000000 |................|
000001D0 00000000 00000000 00000000 00000000 |................|
000001E0 00000000 00000000 00000000 00000000 |................|
000001F0 00000000 00000000 00000000 00000000 |................|
# chdev -l hdisk10 -a pv=yes
hdisk10 changed
# lspv
hdisk0 003752149a0b2b91 rootvg
hdisk10 0037521474170251 None
hdisk11 003752146ff979f4 None
hdisk12 003752146ff9a31b None
# lquerypv -h /dev/hdisk10 0 200
00000000 C9C2D4C1 00000000 00000000 00000000 |................|
00000010 00000000 00000000 00000000 00000000 |................|
00000020 00000000 00000000 00000000 00000000 |................|
00000030 00000000 00000000 00000000 00000000 |................|
00000040 00000000 00000000 00000000 00000000 |................|
00000050 00000000 00000000 00000000 00000000 |................|
00000060 00000000 00000000 00000000 00000000 |................|
00000070 00000000 00000000 00000000 00000000 |................|
00000080 00375214 74170251 00000000 00000000 |.7R.t..Q........|
00000090 00000000 00000000 00000000 00000000 |................|
000000A0 00000000 00000000 00000000 00000000 |................|
000000B0 00000000 00000000 00000000 00000000 |................|
000000C0 00000000 00000000 00000000 00000000 |................|
000000D0 00000000 00000000 00000000 00000000 |................|
000000E0 00000000 00000000 00000000 00000000 |................|
000000F0 00000000 00000000 00000000 00000000 |................|
00000100 00000000 00000000 00000000 00000000 |................|
00000110 00000000 00000000 00000000 00000000 |................|
00000120 00000000 00000000 00000000 00000000 |................|
00000130 00000000 00000000 00000000 00000000 |................|
00000140 00000000 00000000 00000000 00000000 |................|
00000150 00000000 00000000 00000000 00000000 |................|
00000160 00000000 00000000 00000000 00000000 |................|
00000170 00000000 00000000 00000000 00000000 |................|
00000180 00000000 00000000 00000000 00000000 |................|
00000190 00000000 00000000 00000000 00000000 |................|
000001A0 00000000 00000000 00000000 00000000 |................|
000001B0 00000000 00000000 00000000 00000000 |................|
000001C0 00000000 00000000 00000000 00000000 |................|
000001D0 00000000 00000000 00000000 00000000 |................|
000001E0 00000000 00000000 00000000 00000000 |................|
000001F0 00000000 00000000 00000000 00000000 |................|
这样我们就知道chdev -l hdisk10 -a pv=yes更改了哪些数据了。
lquerypv -h /dev/hdisk10 0 200 这个命令行很有用,你可以查看硬盘中任何一个扇区的内容,后面两个参数的具体意思:
lquerypv -h /dev/hdisk10 0
200
0 -- 从硬盘哪个字节开始查看,是十六进制
200 -- 输出到屏幕上的字节数,十六进制,十六进制200转换成十进制,512,就是一个扇区的大小。
假如我们要查看128扇区数据,命令应该是:
lquerypv -h /dev/hdisk10 10000 200
10000怎么换算来的? 128*512=65536(十进制),转换成十六进制是10000,因为我们要看一个扇区的数据,后面的参数就是512字节,转换成十六进制就是200。
mkvg对硬盘的数据改动
我们来看一下操作
# lspv
hdisk0 003752149a0b2b91 rootvg
hdisk13 003752147454a336 None
hdisk14 003752147454c64c None
hdisk15 003752147454e7cd None
# mkvg -s 256 -y testvg hdisk13 hdisk14 hdisk15
# lspv
hdisk0 003752149a0b2b91 rootvg
hdisk13 003752147454a336 testvg
hdisk14 003752147454c64c testvg
hdisk15 003752147454e7cd testvg
***************************************************************************
# readvgda -s hdisk13
lvmid: 1598838349
vgid: 0037521400004c00000000dc74595c25
lvmarea_len: 4212
vgda_len: 2098
vgda_psn[0]: 136
vgda_psn[1]: 2242
reloc_psn: 286749223
pv_num: 1
pp_size: 28
vgsa_len: 8
vgsa_psn[0]: 128
vgsa_psn[1]: 2234
version: 8
vg_type: -8739
(这是LVM record,在硬盘前128个扇区,分别在7sec和70sec)
*=============== 1ST VGDA-VGSA: hdisk13 ===============*
*****************************************
VGSA at block 128
*****************************************
*****************************************
vgsa beg: timestamp 946844818 (386fb492), 357026209 (1547c9a1) --这个是时间戳,在128sec开头8个字节。
vgsa beg: timestamp Sun Jan 2 14:26:58 CST:2000
vgsa.pv_missing: 0
vgsa.stalepp[0]: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
vgsa.stalepp[1]: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
vgsa.stalepp[2]: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
vgsa.factor: 1
vgsa.pad2: 0 0 0
vgsa end: timestamp 946844818 (386fb492), 357026209 (1547c9a1)--这个是时间戳,在135sec结尾8个字节。
vgsa end: timestamp Sun Jan 2 14:26:58 CST:2000
(从LVM record知道,VGSA大小是8sec。mkvg时VGSA只写入时间戳)
*****************************************
VGDA at block 136
*****************************************
*****************************************
vgh.vg_id: 0037521400004c00000000dc74595c25
vgh.numlvs: 0
vgh.maxlvs: 256
vgh.pp_size: 28
vgh.numpvs: 3
vgh.total_vgdas: 3
vgh.vgda_size: 2098
vgh.quorum: 1
vgh.auto_varyon: 1
vgh.check_sum: 0
vgda hdr: timestamp 946844818 (386fb492), 402158211 (17f87283)
vgda hdr: timestamp Sun Jan 2 14:26:58 CST:2000
(这是真正的VGDA头部信息,在硬盘136sec)
********** Physical Volume: 1 ***********
pvh.pv_num: 1
pvh.pv_id: 003752147454a336
pvh.pp_count: 546
pvh.pv_state: 1
pvh.pvnum_vgdas: 1
pvh.psn_part1: 4352
(这是Physical Volume: 1的LP MAP表头部信息,在153sec)
********** Physical Volume: 2 ***********
pvh.pv_num: 2
pvh.pv_id: 003752147454c64c
pvh.pp_count: 15
pvh.pv_state: 1
pvh.pvnum_vgdas: 1
pvh.psn_part1: 4352
(这是Physical Volume: 2的LP MAP表头部信息,在188sec)
********** Physical Volume: 3 ***********
pvh.pv_num: 3
pvh.pv_id: 003752147454e7cd
pvh.pp_count: 67
pvh.pv_state: 1
pvh.pvnum_vgdas: 1
pvh.psn_part1: 4352
(这是Physical Volume: 3 的LP MAP表头部信息,在189sec)
*****************************************
vgt.concurrency: 0
vgda trl: timestamp 946844818 (386fb492), 402158211 (17f87283)
vgda trl: timestamp Sun Jan 2 14:26:58 CST:2000
*=============== 2ND VGDA-VGSA: hdisk13 ===============*
*****************************************
VGSA at block 2234
*****************************************
*****************************************
vgsa beg: timestamp 946844818 (386fb492), 357026209 (1547c9a1)
vgsa beg: timestamp Sun Jan 2 14:26:58 CST:2000
vgsa.pv_missing: 0
vgsa.stalepp[0]: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
vgsa.stalepp[1]: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
vgsa.stalepp[2]: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
vgsa.factor: 1
vgsa.pad2: 0 0 0
vgsa end: timestamp 946844818 (386fb492), 357026209 (1547c9a1)
vgsa end: timestamp Sun Jan 2 14:26:58 CST:2000
*****************************************
VGDA at block 2242
*****************************************
*****************************************
vgh.vg_id: 0037521400004c00000000dc74595c25
vgh.numlvs: 0
vgh.maxlvs: 256
vgh.pp_size: 28
vgh.numpvs: 3
vgh.total_vgdas: 3
vgh.vgda_size: 2098
vgh.quorum: 1
vgh.auto_varyon: 1
vgh.check_sum: 0
vgda hdr: timestamp 946844818 (386fb492), 402158211 (17f87283)
vgda hdr: timestamp Sun Jan 2 14:26:58 CST:2000
********** Physical Volume: 1 ***********
pvh.pv_num: 1
pvh.pv_id: 003752147454a336
pvh.pp_count: 546
pvh.pv_state: 1
pvh.pvnum_vgdas: 1
pvh.psn_part1: 4352
********** Physical Volume: 2 ***********
pvh.pv_num: 2
pvh.pv_id: 003752147454c64c
pvh.pp_count: 15
pvh.pv_state: 1
pvh.pvnum_vgdas: 1
pvh.psn_part1: 4352
********** Physical Volume: 3 ***********
pvh.pv_num: 3
pvh.pv_id: 003752147454e7cd
pvh.pp_count: 67
pvh.pv_state: 1
pvh.pvnum_vgdas: 1
pvh.psn_part1: 4352
*****************************************
vgt.concurrency: 0
vgda trl: timestamp 946844818 (386fb492), 402158211 (17f87283)
vgda trl: timestamp Sun Jan 2 14:26:58 CST:2000
从readvgda 得到的信息,当mkvg的时候,对硬盘的写操作范围是128sec+lvmarea_len: 4212sec,即4340个扇区
其中128sec以前的LVM record很重要,从128-4339扇区,可以说是原先的数据全部被破坏,相当于先全部清0每个扇区,然后写入vgsa、vgda信息。
重新mkvg过的的VG,原来每个硬盘的LP/PP MAP信息全部被破坏。
下面我们来看一下7sec十六进制数据(为了对比我把硬盘先每个字节都填上DD,然后才mkvg):
7sec
#lquerypv -h /dev/hdisk13 E00 200
00000E00 5F4C564D
00375214 00004C00 000000DC |_LVM.7R...L.....|
00000E10 74595C25 00001074 00000832 00000088 |tY/%...t...2....|
00000E20 000008C2 11177227 00000100 0001001C |......r'........|
00000E30 00000008 00000080 000008BA 0008DDDD |................|
00000E40 00000000 DDDDDDDD DDDDDDDD DDDDDDDD |................|
00000E50 DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD |................|
00000E60 DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD |................|
00000E70 DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD |................|
00000E80 DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD |................|
00000E90 DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD |................|
00000EA0 DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD |................|
00000EB0 DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD |................|
00000EC0 DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD |................|
00000ED0 DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD |................|
00000EE0 DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD |................|
00000EF0 DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD |................|
00000F00 DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD |................|
00000F10 DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD |................|
00000F20 DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD |................|
00000F30 DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD |................|
00000F40 DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD |................|
00000F50 DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD |................|
00000F60 DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD |................|
00000F70 DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD |................|
00000F80 DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD |................|
00000F90 DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD |................|
00000FA0 DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD |................|
00000FB0 DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD |................|
00000FC0 DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD |................|
00000FD0 DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD |................|
00000FE0 DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD |................|
00000FF0 DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD |................|
对照:
lvmid: 1598838349
vgid: 0037521400004c00000000dc74595c25
lvmarea_len:
4212
vgda_len: 2098
vgda_psn[0]: 136
vgda_psn[1]: 2242
reloc_psn: 286749223
pv_num: 1
pp_size: 28
vgsa_len: 8
vgsa_psn[0]:
128
vgsa_psn[1]: 2234
version: 8
vg_type: -8739
如果熟悉了这种对照方式,哪些地方出错还可以重新填写构造出来。
以上是VG创建过程中的一些数据改动细节,让我们知道其实mkvg不会造成用户数据区的丢失,只是改动硬盘系统保留区的数据。
打印某块盘的PVMAP 我们如果要看某个LV的LP/PP MAP信息用下列命令: # lslv -m lvname 就可以看到这个LV的所有LP/PP MAP 如果要看整块盘的PVMAP信息,就得用这个命令: lquerypv -p pvid -N hdiskX -scPnaDdAt 如下: # lquerypv -p 003752147454a336 -N hdisk13 -scPnaDdAt 如果一个硬盘PP数量太多,屏幕往上滚动,我们只能看到最后那些PVMAP信息,为了能方便看到完整的PVMAP信息,我们可以把它保存到文本文件里: # lquerypv -p 003752147454a336 -N hdisk13 -scPnaDdAt >>pvmap.txt 这样我们从结果pvmap.txt看到非常完整的PVMAP,可以知道这块盘的PP在LV中的分配情况。 有位前辈曾经研究过系统保留区信息,因为IBM这方面的资料比较少,大家都还有一些未知的地方,如果有人能补充就更好了。 0-127扇区是IBM前生注定要这么做的,128扇区以后的VGSA、VGDA的每一个信息存放位置都是经过精细计算的,不多余一个扇区,更不会少一个扇区。大家先看看这位前辈整理出来的数据,是不是以前我们渴望得知的东西呢,也顺便想想128sec以后扇区变化规律。 First an overview of the disk layout: PSN = Physical Sector Number, LEN = length in physical sectors Physical Sectors are 512 bytes. Use lquerypv -h to view these offsets Physical Sector Layout (Ver 1) Offset PSN Len Purpose 000000 0 1 IPL Record 000200 1 1 Disk Configuration Record 000400 2 1 First Mirror WriteConsistency Cache Record 000600 3 1 Second Mirror Write Consistence CacheRecord 000800 4 3 Unknown 000E00 7 1 LVM Information Record 001000 8 22 Bad Block Directory 008000 64 1 Backup Configuration Record 008C00 70 1 Backup LVM Information Record 008E00 71 22 Backup Bad Block Directory 00F000 120 8 Concurrent Configuraiton Work Record 010000 128 8 VGSA 011000 136 1 VGDA 011200 137 16 LV Information Records 013200 153 2048 PV Information/PP Maps 113200 2201 32 LV Name Registry 117200 2233 1 Unknown 117400 2234 8 Backup VGSA 118400 2242 1 Backup VGDA 118600 2243 16 Backup LV Information Records 11A600 2259 2048 Backup PV Information/PP Maps 21A600 4307 32 Backup LV Name Registry 21E600 4339 1 Unknown Physical Sector Layout (Ver 5) Offset PSN Length Purpose 000000 0 1 IPL Record 000200 1 1 Disk Configuration Record 000400 2 1 First Mirror Write Consistency Cache Record 000600 3 4 Second Mirror Write Consistence Cache Record 000E00 7 1 LVM Information Record 001000 8 22 Bad Block Directory 008000 64 1 Backup Configuration Record 008C00 70 1 Backup LVM Information Record 008E00 71 22 Backup Bad Block Directory 00F000 120 8 Concurrent Configuraiton Work Record 010000 128 256 VGSA 030000 384 1 VGDA 030200 385 424 LV Information Records 065200 809 7752 PV Information/PP Maps 42E200 8561 64 LV Name Registry 436200 8625 79 Unknown 440000 8704 256 Backup VGSA 460000 8960 1 Backup VGDA 460200 8961 424 Backup LV Information Records 495200 9385 7752 Backup PV Information/PP Maps 85E200 17137 64 Backup LV Name Registry 866200 17201 79 Unknown 7扇区大致的数据结构如下,欢迎指正 LVM Information Record typedef struct { uint32 lvm_id; /* 0x000 */ uchar vg_id[16]; /*0x004 */ uint32 lvmarea_len; /* 0x014 */ uint32 vgda_len; /* 0x018 */ uint32 vgda_psn[2]; /* 0x01C */ uint32 reloc_psn; /* 0x024 */ uint32 reloc_len; /* 0x028 */ uint16 pv_num; /* 0x02C */ uint16 pp_size; /* 0x02E */ uint32 vgsa_len; /* 0x030 */ uint32 vgsa_psn[2]; /* 0x034 */ uint16 version; /* 0x03C */ uint16 vg_type; /* 0x03E */ int32 ltg_shift; /* 0x040 */ uchar padding1[444]; /* 0x044 */ } 开讲VGSA,揭开神秘面纱 VGSA--Volume Group Status Area,VG中的硬盘状态、PP状态描述区域。 注明:以下数据分析基于普通VG,硬盘最大数量为32块,即mkvg的时候factor=1,每块硬盘最大PP数为1016。 # readvgda -s hdisk13 lvmid: 1598838349 vgid: 0037521400004c00000000dc74595c25 lvmarea_len: 4212 vgda_len: 2098 vgda_psn[0]: 136 vgda_psn[1]: 2242 reloc_psn: 286749223 pv_num: 1 pp_size: 28 vgsa_len: 8 vgsa_psn[0]: 128 vgsa_psn[1]: 2234 version: 8 vg_type: -8739 *=============== 1ST VGDA-VGSA: hdisk13 ===============* ***************************************** VGSA at block 128 ***************************************** ***************************************** vgsa beg: timestamp 946861740 (386ff6ac), 67100033 (3ffdd81) vgsa beg: timestamp Sun Jan 2 19:09:00 CST:2000 vgsa.pv_missing: 0 vgsa.stalepp[0]: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 vgsa.stalepp[1]: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 vgsa.stalepp[2]: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 vgsa.factor: 1 vgsa.pad2: 0 0 0 vgsa end: timestamp 946861740 (386ff6ac), 67100033 (3ffdd81) vgsa end: timestamp Sun Jan 2 19:09:00 CST:2000 ***************************************** VG中的硬盘状态、PP状态的描述是用0和1表示的,0表示状态良好,1表示出现故障。 为什么vgsa_len是8个扇区呢,VGSA到底要存放多少数据呢? 我们来算一下: VG中的硬盘状态,最多预留32块盘状态描述空间。 硬盘中的PP状态,每块盘最多预留1016 PP 描述空间 32块盘最多有 32*1016 = 32512 个PP状态描述空间 VG中的32块盘硬盘状态用掉多少个字节呢?回答是4个Byte 即:00 00 00 00,这4个Byte转换成bit(二进制)就是:00000000 00000000 00000000 00000000 ,这就是32个盘的状态描述地址,如果VG中的第一块盘坏了,硬盘描述状态就是:00000001 00000000 00000000 00000000 ,转换成十六进制就是01 00 00 00。 一个硬盘中的1016个PP,占用几个字节的状态描述空间呢?回答是127个Byte 1个Byte可以描述8个PP状态,1个硬盘用掉:1016 / 8 = 127 (Byte) PP状态描述空间 32块盘的PP描述用掉: 127 * 32 = 4064 Byte , 4064 byte / 512 = 7.9375 sec ,不到8个扇区,其实VGSA还有一些别的参数,所以分配给VGSA 8sec已经够用了。 VGSA结构如下: typedef struct { uint32 vg_mtime[2]; /* 0x000 */ uint32 pv_unavailable_bitmap; /* 0x008 */ uchar pv01_stale_pp_map[127]; /* 0x00C */ uchar pv02_stale_pp_map[127]; /* 0x08B */ uchar pv03_stale_pp_map[127]; /* 0x10A */ uchar pv04_stale_pp_map[127]; /* 0x189 */ uchar pv05_stale_pp_map[127]; /* 0x208 */ uchar pv06_stale_pp_map[127]; /* 0x287 */ uchar pv07_stale_pp_map[127]; /* 0x306 */ uchar pv08_stale_pp_map[127]; /* 0x385 */ uchar pv09_stale_pp_map[127]; /* 0x404 */ uchar pv10_stale_pp_map[127]; /* 0x483 */ uchar pv11_stale_pp_map[127]; /* 0x502 */ uchar pv12_stale_pp_map[127]; /* 0x581 */ uchar pv13_stale_pp_map[127]; /* 0x600 */ uchar pv14_stale_pp_map[127]; /* 0x67F */ uchar pv15_stale_pp_map[127]; /* 0x6FE */ uchar pv16_stale_pp_map[127]; /* 0x77D */ uchar pv17_stale_pp_map[127]; /* 0x7FC */ uchar pv18_stale_pp_map[127]; /* 0x87B */ uchar pv19_stale_pp_map[127]; /* 0x8FA */ uchar pv20_stale_pp_map[127]; /* 0x979 */ uchar pv21_stale_pp_map[127]; /* 0x9F8 */ uchar pv22_stale_pp_map[127]; /* 0xA77 */ uchar pv23_stale_pp_map[127]; /* 0xAF6 */ uchar pv24_stale_pp_map[127]; /* 0xB75 */ uchar pv25_stale_pp_map[127]; /* 0xBF4 */ uchar pv26_stale_pp_map[127]; /* 0xC73 */ uchar pv27_stale_pp_map[127]; /* 0xCF2 */ uchar pv28_stale_pp_map[127]; /* 0xD71 */ uchar pv29_stale_pp_map[127]; /* 0xDF0 */ uchar pv30_stale_pp_map[127]; /* 0xE6F */ uchar pv31_stale_pp_map[127]; /* 0xEEE */ uchar pv32_stale_pp_map[127]; /* 0xF6D */ uchar unknown1; /*0xFEC */ uchar t_factor; /* 0xFED */ uchar unknown2; /* 0xFEE */ uchar unknown3; /* 0xFEF */ uint32 unknown4; /* 0xFF0 */ uint32 unknown5; /* 0xFF4 */ uint32 vg_mtime[2]; /* 0xFF8 */ } VGSA; 到此,VGSA就不再神秘了!如果曾经想弄清楚VGSA是何物的朋友在以前打破脑袋也想不通的话,我想这个帖子就能给你解开谜团。 上面这些内容不是一看就能领悟的,慢慢琢磨吧。 VGDA--LVM的核心 注明:以下数据分析基于普通VG,硬盘最大数量为32块,即mkvg的时候factor=1,每块硬盘最大PP数为1016。BIG VG和factor不是1的时候不尽相同,推理是一样的。 VGDA是紧接在VGSA之后的,他的基本数据结构如下: vgda summary(VG描述)136sec(大小1sec) --> LV Information Records(LV记录) 137-152sec (大小16sec) --> PV Information/PP Maps(PV信息和PV的PP MAP)153-2200sec(大小2048sec) --> LV Name(LV名称)2201-2232sec(大小32sec) -->VG结束时间戳2233sec(大小1sec) readvgda -s hdisk13命令取得VGDA内容如下: VGDA at block 136 ***************************************** ***************************************** vgh.vg_id: 0037521400004c00000000dc74595c25 vgh.numlvs: 1 vgh.maxlvs: 256 vgh.pp_size: 28 vgh.numpvs: 3 vgh.total_vgdas: 3 vgh.vgda_size: 2098 vgh.quorum: 1 vgh.auto_varyon: 1 vgh.check_sum: 0 vgda hdr: timestamp 946861740 (386ff6ac), 99875615 (5f3fb1f) vgda hdr: timestamp Sun Jan 2 19:09:00 CST:2000 ********** Logical Volume: oralv *********** lve.lvname: 0 lve.maxsize: 512 lve.lv_state: 1 lve.mirror: 3 lve.mirror_policy: 2 lve.num_lps: 10 lve.permissions: 1 lve.bb_relocation: 1 lve.write_verify: 2 lve.mirwrt_consist: 1 lve.stripe_exp: 0 lve.striping_width: 0 lve.lv_avoid: 0 lve.child_minor_num: 0 ********** Physical Volume: 1 *********** pvh.pv_num: 1 pvh.pv_id: 003752147454a336 pvh.pp_count: 546 pvh.pv_state: 1 pvh.pvnum_vgdas: 1 pvh.psn_part1: 4352 * pv_num:pp_num:pp_state lv_name:lp_num:pp_copy_val:pv_fst_mir:part_fst_mir:pv_snd_mir:part_snd_mir * pv1: 1:1 oralv:1:1:3:1:2:1 * pv1: 2:1 oralv:2:1:3:2:2:2 * pv1: 3:1 oralv:3:1:3:3:2:3 * pv1: 4:1 oralv:4:1:3:4:2:4 * pv1: 5:1 oralv:5:1:3:5:2:5 * pv1: 6:1 oralv:6:1:3:6:2:6 * pv1: 7:1 oralv:7:1:3:7:2:7 * pv1: 8:1 oralv:8:1:3:8:2:8 * pv1: 9:1 oralv:9:1:3:9:2:9 * pv1: 10:1 oralv:10:1:3:10:2:10 ********** Physical Volume: 2 *********** pvh.pv_num: 2 pvh.pv_id: 003752147454c64c pvh.pp_count: 15 pvh.pv_state: 1 pvh.pvnum_vgdas: 1 pvh.psn_part1: 4352 * pv_num:pp_num:pp_state lv_name:lp_num:pp_copy_val:pv_fst_mir:part_fst_mir:pv_snd_mir:part_snd_mir * pv2: 1:1 oralv:1:3:1:1:3:1 * pv2: 2:1 oralv:2:3:1:2:3:2 * pv2: 3:1 oralv:3:3:1:3:3:3 * pv2: 4:1 oralv:4:3:1:4:3:4 * pv2: 5:1 oralv:5:3:1:5:3:5 * pv2: 6:1 oralv:6:3:1:6:3:6 * pv2: 7:1 oralv:7:3:1:7:3:7 * pv2: 8:1 oralv:8:3:1:8:3:8 * pv2: 9:1 oralv:9:3:1:9:3:9 * pv2: 10:1 oralv:10:3:1:10:3:10 ********** Physical Volume: 3 *********** pvh.pv_num: 3 pvh.pv_id: 003752147454e7cd pvh.pp_count: 67 pvh.pv_state: 1 pvh.pvnum_vgdas: 1 pvh.psn_part1: 4352 * pv_num:pp_num:pp_state lv_name:lp_num:pp_copy_val:pv_fst_mir:part_fst_mir:pv_snd_mir:part_snd_mir * pv3: 1:1 oralv:1:2:1:1:2:1 * pv3: 2:1 oralv:2:2:1:2:2:2 * pv3: 3:1 oralv:3:2:1:3:2:3 * pv3: 4:1 oralv:4:2:1:4:2:4 * pv3: 5:1 oralv:5:2:1:5:2:5 * pv3: 6:1 oralv:6:2:1:6:2:6 * pv3: 7:1 oralv:7:2:1:7:2:7 * pv3: 8:1 oralv:8:2:1:8:2:8 * pv3: 9:1 oralv:9:2:1:9:2:9 * pv3: 10:1 oralv:10:2:1:10:2:10 ***************************************** vgt.concurrency: 0 vgda trl: timestamp 946861740 (386ff6ac), 99875615 (5f3fb1f) vgda trl: timestamp Sun Jan 2 19:09:00 CST:2000 *=============== 2ND VGDA: hdisk13 ===============* 136扇区是VGDA描述数据,大小是1sec 137扇区开始是LV信息记录,每个LV信息记录占用32字节,一个扇区可以存放 512 / 32 = 16 条LV记录。 这个VG最多可以建立256个LV,所以应该给LV记录表预留 256 / 16 = 16sec 这样的话,LV信息记录表空间是16sec,数据就存放在137-152sec这16sec大小的空间。 153sec开始就是PV Information/PP Maps,存放的是每个硬盘的信息以及硬盘的PP MAP,一个PP MAP记录占用32字节, 1块硬盘最大可以分配1016个PP,这样1块硬盘PP MAP 表大小为 1016 * 32 = 32512 字节,每块硬盘的信息记录占用32字节, 所1块盘PV Information/PP Maps占用的空间为 32512 + 32 = 32544字节,32544 / 512 = 63.5625 sec,因为两块硬盘不能在同一个扇区中存放PP MAP 记录,所以1块硬盘PV Information/PP Maps将占用64sec大小。 这个VG最大硬盘数量为32,所以将预留 64 * 32 = 2048sec的空间来存放PV Information/PP Maps。 这样PV Information/PP Maps空间范围是153-2200sec,共2048sec 2201sec开始是LV名称记录,每个LV名称占用64字节,一个扇区可以存放 512 / 64 = 8个LV名称记录 VG可以创建的LV最大数是256,所以预留 256 / 8 =32sec的空间存放LV名称。 这样LV名称存放在2201-2232sec共32sec。 2233sec是VG结束时间戳,占用1个sec. 这就是一个完整的VGDA的数据存放结构,至于里头的 vgda summary LV Information Records PV Information/PP Maps LV Name 这些数据存放结构,将在以后的帖子里讲解。 注:以下是根据标准VG信息得出,Big VG信息结构稍有不同 136sec VGDA描述扇区结构: typedef struct { uint32 vg_mtime[2]; /* 0x00 */ uchar vg_id[16]; /* 0x08 */ uint16 num_lvs; /* 0x18 */ uint16 max_lvs; /* 0x1A */ uint16 pp_size; /* 0x1C */ uint16 num_pvs; /* 0x1E */ uint16 vgda_len; /* 0x20 */ uint16 unknown1; /* 0x22 */ uint16 unknown2; /* 0x24 */ uint16 conc_capable; /* 0x26 */ uint16 unknown3; /* 0x28 */ uint16 unknown4; /* 0x2A */ uint16 unknown5; /* 0x2C */ uchar padding[466]; /* 0x2E */ } VGDA; 137-152sec LV表信息结构 typedef struct { uint16 minor_num; /* 0x000 */ uint16 reserved1; /*0x002 */ uint16 reserved2; /* 0x004 */ uint16 max_lps; /* 0x006 */ uint8 lv_state; /* 0x008 */ uint8 num_copies; /* 0x009 */ uint8 reserved3; /* 0x00A */ uint8 sched_policy; /* 0x00B */ uint16 reserved4; /* 0x00C */ uint16 num_lps; /* 0x00E */ uint8 permissions; /* 0x010 */ uint8 bb_relocation; /* 0x011 */ uint8 write_verify; /* 0x012 */ uint8 mirwrt_consist; /* 0x013 */ uint16 stripe_size; /* 0x014 */ uint16 stripe_width; /* 0x016 */ uint8 lvmirbkp_copy; /* 0x018 */ uint8 reserved5; /* 0x019 */ uint16 reserved6; /* 0x01A */ uint16 reserved7; /* 0x01C */ uint16 reserved8; /* 0x01E */ } LVIR; mklv、rmlv、删除VG所做的数据改动 mklv所作的操作: 1、更改相应时间戳(vgsa、vgda等) 2、更改136sec,在原来LV数基础上加1 3、添加LV表(137sec-152sec),大小32字节 4、更改该LV所用到的硬盘PVMAP表 5、添加LV名称(2201sec-2232sec),大小64字节 6、添加LVCB(在该LV的第一个LP的头一个扇区) rmlv所作的操作: 1、更改相应时间戳(vgsa、vgda等) 2、更改136sec,在原来LV数基础上减1 3、删除该LV的LV表项(137sec-152sec),大小32字节 4、更改该LV所用到的硬盘PVMAP表,清空 5、删除LV名称 当删除LV的时候并没有更改该LV的LVCB信息。 删除VG所作的操作 1、先删除掉该VG下的所有LV 2、清空7、70扇区的LVM Information Record 总之,删除操作只更改系统保留区的数据,对数据区没有任何改动。 数据恢复初步分析 前面已经提到过,当创建VG、删除VG、创建LV、删除LV等操作都会对硬盘系统保留区的数据作更改。 当然做了这些操作以后发现不对劲,运气好的话及时从ODM库中还能捡回一条命。 我们现在的假设是:删除VG、重建VG以后,ODM库也没办法还原,硬盘系统保留区数据遭受严重破坏, 残留下来的可用数据有限。 恢复要做的第一步就是查找硬盘的LV信息的LVCB,因为删除VG、重建VG不会更改LVCB信息。 LVCB有什么特点呢?就是开头有"AIX LVCB”字样,在硬盘上查找这些字符,在windows下可以用winhex等工具。 在AIX下我们要查找硬盘中哪些位置包含哪些字符,有一个非常有用的命令: # lquerypv -h /dev/hdisk1 0 1F40000000 |grep 'AIX LVCB' 这个命令在前面讲过,但这里的作用是查找硬盘物理扇区中包含的某些字符这个功能,对于底层分析来说,真是鬼斧神工! 如果你的机器I/O速度快的话,半袋烟工夫,你就能看到类似下面的结果: 00220000 41495820 4C564342 00006A66 73320000 |AIX LVCB..jfs2..| 50220000 41495820 4C564342 00006A66 73320000 |AIX LVCB..jfs2..| 280220000 41495820 4C564342 00006A66 73320000 |AIX LVCB..jfs2..| 2B0220000 41495820 4C564342 00006A66 73326C6F |AIX LVCB..jfs2lo| 538220000 41495820 4C564342 00006A66 73320000 |AIX LVCB..jfs2..| 7A0220000 41495820 4C564342 00006A66 73000000 |AIX LVCB..jfs...| 7A8220000 41495820 4C564342 00006A66 73320000 |AIX LVCB..jfs2..| 到了这一步,恭喜你,找到了若干个LV的LVCB信息,也就找到了若干个LV的起始位置! 提供一种恢复思路 我们前面已经找到了LVCB信息,顺着LVCB就能找到相应的Superblock。 接下来就是分析,在分析结束以前,不要盲目mklv。 从LVCB信息中,我们可以得出每个LV的LP数,从Superblock我们可以得出该文件系统的大小,这样我们可以大致确定原先PP大小,PP大小数据要统观全局,最后才能确定下来。 如果一个LV中的LP在硬盘上是连续的,重建LV基本上可以找回数据。 最烦琐的就是LV中的LP不连续,我们怎样确定LV中的LP分布情况呢? 1、先确定原先VG中的LV数量,标出VG中的每个LV起始位置,以及每个LV的LP数。 2、计算相邻LVCB之间的间隔PP数。 3、把得出的这些数据对比整理出头绪,大致确定每个LV的LP分布情况。 根据文件系统Inode信息验证前面的推算是否正确,最终确认LV的真实LP分布情况,然后重建LV,就能恢复数据。 建议在做改动之前,备份好每个硬盘系统保留区,备份找到的每个LV的LVCB,一旦发现异常,还可以还原回来。 LV数量是经过全盘搜索得出的信息确定的,我们的前期工作就是要确定LV数量,LV起始位置等。 LV的LP/PP MAP在删除LV、删除VG、重建VG,重建LV的时候会被破坏,从数据恢复角度来说,我们要重新构建精确的LV信息,才能使原来的LV中的LP/PP MAP还原到破坏之前的状态。 |