]> git.proxmox.com Git - ceph.git/blob - ceph/src/common/PluginRegistry.cc
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / common / PluginRegistry.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4 * Ceph distributed storage system
5 *
6 * Copyright (C) 2013,2014 Cloudwatt <libre.licensing@cloudwatt.com>
7 * Copyright (C) 2014 Red Hat <contact@redhat.com>
8 *
9 * Author: Loic Dachary <loic@dachary.org>
10 *
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
15 *
16 */
17
18 #include <errno.h>
19 #include <dlfcn.h>
20
21 #include "PluginRegistry.h"
22 #include "ceph_ver.h"
23 #include "common/ceph_context.h"
24 #include "common/errno.h"
25 #include "include/str_list.h"
26
27 #include "common/debug.h"
28
29 #define PLUGIN_PREFIX "libceph_"
30 #define PLUGIN_SUFFIX ".so"
31 #define PLUGIN_INIT_FUNCTION "__ceph_plugin_init"
32 #define PLUGIN_VERSION_FUNCTION "__ceph_plugin_version"
33
34 #define dout_subsys ceph_subsys_context
35
36 PluginRegistry::PluginRegistry(CephContext *cct) :
37 cct(cct),
38 lock("PluginRegistry::lock"),
39 loading(false),
40 disable_dlclose(false)
41 {
42 }
43
44 PluginRegistry::~PluginRegistry()
45 {
46 if (disable_dlclose)
47 return;
48
49 for (std::map<std::string,std::map<std::string, Plugin*> >::iterator i =
50 plugins.begin();
51 i != plugins.end();
52 ++i) {
53 for (std::map<std::string,Plugin*>::iterator j = i->second.begin();
54 j != i->second.end(); ++j) {
55 void *library = j->second->library;
56 delete j->second;
57 dlclose(library);
58 }
59 }
60 }
61
62 int PluginRegistry::remove(const std::string& type, const std::string& name)
63 {
64 assert(lock.is_locked());
65
66 std::map<std::string,std::map<std::string,Plugin*> >::iterator i =
67 plugins.find(type);
68 if (i == plugins.end())
69 return -ENOENT;
70 std::map<std::string,Plugin*>::iterator j = i->second.find(name);
71 if (j == i->second.end())
72 return -ENOENT;
73
74 ldout(cct, 1) << __func__ << " " << type << " " << name << dendl;
75 void *library = j->second->library;
76 delete j->second;
77 dlclose(library);
78 i->second.erase(j);
79 if (i->second.empty())
80 plugins.erase(i);
81
82 return 0;
83 }
84
85 int PluginRegistry::add(const std::string& type,
86 const std::string& name,
87 Plugin* plugin)
88 {
89 assert(lock.is_locked());
90 if (plugins.count(type) &&
91 plugins[type].count(name)) {
92 return -EEXIST;
93 }
94 ldout(cct, 1) << __func__ << " " << type << " " << name
95 << " " << plugin << dendl;
96 plugins[type][name] = plugin;
97 return 0;
98 }
99
100 Plugin *PluginRegistry::get_with_load(const std::string& type,
101 const std::string& name)
102 {
103 Mutex::Locker l(lock);
104 Plugin* ret = get(type, name);
105 if (!ret) {
106 int err = load(type, name);
107 if (err == 0)
108 ret = get(type, name);
109 }
110 return ret;
111 }
112
113 Plugin *PluginRegistry::get(const std::string& type,
114 const std::string& name)
115 {
116 assert(lock.is_locked());
117 Plugin *ret = 0;
118
119 std::map<std::string,Plugin*>::iterator j;
120 std::map<std::string,map<std::string,Plugin*> >::iterator i =
121 plugins.find(type);
122 if (i == plugins.end())
123 goto out;
124 j = i->second.find(name);
125 if (j == i->second.end())
126 goto out;
127 ret = j->second;
128
129 out:
130 ldout(cct, 1) << __func__ << " " << type << " " << name
131 << " = " << ret << dendl;
132 return ret;
133 }
134
135 int PluginRegistry::load(const std::string &type,
136 const std::string &name)
137 {
138 assert(lock.is_locked());
139 ldout(cct, 1) << __func__ << " " << type << " " << name << dendl;
140
141 // std::string fname = cct->_conf->plugin_dir + "/" + type + "/" PLUGIN_PREFIX
142 // + name + PLUGIN_SUFFIX;
143 std::string fname = cct->_conf->get_val<std::string>("plugin_dir") + "/" + type + "/" + PLUGIN_PREFIX
144 + name + PLUGIN_SUFFIX;
145 void *library = dlopen(fname.c_str(), RTLD_NOW);
146 if (!library) {
147 string err1(dlerror());
148 // fall back to plugin_dir
149 std::string fname2 = cct->_conf->get_val<std::string>("plugin_dir") + "/" + PLUGIN_PREFIX +
150 name + PLUGIN_SUFFIX;
151 library = dlopen(fname2.c_str(), RTLD_NOW);
152 if (!library) {
153 lderr(cct) << __func__
154 << " failed dlopen(): \"" << err1.c_str()
155 << "\" or \"" << dlerror() << "\""
156 << dendl;
157 return -EIO;
158 }
159 }
160
161 const char * (*code_version)() =
162 (const char *(*)())dlsym(library, PLUGIN_VERSION_FUNCTION);
163 if (code_version == NULL) {
164 lderr(cct) << __func__ << " code_version == NULL" << dlerror() << dendl;
165 return -EXDEV;
166 }
167 if (code_version() != string(CEPH_GIT_NICE_VER)) {
168 lderr(cct) << __func__ << " plugin " << fname << " version "
169 << code_version() << " != expected "
170 << CEPH_GIT_NICE_VER << dendl;
171 dlclose(library);
172 return -EXDEV;
173 }
174
175 int (*code_init)(CephContext *,
176 const std::string& type,
177 const std::string& name) =
178 (int (*)(CephContext *,
179 const std::string& type,
180 const std::string& name))dlsym(library, PLUGIN_INIT_FUNCTION);
181 if (code_init) {
182 int r = code_init(cct, type, name);
183 if (r != 0) {
184 lderr(cct) << __func__ << " " << fname << " "
185 << PLUGIN_INIT_FUNCTION << "(" << cct
186 << "," << type << "," << name << "): " << cpp_strerror(r)
187 << dendl;
188 dlclose(library);
189 return r;
190 }
191 } else {
192 lderr(cct) << __func__ << " " << fname << " dlsym(" << PLUGIN_INIT_FUNCTION
193 << "): " << dlerror() << dendl;
194 dlclose(library);
195 return -ENOENT;
196 }
197
198 Plugin *plugin = get(type, name);
199 if (plugin == 0) {
200 lderr(cct) << __func__ << " " << fname << " "
201 << PLUGIN_INIT_FUNCTION << "()"
202 << "did not register plugin type " << type << " name " << name
203 << dendl;
204 dlclose(library);
205 return -EBADF;
206 }
207
208 plugin->library = library;
209
210 ldout(cct, 1) << __func__ << ": " << type << " " << name
211 << " loaded and registered" << dendl;
212 return 0;
213 }
214
215 /*
216 int ErasureCodePluginRegistry::preload(const std::string &plugins,
217 const std::string &directory,
218 ostream &ss)
219 {
220 Mutex::Locker l(lock);
221 list<string> plugins_list;
222 get_str_list(plugins, plugins_list);
223 for (list<string>::iterator i = plugins_list.begin();
224 i != plugins_list.end();
225 ++i) {
226 ErasureCodePlugin *plugin;
227 int r = load(*i, directory, &plugin, ss);
228 if (r)
229 return r;
230 }
231 return 0;
232 }
233 */