From: "Daniel P. Berrange" <berrange(a)redhat.com>
This adds a 'lockd' lock driver which is just a client which
talks to the lockd daemon to perform all locking. This will
be the default lock driver for any hypervisor which needs one.
* src/Makefile.am: Add lockd.so plugin
* src/locking/lock_driver_lockd.c: Lockd driver impl
---
src/Makefile.am | 16 +-
src/locking/lock_driver_lockd.c | 600 +++++++++++++++++++++++++++++++++++++++
2 files changed, 613 insertions(+), 3 deletions(-)
create mode 100644 src/locking/lock_driver_lockd.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 3e2c376..9a9deab 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -111,6 +111,10 @@ LOCKD_GENERATED = \
BUILT_SOURCES += $(LOCKD_GENERATED)
+LOCK_DRIVER_LOCKD_SOURCES = \
+ locking/lock_driver_lockd.c \
+ $(LOCK_PROTOCOL_GENERATED)
+
LOCK_DAEMON_SOURCES = \
locking/lock_daemon.c \
locking/lock_daemon_dispatch.h \
@@ -1211,6 +1215,14 @@ libvirt_qemu_la_LIBADD = libvirt.la $(CYGWIN_EXTRA_LIBADD)
EXTRA_DIST += $(LIBVIRT_QEMU_SYMBOL_FILE)
if WITH_LIBVIRTD
+lockdriverdir = $(libdir)/libvirt/lock-driver
+lockdriver_LTLIBRARIES = lockd.la
+
+lockd_la_SOURCES = $(LOCK_DRIVER_LOCKD_SOURCES)
+lockd_la_CFLAGS = $(AM_CFLAGS)
+lockd_la_LDFLAGS = -module -avoid-version
+lockd_la_LIBADD = ../gnulib/lib/libgnu.la libvirt-net-rpc.la libvirt-net-rpc-client.la
+
sbin_PROGRAMS = virtlockd
virtlockd_SOURCES = $(LOCK_DAEMON_SOURCES)
@@ -1272,9 +1284,7 @@ virtlockd.init: locking/virtlockd.init.in
$(top_builddir)/config.status
if HAVE_SANLOCK
-lockdriverdir = $(libdir)/libvirt/lock-driver
-lockdriver_LTLIBRARIES = sanlock.la
-
+lockdriver_LTLIBRARIES += sanlock.la
sanlock_la_SOURCES = $(LOCK_DRIVER_SANLOCK_SOURCES)
sanlock_la_CFLAGS = $(AM_CFLAGS)
sanlock_la_LDFLAGS = -module -avoid-version
diff --git a/src/locking/lock_driver_lockd.c b/src/locking/lock_driver_lockd.c
new file mode 100644
index 0000000..b7ac0f7
--- /dev/null
+++ b/src/locking/lock_driver_lockd.c
@@ -0,0 +1,600 @@
+/*
+ * lock_driver_lockd.c: A lock driver which locks nothing
+ *
+ * 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_driver.h"
+#include "memory.h"
+#include "logging.h"
+#include "uuid.h"
+#include "util.h"
+#include "files.h"
+#include "virterror_internal.h"
+#include "rpc/virnetclient.h"
+#include "lock_protocol.h"
+#include "configmake.h"
+
+#define VIR_FROM_THIS VIR_FROM_LOCKING
+
+#define virLockError(code, ...) \
+ virReportErrorHelper(VIR_FROM_THIS, code, __FILE__, \
+ __FUNCTION__, __LINE__, __VA_ARGS__)
+
+typedef struct _virLockManagerLockDPrivate virLockManagerLockDPrivate;
+typedef virLockManagerLockDPrivate *virLockManagerLockDPrivatePtr;
+
+typedef struct _virLockManagerLockDResource virLockManagerLockDResource;
+typedef virLockManagerLockDResource *virLockManagerLockDResourcePtr;
+
+struct _virLockManagerLockDResource {
+ int type;
+ char *name;
+ unsigned int flags;
+ size_t nparams;
+ virLockManagerParamPtr params;
+};
+
+struct _virLockManagerLockDPrivate {
+ int type;
+ unsigned int flags;
+ size_t nparams;
+ virLockManagerParamPtr params;
+ size_t nresources;
+ virLockManagerLockDResourcePtr resources;
+};
+
+
+static virLockManagerParamPtr
+virLockManagerLockDCopyParams(size_t nParams,
+ virLockManagerParamPtr params)
+{
+ virLockManagerParamPtr newParams;
+ size_t i, j;
+
+ if (VIR_ALLOC_N(newParams, nParams) < 0) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ memcpy(newParams, params, sizeof(*params)*nParams);
+
+ for (i = 0 ; i < nParams ; i++) {
+ if (params[i].type == VIR_LOCK_MANAGER_PARAM_TYPE_STRING) {
+ if (!(newParams[i].value.str = strdup(params[i].value.str))) {
+ virReportOOMError();
+ goto error;
+ }
+ }
+ }
+
+ return newParams;
+
+error:
+ for (j = 0 ; j < i ; j++) {
+ VIR_FREE(newParams[i].value.str);
+ }
+ VIR_FREE(newParams);
+ return NULL;
+}
+
+static int virLockManagerLockDInit(unsigned int version,
+ const char *configFile,
+ unsigned int flags)
+{
+ VIR_DEBUG("version=%u configFile=%s flags=%u", version,
NULLSTR(configFile), flags);
+
+ return 0;
+}
+
+static int virLockManagerLockDDeinit(void)
+{
+ VIR_DEBUG(" ");
+
+ return 0;
+}
+
+
+static void virLockManagerLockDFreeParams(size_t nparams,
+ virLockManagerParamPtr params)
+{
+ size_t i;
+
+ if (!params)
+ return;
+
+ for (i = 0 ; i < nparams ; i++) {
+ if (params[i].type == VIR_LOCK_MANAGER_PARAM_TYPE_STRING)
+ VIR_FREE(params[i].value.str);
+ }
+
+ VIR_FREE(params);
+}
+
+
+static void virLockManagerLockDFree(virLockManagerPtr lock)
+{
+ virLockManagerLockDPrivatePtr priv = lock->privateData;
+ size_t i;
+
+ if (!priv)
+ return;
+
+ lock->privateData = NULL;
+
+ for (i = 0 ; i < priv->nresources ; i++)
+ virLockManagerLockDFreeParams(priv->resources[i].nparams,
+ priv->resources[i].params);
+ VIR_FREE(priv->resources);
+
+ virLockManagerLockDFreeParams(priv->nparams, priv->params);
+ VIR_FREE(priv);
+}
+
+
+static lock_param *virLockManagerLockDAddParams(size_t nparams,
+ virLockManagerParamPtr params)
+{
+ size_t i;
+ lock_param *vals = NULL;
+
+ if (VIR_ALLOC_N(vals, nparams) < 0) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ for (i = 0 ; i < nparams ; i++) {
+ vals[i].key = (char*)params[i].key;
+ vals[i].value.type = params[i].type;
+ switch (params[i].type) {
+ case VIR_LOCK_MANAGER_PARAM_TYPE_STRING:
+ vals[i].value.lock_param_value_u.s = params[i].value.str;
+ break;
+ case VIR_LOCK_MANAGER_PARAM_TYPE_INT:
+ vals[i].value.lock_param_value_u.i = params[i].value.i;
+ break;
+ case VIR_LOCK_MANAGER_PARAM_TYPE_LONG:
+ vals[i].value.lock_param_value_u.l = params[i].value.l;
+ break;
+ case VIR_LOCK_MANAGER_PARAM_TYPE_UINT:
+ vals[i].value.lock_param_value_u.ui = params[i].value.ui;
+ break;
+ case VIR_LOCK_MANAGER_PARAM_TYPE_ULONG:
+ vals[i].value.lock_param_value_u.ul = params[i].value.ul;
+ break;
+ case VIR_LOCK_MANAGER_PARAM_TYPE_DOUBLE:
+ vals[i].value.lock_param_value_u.d = params[i].value.d;
+ break;
+ case VIR_LOCK_MANAGER_PARAM_TYPE_UUID:
+ memcpy(vals[i].value.lock_param_value_u.u, params[i].value.uuid,
VIR_UUID_BUFLEN);
+ break;
+ }
+ }
+
+ return vals;
+}
+
+
+static char *virLockManagerLockDPath(bool privileged)
+{
+ char *path;
+ if (privileged) {
+ if (!(path = strdup(LOCALSTATEDIR "/run/libvirt/lockd/lockd.sock"))) {
+ virReportOOMError();
+ return NULL;
+ }
+ } else {
+ char *userdir;
+ if (!(userdir = virGetUserDirectory(geteuid())))
+ return NULL;
+
+ if (virAsprintf(&path, "%s/.libvirt/lockd/lockd.sock", userdir)
< 0) {
+ virReportOOMError();
+ }
+ VIR_FREE(userdir);
+ }
+ return path;
+}
+
+
+static int virLockManagerLockDNew(virLockManagerPtr lock,
+ unsigned int type,
+ size_t nparams,
+ virLockManagerParamPtr params,
+ unsigned int flags)
+{
+ virLockManagerLockDPrivatePtr priv;
+
+ if (VIR_ALLOC(priv) < 0) {
+ virReportOOMError();
+ return -1;
+ }
+ lock->privateData = priv;
+
+ if (nparams > LOCK_PARAMETERS_MAX) {
+ virLockError(VIR_ERR_INTERNAL_ERROR,
+ _("Too many parameters %zu for lock program, max %d"),
+ nparams, LOCK_PARAMETERS_MAX);
+ goto error;
+ }
+
+ priv->type = type;
+ priv->flags = flags;
+ priv->nparams = nparams;
+ if (!(priv->params = virLockManagerLockDCopyParams(nparams, params)))
+ goto error;
+
+ return 0;
+
+error:
+ virLockManagerLockDFree(lock);
+ return -1;
+}
+
+
+static int virLockManagerLockDAddResource(virLockManagerPtr lock,
+ unsigned int type,
+ const char *name,
+ size_t nparams,
+ virLockManagerParamPtr params,
+ unsigned int flags)
+{
+ virLockManagerLockDPrivatePtr priv = lock->privateData;
+ lock_add_resource_args args;
+ char *newName;
+ virLockManagerParamPtr newParams = NULL;
+
+ memset(&args, 0, sizeof(args));
+
+ if (nparams > LOCK_PARAMETERS_MAX) {
+ virLockError(VIR_ERR_INTERNAL_ERROR,
+ _("Too many parameters %zu for lock program, max %d"),
+ nparams, LOCK_PARAMETERS_MAX);
+ goto error;
+ }
+
+ if (!(newName = strdup(name)))
+ goto no_memory;
+
+ if (!(newParams = virLockManagerLockDCopyParams(nparams, params)))
+ goto no_memory;
+
+ if (VIR_EXPAND_N(priv->resources, priv->nresources, 1) < 0)
+ goto no_memory;
+
+ priv->resources[priv->nresources-1].type = type;
+ priv->resources[priv->nresources-1].flags = flags;
+ priv->resources[priv->nresources-1].name = newName;
+ priv->resources[priv->nresources-1].nparams = nparams;
+ priv->resources[priv->nresources-1].params = newParams;
+
+ return 0;
+
+no_memory:
+ virReportOOMError();
+error:
+ virLockManagerLockDFreeParams(nparams, newParams);
+ VIR_FREE(newName);
+ return -1;
+}
+
+
+static virNetClientPtr virLockManagerLockDConnectionNew(bool privileged,
+ virNetClientProgramPtr *prog)
+{
+ virNetClientPtr client = NULL;
+ char *lockdpath;
+
+ *prog = NULL;
+
+ if (!(lockdpath = virLockManagerLockDPath(privileged)))
+ goto error;
+
+ if (!(client = virNetClientNewUNIX(lockdpath,
+ false, NULL)))
+ goto error;
+
+ if (!(*prog = virNetClientProgramNew(LOCK_PROGRAM,
+ LOCK_PROTOCOL_VERSION,
+ NULL,
+ 0,
+ NULL)))
+ goto error;
+
+ if (virNetClientAddProgram(client, *prog) < 0)
+ goto error;
+
+ VIR_FREE(lockdpath);
+
+ return client;
+
+error:
+ VIR_FREE(lockdpath);
+ virNetClientFree(client);
+ virNetClientProgramFree(*prog);
+ return NULL;
+}
+
+
+static int virLockManagerLockDConnectionRegister(virLockManagerPtr lock,
+ virNetClientPtr client,
+ virNetClientProgramPtr program,
+ int *counter,
+ bool restrictAccess)
+{
+ virLockManagerLockDPrivatePtr priv = lock->privateData;
+ lock_register_args args;
+ int rv = -1;
+
+ memset(&args, 0, sizeof(args));
+
+ args.type = priv->type;
+ args.flags = priv->flags;
+ args.restrictAccess = restrictAccess;
+ args.params.params_len = priv->nparams;
+ if (!(args.params.params_val = virLockManagerLockDAddParams(priv->nparams,
priv->params)))
+ goto cleanup;
+
+ if (virNetClientProgramCall(program,
+ client,
+ (*counter)++,
+ LOCK_PROC_REGISTER,
+ (xdrproc_t)xdr_lock_register_args, (char*)&args,
+ (xdrproc_t)xdr_void, NULL) < 0)
+ goto cleanup;
+
+ rv = 0;
+
+cleanup:
+ VIR_FREE(args.params.params_val);
+ return rv;
+}
+
+
+static int virLockManagerLockDConnectionAddResource(virLockManagerPtr lock,
+ virNetClientPtr client,
+ virNetClientProgramPtr program,
+ int *counter,
+ size_t res)
+{
+ virLockManagerLockDPrivatePtr priv = lock->privateData;
+ lock_add_resource_args args;
+ int rv = -1;
+
+ memset(&args, 0, sizeof(args));
+
+ args.type = priv->resources[res].type;
+ args.flags = priv->resources[res].flags;
+ args.name = priv->resources[res].name;
+ args.params.params_len = priv->resources[res].nparams;
+ if (!(args.params.params_val =
virLockManagerLockDAddParams(priv->resources[res].nparams,
+
priv->resources[res].params)))
+ goto cleanup;
+
+ if (virNetClientProgramCall(program,
+ client,
+ (*counter)++,
+ LOCK_PROC_ADD_RESOURCE,
+ (xdrproc_t)xdr_lock_add_resource_args, &args,
+ (xdrproc_t)xdr_void, NULL) < 0)
+ goto cleanup;
+
+ rv = 0;
+
+cleanup:
+ VIR_FREE(args.params.params_val);
+ return rv;
+}
+
+static int virLockManagerLockDConnectionSetup(virLockManagerPtr lock,
+ virNetClientPtr client,
+ virNetClientProgramPtr program,
+ int *counter,
+ bool registerOnly,
+ bool restrictAccess)
+{
+ virLockManagerLockDPrivatePtr priv = lock->privateData;
+ size_t i;
+
+ if (virLockManagerLockDConnectionRegister(lock, client, program,
+ counter, restrictAccess) < 0)
+ return -1;
+
+ if (registerOnly)
+ return 0;
+
+ for (i = 0 ; i < priv->nresources ; i++) {
+ if (virLockManagerLockDConnectionAddResource(lock, client, program,
+ counter, i) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+static int virLockManagerLockDAcquire(virLockManagerPtr lock,
+ const char *state,
+ unsigned int flags,
+ int *fd)
+{
+ virNetClientPtr client = NULL;
+ virNetClientProgramPtr program = NULL;
+ int counter = 0;
+ lock_acquire_args args;
+ int rv = -1;
+
+ memset(&args, 0, sizeof(args));
+
+ if (!(client = virLockManagerLockDConnectionNew(getuid() == 0, &program)))
+ return -1;
+
+ if (fd &&
+ (*fd = virNetClientDupFD(client)) < 0)
+ goto cleanup;
+
+ if (virLockManagerLockDConnectionSetup(lock, client, program, &counter,
+ flags &
VIR_LOCK_MANAGER_ACQUIRE_REGISTER_ONLY,
+ flags & VIR_LOCK_MANAGER_ACQUIRE_RESTRICT)
< 0)
+ goto cleanup;
+
+ if (!(flags & VIR_LOCK_MANAGER_ACQUIRE_REGISTER_ONLY)) {
+ args.flags = flags;
+ if (state) {
+ if (VIR_ALLOC(args.state) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ *args.state = (char*)state;
+ }
+
+ if (virNetClientProgramCall(program,
+ client,
+ counter++,
+ LOCK_PROC_ACQUIRE,
+ (xdrproc_t)xdr_lock_acquire_args, &args,
+ (xdrproc_t)xdr_void, NULL) < 0)
+ goto cleanup;
+ }
+
+ rv = 0;
+
+cleanup:
+ if (rv != 0 && fd)
+ VIR_FORCE_CLOSE(*fd);
+ VIR_FREE(args.state);
+ virNetClientFree(client);
+ virNetClientProgramFree(program);
+
+ return rv;
+}
+
+static int virLockManagerLockDRelease(virLockManagerPtr lock,
+ char **state,
+ unsigned int flags)
+{
+ virNetClientPtr client = NULL;
+ virNetClientProgramPtr program = NULL;
+ int counter = 0;
+ lock_release_args args;
+ lock_release_ret ret;
+ int rv = -1;
+
+ memset(&args, 0, sizeof(args));
+
+ if (!(client = virLockManagerLockDConnectionNew(getuid() == 0, &program)))
+ return -1;
+
+ if (virLockManagerLockDConnectionSetup(lock, client, program,
+ &counter, false, false) < 0)
+ goto cleanup;
+
+ args.flags = flags;
+
+ if (virNetClientProgramCall(program,
+ client,
+ counter++,
+ LOCK_PROC_RELEASE,
+ (xdrproc_t)xdr_lock_release_args, &args,
+ (xdrproc_t)xdr_lock_release_ret, &ret) < 0)
+ goto cleanup;
+
+ if (ret.state) {
+ if (state)
+ *state = *ret.state;
+ else
+ VIR_FREE(*ret.state);
+ VIR_FREE(ret.state);
+ }
+
+ rv = 0;
+
+cleanup:
+ virNetClientFree(client);
+ virNetClientProgramFree(program);
+
+ return rv;
+}
+
+
+static int virLockManagerLockDInquire(virLockManagerPtr lock,
+ char **state,
+ unsigned int flags)
+{
+ virNetClientPtr client = NULL;
+ virNetClientProgramPtr program = NULL;
+ int counter = 0;
+ lock_inquire_args args;
+ lock_inquire_ret ret;
+ int rv = -1;
+
+ memset(&args, 0, sizeof(args));
+
+ if (!(client = virLockManagerLockDConnectionNew(getuid() == 0, &program)))
+ return -1;
+
+ if (virLockManagerLockDConnectionSetup(lock, client, program,
+ &counter, false, false) < 0)
+ goto cleanup;
+
+ args.flags = flags;
+
+ if (virNetClientProgramCall(program,
+ client,
+ counter++,
+ LOCK_PROC_INQUIRE,
+ (xdrproc_t)xdr_lock_inquire_args, &args,
+ (xdrproc_t)xdr_lock_inquire_ret, &ret) < 0)
+ goto cleanup;
+
+ if (ret.state) {
+ if (state)
+ *state = *ret.state;
+ else
+ VIR_FREE(*ret.state);
+ VIR_FREE(ret.state);
+ }
+
+ rv = 0;
+
+cleanup:
+ virNetClientFree(client);
+ virNetClientProgramFree(program);
+
+ return rv;
+}
+
+virLockDriver virLockDriverImpl =
+{
+ .version = VIR_LOCK_MANAGER_VERSION,
+ .flags = 0,
+
+ .drvInit = virLockManagerLockDInit,
+ .drvDeinit = virLockManagerLockDDeinit,
+
+ .drvNew = virLockManagerLockDNew,
+ .drvFree = virLockManagerLockDFree,
+
+ .drvAddResource = virLockManagerLockDAddResource,
+
+ .drvAcquire = virLockManagerLockDAcquire,
+ .drvRelease = virLockManagerLockDRelease,
+
+ .drvInquire = virLockManagerLockDInquire,
+};
--
1.7.6