kfed是一个没有官方文档记录的asm工具,它可以用来读取和修改asm的元数据块。它本身是一个独立的工具,独立于asm实例,因此不管实例是否启动,asm磁盘组是否mount ,它都可以正常使用。kfed最为强大的地方在于它可以修复asm损坏的元数据。
kfed的二进制文件在最近的asm版本中直接可用,如果你没有在$oracle_home/bin看到,可以通过如下步骤来编译获得:
$ cd $oracle_home/rdbms/lib
$ make -f ins* ikfed
译者注,在11g之前的版本,kfed工具默认没有编译,需要手工编译后才能使用。11g之后版本软件安装完成后就已经对kfed完成了编译,直接可以使用。
使用kfed来可以读取一个asm元数据块(4k大小),它的语法是:
$ kfed read [aun=ii aus=jj blkn=kk dev=]asm_disk_name
命令行参数的介绍:
aun-读取的au号,如果不提供值,默认为au 0
aus-au的大小,默认为1048576字节(1mb),如果磁盘组不是默认的au大小,那么需要在命令行中显式的指定au的大小
blkn-读取的块号,默认为块0或者是au的第一个block
dev-asm磁盘或设备名称。注意dev关键字可省略,但是磁盘名是必须输入的
接下来是一个使用kfed工具的例子,展示了读取asm磁盘/dev/sda1的磁盘头:
$ kfed read /dev/sda1 | more
kfbh.endian: 1 ; 0x000: 0x01
kfbh.hard: 130 ; 0x001: 0x82
kfbh.type: 1 ; 0x002: kfbtyp_diskhead
kfbh.datfmt: 1 ; 0x003: 0x01
kfbh.block.blk: 0 ; 0x004: blk=0
kfbh.block.obj: 2147483648 ; 0x008: disk=0
kfbh.check: 3102721733 ; 0x00c: 0xb8efc6c5
kfbh.fcn.base: 0 ; 0x010: 0x00000000
kfbh.fcn.wrap: 0 ; 0x014: 0x00000000
...
kfdhdb.dsknum: 0 ; 0x024: 0x0000
kfdhdb.grptyp: 2 ; 0x026: kfdgtp_normal
kfdhdb.hdrsts: 3 ; 0x027: kfdhdr_member
kfdhdb.dskname: data_0000 ; 0x028: length=9
kfdhdb.grpname: data ; 0x048: length=4
kfdhdb.fgname: data_0000 ; 0x068: length=9
kfdhdb.ausize: 1048576 ; 0x0bc: 0x00100000
kfdhdb.dsksize: 12284 ; 0x0c4: 0x00002ffc
上面的kfed命令非常的简短,大多使用了默认值,等价于下面这个(所有的参数都显式的设置成了它的默认值):
$ kfed read aun=0 aus=1048576 blkn=0 dev=/dev/sda1
我们能够看到上面kfed的输出被很好的格式化方便我们的阅读,元数据块的输出也根据实际的内容做了分组。
在本例中,kfbh区域显示了块头数据,最重要的有kfbh.type-块类型,这里为kfbtyp_diskhead,表明为磁盘头。
我们通过kfed工具查看asm磁盘头元数据块的实际内容,kfdhdb区域:kfdhdb.dsknum代表本磁盘在磁盘组中的编号为0,kfdhdb.grptyp代表磁盘组的冗余级别为normal,kfdhdb.hdrsts代表磁盘头的状态为member,kfdhdb.dskname代表磁盘的名称为data_0000等等。
如果想了解磁盘头的详细信息,可以参照本系列【asm disk header 】篇。
下一个例子里我们来展示下读取asm file directory block-文件目录块,为了能够达到此目的,我们需要使用kfed命令:
$ kfed read aun=10 blkn=1 dev=/dev/sda1 | more
kfbh.type: 4 ; 0x002: kfbtyp_filedir
上面我通过指定au 10和块1来读取asm的文件目录块(kfbh.type kfbtyp_filedir也说明了这是文件目录块),如果读者对这块不太熟悉,可以参照本系列的【asm file directory】篇来了解如何定位到asm文件目录块。
如果一块磁盘本应属于某个asm磁盘组,但是asm磁盘头的kfbh.type部分却显示了kfbtyp_invalid,那么这说明了asm的磁盘头已经损坏,但是也别着急下结论,你查看的是否是正确的磁盘?是否是正确的磁盘分区?是否还可以通过其他的名字访问磁盘(多路径环境),如果你还不够确定或者你的磁盘头确实已经损坏,可以联系oracle支持来解决问题。
以上的办法适用于所有的asm元数据块,如果asm期待读取到一个asm元数据块,然后读取到了一堆的无意义的值,它将标注这个kfbh.type内容为kfbtyp_invalid,同时ora-15196也会出现在asm或者db的alert日志中。(取决于哪一个实例发现了这个问题)
kfed write命令可以对一个asm元数据块进行写入,语法是:
$ kfed write [aun=ii aus=jj blkn=kk dev=]asm_disk_name text=new_contents chksum=yes
上面新的命令行的参数含义:
text - 新块内容的一个文本文件
checksum - yes,计算和写入正确的checksum值,注意文本文件中的checksum值不需要一定是正确的,写入时checksum参数如果设置的是yes,会自动进行计算
asm元数据块可能看上去是好的,但是事实上已经损坏,例如,元数据块的checksum值可能是错误的,这种情况下我们需要去纠正它,其实,如果仅仅是checksum值不正确,可以很容易通过kfed读取这个块然后再写回的方式进行纠正,kfed工具会计算新的checksum值,然后把正确的checksum值写回。
接下来我们用一个完整的例子来演示如何修复一个元数据块的不正确的checksum值,此元数据块位于磁盘/dev/sda1的au 0,块2。
$ kfed read aun=0 blkn=2 dev=/dev/sda1 > /tmp/aun0_blkn2_sda1.kfed
$ kfed write aun=0 blkn=2 dev=/dev/sda1 text=/tmp/aun0_blkn2_sda1.kfed chksum=yes
注意,遇到任何asm元数据块的损坏都请联系oracle的技术支持。
kfed的find命令会检查一个au上的所有块,然后返回每一个块的类型:
$ kfed find [aun=ii aus=jj dev=]asm_disk_name
find命令一定程度上跟之前的read命令很想象,但是find命令会对指定au上的所有块进行读取操作。(read只会操作一个块)
接下来我们通过kfed find命令识别au 0上所有块:
$ kfed find /dev/sda1
输出的结果如预期,块0为 type 1,块1为type 2,其他的所有块为type 3:
block 0 has type 1
block 1 has type 2
block 2 has type 3
block 3 has type 3
block 4 has type 3
block 255 has type 3
译者注:块0为磁盘头,块1为磁盘的 free space table,块2-块255为磁盘的allocation table,对于free space table的内容参考本系列的【free space table】章节,对于allocation table的内容参考本系列的【allocation table】章节。
如果你看到任何其他别的输出,说明了存在一个毁坏asm元数据块,这种情况下请联系oracle的支持寻求帮助。
由于我的au大小是1mb,因此在这个au上有256个块,如果你的au大小为4mb,上面同样的命令会返回1024个块。
我已经强调过,kfed的find命令只能查看asm元数据块的类型,不能查看实际的元数据块的内容,一些asm元数据块的损坏其实是块内容的损坏,例如块类型是正确的,但是块的内容已经损坏。这种毁坏只能在asm读取的时候才能检测到,这种情况下,ora-15196错误会抛出。
kfed工具是一个低调的,但是非常强大的工具,上面我们只是显示了几个命令,它还有很多其他的命令可以用,例如格式化一个空的asm文件,检查asm元数据块的健康性,展示数据结构的大小,以及执行一些鲜为人知的操作。
<b>本文来自云栖社区合作伙伴“dbgeek”</b>