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@xxxxxxxxxx> --- 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