diff --git a/src/test/test_driver.c b/src/test/test_driver.c index 03afe8af8d..dcf1097106 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -10223,6 +10223,172 @@ testDomainAttachHostDevice(testDriver *driver, } +/** + * @def: Domain definition + * @info: Domain device info + * + * Using the device info, find the controller related to the + * device by index and use that controller to return the model. + * + * Returns the model if found, -1 if not with an error message set + */ +static int +testDomainFindSCSIControllerModel(const virDomainDef *def, + virDomainDeviceInfo *info) +{ + virDomainControllerDef *cont; + + if (!(cont = virDomainDeviceFindSCSIController(def, &info->addr.drive))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unable to find a SCSI controller for idx=%1$d"), + info->addr.drive.controller); + return -1; + } + + return cont->model; +} + + +static int +testAssignDeviceDiskAlias(virDomainDef *def, + virDomainDiskDef *disk) +{ + const char *prefix = virDomainDiskBusTypeToString(disk->bus); + int controllerModel = -1; + + if (!disk->info.alias) { + if (disk->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) { + if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI) { + controllerModel = testDomainFindSCSIControllerModel(def, + &disk->info); + if (controllerModel < 0) + return -1; + } + + if (disk->bus != VIR_DOMAIN_DISK_BUS_SCSI || + controllerModel == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSILOGIC) { + disk->info.alias = g_strdup_printf("%s%d-%d-%d", prefix, + disk->info.addr.drive.controller, + disk->info.addr.drive.bus, + disk->info.addr.drive.unit); + } else { + disk->info.alias = g_strdup_printf("%s%d-%d-%d-%d", prefix, + disk->info.addr.drive.controller, + disk->info.addr.drive.bus, + disk->info.addr.drive.target, + disk->info.addr.drive.unit); + } + } else { + int idx = virDiskNameToIndex(disk->dst); + disk->info.alias = g_strdup_printf("%s-disk%d", prefix, idx); + } + } + + return 0; +} + + +static int +testDomainAttachDeviceDiskLiveInternal(testDriver *driver G_GNUC_UNUSED, + virDomainObj *vm, + virDomainDeviceDef *dev) +{ + size_t i; + virDomainDiskDef *disk = dev->data.disk; + int ret = -1; + + if (disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("floppy device hotplug isn't supported")); + return -1; + } + + if (virDomainDiskTranslateSourcePool(disk) < 0) + goto cleanup; + + for (i = 0; i < vm->def->ndisks; i++) { + if (virDomainDiskDefCheckDuplicateInfo(vm->def->disks[i], disk) < 0) + goto cleanup; + } + + switch (disk->bus) { + case VIR_DOMAIN_DISK_BUS_USB: + if (disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("disk device='lun' is not supported for usb bus")); + goto cleanup; + } + + break; + + case VIR_DOMAIN_DISK_BUS_VIRTIO: + if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("cdrom device with virtio bus isn't supported")); + goto cleanup; + } + break; + + case VIR_DOMAIN_DISK_BUS_SCSI: + case VIR_DOMAIN_DISK_BUS_IDE: + case VIR_DOMAIN_DISK_BUS_FDC: + case VIR_DOMAIN_DISK_BUS_XEN: + case VIR_DOMAIN_DISK_BUS_UML: + case VIR_DOMAIN_DISK_BUS_SATA: + case VIR_DOMAIN_DISK_BUS_SD: + case VIR_DOMAIN_DISK_BUS_NONE: + case VIR_DOMAIN_DISK_BUS_LAST: + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, + _("disk bus '%1$s' cannot be hotplugged."), + virDomainDiskBusTypeToString(disk->bus)); + goto cleanup; + } + + if (testAssignDeviceDiskAlias(vm->def, disk) < 0) + goto cleanup; + + virDomainDiskInsert(vm->def, disk); + + ret = 0; + + cleanup: + return ret; +} + + +/** + * testDomainAttachDeviceDiskLive: + * @driver: test driver struct + * @vm: domain object + * @dev: device to attach (expected type is DISK) + * + * Attach a new disk or in case of cdroms/floppies change the media in the drive. + * This function handles all the necessary steps to attach a new storage source + * to the VM. + */ +static int +testDomainAttachDeviceDiskLive(testDriver *driver, + virDomainObj *vm, + virDomainDeviceDef *dev) +{ + virDomainDiskDef *disk = dev->data.disk; + virDomainDiskDef *orig_disk = NULL; + + /* this API overloads media change semantics on disk hotplug + * for devices supporting media changes */ + if ((disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM || + disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) && + (orig_disk = virDomainDiskByTarget(vm->def, disk->dst))) { + virObjectUnref(orig_disk->src); + orig_disk->src = g_steal_pointer(&disk->src); + virDomainDiskDefFree(disk); + return 0; + } + + return testDomainAttachDeviceDiskLiveInternal(driver, vm, dev); +} + + static int testDomainAttachDeviceLive(virDomainObj *vm, virDomainDeviceDef *dev, @@ -10251,8 +10417,16 @@ testDomainAttachDeviceLive(virDomainObj *vm, } break; - case VIR_DOMAIN_DEVICE_NONE: case VIR_DOMAIN_DEVICE_DISK: + testDomainObjCheckDiskTaint(vm, dev->data.disk); + ret = testDomainAttachDeviceDiskLive(driver, vm, dev); + if (!ret) { + alias = dev->data.disk->info.alias; + dev->data.disk = NULL; + } + break; + + case VIR_DOMAIN_DEVICE_NONE: case VIR_DOMAIN_DEVICE_LEASE: case VIR_DOMAIN_DEVICE_FS: case VIR_DOMAIN_DEVICE_INPUT: