[libvirt] [PATCH 08/11] Add higher level lock API for domain objects

Daniel P. Berrange berrange at redhat.com
Mon Jan 24 15:13:07 UTC 2011


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




More information about the libvir-list mailing list