From: "Daniel P. Berrange" <berrange@xxxxxxxxxx> 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@xxxxxxxxxx> --- 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 6b9a7af..663e37b 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -46,6 +46,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 b402297..ec5014a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -158,6 +158,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 \ @@ -1501,7 +1505,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 = \ @@ -1529,7 +1548,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 @@ -1623,9 +1643,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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list