[libvirt] [PATCH 10/14] Add a virtlockd client as a lock driver impl

Daniel P. Berrange berrange at redhat.com
Tue Dec 11 20:41:44 UTC 2012


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

Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
---
 .gitignore                            |   1 +
 po/POTFILES.in                        |   1 +
 run.in                                |   2 +
 src/Makefile.am                       |  54 ++-
 src/locking/libvirt_lockd.aug         |  32 ++
 src/locking/lock_driver_lockd.c       | 658 ++++++++++++++++++++++++++++++++++
 src/locking/lockd.conf                |  18 +
 src/locking/test_libvirt_lockd.aug.in |   6 +
 8 files changed, 766 insertions(+), 6 deletions(-)
 create mode 100644 src/locking/libvirt_lockd.aug
 create mode 100644 src/locking/lock_driver_lockd.c
 create mode 100644 src/locking/lockd.conf
 create mode 100644 src/locking/test_libvirt_lockd.aug.in

diff --git a/.gitignore b/.gitignore
index 6de2308..8023b76 100644
--- a/.gitignore
+++ b/.gitignore
@@ -110,6 +110,7 @@
 /src/libvirt_lxc
 /src/locking/lock_daemon_dispatch_stubs.h
 /src/locking/lock_protocol.[ch]
+/src/locking/qemu-lockd.conf
 /src/locking/qemu-sanlock.conf
 /src/locking/test_libvirt_sanlock.aug
 /src/lxc/lxc_controller_dispatch.h
diff --git a/po/POTFILES.in b/po/POTFILES.in
index c6c72a8..53bf7f0 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -51,6 +51,7 @@ src/libvirt-qemu.c
 src/locking/lock_daemon.c
 src/locking/lock_daemon_config.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/locking/sanlock_helper.c
diff --git a/run.in b/run.in
index f7d30ca..845eef5 100644
--- a/run.in
+++ b/run.in
@@ -53,6 +53,8 @@ fi
 export LD_LIBRARY_PATH
 
 export LIBVIRT_DRIVER_DIR="$b/src/.libs"
+export LIBVIRT_LOCK_MANAGER_PLUGIN_DIR="$b/src/.libs"
+export VIRTLOCKD_PATH="$b/src/virtlockd"
 export LIBVIRTD_PATH="$b/daemon/libvirtd"
 
 # For Python.
diff --git a/src/Makefile.am b/src/Makefile.am
index 8dbb6a5..5808653 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -164,6 +164,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 \
@@ -1298,9 +1302,14 @@ EXTRA_DIST +=							\
 
 check-local: check-augeas
 
-.PHONY: check-augeas check-augeas-qemu check-augeas-lxc check-augeas-sanlock
+.PHONY: check-augeas \
+	check-augeas-qemu \
+	check-augeas-lxc \
+	check-augeas-sanlock \
+	check-augeas-lockd \
+	$(NULL)
 
-check-augeas: check-augeas-qemu check-augeas-lxc check-augeas-sanlock
+check-augeas: check-augeas-qemu check-augeas-lxc check-augeas-sanlock check-augeas-lockd
 
 AUG_GENTEST = $(PERL) $(top_srcdir)/build-aux/augeas-gentest.pl
 EXTRA_DIST += $(top_srcdir)/build-aux/augeas-gentest.pl
@@ -1344,6 +1353,15 @@ else
 check-augeas-sanlock:
 endif
 
+test_libvirt_lockd.aug: locking/test_libvirt_lockd.aug.in \
+		locking/qemu-lockd.conf $(AUG_GENTEST)
+	$(AM_V_GEN)$(AUG_GENTEST) locking/qemu-lockd.conf $< $@
+
+check-augeas-lockd: test_libvirt_lockd.aug
+	$(AM_V_GEN)if test -x '$(AUGPARSE)'; then \
+	    '$(AUGPARSE)' -I $(srcdir)/locking test_libvirt_lockd.aug; \
+	fi
+
 #
 # Build our version script.  This is composed of three parts:
 #
@@ -1537,7 +1555,32 @@ 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
+if WITH_QEMU
+nodist_conf_DATA = locking/qemu-lockd.conf
+BUILT_SOURCES += locking/qemu-lockd.conf
+DISTCLEANFILES += locking/qemu-lockd.conf
+endif
+
+locking/%-lockd.conf: $(srcdir)/locking/lockd.conf
+	$(AM_V_GEN)$(MKDIR_P) locking ; \
+	cp $< $@
+
+
 sbin_PROGRAMS = virtlockd
 
 virtlockd_SOURCES = \
@@ -1565,7 +1608,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
@@ -1659,9 +1703,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 = -I$(top_srcdir)/src/conf $(AM_CFLAGS)
 sanlock_la_LDFLAGS = -module -avoid-version
diff --git a/src/locking/libvirt_lockd.aug b/src/locking/libvirt_lockd.aug
new file mode 100644
index 0000000..4649644
--- /dev/null
+++ b/src/locking/libvirt_lockd.aug
@@ -0,0 +1,32 @@
+(* /etc/libvirt/qemu-lockd.conf *)
+
+module Libvirt_lockd =
+   autoload xfm
+
+   let eol   = del /[ \t]*\n/ "\n"
+   let value_sep   = del /[ \t]*=[ \t]*/  " = "
+   let indent = del /[ \t]*/ ""
+
+   let str_val = del /\"/ "\"" . store /[^\"]*/ . del /\"/ "\""
+   let bool_val = store /0|1/
+   let int_val = store /[0-9]+/
+
+   let str_entry       (kw:string) = [ key kw . value_sep . str_val ]
+   let bool_entry      (kw:string) = [ key kw . value_sep . bool_val ]
+   let int_entry       (kw:string) = [ key kw . value_sep . int_val ]
+
+
+   (* Each enty in the config is one of the following three ... *)
+   let entry = bool_entry "auto_disk_leases"
+             | bool_entry "require_lease_for_disks"
+   let comment = [ label "#comment" . del /#[ \t]*/ "# " .  store /([^ \t\n][^\n]*)?/ . del /\n/ "\n" ]
+   let empty = [ label "#empty" . eol ]
+
+   let record = indent . entry . eol
+
+   let lns = ( record | comment | empty ) *
+
+   let filter = incl "/etc/libvirt/qemu-lockd.conf"
+              . Util.stdexcl
+
+   let xfm = transform lns filter
diff --git a/src/locking/lock_driver_lockd.c b/src/locking/lock_driver_lockd.c
new file mode 100644
index 0000000..089b284
--- /dev/null
+++ b/src/locking/lock_driver_lockd.c
@@ -0,0 +1,658 @@
+/*
+ * 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 "conf.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;
+
+typedef struct _virLockManagerLockDaemonDriver virLockManagerLockDaemonDriver;
+typedef virLockManagerLockDaemonDriver *virLockManagerLockDaemonDriverPtr;
+
+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;
+
+    bool hasRWDisks;
+};
+
+
+struct _virLockManagerLockDaemonDriver {
+    bool autoDiskLease;
+    bool requireLeaseForDisks;
+};
+
+static virLockManagerLockDaemonDriverPtr driver = NULL;
+
+#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 virLockManagerLockDaemonLoadConfig(const char *configFile)
+{
+    virConfPtr conf;
+    virConfValuePtr p;
+
+    if (access(configFile, R_OK) == -1) {
+        if (errno != ENOENT) {
+            virReportSystemError(errno,
+                                 _("Unable to access config file %s"),
+                                 configFile);
+            return -1;
+        }
+        return 0;
+    }
+
+    if (!(conf = virConfReadFile(configFile, 0)))
+        return -1;
+
+#define CHECK_TYPE(name,typ) if (p && p->type != (typ)) {               \
+        virReportError(VIR_ERR_INTERNAL_ERROR,                          \
+                       "%s: %s: expected type " #typ,                   \
+                       configFile, (name));                             \
+        virConfFree(conf);                                              \
+        return -1;                                                      \
+    }
+
+    p = virConfGetValue(conf, "auto_disk_leases");
+    CHECK_TYPE("auto_disk_leases", VIR_CONF_LONG);
+    if (p) driver->autoDiskLease = p->l;
+
+    p = virConfGetValue(conf, "require_lease_for_disks");
+    CHECK_TYPE("require_lease_for_disks", VIR_CONF_LONG);
+    if (p)
+        driver->requireLeaseForDisks = p->l;
+    else
+        driver->requireLeaseForDisks = !driver->autoDiskLease;
+
+    virConfFree(conf);
+    return 0;
+}
+
+
+static char *virLockManagerLockDaemonPath(bool privileged)
+{
+    char *path;
+    if (privileged) {
+        if (!(path = strdup(LOCALSTATEDIR "/run/libvirt/virtlockd-sock"))) {
+            virReportOOMError();
+            return NULL;
+        }
+    } else {
+        char *rundir = NULL;
+
+        if (!(rundir = virGetUserRuntimeDirectory()))
+            return NULL;
+
+        if (virAsprintf(&path, "%s/virtlockd-sock", rundir) < 0) {
+            VIR_FREE(rundir);
+            virReportOOMError();
+            return NULL;
+        }
+
+    }
+    return path;
+}
+
+
+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 virLockManagerLockDaemonDeinit(void);
+
+static int virLockManagerLockDaemonInit(unsigned int version,
+                                        const char *configFile,
+                                        unsigned int flags)
+{
+    VIR_DEBUG("version=%u configFile=%s flags=%x", version, NULLSTR(configFile), flags);
+
+    virCheckFlags(0, -1);
+
+    if (driver)
+        return 0;
+
+    if (VIR_ALLOC(driver) < 0) {
+        virReportOOMError();
+        return -1;
+    }
+
+    driver->requireLeaseForDisks = true;
+    driver->autoDiskLease = true;
+
+    if (virLockManagerLockDaemonLoadConfig(configFile) < 0)
+        goto error;
+
+    return 0;
+
+error:
+    virLockManagerLockDaemonDeinit();
+    return -1;
+}
+
+static int virLockManagerLockDaemonDeinit(void)
+{
+    if (!driver)
+        return 0;
+
+    VIR_FREE(driver);
+
+    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 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 (!driver->autoDiskLease) {
+            if (!(flags & (VIR_LOCK_MANAGER_RESOURCE_SHARED |
+                           VIR_LOCK_MANAGER_RESOURCE_READONLY)))
+                priv->hasRWDisks = true;
+            return 0;
+        }
+        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 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 (priv->nresources == 0 &&
+        priv->hasRWDisks &&
+        driver->requireLeaseForDisks) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Read/write, exclusive access, disks were present, but no leases specified"));
+        return -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,
+};
diff --git a/src/locking/lockd.conf b/src/locking/lockd.conf
new file mode 100644
index 0000000..0b885c5
--- /dev/null
+++ b/src/locking/lockd.conf
@@ -0,0 +1,18 @@
+
+#
+# The default lockd behaviour is to acquire locks directly
+# against each configured disk file / block device. If the
+# application wishes to instead manually manage leases in
+# the guest XML, then this parameter can be disabled
+#
+#auto_disk_leases = 0
+
+#
+# Flag to determine whether we allow starting of guests
+# which do not have any <lease> elements defined in their
+# configuration.
+#
+# If 'auto_disk_leases' is disabled, this setting defaults
+# to enabled, otherwise it defaults to disabled.
+#
+#require_lease_for_disks = 1
diff --git a/src/locking/test_libvirt_lockd.aug.in b/src/locking/test_libvirt_lockd.aug.in
new file mode 100644
index 0000000..5be0d99
--- /dev/null
+++ b/src/locking/test_libvirt_lockd.aug.in
@@ -0,0 +1,6 @@
+module Test_libvirt_lockd =
+  ::CONFIG::
+
+   test Libvirt_lockd.lns get conf =
+{ "auto_disk_leases" = "0" }
+{ "require_lease_for_disks" = "1" }
-- 
1.7.11.7




More information about the libvir-list mailing list