mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-30 17:18:21 +03:00
Remove clvmd and associated code
More code reduction and simplification can follow.
This commit is contained in:
parent
11384637fb
commit
3e781ea446
289
configure.ac
289
configure.ac
@ -46,7 +46,6 @@ case "$host_os" in
|
||||
ODIRECT=yes
|
||||
DM_IOCTLS=yes
|
||||
SELINUX=yes
|
||||
CLUSTER=internal
|
||||
FSADM=yes
|
||||
BLKDEACTIVATE=yes
|
||||
;;
|
||||
@ -61,7 +60,6 @@ case "$host_os" in
|
||||
ODIRECT=no
|
||||
DM_IOCTLS=no
|
||||
SELINUX=no
|
||||
CLUSTER=none
|
||||
FSADM=no
|
||||
BLKDEACTIVATE=no
|
||||
;;
|
||||
@ -282,22 +280,6 @@ esac
|
||||
AC_MSG_RESULT($MANGLING)
|
||||
AC_DEFINE_UNQUOTED([DEFAULT_DM_NAME_MANGLING], $mangling, [Define default name mangling behaviour])
|
||||
|
||||
################################################################################
|
||||
dnl -- cluster_locking inclusion type
|
||||
AC_MSG_CHECKING(whether to include support for cluster locking)
|
||||
AC_ARG_WITH(cluster,
|
||||
AC_HELP_STRING([--with-cluster=TYPE],
|
||||
[cluster LVM locking support: internal/shared/none [internal]]),
|
||||
CLUSTER=$withval)
|
||||
AC_MSG_RESULT($CLUSTER)
|
||||
|
||||
case "$CLUSTER" in
|
||||
none|shared) ;;
|
||||
internal) AC_DEFINE([CLUSTER_LOCKING_INTERNAL], 1,
|
||||
[Define to 1 to include built-in support for clustered LVM locking.]) ;;
|
||||
*) AC_MSG_ERROR([--with-cluster parameter invalid]) ;;
|
||||
esac
|
||||
|
||||
################################################################################
|
||||
dnl -- snapshots inclusion type
|
||||
AC_MSG_CHECKING(whether to include snapshots)
|
||||
@ -671,241 +653,6 @@ AC_ARG_WITH(default-run-dir,
|
||||
AC_DEFINE_UNQUOTED(DEFAULT_RUN_DIR, ["$DEFAULT_RUN_DIR"],
|
||||
[Default LVM run directory.])
|
||||
|
||||
################################################################################
|
||||
dnl -- Build cluster LVM daemon
|
||||
AC_MSG_CHECKING(whether to build cluster LVM daemon)
|
||||
AC_ARG_WITH(clvmd,
|
||||
[ --with-clvmd=TYPE build cluster LVM Daemon
|
||||
The following cluster manager combinations are valid:
|
||||
* cman (RHEL5 or equivalent)
|
||||
* cman,corosync,openais (or selection of them)
|
||||
* singlenode (localhost only)
|
||||
* all (autodetect)
|
||||
* none (disable build)
|
||||
[[none]]],
|
||||
CLVMD=$withval, CLVMD=none)
|
||||
test "$CLVMD" = yes && CLVMD=all
|
||||
AC_MSG_RESULT($CLVMD)
|
||||
|
||||
dnl -- If clvmd enabled without cluster locking, automagically include it
|
||||
test "$CLVMD" != none -a "$CLUSTER" = none && CLUSTER=internal
|
||||
|
||||
dnl -- init pkgconfig if required
|
||||
test "$CLVMD" != none && pkg_config_init
|
||||
|
||||
dnl -- Express clvmd init script Required-Start / Required-Stop
|
||||
CLVMD_CMANAGERS=""
|
||||
dnl -- On RHEL4/RHEL5, qdiskd is started from a separate init script.
|
||||
dnl -- Enable if we are build for cman.
|
||||
CLVMD_NEEDS_QDISKD=no
|
||||
|
||||
dnl -- define build types
|
||||
if [[ `expr x"$CLVMD" : '.*gulm.*'` != 0 ]]; then
|
||||
AC_MSG_ERROR([Since version 2.02.87 GULM locking is no longer supported.]);
|
||||
fi
|
||||
if [[ `expr x"$CLVMD" : '.*cman.*'` != 0 ]]; then
|
||||
BUILDCMAN=yes
|
||||
CLVMD_CMANAGERS="$CLVMD_CMANAGERS cman"
|
||||
CLVMD_NEEDS_QDISKD=yes
|
||||
fi
|
||||
if [[ `expr x"$CLVMD" : '.*corosync.*'` != 0 ]]; then
|
||||
BUILDCOROSYNC=yes
|
||||
CLVMD_CMANAGERS="$CLVMD_CMANAGERS corosync"
|
||||
fi
|
||||
if [[ `expr x"$CLVMD" : '.*openais.*'` != 0 ]]; then
|
||||
BUILDOPENAIS=yes
|
||||
CLVMD_CMANAGERS="$CLVMD_CMANAGERS openais"
|
||||
fi
|
||||
test "$CLVMD_NEEDS_QDISKD" != no && CLVMD_CMANAGERS="$CLVMD_CMANAGERS qdiskd"
|
||||
|
||||
dnl -- define a soft bailout if we are autodetecting
|
||||
soft_bailout() {
|
||||
NOTFOUND=1
|
||||
}
|
||||
|
||||
hard_bailout() {
|
||||
AC_MSG_ERROR([bailing out])
|
||||
}
|
||||
|
||||
dnl -- if clvmd=all then set soft_bailout (we do not want to error)
|
||||
dnl -- and set all builds to yes. We need to do this here
|
||||
dnl -- to skip the openais|corosync sanity check above.
|
||||
if test "$CLVMD" = all; then
|
||||
bailout=soft_bailout
|
||||
BUILDCMAN=yes
|
||||
BUILDCOROSYNC=yes
|
||||
BUILDOPENAIS=yes
|
||||
else
|
||||
bailout=hard_bailout
|
||||
fi
|
||||
|
||||
dnl -- helper macro to check libs without adding them to LIBS
|
||||
check_lib_no_libs() {
|
||||
lib_no_libs_arg1=$1
|
||||
shift
|
||||
lib_no_libs_arg2=$1
|
||||
shift
|
||||
lib_no_libs_args=$@
|
||||
AC_CHECK_LIB([$lib_no_libs_arg1],
|
||||
[$lib_no_libs_arg2],,
|
||||
[$bailout],
|
||||
[$lib_no_libs_args])
|
||||
LIBS=$ac_check_lib_save_LIBS
|
||||
}
|
||||
|
||||
dnl -- Look for cman libraries if required.
|
||||
if test "$BUILDCMAN" = yes; then
|
||||
PKG_CHECK_MODULES(CMAN, libcman, [HAVE_CMAN=yes],
|
||||
[NOTFOUND=0
|
||||
AC_CHECK_HEADERS(libcman.h,,$bailout)
|
||||
check_lib_no_libs cman cman_init
|
||||
if test $NOTFOUND = 0; then
|
||||
AC_MSG_RESULT([no pkg for libcman, using -lcman])
|
||||
CMAN_LIBS="-lcman"
|
||||
HAVE_CMAN=yes
|
||||
fi])
|
||||
CHECKCONFDB=yes
|
||||
CHECKDLM=yes
|
||||
fi
|
||||
|
||||
dnl -- Look for corosync that is required also for openais build
|
||||
dnl -- only enough recent version of corosync ship pkg-config files.
|
||||
dnl -- We can safely rely on that to detect the correct bits.
|
||||
if test "$BUILDCOROSYNC" = yes -o "$BUILDOPENAIS" = yes; then
|
||||
PKG_CHECK_MODULES(COROSYNC, corosync, [HAVE_COROSYNC=yes], $bailout)
|
||||
CHECKCONFDB=yes
|
||||
CHECKCMAP=yes
|
||||
fi
|
||||
|
||||
dnl -- Look for corosync libraries if required.
|
||||
if test "$BUILDCOROSYNC" = yes; then
|
||||
PKG_CHECK_MODULES(QUORUM, libquorum, [HAVE_QUORUM=yes], $bailout)
|
||||
CHECKCPG=yes
|
||||
CHECKDLM=yes
|
||||
fi
|
||||
|
||||
dnl -- Look for openais libraries if required.
|
||||
if test "$BUILDOPENAIS" = yes; then
|
||||
PKG_CHECK_MODULES(SALCK, libSaLck, [HAVE_SALCK=yes], $bailout)
|
||||
CHECKCPG=yes
|
||||
fi
|
||||
|
||||
dnl -- Below are checks for libraries common to more than one build.
|
||||
|
||||
dnl -- Check confdb library.
|
||||
dnl -- mandatory for corosync < 2.0 build.
|
||||
dnl -- optional for openais/cman build.
|
||||
|
||||
if test "$CHECKCONFDB" = yes; then
|
||||
PKG_CHECK_MODULES(CONFDB, libconfdb,
|
||||
[HAVE_CONFDB=yes], [HAVE_CONFDB=no])
|
||||
|
||||
AC_CHECK_HEADERS([corosync/confdb.h],
|
||||
[HAVE_CONFDB_H=yes], [HAVE_CONFDB_H=no])
|
||||
|
||||
if test "$HAVE_CONFDB" != yes -a "$HAVE_CONFDB_H" = yes; then
|
||||
check_lib_no_libs confdb confdb_initialize
|
||||
AC_MSG_RESULT([no pkg for confdb, using -lconfdb])
|
||||
CONFDB_LIBS="-lconfdb"
|
||||
HAVE_CONFDB=yes
|
||||
fi
|
||||
fi
|
||||
|
||||
dnl -- Check cmap library
|
||||
dnl -- mandatory for corosync >= 2.0 build.
|
||||
|
||||
if test "$CHECKCMAP" = yes; then
|
||||
PKG_CHECK_MODULES(CMAP, libcmap,
|
||||
[HAVE_CMAP=yes], [HAVE_CMAP=no])
|
||||
|
||||
AC_CHECK_HEADERS([corosync/cmap.h],
|
||||
[HAVE_CMAP_H=yes], [HAVE_CMAP_H=no])
|
||||
|
||||
if test "$HAVE_CMAP" != yes -a "$HAVE_CMAP_H" = yes; then
|
||||
check_lib_no_libs cmap cmap_initialize
|
||||
AC_MSG_RESULT([no pkg for cmap, using -lcmap])
|
||||
CMAP_LIBS="-lcmap"
|
||||
HAVE_CMAP=yes
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "$BUILDCOROSYNC" = yes -a \
|
||||
"$HAVE_CMAP" != yes -a "$HAVE_CONFDB" != yes -a "$CLVMD" != all; then
|
||||
AC_MSG_ERROR([bailing out... cmap (corosync >= 2.0) or confdb (corosync < 2.0) library is required])
|
||||
fi
|
||||
|
||||
dnl -- Check cpg library.
|
||||
if test "$CHECKCPG" = yes; then
|
||||
PKG_CHECK_MODULES(CPG, libcpg, [HAVE_CPG=yes], [$bailout])
|
||||
fi
|
||||
|
||||
dnl -- Check dlm library.
|
||||
if test "$CHECKDLM" = yes; then
|
||||
PKG_CHECK_MODULES(DLM, libdlm, [HAVE_DLM=yes],
|
||||
[NOTFOUND=0
|
||||
AC_CHECK_HEADERS(libdlm.h,,[$bailout])
|
||||
check_lib_no_libs dlm dlm_lock -lpthread
|
||||
if test $NOTFOUND = 0; then
|
||||
AC_MSG_RESULT([no pkg for libdlm, using -ldlm])
|
||||
DLM_LIBS="-ldlm -lpthread"
|
||||
HAVE_DLM=yes
|
||||
fi])
|
||||
fi
|
||||
|
||||
dnl -- If we are autodetecting, we need to re-create
|
||||
dnl -- the depedencies checks and set a proper CLVMD,
|
||||
dnl -- together with init script Required-Start/Stop entries.
|
||||
if test "$CLVMD" = all; then
|
||||
CLVMD=none
|
||||
CLVMD_CMANAGERS=""
|
||||
CLVMD_NEEDS_QDISKD=no
|
||||
if test "$HAVE_CMAN" = yes -a \
|
||||
"$HAVE_DLM" = yes; then
|
||||
AC_MSG_RESULT([Enabling clvmd cman cluster manager])
|
||||
CLVMD="$CLVMD,cman"
|
||||
CLVMD_CMANAGERS="$CLVMD_CMANAGERS cman"
|
||||
CLVMD_NEEDS_QDISKD=yes
|
||||
fi
|
||||
if test "$HAVE_COROSYNC" = yes -a \
|
||||
"$HAVE_QUORUM" = yes -a \
|
||||
"$HAVE_CPG" = yes -a \
|
||||
"$HAVE_DLM" = yes; then
|
||||
if test "$HAVE_CONFDB" = yes -o "$HAVE_CMAP" = yes; then
|
||||
AC_MSG_RESULT([Enabling clvmd corosync cluster manager])
|
||||
CLVMD="$CLVMD,corosync"
|
||||
CLVMD_CMANAGERS="$CLVMD_CMANAGERS corosync"
|
||||
fi
|
||||
fi
|
||||
if test "$HAVE_COROSYNC" = yes -a \
|
||||
"$HAVE_CPG" = yes -a \
|
||||
"$HAVE_SALCK" = yes; then
|
||||
AC_MSG_RESULT([Enabling clvmd openais cluster manager])
|
||||
CLVMD="$CLVMD,openais"
|
||||
CLVMD_CMANAGERS="$CLVMD_CMANAGERS openais"
|
||||
fi
|
||||
test "$CLVMD_NEEDS_QDISKD" != no && CLVMD_CMANAGERS="$CLVMD_CMANAGERS qdiskd"
|
||||
test "$CLVMD" = none && AC_MSG_RESULT([Disabling clvmd build. No cluster manager detected.])
|
||||
fi
|
||||
|
||||
dnl -- Fixup CLVMD_CMANAGERS with new corosync
|
||||
dnl -- clvmd built with corosync >= 2.0 needs dlm (either init or systemd service)
|
||||
dnl -- to be started.
|
||||
if [[ `expr x"$CLVMD" : '.*corosync.*'` != 0 ]]; then
|
||||
test "$HAVE_CMAP" = yes && CLVMD_CMANAGERS="$CLVMD_CMANAGERS dlm"
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- clvmd pidfile
|
||||
if test "$CLVMD" != none; then
|
||||
AC_ARG_WITH(clvmd-pidfile,
|
||||
AC_HELP_STRING([--with-clvmd-pidfile=PATH],
|
||||
[clvmd pidfile [PID_DIR/clvmd.pid]]),
|
||||
CLVMD_PIDFILE=$withval,
|
||||
CLVMD_PIDFILE="$DEFAULT_PID_DIR/clvmd.pid")
|
||||
AC_DEFINE_UNQUOTED(CLVMD_PIDFILE, ["$CLVMD_PIDFILE"],
|
||||
[Path to clvmd pidfile.])
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Build cluster mirror log daemon
|
||||
AC_MSG_CHECKING(whether to build cluster mirror log daemon)
|
||||
@ -934,11 +681,6 @@ dnl -- Look for corosync libraries if required.
|
||||
if [[ "$BUILD_CMIRRORD" = yes ]]; then
|
||||
pkg_config_init
|
||||
|
||||
AC_DEFINE([CMIRROR_HAS_CHECKPOINT], 1, [Define to 1 to include libSaCkpt.])
|
||||
PKG_CHECK_MODULES(SACKPT, libSaCkpt, [HAVE_SACKPT=yes],
|
||||
[AC_MSG_RESULT([no libSaCkpt, compiling without it])
|
||||
AC_DEFINE([CMIRROR_HAS_CHECKPOINT], 0, [Define to 0 to exclude libSaCkpt.])])
|
||||
|
||||
if test "$HAVE_CPG" != yes; then
|
||||
PKG_CHECK_MODULES(CPG, libcpg)
|
||||
fi
|
||||
@ -1538,7 +1280,7 @@ AC_CHECK_LIB(dl, dlopen,
|
||||
|
||||
################################################################################
|
||||
dnl -- Check for shared/static conflicts
|
||||
if [[ \( "$LVM1" = shared -o "$POOL" = shared -o "$CLUSTER" = shared \
|
||||
if [[ \( "$LVM1" = shared -o "$POOL" = shared \
|
||||
\) -a "$STATIC_LINK" = yes ]]; then
|
||||
AC_MSG_ERROR([Features cannot be 'shared' when building statically])
|
||||
fi
|
||||
@ -1758,18 +1500,6 @@ if test "$BUILD_LVMPOLLD" = yes; then
|
||||
AC_FUNC_STRERROR_R
|
||||
fi
|
||||
|
||||
if test "$CLVMD" != none; then
|
||||
AC_CHECK_HEADERS(mntent.h netdb.h netinet/in.h pthread.h search.h sys/mount.h sys/socket.h sys/uio.h sys/un.h utmpx.h,,AC_MSG_ERROR(bailing out))
|
||||
AC_CHECK_FUNCS(dup2 getmntent memmove select socket,,hard_bailout)
|
||||
AC_FUNC_GETMNTENT
|
||||
AC_FUNC_SELECT_ARGTYPES
|
||||
fi
|
||||
|
||||
if test "$CLUSTER" != none; then
|
||||
AC_CHECK_HEADERS(sys/socket.h sys/un.h,,hard_bailout)
|
||||
AC_CHECK_FUNCS(socket,,hard_bailout)
|
||||
fi
|
||||
|
||||
if test "$BUILD_DMEVENTD" = yes; then
|
||||
AC_CHECK_HEADERS(arpa/inet.h,,hard_bailout)
|
||||
fi
|
||||
@ -1804,8 +1534,6 @@ LVM_PATH="$SBINDIR/lvm"
|
||||
AC_DEFINE_UNQUOTED(LVM_PATH, ["$LVM_PATH"], [Path to lvm binary.])
|
||||
|
||||
USRSBINDIR="$(eval echo $(eval echo $usrsbindir))"
|
||||
CLVMD_PATH="$USRSBINDIR/clvmd"
|
||||
AC_DEFINE_UNQUOTED(CLVMD_PATH, ["$CLVMD_PATH"], [Path to clvmd binary.])
|
||||
|
||||
FSADM_PATH="$SBINDIR/fsadm"
|
||||
AC_DEFINE_UNQUOTED(FSADM_PATH, ["$FSADM_PATH"], [Path to fsadm binary.])
|
||||
@ -1944,14 +1672,6 @@ AC_SUBST(CHMOD)
|
||||
AC_SUBST(CLDFLAGS)
|
||||
AC_SUBST(CLDNOWHOLEARCHIVE)
|
||||
AC_SUBST(CLDWHOLEARCHIVE)
|
||||
AC_SUBST(CLUSTER)
|
||||
AC_SUBST(CLVMD)
|
||||
AC_SUBST(CLVMD_CMANAGERS)
|
||||
AC_SUBST(CLVMD_PATH)
|
||||
AC_SUBST(CMAN_CFLAGS)
|
||||
AC_SUBST(CMAN_LIBS)
|
||||
AC_SUBST(CMAP_CFLAGS)
|
||||
AC_SUBST(CMAP_LIBS)
|
||||
AC_SUBST(CMDLIB)
|
||||
AC_SUBST(CONFDB_CFLAGS)
|
||||
AC_SUBST(CONFDB_LIBS)
|
||||
@ -2067,7 +1787,6 @@ AC_SUBST(DMEVENTD_PIDFILE)
|
||||
AC_SUBST(LVMETAD_PIDFILE)
|
||||
AC_SUBST(LVMPOLLD_PIDFILE)
|
||||
AC_SUBST(LVMLOCKD_PIDFILE)
|
||||
AC_SUBST(CLVMD_PIDFILE)
|
||||
AC_SUBST(CMIRRORD_PIDFILE)
|
||||
AC_SUBST(interface)
|
||||
AC_SUBST(kerneldir)
|
||||
@ -2090,7 +1809,6 @@ Makefile
|
||||
make.tmpl
|
||||
libdm/make.tmpl
|
||||
daemons/Makefile
|
||||
daemons/clvmd/Makefile
|
||||
daemons/cmirrord/Makefile
|
||||
daemons/dmeventd/Makefile
|
||||
daemons/dmeventd/libdevmapper-event.pc
|
||||
@ -2116,7 +1834,6 @@ conf/command_profile_template.profile
|
||||
conf/metadata_profile_template.profile
|
||||
include/Makefile
|
||||
lib/Makefile
|
||||
lib/locking/Makefile
|
||||
include/lvm-version.h
|
||||
libdaemon/Makefile
|
||||
libdaemon/client/Makefile
|
||||
@ -2132,14 +1849,10 @@ 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/com.redhat.lvmdbus1.service
|
||||
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_lvmdbusd_systemd_red_hat.service
|
||||
scripts/lvm2_lvmetad_init_red_hat
|
||||
|
@ -15,11 +15,7 @@ srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
top_builddir = @top_builddir@
|
||||
|
||||
.PHONY: dmeventd clvmd cmirrord lvmetad lvmpolld lvmlockd
|
||||
|
||||
ifneq ("@CLVMD@", "none")
|
||||
SUBDIRS += clvmd
|
||||
endif
|
||||
.PHONY: dmeventd cmirrord lvmetad lvmpolld lvmlockd
|
||||
|
||||
ifeq ("@BUILD_CMIRRORD@", "yes")
|
||||
SUBDIRS += cmirrord
|
||||
@ -53,7 +49,7 @@ ifeq ("@BUILD_DMFILEMAPD@", "yes")
|
||||
endif
|
||||
|
||||
ifeq ($(MAKECMDGOALS),distclean)
|
||||
SUBDIRS = clvmd cmirrord dmeventd lvmetad lvmpolld lvmlockd lvmdbusd dmfilemapd
|
||||
SUBDIRS = cmirrord dmeventd lvmetad lvmpolld lvmlockd lvmdbusd dmfilemapd
|
||||
endif
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
1
daemons/clvmd/.gitignore
vendored
1
daemons/clvmd/.gitignore
vendored
@ -1 +0,0 @@
|
||||
clvmd
|
@ -1,94 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2004 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
top_builddir = @top_builddir@
|
||||
|
||||
CMAN_LIBS = @CMAN_LIBS@
|
||||
CMAN_CFLAGS = @CMAN_CFLAGS@
|
||||
CMAP_LIBS = @CMAP_LIBS@
|
||||
CMAP_CFLAGS = @CMAP_CFLAGS@
|
||||
CONFDB_LIBS = @CONFDB_LIBS@
|
||||
CONFDB_CFLAGS = @CONFDB_CFLAGS@
|
||||
CPG_LIBS = @CPG_LIBS@
|
||||
CPG_CFLAGS = @CPG_CFLAGS@
|
||||
DLM_LIBS = @DLM_LIBS@
|
||||
DLM_CFLAGS = @DLM_CFLAGS@
|
||||
QUORUM_LIBS = @QUORUM_LIBS@
|
||||
QUORUM_CFLAGS = @QUORUM_CFLAGS@
|
||||
SALCK_LIBS = @SALCK_LIBS@
|
||||
SALCK_CFLAGS = @SALCK_CFLAGS@
|
||||
|
||||
SOURCES = \
|
||||
clvmd-command.c\
|
||||
clvmd.c\
|
||||
lvm-functions.c\
|
||||
refresh_clvmd.c
|
||||
|
||||
ifneq (,$(findstring cman,, "@CLVMD@,"))
|
||||
SOURCES += clvmd-cman.c
|
||||
LMLIBS += $(CMAN_LIBS) $(CONFDB_LIBS) $(DLM_LIBS)
|
||||
CFLAGS += $(CMAN_CFLAGS) $(CONFDB_CFLAGS) $(DLM_CFLAGS)
|
||||
DEFS += -DUSE_CMAN
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring openais,, "@CLVMD@,"))
|
||||
SOURCES += clvmd-openais.c
|
||||
LMLIBS += $(CONFDB_LIBS) $(CPG_LIBS) $(SALCK_LIBS)
|
||||
CFLAGS += $(CONFDB_CFLAGS) $(CPG_CFLAGS) $(SALCK_CFLAGS)
|
||||
DEFS += -DUSE_OPENAIS
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring corosync,, "@CLVMD@,"))
|
||||
SOURCES += clvmd-corosync.c
|
||||
LMLIBS += $(CMAP_LIBS) $(CONFDB_LIBS) $(CPG_LIBS) $(DLM_LIBS) $(QUORUM_LIBS)
|
||||
CFLAGS += $(CMAP_CFLAGS) $(CONFDB_CFLAGS) $(CPG_CFLAGS) $(DLM_CFLAGS) $(QUORUM_CFLAGS)
|
||||
DEFS += -DUSE_COROSYNC
|
||||
endif
|
||||
|
||||
ifneq (,$(findstring singlenode,, "@CLVMD@,"))
|
||||
SOURCES += clvmd-singlenode.c
|
||||
DEFS += -DUSE_SINGLENODE
|
||||
endif
|
||||
|
||||
ifeq ($(MAKECMDGOALS),distclean)
|
||||
SOURCES += clvmd-cman.c
|
||||
SOURCES += clvmd-openais.c
|
||||
SOURCES += clvmd-corosync.c
|
||||
SOURCES += clvmd-singlenode.c
|
||||
endif
|
||||
|
||||
TARGETS = \
|
||||
clvmd
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
LIBS += $(LVMINTERNAL_LIBS) $(PTHREAD_LIBS) -laio
|
||||
CFLAGS += -fno-strict-aliasing $(EXTRA_EXEC_CFLAGS)
|
||||
|
||||
INSTALL_TARGETS = \
|
||||
install_clvmd
|
||||
|
||||
clvmd: $(OBJECTS) $(top_builddir)/lib/liblvm-internal.a $(INTERNAL_LIBS)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) \
|
||||
-o clvmd $+ $(LMLIBS) $(LIBS)
|
||||
|
||||
.PHONY: install_clvmd
|
||||
|
||||
install_clvmd: $(TARGETS)
|
||||
$(INSTALL_PROGRAM) -D clvmd $(usrsbindir)/clvmd
|
||||
|
||||
install: $(INSTALL_TARGETS)
|
||||
|
||||
install_cluster: $(INSTALL_TARGETS)
|
@ -1,85 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2007 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/* Definitions for CLVMD server and clients */
|
||||
|
||||
/*
|
||||
* The protocol spoken over the cluster and across the local socket.
|
||||
*/
|
||||
|
||||
#ifndef _CLVM_H
|
||||
#define _CLVM_H
|
||||
|
||||
#include "configure.h"
|
||||
#include <inttypes.h>
|
||||
|
||||
struct clvm_header {
|
||||
uint8_t cmd; /* See below */
|
||||
uint8_t flags; /* See below */
|
||||
uint16_t xid; /* Transaction ID */
|
||||
uint32_t clientid; /* Only used in Daemon->Daemon comms */
|
||||
int32_t status; /* For replies, whether request succeeded */
|
||||
uint32_t arglen; /* Length of argument below.
|
||||
If >1500 then it will be passed
|
||||
around the cluster in the system LV */
|
||||
char node[1]; /* Actually a NUL-terminated string, node name.
|
||||
If this is empty then the command is
|
||||
forwarded to all cluster nodes unless
|
||||
FLAG_LOCAL or FLAG_REMOTE is also set. */
|
||||
char args[1]; /* Arguments for the command follow the
|
||||
node name, This member is only
|
||||
valid if the node name is empty */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Flags */
|
||||
#define CLVMD_FLAG_LOCAL 1 /* Only do this on the local node */
|
||||
#define CLVMD_FLAG_SYSTEMLV 2 /* Data in system LV under my node name */
|
||||
#define CLVMD_FLAG_NODEERRS 4 /* Reply has errors in node-specific portion */
|
||||
#define CLVMD_FLAG_REMOTE 8 /* Do this on all nodes except for the local node */
|
||||
|
||||
/* Name of the local socket to communicate between lvm and clvmd */
|
||||
#define CLVMD_SOCKNAME DEFAULT_RUN_DIR "/clvmd.sock"
|
||||
|
||||
/* Internal commands & replies */
|
||||
#define CLVMD_CMD_REPLY 1
|
||||
#define CLVMD_CMD_VERSION 2 /* Send version around cluster when we start */
|
||||
#define CLVMD_CMD_GOAWAY 3 /* Die if received this - we are running
|
||||
an incompatible version */
|
||||
#define CLVMD_CMD_TEST 4 /* Just for mucking about */
|
||||
|
||||
#define CLVMD_CMD_LOCK 30
|
||||
#define CLVMD_CMD_UNLOCK 31
|
||||
|
||||
/* Lock/Unlock commands */
|
||||
#define CLVMD_CMD_LOCK_LV 50
|
||||
#define CLVMD_CMD_LOCK_VG 51
|
||||
#define CLVMD_CMD_LOCK_QUERY 52
|
||||
|
||||
/* Misc functions */
|
||||
#define CLVMD_CMD_REFRESH 40
|
||||
#define CLVMD_CMD_GET_CLUSTERNAME 41
|
||||
#define CLVMD_CMD_SET_DEBUG 42
|
||||
#define CLVMD_CMD_VG_BACKUP 43
|
||||
#define CLVMD_CMD_RESTART 44
|
||||
#define CLVMD_CMD_SYNC_NAMES 45
|
||||
|
||||
/* Used internally by some callers, but not part of the protocol.*/
|
||||
#ifndef NODE_ALL
|
||||
# define NODE_ALL "*"
|
||||
# define NODE_LOCAL "."
|
||||
# define NODE_REMOTE "^"
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,505 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* CMAN communication layer for clvmd.
|
||||
*/
|
||||
|
||||
#include "clvmd-common.h"
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "clvmd-comms.h"
|
||||
#include "daemons/clvmd/clvm.h"
|
||||
#include "clvmd.h"
|
||||
#include "lvm-functions.h"
|
||||
|
||||
#include <libdlm.h>
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
#define LOCKSPACE_NAME "clvmd"
|
||||
|
||||
struct clvmd_node
|
||||
{
|
||||
struct cman_node *node;
|
||||
int clvmd_up;
|
||||
};
|
||||
|
||||
static int num_nodes;
|
||||
static struct cman_node *nodes = NULL;
|
||||
static struct cman_node this_node;
|
||||
static int count_nodes; /* size of allocated nodes array */
|
||||
static struct dm_hash_table *node_updown_hash;
|
||||
static dlm_lshandle_t *lockspace;
|
||||
static cman_handle_t c_handle;
|
||||
|
||||
static void count_clvmds_running(void);
|
||||
static void get_members(void);
|
||||
static int nodeid_from_csid(const char *csid);
|
||||
static int name_from_nodeid(int nodeid, char *name);
|
||||
static void event_callback(cman_handle_t handle, void *private, int reason, int arg);
|
||||
static void data_callback(cman_handle_t handle, void *private,
|
||||
char *buf, int len, uint8_t port, int nodeid);
|
||||
|
||||
struct lock_wait {
|
||||
pthread_cond_t cond;
|
||||
pthread_mutex_t mutex;
|
||||
struct dlm_lksb lksb;
|
||||
};
|
||||
|
||||
static int _init_cluster(void)
|
||||
{
|
||||
node_updown_hash = dm_hash_create(100);
|
||||
|
||||
/* Open the cluster communication socket */
|
||||
c_handle = cman_init(NULL);
|
||||
if (!c_handle) {
|
||||
syslog(LOG_ERR, "Can't open cluster manager socket: %m");
|
||||
return -1;
|
||||
}
|
||||
DEBUGLOG("Connected to CMAN\n");
|
||||
|
||||
if (cman_start_recv_data(c_handle, data_callback, CLUSTER_PORT_CLVMD)) {
|
||||
syslog(LOG_ERR, "Can't bind cluster socket: %m");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cman_start_notification(c_handle, event_callback)) {
|
||||
syslog(LOG_ERR, "Can't start cluster event listening");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get the cluster members list */
|
||||
get_members();
|
||||
count_clvmds_running();
|
||||
|
||||
DEBUGLOG("CMAN initialisation complete\n");
|
||||
|
||||
/* Create a lockspace for LV & VG locks to live in */
|
||||
lockspace = dlm_open_lockspace(LOCKSPACE_NAME);
|
||||
if (!lockspace) {
|
||||
lockspace = dlm_create_lockspace(LOCKSPACE_NAME, 0600);
|
||||
if (!lockspace) {
|
||||
syslog(LOG_ERR, "Unable to create DLM lockspace for CLVM: %m");
|
||||
return -1;
|
||||
}
|
||||
DEBUGLOG("Created DLM lockspace for CLVMD.\n");
|
||||
} else
|
||||
DEBUGLOG("Opened existing DLM lockspace for CLVMD.\n");
|
||||
|
||||
dlm_ls_pthread_init(lockspace);
|
||||
DEBUGLOG("DLM initialisation complete\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _cluster_init_completed(void)
|
||||
{
|
||||
clvmd_cluster_init_completed();
|
||||
}
|
||||
|
||||
static int _get_main_cluster_fd(void)
|
||||
{
|
||||
return cman_get_fd(c_handle);
|
||||
}
|
||||
|
||||
static int _get_num_nodes(void)
|
||||
{
|
||||
int i;
|
||||
int nnodes = 0;
|
||||
|
||||
/* return number of ACTIVE nodes */
|
||||
for (i=0; i<num_nodes; i++) {
|
||||
if (nodes[i].cn_member && nodes[i].cn_nodeid)
|
||||
nnodes++;
|
||||
}
|
||||
return nnodes;
|
||||
}
|
||||
|
||||
/* send_message with the fd check removed */
|
||||
static int _cluster_send_message(const void *buf, int msglen, const char *csid,
|
||||
const char *errtext)
|
||||
{
|
||||
int nodeid = 0;
|
||||
|
||||
if (csid)
|
||||
memcpy(&nodeid, csid, CMAN_MAX_CSID_LEN);
|
||||
|
||||
if (cman_send_data(c_handle, buf, msglen, 0, CLUSTER_PORT_CLVMD, nodeid) <= 0)
|
||||
{
|
||||
log_error("%s", errtext);
|
||||
}
|
||||
return msglen;
|
||||
}
|
||||
|
||||
static void _get_our_csid(char *csid)
|
||||
{
|
||||
if (this_node.cn_nodeid == 0) {
|
||||
cman_get_node(c_handle, 0, &this_node);
|
||||
}
|
||||
memcpy(csid, &this_node.cn_nodeid, CMAN_MAX_CSID_LEN);
|
||||
}
|
||||
|
||||
/* Call a callback routine for each node is that known (down means not running a clvmd) */
|
||||
static int _cluster_do_node_callback(struct local_client *client,
|
||||
void (*callback) (struct local_client *,
|
||||
const char *,
|
||||
int))
|
||||
{
|
||||
int i;
|
||||
int somedown = 0;
|
||||
|
||||
for (i = 0; i < _get_num_nodes(); i++) {
|
||||
if (nodes[i].cn_member && nodes[i].cn_nodeid) {
|
||||
int up = (int)(long)dm_hash_lookup_binary(node_updown_hash, (char *)&nodes[i].cn_nodeid, sizeof(int));
|
||||
|
||||
callback(client, (char *)&nodes[i].cn_nodeid, up);
|
||||
if (!up)
|
||||
somedown = -1;
|
||||
}
|
||||
}
|
||||
return somedown;
|
||||
}
|
||||
|
||||
/* Process OOB messages from the cluster socket */
|
||||
static void event_callback(cman_handle_t handle, void *private, int reason, int arg)
|
||||
{
|
||||
char namebuf[MAX_CLUSTER_MEMBER_NAME_LEN];
|
||||
|
||||
switch (reason) {
|
||||
case CMAN_REASON_PORTCLOSED:
|
||||
name_from_nodeid(arg, namebuf);
|
||||
log_notice("clvmd on node %s has died\n", namebuf);
|
||||
DEBUGLOG("Got port closed message, removing node %s\n", namebuf);
|
||||
|
||||
dm_hash_insert_binary(node_updown_hash, (char *)&arg, sizeof(int), (void *)0);
|
||||
break;
|
||||
|
||||
case CMAN_REASON_STATECHANGE:
|
||||
DEBUGLOG("Got state change message, re-reading members list\n");
|
||||
get_members();
|
||||
break;
|
||||
|
||||
#if defined(LIBCMAN_VERSION) && LIBCMAN_VERSION >= 2
|
||||
case CMAN_REASON_PORTOPENED:
|
||||
/* Ignore this, wait for startup message from clvmd itself */
|
||||
break;
|
||||
|
||||
case CMAN_REASON_TRY_SHUTDOWN:
|
||||
DEBUGLOG("Got try shutdown, sending OK\n");
|
||||
cman_replyto_shutdown(c_handle, 1);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
/* ERROR */
|
||||
DEBUGLOG("Got unknown event callback message: %d\n", reason);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static struct local_client *cman_client;
|
||||
static int _cluster_fd_callback(struct local_client *fd, char *buf, int len,
|
||||
const char *csid,
|
||||
struct local_client **new_client)
|
||||
{
|
||||
|
||||
/* Save this for data_callback */
|
||||
cman_client = fd;
|
||||
|
||||
/* We never return a new client */
|
||||
*new_client = NULL;
|
||||
|
||||
return cman_dispatch(c_handle, 0);
|
||||
}
|
||||
|
||||
|
||||
static void data_callback(cman_handle_t handle, void *private,
|
||||
char *buf, int len, uint8_t port, int nodeid)
|
||||
{
|
||||
/* Ignore looped back messages */
|
||||
if (nodeid == this_node.cn_nodeid)
|
||||
return;
|
||||
process_message(cman_client, buf, len, (char *)&nodeid);
|
||||
}
|
||||
|
||||
static void _add_up_node(const char *csid)
|
||||
{
|
||||
/* It's up ! */
|
||||
int nodeid = nodeid_from_csid(csid);
|
||||
|
||||
dm_hash_insert_binary(node_updown_hash, (char *)&nodeid, sizeof(int), (void *)1);
|
||||
DEBUGLOG("Added new node %d to updown list\n", nodeid);
|
||||
}
|
||||
|
||||
static void _cluster_closedown(void)
|
||||
{
|
||||
dlm_release_lockspace(LOCKSPACE_NAME, lockspace, 1);
|
||||
cman_finish(c_handle);
|
||||
}
|
||||
|
||||
static int is_listening(int nodeid)
|
||||
{
|
||||
int status;
|
||||
|
||||
do {
|
||||
status = cman_is_listening(c_handle, nodeid, CLUSTER_PORT_CLVMD);
|
||||
if (status < 0 && errno == EBUSY) { /* Don't busywait */
|
||||
sleep(1);
|
||||
errno = EBUSY; /* In case sleep trashes it */
|
||||
}
|
||||
}
|
||||
while (status < 0 && errno == EBUSY);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Populate the list of CLVMDs running.
|
||||
called only at startup time */
|
||||
static void count_clvmds_running(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
int nodeid = nodes[i].cn_nodeid;
|
||||
|
||||
if (is_listening(nodeid) == 1)
|
||||
dm_hash_insert_binary(node_updown_hash, (void *)&nodeid, sizeof(int), (void*)1);
|
||||
else
|
||||
dm_hash_insert_binary(node_updown_hash, (void *)&nodeid, sizeof(int), (void*)0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get a list of active cluster members */
|
||||
static void get_members(void)
|
||||
{
|
||||
int retnodes;
|
||||
int status;
|
||||
int i;
|
||||
int high_nodeid = 0;
|
||||
|
||||
num_nodes = cman_get_node_count(c_handle);
|
||||
if (num_nodes == -1) {
|
||||
log_error("Unable to get node count");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Not enough room for new nodes list ? */
|
||||
if (num_nodes > count_nodes && nodes) {
|
||||
free(nodes);
|
||||
nodes = NULL;
|
||||
}
|
||||
|
||||
if (nodes == NULL) {
|
||||
count_nodes = num_nodes + 10; /* Overallocate a little */
|
||||
nodes = malloc(count_nodes * sizeof(struct cman_node));
|
||||
if (!nodes) {
|
||||
log_error("Unable to allocate nodes array\n");
|
||||
exit(5);
|
||||
}
|
||||
}
|
||||
|
||||
status = cman_get_nodes(c_handle, count_nodes, &retnodes, nodes);
|
||||
if (status < 0) {
|
||||
log_error("Unable to get node details");
|
||||
exit(6);
|
||||
}
|
||||
|
||||
/* Get the highest nodeid */
|
||||
for (i=0; i<retnodes; i++) {
|
||||
if (nodes[i].cn_nodeid > high_nodeid)
|
||||
high_nodeid = nodes[i].cn_nodeid;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Convert a node name to a CSID */
|
||||
static int _csid_from_name(char *csid, const char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
if (strcmp(name, nodes[i].cn_name) == 0) {
|
||||
memcpy(csid, &nodes[i].cn_nodeid, CMAN_MAX_CSID_LEN);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Convert a CSID to a node name */
|
||||
static int _name_from_csid(const char *csid, char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
if (memcmp(csid, &nodes[i].cn_nodeid, CMAN_MAX_CSID_LEN) == 0) {
|
||||
strcpy(name, nodes[i].cn_name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* Who?? */
|
||||
strcpy(name, "Unknown");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Convert a node ID to a node name */
|
||||
static int name_from_nodeid(int nodeid, char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
if (nodeid == nodes[i].cn_nodeid) {
|
||||
strcpy(name, nodes[i].cn_name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* Who?? */
|
||||
strcpy(name, "Unknown");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Convert a CSID to a node ID */
|
||||
static int nodeid_from_csid(const char *csid)
|
||||
{
|
||||
int nodeid;
|
||||
|
||||
memcpy(&nodeid, csid, CMAN_MAX_CSID_LEN);
|
||||
|
||||
return nodeid;
|
||||
}
|
||||
|
||||
static int _is_quorate(void)
|
||||
{
|
||||
return cman_is_quorate(c_handle);
|
||||
}
|
||||
|
||||
static void sync_ast_routine(void *arg)
|
||||
{
|
||||
struct lock_wait *lwait = arg;
|
||||
|
||||
pthread_mutex_lock(&lwait->mutex);
|
||||
pthread_cond_signal(&lwait->cond);
|
||||
pthread_mutex_unlock(&lwait->mutex);
|
||||
}
|
||||
|
||||
static int _sync_lock(const char *resource, int mode, int flags, int *lockid)
|
||||
{
|
||||
int status;
|
||||
struct lock_wait lwait;
|
||||
|
||||
if (!lockid) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUGLOG("sync_lock: '%s' mode:%d flags=%d\n", resource,mode,flags);
|
||||
/* Conversions need the lockid in the LKSB */
|
||||
if (flags & LKF_CONVERT)
|
||||
lwait.lksb.sb_lkid = *lockid;
|
||||
|
||||
pthread_cond_init(&lwait.cond, NULL);
|
||||
pthread_mutex_init(&lwait.mutex, NULL);
|
||||
pthread_mutex_lock(&lwait.mutex);
|
||||
|
||||
status = dlm_ls_lock(lockspace,
|
||||
mode,
|
||||
&lwait.lksb,
|
||||
flags,
|
||||
resource,
|
||||
strlen(resource),
|
||||
0, sync_ast_routine, &lwait, NULL, NULL);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
/* Wait for it to complete */
|
||||
pthread_cond_wait(&lwait.cond, &lwait.mutex);
|
||||
pthread_mutex_unlock(&lwait.mutex);
|
||||
|
||||
*lockid = lwait.lksb.sb_lkid;
|
||||
|
||||
errno = lwait.lksb.sb_status;
|
||||
DEBUGLOG("sync_lock: returning lkid %x\n", *lockid);
|
||||
if (lwait.lksb.sb_status)
|
||||
return -1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _sync_unlock(const char *resource /* UNUSED */, int lockid)
|
||||
{
|
||||
int status;
|
||||
struct lock_wait lwait;
|
||||
|
||||
DEBUGLOG("sync_unlock: '%s' lkid:%x\n", resource, lockid);
|
||||
|
||||
pthread_cond_init(&lwait.cond, NULL);
|
||||
pthread_mutex_init(&lwait.mutex, NULL);
|
||||
pthread_mutex_lock(&lwait.mutex);
|
||||
|
||||
status = dlm_ls_unlock(lockspace, lockid, 0, &lwait.lksb, &lwait);
|
||||
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
/* Wait for it to complete */
|
||||
pthread_cond_wait(&lwait.cond, &lwait.mutex);
|
||||
pthread_mutex_unlock(&lwait.mutex);
|
||||
|
||||
errno = lwait.lksb.sb_status;
|
||||
if (lwait.lksb.sb_status != EUNLOCK)
|
||||
return -1;
|
||||
else
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int _get_cluster_name(char *buf, int buflen)
|
||||
{
|
||||
cman_cluster_t cluster_info;
|
||||
int status;
|
||||
|
||||
status = cman_get_cluster(c_handle, &cluster_info);
|
||||
if (!status) {
|
||||
strncpy(buf, cluster_info.ci_name, buflen);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static struct cluster_ops _cluster_cman_ops = {
|
||||
.name = "cman",
|
||||
.cluster_init_completed = _cluster_init_completed,
|
||||
.cluster_send_message = _cluster_send_message,
|
||||
.name_from_csid = _name_from_csid,
|
||||
.csid_from_name = _csid_from_name,
|
||||
.get_num_nodes = _get_num_nodes,
|
||||
.cluster_fd_callback = _cluster_fd_callback,
|
||||
.get_main_cluster_fd = _get_main_cluster_fd,
|
||||
.cluster_do_node_callback = _cluster_do_node_callback,
|
||||
.is_quorate = _is_quorate,
|
||||
.get_our_csid = _get_our_csid,
|
||||
.add_up_node = _add_up_node,
|
||||
.cluster_closedown = _cluster_closedown,
|
||||
.get_cluster_name = _get_cluster_name,
|
||||
.sync_lock = _sync_lock,
|
||||
.sync_unlock = _sync_unlock,
|
||||
};
|
||||
|
||||
struct cluster_ops *init_cman_cluster(void)
|
||||
{
|
||||
if (!_init_cluster())
|
||||
return &_cluster_cman_ops;
|
||||
else
|
||||
return NULL;
|
||||
}
|
@ -1,415 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2011 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
CLVMD Cluster LVM daemon command processor.
|
||||
|
||||
To add commands to the daemon simply add a processor in do_command and return
|
||||
and messages back in buf and the length in *retlen. The initial value of
|
||||
buflen is the maximum size of the buffer. if buf is not large enough then it
|
||||
may be reallocated by the functions in here to a suitable size bearing in
|
||||
mind that anything larger than the passed-in size will have to be returned
|
||||
using the system LV and so performance will suffer.
|
||||
|
||||
The status return will be negated and passed back to the originating node.
|
||||
|
||||
pre- and post- command routines are called only on the local node. The
|
||||
purpose is primarily to get and release locks, though the pre- routine should
|
||||
also do any other local setups required by the command (if any) and can
|
||||
return a failure code that prevents the command from being distributed around
|
||||
the cluster
|
||||
|
||||
The pre- and post- routines are run in their own thread so can block as long
|
||||
they like, do_command is run in the main clvmd thread so should not block for
|
||||
too long. If the pre-command returns an error code (!=0) then the command
|
||||
will not be propogated around the cluster but the post-command WILL be called
|
||||
|
||||
Also note that the pre and post routine are *always* called on the local
|
||||
node, even if the command to be executed was only requested to run on a
|
||||
remote node. It may peek inside the client structure to check the status of
|
||||
the command.
|
||||
|
||||
The clients of the daemon must, naturally, understand the return messages and
|
||||
codes.
|
||||
|
||||
Routines in here may only READ the values in the client structure passed in
|
||||
apart from client->private which they are free to do what they like with.
|
||||
|
||||
*/
|
||||
|
||||
#include "clvmd-common.h"
|
||||
#include "clvmd-comms.h"
|
||||
#include "daemons/clvmd/clvm.h"
|
||||
#include "clvmd.h"
|
||||
#include "lib/misc/lvm-globals.h"
|
||||
#include "lvm-functions.h"
|
||||
|
||||
#include "lib/locking/locking.h"
|
||||
|
||||
#include <sys/utsname.h>
|
||||
|
||||
extern struct cluster_ops *clops;
|
||||
static int restart_clvmd(void);
|
||||
|
||||
/* This is where all the real work happens:
|
||||
NOTE: client will be NULL when this is executed on a remote node */
|
||||
int do_command(struct local_client *client, struct clvm_header *msg, int msglen,
|
||||
char **buf, int buflen, int *retlen)
|
||||
{
|
||||
char *args = msg->node + strlen(msg->node) + 1;
|
||||
int arglen = msglen - sizeof(struct clvm_header) - strlen(msg->node);
|
||||
int status = 0;
|
||||
char *lockname;
|
||||
const char *locktype;
|
||||
struct utsname nodeinfo;
|
||||
unsigned char lock_cmd;
|
||||
unsigned char lock_flags;
|
||||
|
||||
/* Do the command */
|
||||
switch (msg->cmd) {
|
||||
/* Just a test message */
|
||||
case CLVMD_CMD_TEST:
|
||||
if (arglen > buflen) {
|
||||
char *new_buf;
|
||||
buflen = arglen + 200;
|
||||
new_buf = realloc(*buf, buflen);
|
||||
if (new_buf == NULL) {
|
||||
status = errno;
|
||||
free (*buf);
|
||||
}
|
||||
*buf = new_buf;
|
||||
}
|
||||
if (*buf) {
|
||||
if (uname(&nodeinfo))
|
||||
memset(&nodeinfo, 0, sizeof(nodeinfo));
|
||||
|
||||
*retlen = 1 + dm_snprintf(*buf, buflen,
|
||||
"TEST from %s: %s v%s",
|
||||
nodeinfo.nodename, args,
|
||||
nodeinfo.release);
|
||||
}
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_LOCK_VG:
|
||||
lock_cmd = args[0];
|
||||
lock_flags = args[1];
|
||||
lockname = &args[2];
|
||||
/* Check to see if the VG is in use by LVM1 */
|
||||
do_lock_vg(lock_cmd, lock_flags, lockname);
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_LOCK_LV:
|
||||
/* This is the biggie */
|
||||
lock_cmd = args[0];
|
||||
lock_flags = args[1];
|
||||
lockname = &args[2];
|
||||
status = do_lock_lv(lock_cmd, lock_flags, lockname);
|
||||
/* Replace EIO with something less scary */
|
||||
if (status == EIO) {
|
||||
*retlen = 1 + dm_snprintf(*buf, buflen, "%s",
|
||||
get_last_lvm_error());
|
||||
return EIO;
|
||||
}
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_LOCK_QUERY:
|
||||
lockname = &args[2];
|
||||
if (buflen < 3)
|
||||
return EIO;
|
||||
if ((locktype = do_lock_query(lockname)))
|
||||
*retlen = 1 + dm_snprintf(*buf, buflen, "%s", locktype);
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_REFRESH:
|
||||
do_refresh_cache();
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_SYNC_NAMES:
|
||||
lvm_do_fs_unlock();
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_SET_DEBUG:
|
||||
clvmd_set_debug((debug_t) args[0]);
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_RESTART:
|
||||
status = restart_clvmd();
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_GET_CLUSTERNAME:
|
||||
status = clops->get_cluster_name(*buf, buflen);
|
||||
if (!status)
|
||||
*retlen = strlen(*buf)+1;
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_VG_BACKUP:
|
||||
/*
|
||||
* Do not run backup on local node, caller should do that.
|
||||
*/
|
||||
if (!client)
|
||||
lvm_do_backup(&args[2]);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Won't get here because command is validated in pre_command */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check the status of the command and return the error text */
|
||||
if (status) {
|
||||
if (*buf)
|
||||
*retlen = dm_snprintf(*buf, buflen, "%s", strerror(status)) + 1;
|
||||
else
|
||||
*retlen = 0;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int lock_vg(struct local_client *client)
|
||||
{
|
||||
struct dm_hash_table *lock_hash;
|
||||
struct clvm_header *header =
|
||||
(struct clvm_header *) client->bits.localsock.cmd;
|
||||
unsigned char lock_cmd;
|
||||
int lock_mode;
|
||||
char *args = header->node + strlen(header->node) + 1;
|
||||
int lkid;
|
||||
int status;
|
||||
char *lockname;
|
||||
|
||||
/*
|
||||
* Keep a track of VG locks in our own hash table. In current
|
||||
* practice there should only ever be more than two VGs locked
|
||||
* if a user tries to merge lots of them at once
|
||||
*/
|
||||
if (!client->bits.localsock.private) {
|
||||
if (!(lock_hash = dm_hash_create(3)))
|
||||
return ENOMEM;
|
||||
client->bits.localsock.private = (void *) lock_hash;
|
||||
} else
|
||||
lock_hash = (struct dm_hash_table *) client->bits.localsock.private;
|
||||
|
||||
lock_cmd = args[0] & (LCK_NONBLOCK | LCK_HOLD | LCK_SCOPE_MASK | LCK_TYPE_MASK);
|
||||
lock_mode = ((int) lock_cmd & LCK_TYPE_MASK);
|
||||
/* lock_flags = args[1]; */
|
||||
lockname = &args[2];
|
||||
DEBUGLOG("(%p) doing PRE command LOCK_VG '%s' at %x\n", client, lockname, lock_cmd);
|
||||
|
||||
if (lock_mode == LCK_UNLOCK) {
|
||||
if (!(lkid = (int) (long) dm_hash_lookup(lock_hash, lockname)))
|
||||
return EINVAL;
|
||||
|
||||
if ((status = sync_unlock(lockname, lkid)))
|
||||
status = errno;
|
||||
else
|
||||
dm_hash_remove(lock_hash, lockname);
|
||||
} else {
|
||||
/* Read locks need to be PR; other modes get passed through */
|
||||
if (lock_mode == LCK_READ)
|
||||
lock_mode = LCK_PREAD;
|
||||
|
||||
if ((status = sync_lock(lockname, lock_mode, (lock_cmd & LCK_NONBLOCK) ? LCKF_NOQUEUE : 0, &lkid)))
|
||||
status = errno;
|
||||
else if (!dm_hash_insert(lock_hash, lockname, (void *) (long) lkid))
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/* Pre-command is a good place to get locks that are needed only for the duration
|
||||
of the commands around the cluster (don't forget to free them in post-command),
|
||||
and to sanity check the command arguments */
|
||||
int do_pre_command(struct local_client *client)
|
||||
{
|
||||
struct clvm_header *header =
|
||||
(struct clvm_header *) client->bits.localsock.cmd;
|
||||
unsigned char lock_cmd;
|
||||
unsigned char lock_flags;
|
||||
char *args = header->node + strlen(header->node) + 1;
|
||||
int lockid = 0;
|
||||
int status = 0;
|
||||
char *lockname;
|
||||
|
||||
switch (header->cmd) {
|
||||
case CLVMD_CMD_TEST:
|
||||
status = sync_lock("CLVMD_TEST", LCK_EXCL, 0, &lockid);
|
||||
client->bits.localsock.private = (void *)(long)lockid;
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_LOCK_VG:
|
||||
lockname = &args[2];
|
||||
/* We take out a real lock unless LCK_CACHE was set */
|
||||
if (!strncmp(lockname, "V_", 2) ||
|
||||
!strncmp(lockname, "P_#", 3))
|
||||
status = lock_vg(client);
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_LOCK_LV:
|
||||
lock_cmd = args[0];
|
||||
lock_flags = args[1];
|
||||
lockname = &args[2];
|
||||
status = pre_lock_lv(lock_cmd, lock_flags, lockname);
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_REFRESH:
|
||||
case CLVMD_CMD_GET_CLUSTERNAME:
|
||||
case CLVMD_CMD_SET_DEBUG:
|
||||
case CLVMD_CMD_VG_BACKUP:
|
||||
case CLVMD_CMD_SYNC_NAMES:
|
||||
case CLVMD_CMD_LOCK_QUERY:
|
||||
case CLVMD_CMD_RESTART:
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error("Unknown command %d received\n", header->cmd);
|
||||
status = EINVAL;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Note that the post-command routine is called even if the pre-command or the real command
|
||||
failed */
|
||||
int do_post_command(struct local_client *client)
|
||||
{
|
||||
struct clvm_header *header =
|
||||
(struct clvm_header *) client->bits.localsock.cmd;
|
||||
int status = 0;
|
||||
unsigned char lock_cmd;
|
||||
unsigned char lock_flags;
|
||||
char *args = header->node + strlen(header->node) + 1;
|
||||
char *lockname;
|
||||
|
||||
switch (header->cmd) {
|
||||
case CLVMD_CMD_TEST:
|
||||
status = sync_unlock("CLVMD_TEST", (int) (long) client->bits.localsock.private);
|
||||
client->bits.localsock.private = NULL;
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_LOCK_LV:
|
||||
lock_cmd = args[0];
|
||||
lock_flags = args[1];
|
||||
lockname = &args[2];
|
||||
status = post_lock_lv(lock_cmd, lock_flags, lockname);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Nothing to do here */
|
||||
break;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/* Called when the client is about to be deleted */
|
||||
void cmd_client_cleanup(struct local_client *client)
|
||||
{
|
||||
struct dm_hash_node *v;
|
||||
struct dm_hash_table *lock_hash;
|
||||
int lkid;
|
||||
char *lockname;
|
||||
|
||||
DEBUGLOG("(%p) Client thread cleanup\n", client);
|
||||
if (!client->bits.localsock.private)
|
||||
return;
|
||||
|
||||
lock_hash = (struct dm_hash_table *)client->bits.localsock.private;
|
||||
|
||||
dm_hash_iterate(v, lock_hash) {
|
||||
lkid = (int)(long)dm_hash_get_data(lock_hash, v);
|
||||
lockname = dm_hash_get_key(lock_hash, v);
|
||||
DEBUGLOG("(%p) Cleanup: Unlocking lock %s %x\n", client, lockname, lkid);
|
||||
(void) sync_unlock(lockname, lkid);
|
||||
}
|
||||
|
||||
dm_hash_destroy(lock_hash);
|
||||
client->bits.localsock.private = NULL;
|
||||
}
|
||||
|
||||
static int restart_clvmd(void)
|
||||
{
|
||||
const char **argv;
|
||||
char *lv_name;
|
||||
int argc = 0, max_locks = 0;
|
||||
struct dm_hash_node *hn = NULL;
|
||||
char debug_arg[16];
|
||||
const char *clvmd = getenv("LVM_CLVMD_BINARY") ? : CLVMD_PATH;
|
||||
|
||||
DEBUGLOG("clvmd restart requested\n");
|
||||
|
||||
/* Count exclusively-open LVs */
|
||||
do {
|
||||
hn = get_next_excl_lock(hn, &lv_name);
|
||||
if (lv_name) {
|
||||
max_locks++;
|
||||
if (!*lv_name)
|
||||
break; /* FIXME: Is this error ? */
|
||||
}
|
||||
} while (hn);
|
||||
|
||||
/* clvmd + locks (-E uuid) + debug (-d X) + NULL */
|
||||
if (!(argv = malloc((max_locks * 2 + 6) * sizeof(*argv))))
|
||||
goto_out;
|
||||
|
||||
/*
|
||||
* Build the command-line
|
||||
*/
|
||||
argv[argc++] = "clvmd";
|
||||
|
||||
/* Propagate debug options */
|
||||
if (clvmd_get_debug()) {
|
||||
if (dm_snprintf(debug_arg, sizeof(debug_arg), "-d%u", clvmd_get_debug()) < 0)
|
||||
goto_out;
|
||||
argv[argc++] = debug_arg;
|
||||
}
|
||||
|
||||
/* Propagate foreground options */
|
||||
if (clvmd_get_foreground())
|
||||
argv[argc++] = "-f";
|
||||
|
||||
argv[argc++] = "-I";
|
||||
argv[argc++] = clops->name;
|
||||
|
||||
/* Now add the exclusively-open LVs */
|
||||
hn = NULL;
|
||||
do {
|
||||
hn = get_next_excl_lock(hn, &lv_name);
|
||||
if (lv_name) {
|
||||
if (!*lv_name)
|
||||
break; /* FIXME: Is this error ? */
|
||||
argv[argc++] = "-E";
|
||||
argv[argc++] = lv_name;
|
||||
DEBUGLOG("excl lock: %s\n", lv_name);
|
||||
}
|
||||
} while (hn);
|
||||
argv[argc] = NULL;
|
||||
|
||||
/* Exec new clvmd */
|
||||
DEBUGLOG("--- Restarting %s ---\n", clvmd);
|
||||
for (argc = 1; argv[argc]; argc++) DEBUGLOG("--- %d: %s\n", argc, argv[argc]);
|
||||
|
||||
/* NOTE: This will fail when downgrading! */
|
||||
execvp(clvmd, (char **)argv);
|
||||
out:
|
||||
/* We failed */
|
||||
DEBUGLOG("Restart of clvmd failed.\n");
|
||||
|
||||
free(argv);
|
||||
|
||||
return EIO;
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file must be included first by every clvmd source file.
|
||||
*/
|
||||
#ifndef _LVM_CLVMD_COMMON_H
|
||||
#define _LVM_CLVMD_COMMON_H
|
||||
|
||||
#define _REENTRANT
|
||||
|
||||
#include "tools/tool.h"
|
||||
|
||||
#include "lib/log/lvm-logging.h"
|
||||
|
||||
#endif
|
@ -1,119 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2011 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* Abstraction layer for clvmd cluster communications
|
||||
*/
|
||||
|
||||
#ifndef _CLVMD_COMMS_H
|
||||
#define _CLVMD_COMMS_H
|
||||
|
||||
struct local_client;
|
||||
|
||||
struct cluster_ops {
|
||||
const char *name;
|
||||
void (*cluster_init_completed) (void);
|
||||
|
||||
int (*cluster_send_message) (const void *buf, int msglen,
|
||||
const char *csid,
|
||||
const char *errtext);
|
||||
int (*name_from_csid) (const char *csid, char *name);
|
||||
int (*csid_from_name) (char *csid, const char *name);
|
||||
int (*get_num_nodes) (void);
|
||||
int (*cluster_fd_callback) (struct local_client *fd, char *buf, int len,
|
||||
const char *csid,
|
||||
struct local_client **new_client);
|
||||
int (*get_main_cluster_fd) (void); /* gets accept FD or cman cluster socket */
|
||||
int (*cluster_do_node_callback) (struct local_client *client,
|
||||
void (*callback) (struct local_client *,
|
||||
const char *csid,
|
||||
int node_up));
|
||||
int (*is_quorate) (void);
|
||||
|
||||
void (*get_our_csid) (char *csid);
|
||||
void (*add_up_node) (const char *csid);
|
||||
void (*reread_config) (void);
|
||||
void (*cluster_closedown) (void);
|
||||
|
||||
int (*get_cluster_name)(char *buf, int buflen);
|
||||
|
||||
int (*sync_lock) (const char *resource, int mode,
|
||||
int flags, int *lockid);
|
||||
int (*sync_unlock) (const char *resource, int lockid);
|
||||
|
||||
};
|
||||
|
||||
#ifdef USE_CMAN
|
||||
# include <netinet/in.h>
|
||||
# include "libcman.h"
|
||||
# define CMAN_MAX_CSID_LEN 4
|
||||
# ifndef MAX_CSID_LEN
|
||||
# define MAX_CSID_LEN CMAN_MAX_CSID_LEN
|
||||
# endif
|
||||
# undef MAX_CLUSTER_MEMBER_NAME_LEN
|
||||
# define MAX_CLUSTER_MEMBER_NAME_LEN CMAN_MAX_NODENAME_LEN
|
||||
# define CMAN_MAX_CLUSTER_MESSAGE 1500
|
||||
# define CLUSTER_PORT_CLVMD 11
|
||||
struct cluster_ops *init_cman_cluster(void);
|
||||
#endif
|
||||
|
||||
#ifdef USE_OPENAIS
|
||||
# include <openais/saAis.h>
|
||||
# include <corosync/totem/totem.h>
|
||||
# define OPENAIS_CSID_LEN (sizeof(int))
|
||||
# define OPENAIS_MAX_CLUSTER_MESSAGE MESSAGE_SIZE_MAX
|
||||
# define OPENAIS_MAX_CLUSTER_MEMBER_NAME_LEN SA_MAX_NAME_LENGTH
|
||||
# ifndef MAX_CLUSTER_MEMBER_NAME_LEN
|
||||
# define MAX_CLUSTER_MEMBER_NAME_LEN SA_MAX_NAME_LENGTH
|
||||
# endif
|
||||
# ifndef CMAN_MAX_CLUSTER_MESSAGE
|
||||
# define CMAN_MAX_CLUSTER_MESSAGE MESSAGE_SIZE_MAX
|
||||
# endif
|
||||
# ifndef MAX_CSID_LEN
|
||||
# define MAX_CSID_LEN sizeof(int)
|
||||
# endif
|
||||
struct cluster_ops *init_openais_cluster(void);
|
||||
#endif
|
||||
|
||||
#ifdef USE_COROSYNC
|
||||
# include <corosync/corotypes.h>
|
||||
# define COROSYNC_CSID_LEN (sizeof(int))
|
||||
# define COROSYNC_MAX_CLUSTER_MESSAGE 65535
|
||||
# define COROSYNC_MAX_CLUSTER_MEMBER_NAME_LEN CS_MAX_NAME_LENGTH
|
||||
# ifndef MAX_CLUSTER_MEMBER_NAME_LEN
|
||||
# define MAX_CLUSTER_MEMBER_NAME_LEN CS_MAX_NAME_LENGTH
|
||||
# endif
|
||||
# ifndef CMAN_MAX_CLUSTER_MESSAGE
|
||||
# define CMAN_MAX_CLUSTER_MESSAGE 65535
|
||||
# endif
|
||||
# ifndef MAX_CSID_LEN
|
||||
# define MAX_CSID_LEN sizeof(int)
|
||||
# endif
|
||||
struct cluster_ops *init_corosync_cluster(void);
|
||||
#endif
|
||||
|
||||
#ifdef USE_SINGLENODE
|
||||
# define SINGLENODE_CSID_LEN (sizeof(int))
|
||||
# ifndef MAX_CLUSTER_MEMBER_NAME_LEN
|
||||
# define MAX_CLUSTER_MEMBER_NAME_LEN 64
|
||||
# endif
|
||||
# define SINGLENODE_MAX_CLUSTER_MESSAGE 65535
|
||||
# ifndef MAX_CSID_LEN
|
||||
# define MAX_CSID_LEN sizeof(int)
|
||||
# endif
|
||||
struct cluster_ops *init_singlenode_cluster(void);
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,662 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2009-2012 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* This provides the interface between clvmd and corosync/DLM as the cluster
|
||||
* and lock manager.
|
||||
*/
|
||||
|
||||
#include "clvmd-common.h"
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "daemons/clvmd/clvm.h"
|
||||
#include "clvmd-comms.h"
|
||||
#include "clvmd.h"
|
||||
#include "lvm-functions.h"
|
||||
|
||||
#include "lib/locking/locking.h"
|
||||
|
||||
#include <corosync/cpg.h>
|
||||
#include <corosync/quorum.h>
|
||||
|
||||
#ifdef HAVE_COROSYNC_CONFDB_H
|
||||
# include <corosync/confdb.h>
|
||||
#elif defined HAVE_COROSYNC_CMAP_H
|
||||
# include <corosync/cmap.h>
|
||||
#else
|
||||
# error "Either HAVE_COROSYNC_CONFDB_H or HAVE_COROSYNC_CMAP_H must be defined."
|
||||
#endif
|
||||
|
||||
#include <libdlm.h>
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
/* Timeout value for several corosync calls */
|
||||
#define LOCKSPACE_NAME "clvmd"
|
||||
|
||||
static void corosync_cpg_deliver_callback (cpg_handle_t handle,
|
||||
const struct cpg_name *groupName,
|
||||
uint32_t nodeid,
|
||||
uint32_t pid,
|
||||
void *msg,
|
||||
size_t msg_len);
|
||||
static void corosync_cpg_confchg_callback(cpg_handle_t handle,
|
||||
const struct cpg_name *groupName,
|
||||
const struct cpg_address *member_list, size_t member_list_entries,
|
||||
const struct cpg_address *left_list, size_t left_list_entries,
|
||||
const struct cpg_address *joined_list, size_t joined_list_entries);
|
||||
static void _cluster_closedown(void);
|
||||
|
||||
/* Hash list of nodes in the cluster */
|
||||
static struct dm_hash_table *node_hash;
|
||||
|
||||
/* Number of active nodes */
|
||||
static int num_nodes;
|
||||
static unsigned int our_nodeid;
|
||||
|
||||
static struct local_client *cluster_client;
|
||||
|
||||
/* Corosync handles */
|
||||
static cpg_handle_t cpg_handle;
|
||||
static quorum_handle_t quorum_handle;
|
||||
|
||||
/* DLM Handle */
|
||||
static dlm_lshandle_t *lockspace;
|
||||
|
||||
static struct cpg_name cpg_group_name;
|
||||
|
||||
/* Corosync callback structs */
|
||||
cpg_callbacks_t corosync_cpg_callbacks = {
|
||||
.cpg_deliver_fn = corosync_cpg_deliver_callback,
|
||||
.cpg_confchg_fn = corosync_cpg_confchg_callback,
|
||||
};
|
||||
|
||||
quorum_callbacks_t quorum_callbacks = {
|
||||
.quorum_notify_fn = NULL,
|
||||
};
|
||||
|
||||
struct node_info
|
||||
{
|
||||
enum {NODE_DOWN, NODE_CLVMD} state;
|
||||
int nodeid;
|
||||
};
|
||||
|
||||
|
||||
/* Set errno to something approximating the right value and return 0 or -1 */
|
||||
static int cs_to_errno(cs_error_t err)
|
||||
{
|
||||
switch(err)
|
||||
{
|
||||
case CS_OK:
|
||||
return 0;
|
||||
case CS_ERR_LIBRARY:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case CS_ERR_VERSION:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case CS_ERR_INIT:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case CS_ERR_TIMEOUT:
|
||||
errno = ETIME;
|
||||
break;
|
||||
case CS_ERR_TRY_AGAIN:
|
||||
errno = EAGAIN;
|
||||
break;
|
||||
case CS_ERR_INVALID_PARAM:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case CS_ERR_NO_MEMORY:
|
||||
errno = ENOMEM;
|
||||
break;
|
||||
case CS_ERR_BAD_HANDLE:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case CS_ERR_BUSY:
|
||||
errno = EBUSY;
|
||||
break;
|
||||
case CS_ERR_ACCESS:
|
||||
errno = EPERM;
|
||||
break;
|
||||
case CS_ERR_NOT_EXIST:
|
||||
errno = ENOENT;
|
||||
break;
|
||||
case CS_ERR_NAME_TOO_LONG:
|
||||
errno = ENAMETOOLONG;
|
||||
break;
|
||||
case CS_ERR_EXIST:
|
||||
errno = EEXIST;
|
||||
break;
|
||||
case CS_ERR_NO_SPACE:
|
||||
errno = ENOSPC;
|
||||
break;
|
||||
case CS_ERR_INTERRUPT:
|
||||
errno = EINTR;
|
||||
break;
|
||||
case CS_ERR_NAME_NOT_FOUND:
|
||||
errno = ENOENT;
|
||||
break;
|
||||
case CS_ERR_NO_RESOURCES:
|
||||
errno = ENOMEM;
|
||||
break;
|
||||
case CS_ERR_NOT_SUPPORTED:
|
||||
errno = EOPNOTSUPP;
|
||||
break;
|
||||
case CS_ERR_BAD_OPERATION:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case CS_ERR_FAILED_OPERATION:
|
||||
errno = EIO;
|
||||
break;
|
||||
case CS_ERR_MESSAGE_ERROR:
|
||||
errno = EIO;
|
||||
break;
|
||||
case CS_ERR_QUEUE_FULL:
|
||||
errno = EXFULL;
|
||||
break;
|
||||
case CS_ERR_QUEUE_NOT_AVAILABLE:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case CS_ERR_BAD_FLAGS:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case CS_ERR_TOO_BIG:
|
||||
errno = E2BIG;
|
||||
break;
|
||||
case CS_ERR_NO_SECTIONS:
|
||||
errno = ENOMEM;
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static char *print_corosync_csid(const char *csid)
|
||||
{
|
||||
static char buf[128];
|
||||
int id;
|
||||
|
||||
memcpy(&id, csid, sizeof(int));
|
||||
sprintf(buf, "%d", id);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void corosync_cpg_deliver_callback (cpg_handle_t handle,
|
||||
const struct cpg_name *groupName,
|
||||
uint32_t nodeid,
|
||||
uint32_t pid,
|
||||
void *msg,
|
||||
size_t msg_len)
|
||||
{
|
||||
int target_nodeid;
|
||||
|
||||
memcpy(&target_nodeid, msg, COROSYNC_CSID_LEN);
|
||||
|
||||
DEBUGLOG("%u got message from nodeid %d for %d. len %zd\n",
|
||||
our_nodeid, nodeid, target_nodeid, msg_len-4);
|
||||
|
||||
if (nodeid != our_nodeid)
|
||||
if (target_nodeid == our_nodeid || target_nodeid == 0)
|
||||
process_message(cluster_client, (char *)msg+COROSYNC_CSID_LEN,
|
||||
msg_len-COROSYNC_CSID_LEN, (char*)&nodeid);
|
||||
}
|
||||
|
||||
static void corosync_cpg_confchg_callback(cpg_handle_t handle,
|
||||
const struct cpg_name *groupName,
|
||||
const struct cpg_address *member_list, size_t member_list_entries,
|
||||
const struct cpg_address *left_list, size_t left_list_entries,
|
||||
const struct cpg_address *joined_list, size_t joined_list_entries)
|
||||
{
|
||||
int i;
|
||||
struct node_info *ninfo;
|
||||
|
||||
DEBUGLOG("confchg callback. %zd joined, %zd left, %zd members\n",
|
||||
joined_list_entries, left_list_entries, member_list_entries);
|
||||
|
||||
for (i=0; i<joined_list_entries; i++) {
|
||||
ninfo = dm_hash_lookup_binary(node_hash,
|
||||
(char *)&joined_list[i].nodeid,
|
||||
COROSYNC_CSID_LEN);
|
||||
if (!ninfo) {
|
||||
ninfo = malloc(sizeof(struct node_info));
|
||||
if (!ninfo) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
ninfo->nodeid = joined_list[i].nodeid;
|
||||
dm_hash_insert_binary(node_hash,
|
||||
(char *)&ninfo->nodeid,
|
||||
COROSYNC_CSID_LEN, ninfo);
|
||||
}
|
||||
}
|
||||
ninfo->state = NODE_CLVMD;
|
||||
}
|
||||
|
||||
for (i=0; i<left_list_entries; i++) {
|
||||
ninfo = dm_hash_lookup_binary(node_hash,
|
||||
(char *)&left_list[i].nodeid,
|
||||
COROSYNC_CSID_LEN);
|
||||
if (ninfo)
|
||||
ninfo->state = NODE_DOWN;
|
||||
}
|
||||
|
||||
num_nodes = member_list_entries;
|
||||
}
|
||||
|
||||
static int _init_cluster(void)
|
||||
{
|
||||
cs_error_t err;
|
||||
|
||||
#ifdef QUORUM_SET /* corosync/quorum.h */
|
||||
uint32_t quorum_type;
|
||||
#endif
|
||||
|
||||
node_hash = dm_hash_create(100);
|
||||
|
||||
err = cpg_initialize(&cpg_handle,
|
||||
&corosync_cpg_callbacks);
|
||||
if (err != CS_OK) {
|
||||
syslog(LOG_ERR, "Cannot initialise Corosync CPG service: %d",
|
||||
err);
|
||||
DEBUGLOG("Cannot initialise Corosync CPG service: %d", err);
|
||||
return cs_to_errno(err);
|
||||
}
|
||||
|
||||
#ifdef QUORUM_SET
|
||||
err = quorum_initialize(&quorum_handle,
|
||||
&quorum_callbacks,
|
||||
&quorum_type);
|
||||
|
||||
if (quorum_type != QUORUM_SET) {
|
||||
syslog(LOG_ERR, "Corosync quorum service is not configured");
|
||||
DEBUGLOG("Corosync quorum service is not configured");
|
||||
return EINVAL;
|
||||
}
|
||||
#else
|
||||
err = quorum_initialize(&quorum_handle,
|
||||
&quorum_callbacks);
|
||||
#endif
|
||||
|
||||
if (err != CS_OK) {
|
||||
syslog(LOG_ERR, "Cannot initialise Corosync quorum service: %d",
|
||||
err);
|
||||
DEBUGLOG("Cannot initialise Corosync quorum service: %d", err);
|
||||
return cs_to_errno(err);
|
||||
}
|
||||
|
||||
/* Create a lockspace for LV & VG locks to live in */
|
||||
lockspace = dlm_open_lockspace(LOCKSPACE_NAME);
|
||||
if (!lockspace) {
|
||||
lockspace = dlm_create_lockspace(LOCKSPACE_NAME, 0600);
|
||||
if (!lockspace) {
|
||||
syslog(LOG_ERR, "Unable to create DLM lockspace for CLVM: %m");
|
||||
return -1;
|
||||
}
|
||||
DEBUGLOG("Created DLM lockspace for CLVMD.\n");
|
||||
} else
|
||||
DEBUGLOG("Opened existing DLM lockspace for CLVMD.\n");
|
||||
|
||||
dlm_ls_pthread_init(lockspace);
|
||||
DEBUGLOG("DLM initialisation complete\n");
|
||||
|
||||
/* Connect to the clvmd group */
|
||||
strcpy((char *)cpg_group_name.value, "clvmd");
|
||||
cpg_group_name.length = strlen((char *)cpg_group_name.value);
|
||||
err = cpg_join(cpg_handle, &cpg_group_name);
|
||||
if (err != CS_OK) {
|
||||
cpg_finalize(cpg_handle);
|
||||
quorum_finalize(quorum_handle);
|
||||
dlm_release_lockspace(LOCKSPACE_NAME, lockspace, 1);
|
||||
syslog(LOG_ERR, "Cannot join clvmd process group");
|
||||
DEBUGLOG("Cannot join clvmd process group: %d\n", err);
|
||||
return cs_to_errno(err);
|
||||
}
|
||||
|
||||
err = cpg_local_get(cpg_handle,
|
||||
&our_nodeid);
|
||||
if (err != CS_OK) {
|
||||
cpg_finalize(cpg_handle);
|
||||
quorum_finalize(quorum_handle);
|
||||
dlm_release_lockspace(LOCKSPACE_NAME, lockspace, 1);
|
||||
syslog(LOG_ERR, "Cannot get local node id\n");
|
||||
return cs_to_errno(err);
|
||||
}
|
||||
DEBUGLOG("Our local node id is %d\n", our_nodeid);
|
||||
|
||||
DEBUGLOG("Connected to Corosync\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _cluster_closedown(void)
|
||||
{
|
||||
dlm_release_lockspace(LOCKSPACE_NAME, lockspace, 1);
|
||||
cpg_finalize(cpg_handle);
|
||||
quorum_finalize(quorum_handle);
|
||||
}
|
||||
|
||||
static void _get_our_csid(char *csid)
|
||||
{
|
||||
memcpy(csid, &our_nodeid, sizeof(int));
|
||||
}
|
||||
|
||||
/* Corosync doesn't really have nmode names so we
|
||||
just use the node ID in hex instead */
|
||||
static int _csid_from_name(char *csid, const char *name)
|
||||
{
|
||||
int nodeid;
|
||||
struct node_info *ninfo;
|
||||
|
||||
if (sscanf(name, "%x", &nodeid) == 1) {
|
||||
ninfo = dm_hash_lookup_binary(node_hash, csid, COROSYNC_CSID_LEN);
|
||||
if (ninfo)
|
||||
return nodeid;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _name_from_csid(const char *csid, char *name)
|
||||
{
|
||||
struct node_info *ninfo;
|
||||
|
||||
ninfo = dm_hash_lookup_binary(node_hash, csid, COROSYNC_CSID_LEN);
|
||||
if (!ninfo)
|
||||
{
|
||||
sprintf(name, "UNKNOWN %s", print_corosync_csid(csid));
|
||||
return -1;
|
||||
}
|
||||
|
||||
sprintf(name, "%x", ninfo->nodeid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _get_num_nodes(void)
|
||||
{
|
||||
DEBUGLOG("num_nodes = %d\n", num_nodes);
|
||||
return num_nodes;
|
||||
}
|
||||
|
||||
/* Node is now known to be running a clvmd */
|
||||
static void _add_up_node(const char *csid)
|
||||
{
|
||||
struct node_info *ninfo;
|
||||
|
||||
ninfo = dm_hash_lookup_binary(node_hash, csid, COROSYNC_CSID_LEN);
|
||||
if (!ninfo) {
|
||||
DEBUGLOG("corosync_add_up_node no node_hash entry for csid %s\n",
|
||||
print_corosync_csid(csid));
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUGLOG("corosync_add_up_node %d\n", ninfo->nodeid);
|
||||
|
||||
ninfo->state = NODE_CLVMD;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Call a callback for each node, so the caller knows whether it's up or down */
|
||||
static int _cluster_do_node_callback(struct local_client *master_client,
|
||||
void (*callback)(struct local_client *,
|
||||
const char *csid, int node_up))
|
||||
{
|
||||
struct dm_hash_node *hn;
|
||||
struct node_info *ninfo;
|
||||
|
||||
dm_hash_iterate(hn, node_hash)
|
||||
{
|
||||
char csid[COROSYNC_CSID_LEN];
|
||||
|
||||
ninfo = dm_hash_get_data(node_hash, hn);
|
||||
memcpy(csid, dm_hash_get_key(node_hash, hn), COROSYNC_CSID_LEN);
|
||||
|
||||
DEBUGLOG("down_callback. node %d, state = %d\n", ninfo->nodeid,
|
||||
ninfo->state);
|
||||
|
||||
if (ninfo->state == NODE_CLVMD)
|
||||
callback(master_client, csid, 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Real locking */
|
||||
static int _lock_resource(const char *resource, int mode, int flags, int *lockid)
|
||||
{
|
||||
struct dlm_lksb lksb;
|
||||
int err;
|
||||
|
||||
DEBUGLOG("lock_resource '%s', flags=%d, mode=%d\n", resource, flags, mode);
|
||||
|
||||
if (flags & LKF_CONVERT)
|
||||
lksb.sb_lkid = *lockid;
|
||||
|
||||
err = dlm_ls_lock_wait(lockspace,
|
||||
mode,
|
||||
&lksb,
|
||||
flags,
|
||||
resource,
|
||||
strlen(resource),
|
||||
0,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
if (err != 0)
|
||||
{
|
||||
DEBUGLOG("dlm_ls_lock returned %d\n", errno);
|
||||
return err;
|
||||
}
|
||||
if (lksb.sb_status != 0)
|
||||
{
|
||||
DEBUGLOG("dlm_ls_lock returns lksb.sb_status %d\n", lksb.sb_status);
|
||||
errno = lksb.sb_status;
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUGLOG("lock_resource returning %d, lock_id=%x\n", err, lksb.sb_lkid);
|
||||
|
||||
*lockid = lksb.sb_lkid;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int _unlock_resource(const char *resource, int lockid)
|
||||
{
|
||||
struct dlm_lksb lksb;
|
||||
int err;
|
||||
|
||||
DEBUGLOG("unlock_resource: %s lockid: %x\n", resource, lockid);
|
||||
lksb.sb_lkid = lockid;
|
||||
|
||||
err = dlm_ls_unlock_wait(lockspace,
|
||||
lockid,
|
||||
0,
|
||||
&lksb);
|
||||
if (err != 0)
|
||||
{
|
||||
DEBUGLOG("Unlock returned %d\n", err);
|
||||
return err;
|
||||
}
|
||||
if (lksb.sb_status != EUNLOCK)
|
||||
{
|
||||
DEBUGLOG("dlm_ls_unlock_wait returns lksb.sb_status: %d\n", lksb.sb_status);
|
||||
errno = lksb.sb_status;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _is_quorate(void)
|
||||
{
|
||||
int quorate;
|
||||
if (quorum_getquorate(quorum_handle, &quorate) == CS_OK)
|
||||
return quorate;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _get_main_cluster_fd(void)
|
||||
{
|
||||
int select_fd;
|
||||
|
||||
cpg_fd_get(cpg_handle, &select_fd);
|
||||
return select_fd;
|
||||
}
|
||||
|
||||
static int _cluster_fd_callback(struct local_client *fd, char *buf, int len,
|
||||
const char *csid,
|
||||
struct local_client **new_client)
|
||||
{
|
||||
cluster_client = fd;
|
||||
*new_client = NULL;
|
||||
cpg_dispatch(cpg_handle, CS_DISPATCH_ONE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _cluster_send_message(const void *buf, int msglen, const char *csid,
|
||||
const char *errtext)
|
||||
{
|
||||
static pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
struct iovec iov[2];
|
||||
cs_error_t err;
|
||||
int target_node;
|
||||
|
||||
if (csid)
|
||||
memcpy(&target_node, csid, COROSYNC_CSID_LEN);
|
||||
else
|
||||
target_node = 0;
|
||||
|
||||
iov[0].iov_base = &target_node;
|
||||
iov[0].iov_len = sizeof(int);
|
||||
iov[1].iov_base = (char *)buf;
|
||||
iov[1].iov_len = msglen;
|
||||
|
||||
pthread_mutex_lock(&_mutex);
|
||||
err = cpg_mcast_joined(cpg_handle, CPG_TYPE_AGREED, iov, 2);
|
||||
pthread_mutex_unlock(&_mutex);
|
||||
|
||||
return cs_to_errno(err);
|
||||
}
|
||||
|
||||
#ifdef HAVE_COROSYNC_CONFDB_H
|
||||
/*
|
||||
* We are not necessarily connected to a Red Hat Cluster system,
|
||||
* but if we are, this returns the cluster name from cluster.conf.
|
||||
* I've used confdb rather than ccs to reduce the inter-package
|
||||
* dependancies as well as to allow people to set a cluster name
|
||||
* for themselves even if they are not running on RH cluster.
|
||||
*/
|
||||
static int _get_cluster_name(char *buf, int buflen)
|
||||
{
|
||||
confdb_handle_t handle;
|
||||
int result;
|
||||
size_t namelen = buflen;
|
||||
hdb_handle_t cluster_handle;
|
||||
confdb_callbacks_t callbacks = {
|
||||
.confdb_key_change_notify_fn = NULL,
|
||||
.confdb_object_create_change_notify_fn = NULL,
|
||||
.confdb_object_delete_change_notify_fn = NULL
|
||||
};
|
||||
|
||||
/* This is a default in case everything else fails */
|
||||
strncpy(buf, "Corosync", buflen);
|
||||
|
||||
/* Look for a cluster name in confdb */
|
||||
result = confdb_initialize (&handle, &callbacks);
|
||||
if (result != CS_OK)
|
||||
return 0;
|
||||
|
||||
result = confdb_object_find_start(handle, OBJECT_PARENT_HANDLE);
|
||||
if (result != CS_OK)
|
||||
goto out;
|
||||
|
||||
result = confdb_object_find(handle, OBJECT_PARENT_HANDLE, (void *)"cluster", strlen("cluster"), &cluster_handle);
|
||||
if (result != CS_OK)
|
||||
goto out;
|
||||
|
||||
result = confdb_key_get(handle, cluster_handle, (void *)"name", strlen("name"), buf, &namelen);
|
||||
if (result != CS_OK)
|
||||
goto out;
|
||||
|
||||
buf[namelen] = '\0';
|
||||
|
||||
out:
|
||||
confdb_finalize(handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined HAVE_COROSYNC_CMAP_H
|
||||
|
||||
static int _get_cluster_name(char *buf, int buflen)
|
||||
{
|
||||
cmap_handle_t cmap_handle = 0;
|
||||
int result;
|
||||
char *name = NULL;
|
||||
|
||||
/* This is a default in case everything else fails */
|
||||
strncpy(buf, "Corosync", buflen);
|
||||
|
||||
/* Look for a cluster name in cmap */
|
||||
result = cmap_initialize(&cmap_handle);
|
||||
if (result != CS_OK)
|
||||
return 0;
|
||||
|
||||
result = cmap_get_string(cmap_handle, "totem.cluster_name", &name);
|
||||
if (result != CS_OK)
|
||||
goto out;
|
||||
|
||||
memset(buf, 0, buflen);
|
||||
strncpy(buf, name, buflen - 1);
|
||||
|
||||
out:
|
||||
if (name)
|
||||
free(name);
|
||||
cmap_finalize(cmap_handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static struct cluster_ops _cluster_corosync_ops = {
|
||||
.name = "corosync",
|
||||
.cluster_init_completed = NULL,
|
||||
.cluster_send_message = _cluster_send_message,
|
||||
.name_from_csid = _name_from_csid,
|
||||
.csid_from_name = _csid_from_name,
|
||||
.get_num_nodes = _get_num_nodes,
|
||||
.cluster_fd_callback = _cluster_fd_callback,
|
||||
.get_main_cluster_fd = _get_main_cluster_fd,
|
||||
.cluster_do_node_callback = _cluster_do_node_callback,
|
||||
.is_quorate = _is_quorate,
|
||||
.get_our_csid = _get_our_csid,
|
||||
.add_up_node = _add_up_node,
|
||||
.reread_config = NULL,
|
||||
.cluster_closedown = _cluster_closedown,
|
||||
.get_cluster_name = _get_cluster_name,
|
||||
.sync_lock = _lock_resource,
|
||||
.sync_unlock = _unlock_resource,
|
||||
};
|
||||
|
||||
struct cluster_ops *init_corosync_cluster(void)
|
||||
{
|
||||
if (!_init_cluster())
|
||||
return &_cluster_corosync_ops;
|
||||
else
|
||||
return NULL;
|
||||
}
|
@ -1,687 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2009 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* This provides the interface between clvmd and OpenAIS as the cluster
|
||||
* and lock manager.
|
||||
*/
|
||||
|
||||
#include "clvmd-common.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <fcntl.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#include <openais/saAis.h>
|
||||
#include <openais/saLck.h>
|
||||
|
||||
#include <corosync/corotypes.h>
|
||||
#include <corosync/cpg.h>
|
||||
|
||||
#include "lib/locking/locking.h"
|
||||
#include "daemons/clvmd/clvm.h"
|
||||
#include "clvmd-comms.h"
|
||||
#include "lvm-functions.h"
|
||||
#include "clvmd.h"
|
||||
|
||||
/* Timeout value for several openais calls */
|
||||
#define TIMEOUT 10
|
||||
|
||||
static void openais_cpg_deliver_callback (cpg_handle_t handle,
|
||||
const struct cpg_name *groupName,
|
||||
uint32_t nodeid,
|
||||
uint32_t pid,
|
||||
void *msg,
|
||||
size_t msg_len);
|
||||
static void openais_cpg_confchg_callback(cpg_handle_t handle,
|
||||
const struct cpg_name *groupName,
|
||||
const struct cpg_address *member_list, size_t member_list_entries,
|
||||
const struct cpg_address *left_list, size_t left_list_entries,
|
||||
const struct cpg_address *joined_list, size_t joined_list_entries);
|
||||
|
||||
static void _cluster_closedown(void);
|
||||
|
||||
/* Hash list of nodes in the cluster */
|
||||
static struct dm_hash_table *node_hash;
|
||||
|
||||
/* For associating lock IDs & resource handles */
|
||||
static struct dm_hash_table *lock_hash;
|
||||
|
||||
/* Number of active nodes */
|
||||
static int num_nodes;
|
||||
static unsigned int our_nodeid;
|
||||
|
||||
static struct local_client *cluster_client;
|
||||
|
||||
/* OpenAIS handles */
|
||||
static cpg_handle_t cpg_handle;
|
||||
static SaLckHandleT lck_handle;
|
||||
|
||||
static struct cpg_name cpg_group_name;
|
||||
|
||||
/* Openais callback structs */
|
||||
cpg_callbacks_t openais_cpg_callbacks = {
|
||||
.cpg_deliver_fn = openais_cpg_deliver_callback,
|
||||
.cpg_confchg_fn = openais_cpg_confchg_callback,
|
||||
};
|
||||
|
||||
struct node_info
|
||||
{
|
||||
enum {NODE_UNKNOWN, NODE_DOWN, NODE_UP, NODE_CLVMD} state;
|
||||
int nodeid;
|
||||
};
|
||||
|
||||
struct lock_info
|
||||
{
|
||||
SaLckResourceHandleT res_handle;
|
||||
SaLckLockIdT lock_id;
|
||||
SaNameT lock_name;
|
||||
};
|
||||
|
||||
/* Set errno to something approximating the right value and return 0 or -1 */
|
||||
static int ais_to_errno(SaAisErrorT err)
|
||||
{
|
||||
switch(err)
|
||||
{
|
||||
case SA_AIS_OK:
|
||||
return 0;
|
||||
case SA_AIS_ERR_LIBRARY:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case SA_AIS_ERR_VERSION:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case SA_AIS_ERR_INIT:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case SA_AIS_ERR_TIMEOUT:
|
||||
errno = ETIME;
|
||||
break;
|
||||
case SA_AIS_ERR_TRY_AGAIN:
|
||||
errno = EAGAIN;
|
||||
break;
|
||||
case SA_AIS_ERR_INVALID_PARAM:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case SA_AIS_ERR_NO_MEMORY:
|
||||
errno = ENOMEM;
|
||||
break;
|
||||
case SA_AIS_ERR_BAD_HANDLE:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case SA_AIS_ERR_BUSY:
|
||||
errno = EBUSY;
|
||||
break;
|
||||
case SA_AIS_ERR_ACCESS:
|
||||
errno = EPERM;
|
||||
break;
|
||||
case SA_AIS_ERR_NOT_EXIST:
|
||||
errno = ENOENT;
|
||||
break;
|
||||
case SA_AIS_ERR_NAME_TOO_LONG:
|
||||
errno = ENAMETOOLONG;
|
||||
break;
|
||||
case SA_AIS_ERR_EXIST:
|
||||
errno = EEXIST;
|
||||
break;
|
||||
case SA_AIS_ERR_NO_SPACE:
|
||||
errno = ENOSPC;
|
||||
break;
|
||||
case SA_AIS_ERR_INTERRUPT:
|
||||
errno = EINTR;
|
||||
break;
|
||||
case SA_AIS_ERR_NAME_NOT_FOUND:
|
||||
errno = ENOENT;
|
||||
break;
|
||||
case SA_AIS_ERR_NO_RESOURCES:
|
||||
errno = ENOMEM;
|
||||
break;
|
||||
case SA_AIS_ERR_NOT_SUPPORTED:
|
||||
errno = EOPNOTSUPP;
|
||||
break;
|
||||
case SA_AIS_ERR_BAD_OPERATION:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case SA_AIS_ERR_FAILED_OPERATION:
|
||||
errno = EIO;
|
||||
break;
|
||||
case SA_AIS_ERR_MESSAGE_ERROR:
|
||||
errno = EIO;
|
||||
break;
|
||||
case SA_AIS_ERR_QUEUE_FULL:
|
||||
errno = EXFULL;
|
||||
break;
|
||||
case SA_AIS_ERR_QUEUE_NOT_AVAILABLE:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case SA_AIS_ERR_BAD_FLAGS:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
case SA_AIS_ERR_TOO_BIG:
|
||||
errno = E2BIG;
|
||||
break;
|
||||
case SA_AIS_ERR_NO_SECTIONS:
|
||||
errno = ENOMEM;
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static char *print_openais_csid(const char *csid)
|
||||
{
|
||||
static char buf[128];
|
||||
int id;
|
||||
|
||||
memcpy(&id, csid, sizeof(int));
|
||||
sprintf(buf, "%d", id);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int add_internal_client(int fd, fd_callback_t callback)
|
||||
{
|
||||
struct local_client *client;
|
||||
|
||||
DEBUGLOG("Add_internal_client, fd = %d\n", fd);
|
||||
|
||||
if (!(client = dm_zalloc(sizeof(*client)))) {
|
||||
DEBUGLOG("malloc failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
client->fd = fd;
|
||||
client->type = CLUSTER_INTERNAL;
|
||||
client->callback = callback;
|
||||
add_client(client);
|
||||
|
||||
/* Set Close-on-exec */
|
||||
fcntl(fd, F_SETFD, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void openais_cpg_deliver_callback (cpg_handle_t handle,
|
||||
const struct cpg_name *groupName,
|
||||
uint32_t nodeid,
|
||||
uint32_t pid,
|
||||
void *msg,
|
||||
size_t msg_len)
|
||||
{
|
||||
int target_nodeid;
|
||||
|
||||
memcpy(&target_nodeid, msg, OPENAIS_CSID_LEN);
|
||||
|
||||
DEBUGLOG("%u got message from nodeid %d for %d. len %" PRIsize_t "\n",
|
||||
our_nodeid, nodeid, target_nodeid, msg_len-4);
|
||||
|
||||
if (nodeid != our_nodeid)
|
||||
if (target_nodeid == our_nodeid || target_nodeid == 0)
|
||||
process_message(cluster_client, (char *)msg+OPENAIS_CSID_LEN,
|
||||
msg_len-OPENAIS_CSID_LEN, (char*)&nodeid);
|
||||
}
|
||||
|
||||
static void openais_cpg_confchg_callback(cpg_handle_t handle,
|
||||
const struct cpg_name *groupName,
|
||||
const struct cpg_address *member_list, size_t member_list_entries,
|
||||
const struct cpg_address *left_list, size_t left_list_entries,
|
||||
const struct cpg_address *joined_list, size_t joined_list_entries)
|
||||
{
|
||||
int i;
|
||||
struct node_info *ninfo;
|
||||
|
||||
DEBUGLOG("confchg callback. %" PRIsize_t " joined, "
|
||||
FMTsize_t " left, %" PRIsize_t " members\n",
|
||||
joined_list_entries, left_list_entries, member_list_entries);
|
||||
|
||||
for (i=0; i<joined_list_entries; i++) {
|
||||
ninfo = dm_hash_lookup_binary(node_hash,
|
||||
(char *)&joined_list[i].nodeid,
|
||||
OPENAIS_CSID_LEN);
|
||||
if (!ninfo) {
|
||||
ninfo = malloc(sizeof(struct node_info));
|
||||
if (!ninfo) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
ninfo->nodeid = joined_list[i].nodeid;
|
||||
dm_hash_insert_binary(node_hash,
|
||||
(char *)&ninfo->nodeid,
|
||||
OPENAIS_CSID_LEN, ninfo);
|
||||
}
|
||||
}
|
||||
ninfo->state = NODE_CLVMD;
|
||||
}
|
||||
|
||||
for (i=0; i<left_list_entries; i++) {
|
||||
ninfo = dm_hash_lookup_binary(node_hash,
|
||||
(char *)&left_list[i].nodeid,
|
||||
OPENAIS_CSID_LEN);
|
||||
if (ninfo)
|
||||
ninfo->state = NODE_DOWN;
|
||||
}
|
||||
|
||||
for (i=0; i<member_list_entries; i++) {
|
||||
if (member_list[i].nodeid == 0) continue;
|
||||
ninfo = dm_hash_lookup_binary(node_hash,
|
||||
(char *)&member_list[i].nodeid,
|
||||
OPENAIS_CSID_LEN);
|
||||
if (!ninfo) {
|
||||
ninfo = malloc(sizeof(struct node_info));
|
||||
if (!ninfo) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
ninfo->nodeid = member_list[i].nodeid;
|
||||
dm_hash_insert_binary(node_hash,
|
||||
(char *)&ninfo->nodeid,
|
||||
OPENAIS_CSID_LEN, ninfo);
|
||||
}
|
||||
}
|
||||
ninfo->state = NODE_CLVMD;
|
||||
}
|
||||
|
||||
num_nodes = member_list_entries;
|
||||
}
|
||||
|
||||
static int lck_dispatch(struct local_client *client, char *buf, int len,
|
||||
const char *csid, struct local_client **new_client)
|
||||
{
|
||||
*new_client = NULL;
|
||||
saLckDispatch(lck_handle, SA_DISPATCH_ONE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _init_cluster(void)
|
||||
{
|
||||
SaAisErrorT err;
|
||||
SaVersionT ver = { 'B', 1, 1 };
|
||||
int select_fd;
|
||||
|
||||
node_hash = dm_hash_create(100);
|
||||
lock_hash = dm_hash_create(10);
|
||||
|
||||
err = cpg_initialize(&cpg_handle,
|
||||
&openais_cpg_callbacks);
|
||||
if (err != SA_AIS_OK) {
|
||||
syslog(LOG_ERR, "Cannot initialise OpenAIS CPG service: %d",
|
||||
err);
|
||||
DEBUGLOG("Cannot initialise OpenAIS CPG service: %d", err);
|
||||
return ais_to_errno(err);
|
||||
}
|
||||
|
||||
err = saLckInitialize(&lck_handle,
|
||||
NULL,
|
||||
&ver);
|
||||
if (err != SA_AIS_OK) {
|
||||
cpg_initialize(&cpg_handle, &openais_cpg_callbacks);
|
||||
syslog(LOG_ERR, "Cannot initialise OpenAIS lock service: %d",
|
||||
err);
|
||||
DEBUGLOG("Cannot initialise OpenAIS lock service: %d\n\n", err);
|
||||
return ais_to_errno(err);
|
||||
}
|
||||
|
||||
/* Connect to the clvmd group */
|
||||
strcpy((char *)cpg_group_name.value, "clvmd");
|
||||
cpg_group_name.length = strlen((char *)cpg_group_name.value);
|
||||
err = cpg_join(cpg_handle, &cpg_group_name);
|
||||
if (err != SA_AIS_OK) {
|
||||
cpg_finalize(cpg_handle);
|
||||
saLckFinalize(lck_handle);
|
||||
syslog(LOG_ERR, "Cannot join clvmd process group");
|
||||
DEBUGLOG("Cannot join clvmd process group: %d\n", err);
|
||||
return ais_to_errno(err);
|
||||
}
|
||||
|
||||
err = cpg_local_get(cpg_handle,
|
||||
&our_nodeid);
|
||||
if (err != SA_AIS_OK) {
|
||||
cpg_finalize(cpg_handle);
|
||||
saLckFinalize(lck_handle);
|
||||
syslog(LOG_ERR, "Cannot get local node id\n");
|
||||
return ais_to_errno(err);
|
||||
}
|
||||
DEBUGLOG("Our local node id is %d\n", our_nodeid);
|
||||
|
||||
saLckSelectionObjectGet(lck_handle, (SaSelectionObjectT *)&select_fd);
|
||||
add_internal_client(select_fd, lck_dispatch);
|
||||
|
||||
DEBUGLOG("Connected to OpenAIS\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _cluster_closedown(void)
|
||||
{
|
||||
saLckFinalize(lck_handle);
|
||||
cpg_finalize(cpg_handle);
|
||||
}
|
||||
|
||||
static void _get_our_csid(char *csid)
|
||||
{
|
||||
memcpy(csid, &our_nodeid, sizeof(int));
|
||||
}
|
||||
|
||||
/* OpenAIS doesn't really have nmode names so we
|
||||
just use the node ID in hex instead */
|
||||
static int _csid_from_name(char *csid, const char *name)
|
||||
{
|
||||
int nodeid;
|
||||
struct node_info *ninfo;
|
||||
|
||||
if (sscanf(name, "%x", &nodeid) == 1) {
|
||||
ninfo = dm_hash_lookup_binary(node_hash, csid, OPENAIS_CSID_LEN);
|
||||
if (ninfo)
|
||||
return nodeid;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _name_from_csid(const char *csid, char *name)
|
||||
{
|
||||
struct node_info *ninfo;
|
||||
|
||||
ninfo = dm_hash_lookup_binary(node_hash, csid, OPENAIS_CSID_LEN);
|
||||
if (!ninfo)
|
||||
{
|
||||
sprintf(name, "UNKNOWN %s", print_openais_csid(csid));
|
||||
return -1;
|
||||
}
|
||||
|
||||
sprintf(name, "%x", ninfo->nodeid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _get_num_nodes()
|
||||
{
|
||||
DEBUGLOG("num_nodes = %d\n", num_nodes);
|
||||
return num_nodes;
|
||||
}
|
||||
|
||||
/* Node is now known to be running a clvmd */
|
||||
static void _add_up_node(const char *csid)
|
||||
{
|
||||
struct node_info *ninfo;
|
||||
|
||||
ninfo = dm_hash_lookup_binary(node_hash, csid, OPENAIS_CSID_LEN);
|
||||
if (!ninfo) {
|
||||
DEBUGLOG("openais_add_up_node no node_hash entry for csid %s\n",
|
||||
print_openais_csid(csid));
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUGLOG("openais_add_up_node %d\n", ninfo->nodeid);
|
||||
|
||||
ninfo->state = NODE_CLVMD;
|
||||
}
|
||||
|
||||
/* Call a callback for each node, so the caller knows whether it's up or down */
|
||||
static int _cluster_do_node_callback(struct local_client *master_client,
|
||||
void (*callback)(struct local_client *,
|
||||
const char *csid, int node_up))
|
||||
{
|
||||
struct dm_hash_node *hn;
|
||||
struct node_info *ninfo;
|
||||
int somedown = 0;
|
||||
|
||||
dm_hash_iterate(hn, node_hash)
|
||||
{
|
||||
char csid[OPENAIS_CSID_LEN];
|
||||
|
||||
ninfo = dm_hash_get_data(node_hash, hn);
|
||||
memcpy(csid, dm_hash_get_key(node_hash, hn), OPENAIS_CSID_LEN);
|
||||
|
||||
DEBUGLOG("down_callback. node %d, state = %d\n", ninfo->nodeid,
|
||||
ninfo->state);
|
||||
|
||||
if (ninfo->state != NODE_DOWN)
|
||||
callback(master_client, csid, ninfo->state == NODE_CLVMD);
|
||||
if (ninfo->state != NODE_CLVMD)
|
||||
somedown = -1;
|
||||
}
|
||||
return somedown;
|
||||
}
|
||||
|
||||
/* Real locking */
|
||||
static int _lock_resource(char *resource, int mode, int flags, int *lockid)
|
||||
{
|
||||
struct lock_info *linfo;
|
||||
SaLckResourceHandleT res_handle;
|
||||
SaAisErrorT err;
|
||||
SaLckLockIdT lock_id;
|
||||
SaLckLockStatusT lockStatus;
|
||||
|
||||
/* This needs to be converted from DLM/LVM2 value for OpenAIS LCK */
|
||||
if (flags & LCK_NONBLOCK) flags = SA_LCK_LOCK_NO_QUEUE;
|
||||
|
||||
linfo = malloc(sizeof(struct lock_info));
|
||||
if (!linfo)
|
||||
return -1;
|
||||
|
||||
DEBUGLOG("lock_resource '%s', flags=%d, mode=%d\n", resource, flags, mode);
|
||||
|
||||
linfo->lock_name.length = strlen(resource)+1;
|
||||
strcpy((char *)linfo->lock_name.value, resource);
|
||||
|
||||
err = saLckResourceOpen(lck_handle, &linfo->lock_name,
|
||||
SA_LCK_RESOURCE_CREATE, TIMEOUT, &res_handle);
|
||||
if (err != SA_AIS_OK)
|
||||
{
|
||||
DEBUGLOG("ResourceOpen returned %d\n", err);
|
||||
free(linfo);
|
||||
return ais_to_errno(err);
|
||||
}
|
||||
|
||||
err = saLckResourceLock(
|
||||
res_handle,
|
||||
&lock_id,
|
||||
mode,
|
||||
flags,
|
||||
0,
|
||||
SA_TIME_END,
|
||||
&lockStatus);
|
||||
if (err != SA_AIS_OK && lockStatus != SA_LCK_LOCK_GRANTED)
|
||||
{
|
||||
free(linfo);
|
||||
saLckResourceClose(res_handle);
|
||||
return ais_to_errno(err);
|
||||
}
|
||||
|
||||
/* Wait for it to complete */
|
||||
|
||||
DEBUGLOG("lock_resource returning %d, lock_id=%" PRIx64 "\n",
|
||||
err, lock_id);
|
||||
|
||||
linfo->lock_id = lock_id;
|
||||
linfo->res_handle = res_handle;
|
||||
|
||||
dm_hash_insert(lock_hash, resource, linfo);
|
||||
|
||||
return ais_to_errno(err);
|
||||
}
|
||||
|
||||
|
||||
static int _unlock_resource(char *resource, int lockid)
|
||||
{
|
||||
SaAisErrorT err;
|
||||
struct lock_info *linfo;
|
||||
|
||||
DEBUGLOG("unlock_resource %s\n", resource);
|
||||
linfo = dm_hash_lookup(lock_hash, resource);
|
||||
if (!linfo)
|
||||
return 0;
|
||||
|
||||
DEBUGLOG("unlock_resource: lockid: %" PRIx64 "\n", linfo->lock_id);
|
||||
err = saLckResourceUnlock(linfo->lock_id, SA_TIME_END);
|
||||
if (err != SA_AIS_OK)
|
||||
{
|
||||
DEBUGLOG("Unlock returned %d\n", err);
|
||||
return ais_to_errno(err);
|
||||
}
|
||||
|
||||
/* Release the resource */
|
||||
dm_hash_remove(lock_hash, resource);
|
||||
saLckResourceClose(linfo->res_handle);
|
||||
free(linfo);
|
||||
|
||||
return ais_to_errno(err);
|
||||
}
|
||||
|
||||
static int _sync_lock(const char *resource, int mode, int flags, int *lockid)
|
||||
{
|
||||
int status;
|
||||
char lock1[strlen(resource)+3];
|
||||
char lock2[strlen(resource)+3];
|
||||
|
||||
snprintf(lock1, sizeof(lock1), "%s-1", resource);
|
||||
snprintf(lock2, sizeof(lock2), "%s-2", resource);
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case LCK_EXCL:
|
||||
status = _lock_resource(lock1, SA_LCK_EX_LOCK_MODE, flags, lockid);
|
||||
if (status)
|
||||
goto out;
|
||||
|
||||
/* If we can't get this lock too then bail out */
|
||||
status = _lock_resource(lock2, SA_LCK_EX_LOCK_MODE, LCK_NONBLOCK,
|
||||
lockid);
|
||||
if (status == SA_LCK_LOCK_NOT_QUEUED)
|
||||
{
|
||||
_unlock_resource(lock1, *lockid);
|
||||
status = -1;
|
||||
errno = EAGAIN;
|
||||
}
|
||||
break;
|
||||
|
||||
case LCK_PREAD:
|
||||
case LCK_READ:
|
||||
status = _lock_resource(lock1, SA_LCK_PR_LOCK_MODE, flags, lockid);
|
||||
if (status)
|
||||
goto out;
|
||||
_unlock_resource(lock2, *lockid);
|
||||
break;
|
||||
|
||||
case LCK_WRITE:
|
||||
status = _lock_resource(lock2, SA_LCK_EX_LOCK_MODE, flags, lockid);
|
||||
if (status)
|
||||
goto out;
|
||||
_unlock_resource(lock1, *lockid);
|
||||
break;
|
||||
|
||||
default:
|
||||
status = -1;
|
||||
errno = EINVAL;
|
||||
break;
|
||||
}
|
||||
out:
|
||||
*lockid = mode;
|
||||
return status;
|
||||
}
|
||||
|
||||
static int _sync_unlock(const char *resource, int lockid)
|
||||
{
|
||||
int status = 0;
|
||||
char lock1[strlen(resource)+3];
|
||||
char lock2[strlen(resource)+3];
|
||||
|
||||
snprintf(lock1, sizeof(lock1), "%s-1", resource);
|
||||
snprintf(lock2, sizeof(lock2), "%s-2", resource);
|
||||
|
||||
_unlock_resource(lock1, lockid);
|
||||
_unlock_resource(lock2, lockid);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* We are always quorate ! */
|
||||
static int _is_quorate()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _get_main_cluster_fd(void)
|
||||
{
|
||||
int select_fd;
|
||||
|
||||
cpg_fd_get(cpg_handle, &select_fd);
|
||||
return select_fd;
|
||||
}
|
||||
|
||||
static int _cluster_fd_callback(struct local_client *fd, char *buf, int len,
|
||||
const char *csid,
|
||||
struct local_client **new_client)
|
||||
{
|
||||
cluster_client = fd;
|
||||
*new_client = NULL;
|
||||
cpg_dispatch(cpg_handle, SA_DISPATCH_ONE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _cluster_send_message(const void *buf, int msglen, const char *csid,
|
||||
const char *errtext)
|
||||
{
|
||||
struct iovec iov[2];
|
||||
SaAisErrorT err;
|
||||
int target_node;
|
||||
|
||||
if (csid)
|
||||
memcpy(&target_node, csid, OPENAIS_CSID_LEN);
|
||||
else
|
||||
target_node = 0;
|
||||
|
||||
iov[0].iov_base = &target_node;
|
||||
iov[0].iov_len = sizeof(int);
|
||||
iov[1].iov_base = (char *)buf;
|
||||
iov[1].iov_len = msglen;
|
||||
|
||||
err = cpg_mcast_joined(cpg_handle, CPG_TYPE_AGREED, iov, 2);
|
||||
return ais_to_errno(err);
|
||||
}
|
||||
|
||||
/* We don't have a cluster name to report here */
|
||||
static int _get_cluster_name(char *buf, int buflen)
|
||||
{
|
||||
strncpy(buf, "OpenAIS", buflen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct cluster_ops _cluster_openais_ops = {
|
||||
.name = "openais",
|
||||
.cluster_init_completed = NULL,
|
||||
.cluster_send_message = _cluster_send_message,
|
||||
.name_from_csid = _name_from_csid,
|
||||
.csid_from_name = _csid_from_name,
|
||||
.get_num_nodes = _get_num_nodes,
|
||||
.cluster_fd_callback = _cluster_fd_callback,
|
||||
.get_main_cluster_fd = _get_main_cluster_fd,
|
||||
.cluster_do_node_callback = _cluster_do_node_callback,
|
||||
.is_quorate = _is_quorate,
|
||||
.get_our_csid = _get_our_csid,
|
||||
.add_up_node = _add_up_node,
|
||||
.reread_config = NULL,
|
||||
.cluster_closedown = _cluster_closedown,
|
||||
.get_cluster_name = _get_cluster_name,
|
||||
.sync_lock = _sync_lock,
|
||||
.sync_unlock = _sync_unlock,
|
||||
};
|
||||
|
||||
struct cluster_ops *init_openais_cluster(void)
|
||||
{
|
||||
if (!_init_cluster())
|
||||
return &_cluster_openais_ops;
|
||||
|
||||
return NULL;
|
||||
}
|
@ -1,382 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2009-2013 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "clvmd-common.h"
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "lib/locking/locking.h"
|
||||
#include "daemons/clvmd/clvm.h"
|
||||
#include "clvmd-comms.h"
|
||||
#include "clvmd.h"
|
||||
|
||||
#include <sys/un.h>
|
||||
#include <sys/socket.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
static const char SINGLENODE_CLVMD_SOCKNAME[] = DEFAULT_RUN_DIR "/clvmd_singlenode.sock";
|
||||
static int listen_fd = -1;
|
||||
|
||||
static struct dm_hash_table *_locks;
|
||||
static int _lockid;
|
||||
|
||||
static pthread_mutex_t _lock_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
/* Using one common condition for all locks for simplicity */
|
||||
static pthread_cond_t _lock_cond = PTHREAD_COND_INITIALIZER;
|
||||
|
||||
struct lock {
|
||||
struct dm_list list;
|
||||
int lockid;
|
||||
int mode;
|
||||
};
|
||||
|
||||
static void close_comms(void)
|
||||
{
|
||||
if (listen_fd != -1 && close(listen_fd))
|
||||
stack;
|
||||
(void)unlink(SINGLENODE_CLVMD_SOCKNAME);
|
||||
listen_fd = -1;
|
||||
}
|
||||
|
||||
static int init_comms(void)
|
||||
{
|
||||
mode_t old_mask;
|
||||
struct sockaddr_un addr = { .sun_family = AF_UNIX };
|
||||
|
||||
if (!dm_strncpy(addr.sun_path, SINGLENODE_CLVMD_SOCKNAME,
|
||||
sizeof(addr.sun_path))) {
|
||||
DEBUGLOG("%s: singlenode socket name too long.",
|
||||
SINGLENODE_CLVMD_SOCKNAME);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close_comms();
|
||||
|
||||
(void) dm_prepare_selinux_context(SINGLENODE_CLVMD_SOCKNAME, S_IFSOCK);
|
||||
old_mask = umask(0077);
|
||||
|
||||
listen_fd = socket(PF_UNIX, SOCK_STREAM, 0);
|
||||
if (listen_fd < 0) {
|
||||
DEBUGLOG("Can't create local socket: %s\n", strerror(errno));
|
||||
goto error;
|
||||
}
|
||||
/* Set Close-on-exec */
|
||||
if (fcntl(listen_fd, F_SETFD, 1)) {
|
||||
DEBUGLOG("Setting CLOEXEC on client fd failed: %s\n", strerror(errno));
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (bind(listen_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
DEBUGLOG("Can't bind local socket: %s\n", strerror(errno));
|
||||
goto error;
|
||||
}
|
||||
if (listen(listen_fd, 10) < 0) {
|
||||
DEBUGLOG("Can't listen local socket: %s\n", strerror(errno));
|
||||
goto error;
|
||||
}
|
||||
|
||||
umask(old_mask);
|
||||
(void) dm_prepare_selinux_context(NULL, 0);
|
||||
return 0;
|
||||
error:
|
||||
umask(old_mask);
|
||||
(void) dm_prepare_selinux_context(NULL, 0);
|
||||
close_comms();
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _init_cluster(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (!(_locks = dm_hash_create(128))) {
|
||||
DEBUGLOG("Failed to allocate single-node hash table.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
r = init_comms();
|
||||
if (r) {
|
||||
dm_hash_destroy(_locks);
|
||||
_locks = NULL;
|
||||
return r;
|
||||
}
|
||||
|
||||
DEBUGLOG("Single-node cluster initialised.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _cluster_closedown(void)
|
||||
{
|
||||
close_comms();
|
||||
|
||||
/* If there is any awaited resource, kill it softly */
|
||||
pthread_mutex_lock(&_lock_mutex);
|
||||
dm_hash_destroy(_locks);
|
||||
_locks = NULL;
|
||||
_lockid = 0;
|
||||
pthread_cond_broadcast(&_lock_cond); /* wakeup waiters */
|
||||
pthread_mutex_unlock(&_lock_mutex);
|
||||
}
|
||||
|
||||
static void _get_our_csid(char *csid)
|
||||
{
|
||||
int nodeid = 1;
|
||||
memcpy(csid, &nodeid, sizeof(int));
|
||||
}
|
||||
|
||||
static int _csid_from_name(char *csid, const char *name)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _name_from_csid(const char *csid, char *name)
|
||||
{
|
||||
strcpy(name, "SINGLENODE");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _get_num_nodes(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Node is now known to be running a clvmd */
|
||||
static void _add_up_node(const char *csid)
|
||||
{
|
||||
}
|
||||
|
||||
/* Call a callback for each node, so the caller knows whether it's up or down */
|
||||
static int _cluster_do_node_callback(struct local_client *master_client,
|
||||
void (*callback)(struct local_client *,
|
||||
const char *csid, int node_up))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _lock_file(const char *file, uint32_t flags);
|
||||
|
||||
static const char *_get_mode(int mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case LCK_NULL: return "NULL";
|
||||
case LCK_READ: return "READ";
|
||||
case LCK_PREAD: return "PREAD";
|
||||
case LCK_WRITE: return "WRITE";
|
||||
case LCK_EXCL: return "EXCLUSIVE";
|
||||
case LCK_UNLOCK: return "UNLOCK";
|
||||
default: return "????";
|
||||
}
|
||||
}
|
||||
|
||||
/* Real locking */
|
||||
static int _lock_resource(const char *resource, int mode, int flags, int *lockid)
|
||||
{
|
||||
/* DLM table of allowed transition states */
|
||||
static const int _dlm_table[6][6] = {
|
||||
/* Mode NL CR CW PR PW EX */
|
||||
/* NL */ { 1, 1, 1, 1, 1, 1},
|
||||
/* CR */ { 1, 1, 1, 1, 1, 0},
|
||||
/* CW */ { 1, 1, 1, 0, 0, 0},
|
||||
/* PR */ { 1, 1, 0, 1, 0, 0},
|
||||
/* PW */ { 1, 1, 0, 0, 0, 0},
|
||||
/* EX */ { 1, 0, 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
struct lock *lck = NULL, *lckt;
|
||||
struct dm_list *head;
|
||||
|
||||
DEBUGLOG("Locking resource %s, flags=0x%02x (%s%s%s), mode=%s (%d)\n",
|
||||
resource, flags,
|
||||
(flags & LCKF_NOQUEUE) ? "NOQUEUE" : "",
|
||||
((flags & (LCKF_NOQUEUE | LCKF_CONVERT)) ==
|
||||
(LCKF_NOQUEUE | LCKF_CONVERT)) ? "|" : "",
|
||||
(flags & LCKF_CONVERT) ? "CONVERT" : "",
|
||||
_get_mode(mode), mode);
|
||||
|
||||
mode &= LCK_TYPE_MASK;
|
||||
pthread_mutex_lock(&_lock_mutex);
|
||||
|
||||
retry:
|
||||
if (!(head = dm_hash_lookup(_locks, resource))) {
|
||||
if (flags & LCKF_CONVERT) {
|
||||
/* In real DLM, lock is identified only by lockid, resource is not used */
|
||||
DEBUGLOG("Unlocked resource %s cannot be converted\n", resource);
|
||||
goto_bad;
|
||||
}
|
||||
/* Add new locked resource */
|
||||
if (!(head = dm_malloc(sizeof(struct dm_list))) ||
|
||||
!dm_hash_insert(_locks, resource, head)) {
|
||||
dm_free(head);
|
||||
goto_bad;
|
||||
}
|
||||
|
||||
dm_list_init(head);
|
||||
} else /* Update/convert locked resource */
|
||||
dm_list_iterate_items(lck, head) {
|
||||
/* Check is all locks are compatible with requested lock */
|
||||
if (flags & LCKF_CONVERT) {
|
||||
if (lck->lockid != *lockid)
|
||||
continue;
|
||||
|
||||
DEBUGLOG("Converting resource %s lockid=%d mode:%s -> %s...\n",
|
||||
resource, lck->lockid, _get_mode(lck->mode), _get_mode(mode));
|
||||
dm_list_iterate_items(lckt, head) {
|
||||
if ((lckt->lockid != *lockid) &&
|
||||
!_dlm_table[mode][lckt->mode]) {
|
||||
if (!(flags & LCKF_NOQUEUE) &&
|
||||
/* TODO: Real dlm uses here conversion queues */
|
||||
!pthread_cond_wait(&_lock_cond, &_lock_mutex) &&
|
||||
_locks) /* End of the game? */
|
||||
goto retry;
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
lck->mode = mode; /* Lock is now converted */
|
||||
goto out;
|
||||
} else if (!_dlm_table[mode][lck->mode]) {
|
||||
DEBUGLOG("Resource %s already locked lockid=%d, mode:%s\n",
|
||||
resource, lck->lockid, _get_mode(lck->mode));
|
||||
if (!(flags & LCKF_NOQUEUE) &&
|
||||
!pthread_cond_wait(&_lock_cond, &_lock_mutex) &&
|
||||
_locks) { /* End of the game? */
|
||||
DEBUGLOG("Resource %s retrying lock in mode:%s...\n",
|
||||
resource, _get_mode(mode));
|
||||
goto retry;
|
||||
}
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(flags & LCKF_CONVERT)) {
|
||||
if (!(lck = dm_malloc(sizeof(struct lock))))
|
||||
goto_bad;
|
||||
|
||||
*lockid = lck->lockid = ++_lockid;
|
||||
lck->mode = mode;
|
||||
dm_list_add(head, &lck->list);
|
||||
}
|
||||
out:
|
||||
pthread_cond_broadcast(&_lock_cond); /* to wakeup waiters */
|
||||
pthread_mutex_unlock(&_lock_mutex);
|
||||
DEBUGLOG("Locked resource %s, lockid=%d, mode=%s\n",
|
||||
resource, lck->lockid, _get_mode(lck->mode));
|
||||
|
||||
return 0;
|
||||
bad:
|
||||
pthread_cond_broadcast(&_lock_cond); /* to wakeup waiters */
|
||||
pthread_mutex_unlock(&_lock_mutex);
|
||||
DEBUGLOG("Failed to lock resource %s\n", resource);
|
||||
|
||||
return 1; /* fail */
|
||||
}
|
||||
|
||||
static int _unlock_resource(const char *resource, int lockid)
|
||||
{
|
||||
struct lock *lck;
|
||||
struct dm_list *head;
|
||||
int r = 1;
|
||||
|
||||
if (lockid < 0) {
|
||||
DEBUGLOG("Not tracking unlock of lockid -1: %s, lockid=%d\n",
|
||||
resource, lockid);
|
||||
return 1;
|
||||
}
|
||||
|
||||
DEBUGLOG("Unlocking resource %s, lockid=%d\n", resource, lockid);
|
||||
pthread_mutex_lock(&_lock_mutex);
|
||||
pthread_cond_broadcast(&_lock_cond); /* wakeup waiters */
|
||||
|
||||
if (!(head = dm_hash_lookup(_locks, resource))) {
|
||||
pthread_mutex_unlock(&_lock_mutex);
|
||||
DEBUGLOG("Resource %s is not locked.\n", resource);
|
||||
return 1;
|
||||
}
|
||||
|
||||
dm_list_iterate_items(lck, head)
|
||||
if (lck->lockid == lockid) {
|
||||
dm_list_del(&lck->list);
|
||||
dm_free(lck);
|
||||
r = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
DEBUGLOG("Resource %s has wrong lockid %d.\n", resource, lockid);
|
||||
out:
|
||||
if (dm_list_empty(head)) {
|
||||
//DEBUGLOG("Resource %s is no longer hashed (lockid=%d).\n", resource, lockid);
|
||||
dm_hash_remove(_locks, resource);
|
||||
dm_free(head);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&_lock_mutex);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _is_quorate(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _get_main_cluster_fd(void)
|
||||
{
|
||||
return listen_fd;
|
||||
}
|
||||
|
||||
static int _cluster_fd_callback(struct local_client *fd, char *buf, int len,
|
||||
const char *csid,
|
||||
struct local_client **new_client)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _cluster_send_message(const void *buf, int msglen,
|
||||
const char *csid,
|
||||
const char *errtext)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _get_cluster_name(char *buf, int buflen)
|
||||
{
|
||||
return dm_strncpy(buf, "localcluster", buflen) ? 0 : 1;
|
||||
}
|
||||
|
||||
static struct cluster_ops _cluster_singlenode_ops = {
|
||||
.name = "singlenode",
|
||||
.cluster_init_completed = NULL,
|
||||
.cluster_send_message = _cluster_send_message,
|
||||
.name_from_csid = _name_from_csid,
|
||||
.csid_from_name = _csid_from_name,
|
||||
.get_num_nodes = _get_num_nodes,
|
||||
.cluster_fd_callback = _cluster_fd_callback,
|
||||
.get_main_cluster_fd = _get_main_cluster_fd,
|
||||
.cluster_do_node_callback = _cluster_do_node_callback,
|
||||
.is_quorate = _is_quorate,
|
||||
.get_our_csid = _get_our_csid,
|
||||
.add_up_node = _add_up_node,
|
||||
.reread_config = NULL,
|
||||
.cluster_closedown = _cluster_closedown,
|
||||
.get_cluster_name = _get_cluster_name,
|
||||
.sync_lock = _lock_resource,
|
||||
.sync_unlock = _unlock_resource,
|
||||
};
|
||||
|
||||
struct cluster_ops *init_singlenode_cluster(void)
|
||||
{
|
||||
if (!_init_cluster())
|
||||
return &_cluster_singlenode_ops;
|
||||
|
||||
return NULL;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,126 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _CLVMD_H
|
||||
#define _CLVMD_H
|
||||
|
||||
#define CLVMD_MAJOR_VERSION 0
|
||||
#define CLVMD_MINOR_VERSION 2
|
||||
#define CLVMD_PATCH_VERSION 1
|
||||
|
||||
/* Default time (in seconds) we will wait for all remote commands to execute
|
||||
before declaring them dead */
|
||||
#define DEFAULT_CMD_TIMEOUT 60
|
||||
|
||||
/* One of these for each reply we get from command execution on a node */
|
||||
struct node_reply {
|
||||
char node[MAX_CLUSTER_MEMBER_NAME_LEN];
|
||||
char *replymsg;
|
||||
int status;
|
||||
struct node_reply *next;
|
||||
};
|
||||
|
||||
typedef enum {DEBUG_OFF, DEBUG_STDERR, DEBUG_SYSLOG} debug_t;
|
||||
|
||||
/*
|
||||
* These exist for the use of local sockets only when we are
|
||||
* collecting responses from all cluster nodes
|
||||
*/
|
||||
struct localsock_bits {
|
||||
struct node_reply *replies;
|
||||
int num_replies;
|
||||
int expected_replies;
|
||||
time_t sent_time; /* So we can check for timeouts */
|
||||
int in_progress; /* Only execute one cmd at a time per client */
|
||||
int sent_out; /* Flag to indicate that a command was sent
|
||||
to remote nodes */
|
||||
void *private; /* Private area for command processor use */
|
||||
void *cmd; /* Whole command as passed down local socket */
|
||||
int cmd_len; /* Length of above */
|
||||
int pipe; /* Pipe to send PRE completion status down */
|
||||
int finished; /* Flag to tell subthread to exit */
|
||||
int all_success; /* Set to 0 if any node (or the pre_command)
|
||||
failed */
|
||||
int cleanup_needed; /* helper for cleanup_zombie */
|
||||
struct local_client *pipe_client;
|
||||
pthread_t threadid;
|
||||
enum { PRE_COMMAND, POST_COMMAND } state;
|
||||
pthread_mutex_t mutex; /* Main thread and worker synchronisation */
|
||||
pthread_cond_t cond;
|
||||
};
|
||||
|
||||
/* Entries for PIPE clients */
|
||||
struct pipe_bits {
|
||||
struct local_client *client; /* Actual (localsock) client */
|
||||
pthread_t threadid; /* Our own copy of the thread id */
|
||||
};
|
||||
|
||||
/* Entries for Network socket clients */
|
||||
struct netsock_bits {
|
||||
void *private;
|
||||
int flags;
|
||||
};
|
||||
|
||||
typedef int (*fd_callback_t) (struct local_client * fd, char *buf, int len,
|
||||
const char *csid,
|
||||
struct local_client ** new_client);
|
||||
|
||||
/* One of these for each fd we are listening on */
|
||||
struct local_client {
|
||||
int fd;
|
||||
enum { CLUSTER_MAIN_SOCK, CLUSTER_DATA_SOCK, LOCAL_RENDEZVOUS,
|
||||
LOCAL_SOCK, THREAD_PIPE, CLUSTER_INTERNAL } type;
|
||||
struct local_client *next;
|
||||
unsigned short xid;
|
||||
fd_callback_t callback;
|
||||
uint8_t removeme;
|
||||
|
||||
union {
|
||||
struct localsock_bits localsock;
|
||||
struct pipe_bits pipe;
|
||||
struct netsock_bits net;
|
||||
} bits;
|
||||
};
|
||||
|
||||
#define DEBUGLOG(fmt, args...) debuglog(fmt, ## args)
|
||||
|
||||
#ifndef max
|
||||
#define max(a,b) ((a)>(b)?(a):(b))
|
||||
#endif
|
||||
|
||||
/* The real command processor is in clvmd-command.c */
|
||||
extern int do_command(struct local_client *client, struct clvm_header *msg,
|
||||
int msglen, char **buf, int buflen, int *retlen);
|
||||
|
||||
/* Pre and post command routines are called only on the local node */
|
||||
extern int do_pre_command(struct local_client *client);
|
||||
extern int do_post_command(struct local_client *client);
|
||||
extern void cmd_client_cleanup(struct local_client *client);
|
||||
extern int add_client(struct local_client *new_client);
|
||||
|
||||
extern void clvmd_cluster_init_completed(void);
|
||||
extern void process_message(struct local_client *client, char *buf,
|
||||
int len, const char *csid);
|
||||
extern void debuglog(const char *fmt, ... )
|
||||
__attribute__ ((format(printf, 1, 2)));
|
||||
|
||||
void clvmd_set_debug(debug_t new_de);
|
||||
debug_t clvmd_get_debug(void);
|
||||
int clvmd_get_foreground(void);
|
||||
|
||||
int sync_lock(const char *resource, int mode, int flags, int *lockid);
|
||||
int sync_unlock(const char *resource, int lockid);
|
||||
|
||||
#endif
|
@ -1,927 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2012 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "clvmd-common.h"
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "daemons/clvmd/clvm.h"
|
||||
#include "clvmd-comms.h"
|
||||
#include "clvmd.h"
|
||||
#include "lvm-functions.h"
|
||||
|
||||
/* LVM2 headers */
|
||||
#include "lib/commands/toolcontext.h"
|
||||
#include "lib/cache/lvmcache.h"
|
||||
#include "lib/misc/lvm-globals.h"
|
||||
#include "lib/activate/activate.h"
|
||||
#include "lib/format_text/archiver.h"
|
||||
#include "lib/mm/memlock.h"
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
static struct cmd_context *cmd = NULL;
|
||||
static struct dm_hash_table *lv_hash = NULL;
|
||||
static pthread_mutex_t lv_hash_lock;
|
||||
static pthread_mutex_t lvm_lock;
|
||||
static char last_error[1024];
|
||||
|
||||
struct lv_info {
|
||||
int lock_id;
|
||||
int lock_mode;
|
||||
};
|
||||
|
||||
static const char *decode_full_locking_cmd(uint32_t cmdl)
|
||||
{
|
||||
static char buf[128];
|
||||
const char *type;
|
||||
const char *scope;
|
||||
const char *command;
|
||||
|
||||
switch (cmdl & LCK_TYPE_MASK) {
|
||||
case LCK_NULL:
|
||||
type = "NULL";
|
||||
break;
|
||||
case LCK_READ:
|
||||
type = "READ";
|
||||
break;
|
||||
case LCK_PREAD:
|
||||
type = "PREAD";
|
||||
break;
|
||||
case LCK_WRITE:
|
||||
type = "WRITE";
|
||||
break;
|
||||
case LCK_EXCL:
|
||||
type = "EXCL";
|
||||
break;
|
||||
case LCK_UNLOCK:
|
||||
type = "UNLOCK";
|
||||
break;
|
||||
default:
|
||||
type = "unknown";
|
||||
break;
|
||||
}
|
||||
|
||||
switch (cmdl & LCK_SCOPE_MASK) {
|
||||
case LCK_VG:
|
||||
scope = "VG";
|
||||
command = "LCK_VG";
|
||||
break;
|
||||
case LCK_LV:
|
||||
scope = "LV";
|
||||
switch (cmdl & LCK_MASK) {
|
||||
case LCK_LV_EXCLUSIVE & LCK_MASK:
|
||||
command = "LCK_LV_EXCLUSIVE";
|
||||
break;
|
||||
case LCK_LV_SUSPEND & LCK_MASK:
|
||||
command = "LCK_LV_SUSPEND";
|
||||
break;
|
||||
case LCK_LV_RESUME & LCK_MASK:
|
||||
command = "LCK_LV_RESUME";
|
||||
break;
|
||||
case LCK_LV_ACTIVATE & LCK_MASK:
|
||||
command = "LCK_LV_ACTIVATE";
|
||||
break;
|
||||
case LCK_LV_DEACTIVATE & LCK_MASK:
|
||||
command = "LCK_LV_DEACTIVATE";
|
||||
break;
|
||||
default:
|
||||
command = "unknown";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
scope = "unknown";
|
||||
command = "unknown";
|
||||
break;
|
||||
}
|
||||
|
||||
sprintf(buf, "0x%x %s (%s|%s%s%s%s%s)", cmdl, command, type, scope,
|
||||
cmdl & LCK_NONBLOCK ? "|NONBLOCK" : "",
|
||||
cmdl & LCK_HOLD ? "|HOLD" : "",
|
||||
cmdl & LCK_CLUSTER_VG ? "|CLUSTER_VG" : "",
|
||||
cmdl & LCK_CACHE ? "|CACHE" : "");
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* Only processes 8 bits: excludes LCK_CACHE.
|
||||
*/
|
||||
static const char *decode_locking_cmd(unsigned char cmdl)
|
||||
{
|
||||
return decode_full_locking_cmd((uint32_t) cmdl);
|
||||
}
|
||||
|
||||
static const char *decode_flags(unsigned char flags)
|
||||
{
|
||||
static char buf[128];
|
||||
int len;
|
||||
|
||||
len = sprintf(buf, "0x%x ( %s%s%s%s%s%s%s%s)", flags,
|
||||
flags & LCK_PARTIAL_MODE ? "PARTIAL_MODE|" : "",
|
||||
flags & LCK_MIRROR_NOSYNC_MODE ? "MIRROR_NOSYNC|" : "",
|
||||
flags & LCK_DMEVENTD_MONITOR_MODE ? "DMEVENTD_MONITOR|" : "",
|
||||
flags & LCK_ORIGIN_ONLY_MODE ? "ORIGIN_ONLY|" : "",
|
||||
flags & LCK_TEST_MODE ? "TEST|" : "",
|
||||
flags & LCK_CONVERT_MODE ? "CONVERT|" : "",
|
||||
flags & LCK_DMEVENTD_MONITOR_IGNORE ? "DMEVENTD_MONITOR_IGNORE|" : "",
|
||||
flags & LCK_REVERT_MODE ? "REVERT|" : "");
|
||||
|
||||
if (len > 1)
|
||||
buf[len - 2] = ' ';
|
||||
else
|
||||
buf[0] = '\0';
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
char *get_last_lvm_error(void)
|
||||
{
|
||||
return last_error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Hash lock info helpers
|
||||
*/
|
||||
static struct lv_info *lookup_info(const char *resource)
|
||||
{
|
||||
struct lv_info *lvi;
|
||||
|
||||
pthread_mutex_lock(&lv_hash_lock);
|
||||
lvi = dm_hash_lookup(lv_hash, resource);
|
||||
pthread_mutex_unlock(&lv_hash_lock);
|
||||
|
||||
return lvi;
|
||||
}
|
||||
|
||||
static int insert_info(const char *resource, struct lv_info *lvi)
|
||||
{
|
||||
int ret;
|
||||
|
||||
pthread_mutex_lock(&lv_hash_lock);
|
||||
ret = dm_hash_insert(lv_hash, resource, lvi);
|
||||
pthread_mutex_unlock(&lv_hash_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void remove_info(const char *resource)
|
||||
{
|
||||
int num_open;
|
||||
|
||||
pthread_mutex_lock(&lv_hash_lock);
|
||||
dm_hash_remove(lv_hash, resource);
|
||||
|
||||
/* When last lock is remove, validate there are not left opened devices */
|
||||
if (!dm_hash_get_first(lv_hash)) {
|
||||
if (critical_section())
|
||||
log_error(INTERNAL_ERROR "No volumes are locked however clvmd is in activation mode critical section.");
|
||||
if ((num_open = dev_cache_check_for_open_devices()))
|
||||
log_error(INTERNAL_ERROR "No volumes are locked however %d devices are still open.", num_open);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&lv_hash_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the mode a lock is currently held at (or -1 if not held)
|
||||
*/
|
||||
static int get_current_lock(char *resource)
|
||||
{
|
||||
struct lv_info *lvi;
|
||||
|
||||
if ((lvi = lookup_info(resource)))
|
||||
return lvi->lock_mode;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
void init_lvhash(void)
|
||||
{
|
||||
/* Create hash table for keeping LV locks & status */
|
||||
lv_hash = dm_hash_create(1024);
|
||||
pthread_mutex_init(&lv_hash_lock, NULL);
|
||||
pthread_mutex_init(&lvm_lock, NULL);
|
||||
}
|
||||
|
||||
/* Called at shutdown to tidy the lockspace */
|
||||
void destroy_lvhash(void)
|
||||
{
|
||||
struct dm_hash_node *v;
|
||||
struct lv_info *lvi;
|
||||
char *resource;
|
||||
int status;
|
||||
|
||||
pthread_mutex_lock(&lv_hash_lock);
|
||||
|
||||
dm_hash_iterate(v, lv_hash) {
|
||||
lvi = dm_hash_get_data(lv_hash, v);
|
||||
resource = dm_hash_get_key(lv_hash, v);
|
||||
|
||||
if ((status = sync_unlock(resource, lvi->lock_id)))
|
||||
DEBUGLOG("unlock_all. unlock failed(%d): %s\n",
|
||||
status, strerror(errno));
|
||||
dm_free(lvi);
|
||||
}
|
||||
|
||||
dm_hash_destroy(lv_hash);
|
||||
lv_hash = NULL;
|
||||
|
||||
pthread_mutex_unlock(&lv_hash_lock);
|
||||
}
|
||||
|
||||
/* Gets a real lock and keeps the info in the hash table */
|
||||
static int hold_lock(char *resource, int mode, int flags)
|
||||
{
|
||||
int status;
|
||||
int saved_errno;
|
||||
struct lv_info *lvi;
|
||||
|
||||
/* Mask off invalid options */
|
||||
flags &= LCKF_NOQUEUE | LCKF_CONVERT;
|
||||
|
||||
lvi = lookup_info(resource);
|
||||
|
||||
if (lvi) {
|
||||
if (lvi->lock_mode == mode) {
|
||||
DEBUGLOG("hold_lock, lock mode %d already held\n",
|
||||
mode);
|
||||
return 0;
|
||||
}
|
||||
if ((lvi->lock_mode == LCK_EXCL) && (mode == LCK_WRITE)) {
|
||||
DEBUGLOG("hold_lock, lock already held LCK_EXCL, "
|
||||
"ignoring LCK_WRITE request\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Only allow explicit conversions */
|
||||
if (lvi && !(flags & LCKF_CONVERT)) {
|
||||
errno = EBUSY;
|
||||
return -1;
|
||||
}
|
||||
if (lvi) {
|
||||
/* Already exists - convert it */
|
||||
status = sync_lock(resource, mode, flags, &lvi->lock_id);
|
||||
saved_errno = errno;
|
||||
if (!status)
|
||||
lvi->lock_mode = mode;
|
||||
else
|
||||
DEBUGLOG("hold_lock. convert to %d failed: %s\n", mode,
|
||||
strerror(errno));
|
||||
errno = saved_errno;
|
||||
} else {
|
||||
if (!(lvi = dm_malloc(sizeof(struct lv_info)))) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
lvi->lock_mode = mode;
|
||||
lvi->lock_id = 0;
|
||||
status = sync_lock(resource, mode, flags & ~LCKF_CONVERT, &lvi->lock_id);
|
||||
saved_errno = errno;
|
||||
if (status) {
|
||||
dm_free(lvi);
|
||||
DEBUGLOG("hold_lock. lock at %d failed: %s\n", mode,
|
||||
strerror(errno));
|
||||
} else
|
||||
if (!insert_info(resource, lvi)) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
errno = saved_errno;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Unlock and remove it from the hash table */
|
||||
static int hold_unlock(char *resource)
|
||||
{
|
||||
struct lv_info *lvi;
|
||||
int status;
|
||||
int saved_errno;
|
||||
|
||||
if (!(lvi = lookup_info(resource))) {
|
||||
DEBUGLOG("hold_unlock, lock not already held\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
status = sync_unlock(resource, lvi->lock_id);
|
||||
saved_errno = errno;
|
||||
if (!status) {
|
||||
remove_info(resource);
|
||||
dm_free(lvi);
|
||||
} else {
|
||||
DEBUGLOG("hold_unlock. unlock failed(%d): %s\n", status,
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
errno = saved_errno;
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Watch the return codes here.
|
||||
liblvm API functions return 1(true) for success, 0(false) for failure and don't set errno.
|
||||
libdlm API functions return 0 for success, -1 for failure and do set errno.
|
||||
These functions here return 0 for success or >0 for failure (where the retcode is errno)
|
||||
*/
|
||||
|
||||
/* Activate LV exclusive or non-exclusive */
|
||||
static int do_activate_lv(char *resource, unsigned char command, unsigned char lock_flags, int mode)
|
||||
{
|
||||
int oldmode;
|
||||
int status;
|
||||
int activate_lv;
|
||||
int exclusive = 0;
|
||||
struct lvinfo lvi;
|
||||
|
||||
/* Is it already open ? */
|
||||
oldmode = get_current_lock(resource);
|
||||
if (oldmode == mode && (command & LCK_CLUSTER_VG)) {
|
||||
DEBUGLOG("do_activate_lv, lock already held at %d\n", oldmode);
|
||||
return 0; /* Nothing to do */
|
||||
}
|
||||
|
||||
/* Does the config file want us to activate this LV ? */
|
||||
if (!lv_activation_filter(cmd, resource, &activate_lv, NULL))
|
||||
return EIO;
|
||||
|
||||
if (!activate_lv)
|
||||
return 0; /* Success, we did nothing! */
|
||||
|
||||
/* Do we need to activate exclusively? */
|
||||
if ((activate_lv == 2) || (mode == LCK_EXCL)) {
|
||||
exclusive = 1;
|
||||
mode = LCK_EXCL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to get the lock if it's a clustered volume group.
|
||||
* Use lock conversion only if requested, to prevent implicit conversion
|
||||
* of exclusive lock to shared one during activation.
|
||||
*/
|
||||
if (!test_mode() && command & LCK_CLUSTER_VG) {
|
||||
status = hold_lock(resource, mode, LCKF_NOQUEUE | ((lock_flags & LCK_CONVERT_MODE) ? LCKF_CONVERT:0));
|
||||
if (status) {
|
||||
/* Return an LVM-sensible error for this.
|
||||
* Forcing EIO makes the upper level return this text
|
||||
* rather than the strerror text for EAGAIN.
|
||||
*/
|
||||
if (errno == EAGAIN) {
|
||||
sprintf(last_error, "Volume is busy on another node");
|
||||
errno = EIO;
|
||||
}
|
||||
return errno;
|
||||
}
|
||||
}
|
||||
|
||||
/* If it's suspended then resume it */
|
||||
if (!lv_info_by_lvid(cmd, resource, 0, &lvi, 0, 0))
|
||||
goto error;
|
||||
|
||||
if (lvi.suspended) {
|
||||
critical_section_inc(cmd, "resuming");
|
||||
if (!lv_resume(cmd, resource, 0, NULL)) {
|
||||
critical_section_dec(cmd, "resumed");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now activate it */
|
||||
if (!lv_activate(cmd, resource, exclusive, 0, 0, NULL))
|
||||
goto error;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (!test_mode() && (oldmode == -1 || oldmode != mode))
|
||||
(void)hold_unlock(resource);
|
||||
return EIO;
|
||||
}
|
||||
|
||||
/* Resume the LV if it was active */
|
||||
static int do_resume_lv(char *resource, unsigned char command, unsigned char lock_flags)
|
||||
{
|
||||
int oldmode, origin_only, exclusive, revert;
|
||||
|
||||
/* Is it open ? */
|
||||
oldmode = get_current_lock(resource);
|
||||
if (oldmode == -1 && (command & LCK_CLUSTER_VG)) {
|
||||
DEBUGLOG("do_resume_lv, lock not already held\n");
|
||||
return 0; /* We don't need to do anything */
|
||||
}
|
||||
origin_only = (lock_flags & LCK_ORIGIN_ONLY_MODE) ? 1 : 0;
|
||||
exclusive = (oldmode == LCK_EXCL) ? 1 : 0;
|
||||
revert = (lock_flags & LCK_REVERT_MODE) ? 1 : 0;
|
||||
|
||||
if (!lv_resume_if_active(cmd, resource, origin_only, exclusive, revert, NULL))
|
||||
return EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Suspend the device if active */
|
||||
static int do_suspend_lv(char *resource, unsigned char command, unsigned char lock_flags)
|
||||
{
|
||||
int oldmode;
|
||||
unsigned origin_only = (lock_flags & LCK_ORIGIN_ONLY_MODE) ? 1 : 0;
|
||||
unsigned exclusive;
|
||||
|
||||
/* Is it open ? */
|
||||
oldmode = get_current_lock(resource);
|
||||
if (oldmode == -1 && (command & LCK_CLUSTER_VG)) {
|
||||
DEBUGLOG("do_suspend_lv, lock not already held\n");
|
||||
return 0; /* Not active, so it's OK */
|
||||
}
|
||||
|
||||
exclusive = (oldmode == LCK_EXCL) ? 1 : 0;
|
||||
|
||||
/* Always call lv_suspend to read commited and precommited data */
|
||||
if (!lv_suspend_if_active(cmd, resource, origin_only, exclusive, NULL, NULL))
|
||||
return EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_deactivate_lv(char *resource, unsigned char command, unsigned char lock_flags)
|
||||
{
|
||||
int oldmode;
|
||||
int status;
|
||||
|
||||
/* Is it open ? */
|
||||
oldmode = get_current_lock(resource);
|
||||
if (oldmode == -1 && (command & LCK_CLUSTER_VG)) {
|
||||
DEBUGLOG("do_deactivate_lock, lock not already held\n");
|
||||
return 0; /* We don't need to do anything */
|
||||
}
|
||||
|
||||
if (!lv_deactivate(cmd, resource, NULL))
|
||||
return EIO;
|
||||
|
||||
if (!test_mode() && command & LCK_CLUSTER_VG) {
|
||||
status = hold_unlock(resource);
|
||||
if (status)
|
||||
return errno;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *do_lock_query(char *resource)
|
||||
{
|
||||
int mode;
|
||||
const char *type;
|
||||
|
||||
mode = get_current_lock(resource);
|
||||
switch (mode) {
|
||||
case LCK_NULL: type = "NL"; break;
|
||||
case LCK_READ: type = "CR"; break;
|
||||
case LCK_PREAD:type = "PR"; break;
|
||||
case LCK_WRITE:type = "PW"; break;
|
||||
case LCK_EXCL: type = "EX"; break;
|
||||
default: type = NULL;
|
||||
}
|
||||
|
||||
DEBUGLOG("do_lock_query: resource '%s', mode %i (%s)\n", resource, mode, type ?: "--");
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
/* This is the LOCK_LV part that happens on all nodes in the cluster -
|
||||
it is responsible for the interaction with device-mapper and LVM */
|
||||
int do_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
DEBUGLOG("do_lock_lv: resource '%s', cmd = %s, flags = %s, critical_section = %d\n",
|
||||
resource, decode_locking_cmd(command), decode_flags(lock_flags), critical_section());
|
||||
|
||||
if (!cmd->initialized.config || config_files_changed(cmd)) {
|
||||
/* Reinitialise various settings inc. logging, filters */
|
||||
if (do_refresh_cache()) {
|
||||
log_error("Updated config file invalid. Aborting.");
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&lvm_lock);
|
||||
init_test((lock_flags & LCK_TEST_MODE) ? 1 : 0);
|
||||
|
||||
if (lock_flags & LCK_MIRROR_NOSYNC_MODE)
|
||||
init_mirror_in_sync(1);
|
||||
|
||||
if (lock_flags & LCK_DMEVENTD_MONITOR_IGNORE)
|
||||
init_dmeventd_monitor(DMEVENTD_MONITOR_IGNORE);
|
||||
else {
|
||||
if (lock_flags & LCK_DMEVENTD_MONITOR_MODE)
|
||||
init_dmeventd_monitor(1);
|
||||
else
|
||||
init_dmeventd_monitor(0);
|
||||
}
|
||||
|
||||
cmd->partial_activation = (lock_flags & LCK_PARTIAL_MODE) ? 1 : 0;
|
||||
|
||||
/* clvmd should never try to read suspended device */
|
||||
init_ignore_suspended_devices(1);
|
||||
|
||||
switch (command & LCK_MASK) {
|
||||
case LCK_LV_EXCLUSIVE:
|
||||
status = do_activate_lv(resource, command, lock_flags, LCK_EXCL);
|
||||
break;
|
||||
|
||||
case LCK_LV_SUSPEND:
|
||||
status = do_suspend_lv(resource, command, lock_flags);
|
||||
break;
|
||||
|
||||
case LCK_UNLOCK:
|
||||
case LCK_LV_RESUME: /* if active */
|
||||
status = do_resume_lv(resource, command, lock_flags);
|
||||
break;
|
||||
|
||||
case LCK_LV_ACTIVATE:
|
||||
status = do_activate_lv(resource, command, lock_flags, LCK_READ);
|
||||
break;
|
||||
|
||||
case LCK_LV_DEACTIVATE:
|
||||
status = do_deactivate_lv(resource, command, lock_flags);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUGLOG("Invalid LV command 0x%x\n", command);
|
||||
status = EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (lock_flags & LCK_MIRROR_NOSYNC_MODE)
|
||||
init_mirror_in_sync(0);
|
||||
|
||||
cmd->partial_activation = 0;
|
||||
|
||||
/* clean the pool for another command */
|
||||
dm_pool_empty(cmd->mem);
|
||||
init_test(0);
|
||||
pthread_mutex_unlock(&lvm_lock);
|
||||
|
||||
DEBUGLOG("Command return is %d, critical_section is %d\n", status, critical_section());
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Functions to do on the local node only BEFORE the cluster-wide stuff above happens */
|
||||
int pre_lock_lv(unsigned char command, unsigned char lock_flags, char *resource)
|
||||
{
|
||||
/* Nearly all the stuff happens cluster-wide. Apart from SUSPEND. Here we get the
|
||||
lock out on this node (because we are the node modifying the metadata)
|
||||
before suspending cluster-wide.
|
||||
LCKF_CONVERT is used always, local node is going to modify metadata
|
||||
*/
|
||||
if ((command & (LCK_SCOPE_MASK | LCK_TYPE_MASK)) == LCK_LV_SUSPEND &&
|
||||
(command & LCK_CLUSTER_VG)) {
|
||||
DEBUGLOG("pre_lock_lv: resource '%s', cmd = %s, flags = %s\n",
|
||||
resource, decode_locking_cmd(command), decode_flags(lock_flags));
|
||||
|
||||
if (!(lock_flags & LCK_TEST_MODE) &&
|
||||
hold_lock(resource, LCK_WRITE, LCKF_NOQUEUE | LCKF_CONVERT))
|
||||
return errno;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Functions to do on the local node only AFTER the cluster-wide stuff above happens */
|
||||
int post_lock_lv(unsigned char command, unsigned char lock_flags,
|
||||
char *resource)
|
||||
{
|
||||
int status;
|
||||
unsigned origin_only = (lock_flags & LCK_ORIGIN_ONLY_MODE) ? 1 : 0;
|
||||
|
||||
/* Opposite of above, done on resume after a metadata update */
|
||||
if ((command & (LCK_SCOPE_MASK | LCK_TYPE_MASK)) == LCK_LV_RESUME &&
|
||||
(command & LCK_CLUSTER_VG)) {
|
||||
int oldmode;
|
||||
|
||||
DEBUGLOG("post_lock_lv: resource '%s', cmd = %s, flags = %s\n",
|
||||
resource, decode_locking_cmd(command), decode_flags(lock_flags));
|
||||
|
||||
/* If the lock state is PW then restore it to what it was */
|
||||
oldmode = get_current_lock(resource);
|
||||
if (oldmode == LCK_WRITE) {
|
||||
struct lvinfo lvi;
|
||||
|
||||
pthread_mutex_lock(&lvm_lock);
|
||||
status = lv_info_by_lvid(cmd, resource, origin_only, &lvi, 0, 0);
|
||||
pthread_mutex_unlock(&lvm_lock);
|
||||
if (!status)
|
||||
return EIO;
|
||||
|
||||
if (!(lock_flags & LCK_TEST_MODE)) {
|
||||
if (lvi.exists) {
|
||||
if (hold_lock(resource, LCK_READ, LCKF_CONVERT))
|
||||
return errno;
|
||||
} else if (hold_unlock(resource))
|
||||
return errno;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_refresh_cache(void)
|
||||
{
|
||||
DEBUGLOG("Refreshing context\n");
|
||||
log_notice("Refreshing context");
|
||||
|
||||
pthread_mutex_lock(&lvm_lock);
|
||||
|
||||
if (!refresh_toolcontext(cmd)) {
|
||||
pthread_mutex_unlock(&lvm_lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
init_ignore_suspended_devices(1);
|
||||
lvmcache_label_scan(cmd);
|
||||
label_scan_destroy(cmd); /* destroys bcache (to close devs), keeps lvmcache */
|
||||
dm_pool_empty(cmd->mem);
|
||||
|
||||
pthread_mutex_unlock(&lvm_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle VG lock - drop metadata or update lvmcache state
|
||||
*/
|
||||
void do_lock_vg(unsigned char command, unsigned char lock_flags, char *resource)
|
||||
{
|
||||
uint32_t lock_cmd = command;
|
||||
char *vgname = resource + 2;
|
||||
|
||||
lock_cmd &= (LCK_SCOPE_MASK | LCK_TYPE_MASK | LCK_HOLD);
|
||||
|
||||
/*
|
||||
* Check if LCK_CACHE should be set. All P_ locks except # are cache related.
|
||||
*/
|
||||
if (strncmp(resource, "P_#", 3) && !strncmp(resource, "P_", 2))
|
||||
lock_cmd |= LCK_CACHE;
|
||||
|
||||
DEBUGLOG("do_lock_vg: resource '%s', cmd = %s, flags = %s, critical_section = %d\n",
|
||||
resource, decode_full_locking_cmd(lock_cmd), decode_flags(lock_flags), critical_section());
|
||||
|
||||
/* P_#global causes a full cache refresh */
|
||||
if (!strcmp(resource, "P_" VG_GLOBAL)) {
|
||||
do_refresh_cache();
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&lvm_lock);
|
||||
init_test((lock_flags & LCK_TEST_MODE) ? 1 : 0);
|
||||
|
||||
switch (lock_cmd) {
|
||||
case LCK_VG_COMMIT:
|
||||
DEBUGLOG("vg_commit notification for VG %s\n", vgname);
|
||||
lvmcache_commit_metadata(vgname);
|
||||
break;
|
||||
case LCK_VG_REVERT:
|
||||
DEBUGLOG("vg_revert notification for VG %s\n", vgname);
|
||||
lvmcache_drop_metadata(vgname, 1);
|
||||
break;
|
||||
case LCK_VG_DROP_CACHE:
|
||||
default:
|
||||
DEBUGLOG("Invalidating cached metadata for VG %s\n", vgname);
|
||||
lvmcache_drop_metadata(vgname, 0);
|
||||
}
|
||||
|
||||
init_test(0);
|
||||
pthread_mutex_unlock(&lvm_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Ideally, clvmd should be started before any LVs are active
|
||||
* but this may not be the case...
|
||||
* I suppose this also comes in handy if clvmd crashes, not that it would!
|
||||
*/
|
||||
static int get_initial_state(struct dm_hash_table *excl_uuid)
|
||||
{
|
||||
int lock_mode;
|
||||
char lv[65], vg[65], flags[26], vg_flags[26]; /* with space for '\0' */
|
||||
char uuid[65];
|
||||
char line[255];
|
||||
char *lvs_cmd;
|
||||
const char *lvm_binary = getenv("LVM_BINARY") ? : LVM_PATH;
|
||||
FILE *lvs;
|
||||
|
||||
if (dm_asprintf(&lvs_cmd, "%s lvs --config 'log{command_names=0 prefix=\"\"}' "
|
||||
"--nolocking --noheadings -o vg_uuid,lv_uuid,lv_attr,vg_attr",
|
||||
lvm_binary) < 0)
|
||||
return_0;
|
||||
|
||||
/* FIXME: Maybe link and use liblvm2cmd directly instead of fork */
|
||||
if (!(lvs = popen(lvs_cmd, "r"))) {
|
||||
dm_free(lvs_cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (fgets(line, sizeof(line), lvs)) {
|
||||
if (sscanf(line, "%64s %64s %25s %25s\n", vg, lv, flags, vg_flags) == 4) {
|
||||
|
||||
/* States: s:suspended a:active S:dropped snapshot I:invalid snapshot */
|
||||
if (strlen(vg) == 38 && /* is is a valid UUID ? */
|
||||
(flags[4] == 'a' || flags[4] == 's') && /* is it active or suspended? */
|
||||
vg_flags[5] == 'c') { /* is it clustered ? */
|
||||
/* Convert hyphen-separated UUIDs into one */
|
||||
memcpy(&uuid[0], &vg[0], 6);
|
||||
memcpy(&uuid[6], &vg[7], 4);
|
||||
memcpy(&uuid[10], &vg[12], 4);
|
||||
memcpy(&uuid[14], &vg[17], 4);
|
||||
memcpy(&uuid[18], &vg[22], 4);
|
||||
memcpy(&uuid[22], &vg[27], 4);
|
||||
memcpy(&uuid[26], &vg[32], 6);
|
||||
memcpy(&uuid[32], &lv[0], 6);
|
||||
memcpy(&uuid[38], &lv[7], 4);
|
||||
memcpy(&uuid[42], &lv[12], 4);
|
||||
memcpy(&uuid[46], &lv[17], 4);
|
||||
memcpy(&uuid[50], &lv[22], 4);
|
||||
memcpy(&uuid[54], &lv[27], 4);
|
||||
memcpy(&uuid[58], &lv[32], 6);
|
||||
uuid[64] = '\0';
|
||||
|
||||
/* Look for this lock in the list of EX locks
|
||||
we were passed on the command-line */
|
||||
lock_mode = (dm_hash_lookup(excl_uuid, uuid)) ?
|
||||
LCK_EXCL : LCK_READ;
|
||||
|
||||
DEBUGLOG("getting initial lock for %s\n", uuid);
|
||||
if (hold_lock(uuid, lock_mode, LCKF_NOQUEUE))
|
||||
DEBUGLOG("Failed to hold lock %s\n", uuid);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pclose(lvs))
|
||||
DEBUGLOG("lvs pclose failed: %s\n", strerror(errno));
|
||||
|
||||
dm_free(lvs_cmd);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void lvm2_log_fn(int level, const char *file, int line, int dm_errno,
|
||||
const char *message)
|
||||
{
|
||||
|
||||
/* Send messages to the normal LVM2 logging system too,
|
||||
so we get debug output when it's asked for.
|
||||
We need to NULL the function ptr otherwise it will just call
|
||||
back into here! */
|
||||
init_log_fn(NULL);
|
||||
print_log(level, file, line, dm_errno, "%s", message);
|
||||
init_log_fn(lvm2_log_fn);
|
||||
|
||||
/*
|
||||
* Ignore non-error messages, but store the latest one for returning
|
||||
* to the user.
|
||||
*/
|
||||
if (level != _LOG_ERR && level != _LOG_FATAL)
|
||||
return;
|
||||
|
||||
(void) dm_strncpy(last_error, message, sizeof(last_error));
|
||||
}
|
||||
|
||||
/* This checks some basic cluster-LVM configuration stuff */
|
||||
static void check_config(void)
|
||||
{
|
||||
int locking_type;
|
||||
|
||||
locking_type = find_config_tree_int(cmd, global_locking_type_CFG, NULL);
|
||||
|
||||
if (locking_type == 3) /* compiled-in cluster support */
|
||||
return;
|
||||
|
||||
if (locking_type == 2) { /* External library, check name */
|
||||
const char *libname;
|
||||
|
||||
libname = find_config_tree_str(cmd, global_locking_library_CFG, NULL);
|
||||
if (libname && strstr(libname, "liblvm2clusterlock.so"))
|
||||
return;
|
||||
|
||||
log_error("Incorrect LVM locking library specified in lvm.conf, cluster operations may not work.");
|
||||
return;
|
||||
}
|
||||
log_error("locking_type not set correctly in lvm.conf, cluster operations will not work.");
|
||||
}
|
||||
|
||||
/* Backups up the LVM metadata if it's changed */
|
||||
void lvm_do_backup(const char *vgname)
|
||||
{
|
||||
struct volume_group * vg;
|
||||
int consistent = 0;
|
||||
|
||||
DEBUGLOG("Triggering backup of VG metadata for %s.\n", vgname);
|
||||
|
||||
pthread_mutex_lock(&lvm_lock);
|
||||
|
||||
vg = vg_read_internal(cmd, vgname, NULL /*vgid*/, 0, WARN_PV_READ, &consistent);
|
||||
|
||||
if (vg && consistent)
|
||||
check_current_backup(vg);
|
||||
else
|
||||
log_error("Error backing up metadata, can't find VG for group %s", vgname);
|
||||
|
||||
release_vg(vg);
|
||||
dm_pool_empty(cmd->mem);
|
||||
|
||||
pthread_mutex_unlock(&lvm_lock);
|
||||
}
|
||||
|
||||
struct dm_hash_node *get_next_excl_lock(struct dm_hash_node *v, char **name)
|
||||
{
|
||||
struct lv_info *lvi;
|
||||
|
||||
*name = NULL;
|
||||
if (!v)
|
||||
v = dm_hash_get_first(lv_hash);
|
||||
|
||||
do {
|
||||
if (v) {
|
||||
lvi = dm_hash_get_data(lv_hash, v);
|
||||
DEBUGLOG("Looking for EX locks. found %x mode %d\n", lvi->lock_id, lvi->lock_mode);
|
||||
|
||||
if (lvi->lock_mode == LCK_EXCL) {
|
||||
*name = dm_hash_get_key(lv_hash, v);
|
||||
}
|
||||
v = dm_hash_get_next(lv_hash, v);
|
||||
}
|
||||
} while (v && !*name);
|
||||
|
||||
if (*name)
|
||||
DEBUGLOG("returning EXclusive UUID %s\n", *name);
|
||||
return v;
|
||||
}
|
||||
|
||||
void lvm_do_fs_unlock(void)
|
||||
{
|
||||
pthread_mutex_lock(&lvm_lock);
|
||||
DEBUGLOG("Syncing device names\n");
|
||||
fs_unlock();
|
||||
pthread_mutex_unlock(&lvm_lock);
|
||||
}
|
||||
|
||||
/* Called to initialise the LVM context of the daemon */
|
||||
int init_clvm(struct dm_hash_table *excl_uuid)
|
||||
{
|
||||
/* Use LOG_DAEMON for syslog messages instead of LOG_USER */
|
||||
init_syslog(LOG_DAEMON);
|
||||
openlog("clvmd", LOG_PID, LOG_DAEMON);
|
||||
|
||||
/* Initialise already held locks */
|
||||
if (!get_initial_state(excl_uuid))
|
||||
log_error("Cannot load initial lock states.");
|
||||
|
||||
if (!udev_init_library_context())
|
||||
stack;
|
||||
|
||||
if (!(cmd = create_toolcontext(1, NULL, 0, 1, 1, 1))) {
|
||||
log_error("Failed to allocate command context");
|
||||
udev_fin_library_context();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (stored_errno()) {
|
||||
destroy_toolcontext(cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
cmd->cmd_line = "clvmd";
|
||||
|
||||
/* Check lvm.conf is setup for cluster-LVM */
|
||||
check_config();
|
||||
init_ignore_suspended_devices(1);
|
||||
|
||||
/* Trap log messages so we can pass them back to the user */
|
||||
init_log_fn(lvm2_log_fn);
|
||||
memlock_inc_daemon(cmd);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void destroy_lvm(void)
|
||||
{
|
||||
if (cmd) {
|
||||
memlock_dec_daemon(cmd);
|
||||
destroy_toolcontext(cmd);
|
||||
udev_fin_library_context();
|
||||
cmd = NULL;
|
||||
}
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2010 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/* Functions in lvm-functions.c */
|
||||
|
||||
#ifndef _LVM_FUNCTIONS_H
|
||||
#define _LVM_FUNCTIONS_H
|
||||
|
||||
extern int pre_lock_lv(unsigned char lock_cmd, unsigned char lock_flags,
|
||||
char *resource);
|
||||
extern int do_lock_lv(unsigned char lock_cmd, unsigned char lock_flags,
|
||||
char *resource);
|
||||
extern const char *do_lock_query(char *resource);
|
||||
extern int post_lock_lv(unsigned char lock_cmd, unsigned char lock_flags,
|
||||
char *resource);
|
||||
extern int do_refresh_cache(void);
|
||||
extern int init_clvm(struct dm_hash_table *excl_uuid);
|
||||
extern void destroy_lvm(void);
|
||||
extern void init_lvhash(void);
|
||||
extern void destroy_lvhash(void);
|
||||
extern void lvm_do_backup(const char *vgname);
|
||||
extern char *get_last_lvm_error(void);
|
||||
extern void do_lock_vg(unsigned char command, unsigned char lock_flags,
|
||||
char *resource);
|
||||
extern struct dm_hash_node *get_next_excl_lock(struct dm_hash_node *v, char **name);
|
||||
void lvm_do_fs_unlock(void);
|
||||
|
||||
#endif
|
@ -1,382 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2010 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/* FIXME Remove duplicated functions from this file. */
|
||||
|
||||
/*
|
||||
* Send a command to a running clvmd from the command-line
|
||||
*/
|
||||
|
||||
#include "clvmd-common.h"
|
||||
|
||||
#include "daemons/clvmd/clvm.h"
|
||||
#include "refresh_clvmd.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
typedef struct lvm_response {
|
||||
char node[255];
|
||||
char *response;
|
||||
int status;
|
||||
int len;
|
||||
} lvm_response_t;
|
||||
|
||||
/*
|
||||
* This gets stuck at the start of memory we allocate so we
|
||||
* can sanity-check it at deallocation time
|
||||
*/
|
||||
#define LVM_SIGNATURE 0x434C564D
|
||||
|
||||
static int _clvmd_sock = -1;
|
||||
|
||||
/* Open connection to the clvm daemon */
|
||||
static int _open_local_sock(void)
|
||||
{
|
||||
int local_socket;
|
||||
struct sockaddr_un sockaddr = { .sun_family = AF_UNIX };
|
||||
|
||||
if (!dm_strncpy(sockaddr.sun_path, CLVMD_SOCKNAME, sizeof(sockaddr.sun_path))) {
|
||||
fprintf(stderr, "%s: clvmd socket name too long.", CLVMD_SOCKNAME);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Open local socket */
|
||||
if ((local_socket = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
|
||||
fprintf(stderr, "Local socket creation failed: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (connect(local_socket,(struct sockaddr *) &sockaddr,
|
||||
sizeof(sockaddr))) {
|
||||
int saved_errno = errno;
|
||||
|
||||
fprintf(stderr, "connect() failed on local socket: %s\n",
|
||||
strerror(errno));
|
||||
if (close(local_socket))
|
||||
return -1;
|
||||
|
||||
errno = saved_errno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return local_socket;
|
||||
}
|
||||
|
||||
/* Send a request and return the status */
|
||||
static int _send_request(const char *inbuf, int inlen, char **retbuf, int no_response)
|
||||
{
|
||||
char outbuf[PIPE_BUF];
|
||||
struct clvm_header *outheader = (struct clvm_header *) outbuf;
|
||||
int len;
|
||||
unsigned off;
|
||||
int buflen;
|
||||
int err;
|
||||
|
||||
/* Send it to CLVMD */
|
||||
rewrite:
|
||||
if ( (err = write(_clvmd_sock, inbuf, inlen)) != inlen) {
|
||||
if (err == -1 && errno == EINTR)
|
||||
goto rewrite;
|
||||
fprintf(stderr, "Error writing data to clvmd: %s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
if (no_response)
|
||||
return 1;
|
||||
|
||||
/* Get the response */
|
||||
reread:
|
||||
if ((len = read(_clvmd_sock, outbuf, sizeof(struct clvm_header))) < 0) {
|
||||
if (errno == EINTR)
|
||||
goto reread;
|
||||
fprintf(stderr, "Error reading data from clvmd: %s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
fprintf(stderr, "EOF reading CLVMD");
|
||||
errno = ENOTCONN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Allocate buffer */
|
||||
buflen = len + outheader->arglen;
|
||||
*retbuf = dm_malloc(buflen);
|
||||
if (!*retbuf) {
|
||||
errno = ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Copy the header */
|
||||
memcpy(*retbuf, outbuf, len);
|
||||
outheader = (struct clvm_header *) *retbuf;
|
||||
|
||||
/* Read the returned values */
|
||||
off = 1; /* we've already read the first byte */
|
||||
while (off <= outheader->arglen && len > 0) {
|
||||
len = read(_clvmd_sock, outheader->args + off,
|
||||
buflen - off - offsetof(struct clvm_header, args));
|
||||
if (len > 0)
|
||||
off += len;
|
||||
}
|
||||
|
||||
/* Was it an error ? */
|
||||
if (outheader->status != 0) {
|
||||
errno = outheader->status;
|
||||
|
||||
/* Only return an error here if there are no node-specific
|
||||
errors present in the message that might have more detail */
|
||||
if (!(outheader->flags & CLVMD_FLAG_NODEERRS)) {
|
||||
fprintf(stderr, "cluster request failed: %s\n", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Build the structure header and parse-out wildcard node names */
|
||||
static void _build_header(struct clvm_header *head, int cmd, const char *node,
|
||||
unsigned int len)
|
||||
{
|
||||
head->cmd = cmd;
|
||||
head->status = 0;
|
||||
head->flags = 0;
|
||||
head->xid = 0;
|
||||
head->clientid = 0;
|
||||
if (len)
|
||||
/* 1 byte is used from struct clvm_header.args[1], so -> len - 1 */
|
||||
head->arglen = len - 1;
|
||||
else {
|
||||
head->arglen = 0;
|
||||
*head->args = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* Translate special node names.
|
||||
*/
|
||||
if (!node || !strcmp(node, NODE_ALL))
|
||||
head->node[0] = '\0';
|
||||
else if (!strcmp(node, NODE_LOCAL)) {
|
||||
head->node[0] = '\0';
|
||||
head->flags = CLVMD_FLAG_LOCAL;
|
||||
} else
|
||||
strcpy(head->node, node);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a message to a(or all) node(s) in the cluster and wait for replies
|
||||
*/
|
||||
static int _cluster_request(char cmd, const char *node, void *data, int len,
|
||||
lvm_response_t ** response, int *num, int no_response)
|
||||
{
|
||||
char outbuf[sizeof(struct clvm_header) + len + strlen(node) + 1];
|
||||
char *inptr;
|
||||
char *retbuf = NULL;
|
||||
int status;
|
||||
int i;
|
||||
int num_responses = 0;
|
||||
struct clvm_header *head = (struct clvm_header *) outbuf;
|
||||
lvm_response_t *rarray;
|
||||
|
||||
*num = 0;
|
||||
|
||||
if (_clvmd_sock == -1)
|
||||
_clvmd_sock = _open_local_sock();
|
||||
|
||||
if (_clvmd_sock == -1)
|
||||
return 0;
|
||||
|
||||
_build_header(head, cmd, node, len);
|
||||
if (len)
|
||||
memcpy(head->node + strlen(head->node) + 1, data, len);
|
||||
|
||||
status = _send_request(outbuf, sizeof(struct clvm_header) +
|
||||
strlen(head->node) + len, &retbuf, no_response);
|
||||
if (!status || no_response)
|
||||
goto out;
|
||||
|
||||
/* Count the number of responses we got */
|
||||
head = (struct clvm_header *) retbuf;
|
||||
inptr = head->args;
|
||||
while (inptr[0]) {
|
||||
num_responses++;
|
||||
inptr += strlen(inptr) + 1;
|
||||
inptr += sizeof(int);
|
||||
inptr += strlen(inptr) + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate response array.
|
||||
* With an extra pair of INTs on the front to sanity
|
||||
* check the pointer when we are given it back to free
|
||||
*/
|
||||
*response = NULL;
|
||||
if (!(rarray = dm_malloc(sizeof(lvm_response_t) * num_responses +
|
||||
sizeof(int) * 2))) {
|
||||
errno = ENOMEM;
|
||||
status = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Unpack the response into an lvm_response_t array */
|
||||
inptr = head->args;
|
||||
i = 0;
|
||||
while (inptr[0]) {
|
||||
strcpy(rarray[i].node, inptr);
|
||||
inptr += strlen(inptr) + 1;
|
||||
|
||||
memcpy(&rarray[i].status, inptr, sizeof(int));
|
||||
inptr += sizeof(int);
|
||||
|
||||
rarray[i].response = dm_malloc(strlen(inptr) + 1);
|
||||
if (rarray[i].response == NULL) {
|
||||
/* Free up everything else and return error */
|
||||
int j;
|
||||
for (j = 0; j < i; j++)
|
||||
dm_free(rarray[i].response);
|
||||
dm_free(rarray);
|
||||
errno = ENOMEM;
|
||||
status = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
strcpy(rarray[i].response, inptr);
|
||||
rarray[i].len = strlen(inptr);
|
||||
inptr += strlen(inptr) + 1;
|
||||
i++;
|
||||
}
|
||||
*num = num_responses;
|
||||
*response = rarray;
|
||||
|
||||
out:
|
||||
dm_free(retbuf);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Free reply array */
|
||||
static int _cluster_free_request(lvm_response_t * response, int num)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
dm_free(response[i].response);
|
||||
}
|
||||
|
||||
dm_free(response);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int refresh_clvmd(int all_nodes)
|
||||
{
|
||||
int num_responses;
|
||||
char args[1]; // No args really.
|
||||
lvm_response_t *response = NULL;
|
||||
int saved_errno;
|
||||
int status;
|
||||
int i;
|
||||
|
||||
status = _cluster_request(CLVMD_CMD_REFRESH, all_nodes ? NODE_ALL : NODE_LOCAL, args, 0, &response, &num_responses, 0);
|
||||
|
||||
/* If any nodes were down then display them and return an error */
|
||||
for (i = 0; i < num_responses; i++) {
|
||||
if (response[i].status == EHOSTDOWN) {
|
||||
fprintf(stderr, "clvmd not running on node %s",
|
||||
response[i].node);
|
||||
status = 0;
|
||||
errno = response[i].status;
|
||||
} else if (response[i].status) {
|
||||
fprintf(stderr, "Error resetting node %s: %s",
|
||||
response[i].node,
|
||||
response[i].response[0] ?
|
||||
response[i].response :
|
||||
strerror(response[i].status));
|
||||
status = 0;
|
||||
errno = response[i].status;
|
||||
}
|
||||
}
|
||||
|
||||
saved_errno = errno;
|
||||
_cluster_free_request(response, num_responses);
|
||||
errno = saved_errno;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int restart_clvmd(int all_nodes)
|
||||
{
|
||||
int dummy, status;
|
||||
|
||||
status = _cluster_request(CLVMD_CMD_RESTART, all_nodes ? NODE_ALL : NODE_LOCAL, NULL, 0, NULL, &dummy, 1);
|
||||
|
||||
/*
|
||||
* FIXME: we cannot receive response, clvmd re-exec before it.
|
||||
* but also should not close socket too early (the whole rq is dropped then).
|
||||
* FIXME: This should be handled this way:
|
||||
* - client waits for RESTART ack (and socket close)
|
||||
* - server restarts
|
||||
* - client checks that server is ready again (VERSION command?)
|
||||
*/
|
||||
usleep(500000);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int debug_clvmd(int level, int clusterwide)
|
||||
{
|
||||
int num_responses;
|
||||
char args[1];
|
||||
const char *nodes;
|
||||
lvm_response_t *response = NULL;
|
||||
int saved_errno;
|
||||
int status;
|
||||
int i;
|
||||
|
||||
args[0] = level;
|
||||
if (clusterwide)
|
||||
nodes = NODE_ALL;
|
||||
else
|
||||
nodes = NODE_LOCAL;
|
||||
|
||||
status = _cluster_request(CLVMD_CMD_SET_DEBUG, nodes, args, 1, &response, &num_responses, 0);
|
||||
|
||||
/* If any nodes were down then display them and return an error */
|
||||
for (i = 0; i < num_responses; i++) {
|
||||
if (response[i].status == EHOSTDOWN) {
|
||||
fprintf(stderr, "clvmd not running on node %s",
|
||||
response[i].node);
|
||||
status = 0;
|
||||
errno = response[i].status;
|
||||
} else if (response[i].status) {
|
||||
fprintf(stderr, "Error setting debug on node %s: %s",
|
||||
response[i].node,
|
||||
response[i].response[0] ?
|
||||
response[i].response :
|
||||
strerror(response[i].status));
|
||||
status = 0;
|
||||
errno = response[i].status;
|
||||
}
|
||||
}
|
||||
|
||||
saved_errno = errno;
|
||||
_cluster_free_request(response, num_responses);
|
||||
errno = saved_errno;
|
||||
|
||||
return status;
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
int refresh_clvmd(int all_nodes);
|
||||
int restart_clvmd(int all_nodes);
|
||||
int debug_clvmd(int level, int clusterwide);
|
||||
|
@ -17,8 +17,6 @@ top_builddir = @top_builddir@
|
||||
|
||||
CPG_LIBS = @CPG_LIBS@
|
||||
CPG_CFLAGS = @CPG_CFLAGS@
|
||||
SACKPT_LIBS = @SACKPT_LIBS@
|
||||
SACKPT_CFLAGS = @SACKPT_CFLAGS@
|
||||
|
||||
SOURCES = clogd.c cluster.c compat.c functions.c link_mon.c local.c logging.c
|
||||
|
||||
@ -26,8 +24,8 @@ TARGETS = cmirrord
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
LMLIBS += $(CPG_LIBS) $(SACKPT_LIBS)
|
||||
CFLAGS += $(CPG_CFLAGS) $(SACKPT_CFLAGS) $(EXTRA_EXEC_CFLAGS)
|
||||
LMLIBS += $(CPG_LIBS)
|
||||
CFLAGS += $(CPG_CFLAGS) $(EXTRA_EXEC_CFLAGS)
|
||||
LDFLAGS += $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS)
|
||||
|
||||
cmirrord: $(OBJECTS) $(top_builddir)/lib/liblvm-internal.a
|
||||
|
@ -18,6 +18,9 @@
|
||||
#include "local.h"
|
||||
#include "lib/mm/xlate.h"
|
||||
|
||||
/* FIXME: remove this and the code */
|
||||
#define CMIRROR_HAS_CHECKPOINT 0
|
||||
|
||||
#include <corosync/cpg.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
|
@ -25,15 +25,6 @@
|
||||
/* Define to 1 if the `closedir' function returns void instead of `int'. */
|
||||
#undef CLOSEDIR_VOID
|
||||
|
||||
/* Define to 1 to include built-in support for clustered LVM locking. */
|
||||
#undef CLUSTER_LOCKING_INTERNAL
|
||||
|
||||
/* Path to clvmd binary. */
|
||||
#undef CLVMD_PATH
|
||||
|
||||
/* Path to clvmd pidfile. */
|
||||
#undef CLVMD_PIDFILE
|
||||
|
||||
/* Path to cmirrord pidfile. */
|
||||
#undef CMIRRORD_PIDFILE
|
||||
|
||||
@ -178,12 +169,6 @@
|
||||
/* Define to 1 if you have the `clock_gettime' function. */
|
||||
#undef HAVE_CLOCK_GETTIME
|
||||
|
||||
/* Define to 1 if you have the <corosync/cmap.h> header file. */
|
||||
#undef HAVE_COROSYNC_CMAP_H
|
||||
|
||||
/* Define to 1 if you have the <corosync/confdb.h> header file. */
|
||||
#undef HAVE_COROSYNC_CONFDB_H
|
||||
|
||||
/* Define to 1 if you have the <ctype.h> header file. */
|
||||
#undef HAVE_CTYPE_H
|
||||
|
||||
@ -248,9 +233,6 @@
|
||||
/* Define to 1 if you have the <libaio.h> header file. */
|
||||
#undef HAVE_LIBAIO_H
|
||||
|
||||
/* Define to 1 if you have the <libcman.h> header file. */
|
||||
#undef HAVE_LIBCMAN_H
|
||||
|
||||
/* Define to 1 if dynamic libraries are available. */
|
||||
#undef HAVE_LIBDL
|
||||
|
||||
|
@ -16,10 +16,6 @@ srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
top_builddir = @top_builddir@
|
||||
|
||||
ifeq ("@CLUSTER@", "shared")
|
||||
SUBDIRS += locking
|
||||
endif
|
||||
|
||||
SOURCES =\
|
||||
activate/activate.c \
|
||||
cache/lvmcache.c \
|
||||
@ -66,7 +62,6 @@ SOURCES =\
|
||||
label/label.c \
|
||||
locking/file_locking.c \
|
||||
locking/locking.c \
|
||||
locking/no_locking.c \
|
||||
log/log.c \
|
||||
metadata/cache_manip.c \
|
||||
metadata/lv.c \
|
||||
@ -107,10 +102,6 @@ SOURCES =\
|
||||
uuid/uuid.c \
|
||||
zero/zero.c
|
||||
|
||||
ifeq ("@CLUSTER@", "internal")
|
||||
SOURCES += locking/cluster_locking.c
|
||||
endif
|
||||
|
||||
ifeq ("@DEVMAPPER@", "yes")
|
||||
SOURCES +=\
|
||||
activate/dev_manager.c \
|
||||
@ -118,9 +109,7 @@ ifeq ("@DEVMAPPER@", "yes")
|
||||
endif
|
||||
|
||||
ifeq ("@HAVE_LIBDL@", "yes")
|
||||
SOURCES +=\
|
||||
locking/external_locking.c \
|
||||
misc/sharedlib.c
|
||||
SOURCES += misc/sharedlib.c
|
||||
endif
|
||||
|
||||
ifeq ("@BUILD_LVMETAD@", "yes")
|
||||
|
@ -669,9 +669,7 @@ static int _lv_info(struct cmd_context *cmd, const struct logical_volume *lv,
|
||||
* in progress - as only those could lead to opened files
|
||||
*/
|
||||
if (with_open_count) {
|
||||
if (locking_is_clustered() && !sync_local_dev_names(cmd)) /* Wait to have udev in sync */
|
||||
return_0;
|
||||
else if (fs_has_non_delete_ops())
|
||||
if (fs_has_non_delete_ops())
|
||||
fs_unlock(); /* For non clustered - wait if there are non-delete ops */
|
||||
}
|
||||
|
||||
@ -724,21 +722,6 @@ int lv_info(struct cmd_context *cmd, const struct logical_volume *lv, int use_la
|
||||
return _lv_info(cmd, lv, use_layer, info, NULL, NULL, with_open_count, with_read_ahead);
|
||||
}
|
||||
|
||||
int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, int use_layer,
|
||||
struct lvinfo *info, int with_open_count, int with_read_ahead)
|
||||
{
|
||||
int r;
|
||||
struct logical_volume *lv;
|
||||
|
||||
if (!(lv = lv_from_lvid(cmd, lvid_s, 0)))
|
||||
return 0;
|
||||
|
||||
r = lv_info(cmd, lv, use_layer, info, with_open_count, with_read_ahead);
|
||||
release_vg(lv->vg);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns 1 if lv_with_info_and_seg_status info structure populated,
|
||||
* else 0 on failure or if device not active locally.
|
||||
@ -1521,47 +1504,9 @@ static int _lv_is_active(const struct logical_volume *lv,
|
||||
if (_lv_active(lv->vg->cmd, lv))
|
||||
l = 1;
|
||||
|
||||
if (!vg_is_clustered(lv->vg)) {
|
||||
if (l)
|
||||
e = 1; /* exclusive by definition */
|
||||
goto out;
|
||||
}
|
||||
if (l)
|
||||
e = 1; /* exclusive by definition */
|
||||
|
||||
/* Active locally, and the caller doesn't care about exclusive or remotely */
|
||||
if (l && !exclusive && !remotely)
|
||||
skip_cluster_query = 1;
|
||||
|
||||
if (skip_cluster_query)
|
||||
goto out;
|
||||
|
||||
if ((r = cluster_lock_held(lv->lvid.s, "", &e)) >= 0) {
|
||||
if (l && e)
|
||||
r = 0; /* exclusive locally */
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* If lock query is not supported (due to interfacing with old
|
||||
* code), then we cannot evaluate exclusivity properly.
|
||||
*
|
||||
* Old users of this function will never be affected by this,
|
||||
* since they are only concerned about active vs. not active.
|
||||
* New users of this function who specifically ask for 'exclusive'
|
||||
* will be given a warning message.
|
||||
*/
|
||||
log_warn("WARNING: Unable to determine exclusivity of %s.", display_lvname(lv));
|
||||
|
||||
e = 0;
|
||||
|
||||
/* Also set remotely as a precaution, as we don't know */
|
||||
r = 1;
|
||||
|
||||
/*
|
||||
* We used to attempt activate_lv_excl_local(lv->vg->cmd, lv) here,
|
||||
* but it's unreliable.
|
||||
*/
|
||||
|
||||
out:
|
||||
if (locally)
|
||||
*locally = l;
|
||||
if (exclusive)
|
||||
@ -2146,75 +2091,11 @@ static int _lv_suspend(struct cmd_context *cmd, const char *lvid_s,
|
||||
struct dm_pool *mem = NULL;
|
||||
struct dm_list suspend_lvs;
|
||||
struct lv_list *lvl;
|
||||
const union lvid *lvid = (const union lvid *) lvid_s;
|
||||
const char *vgid = (const char *)lvid->id[0].uuid;
|
||||
struct volume_group *vg;
|
||||
struct volume_group *vg_pre;
|
||||
int found;
|
||||
|
||||
if (!activation())
|
||||
return 1;
|
||||
|
||||
if (!cmd->is_clvmd)
|
||||
goto skip_read;
|
||||
|
||||
if (lv && lv_pre)
|
||||
goto skip_read;
|
||||
|
||||
if (!(vg = lvmcache_get_saved_vg(vgid, 0))) {
|
||||
log_debug("lv_suspend did not find saved_vg %.8s so reading", vgid);
|
||||
if (!(vg = vg_read_by_vgid(cmd, vgid, 0))) {
|
||||
log_error("lv_suspend could not read vgid %.8s", vgid);
|
||||
goto out;
|
||||
}
|
||||
log_debug("lv_suspend using read vg %s %d %p", vg->name, vg->seqno, vg);
|
||||
} else {
|
||||
log_debug("lv_suspend using saved_vg %s %d %p", vg->name, vg->seqno, vg);
|
||||
}
|
||||
|
||||
if (!(vg_pre = lvmcache_get_saved_vg(vgid, 1))) {
|
||||
log_debug("lv_suspend did not find pre saved_vg %.8s so reading", vgid);
|
||||
if (!(vg_pre = vg_read_by_vgid(cmd, vgid, 1))) {
|
||||
log_error("lv_suspend could not read pre vgid %.8s", vgid);
|
||||
goto out;
|
||||
}
|
||||
log_debug("lv_suspend using pre read vg %s %d %p", vg_pre->name, vg_pre->seqno, vg_pre);
|
||||
} else {
|
||||
log_debug("lv_suspend using pre saved_vg %s %d %p", vg_pre->name, vg_pre->seqno, vg_pre);
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that vg and vg_pre returned by vg_read_by_vgid will
|
||||
* not be the same as saved_vg_old/saved_vg_new that would
|
||||
* be returned by lvmcache_get_saved_vg() because the saved_vg's
|
||||
* are copies of the vg struct that is created by _vg_read.
|
||||
* (Should we grab and use the saved_vg to use here instead of
|
||||
* the vg returned by vg_read_by_vgid?)
|
||||
*/
|
||||
|
||||
if ((vg->status & EXPORTED_VG) || (vg_pre->status & EXPORTED_VG)) {
|
||||
log_error("Volume group \"%s\" is exported", vg->name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
lv = lv_to_free = find_lv_in_vg_by_lvid(vg, lvid);
|
||||
lv_pre = lv_pre_to_free = find_lv_in_vg_by_lvid(vg_pre, lvid);
|
||||
|
||||
if (!lv || !lv_pre) {
|
||||
log_error("lv_suspend could not find lv %p lv_pre %p vg %p vg_pre %p vgid %s",
|
||||
lv, lv_pre, vg, vg_pre, vgid);
|
||||
goto out;
|
||||
}
|
||||
|
||||
skip_read:
|
||||
/* lv comes from committed metadata */
|
||||
if (!lv && !(lv_to_free = lv = lv_from_lvid(cmd, lvid_s, 0)))
|
||||
goto_out;
|
||||
|
||||
/* Use precommitted metadata if present */
|
||||
if (!lv_pre && !(lv_pre_to_free = lv_pre = lv_from_lvid(cmd, lvid_s, 1)))
|
||||
goto_out;
|
||||
|
||||
/* Ignore origin_only unless LV is origin in both old and new metadata */
|
||||
/* or LV is thin or thin pool volume */
|
||||
if (!lv_is_thin_volume(lv) && !lv_is_thin_pool(lv) &&
|
||||
@ -2231,19 +2112,6 @@ skip_read:
|
||||
if (!lv_info(cmd, lv, laopts->origin_only, &info, 0, 0))
|
||||
goto_out;
|
||||
|
||||
/*
|
||||
* Save old and new (current and precommitted) versions of the
|
||||
* VG metadata for lv_resume() to use, since lv_resume can't
|
||||
* read metadata given that devices are suspended. lv_resume()
|
||||
* will resume LVs using the old/current metadata if the vg_commit
|
||||
* did happen (or failed), and it will resume LVs using the
|
||||
* new/precommitted metadata if the vg_commit succeeded.
|
||||
*/
|
||||
if (cmd->is_clvmd) {
|
||||
lvmcache_save_vg(lv->vg, 0);
|
||||
lvmcache_save_vg(lv_pre->vg, 1);
|
||||
}
|
||||
|
||||
if (!info.exists || info.suspended) {
|
||||
if (!error_if_not_suspended) {
|
||||
r = 1;
|
||||
@ -2451,55 +2319,12 @@ static int _lv_resume(struct cmd_context *cmd, const char *lvid_s,
|
||||
const struct logical_volume *lv)
|
||||
{
|
||||
struct dm_list *snh;
|
||||
struct volume_group *vg = NULL;
|
||||
struct logical_volume *lv_found = NULL;
|
||||
const union lvid *lvid;
|
||||
const char *vgid;
|
||||
struct lvinfo info;
|
||||
int r = 0;
|
||||
|
||||
if (!activation())
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* When called in clvmd, lvid_s is set and lv is not. We need to
|
||||
* get the VG metadata without reading disks because devs are
|
||||
* suspended. lv_suspend() saved old and new VG metadata for us
|
||||
* to use here. If vg_commit() happened, lvmcache_get_saved_vg_latest
|
||||
* will return the new metadata for us to use in resuming LVs.
|
||||
* If vg_commit() did not happen, lvmcache_get_saved_vg_latest
|
||||
* returns the old metadata which we use to resume LVs.
|
||||
*/
|
||||
if (!lv && lvid_s) {
|
||||
lvid = (const union lvid *) lvid_s;
|
||||
vgid = (const char *)lvid->id[0].uuid;
|
||||
|
||||
if ((vg = lvmcache_get_saved_vg_latest(vgid))) {
|
||||
log_debug_activation("Resuming LVID %s found saved vg seqno %d %s", lvid_s, vg->seqno, vg->name);
|
||||
if ((lv_found = find_lv_in_vg_by_lvid(vg, lvid))) {
|
||||
log_debug_activation("Resuming LVID %s found saved LV %s", lvid_s, display_lvname(lv_found));
|
||||
lv = lv_found;
|
||||
} else
|
||||
log_debug_activation("Resuming LVID %s did not find saved LV", lvid_s);
|
||||
} else
|
||||
log_debug_activation("Resuming LVID %s did not find saved VG", lvid_s);
|
||||
|
||||
/*
|
||||
* resume must have been called without a preceding suspend,
|
||||
* so we need to read the vg.
|
||||
*/
|
||||
|
||||
if (!lv) {
|
||||
log_debug_activation("Resuming LVID %s reading VG", lvid_s);
|
||||
if (!(lv_found = lv_from_lvid(cmd, lvid_s, 0))) {
|
||||
log_debug_activation("Resuming LVID %s failed to read VG", lvid_s);
|
||||
goto out;
|
||||
}
|
||||
|
||||
lv = lv_found;
|
||||
}
|
||||
}
|
||||
|
||||
if (!lv_is_origin(lv) && !lv_is_thin_volume(lv) && !lv_is_thin_pool(lv))
|
||||
laopts->origin_only = 0;
|
||||
|
||||
@ -2620,9 +2445,6 @@ int lv_deactivate(struct cmd_context *cmd, const char *lvid_s, const struct logi
|
||||
if (!activation())
|
||||
return 1;
|
||||
|
||||
if (!lv && !(lv_to_free = lv = lv_from_lvid(cmd, lvid_s, 0)))
|
||||
goto out;
|
||||
|
||||
if (test_mode()) {
|
||||
_skip("Deactivating %s.", display_lvname(lv));
|
||||
r = 1;
|
||||
@ -2694,45 +2516,31 @@ out:
|
||||
int lv_activation_filter(struct cmd_context *cmd, const char *lvid_s,
|
||||
int *activate_lv, const struct logical_volume *lv)
|
||||
{
|
||||
const struct logical_volume *lv_to_free = NULL;
|
||||
int r = 0;
|
||||
|
||||
if (!activation()) {
|
||||
*activate_lv = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!lv && !(lv_to_free = lv = lv_from_lvid(cmd, lvid_s, 0)))
|
||||
goto_out;
|
||||
|
||||
if (!_passes_activation_filter(cmd, lv)) {
|
||||
log_verbose("Not activating %s since it does not pass "
|
||||
"activation filter.", display_lvname(lv));
|
||||
*activate_lv = 0;
|
||||
} else
|
||||
*activate_lv = 1;
|
||||
r = 1;
|
||||
out:
|
||||
if (lv_to_free)
|
||||
release_vg(lv_to_free->vg);
|
||||
|
||||
return r;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
|
||||
struct lv_activate_opts *laopts, int filter,
|
||||
const struct logical_volume *lv)
|
||||
{
|
||||
const struct logical_volume *lv_to_free = NULL;
|
||||
struct lvinfo info;
|
||||
int r = 0;
|
||||
|
||||
if (!activation())
|
||||
return 1;
|
||||
|
||||
if (!lv && !(lv_to_free = lv = lv_from_lvid(cmd, lvid_s, 0)))
|
||||
goto out;
|
||||
|
||||
if (!laopts->exclusive &&
|
||||
(lv_is_origin(lv) ||
|
||||
seg_only_exclusive(first_seg(lv)))) {
|
||||
@ -2771,16 +2579,6 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if cmirrord is running for clustered mirrors.
|
||||
*/
|
||||
if (!laopts->exclusive && vg_is_clustered(lv->vg) &&
|
||||
lv_is_mirror(lv) && !lv_is_raid(lv) &&
|
||||
!cluster_mirror_is_available(lv->vg->cmd)) {
|
||||
log_error("Shared cluster mirrors are not available.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (test_mode()) {
|
||||
_skip("Activating %s.", display_lvname(lv));
|
||||
r = 1;
|
||||
@ -2823,11 +2621,7 @@ static int _lv_activate(struct cmd_context *cmd, const char *lvid_s,
|
||||
|
||||
if (r && !monitor_dev_for_events(cmd, lv, laopts, 1))
|
||||
stack;
|
||||
|
||||
out:
|
||||
if (lv_to_free)
|
||||
release_vg(lv_to_free->vg);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
395
lib/cache/lvmcache.c
vendored
395
lib/cache/lvmcache.c
vendored
@ -65,38 +65,10 @@ struct lvmcache_vginfo {
|
||||
int scan_summary_mismatch; /* vgsummary from devs had mismatching seqno or checksum */
|
||||
};
|
||||
|
||||
struct saved_vg {
|
||||
/*
|
||||
* saved_vg_* are used only by clvmd.
|
||||
* It is not related to lvmcache or vginfo.
|
||||
*
|
||||
* For activation/deactivation, these are used to avoid
|
||||
* clvmd rereading a VG for each LV that is activated.
|
||||
*
|
||||
* For suspend/resume, this is used to avoid disk reads
|
||||
* while devices are suspended:
|
||||
* In suspend, both old (current) and new (precommitted)
|
||||
* metadata is saved. (Each in three forms: buffer, cft,
|
||||
* and vg). In resume, if the vg was committed
|
||||
* (saved_vg_committed is set), then LVs are resumed
|
||||
* using the new metadata, but if the vg wasn't committed,
|
||||
* then LVs are resumed using the old metadata.
|
||||
*
|
||||
* saved_vg_committed is set to 1 when clvmd gets
|
||||
* LCK_VG_COMMIT from vg_commit().
|
||||
*/
|
||||
char vgid[ID_LEN + 1];
|
||||
int saved_vg_committed;
|
||||
struct volume_group *saved_vg_old;
|
||||
struct volume_group *saved_vg_new;
|
||||
struct dm_list saved_vg_to_free;
|
||||
};
|
||||
|
||||
static struct dm_hash_table *_pvid_hash = NULL;
|
||||
static struct dm_hash_table *_vgid_hash = NULL;
|
||||
static struct dm_hash_table *_vgname_hash = NULL;
|
||||
static struct dm_hash_table *_lock_hash = NULL;
|
||||
static struct dm_hash_table *_saved_vg_hash = NULL;
|
||||
static DM_LIST_INIT(_vginfos);
|
||||
static DM_LIST_INIT(_found_duplicate_devs);
|
||||
static DM_LIST_INIT(_unused_duplicate_devs);
|
||||
@ -131,11 +103,6 @@ int lvmcache_init(struct cmd_context *cmd)
|
||||
if (!(_lock_hash = dm_hash_create(128)))
|
||||
return 0;
|
||||
|
||||
if (cmd->is_clvmd) {
|
||||
if (!(_saved_vg_hash = dm_hash_create(128)))
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reinitialising the cache clears the internal record of
|
||||
* which locks are held. The global lock can be held during
|
||||
@ -191,357 +158,6 @@ static void _update_cache_lock_state(const char *vgname, int locked)
|
||||
_update_cache_vginfo_lock_state(vginfo, locked);
|
||||
}
|
||||
|
||||
static struct saved_vg *_saved_vg_from_vgid(const char *vgid)
|
||||
{
|
||||
struct saved_vg *svg;
|
||||
char id[ID_LEN + 1] __attribute__((aligned(8)));
|
||||
|
||||
/* vgid not necessarily NULL-terminated */
|
||||
(void) dm_strncpy(id, vgid, sizeof(id));
|
||||
|
||||
if (!(svg = dm_hash_lookup(_saved_vg_hash, id))) {
|
||||
log_debug_cache("lvmcache: no saved_vg for vgid \"%s\"", id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return svg;
|
||||
}
|
||||
|
||||
static void _saved_vg_inval(struct saved_vg *svg, int inval_old, int inval_new)
|
||||
{
|
||||
struct vg_list *vgl;
|
||||
|
||||
/*
|
||||
* In practice there appears to only ever be a single invalidated vg,
|
||||
* so making saved_vg_to_free a list instead of a pointer is overkill.
|
||||
* But, without proof otherwise, safer to keep the list.
|
||||
*/
|
||||
|
||||
if (inval_old && svg->saved_vg_old) {
|
||||
log_debug_cache("lvmcache: inval saved_vg %s old %p",
|
||||
svg->saved_vg_old->name, svg->saved_vg_old);
|
||||
|
||||
if ((vgl = dm_zalloc(sizeof(*vgl)))) {
|
||||
vgl->vg = svg->saved_vg_old;
|
||||
dm_list_add(&svg->saved_vg_to_free, &vgl->list);
|
||||
}
|
||||
|
||||
svg->saved_vg_old = NULL;
|
||||
}
|
||||
|
||||
if (inval_new && svg->saved_vg_new) {
|
||||
log_debug_cache("lvmcache: inval saved_vg %s new pre %p",
|
||||
svg->saved_vg_new->name, svg->saved_vg_new);
|
||||
|
||||
if ((vgl = dm_zalloc(sizeof(*vgl)))) {
|
||||
vgl->vg = svg->saved_vg_new;
|
||||
dm_list_add(&svg->saved_vg_to_free, &vgl->list);
|
||||
}
|
||||
svg->saved_vg_new = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void _saved_vg_free(struct saved_vg *svg, int free_old, int free_new)
|
||||
{
|
||||
struct vg_list *vgl, *vgl2;
|
||||
struct volume_group *vg;
|
||||
|
||||
if (free_old) {
|
||||
if ((vg = svg->saved_vg_old)) {
|
||||
log_debug_cache("lvmcache: free saved_vg old %s %.8s %d old %p",
|
||||
vg->name, (char *)&vg->id, vg->seqno, vg);
|
||||
|
||||
vg->saved_in_clvmd = 0;
|
||||
release_vg(vg);
|
||||
svg->saved_vg_old = NULL;
|
||||
vg = NULL;
|
||||
}
|
||||
|
||||
dm_list_iterate_items_safe(vgl, vgl2, &svg->saved_vg_to_free) {
|
||||
log_debug_cache("lvmcache: free saved_vg_to_free %s %.8s %d %p",
|
||||
vgl->vg->name, (char *)&vgl->vg->id, vgl->vg->seqno, vgl->vg);
|
||||
|
||||
dm_list_del(&vgl->list);
|
||||
vgl->vg->saved_in_clvmd = 0;
|
||||
release_vg(vgl->vg);
|
||||
}
|
||||
}
|
||||
|
||||
if (free_new) {
|
||||
if ((vg = svg->saved_vg_new)) {
|
||||
log_debug_cache("lvmcache: free saved_vg pre %s %.8s %d %p",
|
||||
vg->name, (char *)&vg->id, vg->seqno, vg);
|
||||
|
||||
vg->saved_in_clvmd = 0;
|
||||
release_vg(vg);
|
||||
svg->saved_vg_new = NULL;
|
||||
vg = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void _drop_metadata(const char *vgname, int drop_precommitted)
|
||||
{
|
||||
struct lvmcache_vginfo *vginfo;
|
||||
struct saved_vg *svg;
|
||||
|
||||
if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, NULL)))
|
||||
return;
|
||||
|
||||
if (!(svg = _saved_vg_from_vgid(vginfo->vgid)))
|
||||
return;
|
||||
|
||||
if (drop_precommitted)
|
||||
_saved_vg_free(svg, 0, 1);
|
||||
else
|
||||
_saved_vg_free(svg, 1, 1);
|
||||
}
|
||||
|
||||
void lvmcache_save_vg(struct volume_group *vg, int precommitted)
|
||||
{
|
||||
struct saved_vg *svg;
|
||||
struct format_instance *fid;
|
||||
struct format_instance_ctx fic;
|
||||
struct volume_group *save_vg = NULL;
|
||||
struct dm_config_tree *save_cft = NULL;
|
||||
const struct format_type *fmt;
|
||||
char *save_buf = NULL;
|
||||
size_t size;
|
||||
int new = precommitted;
|
||||
int old = !precommitted;
|
||||
|
||||
if (!(svg = _saved_vg_from_vgid((const char *)&vg->id))) {
|
||||
/* Nothing is saved yet for this vg */
|
||||
|
||||
if (!(svg = dm_zalloc(sizeof(*svg))))
|
||||
return;
|
||||
|
||||
dm_list_init(&svg->saved_vg_to_free);
|
||||
|
||||
dm_strncpy(svg->vgid, (const char *)vg->id.uuid, sizeof(svg->vgid));
|
||||
|
||||
if (!dm_hash_insert(_saved_vg_hash, svg->vgid, svg)) {
|
||||
log_error("lvmcache: failed to insert saved_vg %s", svg->vgid);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
/* Nothing to do if we've already saved this seqno */
|
||||
|
||||
if (old && svg->saved_vg_old && (svg->saved_vg_old->seqno == vg->seqno))
|
||||
return;
|
||||
|
||||
if (new && svg->saved_vg_new && (svg->saved_vg_new->seqno == vg->seqno))
|
||||
return;
|
||||
|
||||
/* Invalidate the existing saved_vg that will be replaced */
|
||||
|
||||
_saved_vg_inval(svg, old, new);
|
||||
}
|
||||
|
||||
|
||||
if (!(size = export_vg_to_buffer(vg, &save_buf)))
|
||||
goto_bad;
|
||||
|
||||
fmt = vg->fid->fmt;
|
||||
fic.type = FMT_INSTANCE_MDAS | FMT_INSTANCE_AUX_MDAS;
|
||||
fic.context.vg_ref.vg_name = vg->name;
|
||||
fic.context.vg_ref.vg_id = svg->vgid;
|
||||
|
||||
if (!(fid = fmt->ops->create_instance(fmt, &fic)))
|
||||
goto_bad;
|
||||
|
||||
if (!(save_cft = config_tree_from_string_without_dup_node_check(save_buf)))
|
||||
goto_bad;
|
||||
|
||||
if (!(save_vg = import_vg_from_config_tree(save_cft, fid)))
|
||||
goto_bad;
|
||||
|
||||
dm_free(save_buf);
|
||||
dm_config_destroy(save_cft);
|
||||
|
||||
save_vg->saved_in_clvmd = 1;
|
||||
|
||||
if (old) {
|
||||
svg->saved_vg_old = save_vg;
|
||||
log_debug_cache("lvmcache: saved old vg %s seqno %d %p",
|
||||
save_vg->name, save_vg->seqno, save_vg);
|
||||
} else {
|
||||
svg->saved_vg_new = save_vg;
|
||||
log_debug_cache("lvmcache: saved pre vg %s seqno %d %p",
|
||||
save_vg->name, save_vg->seqno, save_vg);
|
||||
}
|
||||
return;
|
||||
|
||||
bad:
|
||||
if (save_buf)
|
||||
dm_free(save_buf);
|
||||
if (save_cft)
|
||||
dm_config_destroy(save_cft);
|
||||
|
||||
_saved_vg_inval(svg, old, new);
|
||||
log_debug_cache("lvmcache: failed to save pre %d vg %s", precommitted, vg->name);
|
||||
}
|
||||
|
||||
struct volume_group *lvmcache_get_saved_vg(const char *vgid, int precommitted)
|
||||
{
|
||||
struct saved_vg *svg;
|
||||
struct volume_group *vg = NULL;
|
||||
int new = precommitted;
|
||||
int old = !precommitted;
|
||||
|
||||
if (!(svg = _saved_vg_from_vgid(vgid)))
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Once new is returned, then also return new if old is requested,
|
||||
* i.e. new becomes both old and new once it's used.
|
||||
*/
|
||||
|
||||
if (new)
|
||||
vg = svg->saved_vg_new;
|
||||
else if (old)
|
||||
vg = svg->saved_vg_old;
|
||||
|
||||
if (vg && old) {
|
||||
if (!svg->saved_vg_new)
|
||||
log_debug_cache("lvmcache: get old saved_vg %d %s %p",
|
||||
vg->seqno, vg->name, vg);
|
||||
else
|
||||
log_debug_cache("lvmcache: get old saved_vg %d %s %p new is %d %p",
|
||||
vg->seqno, vg->name, vg,
|
||||
svg->saved_vg_new->seqno,
|
||||
svg->saved_vg_new);
|
||||
}
|
||||
|
||||
if (vg && new) {
|
||||
if (!svg->saved_vg_old)
|
||||
log_debug_cache("lvmcache: get new saved_vg %d %s %p",
|
||||
vg->seqno, vg->name, vg);
|
||||
else
|
||||
log_debug_cache("lvmcache: get new saved_vg %d %s %p old is %d %p",
|
||||
vg->seqno, vg->name, vg,
|
||||
svg->saved_vg_old->seqno,
|
||||
svg->saved_vg_old);
|
||||
|
||||
if (svg->saved_vg_old && (svg->saved_vg_old->seqno < vg->seqno)) {
|
||||
log_debug_cache("lvmcache: inval saved_vg_old %d %p for new %d %p %s",
|
||||
svg->saved_vg_old->seqno, svg->saved_vg_old,
|
||||
vg->seqno, vg, vg->name);
|
||||
|
||||
_saved_vg_inval(svg, 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (!vg && new && svg->saved_vg_old)
|
||||
log_warn("lvmcache_get_saved_vg pre %d wanted new but only have old %d %s",
|
||||
precommitted,
|
||||
svg->saved_vg_old->seqno,
|
||||
svg->saved_vg_old->name);
|
||||
|
||||
if (!vg && old && svg->saved_vg_new)
|
||||
log_warn("lvmcache_get_saved_vg pre %d wanted old but only have new %d %s",
|
||||
precommitted,
|
||||
svg->saved_vg_new->seqno,
|
||||
svg->saved_vg_new->name);
|
||||
out:
|
||||
if (!vg)
|
||||
log_debug_cache("lvmcache: no saved pre %d %s", precommitted, vgid);
|
||||
return vg;
|
||||
}
|
||||
|
||||
struct volume_group *lvmcache_get_saved_vg_latest(const char *vgid)
|
||||
{
|
||||
struct saved_vg *svg;
|
||||
struct volume_group *vg = NULL;
|
||||
int old = 0;
|
||||
int new = 0;
|
||||
|
||||
if (!(svg = _saved_vg_from_vgid(vgid)))
|
||||
goto out;
|
||||
|
||||
if (svg->saved_vg_committed) {
|
||||
vg = svg->saved_vg_new;
|
||||
new = 1;
|
||||
} else {
|
||||
vg = svg->saved_vg_old;
|
||||
old = 1;
|
||||
}
|
||||
|
||||
if (vg && old) {
|
||||
if (!svg->saved_vg_new)
|
||||
log_debug_cache("lvmcache: get_latest old saved_vg %d %s %p",
|
||||
vg->seqno, vg->name, vg);
|
||||
else
|
||||
log_debug_cache("lvmcache: get_latest old saved_vg %d %s %p new is %d %p",
|
||||
vg->seqno, vg->name, vg,
|
||||
svg->saved_vg_new->seqno,
|
||||
svg->saved_vg_new);
|
||||
}
|
||||
|
||||
if (vg && new) {
|
||||
if (!svg->saved_vg_old)
|
||||
log_debug_cache("lvmcache: get_latest new saved_vg %d %s %p",
|
||||
vg->seqno, vg->name, vg);
|
||||
else
|
||||
log_debug_cache("lvmcache: get_latest new saved_vg %d %s %p old is %d %p",
|
||||
vg->seqno, vg->name, vg,
|
||||
svg->saved_vg_old->seqno,
|
||||
svg->saved_vg_old);
|
||||
|
||||
if (svg->saved_vg_old && (svg->saved_vg_old->seqno < vg->seqno)) {
|
||||
log_debug_cache("lvmcache: inval saved_vg_old %d %p for new %d %p %s",
|
||||
svg->saved_vg_old->seqno, svg->saved_vg_old,
|
||||
vg->seqno, vg, vg->name);
|
||||
|
||||
_saved_vg_inval(svg, 1, 0);
|
||||
}
|
||||
}
|
||||
out:
|
||||
if (!vg)
|
||||
log_debug_cache("lvmcache: no saved vg latest %s", vgid);
|
||||
return vg;
|
||||
}
|
||||
|
||||
void lvmcache_drop_saved_vgid(const char *vgid)
|
||||
{
|
||||
struct saved_vg *svg;
|
||||
|
||||
if ((svg = _saved_vg_from_vgid(vgid)))
|
||||
_saved_vg_inval(svg, 1, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remote node uses this to upgrade precommitted metadata to commited state
|
||||
* when receives vg_commit notification.
|
||||
* (Note that devices can be suspended here, if so, precommitted metadata are already read.)
|
||||
*/
|
||||
void lvmcache_commit_metadata(const char *vgname)
|
||||
{
|
||||
struct lvmcache_vginfo *vginfo;
|
||||
struct saved_vg *svg;
|
||||
|
||||
if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, NULL)))
|
||||
return;
|
||||
|
||||
if ((svg = _saved_vg_from_vgid(vginfo->vgid)))
|
||||
svg->saved_vg_committed = 1;
|
||||
}
|
||||
|
||||
void lvmcache_drop_metadata(const char *vgname, int drop_precommitted)
|
||||
{
|
||||
if (!_saved_vg_hash)
|
||||
return;
|
||||
|
||||
if (lvmcache_vgname_is_locked(VG_GLOBAL))
|
||||
return;
|
||||
|
||||
/* For VG_ORPHANS, we need to invalidate all labels on orphan PVs. */
|
||||
if (!strcmp(vgname, VG_ORPHANS)) {
|
||||
_drop_metadata(FMT_TEXT_ORPHAN_VG_NAME, 0);
|
||||
} else
|
||||
_drop_metadata(vgname, drop_precommitted);
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure vgname2 comes after vgname1 alphabetically.
|
||||
* Orphan locks come last.
|
||||
@ -2514,11 +2130,6 @@ static void _lvmcache_destroy_lockname(struct dm_hash_node *n)
|
||||
dm_hash_get_key(_lock_hash, n));
|
||||
}
|
||||
|
||||
static void _destroy_saved_vg(struct saved_vg *svg)
|
||||
{
|
||||
_saved_vg_free(svg, 1, 1);
|
||||
}
|
||||
|
||||
void lvmcache_destroy(struct cmd_context *cmd, int retain_orphans, int reset)
|
||||
{
|
||||
struct dm_hash_node *n;
|
||||
@ -2555,12 +2166,6 @@ void lvmcache_destroy(struct cmd_context *cmd, int retain_orphans, int reset)
|
||||
_lock_hash = NULL;
|
||||
}
|
||||
|
||||
if (_saved_vg_hash) {
|
||||
dm_hash_iter(_saved_vg_hash, (dm_hash_iterate_fn) _destroy_saved_vg);
|
||||
dm_hash_destroy(_saved_vg_hash);
|
||||
_saved_vg_hash = NULL;
|
||||
}
|
||||
|
||||
if (!dm_list_empty(&_vginfos))
|
||||
log_error(INTERNAL_ERROR "_vginfos list should be empty");
|
||||
dm_list_init(&_vginfos);
|
||||
|
@ -1,26 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.
|
||||
# Copyright (C) 2004-2010 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
top_builddir = @top_builddir@
|
||||
|
||||
SOURCES = cluster_locking.c
|
||||
|
||||
LIB_SHARED = liblvm2clusterlock.$(LIB_SUFFIX)
|
||||
LIB_VERSION = $(LIB_VERSION_LVM)
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
install install_cluster: install_lvm2_plugin
|
@ -1,636 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2009 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* Locking functions for LVM.
|
||||
* The main purpose of this part of the library is to serialise LVM
|
||||
* management operations across a cluster.
|
||||
*/
|
||||
|
||||
#include "lib/misc/lib.h"
|
||||
#include "daemons/clvmd/clvm.h"
|
||||
#include "lib/misc/lvm-string.h"
|
||||
#include "lib/locking/locking.h"
|
||||
#include "locking_types.h"
|
||||
#include "lib/commands/toolcontext.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef CLUSTER_LOCKING_INTERNAL
|
||||
int lock_resource(struct cmd_context *cmd, const char *resource, uint32_t flags, const struct logical_volume *lv __attribute__((unused)));
|
||||
int query_resource(const char *resource, const char *node, int *mode);
|
||||
void locking_end(void);
|
||||
int locking_init(int type, struct dm_config_tree *cf, uint32_t *flags);
|
||||
#endif
|
||||
|
||||
typedef struct lvm_response {
|
||||
char node[255];
|
||||
char *response;
|
||||
int status;
|
||||
int len;
|
||||
} lvm_response_t;
|
||||
|
||||
/*
|
||||
* This gets stuck at the start of memory we allocate so we
|
||||
* can sanity-check it at deallocation time
|
||||
*/
|
||||
#define LVM_SIGNATURE 0x434C564D
|
||||
|
||||
/*
|
||||
* NOTE: the LVMD uses the socket FD as the client ID, this means
|
||||
* that any client that calls fork() will inherit the context of
|
||||
* it's parent.
|
||||
*/
|
||||
static int _clvmd_sock = -1;
|
||||
|
||||
/* FIXME Install SIGPIPE handler? */
|
||||
|
||||
/* Open connection to the Cluster Manager daemon */
|
||||
static int _open_local_sock(int suppress_messages)
|
||||
{
|
||||
int local_socket;
|
||||
struct sockaddr_un sockaddr = { .sun_family = AF_UNIX };
|
||||
|
||||
if (!dm_strncpy(sockaddr.sun_path, CLVMD_SOCKNAME, sizeof(sockaddr.sun_path))) {
|
||||
log_error("%s: clvmd socket name too long.", CLVMD_SOCKNAME);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Open local socket */
|
||||
if ((local_socket = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
|
||||
log_error_suppress(suppress_messages, "Local socket "
|
||||
"creation failed: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if (connect(local_socket,(struct sockaddr *) &sockaddr,
|
||||
sizeof(sockaddr))) {
|
||||
int saved_errno = errno;
|
||||
|
||||
log_error_suppress(suppress_messages, "connect() failed "
|
||||
"on local socket: %s", strerror(errno));
|
||||
if (close(local_socket))
|
||||
stack;
|
||||
|
||||
errno = saved_errno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return local_socket;
|
||||
}
|
||||
|
||||
/* Send a request and return the status */
|
||||
static int _send_request(char *inbuf, int inlen, char **retbuf)
|
||||
{
|
||||
char outbuf[PIPE_BUF] __attribute__((aligned(8)));
|
||||
struct clvm_header *outheader = (struct clvm_header *) outbuf;
|
||||
int len;
|
||||
unsigned off;
|
||||
int buflen;
|
||||
int err;
|
||||
|
||||
/* Send it to CLVMD */
|
||||
rewrite:
|
||||
if ( (err = write(_clvmd_sock, inbuf, inlen)) != inlen) {
|
||||
if (err == -1 && errno == EINTR)
|
||||
goto rewrite;
|
||||
log_error("Error writing data to clvmd: %s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get the response */
|
||||
reread:
|
||||
if ((len = read(_clvmd_sock, outbuf, sizeof(struct clvm_header))) < 0) {
|
||||
if (errno == EINTR)
|
||||
goto reread;
|
||||
log_error("Error reading data from clvmd: %s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
log_error("EOF reading CLVMD");
|
||||
errno = ENOTCONN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Allocate buffer */
|
||||
buflen = len + outheader->arglen;
|
||||
*retbuf = dm_malloc(buflen);
|
||||
if (!*retbuf) {
|
||||
errno = ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Copy the header */
|
||||
memcpy(*retbuf, outbuf, len);
|
||||
outheader = (struct clvm_header *) *retbuf;
|
||||
|
||||
/* Read the returned values */
|
||||
off = 1; /* we've already read the first byte */
|
||||
while (off <= outheader->arglen && len > 0) {
|
||||
len = read(_clvmd_sock, outheader->args + off,
|
||||
buflen - off - offsetof(struct clvm_header, args));
|
||||
if (len > 0)
|
||||
off += len;
|
||||
}
|
||||
|
||||
/* Was it an error ? */
|
||||
if (outheader->status != 0) {
|
||||
errno = outheader->status;
|
||||
|
||||
/* Only return an error here if there are no node-specific
|
||||
errors present in the message that might have more detail */
|
||||
if (!(outheader->flags & CLVMD_FLAG_NODEERRS)) {
|
||||
log_error("cluster request failed: %s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Build the structure header and parse-out wildcard node names */
|
||||
/* FIXME: Cleanup implicit casts of clvmd_cmd (int, char, uint8_t, etc). */
|
||||
static void _build_header(struct clvm_header *head, int clvmd_cmd, const char *node,
|
||||
int len)
|
||||
{
|
||||
head->cmd = clvmd_cmd;
|
||||
head->status = 0;
|
||||
head->flags = 0;
|
||||
head->xid = 0;
|
||||
head->clientid = 0;
|
||||
head->arglen = len;
|
||||
|
||||
/*
|
||||
* Handle special node names.
|
||||
*/
|
||||
if (!node || !strcmp(node, NODE_ALL))
|
||||
head->node[0] = '\0';
|
||||
else if (!strcmp(node, NODE_LOCAL)) {
|
||||
head->node[0] = '\0';
|
||||
head->flags = CLVMD_FLAG_LOCAL;
|
||||
} else if (!strcmp(node, NODE_REMOTE)) {
|
||||
head->node[0] = '\0';
|
||||
head->flags = CLVMD_FLAG_REMOTE;
|
||||
} else
|
||||
strcpy(head->node, node);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a message to a(or all) node(s) in the cluster and wait for replies
|
||||
*/
|
||||
static int _cluster_request(char clvmd_cmd, const char *node, void *data, int len,
|
||||
lvm_response_t ** response, int *num)
|
||||
{
|
||||
char outbuf[sizeof(struct clvm_header) + len + strlen(node) + 1] __attribute__((aligned(8)));
|
||||
char *inptr;
|
||||
char *retbuf = NULL;
|
||||
int status;
|
||||
int i;
|
||||
int num_responses = 0;
|
||||
struct clvm_header *head = (struct clvm_header *) outbuf;
|
||||
lvm_response_t *rarray;
|
||||
|
||||
*num = 0;
|
||||
|
||||
if (_clvmd_sock == -1) {
|
||||
if ((_clvmd_sock = _open_local_sock(0)) == -1)
|
||||
return_0;
|
||||
}
|
||||
|
||||
/* 1 byte is used from struct clvm_header.args[1], so -> len - 1 */
|
||||
_build_header(head, clvmd_cmd, node, len - 1);
|
||||
memcpy(head->node + strlen(head->node) + 1, data, len);
|
||||
|
||||
status = _send_request(outbuf, sizeof(struct clvm_header) +
|
||||
strlen(head->node) + len - 1, &retbuf);
|
||||
if (!status)
|
||||
goto_out;
|
||||
|
||||
/* Count the number of responses we got */
|
||||
head = (struct clvm_header *) retbuf;
|
||||
inptr = head->args;
|
||||
while (inptr[0]) {
|
||||
num_responses++;
|
||||
inptr += strlen(inptr) + 1;
|
||||
inptr += sizeof(int);
|
||||
inptr += strlen(inptr) + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate response array.
|
||||
* With an extra pair of INTs on the front to sanity
|
||||
* check the pointer when we are given it back to free
|
||||
*/
|
||||
*response = NULL;
|
||||
if (!(rarray = dm_malloc(sizeof(lvm_response_t) * num_responses))) {
|
||||
errno = ENOMEM;
|
||||
status = 0;
|
||||
goto_out;
|
||||
}
|
||||
|
||||
/* Unpack the response into an lvm_response_t array */
|
||||
inptr = head->args;
|
||||
i = 0;
|
||||
while (inptr[0]) {
|
||||
strcpy(rarray[i].node, inptr);
|
||||
inptr += strlen(inptr) + 1;
|
||||
|
||||
memcpy(&rarray[i].status, inptr, sizeof(int));
|
||||
inptr += sizeof(int);
|
||||
|
||||
rarray[i].response = dm_malloc(strlen(inptr) + 1);
|
||||
if (rarray[i].response == NULL) {
|
||||
/* Free up everything else and return error */
|
||||
int j;
|
||||
for (j = 0; j < i; j++)
|
||||
dm_free(rarray[i].response);
|
||||
dm_free(rarray);
|
||||
errno = ENOMEM;
|
||||
status = 0;
|
||||
goto_out;
|
||||
}
|
||||
|
||||
strcpy(rarray[i].response, inptr);
|
||||
rarray[i].len = strlen(inptr);
|
||||
inptr += strlen(inptr) + 1;
|
||||
i++;
|
||||
}
|
||||
*num = num_responses;
|
||||
*response = rarray;
|
||||
|
||||
out:
|
||||
dm_free(retbuf);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Free reply array */
|
||||
static int _cluster_free_request(lvm_response_t * response, int num)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
dm_free(response[i].response);
|
||||
}
|
||||
|
||||
dm_free(response);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _lock_for_cluster(struct cmd_context *cmd, unsigned char clvmd_cmd,
|
||||
uint32_t flags, const char *name)
|
||||
{
|
||||
/* TODO: convert to global usable solution and move static into cmd */
|
||||
static unsigned char last_clvmd_cmd = 0;
|
||||
int status;
|
||||
int i;
|
||||
char *args;
|
||||
const char *node = "";
|
||||
int len;
|
||||
int dmeventd_mode;
|
||||
int saved_errno;
|
||||
lvm_response_t *response = NULL;
|
||||
int num_responses;
|
||||
|
||||
assert(name);
|
||||
|
||||
len = strlen(name) + 3;
|
||||
args = alloca(len);
|
||||
strcpy(args + 2, name);
|
||||
|
||||
/* args[0] holds bottom 8 bits except LCK_LOCAL (0x40). */
|
||||
args[0] = flags & (LCK_SCOPE_MASK | LCK_TYPE_MASK | LCK_NONBLOCK | LCK_HOLD | LCK_CLUSTER_VG);
|
||||
|
||||
args[1] = 0;
|
||||
|
||||
if (flags & LCK_ORIGIN_ONLY)
|
||||
args[1] |= LCK_ORIGIN_ONLY_MODE;
|
||||
|
||||
if (flags & LCK_REVERT)
|
||||
args[1] |= LCK_REVERT_MODE;
|
||||
|
||||
if (mirror_in_sync())
|
||||
args[1] |= LCK_MIRROR_NOSYNC_MODE;
|
||||
|
||||
if (test_mode())
|
||||
args[1] |= LCK_TEST_MODE;
|
||||
|
||||
/*
|
||||
* We propagate dmeventd_monitor_mode() to clvmd faithfully, since
|
||||
* dmeventd monitoring is tied to activation which happens inside clvmd
|
||||
* when locking_type = 3.
|
||||
*/
|
||||
dmeventd_mode = dmeventd_monitor_mode();
|
||||
if (dmeventd_mode == DMEVENTD_MONITOR_IGNORE)
|
||||
args[1] |= LCK_DMEVENTD_MONITOR_IGNORE;
|
||||
|
||||
if (dmeventd_mode)
|
||||
args[1] |= LCK_DMEVENTD_MONITOR_MODE;
|
||||
|
||||
if (cmd->partial_activation)
|
||||
args[1] |= LCK_PARTIAL_MODE;
|
||||
|
||||
/*
|
||||
* VG locks are just that: locks, and have no side effects
|
||||
* so we only need to do them on the local node because all
|
||||
* locks are cluster-wide.
|
||||
*
|
||||
* P_ locks /do/ get distributed across the cluster because they might
|
||||
* have side-effects.
|
||||
*
|
||||
* SYNC_NAMES and VG_BACKUP use the VG name directly without prefix.
|
||||
*/
|
||||
if (clvmd_cmd == CLVMD_CMD_SYNC_NAMES) {
|
||||
if (flags & LCK_LOCAL) {
|
||||
node = NODE_LOCAL;
|
||||
if (clvmd_cmd == last_clvmd_cmd) {
|
||||
log_debug("Skipping redundant local sync command.");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
} else if (clvmd_cmd != CLVMD_CMD_VG_BACKUP) {
|
||||
if (strncmp(name, "P_", 2) &&
|
||||
(clvmd_cmd == CLVMD_CMD_LOCK_VG ||
|
||||
(flags & LCK_LOCAL) ||
|
||||
!(flags & LCK_CLUSTER_VG)))
|
||||
node = NODE_LOCAL;
|
||||
else if (flags & LCK_REMOTE)
|
||||
node = NODE_REMOTE;
|
||||
}
|
||||
|
||||
last_clvmd_cmd = clvmd_cmd;
|
||||
status = _cluster_request(clvmd_cmd, node, args, len,
|
||||
&response, &num_responses);
|
||||
|
||||
/* If any nodes were down then display them and return an error */
|
||||
for (i = 0; i < num_responses; i++) {
|
||||
if (response[i].status == EHOSTDOWN) {
|
||||
log_error("clvmd not running on node %s",
|
||||
response[i].node);
|
||||
status = 0;
|
||||
errno = response[i].status;
|
||||
} else if (response[i].status) {
|
||||
log_error("Error locking on node %s: %s",
|
||||
response[i].node,
|
||||
response[i].response[0] ?
|
||||
response[i].response :
|
||||
strerror(response[i].status));
|
||||
status = 0;
|
||||
errno = response[i].status;
|
||||
}
|
||||
}
|
||||
|
||||
saved_errno = errno;
|
||||
_cluster_free_request(response, num_responses);
|
||||
errno = saved_errno;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* API entry point for LVM */
|
||||
#ifdef CLUSTER_LOCKING_INTERNAL
|
||||
static int _lock_resource(struct cmd_context *cmd, const char *resource,
|
||||
uint32_t flags, const struct logical_volume *lv __attribute__((unused)))
|
||||
#else
|
||||
int lock_resource(struct cmd_context *cmd, const char *resource, uint32_t flags, const struct logical_volume *lv __attribute__((unused)))
|
||||
#endif
|
||||
{
|
||||
char lockname[PATH_MAX];
|
||||
int clvmd_cmd = 0;
|
||||
const char *lock_scope;
|
||||
const char *lock_type;
|
||||
|
||||
assert(strlen(resource) < sizeof(lockname));
|
||||
assert(resource);
|
||||
|
||||
switch (flags & LCK_SCOPE_MASK) {
|
||||
case LCK_ACTIVATION:
|
||||
return 1;
|
||||
case LCK_VG:
|
||||
if (!strcmp(resource, VG_SYNC_NAMES)) {
|
||||
log_very_verbose("Requesting sync names.");
|
||||
return _lock_for_cluster(cmd, CLVMD_CMD_SYNC_NAMES,
|
||||
flags & ~LCK_HOLD, resource);
|
||||
}
|
||||
if (flags == LCK_VG_BACKUP) {
|
||||
log_very_verbose("Requesting backup of VG metadata for %s",
|
||||
resource);
|
||||
return _lock_for_cluster(cmd, CLVMD_CMD_VG_BACKUP,
|
||||
LCK_CLUSTER_VG, resource);
|
||||
}
|
||||
|
||||
/* If the VG name is empty then lock the unused PVs */
|
||||
if (dm_snprintf(lockname, sizeof(lockname), "%c_%s",
|
||||
(is_orphan_vg(resource) ||
|
||||
is_global_vg(resource) ||
|
||||
(flags & LCK_CACHE)) ? 'P' : 'V',
|
||||
resource) < 0) {
|
||||
log_error("Locking resource %s too long.", resource);
|
||||
return 0;
|
||||
}
|
||||
|
||||
lock_scope = "VG";
|
||||
clvmd_cmd = CLVMD_CMD_LOCK_VG;
|
||||
/*
|
||||
* Old clvmd does not expect LCK_HOLD which was already processed
|
||||
* in lock_vol, mask it for compatibility reasons.
|
||||
*/
|
||||
if (flags != LCK_VG_COMMIT && flags != LCK_VG_REVERT)
|
||||
flags &= ~LCK_HOLD;
|
||||
|
||||
break;
|
||||
|
||||
case LCK_LV:
|
||||
clvmd_cmd = CLVMD_CMD_LOCK_LV;
|
||||
strcpy(lockname, resource);
|
||||
lock_scope = "LV";
|
||||
flags &= ~LCK_HOLD; /* Mask off HOLD flag */
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error("Unrecognised lock scope: %d",
|
||||
flags & LCK_SCOPE_MASK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch(flags & LCK_TYPE_MASK) {
|
||||
case LCK_UNLOCK:
|
||||
lock_type = "UN";
|
||||
break;
|
||||
case LCK_NULL:
|
||||
lock_type = "NL";
|
||||
break;
|
||||
case LCK_READ:
|
||||
lock_type = "CR";
|
||||
break;
|
||||
case LCK_PREAD:
|
||||
lock_type = "PR";
|
||||
break;
|
||||
case LCK_WRITE:
|
||||
lock_type = "PW";
|
||||
break;
|
||||
case LCK_EXCL:
|
||||
lock_type = "EX";
|
||||
break;
|
||||
default:
|
||||
log_error("Unrecognised lock type: %u",
|
||||
flags & LCK_TYPE_MASK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_very_verbose("Locking %s %s %s (%s%s%s%s%s%s%s%s%s) (0x%x)", lock_scope, lockname,
|
||||
lock_type, lock_scope,
|
||||
flags & LCK_NONBLOCK ? "|NONBLOCK" : "",
|
||||
flags & LCK_HOLD ? "|HOLD" : "",
|
||||
flags & LCK_CLUSTER_VG ? "|CLUSTER" : "",
|
||||
flags & LCK_LOCAL ? "|LOCAL" : "",
|
||||
flags & LCK_REMOTE ? "|REMOTE" : "",
|
||||
flags & LCK_CACHE ? "|CACHE" : "",
|
||||
flags & LCK_ORIGIN_ONLY ? "|ORIGIN_ONLY" : "",
|
||||
flags & LCK_REVERT ? "|REVERT" : "",
|
||||
flags);
|
||||
|
||||
/* Send a message to the cluster manager */
|
||||
return _lock_for_cluster(cmd, clvmd_cmd, flags, lockname);
|
||||
}
|
||||
|
||||
static int _decode_lock_type(const char *response)
|
||||
{
|
||||
if (!response)
|
||||
return LCK_NULL;
|
||||
|
||||
if (!strcmp(response, "EX"))
|
||||
return LCK_EXCL;
|
||||
|
||||
if (!strcmp(response, "CR"))
|
||||
return LCK_READ;
|
||||
|
||||
if (!strcmp(response, "PR"))
|
||||
return LCK_PREAD;
|
||||
|
||||
return_0;
|
||||
}
|
||||
|
||||
#ifdef CLUSTER_LOCKING_INTERNAL
|
||||
static int _query_resource(const char *resource, const char *node, int *mode)
|
||||
#else
|
||||
int query_resource(const char *resource, const char *node, int *mode)
|
||||
#endif
|
||||
{
|
||||
int i, status, len, num_responses, saved_errno;
|
||||
char *args;
|
||||
lvm_response_t *response = NULL;
|
||||
|
||||
saved_errno = errno;
|
||||
len = strlen(resource) + 3;
|
||||
args = alloca(len);
|
||||
strcpy(args + 2, resource);
|
||||
|
||||
args[0] = 0;
|
||||
args[1] = 0;
|
||||
|
||||
status = _cluster_request(CLVMD_CMD_LOCK_QUERY, node, args, len,
|
||||
&response, &num_responses);
|
||||
*mode = LCK_NULL;
|
||||
for (i = 0; i < num_responses; i++) {
|
||||
if (response[i].status == EHOSTDOWN)
|
||||
continue;
|
||||
|
||||
if (!response[i].response[0])
|
||||
continue;
|
||||
|
||||
/*
|
||||
* All nodes should use CR, or exactly one node
|
||||
* should hold EX. (PR is obsolete)
|
||||
* If two nodes report different locks,
|
||||
* something is broken - just return more important mode.
|
||||
*/
|
||||
if (_decode_lock_type(response[i].response) > *mode)
|
||||
*mode = _decode_lock_type(response[i].response);
|
||||
|
||||
log_debug_locking("Lock held for %s, node %s : %s", resource,
|
||||
response[i].node, response[i].response);
|
||||
}
|
||||
|
||||
_cluster_free_request(response, num_responses);
|
||||
errno = saved_errno;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
#ifdef CLUSTER_LOCKING_INTERNAL
|
||||
static void _locking_end(void)
|
||||
#else
|
||||
void locking_end(void)
|
||||
#endif
|
||||
{
|
||||
if (_clvmd_sock != -1 && close(_clvmd_sock))
|
||||
stack;
|
||||
|
||||
_clvmd_sock = -1;
|
||||
}
|
||||
|
||||
#ifdef CLUSTER_LOCKING_INTERNAL
|
||||
static void _reset_locking(void)
|
||||
#else
|
||||
void reset_locking(void)
|
||||
#endif
|
||||
{
|
||||
if (close(_clvmd_sock))
|
||||
stack;
|
||||
|
||||
_clvmd_sock = _open_local_sock(0);
|
||||
if (_clvmd_sock == -1)
|
||||
stack;
|
||||
}
|
||||
|
||||
#ifdef CLUSTER_LOCKING_INTERNAL
|
||||
int init_cluster_locking(struct locking_type *locking, struct cmd_context *cmd,
|
||||
int suppress_messages)
|
||||
{
|
||||
locking->lock_resource = _lock_resource;
|
||||
locking->query_resource = _query_resource;
|
||||
locking->fin_locking = _locking_end;
|
||||
locking->reset_locking = _reset_locking;
|
||||
locking->flags = LCK_PRE_MEMLOCK | LCK_CLUSTERED | LCK_SUPPORTS_REMOTE_QUERIES;
|
||||
|
||||
_clvmd_sock = _open_local_sock(suppress_messages);
|
||||
if (_clvmd_sock == -1)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
int locking_init(int type, struct dm_config_tree *cf, uint32_t *flags)
|
||||
{
|
||||
_clvmd_sock = _open_local_sock(0);
|
||||
if (_clvmd_sock == -1)
|
||||
return 0;
|
||||
|
||||
/* Ask LVM to lock memory before calling us */
|
||||
*flags |= LCK_PRE_MEMLOCK;
|
||||
*flags |= LCK_CLUSTERED;
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
@ -1,106 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "lib/misc/lib.h"
|
||||
#include "locking_types.h"
|
||||
#include "lib/config/defaults.h"
|
||||
#include "lib/misc/sharedlib.h"
|
||||
#include "lib/commands/toolcontext.h"
|
||||
#include "lib/activate/activate.h"
|
||||
|
||||
static void *_locking_lib = NULL;
|
||||
static void (*_reset_fn) (void) = NULL;
|
||||
static void (*_end_fn) (void) = NULL;
|
||||
static int (*_lock_fn) (struct cmd_context * cmd, const char *resource,
|
||||
uint32_t flags) = NULL;
|
||||
static int (*_init_fn) (int type, struct dm_config_tree * cft,
|
||||
uint32_t *flags) = NULL;
|
||||
static int (*_lock_query_fn) (const char *resource, int *mode) = NULL;
|
||||
|
||||
static int _lock_resource(struct cmd_context *cmd, const char *resource,
|
||||
uint32_t flags, const struct logical_volume *lv __attribute__((unused)))
|
||||
{
|
||||
if (!_lock_fn)
|
||||
return 0;
|
||||
|
||||
if (!strcmp(resource, VG_SYNC_NAMES)) {
|
||||
/* Hide this lock request from external locking */
|
||||
fs_unlock();
|
||||
return 1;
|
||||
}
|
||||
|
||||
return _lock_fn(cmd, resource, flags);
|
||||
}
|
||||
|
||||
static void _fin_external_locking(void)
|
||||
{
|
||||
if (_end_fn)
|
||||
_end_fn();
|
||||
|
||||
dlclose(_locking_lib);
|
||||
|
||||
_locking_lib = NULL;
|
||||
_init_fn = NULL;
|
||||
_end_fn = NULL;
|
||||
_lock_fn = NULL;
|
||||
_reset_fn = NULL;
|
||||
}
|
||||
|
||||
static void _reset_external_locking(void)
|
||||
{
|
||||
if (_reset_fn)
|
||||
_reset_fn();
|
||||
}
|
||||
|
||||
int init_external_locking(struct locking_type *locking, struct cmd_context *cmd,
|
||||
int suppress_messages)
|
||||
{
|
||||
const char *libname;
|
||||
|
||||
if (_locking_lib) {
|
||||
log_error_suppress(suppress_messages, "External locking already initialised");
|
||||
return 1;
|
||||
}
|
||||
|
||||
locking->lock_resource = _lock_resource;
|
||||
locking->fin_locking = _fin_external_locking;
|
||||
locking->reset_locking = _reset_external_locking;
|
||||
locking->flags = 0;
|
||||
|
||||
if (!(libname = find_config_tree_str(cmd, global_locking_library_CFG, NULL)))
|
||||
return_0;
|
||||
|
||||
if (!(_locking_lib = load_shared_library(cmd, libname, "locking", 1)))
|
||||
return_0;
|
||||
|
||||
/* Get the functions we need */
|
||||
if (!(_init_fn = dlsym(_locking_lib, "locking_init")) ||
|
||||
!(_lock_fn = dlsym(_locking_lib, "lock_resource")) ||
|
||||
!(_reset_fn = dlsym(_locking_lib, "reset_locking")) ||
|
||||
!(_end_fn = dlsym(_locking_lib, "locking_end"))) {
|
||||
log_error_suppress(suppress_messages, "Shared library %s does "
|
||||
"not contain locking functions", libname);
|
||||
dlclose(_locking_lib);
|
||||
_locking_lib = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(_lock_query_fn = dlsym(_locking_lib, "query_resource")))
|
||||
log_warn_suppress(suppress_messages, "WARNING: %s: _query_resource() "
|
||||
"missing: Using inferior activation method.", libname);
|
||||
|
||||
log_verbose("Loaded external locking library %s", libname);
|
||||
return _init_fn(2, cmd->cft, &locking->flags);
|
||||
}
|
@ -116,101 +116,16 @@ int init_locking(int type, struct cmd_context *cmd, int suppress_messages)
|
||||
|
||||
_blocking_supported = find_config_tree_bool(cmd, global_wait_for_locks_CFG, NULL);
|
||||
|
||||
switch (type) {
|
||||
case 0:
|
||||
init_no_locking(&_locking, cmd, suppress_messages);
|
||||
log_warn_suppress(suppress_messages,
|
||||
"WARNING: Locking disabled. Be careful! "
|
||||
"This could corrupt your metadata.");
|
||||
return 1;
|
||||
if (type != 1)
|
||||
log_warn("WARNING: locking_type deprecated, using file locking.");
|
||||
|
||||
case 1:
|
||||
log_very_verbose("%sFile-based locking selected.",
|
||||
_blocking_supported ? "" : "Non-blocking ");
|
||||
|
||||
if (!init_file_locking(&_locking, cmd, suppress_messages)) {
|
||||
log_error_suppress(suppress_messages,
|
||||
"File-based locking initialisation failed.");
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
|
||||
#ifdef HAVE_LIBDL
|
||||
case 2:
|
||||
if (!is_static()) {
|
||||
log_very_verbose("External locking selected.");
|
||||
if (init_external_locking(&_locking, cmd, suppress_messages))
|
||||
return 1;
|
||||
}
|
||||
if (!find_config_tree_bool(cmd, global_fallback_to_clustered_locking_CFG, NULL)) {
|
||||
log_error_suppress(suppress_messages, "External locking initialisation failed.");
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
log_very_verbose("Falling back to internal clustered locking.");
|
||||
/* Fall through */
|
||||
|
||||
case 3:
|
||||
#ifdef CLUSTER_LOCKING_INTERNAL
|
||||
log_very_verbose("Cluster locking selected.");
|
||||
if (!init_cluster_locking(&_locking, cmd, suppress_messages)) {
|
||||
log_error_suppress(suppress_messages,
|
||||
"Internal cluster locking initialisation failed.");
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
#else
|
||||
log_warn("WARNING: Using locking_type=1, ignoring locking_type=3.");
|
||||
if (type == 3)
|
||||
log_warn("WARNING: See lvmlockd(8) for information on using cluster/clvm VGs.");
|
||||
type = 1;
|
||||
|
||||
log_very_verbose("%sFile-based locking selected.",
|
||||
_blocking_supported ? "" : "Non-blocking ");
|
||||
log_very_verbose("%sFile-based locking selected.", _blocking_supported ? "" : "Non-blocking ");
|
||||
|
||||
if (!init_file_locking(&_locking, cmd, suppress_messages)) {
|
||||
log_error_suppress(suppress_messages,
|
||||
"File-based locking initialisation failed.");
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
case 4:
|
||||
log_verbose("Read-only locking selected. "
|
||||
"Only read operations permitted.");
|
||||
if (!init_readonly_locking(&_locking, cmd, suppress_messages))
|
||||
break;
|
||||
return 1;
|
||||
|
||||
case 5:
|
||||
init_dummy_locking(&_locking, cmd, suppress_messages);
|
||||
log_verbose("Locking disabled for read-only access.");
|
||||
return 1;
|
||||
|
||||
default:
|
||||
log_error("Unknown locking type requested.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((type == 2 || type == 3) &&
|
||||
find_config_tree_bool(cmd, global_fallback_to_local_locking_CFG, NULL)) {
|
||||
log_warn_suppress(suppress_messages, "WARNING: Falling back to local file-based locking.");
|
||||
log_warn_suppress(suppress_messages,
|
||||
"Volume Groups with the clustered attribute will "
|
||||
"be inaccessible.");
|
||||
if (init_file_locking(&_locking, cmd, suppress_messages))
|
||||
return 1;
|
||||
|
||||
log_error_suppress(suppress_messages,
|
||||
"File-based locking initialisation failed.");
|
||||
}
|
||||
|
||||
if (!ignorelockingfailure())
|
||||
return 0;
|
||||
|
||||
log_verbose("Locking disabled - only read operations permitted.");
|
||||
init_readonly_locking(&_locking, cmd, suppress_messages);
|
||||
if (!init_file_locking(&_locking, cmd, suppress_messages))
|
||||
log_error_suppress(suppress_messages, "File-based locking initialisation failed.");
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -325,13 +240,6 @@ int lock_vol(struct cmd_context *cmd, const char *vol, uint32_t flags, const str
|
||||
!lvmcache_verify_lock_order(vol))
|
||||
return_0;
|
||||
|
||||
if ((flags == LCK_VG_DROP_CACHE) ||
|
||||
(strcmp(vol, VG_GLOBAL) && strcmp(vol, VG_SYNC_NAMES))) {
|
||||
/* Skip dropping cache for internal VG names #global, #sync_names */
|
||||
log_debug_locking("Dropping cache for %s.", vol);
|
||||
lvmcache_drop_metadata(vol, 0);
|
||||
}
|
||||
|
||||
break;
|
||||
case LCK_LV:
|
||||
/* All LV locks are non-blocking. */
|
||||
@ -372,24 +280,7 @@ int lock_vol(struct cmd_context *cmd, const char *vol, uint32_t flags, const str
|
||||
*/
|
||||
int activate_lv_excl(struct cmd_context *cmd, const struct logical_volume *lv)
|
||||
{
|
||||
/* Non-clustered VGs are only activated locally. */
|
||||
if (!vg_is_clustered(lv->vg))
|
||||
return activate_lv_excl_local(cmd, lv);
|
||||
|
||||
if (lv_is_active_exclusive_locally(lv))
|
||||
return 1;
|
||||
|
||||
if (!activate_lv_excl_local(cmd, lv))
|
||||
return_0;
|
||||
|
||||
if (lv_is_active_exclusive(lv))
|
||||
return 1;
|
||||
|
||||
/* FIXME Deal with error return codes. */
|
||||
if (!activate_lv_excl_remote(cmd, lv))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
return activate_lv_excl_local(cmd, lv);
|
||||
}
|
||||
|
||||
/* Lock a list of LVs */
|
||||
@ -428,35 +319,6 @@ int locking_is_clustered(void)
|
||||
return (_locking.flags & LCK_CLUSTERED) ? 1 : 0;
|
||||
}
|
||||
|
||||
int locking_supports_remote_queries(void)
|
||||
{
|
||||
return (_locking.flags & LCK_SUPPORTS_REMOTE_QUERIES) ? 1 : 0;
|
||||
}
|
||||
|
||||
int cluster_lock_held(const char *vol, const char *node, int *exclusive)
|
||||
{
|
||||
int mode = LCK_NULL;
|
||||
|
||||
if (!locking_is_clustered())
|
||||
return 0;
|
||||
|
||||
if (!_locking.query_resource)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* If an error occured, expect that volume is active
|
||||
*/
|
||||
if (!_locking.query_resource(vol, node, &mode)) {
|
||||
stack;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (exclusive)
|
||||
*exclusive = (mode == LCK_EXCL);
|
||||
|
||||
return mode == LCK_NULL ? 0 : 1;
|
||||
}
|
||||
|
||||
int sync_local_dev_names(struct cmd_context* cmd)
|
||||
{
|
||||
memlock_unlock(cmd);
|
||||
|
@ -50,9 +50,3 @@ int init_readonly_locking(struct locking_type *locking, struct cmd_context *cmd,
|
||||
|
||||
int init_file_locking(struct locking_type *locking, struct cmd_context *cmd,
|
||||
int suppress_messages);
|
||||
|
||||
int init_external_locking(struct locking_type *locking, struct cmd_context *cmd,
|
||||
int suppress_messages);
|
||||
|
||||
int init_cluster_locking(struct locking_type *locking, struct cmd_context *cmd,
|
||||
int suppress_messages);
|
||||
|
@ -1,126 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2007 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "lib/misc/lib.h"
|
||||
#include "lib/locking/locking.h"
|
||||
#include "locking_types.h"
|
||||
#include "lib/misc/lvm-string.h"
|
||||
#include "lib/activate/activate.h"
|
||||
|
||||
/*
|
||||
* No locking
|
||||
*/
|
||||
|
||||
static void _no_fin_locking(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void _no_reset_locking(void)
|
||||
{
|
||||
}
|
||||
|
||||
static int _no_lock_resource(struct cmd_context *cmd, const char *resource,
|
||||
uint32_t flags, const struct logical_volume *lv)
|
||||
{
|
||||
switch (flags & LCK_SCOPE_MASK) {
|
||||
case LCK_ACTIVATION:
|
||||
break;
|
||||
case LCK_VG:
|
||||
if (!strcmp(resource, VG_SYNC_NAMES))
|
||||
fs_unlock();
|
||||
break;
|
||||
case LCK_LV:
|
||||
switch (flags & LCK_TYPE_MASK) {
|
||||
case LCK_NULL:
|
||||
return lv_deactivate(cmd, resource, lv_committed(lv));
|
||||
case LCK_UNLOCK:
|
||||
return lv_resume_if_active(cmd, resource, (flags & LCK_ORIGIN_ONLY) ? 1: 0, 0,
|
||||
(flags & LCK_REVERT) ? 1 : 0, lv_committed(lv));
|
||||
case LCK_READ:
|
||||
return lv_activate_with_filter(cmd, resource, 0, (lv->status & LV_NOSCAN) ? 1 : 0,
|
||||
(lv->status & LV_TEMPORARY) ? 1 : 0, lv_committed(lv));
|
||||
case LCK_WRITE:
|
||||
return lv_suspend_if_active(cmd, resource, (flags & LCK_ORIGIN_ONLY) ? 1 : 0, 0,
|
||||
lv_committed(lv), lv);
|
||||
case LCK_EXCL:
|
||||
return lv_activate_with_filter(cmd, resource, 1, (lv->status & LV_NOSCAN) ? 1 : 0,
|
||||
(lv->status & LV_TEMPORARY) ? 1 : 0, lv_committed(lv));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
log_error("Unrecognised lock scope: %d",
|
||||
flags & LCK_SCOPE_MASK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _no_query_resource(const char *resource, const char *node, int *mode)
|
||||
{
|
||||
log_very_verbose("Locking is disabled: Treating lock %s as not held.",
|
||||
resource);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _readonly_lock_resource(struct cmd_context *cmd,
|
||||
const char *resource,
|
||||
uint32_t flags, const struct logical_volume *lv)
|
||||
{
|
||||
if ((flags & LCK_TYPE_MASK) == LCK_WRITE &&
|
||||
(flags & LCK_SCOPE_MASK) == LCK_VG &&
|
||||
!(flags & LCK_CACHE) &&
|
||||
strcmp(resource, VG_GLOBAL)) {
|
||||
log_error("Read-only locking type set. "
|
||||
"Write locks are prohibited.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _no_lock_resource(cmd, resource, flags, lv);
|
||||
}
|
||||
|
||||
void init_no_locking(struct locking_type *locking, struct cmd_context *cmd __attribute__((unused)),
|
||||
int suppress_messages)
|
||||
{
|
||||
locking->lock_resource = _no_lock_resource;
|
||||
locking->query_resource = _no_query_resource;
|
||||
locking->reset_locking = _no_reset_locking;
|
||||
locking->fin_locking = _no_fin_locking;
|
||||
locking->flags = LCK_CLUSTERED;
|
||||
}
|
||||
|
||||
int init_readonly_locking(struct locking_type *locking, struct cmd_context *cmd __attribute__((unused)),
|
||||
int suppress_messages)
|
||||
{
|
||||
locking->lock_resource = _readonly_lock_resource;
|
||||
locking->query_resource = _no_query_resource;
|
||||
locking->reset_locking = _no_reset_locking;
|
||||
locking->fin_locking = _no_fin_locking;
|
||||
locking->flags = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void init_dummy_locking(struct locking_type *locking, struct cmd_context *cmd __attribute__((unused)),
|
||||
int suppress_messages)
|
||||
{
|
||||
locking->lock_resource = _readonly_lock_resource;
|
||||
locking->query_resource = _no_query_resource;
|
||||
locking->reset_locking = _no_reset_locking;
|
||||
locking->fin_locking = _no_fin_locking;
|
||||
locking->flags = LCK_CLUSTERED;
|
||||
}
|
@ -1478,21 +1478,11 @@ int lv_active_change(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
|
||||
switch (activate) {
|
||||
case CHANGE_AN:
|
||||
deactivate:
|
||||
log_verbose("Deactivating logical volume %s.", display_lvname(lv));
|
||||
if (!deactivate_lv(cmd, lv))
|
||||
return_0;
|
||||
break;
|
||||
case CHANGE_ALN:
|
||||
if (vg_is_clustered(lv->vg) && (needs_exclusive || _lv_is_exclusive(lv))) {
|
||||
if (!lv_is_active_locally(lv)) {
|
||||
log_error("Cannot deactivate remotely exclusive device %s locally.",
|
||||
display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
/* Unlock whole exclusive activation */
|
||||
goto deactivate;
|
||||
}
|
||||
log_verbose("Deactivating logical volume %s locally.",
|
||||
display_lvname(lv));
|
||||
if (!deactivate_lv_local(cmd, lv))
|
||||
|
@ -7366,7 +7366,6 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
struct logical_volume *lv, *origin_lv = NULL;
|
||||
struct logical_volume *pool_lv = NULL;
|
||||
struct logical_volume *tmp_lv;
|
||||
const struct logical_volume *lock_lv;
|
||||
struct lv_segment *seg, *pool_seg;
|
||||
int thin_pool_was_active = -1; /* not scanned, inactive, active */
|
||||
int historical;
|
||||
@ -7528,18 +7527,6 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
log_error("Caching of origin cache volume smaller then chunk size is unsupported.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Validate cache origin is exclusively active */
|
||||
lock_lv = lv_lock_holder(origin_lv);
|
||||
if (vg_is_clustered(origin_lv->vg) &&
|
||||
locking_is_clustered() &&
|
||||
locking_supports_remote_queries() &&
|
||||
lv_is_active(lock_lv) &&
|
||||
!lv_is_active_exclusive(lock_lv)) {
|
||||
log_error("Cannot cache not exclusively active origin volume %s.",
|
||||
display_lvname(origin_lv));
|
||||
return NULL;
|
||||
}
|
||||
} else if (seg_is_cache(lp)) {
|
||||
if (!pool_lv) {
|
||||
log_error(INTERNAL_ERROR "Pool LV for cache is missing.");
|
||||
@ -7555,13 +7542,6 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
if (!(create_segtype = get_segtype_from_string(vg->cmd, SEG_TYPE_NAME_STRIPED)))
|
||||
return_0;
|
||||
} else if (seg_is_mirrored(lp) || (seg_is_raid(lp) && !seg_is_any_raid0(lp))) {
|
||||
if (is_change_activating(lp->activate) && (lp->activate != CHANGE_AEY) &&
|
||||
vg_is_clustered(vg) && seg_is_mirrored(lp) && !seg_is_raid(lp) &&
|
||||
!cluster_mirror_is_available(vg->cmd)) {
|
||||
log_error("Shared cluster mirrors are not available.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(lp->region_size = adjusted_mirror_region_size(vg->cmd,
|
||||
vg->extent_size,
|
||||
lp->extents,
|
||||
|
@ -1843,13 +1843,6 @@ int vgs_are_compatible(struct cmd_context *cmd __attribute__((unused)),
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Clustering attribute must be the same */
|
||||
if (vg_is_clustered(vg_to) != vg_is_clustered(vg_from)) {
|
||||
log_error("Clustered attribute differs for \"%s\" and \"%s\"",
|
||||
vg_to->name, vg_from->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check no conflicts with LV names */
|
||||
dm_list_iterate_items(lvl1, &vg_to->lvs) {
|
||||
name1 = lvl1->lv->name;
|
||||
@ -4564,123 +4557,6 @@ void free_pv_fid(struct physical_volume *pv)
|
||||
pv_set_fid(pv, NULL);
|
||||
}
|
||||
|
||||
/* This is only called by lv_from_lvid, which is only called from
|
||||
* activate.c so we know the appropriate VG lock is already held and
|
||||
* the vg_read_internal is therefore safe.
|
||||
*/
|
||||
struct volume_group *vg_read_by_vgid(struct cmd_context *cmd,
|
||||
const char *vgid,
|
||||
unsigned precommitted)
|
||||
{
|
||||
const char *vgname;
|
||||
struct volume_group *vg;
|
||||
uint32_t warn_flags = WARN_PV_READ | WARN_INCONSISTENT;
|
||||
int consistent = 0;
|
||||
|
||||
/*
|
||||
* When using lvmlockd we should never reach this point.
|
||||
* The VG is locked, then vg_read() is done, which gets
|
||||
* the latest VG from lvmetad, or disk if lvmetad has
|
||||
* been invalidated. When we get here the VG should
|
||||
* always be cached and returned above.
|
||||
*/
|
||||
if (lvmlockd_use())
|
||||
log_error(INTERNAL_ERROR "vg_read_by_vgid failed with lvmlockd");
|
||||
|
||||
if ((vg = lvmcache_get_saved_vg(vgid, precommitted))) {
|
||||
log_debug_metadata("lvmcache: using saved_vg %s seqno %d pre %d %p",
|
||||
vg->name, vg->seqno, precommitted, vg);
|
||||
return vg;
|
||||
}
|
||||
|
||||
/* Mustn't scan if memory locked: ensure cache gets pre-populated! */
|
||||
if (critical_section())
|
||||
log_debug_metadata("Reading VG by vgid in critical section pre %d vgid %.8s", precommitted, vgid);
|
||||
|
||||
if (!(vgname = lvmcache_vgname_from_vgid(cmd->mem, vgid))) {
|
||||
log_debug_metadata("Reading VG by vgid %.8s no VG name found, retrying.", vgid);
|
||||
lvmcache_destroy(cmd, 1, 0);
|
||||
label_scan_destroy(cmd);
|
||||
lvmcache_label_scan(cmd);
|
||||
warn_flags |= SKIP_RESCAN;
|
||||
}
|
||||
|
||||
if (!(vgname = lvmcache_vgname_from_vgid(cmd->mem, vgid))) {
|
||||
log_debug_metadata("Reading VG by vgid %.8s no VG name found.", vgid);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
consistent = 0;
|
||||
|
||||
label_scan_setup_bcache();
|
||||
|
||||
if (!(vg = _vg_read(cmd, vgname, vgid, 0, warn_flags, &consistent, precommitted))) {
|
||||
log_error("Rescan devices to look for missing VG.");
|
||||
goto scan;
|
||||
}
|
||||
|
||||
if (vg_missing_pv_count(vg)) {
|
||||
log_error("Rescan devices to look for missing PVs.");
|
||||
release_vg(vg);
|
||||
goto scan;
|
||||
}
|
||||
|
||||
label_scan_destroy(cmd); /* drop bcache to close devs, keep lvmcache */
|
||||
lvmcache_save_vg(vg, precommitted);
|
||||
return vg;
|
||||
|
||||
scan:
|
||||
lvmcache_destroy(cmd, 1, 0);
|
||||
label_scan_destroy(cmd);
|
||||
lvmcache_label_scan(cmd);
|
||||
warn_flags |= SKIP_RESCAN;
|
||||
|
||||
if (!(vg = _vg_read(cmd, vgname, vgid, 0, warn_flags, &consistent, precommitted)))
|
||||
goto fail;
|
||||
|
||||
label_scan_destroy(cmd); /* drop bcache to close devs, keep lvmcache */
|
||||
|
||||
lvmcache_save_vg(vg, precommitted);
|
||||
return vg;
|
||||
|
||||
fail:
|
||||
label_scan_destroy(cmd); /* drop bache to close devs, keep lvmcache */
|
||||
log_debug_metadata("Reading VG by vgid %.8s not found.", vgid);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Only called by activate.c */
|
||||
struct logical_volume *lv_from_lvid(struct cmd_context *cmd, const char *lvid_s,
|
||||
unsigned precommitted)
|
||||
{
|
||||
struct logical_volume *lv;
|
||||
struct volume_group *vg;
|
||||
const union lvid *lvid;
|
||||
|
||||
lvid = (const union lvid *) lvid_s;
|
||||
|
||||
log_very_verbose("Finding %svolume group for uuid %s", precommitted ? "precommitted " : "", lvid_s);
|
||||
if (!(vg = vg_read_by_vgid(cmd, (const char *)lvid->id[0].uuid, precommitted))) {
|
||||
log_error("Reading VG not found for LVID %s", lvid_s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
log_verbose("Found volume group \"%s\" %p", vg->name, vg);
|
||||
if (vg->status & EXPORTED_VG) {
|
||||
log_error("Volume group \"%s\" is exported", vg->name);
|
||||
goto out;
|
||||
}
|
||||
if (!(lv = find_lv_in_vg_by_lvid(vg, lvid))) {
|
||||
log_very_verbose("Can't find logical volume id %s", lvid_s);
|
||||
goto out;
|
||||
}
|
||||
|
||||
return lv;
|
||||
out:
|
||||
release_vg(vg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *find_vgname_from_pvid(struct cmd_context *cmd,
|
||||
const char *pvid)
|
||||
{
|
||||
@ -5127,7 +5003,7 @@ int vg_flag_write_locked(struct volume_group *vg)
|
||||
|
||||
static int _access_vg_clustered(struct cmd_context *cmd, const struct volume_group *vg)
|
||||
{
|
||||
if (vg_is_clustered(vg) && !locking_is_clustered()) {
|
||||
if (vg_is_clustered(vg)) {
|
||||
if (!cmd->ignore_clustered_vgs)
|
||||
log_error("Skipping clustered volume group %s", vg->name);
|
||||
else
|
||||
|
@ -374,18 +374,9 @@ int add_pv_to_vg(struct volume_group *vg, const char *pv_name,
|
||||
struct logical_volume *find_lv_in_vg_by_lvid(struct volume_group *vg,
|
||||
const union lvid *lvid);
|
||||
|
||||
struct volume_group *vg_read_by_vgid(struct cmd_context *cmd,
|
||||
const char *vgid,
|
||||
unsigned precommitted);
|
||||
|
||||
struct lv_list *find_lv_in_lv_list(const struct dm_list *ll,
|
||||
const struct logical_volume *lv);
|
||||
|
||||
/* Find LV with given lvid (used during activation) */
|
||||
struct logical_volume *lv_from_lvid(struct cmd_context *cmd,
|
||||
const char *lvid_s,
|
||||
unsigned precommitted);
|
||||
|
||||
/* FIXME Merge these functions with ones above */
|
||||
struct physical_volume *find_pv(struct volume_group *vg, struct device *dev);
|
||||
|
||||
|
@ -612,56 +612,6 @@ int vg_set_alloc_policy(struct volume_group *vg, alloc_policy_t alloc)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Setting the cluster attribute marks active volumes exclusive.
|
||||
*
|
||||
* FIXME: resolve logic with reacquiring proper top-level LV locks
|
||||
* and we likely can't giveup DLM locks for active LVs...
|
||||
*/
|
||||
int vg_set_clustered(struct volume_group *vg, int clustered)
|
||||
{
|
||||
struct lv_list *lvl;
|
||||
int fail = 0;
|
||||
|
||||
if (vg_is_clustered(vg) &&
|
||||
locking_is_clustered() &&
|
||||
locking_supports_remote_queries() &&
|
||||
!clustered) {
|
||||
/*
|
||||
* If the volume is locally active but not exclusively
|
||||
* we cannot determine when other nodes also use
|
||||
* locally active (CR lock), so refuse conversion.
|
||||
*/
|
||||
dm_list_iterate_items(lvl, &vg->lvs)
|
||||
if ((lv_lock_holder(lvl->lv) == lvl->lv) &&
|
||||
lv_is_active(lvl->lv) &&
|
||||
!lv_is_active_exclusive_locally(lvl->lv)) {
|
||||
/* Show all non-local-exclusively active LVs
|
||||
* this includes i.e. clustered mirrors */
|
||||
log_error("Can't change cluster attribute with "
|
||||
"active logical volume %s.",
|
||||
display_lvname(lvl->lv));
|
||||
fail = 1;
|
||||
}
|
||||
|
||||
if (fail) {
|
||||
log_print_unless_silent("Conversion is supported only for "
|
||||
"locally exclusive volumes.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (clustered)
|
||||
vg->status |= CLUSTERED;
|
||||
else
|
||||
vg->status &= ~CLUSTERED;
|
||||
|
||||
log_debug_metadata("Setting volume group %s as %sclustered.",
|
||||
vg->name, clustered ? "" : "not " );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* The input string has already been validated. */
|
||||
|
||||
int vg_set_system_id(struct volume_group *vg, const char *system_id)
|
||||
|
@ -181,7 +181,6 @@ char *vg_lock_args_dup(const struct volume_group *vg);
|
||||
uint32_t vg_seqno(const struct volume_group *vg);
|
||||
uint64_t vg_status(const struct volume_group *vg);
|
||||
int vg_set_alloc_policy(struct volume_group *vg, alloc_policy_t alloc);
|
||||
int vg_set_clustered(struct volume_group *vg, int clustered);
|
||||
int vg_set_system_id(struct volume_group *vg, const char *system_id);
|
||||
int vg_set_lock_type(struct volume_group *vg, const char *lock_type);
|
||||
uint64_t vg_size(const struct volume_group *vg);
|
||||
|
@ -278,14 +278,7 @@ static int _add_log(struct dm_pool *mem, struct lv_segment *seg,
|
||||
char *log_dlid = NULL;
|
||||
uint32_t log_flags = 0;
|
||||
|
||||
/*
|
||||
* Use clustered mirror log for non-exclusive activation
|
||||
* in clustered VG.
|
||||
*/
|
||||
if (!laopts->exclusive && vg_is_clustered(seg->lv->vg))
|
||||
clustered = 1;
|
||||
|
||||
else if (seg->lv->vg->lock_type && !strcmp(seg->lv->vg->lock_type, "dlm")) {
|
||||
if (seg->lv->vg->lock_type && !strcmp(seg->lv->vg->lock_type, "dlm")) {
|
||||
/*
|
||||
* If shared lock was used due to -asy, then we set clustered
|
||||
* to use a clustered mirror log with cmirrod.
|
||||
@ -521,12 +514,6 @@ static int _mirrored_modules_needed(struct dm_pool *mem,
|
||||
!list_segment_modules(mem, first_seg(seg->log_lv), modules))
|
||||
return_0;
|
||||
|
||||
if (vg_is_clustered(seg->lv->vg) &&
|
||||
!str_list_add(mem, modules, MODULE_NAME_CLUSTERED_MIRROR)) {
|
||||
log_error("cluster log string list allocation failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!str_list_add(mem, modules, MODULE_NAME_MIRROR)) {
|
||||
log_error("mirror string list allocation failed");
|
||||
return 0;
|
||||
|
13
tools/args.h
13
tools/args.h
@ -949,17 +949,8 @@ arg(chunksize_ARG, 'c', "chunksize", sizekb_VAL, 0, 0,
|
||||
"See \\fBlvmthin\\fP(7) and \\fBlvmcache\\fP(7) for more information.\n")
|
||||
|
||||
arg(clustered_ARG, 'c', "clustered", bool_VAL, 0, 0,
|
||||
"#vgcreate\n"
|
||||
"Create a clustered VG using clvmd if LVM is compiled with cluster support.\n"
|
||||
"This allows multiple hosts to share a VG on shared devices.\n"
|
||||
"clvmd and a lock manager must be configured and running.\n"
|
||||
"(A clustered VG using clvmd is different from a shared VG using lvmlockd.)\n"
|
||||
"See \\fBclvmd\\fP(8) for more information about clustered VGs.\n"
|
||||
"#vgchange\n"
|
||||
"Change the clustered property of a VG using clvmd.\n"
|
||||
"See \\fBclvmd\\fP(8) for more information about clustered VGs.\n"
|
||||
"#vgsplit\n"
|
||||
"Specifies the clustered property of the new VG.\n")
|
||||
"This option was specific to clvm and is now replaced by\n"
|
||||
"the --shared option with \\fBlvmlockd\\fP(8).\n")
|
||||
|
||||
arg(colon_ARG, 'c', "colon", 0, 0, 0,
|
||||
"Generate colon separated output for easier parsing in scripts or programs.\n"
|
||||
|
@ -1482,7 +1482,7 @@ OO_VGCHANGE: --autobackup Bool, --ignoremonitoring, --ignoreskippedcluster,
|
||||
|
||||
OO_VGCHANGE_META: --addtag Tag, --deltag Tag,
|
||||
--logicalvolume Uint32, --maxphysicalvolumes Uint32, --alloc Alloc, --uuid,
|
||||
--clustered Bool, --pvmetadatacopies MetadataCopiesPV, --vgmetadatacopies MetadataCopiesVG,
|
||||
--pvmetadatacopies MetadataCopiesPV, --vgmetadatacopies MetadataCopiesVG,
|
||||
--physicalextentsize SizeMB, --resizeable Bool,
|
||||
--profile String, --detachprofile, --metadataprofile String
|
||||
|
||||
@ -1692,7 +1692,7 @@ ID: vgscan_general
|
||||
OO_VGSPLIT: --autobackup Bool
|
||||
|
||||
# used only when the destination VG is new
|
||||
OO_VGSPLIT_NEW: --alloc Alloc, --clustered Bool,
|
||||
OO_VGSPLIT_NEW: --alloc Alloc,
|
||||
--maxlogicalvolumes Uint32, --maxphysicalvolumes Uint32,
|
||||
--metadatatype MetadataType, --vgmetadatacopies MetadataCopiesVG
|
||||
|
||||
|
@ -74,13 +74,6 @@ static int _lvchange_permission(struct cmd_context *cmd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lv_is_mirrored(lv) && vg_is_clustered(lv->vg) &&
|
||||
lv_info(cmd, lv, 0, &info, 0, 0) && info.exists) {
|
||||
log_error("Cannot change permissions of mirror %s while active.",
|
||||
display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lv_access & LVM_WRITE) {
|
||||
lv->status |= LVM_WRITE;
|
||||
log_verbose("Setting logical volume %s read/write.",
|
||||
@ -362,12 +355,6 @@ static int _lvchange_resync(struct cmd_context *cmd, struct logical_volume *lv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vg_is_clustered(lv->vg) && lv_is_active(lv)) {
|
||||
log_error("Can't get exclusive access to clustered volume %s.",
|
||||
display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (monitored != DMEVENTD_MONITOR_IGNORE)
|
||||
init_dmeventd_monitor(monitored);
|
||||
init_mirror_in_sync(0);
|
||||
@ -617,16 +604,6 @@ static int _lvchange_persistent(struct cmd_context *cmd,
|
||||
}
|
||||
|
||||
activate = CHANGE_AEY;
|
||||
if (vg_is_clustered(lv->vg) &&
|
||||
locking_is_clustered() &&
|
||||
locking_supports_remote_queries() &&
|
||||
!lv_is_active_exclusive_locally(lv)) {
|
||||
/* Reliable reactivate only locally */
|
||||
log_print_unless_silent("Remotely active LV %s needs "
|
||||
"individual reactivation.",
|
||||
display_lvname(lv));
|
||||
activate = CHANGE_ALY;
|
||||
}
|
||||
}
|
||||
|
||||
/* Ensuring LV is not active */
|
||||
@ -1255,12 +1232,6 @@ static int _lvchange_properties_check(struct cmd_context *cmd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vg_is_clustered(lv->vg) && lv_is_cache_origin(lv) && lv_is_raid(lv)) {
|
||||
log_error("Unable to change internal LV %s directly in a cluster.",
|
||||
display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -780,15 +780,6 @@ static int _lvconvert_mirrors_parse_params(struct cmd_context *cmd,
|
||||
|
||||
*new_log_count = arg_int_value(cmd, mirrorlog_ARG, lp->corelog ? MIRROR_LOG_CORE : DEFAULT_MIRRORLOG);
|
||||
|
||||
/*
|
||||
* No mirrored logs for cluster mirrors until
|
||||
* log daemon is multi-threaded.
|
||||
*/
|
||||
if ((*new_log_count == MIRROR_LOG_MIRRORED) && vg_is_clustered(lv->vg)) {
|
||||
log_error("Log type, \"mirrored\", is unavailable to cluster mirrors.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_verbose("Setting logging type to %s.", get_mirror_log_name(*new_log_count));
|
||||
|
||||
/*
|
||||
@ -2054,10 +2045,6 @@ static int _lvconvert_merge_old_snapshot(struct cmd_context *cmd,
|
||||
log_print_unless_silent("Delaying merge since snapshot is open.");
|
||||
merge_on_activate = 1;
|
||||
}
|
||||
} else if (vg_is_clustered(origin->vg) && lv_is_active(origin)) {
|
||||
/* When it's active somewhere else */
|
||||
log_print_unless_silent("Delaying merge since origin is remotely active.");
|
||||
merge_on_activate = 1;
|
||||
}
|
||||
|
||||
init_snapshot_merge(snap_seg, origin);
|
||||
|
@ -2698,11 +2698,6 @@ static int _init_lvmlockd(struct cmd_context *cmd)
|
||||
}
|
||||
}
|
||||
|
||||
if (use_lvmlockd && locking_is_clustered()) {
|
||||
log_error("ERROR: configuration setting use_lvmlockd cannot be used with clustered locking_type 3.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
lvmlockd_disconnect(); /* start over when tool context is refreshed */
|
||||
lvmlockd_socket = getenv("LVM_LVMLOCKD_SOCKET");
|
||||
if (!lvmlockd_socket)
|
||||
|
@ -67,10 +67,6 @@ static int _pvmove_target_present(struct cmd_context *cmd, int clustered)
|
||||
static unsigned _pvmove_is_exclusive(struct cmd_context *cmd,
|
||||
struct volume_group *vg)
|
||||
{
|
||||
if (vg_is_clustered(vg))
|
||||
if (!_pvmove_target_present(cmd, 1))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -726,7 +726,6 @@ int vgcreate_params_set_defaults(struct cmd_context *cmd,
|
||||
vp_def->max_pv = vg->max_pv;
|
||||
vp_def->max_lv = vg->max_lv;
|
||||
vp_def->alloc = vg->alloc;
|
||||
vp_def->clustered = vg_is_clustered(vg);
|
||||
vp_def->vgmetadatacopies = vg->mda_copies;
|
||||
vp_def->system_id = vg->system_id; /* No need to clone this */
|
||||
} else {
|
||||
@ -741,7 +740,6 @@ int vgcreate_params_set_defaults(struct cmd_context *cmd,
|
||||
vp_def->max_pv = DEFAULT_MAX_PV;
|
||||
vp_def->max_lv = DEFAULT_MAX_LV;
|
||||
vp_def->alloc = DEFAULT_ALLOC_POLICY;
|
||||
vp_def->clustered = DEFAULT_CLUSTERED;
|
||||
vp_def->vgmetadatacopies = DEFAULT_VGMETADATACOPIES;
|
||||
vp_def->system_id = cmd->system_id;
|
||||
}
|
||||
@ -761,11 +759,14 @@ int vgcreate_params_set_from_args(struct cmd_context *cmd,
|
||||
{
|
||||
const char *system_id_arg_str;
|
||||
const char *lock_type = NULL;
|
||||
int locking_type;
|
||||
int use_lvmlockd;
|
||||
int use_clvmd;
|
||||
lock_type_t lock_type_num;
|
||||
|
||||
if (arg_is_set(cmd, clustered_ARG)) {
|
||||
log_error("The clustered option is deprecated, see --shared.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
vp_new->vg_name = skip_dev_dir(cmd, vp_def->vg_name, NULL);
|
||||
vp_new->max_lv = arg_uint_value(cmd, maxlogicalvolumes_ARG,
|
||||
vp_def->max_lv);
|
||||
@ -904,16 +905,9 @@ int vgcreate_params_set_from_args(struct cmd_context *cmd,
|
||||
* - 'vgcreate' (neither option) creates a local VG
|
||||
*/
|
||||
|
||||
locking_type = find_config_tree_int(cmd, global_locking_type_CFG, NULL);
|
||||
use_lvmlockd = find_config_tree_bool(cmd, global_use_lvmlockd_CFG, NULL);
|
||||
use_clvmd = (locking_type == 3);
|
||||
|
||||
if (arg_is_set(cmd, locktype_ARG)) {
|
||||
if (arg_is_set(cmd, clustered_ARG)) {
|
||||
log_error("A lock type cannot be specified with --clustered.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
lock_type = arg_str_value(cmd, locktype_ARG, "");
|
||||
|
||||
if (arg_is_set(cmd, shared_ARG) && !is_lockd_type(lock_type)) {
|
||||
@ -921,26 +915,6 @@ int vgcreate_params_set_from_args(struct cmd_context *cmd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
} else if (arg_is_set(cmd, clustered_ARG)) {
|
||||
const char *arg_str = arg_str_value(cmd, clustered_ARG, "");
|
||||
int clustery = strcmp(arg_str, "y") ? 0 : 1;
|
||||
|
||||
if (use_clvmd) {
|
||||
lock_type = clustery ? "clvm" : "none";
|
||||
|
||||
} else if (use_lvmlockd) {
|
||||
log_error("lvmlockd is configured, use --shared with lvmlockd, and --clustered with clvmd.");
|
||||
return 0;
|
||||
|
||||
} else {
|
||||
if (clustery) {
|
||||
log_error("The --clustered option requires clvmd (locking_type=3).");
|
||||
return 0;
|
||||
}
|
||||
|
||||
lock_type = "none";
|
||||
}
|
||||
|
||||
} else if (arg_is_set(cmd, shared_ARG)) {
|
||||
int found_multiple = 0;
|
||||
|
||||
@ -953,20 +927,13 @@ int vgcreate_params_set_from_args(struct cmd_context *cmd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
} else if (use_clvmd) {
|
||||
log_error("Use --shared with lvmlockd, and --clustered with clvmd.");
|
||||
return 0;
|
||||
|
||||
} else {
|
||||
log_error("Using a shared lock type requires lvmlockd.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (use_clvmd)
|
||||
lock_type = locking_is_clustered() ? "clvm" : "none";
|
||||
else
|
||||
lock_type = "none";
|
||||
lock_type = "none";
|
||||
}
|
||||
|
||||
/*
|
||||
@ -977,6 +944,7 @@ int vgcreate_params_set_from_args(struct cmd_context *cmd,
|
||||
|
||||
switch (lock_type_num) {
|
||||
case LOCK_TYPE_INVALID:
|
||||
case LOCK_TYPE_CLVM:
|
||||
log_error("lock_type %s is invalid", lock_type);
|
||||
return 0;
|
||||
|
||||
@ -987,12 +955,6 @@ int vgcreate_params_set_from_args(struct cmd_context *cmd,
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case LOCK_TYPE_CLVM:
|
||||
if (!use_clvmd) {
|
||||
log_error("Using clvm requires locking_type 3.");
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case LOCK_TYPE_NONE:
|
||||
break;
|
||||
};
|
||||
@ -1001,16 +963,11 @@ int vgcreate_params_set_from_args(struct cmd_context *cmd,
|
||||
* The vg is not owned by one host/system_id.
|
||||
* Locking coordinates access from multiple hosts.
|
||||
*/
|
||||
if (lock_type_num == LOCK_TYPE_DLM || lock_type_num == LOCK_TYPE_SANLOCK || lock_type_num == LOCK_TYPE_CLVM)
|
||||
if (lock_type_num == LOCK_TYPE_DLM || lock_type_num == LOCK_TYPE_SANLOCK)
|
||||
vp_new->system_id = NULL;
|
||||
|
||||
vp_new->lock_type = lock_type;
|
||||
|
||||
if (lock_type_num == LOCK_TYPE_CLVM)
|
||||
vp_new->clustered = 1;
|
||||
else
|
||||
vp_new->clustered = 0;
|
||||
|
||||
log_debug("Setting lock_type to %s", vp_new->lock_type);
|
||||
return 1;
|
||||
}
|
||||
|
139
tools/vgchange.c
139
tools/vgchange.c
@ -308,84 +308,6 @@ static int _vgchange_resizeable(struct cmd_context *cmd,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _vgchange_clustered(struct cmd_context *cmd,
|
||||
struct volume_group *vg)
|
||||
{
|
||||
int clustered = arg_int_value(cmd, clustered_ARG, 0);
|
||||
const char *lock_type = arg_str_value(cmd, locktype_ARG, NULL);
|
||||
struct lv_list *lvl;
|
||||
struct lv_segment *mirror_seg;
|
||||
|
||||
if (find_config_tree_bool(cmd, global_use_lvmlockd_CFG, NULL)) {
|
||||
log_error("lvmlockd requires using the vgchange --lock-type option.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lock_type && !strcmp(lock_type, "clvm"))
|
||||
clustered = 1;
|
||||
|
||||
if (clustered && vg_is_clustered(vg)) {
|
||||
if (vg->system_id && *vg->system_id)
|
||||
log_warn("WARNING: Clearing invalid system ID %s from volume group %s.",
|
||||
vg->system_id, vg->name);
|
||||
else {
|
||||
log_error("Volume group \"%s\" is already clustered", vg->name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!clustered && !vg_is_clustered(vg)) {
|
||||
if ((!vg->system_id || !*vg->system_id) && cmd->system_id && *cmd->system_id)
|
||||
log_warn("Setting missing system ID on Volume Group %s to %s.",
|
||||
vg->name, cmd->system_id);
|
||||
else {
|
||||
log_error("Volume group \"%s\" is already not clustered",
|
||||
vg->name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (clustered && !arg_is_set(cmd, yes_ARG)) {
|
||||
if (!clvmd_is_running()) {
|
||||
if (yes_no_prompt("LVM cluster daemon (clvmd) is not running. "
|
||||
"Make volume group \"%s\" clustered "
|
||||
"anyway? [y/n]: ", vg->name) == 'n') {
|
||||
log_error("No volume groups changed.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
} else if (!locking_is_clustered() &&
|
||||
(yes_no_prompt("LVM locking type is not clustered. "
|
||||
"Make volume group \"%s\" clustered "
|
||||
"anyway? [y/n]: ", vg->name) == 'n')) {
|
||||
log_error("No volume groups changed.");
|
||||
return 0;
|
||||
}
|
||||
#ifdef CMIRROR_REGION_COUNT_LIMIT
|
||||
dm_list_iterate_items(lvl, &vg->lvs) {
|
||||
if (!lv_is_mirror(lvl->lv))
|
||||
continue;
|
||||
mirror_seg = first_seg(lvl->lv);
|
||||
if ((lvl->lv->size / mirror_seg->region_size) >
|
||||
CMIRROR_REGION_COUNT_LIMIT) {
|
||||
log_error("Unable to convert %s to clustered mode:"
|
||||
" Mirror region size of %s is too small.",
|
||||
vg->name, lvl->lv->name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!vg_set_system_id(vg, clustered ? NULL : cmd->system_id))
|
||||
return_0;
|
||||
|
||||
if (!vg_set_clustered(vg, clustered))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _vgchange_logicalvolume(struct cmd_context *cmd,
|
||||
struct volume_group *vg)
|
||||
{
|
||||
@ -676,7 +598,6 @@ static int _vgchange_single(struct cmd_context *cmd, const char *vg_name,
|
||||
{
|
||||
int ret = ECMD_PROCESSED;
|
||||
unsigned i;
|
||||
struct lv_list *lvl;
|
||||
|
||||
static const struct {
|
||||
int arg;
|
||||
@ -690,7 +611,6 @@ static int _vgchange_single(struct cmd_context *cmd, const char *vg_name,
|
||||
{ physicalextentsize_ARG, &_vgchange_pesize },
|
||||
{ uuid_ARG, &_vgchange_uuid },
|
||||
{ alloc_ARG, &_vgchange_alloc },
|
||||
{ clustered_ARG, &_vgchange_clustered },
|
||||
{ vgmetadatacopies_ARG, &_vgchange_metadata_copies },
|
||||
{ metadataprofile_ARG, &_vgchange_profile },
|
||||
{ profile_ARG, &_vgchange_profile },
|
||||
@ -731,31 +651,6 @@ static int _vgchange_single(struct cmd_context *cmd, const char *vg_name,
|
||||
backup(vg);
|
||||
|
||||
log_print_unless_silent("Volume group \"%s\" successfully changed", vg->name);
|
||||
|
||||
/* FIXME: fix clvmd bug and take DLM lock for non clustered VGs. */
|
||||
if (arg_is_set(cmd, clustered_ARG) &&
|
||||
vg_is_clustered(vg) && /* just switched to clustered */
|
||||
locking_is_clustered() &&
|
||||
locking_supports_remote_queries())
|
||||
dm_list_iterate_items(lvl, &vg->lvs) {
|
||||
if ((lv_lock_holder(lvl->lv) != lvl->lv) ||
|
||||
!lv_is_active(lvl->lv))
|
||||
continue;
|
||||
|
||||
if (!activate_lv_excl_local(cmd, lvl->lv) ||
|
||||
!lv_is_active_exclusive_locally(lvl->lv)) {
|
||||
log_error("Can't reactive logical volume %s, "
|
||||
"please fix manually.",
|
||||
display_lvname(lvl->lv));
|
||||
ret = ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (lv_is_mirror(lvl->lv))
|
||||
/* Give hint for clustered mirroring */
|
||||
log_print_unless_silent("For clustered mirroring of %s "
|
||||
"deactivation and activation is needed.",
|
||||
display_lvname(lvl->lv));
|
||||
}
|
||||
}
|
||||
|
||||
if (arg_is_set(cmd, activate_ARG)) {
|
||||
@ -810,7 +705,6 @@ int vgchange(struct cmd_context *cmd, int argc, char **argv)
|
||||
arg_is_set(cmd, resizeable_ARG) ||
|
||||
arg_is_set(cmd, uuid_ARG) ||
|
||||
arg_is_set(cmd, physicalextentsize_ARG) ||
|
||||
arg_is_set(cmd, clustered_ARG) ||
|
||||
arg_is_set(cmd, alloc_ARG) ||
|
||||
arg_is_set(cmd, vgmetadatacopies_ARG);
|
||||
|
||||
@ -964,22 +858,6 @@ static int _vgchange_locktype(struct cmd_context *cmd, struct volume_group *vg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* When lvm is currently using clvm, this function is just an alternative
|
||||
* to vgchange -c{y,n}, and can:
|
||||
* - change none to clvm
|
||||
* - change clvm to none
|
||||
* - it CANNOT change to or from a lockd type
|
||||
*/
|
||||
if (locking_is_clustered()) {
|
||||
if (is_lockd_type(lock_type)) {
|
||||
log_error("Changing to lock type %s requires lvmlockd.", lock_type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _vgchange_clustered(cmd, vg);
|
||||
}
|
||||
|
||||
/*
|
||||
* When lvm is currently using lvmlockd, this function can:
|
||||
* - change none to lockd type
|
||||
@ -996,14 +874,6 @@ static int _vgchange_locktype(struct cmd_context *cmd, struct volume_group *vg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* none to clvm */
|
||||
if (!strcmp(vg->lock_type, "none") && !strcmp(lock_type, "clvm")) {
|
||||
log_warn("New clvm lock type will not be usable with lvmlockd.");
|
||||
vg->status |= CLUSTERED;
|
||||
vg->lock_type = "clvm"; /* this is optional */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* clvm to none */
|
||||
if (!strcmp(vg->lock_type, "clvm") && !strcmp(lock_type, "none")) {
|
||||
vg->status &= ~CLUSTERED;
|
||||
@ -1033,15 +903,6 @@ static int _vgchange_locktype(struct cmd_context *cmd, struct volume_group *vg)
|
||||
lvl->lv->lock_args = NULL;
|
||||
}
|
||||
|
||||
/* ... to clvm */
|
||||
if (!strcmp(lock_type, "clvm")) {
|
||||
log_warn("New clvm lock type will not be usable with lvmlockd.");
|
||||
vg->status |= CLUSTERED;
|
||||
vg->lock_type = "clvm"; /* this is optional */
|
||||
vg->system_id = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ... to lockd type */
|
||||
if (is_lockd_type(lock_type)) {
|
||||
/*
|
||||
|
@ -23,7 +23,6 @@ int vgcreate(struct cmd_context *cmd, int argc, char **argv)
|
||||
struct vgcreate_params vp_def;
|
||||
struct volume_group *vg;
|
||||
const char *tag;
|
||||
const char *clustered_message = "";
|
||||
char *vg_name;
|
||||
struct arg_value_group_list *current_group;
|
||||
|
||||
@ -135,7 +134,6 @@ int vgcreate(struct cmd_context *cmd, int argc, char **argv)
|
||||
!vg_set_max_lv(vg, vp_new.max_lv) ||
|
||||
!vg_set_max_pv(vg, vp_new.max_pv) ||
|
||||
!vg_set_alloc_policy(vg, vp_new.alloc) ||
|
||||
!vg_set_clustered(vg, vp_new.clustered) ||
|
||||
!vg_set_system_id(vg, vp_new.system_id) ||
|
||||
!vg_set_mda_copies(vg, vp_new.vgmetadatacopies))
|
||||
goto_bad;
|
||||
@ -167,11 +165,6 @@ int vgcreate(struct cmd_context *cmd, int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
if (vg_is_clustered(vg))
|
||||
clustered_message = "Clustered ";
|
||||
else if (locking_is_clustered())
|
||||
clustered_message = "Non-clustered ";
|
||||
|
||||
if (!archive(vg))
|
||||
goto_bad;
|
||||
|
||||
@ -197,8 +190,8 @@ int vgcreate(struct cmd_context *cmd, int argc, char **argv)
|
||||
|
||||
backup(vg);
|
||||
|
||||
log_print_unless_silent("%s%colume group \"%s\" successfully created%s%s",
|
||||
clustered_message, *clustered_message ? 'v' : 'V', vg->name,
|
||||
log_print_unless_silent("Volume group \"%s\" successfully created%s%s",
|
||||
vg->name,
|
||||
vg->system_id ? " with system ID " : "", vg->system_id ? : "");
|
||||
|
||||
/*
|
||||
|
@ -646,7 +646,6 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv)
|
||||
!vg_set_max_lv(vg_to, vp_new.max_lv) ||
|
||||
!vg_set_max_pv(vg_to, vp_new.max_pv) ||
|
||||
!vg_set_alloc_policy(vg_to, vp_new.alloc) ||
|
||||
!vg_set_clustered(vg_to, vp_new.clustered) ||
|
||||
!vg_set_system_id(vg_to, vp_new.system_id) ||
|
||||
!vg_set_mda_copies(vg_to, vp_new.vgmetadatacopies))
|
||||
goto_bad;
|
||||
|
Loading…
Reference in New Issue
Block a user