qemu: fix i6300esb watchdog hotplug on Q35

When commit 361c8dc17 added support for hotplugging the i6300esb
watchdog device (first in libvirt-3.9.0), it accidentally contstructed
the commandline for the device_add command before allocating a PCI
address for the device. With no PCI address specified in the command,
the watchdog would simply be placed at the lowest unused PCI slot.

On a 440fx guest, this doesn't cause a problem, because libvirt's PCI
address allocation algorithm would most likely give the same address
anyway (usually a slot on pci-root), so nobody noticed the omission of
address from the command.

But on a Q35 guest, the lowest unused PCI slot is on pcie-root, which
doesn't support hotplug; libvirt knows enough to assign a PCI address
that is on a pcie-to-pci-bridge (because its slots *do* support
hotplug), but qemu doesn't, so if there is no PCI address in the
command, qemu just tries to plug the new device into pcie-root, and
fails because it doesn't support hotplug, e.g.:

  error: Failed to attach device from watchdog.xml
  error: internal error: unable to execute QEMU command 'device_add':
  Bus 'pcie.0' does not support hotplugging

The solution is simply to build the command string after assigning a
PCI address, not before.

Resolves: https://bugzilla.redhat.com/1666559
Signed-off-by: Laine Stump <laine@laine.org>
Reviewed-by: John Ferlan <jferlan@redhat.com>
This commit is contained in:
Laine Stump 2019-01-17 15:05:54 -05:00
parent 01ca4010d8
commit 40136bd316

View File

@ -3280,9 +3280,6 @@ qemuDomainAttachWatchdog(virQEMUDriverPtr driver,
if (qemuAssignDeviceWatchdogAlias(watchdog) < 0) if (qemuAssignDeviceWatchdogAlias(watchdog) < 0)
return -1; return -1;
if (!(watchdogstr = qemuBuildWatchdogDevStr(vm->def, watchdog, priv->qemuCaps)))
return -1;
if (watchdog->model == VIR_DOMAIN_WATCHDOG_MODEL_I6300ESB) { if (watchdog->model == VIR_DOMAIN_WATCHDOG_MODEL_I6300ESB) {
if (qemuDomainEnsurePCIAddress(vm, &dev, driver) < 0) if (qemuDomainEnsurePCIAddress(vm, &dev, driver) < 0)
goto cleanup; goto cleanup;
@ -3294,6 +3291,9 @@ qemuDomainAttachWatchdog(virQEMUDriverPtr driver,
goto cleanup; goto cleanup;
} }
if (!(watchdogstr = qemuBuildWatchdogDevStr(vm->def, watchdog, priv->qemuCaps)))
goto cleanup;
/* QEMU doesn't have a 'dump' action; we tell qemu to 'pause', then /* QEMU doesn't have a 'dump' action; we tell qemu to 'pause', then
libvirt listens for the watchdog event, and we perform the dump libvirt listens for the watchdog event, and we perform the dump
ourselves. so convert 'dump' to 'pause' for the qemu cli */ ourselves. so convert 'dump' to 'pause' for the qemu cli */