qemu: hotplug: Add support for signalling device unplug failure
Similarly to the DEVICE_DELETED event we will be able to tell when unplug of certain device types will be rejected by the guest OS. Wire up the device deletion signalling code to allow handling this.
This commit is contained in:
parent
0f621198a4
commit
1ac3864025
@ -149,6 +149,22 @@ typedef void (*qemuDomainCleanupCallback)(virQEMUDriverPtr driver,
|
|||||||
virDomainObjPtr vm);
|
virDomainObjPtr vm);
|
||||||
|
|
||||||
# define QEMU_DOMAIN_MASTER_KEY_LEN 32 /* 32 bytes for 256 bit random key */
|
# define QEMU_DOMAIN_MASTER_KEY_LEN 32 /* 32 bytes for 256 bit random key */
|
||||||
|
|
||||||
|
|
||||||
|
/* helper data types for async device unplug */
|
||||||
|
typedef enum {
|
||||||
|
QEMU_DOMAIN_UNPLUGGING_DEVICE_STATUS_NONE = 0,
|
||||||
|
QEMU_DOMAIN_UNPLUGGING_DEVICE_STATUS_OK,
|
||||||
|
QEMU_DOMAIN_UNPLUGGING_DEVICE_STATUS_GUEST_REJECTED,
|
||||||
|
} qemuDomainUnpluggingDeviceStatus;
|
||||||
|
|
||||||
|
typedef struct _qemuDomainUnpluggingDevice qemuDomainUnpluggingDevice;
|
||||||
|
typedef qemuDomainUnpluggingDevice *qemuDomainUnpluggingDevicePtr;
|
||||||
|
struct _qemuDomainUnpluggingDevice {
|
||||||
|
const char *alias;
|
||||||
|
qemuDomainUnpluggingDeviceStatus status;
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct _qemuDomainObjPrivate qemuDomainObjPrivate;
|
typedef struct _qemuDomainObjPrivate qemuDomainObjPrivate;
|
||||||
typedef qemuDomainObjPrivate *qemuDomainObjPrivatePtr;
|
typedef qemuDomainObjPrivate *qemuDomainObjPrivatePtr;
|
||||||
struct _qemuDomainObjPrivate {
|
struct _qemuDomainObjPrivate {
|
||||||
@ -199,7 +215,8 @@ struct _qemuDomainObjPrivate {
|
|||||||
|
|
||||||
virPerfPtr perf;
|
virPerfPtr perf;
|
||||||
|
|
||||||
const char *unpluggingDevice; /* alias of the device that is being unplugged */
|
qemuDomainUnpluggingDevice unplug;
|
||||||
|
|
||||||
char **qemuDevices; /* NULL-terminated list of devices aliases known to QEMU */
|
char **qemuDevices; /* NULL-terminated list of devices aliases known to QEMU */
|
||||||
|
|
||||||
bool hookRun; /* true if there was a hook run over this domain */
|
bool hookRun; /* true if there was a hook run over this domain */
|
||||||
|
@ -3334,20 +3334,24 @@ qemuDomainMarkDeviceForRemoval(virDomainObjPtr vm,
|
|||||||
{
|
{
|
||||||
qemuDomainObjPrivatePtr priv = vm->privateData;
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
||||||
|
|
||||||
if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE_DEL_EVENT))
|
memset(&priv->unplug, 0, sizeof(priv->unplug));
|
||||||
priv->unpluggingDevice = info->alias;
|
|
||||||
else
|
if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE_DEL_EVENT))
|
||||||
priv->unpluggingDevice = NULL;
|
return;
|
||||||
|
|
||||||
|
priv->unplug.alias = info->alias;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
qemuDomainResetDeviceRemoval(virDomainObjPtr vm)
|
qemuDomainResetDeviceRemoval(virDomainObjPtr vm)
|
||||||
{
|
{
|
||||||
qemuDomainObjPrivatePtr priv = vm->privateData;
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
||||||
priv->unpluggingDevice = NULL;
|
priv->unplug.alias = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns:
|
/* Returns:
|
||||||
|
* -1 Unplug of the device failed
|
||||||
|
*
|
||||||
* 0 DEVICE_DELETED event is supported and removal of the device did not
|
* 0 DEVICE_DELETED event is supported and removal of the device did not
|
||||||
* finish in qemuDomainRemoveDeviceWaitTime
|
* finish in qemuDomainRemoveDeviceWaitTime
|
||||||
*
|
*
|
||||||
@ -3370,17 +3374,23 @@ qemuDomainWaitForDeviceRemoval(virDomainObjPtr vm)
|
|||||||
return 1;
|
return 1;
|
||||||
until += qemuDomainRemoveDeviceWaitTime;
|
until += qemuDomainRemoveDeviceWaitTime;
|
||||||
|
|
||||||
while (priv->unpluggingDevice) {
|
while (priv->unplug.alias) {
|
||||||
if ((rc = virDomainObjWaitUntil(vm, until)) == 1)
|
if ((rc = virDomainObjWaitUntil(vm, until)) == 1)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
VIR_WARN("Failed to wait on unplug condition for domain '%s' "
|
VIR_WARN("Failed to wait on unplug condition for domain '%s' "
|
||||||
"device '%s'", vm->def->name, priv->unpluggingDevice);
|
"device '%s'", vm->def->name, priv->unplug.alias);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (priv->unplug.status == QEMU_DOMAIN_UNPLUGGING_DEVICE_STATUS_GUEST_REJECTED) {
|
||||||
|
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
|
||||||
|
_("unplug of device was rejected by the guest"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3392,12 +3402,14 @@ qemuDomainWaitForDeviceRemoval(virDomainObjPtr vm)
|
|||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
qemuDomainSignalDeviceRemoval(virDomainObjPtr vm,
|
qemuDomainSignalDeviceRemoval(virDomainObjPtr vm,
|
||||||
const char *devAlias)
|
const char *devAlias,
|
||||||
|
qemuDomainUnpluggingDeviceStatus status)
|
||||||
{
|
{
|
||||||
qemuDomainObjPrivatePtr priv = vm->privateData;
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
||||||
|
|
||||||
if (STREQ_NULLABLE(priv->unpluggingDevice, devAlias)) {
|
if (STREQ_NULLABLE(priv->unplug.alias, devAlias)) {
|
||||||
qemuDomainResetDeviceRemoval(vm);
|
qemuDomainResetDeviceRemoval(vm);
|
||||||
|
priv->unplug.status = status;
|
||||||
virDomainObjBroadcast(vm);
|
virDomainObjBroadcast(vm);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -122,6 +122,7 @@ int qemuDomainRemoveDevice(virQEMUDriverPtr driver,
|
|||||||
virDomainDeviceDefPtr dev);
|
virDomainDeviceDefPtr dev);
|
||||||
|
|
||||||
bool qemuDomainSignalDeviceRemoval(virDomainObjPtr vm,
|
bool qemuDomainSignalDeviceRemoval(virDomainObjPtr vm,
|
||||||
const char *devAlias);
|
const char *devAlias,
|
||||||
|
qemuDomainUnpluggingDeviceStatus status);
|
||||||
|
|
||||||
#endif /* __QEMU_HOTPLUG_H__ */
|
#endif /* __QEMU_HOTPLUG_H__ */
|
||||||
|
@ -1359,7 +1359,8 @@ qemuProcessHandleDeviceDeleted(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
|
|||||||
VIR_DEBUG("Device %s removed from domain %p %s",
|
VIR_DEBUG("Device %s removed from domain %p %s",
|
||||||
devAlias, vm, vm->def->name);
|
devAlias, vm, vm->def->name);
|
||||||
|
|
||||||
if (qemuDomainSignalDeviceRemoval(vm, devAlias))
|
if (qemuDomainSignalDeviceRemoval(vm, devAlias,
|
||||||
|
QEMU_DOMAIN_UNPLUGGING_DEVICE_STATUS_OK))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
if (VIR_ALLOC(processEvent) < 0)
|
if (VIR_ALLOC(processEvent) < 0)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user