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
Signed-off-by: Daniel P. Berrange <berrange(a)redhat.com>
---
po/POTFILES.in | 1 +
src/Makefile.am | 26 +-
src/locking/lock_driver_lockd.c | 561 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 584 insertions(+), 4 deletions(-)
create mode 100644 src/locking/lock_driver_lockd.c
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 6fe9690..618267b 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -42,6 +42,7 @@ src/libvirt.c
src/libvirt-qemu.c
src/locking/lock_daemon.c
src/locking/lock_daemon_dispatch.c
+src/locking/lock_driver_lockd.c
src/locking/lock_driver_sanlock.c
src/locking/lock_manager.c
src/lxc/lxc_cgroup.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 35e8338..777ce07 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -156,6 +156,10 @@ LOCK_DAEMON_GENERATED = \
BUILT_SOURCES += $(LOCK_DAEMON_GENERATED)
MAINTAINERCLEANFILES += $(LOCK_DAEMON_GENERATED)
+LOCK_DRIVER_LOCKD_SOURCES = \
+ locking/lock_driver_lockd.c \
+ $(NULL)
+
LOCK_DAEMON_SOURCES = \
locking/lock_daemon.h \
locking/lock_daemon.c \
@@ -1478,7 +1482,22 @@ libvirt_qemu_la_CFLAGS = $(AM_CFLAGS)
libvirt_qemu_la_LIBADD = libvirt.la $(CYGWIN_EXTRA_LIBADD)
EXTRA_DIST += $(LIBVIRT_QEMU_SYMBOL_FILE)
+lockdriverdir = $(libdir)/libvirt/lock-driver
+lockdriver_LTLIBRARIES =
+
if WITH_LIBVIRTD
+lockdriver_LTLIBRARIES += lockd.la
+lockd_la_SOURCES = \
+ $(LOCK_DRIVER_LOCKD_SOURCES) \
+ $(LOCK_PROTOCOL_GENERATED) \
+ $(NULL)
+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
+if WITH_DTRACE_PROBES
+lockd_la_LIBADD += libvirt_probes.lo
+endif
+
sbin_PROGRAMS = virtlockd
virtlockd_SOURCES = \
@@ -1506,7 +1525,8 @@ virtlockd_LDADD += libvirt_probes.lo
endif
else
-EXTRA_DIST += $(LOCK_DAEMON_SOURCES)
+EXTRA_DIST += $(LOCK_DAEMON_SOURCES) \
+ $(LOCK_DRIVER_LOCKD_SOURCES)
endif
EXTRA_DIST += locking/virtlockd.sysconf
@@ -1600,9 +1620,7 @@ virtlockd.socket: locking/virtlockd.socket.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..462996b
--- /dev/null
+++ b/src/locking/lock_driver_lockd.c
@@ -0,0 +1,561 @@
+/*
+ * 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, see
+ * <
http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <config.h>
+
+#include "lock_driver.h"
+#include "memory.h"
+#include "logging.h"
+#include "uuid.h"
+#include "util.h"
+#include "virfile.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 _virLockManagerLockDaemonPrivate virLockManagerLockDaemonPrivate;
+typedef virLockManagerLockDaemonPrivate *virLockManagerLockDaemonPrivatePtr;
+
+typedef struct _virLockManagerLockDaemonResource virLockManagerLockDaemonResource;
+typedef virLockManagerLockDaemonResource *virLockManagerLockDaemonResourcePtr;
+
+struct _virLockManagerLockDaemonResource {
+ char *lockspace;
+ char *name;
+ unsigned int flags;
+};
+
+struct _virLockManagerLockDaemonPrivate {
+ unsigned char uuid[VIR_UUID_BUFLEN];
+ char *name;
+ int id;
+ pid_t pid;
+
+ size_t nresources;
+ virLockManagerLockDaemonResourcePtr resources;
+};
+
+
+#define VIRTLOCKD_PATH SBINDIR "/virtlockd"
+
+static const char *
+virLockManagerLockDaemonFindDaemon(void)
+{
+ const char *customDaemon = getenv("VIRTLOCKD_PATH");
+
+ if (customDaemon)
+ return customDaemon;
+
+ if (virFileIsExecutable(VIRTLOCKD_PATH))
+ return VIRTLOCKD_PATH;
+
+ return NULL;
+}
+
+static int virLockManagerLockDaemonInit(unsigned int version,
+ const char *configFile,
+ unsigned int flags)
+{
+ VIR_DEBUG("version=%u configFile=%s flags=%x", version,
NULLSTR(configFile), flags);
+
+ return 0;
+}
+
+static int virLockManagerLockDaemonDeinit(void)
+{
+ VIR_DEBUG(" ");
+
+ return 0;
+}
+
+static void virLockManagerLockDaemonFree(virLockManagerPtr lock)
+{
+ virLockManagerLockDaemonPrivatePtr priv = lock->privateData;
+ size_t i;
+
+ if (!priv)
+ return;
+
+ lock->privateData = NULL;
+
+ for (i = 0 ; i < priv->nresources ; i++) {
+ VIR_FREE(priv->resources[i].lockspace);
+ VIR_FREE(priv->resources[i].name);
+ }
+ VIR_FREE(priv->resources);
+
+ VIR_FREE(priv->name);
+
+ VIR_FREE(priv);
+}
+
+
+static char *virLockManagerLockDaemonPath(bool privileged)
+{
+ char *path;
+ if (privileged) {
+ if (!(path = strdup(LOCALSTATEDIR
"/run/libvirt/virtlockd/virtlockd.sock"))) {
+ virReportOOMError();
+ return NULL;
+ }
+ } else {
+ char *userdir;
+ if (!(userdir = virGetUserDirectory()))
+ return NULL;
+
+ if (virAsprintf(&path, "%s/.libvirt/virtlockd/virtlockd.sock",
userdir) < 0) {
+ virReportOOMError();
+ }
+ VIR_FREE(userdir);
+ }
+ return path;
+}
+
+
+static int virLockManagerLockDaemonNew(virLockManagerPtr lock,
+ unsigned int type,
+ size_t nparams,
+ virLockManagerParamPtr params,
+ unsigned int flags)
+{
+ virLockManagerLockDaemonPrivatePtr priv;
+ size_t i;
+
+ virCheckFlags(VIR_LOCK_MANAGER_USES_STATE, -1);
+
+ if (VIR_ALLOC(priv) < 0) {
+ virReportOOMError();
+ return -1;
+ }
+ lock->privateData = priv;
+
+ switch (type) {
+ case VIR_LOCK_MANAGER_OBJECT_TYPE_DOMAIN:
+ for (i = 0 ; i < nparams ; i++) {
+ if (STREQ(params[i].key, "uuid")) {
+ memcpy(priv->uuid, params[i].value.uuid, VIR_UUID_BUFLEN);
+ } else if (STREQ(params[i].key, "name")) {
+ if (!(priv->name = strdup(params[i].value.str))) {
+ virReportOOMError();
+ return -1;
+ }
+ } else if (STREQ(params[i].key, "id")) {
+ priv->id = params[i].value.i;
+ } else if (STREQ(params[i].key, "pid")) {
+ priv->pid = params[i].value.i;
+ } else {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unexpected parameter %s for object"),
+ params[i].key);
+ }
+ }
+ if (priv->id == 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Missing ID parameter for domain object"));
+ return -1;
+ }
+ if (priv->pid == 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Missing PID parameter for domain object"));
+ return -1;
+ }
+ if (!priv->name) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Missing name parameter for domain object"));
+ return -1;
+ }
+ if (!virUUIDIsValid(priv->uuid)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Missing UUID parameter for domain object"));
+ return -1;
+ }
+ break;
+
+ default:
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unknown lock manager object type %d"),
+ type);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int virLockManagerLockDaemonAddResource(virLockManagerPtr lock,
+ unsigned int type,
+ const char *name,
+ size_t nparams,
+ virLockManagerParamPtr params,
+ unsigned int flags)
+{
+ virLockManagerLockDaemonPrivatePtr priv = lock->privateData;
+ char *newName;
+ char *newLockspace = NULL;
+
+ virCheckFlags(VIR_LOCK_MANAGER_RESOURCE_READONLY |
+ VIR_LOCK_MANAGER_RESOURCE_SHARED, -1);
+
+ if (flags & VIR_LOCK_MANAGER_RESOURCE_READONLY)
+ return 0;
+
+ switch (type) {
+ case VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK:
+ if (params || nparams) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Unexpected parameters for disk resource"));
+ return -1;
+ }
+ if (!(newLockspace = strdup(""))) {
+ virReportOOMError();
+ return -1;
+ }
+ break;
+ case VIR_LOCK_MANAGER_RESOURCE_TYPE_LEASE: {
+ size_t i;
+ char *path = NULL;
+ char *lockspace = NULL;
+ for (i = 0 ; i < nparams ; i++) {
+ if (STREQ(params[i].key, "offset")) {
+ if (params[i].value.ul != 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Offset must be zero for this lock
manager"));
+ return -1;
+ }
+ } else if (STREQ(params[i].key, "lockspace")) {
+ lockspace = params[i].value.str;
+ } else if (STREQ(params[i].key, "path")) {
+ path = params[i].value.str;
+ } else {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unexpected parameter %s for lease
resource"),
+ params[i].key);
+ return -1;
+ }
+ }
+ if (!path || !lockspace) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Missing path or lockspace for lease resource"));
+ return -1;
+ }
+ if (virAsprintf(&newLockspace, "%s/%s",
+ path, lockspace) < 0) {
+ virReportOOMError();
+ return -1;
+ }
+ } break;
+ default:
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unknown lock manager object type %d"),
+ type);
+ return -1;
+ }
+
+ if (!(newName = strdup(name)))
+ goto no_memory;
+
+ if (VIR_EXPAND_N(priv->resources, priv->nresources, 1) < 0)
+ goto no_memory;
+
+ priv->resources[priv->nresources-1].lockspace = newLockspace;
+ priv->resources[priv->nresources-1].name = newName;
+
+ if (flags & VIR_LOCK_MANAGER_RESOURCE_SHARED)
+ priv->resources[priv->nresources-1].flags |=
+ VIR_LOCK_SPACE_PROTOCOL_ACQUIRE_RESOURCE_SHARED;
+
+ return 0;
+
+no_memory:
+ virReportOOMError();
+ VIR_FREE(newName);
+ return -1;
+}
+
+
+static int
+virLockManagerLockDaemonConnectionRegister(virLockManagerPtr lock,
+ virNetClientPtr client,
+ virNetClientProgramPtr program,
+ int *counter)
+{
+ virLockManagerLockDaemonPrivatePtr priv = lock->privateData;
+ virLockSpaceProtocolRegisterArgs args;
+ int rv = -1;
+
+ memset(&args, 0, sizeof(args));
+
+ args.flags = 0;
+ memcpy(args.owner.uuid, priv->uuid, VIR_UUID_BUFLEN);
+ args.owner.name = priv->name;
+ args.owner.id = priv->id;
+ args.owner.pid = priv->pid;
+
+ if (virNetClientProgramCall(program,
+ client,
+ (*counter)++,
+ VIR_LOCK_SPACE_PROTOCOL_PROC_REGISTER,
+ 0, NULL, NULL, NULL,
+ (xdrproc_t)xdr_virLockSpaceProtocolRegisterArgs,
(char*)&args,
+ (xdrproc_t)xdr_void, NULL) < 0)
+ goto cleanup;
+
+ rv = 0;
+
+cleanup:
+ return rv;
+}
+
+
+static int
+virLockManagerLockDaemonConnectionRestrict(virLockManagerPtr lock ATTRIBUTE_UNUSED,
+ virNetClientPtr client,
+ virNetClientProgramPtr program,
+ int *counter)
+{
+ virLockSpaceProtocolRestrictArgs args;
+ int rv = -1;
+
+ memset(&args, 0, sizeof(args));
+
+ args.flags = 0;
+
+ if (virNetClientProgramCall(program,
+ client,
+ (*counter)++,
+ VIR_LOCK_SPACE_PROTOCOL_PROC_RESTRICT,
+ 0, NULL, NULL, NULL,
+ (xdrproc_t)xdr_virLockSpaceProtocolRestrictArgs,
(char*)&args,
+ (xdrproc_t)xdr_void, NULL) < 0)
+ goto cleanup;
+
+ rv = 0;
+
+cleanup:
+ return rv;
+}
+
+
+static virNetClientPtr virLockManagerLockDaemonConnectionNew(bool privileged,
+ virNetClientProgramPtr
*prog)
+{
+ virNetClientPtr client = NULL;
+ char *lockdpath;
+ const char *daemonPath = NULL;
+
+ *prog = NULL;
+
+ if (!(lockdpath = virLockManagerLockDaemonPath(privileged)))
+ goto error;
+
+ if (!privileged)
+ daemonPath = virLockManagerLockDaemonFindDaemon();
+
+ if (!(client = virNetClientNewUNIX(lockdpath,
+ daemonPath != NULL,
+ daemonPath)))
+ goto error;
+
+ if (!(*prog = virNetClientProgramNew(VIR_LOCK_SPACE_PROTOCOL_PROGRAM,
+ VIR_LOCK_SPACE_PROTOCOL_PROGRAM_VERSION,
+ NULL,
+ 0,
+ NULL)))
+ goto error;
+
+ if (virNetClientAddProgram(client, *prog) < 0)
+ goto error;
+
+ VIR_FREE(lockdpath);
+
+ return client;
+
+error:
+ VIR_FREE(lockdpath);
+ virNetClientClose(client);
+ virObjectUnref(client);
+ virObjectUnref(*prog);
+ return NULL;
+}
+
+
+static virNetClientPtr
+virLockManagerLockDaemonConnect(virLockManagerPtr lock,
+ virNetClientProgramPtr *program,
+ int *counter)
+{
+ virNetClientPtr client;
+
+ if (!(client = virLockManagerLockDaemonConnectionNew(getuid() == 0, program)))
+ return NULL;
+
+ if (virLockManagerLockDaemonConnectionRegister(lock,
+ client,
+ *program,
+ counter) < 0)
+ goto error;
+
+ return client;
+
+error:
+ virNetClientClose(client);
+ virObjectUnref(client);
+ return NULL;
+}
+
+
+static int virLockManagerLockDaemonAcquire(virLockManagerPtr lock,
+ const char *state ATTRIBUTE_UNUSED,
+ unsigned int flags,
+ int *fd)
+{
+ virNetClientPtr client = NULL;
+ virNetClientProgramPtr program = NULL;
+ int counter = 0;
+ int rv = -1;
+ virLockManagerLockDaemonPrivatePtr priv = lock->privateData;
+
+ virCheckFlags(VIR_LOCK_MANAGER_ACQUIRE_REGISTER_ONLY |
+ VIR_LOCK_MANAGER_ACQUIRE_RESTRICT, -1);
+
+ if (!(client = virLockManagerLockDaemonConnect(lock, &program, &counter)))
+ goto cleanup;
+
+ if (fd &&
+ (*fd = virNetClientDupFD(client, false)) < 0)
+ goto cleanup;
+
+ if (!(flags & VIR_LOCK_MANAGER_ACQUIRE_REGISTER_ONLY)) {
+ size_t i;
+ for (i = 0 ; i < priv->nresources ; i++) {
+ virLockSpaceProtocolAcquireResourceArgs args;
+
+ memset(&args, 0, sizeof(args));
+
+ if (priv->resources[i].lockspace)
+ args.path = priv->resources[i].lockspace;
+ args.name = priv->resources[i].name;
+ args.flags = priv->resources[i].flags;
+
+ if (virNetClientProgramCall(program,
+ client,
+ counter++,
+ VIR_LOCK_SPACE_PROTOCOL_PROC_ACQUIRE_RESOURCE,
+ 0, NULL, NULL, NULL,
+
(xdrproc_t)xdr_virLockSpaceProtocolAcquireResourceArgs, &args,
+ (xdrproc_t)xdr_void, NULL) < 0)
+ goto cleanup;
+ }
+ }
+
+ if ((flags & VIR_LOCK_MANAGER_ACQUIRE_RESTRICT) &&
+ virLockManagerLockDaemonConnectionRestrict(lock, client, program, &counter)
< 0)
+ goto cleanup;
+
+ rv = 0;
+
+cleanup:
+ if (rv != 0 && fd)
+ VIR_FORCE_CLOSE(*fd);
+ virNetClientClose(client);
+ virObjectUnref(client);
+ virObjectUnref(program);
+
+ return rv;
+}
+
+static int virLockManagerLockDaemonRelease(virLockManagerPtr lock,
+ char **state,
+ unsigned int flags)
+{
+ virNetClientPtr client = NULL;
+ virNetClientProgramPtr program = NULL;
+ int counter = 0;
+ virLockSpaceProtocolReleaseResourceArgs args;
+ int rv = -1;
+
+ memset(&args, 0, sizeof(args));
+
+ if (state)
+ *state = NULL;
+
+ if (!(client = virLockManagerLockDaemonConnect(lock, &program, &counter)))
+ goto cleanup;
+
+ args.flags = flags;
+
+ if (virNetClientProgramCall(program,
+ client,
+ counter++,
+ VIR_LOCK_SPACE_PROTOCOL_PROC_RELEASE_RESOURCE,
+ 0, NULL, NULL, NULL,
+ (xdrproc_t)xdr_virLockSpaceProtocolReleaseResourceArgs,
&args,
+ (xdrproc_t)xdr_void, NULL) < 0)
+ goto cleanup;
+
+ rv = 0;
+
+cleanup:
+ virNetClientClose(client);
+ virObjectUnref(client);
+ virObjectUnref(program);
+
+ return rv;
+}
+
+
+static int virLockManagerLockDaemonInquire(virLockManagerPtr lock ATTRIBUTE_UNUSED,
+ char **state,
+ unsigned int flags)
+{
+ virCheckFlags(0, -1);
+
+ if (state)
+ *state = NULL;
+
+ return 0;
+}
+
+virLockDriver virLockDriverImpl =
+{
+ .version = VIR_LOCK_MANAGER_VERSION,
+ .flags = 0,
+
+ .drvInit = virLockManagerLockDaemonInit,
+ .drvDeinit = virLockManagerLockDaemonDeinit,
+
+ .drvNew = virLockManagerLockDaemonNew,
+ .drvFree = virLockManagerLockDaemonFree,
+
+ .drvAddResource = virLockManagerLockDaemonAddResource,
+
+ .drvAcquire = virLockManagerLockDaemonAcquire,
+ .drvRelease = virLockManagerLockDaemonRelease,
+
+ .drvInquire = virLockManagerLockDaemonInquire,
+};
--
1.7.11.2