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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list