]>
Commit | Line | Data |
---|---|---|
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 "PluginRegistry.h" | |
19 | #include "ceph_ver.h" | |
20 | #include "common/errno.h" | |
21 | #include "common/debug.h" | |
22 | ||
23 | #include <dlfcn.h> | |
24 | ||
25 | #define PLUGIN_PREFIX "libceph_" | |
26 | #define PLUGIN_SUFFIX ".so" | |
27 | #define PLUGIN_INIT_FUNCTION "__ceph_plugin_init" | |
28 | #define PLUGIN_VERSION_FUNCTION "__ceph_plugin_version" | |
29 | ||
30 | #define dout_subsys ceph_subsys_context | |
31 | ||
32 | PluginRegistry::PluginRegistry(CephContext *cct) : | |
33 | cct(cct), | |
34 | lock("PluginRegistry::lock"), | |
35 | loading(false), | |
36 | disable_dlclose(false) | |
37 | { | |
38 | } | |
39 | ||
40 | PluginRegistry::~PluginRegistry() | |
41 | { | |
42 | if (disable_dlclose) | |
43 | return; | |
44 | ||
45 | for (std::map<std::string,std::map<std::string, Plugin*> >::iterator i = | |
46 | plugins.begin(); | |
47 | i != plugins.end(); | |
48 | ++i) { | |
49 | for (std::map<std::string,Plugin*>::iterator j = i->second.begin(); | |
50 | j != i->second.end(); ++j) { | |
51 | void *library = j->second->library; | |
52 | delete j->second; | |
53 | dlclose(library); | |
54 | } | |
55 | } | |
56 | } | |
57 | ||
58 | int PluginRegistry::remove(const std::string& type, const std::string& name) | |
59 | { | |
60 | assert(lock.is_locked()); | |
61 | ||
62 | std::map<std::string,std::map<std::string,Plugin*> >::iterator i = | |
63 | plugins.find(type); | |
64 | if (i == plugins.end()) | |
65 | return -ENOENT; | |
66 | std::map<std::string,Plugin*>::iterator j = i->second.find(name); | |
67 | if (j == i->second.end()) | |
68 | return -ENOENT; | |
69 | ||
70 | ldout(cct, 1) << __func__ << " " << type << " " << name << dendl; | |
71 | void *library = j->second->library; | |
72 | delete j->second; | |
73 | dlclose(library); | |
74 | i->second.erase(j); | |
75 | if (i->second.empty()) | |
76 | plugins.erase(i); | |
77 | ||
78 | return 0; | |
79 | } | |
80 | ||
81 | int PluginRegistry::add(const std::string& type, | |
82 | const std::string& name, | |
83 | Plugin* plugin) | |
84 | { | |
85 | assert(lock.is_locked()); | |
86 | if (plugins.count(type) && | |
87 | plugins[type].count(name)) { | |
88 | return -EEXIST; | |
89 | } | |
90 | ldout(cct, 1) << __func__ << " " << type << " " << name | |
91 | << " " << plugin << dendl; | |
92 | plugins[type][name] = plugin; | |
93 | return 0; | |
94 | } | |
95 | ||
96 | Plugin *PluginRegistry::get_with_load(const std::string& type, | |
97 | const std::string& name) | |
98 | { | |
99 | Mutex::Locker l(lock); | |
100 | Plugin* ret = get(type, name); | |
101 | if (!ret) { | |
102 | int err = load(type, name); | |
103 | if (err == 0) | |
104 | ret = get(type, name); | |
105 | } | |
106 | return ret; | |
107 | } | |
108 | ||
109 | Plugin *PluginRegistry::get(const std::string& type, | |
110 | const std::string& name) | |
111 | { | |
112 | assert(lock.is_locked()); | |
113 | Plugin *ret = 0; | |
114 | ||
115 | std::map<std::string,Plugin*>::iterator j; | |
116 | std::map<std::string,map<std::string,Plugin*> >::iterator i = | |
117 | plugins.find(type); | |
118 | if (i == plugins.end()) | |
119 | goto out; | |
120 | j = i->second.find(name); | |
121 | if (j == i->second.end()) | |
122 | goto out; | |
123 | ret = j->second; | |
124 | ||
125 | out: | |
126 | ldout(cct, 1) << __func__ << " " << type << " " << name | |
127 | << " = " << ret << dendl; | |
128 | return ret; | |
129 | } | |
130 | ||
131 | int PluginRegistry::load(const std::string &type, | |
132 | const std::string &name) | |
133 | { | |
134 | assert(lock.is_locked()); | |
135 | ldout(cct, 1) << __func__ << " " << type << " " << name << dendl; | |
136 | ||
137 | // std::string fname = cct->_conf->plugin_dir + "/" + type + "/" PLUGIN_PREFIX | |
138 | // + name + PLUGIN_SUFFIX; | |
139 | std::string fname = cct->_conf->get_val<std::string>("plugin_dir") + "/" + type + "/" + PLUGIN_PREFIX | |
140 | + name + PLUGIN_SUFFIX; | |
141 | void *library = dlopen(fname.c_str(), RTLD_NOW); | |
142 | if (!library) { | |
143 | string err1(dlerror()); | |
144 | // fall back to plugin_dir | |
145 | std::string fname2 = cct->_conf->get_val<std::string>("plugin_dir") + "/" + PLUGIN_PREFIX + | |
146 | name + PLUGIN_SUFFIX; | |
147 | library = dlopen(fname2.c_str(), RTLD_NOW); | |
148 | if (!library) { | |
149 | lderr(cct) << __func__ | |
150 | << " failed dlopen(): \"" << err1.c_str() | |
151 | << "\" or \"" << dlerror() << "\"" | |
152 | << dendl; | |
153 | return -EIO; | |
154 | } | |
155 | } | |
156 | ||
157 | const char * (*code_version)() = | |
158 | (const char *(*)())dlsym(library, PLUGIN_VERSION_FUNCTION); | |
159 | if (code_version == NULL) { | |
160 | lderr(cct) << __func__ << " code_version == NULL" << dlerror() << dendl; | |
161 | return -EXDEV; | |
162 | } | |
163 | if (code_version() != string(CEPH_GIT_NICE_VER)) { | |
164 | lderr(cct) << __func__ << " plugin " << fname << " version " | |
165 | << code_version() << " != expected " | |
166 | << CEPH_GIT_NICE_VER << dendl; | |
167 | dlclose(library); | |
168 | return -EXDEV; | |
169 | } | |
170 | ||
171 | int (*code_init)(CephContext *, | |
172 | const std::string& type, | |
173 | const std::string& name) = | |
174 | (int (*)(CephContext *, | |
175 | const std::string& type, | |
176 | const std::string& name))dlsym(library, PLUGIN_INIT_FUNCTION); | |
177 | if (code_init) { | |
178 | int r = code_init(cct, type, name); | |
179 | if (r != 0) { | |
180 | lderr(cct) << __func__ << " " << fname << " " | |
181 | << PLUGIN_INIT_FUNCTION << "(" << cct | |
182 | << "," << type << "," << name << "): " << cpp_strerror(r) | |
183 | << dendl; | |
184 | dlclose(library); | |
185 | return r; | |
186 | } | |
187 | } else { | |
188 | lderr(cct) << __func__ << " " << fname << " dlsym(" << PLUGIN_INIT_FUNCTION | |
189 | << "): " << dlerror() << dendl; | |
190 | dlclose(library); | |
191 | return -ENOENT; | |
192 | } | |
193 | ||
194 | Plugin *plugin = get(type, name); | |
195 | if (plugin == 0) { | |
196 | lderr(cct) << __func__ << " " << fname << " " | |
197 | << PLUGIN_INIT_FUNCTION << "()" | |
198 | << "did not register plugin type " << type << " name " << name | |
199 | << dendl; | |
200 | dlclose(library); | |
201 | return -EBADF; | |
202 | } | |
203 | ||
204 | plugin->library = library; | |
205 | ||
206 | ldout(cct, 1) << __func__ << ": " << type << " " << name | |
207 | << " loaded and registered" << dendl; | |
208 | return 0; | |
209 | } | |
210 | ||
211 | /* | |
212 | int ErasureCodePluginRegistry::preload(const std::string &plugins, | |
213 | const std::string &directory, | |
214 | ostream &ss) | |
215 | { | |
216 | Mutex::Locker l(lock); | |
217 | list<string> plugins_list; | |
218 | get_str_list(plugins, plugins_list); | |
219 | for (list<string>::iterator i = plugins_list.begin(); | |
220 | i != plugins_list.end(); | |
221 | ++i) { | |
222 | ErasureCodePlugin *plugin; | |
223 | int r = load(*i, directory, &plugin, ss); | |
224 | if (r) | |
225 | return r; | |
226 | } | |
227 | return 0; | |
228 | } | |
229 | */ |