From: "Daniel P. Berrange" <berrange(a)redhat.com>
The default lockd driver behavour is to acquire leases
directly on the disk files. This introduces an alternative
mode, where leases are acquire indirectly on a file that
is based on a SHA256 hash of the disk filename.
Signed-off-by: Daniel P. Berrange <berrange(a)redhat.com>
---
bootstrap.conf | 1 +
src/Makefile.am | 4 +-
src/locking/libvirt_lockd.aug | 1 +
src/locking/lock_driver_lockd.c | 128 +++++++++++++++++++++++++++++++---
src/locking/lockd.conf | 22 ++++++
src/locking/test_libvirt_lockd.aug.in | 1 +
6 files changed, 148 insertions(+), 9 deletions(-)
diff --git a/bootstrap.conf b/bootstrap.conf
index 59dd258..37a0ae1 100644
--- a/bootstrap.conf
+++ b/bootstrap.conf
@@ -36,6 +36,7 @@ connect
configmake
count-one-bits
crypto/md5
+crypto/sha256
dirname-lgpl
environ
execinfo
diff --git a/src/Makefile.am b/src/Makefile.am
index 5808653..0a1b98f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1564,7 +1564,7 @@ lockd_la_SOURCES = \
$(LOCK_DRIVER_LOCKD_SOURCES) \
$(LOCK_PROTOCOL_GENERATED) \
$(NULL)
-lockd_la_CFLAGS = $(AM_CFLAGS)
+lockd_la_CFLAGS = -I$(top_srcdir)/src/conf $(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
@@ -1940,6 +1940,7 @@ EXTRA_DIST += $(SECURITY_DRIVER_APPARMOR_HELPER_SOURCES)
install-data-local: install-init install-systemd
if WITH_LIBVIRTD
$(MKDIR_P) "$(DESTDIR)$(localstatedir)/lib/libvirt/lockd"
+ $(MKDIR_P) "$(DESTDIR)$(localstatedir)/lib/libvirt/lockd/files"
$(MKDIR_P) "$(DESTDIR)$(localstatedir)/run/libvirt/lockd"
endif
$(MKDIR_P) "$(DESTDIR)$(localstatedir)/cache/libvirt"
@@ -1992,6 +1993,7 @@ endif
uninstall-local:: uninstall-init uninstall-systemd
if WITH_LIBVIRTD
+ rmdir "$(DESTDIR)$(localstatedir)/lib/libvirt/lockd/files" ||:
rmdir "$(DESTDIR)$(localstatedir)/lib/libvirt/lockd" ||:
rmdir "$(DESTDIR)$(localstatedir)/run/libvirt/lockd" ||:
endif
diff --git a/src/locking/libvirt_lockd.aug b/src/locking/libvirt_lockd.aug
index 4649644..dafd8f9 100644
--- a/src/locking/libvirt_lockd.aug
+++ b/src/locking/libvirt_lockd.aug
@@ -19,6 +19,7 @@ module Libvirt_lockd =
(* Each enty in the config is one of the following three ... *)
let entry = bool_entry "auto_disk_leases"
| bool_entry "require_lease_for_disks"
+ | str_entry "file_lockspace_dir"
let comment = [ label "#comment" . del /#[ \t]*/ "# " . store
/([^ \t\n][^\n]*)?/ . del /\n/ "\n" ]
let empty = [ label "#empty" . eol ]
diff --git a/src/locking/lock_driver_lockd.c b/src/locking/lock_driver_lockd.c
index 089b284..aa0f94a 100644
--- a/src/locking/lock_driver_lockd.c
+++ b/src/locking/lock_driver_lockd.c
@@ -32,6 +32,7 @@
#include "rpc/virnetclient.h"
#include "lock_protocol.h"
#include "configmake.h"
+#include "sha256.h"
#define VIR_FROM_THIS VIR_FROM_LOCKING
@@ -70,6 +71,8 @@ struct _virLockManagerLockDaemonPrivate {
struct _virLockManagerLockDaemonDriver {
bool autoDiskLease;
bool requireLeaseForDisks;
+
+ char *fileLockSpaceDir;
};
static virLockManagerLockDaemonDriverPtr driver = NULL;
@@ -120,6 +123,17 @@ static int virLockManagerLockDaemonLoadConfig(const char
*configFile)
CHECK_TYPE("auto_disk_leases", VIR_CONF_LONG);
if (p) driver->autoDiskLease = p->l;
+ p = virConfGetValue(conf, "file_lockspace_dir");
+ CHECK_TYPE("file_lockspace_dir", VIR_CONF_STRING);
+ if (p && p->str) {
+ VIR_FREE(driver->fileLockSpaceDir);
+ if (!(driver->fileLockSpaceDir = strdup(p->str))) {
+ virReportOOMError();
+ virConfFree(conf);
+ return -1;
+ }
+ }
+
p = virConfGetValue(conf, "require_lease_for_disks");
CHECK_TYPE("require_lease_for_disks", VIR_CONF_LONG);
if (p)
@@ -288,6 +302,47 @@ error:
}
+static int virLockManagerLockDaemonSetupLockspace(const char *path)
+{
+ virNetClientPtr client;
+ virNetClientProgramPtr program = NULL;
+ virLockSpaceProtocolCreateLockSpaceArgs args;
+ int rv = -1;
+ int counter = 0;
+
+ memset(&args, 0, sizeof(args));
+ args.path = (char*)path;
+
+ if (!(client = virLockManagerLockDaemonConnectionNew(getuid() == 0, &program)))
+ return -1;
+
+ if (virNetClientProgramCall(program,
+ client,
+ counter++,
+ VIR_LOCK_SPACE_PROTOCOL_PROC_CREATE_LOCKSPACE,
+ 0, NULL, NULL, NULL,
+ (xdrproc_t)xdr_virLockSpaceProtocolCreateLockSpaceArgs,
(char*)&args,
+ (xdrproc_t)xdr_void, NULL) < 0) {
+ virErrorPtr err = virGetLastError();
+ if (err && err->code == VIR_ERR_OPERATION_INVALID) {
+ /* The lockspace already exists */
+ virResetLastError();
+ rv = 0;
+ } else {
+ goto cleanup;
+ }
+ }
+
+ rv = 0;
+
+cleanup:
+ virObjectUnref(program);
+ virNetClientClose(client);
+ virObjectUnref(client);
+ return rv;
+}
+
+
static int virLockManagerLockDaemonDeinit(void);
static int virLockManagerLockDaemonInit(unsigned int version,
@@ -312,6 +367,13 @@ static int virLockManagerLockDaemonInit(unsigned int version,
if (virLockManagerLockDaemonLoadConfig(configFile) < 0)
goto error;
+ if (driver->autoDiskLease) {
+ if (driver->fileLockSpaceDir &&
+ virLockManagerLockDaemonSetupLockspace(driver->fileLockSpaceDir) < 0)
+ goto error;
+ }
+
+
return 0;
error:
@@ -324,6 +386,7 @@ static int virLockManagerLockDaemonDeinit(void)
if (!driver)
return 0;
+ VIR_FREE(driver->fileLockSpaceDir);
VIR_FREE(driver);
return 0;
@@ -421,6 +484,36 @@ static int virLockManagerLockDaemonNew(virLockManagerPtr lock,
}
+static const char hex[] = { '0', '1', '2', '3',
'4', '5', '6', '7',
+ '8', '9', 'a', 'b',
'c', 'd', 'e', 'f' };
+
+static char *virLockManagerLockDaemonDiskLeaseName(const char *path)
+{
+ unsigned char buf[SHA256_DIGEST_SIZE];
+ char *ret;
+ int i;
+
+ if (!(sha256_buffer(path, strlen(path), buf))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Unable to compute sha256 checksum"));
+ return NULL;
+ }
+
+ if (VIR_ALLOC_N(ret, (SHA256_DIGEST_SIZE * 2) + 1) < 0) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ for (i = 0 ; i < SHA256_DIGEST_SIZE ; i++) {
+ ret[i*2] = hex[(buf[i] >> 4) & 0xf];
+ ret[(i*2)+1] = hex[buf[i] & 0xf];
+ }
+ ret[(SHA256_DIGEST_SIZE * 2) + 1] = '\0';
+
+ return ret;
+}
+
+
static int virLockManagerLockDaemonAddResource(virLockManagerPtr lock,
unsigned int type,
const char *name,
@@ -429,8 +522,9 @@ static int virLockManagerLockDaemonAddResource(virLockManagerPtr
lock,
unsigned int flags)
{
virLockManagerLockDaemonPrivatePtr priv = lock->privateData;
- char *newName;
+ char *newName = NULL;
char *newLockspace = NULL;
+ bool autoCreate = false;
virCheckFlags(VIR_LOCK_MANAGER_RESOURCE_READONLY |
VIR_LOCK_MANAGER_RESOURCE_SHARED, -1);
@@ -451,10 +545,22 @@ static int virLockManagerLockDaemonAddResource(virLockManagerPtr
lock,
priv->hasRWDisks = true;
return 0;
}
- if (!(newLockspace = strdup(""))) {
- virReportOOMError();
- return -1;
+
+ if (driver->fileLockSpaceDir) {
+ if (!(newLockspace = strdup(driver->fileLockSpaceDir)))
+ goto no_memory;
+ if (!(newName = virLockManagerLockDaemonDiskLeaseName(name)))
+ goto no_memory;
+ autoCreate = true;
+ VIR_DEBUG("Using indirect lease %s for %s", newName, name);
+ } else {
+ if (!(newLockspace = strdup("")))
+ goto no_memory;
+ if (!(newName = strdup(name)))
+ goto no_memory;
+ VIR_DEBUG("Using direct lease for %s", name);
}
+
break;
case VIR_LOCK_MANAGER_RESOURCE_TYPE_LEASE: {
size_t i;
@@ -488,6 +594,9 @@ static int virLockManagerLockDaemonAddResource(virLockManagerPtr
lock,
virReportOOMError();
return -1;
}
+ if (!(newName = strdup(name)))
+ goto no_memory;
+
} break;
default:
virReportError(VIR_ERR_INTERNAL_ERROR,
@@ -496,9 +605,6 @@ static int virLockManagerLockDaemonAddResource(virLockManagerPtr
lock,
return -1;
}
- if (!(newName = strdup(name)))
- goto no_memory;
-
if (VIR_EXPAND_N(priv->resources, priv->nresources, 1) < 0)
goto no_memory;
@@ -509,10 +615,15 @@ static int virLockManagerLockDaemonAddResource(virLockManagerPtr
lock,
priv->resources[priv->nresources-1].flags |=
VIR_LOCK_SPACE_PROTOCOL_ACQUIRE_RESOURCE_SHARED;
+ if (autoCreate)
+ priv->resources[priv->nresources-1].flags |=
+ VIR_LOCK_SPACE_PROTOCOL_ACQUIRE_RESOURCE_AUTOCREATE;
+
return 0;
no_memory:
virReportOOMError();
+ VIR_FREE(newLockspace);
VIR_FREE(newName);
return -1;
}
@@ -521,6 +632,7 @@ no_memory:
static int virLockManagerLockDaemonAcquire(virLockManagerPtr lock,
const char *state ATTRIBUTE_UNUSED,
unsigned int flags,
+ virDomainLockFailureAction action
ATTRIBUTE_UNUSED,
int *fd)
{
virNetClientPtr client = NULL;
@@ -555,7 +667,7 @@ static int virLockManagerLockDaemonAcquire(virLockManagerPtr lock,
memset(&args, 0, sizeof(args));
if (priv->resources[i].lockspace)
- args.path = priv->resources[i].lockspace;
+ args.path = priv->resources[i].lockspace;
args.name = priv->resources[i].name;
args.flags = priv->resources[i].flags;
diff --git a/src/locking/lockd.conf b/src/locking/lockd.conf
index 0b885c5..7545fd9 100644
--- a/src/locking/lockd.conf
+++ b/src/locking/lockd.conf
@@ -16,3 +16,25 @@
# to enabled, otherwise it defaults to disabled.
#
#require_lease_for_disks = 1
+
+
+#
+# The default lockd behaviour is to use the "direct"
+# lockspace, where the locks are acquired against the
+# actual file paths associated with the <disk> devices.
+#
+# Setting a directory here causes lockd to use "indirect"
+# lockspace, where a hash of the <disk> file path is
+# used to create a file in the lockspace directory. The
+# locks are then held on these hash files instead.
+#
+# This can be useful if the file paths refer to block
+# devices which are shared, since /dev fcntl() locks
+# don't propagate across hosts. It is also useful if
+# the filesystem does not support fcntl() locks.
+#
+# Typically this directory would be located on a shared
+# filesystem visible to all hosts accessing the same
+# storage.
+#
+#file_lockspace_dir = "/var/lib/libvirt/lockd/files"
diff --git a/src/locking/test_libvirt_lockd.aug.in
b/src/locking/test_libvirt_lockd.aug.in
index 5be0d99..2e65af6 100644
--- a/src/locking/test_libvirt_lockd.aug.in
+++ b/src/locking/test_libvirt_lockd.aug.in
@@ -4,3 +4,4 @@ module Test_libvirt_lockd =
test Libvirt_lockd.lns get conf =
{ "auto_disk_leases" = "0" }
{ "require_lease_for_disks" = "1" }
+{ "file_lockspace_dir" = "/var/lib/libvirt/lockd/files" }
--
1.7.11.7