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 --- 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list