libblockdev/0001-nvdim-plugin.patch
2018-04-11 12:20:44 +02:00

1686 lines
58 KiB
Diff

From b0b6f77b3c75ca881bf21771f629c0716378ece2 Mon Sep 17 00:00:00 2001
From: Vojtech Trefny <vtrefny@redhat.com>
Date: Mon, 29 Jan 2018 13:56:17 +0100
Subject: [PATCH 1/4] Add the NVDIMM plugin
Add a new plugin for working with the NVDIMM devices. Currently
only namespace management is supported.
---
Makefile.am | 1 +
configure.ac | 6 +
dist/libblockdev.spec.in | 48 +++-
docs/libblockdev-docs.xml.in | 1 +
docs/libblockdev-sections.txt | 22 ++
src/lib/Makefile.am | 3 +-
src/lib/blockdev.c.in | 14 +-
src/lib/plugin_apis/nvdimm.api | 206 ++++++++++++++
src/lib/plugins.h | 1 +
src/plugins/Makefile.am | 16 ++
src/plugins/nvdimm.c | 544 ++++++++++++++++++++++++++++++++++++
src/plugins/nvdimm.h | 76 +++++
src/python/gi/overrides/BlockDev.py | 43 +++
13 files changed, 977 insertions(+), 4 deletions(-)
create mode 100644 src/lib/plugin_apis/nvdimm.api
create mode 100644 src/plugins/nvdimm.c
create mode 100644 src/plugins/nvdimm.h
diff --git a/Makefile.am b/Makefile.am
index ad41c1b..d30acd1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -41,6 +41,7 @@ PLUGINS = btrfs \
lvm \
mdraid \
mpath \
+ nvdimm \
part \
s390 \
swap
diff --git a/configure.ac b/configure.ac
index d41a307..4206afa 100644
--- a/configure.ac
+++ b/configure.ac
@@ -141,6 +141,7 @@ LIBBLOCKDEV_PLUGIN([SWAP], [swap])
LIBBLOCKDEV_PLUGIN([KBD], [kbd])
LIBBLOCKDEV_PLUGIN([PART], [part])
LIBBLOCKDEV_PLUGIN([FS], [fs])
+LIBBLOCKDEV_PLUGIN([NVDIMM], [nvdimm])
AM_CONDITIONAL(WITH_PART_O_WITH_FS, test "x$with_part" != "xno" -o "x$with_fs" != "xno")
@@ -194,6 +195,11 @@ AS_IF([test "x$with_btrfs" != "xno" -o "x$with_mdraid" != "xno" -o "x$with_kbd"
[LIBBLOCKDEV_PKG_CHECK_MODULES([BYTESIZE], [bytesize >= 0.1])],
[])
+AS_IF([test "x$with_nvdimm" != "xno"],
+ [LIBBLOCKDEV_PKG_CHECK_MODULES([UUID], [uuid])
+ LIBBLOCKDEV_PKG_CHECK_MODULES([NDCTL], [libndctl])]
+ [])
+
AC_SUBST([skip_patterns], [$skip_patterns])
AC_SUBST([MAJOR_VER], [\"2\"])
diff --git a/dist/libblockdev.spec.in b/dist/libblockdev.spec.in
index b23bb5b..5e2f52b 100644
--- a/dist/libblockdev.spec.in
+++ b/dist/libblockdev.spec.in
@@ -13,6 +13,7 @@
%define with_kbd @WITH_KBD@
%define with_part @WITH_PART@
%define with_fs @WITH_FS@
+%define with_nvdimm @WITH_NVDIMM@
%define with_gi @WITH_GI@
# python3 is not available on older RHEL
@@ -59,11 +60,14 @@
%if %{with_fs} != 1
%define fs_copts --without-fs
%endif
+%if %{with_nvdimm} != 1
+%define nvdimm_copts --without-nvdimm
+%endif
%if %{with_gi} != 1
%define gi_copts --disable-introspection
%endif
-%define configure_opts %{?distro_copts} %{?btrfs_copts} %{?crypto_copts} %{?dm_copts} %{?loop_copts} %{?lvm_copts} %{?lvm_dbus_copts} %{?mdraid_copts} %{?mpath_copts} %{?swap_copts} %{?kbd_copts} %{?part_copts} %{?fs_copts} %{?gi_copts}
+%define configure_opts %{?distro_copts} %{?btrfs_copts} %{?crypto_copts} %{?dm_copts} %{?loop_copts} %{?lvm_copts} %{?lvm_dbus_copts} %{?mdraid_copts} %{?mpath_copts} %{?swap_copts} %{?kbd_copts} %{?part_copts} %{?fs_copts} %{?nvdimm_copts} %{?gi_copts}
Name: libblockdev
Version: 2.16
@@ -394,6 +398,29 @@ This package contains header files and pkg-config files needed for development
with the libblockdev-mpath plugin/library.
%endif
+%if %{with_nvdimm}
+%package nvdimm
+BuildRequires: ndctl-devel
+BuildRequires: libuuid-devel
+Summary: The NVDIMM plugin for the libblockdev library
+Requires: %{name}-utils%{?_isa} >= 0.11
+Requires: ndctl
+
+%description nvdimm
+The libblockdev library plugin (and in the same time a standalone library)
+providing the functionality related to operations with NVDIMM devices.
+
+%package nvdimm-devel
+Summary: Development files for the libblockdev-nvdimm plugin/library
+Requires: %{name}-nvdimm%{?_isa} = %{version}-%{release}
+Requires: %{name}-utils-devel%{?_isa}
+Requires: glib2-devel
+
+%description nvdimm-devel
+This package contains header files and pkg-config files needed for development
+with the libblockdev-nvdimm plugin/library.
+%endif
+
%if %{with_part}
%package part
@@ -502,6 +529,10 @@ Requires: %{name}-mdraid%{?_isa} = %{version}-%{release}
Requires: %{name}-mpath%{?_isa} = %{version}-%{release}
%endif
+%if %{with_nvdimm}
+Requires: %{name}-nvdimm%{?_isa} = %{version}-%{release}
+%endif
+
%if %{with_part}
Requires: %{name}-part%{?_isa} = %{version}-%{release}
%endif
@@ -580,6 +611,10 @@ find %{buildroot} -type f -name "*.la" | xargs %{__rm}
%postun mpath -p /sbin/ldconfig
%endif
+%if %{with_nvdimm}
+%ldconfig_scriptlets nvdimm
+%endif
+
%if %{with_part}
%post part -p /sbin/ldconfig
%postun part -p /sbin/ldconfig
@@ -765,6 +800,17 @@ find %{buildroot} -type f -name "*.la" | xargs %{__rm}
%endif
+%if %{with_nvdimm}
+%files nvdimm
+%{_libdir}/libbd_nvdimm.so.*
+
+%files nvdimm-devel
+%{_libdir}/libbd_nvdimm.so
+%dir %{_includedir}/blockdev
+%{_includedir}/blockdev/nvdimm.h
+%endif
+
+
%if %{with_part}
%files part
%{_libdir}/libbd_part.so.*
diff --git a/docs/libblockdev-docs.xml.in b/docs/libblockdev-docs.xml.in
index a758657..98aa0bf 100644
--- a/docs/libblockdev-docs.xml.in
+++ b/docs/libblockdev-docs.xml.in
@@ -29,6 +29,7 @@
<xi:include href="xml/lvm.xml"/>
<xi:include href="xml/mdraid.xml"/>
<xi:include href="xml/mpath.xml"/>
+ <xi:include href="xml/nvdimm.xml"/>
<xi:include href="xml/plugins.xml"/>
<xi:include href="xml/part.xml"/>
<xi:include href="xml/swap.xml"/>
diff --git a/docs/libblockdev-sections.txt b/docs/libblockdev-sections.txt
index cc0ae7a..756b5b5 100644
--- a/docs/libblockdev-sections.txt
+++ b/docs/libblockdev-sections.txt
@@ -565,3 +565,25 @@ BDS390Tech
BDS390TechMode
bd_s390_is_tech_avail
</SECTION>
+
+<SECTION>
+<FILE>nvdimm</FILE>
+bd_nvdimm_check_deps
+bd_nvdimm_close
+bd_nvdimm_init
+bd_nvdimm_error_quark
+BD_NVDIMM_ERROR
+BDNVDIMMError
+BDNVDIMMNamespaceMode
+BDNVDIMMNamespaceInfo
+bd_nvdimm_namespace_get_mode_from_str
+bd_nvdimm_namespace_get_mode_str
+bd_nvdimm_namespace_enable
+bd_nvdimm_namespace_disable
+bd_nvdimm_namespace_info
+bd_nvdimm_list_namespaces
+bd_nvdimm_namespace_reconfigure
+BDNVDIMMTech
+BDNVDIMMTechMode
+bd_nvdimm_is_tech_avail
+</SECTION>
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index e020703..d9a91ca 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -30,7 +30,8 @@ GIHEADERS = ${builddir}/plugin_apis/kbd.h \
${builddir}/plugin_apis/loop.h \
${builddir}/plugin_apis/mpath.h \
${builddir}/plugin_apis/part.h \
- ${builddir}/plugin_apis/fs.h
+ ${builddir}/plugin_apis/fs.h \
+ ${builddir}/plugin_apis/nvdimm.h
GIHEADERS += $(wildcard ${srcdir}/../utils/*.[ch])
GIHEADERS += blockdev.c blockdev.h plugins.c plugins.h
diff --git a/src/lib/blockdev.c.in b/src/lib/blockdev.c.in
index 2aeeac2..fd36fee 100644
--- a/src/lib/blockdev.c.in
+++ b/src/lib/blockdev.c.in
@@ -25,6 +25,8 @@
#include "plugin_apis/part.c"
#include "plugin_apis/fs.h"
#include "plugin_apis/fs.c"
+#include "plugin_apis/nvdimm.h"
+#include "plugin_apis/nvdimm.c"
#if defined(__s390__) || defined(__s390x__)
#include "plugin_apis/s390.h"
@@ -59,7 +61,8 @@ static gchar * default_plugin_so[BD_PLUGIN_UNDEF] = {
"libbd_crypto.so."@MAJOR_VER@, "libbd_mpath.so."@MAJOR_VER@,
"libbd_dm.so."@MAJOR_VER@, "libbd_mdraid.so."@MAJOR_VER@,
"libbd_kbd.so."@MAJOR_VER@,"libbd_s390.so."@MAJOR_VER@,
- "libbd_part.so."@MAJOR_VER@, "libbd_fs.so."@MAJOR_VER@
+ "libbd_part.so."@MAJOR_VER@, "libbd_fs.so."@MAJOR_VER@,
+ "libbd_nvdimm.so."@MAJOR_VER@
};
static BDPluginStatus plugins[BD_PLUGIN_UNDEF] = {
{{BD_PLUGIN_LVM, NULL}, NULL},
@@ -74,9 +77,10 @@ static BDPluginStatus plugins[BD_PLUGIN_UNDEF] = {
{{BD_PLUGIN_S390, NULL}, NULL},
{{BD_PLUGIN_PART, NULL}, NULL},
{{BD_PLUGIN_FS, NULL}, NULL},
+ {{BD_PLUGIN_NVDIMM, NULL}, NULL},
};
static gchar* plugin_names[BD_PLUGIN_UNDEF] = {
- "lvm", "btrfs", "swap", "loop", "crypto", "mpath", "dm", "mdraid", "kbd", "s390", "part", "fs"
+ "lvm", "btrfs", "swap", "loop", "crypto", "mpath", "dm", "mdraid", "kbd", "s390", "part", "fs", "nvdimm"
};
static void set_plugin_so_name (BDPlugin name, const gchar *so_name) {
@@ -226,6 +230,10 @@ static void unload_plugins () {
if (plugins[BD_PLUGIN_FS].handle && !unload_fs (plugins[BD_PLUGIN_FS].handle))
g_warning ("Failed to close the fs plugin");
plugins[BD_PLUGIN_FS].handle = NULL;
+
+ if (plugins[BD_PLUGIN_NVDIMM].handle && !unload_nvdimm (plugins[BD_PLUGIN_NVDIMM].handle))
+ g_warning ("Failed to close the nvdimm plugin");
+ plugins[BD_PLUGIN_NVDIMM].handle = NULL;
}
static void load_plugin_from_sonames (BDPlugin plugin, LoadFunc load_fn, void **handle, GSList *sonames) {
@@ -264,6 +272,8 @@ static void do_load (GSList **plugins_sonames) {
load_plugin_from_sonames (BD_PLUGIN_PART, load_part_from_plugin, &(plugins[BD_PLUGIN_PART].handle), plugins_sonames[BD_PLUGIN_PART]);
if (!plugins[BD_PLUGIN_FS].handle && plugins_sonames[BD_PLUGIN_FS])
load_plugin_from_sonames (BD_PLUGIN_FS, load_fs_from_plugin, &(plugins[BD_PLUGIN_FS].handle), plugins_sonames[BD_PLUGIN_FS]);
+ if (!plugins[BD_PLUGIN_NVDIMM].handle && plugins_sonames[BD_PLUGIN_NVDIMM])
+ load_plugin_from_sonames (BD_PLUGIN_NVDIMM, load_nvdimm_from_plugin, &(plugins[BD_PLUGIN_NVDIMM].handle), plugins_sonames[BD_PLUGIN_NVDIMM]);
}
static gboolean load_plugins (BDPluginSpec **require_plugins, gboolean reload, guint64 *num_loaded) {
diff --git a/src/lib/plugin_apis/nvdimm.api b/src/lib/plugin_apis/nvdimm.api
new file mode 100644
index 0000000..3d74f62
--- /dev/null
+++ b/src/lib/plugin_apis/nvdimm.api
@@ -0,0 +1,206 @@
+#include <glib.h>
+#include <glib-object.h>
+#include <blockdev/utils.h>
+
+#ifndef BD_NVDIMM_API
+#define BD_NVDIMM_API
+
+GQuark bd_nvdimm_error_quark (void) {
+ return g_quark_from_static_string ("g-bd-nvdimm-error-quark");
+}
+
+#define BD_NVDIMM_ERROR bd_nvdimm_error_quark ()
+typedef enum {
+ BD_NVDIMM_ERROR_NAMESPACE_PARSE,
+ BD_NVDIMM_ERROR_NAMESPACE_FAIL,
+ BD_NVDIMM_ERROR_NAMESPACE_NOEXIST,
+ BD_NVDIMM_ERROR_NAMESPACE_MODE_INVAL
+} BDNVDIMMError;
+
+typedef enum {
+ BD_NVDIMM_NAMESPACE_MODE_RAW,
+ BD_NVDIMM_NAMESPACE_MODE_SECTOR,
+ BD_NVDIMM_NAMESPACE_MODE_MEMORY,
+ BD_NVDIMM_NAMESPACE_MODE_DAX,
+ BD_NVDIMM_NAMESPACE_MODE_UNKNOWN
+} BDNVDIMMNamespaceMode;
+
+#define BD_NVDIMM_TYPE_NAMESPACE_INFO (bd_nvdimm_namespace_info_get_type ())
+GType bd_nvdimm_namespace_info_get_type();
+
+/**
+ * BDNVDIMMNamespaceInfo:
+ * @dev: namespace device name ("namespaceX.Y")
+ * @mode: mode of the namespace (BDNVDIMMNamespaceMode)
+ * @size: size of the namespace
+ * @uuid: UUID of the namespace
+ * @sector_size: sector size of the namespace (0 for non-sector namespaces)
+ * @blockdev: name of the block device for the namespace
+ * @enabled: whether the namespace is enabled or not
+ */
+typedef struct BDNVDIMMNamespaceInfo {
+ gchar *dev;
+ guint64 mode;
+ guint64 size;
+ gchar *uuid;
+ guint64 sector_size;
+ gchar *blockdev;
+ gboolean enabled;
+} BDNVDIMMNamespaceInfo;
+
+/**
+ * bd_nvdimm_namespace_info_free: (skip)
+ *
+ * Frees @info.
+ */
+void bd_nvdimm_namespace_info_free (BDNVDIMMNamespaceInfo *info) {
+ g_free (info->dev);
+ g_free (info->uuid);
+ g_free (info->blockdev);
+ g_free (info);
+}
+
+/**
+ * bd_nvdimm_namespace_info_copy: (skip)
+ *
+ * Creates a new copy of @info.
+ */
+BDNVDIMMNamespaceInfo* bd_nvdimm_namespace_info_copy (BDNVDIMMNamespaceInfo *info) {
+ BDNVDIMMNamespaceInfo *new_info = g_new0 (BDNVDIMMNamespaceInfo, 1);
+
+ new_info->dev = info->dev;
+ new_info->mode = info->mode;
+ new_info->size = info->size;
+ new_info->uuid = g_strdup (info->uuid);
+ new_info->sector_size = info->sector_size;
+ new_info->blockdev = g_strdup (info->blockdev);
+ new_info->enabled = info->enabled;
+
+ return new_info;
+}
+
+GType bd_nvdimm_namespace_info_get_type () {
+ static GType type = 0;
+
+ if (G_UNLIKELY(type == 0)) {
+ type = g_boxed_type_register_static("BDNVDIMMNamespaceInfo",
+ (GBoxedCopyFunc) bd_nvdimm_namespace_info_copy,
+ (GBoxedFreeFunc) bd_nvdimm_namespace_info_free);
+ }
+
+ return type;
+}
+
+typedef enum {
+ BD_NVDIMM_TECH_NAMESPACE = 0,
+} BDNVDIMMTech;
+
+typedef enum {
+ BD_NVDIMM_TECH_MODE_CREATE = 1 << 0,
+ BD_NVDIMM_TECH_MODE_REMOVE = 1 << 1,
+ BD_NVDIMM_TECH_MODE_ACTIVATE_DEACTIVATE = 1 << 2,
+ BD_NVDIMM_TECH_MODE_QUERY = 1 << 3,
+ BD_NVDIMM_TECH_MODE_RECONFIGURE = 1 << 4,
+} BDNVDIMMTechMode;
+
+/**
+ * bd_nvdimm_is_tech_avail:
+ * @tech: the queried tech
+ * @mode: a bit mask of queried modes of operation (#BDNVDIMMTechMode) for @tech
+ * @error: (out): place to store error (details about why the @tech-@mode combination is not available)
+ *
+ * Returns: whether the @tech-@mode combination is available -- supported by the
+ * plugin implementation and having all the runtime dependencies available
+ */
+gboolean bd_nvdimm_is_tech_avail (BDNVDIMMTech tech, guint64 mode, GError **error);
+
+/**
+ * bd_nvdimm_namespace_get_mode_from_str:
+ * @mode_str: string representation of mode
+ * @error: (out): place to store error (if any)
+ *
+ * Returns: mode matching the @mode_str given or %BD_NVDIMM_NAMESPACE_MODE_UNKNOWN in case of no match
+ *
+ * Tech category: always available
+ */
+BDNVDIMMNamespaceMode bd_nvdimm_namespace_get_mode_from_str (const gchar *mode_str, GError **error);
+
+/**
+ * bd_nvdimm_namespace_get_mode_str:
+ * @mode: mode to get string representation of
+ * @error: (out): place to store error (if any)
+ *
+ * Returns: (transfer none): string representation of @mode or %NULL in case of error
+ *
+ * Tech category: always available
+ */
+const gchar* bd_nvdimm_namespace_get_mode_str (BDNVDIMMNamespaceMode mode, GError **error);
+
+/**
+ * bd_nvdimm_namespace_enable:
+ * @namespace: name of the namespace to enable
+ * @extra: (allow-none) (array zero-terminated=1): extra options (currently unused)
+ * @error: (out): place to store error (if any)
+ *
+ * Returns: whether the @namespace was successfully enabled or not
+ *
+ * Tech category: %BD_NVDIMM_TECH_NAMESPACE-%BD_NVDIMM_TECH_MODE_ACTIVATE_DEACTIVATE
+ */
+gboolean bd_nvdimm_namespace_enable (const gchar *namespace, const BDExtraArg **extra, GError **error);
+
+/**
+ * bd_nvdimm_namespace_disable:
+ * @namespace: name of the namespace to disable
+ * @extra: (allow-none) (array zero-terminated=1): extra options (currently unused)
+ * @error: (out): place to store error (if any)
+ *
+ * Returns: whether the @namespace was successfully disabled or not
+ *
+ * Tech category: %BD_NVDIMM_TECH_NAMESPACE-%BD_NVDIMM_TECH_MODE_ACTIVATE_DEACTIVATE
+ */
+gboolean bd_nvdimm_namespace_disable (const gchar *namespace, const BDExtraArg **extra, GError **error);
+
+/**
+ * bd_nvdimm_namespace_info:
+ * @namespace: namespace to get information about
+ * @extra: (allow-none) (array zero-terminated=1): extra options (currently unused)
+ * @error: (out): place to store error (if any)
+ *
+ * Returns: (transfer full): information about given namespace or %NULL if no such
+ * namespace was found (@error may be set to indicate error)
+ *
+ * Tech category: %BD_NVDIMM_TECH_NAMESPACE-%BD_NVDIMM_TECH_MODE_QUERY
+ */
+BDNVDIMMNamespaceInfo* bd_nvdimm_namespace_info (const gchar *namespace, const BDExtraArg **extra, GError **error);
+
+/**
+ * bd_nvdimm_list_namespaces:
+ * @bus: (allow-none): return only namespaces on given bus (specified by name),
+ * %NULL may be specified to return namespaces from all buses
+ * @region: (allow-none): return only namespaces on given region (specified by regionX name or region id),
+ * %NULL may be specified to return namespaces from all regions
+ * @idle: whether to list idle (not enabled) namespaces too
+ * @extra: (allow-none) (array zero-terminated=1): extra options for the creation (right now
+ * passed to the 'ndctl' utility)
+ * @error: (out): place to store error (if any)
+ *
+ * Returns: (array zero-terminated=1): information about the namespaces on @bus and @region or
+ * %NULL if no namespaces were found (@error may be set to indicate error)
+ *
+ * Tech category: %BD_NVDIMM_TECH_NAMESPACE-%BD_NVDIMM_TECH_MODE_QUERY
+ */
+BDNVDIMMNamespaceInfo** bd_nvdimm_list_namespaces (const gchar *bus, const gchar *region, gboolean idle, const BDExtraArg **extra, GError **error);
+
+/**
+ * bd_nvdimm_namespace_reconfigure:
+ * @namespace: name of the namespace to recofigure
+ * @mode: mode type to set (memory/sector/raw/dax)
+ * @error: (out): place to store error if any
+ * @extra: (allow-none) (array zero-terminated=1): extra options for the creation (right now
+ * passed to the 'ndctl' utility)
+ *
+ * Returns: whether @namespace was successfully reconfigured or not
+ */
+gboolean bd_nvdimm_namespace_reconfigure (const gchar* namespace, BDNVDIMMNamespaceMode mode, gboolean force, const BDExtraArg **extra, GError** error);
+
+#endif /* BD_NVDIMM_API */
diff --git a/src/lib/plugins.h b/src/lib/plugins.h
index 48d2217..9bc9799 100644
--- a/src/lib/plugins.h
+++ b/src/lib/plugins.h
@@ -17,6 +17,7 @@ typedef enum {
BD_PLUGIN_S390,
BD_PLUGIN_PART,
BD_PLUGIN_FS,
+ BD_PLUGIN_NVDIMM,
BD_PLUGIN_UNDEF
} BDPlugin;
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
index b69c8f7..d11bdca 100644
--- a/src/plugins/Makefile.am
+++ b/src/plugins/Makefile.am
@@ -36,6 +36,10 @@ if WITH_MPATH
lib_LTLIBRARIES += libbd_mpath.la
endif
+if WITH_NVDIMM
+lib_LTLIBRARIES += libbd_nvdimm.la
+endif
+
if WITH_SWAP
lib_LTLIBRARIES += libbd_swap.la
endif
@@ -122,6 +126,14 @@ libbd_mpath_la_CPPFLAGS = -I${builddir}/../../include/
libbd_mpath_la_SOURCES = mpath.c mpath.h check_deps.c check_deps.h
endif
+if WITH_NVDIMM
+libbd_nvdimm_la_CFLAGS = $(GLIB_CFLAGS) $(UUID_CFLAGS) $(NDCTL_CFLAGS) -Wall -Wextra -Werror
+libbd_nvdimm_la_LIBADD = $(GLIB_LIBS) $(UUID_LIBS) $(NDCTL_LIBS) ${builddir}/../utils/libbd_utils.la
+libbd_nvdimm_la_LDFLAGS = -L${srcdir}/../utils/ -version-info 2:0:0 -Wl,--no-undefined
+libbd_nvdimm_la_CPPFLAGS = -I${builddir}/../../include/
+libbd_nvdimm_la_SOURCES = nvdimm.c nvdimm.h check_deps.c check_deps.h
+endif
+
if WITH_SWAP
libbd_swap_la_CFLAGS = $(GLIB_CFLAGS) -Wall -Wextra -Werror
libbd_swap_la_LIBADD = $(GLIB_LIBS) ${builddir}/../utils/libbd_utils.la
@@ -194,6 +206,10 @@ if WITH_MPATH
libinclude_HEADERS += mpath.h
endif
+if WITH_NVDIMM
+libinclude_HEADERS += nvdimm.h
+endif
+
if WITH_SWAP
libinclude_HEADERS += swap.h
endif
diff --git a/src/plugins/nvdimm.c b/src/plugins/nvdimm.c
new file mode 100644
index 0000000..7a6802a
--- /dev/null
+++ b/src/plugins/nvdimm.c
@@ -0,0 +1,544 @@
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Vojtech Trefny <vtrefny@redhat.com>
+ */
+
+#include <glib.h>
+#include <blockdev/utils.h>
+#include <ndctl/libndctl.h>
+#include <uuid.h>
+#include <string.h>
+
+#include "nvdimm.h"
+#include "check_deps.h"
+
+/**
+ * SECTION: nvdimm
+ * @short_description: plugin for operations with nvdimm space
+ * @title: NVDIMM
+ * @include: nvdimm.h
+ *
+ * A plugin for operations with NVDIMM devices.
+ */
+
+/**
+ * bd_nvdimm_error_quark: (skip)
+ */
+GQuark bd_nvdimm_error_quark (void) {
+ return g_quark_from_static_string ("g-bd-nvdimm-error-quark");
+}
+
+void bd_nvdimm_namespace_info_free (BDNVDIMMNamespaceInfo *info) {
+ g_free (info->dev);
+ g_free (info->uuid);
+ g_free (info->blockdev);
+ g_free (info);
+}
+
+BDNVDIMMNamespaceInfo* bd_nvdimm_namespace_info_copy (BDNVDIMMNamespaceInfo *info) {
+ BDNVDIMMNamespaceInfo *new_info = g_new0 (BDNVDIMMNamespaceInfo, 1);
+
+ new_info->dev = g_strdup (info->dev);
+ new_info->mode = info->mode;
+ new_info->size = info->size;
+ new_info->uuid = g_strdup (info->uuid);
+ new_info->sector_size = info->sector_size;
+ new_info->blockdev = g_strdup (info->blockdev);
+ new_info->enabled = info->enabled;
+
+ return new_info;
+}
+
+
+static const gchar * const mode_str[BD_NVDIMM_NAMESPACE_MODE_UNKNOWN+1] = {"raw", "sector", "memory", "dax", "unknown"};
+
+static volatile guint avail_deps = 0;
+static GMutex deps_check_lock;
+
+#define DEPS_NDCTL 0
+#define DEPS_NDCTL_MASK (1 << DEPS_NDCTL)
+#define DEPS_LAST 1
+
+static UtilDep deps[DEPS_LAST] = {
+ {"ndctl", NULL, NULL, NULL},
+};
+
+/**
+ * bd_nvdimm_check_deps:
+ *
+ * Returns: whether the plugin's runtime dependencies are satisfied or not
+ *
+ * Function checking plugin's runtime dependencies.
+ *
+ */
+gboolean bd_nvdimm_check_deps () {
+ GError *error = NULL;
+ guint i = 0;
+ gboolean status = FALSE;
+ gboolean ret = TRUE;
+
+ for (i=0; i < DEPS_LAST; i++) {
+ status = bd_utils_check_util_version (deps[i].name, deps[i].version,
+ deps[i].ver_arg, deps[i].ver_regexp, &error);
+ if (!status)
+ g_warning ("%s", error->message);
+ else
+ g_atomic_int_or (&avail_deps, 1 << i);
+ g_clear_error (&error);
+ ret = ret && status;
+ }
+
+ if (!ret)
+ g_warning("Cannot load the NVDIMM plugin");
+
+ return ret;
+}
+
+/**
+ * bd_nvdimm_init:
+ *
+ * Initializes the plugin. **This function is called automatically by the
+ * library's initialization functions.**
+ *
+ */
+gboolean bd_nvdimm_init () {
+ /* nothing to do here */
+ return TRUE;
+}
+
+/**
+ * bd_nvdimm_close:
+ *
+ * Cleans up after the plugin. **This function is called automatically by the
+ * library's functions that unload it.**
+ *
+ */
+void bd_nvdimm_close () {
+ /* nothing to do here */
+ return;
+}
+
+#define UNUSED __attribute__((unused))
+
+/**
+ * bd_nvdimm_is_tech_avail:
+ * @tech: the queried tech
+ * @mode: a bit mask of queried modes of operation (#BDNVDIMMTechMode) for @tech
+ * @error: (out): place to store error (details about why the @tech-@mode combination is not available)
+ *
+ * Returns: whether the @tech-@mode combination is available -- supported by the
+ * plugin implementation and having all the runtime dependencies available
+ */
+gboolean bd_nvdimm_is_tech_avail (BDNVDIMMTech tech, guint64 mode, GError **error) {
+ /* all tech-mode combinations are supported by this implementation of the
+ plugin, namespace reconfigure requires the 'ndctl' utility */
+
+ if (tech == BD_NVDIMM_TECH_NAMESPACE) {
+ if (mode & BD_NVDIMM_TECH_MODE_RECONFIGURE)
+ return check_deps (&avail_deps, DEPS_NDCTL_MASK, deps, DEPS_LAST, &deps_check_lock, error);
+ else
+ return TRUE;
+ } else {
+ g_set_error (error, BD_NVDIMM_ERROR, BD_NVDIMM_ERROR_TECH_UNAVAIL, "Unknown technology");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ * bd_nvdimm_namespace_get_mode_from_str:
+ * @mode_str: string representation of mode
+ * @error: (out): place to store error (if any)
+ *
+ * Returns: mode matching the @mode_str given or %BD_NVDIMM_NAMESPACE_MODE_UNKNOWN in case of no match
+ *
+ * Tech category: always available
+ */
+BDNVDIMMNamespaceMode bd_nvdimm_namespace_get_mode_from_str (const gchar *mode_str, GError **error) {
+ if (g_strcmp0 (mode_str, "raw") == 0)
+ return BD_NVDIMM_NAMESPACE_MODE_RAW;
+ else if (g_strcmp0 (mode_str, "sector") == 0)
+ return BD_NVDIMM_NAMESPACE_MODE_SECTOR;
+ else if (g_strcmp0 (mode_str, "memory") == 0)
+ return BD_NVDIMM_NAMESPACE_MODE_MEMORY;
+ else if (g_strcmp0 (mode_str, "dax") == 0)
+ return BD_NVDIMM_NAMESPACE_MODE_DAX;
+ else {
+ g_set_error (error, BD_NVDIMM_ERROR, BD_NVDIMM_ERROR_NAMESPACE_MODE_INVAL,
+ "Invalid mode given: '%s'", mode_str);
+ return BD_NVDIMM_NAMESPACE_MODE_UNKNOWN;
+ }
+}
+
+/**
+ * bd_nvdimm_namespace_get_mode_str:
+ * @mode: mode to get string representation of
+ * @error: (out): place to store error (if any)
+ *
+ * Returns: (transfer none): string representation of @mode or %NULL in case of error
+ *
+ * Tech category: always available
+ */
+const gchar* bd_nvdimm_namespace_get_mode_str (BDNVDIMMNamespaceMode mode, GError **error) {
+ if (mode <= BD_NVDIMM_NAMESPACE_MODE_UNKNOWN)
+ return mode_str[mode];
+ else {
+ g_set_error (error, BD_NVDIMM_ERROR, BD_NVDIMM_ERROR_NAMESPACE_MODE_INVAL,
+ "Invalid mode given: %d", mode);
+ return NULL;
+ }
+}
+
+static struct ndctl_namespace* get_namespace_by_name (const gchar *namespace, struct ndctl_ctx *ctx) {
+ struct ndctl_namespace *ndns = NULL;
+ struct ndctl_region *region = NULL;
+ struct ndctl_bus *bus = NULL;
+
+ ndctl_bus_foreach (ctx, bus) {
+ ndctl_region_foreach (bus, region) {
+ ndctl_namespace_foreach (region, ndns) {
+ if (g_strcmp0 (namespace, ndctl_namespace_get_devname (ndns)) == 0)
+ return ndns;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * bd_nvdimm_namespace_enable:
+ * @namespace: name of the namespace to enable
+ * @extra: (allow-none) (array zero-terminated=1): extra options (currently unused)
+ * @error: (out): place to store error (if any)
+ *
+ * Returns: whether the @namespace was successfully enabled or not
+ *
+ * Tech category: %BD_NVDIMM_TECH_NAMESPACE-%BD_NVDIMM_TECH_MODE_ACTIVATE_DEACTIVATE
+ */
+gboolean bd_nvdimm_namespace_enable (const gchar *namespace, const BDExtraArg **extra UNUSED, GError **error) {
+ struct ndctl_ctx *ctx = NULL;
+ struct ndctl_namespace *ndns = NULL;
+ gint ret = 0;
+
+ ret = ndctl_new (&ctx);
+ if (ret != 0) {
+ g_set_error (error, BD_NVDIMM_ERROR, BD_NVDIMM_ERROR_NAMESPACE_FAIL,
+ "Failed to create ndctl context");
+ return FALSE;
+ }
+
+ ndns = get_namespace_by_name (namespace, ctx);
+ if (!ndns) {
+ g_set_error (error, BD_NVDIMM_ERROR, BD_NVDIMM_ERROR_NAMESPACE_NOEXIST,
+ "Failed to enable namespace: namespace '%s' not found.", namespace);
+ return FALSE;
+ }
+
+ ret = ndctl_namespace_enable (ndns);
+ if (ret < 0) {
+ g_set_error (error, BD_NVDIMM_ERROR, BD_NVDIMM_ERROR_NAMESPACE_FAIL,
+ "Failed to enable namespace: %s", strerror (-ret));
+ ndctl_unref (ctx);
+ return FALSE;
+ }
+
+ ndctl_unref (ctx);
+ return TRUE;
+}
+
+/**
+ * bd_nvdimm_namespace_disable:
+ * @namespace: name of the namespace to disable
+ * @extra: (allow-none) (array zero-terminated=1): extra options (currently unused)
+ * @error: (out): place to store error (if any)
+ *
+ * Returns: whether the @namespace was successfully disabled or not
+ *
+ * Tech category: %BD_NVDIMM_TECH_NAMESPACE-%BD_NVDIMM_TECH_MODE_ACTIVATE_DEACTIVATE
+ */
+gboolean bd_nvdimm_namespace_disable (const gchar *namespace, const BDExtraArg **extra UNUSED, GError **error) {
+ struct ndctl_ctx *ctx = NULL;
+ struct ndctl_namespace *ndns = NULL;
+ gint ret = 0;
+
+ ret = ndctl_new (&ctx);
+ if (ret != 0) {
+ g_set_error (error, BD_NVDIMM_ERROR, BD_NVDIMM_ERROR_NAMESPACE_FAIL,
+ "Failed to create ndctl context");
+ return FALSE;
+ }
+
+ ndns = get_namespace_by_name (namespace, ctx);
+ if (!ndns) {
+ g_set_error (error, BD_NVDIMM_ERROR, BD_NVDIMM_ERROR_NAMESPACE_NOEXIST,
+ "Failed to disable namespace: namespace '%s' not found.", namespace);
+ return FALSE;
+ }
+
+ ret = ndctl_namespace_disable_safe (ndns);
+ if (ret != 0) {
+ g_set_error (error, BD_NVDIMM_ERROR, BD_NVDIMM_ERROR_NAMESPACE_FAIL,
+ "Failed to disable namespace: %s", strerror (-ret));
+ ndctl_unref (ctx);
+ return FALSE;
+ }
+
+ ndctl_unref (ctx);
+ return TRUE;
+}
+
+static BDNVDIMMNamespaceInfo* get_nvdimm_namespace_info (struct ndctl_namespace *ndns, GError **error) {
+ struct ndctl_btt *btt;
+ struct ndctl_pfn *pfn;
+ struct ndctl_dax *dax;
+ enum ndctl_namespace_mode mode;
+ gchar uuid_buf[37] = {0};
+ uuid_t uuid;
+
+ btt = ndctl_namespace_get_btt (ndns);
+ dax = ndctl_namespace_get_dax (ndns);
+ pfn = ndctl_namespace_get_pfn (ndns);
+ mode = ndctl_namespace_get_mode (ndns);
+
+ BDNVDIMMNamespaceInfo *info = g_new0 (BDNVDIMMNamespaceInfo, 1);
+
+ info->dev = g_strdup (ndctl_namespace_get_devname (ndns));
+
+ switch (mode) {
+ case NDCTL_NS_MODE_MEMORY:
+ if (pfn)
+ info->size = ndctl_pfn_get_size (pfn);
+ else
+ info->size = ndctl_namespace_get_size (ndns);
+ info->mode = BD_NVDIMM_NAMESPACE_MODE_MEMORY;
+ break;
+ case NDCTL_NS_MODE_DAX:
+ if (!dax) {
+ g_set_error (error, BD_NVDIMM_ERROR, BD_NVDIMM_ERROR_NAMESPACE_FAIL,
+ "Failed to get information about namespaces: DAX mode "
+ "detected but no DAX device found.");
+ bd_nvdimm_namespace_info_free (info);
+ return NULL;
+ }
+ info->size = ndctl_dax_get_size (dax);
+ info->mode = BD_NVDIMM_NAMESPACE_MODE_DAX;
+ break;
+ case NDCTL_NS_MODE_SAFE:
+ if (!btt) {
+ g_set_error (error, BD_NVDIMM_ERROR, BD_NVDIMM_ERROR_NAMESPACE_FAIL,
+ "Failed to get information about namespaces: Sector mode "
+ "detected but no BTT device found.");
+ bd_nvdimm_namespace_info_free (info);
+ return NULL;
+ }
+ info->size = ndctl_btt_get_size (btt);
+ info->mode = BD_NVDIMM_NAMESPACE_MODE_SECTOR;
+ break;
+ case NDCTL_NS_MODE_RAW:
+ info->size = ndctl_namespace_get_size (ndns);
+ info->mode = BD_NVDIMM_NAMESPACE_MODE_RAW;
+ break;
+ default:
+ g_set_error (error, BD_NVDIMM_ERROR, BD_NVDIMM_ERROR_NAMESPACE_FAIL,
+ "Failed to get information about namespaces: Unknow mode.");
+ bd_nvdimm_namespace_info_free (info);
+ return NULL;
+ }
+
+ if (btt) {
+ ndctl_btt_get_uuid (btt, uuid);
+ uuid_unparse (uuid, uuid_buf);
+ info->uuid = g_strdup (uuid_buf);
+
+ info->sector_size = ndctl_btt_get_sector_size (btt);
+ info->blockdev = g_strdup (ndctl_btt_get_block_device (btt));
+ } else if (pfn) {
+ ndctl_pfn_get_uuid (pfn, uuid);
+ uuid_unparse (uuid, uuid_buf);
+ info->uuid = g_strdup (uuid_buf);
+
+ info->sector_size = 0; // no sector size for memory mode
+ info->blockdev = g_strdup (ndctl_pfn_get_block_device (pfn));
+ } else if (dax) {
+ ndctl_dax_get_uuid (dax, uuid);
+ uuid_unparse (uuid, uuid_buf);
+ info->uuid = g_strdup (uuid_buf);
+
+ /* no sector size or blockdev for dax mode */
+ info->sector_size = 0;
+ info->blockdev = NULL;
+ } else {
+ ndctl_namespace_get_uuid (ndns, uuid);
+
+ if (uuid_is_null (uuid))
+ info->uuid = NULL;
+ else {
+ uuid_unparse (uuid, uuid_buf);
+ info->uuid = g_strdup (uuid_buf);
+ }
+
+ info->sector_size = 0; // no sector size for raw mode
+ info->blockdev = g_strdup (ndctl_namespace_get_block_device (ndns));
+ }
+
+ info->enabled = ndctl_namespace_is_active (ndns);
+
+ return info;
+}
+
+/**
+ * bd_nvdimm_namespace_info:
+ * @namespace: namespace to get information about
+ * @extra: (allow-none) (array zero-terminated=1): extra options (currently unused)
+ * @error: (out): place to store error (if any)
+ *
+ * Returns: (transfer full): information about given namespace or %NULL if no such
+ * namespace was found (@error may be set to indicate error)
+ *
+ * Tech category: %BD_NVDIMM_TECH_NAMESPACE-%BD_NVDIMM_TECH_MODE_QUERY
+ */
+BDNVDIMMNamespaceInfo* bd_nvdimm_namespace_info (const gchar *namespace, const BDExtraArg **extra UNUSED, GError **error) {
+ struct ndctl_ctx *ctx = NULL;
+ struct ndctl_namespace *ndns = NULL;
+ BDNVDIMMNamespaceInfo *info = NULL;
+ gint ret = 0;
+
+ ret = ndctl_new (&ctx);
+ if (ret != 0) {
+ g_set_error (error, BD_NVDIMM_ERROR, BD_NVDIMM_ERROR_NAMESPACE_FAIL,
+ "Failed to create ndctl context");
+ return NULL;
+ }
+
+ ndns = get_namespace_by_name (namespace, ctx);
+ if (ndns) {
+ info = get_nvdimm_namespace_info (ndns, error);
+ ndctl_unref (ctx);
+ return info;
+ }
+
+ ndctl_unref (ctx);
+ return NULL;
+}
+
+/**
+ * bd_nvdimm_list_namespaces:
+ * @bus_name: (allow-none): return only namespaces on given bus (specified by name),
+ * %NULL may be specified to return namespaces from all buses
+ * @region_name: (allow-none): return only namespaces on given region (specified by 'regionX' name),
+ * %NULL may be specified to return namespaces from all regions
+ * @idle: whether to list idle (not enabled) namespaces too
+ * @extra: (allow-none) (array zero-terminated=1): extra options (currently unused)
+ * @error: (out): place to store error (if any)
+ *
+ * Returns: (array zero-terminated=1): information about the namespaces on @bus and @region or
+ * %NULL if no namespaces were found (@error may be set to indicate error)
+ *
+ * Tech category: %BD_NVDIMM_TECH_NAMESPACE-%BD_NVDIMM_TECH_MODE_QUERY
+ */
+BDNVDIMMNamespaceInfo** bd_nvdimm_list_namespaces (const gchar *bus_name, const gchar *region_name, gboolean idle, const BDExtraArg **extra UNUSED, GError **error) {
+ struct ndctl_ctx *ctx = NULL;
+ struct ndctl_namespace *ndns = NULL;
+ struct ndctl_region *region = NULL;
+ struct ndctl_bus *bus = NULL;
+ gint ret = 0;
+ BDNVDIMMNamespaceInfo **info = NULL;
+
+ GPtrArray *namespaces = g_ptr_array_new ();
+
+ ret = ndctl_new (&ctx);
+ if (ret != 0) {
+ g_set_error (error, BD_NVDIMM_ERROR, BD_NVDIMM_ERROR_NAMESPACE_FAIL,
+ "Failed to create ndctl context");
+ return NULL;
+ }
+
+ ndctl_bus_foreach (ctx, bus) {
+ if (bus_name && g_strcmp0 (bus_name, ndctl_bus_get_devname (bus)) != 0)
+ continue;
+
+ ndctl_region_foreach (bus, region) {
+ if (region_name && g_strcmp0 (bus_name, ndctl_region_get_devname (region)) != 0)
+ continue;
+
+ ndctl_namespace_foreach (region, ndns) {
+ if (!idle && !ndctl_namespace_is_active (ndns))
+ continue;
+
+ BDNVDIMMNamespaceInfo *info = get_nvdimm_namespace_info (ndns, error);
+ if (!info) {
+ g_ptr_array_foreach (namespaces, (GFunc) (void *) bd_nvdimm_namespace_info_free, NULL);
+ g_ptr_array_free (namespaces, FALSE);
+ ndctl_unref (ctx);
+ return NULL;
+ }
+
+ g_ptr_array_add (namespaces, info);
+ }
+ }
+ }
+
+ if (namespaces->len == 0) {
+ ndctl_unref (ctx);
+ return NULL;
+ }
+
+ g_ptr_array_add (namespaces, NULL);
+
+ info = (BDNVDIMMNamespaceInfo **) g_ptr_array_free (namespaces, FALSE);
+ ndctl_unref (ctx);
+
+ return info;
+}
+
+/**
+ * bd_nvdimm_namespace_reconfigure:
+ * @namespace: name of the namespace to recofigure
+ * @mode: mode type to set
+ * @error: (out): place to store error if any
+ * @extra: (allow-none) (array zero-terminated=1): extra options for the creation (right now
+ * passed to the 'ndctl' utility)
+ *
+ * Returns: whether @namespace was successfully reconfigured or not
+ *
+ * Tech category: %BD_NVDIMM_TECH_NAMESPACE-%BD_NVDIMM_TECH_MODE_RECONFIGURE
+ */
+gboolean bd_nvdimm_namespace_reconfigure (const gchar* namespace, BDNVDIMMNamespaceMode mode, gboolean force, const BDExtraArg **extra, GError** error) {
+ const gchar *args[8] = {"ndctl", "create-namespace", "-e", namespace, "-m", NULL, NULL, NULL};
+ gboolean ret = FALSE;
+ const gchar *mode_str = NULL;
+
+ if (!check_deps (&avail_deps, DEPS_NDCTL_MASK, deps, DEPS_LAST, &deps_check_lock, error))
+ return FALSE;
+
+ mode_str = bd_nvdimm_namespace_get_mode_str (mode, error);
+ if (!mode_str)
+ /* error is already populated */
+ return FALSE;
+
+ args[5] = g_strdup (mode_str);
+
+ if (force)
+ args[6] = "-f";
+
+ ret = bd_utils_exec_and_report_error (args, extra, error);
+
+ g_free ((gchar *) args[5]);
+ return ret;
+}
diff --git a/src/plugins/nvdimm.h b/src/plugins/nvdimm.h
new file mode 100644
index 0000000..5a1642f
--- /dev/null
+++ b/src/plugins/nvdimm.h
@@ -0,0 +1,76 @@
+#include <glib.h>
+#include <blockdev/utils.h>
+
+#ifndef BD_NVDIMM
+#define BD_NVDIMM
+
+GQuark bd_nvdimm_error_quark (void);
+#define BD_NVDIMM_ERROR bd_nvdimm_error_quark ()
+typedef enum {
+ BD_NVDIMM_ERROR_NAMESPACE_PARSE,
+ BD_NVDIMM_ERROR_NAMESPACE_FAIL,
+ BD_NVDIMM_ERROR_NAMESPACE_NOEXIST,
+ BD_NVDIMM_ERROR_NAMESPACE_MODE_INVAL,
+ BD_NVDIMM_ERROR_TECH_UNAVAIL,
+} BDNVDIMMError;
+
+typedef enum {
+ BD_NVDIMM_NAMESPACE_MODE_RAW,
+ BD_NVDIMM_NAMESPACE_MODE_SECTOR,
+ BD_NVDIMM_NAMESPACE_MODE_MEMORY,
+ BD_NVDIMM_NAMESPACE_MODE_DAX,
+ BD_NVDIMM_NAMESPACE_MODE_UNKNOWN
+} BDNVDIMMNamespaceMode;
+
+typedef struct BDNVDIMMNamespaceInfo {
+ gchar *dev;
+ guint64 mode;
+ guint64 size;
+ gchar *uuid;
+ guint64 sector_size;
+ gchar *blockdev;
+ gboolean enabled;
+} BDNVDIMMNamespaceInfo;
+
+void bd_nvdimm_namespace_info_free (BDNVDIMMNamespaceInfo *info);
+BDNVDIMMNamespaceInfo* bd_nvdimm_namespace_info_copy (BDNVDIMMNamespaceInfo *info);
+
+typedef enum {
+ BD_NVDIMM_TECH_NAMESPACE = 0,
+} BDNVDIMMTech;
+
+typedef enum {
+ BD_NVDIMM_TECH_MODE_CREATE = 1 << 0,
+ BD_NVDIMM_TECH_MODE_REMOVE = 1 << 1,
+ BD_NVDIMM_TECH_MODE_ACTIVATE_DEACTIVATE = 1 << 2,
+ BD_NVDIMM_TECH_MODE_QUERY = 1 << 3,
+ BD_NVDIMM_TECH_MODE_RECONFIGURE = 1 << 4,
+} BDNVDIMMTechMode;
+
+/*
+ * If using the plugin as a standalone library, the following functions should
+ * be called to:
+ *
+ * check_deps() - check plugin's dependencies, returning TRUE if satisfied
+ * init() - initialize the plugin, returning TRUE on success
+ * close() - clean after the plugin at the end or if no longer used
+ *
+ */
+gboolean bd_nvdimm_check_deps ();
+gboolean bd_nvdimm_init ();
+void bd_nvdimm_close ();
+
+gboolean bd_nvdimm_is_tech_avail (BDNVDIMMTech tech, guint64 mode, GError **error);
+
+BDNVDIMMNamespaceMode bd_nvdimm_namespace_get_mode_from_str (const gchar *mode_str, GError **error);
+const gchar* bd_nvdimm_namespace_get_mode_str (BDNVDIMMNamespaceMode mode, GError **error);
+
+gboolean bd_nvdimm_namespace_enable (const gchar *namespace, const BDExtraArg **extra, GError **error);
+gboolean bd_nvdimm_namespace_disable (const gchar *namespace, const BDExtraArg **extra, GError **error);
+
+BDNVDIMMNamespaceInfo* bd_nvdimm_namespace_info (const gchar *namespace, const BDExtraArg **extra, GError **error);
+BDNVDIMMNamespaceInfo** bd_nvdimm_list_namespaces (const gchar *bus, const gchar *region, gboolean idle, const BDExtraArg **extra, GError **error);
+
+gboolean bd_nvdimm_namespace_reconfigure (const gchar* namespace, BDNVDIMMNamespaceMode mode, gboolean force, const BDExtraArg **extra, GError** error);
+
+#endif /* BD_CRYPTO */
diff --git a/src/python/gi/overrides/BlockDev.py b/src/python/gi/overrides/BlockDev.py
index fb3ffb4..dc634ab 100644
--- a/src/python/gi/overrides/BlockDev.py
+++ b/src/python/gi/overrides/BlockDev.py
@@ -50,6 +50,7 @@ bd_plugins = { "lvm": BlockDev.Plugin.LVM,
"part": BlockDev.Plugin.PART,
"fs": BlockDev.Plugin.FS,
"s390": BlockDev.Plugin.S390,
+ "nvdimm": BlockDev.Plugin.NVDIMM,
}
@@ -692,6 +693,41 @@ def part_create_table(disk, type, ignore_existing=True):
__all__.append("part_create_table")
+_nvdimm_namespace_reconfigure = BlockDev.nvdimm_namespace_reconfigure
+@override(BlockDev.nvdimm_namespace_reconfigure)
+def nvdimm_namespace_reconfigure(namespace, mode, force=False, extra=None, **kwargs):
+ extra = _get_extra(extra, kwargs)
+ return _nvdimm_namespace_reconfigure(namespace, mode, force, extra)
+__all__.append("nvdimm_namespace_reconfigure")
+
+_nvdimm_namespace_info = BlockDev.nvdimm_namespace_info
+@override(BlockDev.nvdimm_namespace_info)
+def nvdimm_namespace_info(namespace, extra=None, **kwargs):
+ extra = _get_extra(extra, kwargs)
+ return _nvdimm_namespace_info(namespace, extra)
+__all__.append("nvdimm_namespace_info")
+
+_nvdimm_list_namespaces = BlockDev.nvdimm_list_namespaces
+@override(BlockDev.nvdimm_list_namespaces)
+def nvdimm_list_namespaces(bus=None, region=None, idle=False, extra=None, **kwargs):
+ extra = _get_extra(extra, kwargs)
+ return _nvdimm_list_namespaces(bus, region, idle, extra)
+__all__.append("nvdimm_list_namespaces")
+
+_nvdimm_namespace_enable = BlockDev.nvdimm_namespace_enable
+@override(BlockDev.nvdimm_namespace_enable)
+def nvdimm_namespace_enable(namespace, extra=None, **kwargs):
+ extra = _get_extra(extra, kwargs)
+ return _nvdimm_namespace_enable(namespace, extra)
+__all__.append("nvdimm_namespace_enable")
+
+_nvdimm_namespace_disable = BlockDev.nvdimm_namespace_disable
+@override(BlockDev.nvdimm_namespace_disable)
+def nvdimm_namespace_disable(namespace, extra=None, **kwargs):
+ extra = _get_extra(extra, kwargs)
+ return _nvdimm_namespace_disable(namespace, extra)
+__all__.append("nvdimm_namespace_disable")
+
## defined in this overrides only!
def plugin_specs_from_names(plugin_names):
ret = []
@@ -886,6 +922,10 @@ class UtilsError(BlockDevError):
pass
__all__.append("UtilsError")
+class NVDIMMError(BlockDevError):
+ pass
+__all__.append("NVDIMMError")
+
class BlockDevNotImplementedError(NotImplementedError, BlockDevError):
pass
__all__.append("BlockDevNotImplementedError")
@@ -927,6 +967,9 @@ __all__.append("part")
fs = ErrorProxy("fs", BlockDev, [(GLib.Error, FSError)], [not_implemented_rule, fs_nofs_rule])
__all__.append("fs")
+nvdimm = ErrorProxy("nvdimm", BlockDev, [(GLib.Error, NVDIMMError)], [not_implemented_rule])
+__all__.append("nvdimm")
+
s390 = ErrorProxy("s390", BlockDev, [(GLib.Error, S390Error)], [not_implemented_rule])
__all__.append("s390")
--
1.8.3.1
From 2fda30f62f962eb9e10894b4d919acd013c9c93b Mon Sep 17 00:00:00 2001
From: Vojtech Trefny <vtrefny@redhat.com>
Date: Wed, 31 Jan 2018 16:27:59 +0100
Subject: [PATCH 2/4] Add tests for the NVDIMM plugin
---
tests/nvdimm_test.py | 178 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 178 insertions(+)
create mode 100644 tests/nvdimm_test.py
diff --git a/tests/nvdimm_test.py b/tests/nvdimm_test.py
new file mode 100644
index 0000000..b4eb43d
--- /dev/null
+++ b/tests/nvdimm_test.py
@@ -0,0 +1,178 @@
+import json
+import os
+import unittest
+import overrides_hack
+
+from utils import run_command, read_file, skip_on, fake_path
+from gi.repository import BlockDev, GLib
+
+
+@skip_on("debian", reason="NVDIMM plugin doesn't work on Debian (missing ndctl)")
+class NVDIMMTestCase(unittest.TestCase):
+
+ requested_plugins = BlockDev.plugin_specs_from_names(("nvdimm",))
+
+ @classmethod
+ def setUpClass(cls):
+ if not BlockDev.is_initialized():
+ BlockDev.init(cls.requested_plugins, None)
+ else:
+ BlockDev.reinit(cls.requested_plugins, True, None)
+
+class NVDIMMNamespaceTestCase(NVDIMMTestCase):
+
+ sys_info = None
+
+ def _get_nvdimm_info(self):
+ ret, out, _err = run_command("ndctl list")
+ if ret != 0 or not out:
+ return None
+
+ decoder = json.JSONDecoder()
+ decoded = decoder.decode(out)
+ return decoded
+
+ def setUp(self):
+ self.sys_info = self._get_nvdimm_info()
+ if not self.sys_info:
+ self.skipTest("No NVDIMM devices available.")
+
+ # skip the test if there is more than one device
+ # these tests change nvdimm mode a we need to be sure that we are really
+ # working with the 'fake' device created by the memmap kernel cmdline option
+ if type(self.sys_info) is not dict:
+ self.skipTest("Multiple NVDIMM devices found.")
+
+ # skip the tests if the nvdimm is a 'fake' one
+ cmdline = read_file("/proc/cmdline")
+ if "memmap=" not in cmdline:
+ self.skipTest("NVDIMM device found, but not created by the 'memmap' kernel command-line option.")
+
+ def _check_namespace_info(self, bd_info):
+ self.assertEqual(bd_info.dev, self.sys_info["dev"])
+ self.assertEqual(bd_info.mode, BlockDev.nvdimm_namespace_get_mode_from_str(self.sys_info["mode"]))
+ self.assertEqual(bd_info.size, self.sys_info["size"])
+
+ if "uuid" in self.sys_info.keys():
+ self.assertEqual(bd_info.uuid, self.sys_info["uuid"])
+ else:
+ self.assertIsNone(bd_info.uuid)
+
+ if "blockdev" in self.sys_info.keys():
+ self.assertEqual(bd_info.blockdev, self.sys_info["blockdev"])
+ else:
+ self.assertIsNone(bd_info.blockdev)
+
+ if "sector_size" in self.sys_info.keys():
+ self.assertEqual(bd_info.sector_size, self.sys_info["sector_size"])
+ else:
+ self.assertEqual(bd_info.sector_size, 0)
+
+ def test_namespace_info(self):
+ # get info about our 'testing' namespace
+ info = BlockDev.nvdimm_namespace_info(self.sys_info["dev"])
+ self._check_namespace_info(info)
+
+ info = BlockDev.nvdimm_namespace_info("definitely-not-a-namespace")
+ self.assertIsNone(info)
+
+ def test_list_namespaces(self):
+ bd_namespaces = BlockDev.nvdimm_list_namespaces()
+ self.assertEqual(len(bd_namespaces), 1)
+
+ self._check_namespace_info(bd_namespaces[0])
+
+ @unittest.skipUnless("JENKINS_HOME" in os.environ, "skipping test that modifies system configuration")
+ def test_enable_disable(self):
+ # non-existing/unknow namespace
+ with self.assertRaises(GLib.GError):
+ BlockDev.nvdimm_namespace_enable("definitely-not-a-namespace")
+
+ # enable the namespace
+ ret = BlockDev.nvdimm_namespace_enable(self.sys_info["dev"])
+ self.assertTrue(ret)
+
+ info = BlockDev.nvdimm_namespace_info(self.sys_info["dev"])
+ self.assertTrue(info.enabled)
+
+ # disable the namespace
+ ret = BlockDev.nvdimm_namespace_disable(self.sys_info["dev"])
+ self.assertTrue(ret)
+
+ info = BlockDev.nvdimm_namespace_info(self.sys_info["dev"])
+ self.assertFalse(info.enabled)
+
+ # and enable it again
+ ret = BlockDev.nvdimm_namespace_enable(self.sys_info["dev"])
+ self.assertTrue(ret)
+
+ info = BlockDev.nvdimm_namespace_info(self.sys_info["dev"])
+ self.assertTrue(info.enabled)
+
+ @unittest.skipUnless("JENKINS_HOME" in os.environ, "skipping test that modifies system configuration")
+ def test_namespace_reconfigure(self):
+ # active namespace -- reconfigure doesn't work without force
+ with self.assertRaises(GLib.GError):
+ BlockDev.nvdimm_namespace_reconfigure(self.sys_info["dev"],
+ BlockDev.NVDIMMNamespaceMode.SECTOR,
+ False)
+
+ # non-existing/unknow mode
+ with self.assertRaises(GLib.GError):
+ BlockDev.nvdimm_namespace_reconfigure(self.sys_info["dev"],
+ BlockDev.NVDIMMNamespaceMode.UNKNOWN,
+ True)
+
+ # non-existing/unknow namespace
+ with self.assertRaises(GLib.GError):
+ BlockDev.nvdimm_namespace_reconfigure("definitely-not-a-namespace",
+ BlockDev.NVDIMMNamespaceMode.SECTOR,
+ True)
+
+ # switch to sector mode
+ ret = BlockDev.nvdimm_namespace_reconfigure(self.sys_info["dev"],
+ BlockDev.NVDIMMNamespaceMode.SECTOR,
+ True, extra={"-l": "512"})
+ self.assertTrue(ret)
+ info = BlockDev.nvdimm_namespace_info(self.sys_info["dev"])
+ self.assertEqual(info.mode, BlockDev.NVDIMMNamespaceMode.SECTOR)
+
+ # and now to memory mode
+ ret = BlockDev.nvdimm_namespace_reconfigure(self.sys_info["dev"],
+ BlockDev.NVDIMMNamespaceMode.MEMORY,
+ True)
+ self.assertTrue(ret)
+ info = BlockDev.nvdimm_namespace_info(self.sys_info["dev"])
+ self.assertEqual(info.mode, BlockDev.NVDIMMNamespaceMode.MEMORY)
+
+ # and back to sector
+ ret = BlockDev.nvdimm_namespace_reconfigure(self.sys_info["dev"],
+ BlockDev.NVDIMMNamespaceMode.SECTOR,
+ True, extra={"-l": "512"})
+ self.assertTrue(ret)
+ info = BlockDev.nvdimm_namespace_info(self.sys_info["dev"])
+ self.assertEqual(info.mode, BlockDev.NVDIMMNamespaceMode.SECTOR)
+
+
+class NVDIMMUnloadTest(NVDIMMTestCase):
+ def setUp(self):
+ # make sure the library is initialized with all plugins loaded for other
+ # tests
+ self.addCleanup(BlockDev.reinit, self.requested_plugins, True, None)
+
+ def test_check_no_ndctl(self):
+ """Verify that checking ndctl tool availability works as expected"""
+
+ # unload all plugins first
+ self.assertTrue(BlockDev.reinit([], True, None))
+
+ with fake_path(all_but="ndctl"):
+ # no ndctl tool available, the NVDIMM plugin should fail to load
+ with self.assertRaises(GLib.GError):
+ BlockDev.reinit(self.requested_plugins, True, None)
+
+ self.assertNotIn("nvdimm", BlockDev.get_available_plugin_names())
+
+ # load the plugins back
+ self.assertTrue(BlockDev.reinit(self.requested_plugins, True, None))
+ self.assertIn("nvdimm", BlockDev.get_available_plugin_names())
--
1.8.3.1
From 333bad8ceafc229b9a8c97df23715a02361aee01 Mon Sep 17 00:00:00 2001
From: Vojtech Trefny <vtrefny@redhat.com>
Date: Thu, 1 Feb 2018 14:46:51 +0100
Subject: [PATCH 3/4] Add --without-xyz to DISTCHECK_CONFIGURE_FLAGS for
disabled plugins
We need to disable these plugins for distcheck because of missing
build dependecies etc.
---
Makefile.am | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 53 insertions(+)
diff --git a/Makefile.am b/Makefile.am
index d30acd1..54b89e1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -4,6 +4,59 @@ SHELL = /bin/bash
ACLOCAL_AMFLAGS = -I m4
DISTCHECK_CONFIGURE_FLAGS = --enable-introspection
+if !WITH_BTRFS
+DISTCHECK_CONFIGURE_FLAGS += --without-btrfs
+endif
+
+if !WITH_CRYPTO
+DISTCHECK_CONFIGURE_FLAGS += --without-crypto
+endif
+
+if !WITH_DM
+DISTCHECK_CONFIGURE_FLAGS += --without-dm
+endif
+
+if !WITH_LOOP
+DISTCHECK_CONFIGURE_FLAGS += --without-loop
+endif
+
+if !WITH_LVM
+DISTCHECK_CONFIGURE_FLAGS += --without-lvm
+endif
+
+if !WITH_LVM_DBUS
+DISTCHECK_CONFIGURE_FLAGS += --without-lvm-dbus
+endif
+
+if !WITH_MDRAID
+DISTCHECK_CONFIGURE_FLAGS += --without-mdraid
+endif
+
+if !WITH_MPATH
+DISTCHECK_CONFIGURE_FLAGS += --without-mpath
+endif
+
+if !WITH_NVDIMM
+DISTCHECK_CONFIGURE_FLAGS += --without-nvdimm
+endif
+
+if !WITH_SWAP
+DISTCHECK_CONFIGURE_FLAGS += --without-swap
+endif
+
+if !WITH_KBD
+DISTCHECK_CONFIGURE_FLAGS += --without-kbd
+endif
+
+if !WITH_PART
+DISTCHECK_CONFIGURE_FLAGS += --without-part
+endif
+
+if !WITH_S390
+DISTCHECK_CONFIGURE_FLAGS += --without-s390
+endif
+
+
SUBDIRS = include src dist scripts data
if WITH_GTK_DOC
SUBDIRS += docs
--
1.8.3.1
From 7ebc9d20fa8b97482a109121dd016e01c4d032e4 Mon Sep 17 00:00:00 2001
From: Vojtech Trefny <vtrefny@redhat.com>
Date: Tue, 6 Feb 2018 14:56:10 +0100
Subject: [PATCH 4/4] Add function for getting NVDIMM namespace name from
devname or path
For example getting "namespace0.0" from "pmem0" or "/dev/pmem0".
---
docs/libblockdev-sections.txt | 1 +
src/lib/plugin_apis/nvdimm.api | 13 +++++++++
src/plugins/nvdimm.c | 63 ++++++++++++++++++++++++++++++++++++++++++
src/plugins/nvdimm.h | 2 ++
tests/nvdimm_test.py | 8 ++++++
5 files changed, 87 insertions(+)
diff --git a/docs/libblockdev-sections.txt b/docs/libblockdev-sections.txt
index 756b5b5..8aaa290 100644
--- a/docs/libblockdev-sections.txt
+++ b/docs/libblockdev-sections.txt
@@ -578,6 +578,7 @@ BDNVDIMMNamespaceMode
BDNVDIMMNamespaceInfo
bd_nvdimm_namespace_get_mode_from_str
bd_nvdimm_namespace_get_mode_str
+bd_nvdimm_namespace_get_devname
bd_nvdimm_namespace_enable
bd_nvdimm_namespace_disable
bd_nvdimm_namespace_info
diff --git a/src/lib/plugin_apis/nvdimm.api b/src/lib/plugin_apis/nvdimm.api
index 3d74f62..9d5260c 100644
--- a/src/lib/plugin_apis/nvdimm.api
+++ b/src/lib/plugin_apis/nvdimm.api
@@ -137,6 +137,19 @@ BDNVDIMMNamespaceMode bd_nvdimm_namespace_get_mode_from_str (const gchar *mode_s
const gchar* bd_nvdimm_namespace_get_mode_str (BDNVDIMMNamespaceMode mode, GError **error);
/**
+ * bd_nvdimm_namespace_get_devname:
+ * @device: name or path of a block device (e.g. "/dev/pmem0")
+ * @error: (out): place to store error (if any)
+ *
+ * Returns: (transfer full): namespace device name (e.g. "namespaceX.Y") for @device
+ * or %NULL if @device is not a NVDIMM namespace
+ * (@error may be set to indicate error)
+ *
+ * Tech category: %BD_NVDIMM_TECH_NAMESPACE-%BD_NVDIMM_TECH_MODE_QUERY
+ */
+gchar* bd_nvdimm_namespace_get_devname (const gchar *device, GError **error);
+
+/**
* bd_nvdimm_namespace_enable:
* @namespace: name of the namespace to enable
* @extra: (allow-none) (array zero-terminated=1): extra options (currently unused)
diff --git a/src/plugins/nvdimm.c b/src/plugins/nvdimm.c
index 7a6802a..40ade05 100644
--- a/src/plugins/nvdimm.c
+++ b/src/plugins/nvdimm.c
@@ -222,6 +222,69 @@ static struct ndctl_namespace* get_namespace_by_name (const gchar *namespace, st
}
/**
+ * bd_nvdimm_namespace_get_devname:
+ * @device: name or path of a block device (e.g. "/dev/pmem0")
+ * @error: (out): place to store error (if any)
+ *
+ * Returns: (transfer full): namespace device name (e.g. "namespaceX.Y") for @device
+ * or %NULL if @device is not a NVDIMM namespace
+ * (@error may be set to indicate error)
+ *
+ * Tech category: %BD_NVDIMM_TECH_NAMESPACE-%BD_NVDIMM_TECH_MODE_QUERY
+ */
+gchar* bd_nvdimm_namespace_get_devname (const gchar *device, GError **error) {
+ struct ndctl_ctx *ctx = NULL;
+ struct ndctl_namespace *ndns = NULL;
+ struct ndctl_region *region = NULL;
+ struct ndctl_bus *bus = NULL;
+ gint success = 0;
+ gchar *ret = NULL;
+
+ /* get rid of the "/dev/" prefix (if any) */
+ if (g_str_has_prefix (device, "/dev/"))
+ device = device + 5;
+
+ success = ndctl_new (&ctx);
+ if (success != 0) {
+ g_set_error (error, BD_NVDIMM_ERROR, BD_NVDIMM_ERROR_NAMESPACE_FAIL,
+ "Failed to create ndctl context");
+ return FALSE;
+ }
+
+ ndctl_bus_foreach (ctx, bus) {
+ ndctl_region_foreach (bus, region) {
+ ndctl_namespace_foreach (region, ndns) {
+ if (!ndctl_namespace_is_active (ndns))
+ continue;
+
+ struct ndctl_btt *btt = ndctl_namespace_get_btt (ndns);
+ struct ndctl_dax *dax = ndctl_namespace_get_dax (ndns);
+ struct ndctl_pfn *pfn = ndctl_namespace_get_pfn (ndns);
+ const gchar *blockdev = NULL;
+
+ if (dax)
+ continue;
+ else if (btt)
+ blockdev = ndctl_btt_get_block_device (btt);
+ else if (pfn)
+ blockdev = ndctl_pfn_get_block_device (pfn);
+ else
+ blockdev = ndctl_namespace_get_block_device (ndns);
+
+ if (g_strcmp0 (blockdev, device) == 0) {
+ ret = g_strdup (ndctl_namespace_get_devname (ndns));
+ ndctl_unref (ctx);
+ return ret;
+ }
+ }
+ }
+ }
+
+ ndctl_unref (ctx);
+ return NULL;
+}
+
+/**
* bd_nvdimm_namespace_enable:
* @namespace: name of the namespace to enable
* @extra: (allow-none) (array zero-terminated=1): extra options (currently unused)
diff --git a/src/plugins/nvdimm.h b/src/plugins/nvdimm.h
index 5a1642f..fcc1038 100644
--- a/src/plugins/nvdimm.h
+++ b/src/plugins/nvdimm.h
@@ -65,6 +65,8 @@ gboolean bd_nvdimm_is_tech_avail (BDNVDIMMTech tech, guint64 mode, GError **erro
BDNVDIMMNamespaceMode bd_nvdimm_namespace_get_mode_from_str (const gchar *mode_str, GError **error);
const gchar* bd_nvdimm_namespace_get_mode_str (BDNVDIMMNamespaceMode mode, GError **error);
+gchar* bd_nvdimm_namespace_get_devname (const gchar *device, GError **error);
+
gboolean bd_nvdimm_namespace_enable (const gchar *namespace, const BDExtraArg **extra, GError **error);
gboolean bd_nvdimm_namespace_disable (const gchar *namespace, const BDExtraArg **extra, GError **error);
diff --git a/tests/nvdimm_test.py b/tests/nvdimm_test.py
index b4eb43d..92a6653 100644
--- a/tests/nvdimm_test.py
+++ b/tests/nvdimm_test.py
@@ -73,6 +73,14 @@ class NVDIMMNamespaceTestCase(NVDIMMTestCase):
info = BlockDev.nvdimm_namespace_info(self.sys_info["dev"])
self._check_namespace_info(info)
+ # test also that getting namespace devname from blockdev name works
+ namespace = BlockDev.nvdimm_namespace_get_devname(info.blockdev)
+ self.assertEqual(namespace, self.sys_info["dev"])
+
+ # should work even with path, e.g. /dev/pmem0
+ namespace = BlockDev.nvdimm_namespace_get_devname("/dev/" + info.blockdev)
+ self.assertEqual(namespace, self.sys_info["dev"])
+
info = BlockDev.nvdimm_namespace_info("definitely-not-a-namespace")
self.assertIsNone(info)
--
1.8.3.1