Define the basic framework lock manager plugins. The basic plugin API for 3rd parties to implemented is defined in include/libvirt/plugins/lock_manager.h The libvirt code for loading & calling into plugins is in src/locking/lock_manager.{c,h} To allow QEMU driver code to assume that there is always a lock manager present, a simple 'nop' implementation is provided and linked in so that it is guarenteed to be available. This impl returns success for everything, so it should be no functional change vs previous libvirt releases. * configure.ac: Add include/libvirt/plugins/Makefile * include/libvirt/Makefile.am: Add plugins sub directory * include/libvirt/plugins/Makefile.am: Install plugin headers * include/libvirt/plugins/lock_manager.h: Public API for implementing plugins * include/libvirt/virterror.h, src/util/virterror.c: Add VIR_FROM_LOCKING * src/locking/lock_manager.c, src/locking/lock_manager.h: Internal API for managing locking * src/locking/lock_manager_nop.c, src/locking/lock_manager_nop.h: A lock manager that always succeeds * src/locking/lock_manager_nop.h, src/locking/domain_lock.c: Higher level API targetted at locking virDomainObj instances. * src/Makefile.am: Add locking code --- configure.ac | 1 + include/libvirt/Makefile.am | 2 + include/libvirt/plugins/Makefile.am | 3 + include/libvirt/plugins/lock_manager.h | 356 ++++++++++++++++++++++++++++++++ include/libvirt/virterror.h | 1 + po/POTFILES.in | 1 + src/Makefile.am | 5 +- src/libvirt_private.syms | 31 +++ src/locking/README | 158 ++++++++++++++ src/locking/domain_lock.c | 343 ++++++++++++++++++++++++++++++ src/locking/domain_lock.h | 50 +++++ src/locking/lock_manager.c | 348 +++++++++++++++++++++++++++++++ src/locking/lock_manager.h | 77 +++++++ src/locking/lock_manager_nop.c | 159 ++++++++++++++ src/locking/lock_manager_nop.h | 4 + src/util/virterror.c | 3 + 16 files changed, 1541 insertions(+), 1 deletions(-) create mode 100644 include/libvirt/plugins/Makefile.am create mode 100644 include/libvirt/plugins/lock_manager.h create mode 100644 src/locking/README create mode 100644 src/locking/domain_lock.c create mode 100644 src/locking/domain_lock.h create mode 100644 src/locking/lock_manager.c create mode 100644 src/locking/lock_manager.h create mode 100644 src/locking/lock_manager_nop.c create mode 100644 src/locking/lock_manager_nop.h diff --git a/configure.ac b/configure.ac index d21d558..b912a7a 100644 --- a/configure.ac +++ b/configure.ac @@ -2245,6 +2245,7 @@ AC_OUTPUT(Makefile src/Makefile include/Makefile docs/Makefile \ libvirt.pc libvirt.spec mingw32-libvirt.spec \ po/Makefile.in \ include/libvirt/Makefile include/libvirt/libvirt.h \ + include/libvirt/plugins/Makefile \ python/Makefile python/tests/Makefile \ daemon/Makefile \ tools/Makefile \ diff --git a/include/libvirt/Makefile.am b/include/libvirt/Makefile.am index b2c2b76..1795254 100644 --- a/include/libvirt/Makefile.am +++ b/include/libvirt/Makefile.am @@ -6,6 +6,8 @@ virinc_HEADERS = libvirt.h \ libvirt-qemu.h \ virterror.h +SUBDIRS = plugins + install-exec-hook: $(mkinstalldirs) $(DESTDIR)$(virincdir) diff --git a/include/libvirt/plugins/Makefile.am b/include/libvirt/plugins/Makefile.am new file mode 100644 index 0000000..0626d74 --- /dev/null +++ b/include/libvirt/plugins/Makefile.am @@ -0,0 +1,3 @@ + +pluginincdir = $(includedir)/libvirt/plugins +plugininc_HEADERS = lock_manager.h diff --git a/include/libvirt/plugins/lock_manager.h b/include/libvirt/plugins/lock_manager.h new file mode 100644 index 0000000..c22621b --- /dev/null +++ b/include/libvirt/plugins/lock_manager.h @@ -0,0 +1,356 @@ +/* + * lock_manager.h: Defines the lock manager plugin API + * + * Copyright (C) 2010 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_PLUGINS_LOCK_MANAGER_H__ +# define __VIR_PLUGINS_LOCK_MANAGER_H__ + +#include <stdarg.h> + +typedef struct _virLockManager virLockManager; +typedef virLockManager *virLockManagerPtr; + +typedef struct _virLockDriver virLockDriver; +typedef virLockDriver *virLockDriverPtr; + +enum { + /* The managed object is a virtual guest domain */ + VIR_LOCK_MANAGER_OBJECT_TYPE_DOMAIN = 0, +} virLockManagerObjectType; + +/* + * Flags to pass to 'load_drv' and also 'new_drv' method + * Plugins must support at least one of the modes. If a + * mode is unsupported, it must return an error + */ +enum { + VIR_LOCK_MANAGER_MODE_CONTENT = (1 << 0), + VIR_LOCK_MANAGER_MODE_METADATA = (1 << 1), +} virLockManagerFlags; + +enum { + /* The resource to be locked is a virtual disk */ + VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK = 0, +} virLockManagerResourceType; + +typedef enum { + /* The resource is assigned in readonly mode */ + VIR_LOCK_MANAGER_RESOURCE_READONLY = (1 << 0), + /* The resource is assigned in shared, writable mode */ + VIR_LOCK_MANAGER_RESOURCE_SHARED = (1 << 1), +} virLockManagerResourceFlags; + +/* + * Changes in major version denote incompatible ABI changes + * Changes in minor version denote new compatible API entry points + * Changes in micro version denote new compatible flags + */ +# define VIR_LOCK_MANAGER_VERSION_MAJOR 1 +# define VIR_LOCK_MANAGER_VERSION_MINOR 0 +# define VIR_LOCK_MANAGER_VERSION_MICRO 0 + +# define VIR_LOCK_MANAGER_VERSION \ + ((VIR_LOCK_MANAGER_VERSION_MAJOR * 1000 * 1000) + \ + (VIR_LOCK_MANAGER_VERSION_MINOR * 1000) + \ + (VIR_LOCK_MANAGER_VERSION_MICRO)) + + +typedef void (*virLockDriverError)(const char *fmt, ...); +typedef void (*virLockDriverErrorV)(const char *fmt, va_list args); + +/** + * virLockDriverInit: + * @version: the libvirt requested plugin ABI version + * @flags: the libvirt requested plugin optional extras + * + * Allow the plugin to validate the libvirt requested + * plugin version / flags. This allows the plugin impl + * to block its use in versions of libvirtd which are + * too old to support key features. + * + * NB: A plugin may be loaded multiple times, for different + * libvirt drivers (eg QEMU, LXC, UML) + * + * Returns -1 if the requested version/flags were inadequate + */ +typedef int (*virLockDriverInit)(unsigned int version, + unsigned int flags); + +/** + * virLockDriverDeinit: + * + * Called to release any resources prior to the plugin + * being unloaded from memory. Returns -1 to prevent + * plugin from being unloaded from memory. + */ +typedef int (*virLockDriverDeinit)(void); + +/** + * virLockManagerNew: + * @man: the lock manager context + * @type: the type of process to be supervised + * @flags: optional flags, currently unused + * + * Initialize a new context to supervise a process, usually + * a virtual machine. If the lock driver requested a + * private data, the <code>privateData</code> field of + * <code>man</code> will be initialized with a suitable + * pointer. + * + * Returns 0 if successful initialized a new context, -1 on error + */ +typedef int (*virLockDriverNew)(virLockManagerPtr man, + unsigned int type, + unsigned int flags); + +/** + * virLockDriverFree: + * @manager: the lock manager context + * + * Release any resources associated with the lock manager + * context private data + */ +typedef void (*virLockDriverFree)(virLockManagerPtr man); + +/** + * virLockDriverAddResource: + * @manager: the lock manager context + * @type: the resource type virLockManagerResourceType + * @name: the resource name + * @flags: the resource access flags + * + * Assign a resource to a managed object. This will + * only be called prior to the object is being locked + * when it is inactive. eg, to set the initial boot + * time disk assignments on a VM + * The format of @name varies according to + * the resource @type. A VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK + * will have a fully qualified file path. + * + * If no flags are given, the resource is assumed to be + * used in exclusive, read-write mode. Access can be + * relaxed to readonly, or shared read-write. + * + * Returns 0 on success, or -1 on failure + */ +typedef int (*virLockDriverAddResource)(virLockManagerPtr man, + unsigned int type, + const char *name, + unsigned int flags); + +/** + * virLockDriverSetParameter: + * @manager: the lock manager context + * @key: the parameter name + * @value: the parameter value + * + * Set a configuration parameter for the managed process. + * A process of VIR_LOCK_MANAGER_START_DOMAIN will be + * given at least 3 parameters: + * + * - id: the domain unique id + * - uuid: the domain uuid + * - name: the domain name + * + * There may be other parameters specific to the lock manager + * plugin that are provided for the managed process + * + * This should only be called prior to the supervised process + * being started. + * + * Returns 0 on success, or -1 on failure + */ +typedef int (*virLockDriverSetParameter)(virLockManagerPtr man, + const char *key, + const char *value); + +/** + * virLockDriverAcquireObject: + * @manager: the lock manager context + * @state: the current lock state + * @flags: optional flags, currently unused + * + * Start managing resources for the object. If the + * object is being transferred from another location + * the current lock state may be passed in. This + * must be called from the PID that represents the + * object to be managed. If the lock is lost at any + * time, the PID will be killed off by the lock manager. + * + * Returns 0 on success, or -1 on failure + */ +typedef int (*virLockDriverAcquireObject)(virLockManagerPtr man, + const char *state, + unsigned int flags); + +/** + * virLockDriverAttachObject: + * @manager: the lock manager context + * @pid: the managed object PID + * @flags: optional flags, currently unused + * + * Re-attach to an existing lock manager instance managing + * PID @pid. + * + * Returns 0 on success, or -1 on failure + */ +typedef int (*virLockDriverAttachObject)(virLockManagerPtr man, + pid_t pid, + unsigned int flags); + +/** + * virLockDriverDetachObject: + * @manager: the lock manager context + * @pid: the managed object PID + * @flags: optional flags, currently unused + * + * Deattach from an existing lock manager instance managing + * PID @pid. + * + * Returns 0 on success, or -1 on failure + */ +typedef int (*virLockDriverDetachObject)(virLockManagerPtr man, + pid_t pid, + unsigned int flags); + +/** + * virLockDriverReleaseObject: + * @manager: the lock manager context + * @flags: optional flags + * + * Inform the lock manager that the supervised process has + * been, or can be stopped. This can must be called from + * the same context as the previous virLockDriverAttachObject + * or virLockDriverAcquireObject call. + * + * Returns 0 on success, or -1 on failure + */ +typedef int (*virLockDriverReleaseObject)(virLockManagerPtr man, + unsigned int flags); + +/** + * virLockDriverGetState: + * @manager: the lock manager context + * @state: pointer to be filled with lock state + * @flags: optional flags, currently unused + * + * Retrieve the current lock state. The returned + * lock state may be NULL if none is required. The + * caller is responsible for freeing the lock + * state string when it is no longer required + * + * Returns 0 on success, or -1 on failure. + */ +typedef int (*virLockDriverGetState)(virLockManagerPtr man, + char **state, + unsigned int flags); + +/** + * virLockDriverAcquireResource: + * @manager: the lock manager context + * @type: the resource type virLockDriverResourceType + * @name: the resource name + * @flags: the resource access flags + * + * Assign a resource to a managed object. This will + * only be called when the object is already locked + * and active. eg, to hotplug a disk into a VM. + * The format of @name varies according to + * the resource @type. A VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK + * will have a fully qualified file path. + * + * If no flags are given, the resource is assumed to be + * used in exclusive, read-write mode. Access can be + * relaxed to readonly, or shared read-write. + * + * Returns 0 on success, or -1 on failure + */ +typedef int (*virLockDriverAcquireResource)(virLockManagerPtr man, + unsigned int type, + const char *name, + unsigned int flags); + +/** + * virLockDriverReleaseResource: + * @manager: the lock manager context + * @type: the resource type virLockDriverResourceType + * @name: the resource name + * @flags: the resource access flags + * + * Dynamically release a resource for a running process. + * This may only be called after the process has been + * started. The format of @name varies according to + * the resource @type. A VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK + * will have a fully qualified file path. + * + * If no flags are given, the resource is assumed to be + * used in exclusive, read-write mode. Access can be + * relaxed to readonly, or shared read-write. + * + * Returns 0 on success, or -1 on failure + */ +typedef int (*virLockDriverReleaseResource)(virLockManagerPtr man, + unsigned int type, + const char *name, + unsigned int flags); + +struct _virLockManager { + virLockDriverPtr driver; + virLockDriverError error; + virLockDriverErrorV errorV; + void *privateData; +}; + +/** + * The plugin must export a static instance of this + * driver table, with the name 'virLockDriverImpl' + */ +struct _virLockDriver { + /** + * @version: the newest implemented plugin ABI version + * @flags: optional flags, currently unused + */ + unsigned int version; + unsigned int flags; + + size_t privateDataLen; + + virLockDriverInit drvInit; + virLockDriverDeinit drvDeinit; + + virLockDriverNew drvNew; + virLockDriverFree drvFree; + + virLockDriverAddResource drvAddResource; + virLockDriverSetParameter drvSetParameter; + + virLockDriverAcquireObject drvAcquireObject; + virLockDriverAttachObject drvAttachObject; + virLockDriverDetachObject drvDetachObject; + virLockDriverReleaseObject drvReleaseObject; + + virLockDriverGetState drvGetState; + + virLockDriverAcquireResource drvAcquireResource; + virLockDriverAcquireResource drvReleaseResource; +}; + + +#endif /* __VIR_PLUGINS_LOCK_MANAGER_H__ */ diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h index eaeb477..c60f7bf 100644 --- a/include/libvirt/virterror.h +++ b/include/libvirt/virterror.h @@ -76,6 +76,7 @@ typedef enum { VIR_FROM_AUDIT, /* Error from auditing subsystem */ VIR_FROM_SYSINFO, /* Error from sysinfo/SMBIOS */ VIR_FROM_STREAMS, /* Error from I/O streams */ + VIR_FROM_LOCKING, /* Error from lock manager */ } virErrorDomain; diff --git a/po/POTFILES.in b/po/POTFILES.in index 2820ac1..75c259c 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -30,6 +30,7 @@ src/fdstream.c src/interface/netcf_driver.c src/internal.h src/libvirt.c +src/locking/lock_manager.c src/lxc/lxc_container.c src/lxc/lxc_conf.c src/lxc/lxc_controller.c diff --git a/src/Makefile.am b/src/Makefile.am index 66af9cf..750612f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -89,7 +89,10 @@ DRIVER_SOURCES = \ datatypes.c datatypes.h \ fdstream.c fdstream.h \ $(NODE_INFO_SOURCES) \ - libvirt.c libvirt_internal.h + libvirt.c libvirt_internal.h \ + locking/lock_manager.c locking/lock_manager.h \ + locking/lock_manager_nop.c locking/lock_manager_nop.h \ + locking/domain_lock.c locking/domain_lock.h # XML configuration format handling sources diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 3af0210..e808375 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -312,6 +312,19 @@ virDomainEventWatchdogNewFromDom; virDomainEventWatchdogNewFromObj; +# domain_lock.h +virDomainLockFree; +virDomainLockForExec; +virDomainLockForStartup; +virDomainLockForShutdown; +virDomainLockForModify; +virDomainLockBeginDiskAttach; +virDomainLockBeginDiskDetach; +virDomainLockEndDiskAttach; +virDomainLockEndDiskDetach; +virDomainLockReleaseAndFree; + + # domain_nwfilter.h virDomainConfNWFilterInstantiate; virDomainConfNWFilterRegister; @@ -479,6 +492,24 @@ virRegisterSecretDriver; virRegisterStorageDriver; +# locking.h +virLockManagerAcquireObject; +virLockManagerAcquireResource; +virLockManagerAddResource; +virLockManagerAttachObject; +virLockManagerDetachObject; +virLockManagerFree; +virLockManagerGetState; +virLockManagerNew; +virLockManagerPluginNew; +virLockManagerPluginRef; +virLockManagerPluginUnref; +virLockManagerReleaseObject; +virLockManagerReleaseResource; +virLockManagerSetParameter; +virLockManagerStartup; + + # logging.h virLogDefineFilter; virLogDefineOutput; diff --git a/src/locking/README b/src/locking/README new file mode 100644 index 0000000..4fa4f89 --- /dev/null +++ b/src/locking/README @@ -0,0 +1,158 @@ + +At libvirtd startup: + + plugin = virLockManagerPluginLoad("sync-manager"); + + +At libvirtd shtudown: + + virLockManagerPluginUnload(plugin) + + +At guest startup: + + manager = virLockManagerNew(plugin, + VIR_LOCK_MANAGER_OBJECT_DOMAIN, + 0); + + virLockManagerSetParameter(manager, "id", id); + virLockManagerSetParameter(manager, "uuid", uuid); + virLockManagerSetParameter(manager, "name", name); + + foreach disk + virLockManagerRegisterResource(manager, + VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK, + disk.path, + ..flags...); + + if (!virLockManagerAcquireObject(manager)) + abort.. + + run QEMU + + +At guest shutdown: + + ...send QEMU 'quit' monitor command, and/or kill(qemupid)... + + if (!virLockManagerShutdown(manager)) + kill(supervisorpid); /* XXX or leave it running ??? */ + + virLockManagerFree(manager); + + + +At libvirtd restart with running guests: + + foreach still running guest + manager = virLockManagerNew(driver, + VIR_LOCK_MANAGER_START_DOMAIN, + VIR_LOCK_MANAGER_NEW_ATTACH); + virLockManagerSetParameter(manager, "id", id); + virLockManagerSetParameter(manager, "uuid", uuid); + virLockManagerSetParameter(manager, "name", name); + + if (!virLockManagerGetChild(manager, &qemupid)) + kill(supervisorpid); /* XXX or leave it running ??? */ + + + +With disk hotplug: + + if (virLockManagerAcquireResource(manager, + VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK, + disk.path + ..flags..)) + ...abort hotplug attempt ... + + ...hotplug the device... + + + +With disk unhotplug: + + ...hotunplug the device... + + if (virLockManagerReleaseResource(manager, + VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK, + disk.path + ..flags..)) + ...log warning ... + + + +During migration: + + 1. On source host + + if (!virLockManagerPrepareMigrate(manager, hosturi)) + ..don't start migration.. + + 2. On dest host + + manager = virLockManagerNew(driver, + VIR_LOCK_MANAGER_START_DOMAIN, + VIR_LOCK_MANAGER_NEW_MIGRATE); + virLockManagerSetParameter(manager, "id", id); + virLockManagerSetParameter(manager, "uuid", uuid); + virLockManagerSetParameter(manager, "name", name); + + foreach disk + virLockManagerRegisterResource(manager, + VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK, + disk.path, + ..flags...); + + char **supervisorargv; + int supervisorargc; + + supervisor = virLockManagerGetSupervisorPath(manager); + virLockManagerGetSupervisorArgs(&argv, &argc); + + cmd = qemuBuildCommandLine(supervisor, supervisorargv, supervisorargv); + + supervisorpid = virCommandExec(cmd); + + if (!virLockManagerGetChild(manager, &qemupid)) + kill(supervisorpid); /* XXX or leave it running ??? */ + + 3. Initiate migration in QEMU on source and wait for completion + + 4a. On failure + + 4a1 On target + + virLockManagerCompleteMigrateIn(manager, + VIR_LOCK_MANAGER_MIGRATE_CANCEL); + virLockManagerShutdown(manager); + virLockManagerFree(manager); + + 4a2 On source + + virLockManagerCompleteMigrateIn(manager, + VIR_LOCK_MANAGER_MIGRATE_CANCEL); + + 4b. On succcess + + + 4b1 On target + + virLockManagerCompleteMigrateIn(manager, 0); + + 42 On source + + virLockManagerCompleteMigrateIn(manager, 0); + virLockManagerShutdown(manager); + virLockManagerFree(manager); + + +Notes: + + - If a lock manager impl does just VM level leases, it can + ignore all the resource paths at startup. + + - If a lock manager impl does not support migrate + it can return an error from all migrate calls + + - If a lock manger impl does not support hotplug + it can return an error from all resource acquire/release calls diff --git a/src/locking/domain_lock.c b/src/locking/domain_lock.c new file mode 100644 index 0000000..086ab4d --- /dev/null +++ b/src/locking/domain_lock.c @@ -0,0 +1,343 @@ + +#include <config.h> + +#include "domain_lock.h" +#include "memory.h" +#include "uuid.h" +#include "virterror_internal.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; + char uuidstr[VIR_UUID_STRING_BUFLEN]; + int i; + + if (!(lock = virLockManagerNew(plugin, + mode, + VIR_LOCK_MANAGER_OBJECT_TYPE_DOMAIN))) + return NULL; + + virUUIDFormat(vm->def->uuid, uuidstr); + if (virLockManagerSetParameter(lock, + "uuid", uuidstr) < 0) + goto error; + if (virLockManagerSetParameter(lock, + "name", vm->def->name) < 0) + goto error; + + if (acquireLock) { + 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; + + if (virLockManagerAddResource(lock, + VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK, + disk->src, + diskFlags) < 0) { + virLockManagerFree(lock); + return NULL; + } + } + + if (virLockManagerAcquireObject(lock, state, 0) < 0) + goto error; + } else { + if (virLockManagerAttachObject(lock, vm->pid, 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) +{ + return virDomainLockNew(contentLockPlugin, + NULL, + dom, + contentState, + NULL, + true, + false); +} + +virDomainLockPtr virDomainLockForStartup(virLockManagerPluginPtr contentLockPlugin, + virLockManagerPluginPtr metadataLockPlugin, + const char *metadataState, + virDomainObjPtr dom) +{ + return virDomainLockNew(contentLockPlugin, + metadataLockPlugin, + dom, + NULL, + metadataState, + false, + true); +} + +virDomainLockPtr virDomainLockForShutdown(virLockManagerPluginPtr contentLockPlugin, + virLockManagerPluginPtr metadataLockPlugin, + virDomainObjPtr dom) +{ + return virDomainLockNew(contentLockPlugin, + metadataLockPlugin, + dom, + NULL, + NULL, + true, + true); +} + +virDomainLockPtr virDomainLockForModify(virLockManagerPluginPtr contentLockPlugin, + virLockManagerPluginPtr metadataLockPlugin, + virDomainObjPtr 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, + diskFlags) < 0) + return -1; + + if (lock->metadataLock && + virLockManagerAcquireResource(lock->metadataLock, + VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK, + disk->src, + diskFlags) < 0) { + virLockManagerReleaseResource(lock->contentLock, + VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK, + disk->src, + diskFlags); + return -1; + } + } else { + if (lock->metadataLock && + virLockManagerReleaseResource(lock->metadataLock, + VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK, + disk->src, + diskFlags) < 0) + return -1; + } + } else { + if (isBegin) { + if (lock->metadataLock && + virLockManagerAcquireResource(lock->metadataLock, + VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK, + disk->src, + diskFlags) < 0) { + return -1; + } + } else { + if (lock->metadataLock && + virLockManagerReleaseResource(lock->metadataLock, + VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK, + disk->src, + diskFlags) < 0) + return -1; + + if (lock->contentLock && + virLockManagerReleaseResource(lock->contentLock, + VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK, + disk->src, + 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, lock->pid, 0); + } + + if (lock->contentLock) { + if (lock->releaseContentLock) + virLockManagerReleaseObject(lock->contentLock, 0); + else + virLockManagerDetachObject(lock->contentLock, lock->pid, 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..923410e --- /dev/null +++ b/src/locking/domain_lock.h @@ -0,0 +1,50 @@ + +#include "internal.h" +#include "domain_conf.h" +#include "lock_manager.h" + +#ifndef __VIR_DOMAIN_LOCK_H__ +# define __VIR_DOMAIN_LOCK_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__ */ diff --git a/src/locking/lock_manager.c b/src/locking/lock_manager.c new file mode 100644 index 0000000..dc5e7d8 --- /dev/null +++ b/src/locking/lock_manager.c @@ -0,0 +1,348 @@ +/* + * lock_manager.c: Implements the internal lock manager API + * + * Copyright (C) 2010 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 "lock_manager.h" +#include "lock_manager_nop.h" +#include "virterror_internal.h" +#include "logging.h" +#include "util.h" +#include "memory.h" + +#include <dlfcn.h> +#include <stdlib.h> +#include <unistd.h> + +#define VIR_FROM_THIS VIR_FROM_LOCKING + +#define virLockError(code, ...) \ + virReportErrorHelper(NULL, VIR_FROM_THIS, code, __FILE__, \ + __FUNCTION__, __LINE__, __VA_ARGS__) + +#define CHECK_PLUGIN(field, errret) \ + if (!plugin->driver->field) { \ + virLockError(VIR_ERR_INTERNAL_ERROR, \ + _("Missing '%s' field in lock manager driver"), \ + #field); \ + return errret; \ + } + +#define CHECK_MANAGER(field, errret) \ + if (!manager->driver->field) { \ + virLockError(VIR_ERR_INTERNAL_ERROR, \ + _("Missing '%s' field in lock manager driver"), \ + #field); \ + return errret; \ + } + +struct _virLockManagerPlugin { + virLockDriverPtr driver; + void *handle; + int refs; +}; + +#define DEFAULT_LOCK_MANAGER_PLUGIN_DIR LIBDIR "/libvirt/lock_manager" + +static void virLockManagerErrorV(const char *fmt, va_list args ATTRIBUTE_UNUSED) +{ + /* XXX how to pass va-list to virReportErrorFull ??? */ + virLockError(VIR_ERR_INTERNAL_ERROR, "%s", fmt); +} + + +static void virLockManagerError(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + virLockManagerErrorV(fmt, args); + va_end(args); +} + +/** + * virLockManagerPluginNew: + * @name: the name of the plugin + * @flag: optional plugin flags + * + * Attempt to load the plugin $(libdir)/libvirt/lock_manager/@name.so + * The plugin driver entry point will be resolved & invoked to obtain + * the lock manager driver. + * + * Even if the loading of the plugin succeeded, this may still + * return NULL if the plugin impl decided that we (libvirtd) + * are too old to support a feature it requires + * + * Returns a plugin object, or NULL if loading failed. + */ +virLockManagerPluginPtr virLockManagerPluginNew(const char *name, + unsigned int flags) +{ + void *handle = NULL; + virLockDriverPtr driver; + virLockManagerPluginPtr plugin; + const char *moddir = getenv("LIBVIRT_LOCK_MANAGER_PLUGIN_DIR"); + char *modfile = NULL; + + if (STREQ(name, "nop")) { + driver = &virLockDriverNop; + } else { + if (moddir == NULL) + moddir = DEFAULT_LOCK_MANAGER_PLUGIN_DIR; + + VIR_DEBUG("Module load %s from %s", name, moddir); + + if (virAsprintf(&modfile, "%s/%s.so", moddir, name) < 0) { + virReportOOMError(); + return NULL; + } + + if (access(modfile, R_OK) < 0) { + virReportSystemError(errno, + _("Plugin %s not accessible"), + modfile); + goto cleanup; + } + + handle = dlopen(modfile, RTLD_NOW | RTLD_LOCAL); + if (!handle) { + virLockError(VIR_ERR_SYSTEM_ERROR, + _("Failed to load plugin %s: %s"), + modfile, dlerror()); + goto cleanup; + } + + if (!(driver = dlsym(handle, "virLockDriverImpl"))) { + virLockError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Missing plugin initialization symbol 'virLockDriverImpl'")); + goto cleanup; + } + } + + if (driver->drvInit(VIR_LOCK_MANAGER_VERSION, flags) < 0) { + virLockError(VIR_ERR_INTERNAL_ERROR, "%s", + _("plugin ABI is not compatible")); + goto cleanup; + } + + if (VIR_ALLOC(plugin) < 0) { + virReportOOMError(); + goto cleanup; + } + + plugin->driver = driver; + plugin->handle = handle; + plugin->refs = 1; + + VIR_FREE(modfile); + return plugin; + +cleanup: + VIR_FREE(modfile); + if (handle) + dlclose(handle); + return NULL; +} + + +/** + * virLockManagerPluginRef: + * @plugin: the plugin implementation to ref + * + * Acquires an additional reference on the plugin. + */ +void virLockManagerPluginRef(virLockManagerPluginPtr plugin) +{ + plugin->refs++; +} + + +/** + * virLockManagerPluginUnref: + * @plugin: the plugin implementation to unref + * + * Releases a reference on the plugin. When the last reference + * is released, it will attempt to unload the plugin from memory. + * The plugin may refuse to allow unloading if this would + * result in an unsafe scenario. + * + */ +void virLockManagerPluginUnref(virLockManagerPluginPtr plugin) +{ + if (!plugin) + return; + + plugin->refs--; + + if (plugin->refs > 0) + return; + + if (plugin->driver->drvDeinit() >= 0) { + if (plugin->handle) + dlclose(plugin->handle); + } else { + VIR_WARN0("Unable to unload lock maanger plugin from memory"); + return; + } + + VIR_FREE(plugin); +} + + +/** + * virLockManagerNew: + * @plugin: the plugin implementation to use + * @type: the type of process to be supervised + * @flags: optional flags, currently unused + * + * Create a new context to supervise a process, usually + * a virtual machine. + * + * Returns a new lock manager context + */ +virLockManagerPtr virLockManagerNew(virLockManagerPluginPtr plugin, + unsigned int type, + unsigned int flags) +{ + virLockManagerPtr lock; + CHECK_PLUGIN(drvNew, NULL); + + if (VIR_ALLOC_VAR(lock, char, plugin->driver->privateDataLen) < 0) { + virReportOOMError(); + return NULL; + } + + lock->driver = plugin->driver; + lock->error = virLockManagerError; + lock->errorV = virLockManagerErrorV; + lock->privateData = plugin->driver->privateDataLen ? lock + sizeof(*lock) : NULL; + + if (plugin->driver->drvNew(lock, type, flags) < 0) { + VIR_FREE(lock); + return NULL; + } + + return lock; +} + + +int virLockManagerAddResource(virLockManagerPtr manager, + unsigned int type, + const char *name, + unsigned int flags) +{ + CHECK_MANAGER(drvAddResource, -1); + + return manager->driver->drvAddResource(manager, type, name, flags); +} + +int virLockManagerAcquireObject(virLockManagerPtr manager, + const char *state, + unsigned int flags) +{ + CHECK_MANAGER(drvAcquireObject, -1); + + return manager->driver->drvAcquireObject(manager, state, flags); +} + + +int virLockManagerAttachObject(virLockManagerPtr manager, + pid_t pid, + unsigned int flags) +{ + CHECK_MANAGER(drvAttachObject, -1); + + return manager->driver->drvAttachObject(manager, pid, flags); +} + + +int virLockManagerDetachObject(virLockManagerPtr manager, + pid_t pid, + unsigned int flags) +{ + CHECK_MANAGER(drvDetachObject, -1); + + return manager->driver->drvDetachObject(manager, pid, flags); +} + + +int virLockManagerReleaseObject(virLockManagerPtr manager, + unsigned int flags) +{ + CHECK_MANAGER(drvReleaseObject, -1); + + return manager->driver->drvReleaseObject(manager, flags); +} + + +int virLockManagerGetState(virLockManagerPtr manager, + char **state, + unsigned int flags) +{ + CHECK_MANAGER(drvGetState, -1); + + return manager->driver->drvGetState(manager, state, flags); +} + + +int virLockManagerSetParameter(virLockManagerPtr manager, + const char *key, + const char *value) +{ + CHECK_MANAGER(drvSetParameter, -1); + + return manager->driver->drvSetParameter(manager, key, value); +} + + +int virLockManagerAcquireResource(virLockManagerPtr manager, + unsigned int type, + const char *name, + unsigned int flags) +{ + CHECK_MANAGER(drvAcquireResource, -1); + + return manager->driver->drvAcquireResource(manager, type, name, flags); +} + + +int virLockManagerReleaseResource(virLockManagerPtr manager, + unsigned int type, + const char *name, + unsigned int flags) +{ + CHECK_MANAGER(drvReleaseResource, -1); + + return manager->driver->drvReleaseResource(manager, type, name, flags); +} + + +int virLockManagerFree(virLockManagerPtr manager) +{ + if (!manager) + return 0; + + CHECK_MANAGER(drvFree, -1); + + manager->driver->drvFree(manager); + + return 0; +} diff --git a/src/locking/lock_manager.h b/src/locking/lock_manager.h new file mode 100644 index 0000000..35d4433 --- /dev/null +++ b/src/locking/lock_manager.h @@ -0,0 +1,77 @@ +/* + * lock_manager.h: Defines the internal lock manager API + * + * Copyright (C) 2010 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_LOCK_MANAGER_H__ +# define __VIR_LOCK_MANAGER_H__ + +# include "internal.h" +# include <libvirt/plugins/lock_manager.h> + +typedef struct _virLockManagerPlugin virLockManagerPlugin; +typedef virLockManagerPlugin *virLockManagerPluginPtr; + +virLockManagerPluginPtr virLockManagerPluginNew(const char *name, + unsigned int flags); +void virLockManagerPluginRef(virLockManagerPluginPtr plugin); +void virLockManagerPluginUnref(virLockManagerPluginPtr plugin); + +virLockManagerPtr virLockManagerNew(virLockManagerPluginPtr plugin, + unsigned int type, + unsigned int flags); + +int virLockManagerSetParameter(virLockManagerPtr manager, + const char *key, + const char *value); + +int virLockManagerAddResource(virLockManagerPtr manager, + unsigned int type, + const char *name, + unsigned int flags); + +int virLockManagerAcquireObject(virLockManagerPtr manager, + const char *state, + unsigned int flags); +int virLockManagerAttachObject(virLockManagerPtr manager, + pid_t pid, + unsigned int flags); +int virLockManagerDetachObject(virLockManagerPtr manager, + pid_t pid, + unsigned int flags); +int virLockManagerReleaseObject(virLockManagerPtr manager, + unsigned int flags); + +int virLockManagerGetState(virLockManagerPtr manager, + char **state, + unsigned int flags); + +int virLockManagerAcquireResource(virLockManagerPtr manager, + unsigned int type, + const char *name, + unsigned int flags); + +int virLockManagerReleaseResource(virLockManagerPtr manager, + unsigned int type, + const char *name, + unsigned int flags); + +int virLockManagerFree(virLockManagerPtr manager); + +#endif /* __VIR_LOCK_MANAGER_H__ */ diff --git a/src/locking/lock_manager_nop.c b/src/locking/lock_manager_nop.c new file mode 100644 index 0000000..e03d6ec --- /dev/null +++ b/src/locking/lock_manager_nop.c @@ -0,0 +1,159 @@ + +#include <config.h> + +#include "lock_manager_nop.h" +#include "memory.h" +#include "logging.h" + +/** + * + * NB: This file must *not* use regular virReportError functions + * but instead use the lock manager plugin error reporting hooks + * + */ + +static int virLockManagerNopInit(unsigned int version, + unsigned int flags) +{ + VIR_DEBUG("version=%u flags=%u", version, flags); + + return 0; +} + +static int virLockManagerNopDeinit(void) +{ + VIR_DEBUG0(""); + + return 0; +} + +static int virLockManagerNopNew(virLockManagerPtr lock, + unsigned int type, + unsigned int flags) +{ + VIR_DEBUG("lock=%p, type=%u flags=%u", lock, type, flags); + + return 0; +} + +static int virLockManagerNopAddResource(virLockManagerPtr lock, + unsigned int type, + const char *name, + unsigned int flags) +{ + VIR_DEBUG("lock=%p type=%u name=%s flags=%u", lock, type, name, flags); + + return 0; +} + +static int virLockManagerNopSetParameter(virLockManagerPtr lock, + const char *key, + const char *value) +{ + VIR_DEBUG("lock=%p key=%s value=%s", lock, key, value); + + return 0; +} + +static int virLockManagerNopAcquireObject(virLockManagerPtr lock, + const char *state, + unsigned int flags) +{ + VIR_DEBUG("lock=%p state=%s flags=%u", lock, state, flags); + + return 0; +} + +static int virLockManagerNopAttachObject(virLockManagerPtr lock, + pid_t pid, + unsigned int flags) +{ + VIR_DEBUG("lock=%p pid=%u flags=%u", lock, (unsigned int)pid, flags); + + return 0; +} + +static int virLockManagerNopDetachObject(virLockManagerPtr lock, + pid_t pid, + unsigned int flags) +{ + VIR_DEBUG("lock=%p pid=%u flags=%u", lock, (unsigned int)pid, flags); + + return 0; +} + + +static int virLockManagerNopReleaseObject(virLockManagerPtr lock, + unsigned int flags) +{ + VIR_DEBUG("lock=%p flags=%u", lock, flags); + + return 0; +} + +static int virLockManagerNopGetState(virLockManagerPtr lock, + char **state, + unsigned int flags) +{ + VIR_DEBUG("lock=%p state=%p flags=%u", lock, state, flags); + + *state = NULL; + + return 0; +} + + +static int virLockManagerNopAcquireResource(virLockManagerPtr lock, + unsigned int type, + const char *name, + unsigned int flags) +{ + VIR_DEBUG("lock=%p type=%u name=%s flags=%u", lock, type, name, flags); + + return 0; +} + +static int virLockManagerNopReleaseResource(virLockManagerPtr lock, + unsigned int type, + const char *name, + unsigned int flags) +{ + VIR_DEBUG("lock=%p type=%u name=%s flags=%u", lock, type, name, flags); + + return 0; +} + +static void virLockManagerNopFree(virLockManagerPtr man) +{ + VIR_DEBUG("lock=%p", man); + + VIR_FREE(man); +} + +virLockDriver virLockDriverNop = +{ + .version = VIR_LOCK_MANAGER_VERSION, + .flags = VIR_LOCK_MANAGER_MODE_CONTENT | VIR_LOCK_MANAGER_MODE_METADATA, + + .privateDataLen = 0, + + .drvInit = virLockManagerNopInit, + .drvDeinit = virLockManagerNopDeinit, + + .drvNew = virLockManagerNopNew, + .drvFree = virLockManagerNopFree, + + .drvAddResource = virLockManagerNopAddResource, + .drvSetParameter = virLockManagerNopSetParameter, + + .drvAcquireObject = virLockManagerNopAcquireObject, + .drvAttachObject = virLockManagerNopAttachObject, + .drvDetachObject = virLockManagerNopDetachObject, + .drvReleaseObject = virLockManagerNopReleaseObject, + + .drvGetState = virLockManagerNopGetState, + + .drvAcquireResource = virLockManagerNopAcquireResource, + .drvReleaseResource = virLockManagerNopReleaseResource, +}; + diff --git a/src/locking/lock_manager_nop.h b/src/locking/lock_manager_nop.h new file mode 100644 index 0000000..61d6d2c --- /dev/null +++ b/src/locking/lock_manager_nop.h @@ -0,0 +1,4 @@ + +#include "lock_manager.h" + +extern virLockDriver virLockDriverNop; diff --git a/src/util/virterror.c b/src/util/virterror.c index 9757fd4..d524d04 100644 --- a/src/util/virterror.c +++ b/src/util/virterror.c @@ -196,6 +196,9 @@ static const char *virErrorDomainName(virErrorDomain domain) { case VIR_FROM_STREAMS: dom = "Streams "; break; + case VIR_FROM_LOCKING: + dom = "Locking "; + break; } return(dom); } -- 1.7.2.3 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list