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(a)redhat.com>
---
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