虚拟磁盘格式1:VMDK

参考文档:Virtual Disk Format 5.0

虚拟磁盘格式: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,更多见

posted @ 2022-04-18 21:26  启林O_o  阅读(1902)  评论(0编辑  收藏  举报