[libvirt] [PATCH 11/14] Add the virtlockd daemon for managing virtual guest locks

Daniel P. Berrange berrange at redhat.com
Thu Jul 7 14:17:29 UTC 2011


From: "Daniel P. Berrange" <berrange at redhat.com>

This adds a new daemon 'virtlockd' which will manage the
locks for all running virtual machines. Communication is
via a new RPC lock program.

The intent is that virtlockd runs forever and if it ever
crashes, the entire host should be restarted (ideally via
a hardware fencing agent) to ensure maximum safety of guest
disks.

* cfg.mk: Ignore the lockd files
* src/locking/lock_daemon.c, src/locking/lock_daemon.h: Main
  daemon startup code
* src/locking/lock_daemon_dispatch.c,
  src/locking/lock_daemon_dispatch.h: RPC dispatcher for lock
  program
* src/locking/virtlockd.init.in: Init script
* src/locking/virtlockd.sysconf: Init script configuration
* libvirt.spec.in: Add initscript
---
 cfg.mk                             |    4 +-
 libvirt.spec.in                    |    8 +
 po/POTFILES.in                     |    5 +
 src/.gitignore                     |    4 +
 src/Makefile.am                    |  106 +++++-
 src/libvirt_private.syms           |    2 +
 src/locking/lock_daemon.c          |  776 ++++++++++++++++++++++++++++++++++++
 src/locking/lock_daemon_dispatch.c |  334 ++++++++++++++++
 src/locking/lock_daemon_dispatch.h |   46 +++
 src/locking/virtlockd.init.in      |   93 +++++
 src/locking/virtlockd.sysconf      |    3 +
 11 files changed, 1374 insertions(+), 7 deletions(-)
 create mode 100644 src/locking/lock_daemon.c
 create mode 100644 src/locking/lock_daemon.h
 create mode 100644 src/locking/lock_daemon_dispatch.c
 create mode 100644 src/locking/lock_daemon_dispatch.h
 create mode 100644 src/locking/virtlockd.init.in
 create mode 100644 src/locking/virtlockd.sysconf

diff --git a/cfg.mk b/cfg.mk
index b00cda3..8074b59 100644
--- a/cfg.mk
+++ b/cfg.mk
@@ -616,7 +616,7 @@ $(srcdir)/src/remote/remote_client_bodies.h:
 # List all syntax-check exemptions:
 exclude_file_name_regexp--sc_avoid_strcase = ^tools/virsh\.c$$
 
-_src1=libvirt|fdstream|qemu/qemu_monitor|util/(command|util)|xen/xend_internal|rpc/virnetsocket
+_src1=libvirt|fdstream|qemu/qemu_monitor|util/(command|util)|xen/xend_internal|rpc/virnetsocket|locking/lock_daemon
 exclude_file_name_regexp--sc_avoid_write = \
   ^(src/($(_src1))|daemon/libvirtd|tools/console)\.c$$
 
@@ -646,7 +646,7 @@ exclude_file_name_regexp--sc_prohibit_empty_lines_at_EOF = \
 
 _src2=src/(util/command|libvirt|lxc/lxc_controller)
 exclude_file_name_regexp--sc_prohibit_fork_wrappers = \
-  (^docs|^($(_src2)|tests/testutils|daemon/libvirtd)\.c$$)
+  (^docs|^($(_src2)|tests/testutils|daemon/libvirtd|src/locking/lock_daemon)\.c$$)
 
 exclude_file_name_regexp--sc_prohibit_gethostname = ^src/util/util\.c$$
 
diff --git a/libvirt.spec.in b/libvirt.spec.in
index 650f0bc..7f6fd13 100644
--- a/libvirt.spec.in
+++ b/libvirt.spec.in
@@ -1007,11 +1007,13 @@ fi
 %{_sysconfdir}/libvirt/nwfilter/*.xml
 
 %{_sysconfdir}/rc.d/init.d/libvirtd
+%{_sysconfdir}/rc.d/init.d/virtlockd
 %if %{with_systemd}
 %{_unitdir}/libvirtd.service
 %endif
 %doc daemon/libvirtd.upstart
 %config(noreplace) %{_sysconfdir}/sysconfig/libvirtd
+%config(noreplace) %{_sysconfdir}/sysconfig/virtlockd
 %config(noreplace) %{_sysconfdir}/libvirt/libvirtd.conf
 %if %{with_dtrace}
 %{_datadir}/systemtap/tapset/libvirtd.stp
@@ -1072,6 +1074,11 @@ fi
 %dir %attr(0755, root, root) %{_localstatedir}/lib/libvirt/dnsmasq/
 %endif
 
+%if %{with_libvirtd}
+%dir %attr(0755, root, root) %{_libdir}/libvirt/lock-driver
+%attr(0755, root, root) %{_libdir}/libvirt/lock-driver/lockd.so
+%endif
+
 %if %{with_qemu}
 %{_datadir}/augeas/lenses/libvirtd_qemu.aug
 %{_datadir}/augeas/lenses/tests/test_libvirtd_qemu.aug
@@ -1105,6 +1112,7 @@ fi
 
 %attr(0755, root, root) %{_libexecdir}/libvirt_iohelper
 %attr(0755, root, root) %{_sbindir}/libvirtd
+%attr(0755, root, root) %{_sbindir}/virtlockd
 
 %{_mandir}/man8/libvirtd.8*
 
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 32eaa2d..bb94d51 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -30,8 +30,13 @@ src/fdstream.c
 src/interface/netcf_driver.c
 src/internal.h
 src/libvirt.c
+src/locking/lock_database.c
+src/locking/lock_driver_fcntl.c
+src/locking/lock_driver_lockd.c
 src/locking/lock_driver_sanlock.c
 src/locking/lock_manager.c
+src/locking/lock_daemon.c
+src/locking/lock_daemon_dispatch.c
 src/lxc/lxc_container.c
 src/lxc/lxc_conf.c
 src/lxc/lxc_controller.c
diff --git a/src/.gitignore b/src/.gitignore
index a619643..c499b47 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -16,3 +16,7 @@ libvirt_qemu.def
 *.s
 remote_protocol-structs-t
 virt-aa-helper
+virtlockd
+virtlockd.socket
+locking/lock_daemon_dispatch_stubs.h
+locking/qemu-sanlock.conf
diff --git a/src/Makefile.am b/src/Makefile.am
index cd8a7e9..3e2c376 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -96,8 +96,34 @@ DRIVER_SOURCES =						\
 		libvirt.c libvirt_internal.h			\
 		locking/lock_manager.c locking/lock_manager.h   \
 		locking/lock_driver.h 				\
+		locking/domain_lock.h locking/domain_lock.c	\
+		locking/lock_driver_nop.h locking/lock_driver_nop.c
+
+LOCK_PROTOCOL_GENERATED = \
+		locking/lock_protocol.h \
+		locking/lock_protocol.c
+
+EXTRA_DIST += locking/lock_protocol.x
+
+LOCKD_GENERATED = \
+		$(LOCK_PROTOCOL_GENERATED) \
+		locking/lock_daemon_dispatch_stubs.h
+
+BUILT_SOURCES += $(LOCKD_GENERATED)
+
+LOCK_DAEMON_SOURCES = \
+		locking/lock_daemon.c \
+		locking/lock_daemon_dispatch.h \
+		locking/lock_daemon_dispatch.c \
+		locking/lock_database.c locking/lock_database.h \
+		locking/lock_manager.c locking/lock_manager.h   \
 		locking/lock_driver_nop.h locking/lock_driver_nop.c \
-		locking/domain_lock.h locking/domain_lock.c
+		locking/lock_driver_fcntl.h locking/lock_driver_fcntl.c \
+		$(LOCKD_GENERATED)
+
+$(srcdir)/locking/lock_daemon_dispatch_stubs.h: locking/lock_protocol.x $(srcdir)/rpc/gendispatch.pl
+	$(AM_V_GEN)perl -w $(srcdir)/rpc/gendispatch.pl -b lock $< > $@
+
 
 LOCK_DRIVER_SANLOCK_SOURCES = \
 		locking/lock_driver_sanlock.c
@@ -1184,12 +1210,73 @@ libvirt_qemu_la_CFLAGS = $(AM_CFLAGS)
 libvirt_qemu_la_LIBADD = libvirt.la $(CYGWIN_EXTRA_LIBADD)
 EXTRA_DIST += $(LIBVIRT_QEMU_SYMBOL_FILE)
 
+if WITH_LIBVIRTD
+sbin_PROGRAMS = virtlockd
+
+virtlockd_SOURCES = $(LOCK_DAEMON_SOURCES)
+virtlockd_CFLAGS = \
+			$(AM_CFLAGS)
+virtlockd_LDFLAGS = \
+			$(AM_LDFLAGS) \
+			$(CYGWIN_EXTRA_LDFLAGS) \
+			$(MINGW_EXTRA_LDFLAGS)
+virtlockd_LDADD = \
+			libvirt-net-rpc-server.la \
+			libvirt-net-rpc.la \
+			libvirt_util.la \
+			../gnulib/lib/libgnu.la \
+			$(CYGWIN_EXTRA_LIBADD)
+endif
+
+EXTRA_DIST += locking/virtlockd.sysconf
+
+install-sysconfig:
+	mkdir -p $(DESTDIR)$(sysconfdir)/sysconfig
+	$(INSTALL_DATA) $(srcdir)/locking/virtlockd.sysconf \
+	  $(DESTDIR)$(sysconfdir)/sysconfig/virtlockd
+
+uninstall-sysconfig:
+	rm -f $(DESTDIR)$(sysconfdir)/sysconfig/virtlockd
+
+EXTRA_DIST += locking/virtlockd.init.in
+
+if WITH_LIBVIRTD
+if LIBVIRT_INIT_SCRIPT_RED_HAT
+install-init:: virtlockd.init install-sysconfig
+	mkdir -p $(DESTDIR)$(sysconfdir)/rc.d/init.d
+	$(INSTALL_SCRIPT) virtlockd.init \
+	  $(DESTDIR)$(sysconfdir)/rc.d/init.d/virtlockd
+
+uninstall-init:: uninstall-sysconfig
+	rm -f $(DESTDIR)$(sysconfdir)/rc.d/init.d/libvirtd
+
+BUILT_SOURCES += virtlockd.init
+else
+install-init::
+uninstall-init::
+endif
+else
+install-init::
+uninstall-init::
+endif
+
+virtlockd.init: locking/virtlockd.init.in $(top_builddir)/config.status
+	$(AM_V_GEN)sed					\
+	    -e s!\@localstatedir\@!@localstatedir@!g	\
+	    -e s!\@sbindir\@!@sbindir@!g		\
+	    -e s!\@sysconfdir\@!@sysconfdir@!g		\
+	    < $< > $@-t &&				\
+	    chmod a+x $@-t &&				\
+	    mv $@-t $@
+
+
+
 if HAVE_SANLOCK
 lockdriverdir = $(libdir)/libvirt/lock-driver
 lockdriver_LTLIBRARIES = sanlock.la
 
 sanlock_la_SOURCES = $(LOCK_DRIVER_SANLOCK_SOURCES)
-sanlock_la_CFLAGS = $(AM_CLFAGS)
+sanlock_la_CFLAGS = $(AM_CFLAGS)
 sanlock_la_LDFLAGS = -module -avoid-version
 sanlock_la_LIBADD = -lsanlock \
 		../gnulib/lib/libgnu.la
@@ -1369,7 +1456,11 @@ endif
 endif
 EXTRA_DIST += $(SECURITY_DRIVER_APPARMOR_HELPER_SOURCES)
 
-install-data-local:
+install-data-local: install-init
+if WITH_LIBVIRTD
+	$(MKDIR_P) "$(DESTDIR)$(localstatedir)/lib/libvirt/lockd"
+	$(MKDIR_P) "$(DESTDIR)$(localstatedir)/run/libvirt/lockd"
+endif
 	$(MKDIR_P) "$(DESTDIR)$(localstatedir)/cache/libvirt"
 	$(MKDIR_P) "$(DESTDIR)$(localstatedir)/lib/libvirt/images"
 	$(MKDIR_P) "$(DESTDIR)$(localstatedir)/lib/libvirt/boot"
@@ -1411,7 +1502,11 @@ if WITH_NETWORK
 	    $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/autostart/default.xml
 endif
 
-uninstall-local::
+uninstall-local:: uninstall-init
+if WITH_LIBVIRTD
+	rmdir "$(DESTDIR)$(localstatedir)/lib/libvirt/lockd" ||:
+	rmdir "$(DESTDIR)$(localstatedir)/run/libvirt/lockd" ||:
+endif
 	rmdir "$(DESTDIR)$(localstatedir)/cache/libvirt" ||:
 	rmdir "$(DESTDIR)$(localstatedir)/lib/libvirt/images" ||:
 	rmdir "$(DESTDIR)$(localstatedir)/lib/libvirt/boot" ||:
@@ -1446,4 +1541,5 @@ endif
 
 CLEANFILES = *.gcov .libs/*.gcda .libs/*.gcno *.gcno *.gcda *.i *.s
 DISTCLEANFILES = $(GENERATED_SYM_FILES)
-MAINTAINERCLEANFILES = $(REMOTE_DRIVER_GENERATED) $(VIR_NET_RPC_GENERATED) $(ESX_DRIVER_GENERATED)
+MAINTAINERCLEANFILES = $(REMOTE_DRIVER_GENERATED) $(VIR_NET_RPC_GENERATED) \
+    $(ESX_DRIVER_GENERATED) $(LOCKD_GENERATED)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 0746dee..ac1d3d2 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -957,6 +957,7 @@ virMutexUnlock;
 virOnce;
 virThreadCreate;
 virThreadID;
+virThreadInitialize;
 virThreadIsSelf;
 virThreadJoin;
 virThreadSelf;
@@ -1065,6 +1066,7 @@ virAuditSend;
 
 # virterror_internal.h
 virDispatchError;
+virErrorInitialize;
 virErrorMsg;
 virRaiseErrorFull;
 virReportErrorHelper;
diff --git a/src/locking/lock_daemon.c b/src/locking/lock_daemon.c
new file mode 100644
index 0000000..1c20715
--- /dev/null
+++ b/src/locking/lock_daemon.c
@@ -0,0 +1,776 @@
+/*
+ * lock_daemon.c: lock management daemon
+ *
+ * Copyright (C) 2006-2011 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * 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
+ *
+ * Author: Daniel P. Berrange <berrange at redhat.com>
+ */
+
+#include <config.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <locale.h>
+
+
+#include "util.h"
+#include "files.h"
+#include "virterror_internal.h"
+#include "logging.h"
+#include "memory.h"
+#include "conf.h"
+#include "rpc/virnetserver.h"
+#include "threads.h"
+#include "lock_daemon_dispatch.h"
+#include "lock_protocol.h"
+#include "lock_driver_fcntl.h"
+#include "intprops.h"
+
+#include "configmake.h"
+
+#define VIR_FROM_THIS VIR_FROM_LOCKING
+
+#define virLockError(code, ...)                                     \
+    virReportErrorHelper(VIR_FROM_THIS, code, __FILE__,             \
+                         __FUNCTION__, __LINE__, __VA_ARGS__)
+
+
+static virNetServerProgramPtr lockProgram = NULL;
+static bool privileged;
+
+enum {
+    VIR_LOCK_DAEMON_ERR_NONE = 0,
+    VIR_LOCK_DAEMON_ERR_PIDFILE,
+    VIR_LOCK_DAEMON_ERR_RUNDIR,
+    VIR_LOCK_DAEMON_ERR_INIT,
+    VIR_LOCK_DAEMON_ERR_SIGNAL,
+    VIR_LOCK_DAEMON_ERR_PRIVS,
+    VIR_LOCK_DAEMON_ERR_NETWORK,
+    VIR_LOCK_DAEMON_ERR_CONFIG,
+    VIR_LOCK_DAEMON_ERR_HOOKS,
+
+    VIR_LOCK_DAEMON_ERR_LAST
+};
+
+VIR_ENUM_DECL(virDaemonErr)
+VIR_ENUM_IMPL(virDaemonErr, VIR_LOCK_DAEMON_ERR_LAST,
+              "Initialization successful",
+              "Unable to obtain pidfile",
+              "Unable to create rundir",
+              "Unable to initialize libvirt",
+              "Unable to setup signal handlers",
+              "Unable to drop privileges",
+              "Unable to initialize network sockets",
+              "Unable to load configuration file",
+              "Unable to look for hook scripts");
+
+
+static int
+virLockDaemonForkIntoBackground(const char *argv0)
+{
+    int statuspipe[2];
+    if (pipe(statuspipe) < 0)
+        return -1;
+
+    int pid = fork();
+    switch (pid) {
+    case 0:
+        {
+            int stdinfd = -1;
+            int stdoutfd = -1;
+            int nextpid;
+
+            VIR_FORCE_CLOSE(statuspipe[0]);
+
+            if ((stdinfd = open("/dev/null", O_RDONLY)) < 0)
+                goto cleanup;
+            if ((stdoutfd = open("/dev/null", O_WRONLY)) < 0)
+                goto cleanup;
+            if (dup2(stdinfd, STDIN_FILENO) != STDIN_FILENO)
+                goto cleanup;
+            if (dup2(stdoutfd, STDOUT_FILENO) != STDOUT_FILENO)
+                goto cleanup;
+            if (dup2(stdoutfd, STDERR_FILENO) != STDERR_FILENO)
+                goto cleanup;
+            if (VIR_CLOSE(stdinfd) < 0)
+                goto cleanup;
+            if (VIR_CLOSE(stdoutfd) < 0)
+                goto cleanup;
+
+            if (setsid() < 0)
+                goto cleanup;
+
+            nextpid = fork();
+            switch (nextpid) {
+            case 0:
+                return statuspipe[1];
+            case -1:
+                return -1;
+            default:
+                _exit(0);
+            }
+
+        cleanup:
+            VIR_FORCE_CLOSE(stdoutfd);
+            VIR_FORCE_CLOSE(stdinfd);
+            return -1;
+
+        }
+
+    case -1:
+        return -1;
+
+    default:
+        {
+            int got, exitstatus = 0;
+            int ret;
+            char status;
+
+            VIR_FORCE_CLOSE(statuspipe[1]);
+
+            /* We wait to make sure the first child forked successfully */
+            if ((got = waitpid(pid, &exitstatus, 0)) < 0 ||
+                got != pid ||
+                exitstatus != 0) {
+                return -1;
+            }
+
+            /* Now block until the second child initializes successfully */
+        again:
+            ret = read(statuspipe[0], &status, 1);
+            if (ret == -1 && errno == EINTR)
+                goto again;
+
+            if (ret == 1 && status != 0) {
+                fprintf(stderr,
+                        _("%s: error: %s. Check /var/log/messages or run without "
+                          "--daemon for more info.\n"), argv0,
+                        virDaemonErrTypeToString(status));
+            }
+            _exit(ret == 1 && status == 0 ? 0 : 1);
+        }
+    }
+}
+
+
+static int
+virLockDaemonAcquirePidFile(const char *argv0, const char *pidFile) {
+    int fd;
+    char ebuf[1024];
+    unsigned long long pid = (unsigned long long)getpid();
+    char pidstr[INT_BUFSIZE_BOUND(pid)];
+
+    if (pidFile[0] == '\0')
+        return 0;
+
+    while (1) {
+        struct stat a, b;
+        if ((fd = open(pidFile, O_WRONLY|O_CREAT, 0644)) < 0) {
+            VIR_ERROR(_("%s: Failed to open pid file '%s' : %s"),
+                      argv0, pidFile, virStrerror(errno, ebuf, sizeof ebuf));
+            return -1;
+        }
+
+        if (fstat(fd, &b) < 0) {
+            VIR_ERROR(_("%s: Pid file '%s' disappeared: %s"),
+                      argv0, pidFile, virStrerror(errno, ebuf, sizeof ebuf));
+            VIR_FORCE_CLOSE(fd);
+            return -1;
+        }
+
+        if (virFileLock(fd, false, 0, 1) < 0) {
+            VIR_ERROR(_("%s: Failed to acquire pid file '%s' : %s"),
+                      argv0, pidFile, virStrerror(errno, ebuf, sizeof ebuf));
+            VIR_FORCE_CLOSE(fd);
+            return -1;
+        }
+
+        /* Now make sure the pidfile we locked is the same
+         * one that now exists on the filesystem
+         */
+
+        if (stat(pidFile, &a) < 0) {
+            VIR_DEBUG("%s: Pid file '%s' disappeared: %s",
+                      argv0, pidFile, virStrerror(errno, ebuf, sizeof ebuf));
+            VIR_FORCE_CLOSE(fd);
+            continue;
+        }
+
+        if (a.st_ino == b.st_ino)
+            break;
+
+        VIR_DEBUG("%s: Pid file '%s' was recreated",
+                  argv0, pidFile);
+        VIR_FORCE_CLOSE(fd);
+    }
+
+    snprintf(pidstr, sizeof(pidstr), "%llu", pid);
+
+    if (safewrite(fd, pidstr, strlen(pidstr)) < 0) {
+            VIR_ERROR(_("Failed to write to pid file '%s' : %s"),
+                      pidFile, virStrerror(errno, ebuf, sizeof ebuf));
+    }
+
+    return fd;
+}
+
+
+static int
+virLockDaemonMakePaths(char **basedir,
+                       char **statedir,
+                       char **pidfile,
+                       char **sockfile)
+{
+    char *userdir = NULL;
+    uid_t uid = geteuid();
+
+    *basedir = *statedir = *pidfile = *sockfile = NULL;
+
+    if (privileged) {
+        if (!(*basedir = strdup(LOCALSTATEDIR "/run/libvirt")))
+            goto no_memory;
+    } else {
+        if (!(userdir = virGetUserDirectory(uid)))
+            goto error;
+
+        if (virAsprintf(basedir, "%s/.libvirt", userdir) < 0)
+            goto no_memory;
+    }
+
+    if (virAsprintf(statedir, "%s/lockd", *basedir) < 0)
+        goto no_memory;
+    if (virAsprintf(pidfile, "%s/lockd.pid", *statedir) < 0)
+        goto no_memory;
+    if (virAsprintf(sockfile, "%s/lockd.sock", *statedir) < 0)
+        goto no_memory;
+
+    VIR_FREE(userdir);
+    return 0;
+
+no_memory:
+    VIR_FREE(*basedir);
+    VIR_FREE(*statedir);
+    VIR_FREE(*pidfile);
+    VIR_FREE(*sockfile);
+error:
+    VIR_FREE(userdir);
+    return -1;
+}
+
+static void
+virLockDaemonErrorHandler(void *opaque ATTRIBUTE_UNUSED,
+                          virErrorPtr err ATTRIBUTE_UNUSED)
+{
+    /* Don't do anything, since logging infrastructure already
+     * took care of reporting the error */
+}
+
+
+/*
+ * Set up the logging environment
+ * By default if daemonized all errors go to syslog and the logging
+ * is also saved onto the logfile libvird.log, but if verbose or error
+ * debugging is asked for then output informations or debug.
+ */
+static int
+virLockDaemonSetLogging(virConfPtr conf ATTRIBUTE_UNUSED,
+                        const char *filename ATTRIBUTE_UNUSED,
+                        int godaemon, int verbose)
+{
+    //int log_level = 0;
+    char *log_filters = NULL;
+    char *log_outputs = NULL;
+    int ret = -1;
+
+    virLogReset();
+#if 0
+    /*
+     * Libvirtd's order of precedence is:
+     * cmdline > environment > config
+     *
+     * In order to achieve this, we must process configuration in
+     * different order for the log level versus the filters and
+     * outputs. Because filters and outputs append, we have to look at
+     * the environment first and then only check the config file if
+     * there was no result from the environment. The default output is
+     * then applied only if there was no setting from either of the
+     * first two. Because we don't have a way to determine if the log
+     * level has been set, we must process variables in the opposite
+     * order, each one overriding the previous.
+     */
+    GET_CONF_INT (conf, filename, log_level);
+    if (log_level != 0)
+        virLogSetDefaultPriority(log_level);
+
+    if (virLogGetNbFilters() == 0) {
+        GET_CONF_STR (conf, filename, log_filters);
+        virLogParseFilters(log_filters);
+    }
+
+    if (virLogGetNbOutputs() == 0) {
+        GET_CONF_STR (conf, filename, log_outputs);
+        virLogParseOutputs(log_outputs);
+    }
+#endif
+
+    virLogSetFromEnv();
+
+    /*
+     * If no defined outputs, then direct to syslog when running
+     * as daemon. Otherwise the default output is stderr.
+     */
+    if (virLogGetNbOutputs() == 0) {
+        char *tmp = NULL;
+        if (godaemon) {
+            if (virAsprintf (&tmp, "%d:syslog:libvirtd",
+                             virLogGetDefaultPriority()) < 0)
+                goto free_and_fail;
+        } else {
+            if (virAsprintf (&tmp, "%d:stderr",
+                             virLogGetDefaultPriority()) < 0)
+                goto free_and_fail;
+        }
+        virLogParseOutputs(tmp);
+        VIR_FREE(tmp);
+    }
+
+    /*
+     * Command line override for --verbose
+     */
+    if ((verbose) && (virLogGetDefaultPriority() > VIR_LOG_INFO))
+        virLogSetDefaultPriority(VIR_LOG_INFO);
+
+    ret = 0;
+
+free_and_fail:
+    VIR_FREE(log_filters);
+    VIR_FREE(log_outputs);
+    return(ret);
+}
+
+/* Read the config file if it exists.
+ * Only used in the remote case, hence the name.
+ */
+static int
+virLockDaemonReadConfigFile(const char *filename,
+                            int godaemon, int verbose)
+{
+    virConfPtr conf;
+
+    if (!(conf = virConfReadFile (filename, 0)))
+        goto error;
+
+    if (virLockDaemonSetLogging(conf, filename, godaemon, verbose) < 0)
+        goto error;
+
+    virConfFree (conf);
+    return 0;
+
+error:
+    virConfFree (conf);
+
+    return -1;
+}
+
+/* Display version information. */
+static void
+ virLockDaemonVersion(const char *argv0)
+{
+    printf ("%s (%s) %s\n", argv0, PACKAGE_NAME, PACKAGE_VERSION);
+}
+
+static void
+virLockDaemonShutdownHandler(virNetServerPtr srv,
+                             siginfo_t *sig ATTRIBUTE_UNUSED,
+                             void *opaque ATTRIBUTE_UNUSED)
+{
+    virNetServerQuit(srv);
+}
+
+static int
+virLockDaemonSetupSignals(virNetServerPtr srv)
+{
+    if (virNetServerAddSignalHandler(srv, SIGINT, virLockDaemonShutdownHandler, NULL) < 0)
+        return -1;
+    if (virNetServerAddSignalHandler(srv, SIGQUIT, virLockDaemonShutdownHandler, NULL) < 0)
+        return -1;
+    if (virNetServerAddSignalHandler(srv, SIGTERM, virLockDaemonShutdownHandler, NULL) < 0)
+        return -1;
+    return 0;
+}
+
+static int
+virLockDaemonSetupNetworking(virNetServerPtr srv, const char *sock_path)
+{
+    virNetServerServicePtr svc;
+
+    if (!(svc = virNetServerServiceNewUNIX(sock_path, 0700, 0, 0, false, 1, NULL)))
+        return -1;
+
+    if (virNetServerAddService(srv, svc, NULL) < 0) {
+        virNetServerServiceFree(svc);
+        return -1;
+    }
+    return 0;
+}
+
+
+static void
+virLockDaemonClientFreeFunc(void *data)
+{
+    virLockDaemonClientPrivatePtr priv = data;
+
+    VIR_DEBUG("Client %p dead, freeing manager %p",
+              priv, priv->manager);
+
+    virMutexLock(&priv->lock);
+    virLockManagerFree(priv->manager);
+    virMutexUnlock(&priv->lock);
+    virMutexDestroy(&priv->lock);
+    VIR_FREE(priv);
+}
+
+static int
+virLockDaemonClientInit(virNetServerPtr srv ATTRIBUTE_UNUSED,
+                        virNetServerClientPtr client)
+{
+    virLockDaemonClientPrivate *priv;
+
+    if (VIR_ALLOC(priv) < 0) {
+        virReportOOMError();
+        return -1;
+    }
+
+    if (virMutexInit(&priv->lock) < 0) {
+        VIR_FREE(priv);
+        virReportOOMError();
+        return -1;
+    }
+
+    if (virNetServerClientGetLocalIdentity(client,
+                                           &priv->uid,
+                                           &priv->pid) < 0)
+        goto error;
+
+    VIR_DEBUG("New client %p pid %llu uid %llu",
+              priv, (unsigned long long)priv->pid,
+              (unsigned long long)priv->uid);
+
+    if (!privileged) {
+        if (geteuid() != priv->uid) {
+            virLockError(VIR_ERR_OPERATION_DENIED,
+                         _("Disallowing client %llu with uid %llu"),
+                         (unsigned long long)priv->pid,
+                         (unsigned long long)priv->uid);
+
+            goto error;
+        }
+    } else {
+        if (priv->uid != 0) {
+            virLockError(VIR_ERR_OPERATION_DENIED,
+                         _("Disallowing client %llu with uid %llu"),
+                         (unsigned long long)priv->pid,
+                         (unsigned long long)priv->uid);
+            goto error;
+        }
+    }
+
+    virNetServerClientSetPrivateData(client, priv, virLockDaemonClientFreeFunc);
+    return 0;
+
+error:
+    virMutexDestroy(&priv->lock);
+    VIR_FREE(priv);
+    return -1;
+}
+
+
+static void
+virLockDaemonUsage(const char *argv0)
+{
+    fprintf (stderr,
+             _("\n\
+Usage:\n\
+  %s [options]\n\
+\n\
+Options:\n\
+  -v | --verbose         Verbose messages.\n\
+  -d | --daemon          Run as a daemon & write PID file.\n\
+  -t | --timeout <secs>  Exit after timeout period.\n\
+  -f | --config <file>   Configuration file.\n\
+     | --version         Display version information.\n\
+  -p | --pid-file <file> Change name of PID file.\n\
+\n\
+libvirt lock management daemon:\n\
+\n\
+  Default paths:\n\
+\n\
+    Configuration file (unless overridden by -f):\n\
+      %s/libvirt/libvirtd.conf\n\
+\n\
+    Sockets (as root):\n\
+      %s/run/virtlockd.sock\n\
+\n\
+    Sockets (as non-root):\n\
+      $HOME/.libvirt/virtlockd.sock (in UNIX abstract namespace)\n\
+\n\
+    Default PID file (as root):\
+      %s/run/virtlockd.pid\n\
+\n\
+    Default PID file (as non-root):\
+      $HOME/.libvirt/virtlockd.pid\n\
+\n"),
+             argv0,
+             SYSCONFDIR,
+             LOCALSTATEDIR,
+             LOCALSTATEDIR);
+}
+
+enum {
+    OPT_VERSION = 129
+};
+
+#define MAX_LISTEN 5
+int main(int argc, char **argv) {
+    virNetServerPtr srv = NULL;
+    const char *remote_config_file = NULL;
+    int statuswrite = -1;
+    int ret = 1;
+    int verbose = 0;
+    int godaemon = 0;
+    int timeout = 0;
+    char *base_dir = NULL;
+    char *state_dir = NULL;
+    char *pid_file = NULL;
+    int pid_file_fd = -1;
+    char *sock_file = NULL;
+
+    struct option opts[] = {
+        { "verbose", no_argument, &verbose, 1},
+        { "daemon", no_argument, &godaemon, 1},
+        { "config", required_argument, NULL, 'f'},
+        { "timeout", required_argument, NULL, 't'},
+        { "pid-file", required_argument, NULL, 'p'},
+        { "version", no_argument, NULL, OPT_VERSION },
+        { "help", no_argument, NULL, '?' },
+        {0, 0, 0, 0}
+    };
+
+    privileged = getuid() == 0;
+
+    if (setlocale (LC_ALL, "") == NULL ||
+        bindtextdomain (PACKAGE, LOCALEDIR) == NULL ||
+        textdomain(PACKAGE) == NULL ||
+        virThreadInitialize() < 0 ||
+        virErrorInitialize() < 0 ||
+        virRandomInitialize(time(NULL) ^ getpid())) {
+        fprintf(stderr, _("%s: initialization failed\n"), argv[0]);
+        exit(EXIT_FAILURE);
+    }
+
+    if (virLockDaemonMakePaths(&base_dir, &state_dir,
+                               &pid_file, &sock_file) < 0)
+        exit(EXIT_FAILURE);
+
+    while (1) {
+        int optidx = 0;
+        int c;
+        char *tmp;
+
+        c = getopt_long(argc, argv, "ldf:p:t:v", opts, &optidx);
+
+        if (c == -1) {
+            break;
+        }
+
+        switch (c) {
+        case 0:
+            /* Got one of the flags */
+            break;
+        case 'v':
+            verbose = 1;
+            break;
+        case 'd':
+            godaemon = 1;
+            break;
+
+        case 't':
+            if (virStrToLong_i(optarg, &tmp, 10, &timeout) != 0
+                || timeout <= 0
+                /* Ensure that we can multiply by 1000 without overflowing.  */
+                || timeout > INT_MAX / 1000)
+                timeout = -1;
+            break;
+
+        case 'p':
+            VIR_FREE(pid_file);
+            if (!(pid_file = strdup(optarg)))
+                exit(EXIT_FAILURE);
+            break;
+
+        case 'f':
+            remote_config_file = optarg;
+            break;
+
+        case OPT_VERSION:
+            virLockDaemonVersion(argv[0]);
+            return 0;
+
+        case '?':
+            virLockDaemonUsage(argv[0]);
+            return 2;
+
+        default:
+            fprintf (stderr, _("%s: internal error: unknown flag: %c\n"),
+                     argv[0], c);
+            exit (EXIT_FAILURE);
+        }
+    }
+
+    if (remote_config_file == NULL) {
+        static const char *default_config_file
+            = SYSCONFDIR "/libvirt/virtlockd.conf";
+        remote_config_file =
+            (access(default_config_file, R_OK) == 0
+             ? default_config_file
+             : "/dev/null");
+    }
+
+    if (godaemon) {
+        char ebuf[1024];
+        if ((statuswrite = virLockDaemonForkIntoBackground(argv[0])) < 0) {
+            VIR_ERROR(_("Failed to fork as daemon: %s"),
+                      virStrerror(errno, ebuf, sizeof ebuf));
+            goto cleanup;
+        }
+    }
+
+    if (!(srv = virNetServerNew(1, 1, 20, NULL,
+                                virLockDaemonClientInit))) {
+        ret = VIR_LOCK_DAEMON_ERR_INIT;
+        goto cleanup;
+    }
+
+    if ((virLockDaemonSetupSignals(srv)) < 0) {
+        ret = VIR_LOCK_DAEMON_ERR_SIGNAL;
+        goto cleanup;
+    }
+
+    /* Ensure the rundir exists (on tmpfs on some systems) */
+    if (mkdir(base_dir, 0755)) {
+        if (errno != EEXIST) {
+            char ebuf[1024];
+            VIR_ERROR(_("unable to create rundir %s: %s"), base_dir,
+                      virStrerror(errno, ebuf, sizeof(ebuf)));
+            ret = VIR_LOCK_DAEMON_ERR_RUNDIR;
+            goto cleanup;
+        }
+    }
+    if (mkdir(state_dir, 0700)) {
+        if (errno != EEXIST) {
+            char ebuf[1024];
+            VIR_ERROR(_("unable to create rundir %s: %s"), state_dir,
+                      virStrerror(errno, ebuf, sizeof(ebuf)));
+            ret = VIR_LOCK_DAEMON_ERR_RUNDIR;
+            goto cleanup;
+        }
+    }
+
+    /* If we have a pidfile set, claim it now, exiting if already taken */
+    if ((pid_file_fd = virLockDaemonAcquirePidFile(argv[0], pid_file)) < 0) {
+        ret = VIR_LOCK_DAEMON_ERR_PIDFILE;
+        goto cleanup;
+    }
+
+    /* Read the config file (if it exists). */
+    if (virLockDaemonReadConfigFile(remote_config_file, godaemon, verbose) < 0) {
+        ret = VIR_LOCK_DAEMON_ERR_CONFIG;
+        goto cleanup;
+    }
+
+    if (virLockDriverFcntl.drvInit(VIR_LOCK_MANAGER_VERSION, NULL, 0) < 0) {
+        ret = VIR_LOCK_DAEMON_ERR_INIT;
+        goto cleanup;
+    }
+
+    if (!(lockProgram = virNetServerProgramNew(LOCK_PROGRAM,
+                                               LOCK_PROTOCOL_VERSION,
+                                               lockProcs, lockNProcs))) {
+        ret = VIR_LOCK_DAEMON_ERR_INIT;
+        goto cleanup;
+    }
+    if (virNetServerAddProgram(srv, lockProgram) < 0) {
+        ret = VIR_LOCK_DAEMON_ERR_INIT;
+        goto cleanup;
+    }
+
+
+    if (virLockDaemonSetupNetworking(srv, sock_file) < 0) {
+        ret = VIR_LOCK_DAEMON_ERR_NETWORK;
+        goto cleanup;
+    }
+
+    /* Disable error func, now logging is setup */
+    virSetErrorFunc(NULL, virLockDaemonErrorHandler);
+
+
+    /* Tell parent of daemon that basic initialization is complete
+     * In particular we're ready to accept net connections & have
+     * written the pidfile
+     */
+    if (statuswrite != -1) {
+        char status = 0;
+        while (write(statuswrite, &status, 1) == -1 &&
+               errno == EINTR)
+            ;
+        VIR_FORCE_CLOSE(statuswrite);
+    }
+
+    /* Start accepting new clients from network */
+
+    virNetServerUpdateServices(srv, true);
+    virNetServerRun(srv);
+    ret = 0;
+
+cleanup:
+    virNetServerProgramFree(lockProgram);
+    virNetServerFree(srv);
+    if (statuswrite != -1) {
+        if (ret != 0) {
+            /* Tell parent of daemon what failed */
+            char status = ret;
+            while (write(statuswrite, &status, 1) == -1 &&
+                   errno == EINTR)
+                ;
+        }
+        VIR_FORCE_CLOSE(statuswrite);
+    }
+    if (pid_file_fd != -1) {
+        unlink(pid_file);
+        VIR_FORCE_CLOSE(pid_file_fd);
+    }
+    virLogShutdown();
+    VIR_FREE(pid_file);
+    VIR_FREE(sock_file);
+    VIR_FREE(state_dir);
+    return ret;
+}
diff --git a/src/locking/lock_daemon.h b/src/locking/lock_daemon.h
new file mode 100644
index 0000000..e69de29
diff --git a/src/locking/lock_daemon_dispatch.c b/src/locking/lock_daemon_dispatch.c
new file mode 100644
index 0000000..1909b9c
--- /dev/null
+++ b/src/locking/lock_daemon_dispatch.c
@@ -0,0 +1,334 @@
+/*
+ * lock_daemon_dispatch.c: lock management daemon
+ *
+ * Copyright (C) 2006-2011 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * 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
+ *
+ * Author: Daniel P. Berrange <berrange at redhat.com>
+ */
+
+#include <config.h>
+
+#include "logging.h"
+#include "virterror_internal.h"
+#include "rpc/virnetserver.h"
+#include "rpc/virnetserverclient.h"
+#include "memory.h"
+#include "lock_protocol.h"
+#include "lock_daemon_dispatch.h"
+#include "lock_daemon_dispatch_stubs.h"
+#include "lock_driver_fcntl.h"
+
+
+#define VIR_FROM_THIS VIR_FROM_LOCKING
+
+#define virLockError(code, ...)                                     \
+    virReportErrorHelper(VIR_FROM_THIS, code, __FILE__,             \
+                         __FUNCTION__, __LINE__, __VA_ARGS__)
+
+static virLockManagerParamPtr lockDispatchParameters(size_t nparams,
+                                                     lock_param *params)
+{
+    virLockManagerParamPtr ret = NULL;
+    int i;
+
+    if (VIR_ALLOC_N(ret, nparams) < 0) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    for (i = 0 ; i < nparams ; i++) {
+        ret[i].key = params[i].key;
+        ret[i].type = params[i].value.type;
+
+        switch (ret[i].type) {
+        case VIR_LOCK_MANAGER_PARAM_TYPE_STRING:
+            ret[i].value.str = params[i].value.lock_param_value_u.s;
+            break;
+        case VIR_LOCK_MANAGER_PARAM_TYPE_INT:
+            ret[i].value.i = params[i].value.lock_param_value_u.i;
+            break;
+        case VIR_LOCK_MANAGER_PARAM_TYPE_LONG:
+            ret[i].value.l = params[i].value.lock_param_value_u.l;
+            break;
+        case VIR_LOCK_MANAGER_PARAM_TYPE_UINT:
+            ret[i].value.ui = params[i].value.lock_param_value_u.ui;
+            break;
+        case VIR_LOCK_MANAGER_PARAM_TYPE_ULONG:
+            ret[i].value.ul = params[i].value.lock_param_value_u.ul;
+            break;
+        case VIR_LOCK_MANAGER_PARAM_TYPE_DOUBLE:
+            ret[i].value.d = params[i].value.lock_param_value_u.d;
+            break;
+        case VIR_LOCK_MANAGER_PARAM_TYPE_UUID:
+            memcpy(ret[i].value.uuid, params[i].value.lock_param_value_u.u, VIR_UUID_BUFLEN);
+            break;
+        }
+    }
+
+    return ret;
+}
+
+static int lockDispatchRegister(virNetServerPtr server ATTRIBUTE_UNUSED,
+                                virNetServerClientPtr client,
+                                virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                                virNetMessageErrorPtr rerr,
+                                lock_register_args *args)
+{
+    int rv = -1;
+    virLockDaemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
+    virLockManagerParamPtr params = NULL;
+    size_t nparams;
+
+    virMutexLock(&priv->lock);
+
+    if (priv->manager) {
+        virLockError(VIR_ERR_INTERNAL_ERROR, "%s", _("lock manager already open"));
+        goto cleanup;
+    }
+
+    if (priv->restrictAccess) {
+        virLockError(VIR_ERR_OPERATION_DENIED, "%s",
+                     _("lock manager has been restricted"));
+        goto cleanup;
+    }
+
+    if (args->params.params_len > LOCK_PARAMETERS_MAX) {
+        virLockError(VIR_ERR_INTERNAL_ERROR,
+                     _("Too many parameters %u for lock program, max %u"),
+                     args->params.params_len, LOCK_PARAMETERS_MAX);
+        goto cleanup;
+    }
+
+    if (!(params = lockDispatchParameters(args->params.params_len,
+                                          args->params.params_val)))
+        goto cleanup;
+
+    nparams = args->params.params_len;
+    if (VIR_EXPAND_N(params, nparams, 1) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    params[nparams-1].type = VIR_LOCK_MANAGER_PARAM_TYPE_UINT;
+    params[nparams-1].key = "client-pid";
+    params[nparams-1].value.i = priv->pid;
+
+    if (!(priv->manager = virLockManagerNew(&virLockDriverFcntl,
+                                            args->type,
+                                            nparams,
+                                            params,
+                                            args->flags)))
+        goto cleanup;
+
+    priv->restrictAccess = args->restrictAccess;
+
+    rv = 0;
+
+cleanup:
+    if (rv < 0)
+        virNetMessageSaveError(rerr);
+    VIR_FREE(params);
+    virMutexUnlock(&priv->lock);
+    return rv;
+}
+
+
+static int lockDispatchAddResource(virNetServerPtr server ATTRIBUTE_UNUSED,
+                                   virNetServerClientPtr client,
+                                   virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                                   virNetMessageErrorPtr rerr,
+                                   lock_add_resource_args *args)
+{
+    int rv = -1;
+    virLockDaemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
+    virLockManagerParamPtr params = NULL;
+
+    virMutexLock(&priv->lock);
+
+    if (!priv->manager) {
+        virLockError(VIR_ERR_INTERNAL_ERROR, "%s", _("lock manager not open"));
+        goto cleanup;
+    }
+
+    if (priv->restrictAccess) {
+        virLockError(VIR_ERR_OPERATION_DENIED, "%s",
+                     _("lock manager has been restricted"));
+        goto cleanup;
+    }
+
+    if (args->params.params_len > LOCK_PARAMETERS_MAX) {
+        virLockError(VIR_ERR_INTERNAL_ERROR,
+                     _("Too many parameters %u for lock program, max %u"),
+                     args->params.params_len, LOCK_PARAMETERS_MAX);
+        goto cleanup;
+    }
+
+    if (!(params = lockDispatchParameters(args->params.params_len,
+                                          args->params.params_val)))
+        goto cleanup;
+
+    if (virLockManagerAddResource(priv->manager,
+                                  args->type,
+                                  args->name,
+                                  args->params.params_len,
+                                  params,
+                                  args->flags) < 0)
+        goto cleanup;
+
+    rv = 0;
+
+cleanup:
+    if (rv < 0)
+        virNetMessageSaveError(rerr);
+    VIR_FREE(params);
+    virMutexUnlock(&priv->lock);
+    return rv;
+}
+
+
+static int lockDispatchAcquire(virNetServerPtr server ATTRIBUTE_UNUSED,
+                               virNetServerClientPtr client,
+                               virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                               virNetMessageErrorPtr rerr,
+                               lock_acquire_args *args)
+{
+    int rv = -1;
+    virLockDaemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
+
+    virMutexLock(&priv->lock);
+
+    if (!priv->manager) {
+        virLockError(VIR_ERR_INTERNAL_ERROR, "%s", _("lock manager not open"));
+        goto cleanup;
+    }
+
+    if (priv->restrictAccess) {
+        virLockError(VIR_ERR_OPERATION_DENIED, "%s",
+                     _("lock manager has been restricted"));
+        goto cleanup;
+    }
+
+    if (virLockManagerAcquire(priv->manager,
+                              args->state ? *args->state : NULL,
+                              args->flags,
+                              NULL) < 0)
+        goto cleanup;
+
+    rv = 0;
+
+cleanup:
+    if (rv < 0)
+        virNetMessageSaveError(rerr);
+    virMutexUnlock(&priv->lock);
+    return rv;
+}
+
+
+static int lockDispatchRelease(virNetServerPtr server ATTRIBUTE_UNUSED,
+                               virNetServerClientPtr client,
+                               virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                               virNetMessageErrorPtr rerr,
+                               lock_release_args *args,
+                               lock_release_ret *ret)
+{
+    int rv = -1;
+    virLockDaemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
+
+    virMutexLock(&priv->lock);
+
+    if (!priv->manager) {
+        virLockError(VIR_ERR_INTERNAL_ERROR, "%s", _("lock manager not open"));
+        goto cleanup;
+    }
+
+    if (priv->restrictAccess) {
+        virLockError(VIR_ERR_OPERATION_DENIED, "%s",
+                     _("lock manager has been restricted"));
+        goto cleanup;
+    }
+
+    if (VIR_ALLOC(ret->state) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    if (virLockManagerRelease(priv->manager,
+                              ret->state,
+                              args->flags) < 0)
+        goto cleanup;
+
+    rv = 0;
+
+cleanup:
+    if (rv < 0) {
+        virNetMessageSaveError(rerr);
+        VIR_FREE(ret->state);
+    }
+    virMutexUnlock(&priv->lock);
+    return rv;
+}
+
+
+static int lockDispatchInquire(virNetServerPtr server ATTRIBUTE_UNUSED,
+                               virNetServerClientPtr client,
+                               virNetMessageHeaderPtr hdr ATTRIBUTE_UNUSED,
+                               virNetMessageErrorPtr rerr,
+                               lock_inquire_args *args,
+                               lock_inquire_ret *ret)
+{
+    int rv = -1;
+    virLockDaemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
+
+    virMutexLock(&priv->lock);
+
+    if (!priv->manager) {
+        virLockError(VIR_ERR_INTERNAL_ERROR, "%s", _("lock manager not open"));
+        goto cleanup;
+    }
+
+    if (priv->restrictAccess) {
+        virLockError(VIR_ERR_OPERATION_DENIED, "%s",
+                     _("lock manager has been restricted"));
+        goto cleanup;
+    }
+
+    if (VIR_ALLOC(ret->state) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    if (virLockManagerInquire(priv->manager,
+                              ret->state,
+                              args->flags) < 0)
+        goto cleanup;
+
+    rv = 0;
+
+cleanup:
+    if (rv < 0) {
+        virNetMessageSaveError(rerr);
+        VIR_FREE(ret->state);
+    }
+    virMutexUnlock(&priv->lock);
+    return rv;
+}
diff --git a/src/locking/lock_daemon_dispatch.h b/src/locking/lock_daemon_dispatch.h
new file mode 100644
index 0000000..601e094
--- /dev/null
+++ b/src/locking/lock_daemon_dispatch.h
@@ -0,0 +1,46 @@
+/*
+ * lock_daemon_dispatch.h: lock management daemon
+ *
+ * Copyright (C) 2006-2011 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * 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
+ *
+ * Author: Daniel P. Berrange <berrange at redhat.com>
+ */
+
+#ifndef __VIR_LOCK_DAEMON_DISPATCH_H__
+# define __VIR_LOCK_DAEMON_DISPATCH_H__
+
+# include "threads.h"
+# include "lock_manager.h"
+
+extern virNetServerProgramProc lockProcs[];
+extern size_t lockNProcs;
+
+
+typedef struct _virLockDaemonClientPrivate virLockDaemonClientPrivate;
+typedef virLockDaemonClientPrivate *virLockDaemonClientPrivatePtr;
+
+struct _virLockDaemonClientPrivate {
+    virMutex lock;
+    virLockManagerPtr manager;
+    bool restrictAccess;
+    uid_t uid;
+    pid_t pid;
+};
+
+
+#endif /* __VIR_LOCK_DAEMON_DISPATCH_H__ */
diff --git a/src/locking/virtlockd.init.in b/src/locking/virtlockd.init.in
new file mode 100644
index 0000000..1adea07
--- /dev/null
+++ b/src/locking/virtlockd.init.in
@@ -0,0 +1,93 @@
+#!/bin/sh
+
+# the following is the LSB init header see
+# http://www.linux-foundation.org/spec//booksets/LSB-Core-generic/LSB-Core-generic.html#INITSCRCOMCONV
+#
+### BEGIN INIT INFO
+# Provides: virtlockd
+# Default-Start: 3 4 5
+# Short-Description: virtual machine lock manager
+# Description: This is a daemon for managing locks
+#              on virtual machine disk images
+### END INIT INFO
+
+# the following is chkconfig init header
+#
+# virtlockd:   virtual machine lock manager
+#
+# chkconfig: 345 97 03
+# description:  This is a daemon for managing locks \
+#               on virtual machine disk images
+#
+# processname: virtlockd
+# pidfile: @localstatedir@/run/libvirt/virtlockd.pid
+#
+
+# Source function library.
+. @sysconfdir@/rc.d/init.d/functions
+
+SERVICE=virtlockd
+PROCESS=virtlockd
+PIDFILE=@localstatedir@/run/libvirt/lockd/$SERVICE.pid
+
+VIRTLOCKD_ARGS=
+
+test -f @sysconfdir@/sysconfig/virtlockd && . @sysconfdir@/sysconfig/virtlockd
+
+RETVAL=0
+
+start() {
+    echo -n $"Starting $SERVICE daemon: "
+    daemon --pidfile $PIDFILE --check $SERVICE $PROCESS --daemon $VIRTLOCKD_ARGS
+    RETVAL=$?
+    echo
+    [ $RETVAL -eq 0 ] && touch @localstatedir@/lock/subsys/$SERVICE
+}
+
+stop() {
+    echo -n $"Stopping $SERVICE daemon: "
+
+    killproc -p $PIDFILE $PROCESS
+    RETVAL=$?
+    echo
+    if [ $RETVAL -eq 0 ]; then
+        rm -f @localstatedir@/lock/subsys/$SERVICE
+        rm -f $PIDFILE
+    fi
+}
+
+restart() {
+    stop
+    start
+}
+
+reload() {
+    echo -n $"Reloading $SERVICE configuration: "
+
+    killproc -p $PIDFILE $PROCESS -HUP
+    RETVAL=$?
+    echo
+    return $RETVAL
+}
+
+# See how we were called.
+case "$1" in
+    start|stop|restart|reload)
+        $1
+        ;;
+    status)
+        status -p $PIDFILE $PROCESS
+        RETVAL=$?
+        ;;
+    force-reload)
+        reload
+        ;;
+    condrestart|try-restart)
+        [ -f @localstatedir@/lock/subsys/$SERVICE ] && restart || :
+        ;;
+    *)
+        echo $"Usage: $0 {start|stop|status|restart|condrestart|reload|force-reload|try-restart}"
+        exit 2
+        ;;
+esac
+exit $RETVAL
diff --git a/src/locking/virtlockd.sysconf b/src/locking/virtlockd.sysconf
new file mode 100644
index 0000000..d44dc46
--- /dev/null
+++ b/src/locking/virtlockd.sysconf
@@ -0,0 +1,3 @@
+#
+# Pass extra arguments to virtlockd
+#VIRTLOCKD_ARGS=
-- 
1.7.6




More information about the libvir-list mailing list