Define the basic framework lock manager plugins. The
basic plugin API for 3rd parties to implemented is
defined in
src/locking/lock_driver.h
This allows dlopen()able modules for alternative locking
schemes, however, we do not install the header. This
requires lock plugins to be in-tree allowing changing of
the lock manager plugin API in future.
The libvirt code for loading & calling into plugins
is in
src/locking/lock_manager.{c,h}
* include/libvirt/virterror.h, src/util/virterror.c: Add
VIR_FROM_LOCKING
* src/locking/lock_driver.h: API for lock driver plugins
to implement
* src/locking/lock_manager.c, src/locking/lock_manager.h:
Internal API for managing locking
* src/Makefile.am: Add locking code
---
include/libvirt/virterror.h | 1 +
po/POTFILES.in | 1 +
src/Makefile.am | 3 +-
src/libvirt_private.syms | 18 ++
src/locking/README | 158 +++++++++++++++++
src/locking/lock_driver.h | 395 +++++++++++++++++++++++++++++++++++++++++++
src/locking/lock_manager.c | 394 ++++++++++++++++++++++++++++++++++++++++++
src/locking/lock_manager.h | 79 +++++++++
src/util/virterror.c | 3 +
9 files changed, 1051 insertions(+), 1 deletions(-)
create mode 100644 src/locking/README
create mode 100644 src/locking/lock_driver.h
create mode 100644 src/locking/lock_manager.c
create mode 100644 src/locking/lock_manager.h
diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h
index 5962dbf..33118c6 100644
--- a/include/libvirt/virterror.h
+++ b/include/libvirt/virterror.h
@@ -79,6 +79,7 @@ typedef enum {
VIR_FROM_SYSINFO = 37, /* Error from sysinfo/SMBIOS */
VIR_FROM_STREAMS = 38, /* Error from I/O streams */
VIR_FROM_VMWARE = 39, /* Error from VMware driver */
+ VIR_FROM_LOCKING = 40, /* Error from lock manager */
} virErrorDomain;
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 5f2ed75..47f2f20 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -29,6 +29,7 @@ src/fdstream.c
src/interface/netcf_driver.c
src/internal.h
src/libvirt.c
+src/locking/lock_manager.c
src/lxc/lxc_container.c
src/lxc/lxc_conf.c
src/lxc/lxc_controller.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 2f94efd..f001daf 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -91,7 +91,8 @@ DRIVER_SOURCES = \
datatypes.c datatypes.h \
fdstream.c fdstream.h \
$(NODE_INFO_SOURCES) \
- libvirt.c libvirt_internal.h
+ libvirt.c libvirt_internal.h \
+ locking/lock_manager.c locking/lock_manager.h
# XML configuration format handling sources
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 99df0f7..b45f501 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -525,6 +525,24 @@ virRegisterSecretDriver;
virRegisterStorageDriver;
+# locking.h
+virLockManagerAcquireObject;
+virLockManagerAcquireResource;
+virLockManagerAddResource;
+virLockManagerAttachObject;
+virLockManagerDetachObject;
+virLockManagerFree;
+virLockManagerGetState;
+virLockManagerNew;
+virLockManagerPluginNew;
+virLockManagerPluginRef;
+virLockManagerPluginUnref;
+virLockManagerReleaseObject;
+virLockManagerReleaseResource;
+virLockManagerSetParameter;
+virLockManagerStartup;
+
+
# logging.h
virLogDefineFilter;
virLogDefineOutput;
diff --git a/src/locking/README b/src/locking/README
new file mode 100644
index 0000000..4fa4f89
--- /dev/null
+++ b/src/locking/README
@@ -0,0 +1,158 @@
+
+At libvirtd startup:
+
+ plugin = virLockManagerPluginLoad("sync-manager");
+
+
+At libvirtd shtudown:
+
+ virLockManagerPluginUnload(plugin)
+
+
+At guest startup:
+
+ manager = virLockManagerNew(plugin,
+ VIR_LOCK_MANAGER_OBJECT_DOMAIN,
+ 0);
+
+ virLockManagerSetParameter(manager, "id", id);
+ virLockManagerSetParameter(manager, "uuid", uuid);
+ virLockManagerSetParameter(manager, "name", name);
+
+ foreach disk
+ virLockManagerRegisterResource(manager,
+ VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK,
+ disk.path,
+ ..flags...);
+
+ if (!virLockManagerAcquireObject(manager))
+ abort..
+
+ run QEMU
+
+
+At guest shutdown:
+
+ ...send QEMU 'quit' monitor command, and/or kill(qemupid)...
+
+ if (!virLockManagerShutdown(manager))
+ kill(supervisorpid); /* XXX or leave it running ??? */
+
+ virLockManagerFree(manager);
+
+
+
+At libvirtd restart with running guests:
+
+ foreach still running guest
+ manager = virLockManagerNew(driver,
+ VIR_LOCK_MANAGER_START_DOMAIN,
+ VIR_LOCK_MANAGER_NEW_ATTACH);
+ virLockManagerSetParameter(manager, "id", id);
+ virLockManagerSetParameter(manager, "uuid", uuid);
+ virLockManagerSetParameter(manager, "name", name);
+
+ if (!virLockManagerGetChild(manager, &qemupid))
+ kill(supervisorpid); /* XXX or leave it running ??? */
+
+
+
+With disk hotplug:
+
+ if (virLockManagerAcquireResource(manager,
+ VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK,
+ disk.path
+ ..flags..))
+ ...abort hotplug attempt ...
+
+ ...hotplug the device...
+
+
+
+With disk unhotplug:
+
+ ...hotunplug the device...
+
+ if (virLockManagerReleaseResource(manager,
+ VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK,
+ disk.path
+ ..flags..))
+ ...log warning ...
+
+
+
+During migration:
+
+ 1. On source host
+
+ if (!virLockManagerPrepareMigrate(manager, hosturi))
+ ..don't start migration..
+
+ 2. On dest host
+
+ manager = virLockManagerNew(driver,
+ VIR_LOCK_MANAGER_START_DOMAIN,
+ VIR_LOCK_MANAGER_NEW_MIGRATE);
+ virLockManagerSetParameter(manager, "id", id);
+ virLockManagerSetParameter(manager, "uuid", uuid);
+ virLockManagerSetParameter(manager, "name", name);
+
+ foreach disk
+ virLockManagerRegisterResource(manager,
+ VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK,
+ disk.path,
+ ..flags...);
+
+ char **supervisorargv;
+ int supervisorargc;
+
+ supervisor = virLockManagerGetSupervisorPath(manager);
+ virLockManagerGetSupervisorArgs(&argv, &argc);
+
+ cmd = qemuBuildCommandLine(supervisor, supervisorargv, supervisorargv);
+
+ supervisorpid = virCommandExec(cmd);
+
+ if (!virLockManagerGetChild(manager, &qemupid))
+ kill(supervisorpid); /* XXX or leave it running ??? */
+
+ 3. Initiate migration in QEMU on source and wait for completion
+
+ 4a. On failure
+
+ 4a1 On target
+
+ virLockManagerCompleteMigrateIn(manager,
+ VIR_LOCK_MANAGER_MIGRATE_CANCEL);
+ virLockManagerShutdown(manager);
+ virLockManagerFree(manager);
+
+ 4a2 On source
+
+ virLockManagerCompleteMigrateIn(manager,
+ VIR_LOCK_MANAGER_MIGRATE_CANCEL);
+
+ 4b. On succcess
+
+
+ 4b1 On target
+
+ virLockManagerCompleteMigrateIn(manager, 0);
+
+ 42 On source
+
+ virLockManagerCompleteMigrateIn(manager, 0);
+ virLockManagerShutdown(manager);
+ virLockManagerFree(manager);
+
+
+Notes:
+
+ - If a lock manager impl does just VM level leases, it can
+ ignore all the resource paths at startup.
+
+ - If a lock manager impl does not support migrate
+ it can return an error from all migrate calls
+
+ - If a lock manger impl does not support hotplug
+ it can return an error from all resource acquire/release calls
diff --git a/src/locking/lock_driver.h b/src/locking/lock_driver.h
new file mode 100644
index 0000000..a8b337d
--- /dev/null
+++ b/src/locking/lock_driver.h
@@ -0,0 +1,395 @@
+/*
+ * lock_driver.h: Defines the lock driver plugin 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
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef __VIR_PLUGINS_LOCK_DRIVER_H__
+# define __VIR_PLUGINS_LOCK_DRIVER_H__
+
+# include "internal.h"
+
+typedef struct _virLockManager virLockManager;
+typedef virLockManager *virLockManagerPtr;
+
+typedef struct _virLockDriver virLockDriver;
+typedef virLockDriver *virLockDriverPtr;
+
+typedef struct _virLockManagerParam virLockManagerParam;
+typedef virLockManagerParam *virLockManagerParamPtr;
+
+enum {
+ /* The managed object is a virtual guest domain */
+ VIR_LOCK_MANAGER_OBJECT_TYPE_DOMAIN = 0,
+} virLockManagerObjectType;
+
+/*
+ * Flags to pass to 'load_drv' and also 'new_drv' method
+ * Plugins must support at least one of the modes. If a
+ * mode is unsupported, it must return an error
+ */
+enum {
+ VIR_LOCK_MANAGER_MODE_CONTENT = (1 << 0),
+ VIR_LOCK_MANAGER_MODE_METADATA = (1 << 1),
+} virLockManagerFlags;
+
+enum {
+ /* The resource to be locked is a virtual disk */
+ VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK = 0,
+ /* A lease against an arbitrary resource */
+ VIR_LOCK_MANAGER_RESOURCE_TYPE_LEASE = 1,
+} virLockManagerResourceType;
+
+typedef enum {
+ /* The resource is assigned in readonly mode */
+ VIR_LOCK_MANAGER_RESOURCE_READONLY = (1 << 0),
+ /* The resource is assigned in shared, writable mode */
+ VIR_LOCK_MANAGER_RESOURCE_SHARED = (1 << 1),
+} virLockManagerResourceFlags;
+
+enum {
+ VIR_LOCK_MANAGER_PARAM_TYPE_STRING,
+ VIR_LOCK_MANAGER_PARAM_TYPE_INT,
+ VIR_LOCK_MANAGER_PARAM_TYPE_LONG,
+ VIR_LOCK_MANAGER_PARAM_TYPE_UINT,
+ VIR_LOCK_MANAGER_PARAM_TYPE_ULONG,
+ VIR_LOCK_MANAGER_PARAM_TYPE_DOUBLE,
+ VIR_LOCK_MANAGER_PARAM_TYPE_UUID,
+};
+
+struct _virLockManagerParam {
+ int type;
+ const char *key;
+ union {
+ int i;
+ long long l;
+ unsigned int ui;
+ unsigned long long ul;
+ double d;
+ char *str;
+ unsigned char uuid[16];
+ } value;
+};
+
+
+/*
+ * Changes in major version denote incompatible ABI changes
+ * Changes in minor version denote new compatible API entry points
+ * Changes in micro version denote new compatible flags
+ */
+# define VIR_LOCK_MANAGER_VERSION_MAJOR 1
+# define VIR_LOCK_MANAGER_VERSION_MINOR 0
+# define VIR_LOCK_MANAGER_VERSION_MICRO 0
+
+# define VIR_LOCK_MANAGER_VERSION \
+ ((VIR_LOCK_MANAGER_VERSION_MAJOR * 1000 * 1000) + \
+ (VIR_LOCK_MANAGER_VERSION_MINOR * 1000) + \
+ (VIR_LOCK_MANAGER_VERSION_MICRO))
+
+
+
+/**
+ * virLockDriverInit:
+ * @version: the libvirt requested plugin ABI version
+ * @flags: the libvirt requested plugin optional extras
+ *
+ * Allow the plugin to validate the libvirt requested
+ * plugin version / flags. This allows the plugin impl
+ * to block its use in versions of libvirtd which are
+ * too old to support key features.
+ *
+ * NB: A plugin may be loaded multiple times, for different
+ * libvirt drivers (eg QEMU, LXC, UML)
+ *
+ * Returns -1 if the requested version/flags were inadequate
+ */
+typedef int (*virLockDriverInit)(unsigned int version,
+ unsigned int flags);
+
+/**
+ * virLockDriverDeinit:
+ *
+ * Called to release any resources prior to the plugin
+ * being unloaded from memory. Returns -1 to prevent
+ * plugin from being unloaded from memory.
+ */
+typedef int (*virLockDriverDeinit)(void);
+
+/**
+ * virLockManagerNew:
+ * @man: the lock manager context
+ * @type: the type of process to be supervised
+ * @nparams: number of metadata parameters
+ * @params: extra metadata parameters
+ * @flags: optional flags, currently unused
+ *
+ * Initialize a new context to supervise a process, usually
+ * a virtual machine. The lock driver implementation can use
+ * the <code>privateData</code> field of <code>man</code>
+ * to store a pointer to any driver specific state.
+ *
+ * A process of VIR_LOCK_MANAGER_START_DOMAIN will be
+ * given the following parameters
+ *
+ * - id: the domain unique id (unsigned int)
+ * - uuid: the domain uuid (uuid)
+ * - name: the domain name (string)
+ * - pid: process ID owning the lock (unsigned int)
+ *
+ * Returns 0 if successful initialized a new context, -1 on error
+ */
+typedef int (*virLockDriverNew)(virLockManagerPtr man,
+ unsigned int type,
+ size_t nparams,
+ virLockManagerParamPtr params,
+ unsigned int flags);
+
+/**
+ * virLockDriverFree:
+ * @manager: the lock manager context
+ *
+ * Release any resources associated with the lock manager
+ * context private data
+ */
+typedef void (*virLockDriverFree)(virLockManagerPtr man);
+
+/**
+ * virLockDriverAddResource:
+ * @manager: the lock manager context
+ * @type: the resource type virLockManagerResourceType
+ * @name: the resource name
+ * @nparams: number of metadata parameters
+ * @params: extra metadata parameters
+ * @flags: the resource access flags
+ *
+ * Assign a resource to a managed object. This will
+ * only be called prior to the object is being locked
+ * when it is inactive. eg, to set the initial boot
+ * time disk assignments on a VM
+ * The format of @name varies according to
+ * the resource @type. A VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK
+ * or VIR_LOCK_MANAGER_RESOURCE_TYPE_LEASE will have the
+ * fully qualified file path.
+ *
+ * A resource of type VIR_LOCK_MANAGER_RESOURCE_TYPE_LEASE
+ * will receive at least the following extra parameters
+ *
+ * - 'uuid': globally unique identifier of the lease (uuid)
+ * - 'offset': byte offset within the lease (unsigned long long)
+ * - 'length': number of bytes in lease region (unsigned long long)
+ *
+ * If no flags are given, the resource is assumed to be
+ * used in exclusive, read-write mode. Access can be
+ * relaxed to readonly, or shared read-write.
+ *
+ * Returns 0 on success, or -1 on failure
+ */
+typedef int (*virLockDriverAddResource)(virLockManagerPtr man,
+ unsigned int type,
+ const char *name,
+ size_t nparams,
+ virLockManagerParamPtr params,
+ unsigned int flags);
+
+/**
+ * virLockDriverAcquireObject:
+ * @manager: the lock manager context
+ * @state: the current lock state
+ * @flags: optional flags, currently unused
+ *
+ * Start managing resources for the object. If the
+ * object is being transferred from another location
+ * the current lock state may be passed in. This
+ * must be called from the PID that represents the
+ * object to be managed. If the lock is lost at any
+ * time, the PID will be killed off by the lock manager.
+ *
+ * Returns 0 on success, or -1 on failure
+ */
+typedef int (*virLockDriverAcquireObject)(virLockManagerPtr man,
+ const char *state,
+ unsigned int flags);
+
+/**
+ * virLockDriverAttachObject:
+ * @manager: the lock manager context
+ * @flags: optional flags, currently unused
+ *
+ * Re-attach to an existing lock manager instance managing
+ * PID @pid.
+ *
+ * Returns 0 on success, or -1 on failure
+ */
+typedef int (*virLockDriverAttachObject)(virLockManagerPtr man,
+ unsigned int flags);
+
+/**
+ * virLockDriverDetachObject:
+ * @manager: the lock manager context
+ * @flags: optional flags, currently unused
+ *
+ * Deattach from an existing lock manager instance managing
+ * PID @pid.
+ *
+ * Returns 0 on success, or -1 on failure
+ */
+typedef int (*virLockDriverDetachObject)(virLockManagerPtr man,
+ unsigned int flags);
+
+/**
+ * virLockDriverReleaseObject:
+ * @manager: the lock manager context
+ * @flags: optional flags
+ *
+ * Inform the lock manager that the supervised process has
+ * been, or can be stopped. This can must be called from
+ * the same context as the previous virLockDriverAttachObject
+ * or virLockDriverAcquireObject call.
+ *
+ * Returns 0 on success, or -1 on failure
+ */
+typedef int (*virLockDriverReleaseObject)(virLockManagerPtr man,
+ unsigned int flags);
+
+/**
+ * virLockDriverGetState:
+ * @manager: the lock manager context
+ * @state: pointer to be filled with lock state
+ * @flags: optional flags, currently unused
+ *
+ * Retrieve the current lock state. The returned
+ * lock state may be NULL if none is required. The
+ * caller is responsible for freeing the lock
+ * state string when it is no longer required
+ *
+ * Returns 0 on success, or -1 on failure.
+ */
+typedef int (*virLockDriverGetState)(virLockManagerPtr man,
+ char **state,
+ unsigned int flags);
+
+/**
+ * virLockDriverAcquireResource:
+ * @manager: the lock manager context
+ * @type: the resource type virLockDriverResourceType
+ * @name: the resource name
+ * @nparams: number of metadata parameters
+ * @params: extra metadata parameters
+ * @flags: the resource access flags
+ *
+ * Assign a resource to a managed object. This will
+ * only be called when the object is already locked
+ * and active. eg, to hotplug a disk into a VM.
+ * The format of @name varies according to
+ * the resource @type. A VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK
+ * or VIR_LOCK_MANAGER_RESOURCE_TYPE_LEASE will have the
+ * fully qualified file path.
+ *
+ * A resource of type VIR_LOCK_MANAGER_RESOURCE_TYPE_LEASE
+ * will receive at least the following extra parameters
+ *
+ * - 'uuid': globally unique identifier of the lease (uuid)
+ * - 'offset': byte offset within the lease (unsigned long long)
+ * - 'length': number of bytes in lease region (unsigned long long)
+ *
+ * If no flags are given, the resource is assumed to be
+ * used in exclusive, read-write mode. Access can be
+ * relaxed to readonly, or shared read-write.
+ *
+ * Returns 0 on success, or -1 on failure
+ */
+typedef int (*virLockDriverAcquireResource)(virLockManagerPtr man,
+ unsigned int type,
+ const char *name,
+ size_t nparams,
+ virLockManagerParamPtr params,
+ unsigned int flags);
+
+/**
+ * virLockDriverReleaseResource:
+ * @manager: the lock manager context
+ * @type: the resource type virLockDriverResourceType
+ * @name: the resource name
+ * @nparams: number of metadata parameters
+ * @params: extra metadata parameters
+ * @flags: the resource access flags
+ *
+ * Dynamically release a resource for a running process.
+ * This may only be called after the process has been
+ * started. The format of @name varies according to
+ * the resource @type. A VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK
+ * will have a fully qualified file path.
+ *
+ * A resource of type VIR_LOCK_MANAGER_RESOURCE_TYPE_LEASE
+ * will receive at least the following extra parameters
+ *
+ * - 'uuid': globally unique identifier of the lease (uuid)
+ * - 'offset': byte offset within the lease (unsigned long long)
+ * - 'length': number of bytes in lease region (unsigned long long)
+ *
+ * If no flags are given, the resource is assumed to be
+ * used in exclusive, read-write mode. Access can be
+ * relaxed to readonly, or shared read-write.
+ *
+ * Returns 0 on success, or -1 on failure
+ */
+typedef int (*virLockDriverReleaseResource)(virLockManagerPtr man,
+ unsigned int type,
+ const char *name,
+ size_t nparams,
+ virLockManagerParamPtr params,
+ unsigned int flags);
+
+struct _virLockManager {
+ virLockDriverPtr driver;
+ void *privateData;
+};
+
+/**
+ * The plugin must export a static instance of this
+ * driver table, with the name 'virLockDriverImpl'
+ */
+struct _virLockDriver {
+ /**
+ * @version: the newest implemented plugin ABI version
+ * @flags: optional flags, currently unused
+ */
+ unsigned int version;
+ unsigned int flags;
+
+ virLockDriverInit drvInit;
+ virLockDriverDeinit drvDeinit;
+
+ virLockDriverNew drvNew;
+ virLockDriverFree drvFree;
+
+ virLockDriverAddResource drvAddResource;
+
+ virLockDriverAcquireObject drvAcquireObject;
+ virLockDriverAttachObject drvAttachObject;
+ virLockDriverDetachObject drvDetachObject;
+ virLockDriverReleaseObject drvReleaseObject;
+
+ virLockDriverGetState drvGetState;
+
+ virLockDriverAcquireResource drvAcquireResource;
+ virLockDriverReleaseResource drvReleaseResource;
+};
+
+
+#endif /* __VIR_PLUGINS_LOCK_DRIVER_H__ */
diff --git a/src/locking/lock_manager.c b/src/locking/lock_manager.c
new file mode 100644
index 0000000..9c98555
--- /dev/null
+++ b/src/locking/lock_manager.c
@@ -0,0 +1,394 @@
+/*
+ * 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
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <config.h>
+
+#include "lock_manager.h"
+#include "virterror_internal.h"
+#include "logging.h"
+#include "util.h"
+#include "memory.h"
+#include "uuid.h"
+
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "configmake.h"
+
+#define VIR_FROM_THIS VIR_FROM_LOCKING
+
+#define virLockError(code, ...) \
+ virReportErrorHelper(NULL, VIR_FROM_THIS, code, __FILE__, \
+ __FUNCTION__, __LINE__, __VA_ARGS__)
+
+#define CHECK_PLUGIN(field, errret) \
+ if (!plugin->driver->field) { \
+ virLockError(VIR_ERR_INTERNAL_ERROR, \
+ _("Missing '%s' field in lock manager driver"), \
+ #field); \
+ return errret; \
+ }
+
+#define CHECK_MANAGER(field, errret) \
+ if (!manager->driver->field) { \
+ virLockError(VIR_ERR_INTERNAL_ERROR, \
+ _("Missing '%s' field in lock manager driver"), \
+ #field); \
+ return errret; \
+ }
+
+struct _virLockManagerPlugin {
+ virLockDriverPtr driver;
+ void *handle;
+ int refs;
+};
+
+#define DEFAULT_LOCK_MANAGER_PLUGIN_DIR LIBDIR "/libvirt/lock-driver"
+
+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;
+ 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/(a)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.
+ */
+virLockManagerPluginPtr virLockManagerPluginNew(const char *name,
+ unsigned int flags)
+{
+ void *handle = NULL;
+ virLockDriverPtr driver;
+ virLockManagerPluginPtr plugin;
+ const char *moddir = getenv("LIBVIRT_LOCK_MANAGER_PLUGIN_DIR");
+ char *modfile = NULL;
+
+ if (moddir == NULL)
+ moddir = DEFAULT_LOCK_MANAGER_PLUGIN_DIR;
+
+ VIR_DEBUG("Module load %s from %s", name, moddir);
+
+ if (virAsprintf(&modfile, "%s/%s.so", moddir, name) < 0) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ if (access(modfile, R_OK) < 0) {
+ virReportSystemError(errno,
+ _("Plugin %s not accessible"),
+ modfile);
+ goto cleanup;
+ }
+
+ handle = dlopen(modfile, RTLD_NOW | RTLD_LOCAL);
+ if (!handle) {
+ virLockError(VIR_ERR_SYSTEM_ERROR,
+ _("Failed to load plugin %s: %s"),
+ modfile, dlerror());
+ goto cleanup;
+ }
+
+ if (!(driver = dlsym(handle, "virLockDriverImpl"))) {
+ virLockError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Missing plugin initialization symbol
'virLockDriverImpl'"));
+ goto cleanup;
+ }
+
+ if (driver->drvInit(VIR_LOCK_MANAGER_VERSION, flags) < 0) {
+ virLockError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("plugin ABI is not compatible"));
+ goto cleanup;
+ }
+
+ if (VIR_ALLOC(plugin) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ plugin->driver = driver;
+ plugin->handle = handle;
+ plugin->refs = 1;
+
+ VIR_FREE(modfile);
+ return plugin;
+
+cleanup:
+ VIR_FREE(modfile);
+ if (handle)
+ dlclose(handle);
+ return NULL;
+}
+
+
+/**
+ * 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.
+ *
+ */
+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_WARN0("Unable to unload lock maanger plugin from memory");
+ return;
+ }
+
+ VIR_FREE(plugin);
+}
+
+
+/**
+ * virLockManagerNew:
+ * @plugin: the plugin implementation to use
+ * @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
+ */
+virLockManagerPtr virLockManagerNew(virLockManagerPluginPtr plugin,
+ unsigned int type,
+ size_t nparams,
+ virLockManagerParamPtr params,
+ unsigned int flags)
+{
+ virLockManagerPtr manager;
+ VIR_DEBUG("plugin=%p type=%u nparams=%zu params=%p flags=%u",
+ plugin, type, nparams, params, flags);
+ virLockManagerLogParams(nparams, params);
+
+ CHECK_PLUGIN(drvNew, NULL);
+
+ if (VIR_ALLOC(manager) < 0) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ manager->driver = plugin->driver;
+
+ if (plugin->driver->drvNew(manager, type, nparams, params, flags) < 0) {
+ VIR_FREE(manager);
+ return NULL;
+ }
+
+ return manager;
+}
+
+
+int virLockManagerAddResource(virLockManagerPtr manager,
+ unsigned int type,
+ const char *name,
+ size_t nparams,
+ virLockManagerParamPtr params,
+ unsigned int flags)
+{
+ VIR_DEBUG("manager=%p type=%u name=%s nparams=%zu params=%p flags=%u",
+ manager, type, name, nparams, params, flags);
+ virLockManagerLogParams(nparams, params);
+
+ CHECK_MANAGER(drvAddResource, -1);
+
+ return manager->driver->drvAddResource(manager,
+ type, name,
+ nparams, params,
+ flags);
+}
+
+int virLockManagerAcquireObject(virLockManagerPtr manager,
+ const char *state,
+ unsigned int flags)
+{
+ VIR_DEBUG("manager=%p state=%s flags=%u", manager, state, flags);
+
+ CHECK_MANAGER(drvAcquireObject, -1);
+
+ return manager->driver->drvAcquireObject(manager, state, flags);
+}
+
+
+int virLockManagerAttachObject(virLockManagerPtr manager,
+ unsigned int flags)
+{
+ VIR_DEBUG("manager=%p flags=%u", manager, flags);
+
+ CHECK_MANAGER(drvAttachObject, -1);
+
+ return manager->driver->drvAttachObject(manager, flags);
+}
+
+
+int virLockManagerDetachObject(virLockManagerPtr manager,
+ unsigned int flags)
+{
+ VIR_DEBUG("manager=%p flags=%u", manager, flags);
+
+ CHECK_MANAGER(drvDetachObject, -1);
+
+ return manager->driver->drvDetachObject(manager, flags);
+}
+
+
+int virLockManagerReleaseObject(virLockManagerPtr manager,
+ unsigned int flags)
+{
+ VIR_DEBUG("manager=%p flags=%u", manager, flags);
+
+ CHECK_MANAGER(drvReleaseObject, -1);
+
+ return manager->driver->drvReleaseObject(manager, flags);
+}
+
+
+int virLockManagerGetState(virLockManagerPtr manager,
+ char **state,
+ unsigned int flags)
+{
+ VIR_DEBUG("manager=%p state=%p flags=%u", manager, state, flags);
+
+ CHECK_MANAGER(drvGetState, -1);
+
+ return manager->driver->drvGetState(manager, state, flags);
+}
+
+
+int virLockManagerAcquireResource(virLockManagerPtr manager,
+ unsigned int type,
+ const char *name,
+ size_t nparams,
+ virLockManagerParamPtr params,
+ unsigned int flags)
+{
+ VIR_DEBUG("manager=%p type=%u name=%s nparams=%zu params=%p flags=%u",
+ manager, type, name, nparams, params, flags);
+ virLockManagerLogParams(nparams, params);
+
+ CHECK_MANAGER(drvAcquireResource, -1);
+
+ return manager->driver->drvAcquireResource(manager,
+ type, name,
+ nparams, params,
+ flags);
+}
+
+
+int virLockManagerReleaseResource(virLockManagerPtr manager,
+ unsigned int type,
+ const char *name,
+ size_t nparams,
+ virLockManagerParamPtr params,
+ unsigned int flags)
+{
+ VIR_DEBUG("manager=%p type=%u name=%s nparams=%zu params=%p flags=%u",
+ manager, type, name, nparams, params, flags);
+ virLockManagerLogParams(nparams, params);
+
+ CHECK_MANAGER(drvReleaseResource, -1);
+
+ return manager->driver->drvReleaseResource(manager,
+ type, name,
+ nparams, params,
+ flags);
+}
+
+
+int virLockManagerFree(virLockManagerPtr manager)
+{
+ VIR_DEBUG("manager=%p", manager);
+
+ if (!manager)
+ return 0;
+
+ CHECK_MANAGER(drvFree, -1);
+
+ manager->driver->drvFree(manager);
+
+ return 0;
+}
diff --git a/src/locking/lock_manager.h b/src/locking/lock_manager.h
new file mode 100644
index 0000000..a33cb68
--- /dev/null
+++ b/src/locking/lock_manager.h
@@ -0,0 +1,79 @@
+/*
+ * lock_manager.h: Defines 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
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef __VIR_LOCK_MANAGER_H__
+# define __VIR_LOCK_MANAGER_H__
+
+# include "internal.h"
+# include "lock_driver.h"
+
+typedef struct _virLockManagerPlugin virLockManagerPlugin;
+typedef virLockManagerPlugin *virLockManagerPluginPtr;
+
+virLockManagerPluginPtr virLockManagerPluginNew(const char *name,
+ unsigned int flags);
+void virLockManagerPluginRef(virLockManagerPluginPtr plugin);
+void virLockManagerPluginUnref(virLockManagerPluginPtr plugin);
+
+virLockManagerPtr virLockManagerNew(virLockManagerPluginPtr plugin,
+ unsigned int type,
+ size_t nparams,
+ virLockManagerParamPtr params,
+ unsigned int flags);
+
+int virLockManagerAddResource(virLockManagerPtr manager,
+ unsigned int type,
+ const char *name,
+ size_t nparams,
+ virLockManagerParamPtr params,
+ unsigned int flags);
+
+int virLockManagerAcquireObject(virLockManagerPtr manager,
+ const char *state,
+ unsigned int flags);
+int virLockManagerAttachObject(virLockManagerPtr manager,
+ unsigned int flags);
+int virLockManagerDetachObject(virLockManagerPtr manager,
+ unsigned int flags);
+int virLockManagerReleaseObject(virLockManagerPtr manager,
+ unsigned int flags);
+
+int virLockManagerGetState(virLockManagerPtr manager,
+ char **state,
+ unsigned int flags);
+
+int virLockManagerAcquireResource(virLockManagerPtr manager,
+ unsigned int type,
+ const char *name,
+ size_t nparams,
+ virLockManagerParamPtr params,
+ unsigned int flags);
+
+int virLockManagerReleaseResource(virLockManagerPtr manager,
+ unsigned int type,
+ const char *name,
+ size_t nparams,
+ virLockManagerParamPtr params,
+ unsigned int flags);
+
+int virLockManagerFree(virLockManagerPtr manager);
+
+#endif /* __VIR_LOCK_MANAGER_H__ */
diff --git a/src/util/virterror.c b/src/util/virterror.c
index e45b582..c90fdfb 100644
--- a/src/util/virterror.c
+++ b/src/util/virterror.c
@@ -200,6 +200,9 @@ static const char *virErrorDomainName(virErrorDomain domain) {
case VIR_FROM_STREAMS:
dom = "Streams ";
break;
+ case VIR_FROM_LOCKING:
+ dom = "Locking ";
+ break;
}
return(dom);
}
--
1.7.3.4