[libvirt] [PATCH 12/14] Add a 'lockd' lock driver implementation

Daniel P. Berrange berrange at redhat.com
Thu Jul 7 14:17:30 UTC 2011


From: "Daniel P. Berrange" <berrange at 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




More information about the libvir-list mailing list