summaryrefslogtreecommitdiffstats
path: root/src/common/PluginRegistry.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/PluginRegistry.cc')
-rw-r--r--src/common/PluginRegistry.cc232
1 files changed, 232 insertions, 0 deletions
diff --git a/src/common/PluginRegistry.cc b/src/common/PluginRegistry.cc
new file mode 100644
index 000000000..dd85d64fd
--- /dev/null
+++ b/src/common/PluginRegistry.cc
@@ -0,0 +1,232 @@
+// -*- 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 "PluginRegistry.h"
+#include "ceph_ver.h"
+#include "common/ceph_context.h"
+#include "common/errno.h"
+#include "common/debug.h"
+#include "include/dlfcn_compat.h"
+
+#define PLUGIN_PREFIX "libceph_"
+#define PLUGIN_SUFFIX SHARED_LIB_SUFFIX
+#define PLUGIN_INIT_FUNCTION "__ceph_plugin_init"
+#define PLUGIN_VERSION_FUNCTION "__ceph_plugin_version"
+
+#define dout_subsys ceph_subsys_context
+
+using std::map;
+using std::string;
+
+namespace ceph {
+
+PluginRegistry::PluginRegistry(CephContext *cct) :
+ cct(cct),
+ loading(false),
+ disable_dlclose(false)
+{
+}
+
+PluginRegistry::~PluginRegistry()
+{
+ if (disable_dlclose)
+ return;
+
+ for (std::map<std::string,std::map<std::string, Plugin*> >::iterator i =
+ plugins.begin();
+ i != plugins.end();
+ ++i) {
+ for (std::map<std::string,Plugin*>::iterator j = i->second.begin();
+ j != i->second.end(); ++j) {
+ void *library = j->second->library;
+ delete j->second;
+ dlclose(library);
+ }
+ }
+}
+
+int PluginRegistry::remove(const std::string& type, const std::string& name)
+{
+ ceph_assert(ceph_mutex_is_locked(lock));
+
+ std::map<std::string,std::map<std::string,Plugin*> >::iterator i =
+ plugins.find(type);
+ if (i == plugins.end())
+ return -ENOENT;
+ std::map<std::string,Plugin*>::iterator j = i->second.find(name);
+ if (j == i->second.end())
+ return -ENOENT;
+
+ ldout(cct, 1) << __func__ << " " << type << " " << name << dendl;
+ void *library = j->second->library;
+ delete j->second;
+ dlclose(library);
+ i->second.erase(j);
+ if (i->second.empty())
+ plugins.erase(i);
+
+ return 0;
+}
+
+int PluginRegistry::add(const std::string& type,
+ const std::string& name,
+ Plugin* plugin)
+{
+ ceph_assert(ceph_mutex_is_locked(lock));
+ if (plugins.count(type) &&
+ plugins[type].count(name)) {
+ return -EEXIST;
+ }
+ ldout(cct, 1) << __func__ << " " << type << " " << name
+ << " " << plugin << dendl;
+ plugins[type][name] = plugin;
+ return 0;
+}
+
+Plugin *PluginRegistry::get_with_load(const std::string& type,
+ const std::string& name)
+{
+ std::lock_guard l(lock);
+ Plugin* ret = get(type, name);
+ if (!ret) {
+ int err = load(type, name);
+ if (err == 0)
+ ret = get(type, name);
+ }
+ return ret;
+}
+
+Plugin *PluginRegistry::get(const std::string& type,
+ const std::string& name)
+{
+ ceph_assert(ceph_mutex_is_locked(lock));
+ Plugin *ret = 0;
+
+ std::map<std::string,Plugin*>::iterator j;
+ std::map<std::string,map<std::string,Plugin*> >::iterator i =
+ plugins.find(type);
+ if (i == plugins.end())
+ goto out;
+ j = i->second.find(name);
+ if (j == i->second.end())
+ goto out;
+ ret = j->second;
+
+ out:
+ ldout(cct, 1) << __func__ << " " << type << " " << name
+ << " = " << ret << dendl;
+ return ret;
+}
+
+int PluginRegistry::load(const std::string &type,
+ const std::string &name)
+{
+ ceph_assert(ceph_mutex_is_locked(lock));
+ ldout(cct, 1) << __func__ << " " << type << " " << name << dendl;
+
+ std::string fname = cct->_conf.get_val<std::string>("plugin_dir") + "/" + type + "/" + PLUGIN_PREFIX
+ + name + PLUGIN_SUFFIX;
+ void *library = dlopen(fname.c_str(), RTLD_NOW);
+ if (!library) {
+ string err1(dlerror());
+ // fall back to plugin_dir
+ fname = cct->_conf.get_val<std::string>("plugin_dir") + "/" + PLUGIN_PREFIX +
+ name + PLUGIN_SUFFIX;
+ library = dlopen(fname.c_str(), RTLD_NOW);
+ if (!library) {
+ lderr(cct) << __func__
+ << " failed dlopen(): \"" << err1.c_str()
+ << "\" or \"" << dlerror() << "\""
+ << dendl;
+ return -EIO;
+ }
+ }
+
+ const char * (*code_version)() =
+ (const char *(*)())dlsym(library, PLUGIN_VERSION_FUNCTION);
+ if (code_version == NULL) {
+ lderr(cct) << __func__ << " code_version == NULL" << dlerror() << dendl;
+ return -EXDEV;
+ }
+ if (code_version() != string(CEPH_GIT_NICE_VER)) {
+ lderr(cct) << __func__ << " plugin " << fname << " version "
+ << code_version() << " != expected "
+ << CEPH_GIT_NICE_VER << dendl;
+ dlclose(library);
+ return -EXDEV;
+ }
+
+ int (*code_init)(CephContext *,
+ const std::string& type,
+ const std::string& name) =
+ (int (*)(CephContext *,
+ const std::string& type,
+ const std::string& name))dlsym(library, PLUGIN_INIT_FUNCTION);
+ if (code_init) {
+ int r = code_init(cct, type, name);
+ if (r != 0) {
+ lderr(cct) << __func__ << " " << fname << " "
+ << PLUGIN_INIT_FUNCTION << "(" << cct
+ << "," << type << "," << name << "): " << cpp_strerror(r)
+ << dendl;
+ dlclose(library);
+ return r;
+ }
+ } else {
+ lderr(cct) << __func__ << " " << fname << " dlsym(" << PLUGIN_INIT_FUNCTION
+ << "): " << dlerror() << dendl;
+ dlclose(library);
+ return -ENOENT;
+ }
+
+ Plugin *plugin = get(type, name);
+ if (plugin == 0) {
+ lderr(cct) << __func__ << " " << fname << " "
+ << PLUGIN_INIT_FUNCTION << "()"
+ << "did not register plugin type " << type << " name " << name
+ << dendl;
+ dlclose(library);
+ return -EBADF;
+ }
+
+ plugin->library = library;
+
+ ldout(cct, 1) << __func__ << ": " << type << " " << name
+ << " loaded and registered" << dendl;
+ 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;
+}
+*/