]> git.proxmox.com Git - ceph.git/blame - ceph/src/erasure-code/ErasureCodePlugin.cc
import 15.2.0 Octopus source
[ceph.git] / ceph / src / erasure-code / ErasureCodePlugin.cc
CommitLineData
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
27using 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
38namespace ceph {
39
7c673cae
FG
40ErasureCodePluginRegistry ErasureCodePluginRegistry::singleton;
41
9f95a23c 42ErasureCodePluginRegistry::ErasureCodePluginRegistry() = default;
7c673cae
FG
43
44ErasureCodePluginRegistry::~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
58int 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
71int 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
81ErasureCodePlugin *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
90int 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
120static const char *an_older_version() {
121 return "an older version";
122}
123
124int 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
184int 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}