1
0
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:
David Teigland 2018-06-05 10:47:01 -05:00
parent 11384637fb
commit 3e781ea446
47 changed files with 36 additions and 9364 deletions

View File

@ -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

View File

@ -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

View File

@ -1 +0,0 @@
clvmd

View File

@ -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,, &quot;@CLVMD@,&quot;))
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)

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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;
}
}

View File

@ -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

View File

@ -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;
}

View File

@ -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);

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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")

View File

@ -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
View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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))

View File

@ -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,

View File

@ -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

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -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;

View File

@ -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"

View File

@ -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

View File

@ -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;
}

View File

@ -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);

View File

@ -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)

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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)) {
/*

View File

@ -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 ? : "");
/*

View File

@ -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;