1 /*
2 * lock_manager.c: Implements the internal lock manager API
3 *
4 * Copyright (C) 2010-2011 Red Hat, Inc.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21
22 #include <config.h>
23
24 #include "lock_manager.h"
25 #include "lock_driver_nop.h"
26 #include "virerror.h"
27 #include "virfile.h"
28 #include "virlog.h"
29 #include "viralloc.h"
30 #include "viruuid.h"
31 #include "virstring.h"
32
33 #if WITH_DLFCN_H
34 # include <dlfcn.h>
35 #endif
36 #include <unistd.h>
37
38 #include "configmake.h"
39
40 #define VIR_FROM_THIS VIR_FROM_LOCKING
41
42 VIR_LOG_INIT("locking.lock_manager");
43
44 #define CHECK_DRIVER(field, errret) \
45 if (!driver->field) { \
46 virReportError(VIR_ERR_INTERNAL_ERROR, \
47 _("Missing '%s' field in lock manager driver"), \
48 #field); \
49 return errret; \
50 }
51
52 #define CHECK_MANAGER(field, errret) \
53 if (!lock->driver->field) { \
54 virReportError(VIR_ERR_INTERNAL_ERROR, \
55 _("Missing '%s' field in lock manager driver"), \
56 #field); \
57 return errret; \
58 }
59
60 struct _virLockManagerPlugin {
61 char *name;
62 virLockDriver *driver;
63 void *handle;
64 int refs;
65 };
66
virLockManagerLogParams(size_t nparams,virLockManagerParam * params)67 static void virLockManagerLogParams(size_t nparams,
68 virLockManagerParam *params)
69 {
70 size_t i;
71 char uuidstr[VIR_UUID_STRING_BUFLEN];
72 for (i = 0; i < nparams; i++) {
73 switch (params[i].type) {
74 case VIR_LOCK_MANAGER_PARAM_TYPE_INT:
75 VIR_DEBUG(" key=%s type=int value=%d", params[i].key, params[i].value.iv);
76 break;
77 case VIR_LOCK_MANAGER_PARAM_TYPE_UINT:
78 VIR_DEBUG(" key=%s type=uint value=%u", params[i].key, params[i].value.ui);
79 break;
80 case VIR_LOCK_MANAGER_PARAM_TYPE_LONG:
81 VIR_DEBUG(" key=%s type=long value=%lld", params[i].key, params[i].value.l);
82 break;
83 case VIR_LOCK_MANAGER_PARAM_TYPE_ULONG:
84 VIR_DEBUG(" key=%s type=ulong value=%llu", params[i].key, params[i].value.ul);
85 break;
86 case VIR_LOCK_MANAGER_PARAM_TYPE_DOUBLE:
87 VIR_DEBUG(" key=%s type=double value=%lf", params[i].key, params[i].value.d);
88 break;
89 case VIR_LOCK_MANAGER_PARAM_TYPE_STRING:
90 VIR_DEBUG(" key=%s type=string value=%s", params[i].key, params[i].value.str);
91 break;
92 case VIR_LOCK_MANAGER_PARAM_TYPE_CSTRING:
93 VIR_DEBUG(" key=%s type=cstring value=%s", params[i].key, params[i].value.cstr);
94 break;
95 case VIR_LOCK_MANAGER_PARAM_TYPE_UUID:
96 virUUIDFormat(params[i].value.uuid, uuidstr);
97 VIR_DEBUG(" key=%s type=uuid value=%s", params[i].key, uuidstr);
98 break;
99 }
100 }
101 }
102
103
104 /**
105 * virLockManagerPluginNew:
106 * @name: the name of the plugin
107 * @flag: optional plugin flags
108 *
109 * Attempt to load the plugin $(libdir)/libvirt/lock-driver/@name.so
110 * The plugin driver entry point will be resolved & invoked to obtain
111 * the lock manager driver.
112 *
113 * Even if the loading of the plugin succeeded, this may still
114 * return NULL if the plugin impl decided that we (libvirtd)
115 * are too old to support a feature it requires
116 *
117 * Returns a plugin object, or NULL if loading failed.
118 */
119 #if WITH_DLFCN_H
virLockManagerPluginNew(const char * name,const char * driverName,const char * configDir,unsigned int flags)120 virLockManagerPlugin *virLockManagerPluginNew(const char *name,
121 const char *driverName,
122 const char *configDir,
123 unsigned int flags)
124 {
125 void *handle = NULL;
126 virLockDriver *driver;
127 virLockManagerPlugin *plugin = NULL;
128 char *modfile = NULL;
129 char *configFile = NULL;
130
131 VIR_DEBUG("name=%s driverName=%s configDir=%s flags=0x%x",
132 name, driverName, configDir, flags);
133
134 configFile = g_strdup_printf("%s/%s-%s.conf", configDir, driverName, name);
135
136 if (STREQ(name, "nop")) {
137 driver = &virLockDriverNop;
138 } else {
139 if (!(modfile = virFileFindResourceFull(name,
140 NULL,
141 VIR_FILE_MODULE_EXT,
142 abs_top_builddir "/src",
143 LIBDIR "/libvirt/lock-driver",
144 "LIBVIRT_LOCK_MANAGER_PLUGIN_DIR")))
145 goto cleanup;
146
147 VIR_DEBUG("Module load %s from %s", name, modfile);
148
149 if (access(modfile, R_OK) < 0) {
150 virReportSystemError(errno,
151 _("Plugin %s not accessible"),
152 modfile);
153 goto cleanup;
154 }
155
156 handle = dlopen(modfile, RTLD_NOW | RTLD_LOCAL);
157 if (!handle) {
158 virReportError(VIR_ERR_SYSTEM_ERROR,
159 _("Failed to load plugin %s: %s"),
160 modfile, dlerror());
161 goto cleanup;
162 }
163
164 if (!(driver = dlsym(handle, "virLockDriverImpl"))) {
165 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
166 _("Missing plugin initialization symbol 'virLockDriverImpl'"));
167 goto cleanup;
168 }
169 }
170
171 if (driver->drvInit(VIR_LOCK_MANAGER_VERSION, configFile, flags) < 0)
172 goto cleanup;
173
174 plugin = g_new0(virLockManagerPlugin, 1);
175
176 plugin->driver = driver;
177 plugin->handle = handle;
178 plugin->refs = 1;
179 plugin->name = g_strdup(name);
180
181 VIR_FREE(configFile);
182 VIR_FREE(modfile);
183 return plugin;
184
185 cleanup:
186 VIR_FREE(configFile);
187 VIR_FREE(plugin);
188 VIR_FREE(modfile);
189 if (handle)
190 dlclose(handle);
191 return NULL;
192 }
193 #else /* !WITH_DLFCN_H */
194 virLockManagerPlugin *
virLockManagerPluginNew(const char * name G_GNUC_UNUSED,const char * driverName G_GNUC_UNUSED,const char * configDir G_GNUC_UNUSED,unsigned int flags_unused G_GNUC_UNUSED)195 virLockManagerPluginNew(const char *name G_GNUC_UNUSED,
196 const char *driverName G_GNUC_UNUSED,
197 const char *configDir G_GNUC_UNUSED,
198 unsigned int flags_unused G_GNUC_UNUSED)
199 {
200 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
201 _("this platform is missing dlopen"));
202 return NULL;
203 }
204 #endif /* !WITH_DLFCN_H */
205
206
207 /**
208 * virLockManagerPluginRef:
209 * @plugin: the plugin implementation to ref
210 *
211 * Acquires an additional reference on the plugin.
212 */
virLockManagerPluginRef(virLockManagerPlugin * plugin)213 void virLockManagerPluginRef(virLockManagerPlugin *plugin)
214 {
215 plugin->refs++;
216 }
217
218
219 /**
220 * virLockManagerPluginUnref:
221 * @plugin: the plugin implementation to unref
222 *
223 * Releases a reference on the plugin. When the last reference
224 * is released, it will attempt to unload the plugin from memory.
225 * The plugin may refuse to allow unloading if this would
226 * result in an unsafe scenario.
227 *
228 */
229 #if WITH_DLFCN_H
virLockManagerPluginUnref(virLockManagerPlugin * plugin)230 void virLockManagerPluginUnref(virLockManagerPlugin *plugin)
231 {
232 if (!plugin)
233 return;
234
235 plugin->refs--;
236
237 if (plugin->refs > 0)
238 return;
239
240 if (plugin->driver->drvDeinit() >= 0) {
241 if (plugin->handle)
242 dlclose(plugin->handle);
243 } else {
244 VIR_WARN("Unable to unload lock maanger plugin from memory");
245 return;
246 }
247
248 g_free(plugin->name);
249 g_free(plugin);
250 }
251 #else /* !WITH_DLFCN_H */
virLockManagerPluginUnref(virLockManagerPlugin * plugin G_GNUC_UNUSED)252 void virLockManagerPluginUnref(virLockManagerPlugin *plugin G_GNUC_UNUSED)
253 {
254 }
255 #endif /* !WITH_DLFCN_H */
256
257
virLockManagerPluginGetName(virLockManagerPlugin * plugin)258 const char *virLockManagerPluginGetName(virLockManagerPlugin *plugin)
259 {
260 VIR_DEBUG("plugin=%p", plugin);
261
262 return plugin->name;
263 }
264
265
virLockManagerPluginUsesState(virLockManagerPlugin * plugin)266 bool virLockManagerPluginUsesState(virLockManagerPlugin *plugin)
267 {
268 VIR_DEBUG("plugin=%p", plugin);
269
270 return plugin->driver->flags & VIR_LOCK_MANAGER_USES_STATE;
271 }
272
273
virLockManagerPluginGetDriver(virLockManagerPlugin * plugin)274 virLockDriver *virLockManagerPluginGetDriver(virLockManagerPlugin *plugin)
275 {
276 VIR_DEBUG("plugin=%p", plugin);
277
278 return plugin->driver;
279 }
280
281 /**
282 * virLockManagerNew:
283 * @driver: the lock manager implementation to use
284 * @type: the type of process to be supervised
285 * @flags: bitwise-OR of virLockManagerNewFlags
286 *
287 * Create a new context to supervise a process, usually
288 * a virtual machine.
289 *
290 * Returns a new lock manager context
291 */
virLockManagerNew(virLockDriver * driver,unsigned int type,size_t nparams,virLockManagerParam * params,unsigned int flags)292 virLockManager *virLockManagerNew(virLockDriver *driver,
293 unsigned int type,
294 size_t nparams,
295 virLockManagerParam *params,
296 unsigned int flags)
297 {
298 virLockManager *lock;
299 VIR_DEBUG("driver=%p type=%u nparams=%zu params=%p flags=0x%x",
300 driver, type, nparams, params, flags);
301 virLockManagerLogParams(nparams, params);
302
303 CHECK_DRIVER(drvNew, NULL);
304
305 lock = g_new0(virLockManager, 1);
306
307 lock->driver = driver;
308
309 if (driver->drvNew(lock, type, nparams, params, flags) < 0) {
310 VIR_FREE(lock);
311 return NULL;
312 }
313
314 return lock;
315 }
316
317
virLockManagerAddResource(virLockManager * lock,unsigned int type,const char * name,size_t nparams,virLockManagerParam * params,unsigned int flags)318 int virLockManagerAddResource(virLockManager *lock,
319 unsigned int type,
320 const char *name,
321 size_t nparams,
322 virLockManagerParam *params,
323 unsigned int flags)
324 {
325 VIR_DEBUG("lock=%p type=%u name=%s nparams=%zu params=%p flags=0x%x",
326 lock, type, name, nparams, params, flags);
327 virLockManagerLogParams(nparams, params);
328
329 CHECK_MANAGER(drvAddResource, -1);
330
331 return lock->driver->drvAddResource(lock,
332 type, name,
333 nparams, params,
334 flags);
335 }
336
virLockManagerAcquire(virLockManager * lock,const char * state,unsigned int flags,virDomainLockFailureAction action,int * fd)337 int virLockManagerAcquire(virLockManager *lock,
338 const char *state,
339 unsigned int flags,
340 virDomainLockFailureAction action,
341 int *fd)
342 {
343 VIR_DEBUG("lock=%p state='%s' flags=0x%x action=%d fd=%p",
344 lock, NULLSTR(state), flags, action, fd);
345
346 CHECK_MANAGER(drvAcquire, -1);
347
348 if (fd)
349 *fd = -1;
350
351 return lock->driver->drvAcquire(lock, state, flags, action, fd);
352 }
353
354
virLockManagerRelease(virLockManager * lock,char ** state,unsigned int flags)355 int virLockManagerRelease(virLockManager *lock,
356 char **state,
357 unsigned int flags)
358 {
359 VIR_DEBUG("lock=%p state=%p flags=0x%x", lock, state, flags);
360
361 CHECK_MANAGER(drvRelease, -1);
362
363 return lock->driver->drvRelease(lock, state, flags);
364 }
365
366
virLockManagerInquire(virLockManager * lock,char ** state,unsigned int flags)367 int virLockManagerInquire(virLockManager *lock,
368 char **state,
369 unsigned int flags)
370 {
371 VIR_DEBUG("lock=%p state=%p flags=0x%x", lock, state, flags);
372
373 CHECK_MANAGER(drvInquire, -1);
374
375 return lock->driver->drvInquire(lock, state, flags);
376 }
377
378
virLockManagerFree(virLockManager * lock)379 int virLockManagerFree(virLockManager *lock)
380 {
381 VIR_DEBUG("lock=%p", lock);
382
383 if (!lock)
384 return 0;
385
386 CHECK_MANAGER(drvFree, -1);
387
388 lock->driver->drvFree(lock);
389
390 g_free(lock);
391
392 return 0;
393 }
394