2010-09-13 13:02:58 +00:00
|
|
|
/*
|
|
|
|
* lock_manager.c: Implements the internal lock manager API
|
|
|
|
*
|
|
|
|
* Copyright (C) 2010-2011 Red Hat, Inc.
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
2012-09-20 22:30:55 +00:00
|
|
|
* License along with this library. If not, see
|
2012-07-21 10:06:23 +00:00
|
|
|
* <http://www.gnu.org/licenses/>.
|
2010-09-13 13:02:58 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include "lock_manager.h"
|
2011-01-24 12:14:52 +00:00
|
|
|
#include "lock_driver_nop.h"
|
2012-12-13 18:21:53 +00:00
|
|
|
#include "virerror.h"
|
2012-12-12 17:59:27 +00:00
|
|
|
#include "virlog.h"
|
2012-12-13 17:44:57 +00:00
|
|
|
#include "virutil.h"
|
2012-12-12 18:06:53 +00:00
|
|
|
#include "viralloc.h"
|
2012-12-13 18:01:25 +00:00
|
|
|
#include "viruuid.h"
|
2010-09-13 13:02:58 +00:00
|
|
|
|
2011-06-03 08:20:49 +00:00
|
|
|
#if HAVE_DLFCN_H
|
|
|
|
# include <dlfcn.h>
|
|
|
|
#endif
|
2010-09-13 13:02:58 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include "configmake.h"
|
|
|
|
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_LOCKING
|
|
|
|
|
2011-07-06 16:15:54 +00:00
|
|
|
#define CHECK_DRIVER(field, errret) \
|
|
|
|
if (!driver->field) { \
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, \
|
|
|
|
_("Missing '%s' field in lock manager driver"), \
|
|
|
|
#field); \
|
2010-09-13 13:02:58 +00:00
|
|
|
return errret; \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define CHECK_MANAGER(field, errret) \
|
|
|
|
if (!lock->driver->field) { \
|
2012-07-18 13:37:08 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, \
|
|
|
|
_("Missing '%s' field in lock manager driver"), \
|
|
|
|
#field); \
|
2010-09-13 13:02:58 +00:00
|
|
|
return errret; \
|
|
|
|
}
|
|
|
|
|
|
|
|
struct _virLockManagerPlugin {
|
|
|
|
char *name;
|
|
|
|
virLockDriverPtr driver;
|
|
|
|
void *handle;
|
|
|
|
int refs;
|
|
|
|
};
|
|
|
|
|
|
|
|
#define DEFAULT_LOCK_MANAGER_PLUGIN_DIR LIBDIR "/libvirt/lock-driver"
|
|
|
|
|
2012-08-21 13:21:47 +00:00
|
|
|
static const char *virLockManagerPluginDir = DEFAULT_LOCK_MANAGER_PLUGIN_DIR;
|
|
|
|
|
|
|
|
void
|
|
|
|
virLockManagerSetPluginDir(const char *dir)
|
|
|
|
{
|
|
|
|
if (dir)
|
|
|
|
virLockManagerPluginDir = dir;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-09-13 13:02:58 +00:00
|
|
|
static void virLockManagerLogParams(size_t nparams,
|
|
|
|
virLockManagerParamPtr params)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
for (i = 0 ; i < nparams ; i++) {
|
|
|
|
switch (params[i].type) {
|
|
|
|
case VIR_LOCK_MANAGER_PARAM_TYPE_INT:
|
|
|
|
VIR_DEBUG(" key=%s type=int value=%d", params[i].key, params[i].value.i);
|
|
|
|
break;
|
|
|
|
case VIR_LOCK_MANAGER_PARAM_TYPE_UINT:
|
|
|
|
VIR_DEBUG(" key=%s type=uint value=%u", params[i].key, params[i].value.ui);
|
|
|
|
break;
|
|
|
|
case VIR_LOCK_MANAGER_PARAM_TYPE_LONG:
|
|
|
|
VIR_DEBUG(" key=%s type=long value=%lld", params[i].key, params[i].value.l);
|
|
|
|
break;
|
|
|
|
case VIR_LOCK_MANAGER_PARAM_TYPE_ULONG:
|
|
|
|
VIR_DEBUG(" key=%s type=ulong value=%llu", params[i].key, params[i].value.ul);
|
|
|
|
break;
|
|
|
|
case VIR_LOCK_MANAGER_PARAM_TYPE_DOUBLE:
|
|
|
|
VIR_DEBUG(" key=%s type=double value=%lf", params[i].key, params[i].value.d);
|
|
|
|
break;
|
|
|
|
case VIR_LOCK_MANAGER_PARAM_TYPE_STRING:
|
|
|
|
VIR_DEBUG(" key=%s type=string value=%s", params[i].key, params[i].value.str);
|
|
|
|
break;
|
2012-09-17 13:12:53 +00:00
|
|
|
case VIR_LOCK_MANAGER_PARAM_TYPE_CSTRING:
|
|
|
|
VIR_DEBUG(" key=%s type=cstring value=%s", params[i].key, params[i].value.cstr);
|
|
|
|
break;
|
2010-09-13 13:02:58 +00:00
|
|
|
case VIR_LOCK_MANAGER_PARAM_TYPE_UUID:
|
|
|
|
virUUIDFormat(params[i].value.uuid, uuidstr);
|
|
|
|
VIR_DEBUG(" key=%s type=uuid value=%s", params[i].key, uuidstr);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virLockManagerPluginNew:
|
|
|
|
* @name: the name of the plugin
|
|
|
|
* @flag: optional plugin flags
|
|
|
|
*
|
|
|
|
* Attempt to load the plugin $(libdir)/libvirt/lock-driver/@name.so
|
|
|
|
* The plugin driver entry point will be resolved & invoked to obtain
|
|
|
|
* the lock manager driver.
|
|
|
|
*
|
|
|
|
* Even if the loading of the plugin succeeded, this may still
|
|
|
|
* return NULL if the plugin impl decided that we (libvirtd)
|
|
|
|
* are too old to support a feature it requires
|
|
|
|
*
|
|
|
|
* Returns a plugin object, or NULL if loading failed.
|
|
|
|
*/
|
2011-06-03 08:20:49 +00:00
|
|
|
#if HAVE_DLFCN_H
|
2010-09-13 13:02:58 +00:00
|
|
|
virLockManagerPluginPtr virLockManagerPluginNew(const char *name,
|
2012-12-11 15:59:21 +00:00
|
|
|
const char *driverName,
|
|
|
|
const char *configDir,
|
2010-09-13 13:02:58 +00:00
|
|
|
unsigned int flags)
|
|
|
|
{
|
|
|
|
void *handle = NULL;
|
|
|
|
virLockDriverPtr driver;
|
2011-06-02 22:38:38 +00:00
|
|
|
virLockManagerPluginPtr plugin = NULL;
|
2010-09-13 13:02:58 +00:00
|
|
|
const char *moddir = getenv("LIBVIRT_LOCK_MANAGER_PLUGIN_DIR");
|
|
|
|
char *modfile = NULL;
|
2012-12-11 15:59:21 +00:00
|
|
|
char *configFile = NULL;
|
|
|
|
|
|
|
|
VIR_DEBUG("name=%s driverName=%s configDir=%s flags=%x",
|
|
|
|
name, driverName, configDir, flags);
|
|
|
|
|
|
|
|
if (virAsprintf(&configFile, "%s/%s-%s.conf",
|
|
|
|
configDir, driverName, name) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-09-13 13:02:58 +00:00
|
|
|
|
2011-01-24 12:14:52 +00:00
|
|
|
if (STREQ(name, "nop")) {
|
|
|
|
driver = &virLockDriverNop;
|
|
|
|
} else {
|
|
|
|
if (moddir == NULL)
|
2012-08-21 13:21:47 +00:00
|
|
|
moddir = virLockManagerPluginDir;
|
2010-09-13 13:02:58 +00:00
|
|
|
|
2011-01-24 12:14:52 +00:00
|
|
|
VIR_DEBUG("Module load %s from %s", name, moddir);
|
2010-09-13 13:02:58 +00:00
|
|
|
|
2011-01-24 12:14:52 +00:00
|
|
|
if (virAsprintf(&modfile, "%s/%s.so", moddir, name) < 0) {
|
|
|
|
virReportOOMError();
|
2012-12-11 15:59:21 +00:00
|
|
|
goto cleanup;
|
2011-01-24 12:14:52 +00:00
|
|
|
}
|
2010-09-13 13:02:58 +00:00
|
|
|
|
2011-01-24 12:14:52 +00:00
|
|
|
if (access(modfile, R_OK) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Plugin %s not accessible"),
|
|
|
|
modfile);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2010-09-13 13:02:58 +00:00
|
|
|
|
2011-01-24 12:14:52 +00:00
|
|
|
handle = dlopen(modfile, RTLD_NOW | RTLD_LOCAL);
|
|
|
|
if (!handle) {
|
2012-07-18 13:37:08 +00:00
|
|
|
virReportError(VIR_ERR_SYSTEM_ERROR,
|
|
|
|
_("Failed to load plugin %s: %s"),
|
|
|
|
modfile, dlerror());
|
2011-01-24 12:14:52 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2010-09-13 13:02:58 +00:00
|
|
|
|
2011-01-24 12:14:52 +00:00
|
|
|
if (!(driver = dlsym(handle, "virLockDriverImpl"))) {
|
2012-07-18 13:37:08 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Missing plugin initialization symbol 'virLockDriverImpl'"));
|
2011-01-24 12:14:52 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2010-09-13 13:02:58 +00:00
|
|
|
}
|
|
|
|
|
2011-06-13 13:30:26 +00:00
|
|
|
if (driver->drvInit(VIR_LOCK_MANAGER_VERSION, configFile, flags) < 0)
|
2010-09-13 13:02:58 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(plugin) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
plugin->driver = driver;
|
|
|
|
plugin->handle = handle;
|
|
|
|
plugin->refs = 1;
|
|
|
|
if (!(plugin->name = strdup(name))) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2012-12-11 15:59:21 +00:00
|
|
|
VIR_FREE(configFile);
|
2010-09-13 13:02:58 +00:00
|
|
|
VIR_FREE(modfile);
|
|
|
|
return plugin;
|
|
|
|
|
|
|
|
cleanup:
|
2012-12-11 15:59:21 +00:00
|
|
|
VIR_FREE(configFile);
|
2011-06-02 22:38:38 +00:00
|
|
|
VIR_FREE(plugin);
|
2010-09-13 13:02:58 +00:00
|
|
|
VIR_FREE(modfile);
|
|
|
|
if (handle)
|
|
|
|
dlclose(handle);
|
|
|
|
return NULL;
|
|
|
|
}
|
2011-06-03 08:20:49 +00:00
|
|
|
#else /* !HAVE_DLFCN_H */
|
2011-07-07 17:57:43 +00:00
|
|
|
virLockManagerPluginPtr
|
|
|
|
virLockManagerPluginNew(const char *name ATTRIBUTE_UNUSED,
|
2012-12-11 15:59:21 +00:00
|
|
|
const char *driverName ATTRIBUTE_UNUSED,
|
|
|
|
const char *configDir ATTRIBUTE_UNUSED,
|
2011-07-07 17:57:43 +00:00
|
|
|
unsigned int flags_unused ATTRIBUTE_UNUSED)
|
2011-06-03 08:20:49 +00:00
|
|
|
{
|
2012-07-18 13:37:08 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("this platform is missing dlopen"));
|
2011-06-03 08:20:49 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
#endif /* !HAVE_DLFCN_H */
|
2010-09-13 13:02:58 +00:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virLockManagerPluginRef:
|
|
|
|
* @plugin: the plugin implementation to ref
|
|
|
|
*
|
|
|
|
* Acquires an additional reference on the plugin.
|
|
|
|
*/
|
|
|
|
void virLockManagerPluginRef(virLockManagerPluginPtr plugin)
|
|
|
|
{
|
|
|
|
plugin->refs++;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virLockManagerPluginUnref:
|
|
|
|
* @plugin: the plugin implementation to unref
|
|
|
|
*
|
|
|
|
* Releases a reference on the plugin. When the last reference
|
|
|
|
* is released, it will attempt to unload the plugin from memory.
|
|
|
|
* The plugin may refuse to allow unloading if this would
|
|
|
|
* result in an unsafe scenario.
|
|
|
|
*
|
|
|
|
*/
|
2011-06-03 08:20:49 +00:00
|
|
|
#if HAVE_DLFCN_H
|
2010-09-13 13:02:58 +00:00
|
|
|
void virLockManagerPluginUnref(virLockManagerPluginPtr plugin)
|
|
|
|
{
|
|
|
|
if (!plugin)
|
|
|
|
return;
|
|
|
|
|
|
|
|
plugin->refs--;
|
|
|
|
|
|
|
|
if (plugin->refs > 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (plugin->driver->drvDeinit() >= 0) {
|
|
|
|
if (plugin->handle)
|
|
|
|
dlclose(plugin->handle);
|
|
|
|
} else {
|
|
|
|
VIR_WARN("Unable to unload lock maanger plugin from memory");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_FREE(plugin->name);
|
|
|
|
VIR_FREE(plugin);
|
|
|
|
}
|
2011-06-03 08:20:49 +00:00
|
|
|
#else /* !HAVE_DLFCN_H */
|
|
|
|
void virLockManagerPluginUnref(virLockManagerPluginPtr plugin ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
#endif /* !HAVE_DLFCN_H */
|
2010-09-13 13:02:58 +00:00
|
|
|
|
|
|
|
|
|
|
|
const char *virLockManagerPluginGetName(virLockManagerPluginPtr plugin)
|
|
|
|
{
|
|
|
|
VIR_DEBUG("plugin=%p", plugin);
|
|
|
|
|
|
|
|
return plugin->name;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool virLockManagerPluginUsesState(virLockManagerPluginPtr plugin)
|
|
|
|
{
|
|
|
|
VIR_DEBUG("plugin=%p", plugin);
|
|
|
|
|
|
|
|
return plugin->driver->flags & VIR_LOCK_MANAGER_USES_STATE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-07-06 16:15:54 +00:00
|
|
|
virLockDriverPtr virLockManagerPluginGetDriver(virLockManagerPluginPtr plugin)
|
|
|
|
{
|
|
|
|
VIR_DEBUG("plugin=%p", plugin);
|
|
|
|
|
|
|
|
return plugin->driver;
|
|
|
|
}
|
|
|
|
|
2010-09-13 13:02:58 +00:00
|
|
|
/**
|
|
|
|
* virLockManagerNew:
|
2011-07-06 16:15:54 +00:00
|
|
|
* @driver: the lock manager implementation to use
|
2010-09-13 13:02:58 +00:00
|
|
|
* @type: the type of process to be supervised
|
|
|
|
* @flags: optional flags, currently unused
|
|
|
|
*
|
|
|
|
* Create a new context to supervise a process, usually
|
|
|
|
* a virtual machine.
|
|
|
|
*
|
|
|
|
* Returns a new lock manager context
|
|
|
|
*/
|
2011-07-06 16:15:54 +00:00
|
|
|
virLockManagerPtr virLockManagerNew(virLockDriverPtr driver,
|
2010-09-13 13:02:58 +00:00
|
|
|
unsigned int type,
|
|
|
|
size_t nparams,
|
|
|
|
virLockManagerParamPtr params,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
|
|
|
virLockManagerPtr lock;
|
2011-07-06 16:15:54 +00:00
|
|
|
VIR_DEBUG("driver=%p type=%u nparams=%zu params=%p flags=%x",
|
|
|
|
driver, type, nparams, params, flags);
|
2010-09-13 13:02:58 +00:00
|
|
|
virLockManagerLogParams(nparams, params);
|
|
|
|
|
2011-07-06 16:15:54 +00:00
|
|
|
CHECK_DRIVER(drvNew, NULL);
|
2010-09-13 13:02:58 +00:00
|
|
|
|
|
|
|
if (VIR_ALLOC(lock) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2011-07-06 16:15:54 +00:00
|
|
|
lock->driver = driver;
|
2010-09-13 13:02:58 +00:00
|
|
|
|
2011-07-06 16:15:54 +00:00
|
|
|
if (driver->drvNew(lock, type, nparams, params, flags) < 0) {
|
2010-09-13 13:02:58 +00:00
|
|
|
VIR_FREE(lock);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return lock;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int virLockManagerAddResource(virLockManagerPtr lock,
|
|
|
|
unsigned int type,
|
|
|
|
const char *name,
|
|
|
|
size_t nparams,
|
|
|
|
virLockManagerParamPtr params,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
2011-07-08 15:18:48 +00:00
|
|
|
VIR_DEBUG("lock=%p type=%u name=%s nparams=%zu params=%p flags=%x",
|
2010-09-13 13:02:58 +00:00
|
|
|
lock, type, name, nparams, params, flags);
|
|
|
|
virLockManagerLogParams(nparams, params);
|
|
|
|
|
|
|
|
CHECK_MANAGER(drvAddResource, -1);
|
|
|
|
|
|
|
|
return lock->driver->drvAddResource(lock,
|
|
|
|
type, name,
|
|
|
|
nparams, params,
|
|
|
|
flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
int virLockManagerAcquire(virLockManagerPtr lock,
|
|
|
|
const char *state,
|
2011-06-24 14:14:41 +00:00
|
|
|
unsigned int flags,
|
2012-09-18 11:40:13 +00:00
|
|
|
virDomainLockFailureAction action,
|
2011-06-24 14:14:41 +00:00
|
|
|
int *fd)
|
2010-09-13 13:02:58 +00:00
|
|
|
{
|
2012-09-18 11:40:13 +00:00
|
|
|
VIR_DEBUG("lock=%p state='%s' flags=%x action=%d fd=%p",
|
|
|
|
lock, NULLSTR(state), flags, action, fd);
|
2010-09-13 13:02:58 +00:00
|
|
|
|
|
|
|
CHECK_MANAGER(drvAcquire, -1);
|
|
|
|
|
2011-06-24 14:14:41 +00:00
|
|
|
if (fd)
|
|
|
|
*fd = -1;
|
|
|
|
|
2012-09-18 11:40:13 +00:00
|
|
|
return lock->driver->drvAcquire(lock, state, flags, action, fd);
|
2010-09-13 13:02:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int virLockManagerRelease(virLockManagerPtr lock,
|
|
|
|
char **state,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
2011-07-08 15:18:48 +00:00
|
|
|
VIR_DEBUG("lock=%p state=%p flags=%x", lock, state, flags);
|
2010-09-13 13:02:58 +00:00
|
|
|
|
|
|
|
CHECK_MANAGER(drvRelease, -1);
|
|
|
|
|
|
|
|
return lock->driver->drvRelease(lock, state, flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int virLockManagerInquire(virLockManagerPtr lock,
|
|
|
|
char **state,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
2011-07-08 15:18:48 +00:00
|
|
|
VIR_DEBUG("lock=%p state=%p flags=%x", lock, state, flags);
|
2010-09-13 13:02:58 +00:00
|
|
|
|
|
|
|
CHECK_MANAGER(drvInquire, -1);
|
|
|
|
|
|
|
|
return lock->driver->drvInquire(lock, state, flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int virLockManagerFree(virLockManagerPtr lock)
|
|
|
|
{
|
|
|
|
VIR_DEBUG("lock=%p", lock);
|
|
|
|
|
|
|
|
if (!lock)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
CHECK_MANAGER(drvFree, -1);
|
|
|
|
|
|
|
|
lock->driver->drvFree(lock);
|
|
|
|
|
|
|
|
VIR_FREE(lock);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|