]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 "ceph_ver.h" | |
22 | #include "ErasureCodePlugin.h" | |
23 | #include "common/errno.h" | |
24 | #include "include/str_list.h" | |
9f95a23c | 25 | #include "include/ceph_assert.h" |
7c673cae | 26 | |
31f18b77 FG |
27 | using namespace std; |
28 | ||
7c673cae | 29 | #define PLUGIN_PREFIX "libec_" |
11fdf7f2 | 30 | #if defined(__APPLE__) |
7c673cae FG |
31 | #define PLUGIN_SUFFIX ".dylib" |
32 | #else | |
33 | #define PLUGIN_SUFFIX ".so" | |
34 | #endif | |
35 | #define PLUGIN_INIT_FUNCTION "__erasure_code_init" | |
36 | #define PLUGIN_VERSION_FUNCTION "__erasure_code_version" | |
37 | ||
9f95a23c TL |
38 | namespace ceph { |
39 | ||
7c673cae FG |
40 | ErasureCodePluginRegistry ErasureCodePluginRegistry::singleton; |
41 | ||
9f95a23c | 42 | ErasureCodePluginRegistry::ErasureCodePluginRegistry() = default; |
7c673cae FG |
43 | |
44 | ErasureCodePluginRegistry::~ErasureCodePluginRegistry() | |
45 | { | |
46 | if (disable_dlclose) | |
47 | return; | |
48 | ||
49 | for (std::map<std::string,ErasureCodePlugin*>::iterator i = plugins.begin(); | |
50 | i != plugins.end(); | |
51 | ++i) { | |
52 | void *library = i->second->library; | |
53 | delete i->second; | |
54 | dlclose(library); | |
55 | } | |
56 | } | |
57 | ||
58 | int ErasureCodePluginRegistry::remove(const std::string &name) | |
59 | { | |
9f95a23c | 60 | ceph_assert(ceph_mutex_is_locked(lock)); |
7c673cae FG |
61 | if (plugins.find(name) == plugins.end()) |
62 | return -ENOENT; | |
63 | std::map<std::string,ErasureCodePlugin*>::iterator plugin = plugins.find(name); | |
64 | void *library = plugin->second->library; | |
65 | delete plugin->second; | |
66 | dlclose(library); | |
67 | plugins.erase(plugin); | |
68 | return 0; | |
69 | } | |
70 | ||
71 | int ErasureCodePluginRegistry::add(const std::string &name, | |
72 | ErasureCodePlugin* plugin) | |
73 | { | |
9f95a23c | 74 | ceph_assert(ceph_mutex_is_locked(lock)); |
7c673cae FG |
75 | if (plugins.find(name) != plugins.end()) |
76 | return -EEXIST; | |
77 | plugins[name] = plugin; | |
78 | return 0; | |
79 | } | |
80 | ||
81 | ErasureCodePlugin *ErasureCodePluginRegistry::get(const std::string &name) | |
82 | { | |
9f95a23c | 83 | ceph_assert(ceph_mutex_is_locked(lock)); |
7c673cae FG |
84 | if (plugins.find(name) != plugins.end()) |
85 | return plugins[name]; | |
86 | else | |
87 | return 0; | |
88 | } | |
89 | ||
90 | int ErasureCodePluginRegistry::factory(const std::string &plugin_name, | |
91 | const std::string &directory, | |
92 | ErasureCodeProfile &profile, | |
93 | ErasureCodeInterfaceRef *erasure_code, | |
94 | ostream *ss) | |
95 | { | |
96 | ErasureCodePlugin *plugin; | |
97 | { | |
9f95a23c | 98 | std::lock_guard l{lock}; |
7c673cae FG |
99 | plugin = get(plugin_name); |
100 | if (plugin == 0) { | |
101 | loading = true; | |
102 | int r = load(plugin_name, directory, &plugin, ss); | |
103 | loading = false; | |
104 | if (r != 0) | |
105 | return r; | |
106 | } | |
107 | } | |
108 | ||
109 | int r = plugin->factory(directory, profile, erasure_code, ss); | |
110 | if (r) | |
111 | return r; | |
112 | if (profile != (*erasure_code)->get_profile()) { | |
113 | *ss << __func__ << " profile " << profile << " != get_profile() " | |
114 | << (*erasure_code)->get_profile() << std::endl; | |
115 | return -EINVAL; | |
116 | } | |
117 | return 0; | |
118 | } | |
119 | ||
120 | static const char *an_older_version() { | |
121 | return "an older version"; | |
122 | } | |
123 | ||
124 | int ErasureCodePluginRegistry::load(const std::string &plugin_name, | |
125 | const std::string &directory, | |
126 | ErasureCodePlugin **plugin, | |
127 | ostream *ss) | |
128 | { | |
9f95a23c | 129 | ceph_assert(ceph_mutex_is_locked(lock)); |
7c673cae FG |
130 | std::string fname = directory + "/" PLUGIN_PREFIX |
131 | + plugin_name + PLUGIN_SUFFIX; | |
132 | void *library = dlopen(fname.c_str(), RTLD_NOW); | |
133 | if (!library) { | |
134 | *ss << "load dlopen(" << fname << "): " << dlerror(); | |
135 | return -EIO; | |
136 | } | |
137 | ||
138 | const char * (*erasure_code_version)() = | |
139 | (const char *(*)())dlsym(library, PLUGIN_VERSION_FUNCTION); | |
140 | if (erasure_code_version == NULL) | |
141 | erasure_code_version = an_older_version; | |
142 | if (erasure_code_version() != string(CEPH_GIT_NICE_VER)) { | |
143 | *ss << "expected plugin " << fname << " version " << CEPH_GIT_NICE_VER | |
144 | << " but it claims to be " << erasure_code_version() << " instead"; | |
145 | dlclose(library); | |
146 | return -EXDEV; | |
147 | } | |
148 | ||
149 | int (*erasure_code_init)(const char *, const char *) = | |
150 | (int (*)(const char *, const char *))dlsym(library, PLUGIN_INIT_FUNCTION); | |
151 | if (erasure_code_init) { | |
152 | std::string name = plugin_name; | |
153 | int r = erasure_code_init(name.c_str(), directory.c_str()); | |
154 | if (r != 0) { | |
155 | *ss << "erasure_code_init(" << plugin_name | |
156 | << "," << directory | |
157 | << "): " << cpp_strerror(r); | |
158 | dlclose(library); | |
159 | return r; | |
160 | } | |
161 | } else { | |
162 | *ss << "load dlsym(" << fname | |
163 | << ", " << PLUGIN_INIT_FUNCTION | |
164 | << "): " << dlerror(); | |
165 | dlclose(library); | |
166 | return -ENOENT; | |
167 | } | |
168 | ||
169 | *plugin = get(plugin_name); | |
170 | if (*plugin == 0) { | |
171 | *ss << "load " << PLUGIN_INIT_FUNCTION << "()" | |
172 | << "did not register " << plugin_name; | |
173 | dlclose(library); | |
174 | return -EBADF; | |
175 | } | |
176 | ||
177 | (*plugin)->library = library; | |
178 | ||
179 | *ss << __func__ << ": " << plugin_name << " "; | |
180 | ||
181 | return 0; | |
182 | } | |
183 | ||
184 | int ErasureCodePluginRegistry::preload(const std::string &plugins, | |
185 | const std::string &directory, | |
186 | ostream *ss) | |
187 | { | |
9f95a23c | 188 | std::lock_guard l{lock}; |
7c673cae FG |
189 | list<string> plugins_list; |
190 | get_str_list(plugins, plugins_list); | |
191 | for (list<string>::iterator i = plugins_list.begin(); | |
192 | i != plugins_list.end(); | |
193 | ++i) { | |
194 | ErasureCodePlugin *plugin; | |
195 | int r = load(*i, directory, &plugin, ss); | |
196 | if (r) | |
197 | return r; | |
198 | } | |
199 | return 0; | |
200 | } | |
9f95a23c | 201 | } |