// -*- 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 * Copyright (C) 2014 Red Hat * * Author: Loic Dachary * * 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/errno.h" #include "common/debug.h" #include #define PLUGIN_PREFIX "libceph_" #define PLUGIN_SUFFIX ".so" #define PLUGIN_INIT_FUNCTION "__ceph_plugin_init" #define PLUGIN_VERSION_FUNCTION "__ceph_plugin_version" #define dout_subsys ceph_subsys_context PluginRegistry::PluginRegistry(CephContext *cct) : cct(cct), lock("PluginRegistry::lock"), loading(false), disable_dlclose(false) { } PluginRegistry::~PluginRegistry() { if (disable_dlclose) return; for (std::map >::iterator i = plugins.begin(); i != plugins.end(); ++i) { for (std::map::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) { assert(lock.is_locked()); std::map >::iterator i = plugins.find(type); if (i == plugins.end()) return -ENOENT; std::map::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) { assert(lock.is_locked()); 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) { Mutex::Locker 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) { assert(lock.is_locked()); Plugin *ret = 0; std::map::iterator j; std::map >::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) { assert(lock.is_locked()); ldout(cct, 1) << __func__ << " " << type << " " << name << dendl; // std::string fname = cct->_conf->plugin_dir + "/" + type + "/" PLUGIN_PREFIX // + name + PLUGIN_SUFFIX; std::string fname = cct->_conf->get_val("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 std::string fname2 = cct->_conf->get_val("plugin_dir") + "/" + PLUGIN_PREFIX + name + PLUGIN_SUFFIX; library = dlopen(fname2.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) { Mutex::Locker l(lock); list plugins_list; get_str_list(plugins, plugins_list); for (list::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; } */