Implement dispatch functions for lock protocol in virtlockd

Introduce a lock_daemon_dispatch.c file which implements the
server side dispatcher the RPC APIs previously defined in the
lock protocol.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
This commit is contained in:
Daniel P. Berrange 2012-08-03 10:27:07 +01:00
parent ad39fd83a8
commit 0e49b83912
8 changed files with 644 additions and 2 deletions

1
.gitignore vendored
View File

@ -108,6 +108,7 @@
/src/libvirt_*helper
/src/libvirt_*probes.h
/src/libvirt_lxc
/src/locking/lock_daemon_dispatch_stubs.h
/src/locking/lock_protocol.[ch]
/src/locking/qemu-sanlock.conf
/src/locking/test_libvirt_sanlock.aug

View File

@ -50,6 +50,7 @@ src/libvirt.c
src/libvirt-qemu.c
src/locking/lock_daemon.c
src/locking/lock_daemon_config.c
src/locking/lock_daemon_dispatch.c
src/locking/lock_driver_sanlock.c
src/locking/lock_manager.c
src/locking/sanlock_helper.c

View File

@ -157,13 +157,26 @@ EXTRA_DIST += locking/lock_protocol.x
BUILT_SOURCES += $(LOCK_PROTOCOL_GENERATED)
MAINTAINERCLEANFILES += $(LOCK_PROTOCOL_GENERATED)
LOCK_DAEMON_GENERATED = \
locking/lock_daemon_dispatch_stubs.h
$(NULL)
BUILT_SOURCES += $(LOCK_DAEMON_GENERATED)
MAINTAINERCLEANFILES += $(LOCK_DAEMON_GENERATED)
LOCK_DAEMON_SOURCES = \
locking/lock_daemon.h \
locking/lock_daemon.c \
locking/lock_daemon_config.h \
locking/lock_daemon_config.c \
locking/lock_daemon_dispatch.c \
locking/lock_daemon_dispatch.h \
$(NULL)
$(srcdir)/locking/lock_daemon_dispatch_stubs.h: locking/lock_protocol.x $(srcdir)/rpc/gendispatch.pl Makefile.am
$(AM_V_GEN)perl -w $(srcdir)/rpc/gendispatch.pl -b virLockSpaceProtocol VIR_LOCK_SPACE_PROTOCOL $< > $@
NETDEV_CONF_SOURCES = \
conf/netdev_bandwidth_conf.h conf/netdev_bandwidth_conf.c \
conf/netdev_vport_profile_conf.h conf/netdev_vport_profile_conf.c \
@ -1532,6 +1545,7 @@ sbin_PROGRAMS = virtlockd
virtlockd_SOURCES = \
$(LOCK_DAEMON_SOURCES) \
$(LOCK_PROTOCOL_GENERATED) \
$(LOCK_DAEMON_GENERATED) \
$(NULL)
virtlockd_CFLAGS = \
$(AM_CFLAGS) \

View File

@ -236,6 +236,28 @@
} \
} while (0)
/**
* virCheckFlagsGoto:
* @supported: an OR'ed set of supported flags
* @label: label to jump to on error
*
* To avoid memory leaks this macro has to be used before any non-trivial
* code which could possibly allocate some memory.
*
* Returns nothing. Jumps to a label if unsupported flags were
* passed to it.
*/
# define virCheckFlagsGoto(supported, label) \
do { \
unsigned long __unsuppflags = flags & ~(supported); \
if (__unsuppflags) { \
virReportInvalidArg(flags, \
_("unsupported flags (0x%lx) in function %s"), \
__unsuppflags, __FUNCTION__); \
goto label; \
} \
} while (0)
# define virCheckNonNullArgReturn(argname, retval) \
do { \
if (argname == NULL) { \

View File

@ -36,6 +36,7 @@
#include "util.h"
#include "virfile.h"
#include "virpidfile.h"
#include "virprocess.h"
#include "virterror_internal.h"
#include "logging.h"
#include "memory.h"
@ -44,13 +45,20 @@
#include "virrandom.h"
#include "virhash.h"
#include "locking/lock_daemon_dispatch.h"
#include "locking/lock_protocol.h"
#include "configmake.h"
#define VIR_FROM_THIS VIR_FROM_LOCKING
#define VIR_LOCK_DAEMON_NUM_LOCKSPACES 3
struct _virLockDaemon {
virMutex lock;
virNetServerPtr srv;
virHashTablePtr lockspaces;
virLockSpacePtr defaultLockspace;
};
virLockDaemonPtr lockDaemon = NULL;
@ -94,11 +102,19 @@ virLockDaemonFree(virLockDaemonPtr lockd)
return;
virObjectUnref(lockd->srv);
virHashFree(lockd->lockspaces);
virLockSpaceFree(lockd->defaultLockspace);
VIR_FREE(lockd);
}
static void virLockDaemonLockSpaceDataFree(void *data,
const void *key ATTRIBUTE_UNUSED)
{
virLockSpaceFree(data);
}
static virLockDaemonPtr
virLockDaemonNew(bool privileged)
{
@ -125,6 +141,13 @@ virLockDaemonNew(bool privileged)
(void*)(intptr_t)(privileged ? 0x1 : 0x0))))
goto error;
if (!(lockd->lockspaces = virHashCreate(VIR_LOCK_DAEMON_NUM_LOCKSPACES,
virLockDaemonLockSpaceDataFree)))
goto error;
if (!(lockd->defaultLockspace = virLockSpaceNew(NULL)))
goto error;
return lockd;
error:
@ -133,6 +156,31 @@ error:
}
int virLockDaemonAddLockSpace(virLockDaemonPtr lockd,
const char *path,
virLockSpacePtr lockspace)
{
int ret;
virMutexLock(&lockd->lock);
ret = virHashAddEntry(lockd->lockspaces, path, lockspace);
virMutexUnlock(&lockd->lock);
return ret;
}
virLockSpacePtr virLockDaemonFindLockSpace(virLockDaemonPtr lockd,
const char *path)
{
virLockSpacePtr lockspace;
virMutexLock(&lockd->lock);
if (path && STRNEQ(path, ""))
lockspace = virHashLookup(lockd->lockspaces, path);
else
lockspace = lockd->defaultLockspace;
virMutexUnlock(&lockd->lock);
return lockspace;
}
static int
virLockDaemonForkIntoBackground(const char *argv0)
{
@ -466,6 +514,30 @@ virLockDaemonSetupNetworking(virNetServerPtr srv, const char *sock_path)
}
struct virLockDaemonClientReleaseData {
virLockDaemonClientPtr client;
bool hadSomeLeases;
bool gotError;
};
static void
virLockDaemonClientReleaseLockspace(void *payload,
const void *name ATTRIBUTE_UNUSED,
void *opaque)
{
virLockSpacePtr lockspace = payload;
struct virLockDaemonClientReleaseData *data = opaque;
int rc;
rc = virLockSpaceReleaseResourcesForOwner(lockspace,
data->client->clientPid);
if (rc > 0)
data->hadSomeLeases = true;
else if (rc < 0)
data->gotError = true;
}
static void
virLockDaemonClientFree(void *opaque)
{
@ -474,9 +546,52 @@ virLockDaemonClientFree(void *opaque)
if (!priv)
return;
VIR_DEBUG("priv=%p client=%lld",
VIR_DEBUG("priv=%p client=%lld owner=%lld",
priv,
(unsigned long long)priv->clientPid);
(unsigned long long)priv->clientPid,
(unsigned long long)priv->ownerPid);
/* If client & owner match, this is the lock holder */
if (priv->clientPid == priv->ownerPid) {
size_t i;
struct virLockDaemonClientReleaseData data = {
.client = priv, .hadSomeLeases = false, .gotError = false
};
/* Release all locks associated with this
* owner in all lockspaces */
virMutexLock(&lockDaemon->lock);
virHashForEach(lockDaemon->lockspaces,
virLockDaemonClientReleaseLockspace,
&data);
virLockDaemonClientReleaseLockspace(lockDaemon->defaultLockspace,
"",
&data);
virMutexUnlock(&lockDaemon->lock);
/* If the client had some active leases when it
* closed the connection, we must kill it off
* to make sure it doesn't do nasty stuff */
if (data.gotError || data.hadSomeLeases) {
for (i = 0 ; i < 15 ; i++) {
int signum;
if (i == 0)
signum = SIGTERM;
else if (i == 8)
signum = SIGKILL;
else
signum = 0;
if (virProcessKill(priv->clientPid, signum) < 0) {
if (errno == ESRCH)
break;
VIR_WARN("Failed to kill off pid %lld",
(unsigned long long)priv->clientPid);
}
usleep(200 * 1000);
}
}
}
virMutexDestroy(&priv->lock);
VIR_FREE(priv);
@ -597,6 +712,7 @@ enum {
#define MAX_LISTEN 5
int main(int argc, char **argv) {
virNetServerProgramPtr lockProgram = NULL;
char *remote_config_file = NULL;
int statuswrite = -1;
int ret = 1;
@ -795,6 +911,18 @@ int main(int argc, char **argv) {
goto cleanup;
}
if (!(lockProgram = virNetServerProgramNew(VIR_LOCK_SPACE_PROTOCOL_PROGRAM,
VIR_LOCK_SPACE_PROTOCOL_PROGRAM_VERSION,
virLockSpaceProtocolProcs,
virLockSpaceProtocolNProcs))) {
ret = VIR_LOCK_DAEMON_ERR_INIT;
goto cleanup;
}
if (virNetServerAddProgram(lockDaemon->srv, lockProgram) < 0) {
ret = VIR_LOCK_DAEMON_ERR_INIT;
goto cleanup;
}
/* Disable error func, now logging is setup */
virSetErrorFunc(NULL, virLockDaemonErrorHandler);
@ -818,6 +946,7 @@ int main(int argc, char **argv) {
ret = 0;
cleanup:
virObjectUnref(lockProgram);
virLockDaemonFree(lockDaemon);
if (statuswrite != -1) {
if (ret != 0) {

View File

@ -34,10 +34,23 @@ typedef virLockDaemonClient *virLockDaemonClientPtr;
struct _virLockDaemonClient {
virMutex lock;
bool restricted;
pid_t ownerPid;
char *ownerName;
unsigned char ownerUUID[VIR_UUID_BUFLEN];
unsigned int ownerId;
pid_t clientPid;
};
extern virLockDaemonPtr lockDaemon;
int virLockDaemonAddLockSpace(virLockDaemonPtr lockd,
const char *path,
virLockSpacePtr lockspace);
virLockSpacePtr virLockDaemonFindLockSpace(virLockDaemonPtr lockd,
const char *path);
#endif /* __VIR_LOCK_DAEMON_H__ */

View File

@ -0,0 +1,431 @@
/*
* lock_daemon_dispatch.c: lock management daemon dispatch
*
* Copyright (C) 2006-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/>.
*
* Author: Daniel P. Berrange <berrange@redhat.com>
*/
#include <config.h>
#include "rpc/virnetserver.h"
#include "rpc/virnetserverclient.h"
#include "util.h"
#include "logging.h"
#include "lock_daemon.h"
#include "lock_protocol.h"
#include "lock_daemon_dispatch_stubs.h"
#include "virterror_internal.h"
#define VIR_FROM_THIS VIR_FROM_RPC
static int
virLockSpaceProtocolDispatchAcquireResource(virNetServerPtr server ATTRIBUTE_UNUSED,
virNetServerClientPtr client,
virNetMessagePtr msg ATTRIBUTE_UNUSED,
virNetMessageErrorPtr rerr,
virLockSpaceProtocolAcquireResourceArgs *args)
{
int rv = -1;
unsigned int flags = args->flags;
virLockDaemonClientPtr priv =
virNetServerClientGetPrivateData(client);
virLockSpacePtr lockspace;
unsigned int newFlags;
virMutexLock(&priv->lock);
virCheckFlagsGoto(VIR_LOCK_SPACE_PROTOCOL_ACQUIRE_RESOURCE_SHARED |
VIR_LOCK_SPACE_PROTOCOL_ACQUIRE_RESOURCE_AUTOCREATE, cleanup);
if (priv->restricted) {
virReportError(VIR_ERR_OPERATION_DENIED, "%s",
_("lock manager connection has been restricted"));
goto cleanup;
}
if (!priv->ownerPid) {
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
_("lock owner details have not been registered"));
goto cleanup;
}
if (!(lockspace = virLockDaemonFindLockSpace(lockDaemon, args->path))) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Lockspace for path %s does not exist"),
args->path);
goto cleanup;
}
newFlags = 0;
if (flags & VIR_LOCK_SPACE_PROTOCOL_ACQUIRE_RESOURCE_SHARED)
newFlags |= VIR_LOCK_SPACE_ACQUIRE_SHARED;
if (flags & VIR_LOCK_SPACE_PROTOCOL_ACQUIRE_RESOURCE_AUTOCREATE)
newFlags |= VIR_LOCK_SPACE_ACQUIRE_AUTOCREATE;
if (virLockSpaceAcquireResource(lockspace,
args->name,
priv->ownerPid,
newFlags) < 0)
goto cleanup;
rv = 0;
cleanup:
if (rv < 0)
virNetMessageSaveError(rerr);
virMutexUnlock(&priv->lock);
return rv;
}
static int
virLockSpaceProtocolDispatchCreateResource(virNetServerPtr server ATTRIBUTE_UNUSED,
virNetServerClientPtr client,
virNetMessagePtr msg ATTRIBUTE_UNUSED,
virNetMessageErrorPtr rerr,
virLockSpaceProtocolCreateResourceArgs *args)
{
int rv = -1;
unsigned int flags = args->flags;
virLockDaemonClientPtr priv =
virNetServerClientGetPrivateData(client);
virLockSpacePtr lockspace;
virMutexLock(&priv->lock);
virCheckFlagsGoto(0, cleanup);
if (priv->restricted) {
virReportError(VIR_ERR_OPERATION_DENIED, "%s",
_("lock manager connection has been restricted"));
goto cleanup;
}
if (!priv->ownerPid) {
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
_("lock owner details have not been registered"));
goto cleanup;
}
if (!(lockspace = virLockDaemonFindLockSpace(lockDaemon, args->path))) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Lockspace for path %s does not exist"),
args->path);
goto cleanup;
}
if (virLockSpaceCreateResource(lockspace, args->name) < 0)
goto cleanup;
rv = 0;
cleanup:
if (rv < 0)
virNetMessageSaveError(rerr);
virMutexUnlock(&priv->lock);
return rv;
}
static int
virLockSpaceProtocolDispatchDeleteResource(virNetServerPtr server ATTRIBUTE_UNUSED,
virNetServerClientPtr client,
virNetMessagePtr msg ATTRIBUTE_UNUSED,
virNetMessageErrorPtr rerr,
virLockSpaceProtocolDeleteResourceArgs *args)
{
int rv = -1;
unsigned int flags = args->flags;
virLockDaemonClientPtr priv =
virNetServerClientGetPrivateData(client);
virLockSpacePtr lockspace;
virMutexLock(&priv->lock);
virCheckFlagsGoto(0, cleanup);
if (priv->restricted) {
virReportError(VIR_ERR_OPERATION_DENIED, "%s",
_("lock manager connection has been restricted"));
goto cleanup;
}
if (!priv->ownerPid) {
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
_("lock owner details have not been registered"));
goto cleanup;
}
if (!(lockspace = virLockDaemonFindLockSpace(lockDaemon, args->path))) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Lockspace for path %s does not exist"),
args->path);
goto cleanup;
}
if (virLockSpaceDeleteResource(lockspace, args->name) < 0)
goto cleanup;
rv = 0;
cleanup:
if (rv < 0)
virNetMessageSaveError(rerr);
virMutexUnlock(&priv->lock);
return rv;
}
static int
virLockSpaceProtocolDispatchNew(virNetServerPtr server ATTRIBUTE_UNUSED,
virNetServerClientPtr client,
virNetMessagePtr msg ATTRIBUTE_UNUSED,
virNetMessageErrorPtr rerr,
virLockSpaceProtocolNewArgs *args)
{
int rv = -1;
unsigned int flags = args->flags;
virLockDaemonClientPtr priv =
virNetServerClientGetPrivateData(client);
virLockSpacePtr lockspace;
virMutexLock(&priv->lock);
virCheckFlagsGoto(0, cleanup);
if (priv->restricted) {
virReportError(VIR_ERR_OPERATION_DENIED, "%s",
_("lock manager connection has been restricted"));
goto cleanup;
}
if (!priv->ownerPid) {
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
_("lock owner details have not been registered"));
goto cleanup;
}
if (!args->path || STREQ(args->path, "")) {
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
_("the default lockspace already exists"));
goto cleanup;
}
if ((lockspace = virLockDaemonFindLockSpace(lockDaemon, args->path))) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Lockspace for path %s already exists"),
args->path);
goto cleanup;
}
virResetLastError();
lockspace = virLockSpaceNew(args->path);
virLockDaemonAddLockSpace(lockDaemon, args->path, lockspace);
rv = 0;
cleanup:
if (rv < 0)
virNetMessageSaveError(rerr);
virMutexUnlock(&priv->lock);
return rv;
}
static int
virLockSpaceProtocolDispatchRegister(virNetServerPtr server ATTRIBUTE_UNUSED,
virNetServerClientPtr client,
virNetMessagePtr msg ATTRIBUTE_UNUSED,
virNetMessageErrorPtr rerr,
virLockSpaceProtocolRegisterArgs *args)
{
int rv = -1;
unsigned int flags = args->flags;
virLockDaemonClientPtr priv =
virNetServerClientGetPrivateData(client);
virMutexLock(&priv->lock);
virCheckFlagsGoto(0, cleanup);
if (priv->restricted) {
virReportError(VIR_ERR_OPERATION_DENIED, "%s",
_("lock manager connection has been restricted"));
goto cleanup;
}
if (priv->ownerPid) {
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
_("lock owner details have already been registered"));
goto cleanup;
}
if (!(priv->ownerName = strdup(args->owner.name))) {
virReportOOMError();
goto cleanup;
}
memcpy(priv->ownerUUID, args->owner.uuid, VIR_UUID_BUFLEN);
priv->ownerId = args->owner.id;
priv->ownerPid = args->owner.pid;
VIR_DEBUG("ownerName=%s ownerId=%d ownerPid=%lld",
priv->ownerName, priv->ownerId, (unsigned long long)priv->ownerPid);
rv = 0;
cleanup:
if (rv < 0)
virNetMessageSaveError(rerr);
virMutexUnlock(&priv->lock);
return rv;
}
static int
virLockSpaceProtocolDispatchReleaseResource(virNetServerPtr server ATTRIBUTE_UNUSED,
virNetServerClientPtr client,
virNetMessagePtr msg ATTRIBUTE_UNUSED,
virNetMessageErrorPtr rerr,
virLockSpaceProtocolReleaseResourceArgs *args)
{
int rv = -1;
unsigned int flags = args->flags;
virLockDaemonClientPtr priv =
virNetServerClientGetPrivateData(client);
virLockSpacePtr lockspace;
virMutexLock(&priv->lock);
virCheckFlagsGoto(0, cleanup);
if (priv->restricted) {
virReportError(VIR_ERR_OPERATION_DENIED, "%s",
_("lock manager connection has been restricted"));
goto cleanup;
}
if (!priv->ownerPid) {
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
_("lock owner details have not been registered"));
goto cleanup;
}
if (!(lockspace = virLockDaemonFindLockSpace(lockDaemon, args->path))) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Lockspace for path %s does not exist"),
args->path);
goto cleanup;
}
if (virLockSpaceReleaseResource(lockspace,
args->name,
priv->ownerPid) < 0)
goto cleanup;
rv = 0;
cleanup:
if (rv < 0)
virNetMessageSaveError(rerr);
virMutexUnlock(&priv->lock);
return rv;
}
static int
virLockSpaceProtocolDispatchRestrict(virNetServerPtr server ATTRIBUTE_UNUSED,
virNetServerClientPtr client,
virNetMessagePtr msg ATTRIBUTE_UNUSED,
virNetMessageErrorPtr rerr,
virLockSpaceProtocolRestrictArgs *args)
{
int rv = -1;
unsigned int flags = args->flags;
virLockDaemonClientPtr priv =
virNetServerClientGetPrivateData(client);
virMutexLock(&priv->lock);
virCheckFlagsGoto(0, cleanup);
if (priv->restricted) {
virReportError(VIR_ERR_OPERATION_DENIED, "%s",
_("lock manager connection has been restricted"));
goto cleanup;
}
if (!priv->ownerPid) {
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
_("lock owner details have not been registered"));
goto cleanup;
}
priv->restricted = true;
rv = 0;
cleanup:
if (rv < 0)
virNetMessageSaveError(rerr);
virMutexUnlock(&priv->lock);
return rv;
}
static int
virLockSpaceProtocolDispatchCreateLockSpace(virNetServerPtr server ATTRIBUTE_UNUSED,
virNetServerClientPtr client,
virNetMessagePtr msg ATTRIBUTE_UNUSED,
virNetMessageErrorPtr rerr,
virLockSpaceProtocolCreateLockSpaceArgs *args)
{
int rv = -1;
virLockDaemonClientPtr priv =
virNetServerClientGetPrivateData(client);
virLockSpacePtr lockspace;
virMutexLock(&priv->lock);
if (priv->restricted) {
virReportError(VIR_ERR_OPERATION_DENIED, "%s",
_("lock manager connection has been restricted"));
goto cleanup;
}
if ((lockspace = virLockDaemonFindLockSpace(lockDaemon, args->path))) {
virReportError(VIR_ERR_OPERATION_INVALID,
_("Lockspace for path %s already exists"),
args->path);
goto cleanup;
}
if (!(lockspace = virLockSpaceNew(args->path)))
goto cleanup;
if (virLockDaemonAddLockSpace(lockDaemon, args->path, lockspace) < 0) {
virLockSpaceFree(lockspace);
goto cleanup;
}
rv = 0;
cleanup:
if (rv < 0)
virNetMessageSaveError(rerr);
virMutexUnlock(&priv->lock);
return rv;
}

View File

@ -0,0 +1,31 @@
/*
* lock_daemon_dispatch.h: lock management daemon dispatch
*
* Copyright (C) 2006-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/>.
*
* Author: Daniel P. Berrange <berrange@redhat.com>
*/
#ifndef __VIR_LOCK_DAEMON_DISPATCH_H__
# define __VIR_LOCK_DAEMON_DISPATCH_H__
# include "rpc/virnetserverprogram.h"
extern virNetServerProgramProc virLockSpaceProtocolProcs[];
extern size_t virLockSpaceProtocolNProcs;
#endif /* __VIR_LOCK_DAEMON_DISPATCH_H__ */