qemu: include nbdkit state in private xml

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@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
This commit is contained in:
Jonathon Jongsma 2022-07-08 10:40:06 -05:00
parent d20a6eda44
commit dfa657aa27
5 changed files with 141 additions and 0 deletions

View File

@ -1958,6 +1958,33 @@ 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))) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("missing nbdkit pidfile"));
return -1;
}
if (!(socketfile = virXPathString("string(./socketfile)", ctxt))) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("missing nbdkit socketfile"));
return -1;
}
qemuNbdkitReconnectStorageSource(src, pidfile, socketfile);
return 0;
}
static int
qemuStorageSourcePrivateDataParse(xmlXPathContextPtr ctxt,
virStorageSource *src)
@ -1971,6 +1998,7 @@ qemuStorageSourcePrivateDataParse(xmlXPathContextPtr ctxt,
bool fdsetPresent = false;
unsigned int fdSetID;
int enccount;
xmlNodePtr nbdkitnode = NULL;
src->nodestorage = virXPathString("string(./nodenames/nodename[@type='storage']/@name)", ctxt);
src->nodeformat = virXPathString("string(./nodenames/nodename[@type='format']/@name)", ctxt);
@ -2036,6 +2064,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;
}
@ -2053,6 +2085,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)
@ -2102,6 +2151,9 @@ qemuStorageSourcePrivateDataFormat(virStorageSource *src,
if (src->thresholdEventWithIndex)
virBufferAddLit(buf, "<thresholdEvent indexUsed='yes'/>\n");
if (srcPriv)
qemuStorageSourcePrivateDataFormatNbdkit(srcPriv->nbdkitProcess, buf);
return 0;
}

View File

@ -627,6 +627,77 @@ 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 void
qemuNbdkitStorageSourceManageProcessOne(virStorageSource *source)
{
qemuDomainStorageSourcePrivate *srcpriv = QEMU_DOMAIN_STORAGE_SOURCE_PRIVATE(source);
qemuNbdkitProcess *proc;
if (!srcpriv)
return;
proc = srcpriv->nbdkitProcess;
if (!proc)
return;
if (proc->pid <= 0) {
if (virPidFileReadPath(proc->pidfile, &proc->pid) < 0) {
VIR_WARN("Unable to read pidfile '%s'", proc->pidfile);
return;
}
}
if (virProcessKill(proc->pid, 0) < 0)
VIR_WARN("nbdkit process %i is not alive", proc->pid);
}
/**
* 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.
*/
void
qemuNbdkitStorageSourceManageProcess(virStorageSource *source)
{
virStorageSource *backing;
for (backing = source; backing != NULL; backing = backing->backingStore)
qemuNbdkitStorageSourceManageProcessOne(backing);
}
bool
qemuNbdkitInitStorageSource(qemuNbdkitCaps *caps,

View File

@ -54,6 +54,14 @@ qemuNbdkitInitStorageSource(qemuNbdkitCaps *nbdkitCaps,
uid_t user,
gid_t group);
void
qemuNbdkitReconnectStorageSource(virStorageSource *source,
const char *pidfile,
const char *socketfile);
void
qemuNbdkitStorageSourceManageProcess(virStorageSource *src);
bool
qemuNbdkitCapsGet(qemuNbdkitCaps *nbdkitCaps,
qemuNbdkitCapsFlags flag);

View File

@ -9054,6 +9054,12 @@ qemuProcessReconnect(void *opaque)
}
}
for (i = 0; i < obj->def->ndisks; i++)
qemuNbdkitStorageSourceManageProcess(obj->def->disks[i]->src);
if (obj->def->os.loader && obj->def->os.loader->nvram)
qemuNbdkitStorageSourceManageProcess(obj->def->os.loader->nvram);
/* update domain state XML with possibly updated state in virDomainObj */
if (virDomainObjSave(obj, driver->xmlopt, cfg->stateDir) < 0)
goto error;

View File

@ -345,6 +345,10 @@
<fdset type='storage' id='1337'/>
</fdsets>
<thresholdEvent indexUsed='yes'/>
<nbdkit>
<pidfile>/path/to/nbdkit.pid</pidfile>
<socketfile>/path/to/nbdkit.socket</socketfile>
</nbdkit>
</privateData>
</source>
<backingStore/>