summaryrefslogtreecommitdiffstats
path: root/src/extblkdev
diff options
context:
space:
mode:
Diffstat (limited to 'src/extblkdev')
-rw-r--r--src/extblkdev/CMakeLists.txt14
-rw-r--r--src/extblkdev/ExtBlkDevInterface.h141
-rw-r--r--src/extblkdev/ExtBlkDevPlugin.cc268
-rw-r--r--src/extblkdev/ExtBlkDevPlugin.h38
-rw-r--r--src/extblkdev/vdo/CMakeLists.txt9
-rw-r--r--src/extblkdev/vdo/ExtBlkDevPluginVdo.cc59
-rw-r--r--src/extblkdev/vdo/ExtBlkDevPluginVdo.h34
-rw-r--r--src/extblkdev/vdo/ExtBlkDevVdo.cc156
-rw-r--r--src/extblkdev/vdo/ExtBlkDevVdo.h52
9 files changed, 771 insertions, 0 deletions
diff --git a/src/extblkdev/CMakeLists.txt b/src/extblkdev/CMakeLists.txt
new file mode 100644
index 000000000..64010f31c
--- /dev/null
+++ b/src/extblkdev/CMakeLists.txt
@@ -0,0 +1,14 @@
+## extended block device plugins
+
+set(extblkdev_plugin_dir ${CEPH_INSTALL_PKGLIBDIR}/extblkdev)
+
+add_subdirectory(vdo)
+
+add_library(extblkdev STATIC ExtBlkDevPlugin.cc)
+
+if(NOT WIN32)
+target_link_libraries(extblkdev cap)
+endif()
+
+add_custom_target(extblkdev_plugins DEPENDS
+ ceph_ebd_vdo)
diff --git a/src/extblkdev/ExtBlkDevInterface.h b/src/extblkdev/ExtBlkDevInterface.h
new file mode 100644
index 000000000..219780fcd
--- /dev/null
+++ b/src/extblkdev/ExtBlkDevInterface.h
@@ -0,0 +1,141 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph distributed storage system
+ *
+ * (C) Copyright IBM Corporation 2022
+ * Author: Martin Ohmacht <mohmacht@us.ibm.com>
+ *
+ * Based on the file ceph/src/erasure-code/ErasureCodeInterface.h
+ * Copyright (C) 2013 Cloudwatt <libre.licensing@cloudwatt.com>
+ * Author: Loic Dachary <loic@dachary.org>
+ *
+ * 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.
+ *
+ */
+
+#ifndef CEPH_EXT_BLK_DEV_INTERFACE_H
+#define CEPH_EXT_BLK_DEV_INTERFACE_H
+
+/*! @file ExtBlkDevInterface.h
+ @brief Interface provided by extended block device plugins
+
+ Block devices with verdor specific capabilities rely on plugins implementing
+ **ExtBlkDevInterface** to provide access to their capabilities.
+
+ Methods returning an **int** return **0** on success and a
+ negative value on error.
+ */
+
+#include <string>
+#include <map>
+#include <ostream>
+#include <memory>
+#ifdef __linux__
+#include <sys/capability.h>
+#else
+typedef void *cap_t;
+#endif
+
+#include "common/PluginRegistry.h"
+
+namespace ceph {
+ class ExtBlkDevState {
+ uint64_t logical_total=0;
+ uint64_t logical_avail=0;
+ uint64_t physical_total=0;
+ uint64_t physical_avail=0;
+ public:
+ uint64_t get_logical_total(){return logical_total;}
+ uint64_t get_logical_avail(){return logical_avail;}
+ uint64_t get_physical_total(){return physical_total;}
+ uint64_t get_physical_avail(){return physical_avail;}
+ void set_logical_total(uint64_t alogical_total){logical_total=alogical_total;}
+ void set_logical_avail(uint64_t alogical_avail){logical_avail=alogical_avail;}
+ void set_physical_total(uint64_t aphysical_total){physical_total=aphysical_total;}
+ void set_physical_avail(uint64_t aphysical_avail){physical_avail=aphysical_avail;}
+ };
+
+
+ class ExtBlkDevInterface {
+ public:
+ virtual ~ExtBlkDevInterface() {}
+
+ /**
+ * Initialize the instance if device logdevname is supported
+ *
+ * Return 0 on success or a negative errno on error
+ *
+ * @param [in] logdevname name of device to check for support by this plugin
+ * @return 0 on success or a negative errno on error.
+ */
+ virtual int init(const std::string& logdevname) = 0;
+
+ /**
+ * Return the name of the underlying device detected by **init** method
+ *
+ * @return the name of the underlying device
+ */
+ virtual const std::string& get_devname() const = 0;
+
+ /**
+ * Provide status of underlying physical storage after compression
+ *
+ * Return 0 on success or a negative errno on error.
+ *
+ * @param [out] state current state of the undelying device
+ * @return 0 on success or a negative errno on error.
+ */
+ virtual int get_state(ExtBlkDevState& state) = 0;
+
+ /**
+ * Populate property map with meta data of device.
+ *
+ * @param [in] prefix prefix to be prepended to all map values by this method
+ * @param [in,out] pm property map of the device, to be extended by attributes detected by this plugin
+ * @return 0 on success or a negative errno on error.
+ */
+ virtual int collect_metadata(const std::string& prefix, std::map<std::string,std::string> *pm) = 0;
+ };
+
+ typedef std::shared_ptr<ExtBlkDevInterface> ExtBlkDevInterfaceRef;
+
+ class ExtBlkDevPlugin : public Plugin {
+ public:
+
+ explicit ExtBlkDevPlugin(CephContext *cct) : Plugin(cct) {}
+ virtual ~ExtBlkDevPlugin() {}
+
+ /**
+ * Indicate plugin-required capabilities in permitted set
+ * If a plugin requires a capability to be active in the
+ * permitted set when invoked, it must indicate so by setting
+ * the required flags in the cap_t structure passed into this method.
+ * The cap_t structure is empty when passed into the method, and only the
+ * method's modifications to the permitted set are used by ceph.
+ * The plugin must elevate the capabilities into the effective
+ * set at a later point when needed during the invocation of its
+ * other methods, and is responsible to restore the effective set
+ * before returning from the method
+ *
+ * @param [out] caps capability set indicating the necessary capabilities
+ */
+ virtual int get_required_cap_set(cap_t caps) = 0;
+
+ /**
+ * Factory method, creating ExtBlkDev instances
+ *
+ * @param [in] logdevname name of logic device, may be composed of physical devices
+ * @param [out] ext_blk_dev object created on successful device support detection
+ * @return 0 on success or a negative errno on error.
+ */
+ virtual int factory(const std::string& logdevname,
+ ExtBlkDevInterfaceRef& ext_blk_dev) = 0;
+ };
+
+}
+
+#endif
diff --git a/src/extblkdev/ExtBlkDevPlugin.cc b/src/extblkdev/ExtBlkDevPlugin.cc
new file mode 100644
index 000000000..28f47311b
--- /dev/null
+++ b/src/extblkdev/ExtBlkDevPlugin.cc
@@ -0,0 +1,268 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph distributed storage system
+ *
+ * (C) Copyright IBM Corporation 2022
+ * Author: Martin Ohmacht <mohmacht@us.ibm.com>
+ *
+ * Based on the file ceph/src/erasure-code/ErasureCodePlugin.cc
+ * Copyright (C) 2013,2014 Cloudwatt <libre.licensing@cloudwatt.com>
+ * Copyright (C) 2014 Red Hat <contact@redhat.com>
+ *
+ * Author: Loic Dachary <loic@dachary.org>
+ *
+ * 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.
+ *
+ */
+
+#include <errno.h>
+
+#include "ceph_ver.h"
+#include "ExtBlkDevPlugin.h"
+#include "common/errno.h"
+#include "include/dlfcn_compat.h"
+#include "include/str_list.h"
+#include "include/ceph_assert.h"
+#include "common/ceph_context.h"
+#include "common/debug.h"
+
+#define dout_subsys ceph_subsys_bdev
+#define dout_context cct
+
+using namespace std;
+
+namespace ceph {
+
+ namespace extblkdev {
+
+
+#ifdef __linux__
+ // iterate across plugins and determine each capability's reqirement
+ // merge requirements into merge_caps set
+ int get_required_caps(CephContext *cct, cap_t &merge_caps)
+ {
+ cap_t plugin_caps = nullptr;
+ auto close_caps_on_return = make_scope_guard([&] {
+ if (plugin_caps != nullptr) {
+ cap_free(plugin_caps);
+ }
+ });
+
+ // plugin-private cap set to populate by a plugin
+ plugin_caps = cap_init();
+ if (plugin_caps == nullptr) {
+ return -errno;
+ }
+ auto registry = cct->get_plugin_registry();
+ std::lock_guard l(registry->lock);
+ // did we preload any extblkdev type plugins?
+ auto ptype = registry->plugins.find("extblkdev");
+ if (ptype != registry->plugins.end()) {
+ // iterate over all extblkdev plugins
+ for (auto& it : ptype->second) {
+ // clear cap set before passing to plugin
+ if (cap_clear(plugin_caps) < 0) {
+ return -errno;
+ }
+ // let plugin populate set with required caps
+ auto ebdplugin = dynamic_cast<ExtBlkDevPlugin*>(it.second);
+ if (ebdplugin == nullptr) {
+ derr << __func__ << " Is not an extblkdev plugin: " << it.first << dendl;
+ return -ENOENT;
+ }
+ int rc = ebdplugin->get_required_cap_set(plugin_caps);
+ if (rc != 0)
+ return rc;
+ // iterate over capabilities and check for active bits
+ for (int i = 0; i <= CAP_LAST_CAP; ++i) {
+ cap_flag_value_t val;
+ if (cap_get_flag(plugin_caps, i, CAP_PERMITTED, &val) < 0) {
+ return -errno;
+ }
+ if (val != CAP_CLEAR) {
+ cap_value_t arr[1];
+ arr[0] = i;
+ // set capability in merged set
+ if (cap_set_flag(merge_caps, CAP_PERMITTED, 1, arr, CAP_SET) < 0) {
+ return -errno;
+ }
+ }
+ }
+ }
+ }
+ return 0;
+ }
+
+ // trim away all capabilities of this process that are not explicitly set in merge_set
+ int trim_caps(CephContext *cct, cap_t &merge_caps)
+ {
+ cap_t proc_caps = nullptr;
+ auto close_caps_on_return = make_scope_guard([&] {
+ if (proc_caps != nullptr) {
+ cap_free(proc_caps);
+ }
+ });
+ bool changed = false;
+ // get process capability set
+ proc_caps = cap_get_proc();
+ if (proc_caps == nullptr) {
+ dout(1) << " cap_get_proc failed with errno: " << errno << dendl;
+ return -errno;
+ }
+ {
+ char *cap_str = cap_to_text(proc_caps, 0);
+ if (cap_str != nullptr){
+ dout(10) << " cap_get_proc yields: " << cap_str << dendl;
+ cap_free(cap_str);
+ }
+ }
+ // iterate over capabilities
+ for (int i = 0; i <= CAP_LAST_CAP; ++i) {
+ cap_flag_value_t val;
+ if (cap_get_flag(merge_caps, i, CAP_PERMITTED, &val) < 0) {
+ return -errno;
+ }
+ if (val == CAP_CLEAR) {
+ if (cap_get_flag(proc_caps, i, CAP_PERMITTED, &val) < 0) {
+ return -errno;
+ }
+ if (val != CAP_CLEAR) {
+ // if bit clear in merged set, but set in process set, clear in process set
+ changed = true;
+ cap_value_t arr[1];
+ arr[0] = i;
+ if (cap_set_flag(proc_caps, CAP_PERMITTED, 1, arr, CAP_CLEAR) < 0) {
+ return -errno;
+ }
+ if (cap_set_flag(proc_caps, CAP_EFFECTIVE, 1, arr, CAP_CLEAR) < 0) {
+ return -errno;
+ }
+ }
+ }
+ }
+ // apply reduced capability set to process
+ if (changed) {
+ char *cap_str = cap_to_text(proc_caps, 0);
+ if (cap_str != nullptr){
+ dout(10) << " new caps for cap_set_proc: " << cap_str << dendl;
+ cap_free(cap_str);
+ }
+ if (cap_set_proc(proc_caps) < 0) {
+ dout(1) << " cap_set_proc failed with errno: " << errno << dendl;
+ return -errno;
+ }
+ }
+ return 0;
+ }
+
+ int limit_caps(CephContext *cct)
+ {
+ cap_t merge_caps = nullptr;
+ auto close_caps_on_return = make_scope_guard([&] {
+ if (merge_caps != nullptr) {
+ cap_free(merge_caps);
+ }
+ });
+ // collect required caps in merge_caps
+ merge_caps = cap_init();
+ if (merge_caps == nullptr) {
+ return -errno;
+ }
+ int rc = get_required_caps(cct, merge_caps);
+ if (rc != 0) {
+ return rc;
+ }
+ return trim_caps(cct, merge_caps);
+ }
+#endif
+
+ // preload set of extblkdev plugins defined in config
+ int preload(CephContext *cct)
+ {
+ const auto& conf = cct->_conf;
+ string plugins = conf.get_val<std::string>("osd_extblkdev_plugins");
+ dout(10) << "starting preload of extblkdev plugins: " << plugins << dendl;
+
+ list<string> plugins_list;
+ get_str_list(plugins, plugins_list);
+
+ auto registry = cct->get_plugin_registry();
+ {
+ std::lock_guard l(registry->lock);
+ for (auto& plg : plugins_list) {
+ dout(10) << "starting load of extblkdev plugin: " << plg << dendl;
+ int rc = registry->load("extblkdev", std::string("ebd_") + plg);
+ if (rc) {
+ derr << __func__ << " failed preloading extblkdev plugin: " << plg << dendl;
+ return rc;
+ }else{
+ dout(10) << "successful load of extblkdev plugin: " << plg << dendl;
+ }
+ }
+ }
+#ifdef __linux__
+ // if we are still running as root, we do not need to trim capabilities
+ // as we are intended to use the privileges
+ if (geteuid() == 0) {
+ return 0;
+ }
+ return limit_caps(cct);
+#else
+ return 0;
+#endif
+ }
+
+
+ // scan extblkdev plugins for support of this device
+ int detect_device(CephContext *cct,
+ const std::string &logdevname,
+ ExtBlkDevInterfaceRef& ebd_impl)
+ {
+ int rc = -ENOENT;
+ std::string plg_name;
+ auto registry = cct->get_plugin_registry();
+ std::lock_guard l(registry->lock);
+ auto ptype = registry->plugins.find("extblkdev");
+ if (ptype == registry->plugins.end()) {
+ return -ENOENT;
+ }
+
+ for (auto& it : ptype->second) {
+
+ dout(10) << __func__ << " Trying to detect block device " << logdevname
+ << " using plugin " << it.first << dendl;
+ auto ebdplugin = dynamic_cast<ExtBlkDevPlugin*>(it.second);
+ if (ebdplugin == nullptr) {
+ derr << __func__ << " Is not an extblkdev plugin: " << it.first << dendl;
+ return -ENOENT;
+ }
+ rc = ebdplugin->factory(logdevname, ebd_impl);
+ if (rc == 0) {
+ plg_name = it.first;
+ break;
+ }
+ }
+ if (rc == 0) {
+ dout(1) << __func__ << " using plugin " << plg_name << ", " << "volume " << ebd_impl->get_devname()
+ << " maps to " << logdevname << dendl;
+ } else {
+ dout(10) << __func__ << " no plugin volume maps to " << logdevname << dendl;
+ }
+ return rc;
+ }
+
+ // release device object
+ int release_device(ExtBlkDevInterfaceRef& ebd_impl)
+ {
+ if (ebd_impl) {
+ ebd_impl.reset();
+ }
+ return 0;
+ }
+
+ }
+}
diff --git a/src/extblkdev/ExtBlkDevPlugin.h b/src/extblkdev/ExtBlkDevPlugin.h
new file mode 100644
index 000000000..beb9e4963
--- /dev/null
+++ b/src/extblkdev/ExtBlkDevPlugin.h
@@ -0,0 +1,38 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph distributed storage system
+ *
+ * (C) Copyright IBM Corporation 2022
+ * Author: Martin Ohmacht <mohmacht@us.ibm.com>
+ *
+ * Based on the file ceph/src/erasure-code/ErasureCodePlugin.h
+ * Copyright (C) 2013,2014 Cloudwatt <libre.licensing@cloudwatt.com>
+ * Copyright (C) 2014 Red Hat <contact@redhat.com>
+ *
+ * Author: Loic Dachary <loic@dachary.org>
+ *
+ * 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.
+ *
+ */
+
+#ifndef CEPH_EXT_BLK_DEV_PLUGIN_H
+#define CEPH_EXT_BLK_DEV_PLUGIN_H
+
+#include "ExtBlkDevInterface.h"
+
+namespace ceph {
+
+ namespace extblkdev {
+ int preload(CephContext *cct);
+ int detect_device(CephContext *cct,
+ const std::string &logdevname,
+ ExtBlkDevInterfaceRef& ebd_impl);
+ int release_device(ExtBlkDevInterfaceRef& ebd_impl);
+ }
+}
+
+#endif
diff --git a/src/extblkdev/vdo/CMakeLists.txt b/src/extblkdev/vdo/CMakeLists.txt
new file mode 100644
index 000000000..60d4f293d
--- /dev/null
+++ b/src/extblkdev/vdo/CMakeLists.txt
@@ -0,0 +1,9 @@
+# vdo plugin
+
+set(vdo_srcs
+ ExtBlkDevPluginVdo.cc
+ ExtBlkDevVdo.cc
+)
+
+add_library(ceph_ebd_vdo SHARED ${vdo_srcs})
+install(TARGETS ceph_ebd_vdo DESTINATION ${extblkdev_plugin_dir})
diff --git a/src/extblkdev/vdo/ExtBlkDevPluginVdo.cc b/src/extblkdev/vdo/ExtBlkDevPluginVdo.cc
new file mode 100644
index 000000000..dbe156182
--- /dev/null
+++ b/src/extblkdev/vdo/ExtBlkDevPluginVdo.cc
@@ -0,0 +1,59 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * (C) Copyright IBM Corporation 2022
+ * Author: Martin Ohmacht <mohmacht@us.ibm.com>
+ *
+ * Based on the file src/erasure-code/clay/ErasureCodePluginClay.cc
+ * Copyright (C) 2018 Indian Institute of Science <office.ece@iisc.ac.in>
+ *
+ * Author: Myna Vajha <mynaramana@gmail.com>
+ *
+ * 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.
+ *
+ */
+
+#include "ceph_ver.h"
+#include "ExtBlkDevPluginVdo.h"
+#include "common/ceph_context.h"
+
+
+// This plugin does not require any capabilities to be set
+int ExtBlkDevPluginVdo::get_required_cap_set(cap_t caps)
+{
+ return 0;
+}
+
+
+int ExtBlkDevPluginVdo::factory(const std::string& logdevname,
+ ceph::ExtBlkDevInterfaceRef& ext_blk_dev)
+{
+ auto vdo = new ExtBlkDevVdo(cct);
+ int r = vdo->init(logdevname);
+ if (r != 0) {
+ delete vdo;
+ return r;
+ }
+ ext_blk_dev.reset(vdo);
+ return 0;
+};
+
+const char *__ceph_plugin_version() { return CEPH_GIT_NICE_VER; }
+
+int __ceph_plugin_init(CephContext *cct,
+ const std::string& type,
+ const std::string& name)
+{
+ auto plg = new ExtBlkDevPluginVdo(cct);
+ if(plg == 0) return -ENOMEM;
+ int rc = cct->get_plugin_registry()->add(type, name, plg);
+ if(rc != 0){
+ delete plg;
+ }
+ return rc;
+}
diff --git a/src/extblkdev/vdo/ExtBlkDevPluginVdo.h b/src/extblkdev/vdo/ExtBlkDevPluginVdo.h
new file mode 100644
index 000000000..784f642ec
--- /dev/null
+++ b/src/extblkdev/vdo/ExtBlkDevPluginVdo.h
@@ -0,0 +1,34 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph distributed storage system
+ *
+ * (C) Copyright IBM Corporation 2022
+ * Author: Martin Ohmacht <mohmacht@us.ibm.com>
+ *
+ * Based on the file src/erasure-code/clay/ErasureCodePluginClay.h
+ * Copyright (C) 2018 Indian Institute of Science <office.ece@iisc.ac.in>
+ *
+ * Author: Myna Vajha <mynaramana@gmail.com>
+ *
+ * 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.
+ *
+ */
+
+#ifndef CEPH_EXT_BLK_DEV_PLUGIN_VDO_H
+#define CEPH_EXT_BLK_DEV_PLUGIN_VDO_H
+
+#include "ExtBlkDevVdo.h"
+
+class ExtBlkDevPluginVdo : public ceph::ExtBlkDevPlugin {
+public:
+ explicit ExtBlkDevPluginVdo(CephContext *cct) : ExtBlkDevPlugin(cct) {}
+ int get_required_cap_set(cap_t caps) override;
+ int factory(const std::string& logdevname,
+ ceph::ExtBlkDevInterfaceRef& ext_blk_dev) override;
+};
+
+#endif
diff --git a/src/extblkdev/vdo/ExtBlkDevVdo.cc b/src/extblkdev/vdo/ExtBlkDevVdo.cc
new file mode 100644
index 000000000..c40cd1a1a
--- /dev/null
+++ b/src/extblkdev/vdo/ExtBlkDevVdo.cc
@@ -0,0 +1,156 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * (C) Copyright IBM Corporation 2022
+ * Author: Martin Ohmacht <mohmacht@us.ibm.com>
+ *
+ * Based on the file ceph/src/common/blkdev.cc
+ * Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation. See file COPYING.
+ *
+ */
+
+
+#include "ExtBlkDevVdo.h"
+#include "common/blkdev.h"
+#include "include/stringify.h"
+#include <errno.h>
+#include "common/debug.h"
+
+#define dout_subsys ceph_subsys_bdev
+#define dout_context cct
+#undef dout_prefix
+#define dout_prefix *_dout << "vdo(" << this << ") "
+
+
+int ExtBlkDevVdo::_get_vdo_stats_handle(const std::string& devname)
+{
+ int rc = -ENOENT;
+ dout(10) << __func__ << " VDO init checking device: " << devname << dendl;
+
+ // we need to go from the raw devname (e.g., dm-4) to the VDO volume name.
+ // currently the best way seems to be to look at /dev/mapper/* ...
+ std::string expect = std::string("../") + devname; // expected symlink target
+ DIR *dir = ::opendir("/dev/mapper");
+ if (!dir) {
+ return -errno;
+ }
+ struct dirent *de = nullptr;
+ while ((de = ::readdir(dir))) {
+ if (de->d_name[0] == '.')
+ continue;
+ char fn[4096], target[4096];
+ snprintf(fn, sizeof(fn), "/dev/mapper/%s", de->d_name);
+ int r = readlink(fn, target, sizeof(target));
+ if (r < 0 || r >= (int)sizeof(target))
+ continue;
+ target[r] = 0;
+ if (expect == target) {
+ snprintf(fn, sizeof(fn), "/sys/kvdo/%s/statistics", de->d_name);
+ int vdo_fd = ::open(fn, O_RDONLY|O_CLOEXEC);
+ if (vdo_fd >= 0) {
+ name = de->d_name;
+ vdo_dir_fd = vdo_fd;
+ rc = 0;
+ break;
+ }
+ }
+ }
+ closedir(dir);
+ return rc;
+}
+
+int ExtBlkDevVdo::get_vdo_stats_handle()
+{
+ std::set<std::string> devs = { logdevname };
+ while (!devs.empty()) {
+ std::string dev = *devs.begin();
+ devs.erase(devs.begin());
+ int rc = _get_vdo_stats_handle(dev);
+ if (rc == 0) {
+ // yay, it's vdo
+ return rc;
+ }
+ // ok, see if there are constituent devices
+ if (dev.find("dm-") == 0) {
+ get_dm_parents(dev, &devs);
+ }
+ }
+ return -ENOENT;
+}
+
+int64_t ExtBlkDevVdo::get_vdo_stat(const char *property)
+{
+ int64_t ret = 0;
+ int fd = ::openat(vdo_dir_fd, property, O_RDONLY|O_CLOEXEC);
+ if (fd < 0) {
+ return 0;
+ }
+ char buf[1024];
+ int r = ::read(fd, buf, sizeof(buf) - 1);
+ if (r > 0) {
+ buf[r] = 0;
+ ret = atoll(buf);
+ }
+ VOID_TEMP_FAILURE_RETRY(::close(fd));
+ return ret;
+}
+
+
+int ExtBlkDevVdo::init(const std::string& alogdevname)
+{
+ logdevname = alogdevname;
+ // get directory handle for VDO metadata
+ return get_vdo_stats_handle();
+}
+
+
+int ExtBlkDevVdo::get_state(ceph::ExtBlkDevState& state)
+{
+ int64_t block_size = get_vdo_stat("block_size");
+ int64_t physical_blocks = get_vdo_stat("physical_blocks");
+ int64_t overhead_blocks_used = get_vdo_stat("overhead_blocks_used");
+ int64_t data_blocks_used = get_vdo_stat("data_blocks_used");
+ int64_t logical_blocks = get_vdo_stat("logical_blocks");
+ int64_t logical_blocks_used = get_vdo_stat("logical_blocks_used");
+ if (!block_size
+ || !physical_blocks
+ || !overhead_blocks_used
+ || !data_blocks_used
+ || !logical_blocks) {
+ dout(1) << __func__ << " VDO sysfs provided zero value for at least one statistic: " << dendl;
+ dout(1) << __func__ << " VDO block_size: " << block_size << dendl;
+ dout(1) << __func__ << " VDO physical_blocks: " << physical_blocks << dendl;
+ dout(1) << __func__ << " VDO overhead_blocks_used: " << overhead_blocks_used << dendl;
+ dout(1) << __func__ << " VDO data_blocks_used: " << data_blocks_used << dendl;
+ dout(1) << __func__ << " VDO logical_blocks: " << logical_blocks << dendl;
+ return -1;
+ }
+ int64_t avail_blocks =
+ physical_blocks - overhead_blocks_used - data_blocks_used;
+ int64_t logical_avail_blocks =
+ logical_blocks - logical_blocks_used;
+ state.set_logical_total(block_size * logical_blocks);
+ state.set_logical_avail(block_size * logical_avail_blocks);
+ state.set_physical_total(block_size * physical_blocks);
+ state.set_physical_avail(block_size * avail_blocks);
+ return 0;
+}
+
+int ExtBlkDevVdo::collect_metadata(const std::string& prefix, std::map<std::string,std::string> *pm)
+{
+ ceph::ExtBlkDevState state;
+ int rc = get_state(state);
+ if(rc != 0){
+ return rc;
+ }
+ (*pm)[prefix + "vdo"] = "true";
+ (*pm)[prefix + "vdo_physical_size"] = stringify(state.get_physical_total());
+ return 0;
+}
diff --git a/src/extblkdev/vdo/ExtBlkDevVdo.h b/src/extblkdev/vdo/ExtBlkDevVdo.h
new file mode 100644
index 000000000..09865a27e
--- /dev/null
+++ b/src/extblkdev/vdo/ExtBlkDevVdo.h
@@ -0,0 +1,52 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * (C) Copyright IBM Corporation 2022
+ * Author: Martin Ohmacht <mohmacht@us.ibm.com>
+ *
+ * Based on the file ceph/src/common/blkdev.cc
+ * Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
+ *
+ * And also based on the file src/erasure-code/clay/ErasureCodeClay.h
+ * Copyright (C) 2018 Indian Institute of Science <office.ece@iisc.ac.in>
+ *
+ * Author: Myna Vajha <mynaramana@gmail.com>
+ *
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation. See file COPYING.
+ *
+ */
+
+#ifndef CEPH_EXT_BLK_DEV_VDO_H
+#define CEPH_EXT_BLK_DEV_VDO_H
+
+#include "extblkdev/ExtBlkDevInterface.h"
+#include "include/compat.h"
+
+class ExtBlkDevVdo final : public ceph::ExtBlkDevInterface
+{
+ int vdo_dir_fd = -1; ///< fd for vdo sysfs directory
+ std::string name; // name of the underlying vdo device
+ std::string logdevname; // name of the top level logical device
+ CephContext *cct;
+public:
+ explicit ExtBlkDevVdo(CephContext *cct) : cct(cct) {}
+ ~ExtBlkDevVdo(){
+ if(vdo_dir_fd >= 0)
+ VOID_TEMP_FAILURE_RETRY(::close(vdo_dir_fd));
+ }
+ int _get_vdo_stats_handle(const std::string& devname);
+ int get_vdo_stats_handle();
+ int64_t get_vdo_stat(const char *property);
+ virtual int init(const std::string& logdevname);
+ virtual const std::string& get_devname() const {return name;}
+ virtual int get_state(ceph::ExtBlkDevState& state);
+ virtual int collect_metadata(const std::string& prefix, std::map<std::string,std::string> *pm);
+};
+
+#endif