diff options
Diffstat (limited to '')
-rw-r--r-- | src/common/PluginRegistry.cc | 232 |
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; +} +*/ |