1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00

lvmpolld: Add standalone polldaemon.

See doc/lvmpolld_overview.txt
This commit is contained in:
Ondrej Kozina 2015-05-09 00:59:18 +01:00 committed by Alasdair G Kergon
parent be23fae488
commit e587b0677b
227 changed files with 3547 additions and 49 deletions

View File

@ -1,5 +1,7 @@
Version 2.02.120 -
===============================
Add lvpoll for cmdline communication with lvmpolld.
Add lvmpolld acting as a free-standing version of polldaemon.
Properly validate PV size for pvcreate --restorefile.
Fix check if pvcreate wiped device (2.02.117).
Fix storing of vgid when caching metadata (2.02.118).

View File

@ -938,6 +938,16 @@ global {
# Comments starting with the character # are ignored.
# This configuration option does not have a default value defined.
# system_id_file = ""
# Indicates whether to use lvmpolld instead of classical polldaemon (a process
# forked off an initiating lvm command) or not. When set to 1 and native systemd
# service is installed in the system lvm starts using lvmpolld. lvmpolld gets
# auto-activated by systemd when a message lands on the respective lvmpolld socket.
# All commands that would require polling of in-progress operation are therefore
# spawned in lvmpolld's service cgroup.
#
# When set to 0 lvm falls back to classical polling.
use_lvmpolld = 0
}
# Configuration section activation.

49
configure vendored
View File

@ -636,6 +636,7 @@ kerneldir
interface
CMIRRORD_PIDFILE
CLVMD_PIDFILE
LVMPOLLD_PIDFILE
LVMETAD_PIDFILE
DMEVENTD_PIDFILE
WRITE_INSTALL
@ -724,6 +725,7 @@ CLDWHOLEARCHIVE
CLDNOWHOLEARCHIVE
CLDFLAGS
CACHE
BUILD_LVMPOLLD
BUILD_LVMETAD
BUILD_DMEVENTD
BUILD_CMIRRORD
@ -914,6 +916,8 @@ enable_valgrind_pool
enable_devmapper
enable_lvmetad
with_lvmetad_pidfile
enable_lvmpolld
with_lvmpolld_pidfile
enable_blkid_wiping
enable_udev_systemd_background_jobs
enable_udev_sync
@ -1627,6 +1631,7 @@ Optional Features:
--enable-valgrind-pool enable valgrind awareness of pools
--disable-devmapper disable LVM2 device-mapper interaction
--enable-lvmetad enable the LVM Metadata Daemon
--enable-lvmpolld enable the LVM Polling Daemon
--disable-blkid_wiping disable libblkid detection of signatures when wiping
and use native code instead
--disable-udev-systemd-background-jobs
@ -1718,6 +1723,8 @@ Optional Packages:
--with-optimisation=OPT C optimisation flag [OPT=-O2]
--with-lvmetad-pidfile=PATH
lvmetad pidfile [PID_DIR/lvmetad.pid]
--with-lvmpolld-pidfile=PATH
lvmpolld pidfile [PID_DIR/lvmpolld.pid]
--with-localedir=DIR translation files in DIR [PREFIX/share/locale]
--with-confdir=DIR configuration files in DIR [/etc]
--with-staticdir=DIR static binaries in DIR [EPREFIX/sbin]
@ -3033,6 +3040,7 @@ case "$host_os" in
LIB_SUFFIX=so
DEVMAPPER=yes
LVMETAD=no
LVMPOLLD=no
ODIRECT=yes
DM_IOCTLS=yes
SELINUX=yes
@ -10855,6 +10863,39 @@ _ACEOF
fi
################################################################################
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build lvmpolld" >&5
$as_echo_n "checking whether to build lvmpolld... " >&6; }
# Check whether --enable-lvmpolld was given.
if test "${enable_lvmpolld+set}" = set; then :
enableval=$enable_lvmpolld; LVMPOLLD=$enableval
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $LVMPOLLD" >&5
$as_echo "$LVMPOLLD" >&6; }
BUILD_LVMPOLLD=$LVMPOLLD
if test "$BUILD_LVMPOLLD" = yes; then
$as_echo "#define LVMPOLLD_SUPPORT 1" >>confdefs.h
# Check whether --with-lvmpolld-pidfile was given.
if test "${with_lvmpolld_pidfile+set}" = set; then :
withval=$with_lvmpolld_pidfile; LVMPOLLD_PIDFILE=$withval
else
LVMPOLLD_PIDFILE="$DEFAULT_PID_DIR/lvmpolld.pid"
fi
cat >>confdefs.h <<_ACEOF
#define LVMPOLLD_PIDFILE "$LVMPOLLD_PIDFILE"
_ACEOF
fi
################################################################################
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable libblkid detection of signatures when wiping" >&5
$as_echo_n "checking whether to enable libblkid detection of signatures when wiping... " >&6; }
@ -13144,11 +13185,13 @@ LVM_LIBAPI=`echo "$VER" | $AWK -F '[()]' '{print $2}'`
################################################################################
ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/lvm2/Makefile daemons/dmeventd/plugins/raid/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile daemons/dmeventd/plugins/thin/Makefile daemons/lvmetad/Makefile conf/Makefile conf/example.conf conf/lvmlocal.conf conf/command_profile_template.profile conf/metadata_profile_template.profile include/.symlinks include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile lib/replicator/Makefile lib/misc/lvm-version.h lib/raid/Makefile lib/snapshot/Makefile lib/thin/Makefile lib/cache_segtype/Makefile libdaemon/Makefile libdaemon/client/Makefile libdaemon/server/Makefile libdm/Makefile libdm/libdevmapper.pc liblvm/Makefile liblvm/liblvm2app.pc man/Makefile po/Makefile python/Makefile python/setup.py scripts/blkdeactivate.sh scripts/blk_availability_init_red_hat scripts/blk_availability_systemd_red_hat.service scripts/clvmd_init_red_hat scripts/cmirrord_init_red_hat scripts/dm_event_systemd_red_hat.service scripts/dm_event_systemd_red_hat.socket scripts/lvm2_cluster_activation_red_hat.sh scripts/lvm2_cluster_activation_systemd_red_hat.service scripts/lvm2_clvmd_systemd_red_hat.service scripts/lvm2_cmirrord_systemd_red_hat.service scripts/lvm2_lvmetad_init_red_hat scripts/lvm2_lvmetad_systemd_red_hat.service scripts/lvm2_lvmetad_systemd_red_hat.socket scripts/lvm2_monitoring_init_red_hat scripts/lvm2_monitoring_systemd_red_hat.service scripts/lvm2_pvscan_systemd_red_hat@.service scripts/lvm2_tmpfiles_red_hat.conf scripts/Makefile test/Makefile test/api/Makefile test/unit/Makefile tools/Makefile udev/Makefile unit-tests/datastruct/Makefile unit-tests/regex/Makefile unit-tests/mm/Makefile"
ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile daemons/cmirrord/Makefile daemons/dmeventd/Makefile daemons/dmeventd/libdevmapper-event.pc daemons/dmeventd/plugins/Makefile daemons/dmeventd/plugins/lvm2/Makefile daemons/dmeventd/plugins/raid/Makefile daemons/dmeventd/plugins/mirror/Makefile daemons/dmeventd/plugins/snapshot/Makefile daemons/dmeventd/plugins/thin/Makefile daemons/lvmetad/Makefile daemons/lvmpolld/Makefile conf/Makefile conf/example.conf conf/lvmlocal.conf conf/command_profile_template.profile conf/metadata_profile_template.profile include/.symlinks include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile lib/replicator/Makefile lib/misc/lvm-version.h lib/raid/Makefile lib/snapshot/Makefile lib/thin/Makefile lib/cache_segtype/Makefile libdaemon/Makefile libdaemon/client/Makefile libdaemon/server/Makefile libdm/Makefile libdm/libdevmapper.pc liblvm/Makefile liblvm/liblvm2app.pc man/Makefile po/Makefile python/Makefile python/setup.py scripts/blkdeactivate.sh scripts/blk_availability_init_red_hat scripts/blk_availability_systemd_red_hat.service scripts/clvmd_init_red_hat scripts/cmirrord_init_red_hat scripts/dm_event_systemd_red_hat.service scripts/dm_event_systemd_red_hat.socket scripts/lvm2_cluster_activation_red_hat.sh scripts/lvm2_cluster_activation_systemd_red_hat.service scripts/lvm2_clvmd_systemd_red_hat.service scripts/lvm2_cmirrord_systemd_red_hat.service scripts/lvm2_lvmetad_init_red_hat scripts/lvm2_lvmetad_systemd_red_hat.service scripts/lvm2_lvmetad_systemd_red_hat.socket scripts/lvm2_lvmpolld_init_red_hat scripts/lvm2_lvmpolld_systemd_red_hat.service scripts/lvm2_lvmpolld_systemd_red_hat.socket scripts/lvm2_monitoring_init_red_hat scripts/lvm2_monitoring_systemd_red_hat.service scripts/lvm2_pvscan_systemd_red_hat@.service scripts/lvm2_tmpfiles_red_hat.conf scripts/Makefile test/Makefile test/api/Makefile test/unit/Makefile tools/Makefile udev/Makefile unit-tests/datastruct/Makefile unit-tests/regex/Makefile unit-tests/mm/Makefile"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
@ -13857,6 +13900,7 @@ do
"daemons/dmeventd/plugins/snapshot/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/dmeventd/plugins/snapshot/Makefile" ;;
"daemons/dmeventd/plugins/thin/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/dmeventd/plugins/thin/Makefile" ;;
"daemons/lvmetad/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/lvmetad/Makefile" ;;
"daemons/lvmpolld/Makefile") CONFIG_FILES="$CONFIG_FILES daemons/lvmpolld/Makefile" ;;
"conf/Makefile") CONFIG_FILES="$CONFIG_FILES conf/Makefile" ;;
"conf/example.conf") CONFIG_FILES="$CONFIG_FILES conf/example.conf" ;;
"conf/lvmlocal.conf") CONFIG_FILES="$CONFIG_FILES conf/lvmlocal.conf" ;;
@ -13900,6 +13944,9 @@ do
"scripts/lvm2_lvmetad_init_red_hat") CONFIG_FILES="$CONFIG_FILES scripts/lvm2_lvmetad_init_red_hat" ;;
"scripts/lvm2_lvmetad_systemd_red_hat.service") CONFIG_FILES="$CONFIG_FILES scripts/lvm2_lvmetad_systemd_red_hat.service" ;;
"scripts/lvm2_lvmetad_systemd_red_hat.socket") CONFIG_FILES="$CONFIG_FILES scripts/lvm2_lvmetad_systemd_red_hat.socket" ;;
"scripts/lvm2_lvmpolld_init_red_hat") CONFIG_FILES="$CONFIG_FILES scripts/lvm2_lvmpolld_init_red_hat" ;;
"scripts/lvm2_lvmpolld_systemd_red_hat.service") CONFIG_FILES="$CONFIG_FILES scripts/lvm2_lvmpolld_systemd_red_hat.service" ;;
"scripts/lvm2_lvmpolld_systemd_red_hat.socket") CONFIG_FILES="$CONFIG_FILES scripts/lvm2_lvmpolld_systemd_red_hat.socket" ;;
"scripts/lvm2_monitoring_init_red_hat") CONFIG_FILES="$CONFIG_FILES scripts/lvm2_monitoring_init_red_hat" ;;
"scripts/lvm2_monitoring_systemd_red_hat.service") CONFIG_FILES="$CONFIG_FILES scripts/lvm2_monitoring_systemd_red_hat.service" ;;
"scripts/lvm2_pvscan_systemd_red_hat@.service") CONFIG_FILES="$CONFIG_FILES scripts/lvm2_pvscan_systemd_red_hat@.service" ;;

View File

@ -39,6 +39,7 @@ case "$host_os" in
LIB_SUFFIX=so
DEVMAPPER=yes
LVMETAD=no
LVMPOLLD=no
ODIRECT=yes
DM_IOCTLS=yes
SELINUX=yes
@ -1077,6 +1078,29 @@ if test "$BUILD_LVMETAD" = yes; then
[Path to lvmetad pidfile.])
fi
################################################################################
dnl -- Build lvmpolld
AC_MSG_CHECKING(whether to build lvmpolld)
AC_ARG_ENABLE(lvmpolld,
AC_HELP_STRING([--enable-lvmpolld],
[enable the LVM Polling Daemon]),
LVMPOLLD=$enableval)
AC_MSG_RESULT($LVMPOLLD)
BUILD_LVMPOLLD=$LVMPOLLD
if test "$BUILD_LVMPOLLD" = yes; then
AC_DEFINE([LVMPOLLD_SUPPORT], 1, [Define to 1 to include code that uses lvmpolld.])
AC_ARG_WITH(lvmpolld-pidfile,
AC_HELP_STRING([--with-lvmpolld-pidfile=PATH],
[lvmpolld pidfile [PID_DIR/lvmpolld.pid]]),
LVMPOLLD_PIDFILE=$withval,
LVMPOLLD_PIDFILE="$DEFAULT_PID_DIR/lvmpolld.pid")
AC_DEFINE_UNQUOTED(LVMPOLLD_PIDFILE, ["$LVMPOLLD_PIDFILE"],
[Path to lvmpolld pidfile.])
fi
################################################################################
dnl -- Enable blkid wiping functionality
AC_MSG_CHECKING(whether to enable libblkid detection of signatures when wiping)
@ -1687,6 +1711,7 @@ AC_SUBST(BLKID_WIPING)
AC_SUBST(BUILD_CMIRRORD)
AC_SUBST(BUILD_DMEVENTD)
AC_SUBST(BUILD_LVMETAD)
AC_SUBST(BUILD_LVMPOLLD)
AC_SUBST(CACHE)
AC_SUBST(CFLAGS)
AC_SUBST(CFLOW_CMD)
@ -1805,6 +1830,7 @@ AC_SUBST(VALGRIND_POOL)
AC_SUBST(WRITE_INSTALL)
AC_SUBST(DMEVENTD_PIDFILE)
AC_SUBST(LVMETAD_PIDFILE)
AC_SUBST(LVMPOLLD_PIDFILE)
AC_SUBST(CLVMD_PIDFILE)
AC_SUBST(CMIRRORD_PIDFILE)
AC_SUBST(interface)
@ -1838,6 +1864,7 @@ daemons/dmeventd/plugins/mirror/Makefile
daemons/dmeventd/plugins/snapshot/Makefile
daemons/dmeventd/plugins/thin/Makefile
daemons/lvmetad/Makefile
daemons/lvmpolld/Makefile
conf/Makefile
conf/example.conf
conf/lvmlocal.conf
@ -1881,6 +1908,9 @@ scripts/lvm2_cmirrord_systemd_red_hat.service
scripts/lvm2_lvmetad_init_red_hat
scripts/lvm2_lvmetad_systemd_red_hat.service
scripts/lvm2_lvmetad_systemd_red_hat.socket
scripts/lvm2_lvmpolld_init_red_hat
scripts/lvm2_lvmpolld_systemd_red_hat.service
scripts/lvm2_lvmpolld_systemd_red_hat.socket
scripts/lvm2_monitoring_init_red_hat
scripts/lvm2_monitoring_systemd_red_hat.service
scripts/lvm2_pvscan_systemd_red_hat@.service

View File

@ -1,5 +1,5 @@
#
# Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
# Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved.
#
# This file is part of LVM2.
#
@ -15,7 +15,7 @@ srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = @top_builddir@
.PHONY: dmeventd clvmd cmirrord lvmetad
.PHONY: dmeventd clvmd cmirrord lvmetad lvmpolld
ifneq ("@CLVMD@", "none")
SUBDIRS += clvmd
@ -36,8 +36,12 @@ ifeq ("@BUILD_LVMETAD@", "yes")
SUBDIRS += lvmetad
endif
ifeq ("@BUILD_LVMPOLLD@", "yes")
SUBDIRS += lvmpolld
endif
ifeq ($(MAKECMDGOALS),distclean)
SUBDIRS = clvmd cmirrord dmeventd lvmetad
SUBDIRS = clvmd cmirrord dmeventd lvmetad lvmpolld
endif
include $(top_builddir)/make.tmpl

View File

@ -0,0 +1,49 @@
#
# Copyright (C) 2014-2015 Red Hat, Inc.
#
# This file is part of LVM2.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU Lesser General Public License v.2.1.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
srcdir = @srcdir@
top_srcdir = @top_srcdir@
top_builddir = @top_builddir@
SOURCES = lvmpolld-core.c lvmpolld-data-utils.c lvmpolld-cmd-utils.c
TARGETS = lvmpolld
.PHONY: install_lvmpolld
CFLOW_LIST = $(SOURCES)
CFLOW_LIST_TARGET = $(LIB_NAME).cflow
CFLOW_TARGET = lvmpolld
include $(top_builddir)/make.tmpl
INCLUDES += -I$(top_srcdir)/libdaemon/server
LVMLIBS = -ldaemonserver $(LVMINTERNAL_LIBS) -ldevmapper
LIBS += $(PTHREAD_LIBS)
LDFLAGS += -L$(top_builddir)/libdaemon/server $(DAEMON_LDFLAGS)
CLDFLAGS += -L$(top_builddir)/libdaemon/server
CFLAGS += $(DAEMON_CFLAGS)
lvmpolld: $(OBJECTS) $(top_builddir)/libdaemon/client/libdaemonclient.a \
$(top_builddir)/libdaemon/server/libdaemonserver.a
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) \
$(DL_LIBS) $(LVMLIBS) $(LIBS)
install_lvmpolld: lvmpolld
$(INSTALL_PROGRAM) -D $< $(sbindir)/$(<F)
install_lvm2: install_lvmpolld
install: install_lvm2

View File

@ -0,0 +1,140 @@
/*
* Copyright (C) 2015 Red Hat, Inc.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "lvmpolld-common.h"
/* extract this info from autoconf/automake files */
#define LVPOLL_CMD "lvpoll"
#define MIN_ARGV_SIZE 8
static const char *const const polling_ops[] = { [PVMOVE] = LVMPD_REQ_PVMOVE,
[CONVERT] = LVMPD_REQ_CONVERT,
[MERGE] = LVMPD_REQ_MERGE,
[MERGE_THIN] = LVMPD_REQ_MERGE_THIN };
const char *polling_op(enum poll_type type)
{
return type < POLL_TYPE_MAX ? polling_ops[type] : "<undefined>";
}
static int add_to_cmd_arr(const char ***cmdargv, const char *str, unsigned *ind)
{
const char **newargv = *cmdargv;
if (*ind && !(*ind % MIN_ARGV_SIZE)) {
newargv = dm_realloc(*cmdargv, (*ind / MIN_ARGV_SIZE + 1) * MIN_ARGV_SIZE * sizeof(char *));
if (!newargv)
return 0;
*cmdargv = newargv;
}
*(*cmdargv + (*ind)++) = str;
return 1;
}
const char **cmdargv_ctr(const struct lvmpolld_lv *pdlv, const char *lvm_binary, unsigned abort_polling, unsigned handle_missing_pvs)
{
unsigned i = 0;
const char **cmd_argv = dm_malloc(MIN_ARGV_SIZE * sizeof(char *));
if (!cmd_argv)
return NULL;
/* path to lvm2 binary */
if (!add_to_cmd_arr(&cmd_argv, lvm_binary, &i))
goto err;
/* cmd to execute */
if (!add_to_cmd_arr(&cmd_argv, LVPOLL_CMD, &i))
goto err;
/* transfer internal polling interval */
if (pdlv->sinterval &&
(!add_to_cmd_arr(&cmd_argv, "--interval", &i) ||
!add_to_cmd_arr(&cmd_argv, pdlv->sinterval, &i)))
goto err;
/* pass abort param */
if (abort_polling &&
!add_to_cmd_arr(&cmd_argv, "--abort", &i))
goto err;
/* pass handle-missing-pvs. used by mirror polling operation */
if (handle_missing_pvs &&
!add_to_cmd_arr(&cmd_argv, "--handlemissingpvs", &i))
goto err;
/* one of: "convert", "pvmove", "merge", "merge_thin" */
if (!add_to_cmd_arr(&cmd_argv, "--polloperation", &i) ||
!add_to_cmd_arr(&cmd_argv, polling_ops[pdlv->type], &i))
goto err;
/* vg/lv name */
if (!add_to_cmd_arr(&cmd_argv, pdlv->lvname, &i))
goto err;
/* terminating NULL */
if (!add_to_cmd_arr(&cmd_argv, NULL, &i))
goto err;
return cmd_argv;
err:
dm_free(cmd_argv);
return NULL;
}
/* FIXME: in fact exclude should be va list */
static int copy_env(const char ***cmd_envp, unsigned *i, const char *exclude)
{
const char * const* tmp = (const char * const*) environ;
if (!tmp)
return 0;
while (*tmp) {
if (strncmp(*tmp, exclude, strlen(exclude)) && !add_to_cmd_arr(cmd_envp, *tmp, i))
return 0;
tmp++;
}
return 1;
}
const char **cmdenvp_ctr(const struct lvmpolld_lv *pdlv)
{
unsigned i = 0;
const char **cmd_envp = dm_malloc(MIN_ARGV_SIZE * sizeof(char *));
if (!cmd_envp)
return NULL;
/* copy whole environment from lvmpolld, exclude LVM_SYSTEM_DIR if set */
if (!copy_env(&cmd_envp, &i, "LVM_SYSTEM_DIR="))
goto err;
/* Add per client LVM_SYSTEM_DIR variable if set */
if (*pdlv->lvm_system_dir_env && !add_to_cmd_arr(&cmd_envp, pdlv->lvm_system_dir_env, &i))
goto err;
/* terminating NULL */
if (!add_to_cmd_arr(&cmd_envp, NULL, &i))
goto err;
return cmd_envp;
err:
dm_free(cmd_envp);
return NULL;
}

View File

@ -0,0 +1,25 @@
/*
* Copyright (C) 2015 Red Hat, Inc.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _LVM_LVMPOLLD_CMD_UTILS_H
#define _LVM_LVMPOLLD_CMD_UTILS_H
#include "lvmpolld-data-utils.h"
const char **cmdargv_ctr(const struct lvmpolld_lv *pdlv, const char *lvm_binary, unsigned abort, unsigned handle_missing_pvs);
const char **cmdenvp_ctr(const struct lvmpolld_lv *pdlv);
const char *polling_op(enum poll_type);
#endif /* _LVM_LVMPOLLD_CMD_UTILS_H */

View File

@ -0,0 +1,36 @@
/*
* Copyright (C) 2010-2015 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* This file must be included first by every lvmpolld source file.
*/
#ifndef _LVM_LVMPOLLD_COMMON_H
#define _LVM_LVMPOLLD_COMMON_H
#include "configure.h"
#define _REENTRANT
#define _GNU_SOURCE
#define _FILE_OFFSET_BITS 64
#include "libdevmapper.h"
#include "lvmpolld-cmd-utils.h"
#include "lvmpolld-protocol.h"
#include <assert.h>
#include <errno.h>
#include <unistd.h>
#endif /* _LVM_LVMPOLLD_COMMON_H */

View File

@ -0,0 +1,817 @@
/*
* Copyright (C) 2014-2015 Red Hat, Inc.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "lvmpolld-common.h"
#include "lvm-version.h"
#include "daemon-server.h"
#include "daemon-log.h"
#include <poll.h>
#include <wait.h>
#define LVMPOLLD_SOCKET DEFAULT_RUN_DIR "/lvmpolld.socket"
#define PD_LOG_PREFIX "LVMPOLLD"
#define LVM2_LOG_PREFIX "\tLVPOLL"
/* predefined reason for response = "failed" case */
#define REASON_REQ_NOT_IMPLEMENTED "request not implemented"
#define REASON_MISSING_LVID "request requires lvid set"
#define REASON_MISSING_LVNAME "request requires lvname set"
#define REASON_MISSING_VGNAME "request requires vgname set"
#define REASON_POLLING_FAILED "polling of lvm command failed"
#define REASON_ILLEGAL_ABORT_REQUEST "abort only supported with PVMOVE polling operation"
#define REASON_DIFFERENT_OPERATION_IN_PROGRESS "Different operation on LV already in progress"
#define REASON_INVALID_INTERVAL "request requires interval set"
#define REASON_ENOMEM "not enough memory"
struct lvmpolld_state {
daemon_idle *idle;
log_state *log;
const char *log_config;
const char *lvm_binary;
struct lvmpolld_store *id_to_pdlv_abort;
struct lvmpolld_store *id_to_pdlv_poll;
};
static pthread_key_t key;
static const char *_strerror_r(int errnum, struct lvmpolld_thread_data *data)
{
#ifdef _GNU_SOURCE
return strerror_r(errnum, data->buf, sizeof(data->buf)); /* never returns NULL */
#elif (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600)
return strerror_r(errnum, data->buf, sizeof(data->buf)) ? "" : data->buf;
#else
# warning "Can't decide proper strerror_r implementation. lvmpolld will not issue specific system error messages"
return "";
#endif
}
static void usage(const char *prog, FILE *file)
{
fprintf(file, "Usage:\n"
"%s [-V] [-h] [-f] [-l {all|wire|debug}] [-s path]\n\n"
" -V Show version info\n"
" -h Show this help information\n"
" -f Don't fork, run in the foreground\n"
" -l Logging message level (-l {all|wire|debug})\n"
" -p Set path to the pidfile\n"
" -s Set path to the socket to listen on\n"
" -B Path to lvm2 binary\n"
" -t Time to wait in seconds before shutdown on idle (missing or 0 = inifinite)\n\n", prog);
}
static int init(struct daemon_state *s)
{
struct lvmpolld_state *ls = s->private;
ls->log = s->log;
if (!daemon_log_parse(ls->log, DAEMON_LOG_OUTLET_STDERR, ls->log_config, 1))
return 0;
if (pthread_key_create(&key, lvmpolld_thread_data_destroy)) {
FATAL(ls, "%s: %s", PD_LOG_PREFIX, "Failed to create pthread key");
return 0;
}
ls->id_to_pdlv_poll = pdst_init("polling");
ls->id_to_pdlv_abort = pdst_init("abort");
if (!ls->id_to_pdlv_poll || !ls->id_to_pdlv_abort) {
FATAL(ls, "%s: %s", PD_LOG_PREFIX, "Failed to allocate internal data structures");
return 0;
}
ls->lvm_binary = ls->lvm_binary ?: LVM_PATH;
if (access(ls->lvm_binary, X_OK)) {
FATAL(ls, "%s: %s %s", PD_LOG_PREFIX, "Execute access rights denied on", ls->lvm_binary);
return 0;
}
if (ls->idle)
ls->idle->is_idle = 1;
return 1;
}
static void lvmpolld_stores_lock(struct lvmpolld_state *ls)
{
pdst_lock(ls->id_to_pdlv_poll);
pdst_lock(ls->id_to_pdlv_abort);
}
static void lvmpolld_stores_unlock(struct lvmpolld_state *ls)
{
pdst_unlock(ls->id_to_pdlv_abort);
pdst_unlock(ls->id_to_pdlv_poll);
}
static void lvmpolld_global_lock(struct lvmpolld_state *ls)
{
lvmpolld_stores_lock(ls);
pdst_locked_lock_all_pdlvs(ls->id_to_pdlv_poll);
pdst_locked_lock_all_pdlvs(ls->id_to_pdlv_abort);
}
static void lvmpolld_global_unlock(struct lvmpolld_state *ls)
{
pdst_locked_unlock_all_pdlvs(ls->id_to_pdlv_abort);
pdst_locked_unlock_all_pdlvs(ls->id_to_pdlv_poll);
lvmpolld_stores_unlock(ls);
}
static int fini(struct daemon_state *s)
{
int done;
const struct timespec t = { .tv_nsec = 250000000 }; /* .25 sec */
struct lvmpolld_state *ls = s->private;
DEBUGLOG(s, "fini");
DEBUGLOG(s, "sending cancel requests");
lvmpolld_global_lock(ls);
pdst_locked_send_cancel(ls->id_to_pdlv_poll);
pdst_locked_send_cancel(ls->id_to_pdlv_abort);
lvmpolld_global_unlock(ls);
DEBUGLOG(s, "waiting for background threads to finish");
while(1) {
lvmpolld_stores_lock(ls);
done = !pdst_locked_get_active_count(ls->id_to_pdlv_poll) &&
!pdst_locked_get_active_count(ls->id_to_pdlv_abort);
lvmpolld_stores_unlock(ls);
if (done)
break;
nanosleep(&t, NULL);
}
DEBUGLOG(s, "destroying internal data structures");
lvmpolld_stores_lock(ls);
pdst_locked_destroy_all_pdlvs(ls->id_to_pdlv_poll);
pdst_locked_destroy_all_pdlvs(ls->id_to_pdlv_abort);
lvmpolld_stores_unlock(ls);
pdst_destroy(ls->id_to_pdlv_poll);
pdst_destroy(ls->id_to_pdlv_abort);
pthread_key_delete(key);
return 1;
}
static response reply(const char *res, const char *reason)
{
return daemon_reply_simple(res, "reason = %s", reason, NULL);
}
static int read_single_line(struct lvmpolld_thread_data *data, int err)
{
ssize_t r = getline(&data->line, &data->line_size, err ? data->ferr : data->fout);
if (r > 0 && *(data->line + r - 1) == '\n')
*(data->line + r - 1) = '\0';
return (r > 0);
}
static void update_idle_state(struct lvmpolld_state *ls)
{
if (!ls->idle)
return;
lvmpolld_stores_lock(ls);
ls->idle->is_idle = !pdst_locked_get_active_count(ls->id_to_pdlv_poll) &&
!pdst_locked_get_active_count(ls->id_to_pdlv_abort);
lvmpolld_stores_unlock(ls);
DEBUGLOG(ls, "%s: %s %s%s", PD_LOG_PREFIX, "daemon is", ls->idle->is_idle ? "" : "not ", "idle");
}
/* make this configurable */
#define MAX_TIMEOUT 2
static int poll_for_output(struct lvmpolld_lv *pdlv, struct lvmpolld_thread_data *data)
{
int ch_stat, r, err = 1, fds_count = 2, timeout = 0;
pid_t pid;
struct lvmpolld_cmd_stat cmd_state = { .retcode = -1, .signal = 0 };
struct pollfd fds[] = { { .fd = data->outpipe[0], .events = POLLIN },
{ .fd = data->errpipe[0], .events = POLLIN } };
if (!(data->fout = fdopen(data->outpipe[0], "r")) || !(data->ferr = fdopen(data->errpipe[0], "r"))) {
ERROR(pdlv->ls, "%s: %s: (%d) %s", PD_LOG_PREFIX, "failed to open file stream",
errno, _strerror_r(errno, data));
goto out;
}
while (1) {
do {
r = poll(fds, 2, pdlv_get_timeout(pdlv) * 1000);
} while (r < 0 && errno == EINTR);
DEBUGLOG(pdlv->ls, "%s: %s %d", PD_LOG_PREFIX, "poll() returned", r);
if (r < 0) {
ERROR(pdlv->ls, "%s: %s (PID %d) failed: (%d) %s",
PD_LOG_PREFIX, "poll() for LVM2 cmd", pdlv->cmd_pid,
errno, _strerror_r(errno, data));
goto out;
} else if (!r) {
timeout++;
WARN(pdlv->ls, "%s: %s (PID %d) %s", PD_LOG_PREFIX,
"polling for output of the lvm cmd", pdlv->cmd_pid,
"has timed out");
if (timeout > MAX_TIMEOUT) {
ERROR(pdlv->ls, "%s: %s (PID %d) (no output for %d seconds)",
PD_LOG_PREFIX,
"LVM2 cmd is unresponsive too long",
pdlv->cmd_pid,
timeout * pdlv_get_timeout(pdlv));
goto out;
}
continue; /* while(1) */
}
timeout = 0;
/* handle the command's STDOUT */
if (fds[0].revents & POLLIN) {
DEBUGLOG(pdlv->ls, "%s: %s", PD_LOG_PREFIX, "caught input data in STDOUT");
assert(read_single_line(data, 0)); /* may block indef. anyway */
INFO(pdlv->ls, "%s: PID %d: %s: '%s'", LVM2_LOG_PREFIX,
pdlv->cmd_pid, "STDOUT", data->line);
} else if (fds[0].revents) {
if (fds[0].revents & POLLHUP)
DEBUGLOG(pdlv->ls, "%s: %s", PD_LOG_PREFIX, "caught POLLHUP");
else
WARN(pdlv->ls, "%s: %s", PD_LOG_PREFIX, "poll for command's STDOUT failed");
fds[0].fd = -1;
fds_count--;
}
/* handle the command's STDERR */
if (fds[1].revents & POLLIN) {
DEBUGLOG(pdlv->ls, "%s: %s", PD_LOG_PREFIX,
"caught input data in STDERR");
assert(read_single_line(data, 1)); /* may block indef. anyway */
INFO(pdlv->ls, "%s: PID %d: %s: '%s'", LVM2_LOG_PREFIX,
pdlv->cmd_pid, "STDERR", data->line);
} else if (fds[1].revents) {
if (fds[1].revents & POLLHUP)
DEBUGLOG(pdlv->ls, "%s: %s", PD_LOG_PREFIX, "caught err POLLHUP");
else
WARN(pdlv->ls, "%s: %s", PD_LOG_PREFIX, "poll for command's STDOUT failed");
fds[1].fd = -1;
fds_count--;
}
do {
/*
* fds_count == 0 means polling reached EOF
* or received error on both descriptors.
* In such case, just wait for command to finish
*/
pid = waitpid(pdlv->cmd_pid, &ch_stat, fds_count ? WNOHANG : 0);
} while (pid < 0 && errno == EINTR);
if (pid) {
if (pid < 0) {
ERROR(pdlv->ls, "%s: %s (PID %d) failed: (%d) %s",
PD_LOG_PREFIX, "waitpid() for lvm2 cmd",
pdlv->cmd_pid, errno,
_strerror_r(errno, data));
goto out;
}
DEBUGLOG(pdlv->ls, "%s: %s", PD_LOG_PREFIX, "child exited");
break;
}
} /* while(1) */
DEBUGLOG(pdlv->ls, "%s: %s", PD_LOG_PREFIX, "about to collect remaining lines");
if (fds[0].fd >= 0)
while (read_single_line(data, 0)) {
assert(r > 0);
INFO(pdlv->ls, "%s: PID %d: %s: %s", LVM2_LOG_PREFIX, pdlv->cmd_pid, "STDOUT", data->line);
}
if (fds[1].fd >= 0)
while (read_single_line(data, 1)) {
assert(r > 0);
INFO(pdlv->ls, "%s: PID %d: %s: %s", LVM2_LOG_PREFIX, pdlv->cmd_pid, "STDERR", data->line);
}
if (WIFEXITED(ch_stat)) {
INFO(pdlv->ls, "%s: %s (PID %d) %s (%d)", PD_LOG_PREFIX,
"lvm2 cmd", pdlv->cmd_pid, "exited with", WEXITSTATUS(ch_stat));
cmd_state.retcode = WEXITSTATUS(ch_stat);
} else if (WIFSIGNALED(ch_stat)) {
WARN(pdlv->ls, "%s: %s (PID %d) %s (%d)", PD_LOG_PREFIX,
"lvm2 cmd", pdlv->cmd_pid, "got terminated by signal",
WTERMSIG(ch_stat));
cmd_state.signal = WTERMSIG(ch_stat);
}
err = 0;
out:
if (!err)
pdlv_set_cmd_state(pdlv, &cmd_state);
return err;
}
static void debug_print(struct lvmpolld_state *ls, const char * const* ptr)
{
const char * const* tmp = ptr;
if (!tmp)
return;
while (*tmp) {
DEBUGLOG(ls, "%s: %s", PD_LOG_PREFIX, *tmp);
tmp++;
}
}
static void *fork_and_poll(void *args)
{
int outfd, errfd, state;
struct lvmpolld_thread_data *data;
pid_t r;
int error = 1;
struct lvmpolld_lv *pdlv = (struct lvmpolld_lv *) args;
struct lvmpolld_state *ls = pdlv->ls;
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
data = lvmpolld_thread_data_constructor(pdlv);
pthread_setspecific(key, data);
pthread_setcancelstate(state, &state);
if (!data) {
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "Failed to initialize per-thread data");
goto err;
}
DEBUGLOG(ls, "%s: %s", PD_LOG_PREFIX, "cmd line arguments:");
debug_print(ls, pdlv->cmdargv);
DEBUGLOG(ls, "%s: %s", PD_LOG_PREFIX, "---end---");
DEBUGLOG(ls, "%s: %s", PD_LOG_PREFIX, "cmd environment variables:");
debug_print(ls, pdlv->cmdenvp);
DEBUGLOG(ls, "%s: %s", PD_LOG_PREFIX, "---end---");
outfd = data->outpipe[1];
errfd = data->errpipe[1];
r = fork();
if (!r) {
/* child */
/* !!! Do not touch any posix thread primitives !!! */
if ((dup2(outfd, STDOUT_FILENO ) != STDOUT_FILENO) ||
(dup2(errfd, STDERR_FILENO ) != STDERR_FILENO))
_exit(100);
execve(*(pdlv->cmdargv), (char *const *)pdlv->cmdargv, (char *const *)pdlv->cmdenvp);
_exit(101);
} else {
/* parent */
if (r == -1) {
ERROR(ls, "%s: %s: (%d) %s", PD_LOG_PREFIX, "fork failed",
errno, _strerror_r(errno, data));
goto err;
}
INFO(ls, "%s: LVM2 cmd \"%s\" (PID: %d)", PD_LOG_PREFIX, *(pdlv->cmdargv), r);
pdlv->cmd_pid = r;
/* failure to close write end of any pipe will result in broken polling */
if (close(data->outpipe[1])) {
ERROR(ls, "%s: %s: (%d) %s", PD_LOG_PREFIX, "failed to close write end of pipe",
errno, _strerror_r(errno, data));
goto err;
}
data->outpipe[1] = -1;
if (close(data->errpipe[1])) {
ERROR(ls, "%s: %s: (%d) %s", PD_LOG_PREFIX, "failed to close write end of err pipe",
errno, _strerror_r(errno, data));
goto err;
}
data->errpipe[1] = -1;
error = poll_for_output(pdlv, data);
DEBUGLOG(ls, "%s: %s", PD_LOG_PREFIX, "polling for lvpoll output has finished");
}
err:
r = 0;
pdst_lock(pdlv->pdst);
if (error) {
/* last reader is responsible for pdlv cleanup */
r = pdlv->cmd_pid;
pdlv_set_error(pdlv, 1);
}
pdlv_set_polling_finished(pdlv, 1);
if (data)
data->pdlv = NULL;
pdst_locked_dec(pdlv->pdst);
pdst_unlock(pdlv->pdst);
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
lvmpolld_thread_data_destroy(data);
pthread_setspecific(key, NULL);
pthread_setcancelstate(state, &state);
update_idle_state(ls);
/*
* This is unfortunate case where we
* know nothing about state of lvm cmd and
* (eventually) ongoing progress.
*
* harvest zombies
*/
if (r)
while(waitpid(r, NULL, 0) < 0 && errno == EINTR);
return NULL;
}
static response progress_info(client_handle h, struct lvmpolld_state *ls, request req)
{
char *id;
struct lvmpolld_lv *pdlv;
struct lvmpolld_store *pdst;
struct lvmpolld_lv_state st;
response r;
const char *lvid = daemon_request_str(req, LVMPD_PARM_LVID, NULL);
const char *sysdir = daemon_request_str(req, LVMPD_PARM_SYSDIR, NULL);
unsigned abort_polling = daemon_request_int(req, LVMPD_PARM_ABORT, 0);
if (!lvid)
return reply(LVMPD_RESP_FAILED, REASON_MISSING_LVID);
id = construct_id(sysdir, lvid);
if (!id) {
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "progress_info request failed to construct ID.");
return reply(LVMPD_RESP_FAILED, REASON_ENOMEM);
}
DEBUGLOG(ls, "%s: %s: %s", PD_LOG_PREFIX, "ID", id);
pdst = abort_polling ? ls->id_to_pdlv_abort : ls->id_to_pdlv_poll;
pdst_lock(pdst);
pdlv = pdst_locked_lookup(pdst, id);
if (pdlv) {
/*
* with store lock held, I'm the only reader accessing the pdlv
*/
st = pdlv_get_status(pdlv);
if (st.error || st.polling_finished) {
INFO(ls, "%s: %s %s", PD_LOG_PREFIX,
"Polling finished. Removing related data structure for LV",
lvid);
pdst_locked_remove(pdst, id);
pdlv_destroy(pdlv);
}
}
/* pdlv must not be dereferenced from now on */
pdst_unlock(pdst);
dm_free(id);
if (pdlv) {
if (st.error)
return reply(LVMPD_RESP_FAILED, REASON_POLLING_FAILED);
if (st.polling_finished)
r = daemon_reply_simple(LVMPD_RESP_FINISHED,
"reason = %s", st.cmd_state.signal ? LVMPD_REAS_SIGNAL : LVMPD_REAS_RETCODE,
LVMPD_PARM_VALUE " = %d", st.cmd_state.signal ?: st.cmd_state.retcode,
NULL);
else
r = daemon_reply_simple(LVMPD_RESP_IN_PROGRESS, NULL);
}
else
r = daemon_reply_simple(LVMPD_RESP_NOT_FOUND, NULL);
return r;
}
static struct lvmpolld_lv *construct_pdlv(request req, struct lvmpolld_state *ls,
struct lvmpolld_store *pdst,
const char *interval, const char *id,
const char *vgname, const char *lvname,
const char *sysdir, enum poll_type type,
unsigned abort_polling, unsigned uinterval)
{
const char **cmdargv, **cmdenvp;
struct lvmpolld_lv *pdlv;
unsigned handle_missing_pvs = daemon_request_int(req, LVMPD_PARM_HANDLE_MISSING_PVS, 0);
pdlv = pdlv_create(ls, id, vgname, lvname, sysdir, type,
interval, uinterval, pdst);
if (!pdlv) {
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "failed to create internal LV data structure.");
return NULL;
}
cmdargv = cmdargv_ctr(pdlv, pdlv->ls->lvm_binary, abort_polling, handle_missing_pvs);
if (!cmdargv) {
pdlv_destroy(pdlv);
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "failed to construct cmd arguments for lvpoll command");
return NULL;
}
cmdenvp = cmdenvp_ctr(pdlv);
if (!cmdenvp) {
pdlv_destroy(pdlv);
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "failed to construct cmd environment for lvpoll command");
return NULL;
}
pdlv->cmdargv = cmdargv;
pdlv->cmdenvp = cmdenvp;
return pdlv;
}
static int spawn_detached_thread(struct lvmpolld_lv *pdlv)
{
int r;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
r = pthread_create(&pdlv->tid, &attr, fork_and_poll, (void *)pdlv);
pthread_attr_destroy(&attr);
return !r;
}
static response poll_init(client_handle h, struct lvmpolld_state *ls, request req, enum poll_type type)
{
char *id;
struct lvmpolld_lv *pdlv;
struct lvmpolld_store *pdst;
unsigned uinterval;
const char *interval = daemon_request_str(req, LVMPD_PARM_INTERVAL, NULL);
const char *lvid = daemon_request_str(req, LVMPD_PARM_LVID, NULL);
const char *lvname = daemon_request_str(req, LVMPD_PARM_LVNAME, NULL);
const char *vgname = daemon_request_str(req, LVMPD_PARM_VGNAME, NULL);
const char *sysdir = daemon_request_str(req, LVMPD_PARM_SYSDIR, NULL);
unsigned abort_polling = daemon_request_int(req, LVMPD_PARM_ABORT, 0);
assert(type < POLL_TYPE_MAX);
if (abort_polling && type != PVMOVE)
return reply(LVMPD_RESP_EINVAL, REASON_ILLEGAL_ABORT_REQUEST);
if (!interval || strpbrk(interval, "-") || sscanf(interval, "%u", &uinterval) != 1)
return reply(LVMPD_RESP_EINVAL, REASON_INVALID_INTERVAL);
if (!lvname)
return reply(LVMPD_RESP_FAILED, REASON_MISSING_LVNAME);
if (!lvid)
return reply(LVMPD_RESP_FAILED, REASON_MISSING_LVID);
if (!vgname)
return reply(LVMPD_RESP_FAILED, REASON_MISSING_VGNAME);
id = construct_id(sysdir, lvid);
if (!id) {
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "poll_init request failed to construct ID.");
return reply(LVMPD_RESP_FAILED, REASON_ENOMEM);
}
DEBUGLOG(ls, "%s: %s=%s", PD_LOG_PREFIX, "ID", id);
pdst = abort_polling ? ls->id_to_pdlv_abort : ls->id_to_pdlv_poll;
pdst_lock(pdst);
pdlv = pdst_locked_lookup(pdst, id);
if (pdlv && pdlv_get_polling_finished(pdlv)) {
WARN(ls, "%s: %s %s", PD_LOG_PREFIX, "Force removal of uncollected info for LV",
lvid);
/*
* lvmpolld has to remove uncollected results in this case.
* otherwise it would have to refuse request for new polling
* lv with same id.
*/
pdst_locked_remove(pdst, id);
pdlv_destroy(pdlv);
pdlv = NULL;
}
if (pdlv) {
if (!pdlv_is_type(pdlv, type)) {
pdst_unlock(pdst);
ERROR(ls, "%s: %s '%s': expected: %s, requested: %s",
PD_LOG_PREFIX, "poll operation type mismatch on LV identified by",
id,
polling_op(pdlv_get_type(pdlv)), polling_op(type));
dm_free(id);
return reply(LVMPD_RESP_EINVAL,
REASON_DIFFERENT_OPERATION_IN_PROGRESS);
}
pdlv->init_rq_count++; /* safe. protected by store lock */
} else {
pdlv = construct_pdlv(req, ls, pdst, interval, id, vgname,
lvname, sysdir, type, abort_polling, 2 * uinterval);
if (!pdlv) {
pdst_unlock(pdst);
dm_free(id);
return reply(LVMPD_RESP_FAILED, REASON_ENOMEM);
}
if (!pdst_locked_insert(pdst, id, pdlv)) {
pdlv_destroy(pdlv);
pdst_unlock(pdst);
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "couldn't store internal LV data structure");
dm_free(id);
return reply(LVMPD_RESP_FAILED, REASON_ENOMEM);
}
if (!spawn_detached_thread(pdlv)) {
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "failed to spawn detached monitoring thread");
pdst_locked_remove(pdst, id);
pdlv_destroy(pdlv);
pdst_unlock(pdst);
dm_free(id);
return reply(LVMPD_RESP_FAILED, REASON_ENOMEM);
}
pdst_locked_inc(pdst);
if (ls->idle)
ls->idle->is_idle = 0;
}
pdst_unlock(pdst);
dm_free(id);
return daemon_reply_simple(LVMPD_RESP_OK, NULL);
}
static response dump_state(client_handle h, struct lvmpolld_state *ls, request r)
{
response res = { 0 };
struct buffer *b = &res.buffer;
buffer_init(b);
lvmpolld_global_lock(ls);
buffer_append(b, "# Registered polling operations\n\n");
buffer_append(b, "poll {\n");
pdst_locked_dump(ls->id_to_pdlv_poll, b);
buffer_append(b, "}\n\n");
buffer_append(b, "# Registered abort operations\n\n");
buffer_append(b, "abort {\n");
pdst_locked_dump(ls->id_to_pdlv_abort, b);
buffer_append(b, "}\n\n");
lvmpolld_global_unlock(ls);
return res;
}
static response handler(struct daemon_state s, client_handle h, request r)
{
struct lvmpolld_state *ls = s.private;
const char *rq = daemon_request_str(r, "request", "NONE");
if (!strcmp(rq, LVMPD_REQ_PVMOVE))
return poll_init(h, ls, r, PVMOVE);
else if (!strcmp(rq, LVMPD_REQ_CONVERT))
return poll_init(h, ls, r, CONVERT);
else if (!strcmp(rq, LVMPD_REQ_MERGE))
return poll_init(h, ls, r, MERGE);
else if (!strcmp(rq, LVMPD_REQ_MERGE_THIN))
return poll_init(h, ls, r, MERGE_THIN);
else if (!strcmp(rq, LVMPD_REQ_PROGRESS))
return progress_info(h, ls, r);
else if (!strcmp(rq, LVMPD_REQ_DUMP))
return dump_state(h, ls, r);
else
return reply(LVMPD_RESP_EINVAL, REASON_REQ_NOT_IMPLEMENTED);
}
static int process_timeout_arg(const char *str, unsigned *max_timeouts)
{
char *endptr;
unsigned long l;
l = strtoul(str, &endptr, 10);
if (errno || *endptr || l >= UINT_MAX)
return 0;
*max_timeouts = (unsigned) l;
return 1;
}
int main(int argc, char *argv[])
{
signed char opt;
struct timeval timeout;
daemon_idle di = { .ptimeout = &timeout };
struct lvmpolld_state ls = { .log_config = "" };
daemon_state s = {
.daemon_fini = fini,
.daemon_init = init,
.handler = handler,
.name = "lvmpolld",
.pidfile = getenv("LVM_LVMPOLLD_PIDFILE") ?: LVMPOLLD_PIDFILE,
.private = &ls,
.protocol = LVMPOLLD_PROTOCOL,
.protocol_version = LVMPOLLD_PROTOCOL_VERSION,
.socket_path = getenv("LVM_LVMPOLLD_SOCKET") ?: LVMPOLLD_SOCKET,
};
while ((opt = getopt(argc, argv, "?fhVl:p:s:B:t:")) != EOF) {
switch (opt) {
case '?':
usage(argv[0], stderr);
exit(0);
case 'B': /* --binary */
ls.lvm_binary = optarg;
break;
case 'V':
printf("lvmpolld version: " LVM_VERSION "\n");
exit(1);
case 'f':
s.foreground = 1;
break;
case 'h':
usage(argv[0], stdout);
exit(0);
case 'l':
ls.log_config = optarg;
break;
case 'p':
s.pidfile = optarg;
break;
case 's': /* --socket */
s.socket_path = optarg;
break;
case 't': /* --timeout in seconds */
if (!process_timeout_arg(optarg, &di.max_timeouts)) {
fprintf(stderr, "Invalid value of timeout parameter");
exit(1);
}
/* 0 equals to wait indefinitely */
if (di.max_timeouts)
s.idle = ls.idle = &di;
break;
}
}
daemon_start(s);
return 0;
}

View File

@ -0,0 +1,388 @@
/*
* Copyright (C) 2014-2015 Red Hat, Inc.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "lvmpolld-common.h"
#include "config-util.h"
#include <fcntl.h>
#include <signal.h>
static char *_construct_full_lvname(const char *vgname, const char *lvname)
{
char *name;
size_t l;
l = strlen(vgname) + strlen(lvname) + 2; /* vg/lv and \0 */
name = (char *) dm_malloc(l * sizeof(char));
if (!name)
return NULL;
if (dm_snprintf(name, l, "%s/%s", vgname, lvname) < 0) {
dm_free(name);
name = NULL;
}
return name;
}
static char *_construct_lvm_system_dir_env(const char *sysdir)
{
/*
* Store either "LVM_SYSTEM_DIR=/path/to..."
* - or -
* just single char to store NULL byte
*/
size_t l = sysdir ? strlen(sysdir) + 16 : 1;
char *env = (char *) dm_malloc(l * sizeof(char));
if (!env)
return NULL;
*env = '\0';
if (sysdir && dm_snprintf(env, l, "LVM_SYSTEM_DIR=%s", sysdir) < 0) {
dm_free(env);
env = NULL;
}
return env;
}
static const char *_get_lvid(const char *lvmpolld_id, const char *sysdir)
{
return lvmpolld_id ? (lvmpolld_id + (sysdir ? strlen(sysdir) : 0)) : NULL;
}
char *construct_id(const char *sysdir, const char *uuid)
{
char *id;
int r;
size_t l;
l = strlen(uuid) + (sysdir ? strlen(sysdir) : 0) + 1;
id = (char *) dm_malloc(l * sizeof(char));
if (!id)
return NULL;
r = sysdir ? dm_snprintf(id, l, "%s%s", sysdir, uuid) :
dm_snprintf(id, l, "%s", uuid);
if (r < 0) {
dm_free(id);
id = NULL;
}
return id;
}
struct lvmpolld_lv *pdlv_create(struct lvmpolld_state *ls, const char *id,
const char *vgname, const char *lvname,
const char *sysdir, enum poll_type type,
const char *sinterval, unsigned pdtimeout,
struct lvmpolld_store *pdst)
{
char *lvmpolld_id = dm_strdup(id), /* copy */
*full_lvname = _construct_full_lvname(vgname, lvname), /* copy */
*lvm_system_dir_env = _construct_lvm_system_dir_env(sysdir); /* copy */
struct lvmpolld_lv tmp = {
.ls = ls,
.type = type,
.lvmpolld_id = lvmpolld_id,
.lvid = _get_lvid(lvmpolld_id, sysdir),
.lvname = full_lvname,
.lvm_system_dir_env = lvm_system_dir_env,
.sinterval = dm_strdup(sinterval), /* copy */
.pdtimeout = pdtimeout < MIN_POLLING_TIMEOUT ? MIN_POLLING_TIMEOUT : pdtimeout,
.cmd_state = { .retcode = -1, .signal = 0 },
.pdst = pdst,
.init_rq_count = 1
}, *pdlv = (struct lvmpolld_lv *) dm_malloc(sizeof(struct lvmpolld_lv));
if (!pdlv || !tmp.lvid || !tmp.lvname || !tmp.lvm_system_dir_env || !tmp.sinterval)
goto err;
memcpy(pdlv, &tmp, sizeof(*pdlv));
if (pthread_mutex_init(&pdlv->lock, NULL))
goto err;
return pdlv;
err:
dm_free((void *)full_lvname);
dm_free((void *)lvmpolld_id);
dm_free((void *)lvm_system_dir_env);
dm_free((void *)tmp.sinterval);
dm_free((void *)pdlv);
return NULL;
}
void pdlv_destroy(struct lvmpolld_lv *pdlv)
{
dm_free((void *)pdlv->lvmpolld_id);
dm_free((void *)pdlv->lvname);
dm_free((void *)pdlv->sinterval);
dm_free((void *)pdlv->lvm_system_dir_env);
dm_free((void *)pdlv->cmdargv);
dm_free((void *)pdlv->cmdenvp);
pthread_mutex_destroy(&pdlv->lock);
dm_free((void *)pdlv);
}
unsigned pdlv_get_polling_finished(struct lvmpolld_lv *pdlv)
{
unsigned ret;
pdlv_lock(pdlv);
ret = pdlv->polling_finished;
pdlv_unlock(pdlv);
return ret;
}
struct lvmpolld_lv_state pdlv_get_status(struct lvmpolld_lv *pdlv)
{
struct lvmpolld_lv_state r;
pdlv_lock(pdlv);
r.error = pdlv_locked_error(pdlv);
r.polling_finished = pdlv_locked_polling_finished(pdlv);
r.cmd_state = pdlv_locked_cmd_state(pdlv);
pdlv_unlock(pdlv);
return r;
}
void pdlv_set_cmd_state(struct lvmpolld_lv *pdlv, const struct lvmpolld_cmd_stat *cmd_state)
{
pdlv_lock(pdlv);
pdlv->cmd_state = *cmd_state;
pdlv_unlock(pdlv);
}
void pdlv_set_error(struct lvmpolld_lv *pdlv, unsigned error)
{
pdlv_lock(pdlv);
pdlv->error = error;
pdlv_unlock(pdlv);
}
void pdlv_set_polling_finished(struct lvmpolld_lv *pdlv, unsigned finished)
{
pdlv_lock(pdlv);
pdlv->polling_finished = finished;
pdlv_unlock(pdlv);
}
struct lvmpolld_store *pdst_init(const char *name)
{
struct lvmpolld_store *pdst = (struct lvmpolld_store *) dm_malloc(sizeof(struct lvmpolld_store));
if (!pdst)
return NULL;
pdst->store = dm_hash_create(32);
if (!pdst->store)
goto err_hash;
if (pthread_mutex_init(&pdst->lock, NULL))
goto err_mutex;
pdst->name = name;
return pdst;
err_mutex:
dm_hash_destroy(pdst->store);
err_hash:
dm_free(pdst);
return NULL;
}
void pdst_destroy(struct lvmpolld_store *pdst)
{
if (!pdst)
return;
dm_hash_destroy(pdst->store);
pthread_mutex_destroy(&pdst->lock);
dm_free(pdst);
}
void pdst_locked_lock_all_pdlvs(const struct lvmpolld_store *pdst)
{
struct dm_hash_node *n;
dm_hash_iterate(n, pdst->store)
pdlv_lock(dm_hash_get_data(pdst->store, n));
}
void pdst_locked_unlock_all_pdlvs(const struct lvmpolld_store *pdst)
{
struct dm_hash_node *n;
dm_hash_iterate(n, pdst->store)
pdlv_unlock(dm_hash_get_data(pdst->store, n));
}
static void _pdlv_locked_dump(struct buffer *buff, const struct lvmpolld_lv *pdlv)
{
char tmp[1024];
const struct lvmpolld_cmd_stat *cmd_state = &pdlv->cmd_state;
/* pdlv-section { */
if (dm_snprintf(tmp, sizeof(tmp), "\t%s {\n", pdlv->lvmpolld_id) > 0)
buffer_append(buff, tmp);
if (dm_snprintf(tmp, sizeof(tmp), "\t\tlvid=\"%s\"\n", pdlv->lvid) > 0)
buffer_append(buff, tmp);
if (dm_snprintf(tmp, sizeof(tmp), "\t\ttype=\"%s\"\n", polling_op(pdlv->type)) > 0)
buffer_append(buff, tmp);
if (dm_snprintf(tmp, sizeof(tmp), "\t\tlvname=\"%s\"\n", pdlv->lvname) > 0)
buffer_append(buff, tmp);
if (dm_snprintf(tmp, sizeof(tmp), "\t\tlvmpolld_internal_timeout=%d\n", pdlv->pdtimeout) > 0)
buffer_append(buff, tmp);
if (dm_snprintf(tmp, sizeof(tmp), "\t\tlvm_command_interval=\"%s\"\n", pdlv->sinterval ?: "<undefined>") > 0)
buffer_append(buff, tmp);
if (dm_snprintf(tmp, sizeof(tmp), "\t\tLVM_SYSTEM_DIR=\"%s\"\n",
(*pdlv->lvm_system_dir_env ? (pdlv->lvm_system_dir_env + strlen("LVM_SYSTEM_DIR=")) : "<undefined>")) > 0)
buffer_append(buff, tmp);
if (dm_snprintf(tmp, sizeof(tmp), "\t\tlvm_command_pid=%d\n", pdlv->cmd_pid) > 0)
buffer_append(buff, tmp);
if (dm_snprintf(tmp, sizeof(tmp), "\t\tpolling_finished=%d\n", pdlv->polling_finished) > 0)
buffer_append(buff, tmp);
if (dm_snprintf(tmp, sizeof(tmp), "\t\terror_occured=%d\n", pdlv->error) > 0)
buffer_append(buff, tmp);
if (dm_snprintf(tmp, sizeof(tmp), "\t\tinit_requests_count=%d\n", pdlv->init_rq_count) > 0)
buffer_append(buff, tmp);
/* lvm_commmand-section { */
buffer_append(buff, "\t\tlvm_command {\n");
if (cmd_state->retcode == -1 && !cmd_state->signal)
buffer_append(buff, "\t\t\tstate=\"" LVMPD_RESP_IN_PROGRESS "\"\n");
else {
buffer_append(buff, "\t\t\tstate=\"" LVMPD_RESP_FINISHED "\"\n");
if (dm_snprintf(tmp, sizeof(tmp), "\t\t\treason=\"%s\"\n\t\t\tvalue=%d\n",
(cmd_state->signal ? LVMPD_REAS_SIGNAL : LVMPD_REAS_RETCODE),
(cmd_state->signal ?: cmd_state->retcode)) > 0)
buffer_append(buff, tmp);
}
buffer_append(buff, "\t\t}\n");
/* } lvm_commmand-section */
buffer_append(buff, "\t}\n");
/* } pdlv-section */
}
void pdst_locked_dump(const struct lvmpolld_store *pdst, struct buffer *buff)
{
struct dm_hash_node *n;
dm_hash_iterate(n, pdst->store)
_pdlv_locked_dump(buff, dm_hash_get_data(pdst->store, n));
}
void pdst_locked_send_cancel(const struct lvmpolld_store *pdst)
{
struct lvmpolld_lv *pdlv;
struct dm_hash_node *n;
dm_hash_iterate(n, pdst->store) {
pdlv = dm_hash_get_data(pdst->store, n);
if (!pdlv_locked_polling_finished(pdlv))
pthread_cancel(pdlv->tid);
}
}
void pdst_locked_destroy_all_pdlvs(const struct lvmpolld_store *pdst)
{
struct dm_hash_node *n;
dm_hash_iterate(n, pdst->store)
pdlv_destroy(dm_hash_get_data(pdst->store, n));
}
struct lvmpolld_thread_data *lvmpolld_thread_data_constructor(struct lvmpolld_lv *pdlv)
{
struct lvmpolld_thread_data *data = (struct lvmpolld_thread_data *) dm_malloc(sizeof(struct lvmpolld_thread_data));
if (!data)
return NULL;
data->pdlv = NULL;
data->line = NULL;
data->fout = data->ferr = NULL;
data->outpipe[0] = data->outpipe[1] = data->errpipe[0] = data->errpipe[1] = -1;
if (pipe(data->outpipe) || pipe(data->errpipe)) {
lvmpolld_thread_data_destroy(data);
return NULL;
}
if (fcntl(data->outpipe[0], F_SETFD, FD_CLOEXEC) ||
fcntl(data->outpipe[1], F_SETFD, FD_CLOEXEC) ||
fcntl(data->errpipe[0], F_SETFD, FD_CLOEXEC) ||
fcntl(data->errpipe[1], F_SETFD, FD_CLOEXEC)) {
lvmpolld_thread_data_destroy(data);
return NULL;
}
data->pdlv = pdlv;
return data;
}
void lvmpolld_thread_data_destroy(void *thread_private)
{
struct lvmpolld_thread_data *data = (struct lvmpolld_thread_data *) thread_private;
if (!data)
return;
if (data->pdlv) {
pdst_lock(data->pdlv->pdst);
/*
* FIXME: skip this step if lvmpolld is activated
* by systemd.
*/
if (!pdlv_get_polling_finished(data->pdlv))
kill(data->pdlv->cmd_pid, SIGTERM);
pdlv_set_polling_finished(data->pdlv, 1);
pdst_locked_dec(data->pdlv->pdst);
pdst_unlock(data->pdlv->pdst);
}
dm_free(data->line);
if (data->fout && !fclose(data->fout))
data->outpipe[0] = -1;
if (data->ferr && !fclose(data->ferr))
data->errpipe[0] = -1;
if (data->outpipe[0] >= 0)
close(data->outpipe[0]);
if (data->outpipe[1] >= 0)
close(data->outpipe[1]);
if (data->errpipe[0] >= 0)
close(data->errpipe[0]);
if (data->errpipe[1] >= 0)
close(data->errpipe[1]);
dm_free(data);
}

View File

@ -0,0 +1,215 @@
/*
* Copyright (C) 2014-2015 Red Hat, Inc.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _LVM_LVMPOLLD_DATA_UTILS_H
#define _LVM_LVMPOLLD_DATA_UTILS_H
#include <pthread.h>
struct buffer;
struct lvmpolld_state;
enum poll_type {
PVMOVE = 0,
CONVERT,
MERGE,
MERGE_THIN,
POLL_TYPE_MAX
};
struct lvmpolld_cmd_stat {
int retcode;
int signal;
};
struct lvmpolld_store {
pthread_mutex_t lock;
void *store;
const char *name;
unsigned active_polling_count;
};
struct lvmpolld_lv {
/*
* accessing following vars doesn't
* require struct lvmpolld_lv lock
*/
struct lvmpolld_state *const ls;
const enum poll_type type;
const char *const lvid;
const char *const lvmpolld_id;
const char *const lvname; /* full vg/lv name */
const unsigned pdtimeout; /* in seconds */
const char *const sinterval;
const char *const lvm_system_dir_env;
struct lvmpolld_store *const pdst;
const char *const *cmdargv;
const char *const *cmdenvp;
/* only used by write */
pid_t cmd_pid;
pthread_t tid;
pthread_mutex_t lock;
/* block of shared variables protected by lock */
struct lvmpolld_cmd_stat cmd_state;
unsigned init_rq_count; /* for debuging purposes only */
unsigned polling_finished:1; /* no more updates */
unsigned error:1; /* unrecoverable error occured in lvmpolld */
};
typedef void (*lvmpolld_parse_output_fn_t) (struct lvmpolld_lv *pdlv, const char *line);
/* TODO: replace with configuration option */
#define MIN_POLLING_TIMEOUT 60
struct lvmpolld_lv_state {
unsigned error:1;
unsigned polling_finished:1;
struct lvmpolld_cmd_stat cmd_state;
};
struct lvmpolld_thread_data {
char *line;
size_t line_size;
int outpipe[2];
int errpipe[2];
FILE *fout;
FILE *ferr;
char buf[1024];
struct lvmpolld_lv *pdlv;
};
char *construct_id(const char *sysdir, const char *lvid);
/* LVMPOLLD_LV_T section */
/* only call with appropriate struct lvmpolld_store lock held */
struct lvmpolld_lv *pdlv_create(struct lvmpolld_state *ls, const char *id,
const char *vgname, const char *lvname,
const char *sysdir, enum poll_type type,
const char *sinterval, unsigned pdtimeout,
struct lvmpolld_store *pdst);
/* only call with appropriate struct lvmpolld_store lock held */
void pdlv_destroy(struct lvmpolld_lv *pdlv);
static inline void pdlv_lock(struct lvmpolld_lv *pdlv)
{
pthread_mutex_lock(&pdlv->lock);
}
static inline void pdlv_unlock(struct lvmpolld_lv *pdlv)
{
pthread_mutex_unlock(&pdlv->lock);
}
/*
* no struct lvmpolld_lv lock required section
*/
static inline int pdlv_is_type(const struct lvmpolld_lv *pdlv, enum poll_type type)
{
return pdlv->type == type;
}
static inline unsigned pdlv_get_timeout(const struct lvmpolld_lv *pdlv)
{
return pdlv->pdtimeout;
}
static inline enum poll_type pdlv_get_type(const struct lvmpolld_lv *pdlv)
{
return pdlv->type;
}
unsigned pdlv_get_polling_finished(struct lvmpolld_lv *pdlv);
struct lvmpolld_lv_state pdlv_get_status(struct lvmpolld_lv *pdlv);
void pdlv_set_cmd_state(struct lvmpolld_lv *pdlv, const struct lvmpolld_cmd_stat *cmd_state);
void pdlv_set_error(struct lvmpolld_lv *pdlv, unsigned error);
void pdlv_set_polling_finished(struct lvmpolld_lv *pdlv, unsigned finished);
/*
* struct lvmpolld_lv lock required section
*/
static inline struct lvmpolld_cmd_stat pdlv_locked_cmd_state(const struct lvmpolld_lv *pdlv)
{
return pdlv->cmd_state;
}
static inline int pdlv_locked_polling_finished(const struct lvmpolld_lv *pdlv)
{
return pdlv->polling_finished;
}
static inline unsigned pdlv_locked_error(const struct lvmpolld_lv *pdlv)
{
return pdlv->error;
}
/* struct lvmpolld_store manipulation routines */
struct lvmpolld_store *pdst_init(const char *name);
void pdst_destroy(struct lvmpolld_store *pdst);
void pdst_locked_dump(const struct lvmpolld_store *pdst, struct buffer *buff);
void pdst_locked_lock_all_pdlvs(const struct lvmpolld_store *pdst);
void pdst_locked_unlock_all_pdlvs(const struct lvmpolld_store *pdst);
void pdst_locked_destroy_all_pdlvs(const struct lvmpolld_store *pdst);
void pdst_locked_send_cancel(const struct lvmpolld_store *pdst);
static inline void pdst_lock(struct lvmpolld_store *pdst)
{
pthread_mutex_lock(&pdst->lock);
}
static inline void pdst_unlock(struct lvmpolld_store *pdst)
{
pthread_mutex_unlock(&pdst->lock);
}
static inline void pdst_locked_inc(struct lvmpolld_store *pdst)
{
pdst->active_polling_count++;
}
static inline void pdst_locked_dec(struct lvmpolld_store *pdst)
{
pdst->active_polling_count--;
}
static inline unsigned pdst_locked_get_active_count(const struct lvmpolld_store *pdst)
{
return pdst->active_polling_count;
}
static inline int pdst_locked_insert(struct lvmpolld_store *pdst, const char *key, struct lvmpolld_lv *pdlv)
{
return dm_hash_insert(pdst->store, key, pdlv);
}
static inline struct lvmpolld_lv *pdst_locked_lookup(struct lvmpolld_store *pdst, const char *key)
{
return dm_hash_lookup(pdst->store, key);
}
static inline void pdst_locked_remove(struct lvmpolld_store *pdst, const char *key)
{
dm_hash_remove(pdst->store, key);
}
struct lvmpolld_thread_data *lvmpolld_thread_data_constructor(struct lvmpolld_lv *pdlv);
void lvmpolld_thread_data_destroy(void *thread_private);
#endif /* _LVM_LVMPOLLD_DATA_UTILS_H */

View File

@ -0,0 +1,49 @@
/*
* Copyright (C) 2015 Red Hat, Inc.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _LVM_LVMPOLLD_PROTOCOL_H
#define _LVM_LVMPOLLD_PROTOCOL_H
#include "polling_ops.h"
#define LVMPOLLD_PROTOCOL "lvmpolld"
#define LVMPOLLD_PROTOCOL_VERSION 1
#define LVMPD_REQ_CONVERT CONVERT_POLL
#define LVMPD_REQ_DUMP "dump"
#define LVMPD_REQ_MERGE MERGE_POLL
#define LVMPD_REQ_MERGE_THIN MERGE_THIN_POLL
#define LVMPD_REQ_PROGRESS "progress_info"
#define LVMPD_REQ_PVMOVE PVMOVE_POLL
#define LVMPD_PARM_ABORT "abort"
#define LVMPD_PARM_HANDLE_MISSING_PVS "handle_missing_pvs"
#define LVMPD_PARM_INTERVAL "interval"
#define LVMPD_PARM_LVID "lvid"
#define LVMPD_PARM_LVNAME "lvname"
#define LVMPD_PARM_SYSDIR "sysdir"
#define LVMPD_PARM_VALUE "value" /* either retcode or signal value */
#define LVMPD_PARM_VGNAME "vgname"
#define LVMPD_RESP_FAILED "failed"
#define LVMPD_RESP_FINISHED "finished"
#define LVMPD_RESP_IN_PROGRESS "in_progress"
#define LVMPD_RESP_EINVAL "invalid"
#define LVMPD_RESP_NOT_FOUND "not_found"
#define LVMPD_RESP_OK "OK"
#define LVMPD_REAS_RETCODE "retcode" /* lvm cmd ret code */
#define LVMPD_REAS_SIGNAL "signal" /* lvm cmd terminating singal */
#endif /* _LVM_LVMPOLLD_PROTOCOL_H */

View File

@ -0,0 +1,25 @@
/*
* Copyright (C) 2014-2015 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _LVM_TOOL_POLLING_OPS_H
#define _LVM_TOOL_POLLING_OPS_H
/* this file is also part of lvmpolld protocol */
#define PVMOVE_POLL "pvmove"
#define CONVERT_POLL "convert"
#define MERGE_POLL "merge"
#define MERGE_THIN_POLL "merge_thin"
#endif /* _LVM_TOOL_POLLING_OPS_H */

81
doc/lvmpolld_overview.txt Normal file
View File

@ -0,0 +1,81 @@
LVM poll daemon overview
========================
(last updated: 2015-05-09)
LVM poll daemon (lvmpolld) is the alternative for lvm2 classical polling
mechanisms. The motivation behind new lvmpolld was to create persistent
system service that would be more durable and transparent. It's suited
particularly for any systemd enabled distribution.
Before lvmpolld any background polling process originating in a lvm2 command
initiated inside cgroup of a systemd service could get killed if the main
process (service) exited in such cgroup. That could lead to premature termination
of such lvm2 polling process.
Also without lvmpolld there were no means to detect a particular polling process
suited for monitoring of specific operation is already in-progress and therefore
it's not desirable to start next one with exactly same task. lvmpolld is able to
detect such duplicate requests and not spawn such redundant process.
lvmpolld is primarily targeted for systems with systemd as init process. For systems
without systemd there's no need to install lvmpolld because there is no issue
with observation described in second paragraph. You can still benefit from
avoiding duplicate polling process being spawned, but without systemd lvmpolld
can't easily be run on-demand (activated by a socket maintained by systemd).
lvmpolld implement shutdown on idle and can shutdown automatically when idle
for requested time. 60 second is recommended default here. This behaviour can be
turned off if found useless.
Data structures
---------------
a) Logical Volume (struct lvmpolld_lv)
Each operation is identified by LV. Internal identifier within lvmpolld
is full LV uuid (vg_uuid+lv_uuid) prefixed with LVM_SYSTEM_DIR if set by client.
such full identifier may look like:
"/etc/lvm/lvm.confWFd2dU67S8Av29IcJCnYzqQirdfElnxzhCdzEh7EJrfCn9R1TIQjIj58weUZDre4"
or without LVM_SYSTEM_DIR being set explicitly:
"WFd2dU67S8Av29IcJCnYzqQirdfElnxzhCdzEh7EJrfCn9R1TIQjIj58weUZDre4"
LV carries various metadata about polling operation. The most significant are:
VG name
LV name
polling interval (usually --interval passed to lvm2 command or default from lvm2
configuration)
operation type (one of: pvmove, convert, merge, thin_merge)
LVM_SYSTEM_DIR (if set, this is also passed among environment variables of lvpoll
command spawned by lvmpolld)
b) LV stores (struct lvmpolld_store)
lvmpolld uses two stores for Logical volumes (struct lvmpolld_lv). One store for polling
operations in-progress. These operations are as of now: PV move, mirror up-conversion,
classical snapshot merge, thin snapshot merge.
The second store is suited only for pvmove --abort operations in-progress. Both
stores are independent and identical LVs (pvmove /dev/sda3 and pvmove --abort /dev/sda3)
can be run concurently from lvmpolld point of view (on lvm2 side the consistency is
guaranteed by lvm2 locking mechanism).
Locking order
-------------
There are two types of locks in lvmpolld. Each store has own store lock and each LV has
own lv lock.
Locking order is:
1) store lock
2) LV lock
Each LV has to be inside a store. When daemon requires to take both locks it has
to take a store lock first and LV lock has to be taken afterwards (after the
appropriate store lock where the LV is being stored :))

View File

@ -1,6 +1,8 @@
@top_srcdir@/daemons/clvmd/clvm.h
@top_srcdir@/daemons/dmeventd/libdevmapper-event.h
@top_srcdir@/daemons/lvmetad/lvmetad-client.h
@top_srcdir@/daemons/lvmpolld/lvmpolld-protocol.h
@top_srcdir@/daemons/lvmpolld/polling_ops.h
@top_srcdir@/liblvm/lvm2app.h
@top_srcdir@/lib/activate/activate.h
@top_srcdir@/lib/activate/targets.h
@ -29,6 +31,8 @@
@top_srcdir@/lib/locking/locking.h
@top_srcdir@/lib/log/log.h
@top_srcdir@/lib/log/lvm-logging.h
@top_srcdir@/lib/lvmpolld/lvmpolld-client.h
@top_srcdir@/lib/lvmpolld/polldaemon.h
@top_srcdir@/lib/metadata/lv.h
@top_srcdir@/lib/metadata/lv_alloc.h
@top_srcdir@/lib/metadata/metadata.h

View File

@ -196,6 +196,11 @@ ifeq ("@BUILD_LVMETAD@", "yes")
cache/lvmetad.c
endif
ifeq ("@BUILD_LVMPOLLD@", "yes")
SOURCES +=\
lvmpolld/lvmpolld-client.c
endif
ifeq ("@DMEVENTD@", "yes")
CLDFLAGS += -L$(top_builddir)/daemons/dmeventd
LIBS += -ldevmapper-event

View File

@ -30,6 +30,7 @@
#include "lvmcache.h"
#include "lvmetad.h"
#include "archiver.h"
#include "lvmpolld-client.h"
#ifdef HAVE_LIBDL
#include "sharedlib.h"
@ -475,6 +476,7 @@ static int _process_config(struct cmd_context *cmd)
const struct dm_config_value *cv;
int64_t pv_min_kb;
const char *lvmetad_socket;
const char *lvmpolld_socket;
int udev_disabled = 0;
char sysfs_dir[PATH_MAX];
@ -618,6 +620,7 @@ static int _process_config(struct cmd_context *cmd)
(find_config_tree_bool(cmd, global_detect_internal_vg_cache_corruption_CFG, NULL));
lvmetad_disconnect();
lvmpolld_disconnect();
lvmetad_socket = getenv("LVM_LVMETAD_SOCKET");
if (!lvmetad_socket)
@ -644,6 +647,13 @@ static int _process_config(struct cmd_context *cmd)
if (!_init_system_id(cmd))
return_0;
lvmpolld_socket = getenv("LVM_LVMPOLLD_SOCKET");
if (!lvmpolld_socket)
lvmpolld_socket = DEFAULT_RUN_DIR "/lvmpolld.socket";
lvmpolld_set_socket(lvmpolld_socket);
lvmpolld_set_active(find_config_tree_bool(cmd, global_use_lvmpolld_CFG, NULL));
return 1;
}
@ -2065,6 +2075,7 @@ void destroy_toolcontext(struct cmd_context *cmd)
lvmetad_release_token();
lvmetad_disconnect();
lvmpolld_disconnect();
release_log_memory();
activation_exit();

View File

@ -920,6 +920,15 @@ cfg(activation_checks_CFG, "checks", activation_CFG_SECTION, 0, CFG_TYPE_BOOL, D
"Some of the checks may be expensive, so it's best to use\n"
"this only when there seems to be a problem.\n")
cfg(global_use_lvmpolld_CFG, "use_lvmpolld", global_CFG_SECTION, 0, CFG_TYPE_BOOL, 0, vsn(2, 2, 120), NULL, 0, NULL,
"Indicates whether to use lvmpolld instead of classical polldaemon (a process\n"
"forked off an initiating lvm command) or not. When set to 1 and native systemd\n"
"service is installed in the system lvm starts using lvmpolld. lvmpolld gets\n"
"auto-activated by systemd when a message lands on the respective lvmpolld socket.\n"
"All commands that would require polling of in-progress operation are therefore\n"
"spawned in lvmpolld's service cgroup.\n"
"When set to 0 lvm falls back to classical polling.\n")
cfg(activation_udev_sync_CFG, "udev_sync", activation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_UDEV_SYNC, vsn(2, 2, 51), NULL, 0, NULL,
"Use udev notifications to synchronize udev and LVM.\n"
"When disabled, LVM commands will not wait for notifications\n"

View File

@ -0,0 +1,311 @@
/*
* Copyright (C) 2015 Red Hat, Inc.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "lib.h"
#include "daemon-io.h"
#include "lvmpolld-client.h"
#include "lvmpolld-protocol.h"
#include "metadata-exported.h"
#include "polldaemon.h"
#include "toolcontext.h"
struct progress_info {
unsigned error:1;
unsigned finished:1;
int cmd_signal;
int cmd_retcode;
};
static int _lvmpolld_use;
static int _lvmpolld_connected;
static const char* _lvmpolld_socket;
static daemon_handle _lvmpolld = { .error = 0 };
static daemon_handle _lvmpolld_connect(const char *socket)
{
daemon_info lvmpolld_info = {
.path = "lvmpolld",
.socket = socket ?: LVMPOLLD_SOCKET,
.protocol = LVMPOLLD_PROTOCOL,
.protocol_version = LVMPOLLD_PROTOCOL_VERSION
};
return daemon_open(lvmpolld_info);
}
void lvmpolld_set_active(int active)
{
_lvmpolld_use = active;
}
void lvmpolld_set_socket(const char *socket)
{
_lvmpolld_socket = socket;
}
int lvmpolld_use(void)
{
if (!_lvmpolld_use)
return 0;
if (!_lvmpolld_connected && !_lvmpolld.error) {
_lvmpolld = _lvmpolld_connect(_lvmpolld_socket);
_lvmpolld_connected = _lvmpolld.socket_fd >= 0;
}
return _lvmpolld_connected;
}
void lvmpolld_disconnect(void)
{
if (_lvmpolld_connected) {
daemon_close(_lvmpolld);
_lvmpolld_connected = 0;
}
}
static void _process_error_response(daemon_reply rep)
{
if (!strcmp(daemon_reply_str(rep, "response", ""), LVMPD_RESP_FAILED))
log_error("lvmpolld failed to process a request. The reason was: %s.",
daemon_reply_str(rep, "reason", "<empty>"));
else if (!strcmp(daemon_reply_str(rep, "response", ""), LVMPD_RESP_EINVAL))
log_error("lvmpolld couldn't handle a request. "
"It might be due to daemon internal state. The reason was: %s.",
daemon_reply_str(rep, "reason", "<empty>"));
else
log_error("Unexpected response %s. The reason: %s.",
daemon_reply_str(rep, "response", "<empty>"),
daemon_reply_str(rep, "reason", "<empty>"));
log_print_unless_silent("For more detailed information see lvmpolld log file.");
}
static struct progress_info _request_progress_info(const char *uuid, unsigned abort_polling)
{
daemon_reply rep;
const char *e = getenv("LVM_SYSTEM_DIR");
struct progress_info ret = { .error = 1, .finished = 1 };
daemon_request req = daemon_request_make(LVMPD_REQ_PROGRESS);
if (!daemon_request_extend(req, LVMPD_PARM_LVID " = %s", uuid, NULL)) {
log_error("Failed to create " LVMPD_REQ_PROGRESS " request.");
goto out_req;
}
if (abort_polling &&
!daemon_request_extend(req, LVMPD_PARM_ABORT " = %d", abort_polling, NULL)) {
log_error("Failed to create " LVMPD_REQ_PROGRESS " request.");
goto out_req;
}
if (e &&
!(daemon_request_extend(req, LVMPD_PARM_SYSDIR " = %s",
e, NULL))) {
log_error("Failed to create " LVMPD_REQ_PROGRESS " request.");
goto out_req;
}
rep = daemon_send(_lvmpolld, req);
if (rep.error) {
log_error("Failed to process request with error %s (errno: %d).",
strerror(rep.error), rep.error);
goto out_rep;
}
if (!strcmp(daemon_reply_str(rep, "response", ""), LVMPD_RESP_IN_PROGRESS)) {
ret.finished = 0;
ret.error = 0;
} else if (!strcmp(daemon_reply_str(rep, "response", ""), LVMPD_RESP_FINISHED)) {
if (!strcmp(daemon_reply_str(rep, "reason", ""), LVMPD_REAS_SIGNAL))
ret.cmd_signal = daemon_reply_int(rep, LVMPD_PARM_VALUE, 0);
else
ret.cmd_retcode = daemon_reply_int(rep, LVMPD_PARM_VALUE, -1);
ret.error = 0;
} else if (!strcmp(daemon_reply_str(rep, "response", ""), LVMPD_RESP_NOT_FOUND)) {
log_verbose("No polling operation in progress regarding LV %s.", uuid);
ret.error = 0;
} else {
_process_error_response(rep);
stack;
}
out_rep:
daemon_reply_destroy(rep);
out_req:
daemon_request_destroy(req);
return ret;
}
/*
* interval in seconds long
* enough for more than a year
* of waiting
*/
#define INTERV_SIZE 10
static int _process_poll_init(const struct cmd_context *cmd, const char *poll_type,
const struct poll_operation_id *id, const struct daemon_parms *parms)
{
char *str;
daemon_reply rep;
daemon_request req;
const char *e = getenv("LVM_SYSTEM_DIR");
int r = 0;
str = dm_malloc(INTERV_SIZE * sizeof(char));
if (!str)
return r;
if (snprintf(str, INTERV_SIZE, "%u", parms->interval) >= INTERV_SIZE) {
log_warn("Interval string conversion got truncated.");
str[INTERV_SIZE - 1] = '\0';
}
req = daemon_request_make(poll_type);
if (!daemon_request_extend(req, LVMPD_PARM_LVID " = %s", id->uuid,
LVMPD_PARM_VGNAME " = %s", id->vg_name,
LVMPD_PARM_LVNAME " = %s", id->lv_name,
LVMPD_PARM_INTERVAL " = %s", str,
"cmdline = %s", cmd->cmd_line, /* FIXME: debug param only */
NULL)) {
log_error("Failed to create %s request.", poll_type);
goto out_req;
}
if (parms->aborting &&
!(daemon_request_extend(req, LVMPD_PARM_ABORT " = %d", parms->aborting, NULL))) {
log_error("Failed to create %s request." , poll_type);
goto out_req;
}
if (cmd->handles_missing_pvs &&
!(daemon_request_extend(req, LVMPD_PARM_HANDLE_MISSING_PVS " = %d",
cmd->handles_missing_pvs, NULL))) {
log_error("Failed to create %s request." , poll_type);
goto out_req;
}
if (e &&
!(daemon_request_extend(req, LVMPD_PARM_SYSDIR " = %s",
e, NULL))) {
log_error("Failed to create %s request." , poll_type);
goto out_req;
}
rep = daemon_send(_lvmpolld, req);
if (rep.error) {
log_error("Failed to process request with error %s (errno: %d).",
strerror(rep.error), rep.error);
goto out_rep;
}
if (!strcmp(daemon_reply_str(rep, "response", ""), LVMPD_RESP_OK))
r = 1;
else {
_process_error_response(rep);
stack;
}
out_rep:
daemon_reply_destroy(rep);
out_req:
daemon_request_destroy(req);
dm_free(str);
return r;
}
int lvmpolld_poll_init(const struct cmd_context *cmd, const struct poll_operation_id *id,
const struct daemon_parms *parms)
{
int r = 0;
if (!id->uuid) {
log_error(INTERNAL_ERROR "Use of lvmpolld requires uuid set");
return 0;
}
if (!id->vg_name) {
log_error(INTERNAL_ERROR "Use of lvmpolld requires vgname set");
return 0;
}
if (!id->lv_name) {
log_error(INTERNAL_ERROR "Use of lvmpolld requires lvname set");
return 0;
}
if (parms->lv_type & PVMOVE) {
log_verbose("lvmpolld: Requesting pvmove%s", parms->aborting ? " abort." : ".");
r = _process_poll_init(cmd, LVMPD_REQ_PVMOVE, id, parms);
} else if (parms->lv_type & CONVERTING) {
log_verbose("lvmpolld: Requesting convert mirror.");
r = _process_poll_init(cmd, LVMPD_REQ_CONVERT, id, parms);
} else if (parms->lv_type & MERGING) {
if (parms->lv_type & SNAPSHOT) {
log_verbose("lvmpolld: Requesting snapshot merge.");
r = _process_poll_init(cmd, LVMPD_REQ_MERGE, id, parms);
}
else if (parms->lv_type & THIN_VOLUME) {
log_verbose("lvmpolld: Thin snapshot merge.");
r = _process_poll_init(cmd, LVMPD_REQ_MERGE_THIN, id, parms);
}
else {
log_error(INTERNAL_ERROR "Unsupported poll operation.");
}
} else
log_error(INTERNAL_ERROR "Unsupported poll operation");
return r;
}
int lvmpolld_request_info(const struct poll_operation_id *id, const struct daemon_parms *parms, unsigned *finished)
{
struct progress_info info;
int ret = 0;
*finished = 1;
if (!id->uuid) {
log_error(INTERNAL_ERROR "use of lvmpolld requires uuid being set");
return 0;
}
info = _request_progress_info(id->uuid, parms->aborting);
*finished = info.finished;
if (info.error)
return_0;
if (info.finished) {
if (info.cmd_signal)
log_error("Polling command got terminated by signal (%d).",
info.cmd_signal);
else if (info.cmd_retcode)
log_error("Polling command exited with return code: %d.",
info.cmd_retcode);
else {
log_verbose("Polling finished successfully.");
ret = 1;
}
} else
ret = 1;
return ret;
}

View File

@ -0,0 +1,52 @@
/*
* Copyright (C) 2014-2015 Red Hat, Inc.
*
* This file is part of LVM2.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v.2.1.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _LVM_LVMPOLLD_CLIENT_H
#define _LVM_LVMPOLLD_CLIENT_H
# ifdef LVMPOLLD_SUPPORT
# include "daemon-client.h"
# define LVMPOLLD_SOCKET DEFAULT_RUN_DIR "/lvmpolld.socket"
struct cmd_context;
struct poll_operation_id;
struct daemon_parms;
void lvmpolld_disconnect(void);
int lvmpolld_poll_init(const struct cmd_context *cmd, const struct poll_operation_id *id,
const struct daemon_parms *parms);
int lvmpolld_request_info(const struct poll_operation_id *id, const struct daemon_parms *parms,
unsigned *finished);
int lvmpolld_use(void);
void lvmpolld_set_active(int active);
void lvmpolld_set_socket(const char *socket);
# else
# define lvmpolld_disconnect() do {} while (0)
# define lvmpolld_poll_init(cmd, id, parms) (0)
# define lvmpolld_request_info(id, parms, finished) (0)
# define lvmpolld_use() (0)
# define lvmpolld_set_active(active) do {} while (0)
# define lvmpolld_set_socket(socket) do {} while (0)
# endif /* LVMPOLLD_SUPPORT */
#endif /* _LVM_LVMPOLLD_CLIENT_H */

View File

@ -500,6 +500,12 @@
/* Define to 1 to include code that uses lvmetad. */
#undef LVMETAD_SUPPORT
/* Path to lvmpolld pidfile. */
#undef LVMPOLLD_PIDFILE
/* Define to 1 to include code that uses lvmpolld. */
#undef LVMPOLLD_SUPPORT
/* Path to lvm binary. */
#undef LVM_PATH

View File

@ -19,7 +19,7 @@ top_builddir = @top_builddir@
SUBDIRS += client
ifeq ("@BUILD_LVMETAD@", "yes")
ifeq (yes, $(shell test @BUILD_LVMETAD@ == yes -o @BUILD_LVMPOLLD@ == yes && echo yes))
SUBDIRS += server
server: client
endif

View File

@ -491,7 +491,7 @@ distclean: cleandir $(SUBDIRS.distclean)
echo " local:"; echo " *;"; echo "};") > $@
ifeq (,$(findstring $(MAKECMDGOALS),cscope.out cflow clean distclean lcov \
help check check_local check_cluster check_lvmetad))
help check check_local check_cluster check_lvmetad check_lvmpolld))
ifdef SOURCES
-include $(SOURCES:.c=.d) $(CXXSOURCES:.cpp=.d)
endif

View File

@ -40,6 +40,12 @@ else
LVMETAD =
endif
ifeq ("@BUILD_LVMPOLLD@", "yes")
LVMPOLLD = lvmpolld.8
else
LVMPOLLD =
endif
MAN5=lvm.conf.5
MAN7=lvmsystemid.7
MAN8=lvm-config.8 lvm-dumpconfig.8 \
@ -50,7 +56,7 @@ MAN8=lvm-config.8 lvm-dumpconfig.8 \
pvresize.8 pvs.8 pvscan.8 vgcfgbackup.8 vgcfgrestore.8 vgchange.8 \
vgck.8 vgcreate.8 vgconvert.8 vgdisplay.8 vgexport.8 vgextend.8 \
vgimport.8 vgimportclone.8 vgmerge.8 vgmknodes.8 vgreduce.8 vgremove.8 \
vgrename.8 vgs.8 vgscan.8 vgsplit.8 $(FSADMMAN) $(LVMETAD)
vgrename.8 vgs.8 vgscan.8 vgsplit.8 $(FSADMMAN) $(LVMETAD) $(LVMPOLLD)
ifneq ("@CLVMD@", "none")
MAN8CLUSTER=clvmd.8

View File

@ -525,6 +525,12 @@ Path for the lvmetad pid file.
.TP
.B LVM_LVMETAD_SOCKET
Path for the lvmetad socket file.
.TP
.B LVM_LVMPOLLD_PIDFILE
Path for the lvmpolld pid file.
.TP
.B LVM_LVMPOLLD_SOCKET
Path for the lvmpolld socket file.
.SH FILES
.I #DEFAULT_SYS_DIR#/lvm.conf
.br

86
man/lvmpolld.8.in Normal file
View File

@ -0,0 +1,86 @@
.TH LVMETAD 8 "LVM TOOLS #VERSION#" "Red Hat Inc" \" -*- nroff -*-
.SH NAME
lvmpolld \(em LVM poll daemon
.SH SYNOPSIS
.B lvmpolld
.RB [ \-l
.RI { all | wire | debug }]
.RB [ \-p
.IR pidfile_path ]
.RB [ \-s
.IR socket_path ]
.RB [ \-B
.IR lvm_binary_path ]
.RB [ \-t
.IR timeout_value ]
.RB [ \-f ]
.RB [ \-h ]
.RB [ \-V ]
.RB [ \-? ]
.SH DESCRIPTION
lvmpolld is polling daemon for LVM. The daemon receives requests for polling
of already initialised operations originating in LVM2 command line tool.
The requests for polling originates in \fBlvconvert\fP, \fBpvmove\fP,
\fBlvchange\fP or \fBvgchange\fP LVM2 command.
The purpose of lvmpolld is to reduce the number of spawned background processes
per otherwise unique polling operation. There should be only one. It also eliminates
the possibility of unsolicited termination of background process by external factors.
lvmpolld is used by LVM only if it is enabled in \fBlvm.conf\fP(5) by specifying the
\fBglobal/use_lvmpolld\fP setting. If this is not defined in the LVM configuration
explicitly then default setting is used instead (see the output of
\fBlvmconfig \-\-type default global/use_lvmpolld\fP command).
.SH OPTIONS
To run the daemon in a test environment both the pidfile_path and the
socket_path should be changed from the defaults.
.TP
.B \-f
Don't fork, but run in the foreground.
.TP
.BR \-h ", " \-?
Show help information.
.TP
.IR \fB\-l " {" all | wire | debug }
Select the type of log messages to generate.
Messages are logged by syslog.
Additionally, when \-f is given they are also sent to standard error.
There are two classes of messages: wire and debug. Selecting 'all' supplies both
and is equivalent to a comma-separated list \-l wire,debug.
.TP
.B \-p \fIpidfile_path
Path to the pidfile. This overrides both the built-in default
(#DEFAULT_PID_DIR#/lvmpolld.pid) and the environment variable
\fBLVM_LVMPOLLD_PIDFILE\fP. This file is used to prevent more
than one instance of the daemon running simultaneously.
.TP
.B \-s \fIsocket_path
Path to the socket file. This overrides both the built-in default
(#DEFAULT_RUN_DIR#/lvmpolld.socket) and the environment variable
\fBLVM_LVMPOLLD_SOCKET\fP.
.TP
.B \-t \fItimeout_value
When runs as native systemd service daemon may shutdown after being
idle for the given time (in seconds). When the option is omitted or
the value given is zero the daemon never shutdowns on idle. When
the daemon doesn't run as native systemd service the timeout is
ignored and never shutdowns on idle.
.TP
.B \-B \fIlvm_binary_path
Optional path to alternative LVM binary (default: #LVM_PATH#). Use for
testing purposes only.
.TP
.B \-V
Display the version of lvmpolld daemon.
.SH ENVIRONMENT VARIABLES
.TP
.B LVM_LVMPOLLD_PIDFILE
Path for the pid file.
.TP
.B LVM_LVMPOLLD_SOCKET
Path for the socket file.
.SH SEE ALSO
.BR lvm (8),
.BR lvm.conf (5)

3
scripts/.gitignore vendored
View File

@ -4,6 +4,9 @@ dm_event_systemd_red_hat.service
lvm2_lvmetad_init_red_hat
lvm2_lvmetad_systemd_red_hat.service
lvm2_lvmetad_systemd_red_hat.socket
lvm2_lvmpolld_init_red_hat
lvm2_lvmpolld_systemd_red_hat.service
lvm2_lvmpolld_systemd_red_hat.socket
lvm2_monitoring_init_red_hat
lvm2_monitoring_systemd_red_hat.service
lvm2_tmpfiles_red_hat.conf

View File

@ -75,6 +75,9 @@ endif
ifeq ("@BUILD_LVMETAD@", "yes")
$(INSTALL_SCRIPT) lvm2_lvmetad_init_red_hat $(initdir)/lvm2-lvmetad
endif
ifeq ("@BUILD_LVMPOLLD@", "yes")
$(INSTALL_SCRIPT) lvm2_lvmpolld_init_red_hat $(initdir)/lvm2-lvmpolld
endif
ifneq ("@CLVMD@", "none")
$(INSTALL_SCRIPT) clvmd_init_red_hat $(initdir)/clvmd
endif
@ -114,6 +117,10 @@ ifeq ("@BUILD_LVMETAD@", "yes")
$(INSTALL_DATA) lvm2_lvmetad_systemd_red_hat.service $(systemd_unit_dir)/lvm2-lvmetad.service
$(INSTALL_DATA) lvm2_pvscan_systemd_red_hat@.service $(systemd_unit_dir)/lvm2-pvscan@.service
endif
ifeq ("@BUILD_LVMPOLLD@", "yes")
$(INSTALL_DATA) lvm2_lvmpolld_systemd_red_hat.socket $(systemd_unit_dir)/lvm2-lvmpolld.socket
$(INSTALL_DATA) lvm2_lvmpolld_systemd_red_hat.service $(systemd_unit_dir)/lvm2-lvmpolld.service
endif
ifneq ("@CLVMD@", "none")
$(INSTALL_DATA) lvm2_clvmd_systemd_red_hat.service $(systemd_unit_dir)/lvm2-clvmd.service
$(INSTALL_DATA) lvm2_cluster_activation_systemd_red_hat.service $(systemd_unit_dir)/lvm2-cluster-activation.service
@ -142,6 +149,8 @@ DISTCLEAN_TARGETS += \
lvm2_lvmetad_init_red_hat \
lvm2_lvmetad_systemd_red_hat.service \
lvm2_lvmetad_systemd_red_hat.socket \
lvm2_lvmpolld_systemd_red_hat.service \
lvm2_lvmpolld_systemd_red_hat.socket \
lvm2_monitoring_init_red_hat \
lvm2_monitoring_systemd_red_hat.service \
lvm2_pvscan_systemd_red_hat@.service \

View File

@ -0,0 +1,114 @@
#!/bin/bash
#
# Copyright (C) 2015 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# This file is part of LVM2.
# It is required for the proper handling of failures of LVM2 mirror
# devices that were created using the -m option of lvcreate.
#
#
# chkconfig: 12345 02 99
# description: Starts and stops LVM poll daemon
#
# For Red-Hat-based distributions such as Fedora, RHEL, CentOS.
#
### BEGIN INIT INFO
# Provides: lvm2-lvmpolld
# Required-Start: $local_fs
# Required-Stop: $local_fs
# Default-Start: 1 2 3 4 5
# Default-Stop: 0 6
# Short-Description: A daemon that is responsible for monitoring in-progress
# and possibly longer term operations on logical volumes.
# It helps to reduce the number of spawned processes if same
# logical volume is requested to get monitored multiple times.
# Also avoids unsolicited termination due to external factors.
### END INIT INFO
. /etc/init.d/functions
DAEMON=lvmpolld
exec_prefix=@exec_prefix@
sbindir=@sbindir@
LOCK_FILE="/var/lock/subsys/$DAEMON"
PID_FILE="@LVMPOLLD_PIDFILE@"
rh_status() {
status -p $PID_FILE $DAEMON
}
rh_status_q() {
rh_status >/dev/null 2>&1
}
start()
{
ret=0
action "Starting LVM poll daemon:" $DAEMON || ret=$?
return $ret
}
stop()
{
ret=0
action "Signaling LVM poll daemon to exit:" killproc -p $PID_FILE $DAEMON -TERM || ret=$?
return $ret
}
rtrn=1
# See how we were called.
case "$1" in
start)
rh_status_q && exit 0
start
rtrn=$?
[ $rtrn = 0 ] && touch $LOCK_FILE
;;
stop|force-stop)
rh_status_q || exit 0
stop
rtrn=$?
[ $rtrn = 0 ] && rm -f $LOCK_FILE
;;
restart)
if stop
then
start
fi
rtrn=$?
;;
condrestart|try-restart)
rh_status_q || exit 0
if stop
then
start
fi
rtrn=$?
;;
status)
rh_status
rtrn=$?
;;
*)
echo $"Usage: $0 {start|stop|force-stop|restart|condrestart|try-restart|status}"
;;
esac
exit $rtrn

View File

@ -0,0 +1,17 @@
[Unit]
Description=LVM2 poll daemon
Documentation=man:lvmpolld(8)
Requires=lvm2-lvmpolld.socket
After=lvm2-lvmpolld.socket
DefaultDependencies=no
Conflicts=shutdown.target
[Service]
Type=simple
NonBlocking=true
ExecStart=@sbindir@/lvmpolld -t 60 -f
Environment=SD_ACTIVATION=1
PIDFile=@LVMPOLLD_PIDFILE@
[Install]
WantedBy=sysinit.target

View File

@ -0,0 +1,12 @@
[Unit]
Description=LVM2 poll daemon socket
Documentation=man:lvmpolld(8)
DefaultDependencies=no
[Socket]
ListenStream=@DEFAULT_RUN_DIR@/lvmpolld.socket
SocketMode=0600
RemoveOnStop=true
[Install]
WantedBy=sysinit.target

View File

@ -1,7 +1,7 @@
#!/bin/bash
# We use some bash-isms (getopts?)
# Copyright (C) 2007-2010 Red Hat, Inc. All rights reserved.
# Copyright (C) 2007-2015 Red Hat, Inc. All rights reserved.
#
# This file is part of LVM2.
#
@ -41,6 +41,7 @@ NC=nc
LVM=${LVM_BINARY-lvm}
DMSETUP=${DMSETUP_BINARY-dmsetup}
LVMETAD_SOCKET=${LVM_LVMETAD_SOCKET-/var/run/lvm/lvmetad.socket}
LVMPOLLD_SOCKET=${LVM_LVMPOLLD_SOCKET-/var/run/lvm/lvmpolld.socket}
die() {
code=$1; shift
@ -59,6 +60,7 @@ function usage {
echo " -c if running clvmd, gather cluster data as well"
echo " -d <directory> dump into a directory instead of tarball"
echo " -l gather lvmetad state if running"
echo " -p gather lvmpolld state if running"
echo " -m gather LVM metadata from the PVs"
echo " -s gather system info and context"
echo " -u gather udev info and context"
@ -72,13 +74,14 @@ clustered=0
metadata=0
sysreport=0
udev=0
while getopts :acd:hlmus opt; do
while getopts :acd:hlpmus opt; do
case $opt in
a) advanced=1 ;;
c) clustered=1 ;;
d) userdir=$OPTARG ;;
h) usage ;;
l) lvmetad=1 ;;
p) lvmpolld=1 ;;
m) metadata=1 ;;
s) sysreport=1 ;;
u) udev=1 ;;
@ -236,6 +239,7 @@ if (( $metadata )); then
done
fi
# FIXME: add lvmpolld.service here
if (( $sysreport )); then
myecho "Gathering system info..."
@ -296,6 +300,22 @@ if (( $lvmetad )); then
} > "$dir/lvmetad.txt"
fi
if (( $lvmpolld )); then
(echo 'request="dump"'; echo '##') | {
if type -p $SOCAT >& /dev/null; then
echo "$SOCAT unix-connect:$LVMPOLLD_SOCKET -" >> "$log"
$SOCAT "unix-connect:$LVMPOLLD_SOCKET" - 2>> "$log"
elif echo | $NC -U "$LVMPOLLD_SOCKET"; then
echo "$NC -U $LVMPOLLD_SOCKET" >> "$log"
$NC -U "$LVMPOLLD_SOCKET" 2>> "$log"
else
myecho "WARNING: Neither socat nor nc -U seems to be available." 1>&2
echo "# DUMP FAILED"
return 1
fi
} > "$dir/lvmpolld.txt"
fi
if test -z "$userdir"; then
lvm_dump="$dirbase.tgz"
myecho "Creating report tarball in $HOME/$lvm_dump..."

View File

@ -56,6 +56,11 @@ LVMETAD_NDEV_FLAVOUR = ,ndev-lvmetad
LVMETAD_UDEV_FLAVOUR = ,udev-lvmetad
endif
ifeq ("@BUILD_LVMPOLLD@", "yes")
LVMPOLLD_RUN_BASE = $(RUN_BASE)
LVMPOLLD_NDEV_FLAVOUR = ,ndev-lvmpolld,ndev-cluster-lvmpolld,ndev-lvmetad-lvmpolld
LVMPOLLD_UDEV_FLAVOUR = ,udev-lvmpolld,udev-cluster-lvmpolld,udev-lvmetad-lvmpolld
endif
# Shell quote;
SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
@ -73,6 +78,7 @@ help:
@echo " check_local Run tests without clvmd and lvmetad."
@echo " check_cluster Run tests with cluster daemon."
@echo " check_lvmetad Run tests with lvmetad daemon."
@echo " check_lvmpolld Run tests with lvmpolld daemon."
@echo " clean Clean dir."
@echo " help Display callable targets."
@echo -e "\nSupported variables:"
@ -83,6 +89,7 @@ help:
@echo " LVM_TEST_LOCKING Normal (1), Cluster (3)."
@echo " LVM_TEST_LVMETAD Start lvmetad (1)."
@echo " LVM_TEST_LVMETAD_DEBUG_OPTS Allows to override debug opts [-l all]."
@echo " LVM_TEST_LVMPOLLD Start lvmpolld"
@echo " LVM_TEST_NODEBUG Do not debug lvm commands."
@echo " LVM_TEST_PARALLEL May skip agresive wipe of LVMTEST resources."
@echo " LVM_TEST_RESULTS Where to create result files [results]."
@ -109,12 +116,12 @@ help:
check: .tests-stamp
VERBOSE=$(VERBOSE) ./lib/runner \
--testdir . --outdir $(LVM_TEST_RESULTS) \
--flavours ndev-vanilla,ndev-cluster$(LVMETAD_NDEV_FLAVOUR) --only $(T) --skip $(S)
--flavours ndev-vanilla,ndev-cluster$(LVMETAD_NDEV_FLAVOUR)$(LVMPOLLD_NDEV_FLAVOUR) --only $(T) --skip $(S)
check_system: .tests-stamp
VERBOSE=$(VERBOSE) ./lib/runner \
--testdir . --outdir $(LVM_TEST_RESULTS) \
--flavours udev-vanilla,udev-cluster$(LVMETAD_UDEV_FLAVOUR) --only $(T) --skip $(S)
--flavours udev-vanilla,udev-cluster$(LVMETAD_UDEV_FLAVOUR)$(LVMPOLLD_UDEV_FLAVOUR) --only $(T) --skip $(S)
check_cluster: .tests-stamp
VERBOSE=$(VERBOSE) ./lib/runner \
@ -133,11 +140,21 @@ check_lvmetad: .tests-stamp
--flavours ndev-lvmetad --only $(T) --skip $(S)
endif
ifeq ("@BUILD_LVMPOLLD@", "yes")
check_lvmpolld: .tests-stamp
VERBOSE=$(VERBOSE) ./lib/runner \
--testdir . --outdir results \
--flavours udev-lvmpolld,udev-cluster-lvmpolld,udev-lvmetad-lvmpolld --only $(T) --skip $(S)
endif
DATADIR = $(datadir)/lvm2-testsuite
EXECDIR = $(libexecdir)/lvm2-testsuite
LIB_FLAVOURS = lib/flavour-ndev-vanilla lib/flavour-ndev-cluster lib/flavour-ndev-lvmetad \
lib/flavour-udev-vanilla lib/flavour-udev-cluster lib/flavour-udev-lvmetad
lib/flavour-udev-vanilla lib/flavour-udev-cluster lib/flavour-udev-lvmetad \
lib/flavour-udev-lvmpolld lib/flavour-ndev-lvmpolld lib/flavour-ndev-cluster-lvmpolld \
lib/flavour-ndev-lvmetad-lvmpolld lib/flavour-udev-lvmpolld lib/flavour-udev-cluster-lvmpolld \
lib/flavour-udev-lvmetad-lvmpolld
LIB_LOCAL = lib/paths lib/runner
LIB_EXEC = lib/not lib/invalid lib/fail lib/should
@ -190,6 +207,7 @@ lib/paths-common: $(srcdir)/Makefile.in .lib-dir-stamp Makefile
echo 'export RAID=@RAID@' >> $@-t
echo 'export CACHE=@CACHE@' >> $@-t
echo 'export LVMETAD_PIDFILE="@LVMETAD_PIDFILE@"' >> $@-t
echo 'export LVMPOLLD_PIDFILE="@LVMPOLLD_PIDFILE@"' >> $@-t
echo 'export DMEVENTD_PIDFILE="@DMEVENTD_PIDFILE@"' >> $@-t
echo 'export CLVMD_PIDFILE="@CLVMD_PIDFILE@"' >> $@-t
echo 'export LVM_TEST_THIN_CHECK_CMD=$${LVM_TEST_THIN_CHECK_CMD-@THIN_CHECK_CMD@}' >> $@-t
@ -240,6 +258,7 @@ LIB = $(LIB_SHARED) $(LIB_LOCAL) $(LIB_EXEC) $(LIB_FLAVOURS)
ln -fs $(abs_top_builddir)/daemons/clvmd/clvmd lib/clvmd
ln -fs $(abs_top_builddir)/daemons/dmeventd/dmeventd lib/dmeventd
ln -fs $(abs_top_builddir)/daemons/lvmetad/lvmetad lib/lvmetad
ln -fs $(abs_top_builddir)/daemons/lvmpolld/lvmpolld lib/lvmpolld
ln -fs $(abs_top_srcdir)/scripts/vgimportclone.sh lib/vgimportclone
ln -fs $(abs_top_srcdir)/scripts/fsadm.sh lib/fsadm
ln -fs $(abs_top_srcdir)/conf/thin-performance.profile lib/thin-performance.profile
@ -256,7 +275,8 @@ CLEAN_TARGETS += .lib-dir-stamp .tests-stamp $(LIB) $(addprefix lib/,$(CMDS)) \
lib/clvmd lib/dmeventd lib/dmsetup lib/lvmetad lib/fsadm lib/vgimportclone \
lib/thin-performance.profile lib/harness \
lib/paths-installed lib/paths-installed-t \
lib/paths-common lib/paths-common-t
lib/paths-common lib/paths-common-t \
lib/lvmpolld
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@

View File

@ -136,6 +136,47 @@ notify_lvmetad() {
fi
}
prepare_lvmpolld() {
set -x
rm -f debug.log
# skip if we don't have our own lvmpolld...
(which lvmpolld 2>/dev/null | grep "$abs_builddir") || skip
lvmconf "global/use_lvmpolld = 1"
local run_valgrind=
test "${LVM_VALGRIND_LVMPOLLD:-0}" -eq 0 || run_valgrind="run_valgrind"
kill_sleep_kill_ LOCAL_LVMPOLLD ${LVM_VALGRIND_LVMPOLLD:-0}
echo "preparing lvmpolld..."
$run_valgrind lvmpolld -f "$@" -s "$TESTDIR/lvmpolld.socket" -B "$TESTDIR/lib/lvm" -l all &
echo $! > LOCAL_LVMPOLLD
while ! test -e "$TESTDIR/lvmpolld.socket"; do echo -n .; sleep .1; done # wait for the socket
echo ok
}
lvmpolld_talk() {
local use=nc
if type -p socat >& /dev/null; then
use=socat
elif echo | not nc -U "$TESTDIR/lvmpolld.socket" ; then
echo "WARNING: Neither socat nor nc -U seems to be available." 1>&2
echo "# failed to contact lvmpolld"
return 1
fi
if test "$use" = nc ; then
nc -U "$TESTDIR/lvmpolld.socket"
else
socat "unix-connect:$TESTDIR/lvmpolld.socket" -
fi | tee -a lvmpolld-talk.txt
}
lvmpolld_dump() {
(echo 'request="dump"'; echo '##') | lvmpolld_talk "$@"
}
teardown_devs_prefixed() {
local prefix=$1
local stray=${2:-0}
@ -286,6 +327,10 @@ teardown() {
$vg $vg1 $vg2 $vg3 $vg4 &>/dev/null || rm -f debug.log strace.log
}
kill_sleep_kill_ LOCAL_LVMPOLLD ${LVM_VALGRIND_LVMPOLLD:-0}
echo -n .
kill_sleep_kill_ LOCAL_CLVMD ${LVM_VALGRIND_CLVMD:-0}
echo -n .
@ -1094,16 +1139,57 @@ dmsetup_wrapped() {
dmsetup "$@"
}
awk_parse_init_count_in_lvmpolld_dump() {
printf '%s' \
\
$'BEGINFILE { x=0; answ=0; FS="="; key="[[:space:]]*"vkey }' \
$'{' \
$'if (/.*{$/) { x++ }' \
$'else if (/.*}$/) { x-- }' \
$'else if ( x == 2 && $1 ~ key) { value=substr($2, 2); value=substr(value, 1, length(value) - 1); }' \
$'if ( x == 2 && value == vvalue && $1 ~ /[[:space:]]*init_requests_count/) { answ=$2 }' \
$'if (answ > 0) { exit 0 }' \
$'}' \
$'END { printf "%d", answ }'
}
check_lvmpolld_init_rq_count() {
local ret=$(awk -v vvalue="$2" -v vkey=${3:-lvname} "$(awk_parse_init_count_in_lvmpolld_dump)" lvmpolld_dump.txt)
test $ret -eq $1 || {
echo "check_lvmpolld_init_rq_count failed. Expected $1, got $ret"
return 1
}
}
wait_pvmove_lv_ready() {
# given sleep .1 this is about 60 secs of waiting
local retries=${2:-300}
while : ; do
test $retries -le 0 && die "Waiting for pvmove LV to get activated has timed out"
dmsetup info -c -o tables_loaded $1 > out 2>/dev/null|| true;
not grep Live out >/dev/null || break
sleep .1
retries=$((retries-1))
done
if [ -e LOCAL_LVMPOLLD ]; then
local lvid
while : ; do
test $retries -le 0 && die "Waiting for lvmpolld timed out"
test -n "$lvid" || {
lvid=$(get lv_field ${1//-/\/} vg_uuid,lv_uuid -a 2>/dev/null)
lvid=${lvid//\ /}
lvid=${lvid//-/}
}
test -z "$lvid" || {
lvmpolld_dump > lvmpolld_dump.txt
! check_lvmpolld_init_rq_count 1 $lvid lvid || break;
}
sleep .1
retries=$((retries-1))
done
else
while : ; do
test $retries -le 0 && die "Waiting for pvmove LV to get activated has timed out"
dmsetup info -c -o tables_loaded $1 > out 2>/dev/null|| true;
not grep Live out >/dev/null || break
sleep .1
retries=$((retries-1))
done
fi
}
# return total memory size in kB units

View File

@ -0,0 +1,2 @@
export LVM_TEST_LOCKING=3
export LVM_TEST_LVMPOLLD=1

View File

@ -0,0 +1,3 @@
export LVM_TEST_LOCKING=1
export LVM_TEST_LVMETAD=1
export LVM_TEST_LVMPOLLD=1

View File

@ -0,0 +1,2 @@
export LVM_TEST_LOCKING=1
export LVM_TEST_LVMPOLLD=1

View File

@ -0,0 +1,3 @@
export LVM_TEST_LOCKING=3
export LVM_TEST_LVMPOLLD=1
export LVM_TEST_DEVDIR=/dev

View File

@ -0,0 +1,4 @@
export LVM_TEST_LOCKING=1
export LVM_TEST_LVMETAD=1
export LVM_TEST_LVMPOLLD=1
export LVM_TEST_DEVDIR=/dev

View File

@ -0,0 +1,3 @@
export LVM_TEST_LOCKING=1
export LVM_TEST_LVMPOLLD=1
export LVM_TEST_DEVDIR=/dev

View File

@ -100,6 +100,13 @@ else
aux prepare_clvmd
fi
echo "LVM_TEST_LVMPOLLD=$LVM_TEST_LVMPOLLD"
test -n "$LVM_TEST_LVMPOLLD" && {
export LVM_LVMPOLLD_SOCKET="$TESTDIR/lvmpolld.socket"
export LVM_LVMPOLLD_PIDFILE="$TESTDIR/lvmpolld.pid"
aux prepare_lvmpolld
}
echo "<======== Processing test: \"$TESTNAME\" ========>"
set -vx

View File

@ -11,6 +11,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
lvm version
test -n "$abs_top_builddir" || skip

View File

@ -14,6 +14,7 @@
# Just skip this test if minor is already in use...
dmsetup info | tee info
egrep "^Major, minor: *[0-9]+, 123" info && skip
test -e LOCAL_LVMPOLLD && skip
aux prepare_vg 2
lvcreate -a n --zero n -l 1 -n foo $vg

View File

@ -18,6 +18,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
aux prepare_vg 2
lvcreate -l100%FREE -n span $vg

View File

@ -18,6 +18,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
aux prepare_vg 4
lvcreate -l1 -n linear1 $vg "$dev1"

View File

@ -11,6 +11,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
aux prepare_vg 3
lvcreate -aey --type mirror -m 1 -l 1 --nosync -n mirror $vg

View File

@ -11,6 +11,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
# Test skip activation flag -k|--setactivationskip
aux prepare_vg

View File

@ -16,6 +16,7 @@ export LVM_BINARY=lvm
. lib/inittest
# only clvmd based test, skip otherwise
test -e LOCAL_LVMPOLLD && skip
test -e LOCAL_CLVMD || skip
read LOCAL_CLVMD < LOCAL_CLVMD

View File

@ -16,6 +16,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
aux prepare_pvs 5
get_devs

View File

@ -15,6 +15,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
#
# Main
#

View File

@ -11,6 +11,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
aux prepare_dmeventd
aux prepare_vg 5

View File

@ -11,6 +11,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
flatten() {
cat > flatten.config
for s in `egrep '^[a-z]+ {$' flatten.config | sed -e s,{$,,`; do

View File

@ -13,6 +13,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
which md5sum || skip
aux prepare_pvs 1

View File

@ -13,6 +13,8 @@ test_description='Exercise fsadm filesystem resize'
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
aux prepare_vg 1 100
# set to "skip" to avoid testing given fs and test warning result

View File

@ -11,6 +11,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
aux prepare_vg 3 12
lvcreate -aye --type mirror -m 1 -l 1 -n mirror $vg

View File

@ -15,6 +15,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
aux prepare_devs 5
get_devs

View File

@ -13,8 +13,10 @@ test_description='test some blocking / non-blocking multi-vg operations'
. lib/inittest
aux prepare_devs 3
test -e LOCAL_LVMPOLLD && skip
test -e LOCAL_CLVMD && skip
aux prepare_devs 3
pvcreate "$dev1" "$dev2"
vgcreate $vg "$dev1" "$dev2"

View File

@ -14,6 +14,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
which mkfs.ext3 || skip
which fsck || skip

View File

@ -11,6 +11,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
aux have_cache 1 3 0 || skip
aux prepare_vg 3

View File

@ -11,6 +11,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
# FIXME RESYNC doesn't work in cluster with exclusive activation
# seriously broken!
test -e LOCAL_CLVMD && skip

View File

@ -11,6 +11,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
aux have_raid 1 3 2 || skip
aux prepare_vg 4

View File

@ -11,6 +11,7 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
aux prepare_vg 4

View File

@ -13,6 +13,8 @@ TEST_RAID=raid10
. shell/lvchange-raid.sh
test -e LOCAL_LVMPOLLD && skip
aux have_raid 1 5 2 || skip
run_types raid10 -m 1 -i 2 "$dev1" "$dev2" "$dev3" "$dev4"

View File

@ -13,6 +13,8 @@ TEST_RAID=raid456
. shell/lvchange-raid.sh
test -e LOCAL_LVMPOLLD && skip
aux raid456_replace_works || skip
aux have_raid 1 5 2 || skip

View File

@ -13,6 +13,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
# Proper mismatch count 1.5.2+ upstream, 1.3.5 < x < 1.4.0 in RHEL6
aux have_raid 1 3 5 &&
! aux have_raid 1 4 0 ||

View File

@ -11,6 +11,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
aux have_thin 1 0 0 || skip
aux prepare_pvs 3

View File

@ -13,6 +13,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
aux have_cache 1 3 0 || skip
aux have_raid 1 0 0 || skip

View File

@ -13,6 +13,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
aux have_cache 1 3 0 || skip
aux have_thin 1 0 0 || skip

View File

@ -13,6 +13,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
aux have_cache 1 3 0 || skip
aux prepare_vg 5 80

View File

@ -11,6 +11,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
aux have_raid 1 3 0 || skip
aux prepare_pvs 5

View File

@ -14,6 +14,8 @@ export LVM_TEST_LVMETAD_DEBUG_OPTS=${LVM_TEST_LVMETAD_DEBUG_OPTS-}
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
get_image_pvs() {
local d
local images

View File

@ -11,6 +11,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
get_image_pvs() {
local d
local images

View File

@ -11,6 +11,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
get_image_pvs() {
local d
local images

View File

@ -11,6 +11,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
which mkfs.ext2 || skip
aux mirror_recovery_works || skip

View File

@ -11,6 +11,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
which mkfs.ext3 || skip
aux have_raid 1 3 0 || skip

View File

@ -11,6 +11,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
aux have_raid 1 3 0 || skip
aux raid456_replace_works || skip

View File

@ -11,6 +11,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
aux prepare_vg 5
aux lvmconf 'allocation/maximise_cling = 0' \
'allocation/mirror_logs_require_separate_pvs = 1'

View File

@ -14,6 +14,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
which mkfs.ext2 || skip
#

View File

@ -11,6 +11,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
aux prepare_dmeventd
aux mirror_recovery_works || skip
aux prepare_vg 5

View File

@ -11,6 +11,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
aux mirror_recovery_works || skip
aux prepare_vg 5

View File

@ -14,6 +14,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
aux prepare_pvs 1
vgcreate -s 1k $vg $(cat DEVICES)

View File

@ -14,6 +14,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
which mkfs.ext2 || skip
which fsck || skip

View File

@ -12,6 +12,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
aux have_thin 1 0 0 || skip
aux have_raid 1 4 0 || skip

View File

@ -12,6 +12,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
prepare_lvs() {
lvremove -f $vg
lvcreate -L10M -n $lv1 $vg

View File

@ -16,6 +16,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
aux have_cache 1 3 0 || skip
# FIXME: parallel cache metadata allocator is crashing when used value 8000!

View File

@ -13,6 +13,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
# FIXME update test to make something useful on <16T
aux can_use_16T || skip

View File

@ -13,6 +13,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
# FIXME update test to make something useful on <16T
aux can_use_16T || skip

View File

@ -13,6 +13,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
# FIXME update test to make something useful on <16T
aux can_use_16T || skip

View File

@ -10,6 +10,9 @@
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
aux prepare_vg 5 80
aux lvmconf 'allocation/maximise_cling = 0' \
'allocation/mirror_logs_require_separate_pvs = 1'

View File

@ -11,6 +11,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
aux prepare_vg 2
aux disable_dev "$dev1"

View File

@ -13,6 +13,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
cleanup_lvs() {
lvremove -ff $vg
(dm_table | not grep $vg) || \

View File

@ -11,6 +11,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
aux prepare_pvs 3
aux lvmconf 'allocation/maximise_cling = 0' \
'allocation/mirror_logs_require_separate_pvs = 1'

View File

@ -11,6 +11,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
lv_devices() {
test $3 -eq $(get lv_devices $1/$2 | wc -w)
}

View File

@ -11,6 +11,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
lv_devices() {
test $3 -eq $(get lv_devices $1/$2 | wc -w)
}

View File

@ -11,6 +11,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
aux prepare_vg 3
# fail multiple devices

View File

@ -13,6 +13,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
init_lv_() {
mkswap "$DM_DEV_DIR/$vg/$lv1"
}

View File

@ -11,6 +11,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
aux prepare_pvs
vgcreate -s 1k $vg $(cat DEVICES)

View File

@ -11,6 +11,8 @@
. lib/inittest
test -e LOCAL_LVMPOLLD && skip
aux prepare_vg 9
lvcreate -aey --nosync -i2 -l2 --type mirror -m1 --mirrorlog core -n $lv1 $vg 2>&1 | tee log

Some files were not shown because too many files have changed in this diff Show More