virDomainObjPtr vm);
# 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 qemuDomainObjPrivate *qemuDomainObjPrivatePtr;
struct _qemuDomainObjPrivate {
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 */
bool hookRun; /* true if there was a hook run over this domain */
{
qemuDomainObjPrivatePtr priv = vm->privateData;
- if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE_DEL_EVENT))
- priv->unpluggingDevice = info->alias;
- else
- priv->unpluggingDevice = NULL;
+ memset(&priv->unplug, 0, sizeof(priv->unplug));
+
+ if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE_DEL_EVENT))
+ return;
+
+ priv->unplug.alias = info->alias;
}
static void
qemuDomainResetDeviceRemoval(virDomainObjPtr vm)
{
qemuDomainObjPrivatePtr priv = vm->privateData;
- priv->unpluggingDevice = NULL;
+ priv->unplug.alias = NULL;
}
/* Returns:
+ * -1 Unplug of the device failed
+ *
* 0 DEVICE_DELETED event is supported and removal of the device did not
* finish in qemuDomainRemoveDeviceWaitTime
*
return 1;
until += qemuDomainRemoveDeviceWaitTime;
- while (priv->unpluggingDevice) {
+ while (priv->unplug.alias) {
if ((rc = virDomainObjWaitUntil(vm, until)) == 1)
return 0;
if (rc < 0) {
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;
}
}
+ 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;
}
*/
bool
qemuDomainSignalDeviceRemoval(virDomainObjPtr vm,
- const char *devAlias)
+ const char *devAlias,
+ qemuDomainUnpluggingDeviceStatus status)
{
qemuDomainObjPrivatePtr priv = vm->privateData;
- if (STREQ_NULLABLE(priv->unpluggingDevice, devAlias)) {
+ if (STREQ_NULLABLE(priv->unplug.alias, devAlias)) {
qemuDomainResetDeviceRemoval(vm);
+ priv->unplug.status = status;
virDomainObjBroadcast(vm);
return true;
}
VIR_DEBUG("Device %s removed from domain %p %s",
devAlias, vm, vm->def->name);
- if (qemuDomainSignalDeviceRemoval(vm, devAlias))
+ if (qemuDomainSignalDeviceRemoval(vm, devAlias,
+ QEMU_DOMAIN_UNPLUGGING_DEVICE_STATUS_OK))
goto cleanup;
if (VIR_ALLOC(processEvent) < 0)