二、VHD/VHDX虚拟硬盘的架构是什么,和物理的硬盘相比,VHD/VHDX虚拟硬盘有何不同?
一个传统的物理硬盘抛开物理组成部分的话,物理组成部分无非就是:接口、Buffer、主控芯片、RAM、电机(SSD就是Flash颗粒)。剩下的就是一个地址序列,这个序列从0~n-1,每个地址包含512B(字节)的控件。一般我们将这些地址称作逻辑块地址(LBA),每块由512B组成。分区表的作用是:告诉系统,磁盘的分区有几个,开始位置和结束位置。磁盘分区表格式目前主要有两种MBR分区表和GUID分区表(GPT)。
VHD/VHDX虚拟硬盘是没有所谓的物理组成部分的,因此VHD/VHDX虚拟硬盘的架构其实就表现为是一个地址序列。
同样,我们先来说说VHD:
在微软的VHD 文件格式规范中【http://download.microsoft.com/download/f/f/e/ffef50a5-07dd-4cf8-aaa3-442c0673a029/Virtual%20Hard%20Disk%20Format%20Spec_10_18_06.doc】,虚拟硬盘VHD文件格式有三种类型:
固定虚拟硬盘:VHD映像文件在存储上预分配为所请求的最大大小。固定虚拟硬盘是用相同容量的VHD 文件模拟同样容量的一个虚拟硬盘,固定虚拟硬盘的VHD 文件在创建时,已分配了全部的空间,确定了大小,不随着数据的写入而改变。
可扩展方式:也称为“动态”和“可动态扩展”方式,VHD映像文件仅使用存储上足够空间来存储虚拟磁盘当前包含的实际数据。创建此类型的虚拟磁盘时,VHD API不会根据请求的最大大小测试物理磁盘上的可用空间,因此可以成功创建最大大小大于可用物理磁盘空间的动态虚拟磁盘空间。值得注意的是,VHD动态虚拟磁盘的最大大小为2,040GB。
差异方式:这种方式是建立在母盘(固定、动态或差分VHD)上的快照,必须有一个基本的VHD虚拟硬盘作为父虚拟磁盘,不能独立存在。在父虚拟磁盘之上创建差异磁盘之后,任何后续写入都写入到差异VHD映像文件中,并且不会修改父VHD映像文件。而且,差异磁盘可以在差异磁盘之上再建立差异磁盘。这也就是CitrixPVS多版本管理的技术。
上述的三种,每一种类型都有着自己的文件格式。
1、固定虚拟硬盘
VHD虚拟硬盘的固定虚拟硬盘的格式:
固定虚拟硬盘的VHD 格式分为两个结构:数据区域和页脚区域。数据区域结构和虚拟硬盘相同,即数据区的扇区与虚拟硬盘的扇区顺序映射。页脚结构是所有类型的VHD 文件共有的结构,位于文件的尾部,占据一个扇区的大小(512B字节)。整个文件的大小是设定的VHD虚拟硬盘大小加上页脚大小(一个扇区),即VHD虚拟硬盘的真实大小是我们设置的值(比如40GB)加上一个扇区的大小(512B字节)。 固定虚拟硬盘所支持的硬盘大小受到操作系统的限制。例如,在FAT32文件系统上,虚拟硬盘的最大大小为4 GB。
而固定虚拟硬盘的VHD虚拟硬盘页脚区域里面有什么呢?根据VHD文件格式的规范文档说明,该页脚格式是所有的VHD类型都共享的格式,也就是该页脚区域的格式是通用的。其页脚区域规定:
硬盘页脚字段 | 大小(字节) |
Cookie(标识) | 8 |
Features(特性) | 4 |
File Format Version(文件格式版本) | 4 |
Data Offset(数据偏移量) | 8 |
Time Stamp(时间戳) | 4 |
Creator Application(应用程序创建者) | 4 |
Creator Version(创建者版本) | 4 |
Creator Host OS(创建者系统) | 4 |
Original Size(原始长度) | 8 |
Current Size(当前长度) | 8 |
Disk Geometry(磁盘参数) | 4 |
Disk Type(磁盘类型) | 4 |
Checksum(校验和) | 4 |
Unique Id(唯一ID) | 16 |
Saved State(保存状态) | 1 |
Reserved(保留) | 427 |
其完整格式如下所示:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | |
标识 | 特性 | 文件格式版本 | 数据偏移量 | |||||||||||||||||||||
时间戳 | 应用程序创建者 | 创建者版本 | 创建者系统 | 原始长度 | ||||||||||||||||||||
当前长度 | 磁盘参数 | 磁盘类型 | 校验和 | 唯一ID | ||||||||||||||||||||
唯一ID | 存态 | 保留 | ||||||||||||||||||||||
保留(427字节) | ||||||||||||||||||||||||
从图上可以看出,页脚结构共有512 字节,其定义了VHD 文件标志、类型、容量等相关信息。下面介绍页脚区域各个字段的意义。
(1)Cookie标识占8 字节。Cookie用于标识硬盘映像的原始唯一创建者。值区分大小写。固定虚拟硬盘的值是“conectix”字符串。cookie存储为8个字符的ASCII字符串,其中“c”在第一个字节,“o”在第二个字节,依此类推。
(2)特性占4 字节。这个字段说明该文件支持的特定功能,常用特性有:无、临时、保留。无特性表明该文件没有嵌入特定功能;特性为临时,表明这是一个临时的VHD 文件,当关机时会被删除;保留特性下,这一位的值必须置为1。
功能 | 值 |
未启用任何功能 | 0x00000000 |
临时 | 0x00000001 |
保留 | 0x00000002 |
(3)文件格式版本占4 字节。表明VHD 的版本信息。此字段分为主要/次要版本,并与创建文件时使用的规范的版本相匹配。最高有效的两个字节用于主要版本。最低有效两个字节是次要版本。这必须与文件格式规范匹配。对于当前规范,此字段必须初始化为0x00010000。
(4)数据偏移量占8字节。该字段保存从文件开头到下一个结构的绝对字节偏移量。此字段用于动态磁盘和差异磁盘,但不用于固定磁盘。对于固定磁盘,此字段应设置为0xFFFFFFFF。
(5)时间戳占4字节。此字段存储硬盘映像的创建时间。这是从UTC/ GMT时区2000年1月1日12:00:00:00开始计时以来的秒数。
(6)应用程序创建者占4字节。此字段用于记录哪个应用程序创建了硬盘。该字段是一个左对齐的文本字段。它使用单字节字符集。如果硬盘由Microsoft Virtual PC创建,则在此字段中写入“vpc”。如果硬盘映像由MicrosoftVirtual Server创建,则在此字段中写入“vs”。其他应用程序应使用自己的唯一标识符。每个应用程序在Windwos中都会有一个自己唯一的标识符。
(7)创建者版本占4字节。此字段保存创建硬盘映像的应用程序的主要/次要版本。
(8)创建者系统占4字节。此字段存储在其上创建此磁盘映像的主机操作系统的类型。
(9)原始长度占8字节。此字段存储创建时从虚拟机的角度来看的硬盘大小(以字节为单位)。此字段用于信息目的。
(10)当前长度占8字节。此字段从虚拟机的角度存储硬盘的当前大小(以字节为单位)。在固定虚拟硬盘格式下,此值与创建硬盘时的原始大小相同。在动态方式下,此值可根据硬盘是否扩展而更改。
(11)硬盘参数占4字节。此字段存储硬盘的磁道,磁头和每磁道的扇区值。
磁盘参数字段 | 大小(字节) |
Cylinder | 2 |
Heads | 1 |
Sectors per track/cylinder | 1 |
当硬盘被配置为ATA硬盘时,ATA控制器使用CHS值(即,磁道,磁头,每磁道的扇区)来确定磁盘的大小。当用户创建具有一定大小的硬盘时,虚拟机中的硬盘映像的大小小于用户创建的硬盘映像的大小。这是因为从硬盘大小计算的CHS值向下取整。
(12)磁盘类型占4字节。
磁盘类型字段 | 值 |
无 | 0 |
Reserved (deprecated) | 1 |
Fixed hard disk | 2 |
Dynamic hard disk | 3 |
Differencing hard disk | 4 |
Reserved (deprecated) | 5 |
Reserved (deprecated) | 6 |
(13)校验和占4字节。此字段只检验VHD 文件的页脚区域,不包括数据部分。校验和是由页脚中除去校验和字段的信息之后计算得到的。如果校验和出错,则认定文件损坏。
(14)唯一ID占16字节。每一块硬盘都有一个唯一ID用于识别硬盘。该唯一的ID是一个128位的通用唯一标识符(UUID)。此字段用于将父硬盘映像与其差异硬盘映像进行关联。
(15)已保存状态占1字节。此字段保存一个字节标志,描述系统是否处于保存状态。如果硬盘处于保存状态,则该值设置为1。无法在保存状态的硬盘上执行压缩和扩展操作。
(16)保留占427字节。此字段顾名思义的保留字段,用于今后可能的参数以及字段扩展,其存储的数据全部是0。它的大小是427字节。
2、可扩展方式(动态)虚拟硬盘
由于可扩展的VHD虚拟硬盘的动态性,因此不同于固定虚拟硬盘的VHD的格式。可扩展的VHD 大小随着写入的数据而动态变化。比如创建一个60GB的可扩展的VHD文件时,它的初始大小可能仅为几百MB,但是随着后期数据的不断写入,可扩展的VHD文件逐渐增加,并最终达到60GB的最大值。这中间存储的数据是随机的,杂乱无章的。因此就必须得有一个类似于记录本一样的东西来记录后来增加的这些数据是存储于那个柱面的那个扇区上。
VHD可扩展的虚拟硬盘格式在规范文档中表示如下:
逻辑结构图表示如下:
由上图可看出,一个扩展的VHD文件由页脚备份区域、头部区域、块分配表、数据区和页脚区域组成。页脚备份区域是对页脚区域的备份,位于文件的第0 扇区;头部区域是1024字节的固定长度,位于文件的第1、2 扇区;块分配表位于头部区域之后,每个条目占4 字节,其随着数据的增长而动态扩展扇区,不固定长度;数据区位于块分配表之后,每个数据块包括扇区位图和块数据,分别为512 字节和2 MB,同样其随着数据的增长而动态扩展扇区,不固定长度;页脚区域是512字节,与固定虚拟硬盘VHD的页脚区域是一样的大小,只是其中关键值不同,其位于文件的最后一个扇区;
1、页脚备份区域
是对页脚区域的备份,其数据和页脚区域一摸一样,因此了解了页脚区域就行,页脚区域在上述的固定虚拟硬盘中以及进行了详细计介绍。
2、头部区域
可扩展的VHD的头部区域表示文件的概况,包括数据块大小,块分配表位置和数量,以及关于差分等重要信息。
在VHD格式规范文档中,可扩展的VHD文件头部的格式如下表所示:
可扩展磁盘头部字段 | 大小(字节) |
Cookie(标识) | 8 |
Data Offset(数据偏移量) | 8 |
Table Offset(表偏移量) | 8 |
Header Version(头部版本) | 4 |
Max Table Entries(最大表条目) | 4 |
Block Size(块大小) | 4 |
Checksum(校验和) | 4 |
Parent Unique ID(母盘唯一ID) | 16 |
Parent Time Stamp(母盘时间戳) | 4 |
Reserved(保留) | 4 |
Parent Unicode Name(母盘Unicode名称) | 512 |
Parent Locator Entry 1(母盘定位器条目1) | 24 |
Parent Locator Entry 2(母盘定位器条目2) | 24 |
Parent Locator Entry 3(母盘定位器条目3) | 24 |
Parent Locator Entry 4(母盘定位器条目4) | 24 |
Parent Locator Entry 5(母盘定位器条目5) | 24 |
Parent Locator Entry 6(母盘定位器条目6) | 24 |
Parent Locator Entry 7(母盘定位器条目7) | 24 |
Parent Locator Entry 8(母盘定位器条目8) | 24 |
Reserved(保留) | 256 |
其逻辑结构如下图所示:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | |
标识 | 数据偏移量 | 表偏移量 | ||||||||||||||||||||||
头部版本 | 最大表条目 | 块大小 | 校验和 | 母盘唯一ID | ||||||||||||||||||||
母盘唯一ID | 母盘时间戳 | 保留 | 母盘Unicode名称 | |||||||||||||||||||||
母盘Unicode名称(512B字节) | ||||||||||||||||||||||||
母盘定位器条目1 | ||||||||||||||||||||||||
………… | ||||||||||||||||||||||||
母盘定位器条目8 | ||||||||||||||||||||||||
保留(256B字节) | ||||||||||||||||||||||||
下面提供了可扩展VHD虚拟硬盘头部字段的详细说明。
(1)Cookie标识占8字节。此字段保存值为“cxsparse”。此字段标识头部是否为合法的头部字段。
(2)数据偏移量占8字节。此字段包含硬盘映像中下一个结构的绝对字节偏移量。目前未被现有任何所格式使用,默认设置为0xFFFFFFFF。
(3)表偏移量占8字节。此字段存储文件中块分配表(BAT)的绝对字节偏移量。由于前两个字段为固定长度,因此块分配表总是从0x600 处开始,字段固定为0x600。
(4)头部版本占4字节。此字段用于存储可扩展VHD虚拟硬盘头部的版本。该字段分为主/次版本。最低有效两个字节表示次版本,最高有效两个字节表示主版本。这必须与文件格式规范匹配。对于本规范,此字段必须初始化为0x00010000。主版本将仅在标头格式修改为不再与产品的旧版本兼容时增加。
(5)最大表条目占4字节。此字段保存BAT中存在的最大条目。这应该等于磁盘中的块数(即磁盘大小除以块大小)。
(6)块大小占4字节。该字段定义了块的容量。块是动态和差异硬盘的扩展单元。它以字节存储。此大小不包括块位图的大小。它只是块的数据部分的大小。每个块的扇区必须总是2的幂次方。默认值为0x00200000(表示块大小为2 MB)。
(7)校验和占4字节。此字段持有动态头部的基本校验和。它是除去头部字段之外其他所有字段之和的一个补码,和页脚区域的校验和计算是一样的。如果校验和验证失败,则会判定文件已损坏。
(8)母盘唯一ID占16字节。此字段用于区分硬盘。差异硬盘存储母盘的128位UUID。可扩展的VHD 虚拟硬盘中这个字段置零。
(9)母盘时间戳占4字节。此字段存储母盘的修改时间戳。这是从时区UTC / GMT 2000年1月1日12:00:00:00开始计算以来的秒数。
(10)保留占4字节。此字段置为零。
(11)母盘Unicode名称占512字节。此字段包含母盘文件名的Unicode字符串(UTF-16)。
(12)母盘定位器条目占192字节(8个条目,每个条目24字节)。这些条目在存储差异硬盘的母盘定位器的文件中存储绝对字节偏移量。用来在不同平台之间迁移VHD文件。此字段仅用于差异磁盘,对于动态磁盘设置为零。
下表描述了每个定位器条目内的字段。
母盘定位器表字段 | 大小(字节) |
Platform Code | 4 |
Platform Data Space | 4 |
Platform Data Length | 4 |
Reserved | 4 |
Platform Data Offset | 8 |
平台代码占4字节。平台代码描述了哪种平台特定的格式用于文件定位器。对于Windows,文件定位器存储为路径(例如,“c\disksp_w_picpaths\ParentDisk.vhd”)。在Macintosh系统上,文件定位器是包含“别名”的二进制大对象(blob)。母盘定位器表用于支持跨平台移动硬盘映像。
一些当前的平台代码包括以下:
Platform Code | Description |
None (0x0) | |
Wi2r (0x57693272) | [deprecated] |
Wi2k (0x5769326B) | [deprecated] |
W2ru (0x57327275) | Unicode pathname (UTF-16) on Windows relative to the differencing disk pathname. |
W2ku (0x57326B75) | Absolute Unicode (UTF-16) pathname on Windows. |
Mac (0x4D616320) | (Mac OS alias stored as a blob) |
MacX(0x4D616358) | A file URL with UTF-8 encoding conforming to RFC 2396. |
平台数据空间占4字节。此字段存储存储母盘定位器所需的512字节扇区数。
平台数据长度占4字节。此字段存储母盘定位器的实际长度(以字节为单位)。
保留占4字节。此字段必须设置为零。
平台数据偏移占8字节。该字段存储存储平台特定文件定位器数据的绝对文件偏移量(以字节为单位)。
(13)保留占256字节。初始化为零。
3、块分配表
块分配表简称BAT,是可扩展VHD文件格式中一个重要的结构,存储了虚拟硬盘到VHD文件的地址映射信息。它由可扩展虚拟硬盘头部的“表偏移”字段指向。
BAT的大小是在创建硬盘期间计算的。BAT中的条目数是完全展开时存储磁盘内容所需的块数。例如,使用2 MB块的基本单位数据块来存储2GB数据,磁盘映像需要1024个BAT条目。 每个条目都是4个字节长,那么大小就为4096个字节。,从块分配表的第1个字节(0x600)开始,所有未使用的表条目都初始化为0xFFFFFFFF。
BAT总是扩展到扇区边界。 可扩展磁盘头部中的“最大表条目”字段指示有多少条目有效。
BAT的条目存储了虚拟硬盘的块地址映射到VHD文件的绝对扇区偏移量,表示虚拟硬盘的块中的数据存储在VHD 文件中以该扇区开始的数据块内。如果向虚拟硬盘的块写入数据,那对应的块分配表的条目为该块在VHD文件分配空间;如果虚拟硬盘的块没有数据写入,那对应的块分配表条目就不分配空间。这保证了虚拟硬盘通过块分配表的动态更新可以随时向VHD 文件写入数据,也阐明了VHD文件容量的动态变化。
其具体的流程图如下图所示:
上图中描述了虚拟硬盘的数据块到VHD文件的数据块的映射关系。块分配表的条目与虚拟硬盘块的数目是保持一致的,且硬盘的第n个块对应块分配表的条目n,也就是一一对应的关系,这样的好处是方便的进行读取的时候按顺序查找所存储的数据在哪个数据块上。但VHD文件的数据区的数据块的顺序不与此对应。图中,块分配表的条目0为虚拟硬盘的第0块分配到VHD文件中以某扇区开始的第1块,即写入虚拟硬盘第0 块的数据会存储在VHD 文件的某扇区第1块数据块区域,这里的某扇区即是VHD文件存储在真实硬盘上的扇区。因此我们就可以理顺VHD虚拟硬盘快分配表的工作模式了:
1)、数据写入到虚拟硬盘数据块。数据首先写入到VHD虚拟硬盘的数据块中;
2)、记录块分配表。然后根据其数据块写入的对应块分配表,记录相应的虚拟硬盘数据块到VHD文件的数据区域的数据块的地址映射信息。
4、数据块
数据块由扇区位图和数据组成。对于VHD可扩展硬盘,扇区位图指示了哪些扇区包含有效数据(值为1),以及哪些扇区未被使用(值为0)。对于差异硬盘,扇区位图指示哪些扇区位于差异磁盘(值为1)内,哪些扇区位于母盘(值为0)中。位图总计有512字节即一个扇区大小。
块是扇区倍数的乘方。默认情况下,块的大小为4096个512字节扇区(2 MB)。虚拟硬盘的所有块必须具有相同的大小。此大小在可扩展虚拟硬盘头部的“块大小”字段中定义。
位图中的相应位为零的块中的所有扇区必须在虚拟硬盘上包含512字节的零。访问磁盘映像的软件可以利用该假设来提高性能。
虚拟硬盘的块经块分配表分配空间后,指向数据块中的扇区位图,通过查看扇区位图的每一位,确认块数据区的使用情况,然后进行对数据的操作。
明白了上述的基本知识之后,我们来说说如何实现可扩展的虚拟硬盘?
首先,数据块按需分配。创建可扩展的虚拟硬盘时,最初不为其分配数据块。新创建的映像仅包含前面描述的数据结构(包括可扩展的虚拟硬盘头部和块分配表BAT)。
当数据写入映像时,可扩展的虚拟硬盘将为写入的数据扩展一个个新的数据块。然后BAT被一一对应进行更新,以包含在映像内分配的每个新数据块的偏移量。
VHD有一个计算公式可以让虚拟硬盘知道其将虚拟硬盘的数据块中的扇区映射到VHD映像文件块中的那个扇区。
要从引用的扇区号计算块号,该公式如下所示:
BlockNumber = floor(RawSectorNumber / SectorsPerBlock)
SectorInBlock = RawSectorNumber%SectorsPerBlock
BlockNumber用作BAT的索引。 BAT条目包含块位图开始的绝对扇区偏移,后面跟块的数据。以下公式可用于计算数据的位置:
ActualSectorLocation = BAT[BlockNumber] + BlockBitmapSectorCount + SectorInBlock
以这种方式,可以以任何顺序分配块,同时保持其通过BAT的排序找到数据。
5、页脚区域
当新分配一个数据块时,页脚区域必须被推回到文件的末尾。
本文出自 “” 博客,请务必保留此出处