To facilitate use of the locking plugins from hypervisor drivers,
introduce a higher level API for locking virDomainObjPtr instances.
In includes APIs targetted to VM startup, and hotplug/unplug
* src/Makefile.am: Add domain lock API
* src/locking/domain_lock.c, src/locking/domain_lock.h: High
level API for domain locking
---
src/Makefile.am | 3 +-
src/libvirt_private.syms | 13 ++
src/locking/README | 7 +
src/locking/domain_lock.c | 442 +++++++++++++++++++++++++++++++++++++++++++++
src/locking/domain_lock.h | 70 +++++++
5 files changed, 534 insertions(+), 1 deletions(-)
create mode 100644 src/locking/domain_lock.c
create mode 100644 src/locking/domain_lock.h
diff --git a/src/Makefile.am b/src/Makefile.am
index 9bd20e5..b68a9b4 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -94,7 +94,8 @@ DRIVER_SOURCES = \
libvirt.c libvirt_internal.h \
locking/lock_manager.c locking/lock_manager.h \
locking/lock_driver.h \
- locking/lock_driver_nop.h locking/lock_driver_nop.c
+ locking/lock_driver_nop.h locking/lock_driver_nop.c \
+ locking/domain_lock.h locking/domain_lock.c
# XML configuration format handling sources
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index b45f501..8005f20 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -357,6 +357,19 @@ virDomainEventWatchdogNewFromDom;
virDomainEventWatchdogNewFromObj;
+# domain_lock.h
+virDomainLockFree;
+virDomainLockForExec;
+virDomainLockForStartup;
+virDomainLockForShutdown;
+virDomainLockForModify;
+virDomainLockBeginDiskAttach;
+virDomainLockBeginDiskDetach;
+virDomainLockEndDiskAttach;
+virDomainLockEndDiskDetach;
+virDomainLockReleaseAndFree;
+
+
# domain_nwfilter.h
virDomainConfNWFilterInstantiate;
virDomainConfNWFilterRegister;
diff --git a/src/locking/README b/src/locking/README
index 4fa4f89..da2a8f8 100644
--- a/src/locking/README
+++ b/src/locking/README
@@ -1,3 +1,10 @@
+ Using the Lock Manager APIs
+ ===========================
+
+This file describes how to use the lock manager APIs.
+All the guest lifecycle sequences here have higher
+level wrappers provided by the 'domain_lock.h' API,
+which simplify thue usage
At libvirtd startup:
diff --git a/src/locking/domain_lock.c b/src/locking/domain_lock.c
new file mode 100644
index 0000000..60b7926
--- /dev/null
+++ b/src/locking/domain_lock.c
@@ -0,0 +1,442 @@
+/*
+ * domain_lock.c: Locking for domain lifecycle operations
+ *
+ * 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 <intprops.h>
+
+#include "domain_lock.h"
+#include "memory.h"
+#include "uuid.h"
+#include "virterror_internal.h"
+#include "logging.h"
+
+#define VIR_FROM_THIS VIR_FROM_LOCKING
+
+struct _virDomainLock {
+ virLockManagerPtr contentLock;
+ virLockManagerPtr metadataLock;
+
+ pid_t pid;
+
+ bool releaseContentLock;
+ bool releaseMetadataLock;
+};
+
+static virLockManagerPtr virDomainLockNewManager(virLockManagerPluginPtr plugin,
+ virDomainObjPtr vm,
+ const char *state,
+ int mode,
+ bool acquireLock)
+{
+ virLockManagerPtr lock;
+ int i;
+ virLockManagerParam params[] = {
+ { .type = VIR_LOCK_MANAGER_PARAM_TYPE_UUID,
+ .key = "uuid",
+ },
+ { .type = VIR_LOCK_MANAGER_PARAM_TYPE_STRING,
+ .key = "name",
+ .value = { .str = vm->def->name },
+ },
+ { .type = VIR_LOCK_MANAGER_PARAM_TYPE_UINT,
+ .key = "id",
+ .value = { .i = vm->def->id },
+ },
+ { .type = VIR_LOCK_MANAGER_PARAM_TYPE_UINT,
+ .key = "pid",
+ .value = { .i = vm->pid },
+ },
+ };
+ VIR_DEBUG("plugin=%p vm=%p state=%s mode=%d acquire=%d",
+ plugin, vm, state, mode, acquireLock);
+
+ memcpy(params[0].value.uuid, vm->def->uuid, VIR_UUID_BUFLEN);
+
+ if (!(lock = virLockManagerNew(plugin,
+ VIR_LOCK_MANAGER_OBJECT_TYPE_DOMAIN,
+ ARRAY_CARDINALITY(params),
+ params,
+ mode)))
+ return NULL;
+
+ if (acquireLock) {
+ VIR_DEBUG0("Acquiring leases");
+ for (i = 0 ; i < vm->def->nleases ; i++) {
+ virDomainLeaseDefPtr lease = vm->def->leases[i];
+ unsigned int leaseFlags = 0;
+ virLockManagerParam lparams[] = {
+ { .type = VIR_LOCK_MANAGER_PARAM_TYPE_STRING,
+ .key = "path",
+ .value = { .str = lease->path },
+ },
+ { .type = VIR_LOCK_MANAGER_PARAM_TYPE_ULONG,
+ .key = "offset",
+ .value = { .ul = lease->offset },
+ },
+ { .type = VIR_LOCK_MANAGER_PARAM_TYPE_ULONG,
+ .key = "length",
+ .value = { .ul = lease->length },
+ },
+ };
+
+ VIR_DEBUG("Acquire lease %s", lease->path);
+ if (virLockManagerAddResource(lock,
+ VIR_LOCK_MANAGER_RESOURCE_TYPE_LEASE,
+ lease->key,
+ ARRAY_CARDINALITY(lparams),
+ lparams,
+ leaseFlags) < 0) {
+ VIR_DEBUG("Failed lease %s", lease->path);
+ virLockManagerFree(lock);
+ return NULL;
+ }
+ }
+
+ VIR_DEBUG0("Acquiring disks");
+ for (i = 0 ; i < vm->def->ndisks ; i++) {
+ virDomainDiskDefPtr disk = vm->def->disks[i];
+ unsigned int diskFlags = 0;
+ if (!disk->src)
+ continue;
+
+ if (!(disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK ||
+ disk->type == VIR_DOMAIN_DISK_TYPE_FILE ||
+ disk->type == VIR_DOMAIN_DISK_TYPE_DIR))
+ continue;
+
+ if (disk->readonly)
+ diskFlags |= VIR_LOCK_MANAGER_RESOURCE_READONLY;
+ if (disk->shared)
+ diskFlags |= VIR_LOCK_MANAGER_RESOURCE_SHARED;
+
+ VIR_DEBUG("Acquire disk %s", disk->src);
+ if (virLockManagerAddResource(lock,
+ VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK,
+ disk->src,
+ 0,
+ NULL,
+ diskFlags) < 0) {
+ VIR_DEBUG("Failed disk %s", disk->src);
+ virLockManagerFree(lock);
+ return NULL;
+ }
+ }
+
+ if (virLockManagerAcquireObject(lock, state, 0) < 0)
+ goto error;
+ } else {
+ if (virLockManagerAttachObject(lock, 0) < 0)
+ goto error;
+ }
+
+ return lock;
+
+error:
+ virLockManagerFree(lock);
+ return NULL;
+}
+
+
+static virDomainLockPtr virDomainLockNew(virLockManagerPluginPtr contentLockPlugin,
+ virLockManagerPluginPtr metadataLockPlugin,
+ virDomainObjPtr dom,
+ const char *contentState,
+ const char *metadataState,
+ bool acquireContentLock,
+ bool acquireMetadataLock)
+{
+ virDomainLockPtr lock;
+
+ if (VIR_ALLOC(lock) < 0) {
+ virReportOOMError();
+ goto error;
+ }
+
+ if (contentLockPlugin &&
+ !(lock->contentLock = virDomainLockNewManager(contentLockPlugin,
+ dom,
+ contentState,
+ VIR_LOCK_MANAGER_MODE_CONTENT,
+ acquireContentLock)))
+ goto error;
+
+ lock->releaseContentLock = acquireContentLock;
+
+ if (metadataLockPlugin &&
+ !(lock->metadataLock = virDomainLockNewManager(metadataLockPlugin,
+ dom,
+ metadataState,
+ VIR_LOCK_MANAGER_MODE_METADATA,
+ acquireMetadataLock)))
+ goto error;
+
+ lock->releaseMetadataLock = acquireMetadataLock;
+
+ lock->pid = dom->pid;
+
+ return lock;
+
+error:
+ virDomainLockFree(lock);
+ return NULL;
+}
+
+
+virDomainLockPtr virDomainLockForExec(virLockManagerPluginPtr contentLockPlugin,
+ const char *contentState,
+ virDomainObjPtr dom)
+{
+ VIR_DEBUG("contentLockPlugin=%p contentState=%s dom=%p",
+ contentLockPlugin, contentState, dom);
+
+ return virDomainLockNew(contentLockPlugin,
+ NULL,
+ dom,
+ contentState,
+ NULL,
+ true,
+ false);
+}
+
+virDomainLockPtr virDomainLockForStartup(virLockManagerPluginPtr contentLockPlugin,
+ virLockManagerPluginPtr metadataLockPlugin,
+ const char *metadataState,
+ virDomainObjPtr dom)
+{
+ VIR_DEBUG("contentLockPlugin=%p metadataLockPlugin=%p metadataState=%s
dom=%p",
+ contentLockPlugin, metadataLockPlugin, metadataState, dom);
+
+ return virDomainLockNew(contentLockPlugin,
+ metadataLockPlugin,
+ dom,
+ NULL,
+ metadataState,
+ false,
+ true);
+}
+
+virDomainLockPtr virDomainLockForShutdown(virLockManagerPluginPtr contentLockPlugin,
+ virLockManagerPluginPtr metadataLockPlugin,
+ virDomainObjPtr dom)
+{
+ VIR_DEBUG("contentLockPlugin=%p metadataLockPlugin=%p dom=%p",
+ contentLockPlugin, metadataLockPlugin, dom);
+
+ return virDomainLockNew(contentLockPlugin,
+ metadataLockPlugin,
+ dom,
+ NULL,
+ NULL,
+ true,
+ true);
+}
+
+virDomainLockPtr virDomainLockForModify(virLockManagerPluginPtr contentLockPlugin,
+ virLockManagerPluginPtr metadataLockPlugin,
+ virDomainObjPtr dom)
+{
+ VIR_DEBUG("contentLockPlugin=%p metadataLockPlugin=%p dom=%p",
+ contentLockPlugin, metadataLockPlugin, dom);
+
+ return virDomainLockNew(contentLockPlugin,
+ metadataLockPlugin,
+ dom,
+ NULL,
+ NULL,
+ false,
+ false);
+}
+
+
+static int virDomainLockDiskOperation(virDomainLockPtr lock,
+ virDomainDiskDefPtr disk,
+ bool isBegin,
+ bool isAttach)
+{
+ unsigned int diskFlags = 0;
+ if (!disk->src)
+ return 0;
+
+ if (!(disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK ||
+ disk->type == VIR_DOMAIN_DISK_TYPE_FILE ||
+ disk->type == VIR_DOMAIN_DISK_TYPE_DIR))
+ return 0;
+
+ if (disk->readonly)
+ diskFlags |= VIR_LOCK_MANAGER_RESOURCE_READONLY;
+ if (disk->shared)
+ diskFlags |= VIR_LOCK_MANAGER_RESOURCE_SHARED;
+
+ if (isAttach) {
+ if (isBegin) {
+ if (lock->contentLock &&
+ virLockManagerAcquireResource(lock->contentLock,
+ VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK,
+ disk->src,
+ 0,
+ NULL,
+ diskFlags) < 0)
+ return -1;
+
+ if (lock->metadataLock &&
+ virLockManagerAcquireResource(lock->metadataLock,
+ VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK,
+ disk->src,
+ 0,
+ NULL,
+ diskFlags) < 0) {
+ virLockManagerReleaseResource(lock->contentLock,
+ VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK,
+ disk->src,
+ 0,
+ NULL,
+ diskFlags);
+ return -1;
+ }
+ } else {
+ if (lock->metadataLock &&
+ virLockManagerReleaseResource(lock->metadataLock,
+ VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK,
+ disk->src,
+ 0,
+ NULL,
+ diskFlags) < 0)
+ return -1;
+ }
+ } else {
+ if (isBegin) {
+ if (lock->metadataLock &&
+ virLockManagerAcquireResource(lock->metadataLock,
+ VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK,
+ disk->src,
+ 0,
+ NULL,
+ diskFlags) < 0) {
+ return -1;
+ }
+ } else {
+ if (lock->metadataLock &&
+ virLockManagerReleaseResource(lock->metadataLock,
+ VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK,
+ disk->src,
+ 0,
+ NULL,
+ diskFlags) < 0)
+ return -1;
+
+ if (lock->contentLock &&
+ virLockManagerReleaseResource(lock->contentLock,
+ VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK,
+ disk->src,
+ 0,
+ NULL,
+ diskFlags) < 0)
+ return -1;
+
+ }
+ }
+
+ return 0;
+}
+
+int virDomainLockBeginDiskAttach(virDomainLockPtr lock,
+ virDomainDiskDefPtr disk)
+{
+ return virDomainLockDiskOperation(lock, disk, true, true);
+}
+
+int virDomainLockEndDiskAttach(virDomainLockPtr lock,
+ virDomainDiskDefPtr disk)
+{
+ return virDomainLockDiskOperation(lock, disk, false, true);
+}
+
+
+int virDomainLockBeginDiskDetach(virDomainLockPtr lock,
+ virDomainDiskDefPtr disk)
+{
+ return virDomainLockDiskOperation(lock, disk, true, false);
+}
+
+
+int virDomainLockEndDiskDetach(virDomainLockPtr lock,
+ virDomainDiskDefPtr disk)
+{
+ return virDomainLockDiskOperation(lock, disk, false, false);
+}
+
+
+void virDomainLockFree(virDomainLockPtr lock)
+{
+ if (!lock)
+ return;
+
+ virLockManagerFree(lock->metadataLock);
+ virLockManagerFree(lock->contentLock);
+
+ VIR_FREE(lock);
+}
+
+void virDomainLockReleaseAndFree(virDomainLockPtr lock)
+{
+ if (!lock)
+ return;
+
+ if (lock->metadataLock) {
+ if (lock->releaseMetadataLock)
+ virLockManagerReleaseObject(lock->metadataLock, 0);
+ else
+ virLockManagerDetachObject(lock->metadataLock, 0);
+ }
+
+ if (lock->contentLock) {
+ if (lock->releaseContentLock)
+ virLockManagerReleaseObject(lock->contentLock, 0);
+ else
+ virLockManagerDetachObject(lock->contentLock, 0);
+ }
+
+ virDomainLockFree(lock);
+}
+
+int virDomainLockGetState(virDomainLockPtr lock,
+ char **contentState,
+ char **metadataState,
+ unsigned int flags)
+{
+ *contentState = NULL;
+ *metadataState = NULL;
+
+ if (lock->contentLock) {
+ if (virLockManagerGetState(lock->contentLock, contentState, flags) < 0)
+ return -1;
+ }
+
+ if (lock->metadataLock) {
+ if (virLockManagerGetState(lock->metadataLock, metadataState, flags) < 0)
{
+ VIR_FREE(*contentState);
+ return -1;
+ }
+ }
+
+ return 0;
+}
diff --git a/src/locking/domain_lock.h b/src/locking/domain_lock.h
new file mode 100644
index 0000000..d49fb94
--- /dev/null
+++ b/src/locking/domain_lock.h
@@ -0,0 +1,70 @@
+/*
+ * domain_lock.c: Locking for domain lifecycle operations
+ *
+ * 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
+ *
+ */
+
+#ifndef __VIR_DOMAIN_LOCK_H__
+# define __VIR_DOMAIN_LOCK_H__
+
+# include "internal.h"
+# include "domain_conf.h"
+# include "lock_manager.h"
+
+typedef struct _virDomainLock virDomainLock;
+typedef virDomainLock *virDomainLockPtr;
+
+virDomainLockPtr virDomainLockForExec(virLockManagerPluginPtr contentLockPlugin,
+ const char *state,
+ virDomainObjPtr dom);
+
+virDomainLockPtr virDomainLockForStartup(virLockManagerPluginPtr contentLockPlugin,
+ virLockManagerPluginPtr metadataLockPlugin,
+ const char *state,
+ virDomainObjPtr dom);
+
+virDomainLockPtr virDomainLockForShutdown(virLockManagerPluginPtr contentLockPlugin,
+ virLockManagerPluginPtr metadataLockPlugin,
+ virDomainObjPtr dom);
+
+virDomainLockPtr virDomainLockForModify(virLockManagerPluginPtr contentLockPlugin,
+ virLockManagerPluginPtr metadataLockPlugin,
+ virDomainObjPtr dom);
+
+int virDomainLockBeginDiskAttach(virDomainLockPtr dom,
+ virDomainDiskDefPtr disk);
+
+int virDomainLockEndDiskAttach(virDomainLockPtr dom,
+ virDomainDiskDefPtr disk);
+
+int virDomainLockBeginDiskDetach(virDomainLockPtr dom,
+ virDomainDiskDefPtr disk);
+
+int virDomainLockEndDiskDetach(virDomainLockPtr dom,
+ virDomainDiskDefPtr disk);
+
+void virDomainLockFree(virDomainLockPtr lock);
+void virDomainLockReleaseAndFree(virDomainLockPtr lock);
+
+int virDomainLockGetState(virDomainLockPtr manager,
+ char **contentState,
+ char **metadataState,
+ unsigned int flags);
+
+
+#endif /* __VIR_DOMAIN_LOCK_H__ */
--
1.7.3.4