From: "Daniel P. Berrange" <berrange@xxxxxxxxxx> 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list