提交 c57e3d89 编写于 作者: D Daniel P. Berrange

Introduce basic infrastructure for virtlockd daemon

The virtlockd daemon will maintain locks on behalf of libvirtd.
There are two reasons for it to be separate

 - Avoid risk of other libvirtd threads accidentally
   releasing fcntl() locks by opening + closing a file
   that is locked
 - Ensure locks can be preserved across libvirtd restarts.
   virtlockd will need to be able to re-exec itself while
   maintaining locks. This is simpler to achieve if its
   sole job is maintaining locks
Signed-off-by: NDaniel P. Berrange <berrange@redhat.com>
上级 f199f75e
...@@ -123,6 +123,8 @@ ...@@ -123,6 +123,8 @@
/src/test_libvirt*.aug /src/test_libvirt*.aug
/src/util/virkeymaps.h /src/util/virkeymaps.h
/src/virt-aa-helper /src/virt-aa-helper
/src/virtlockd
/src/virtlockd.init
/tests/*.log /tests/*.log
/tests/*.pid /tests/*.pid
/tests/*xml2*test /tests/*xml2*test
......
...@@ -655,6 +655,8 @@ sc_prohibit_cross_inclusion: ...@@ -655,6 +655,8 @@ sc_prohibit_cross_inclusion:
@for dir in $(cross_dirs); do \ @for dir in $(cross_dirs); do \
case $$dir in \ case $$dir in \
util/) safe="util";; \ util/) safe="util";; \
locking/) \
safe="($$dir|util|conf|rpc)";; \
cpu/ | locking/ | network/ | rpc/ | security/) \ cpu/ | locking/ | network/ | rpc/ | security/) \
safe="($$dir|util|conf)";; \ safe="($$dir|util|conf)";; \
xenapi/ | xenxs/ ) safe="($$dir|util|conf|xen)";; \ xenapi/ | xenxs/ ) safe="($$dir|util|conf|xen)";; \
...@@ -743,7 +745,7 @@ $(srcdir)/src/remote/remote_client_bodies.h: $(srcdir)/src/remote/remote_protoco ...@@ -743,7 +745,7 @@ $(srcdir)/src/remote/remote_client_bodies.h: $(srcdir)/src/remote/remote_protoco
# List all syntax-check exemptions: # List all syntax-check exemptions:
exclude_file_name_regexp--sc_avoid_strcase = ^tools/virsh\.h$$ exclude_file_name_regexp--sc_avoid_strcase = ^tools/virsh\.h$$
_src1=libvirt|fdstream|qemu/qemu_monitor|util/(command|util)|xen/xend_internal|rpc/virnetsocket|lxc/lxc_controller _src1=libvirt|fdstream|qemu/qemu_monitor|util/(command|util)|xen/xend_internal|rpc/virnetsocket|lxc/lxc_controller|locking/lock_daemon
exclude_file_name_regexp--sc_avoid_write = \ exclude_file_name_regexp--sc_avoid_write = \
^(src/($(_src1))|daemon/libvirtd|tools/console|tests/(shunload|virnettlscontext)test)\.c$$ ^(src/($(_src1))|daemon/libvirtd|tools/console|tests/(shunload|virnettlscontext)test)\.c$$
...@@ -776,7 +778,7 @@ exclude_file_name_regexp--sc_prohibit_close = \ ...@@ -776,7 +778,7 @@ exclude_file_name_regexp--sc_prohibit_close = \
exclude_file_name_regexp--sc_prohibit_empty_lines_at_EOF = \ exclude_file_name_regexp--sc_prohibit_empty_lines_at_EOF = \
(^tests/(qemuhelp|nodeinfo)data/|\.(gif|ico|png|diff)$$) (^tests/(qemuhelp|nodeinfo)data/|\.(gif|ico|png|diff)$$)
_src2=src/(util/command|libvirt|lxc/lxc_controller) _src2=src/(util/command|libvirt|lxc/lxc_controller|locking/lock_daemon)
exclude_file_name_regexp--sc_prohibit_fork_wrappers = \ exclude_file_name_regexp--sc_prohibit_fork_wrappers = \
(^($(_src2)|tests/testutils|daemon/libvirtd)\.c$$) (^($(_src2)|tests/testutils|daemon/libvirtd)\.c$$)
......
...@@ -1662,9 +1662,11 @@ fi ...@@ -1662,9 +1662,11 @@ fi
%else %else
%{_sysconfdir}/rc.d/init.d/libvirtd %{_sysconfdir}/rc.d/init.d/libvirtd
%{_sysconfdir}/rc.d/init.d/libvirt-guests %{_sysconfdir}/rc.d/init.d/libvirt-guests
%{_sysconfdir}/rc.d/init.d/virtlockd
%endif %endif
%doc daemon/libvirtd.upstart %doc daemon/libvirtd.upstart
%config(noreplace) %{_sysconfdir}/sysconfig/libvirtd %config(noreplace) %{_sysconfdir}/sysconfig/libvirtd
%config(noreplace) %{_sysconfdir}/sysconfig/virtlockd
%config(noreplace) %{_sysconfdir}/libvirt/libvirtd.conf %config(noreplace) %{_sysconfdir}/libvirt/libvirtd.conf
%if 0%{?fedora} >= 14 || 0%{?rhel} >= 6 %if 0%{?fedora} >= 14 || 0%{?rhel} >= 6
%config(noreplace) %{_sysconfdir}/sysctl.d/libvirtd %config(noreplace) %{_sysconfdir}/sysctl.d/libvirtd
...@@ -1731,6 +1733,10 @@ rm -f $RPM_BUILD_ROOT%{_sysconfdir}/sysctl.d/libvirtd ...@@ -1731,6 +1733,10 @@ rm -f $RPM_BUILD_ROOT%{_sysconfdir}/sysctl.d/libvirtd
%dir %attr(0755, root, root) %{_localstatedir}/lib/libvirt/dnsmasq/ %dir %attr(0755, root, root) %{_localstatedir}/lib/libvirt/dnsmasq/
%endif %endif
%if %{with_libvirtd}
%dir %attr(0755, root, root) %{_libdir}/libvirt/lock-driver
%endif
%if %{with_qemu} %if %{with_qemu}
%{_datadir}/augeas/lenses/libvirtd_qemu.aug %{_datadir}/augeas/lenses/libvirtd_qemu.aug
%{_datadir}/augeas/lenses/tests/test_libvirtd_qemu.aug %{_datadir}/augeas/lenses/tests/test_libvirtd_qemu.aug
...@@ -1764,6 +1770,7 @@ rm -f $RPM_BUILD_ROOT%{_sysconfdir}/sysctl.d/libvirtd ...@@ -1764,6 +1770,7 @@ rm -f $RPM_BUILD_ROOT%{_sysconfdir}/sysctl.d/libvirtd
%attr(0755, root, root) %{_libexecdir}/libvirt_iohelper %attr(0755, root, root) %{_libexecdir}/libvirt_iohelper
%attr(0755, root, root) %{_sbindir}/libvirtd %attr(0755, root, root) %{_sbindir}/libvirtd
%attr(0755, root, root) %{_sbindir}/virtlockd
%{_mandir}/man8/libvirtd.8* %{_mandir}/man8/libvirtd.8*
......
...@@ -48,6 +48,8 @@ src/interface/interface_backend_udev.c ...@@ -48,6 +48,8 @@ src/interface/interface_backend_udev.c
src/internal.h src/internal.h
src/libvirt.c src/libvirt.c
src/libvirt-qemu.c src/libvirt-qemu.c
src/locking/lock_daemon.c
src/locking/lock_daemon_config.c
src/locking/lock_driver_sanlock.c src/locking/lock_driver_sanlock.c
src/locking/lock_manager.c src/locking/lock_manager.c
src/locking/sanlock_helper.c src/locking/sanlock_helper.c
......
...@@ -148,6 +148,13 @@ LOCK_DRIVER_SANLOCK_SOURCES = \ ...@@ -148,6 +148,13 @@ LOCK_DRIVER_SANLOCK_SOURCES = \
LOCK_DRIVER_SANLOCK_HELPER_SOURCES = \ LOCK_DRIVER_SANLOCK_HELPER_SOURCES = \
locking/sanlock_helper.c locking/sanlock_helper.c
LOCK_DAEMON_SOURCES = \
locking/lock_daemon.h \
locking/lock_daemon.c \
locking/lock_daemon_config.h \
locking/lock_daemon_config.c \
$(NULL)
NETDEV_CONF_SOURCES = \ NETDEV_CONF_SOURCES = \
conf/netdev_bandwidth_conf.h conf/netdev_bandwidth_conf.c \ conf/netdev_bandwidth_conf.h conf/netdev_bandwidth_conf.c \
conf/netdev_vport_profile_conf.h conf/netdev_vport_profile_conf.c \ conf/netdev_vport_profile_conf.h conf/netdev_vport_profile_conf.c \
...@@ -1510,6 +1517,76 @@ libvirt_qemu_la_CFLAGS = $(AM_CFLAGS) ...@@ -1510,6 +1517,76 @@ libvirt_qemu_la_CFLAGS = $(AM_CFLAGS)
libvirt_qemu_la_LIBADD = libvirt.la $(CYGWIN_EXTRA_LIBADD) libvirt_qemu_la_LIBADD = libvirt.la $(CYGWIN_EXTRA_LIBADD)
EXTRA_DIST += $(LIBVIRT_QEMU_SYMBOL_FILE) EXTRA_DIST += $(LIBVIRT_QEMU_SYMBOL_FILE)
if WITH_LIBVIRTD
sbin_PROGRAMS = virtlockd
virtlockd_SOURCES = $(LOCK_DAEMON_SOURCES)
virtlockd_CFLAGS = \
$(AM_CFLAGS) \
$(NULL)
virtlockd_LDFLAGS = \
$(AM_LDFLAGS) \
$(CYGWIN_EXTRA_LDFLAGS) \
$(MINGW_EXTRA_LDFLAGS) \
$(NULL)
virtlockd_LDADD = \
libvirt-net-rpc-server.la \
libvirt-net-rpc.la \
libvirt_util.la \
../gnulib/lib/libgnu.la \
$(CYGWIN_EXTRA_LIBADD) \
$(NULL)
if WITH_DTRACE_PROBES
virtlockd_LDADD += libvirt_probes.lo
endif
else
EXTRA_DIST += $(LOCK_DAEMON_SOURCES)
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 if HAVE_SANLOCK
lockdriverdir = $(libdir)/libvirt/lock-driver lockdriverdir = $(libdir)/libvirt/lock-driver
lockdriver_LTLIBRARIES = sanlock.la lockdriver_LTLIBRARIES = sanlock.la
...@@ -1747,7 +1824,11 @@ endif ...@@ -1747,7 +1824,11 @@ endif
endif endif
EXTRA_DIST += $(SECURITY_DRIVER_APPARMOR_HELPER_SOURCES) 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)/cache/libvirt"
$(MKDIR_P) "$(DESTDIR)$(localstatedir)/lib/libvirt/images" $(MKDIR_P) "$(DESTDIR)$(localstatedir)/lib/libvirt/images"
$(MKDIR_P) "$(DESTDIR)$(localstatedir)/lib/libvirt/filesystems" $(MKDIR_P) "$(DESTDIR)$(localstatedir)/lib/libvirt/filesystems"
...@@ -1796,7 +1877,11 @@ if WITH_NETWORK ...@@ -1796,7 +1877,11 @@ if WITH_NETWORK
$(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/autostart/default.xml $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/autostart/default.xml
endif 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)/cache/libvirt" ||:
rmdir "$(DESTDIR)$(localstatedir)/lib/libvirt/images" ||: rmdir "$(DESTDIR)$(localstatedir)/lib/libvirt/images" ||:
rmdir "$(DESTDIR)$(localstatedir)/lib/libvirt/filesystems" ||: rmdir "$(DESTDIR)$(localstatedir)/lib/libvirt/filesystems" ||:
......
此差异已折叠。
/*
* lock_daemon.h: lock management daemon
*
* 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_H__
# define __VIR_LOCK_DAEMON_H__
# include "virlockspace.h"
# include "threads.h"
typedef struct _virLockDaemon virLockDaemon;
typedef virLockDaemon *virLockDaemonPtr;
typedef struct _virLockDaemonClient virLockDaemonClient;
typedef virLockDaemonClient *virLockDaemonClientPtr;
struct _virLockDaemonClient {
virMutex lock;
pid_t clientPid;
};
extern virLockDaemonPtr lockDaemon;
#endif /* __VIR_LOCK_DAEMON_H__ */
/*
* lock_daemon_config.h: virtlockd config file handling
*
* Copyright (C) 2006-2012 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, see
* <http://www.gnu.org/licenses/>.
*
* Author: Daniel P. Berrange <berrange@redhat.com>
*/
#include <config.h>
#include "lock_daemon_config.h"
#include "conf.h"
#include "memory.h"
#include "virterror_internal.h"
#include "logging.h"
#include "rpc/virnetserver.h"
#include "configmake.h"
#define VIR_FROM_THIS VIR_FROM_CONF
/* A helper function used by each of the following macros. */
static int
checkType(virConfValuePtr p, const char *filename,
const char *key, virConfType required_type)
{
if (p->type != required_type) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("remoteReadConfigFile: %s: %s: invalid type:"
" got %s; expected %s"), filename, key,
virConfTypeName(p->type),
virConfTypeName(required_type));
return -1;
}
return 0;
}
/* If there is no config data for the key, #var_name, then do nothing.
If there is valid data of type VIR_CONF_STRING, and strdup succeeds,
store the result in var_name. Otherwise, (i.e. invalid type, or strdup
failure), give a diagnostic and "goto" the cleanup-and-fail label. */
#define GET_CONF_STR(conf, filename, var_name) \
do { \
virConfValuePtr p = virConfGetValue(conf, #var_name); \
if (p) { \
if (checkType(p, filename, #var_name, VIR_CONF_STRING) < 0) \
goto error; \
VIR_FREE(data->var_name); \
if (!(data->var_name = strdup(p->str))) { \
virReportOOMError(); \
goto error; \
} \
} \
} while (0)
/* Like GET_CONF_STR, but for integral values. */
#define GET_CONF_INT(conf, filename, var_name) \
do { \
virConfValuePtr p = virConfGetValue(conf, #var_name); \
if (p) { \
if (checkType(p, filename, #var_name, VIR_CONF_LONG) < 0) \
goto error; \
data->var_name = p->l; \
} \
} while (0)
int
virLockDaemonConfigFilePath(bool privileged, char **configfile)
{
if (privileged) {
if (!(*configfile = strdup(SYSCONFDIR "/libvirt/virtlockd.conf")))
goto no_memory;
} else {
char *configdir = NULL;
if (!(configdir = virGetUserConfigDirectory()))
goto error;
if (virAsprintf(configfile, "%s/virtlockd.conf", configdir) < 0) {
VIR_FREE(configdir);
goto no_memory;
}
VIR_FREE(configdir);
}
return 0;
no_memory:
virReportOOMError();
error:
return -1;
}
virLockDaemonConfigPtr
virLockDaemonConfigNew(bool privileged ATTRIBUTE_UNUSED)
{
virLockDaemonConfigPtr data;
if (VIR_ALLOC(data) < 0) {
virReportOOMError();
return NULL;
}
data->log_buffer_size = 64;
return data;
}
void
virLockDaemonConfigFree(virLockDaemonConfigPtr data)
{
if (!data)
return;
VIR_FREE(data->log_filters);
VIR_FREE(data->log_outputs);
VIR_FREE(data);
}
static int
virLockDaemonConfigLoadOptions(virLockDaemonConfigPtr data,
const char *filename,
virConfPtr conf)
{
GET_CONF_INT(conf, filename, log_level);
GET_CONF_STR(conf, filename, log_filters);
GET_CONF_STR(conf, filename, log_outputs);
GET_CONF_INT(conf, filename, log_buffer_size);
return 0;
error:
return -1;
}
/* Read the config file if it exists.
* Only used in the remote case, hence the name.
*/
int
virLockDaemonConfigLoadFile(virLockDaemonConfigPtr data,
const char *filename,
bool allow_missing)
{
virConfPtr conf;
int ret;
if (allow_missing &&
access(filename, R_OK) == -1 &&
errno == ENOENT)
return 0;
conf = virConfReadFile(filename, 0);
if (!conf)
return -1;
ret = virLockDaemonConfigLoadOptions(data, filename, conf);
virConfFree(conf);
return ret;
}
int virLockDaemonConfigLoadData(virLockDaemonConfigPtr data,
const char *filename,
const char *filedata)
{
virConfPtr conf;
int ret;
conf = virConfReadMem(filedata, strlen(filedata), 0);
if (!conf)
return -1;
ret = virLockDaemonConfigLoadOptions(data, filename, conf);
virConfFree(conf);
return ret;
}
/*
* lock_daemon_config.h: virtlockd config file handling
*
* Copyright (C) 2006-2012 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, see
* <http://www.gnu.org/licenses/>.
*
* Author: Daniel P. Berrange <berrange@redhat.com>
*/
#ifndef __VIR_LOCK_DAEMON_CONFIG_H__
# define __VIR_LOCK_DAEMON_CONFIG_H__
# include "internal.h"
typedef struct _virLockDaemonConfig virLockDaemonConfig;
typedef virLockDaemonConfig *virLockDaemonConfigPtr;
struct _virLockDaemonConfig {
int log_level;
char *log_filters;
char *log_outputs;
int log_buffer_size;
};
int virLockDaemonConfigFilePath(bool privileged, char **configfile);
virLockDaemonConfigPtr virLockDaemonConfigNew(bool privileged);
void virLockDaemonConfigFree(virLockDaemonConfigPtr data);
int virLockDaemonConfigLoadFile(virLockDaemonConfigPtr data,
const char *filename,
bool allow_missing);
int virLockDaemonConfigLoadData(virLockDaemonConfigPtr data,
const char *filename,
const char *filedata);
#endif /* __LIBVIRTD_CONFIG_H__ */
#!/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
#
# Pass extra arguments to virtlockd
#VIRTLOCKD_ARGS=
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册