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