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>