On 12.09.2012 18:29, Daniel P. Berrange wrote: > 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 > ACK with one nit > 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) indentation > 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, > +}; > -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list