summaryrefslogtreecommitdiffstats
path: root/src/erasure-code/ErasureCodePlugin.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/erasure-code/ErasureCodePlugin.cc')
-rw-r--r--src/erasure-code/ErasureCodePlugin.cc197
1 files changed, 197 insertions, 0 deletions
diff --git a/src/erasure-code/ErasureCodePlugin.cc b/src/erasure-code/ErasureCodePlugin.cc
new file mode 100644
index 000000000..f189b91fd
--- /dev/null
+++ b/src/erasure-code/ErasureCodePlugin.cc
@@ -0,0 +1,197 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph distributed storage system
+ *
+ * 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 "ErasureCodePlugin.h"
+#include "common/errno.h"
+#include "include/dlfcn_compat.h"
+#include "include/str_list.h"
+#include "include/ceph_assert.h"
+
+using namespace std;
+
+#define PLUGIN_PREFIX "libec_"
+#define PLUGIN_SUFFIX SHARED_LIB_SUFFIX
+#define PLUGIN_INIT_FUNCTION "__erasure_code_init"
+#define PLUGIN_VERSION_FUNCTION "__erasure_code_version"
+
+namespace ceph {
+
+ErasureCodePluginRegistry ErasureCodePluginRegistry::singleton;
+
+ErasureCodePluginRegistry::ErasureCodePluginRegistry() = default;
+
+ErasureCodePluginRegistry::~ErasureCodePluginRegistry()
+{
+ if (disable_dlclose)
+ return;
+
+ for (std::map<std::string,ErasureCodePlugin*>::iterator i = plugins.begin();
+ i != plugins.end();
+ ++i) {
+ void *library = i->second->library;
+ delete i->second;
+ dlclose(library);
+ }
+}
+
+int ErasureCodePluginRegistry::remove(const std::string &name)
+{
+ ceph_assert(ceph_mutex_is_locked(lock));
+ if (plugins.find(name) == plugins.end())
+ return -ENOENT;
+ std::map<std::string,ErasureCodePlugin*>::iterator plugin = plugins.find(name);
+ void *library = plugin->second->library;
+ delete plugin->second;
+ dlclose(library);
+ plugins.erase(plugin);
+ return 0;
+}
+
+int ErasureCodePluginRegistry::add(const std::string &name,
+ ErasureCodePlugin* plugin)
+{
+ ceph_assert(ceph_mutex_is_locked(lock));
+ if (plugins.find(name) != plugins.end())
+ return -EEXIST;
+ plugins[name] = plugin;
+ return 0;
+}
+
+ErasureCodePlugin *ErasureCodePluginRegistry::get(const std::string &name)
+{
+ ceph_assert(ceph_mutex_is_locked(lock));
+ if (plugins.find(name) != plugins.end())
+ return plugins[name];
+ else
+ return 0;
+}
+
+int ErasureCodePluginRegistry::factory(const std::string &plugin_name,
+ const std::string &directory,
+ ErasureCodeProfile &profile,
+ ErasureCodeInterfaceRef *erasure_code,
+ ostream *ss)
+{
+ ErasureCodePlugin *plugin;
+ {
+ std::lock_guard l{lock};
+ plugin = get(plugin_name);
+ if (plugin == 0) {
+ loading = true;
+ int r = load(plugin_name, directory, &plugin, ss);
+ loading = false;
+ if (r != 0)
+ return r;
+ }
+ }
+
+ int r = plugin->factory(directory, profile, erasure_code, ss);
+ if (r)
+ return r;
+ if (profile != (*erasure_code)->get_profile()) {
+ *ss << __func__ << " profile " << profile << " != get_profile() "
+ << (*erasure_code)->get_profile() << std::endl;
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static const char *an_older_version() {
+ return "an older version";
+}
+
+int ErasureCodePluginRegistry::load(const std::string &plugin_name,
+ const std::string &directory,
+ ErasureCodePlugin **plugin,
+ ostream *ss)
+{
+ ceph_assert(ceph_mutex_is_locked(lock));
+ std::string fname = directory + "/" PLUGIN_PREFIX
+ + plugin_name + PLUGIN_SUFFIX;
+ void *library = dlopen(fname.c_str(), RTLD_NOW);
+ if (!library) {
+ *ss << "load dlopen(" << fname << "): " << dlerror();
+ return -EIO;
+ }
+
+ const char * (*erasure_code_version)() =
+ (const char *(*)())dlsym(library, PLUGIN_VERSION_FUNCTION);
+ if (erasure_code_version == NULL)
+ erasure_code_version = an_older_version;
+ if (erasure_code_version() != string(CEPH_GIT_NICE_VER)) {
+ *ss << "expected plugin " << fname << " version " << CEPH_GIT_NICE_VER
+ << " but it claims to be " << erasure_code_version() << " instead";
+ dlclose(library);
+ return -EXDEV;
+ }
+
+ int (*erasure_code_init)(const char *, const char *) =
+ (int (*)(const char *, const char *))dlsym(library, PLUGIN_INIT_FUNCTION);
+ if (erasure_code_init) {
+ std::string name = plugin_name;
+ int r = erasure_code_init(name.c_str(), directory.c_str());
+ if (r != 0) {
+ *ss << "erasure_code_init(" << plugin_name
+ << "," << directory
+ << "): " << cpp_strerror(r);
+ dlclose(library);
+ return r;
+ }
+ } else {
+ *ss << "load dlsym(" << fname
+ << ", " << PLUGIN_INIT_FUNCTION
+ << "): " << dlerror();
+ dlclose(library);
+ return -ENOENT;
+ }
+
+ *plugin = get(plugin_name);
+ if (*plugin == 0) {
+ *ss << "load " << PLUGIN_INIT_FUNCTION << "()"
+ << "did not register " << plugin_name;
+ dlclose(library);
+ return -EBADF;
+ }
+
+ (*plugin)->library = library;
+
+ *ss << __func__ << ": " << plugin_name << " ";
+
+ return 0;
+}
+
+int ErasureCodePluginRegistry::preload(const std::string &plugins,
+ const std::string &directory,
+ ostream *ss)
+{
+ std::lock_guard l{lock};
+ list<string> plugins_list;
+ get_str_list(plugins, plugins_list);
+ for (list<string>::iterator i = plugins_list.begin();
+ i != plugins_list.end();
+ ++i) {
+ ErasureCodePlugin *plugin;
+ int r = load(*i, directory, &plugin, ss);
+ if (r)
+ return r;
+ }
+ return 0;
+}
+}