In future commits, we will optionally use nbdkit to serve some remote
disk sources. This patch queries to see whether nbdkit is installed on
the host and queries it for capabilities. These capabilities are stored
in the qemu driver.
Signed-off-by: Jonathon Jongsma <jjongsma(a)redhat.com>
---
po/POTFILES | 1 +
src/qemu/meson.build | 1 +
src/qemu/qemu_conf.h | 3 +
src/qemu/qemu_driver.c | 3 +
src/qemu/qemu_nbdkit.c | 226 +++++++++++++++++++++++++++++++++++++++++
src/qemu/qemu_nbdkit.h | 51 ++++++++++
6 files changed, 285 insertions(+)
create mode 100644 src/qemu/qemu_nbdkit.c
create mode 100644 src/qemu/qemu_nbdkit.h
diff --git a/po/POTFILES b/po/POTFILES
index d32105f7d5..1fd92256d4 100644
--- a/po/POTFILES
+++ b/po/POTFILES
@@ -179,6 +179,7 @@ src/qemu/qemu_monitor.c
src/qemu/qemu_monitor_json.c
src/qemu/qemu_monitor_text.c
src/qemu/qemu_namespace.c
+src/qemu/qemu_nbdkit.c
src/qemu/qemu_process.c
src/qemu/qemu_qapi.c
src/qemu/qemu_saveimage.c
diff --git a/src/qemu/meson.build b/src/qemu/meson.build
index 96952cc52d..101cf3591f 100644
--- a/src/qemu/meson.build
+++ b/src/qemu/meson.build
@@ -28,6 +28,7 @@ qemu_driver_sources = [
'qemu_monitor_json.c',
'qemu_monitor_text.c',
'qemu_namespace.c',
+ 'qemu_nbdkit.c',
'qemu_process.c',
'qemu_qapi.c',
'qemu_saveimage.c',
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
index c40c452f58..d05c715400 100644
--- a/src/qemu/qemu_conf.h
+++ b/src/qemu/qemu_conf.h
@@ -36,6 +36,7 @@
#include "virthreadpool.h"
#include "locking/lock_manager.h"
#include "qemu_capabilities.h"
+#include "qemu_nbdkit.h"
#include "virclosecallbacks.h"
#include "virhostdev.h"
#include "virfile.h"
@@ -306,6 +307,8 @@ struct _virQEMUDriver {
/* Immutable pointer, self-locking APIs */
virHashAtomic *migrationErrors;
+
+ qemuNbdkitCaps *nbdkitCaps;
};
virQEMUDriverConfig *virQEMUDriverConfigNew(bool privileged,
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 707f4cc1bb..943fa8621d 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -832,6 +832,9 @@ qemuStateInitialize(bool privileged,
defsecmodel)))
goto error;
+ /* find whether nbdkit is available and query its capabilities */
+ qemu_driver->nbdkitCaps = qemuQueryNbdkitCaps();
+
/* If hugetlbfs is present, then we need to create a sub-directory within
* it, since we can't assume the root mount point has permissions that
* will let our spawned QEMU instances use it. */
diff --git a/src/qemu/qemu_nbdkit.c b/src/qemu/qemu_nbdkit.c
new file mode 100644
index 0000000000..f55f68299f
--- /dev/null
+++ b/src/qemu/qemu_nbdkit.c
@@ -0,0 +1,226 @@
+/*
+ * qemu_nbdkit.c: helpers for using nbdkit
+ *
+ * Copyright (C) 2021 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <
http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <config.h>
+#include <glib.h>
+
+#include "vircommand.h"
+#include "virerror.h"
+#include "virlog.h"
+#include "virpidfile.h"
+#include "virsecureerase.h"
+#include "virutil.h"
+#include "qemu_block.h"
+#include "qemu_conf.h"
+#include "qemu_domain.h"
+#include "qemu_driver.h"
+#include "qemu_extdevice.h"
+#include "qemu_nbdkit.h"
+#include "qemu_security.h"
+
+#include <fcntl.h>
+
+#define VIR_FROM_THIS VIR_FROM_QEMU
+
+VIR_LOG_INIT("qemu.nbdkit");
+
+VIR_ENUM_IMPL(qemuNbdkitCaps,
+ QEMU_NBDKIT_CAPS_LAST,
+ /* 0 */
+ "plugin-curl", /* QEMU_NBDKIT_CAPS_PLUGIN_CURL */
+ "plugin-ssh", /* QEMU_NBDKIT_CAPS_PLUGIN_SSH */
+ "filter-readahead", /* QEMU_NBDKIT_CAPS_FILTER_READAHEAD */
+);
+
+struct _qemuNbdkitCaps {
+ GObject parent;
+
+ char *path;
+ char *version;
+
+ virBitmap *flags;
+};
+G_DEFINE_TYPE(qemuNbdkitCaps, qemu_nbdkit_caps, G_TYPE_OBJECT);
+
+
+static void
+qemuNbdkitCheckCommandCap(qemuNbdkitCaps *nbdkit,
+ virCommand *cmd,
+ qemuNbdkitCapsFlags cap)
+{
+ if (virCommandRun(cmd, NULL) != 0)
+ return;
+
+ VIR_DEBUG("Setting nbdkit capability %i", cap);
+ ignore_value(virBitmapSetBit(nbdkit->flags, cap));
+}
+
+
+static void
+qemuNbdkitQueryFilter(qemuNbdkitCaps *nbdkit,
+ const char *filter,
+ qemuNbdkitCapsFlags cap)
+{
+ g_autoptr(virCommand) cmd = virCommandNewArgList(nbdkit->path,
+ "--version",
+ NULL);
+
+ virCommandAddArgPair(cmd, "--filter", filter);
+
+ /* use null plugin to check for filter */
+ virCommandAddArg(cmd, "null");
+
+ qemuNbdkitCheckCommandCap(nbdkit, cmd, cap);
+}
+
+
+static void
+qemuNbdkitQueryPlugin(qemuNbdkitCaps *nbdkit,
+ const char *plugin,
+ qemuNbdkitCapsFlags cap)
+{
+ g_autoptr(virCommand) cmd = virCommandNewArgList(nbdkit->path,
+ plugin,
+ "--version",
+ NULL);
+
+ qemuNbdkitCheckCommandCap(nbdkit, cmd, cap);
+}
+
+
+static void
+qemuNbdkitCapsQueryPlugins(qemuNbdkitCaps *nbdkit)
+{
+ qemuNbdkitQueryPlugin(nbdkit, "curl", QEMU_NBDKIT_CAPS_PLUGIN_CURL);
+ qemuNbdkitQueryPlugin(nbdkit, "ssh", QEMU_NBDKIT_CAPS_PLUGIN_SSH);
+}
+
+
+static void
+qemuNbdkitCapsQueryFilters(qemuNbdkitCaps *nbdkit)
+{
+ qemuNbdkitQueryFilter(nbdkit, "readahead",
+ QEMU_NBDKIT_CAPS_FILTER_READAHEAD);
+}
+
+
+static int
+qemuNbdkitCapsQueryVersion(qemuNbdkitCaps *nbdkit)
+{
+ g_autoptr(virCommand) cmd = virCommandNewArgList(nbdkit->path,
+ "--version",
+ NULL);
+
+ virCommandSetOutputBuffer(cmd, &nbdkit->version);
+
+ if (virCommandRun(cmd, NULL) != 0)
+ return -1;
+
+ VIR_DEBUG("Got nbdkit version %s", nbdkit->version);
+ return 0;
+}
+
+
+static void qemuNbdkitCapsFinalize(GObject *object)
+{
+ qemuNbdkitCaps *nbdkit = QEMU_NBDKIT_CAPS(object);
+
+ g_clear_pointer(&nbdkit->path, g_free);
+ g_clear_pointer(&nbdkit->version, g_free);
+ g_clear_pointer(&nbdkit->flags, virBitmapFree);
+
+ G_OBJECT_CLASS(qemu_nbdkit_caps_parent_class)->finalize(object);
+}
+
+
+void qemu_nbdkit_caps_init(qemuNbdkitCaps *caps)
+{
+ caps->flags = virBitmapNew(QEMU_NBDKIT_CAPS_LAST);
+ caps->version = NULL;
+}
+
+
+static void
+qemu_nbdkit_caps_class_init(qemuNbdkitCapsClass *klass)
+{
+ GObjectClass *obj = G_OBJECT_CLASS(klass);
+
+ obj->finalize = qemuNbdkitCapsFinalize;
+}
+
+
+qemuNbdkitCaps *
+qemuNbdkitCapsNew(const char *path)
+{
+ qemuNbdkitCaps *caps = g_object_new(QEMU_TYPE_NBDKIT_CAPS, NULL);
+ caps->path = g_strdup(path);
+
+ return caps;
+}
+
+
+static void
+qemuNbdkitCapsQuery(qemuNbdkitCaps *caps)
+{
+ qemuNbdkitCapsQueryPlugins(caps);
+ qemuNbdkitCapsQueryFilters(caps);
+ qemuNbdkitCapsQueryVersion(caps);
+}
+
+
+qemuNbdkitCaps *
+qemuQueryNbdkitCaps(void)
+{
+ qemuNbdkitCaps *caps = NULL;
+ g_autofree char *path = virFindFileInPath("nbdkit");
+
+ if (!path)
+ return NULL;
+
+ if (!virFileIsExecutable(path)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, _("nbdkit '%s' is not
executable"),
+ path);
+ return NULL;
+ }
+
+ VIR_DEBUG("found nbdkit executable '%s'", path);
+
+ caps = qemuNbdkitCapsNew(path);
+ qemuNbdkitCapsQuery(caps);
+
+ return caps;
+}
+
+
+bool
+qemuNbdkitCapsGet(qemuNbdkitCaps *nbdkitCaps,
+ qemuNbdkitCapsFlags flag)
+{
+ return virBitmapIsBitSet(nbdkitCaps->flags, flag);
+}
+
+
+void
+qemuNbdkitCapsSet(qemuNbdkitCaps *nbdkitCaps,
+ qemuNbdkitCapsFlags flag)
+{
+ ignore_value(virBitmapSetBit(nbdkitCaps->flags, flag));
+}
diff --git a/src/qemu/qemu_nbdkit.h b/src/qemu/qemu_nbdkit.h
new file mode 100644
index 0000000000..4baf4d4d31
--- /dev/null
+++ b/src/qemu/qemu_nbdkit.h
@@ -0,0 +1,51 @@
+/*
+ * qemu_nbdkit.h: helpers for using nbdkit
+ *
+ * Copyright (C) 2021 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <
http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include "internal.h"
+#include "virbitmap.h"
+#include "vircgroup.h"
+#include "vircommand.h"
+#include "virstorageobj.h"
+#include "viruri.h"
+
+typedef struct _qemuNbdkitCaps qemuNbdkitCaps;
+
+typedef enum {
+ QEMU_NBDKIT_CAPS_PLUGIN_CURL,
+ QEMU_NBDKIT_CAPS_PLUGIN_SSH,
+ QEMU_NBDKIT_CAPS_FILTER_READAHEAD,
+ QEMU_NBDKIT_CAPS_LAST,
+} qemuNbdkitCapsFlags;
+
+VIR_ENUM_DECL(qemuNbdkitCaps);
+
+qemuNbdkitCaps* qemuQueryNbdkitCaps(void);
+
+qemuNbdkitCaps* qemuNbdkitCapsNew(const char *path);
+
+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);
--
2.37.1