dumpxml can now serialize: * floppy drives * file-backed and device-backed disk drives * images mounted to virtual CD/DVD drives * IDE and SCSI controllers Co-authored-by: Sri Ramanujam <sramanujam@xxxxxxxxx> Signed-off-by: Matt Coleman <matt@xxxxxxxxx> --- src/hyperv/hyperv_driver.c | 419 +++++++++++++++++++++++++- src/hyperv/hyperv_driver.h | 3 + src/hyperv/hyperv_private.h | 2 + src/hyperv/hyperv_wmi.c | 45 +++ src/hyperv/hyperv_wmi.h | 8 + src/hyperv/hyperv_wmi_classes.h | 19 ++ src/hyperv/hyperv_wmi_generator.input | 134 ++++++++ 7 files changed, 629 insertions(+), 1 deletion(-) diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c index 40739595ac..326c0169e7 100644 --- a/src/hyperv/hyperv_driver.c +++ b/src/hyperv/hyperv_driver.c @@ -293,6 +293,396 @@ hypervCapsInit(hypervPrivate *priv) return NULL; } +/* + * Virtual device functions + */ +static int +hypervGetDeviceParentRasdFromDeviceId(const char *parentDeviceId, + Msvm_ResourceAllocationSettingData *list, + Msvm_ResourceAllocationSettingData **out) +{ + Msvm_ResourceAllocationSettingData *entry = list; + *out = NULL; + + while (entry) { + g_autofree char *escapedDeviceId = virStringReplace(entry->data->InstanceID, "\\", "\\\\"); + g_autofree char *expectedSuffix = g_strdup_printf("%s\"", escapedDeviceId); + + if (g_str_has_suffix(parentDeviceId, expectedSuffix)) { + *out = entry; + break; + } + + entry = entry->next; + } + + if (*out) + return 0; + + return -1; +} + + + +/* + * Functions for deserializing device entries + */ +static int +hypervDomainDefAppendController(virDomainDefPtr def, + int idx, + virDomainControllerType controllerType) +{ + virDomainControllerDefPtr controller = NULL; + + if (!(controller = virDomainControllerDefNew(controllerType))) + return -1; + + controller->idx = idx; + + if (VIR_APPEND_ELEMENT(def->controllers, def->ncontrollers, controller) < 0) + return -1; + + return 0; +} + + +static int +hypervDomainDefAppendIDEController(virDomainDefPtr def) +{ + return hypervDomainDefAppendController(def, 0, VIR_DOMAIN_CONTROLLER_TYPE_IDE); +} + + +static int +hypervDomainDefAppendSCSIController(virDomainDefPtr def, int idx) +{ + return hypervDomainDefAppendController(def, idx, VIR_DOMAIN_CONTROLLER_TYPE_SCSI); +} + + +static int +hypervDomainDefAppendDisk(virDomainDefPtr def, + virDomainDiskDefPtr disk, + virDomainDiskBus busType, + int diskNameOffset, + const char *diskNamePrefix, + int maxControllers, + Msvm_ResourceAllocationSettingData **controllers, + Msvm_ResourceAllocationSettingData *diskParent, + Msvm_ResourceAllocationSettingData *diskController) +{ + size_t i = 0; + int ctrlr_idx = -1; + int addr = -1; + + if (virStrToLong_i(diskParent->data->AddressOnParent, NULL, 10, &addr) < 0) + return -1; + + if (addr < 0) + return -1; + + /* Find controller index */ + for (i = 0; i < maxControllers; i++) { + if (diskController == controllers[i]) { + ctrlr_idx = i; + break; + } + } + + if (ctrlr_idx < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not find controller for disk!")); + return -1; + } + + disk->bus = busType; + disk->dst = virIndexToDiskName(ctrlr_idx * diskNameOffset + addr, diskNamePrefix); + if (busType == VIR_DOMAIN_DISK_BUS_IDE) { + disk->info.addr.drive.controller = 0; + disk->info.addr.drive.bus = ctrlr_idx; + } else { + disk->info.addr.drive.controller = ctrlr_idx; + disk->info.addr.drive.bus = 0; + } + disk->info.addr.drive.target = 0; + disk->info.addr.drive.unit = addr; + + if (VIR_APPEND_ELEMENT(def->disks, def->ndisks, disk) < 0) + return -1; + + return 0; +} + + +static int +hypervDomainDefParseFloppyStorageExtent(virDomainDefPtr def, virDomainDiskDefPtr disk) +{ + disk->bus = VIR_DOMAIN_DISK_BUS_FDC; + disk->dst = g_strdup("fda"); + + if (VIR_APPEND_ELEMENT(def->disks, def->ndisks, disk) < 0) + return -1; + + return 0; +} + + +static int +hypervDomainDefParseVirtualExtent(hypervPrivate *priv, + virDomainDefPtr def, + Msvm_StorageAllocationSettingData *disk_entry, + Msvm_ResourceAllocationSettingData *rasd, + Msvm_ResourceAllocationSettingData **ideChannels, + Msvm_ResourceAllocationSettingData **scsiControllers) +{ + Msvm_ResourceAllocationSettingData *diskParent = NULL; + Msvm_ResourceAllocationSettingData *controller = NULL; + virDomainDiskDefPtr disk = NULL; + int result = -1; + + if (disk_entry->data->HostResource.count < 1) + goto cleanup; + + if (!(disk = virDomainDiskDefNew(priv->xmlopt))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not allocate disk definition")); + goto cleanup; + } + + /* get disk associated with storage extent */ + if (hypervGetDeviceParentRasdFromDeviceId(disk_entry->data->Parent, rasd, &diskParent) < 0) + goto cleanup; + + /* get associated controller */ + if (hypervGetDeviceParentRasdFromDeviceId(diskParent->data->Parent, rasd, &controller) < 0) + goto cleanup; + + /* common fields first */ + disk->src->type = VIR_STORAGE_TYPE_FILE; + disk->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE; + + /* note if it's a CDROM disk */ + if (STREQ(disk_entry->data->ResourceSubType, "Microsoft:Hyper-V:Virtual CD/DVD Disk")) + disk->device = VIR_DOMAIN_DISK_DEVICE_CDROM; + else + disk->device = VIR_DOMAIN_DISK_DEVICE_DISK; + + /* copy in the source path */ + virDomainDiskSetSource(disk, *(char **)disk_entry->data->HostResource.data); + + /* controller-specific fields */ + if (controller->data->ResourceType == MSVM_RASD_RESOURCETYPE_PARALLEL_SCSI_HBA) { + if (hypervDomainDefAppendDisk(def, disk, VIR_DOMAIN_DISK_BUS_SCSI, + 64, "sd", HYPERV_MAX_SCSI_CONTROLLERS, + scsiControllers, diskParent, controller) < 0) { + goto cleanup; + } + } else if (controller->data->ResourceType == MSVM_RASD_RESOURCETYPE_IDE_CONTROLLER) { + if (hypervDomainDefAppendDisk(def, disk, VIR_DOMAIN_DISK_BUS_IDE, + 2, "hd", HYPERV_MAX_IDE_CHANNELS, + ideChannels, diskParent, controller) < 0) { + goto cleanup; + } + } else if (controller->data->ResourceType == MSVM_RASD_RESOURCETYPE_OTHER && + diskParent->data->ResourceType == MSVM_RASD_RESOURCETYPE_DISKETTE_DRIVE) { + if (hypervDomainDefParseFloppyStorageExtent(def, disk) < 0) + goto cleanup; + disk->device = VIR_DOMAIN_DISK_DEVICE_FLOPPY; + } else { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unrecognized controller type %d"), + controller->data->ResourceType); + goto cleanup; + } + + result = 0; + + cleanup: + if (result != 0 && disk) + virDomainDiskDefFree(disk); + + return result; +} + + +static int +hypervDomainDefParsePhysicalDisk(hypervPrivate *priv, + virDomainDefPtr def, + Msvm_ResourceAllocationSettingData *entry, + Msvm_ResourceAllocationSettingData *rasd, + Msvm_ResourceAllocationSettingData **ideChannels, + Msvm_ResourceAllocationSettingData **scsiControllers) +{ + int result = -1; + Msvm_ResourceAllocationSettingData *controller = NULL; + Msvm_DiskDrive *diskdrive = NULL; + virDomainDiskDefPtr disk = NULL; + char **hostResource = entry->data->HostResource.data; + g_autofree char *hostEscaped = NULL; + g_autofree char *driveNumberStr = NULL; + g_auto(virBuffer) query = VIR_BUFFER_INITIALIZER; + int addr = -1, ctrlr_idx = -1; + size_t i = 0; + + if (virStrToLong_i(entry->data->AddressOnParent, NULL, 10, &addr) < 0) + return -1; + + if (addr < 0) + return -1; + + if (hypervGetDeviceParentRasdFromDeviceId(entry->data->Parent, rasd, &controller) < 0) + goto cleanup; + + /* create disk definition */ + if (!(disk = virDomainDiskDefNew(priv->xmlopt))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not allocate disk def")); + goto cleanup; + } + + /* Query Msvm_DiskDrive for the DriveNumber */ + hostEscaped = virStringReplace(*hostResource, "\\\"", "\""); + hostEscaped = virStringReplace(hostEscaped, "\\", "\\\\"); + + /* quotes must be preserved, so virBufferEscapeSQL can't be used */ + virBufferAsprintf(&query, + MSVM_DISKDRIVE_WQL_SELECT "WHERE __PATH='%s'", + hostEscaped); + + if (hypervGetWmiClass(Msvm_DiskDrive, &diskdrive) < 0) + goto cleanup; + + if (!diskdrive) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not find Msvm_DiskDrive object")); + goto cleanup; + } + + driveNumberStr = g_strdup_printf("%u", diskdrive->data->DriveNumber); + virDomainDiskSetSource(disk, driveNumberStr); + + if (addr < 0) + goto cleanup; + + if (controller->data->ResourceType == MSVM_RASD_RESOURCETYPE_PARALLEL_SCSI_HBA) { + for (i = 0; i < HYPERV_MAX_SCSI_CONTROLLERS; i++) { + if (controller == scsiControllers[i]) { + ctrlr_idx = i; + break; + } + } + disk->bus = VIR_DOMAIN_DISK_BUS_SCSI; + disk->dst = virIndexToDiskName(ctrlr_idx * 64 + addr, "sd"); + disk->info.addr.drive.unit = addr; + disk->info.addr.drive.controller = ctrlr_idx; + disk->info.addr.drive.bus = 0; + } else if (controller->data->ResourceType == MSVM_RASD_RESOURCETYPE_IDE_CONTROLLER) { + for (i = 0; i < HYPERV_MAX_IDE_CHANNELS; i++) { + if (controller == ideChannels[i]) { + ctrlr_idx = i; + break; + } + } + disk->bus = VIR_DOMAIN_DISK_BUS_IDE; + disk->dst = virIndexToDiskName(ctrlr_idx * 4 + addr, "hd"); + disk->info.addr.drive.unit = addr; + disk->info.addr.drive.controller = 0; + disk->info.addr.drive.bus = ctrlr_idx; + } else { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid controller type for LUN")); + goto cleanup; + } + + disk->info.addr.drive.target = 0; + virDomainDiskSetType(disk, VIR_STORAGE_TYPE_BLOCK); + disk->device = VIR_DOMAIN_DISK_DEVICE_DISK; + + disk->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE; + + if (VIR_APPEND_ELEMENT(def->disks, def->ndisks, disk) < 0) + goto cleanup; + + result = 0; + + cleanup: + if (result != 0 && disk) + virDomainDiskDefFree(disk); + hypervFreeObject(priv, (hypervObject *)diskdrive); + + return result; +} + + +static int +hypervDomainDefParseStorage(hypervPrivate *priv, + virDomainDefPtr def, + Msvm_ResourceAllocationSettingData *rasd, + Msvm_StorageAllocationSettingData *sasd) +{ + Msvm_ResourceAllocationSettingData *entry = rasd; + Msvm_StorageAllocationSettingData *disk_entry = sasd; + Msvm_ResourceAllocationSettingData *ideChannels[HYPERV_MAX_IDE_CHANNELS]; + Msvm_ResourceAllocationSettingData *scsiControllers[HYPERV_MAX_SCSI_CONTROLLERS]; + bool hasIdeController = false; + int channel = -1; + int scsi_idx = 0; + + /* first pass: populate storage controllers */ + while (entry) { + if (entry->data->ResourceType == MSVM_RASD_RESOURCETYPE_IDE_CONTROLLER) { + channel = entry->data->Address[0] - '0'; + ideChannels[channel] = entry; + if (!hasIdeController) { + /* Hyper-V represents its PIIX4 controller's two channels as separate objects. */ + if (hypervDomainDefAppendIDEController(def) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not add IDE controller")); + return -1; + } + hasIdeController = true; + } + } else if (entry->data->ResourceType == MSVM_RASD_RESOURCETYPE_PARALLEL_SCSI_HBA) { + scsiControllers[scsi_idx++] = entry; + if (hypervDomainDefAppendSCSIController(def, scsi_idx - 1) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not parse SCSI controller")); + return -1; + } + } + + entry = entry->next; + } + + /* second pass: populate physical disks */ + entry = rasd; + while (entry) { + if (entry->data->ResourceType == MSVM_RASD_RESOURCETYPE_DISK_DRIVE && + entry->data->HostResource.count > 0) { + char **hostResource = entry->data->HostResource.data; + + if (strstr(*hostResource, "NODRIVE")) { + /* Hyper-V doesn't let you define LUNs with no connection */ + VIR_DEBUG("Skipping empty LUN '%s'", *hostResource); + entry = entry->next; + continue; + } + + if (hypervDomainDefParsePhysicalDisk(priv, def, entry, rasd, + ideChannels, scsiControllers) < 0) + return -1; + } + + entry = entry->next; + } + + /* third pass: populate virtual disks */ + while (disk_entry) { + if (hypervDomainDefParseVirtualExtent(priv, def, disk_entry, rasd, + ideChannels, scsiControllers) < 0) + return -1; + + disk_entry = disk_entry->next; + } + + return 0; +} + + + /* * Driver functions */ @@ -1249,6 +1639,8 @@ hypervDomainGetXMLDesc(virDomainPtr domain, unsigned int flags) Msvm_VirtualSystemSettingData *virtualSystemSettingData = NULL; Msvm_ProcessorSettingData *processorSettingData = NULL; Msvm_MemorySettingData *memorySettingData = NULL; + Msvm_ResourceAllocationSettingData *rasd = NULL; + Msvm_StorageAllocationSettingData *sasd = NULL; virCheckFlags(VIR_DOMAIN_XML_COMMON_FLAGS, NULL); @@ -1275,6 +1667,18 @@ hypervDomainGetXMLDesc(virDomainPtr domain, unsigned int flags) &memorySettingData) < 0) goto cleanup; + if (hypervGetResourceAllocationSD(priv, + virtualSystemSettingData->data->InstanceID, + &rasd) < 0) { + goto cleanup; + } + + if (hypervGetStorageAllocationSD(priv, + virtualSystemSettingData->data->InstanceID, + &sasd) < 0) { + goto cleanup; + } + /* Fill struct */ def->virtType = VIR_DOMAIN_VIRT_HYPERV; @@ -1324,7 +1728,18 @@ hypervDomainGetXMLDesc(virDomainPtr domain, unsigned int flags) def->os.type = VIR_DOMAIN_OSTYPE_HVM; - /* FIXME: devices section is totally missing */ + /* Allocate space for all potential devices */ + + /* 256 scsi drives + 8 ide drives */ + def->disks = g_new0(virDomainDiskDefPtr, 264); + def->ndisks = 0; + + /* 1 ide & 4 scsi controllers */ + def->controllers = g_new0(virDomainControllerDefPtr, 5); + def->ncontrollers = 0; + + if (hypervDomainDefParseStorage(priv, def, rasd, sasd) < 0) + goto cleanup; /* XXX xmlopts must be non-NULL */ xml = virDomainDefFormat(def, NULL, @@ -1336,6 +1751,8 @@ hypervDomainGetXMLDesc(virDomainPtr domain, unsigned int flags) hypervFreeObject(priv, (hypervObject *)virtualSystemSettingData); hypervFreeObject(priv, (hypervObject *)processorSettingData); hypervFreeObject(priv, (hypervObject *)memorySettingData); + hypervFreeObject(priv, (hypervObject *)rasd); + hypervFreeObject(priv, (hypervObject *)sasd); return xml; } diff --git a/src/hyperv/hyperv_driver.h b/src/hyperv/hyperv_driver.h index 8099b5714b..3a71a2943e 100644 --- a/src/hyperv/hyperv_driver.h +++ b/src/hyperv/hyperv_driver.h @@ -22,4 +22,7 @@ #pragma once +#define HYPERV_MAX_SCSI_CONTROLLERS 4 +#define HYPERV_MAX_IDE_CHANNELS 2 + int hypervRegister(void); diff --git a/src/hyperv/hyperv_private.h b/src/hyperv/hyperv_private.h index f400f58c3a..7a2a1d59ee 100644 --- a/src/hyperv/hyperv_private.h +++ b/src/hyperv/hyperv_private.h @@ -28,10 +28,12 @@ #include "virerror.h" #include "hyperv_util.h" #include "capabilities.h" +#include "domain_conf.h" typedef struct _hypervPrivate hypervPrivate; struct _hypervPrivate { hypervParsedUri *parsedUri; WsManClient *client; virCapsPtr caps; + virDomainXMLOptionPtr xmlopt; }; diff --git a/src/hyperv/hyperv_wmi.c b/src/hyperv/hyperv_wmi.c index efd0659051..466296fe2a 100644 --- a/src/hyperv/hyperv_wmi.c +++ b/src/hyperv/hyperv_wmi.c @@ -1490,6 +1490,32 @@ hypervGetMsvmVirtualSystemSettingDataFromUUID(hypervPrivate *priv, } +int +hypervGetResourceAllocationSD(hypervPrivate *priv, + const char *id, + Msvm_ResourceAllocationSettingData **data) +{ + g_auto(virBuffer) query = VIR_BUFFER_INITIALIZER; + virBufferEscapeSQL(&query, + "ASSOCIATORS OF {Msvm_VirtualSystemSettingData.InstanceID='%s'} " + "WHERE AssocClass = Msvm_VirtualSystemSettingDataComponent " + "ResultClass = Msvm_ResourceAllocationSettingData", + id); + + if (hypervGetWmiClass(Msvm_ResourceAllocationSettingData, data) < 0) + return -1; + + if (!*data) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not look up resource allocation setting data with virtual system instance ID '%s'"), + id); + return -1; + } + + return 0; +} + + int hypervGetProcessorSD(hypervPrivate *priv, const char *id, @@ -1536,6 +1562,25 @@ hypervGetMemorySD(hypervPrivate *priv, } +int +hypervGetStorageAllocationSD(hypervPrivate *priv, + const char *id, + Msvm_StorageAllocationSettingData **data) +{ + g_auto(virBuffer) query = VIR_BUFFER_INITIALIZER; + virBufferEscapeSQL(&query, + "ASSOCIATORS OF {Msvm_VirtualSystemSettingData.InstanceID='%s'} " + "WHERE AssocClass = Msvm_VirtualSystemSettingDataComponent " + "ResultClass = Msvm_StorageAllocationSettingData", + id); + + if (hypervGetWmiClass(Msvm_StorageAllocationSettingData, data) < 0) + return -1; + + return 0; +} + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Msvm_VirtualSystemManagementService */ diff --git a/src/hyperv/hyperv_wmi.h b/src/hyperv/hyperv_wmi.h index 34334a0153..31f7e2e3ba 100644 --- a/src/hyperv/hyperv_wmi.h +++ b/src/hyperv/hyperv_wmi.h @@ -236,6 +236,10 @@ int hypervGetMsvmVirtualSystemSettingDataFromUUID(hypervPrivate *priv, const char *uuid_string, Msvm_VirtualSystemSettingData **list); +int hypervGetResourceAllocationSD(hypervPrivate *priv, + const char *id, + Msvm_ResourceAllocationSettingData **data); + int hypervGetProcessorSD(hypervPrivate *priv, const char *id, Msvm_ProcessorSettingData **data); @@ -244,6 +248,10 @@ int hypervGetMemorySD(hypervPrivate *priv, const char *vssd_instanceid, Msvm_MemorySettingData **list); +int hypervGetStorageAllocationSD(hypervPrivate *priv, + const char *id, + Msvm_StorageAllocationSettingData **data); + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Msvm_VirtualSystemManagementService */ diff --git a/src/hyperv/hyperv_wmi_classes.h b/src/hyperv/hyperv_wmi_classes.h index 161e9be131..36c0e60c2a 100644 --- a/src/hyperv/hyperv_wmi_classes.h +++ b/src/hyperv/hyperv_wmi_classes.h @@ -98,6 +98,25 @@ enum _Msvm_ConcreteJob_JobState { }; + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Msvm_ResourceAllocationSettingData + */ + +/* https://docs.microsoft.com/en-us/windows/win32/hyperv_v2/msvm-resourceallocationsettingdata */ +enum _Msvm_ResourceAllocationSettingData_ResourceType { + MSVM_RASD_RESOURCETYPE_OTHER = 1, + MSVM_RASD_RESOURCETYPE_IDE_CONTROLLER = 5, + MSVM_RASD_RESOURCETYPE_PARALLEL_SCSI_HBA = 6, + MSVM_RASD_RESOURCETYPE_DISKETTE_DRIVE = 14, + MSVM_RASD_RESOURCETYPE_CD_DRIVE = 15, + MSVM_RASD_RESOURCETYPE_DVD_DRIVE = 16, + MSVM_RASD_RESOURCETYPE_DISK_DRIVE = 17, + MSVM_RASD_RESOURCETYPE_STORAGE_EXTENT = 19, +}; + + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * WMI */ diff --git a/src/hyperv/hyperv_wmi_generator.input b/src/hyperv/hyperv_wmi_generator.input index bc0e781676..e1b4fd3f9f 100644 --- a/src/hyperv/hyperv_wmi_generator.input +++ b/src/hyperv/hyperv_wmi_generator.input @@ -601,6 +601,34 @@ class Msvm_VirtualSystemManagementService end +class Msvm_ResourceAllocationSettingData + string InstanceID + string Caption + string Description + string ElementName + uint16 ResourceType + string OtherResourceType + string ResourceSubType + string PoolID + uint16 ConsumerVisibility + string HostResource[] + string AllocationUnits + uint64 VirtualQuantity + uint64 Reservation + uint64 Limit + uint32 Weight + boolean AutomaticAllocation + boolean AutomaticDeallocation + string Parent + string Connection[] + string Address + uint16 MappingBehavior + string AddressOnParent + string VirtualQuantityUnits + string VirtualSystemIdentifiers[] +end + + class Msvm_Keyboard string InstanceID string Caption @@ -688,3 +716,109 @@ class Msvm_ShutdownComponent uint16 AdditionalAvailability[] uint64 MaxQuiesceTime end + + +class Msvm_DiskDrive + string InstanceID + string Caption + string Description + string ElementName + datetime InstallDate + string Name + uint16 OperationalStatus[] + string StatusDescriptions[] + string Status + uint16 HealthState + uint16 CommunicationStatus + uint16 DetailedStatus + uint16 OperatingStatus + uint16 PrimaryStatus + uint16 EnabledState + string OtherEnabledState + uint16 RequestedState + uint16 EnabledDefault + datetime TimeOfLastStateChange + uint16 AvailableRequestedStates[] + uint16 TransitioningToState + string SystemCreationClassName + string SystemName + string CreationClassName + string DeviceID + boolean PowerManagementSupported + uint16 PowerManagementCapabilities[] + uint16 Availability + uint16 StatusInfo + uint32 LastErrorCode + string ErrorDescription + boolean ErrorCleared + string OtherIdentifyingInfo[] + uint64 PowerOnHours + uint64 TotalPowerOnHours + string IdentifyingDescriptions[] + uint16 AdditionalAvailability[] + uint64 MaxQuiesceTime + uint16 Capabilities[] + string CapabilityDescriptions[] + string ErrorMethodology + string CompressionMethod + uint32 NumberOfMediaSupported + uint64 MaxMediaSize + uint64 DefaultBlockSize + uint64 MaxBlockSize + uint64 MinBlockSize + boolean NeedsCleaning + boolean MediaIsLocked + uint16 Security + datetime LastCleaned + uint64 MaxAccessTime + uint32 UncompressedDataRate + uint64 LoadTime + uint64 UnloadTime + uint64 MountCount + datetime TimeOfLastMount + uint64 TotalMountTime + string UnitsDescription + uint64 MaxUnitsBeforeCleaning + uint64 UnitsUsed + uint32 DriveNumber +end + + +class Msvm_StorageAllocationSettingData + string InstanceID + string Caption + string Description + string ElementName + uint16 ResourceType + string OtherResourceType + string ResourceSubType + string PoolID + uint16 ConsumerVisibility + string HostResource[] + string AllocationUnits + uint64 VirtualQuantity + uint64 Limit + uint32 Weight + boolean AutomaticAllocation + boolean AutomaticDeallocation + string Parent + string Connection[] + string Address + uint16 MappingBehavior + string AddressOnParent + uint64 VirtualResourceBlockSize + string VirtualQuantityUnits + uint16 Access + uint64 HostResourceBlockSize + uint64 Reservation + uint64 HostExtentStartingAddress + string HostExtentName + uint16 HostExtentNameFormat + string OtherHostExtentNameFormat + uint16 HostExtentNameNamespace + string OtherHostExtentNameNamespace + uint64 IOPSLimit + uint64 IOPSReservation + string IOPSAllocationUnits + boolean PersistentReservationsSupported +end -- 2.27.0