Add the @target_bus argument which will allow a caller to pass the virDomainDiskBus onto which the @info (<address>) would be placed. This will allow logic to provide the bus for cold plugged devices to determine whether the about to be added device <address> is already present on the @bus. Just passing the @info isn't sufficient since, for example, ADDRESS_TYPE_DRIVE is used for both SCSI and IDE <disk>'s as well as 'scsi' and 'scsi_host' <hostdev>'s. Signed-off-by: John Ferlan <jferlan@xxxxxxxxxx> --- src/conf/domain_conf.c | 32 ++++++++++++++++++++++++++++---- src/conf/domain_conf.h | 3 ++- src/qemu/qemu_driver.c | 2 +- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 7396616eda..82df8012af 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -3688,13 +3688,31 @@ virDomainDeviceGetInfo(virDomainDeviceDefPtr device) } +struct virDomainDefHasDeviceAddressIteratorData { + int target_bus; /* virDomainDiskBus or -1 */ + virDomainDeviceInfoPtr info; +}; + static int virDomainDefHasDeviceAddressIterator(virDomainDefPtr def ATTRIBUTE_UNUSED, - virDomainDeviceDefPtr dev ATTRIBUTE_UNUSED, + virDomainDeviceDefPtr dev, virDomainDeviceInfoPtr info, void *opaque) { - virDomainDeviceInfoPtr needle = opaque; + struct virDomainDefHasDeviceAddressIteratorData *data = opaque; + int target_bus = data->target_bus; + virDomainDeviceInfoPtr needle = data->info; + + /* If the target_bus of the about to be cold plugged device needs + * to be checked and the currently to be matched device is a disk, + * then compare it's target bus against the new device. If they don't + * match, then no need to compare. For disks this ensures addresses + * using drive won't erroneously match if one is IDE and another is SCSI. + * Likewise, for SCSI hostdev's this ensures the new hostdev doesn't + * erroneously match an IDE for the address comparison. */ + if (target_bus != -1 && dev->type == VIR_DOMAIN_DEVICE_DISK && + dev->data.disk->bus != target_bus) + return 0; /* break iteration if the info was found */ if (virDomainDeviceInfoAddressIsEqual(info, needle)) @@ -3933,12 +3951,18 @@ virDomainDeviceInfoIterate(virDomainDefPtr def, bool virDomainDefHasDeviceAddress(virDomainDefPtr def, + int target_bus, virDomainDeviceInfoPtr info) { + struct virDomainDefHasDeviceAddressIteratorData data = { + .target_bus = target_bus, + .info = info, + }; + if (virDomainDeviceInfoIterateInternal(def, virDomainDefHasDeviceAddressIterator, true, - info) < 0) + &data) < 0) return true; return false; @@ -17508,7 +17532,7 @@ virDomainMemoryInsert(virDomainDefPtr def, int id = def->nmems; if (mem->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE && - virDomainDefHasDeviceAddress(def, &mem->info)) { + virDomainDefHasDeviceAddress(def, -1, &mem->info)) { virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("Domain already contains a device with the same " "address")); diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 0f10e242fd..82231161c6 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -2912,8 +2912,9 @@ int virDomainDeviceInfoIterate(virDomainDefPtr def, void *opaque); bool virDomainDefHasDeviceAddress(virDomainDefPtr def, + int target_bus, virDomainDeviceInfoPtr info) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK; + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3) ATTRIBUTE_RETURN_CHECK; void virDomainDefFree(virDomainDefPtr vm); diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 8fae46370e..5f91d463ae 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -8082,7 +8082,7 @@ qemuDomainAttachDeviceConfig(virDomainDefPtr vmdef, case VIR_DOMAIN_DEVICE_RNG: if (dev->data.rng->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE && - virDomainDefHasDeviceAddress(vmdef, &dev->data.rng->info)) { + virDomainDefHasDeviceAddress(vmdef, -1, &dev->data.rng->info)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("a device with the same address already exists ")); return -1; -- 2.17.1 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list