[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [PATCH 06/11] Basic framework for lock manager plugins



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/@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


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]