[libvirt] [PATCH v2 06/11] qemu: handle race on device deletion and usb host device plugging

Nikolay Shirokovskiy nshirokovskiy at virtuozzo.com
Fri Sep 13 08:04:38 UTC 2019



On 12.09.2019 23:37, Daniel Henrique Barboza wrote:
> 
> 
> On 9/9/19 8:33 AM, Nikolay Shirokovskiy wrote:
>> Imagine host usb device is unplugged from host and as a result we send
>> command to qemu to delete appropriate device. Then before qemu device is
>> deleted host usb device is plugged back. Currenly code supposes there is
> 
> s/Currenly/Currently
> 
> 
>> no remnant device in qemu and will try to add new device and the attempt
>> will fail.
>>
>> Instead let's check the device is not yet deleted and postpone adding
>> qemu device to device_deleted event handler.
>>
>> Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy at virtuozzo.com>
>> ---
> 
> Honestly, I tried to give a NACK to this patch, not because of coding
> issues, but because I find it quite convoluted what you're doing here.
> 
> qemuCheckHostdevPlugged() is calling qemuDomainAttachHostDevice()
> if the USB device is found. Problem is that you're calling this check function
> it right after qemuDomainRemoveDevice(), inside a function that is supposed
> to handle delete events. The result is a flow like this:
> 
> - inside processDeviceDeletedEvent:
> 
>     virDomainDefFindDevice(vm->def, devAlias, &dev, true)
> 
>     qemuDomainRemoveDevice(driver, vm, &dev)
> 
>     qemuCheckHostdevPlugged(driver, vm, devAlias);
> 
> - inside qemuCheckHostdevPlugged:
> 
>   virDomainDefFindDevice(vm->def, devAlias, &dev, false) <---- same find you just did
> 
> ( .... other code that verifies if the USB device exists in the host ...)
> 
>   qemuDomainAttachHostDevice(driver, vm, hostdev)
> 
> 
> So in short, you are executing a find(), then a remove(), then the same
> find() again, some code to assert that the USB is plugged in the host,
> then attach().

Yeah this is because remove() in case of unplugging does not actually remove
device from libvirt config, so both find()s find same device.

Nikolay

> 
> Problem is that I didn't come up with a cleaner solution for the problem you're
> solving here, at least considering the changes from the previous patches
> and the current code base. That said:
> 
> 
> Reviewed-by: Daniel Henrique Barboza <danielhb413 at gmail.com>
> 
> 
> 
> 
> 
> 
> 
> 
>>   src/qemu/qemu_driver.c | 49 ++++++++++++++++++++++++++++++++++++++++++
>>   1 file changed, 49 insertions(+)
>>
>> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
>> index f1802b5d44..21640e49c7 100644
>> --- a/src/qemu/qemu_driver.c
>> +++ b/src/qemu/qemu_driver.c
>> @@ -4671,6 +4671,44 @@ processGuestPanicEvent(virQEMUDriverPtr driver,
>>   }
>>     +static int
>> +qemuCheckHostdevPlugged(virQEMUDriverPtr driver,
>> +                        virDomainObjPtr vm,
>> +                        const char *devAlias)
>> +{
>> +    virDomainHostdevDefPtr hostdev;
>> +    virDomainHostdevSubsysUSBPtr usbsrc;
>> +    virDomainDeviceDef dev;
>> +    int num;
>> +
>> +    if (virDomainDefFindDevice(vm->def, devAlias, &dev, false) < 0)
>> +        return 0;
>> +
>> +    if (dev.type != VIR_DOMAIN_DEVICE_HOSTDEV)
>> +        return 0;
>> +
>> +    hostdev = dev.data.hostdev;
>> +    if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
>> +        return 0;
>> +
>> +    usbsrc = &hostdev->source.subsys.u.usb;
>> +    if (!usbsrc->vendor || !usbsrc->product)
>> +        return 0;
>> +
>> +    if ((num = virUSBDeviceFindByVendor(usbsrc->vendor, usbsrc->product,
>> +                                        NULL, false, NULL)) < 0)
>> +        return -1;
>> +
>> +    if (num == 0)
>> +        return 0;
>> +
>> +    if (qemuDomainAttachHostDevice(driver, vm, hostdev) < 0)
>> +        return -1;
>> +
>> +    return 0;
>> +}
>> +
>> +
>>   static void
>>   processDeviceDeletedEvent(virQEMUDriverPtr driver,
>>                             virDomainObjPtr vm,
>> @@ -4698,6 +4736,11 @@ processDeviceDeletedEvent(virQEMUDriverPtr driver,
>>             if (qemuDomainRemoveDevice(driver, vm, &dev) < 0)
>>               goto endjob;
>> +
>> +        /* Fall thru and save status file even on error condition because
>> +         * device is removed successfully and changed configuration need
>> +         * to be saved in status file. */
>> +        qemuCheckHostdevPlugged(driver, vm, devAlias);
>>       }
>>         if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0)
>> @@ -5300,6 +5343,12 @@ processUSBAddedEvent(virQEMUDriverPtr driver,
>>       if (i == vm->def->nhostdevs)
>>           goto cleanup;
>>   +    /* if device is not yet even deleted from qemu then handle plugging later.
>> +     * Or we failed handling host usb device unplugging, then another attempt of
>> +     * unplug/plug could help. */
>> +    if (usbsrc->bus || usbsrc->device)
>> +        goto cleanup;
>> +
>>       if (qemuDomainAttachHostDevice(driver, vm, hostdev) < 0)
>>           goto cleanup;
>>   
> 




More information about the libvir-list mailing list