VMware 虚拟化编程(1) — VMDK/VDDK/VixDiskLib/VADP 概念简析
VMware 虚拟化编程(2) — 虚拟磁盘文件类型详解
VMware 虚拟化编程(3) —VMware vSphere Web Service API 解析
VMware 虚拟化编程(4) — VDDK 安装
VMware 虚拟化编程(5) — VixDiskLib 虚拟磁盘库详解之一
VMware 虚拟化编程(6) — VixDiskLib 虚拟磁盘库详解之二
紧接上篇。
函数原型:
/**
* Retrieves the list of keys in the metadata table.
* Key names are returned as list of null-terminated strings,
* followed by an additional NULL character.
* @param diskHandle [in] Handle to an open virtual disk.
* @param keys [out, optional] Keynames buffer, can be NULL.
* @param maxLen [in] Size of the keynames buffer.
* @param requiredLen [out, optional] Space required for the keys including the double
* end-of-string characters.
* @return VIX_OK if success, suitable VIX error code otherwise.
*/
VixError
VixDiskLib_GetMetadataKeys(VixDiskLibHandle diskHandle,
char *keys,
size_t maxLen,
size_t *requiredLen);
/**
* Retrieves the value of a metadata entry corresponding to the supplied key.
* @param diskHandle [in] Handle to an open virtual disk.
* @param key [in] Key name.
* @param buf [out, optional] Placeholder for key's value in the metadata store,
* can be NULL.
* @param bufLen [in] Size of the buffer.
* @param requiredLen [out, optional] Size of buffer required for the value (including
* end of string character)
* @return VIX_OK if success, VIX_E_DISK_BUFFER_TOO_SMALL if too small a buffer
* and other errors as applicable.
*/
VixError
VixDiskLib_ReadMetadata(VixDiskLibHandle diskHandle,
const char *key,
char *buf,
size_t bufLen,
size_t *requiredLen);
函数调用:
vixError = VixDiskLib_ReadMetadataKeys(diskHandle, &buf[0], requiredLen, NULL);
vixError = VixDiskLib_ReadMetadata(diskHandle, metakey, &val[0],requiredLen, NULL);
元数据表中包含了磁盘卷标、LUN、分区布局、链接个数、文件属性、锁、RDM 封装等信息,Hosted Disk 和 Managed Disk 的元数据也并不相同。
adapterType= buslogic
geometry.heads= 64
geometry.cylinders= 100
geometry.sectors= 32
uuid= 60 00 c2 93 7b a0 3a 03 9f 22 56 c5 29 93 b7 27
需要注意的是,VixDiskLib_ReadMetadataKeys 获取的虚拟磁盘的元数据表中的 key,而非 value,其需要和 VixDiskLib_ReadMetadata 结合使用。
函数原型:
/**
* Creates or modifies a metadata table entry.
* @param diskHandle [in] Handle to an open virtual disk.
* @param key [in] Key name.
* @param val [in] Key's value.
* @return VIX_OK if success, suitable VIX error code otherwise.
*/
VixError
VixDiskLib_WriteMetadata(VixDiskLibHandle diskHandle,
const char *key,
const char *val);
函数调用:
vixError = VixDiskLib_WriteMetadata(diskHandle, metakey, metaVal);
VixDiskLib_WriteMetadata 通过指定 Key/Value 对来更新虚拟磁盘的元数据。如果 Key 不存在,则会新添一项;如果 Key 存在,则更新 Value。Key 可以被设置为空,但是不能删除。
函数原型:
/**
* Creates a local disk. Remote disk creation is not supported.
* @param connection [in] A valid connection.
* @param path [in] VMDK file name given as absolute path
* e.g. "c:\\My Virtual Machines\\MailServer\SystemDisk.vmdk".
* @param createParams [in] Specification for the new disk (type, capacity ...).
* @param progressFunc [in] Callback to report progress.
* @param progressCallbackData [in] Callback data pointer.
* @return VIX_OK if success suitable VIX error code otherwise.
*/
VixError
VixDiskLib_Create(const VixDiskLibConnection connection,
const char *path,
const VixDiskLibCreateParams *createParams,
VixDiskLibProgressFunc progressFunc,
void *progressCallbackData);
函数调用:
vixError = VixDiskLib_Create(connectionHandle, diskPath, &createParams, NULL, NULL);
当你使用 VixDiskLib_ConnectEx 或 VixDiskLib_Connect 连接到 ESX/ESXi Host 之后,就可以调用该函数创建一个新的 hosted disk(本地磁盘)。
@param createParams
:需要指定 磁盘类型、适配器类型、硬件版本,容量 等信息。 NOTE:在 FAT32 以及 FAT 文件系统上,VixDiskLib_Create 要求 hosted disk 的 size 小于 4GB;NTFS 文件系统上,hosted disk 的 size 小于 16TB-54KB(hex FFFFFFF0000);在 ReFS 和 exFAT 文件系统,hosted disk 的 size 小于 2^64 ‐ 1。在最新的 vSphere5.5 以及更新版本中,将支持大于 2TB 的 VMDK File。包括 NFS3 在内的基于 POSIX 的文件系统不再有 2GB 的 VMDK File Size Limit。
函数原型
/**
* Copies a disk with proper conversion.
* @param dstConnection [in] A valid connection to access the destination disk.
* @param dstPath [in] Absolute path for the (new) destination disk.
* @param srcConnection [in] A valid connection to access the source disk.
* @param srcPath [in] Absolute path for the source disk.
* @param vixCreateParams [in] creationParameters (disktype, hardware type...).
* If the destination is remote, createParams is currently
* ignored and disk with default size and adapter type is
* created.
* @param progressFunc [in] Callback to report progress (called on the same thread).
* @param progressCallbackData [in] Opaque pointer passed along with the percent
* complete.
* @param overWrite [in] TRUE if Clone should overwrite an existing file.
* @return VIX_OK if success, suitable VIX error code otherwise (network errors like
* file already exists
* handshake failure, ...
* are all combined into a generic connect message).
*/
VixError
VixDiskLib_Clone(const VixDiskLibConnection dstConnection,
const char *dstPath,
const VixDiskLibConnection srcConnection,
const char *srcPath,
const VixDiskLibCreateParams *vixCreateParams,
VixDiskLibProgressFunc progressFunc,
void *progressCallbackData,
Bool overWrite);
函数调用:
vixError = VixDiskLib_Clone(dstconnection, dstPath, srcConnection, srcPath, &createParams, CloneProgressFunc, NULL, TRUE);
VixDiskLib_Clone 函数能够将一个 VMDK File 中的数据拷贝到另一个 VMDK File 中,支持指定 磁盘类型,磁盘大小,硬件版本 等信息。
因为 VixDiskLib_Create 函数仅支持创建本地的 hosted disk,所以如果你希望创建一个 Remote Managed Disk 的话,就需要使用特别的方式。
函数原型:
/**
* Deletes all extents of the specified disk link. If the path refers to a
* parent disk, the child (redo log) will be orphaned.
* Unlinking the child does not affect the parent.
* @param connection [in] A valid connection.
* @param path [in] Path to the disk to be deleted.
* @return VIX_OK if success, suitable VIX error code otherwise.
*/
VixError
VixDiskLib_Unlink(VixDiskLibConnection connection,
const char *path);
函数调用:
vixError= VixDiskLib(connectionHandle, diskpath);
该函数需要提供两个参数,连接句柄和 VMDK File Name,调用该函数能够彻底删除 VMDK File。需要注意的是,删除一个 VMDK 后,它包含的所有信息都将丢失。一般的,如果虚拟机正在运行,那么 HostOS 将会阻止你删除 VMDK File。 但如果你删除了一个电源已关闭的虚拟机的 VMDK 文件,那么这个 GuestOS 将无法启动。
函数原型:
/**
* Grows an existing disk, only local disks are grown.
* @pre The specified disk is not open.
* @param connection [in] A valid connection.
* @param path [in] Path to the disk to be grown.
* @param capacity [in] Target size for the disk.
* @param updateGeometry [in] Should vixDiskLib update the geometry?
* @param progressFunc [in] Callback to report progress (called on the same thread).
* @param progressCallbackData [in] Opaque pointer passed along with the percent
* complete.
* @return VIX_OK if success, suitable VIX error code otherwise.
*/
VixError
VixDiskLib_Grow(VixDiskLibConnection connection,
const char *path,
VixDiskLibSectorType capacity,
Bool updateGeometry,
VixDiskLibProgressFunc progressFunc,
void *progressCallbackData);
函数调用:
vixError= VixDiskLib_Grow(connectionHandle, diskpath, size, FALSE, GrowProgressFunc, NULL);
调用 VixDiskLib_Grow 函数能够通过增加扇区数量的方式来扩展一个已存在的 VMDK File,但该函数同样仅支持 hosted disk。
函数原型:
/**
* Shrinks an existing disk, only local disks are shrunk.
* @param diskHandle [in] Handle to an open virtual disk.
* @param progressFunc [in] Callback to report progress (called on the same thread).
* @param progressCallbackData [in] Opaque pointer passed along with the percent
* complete.
* @return VIX_OK if success, suitable VIX error code otherwise.
*/
VixError
VixDiskLib_Shrink(VixDiskLibHandle diskHandle,
VixDiskLibProgressFunc progressFunc,
void *progressCallbackData);
函数调用:
vixError= VixDiskLib_Shrink(diskHandle, ShrinkProgressFunc, NULL);
调用 VixDiskLib_Shrink 函数能够回收 VMDK File 中未被使用的空间(标记为 0 的 Blocks),该函数一般对 SPARSE 稀疏型磁盘文件而言效果更佳明显。同样的该函数仅支持 hosted disk。
NOTE:我们可以调用 VixDiskLib_Write 来将未被使用的磁盘空间置零,然后再调用 VixDiskLib_Shrink 来回收这些空间。而且调用 VixDiskLib_Shrink 并不会减少磁盘的实际容量,却可以获得更多的可用空余磁盘空间。
函数原型:
/**
* Defragments an existing disk.
* @param diskHandle [in] Handle to an open virtual disk.
* @param progressFunc [in] Callback to report progress (called on the same thread).
* @param progressCallbackData [in] Opaque pointer passed along with the percent
* complete.
* @return VIX_OK if success, suitable VIX error code otherwise.
*/
VixError
VixDiskLib_Defragment(VixDiskLibHandle diskHandle,
VixDiskLibProgressFunc progressFunc,
void *progressCallbackData);
函数调用:
vixError = VixDiskLib_Defragment(diskHandle, DefragProgressFunc, NULL);
调用函数 VixDiskLib_Defragment 能够对一个已存在的 VMDK File 进行碎片整理,碎片整理能够有效的提高磁盘的性能。需要注意的是碎片整理操作仅会对 SPARSE 稀疏型磁盘文件有效,而平面类型 FLAG 的磁盘文件则无需要进行碎片整理。
NOTE:VixDiskLib_Defragment 实际上是将 2GB 范围内的碎片数据往更低的区段移动,该操作对于 GuestOS 自带的碎片整理工具而言是透明的。VMware 会推荐一种「由内到外」的碎片整理方案,即使用 GuestOS ==> VMDK(VixDiskLib_Defragment) ==> HostOS 的顺序进行整理。
函数原型:
/**
* Renames a virtual disk.
* @param srcFileName [in] Virtual disk file to rename.
* @param dstFileName [in] New name for the virtual disk.
* @return VIX_OK if success, suitable VIX error code otherwise.
*/
VixError
VixDiskLib_Rename(const char *srcFileName,
const char *dstFileName);
函数调用:
vixError = VixDiskLib_Rename(oldDiskpath, newDiskpath);
该函数需要传入两个参数,新旧的 VMDK File Name。HostOS 需要将 GuestOS 的 VMDK File 储存在一个可预见的位置,在 Rename 期间的任何文件访问都有可能造成 I/O 失败,或导致 GuestOS 故障。所以需要注意的是,调用该函数之前,需要确保关闭虚拟机电源。
通常,我们可以通过创建一个虚拟机的快照来生成 VMDK File 的一个重写日志,这个快照包含了磁盘数据和虚拟机状态。但对于 Hosted Disk,我们也可以直接调用 VixDiskLib_CreateChild 函数来生成一个重写日志。所以在 VDDK 相关的术语中,子磁盘(Child Disk)、重做日志(Redo Log)、差异链(Delta Link)、快照数据文件(Snapshot File) 具有相同的含义。从最原始的父磁盘文件(Base File)开始,每一个子磁盘都包含了从父磁盘的原始状态到自身当前状态的集合。换句话说,每个快照数据文件都包含了从上一个快照时间点到当前快照时间点之间的更新数据。
NOTE 1:这些快照数据文件类型为 VIXDISKLIB_DISK_VMFS_SPARSE 稀疏型磁盘文件,并使用了 COW 的机制来存放更新数据,以此来节省存储空间。可参考 《再谈 COW、ROW 快照技术》
NOTE 2:子磁盘被创建之后,vm.vmdk 的指向就会被更改指向它。也就是说,此时的父磁盘是 OR 只读的状态,而子磁盘才是 RW 可读写的状态。
NOTE 3:VMware 虚拟机的第一次快照所得到的快照数据实际上是虚拟机当前状态的全量数据,而之后的快照一般均为增量数据。
函数原型:
/**
* Creates a redo log from a parent disk.
* @param diskHandle [in] Handle to an open virtual disk.
* @param childPath [in] Redo log file name given as absolute path
* e.g. "c:\\My Virtual Machines\\MailServer\SystemDisk_s0001.vmdk".
* @param diskType [in] Either VIXDISKLIB_DISK_MONOLITHIC_SPARSE or
* VIXDISKLIB_DISK_SPLIT_SPARSE.
* @param progressFunc [in] Callback to report progress.
* @param progressCallbackData [in] Callback data pointer.
* @return VIX_OK if success, suitable VIX error code otherwise.
*/
VixError
VixDiskLib_CreateChild(VixDiskLibHandle diskHandle,
const char *childPath,
VixDiskLibDiskType diskType,
VixDiskLibProgressFunc progressFunc,
void *progressCallbackData);
函数调用:
vixError = VixDiskLib_CreateChild(parentHandle, diskPath, VIXDISKLIB_DISK_MONOLITHIC_SPARSE, NULL, NULL);
函数原型:
/**
* Attaches the child disk chain to the parent disk chain. Parent handle is
* invalid after attaching and child represents the combined disk chain.
* @param parent [in] Handle to the disk to be attached.
* @param child [in] Handle to the disk to attach.
* @return VIX_OK if success, suitable VIX error code otherwise.
*/
VixError
VixDiskLib_Attach(VixDiskLibHandle parent, VixDiskLibHandle child);
函数调用:
vixError = VixDiskLib_Attach(parentHandle, childHandle);
如上图,当我们希望访问 Child1 时间点的快照数据时,需要先将子磁盘 Child1a 挂载到 Child1 之后,那么实际上我们会获取到了 Child1 快照时间点时刻的虚拟机状态。类似于将虚拟机恢复到指定的快照时间点,也类似于新建了一条快照链的分支。
当我们对虚拟机的虚拟磁盘进行操作时,需要对这些操作保证一定的原子性,也就是说我们需要保证在对虚拟磁盘的才做完成之前,不会被别的虚拟机操作打断。VDDK 5.0 之后包含了两个新的 VixDiskLib 调用 PrepareForAccess 和 EndAccess,它们用于虚拟机备份时禁用和启用存储迁移功能。这避免了在执行备份时,虚拟机移动了它的存储,从而导致旧的磁盘镜像被遗留了下来。VMware 强烈建议使用这两个调用。
函数原型:
/**
* This function is used to notify the host of the virtual machine that the
* disks of the virtual machine will be opened. The host disables operations on
* the virtual machine that may be adversely affected if they are performed
* while the disks are open by a third party application.
*
* @param connectParams [in] This is always used on remote connections.
* @param identity [in] An arbitrary string containing the identity of the
* application.
* @return VIX_OK if success, suitable VIX error code otherwise.
*/
VixError
VixDiskLib_PrepareForAccess(const VixDiskLibConnectParams *connectParams,
const char *identity);
函数调用:
vixError = VixDiskLib_PrepareForAccess(&cnxParams, “vmName”);
@param identity
:一个标识字符串,仅用于跟踪目的,且长度不超过 50 个字符。可以是虚拟机名称或者应用程序名称。VixDiskLib_PrepareForAccess 函数会通知 vCenter 服务器,ESXi 主机正在打开一个虚拟磁盘,ESXi 主机应该推迟所有可能会干扰这次虚拟磁盘访问的虚拟机操作。例如:该函数会禁止虚拟机的 RelocateVM_Task 迁移操作。
NOTE 1:在备份应用程序中,应该在创建虚拟机快照前调用此函数。
NOTE 2:调用该函数必须连接到 vCenter,如果直接到 ESX/ESXi Host 上调用,系统会抛出错误消息:「VDDK: HostAgent is not a vCenter, cannot disable svmotion.」
NOTE 3:在调用该函数时应该以超时时间作为释放依据,否则容易出现程序逻辑上的流动。EXAMPLE:下面的代码片段中,在备份程序中使用 PrepareForAccess 等待存储迁移(Storage vMotion)完成,设定最多只等待 10 分钟。
if(appGlobals.vmxSpec != NULL) {
for (int i = 0; i < 10; i+) {
vixError =VxiDiskLib_PrepareForAccess(&cnxParams, “Sample”);
if (vixError == VIX_OK) {
break;
}
else {
Sleep(60000);
}
}
}
函数原型:
/**
* This function is used to notify the host of a virtual machine that the
* virtual machine disks are closed and that the operations which rely on the
* virtual machine disks to be closed can now be allowed.
*
* @param connectParams [in] Always used for a remote connection. Must be the
* same parameters as used in the corresponding PrepareForAccess call.
* @param identity [in] An arbitrary string containing the identity of the
* application.
* @return VIX_OK of success, suitable VIX error code otherwise.
*/
VixError
VixDiskLib_EndAccess(const VixDiskLibConnectParams *connectParams,
const char *identity);
函数调用:
vixError= VixDiskLib_EndAccess(&cnxParams, “vmName”);
每一次调用 VixDiskLib_PrepareForAcccess 都应该相应的调用一次 VixDiskLib_EndAccess 函数。该函数会通知 ESXi 主机,虚拟磁盘访问已经被关闭,被推迟的虚拟磁盘操作现在可以启用了,如 vMotion,RelocateVM_Task。
NOTE:该函数还能够在关闭所有虚拟磁盘并删除所有虚拟机快照后调用,也能够在奔溃后调用它来做一次 Cleanup 清除操作。
除了高级传输模式以外,大多数操作都 能支持 Hosted Disk,但不包括:
- VixDiskLib_ConnectEx() 扩展连接函数。
- SAN 和 HotAdd 高级传输。
- 使用 VixDiskLib_PrepareForAccess() 和 VixDiskLib_EndAccess() 延迟存储迁移。
vixError= VixDiskLib_Clone(appGlobals.connection, appGlobals.diskPath, srcConnection,appGlobals.srcPath, &createParam, CloneProgressFunc, NULL, TRUE);
# appGlloobals.connection, appGlobals.diskPath 表示 ESX/ESXi Host 上的远程 VMDK File
# srcConection, appGlobals.srcPath 表示本地 VMDK File。
NOTE:无论在步骤 1 中创建什么类型的 VMDK File,在步骤 3 克隆之后它都会变成 VIXDISKLIB_DISK_VMFS_FLAT 类型的虚拟磁盘。
-.vmdk
重写日志。
是一个序列号,可以通过时间戳来表示。