Add xml to the private data for a disk source to represent the nbdkit process so that the state can be re-created if the libvirt daemon is restarted. Format: <nbdkit> <pidfile>/path/to/nbdkit.pid</pidfile> <socketfile>/path/to/nbdkit.socket</socketfile> </nbdkit> Signed-off-by: Jonathon Jongsma <jjongsma@xxxxxxxxxx> --- src/qemu/qemu_domain.c | 48 ++++++++++++++ src/qemu/qemu_nbdkit.c | 77 +++++++++++++++++++++++ src/qemu/qemu_nbdkit.h | 8 +++ src/qemu/qemu_process.c | 11 ++++ tests/qemustatusxml2xmldata/modern-in.xml | 4 ++ 5 files changed, 148 insertions(+) diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 0e3eaf49f8..28d4bddf14 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -1911,6 +1911,29 @@ qemuStorageSourcePrivateDataAssignSecinfo(qemuDomainSecretInfo **secinfo, } +static int +qemuStorageSourcePrivateDataParseNbdkit(xmlNodePtr node, + xmlXPathContextPtr ctxt, + virStorageSource *src) +{ + g_autofree char *pidfile = NULL; + g_autofree char *socketfile = NULL; + VIR_XPATH_NODE_AUTORESTORE(ctxt); + + ctxt->node = node; + + if (!(pidfile = virXPathString("string(./pidfile)", ctxt))) + return -1; + + if (!(socketfile = virXPathString("string(./socketfile)", ctxt))) + return -1; + + qemuNbdkitReconnectStorageSource(src, pidfile, socketfile); + + return 0; +} + + static int qemuStorageSourcePrivateDataParse(xmlXPathContextPtr ctxt, virStorageSource *src) @@ -1921,6 +1944,7 @@ qemuStorageSourcePrivateDataParse(xmlXPathContextPtr ctxt, g_autofree char *httpcookiealias = NULL; g_autofree char *tlskeyalias = NULL; g_autofree char *thresholdEventWithIndex = NULL; + xmlNodePtr nbdkitnode = NULL; src->nodestorage = virXPathString("string(./nodenames/nodename[@type='storage']/@name)", ctxt); src->nodeformat = virXPathString("string(./nodenames/nodename[@type='format']/@name)", ctxt); @@ -1964,6 +1988,10 @@ qemuStorageSourcePrivateDataParse(xmlXPathContextPtr ctxt, virTristateBoolTypeFromString(thresholdEventWithIndex) == VIR_TRISTATE_BOOL_YES) src->thresholdEventWithIndex = true; + if ((nbdkitnode = virXPathNode("nbdkit", ctxt))) { + if (qemuStorageSourcePrivateDataParseNbdkit(nbdkitnode, ctxt, src) < 0) + return -1; + } return 0; } @@ -1981,6 +2009,23 @@ qemuStorageSourcePrivateDataFormatSecinfo(virBuffer *buf, } +static void +qemuStorageSourcePrivateDataFormatNbdkit(qemuNbdkitProcess *nbdkit, + virBuffer *buf) +{ + g_auto(virBuffer) childBuf = VIR_BUFFER_INIT_CHILD(buf); + + if (!nbdkit) + return; + + virBufferEscapeString(&childBuf, "<pidfile>%s</pidfile>\n", + nbdkit->pidfile); + virBufferEscapeString(&childBuf, "<socketfile>%s</socketfile>\n", + nbdkit->socketfile); + virXMLFormatElement(buf, "nbdkit", NULL, &childBuf); +} + + static int qemuStorageSourcePrivateDataFormat(virStorageSource *src, virBuffer *buf) @@ -2019,6 +2064,9 @@ qemuStorageSourcePrivateDataFormat(virStorageSource *src, if (src->thresholdEventWithIndex) virBufferAddLit(buf, "<thresholdEvent indexUsed='yes'/>\n"); + if (srcPriv) + qemuStorageSourcePrivateDataFormatNbdkit(srcPriv->nbdkitProcess, buf); + return 0; } diff --git a/src/qemu/qemu_nbdkit.c b/src/qemu/qemu_nbdkit.c index 00ca945904..2b26e9bc08 100644 --- a/src/qemu/qemu_nbdkit.c +++ b/src/qemu/qemu_nbdkit.c @@ -627,6 +627,83 @@ qemuNbdkitProcessNew(virStorageSource *source, return nbdkit; } +/** + * qemuNbdkitReconnectStorageSource: + * @source: a storage source + * @pidfile: a pidfile for an nbdkit process + * @socketfile: the socket file associated with the nbdkit process + * + * This function constructs a new qemuNbdkitProcess object with the given values for @pidfile and + * @socketfile and stores it in @source. This is intended to be called when the libvirt daemon is + * restarted and tries to reconnect to all currently-running domains. Since this function is called + * from the code that parses the current daemon state, it should not perform any filesystem + * operations, or anything else that might fail. Additional initialization will be done later by + * calling qemuNbdkitStorageSourceManageProcess(). + */ +void +qemuNbdkitReconnectStorageSource(virStorageSource *source, + const char *pidfile, + const char *socketfile) +{ + qemuDomainStorageSourcePrivate *srcpriv = qemuDomainStorageSourcePrivateFetch(source); + + if (srcpriv->nbdkitProcess) { + VIR_WARN("source already has an nbdkit process"); + return; + } + + srcpriv->nbdkitProcess = qemuNbdkitProcessNew(source, pidfile, socketfile); +} + + +static int +qemuNbdkitStorageSourceManageProcessOne(virStorageSource *source) +{ + qemuDomainStorageSourcePrivate *srcpriv = QEMU_DOMAIN_STORAGE_SOURCE_PRIVATE(source); + qemuNbdkitProcess *proc; + + if (!srcpriv) + return 0; + + proc = srcpriv->nbdkitProcess; + + if (proc) { + if (proc->pid <= 0) { + if (virPidFileReadPath(proc->pidfile, &proc->pid) < 0) + return -1; + } + + if (virProcessKill(proc->pid, 0) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("nbdkit process %i is not alive"), proc->pid); + return -1; + } + } + + return 0; +} + +/** + * qemuNbdkitStorageSourceManageProcess: + * @source: a storage source + * @vm: the vm that owns this storage source + * + * This function re-enables monitoring of any nbdkit processes associated with the backing chain of + * @source. It is intended to be called after libvirt restarts and has loaded its current state from + * disk and is attempting to re-connect to active domains. + */ +int +qemuNbdkitStorageSourceManageProcess(virStorageSource *source) +{ + virStorageSource *backing; + for (backing = source->backingStore; backing != NULL; backing = backing->backingStore) { + if (qemuNbdkitStorageSourceManageProcessOne(backing) < 0) + return -1; + } + + return qemuNbdkitStorageSourceManageProcessOne(source); +} + bool qemuNbdkitInitStorageSource(qemuNbdkitCaps *caps, diff --git a/src/qemu/qemu_nbdkit.h b/src/qemu/qemu_nbdkit.h index ccd418b7d3..2be46b6002 100644 --- a/src/qemu/qemu_nbdkit.h +++ b/src/qemu/qemu_nbdkit.h @@ -54,6 +54,14 @@ qemuNbdkitInitStorageSource(qemuNbdkitCaps *nbdkitCaps, uid_t user, gid_t group); +void +qemuNbdkitReconnectStorageSource(virStorageSource *source, + const char *pidfile, + const char *socketfile); + +int +qemuNbdkitStorageSourceManageProcess(virStorageSource *src); + bool qemuNbdkitCapsGet(qemuNbdkitCaps *nbdkitCaps, qemuNbdkitCapsFlags flag); diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 6d1751b5d7..7ec31ef6ac 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -9047,6 +9047,17 @@ qemuProcessReconnect(void *opaque) } } + for (i = 0; i < obj->def->ndisks; i++) { + virDomainDiskDef *disk = obj->def->disks[i]; + if (qemuNbdkitStorageSourceManageProcess(disk->src) < 0) + goto error; + } + + if (obj->def->os.loader && obj->def->os.loader->nvram) { + if (qemuNbdkitStorageSourceManageProcess(obj->def->os.loader->nvram) < 0) + goto error; + } + /* update domain state XML with possibly updated state in virDomainObj */ if (virDomainObjSave(obj, driver->xmlopt, cfg->stateDir) < 0) goto error; diff --git a/tests/qemustatusxml2xmldata/modern-in.xml b/tests/qemustatusxml2xmldata/modern-in.xml index 7759034f7a..71b3eb4736 100644 --- a/tests/qemustatusxml2xmldata/modern-in.xml +++ b/tests/qemustatusxml2xmldata/modern-in.xml @@ -342,6 +342,10 @@ <TLSx509 alias='transport-alias'/> </objects> <thresholdEvent indexUsed='yes'/> + <nbdkit> + <pidfile>/path/to/nbdkit.pid</pidfile> + <socketfile>/path/to/nbdkit.socket</socketfile> + </nbdkit> </privateData> </source> <backingStore/> -- 2.39.0