Using libblkio (https://libblkio.gitlab.io/) this implements a plugin
for reading and writing various disk sources mainly used in
virtualization and other high performance cases. These include: NVMe,
vhost-user, vhost-vdpa and VFIO PCI.
Note the current implementation uses the simplest libblkio API mode
(blocking) and so it is not suitable for high performance access.
---
plugins/blkio/nbdkit-blkio-plugin.pod | 117 +++++++++++
configure.ac | 20 ++
plugins/blkio/Makefile.am | 80 ++++++++
plugins/blkio/blkio.c | 270 ++++++++++++++++++++++++++
README.md | 4 +
TODO | 7 +
6 files changed, 498 insertions(+)
diff --git a/plugins/blkio/nbdkit-blkio-plugin.pod
b/plugins/blkio/nbdkit-blkio-plugin.pod
new file mode 100644
index 000000000..c76784687
--- /dev/null
+++ b/plugins/blkio/nbdkit-blkio-plugin.pod
@@ -0,0 +1,117 @@
+=head1 NAME
+
+nbdkit-blkio-plugin - libblkio plugin for NVMe, vhost-user, vDPA, VFIO
+
+=head1 SYNOPSIS
+
+ nbdkit blkio [driver=]DRIVER [path=FILENAME] [num-queues=N] ...
+
+=head1 DESCRIPTION
+
+nbdkit-blkio-plugin is an L<nbdkit(1)> plugin for using
+L<libblkio|https://libblkio.gitlab.io/> to access various disk sources
+used for high performance applications and virtualization. These
+include: NVMe, vhost-user, vDPA and VFIO.
+
+The first parameter after the plugin name should be the L<libblkio
+driver|https://libblkio.gitlab.io/libblkio/blkio.html#drivers>. For
+example:
+
+ nbdkit blkio virtio-blk-vhost-user path=vhost.sock
+
+=head2 Driver: C<nvme-io_uring>
+
+ nbdkit blkio nvme-io_uring path=/dev/ng0n1
+
+Connect to an NVMe device, issuing commands through Linux io_uring
+(requires Linux E<ge> 5.19).
+
+=head2 Driver: C<virtio-blk-vfio-pci>
+
+ nbdkit blkio virtio-blk-vfio-pci path=/sys/bus/pci/devices/0000:00:01.0
+
+Connect to a PCI device which implements virtio-blk using VFIO. The
+path is the path to the device's sysfs directory (see L<lspci(8)>).
+
+=head2 Driver: C<virtio-blk-vhost-user>
+
+ nbdkit blkio virtio-blk-vhost-user path=vhost.sock
+
+Connect to a vhost-user-blk device, such as one exported by
+L<qemu-storage-daemon(1)>. The path is the vhost-user Unix domain
+socket.
+
+=head2 Driver: C<virtio-blk-vhost-vdpa>
+
+ nbdkit blkio virtio-blk-vhost-vdpa path=chardev
+
+Connect to a vDPA device which might be implemented in software
+(eg. VDUSE) or hardware. The path is the vhost-vdpa character device.
+
+=head2 Driver: C<io_uring>
+
+ nbdkit blkio io_uring path=FILENAME
+
+You can use this driver to access local files and block devices
+through the libblkio C<io_uring> driver, but it is usually better and
+easier to use L<nbdkit-file-plugin(1)>.
+
+=head1 PARAMETERS
+
+=over 4
+
+=item [B<driver=>]DRIVER
+
+The name of the libblkio driver to use.
+
+This parameter is required.
+
+C<driver=> is a magic config key and may be omitted in most cases.
+See L<nbdkit(1)/Magic parameters>.
+
+=item PROPERTYB<=>VALUE
+
+Properties such as C<path>, C<num-entries> etc are translated to
+libblkio properties. Consult the L<libblkio
+documentation|https://libblkio.gitlab.io/libblkio/blkio.html> for a
+complete list.
+
+=item B<get=>PROPERTY
+
+Get (print) the value of a property after connecting. The property is
+fetched and printed in nbdkit debug output, so you will need to use
+the I<--verbose> flag. This is useful for debugging.
+
+=back
+
+=head1 FILES
+
+=over 4
+
+=item F<$plugindir/nbdkit-blkio-plugin.so>
+
+The plugin.
+
+Use C<nbdkit --dump-config> to find the location of C<$plugindir>.
+
+=back
+
+=head1 VERSION
+
+C<nbdkit-blkio-plugin> first appeared in nbdkit 1.34.
+
+=head1 SEE ALSO
+
+L<nbdkit-file-plugin(1)>,
+L<lspci(8)>,
+L<qemu-storage-daemon(1)>,
+L<https://libblkio.gitlab.io>,
+L<https://libblkio.gitlab.io/libblkio/blkio.html>.
+
+=head1 AUTHORS
+
+Richard W.M. Jones
+
+=head1 COPYRIGHT
+
+Copyright (C) 2014-2023 Red Hat Inc.
diff --git a/configure.ac b/configure.ac
index e03374b12..6afeac38e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -74,6 +74,7 @@ lang_plugins="\
tcl \
"
non_lang_plugins="\
+ blkio \
cdi \
curl \
data \
@@ -1094,6 +1095,23 @@ AS_IF([test "x$enable_golang" !=
"xno"],[
],[GOLANG=no])
AM_CONDITIONAL([HAVE_GOLANG],[test "x$GOLANG" != "xno"])
+dnl Check for libblkio (only if you want to compile the blkio plugin).
+AC_ARG_WITH([libblkio],
+ [AS_HELP_STRING([--without-libblkio],
+ [disable blkio plugin @<:@default=check@:>@])],
+ [],
+ [with_libblkio=check])
+AS_IF([test "$with_libblkio" != "no"],[
+ PKG_CHECK_MODULES([LIBBLKIO], [blkio],[
+ printf "libblkio version is "; $PKG_CONFIG --modversion blkio
+ AC_SUBST([LIBBLKIO_CFLAGS])
+ AC_SUBST([LIBBLKIO_LIBS])
+ AC_DEFINE([HAVE_LIBBLKIO],[1],[libblkio found at compile time.])
+ ],
+ [AC_MSG_WARN([libblkio not found, blkio plugin will be disabled])])
+])
+AM_CONDITIONAL([HAVE_LIBBLKIO],[test "x$LIBBLKIO_LIBS" !=
"x"])
+
dnl Check for curl (only if you want to compile the curl plugin).
AC_ARG_WITH([curl],
[AS_HELP_STRING([--without-curl],
@@ -1402,6 +1420,7 @@ AC_CONFIG_FILES([Makefile
include/Makefile
include/nbdkit-version.h
plugins/Makefile
+ plugins/blkio/Makefile
plugins/cc/Makefile
plugins/cdi/Makefile
plugins/curl/Makefile
@@ -1533,6 +1552,7 @@ feature "TLS" test
"x$GNUTLS_LIBS" != "x"
echo
echo "Optional plugins:"
echo
+feature "blkio" test "x$HAVE_LIBBLKIO_TRUE" =
"x"
feature "curl" test "x$HAVE_CURL_TRUE" =
"x"
feature "example4" test "x$HAVE_PERL_TRUE" =
"x"
feature "floppy" test "x$HAVE_ICONV_TRUE" =
"x"
diff --git a/plugins/blkio/Makefile.am b/plugins/blkio/Makefile.am
new file mode 100644
index 000000000..dbedcc2eb
--- /dev/null
+++ b/plugins/blkio/Makefile.am
@@ -0,0 +1,80 @@
+# nbdkit
+# Copyright (C) 2014-2023 Red Hat Inc.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# * Neither the name of Red Hat nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS
IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+
+include $(top_srcdir)/common-rules.mk
+
+EXTRA_DIST = nbdkit-blkio-plugin.pod
+
+if HAVE_LIBBLKIO
+
+plugin_LTLIBRARIES = nbdkit-blkio-plugin.la
+
+nbdkit_blkio_plugin_la_SOURCES = \
+ blkio.c \
+ $(top_srcdir)/include/nbdkit-plugin.h \
+ $(NULL)
+
+nbdkit_blkio_plugin_la_CPPFLAGS = \
+ -I$(top_srcdir)/include \
+ -I$(top_builddir)/include \
+ -I$(top_srcdir)/common/utils \
+ $(NULL)
+nbdkit_blkio_plugin_la_CFLAGS = \
+ $(WARNINGS_CFLAGS) \
+ $(LIBBLKIO_CFLAGS) \
+ $(NULL)
+nbdkit_blkio_plugin_la_LIBADD = \
+ $(top_builddir)/common/utils/libutils.la \
+ $(IMPORT_LIBRARY_ON_WINDOWS) \
+ $(LIBBLKIO_LIBS) \
+ $(NULL)
+nbdkit_blkio_plugin_la_LDFLAGS = \
+ -module -avoid-version -shared $(NO_UNDEFINED_ON_WINDOWS) \
+ $(NULL)
+if USE_LINKER_SCRIPT
+nbdkit_blkio_plugin_la_LDFLAGS += \
+ -Wl,--version-script=$(top_srcdir)/plugins/plugins.syms
+endif
+
+if HAVE_POD
+
+man_MANS = nbdkit-blkio-plugin.1
+CLEANFILES += $(man_MANS)
+
+nbdkit-blkio-plugin.1: nbdkit-blkio-plugin.pod \
+ $(top_builddir)/podwrapper.pl
+ $(PODWRAPPER) --section=1 --man $@ \
+ --html $(top_builddir)/html/$@.html \
+ $<
+
+endif HAVE_POD
+
+endif
diff --git a/plugins/blkio/blkio.c b/plugins/blkio/blkio.c
new file mode 100644
index 000000000..058850f63
--- /dev/null
+++ b/plugins/blkio/blkio.c
@@ -0,0 +1,270 @@
+/* nbdkit
+ * Copyright (C) 2014-2023 Red Hat Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of Red Hat nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS
IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <errno.h>
+
+#include <blkio.h>
+
+#define NBDKIT_API_VERSION 2
+#include <nbdkit-plugin.h>
+
+#include "vector.h"
+#include "const-string-vector.h"
+
+/* libblkio could do parallel, but we would need to reimplement this
+ * plugin to use the libblkio event model.
+ */
+#define THREAD_MODEL NBDKIT_THREAD_MODEL_SERIALIZE_ALL_REQUESTS
+
+struct property {
+ const char *name;
+ const char *value;
+};
+DEFINE_VECTOR_TYPE(properties, struct property)
+
+static const char *driver = NULL; /* driver name - required */
+static properties props = empty_vector; /* other command line params */
+static const_string_vector gets = empty_vector; /* get= parameters */
+
+static void
+bio_unload (void)
+{
+ properties_reset (&props);
+ const_string_vector_reset (&gets);
+}
+
+/* Called for each key=value passed on the command line. */
+static int
+bio_config (const char *key, const char *value)
+{
+ if (strcmp (key, "driver") == 0) {
+ if (driver != NULL) {
+ nbdkit_error ("'driver' property set more than once");
+ return -1;
+ }
+ driver = value;
+ }
+ else if (strcmp (key, "get") == 0) {
+ if (const_string_vector_append (&gets, value) == -1)
+ return -1;
+ }
+ else if (strcmp (key, "read-only") == 0) {
+ nbdkit_error ("do not set the libblkio \"read-only\"
parameter, "
+ "use the nbdkit -r flag if read-only is required");
+ return -1;
+ }
+ else /* general property */ {
+ struct property prop = { .name = key, .value = value };
+ if (properties_append (&props, prop) == -1)
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Check the user did pass a driver parameter. */
+static int
+bio_config_complete (void)
+{
+ if (driver == NULL) {
+ nbdkit_error ("you must supply the driver=<DRIVER> parameter
"
+ "after the plugin name on the command line");
+ return -1;
+ }
+
+ return 0;
+}
+
+#define bio_config_help \
+ "driver=<DRIVER> (required) Driver name (eg.
\"nvme-io_uring\").\n" \
+ "PROPERTY=VALUE Set arbitrary libblkio property.\n" \
+ "get=PROPERTY Print property name after connection."
+
+/* XXX Should be possible to query this from libblkio. */
+static bool
+is_preconnect_property (const char *name)
+{
+ return strcmp (name, "can-add-queues") == 0 ||
+ strcmp (name, "driver") == 0 ||
+ strcmp (name, "fd") == 0 ||
+ strcmp (name, "path") == 0 ||
+ strcmp (name, "read-only") == 0;
+}
+
+/* Create the per-connection handle. */
+static void *
+bio_open (int readonly)
+{
+ struct blkio *b;
+ size_t i;
+
+ errno = blkio_create (driver, &b);
+ if (errno != 0) {
+ nbdkit_error ("blkio_create: error opening driver: %s: %m",
driver);
+ return NULL;
+ }
+
+ /* Always set the read-only property to a true or false value. */
+ errno = blkio_set_bool (b, "read-only", !!readonly);
+ if (errno != 0) {
+ nbdkit_error ("error setting property: read-only=%s: %m",
+ readonly ? "true" : "false");
+ blkio_destroy (&b);
+ return NULL;
+ }
+
+ /* Set the pre-connect properties. */
+ for (i = 0; i < props.len; ++i) {
+ const struct property *prop = &props.ptr[i];
+
+ if (is_preconnect_property (prop->name)) {
+ errno = blkio_set_str (b, prop->name, prop->value);
+ if (errno != 0) {
+ nbdkit_error ("error setting property: %s=%s: %m",
+ prop->name, prop->value);
+ blkio_destroy (&b);
+ return NULL;
+ }
+ }
+ }
+
+ /* Connect. */
+ errno = blkio_connect (b);
+ if (errno != 0) {
+ nbdkit_error ("blkio_connect: failed to connect to device: %m");
+ blkio_destroy (&b);
+ return NULL;
+ }
+
+ /* Set the post-connect properties. */
+ for (i = 0; i < props.len; ++i) {
+ const struct property *prop = &props.ptr[i];
+
+ if (! is_preconnect_property (prop->name)) {
+ errno = blkio_set_str (b, prop->name, prop->value);
+ if (errno != 0) {
+ nbdkit_error ("error setting property: %s=%s: %m",
+ prop->name, prop->value);
+ blkio_destroy (&b);
+ return NULL;
+ }
+ }
+ }
+
+ /* Start the block device. */
+ errno = blkio_start (b);
+ if (errno != 0) {
+ nbdkit_error ("blkio_start: failed to start device: %m");
+ blkio_destroy (&b);
+ return NULL;
+ }
+
+ /* Print any properties requested on the command line. */
+ for (i = 0; i < gets.len; ++i) {
+ const char *name = gets.ptr[i];
+ char *value = NULL;
+
+ if (blkio_get_str (b, name, &value) == 0)
+ nbdkit_debug ("get %s = %s", name, value);
+ else
+ nbdkit_debug ("could not get property %s: %m", name);
+ free (value);
+ }
+
+ return b;
+}
+
+/* Close the handle. */
+static void
+bio_close (void *handle)
+{
+ struct blkio *b = handle;
+
+ blkio_destroy (&b);
+}
+
+/* Get the device size. */
+static int64_t
+bio_get_size (void *handle)
+{
+ struct blkio *b = handle;
+ uint64_t r;
+
+ errno = blkio_get_uint64 (b, "capacity", &r);
+ if (errno != 0) {
+ nbdkit_error ("error reading device capacity: %m");
+ return -1;
+ }
+
+ return r;
+}
+
+/* Read data from the device. */
+static int
+bio_pread (void *handle, void *buf, uint32_t count, uint64_t offset,
+ uint32_t flags)
+{
+ nbdkit_error ("XXX NOT IMPL XXX");
+ return -1;
+}
+
+/* Write data to the device. */
+static int
+bio_pwrite (void *handle, const void *buf, uint32_t count, uint64_t offset,
+ uint32_t flags)
+{
+ nbdkit_error ("XXX NOT IMPL XXX");
+ return -1;
+}
+
+static struct nbdkit_plugin plugin = {
+ .name = "blkio",
+ .version = PACKAGE_VERSION,
+ .unload = bio_unload,
+ .config = bio_config,
+ .config_complete = bio_config_complete,
+ .config_help = bio_config_help,
+ .magic_config_key = "driver",
+ .open = bio_open,
+ .close = bio_close,
+ .get_size = bio_get_size,
+ .pread = bio_pread,
+ .pwrite = bio_pwrite,
+ .errno_is_preserved = 1,
+};
+
+NBDKIT_REGISTER_PLUGIN(plugin)
diff --git a/README.md b/README.md
index eff94379b..a204ccf39 100644
--- a/README.md
+++ b/README.md
@@ -118,6 +118,10 @@ For the bittorrent plugin:
* [libtorrent-rasterbar](https://www.libtorrent.org)
+For the blkio plugin:
+
+* [libblkio](https://libblkio.gitlab.io/)
+
For the containerized data importer (CDI) plugin:
* podman
diff --git a/TODO b/TODO
index feeb09289..d4c85df9b 100644
--- a/TODO
+++ b/TODO
@@ -155,6 +155,13 @@ nbdkit-cdi-plugin:
* Look at using skopeo instead of podman pull
(https://github.com/containers/skopeo)
+nbdkit-blkio-plugin:
+
+* Use event-driven mode instead of blocking mode. This involves
+ restructuring the plugin so that there is one or more background
+ threads to handle the events, and nbdkit threads issue requests to
+ these threads. (See how it is done in the VDDK plugin.)
+
Suggestions for language plugins
--------------------------------
--
2.37.3