From: "Daniel P. Berrange" <berrange(a)redhat.com>
The 'fcntl' lock driver is a implementation of the lock manager
driver API, which will be linked directly into the virtlockd
process. It will use the simple lock database added in the
previous commit to acquire/release locks for leases or disks
associated with virtual machines.
* src/locking/lock_driver_fcntl.c, src/locking/lock_driver_fcntl.h:
Add fcntl lock driver implementation
---
bootstrap.conf | 1 +
src/locking/lock_driver_fcntl.c | 929 +++++++++++++++++++++++++++++++++++++++
src/locking/lock_driver_fcntl.h | 4 +
3 files changed, 934 insertions(+), 0 deletions(-)
create mode 100644 src/locking/lock_driver_fcntl.c
create mode 100644 src/locking/lock_driver_fcntl.h
diff --git a/bootstrap.conf b/bootstrap.conf
index 581d60b..f78d167 100644
--- a/bootstrap.conf
+++ b/bootstrap.conf
@@ -34,6 +34,7 @@ connect
configmake
count-one-bits
crypto/md5
+crypto/sha256
dirname-lgpl
fcntl-h
fnmatch
diff --git a/src/locking/lock_driver_fcntl.c b/src/locking/lock_driver_fcntl.c
new file mode 100644
index 0000000..904be45
--- /dev/null
+++ b/src/locking/lock_driver_fcntl.c
@@ -0,0 +1,929 @@
+/*
+ * lock_driver_fcntl.c: A lock driver using fcntl()
+ *
+ * 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 <stdbool.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#include "lock_driver_fcntl.h"
+#include "lock_database.h"
+#include "memory.h"
+#include "logging.h"
+#include "uuid.h"
+#include "util.h"
+#include "files.h"
+#include "threads.h"
+#include "virterror_internal.h"
+#include "conf.h"
+#include "configmake.h"
+#include "sha256.h"
+#include "hash.h"
+
+#define VIR_FROM_THIS VIR_FROM_LOCKING
+
+#define virLockError(code, ...) \
+ virReportErrorHelper(VIR_FROM_THIS, code, __FILE__, \
+ __FUNCTION__, __LINE__, __VA_ARGS__)
+
+typedef struct _virLockManagerFcntlResource virLockManagerFcntlResource;
+typedef virLockManagerFcntlResource *virLockManagerFcntlResourcePtr;
+
+typedef struct _virLockManagerFcntlObject virLockManagerFcntlObject;
+typedef virLockManagerFcntlObject *virLockManagerFcntlObjectPtr;
+
+typedef struct _virLockManagerFcntlPrivate virLockManagerFcntlPrivate;
+typedef virLockManagerFcntlPrivate *virLockManagerFcntlPrivatePtr;
+
+#define VIR_LOCK_FCNTL_LOCKSPACE_FILES_NAME \
+ "org.libvirt.lockd.files"
+
+struct _virLockManagerFcntlResource {
+ char *path;
+ char *lockspace;
+ char *key;
+ bool shared;
+ bool active;
+};
+
+struct _virLockManagerFcntlObject {
+ char *hashKey;
+
+ int refs;
+ bool dead; /* True if the primary client has gone */
+
+ char *name;
+ unsigned char uuid[VIR_UUID_BUFLEN];
+ pid_t pid;
+
+ /* Resources currently held by the object */
+ size_t nresources;
+ virLockManagerFcntlResourcePtr *resources;
+};
+
+struct _virLockManagerFcntlPrivate {
+ pid_t pid;
+ virLockManagerFcntlObjectPtr object;
+
+ /* Resources added, but yet to be acquired/released */
+ size_t nresources;
+ virLockManagerFcntlResourcePtr *resources;
+};
+
+struct _virLockManagerFcntlDriver {
+ virMutex lock;
+ char *autoDiskLeasePath;
+ virLockDatabasePtr lockDB;
+ virHashTablePtr objects;
+} *driver;
+
+
+static char *virLockManagerFcntlNewHash(const char *key)
+{
+ char buf[SHA256_DIGEST_SIZE];
+ char *sum;
+ const char hex[16] = { '0', '1', '2', '3',
'4', '5', '6', '7',
+ '8', '9', 'a', 'b',
'c', 'd', 'e', 'f' };
+ size_t i;
+
+ if (!(sha256_buffer(key, strlen(key), buf)))
+ return NULL;
+
+ if (VIR_ALLOC_N(sum, (SHA256_DIGEST_SIZE * 2) + 1) < 0) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ for (i = 0 ; i < SHA256_DIGEST_SIZE ; i++) {
+ sum[i*2] = hex[(buf[i] >> 4) & 0xf];
+ sum[(i*2)+1] = hex[buf[i] & 0xf];
+ }
+ sum[(SHA256_DIGEST_SIZE*2)] = '\0';
+
+ return sum;
+}
+
+
+
+static void virLockManagerFcntlResourceFree(virLockManagerFcntlResourcePtr res)
+{
+ if (!res)
+ return;
+
+ VIR_FREE(res->path);
+ VIR_FREE(res->lockspace);
+ VIR_FREE(res->key);
+
+ VIR_FREE(res);
+}
+
+
+static void virLockManagerFcntlObjectFree(virLockManagerFcntlObjectPtr object)
+{
+ size_t i;
+
+ if (!object)
+ return;
+
+ object->refs--;
+ if (object->refs)
+ return;
+
+ VIR_FREE(object->hashKey);
+ VIR_FREE(object->name);
+ if (object->resources) {
+ for (i = 0 ; i < object->nresources ; i++)
+ virLockManagerFcntlResourceFree(object->resources[i]);
+ VIR_FREE(object->resources);
+ }
+
+ VIR_FREE(object);
+}
+
+
+static void virLockManagerFcntlPrivateFree(virLockManagerFcntlPrivatePtr priv)
+{
+ size_t i;
+
+ if (!priv)
+ return;
+
+ virLockManagerFcntlObjectFree(priv->object);
+
+ if (priv->resources) {
+ for (i = 0 ; i < priv->nresources ; i++)
+ virLockManagerFcntlResourceFree(priv->resources[i]);
+ VIR_FREE(priv->resources);
+ }
+
+ VIR_FREE(priv);
+}
+
+
+static virLockManagerFcntlObjectPtr
+virLockManagerFcntlObjectNew(const char *name,
+ unsigned char *uuid,
+ pid_t pid)
+{
+ virLockManagerFcntlObjectPtr obj;
+
+ if (VIR_ALLOC(obj) < 0)
+ goto no_memory;
+
+ if (!(obj->name = strdup(name)))
+ goto no_memory;
+ memcpy(obj->uuid, uuid, VIR_UUID_BUFLEN);
+ obj->pid = pid;
+ obj->refs = 1;
+
+ return obj;
+
+no_memory:
+ virReportOOMError();
+ virLockManagerFcntlObjectFree(obj);
+ return NULL;
+}
+
+static virLockManagerFcntlPrivatePtr
+virLockManagerFcntlPrivateNewAttach(virLockManagerFcntlObjectPtr object,
+ pid_t clientPid)
+{
+ virLockManagerFcntlPrivatePtr priv;
+
+ if (VIR_ALLOC(priv) < 0)
+ goto no_memory;
+
+ object->refs++;
+ priv->object = object;
+ priv->pid = clientPid;
+
+ return priv;
+
+no_memory:
+ virReportOOMError();
+ return NULL;
+}
+
+
+static virLockManagerFcntlPrivatePtr
+virLockManagerFcntlPrivateNew(const char *name,
+ unsigned char *uuid,
+ pid_t pid,
+ pid_t clientPid)
+{
+ virLockManagerFcntlPrivatePtr priv;
+
+ if (VIR_ALLOC(priv) < 0)
+ goto no_memory;
+
+ if (!(priv->object = virLockManagerFcntlObjectNew(name, uuid, pid)))
+ goto error;
+ priv->pid = clientPid;
+
+ return priv;
+
+no_memory:
+ virReportOOMError();
+error:
+ VIR_FREE(priv);
+ return NULL;
+}
+
+
+static virLockManagerFcntlResourcePtr
+virLockManagerFcntlResourceNew(const char *path,
+ const char *lockspace,
+ const char *key,
+ bool hashKey,
+ bool shared)
+{
+ virLockManagerFcntlResourcePtr res;
+
+ if (VIR_ALLOC(res) < 0)
+ goto no_memory;
+
+ if (!(res->path = strdup(path)))
+ goto no_memory;
+ if (!(res->lockspace = strdup(lockspace)))
+ goto no_memory;
+ if (hashKey) {
+ if (!(res->key = virLockManagerFcntlNewHash(key)))
+ goto error;
+ } else {
+ if (!(res->key = strdup(key)))
+ goto no_memory;
+ }
+
+ res->shared = shared;
+
+ return res;
+
+no_memory:
+ virReportOOMError();
+error:
+ virLockManagerFcntlResourceFree(res);
+ return NULL;
+}
+
+
+#if 0
+/*
+ * sanlock plugin for the libvirt virLockManager API
+ */
+static int virLockManagerFcntlLoadConfig(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)) { \
+ virLockError(VIR_ERR_INTERNAL_ERROR, \
+ "%s: %s: expected type " #typ, \
+ configFile, (name)); \
+ virConfFree(conf); \
+ return -1; \
+ }
+
+ p = virConfGetValue(conf, "disk_lease_dir");
+ CHECK_TYPE("disk_lease_dir", VIR_CONF_STRING);
+ if (p && p->str) {
+ VIR_FREE(driver.autoDiskLeasePath);
+ if (!(driver.autoDiskLeasePath = strdup(p->str))) {
+ virReportOOMError();
+ virConfFree(conf);
+ return -1;
+ }
+ }
+
+ virConfFree(conf);
+ return 0;
+}
+#endif
+
+static char *virLockManagerFcntlPath(bool privileged)
+{
+ char *path;
+ if (privileged) {
+ if (!(path = strdup(LOCALSTATEDIR "/lib/libvirt/lockd"))) {
+ virReportOOMError();
+ return NULL;
+ }
+ } else {
+ char *userdir;
+ if (!(userdir = virGetUserDirectory(geteuid())))
+ return NULL;
+
+ if (virAsprintf(&path, "%s/.libvirt/lockd", userdir) < 0) {
+ virReportOOMError();
+ }
+ VIR_FREE(userdir);
+ }
+ return path;
+}
+
+
+
+static int virLockManagerFcntlInit(unsigned int version ATTRIBUTE_UNUSED,
+ const char *configFile ATTRIBUTE_UNUSED,
+ unsigned int flags ATTRIBUTE_UNUSED)
+{
+ unsigned char hostuuid[VIR_UUID_BUFLEN];
+ char *hostname = virGetHostname(NULL);
+ if (!hostname)
+ return -1;
+
+ if (driver) {
+ virLockError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Driver already initialized"));
+ return -1;
+ }
+
+ if (VIR_ALLOC(driver) < 0) {
+ virReportOOMError();
+ return -1;
+ }
+
+ if (virMutexInit(&driver->lock) < 0) {
+ virLockError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Unable to initialize driver mutex"));
+ VIR_FREE(driver);
+ return -1;
+ }
+
+ if (!(driver->lockDB = virLockDatabaseNew(hostuuid, hostname)))
+ goto error;
+
+ if (!(driver->autoDiskLeasePath = virLockManagerFcntlPath(getuid() == 0))) {
+ virReportOOMError();
+ goto error;
+ }
+
+ if (!(driver->objects = virHashCreate(10, NULL)))
+ goto error;
+
+#if 0
+ if (virLockManagerFcntlLoadConfig(configFile) < 0)
+ goto error;
+#endif
+
+ /* A standard lockspace to which we map virtual disk files */
+ if (virLockDatabaseCreateLockspace(driver->lockDB,
+ driver->autoDiskLeasePath,
+ VIR_LOCK_FCNTL_LOCKSPACE_FILES_NAME,
+ true) < 0)
+ goto error;
+
+ VIR_FREE(hostname);
+ return 0;
+
+error:
+ virLockDatabaseFree(driver->lockDB);
+ driver->lockDB = NULL;
+ VIR_FREE(driver->autoDiskLeasePath);
+ VIR_FREE(hostname);
+ return -1;
+}
+
+static int virLockManagerFcntlDeinit(void)
+{
+ virLockDatabaseFree(driver->lockDB);
+ VIR_FREE(driver->autoDiskLeasePath);
+ virMutexDestroy(&driver->lock);
+ VIR_FREE(driver);
+ return 0;
+}
+
+
+static char *virLockManagerFcntlObjectName(unsigned char *uuid,
+ pid_t pid)
+{
+ char *ret;
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+
+ virUUIDFormat(uuid, uuidstr);
+
+ if (virAsprintf(&ret, "%s-%llu", uuidstr, (long long unsigned)pid) <
0)
+ return NULL;
+ return ret;
+}
+
+
+static int virLockManagerFcntlNew(virLockManagerPtr lock,
+ unsigned int type,
+ size_t nparams,
+ virLockManagerParamPtr params,
+ unsigned int flags)
+{
+ virLockManagerFcntlPrivatePtr priv = NULL;
+ char *name = NULL;
+ pid_t pid = 0;
+ pid_t clientPid = 0;
+ unsigned char *uuid = NULL;
+ size_t i;
+ char *objectName = NULL;
+ int ret = -1;
+
+ virCheckFlags(0, -1);
+
+ virMutexLock(&driver->lock);
+
+ if (type != VIR_LOCK_MANAGER_OBJECT_TYPE_DOMAIN)
+ goto cleanup;
+
+ for (i = 0 ; i < nparams ; i++) {
+ virLockManagerParamPtr param = ¶ms[i];
+ if (STREQ(param->key, "uuid")) {
+ uuid = param->value.uuid;
+ } else if (STREQ(param->key, "name")) {
+ name = param->value.str;
+ } else if (STREQ(param->key, "pid")) {
+ pid = param->value.ui;
+ } else if (STREQ(param->key, "client-pid")) {
+ clientPid = param->value.ui;
+ }
+ }
+
+ if (!name) {
+ virLockError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Missing 'name' parameter for object lock"));
+ goto cleanup;
+ }
+
+ if (!pid) {
+ virLockError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Missing 'pid' parameter for object lock"));
+ goto cleanup;
+ }
+
+ if (!clientPid) {
+ virLockError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Missing 'client-pid' parameter for object
lock"));
+ goto cleanup;
+ }
+
+ if (!uuid) {
+ virLockError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Missing 'uuid' parameter for object lock"));
+ goto cleanup;
+ }
+
+ if (!virUUIDIsValid(uuid)) {
+ virLockError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Malformed 'uuid' parameter for object lock"));
+ goto cleanup;
+ }
+
+ objectName = virLockManagerFcntlObjectName(uuid, pid);
+ if (clientPid == pid) {
+ if (!(priv = virLockManagerFcntlPrivateNew(name, uuid, pid, clientPid)))
+ goto cleanup;
+
+ if (virHashAddEntry(driver->objects, objectName, priv->object) < 0)
+ goto cleanup;
+
+ priv->object->hashKey = objectName;
+ objectName = NULL;
+ } else {
+ virLockManagerFcntlObjectPtr object = virHashLookup(driver->objects,
objectName);
+
+ if (!object) {
+ virLockError(VIR_ERR_INTERNAL_ERROR,
+ _("No active connection for object %s (%s)"),
+ objectName, name);
+ goto cleanup;
+ }
+
+ if (!(priv = virLockManagerFcntlPrivateNewAttach(object, clientPid)))
+ goto cleanup;
+ }
+
+ lock->privateData = priv;
+
+ ret = 0;
+
+cleanup:
+ if (ret != 0)
+ virLockManagerFcntlPrivateFree(priv);
+ VIR_FREE(objectName);
+ virMutexUnlock(&driver->lock);
+ return ret;
+}
+
+
+static int virLockManagerFcntlAddResource(virLockManagerPtr lock,
+ unsigned int type,
+ const char *name,
+ size_t nparams,
+ virLockManagerParamPtr params,
+ unsigned int flags)
+{
+ virLockManagerFcntlPrivatePtr priv = lock->privateData;
+ virLockManagerFcntlResourcePtr res;
+ const char *lockspace = NULL;
+ const char *path = NULL;
+ bool hashName = false;
+ size_t i;
+ int ret = 0;
+
+ virCheckFlags(VIR_LOCK_MANAGER_RESOURCE_SHARED |
+ VIR_LOCK_MANAGER_RESOURCE_READONLY, -1);
+
+ if ((flags & VIR_LOCK_MANAGER_RESOURCE_READONLY) &&
+ (flags & VIR_LOCK_MANAGER_RESOURCE_SHARED)) {
+ virLockError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Lease flags cannot request 'shared' and
'readonly' at the same time"));
+ return -1;
+ }
+
+ if (flags & VIR_LOCK_MANAGER_RESOURCE_READONLY)
+ return 0;
+
+ virMutexLock(&driver->lock);
+
+ switch (type) {
+ case VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK:
+ hashName = true;
+ path = driver->autoDiskLeasePath;
+ lockspace = VIR_LOCK_FCNTL_LOCKSPACE_FILES_NAME;
+ break;
+
+ case VIR_LOCK_MANAGER_RESOURCE_TYPE_LEASE:
+ for (i = 0 ; i < nparams ; i++) {
+ virLockManagerParamPtr param = ¶ms[i];
+ if (STREQ(param->key, "path")) {
+ path = param->value.str;
+ } else if (STREQ(param->key, "lockspace")) {
+ lockspace = param->value.str;
+ } else if (STREQ(param->key, "offset")) {
+ if (param->value.ul) {
+ virLockError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("lease offset must be zero"));
+ goto cleanup;
+ }
+ } else {
+ virLockError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Unexpected parameter %s"),
+ param->key);
+ goto cleanup;
+ }
+ }
+ break;
+
+ default:
+ virLockError(VIR_ERR_INTERNAL_ERROR,
+ _("Unsupported resource type %d"),
+ type);
+ goto cleanup;
+ }
+
+ if (!lockspace) {
+ virLockError(VIR_ERR_INTERNAL_ERROR,
+ _("Missing lockspace for resource %s"), name);
+ goto cleanup;
+ }
+
+ if (!path) {
+ virLockError(VIR_ERR_INTERNAL_ERROR,
+ _("Missing lock path for resource %s"), name);
+ goto cleanup;
+ }
+
+ if (priv->object->dead) {
+ virLockError(VIR_ERR_INTERNAL_ERROR,
+ _("The object connection for %s has died"),
+ priv->object->name);
+ goto cleanup;
+ }
+
+ if (!(res = virLockManagerFcntlResourceNew(path, lockspace, name, hashName,
+ flags &
VIR_LOCK_MANAGER_RESOURCE_SHARED)))
+ goto cleanup;
+
+ if (VIR_EXPAND_N(priv->resources, priv->nresources, 1) < 0) {
+ virLockManagerFcntlResourceFree(res);
+ goto cleanup;
+ }
+ priv->resources[priv->nresources-1] = res;
+
+ ret = 0;
+
+cleanup:
+ virMutexUnlock(&driver->lock);
+ return ret;
+}
+
+
+static int virLockManagerFcntlAcquire(virLockManagerPtr lock,
+ const char *state ATTRIBUTE_UNUSED,
+ unsigned int flags,
+ int *fd ATTRIBUTE_UNUSED)
+{
+ virLockManagerFcntlPrivatePtr priv = lock->privateData;
+ size_t i = 0;
+ int ret = -1;
+
+ virCheckFlags(VIR_LOCK_MANAGER_ACQUIRE_RESTRICT |
+ VIR_LOCK_MANAGER_ACQUIRE_REGISTER_ONLY, -1);
+
+ if (flags & VIR_LOCK_MANAGER_ACQUIRE_REGISTER_ONLY)
+ return 0;
+
+ virMutexLock(&driver->lock);
+
+ if (priv->object->dead) {
+ virLockError(VIR_ERR_INTERNAL_ERROR,
+ _("The object connection for %s has died"),
+ priv->object->name);
+ goto cleanup;
+ }
+
+ if (VIR_EXPAND_N(priv->object->resources,
+ priv->object->nresources,
+ priv->nresources) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ for (i = 0 ; i < priv->nresources ; i++) {
+ if (virLockDatabaseAcquireLease(driver->lockDB,
+ priv->resources[i]->path,
+ priv->resources[i]->lockspace,
+ priv->resources[i]->key,
+ priv->resources[i]->shared) < 0) {
+ i--;
+ goto error;
+ }
+ priv->resources[i]->active = true;
+ }
+
+ for (i = 0 ; i < priv->nresources ; i++) {
+
priv->object->resources[priv->object->nresources-priv->nresources+i]
+ = priv->resources[i];
+ }
+ VIR_FREE(priv->resources);
+ priv->nresources = 0;
+
+ ret = 0;
+
+cleanup:
+ virMutexUnlock(&driver->lock);
+ return ret;
+
+error:
+ for (i = 0 ; i < priv->nresources ; i++) {
+ if (priv->resources[i]->active &&
+ virLockDatabaseReleaseLease(driver->lockDB,
+ priv->resources[i]->path,
+ priv->resources[i]->lockspace,
+ priv->resources[i]->key,
+ priv->resources[i]->shared) < 0)
+ VIR_WARN("Cannot release resource after failed lock");
+ priv->resources[i]->active = false;
+ }
+ VIR_SHRINK_N(priv->object->resources,
+ priv->object->nresources,
+ priv->nresources);
+ goto cleanup;
+}
+
+
+static int virLockManagerFcntlRelease(virLockManagerPtr lock,
+ char **state,
+ unsigned int flags)
+{
+ virLockManagerFcntlPrivatePtr priv = lock->privateData;
+ size_t i;
+ size_t j;
+ int ret = -1;
+ bool failed = false;
+ int *indexes;
+
+ virCheckFlags(0, -1);
+
+ *state = NULL;
+
+ virMutexLock(&driver->lock);
+
+ if (priv->object->dead) {
+ virLockError(VIR_ERR_INTERNAL_ERROR,
+ _("The object connection for %s has died"),
+ priv->object->name);
+ goto cleanup;
+ }
+
+ if (VIR_ALLOC_N(indexes, priv->nresources) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ /* Make sure the resources requested for release are in fact
+ * currently held by this object
+ */
+ for (i = 0 ; i < priv->nresources ; i++) {
+ bool match = false;
+ for (j = 0 ; j < priv->object->nresources ; j++) {
+ if (STREQ(priv->resources[i]->path,
+ priv->object->resources[j]->path) &&
+ STREQ(priv->resources[i]->lockspace,
+ priv->object->resources[j]->lockspace) &&
+ STREQ(priv->resources[i]->key,
+ priv->object->resources[j]->key)) {
+ match = true;
+ indexes[i] = j;
+ break;
+ }
+ }
+
+ if (!match) {
+ virLockError(VIR_ERR_INTERNAL_ERROR,
+ _("Lease %s in lockspace %s at %s is not held by this
object"),
+ priv->resources[i]->key,
+ priv->resources[i]->lockspace,
+ priv->resources[i]->path);
+ VIR_FREE(indexes);
+ return -1;
+ }
+ }
+
+
+ /*
+ * Acquire all the new leases
+ */
+ for (i = 0 ; i < priv->nresources ; i++) {
+ if (virLockDatabaseReleaseLease(driver->lockDB,
+ priv->resources[i]->path,
+ priv->resources[i]->lockspace,
+ priv->resources[i]->key,
+ priv->resources[i]->shared) < 0) {
+ failed = true;
+ } else {
+ priv->object->resources[indexes[i]]->active = false;
+ }
+ }
+
+ /*
+ * Move the newly held resources to the object resource list
+ */
+ for (i = 0, j = 0 ; i < priv->object->nresources ; i++) {
+ if (priv->object->resources[i]->active) {
+ priv->object->resources[j] = priv->object->resources[i];
+ j++;
+ } else {
+ virLockManagerFcntlResourceFree(priv->object->resources[i]);
+ }
+ }
+ VIR_SHRINK_N(priv->object->resources,
+ priv->object->nresources,
+ j);
+
+ VIR_FREE(indexes);
+
+ ret = failed ? -1 : 0;
+
+cleanup:
+ virMutexUnlock(&driver->lock);
+ return ret;
+}
+
+
+static int virLockManagerFcntlInquire(virLockManagerPtr lock ATTRIBUTE_UNUSED,
+ char **state,
+ unsigned int flags)
+{
+ virLockManagerFcntlPrivatePtr priv = lock->privateData;
+ int ret = -1;
+
+ virCheckFlags(0, -1);
+
+ *state = NULL;
+
+ virMutexLock(&driver->lock);
+
+ if (priv->object->dead) {
+ virLockError(VIR_ERR_INTERNAL_ERROR,
+ _("The object connection for %s has died"),
+ priv->object->name);
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+ virMutexUnlock(&driver->lock);
+ return ret;
+}
+
+
+static void virLockManagerFcntlFree(virLockManagerPtr lock)
+{
+ virLockManagerFcntlPrivatePtr priv = lock->privateData;
+
+ /*
+ * If the primary object PID closed its connection,
+ * we need to make sure it is really dead and release
+ * its resources
+ */
+ if (priv->pid == priv->object->pid) {
+ size_t i;
+
+ VIR_DEBUG("Killing off PID %llu hash key %s",
+ (unsigned long long)priv->pid, priv->object->hashKey);
+
+ virHashRemoveEntry(driver->objects, priv->object->hashKey);
+
+ /*
+ * Kill off all held leases
+ */
+ for (i = 0 ; i < priv->object->nresources ; i++) {
+ if (virLockDatabaseReleaseLease(driver->lockDB,
+ priv->object->resources[i]->path,
+
priv->object->resources[i]->lockspace,
+ priv->object->resources[i]->key,
+ priv->object->resources[i]->shared)
< 0) {
+ VIR_WARN("Unable to release resource %s in %s at %s",
+ priv->object->resources[i]->key,
+ priv->object->resources[i]->lockspace,
+ priv->object->resources[i]->path);
+ }
+ }
+
+ /* This loop sends SIGTERM, then waits a few iterations
+ * (1.6 seconds) to see if it dies. If still alive then
+ * it does SIGKILL, and waits a few more iterations (1.6
+ * seconds more) to confirm that it has really gone.
+ */
+ for (i = 0 ; i < 15 ; i++) {
+ int signum;
+ if (i == 0)
+ signum = SIGTERM;
+ else if (i == 8)
+ signum = SIGKILL;
+ else
+ signum = 0; /* Just check for existence */
+
+ if (virKillProcess(priv->object->pid, signum) < 0) {
+ if (errno != ESRCH) {
+ char ebuf[1024];
+ VIR_WARN("Failed to kill process %d %s",
+ priv->object->pid, virStrerror(errno, ebuf, sizeof
ebuf));
+ }
+ break;
+ }
+
+ usleep(200 * 1000);
+ }
+
+ priv->object->dead = true;
+ }
+
+ virLockManagerFcntlPrivateFree(priv);
+}
+
+virLockDriver virLockDriverFcntl =
+{
+ .version = VIR_LOCK_MANAGER_VERSION,
+
+ .drvInit = virLockManagerFcntlInit,
+ .drvDeinit = virLockManagerFcntlDeinit,
+
+ .drvNew = virLockManagerFcntlNew,
+ .drvFree = virLockManagerFcntlFree,
+
+ .drvAddResource = virLockManagerFcntlAddResource,
+
+ .drvAcquire = virLockManagerFcntlAcquire,
+ .drvRelease = virLockManagerFcntlRelease,
+
+ .drvInquire = virLockManagerFcntlInquire,
+};
diff --git a/src/locking/lock_driver_fcntl.h b/src/locking/lock_driver_fcntl.h
new file mode 100644
index 0000000..c539fe1
--- /dev/null
+++ b/src/locking/lock_driver_fcntl.h
@@ -0,0 +1,4 @@
+
+#include "lock_driver.h"
+
+extern virLockDriver virLockDriverFcntl;
--
1.7.6