mirror of
git://sourceware.org/git/lvm2.git
synced 2025-09-26 01:44:19 +03:00
Compare commits
53 Commits
old-v2_00_
...
v2_00_24
Author | SHA1 | Date | |
---|---|---|---|
|
34d9b5e3d7 | ||
|
3bf5189d86 | ||
|
12e5b0681b | ||
|
8c0285d608 | ||
|
36558fa3b8 | ||
|
235f940cde | ||
|
803d61fcbc | ||
|
ffbd7d8de4 | ||
|
4ed924d7c7 | ||
|
798dc9948b | ||
|
13515f7ee4 | ||
|
ef80824c26 | ||
|
c8503fd65e | ||
|
b3c454fb1c | ||
|
1d7723e873 | ||
|
77100b2365 | ||
|
259a788134 | ||
|
39511455cb | ||
|
b04c16178e | ||
|
49a959c06e | ||
|
096a8932b4 | ||
|
e39e66df93 | ||
|
513633f49a | ||
|
eb3740daaf | ||
|
f7947b148a | ||
|
9a2a702f3f | ||
|
c65d95bf29 | ||
|
753a5edc4f | ||
|
0b3f853c2d | ||
|
3527fcf1d5 | ||
|
4544a89c7a | ||
|
ffeae9005e | ||
|
47217bcfb7 | ||
|
80ff58b57a | ||
|
d15dd368f1 | ||
|
8a2ec32bd8 | ||
|
410496ed52 | ||
|
b7b07552e5 | ||
|
44486e80d9 | ||
|
7890c527d8 | ||
|
2c82ab79a7 | ||
|
e3ebe5fc53 | ||
|
0ac430892e | ||
|
a7739c942c | ||
|
24581482d0 | ||
|
0571c3b453 | ||
|
73e7f5a0b0 | ||
|
20c0adb961 | ||
|
a01e03562f | ||
|
d184ed0130 | ||
|
089e1c2aee | ||
|
ebab0e91ee | ||
|
858a2b1b88 |
12
Makefile.in
12
Makefile.in
@@ -22,11 +22,13 @@ ifeq ("@INTL@", "yes")
|
||||
SUBDIRS += po
|
||||
endif
|
||||
|
||||
SUBDIRS += lib tools
|
||||
SUBDIRS += lib tools daemons
|
||||
|
||||
ifeq ($(MAKECMDGOALS),distclean)
|
||||
SUBDIRS += lib/format1 \
|
||||
SUBDIRS += daemons/clvmd \
|
||||
lib/format1 \
|
||||
lib/format_pool \
|
||||
lib/locking \
|
||||
lib/mirror \
|
||||
lib/snapshot \
|
||||
po \
|
||||
@@ -35,14 +37,16 @@ endif
|
||||
|
||||
include make.tmpl
|
||||
|
||||
daemons: lib
|
||||
lib: include
|
||||
tools: lib
|
||||
po: lib tools
|
||||
po: tools daemons
|
||||
|
||||
ifeq ("@INTL@", "yes")
|
||||
lib.pofile: include.pofile
|
||||
tools.pofile: lib.pofile
|
||||
po.pofile: lib.pofile tools.pofile
|
||||
daemons.pofile: lib.pofile
|
||||
po.pofile: tools.pofile daemons.pofile
|
||||
pofile: po.pofile
|
||||
endif
|
||||
|
||||
|
4
README
4
README
@@ -9,8 +9,8 @@ Installation instructions are in INSTALL.
|
||||
There is no warranty - see COPYING and COPYING.LIB.
|
||||
|
||||
Tarballs are available from:
|
||||
ftp://ftp.sistina.com/pub/LVM2/tools/
|
||||
ftp://ftp.sistina.com/pub/LVM2/device-mapper/
|
||||
ftp://sources.redhat.com/pub/lvm2/
|
||||
ftp://sources.redhat.com/pub/dm/
|
||||
|
||||
To access the CVS tree use:
|
||||
cvs -d :pserver:cvs@sources.redhat.com:/cvs/lvm2 login
|
||||
|
60
WHATS_NEW
60
WHATS_NEW
@@ -1,3 +1,63 @@
|
||||
Version 2.00.24 - 16th September 2004
|
||||
=====================================
|
||||
Fix pool_empty so it really does empty the memory pool.
|
||||
Rename old segtypes files to segtype.
|
||||
Some fixes to memory debugging code.
|
||||
Exclude internal commands formats & segtypes from install.
|
||||
|
||||
Version 2.00.23 - 15th September 2004
|
||||
=====================================
|
||||
Export dm name build & split functions.
|
||||
Use O_NOATIME on devices if available.
|
||||
Write log message when each segtype/format gets initialised.
|
||||
New commands 'segtypes' and 'formats'.
|
||||
Suppress pvmove abort message in test mode.
|
||||
Improve pvcreate/remove device not found error message.
|
||||
Allow pvmove to move data within the same PV.
|
||||
Describe how pvmove works on man page.
|
||||
Test for incompatible format/segtype combinations in lv_extend.
|
||||
Fix lvchange example on man page.
|
||||
|
||||
Version 2.00.22 - 3rd September 2004
|
||||
====================================
|
||||
Fix /dev/vgname perms.
|
||||
Restructure xlate.h.
|
||||
Add clvmd man page.
|
||||
|
||||
Version 2.00.21 - 19th August 2004
|
||||
==================================
|
||||
Update cnxman-socket.h from cman.
|
||||
Recognise iseries/vd devices.
|
||||
Use 'make install_cluster' to install cluster extensions only.
|
||||
Cope with DT_UNKNOWN in sysfs.
|
||||
Fix extents_moved metadata size comment.
|
||||
Remove duplicate line in pvremove help text.
|
||||
Support variable mirror region size.
|
||||
Support PE ranges in pvmove source PV.
|
||||
Fixes to as-yet-unused LV segment splitting code.
|
||||
Change alloc_areas to pe_ranges and allow suppression of availability checks.
|
||||
Add dev_size column to pvs.
|
||||
Add report columns for in-kernel device number.
|
||||
|
||||
Version 2.00.20 - 3 July 2004
|
||||
=============================
|
||||
More autoconf fixes.
|
||||
Fix device number handling for 2.6 kernels.
|
||||
|
||||
Version 2.00.19 - 29 June 2004
|
||||
==============================
|
||||
Reduce severity of setlocale failure message.
|
||||
Recognise argv[0] "initrd-lvm" (pld-linux).
|
||||
Make -O2 configurable.
|
||||
Added --disable-selinux to configure script.
|
||||
LD_FLAGS->LDFLAGS & LD_DEPS->LDDEPS in configure script.
|
||||
Add init_debug to clvmd.
|
||||
|
||||
Version 2.00.18 - 24 June 2004
|
||||
==============================
|
||||
Fix vgchange activation.
|
||||
Add cluster support.
|
||||
|
||||
Version 2.00.17 - 20 June 2004
|
||||
==============================
|
||||
configure --enable-fsadm to try out fsadm. fsadm is not tested yet.
|
||||
|
@@ -1,3 +1,12 @@
|
||||
Version 1.00.20 -
|
||||
=============================
|
||||
|
||||
Version 1.00.19 - 3 July 2004
|
||||
=============================
|
||||
More autoconf fixes.
|
||||
Fix a dmsetup newline.
|
||||
Fix device number handling for 2.6 kernels.
|
||||
|
||||
Version 1.00.18 - 20 Jun 2004
|
||||
=============================
|
||||
Fix a uuid free in libdm-iface.
|
||||
|
411
configure.in
411
configure.in
@@ -1,29 +1,64 @@
|
||||
##
|
||||
## Copyright 1999-2000 Sistina Software, Inc.
|
||||
## Copyright (C) 2000-2004 Sistina Software, Inc. All rights reserved.
|
||||
## Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||
##
|
||||
## This is free software released under the GNU General Public License.
|
||||
## There is no warranty for this software. See the file COPYING for
|
||||
## details.
|
||||
## This file is part of the LVM2.
|
||||
##
|
||||
## See the file CONTRIBUTORS for a list of contributors.
|
||||
## 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.
|
||||
##
|
||||
## This file is maintained by:
|
||||
## AJ Lewis <lewis@sistina.com>
|
||||
##
|
||||
## File name: configure.in
|
||||
##
|
||||
## Description: Input file for autoconf. Generates the configure script
|
||||
## that tries to keep everything nice and portable. It also
|
||||
## simplifies distribution package building considerably.
|
||||
## You should have received a copy of the GNU General Public License
|
||||
## along with this program; if not, write to the Free Software Foundation,
|
||||
## Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
################################################################################
|
||||
|
||||
dnl Process this file with autoconf to produce a configure script.
|
||||
AC_PREREQ(2.53)
|
||||
################################################################################
|
||||
dnl -- Process this file with autoconf to produce a configure script.
|
||||
AC_INIT(lib/device/dev-cache.h)
|
||||
|
||||
dnl setup the directory where autoconf has auxilary files
|
||||
################################################################################
|
||||
dnl -- Setup the directory where autoconf has auxilary files
|
||||
AC_CONFIG_AUX_DIR(autoconf)
|
||||
|
||||
dnl Checks for programs.
|
||||
################################################################################
|
||||
dnl -- Get system type
|
||||
AC_CANONICAL_SYSTEM
|
||||
|
||||
case "$host_os" in
|
||||
linux*)
|
||||
CFLAGS="$CFLAGS"
|
||||
COPTIMISE_FLAG="-O2"
|
||||
CLDFLAGS="$CLDFLAGS -Wl,--version-script,.export.sym"
|
||||
CLDWHOLEARCHIVE="-Wl,-whole-archive"
|
||||
CLDNOWHOLEARCHIVE="-Wl,-no-whole-archive"
|
||||
LDDEPS="$LDDEPS .export.sym"
|
||||
LDFLAGS="$LDFLAGS -Wl,--export-dynamic"
|
||||
SOFLAG="-shared"
|
||||
DEVMAPPER=yes
|
||||
ODIRECT=yes
|
||||
SELINUX=yes
|
||||
CLUSTER=internal
|
||||
FSADM=no ;;
|
||||
darwin*)
|
||||
CFLAGS="$CFLAGS -no-cpp-precomp -fno-common"
|
||||
COPTIMISE_FLAG="-O2"
|
||||
CLDFLAGS="$CLDFLAGS"
|
||||
CLDWHOLEARCHIVE="-all_load"
|
||||
CLDNOWHOLEARCHIVE=
|
||||
LDDEPS="$LDDEPS"
|
||||
LDFLAGS="$LDFLAGS"
|
||||
SOFLAG="-dynamiclib"
|
||||
DEVMAPPER=no
|
||||
ODIRECT=no
|
||||
SELINUX=no
|
||||
CLUSTER=none
|
||||
FSADM=no ;;
|
||||
esac
|
||||
|
||||
################################################################################
|
||||
dnl -- Checks for programs.
|
||||
AC_PROG_AWK
|
||||
AC_PROG_CC
|
||||
AC_PROG_INSTALL
|
||||
@@ -31,220 +66,304 @@ AC_PROG_LN_S
|
||||
AC_PROG_MAKE_SET
|
||||
AC_PROG_RANLIB
|
||||
|
||||
dnl Checks for header files.
|
||||
################################################################################
|
||||
dnl -- Checks for header files.
|
||||
AC_HEADER_DIRENT
|
||||
AC_HEADER_STDC
|
||||
AC_CHECK_HEADERS(fcntl.h malloc.h sys/ioctl.h unistd.h)
|
||||
AC_HEADER_SYS_WAIT
|
||||
AC_HEADER_TIME
|
||||
|
||||
dnl Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_CHECK_HEADERS(fcntl.h limits.h locale.h stddef.h syslog.h sys/file.h sys/ioctl.h sys/param.h sys/time.h,,AC_MSG_ERROR(bailing out))
|
||||
AC_CHECK_HEADERS(assert.h ctype.h libgen.h signal.h stdio.h sys/mman.h sys/resource.h sys/stat.h sys/types.h sys/utsname.h sys/wait.h time.h,,AC_MSG_ERROR(bailing out))
|
||||
|
||||
case "$host_os" in
|
||||
linux*)
|
||||
AC_CHECK_HEADERS(asm/byteorder.h linux/fs.h malloc.h,,AC_MSG_ERROR(bailing out)) ;;
|
||||
darwin*)
|
||||
AC_CHECK_HEADERS(machine/endian.h sys/disk.h,,AC_MSG_ERROR(bailing out)) ;;
|
||||
esac
|
||||
|
||||
################################################################################
|
||||
dnl -- Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_C_CONST
|
||||
AC_C_INLINE
|
||||
AC_TYPE_OFF_T
|
||||
AC_TYPE_PID_T
|
||||
AC_TYPE_SIZE_T
|
||||
AC_TYPE_MODE_T
|
||||
AC_STRUCT_ST_RDEV
|
||||
AC_HEADER_TIME
|
||||
AC_STRUCT_TM
|
||||
|
||||
dnl Get system type
|
||||
AC_CANONICAL_SYSTEM
|
||||
################################################################################
|
||||
dnl -- Check for functions
|
||||
AC_CHECK_FUNCS(gethostname getpagesize memset munmap setlocale strcasecmp strchr strdup strncasecmp strerror strrchr strstr strtol strtoul,,AC_MSG_ERROR(bailing out))
|
||||
AC_FUNC_ALLOCA
|
||||
AC_FUNC_CLOSEDIR_VOID
|
||||
AC_FUNC_FORK
|
||||
AC_FUNC_LSTAT
|
||||
AC_FUNC_MALLOC
|
||||
AC_FUNC_MEMCMP
|
||||
AC_FUNC_MMAP
|
||||
AC_FUNC_STAT
|
||||
AC_FUNC_STRTOD
|
||||
|
||||
case "$host_os" in
|
||||
linux*)
|
||||
CFLAGS=
|
||||
CLDFLAGS="-Wl,--version-script,.export.sym"
|
||||
CLDWHOLEARCHIVE="-Wl,-whole-archive"
|
||||
CLDNOWHOLEARCHIVE="-Wl,-no-whole-archive"
|
||||
LD_DEPS=".export.sym"
|
||||
LD_FLAGS="-Wl,--export-dynamic"
|
||||
SOFLAG="-shared"
|
||||
DEVMAPPER=yes
|
||||
ODIRECT=yes
|
||||
FSADM=no ;;
|
||||
darwin*)
|
||||
CFLAGS="-no-cpp-precomp -fno-common"
|
||||
CLDFLAGS=
|
||||
CLDWHOLEARCHIVE="-all_load"
|
||||
CLDNOWHOLEARCHIVE=
|
||||
LD_DEPS=
|
||||
LD_FLAGS=
|
||||
SOFLAG="-dynamiclib"
|
||||
DEVMAPPER=no
|
||||
ODIRECT=no
|
||||
FSADM=no ;;
|
||||
esac
|
||||
|
||||
dnl -- prefix is /usr by default, the exec_prefix default is setup later
|
||||
################################################################################
|
||||
dnl -- Prefix is /usr by default, the exec_prefix default is setup later
|
||||
AC_PREFIX_DEFAULT(/usr)
|
||||
|
||||
OWNER="root"
|
||||
GROUP="root"
|
||||
################################################################################
|
||||
dnl -- Parallel make jobs?
|
||||
AC_ARG_ENABLE(jobs, [ --enable-jobs=NUM Number of jobs to run simultaneously], JOBS=-j$enableval, JOBS=-j2)
|
||||
|
||||
################################################################################
|
||||
dnl -- Setup the ownership of the files
|
||||
AC_MSG_CHECKING(file owner)
|
||||
OWNER="root"
|
||||
|
||||
dnl -- setup the ownership of the files
|
||||
AC_ARG_WITH(user,
|
||||
[ --with-user=USER Set the owner of installed files ],
|
||||
[ OWNER="$withval" ])
|
||||
AC_MSG_RESULT($OWNER)
|
||||
|
||||
if test x$OWNER != x; then
|
||||
OWNER="-o $OWNER"
|
||||
fi
|
||||
|
||||
dnl -- setup the group ownership of the files
|
||||
################################################################################
|
||||
dnl -- Setup the group ownership of the files
|
||||
AC_MSG_CHECKING(group owner)
|
||||
GROUP="root"
|
||||
AC_ARG_WITH(group,
|
||||
[ --with-group=GROUP Set the group owner of installed files ],
|
||||
[ GROUP="$withval" ])
|
||||
AC_MSG_RESULT($GROUP)
|
||||
|
||||
if test x$GROUP != x; then
|
||||
GROUP="-g $GROUP"
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- LVM1 tool fallback option
|
||||
AC_MSG_CHECKING(whether to enable lvm1 fallback)
|
||||
AC_ARG_ENABLE(lvm1_fallback, [ --enable-lvm1_fallback Use this to fall back and use LVM1 binaries if
|
||||
device-mapper is missing from the kernel], LVM1_FALLBACK=$enableval, LVM1_FALLBACK=no)
|
||||
AC_MSG_RESULT($LVM1_FALLBACK)
|
||||
|
||||
if test x$LVM1_FALLBACK = xyes; then
|
||||
CFLAGS="$CFLAGS -DLVM1_FALLBACK"
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- format1 inclusion type
|
||||
AC_MSG_CHECKING(whether to include support for lvm1 metadata)
|
||||
AC_ARG_WITH(lvm1,
|
||||
[ --with-lvm1=TYPE LVM1 metadata support: internal/shared/none
|
||||
[TYPE=internal] ],
|
||||
[ LVM1="$withval" ],
|
||||
[ LVM1="internal" ])
|
||||
AC_MSG_RESULT($LVM1)
|
||||
|
||||
if [[ "x$LVM1" != xnone -a "x$LVM1" != xinternal -a "x$LVM1" != xshared ]];
|
||||
then AC_MSG_ERROR(
|
||||
--with-lvm1 parameter invalid
|
||||
)
|
||||
exit
|
||||
fi;
|
||||
|
||||
if test x$LVM1 = xinternal; then
|
||||
CFLAGS="$CFLAGS -DLVM1_INTERNAL"
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- format_pool inclusion type
|
||||
AC_MSG_CHECKING(whether to include support for GFS pool metadata)
|
||||
AC_ARG_WITH(pool,
|
||||
[ --with-pool=TYPE GFS pool read-only support: internal/shared/none
|
||||
[TYPE=internal] ],
|
||||
[ POOL="$withval" ],
|
||||
[ POOL="internal" ])
|
||||
AC_MSG_RESULT($POOL)
|
||||
|
||||
if [[ "x$POOL" != xnone -a "x$POOL" != xinternal -a "x$POOL" != xshared ]];
|
||||
then AC_MSG_ERROR(
|
||||
--with-pool parameter invalid
|
||||
)
|
||||
exit
|
||||
fi;
|
||||
|
||||
if test x$POOL = xinternal; then
|
||||
CFLAGS="$CFLAGS -DPOOL_INTERNAL"
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- cluster_locking inclusion type
|
||||
AC_MSG_CHECKING(whether to include support for cluster locking)
|
||||
AC_ARG_WITH(cluster,
|
||||
[ --with-cluster=TYPE Cluster LVM locking support: internal/shared/none
|
||||
[TYPE=internal] ],
|
||||
[ CLUSTER="$withval" ])
|
||||
AC_MSG_RESULT($CLUSTER)
|
||||
|
||||
AC_ARG_ENABLE(jobs, [ --enable-jobs=NUM Number of jobs to run simultaneously], JOBS=-j$enableval, JOBS=-j2)
|
||||
if [[ "x$CLUSTER" != xnone -a "x$CLUSTER" != xinternal -a "x$CLUSTER" != xshared ]];
|
||||
then AC_MSG_ERROR(
|
||||
--with-cluster parameter invalid
|
||||
)
|
||||
fi;
|
||||
|
||||
if test x$CLUSTER = xinternal; then
|
||||
CFLAGS="$CFLAGS -DCLUSTER_LOCKING_INTERNAL"
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- snapshots inclusion type
|
||||
AC_MSG_CHECKING(whether to include snapshots)
|
||||
AC_ARG_WITH(snapshots,
|
||||
[ --with-snapshots=TYPE Snapshot support: internal/shared/none
|
||||
[TYPE=internal] ],
|
||||
[ SNAPSHOTS="$withval" ],
|
||||
[ SNAPSHOTS="internal" ])
|
||||
AC_MSG_RESULT($SNAPSHOTS)
|
||||
|
||||
if [[ "x$SNAPSHOTS" != xnone -a "x$SNAPSHOTS" != xinternal -a "x$SNAPSHOTS" != xshared ]];
|
||||
then AC_MSG_ERROR(
|
||||
--with-snapshots parameter invalid
|
||||
)
|
||||
exit
|
||||
fi;
|
||||
|
||||
if test x$SNAPSHOTS = xinternal; then
|
||||
CFLAGS="$CFLAGS -DSNAPSHOT_INTERNAL"
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- mirrors inclusion type
|
||||
AC_MSG_CHECKING(whether to include mirrors)
|
||||
AC_ARG_WITH(mirrors,
|
||||
[ --with-mirrors=TYPE Mirror support: internal/shared/none
|
||||
[TYPE=internal] ],
|
||||
[ MIRRORS="$withval" ],
|
||||
[ MIRRORS="internal" ])
|
||||
AC_MSG_RESULT($MIRRORS)
|
||||
|
||||
if [[ "x$MIRRORS" != xnone -a "x$MIRRORS" != xinternal -a "x$MIRRORS" != xshared ]];
|
||||
then AC_MSG_ERROR(
|
||||
--with-mirrors parameter invalid
|
||||
)
|
||||
exit
|
||||
fi;
|
||||
|
||||
if test x$MIRRORS = xinternal; then
|
||||
CFLAGS="$CFLAGS -DMIRRORED_INTERNAL"
|
||||
fi
|
||||
|
||||
dnl Enables staticly-linked tools
|
||||
################################################################################
|
||||
dnl -- Enables staticly-linked tools
|
||||
AC_MSG_CHECKING(whether to use static linking)
|
||||
AC_ARG_ENABLE(static_link, [ --enable-static_link Use this to link the tools to their libraries
|
||||
statically. Default is dynamic linking], STATIC_LINK=$enableval, STATIC_LINK=no)
|
||||
AC_MSG_RESULT($STATIC_LINK)
|
||||
|
||||
dnl Enable readline
|
||||
AC_ARG_ENABLE(readline, [ --enable-readline Enable readline support], \
|
||||
################################################################################
|
||||
dnl -- Enable readline
|
||||
AC_MSG_CHECKING(whether to enable readline)
|
||||
AC_ARG_ENABLE(readline, [ --enable-readline Enable readline support],
|
||||
READLINE=$enableval, READLINE=no)
|
||||
AC_MSG_RESULT($READLINE)
|
||||
|
||||
if test x$READLINE = xyes; then
|
||||
CFLAGS="$CFLAGS -DREADLINE_SUPPORT"
|
||||
fi
|
||||
|
||||
echo $ac_n "checking whether to enable debugging""... $ac_c" 1>&6
|
||||
dnl Enable Debugging
|
||||
AC_ARG_ENABLE(debug, [ --enable-debug Enable debugging], \
|
||||
DEBUG=yes, DEBUG=no)
|
||||
echo "$ac_t""$DEBUG" 1>&6
|
||||
################################################################################
|
||||
dnl -- Disable selinux
|
||||
AC_MSG_CHECKING(whether to enable selinux support)
|
||||
AC_ARG_ENABLE(selinux, [ --disable-selinux Disable selinux support],
|
||||
SELINUX=$enableval)
|
||||
AC_MSG_RESULT($SELINUX)
|
||||
|
||||
echo $ac_n "checking whether to enable device-mapper""... $ac_c" 1>&6
|
||||
dnl Disable devmapper
|
||||
AC_ARG_ENABLE(devmapper, [ --disable-devmapper Disable device-mapper interaction], \
|
||||
DEVMAPPER=no)
|
||||
echo "$ac_t""$DEVMAPPER" 1>&6
|
||||
################################################################################
|
||||
dnl -- Build cluster LVM daemon
|
||||
AC_MSG_CHECKING(whether to build cluster LVM daemon)
|
||||
AC_ARG_WITH(clvmd, [ --with-clvmd Build cluster LVM Daemon],
|
||||
CLVMD=$withval, CLVMD=no)
|
||||
AC_MSG_RESULT($CLVMD)
|
||||
|
||||
dnl -- If clvmd enabled without cluster locking, automagically include it
|
||||
if test x$CLVMD = xyes && test x$CLUSTER = xnone; then
|
||||
CLUSTER=internal
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Enable debugging
|
||||
AC_MSG_CHECKING(whether to enable debugging)
|
||||
AC_ARG_ENABLE(debug, [ --enable-debug Enable debugging],
|
||||
DEBUG=$enableval, DEBUG=no)
|
||||
AC_MSG_RESULT($DEBUG)
|
||||
|
||||
dnl -- Normally turn off optimisation for debug builds
|
||||
if test x$DEBUG = xyes; then
|
||||
COPTIMISE_FLAG=
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Override optimisation
|
||||
AC_MSG_CHECKING(for C optimisation flag)
|
||||
AC_ARG_WITH(optimisation,
|
||||
[ --with-optimisation=OPT C optimisation flag [OPT=-O2] ],
|
||||
[ COPTIMISE_FLAG="$withval" ])
|
||||
AC_MSG_RESULT($COPTIMISE_FLAG)
|
||||
|
||||
################################################################################
|
||||
dnl -- Disable devmapper
|
||||
AC_MSG_CHECKING(whether to use device-mapper)
|
||||
AC_ARG_ENABLE(devmapper, [ --disable-devmapper Disable device-mapper interaction],
|
||||
DEVMAPPER=$enableval)
|
||||
AC_MSG_RESULT($DEVMAPPER)
|
||||
|
||||
if test x$DEVMAPPER = xyes; then
|
||||
CFLAGS="$CFLAGS -DDEVMAPPER_SUPPORT"
|
||||
fi
|
||||
|
||||
echo $ac_n "checking whether to enable O_DIRECT""... $ac_c" 1>&6
|
||||
dnl Disable O_DIRECT
|
||||
AC_ARG_ENABLE(o_direct, [ --disable-o_direct Disable O_DIRECT], \
|
||||
ODIRECT=no)
|
||||
echo "$ac_t""$ODIRECT" 1>&6
|
||||
################################################################################
|
||||
dnl -- Disable O_DIRECT
|
||||
AC_MSG_CHECKING(whether to enable O_DIRECT)
|
||||
AC_ARG_ENABLE(o_direct, [ --disable-o_direct Disable O_DIRECT],
|
||||
ODIRECT=$enableval)
|
||||
AC_MSG_RESULT($ODIRECT)
|
||||
|
||||
if test x$ODIRECT = xyes; then
|
||||
CFLAGS="$CFLAGS -DO_DIRECT_SUPPORT"
|
||||
fi
|
||||
|
||||
echo $ac_n "checking whether to compile liblvm2cmd.so""... $ac_c" 1>&6
|
||||
dnl Enable cmdlib
|
||||
AC_ARG_ENABLE(cmdlib, [ --enable-cmdlib Build shared command library], \
|
||||
CMDLIB=yes, CMDLIB=no)
|
||||
echo "$ac_t""$CMDLIB" 1>&6
|
||||
################################################################################
|
||||
dnl -- Enable cmdlib
|
||||
AC_MSG_CHECKING(whether to compile liblvm2cmd.so)
|
||||
AC_ARG_ENABLE(cmdlib, [ --enable-cmdlib Build shared command library],
|
||||
CMDLIB=$enableval, CMDLIB=no)
|
||||
AC_MSG_RESULT($CMDLIB)
|
||||
|
||||
if test x$CMDLIB = xyes; then
|
||||
CFLAGS="$CFLAGS -DCMDLIB"
|
||||
fi
|
||||
|
||||
echo $ac_n "checking whether to enable fsadm""... $ac_c" 1>&6
|
||||
dnl Enable fsadm
|
||||
AC_ARG_ENABLE(fsadm, [ --enable-fsadm Enable fsadm], FSADM=yes)
|
||||
echo "$ac_t""$FSADM" 1>&6
|
||||
################################################################################
|
||||
dnl -- Enable fsadm
|
||||
AC_MSG_CHECKING(whether to build fsadm)
|
||||
AC_ARG_ENABLE(fsadm, [ --enable-fsadm Enable fsadm],
|
||||
FSADM=$enableval)
|
||||
AC_MSG_RESULT($FSADM)
|
||||
|
||||
dnl Mess with default exec_prefix
|
||||
################################################################################
|
||||
dnl -- Mess with default exec_prefix
|
||||
if [[ "x$exec_prefix" = xNONE -a "x$prefix" = xNONE ]];
|
||||
then exec_prefix="";
|
||||
fi;
|
||||
|
||||
dnl Checks for library functions.
|
||||
################################################################################
|
||||
dnl -- Checks for library functions.
|
||||
AC_PROG_GCC_TRADITIONAL
|
||||
AC_TYPE_SIGNAL
|
||||
AC_FUNC_VPRINTF
|
||||
AC_CHECK_FUNCS(mkdir rmdir uname)
|
||||
AC_CHECK_FUNCS(mkdir rmdir uname,,AC_MSG_ERROR(bailing out))
|
||||
|
||||
dnl check for termcap (Shamelessly copied from parted 1.4.17)
|
||||
################################################################################
|
||||
dnl -- Check for termcap (Shamelessly copied from parted 1.4.17)
|
||||
if test x$READLINE = xyes; then
|
||||
AC_SEARCH_LIBS(tgetent, ncurses curses termcap termlib, ,
|
||||
AC_MSG_ERROR(
|
||||
@@ -257,11 +376,11 @@ Note: if you are using precompiled packages you will also need the development
|
||||
Note: (n)curses also seems to work as a substitute for termcap. This was
|
||||
not found either - but you could try installing that as well.
|
||||
)
|
||||
exit
|
||||
)
|
||||
fi
|
||||
|
||||
dnl Check for dlopen
|
||||
################################################################################
|
||||
dnl -- Check for dlopen
|
||||
AC_CHECK_LIB(dl, dlopen, HAVE_LIBDL=yes, HAVE_LIBDL=no)
|
||||
|
||||
if [[ "x$HAVE_LIBDL" = xyes -a "x$STATIC_LINK" = xno ]]; then
|
||||
@@ -271,28 +390,37 @@ else
|
||||
HAVE_LIBDL=no
|
||||
fi
|
||||
|
||||
dnl Check for shared/static conflicts
|
||||
if [[ \( "x$LVM1" = xshared -o "x$POOL" = xshared -o \
|
||||
"x$SNAPSHOTS" = xshared -o "x$MIRRORS" = xshared \
|
||||
################################################################################
|
||||
dnl -- Check for shared/static conflicts
|
||||
if [[ \( "x$LVM1" = xshared -o "x$POOL" = xshared -o "x$CLUSTER" = xshared \
|
||||
-o "x$SNAPSHOTS" = xshared -o "x$MIRRORS" = xshared \
|
||||
\) -a "x$STATIC_LINK" = xyes ]];
|
||||
then AC_MSG_ERROR(
|
||||
Features cannot be 'shared' when building statically
|
||||
)
|
||||
exit
|
||||
fi
|
||||
|
||||
dnl Check for is_selinux_enabled
|
||||
AC_CHECK_LIB(selinux, is_selinux_enabled, HAVE_SELINUX=yes, HAVE_SELINUX=no)
|
||||
################################################################################
|
||||
dnl -- Check for is_selinux_enabled
|
||||
if test x$SELINUX = xyes; then
|
||||
AC_MSG_CHECKING(for is_selinux_enabled function)
|
||||
AC_CHECK_LIB(selinux, is_selinux_enabled, HAVE_SELINUX=yes, HAVE_SELINUX=no)
|
||||
AC_MSG_RESULT($HAVE_SELINUX)
|
||||
|
||||
if test x$HAVE_SELINUX = xyes; then
|
||||
CFLAGS="$CFLAGS -DHAVE_SELINUX"
|
||||
LIBS="-lselinux $LIBS"
|
||||
if test x$HAVE_SELINUX = xyes; then
|
||||
CFLAGS="$CFLAGS -DHAVE_SELINUX"
|
||||
LIBS="-lselinux $LIBS"
|
||||
else
|
||||
AC_MSG_WARN(Disabling selinux)
|
||||
fi
|
||||
fi
|
||||
|
||||
dnl Check for getopt
|
||||
################################################################################
|
||||
dnl -- Check for getopt
|
||||
AC_CHECK_HEADERS(getopt.h, CFLAGS="$CFLAGS -DHAVE_GETOPTLONG")
|
||||
|
||||
dnl Check for readline (Shamelessly copied from parted 1.4.17)
|
||||
################################################################################
|
||||
dnl -- Check for readline (Shamelessly copied from parted 1.4.17)
|
||||
if test x$READLINE = xyes; then
|
||||
AC_CHECK_LIB(readline, readline, ,
|
||||
AC_MSG_ERROR(
|
||||
@@ -303,17 +431,17 @@ support with --disable-readline or download and install readline from:
|
||||
Note: if you are using precompiled packages you will also need the development
|
||||
package as well (which may be called readline-devel or something similar).
|
||||
)
|
||||
exit
|
||||
)
|
||||
AC_CHECK_FUNC(rl_completion_matches, CFLAGS="$CFLAGS -DHAVE_RL_COMPLETION_MATCHES")
|
||||
|
||||
fi
|
||||
|
||||
echo $ac_n "checking whether to enable internationalisation""... $ac_c" 1>&6
|
||||
dnl Internationalisation stuff
|
||||
AC_ARG_ENABLE(nls, [ --enable-nls Enable Native Language Support],\
|
||||
INTL=yes, INTL=no)
|
||||
echo "$ac_t""$INTL" 1>&6
|
||||
################################################################################
|
||||
dnl -- Internationalisation stuff
|
||||
AC_MSG_CHECKING(whether to enable internationalisation)
|
||||
AC_ARG_ENABLE(nls, [ --enable-nls Enable Native Language Support],
|
||||
INTL=$enableval, INTL=no)
|
||||
AC_MSG_RESULT($INTL)
|
||||
|
||||
if test x$INTL = xyes; then
|
||||
INTL_PACKAGE="lvm2"
|
||||
@@ -322,7 +450,6 @@ if test x$INTL = xyes; then
|
||||
then AC_MSG_ERROR(
|
||||
msgfmt not found in path $PATH
|
||||
)
|
||||
exit
|
||||
fi;
|
||||
|
||||
AC_ARG_WITH(localedir,
|
||||
@@ -331,6 +458,7 @@ if test x$INTL = xyes; then
|
||||
[ LOCALEDIR='${prefix}/share/locale' ])
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
AC_ARG_WITH(confdir,
|
||||
[ --with-confdir=DIR Configuration files in DIR [/etc]],
|
||||
[ CONFDIR="$withval" ],
|
||||
@@ -341,13 +469,54 @@ AC_ARG_WITH(staticdir,
|
||||
[ STATICDIR="$withval" ],
|
||||
[ STATICDIR='${exec_prefix}/sbin' ])
|
||||
|
||||
################################################################################
|
||||
dnl -- Ensure additional headers required
|
||||
if test x$READLINE = xyes; then
|
||||
AC_CHECK_HEADERS(readline/readline.h readline/history.h,,AC_MSG_ERROR(bailing out))
|
||||
fi
|
||||
|
||||
if test x$CLVMD = xyes; 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,,AC_MSG_ERROR(bailing out))
|
||||
AC_FUNC_GETMNTENT
|
||||
# AC_FUNC_REALLOC
|
||||
AC_FUNC_SELECT_ARGTYPES
|
||||
fi
|
||||
|
||||
if test x$FSADM = xyes; then
|
||||
AC_CHECK_HEADERS(fstab.h sys/mount.h sys/vfs.h,,AC_MSG_ERROR(bailing out))
|
||||
AC_CHECK_FUNCS(memmove,,AC_MSG_ERROR(bailing out))
|
||||
fi
|
||||
|
||||
if test x$CLUSTER != xnone; then
|
||||
AC_CHECK_HEADERS(sys/socket.h sys/un.h,,AC_MSG_ERROR(bailing out))
|
||||
AC_CHECK_FUNCS(socket,,AC_MSG_ERROR(bailing out))
|
||||
fi
|
||||
|
||||
if test x$HAVE_LIBDL = xyes; then
|
||||
AC_CHECK_HEADERS(dlfcn.h,,AC_MSG_ERROR(bailing out))
|
||||
fi
|
||||
|
||||
if test x$INTL = xyes; then
|
||||
AC_CHECK_HEADERS(libintl.h,,AC_MSG_ERROR(bailing out))
|
||||
fi
|
||||
|
||||
if test x$DEVMAPPER = xyes; then
|
||||
AC_CHECK_HEADERS(libdevmapper.h,,AC_MSG_ERROR(bailing out))
|
||||
fi
|
||||
|
||||
if test x$HAVE_SELINUX = xyes; then
|
||||
AC_CHECK_HEADERS(selinux/selinux.h,,AC_MSG_ERROR(bailing out))
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
if test "-f VERSION"; then
|
||||
LVM_VERSION="\"`cat VERSION`\""
|
||||
else
|
||||
LVM_VERSION="Unknown"
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
AC_SUBST(JOBS)
|
||||
AC_SUBST(STATIC_LINK)
|
||||
AC_SUBST(LVM1)
|
||||
@@ -357,11 +526,12 @@ AC_SUBST(MIRRORS)
|
||||
AC_SUBST(OWNER)
|
||||
AC_SUBST(GROUP)
|
||||
AC_SUBST(CFLAGS)
|
||||
AC_SUBST(COPTIMISE_FLAG)
|
||||
AC_SUBST(CLDFLAGS)
|
||||
AC_SUBST(CLDWHOLEARCHIVE)
|
||||
AC_SUBST(CLDNOWHOLEARCHIVE)
|
||||
AC_SUBST(LD_DEPS)
|
||||
AC_SUBST(LD_FLAGS)
|
||||
AC_SUBST(LDDEPS)
|
||||
AC_SUBST(LDFLAGS)
|
||||
AC_SUBST(SOFLAG)
|
||||
AC_SUBST(LIBS)
|
||||
AC_SUBST(LVM_VERSION)
|
||||
@@ -377,18 +547,24 @@ AC_SUBST(CONFDIR)
|
||||
AC_SUBST(STATICDIR)
|
||||
AC_SUBST(INTL_PACKAGE)
|
||||
AC_SUBST(INTL)
|
||||
AC_SUBST(CLVMD)
|
||||
AC_SUBST(CLUSTER)
|
||||
AC_SUBST(FSADM)
|
||||
|
||||
dnl First and last lines should not contain files to generate in order to
|
||||
dnl keep utility scripts running properly
|
||||
################################################################################
|
||||
dnl -- First and last lines should not contain files to generate in order to
|
||||
dnl -- keep utility scripts running properly
|
||||
AC_OUTPUT( \
|
||||
Makefile \
|
||||
make.tmpl \
|
||||
make.tmpl \
|
||||
daemons/Makefile \
|
||||
daemons/clvmd/Makefile \
|
||||
doc/Makefile \
|
||||
include/Makefile \
|
||||
lib/Makefile \
|
||||
lib/format1/Makefile \
|
||||
lib/format_pool/Makefile \
|
||||
lib/locking/Makefile \
|
||||
lib/mirror/Makefile \
|
||||
lib/snapshot/Makefile \
|
||||
man/Makefile \
|
||||
@@ -404,14 +580,9 @@ test/filters/Makefile \
|
||||
)
|
||||
|
||||
if test x$ODIRECT != xyes; then
|
||||
echo
|
||||
echo Warning: O_DIRECT disabled.
|
||||
echo Use of pvmove may cause machine to lock up under low memory conditions.
|
||||
echo
|
||||
AC_MSG_WARN(Warning: O_DIRECT disabled: low-memory pvmove may lock up)
|
||||
fi
|
||||
|
||||
if test x$FSADM == xyes; then
|
||||
echo
|
||||
echo Warning: fsadm support is untested.
|
||||
echo
|
||||
AC_MSG_WARN(fsadm support is untested)
|
||||
fi
|
||||
|
23
daemons/Makefile.in
Normal file
23
daemons/Makefile.in
Normal file
@@ -0,0 +1,23 @@
|
||||
#
|
||||
# Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This file is part of the 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
ifeq ("@CLVMD@", "yes")
|
||||
SUBDIRS = clvmd
|
||||
endif
|
||||
|
||||
include $(top_srcdir)/make.tmpl
|
||||
|
49
daemons/clvmd/Makefile.in
Normal file
49
daemons/clvmd/Makefile.in
Normal file
@@ -0,0 +1,49 @@
|
||||
#
|
||||
# Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This file is part of the 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
SOURCES = \
|
||||
clvmd-cman.c \
|
||||
clvmd-command.c \
|
||||
clvmd.c \
|
||||
libclvm.c \
|
||||
lvm-functions.c \
|
||||
system-lv.c
|
||||
|
||||
TARGETS = \
|
||||
clvmd
|
||||
|
||||
include $(top_srcdir)/make.tmpl
|
||||
|
||||
CFLAGS += -D_REENTRANT -fno-strict-aliasing
|
||||
LIBS += -ldevmapper -ldlm -llvm -lpthread
|
||||
|
||||
INSTALL_TARGETS = \
|
||||
install_clvmd
|
||||
|
||||
clvmd: $(OBJECTS) $(top_srcdir)/lib/liblvm.a
|
||||
$(CC) -o clvmd $(OBJECTS) $(LDFLAGS) $(LVMLIBS) $(LIBS)
|
||||
|
||||
.PHONY: install_clvmd
|
||||
|
||||
install_clvmd: $(TARGETS)
|
||||
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) clvmd \
|
||||
$(sbindir)/clvmd
|
||||
|
||||
install: $(INSTALL_TARGETS)
|
||||
|
||||
install_cluster: $(INSTALL_TARGETS)
|
||||
|
65
daemons/clvmd/clvm.h
Normal file
65
daemons/clvmd/clvm.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* Definitions for CLVMD server and clients */
|
||||
|
||||
/*
|
||||
* The protocol spoken over the cluster and across the local socket.
|
||||
*/
|
||||
|
||||
#ifndef _CLVM_H
|
||||
#define _CLVM_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 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 */
|
||||
|
||||
/* Name of the local socket to communicate between libclvm and clvmd */
|
||||
//static const char CLVMD_SOCKNAME[]="/var/run/clvmd";
|
||||
static const char CLVMD_SOCKNAME[] = "\0clvmd";
|
||||
|
||||
/* 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
|
||||
|
||||
#endif
|
499
daemons/clvmd/clvmd-cman.c
Normal file
499
daemons/clvmd/clvmd-cman.c
Normal file
@@ -0,0 +1,499 @@
|
||||
/*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* CMAN communication layer for clvmd.
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <syslog.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "clvmd-comms.h"
|
||||
#include "clvm.h"
|
||||
#include "libdlm.h"
|
||||
#include "log.h"
|
||||
#include "clvmd.h"
|
||||
#include "lvm-functions.h"
|
||||
|
||||
#define LOCKSPACE_NAME "clvmd"
|
||||
|
||||
static int cluster_sock;
|
||||
static int num_nodes;
|
||||
static struct cl_cluster_node *nodes = NULL;
|
||||
static int count_nodes; /* size of allocated nodes array */
|
||||
static int max_updown_nodes = 50; /* Current size of the allocated array */
|
||||
/* Node up/down status, indexed by nodeid */
|
||||
static int *node_updown = NULL;
|
||||
static dlm_lshandle_t *lockspace;
|
||||
|
||||
static void sigusr1_handler(int sig);
|
||||
static void count_clvmds_running(void);
|
||||
static void get_members(void);
|
||||
static int nodeid_from_csid(char *csid);
|
||||
static int name_from_nodeid(int nodeid, char *name);
|
||||
|
||||
struct lock_wait {
|
||||
pthread_cond_t cond;
|
||||
pthread_mutex_t mutex;
|
||||
struct dlm_lksb lksb;
|
||||
};
|
||||
|
||||
int init_cluster()
|
||||
{
|
||||
struct sockaddr_cl saddr;
|
||||
int port = CLUSTER_PORT_CLVMD;
|
||||
|
||||
/* Open the cluster communication socket */
|
||||
cluster_sock = socket(AF_CLUSTER, SOCK_DGRAM, CLPROTO_CLIENT);
|
||||
if (cluster_sock == -1) {
|
||||
perror("Can't open cluster socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Bind to our port number on the cluster.
|
||||
Writes to this will block if the cluster loses quorum */
|
||||
saddr.scl_family = AF_CLUSTER;
|
||||
saddr.scl_port = port;
|
||||
|
||||
if (bind
|
||||
(cluster_sock, (struct sockaddr *) &saddr,
|
||||
sizeof(struct sockaddr_cl))) {
|
||||
log_error("Can't bind cluster socket: %m");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get the cluster members list */
|
||||
get_members();
|
||||
count_clvmds_running();
|
||||
|
||||
/* Create a lockspace for LV & VG locks to live in */
|
||||
lockspace = dlm_create_lockspace(LOCKSPACE_NAME, 0600);
|
||||
if (!lockspace) {
|
||||
log_error("Unable to create lockspace for CLVM\n");
|
||||
return -1;
|
||||
}
|
||||
dlm_ls_pthread_init(lockspace);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_main_cluster_fd()
|
||||
{
|
||||
return cluster_sock;
|
||||
}
|
||||
|
||||
int get_num_nodes()
|
||||
{
|
||||
return num_nodes;
|
||||
}
|
||||
|
||||
/* send_message with the fd check removed */
|
||||
int cluster_send_message(void *buf, int msglen, char *csid, const char *errtext)
|
||||
{
|
||||
struct iovec iov[2];
|
||||
struct msghdr msg;
|
||||
struct sockaddr_cl saddr;
|
||||
int len = 0;
|
||||
|
||||
msg.msg_control = NULL;
|
||||
msg.msg_controllen = 0;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_flags = 0;
|
||||
iov[0].iov_len = msglen;
|
||||
iov[0].iov_base = buf;
|
||||
|
||||
saddr.scl_family = AF_CLUSTER;
|
||||
saddr.scl_port = CLUSTER_PORT_CLVMD;
|
||||
if (csid) {
|
||||
msg.msg_name = &saddr;
|
||||
msg.msg_namelen = sizeof(saddr);
|
||||
memcpy(&saddr.scl_nodeid, csid, MAX_CSID_LEN);
|
||||
} else { /* Cluster broadcast */
|
||||
|
||||
msg.msg_name = NULL;
|
||||
msg.msg_namelen = 0;
|
||||
}
|
||||
|
||||
do {
|
||||
len = sendmsg(cluster_sock, &msg, 0);
|
||||
if (len < 0 && errno != EAGAIN)
|
||||
log_error(errtext);
|
||||
|
||||
} while (len == -1 && errno == EAGAIN);
|
||||
return len;
|
||||
}
|
||||
|
||||
void get_our_csid(char *csid)
|
||||
{
|
||||
int i;
|
||||
memset(csid, 0, MAX_CSID_LEN);
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
if (nodes[i].us)
|
||||
memcpy(csid, &nodes[i].node_id, MAX_CSID_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
/* Call a callback routine for each node that known (down mean not running a clvmd) */
|
||||
int cluster_do_node_callback(struct local_client *client,
|
||||
void (*callback) (struct local_client *, char *,
|
||||
int))
|
||||
{
|
||||
int i;
|
||||
int somedown = 0;
|
||||
|
||||
for (i = 0; i < get_num_nodes(); i++) {
|
||||
callback(client, (char *)&nodes[i].node_id, node_updown[nodes[i].node_id]);
|
||||
if (!node_updown[nodes[i].node_id])
|
||||
somedown = -1;
|
||||
}
|
||||
return somedown;
|
||||
}
|
||||
|
||||
/* Process OOB message from the cluster socket,
|
||||
this currently just means that a node has stopped listening on our port */
|
||||
static void process_oob_msg(char *buf, int len, int nodeid)
|
||||
{
|
||||
char namebuf[256];
|
||||
switch (buf[0]) {
|
||||
case CLUSTER_OOB_MSG_PORTCLOSED:
|
||||
name_from_nodeid(nodeid, namebuf);
|
||||
log_notice("clvmd on node %s has died\n", namebuf);
|
||||
DEBUGLOG("Got OOB message, removing node %s\n", namebuf);
|
||||
|
||||
node_updown[nodeid] = 0;
|
||||
break;
|
||||
|
||||
case CLUSTER_OOB_MSG_STATECHANGE:
|
||||
DEBUGLOG("Got OOB message, Cluster state change\n");
|
||||
get_members();
|
||||
break;
|
||||
default:
|
||||
/* ERROR */
|
||||
DEBUGLOG("Got unknown OOB message: %d\n", buf[0]);
|
||||
}
|
||||
}
|
||||
|
||||
int cluster_fd_callback(struct local_client *fd, char *buf, int len, char *csid,
|
||||
struct local_client **new_client)
|
||||
{
|
||||
struct iovec iov[2];
|
||||
struct msghdr msg;
|
||||
struct sockaddr_cl saddr;
|
||||
|
||||
/* We never return a new client */
|
||||
*new_client = NULL;
|
||||
|
||||
msg.msg_control = NULL;
|
||||
msg.msg_controllen = 0;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_name = &saddr;
|
||||
msg.msg_flags = 0;
|
||||
msg.msg_namelen = sizeof(saddr);
|
||||
iov[0].iov_len = len;
|
||||
iov[0].iov_base = buf;
|
||||
|
||||
len = recvmsg(cluster_sock, &msg, MSG_OOB | O_NONBLOCK);
|
||||
if (len < 0 && errno == EAGAIN)
|
||||
return len;
|
||||
|
||||
DEBUGLOG("Read on cluster socket, len = %d\n", len);
|
||||
|
||||
/* A real error */
|
||||
if (len < 0) {
|
||||
log_error("read error on cluster socket: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* EOF - we have left the cluster */
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
/* Is it OOB? probably a node gone down */
|
||||
if (msg.msg_flags & MSG_OOB) {
|
||||
process_oob_msg(iov[0].iov_base, len, saddr.scl_nodeid);
|
||||
|
||||
/* Tell the upper layer to ignore this message */
|
||||
len = -1;
|
||||
errno = EAGAIN;
|
||||
}
|
||||
memcpy(csid, &saddr.scl_nodeid, sizeof(saddr.scl_nodeid));
|
||||
return len;
|
||||
}
|
||||
|
||||
void add_up_node(char *csid)
|
||||
{
|
||||
/* It's up ! */
|
||||
int nodeid = nodeid_from_csid(csid);
|
||||
|
||||
if (nodeid >= max_updown_nodes) {
|
||||
int *new_updown = realloc(node_updown, max_updown_nodes + 10);
|
||||
|
||||
if (new_updown) {
|
||||
node_updown = new_updown;
|
||||
max_updown_nodes += 10;
|
||||
DEBUGLOG("realloced more space for nodes. now %d\n",
|
||||
max_updown_nodes);
|
||||
} else {
|
||||
log_error
|
||||
("Realloc failed. Node status for clvmd will be wrong\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
node_updown[nodeid] = 1;
|
||||
DEBUGLOG("Added new node %d to updown list\n", nodeid);
|
||||
}
|
||||
|
||||
void cluster_closedown()
|
||||
{
|
||||
unlock_all();
|
||||
dlm_release_lockspace(LOCKSPACE_NAME, lockspace, 1);
|
||||
close(cluster_sock);
|
||||
}
|
||||
|
||||
static int is_listening(int nodeid)
|
||||
{
|
||||
struct cl_listen_request rq;
|
||||
int status;
|
||||
|
||||
rq.port = CLUSTER_PORT_CLVMD;
|
||||
rq.nodeid = nodeid;
|
||||
|
||||
do {
|
||||
status = ioctl(cluster_sock, SIOCCLUSTER_ISLISTENING, &rq);
|
||||
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 */
|
||||
void count_clvmds_running(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
node_updown[nodes[i].node_id] = is_listening(nodes[i].node_id);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get a list of active cluster members */
|
||||
static void get_members()
|
||||
{
|
||||
struct cl_cluster_nodelist nodelist;
|
||||
|
||||
num_nodes = ioctl(cluster_sock, SIOCCLUSTER_GETMEMBERS, 0);
|
||||
if (num_nodes == -1) {
|
||||
perror("get nodes");
|
||||
} else {
|
||||
/* 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 cl_cluster_node));
|
||||
if (!nodes) {
|
||||
perror("Unable to allocate nodes array\n");
|
||||
exit(5);
|
||||
}
|
||||
}
|
||||
nodelist.max_members = count_nodes;
|
||||
nodelist.nodes = nodes;
|
||||
|
||||
num_nodes = ioctl(cluster_sock, SIOCCLUSTER_GETMEMBERS, &nodelist);
|
||||
if (num_nodes <= 0) {
|
||||
perror("get node details");
|
||||
exit(6);
|
||||
}
|
||||
|
||||
/* Sanity check struct */
|
||||
if (nodes[0].size != sizeof(struct cl_cluster_node)) {
|
||||
log_error
|
||||
("sizeof(cl_cluster_node) does not match size returned from the kernel: aborting\n");
|
||||
exit(10);
|
||||
}
|
||||
|
||||
if (node_updown == NULL) {
|
||||
node_updown =
|
||||
(int *) malloc(sizeof(int) *
|
||||
max(num_nodes, max_updown_nodes));
|
||||
memset(node_updown, 0,
|
||||
sizeof(int) * max(num_nodes, max_updown_nodes));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert a node name to a CSID */
|
||||
int csid_from_name(char *csid, char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
if (strcmp(name, nodes[i].name) == 0) {
|
||||
memcpy(csid, &nodes[i].node_id, MAX_CSID_LEN);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Convert a CSID to a node name */
|
||||
int name_from_csid(char *csid, char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
if (memcmp(csid, &nodes[i].node_id, MAX_CSID_LEN) == 0) {
|
||||
strcpy(name, nodes[i].name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* Who?? */
|
||||
strcpy(name, "Unknown");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Convert a node ID to a node name */
|
||||
int name_from_nodeid(int nodeid, char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
if (nodeid == nodes[i].node_id) {
|
||||
strcpy(name, nodes[i].name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* Who?? */
|
||||
strcpy(name, "Unknown");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Convert a CSID to a node ID */
|
||||
static int nodeid_from_csid(char *csid)
|
||||
{
|
||||
int nodeid;
|
||||
|
||||
memcpy(&nodeid, csid, MAX_CSID_LEN);
|
||||
|
||||
return nodeid;
|
||||
}
|
||||
|
||||
int is_quorate()
|
||||
{
|
||||
return ioctl(cluster_sock, SIOCCLUSTER_ISQUORATE, 0);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
int sync_lock(const char *resource, int mode, int flags, int *lockid)
|
||||
{
|
||||
int status;
|
||||
struct lock_wait lwait;
|
||||
|
||||
if (!lockid) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
if (lwait.lksb.sb_status)
|
||||
return -1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sync_unlock(const char *resource /* UNUSED */, int lockid)
|
||||
{
|
||||
int status;
|
||||
struct lock_wait lwait;
|
||||
|
||||
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;
|
||||
|
||||
}
|
219
daemons/clvmd/clvmd-command.c
Normal file
219
daemons/clvmd/clvmd-command.c
Normal file
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 <pthread.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "list.h"
|
||||
#include "locking.h"
|
||||
#include "log.h"
|
||||
#include "lvm-functions.h"
|
||||
#include "clvmd-comms.h"
|
||||
#include "clvm.h"
|
||||
#include "clvmd.h"
|
||||
#include "libdlm.h"
|
||||
|
||||
/* 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;
|
||||
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) {
|
||||
buflen = arglen + 200;
|
||||
*buf = realloc(*buf, buflen);
|
||||
}
|
||||
uname(&nodeinfo);
|
||||
*retlen = 1 + snprintf(*buf, buflen, "TEST from %s: %s v%s",
|
||||
nodeinfo.nodename, args,
|
||||
nodeinfo.release);
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_LOCK_VG:
|
||||
/* Check to see if the VG is in use by LVM1 */
|
||||
status = do_check_lvm1(&args[2]);
|
||||
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 + snprintf(*buf, buflen,
|
||||
"Internal lvm error, check syslog");
|
||||
return EIO;
|
||||
}
|
||||
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) {
|
||||
*retlen = 1 + snprintf(*buf, buflen, strerror(status));
|
||||
}
|
||||
|
||||
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;
|
||||
int status = 0;
|
||||
char *lockname;
|
||||
|
||||
switch (header->cmd) {
|
||||
case CLVMD_CMD_TEST:
|
||||
status = sync_lock("CLVMD_TEST", LKM_EXMODE, 0, &lockid);
|
||||
client->bits.localsock.private = (void *) lockid;
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_LOCK_VG:
|
||||
lock_cmd = args[0];
|
||||
lock_flags = args[1];
|
||||
lockname = &args[2];
|
||||
DEBUGLOG("doing PRE command LOCK_VG %s at %x\n", lockname,
|
||||
lock_cmd);
|
||||
if (lock_cmd == LCK_UNLOCK) {
|
||||
hold_unlock(lockname);
|
||||
} else {
|
||||
status =
|
||||
hold_lock(lockname, (int) lock_cmd,
|
||||
(int) lock_flags);
|
||||
if (status)
|
||||
status = errno;
|
||||
}
|
||||
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;
|
||||
|
||||
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);
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_LOCK_VG:
|
||||
/* Nothing to do here */
|
||||
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;
|
||||
}
|
||||
return status;
|
||||
}
|
55
daemons/clvmd/clvmd-comms.h
Normal file
55
daemons/clvmd/clvmd-comms.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* Abstraction layer for clvmd cluster communications
|
||||
*/
|
||||
|
||||
#ifndef _CLVMD_COMMS_H
|
||||
#define _CLVMD_COMMS_H
|
||||
|
||||
struct local_client;
|
||||
|
||||
extern int cluster_send_message(void *buf, int msglen, char *csid,
|
||||
const char *errtext);
|
||||
extern int name_from_csid(char *csid, char *name);
|
||||
extern int csid_from_name(char *csid, char *name);
|
||||
extern int get_num_nodes(void);
|
||||
extern int cluster_fd_callback(struct local_client *fd, char *buf, int len,
|
||||
char *csid, struct local_client **new_client);
|
||||
extern int init_cluster(void);
|
||||
extern int get_main_cluster_fd(void); /* gets accept FD or cman cluster socket */
|
||||
extern int cluster_do_node_callback(struct local_client *client,
|
||||
void (*callback) (struct local_client *,
|
||||
char *csid, int node_up));
|
||||
extern int is_quorate(void);
|
||||
|
||||
extern void get_our_csid(char *csid);
|
||||
extern void add_up_node(char *csid);
|
||||
extern void cluster_closedown(void);
|
||||
|
||||
extern int sync_lock(const char *resource, int mode, int flags, int *lockid);
|
||||
extern int sync_unlock(const char *resource, int lockid);
|
||||
|
||||
#ifdef USE_GULM
|
||||
#include "tcp-comms.h"
|
||||
#else
|
||||
/* cman */
|
||||
#include "cnxman-socket.h"
|
||||
#define MAX_CSID_LEN 4
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
880
daemons/clvmd/clvmd-gulm.c
Normal file
880
daemons/clvmd/clvmd-gulm.c
Normal file
@@ -0,0 +1,880 @@
|
||||
/******************************************************************************
|
||||
*******************************************************************************
|
||||
**
|
||||
** Copyright (C) Sistina Software, Inc. 2002-2003 All rights reserved.
|
||||
**
|
||||
*******************************************************************************
|
||||
******************************************************************************/
|
||||
|
||||
/* This provides the interface between clvmd and gulm as the cluster
|
||||
* and lock manager.
|
||||
*
|
||||
* It also provides the "liblm" functions too as it's hard (and pointless)
|
||||
* to seperate them out when using gulm.
|
||||
*
|
||||
* What it does /not/ provide is the communications between clvmd daemons
|
||||
* on the cluster nodes. That is done in tcp-comms.c
|
||||
*/
|
||||
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <utmpx.h>
|
||||
#include <syslog.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "ccs.h"
|
||||
#include "list.h"
|
||||
#include "locking.h"
|
||||
#include "log.h"
|
||||
#include "clvm.h"
|
||||
#include "clvmd-comms.h"
|
||||
#include "clvmd.h"
|
||||
#include "hash.h"
|
||||
#include "clvmd-gulm.h"
|
||||
#include "libgulm.h"
|
||||
#include "hash.h"
|
||||
|
||||
/* Hash list of nodes in the cluster */
|
||||
static struct hash_table *node_hash;
|
||||
|
||||
/* hash list of outstanding lock requests */
|
||||
static struct hash_table *lock_hash;
|
||||
|
||||
/* Copy of the current core state */
|
||||
static uint8_t current_corestate;
|
||||
|
||||
/* Number of active nodes */
|
||||
static int num_nodes;
|
||||
|
||||
static char *cluster_name;
|
||||
|
||||
static pthread_mutex_t lock_start_mutex;
|
||||
static volatile int lock_start_flag;
|
||||
|
||||
struct node_info
|
||||
{
|
||||
enum {NODE_UNKNOWN, NODE_DOWN, NODE_UP, NODE_CLVMD} state;
|
||||
char name[MAX_CLUSTER_MEMBER_NAME_LEN];
|
||||
};
|
||||
|
||||
struct lock_wait
|
||||
{
|
||||
pthread_cond_t cond;
|
||||
pthread_mutex_t mutex;
|
||||
int status;
|
||||
};
|
||||
|
||||
/* Forward */
|
||||
static int read_from_core_sock(struct local_client *client, char *buf, int len, char *csid,
|
||||
struct local_client **new_client);
|
||||
static int read_from_lock_sock(struct local_client *client, char *buf, int len, char *csid,
|
||||
struct local_client **new_client);
|
||||
static int get_all_cluster_nodes(void);
|
||||
|
||||
/* In tcp-comms.c */
|
||||
extern struct hash_table *sock_hash;
|
||||
|
||||
static int add_internal_client(int fd, fd_callback_t callback)
|
||||
{
|
||||
struct local_client *client;
|
||||
|
||||
DEBUGLOG("Add_internal_client, fd = %d\n", fd);
|
||||
|
||||
/* Add a GULM file descriptor it to the main loop */
|
||||
client = malloc(sizeof(struct local_client));
|
||||
if (!client)
|
||||
{
|
||||
DEBUGLOG("malloc failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(client, 0, sizeof(struct local_client));
|
||||
client->fd = fd;
|
||||
client->type = CLUSTER_INTERNAL;
|
||||
client->callback = callback;
|
||||
add_client(client);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Gulm library handle */
|
||||
static gulm_interface_p gulm_if;
|
||||
static lg_core_callbacks_t core_callbacks;
|
||||
static lg_lockspace_callbacks_t lock_callbacks;
|
||||
|
||||
static void badsig_handler(int sig)
|
||||
{
|
||||
DEBUGLOG("got sig %d\n", sig);
|
||||
cluster_closedown();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static void sighup_handler(int sig)
|
||||
{
|
||||
DEBUGLOG("got SIGHUP\n");
|
||||
|
||||
/* Re-read CCS node list */
|
||||
get_all_cluster_nodes();
|
||||
}
|
||||
|
||||
int init_cluster()
|
||||
{
|
||||
int status;
|
||||
int ccs_h;
|
||||
|
||||
/* Get cluster name from CCS */
|
||||
/* TODO: is this right? */
|
||||
ccs_h = ccs_connect();
|
||||
ccs_get(ccs_h, "//cluster/@name", &cluster_name);
|
||||
ccs_disconnect(ccs_h);
|
||||
|
||||
/* Block locking until we are logged in */
|
||||
pthread_mutex_init(&lock_start_mutex, NULL);
|
||||
pthread_mutex_lock(&lock_start_mutex);
|
||||
lock_start_flag = 1;
|
||||
|
||||
node_hash = hash_create(100);
|
||||
lock_hash = hash_create(10);
|
||||
|
||||
/* Get all nodes from CCS */
|
||||
get_all_cluster_nodes();
|
||||
|
||||
/* Initialise GULM library */
|
||||
status = lg_initialize(&gulm_if, cluster_name, "clvmd");
|
||||
if (status)
|
||||
{
|
||||
DEBUGLOG("lg_initialize failed: %d\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Connect to core - we are not "important" :-) */
|
||||
status = lg_core_login(gulm_if, 0);
|
||||
if (status)
|
||||
{
|
||||
DEBUGLOG("lg_core_login failed: %d\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Initialise the inter-node comms */
|
||||
status = init_comms();
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
/* Add core FD to the list */
|
||||
status = add_internal_client(lg_core_selector(gulm_if), read_from_core_sock);
|
||||
if (status)
|
||||
{
|
||||
DEBUGLOG("can't allocate client space\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Connect to the lock server */
|
||||
if (lg_lock_login(gulm_if, "CLVM"))
|
||||
{
|
||||
syslog(LOG_ERR, "Cannot login in to LOCK server\n");
|
||||
DEBUGLOG("Cannot login in to LOCK server\n");
|
||||
exit(88);
|
||||
}
|
||||
|
||||
/* Add lockspace FD to the list */
|
||||
status = add_internal_client(lg_lock_selector(gulm_if), read_from_lock_sock);
|
||||
if (status)
|
||||
{
|
||||
DEBUGLOG("can't allocate client space\n");
|
||||
exit(status);
|
||||
}
|
||||
|
||||
/* Request a list of nodes, we can;t really do anything until
|
||||
this comes back */
|
||||
status = lg_core_nodelist(gulm_if);
|
||||
if (status)
|
||||
{
|
||||
DEBUGLOG("lg_core_nodelist failed: %d\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* So I can kill it without taking GULM down too */
|
||||
signal(SIGINT, badsig_handler);
|
||||
signal(SIGTERM, badsig_handler);
|
||||
|
||||
/* Re-read the node list on SIGHUP */
|
||||
signal(SIGHUP, sighup_handler);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cluster_closedown()
|
||||
{
|
||||
DEBUGLOG("cluster_closedown\n");
|
||||
lg_lock_logout(gulm_if);
|
||||
lg_core_logout(gulm_if);
|
||||
lg_core_shutdown(gulm_if);
|
||||
lg_release(gulm_if);
|
||||
}
|
||||
|
||||
/* Expire locks for a named node, or us */
|
||||
#define GIO_KEY_SIZE 46
|
||||
static void drop_expired_locks(char *nodename)
|
||||
{
|
||||
struct utsname nodeinfo;
|
||||
uint8_t mask[GIO_KEY_SIZE];
|
||||
|
||||
memset(mask, 0xff, GIO_KEY_SIZE);
|
||||
|
||||
if (!nodename)
|
||||
{
|
||||
uname(&nodeinfo);
|
||||
nodename = nodeinfo.nodename;
|
||||
}
|
||||
|
||||
if (lg_lock_drop_exp(gulm_if, nodename, mask, GIO_KEY_SIZE))
|
||||
{
|
||||
DEBUGLOG("Error calling lg_lock_drop_exp()\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int read_from_core_sock(struct local_client *client, char *buf, int len, char *csid,
|
||||
struct local_client **new_client)
|
||||
{
|
||||
int status;
|
||||
|
||||
*new_client = NULL;
|
||||
status = lg_core_handle_messages(gulm_if, &core_callbacks, NULL);
|
||||
return status<0 ? status : 1;
|
||||
}
|
||||
|
||||
static int read_from_lock_sock(struct local_client *client, char *buf, int len, char *csid,
|
||||
struct local_client **new_client)
|
||||
{
|
||||
int status;
|
||||
|
||||
*new_client = NULL;
|
||||
status = lg_lock_handle_messages(gulm_if, &lock_callbacks, NULL);
|
||||
return status<0 ? status : 1;
|
||||
}
|
||||
|
||||
|
||||
/* CORE callback routines */
|
||||
static int core_login_reply(void *misc, uint64_t gen, uint32_t error, uint32_t rank, uint8_t corestate)
|
||||
{
|
||||
DEBUGLOG("CORE Got a Login reply. gen:%lld err:%d rank:%d corestate:%d\n",
|
||||
gen, error, rank, corestate);
|
||||
|
||||
if (error)
|
||||
exit(error);
|
||||
|
||||
current_corestate = corestate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void set_node_state(struct node_info *ninfo, char *csid, uint8_t nodestate)
|
||||
{
|
||||
if (nodestate == lg_core_Logged_in)
|
||||
{
|
||||
/* Don't clobber NODE_CLVMD state */
|
||||
if (ninfo->state != NODE_CLVMD)
|
||||
{
|
||||
if (ninfo->state == NODE_UNKNOWN ||
|
||||
ninfo->state == NODE_DOWN)
|
||||
num_nodes++;
|
||||
|
||||
ninfo->state = NODE_UP;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (nodestate == lg_core_Expired ||
|
||||
nodestate == lg_core_Fenced ||
|
||||
nodestate == lg_core_Logged_out)
|
||||
{
|
||||
if (ninfo->state != NODE_DOWN)
|
||||
num_nodes--;
|
||||
ninfo->state = NODE_DOWN;
|
||||
tcp_remove_client(csid);
|
||||
}
|
||||
}
|
||||
DEBUGLOG("set_node_state, '%s' state = %d, num_nodes=%d\n",
|
||||
ninfo->name, ninfo->state, num_nodes);
|
||||
}
|
||||
|
||||
static struct node_info *add_or_set_node(char *name, uint32_t ip, uint8_t state)
|
||||
{
|
||||
struct node_info *ninfo;
|
||||
|
||||
ninfo = hash_lookup_binary(node_hash, (char *)&ip, MAX_CSID_LEN);
|
||||
if (!ninfo)
|
||||
{
|
||||
/* If we can't find that node then re-read the config file in case it
|
||||
was added after we were started */
|
||||
DEBUGLOG("Node %s not found, re-reading config file\n", name);
|
||||
get_all_cluster_nodes();
|
||||
|
||||
/* Now try again */
|
||||
ninfo = hash_lookup_binary(node_hash, (char *)&ip, MAX_CSID_LEN);
|
||||
if (!ninfo)
|
||||
{
|
||||
DEBUGLOG("Ignoring node %s, not part of the SAN cluster\n", name);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
set_node_state(ninfo, (char *)&ip, state);
|
||||
|
||||
return ninfo;
|
||||
}
|
||||
|
||||
static int core_nodelist(void *misc, lglcb_t type, char *name, uint32_t ip, uint8_t state)
|
||||
{
|
||||
DEBUGLOG("CORE nodelist\n");
|
||||
|
||||
if (type == lglcb_start)
|
||||
{
|
||||
DEBUGLOG("Got Nodelist, start\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (type == lglcb_item)
|
||||
{
|
||||
DEBUGLOG("Got nodelist, item: %s, %#x, %#x\n", name, ip, state);
|
||||
|
||||
add_or_set_node(name, ip, state);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (type == lglcb_stop)
|
||||
{
|
||||
char ourcsid[MAX_CSID_LEN];
|
||||
|
||||
DEBUGLOG("Got Nodelist, stop\n");
|
||||
clvmd_cluster_init_completed();
|
||||
|
||||
/* Mark ourself as up */
|
||||
get_our_csid(ourcsid);
|
||||
add_up_node(ourcsid);
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUGLOG("Unknown lglcb_t %#x\n", type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int core_statechange(void *misc, uint8_t corestate, uint32_t masterip, char *mastername)
|
||||
{
|
||||
DEBUGLOG("CORE Got statechange corestate:%#x masterip:%#x mastername:%s\n",
|
||||
corestate, masterip, mastername);
|
||||
|
||||
current_corestate = corestate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int core_nodechange(void *misc, char *nodename, uint32_t nodeip, uint8_t nodestate)
|
||||
{
|
||||
struct node_info *ninfo;
|
||||
|
||||
DEBUGLOG("CORE node change, name=%s, ip=%x, state = %d\n", nodename, nodeip, nodestate);
|
||||
|
||||
/* If we don't get nodeip here, try a lookup by name */
|
||||
if (!nodeip)
|
||||
csid_from_name((char *)&nodeip, nodename);
|
||||
if (!nodeip)
|
||||
return 0;
|
||||
|
||||
ninfo = add_or_set_node(nodename, nodeip, nodestate);
|
||||
if (!ninfo)
|
||||
return 0;
|
||||
|
||||
/* Check if we need to drop any expired locks */
|
||||
if (ninfo->state == NODE_DOWN)
|
||||
{
|
||||
drop_expired_locks(nodename);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
static int core_error(void *misc, uint32_t err)
|
||||
{
|
||||
DEBUGLOG("CORE error: %d\n", err);
|
||||
// Not sure what happens here
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* LOCK callback routines */
|
||||
static int lock_login_reply(void *misc, uint32_t error, uint8_t which)
|
||||
{
|
||||
DEBUGLOG("LOCK Got a Login reply. err:%d which:%d\n",
|
||||
error, which);
|
||||
|
||||
if (error)
|
||||
exit(error);
|
||||
|
||||
/* Drop any expired locks for us that might be hanging around */
|
||||
drop_expired_locks(NULL);
|
||||
|
||||
/* Enable locking operations in other threads */
|
||||
if (lock_start_flag)
|
||||
{
|
||||
lock_start_flag = 0;
|
||||
pthread_mutex_unlock(&lock_start_mutex);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lock_lock_state(void *misc, uint8_t *key, uint16_t keylen, uint8_t state, uint32_t flags, uint32_t error,
|
||||
uint8_t *LVB, uint16_t LVBlen)
|
||||
{
|
||||
struct lock_wait *lwait;
|
||||
|
||||
DEBUGLOG("LOCK lock state: %s, error = %d\n", key, error);
|
||||
|
||||
lwait = hash_lookup(lock_hash, key);
|
||||
if (!lwait)
|
||||
{
|
||||
DEBUGLOG("Can't find hash entry for resource %s\n", key);
|
||||
return 0;
|
||||
}
|
||||
lwait->status = error;
|
||||
pthread_mutex_lock(&lwait->mutex);
|
||||
pthread_cond_signal(&lwait->cond);
|
||||
pthread_mutex_unlock(&lwait->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
static int lock_error(void *misc, uint32_t err)
|
||||
{
|
||||
DEBUGLOG("LOCK error: %d\n", err);
|
||||
// Not sure what happens here
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* CORE callbacks */
|
||||
static lg_core_callbacks_t core_callbacks = {
|
||||
.login_reply = core_login_reply,
|
||||
.nodelist = core_nodelist,
|
||||
.statechange = core_statechange,
|
||||
.nodechange = core_nodechange,
|
||||
.error = core_error,
|
||||
};
|
||||
|
||||
/* LOCK callbacks */
|
||||
static lg_lockspace_callbacks_t lock_callbacks = {
|
||||
.login_reply = lock_login_reply,
|
||||
.lock_state = lock_lock_state,
|
||||
.error = lock_error,
|
||||
};
|
||||
|
||||
/* Allow tcp-comms to loop round the list of active nodes */
|
||||
int get_next_node_csid(void **context, char *csid)
|
||||
{
|
||||
struct node_info *ninfo = NULL;
|
||||
|
||||
/* First node */
|
||||
if (!*context)
|
||||
{
|
||||
*context = hash_get_first(node_hash);
|
||||
}
|
||||
else
|
||||
{
|
||||
*context = hash_get_next(node_hash, *context);
|
||||
}
|
||||
if (*context)
|
||||
ninfo = hash_get_data(node_hash, *context);
|
||||
|
||||
/* Find a node that is UP */
|
||||
while (*context && ninfo->state == NODE_DOWN)
|
||||
{
|
||||
*context = hash_get_next(node_hash, *context);
|
||||
if (*context)
|
||||
{
|
||||
ninfo = hash_get_data(node_hash, *context);
|
||||
}
|
||||
}
|
||||
|
||||
if (!*context || ninfo->state == NODE_DOWN)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(csid, hash_get_key(node_hash, *context), MAX_CSID_LEN);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int name_from_csid(char *csid, char *name)
|
||||
{
|
||||
struct node_info *ninfo;
|
||||
|
||||
ninfo = hash_lookup_binary(node_hash, csid, MAX_CSID_LEN);
|
||||
if (!ninfo)
|
||||
{
|
||||
sprintf(name, "UNKNOWN [%d.%d.%d.%d]",
|
||||
csid[0], csid[1], csid[2], csid[3]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
strcpy(name, ninfo->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int csid_from_name(char *csid, char *name)
|
||||
{
|
||||
struct hash_node *hn;
|
||||
struct node_info *ninfo;
|
||||
|
||||
hash_iterate(hn, node_hash)
|
||||
{
|
||||
ninfo = hash_get_data(node_hash, hn);
|
||||
if (strcmp(ninfo->name, name) == 0)
|
||||
{
|
||||
memcpy(csid, hash_get_key(node_hash, hn), MAX_CSID_LEN);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int get_num_nodes()
|
||||
{
|
||||
DEBUGLOG("num_nodes = %d\n", num_nodes);
|
||||
return num_nodes;
|
||||
}
|
||||
|
||||
/* Node is now known to be running a clvmd */
|
||||
void add_up_node(char *csid)
|
||||
{
|
||||
struct node_info *ninfo;
|
||||
|
||||
ninfo = hash_lookup_binary(node_hash, csid, MAX_CSID_LEN);
|
||||
if (!ninfo)
|
||||
return;
|
||||
|
||||
ninfo->state = NODE_CLVMD;
|
||||
return;
|
||||
|
||||
}
|
||||
/* Node is now known to be NOT running a clvmd */
|
||||
void add_down_node(char *csid)
|
||||
{
|
||||
struct node_info *ninfo;
|
||||
|
||||
ninfo = hash_lookup_binary(node_hash, csid, MAX_CSID_LEN);
|
||||
if (!ninfo)
|
||||
return;
|
||||
|
||||
/* Only set it to UP if it was previously known to be
|
||||
running clvmd - gulm may set it DOWN quite soon */
|
||||
if (ninfo->state == NODE_CLVMD)
|
||||
ninfo->state = NODE_UP;
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
/* Call a callback for each node, so the caller knows whether it's up or down */
|
||||
int cluster_do_node_callback(struct local_client *master_client,
|
||||
void (*callback)(struct local_client *, char *csid, int node_up))
|
||||
{
|
||||
struct hash_node *hn;
|
||||
struct node_info *ninfo;
|
||||
|
||||
hash_iterate(hn, node_hash)
|
||||
{
|
||||
char csid[MAX_CSID_LEN];
|
||||
struct local_client *client;
|
||||
|
||||
ninfo = hash_get_data(node_hash, hn);
|
||||
memcpy(csid, hash_get_key(node_hash, hn), MAX_CSID_LEN);
|
||||
|
||||
DEBUGLOG("down_callback. node %s, state = %d\n", ninfo->name, ninfo->state);
|
||||
|
||||
client = hash_lookup_binary(sock_hash, csid, MAX_CSID_LEN);
|
||||
if (client)
|
||||
callback(master_client, csid, ninfo->state == NODE_CLVMD);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Convert gulm error codes to unix errno numbers */
|
||||
static int gulm_to_errno(int gulm_ret)
|
||||
{
|
||||
switch (gulm_ret)
|
||||
{
|
||||
case lg_err_TryFailed:
|
||||
errno = EAGAIN;
|
||||
break;
|
||||
|
||||
case lg_err_AlreadyPend:
|
||||
errno = EBUSY;
|
||||
|
||||
/* More?? */
|
||||
default:
|
||||
errno = EINVAL;
|
||||
}
|
||||
|
||||
return gulm_ret ? -1 : 0;
|
||||
}
|
||||
|
||||
/* Real locking */
|
||||
static int _lock_resource(char *resource, int mode, int flags, int *lockid)
|
||||
{
|
||||
int status;
|
||||
struct lock_wait lwait;
|
||||
|
||||
/* Wait until the lock module is ready */
|
||||
if (lock_start_flag)
|
||||
{
|
||||
pthread_mutex_lock(&lock_start_mutex);
|
||||
pthread_mutex_unlock(&lock_start_mutex);
|
||||
}
|
||||
|
||||
pthread_cond_init(&lwait.cond, NULL);
|
||||
pthread_mutex_init(&lwait.mutex, NULL);
|
||||
pthread_mutex_lock(&lwait.mutex);
|
||||
|
||||
/* This needs to be converted from DLM/LVM2 value for GULM */
|
||||
if (flags == LCK_NONBLOCK) flags = lg_lock_flag_Try;
|
||||
|
||||
hash_insert(lock_hash, resource, &lwait);
|
||||
DEBUGLOG("lock_resource '%s', flags=%d, mode=%d\n", resource, flags, mode);
|
||||
|
||||
status = lg_lock_state_req(gulm_if, resource, strlen(resource)+1,
|
||||
mode, flags, NULL, 0);
|
||||
if (status)
|
||||
{
|
||||
DEBUGLOG("lg_lock_state returned %d\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Wait for it to complete */
|
||||
pthread_cond_wait(&lwait.cond, &lwait.mutex);
|
||||
pthread_mutex_unlock(&lwait.mutex);
|
||||
|
||||
hash_remove(lock_hash, resource);
|
||||
DEBUGLOG("lock-resource returning %d\n", lwait.status);
|
||||
|
||||
return gulm_to_errno(lwait.status);
|
||||
}
|
||||
|
||||
|
||||
static int _unlock_resource(char *resource, int lockid)
|
||||
{
|
||||
int status;
|
||||
struct lock_wait lwait;
|
||||
|
||||
pthread_cond_init(&lwait.cond, NULL);
|
||||
pthread_mutex_init(&lwait.mutex, NULL);
|
||||
pthread_mutex_lock(&lwait.mutex);
|
||||
|
||||
hash_insert(lock_hash, resource, &lwait);
|
||||
|
||||
DEBUGLOG("unlock_resource %s\n", resource);
|
||||
status = lg_lock_state_req(gulm_if, resource, strlen(resource)+1,
|
||||
lg_lock_state_Unlock, 0, NULL, 0);
|
||||
|
||||
if (status)
|
||||
{
|
||||
DEBUGLOG("lg_lock_state(unlock) returned %d\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Wait for it to complete */
|
||||
|
||||
pthread_cond_wait(&lwait.cond, &lwait.mutex);
|
||||
pthread_mutex_unlock(&lwait.mutex);
|
||||
|
||||
hash_remove(lock_hash, resource);
|
||||
|
||||
return gulm_to_errno(lwait.status);
|
||||
}
|
||||
|
||||
|
||||
/* These two locking functions MUST be called in a seperate thread from
|
||||
the clvmd main loop because they expect to be woken up by it.
|
||||
|
||||
These are abstractions around the real locking functions (above)
|
||||
as we need to emulate the DLM's EX/PW/CW interaction with GULM using
|
||||
two locks.
|
||||
To aid unlocking, we store the lock mode in the lockid (as GULM
|
||||
doesn't use this).
|
||||
*/
|
||||
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, lg_lock_state_Exclusive, flags, lockid);
|
||||
if (status)
|
||||
goto out;
|
||||
|
||||
/* If we can't get this lock then bail out */
|
||||
status = _lock_resource(lock2, lg_lock_state_Exclusive, LCK_NONBLOCK, lockid);
|
||||
if (status == lg_err_TryFailed)
|
||||
{
|
||||
_unlock_resource(lock1, *lockid);
|
||||
status = -1;
|
||||
errno = EAGAIN;
|
||||
}
|
||||
break;
|
||||
|
||||
case LCK_READ:
|
||||
status = _lock_resource(lock1, lg_lock_state_Shared, flags, lockid);
|
||||
break;
|
||||
|
||||
case LCK_WRITE:
|
||||
status = _lock_resource(lock2, lg_lock_state_Exclusive, flags, lockid);
|
||||
break;
|
||||
|
||||
default:
|
||||
status = -1;
|
||||
errno = EINVAL;
|
||||
break;
|
||||
}
|
||||
out:
|
||||
*lockid = mode;
|
||||
return status;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/* The held lock mode is in the lock id */
|
||||
assert(lockid == LCK_EXCL ||
|
||||
lockid == LCK_READ ||
|
||||
lockid == LCK_WRITE);
|
||||
|
||||
switch (lockid)
|
||||
{
|
||||
case LCK_EXCL:
|
||||
status = _unlock_resource(lock1, lockid);
|
||||
if (status)
|
||||
goto out;
|
||||
status = _unlock_resource(lock2, lockid);
|
||||
break;
|
||||
|
||||
case LCK_READ:
|
||||
status = _unlock_resource(lock1, lockid);
|
||||
break;
|
||||
|
||||
case LCK_WRITE:
|
||||
status = _unlock_resource(lock2, lockid);
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
||||
int is_quorate()
|
||||
{
|
||||
if (current_corestate == lg_core_Slave ||
|
||||
current_corestate == lg_core_Master ||
|
||||
current_corestate == lg_core_Client)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get all the cluster node names & IPs from CCS and
|
||||
add them to our node list so we know who to talk to.
|
||||
Called when we start up and if we get sent SIGHUP.
|
||||
*/
|
||||
static int get_all_cluster_nodes()
|
||||
{
|
||||
int ctree;
|
||||
char *nodename;
|
||||
int error;
|
||||
|
||||
/* Open the config file */
|
||||
ctree = ccs_connect();
|
||||
if (ctree <= 0)
|
||||
{
|
||||
log_error("Error connecting to CCS");
|
||||
return -1;
|
||||
}
|
||||
|
||||
error = ccs_get(ctree, "//nodes/node/@name", &nodename);
|
||||
while (nodename)
|
||||
{
|
||||
char nodeip[MAX_CSID_LEN];
|
||||
char *clvmflag;
|
||||
char key[256];
|
||||
|
||||
sprintf(key, "//nodes/node[@name=\"%s\"]/clvm", nodename);
|
||||
ccs_get(ctree, key, &clvmflag);
|
||||
|
||||
if ((get_ip_address(nodename, nodeip) == 0) && atoi(clvmflag))
|
||||
{
|
||||
struct node_info *ninfo;
|
||||
|
||||
/* If it's not in the list, then add it */
|
||||
ninfo = hash_lookup_binary(node_hash, nodeip, MAX_CSID_LEN);
|
||||
if (!ninfo)
|
||||
{
|
||||
ninfo = malloc(sizeof(struct node_info));
|
||||
if (!ninfo)
|
||||
{
|
||||
syslog(LOG_ERR, "Cannot alloc memory for node info\n");
|
||||
ccs_disconnect(ctree);
|
||||
return -1;
|
||||
}
|
||||
strcpy(ninfo->name, nodename);
|
||||
|
||||
ninfo->state = NODE_DOWN;
|
||||
hash_insert_binary(node_hash, nodeip, MAX_CSID_LEN, ninfo);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUGLOG("node %s has clvm disabled\n", nodename);
|
||||
}
|
||||
if (clvmflag) free(clvmflag);
|
||||
free(nodename);
|
||||
error = ccs_get(ctree, "//nodes/node/@name", &nodename);
|
||||
}
|
||||
|
||||
/* Finished with config file */
|
||||
ccs_disconnect(ctree);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gulm_fd(void)
|
||||
{
|
||||
return lg_core_selector(gulm_if);
|
||||
}
|
9
daemons/clvmd/clvmd-gulm.h
Normal file
9
daemons/clvmd/clvmd-gulm.h
Normal file
@@ -0,0 +1,9 @@
|
||||
|
||||
|
||||
|
||||
extern int get_next_node_csid(void **context, char *csid);
|
||||
extern void add_down_node(char *csid);
|
||||
extern int gulm_fd(void);
|
||||
extern int get_ip_address(char *node, char *addr);
|
||||
extern void tcp_remove_client(char *csid);
|
||||
extern int alloc_client(int fd, char *csid, struct local_client **new_client);
|
1693
daemons/clvmd/clvmd.c
Normal file
1693
daemons/clvmd/clvmd.c
Normal file
File diff suppressed because it is too large
Load Diff
119
daemons/clvmd/clvmd.h
Normal file
119
daemons/clvmd/clvmd.h
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _CLVMD_H
|
||||
#define _CLVMD_H
|
||||
|
||||
#define CLVMD_MAJOR_VERSION 0
|
||||
#define CLVMD_MINOR_VERSION 2
|
||||
#define CLVMD_PATCH_VERSION 1
|
||||
|
||||
/* Name of the cluster LVM admin lock */
|
||||
#define ADMIN_LOCK_NAME "CLVMD_ADMIN"
|
||||
|
||||
/* 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;
|
||||
};
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
struct local_client *pipe_client;
|
||||
pthread_t threadid;
|
||||
enum { PRE_COMMAND, POST_COMMAND, QUIT } state;
|
||||
pthread_mutex_t mutex; /* Main thread and worker synchronisation */
|
||||
pthread_cond_t cond;
|
||||
|
||||
pthread_mutex_t reply_mutex; /* Protect reply structure */
|
||||
};
|
||||
|
||||
/* 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,
|
||||
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;
|
||||
|
||||
union {
|
||||
struct localsock_bits localsock;
|
||||
struct pipe_bits pipe;
|
||||
struct netsock_bits net;
|
||||
} bits;
|
||||
};
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DEBUGLOG(fmt, args...) fprintf(stderr, "CLVMD[%d]: %ld ", getpid(), time(NULL) ); fprintf(stderr, fmt, ## args)
|
||||
#else
|
||||
#define DEBUGLOG(fmt, args...)
|
||||
#endif
|
||||
|
||||
#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 int add_client(struct local_client *new_client);
|
||||
|
||||
extern void clvmd_cluster_init_completed(void);
|
||||
|
||||
#endif
|
225
daemons/clvmd/cnxman-socket.h
Normal file
225
daemons/clvmd/cnxman-socket.h
Normal file
@@ -0,0 +1,225 @@
|
||||
/******************************************************************************
|
||||
*******************************************************************************
|
||||
**
|
||||
** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
|
||||
** Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||
**
|
||||
** This copyrighted material is made available to anyone wishing to use,
|
||||
** modify, copy, or redistribute it subject to the terms and conditions
|
||||
** of the GNU General Public License v.2.
|
||||
**
|
||||
*******************************************************************************
|
||||
******************************************************************************/
|
||||
|
||||
/* CMAN socket interface header,
|
||||
may be include by user or kernel code */
|
||||
|
||||
#ifndef __CNXMAN_SOCKET_H
|
||||
#define __CNXMAN_SOCKET_H
|
||||
|
||||
/* A currently unused number. TIPC also uses this number and you're unlikely
|
||||
to be using both.
|
||||
*/
|
||||
#define AF_CLUSTER 30
|
||||
#define PF_CLUSTER AF_CLUSTER
|
||||
|
||||
/* Protocol(socket) types */
|
||||
#define CLPROTO_MASTER 2
|
||||
#define CLPROTO_CLIENT 3
|
||||
|
||||
/* ioctls -- should register these properly */
|
||||
#define SIOCCLUSTER_NOTIFY _IOW('x', 0x01, int)
|
||||
#define SIOCCLUSTER_REMOVENOTIFY _IO( 'x', 0x02)
|
||||
#define SIOCCLUSTER_GETMEMBERS _IOR('x', 0x03, struct cl_cluster_nodelist)
|
||||
#define SIOCCLUSTER_SETEXPECTED_VOTES _IOW('x', 0x04, int)
|
||||
#define SIOCCLUSTER_ISQUORATE _IO( 'x', 0x05)
|
||||
#define SIOCCLUSTER_ISLISTENING _IOW('x', 0x06, struct cl_listen_request)
|
||||
#define SIOCCLUSTER_GETALLMEMBERS _IOR('x', 0x07, struct cl_cluster_nodelist)
|
||||
#define SIOCCLUSTER_SET_VOTES _IOW('x', 0x08, int)
|
||||
#define SIOCCLUSTER_GET_VERSION _IOR('x', 0x09, struct cl_version)
|
||||
#define SIOCCLUSTER_SET_VERSION _IOW('x', 0x0a, struct cl_version)
|
||||
#define SIOCCLUSTER_ISACTIVE _IO( 'x', 0x0b)
|
||||
#define SIOCCLUSTER_KILLNODE _IOW('x', 0x0c, int)
|
||||
#define SIOCCLUSTER_GET_JOINCOUNT _IO( 'x', 0x0d)
|
||||
#define SIOCCLUSTER_SERVICE_REGISTER _IOW('x', 0x0e, char)
|
||||
#define SIOCCLUSTER_SERVICE_UNREGISTER _IO('x', 0x0f)
|
||||
#define SIOCCLUSTER_SERVICE_JOIN _IO( 'x', 0x10)
|
||||
#define SIOCCLUSTER_SERVICE_LEAVE _IO( 'x', 0x20)
|
||||
#define SIOCCLUSTER_SERVICE_SETSIGNAL _IOW('x', 0x30, int)
|
||||
#define SIOCCLUSTER_SERVICE_STARTDONE _IOW('x', 0x40, unsigned int)
|
||||
#define SIOCCLUSTER_SERVICE_GETEVENT _IOR('x', 0x50, struct cl_service_event)
|
||||
#define SIOCCLUSTER_SERVICE_GETMEMBERS _IOR('x', 0x60, struct cl_cluster_nodelist)
|
||||
#define SIOCCLUSTER_SERVICE_GLOBALID _IOR('x', 0x70, uint32_t)
|
||||
#define SIOCCLUSTER_SERVICE_SETLEVEL _IOR('x', 0x80, int)
|
||||
#define SIOCCLUSTER_GETNODE _IOWR('x', 0x90, struct cl_cluster_node)
|
||||
#define SIOCCLUSTER_BARRIER _IOW('x', 0x0a0, struct cl_barrier_info)
|
||||
|
||||
/* These were setsockopts */
|
||||
#define SIOCCLUSTER_PASS_SOCKET _IOW('x', 0x0b0, struct cl_passed_sock)
|
||||
#define SIOCCLUSTER_SET_NODENAME _IOW('x', 0x0b1, char *)
|
||||
#define SIOCCLUSTER_SET_NODEID _IOW('x', 0x0b2, int)
|
||||
#define SIOCCLUSTER_JOIN_CLUSTER _IOW('x', 0x0b3, struct cl_join_cluster_info)
|
||||
#define SIOCCLUSTER_LEAVE_CLUSTER _IOW('x', 0x0b4, int)
|
||||
|
||||
|
||||
/* Maximum size of a cluster message */
|
||||
#define MAX_CLUSTER_MESSAGE 1500
|
||||
#define MAX_CLUSTER_MEMBER_NAME_LEN 255
|
||||
#define MAX_BARRIER_NAME_LEN 33
|
||||
#define MAX_SA_ADDR_LEN 12
|
||||
#define MAX_CLUSTER_NAME_LEN 16
|
||||
|
||||
/* Well-known cluster port numbers */
|
||||
#define CLUSTER_PORT_MEMBERSHIP 1 /* Mustn't block during cluster
|
||||
* transitions! */
|
||||
#define CLUSTER_PORT_SERVICES 2
|
||||
#define CLUSTER_PORT_SYSMAN 10 /* Remote execution daemon */
|
||||
#define CLUSTER_PORT_CLVMD 11 /* Cluster LVM daemon */
|
||||
#define CLUSTER_PORT_SLM 12 /* LVM SLM (simple lock manager) */
|
||||
|
||||
/* Port numbers above this will be blocked when the cluster is inquorate or in
|
||||
* transition */
|
||||
#define HIGH_PROTECTED_PORT 9
|
||||
|
||||
/* Reasons for leaving the cluster */
|
||||
#define CLUSTER_LEAVEFLAG_DOWN 0 /* Normal shutdown */
|
||||
#define CLUSTER_LEAVEFLAG_KILLED 1
|
||||
#define CLUSTER_LEAVEFLAG_PANIC 2
|
||||
#define CLUSTER_LEAVEFLAG_REMOVED 3 /* This one can reduce quorum */
|
||||
#define CLUSTER_LEAVEFLAG_REJECTED 4 /* Not allowed into the cluster in the
|
||||
* first place */
|
||||
#define CLUSTER_LEAVEFLAG_INCONSISTENT 5 /* Our view of the cluster is
|
||||
* in a minority */
|
||||
#define CLUSTER_LEAVEFLAG_DEAD 6 /* Discovered to be dead */
|
||||
#define CLUSTER_LEAVEFLAG_FORCE 0x10 /* Forced by command-line */
|
||||
|
||||
/* OOB messages sent to a local socket */
|
||||
#define CLUSTER_OOB_MSG_PORTCLOSED 1
|
||||
#define CLUSTER_OOB_MSG_STATECHANGE 2
|
||||
#define CLUSTER_OOB_MSG_SERVICEEVENT 3
|
||||
|
||||
/* Sendmsg flags, these are above the normal sendmsg flags so they don't
|
||||
* interfere */
|
||||
#define MSG_NOACK 0x010000 /* Don't need an ACK for this message */
|
||||
#define MSG_QUEUE 0x020000 /* Queue the message for sending later */
|
||||
#define MSG_MULTICAST 0x080000 /* Message was sent to all nodes in the cluster
|
||||
*/
|
||||
#define MSG_ALLINT 0x100000 /* Send out of all interfaces */
|
||||
|
||||
typedef enum { NODESTATE_REMOTEMEMBER, NODESTATE_JOINING, NODESTATE_MEMBER,
|
||||
NODESTATE_DEAD } nodestate_t;
|
||||
|
||||
|
||||
struct sockaddr_cl {
|
||||
unsigned short scl_family;
|
||||
unsigned char scl_flags;
|
||||
unsigned char scl_port;
|
||||
int scl_nodeid;
|
||||
};
|
||||
|
||||
/*
|
||||
* This is how we pass the multicast & receive sockets into kernel space.
|
||||
*/
|
||||
struct cl_passed_sock {
|
||||
int fd; /* FD of master socket to do multicast on */
|
||||
int number; /* Socket number, to match up recvonly & bcast
|
||||
* sockets */
|
||||
int multicast; /* Is it multicast or receive ? */
|
||||
};
|
||||
|
||||
/* Cluster configuration info passed when we join the cluster */
|
||||
struct cl_join_cluster_info {
|
||||
unsigned char votes;
|
||||
unsigned int expected_votes;
|
||||
unsigned int two_node;
|
||||
unsigned int config_version;
|
||||
|
||||
char cluster_name[17];
|
||||
};
|
||||
|
||||
|
||||
/* This is the structure, per node, returned from the membership ioctl */
|
||||
struct cl_cluster_node {
|
||||
unsigned int size;
|
||||
unsigned int node_id;
|
||||
unsigned int us;
|
||||
unsigned int leave_reason;
|
||||
unsigned int incarnation;
|
||||
nodestate_t state;
|
||||
char name[MAX_CLUSTER_MEMBER_NAME_LEN];
|
||||
unsigned char votes;
|
||||
};
|
||||
|
||||
/* The struct passed to the membership ioctls */
|
||||
struct cl_cluster_nodelist {
|
||||
uint32_t max_members;
|
||||
struct cl_cluster_node *nodes;
|
||||
};
|
||||
|
||||
/* Structure passed to SIOCCLUSTER_ISLISTENING */
|
||||
struct cl_listen_request {
|
||||
unsigned char port;
|
||||
int nodeid;
|
||||
};
|
||||
|
||||
/* A Cluster PORTCLOSED message - received by a local user as an OOB message */
|
||||
struct cl_portclosed_oob {
|
||||
unsigned char cmd; /* CLUSTER_OOB_MSG_PORTCLOSED */
|
||||
unsigned char port;
|
||||
};
|
||||
|
||||
/* Get all version numbers or set the config version */
|
||||
struct cl_version {
|
||||
unsigned int major;
|
||||
unsigned int minor;
|
||||
unsigned int patch;
|
||||
unsigned int config;
|
||||
};
|
||||
|
||||
/* structure passed to barrier ioctls */
|
||||
struct cl_barrier_info {
|
||||
char cmd;
|
||||
char name[MAX_BARRIER_NAME_LEN];
|
||||
unsigned int flags;
|
||||
unsigned long arg;
|
||||
};
|
||||
|
||||
typedef enum { SERVICE_EVENT_STOP, SERVICE_EVENT_START, SERVICE_EVENT_FINISH,
|
||||
SERVICE_EVENT_LEAVEDONE } service_event_t;
|
||||
|
||||
typedef enum { SERVICE_START_FAILED, SERVICE_START_JOIN, SERVICE_START_LEAVE }
|
||||
service_start_t;
|
||||
|
||||
struct cl_service_event {
|
||||
service_event_t type;
|
||||
service_start_t start_type;
|
||||
unsigned int event_id;
|
||||
unsigned int last_stop;
|
||||
unsigned int last_start;
|
||||
unsigned int last_finish;
|
||||
unsigned int node_count;
|
||||
};
|
||||
|
||||
|
||||
/* Commands to the barrier ioctl */
|
||||
#define BARRIER_IOCTL_REGISTER 1
|
||||
#define BARRIER_IOCTL_CHANGE 2
|
||||
#define BARRIER_IOCTL_DELETE 3
|
||||
#define BARRIER_IOCTL_WAIT 4
|
||||
|
||||
/* Attributes of a barrier - bitmask */
|
||||
#define BARRIER_ATTR_AUTODELETE 1
|
||||
#define BARRIER_ATTR_MULTISTEP 2
|
||||
#define BARRIER_ATTR_MANUAL 4
|
||||
#define BARRIER_ATTR_ENABLED 8
|
||||
#define BARRIER_ATTR_CALLBACK 16
|
||||
|
||||
/* Attribute setting commands */
|
||||
#define BARRIER_SETATTR_AUTODELETE 1
|
||||
#define BARRIER_SETATTR_MULTISTEP 2
|
||||
#define BARRIER_SETATTR_ENABLED 3
|
||||
#define BARRIER_SETATTR_NODES 4
|
||||
#define BARRIER_SETATTR_CALLBACK 5
|
||||
#define BARRIER_SETATTR_TIMEOUT 6
|
||||
|
||||
#endif
|
446
daemons/clvmd/libclvm.c
Normal file
446
daemons/clvmd/libclvm.c
Normal file
@@ -0,0 +1,446 @@
|
||||
/*
|
||||
* Copyright (C) 1997-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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* library functions for Cluster LVM Daemon */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <syslog.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <search.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "clvm.h"
|
||||
#include "libclvm.h"
|
||||
|
||||
/* CLVM in hex! */
|
||||
#define LVM_SIGNATURE 0x434C564D
|
||||
|
||||
#define MAX_CLUSTER_MEMBER_NAME_LEN 255
|
||||
|
||||
/* 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;
|
||||
|
||||
static int open_local_sock(void)
|
||||
{
|
||||
int local_socket;
|
||||
struct sockaddr_un sockaddr;
|
||||
|
||||
/* Open local socket */
|
||||
local_socket = socket(PF_UNIX, SOCK_STREAM, 0);
|
||||
if (local_socket < 0) {
|
||||
perror("Can't create local socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
fcntl(local_socket, F_SETFD, !FD_CLOEXEC);
|
||||
|
||||
strcpy(sockaddr.sun_path, CLVMD_SOCKNAME);
|
||||
sockaddr.sun_family = AF_UNIX;
|
||||
if (connect
|
||||
(local_socket, (struct sockaddr *) &sockaddr, sizeof(sockaddr))) {
|
||||
int saved_errno = errno;
|
||||
|
||||
close(local_socket);
|
||||
|
||||
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];
|
||||
struct clvm_header *outheader = (struct clvm_header *) outbuf;
|
||||
int len;
|
||||
int off;
|
||||
fd_set fds;
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(clvmd_sock, &fds);
|
||||
|
||||
/* Send it to CLVMD */
|
||||
if (write(clvmd_sock, inbuf, inlen) != inlen) {
|
||||
perror("Error writing to CLVMD");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get the response */
|
||||
if ((len = read(clvmd_sock, outbuf, sizeof(struct clvm_header))) < 0) {
|
||||
perror("Error reading CLVMD");
|
||||
return -1;
|
||||
}
|
||||
if (len == 0) {
|
||||
fprintf(stderr, "EOF reading CLVMD");
|
||||
errno = ENOTCONN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Allocate buffer */
|
||||
*retbuf = malloc(len + outheader->arglen);
|
||||
if (!*retbuf) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 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, PIPE_BUF);
|
||||
if (len > 0)
|
||||
off += len;
|
||||
}
|
||||
|
||||
/* Was it an error ? */
|
||||
if (outheader->status < 0) {
|
||||
errno = -outheader->status;
|
||||
return -2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Build the structure header and parse-out wildcard node names */
|
||||
static void build_header(struct clvm_header *head, int cmd, const char *node,
|
||||
void *data, int len)
|
||||
{
|
||||
head->cmd = cmd;
|
||||
head->status = 0;
|
||||
head->flags = 0;
|
||||
head->clientid = 0;
|
||||
head->arglen = len;
|
||||
if (node) {
|
||||
/* Allow a couple of special node names:
|
||||
"*" for all nodes,
|
||||
"." for the local node only
|
||||
*/
|
||||
if (strcmp(node, "*") == 0) {
|
||||
head->node[0] = '\0';
|
||||
} else if (strcmp(node, ".") == 0) {
|
||||
head->node[0] = '\0';
|
||||
head->flags = CLVMD_FLAG_LOCAL;
|
||||
} else {
|
||||
strcpy(head->node, node);
|
||||
}
|
||||
} else {
|
||||
head->node[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/* Send a message to a(or all) node(s) in the cluster */
|
||||
int lvm_cluster_write(char cmd, char *node, void *data, int len)
|
||||
{
|
||||
char outbuf[sizeof(struct clvm_header) + len + strlen(node) + 1];
|
||||
char *retbuf = NULL;
|
||||
int status;
|
||||
struct clvm_header *head = (struct clvm_header *) outbuf;
|
||||
|
||||
if (clvmd_sock == -1)
|
||||
clvmd_sock = open_local_sock();
|
||||
if (clvmd_sock == -1)
|
||||
return -1;
|
||||
|
||||
build_header(head, cmd, node, data, len);
|
||||
memcpy(head->node + strlen(head->node) + 1, data, len);
|
||||
|
||||
status =
|
||||
send_request(outbuf,
|
||||
sizeof(struct clvm_header) + strlen(head->node) + len,
|
||||
&retbuf);
|
||||
if (retbuf)
|
||||
free(retbuf);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* API: Send a message to a(or all) node(s) in the cluster
|
||||
and wait for replies */
|
||||
int lvm_cluster_request(char cmd, const char *node, void *data, int len,
|
||||
lvm_response_t ** response, int *num)
|
||||
{
|
||||
char outbuf[sizeof(struct clvm_header) + len + strlen(node) + 1];
|
||||
int *outptr;
|
||||
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 -1;
|
||||
|
||||
build_header(head, cmd, node, data, len);
|
||||
memcpy(head->node + strlen(head->node) + 1, data, len);
|
||||
|
||||
status =
|
||||
send_request(outbuf,
|
||||
sizeof(struct clvm_header) + strlen(head->node) + len,
|
||||
&retbuf);
|
||||
if (status == 0 || status == -2) {
|
||||
/* 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 */
|
||||
outptr =
|
||||
malloc(sizeof(lvm_response_t) * num_responses +
|
||||
sizeof(int) * 2);
|
||||
if (!outptr) {
|
||||
if (retbuf)
|
||||
free(retbuf);
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*response = (lvm_response_t *) (outptr + 2);
|
||||
outptr[0] = LVM_SIGNATURE;
|
||||
outptr[1] = num_responses;
|
||||
rarray = *response;
|
||||
|
||||
/* 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;
|
||||
|
||||
rarray[i].status = *(int *) inptr;
|
||||
inptr += sizeof(int);
|
||||
|
||||
rarray[i].response = malloc(strlen(inptr) + 1);
|
||||
if (rarray[i].response == NULL) {
|
||||
/* Free up everything else and return error */
|
||||
int j;
|
||||
for (j = 0; j < i; j++)
|
||||
free(rarray[i].response);
|
||||
free(outptr);
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
strcpy(rarray[i].response, inptr);
|
||||
rarray[i].len = strlen(inptr);
|
||||
inptr += strlen(inptr) + 1;
|
||||
i++;
|
||||
}
|
||||
*num = num_responses;
|
||||
*response = rarray;
|
||||
}
|
||||
|
||||
if (retbuf)
|
||||
free(retbuf);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* API: Free reply array */
|
||||
int lvm_cluster_free_request(lvm_response_t * response)
|
||||
{
|
||||
int *ptr = (int *) response - 2;
|
||||
int i;
|
||||
int num;
|
||||
|
||||
/* Check it's ours to free */
|
||||
if (response == NULL || *ptr != LVM_SIGNATURE) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
num = ptr[1];
|
||||
for (i = 0; i < num; i++) {
|
||||
free(response[i].response);
|
||||
}
|
||||
free(ptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* These are a "higher-level" API providing black-box lock/unlock
|
||||
functions for cluster LVM...maybe */
|
||||
|
||||
/* Set by lock(), used by unlock() */
|
||||
static int num_responses;
|
||||
static lvm_response_t *response;
|
||||
|
||||
int lvm_lock_for_cluster(char scope, char *name, int verbosity)
|
||||
{
|
||||
int status;
|
||||
int i;
|
||||
char *args;
|
||||
int len;
|
||||
|
||||
if (name) {
|
||||
len = strlen(name) + 2;
|
||||
args = alloca(len);
|
||||
strcpy(args + 1, name);
|
||||
} else {
|
||||
len = 2;
|
||||
args = alloca(len);
|
||||
args[1] = '\0';
|
||||
}
|
||||
args[0] = scope;
|
||||
|
||||
status = lvm_cluster_request(CLVMD_CMD_LOCK,
|
||||
"", 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) {
|
||||
if (verbosity)
|
||||
fprintf(stderr,
|
||||
"clvmd not running on node %s\n",
|
||||
response[i].node);
|
||||
status = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* If there was an error then free the memory now as the caller won't
|
||||
want to do the unlock */
|
||||
if (status) {
|
||||
int saved_errno = errno;
|
||||
lvm_cluster_free_request(response);
|
||||
num_responses = 0;
|
||||
errno = saved_errno;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
int lvm_unlock_for_cluster(char scope, char *name, int verbosity)
|
||||
{
|
||||
int status;
|
||||
int i;
|
||||
int len;
|
||||
int failed;
|
||||
int num_unlock_responses;
|
||||
char *args;
|
||||
lvm_response_t *unlock_response;
|
||||
|
||||
/* We failed - this should not have been called */
|
||||
if (num_responses == 0)
|
||||
return 0;
|
||||
|
||||
if (name) {
|
||||
len = strlen(name) + 2;
|
||||
args = alloca(len);
|
||||
strcpy(args + 1, name);
|
||||
} else {
|
||||
len = 2;
|
||||
args = alloca(len);
|
||||
args[1] = '\0';
|
||||
}
|
||||
args[0] = scope;
|
||||
|
||||
/* See if it failed anywhere */
|
||||
failed = 0;
|
||||
for (i = 0; i < num_responses; i++) {
|
||||
if (response[i].status != 0)
|
||||
failed++;
|
||||
}
|
||||
|
||||
/* If it failed on any nodes then we only unlock on
|
||||
the nodes that succeeded */
|
||||
if (failed) {
|
||||
for (i = 0; i < num_responses; i++) {
|
||||
/* Unlock the ones that succeeded */
|
||||
if (response[i].status == 0) {
|
||||
status = lvm_cluster_request(CLVMD_CMD_UNLOCK,
|
||||
response[i].node,
|
||||
args, len,
|
||||
&unlock_response,
|
||||
&num_unlock_responses);
|
||||
if (status) {
|
||||
if (verbosity)
|
||||
fprintf(stderr,
|
||||
"cluster command to node %s failed: %s\n",
|
||||
response[i].node,
|
||||
strerror(errno));
|
||||
} else if (unlock_response[0].status != 0) {
|
||||
if (verbosity > 1)
|
||||
fprintf(stderr,
|
||||
"unlock on node %s failed: %s\n",
|
||||
response[i].node,
|
||||
strerror(unlock_response
|
||||
[0].status));
|
||||
}
|
||||
lvm_cluster_free_request(unlock_response);
|
||||
} else {
|
||||
if (verbosity)
|
||||
fprintf(stderr,
|
||||
"command on node %s failed: '%s' - will be left locked\n",
|
||||
response[i].node,
|
||||
strerror(response[i].status));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* All OK, we can do a full cluster unlock */
|
||||
status = lvm_cluster_request(CLVMD_CMD_UNLOCK,
|
||||
"",
|
||||
args, len,
|
||||
&unlock_response,
|
||||
&num_unlock_responses);
|
||||
if (status) {
|
||||
if (verbosity > 1)
|
||||
fprintf(stderr, "cluster command failed: %s\n",
|
||||
strerror(errno));
|
||||
} else {
|
||||
for (i = 0; i < num_unlock_responses; i++) {
|
||||
if (unlock_response[i].status != 0) {
|
||||
if (verbosity > 1)
|
||||
fprintf(stderr,
|
||||
"unlock on node %s failed: %s\n",
|
||||
response[i].node,
|
||||
strerror(unlock_response
|
||||
[0].status));
|
||||
}
|
||||
}
|
||||
}
|
||||
lvm_cluster_free_request(unlock_response);
|
||||
}
|
||||
lvm_cluster_free_request(response);
|
||||
|
||||
return 0;
|
||||
}
|
36
daemons/clvmd/libclvm.h
Normal file
36
daemons/clvmd/libclvm.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 1997-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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _LIBCLVM_H
|
||||
#define _LIBCLVM_H
|
||||
|
||||
typedef struct lvm_response {
|
||||
char node[255];
|
||||
char *response;
|
||||
int status;
|
||||
int len;
|
||||
|
||||
} lvm_response_t;
|
||||
|
||||
extern int lvm_cluster_request(char cmd, const char *node, void *data, int len,
|
||||
lvm_response_t ** response, int *num);
|
||||
extern int lvm_cluster_write(char cmd, char *node, void *data, int len);
|
||||
extern int lvm_cluster_free_request(lvm_response_t * response);
|
||||
|
||||
/* The "high-level" API */
|
||||
extern int lvm_lock_for_cluster(char scope, char *name, int verbosity);
|
||||
extern int lvm_unlock_for_cluster(char scope, char *name, int verbosity);
|
||||
|
||||
#endif
|
447
daemons/clvmd/lvm-functions.c
Normal file
447
daemons/clvmd/lvm-functions.c
Normal file
@@ -0,0 +1,447 @@
|
||||
/*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <syslog.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "libdlm.h"
|
||||
#include "clvm.h"
|
||||
#include "clvmd-comms.h"
|
||||
#include "clvmd.h"
|
||||
#include "lvm-functions.h"
|
||||
|
||||
/* LVM2 headers */
|
||||
#include "toolcontext.h"
|
||||
#include "log.h"
|
||||
#include "activate.h"
|
||||
#include "hash.h"
|
||||
#include "locking.h"
|
||||
|
||||
static struct cmd_context *cmd = NULL;
|
||||
static struct hash_table *lv_hash = NULL;
|
||||
|
||||
struct lv_info {
|
||||
int lock_id;
|
||||
int lock_mode;
|
||||
};
|
||||
|
||||
/* 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;
|
||||
|
||||
lvi = hash_lookup(lv_hash, resource);
|
||||
if (lvi) {
|
||||
return lvi->lock_mode;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Called at shutdown to tidy the lockspace */
|
||||
void unlock_all()
|
||||
{
|
||||
struct hash_node *v;
|
||||
hash_iterate(v, lv_hash) {
|
||||
struct lv_info *lvi = hash_get_data(lv_hash, v);
|
||||
|
||||
sync_unlock(hash_get_key(lv_hash, v), lvi->lock_id);
|
||||
}
|
||||
}
|
||||
|
||||
/* Gets a real lock and keeps the info in the hash table */
|
||||
int hold_lock(char *resource, int mode, int flags)
|
||||
{
|
||||
int status;
|
||||
int saved_errno;
|
||||
struct lv_info *lvi;
|
||||
|
||||
flags &= LKF_NOQUEUE; /* Only LKF_NOQUEUE is valid here */
|
||||
|
||||
lvi = hash_lookup(lv_hash, resource);
|
||||
if (lvi) {
|
||||
/* Already exists - convert it */
|
||||
status =
|
||||
sync_lock(resource, mode, LKF_CONVERT | flags,
|
||||
&lvi->lock_id);
|
||||
saved_errno = errno;
|
||||
if (!status)
|
||||
lvi->lock_mode = mode;
|
||||
|
||||
if (status) {
|
||||
DEBUGLOG("hold_lock. convert to %d failed: %s\n", mode,
|
||||
strerror(errno));
|
||||
}
|
||||
errno = saved_errno;
|
||||
} else {
|
||||
lvi = malloc(sizeof(struct lv_info));
|
||||
if (!lvi)
|
||||
return -1;
|
||||
|
||||
lvi->lock_mode = mode;
|
||||
status = sync_lock(resource, mode, flags, &lvi->lock_id);
|
||||
saved_errno = errno;
|
||||
if (status) {
|
||||
free(lvi);
|
||||
DEBUGLOG("hold_lock. lock at %d failed: %s\n", mode,
|
||||
strerror(errno));
|
||||
} else {
|
||||
hash_insert(lv_hash, resource, lvi);
|
||||
}
|
||||
errno = saved_errno;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Unlock and remove it from the hash table */
|
||||
int hold_unlock(char *resource)
|
||||
{
|
||||
struct lv_info *lvi;
|
||||
int status;
|
||||
int saved_errno;
|
||||
|
||||
lvi = hash_lookup(lv_hash, resource);
|
||||
|
||||
if (!lvi) {
|
||||
DEBUGLOG("hold_unlock, lock not already held\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
status = sync_unlock(resource, lvi->lock_id);
|
||||
saved_errno = errno;
|
||||
if (!status) {
|
||||
hash_remove(lv_hash, resource);
|
||||
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, int mode)
|
||||
{
|
||||
int oldmode;
|
||||
int status;
|
||||
int activate_lv;
|
||||
struct lvinfo lvi;
|
||||
|
||||
/* Is it already open ? */
|
||||
oldmode = get_current_lock(resource);
|
||||
if (oldmode == mode) {
|
||||
return 0; /* Nothing to do */
|
||||
}
|
||||
|
||||
/* Does the config file want us to activate this LV ? */
|
||||
if (!lv_activation_filter(cmd, resource, &activate_lv))
|
||||
return EIO;
|
||||
|
||||
if (!activate_lv)
|
||||
return 0; /* Success, we did nothing! */
|
||||
|
||||
/* Do we need to activate exclusively? */
|
||||
if (activate_lv == 2)
|
||||
mode = LKM_EXMODE;
|
||||
|
||||
/* OK, try to get the lock */
|
||||
status = hold_lock(resource, mode, LKF_NOQUEUE);
|
||||
if (status)
|
||||
return errno;
|
||||
|
||||
/* If it's suspended then resume it */
|
||||
if (!lv_info_by_lvid(cmd, resource, &lvi))
|
||||
return EIO;
|
||||
|
||||
if (lvi.suspended)
|
||||
if (!lv_resume(cmd, resource))
|
||||
return EIO;
|
||||
|
||||
/* Now activate it */
|
||||
if (!lv_activate(cmd, resource))
|
||||
return EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Resume the LV if it was active */
|
||||
static int do_resume_lv(char *resource)
|
||||
{
|
||||
int oldmode;
|
||||
|
||||
/* Is it open ? */
|
||||
oldmode = get_current_lock(resource);
|
||||
if (oldmode == -1) {
|
||||
DEBUGLOG("do_deactivate_lock, lock not already held\n");
|
||||
return 0; /* We don't need to do anything */
|
||||
}
|
||||
|
||||
if (!lv_resume_if_active(cmd, resource))
|
||||
return EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Suspend the device if active */
|
||||
static int do_suspend_lv(char *resource)
|
||||
{
|
||||
int oldmode;
|
||||
struct lvinfo lvi;
|
||||
|
||||
/* Is it open ? */
|
||||
oldmode = get_current_lock(resource);
|
||||
if (oldmode == -1) {
|
||||
DEBUGLOG("do_suspend_lv, lock held at %d\n", oldmode);
|
||||
return 0; /* Not active, so it's OK */
|
||||
}
|
||||
|
||||
/* Only suspend it if it exists */
|
||||
if (!lv_info_by_lvid(cmd, resource, &lvi))
|
||||
return EIO;
|
||||
|
||||
if (lvi.exists) {
|
||||
if (!lv_suspend_if_active(cmd, resource)) {
|
||||
return EIO;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_deactivate_lv(char *resource)
|
||||
{
|
||||
int oldmode;
|
||||
int status;
|
||||
|
||||
/* Is it open ? */
|
||||
oldmode = get_current_lock(resource);
|
||||
if (oldmode == -1) {
|
||||
DEBUGLOG("do_deactivate_lock, lock not already held\n");
|
||||
return 0; /* We don't need to do anything */
|
||||
}
|
||||
|
||||
if (!lv_deactivate(cmd, resource))
|
||||
return EIO;
|
||||
|
||||
status = hold_unlock(resource);
|
||||
if (status)
|
||||
return errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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 = 0x%x, flags = %d\n",
|
||||
resource, command, lock_flags);
|
||||
|
||||
if (!cmd->config_valid || config_files_changed(cmd)) {
|
||||
/* Reinitialise various settings inc. logging, filters */
|
||||
if (!refresh_toolcontext(cmd)) {
|
||||
log_error("Updated config file invalid. Aborting.");
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
switch (command) {
|
||||
case LCK_LV_EXCLUSIVE:
|
||||
status = do_activate_lv(resource, LKM_EXMODE);
|
||||
break;
|
||||
|
||||
case LCK_LV_SUSPEND:
|
||||
status = do_suspend_lv(resource);
|
||||
break;
|
||||
|
||||
case LCK_UNLOCK:
|
||||
case LCK_LV_RESUME: /* if active */
|
||||
status = do_resume_lv(resource);
|
||||
break;
|
||||
|
||||
case LCK_LV_ACTIVATE:
|
||||
status = do_activate_lv(resource, LKM_CRMODE);
|
||||
break;
|
||||
|
||||
case LCK_LV_DEACTIVATE:
|
||||
status = do_deactivate_lv(resource);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUGLOG("Invalid LV command 0x%x\n", command);
|
||||
status = EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
/* clean the pool for another command */
|
||||
pool_empty(cmd->mem);
|
||||
|
||||
DEBUGLOG("Command return is %d\n", status);
|
||||
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.
|
||||
*/
|
||||
if (command == LCK_LV_SUSPEND) {
|
||||
DEBUGLOG("pre_lock_lv: resource '%s', cmd = 0x%x, flags = %d\n",
|
||||
resource, command, lock_flags);
|
||||
|
||||
if (hold_lock(resource, LKM_PWMODE, LKF_NOQUEUE))
|
||||
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)
|
||||
{
|
||||
/* Opposite of above, done on resume after a metadata update */
|
||||
if (command == LCK_LV_RESUME) {
|
||||
int oldmode;
|
||||
|
||||
DEBUGLOG
|
||||
("post_lock_lv: resource '%s', cmd = 0x%x, flags = %d\n",
|
||||
resource, command, lock_flags);
|
||||
|
||||
/* If the lock state is PW then restore it to what it was */
|
||||
oldmode = get_current_lock(resource);
|
||||
if (oldmode == LKM_PWMODE) {
|
||||
struct lvinfo lvi;
|
||||
|
||||
if (!lv_info_by_lvid(cmd, resource, &lvi))
|
||||
return EIO;
|
||||
|
||||
if (lvi.exists) {
|
||||
if (hold_lock(resource, LKM_CRMODE, 0))
|
||||
return errno;
|
||||
} else {
|
||||
if (hold_unlock(resource))
|
||||
return errno;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check if a VG is un use by LVM1 so we don't stomp on it */
|
||||
int do_check_lvm1(char *vgname)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = check_lvm1_vg_inactive(cmd, vgname);
|
||||
|
||||
return status == 1 ? 0 : EBUSY;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 void *get_initial_state()
|
||||
{
|
||||
char lv[64], vg[64], flags[25];
|
||||
char uuid[65];
|
||||
char line[255];
|
||||
FILE *lvs =
|
||||
popen
|
||||
("/sbin/lvm lvs --nolocking --noheadings -o vg_uuid,lv_uuid,lv_attr",
|
||||
"r");
|
||||
|
||||
if (!lvs)
|
||||
return NULL;
|
||||
|
||||
while (fgets(line, sizeof(line), lvs)) {
|
||||
if (sscanf(line, "%s %s %s\n", vg, lv, flags) == 3) {
|
||||
/* States: s:suspended a:active S:dropped snapshot I:invalid snapshot */
|
||||
if (flags[4] == 'a' || flags[4] == 's') { /* is it active or suspended? */
|
||||
/* 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';
|
||||
|
||||
DEBUGLOG("getting initial lock for %s\n", uuid);
|
||||
hold_lock(uuid, LKM_CRMODE, LKF_NOQUEUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(lvs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void init_lvhash()
|
||||
{
|
||||
/* Create hash table for keeping LV locks & status */
|
||||
lv_hash = hash_create(100);
|
||||
}
|
||||
|
||||
/* Called to initialise the LVM context of the daemon */
|
||||
int init_lvm(void)
|
||||
{
|
||||
if (!(cmd = create_toolcontext(NULL))) {
|
||||
log_error("Failed to allocate command context");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Use LOG_DAEMON for syslog messages instead of LOG_USER */
|
||||
init_syslog(LOG_DAEMON);
|
||||
init_debug(_LOG_ERR);
|
||||
|
||||
get_initial_state();
|
||||
|
||||
return 1;
|
||||
}
|
35
daemons/clvmd/lvm-functions.h
Normal file
35
daemons/clvmd/lvm-functions.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 int post_lock_lv(unsigned char lock_cmd, unsigned char lock_flags,
|
||||
char *resource);
|
||||
extern int do_check_lvm1(char *vgname);
|
||||
extern int init_lvm(void);
|
||||
extern void init_lvhash(void);
|
||||
|
||||
extern int hold_unlock(char *resource);
|
||||
extern int hold_lock(char *resource, int mode, int flags);
|
||||
extern void unlock_all(void);
|
||||
|
||||
#endif
|
369
daemons/clvmd/system-lv.c
Normal file
369
daemons/clvmd/system-lv.c
Normal file
@@ -0,0 +1,369 @@
|
||||
/*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* Routines dealing with the System LV */
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <syslog.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <mntent.h>
|
||||
|
||||
#include "libdlm.h"
|
||||
#include "log.h"
|
||||
#include "list.h"
|
||||
#include "locking.h"
|
||||
#include "system-lv.h"
|
||||
#include "clvmd-comms.h"
|
||||
#ifdef HAVE_CCS
|
||||
#include "ccs.h"
|
||||
#endif
|
||||
|
||||
#define SYSTEM_LV_FILESYSTEM "ext2"
|
||||
#define SYSTEM_LV_MOUNTPOINT "/tmp/.clvmd-XXXXXX"
|
||||
|
||||
extern char *config_filename(void);
|
||||
|
||||
static char system_lv_name[PATH_MAX] = { '\0' };
|
||||
static char mount_point[PATH_MAX] = { '\0' };
|
||||
static int mounted = 0;
|
||||
static int mounted_rw = 0;
|
||||
static int lockid;
|
||||
static const char *lock_name = "CLVM_SYSTEM_LV";
|
||||
|
||||
/* Look in /proc/mounts or (as a last resort) /etc/mtab to
|
||||
see if the system-lv is mounted. If it is mounted and we
|
||||
think it's not then abort because we don't have the right
|
||||
lock status and we don't know what other processes are doing with it.
|
||||
|
||||
Returns 1 for mounted, 0 for not mounted so it matches the condition
|
||||
of the "mounted" static variable above.
|
||||
*/
|
||||
static int is_really_mounted(void)
|
||||
{
|
||||
FILE *mountfile;
|
||||
struct mntent *ment;
|
||||
|
||||
mountfile = setmntent("/proc/mounts", "r");
|
||||
if (!mountfile) {
|
||||
mountfile = setmntent("/etc/mtab", "r");
|
||||
if (!mountfile) {
|
||||
log_error("Unable to open /proc/mounts or /etc/mtab");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Look for system LV name in the file */
|
||||
do {
|
||||
ment = getmntent(mountfile);
|
||||
if (ment) {
|
||||
if (strcmp(ment->mnt_fsname, system_lv_name) == 0) {
|
||||
endmntent(mountfile);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (ment);
|
||||
|
||||
endmntent(mountfile);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get the system LV name from the config file */
|
||||
static int find_system_lv(void)
|
||||
{
|
||||
if (system_lv_name[0] == '\0') {
|
||||
#ifdef HAVE_CCS
|
||||
int error;
|
||||
ccs_node_t *ctree;
|
||||
|
||||
/* Read the cluster config file */
|
||||
/* Open the config file */
|
||||
error = open_ccs_file(&ctree, "clvm.ccs");
|
||||
if (error) {
|
||||
perror("reading config file");
|
||||
return -1;
|
||||
}
|
||||
|
||||
strcpy(system_lv_name, find_ccs_str(ctree,
|
||||
"cluster/systemlv", '/',
|
||||
"/dev/vg/system_lv"));
|
||||
|
||||
/* Finished with config file */
|
||||
close_ccs_file(ctree);
|
||||
#else
|
||||
if (getenv("CLVMD_SYSTEM_LV"))
|
||||
strcpy(system_lv_name, getenv("CLVMD_SYSTEM_LV"));
|
||||
else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* See if it has been mounted outside our control */
|
||||
if (is_really_mounted() != mounted) {
|
||||
log_error
|
||||
("The system LV state has been mounted/umounted outside the control of clvmd\n"
|
||||
"it cannot not be used for cluster communications until this is fixed.\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* No prizes */
|
||||
int system_lv_umount(void)
|
||||
{
|
||||
if (!mounted)
|
||||
return 0;
|
||||
|
||||
if (umount(mount_point) < 0) {
|
||||
log_error("umount of system LV (%s) failed: %m\n",
|
||||
system_lv_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sync_unlock(lock_name, lockid);
|
||||
mounted = 0;
|
||||
|
||||
/* Remove the mount point */
|
||||
rmdir(mount_point);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int system_lv_mount(int readwrite)
|
||||
{
|
||||
int status;
|
||||
int saved_errno;
|
||||
int fd;
|
||||
|
||||
if (find_system_lv()) {
|
||||
errno = EBUSY;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Is it already mounted suitably? */
|
||||
if (mounted) {
|
||||
if (!readwrite || (readwrite && mounted_rw)) {
|
||||
return 0;
|
||||
} else {
|
||||
/* Mounted RO and we need RW */
|
||||
if (system_lv_umount() < 0)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Randomize the mount point */
|
||||
strcpy(mount_point, SYSTEM_LV_MOUNTPOINT);
|
||||
fd = mkstemp(mount_point);
|
||||
if (fd < 0) {
|
||||
log_error("mkstemp for system LV mount point failed: %m\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Race condition here but there's no mkstemp for directories */
|
||||
close(fd);
|
||||
unlink(mount_point);
|
||||
mkdir(mount_point, 0600);
|
||||
|
||||
/* Make sure we have a system-lv lock */
|
||||
status =
|
||||
sync_lock(lock_name, (readwrite) ? LKM_EXMODE : LKM_CRMODE, 0,
|
||||
&lockid);
|
||||
if (status < 0)
|
||||
return -1;
|
||||
|
||||
/* Mount it */
|
||||
if (mount(system_lv_name, mount_point, SYSTEM_LV_FILESYSTEM,
|
||||
MS_MGC_VAL | MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_SYNCHRONOUS
|
||||
| (readwrite ? 0 : MS_RDONLY), NULL) < 0) {
|
||||
/* mount(2) returns EINVAL if the volume has no FS on it. So, if we want to
|
||||
write to it we try to make a filesystem in it and retry the mount */
|
||||
if (errno == EINVAL && readwrite) {
|
||||
char cmd[256];
|
||||
|
||||
log_error("Attempting mkfs on system LV device %s\n",
|
||||
system_lv_name);
|
||||
snprintf(cmd, sizeof(cmd), "/sbin/mkfs -t %s %s",
|
||||
SYSTEM_LV_FILESYSTEM, system_lv_name);
|
||||
system(cmd);
|
||||
|
||||
if (mount
|
||||
(system_lv_name, mount_point, SYSTEM_LV_FILESYSTEM,
|
||||
MS_MGC_VAL | MS_NOSUID | MS_NODEV | MS_NOEXEC |
|
||||
MS_SYNCHRONOUS | (readwrite ? 0 : MS_RDONLY),
|
||||
NULL) == 0)
|
||||
goto mounted;
|
||||
}
|
||||
|
||||
saved_errno = errno;
|
||||
log_error("mount of system LV (%s, %s, %s) failed: %m\n",
|
||||
system_lv_name, mount_point, SYSTEM_LV_FILESYSTEM);
|
||||
sync_unlock(lock_name, lockid);
|
||||
errno = saved_errno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
mounted:
|
||||
/* Set the internal flags */
|
||||
mounted = 1;
|
||||
mounted_rw = readwrite;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Erase *all* files in the root directory of the system LV.
|
||||
This *MUST* be called with an appropriate lock held!
|
||||
The LV is left mounted RW because it is assumed that the
|
||||
caller wants to write something here after clearing some space */
|
||||
int system_lv_eraseall(void)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *ent;
|
||||
char fname[PATH_MAX];
|
||||
|
||||
/* Must be mounted R/W */
|
||||
system_lv_mount(1);
|
||||
|
||||
dir = opendir(mount_point);
|
||||
if (!dir)
|
||||
return -1;
|
||||
|
||||
while ((ent = readdir(dir))) {
|
||||
struct stat st;
|
||||
snprintf(fname, sizeof(fname), "%s/%s", mount_point,
|
||||
ent->d_name);
|
||||
|
||||
if (stat(fname, &st)) {
|
||||
if (S_ISREG(st.st_mode))
|
||||
unlink(fname);
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This is a "high-level" routine - it mounts the system LV, writes
|
||||
the data into a file named after this node and then umounts the LV
|
||||
again */
|
||||
int system_lv_write_data(char *data, ssize_t len)
|
||||
{
|
||||
struct utsname nodeinfo;
|
||||
char fname[PATH_MAX];
|
||||
int outfile;
|
||||
ssize_t thiswrite;
|
||||
ssize_t written;
|
||||
|
||||
if (system_lv_mount(1))
|
||||
return -1;
|
||||
|
||||
/* Build the file name we are goingto use. */
|
||||
uname(&nodeinfo);
|
||||
snprintf(fname, sizeof(fname), "%s/%s", mount_point, nodeinfo.nodename);
|
||||
|
||||
/* Open the file for output */
|
||||
outfile = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0600);
|
||||
if (outfile < 0) {
|
||||
int saved_errno = errno;
|
||||
system_lv_umount();
|
||||
errno = saved_errno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
written = 0;
|
||||
do {
|
||||
thiswrite = write(outfile, data + written, len - written);
|
||||
if (thiswrite > 0)
|
||||
written += thiswrite;
|
||||
|
||||
} while (written < len && thiswrite > 0);
|
||||
|
||||
close(outfile);
|
||||
|
||||
system_lv_umount();
|
||||
return (thiswrite < 0) ? -1 : 0;
|
||||
}
|
||||
|
||||
/* This is a "high-level" routine - it mounts the system LV, reads
|
||||
the data from a named file and then umounts the LV
|
||||
again */
|
||||
int system_lv_read_data(char *fname_base, char *data, ssize_t *len)
|
||||
{
|
||||
char fname[PATH_MAX];
|
||||
int outfile;
|
||||
struct stat st;
|
||||
ssize_t filesize;
|
||||
ssize_t thisread;
|
||||
ssize_t readbytes;
|
||||
|
||||
if (system_lv_mount(0))
|
||||
return -1;
|
||||
|
||||
/* Build the file name we are going to use. */
|
||||
snprintf(fname, sizeof(fname), "%s/%s", mount_point, fname_base);
|
||||
|
||||
/* Get the file size and stuff. Actually we only need the file size but
|
||||
this will also check that the file exists */
|
||||
if (stat(fname, &st) < 0) {
|
||||
int saved_errno = errno;
|
||||
|
||||
log_error("stat of file %s on system LV failed: %m\n", fname);
|
||||
system_lv_umount();
|
||||
errno = saved_errno;
|
||||
return -1;
|
||||
}
|
||||
filesize = st.st_size;
|
||||
|
||||
outfile = open(fname, O_RDONLY);
|
||||
if (outfile < 0) {
|
||||
int saved_errno = errno;
|
||||
|
||||
log_error("open of file %s on system LV failed: %m\n", fname);
|
||||
system_lv_umount();
|
||||
errno = saved_errno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
readbytes = 0;
|
||||
do {
|
||||
thisread =
|
||||
read(outfile, data + readbytes, filesize - readbytes);
|
||||
if (thisread > 0)
|
||||
readbytes += thisread;
|
||||
|
||||
} while (readbytes < filesize && thisread > 0);
|
||||
|
||||
close(outfile);
|
||||
|
||||
system_lv_umount();
|
||||
|
||||
*len = readbytes;
|
||||
return (thisread < 0) ? -1 : 0;
|
||||
}
|
30
daemons/clvmd/system-lv.h
Normal file
30
daemons/clvmd/system-lv.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _CLVM_SYSTEM_LV_H
|
||||
#define _CLVM_SYSTEM_LV_H
|
||||
|
||||
/* Prototypes for System-LV functions */
|
||||
|
||||
/* "low-level" functions */
|
||||
extern int system_lv_umount(void);
|
||||
extern int system_lv_mount(int readwrite);
|
||||
extern int system_lv_eraseall(void);
|
||||
|
||||
/* "high-level" functions */
|
||||
extern int system_lv_write_data(char *data, ssize_t len);
|
||||
extern int system_lv_read_data(char *fname_base, char *data, ssize_t *len);
|
||||
|
||||
#endif
|
480
daemons/clvmd/tcp-comms.c
Normal file
480
daemons/clvmd/tcp-comms.c
Normal file
@@ -0,0 +1,480 @@
|
||||
/******************************************************************************
|
||||
*******************************************************************************
|
||||
**
|
||||
** Copyright (C) Sistina Software, Inc. 2002-2003 All rights reserved.
|
||||
**
|
||||
*******************************************************************************
|
||||
******************************************************************************/
|
||||
|
||||
/* This provides the inter-clvmd communications for a system without CMAN.
|
||||
There is a listening TCP socket which accepts new connections in the
|
||||
normal way.
|
||||
It can also make outgoing connnections to the other clvmd nodes.
|
||||
*/
|
||||
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <syslog.h>
|
||||
#include <netdb.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "ccs.h"
|
||||
#include "clvm.h"
|
||||
#include "clvmd-comms.h"
|
||||
#include "clvmd.h"
|
||||
#include "clvmd-gulm.h"
|
||||
#include "hash.h"
|
||||
|
||||
#define DEFAULT_TCP_PORT 21064
|
||||
|
||||
static int listen_fd = -1;
|
||||
static int tcp_port;
|
||||
struct hash_table *sock_hash;
|
||||
|
||||
static int get_tcp_port(int default_port);
|
||||
static int get_our_ip_address(char *addr, int *family);
|
||||
static int read_from_tcpsock(struct local_client *fd, char *buf, int len, char *csid,
|
||||
struct local_client **new_client);
|
||||
|
||||
/* Called by init_cluster() to open up the listening socket */
|
||||
// TODO: IPv6 compat.
|
||||
int init_comms()
|
||||
{
|
||||
struct sockaddr *addr = NULL;
|
||||
struct sockaddr_in addr4;
|
||||
struct sockaddr_in6 addr6;
|
||||
int addr_len;
|
||||
int family;
|
||||
char address[MAX_CSID_LEN];
|
||||
|
||||
sock_hash = hash_create(100);
|
||||
tcp_port = get_tcp_port(DEFAULT_TCP_PORT);
|
||||
|
||||
/* Get IP address and IP type */
|
||||
get_our_ip_address(address, &family);
|
||||
if (family == AF_INET)
|
||||
{
|
||||
memcpy(&addr4.sin_addr, addr, sizeof(struct in_addr));
|
||||
addr = (struct sockaddr *)&addr4;
|
||||
addr4.sin_port = htons(tcp_port);
|
||||
addr_len = sizeof(addr4);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(&addr6.sin6_addr, addr, sizeof(struct in6_addr));
|
||||
addr = (struct sockaddr *)&addr6;
|
||||
addr6.sin6_port = htons(tcp_port);
|
||||
addr_len = sizeof(addr6);
|
||||
}
|
||||
|
||||
listen_fd = socket(family, SOCK_STREAM, 0);
|
||||
|
||||
if (listen_fd < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
int one = 1;
|
||||
setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int));
|
||||
}
|
||||
|
||||
addr->sa_family = family;
|
||||
|
||||
if (bind(listen_fd, addr, addr_len) < 0)
|
||||
{
|
||||
DEBUGLOG("Can't bind to port\n");
|
||||
syslog(LOG_ERR, "Can't bind to port %d, is clvmd already running ?", tcp_port);
|
||||
close(listen_fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
listen(listen_fd, 5);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tcp_remove_client(char *csid)
|
||||
{
|
||||
struct local_client *client;
|
||||
DEBUGLOG("tcp_remove_client\n");
|
||||
|
||||
/* Don't actually close the socket here - that's the
|
||||
job of clvmd.c whch will do the job when it notices the
|
||||
other end has gone. We just need to remove the client(s) from
|
||||
the hash table so we don't try to use it for sending any more */
|
||||
client = hash_lookup_binary(sock_hash, csid, MAX_CSID_LEN);
|
||||
if (client)
|
||||
{
|
||||
hash_remove_binary(sock_hash, csid, MAX_CSID_LEN);
|
||||
}
|
||||
|
||||
/* Look for a mangled one too */
|
||||
csid[0] ^= 0x80;
|
||||
|
||||
client = hash_lookup_binary(sock_hash, csid, MAX_CSID_LEN);
|
||||
if (client)
|
||||
{
|
||||
hash_remove_binary(sock_hash, csid, MAX_CSID_LEN);
|
||||
}
|
||||
|
||||
/* Put it back as we found it */
|
||||
csid[0] ^= 0x80;
|
||||
}
|
||||
|
||||
int alloc_client(int fd, char *csid, struct local_client **new_client)
|
||||
{
|
||||
struct local_client *client;
|
||||
|
||||
DEBUGLOG("alloc_client %d csid = [%d.%d.%d.%d]\n", fd,csid[0],csid[1],csid[2],csid[3]);
|
||||
|
||||
/* Create a local_client and return it */
|
||||
client = malloc(sizeof(struct local_client));
|
||||
if (!client)
|
||||
{
|
||||
DEBUGLOG("malloc failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(client, 0, sizeof(struct local_client));
|
||||
client->fd = fd;
|
||||
client->type = CLUSTER_DATA_SOCK;
|
||||
client->callback = read_from_tcpsock;
|
||||
if (new_client)
|
||||
*new_client = client;
|
||||
|
||||
/* Add to our list of node sockets */
|
||||
if (hash_lookup_binary(sock_hash, csid, MAX_CSID_LEN))
|
||||
{
|
||||
DEBUGLOG("alloc_client mangling CSID for second connection\n");
|
||||
/* This is a duplicate connection but we can't close it because
|
||||
the other end may already have started sending.
|
||||
So, we mangle the IP address and keep it, all sending will
|
||||
go out of the main FD
|
||||
*/
|
||||
csid[0] ^= 0x80;
|
||||
client->bits.net.flags = 1; /* indicate mangled CSID */
|
||||
|
||||
/* If it still exists then kill the connection as we should only
|
||||
ever have one incoming connection from each node */
|
||||
if (hash_lookup_binary(sock_hash, csid, MAX_CSID_LEN))
|
||||
{
|
||||
DEBUGLOG("Multiple incoming connections from node\n");
|
||||
syslog(LOG_ERR, " Bogus incoming connection from %d.%d.%d.%d\n", csid[0],csid[1],csid[2],csid[3]);
|
||||
|
||||
free(client);
|
||||
errno = ECONNREFUSED;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
hash_insert_binary(sock_hash, csid, MAX_CSID_LEN, client);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_main_cluster_fd()
|
||||
{
|
||||
return listen_fd;
|
||||
}
|
||||
|
||||
|
||||
/* Read on main comms (listen) socket, accept it */
|
||||
int cluster_fd_callback(struct local_client *fd, char *buf, int len, char *csid,
|
||||
struct local_client **new_client)
|
||||
{
|
||||
int newfd;
|
||||
struct sockaddr_in addr;
|
||||
socklen_t addrlen = sizeof(addr);
|
||||
int status;
|
||||
char name[MAX_CLUSTER_MEMBER_NAME_LEN];
|
||||
|
||||
DEBUGLOG("cluster_fd_callback\n");
|
||||
*new_client = NULL;
|
||||
newfd = accept(listen_fd, (struct sockaddr *)&addr, &addrlen);
|
||||
|
||||
DEBUGLOG("cluster_fd_callback, newfd=%d (errno=%d)\n", newfd, errno);
|
||||
if (!newfd)
|
||||
{
|
||||
syslog(LOG_ERR, "error in accept: %m");
|
||||
errno = EAGAIN;
|
||||
return -1; /* Don't return an error or clvmd will close the listening FD */
|
||||
}
|
||||
|
||||
/* Check that the client is a member of the cluster
|
||||
and reject if not.
|
||||
// FIXME: IPv4 specific
|
||||
*/
|
||||
if (name_from_csid((char *)&addr.sin_addr.s_addr, name) < 0)
|
||||
{
|
||||
char *ip = (char *)&addr.sin_addr.s_addr;
|
||||
syslog(LOG_ERR, "Got connect from non-cluster node %d.%d.%d.%d\n",
|
||||
ip[0], ip[1], ip[2], ip[3]);
|
||||
DEBUGLOG("Got connect from non-cluster node %d.%d.%d.%d\n",
|
||||
ip[0], ip[1], ip[2], ip[3]);
|
||||
close(newfd);
|
||||
|
||||
errno = EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
status = alloc_client(newfd, (char *)&addr.sin_addr.s_addr, new_client);
|
||||
if (status)
|
||||
{
|
||||
DEBUGLOG("cluster_fd_callback, alloc_client failed, status = %d\n", status);
|
||||
close(newfd);
|
||||
/* See above... */
|
||||
errno = EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
DEBUGLOG("cluster_fd_callback, returning %d, %p\n", newfd, *new_client);
|
||||
return newfd;
|
||||
}
|
||||
|
||||
|
||||
static int read_from_tcpsock(struct local_client *client, char *buf, int len, char *csid,
|
||||
struct local_client **new_client)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
socklen_t slen = sizeof(addr);
|
||||
int status;
|
||||
|
||||
DEBUGLOG("read_from_tcpsock fd %d\n", client->fd);
|
||||
*new_client = NULL;
|
||||
|
||||
/* Get "csid" */
|
||||
getpeername(client->fd, (struct sockaddr *)&addr, &slen);
|
||||
memcpy(csid, &addr.sin_addr.s_addr, MAX_CSID_LEN);
|
||||
|
||||
status = read(client->fd, buf, len);
|
||||
|
||||
DEBUGLOG("read_from_tcpsock, status = %d(errno = %d)\n", status, errno);
|
||||
|
||||
/* Remove it from the hash table if there's an error, clvmd will
|
||||
remove the socket from its lists and free the client struct */
|
||||
if (status == 0 ||
|
||||
(status < 0 && errno != EAGAIN && errno != EINTR))
|
||||
{
|
||||
char remcsid[MAX_CSID_LEN];
|
||||
|
||||
memcpy(remcsid, csid, MAX_CSID_LEN);
|
||||
close(client->fd);
|
||||
|
||||
/* If the csid was mangled, then make sure we remove the right entry */
|
||||
if (client->bits.net.flags)
|
||||
remcsid[0] ^= 0x80;
|
||||
hash_remove_binary(sock_hash, remcsid, MAX_CSID_LEN);
|
||||
|
||||
/* Tell cluster manager layer */
|
||||
add_down_node(remcsid);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static int connect_csid(char *csid, struct local_client **newclient)
|
||||
{
|
||||
int fd;
|
||||
struct sockaddr_in addr;
|
||||
int status;
|
||||
|
||||
DEBUGLOG("Connecting socket\n");
|
||||
fd = socket(PF_INET, SOCK_STREAM, 0);
|
||||
|
||||
if (fd < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "Unable to create new socket: %m");
|
||||
return -1;
|
||||
}
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
memcpy(&addr.sin_addr.s_addr, csid, MAX_CSID_LEN);
|
||||
addr.sin_port = htons(tcp_port);
|
||||
|
||||
DEBUGLOG("Connecting socket %d\n", fd);
|
||||
if (connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "Unable to connect to remote node: %m");
|
||||
DEBUGLOG("Unable to connect to remote node: %s\n", strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
status = alloc_client(fd, csid, newclient);
|
||||
if (status)
|
||||
close(fd);
|
||||
else
|
||||
add_client(*newclient);
|
||||
|
||||
/* If we can connect to it, it must be running a clvmd */
|
||||
add_up_node(csid);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Send a message to a known CSID */
|
||||
static int tcp_send_message(void *buf, int msglen, unsigned char *csid, const char *errtext)
|
||||
{
|
||||
int status;
|
||||
struct local_client *client;
|
||||
char ourcsid[MAX_CSID_LEN];
|
||||
|
||||
assert(csid);
|
||||
|
||||
DEBUGLOG("tcp_send_message, csid = [%d.%d.%d.%d], msglen = %d\n", csid[0],csid[1],csid[2],csid[3], msglen);
|
||||
|
||||
/* Don't connect to ourself */
|
||||
get_our_csid(ourcsid);
|
||||
if (memcmp(csid, ourcsid, MAX_CSID_LEN) == 0)
|
||||
return msglen;
|
||||
|
||||
client = hash_lookup_binary(sock_hash, csid, MAX_CSID_LEN);
|
||||
if (!client)
|
||||
{
|
||||
status = connect_csid(csid, &client);
|
||||
if (status)
|
||||
return -1;
|
||||
}
|
||||
DEBUGLOG("tcp_send_message, fd = %d\n", client->fd);
|
||||
|
||||
return write(client->fd, buf, msglen);
|
||||
}
|
||||
|
||||
|
||||
int cluster_send_message(void *buf, int msglen, char *csid, const char *errtext)
|
||||
{
|
||||
int status=0;
|
||||
|
||||
DEBUGLOG("cluster send message, csid = %p, msglen = %d\n", csid, msglen);
|
||||
|
||||
/* If csid is NULL then send to all known (not just connected) nodes */
|
||||
if (!csid)
|
||||
{
|
||||
void *context = NULL;
|
||||
char loop_csid[MAX_CSID_LEN];
|
||||
|
||||
/* Loop round all gulm-known nodes */
|
||||
while (get_next_node_csid(&context, loop_csid))
|
||||
{
|
||||
status = tcp_send_message(buf, msglen, loop_csid, errtext);
|
||||
if (status == 0 ||
|
||||
(status < 0 && (errno == EAGAIN || errno == EINTR)))
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
status = tcp_send_message(buf, msglen, csid, errtext);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static int get_tcp_port(int default_port)
|
||||
{
|
||||
int ccs_handle;
|
||||
int port = default_port;
|
||||
char *portstr;
|
||||
|
||||
ccs_handle = ccs_connect();
|
||||
if (ccs_handle)
|
||||
{
|
||||
return port;
|
||||
}
|
||||
|
||||
if (!ccs_get(ccs_handle, "//clvm/@port", &portstr))
|
||||
{
|
||||
port = atoi(portstr);
|
||||
free(portstr);
|
||||
|
||||
if (port <= 0 && port >= 65536)
|
||||
port = default_port;
|
||||
}
|
||||
ccs_disconnect(ccs_handle);
|
||||
|
||||
DEBUGLOG("Using port %d for communications\n", port);
|
||||
return port;
|
||||
}
|
||||
|
||||
/* To get our own IP address we get the locally bound address of the
|
||||
socket that's talking to GULM in the assumption(eek) that it will
|
||||
be on the "right" network in a multi-homed system */
|
||||
static int get_our_ip_address(char *addr, int *family)
|
||||
{
|
||||
/* Use a sockaddr_in6 to make sure it's big enough */
|
||||
struct sockaddr_in6 saddr;
|
||||
int socklen = sizeof(saddr);
|
||||
|
||||
if (!getsockname(gulm_fd(), (struct sockaddr *)&saddr, &socklen))
|
||||
{
|
||||
if (saddr.sin6_family == AF_INET6)
|
||||
{
|
||||
memcpy(addr, &saddr.sin6_addr, sizeof(saddr.sin6_addr));
|
||||
}
|
||||
else
|
||||
{
|
||||
struct sockaddr_in *sin4 = (struct sockaddr_in *)&saddr;
|
||||
memcpy(addr, &sin4->sin_addr, sizeof(sin4->sin_addr));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Public version of above for those that don't care what protocol
|
||||
we're using */
|
||||
void get_our_csid(char *csid)
|
||||
{
|
||||
static char our_csid[MAX_CSID_LEN];
|
||||
static int got_csid = 0;
|
||||
|
||||
if (!got_csid)
|
||||
{
|
||||
int family;
|
||||
|
||||
memset(our_csid, 0, sizeof(our_csid));
|
||||
if (get_our_ip_address(our_csid, &family))
|
||||
{
|
||||
got_csid = 1;
|
||||
}
|
||||
}
|
||||
memcpy(csid, our_csid, MAX_CSID_LEN);
|
||||
}
|
||||
|
||||
/* Get someone else's IP address from DNS */
|
||||
int get_ip_address(char *node, char *addr)
|
||||
{
|
||||
struct hostent *he;
|
||||
|
||||
memset(addr, 0, MAX_CSID_LEN);
|
||||
|
||||
// TODO: what do we do about multi-homed hosts ???
|
||||
// CCSs ip_interfaces solved this but some bugger removed it.
|
||||
|
||||
/* Try IPv6 first. The man page for gethostbyname implies that
|
||||
it will lookup ip6 & ip4 names, but it seems not to */
|
||||
he = gethostbyname2(node, AF_INET6);
|
||||
if (!he)
|
||||
he = gethostbyname2(node, AF_INET);
|
||||
if (!he)
|
||||
return -1;
|
||||
|
||||
/* For IPv4 address just use the lower 4 bytes */
|
||||
memcpy(&addr, he->h_addr_list[0],
|
||||
he->h_length);
|
||||
|
||||
return 0;
|
||||
}
|
7
daemons/clvmd/tcp-comms.h
Normal file
7
daemons/clvmd/tcp-comms.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#include <netinet/in.h>
|
||||
|
||||
#define MAX_CLUSTER_MESSAGE 1600
|
||||
#define MAX_CSID_LEN sizeof(struct in6_addr)
|
||||
#define MAX_CLUSTER_MEMBER_NAME_LEN 128
|
||||
|
||||
extern int init_comms(void);
|
@@ -1,3 +1,4 @@
|
||||
../daemons/clvmd/clvm.h
|
||||
../lib/activate/activate.h
|
||||
../lib/activate/targets.h
|
||||
../lib/cache/lvmcache.h
|
||||
@@ -30,7 +31,7 @@
|
||||
../lib/log/log.h
|
||||
../lib/metadata/lv_alloc.h
|
||||
../lib/metadata/metadata.h
|
||||
../lib/metadata/segtypes.h
|
||||
../lib/metadata/segtype.h
|
||||
../lib/mm/dbg_malloc.h
|
||||
../lib/mm/memlock.h
|
||||
../lib/mm/pool.h
|
||||
|
@@ -20,6 +20,8 @@ VPATH = @srcdir@
|
||||
|
||||
LN_S = @LN_S@
|
||||
|
||||
.PHONY: clean distclean all install pofile install_cluster
|
||||
|
||||
all: .symlinks_created
|
||||
|
||||
.symlinks_created: .symlinks
|
||||
@@ -37,5 +39,5 @@ clean:
|
||||
|
||||
install:
|
||||
|
||||
.PHONY: clean distclean all install pofile
|
||||
install_cluster:
|
||||
|
||||
|
@@ -70,7 +70,7 @@ SOURCES =\
|
||||
metadata/metadata.c \
|
||||
metadata/mirror.c \
|
||||
metadata/pv_map.c \
|
||||
metadata/segtypes.c \
|
||||
metadata/segtype.c \
|
||||
metadata/snapshot_manip.c \
|
||||
misc/crc.c \
|
||||
misc/lvm-file.c \
|
||||
@@ -104,6 +104,14 @@ ifeq ("@POOL@", "internal")
|
||||
format_pool/pool_label.c
|
||||
endif
|
||||
|
||||
ifeq ("@CLUSTER@", "internal")
|
||||
SOURCES += locking/cluster_locking.c
|
||||
endif
|
||||
|
||||
ifeq ("@CLUSTER@", "shared")
|
||||
SUBDIRS += locking
|
||||
endif
|
||||
|
||||
ifeq ("@SNAPSHOTS@", "internal")
|
||||
SOURCES += snapshot/snapshot.c
|
||||
endif
|
||||
|
@@ -21,7 +21,7 @@
|
||||
#include "lvm-string.h"
|
||||
#include "fs.h"
|
||||
#include "defaults.h"
|
||||
#include "segtypes.h"
|
||||
#include "segtype.h"
|
||||
#include "display.h"
|
||||
#include "toolcontext.h"
|
||||
#include "targets.h"
|
||||
@@ -165,89 +165,6 @@ static inline void _clear_flag(struct dev_layer *dl, int bit)
|
||||
dl->flags &= ~(1 << bit);
|
||||
}
|
||||
|
||||
/*
|
||||
* Device layer names are all of the form <vg>-<lv>-<layer>, any
|
||||
* other hyphens that appear in these names are quoted with yet
|
||||
* another hyphen. The top layer of any device has no layer
|
||||
* name. eg, vg0-lvol0.
|
||||
*/
|
||||
static void _count_hyphens(const char *str, size_t *len, int *hyphens)
|
||||
{
|
||||
const char *ptr;
|
||||
|
||||
for (ptr = str; *ptr; ptr++, (*len)++)
|
||||
if (*ptr == '-')
|
||||
(*hyphens)++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copies a string, quoting hyphens with hyphens.
|
||||
*/
|
||||
static void _quote_hyphens(char **out, const char *src)
|
||||
{
|
||||
while (*src) {
|
||||
if (*src == '-')
|
||||
*(*out)++ = '-';
|
||||
|
||||
*(*out)++ = *src++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* <vg>-<lv>-<layer> or if !layer just <vg>-<lv>.
|
||||
*/
|
||||
static char *_build_name(struct pool *mem, const char *vg,
|
||||
const char *lv, const char *layer)
|
||||
{
|
||||
size_t len = 0;
|
||||
int hyphens = 0;
|
||||
char *r, *out;
|
||||
|
||||
_count_hyphens(vg, &len, &hyphens);
|
||||
_count_hyphens(lv, &len, &hyphens);
|
||||
|
||||
if (layer && *layer)
|
||||
_count_hyphens(layer, &len, &hyphens);
|
||||
|
||||
len += hyphens + 2;
|
||||
|
||||
if (!(r = pool_alloc(mem, len))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
out = r;
|
||||
_quote_hyphens(&out, vg);
|
||||
*out++ = '-';
|
||||
_quote_hyphens(&out, lv);
|
||||
|
||||
if (layer && *layer) {
|
||||
*out++ = '-';
|
||||
_quote_hyphens(&out, layer);
|
||||
}
|
||||
*out = '\0';
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Find start of LV component in hyphenated name */
|
||||
static char *_find_lv_name(char *vg)
|
||||
{
|
||||
char *c = vg;
|
||||
|
||||
while (*c && *(c + 1)) {
|
||||
if (*c == '-') {
|
||||
if (*(c + 1) == '-')
|
||||
c++;
|
||||
else
|
||||
return (c + 1);
|
||||
}
|
||||
c++;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *_build_dlid(struct pool *mem, const char *lvid, const char *layer)
|
||||
{
|
||||
char *dlid;
|
||||
@@ -519,10 +436,16 @@ static int _percent(struct dev_manager *dm, const char *name, const char *uuid,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _rename(struct dev_layer *dl, char *newname)
|
||||
static int _rename(struct dev_manager *dm, struct dev_layer *dl, char *newname)
|
||||
{
|
||||
int r = 1;
|
||||
struct dm_task *dmt;
|
||||
char *vgname, *lvname, *layer;
|
||||
|
||||
if (!split_dm_name(dm->mem, dl->name, &vgname, &lvname, &layer)) {
|
||||
log_error("Couldn't split up dm layer name %s", dl->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_verbose("Renaming %s to %s", dl->name, newname);
|
||||
|
||||
@@ -537,11 +460,13 @@ static int _rename(struct dev_layer *dl, char *newname)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(r = dm_task_run(dmt)))
|
||||
if (!(r = dm_task_run(dmt))) {
|
||||
log_error("Couldn't rename device '%s'.", dl->name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (r && _get_flag(dl, VISIBLE))
|
||||
fs_rename_lv(dl->lv, newname, _find_lv_name(dl->name));
|
||||
fs_rename_lv(dl->lv, newname, lvname);
|
||||
|
||||
dl->name = newname;
|
||||
|
||||
@@ -1052,7 +977,7 @@ int dev_manager_info(struct dev_manager *dm, const struct logical_volume *lv,
|
||||
/*
|
||||
* Build a name for the top layer.
|
||||
*/
|
||||
if (!(name = _build_name(dm->mem, lv->vg->name, lv->name, NULL))) {
|
||||
if (!(name = build_dm_name(dm->mem, lv->vg->name, lv->name, NULL))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -1077,7 +1002,7 @@ int dev_manager_snapshot_percent(struct dev_manager *dm,
|
||||
/*
|
||||
* Build a name for the top layer.
|
||||
*/
|
||||
if (!(name = _build_name(dm->mem, lv->vg->name, lv->name, NULL))) {
|
||||
if (!(name = build_dm_name(dm->mem, lv->vg->name, lv->name, NULL))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -1109,7 +1034,7 @@ int dev_manager_mirror_percent(struct dev_manager *dm,
|
||||
/*
|
||||
* Build a name for the top layer.
|
||||
*/
|
||||
if (!(name = _build_name(dm->mem, lv->vg->name, lv->name, NULL))) {
|
||||
if (!(name = build_dm_name(dm->mem, lv->vg->name, lv->name, NULL))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -1173,7 +1098,7 @@ static struct dev_layer *_create_layer(struct dev_manager *dm,
|
||||
char *name, *dlid;
|
||||
struct dev_layer *dl;
|
||||
|
||||
if (!(name = _build_name(dm->mem, lv->vg->name, lv->name, layer))) {
|
||||
if (!(name = build_dm_name(dm->mem, lv->vg->name, lv->name, layer))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
@@ -1618,11 +1543,11 @@ static int _create_rec(struct dev_manager *dm, struct dev_layer *dl)
|
||||
if (dl->info.exists) {
|
||||
if ((suffix = rindex(dl->dlid, '-')))
|
||||
suffix++;
|
||||
newname = _build_name(dm->mem, dm->vg_name, dl->lv->name,
|
||||
suffix);
|
||||
newname = build_dm_name(dm->mem, dm->vg_name, dl->lv->name,
|
||||
suffix);
|
||||
if (strcmp(newname, dl->name)) {
|
||||
if (!_suspend_parents(dm, dl) ||
|
||||
!_suspend(dl) || !_rename(dl, newname)) {
|
||||
!_suspend(dl) || !_rename(dm, dl, newname)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -2227,8 +2152,8 @@ int dev_manager_lv_mknodes(const struct logical_volume *lv)
|
||||
{
|
||||
char *name;
|
||||
|
||||
if (!(name = _build_name(lv->vg->cmd->mem, lv->vg->name,
|
||||
lv->name, NULL))) {
|
||||
if (!(name = build_dm_name(lv->vg->cmd->mem, lv->vg->name,
|
||||
lv->name, NULL))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
@@ -46,7 +46,7 @@ static int _mk_dir(const char *dev_dir, const char *vg_name)
|
||||
return 1;
|
||||
|
||||
log_very_verbose("Creating directory %s", vg_path);
|
||||
if (mkdir(vg_path, 0555)) {
|
||||
if (mkdir(vg_path, 0777)) {
|
||||
log_sys_error("mkdir", vg_path);
|
||||
return 0;
|
||||
}
|
||||
|
@@ -33,7 +33,7 @@
|
||||
#include "display.h"
|
||||
#include "memlock.h"
|
||||
#include "str_list.h"
|
||||
#include "segtypes.h"
|
||||
#include "segtype.h"
|
||||
#include "lvmcache.h"
|
||||
|
||||
#ifdef HAVE_LIBDL
|
||||
@@ -798,7 +798,7 @@ struct cmd_context *create_toolcontext(struct arg *the_args)
|
||||
#endif
|
||||
|
||||
if (!setlocale(LC_ALL, ""))
|
||||
log_error("setlocale failed");
|
||||
log_very_verbose("setlocale failed");
|
||||
|
||||
#ifdef INTL_PACKAGE
|
||||
bindtextdomain(INTL_PACKAGE, LOCALEDIR);
|
||||
|
@@ -96,9 +96,9 @@
|
||||
#define DEFAULT_PVS_COLS "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free"
|
||||
#define DEFAULT_SEGS_COLS "lv_name,vg_name,lv_attr,stripes,segtype,seg_size"
|
||||
|
||||
#define DEFAULT_LVS_COLS_VERB "lv_name,vg_name,seg_count,lv_attr,lv_size,lv_major,lv_minor,origin,snap_percent,move_pv,copy_percent,lv_uuid"
|
||||
#define DEFAULT_LVS_COLS_VERB "lv_name,vg_name,seg_count,lv_attr,lv_size,lv_major,lv_minor,lv_kernel_major,lv_kernel_minor,origin,snap_percent,move_pv,copy_percent,lv_uuid"
|
||||
#define DEFAULT_VGS_COLS_VERB "vg_name,vg_attr,vg_extent_size,pv_count,lv_count,snap_count,vg_size,vg_free,vg_uuid"
|
||||
#define DEFAULT_PVS_COLS_VERB "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pv_uuid"
|
||||
#define DEFAULT_PVS_COLS_VERB "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,dev_size,pv_uuid"
|
||||
#define DEFAULT_SEGS_COLS_VERB "lv_name,vg_name,lv_attr,seg_start,seg_size,stripes,segtype,stripesize,chunksize"
|
||||
|
||||
#define DEFAULT_LVS_SORT "vg_name,lv_name"
|
||||
|
@@ -212,7 +212,7 @@ static int _aligned_io(struct device_area *where, void *buffer,
|
||||
* Public functions
|
||||
*---------------------------------------------------------------*/
|
||||
|
||||
int dev_get_size(struct device *dev, uint64_t *size)
|
||||
int dev_get_size(const struct device *dev, uint64_t *size)
|
||||
{
|
||||
int fd;
|
||||
const char *name = dev_name(dev);
|
||||
@@ -300,6 +300,12 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet)
|
||||
flags |= O_DIRECT;
|
||||
#endif
|
||||
|
||||
#ifdef O_NOATIME
|
||||
/* Don't update atime on device inodes */
|
||||
if (!(dev->flags & DEV_REGULAR))
|
||||
flags |= O_NOATIME;
|
||||
#endif
|
||||
|
||||
if ((dev->fd = open(name, flags, 0777)) < 0) {
|
||||
log_sys_error("open", name);
|
||||
return 0;
|
||||
|
@@ -55,7 +55,7 @@ struct device_area {
|
||||
/*
|
||||
* All io should use these routines.
|
||||
*/
|
||||
int dev_get_size(struct device *dev, uint64_t *size);
|
||||
int dev_get_size(const struct device *dev, uint64_t *size);
|
||||
int dev_get_sectsize(struct device *dev, uint32_t *size);
|
||||
|
||||
/* Use quiet version if device number could change e.g. when opening LV */
|
||||
|
@@ -18,7 +18,7 @@
|
||||
#include "display.h"
|
||||
#include "activate.h"
|
||||
#include "toolcontext.h"
|
||||
#include "segtypes.h"
|
||||
#include "segtype.h"
|
||||
|
||||
#define SIZE_BUF 128
|
||||
|
||||
@@ -662,3 +662,22 @@ void vgdisplay_short(struct volume_group *vg)
|
||||
SIZE_SHORT));
|
||||
return;
|
||||
}
|
||||
|
||||
void display_formats(struct cmd_context *cmd)
|
||||
{
|
||||
struct format_type *fmt;
|
||||
|
||||
list_iterate_items(fmt, &cmd->formats) {
|
||||
log_print("%s", fmt->name);
|
||||
}
|
||||
}
|
||||
|
||||
void display_segtypes(struct cmd_context *cmd)
|
||||
{
|
||||
struct segment_type *segtype;
|
||||
|
||||
list_iterate_items(segtype, &cmd->segtypes) {
|
||||
log_print("%s", segtype->name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -45,6 +45,9 @@ void vgdisplay_full(struct volume_group *vg);
|
||||
void vgdisplay_colons(struct volume_group *vg);
|
||||
void vgdisplay_short(struct volume_group *vg);
|
||||
|
||||
void display_formats(struct cmd_context *cmd);
|
||||
void display_segtypes(struct cmd_context *cmd);
|
||||
|
||||
/*
|
||||
* Allocation policy display conversion routines.
|
||||
*/
|
||||
|
@@ -16,7 +16,7 @@
|
||||
#include "pool.h"
|
||||
#include "list.h"
|
||||
#include "toolcontext.h"
|
||||
#include "segtypes.h"
|
||||
#include "segtype.h"
|
||||
#include "display.h"
|
||||
#include "text_export.h"
|
||||
#include "text_import.h"
|
||||
@@ -97,5 +97,7 @@ struct segment_type *init_error_segtype(struct cmd_context *cmd)
|
||||
segtype->private = NULL;
|
||||
segtype->flags = SEG_CAN_SPLIT | SEG_VIRTUAL;
|
||||
|
||||
log_very_verbose("Initialised segtype: %s", segtype->name);
|
||||
|
||||
return segtype;
|
||||
}
|
||||
|
@@ -169,6 +169,8 @@ static int _read_devs(struct dev_set *ds, const char *dir)
|
||||
{
|
||||
struct dirent *d;
|
||||
DIR *dr;
|
||||
unsigned char dtype;
|
||||
struct stat info;
|
||||
char path[PATH_MAX];
|
||||
dev_t dev;
|
||||
int r = 1;
|
||||
@@ -189,19 +191,29 @@ static int _read_devs(struct dev_set *ds, const char *dir)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (d->d_type == DT_DIR) {
|
||||
dtype = d->d_type;
|
||||
|
||||
if (dtype == DT_UNKNOWN) {
|
||||
if (stat(path, &info) >= 0) {
|
||||
if (S_ISDIR(info.st_mode))
|
||||
dtype = DT_DIR;
|
||||
else if (S_ISREG(info.st_mode))
|
||||
dtype = DT_REG;
|
||||
}
|
||||
}
|
||||
|
||||
if (dtype == DT_DIR) {
|
||||
if (!_read_devs(ds, path)) {
|
||||
r = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((d->d_type == DT_REG && !strcmp(d->d_name, "dev")))
|
||||
if ((dtype == DT_REG && !strcmp(d->d_name, "dev")))
|
||||
if (!_read_dev(path, &dev) || !_set_insert(ds, dev)) {
|
||||
r = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (closedir(dr))
|
||||
|
@@ -25,7 +25,7 @@
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
|
||||
#define NUMBER_OF_MAJORS 256
|
||||
#define NUMBER_OF_MAJORS 4096
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
@@ -55,6 +55,7 @@ static const device_info_t device_info[] = {
|
||||
{"drbd", 16}, /* Distributed Replicated Block Device */
|
||||
{"power2", 16}, /* EMC Powerpath */
|
||||
{"i2o_block", 16}, /* i2o Block Disk */
|
||||
{"iseries/vd", 8}, /* iSeries disks */
|
||||
{NULL, 0}
|
||||
};
|
||||
|
||||
@@ -96,6 +97,7 @@ static int *_scan_proc_dev(const char *proc, const struct config_node *cn)
|
||||
int *max_partitions_by_major;
|
||||
char *name;
|
||||
|
||||
/* FIXME Make this sparse */
|
||||
if (!(max_partitions_by_major =
|
||||
dbg_malloc(sizeof(int) * NUMBER_OF_MAJORS))) {
|
||||
log_error("Filter failed to allocate max_partitions_by_major");
|
||||
|
@@ -21,7 +21,9 @@
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifdef linux
|
||||
# include <linux/kdev_t.h>
|
||||
# define MAJOR(dev) ((dev & 0xfff00) >> 8)
|
||||
# define MINOR(dev) ((dev & 0xff) | ((dev >> 12) & 0xfff00))
|
||||
# define MKDEV(ma,mi) ((mi & 0xff) | (ma << 8) | ((mi & ~0xff) << 12))
|
||||
#else
|
||||
# define MAJOR(x) major((x))
|
||||
# define MINOR(x) minor((x))
|
||||
|
@@ -29,8 +29,6 @@ LIB_SHARED = liblvm2format1.so
|
||||
|
||||
include $(top_srcdir)/make.tmpl
|
||||
|
||||
.PHONY: install
|
||||
|
||||
install: liblvm2format1.so
|
||||
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \
|
||||
$(libdir)/liblvm2format1.so.$(LIB_VERSION)
|
||||
|
@@ -24,6 +24,7 @@
|
||||
#include "lvmcache.h"
|
||||
#include "lvm1-label.h"
|
||||
#include "format1.h"
|
||||
#include "segtype.h"
|
||||
|
||||
#define FMT_LVM1_NAME "lvm1"
|
||||
|
||||
@@ -492,6 +493,17 @@ static int _vg_setup(struct format_instance *fid, struct volume_group *vg)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _segtype_supported (struct format_instance *fid,
|
||||
struct segment_type *segtype)
|
||||
{
|
||||
if (!(segtype->flags & SEG_FORMAT1_SUPPORT)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct metadata_area_ops _metadata_format1_ops = {
|
||||
vg_read:_vg_read,
|
||||
vg_write:_vg_write,
|
||||
@@ -542,6 +554,7 @@ static struct format_handler _format1_ops = {
|
||||
pv_write:_pv_write,
|
||||
lv_setup:_lv_setup,
|
||||
vg_setup:_vg_setup,
|
||||
segtype_supported:_segtype_supported,
|
||||
create_instance:_create_instance,
|
||||
destroy_instance:_destroy_instance,
|
||||
destroy:_destroy,
|
||||
@@ -578,5 +591,7 @@ struct format_type *init_format(struct cmd_context *cmd)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
log_very_verbose("Initialised format: %s", fmt->name);
|
||||
|
||||
return fmt;
|
||||
}
|
||||
|
@@ -25,7 +25,7 @@
|
||||
#include "lvm-string.h"
|
||||
#include "filter.h"
|
||||
#include "toolcontext.h"
|
||||
#include "segtypes.h"
|
||||
#include "segtype.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
|
@@ -20,7 +20,7 @@
|
||||
#include "disk-rep.h"
|
||||
#include "lv_alloc.h"
|
||||
#include "display.h"
|
||||
#include "segtypes.h"
|
||||
#include "segtype.h"
|
||||
|
||||
/*
|
||||
* After much thought I have decided it is easier,
|
||||
|
@@ -26,8 +26,6 @@ LIB_SHARED = liblvm2formatpool.so
|
||||
|
||||
include $(top_srcdir)/make.tmpl
|
||||
|
||||
.PHONY: install
|
||||
|
||||
install: liblvm2formatpool.so
|
||||
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \
|
||||
$(libdir)/liblvm2formatpool.so.$(LIB_VERSION)
|
||||
|
@@ -357,5 +357,7 @@ struct format_type *init_format(struct cmd_context *cmd)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
log_very_verbose("Initialised format: %s", fmt->name);
|
||||
|
||||
return fmt;
|
||||
}
|
||||
|
@@ -22,7 +22,7 @@
|
||||
#include "lv_alloc.h"
|
||||
#include "str_list.h"
|
||||
#include "display.h"
|
||||
#include "segtypes.h"
|
||||
#include "segtype.h"
|
||||
|
||||
/* This file contains only imports at the moment... */
|
||||
|
||||
@@ -146,7 +146,7 @@ int import_pool_pvs(const struct format_type *fmt, struct volume_group *vg,
|
||||
}
|
||||
pl->pv = pvl->pv;
|
||||
pvl->mdas = NULL;
|
||||
pvl->alloc_areas = NULL;
|
||||
pvl->pe_ranges = NULL;
|
||||
list_add(pvs, &pvl->list);
|
||||
}
|
||||
|
||||
|
@@ -20,7 +20,7 @@
|
||||
#include "pool.h"
|
||||
#include "display.h"
|
||||
#include "lvm-string.h"
|
||||
#include "segtypes.h"
|
||||
#include "segtype.h"
|
||||
#include "text_export.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
@@ -1682,14 +1682,15 @@ struct format_type *create_text_format(struct cmd_context *cmd)
|
||||
}
|
||||
}
|
||||
|
||||
if (!(cn = find_config_node(cmd->cft->root, "metadata/disk_areas")))
|
||||
return fmt;
|
||||
|
||||
for (cn = cn->child; cn; cn = cn->sib) {
|
||||
if (!_get_config_disk_area(cmd, cn, &mda_lists->raws))
|
||||
goto err;
|
||||
if ((cn = find_config_node(cmd->cft->root, "metadata/disk_areas"))) {
|
||||
for (cn = cn->child; cn; cn = cn->sib) {
|
||||
if (!_get_config_disk_area(cmd, cn, &mda_lists->raws))
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
log_very_verbose("Initialised format: %s", fmt->name);
|
||||
|
||||
return fmt;
|
||||
|
||||
err:
|
||||
|
@@ -22,7 +22,7 @@
|
||||
#include "toolcontext.h"
|
||||
#include "lvmcache.h"
|
||||
#include "lv_alloc.h"
|
||||
#include "segtypes.h"
|
||||
#include "segtype.h"
|
||||
#include "text_import.h"
|
||||
|
||||
typedef int (*section_fn) (struct format_instance * fid, struct pool * mem,
|
||||
|
4
lib/locking/.exported_symbols
Normal file
4
lib/locking/.exported_symbols
Normal file
@@ -0,0 +1,4 @@
|
||||
locking_init
|
||||
locking_end
|
||||
lock_resource
|
||||
reset_locking
|
30
lib/locking/Makefile.in
Normal file
30
lib/locking/Makefile.in
Normal file
@@ -0,0 +1,30 @@
|
||||
#
|
||||
# Copyright (C) 2003-2004 Sistina Software, Inc. All rights reserved.
|
||||
# Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This file is part of the 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
SOURCES = cluster_locking.c
|
||||
|
||||
LIB_SHARED = liblvm2clusterlock.so
|
||||
|
||||
include $(top_srcdir)/make.tmpl
|
||||
|
||||
install install_cluster: liblvm2clusterlock.so
|
||||
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \
|
||||
$(libdir)/liblvm2clusterlock.so.$(LIB_VERSION)
|
||||
$(LN_S) -f liblvm2clusterlock.so.$(LIB_VERSION) \
|
||||
$(libdir)/liblvm2clusterlock.so
|
||||
|
462
lib/locking/cluster_locking.c
Normal file
462
lib/locking/cluster_locking.c
Normal file
@@ -0,0 +1,462 @@
|
||||
/*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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.h"
|
||||
#include "clvm.h"
|
||||
#include "lvm-string.h"
|
||||
#include "locking.h"
|
||||
#include "locking_types.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, int flags);
|
||||
void locking_end(void);
|
||||
int locking_init(int type, struct 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(void)
|
||||
{
|
||||
int local_socket;
|
||||
struct sockaddr_un sockaddr;
|
||||
|
||||
/* Open local socket */
|
||||
if ((local_socket = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
|
||||
log_error("Local socket creation failed: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&sockaddr, 0, sizeof(sockaddr));
|
||||
memcpy(sockaddr.sun_path, CLVMD_SOCKNAME, sizeof(CLVMD_SOCKNAME));
|
||||
|
||||
sockaddr.sun_family = AF_UNIX;
|
||||
|
||||
if (connect(local_socket,(struct sockaddr *) &sockaddr,
|
||||
sizeof(sockaddr))) {
|
||||
int saved_errno = errno;
|
||||
|
||||
log_error("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];
|
||||
struct clvm_header *outheader = (struct clvm_header *) outbuf;
|
||||
int len;
|
||||
int 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 = dbg_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;
|
||||
log_error("cluster send request failed: %s", 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,
|
||||
int len)
|
||||
{
|
||||
head->cmd = cmd;
|
||||
head->status = 0;
|
||||
head->flags = 0;
|
||||
head->clientid = 0;
|
||||
head->arglen = len;
|
||||
|
||||
if (node) {
|
||||
/*
|
||||
* Allow a couple of special node names:
|
||||
* "*" for all nodes,
|
||||
* "." for the local node only
|
||||
*/
|
||||
if (strcmp(node, "*") == 0) {
|
||||
head->node[0] = '\0';
|
||||
} else if (strcmp(node, ".") == 0) {
|
||||
head->node[0] = '\0';
|
||||
head->flags = CLVMD_FLAG_LOCAL;
|
||||
} else
|
||||
strcpy(head->node, node);
|
||||
} else
|
||||
head->node[0] = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
char outbuf[sizeof(struct clvm_header) + len + strlen(node) + 1];
|
||||
int *outptr;
|
||||
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);
|
||||
memcpy(head->node + strlen(head->node) + 1, data, len);
|
||||
|
||||
status = _send_request(outbuf, sizeof(struct clvm_header) +
|
||||
strlen(head->node) + len, &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
|
||||
*/
|
||||
outptr = dbg_malloc(sizeof(lvm_response_t) * num_responses +
|
||||
sizeof(int) * 2);
|
||||
if (!outptr) {
|
||||
errno = ENOMEM;
|
||||
status = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*response = (lvm_response_t *) (outptr + 2);
|
||||
outptr[0] = LVM_SIGNATURE;
|
||||
outptr[1] = num_responses;
|
||||
rarray = *response;
|
||||
|
||||
/* 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;
|
||||
|
||||
rarray[i].status = *(int *) inptr;
|
||||
inptr += sizeof(int);
|
||||
|
||||
rarray[i].response = dbg_malloc(strlen(inptr) + 1);
|
||||
if (rarray[i].response == NULL) {
|
||||
/* Free up everything else and return error */
|
||||
int j;
|
||||
for (j = 0; j < i; j++)
|
||||
dbg_free(rarray[i].response);
|
||||
free(outptr);
|
||||
errno = ENOMEM;
|
||||
status = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
strcpy(rarray[i].response, inptr);
|
||||
rarray[i].len = strlen(inptr);
|
||||
inptr += strlen(inptr) + 1;
|
||||
i++;
|
||||
}
|
||||
*num = num_responses;
|
||||
*response = rarray;
|
||||
|
||||
out:
|
||||
if (retbuf)
|
||||
dbg_free(retbuf);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Free reply array */
|
||||
static int _cluster_free_request(lvm_response_t * response)
|
||||
{
|
||||
int *ptr = (int *) response - 2;
|
||||
int i;
|
||||
int num;
|
||||
|
||||
/* Check it's ours to free */
|
||||
if (response == NULL || *ptr != LVM_SIGNATURE) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
num = ptr[1];
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
dbg_free(response[i].response);
|
||||
}
|
||||
|
||||
dbg_free(ptr);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _lock_for_cluster(unsigned char cmd, unsigned int flags, char *name)
|
||||
{
|
||||
int status;
|
||||
int i;
|
||||
char *args;
|
||||
const char *node = "";
|
||||
int len;
|
||||
int saved_errno = errno;
|
||||
lvm_response_t *response = NULL;
|
||||
int num_responses;
|
||||
|
||||
assert(name);
|
||||
|
||||
len = strlen(name) + 3;
|
||||
args = alloca(len);
|
||||
strcpy(args + 2, name);
|
||||
|
||||
args[0] = flags & 0xBF; /* Maskoff LOCAL flag */
|
||||
args[1] = 0; /* Not used now */
|
||||
|
||||
/*
|
||||
* 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.
|
||||
* Also, if the lock is exclusive it makes no sense to try to
|
||||
* acquire it on all nodes, so just do that on the local node too.
|
||||
*/
|
||||
if (cmd == CLVMD_CMD_LOCK_VG ||
|
||||
(flags & LCK_TYPE_MASK) == LCK_EXCL ||
|
||||
(flags & LCK_LOCAL))
|
||||
node = ".";
|
||||
|
||||
status = _cluster_request(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;
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
|
||||
saved_errno = errno;
|
||||
_cluster_free_request(response);
|
||||
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,
|
||||
int flags)
|
||||
#else
|
||||
int lock_resource(struct cmd_context *cmd, const char *resource, int flags)
|
||||
#endif
|
||||
{
|
||||
char lockname[PATH_MAX];
|
||||
int cluster_cmd = 0;
|
||||
|
||||
assert(strlen(resource) < sizeof(lockname));
|
||||
|
||||
switch (flags & LCK_SCOPE_MASK) {
|
||||
case LCK_VG:
|
||||
/* If the VG name is empty then lock the unused PVs */
|
||||
if (!resource || !*resource)
|
||||
lvm_snprintf(lockname, sizeof(lockname), "P_orphans");
|
||||
else
|
||||
lvm_snprintf(lockname, sizeof(lockname), "V_%s",
|
||||
resource);
|
||||
|
||||
cluster_cmd = CLVMD_CMD_LOCK_VG;
|
||||
flags &= LCK_TYPE_MASK;
|
||||
break;
|
||||
|
||||
case LCK_LV:
|
||||
cluster_cmd = CLVMD_CMD_LOCK_LV;
|
||||
strcpy(lockname, resource);
|
||||
flags &= 0xffdf; /* Mask off HOLD flag */
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error("Unrecognised lock scope: %d",
|
||||
flags & LCK_SCOPE_MASK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Send a message to the cluster manager */
|
||||
log_very_verbose("Locking %s at 0x%x", lockname, flags);
|
||||
|
||||
return _lock_for_cluster(cluster_cmd, flags, lockname);
|
||||
}
|
||||
|
||||
#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();
|
||||
if (_clvmd_sock == -1)
|
||||
stack;
|
||||
}
|
||||
|
||||
#ifdef CLUSTER_LOCKING_INTERNAL
|
||||
int init_cluster_locking(struct locking_type *locking, struct config_tree *cft)
|
||||
{
|
||||
locking->lock_resource = _lock_resource;
|
||||
locking->fin_locking = _locking_end;
|
||||
locking->reset_locking = _reset_locking;
|
||||
locking->flags = LCK_PRE_MEMLOCK;
|
||||
|
||||
_clvmd_sock = _open_local_sock();
|
||||
if (_clvmd_sock == -1)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
int locking_init(int type, struct config_tree *cf, uint32_t *flags)
|
||||
{
|
||||
_clvmd_sock = _open_local_sock();
|
||||
if (_clvmd_sock == -1)
|
||||
return 0;
|
||||
|
||||
/* Ask LVM to lock memory before calling us */
|
||||
*flags |= LCK_PRE_MEMLOCK;
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
@@ -145,6 +145,14 @@ int init_locking(int type, struct config_tree *cft)
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
#ifdef CLUSTER_LOCKING_INTERNAL
|
||||
case 3:
|
||||
if (!init_cluster_locking(&_locking, cft))
|
||||
break;
|
||||
log_very_verbose("Cluster locking enabled.");
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
default:
|
||||
log_error("Unknown locking type requested.");
|
||||
return 0;
|
||||
|
@@ -40,3 +40,4 @@ int init_no_locking(struct locking_type *locking, struct config_tree *cf);
|
||||
int init_file_locking(struct locking_type *locking, struct config_tree *cf);
|
||||
|
||||
int init_external_locking(struct locking_type *locking, struct config_tree *cf);
|
||||
int init_cluster_locking(struct locking_type *locking, struct config_tree *cf);
|
||||
|
@@ -21,7 +21,7 @@
|
||||
#include "toolcontext.h"
|
||||
#include "lv_alloc.h"
|
||||
#include "display.h"
|
||||
#include "segtypes.h"
|
||||
#include "segtype.h"
|
||||
|
||||
/*
|
||||
* These functions adjust the pe counts in pv's
|
||||
@@ -623,6 +623,16 @@ int lv_extend(struct format_instance *fid,
|
||||
lv->le_count += extents;
|
||||
lv->size += (uint64_t) extents *lv->vg->extent_size;
|
||||
|
||||
if (fid->fmt->ops->segtype_supported &&
|
||||
!fid->fmt->ops->segtype_supported(fid, segtype)) {
|
||||
log_error("Metadata format (%s) does not support required "
|
||||
"LV segment type (%s).", fid->fmt->name,
|
||||
segtype->name);
|
||||
log_error("Consider changing the metadata format by running "
|
||||
"vgconvert.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_allocate(lv->vg, lv, allocatable_pvs, old_le_count, alloc,
|
||||
segtype, stripes, stripe_size, mirrors, mirrored_pv,
|
||||
mirrored_pe, status)) {
|
||||
|
@@ -18,7 +18,7 @@
|
||||
#include "toolcontext.h"
|
||||
#include "lv_alloc.h"
|
||||
#include "str_list.h"
|
||||
#include "segtypes.h"
|
||||
#include "segtype.h"
|
||||
|
||||
/*
|
||||
* Attempt to merge two adjacent segments.
|
||||
@@ -39,6 +39,9 @@ int lv_merge_segments(struct logical_volume *lv)
|
||||
struct list *segh, *t;
|
||||
struct lv_segment *current, *prev = NULL;
|
||||
|
||||
if (lv->status & LOCKED || lv->status & PVMOVE)
|
||||
return 1;
|
||||
|
||||
list_iterate_safe(segh, t, &lv->segments) {
|
||||
current = list_item(segh, struct lv_segment);
|
||||
|
||||
@@ -77,6 +80,7 @@ int lv_check_segments(struct logical_volume *lv)
|
||||
|
||||
/*
|
||||
* Split the supplied segment at the supplied logical extent
|
||||
* NB Use LE numbering that works across stripes PV1: 0,2,4 PV2: 1,3,5 etc.
|
||||
*/
|
||||
static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg,
|
||||
uint32_t le)
|
||||
@@ -85,6 +89,7 @@ static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg,
|
||||
struct lv_segment *split_seg;
|
||||
uint32_t s;
|
||||
uint32_t offset = le - seg->le;
|
||||
uint32_t area_offset;
|
||||
|
||||
if (!(seg->segtype->flags & SEG_CAN_SPLIT)) {
|
||||
log_error("Unable to split the %s segment at LE %" PRIu32
|
||||
@@ -107,8 +112,9 @@ static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg,
|
||||
}
|
||||
|
||||
/* In case of a striped segment, the offset has to be / stripes */
|
||||
area_offset = offset;
|
||||
if (seg->segtype->flags & SEG_AREAS_STRIPED)
|
||||
offset /= seg->area_count;
|
||||
area_offset /= seg->area_count;
|
||||
|
||||
/* Adjust the PV mapping */
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
@@ -116,12 +122,19 @@ static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg,
|
||||
switch (seg->area[s].type) {
|
||||
case AREA_LV:
|
||||
split_seg->area[s].u.lv.le =
|
||||
seg->area[s].u.lv.le + offset;
|
||||
seg->area[s].u.lv.le + area_offset;
|
||||
log_debug("Split %s:%u[%u] at %u: %s LE %u", lv->name,
|
||||
seg->le, s, le, seg->area[s].u.lv.lv->name,
|
||||
split_seg->area[s].u.lv.le);
|
||||
break;
|
||||
|
||||
case AREA_PV:
|
||||
split_seg->area[s].u.pv.pe =
|
||||
seg->area[s].u.pv.pe + offset;
|
||||
seg->area[s].u.pv.pe + area_offset;
|
||||
log_debug("Split %s:%u[%u] at %u: %s PE %u", lv->name,
|
||||
seg->le, s, le,
|
||||
dev_name(seg->area[s].u.pv.pv->dev),
|
||||
split_seg->area[s].u.pv.pe);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -131,8 +144,13 @@ static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg,
|
||||
}
|
||||
}
|
||||
|
||||
split_seg->area_len = seg->area_len - offset;
|
||||
seg->area_len = offset;
|
||||
split_seg->area_len -= area_offset;
|
||||
seg->area_len = area_offset;
|
||||
|
||||
split_seg->len -= offset;
|
||||
seg->len = offset;
|
||||
|
||||
split_seg->le = seg->le + seg->len;
|
||||
|
||||
/* Add split off segment to the list _after_ the original one */
|
||||
list_add_h(&seg->list, &split_seg->list);
|
||||
|
@@ -265,7 +265,7 @@ struct name_list {
|
||||
char *name;
|
||||
};
|
||||
|
||||
struct alloc_area {
|
||||
struct pe_range {
|
||||
struct list list;
|
||||
uint32_t start; /* PEs */
|
||||
uint32_t count; /* PEs */
|
||||
@@ -275,7 +275,7 @@ struct pv_list {
|
||||
struct list list;
|
||||
struct physical_volume *pv;
|
||||
struct list *mdas; /* Metadata areas */
|
||||
struct list *alloc_areas; /* Areas we may allocate from */
|
||||
struct list *pe_ranges; /* Ranges of PEs e.g. for allocation */
|
||||
};
|
||||
|
||||
struct lv_list {
|
||||
@@ -341,6 +341,12 @@ struct format_handler {
|
||||
*/
|
||||
int (*vg_setup) (struct format_instance * fi, struct volume_group * vg);
|
||||
|
||||
/*
|
||||
* Check whether particular segment type is supported.
|
||||
*/
|
||||
int (*segtype_supported) (struct format_instance *fid,
|
||||
struct segment_type *segtype);
|
||||
|
||||
/*
|
||||
* Create format instance with a particular metadata area
|
||||
*/
|
||||
@@ -501,7 +507,7 @@ int vg_remove_snapshot(struct volume_group *vg, struct logical_volume *cow);
|
||||
*/
|
||||
int insert_pvmove_mirrors(struct cmd_context *cmd,
|
||||
struct logical_volume *lv_mirr,
|
||||
struct physical_volume *pv,
|
||||
struct list *source_pvl,
|
||||
struct logical_volume *lv,
|
||||
struct list *allocatable_pvs,
|
||||
struct list *lvs_changed);
|
||||
|
@@ -16,7 +16,7 @@
|
||||
#include "lib.h"
|
||||
#include "metadata.h"
|
||||
#include "toolcontext.h"
|
||||
#include "segtypes.h"
|
||||
#include "segtype.h"
|
||||
#include "display.h"
|
||||
#include "activate.h"
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
*/
|
||||
int insert_pvmove_mirrors(struct cmd_context *cmd,
|
||||
struct logical_volume *lv_mirr,
|
||||
struct physical_volume *pv,
|
||||
struct list *source_pvl,
|
||||
struct logical_volume *lv,
|
||||
struct list *allocatable_pvs,
|
||||
struct list *lvs_changed)
|
||||
@@ -34,9 +34,15 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
|
||||
struct list *segh;
|
||||
struct lv_segment *seg;
|
||||
struct lv_list *lvl;
|
||||
struct pv_list *pvl;
|
||||
int lv_used = 0;
|
||||
uint32_t s, start_le, extent_count = 0u;
|
||||
struct segment_type *segtype;
|
||||
struct pe_range *per;
|
||||
uint32_t pe_start, pe_end, per_end, stripe_multiplier;
|
||||
|
||||
/* Only 1 PV may feature in source_pvl */
|
||||
pvl = list_item(source_pvl->n, struct pv_list);
|
||||
|
||||
if (!(segtype = get_segtype_from_string(lv->vg->cmd, "mirror"))) {
|
||||
stack;
|
||||
@@ -50,43 +56,113 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Split LV segments to match PE ranges */
|
||||
list_iterate(segh, &lv->segments) {
|
||||
seg = list_item(segh, struct lv_segment);
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
if (seg->area[s].type != AREA_PV ||
|
||||
seg->area[s].u.pv.pv->dev != pvl->pv->dev)
|
||||
continue;
|
||||
|
||||
/* Do these PEs need moving? */
|
||||
list_iterate_items(per, pvl->pe_ranges) {
|
||||
pe_start = seg->area[s].u.pv.pe;
|
||||
pe_end = pe_start + seg->area_len - 1;
|
||||
per_end = per->start + per->count - 1;
|
||||
|
||||
/* No overlap? */
|
||||
if ((pe_end < per->start) ||
|
||||
(pe_start > per_end))
|
||||
continue;
|
||||
|
||||
if (seg->segtype->flags & SEG_AREAS_STRIPED)
|
||||
stripe_multiplier = seg->area_count;
|
||||
else
|
||||
stripe_multiplier = 1;
|
||||
|
||||
if ((per->start != pe_start &&
|
||||
per->start > pe_start) &&
|
||||
!lv_split_segment(lv, seg->le +
|
||||
(per->start - pe_start) *
|
||||
stripe_multiplier)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((per_end != pe_end &&
|
||||
per_end < pe_end) &&
|
||||
!lv_split_segment(lv, seg->le +
|
||||
(per_end - pe_start + 1) *
|
||||
stripe_multiplier)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Work through all segments on the supplied PV */
|
||||
list_iterate(segh, &lv->segments) {
|
||||
seg = list_item(segh, struct lv_segment);
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
if (seg->area[s].type != AREA_PV ||
|
||||
seg->area[s].u.pv.pv->dev != pv->dev)
|
||||
seg->area[s].u.pv.pv->dev != pvl->pv->dev)
|
||||
continue;
|
||||
|
||||
/* First time, add LV to list of LVs affected */
|
||||
if (!lv_used) {
|
||||
if (!(lvl = pool_alloc(cmd->mem, sizeof(*lvl)))) {
|
||||
log_error("lv_list alloc failed");
|
||||
pe_start = seg->area[s].u.pv.pe;
|
||||
|
||||
/* Do these PEs need moving? */
|
||||
list_iterate_items(per, pvl->pe_ranges) {
|
||||
per_end = per->start + per->count - 1;
|
||||
|
||||
if ((pe_start < per->start) ||
|
||||
(pe_start > per_end))
|
||||
continue;
|
||||
|
||||
log_debug("Matched PE range %u-%u against "
|
||||
"%s %u len %u", per->start, per_end,
|
||||
dev_name(seg->area[s].u.pv.pv->dev),
|
||||
seg->area[s].u.pv.pe, seg->area_len);
|
||||
|
||||
/* First time, add LV to list of LVs affected */
|
||||
if (!lv_used) {
|
||||
if (!(lvl = pool_alloc(cmd->mem, sizeof(*lvl)))) {
|
||||
log_error("lv_list alloc failed");
|
||||
return 0;
|
||||
}
|
||||
lvl->lv = lv;
|
||||
list_add(lvs_changed, &lvl->list);
|
||||
lv_used = 1;
|
||||
}
|
||||
|
||||
log_very_verbose("Moving %s:%u-%u of %s/%s",
|
||||
dev_name(pvl->pv->dev),
|
||||
seg->area[s].u.pv.pe,
|
||||
seg->area[s].u.pv.pe +
|
||||
seg->area_len - 1,
|
||||
lv->vg->name, lv->name);
|
||||
|
||||
start_le = lv_mirr->le_count;
|
||||
if (!lv_extend(lv->vg->fid, lv_mirr, segtype, 1,
|
||||
seg->area_len, 0u, seg->area_len,
|
||||
seg->area[s].u.pv.pv,
|
||||
seg->area[s].u.pv.pe,
|
||||
PVMOVE, allocatable_pvs,
|
||||
lv->alloc)) {
|
||||
log_error("Unable to allocate "
|
||||
"temporary LV for pvmove.");
|
||||
return 0;
|
||||
}
|
||||
lvl->lv = lv;
|
||||
list_add(lvs_changed, &lvl->list);
|
||||
lv_used = 1;
|
||||
seg->area[s].type = AREA_LV;
|
||||
seg->area[s].u.lv.lv = lv_mirr;
|
||||
seg->area[s].u.lv.le = start_le;
|
||||
|
||||
extent_count += seg->area_len;
|
||||
|
||||
lv->status |= LOCKED;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
start_le = lv_mirr->le_count;
|
||||
if (!lv_extend(lv->vg->fid, lv_mirr, segtype, 1,
|
||||
seg->area_len, 0u, seg->area_len,
|
||||
seg->area[s].u.pv.pv,
|
||||
seg->area[s].u.pv.pe,
|
||||
PVMOVE, allocatable_pvs,
|
||||
lv->alloc)) {
|
||||
log_error("Allocation for temporary "
|
||||
"pvmove LV failed");
|
||||
return 0;
|
||||
}
|
||||
seg->area[s].type = AREA_LV;
|
||||
seg->area[s].u.lv.lv = lv_mirr;
|
||||
seg->area[s].u.lv.le = start_le;
|
||||
|
||||
extent_count += seg->area_len;
|
||||
|
||||
lv->status |= LOCKED;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,8 +243,12 @@ int remove_pvmove_mirrors(struct volume_group *vg,
|
||||
lv1->status &= ~LOCKED;
|
||||
}
|
||||
}
|
||||
if (!lv_merge_segments(lv1))
|
||||
stack;
|
||||
|
||||
}
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@@ -206,13 +206,13 @@ static int _create_areas(struct pool *mem, struct pv_map *pvm, uint32_t start,
|
||||
static int _create_allocatable_areas(struct pool *mem, struct pv_map *pvm)
|
||||
{
|
||||
struct list *alloc_areas, *aah;
|
||||
struct alloc_area *aa;
|
||||
struct pe_range *aa;
|
||||
|
||||
alloc_areas = pvm->pvl->alloc_areas;
|
||||
alloc_areas = pvm->pvl->pe_ranges;
|
||||
|
||||
if (alloc_areas) {
|
||||
list_iterate(aah, alloc_areas) {
|
||||
aa = list_item(aah, struct alloc_area);
|
||||
aa = list_item(aah, struct pe_range);
|
||||
if (!_create_areas(mem, pvm, aa->start, aa->count)) {
|
||||
stack;
|
||||
return 0;
|
||||
|
@@ -15,7 +15,7 @@
|
||||
|
||||
#include "lib.h"
|
||||
#include "toolcontext.h"
|
||||
#include "segtypes.h"
|
||||
#include "segtype.h"
|
||||
|
||||
struct segment_type *get_segtype_from_string(struct cmd_context *cmd,
|
||||
const char *str)
|
@@ -85,4 +85,8 @@ struct segment_type *init_snapshot_segtype(struct cmd_context *cmd);
|
||||
struct segment_type *init_mirrored_segtype(struct cmd_context *cmd);
|
||||
#endif
|
||||
|
||||
#ifdef CRYPT_INTERNAL
|
||||
struct segment_type *init_crypt_segtype(struct cmd_context *cmd);
|
||||
#endif
|
||||
|
||||
#endif
|
@@ -22,8 +22,6 @@ LIB_SHARED = liblvm2mirror.so
|
||||
|
||||
include $(top_srcdir)/make.tmpl
|
||||
|
||||
.PHONY: install
|
||||
|
||||
install: liblvm2mirror.so
|
||||
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \
|
||||
$(libdir)/liblvm2mirror.so.$(LIB_VERSION)
|
||||
|
@@ -18,7 +18,7 @@
|
||||
#include "list.h"
|
||||
#include "toolcontext.h"
|
||||
#include "metadata.h"
|
||||
#include "segtypes.h"
|
||||
#include "segtype.h"
|
||||
#include "display.h"
|
||||
#include "text_export.h"
|
||||
#include "text_import.h"
|
||||
@@ -95,7 +95,7 @@ static int _text_export(const struct lv_segment *seg, struct formatter *f)
|
||||
{
|
||||
outf(f, "mirror_count = %u", seg->area_count);
|
||||
if (seg->status & PVMOVE)
|
||||
out_size(f, (uint64_t) seg->extents_copied,
|
||||
out_size(f, (uint64_t) seg->extents_copied * seg->lv->vg->extent_size,
|
||||
"extents_moved = %u", seg->extents_copied);
|
||||
|
||||
return out_areas(f, seg, "mirror");
|
||||
@@ -130,6 +130,7 @@ static int _compose_target_line(struct dev_manager *dm, struct pool *mem,
|
||||
int mirror_status = MIRR_RUNNING;
|
||||
int areas = seg->area_count;
|
||||
int start_area = 0u;
|
||||
uint32_t region_size, region_max;
|
||||
|
||||
if (!*target_state)
|
||||
*target_state = _init_target(mem, cft);
|
||||
@@ -143,7 +144,7 @@ static int _compose_target_line(struct dev_manager *dm, struct pool *mem,
|
||||
if (seg->extents_copied == seg->area_len) {
|
||||
mirror_status = MIRR_COMPLETED;
|
||||
start_area = 1;
|
||||
} else if (*pvmove_mirror_count++) {
|
||||
} else if ((*pvmove_mirror_count)++) {
|
||||
mirror_status = MIRR_DISABLED;
|
||||
areas = 1;
|
||||
}
|
||||
@@ -153,8 +154,20 @@ static int _compose_target_line(struct dev_manager *dm, struct pool *mem,
|
||||
*target = "linear";
|
||||
} else {
|
||||
*target = "mirror";
|
||||
|
||||
/* Find largest power of 2 region size unit we can use */
|
||||
region_max = (1 << (ffs(seg->area_len) - 1)) *
|
||||
seg->lv->vg->extent_size;
|
||||
|
||||
region_size = mirr_state->region_size;
|
||||
if (region_max < region_size) {
|
||||
region_size = region_max;
|
||||
log_verbose("Using reduced mirror region size of %u sectors",
|
||||
region_size);
|
||||
}
|
||||
|
||||
if ((*pos = lvm_snprintf(params, paramsize, "core 1 %u %u ",
|
||||
mirr_state->region_size, areas)) < 0) {
|
||||
region_size, areas)) < 0) {
|
||||
stack;
|
||||
return -1;
|
||||
}
|
||||
@@ -162,7 +175,6 @@ static int _compose_target_line(struct dev_manager *dm, struct pool *mem,
|
||||
|
||||
return compose_areas_line(dm, seg, params, paramsize, pos, start_area,
|
||||
areas);
|
||||
|
||||
}
|
||||
|
||||
static int _target_percent(void **target_state, struct pool *mem,
|
||||
@@ -188,8 +200,7 @@ static int _target_percent(void **target_state, struct pool *mem,
|
||||
*total_denominator += denominator;
|
||||
|
||||
if (seg)
|
||||
seg->extents_copied = mirr_state->region_size *
|
||||
numerator / seg->lv->vg->extent_size;
|
||||
seg->extents_copied = seg->area_len * numerator / denominator;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -247,5 +258,7 @@ struct segment_type *init_segtype(struct cmd_context *cmd)
|
||||
segtype->private = NULL;
|
||||
segtype->flags = SEG_AREAS_MIRRORED;
|
||||
|
||||
log_very_verbose("Initialised segtype: %s", segtype->name);
|
||||
|
||||
return segtype;
|
||||
}
|
||||
|
@@ -16,6 +16,7 @@
|
||||
#include "lib.h"
|
||||
#include "lvm-types.h"
|
||||
#include "lvm-string.h"
|
||||
#include "pool.h"
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
@@ -98,3 +99,107 @@ int split_words(char *buffer, unsigned max, char **argv)
|
||||
|
||||
return arg;
|
||||
}
|
||||
|
||||
/*
|
||||
* Device layer names are all of the form <vg>-<lv>-<layer>, any
|
||||
* other hyphens that appear in these names are quoted with yet
|
||||
* another hyphen. The top layer of any device has no layer
|
||||
* name. eg, vg0-lvol0.
|
||||
*/
|
||||
static void _count_hyphens(const char *str, size_t *len, int *hyphens)
|
||||
{
|
||||
const char *ptr;
|
||||
|
||||
for (ptr = str; *ptr; ptr++, (*len)++)
|
||||
if (*ptr == '-')
|
||||
(*hyphens)++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copies a string, quoting hyphens with hyphens.
|
||||
*/
|
||||
static void _quote_hyphens(char **out, const char *src)
|
||||
{
|
||||
while (*src) {
|
||||
if (*src == '-')
|
||||
*(*out)++ = '-';
|
||||
|
||||
*(*out)++ = *src++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* <vg>-<lv>-<layer> or if !layer just <vg>-<lv>.
|
||||
*/
|
||||
char *build_dm_name(struct pool *mem, const char *vg,
|
||||
const char *lv, const char *layer)
|
||||
{
|
||||
size_t len = 0;
|
||||
int hyphens = 0;
|
||||
char *r, *out;
|
||||
|
||||
_count_hyphens(vg, &len, &hyphens);
|
||||
_count_hyphens(lv, &len, &hyphens);
|
||||
|
||||
if (layer && *layer)
|
||||
_count_hyphens(layer, &len, &hyphens);
|
||||
|
||||
len += hyphens + 2;
|
||||
|
||||
if (!(r = pool_alloc(mem, len))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
out = r;
|
||||
_quote_hyphens(&out, vg);
|
||||
*out++ = '-';
|
||||
_quote_hyphens(&out, lv);
|
||||
|
||||
if (layer && *layer) {
|
||||
*out++ = '-';
|
||||
_quote_hyphens(&out, layer);
|
||||
}
|
||||
*out = '\0';
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove hyphen quoting from a component of a name.
|
||||
* NULL-terminates the component and returns start of next component.
|
||||
*/
|
||||
static char *_unquote(char *component)
|
||||
{
|
||||
char *c = component;
|
||||
char *o = c;
|
||||
|
||||
while (*c) {
|
||||
if (*(c + 1)) {
|
||||
if (*c == '-') {
|
||||
if (*(c + 1) == '-')
|
||||
c++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
*o = *c;
|
||||
o++;
|
||||
c++;
|
||||
}
|
||||
|
||||
*o = '\0';
|
||||
return (c + 1);
|
||||
}
|
||||
|
||||
int split_dm_name(struct pool *mem, const char *dmname,
|
||||
char **vgname, char **lvname, char **layer)
|
||||
{
|
||||
if (!(*vgname = pool_strdup(mem, dmname)))
|
||||
return 0;
|
||||
|
||||
_unquote(*layer = _unquote(*lvname = _unquote(*vgname)));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@@ -19,6 +19,8 @@
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
struct pool;
|
||||
|
||||
/*
|
||||
* On error, up to glibc 2.0.6, snprintf returned -1 if buffer was too small;
|
||||
* From glibc 2.1 it returns number of chars (excl. trailing null) that would
|
||||
@@ -32,4 +34,10 @@ int emit_to_buffer(char **buffer, size_t *size, const char *fmt, ...);
|
||||
|
||||
int split_words(char *buffer, unsigned max, char **argv);
|
||||
|
||||
char *build_dm_name(struct pool *mem, const char *vg,
|
||||
const char *lv, const char *layer);
|
||||
|
||||
int split_dm_name(struct pool *mem, const char *dmname,
|
||||
char **vgname, char **lvname, char **layer);
|
||||
|
||||
#endif
|
||||
|
@@ -29,11 +29,13 @@ struct memblock {
|
||||
};
|
||||
|
||||
static struct {
|
||||
unsigned int blocks, mblocks;
|
||||
unsigned block_serialno;/* Non-decreasing serialno of block */
|
||||
unsigned blocks_allocated; /* Current number of blocks allocated */
|
||||
unsigned blocks_max; /* Max no of concurrently-allocated blocks */
|
||||
unsigned int bytes, mbytes;
|
||||
|
||||
} _mem_stats = {
|
||||
0, 0, 0, 0};
|
||||
0, 0, 0, 0, 0};
|
||||
|
||||
static struct memblock *_head = 0;
|
||||
static struct memblock *_tail = 0;
|
||||
@@ -65,7 +67,7 @@ void *malloc_aux(size_t s, const char *file, int line)
|
||||
/* setup fields */
|
||||
nb->magic = nb + 1;
|
||||
nb->length = s;
|
||||
nb->id = ++_mem_stats.blocks;
|
||||
nb->id = ++_mem_stats.block_serialno;
|
||||
nb->next = 0;
|
||||
nb->prev = _tail;
|
||||
|
||||
@@ -89,8 +91,9 @@ void *malloc_aux(size_t s, const char *file, int line)
|
||||
*ptr++ = (char) nb->id;
|
||||
}
|
||||
|
||||
if (_mem_stats.blocks > _mem_stats.mblocks)
|
||||
_mem_stats.mblocks = _mem_stats.blocks;
|
||||
_mem_stats.blocks_allocated++;
|
||||
if (_mem_stats.blocks_allocated > _mem_stats.blocks_max)
|
||||
_mem_stats.blocks_max = _mem_stats.blocks_allocated;
|
||||
|
||||
_mem_stats.bytes += s;
|
||||
if (_mem_stats.bytes > _mem_stats.mbytes)
|
||||
@@ -140,8 +143,8 @@ void free_aux(void *p)
|
||||
else
|
||||
_tail = mb->prev;
|
||||
|
||||
assert(_mem_stats.blocks);
|
||||
_mem_stats.blocks--;
|
||||
assert(_mem_stats.blocks_allocated);
|
||||
_mem_stats.blocks_allocated--;
|
||||
_mem_stats.bytes -= mb->length;
|
||||
|
||||
/* free the memory */
|
||||
|
@@ -83,7 +83,7 @@ static void _append_block(struct pool *p, struct block *b)
|
||||
|
||||
static struct block *_new_block(size_t s, unsigned alignment)
|
||||
{
|
||||
static char *_oom = "Out of memory";
|
||||
static const char *_oom = "Out of memory";
|
||||
|
||||
/* FIXME: I'm currently ignoring the alignment arg. */
|
||||
size_t len = sizeof(struct block) + s;
|
||||
@@ -180,10 +180,13 @@ int pool_grow_object(struct pool *p, const void *buffer, size_t delta)
|
||||
|
||||
if (p->object) {
|
||||
memcpy(new->data, p->object->data, p->object->size);
|
||||
dbg_free(p->object->data);
|
||||
dbg_free(p->object);
|
||||
}
|
||||
p->object = new;
|
||||
|
||||
memcpy(new->data + size - delta, buffer, delta);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@@ -109,8 +109,8 @@ void pool_empty(struct pool *p)
|
||||
for (c = p->chunk; c && c->prev; c = c->prev)
|
||||
;
|
||||
|
||||
if (p->chunk)
|
||||
pool_free(p, (char *) (p->chunk + 1));
|
||||
if (c)
|
||||
pool_free(p, (char *) (c + 1));
|
||||
}
|
||||
|
||||
void pool_free(struct pool *p, void *ptr)
|
||||
|
@@ -17,6 +17,41 @@
|
||||
#define _LVM_XLATE_H
|
||||
|
||||
#ifdef linux
|
||||
# include <endian.h>
|
||||
# include <byteswap.h>
|
||||
#else
|
||||
# include <machine/endian.h>
|
||||
# define bswap_16(x) (((x) & 0x00ffU) << 8 | \
|
||||
((x) & 0xff00U) >> 8)
|
||||
# define bswap_32(x) (((x) & 0x000000ffU) << 24 | \
|
||||
((x) & 0xff000000U) >> 24 | \
|
||||
((x) & 0x0000ff00U) << 8 | \
|
||||
((x) & 0x00ff0000U) >> 8)
|
||||
# define bswap_64(x) (((x) & 0x00000000000000ffU) << 56 | \
|
||||
((x) & 0xff00000000000000U) >> 56 | \
|
||||
((x) & 0x000000000000ff00U) << 40 | \
|
||||
((x) & 0x00ff000000000000U) >> 40 | \
|
||||
((x) & 0x0000000000ff0000U) << 24 | \
|
||||
((x) & 0x0000ff0000000000U) >> 24 | \
|
||||
((x) & 0x00000000ff000000U) << 8 | \
|
||||
((x) & 0x000000ff00000000U) >> 8)
|
||||
#endif
|
||||
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
# define xlate16(x) (x)
|
||||
# define xlate32(x) (x)
|
||||
# define xlate64(x) (x)
|
||||
# define xlate16_be(x) bswap_16(x)
|
||||
# define xlate32_be(x) bswap_32(x)
|
||||
# define xlate64_be(x) bswap_64(x)
|
||||
#elif BYTE_ORDER == BIG_ENDIAN
|
||||
# define xlate16(x) bswap_16(x)
|
||||
# define xlate32(x) bswap_32(x)
|
||||
# define xlate64(x) bswap_64(x)
|
||||
# define xlate16_be(x) (x)
|
||||
# define xlate32_be(x) (x)
|
||||
# define xlate64_be(x) (x)
|
||||
#else
|
||||
# include <asm/byteorder.h>
|
||||
# define xlate16(x) __cpu_to_le16((x))
|
||||
# define xlate32(x) __cpu_to_le32((x))
|
||||
@@ -24,41 +59,6 @@
|
||||
# define xlate16_be(x) __cpu_to_be16((x))
|
||||
# define xlate32_be(x) __cpu_to_be32((x))
|
||||
# define xlate64_be(x) __cpu_to_be64((x))
|
||||
#else
|
||||
# include <machine/endian.h>
|
||||
# if !defined(BYTE_ORDER) || \
|
||||
(BYTE_ORDER != BIG_ENDIAN && BYTE_ORDER != LITTLE_ENDIAN)
|
||||
# error "Undefined or unrecognised BYTE_ORDER";
|
||||
# endif
|
||||
# define __xlate16(x) (((x) & 0x00ffU) << 8 | \
|
||||
((x) & 0xff00U) >> 8)
|
||||
# define __xlate32(x) (((x) & 0x000000ffU) << 24 | \
|
||||
((x) & 0xff000000U) >> 24 | \
|
||||
((x) & 0x0000ff00U) << 8 | \
|
||||
((x) & 0x00ff0000U) >> 8)
|
||||
# define __xlate64(x) (((x) & 0x00000000000000ffU) << 56 | \
|
||||
((x) & 0xff00000000000000U) >> 56 | \
|
||||
((x) & 0x000000000000ff00U) << 40 | \
|
||||
((x) & 0x00ff000000000000U) >> 40 | \
|
||||
((x) & 0x0000000000ff0000U) << 24 | \
|
||||
((x) & 0x0000ff0000000000U) >> 24 | \
|
||||
((x) & 0x00000000ff000000U) << 8 | \
|
||||
((x) & 0x000000ff00000000U) >> 8)
|
||||
# if BYTE_ORDER == LITTLE_ENDIAN
|
||||
# define xlate16(x) (x)
|
||||
# define xlate32(x) (x)
|
||||
# define xlate64(x) (x)
|
||||
# define xlate16_be(x) __xlate16(x)
|
||||
# define xlate32_be(x) __xlate32(x)
|
||||
# define xlate64_be(x) __xlate64(x)
|
||||
# else
|
||||
# define xlate16(x) __xlate16(x)
|
||||
# define xlate32(x) __xlate32(x)
|
||||
# define xlate64(x) __xlate64(x)
|
||||
# define xlate16_be(x) (x)
|
||||
# define xlate32_be(x) (x)
|
||||
# define xlate64_be(x) (x)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@@ -23,6 +23,8 @@ FIELD(LVS, lv, STR, "LV", name, 4, string, "lv_name")
|
||||
FIELD(LVS, lv, STR, "Attr", lvid, 4, lvstatus, "lv_attr")
|
||||
FIELD(LVS, lv, NUM, "Maj", major, 3, int32, "lv_major")
|
||||
FIELD(LVS, lv, NUM, "Min", minor, 3, int32, "lv_minor")
|
||||
FIELD(LVS, lv, STR, "KMaj", lvid, 4, lvkmaj, "lv_kernel_major")
|
||||
FIELD(LVS, lv, STR, "KMin", lvid, 4, lvkmin, "lv_kernel_minor")
|
||||
FIELD(LVS, lv, NUM, "LSize", size, 5, size64, "lv_size")
|
||||
FIELD(LVS, lv, NUM, "#Seg", lvid, 4, lvsegcount, "seg_count")
|
||||
FIELD(LVS, lv, STR, "Origin", lvid, 6, origin, "origin")
|
||||
@@ -34,6 +36,7 @@ FIELD(LVS, lv, STR, "LV Tags", tags, 7, tags, "lv_tags")
|
||||
FIELD(PVS, pv, STR, "Fmt", id, 3, pvfmt, "pv_fmt")
|
||||
FIELD(PVS, pv, STR, "PV UUID", id, 38, uuid, "pv_uuid")
|
||||
FIELD(PVS, pv, NUM, "PSize", id, 5, pvsize, "pv_size")
|
||||
FIELD(PVS, pv, NUM, "DevSize", dev, 7, devsize, "dev_size")
|
||||
FIELD(PVS, pv, NUM, "PFree", id, 5, pvfree, "pv_free")
|
||||
FIELD(PVS, pv, NUM, "Used", id, 4, pvused, "pv_used")
|
||||
FIELD(PVS, pv, STR, "PV", dev, 10, dev_name, "pv_name")
|
||||
|
@@ -21,7 +21,7 @@
|
||||
#include "lvm-string.h"
|
||||
#include "display.h"
|
||||
#include "activate.h"
|
||||
#include "segtypes.h"
|
||||
#include "segtype.h"
|
||||
|
||||
/*
|
||||
* For macro use
|
||||
@@ -259,6 +259,65 @@ static int _pvfmt_disp(struct report_handle *rh, struct field *field,
|
||||
return _string_disp(rh, field, &pv->fmt->name);
|
||||
}
|
||||
|
||||
static int _int_disp(struct report_handle *rh, struct field *field,
|
||||
const void *data)
|
||||
{
|
||||
const int value = *(const int *) data;
|
||||
uint64_t *sortval;
|
||||
char *repstr;
|
||||
|
||||
if (!(repstr = pool_zalloc(rh->mem, 13))) {
|
||||
log_error("pool_alloc failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(sortval = pool_alloc(rh->mem, sizeof(int64_t)))) {
|
||||
log_error("pool_alloc failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lvm_snprintf(repstr, 12, "%d", value) < 0) {
|
||||
log_error("int too big: %d", value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*sortval = (const uint64_t) value;
|
||||
field->sort_value = sortval;
|
||||
field->report_string = repstr;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _lvkmaj_disp(struct report_handle *rh, struct field *field,
|
||||
const void *data)
|
||||
{
|
||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||
struct lvinfo info;
|
||||
uint64_t minusone = UINT64_C(-1);
|
||||
|
||||
if (lv_info(lv, &info) && info.exists)
|
||||
return _int_disp(rh, field, &info.major);
|
||||
else
|
||||
return _int_disp(rh, field, &minusone);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _lvkmin_disp(struct report_handle *rh, struct field *field,
|
||||
const void *data)
|
||||
{
|
||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||
struct lvinfo info;
|
||||
uint64_t minusone = UINT64_C(-1);
|
||||
|
||||
if (lv_info(lv, &info) && info.exists)
|
||||
return _int_disp(rh, field, &info.minor);
|
||||
else
|
||||
return _int_disp(rh, field, &minusone);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _lvstatus_disp(struct report_handle *rh, struct field *field,
|
||||
const void *data)
|
||||
{
|
||||
@@ -586,6 +645,18 @@ static int _pvsize_disp(struct report_handle *rh, struct field *field,
|
||||
return _size64_disp(rh, field, &size);
|
||||
}
|
||||
|
||||
static int _devsize_disp(struct report_handle *rh, struct field *field,
|
||||
const void *data)
|
||||
{
|
||||
const struct device *dev = *(const struct device **) data;
|
||||
uint64_t size;
|
||||
|
||||
if (!dev_get_size(dev, &size))
|
||||
size = 0;
|
||||
|
||||
return _size64_disp(rh, field, &size);
|
||||
}
|
||||
|
||||
static int _vgfree_disp(struct report_handle *rh, struct field *field,
|
||||
const void *data)
|
||||
{
|
||||
|
@@ -22,8 +22,6 @@ LIB_SHARED = liblvm2snapshot.so
|
||||
|
||||
include $(top_srcdir)/make.tmpl
|
||||
|
||||
.PHONY: install
|
||||
|
||||
install: liblvm2snapshot.so
|
||||
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \
|
||||
$(libdir)/liblvm2snapshot.so.$(LIB_VERSION)
|
||||
|
@@ -18,7 +18,7 @@
|
||||
#include "list.h"
|
||||
#include "toolcontext.h"
|
||||
#include "metadata.h"
|
||||
#include "segtypes.h"
|
||||
#include "segtype.h"
|
||||
#include "text_export.h"
|
||||
#include "config.h"
|
||||
#include "activate.h"
|
||||
@@ -161,5 +161,7 @@ struct segment_type *init_segtype(struct cmd_context *cmd)
|
||||
segtype->private = NULL;
|
||||
segtype->flags = SEG_SNAPSHOT;
|
||||
|
||||
log_very_verbose("Initialised segtype: %s", segtype->name);
|
||||
|
||||
return segtype;
|
||||
}
|
||||
|
@@ -17,7 +17,7 @@
|
||||
#include "pool.h"
|
||||
#include "list.h"
|
||||
#include "toolcontext.h"
|
||||
#include "segtypes.h"
|
||||
#include "segtype.h"
|
||||
#include "display.h"
|
||||
#include "text_export.h"
|
||||
#include "text_import.h"
|
||||
@@ -217,5 +217,7 @@ struct segment_type *init_striped_segtype(struct cmd_context *cmd)
|
||||
segtype->flags =
|
||||
SEG_CAN_SPLIT | SEG_AREAS_STRIPED | SEG_FORMAT1_SUPPORT;
|
||||
|
||||
log_very_verbose("Initialised segtype: %s", segtype->name);
|
||||
|
||||
return segtype;
|
||||
}
|
||||
|
@@ -16,7 +16,7 @@
|
||||
#include "pool.h"
|
||||
#include "list.h"
|
||||
#include "toolcontext.h"
|
||||
#include "segtypes.h"
|
||||
#include "segtype.h"
|
||||
#include "display.h"
|
||||
#include "text_export.h"
|
||||
#include "text_import.h"
|
||||
@@ -97,5 +97,7 @@ struct segment_type *init_zero_segtype(struct cmd_context *cmd)
|
||||
segtype->private = NULL;
|
||||
segtype->flags = SEG_CAN_SPLIT | SEG_VIRTUAL;
|
||||
|
||||
log_very_verbose("Initialised segtype: %s", segtype->name);
|
||||
|
||||
return segtype;
|
||||
}
|
||||
|
@@ -16,9 +16,9 @@
|
||||
#ifndef _LINUX_LIBDM_COMPAT_H
|
||||
#define _LINUX_LIBDM_COMPAT_H
|
||||
|
||||
#include "kdev_t.h"
|
||||
#include <inttypes.h>
|
||||
#include <linux/dm-ioctl.h>
|
||||
#include <linux/kdev_t.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
struct dm_task;
|
||||
|
@@ -33,8 +33,8 @@
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef linux
|
||||
# include "kdev_t.h"
|
||||
# include <linux/limits.h>
|
||||
# include <linux/kdev_t.h>
|
||||
# include <linux/dm-ioctl.h>
|
||||
#else
|
||||
# define MAJOR(x) major((x))
|
||||
|
@@ -17,6 +17,7 @@
|
||||
#include "libdm-common.h"
|
||||
#include "list.h"
|
||||
#include "log.h"
|
||||
#include "kdev_t.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -27,7 +28,6 @@
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <linux/dm-ioctl.h>
|
||||
#include <linux/kdev_t.h>
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
# include <selinux/selinux.h>
|
||||
@@ -208,7 +208,7 @@ static int _set_selinux_context(const char *path)
|
||||
|
||||
log_debug("Setting SELinux context for %s", path);
|
||||
if (is_selinux_enabled() <= 0)
|
||||
return 0;
|
||||
return 1;
|
||||
|
||||
if (matchpathcon(path, 0, &scontext) < 0) {
|
||||
log_error("%s: matchpathcon failed: %s", path, strerror(errno));
|
||||
|
31
make.tmpl.in
31
make.tmpl.in
@@ -28,8 +28,8 @@ CFLAGS += @CFLAGS@
|
||||
CLDFLAGS += @CLDFLAGS@
|
||||
CLDWHOLEARCHIVE += @CLDWHOLEARCHIVE@
|
||||
CLDNOWHOLEARCHIVE += @CLDNOWHOLEARCHIVE@
|
||||
LD_DEPS += @LD_DEPS@
|
||||
LD_FLAGS += @LD_FLAGS@
|
||||
LDDEPS += @LDDEPS@
|
||||
LDFLAGS += @LDFLAGS@
|
||||
SOFLAG += @SOFLAG@
|
||||
|
||||
# Setup directory variables
|
||||
@@ -61,24 +61,24 @@ CFLAGS += -fPIC -Wall -Wundef -Wshadow -Wcast-align -Wwrite-strings -Wmissing-pr
|
||||
|
||||
#CFLAGS += -W -Wconversion -Wpointer-arith -Wredundant-decls -Wbad-function-cast -Wcast-qual -Wmissing-noreturn
|
||||
|
||||
CFLAGS += @COPTIMISE_FLAG@
|
||||
|
||||
ifeq ("@DEBUG@", "yes")
|
||||
CFLAGS += -g -fno-omit-frame-pointer -DDEBUG
|
||||
CFLAGS += -DDEBUG_MEM
|
||||
else
|
||||
CFLAGS += -O2
|
||||
endif
|
||||
|
||||
ifeq ("@INTL@", "yes")
|
||||
CFLAGS += -DINTL_PACKAGE=\"@INTL_PACKAGE@\" -DLOCALEDIR=\"@LOCALEDIR@\"
|
||||
endif
|
||||
|
||||
LD_FLAGS += -L$(top_srcdir)/lib -L$(libdir)
|
||||
LDFLAGS += -L$(top_srcdir)/lib -L$(libdir)
|
||||
|
||||
#CFLAGS += -DDEBUG_POOL
|
||||
#CFLAGS += -DBOUNDS_CHECK
|
||||
|
||||
#CFLAGS += -pg
|
||||
#LD_FLAGS += -pg
|
||||
#LDFLAGS += -pg
|
||||
|
||||
STRIP=
|
||||
#STRIP = -s
|
||||
@@ -99,20 +99,22 @@ DEPS = $(top_srcdir)/make.tmpl $(top_srcdir)/VERSION Makefile $(INC_LNS)
|
||||
OBJECTS = $(SOURCES:%.c=%.o)
|
||||
POTFILES = $(SOURCES:%.c=%.pot)
|
||||
|
||||
.PHONY: all install install_cluster pofile distclean clean
|
||||
.PHONY: $(SUBDIRS) $(SUBDIRS.install) $(SUBDIRS.clean) $(SUBDIRS.distclean)
|
||||
.PHONY: $(SUBDIRS.pofile) $(SUBDIRS.install_cluster)
|
||||
|
||||
SUBDIRS.install := $(SUBDIRS:=.install)
|
||||
SUBDIRS.install_cluster := $(SUBDIRS:=.install_cluster)
|
||||
SUBDIRS.pofile := $(SUBDIRS:=.pofile)
|
||||
SUBDIRS.clean := $(SUBDIRS:=.clean)
|
||||
SUBDIRS.distclean := $(SUBDIRS:=.distclean)
|
||||
|
||||
.PHONY: all install pofile distclean clean
|
||||
.PHONY: $(SUBDIRS) $(SUBDIRS.install) $(SUBDIRS.clean) $(SUBDIRS.distclean)
|
||||
.PHONY: $(SUBDIRS.pofile)
|
||||
|
||||
TARGETS += $(LIB_SHARED) $(LIB_STATIC)
|
||||
|
||||
all: $(SUBDIRS) $(TARGETS)
|
||||
|
||||
install: all $(SUBDIRS.install)
|
||||
install_cluster: all $(SUBDIRS.install_cluster)
|
||||
|
||||
$(SUBDIRS):
|
||||
$(MAKE) -C $@
|
||||
@@ -120,6 +122,9 @@ $(SUBDIRS):
|
||||
$(SUBDIRS.install): $(SUBDIRS)
|
||||
$(MAKE) -C $(@:.install=) install
|
||||
|
||||
$(SUBDIRS.install_cluster): $(SUBDIRS)
|
||||
$(MAKE) -C $(@:.install_cluster=) install_cluster
|
||||
|
||||
$(SUBDIRS.clean):
|
||||
-$(MAKE) -C $(@:.clean=) clean
|
||||
|
||||
@@ -145,7 +150,7 @@ $(TARGETS): $(OBJECTS)
|
||||
%.so: %.o
|
||||
$(CC) -c $(INCLUDES) $(CFLAGS) $< -o $@
|
||||
|
||||
$(LIB_SHARED): $(OBJECTS) $(LD_DEPS)
|
||||
$(LIB_SHARED): $(OBJECTS) $(LDDEPS)
|
||||
$(CC) $(SOFLAG) -Wl,-soname,$(notdir $@).$(LIB_VERSION) \
|
||||
$(CLDFLAGS) $(OBJECTS) -o $@
|
||||
|
||||
@@ -166,11 +171,11 @@ $(LIB_STATIC): $(OBJECTS)
|
||||
|
||||
clean: $(SUBDIRS.clean)
|
||||
$(RM) $(OBJECTS) $(TARGETS) $(CLEAN_TARGETS) $(SOURCES:%.c=%.d) \
|
||||
$(SOURCES:%.c=%.pot) $(LD_DEPS)
|
||||
$(SOURCES:%.c=%.pot) $(LDDEPS)
|
||||
|
||||
distclean: $(SUBDIRS.distclean)
|
||||
$(RM) $(OBJECTS) $(TARGETS) $(CLEAN_TARGETS) $(SOURCES:%.c=%.d) \
|
||||
$(SOURCES:%.c=%.pot) $(LD_DEPS) \
|
||||
$(SOURCES:%.c=%.pot) $(LDDEPS) \
|
||||
config.cache config.log config.status \
|
||||
Makefile make.tmpl core \
|
||||
version.h lvm2.po
|
||||
|
@@ -24,11 +24,16 @@ MAN8=lvchange.8 lvcreate.8 lvdisplay.8 lvextend.8 lvm.8 lvmchange.8 \
|
||||
vgconvert.8 vgdisplay.8 vgexport.8 vgextend.8 vgimport.8 \
|
||||
vgmerge.8 vgmknodes.8 vgreduce.8 vgremove.8 vgrename.8 \
|
||||
vgs.8 vgscan.8 vgsplit.8
|
||||
MAN8CLUSTER=clvmd.8
|
||||
MAN5DIR=${mandir}/man5
|
||||
MAN8DIR=${mandir}/man8
|
||||
|
||||
include $(top_srcdir)/make.tmpl
|
||||
|
||||
ifeq ("@CLVMD@", "yes")
|
||||
install: install_cluster
|
||||
endif
|
||||
|
||||
install:
|
||||
@echo "Installing $(MAN8) in $(MAN8DIR)"
|
||||
@for f in $(MAN8); \
|
||||
@@ -43,3 +48,11 @@ install:
|
||||
$(RM) $(MAN5DIR)/$$f; \
|
||||
@INSTALL@ -D $(OWNER) $(GROUP) -m 444 $$f $(MAN5DIR)/$$f; \
|
||||
done
|
||||
|
||||
install_cluster:
|
||||
@echo "Installing $(MAN8CLUSTER) in $(MAN8DIR)"
|
||||
@for f in $(MAN8CLUSTER); \
|
||||
do \
|
||||
$(RM) $(MAN8DIR)/$$f; \
|
||||
@INSTALL@ -D $(OWNER) $(GROUP) -m 444 $$f $(MAN8DIR)/$$f; \
|
||||
done
|
||||
|
28
man/clvmd.8
Normal file
28
man/clvmd.8
Normal file
@@ -0,0 +1,28 @@
|
||||
.TH CLVMD 8 "LVM TOOLS" "Red Hat Inc" \" -*- nroff -*-
|
||||
.SH NAME
|
||||
clvmd \- cluster LVM daemon
|
||||
.SH SYNOPSIS
|
||||
.B clvmd
|
||||
[\-d] [\-h]
|
||||
[\-t <timeout>]
|
||||
[\-V]
|
||||
.SH DESCRIPTION
|
||||
clvmd is the daemon that distributes LVM metadata updates around a cluster.
|
||||
It must be running on all nodes in the cluster and will give an error
|
||||
if a node in the cluster does not have this daemon running.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.I \-d
|
||||
Runs in the foreground and prints debugging information (if compiled in) to
|
||||
stderr. By default, clvmd will fork into the background when invoked.
|
||||
.TP
|
||||
.I \-t <timeout>
|
||||
Specifies the timeout for commands to run around the cluster. This should not
|
||||
be so small that commands with many disk updates to do will fail, so you
|
||||
may need to increase this on systems with very large disk farms.
|
||||
The default is 30 seconds.
|
||||
.TP
|
||||
.I \-V
|
||||
Display the version of the cluster LVM daemon.
|
||||
.SH SEE ALSO
|
||||
.BR lvm (8)
|
@@ -44,8 +44,9 @@ Change access permission to read-only or read/write.
|
||||
Change read ahead sector count per logical between 2 and 120.
|
||||
Not used by device-mapper.
|
||||
.SH Examples
|
||||
"lvchange -x n vg00/lvol1" prevents the allocation of any physical
|
||||
extents on logical volume lvol1 in volume group vg00.
|
||||
"lvchange -p r vg00/lvol1" changes the permission on
|
||||
volume lvol1 in volume group vg00 to be read-only.
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR lvm (8),
|
||||
.BR lvcreate (8)
|
||||
|
55
man/pvmove.8
55
man/pvmove.8
@@ -3,10 +3,10 @@
|
||||
pvmove \- move physical extents
|
||||
.SH SYNOPSIS
|
||||
.B pvmove
|
||||
[\-\-abort]
|
||||
[\-\-abort] [\-\-background]
|
||||
[\-d/\-\-debug] [\-h/\-\-help] [\-i/\-\-interval Seconds] [\-v/\-\-verbose]
|
||||
[\-n/\-\-name LogicalVolume]
|
||||
[SourcePhysicalVolume [DestinationPhysicalVolume[:PE[-PE]...]...]]
|
||||
[SourcePhysicalVolume[:PE[-PE]...] [DestinationPhysicalVolume[:PE[-PE]...]...]]
|
||||
.SH DESCRIPTION
|
||||
.B pvmove
|
||||
allows you to move the allocated physical extents (PEs) on
|
||||
@@ -23,13 +23,56 @@ is specifed, the normal allocation rules for the volume group are used.
|
||||
|
||||
If \fBpvmove\fP gets interrupted for any reason (e.g. the machine crashes)
|
||||
then run \fBpvmove\fP again without any PhysicalVolume arguments to
|
||||
continue with any moves that were in progress or use \fBpvmove --abort\fP to
|
||||
abort them.
|
||||
restart any moves that were in progress from the last checkpoint.
|
||||
Alternatively use \fBpvmove --abort\fP at any time to abort them
|
||||
at the last checkpoint.
|
||||
|
||||
You can run more than one pvmove at once provided they are moving data
|
||||
off different SourcePhysicalVolumes, but additional pvmoves will ignore
|
||||
any logical volumes already in the process of being changed, so some
|
||||
data might not get moved.
|
||||
|
||||
\fBpvmove\fP works as follows:
|
||||
|
||||
1. A temporary 'pvmove' logical volume is created to store
|
||||
details of all the data movements required.
|
||||
|
||||
2. Every logical volume in the volume group is searched
|
||||
for contiguous data that need moving
|
||||
according to the command line arguments.
|
||||
For each piece of data found, a new segment is added to the end of the
|
||||
pvmove LV.
|
||||
This segment takes the form of a temporary mirror to copy the data
|
||||
from the original location to a newly-allocated location.
|
||||
The original LV is updated to use the new temporary mirror segment
|
||||
in the pvmove LV instead of accessing the data directly.
|
||||
|
||||
3. The volume group metadata is updated on disk.
|
||||
|
||||
4. The first segment of the pvmove logical volume is activated and starts
|
||||
to mirror the first part of the data. Only one segment is mirrored at once
|
||||
as this is usually more efficient.
|
||||
|
||||
5. A daemon repeatedly checks progress at the specified time interval.
|
||||
When it detects that the first temporary mirror is in-sync,
|
||||
it breaks that mirror so that only the new location for that data gets used
|
||||
and writes a checkpoint into the volume group metadata on disk.
|
||||
Then it activates the mirror for the next segment of the pvmove LV.
|
||||
|
||||
6. When there are no more segments left to be mirrored,
|
||||
the temporary logical volume is removed and the volume group metadata
|
||||
is updated so that the logical volumes reflect the new data locations.
|
||||
|
||||
Note that this new process cannot support the original LVM1
|
||||
type of on-disk metadata. Metadata can be converted using \fBvgconvert\fP(8).
|
||||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.I \-\-abort
|
||||
Abort any moves currently in progress.
|
||||
Abort any moves in progress.
|
||||
.TP
|
||||
.I \-\-background
|
||||
Run the daemon in the background.
|
||||
.TP
|
||||
.I \-i, \-\-interval Seconds
|
||||
Report progress as a percentage at regular intervals.
|
||||
@@ -50,4 +93,4 @@ runtime information, use:
|
||||
\ pvmove -v /dev/hda4
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR lvm (8)
|
||||
.BR lvm (8), vgconvert (8)
|
||||
|
3371
po/lvm2.po
3371
po/lvm2.po
File diff suppressed because it is too large
Load Diff
154
scripts/clvmd_fix_conf.sh
Normal file
154
scripts/clvmd_fix_conf.sh
Normal file
@@ -0,0 +1,154 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Edit an lvm.conf file to enable cluster locking.
|
||||
#
|
||||
# $1 is the directory where the locking library is installed.
|
||||
# $2 (optional) is the config file
|
||||
# $3 (optional) is the locking library name
|
||||
#
|
||||
#
|
||||
PREFIX=$1
|
||||
LVMCONF=$2
|
||||
LIB=$3
|
||||
|
||||
if [ -z "$PREFIX" ]
|
||||
then
|
||||
echo "usage: $0 <prefix> [<config file>] [<library>]"
|
||||
echo ""
|
||||
echo "<prefix> location of the cluster locking shared library. (no default)"
|
||||
echo "<config file> name of the LVM config file (default: /etc/lvm/lvm.conf)"
|
||||
echo "<library> name of the shared library (default: liblvm2clusterlock.so)"
|
||||
echo ""
|
||||
exit 0
|
||||
fi
|
||||
|
||||
[ -z "$LVMCONF" ] && LVMCONF="/etc/lvm/lvm.conf"
|
||||
[ -z "$LIB" ] && LIB="liblvm2clusterlock.so"
|
||||
|
||||
if [ "${PREFIX:0:1}" != "/" ]
|
||||
then
|
||||
echo "Prefix must be an absolute path name (starting with a /)"
|
||||
exit 12
|
||||
fi
|
||||
|
||||
if [ ! -f "$LVMCONF" ]
|
||||
then
|
||||
echo "$LVMCONF does not exist"
|
||||
exit 10
|
||||
fi
|
||||
|
||||
if [ ! -f "$PREFIX/$LIB" ]
|
||||
then
|
||||
echo "$PREFIX/$LIB does not exist, did you do a \"make install\" ?"
|
||||
exit 11
|
||||
fi
|
||||
|
||||
|
||||
SCRIPTFILE=`mktemp -t lvmscript.XXXXXXXXXX`
|
||||
TMPFILE=`mktemp -t lvmtmp.XXXXXXXXXX`
|
||||
|
||||
|
||||
# Flags so we know which parts of the file we can replace and which need
|
||||
# adding. These are return codes from grep, so zero means it IS present!
|
||||
have_type=1
|
||||
have_dir=1
|
||||
have_library=1
|
||||
have_global=1
|
||||
|
||||
grep -q '^[[:blank:]]*locking_type[[:blank:]]*=' $LVMCONF
|
||||
have_type=$?
|
||||
|
||||
grep -q '^[[:blank:]]*library_dir[[:blank:]]*=' $LVMCONF
|
||||
have_dir=$?
|
||||
|
||||
grep -q '^[[:blank:]]*locking_library[[:blank:]]*=' $LVMCONF
|
||||
have_library=$?
|
||||
|
||||
# Those options are in section "global {" so we must have one if any are present.
|
||||
if [ "$have_type" = "0" -o "$have_dir" = "0" -o "$have_library" = "0" ]
|
||||
then
|
||||
|
||||
# See if we can find it...
|
||||
grep -q '^[[:blank:]]*global[[:blank:]]*{' $LVMCONF
|
||||
have_global=$?
|
||||
|
||||
if [ "$have_global" = "1" ]
|
||||
then
|
||||
echo "global keys but no 'global {' found, can't edit file"
|
||||
exit 12
|
||||
fi
|
||||
fi
|
||||
|
||||
# So if we don't have "global {" we need to create one and
|
||||
# populate it
|
||||
|
||||
if [ "$have_global" = "1" ]
|
||||
then
|
||||
cat $LVMCONF - <<EOF > $TMPFILE
|
||||
global {
|
||||
# Enable locking for cluster LVM
|
||||
locking_type = 2
|
||||
library_dir = "$PREFIX"
|
||||
locking_library = "$LIB"
|
||||
}
|
||||
EOF
|
||||
if [ $? != 0 ]
|
||||
then
|
||||
echo "failed to create temporary config file, $LVMCONF not updated"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
#
|
||||
# We have a "global {" section, so add or replace the
|
||||
# locking entries as appropriate
|
||||
#
|
||||
|
||||
if [ "$have_type" = "0" ]
|
||||
then
|
||||
SEDCMD=" s/^[[:blank:]]*locking_type[[:blank:]]*=.*/\ \ \ \ locking_type = 2/g"
|
||||
else
|
||||
SEDCMD=" /global[[:blank:]]*{/a\ \ \ \ locking_type = 2"
|
||||
fi
|
||||
|
||||
if [ "$have_dir" = "0" ]
|
||||
then
|
||||
SEDCMD="${SEDCMD}\ns'^[[:blank:]]*library_dir[[:blank:]]*=.*'\ \ \ \ library_dir = \"$PREFIX\"'g"
|
||||
else
|
||||
SEDCMD="${SEDCMD}\n/global[[:blank:]]*{/a\ \ \ \ library_dir = \"$PREFIX\""
|
||||
fi
|
||||
|
||||
if [ "$have_library" = "0" ]
|
||||
then
|
||||
SEDCMD="${SEDCMD}\ns/^[[:blank:]]*locking_library[[:blank:]]*=.*/\ \ \ \ locking_library = \"$LIB\"/g"
|
||||
else
|
||||
SEDCMD="${SEDCMD}\n/global[[:blank:]]*{/a\ \ \ \ locking_library = \"$LIB\""
|
||||
fi
|
||||
|
||||
echo -e $SEDCMD > $SCRIPTFILE
|
||||
sed <$LVMCONF >$TMPFILE -f $SCRIPTFILE
|
||||
if [ $? != 0 ]
|
||||
then
|
||||
echo "sed failed, $LVMCONF not updated"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Now we have a suitably editted config file in a temp place,
|
||||
# backup the original and copy our new one into place.
|
||||
|
||||
cp $LVMCONF $LVMCONF.nocluster
|
||||
if [ $? != 0 ]
|
||||
then
|
||||
echo "failed to backup old config file, $LVMCONF not updated"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
cp $TMPFILE $LVMCONF
|
||||
if [ $? != 0 ]
|
||||
then
|
||||
echo "failed to copy new config file into place, check $LVMCONF is still OK"
|
||||
exit 3
|
||||
fi
|
||||
|
||||
rm -f $SCRIPTFILE $TMPFILE
|
||||
|
90
scripts/clvmd_init
Executable file
90
scripts/clvmd_init
Executable file
@@ -0,0 +1,90 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# /etc/rc.d/init.d/clvmd
|
||||
#
|
||||
# Starts the clvm daemon
|
||||
# NOTE: These startup levels may not be right yet - it depends on where
|
||||
# the rest of the cluster startup goes.
|
||||
#
|
||||
# chkconfig: 345 72 5
|
||||
# description: distributes LVM commands in a clustered environment. \
|
||||
# a clvmd must be run on all nodes in a cluster for clustered LVM \
|
||||
# operations to work.
|
||||
# processname: clvmd
|
||||
|
||||
# Source function library.
|
||||
. /etc/init.d/functions
|
||||
|
||||
BINARY=/usr/sbin/clvmd
|
||||
LOCKFILE=/var/lock/subsys/clvmd
|
||||
|
||||
test -x "$BINARY" || exit 0
|
||||
|
||||
RETVAL=0
|
||||
|
||||
#
|
||||
# See how we were called.
|
||||
#
|
||||
|
||||
prog="clvmd"
|
||||
|
||||
start() {
|
||||
# Check if clvmd is already running
|
||||
if [ ! -f "$LOCKFILE" ]; then
|
||||
echo -n $"Starting $prog: "
|
||||
daemon $BINARY
|
||||
RETVAL=$?
|
||||
[ $RETVAL -eq 0 ] && touch $LOCKFILE
|
||||
echo
|
||||
fi
|
||||
return $RETVAL
|
||||
}
|
||||
|
||||
stop() {
|
||||
echo -n $"Stopping $prog: "
|
||||
killproc $BINARY
|
||||
RETVAL=$?
|
||||
[ $RETVAL -eq 0 ] && rm -f $LOCKFILE
|
||||
echo
|
||||
return $RETVAL
|
||||
}
|
||||
|
||||
|
||||
restart() {
|
||||
stop
|
||||
start
|
||||
}
|
||||
|
||||
reload() {
|
||||
restart
|
||||
}
|
||||
|
||||
status_clvm() {
|
||||
status $BINARY
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
start
|
||||
;;
|
||||
stop)
|
||||
stop
|
||||
;;
|
||||
reload|restart)
|
||||
restart
|
||||
;;
|
||||
condrestart)
|
||||
if [ -f $LOCKFILE ]; then
|
||||
restart
|
||||
fi
|
||||
;;
|
||||
status)
|
||||
status_clvm
|
||||
;;
|
||||
*)
|
||||
echo $"Usage: $0 {start|stop|restart|condrestart|status}"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
exit $?
|
||||
exit $RETVAL
|
@@ -23,6 +23,7 @@ endif
|
||||
SOURCES =\
|
||||
archiver.c \
|
||||
dumpconfig.c \
|
||||
formats.c \
|
||||
lvchange.c \
|
||||
lvcreate.c \
|
||||
lvdisplay.c \
|
||||
@@ -43,6 +44,7 @@ SOURCES =\
|
||||
pvremove.c \
|
||||
pvscan.c \
|
||||
reporter.c \
|
||||
segtypes.c \
|
||||
toollib.c \
|
||||
vgcfgbackup.c \
|
||||
vgcfgrestore.c \
|
||||
@@ -91,23 +93,23 @@ endif
|
||||
include $(top_srcdir)/make.tmpl
|
||||
|
||||
lvm: $(OBJECTS) lvm.o $(top_srcdir)/lib/liblvm.a
|
||||
$(CC) -o $@ $(OBJECTS) lvm.o $(LD_FLAGS) $(LVMLIBS) $(LIBS) -rdynamic
|
||||
$(CC) -o $@ $(OBJECTS) lvm.o $(LDFLAGS) $(LVMLIBS) $(LIBS) -rdynamic
|
||||
|
||||
lvm.static: $(OBJECTS) lvm.o $(top_srcdir)/lib/liblvm.a
|
||||
$(CC) -o $@ $(OBJECTS) lvm.o -static $(LD_FLAGS) $(LVMLIBS) $(LIBS) \
|
||||
$(CC) -o $@ $(OBJECTS) lvm.o -static $(LDFLAGS) $(LVMLIBS) $(LIBS) \
|
||||
-rdynamic
|
||||
|
||||
liblvm2cmd.a: $(top_srcdir)/lib/liblvm.a $(OBJECTS)
|
||||
cat $(top_srcdir)/lib/liblvm.a > $@
|
||||
$(AR) rs $@ $(OBJECTS)
|
||||
|
||||
liblvm2cmd.so: liblvm2cmd.a $(LD_DEPS)
|
||||
liblvm2cmd.so: liblvm2cmd.a $(LDDEPS)
|
||||
$(CC) -o liblvm2cmd.so $(SOFLAG) $(CLDFLAGS) \
|
||||
$(CLDWHOLEARCHIVE) liblvm2cmd.a $(CLDNOWHOLEARCHIVE)
|
||||
|
||||
.commands: commands.h cmdnames.h Makefile
|
||||
$(CC) -E -P cmdnames.h 2> /dev/null | \
|
||||
egrep -v '^ *(|#.*|dumpconfig|help|pvdata|version) *$$' > .commands
|
||||
egrep -v '^ *(|#.*|dumpconfig|formats|help|pvdata|segtypes|version) *$$' > .commands
|
||||
|
||||
.PHONY: install_cmdlib_dynamic install_cmdlib_static \
|
||||
install_tools_dynamic install_tools_static
|
||||
|
@@ -32,6 +32,10 @@ xx(dumpconfig,
|
||||
"Dump active configuration",
|
||||
"dumpconfig <filename>\n")
|
||||
|
||||
xx(formats,
|
||||
"List available metadata formats",
|
||||
"formats\n")
|
||||
|
||||
xx(help,
|
||||
"Display help for commands",
|
||||
"help <command>" "\n")
|
||||
@@ -428,6 +432,7 @@ xx(pvmove,
|
||||
"pvmove " "\n"
|
||||
"\t[--abort]\n"
|
||||
"\t[-A|--autobackup {y|n}]\n"
|
||||
"\t[--alloc AllocationType]\n"
|
||||
"\t[-b|--background]\n"
|
||||
"\t[-d|--debug]\n "
|
||||
"\t[-f|--force]\n"
|
||||
@@ -438,12 +443,11 @@ xx(pvmove,
|
||||
"\t[--version]\n"
|
||||
"\t[{-n|--name} LogicalVolume]\n"
|
||||
/* "\t[{-n|--name} LogicalVolume[:LogicalExtent[-LogicalExtent]...]]\n" */
|
||||
"\tSourcePhysicalVolume\n"
|
||||
/* "\tSourcePhysicalVolume[:PhysicalExtent[-PhysicalExtent]...]}\n" */
|
||||
"\tSourcePhysicalVolume[:PhysicalExtent[-PhysicalExtent]...]}\n"
|
||||
"\t[DestinationPhysicalVolume[:PhysicalExtent[-PhysicalExtent]...]...]\n",
|
||||
|
||||
abort_ARG, autobackup_ARG, background_ARG, force_ARG, interval_ARG, name_ARG,
|
||||
test_ARG)
|
||||
abort_ARG, alloc_ARG, autobackup_ARG, background_ARG, force_ARG,
|
||||
interval_ARG, name_ARG, test_ARG)
|
||||
|
||||
xx(pvremove,
|
||||
"Remove LVM label(s) from physical volume(s)",
|
||||
@@ -451,7 +455,6 @@ xx(pvremove,
|
||||
"\t[-d|--debug]" "\n"
|
||||
"\t[-f[f]|--force [--force]] " "\n"
|
||||
"\t[-h|-?|--help] " "\n"
|
||||
"\t[-y|--yes]" "\n"
|
||||
"\t[-t|--test] " "\n"
|
||||
"\t[-v|--verbose] " "\n"
|
||||
"\t[-y|--yes]" "\n"
|
||||
@@ -514,6 +517,10 @@ xx(pvscan,
|
||||
exported_ARG, ignorelockingfailure_ARG, novolumegroup_ARG, partial_ARG,
|
||||
short_ARG, uuid_ARG)
|
||||
|
||||
xx(segtypes,
|
||||
"List available segment types",
|
||||
"segtypes\n")
|
||||
|
||||
xx(vgcfgbackup,
|
||||
"Backup volume group configuration(s)",
|
||||
"vgcfgbackup " "\n"
|
||||
|
@@ -38,7 +38,7 @@ extern char *optarg;
|
||||
#endif
|
||||
|
||||
#ifdef linux
|
||||
# include <linux/kdev_t.h>
|
||||
# include "kdev_t.h"
|
||||
#else
|
||||
# define MAJOR(x) major((x))
|
||||
# define MINOR(x) minor((x))
|
||||
@@ -505,9 +505,10 @@ static int _status(int argc, char **argv, void *data)
|
||||
if (data && !_switches[VERBOSE_ARG])
|
||||
printf("%s: ", name);
|
||||
if (target_type) {
|
||||
printf("%" PRIu64 " %" PRIu64 " %s %s\n",
|
||||
printf("%" PRIu64 " %" PRIu64 " %s %s",
|
||||
start, length, target_type, params);
|
||||
}
|
||||
printf("\n");
|
||||
} while (next);
|
||||
|
||||
if (data && _switches[VERBOSE_ARG])
|
||||
|
23
tools/formats.c
Normal file
23
tools/formats.c
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2003-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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "tools.h"
|
||||
|
||||
int formats(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
display_formats(cmd);
|
||||
|
||||
return ECMD_PROCESSED;
|
||||
}
|
@@ -418,7 +418,7 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
|
||||
*/
|
||||
if (lp->pv_count) {
|
||||
if (!(pvh = create_pv_list(cmd->mem, vg,
|
||||
lp->pv_count, lp->pvs))) {
|
||||
lp->pv_count, lp->pvs, 1))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
@@ -1394,7 +1394,8 @@ int lvm2_main(int argc, char **argv)
|
||||
base = basename(namebase);
|
||||
while (*base == '/')
|
||||
base++;
|
||||
if (strcmp(base, "lvm") && strcmp(base, "lvm.static"))
|
||||
if (strcmp(base, "lvm") && strcmp(base, "lvm.static") &&
|
||||
strcmp(base, "initrd-lvm"))
|
||||
alias = 1;
|
||||
free(namebase);
|
||||
|
||||
|
@@ -351,7 +351,7 @@ static int _lvresize(struct cmd_context *cmd, struct lvresize_params *lp)
|
||||
if (lp->argc)
|
||||
log_print("Ignoring PVs on command line when reducing");
|
||||
} else if (!(pvh = lp->argc ? create_pv_list(cmd->mem, vg, lp->argc,
|
||||
lp->argv) : &vg->pvs)) {
|
||||
lp->argv, 1) : &vg->pvs)) {
|
||||
stack;
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
@@ -149,7 +149,8 @@ static int pvcreate_single(struct cmd_context *cmd, const char *pv_name,
|
||||
DEFAULT_PVMETADATACOPIES);
|
||||
|
||||
if (!(dev = dev_cache_get(pv_name, cmd->filter))) {
|
||||
log_error("%s: Couldn't find device.", pv_name);
|
||||
log_error("%s: Couldn't find device. Check your filters?",
|
||||
pv_name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "tools.h"
|
||||
#include "polldaemon.h"
|
||||
#include "display.h"
|
||||
|
||||
/* Allow /dev/vgname/lvname, vgname/lvname or lvname */
|
||||
static const char *_extract_lvname(struct cmd_context *cmd, const char *vgname,
|
||||
@@ -85,14 +86,15 @@ static struct volume_group *_get_vg(struct cmd_context *cmd, const char *vgname)
|
||||
/* Create list of PVs for allocation of replacement extents */
|
||||
static struct list *_get_allocatable_pvs(struct cmd_context *cmd, int argc,
|
||||
char **argv, struct volume_group *vg,
|
||||
struct physical_volume *pv)
|
||||
struct physical_volume *pv,
|
||||
alloc_policy_t alloc)
|
||||
{
|
||||
struct list *allocatable_pvs, *pvht, *pvh;
|
||||
struct pv_list *pvl;
|
||||
|
||||
if (argc) {
|
||||
if (!(allocatable_pvs = create_pv_list(cmd->mem, vg, argc,
|
||||
argv))) {
|
||||
argv, 1))) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
@@ -103,13 +105,18 @@ static struct list *_get_allocatable_pvs(struct cmd_context *cmd, int argc,
|
||||
}
|
||||
}
|
||||
|
||||
/* Don't allocate onto the PV we're clearing! */
|
||||
/* Remove PV if full */
|
||||
list_iterate_safe(pvh, pvht, allocatable_pvs) {
|
||||
pvl = list_item(pvh, struct pv_list);
|
||||
if ((pvl->pv->dev == pv->dev) ||
|
||||
(pvl->pv->pe_count == pvl->pv->pe_alloc_count))
|
||||
list_del(&pvl->list);
|
||||
|
||||
/* Don't allocate onto the PV we're clearing! */
|
||||
if ((alloc != ALLOC_ANYWHERE) && (pvl->pv->dev == pv->dev)) {
|
||||
list_del(&pvl->list);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Remove PV if full */
|
||||
if ((pvl->pv->pe_count == pvl->pv->pe_alloc_count))
|
||||
list_del(&pvl->list);
|
||||
}
|
||||
|
||||
if (list_empty(allocatable_pvs)) {
|
||||
@@ -123,15 +130,17 @@ static struct list *_get_allocatable_pvs(struct cmd_context *cmd, int argc,
|
||||
/* Create new LV with mirror segments for the required copies */
|
||||
static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd,
|
||||
struct volume_group *vg,
|
||||
struct physical_volume *pv,
|
||||
struct list *source_pvl,
|
||||
const char *lv_name,
|
||||
struct list *allocatable_pvs,
|
||||
alloc_policy_t alloc,
|
||||
struct list **lvs_changed)
|
||||
{
|
||||
struct logical_volume *lv_mirr, *lv;
|
||||
struct lv_list *lvl;
|
||||
|
||||
/* FIXME Cope with non-contiguous => splitting existing segments */
|
||||
/* FIXME Pass 'alloc' down to lv_extend */
|
||||
if (!(lv_mirr = lv_create_empty(vg->fid, NULL, "pvmove%d",
|
||||
LVM_READ | LVM_WRITE,
|
||||
ALLOC_CONTIGUOUS, vg))) {
|
||||
@@ -165,7 +174,7 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd,
|
||||
log_print("Skipping locked LV %s", lv->name);
|
||||
continue;
|
||||
}
|
||||
if (!insert_pvmove_mirrors(cmd, lv_mirr, pv, lv,
|
||||
if (!insert_pvmove_mirrors(cmd, lv_mirr, source_pvl, lv,
|
||||
allocatable_pvs, *lvs_changed)) {
|
||||
stack;
|
||||
return NULL;
|
||||
@@ -222,8 +231,10 @@ static int _update_metadata(struct cmd_context *cmd, struct volume_group *vg,
|
||||
/* Only the first mirror segment gets activated as a mirror */
|
||||
if (first_time) {
|
||||
if (!activate_lv(cmd, lv_mirr->lvid.s)) {
|
||||
log_error("ABORTING: Temporary mirror activation "
|
||||
"failed. Run pvmove --abort.");
|
||||
if (!test_mode())
|
||||
log_error("ABORTING: Temporary mirror "
|
||||
"activation failed. "
|
||||
"Run pvmove --abort.");
|
||||
/* FIXME Resume using *original* metadata here! */
|
||||
resume_lvs(cmd, lvs_changed);
|
||||
return 0;
|
||||
@@ -248,13 +259,20 @@ static int _set_up_pvmove(struct cmd_context *cmd, const char *pv_name,
|
||||
int argc, char **argv)
|
||||
{
|
||||
const char *lv_name = NULL;
|
||||
char *pv_name_arg;
|
||||
struct volume_group *vg;
|
||||
struct list *source_pvl;
|
||||
struct list *allocatable_pvs;
|
||||
alloc_policy_t alloc;
|
||||
struct list *lvs_changed;
|
||||
struct physical_volume *pv;
|
||||
struct logical_volume *lv_mirr;
|
||||
int first_time = 1;
|
||||
|
||||
pv_name_arg = argv[0];
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
/* Find PV (in VG) */
|
||||
if (!(pv = find_pv_by_name(cmd, pv_name))) {
|
||||
stack;
|
||||
@@ -299,10 +317,22 @@ static int _set_up_pvmove(struct cmd_context *cmd, const char *pv_name,
|
||||
|
||||
first_time = 0;
|
||||
} else {
|
||||
/* Determine PE ranges to be moved */
|
||||
if (!(source_pvl = create_pv_list(cmd->mem, vg, 1,
|
||||
&pv_name_arg, 0))) {
|
||||
stack;
|
||||
unlock_vg(cmd, pv->vg_name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG,
|
||||
ALLOC_INHERIT);
|
||||
if (alloc == ALLOC_INHERIT)
|
||||
alloc = vg->alloc;
|
||||
|
||||
/* Get PVs we can use for allocation */
|
||||
if (!(allocatable_pvs = _get_allocatable_pvs(cmd, argc, argv,
|
||||
vg, pv))) {
|
||||
vg, pv, alloc))) {
|
||||
stack;
|
||||
unlock_vg(cmd, pv->vg_name);
|
||||
return ECMD_FAILED;
|
||||
@@ -314,8 +344,8 @@ static int _set_up_pvmove(struct cmd_context *cmd, const char *pv_name,
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!(lv_mirr = _set_up_pvmove_lv(cmd, vg, pv, lv_name,
|
||||
allocatable_pvs,
|
||||
if (!(lv_mirr = _set_up_pvmove_lv(cmd, vg, source_pvl, lv_name,
|
||||
allocatable_pvs, alloc,
|
||||
&lvs_changed))) {
|
||||
stack;
|
||||
unlock_vg(cmd, pv->vg_name);
|
||||
@@ -459,12 +489,21 @@ int pvmove_poll(struct cmd_context *cmd, const char *pv_name,
|
||||
int pvmove(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
char *pv_name = NULL;
|
||||
char *colon;
|
||||
int ret;
|
||||
|
||||
if (argc) {
|
||||
pv_name = argv[0];
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
/* Drop any PE lists from PV name */
|
||||
if ((colon = strchr(pv_name, ':'))) {
|
||||
if (!(pv_name = pool_strndup(cmd->mem, pv_name,
|
||||
(unsigned) (colon -
|
||||
pv_name)))) {
|
||||
log_error("Failed to clone PV name");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!arg_count(cmd, abort_ARG) &&
|
||||
(ret = _set_up_pvmove(cmd, pv_name, argc, argv)) !=
|
||||
@@ -472,6 +511,7 @@ int pvmove(struct cmd_context *cmd, int argc, char **argv)
|
||||
stack;
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return pvmove_poll(cmd, pv_name,
|
||||
|
@@ -81,7 +81,8 @@ static int pvremove_single(struct cmd_context *cmd, const char *pv_name,
|
||||
goto error;
|
||||
|
||||
if (!(dev = dev_cache_get(pv_name, cmd->filter))) {
|
||||
log_error("%s: Couldn't find device.", pv_name);
|
||||
log_error("%s: Couldn't find device. Check your filters?",
|
||||
pv_name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
23
tools/segtypes.c
Normal file
23
tools/segtypes.c
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2003-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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "tools.h"
|
||||
|
||||
int segtypes(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
display_segtypes(cmd);
|
||||
|
||||
return ECMD_PROCESSED;
|
||||
}
|
@@ -694,40 +694,40 @@ char *default_vgname(struct cmd_context *cmd)
|
||||
return pool_strdup(cmd->mem, vg_path);
|
||||
}
|
||||
|
||||
static int _add_alloc_area(struct pool *mem, struct list *alloc_areas,
|
||||
uint32_t start, uint32_t count)
|
||||
static int _add_pe_range(struct pool *mem, struct list *pe_ranges,
|
||||
uint32_t start, uint32_t count)
|
||||
{
|
||||
struct alloc_area *aa;
|
||||
struct pe_range *per;
|
||||
|
||||
log_debug("Adding alloc area: start PE %" PRIu32 " length %" PRIu32,
|
||||
log_debug("Adding PE range: start PE %" PRIu32 " length %" PRIu32,
|
||||
start, count);
|
||||
|
||||
/* Ensure no overlap with existing areas */
|
||||
list_iterate_items(aa, alloc_areas) {
|
||||
if (((start < aa->start) && (start + count - 1 >= aa->start)) ||
|
||||
((start >= aa->start) &&
|
||||
(aa->start + aa->count - 1) >= start)) {
|
||||
list_iterate_items(per, pe_ranges) {
|
||||
if (((start < per->start) && (start + count - 1 >= per->start))
|
||||
|| ((start >= per->start) &&
|
||||
(per->start + per->count - 1) >= start)) {
|
||||
log_error("Overlapping PE ranges detected (%" PRIu32
|
||||
"-%" PRIu32 ", %" PRIu32 "-%" PRIu32 ")",
|
||||
start, start + count - 1, aa->start,
|
||||
aa->start + aa->count - 1);
|
||||
start, start + count - 1, per->start,
|
||||
per->start + per->count - 1);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(aa = pool_alloc(mem, sizeof(*aa)))) {
|
||||
if (!(per = pool_alloc(mem, sizeof(*per)))) {
|
||||
log_error("Allocation of list failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
aa->start = start;
|
||||
aa->count = count;
|
||||
list_add(alloc_areas, &aa->list);
|
||||
per->start = start;
|
||||
per->count = count;
|
||||
list_add(pe_ranges, &per->list);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _parse_pes(struct pool *mem, char *c, struct list *alloc_areas,
|
||||
static int _parse_pes(struct pool *mem, char *c, struct list *pe_ranges,
|
||||
uint32_t size)
|
||||
{
|
||||
char *endptr;
|
||||
@@ -735,7 +735,7 @@ static int _parse_pes(struct pool *mem, char *c, struct list *alloc_areas,
|
||||
|
||||
/* Default to whole PV */
|
||||
if (!c) {
|
||||
if (!_add_alloc_area(mem, alloc_areas, UINT32_C(0), size)) {
|
||||
if (!_add_pe_range(mem, pe_ranges, UINT32_C(0), size)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -785,7 +785,7 @@ static int _parse_pes(struct pool *mem, char *c, struct list *alloc_areas,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_add_alloc_area(mem, alloc_areas, start, end - start + 1)) {
|
||||
if (!_add_pe_range(mem, pe_ranges, start, end - start + 1)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -800,19 +800,20 @@ static int _parse_pes(struct pool *mem, char *c, struct list *alloc_areas,
|
||||
}
|
||||
|
||||
static void _create_pv_entry(struct pool *mem, struct pv_list *pvl,
|
||||
char *colon, struct list *r)
|
||||
char *colon, int allocatable_only, struct list *r)
|
||||
{
|
||||
const char *pvname;
|
||||
struct pv_list *new_pvl;
|
||||
struct list *alloc_areas;
|
||||
struct list *pe_ranges;
|
||||
|
||||
pvname = dev_name(pvl->pv->dev);
|
||||
if (!(pvl->pv->status & ALLOCATABLE_PV)) {
|
||||
if (allocatable_only && !(pvl->pv->status & ALLOCATABLE_PV)) {
|
||||
log_error("Physical volume %s not allocatable", pvname);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pvl->pv->pe_count == pvl->pv->pe_alloc_count) {
|
||||
if (allocatable_only &&
|
||||
(pvl->pv->pe_count == pvl->pv->pe_alloc_count)) {
|
||||
log_err("No free extents on physical volume \"%s\"", pvname);
|
||||
return;
|
||||
}
|
||||
@@ -824,24 +825,24 @@ static void _create_pv_entry(struct pool *mem, struct pv_list *pvl,
|
||||
|
||||
memcpy(new_pvl, pvl, sizeof(*new_pvl));
|
||||
|
||||
if (!(alloc_areas = pool_alloc(mem, sizeof(*alloc_areas)))) {
|
||||
log_error("Allocation of alloc_areas list failed");
|
||||
if (!(pe_ranges = pool_alloc(mem, sizeof(*pe_ranges)))) {
|
||||
log_error("Allocation of pe_ranges list failed");
|
||||
return;
|
||||
}
|
||||
list_init(alloc_areas);
|
||||
list_init(pe_ranges);
|
||||
|
||||
/* Specify which physical extents may be used for allocation */
|
||||
if (!_parse_pes(mem, colon, alloc_areas, pvl->pv->pe_count)) {
|
||||
/* Determine selected physical extents */
|
||||
if (!_parse_pes(mem, colon, pe_ranges, pvl->pv->pe_count)) {
|
||||
stack;
|
||||
return;
|
||||
}
|
||||
new_pvl->alloc_areas = alloc_areas;
|
||||
new_pvl->pe_ranges = pe_ranges;
|
||||
|
||||
list_add(r, &new_pvl->list);
|
||||
}
|
||||
|
||||
struct list *create_pv_list(struct pool *mem,
|
||||
struct volume_group *vg, int argc, char **argv)
|
||||
struct list *create_pv_list(struct pool *mem, struct volume_group *vg, int argc,
|
||||
char **argv, int allocatable_only)
|
||||
{
|
||||
struct list *r;
|
||||
struct pv_list *pvl;
|
||||
@@ -870,7 +871,8 @@ struct list *create_pv_list(struct pool *mem,
|
||||
list_iterate_items(pvl, &vg->pvs) {
|
||||
if (str_list_match_item(&pvl->pv->tags,
|
||||
tagname)) {
|
||||
_create_pv_entry(mem, pvl, NULL, r);
|
||||
_create_pv_entry(mem, pvl, NULL,
|
||||
allocatable_only, r);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
@@ -892,7 +894,7 @@ struct list *create_pv_list(struct pool *mem,
|
||||
"Volume Group \"%s\"", pvname, vg->name);
|
||||
return NULL;
|
||||
}
|
||||
_create_pv_entry(mem, pvl, colon, r);
|
||||
_create_pv_entry(mem, pvl, colon, allocatable_only, r);
|
||||
}
|
||||
|
||||
if (list_empty(r))
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user