[PATCH 06/11] hyperv: attach virtual disks when defining domains

Daniel P. Berrangé berrange at redhat.com
Thu Nov 26 14:48:10 UTC 2020


On Tue, Nov 24, 2020 at 02:48:35PM -0500, Matt Coleman wrote:
> Co-authored-by: Sri Ramanujam <sramanujam at datto.com>
> Signed-off-by: Matt Coleman <matt at datto.com>
> ---
>  src/hyperv/hyperv_driver.c      | 244 +++++++++++++++++++++++++++++++-
>  src/hyperv/hyperv_wmi_classes.h |   1 +
>  2 files changed, 242 insertions(+), 3 deletions(-)
> 
> diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c
> index 1ad52e598a..a3da2ec524 100644
> --- a/src/hyperv/hyperv_driver.c
> +++ b/src/hyperv/hyperv_driver.c
> @@ -327,6 +327,30 @@ hypervGetDeviceParentRasdFromDeviceId(const char *parentDeviceId,
>  }
>  
>  
> +static char *
> +hypervGetInstanceIDFromXMLResponse(WsXmlDocH response)
> +{
> +    WsXmlNodeH envelope = NULL;
> +    char *instanceId = NULL;
> +
> +    envelope = ws_xml_get_soap_envelope(response);
> +    if (!envelope) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid XML response"));
> +        return NULL;
> +    }
> +
> +    instanceId = ws_xml_get_xpath_value(response, (char *)"//w:Selector[@Name='InstanceID']");
> +
> +    if (!instanceId) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                       _("Could not find selectors in method response"));
> +        return NULL;
> +    }
> +
> +    return instanceId;
> +}
> +
> +
>  static int
>  hypervDomainCreateSCSIController(virDomainPtr domain)
>  {
> @@ -359,10 +383,175 @@ hypervDomainCreateSCSIController(virDomainPtr domain)
>  
>  
>  static int
> -hypervDomainAttachStorage(virDomainPtr domain, virDomainDefPtr def)
> +hypervDomainAddVirtualDiskParent(virDomainPtr domain,
> +                                 virDomainDiskDefPtr disk,
> +                                 Msvm_ResourceAllocationSettingData *controller,
> +                                 const char *hostname,
> +                                 WsXmlDocH *response)
>  {
> +    g_autoptr(GHashTable) controllerResource = NULL;
> +    g_autofree char *parentInstanceIDEscaped = NULL;
> +    g_autofree char *parent__PATH = NULL;
> +    g_autofree char *addressString = g_strdup_printf("%u", disk->info.addr.drive.unit);

Validate disk->info.type == DRIVE before accessing this field otherwise
the union contents is undefined.

> +    g_autofree char *resourceType = NULL;
> +
> +    resourceType = g_strdup_printf("%d", MSVM_RASD_RESOURCETYPE_DISK_DRIVE);
> +
> +    controllerResource = hypervCreateEmbeddedParam(Msvm_ResourceAllocationSettingData_WmiInfo);
> +    if (!controllerResource)
> +        return -1;
> +
> +    parentInstanceIDEscaped = virStringReplace(controller->data->InstanceID, "\\", "\\\\");
> +    parent__PATH = g_strdup_printf("\\\\%s\\Root\\Virtualization\\V2:"
> +                                   "Msvm_ResourceAllocationSettingData.InstanceID=\"%s\"",
> +                                   hostname, parentInstanceIDEscaped);
> +    if (!parent__PATH)
> +        return -1;
> +
> +    if (hypervSetEmbeddedProperty(controllerResource, "Parent", parent__PATH) < 0)
> +        return -1;
> +
> +    if (hypervSetEmbeddedProperty(controllerResource, "AddressOnParent", addressString) < 0)
> +        return -1;
> +
> +    if (hypervSetEmbeddedProperty(controllerResource, "ResourceType", resourceType) < 0)
> +        return -1;
> +
> +    if (hypervSetEmbeddedProperty(controllerResource, "ResourceSubType",
> +                                  "Microsoft:Hyper-V:Synthetic Disk Drive") < 0)
> +        return -1;
> +
> +    if (hypervMsvmVSMSAddResourceSettings(domain, &controllerResource,
> +                                          Msvm_ResourceAllocationSettingData_WmiInfo,
> +                                          response) < 0)
> +        return -1;
> +
> +    return 0;
> +}
> +
> +
> +static int
> +hypervDomainAddVirtualHardDisk(virDomainPtr domain,
> +                               virDomainDiskDefPtr disk,
> +                               const char *hostname,
> +                               char *parentInstanceID)
> +{
> +    g_autoptr(GHashTable) volumeResource = NULL;
> +    g_autofree char *vhdInstanceIdEscaped = NULL;
> +    g_autofree char *vhd__PATH = NULL;
> +    g_autofree char *resourceType = NULL;
> +
> +    resourceType = g_strdup_printf("%d", MSVM_RASD_RESOURCETYPE_LOGICAL_DISK);
> +
> +    volumeResource = hypervCreateEmbeddedParam(Msvm_ResourceAllocationSettingData_WmiInfo);
> +    if (!volumeResource)
> +        return -1;
> +
> +    vhdInstanceIdEscaped = virStringReplace(parentInstanceID, "\\", "\\\\");
> +    vhd__PATH = g_strdup_printf("\\\\%s\\Root\\Virtualization\\V2:"
> +                                "Msvm_ResourceAllocationSettingData.InstanceID=\"%s\"",
> +                                hostname, vhdInstanceIdEscaped);
> +
> +    if (!vhd__PATH)
> +        return -1;
> +
> +    if (hypervSetEmbeddedProperty(volumeResource, "Parent", vhd__PATH) < 0)
> +        return -1;
> +
> +    if (hypervSetEmbeddedProperty(volumeResource, "HostResource", disk->src->path) < 0)
> +        return -1;
> +
> +    if (hypervSetEmbeddedProperty(volumeResource, "ResourceType", resourceType) < 0)
> +        return -1;
> +
> +    if (hypervSetEmbeddedProperty(volumeResource, "ResourceSubType",
> +                                  "Microsoft:Hyper-V:Virtual Hard Disk") < 0)
> +        return -1;

The disk->device can be disk, or cdrom or floppy. So if you're hadcoding disk, then
validate disk->device matches.

> +
> +    if (hypervMsvmVSMSAddResourceSettings(domain, &volumeResource,
> +                                          Msvm_ResourceAllocationSettingData_WmiInfo,
> +                                          NULL) < 0)
> +        return -1;
> +
> +    return 0;
> +}
> +
> +
> +static int
> +hypervDomainAttachVirtualDisk(virDomainPtr domain,
> +                              virDomainDiskDefPtr disk,
> +                              Msvm_ResourceAllocationSettingData *controller,
> +                              const char *hostname)
> +{
> +    int result = -1;
> +    g_autofree char *parentInstanceID = NULL;
> +    WsXmlDocH response = NULL;
> +
> +    VIR_DEBUG("Now attaching disk image '%s' with address %d to bus %d of type %d",
> +              disk->src->path, disk->info.addr.drive.unit, disk->info.addr.drive.controller, disk->bus);

Don't access the disk->info.addr until its type is validated


> +
> +    if (hypervDomainAddVirtualDiskParent(domain, disk, controller, hostname, &response) < 0)
> +        return -1;
> +
> +    if (!response) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not add virtual disk parent"));
> +        return -1;
> +    }
> +
> +    parentInstanceID = hypervGetInstanceIDFromXMLResponse(response);
> +    if (!parentInstanceID)
> +        goto cleanup;
> +
> +    if (hypervDomainAddVirtualHardDisk(domain, disk, hostname, parentInstanceID) < 0)
> +        goto cleanup;
> +
> +    result = 0;
> +
> + cleanup:
> +    ws_xml_destroy_doc(response);
> +
> +    return result;
> +}
> +
> +
> +static int
> +hypervDomainAttachStorageVolume(virDomainPtr domain,
> +                                virDomainDiskDefPtr disk,
> +                                Msvm_ResourceAllocationSettingData *controller,
> +                                const char *hostname)
> +{
> +    switch (disk->device) {
> +    case VIR_DOMAIN_DISK_DEVICE_DISK:
> +        if (disk->src->type == VIR_STORAGE_TYPE_FILE)
> +            return hypervDomainAttachVirtualDisk(domain, disk, controller, hostname);
> +        else
> +            virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unsupported disk type"));
> +        break;
> +    default:
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unsupported disk bus"));
> +        break;
> +    }
> +
> +    return -1;
> +}
> +
> +
> +static int
> +hypervDomainAttachStorage(virDomainPtr domain, virDomainDefPtr def, const char *hostname)
> +{
> +    int result = -1;
> +    hypervPrivate *priv = domain->conn->privateData;
>      size_t i = 0;
> +    char uuid_string[VIR_UUID_STRING_BUFLEN];
> +    int num_scsi_controllers = 0;
> +    int ctrlr_idx = -1;
> +    Msvm_VirtualSystemSettingData *vssd = NULL;
> +    Msvm_ResourceAllocationSettingData *rasd = NULL;
> +    Msvm_ResourceAllocationSettingData *entry = NULL;
> +    Msvm_ResourceAllocationSettingData *ideChannels[HYPERV_MAX_IDE_CHANNELS];
> +    Msvm_ResourceAllocationSettingData *scsiControllers[HYPERV_MAX_SCSI_CONTROLLERS];
>  
> +    /* start with attaching scsi controllers */
>      for (i = 0; i < def->ncontrollers; i++) {
>          if (def->controllers[i]->type != VIR_DOMAIN_CONTROLLER_TYPE_SCSI)
>              continue;
> @@ -371,7 +560,55 @@ hypervDomainAttachStorage(virDomainPtr domain, virDomainDefPtr def)
>              return -1;
>      }
>  
> -    return 0;
> +    virUUIDFormat(domain->uuid, uuid_string);
> +
> +    /* filter through all the rasd entries and isolate our controllers */
> +    if (hypervGetMsvmVirtualSystemSettingDataFromUUID(priv, uuid_string, &vssd) < 0)
> +        goto cleanup;
> +
> +    if (hypervGetResourceAllocationSD(priv, vssd->data->InstanceID, &rasd) < 0)
> +        goto cleanup;
> +
> +    entry = rasd;
> +    while (entry) {
> +        if (entry->data->ResourceType == MSVM_RASD_RESOURCETYPE_IDE_CONTROLLER)
> +            ideChannels[entry->data->Address[0] - '0'] = entry;
> +        else if (entry->data->ResourceType == MSVM_RASD_RESOURCETYPE_PARALLEL_SCSI_HBA)
> +            scsiControllers[num_scsi_controllers++] = entry;
> +
> +        entry = entry->next;
> +    }
> +
> +    /* now we loop through and attach all the disks */
> +    for (i = 0; i < def->ndisks; i++) {
> +        switch (def->disks[i]->bus) {
> +        case VIR_DOMAIN_DISK_BUS_IDE:
> +            ctrlr_idx = def->disks[i]->info.addr.drive.bus;
> +            if (hypervDomainAttachStorageVolume(domain, def->disks[i],
> +                                                ideChannels[ctrlr_idx], hostname) < 0) {
> +                goto cleanup;
> +            }
> +            break;
> +        case VIR_DOMAIN_DISK_BUS_SCSI:
> +            ctrlr_idx = def->disks[i]->info.addr.drive.controller;
> +            if (hypervDomainAttachStorageVolume(domain, def->disks[i],
> +                                                scsiControllers[ctrlr_idx], hostname) < 0) {
> +                goto cleanup;
> +            }
> +            break;
> +        default:
> +            virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unsupported controller type"));
> +            goto cleanup;
> +        }
> +    }
> +
> +    result = 0;
> +
> + cleanup:
> +    hypervFreeObject(priv, (hypervObject *)rasd);
> +    hypervFreeObject(priv, (hypervObject *)vssd);
> +
> +    return result;
>  }
>  
>  
> @@ -1991,6 +2228,7 @@ static virDomainPtr
>  hypervDomainDefineXML(virConnectPtr conn, const char *xml)
>  {
>      hypervPrivate *priv = conn->privateData;
> +    g_autofree char *hostname = hypervConnectGetHostname(conn);
>      g_autoptr(virDomainDef) def = NULL;
>      virDomainPtr domain = NULL;
>      g_autoptr(hypervInvokeParamsList) params = NULL;
> @@ -2051,7 +2289,7 @@ hypervDomainDefineXML(virConnectPtr conn, const char *xml)
>          goto error;
>  
>      /* attach all storage */
> -    if (hypervDomainAttachStorage(domain, def) < 0)
> +    if (hypervDomainAttachStorage(domain, def, hostname) < 0)
>          goto error;
>  
>      return domain;
> diff --git a/src/hyperv/hyperv_wmi_classes.h b/src/hyperv/hyperv_wmi_classes.h
> index 36c0e60c2a..2c03ca3745 100644
> --- a/src/hyperv/hyperv_wmi_classes.h
> +++ b/src/hyperv/hyperv_wmi_classes.h
> @@ -113,6 +113,7 @@ enum _Msvm_ResourceAllocationSettingData_ResourceType {
>      MSVM_RASD_RESOURCETYPE_DVD_DRIVE = 16,
>      MSVM_RASD_RESOURCETYPE_DISK_DRIVE = 17,
>      MSVM_RASD_RESOURCETYPE_STORAGE_EXTENT = 19,
> +    MSVM_RASD_RESOURCETYPE_LOGICAL_DISK = 31,
>  };
>  
>  
> -- 
> 2.27.0
> 
> 

Regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|




More information about the libvir-list mailing list