[libvirt PATCH v5 18/32] qemu: include nbdkit state in private xml

Jonathon Jongsma jjongsma at redhat.com
Tue Feb 14 17:08:05 UTC 2023


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 at redhat.com>
---
 src/qemu/qemu_domain.c                    | 52 +++++++++++++++++
 src/qemu/qemu_nbdkit.c                    | 71 +++++++++++++++++++++++
 src/qemu/qemu_nbdkit.h                    |  8 +++
 src/qemu/qemu_process.c                   |  6 ++
 tests/qemustatusxml2xmldata/modern-in.xml |  4 ++
 5 files changed, 141 insertions(+)

diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 099ce2ab9a..781b80b46d 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -1936,6 +1936,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)
@@ -1948,6 +1975,7 @@ qemuStorageSourcePrivateDataParse(xmlXPathContextPtr ctxt,
     g_autofree char *thresholdEventWithIndex = NULL;
     bool fdsetPresent = false;
     unsigned int fdSetID;
+    xmlNodePtr nbdkitnode = NULL;
 
     src->nodestorage = virXPathString("string(./nodenames/nodename[@type='storage']/@name)", ctxt);
     src->nodeformat = virXPathString("string(./nodenames/nodename[@type='format']/@name)", ctxt);
@@ -1996,6 +2024,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;
 }
 
@@ -2013,6 +2045,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)
@@ -2059,6 +2108,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 c79c9ec6cd..5f0c0c23b5 100644
--- a/src/qemu/qemu_nbdkit.c
+++ b/src/qemu/qemu_nbdkit.c
@@ -628,6 +628,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,
diff --git a/src/qemu/qemu_nbdkit.h b/src/qemu/qemu_nbdkit.h
index ccd418b7d3..7e2aeed4eb 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);
+
+void
+qemuNbdkitStorageSourceManageProcess(virStorageSource *src);
+
 bool
 qemuNbdkitCapsGet(qemuNbdkitCaps *nbdkitCaps,
                   qemuNbdkitCapsFlags flag);
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index a61c3192fd..d0b797575d 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -9035,6 +9035,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;
diff --git a/tests/qemustatusxml2xmldata/modern-in.xml b/tests/qemustatusxml2xmldata/modern-in.xml
index cdab1d7178..6efb52fb14 100644
--- a/tests/qemustatusxml2xmldata/modern-in.xml
+++ b/tests/qemustatusxml2xmldata/modern-in.xml
@@ -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/>
-- 
2.39.1



More information about the libvir-list mailing list