An upcoming patch will be checking if the addition of a new net device
requires adjusting the domain locked memory limit, which must be done
prior to sending the command to qemu to add the new device. But
qemuDomainAdjustMaxMemLock() checks all (and only) the devices that
are currently in the domain definition, and currently we are adding
new net devices to the domain definition only at the very end of the
hotplug operation, after qemu has already executed the device_add
command.
In order for the upcoming patch to work, this patch changes
qemuDomainAttachNetDevice() to add the device to the domain nets list
at an earlier time. It can't be added until after PCI address and
alias name have been determined (because both of those examine
existing devices in the domain to figure out a unique value for the
new device), but must be done before making the qemu monitor call.
Since the device has been added to the list earlier, we need to
potentially remove it on failure. This is done by replacing the
existing call to virDomainNetRemoveHostdev() (which checks if this is
a hostdev net device, and if so removes it from the hostdevs list,
since it could have already been added to that list) with a call to
the new virDomainNetRemoveByObj(), which looks for the device on both
nets and hostdevs lists, and removes it where it finds it.
Signed-off-by: Laine Stump <laine(a)redhat.com>
---
src/qemu/qemu_hotplug.c | 25 ++++++++++++++++++-------
1 file changed, 18 insertions(+), 7 deletions(-)
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 244cf65c87..dff31666f7 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -1196,9 +1196,6 @@ qemuDomainAttachNetDevice(virQEMUDriver *driver,
g_autoptr(virConnect) conn = NULL;
virErrorPtr save_err = NULL;
- /* preallocate new slot for device */
- VIR_REALLOC_N(vm->def->nets, vm->def->nnets + 1);
-
/* If appropriate, grab a physical device from the configured
* network's pool of devices, or resolve bridge device name
* to the one defined in the network definition.
@@ -1249,6 +1246,18 @@ qemuDomainAttachNetDevice(virQEMUDriver *driver,
releaseaddr = true;
+ /* We've completed all examinations of the full domain definition
+ * that require the new device to *not* be present (e.g. PCI
+ * address allocation and alias name assignment) so it is now safe
+ * to add the new device to the domain's nets list (in order for
+ * it to be in place for checks that *do* need it present in the
+ * domain definition, e.g. checking if we need to adjust the
+ * locked memory limit). This means we will need to remove it if
+ * there is a failure.
+ */
+ if (VIR_APPEND_ELEMENT_COPY(vm->def->nets, vm->def->nnets, net) < 0)
+ goto cleanup;
+
switch (actualType) {
case VIR_DOMAIN_NET_TYPE_BRIDGE:
case VIR_DOMAIN_NET_TYPE_NETWORK:
@@ -1505,9 +1514,7 @@ qemuDomainAttachNetDevice(virQEMUDriver *driver,
ret = 0;
cleanup:
- if (!ret) {
- vm->def->nets[vm->def->nnets++] = net;
- } else {
+ if (ret < 0) {
virErrorPreserveLast(&save_err);
if (releaseaddr)
qemuDomainReleaseDeviceAddress(vm, &net->info);
@@ -1529,7 +1536,11 @@ qemuDomainAttachNetDevice(virQEMUDriver *driver,
qemuDomainNetDeviceVportRemove(net);
}
- virDomainNetRemoveHostdev(vm->def, net);
+ /* we had potentially pre-added the device to the domain
+ * device lists, if so we need to remove it (from def->nets
+ * and/or def->hostdevs) on failure
+ */
+ virDomainNetRemoveByObj(vm->def, net);
if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
if (conn)
--
2.31.1