【作者简介】
本人医疗行业DBA,精通oracle底层;会文件、触发器加密的勒索恢复、asm磁盘组不能mount及各种灾难恢复,后面将利用空闲时间将自己工作中遇到的问题及整理的资料分享给更多愿意学习和提升自己的dba。作者微信号:Oray_123
【正文】
1、介绍
ASM的2号文件是ASM的磁盘目录,它跟踪磁盘组中的所有磁盘。每个asm磁盘组都有自己的磁盘目录。磁盘目录也是一个普通的asm文件,磁盘组冗余不同,存放的份数也不同。
每个磁盘目录的条目都维护了如下的一些信息:
● 磁盘号
● 磁盘的状态
● 磁盘的名称
● 所在的Failgroup名称
● 创建的时间戳
● 失败的时间戳
● 自失败时间戳截止目前的时间
● resize目标值
● 磁盘修复时间
● Zone的信息
使用场景:磁盘头所有备份都无法恢复的情况下,手工构造磁盘头需要读取这部分信息出来编辑修改磁盘头,进而mount磁盘组;
2、定位磁盘目录
set line 200
col diskgroup_name for a15
col disk_name for a10
col path for a40
select a.GROUP_NUMBER,a.name diskgroup_name,a.type,a.allocation_unit_size/1024/1024 unit_mb,a.voting_files,b.DISK_NUMBER,b.name disk_name,b.path,
b.os_mb/1024 as os_gb,b.total_mb/1024 as total_gb,b.free_mb/1024 as free_gb
from v$asm_diskgroup a,v$asm_disk b where a.group_number=b.group_number;

我们可以在ASM实例中查询固态表X$KFFXP来查看哪些AU属于ASM的2号文件,同时通过join视图V$ASM_DISK_STAT来获取ASM的磁盘名称,让我们来对一个磁盘组进行查询:
set line 200
col "disk name" for a20
col path for a30
SQL> SELECT x.xnum_kffxp "Extent",
x.au_kffxp "AU",
x.disk_kffxp "Disk #",
d.name "Disk name",
d.path,
d.GROUP_NUMBER,
d.DISK_NUMBER
FROM x$kffxp x, v$asm_disk_stat d
WHERE x.group_kffxp=d.group_number
and x.disk_kffxp=d.disk_number
--and x.group_kffxp=1
and x.number_kffxp=2
ORDER BY 1, 2;

上面的结果展示了3个内容:1、外部冗余上面,只有一个磁盘的disk上保留了磁盘目录file 2的信息;2、normal冗余的磁盘组中,ASM的磁盘目录做了3重镜像。
3、normal上有3重镜像,由于数据在3个AU中是一样的,我们只需要查看第一个AU的内容就可以了,这里是/dev/asmdisk1的AU 3:
让我们使用kfed工具查看下磁盘目录的具体内容:
--第一个for循环au,前20个
--第二个for循环blkn,如果是1M的au,0-255,如果是4M的au,0-1023,根据实际情况调整
for ((i=0;i<=20;i++));do
for ((j=0;j<255;j++));do
DIR=`kfed read dev/asmdisk1 aunum=$i blknum=$j aus=1048576|grep -i diskdir`
if [ "$DIR" != "" ];then
echo "aun="$i "blknum="$j "dir="$DIR
fi
done;
done;

可以可能到,DISK directory 在/dev/asmdisk5上面,使用kfed read dev/asmdisk5 aun=2
--每个磁盘组的磁盘只包含自己磁盘组和磁盘的磁盘目录信息;
for ((j=0;j<255;j++));do
DIR=`kfed read dev/asmdisk1 aun=3 blknum=$j |grep dskname|grep -v "length=0"|tr -d " "|sed "s/.dskname:/=/"|cut -d";" -f 1|paste -d ";" - -`
if [ "$DIR" != "" ];then
echo "blknum="$j "dir="$DIR
fi
done;

--通过上面的扫描可以发现磁盘目录的信息都在块1,其中kfddde[0] 表示的是data 0号磁盘的信息,同理kfddde[1] 表示的是data 1号磁盘的信息
--通过实际对比,我们知道了,要从实际磁盘目录中拿数据的位置:/dev/asmdisk5 aun=2 blkn=0 的 kfddde[0] kfddde[1] kfddde[2]结构体中;
[root@hisdb01 ~]# kfed read dev/asmdisk1 aun=3 blkn=0 aus=1048576|egrep -i "kfbh.type|kfddde\[0\]|kfddde\[1\]|kfddde\[2\]"
3、kfed解析磁盘目录
//通过file 1 定位到file 2的位置:0号磁盘2号au
[root@hisdb01 ~]# kfed read dev/asmdisk1 aun=0 blkn=0|egrep -i "f1b1|dsknum|au"
kfdhdb.dsknum: 0 ; 0x024: 0x0000
kfdhdb.ausize: 1048576 ; 0x0bc: 0x00100000
kfdhdb.f1b1locn: 2 ; 0x0d4: 0x00000002
[root@hisdb01 ~]# kfed read dev/asmdisk1 aun=2 blkn=1|more
kfbh.endian: 1 ; 0x000: 0x01
kfbh.hard: 130 ; 0x001: 0x82
kfbh.type: 4 ; 0x002: KFBTYP_FILEDIR
kfbh.datfmt: 1 ; 0x003: 0x01
kfbh.block.blk: 1 ; 0x004: blk=1
kfbh.block.obj: 1 ; 0x008: file=1
...
kfffde[0].xptr.au: 2 ; 0x4a0: 0x00000002
kfffde[0].xptr.disk: 0 ; 0x4a4: 0x0000
kfffde[0].xptr.flags: 0 ; 0x4a6: L=0 E=0 D=0 S=0
kfffde[0].xptr.chk: 40 ; 0x4a7: 0x28
kfffde[1].xptr.au: 2 ; 0x4a8: 0x00000002
kfffde[1].xptr.disk: 1 ; 0x4ac: 0x0001
kfffde[1].xptr.flags: 0 ; 0x4ae: L=0 E=0 D=0 S=0
kfffde[1].xptr.chk: 41 ; 0x4af: 0x29
kfffde[2].xptr.au: 2 ; 0x4b0: 0x00000002
kfffde[2].xptr.disk: 2 ; 0x4b4: 0x0002
kfffde[2].xptr.flags: 0 ; 0x4b6: L=0 E=0 D=0 S=0
kfffde[2].xptr.chk: 42 ; 0x4b7: 0x2a
//由于一个au是1M,asm 块大小是4096,所以一个au保存256个块,file 1 的分配信息是从0号磁盘2号au的第二个块开始的;file 2 的分配信息是从第三个块开始的(blkn=2);
[root@hisdb01 ~]# kfed read dev/asmdisk1 aun=2 blkn=2|more
kfbh.endian: 1 ; 0x000: 0x01
kfbh.hard: 130 ; 0x001: 0x82
kfbh.type: 4 ; 0x002: KFBTYP_FILEDIR
kfbh.datfmt: 1 ; 0x003: 0x01
kfbh.block.blk: 2 ; 0x004: blk=2
kfbh.block.obj: 1 ; 0x008: file=1
...
kfffde[0].xptr.au: 3 ; 0x4a0: 0x00000003
kfffde[0].xptr.disk: 0 ; 0x4a4: 0x0000
kfffde[0].xptr.flags: 0 ; 0x4a6: L=0 E=0 D=0 S=0
kfffde[0].xptr.chk: 41 ; 0x4a7: 0x29
kfffde[1].xptr.au: 3 ; 0x4a8: 0x00000003
kfffde[1].xptr.disk: 1 ; 0x4ac: 0x0001
kfffde[1].xptr.flags: 0 ; 0x4ae: L=0 E=0 D=0 S=0
kfffde[1].xptr.chk: 40 ; 0x4af: 0x28
kfffde[2].xptr.au: 3 ; 0x4b0: 0x00000003
kfffde[2].xptr.disk: 2 ; 0x4b4: 0x0002
kfffde[2].xptr.flags: 0 ; 0x4b6: L=0 E=0 D=0 S=0
kfffde[2].xptr.chk: 43 ; 0x4b7: 0x2b
通过上面可以看到,分配了3个au,都是在au=3,只是盘号为0,1,2
//查看具体的磁盘目录信息, 对比几个au的块信息,发现都是一样的,没有不同之处;
[root@hisdb01 ~]# kfed read /dev/asmdisk1 aun=3 blkn=0 > 1
[root@hisdb01 ~]# kfed read /dev/asmdisk2 aun=3 blkn=0 > 2
[root@hisdb01 ~]# kfed read /dev/asmdisk3 aun=3 blkn=0 > 3
[root@hisdb01 ~]# diff 1 2
[root@hisdb01 ~]# diff 1 3
[root@hisdb01 ~]# diff 2 3
//从下面的信息可以看出,asm disk directory的结构分为3部分:
1) kfbh,这部分表示块头信息;通用
2) kffdnd,这部分是目录结构信息
3) kfddde,这部分是disk directory元数据中最重要的一部分结构,每个磁盘用kfddde[n]来表示;比如systemdg 是normal磁盘组的磁盘目录,用了三部分来表示3块磁盘;
[root@hisdb01 ~]# cat 1
kfbh.endian: 1 ; 0x000: 0x01
kfbh.hard: 130 ; 0x001: 0x82
kfbh.type: 6 ; 0x002: KFBTYP_DISKDIR
kfbh.datfmt: 1 ; 0x003: 0x01
kfbh.block.blk: 0 ; 0x004: blk=0
kfbh.block.obj: 2 ; 0x008: file=2
kfbh.check: 175336811 ; 0x00c: 0x0a736d6b
kfbh.fcn.base: 541 ; 0x010: 0x0000021d
kfbh.fcn.wrap: 0 ; 0x014: 0x00000000
kfbh.spare1: 0 ; 0x018: 0x00000000
kfbh.spare2: 0 ; 0x01c: 0x00000000
kffdnd.bnode.incarn: 1 ; 0x000: A=1 NUMM=0x0 --分配信息,包括block的分支号和指向next freelist block的指针
kffdnd.bnode.frlist.number: 4294967295 ; 0x004: 0xffffffff
kffdnd.bnode.frlist.incarn: 0 ; 0x008: A=0 NUMM=0x0
kffdnd.overfl.number: 4294967295 ; 0x00c: 0xffffffff
kffdnd.overfl.incarn: 0 ; 0x010: A=0 NUMM=0x0 --overf1,表示指向同层级的下一个block
kffdnd.parent.number: 0 ; 0x014: 0x00000000 --表示指向上一层的block
kffdnd.parent.incarn: 1 ; 0x018: A=1 NUMM=0x0
kffdnd.fstblk.number: 0 ; 0x01c: 0x00000000 ---这里的fst应该不是指的free space table,我猜测应该是指的第一个block。
kffdnd.fstblk.incarn: 1 ; 0x020: A=1 NUMM=0x0
kfddde[0].entry.incarn: 1 ; 0x024: A=1 NUMM=0x0
kfddde[0].entry.hash: 0 ; 0x028: 0x00000000
kfddde[0].entry.refer.number:4294967295 ; 0x02c: 0xffffffff
kfddde[0].entry.refer.incarn: 0 ; 0x030: A=0 NUMM=0x0
---- 上面这部分是kfddde.entry信息,里面包括了分支号,hash值、以及指向下一层级相关block的指针,这部分内容无需过多关注
kfddde[0].dsknum: 0 ; 0x034: 0x0000 ---diskgroup中,该disk的disk编号,从0开始排序,该值为0,说明该disk是这个磁盘组中的第一个disk
kfddde[0].state: 2 ; 0x036: KFDSTA_NORMAL ---disk状态。其中2表示normal。在asm中,该值对应v$asm_disk.state,主要有如下几种值:
UNKNOWN ---disk不被diskgroup所识别,通常是diskgroup没有mount。
NORMAL ---disk目前处于online状态,操作正常。
ADDING ---表示disk正在被加入到diskgroup当中,其中add disk过程涉及到一系列的操作,包括更新pst,fst,disk dir以及reblance等各项操作。
DROPPING ---表示disk正在被从某个diskgroup中删除,该操作可以认为是adding的相反过程
HUNG ---该状态表示在drop disk的过程中,由于diskgroup 空间不足而不能完成reblance操作而导致disk处于hung状态。
FORCING ---该状态表示disk已经从diskgroup中移除,但是其disk上的数据尚未被卸载,很可能是强制drop。
DROPPED ---表示disk已经从diskgroup中删除且完成了一系列的相关操作。
关于这个,大家可以去参考官方文档的v$asm_disk.state,我这里再补充一点网上搜到的内容:
#define KFDSTA_INVALID ((kfdsta)0) /* Illegal value */
#define KFDSTA_UNKNOWN ((kfdsta)1) /* ASM disk state not known */
#define KFDSTA_NORMAL ((kfdsta)2) /* Happy disk */
#define KFDSTA_UNUSED ((kfdsta)3) /* Unused State - Open */
#define KFDSTA_DROPPING ((kfdsta)4) /* Disk being dropped from group */
#define KFDSTA_HUNG ((kfdsta)5) /* Disk drop operation hung */
#define KFDSTA_FORCING ((kfdsta)6) /* Disk beinng drop forced */
#define KFDSTA_DROPPED ((kfdsta)7) /* Disk no longer part of group */
#define KFDSTA_ADDING ((kfdsta)8) /* Disk being globally validated */
kfddde[0].ddchgfl: 132 ; 0x037: 0x84
kfddde[0].dskname: SYSTEMDG_0000 ; 0x038: length=13 --磁盘名称,这是asm中定义的diskname.
kfddde[0].fgname: SYSTEMDG_0000 ; 0x058: length=13 ----这表示failgroup diskname,由于我这里是normal冗余,没有单独指定failgroup所以failgroup就是本身。
kfddde[0].crestmp.hi: 33097356 ; 0x078: HOUR=0xc DAYS=0x14 MNTH=0x1 YEAR=0x7e4
kfddde[0].crestmp.lo: 1903236096 ; 0x07c: USEC=0x0 MSEC=0x45 SECS=0x17 MINS=0x1c --这表示磁盘的创建时间
kfddde[0].failstmp.hi: 0 ; 0x080: HOUR=0x0 DAYS=0x0 MNTH=0x0 YEAR=0x0
kfddde[0].failstmp.lo: 0 ; 0x084: USEC=0x0 MSEC=0x0 SECS=0x0 MINS=0x0 --这表示磁盘失败的时间戳
kfddde[0].timer: 0 ; 0x088: 0x00000000
kfddde[0].size: 1000 ; 0x08c: 0x000003e8 --磁盘的大小,由于au是1M,所以磁盘是1000M
kfddde[0].srRloc.super.hiStart: 0 ; 0x090: 0x00000000
kfddde[0].srRloc.super.loStart: 0 ; 0x094: 0x00000000
kfddde[0].srRloc.super.length: 0 ; 0x098: 0x00000000
kfddde[0].srRloc.incarn: 0 ; 0x09c: 0x00000000
kfddde[0].dskrprtm: 0 ; 0x0a0: 0x00000000
下面的这部分内容是zone信息,我是这样理解的,同一个磁盘组,asm将该磁盘组中的所有disk看成一个整体,然后将这些disks进行划分,有点类似分区的感觉或在VG的基础上创建LV的感觉,这里需要注意的是,如果你的磁盘组中有3个盘,那么这里就会分配3个zone,如果是4个就会分配4个,总之,是一一对应的。这样也就保证了同一个磁盘组中的数据是绝对分散的。
kfddde[0].start0: 0 ; 0x0a4: 0x00000000 --zone的其实位置
kfddde[0].size0: 1000 ; 0x0a8: 0x000003e8 --该disk的总大小
kfddde[0].used0: 101 ; 0x0ac: 0x00000065 --该disk的已使用量,这里表示该disk,也就是/dev/asmdisk1使用了101M
kfddde[0].slot: 0 ; 0x0b0: 0x00000000
kfddde[0].imbal00[0]: 99 ; 0x0b4: 0x00000063 --这里我不确定是什么意思,猜测应该是该disk中的data数据大小,除开asm元数据的数据使用量。99M
kfddde[0].imbal00[1]: 0 ; 0x0b8: 0x00000000
kfddde[0].imbal00[2]: 0 ; 0x0bc: 0x00000000
kfddde[0].imbal00[3]: 0 ; 0x0c0: 0x00000000
kfddde[0].imbal01[0]: 0 ; 0x0c4: 0x00000000
kfddde[0].imbal01[1]: 0 ; 0x0c8: 0x00000000
kfddde[0].imbal01[2]: 0 ; 0x0cc: 0x00000000
kfddde[0].imbal01[3]: 0 ; 0x0d0: 0x00000000
kfddde[0].imbal02[0]: 0 ; 0x0d4: 0x00000000
kfddde[0].imbal02[1]: 0 ; 0x0d8: 0x00000000
kfddde[0].imbal02[2]: 0 ; 0x0dc: 0x00000000
kfddde[0].imbal02[3]: 0 ; 0x0e0: 0x00000000
kfddde[0].imbal03[0]: 0 ; 0x0e4: 0x00000000
kfddde[0].imbal03[1]: 0 ; 0x0e8: 0x00000000
kfddde[0].imbal03[2]: 0 ; 0x0ec: 0x00000000
kfddde[0].imbal03[3]: 0 ; 0x0f0: 0x00000000
...
kfddde[1].entry.incarn: 1 ; 0x1e4: A=1 NUMM=0x0
kfddde[1].entry.hash: 1 ; 0x1e8: 0x00000001
kfddde[1].entry.refer.number:4294967295 ; 0x1ec: 0xffffffff
kfddde[1].entry.refer.incarn: 0 ; 0x1f0: A=0 NUMM=0x0
kfddde[1].dsknum: 1 ; 0x1f4: 0x0001
kfddde[1].state: 2 ; 0x1f6: KFDSTA_NORMAL
kfddde[1].ddchgfl: 132 ; 0x1f7: 0x84
kfddde[1].dskname: SYSTEMDG_0001 ; 0x1f8: length=13
kfddde[1].fgname: SYSTEMDG_0001 ; 0x218: length=13
kfddde[1].crestmp.hi: 33097356 ; 0x238: HOUR=0xc DAYS=0x14 MNTH=0x1 YEAR=0x7e4
kfddde[1].crestmp.lo: 1903236096 ; 0x23c: USEC=0x0 MSEC=0x45 SECS=0x17 MINS=0x1c
kfddde[1].failstmp.hi: 0 ; 0x240: HOUR=0x0 DAYS=0x0 MNTH=0x0 YEAR=0x0
kfddde[1].failstmp.lo: 0 ; 0x244: USEC=0x0 MSEC=0x0 SECS=0x0 MINS=0x0
kfddde[1].timer: 0 ; 0x248: 0x00000000
kfddde[1].size: 1000 ; 0x24c: 0x000003e8
kfddde[1].srRloc.super.hiStart: 0 ; 0x250: 0x00000000
kfddde[1].srRloc.super.loStart: 0 ; 0x254: 0x00000000
kfddde[1].srRloc.super.length: 0 ; 0x258: 0x00000000
kfddde[1].srRloc.incarn: 0 ; 0x25c: 0x00000000
kfddde[1].dskrprtm: 0 ; 0x260: 0x00000000
kfddde[1].start0: 0 ; 0x264: 0x00000000
kfddde[1].size0: 1000 ; 0x268: 0x000003e8
kfddde[1].used0: 101 ; 0x26c: 0x00000065
kfddde[1].slot: 0 ; 0x270: 0x00000000
kfddde[1].imbal00[0]: 99 ; 0x274: 0x00000063
kfddde[1].imbal00[1]: 0 ; 0x278: 0x00000000
kfddde[1].imbal00[2]: 0 ; 0x27c: 0x00000000
kfddde[1].imbal00[3]: 0 ; 0x280: 0x00000000
kfddde[1].imbal01[0]: 0 ; 0x284: 0x00000000
kfddde[1].imbal01[1]: 0 ; 0x288: 0x00000000
kfddde[1].imbal01[2]: 0 ; 0x28c: 0x00000000
kfddde[1].imbal01[3]: 0 ; 0x290: 0x00000000
kfddde[1].imbal02[0]: 0 ; 0x294: 0x00000000
kfddde[1].imbal02[1]: 0 ; 0x298: 0x00000000
kfddde[1].imbal02[2]: 0 ; 0x29c: 0x00000000
kfddde[1].imbal02[3]: 0 ; 0x2a0: 0x00000000
kfddde[1].imbal03[0]: 0 ; 0x2a4: 0x00000000
kfddde[1].imbal03[1]: 0 ; 0x2a8: 0x00000000
kfddde[1].imbal03[2]: 0 ; 0x2ac: 0x00000000
kfddde[1].imbal03[3]: 0 ; 0x2b0: 0x00000000
...
kfddde[2].entry.incarn: 1 ; 0x3a4: A=1 NUMM=0x0
kfddde[2].entry.hash: 2 ; 0x3a8: 0x00000002
kfddde[2].entry.refer.number:4294967295 ; 0x3ac: 0xffffffff
kfddde[2].entry.refer.incarn: 0 ; 0x3b0: A=0 NUMM=0x0
kfddde[2].dsknum: 2 ; 0x3b4: 0x0002
kfddde[2].state: 2 ; 0x3b6: KFDSTA_NORMAL
kfddde[2].ddchgfl: 132 ; 0x3b7: 0x84
kfddde[2].dskname: SYSTEMDG_0002 ; 0x3b8: length=13
kfddde[2].fgname: SYSTEMDG_0002 ; 0x3d8: length=13
kfddde[2].crestmp.hi: 33097356 ; 0x3f8: HOUR=0xc DAYS=0x14 MNTH=0x1 YEAR=0x7e4
kfddde[2].crestmp.lo: 1903236096 ; 0x3fc: USEC=0x0 MSEC=0x45 SECS=0x17 MINS=0x1c
kfddde[2].failstmp.hi: 0 ; 0x400: HOUR=0x0 DAYS=0x0 MNTH=0x0 YEAR=0x0
kfddde[2].failstmp.lo: 0 ; 0x404: USEC=0x0 MSEC=0x0 SECS=0x0 MINS=0x0
kfddde[2].timer: 0 ; 0x408: 0x00000000
kfddde[2].size: 1000 ; 0x40c: 0x000003e8
kfddde[2].srRloc.super.hiStart: 0 ; 0x410: 0x00000000
kfddde[2].srRloc.super.loStart: 0 ; 0x414: 0x00000000
kfddde[2].srRloc.super.length: 0 ; 0x418: 0x00000000
kfddde[2].srRloc.incarn: 0 ; 0x41c: 0x00000000
kfddde[2].dskrprtm: 0 ; 0x420: 0x00000000
kfddde[2].start0: 0 ; 0x424: 0x00000000
kfddde[2].size0: 1000 ; 0x428: 0x000003e8
kfddde[2].used0: 101 ; 0x42c: 0x00000065
kfddde[2].slot: 0 ; 0x430: 0x00000000
kfddde[2].imbal00[0]: 99 ; 0x434: 0x00000063
kfddde[2].imbal00[1]: 0 ; 0x438: 0x00000000
kfddde[2].imbal00[2]: 0 ; 0x43c: 0x00000000
kfddde[2].imbal00[3]: 0 ; 0x440: 0x00000000
kfddde[2].imbal01[0]: 0 ; 0x444: 0x00000000
kfddde[2].imbal01[1]: 0 ; 0x448: 0x00000000
kfddde[2].imbal01[2]: 0 ; 0x44c: 0x00000000
kfddde[2].imbal01[3]: 0 ; 0x450: 0x00000000
kfddde[2].imbal02[0]: 0 ; 0x454: 0x00000000
kfddde[2].imbal02[1]: 0 ; 0x458: 0x00000000
kfddde[2].imbal02[2]: 0 ; 0x45c: 0x00000000
kfddde[2].imbal02[3]: 0 ; 0x460: 0x00000000
kfddde[2].imbal03[0]: 0 ; 0x464: 0x00000000
kfddde[2].imbal03[1]: 0 ; 0x468: 0x00000000
kfddde[2].imbal03[2]: 0 ; 0x46c: 0x00000000
kfddde[2].imbal03[3]: 0 ; 0x470: 0x00000000
...
输出信息中的kfbh.type为KFBTYP_DISKDIR代表了这是一个磁盘目录。ASM中的磁盘的信息存储在上面输出内容的kfddde的区域,kfddde[0] 是关于磁盘0,kfddde[1]是关于磁盘1,以此类推。以这种方式我们可以知道磁盘组中所有磁盘的信息,就像你看到的,大部分的信息都可以通过视图V$ASM_DISK去获取,而不需要通过kfed这种工具去查看。




