提交 0dfb8a1b 编写于 作者: J Jiri Denemark

qemu: Unplug devices that disappeared when libvirtd was down

In case libvirtd is asked to unplug a device but the device is actually
unplugged later when libvirtd is not running, we need to detect that and
remove such device when libvirtd starts again and reconnects to running
domains.
上级 58b147ad
...@@ -339,6 +339,16 @@ qemuDomainObjPrivateXMLFormat(virBufferPtr buf, void *data) ...@@ -339,6 +339,16 @@ qemuDomainObjPrivateXMLFormat(virBufferPtr buf, void *data)
if (priv->fakeReboot) if (priv->fakeReboot)
virBufferAddLit(buf, " <fakereboot/>\n"); virBufferAddLit(buf, " <fakereboot/>\n");
if (priv->qemuDevices && *priv->qemuDevices) {
char **tmp = priv->qemuDevices;
virBufferAddLit(buf, " <devices>\n");
while (*tmp) {
virBufferAsprintf(buf, " <device alias='%s'/>\n", *tmp);
tmp++;
}
virBufferAddLit(buf, " </devices>\n");
}
return 0; return 0;
} }
...@@ -479,12 +489,35 @@ qemuDomainObjPrivateXMLParse(xmlXPathContextPtr ctxt, void *data) ...@@ -479,12 +489,35 @@ qemuDomainObjPrivateXMLParse(xmlXPathContextPtr ctxt, void *data)
priv->fakeReboot = virXPathBoolean("boolean(./fakereboot)", ctxt) == 1; priv->fakeReboot = virXPathBoolean("boolean(./fakereboot)", ctxt) == 1;
if ((n = virXPathNodeSet("./devices/device", ctxt, &nodes)) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("failed to parse qemu device list"));
goto error;
}
if (n > 0) {
/* NULL-terminated list */
if (VIR_ALLOC_N(priv->qemuDevices, n + 1) < 0)
goto error;
for (i = 0; i < n; i++) {
priv->qemuDevices[i] = virXMLPropString(nodes[i], "alias");
if (!priv->qemuDevices[i]) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("failed to parse qemu device list"));
goto error;
}
}
}
VIR_FREE(nodes);
return 0; return 0;
error: error:
virDomainChrSourceDefFree(priv->monConfig); virDomainChrSourceDefFree(priv->monConfig);
priv->monConfig = NULL; priv->monConfig = NULL;
VIR_FREE(nodes); VIR_FREE(nodes);
virStringFreeList(priv->qemuDevices);
priv->qemuDevices = NULL;
virObjectUnref(qemuCaps); virObjectUnref(qemuCaps);
return -1; return -1;
} }
...@@ -2214,3 +2247,26 @@ qemuDomainMemoryLimit(virDomainDefPtr def) ...@@ -2214,3 +2247,26 @@ qemuDomainMemoryLimit(virDomainDefPtr def)
return mem; return mem;
} }
int
qemuDomainUpdateDeviceList(virQEMUDriverPtr driver,
virDomainObjPtr vm)
{
qemuDomainObjPrivatePtr priv = vm->privateData;
char **aliases;
if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE_DEL_EVENT))
return 0;
qemuDomainObjEnterMonitor(driver, vm);
if (qemuMonitorGetDeviceAliases(priv->mon, &aliases) < 0) {
qemuDomainObjExitMonitor(driver, vm);
return -1;
}
qemuDomainObjExitMonitor(driver, vm);
virStringFreeList(priv->qemuDevices);
priv->qemuDevices = aliases;
return 0;
}
...@@ -171,6 +171,7 @@ struct _qemuDomainObjPrivate { ...@@ -171,6 +171,7 @@ struct _qemuDomainObjPrivate {
virCond unplugFinished; /* signals that unpluggingDevice was unplugged */ virCond unplugFinished; /* signals that unpluggingDevice was unplugged */
const char *unpluggingDevice; /* alias of the device that is being unplugged */ const char *unpluggingDevice; /* alias of the device that is being unplugged */
char **qemuDevices; /* NULL-terminated list of devices aliases known to QEMU */
}; };
typedef enum { typedef enum {
...@@ -363,4 +364,7 @@ extern virDomainDefParserConfig virQEMUDriverDomainDefParserConfig; ...@@ -363,4 +364,7 @@ extern virDomainDefParserConfig virQEMUDriverDomainDefParserConfig;
unsigned long long qemuDomainMemoryLimit(virDomainDefPtr def); unsigned long long qemuDomainMemoryLimit(virDomainDefPtr def);
int qemuDomainUpdateDeviceList(virQEMUDriverPtr driver,
virDomainObjPtr vm);
#endif /* __QEMU_DOMAIN_H__ */ #endif /* __QEMU_DOMAIN_H__ */
...@@ -6494,6 +6494,9 @@ qemuDomainAttachDeviceLive(virDomainObjPtr vm, ...@@ -6494,6 +6494,9 @@ qemuDomainAttachDeviceLive(virDomainObjPtr vm,
break; break;
} }
if (ret == 0)
qemuDomainUpdateDeviceList(driver, vm);
return ret; return ret;
} }
...@@ -6603,6 +6606,9 @@ qemuDomainDetachDeviceLive(virDomainObjPtr vm, ...@@ -6603,6 +6606,9 @@ qemuDomainDetachDeviceLive(virDomainObjPtr vm,
break; break;
} }
if (ret == 0)
qemuDomainUpdateDeviceList(driver, vm);
return ret; return ret;
} }
......
...@@ -2969,6 +2969,39 @@ qemuProcessRecoverJob(virQEMUDriverPtr driver, ...@@ -2969,6 +2969,39 @@ qemuProcessRecoverJob(virQEMUDriverPtr driver,
return 0; return 0;
} }
static int
qemuProcessUpdateDevices(virQEMUDriverPtr driver,
virDomainObjPtr vm)
{
qemuDomainObjPrivatePtr priv = vm->privateData;
virDomainDeviceDef dev;
char **old;
char **tmp;
int ret = -1;
if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE_DEL_EVENT))
return 0;
old = priv->qemuDevices;
priv->qemuDevices = NULL;
if (qemuDomainUpdateDeviceList(driver, vm) < 0)
goto cleanup;
if ((tmp = old)) {
while (*tmp) {
if (!virStringArrayHasString(priv->qemuDevices, *tmp) &&
virDomainDefFindDevice(vm->def, *tmp, &dev, false) == 0)
qemuDomainRemoveDevice(driver, vm, &dev);
tmp++;
}
}
ret = 0;
cleanup:
virStringFreeList(old);
return ret;
}
struct qemuProcessReconnectData { struct qemuProcessReconnectData {
virConnectPtr conn; virConnectPtr conn;
virQEMUDriverPtr driver; virQEMUDriverPtr driver;
...@@ -3105,6 +3138,9 @@ qemuProcessReconnect(void *opaque) ...@@ -3105,6 +3138,9 @@ qemuProcessReconnect(void *opaque)
if (qemuProcessRecoverJob(driver, obj, conn, &oldjob) < 0) if (qemuProcessRecoverJob(driver, obj, conn, &oldjob) < 0)
goto error; goto error;
if (qemuProcessUpdateDevices(driver, obj) < 0)
goto error;
/* update domain state XML with possibly updated state in virDomainObj */ /* update domain state XML with possibly updated state in virDomainObj */
if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, obj) < 0) if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, obj) < 0)
goto error; goto error;
...@@ -3905,6 +3941,10 @@ int qemuProcessStart(virConnectPtr conn, ...@@ -3905,6 +3941,10 @@ int qemuProcessStart(virConnectPtr conn,
qemuDomainObjExitMonitor(driver, vm); qemuDomainObjExitMonitor(driver, vm);
VIR_DEBUG("Fetching list of active devices");
if (qemuDomainUpdateDeviceList(driver, vm) < 0)
goto cleanup;
/* Technically, qemuProcessStart can be called from inside /* Technically, qemuProcessStart can be called from inside
* QEMU_ASYNC_JOB_MIGRATION_IN, but we are okay treating this like * QEMU_ASYNC_JOB_MIGRATION_IN, but we are okay treating this like
* a sync job since no other job can call into the domain until * a sync job since no other job can call into the domain until
...@@ -4166,6 +4206,9 @@ void qemuProcessStop(virQEMUDriverPtr driver, ...@@ -4166,6 +4206,9 @@ void qemuProcessStop(virQEMUDriverPtr driver,
VIR_FREE(vm->def->seclabels[i]->imagelabel); VIR_FREE(vm->def->seclabels[i]->imagelabel);
} }
virStringFreeList(priv->qemuDevices);
priv->qemuDevices = NULL;
virDomainDefClearDeviceAliases(vm->def); virDomainDefClearDeviceAliases(vm->def);
if (!priv->persistentAddrs) { if (!priv->persistentAddrs) {
virDomainDefClearPCIAddresses(vm->def); virDomainDefClearPCIAddresses(vm->def);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册