Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / 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 "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 */