[libvirt] [PATCH v3 0/7] Introduce API for dumping domain IP addresses
by Michal Privoznik
This feature has been requested for a very long time. However,
we had to wait for guest agent to obtain reliable results as
user might create totally different structure of interfaces than
seen from outside (e.g. bonding, virtual interfaces, etc.).
That's the main reason why sniffing for domain traffic can
return bogus results. Fortunately, qemu guest agent implement
requested part for a while so nothing holds us back anymore.
To make matters worse, guest OS can assign whatever name to
an interface and changing MAC inside guest isn't propagated
to the host which in the end see original one.
Therefore, finding correlation between interface within guest
and the host side end is left as exercise for mgmt applications.
This API is called virDomainInterfacesAddresses (okay, maybe
too many plurals) and returns a dynamically allocated array
of virDomainInterface struct. We agreed on this in previous versions.
Michal Privoznik (7):
Introduce virDomainInterfacesAddresses API
virsh: Expose virDomainInterfacesAddresses
qemu_agent: Implement 'guest-network-get-interfaces' command handling
qemu: Implement virDomainInterfacesAddresses
remote: Implement virDomainInterfacesAddresses
python: Expose virDomainInterfacesAddresses
python: create example for dumping domain IP addresses
daemon/remote.c | 124 +++++++++++++++++++++++++++++++
examples/python/Makefile.am | 2 +-
examples/python/README | 1 +
examples/python/domipaddrs.py | 50 +++++++++++++
include/libvirt/libvirt.h.in | 36 +++++++++
python/generator.py | 1 +
python/libvirt-override-api.xml | 6 ++
python/libvirt-override.c | 115 ++++++++++++++++++++++++++++
src/driver.h | 5 +
src/libvirt.c | 98 ++++++++++++++++++++++++
src/libvirt_public.syms | 1 +
src/qemu/qemu_agent.c | 156 +++++++++++++++++++++++++++++++++++++++
src/qemu/qemu_agent.h | 3 +
src/qemu/qemu_driver.c | 76 +++++++++++++++++++
src/remote/remote_driver.c | 88 ++++++++++++++++++++++
src/remote/remote_protocol.x | 24 ++++++-
src/remote_protocol-structs | 24 ++++++
tools/virsh-domain-monitor.c | 112 ++++++++++++++++++++++++++++
tools/virsh.pod | 11 +++
19 files changed, 931 insertions(+), 2 deletions(-)
create mode 100644 examples/python/domipaddrs.py
--
1.7.8.6
12 years, 3 months
[libvirt] [PATCH] Introduce an internal API for handling file based lockspaces
by Daniel P. Berrange
From: "Daniel P. Berrange" <berrange(a)redhat.com>
The previously introduced virFile{Lock,Unlock} APIs provide a
way to acquire/release fcntl() locks on individual files. For
unknown reason though, the POSIX spec says that fcntl() locks
are released when *any* file handle refering to the same path
is closed. In the following sequence
threadA: fd1 = open("foo")
threadB: fd2 = open("foo")
threadA: virFileLock(fd1)
threadB: virFileLock(fd2)
threadB: close(fd2)
you'd expect threadA to come out holding a lock on 'foo', and
indeed it does hold a lock for a very short time. Unfortunately
when threadB does close(fd2) this releases the lock associated
with fd1. For the current libvirt use case for virFileLock -
pidfiles - this doesn't matter since the lock is acquired
at startup while single threaded an never released until
exit.
To provide a more generally useful API though, it is neccessary
to introduce a slightly higher level abstraction, which is to
be referred to as a "lockspace". This is to be provided by
a virLockSpacePtr object in src/util/virlockspace.{c,h}. The
core idea is that the lockspace keeps track of what files are
already open+locked. This means that when a 2nd thread comes
along and tries to acquire a lock, it doesn't end up opening
and closing a new FD. The lockspace just checks the current
list of held locks and immediately returns VIR_ERR_RESOURCE_BUSY.
NB, the API as it stands is designed on the basis that the
files being locked are not being otherwise opened and used
by the application code. ie the files which are used to
maintain the locks are not the files associated with the
resources themselves. One approach to using this API is to
acquire locks based on a hash of the filepath.
eg to lock /var/lib/libvirt/images/foo.img the application
might do
virLockSpacePtr lockspace = virLockSpaceNew("/var/lib/libvirt/imagelocks");
lockname = md5sum("/var/lib/libvirt/images/foo.img")
virLockSpaceAcquireLock(lockspace, lockname)
This patch is the basis for the soon to be re-submitted
patch series providing a virtlockd daemon
---
.gitignore | 1 +
include/libvirt/virterror.h | 2 +
src/Makefile.am | 1 +
src/libvirt_private.syms | 9 +
src/util/virlockspace.c | 419 ++++++++++++++++++++++++++++++++++++++++++++
src/util/virlockspace.h | 51 ++++++
src/util/virterror.c | 9 +-
tests/Makefile.am | 7 +-
tests/virlockspacetest.c | 311 ++++++++++++++++++++++++++++++++
9 files changed, 808 insertions(+), 2 deletions(-)
create mode 100644 src/util/virlockspace.c
create mode 100644 src/util/virlockspace.h
create mode 100644 tests/virlockspacetest.c
diff --git a/.gitignore b/.gitignore
index 5ea281a..9e566c4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -157,6 +157,7 @@
/tests/virdrivermoduletest
/tests/virhashtest
/tests/virkeyfiletest
+/tests/virlockspacetest
/tests/virnet*test
/tests/virshtest
/tests/virtimetest
diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h
index ad8e101..3e72cb7 100644
--- a/include/libvirt/virterror.h
+++ b/include/libvirt/virterror.h
@@ -110,6 +110,7 @@ typedef enum {
VIR_FROM_AUTH = 46, /* Error from auth handling */
VIR_FROM_DBUS = 47, /* Error from DBus */
VIR_FROM_PARALLELS = 48, /* Error from Parallels */
+ VIR_FROM_LOCKSPACE = 49, /* Error from lockspace */
# ifdef VIR_ENUM_SENTINELS
VIR_ERR_DOMAIN_LAST
@@ -277,6 +278,7 @@ typedef enum {
VIR_ERR_MIGRATE_UNSAFE = 81, /* Migration is not safe */
VIR_ERR_OVERFLOW = 82, /* integer overflow */
VIR_ERR_BLOCK_COPY_ACTIVE = 83, /* action prevented by block copy job */
+ VIR_ERR_RESOURCE_BUSY = 84, /* resource is already in use */
} virErrorNumber;
/**
diff --git a/src/Makefile.am b/src/Makefile.am
index b48ce65..527a2b8 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -95,6 +95,7 @@ UTIL_SOURCES = \
util/virkeycode.c util/virkeycode.h \
util/virkeyfile.c util/virkeyfile.h \
util/virkeymaps.h \
+ util/virlockspace.c util/virlockspace.h \
util/virmacaddr.h util/virmacaddr.c \
util/virnetdev.h util/virnetdev.c \
util/virnetdevbandwidth.h util/virnetdevbandwidth.c \
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index ac392fe..69f021d 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1248,6 +1248,15 @@ virKeyFileHasGroup;
virKeyFileGetValueString;
+# virlockspace.h
+virLockSpaceNew;
+virLockSpaceFree;
+virLockSpaceCreateResource;
+virLockSpaceDeleteResource;
+virLockSpaceAcquireResource;
+virLockSpaceReleaseResource;
+
+
# virmacaddr.h
virMacAddrCmp;
virMacAddrCmpRaw;
diff --git a/src/util/virlockspace.c b/src/util/virlockspace.c
new file mode 100644
index 0000000..727036b
--- /dev/null
+++ b/src/util/virlockspace.c
@@ -0,0 +1,419 @@
+/*
+ * virlockspace.c: simple file based lockspaces
+ *
+ * Copyright (C) 2012 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, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <config.h>
+
+#include "virlockspace.h"
+#include "logging.h"
+#include "memory.h"
+#include "virterror_internal.h"
+#include "util.h"
+#include "virfile.h"
+#include "virhash.h"
+#include "threads.h"
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#define VIR_FROM_THIS VIR_FROM_LOCKSPACE
+
+typedef struct _virLockSpaceResource virLockSpaceResource;
+typedef virLockSpaceResource *virLockSpaceResourcePtr;
+
+struct _virLockSpaceResource {
+ char *name;
+ char *path;
+ int fd;
+ int flags;
+ unsigned int holdCount;
+};
+
+struct _virLockSpace {
+ char *dir;
+ virMutex lock;
+
+ virHashTablePtr resources;
+};
+
+
+static char *virLockSpaceGetResourcePath(virLockSpacePtr lockspace,
+ const char *resname)
+{
+ char *ret;
+ if (virAsprintf(&ret, "%s/%s", lockspace->dir, resname) < 0) {
+ virReportOOMError();
+ return NULL;
+ }
+ return ret;
+}
+
+
+static void virLockSpaceResourceFree(virLockSpaceResourcePtr res)
+{
+ if (!res)
+ return;
+
+ if (res->holdCount &&
+ (res->flags & VIR_LOCK_SPACE_ACQUIRE_AUTOCREATE)) {
+ if (res->flags & VIR_LOCK_SPACE_ACQUIRE_SHARED) {
+ /* We must upgrade to an exclusive lock to ensure
+ * no one else still has it before trying to delete */
+ if (virFileLock(res->fd, false, 0, 1) < 0) {
+ VIR_DEBUG("Could not upgrade shared lease to exclusive, not deleting");
+ } else {
+ unlink(res->path);
+ }
+ } else {
+ unlink(res->path);
+ }
+ }
+
+ VIR_FORCE_CLOSE(res->fd);
+ VIR_FREE(res->path);
+ VIR_FREE(res->name);
+ VIR_FREE(res);
+}
+
+
+static virLockSpaceResourcePtr
+virLockSpaceResourceNew(virLockSpacePtr lockspace,
+ const char *resname,
+ unsigned int flags)
+{
+ virLockSpaceResourcePtr res;
+ bool shared = !!(flags & VIR_LOCK_SPACE_ACQUIRE_SHARED);
+
+ if (VIR_ALLOC(res) < 0)
+ return NULL;
+
+ res->fd = -1;
+ res->flags = flags;
+
+ if (!(res->name = strdup(resname)))
+ goto no_memory;
+
+ if (!(res->path = virLockSpaceGetResourcePath(lockspace, resname)))
+ goto no_memory;
+
+ if (flags & VIR_LOCK_SPACE_ACQUIRE_AUTOCREATE) {
+ while (1) {
+ struct stat a, b;
+ if ((res->fd = open(res->path, O_RDWR|O_CREAT, 0600)) < 0) {
+ virReportSystemError(errno,
+ _("Unable to open/create resource %s"),
+ res->path);
+ goto error;
+ }
+
+ if (virSetCloseExec(res->fd) < 0) {
+ virReportSystemError(errno,
+ _("Failed to set close-on-exec flag '%s'"),
+ res->path);
+ goto error;
+ }
+
+ if (fstat(res->fd, &b) < 0) {
+ virReportSystemError(errno,
+ _("Unable to check status of pid file '%s'"),
+ res->path);
+ goto error;
+ }
+
+ if (virFileLock(res->fd, shared, 0, 1) < 0) {
+ if (errno == EACCES || errno == EAGAIN) {
+ virReportError(VIR_ERR_RESOURCE_BUSY,
+ _("Lockspace resource '%s' is locked"),
+ resname);
+ } else {
+ virReportSystemError(errno,
+ _("Unable to acquire lock on '%s'"),
+ res->path);
+ }
+ goto error;
+ }
+
+ /* Now make sure the pidfile we locked is the same
+ * one that now exists on the filesystem
+ */
+ if (stat(res->path, &a) < 0) {
+ char ebuf[1024] ATTRIBUTE_UNUSED;
+ VIR_DEBUG("Resource '%s' disappeared: %s",
+ res->path, virStrerror(errno, ebuf, sizeof(ebuf)));
+ VIR_FORCE_CLOSE(res->fd);
+ /* Someone else must be racing with us, so try agin */
+ continue;
+ }
+
+ if (a.st_ino == b.st_ino)
+ break;
+
+ VIR_DEBUG("Resource '%s' was recreated", res->path);
+ VIR_FORCE_CLOSE(res->fd);
+ /* Someone else must be racing with us, so try agin */
+ }
+ } else {
+ if ((res->fd = open(res->path, O_RDWR)) < 0) {
+ virReportSystemError(errno,
+ _("Unable to open resource %s"),
+ res->path);
+ goto error;
+ }
+
+ if (virSetCloseExec(res->fd) < 0) {
+ virReportSystemError(errno,
+ _("Failed to set close-on-exec flag '%s'"),
+ res->path);
+ goto error;
+ }
+
+ if (virFileLock(res->fd, !!(flags & VIR_LOCK_SPACE_ACQUIRE_SHARED), 0, 0) < 0) {
+ if (errno == EACCES || errno == EAGAIN) {
+ virReportError(VIR_ERR_RESOURCE_BUSY,
+ _("Lockspace resource '%s' is locked"),
+ resname);
+ } else {
+ virReportSystemError(errno,
+ _("Unable to acquire lock on '%s'"),
+ res->path);
+ }
+ goto error;
+ }
+ }
+ res->holdCount = 1;
+
+ return res;
+
+no_memory:
+ virReportOOMError();
+error:
+ virLockSpaceResourceFree(res);
+ return NULL;
+}
+
+
+static void virLockSpaceResourceDataFree(void *opaque, const void *name ATTRIBUTE_UNUSED)
+{
+ virLockSpaceResourcePtr res = opaque;
+ virLockSpaceResourceFree(res);
+}
+
+
+virLockSpacePtr virLockSpaceNew(const char *directory)
+{
+ virLockSpacePtr lockspace;
+
+ if (VIR_ALLOC(lockspace) < 0)
+ return NULL;
+
+ if (virMutexInit(&lockspace->lock) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Unable to initialize lockspace mutex"));
+ VIR_FREE(lockspace);
+ return NULL;
+ }
+
+ if (!(lockspace->dir = strdup(directory)))
+ goto no_memory;
+
+ if (!(lockspace->resources = virHashCreate(10,
+ virLockSpaceResourceDataFree)))
+ goto error;
+
+ if (virFileExists(directory)) {
+ if (!virFileIsDir(directory)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Lockspace location %s exists, but is not a directory"),
+ directory);
+ goto error;
+ }
+ } else {
+ if (virFileMakePathWithMode(directory, 0700) < 0) {
+ virReportSystemError(errno,
+ _("Unable to create lockspace %s"),
+ directory);
+ goto error;
+ }
+ }
+
+ return lockspace;
+
+no_memory:
+ virReportOOMError();
+error:
+ virLockSpaceFree(lockspace);
+ return NULL;
+}
+
+
+void virLockSpaceFree(virLockSpacePtr lockspace)
+{
+ if (!lockspace)
+ return;
+
+ virHashFree(lockspace->resources);
+ VIR_FREE(lockspace->dir);
+ virMutexDestroy(&lockspace->lock);
+ VIR_FREE(lockspace);
+}
+
+
+int virLockSpaceCreateResource(virLockSpacePtr lockspace,
+ const char *resname)
+{
+ int ret = -1;
+ char *respath = NULL;
+ virLockSpaceResourcePtr res;
+
+ VIR_DEBUG("lockspace=%p resname=%s", lockspace, resname);
+
+ virMutexLock(&lockspace->lock);
+
+ if ((res = virHashLookup(lockspace->resources, resname))) {
+ virReportError(VIR_ERR_RESOURCE_BUSY,
+ _("Lockspace resource '%s' is locked"),
+ resname);
+ goto cleanup;
+ }
+
+ if (!(respath = virLockSpaceGetResourcePath(lockspace, resname)))
+ goto cleanup;
+
+ if (virFileTouch(respath, 0600) < 0)
+ goto cleanup;
+
+ ret = 0;
+
+cleanup:
+ virMutexUnlock(&lockspace->lock);
+ VIR_FREE(respath);
+ return ret;
+}
+
+
+int virLockSpaceDeleteResource(virLockSpacePtr lockspace,
+ const char *resname)
+{
+ int ret = -1;
+ char *respath = NULL;
+ virLockSpaceResourcePtr res;
+
+ VIR_DEBUG("lockspace=%p resname=%s", lockspace, resname);
+
+ virMutexLock(&lockspace->lock);
+
+ if ((res = virHashLookup(lockspace->resources, resname))) {
+ virReportError(VIR_ERR_RESOURCE_BUSY,
+ _("Lockspace resource '%s' is locked"),
+ resname);
+ goto cleanup;
+ }
+
+ if (!(respath = virLockSpaceGetResourcePath(lockspace, resname)))
+ goto cleanup;
+
+ if (unlink(respath) < 0 &&
+ errno != ENOENT) {
+ virReportSystemError(errno,
+ _("Unable to delete lockspace resource %s"),
+ respath);
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+ virMutexUnlock(&lockspace->lock);
+ VIR_FREE(respath);
+ return ret;
+}
+
+
+int virLockSpaceAcquireResource(virLockSpacePtr lockspace,
+ const char *resname,
+ unsigned int flags)
+{
+ int ret = -1;
+ virLockSpaceResourcePtr res;
+
+ VIR_DEBUG("lockspace=%p resname=%s flags=%x", lockspace, resname, flags);
+
+ virMutexLock(&lockspace->lock);
+
+ if ((res = virHashLookup(lockspace->resources, resname))) {
+ if ((res->flags & VIR_LOCK_SPACE_ACQUIRE_SHARED) &&
+ (flags & VIR_LOCK_SPACE_ACQUIRE_SHARED)) {
+ res->holdCount++;
+ goto done;
+ }
+ virReportError(VIR_ERR_RESOURCE_BUSY,
+ _("Lockspace resource '%s' is locked"),
+ resname);
+ goto cleanup;
+ }
+
+ if (!(res = virLockSpaceResourceNew(lockspace, resname, flags)))
+ goto cleanup;
+
+ if (virHashAddEntry(lockspace->resources, resname, res) < 0) {
+ virLockSpaceResourceFree(res);
+ goto cleanup;
+ }
+
+done:
+ ret = 0;
+
+cleanup:
+ virMutexUnlock(&lockspace->lock);
+ return ret;
+}
+
+
+int virLockSpaceReleaseResource(virLockSpacePtr lockspace,
+ const char *resname)
+{
+ int ret = -1;
+ virLockSpaceResourcePtr res;
+
+ VIR_DEBUG("lockspace=%p resname=%s", lockspace, resname);
+
+ virMutexLock(&lockspace->lock);
+
+ if (!(res = virHashLookup(lockspace->resources, resname))) {
+ virReportError(VIR_ERR_RESOURCE_BUSY,
+ _("Lockspace resource '%s' is not locked"),
+ resname);
+ goto cleanup;
+ }
+
+ if (res->holdCount == 1) {
+ if (virHashRemoveEntry(lockspace->resources, resname) < 0)
+ goto cleanup;
+ } else {
+ res->holdCount--;
+ }
+
+ ret = 0;
+
+cleanup:
+ virMutexUnlock(&lockspace->lock);
+ return ret;
+}
diff --git a/src/util/virlockspace.h b/src/util/virlockspace.h
new file mode 100644
index 0000000..6d91728
--- /dev/null
+++ b/src/util/virlockspace.h
@@ -0,0 +1,51 @@
+/*
+ * virlockspace.h: simple file based lockspaces
+ *
+ * Copyright (C) 2012 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, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __VIR_LOCK_SPACE_H__
+# define __VIR_LOCK_SPACE_H__
+
+#include "internal.h"
+
+typedef struct _virLockSpace virLockSpace;
+typedef virLockSpace *virLockSpacePtr;
+
+virLockSpacePtr virLockSpaceNew(const char *directory);
+
+void virLockSpaceFree(virLockSpacePtr lockspace);
+
+int virLockSpaceCreateResource(virLockSpacePtr lockspace,
+ const char *resname);
+int virLockSpaceDeleteResource(virLockSpacePtr lockspace,
+ const char *resname);
+
+typedef enum {
+ VIR_LOCK_SPACE_ACQUIRE_SHARED = (1 << 0),
+ VIR_LOCK_SPACE_ACQUIRE_AUTOCREATE = (1 << 1),
+} virLockSpaceAcquireFlags;
+
+int virLockSpaceAcquireResource(virLockSpacePtr lockspace,
+ const char *resname,
+ unsigned int flags);
+
+int virLockSpaceReleaseResource(virLockSpacePtr lockspace,
+ const char *resname);
+
+#endif /* __VIR_LOCK_SPACE_H__ */
diff --git a/src/util/virterror.c b/src/util/virterror.c
index a40cfe0..74f511a 100644
--- a/src/util/virterror.c
+++ b/src/util/virterror.c
@@ -112,7 +112,8 @@ VIR_ENUM_IMPL(virErrorDomain, VIR_ERR_DOMAIN_LAST,
"URI Utils", /* 45 */
"Authentication Utils",
"DBus Utils",
- "Parallels Cloud Server"
+ "Parallels Cloud Server",
+ "Lock Space",
)
@@ -1185,6 +1186,12 @@ virErrorMsg(virErrorNumber error, const char *info)
else
errmsg = _("block copy still active: %s");
break;
+ case VIR_ERR_RESOURCE_BUSY:
+ if (info == NULL)
+ errmsg = _("resource busy");
+ else
+ errmsg = _("resource busy %s");
+ break;
}
return errmsg;
}
diff --git a/tests/Makefile.am b/tests/Makefile.am
index b931cea..8ca6441 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -91,7 +91,7 @@ test_programs = virshtest sockettest \
virhashtest virnetmessagetest virnetsockettest \
utiltest virnettlscontexttest shunloadtest \
virtimetest viruritest virkeyfiletest \
- virauthconfigtest
+ virauthconfigtest virlockspacetest
if WITH_DRIVER_MODULES
test_programs += virdrivermoduletest
@@ -503,6 +503,11 @@ virtimetest_SOURCES = \
virtimetest_CFLAGS = -Dabs_builddir="\"$(abs_builddir)\"" $(AM_CFLAGS)
virtimetest_LDADD = $(LDADDS)
+virlockspacetest_SOURCES = \
+ virlockspacetest.c testutils.h testutils.c
+virlockspacetest_CFLAGS = -Dabs_builddir="\"$(abs_builddir)\"" $(AM_CFLAGS)
+virlockspacetest_LDADD = $(LDADDS)
+
viruritest_SOURCES = \
viruritest.c testutils.h testutils.c
viruritest_CFLAGS = -Dabs_builddir="\"$(abs_builddir)\"" $(AM_CFLAGS)
diff --git a/tests/virlockspacetest.c b/tests/virlockspacetest.c
new file mode 100644
index 0000000..37175cb
--- /dev/null
+++ b/tests/virlockspacetest.c
@@ -0,0 +1,311 @@
+/*
+ * Copyright (C) 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, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Author: Daniel P. Berrange <berrange(a)redhat.com>
+ */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <signal.h>
+
+#include "testutils.h"
+#include "util.h"
+#include "virterror_internal.h"
+#include "memory.h"
+#include "logging.h"
+
+#include "virlockspace.h"
+
+#define VIR_FROM_THIS VIR_FROM_RPC
+
+#define LOCKSPACE_DIR abs_builddir "/virlockspacedata"
+
+static int testLockSpaceCreate(const void *args ATTRIBUTE_UNUSED)
+{
+ virLockSpacePtr lockspace;
+ int ret = -1;
+
+ rmdir(LOCKSPACE_DIR);
+
+ lockspace = virLockSpaceNew(LOCKSPACE_DIR);
+
+ if (!virFileIsDir(LOCKSPACE_DIR))
+ goto cleanup;
+
+ ret = 0;
+
+cleanup:
+ virLockSpaceFree(lockspace);
+ rmdir(LOCKSPACE_DIR);
+ return ret;
+}
+
+
+static int testLockSpaceResourceLifecycle(const void *args ATTRIBUTE_UNUSED)
+{
+ virLockSpacePtr lockspace;
+ int ret = -1;
+
+ unlink(LOCKSPACE_DIR);
+
+ lockspace = virLockSpaceNew(LOCKSPACE_DIR);
+
+ if (!virFileIsDir(LOCKSPACE_DIR))
+ goto cleanup;
+
+ if (virLockSpaceCreateResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (!virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ if (virLockSpaceDeleteResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ ret = 0;
+
+cleanup:
+ virLockSpaceFree(lockspace);
+ rmdir(LOCKSPACE_DIR);
+ return ret;
+}
+
+
+static int testLockSpaceResourceLockExcl(const void *args ATTRIBUTE_UNUSED)
+{
+ virLockSpacePtr lockspace;
+ int ret = -1;
+
+ unlink(LOCKSPACE_DIR);
+
+ lockspace = virLockSpaceNew(LOCKSPACE_DIR);
+
+ if (!virFileIsDir(LOCKSPACE_DIR))
+ goto cleanup;
+
+ if (virLockSpaceCreateResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virLockSpaceAcquireResource(lockspace, "foo", 0) < 0)
+ goto cleanup;
+
+ if (!virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ if (virLockSpaceAcquireResource(lockspace, "foo", 0) == 0)
+ goto cleanup;
+
+ if (virLockSpaceDeleteResource(lockspace, "foo") == 0)
+ goto cleanup;
+
+ if (virLockSpaceReleaseResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virLockSpaceDeleteResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ ret = 0;
+
+cleanup:
+ virLockSpaceFree(lockspace);
+ rmdir(LOCKSPACE_DIR);
+ return ret;
+}
+
+
+static int testLockSpaceResourceLockExclAuto(const void *args ATTRIBUTE_UNUSED)
+{
+ virLockSpacePtr lockspace;
+ int ret = -1;
+
+ unlink(LOCKSPACE_DIR);
+
+ lockspace = virLockSpaceNew(LOCKSPACE_DIR);
+
+ if (!virFileIsDir(LOCKSPACE_DIR))
+ goto cleanup;
+
+ if (virLockSpaceCreateResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virLockSpaceAcquireResource(lockspace, "foo", VIR_LOCK_SPACE_ACQUIRE_AUTOCREATE) < 0)
+ goto cleanup;
+
+ if (!virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ if (virLockSpaceReleaseResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ ret = 0;
+
+cleanup:
+ virLockSpaceFree(lockspace);
+ rmdir(LOCKSPACE_DIR);
+ return ret;
+}
+
+
+static int testLockSpaceResourceLockShr(const void *args ATTRIBUTE_UNUSED)
+{
+ virLockSpacePtr lockspace;
+ int ret = -1;
+
+ unlink(LOCKSPACE_DIR);
+
+ lockspace = virLockSpaceNew(LOCKSPACE_DIR);
+
+ if (!virFileIsDir(LOCKSPACE_DIR))
+ goto cleanup;
+
+ if (virLockSpaceCreateResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virLockSpaceAcquireResource(lockspace, "foo", VIR_LOCK_SPACE_ACQUIRE_SHARED) < 0)
+ goto cleanup;
+
+ if (virLockSpaceAcquireResource(lockspace, "foo", 0) == 0)
+ goto cleanup;
+
+ if (virLockSpaceAcquireResource(lockspace, "foo", VIR_LOCK_SPACE_ACQUIRE_SHARED) < 0)
+ goto cleanup;
+
+ if (virLockSpaceDeleteResource(lockspace, "foo") == 0)
+ goto cleanup;
+
+ if (virLockSpaceReleaseResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virLockSpaceDeleteResource(lockspace, "foo") == 0)
+ goto cleanup;
+
+ if (virLockSpaceReleaseResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virLockSpaceDeleteResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ ret = 0;
+
+cleanup:
+ virLockSpaceFree(lockspace);
+ rmdir(LOCKSPACE_DIR);
+ return ret;
+}
+
+
+static int testLockSpaceResourceLockShrAuto(const void *args ATTRIBUTE_UNUSED)
+{
+ virLockSpacePtr lockspace;
+ int ret = -1;
+
+ unlink(LOCKSPACE_DIR);
+
+ lockspace = virLockSpaceNew(LOCKSPACE_DIR);
+
+ if (!virFileIsDir(LOCKSPACE_DIR))
+ goto cleanup;
+
+ if (virLockSpaceCreateResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virLockSpaceAcquireResource(lockspace, "foo",
+ VIR_LOCK_SPACE_ACQUIRE_SHARED |
+ VIR_LOCK_SPACE_ACQUIRE_AUTOCREATE) < 0)
+ goto cleanup;
+
+ if (!virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ if (virLockSpaceAcquireResource(lockspace, "foo",
+ VIR_LOCK_SPACE_ACQUIRE_AUTOCREATE) == 0)
+ goto cleanup;
+
+ if (!virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ if (virLockSpaceAcquireResource(lockspace, "foo",
+ VIR_LOCK_SPACE_ACQUIRE_SHARED |
+ VIR_LOCK_SPACE_ACQUIRE_AUTOCREATE) < 0)
+ goto cleanup;
+
+ if (!virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ if (virLockSpaceReleaseResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (!virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ if (virLockSpaceReleaseResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ ret = 0;
+
+cleanup:
+ virLockSpaceFree(lockspace);
+ rmdir(LOCKSPACE_DIR);
+ return ret;
+}
+
+
+static int
+mymain(void)
+{
+ int ret = 0;
+
+ signal(SIGPIPE, SIG_IGN);
+
+ if (virtTestRun("Lockspace creation", 1, testLockSpaceCreate, NULL) < 0)
+ ret = -1;
+
+ if (virtTestRun("Lockspace res lifecycle", 1, testLockSpaceResourceLifecycle, NULL) < 0)
+ ret = -1;
+
+ if (virtTestRun("Lockspace res lock excl", 1, testLockSpaceResourceLockExcl, NULL) < 0)
+ ret = -1;
+
+ if (virtTestRun("Lockspace res lock shr", 1, testLockSpaceResourceLockShr, NULL) < 0)
+ ret = -1;
+
+ if (virtTestRun("Lockspace res lock excl auto", 1, testLockSpaceResourceLockExclAuto, NULL) < 0)
+ ret = -1;
+
+ if (virtTestRun("Lockspace res lock shr auto", 1, testLockSpaceResourceLockShrAuto, NULL) < 0)
+ ret = -1;
+
+ return ret==0 ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+VIRT_TEST_MAIN(mymain)
--
1.7.11.2
12 years, 3 months
[libvirt] [PATCH v2] Introduce an internal API for handling file based lockspaces
by Daniel P. Berrange
From: "Daniel P. Berrange" <berrange(a)redhat.com>
The previously introduced virFile{Lock,Unlock} APIs provide a
way to acquire/release fcntl() locks on individual files. For
unknown reason though, the POSIX spec says that fcntl() locks
are released when *any* file handle refering to the same path
is closed. In the following sequence
threadA: fd1 = open("foo")
threadB: fd2 = open("foo")
threadA: virFileLock(fd1)
threadB: virFileLock(fd2)
threadB: close(fd2)
you'd expect threadA to come out holding a lock on 'foo', and
indeed it does hold a lock for a very short time. Unfortunately
when threadB does close(fd2) this releases the lock associated
with fd1. For the current libvirt use case for virFileLock -
pidfiles - this doesn't matter since the lock is acquired
at startup while single threaded an never released until
exit.
To provide a more generally useful API though, it is neccessary
to introduce a slightly higher level abstraction, which is to
be referred to as a "lockspace". This is to be provided by
a virLockSpacePtr object in src/util/virlockspace.{c,h}. The
core idea is that the lockspace keeps track of what files are
already open+locked. This means that when a 2nd thread comes
along and tries to acquire a lock, it doesn't end up opening
and closing a new FD. The lockspace just checks the current
list of held locks and immediately returns VIR_ERR_RESOURCE_BUSY.
NB, the API as it stands is designed on the basis that the
files being locked are not being otherwise opened and used
by the application code. One approach to using this API is to
acquire locks based on a hash of the filepath.
eg to lock /var/lib/libvirt/images/foo.img the application
might do
virLockSpacePtr lockspace = virLockSpaceNew("/var/lib/libvirt/imagelocks");
lockname = md5sum("/var/lib/libvirt/images/foo.img")
virLockSpaceAcquireLock(lockspace, lockname)
It is also possible to do locks directly on resources by
using a NULL lockspace directory and then using the file
path as the lock name eg
virLockSpacePtr lockspace = virLockSpaceNew(NULL)
virLockSpaceAcquireLock(lockspace, "/var/lib/libvirt/images/foo.img")
This is only safe todo though if no other part of the proces
will be opening the files. This will be the case when this
code is used inside the soon-to-be-reposted virlockd daemon
---
.gitignore | 1 +
include/libvirt/virterror.h | 2 +
src/Makefile.am | 1 +
src/libvirt_private.syms | 9 +
src/util/virlockspace.c | 430 ++++++++++++++++++++++++++++++++++++++++++++
src/util/virlockspace.h | 51 ++++++
src/util/virterror.c | 9 +-
tests/Makefile.am | 7 +-
tests/virlockspacetest.c | 360 +++++++++++++++++++++++++++++++++++++
9 files changed, 868 insertions(+), 2 deletions(-)
create mode 100644 src/util/virlockspace.c
create mode 100644 src/util/virlockspace.h
create mode 100644 tests/virlockspacetest.c
diff --git a/.gitignore b/.gitignore
index 5ea281a..9e566c4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -157,6 +157,7 @@
/tests/virdrivermoduletest
/tests/virhashtest
/tests/virkeyfiletest
+/tests/virlockspacetest
/tests/virnet*test
/tests/virshtest
/tests/virtimetest
diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h
index ad8e101..3e72cb7 100644
--- a/include/libvirt/virterror.h
+++ b/include/libvirt/virterror.h
@@ -110,6 +110,7 @@ typedef enum {
VIR_FROM_AUTH = 46, /* Error from auth handling */
VIR_FROM_DBUS = 47, /* Error from DBus */
VIR_FROM_PARALLELS = 48, /* Error from Parallels */
+ VIR_FROM_LOCKSPACE = 49, /* Error from lockspace */
# ifdef VIR_ENUM_SENTINELS
VIR_ERR_DOMAIN_LAST
@@ -277,6 +278,7 @@ typedef enum {
VIR_ERR_MIGRATE_UNSAFE = 81, /* Migration is not safe */
VIR_ERR_OVERFLOW = 82, /* integer overflow */
VIR_ERR_BLOCK_COPY_ACTIVE = 83, /* action prevented by block copy job */
+ VIR_ERR_RESOURCE_BUSY = 84, /* resource is already in use */
} virErrorNumber;
/**
diff --git a/src/Makefile.am b/src/Makefile.am
index b48ce65..527a2b8 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -95,6 +95,7 @@ UTIL_SOURCES = \
util/virkeycode.c util/virkeycode.h \
util/virkeyfile.c util/virkeyfile.h \
util/virkeymaps.h \
+ util/virlockspace.c util/virlockspace.h \
util/virmacaddr.h util/virmacaddr.c \
util/virnetdev.h util/virnetdev.c \
util/virnetdevbandwidth.h util/virnetdevbandwidth.c \
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index ac392fe..69f021d 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1248,6 +1248,15 @@ virKeyFileHasGroup;
virKeyFileGetValueString;
+# virlockspace.h
+virLockSpaceNew;
+virLockSpaceFree;
+virLockSpaceCreateResource;
+virLockSpaceDeleteResource;
+virLockSpaceAcquireResource;
+virLockSpaceReleaseResource;
+
+
# virmacaddr.h
virMacAddrCmp;
virMacAddrCmpRaw;
diff --git a/src/util/virlockspace.c b/src/util/virlockspace.c
new file mode 100644
index 0000000..adc3170
--- /dev/null
+++ b/src/util/virlockspace.c
@@ -0,0 +1,430 @@
+/*
+ * virlockspace.c: simple file based lockspaces
+ *
+ * Copyright (C) 2012 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, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <config.h>
+
+#include "virlockspace.h"
+#include "logging.h"
+#include "memory.h"
+#include "virterror_internal.h"
+#include "util.h"
+#include "virfile.h"
+#include "virhash.h"
+#include "threads.h"
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#define VIR_FROM_THIS VIR_FROM_LOCKSPACE
+
+typedef struct _virLockSpaceResource virLockSpaceResource;
+typedef virLockSpaceResource *virLockSpaceResourcePtr;
+
+struct _virLockSpaceResource {
+ char *name;
+ char *path;
+ int fd;
+ int flags;
+ unsigned int holdCount;
+};
+
+struct _virLockSpace {
+ char *dir;
+ virMutex lock;
+
+ virHashTablePtr resources;
+};
+
+
+static char *virLockSpaceGetResourcePath(virLockSpacePtr lockspace,
+ const char *resname)
+{
+ char *ret;
+ if (lockspace->dir) {
+ if (virAsprintf(&ret, "%s/%s", lockspace->dir, resname) < 0) {
+ virReportOOMError();
+ return NULL;
+ }
+ } else {
+ if (!(ret = strdup(resname))) {
+ virReportOOMError();
+ return NULL;
+ }
+ }
+
+ return ret;
+}
+
+
+static void virLockSpaceResourceFree(virLockSpaceResourcePtr res)
+{
+ if (!res)
+ return;
+
+ if (res->holdCount &&
+ (res->flags & VIR_LOCK_SPACE_ACQUIRE_AUTOCREATE)) {
+ if (res->flags & VIR_LOCK_SPACE_ACQUIRE_SHARED) {
+ /* We must upgrade to an exclusive lock to ensure
+ * no one else still has it before trying to delete */
+ if (virFileLock(res->fd, false, 0, 1) < 0) {
+ VIR_DEBUG("Could not upgrade shared lease to exclusive, not deleting");
+ } else {
+ unlink(res->path);
+ }
+ } else {
+ unlink(res->path);
+ }
+ }
+
+ VIR_FORCE_CLOSE(res->fd);
+ VIR_FREE(res->path);
+ VIR_FREE(res->name);
+ VIR_FREE(res);
+}
+
+
+static virLockSpaceResourcePtr
+virLockSpaceResourceNew(virLockSpacePtr lockspace,
+ const char *resname,
+ unsigned int flags)
+{
+ virLockSpaceResourcePtr res;
+ bool shared = !!(flags & VIR_LOCK_SPACE_ACQUIRE_SHARED);
+
+ if (VIR_ALLOC(res) < 0)
+ return NULL;
+
+ res->fd = -1;
+ res->flags = flags;
+
+ if (!(res->name = strdup(resname)))
+ goto no_memory;
+
+ if (!(res->path = virLockSpaceGetResourcePath(lockspace, resname)))
+ goto no_memory;
+
+ if (flags & VIR_LOCK_SPACE_ACQUIRE_AUTOCREATE) {
+ while (1) {
+ struct stat a, b;
+ if ((res->fd = open(res->path, O_RDWR|O_CREAT, 0600)) < 0) {
+ virReportSystemError(errno,
+ _("Unable to open/create resource %s"),
+ res->path);
+ goto error;
+ }
+
+ if (virSetCloseExec(res->fd) < 0) {
+ virReportSystemError(errno,
+ _("Failed to set close-on-exec flag '%s'"),
+ res->path);
+ goto error;
+ }
+
+ if (fstat(res->fd, &b) < 0) {
+ virReportSystemError(errno,
+ _("Unable to check status of pid file '%s'"),
+ res->path);
+ goto error;
+ }
+
+ if (virFileLock(res->fd, shared, 0, 1) < 0) {
+ if (errno == EACCES || errno == EAGAIN) {
+ virReportError(VIR_ERR_RESOURCE_BUSY,
+ _("Lockspace resource '%s' is locked"),
+ resname);
+ } else {
+ virReportSystemError(errno,
+ _("Unable to acquire lock on '%s'"),
+ res->path);
+ }
+ goto error;
+ }
+
+ /* Now make sure the pidfile we locked is the same
+ * one that now exists on the filesystem
+ */
+ if (stat(res->path, &a) < 0) {
+ char ebuf[1024] ATTRIBUTE_UNUSED;
+ VIR_DEBUG("Resource '%s' disappeared: %s",
+ res->path, virStrerror(errno, ebuf, sizeof(ebuf)));
+ VIR_FORCE_CLOSE(res->fd);
+ /* Someone else must be racing with us, so try agin */
+ continue;
+ }
+
+ if (a.st_ino == b.st_ino)
+ break;
+
+ VIR_DEBUG("Resource '%s' was recreated", res->path);
+ VIR_FORCE_CLOSE(res->fd);
+ /* Someone else must be racing with us, so try agin */
+ }
+ } else {
+ if ((res->fd = open(res->path, O_RDWR)) < 0) {
+ virReportSystemError(errno,
+ _("Unable to open resource %s"),
+ res->path);
+ goto error;
+ }
+
+ if (virSetCloseExec(res->fd) < 0) {
+ virReportSystemError(errno,
+ _("Failed to set close-on-exec flag '%s'"),
+ res->path);
+ goto error;
+ }
+
+ if (virFileLock(res->fd, !!(flags & VIR_LOCK_SPACE_ACQUIRE_SHARED), 0, 0) < 0) {
+ if (errno == EACCES || errno == EAGAIN) {
+ virReportError(VIR_ERR_RESOURCE_BUSY,
+ _("Lockspace resource '%s' is locked"),
+ resname);
+ } else {
+ virReportSystemError(errno,
+ _("Unable to acquire lock on '%s'"),
+ res->path);
+ }
+ goto error;
+ }
+ }
+ res->holdCount = 1;
+
+ return res;
+
+no_memory:
+ virReportOOMError();
+error:
+ virLockSpaceResourceFree(res);
+ return NULL;
+}
+
+
+static void virLockSpaceResourceDataFree(void *opaque, const void *name ATTRIBUTE_UNUSED)
+{
+ virLockSpaceResourcePtr res = opaque;
+ virLockSpaceResourceFree(res);
+}
+
+
+virLockSpacePtr virLockSpaceNew(const char *directory)
+{
+ virLockSpacePtr lockspace;
+
+ if (VIR_ALLOC(lockspace) < 0)
+ return NULL;
+
+ if (virMutexInit(&lockspace->lock) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Unable to initialize lockspace mutex"));
+ VIR_FREE(lockspace);
+ return NULL;
+ }
+
+ if (directory &&
+ !(lockspace->dir = strdup(directory)))
+ goto no_memory;
+
+ if (!(lockspace->resources = virHashCreate(10,
+ virLockSpaceResourceDataFree)))
+ goto error;
+
+ if (directory) {
+ if (virFileExists(directory)) {
+ if (!virFileIsDir(directory)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Lockspace location %s exists, but is not a directory"),
+ directory);
+ goto error;
+ }
+ } else {
+ if (virFileMakePathWithMode(directory, 0700) < 0) {
+ virReportSystemError(errno,
+ _("Unable to create lockspace %s"),
+ directory);
+ goto error;
+ }
+ }
+ }
+
+ return lockspace;
+
+no_memory:
+ virReportOOMError();
+error:
+ virLockSpaceFree(lockspace);
+ return NULL;
+}
+
+
+void virLockSpaceFree(virLockSpacePtr lockspace)
+{
+ if (!lockspace)
+ return;
+
+ virHashFree(lockspace->resources);
+ VIR_FREE(lockspace->dir);
+ virMutexDestroy(&lockspace->lock);
+ VIR_FREE(lockspace);
+}
+
+
+int virLockSpaceCreateResource(virLockSpacePtr lockspace,
+ const char *resname)
+{
+ int ret = -1;
+ char *respath = NULL;
+ virLockSpaceResourcePtr res;
+
+ VIR_DEBUG("lockspace=%p resname=%s", lockspace, resname);
+
+ virMutexLock(&lockspace->lock);
+
+ if ((res = virHashLookup(lockspace->resources, resname))) {
+ virReportError(VIR_ERR_RESOURCE_BUSY,
+ _("Lockspace resource '%s' is locked"),
+ resname);
+ goto cleanup;
+ }
+
+ if (!(respath = virLockSpaceGetResourcePath(lockspace, resname)))
+ goto cleanup;
+
+ if (virFileTouch(respath, 0600) < 0)
+ goto cleanup;
+
+ ret = 0;
+
+cleanup:
+ virMutexUnlock(&lockspace->lock);
+ VIR_FREE(respath);
+ return ret;
+}
+
+
+int virLockSpaceDeleteResource(virLockSpacePtr lockspace,
+ const char *resname)
+{
+ int ret = -1;
+ char *respath = NULL;
+ virLockSpaceResourcePtr res;
+
+ VIR_DEBUG("lockspace=%p resname=%s", lockspace, resname);
+
+ virMutexLock(&lockspace->lock);
+
+ if ((res = virHashLookup(lockspace->resources, resname))) {
+ virReportError(VIR_ERR_RESOURCE_BUSY,
+ _("Lockspace resource '%s' is locked"),
+ resname);
+ goto cleanup;
+ }
+
+ if (!(respath = virLockSpaceGetResourcePath(lockspace, resname)))
+ goto cleanup;
+
+ if (unlink(respath) < 0 &&
+ errno != ENOENT) {
+ virReportSystemError(errno,
+ _("Unable to delete lockspace resource %s"),
+ respath);
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+ virMutexUnlock(&lockspace->lock);
+ VIR_FREE(respath);
+ return ret;
+}
+
+
+int virLockSpaceAcquireResource(virLockSpacePtr lockspace,
+ const char *resname,
+ unsigned int flags)
+{
+ int ret = -1;
+ virLockSpaceResourcePtr res;
+
+ VIR_DEBUG("lockspace=%p resname=%s flags=%x", lockspace, resname, flags);
+
+ virMutexLock(&lockspace->lock);
+
+ if ((res = virHashLookup(lockspace->resources, resname))) {
+ if ((res->flags & VIR_LOCK_SPACE_ACQUIRE_SHARED) &&
+ (flags & VIR_LOCK_SPACE_ACQUIRE_SHARED)) {
+ res->holdCount++;
+ goto done;
+ }
+ virReportError(VIR_ERR_RESOURCE_BUSY,
+ _("Lockspace resource '%s' is locked"),
+ resname);
+ goto cleanup;
+ }
+
+ if (!(res = virLockSpaceResourceNew(lockspace, resname, flags)))
+ goto cleanup;
+
+ if (virHashAddEntry(lockspace->resources, resname, res) < 0) {
+ virLockSpaceResourceFree(res);
+ goto cleanup;
+ }
+
+done:
+ ret = 0;
+
+cleanup:
+ virMutexUnlock(&lockspace->lock);
+ return ret;
+}
+
+
+int virLockSpaceReleaseResource(virLockSpacePtr lockspace,
+ const char *resname)
+{
+ int ret = -1;
+ virLockSpaceResourcePtr res;
+
+ VIR_DEBUG("lockspace=%p resname=%s", lockspace, resname);
+
+ virMutexLock(&lockspace->lock);
+
+ if (!(res = virHashLookup(lockspace->resources, resname))) {
+ virReportError(VIR_ERR_RESOURCE_BUSY,
+ _("Lockspace resource '%s' is not locked"),
+ resname);
+ goto cleanup;
+ }
+
+ if (res->holdCount == 1) {
+ if (virHashRemoveEntry(lockspace->resources, resname) < 0)
+ goto cleanup;
+ } else {
+ res->holdCount--;
+ }
+
+ ret = 0;
+
+cleanup:
+ virMutexUnlock(&lockspace->lock);
+ return ret;
+}
diff --git a/src/util/virlockspace.h b/src/util/virlockspace.h
new file mode 100644
index 0000000..6d91728
--- /dev/null
+++ b/src/util/virlockspace.h
@@ -0,0 +1,51 @@
+/*
+ * virlockspace.h: simple file based lockspaces
+ *
+ * Copyright (C) 2012 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, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __VIR_LOCK_SPACE_H__
+# define __VIR_LOCK_SPACE_H__
+
+#include "internal.h"
+
+typedef struct _virLockSpace virLockSpace;
+typedef virLockSpace *virLockSpacePtr;
+
+virLockSpacePtr virLockSpaceNew(const char *directory);
+
+void virLockSpaceFree(virLockSpacePtr lockspace);
+
+int virLockSpaceCreateResource(virLockSpacePtr lockspace,
+ const char *resname);
+int virLockSpaceDeleteResource(virLockSpacePtr lockspace,
+ const char *resname);
+
+typedef enum {
+ VIR_LOCK_SPACE_ACQUIRE_SHARED = (1 << 0),
+ VIR_LOCK_SPACE_ACQUIRE_AUTOCREATE = (1 << 1),
+} virLockSpaceAcquireFlags;
+
+int virLockSpaceAcquireResource(virLockSpacePtr lockspace,
+ const char *resname,
+ unsigned int flags);
+
+int virLockSpaceReleaseResource(virLockSpacePtr lockspace,
+ const char *resname);
+
+#endif /* __VIR_LOCK_SPACE_H__ */
diff --git a/src/util/virterror.c b/src/util/virterror.c
index a40cfe0..74f511a 100644
--- a/src/util/virterror.c
+++ b/src/util/virterror.c
@@ -112,7 +112,8 @@ VIR_ENUM_IMPL(virErrorDomain, VIR_ERR_DOMAIN_LAST,
"URI Utils", /* 45 */
"Authentication Utils",
"DBus Utils",
- "Parallels Cloud Server"
+ "Parallels Cloud Server",
+ "Lock Space",
)
@@ -1185,6 +1186,12 @@ virErrorMsg(virErrorNumber error, const char *info)
else
errmsg = _("block copy still active: %s");
break;
+ case VIR_ERR_RESOURCE_BUSY:
+ if (info == NULL)
+ errmsg = _("resource busy");
+ else
+ errmsg = _("resource busy %s");
+ break;
}
return errmsg;
}
diff --git a/tests/Makefile.am b/tests/Makefile.am
index b931cea..8ca6441 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -91,7 +91,7 @@ test_programs = virshtest sockettest \
virhashtest virnetmessagetest virnetsockettest \
utiltest virnettlscontexttest shunloadtest \
virtimetest viruritest virkeyfiletest \
- virauthconfigtest
+ virauthconfigtest virlockspacetest
if WITH_DRIVER_MODULES
test_programs += virdrivermoduletest
@@ -503,6 +503,11 @@ virtimetest_SOURCES = \
virtimetest_CFLAGS = -Dabs_builddir="\"$(abs_builddir)\"" $(AM_CFLAGS)
virtimetest_LDADD = $(LDADDS)
+virlockspacetest_SOURCES = \
+ virlockspacetest.c testutils.h testutils.c
+virlockspacetest_CFLAGS = -Dabs_builddir="\"$(abs_builddir)\"" $(AM_CFLAGS)
+virlockspacetest_LDADD = $(LDADDS)
+
viruritest_SOURCES = \
viruritest.c testutils.h testutils.c
viruritest_CFLAGS = -Dabs_builddir="\"$(abs_builddir)\"" $(AM_CFLAGS)
diff --git a/tests/virlockspacetest.c b/tests/virlockspacetest.c
new file mode 100644
index 0000000..ea77ff5
--- /dev/null
+++ b/tests/virlockspacetest.c
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 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, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Author: Daniel P. Berrange <berrange(a)redhat.com>
+ */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/stat.h>
+
+#include "testutils.h"
+#include "util.h"
+#include "virterror_internal.h"
+#include "memory.h"
+#include "logging.h"
+
+#include "virlockspace.h"
+
+#define VIR_FROM_THIS VIR_FROM_RPC
+
+#define LOCKSPACE_DIR abs_builddir "/virlockspacedata"
+
+static int testLockSpaceCreate(const void *args ATTRIBUTE_UNUSED)
+{
+ virLockSpacePtr lockspace;
+ int ret = -1;
+
+ rmdir(LOCKSPACE_DIR);
+
+ lockspace = virLockSpaceNew(LOCKSPACE_DIR);
+
+ if (!virFileIsDir(LOCKSPACE_DIR))
+ goto cleanup;
+
+ ret = 0;
+
+cleanup:
+ virLockSpaceFree(lockspace);
+ rmdir(LOCKSPACE_DIR);
+ return ret;
+}
+
+
+static int testLockSpaceResourceLifecycle(const void *args ATTRIBUTE_UNUSED)
+{
+ virLockSpacePtr lockspace;
+ int ret = -1;
+
+ rmdir(LOCKSPACE_DIR);
+
+ lockspace = virLockSpaceNew(LOCKSPACE_DIR);
+
+ if (!virFileIsDir(LOCKSPACE_DIR))
+ goto cleanup;
+
+ if (virLockSpaceCreateResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (!virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ if (virLockSpaceDeleteResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ ret = 0;
+
+cleanup:
+ virLockSpaceFree(lockspace);
+ rmdir(LOCKSPACE_DIR);
+ return ret;
+}
+
+
+static int testLockSpaceResourceLockExcl(const void *args ATTRIBUTE_UNUSED)
+{
+ virLockSpacePtr lockspace;
+ int ret = -1;
+
+ rmdir(LOCKSPACE_DIR);
+
+ lockspace = virLockSpaceNew(LOCKSPACE_DIR);
+
+ if (!virFileIsDir(LOCKSPACE_DIR))
+ goto cleanup;
+
+ if (virLockSpaceCreateResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virLockSpaceAcquireResource(lockspace, "foo", 0) < 0)
+ goto cleanup;
+
+ if (!virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ if (virLockSpaceAcquireResource(lockspace, "foo", 0) == 0)
+ goto cleanup;
+
+ if (virLockSpaceDeleteResource(lockspace, "foo") == 0)
+ goto cleanup;
+
+ if (virLockSpaceReleaseResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virLockSpaceDeleteResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ ret = 0;
+
+cleanup:
+ virLockSpaceFree(lockspace);
+ rmdir(LOCKSPACE_DIR);
+ return ret;
+}
+
+
+static int testLockSpaceResourceLockExclAuto(const void *args ATTRIBUTE_UNUSED)
+{
+ virLockSpacePtr lockspace;
+ int ret = -1;
+
+ rmdir(LOCKSPACE_DIR);
+
+ lockspace = virLockSpaceNew(LOCKSPACE_DIR);
+
+ if (!virFileIsDir(LOCKSPACE_DIR))
+ goto cleanup;
+
+ if (virLockSpaceCreateResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virLockSpaceAcquireResource(lockspace, "foo", VIR_LOCK_SPACE_ACQUIRE_AUTOCREATE) < 0)
+ goto cleanup;
+
+ if (!virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ if (virLockSpaceReleaseResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ ret = 0;
+
+cleanup:
+ virLockSpaceFree(lockspace);
+ rmdir(LOCKSPACE_DIR);
+ return ret;
+}
+
+
+static int testLockSpaceResourceLockShr(const void *args ATTRIBUTE_UNUSED)
+{
+ virLockSpacePtr lockspace;
+ int ret = -1;
+
+ rmdir(LOCKSPACE_DIR);
+
+ lockspace = virLockSpaceNew(LOCKSPACE_DIR);
+
+ if (!virFileIsDir(LOCKSPACE_DIR))
+ goto cleanup;
+
+ if (virLockSpaceCreateResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virLockSpaceAcquireResource(lockspace, "foo", VIR_LOCK_SPACE_ACQUIRE_SHARED) < 0)
+ goto cleanup;
+
+ if (virLockSpaceAcquireResource(lockspace, "foo", 0) == 0)
+ goto cleanup;
+
+ if (virLockSpaceAcquireResource(lockspace, "foo", VIR_LOCK_SPACE_ACQUIRE_SHARED) < 0)
+ goto cleanup;
+
+ if (virLockSpaceDeleteResource(lockspace, "foo") == 0)
+ goto cleanup;
+
+ if (virLockSpaceReleaseResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virLockSpaceDeleteResource(lockspace, "foo") == 0)
+ goto cleanup;
+
+ if (virLockSpaceReleaseResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virLockSpaceDeleteResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ ret = 0;
+
+cleanup:
+ virLockSpaceFree(lockspace);
+ rmdir(LOCKSPACE_DIR);
+ return ret;
+}
+
+
+static int testLockSpaceResourceLockShrAuto(const void *args ATTRIBUTE_UNUSED)
+{
+ virLockSpacePtr lockspace;
+ int ret = -1;
+
+ rmdir(LOCKSPACE_DIR);
+
+ lockspace = virLockSpaceNew(LOCKSPACE_DIR);
+
+ if (!virFileIsDir(LOCKSPACE_DIR))
+ goto cleanup;
+
+ if (virLockSpaceCreateResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virLockSpaceAcquireResource(lockspace, "foo",
+ VIR_LOCK_SPACE_ACQUIRE_SHARED |
+ VIR_LOCK_SPACE_ACQUIRE_AUTOCREATE) < 0)
+ goto cleanup;
+
+ if (!virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ if (virLockSpaceAcquireResource(lockspace, "foo",
+ VIR_LOCK_SPACE_ACQUIRE_AUTOCREATE) == 0)
+ goto cleanup;
+
+ if (!virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ if (virLockSpaceAcquireResource(lockspace, "foo",
+ VIR_LOCK_SPACE_ACQUIRE_SHARED |
+ VIR_LOCK_SPACE_ACQUIRE_AUTOCREATE) < 0)
+ goto cleanup;
+
+ if (!virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ if (virLockSpaceReleaseResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (!virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ if (virLockSpaceReleaseResource(lockspace, "foo") < 0)
+ goto cleanup;
+
+ if (virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ ret = 0;
+
+cleanup:
+ virLockSpaceFree(lockspace);
+ rmdir(LOCKSPACE_DIR);
+ return ret;
+}
+
+
+static int testLockSpaceResourceLockPath(const void *args ATTRIBUTE_UNUSED)
+{
+ virLockSpacePtr lockspace;
+ int ret = -1;
+
+ rmdir(LOCKSPACE_DIR);
+
+ lockspace = virLockSpaceNew(NULL);
+
+ mkdir(LOCKSPACE_DIR, 0700);
+
+ if (virLockSpaceCreateResource(lockspace, LOCKSPACE_DIR "/foo") < 0)
+ goto cleanup;
+
+ if (virLockSpaceAcquireResource(lockspace, LOCKSPACE_DIR "/foo", 0) < 0)
+ goto cleanup;
+
+ if (!virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ if (virLockSpaceAcquireResource(lockspace, LOCKSPACE_DIR "/foo", 0) == 0)
+ goto cleanup;
+
+ if (virLockSpaceDeleteResource(lockspace, LOCKSPACE_DIR "/foo") == 0)
+ goto cleanup;
+
+ if (virLockSpaceReleaseResource(lockspace, LOCKSPACE_DIR "/foo") < 0)
+ goto cleanup;
+
+ if (virLockSpaceDeleteResource(lockspace, LOCKSPACE_DIR "/foo") < 0)
+ goto cleanup;
+
+ if (virFileExists(LOCKSPACE_DIR "/foo"))
+ goto cleanup;
+
+ ret = 0;
+
+cleanup:
+ virLockSpaceFree(lockspace);
+ rmdir(LOCKSPACE_DIR);
+ return ret;
+}
+
+
+
+static int
+mymain(void)
+{
+ int ret = 0;
+
+ signal(SIGPIPE, SIG_IGN);
+
+ if (virtTestRun("Lockspace creation", 1, testLockSpaceCreate, NULL) < 0)
+ ret = -1;
+
+ if (virtTestRun("Lockspace res lifecycle", 1, testLockSpaceResourceLifecycle, NULL) < 0)
+ ret = -1;
+
+ if (virtTestRun("Lockspace res lock excl", 1, testLockSpaceResourceLockExcl, NULL) < 0)
+ ret = -1;
+
+ if (virtTestRun("Lockspace res lock shr", 1, testLockSpaceResourceLockShr, NULL) < 0)
+ ret = -1;
+
+ if (virtTestRun("Lockspace res lock excl auto", 1, testLockSpaceResourceLockExclAuto, NULL) < 0)
+ ret = -1;
+
+ if (virtTestRun("Lockspace res lock shr auto", 1, testLockSpaceResourceLockShrAuto, NULL) < 0)
+ ret = -1;
+
+ if (virtTestRun("Lockspace res full path", 1, testLockSpaceResourceLockPath, NULL) < 0)
+ ret = -1;
+
+ return ret==0 ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+VIRT_TEST_MAIN(mymain)
--
1.7.11.2
12 years, 3 months
[libvirt] [PATCH] build: commit to 0.10.0 release naming
by Eric Blake
With 0.10.0-rc0 out the door, we are committed to the next version
number.
* src/libvirt_public.syms (LIBVIRT_0.9.14): Rename...
(LIBVIRT_0.10.0): ...to this.
* docs/formatdomain.html.in: Fix fallout.
* src/openvz/openvz_driver.c (openvzDriver): Likewise.
* src/remote/remote_driver.c (remote_driver): Likewise.
---
I almost pushed this under the trivial rule, but realized that
anyone that builds an app against rc0 will be binary incompatible
with the .so post-patch. Are we okay declaring that rc0 is
unsupported so the ABI break is okay, or do I need to respin
the .syms portion of this patch to keep the LIBVIRT_0.9.14
label even though we had no 0.9.14 release?
docs/formatdomain.html.in | 2 +-
src/libvirt_public.syms | 2 +-
src/openvz/openvz_driver.c | 2 +-
src/remote/remote_driver.c | 2 +-
4 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index b8db76e..54e0f13 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -780,7 +780,7 @@
CPU model will fail. Supported values for <code>fallback</code>
attribute are: <code>allow</code> (this is the default), and
<code>forbid</code>. The optional <code>vendor_id</code> attribute
- (<span class="since">Since 0.9.14</span>) can be used to set the
+ (<span class="since">Since 0.10.0</span>) can be used to set the
vendor id seen by the guest. It must be exactly 12 characters long.
If not set the vendor id of the host is used. Typical possible
values are "AuthenticAMD" and "GenuineIntel".</dd>
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index 5004182..e3ba119 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -544,7 +544,7 @@ LIBVIRT_0.9.13 {
virDomainSnapshotRef;
} LIBVIRT_0.9.11;
-LIBVIRT_0.9.14 {
+LIBVIRT_0.10.0 {
global:
virDomainGetHostname;
virConnectRegisterCloseCallback;
diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c
index 4cc7f46..48b5219 100644
--- a/src/openvz/openvz_driver.c
+++ b/src/openvz/openvz_driver.c
@@ -2170,7 +2170,7 @@ static virDriver openvzDriver = {
.domainIsUpdated = openvzDomainIsUpdated, /* 0.8.6 */
.isAlive = openvzIsAlive, /* 0.9.8 */
.domainUpdateDeviceFlags = openvzDomainUpdateDeviceFlags, /* 0.9.13 */
- .domainGetHostname = openvzDomainGetHostname, /* 0.9.14 */
+ .domainGetHostname = openvzDomainGetHostname, /* 0.10.0 */
};
int openvzRegister(void) {
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index 9ac27b2..23b13d3 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -5378,7 +5378,7 @@ static virDriver remote_driver = {
.domainGetDiskErrors = remoteDomainGetDiskErrors, /* 0.9.10 */
.domainSetMetadata = remoteDomainSetMetadata, /* 0.9.10 */
.domainGetMetadata = remoteDomainGetMetadata, /* 0.9.10 */
- .domainGetHostname = remoteDomainGetHostname, /* 0.9.14 */
+ .domainGetHostname = remoteDomainGetHostname, /* 0.10.0 */
};
static virNetworkDriver network_driver = {
--
1.7.11.2
12 years, 3 months
[libvirt] [PATCH] qemu: Fix typo in qemuDomainModifyDeviceFlags
by Michal Privoznik
One of our latest commits fbe87126 introduced this nasty typo:
func(vmdef, ...); where func() dereference vmdef->ncontrollers,
and vmdef was initialized to NULL. This leaves us with unconditional
immediate segfault. It should be vm->def instead.
---
Despite this could qualify to be pushed under trivial rule, I'd feel more
comfortable with an ACK.
src/qemu/qemu_driver.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index b3f946c..270e4dd 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -5833,7 +5833,7 @@ qemuDomainModifyDeviceFlags(virDomainPtr dom, const char *xml,
}
if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
- if (virDomainDefCompatibleDevice(vmdef, dev) < 0)
+ if (virDomainDefCompatibleDevice(vm->def, dev) < 0)
goto endjob;
/* Make a copy for updated domain. */
--
1.7.8.6
12 years, 3 months
[libvirt] [PATCH] daemon: Portable auto-detection of driver module directory
by Jiri Denemark
When running libvirtd from a build directory on a system with unmodified
libtool, libvirtd's binary is not renamed as "lt-libvirtd". Check for
"/daemon/.libs/libvirtd" in addition to "lt-libvirtd".
---
daemon/libvirtd.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c
index ffbe067..a316427 100644
--- a/daemon/libvirtd.c
+++ b/daemon/libvirtd.c
@@ -972,7 +972,8 @@ int main(int argc, char **argv) {
virLogSetFromEnv();
#ifdef WITH_DRIVER_MODULES
- if (strstr(argv[0], "lt-libvirtd")) {
+ if (strstr(argv[0], "lt-libvirtd") ||
+ strstr(argv[0], "/daemon/.libs/libvirtd")) {
char *tmp = strrchr(argv[0], '/');
if (!tmp) {
fprintf(stderr, _("%s: cannot identify driver directory\n"), argv[0]);
--
1.7.11.1
12 years, 3 months
[libvirt] [PATCH 1/2] build: Link security manager into libvirt.so
by Jiri Denemark
Security manager is not a dynamically loadable driver, it's a common
infrastructure similar to util, conf, cpu, etc. used by individual
drivers. Such code is allowed to be linked into libvirt.so.
This reverts commit ec5b7bd2ecbf40ceff5b2d4fc00d5cfdfba966a4 and most of
aae5cfb69948fddef556f8f5b9f80a444f9c6125.
This patch is supposed to fix virdrivermoduletest failures for qemu and
lxc drivers as well as libvirtd's ability to load qemu and lxc drivers.
---
daemon/Makefile.am | 1 -
src/Makefile.am | 3 +--
src/libvirt_private.syms | 31 +++++++++++++++++++++++++++++++
tests/Makefile.am | 5 ++---
4 files changed, 34 insertions(+), 6 deletions(-)
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index b8ecbef..928aeaf 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -164,7 +164,6 @@ endif
if WITH_NWFILTER
libvirtd_LDADD += ../src/libvirt_driver_nwfilter.la
endif
-libvirtd_LDADD += ../src/libvirt_driver_security.la
endif
libvirtd_LDADD += ../src/libvirt.la
diff --git a/src/Makefile.am b/src/Makefile.am
index 6f8838b..2b09141 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1161,8 +1161,7 @@ endif
libvirt_driver_security_la_SOURCES = $(SECURITY_DRIVER_SOURCES)
noinst_LTLIBRARIES += libvirt_driver_security.la
-# Stateful, so linked to daemon instead
-#libvirt_la_BUILT_LIBADD += libvirt_driver_security.la
+libvirt_la_BUILT_LIBADD += libvirt_driver_security.la
libvirt_driver_security_la_CFLAGS = \
-I$(top_srcdir)/src/conf $(AM_CFLAGS)
libvirt_driver_security_la_LDFLAGS = $(AM_LDFLAGS)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 97f3b14..71341a2 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -962,6 +962,37 @@ virSecretUsageTypeTypeFromString;
virSecretUsageTypeTypeToString;
+# security_driver.h
+virSecurityDriverLookup;
+
+
+# security_manager.h
+virSecurityManagerClearSocketLabel;
+virSecurityManagerFree;
+virSecurityManagerGenLabel;
+virSecurityManagerGetDOI;
+virSecurityManagerGetModel;
+virSecurityManagerGetProcessLabel;
+virSecurityManagerNew;
+virSecurityManagerNewStack;
+virSecurityManagerNewDAC;
+virSecurityManagerReleaseLabel;
+virSecurityManagerReserveLabel;
+virSecurityManagerRestoreImageLabel;
+virSecurityManagerRestoreAllLabel;
+virSecurityManagerRestoreHostdevLabel;
+virSecurityManagerRestoreSavedStateLabel;
+virSecurityManagerSetAllLabel;
+virSecurityManagerSetDaemonSocketLabel;
+virSecurityManagerSetImageFDLabel;
+virSecurityManagerSetImageLabel;
+virSecurityManagerSetHostdevLabel;
+virSecurityManagerSetProcessLabel;
+virSecurityManagerSetSavedStateLabel;
+virSecurityManagerSetSocketLabel;
+virSecurityManagerVerify;
+virSecurityManagerGetMountOptions;
+
# sexpr.h
sexpr_append;
sexpr_cons;
diff --git a/tests/Makefile.am b/tests/Makefile.am
index b931cea..a466480 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -294,8 +294,7 @@ endif
if WITH_QEMU
-qemu_LDADDS = ../src/libvirt_driver_qemu_impl.la \
- ../src/libvirt_driver_security.la
+qemu_LDADDS = ../src/libvirt_driver_qemu_impl.la
if WITH_NETWORK
qemu_LDADDS += ../src/libvirt_driver_network_impl.la
endif
@@ -520,7 +519,7 @@ virauthconfigtest_LDADD = $(LDADDS)
seclabeltest_SOURCES = \
seclabeltest.c
-seclabeltest_LDADD = $(LDADDS) ../src/libvirt_driver_security.la
+seclabeltest_LDADD = $(LDADDS)
virbuftest_SOURCES = \
virbuftest.c testutils.h testutils.c
--
1.7.11.1
12 years, 3 months
[libvirt] [PATCH v4 00/12] Support hypervisor-threads-pin in vcpupin.
by tangchen
Users can use vcpupin command to bind a vcpu thread to a specific physical cpu.
But besides vcpu threads, there are alse some other threads created by qemu
(known as hypervisor threads) that could not be explicitly bound to physical cpus.
The first 3 patches are from Wen Congyang, which implement Cgroup for differrent
hypervisors.
The other 10 patches implemented hypervisor threads binding, in two ways:
1) Use sched_setaffinity() function;
2) Use cpuset cgroup.
A new xml element is introduced, and vcpupin command is improved, see below.
1. Introduce new xml elements:
<cputune>
......
<hypervisorpin cpuset='1'/>
</cputune>
2. Improve vcpupin command to support hypervisor threads binding.
For example, vm1 has the following configuration:
<cputune>
<vcpupin vcpu='1' cpuset='1'/>
<vcpupin vcpu='0' cpuset='0'/>
<hypervisorpin cpuset='1'/>
</cputune>
1) query all threads pining
# vcpupin vm1
VCPU: CPU Affinity
----------------------------------
0: 0
1: 1
Hypervisor: CPU Affinity
----------------------------------
*: 1
2) query hypervisor threads pining only
# vcpupin vm1 --hypervisor
Hypervisor: CPU Affinity
----------------------------------
*: 1
3) change hypervisor threads pining
# vcpupin vm1 --hypervisor 0-1
# vcpupin vm1 --hypervisor
Hypervisor: CPU Affinity
----------------------------------
*: 0-1
# taskset -p 397
pid 397's current affinity mask: 3
Note: If users want to pin a vcpu thread to pcpu, --vcpu option could no longer be omitted.
Tang Chen (9):
Enable cpuset cgroup and synchronous vcpupin info to cgroup.
Support hypervisorpin xml parse.
Introduce qemuSetupCgroupHypervisorPin and synchronize hypervisorpin
info to cgroup.
Add qemuProcessSetHypervisorAffinites and set hypervisor threads
affinities
Introduce virDomainHypervisorPinAdd and virDomainHypervisorPinDel
functions
Introduce virDomainPinHypervisorFlags and
virDomainGetHypervisorPinInfo functions.
Introduce qemudDomainPinHypervisorFlags and
qemudDomainGetHypervisorPinInfo in qemu driver.
Introduce remoteDomainPinHypervisorFlags and
remoteDomainGetHypervisorPinInfo functions in remote driver.
Improve vcpupin to support hypervisorpin dynically.
Wen Congyang (3):
Introduce the function virCgroupForHypervisor
Introduce the function virCgroupMoveTask
create a new cgroup and move all hypervisor threads to the new cgroup
daemon/remote.c | 103 +++++++++
docs/schemas/domaincommon.rng | 7 +
include/libvirt/libvirt.h.in | 10 +
src/conf/domain_conf.c | 169 +++++++++++++-
src/conf/domain_conf.h | 7 +
src/driver.h | 13 +-
src/libvirt.c | 147 +++++++++++++
src/libvirt_private.syms | 7 +
src/libvirt_public.syms | 2 +
src/qemu/qemu_cgroup.c | 151 ++++++++++++-
src/qemu/qemu_cgroup.h | 5 +
src/qemu/qemu_driver.c | 267 ++++++++++++++++++++++-
src/qemu/qemu_process.c | 60 ++++-
src/remote/remote_driver.c | 102 +++++++++
src/remote/remote_protocol.x | 23 +-
src/remote_protocol-structs | 24 ++
src/util/cgroup.c | 188 +++++++++++++++-
src/util/cgroup.h | 15 ++
tests/qemuxml2argvdata/qemuxml2argv-cputune.xml | 1 +
tests/vcpupin | 6 +-
tools/virsh.c | 147 ++++++++-----
tools/virsh.pod | 16 +-
22 files changed, 1393 insertions(+), 77 deletions(-)
--
1.7.10.2
--
Best Regards,
Tang chen
12 years, 3 months
[libvirt] Stored secrets seem to get corrupted
by Wido den Hollander
Hi,
On one of my systems I'm having troubles with my RBD storage backend.
At first I thought it was a problem with my code, but after trying the
same code on a second machine I'm a bit confused.
The problem is that the storage backend tries to retrieve the value of a
secret and base64 decode it, that fails.
My debug log shows:
debug : virStorageBackendRBDOpenRADOSConn:65 : Using cephx authorization
debug : virStorageBackendRBDOpenRADOSConn:75 : Looking up secret by
UUID: 322bccea-f2ed-4eae-a7e5-d0793ffb162d
debug : virSecretLookupByUUIDString:14128 : conn=0x7fac9c0009c0,
uuidstr=322bccea-f2ed-4eae-a7e5-d0793ffb162d
debug : virSecretLookupByUUID:14086 : conn=0x7fac9c0009c0,
uuid=322bccea-f2ed-4eae-a7e5-d0793ffb162d
debug : virSecretGetValue:14486 : secret=0x7fac94000d30,
value_size=0x7facad481918, flags=0
debug : virStorageBackendRBDOpenRADOSConn:103 : Found cephx key: `I^%
debug : virStorageBackendRBDOpenRADOSConn:135 : Found 1 RADOS cluster
monitors in the pool configuration
debug : virStorageBackendRBDOpenRADOSConn:159 : RADOS mon_host has been
set to: 31.25.100.131:6789,
error : virStorageBackendRBDOpenRADOSConn:171 : internal error failed to
connect to the RADOS monitor on: 31.25.100.131:6789,
It goes wrong at "Found cephx key: <garbage>"
So I figured it had to be something in my code and I went over the code
again, but nothing seemed odd.
I tried the same checkout (tag: 0.9.13-rc1) on a different host (also
Ubuntu 12.04) and that worked.
The secret and pool XML's are the same, but what I found is that the
secret storage on disk seems to go wrong on one machine.
Notice this behavior:
root@stack01:~# virsh secret-set-value
322bccea-f2ed-4eae-a7e5-d0793ffb162d
AQAE+uJPCFpELBAAkTniQvHabBGj0Quwnu2imA==
Secret value set
root@stack01:~# md5sum
/etc/libvirt/secrets/322bccea-f2ed-4eae-a7e5-d0793ffb162d.base64
b4b147bc522828731f1a016bfa72c073
/etc/libvirt/secrets/322bccea-f2ed-4eae-a7e5-d0793ffb162d.base64
root@stack01:~# virsh secret-set-value
322bccea-f2ed-4eae-a7e5-d0793ffb162d
AQAE+uJPCFpELBAAkTniQvHabBGj0Quwnu2imA==
Secret value set
root@stack01:~# md5sum
/etc/libvirt/secrets/322bccea-f2ed-4eae-a7e5-d0793ffb162d.base64
927e2458c32cc3f6754d91694e41333f
/etc/libvirt/secrets/322bccea-f2ed-4eae-a7e5-d0793ffb162d.base64
root@stack01:~#
As you can see, the md5sum of the file changes when I set the value of
the secret to the same.
I tried the same on the other host:
root@stack02:~# virsh secret-set-value
322bccea-f2ed-4eae-a7e5-d0793ffb162d
AQAE+uJPCFpELBAAkTniQvHabBGj0Quwnu2imA==
Secret value set
root@stack02:~# md5sum
/etc/libvirt/secrets/322bccea-f2ed-4eae-a7e5-d0793ffb162d.base64
c30db27f9ebfe3f7903470d4bd542d1d
/etc/libvirt/secrets/322bccea-f2ed-4eae-a7e5-d0793ffb162d.base64
root@stack02:~# virsh secret-set-value
322bccea-f2ed-4eae-a7e5-d0793ffb162d
AQAE+uJPCFpELBAAkTniQvHabBGj0Quwnu2imA==
Secret value set
root@stack02:~# md5sum
/etc/libvirt/secrets/322bccea-f2ed-4eae-a7e5-d0793ffb162d.base64
c30db27f9ebfe3f7903470d4bd542d1d
/etc/libvirt/secrets/322bccea-f2ed-4eae-a7e5-d0793ffb162d.base64
root@stack02:~# virsh secret-set-value
322bccea-f2ed-4eae-a7e5-d0793ffb162d
AQAE+uJPCFpELBAAkTniQvHabBGj0Quwnu2imA==
Secret value set
root@stack02:~# md5sum
/etc/libvirt/secrets/322bccea-f2ed-4eae-a7e5-d0793ffb162d.base64
c30db27f9ebfe3f7903470d4bd542d1d
/etc/libvirt/secrets/322bccea-f2ed-4eae-a7e5-d0793ffb162d.base64
root@stack02:~#
The md5sum stays the same on stack02.
I verified that stack01 isn't out of disk space or out of inodes, those
are in the acceptable values range.
Any suggestions?
For the record, the hosts:
OS: Ubuntu 12.04 x864_64
Kernel: 3.2.0-25-generic
Libvirt commit: 0fce94fe1bd782ac4c33fdd59d13ee37b3437413
Thank you,
Wido
12 years, 3 months
[libvirt] [PATCH] Change function signature for creating new lock manager instances
by Daniel P. Berrange
From: "Daniel P. Berrange" <berrange(a)redhat.com>
To allow a virLockManagerPtr to be created directly from a
driver table struct, replace the virLockManagerPluginPtr parameter
with a virLockDriverPtr parameter.
* src/locking/domain_lock.c, src/locking/lock_manager.c,
src/locking/lock_manager.h: Replace plugin param with
a driver in virLockManagerNew
---
src/locking/domain_lock.c | 2 +-
src/locking/lock_manager.c | 31 +++++++++++++++++++------------
src/locking/lock_manager.h | 3 ++-
3 files changed, 22 insertions(+), 14 deletions(-)
diff --git a/src/locking/domain_lock.c b/src/locking/domain_lock.c
index 55f5640..ba49f9c 100644
--- a/src/locking/domain_lock.c
+++ b/src/locking/domain_lock.c
@@ -124,7 +124,7 @@ static virLockManagerPtr virDomainLockManagerNew(virLockManagerPluginPtr plugin,
memcpy(params[0].value.uuid, dom->def->uuid, VIR_UUID_BUFLEN);
- if (!(lock = virLockManagerNew(plugin,
+ if (!(lock = virLockManagerNew(virLockManagerPluginGetDriver(plugin),
VIR_LOCK_MANAGER_OBJECT_TYPE_DOMAIN,
ARRAY_CARDINALITY(params),
params,
diff --git a/src/locking/lock_manager.c b/src/locking/lock_manager.c
index 18e739e..5f65ecf 100644
--- a/src/locking/lock_manager.c
+++ b/src/locking/lock_manager.c
@@ -39,11 +39,11 @@
#define VIR_FROM_THIS VIR_FROM_LOCKING
-#define CHECK_PLUGIN(field, errret) \
- if (!plugin->driver->field) { \
- virReportError(VIR_ERR_INTERNAL_ERROR, \
- _("Missing '%s' field in lock manager driver"), \
- #field); \
+#define CHECK_DRIVER(field, errret) \
+ if (!driver->field) { \
+ virLockError(VIR_ERR_INTERNAL_ERROR, \
+ _("Missing '%s' field in lock manager driver"), \
+ #field); \
return errret; \
}
@@ -265,9 +265,16 @@ bool virLockManagerPluginUsesState(virLockManagerPluginPtr plugin)
}
+virLockDriverPtr virLockManagerPluginGetDriver(virLockManagerPluginPtr plugin)
+{
+ VIR_DEBUG("plugin=%p", plugin);
+
+ return plugin->driver;
+}
+
/**
* virLockManagerNew:
- * @plugin: the plugin implementation to use
+ * @driver: the lock manager implementation to use
* @type: the type of process to be supervised
* @flags: optional flags, currently unused
*
@@ -276,27 +283,27 @@ bool virLockManagerPluginUsesState(virLockManagerPluginPtr plugin)
*
* Returns a new lock manager context
*/
-virLockManagerPtr virLockManagerNew(virLockManagerPluginPtr plugin,
+virLockManagerPtr virLockManagerNew(virLockDriverPtr driver,
unsigned int type,
size_t nparams,
virLockManagerParamPtr params,
unsigned int flags)
{
virLockManagerPtr lock;
- VIR_DEBUG("plugin=%p type=%u nparams=%zu params=%p flags=%x",
- plugin, type, nparams, params, flags);
+ VIR_DEBUG("driver=%p type=%u nparams=%zu params=%p flags=%x",
+ driver, type, nparams, params, flags);
virLockManagerLogParams(nparams, params);
- CHECK_PLUGIN(drvNew, NULL);
+ CHECK_DRIVER(drvNew, NULL);
if (VIR_ALLOC(lock) < 0) {
virReportOOMError();
return NULL;
}
- lock->driver = plugin->driver;
+ lock->driver = driver;
- if (plugin->driver->drvNew(lock, type, nparams, params, flags) < 0) {
+ if (driver->drvNew(lock, type, nparams, params, flags) < 0) {
VIR_FREE(lock);
return NULL;
}
diff --git a/src/locking/lock_manager.h b/src/locking/lock_manager.h
index b548d45..25c7f7f 100644
--- a/src/locking/lock_manager.h
+++ b/src/locking/lock_manager.h
@@ -37,8 +37,9 @@ void virLockManagerPluginUnref(virLockManagerPluginPtr plugin);
const char *virLockManagerPluginGetName(virLockManagerPluginPtr plugin);
bool virLockManagerPluginUsesState(virLockManagerPluginPtr plugin);
+virLockDriverPtr virLockManagerPluginGetDriver(virLockManagerPluginPtr plugin);
-virLockManagerPtr virLockManagerNew(virLockManagerPluginPtr plugin,
+virLockManagerPtr virLockManagerNew(virLockDriverPtr driver,
unsigned int type,
size_t nparams,
virLockManagerParamPtr params,
--
1.7.11.2
12 years, 3 months