虛擬磁盤格式:VMDK
vmware設計VMDK的文件格式來模擬物理磁盤,使得虛擬機的操作系統讀寫虛擬磁盤時使用與物理磁盤相應的接口
虛擬磁盤作為一個或多個文件存儲在主機或遠程設備上
- 在vmware workstation或mware pusion上:存在底層主機操作系統(win,Linux.,mac)提供的文件系統上
- 在數據中心平台上:存在Esxi主機存儲或網絡連接的存儲上
- 在Exi主機上:存在VMES(虛擬機文件系統)分區上
總體結構
開始VMDK僅包含一個虛擬盤(base disk),如果拍攝虛擬機快照,會產生增量鏈接(delta link,可能有多個)
每個鏈接由多個區段(extent)組成,每個段對應一個物理存儲區域,即對應一個文件(通常)
下圖中link B,C的區段是開始較小,隨時間變大的區段,稱為稀疏區段(sparse)
linkA的區段可以是稀疏區段,也可以是預先分配好大小的區段(flat,創建時已經預先分配好空間),甚至可以直接由物理設備支持。
描述符文件
VMDK有文本描述符文件,用於描述磁盤中數據布局。該文件可以是單獨文件,也可以包含到虛擬磁盤其它文件內。
下圖為一個ubuntu虛擬機的描述文件。#開頭的為注釋信息。
header部分
更詳細內容見文檔Virtual Disk Format 5.0
字段 | 說明 |
---|---|
version | 表示描述文件的版本,默認為1 |
CID | 內容ID值,一個32位隨機值。當磁盤被打開,第1次修改內容后就會更新 |
paratCID | 父鏈接內容ID值,如linkB的parantCID就是likA的CID,如果沒有父鏈接,則值設為ffffffff |
createType | 描述虛擬碰盤的類型。如果值含有flat就表示已預先分配空間,包含sparse表示按需分配是稀疏磁盤,包含vmfs表示用於Esxi上的存儲,如圖中的2GbMaxExtentsparse表示2GB或更小的稀疏磁盤 |
extent部分
每行描述一個區段
如上圖中第一行RW 4192256 SPARSE "ubuntu-sever-10.10-i386-s001.vmdk"
字段 | 說明 |
---|---|
RW | 訪問權限,這里為可讀可寫 |
4192256 | 占幾個扇區,一個扇區512B,這里換算下來約為2GB |
SPARSE | 區段的存儲分配方式,這里為稀疏的 |
"ubuntu-sever-10.10-i386-s001.vmdk" | 文件名,表示區段相對於描述符文件的路徑 |
disk database部分
存儲虛擬磁盤的其它信息,格式為ddb.<名字>="值"
如ddb.adapterType="lsilogic"表示適配器類型為SCSI,用於SCSI磁盤。
以下表示由適配器初始化的磁盤的每道扇區數,磁頭數,柱面數。
ddb.geometry.sectors = "63"
ddb.geometry.heads = "255"
ddb.geometry.cylinders = "2610"
搜索disk database信息時由底部向頂部開始(即由link C開始)
稀疏區段
這里主要介紹vmware workstation等主機平台的稀疏區段的格式,結構如下圖所示
spare header稀疏頭部分
結構以小端存儲,定義為sectortype的類型是以扇區為單位
字段 | 類型 | 意義 |
---|---|---|
magicNumber | uint32 | 用於驗證每個區段的有效性,vmdk文件的就初始化為0×564d444(即VMDK) |
version | uint32 | 版片號,1或2 |
flags | uint32 | 每比特為一標記。如第16比特表分頁(grains)是否被壓縮 |
capacity | sectortype(uint64) | 該區段的大小,必須是分頁大小的整數倍 |
grainsize | sectortype | 一個頁的大小、必須為2的冪次,次數大於8 |
descriptoroffset | sectortype | 嵌入在段中的描述符文件的偏移量,偏移為幾個扇區,如果沒都為0 |
descriptrsize | sectortype | 當描述符的偏移量不為0是才有效,描述符文件大小 |
numGTEsPerGT | uint32 | 頁表中條目的數量,虛擬磁盤中為512 |
rgdOffset | sectortype | 冗余元數據第0層偏移,偏移為幾個扇區 |
gdOffset | sectortype | 元數據第0層偏移(在下一小節介紹這一概念),偏移為幾個扇區, |
overHead | sectortype | 元數據所占扇區數 |
uncleanShutdown | bool(uint8) | 關閉區段時設置為false,打開時設置為true,如果打開后發現為true,就要進行一致性檢測 |
sigleEndLineChar | char(uint8) | 當用FTP傳輸時,用以下4個進行檢測是否被損壞,初始值為'\n' |
nonEndLineChar | char | 初始值為' ' |
doubleEndLineChar1 | char | 初始值為'\r' |
doubleEndLineChar2 | char | 初始值為'\n' |
compressAlgorithm | uint16 | 磁盤中每一頁的壓縮算法 |
pad[433] | uint8 | 433B的填充,加上前面的79B,所以頭信息共占512B,一個扇區 |
當vsersion=2,flags第2比特被設置時,表示采用zeroed-grain GTE,一般是快照或磁盤被壓縮時設置
下面結合實際看一看,如下圖,為一個區段的第一個扇區的數據
顏色 | 意義 |
---|---|
黃色 | 就是KDMV |
綠色 | 版本號 |
藍色 | flag |
粉色 | 因為小端存儲,所以為3FF800,化為10進制為4192256,因為是sectortype,再乘以512B,約為2GB,即該區段有2GB |
紅色 | 頁的大小,同樣化下來為64KB |
紫色 | 描述符在段中的偏移量,都為0,說明該段不包含 |
白色 | 描述符文件大小也為0 |
橘色 | 頁表中條目數量為512 |
灰色 | 冗余元數據第0層偏移,為1,即1個扇區 |
黑色 | 元數據第0層偏移,為258,即258個扇區 |
青色 | 元數據占扇區數640*512 |
黑框 | false |
四個紅框 | '\n',' ','\r','\n'四個字符 |
紅線 | 壓縮算法,沒有壓縮 |
稀疏區段元數據(grain directory, grain table)部分
grain directory頁目錄(GD)是第0層元數據,grain table頁表(GT)是第1層元數據,頁目錄中的每一個條目指向一個頁表區塊,如下圖所示
redundancy grain directory,redundancy grain table為保存的副本
頁目錄中的條目(GDE)指頁表在稀疏區段中的偏移量,條目的數量取決於段的大小,一個條目占32位
頁表中的條目(GTE)指一個頁在稀疏區段中的偏移量,每個頁表有512個條目,每個條目占32位,所以一個頁表占2KB
在頭中的grainsize表示頁的大小為64KB,區段的大小是頁的大小的整數倍,所以也可知道VMDK采用的是段頁式的存儲結構
下面再結合實際看一看
首先找頁目錄
冗余頁目錄為1扇區處(由頭信息知),即偏移512B,冗余頁目錄如下
再找冗余頁表
只看上圖冗余頁目錄第一個32位 02 00 00 00,小端存儲,就是2,2扇區偏移1024B,所以第一個冗余頁表如下圖
那么冗余頁表第一個32比特80 02 00 00表示第一個頁在640扇區偏移處
再看看頁目錄和頁表是否與冗余頁目錄頁表一致:
頁目錄在258扇區處(由頭信息知),即偏移132096B,頁目錄如下
頁目錄第一個32位 03 01 00 00,為259,即偏移132608B,第一個頁表如下
那么第一個頁表第一個32比特80 02 00 00表示第一個頁在640扇區偏移處,可見冗余頁表頁目錄與頁表,頁目錄一致
下面再看看第一個數據的頁,偏移在640*512,即偏移327680,這里因為是MBR的分區結構,我們可以看到陰影處為第一個分區表,在陰影中00 08 00 00表示第一個分區的起始扇區號為2048,更多見