[libvirt PATCH v2 08/16] qemu: Add qemuNbdkitProcess

Jonathon Jongsma jjongsma at redhat.com
Wed Aug 31 18:40:53 UTC 2022


An object for storing information about a nbdkit process that is serving
a specific virStorageSource. At the moment, this information is just
stored in the private data of virStorageSource and not used at all.
Future commits will use this data to actually start a nbdkit process.

Signed-off-by: Jonathon Jongsma <jjongsma at redhat.com>
---
 src/qemu/qemu_conf.c   | 22 ++++++++++++
 src/qemu/qemu_conf.h   |  3 ++
 src/qemu/qemu_domain.c | 29 +++++++++++++++
 src/qemu/qemu_domain.h |  4 +++
 src/qemu/qemu_nbdkit.c | 82 ++++++++++++++++++++++++++++++++++++++++++
 src/qemu/qemu_nbdkit.h | 24 +++++++++++++
 6 files changed, 164 insertions(+)

diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index 3b75cdeb95..b5f451a8f9 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -1571,3 +1571,25 @@ qemuGetMemoryBackingPath(virQEMUDriver *driver,
     *memPath = g_strdup_printf("%s/%s", domainPath, alias);
     return 0;
 }
+
+/*
+ * qemuGetNbdkitCaps:
+ * @driver: the qemu driver
+ *
+ * Gets the capabilities for Nbdkit for the specified driver. These can be used
+ * to determine whether a particular disk source can be served by nbdkit or
+ * not.
+ *
+ * Returns: a reference to qemuNbdkitCaps or NULL
+ */
+qemuNbdkitCaps*
+qemuGetNbdkitCaps(virQEMUDriver *driver)
+{
+    if (!driver->nbdkitBinary)
+        driver->nbdkitBinary = virFindFileInPath("nbdkit");
+
+    if (driver->nbdkitBinary)
+        return virFileCacheLookup(driver->nbdkitCapsCache, driver->nbdkitBinary);
+
+    return NULL;
+}
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
index 414bcfb8a2..91212d6608 100644
--- a/src/qemu/qemu_conf.h
+++ b/src/qemu/qemu_conf.h
@@ -309,6 +309,7 @@ struct _virQEMUDriver {
     virHashAtomic *migrationErrors;
 
     virFileCache *nbdkitCapsCache;
+    char *nbdkitBinary;
 };
 
 virQEMUDriverConfig *virQEMUDriverConfigNew(bool privileged,
@@ -362,3 +363,5 @@ int qemuGetMemoryBackingPath(virQEMUDriver *driver,
                              const virDomainDef *def,
                              const char *alias,
                              char **memPath);
+
+qemuNbdkitCaps* qemuGetNbdkitCaps(virQEMUDriver *driver);
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index fe3ce023a4..5b3b2d3e9c 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -819,6 +819,7 @@ qemuDomainStorageSourcePrivateDispose(void *obj)
     g_clear_pointer(&priv->encinfo, qemuDomainSecretInfoFree);
     g_clear_pointer(&priv->httpcookie, qemuDomainSecretInfoFree);
     g_clear_pointer(&priv->tlsKeySecret, qemuDomainSecretInfoFree);
+    g_clear_pointer(&priv->nbdkitProcess, qemuNbdkitProcessFree);
 }
 
 
@@ -10013,6 +10014,32 @@ qemuDomainPrepareStorageSourceNFS(virStorageSource *src)
 }
 
 
+/* qemuPrepareStorageSourceNbdkit:
+ * @src: source for a disk
+ *
+ * If src is an network source that is managed by nbdkit, prepare data so that
+ * nbdkit can be launched before the domain is started
+ *
+ * Returns true if nbdkit will be used for this source,
+ */
+static bool
+qemuDomainPrepareStorageSourceNbdkit(virStorageSource *src,
+                                     virQEMUDriverConfig *cfg,
+                                     const char *alias,
+                                     qemuDomainObjPrivate *priv)
+{
+    g_autoptr(qemuNbdkitCaps) nbdkit = qemuGetNbdkitCaps(priv->driver);
+    if (!nbdkit)
+        return false;
+
+    if (virStorageSourceGetActualType(src) != VIR_STORAGE_TYPE_NETWORK)
+        return false;
+
+    return qemuNbdkitInitStorageSource(nbdkit, src, priv->libDir,
+                                       alias, cfg->user, cfg->group);
+}
+
+
 /* qemuProcessPrepareStorageSourceTLS:
  * @source: source for a disk
  * @cfg: driver configuration
@@ -10787,6 +10814,8 @@ qemuDomainPrepareStorageSourceBlockdevNodename(virDomainDiskDef *disk,
     if (qemuDomainPrepareStorageSourceNFS(src) < 0)
         return -1;
 
+    qemuDomainPrepareStorageSourceNbdkit(src, cfg, src->nodestorage, priv);
+
     return 0;
 }
 
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
index 592ee9805b..563b0aa925 100644
--- a/src/qemu/qemu_domain.h
+++ b/src/qemu/qemu_domain.h
@@ -33,6 +33,7 @@
 #include "qemu_conf.h"
 #include "qemu_capabilities.h"
 #include "qemu_migration_params.h"
+#include "qemu_nbdkit.h"
 #include "qemu_slirp.h"
 #include "qemu_fd.h"
 #include "virchrdev.h"
@@ -293,6 +294,9 @@ struct _qemuDomainStorageSourcePrivate {
 
     /* key for decrypting TLS certificate */
     qemuDomainSecretInfo *tlsKeySecret;
+
+    /* an nbdkit process for serving network storage sources */
+    qemuNbdkitProcess *nbdkitProcess;
 };
 
 virObject *qemuDomainStorageSourcePrivateNew(void);
diff --git a/src/qemu/qemu_nbdkit.c b/src/qemu/qemu_nbdkit.c
index fc83f80f1f..4df8957196 100644
--- a/src/qemu/qemu_nbdkit.c
+++ b/src/qemu/qemu_nbdkit.c
@@ -579,3 +579,85 @@ qemuNbdkitCapsCacheNew(const char *cachedir)
     g_autofree char *dir = g_build_filename(cachedir, "nbdkitcapabilities", NULL);
     return virFileCacheNew(dir, "xml", &nbdkitCapsCacheHandlers);
 }
+
+
+static qemuNbdkitProcess *
+qemuNbdkitProcessNew(qemuNbdkitCaps *caps,
+                     virStorageSource *source,
+                     char *statedir,
+                     const char *alias,
+                     uid_t user,
+                     gid_t group)
+{
+    qemuNbdkitProcess *proc = g_new0(qemuNbdkitProcess, 1);
+    g_autofree char *pidfile = g_strdup_printf("nbdkit-%s.pid", alias);
+    g_autofree char *socketfile = g_strdup_printf("nbdkit-%s.socket", alias);
+
+    proc->caps = g_object_ref(caps);
+    /* weak reference -- source owns this object, so it will always outlive us */
+    proc->source = source;
+    proc->user = user;
+    proc->group = group;
+    proc->pidfile = g_build_filename(statedir, pidfile, NULL);
+    proc->socketfile = g_build_filename(statedir, socketfile, NULL);
+
+    return proc;
+}
+
+
+bool
+qemuNbdkitInitStorageSource(qemuNbdkitCaps *caps,
+                            virStorageSource *source,
+                            char *statedir,
+                            const char *alias,
+                            uid_t user,
+                            gid_t group)
+{
+    qemuDomainStorageSourcePrivate *srcPriv = qemuDomainStorageSourcePrivateFetch(source);
+
+    if (srcPriv->nbdkitProcess)
+        return false;
+
+    switch (source->protocol) {
+        case VIR_STORAGE_NET_PROTOCOL_HTTP:
+        case VIR_STORAGE_NET_PROTOCOL_HTTPS:
+        case VIR_STORAGE_NET_PROTOCOL_FTP:
+        case VIR_STORAGE_NET_PROTOCOL_FTPS:
+        case VIR_STORAGE_NET_PROTOCOL_TFTP:
+            if (!virBitmapIsBitSet(caps->flags, QEMU_NBDKIT_CAPS_PLUGIN_CURL))
+                return false;
+            break;
+        case VIR_STORAGE_NET_PROTOCOL_SSH:
+            if (!virBitmapIsBitSet(caps->flags, QEMU_NBDKIT_CAPS_PLUGIN_SSH))
+                return false;
+            break;
+        case VIR_STORAGE_NET_PROTOCOL_NONE:
+        case VIR_STORAGE_NET_PROTOCOL_NBD:
+        case VIR_STORAGE_NET_PROTOCOL_RBD:
+        case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG:
+        case VIR_STORAGE_NET_PROTOCOL_GLUSTER:
+        case VIR_STORAGE_NET_PROTOCOL_ISCSI:
+        case VIR_STORAGE_NET_PROTOCOL_VXHS:
+        case VIR_STORAGE_NET_PROTOCOL_NFS:
+        case VIR_STORAGE_NET_PROTOCOL_LAST:
+            return false;
+    }
+    srcPriv->nbdkitProcess = qemuNbdkitProcessNew(caps, source, statedir, alias, user, group);
+
+    return true;
+}
+
+
+void
+qemuNbdkitProcessFree(qemuNbdkitProcess *proc)
+{
+    if (virProcessKillPainfully(proc->pid, true) < 0)
+        VIR_WARN("Unable to kill nbdkit process");
+
+    unlink(proc->pidfile);
+    g_clear_pointer(&proc->pidfile, g_free);
+    unlink(proc->socketfile);
+    g_clear_pointer(&proc->socketfile, g_free);
+    g_clear_object(&proc->caps);
+    g_free(proc);
+}
diff --git a/src/qemu/qemu_nbdkit.h b/src/qemu/qemu_nbdkit.h
index 3e34403d90..24762cce8f 100644
--- a/src/qemu/qemu_nbdkit.h
+++ b/src/qemu/qemu_nbdkit.h
@@ -30,6 +30,7 @@
 #include "viruri.h"
 
 typedef struct _qemuNbdkitCaps qemuNbdkitCaps;
+typedef struct _qemuNbdkitProcess qemuNbdkitProcess;
 
 typedef enum {
     QEMU_NBDKIT_CAPS_PLUGIN_CURL,
@@ -44,9 +45,32 @@ qemuNbdkitCaps* qemuNbdkitCapsNew(const char *path);
 
 virFileCache* qemuNbdkitCapsCacheNew(const char *cachedir);
 
+bool qemuNbdkitInitStorageSource(qemuNbdkitCaps *nbdkitCaps,
+                                 virStorageSource *source,
+                                 char *statedir,
+                                 const char *alias,
+                                 uid_t user,
+                                 gid_t group
+                                 /*, char *selinux_label*/);
+
 bool qemuNbdkitCapsGet(qemuNbdkitCaps *nbdkitCaps, qemuNbdkitCapsFlags flag);
 
 void qemuNbdkitCapsSet(qemuNbdkitCaps *nbdkitCaps, qemuNbdkitCapsFlags flag);
 
 #define QEMU_TYPE_NBDKIT_CAPS qemu_nbdkit_caps_get_type()
 G_DECLARE_FINAL_TYPE(qemuNbdkitCaps, qemu_nbdkit_caps, QEMU, NBDKIT_CAPS, GObject);
+
+struct _qemuNbdkitProcess {
+    qemuNbdkitCaps *caps;
+    virStorageSource *source;
+
+    char *pidfile;
+    char *socketfile;
+    uid_t user;
+    gid_t group;
+    pid_t pid;
+};
+
+void qemuNbdkitProcessFree(qemuNbdkitProcess *proc);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(qemuNbdkitProcess, qemuNbdkitProcessFree);
-- 
2.37.1



More information about the libvir-list mailing list