mirror of
git://sourceware.org/git/lvm2.git
synced 2025-11-10 08:23:48 +03:00
Compare commits
121 Commits
old-dm_v1_
...
v2_00_25
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6a98f60e2e | ||
|
|
6f2e24c47d | ||
|
|
aafa368923 | ||
|
|
eb783cab4c | ||
|
|
6533aa865a | ||
|
|
f1a1e1bc07 | ||
|
|
953f4838dd | ||
|
|
130b892d34 | ||
|
|
6ad525c77e | ||
|
|
d0ca74ad27 | ||
|
|
9806f69b4d | ||
|
|
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 | ||
|
|
02bd59827c | ||
|
|
4991428510 | ||
|
|
3b245f5dc1 | ||
|
|
c9c81da901 | ||
|
|
4919cdc3fb | ||
|
|
e90e1f577d | ||
|
|
afd4284403 | ||
|
|
150b350d31 | ||
|
|
2818520bd1 | ||
|
|
2819952292 | ||
|
|
5af71af51c | ||
|
|
07a55b51df | ||
|
|
66dd68b49d | ||
|
|
9812657777 | ||
|
|
0b09312fc6 | ||
|
|
d0a7ac6b74 | ||
|
|
ff9a238fbd | ||
|
|
359fffa5f1 | ||
|
|
5bf92ced1a | ||
|
|
340bcc7b45 | ||
|
|
ef03742bd4 | ||
|
|
20431ec16d | ||
|
|
becba8157b | ||
|
|
51fd3bb0eb | ||
|
|
4bbd3acb4e | ||
|
|
3bc930ea7b | ||
|
|
d1b26f8e86 | ||
|
|
fdf15caaff | ||
|
|
c7b4a53c0b | ||
|
|
af78dc0308 | ||
|
|
5ad39493c4 | ||
|
|
61f597b408 | ||
|
|
2162825240 | ||
|
|
2b780e70d1 | ||
|
|
a3823f818e | ||
|
|
1f7c47bcaf | ||
|
|
ec53c365a2 | ||
|
|
793ad1f2d4 | ||
|
|
9bc733b76c | ||
|
|
21b28f0217 | ||
|
|
d3e23caa52 | ||
|
|
9e7518de67 | ||
|
|
679f0047aa | ||
|
|
d77d5ce14b | ||
|
|
33ec22a2af | ||
|
|
353053225f | ||
|
|
b7f3d6f7f7 | ||
|
|
e34577499d | ||
|
|
4cf8960c0c | ||
|
|
1f93ea0675 | ||
|
|
25b705c3a8 | ||
|
|
0725588731 | ||
|
|
fc5c61cc8b | ||
|
|
ac282e63c6 | ||
|
|
c3941941ce | ||
|
|
46cdd53323 | ||
|
|
3ff3e302c3 |
15
Makefile.in
15
Makefile.in
@@ -22,24 +22,31 @@ ifeq ("@INTL@", "yes")
|
|||||||
SUBDIRS += po
|
SUBDIRS += po
|
||||||
endif
|
endif
|
||||||
|
|
||||||
SUBDIRS += lib tools
|
SUBDIRS += lib tools daemons
|
||||||
|
|
||||||
ifeq ($(MAKECMDGOALS),distclean)
|
ifeq ($(MAKECMDGOALS),distclean)
|
||||||
SUBDIRS += lib/format1 \
|
SUBDIRS += daemons/clvmd \
|
||||||
|
lib/format1 \
|
||||||
|
lib/format_pool \
|
||||||
|
lib/locking \
|
||||||
|
lib/mirror \
|
||||||
|
lib/snapshot \
|
||||||
po \
|
po \
|
||||||
test/mm test/device test/format1 test/regex test/filters
|
test/mm test/device test/format1 test/regex test/filters
|
||||||
endif
|
endif
|
||||||
|
|
||||||
include make.tmpl
|
include make.tmpl
|
||||||
|
|
||||||
|
daemons: lib
|
||||||
lib: include
|
lib: include
|
||||||
tools: lib
|
tools: lib
|
||||||
po: lib tools
|
po: tools daemons
|
||||||
|
|
||||||
ifeq ("@INTL@", "yes")
|
ifeq ("@INTL@", "yes")
|
||||||
lib.pofile: include.pofile
|
lib.pofile: include.pofile
|
||||||
tools.pofile: lib.pofile
|
tools.pofile: lib.pofile
|
||||||
po.pofile: lib.pofile tools.pofile
|
daemons.pofile: lib.pofile
|
||||||
|
po.pofile: tools.pofile daemons.pofile
|
||||||
pofile: po.pofile
|
pofile: po.pofile
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|||||||
4
README
4
README
@@ -9,8 +9,8 @@ Installation instructions are in INSTALL.
|
|||||||
There is no warranty - see COPYING and COPYING.LIB.
|
There is no warranty - see COPYING and COPYING.LIB.
|
||||||
|
|
||||||
Tarballs are available from:
|
Tarballs are available from:
|
||||||
ftp://ftp.sistina.com/pub/LVM2/tools/
|
ftp://sources.redhat.com/pub/lvm2/
|
||||||
ftp://ftp.sistina.com/pub/LVM2/device-mapper/
|
ftp://sources.redhat.com/pub/dm/
|
||||||
|
|
||||||
To access the CVS tree use:
|
To access the CVS tree use:
|
||||||
cvs -d :pserver:cvs@sources.redhat.com:/cvs/lvm2 login
|
cvs -d :pserver:cvs@sources.redhat.com:/cvs/lvm2 login
|
||||||
|
|||||||
125
WHATS_NEW
125
WHATS_NEW
@@ -1,3 +1,128 @@
|
|||||||
|
Version 2.00.25 - 29th September 2004
|
||||||
|
=====================================
|
||||||
|
Fix return code from rm_link for vgmknodes.
|
||||||
|
Make clvmd LV hash table thread-safe.
|
||||||
|
Fix clvmd locking so it will lock out multiple users on the same node.
|
||||||
|
Fix clvmd VG locking to it can cope with multiple VG locks.
|
||||||
|
Remove spurious trailing dot in lvreduce man page.
|
||||||
|
Fix vgremove locking.
|
||||||
|
|
||||||
|
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.
|
||||||
|
Display all filtered devices, not just PVs, with pvs -a.
|
||||||
|
Fix sync_dir() when no / in filename
|
||||||
|
vgcfgbackup -f accepts template with %s for VG name.
|
||||||
|
Extend hash functions to handle non-null-terminated data.
|
||||||
|
Add local activation support.
|
||||||
|
Tidy relative paths in makefile includes.
|
||||||
|
fsadm support for fsck and resizing - needs testing.
|
||||||
|
Add read-only GFS pool support.
|
||||||
|
Add lvm2create_initrd script from http://poochiereds.net/svn/lvm2/
|
||||||
|
Fix rounding of large diplayed sizes.
|
||||||
|
Suppress decimal point when using units of sectors/bytes.
|
||||||
|
Additional kernel target checks before pvmove & snapshot creation.
|
||||||
|
Add i2o_block.
|
||||||
|
|
||||||
|
Version 2.00.16 - 24 May 2004
|
||||||
|
=============================
|
||||||
|
Set area_count within alloc_lv_segment.
|
||||||
|
Remove error labels from lvresize.
|
||||||
|
Fix a pvs error path.
|
||||||
|
xxchange -ae for exclusive activation.
|
||||||
|
Don't return non-zero status if there aren't any volume groups.
|
||||||
|
Add --alloc argument to tools.
|
||||||
|
Rename allocation policies to contiguous, normal, anywhere, inherit.
|
||||||
|
nextfree becomes normal; anywhere isn't implemented yet.
|
||||||
|
LV inherits allocation policy from VG. Defaults: LV - inherit; VG - normal
|
||||||
|
Additional status character added to vgs to indicate allocation policy.
|
||||||
|
Add reset_fn to external_locking.
|
||||||
|
Ensure presence of virtual targets before attempting activating.
|
||||||
|
Attempt to fix resizing of snapshot origins.
|
||||||
|
Restructure lvresize, bringing it closer to lvcreate.
|
||||||
|
A quick sanity check on vg_disk struct when read in. More checks needed.
|
||||||
|
Only include visible LVs in active/open counts.
|
||||||
|
Add virtual segment types, zero and error. A large sparse device can be
|
||||||
|
constructed as a writeable snapshot of a large zero segment.
|
||||||
|
Add --type to lvcreate/resize.
|
||||||
|
Push lv_create & alloc policy up to tool level.
|
||||||
|
Fix pvdisplay return code.
|
||||||
|
Detect invalid LV names in arg lists.
|
||||||
|
Reporting uses line-at-a-time output.
|
||||||
|
lvm2 format sets unlimited_vols format flag.
|
||||||
|
Internal-only metadata flag support.
|
||||||
|
Basic checking for presence of device-mapper targets.
|
||||||
|
Separate out polldaemon.
|
||||||
|
Revise internal locking semantics.
|
||||||
|
Move find_pv_by_name to library.
|
||||||
|
Rename move->copy.
|
||||||
|
Add devices to segments report.
|
||||||
|
Begin separating out segment code. There's a lot of change here.
|
||||||
|
Compress any (obsolete) long LVM1 pvids encountered.
|
||||||
|
Support for tagged config files.
|
||||||
|
Don't abort operations if selinux present but disabled.
|
||||||
|
Fix typo in configure which left HAVE_LIBDL unset.
|
||||||
|
|
||||||
Version 2.00.15 - 19 Apr 2004
|
Version 2.00.15 - 19 Apr 2004
|
||||||
=============================
|
=============================
|
||||||
configure --with-owner= --with-group= to avoid -o and -g args to 'install'
|
configure --with-owner= --with-group= to avoid -o and -g args to 'install'
|
||||||
|
|||||||
16
WHATS_NEW_DM
16
WHATS_NEW_DM
@@ -1,3 +1,19 @@
|
|||||||
|
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.
|
||||||
|
Fix a targets string size calc in driver.
|
||||||
|
Add -c to dmsetup for column-based output.
|
||||||
|
Add target message-passing ioctl.
|
||||||
|
|
||||||
Version 1.00.17 - 17 Apr 2004
|
Version 1.00.17 - 17 Apr 2004
|
||||||
=============================
|
=============================
|
||||||
configure --with-owner= --with-group= to avoid -o and -g args to 'install'
|
configure --with-owner= --with-group= to avoid -o and -g args to 'install'
|
||||||
|
|||||||
465
configure.in
465
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.
|
## This file is part of the LVM2.
|
||||||
## There is no warranty for this software. See the file COPYING for
|
|
||||||
## details.
|
|
||||||
##
|
##
|
||||||
## 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:
|
## You should have received a copy of the GNU General Public License
|
||||||
## AJ Lewis <lewis@sistina.com>
|
## along with this program; if not, write to the Free Software Foundation,
|
||||||
##
|
## Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
## 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.
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
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)
|
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)
|
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_AWK
|
||||||
AC_PROG_CC
|
AC_PROG_CC
|
||||||
AC_PROG_INSTALL
|
AC_PROG_INSTALL
|
||||||
@@ -31,158 +66,304 @@ AC_PROG_LN_S
|
|||||||
AC_PROG_MAKE_SET
|
AC_PROG_MAKE_SET
|
||||||
AC_PROG_RANLIB
|
AC_PROG_RANLIB
|
||||||
|
|
||||||
dnl Checks for header files.
|
################################################################################
|
||||||
|
dnl -- Checks for header files.
|
||||||
AC_HEADER_DIRENT
|
AC_HEADER_DIRENT
|
||||||
AC_HEADER_STDC
|
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_CONST
|
||||||
AC_C_INLINE
|
AC_C_INLINE
|
||||||
AC_TYPE_OFF_T
|
AC_TYPE_OFF_T
|
||||||
AC_TYPE_PID_T
|
AC_TYPE_PID_T
|
||||||
AC_TYPE_SIZE_T
|
AC_TYPE_SIZE_T
|
||||||
|
AC_TYPE_MODE_T
|
||||||
AC_STRUCT_ST_RDEV
|
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*)
|
dnl -- Prefix is /usr by default, the exec_prefix default is setup later
|
||||||
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 ;;
|
|
||||||
darwin*)
|
|
||||||
CFLAGS="-no-cpp-precomp -fno-common"
|
|
||||||
CLDFLAGS=
|
|
||||||
CLDWHOLEARCHIVE="-all_load"
|
|
||||||
CLDNOWHOLEARCHIVE=
|
|
||||||
LD_DEPS=
|
|
||||||
LD_FLAGS=
|
|
||||||
SOFLAG="-dynamiclib"
|
|
||||||
DEVMAPPER=no
|
|
||||||
ODIRECT=no ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
dnl -- prefix is /usr by default, the exec_prefix default is setup later
|
|
||||||
AC_PREFIX_DEFAULT(/usr)
|
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,
|
AC_ARG_WITH(user,
|
||||||
[ --with-user=USER Set the owner of installed files ],
|
[ --with-user=USER Set the owner of installed files ],
|
||||||
[ OWNER="$withval" ])
|
[ OWNER="$withval" ])
|
||||||
|
AC_MSG_RESULT($OWNER)
|
||||||
|
|
||||||
if test x$OWNER != x; then
|
if test x$OWNER != x; then
|
||||||
OWNER="-o $OWNER"
|
OWNER="-o $OWNER"
|
||||||
fi
|
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,
|
AC_ARG_WITH(group,
|
||||||
[ --with-group=GROUP Set the group owner of installed files ],
|
[ --with-group=GROUP Set the group owner of installed files ],
|
||||||
[ GROUP="$withval" ])
|
[ GROUP="$withval" ])
|
||||||
|
AC_MSG_RESULT($GROUP)
|
||||||
|
|
||||||
if test x$GROUP != x; then
|
if test x$GROUP != x; then
|
||||||
GROUP="-g $GROUP"
|
GROUP="-g $GROUP"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
################################################################################
|
||||||
dnl -- LVM1 tool fallback option
|
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
|
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)
|
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
|
if test x$LVM1_FALLBACK = xyes; then
|
||||||
CFLAGS="$CFLAGS -DLVM1_FALLBACK"
|
CFLAGS="$CFLAGS -DLVM1_FALLBACK"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
################################################################################
|
||||||
dnl -- format1 inclusion type
|
dnl -- format1 inclusion type
|
||||||
|
AC_MSG_CHECKING(whether to include support for lvm1 metadata)
|
||||||
AC_ARG_WITH(lvm1,
|
AC_ARG_WITH(lvm1,
|
||||||
[ --with-lvm1=TYPE LVM1 metadata support: internal/shared/none
|
[ --with-lvm1=TYPE LVM1 metadata support: internal/shared/none
|
||||||
[TYPE=internal] ],
|
[TYPE=internal] ],
|
||||||
[ LVM1="$withval" ],
|
[ LVM1="$withval" ],
|
||||||
[ LVM1="internal" ])
|
[ LVM1="internal" ])
|
||||||
|
AC_MSG_RESULT($LVM1)
|
||||||
|
|
||||||
if [[ "x$LVM1" != xnone -a "x$LVM1" != xinternal -a "x$LVM1" != xshared ]];
|
if [[ "x$LVM1" != xnone -a "x$LVM1" != xinternal -a "x$LVM1" != xshared ]];
|
||||||
then AC_MSG_ERROR(
|
then AC_MSG_ERROR(
|
||||||
--with-lvm1 parameter invalid
|
--with-lvm1 parameter invalid
|
||||||
)
|
)
|
||||||
exit
|
|
||||||
fi;
|
fi;
|
||||||
|
|
||||||
if test x$LVM1 = xinternal; then
|
if test x$LVM1 = xinternal; then
|
||||||
CFLAGS="$CFLAGS -DLVM1_INTERNAL"
|
CFLAGS="$CFLAGS -DLVM1_INTERNAL"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
AC_ARG_ENABLE(jobs, [ --enable-jobs=NUM Number of jobs to run simultaneously], JOBS=-j$enableval, JOBS=-j2)
|
################################################################################
|
||||||
|
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)
|
||||||
|
|
||||||
dnl Enables staticly-linked tools
|
if [[ "x$POOL" != xnone -a "x$POOL" != xinternal -a "x$POOL" != xshared ]];
|
||||||
|
then AC_MSG_ERROR(
|
||||||
|
--with-pool parameter invalid
|
||||||
|
)
|
||||||
|
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)
|
||||||
|
|
||||||
|
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
|
||||||
|
)
|
||||||
|
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
|
||||||
|
)
|
||||||
|
fi;
|
||||||
|
|
||||||
|
if test x$MIRRORS = xinternal; then
|
||||||
|
CFLAGS="$CFLAGS -DMIRRORED_INTERNAL"
|
||||||
|
fi
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
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
|
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)
|
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)
|
READLINE=$enableval, READLINE=no)
|
||||||
|
AC_MSG_RESULT($READLINE)
|
||||||
|
|
||||||
if test x$READLINE = xyes; then
|
if test x$READLINE = xyes; then
|
||||||
CFLAGS="$CFLAGS -DREADLINE_SUPPORT"
|
CFLAGS="$CFLAGS -DREADLINE_SUPPORT"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo $ac_n "checking whether to enable debugging""... $ac_c" 1>&6
|
################################################################################
|
||||||
dnl Enable Debugging
|
dnl -- Disable selinux
|
||||||
AC_ARG_ENABLE(debug, [ --enable-debug Enable debugging], \
|
AC_MSG_CHECKING(whether to enable selinux support)
|
||||||
DEBUG=yes, DEBUG=no)
|
AC_ARG_ENABLE(selinux, [ --disable-selinux Disable selinux support],
|
||||||
echo "$ac_t""$DEBUG" 1>&6
|
SELINUX=$enableval)
|
||||||
|
AC_MSG_RESULT($SELINUX)
|
||||||
|
|
||||||
echo $ac_n "checking whether to enable device-mapper""... $ac_c" 1>&6
|
################################################################################
|
||||||
dnl Disable devmapper
|
dnl -- Build cluster LVM daemon
|
||||||
AC_ARG_ENABLE(devmapper, [ --disable-devmapper Disable device-mapper interaction], \
|
AC_MSG_CHECKING(whether to build cluster LVM daemon)
|
||||||
DEVMAPPER=no)
|
AC_ARG_WITH(clvmd, [ --with-clvmd Build cluster LVM Daemon],
|
||||||
echo "$ac_t""$DEVMAPPER" 1>&6
|
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
|
if test x$DEVMAPPER = xyes; then
|
||||||
CFLAGS="$CFLAGS -DDEVMAPPER_SUPPORT"
|
CFLAGS="$CFLAGS -DDEVMAPPER_SUPPORT"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo $ac_n "checking whether to enable O_DIRECT""... $ac_c" 1>&6
|
################################################################################
|
||||||
dnl Disable O_DIRECT
|
dnl -- Disable O_DIRECT
|
||||||
AC_ARG_ENABLE(o_direct, [ --disable-o_direct Disable O_DIRECT], \
|
AC_MSG_CHECKING(whether to enable O_DIRECT)
|
||||||
ODIRECT=no)
|
AC_ARG_ENABLE(o_direct, [ --disable-o_direct Disable O_DIRECT],
|
||||||
echo "$ac_t""$ODIRECT" 1>&6
|
ODIRECT=$enableval)
|
||||||
|
AC_MSG_RESULT($ODIRECT)
|
||||||
|
|
||||||
if test x$ODIRECT = xyes; then
|
if test x$ODIRECT = xyes; then
|
||||||
CFLAGS="$CFLAGS -DO_DIRECT_SUPPORT"
|
CFLAGS="$CFLAGS -DO_DIRECT_SUPPORT"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo $ac_n "checking whether to compile liblvm2cmd.so""... $ac_c" 1>&6
|
################################################################################
|
||||||
dnl Enable cmdlib
|
dnl -- Enable cmdlib
|
||||||
AC_ARG_ENABLE(cmdlib, [ --enable-cmdlib Build shared command library], \
|
AC_MSG_CHECKING(whether to compile liblvm2cmd.so)
|
||||||
CMDLIB=yes, CMDLIB=no)
|
AC_ARG_ENABLE(cmdlib, [ --enable-cmdlib Build shared command library],
|
||||||
echo "$ac_t""$CMDLIB" 1>&6
|
CMDLIB=$enableval, CMDLIB=no)
|
||||||
|
AC_MSG_RESULT($CMDLIB)
|
||||||
|
|
||||||
if test x$CMDLIB = xyes; then
|
if test x$CMDLIB = xyes; then
|
||||||
CFLAGS="$CFLAGS -DCMDLIB"
|
CFLAGS="$CFLAGS -DCMDLIB"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
dnl Mess with default exec_prefix
|
################################################################################
|
||||||
|
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
|
||||||
if [[ "x$exec_prefix" = xNONE -a "x$prefix" = xNONE ]];
|
if [[ "x$exec_prefix" = xNONE -a "x$prefix" = xNONE ]];
|
||||||
then exec_prefix="";
|
then exec_prefix="";
|
||||||
fi;
|
fi;
|
||||||
|
|
||||||
dnl Checks for library functions.
|
################################################################################
|
||||||
|
dnl -- Checks for library functions.
|
||||||
AC_PROG_GCC_TRADITIONAL
|
AC_PROG_GCC_TRADITIONAL
|
||||||
AC_TYPE_SIGNAL
|
AC_TYPE_SIGNAL
|
||||||
AC_FUNC_VPRINTF
|
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
|
if test x$READLINE = xyes; then
|
||||||
AC_SEARCH_LIBS(tgetent, ncurses curses termcap termlib, ,
|
AC_SEARCH_LIBS(tgetent, ncurses curses termcap termlib, ,
|
||||||
AC_MSG_ERROR(
|
AC_MSG_ERROR(
|
||||||
@@ -195,40 +376,51 @@ 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
|
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.
|
not found either - but you could try installing that as well.
|
||||||
)
|
)
|
||||||
exit
|
|
||||||
)
|
)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
dnl Check for dlopen
|
################################################################################
|
||||||
|
dnl -- Check for dlopen
|
||||||
AC_CHECK_LIB(dl, dlopen, HAVE_LIBDL=yes, HAVE_LIBDL=no)
|
AC_CHECK_LIB(dl, dlopen, HAVE_LIBDL=yes, HAVE_LIBDL=no)
|
||||||
|
|
||||||
if [[ "x$HAVE_LIBDL" = xyes -a "xSTATIC_LINK" = xno ]]; then
|
if [[ "x$HAVE_LIBDL" = xyes -a "x$STATIC_LINK" = xno ]]; then
|
||||||
CFLAGS="$CFLAGS -DHAVE_LIBDL"
|
CFLAGS="$CFLAGS -DHAVE_LIBDL"
|
||||||
LIBS="-ldl $LIBS"
|
LIBS="-ldl $LIBS"
|
||||||
else
|
else
|
||||||
HAVE_LIBDL=no
|
HAVE_LIBDL=no
|
||||||
fi
|
fi
|
||||||
|
|
||||||
dnl Check for shared/static conflicts
|
################################################################################
|
||||||
if [[ "x$LVM1" = xshared -a "x$STATIC_LINK" = xyes ]];
|
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(
|
then AC_MSG_ERROR(
|
||||||
Features cannot be 'shared' when building statically
|
Features cannot be 'shared' when building statically
|
||||||
)
|
)
|
||||||
exit
|
|
||||||
fi
|
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
|
if test x$HAVE_SELINUX = xyes; then
|
||||||
CFLAGS="$CFLAGS -DHAVE_SELINUX"
|
CFLAGS="$CFLAGS -DHAVE_SELINUX"
|
||||||
LIBS="-lselinux $LIBS"
|
LIBS="-lselinux $LIBS"
|
||||||
|
else
|
||||||
|
AC_MSG_WARN(Disabling selinux)
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
dnl Check for getopt
|
################################################################################
|
||||||
|
dnl -- Check for getopt
|
||||||
AC_CHECK_HEADERS(getopt.h, CFLAGS="$CFLAGS -DHAVE_GETOPTLONG")
|
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
|
if test x$READLINE = xyes; then
|
||||||
AC_CHECK_LIB(readline, readline, ,
|
AC_CHECK_LIB(readline, readline, ,
|
||||||
AC_MSG_ERROR(
|
AC_MSG_ERROR(
|
||||||
@@ -239,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
|
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).
|
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")
|
AC_CHECK_FUNC(rl_completion_matches, CFLAGS="$CFLAGS -DHAVE_RL_COMPLETION_MATCHES")
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo $ac_n "checking whether to enable internationalisation""... $ac_c" 1>&6
|
################################################################################
|
||||||
dnl Internationalisation stuff
|
dnl -- Internationalisation stuff
|
||||||
AC_ARG_ENABLE(nls, [ --enable-nls Enable Native Language Support],\
|
AC_MSG_CHECKING(whether to enable internationalisation)
|
||||||
INTL=yes, INTL=no)
|
AC_ARG_ENABLE(nls, [ --enable-nls Enable Native Language Support],
|
||||||
echo "$ac_t""$INTL" 1>&6
|
INTL=$enableval, INTL=no)
|
||||||
|
AC_MSG_RESULT($INTL)
|
||||||
|
|
||||||
if test x$INTL = xyes; then
|
if test x$INTL = xyes; then
|
||||||
INTL_PACKAGE="lvm2"
|
INTL_PACKAGE="lvm2"
|
||||||
@@ -258,7 +450,6 @@ if test x$INTL = xyes; then
|
|||||||
then AC_MSG_ERROR(
|
then AC_MSG_ERROR(
|
||||||
msgfmt not found in path $PATH
|
msgfmt not found in path $PATH
|
||||||
)
|
)
|
||||||
exit
|
|
||||||
fi;
|
fi;
|
||||||
|
|
||||||
AC_ARG_WITH(localedir,
|
AC_ARG_WITH(localedir,
|
||||||
@@ -267,6 +458,7 @@ if test x$INTL = xyes; then
|
|||||||
[ LOCALEDIR='${prefix}/share/locale' ])
|
[ LOCALEDIR='${prefix}/share/locale' ])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
################################################################################
|
||||||
AC_ARG_WITH(confdir,
|
AC_ARG_WITH(confdir,
|
||||||
[ --with-confdir=DIR Configuration files in DIR [/etc]],
|
[ --with-confdir=DIR Configuration files in DIR [/etc]],
|
||||||
[ CONFDIR="$withval" ],
|
[ CONFDIR="$withval" ],
|
||||||
@@ -277,24 +469,69 @@ AC_ARG_WITH(staticdir,
|
|||||||
[ STATICDIR="$withval" ],
|
[ STATICDIR="$withval" ],
|
||||||
[ STATICDIR='${exec_prefix}/sbin' ])
|
[ 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
|
if test "-f VERSION"; then
|
||||||
LVM_VERSION="\"`cat VERSION`\""
|
LVM_VERSION="\"`cat VERSION`\""
|
||||||
else
|
else
|
||||||
LVM_VERSION="Unknown"
|
LVM_VERSION="Unknown"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
################################################################################
|
||||||
AC_SUBST(JOBS)
|
AC_SUBST(JOBS)
|
||||||
AC_SUBST(STATIC_LINK)
|
AC_SUBST(STATIC_LINK)
|
||||||
AC_SUBST(LVM1)
|
AC_SUBST(LVM1)
|
||||||
|
AC_SUBST(POOL)
|
||||||
|
AC_SUBST(SNAPSHOTS)
|
||||||
|
AC_SUBST(MIRRORS)
|
||||||
AC_SUBST(OWNER)
|
AC_SUBST(OWNER)
|
||||||
AC_SUBST(GROUP)
|
AC_SUBST(GROUP)
|
||||||
AC_SUBST(CFLAGS)
|
AC_SUBST(CFLAGS)
|
||||||
|
AC_SUBST(COPTIMISE_FLAG)
|
||||||
AC_SUBST(CLDFLAGS)
|
AC_SUBST(CLDFLAGS)
|
||||||
AC_SUBST(CLDWHOLEARCHIVE)
|
AC_SUBST(CLDWHOLEARCHIVE)
|
||||||
AC_SUBST(CLDNOWHOLEARCHIVE)
|
AC_SUBST(CLDNOWHOLEARCHIVE)
|
||||||
AC_SUBST(LD_DEPS)
|
AC_SUBST(LDDEPS)
|
||||||
AC_SUBST(LD_FLAGS)
|
AC_SUBST(LDFLAGS)
|
||||||
AC_SUBST(SOFLAG)
|
AC_SUBST(SOFLAG)
|
||||||
AC_SUBST(LIBS)
|
AC_SUBST(LIBS)
|
||||||
AC_SUBST(LVM_VERSION)
|
AC_SUBST(LVM_VERSION)
|
||||||
@@ -310,20 +547,31 @@ AC_SUBST(CONFDIR)
|
|||||||
AC_SUBST(STATICDIR)
|
AC_SUBST(STATICDIR)
|
||||||
AC_SUBST(INTL_PACKAGE)
|
AC_SUBST(INTL_PACKAGE)
|
||||||
AC_SUBST(INTL)
|
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( \
|
AC_OUTPUT( \
|
||||||
Makefile \
|
Makefile \
|
||||||
make.tmpl \
|
make.tmpl \
|
||||||
|
daemons/Makefile \
|
||||||
|
daemons/clvmd/Makefile \
|
||||||
doc/Makefile \
|
doc/Makefile \
|
||||||
include/Makefile \
|
include/Makefile \
|
||||||
lib/Makefile \
|
lib/Makefile \
|
||||||
lib/format1/Makefile \
|
lib/format1/Makefile \
|
||||||
|
lib/format_pool/Makefile \
|
||||||
|
lib/locking/Makefile \
|
||||||
|
lib/mirror/Makefile \
|
||||||
|
lib/snapshot/Makefile \
|
||||||
man/Makefile \
|
man/Makefile \
|
||||||
po/Makefile \
|
po/Makefile \
|
||||||
tools/Makefile \
|
tools/Makefile \
|
||||||
tools/version.h \
|
tools/version.h \
|
||||||
|
tools/fsadm/Makefile \
|
||||||
test/mm/Makefile \
|
test/mm/Makefile \
|
||||||
test/device/Makefile \
|
test/device/Makefile \
|
||||||
test/format1/Makefile \
|
test/format1/Makefile \
|
||||||
@@ -332,8 +580,9 @@ test/filters/Makefile \
|
|||||||
)
|
)
|
||||||
|
|
||||||
if test x$ODIRECT != xyes; then
|
if test x$ODIRECT != xyes; then
|
||||||
echo
|
AC_MSG_WARN(Warning: O_DIRECT disabled: low-memory pvmove may lock up)
|
||||||
echo Warning: O_DIRECT disabled.
|
fi
|
||||||
echo Use of pvmove may cause machine to lock up under low memory conditions.
|
|
||||||
echo
|
if test x$FSADM == xyes; then
|
||||||
|
AC_MSG_WARN(fsadm support is untested)
|
||||||
fi
|
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
|
||||||
503
daemons/clvmd/clvmd-cman.c
Normal file
503
daemons/clvmd/clvmd-cman.c
Normal file
@@ -0,0 +1,503 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUGLOG("sync_lock: '%s' mode:%d flags=%d\n", resource,mode,flags);
|
||||||
|
/* Conversions need the lockid in the LKSB */
|
||||||
|
if (flags & LKF_CONVERT)
|
||||||
|
lwait.lksb.sb_lkid = *lockid;
|
||||||
|
|
||||||
|
pthread_cond_init(&lwait.cond, NULL);
|
||||||
|
pthread_mutex_init(&lwait.mutex, NULL);
|
||||||
|
pthread_mutex_lock(&lwait.mutex);
|
||||||
|
|
||||||
|
status = dlm_ls_lock(lockspace,
|
||||||
|
mode,
|
||||||
|
&lwait.lksb,
|
||||||
|
flags,
|
||||||
|
resource,
|
||||||
|
strlen(resource),
|
||||||
|
0, sync_ast_routine, &lwait, NULL, NULL);
|
||||||
|
if (status)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
/* Wait for it to complete */
|
||||||
|
pthread_cond_wait(&lwait.cond, &lwait.mutex);
|
||||||
|
pthread_mutex_unlock(&lwait.mutex);
|
||||||
|
|
||||||
|
*lockid = lwait.lksb.sb_lkid;
|
||||||
|
|
||||||
|
errno = lwait.lksb.sb_status;
|
||||||
|
DEBUGLOG("sync_lock: returning lkid %x\n", *lockid);
|
||||||
|
if (lwait.lksb.sb_status)
|
||||||
|
return -1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sync_unlock(const char *resource /* UNUSED */, int lockid)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
struct lock_wait lwait;
|
||||||
|
|
||||||
|
DEBUGLOG("sync_unlock: '%s' lkid:%x\n", resource, lockid);
|
||||||
|
|
||||||
|
pthread_cond_init(&lwait.cond, NULL);
|
||||||
|
pthread_mutex_init(&lwait.mutex, NULL);
|
||||||
|
pthread_mutex_lock(&lwait.mutex);
|
||||||
|
|
||||||
|
status = dlm_ls_unlock(lockspace, lockid, 0, &lwait.lksb, &lwait);
|
||||||
|
|
||||||
|
if (status)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
/* Wait for it to complete */
|
||||||
|
pthread_cond_wait(&lwait.cond, &lwait.mutex);
|
||||||
|
pthread_mutex_unlock(&lwait.mutex);
|
||||||
|
|
||||||
|
errno = lwait.lksb.sb_status;
|
||||||
|
if (lwait.lksb.sb_status != EUNLOCK)
|
||||||
|
return -1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
285
daemons/clvmd/clvmd-command.c
Normal file
285
daemons/clvmd/clvmd-command.c
Normal file
@@ -0,0 +1,285 @@
|
|||||||
|
/*
|
||||||
|
* 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 "hash.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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lock_vg(struct local_client *client)
|
||||||
|
{
|
||||||
|
struct hash_table *lock_hash;
|
||||||
|
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 lkid;
|
||||||
|
int status = 0;
|
||||||
|
char *lockname;
|
||||||
|
|
||||||
|
/* Keep a track of VG locks in our own hash table. In current
|
||||||
|
practice there should only ever be more than two VGs locked
|
||||||
|
if a user tries to merge lots of them at once */
|
||||||
|
if (client->bits.localsock.private) {
|
||||||
|
lock_hash = (struct hash_table *)client->bits.localsock.private;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lock_hash = hash_create(3);
|
||||||
|
if (!lock_hash)
|
||||||
|
return ENOMEM;
|
||||||
|
client->bits.localsock.private = (void *)lock_hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
lock_cmd = args[0];
|
||||||
|
lock_flags = args[1];
|
||||||
|
lockname = &args[2];
|
||||||
|
DEBUGLOG("doing PRE command LOCK_VG '%s' at %x (client=%p)\n", lockname, lock_cmd, client);
|
||||||
|
|
||||||
|
if (lock_cmd == LCK_UNLOCK) {
|
||||||
|
|
||||||
|
lkid = (int)(long)hash_lookup(lock_hash, lockname);
|
||||||
|
if (lkid == 0)
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
status = sync_unlock(lockname, lkid);
|
||||||
|
if (status)
|
||||||
|
status = errno;
|
||||||
|
else
|
||||||
|
hash_remove(lock_hash, lockname);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
status = sync_lock(lockname, (int)lock_cmd, (int)lock_flags, &lkid);
|
||||||
|
if (status)
|
||||||
|
status = errno;
|
||||||
|
else
|
||||||
|
hash_insert(lock_hash, lockname, (void *)lkid);
|
||||||
|
}
|
||||||
|
|
||||||
|
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:
|
||||||
|
status = lock_vg(client);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CLVMD_CMD_LOCK_LV:
|
||||||
|
lock_cmd = args[0];
|
||||||
|
lock_flags = args[1];
|
||||||
|
lockname = &args[2];
|
||||||
|
status = pre_lock_lv(lock_cmd, lock_flags, lockname);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
log_error("Unknown command %d received\n", header->cmd);
|
||||||
|
status = EINVAL;
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Note that the post-command routine is called even if the pre-command or the real command
|
||||||
|
failed */
|
||||||
|
int do_post_command(struct local_client *client)
|
||||||
|
{
|
||||||
|
struct clvm_header *header =
|
||||||
|
(struct clvm_header *) client->bits.localsock.cmd;
|
||||||
|
int status = 0;
|
||||||
|
unsigned char lock_cmd;
|
||||||
|
unsigned char lock_flags;
|
||||||
|
char *args = header->node + strlen(header->node) + 1;
|
||||||
|
char *lockname;
|
||||||
|
|
||||||
|
switch (header->cmd) {
|
||||||
|
case CLVMD_CMD_TEST:
|
||||||
|
status =
|
||||||
|
sync_unlock("CLVMD_TEST", (int) (long) client->bits.localsock.private);
|
||||||
|
client->bits.localsock.private = 0;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Called when the client is about to be deleted */
|
||||||
|
void cmd_client_cleanup(struct local_client *client)
|
||||||
|
{
|
||||||
|
if (client->bits.localsock.private) {
|
||||||
|
|
||||||
|
struct hash_node *v;
|
||||||
|
struct hash_table *lock_hash =
|
||||||
|
(struct hash_table *)client->bits.localsock.private;
|
||||||
|
|
||||||
|
hash_iterate(v, lock_hash) {
|
||||||
|
int lkid = (int)(long)hash_get_data(lock_hash, v);
|
||||||
|
|
||||||
|
DEBUGLOG("cleanup: Unlocking lkid %x\n", lkid);
|
||||||
|
sync_unlock("DUMMY", lkid);
|
||||||
|
}
|
||||||
|
|
||||||
|
hash_destroy(lock_hash);
|
||||||
|
client->bits.localsock.private = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
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);
|
||||||
1698
daemons/clvmd/clvmd.c
Normal file
1698
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 void cmd_client_cleanup(struct local_client *client);
|
||||||
|
extern int add_client(struct local_client *new_client);
|
||||||
|
|
||||||
|
extern void clvmd_cluster_init_completed(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
226
daemons/clvmd/cnxman-socket.h
Normal file
226
daemons/clvmd/cnxman-socket.h
Normal file
@@ -0,0 +1,226 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
*******************************************************************************
|
||||||
|
**
|
||||||
|
** 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 */
|
||||||
|
#define MSG_REPLYEXP 0x200000 /* Reply is expected */
|
||||||
|
|
||||||
|
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
|
||||||
461
daemons/clvmd/lvm-functions.c
Normal file
461
daemons/clvmd/lvm-functions.c
Normal file
@@ -0,0 +1,461 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
static pthread_mutex_t lv_hash_lock;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&lv_hash_lock);
|
||||||
|
lvi = hash_lookup(lv_hash, resource);
|
||||||
|
pthread_mutex_unlock(&lv_hash_lock);
|
||||||
|
if (lvi) {
|
||||||
|
return lvi->lock_mode;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called at shutdown to tidy the lockspace */
|
||||||
|
void unlock_all()
|
||||||
|
{
|
||||||
|
struct hash_node *v;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&lv_hash_lock);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&lv_hash_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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 */
|
||||||
|
|
||||||
|
pthread_mutex_lock(&lv_hash_lock);
|
||||||
|
lvi = hash_lookup(lv_hash, resource);
|
||||||
|
pthread_mutex_unlock(&lv_hash_lock);
|
||||||
|
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 {
|
||||||
|
pthread_mutex_lock(&lv_hash_lock);
|
||||||
|
hash_insert(lv_hash, resource, lvi);
|
||||||
|
pthread_mutex_unlock(&lv_hash_lock);
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&lv_hash_lock);
|
||||||
|
lvi = hash_lookup(lv_hash, resource);
|
||||||
|
pthread_mutex_unlock(&lv_hash_lock);
|
||||||
|
if (!lvi) {
|
||||||
|
DEBUGLOG("hold_unlock, lock not already held\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = sync_unlock(resource, lvi->lock_id);
|
||||||
|
saved_errno = errno;
|
||||||
|
if (!status) {
|
||||||
|
pthread_mutex_lock(&lv_hash_lock);
|
||||||
|
hash_remove(lv_hash, resource);
|
||||||
|
pthread_mutex_unlock(&lv_hash_lock);
|
||||||
|
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);
|
||||||
|
pthread_mutex_init(&lv_hash_lock, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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);
|
||||||
@@ -18,7 +18,7 @@ VPATH = @srcdir@
|
|||||||
CONFSRC=example.conf
|
CONFSRC=example.conf
|
||||||
CONFDEST=lvm.conf
|
CONFDEST=lvm.conf
|
||||||
|
|
||||||
include ../make.tmpl
|
include $(top_srcdir)/make.tmpl
|
||||||
|
|
||||||
install:
|
install:
|
||||||
@if [ ! -e $(confdir)/$(CONFDEST) ]; then \
|
@if [ ! -e $(confdir)/$(CONFDEST) ]; then \
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
|
../daemons/clvmd/clvm.h
|
||||||
../lib/activate/activate.h
|
../lib/activate/activate.h
|
||||||
|
../lib/activate/targets.h
|
||||||
../lib/cache/lvmcache.h
|
../lib/cache/lvmcache.h
|
||||||
../lib/commands/errors.h
|
../lib/commands/errors.h
|
||||||
../lib/commands/toolcontext.h
|
../lib/commands/toolcontext.h
|
||||||
@@ -20,12 +22,16 @@
|
|||||||
../lib/filters/filter-sysfs.h
|
../lib/filters/filter-sysfs.h
|
||||||
../lib/filters/filter.h
|
../lib/filters/filter.h
|
||||||
../lib/format1/format1.h
|
../lib/format1/format1.h
|
||||||
|
../lib/format_pool/format_pool.h
|
||||||
../lib/format_text/format-text.h
|
../lib/format_text/format-text.h
|
||||||
|
../lib/format_text/text_export.h
|
||||||
|
../lib/format_text/text_import.h
|
||||||
../lib/label/label.h
|
../lib/label/label.h
|
||||||
../lib/locking/locking.h
|
../lib/locking/locking.h
|
||||||
../lib/log/log.h
|
../lib/log/log.h
|
||||||
../lib/metadata/lv_alloc.h
|
../lib/metadata/lv_alloc.h
|
||||||
../lib/metadata/metadata.h
|
../lib/metadata/metadata.h
|
||||||
|
../lib/metadata/segtype.h
|
||||||
../lib/mm/dbg_malloc.h
|
../lib/mm/dbg_malloc.h
|
||||||
../lib/mm/memlock.h
|
../lib/mm/memlock.h
|
||||||
../lib/mm/pool.h
|
../lib/mm/pool.h
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ VPATH = @srcdir@
|
|||||||
|
|
||||||
LN_S = @LN_S@
|
LN_S = @LN_S@
|
||||||
|
|
||||||
|
.PHONY: clean distclean all install pofile install_cluster
|
||||||
|
|
||||||
all: .symlinks_created
|
all: .symlinks_created
|
||||||
|
|
||||||
.symlinks_created: .symlinks
|
.symlinks_created: .symlinks
|
||||||
@@ -37,5 +39,5 @@ clean:
|
|||||||
|
|
||||||
install:
|
install:
|
||||||
|
|
||||||
.PHONY: clean distclean all install pofile
|
install_cluster:
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,18 @@ ifeq ("@LVM1@", "shared")
|
|||||||
SUBDIRS = format1
|
SUBDIRS = format1
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ("@POOL@", "shared")
|
||||||
|
SUBDIRS += format_pool
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ("@SNAPSHOTS@", "shared")
|
||||||
|
SUBDIRS += snapshot
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ("@MIRRORS@", "shared")
|
||||||
|
SUBDIRS += mirror
|
||||||
|
endif
|
||||||
|
|
||||||
SOURCES =\
|
SOURCES =\
|
||||||
activate/activate.c \
|
activate/activate.c \
|
||||||
cache/lvmcache.c \
|
cache/lvmcache.c \
|
||||||
@@ -33,6 +45,7 @@ SOURCES =\
|
|||||||
device/dev-io.c \
|
device/dev-io.c \
|
||||||
device/device.c \
|
device/device.c \
|
||||||
display/display.c \
|
display/display.c \
|
||||||
|
error/errseg.c \
|
||||||
filters/filter-composite.c \
|
filters/filter-composite.c \
|
||||||
filters/filter-persistent.c \
|
filters/filter-persistent.c \
|
||||||
filters/filter-regex.c \
|
filters/filter-regex.c \
|
||||||
@@ -57,6 +70,7 @@ SOURCES =\
|
|||||||
metadata/metadata.c \
|
metadata/metadata.c \
|
||||||
metadata/mirror.c \
|
metadata/mirror.c \
|
||||||
metadata/pv_map.c \
|
metadata/pv_map.c \
|
||||||
|
metadata/segtype.c \
|
||||||
metadata/snapshot_manip.c \
|
metadata/snapshot_manip.c \
|
||||||
misc/crc.c \
|
misc/crc.c \
|
||||||
misc/lvm-file.c \
|
misc/lvm-file.c \
|
||||||
@@ -67,7 +81,9 @@ SOURCES =\
|
|||||||
regex/parse_rx.c \
|
regex/parse_rx.c \
|
||||||
regex/ttree.c \
|
regex/ttree.c \
|
||||||
report/report.c \
|
report/report.c \
|
||||||
uuid/uuid.c
|
striped/striped.c \
|
||||||
|
uuid/uuid.c \
|
||||||
|
zero/zero.c
|
||||||
|
|
||||||
ifeq ("@LVM1@", "internal")
|
ifeq ("@LVM1@", "internal")
|
||||||
SOURCES +=\
|
SOURCES +=\
|
||||||
@@ -80,6 +96,30 @@ ifeq ("@LVM1@", "internal")
|
|||||||
format1/vg_number.c
|
format1/vg_number.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ("@POOL@", "internal")
|
||||||
|
SOURCES +=\
|
||||||
|
format_pool/disk_rep.c \
|
||||||
|
format_pool/format_pool.c \
|
||||||
|
format_pool/import_export.c \
|
||||||
|
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
|
||||||
|
|
||||||
|
ifeq ("@MIRRORS@", "internal")
|
||||||
|
SOURCES += mirror/mirrored.c
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ("@DEBUG@", "yes")
|
ifeq ("@DEBUG@", "yes")
|
||||||
SOURCES += mm/dbg_malloc.c
|
SOURCES += mm/dbg_malloc.c
|
||||||
endif
|
endif
|
||||||
@@ -104,5 +144,5 @@ LIB_STATIC = liblvm.a
|
|||||||
|
|
||||||
$(SUBDIRS): $(LIB_STATIC)
|
$(SUBDIRS): $(LIB_STATIC)
|
||||||
|
|
||||||
include ../make.tmpl
|
include $(top_srcdir)/make.tmpl
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
#include "toolcontext.h"
|
#include "toolcontext.h"
|
||||||
#include "dev_manager.h"
|
#include "dev_manager.h"
|
||||||
#include "str_list.h"
|
#include "str_list.h"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@@ -173,13 +174,13 @@ int activation(void)
|
|||||||
static int _passes_activation_filter(struct cmd_context *cmd,
|
static int _passes_activation_filter(struct cmd_context *cmd,
|
||||||
struct logical_volume *lv)
|
struct logical_volume *lv)
|
||||||
{
|
{
|
||||||
struct config_node *cn;
|
const struct config_node *cn;
|
||||||
struct config_value *cv;
|
struct config_value *cv;
|
||||||
char *str;
|
char *str;
|
||||||
char path[PATH_MAX];
|
char path[PATH_MAX];
|
||||||
|
|
||||||
if (!(cn = find_config_node(cmd->cft->root, "activation/volume_list"))) {
|
if (!(cn = find_config_node(cmd->cft->root, "activation/volume_list"))) {
|
||||||
/* If no hosts tags defined, activate */
|
/* If no host tags defined, activate */
|
||||||
if (list_empty(&cmd->tags))
|
if (list_empty(&cmd->tags))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
@@ -341,7 +342,7 @@ static int _lv_info(const struct logical_volume *lv, int mknodes,
|
|||||||
if (!activation())
|
if (!activation())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cft))) {
|
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name))) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -387,7 +388,7 @@ int lv_snapshot_percent(struct logical_volume *lv, float *percent)
|
|||||||
if (!activation())
|
if (!activation())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cft))) {
|
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name))) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -419,7 +420,7 @@ int lv_mirror_percent(struct logical_volume *lv, int wait, float *percent,
|
|||||||
if (!info.exists)
|
if (!info.exists)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cft))) {
|
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name))) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -462,7 +463,7 @@ static int _lv_activate_lv(struct logical_volume *lv)
|
|||||||
int r;
|
int r;
|
||||||
struct dev_manager *dm;
|
struct dev_manager *dm;
|
||||||
|
|
||||||
if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cft))) {
|
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name))) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -479,7 +480,7 @@ static int _lv_deactivate(struct logical_volume *lv)
|
|||||||
int r;
|
int r;
|
||||||
struct dev_manager *dm;
|
struct dev_manager *dm;
|
||||||
|
|
||||||
if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cft))) {
|
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name))) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -496,7 +497,7 @@ static int _lv_suspend_lv(struct logical_volume *lv)
|
|||||||
int r;
|
int r;
|
||||||
struct dev_manager *dm;
|
struct dev_manager *dm;
|
||||||
|
|
||||||
if (!(dm = dev_manager_create(lv->vg->name, lv->vg->cmd->cft))) {
|
if (!(dm = dev_manager_create(lv->vg->cmd, lv->vg->name))) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -509,7 +510,7 @@ static int _lv_suspend_lv(struct logical_volume *lv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These two functions return the number of LVs in the state,
|
* These two functions return the number of visible LVs in the state,
|
||||||
* or -1 on error.
|
* or -1 on error.
|
||||||
*/
|
*/
|
||||||
int lvs_in_vg_activated(struct volume_group *vg)
|
int lvs_in_vg_activated(struct volume_group *vg)
|
||||||
@@ -523,7 +524,8 @@ int lvs_in_vg_activated(struct volume_group *vg)
|
|||||||
|
|
||||||
list_iterate(lvh, &vg->lvs) {
|
list_iterate(lvh, &vg->lvs) {
|
||||||
lv = list_item(lvh, struct lv_list)->lv;
|
lv = list_item(lvh, struct lv_list)->lv;
|
||||||
count += (_lv_active(lv) == 1);
|
if (lv->status & VISIBLE_LV)
|
||||||
|
count += (_lv_active(lv) == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
@@ -540,7 +542,8 @@ int lvs_in_vg_opened(struct volume_group *vg)
|
|||||||
|
|
||||||
list_iterate(lvh, &vg->lvs) {
|
list_iterate(lvh, &vg->lvs) {
|
||||||
lv = list_item(lvh, struct lv_list)->lv;
|
lv = list_item(lvh, struct lv_list)->lv;
|
||||||
count += (_lv_open_count(lv) > 0);
|
if (lv->status & VISIBLE_LV)
|
||||||
|
count += (_lv_open_count(lv) > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
|
|||||||
@@ -21,7 +21,11 @@
|
|||||||
#include "lvm-string.h"
|
#include "lvm-string.h"
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include "defaults.h"
|
#include "defaults.h"
|
||||||
|
#include "segtype.h"
|
||||||
|
#include "display.h"
|
||||||
#include "toolcontext.h"
|
#include "toolcontext.h"
|
||||||
|
#include "targets.h"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
#include <libdevmapper.h>
|
#include <libdevmapper.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
@@ -62,13 +66,8 @@ enum {
|
|||||||
SUSPENDED = 4,
|
SUSPENDED = 4,
|
||||||
NOPROPAGATE = 5,
|
NOPROPAGATE = 5,
|
||||||
TOPLEVEL = 6,
|
TOPLEVEL = 6,
|
||||||
REMOVE = 7
|
REMOVE = 7,
|
||||||
};
|
RESUME_IMMEDIATE = 8
|
||||||
|
|
||||||
enum {
|
|
||||||
MIRR_DISABLED,
|
|
||||||
MIRR_RUNNING,
|
|
||||||
MIRR_COMPLETED
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -112,14 +111,14 @@ struct dl_list {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const char *stripe_filler = NULL;
|
static const char *stripe_filler = NULL;
|
||||||
static uint32_t mirror_region_size = 0;
|
|
||||||
|
|
||||||
struct dev_manager {
|
struct dev_manager {
|
||||||
struct pool *mem;
|
struct pool *mem;
|
||||||
|
|
||||||
struct config_tree *cft;
|
struct cmd_context *cmd;
|
||||||
|
|
||||||
const char *stripe_filler;
|
const char *stripe_filler;
|
||||||
uint32_t mirror_region_size;
|
void *target_state;
|
||||||
uint32_t pvmove_mirror_count;
|
uint32_t pvmove_mirror_count;
|
||||||
|
|
||||||
char *vg_name;
|
char *vg_name;
|
||||||
@@ -166,89 +165,6 @@ static inline void _clear_flag(struct dev_layer *dl, int bit)
|
|||||||
dl->flags &= ~(1 << 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)
|
static char *_build_dlid(struct pool *mem, const char *lvid, const char *layer)
|
||||||
{
|
{
|
||||||
char *dlid;
|
char *dlid;
|
||||||
@@ -336,7 +252,7 @@ static int _info_run(const char *name, const char *uuid, struct dm_info *info,
|
|||||||
static int _info(const char *name, const char *uuid, int mknodes,
|
static int _info(const char *name, const char *uuid, int mknodes,
|
||||||
struct dm_info *info, struct pool *mem, char **uuid_out)
|
struct dm_info *info, struct pool *mem, char **uuid_out)
|
||||||
{
|
{
|
||||||
if (!mknodes && uuid && *uuid &&
|
if (!mknodes && uuid && *uuid &&
|
||||||
_info_run(NULL, uuid, info, 0, mem, uuid_out) && info->exists)
|
_info_run(NULL, uuid, info, 0, mem, uuid_out) && info->exists)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
@@ -427,18 +343,16 @@ static int _percent_run(struct dev_manager *dm, const char *name,
|
|||||||
uint64_t start, length;
|
uint64_t start, length;
|
||||||
char *type = NULL;
|
char *type = NULL;
|
||||||
char *params = NULL;
|
char *params = NULL;
|
||||||
float percent2;
|
|
||||||
struct list *segh = &lv->segments;
|
struct list *segh = &lv->segments;
|
||||||
struct lv_segment *seg = NULL;
|
struct lv_segment *seg = NULL;
|
||||||
|
struct segment_type *segtype;
|
||||||
|
|
||||||
uint64_t numerator, denominator;
|
|
||||||
uint64_t total_numerator = 0, total_denominator = 0;
|
uint64_t total_numerator = 0, total_denominator = 0;
|
||||||
|
|
||||||
*percent = -1;
|
*percent = -1;
|
||||||
|
|
||||||
if (!(dmt = _setup_task(name, uuid, event_nr,
|
if (!(dmt = _setup_task(name, uuid, event_nr,
|
||||||
wait ? DM_DEVICE_WAITEVENT : DM_DEVICE_STATUS)))
|
wait ? DM_DEVICE_WAITEVENT : DM_DEVICE_STATUS))) {
|
||||||
{
|
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -471,40 +385,19 @@ static int _percent_run(struct dev_manager *dm, const char *name,
|
|||||||
if (!type || !params || strcmp(type, target_type))
|
if (!type || !params || strcmp(type, target_type))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Mirror? */
|
if (!(segtype = get_segtype_from_string(dm->cmd, type)))
|
||||||
if (!strcmp(type, "mirror")) {
|
|
||||||
log_debug("Mirror status: %s", params);
|
|
||||||
if (sscanf(params, "%*d %*x:%*x %*x:%*x %" PRIu64
|
|
||||||
"/%" PRIu64, &numerator,
|
|
||||||
&denominator) != 2) {
|
|
||||||
log_error("Failure parsing mirror status: %s",
|
|
||||||
params);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
total_numerator += numerator;
|
|
||||||
total_denominator += denominator;
|
|
||||||
|
|
||||||
if (seg && (seg->status & PVMOVE))
|
|
||||||
seg->extents_moved = dm->mirror_region_size *
|
|
||||||
numerator / lv->vg->extent_size;
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (segtype->ops->target_percent &&
|
||||||
|
!segtype->ops->target_percent(&dm->target_state, dm->mem,
|
||||||
|
dm->cmd->cft, seg, params,
|
||||||
|
&total_numerator,
|
||||||
|
&total_denominator,
|
||||||
|
percent)) {
|
||||||
|
stack;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(type, "snapshot"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* Snapshot */
|
|
||||||
if (index(params, '/')) {
|
|
||||||
if (sscanf(params, "%" PRIu64 "/%" PRIu64,
|
|
||||||
&numerator, &denominator) == 2) {
|
|
||||||
total_numerator += numerator;
|
|
||||||
total_denominator += denominator;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
} else if (sscanf(params, "%f", &percent2) == 1) {
|
|
||||||
*percent += percent2;
|
|
||||||
*percent /= 2;
|
|
||||||
}
|
|
||||||
} while (next);
|
} while (next);
|
||||||
|
|
||||||
if (lv && (segh = list_next(&lv->segments, segh))) {
|
if (lv && (segh = list_next(&lv->segments, segh))) {
|
||||||
@@ -515,7 +408,7 @@ static int _percent_run(struct dev_manager *dm, const char *name,
|
|||||||
|
|
||||||
if (total_denominator)
|
if (total_denominator)
|
||||||
*percent = (float) total_numerator *100 / total_denominator;
|
*percent = (float) total_numerator *100 / total_denominator;
|
||||||
else
|
else if (*percent < 0)
|
||||||
*percent = 100;
|
*percent = 100;
|
||||||
|
|
||||||
log_debug("LV percent: %f", *percent);
|
log_debug("LV percent: %f", *percent);
|
||||||
@@ -543,10 +436,16 @@ static int _percent(struct dev_manager *dm, const char *name, const char *uuid,
|
|||||||
return 0;
|
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;
|
int r = 1;
|
||||||
struct dm_task *dmt;
|
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);
|
log_verbose("Renaming %s to %s", dl->name, newname);
|
||||||
|
|
||||||
@@ -561,11 +460,13 @@ static int _rename(struct dev_layer *dl, char *newname)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(r = dm_task_run(dmt)))
|
if (!(r = dm_task_run(dmt))) {
|
||||||
log_error("Couldn't rename device '%s'.", dl->name);
|
log_error("Couldn't rename device '%s'.", dl->name);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (r && _get_flag(dl, VISIBLE))
|
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;
|
dl->name = newname;
|
||||||
|
|
||||||
@@ -574,6 +475,55 @@ static int _rename(struct dev_layer *dl, char *newname)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int _suspend_or_resume(const char *name, action_t suspend)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
struct dm_task *dmt;
|
||||||
|
int sus = (suspend == SUSPEND) ? 1 : 0;
|
||||||
|
int task = sus ? DM_DEVICE_SUSPEND : DM_DEVICE_RESUME;
|
||||||
|
|
||||||
|
log_very_verbose("%s %s", sus ? "Suspending" : "Resuming", name);
|
||||||
|
if (!(dmt = _setup_task(name, NULL, 0, task))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(r = dm_task_run(dmt)))
|
||||||
|
log_error("Couldn't %s device '%s'", sus ? "suspend" : "resume",
|
||||||
|
name);
|
||||||
|
|
||||||
|
dm_task_destroy(dmt);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _suspend(struct dev_layer *dl)
|
||||||
|
{
|
||||||
|
if (!dl->info.exists || dl->info.suspended)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (!_suspend_or_resume(dl->name, SUSPEND)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dl->info.suspended = 1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _resume(struct dev_layer *dl)
|
||||||
|
{
|
||||||
|
if (!dl->info.exists || !dl->info.suspended)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (!_suspend_or_resume(dl->name, RESUME)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dl->info.suspended = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int _load(struct dev_manager *dm, struct dev_layer *dl, int task)
|
static int _load(struct dev_manager *dm, struct dev_layer *dl, int task)
|
||||||
{
|
{
|
||||||
int r = 1;
|
int r = 1;
|
||||||
@@ -633,9 +583,9 @@ static int _load(struct dev_manager *dm, struct dev_layer *dl, int task)
|
|||||||
log_error("Couldn't load device '%s'.", dl->name);
|
log_error("Couldn't load device '%s'.", dl->name);
|
||||||
if ((dl->lv->minor >= 0 || dl->lv->major >= 0) &&
|
if ((dl->lv->minor >= 0 || dl->lv->major >= 0) &&
|
||||||
_get_flag(dl, VISIBLE))
|
_get_flag(dl, VISIBLE))
|
||||||
log_error("Perhaps the persistent device number "
|
log_error("Perhaps the persistent device number "
|
||||||
"%d:%d is already in use?",
|
"%d:%d is already in use?",
|
||||||
dl->lv->major, dl->lv->minor);
|
dl->lv->major, dl->lv->minor);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dm_task_get_info(dmt, &dl->info)) {
|
if (!dm_task_get_info(dmt, &dl->info)) {
|
||||||
@@ -650,6 +600,13 @@ static int _load(struct dev_manager *dm, struct dev_layer *dl, int task)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_get_flag(dl, RESUME_IMMEDIATE) && dl->info.suspended &&
|
||||||
|
!_resume(dl)) {
|
||||||
|
stack;
|
||||||
|
r = 0;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
log_very_verbose("Activated %s %s %03u:%03u", dl->name,
|
log_very_verbose("Activated %s %s %03u:%03u", dl->name,
|
||||||
dl->dlid, dl->info.major, dl->info.minor);
|
dl->dlid, dl->info.major, dl->info.minor);
|
||||||
|
|
||||||
@@ -696,55 +653,6 @@ static int _remove(struct dev_layer *dl)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _suspend_or_resume(const char *name, action_t suspend)
|
|
||||||
{
|
|
||||||
int r;
|
|
||||||
struct dm_task *dmt;
|
|
||||||
int sus = (suspend == SUSPEND) ? 1 : 0;
|
|
||||||
int task = sus ? DM_DEVICE_SUSPEND : DM_DEVICE_RESUME;
|
|
||||||
|
|
||||||
log_very_verbose("%s %s", sus ? "Suspending" : "Resuming", name);
|
|
||||||
if (!(dmt = _setup_task(name, NULL, 0, task))) {
|
|
||||||
stack;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(r = dm_task_run(dmt)))
|
|
||||||
log_error("Couldn't %s device '%s'", sus ? "suspend" : "resume",
|
|
||||||
name);
|
|
||||||
|
|
||||||
dm_task_destroy(dmt);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _suspend(struct dev_layer *dl)
|
|
||||||
{
|
|
||||||
if (!dl->info.exists || dl->info.suspended)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
if (!_suspend_or_resume(dl->name, SUSPEND)) {
|
|
||||||
stack;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
dl->info.suspended = 1;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _resume(struct dev_layer *dl)
|
|
||||||
{
|
|
||||||
if (!dl->info.exists || !dl->info.suspended)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
if (!_suspend_or_resume(dl->name, RESUME)) {
|
|
||||||
stack;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
dl->info.suspended = 0;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The functions that populate the table in a dm_task as part of
|
* The functions that populate the table in a dm_task as part of
|
||||||
* a create/reload.
|
* a create/reload.
|
||||||
@@ -759,98 +667,26 @@ static int _emit_target_line(struct dev_manager *dm, struct dm_task *dmt,
|
|||||||
size_t paramsize)
|
size_t paramsize)
|
||||||
{
|
{
|
||||||
uint64_t esize = seg->lv->vg->extent_size;
|
uint64_t esize = seg->lv->vg->extent_size;
|
||||||
uint32_t s, start_area = 0u, areas = seg->area_count;
|
int w = 0;
|
||||||
int w = 0, tw = 0;
|
|
||||||
const char *target = NULL;
|
const char *target = NULL;
|
||||||
const char *trailing_space;
|
int r;
|
||||||
int mirror_status;
|
|
||||||
struct dev_layer *dl;
|
|
||||||
char devbuf[10];
|
|
||||||
|
|
||||||
switch (seg->type) {
|
if (!seg->segtype->ops->compose_target_line) {
|
||||||
case SEG_SNAPSHOT:
|
|
||||||
log_error("_emit_target: Internal error: Can't handle "
|
log_error("_emit_target: Internal error: Can't handle "
|
||||||
"SEG_SNAPSHOT");
|
"segment type %s", seg->segtype->name);
|
||||||
return 0;
|
return 0;
|
||||||
/* Target formats:
|
|
||||||
* linear [device offset]+
|
|
||||||
* striped #stripes stripe_size [device offset]+
|
|
||||||
* mirror log_type #log_params [log_params]*
|
|
||||||
* #mirrors [device offset]+
|
|
||||||
*/
|
|
||||||
case SEG_STRIPED:
|
|
||||||
if (areas == 1)
|
|
||||||
target = "linear";
|
|
||||||
else if (areas > 1) {
|
|
||||||
target = "striped";
|
|
||||||
if ((tw = lvm_snprintf(params, paramsize, "%u %u ",
|
|
||||||
areas, seg->stripe_size)) < 0)
|
|
||||||
goto error;
|
|
||||||
w = tw;
|
|
||||||
} else {
|
|
||||||
log_error("_emit_target: Internal error: SEG_STRIPED "
|
|
||||||
"with no stripes");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SEG_MIRRORED:
|
|
||||||
mirror_status = MIRR_RUNNING;
|
|
||||||
if (seg->status & PVMOVE) {
|
|
||||||
if (seg->extents_moved == seg->area_len) {
|
|
||||||
mirror_status = MIRR_COMPLETED;
|
|
||||||
start_area = 1;
|
|
||||||
} else if (dm->pvmove_mirror_count++) {
|
|
||||||
mirror_status = MIRR_DISABLED;
|
|
||||||
areas = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (mirror_status != MIRR_RUNNING) {
|
|
||||||
target = "linear";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
target = "mirror";
|
|
||||||
if ((tw = lvm_snprintf(params, paramsize, "core 1 %u %u ",
|
|
||||||
dm->mirror_region_size, areas)) < 0)
|
|
||||||
goto error;
|
|
||||||
w = tw;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (s = start_area; s < areas; s++, w += tw) {
|
if ((r = seg->segtype->ops->compose_target_line(dm, dm->mem,
|
||||||
trailing_space = (areas - s - 1) ? " " : "";
|
dm->cmd->cft,
|
||||||
if ((seg->area[s].type == AREA_PV &&
|
&dm->target_state, seg,
|
||||||
(!seg->area[s].u.pv.pv || !seg->area[s].u.pv.pv->dev)) ||
|
params, paramsize,
|
||||||
(seg->area[s].type == AREA_LV && !seg->area[s].u.lv.lv))
|
&target, &w,
|
||||||
tw = lvm_snprintf(params + w, paramsize - w,
|
&dm->
|
||||||
"%s 0%s", dm->stripe_filler,
|
pvmove_mirror_count)) <=
|
||||||
trailing_space);
|
0) {
|
||||||
else if (seg->area[s].type == AREA_PV)
|
stack;
|
||||||
tw = lvm_snprintf(params + w, paramsize - w,
|
return r;
|
||||||
"%s %" PRIu64 "%s",
|
|
||||||
dev_name(seg->area[s].u.pv.pv->dev),
|
|
||||||
(seg->area[s].u.pv.pv->pe_start +
|
|
||||||
(esize * seg->area[s].u.pv.pe)),
|
|
||||||
trailing_space);
|
|
||||||
else {
|
|
||||||
if (!(dl = hash_lookup(dm->layers,
|
|
||||||
seg->area[s].u.lv.lv->lvid.s))) {
|
|
||||||
log_error("device layer %s missing from hash",
|
|
||||||
seg->area[s].u.lv.lv->lvid.s);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (!dm_format_dev(devbuf, sizeof(devbuf), dl->info.major, dl->info.minor)) {
|
|
||||||
log_error("Failed to format device number as dm target (%u,%u)",
|
|
||||||
dl->info.major, dl->info.minor);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
tw = lvm_snprintf(params + w, paramsize - w,
|
|
||||||
"%s %" PRIu64 "%s", devbuf,
|
|
||||||
esize * seg->area[s].u.lv.le,
|
|
||||||
trailing_space);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tw < 0)
|
|
||||||
goto error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log_debug("Adding target: %" PRIu64 " %" PRIu64 " %s %s",
|
log_debug("Adding target: %" PRIu64 " %" PRIu64 " %s %s",
|
||||||
@@ -863,11 +699,62 @@ static int _emit_target_line(struct dev_manager *dm, struct dm_task *dmt,
|
|||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
error:
|
int compose_areas_line(struct dev_manager *dm, struct lv_segment *seg,
|
||||||
log_debug("Insufficient space in params[%" PRIsize_t "] for target "
|
char *params, size_t paramsize, int *pos, int start_area,
|
||||||
"parameters.", paramsize);
|
int areas)
|
||||||
return -1;
|
{
|
||||||
|
uint32_t s;
|
||||||
|
int tw = 0;
|
||||||
|
const char *trailing_space;
|
||||||
|
uint64_t esize = seg->lv->vg->extent_size;
|
||||||
|
struct dev_layer *dl;
|
||||||
|
char devbuf[10];
|
||||||
|
|
||||||
|
for (s = start_area; s < areas; s++, *pos += tw) {
|
||||||
|
trailing_space = (areas - s - 1) ? " " : "";
|
||||||
|
if ((seg->area[s].type == AREA_PV &&
|
||||||
|
(!seg->area[s].u.pv.pv || !seg->area[s].u.pv.pv->dev)) ||
|
||||||
|
(seg->area[s].type == AREA_LV && !seg->area[s].u.lv.lv))
|
||||||
|
tw = lvm_snprintf(params + *pos, paramsize - *pos,
|
||||||
|
"%s 0%s", dm->stripe_filler,
|
||||||
|
trailing_space);
|
||||||
|
else if (seg->area[s].type == AREA_PV)
|
||||||
|
tw = lvm_snprintf(params + *pos, paramsize - *pos,
|
||||||
|
"%s %" PRIu64 "%s",
|
||||||
|
dev_name(seg->area[s].u.pv.pv->dev),
|
||||||
|
(seg->area[s].u.pv.pv->pe_start +
|
||||||
|
(esize * seg->area[s].u.pv.pe)),
|
||||||
|
trailing_space);
|
||||||
|
else {
|
||||||
|
if (!(dl = hash_lookup(dm->layers,
|
||||||
|
seg->area[s].u.lv.lv->lvid.s))) {
|
||||||
|
log_error("device layer %s missing from hash",
|
||||||
|
seg->area[s].u.lv.lv->lvid.s);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!dm_format_dev
|
||||||
|
(devbuf, sizeof(devbuf), dl->info.major,
|
||||||
|
dl->info.minor)) {
|
||||||
|
log_error
|
||||||
|
("Failed to format device number as dm target (%u,%u)",
|
||||||
|
dl->info.major, dl->info.minor);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
tw = lvm_snprintf(params + *pos, paramsize - *pos,
|
||||||
|
"%s %" PRIu64 "%s", devbuf,
|
||||||
|
esize * seg->area[s].u.lv.le,
|
||||||
|
trailing_space);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tw < 0) {
|
||||||
|
stack;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _emit_target(struct dev_manager *dm, struct dm_task *dmt,
|
static int _emit_target(struct dev_manager *dm, struct dm_task *dmt,
|
||||||
@@ -892,6 +779,9 @@ static int _emit_target(struct dev_manager *dm, struct dm_task *dmt,
|
|||||||
if (ret >= 0)
|
if (ret >= 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
log_debug("Insufficient space in params[%" PRIsize_t
|
||||||
|
"] for target parameters.", paramsize);
|
||||||
|
|
||||||
paramsize *= 2;
|
paramsize *= 2;
|
||||||
} while (paramsize < MAX_TARGET_PARAMSIZE);
|
} while (paramsize < MAX_TARGET_PARAMSIZE);
|
||||||
|
|
||||||
@@ -1023,8 +913,8 @@ static int _populate_snapshot(struct dev_manager *dm,
|
|||||||
/*
|
/*
|
||||||
* dev_manager implementation.
|
* dev_manager implementation.
|
||||||
*/
|
*/
|
||||||
struct dev_manager *dev_manager_create(const char *vg_name,
|
struct dev_manager *dev_manager_create(struct cmd_context *cmd,
|
||||||
struct config_tree *cft)
|
const char *vg_name)
|
||||||
{
|
{
|
||||||
struct pool *mem;
|
struct pool *mem;
|
||||||
struct dev_manager *dm;
|
struct dev_manager *dm;
|
||||||
@@ -1039,22 +929,16 @@ struct dev_manager *dev_manager_create(const char *vg_name,
|
|||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dm->cmd = cmd;
|
||||||
dm->mem = mem;
|
dm->mem = mem;
|
||||||
dm->cft = cft;
|
|
||||||
if (!stripe_filler) {
|
if (!stripe_filler) {
|
||||||
stripe_filler = find_config_str(cft->root,
|
stripe_filler = find_config_str(cmd->cft->root,
|
||||||
"activation/missing_stripe_filler",
|
"activation/missing_stripe_filler",
|
||||||
DEFAULT_STRIPE_FILLER);
|
DEFAULT_STRIPE_FILLER);
|
||||||
}
|
}
|
||||||
dm->stripe_filler = stripe_filler;
|
dm->stripe_filler = stripe_filler;
|
||||||
|
|
||||||
if (!mirror_region_size) {
|
|
||||||
mirror_region_size = 2 * find_config_int(cft->root,
|
|
||||||
"activation/mirror_region_size",
|
|
||||||
DEFAULT_MIRROR_REGION_SIZE);
|
|
||||||
}
|
|
||||||
dm->mirror_region_size = mirror_region_size;
|
|
||||||
|
|
||||||
if (!(dm->vg_name = pool_strdup(dm->mem, vg_name))) {
|
if (!(dm->vg_name = pool_strdup(dm->mem, vg_name))) {
|
||||||
stack;
|
stack;
|
||||||
goto bad;
|
goto bad;
|
||||||
@@ -1070,6 +954,8 @@ struct dev_manager *dev_manager_create(const char *vg_name,
|
|||||||
list_init(&dm->remove_list);
|
list_init(&dm->remove_list);
|
||||||
list_init(&dm->suspend_list);
|
list_init(&dm->suspend_list);
|
||||||
|
|
||||||
|
dm->target_state = NULL;
|
||||||
|
|
||||||
return dm;
|
return dm;
|
||||||
|
|
||||||
bad:
|
bad:
|
||||||
@@ -1091,7 +977,7 @@ int dev_manager_info(struct dev_manager *dm, const struct logical_volume *lv,
|
|||||||
/*
|
/*
|
||||||
* Build a name for the top layer.
|
* 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;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1116,7 +1002,7 @@ int dev_manager_snapshot_percent(struct dev_manager *dm,
|
|||||||
/*
|
/*
|
||||||
* Build a name for the top layer.
|
* 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;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1148,7 +1034,7 @@ int dev_manager_mirror_percent(struct dev_manager *dm,
|
|||||||
/*
|
/*
|
||||||
* Build a name for the top layer.
|
* 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;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1212,7 +1098,7 @@ static struct dev_layer *_create_layer(struct dev_manager *dm,
|
|||||||
char *name, *dlid;
|
char *name, *dlid;
|
||||||
struct dev_layer *dl;
|
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;
|
stack;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1282,15 +1168,13 @@ static int _expand_vanilla(struct dev_manager *dm, struct logical_volume *lv,
|
|||||||
/* Add dependencies for any LVs that segments refer to */
|
/* Add dependencies for any LVs that segments refer to */
|
||||||
list_iterate(segh, &lv->segments) {
|
list_iterate(segh, &lv->segments) {
|
||||||
seg = list_item(segh, struct lv_segment);
|
seg = list_item(segh, struct lv_segment);
|
||||||
if (seg->type != SEG_STRIPED && seg->type != SEG_MIRRORED)
|
|
||||||
continue;
|
|
||||||
for (s = 0; s < seg->area_count; s++) {
|
for (s = 0; s < seg->area_count; s++) {
|
||||||
if (seg->area[s].type != AREA_LV)
|
if (seg->area[s].type != AREA_LV)
|
||||||
continue;
|
continue;
|
||||||
if (!str_list_add(dm->mem, &dl->pre_create,
|
if (!str_list_add(dm->mem, &dl->pre_create,
|
||||||
_build_dlid(dm->mem,
|
_build_dlid(dm->mem,
|
||||||
seg->area[s].u.lv.
|
seg->area[s].u.lv.lv->
|
||||||
lv->lvid.s, NULL))) {
|
lvid.s, NULL))) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1311,7 +1195,7 @@ static int _expand_vanilla(struct dev_manager *dm, struct logical_volume *lv,
|
|||||||
_clear_flag(dlr, VISIBLE);
|
_clear_flag(dlr, VISIBLE);
|
||||||
_clear_flag(dlr, TOPLEVEL);
|
_clear_flag(dlr, TOPLEVEL);
|
||||||
_set_flag(dlr, REMOVE);
|
_set_flag(dlr, REMOVE);
|
||||||
|
|
||||||
/* add the dependency on the real device */
|
/* add the dependency on the real device */
|
||||||
if (!str_list_add(dm->mem, &dl->pre_create,
|
if (!str_list_add(dm->mem, &dl->pre_create,
|
||||||
pool_strdup(dm->mem, dlr->dlid))) {
|
pool_strdup(dm->mem, dlr->dlid))) {
|
||||||
@@ -1336,6 +1220,9 @@ static int _expand_origin_real(struct dev_manager *dm,
|
|||||||
_clear_flag(dl, VISIBLE);
|
_clear_flag(dl, VISIBLE);
|
||||||
_clear_flag(dl, TOPLEVEL);
|
_clear_flag(dl, TOPLEVEL);
|
||||||
|
|
||||||
|
/* Size changes must take effect before tables using it are reloaded */
|
||||||
|
_set_flag(dl, RESUME_IMMEDIATE);
|
||||||
|
|
||||||
real_dlid = dl->dlid;
|
real_dlid = dl->dlid;
|
||||||
|
|
||||||
if (!(dl = _create_layer(dm, NULL, lv))) {
|
if (!(dl = _create_layer(dm, NULL, lv))) {
|
||||||
@@ -1656,11 +1543,11 @@ static int _create_rec(struct dev_manager *dm, struct dev_layer *dl)
|
|||||||
if (dl->info.exists) {
|
if (dl->info.exists) {
|
||||||
if ((suffix = rindex(dl->dlid, '-')))
|
if ((suffix = rindex(dl->dlid, '-')))
|
||||||
suffix++;
|
suffix++;
|
||||||
newname = _build_name(dm->mem, dm->vg_name, dl->lv->name,
|
newname = build_dm_name(dm->mem, dm->vg_name, dl->lv->name,
|
||||||
suffix);
|
suffix);
|
||||||
if (strcmp(newname, dl->name)) {
|
if (strcmp(newname, dl->name)) {
|
||||||
if (!_suspend_parents(dm, dl) ||
|
if (!_suspend_parents(dm, dl) ||
|
||||||
!_suspend(dl) || !_rename(dl, newname)) {
|
!_suspend(dl) || !_rename(dm, dl, newname)) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1688,7 +1575,6 @@ static int _create_rec(struct dev_manager *dm, struct dev_layer *dl)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int _build_all_layers(struct dev_manager *dm, struct volume_group *vg)
|
static int _build_all_layers(struct dev_manager *dm, struct volume_group *vg)
|
||||||
{
|
{
|
||||||
struct list *lvh;
|
struct list *lvh;
|
||||||
@@ -1756,8 +1642,7 @@ static int _populate_pre_suspend_lists(struct dev_manager *dm)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!str_list_add(dm->mem, &dep->pre_create,
|
if (!str_list_add(dm->mem, &dep->pre_create, dl->dlid)) {
|
||||||
dl->dlid)) {
|
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1773,8 +1658,7 @@ static int _populate_pre_suspend_lists(struct dev_manager *dm)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!str_list_add(dm->mem, &dep->pre_suspend,
|
if (!str_list_add(dm->mem, &dep->pre_suspend, dl->dlid)) {
|
||||||
dl->dlid)) {
|
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -2086,6 +1970,73 @@ static int _remove_suspended_lvs(struct dev_manager *dm,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int _targets_present(struct dev_manager *dm, struct list *lvs)
|
||||||
|
{
|
||||||
|
struct logical_volume *lv;
|
||||||
|
struct list *lvh, *segh;
|
||||||
|
struct segment_type *segtype;
|
||||||
|
struct lv_segment *seg;
|
||||||
|
int snapshots = 0, mirrors = 0;
|
||||||
|
|
||||||
|
list_iterate(lvh, lvs) {
|
||||||
|
lv = list_item(lvh, struct lv_list)->lv;
|
||||||
|
|
||||||
|
if (!snapshots)
|
||||||
|
if (lv_is_cow(lv) || lv_is_origin(lv))
|
||||||
|
snapshots = 1;
|
||||||
|
|
||||||
|
if (!mirrors)
|
||||||
|
if (lv->status & PVMOVE)
|
||||||
|
mirrors = 1;
|
||||||
|
|
||||||
|
if (lv->status & VIRTUAL) {
|
||||||
|
list_iterate(segh, &lv->segments) {
|
||||||
|
seg = list_item(segh, struct lv_segment);
|
||||||
|
if (seg->segtype->ops->target_present &&
|
||||||
|
!seg->segtype->ops->target_present()) {
|
||||||
|
log_error("Can't expand LV: %s target "
|
||||||
|
"support missing "
|
||||||
|
"from kernel?",
|
||||||
|
seg->segtype->name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mirrors) {
|
||||||
|
if (!(segtype = get_segtype_from_string(dm->cmd, "mirror"))) {
|
||||||
|
log_error("Can't expand LV: Mirror support "
|
||||||
|
"missing from tools?");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!segtype->ops->target_present ||
|
||||||
|
!segtype->ops->target_present()) {
|
||||||
|
log_error("Can't expand LV: Mirror support missing "
|
||||||
|
"from kernel?");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (snapshots) {
|
||||||
|
if (!(segtype = get_segtype_from_string(dm->cmd, "snapshot"))) {
|
||||||
|
log_error("Can't expand LV: Snapshot support "
|
||||||
|
"missing from tools?");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!segtype->ops->target_present ||
|
||||||
|
!segtype->ops->target_present()) {
|
||||||
|
log_error("Can't expand LV: Snapshot support missing "
|
||||||
|
"from kernel?");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int _fill_in_active_list(struct dev_manager *dm, struct volume_group *vg)
|
static int _fill_in_active_list(struct dev_manager *dm, struct volume_group *vg)
|
||||||
{
|
{
|
||||||
char *dlid;
|
char *dlid;
|
||||||
@@ -2168,6 +2119,12 @@ static int _action(struct dev_manager *dm, struct logical_volume *lv,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!_targets_present(dm, &dm->active_list) ||
|
||||||
|
!_targets_present(dm, &dm->reload_list)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (!_execute(dm, lv->vg)) {
|
if (!_execute(dm, lv->vg)) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
@@ -2195,8 +2152,8 @@ int dev_manager_lv_mknodes(const struct logical_volume *lv)
|
|||||||
{
|
{
|
||||||
char *name;
|
char *name;
|
||||||
|
|
||||||
if (!(name = _build_name(lv->vg->cmd->mem, lv->vg->name,
|
if (!(name = build_dm_name(lv->vg->cmd->mem, lv->vg->name,
|
||||||
lv->name, NULL))) {
|
lv->name, NULL))) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,17 +16,16 @@
|
|||||||
#ifndef _LVM_DEV_MANAGER_H
|
#ifndef _LVM_DEV_MANAGER_H
|
||||||
#define _LVM_DEV_MANAGER_H
|
#define _LVM_DEV_MANAGER_H
|
||||||
|
|
||||||
#include "metadata.h"
|
struct logical_volume;
|
||||||
#include "config.h"
|
struct cmd_context;
|
||||||
|
|
||||||
struct dev_manager;
|
struct dev_manager;
|
||||||
struct dm_info;
|
struct dm_info;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Constructor and destructor.
|
* Constructor and destructor.
|
||||||
*/
|
*/
|
||||||
struct dev_manager *dev_manager_create(const char *vg_name,
|
struct dev_manager *dev_manager_create(struct cmd_context *cmd,
|
||||||
struct config_tree *cf);
|
const char *vg_name);
|
||||||
void dev_manager_destroy(struct dev_manager *dm);
|
void dev_manager_destroy(struct dev_manager *dm);
|
||||||
void dev_manager_exit(void);
|
void dev_manager_exit(void);
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ static int _mk_dir(const char *dev_dir, const char *vg_name)
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
log_very_verbose("Creating directory %s", vg_path);
|
log_very_verbose("Creating directory %s", vg_path);
|
||||||
if (mkdir(vg_path, 0555)) {
|
if (mkdir(vg_path, 0777)) {
|
||||||
log_sys_error("mkdir", vg_path);
|
log_sys_error("mkdir", vg_path);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -65,10 +65,10 @@ static int _rm_dir(const char *dev_dir, const char *vg_name)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_very_verbose("Removing directory %s", vg_path);
|
if (is_empty_dir(vg_path)) {
|
||||||
|
log_very_verbose("Removing directory %s", vg_path);
|
||||||
if (is_empty_dir(vg_path))
|
|
||||||
rmdir(vg_path);
|
rmdir(vg_path);
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -181,7 +181,7 @@ static int _mk_link(const char *dev_dir, const char *vg_name,
|
|||||||
|
|
||||||
#ifdef HAVE_SELINUX
|
#ifdef HAVE_SELINUX
|
||||||
if (!set_selinux_context(lv_path)) {
|
if (!set_selinux_context(lv_path)) {
|
||||||
log_sys_error("set_selinux_context", lv_path);
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -202,9 +202,9 @@ static int _rm_link(const char *dev_dir, const char *vg_name,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (lstat(lv_path, &buf) || !S_ISLNK(buf.st_mode)) {
|
if (lstat(lv_path, &buf) || !S_ISLNK(buf.st_mode)) {
|
||||||
if (errno != ENOENT)
|
if (errno == ENOENT)
|
||||||
log_error("%s not symbolic link - not removing",
|
return 1;
|
||||||
lv_path);
|
log_error("%s not symbolic link - not removing", lv_path);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
25
lib/activate/targets.h
Normal file
25
lib/activate/targets.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LVM_TARGETS_H
|
||||||
|
#define _LVM_TARGETS_H
|
||||||
|
|
||||||
|
struct dev_manager;
|
||||||
|
struct lv_segment;
|
||||||
|
|
||||||
|
int compose_areas_line(struct dev_manager *dm, struct lv_segment *seg, char *params, size_t paramsize, int *pos,
|
||||||
|
int start_area, int areas);
|
||||||
|
|
||||||
|
#endif
|
||||||
5
lib/cache/lvmcache.h
vendored
5
lib/cache/lvmcache.h
vendored
@@ -20,7 +20,6 @@
|
|||||||
#include "dev-cache.h"
|
#include "dev-cache.h"
|
||||||
#include "uuid.h"
|
#include "uuid.h"
|
||||||
#include "label.h"
|
#include "label.h"
|
||||||
#include "metadata.h"
|
|
||||||
|
|
||||||
#define ORPHAN ""
|
#define ORPHAN ""
|
||||||
|
|
||||||
@@ -30,6 +29,10 @@
|
|||||||
/* LVM specific per-volume info */
|
/* LVM specific per-volume info */
|
||||||
/* Eventual replacement for struct physical_volume perhaps? */
|
/* Eventual replacement for struct physical_volume perhaps? */
|
||||||
|
|
||||||
|
struct cmd_context;
|
||||||
|
struct format_type;
|
||||||
|
struct volume_group;
|
||||||
|
|
||||||
struct lvmcache_vginfo {
|
struct lvmcache_vginfo {
|
||||||
struct list list; /* Join these vginfos together */
|
struct list list; /* Join these vginfos together */
|
||||||
struct list infos; /* List head for lvmcache_infos */
|
struct list infos; /* List head for lvmcache_infos */
|
||||||
|
|||||||
@@ -33,6 +33,8 @@
|
|||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include "memlock.h"
|
#include "memlock.h"
|
||||||
#include "str_list.h"
|
#include "str_list.h"
|
||||||
|
#include "segtype.h"
|
||||||
|
#include "lvmcache.h"
|
||||||
|
|
||||||
#ifdef HAVE_LIBDL
|
#ifdef HAVE_LIBDL
|
||||||
#include "sharedlib.h"
|
#include "sharedlib.h"
|
||||||
@@ -42,6 +44,10 @@
|
|||||||
#include "format1.h"
|
#include "format1.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef POOL_INTERNAL
|
||||||
|
#include "format_pool.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
@@ -116,8 +122,7 @@ static void _init_logging(struct cmd_context *cmd)
|
|||||||
find_config_int(cmd->cft->root, "global/test", 0);
|
find_config_int(cmd->cft->root, "global/test", 0);
|
||||||
|
|
||||||
/* Settings for logging to file */
|
/* Settings for logging to file */
|
||||||
if (find_config_int(cmd->cft->root, "log/overwrite",
|
if (find_config_int(cmd->cft->root, "log/overwrite", DEFAULT_OVERWRITE))
|
||||||
DEFAULT_OVERWRITE))
|
|
||||||
append = 0;
|
append = 0;
|
||||||
|
|
||||||
log_file = find_config_str(cmd->cft->root, "log/file", 0);
|
log_file = find_config_str(cmd->cft->root, "log/file", 0);
|
||||||
@@ -198,51 +203,260 @@ static int _process_config(struct cmd_context *cmd)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find and read config file */
|
static int _set_tag(struct cmd_context *cmd, const char *tag)
|
||||||
static int _init_config(struct cmd_context *cmd)
|
|
||||||
{
|
{
|
||||||
struct stat info;
|
log_very_verbose("Setting host tag: %s", pool_strdup(cmd->libmem, tag));
|
||||||
char config_file[PATH_MAX] = "";
|
|
||||||
|
|
||||||
if (!(cmd->cft = create_config_tree())) {
|
if (!str_list_add(cmd->libmem, &cmd->tags, tag)) {
|
||||||
stack;
|
log_error("_set_tag: str_list_add %s failed", tag);
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* No config file if LVM_SYSTEM_DIR is empty */
|
|
||||||
if (!*cmd->sys_dir)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
if (lvm_snprintf(config_file, sizeof(config_file),
|
|
||||||
"%s/lvm.conf", cmd->sys_dir) < 0) {
|
|
||||||
log_error("LVM_SYSTEM_DIR was too long");
|
|
||||||
destroy_config_tree(cmd->cft);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Is there a config file? */
|
|
||||||
if (stat(config_file, &info) == -1) {
|
|
||||||
if (errno == ENOENT)
|
|
||||||
return 1;
|
|
||||||
log_sys_error("stat", config_file);
|
|
||||||
destroy_config_tree(cmd->cft);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!read_config_file(cmd->cft, config_file)) {
|
|
||||||
log_error("Failed to load config file %s", config_file);
|
|
||||||
destroy_config_tree(cmd->cft);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _init_dev_cache(struct cmd_context *cmd)
|
static int _check_host_filters(struct cmd_context *cmd, struct config_node *hn,
|
||||||
|
int *passes)
|
||||||
{
|
{
|
||||||
struct config_node *cn;
|
struct config_node *cn;
|
||||||
struct config_value *cv;
|
struct config_value *cv;
|
||||||
|
|
||||||
|
*passes = 1;
|
||||||
|
|
||||||
|
for (cn = hn; cn; cn = cn->sib) {
|
||||||
|
if (!cn->v)
|
||||||
|
continue;
|
||||||
|
if (!strcmp(cn->key, "host_list")) {
|
||||||
|
*passes = 0;
|
||||||
|
if (cn->v->type == CFG_EMPTY_ARRAY)
|
||||||
|
continue;
|
||||||
|
for (cv = cn->v; cv; cv = cv->next) {
|
||||||
|
if (cv->type != CFG_STRING) {
|
||||||
|
log_error("Invalid hostname string "
|
||||||
|
"for tag %s", cn->key);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!strcmp(cv->v.str, cmd->hostname)) {
|
||||||
|
*passes = 1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!strcmp(cn->key, "host_filter")) {
|
||||||
|
log_error("host_filter not supported yet");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _init_tags(struct cmd_context *cmd, struct config_tree *cft)
|
||||||
|
{
|
||||||
|
const struct config_node *tn, *cn;
|
||||||
|
const char *tag;
|
||||||
|
int passes;
|
||||||
|
|
||||||
|
if (!(tn = find_config_node(cft->root, "tags")) || !tn->child)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* NB hosttags 0 when already 1 intentionally does not delete the tag */
|
||||||
|
if (!cmd->hosttags && find_config_int(cft->root, "tags/hosttags",
|
||||||
|
DEFAULT_HOSTTAGS)) {
|
||||||
|
/* FIXME Strip out invalid chars: only A-Za-z0-9_+.- */
|
||||||
|
if (!_set_tag(cmd, cmd->hostname)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
cmd->hosttags = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (cn = tn->child; cn; cn = cn->sib) {
|
||||||
|
if (cn->v)
|
||||||
|
continue;
|
||||||
|
tag = cn->key;
|
||||||
|
if (*tag == '@')
|
||||||
|
tag++;
|
||||||
|
if (!validate_name(tag)) {
|
||||||
|
log_error("Invalid tag in config file: %s", cn->key);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (cn->child) {
|
||||||
|
passes = 0;
|
||||||
|
if (!_check_host_filters(cmd, cn->child, &passes)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!passes)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!_set_tag(cmd, tag)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _load_config_file(struct cmd_context *cmd, const char *tag)
|
||||||
|
{
|
||||||
|
char config_file[PATH_MAX] = "";
|
||||||
|
const char *filler = "";
|
||||||
|
struct stat info;
|
||||||
|
struct config_tree_list *cfl;
|
||||||
|
|
||||||
|
if (*tag)
|
||||||
|
filler = "_";
|
||||||
|
|
||||||
|
if (lvm_snprintf(config_file, sizeof(config_file), "%s/lvm%s%s.conf",
|
||||||
|
cmd->sys_dir, filler, tag) < 0) {
|
||||||
|
log_error("LVM_SYSTEM_DIR or tag was too long");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(cfl = pool_alloc(cmd->libmem, sizeof(*cfl)))) {
|
||||||
|
log_error("config_tree_list allocation failed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(cfl->cft = create_config_tree(config_file))) {
|
||||||
|
log_error("config_tree allocation failed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Is there a config file? */
|
||||||
|
if (stat(config_file, &info) == -1) {
|
||||||
|
if (errno == ENOENT) {
|
||||||
|
list_add(&cmd->config_files, &cfl->list);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
log_sys_error("stat", config_file);
|
||||||
|
destroy_config_tree(cfl->cft);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_very_verbose("Loading config file: %s", config_file);
|
||||||
|
if (!read_config_file(cfl->cft)) {
|
||||||
|
log_error("Failed to load config file %s", config_file);
|
||||||
|
destroy_config_tree(cfl->cft);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_add(&cmd->config_files, &cfl->list);
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (*tag)
|
||||||
|
_init_tags(cmd, cfl->cft);
|
||||||
|
else
|
||||||
|
/* Use temporary copy of lvm.conf while loading other files */
|
||||||
|
cmd->cft = cfl->cft;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find and read first config file */
|
||||||
|
static int _init_lvm_conf(struct cmd_context *cmd)
|
||||||
|
{
|
||||||
|
/* No config file if LVM_SYSTEM_DIR is empty */
|
||||||
|
if (!*cmd->sys_dir) {
|
||||||
|
if (!(cmd->cft = create_config_tree(NULL))) {
|
||||||
|
log_error("Failed to create config tree");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_load_config_file(cmd, "")) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read any additional config files */
|
||||||
|
static int _init_tag_configs(struct cmd_context *cmd)
|
||||||
|
{
|
||||||
|
struct str_list *sl;
|
||||||
|
|
||||||
|
/* Tag list may grow while inside this loop */
|
||||||
|
list_iterate_items(sl, &cmd->tags) {
|
||||||
|
if (!_load_config_file(cmd, sl->str)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _merge_config_files(struct cmd_context *cmd)
|
||||||
|
{
|
||||||
|
struct config_tree_list *cfl;
|
||||||
|
|
||||||
|
/* Replace temporary duplicate copy of lvm.conf */
|
||||||
|
if (cmd->cft->root) {
|
||||||
|
if (!(cmd->cft = create_config_tree(NULL))) {
|
||||||
|
log_error("Failed to create config tree");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
list_iterate_items(cfl, &cmd->config_files) {
|
||||||
|
/* Merge all config trees into cmd->cft using merge/tag rules */
|
||||||
|
if (!merge_config_tree(cmd, cmd->cft, cfl->cft)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _destroy_tags(struct cmd_context *cmd)
|
||||||
|
{
|
||||||
|
struct list *slh, *slht;
|
||||||
|
|
||||||
|
list_iterate_safe(slh, slht, &cmd->tags) {
|
||||||
|
list_del(slh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int config_files_changed(struct cmd_context *cmd)
|
||||||
|
{
|
||||||
|
struct config_tree_list *cfl;
|
||||||
|
|
||||||
|
list_iterate_items(cfl, &cmd->config_files) {
|
||||||
|
if (config_file_changed(cfl->cft))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _destroy_tag_configs(struct cmd_context *cmd)
|
||||||
|
{
|
||||||
|
struct config_tree_list *cfl;
|
||||||
|
|
||||||
|
if (cmd->cft && cmd->cft->root) {
|
||||||
|
destroy_config_tree(cmd->cft);
|
||||||
|
cmd->cft = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_iterate_items(cfl, &cmd->config_files) {
|
||||||
|
destroy_config_tree(cfl->cft);
|
||||||
|
}
|
||||||
|
|
||||||
|
list_init(&cmd->config_files);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _init_dev_cache(struct cmd_context *cmd)
|
||||||
|
{
|
||||||
|
const struct config_node *cn;
|
||||||
|
struct config_value *cv;
|
||||||
|
|
||||||
if (!dev_cache_init()) {
|
if (!dev_cache_init()) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
@@ -281,7 +495,7 @@ static int _init_dev_cache(struct cmd_context *cmd)
|
|||||||
static struct dev_filter *_init_filter_components(struct cmd_context *cmd)
|
static struct dev_filter *_init_filter_components(struct cmd_context *cmd)
|
||||||
{
|
{
|
||||||
unsigned nr_filt = 0;
|
unsigned nr_filt = 0;
|
||||||
struct config_node *cn;
|
const struct config_node *cn;
|
||||||
struct dev_filter *filters[MAX_FILTERS];
|
struct dev_filter *filters[MAX_FILTERS];
|
||||||
|
|
||||||
memset(filters, 0, sizeof(filters));
|
memset(filters, 0, sizeof(filters));
|
||||||
@@ -351,8 +565,8 @@ static int _init_filters(struct cmd_context *cmd)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_cache =
|
dev_cache = find_config_str(cmd->cft->root, "devices/cache",
|
||||||
find_config_str(cmd->cft->root, "devices/cache", cache_file);
|
cache_file);
|
||||||
if (!(f4 = persistent_filter_create(f3, dev_cache))) {
|
if (!(f4 = persistent_filter_create(f3, dev_cache))) {
|
||||||
log_error("Failed to create persistent device filter");
|
log_error("Failed to create persistent device filter");
|
||||||
return 0;
|
return 0;
|
||||||
@@ -384,7 +598,7 @@ static int _init_formats(struct cmd_context *cmd)
|
|||||||
struct list *fmth;
|
struct list *fmth;
|
||||||
|
|
||||||
#ifdef HAVE_LIBDL
|
#ifdef HAVE_LIBDL
|
||||||
struct config_node *cn;
|
const struct config_node *cn;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
label_init();
|
label_init();
|
||||||
@@ -396,6 +610,13 @@ static int _init_formats(struct cmd_context *cmd)
|
|||||||
list_add(&cmd->formats, &fmt->list);
|
list_add(&cmd->formats, &fmt->list);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef POOL_INTERNAL
|
||||||
|
if (!(fmt = init_pool_format(cmd)))
|
||||||
|
return 0;
|
||||||
|
fmt->library = NULL;
|
||||||
|
list_add(&cmd->formats, &fmt->list);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_LIBDL
|
#ifdef HAVE_LIBDL
|
||||||
/* Load any formats in shared libs */
|
/* Load any formats in shared libs */
|
||||||
if ((cn = find_config_node(cmd->cft->root, "global/format_libraries"))) {
|
if ((cn = find_config_node(cmd->cft->root, "global/format_libraries"))) {
|
||||||
@@ -454,6 +675,97 @@ static int _init_formats(struct cmd_context *cmd)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int _init_segtypes(struct cmd_context *cmd)
|
||||||
|
{
|
||||||
|
struct segment_type *segtype;
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBDL
|
||||||
|
const struct config_node *cn;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!(segtype = init_striped_segtype(cmd)))
|
||||||
|
return 0;
|
||||||
|
segtype->library = NULL;
|
||||||
|
list_add(&cmd->segtypes, &segtype->list);
|
||||||
|
|
||||||
|
if (!(segtype = init_zero_segtype(cmd)))
|
||||||
|
return 0;
|
||||||
|
segtype->library = NULL;
|
||||||
|
list_add(&cmd->segtypes, &segtype->list);
|
||||||
|
|
||||||
|
if (!(segtype = init_error_segtype(cmd)))
|
||||||
|
return 0;
|
||||||
|
segtype->library = NULL;
|
||||||
|
list_add(&cmd->segtypes, &segtype->list);
|
||||||
|
|
||||||
|
#ifdef SNAPSHOT_INTERNAL
|
||||||
|
if (!(segtype = init_snapshot_segtype(cmd)))
|
||||||
|
return 0;
|
||||||
|
segtype->library = NULL;
|
||||||
|
list_add(&cmd->segtypes, &segtype->list);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef MIRRORED_INTERNAL
|
||||||
|
if (!(segtype = init_mirrored_segtype(cmd)))
|
||||||
|
return 0;
|
||||||
|
segtype->library = NULL;
|
||||||
|
list_add(&cmd->segtypes, &segtype->list);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBDL
|
||||||
|
/* Load any formats in shared libs */
|
||||||
|
if ((cn = find_config_node(cmd->cft->root, "global/segment_libraries"))) {
|
||||||
|
|
||||||
|
struct config_value *cv;
|
||||||
|
struct segment_type *(*init_segtype_fn) (struct cmd_context *);
|
||||||
|
void *lib;
|
||||||
|
struct list *sgtl, *tmp;
|
||||||
|
struct segment_type *segtype2;
|
||||||
|
|
||||||
|
for (cv = cn->v; cv; cv = cv->next) {
|
||||||
|
if (cv->type != CFG_STRING) {
|
||||||
|
log_error("Invalid string in config file: "
|
||||||
|
"global/segment_libraries");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!(lib = load_shared_library(cmd->cft, cv->v.str,
|
||||||
|
"segment type"))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(init_segtype_fn = dlsym(lib, "init_segtype"))) {
|
||||||
|
log_error("Shared library %s does not contain "
|
||||||
|
"segment type functions", cv->v.str);
|
||||||
|
dlclose(lib);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(segtype = init_segtype_fn(cmd)))
|
||||||
|
return 0;
|
||||||
|
segtype->library = lib;
|
||||||
|
list_add(&cmd->segtypes, &segtype->list);
|
||||||
|
|
||||||
|
list_iterate_safe(sgtl, tmp, &cmd->segtypes) {
|
||||||
|
segtype2 = list_item(sgtl, struct segment_type);
|
||||||
|
if (!strcmp(segtype2->name, segtype->name)) {
|
||||||
|
log_error("Duplicate segment type %s: "
|
||||||
|
"unloading shared library %s",
|
||||||
|
segtype->name, cv->v.str);
|
||||||
|
list_del(&segtype->list);
|
||||||
|
segtype->ops->destroy(segtype);
|
||||||
|
dlclose(lib);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int _init_hostname(struct cmd_context *cmd)
|
static int _init_hostname(struct cmd_context *cmd)
|
||||||
{
|
{
|
||||||
struct utsname uts;
|
struct utsname uts;
|
||||||
@@ -476,105 +788,6 @@ static int _init_hostname(struct cmd_context *cmd)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _set_tag(struct cmd_context *cmd, const char *tag)
|
|
||||||
{
|
|
||||||
log_very_verbose("Setting host tag: %s", pool_strdup(cmd->libmem, tag));
|
|
||||||
|
|
||||||
if (!str_list_add(cmd->libmem, &cmd->tags, tag)) {
|
|
||||||
log_error("_init_tags: str_list_add %s failed", tag);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _check_host_filters(struct cmd_context *cmd, struct config_node *hn,
|
|
||||||
int *passes)
|
|
||||||
{
|
|
||||||
struct config_node *cn;
|
|
||||||
struct config_value *cv;
|
|
||||||
|
|
||||||
*passes = 1;
|
|
||||||
|
|
||||||
for (cn = hn; cn; cn = cn->sib) {
|
|
||||||
if (!cn->v)
|
|
||||||
continue;
|
|
||||||
if (!strcmp(cn->key, "host_list")) {
|
|
||||||
*passes = 0;
|
|
||||||
if (cn->v->type == CFG_EMPTY_ARRAY)
|
|
||||||
continue;
|
|
||||||
for (cv = cn->v; cv; cv = cv->next) {
|
|
||||||
if (cv->type != CFG_STRING) {
|
|
||||||
log_error("Invalid hostname string "
|
|
||||||
"for tag %s", cn->key);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (!strcmp(cv->v.str, cmd->hostname)) {
|
|
||||||
*passes = 1;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!strcmp(cn->key, "host_filter")) {
|
|
||||||
log_error("host_filter not supported yet");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _init_tags(struct cmd_context *cmd)
|
|
||||||
{
|
|
||||||
struct config_node *tn, *cn;
|
|
||||||
const char *tag;
|
|
||||||
int passes;
|
|
||||||
|
|
||||||
list_init(&cmd->tags);
|
|
||||||
|
|
||||||
if (!(tn = find_config_node(cmd->cft->root, "tags")) ||
|
|
||||||
!tn->child) {
|
|
||||||
log_very_verbose("No tags defined in config file");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (find_config_int(cmd->cft->root, "tags/hosttags",
|
|
||||||
DEFAULT_HOSTTAGS)) {
|
|
||||||
/* FIXME Strip out invalid chars: only A-Za-z0-9_+.- */
|
|
||||||
if (!_set_tag(cmd, cmd->hostname)) {
|
|
||||||
stack;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (cn = tn->child; cn; cn = cn->sib) {
|
|
||||||
if (cn->v)
|
|
||||||
continue;
|
|
||||||
tag = cn->key;
|
|
||||||
if (*tag == '@')
|
|
||||||
tag++;
|
|
||||||
if (!validate_name(tag)) {
|
|
||||||
log_error("Invalid tag in config file: %s", cn->key);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (cn->child) {
|
|
||||||
passes = 0;
|
|
||||||
if (!_check_host_filters(cmd, cn->child, &passes)) {
|
|
||||||
stack;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (!passes)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!_set_tag(cmd, tag)) {
|
|
||||||
stack;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Entry point */
|
/* Entry point */
|
||||||
struct cmd_context *create_toolcontext(struct arg *the_args)
|
struct cmd_context *create_toolcontext(struct arg *the_args)
|
||||||
{
|
{
|
||||||
@@ -585,7 +798,7 @@ struct cmd_context *create_toolcontext(struct arg *the_args)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!setlocale(LC_ALL, ""))
|
if (!setlocale(LC_ALL, ""))
|
||||||
log_error("setlocale failed");
|
log_very_verbose("setlocale failed");
|
||||||
|
|
||||||
#ifdef INTL_PACKAGE
|
#ifdef INTL_PACKAGE
|
||||||
bindtextdomain(INTL_PACKAGE, LOCALEDIR);
|
bindtextdomain(INTL_PACKAGE, LOCALEDIR);
|
||||||
@@ -599,7 +812,11 @@ struct cmd_context *create_toolcontext(struct arg *the_args)
|
|||||||
}
|
}
|
||||||
memset(cmd, 0, sizeof(*cmd));
|
memset(cmd, 0, sizeof(*cmd));
|
||||||
cmd->args = the_args;
|
cmd->args = the_args;
|
||||||
|
cmd->hosttags = 0;
|
||||||
list_init(&cmd->formats);
|
list_init(&cmd->formats);
|
||||||
|
list_init(&cmd->segtypes);
|
||||||
|
list_init(&cmd->tags);
|
||||||
|
list_init(&cmd->config_files);
|
||||||
|
|
||||||
strcpy(cmd->sys_dir, DEFAULT_SYS_DIR);
|
strcpy(cmd->sys_dir, DEFAULT_SYS_DIR);
|
||||||
|
|
||||||
@@ -610,16 +827,28 @@ struct cmd_context *create_toolcontext(struct arg *the_args)
|
|||||||
if (*cmd->sys_dir && !create_dir(cmd->sys_dir))
|
if (*cmd->sys_dir && !create_dir(cmd->sys_dir))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (!_init_config(cmd))
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
_init_logging(cmd);
|
|
||||||
|
|
||||||
if (!(cmd->libmem = pool_create(4 * 1024))) {
|
if (!(cmd->libmem = pool_create(4 * 1024))) {
|
||||||
log_error("Library memory pool creation failed");
|
log_error("Library memory pool creation failed");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!_init_lvm_conf(cmd))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
_init_logging(cmd);
|
||||||
|
|
||||||
|
if (!_init_hostname(cmd))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (!_init_tags(cmd, cmd->cft))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (!_init_tag_configs(cmd))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (!_merge_config_files(cmd))
|
||||||
|
goto error;
|
||||||
|
|
||||||
if (!_process_config(cmd))
|
if (!_process_config(cmd))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
@@ -639,14 +868,12 @@ struct cmd_context *create_toolcontext(struct arg *the_args)
|
|||||||
if (!_init_formats(cmd))
|
if (!_init_formats(cmd))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (!_init_hostname(cmd))
|
if (!_init_segtypes(cmd))
|
||||||
goto error;
|
|
||||||
|
|
||||||
if (!_init_tags(cmd))
|
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
cmd->current_settings = cmd->default_settings;
|
cmd->current_settings = cmd->default_settings;
|
||||||
|
|
||||||
|
cmd->config_valid = 1;
|
||||||
return cmd;
|
return cmd;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
@@ -654,16 +881,6 @@ struct cmd_context *create_toolcontext(struct arg *the_args)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int refresh_toolcontext(struct cmd_context *cmd)
|
|
||||||
{
|
|
||||||
_init_logging(cmd);
|
|
||||||
_init_tags(cmd);
|
|
||||||
|
|
||||||
/* FIXME Reset filters and dev_cache */
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _destroy_formats(struct list *formats)
|
static void _destroy_formats(struct list *formats)
|
||||||
{
|
{
|
||||||
struct list *fmtl, *tmp;
|
struct list *fmtl, *tmp;
|
||||||
@@ -682,6 +899,83 @@ static void _destroy_formats(struct list *formats)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _destroy_segtypes(struct list *segtypes)
|
||||||
|
{
|
||||||
|
struct list *sgtl, *tmp;
|
||||||
|
struct segment_type *segtype;
|
||||||
|
void *lib;
|
||||||
|
|
||||||
|
list_iterate_safe(sgtl, tmp, segtypes) {
|
||||||
|
segtype = list_item(sgtl, struct segment_type);
|
||||||
|
list_del(&segtype->list);
|
||||||
|
lib = segtype->library;
|
||||||
|
segtype->ops->destroy(segtype);
|
||||||
|
#ifdef HAVE_LIBDL
|
||||||
|
if (lib)
|
||||||
|
dlclose(lib);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int refresh_toolcontext(struct cmd_context *cmd)
|
||||||
|
{
|
||||||
|
log_verbose("Reloading config files");
|
||||||
|
|
||||||
|
if (cmd->config_valid) {
|
||||||
|
if (cmd->dump_filter)
|
||||||
|
persistent_filter_dump(cmd->filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
activation_exit();
|
||||||
|
lvmcache_destroy();
|
||||||
|
label_exit();
|
||||||
|
_destroy_segtypes(&cmd->segtypes);
|
||||||
|
_destroy_formats(&cmd->formats);
|
||||||
|
if (cmd->filter) {
|
||||||
|
cmd->filter->destroy(cmd->filter);
|
||||||
|
cmd->filter = NULL;
|
||||||
|
}
|
||||||
|
dev_cache_exit();
|
||||||
|
_destroy_tags(cmd);
|
||||||
|
_destroy_tag_configs(cmd);
|
||||||
|
|
||||||
|
cmd->config_valid = 0;
|
||||||
|
|
||||||
|
cmd->hosttags = 0;
|
||||||
|
|
||||||
|
if (!_init_lvm_conf(cmd))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
_init_logging(cmd);
|
||||||
|
|
||||||
|
if (!_init_tags(cmd, cmd->cft))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!_init_tag_configs(cmd))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!_merge_config_files(cmd))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!_process_config(cmd))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!_init_dev_cache(cmd))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!_init_filters(cmd))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!_init_formats(cmd))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!_init_segtypes(cmd))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
cmd->config_valid = 1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
void destroy_toolcontext(struct cmd_context *cmd)
|
void destroy_toolcontext(struct cmd_context *cmd)
|
||||||
{
|
{
|
||||||
if (cmd->dump_filter)
|
if (cmd->dump_filter)
|
||||||
@@ -690,11 +984,13 @@ void destroy_toolcontext(struct cmd_context *cmd)
|
|||||||
activation_exit();
|
activation_exit();
|
||||||
lvmcache_destroy();
|
lvmcache_destroy();
|
||||||
label_exit();
|
label_exit();
|
||||||
|
_destroy_segtypes(&cmd->segtypes);
|
||||||
_destroy_formats(&cmd->formats);
|
_destroy_formats(&cmd->formats);
|
||||||
cmd->filter->destroy(cmd->filter);
|
cmd->filter->destroy(cmd->filter);
|
||||||
pool_destroy(cmd->mem);
|
pool_destroy(cmd->mem);
|
||||||
dev_cache_exit();
|
dev_cache_exit();
|
||||||
destroy_config_tree(cmd->cft);
|
_destroy_tags(cmd);
|
||||||
|
_destroy_tag_configs(cmd);
|
||||||
pool_destroy(cmd->libmem);
|
pool_destroy(cmd->libmem);
|
||||||
dbg_free(cmd);
|
dbg_free(cmd);
|
||||||
|
|
||||||
|
|||||||
@@ -17,9 +17,7 @@
|
|||||||
#define _LVM_TOOLCONTEXT_H
|
#define _LVM_TOOLCONTEXT_H
|
||||||
|
|
||||||
#include "dev-cache.h"
|
#include "dev-cache.h"
|
||||||
#include "config.h"
|
|
||||||
#include "pool.h"
|
#include "pool.h"
|
||||||
#include "metadata.h"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
@@ -47,6 +45,8 @@ struct config_info {
|
|||||||
mode_t umask;
|
mode_t umask;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct config_tree;
|
||||||
|
|
||||||
/* FIXME Split into tool & library contexts */
|
/* FIXME Split into tool & library contexts */
|
||||||
/* command-instance-related variables needed by library */
|
/* command-instance-related variables needed by library */
|
||||||
struct cmd_context {
|
struct cmd_context {
|
||||||
@@ -57,6 +57,7 @@ struct cmd_context {
|
|||||||
struct format_type *fmt_backup; /* Format to use for backups */
|
struct format_type *fmt_backup; /* Format to use for backups */
|
||||||
|
|
||||||
struct list formats; /* Available formats */
|
struct list formats; /* Available formats */
|
||||||
|
struct list segtypes; /* Available segment types */
|
||||||
const char *hostname;
|
const char *hostname;
|
||||||
const char *kernel_vsn;
|
const char *kernel_vsn;
|
||||||
|
|
||||||
@@ -68,12 +69,15 @@ struct cmd_context {
|
|||||||
struct dev_filter *filter;
|
struct dev_filter *filter;
|
||||||
int dump_filter; /* Dump filter when exiting? */
|
int dump_filter; /* Dump filter when exiting? */
|
||||||
|
|
||||||
|
struct list config_files;
|
||||||
|
int config_valid;
|
||||||
struct config_tree *cft;
|
struct config_tree *cft;
|
||||||
struct config_info default_settings;
|
struct config_info default_settings;
|
||||||
struct config_info current_settings;
|
struct config_info current_settings;
|
||||||
|
|
||||||
/* List of defined tags */
|
/* List of defined tags */
|
||||||
struct list tags;
|
struct list tags;
|
||||||
|
int hosttags;
|
||||||
|
|
||||||
char sys_dir[PATH_MAX];
|
char sys_dir[PATH_MAX];
|
||||||
char dev_dir[PATH_MAX];
|
char dev_dir[PATH_MAX];
|
||||||
@@ -83,5 +87,6 @@ struct cmd_context {
|
|||||||
struct cmd_context *create_toolcontext(struct arg *the_args);
|
struct cmd_context *create_toolcontext(struct arg *the_args);
|
||||||
void destroy_toolcontext(struct cmd_context *cmd);
|
void destroy_toolcontext(struct cmd_context *cmd);
|
||||||
int refresh_toolcontext(struct cmd_context *cmd);
|
int refresh_toolcontext(struct cmd_context *cmd);
|
||||||
|
int config_files_changed(struct cmd_context *cmd);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
#include "crc.h"
|
#include "crc.h"
|
||||||
#include "pool.h"
|
#include "pool.h"
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
|
#include "str_list.h"
|
||||||
|
#include "toolcontext.h"
|
||||||
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
@@ -56,6 +58,7 @@ struct cs {
|
|||||||
struct pool *mem;
|
struct pool *mem;
|
||||||
time_t timestamp;
|
time_t timestamp;
|
||||||
char *filename;
|
char *filename;
|
||||||
|
int exists;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void _get_token(struct parser *p, int tok_prev);
|
static void _get_token(struct parser *p, int tok_prev);
|
||||||
@@ -93,7 +96,7 @@ static int _tok_match(const char *str, const char *b, const char *e)
|
|||||||
/*
|
/*
|
||||||
* public interface
|
* public interface
|
||||||
*/
|
*/
|
||||||
struct config_tree *create_config_tree(void)
|
struct config_tree *create_config_tree(const char *filename)
|
||||||
{
|
{
|
||||||
struct cs *c;
|
struct cs *c;
|
||||||
struct pool *mem = pool_create(10 * 1024);
|
struct pool *mem = pool_create(10 * 1024);
|
||||||
@@ -103,7 +106,7 @@ struct config_tree *create_config_tree(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(c = pool_alloc(mem, sizeof(*c)))) {
|
if (!(c = pool_zalloc(mem, sizeof(*c)))) {
|
||||||
stack;
|
stack;
|
||||||
pool_destroy(mem);
|
pool_destroy(mem);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -112,7 +115,9 @@ struct config_tree *create_config_tree(void)
|
|||||||
c->mem = mem;
|
c->mem = mem;
|
||||||
c->cft.root = (struct config_node *) NULL;
|
c->cft.root = (struct config_node *) NULL;
|
||||||
c->timestamp = 0;
|
c->timestamp = 0;
|
||||||
c->filename = NULL;
|
c->exists = 0;
|
||||||
|
if (filename)
|
||||||
|
c->filename = pool_strdup(c->mem, filename);
|
||||||
return &c->cft;
|
return &c->cft;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,29 +209,33 @@ int read_config_fd(struct config_tree *cft, struct device *dev,
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
int read_config_file(struct config_tree *cft, const char *file)
|
int read_config_file(struct config_tree *cft)
|
||||||
{
|
{
|
||||||
struct cs *c = (struct cs *) cft;
|
struct cs *c = (struct cs *) cft;
|
||||||
struct stat info;
|
struct stat info;
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
int r = 1;
|
int r = 1;
|
||||||
|
|
||||||
if (stat(file, &info)) {
|
if (stat(c->filename, &info)) {
|
||||||
log_sys_error("stat", file);
|
log_sys_error("stat", c->filename);
|
||||||
|
c->exists = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!S_ISREG(info.st_mode)) {
|
if (!S_ISREG(info.st_mode)) {
|
||||||
log_error("%s is not a regular file", file);
|
log_error("%s is not a regular file", c->filename);
|
||||||
|
c->exists = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c->exists = 1;
|
||||||
|
|
||||||
if (info.st_size == 0) {
|
if (info.st_size == 0) {
|
||||||
log_verbose("%s is empty", file);
|
log_verbose("%s is empty", c->filename);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(dev = dev_create_file(file, NULL, NULL))) {
|
if (!(dev = dev_create_file(c->filename, NULL, NULL))) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -242,7 +251,6 @@ int read_config_file(struct config_tree *cft, const char *file)
|
|||||||
dev_close(dev);
|
dev_close(dev);
|
||||||
|
|
||||||
c->timestamp = info.st_mtime;
|
c->timestamp = info.st_mtime;
|
||||||
c->filename = pool_strdup(c->mem, file);
|
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@@ -255,74 +263,43 @@ time_t config_file_timestamp(struct config_tree *cft)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns 1 if config file reloaded
|
* Return 1 if config files ought to be reloaded
|
||||||
*/
|
*/
|
||||||
int reload_config_file(struct config_tree **cft)
|
int config_file_changed(struct config_tree *cft)
|
||||||
{
|
{
|
||||||
struct config_tree *new_cft;
|
struct cs *c = (struct cs *) cft;
|
||||||
struct cs *c = (struct cs *) *cft;
|
|
||||||
struct cs *new_cs;
|
|
||||||
struct stat info;
|
struct stat info;
|
||||||
struct device *dev;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if (!c->filename)
|
if (!c->filename)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (stat(c->filename, &info) == -1) {
|
if (stat(c->filename, &info) == -1) {
|
||||||
if (errno == ENOENT)
|
/* Ignore a deleted config file: still use original data */
|
||||||
return 1;
|
if (errno == ENOENT) {
|
||||||
|
if (!c->exists)
|
||||||
|
return 0;
|
||||||
|
log_very_verbose("Config file %s has disappeared!",
|
||||||
|
c->filename);
|
||||||
|
goto reload;
|
||||||
|
}
|
||||||
log_sys_error("stat", c->filename);
|
log_sys_error("stat", c->filename);
|
||||||
log_error("Failed to reload configuration file");
|
log_error("Failed to reload configuration files");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!S_ISREG(info.st_mode)) {
|
if (!S_ISREG(info.st_mode)) {
|
||||||
log_error("Configuration file %s is not a regular file",
|
log_error("Configuration file %s is not a regular file",
|
||||||
c->filename);
|
c->filename);
|
||||||
return 0;
|
goto reload;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Unchanged? */
|
/* Unchanged? */
|
||||||
if (c->timestamp == info.st_mtime)
|
if (c->timestamp == info.st_mtime)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
log_verbose("Detected config file change: Reloading %s", c->filename);
|
reload:
|
||||||
|
log_verbose("Detected config file change to %s", c->filename);
|
||||||
if (info.st_size == 0) {
|
return 1;
|
||||||
log_verbose("Config file reload: %s is empty", c->filename);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(new_cft = create_config_tree())) {
|
|
||||||
log_error("Allocation of new config_tree failed");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(dev = dev_create_file(c->filename, NULL, NULL))) {
|
|
||||||
stack;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!dev_open_flags(dev, O_RDONLY, 0, 0)) {
|
|
||||||
stack;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = read_config_fd(new_cft, dev, 0, (size_t) info.st_size,
|
|
||||||
0, 0, (checksum_fn_t) NULL, 0);
|
|
||||||
|
|
||||||
dev_close(dev);
|
|
||||||
|
|
||||||
if (r) {
|
|
||||||
new_cs = (struct cs *) new_cft;
|
|
||||||
new_cs->filename = pool_strdup(new_cs->mem, c->filename);
|
|
||||||
new_cs->timestamp = info.st_mtime;
|
|
||||||
destroy_config_tree(*cft);
|
|
||||||
*cft = new_cft;
|
|
||||||
}
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _write_value(FILE *fp, struct config_value *v)
|
static void _write_value(FILE *fp, struct config_value *v)
|
||||||
@@ -739,7 +716,8 @@ static char *_dup_tok(struct parser *p)
|
|||||||
/*
|
/*
|
||||||
* utility functions
|
* utility functions
|
||||||
*/
|
*/
|
||||||
struct config_node *find_config_node(struct config_node *cn, const char *path)
|
struct config_node *find_config_node(const struct config_node *cn,
|
||||||
|
const char *path)
|
||||||
{
|
{
|
||||||
const char *e;
|
const char *e;
|
||||||
|
|
||||||
@@ -767,13 +745,13 @@ struct config_node *find_config_node(struct config_node *cn, const char *path)
|
|||||||
path = e;
|
path = e;
|
||||||
}
|
}
|
||||||
|
|
||||||
return cn;
|
return (struct config_node *) cn;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *find_config_str(struct config_node *cn,
|
const char *find_config_str(const struct config_node *cn,
|
||||||
const char *path, const char *fail)
|
const char *path, const char *fail)
|
||||||
{
|
{
|
||||||
struct config_node *n = find_config_node(cn, path);
|
const struct config_node *n = find_config_node(cn, path);
|
||||||
|
|
||||||
if (n && n->v->type == CFG_STRING) {
|
if (n && n->v->type == CFG_STRING) {
|
||||||
if (*n->v->v.str)
|
if (*n->v->v.str)
|
||||||
@@ -787,9 +765,9 @@ const char *find_config_str(struct config_node *cn,
|
|||||||
return fail;
|
return fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
int find_config_int(struct config_node *cn, const char *path, int fail)
|
int find_config_int(const struct config_node *cn, const char *path, int fail)
|
||||||
{
|
{
|
||||||
struct config_node *n = find_config_node(cn, path);
|
const struct config_node *n = find_config_node(cn, path);
|
||||||
|
|
||||||
if (n && n->v->type == CFG_INT) {
|
if (n && n->v->type == CFG_INT) {
|
||||||
log_very_verbose("Setting %s to %d", path, n->v->v.i);
|
log_very_verbose("Setting %s to %d", path, n->v->v.i);
|
||||||
@@ -801,9 +779,10 @@ int find_config_int(struct config_node *cn, const char *path, int fail)
|
|||||||
return fail;
|
return fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
float find_config_float(struct config_node *cn, const char *path, float fail)
|
float find_config_float(const struct config_node *cn, const char *path,
|
||||||
|
float fail)
|
||||||
{
|
{
|
||||||
struct config_node *n = find_config_node(cn, path);
|
const struct config_node *n = find_config_node(cn, path);
|
||||||
|
|
||||||
if (n && n->v->type == CFG_FLOAT) {
|
if (n && n->v->type == CFG_FLOAT) {
|
||||||
log_very_verbose("Setting %s to %f", path, n->v->v.r);
|
log_very_verbose("Setting %s to %f", path, n->v->v.r);
|
||||||
@@ -843,9 +822,9 @@ static int _str_to_bool(const char *str, int fail)
|
|||||||
return fail;
|
return fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
int find_config_bool(struct config_node *cn, const char *path, int fail)
|
int find_config_bool(const struct config_node *cn, const char *path, int fail)
|
||||||
{
|
{
|
||||||
struct config_node *n = find_config_node(cn, path);
|
const struct config_node *n = find_config_node(cn, path);
|
||||||
struct config_value *v;
|
struct config_value *v;
|
||||||
|
|
||||||
if (!n)
|
if (!n)
|
||||||
@@ -864,10 +843,10 @@ int find_config_bool(struct config_node *cn, const char *path, int fail)
|
|||||||
return fail;
|
return fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_config_uint32(struct config_node *cn, const char *path,
|
int get_config_uint32(const struct config_node *cn, const char *path,
|
||||||
uint32_t *result)
|
uint32_t *result)
|
||||||
{
|
{
|
||||||
struct config_node *n;
|
const struct config_node *n;
|
||||||
|
|
||||||
n = find_config_node(cn, path);
|
n = find_config_node(cn, path);
|
||||||
|
|
||||||
@@ -878,10 +857,10 @@ int get_config_uint32(struct config_node *cn, const char *path,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_config_uint64(struct config_node *cn, const char *path,
|
int get_config_uint64(const struct config_node *cn, const char *path,
|
||||||
uint64_t *result)
|
uint64_t *result)
|
||||||
{
|
{
|
||||||
struct config_node *n;
|
const struct config_node *n;
|
||||||
|
|
||||||
n = find_config_node(cn, path);
|
n = find_config_node(cn, path);
|
||||||
|
|
||||||
@@ -893,9 +872,10 @@ int get_config_uint64(struct config_node *cn, const char *path,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_config_str(struct config_node *cn, const char *path, char **result)
|
int get_config_str(const struct config_node *cn, const char *path,
|
||||||
|
char **result)
|
||||||
{
|
{
|
||||||
struct config_node *n;
|
const struct config_node *n;
|
||||||
|
|
||||||
n = find_config_node(cn, path);
|
n = find_config_node(cn, path);
|
||||||
|
|
||||||
@@ -905,3 +885,115 @@ int get_config_str(struct config_node *cn, const char *path, char **result)
|
|||||||
*result = n->v->v.str;
|
*result = n->v->v.str;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Insert cn2 after cn1 */
|
||||||
|
static void _insert_config_node(struct config_node **cn1,
|
||||||
|
struct config_node *cn2)
|
||||||
|
{
|
||||||
|
if (!*cn1) {
|
||||||
|
*cn1 = cn2;
|
||||||
|
cn2->sib = NULL;
|
||||||
|
} else {
|
||||||
|
cn2->sib = (*cn1)->sib;
|
||||||
|
(*cn1)->sib = cn2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Merge section cn2 into section cn1 (which has the same name)
|
||||||
|
* overwriting any existing cn1 nodes with matching names.
|
||||||
|
*/
|
||||||
|
static void _merge_section(struct config_node *cn1, struct config_node *cn2)
|
||||||
|
{
|
||||||
|
struct config_node *cn, *nextn, *oldn;
|
||||||
|
struct config_value *cv;
|
||||||
|
|
||||||
|
for (cn = cn2->child; cn; cn = nextn) {
|
||||||
|
nextn = cn->sib;
|
||||||
|
|
||||||
|
/* Skip "tags" */
|
||||||
|
if (!strcmp(cn->key, "tags"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Subsection? */
|
||||||
|
if (!cn->v)
|
||||||
|
/* Ignore - we don't have any of these yet */
|
||||||
|
continue;
|
||||||
|
/* Not already present? */
|
||||||
|
if (!(oldn = find_config_node(cn1->child, cn->key))) {
|
||||||
|
_insert_config_node(&cn1->child, cn);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Merge certain value lists */
|
||||||
|
if ((!strcmp(cn1->key, "activation") &&
|
||||||
|
!strcmp(cn->key, "volume_list")) ||
|
||||||
|
(!strcmp(cn1->key, "devices") &&
|
||||||
|
(!strcmp(cn->key, "filter") || !strcmp(cn->key, "types")))) {
|
||||||
|
cv = cn->v;
|
||||||
|
while (cv->next)
|
||||||
|
cv = cv->next;
|
||||||
|
cv->next = oldn->v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Replace values */
|
||||||
|
oldn->v = cn->v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _match_host_tags(struct list *tags, struct config_node *tn)
|
||||||
|
{
|
||||||
|
struct config_value *tv;
|
||||||
|
const char *str;
|
||||||
|
|
||||||
|
for (tv = tn->v; tv; tv = tv->next) {
|
||||||
|
if (tv->type != CFG_STRING)
|
||||||
|
continue;
|
||||||
|
str = tv->v.str;
|
||||||
|
if (*str == '@')
|
||||||
|
str++;
|
||||||
|
if (!*str)
|
||||||
|
continue;
|
||||||
|
if (str_list_match_item(tags, str))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Destructively merge a new config tree into an existing one */
|
||||||
|
int merge_config_tree(struct cmd_context *cmd, struct config_tree *cft,
|
||||||
|
struct config_tree *newdata)
|
||||||
|
{
|
||||||
|
struct config_node *root = cft->root;
|
||||||
|
struct config_node *cn, *nextn, *oldn, *tn, *cn2;
|
||||||
|
|
||||||
|
for (cn = newdata->root; cn; cn = nextn) {
|
||||||
|
nextn = cn->sib;
|
||||||
|
/* Ignore tags section */
|
||||||
|
if (!strcmp(cn->key, "tags"))
|
||||||
|
continue;
|
||||||
|
/* If there's a tags node, skip if host tags don't match */
|
||||||
|
if ((tn = find_config_node(cn->child, "tags"))) {
|
||||||
|
if (!_match_host_tags(&cmd->tags, tn))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!(oldn = find_config_node(root, cn->key))) {
|
||||||
|
_insert_config_node(&cft->root, cn);
|
||||||
|
/* Remove any "tags" nodes */
|
||||||
|
for (cn2 = cn->child; cn2; cn2 = cn2->sib) {
|
||||||
|
if (!strcmp(cn2->key, "tags")) {
|
||||||
|
cn->child = cn2->sib;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (cn2->sib && !strcmp(cn2->sib->key, "tags")) {
|
||||||
|
cn2->sib = cn2->sib->sib;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
_merge_section(oldn, cn);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,7 +16,8 @@
|
|||||||
#ifndef _LVM_CONFIG_H
|
#ifndef _LVM_CONFIG_H
|
||||||
#define _LVM_CONFIG_H
|
#define _LVM_CONFIG_H
|
||||||
|
|
||||||
#include "device.h"
|
struct device;
|
||||||
|
struct cmd_context;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
CFG_STRING,
|
CFG_STRING,
|
||||||
@@ -45,42 +46,51 @@ struct config_tree {
|
|||||||
struct config_node *root;
|
struct config_node *root;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct config_tree *create_config_tree(void);
|
struct config_tree_list {
|
||||||
void destroy_config_tree(struct config_tree *cf);
|
struct list list;
|
||||||
|
struct config_tree *cft;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct config_tree *create_config_tree(const char *filename);
|
||||||
|
void destroy_config_tree(struct config_tree *cft);
|
||||||
|
|
||||||
typedef uint32_t (*checksum_fn_t) (uint32_t initial, void *buf, uint32_t size);
|
typedef uint32_t (*checksum_fn_t) (uint32_t initial, void *buf, uint32_t size);
|
||||||
|
|
||||||
int read_config_fd(struct config_tree *cf, struct device *dev,
|
int read_config_fd(struct config_tree *cft, struct device *dev,
|
||||||
off_t offset, size_t size, off_t offset2, size_t size2,
|
off_t offset, size_t size, off_t offset2, size_t size2,
|
||||||
checksum_fn_t checksum_fn, uint32_t checksum);
|
checksum_fn_t checksum_fn, uint32_t checksum);
|
||||||
|
|
||||||
int read_config_file(struct config_tree *cf, const char *file);
|
int read_config_file(struct config_tree *cft);
|
||||||
int write_config_file(struct config_tree *cf, const char *file);
|
int write_config_file(struct config_tree *cft, const char *file);
|
||||||
int reload_config_file(struct config_tree **cf);
|
time_t config_file_timestamp(struct config_tree *cft);
|
||||||
time_t config_file_timestamp(struct config_tree *cf);
|
int config_file_changed(struct config_tree *cft);
|
||||||
|
int merge_config_tree(struct cmd_context *cmd, struct config_tree *cft,
|
||||||
|
struct config_tree *newdata);
|
||||||
|
|
||||||
struct config_node *find_config_node(struct config_node *cn,
|
struct config_node *find_config_node(const struct config_node *cn,
|
||||||
const char *path);
|
const char *path);
|
||||||
|
|
||||||
const char *find_config_str(struct config_node *cn, const char *path,
|
const char *find_config_str(const struct config_node *cn, const char *path,
|
||||||
const char *fail);
|
const char *fail);
|
||||||
|
|
||||||
int find_config_int(struct config_node *cn, const char *path, int fail);
|
int find_config_int(const struct config_node *cn, const char *path, int fail);
|
||||||
|
|
||||||
float find_config_float(struct config_node *cn, const char *path, float fail);
|
float find_config_float(const struct config_node *cn, const char *path,
|
||||||
|
float fail);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Understands (0, ~0), (y, n), (yes, no), (on,
|
* Understands (0, ~0), (y, n), (yes, no), (on,
|
||||||
* off), (true, false).
|
* off), (true, false).
|
||||||
*/
|
*/
|
||||||
int find_config_bool(struct config_node *cn, const char *path, int fail);
|
int find_config_bool(const struct config_node *cn, const char *path, int fail);
|
||||||
|
|
||||||
int get_config_uint32(struct config_node *cn, const char *path,
|
int get_config_uint32(const struct config_node *cn, const char *path,
|
||||||
uint32_t *result);
|
uint32_t *result);
|
||||||
|
|
||||||
int get_config_uint64(struct config_node *cn, const char *path,
|
int get_config_uint64(const struct config_node *cn, const char *path,
|
||||||
uint64_t *result);
|
uint64_t *result);
|
||||||
|
|
||||||
int get_config_str(struct config_node *cn, const char *path, char **result);
|
int get_config_str(const struct config_node *cn, const char *path,
|
||||||
|
char **result);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -91,14 +91,14 @@
|
|||||||
#define DEFAULT_REP_HEADINGS 1
|
#define DEFAULT_REP_HEADINGS 1
|
||||||
#define DEFAULT_REP_SEPARATOR " "
|
#define DEFAULT_REP_SEPARATOR " "
|
||||||
|
|
||||||
#define DEFAULT_LVS_COLS "lv_name,vg_name,lv_attr,lv_size,origin,snap_percent,move_pv,move_percent"
|
#define DEFAULT_LVS_COLS "lv_name,vg_name,lv_attr,lv_size,origin,snap_percent,move_pv,copy_percent"
|
||||||
#define DEFAULT_VGS_COLS "vg_name,pv_count,lv_count,snap_count,vg_attr,vg_size,vg_free"
|
#define DEFAULT_VGS_COLS "vg_name,pv_count,lv_count,snap_count,vg_attr,vg_size,vg_free"
|
||||||
#define DEFAULT_PVS_COLS "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free"
|
#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_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,move_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_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_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"
|
#define DEFAULT_LVS_SORT "vg_name,lv_name"
|
||||||
|
|||||||
@@ -19,7 +19,8 @@
|
|||||||
struct hash_node {
|
struct hash_node {
|
||||||
struct hash_node *next;
|
struct hash_node *next;
|
||||||
void *data;
|
void *data;
|
||||||
char key[1];
|
int keylen;
|
||||||
|
char key[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct hash_table {
|
struct hash_table {
|
||||||
@@ -56,22 +57,23 @@ static unsigned char _nums[] = {
|
|||||||
209
|
209
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct hash_node *_create_node(const char *str)
|
static struct hash_node *_create_node(const char *str, int len)
|
||||||
{
|
{
|
||||||
/* remember sizeof(n) includes an extra char from key[1],
|
struct hash_node *n = dbg_malloc(sizeof(*n) + len);
|
||||||
so not adding 1 to the strlen as you would expect */
|
|
||||||
struct hash_node *n = dbg_malloc(sizeof(*n) + strlen(str));
|
|
||||||
|
|
||||||
if (n)
|
if (n) {
|
||||||
strcpy(n->key, str);
|
memcpy(n->key, str, len);
|
||||||
|
n->keylen = len;
|
||||||
|
}
|
||||||
|
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned _hash(const char *str)
|
static unsigned _hash(const char *str, uint32_t len)
|
||||||
{
|
{
|
||||||
unsigned long h = 0, g;
|
unsigned long h = 0, g, i;
|
||||||
while (*str) {
|
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
h <<= 4;
|
h <<= 4;
|
||||||
h += _nums[(int) *str++];
|
h += _nums[(int) *str++];
|
||||||
g = h & ((unsigned long) 0xf << 16u);
|
g = h & ((unsigned long) 0xf << 16u);
|
||||||
@@ -80,6 +82,7 @@ static unsigned _hash(const char *str)
|
|||||||
h ^= g >> 5u;
|
h ^= g >> 5u;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,32 +137,35 @@ void hash_destroy(struct hash_table *t)
|
|||||||
dbg_free(t);
|
dbg_free(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct hash_node **_find(struct hash_table *t, const char *key)
|
static inline struct hash_node **_find(struct hash_table *t, const char *key,
|
||||||
|
uint32_t len)
|
||||||
{
|
{
|
||||||
unsigned h = _hash(key) & (t->num_slots - 1);
|
unsigned h = _hash(key, len) & (t->num_slots - 1);
|
||||||
struct hash_node **c;
|
struct hash_node **c;
|
||||||
|
|
||||||
for (c = &t->slots[h]; *c; c = &((*c)->next))
|
for (c = &t->slots[h]; *c; c = &((*c)->next))
|
||||||
if (!strcmp(key, (*c)->key))
|
if (!memcmp(key, (*c)->key, len))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *hash_lookup(struct hash_table *t, const char *key)
|
void *hash_lookup_binary(struct hash_table *t, const char *key,
|
||||||
|
uint32_t len)
|
||||||
{
|
{
|
||||||
struct hash_node **c = _find(t, key);
|
struct hash_node **c = _find(t, key, len);
|
||||||
return *c ? (*c)->data : 0;
|
return *c ? (*c)->data : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int hash_insert(struct hash_table *t, const char *key, void *data)
|
int hash_insert_binary(struct hash_table *t, const char *key,
|
||||||
|
uint32_t len, void *data)
|
||||||
{
|
{
|
||||||
struct hash_node **c = _find(t, key);
|
struct hash_node **c = _find(t, key, len);
|
||||||
|
|
||||||
if (*c)
|
if (*c)
|
||||||
(*c)->data = data;
|
(*c)->data = data;
|
||||||
else {
|
else {
|
||||||
struct hash_node *n = _create_node(key);
|
struct hash_node *n = _create_node(key, len);
|
||||||
|
|
||||||
if (!n)
|
if (!n)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -173,9 +179,10 @@ int hash_insert(struct hash_table *t, const char *key, void *data)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void hash_remove(struct hash_table *t, const char *key)
|
void hash_remove_binary(struct hash_table *t, const char *key,
|
||||||
|
uint32_t len)
|
||||||
{
|
{
|
||||||
struct hash_node **c = _find(t, key);
|
struct hash_node **c = _find(t, key, len);
|
||||||
|
|
||||||
if (*c) {
|
if (*c) {
|
||||||
struct hash_node *old = *c;
|
struct hash_node *old = *c;
|
||||||
@@ -185,6 +192,21 @@ void hash_remove(struct hash_table *t, const char *key)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *hash_lookup(struct hash_table *t, const char *key)
|
||||||
|
{
|
||||||
|
return hash_lookup_binary(t, key, strlen(key) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int hash_insert(struct hash_table *t, const char *key, void *data)
|
||||||
|
{
|
||||||
|
return hash_insert_binary(t, key, strlen(key) + 1, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hash_remove(struct hash_table *t, const char *key)
|
||||||
|
{
|
||||||
|
hash_remove_binary(t, key, strlen(key) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
unsigned hash_get_num_entries(struct hash_table *t)
|
unsigned hash_get_num_entries(struct hash_table *t)
|
||||||
{
|
{
|
||||||
return t->num_nodes;
|
return t->num_nodes;
|
||||||
@@ -235,6 +257,6 @@ struct hash_node *hash_get_first(struct hash_table *t)
|
|||||||
|
|
||||||
struct hash_node *hash_get_next(struct hash_table *t, struct hash_node *n)
|
struct hash_node *hash_get_next(struct hash_table *t, struct hash_node *n)
|
||||||
{
|
{
|
||||||
unsigned h = _hash(n->key) & (t->num_slots - 1);
|
unsigned h = _hash(n->key, n->keylen) & (t->num_slots - 1);
|
||||||
return n->next ? n->next : _next_slot(t, h + 1);
|
return n->next ? n->next : _next_slot(t, h + 1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,10 +26,14 @@ void hash_destroy(struct hash_table *t);
|
|||||||
void hash_wipe(struct hash_table *t);
|
void hash_wipe(struct hash_table *t);
|
||||||
|
|
||||||
void *hash_lookup(struct hash_table *t, const char *key);
|
void *hash_lookup(struct hash_table *t, const char *key);
|
||||||
void *hash_lookup_fixed(struct hash_table *t, const char *key, uint32_t len);
|
|
||||||
int hash_insert(struct hash_table *t, const char *key, void *data);
|
int hash_insert(struct hash_table *t, const char *key, void *data);
|
||||||
void hash_remove(struct hash_table *t, const char *key);
|
void hash_remove(struct hash_table *t, const char *key);
|
||||||
|
|
||||||
|
void *hash_lookup_binary(struct hash_table *t, const char *key, uint32_t len);
|
||||||
|
int hash_insert_binary(struct hash_table *t, const char *key, uint32_t len,
|
||||||
|
void *data);
|
||||||
|
void hash_remove_binary(struct hash_table *t, const char *key, uint32_t len);
|
||||||
|
|
||||||
unsigned hash_get_num_entries(struct hash_table *t);
|
unsigned hash_get_num_entries(struct hash_table *t);
|
||||||
void hash_iter(struct hash_table *t, iterate_fn f);
|
void hash_iter(struct hash_table *t, iterate_fn f);
|
||||||
|
|
||||||
|
|||||||
@@ -212,7 +212,7 @@ static int _aligned_io(struct device_area *where, void *buffer,
|
|||||||
* Public functions
|
* 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;
|
int fd;
|
||||||
const char *name = dev_name(dev);
|
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;
|
flags |= O_DIRECT;
|
||||||
#endif
|
#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) {
|
if ((dev->fd = open(name, flags, 0777)) < 0) {
|
||||||
log_sys_error("open", name);
|
log_sys_error("open", name);
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ struct device_area {
|
|||||||
/*
|
/*
|
||||||
* All io should use these routines.
|
* 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);
|
int dev_get_sectsize(struct device *dev, uint32_t *size);
|
||||||
|
|
||||||
/* Use quiet version if device number could change e.g. when opening LV */
|
/* Use quiet version if device number could change e.g. when opening LV */
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include "activate.h"
|
#include "activate.h"
|
||||||
#include "toolcontext.h"
|
#include "toolcontext.h"
|
||||||
|
#include "segtype.h"
|
||||||
|
|
||||||
#define SIZE_BUF 128
|
#define SIZE_BUF 128
|
||||||
|
|
||||||
@@ -26,23 +27,13 @@ static struct {
|
|||||||
const char *str;
|
const char *str;
|
||||||
} _policies[] = {
|
} _policies[] = {
|
||||||
{
|
{
|
||||||
ALLOC_NEXT_FREE, "next free"}, {
|
|
||||||
ALLOC_CONTIGUOUS, "contiguous"}, {
|
ALLOC_CONTIGUOUS, "contiguous"}, {
|
||||||
ALLOC_DEFAULT, "next free (default)"}
|
ALLOC_NORMAL, "normal"}, {
|
||||||
};
|
ALLOC_ANYWHERE, "anywhere"}, {
|
||||||
|
ALLOC_INHERIT, "inherit"}
|
||||||
static struct {
|
|
||||||
segment_type_t segtype;
|
|
||||||
const char *str;
|
|
||||||
} _segtypes[] = {
|
|
||||||
{
|
|
||||||
SEG_STRIPED, "striped"}, {
|
|
||||||
SEG_MIRRORED, "mirror"}, {
|
|
||||||
SEG_SNAPSHOT, "snapshot"}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int _num_policies = sizeof(_policies) / sizeof(*_policies);
|
static int _num_policies = sizeof(_policies) / sizeof(*_policies);
|
||||||
static int _num_segtypes = sizeof(_segtypes) / sizeof(*_segtypes);
|
|
||||||
|
|
||||||
uint64_t units_to_bytes(const char *units, char *unit_type)
|
uint64_t units_to_bytes(const char *units, char *unit_type)
|
||||||
{
|
{
|
||||||
@@ -124,17 +115,6 @@ const char *get_alloc_string(alloc_policy_t alloc)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *get_segtype_string(segment_type_t segtype)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < _num_segtypes; i++)
|
|
||||||
if (_segtypes[i].segtype == segtype)
|
|
||||||
return _segtypes[i].str;
|
|
||||||
|
|
||||||
return "unknown";
|
|
||||||
}
|
|
||||||
|
|
||||||
alloc_policy_t get_alloc_from_string(const char *str)
|
alloc_policy_t get_alloc_from_string(const char *str)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@@ -143,26 +123,19 @@ alloc_policy_t get_alloc_from_string(const char *str)
|
|||||||
if (!strcmp(_policies[i].str, str))
|
if (!strcmp(_policies[i].str, str))
|
||||||
return _policies[i].alloc;
|
return _policies[i].alloc;
|
||||||
|
|
||||||
log_error("Unrecognised allocation policy - using default");
|
/* Special case for old metadata */
|
||||||
return ALLOC_DEFAULT;
|
if(!strcmp("next free", str))
|
||||||
}
|
return ALLOC_NORMAL;
|
||||||
|
|
||||||
segment_type_t get_segtype_from_string(const char *str)
|
log_error("Unrecognised allocation policy %s", str);
|
||||||
{
|
return ALLOC_INVALID;
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < _num_segtypes; i++)
|
|
||||||
if (!strcmp(_segtypes[i].str, str))
|
|
||||||
return _segtypes[i].segtype;
|
|
||||||
|
|
||||||
log_error("Unrecognised segment type - using default (striped)");
|
|
||||||
return SEG_STRIPED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Size supplied in sectors */
|
||||||
const char *display_size(struct cmd_context *cmd, uint64_t size, size_len_t sl)
|
const char *display_size(struct cmd_context *cmd, uint64_t size, size_len_t sl)
|
||||||
{
|
{
|
||||||
int s;
|
int s;
|
||||||
int suffix = 1;
|
int suffix = 1, precision;
|
||||||
uint64_t byte = UINT64_C(0);
|
uint64_t byte = UINT64_C(0);
|
||||||
uint64_t units = UINT64_C(1024);
|
uint64_t units = UINT64_C(1024);
|
||||||
char *size_buf = NULL;
|
char *size_buf = NULL;
|
||||||
@@ -197,8 +170,9 @@ const char *display_size(struct cmd_context *cmd, uint64_t size, size_len_t sl)
|
|||||||
|
|
||||||
if (s < 8) {
|
if (s < 8) {
|
||||||
byte = cmd->current_settings.unit_factor;
|
byte = cmd->current_settings.unit_factor;
|
||||||
size *= UINT64_C(1024);
|
size *= UINT64_C(512);
|
||||||
} else {
|
} else {
|
||||||
|
size /= 2;
|
||||||
suffix = 1;
|
suffix = 1;
|
||||||
if (cmd->current_settings.unit_type == 'H')
|
if (cmd->current_settings.unit_type == 'H')
|
||||||
units = UINT64_C(1000);
|
units = UINT64_C(1000);
|
||||||
@@ -210,8 +184,18 @@ const char *display_size(struct cmd_context *cmd, uint64_t size, size_len_t sl)
|
|||||||
s++, byte /= units;
|
s++, byte /= units;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(size_buf, SIZE_BUF - 1, "%.2f%s", (float) size / byte,
|
/* FIXME Make precision configurable */
|
||||||
suffix ? size_str[s][sl] : "");
|
switch(toupper((int) cmd->current_settings.unit_type)) {
|
||||||
|
case 'B':
|
||||||
|
case 'S':
|
||||||
|
precision = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
precision = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(size_buf, SIZE_BUF - 1, "%.*f%s", precision,
|
||||||
|
(double) size / byte, suffix ? size_str[s][sl] : "");
|
||||||
|
|
||||||
return size_buf;
|
return size_buf;
|
||||||
}
|
}
|
||||||
@@ -264,18 +248,18 @@ void pvdisplay_full(struct cmd_context *cmd, struct physical_volume *pv,
|
|||||||
log_print("VG Name %s%s", pv->vg_name,
|
log_print("VG Name %s%s", pv->vg_name,
|
||||||
pv->status & EXPORTED_VG ? " (exported)" : "");
|
pv->status & EXPORTED_VG ? " (exported)" : "");
|
||||||
|
|
||||||
size = display_size(cmd, (uint64_t) pv->size / 2, SIZE_SHORT);
|
size = display_size(cmd, (uint64_t) pv->size, SIZE_SHORT);
|
||||||
if (pv->pe_size && pv->pe_count) {
|
if (pv->pe_size && pv->pe_count) {
|
||||||
|
|
||||||
/******** FIXME display LVM on-disk data size
|
/******** FIXME display LVM on-disk data size
|
||||||
size2 = display_size(pv->size / 2, SIZE_SHORT);
|
size2 = display_size(pv->size, SIZE_SHORT);
|
||||||
********/
|
********/
|
||||||
|
|
||||||
log_print("PV Size %s" " / not usable %s", /* [LVM: %s]", */
|
log_print("PV Size %s" " / not usable %s", /* [LVM: %s]", */
|
||||||
size, display_size(cmd,
|
size,
|
||||||
(pv->size -
|
display_size(cmd, (pv->size -
|
||||||
pv->pe_count * pv->pe_size) / 2,
|
pv->pe_count * pv->pe_size),
|
||||||
SIZE_SHORT));
|
SIZE_SHORT));
|
||||||
|
|
||||||
} else
|
} else
|
||||||
log_print("PV Size %s", size);
|
log_print("PV Size %s", size);
|
||||||
@@ -386,8 +370,7 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
|
|||||||
snap_active = lv_snapshot_percent(snap->cow,
|
snap_active = lv_snapshot_percent(snap->cow,
|
||||||
&snap_percent);
|
&snap_percent);
|
||||||
if (!snap_active || snap_percent < 0 ||
|
if (!snap_active || snap_percent < 0 ||
|
||||||
snap_percent >= 100)
|
snap_percent >= 100) snap_active = 0;
|
||||||
snap_active = 0;
|
|
||||||
log_print(" %s%s/%s [%s]",
|
log_print(" %s%s/%s [%s]",
|
||||||
lv->vg->cmd->dev_dir, lv->vg->name,
|
lv->vg->cmd->dev_dir, lv->vg->name,
|
||||||
snap->cow->name,
|
snap->cow->name,
|
||||||
@@ -419,7 +402,7 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
|
|||||||
|
|
||||||
log_print("LV Size %s",
|
log_print("LV Size %s",
|
||||||
display_size(cmd,
|
display_size(cmd,
|
||||||
snap ? snap->origin->size / 2 : lv->size / 2,
|
snap ? snap->origin->size : lv->size,
|
||||||
SIZE_SHORT));
|
SIZE_SHORT));
|
||||||
|
|
||||||
log_print("Current LE %u",
|
log_print("Current LE %u",
|
||||||
@@ -440,11 +423,11 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
|
|||||||
snap_percent = 100;
|
snap_percent = 100;
|
||||||
|
|
||||||
log_print("Snapshot chunk size %s",
|
log_print("Snapshot chunk size %s",
|
||||||
display_size(cmd, (uint64_t) snap->chunk_size / 2,
|
display_size(cmd, (uint64_t) snap->chunk_size,
|
||||||
SIZE_SHORT));
|
SIZE_SHORT));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
size = display_size(lv->size / 2, SIZE_SHORT);
|
size = display_size(lv->size, SIZE_SHORT);
|
||||||
sscanf(size, "%f", &fsize);
|
sscanf(size, "%f", &fsize);
|
||||||
fused = fsize * snap_percent / 100;
|
fused = fsize * snap_percent / 100;
|
||||||
*/
|
*/
|
||||||
@@ -478,7 +461,7 @@ int lvdisplay_full(struct cmd_context *cmd, struct logical_volume *lv,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _display_stripe(struct lv_segment *seg, uint32_t s, const char *pre)
|
void display_stripe(const struct lv_segment *seg, uint32_t s, const char *pre)
|
||||||
{
|
{
|
||||||
switch (seg->area[s].type) {
|
switch (seg->area[s].type) {
|
||||||
case AREA_PV:
|
case AREA_PV:
|
||||||
@@ -506,52 +489,18 @@ static void _display_stripe(struct lv_segment *seg, uint32_t s, const char *pre)
|
|||||||
|
|
||||||
int lvdisplay_segments(struct logical_volume *lv)
|
int lvdisplay_segments(struct logical_volume *lv)
|
||||||
{
|
{
|
||||||
uint32_t s;
|
|
||||||
struct list *segh;
|
|
||||||
struct lv_segment *seg;
|
struct lv_segment *seg;
|
||||||
|
|
||||||
log_print("--- Segments ---");
|
log_print("--- Segments ---");
|
||||||
|
|
||||||
list_iterate(segh, &lv->segments) {
|
list_iterate_items(seg, &lv->segments) {
|
||||||
seg = list_item(segh, struct lv_segment);
|
|
||||||
|
|
||||||
log_print("Logical extent %u to %u:",
|
log_print("Logical extent %u to %u:",
|
||||||
seg->le, seg->le + seg->len - 1);
|
seg->le, seg->le + seg->len - 1);
|
||||||
|
|
||||||
if (seg->type == SEG_STRIPED && seg->area_count == 1)
|
log_print(" Type\t\t%s", seg->segtype->ops->name(seg));
|
||||||
log_print(" Type\t\tlinear");
|
|
||||||
else
|
|
||||||
log_print(" Type\t\t%s",
|
|
||||||
get_segtype_string(seg->type));
|
|
||||||
|
|
||||||
switch (seg->type) {
|
if (seg->segtype->ops->display)
|
||||||
case SEG_STRIPED:
|
seg->segtype->ops->display(seg);
|
||||||
if (seg->area_count == 1)
|
|
||||||
_display_stripe(seg, 0, " ");
|
|
||||||
else {
|
|
||||||
log_print(" Stripes\t\t%u", seg->area_count);
|
|
||||||
log_print(" Stripe size\t\t%u KB",
|
|
||||||
seg->stripe_size / 2);
|
|
||||||
|
|
||||||
for (s = 0; s < seg->area_count; s++) {
|
|
||||||
log_print(" Stripe %d:", s);
|
|
||||||
_display_stripe(seg, s, " ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log_print(" ");
|
|
||||||
break;
|
|
||||||
case SEG_SNAPSHOT:
|
|
||||||
break;
|
|
||||||
case SEG_MIRRORED:
|
|
||||||
log_print(" Mirrors\t\t%u", seg->area_count);
|
|
||||||
log_print(" Mirror size\t\t%u", seg->area_len);
|
|
||||||
log_print(" Mirror original:");
|
|
||||||
_display_stripe(seg, 0, " ");
|
|
||||||
log_print(" Mirror destination:");
|
|
||||||
_display_stripe(seg, 1, " ");
|
|
||||||
log_print(" ");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log_print(" ");
|
log_print(" ");
|
||||||
@@ -605,7 +554,7 @@ void vgdisplay_full(struct volume_group *vg)
|
|||||||
log_print("Open LV %u", lvs_in_vg_opened(vg));
|
log_print("Open LV %u", lvs_in_vg_opened(vg));
|
||||||
/****** FIXME Max LV Size
|
/****** FIXME Max LV Size
|
||||||
log_print ( "MAX LV Size %s",
|
log_print ( "MAX LV Size %s",
|
||||||
( s1 = display_size ( LVM_LV_SIZE_MAX(vg) / 2, SIZE_SHORT)));
|
( s1 = display_size ( LVM_LV_SIZE_MAX(vg), SIZE_SHORT)));
|
||||||
free ( s1);
|
free ( s1);
|
||||||
*********/
|
*********/
|
||||||
log_print("Max PV %u", vg->max_pv);
|
log_print("Max PV %u", vg->max_pv);
|
||||||
@@ -614,32 +563,25 @@ void vgdisplay_full(struct volume_group *vg)
|
|||||||
|
|
||||||
log_print("VG Size %s",
|
log_print("VG Size %s",
|
||||||
display_size(vg->cmd,
|
display_size(vg->cmd,
|
||||||
(uint64_t) vg->extent_count * (vg->extent_size /
|
(uint64_t) vg->extent_count * vg->extent_size,
|
||||||
2), SIZE_SHORT));
|
SIZE_SHORT));
|
||||||
|
|
||||||
log_print("PE Size %s",
|
log_print("PE Size %s",
|
||||||
display_size(vg->cmd, (uint64_t) vg->extent_size / 2,
|
display_size(vg->cmd, (uint64_t) vg->extent_size,
|
||||||
SIZE_SHORT));
|
SIZE_SHORT));
|
||||||
|
|
||||||
log_print("Total PE %u", vg->extent_count);
|
log_print("Total PE %u", vg->extent_count);
|
||||||
|
|
||||||
log_print("Alloc PE / Size %u / %s",
|
log_print("Alloc PE / Size %u / %s",
|
||||||
vg->extent_count - vg->free_count, display_size(vg->cmd,
|
vg->extent_count - vg->free_count,
|
||||||
((uint64_t)
|
display_size(vg->cmd,
|
||||||
vg->
|
((uint64_t) vg->extent_count - vg->free_count) *
|
||||||
extent_count
|
vg->extent_size, SIZE_SHORT));
|
||||||
-
|
|
||||||
vg->
|
|
||||||
free_count) *
|
|
||||||
(vg->
|
|
||||||
extent_size /
|
|
||||||
2),
|
|
||||||
SIZE_SHORT));
|
|
||||||
|
|
||||||
log_print("Free PE / Size %u / %s", vg->free_count,
|
log_print("Free PE / Size %u / %s", vg->free_count,
|
||||||
display_size(vg->cmd,
|
display_size(vg->cmd,
|
||||||
(uint64_t) vg->free_count * (vg->extent_size /
|
(uint64_t) vg->free_count * vg->extent_size,
|
||||||
2), SIZE_SHORT));
|
SIZE_SHORT));
|
||||||
|
|
||||||
if (!id_write_format(&vg->id, uuid, sizeof(uuid))) {
|
if (!id_write_format(&vg->id, uuid, sizeof(uuid))) {
|
||||||
stack;
|
stack;
|
||||||
@@ -708,15 +650,34 @@ void vgdisplay_short(struct volume_group *vg)
|
|||||||
{
|
{
|
||||||
log_print("\"%s\" %-9s [%-9s used / %s free]", vg->name,
|
log_print("\"%s\" %-9s [%-9s used / %s free]", vg->name,
|
||||||
/********* FIXME if "open" print "/used" else print "/idle"??? ******/
|
/********* FIXME if "open" print "/used" else print "/idle"??? ******/
|
||||||
display_size(vg->cmd, (uint64_t) vg->extent_count *
|
display_size(vg->cmd,
|
||||||
vg->extent_size / 2, SIZE_SHORT),
|
(uint64_t) vg->extent_count * vg->extent_size,
|
||||||
|
SIZE_SHORT),
|
||||||
display_size(vg->cmd,
|
display_size(vg->cmd,
|
||||||
((uint64_t) vg->extent_count -
|
((uint64_t) vg->extent_count -
|
||||||
vg->free_count) * vg->extent_size / 2,
|
vg->free_count) * vg->extent_size,
|
||||||
SIZE_SHORT), display_size(vg->cmd,
|
SIZE_SHORT),
|
||||||
(uint64_t) vg->
|
display_size(vg->cmd,
|
||||||
free_count *
|
(uint64_t) vg->free_count * vg->extent_size,
|
||||||
vg->extent_size / 2,
|
SIZE_SHORT));
|
||||||
SIZE_SHORT));
|
|
||||||
return;
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ uint64_t units_to_bytes(const char *units, char *unit_type);
|
|||||||
/* Specify size in KB */
|
/* Specify size in KB */
|
||||||
const char *display_size(struct cmd_context *cmd, uint64_t size, size_len_t sl);
|
const char *display_size(struct cmd_context *cmd, uint64_t size, size_len_t sl);
|
||||||
char *display_uuid(char *uuidstr);
|
char *display_uuid(char *uuidstr);
|
||||||
|
void display_stripe(const struct lv_segment *seg, uint32_t s, const char *pre);
|
||||||
|
|
||||||
void pvdisplay_colons(struct physical_volume *pv);
|
void pvdisplay_colons(struct physical_volume *pv);
|
||||||
void pvdisplay_full(struct cmd_context *cmd, struct physical_volume *pv,
|
void pvdisplay_full(struct cmd_context *cmd, struct physical_volume *pv,
|
||||||
@@ -44,16 +45,13 @@ void vgdisplay_full(struct volume_group *vg);
|
|||||||
void vgdisplay_colons(struct volume_group *vg);
|
void vgdisplay_colons(struct volume_group *vg);
|
||||||
void vgdisplay_short(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.
|
* Allocation policy display conversion routines.
|
||||||
*/
|
*/
|
||||||
const char *get_alloc_string(alloc_policy_t alloc);
|
const char *get_alloc_string(alloc_policy_t alloc);
|
||||||
alloc_policy_t get_alloc_from_string(const char *str);
|
alloc_policy_t get_alloc_from_string(const char *str);
|
||||||
|
|
||||||
/*
|
|
||||||
* Segment type display conversion routines.
|
|
||||||
*/
|
|
||||||
segment_type_t get_segtype_from_string(const char *str);
|
|
||||||
const char *get_segtype_string(segment_type_t segtype);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
103
lib/error/errseg.c
Normal file
103
lib/error/errseg.c
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* 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 "lib.h"
|
||||||
|
#include "pool.h"
|
||||||
|
#include "list.h"
|
||||||
|
#include "toolcontext.h"
|
||||||
|
#include "segtype.h"
|
||||||
|
#include "display.h"
|
||||||
|
#include "text_export.h"
|
||||||
|
#include "text_import.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "str_list.h"
|
||||||
|
#include "targets.h"
|
||||||
|
#include "lvm-string.h"
|
||||||
|
#include "activate.h"
|
||||||
|
|
||||||
|
static const char *_name(const struct lv_segment *seg)
|
||||||
|
{
|
||||||
|
return seg->segtype->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _merge_segments(struct lv_segment *seg1, struct lv_segment *seg2)
|
||||||
|
{
|
||||||
|
seg1->len += seg2->len;
|
||||||
|
seg1->area_len += seg2->area_len;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEVMAPPER_SUPPORT
|
||||||
|
static int _compose_target_line(struct dev_manager *dm, struct pool *mem,
|
||||||
|
struct config_tree *cft, void **target_state,
|
||||||
|
struct lv_segment *seg, char *params,
|
||||||
|
size_t paramsize, const char **target, int *pos,
|
||||||
|
uint32_t *pvmove_mirror_count)
|
||||||
|
{
|
||||||
|
/* error */
|
||||||
|
|
||||||
|
*target = "error";
|
||||||
|
*params = '\0';
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _target_present(void)
|
||||||
|
{
|
||||||
|
static int checked = 0;
|
||||||
|
static int present = 0;
|
||||||
|
|
||||||
|
if (!checked)
|
||||||
|
present = target_present("error");
|
||||||
|
|
||||||
|
checked = 1;
|
||||||
|
return present;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void _destroy(const struct segment_type *segtype)
|
||||||
|
{
|
||||||
|
dbg_free((void *) segtype);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct segtype_handler _error_ops = {
|
||||||
|
name:_name,
|
||||||
|
merge_segments:_merge_segments,
|
||||||
|
#ifdef DEVMAPPER_SUPPORT
|
||||||
|
compose_target_line:_compose_target_line,
|
||||||
|
target_present:_target_present,
|
||||||
|
#endif
|
||||||
|
destroy:_destroy,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct segment_type *init_error_segtype(struct cmd_context *cmd)
|
||||||
|
{
|
||||||
|
struct segment_type *segtype = dbg_malloc(sizeof(*segtype));
|
||||||
|
|
||||||
|
if (!segtype) {
|
||||||
|
stack;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
segtype->cmd = cmd;
|
||||||
|
segtype->ops = &_error_ops;
|
||||||
|
segtype->name = "error";
|
||||||
|
segtype->private = NULL;
|
||||||
|
segtype->flags = SEG_CAN_SPLIT | SEG_VIRTUAL;
|
||||||
|
|
||||||
|
log_very_verbose("Initialised segtype: %s", segtype->name);
|
||||||
|
|
||||||
|
return segtype;
|
||||||
|
}
|
||||||
@@ -48,7 +48,7 @@ static void _destroy(struct dev_filter *f)
|
|||||||
|
|
||||||
struct dev_filter *composite_filter_create(int n, struct dev_filter **filters)
|
struct dev_filter *composite_filter_create(int n, struct dev_filter **filters)
|
||||||
{
|
{
|
||||||
struct dev_filter **filters_copy, *cf;
|
struct dev_filter **filters_copy, *cft;
|
||||||
|
|
||||||
if (!filters) {
|
if (!filters) {
|
||||||
stack;
|
stack;
|
||||||
@@ -63,15 +63,15 @@ struct dev_filter *composite_filter_create(int n, struct dev_filter **filters)
|
|||||||
memcpy(filters_copy, filters, sizeof(*filters) * n);
|
memcpy(filters_copy, filters, sizeof(*filters) * n);
|
||||||
filters_copy[n] = NULL;
|
filters_copy[n] = NULL;
|
||||||
|
|
||||||
if (!(cf = dbg_malloc(sizeof(*cf)))) {
|
if (!(cft = dbg_malloc(sizeof(*cft)))) {
|
||||||
log_error("compsoite filters allocation failed");
|
log_error("compsoite filters allocation failed");
|
||||||
dbg_free(filters_copy);
|
dbg_free(filters_copy);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
cf->passes_filter = _and_p;
|
cft->passes_filter = _and_p;
|
||||||
cf->destroy = _destroy;
|
cft->destroy = _destroy;
|
||||||
cf->private = filters_copy;
|
cft->private = filters_copy;
|
||||||
|
|
||||||
return cf;
|
return cft;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ int persistent_filter_wipe(struct dev_filter *f)
|
|||||||
static int _read_array(struct pfilter *pf, struct config_tree *cft,
|
static int _read_array(struct pfilter *pf, struct config_tree *cft,
|
||||||
const char *path, void *data)
|
const char *path, void *data)
|
||||||
{
|
{
|
||||||
struct config_node *cn;
|
const struct config_node *cn;
|
||||||
struct config_value *cv;
|
struct config_value *cv;
|
||||||
|
|
||||||
if (!(cn = find_config_node(cft->root, path))) {
|
if (!(cn = find_config_node(cft->root, path))) {
|
||||||
@@ -99,12 +99,12 @@ int persistent_filter_load(struct dev_filter *f)
|
|||||||
int r = 0;
|
int r = 0;
|
||||||
struct config_tree *cft;
|
struct config_tree *cft;
|
||||||
|
|
||||||
if (!(cft = create_config_tree())) {
|
if (!(cft = create_config_tree(pf->file))) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!read_config_file(cft, pf->file)) {
|
if (!read_config_file(cft)) {
|
||||||
stack;
|
stack;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -169,6 +169,8 @@ static int _read_devs(struct dev_set *ds, const char *dir)
|
|||||||
{
|
{
|
||||||
struct dirent *d;
|
struct dirent *d;
|
||||||
DIR *dr;
|
DIR *dr;
|
||||||
|
unsigned char dtype;
|
||||||
|
struct stat info;
|
||||||
char path[PATH_MAX];
|
char path[PATH_MAX];
|
||||||
dev_t dev;
|
dev_t dev;
|
||||||
int r = 1;
|
int r = 1;
|
||||||
@@ -189,19 +191,29 @@ static int _read_devs(struct dev_set *ds, const char *dir)
|
|||||||
continue;
|
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)) {
|
if (!_read_devs(ds, path)) {
|
||||||
r = 0;
|
r = 0;
|
||||||
break;
|
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)) {
|
if (!_read_dev(path, &dev) || !_set_insert(ds, dev)) {
|
||||||
r = 0;
|
r = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (closedir(dr))
|
if (closedir(dr))
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
#define NUMBER_OF_MAJORS 256
|
#define NUMBER_OF_MAJORS 4096
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char *name;
|
const char *name;
|
||||||
@@ -54,6 +54,8 @@ static const device_info_t device_info[] = {
|
|||||||
{"ataraid", 16}, /* ATA Raid */
|
{"ataraid", 16}, /* ATA Raid */
|
||||||
{"drbd", 16}, /* Distributed Replicated Block Device */
|
{"drbd", 16}, /* Distributed Replicated Block Device */
|
||||||
{"power2", 16}, /* EMC Powerpath */
|
{"power2", 16}, /* EMC Powerpath */
|
||||||
|
{"i2o_block", 16}, /* i2o Block Disk */
|
||||||
|
{"iseries/vd", 8}, /* iSeries disks */
|
||||||
{NULL, 0}
|
{NULL, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -82,7 +84,7 @@ static int _passes_lvm_type_device_filter(struct dev_filter *f,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int *_scan_proc_dev(const char *proc, struct config_node *cn)
|
static int *_scan_proc_dev(const char *proc, const struct config_node *cn)
|
||||||
{
|
{
|
||||||
char line[80];
|
char line[80];
|
||||||
char proc_devices[PATH_MAX];
|
char proc_devices[PATH_MAX];
|
||||||
@@ -95,6 +97,7 @@ static int *_scan_proc_dev(const char *proc, struct config_node *cn)
|
|||||||
int *max_partitions_by_major;
|
int *max_partitions_by_major;
|
||||||
char *name;
|
char *name;
|
||||||
|
|
||||||
|
/* FIXME Make this sparse */
|
||||||
if (!(max_partitions_by_major =
|
if (!(max_partitions_by_major =
|
||||||
dbg_malloc(sizeof(int) * NUMBER_OF_MAJORS))) {
|
dbg_malloc(sizeof(int) * NUMBER_OF_MAJORS))) {
|
||||||
log_error("Filter failed to allocate max_partitions_by_major");
|
log_error("Filter failed to allocate max_partitions_by_major");
|
||||||
@@ -199,7 +202,7 @@ static int *_scan_proc_dev(const char *proc, struct config_node *cn)
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct dev_filter *lvm_type_filter_create(const char *proc,
|
struct dev_filter *lvm_type_filter_create(const char *proc,
|
||||||
struct config_node *cn)
|
const struct config_node *cn)
|
||||||
{
|
{
|
||||||
struct dev_filter *f;
|
struct dev_filter *f;
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,9 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#ifdef linux
|
#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
|
#else
|
||||||
# define MAJOR(x) major((x))
|
# define MAJOR(x) major((x))
|
||||||
# define MINOR(x) minor((x))
|
# define MINOR(x) minor((x))
|
||||||
@@ -29,7 +31,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct dev_filter *lvm_type_filter_create(const char *proc,
|
struct dev_filter *lvm_type_filter_create(const char *proc,
|
||||||
struct config_node *cn);
|
const struct config_node *cn);
|
||||||
|
|
||||||
void lvm_type_filter_destroy(struct dev_filter *f);
|
void lvm_type_filter_destroy(struct dev_filter *f);
|
||||||
|
|
||||||
|
|||||||
@@ -27,9 +27,7 @@ SOURCES =\
|
|||||||
|
|
||||||
LIB_SHARED = liblvm2format1.so
|
LIB_SHARED = liblvm2format1.so
|
||||||
|
|
||||||
include ../../make.tmpl
|
include $(top_srcdir)/make.tmpl
|
||||||
|
|
||||||
.PHONY: install
|
|
||||||
|
|
||||||
install: liblvm2format1.so
|
install: liblvm2format1.so
|
||||||
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \
|
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \
|
||||||
|
|||||||
@@ -117,6 +117,7 @@ static void _xlate_extents(struct pe_disk *extents, uint32_t count)
|
|||||||
static int _munge_formats(struct pv_disk *pvd)
|
static int _munge_formats(struct pv_disk *pvd)
|
||||||
{
|
{
|
||||||
uint32_t pe_start;
|
uint32_t pe_start;
|
||||||
|
int b, e;
|
||||||
|
|
||||||
switch (pvd->version) {
|
switch (pvd->version) {
|
||||||
case 1:
|
case 1:
|
||||||
@@ -134,17 +135,54 @@ static int _munge_formats(struct pv_disk *pvd)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* UUID too long? */
|
||||||
|
if (pvd->pv_uuid[ID_LEN]) {
|
||||||
|
/* Retain ID_LEN chars from end */
|
||||||
|
for (e = ID_LEN; e < sizeof(pvd->pv_uuid); e++) {
|
||||||
|
if (!pvd->pv_uuid[e]) {
|
||||||
|
e--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (b = 0; b < ID_LEN; b++) {
|
||||||
|
pvd->pv_uuid[b] = pvd->pv_uuid[++e - ID_LEN];
|
||||||
|
/* FIXME Remove all invalid chars */
|
||||||
|
if (pvd->pv_uuid[b] == '/')
|
||||||
|
pvd->pv_uuid[b] = '#';
|
||||||
|
}
|
||||||
|
memset(&pvd->pv_uuid[ID_LEN], 0, sizeof(pvd->pv_uuid) - ID_LEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If UUID is missing, create one */
|
||||||
|
if (pvd->pv_uuid[0] == '\0')
|
||||||
|
uuid_from_num(pvd->pv_uuid, pvd->pv_number);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _read_pvd(struct device *dev, struct pv_disk *pvd)
|
/*
|
||||||
|
* If exported, remove "PV_EXP" from end of VG name
|
||||||
|
*/
|
||||||
|
static void _munge_exported_vg(struct pv_disk *pvd)
|
||||||
{
|
{
|
||||||
if (!dev_read(dev, UINT64_C(0), sizeof(*pvd), pvd)) {
|
int l;
|
||||||
log_very_verbose("Failed to read PV data from %s",
|
size_t s;
|
||||||
dev_name(dev));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* Return if PV not in a VG */
|
||||||
|
if ((!*pvd->vg_name))
|
||||||
|
return;
|
||||||
|
/* FIXME also check vgd->status & VG_EXPORTED? */
|
||||||
|
|
||||||
|
l = strlen(pvd->vg_name);
|
||||||
|
s = sizeof(EXPORTED_TAG);
|
||||||
|
if (!strncmp(pvd->vg_name + l - s + 1, EXPORTED_TAG, s)) {
|
||||||
|
pvd->vg_name[l - s + 1] = '\0';
|
||||||
|
pvd->pv_status |= VG_EXPORTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int munge_pvd(struct device *dev, struct pv_disk *pvd)
|
||||||
|
{
|
||||||
_xlate_pvd(pvd);
|
_xlate_pvd(pvd);
|
||||||
|
|
||||||
if (pvd->id[0] != 'H' || pvd->id[1] != 'M') {
|
if (pvd->id[0] != 'H' || pvd->id[1] != 'M') {
|
||||||
@@ -159,13 +197,23 @@ static int _read_pvd(struct device *dev, struct pv_disk *pvd)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If UUID is missing, create one */
|
/* If VG is exported, set VG name back to the real name */
|
||||||
if (pvd->pv_uuid[0] == '\0')
|
_munge_exported_vg(pvd);
|
||||||
uuid_from_num(pvd->pv_uuid, pvd->pv_number);
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int _read_pvd(struct device *dev, struct pv_disk *pvd)
|
||||||
|
{
|
||||||
|
if (!dev_read(dev, UINT64_C(0), sizeof(*pvd), pvd)) {
|
||||||
|
log_very_verbose("Failed to read PV data from %s",
|
||||||
|
dev_name(dev));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return munge_pvd(dev, pvd);
|
||||||
|
}
|
||||||
|
|
||||||
static int _read_lvd(struct device *dev, uint64_t pos, struct lv_disk *disk)
|
static int _read_lvd(struct device *dev, uint64_t pos, struct lv_disk *disk)
|
||||||
{
|
{
|
||||||
if (!dev_read(dev, pos, sizeof(*disk), disk))
|
if (!dev_read(dev, pos, sizeof(*disk), disk))
|
||||||
@@ -185,6 +233,9 @@ static int _read_vgd(struct disk_list *data)
|
|||||||
|
|
||||||
_xlate_vgd(vgd);
|
_xlate_vgd(vgd);
|
||||||
|
|
||||||
|
if ((vgd->lv_max > MAX_LV) || (vgd->pv_max > MAX_PV))
|
||||||
|
fail;
|
||||||
|
|
||||||
/* If UUID is missing, create one */
|
/* If UUID is missing, create one */
|
||||||
if (vgd->vg_uuid[0] == '\0')
|
if (vgd->vg_uuid[0] == '\0')
|
||||||
uuid_from_num(vgd->vg_uuid, vgd->vg_number);
|
uuid_from_num(vgd->vg_uuid, vgd->vg_number);
|
||||||
@@ -269,26 +320,6 @@ static int _read_extents(struct disk_list *data)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* If exported, remove "PV_EXP" from end of VG name
|
|
||||||
*/
|
|
||||||
void munge_exported_vg(struct pv_disk *pvd)
|
|
||||||
{
|
|
||||||
int l;
|
|
||||||
size_t s;
|
|
||||||
|
|
||||||
/* Return if PV not in a VG */
|
|
||||||
if ((!*pvd->vg_name))
|
|
||||||
return;
|
|
||||||
|
|
||||||
l = strlen(pvd->vg_name);
|
|
||||||
s = sizeof(EXPORTED_TAG);
|
|
||||||
if (!strncmp(pvd->vg_name + l - s + 1, EXPORTED_TAG, s)) {
|
|
||||||
pvd->vg_name[l - s + 1] = '\0';
|
|
||||||
pvd->pv_status |= VG_EXPORTED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct disk_list *__read_disk(const struct format_type *fmt,
|
static struct disk_list *__read_disk(const struct format_type *fmt,
|
||||||
struct device *dev, struct pool *mem,
|
struct device *dev, struct pool *mem,
|
||||||
const char *vg_name)
|
const char *vg_name)
|
||||||
@@ -312,9 +343,6 @@ static struct disk_list *__read_disk(const struct format_type *fmt,
|
|||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If VG is exported, set VG name back to the real name */
|
|
||||||
munge_exported_vg(&dl->pvd);
|
|
||||||
|
|
||||||
if (!(info = lvmcache_add(fmt->labeller, dl->pvd.pv_uuid, dev,
|
if (!(info = lvmcache_add(fmt->labeller, dl->pvd.pv_uuid, dev,
|
||||||
dl->pvd.vg_name, NULL)))
|
dl->pvd.vg_name, NULL)))
|
||||||
stack;
|
stack;
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ int export_vg(struct vg_disk *vgd, struct volume_group *vg);
|
|||||||
|
|
||||||
int import_lv(struct pool *mem, struct logical_volume *lv, struct lv_disk *lvd);
|
int import_lv(struct pool *mem, struct logical_volume *lv, struct lv_disk *lvd);
|
||||||
|
|
||||||
int import_extents(struct pool *mem, struct volume_group *vg,
|
int import_extents(struct cmd_context *cmd, struct volume_group *vg,
|
||||||
struct list *pvds);
|
struct list *pvds);
|
||||||
int export_extents(struct disk_list *dl, uint32_t lv_num,
|
int export_extents(struct disk_list *dl, uint32_t lv_num,
|
||||||
struct logical_volume *lv, struct physical_volume *pv);
|
struct logical_volume *lv, struct physical_volume *pv);
|
||||||
@@ -237,7 +237,7 @@ int export_uuids(struct disk_list *dl, struct volume_group *vg);
|
|||||||
void export_numbers(struct list *pvds, struct volume_group *vg);
|
void export_numbers(struct list *pvds, struct volume_group *vg);
|
||||||
|
|
||||||
void export_pv_act(struct list *pvds);
|
void export_pv_act(struct list *pvds);
|
||||||
void munge_exported_vg(struct pv_disk *pvd);
|
int munge_pvd(struct device *dev, struct pv_disk *pvd);
|
||||||
|
|
||||||
/* blech */
|
/* blech */
|
||||||
int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter,
|
int get_free_vg_number(struct format_instance *fid, struct dev_filter *filter,
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
#include "lvmcache.h"
|
#include "lvmcache.h"
|
||||||
#include "lvm1-label.h"
|
#include "lvm1-label.h"
|
||||||
#include "format1.h"
|
#include "format1.h"
|
||||||
|
#include "segtype.h"
|
||||||
|
|
||||||
#define FMT_LVM1_NAME "lvm1"
|
#define FMT_LVM1_NAME "lvm1"
|
||||||
|
|
||||||
@@ -164,7 +165,7 @@ static struct volume_group *_build_vg(struct format_instance *fid,
|
|||||||
if (!import_lvs(mem, vg, pvs))
|
if (!import_lvs(mem, vg, pvs))
|
||||||
goto bad;
|
goto bad;
|
||||||
|
|
||||||
if (!import_extents(mem, vg, pvs))
|
if (!import_extents(fid->fmt->cmd, vg, pvs))
|
||||||
goto bad;
|
goto bad;
|
||||||
|
|
||||||
if (!import_snapshots(mem, vg, pvs))
|
if (!import_snapshots(mem, vg, pvs))
|
||||||
@@ -345,7 +346,7 @@ static int _pv_setup(const struct format_type *fmt,
|
|||||||
pv->size--;
|
pv->size--;
|
||||||
if (pv->size > MAX_PV_SIZE) {
|
if (pv->size > MAX_PV_SIZE) {
|
||||||
log_error("Physical volumes cannot be bigger than %s",
|
log_error("Physical volumes cannot be bigger than %s",
|
||||||
display_size(fmt->cmd, (uint64_t) MAX_PV_SIZE / 2,
|
display_size(fmt->cmd, (uint64_t) MAX_PV_SIZE,
|
||||||
SIZE_SHORT));
|
SIZE_SHORT));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -386,7 +387,7 @@ static int _lv_setup(struct format_instance *fid, struct logical_volume *lv)
|
|||||||
}
|
}
|
||||||
if (lv->size > max_size) {
|
if (lv->size > max_size) {
|
||||||
log_error("logical volumes cannot be larger than %s",
|
log_error("logical volumes cannot be larger than %s",
|
||||||
display_size(fid->fmt->cmd, max_size / 2,
|
display_size(fid->fmt->cmd, max_size,
|
||||||
SIZE_SHORT));
|
SIZE_SHORT));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -468,21 +469,18 @@ static int _vg_setup(struct format_instance *fid, struct volume_group *vg)
|
|||||||
|
|
||||||
if (vg->extent_size > MAX_PE_SIZE || vg->extent_size < MIN_PE_SIZE) {
|
if (vg->extent_size > MAX_PE_SIZE || vg->extent_size < MIN_PE_SIZE) {
|
||||||
log_error("Extent size must be between %s and %s",
|
log_error("Extent size must be between %s and %s",
|
||||||
display_size(fid->fmt->cmd, (uint64_t) MIN_PE_SIZE
|
display_size(fid->fmt->cmd, (uint64_t) MIN_PE_SIZE,
|
||||||
/ 2,
|
SIZE_SHORT),
|
||||||
SIZE_SHORT), display_size(fid->fmt->cmd,
|
display_size(fid->fmt->cmd, (uint64_t) MAX_PE_SIZE,
|
||||||
(uint64_t)
|
SIZE_SHORT));
|
||||||
MAX_PE_SIZE
|
|
||||||
/ 2,
|
|
||||||
SIZE_SHORT));
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vg->extent_size % MIN_PE_SIZE) {
|
if (vg->extent_size % MIN_PE_SIZE) {
|
||||||
log_error("Extent size must be multiple of %s",
|
log_error("Extent size must be multiple of %s",
|
||||||
display_size(fid->fmt->cmd,
|
display_size(fid->fmt->cmd, (uint64_t) MIN_PE_SIZE,
|
||||||
(uint64_t) MIN_PE_SIZE / 2, SIZE_SHORT));
|
SIZE_SHORT));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -495,6 +493,17 @@ static int _vg_setup(struct format_instance *fid, struct volume_group *vg)
|
|||||||
return 1;
|
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 = {
|
static struct metadata_area_ops _metadata_format1_ops = {
|
||||||
vg_read:_vg_read,
|
vg_read:_vg_read,
|
||||||
vg_write:_vg_write,
|
vg_write:_vg_write,
|
||||||
@@ -545,6 +554,7 @@ static struct format_handler _format1_ops = {
|
|||||||
pv_write:_pv_write,
|
pv_write:_pv_write,
|
||||||
lv_setup:_lv_setup,
|
lv_setup:_lv_setup,
|
||||||
vg_setup:_vg_setup,
|
vg_setup:_vg_setup,
|
||||||
|
segtype_supported:_segtype_supported,
|
||||||
create_instance:_create_instance,
|
create_instance:_create_instance,
|
||||||
destroy_instance:_destroy_instance,
|
destroy_instance:_destroy_instance,
|
||||||
destroy:_destroy,
|
destroy:_destroy,
|
||||||
@@ -581,5 +591,7 @@ struct format_type *init_format(struct cmd_context *cmd)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log_very_verbose("Initialised format: %s", fmt->name);
|
||||||
|
|
||||||
return fmt;
|
return fmt;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
#include "lvm-string.h"
|
#include "lvm-string.h"
|
||||||
#include "filter.h"
|
#include "filter.h"
|
||||||
#include "toolcontext.h"
|
#include "toolcontext.h"
|
||||||
|
#include "segtype.h"
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
@@ -236,6 +237,7 @@ int import_vg(struct pool *mem,
|
|||||||
vg->free_count = vgd->pe_total - vgd->pe_allocated;
|
vg->free_count = vgd->pe_total - vgd->pe_allocated;
|
||||||
vg->max_lv = vgd->lv_max;
|
vg->max_lv = vgd->lv_max;
|
||||||
vg->max_pv = vgd->pv_max;
|
vg->max_pv = vgd->pv_max;
|
||||||
|
vg->alloc = ALLOC_NORMAL;
|
||||||
|
|
||||||
if (partial)
|
if (partial)
|
||||||
vg->status |= PARTIAL_VG;
|
vg->status |= PARTIAL_VG;
|
||||||
@@ -315,7 +317,7 @@ int import_lv(struct pool *mem, struct logical_volume *lv, struct lv_disk *lvd)
|
|||||||
if (lvd->lv_allocation & LV_CONTIGUOUS)
|
if (lvd->lv_allocation & LV_CONTIGUOUS)
|
||||||
lv->alloc = ALLOC_CONTIGUOUS;
|
lv->alloc = ALLOC_CONTIGUOUS;
|
||||||
else
|
else
|
||||||
lv->alloc = ALLOC_NEXT_FREE;
|
lv->alloc = ALLOC_NORMAL;
|
||||||
|
|
||||||
lv->read_ahead = lvd->lv_read_ahead;
|
lv->read_ahead = lvd->lv_read_ahead;
|
||||||
lv->size = lvd->lv_size;
|
lv->size = lvd->lv_size;
|
||||||
@@ -380,9 +382,10 @@ int export_extents(struct disk_list *dl, uint32_t lv_num,
|
|||||||
seg = list_item(segh, struct lv_segment);
|
seg = list_item(segh, struct lv_segment);
|
||||||
|
|
||||||
for (s = 0; s < seg->area_count; s++) {
|
for (s = 0; s < seg->area_count; s++) {
|
||||||
if (seg->type != SEG_STRIPED) {
|
if (!(seg->segtype->flags & SEG_FORMAT1_SUPPORT)) {
|
||||||
log_error("Non-striped segment type in LV %s: "
|
log_error("Segment type %s in LV %s: "
|
||||||
"unsupported by format1", lv->name);
|
"unsupported by format1",
|
||||||
|
seg->segtype->name, lv->name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (seg->area[s].type != AREA_PV) {
|
if (seg->area[s].type != AREA_PV) {
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
#include "pool.h"
|
#include "pool.h"
|
||||||
#include "disk-rep.h"
|
#include "disk-rep.h"
|
||||||
#include "lv_alloc.h"
|
#include "lv_alloc.h"
|
||||||
|
#include "display.h"
|
||||||
|
#include "segtype.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* After much thought I have decided it is easier,
|
* After much thought I have decided it is easier,
|
||||||
@@ -201,21 +203,24 @@ static int _check_maps_are_complete(struct hash_table *maps)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _read_linear(struct pool *mem, struct lv_map *lvm)
|
static int _read_linear(struct cmd_context *cmd, struct lv_map *lvm)
|
||||||
{
|
{
|
||||||
uint32_t le = 0;
|
uint32_t le = 0;
|
||||||
struct lv_segment *seg;
|
struct lv_segment *seg;
|
||||||
|
|
||||||
while (le < lvm->lv->le_count) {
|
while (le < lvm->lv->le_count) {
|
||||||
seg = alloc_lv_segment(mem, 1);
|
seg = alloc_lv_segment(cmd->mem, 1);
|
||||||
|
|
||||||
seg->lv = lvm->lv;
|
seg->lv = lvm->lv;
|
||||||
seg->type = SEG_STRIPED;
|
if (!(seg->segtype = get_segtype_from_string(cmd, "striped"))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
seg->le = le;
|
seg->le = le;
|
||||||
seg->len = 0;
|
seg->len = 0;
|
||||||
seg->area_len = 0;
|
seg->area_len = 0;
|
||||||
seg->stripe_size = 0;
|
seg->stripe_size = 0;
|
||||||
seg->area_count = 1;
|
|
||||||
|
|
||||||
seg->area[0].type = AREA_PV;
|
seg->area[0].type = AREA_PV;
|
||||||
seg->area[0].u.pv.pv = lvm->map[le].pv;
|
seg->area[0].u.pv.pv = lvm->map[le].pv;
|
||||||
@@ -251,13 +256,12 @@ static int _check_stripe(struct lv_map *lvm, struct lv_segment *seg,
|
|||||||
if ((lvm->map[le + st * len].pv != seg->area[st].u.pv.pv) ||
|
if ((lvm->map[le + st * len].pv != seg->area[st].u.pv.pv) ||
|
||||||
(seg->area[st].u.pv.pv &&
|
(seg->area[st].u.pv.pv &&
|
||||||
lvm->map[le + st * len].pe !=
|
lvm->map[le + st * len].pe !=
|
||||||
seg->area[st].u.pv.pe + seg->len))
|
seg->area[st].u.pv.pe + seg->len)) return 0;
|
||||||
return 0;
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _read_stripes(struct pool *mem, struct lv_map *lvm)
|
static int _read_stripes(struct cmd_context *cmd, struct lv_map *lvm)
|
||||||
{
|
{
|
||||||
uint32_t st, le = 0, len;
|
uint32_t st, le = 0, len;
|
||||||
struct lv_segment *seg;
|
struct lv_segment *seg;
|
||||||
@@ -273,15 +277,17 @@ static int _read_stripes(struct pool *mem, struct lv_map *lvm)
|
|||||||
len = lvm->lv->le_count / lvm->stripes;
|
len = lvm->lv->le_count / lvm->stripes;
|
||||||
|
|
||||||
while (le < len) {
|
while (le < len) {
|
||||||
if (!(seg = alloc_lv_segment(mem, lvm->stripes))) {
|
if (!(seg = alloc_lv_segment(cmd->mem, lvm->stripes))) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
seg->lv = lvm->lv;
|
seg->lv = lvm->lv;
|
||||||
seg->type = SEG_STRIPED;
|
if (!(seg->segtype = get_segtype_from_string(cmd, "striped"))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
seg->stripe_size = lvm->stripe_size;
|
seg->stripe_size = lvm->stripe_size;
|
||||||
seg->area_count = lvm->stripes;
|
|
||||||
seg->le = seg->area_count * le;
|
seg->le = seg->area_count * le;
|
||||||
seg->len = 1;
|
seg->len = 1;
|
||||||
seg->area_len = 1;
|
seg->area_len = 1;
|
||||||
@@ -312,20 +318,20 @@ static int _read_stripes(struct pool *mem, struct lv_map *lvm)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _build_segments(struct pool *mem, struct lv_map *lvm)
|
static int _build_segments(struct cmd_context *cmd, struct lv_map *lvm)
|
||||||
{
|
{
|
||||||
return (lvm->stripes > 1 ? _read_stripes(mem, lvm) :
|
return (lvm->stripes > 1 ? _read_stripes(cmd, lvm) :
|
||||||
_read_linear(mem, lvm));
|
_read_linear(cmd, lvm));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _build_all_segments(struct pool *mem, struct hash_table *maps)
|
static int _build_all_segments(struct cmd_context *cmd, struct hash_table *maps)
|
||||||
{
|
{
|
||||||
struct hash_node *n;
|
struct hash_node *n;
|
||||||
struct lv_map *lvm;
|
struct lv_map *lvm;
|
||||||
|
|
||||||
for (n = hash_get_first(maps); n; n = hash_get_next(maps, n)) {
|
for (n = hash_get_first(maps); n; n = hash_get_next(maps, n)) {
|
||||||
lvm = (struct lv_map *) hash_get_data(maps, n);
|
lvm = (struct lv_map *) hash_get_data(maps, n);
|
||||||
if (!_build_segments(mem, lvm)) {
|
if (!_build_segments(cmd, lvm)) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -334,7 +340,8 @@ static int _build_all_segments(struct pool *mem, struct hash_table *maps)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int import_extents(struct pool *mem, struct volume_group *vg, struct list *pvds)
|
int import_extents(struct cmd_context *cmd, struct volume_group *vg,
|
||||||
|
struct list *pvds)
|
||||||
{
|
{
|
||||||
int r = 0;
|
int r = 0;
|
||||||
struct pool *scratch = pool_create(10 * 1024);
|
struct pool *scratch = pool_create(10 * 1024);
|
||||||
@@ -360,7 +367,7 @@ int import_extents(struct pool *mem, struct volume_group *vg, struct list *pvds)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_build_all_segments(mem, maps)) {
|
if (!_build_all_segments(cmd, maps)) {
|
||||||
log_err("Couldn't build extent segments.");
|
log_err("Couldn't build extent segments.");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,7 +60,8 @@ static int _read(struct labeller *l, struct device *dev, char *buf,
|
|||||||
struct pv_disk *pvd = (struct pv_disk *) buf;
|
struct pv_disk *pvd = (struct pv_disk *) buf;
|
||||||
struct lvmcache_info *info;
|
struct lvmcache_info *info;
|
||||||
|
|
||||||
munge_exported_vg(pvd);
|
munge_pvd(dev, pvd);
|
||||||
|
|
||||||
if (!(info = lvmcache_add(l, pvd->pv_uuid, dev, pvd->vg_name, NULL))) {
|
if (!(info = lvmcache_add(l, pvd->pv_uuid, dev, pvd->vg_name, NULL))) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
1
lib/format_pool/.exported_symbols
Normal file
1
lib/format_pool/.exported_symbols
Normal file
@@ -0,0 +1 @@
|
|||||||
|
init_format
|
||||||
35
lib/format_pool/Makefile.in
Normal file
35
lib/format_pool/Makefile.in
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
#
|
||||||
|
# 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 =\
|
||||||
|
disk_rep.c \
|
||||||
|
format_pool.c \
|
||||||
|
import_export.c \
|
||||||
|
pool_label.c
|
||||||
|
|
||||||
|
LIB_SHARED = liblvm2formatpool.so
|
||||||
|
|
||||||
|
include $(top_srcdir)/make.tmpl
|
||||||
|
|
||||||
|
install: liblvm2formatpool.so
|
||||||
|
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) $< \
|
||||||
|
$(libdir)/liblvm2formatpool.so.$(LIB_VERSION)
|
||||||
|
$(LN_S) -f liblvm2formatpool.so.$(LIB_VERSION) \
|
||||||
|
$(libdir)/liblvm2formatpool.so
|
||||||
|
|
||||||
|
|
||||||
385
lib/format_pool/disk_rep.c
Normal file
385
lib/format_pool/disk_rep.c
Normal file
@@ -0,0 +1,385 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lib.h"
|
||||||
|
#include "pool.h"
|
||||||
|
#include "label.h"
|
||||||
|
#include "metadata.h"
|
||||||
|
#include "lvmcache.h"
|
||||||
|
#include "filter.h"
|
||||||
|
#include "list.h"
|
||||||
|
#include "xlate.h"
|
||||||
|
|
||||||
|
#include "disk_rep.h"
|
||||||
|
|
||||||
|
/* FIXME: memcpy might not be portable */
|
||||||
|
#define CPIN_8(x, y, z) {memcpy((x), (y), (z));}
|
||||||
|
#define CPOUT_8(x, y, z) {memcpy((y), (x), (z));}
|
||||||
|
#define CPIN_16(x, y) {(x) = xlate16_be((y));}
|
||||||
|
#define CPOUT_16(x, y) {(y) = xlate16_be((x));}
|
||||||
|
#define CPIN_32(x, y) {(x) = xlate32_be((y));}
|
||||||
|
#define CPOUT_32(x, y) {(y) = xlate32_be((x));}
|
||||||
|
#define CPIN_64(x, y) {(x) = xlate64_be((y));}
|
||||||
|
#define CPOUT_64(x, y) {(y) = xlate64_be((x));}
|
||||||
|
|
||||||
|
static int __read_pool_disk(const struct format_type *fmt, struct device *dev,
|
||||||
|
struct pool *mem, struct pool_list *pl,
|
||||||
|
const char *vg_name)
|
||||||
|
{
|
||||||
|
char buf[512];
|
||||||
|
|
||||||
|
/* FIXME: Need to check the cache here first */
|
||||||
|
if (!dev_read(dev, UINT64_C(0), 512, buf)) {
|
||||||
|
log_very_verbose("Failed to read PV data from %s",
|
||||||
|
dev_name(dev));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!read_pool_label(pl, fmt->labeller, dev, buf, NULL)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _add_pl_to_list(struct list *head, struct pool_list *data)
|
||||||
|
{
|
||||||
|
struct list *pvdh;
|
||||||
|
struct pool_list *pl;
|
||||||
|
|
||||||
|
list_iterate(pvdh, head) {
|
||||||
|
pl = list_item(pvdh, struct pool_list);
|
||||||
|
|
||||||
|
if (id_equal(&data->pv_uuid, &pl->pv_uuid)) {
|
||||||
|
char uuid[ID_LEN + 7];
|
||||||
|
|
||||||
|
id_write_format(&pl->pv_uuid, uuid, ID_LEN + 7);
|
||||||
|
|
||||||
|
if (MAJOR(data->dev->dev) != md_major()) {
|
||||||
|
log_very_verbose("Ignoring duplicate PV %s on "
|
||||||
|
"%s", uuid,
|
||||||
|
dev_name(data->dev));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
log_very_verbose("Duplicate PV %s - using md %s",
|
||||||
|
uuid, dev_name(data->dev));
|
||||||
|
list_del(pvdh);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list_add(head, &data->list);
|
||||||
|
}
|
||||||
|
|
||||||
|
int read_pool_label(struct pool_list *pl, struct labeller *l,
|
||||||
|
struct device *dev, char *buf, struct label **label)
|
||||||
|
{
|
||||||
|
struct lvmcache_info *info;
|
||||||
|
struct id pvid;
|
||||||
|
struct id vgid;
|
||||||
|
char uuid[ID_LEN + 7];
|
||||||
|
struct pool_disk *pd = &pl->pd;
|
||||||
|
|
||||||
|
pool_label_in(pd, buf);
|
||||||
|
|
||||||
|
get_pool_pv_uuid(&pvid, pd);
|
||||||
|
id_write_format(&pvid, uuid, ID_LEN + 7);
|
||||||
|
log_debug("Calculated uuid %s for %s", uuid, dev_name(dev));
|
||||||
|
|
||||||
|
get_pool_vg_uuid(&vgid, pd);
|
||||||
|
id_write_format(&vgid, uuid, ID_LEN + 7);
|
||||||
|
log_debug("Calculated uuid %s for %s", uuid, pd->pl_pool_name);
|
||||||
|
|
||||||
|
if (!(info = lvmcache_add(l, (char *) &pvid, dev, pd->pl_pool_name,
|
||||||
|
(char *) &vgid))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (label)
|
||||||
|
*label = info->label;
|
||||||
|
|
||||||
|
info->device_size = xlate32_be(pd->pl_blocks) << SECTOR_SHIFT;
|
||||||
|
list_init(&info->mdas);
|
||||||
|
|
||||||
|
info->status &= ~CACHE_INVALID;
|
||||||
|
|
||||||
|
pl->dev = dev;
|
||||||
|
pl->pv = NULL;
|
||||||
|
memcpy(&pl->pv_uuid, &pvid, sizeof(pvid));
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pool_label_out - copies a pool_label_t into a char buffer
|
||||||
|
* @pl: ptr to a pool_label_t struct
|
||||||
|
* @buf: ptr to raw space where label info will be copied
|
||||||
|
*
|
||||||
|
* This function is important because it takes care of all of
|
||||||
|
* the endian issues when copying to disk. This way, when
|
||||||
|
* machines of different architectures are used, they will
|
||||||
|
* be able to interpret ondisk labels correctly. Always use
|
||||||
|
* this function before writing to disk.
|
||||||
|
*/
|
||||||
|
void pool_label_out(struct pool_disk *pl, char *buf)
|
||||||
|
{
|
||||||
|
struct pool_disk *bufpl = (struct pool_disk *) buf;
|
||||||
|
|
||||||
|
CPOUT_64(pl->pl_magic, bufpl->pl_magic);
|
||||||
|
CPOUT_64(pl->pl_pool_id, bufpl->pl_pool_id);
|
||||||
|
CPOUT_8(pl->pl_pool_name, bufpl->pl_pool_name, POOL_NAME_SIZE);
|
||||||
|
CPOUT_32(pl->pl_version, bufpl->pl_version);
|
||||||
|
CPOUT_32(pl->pl_subpools, bufpl->pl_subpools);
|
||||||
|
CPOUT_32(pl->pl_sp_id, bufpl->pl_sp_id);
|
||||||
|
CPOUT_32(pl->pl_sp_devs, bufpl->pl_sp_devs);
|
||||||
|
CPOUT_32(pl->pl_sp_devid, bufpl->pl_sp_devid);
|
||||||
|
CPOUT_32(pl->pl_sp_type, bufpl->pl_sp_type);
|
||||||
|
CPOUT_64(pl->pl_blocks, bufpl->pl_blocks);
|
||||||
|
CPOUT_32(pl->pl_striping, bufpl->pl_striping);
|
||||||
|
CPOUT_32(pl->pl_sp_dmepdevs, bufpl->pl_sp_dmepdevs);
|
||||||
|
CPOUT_32(pl->pl_sp_dmepid, bufpl->pl_sp_dmepid);
|
||||||
|
CPOUT_32(pl->pl_sp_weight, bufpl->pl_sp_weight);
|
||||||
|
CPOUT_32(pl->pl_minor, bufpl->pl_minor);
|
||||||
|
CPOUT_32(pl->pl_padding, bufpl->pl_padding);
|
||||||
|
CPOUT_8(pl->pl_reserve, bufpl->pl_reserve, 184);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pool_label_in - copies a char buffer into a pool_label_t
|
||||||
|
* @pl: ptr to a pool_label_t struct
|
||||||
|
* @buf: ptr to raw space where label info is copied from
|
||||||
|
*
|
||||||
|
* This function is important because it takes care of all of
|
||||||
|
* the endian issues when information from disk is about to be
|
||||||
|
* used. This way, when machines of different architectures
|
||||||
|
* are used, they will be able to interpret ondisk labels
|
||||||
|
* correctly. Always use this function before using labels that
|
||||||
|
* were read from disk.
|
||||||
|
*/
|
||||||
|
void pool_label_in(struct pool_disk *pl, char *buf)
|
||||||
|
{
|
||||||
|
struct pool_disk *bufpl = (struct pool_disk *) buf;
|
||||||
|
|
||||||
|
CPIN_64(pl->pl_magic, bufpl->pl_magic);
|
||||||
|
CPIN_64(pl->pl_pool_id, bufpl->pl_pool_id);
|
||||||
|
CPIN_8(pl->pl_pool_name, bufpl->pl_pool_name, POOL_NAME_SIZE);
|
||||||
|
CPIN_32(pl->pl_version, bufpl->pl_version);
|
||||||
|
CPIN_32(pl->pl_subpools, bufpl->pl_subpools);
|
||||||
|
CPIN_32(pl->pl_sp_id, bufpl->pl_sp_id);
|
||||||
|
CPIN_32(pl->pl_sp_devs, bufpl->pl_sp_devs);
|
||||||
|
CPIN_32(pl->pl_sp_devid, bufpl->pl_sp_devid);
|
||||||
|
CPIN_32(pl->pl_sp_type, bufpl->pl_sp_type);
|
||||||
|
CPIN_64(pl->pl_blocks, bufpl->pl_blocks);
|
||||||
|
CPIN_32(pl->pl_striping, bufpl->pl_striping);
|
||||||
|
CPIN_32(pl->pl_sp_dmepdevs, bufpl->pl_sp_dmepdevs);
|
||||||
|
CPIN_32(pl->pl_sp_dmepid, bufpl->pl_sp_dmepid);
|
||||||
|
CPIN_32(pl->pl_sp_weight, bufpl->pl_sp_weight);
|
||||||
|
CPIN_32(pl->pl_minor, bufpl->pl_minor);
|
||||||
|
CPIN_32(pl->pl_padding, bufpl->pl_padding);
|
||||||
|
CPIN_8(pl->pl_reserve, bufpl->pl_reserve, 184);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char _calc_char(unsigned int id)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* [0-9A-Za-z!#] - 64 printable chars (6-bits)
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (id < 10)
|
||||||
|
return id + 48;
|
||||||
|
if (id < 36)
|
||||||
|
return (id - 10) + 65;
|
||||||
|
if (id < 62)
|
||||||
|
return (id - 36) + 97;
|
||||||
|
if (id == 62)
|
||||||
|
return '!';
|
||||||
|
if (id == 63)
|
||||||
|
return '#';
|
||||||
|
|
||||||
|
return '%';
|
||||||
|
}
|
||||||
|
|
||||||
|
void get_pool_uuid(char *uuid, uint64_t poolid, uint32_t spid, uint32_t devid)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
unsigned shifter = 0x003F;
|
||||||
|
|
||||||
|
assert(ID_LEN == 32);
|
||||||
|
memset(uuid, 0, ID_LEN);
|
||||||
|
strcat(uuid, "POOL0000000000");
|
||||||
|
|
||||||
|
/* We grab the entire 64 bits (+2 that get shifted in) */
|
||||||
|
for (i = 13; i < 24; i++) {
|
||||||
|
uuid[i] = _calc_char(((unsigned) poolid) & shifter);
|
||||||
|
poolid = poolid >> 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We grab the entire 32 bits (+4 that get shifted in) */
|
||||||
|
for (i = 24; i < 30; i++) {
|
||||||
|
uuid[i] = _calc_char((unsigned) (spid & shifter));
|
||||||
|
spid = spid >> 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Since we can only have 128 devices, we only worry about the
|
||||||
|
* last 12 bits
|
||||||
|
*/
|
||||||
|
for (i = 30; i < 32; i++) {
|
||||||
|
uuid[i] = _calc_char((unsigned) (devid & shifter));
|
||||||
|
devid = devid >> 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _read_vg_pds(const struct format_type *fmt, struct pool *mem,
|
||||||
|
struct lvmcache_vginfo *vginfo, struct list *head,
|
||||||
|
uint32_t *devcount)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct list *vgih = NULL;
|
||||||
|
struct device *dev;
|
||||||
|
struct pool_list *pl = NULL;
|
||||||
|
struct pool *tmpmem = NULL;
|
||||||
|
|
||||||
|
uint32_t sp_count = 0;
|
||||||
|
uint32_t *sp_devs = NULL;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* FIXME: maybe should return a different error in memory
|
||||||
|
* allocation failure */
|
||||||
|
if (!(tmpmem = pool_create(512))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_iterate(vgih, &vginfo->infos) {
|
||||||
|
dev = list_item(vgih, struct lvmcache_info)->dev;
|
||||||
|
if (dev &&
|
||||||
|
!(pl = read_pool_disk(fmt, dev, mem, vginfo->vgname)))
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
* We need to keep track of the total expected number
|
||||||
|
* of devices per subpool
|
||||||
|
*/
|
||||||
|
if (!sp_count) {
|
||||||
|
sp_count = pl->pd.pl_subpools;
|
||||||
|
if (!(sp_devs =
|
||||||
|
pool_zalloc(tmpmem,
|
||||||
|
sizeof(uint32_t) * sp_count))) {
|
||||||
|
log_error("Unable to allocate %d 32-bit uints",
|
||||||
|
sp_count);
|
||||||
|
pool_destroy(tmpmem);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* watch out for a pool label with a different subpool
|
||||||
|
* count than the original - give up if it does
|
||||||
|
*/
|
||||||
|
if (sp_count != pl->pd.pl_subpools)
|
||||||
|
break;
|
||||||
|
|
||||||
|
_add_pl_to_list(head, pl);
|
||||||
|
|
||||||
|
if (sp_count > pl->pd.pl_sp_id && sp_devs[pl->pd.pl_sp_id] == 0)
|
||||||
|
sp_devs[pl->pd.pl_sp_id] = pl->pd.pl_sp_devs;
|
||||||
|
}
|
||||||
|
|
||||||
|
*devcount = 0;
|
||||||
|
for (i = 0; i < sp_count; i++) {
|
||||||
|
*devcount += sp_devs[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
pool_destroy(tmpmem);
|
||||||
|
|
||||||
|
if (pl && *pl->pd.pl_pool_name)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int read_pool_pds(const struct format_type *fmt, const char *vg_name,
|
||||||
|
struct pool *mem, struct list *pdhead)
|
||||||
|
{
|
||||||
|
struct lvmcache_vginfo *vginfo;
|
||||||
|
uint32_t totaldevs;
|
||||||
|
int full_scan = -1;
|
||||||
|
|
||||||
|
do {
|
||||||
|
/*
|
||||||
|
* If the cache scanning doesn't work, this will never work
|
||||||
|
*/
|
||||||
|
if (vg_name && (vginfo = vginfo_from_vgname(vg_name)) &&
|
||||||
|
vginfo->infos.n) {
|
||||||
|
|
||||||
|
if (_read_vg_pds(fmt, mem, vginfo, pdhead, &totaldevs)) {
|
||||||
|
/*
|
||||||
|
* If we found all the devices we were
|
||||||
|
* expecting, return success
|
||||||
|
*/
|
||||||
|
if (list_size(pdhead) == totaldevs)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* accept partial pool if we've done a full
|
||||||
|
* rescan of the cache
|
||||||
|
*/
|
||||||
|
if (full_scan > 0)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Failed */
|
||||||
|
list_init(pdhead);
|
||||||
|
|
||||||
|
full_scan++;
|
||||||
|
if (full_scan > 1) {
|
||||||
|
log_debug("No devices for vg %s found in cache",
|
||||||
|
vg_name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
lvmcache_label_scan(fmt->cmd, full_scan);
|
||||||
|
|
||||||
|
} while (1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct pool_list *read_pool_disk(const struct format_type *fmt,
|
||||||
|
struct device *dev, struct pool *mem,
|
||||||
|
const char *vg_name)
|
||||||
|
{
|
||||||
|
struct pool_list *pl;
|
||||||
|
|
||||||
|
if (!dev_open(dev)) {
|
||||||
|
stack;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(pl = pool_zalloc(mem, sizeof(*pl)))) {
|
||||||
|
log_error("Unable to allocate pool list structure");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!__read_pool_disk(fmt, dev, mem, pl, vg_name)) {
|
||||||
|
stack;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dev_close(dev))
|
||||||
|
stack;
|
||||||
|
|
||||||
|
return pl;
|
||||||
|
|
||||||
|
}
|
||||||
178
lib/format_pool/disk_rep.h
Normal file
178
lib/format_pool/disk_rep.h
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
/*
|
||||||
|
* 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 DISK_REP_FORMAT_POOL_H
|
||||||
|
#define DISK_REP_FORMAT_POOL_H
|
||||||
|
|
||||||
|
#include "label.h"
|
||||||
|
#include "metadata.h"
|
||||||
|
#include "pool.h"
|
||||||
|
|
||||||
|
/* From NSP.cf */
|
||||||
|
#define NSPMajorVersion 4
|
||||||
|
#define NSPMinorVersion 1
|
||||||
|
#define NSPUpdateLevel 3
|
||||||
|
|
||||||
|
/* From pool_std.h */
|
||||||
|
#define POOL_NAME_SIZE (256)
|
||||||
|
#define POOL_MAGIC 0x011670
|
||||||
|
#define POOL_MAJOR (121)
|
||||||
|
#define POOL_MAX_DEVICES 128
|
||||||
|
|
||||||
|
/* When checking for version matching, the first two numbers **
|
||||||
|
** are important for metadata formats, a.k.a pool labels. **
|
||||||
|
** All the numbers are important when checking if the user **
|
||||||
|
** space tools match up with the kernel module............. */
|
||||||
|
#define POOL_VERSION (NSPMajorVersion << 16 | \
|
||||||
|
NSPMinorVersion << 8 | \
|
||||||
|
NSPUpdateLevel)
|
||||||
|
|
||||||
|
/* Pool label is at the head of every pool disk partition */
|
||||||
|
#define SIZEOF_POOL_LABEL (8192)
|
||||||
|
|
||||||
|
/* in sectors */
|
||||||
|
#define POOL_PE_SIZE (SIZEOF_POOL_LABEL >> SECTOR_SHIFT)
|
||||||
|
#define POOL_PE_START (SIZEOF_POOL_LABEL >> SECTOR_SHIFT)
|
||||||
|
|
||||||
|
/* Helper fxns */
|
||||||
|
#define get_pool_vg_uuid(id, pd) do { get_pool_uuid((char *)(id), \
|
||||||
|
(pd)->pl_pool_id, 0, 0); \
|
||||||
|
} while(0)
|
||||||
|
#define get_pool_pv_uuid(id, pd) do { get_pool_uuid((char *)(id), \
|
||||||
|
(pd)->pl_pool_id, \
|
||||||
|
(pd)->pl_sp_id, \
|
||||||
|
(pd)->pl_sp_devid); \
|
||||||
|
} while(0)
|
||||||
|
#define get_pool_lv_uuid(id, pd) do { get_pool_uuid((char *)&(id)[0], \
|
||||||
|
(pd)->pl_pool_id, 0, 0); \
|
||||||
|
get_pool_uuid((char*)&(id)[1], \
|
||||||
|
(pd)->pl_pool_id, 0, 0); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
struct pool_disk;
|
||||||
|
struct pool_list;
|
||||||
|
struct user_subpool;
|
||||||
|
struct user_device;
|
||||||
|
|
||||||
|
/* This must be kept up to date with sistina/pool/module/pool_sptypes.h */
|
||||||
|
|
||||||
|
/* Generic Labels */
|
||||||
|
#define SPTYPE_DATA (0x00000000)
|
||||||
|
|
||||||
|
/* GFS specific labels */
|
||||||
|
#define SPTYPE_GFS_DATA (0x68011670)
|
||||||
|
#define SPTYPE_GFS_JOURNAL (0x69011670)
|
||||||
|
|
||||||
|
struct sptype_name {
|
||||||
|
const char *name;
|
||||||
|
uint32_t label;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct sptype_name sptype_names[] = {
|
||||||
|
{"data", SPTYPE_DATA},
|
||||||
|
|
||||||
|
{"gfs_data", SPTYPE_GFS_DATA},
|
||||||
|
{"gfs_journal", SPTYPE_GFS_JOURNAL},
|
||||||
|
|
||||||
|
{"", 0x0} /* This must be the last flag. */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pool_disk {
|
||||||
|
uint64_t pl_magic; /* Pool magic number */
|
||||||
|
uint64_t pl_pool_id; /* Unique pool identifier */
|
||||||
|
char pl_pool_name[POOL_NAME_SIZE]; /* Name of pool */
|
||||||
|
uint32_t pl_version; /* Pool version */
|
||||||
|
uint32_t pl_subpools; /* Number of subpools in this pool */
|
||||||
|
uint32_t pl_sp_id; /* Subpool number within pool */
|
||||||
|
uint32_t pl_sp_devs; /* Number of data partitions in this subpool */
|
||||||
|
uint32_t pl_sp_devid; /* Partition number within subpool */
|
||||||
|
uint32_t pl_sp_type; /* Partition type */
|
||||||
|
uint64_t pl_blocks; /* Number of blocks in this partition */
|
||||||
|
uint32_t pl_striping; /* Striping size within subpool */
|
||||||
|
/*
|
||||||
|
* If the number of DMEP devices is zero, then the next field **
|
||||||
|
* ** (pl_sp_dmepid) becomes the subpool ID for redirection. In **
|
||||||
|
* ** other words, if this subpool does not have the capability **
|
||||||
|
* ** to do DMEP, then it must specify which subpool will do it **
|
||||||
|
* ** in it's place
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* While the next 3 field are no longer used, they must stay to keep **
|
||||||
|
* ** backward compatibility...........................................
|
||||||
|
*/
|
||||||
|
uint32_t pl_sp_dmepdevs;/* Number of dmep devices in this subpool */
|
||||||
|
uint32_t pl_sp_dmepid; /* Dmep device number within subpool */
|
||||||
|
uint32_t pl_sp_weight; /* if dmep dev, pref to using it */
|
||||||
|
|
||||||
|
uint32_t pl_minor; /* the pool minor number */
|
||||||
|
uint32_t pl_padding; /* reminder - think about alignment */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Even though we're zeroing out 8k at the front of the disk before
|
||||||
|
* writing the label, putting this in
|
||||||
|
*/
|
||||||
|
char pl_reserve[184]; /* bump the structure size out to 512 bytes */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pool_list {
|
||||||
|
struct list list;
|
||||||
|
struct pool_disk pd;
|
||||||
|
struct physical_volume *pv;
|
||||||
|
struct id pv_uuid;
|
||||||
|
struct device *dev;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct user_subpool {
|
||||||
|
uint32_t initialized;
|
||||||
|
uint32_t id;
|
||||||
|
uint32_t striping;
|
||||||
|
uint32_t num_devs;
|
||||||
|
uint32_t type;
|
||||||
|
uint32_t dummy;
|
||||||
|
struct user_device *devs;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct user_device {
|
||||||
|
uint32_t initialized;
|
||||||
|
uint32_t sp_id;
|
||||||
|
uint32_t devid;
|
||||||
|
uint32_t dummy;
|
||||||
|
uint64_t blocks;
|
||||||
|
struct physical_volume *pv;
|
||||||
|
};
|
||||||
|
|
||||||
|
int read_pool_label(struct pool_list *pl, struct labeller *l,
|
||||||
|
struct device *dev, char *buf, struct label **label);
|
||||||
|
void pool_label_out(struct pool_disk *pl, char *buf);
|
||||||
|
void pool_label_in(struct pool_disk *pl, char *buf);
|
||||||
|
void get_pool_uuid(char *uuid, uint64_t poolid, uint32_t spid, uint32_t devid);
|
||||||
|
int import_pool_vg(struct volume_group *vg, struct pool *mem, struct list *pls);
|
||||||
|
int import_pool_lvs(struct volume_group *vg, struct pool *mem,
|
||||||
|
struct list *pls);
|
||||||
|
int import_pool_pvs(const struct format_type *fmt, struct volume_group *vg,
|
||||||
|
struct list *pvs, struct pool *mem, struct list *pls);
|
||||||
|
int import_pool_pv(const struct format_type *fmt, struct pool *mem,
|
||||||
|
struct volume_group *vg, struct physical_volume *pv,
|
||||||
|
struct pool_list *pl);
|
||||||
|
int import_pool_segments(struct list *lvs, struct pool *mem,
|
||||||
|
struct user_subpool *usp, int sp_count);
|
||||||
|
int read_pool_pds(const struct format_type *fmt, const char *vgname,
|
||||||
|
struct pool *mem, struct list *head);
|
||||||
|
struct pool_list *read_pool_disk(const struct format_type *fmt,
|
||||||
|
struct device *dev, struct pool *mem,
|
||||||
|
const char *vg_name);
|
||||||
|
|
||||||
|
#endif /* DISK_REP_POOL_FORMAT_H */
|
||||||
363
lib/format_pool/format_pool.c
Normal file
363
lib/format_pool/format_pool.c
Normal file
@@ -0,0 +1,363 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lib.h"
|
||||||
|
#include "pool.h"
|
||||||
|
#include "label.h"
|
||||||
|
#include "metadata.h"
|
||||||
|
#include "hash.h"
|
||||||
|
#include "limits.h"
|
||||||
|
#include "list.h"
|
||||||
|
#include "display.h"
|
||||||
|
#include "toolcontext.h"
|
||||||
|
#include "lvmcache.h"
|
||||||
|
#include "disk_rep.h"
|
||||||
|
#include "format_pool.h"
|
||||||
|
#include "pool_label.h"
|
||||||
|
|
||||||
|
#define FMT_POOL_NAME "pool"
|
||||||
|
|
||||||
|
/* Must be called after pvs are imported */
|
||||||
|
static struct user_subpool *_build_usp(struct list *pls, struct pool *mem,
|
||||||
|
int *sps)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct list *plhs;
|
||||||
|
struct pool_list *pl;
|
||||||
|
struct user_subpool *usp = NULL, *cur_sp = NULL;
|
||||||
|
struct user_device *cur_dev = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FIXME: Need to do some checks here - I'm tempted to add a
|
||||||
|
* user_pool structure and build the entire thing to check against.
|
||||||
|
*/
|
||||||
|
list_iterate(plhs, pls) {
|
||||||
|
pl = list_item(plhs, struct pool_list);
|
||||||
|
|
||||||
|
*sps = pl->pd.pl_subpools;
|
||||||
|
if (!usp && (!(usp = pool_zalloc(mem, sizeof(*usp) * (*sps))))) {
|
||||||
|
log_error("Unable to allocate %d subpool structures",
|
||||||
|
*sps);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cur_sp != &usp[pl->pd.pl_sp_id]) {
|
||||||
|
cur_sp = &usp[pl->pd.pl_sp_id];
|
||||||
|
|
||||||
|
cur_sp->id = pl->pd.pl_sp_id;
|
||||||
|
cur_sp->striping = pl->pd.pl_striping;
|
||||||
|
cur_sp->num_devs = pl->pd.pl_sp_devs;
|
||||||
|
cur_sp->type = pl->pd.pl_sp_type;
|
||||||
|
cur_sp->initialized = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cur_sp->devs &&
|
||||||
|
(!(cur_sp->devs =
|
||||||
|
pool_zalloc(mem,
|
||||||
|
sizeof(*usp->devs) * pl->pd.pl_sp_devs)))) {
|
||||||
|
|
||||||
|
log_error("Unable to allocate %d pool_device "
|
||||||
|
"structures", pl->pd.pl_sp_devs);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
cur_dev = &cur_sp->devs[pl->pd.pl_sp_devid];
|
||||||
|
cur_dev->sp_id = cur_sp->id;
|
||||||
|
cur_dev->devid = pl->pd.pl_sp_id;
|
||||||
|
cur_dev->blocks = pl->pd.pl_blocks;
|
||||||
|
cur_dev->pv = pl->pv;
|
||||||
|
cur_dev->initialized = 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return usp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _check_usp(char *vgname, struct user_subpool *usp, int sp_count)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
for (i = 0; i < sp_count; i++) {
|
||||||
|
if (!usp[i].initialized) {
|
||||||
|
log_error("Missing subpool %d in pool %s", i, vgname);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
for (j = 0; j < usp[i].num_devs; j++) {
|
||||||
|
if (!usp[i].devs[j].initialized) {
|
||||||
|
log_error("Missing device %d for subpool %d"
|
||||||
|
" in pool %s", j, i, vgname);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct volume_group *_build_vg_from_pds(struct format_instance
|
||||||
|
*fid, struct pool *mem,
|
||||||
|
struct list *pds)
|
||||||
|
{
|
||||||
|
struct pool *smem = fid->fmt->cmd->mem;
|
||||||
|
struct volume_group *vg = NULL;
|
||||||
|
struct user_subpool *usp = NULL;
|
||||||
|
int sp_count;
|
||||||
|
|
||||||
|
if (!(vg = pool_zalloc(smem, sizeof(*vg)))) {
|
||||||
|
log_error("Unable to allocate volume group structure");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
vg->cmd = fid->fmt->cmd;
|
||||||
|
vg->fid = fid;
|
||||||
|
vg->name = NULL;
|
||||||
|
vg->status = 0;
|
||||||
|
vg->extent_count = 0;
|
||||||
|
vg->pv_count = 0;
|
||||||
|
vg->lv_count = 0;
|
||||||
|
vg->snapshot_count = 0;
|
||||||
|
vg->seqno = 1;
|
||||||
|
vg->system_id = NULL;
|
||||||
|
list_init(&vg->pvs);
|
||||||
|
list_init(&vg->lvs);
|
||||||
|
list_init(&vg->snapshots);
|
||||||
|
list_init(&vg->tags);
|
||||||
|
|
||||||
|
if (!import_pool_vg(vg, smem, pds)) {
|
||||||
|
stack;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!import_pool_pvs(fid->fmt, vg, &vg->pvs, smem, pds)) {
|
||||||
|
stack;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!import_pool_lvs(vg, smem, pds)) {
|
||||||
|
stack;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* I need an intermediate subpool structure that contains all the
|
||||||
|
* relevant info for this. Then i can iterate through the subpool
|
||||||
|
* structures for checking, and create the segments
|
||||||
|
*/
|
||||||
|
if (!(usp = _build_usp(pds, mem, &sp_count))) {
|
||||||
|
stack;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* check the subpool structures - we can't handle partial VGs in
|
||||||
|
* the pool format, so this will error out if we're missing PVs
|
||||||
|
*/
|
||||||
|
if (!_check_usp(vg->name, usp, sp_count)) {
|
||||||
|
stack;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!import_pool_segments(&vg->lvs, smem, usp, sp_count)) {
|
||||||
|
stack;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return vg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct volume_group *_vg_read(struct format_instance *fid,
|
||||||
|
const char *vg_name,
|
||||||
|
struct metadata_area *mda)
|
||||||
|
{
|
||||||
|
struct pool *mem = pool_create(1024);
|
||||||
|
struct list pds;
|
||||||
|
struct volume_group *vg = NULL;
|
||||||
|
|
||||||
|
list_init(&pds);
|
||||||
|
|
||||||
|
/* We can safely ignore the mda passed in */
|
||||||
|
|
||||||
|
if (!mem) {
|
||||||
|
stack;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Strip dev_dir if present */
|
||||||
|
vg_name = strip_dir(vg_name, fid->fmt->cmd->dev_dir);
|
||||||
|
|
||||||
|
/* Read all the pvs in the vg */
|
||||||
|
if (!read_pool_pds(fid->fmt, vg_name, mem, &pds)) {
|
||||||
|
stack;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do the rest of the vg stuff */
|
||||||
|
if (!(vg = _build_vg_from_pds(fid, mem, &pds))) {
|
||||||
|
stack;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
pool_destroy(mem);
|
||||||
|
return vg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _pv_setup(const struct format_type *fmt,
|
||||||
|
uint64_t pe_start, uint32_t extent_count,
|
||||||
|
uint32_t extent_size,
|
||||||
|
int pvmetadatacopies,
|
||||||
|
uint64_t pvmetadatasize, struct list *mdas,
|
||||||
|
struct physical_volume *pv, struct volume_group *vg)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _pv_read(const struct format_type *fmt, const char *pv_name,
|
||||||
|
struct physical_volume *pv, struct list *mdas)
|
||||||
|
{
|
||||||
|
struct pool *mem = pool_create(1024);
|
||||||
|
struct pool_list *pl;
|
||||||
|
struct device *dev;
|
||||||
|
int r = 0;
|
||||||
|
|
||||||
|
log_very_verbose("Reading physical volume data %s from disk", pv_name);
|
||||||
|
|
||||||
|
if (!mem) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(dev = dev_cache_get(pv_name, fmt->cmd->filter))) {
|
||||||
|
stack;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* I need to read the disk and populate a pv structure here
|
||||||
|
* I'll probably need to abstract some of this later for the
|
||||||
|
* vg_read code
|
||||||
|
*/
|
||||||
|
if (!(pl = read_pool_disk(fmt, dev, mem, NULL))) {
|
||||||
|
stack;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!import_pool_pv(fmt, fmt->cmd->mem, NULL, pv, pl)) {
|
||||||
|
stack;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
pv->fmt = fmt;
|
||||||
|
|
||||||
|
r = 1;
|
||||||
|
|
||||||
|
out:
|
||||||
|
pool_destroy(mem);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* *INDENT-OFF* */
|
||||||
|
static struct metadata_area_ops _metadata_format_pool_ops = {
|
||||||
|
vg_read:_vg_read,
|
||||||
|
};
|
||||||
|
/* *INDENT-ON* */
|
||||||
|
|
||||||
|
static struct format_instance *_create_instance(const struct format_type *fmt,
|
||||||
|
const char *vgname,
|
||||||
|
void *private)
|
||||||
|
{
|
||||||
|
struct format_instance *fid;
|
||||||
|
struct metadata_area *mda;
|
||||||
|
|
||||||
|
if (!(fid = pool_zalloc(fmt->cmd->mem, sizeof(*fid)))) {
|
||||||
|
log_error("Unable to allocate format instance structure for "
|
||||||
|
"pool format");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
fid->fmt = fmt;
|
||||||
|
list_init(&fid->metadata_areas);
|
||||||
|
|
||||||
|
/* Define a NULL metadata area */
|
||||||
|
if (!(mda = pool_zalloc(fmt->cmd->mem, sizeof(*mda)))) {
|
||||||
|
log_error("Unable to allocate metadata area structure "
|
||||||
|
"for pool format");
|
||||||
|
pool_free(fmt->cmd->mem, fid);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mda->ops = &_metadata_format_pool_ops;
|
||||||
|
mda->metadata_locn = NULL;
|
||||||
|
list_add(&fid->metadata_areas, &mda->list);
|
||||||
|
|
||||||
|
return fid;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _destroy_instance(struct format_instance *fid)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _destroy(const struct format_type *fmt)
|
||||||
|
{
|
||||||
|
dbg_free((void *) fmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* *INDENT-OFF* */
|
||||||
|
static struct format_handler _format_pool_ops = {
|
||||||
|
pv_read:_pv_read,
|
||||||
|
pv_setup:_pv_setup,
|
||||||
|
create_instance:_create_instance,
|
||||||
|
destroy_instance:_destroy_instance,
|
||||||
|
destroy:_destroy,
|
||||||
|
};
|
||||||
|
/* *INDENT-ON */
|
||||||
|
|
||||||
|
#ifdef POOL_INTERNAL
|
||||||
|
struct format_type *init_pool_format(struct cmd_context *cmd)
|
||||||
|
#else /* Shared */
|
||||||
|
struct format_type *init_format(struct cmd_context *cmd);
|
||||||
|
struct format_type *init_format(struct cmd_context *cmd)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
struct format_type *fmt = dbg_malloc(sizeof(*fmt));
|
||||||
|
|
||||||
|
if (!fmt) {
|
||||||
|
log_error("Unable to allocate format type structure for pool "
|
||||||
|
"format");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt->cmd = cmd;
|
||||||
|
fmt->ops = &_format_pool_ops;
|
||||||
|
fmt->name = FMT_POOL_NAME;
|
||||||
|
fmt->alias = NULL;
|
||||||
|
fmt->features = 0;
|
||||||
|
fmt->private = NULL;
|
||||||
|
|
||||||
|
if (!(fmt->labeller = pool_labeller_create(fmt))) {
|
||||||
|
log_error("Couldn't create pool label handler.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(label_register_handler(FMT_POOL_NAME, fmt->labeller))) {
|
||||||
|
log_error("Couldn't register pool label handler.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_very_verbose("Initialised format: %s", fmt->name);
|
||||||
|
|
||||||
|
return fmt;
|
||||||
|
}
|
||||||
25
lib/format_pool/format_pool.h
Normal file
25
lib/format_pool/format_pool.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LVM_FORMAT_POOL_H
|
||||||
|
#define _LVM_FORMAT_POOL_H
|
||||||
|
|
||||||
|
#include "metadata.h"
|
||||||
|
|
||||||
|
#ifdef POOL_INTERNAL
|
||||||
|
struct format_type *init_pool_format(struct cmd_context *cmd);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
309
lib/format_pool/import_export.c
Normal file
309
lib/format_pool/import_export.c
Normal file
@@ -0,0 +1,309 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lib.h"
|
||||||
|
#include "pool.h"
|
||||||
|
#include "label.h"
|
||||||
|
#include "metadata.h"
|
||||||
|
#include "lvmcache.h"
|
||||||
|
#include "disk_rep.h"
|
||||||
|
#include "lv_alloc.h"
|
||||||
|
#include "str_list.h"
|
||||||
|
#include "display.h"
|
||||||
|
#include "segtype.h"
|
||||||
|
|
||||||
|
/* This file contains only imports at the moment... */
|
||||||
|
|
||||||
|
int import_pool_vg(struct volume_group *vg, struct pool *mem, struct list *pls)
|
||||||
|
{
|
||||||
|
struct list *plhs;
|
||||||
|
struct pool_list *pl;
|
||||||
|
|
||||||
|
list_iterate(plhs, pls) {
|
||||||
|
pl = list_item(plhs, struct pool_list);
|
||||||
|
|
||||||
|
vg->extent_count +=
|
||||||
|
((pl->pd.pl_blocks) / POOL_PE_SIZE);
|
||||||
|
|
||||||
|
vg->pv_count++;
|
||||||
|
|
||||||
|
if (vg->name)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
vg->name = pool_strdup(mem, pl->pd.pl_pool_name);
|
||||||
|
get_pool_vg_uuid(&vg->id, &pl->pd);
|
||||||
|
vg->extent_size = POOL_PE_SIZE;
|
||||||
|
vg->status |= LVM_READ | LVM_WRITE | CLUSTERED | SHARED;
|
||||||
|
vg->free_count = 0;
|
||||||
|
vg->max_lv = 1;
|
||||||
|
vg->max_pv = POOL_MAX_DEVICES;
|
||||||
|
vg->alloc = ALLOC_NORMAL;
|
||||||
|
vg->lv_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int import_pool_lvs(struct volume_group *vg, struct pool *mem, struct list *pls)
|
||||||
|
{
|
||||||
|
struct pool_list *pl;
|
||||||
|
struct list *plhs;
|
||||||
|
struct lv_list *lvl = pool_zalloc(mem, sizeof(*lvl));
|
||||||
|
struct logical_volume *lv;
|
||||||
|
|
||||||
|
if (!lvl) {
|
||||||
|
log_error("Unable to allocate lv list structure");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(lvl->lv = pool_zalloc(mem, sizeof(*lvl->lv)))) {
|
||||||
|
log_error("Unable to allocate logical volume structure");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
lv = lvl->lv;
|
||||||
|
lv->status = 0;
|
||||||
|
lv->vg = vg;
|
||||||
|
lv->alloc = ALLOC_NORMAL;
|
||||||
|
lv->size = 0;
|
||||||
|
lv->name = NULL;
|
||||||
|
lv->le_count = 0;
|
||||||
|
lv->read_ahead = 0;
|
||||||
|
list_init(&lv->segments);
|
||||||
|
list_init(&lv->tags);
|
||||||
|
|
||||||
|
list_iterate(plhs, pls) {
|
||||||
|
pl = list_item(plhs, struct pool_list);
|
||||||
|
|
||||||
|
lv->size += pl->pd.pl_blocks;
|
||||||
|
|
||||||
|
if (lv->name)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!(lv->name = pool_strdup(mem, pl->pd.pl_pool_name))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
get_pool_lv_uuid(lv->lvid.id, &pl->pd);
|
||||||
|
log_debug("Calculated lv uuid for lv %s: %s", lv->name,
|
||||||
|
lv->lvid.s);
|
||||||
|
|
||||||
|
lv->status |= VISIBLE_LV | LVM_READ | LVM_WRITE;
|
||||||
|
lv->major = POOL_MAJOR;
|
||||||
|
|
||||||
|
/* for pool a minor of 0 is dynamic */
|
||||||
|
if (pl->pd.pl_minor) {
|
||||||
|
lv->status |= FIXED_MINOR;
|
||||||
|
lv->minor = pl->pd.pl_minor;
|
||||||
|
} else {
|
||||||
|
lv->minor = -1;
|
||||||
|
}
|
||||||
|
list_init(&lv->segments);
|
||||||
|
list_init(&lv->tags);
|
||||||
|
}
|
||||||
|
|
||||||
|
lv->le_count = lv->size / POOL_PE_SIZE;
|
||||||
|
lvl->lv = lv;
|
||||||
|
list_add(&vg->lvs, &lvl->list);
|
||||||
|
vg->lv_count++;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int import_pool_pvs(const struct format_type *fmt, struct volume_group *vg,
|
||||||
|
struct list *pvs, struct pool *mem, struct list *pls)
|
||||||
|
{
|
||||||
|
struct pv_list *pvl;
|
||||||
|
struct pool_list *pl;
|
||||||
|
struct list *plhs;
|
||||||
|
|
||||||
|
list_iterate(plhs, pls) {
|
||||||
|
pl = list_item(plhs, struct pool_list);
|
||||||
|
|
||||||
|
if (!(pvl = pool_zalloc(mem, sizeof(*pvl)))) {
|
||||||
|
log_error("Unable to allocate pv list structure");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!(pvl->pv = pool_zalloc(mem, sizeof(*pvl->pv)))) {
|
||||||
|
log_error("Unable to allocate pv structure");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!import_pool_pv(fmt, mem, vg, pvl->pv, pl)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
pl->pv = pvl->pv;
|
||||||
|
pvl->mdas = NULL;
|
||||||
|
pvl->pe_ranges = NULL;
|
||||||
|
list_add(pvs, &pvl->list);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int import_pool_pv(const struct format_type *fmt, struct pool *mem,
|
||||||
|
struct volume_group *vg, struct physical_volume *pv,
|
||||||
|
struct pool_list *pl)
|
||||||
|
{
|
||||||
|
struct pool_disk *pd = &pl->pd;
|
||||||
|
|
||||||
|
memset(pv, 0, sizeof(*pv));
|
||||||
|
|
||||||
|
get_pool_pv_uuid(&pv->id, pd);
|
||||||
|
pv->fmt = fmt;
|
||||||
|
|
||||||
|
pv->dev = pl->dev;
|
||||||
|
if (!(pv->vg_name = pool_strdup(mem, pd->pl_pool_name))) {
|
||||||
|
log_error("Unable to duplicate vg_name string");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
pv->status = 0;
|
||||||
|
pv->size = pd->pl_blocks;
|
||||||
|
pv->pe_size = POOL_PE_SIZE;
|
||||||
|
pv->pe_start = POOL_PE_START;
|
||||||
|
pv->pe_count = pv->size / POOL_PE_SIZE;
|
||||||
|
pv->pe_alloc_count = pv->pe_count;
|
||||||
|
|
||||||
|
list_init(&pv->tags);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *_cvt_sptype(uint32_t sptype)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; sptype_names[i].name[0]; i++) {
|
||||||
|
if (sptype == sptype_names[i].label) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log_debug("Found sptype %X and converted it to %s",
|
||||||
|
sptype, sptype_names[i].name);
|
||||||
|
return sptype_names[i].name;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _add_stripe_seg(struct pool *mem,
|
||||||
|
struct user_subpool *usp, struct logical_volume *lv,
|
||||||
|
uint32_t *le_cur)
|
||||||
|
{
|
||||||
|
struct lv_segment *seg;
|
||||||
|
int j;
|
||||||
|
|
||||||
|
if (!(seg = alloc_lv_segment(mem, usp->num_devs))) {
|
||||||
|
log_error("Unable to allocate striped lv_segment structure");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(usp->striping & (usp->striping - 1)) {
|
||||||
|
log_error("Stripe size must be a power of 2");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
seg->stripe_size = usp->striping;
|
||||||
|
seg->status |= 0;
|
||||||
|
seg->le += *le_cur;
|
||||||
|
|
||||||
|
/* add the subpool type to the segment tag list */
|
||||||
|
str_list_add(mem, &seg->tags, _cvt_sptype(usp->type));
|
||||||
|
|
||||||
|
for (j = 0; j < usp->num_devs; j++) {
|
||||||
|
if (!(seg->segtype = get_segtype_from_string(lv->vg->cmd,
|
||||||
|
"striped"))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
seg->area_len = (usp->devs[j].blocks) / POOL_PE_SIZE;
|
||||||
|
seg->len += seg->area_len;
|
||||||
|
*le_cur += seg->area_len;
|
||||||
|
seg->lv = lv;
|
||||||
|
|
||||||
|
seg->area[j].type = AREA_PV;
|
||||||
|
seg->area[j].u.pv.pv = usp->devs[j].pv;
|
||||||
|
seg->area[j].u.pv.pe = 0;
|
||||||
|
}
|
||||||
|
list_add(&lv->segments, &seg->list);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _add_linear_seg(struct pool *mem,
|
||||||
|
struct user_subpool *usp, struct logical_volume *lv,
|
||||||
|
uint32_t *le_cur)
|
||||||
|
{
|
||||||
|
struct lv_segment *seg;
|
||||||
|
int j;
|
||||||
|
|
||||||
|
for (j = 0; j < usp->num_devs; j++) {
|
||||||
|
/* linear segments only have 1 data area */
|
||||||
|
if (!(seg = alloc_lv_segment(mem, 1))) {
|
||||||
|
log_error("Unable to allocate linear lv_segment "
|
||||||
|
"structure");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
seg->stripe_size = usp->striping;
|
||||||
|
seg->le += *le_cur;
|
||||||
|
seg->chunk_size = POOL_PE_SIZE;
|
||||||
|
seg->status |= 0;
|
||||||
|
if (!(seg->segtype = get_segtype_from_string(lv->vg->cmd,
|
||||||
|
"striped"))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* add the subpool type to the segment tag list */
|
||||||
|
str_list_add(mem, &seg->tags, _cvt_sptype(usp->type));
|
||||||
|
|
||||||
|
seg->lv = lv;
|
||||||
|
|
||||||
|
seg->area_len = (usp->devs[j].blocks) / POOL_PE_SIZE;
|
||||||
|
seg->len = seg->area_len;
|
||||||
|
*le_cur += seg->len;
|
||||||
|
seg->area[0].type = AREA_PV;
|
||||||
|
seg->area[0].u.pv.pv = usp->devs[j].pv;
|
||||||
|
seg->area[0].u.pv.pe = 0;
|
||||||
|
list_add(&lv->segments, &seg->list);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int import_pool_segments(struct list *lvs, struct pool *mem,
|
||||||
|
struct user_subpool *usp, int subpools)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct list *lvhs;
|
||||||
|
struct lv_list *lvl;
|
||||||
|
struct logical_volume *lv;
|
||||||
|
uint32_t le_cur = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
list_iterate(lvhs, lvs) {
|
||||||
|
lvl = list_item(lvhs, struct lv_list);
|
||||||
|
|
||||||
|
lv = lvl->lv;
|
||||||
|
for (i = 0; i < subpools; i++) {
|
||||||
|
if (usp[i].striping) {
|
||||||
|
if (!_add_stripe_seg(mem, &usp[i], lv, &le_cur)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!_add_linear_seg(mem, &usp[i], lv, &le_cur)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
}
|
||||||
108
lib/format_pool/pool_label.c
Normal file
108
lib/format_pool/pool_label.c
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lib.h"
|
||||||
|
#include "pool.h"
|
||||||
|
#include "label.h"
|
||||||
|
#include "metadata.h"
|
||||||
|
#include "xlate.h"
|
||||||
|
#include "disk_rep.h"
|
||||||
|
#include "pool_label.h"
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
static void _not_supported(const char *op)
|
||||||
|
{
|
||||||
|
log_error("The '%s' operation is not supported for the pool labeller.",
|
||||||
|
op);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _can_handle(struct labeller *l, char *buf, uint64_t sector)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct pool_disk pd;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* POOL label must always be in first sector
|
||||||
|
*/
|
||||||
|
if (sector)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
pool_label_in(&pd, buf);
|
||||||
|
|
||||||
|
/* can ignore 8 rightmost bits for ondisk format check */
|
||||||
|
if ((pd.pl_magic == POOL_MAGIC) &&
|
||||||
|
(pd.pl_version >> 8 == POOL_VERSION >> 8))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _write(struct label *label, char *buf)
|
||||||
|
{
|
||||||
|
_not_supported("write");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _read(struct labeller *l, struct device *dev, char *buf,
|
||||||
|
struct label **label)
|
||||||
|
{
|
||||||
|
struct pool_list pl;
|
||||||
|
|
||||||
|
return read_pool_label(&pl, l, dev, buf, label);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _initialise_label(struct labeller *l, struct label *label)
|
||||||
|
{
|
||||||
|
strcpy(label->type, "POOL");
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _destroy_label(struct labeller *l, struct label *label)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _destroy(struct labeller *l)
|
||||||
|
{
|
||||||
|
dbg_free(l);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct label_ops _pool_ops = {
|
||||||
|
can_handle:_can_handle,
|
||||||
|
write:_write,
|
||||||
|
read:_read,
|
||||||
|
verify:_can_handle,
|
||||||
|
initialise_label:_initialise_label,
|
||||||
|
destroy_label:_destroy_label,
|
||||||
|
destroy:_destroy
|
||||||
|
};
|
||||||
|
|
||||||
|
struct labeller *pool_labeller_create(struct format_type *fmt)
|
||||||
|
{
|
||||||
|
struct labeller *l;
|
||||||
|
|
||||||
|
if (!(l = dbg_malloc(sizeof(*l)))) {
|
||||||
|
log_error("Couldn't allocate labeller object.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
l->ops = &_pool_ops;
|
||||||
|
l->private = (const void *) fmt;
|
||||||
|
|
||||||
|
return l;
|
||||||
|
}
|
||||||
23
lib/format_pool/pool_label.h
Normal file
23
lib/format_pool/pool_label.h
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* 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 _LVM_POOL_LABEL_H
|
||||||
|
#define _LVM_POOL_LABEL_H
|
||||||
|
|
||||||
|
#include "metadata.h"
|
||||||
|
|
||||||
|
struct labeller *pool_labeller_create(struct format_type *fmt);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -380,4 +380,3 @@ int backup_list(struct cmd_context *cmd, const char *dir, const char *vgname)
|
|||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,8 @@
|
|||||||
#include "pool.h"
|
#include "pool.h"
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include "lvm-string.h"
|
#include "lvm-string.h"
|
||||||
|
#include "segtype.h"
|
||||||
|
#include "text_export.h"
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
@@ -74,14 +76,6 @@ static void _init(void)
|
|||||||
/*
|
/*
|
||||||
* Formatting functions.
|
* Formatting functions.
|
||||||
*/
|
*/
|
||||||
static int _out_size(struct formatter *f, uint64_t size, const char *fmt, ...)
|
|
||||||
__attribute__ ((format(printf, 3, 4)));
|
|
||||||
|
|
||||||
static int _out_hint(struct formatter *f, const char *fmt, ...)
|
|
||||||
__attribute__ ((format(printf, 2, 3)));
|
|
||||||
|
|
||||||
static int _out(struct formatter *f, const char *fmt, ...)
|
|
||||||
__attribute__ ((format(printf, 2, 3)));
|
|
||||||
|
|
||||||
#define MAX_INDENT 5
|
#define MAX_INDENT 5
|
||||||
static void _inc_indent(struct formatter *f)
|
static void _inc_indent(struct formatter *f)
|
||||||
@@ -206,7 +200,7 @@ static int _sectors_to_units(uint64_t sectors, char *buffer, size_t s)
|
|||||||
* Appends a comment giving a size in more easily
|
* Appends a comment giving a size in more easily
|
||||||
* readable form (eg, 4M instead of 8096).
|
* readable form (eg, 4M instead of 8096).
|
||||||
*/
|
*/
|
||||||
static int _out_size(struct formatter *f, uint64_t size, const char *fmt, ...)
|
int out_size(struct formatter *f, uint64_t size, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
char buffer[64];
|
char buffer[64];
|
||||||
va_list ap;
|
va_list ap;
|
||||||
@@ -226,7 +220,7 @@ static int _out_size(struct formatter *f, uint64_t size, const char *fmt, ...)
|
|||||||
* Appends a comment indicating that the line is
|
* Appends a comment indicating that the line is
|
||||||
* only a hint.
|
* only a hint.
|
||||||
*/
|
*/
|
||||||
static int _out_hint(struct formatter *f, const char *fmt, ...)
|
int out_hint(struct formatter *f, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
int r;
|
int r;
|
||||||
@@ -241,7 +235,7 @@ static int _out_hint(struct formatter *f, const char *fmt, ...)
|
|||||||
/*
|
/*
|
||||||
* The normal output function.
|
* The normal output function.
|
||||||
*/
|
*/
|
||||||
static int _out(struct formatter *f, const char *fmt, ...)
|
int out_text(struct formatter *f, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
int r;
|
int r;
|
||||||
@@ -253,8 +247,6 @@ static int _out(struct formatter *f, const char *fmt, ...)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define _outf(args...) do {if (!_out(args)) {stack; return 0;}} while (0)
|
|
||||||
|
|
||||||
static int _print_header(struct formatter *f,
|
static int _print_header(struct formatter *f,
|
||||||
struct volume_group *vg, const char *desc)
|
struct volume_group *vg, const char *desc)
|
||||||
{
|
{
|
||||||
@@ -262,17 +254,17 @@ static int _print_header(struct formatter *f,
|
|||||||
|
|
||||||
t = time(NULL);
|
t = time(NULL);
|
||||||
|
|
||||||
_outf(f, "# Generated by LVM2: %s", ctime(&t));
|
outf(f, "# Generated by LVM2: %s", ctime(&t));
|
||||||
_outf(f, CONTENTS_FIELD " = \"" CONTENTS_VALUE "\"");
|
outf(f, CONTENTS_FIELD " = \"" CONTENTS_VALUE "\"");
|
||||||
_outf(f, FORMAT_VERSION_FIELD " = %d", FORMAT_VERSION_VALUE);
|
outf(f, FORMAT_VERSION_FIELD " = %d", FORMAT_VERSION_VALUE);
|
||||||
f->nl(f);
|
f->nl(f);
|
||||||
|
|
||||||
_outf(f, "description = \"%s\"", desc);
|
outf(f, "description = \"%s\"", desc);
|
||||||
f->nl(f);
|
f->nl(f);
|
||||||
_outf(f, "creation_host = \"%s\"\t# %s %s %s %s %s", _utsname.nodename,
|
outf(f, "creation_host = \"%s\"\t# %s %s %s %s %s", _utsname.nodename,
|
||||||
_utsname.sysname, _utsname.nodename, _utsname.release,
|
_utsname.sysname, _utsname.nodename, _utsname.release,
|
||||||
_utsname.version, _utsname.machine);
|
_utsname.version, _utsname.machine);
|
||||||
_outf(f, "creation_time = %lu\t# %s", t, ctime(&t));
|
outf(f, "creation_time = %lu\t# %s", t, ctime(&t));
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -286,34 +278,41 @@ static int _print_vg(struct formatter *f, struct volume_group *vg)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
_outf(f, "id = \"%s\"", buffer);
|
outf(f, "id = \"%s\"", buffer);
|
||||||
|
|
||||||
_outf(f, "seqno = %u", vg->seqno);
|
outf(f, "seqno = %u", vg->seqno);
|
||||||
|
|
||||||
if (!print_flags(vg->status, VG_FLAGS, buffer, sizeof(buffer))) {
|
if (!print_flags(vg->status, VG_FLAGS, buffer, sizeof(buffer))) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
_outf(f, "status = %s", buffer);
|
outf(f, "status = %s", buffer);
|
||||||
|
|
||||||
if (!list_empty(&vg->tags)) {
|
if (!list_empty(&vg->tags)) {
|
||||||
if (!print_tags(&vg->tags, buffer, sizeof(buffer))) {
|
if (!print_tags(&vg->tags, buffer, sizeof(buffer))) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
_outf(f, "tags = %s", buffer);
|
outf(f, "tags = %s", buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vg->system_id && *vg->system_id)
|
if (vg->system_id && *vg->system_id)
|
||||||
_outf(f, "system_id = \"%s\"", vg->system_id);
|
outf(f, "system_id = \"%s\"", vg->system_id);
|
||||||
|
|
||||||
if (!_out_size(f, (uint64_t) vg->extent_size, "extent_size = %u",
|
if (!out_size(f, (uint64_t) vg->extent_size, "extent_size = %u",
|
||||||
vg->extent_size)) {
|
vg->extent_size)) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
_outf(f, "max_lv = %u", vg->max_lv);
|
outf(f, "max_lv = %u", vg->max_lv);
|
||||||
_outf(f, "max_pv = %u", vg->max_pv);
|
outf(f, "max_pv = %u", vg->max_pv);
|
||||||
|
|
||||||
|
/* Default policy is NORMAL; INHERIT is meaningless */
|
||||||
|
if (vg->alloc != ALLOC_NORMAL && vg->alloc != ALLOC_INHERIT) {
|
||||||
|
f->nl(f);
|
||||||
|
outf(f, "allocation_policy = \"%s\"",
|
||||||
|
get_alloc_string(vg->alloc));
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -336,7 +335,7 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
|
|||||||
char buffer[4096];
|
char buffer[4096];
|
||||||
const char *name;
|
const char *name;
|
||||||
|
|
||||||
_outf(f, "physical_volumes {");
|
outf(f, "physical_volumes {");
|
||||||
_inc_indent(f);
|
_inc_indent(f);
|
||||||
|
|
||||||
list_iterate(pvh, &vg->pvs) {
|
list_iterate(pvh, &vg->pvs) {
|
||||||
@@ -348,7 +347,7 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
f->nl(f);
|
f->nl(f);
|
||||||
_outf(f, "%s {", name);
|
outf(f, "%s {", name);
|
||||||
_inc_indent(f);
|
_inc_indent(f);
|
||||||
|
|
||||||
if (!id_write_format(&pv->id, buffer, sizeof(buffer))) {
|
if (!id_write_format(&pv->id, buffer, sizeof(buffer))) {
|
||||||
@@ -356,8 +355,8 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
_outf(f, "id = \"%s\"", buffer);
|
outf(f, "id = \"%s\"", buffer);
|
||||||
if (!_out_hint(f, "device = \"%s\"", dev_name(pv->dev))) {
|
if (!out_hint(f, "device = \"%s\"", dev_name(pv->dev))) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -367,119 +366,106 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
|
|||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
_outf(f, "status = %s", buffer);
|
outf(f, "status = %s", buffer);
|
||||||
|
|
||||||
if (!list_empty(&pv->tags)) {
|
if (!list_empty(&pv->tags)) {
|
||||||
if (!print_tags(&pv->tags, buffer, sizeof(buffer))) {
|
if (!print_tags(&pv->tags, buffer, sizeof(buffer))) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
_outf(f, "tags = %s", buffer);
|
outf(f, "tags = %s", buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
_outf(f, "pe_start = %" PRIu64, pv->pe_start);
|
outf(f, "pe_start = %" PRIu64, pv->pe_start);
|
||||||
if (!_out_size(f, vg->extent_size * (uint64_t) pv->pe_count,
|
if (!out_size(f, vg->extent_size * (uint64_t) pv->pe_count,
|
||||||
"pe_count = %u", pv->pe_count)) {
|
"pe_count = %u", pv->pe_count)) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
_dec_indent(f);
|
_dec_indent(f);
|
||||||
_outf(f, "}");
|
outf(f, "}");
|
||||||
}
|
}
|
||||||
|
|
||||||
_dec_indent(f);
|
_dec_indent(f);
|
||||||
_outf(f, "}");
|
outf(f, "}");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _print_segment(struct formatter *f, struct volume_group *vg,
|
static int _print_segment(struct formatter *f, struct volume_group *vg,
|
||||||
int count, struct lv_segment *seg)
|
int count, struct lv_segment *seg)
|
||||||
{
|
{
|
||||||
unsigned int s;
|
|
||||||
const char *name;
|
|
||||||
const char *type;
|
|
||||||
char buffer[4096];
|
char buffer[4096];
|
||||||
|
|
||||||
_outf(f, "segment%u {", count);
|
outf(f, "segment%u {", count);
|
||||||
_inc_indent(f);
|
_inc_indent(f);
|
||||||
|
|
||||||
_outf(f, "start_extent = %u", seg->le);
|
outf(f, "start_extent = %u", seg->le);
|
||||||
if (!_out_size(f, (uint64_t) seg->len * vg->extent_size,
|
if (!out_size(f, (uint64_t) seg->len * vg->extent_size,
|
||||||
"extent_count = %u", seg->len)) {
|
"extent_count = %u", seg->len)) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
f->nl(f);
|
f->nl(f);
|
||||||
_outf(f, "type = \"%s\"", get_segtype_string(seg->type));
|
outf(f, "type = \"%s\"", seg->segtype->name);
|
||||||
|
|
||||||
if (!list_empty(&seg->tags)) {
|
if (!list_empty(&seg->tags)) {
|
||||||
if (!print_tags(&seg->tags, buffer, sizeof(buffer))) {
|
if (!print_tags(&seg->tags, buffer, sizeof(buffer))) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
_outf(f, "tags = %s", buffer);
|
outf(f, "tags = %s", buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (seg->type) {
|
if (seg->segtype->ops->text_export &&
|
||||||
case SEG_SNAPSHOT:
|
!seg->segtype->ops->text_export(seg, f)) {
|
||||||
_outf(f, "chunk_size = %u", seg->chunk_size);
|
stack;
|
||||||
_outf(f, "origin = \"%s\"", seg->origin->name);
|
return 0;
|
||||||
_outf(f, "cow_store = \"%s\"", seg->cow->name);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SEG_MIRRORED:
|
|
||||||
case SEG_STRIPED:
|
|
||||||
type = (seg->type == SEG_MIRRORED) ? "mirror" : "stripe";
|
|
||||||
_outf(f, "%s_count = %u%s", type, seg->area_count,
|
|
||||||
(seg->area_count == 1) ? "\t# linear" : "");
|
|
||||||
|
|
||||||
if ((seg->type == SEG_MIRRORED) && (seg->status & PVMOVE))
|
|
||||||
_out_size(f, (uint64_t) seg->extents_moved,
|
|
||||||
"extents_moved = %u", seg->extents_moved);
|
|
||||||
|
|
||||||
if ((seg->type == SEG_STRIPED) && (seg->area_count > 1))
|
|
||||||
_out_size(f, (uint64_t) seg->stripe_size,
|
|
||||||
"stripe_size = %u", seg->stripe_size);
|
|
||||||
|
|
||||||
f->nl(f);
|
|
||||||
|
|
||||||
_outf(f, "%ss = [", type);
|
|
||||||
_inc_indent(f);
|
|
||||||
|
|
||||||
for (s = 0; s < seg->area_count; s++) {
|
|
||||||
switch (seg->area[s].type) {
|
|
||||||
case AREA_PV:
|
|
||||||
if (!(name = _get_pv_name(f, seg->
|
|
||||||
area[s].u.pv.pv))) {
|
|
||||||
stack;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
_outf(f, "\"%s\", %u%s", name,
|
|
||||||
seg->area[s].u.pv.pe,
|
|
||||||
(s == seg->area_count - 1) ? "" : ",");
|
|
||||||
break;
|
|
||||||
case AREA_LV:
|
|
||||||
_outf(f, "\"%s\", %u%s",
|
|
||||||
seg->area[s].u.lv.lv->name,
|
|
||||||
seg->area[s].u.lv.le,
|
|
||||||
(s == seg->area_count - 1) ? "" : ",");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_dec_indent(f);
|
|
||||||
_outf(f, "]");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_dec_indent(f);
|
_dec_indent(f);
|
||||||
_outf(f, "}");
|
outf(f, "}");
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int out_areas(struct formatter *f, const struct lv_segment *seg,
|
||||||
|
const char *type)
|
||||||
|
{
|
||||||
|
const char *name;
|
||||||
|
unsigned int s;
|
||||||
|
|
||||||
|
f->nl(f);
|
||||||
|
|
||||||
|
outf(f, "%ss = [", type);
|
||||||
|
_inc_indent(f);
|
||||||
|
|
||||||
|
for (s = 0; s < seg->area_count; s++) {
|
||||||
|
switch (seg->area[s].type) {
|
||||||
|
case AREA_PV:
|
||||||
|
if (!(name = _get_pv_name(f, seg->area[s].u.pv.pv))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
outf(f, "\"%s\", %u%s", name,
|
||||||
|
seg->area[s].u.pv.pe,
|
||||||
|
(s == seg->area_count - 1) ? "" : ",");
|
||||||
|
break;
|
||||||
|
case AREA_LV:
|
||||||
|
outf(f, "\"%s\", %u%s",
|
||||||
|
seg->area[s].u.lv.lv->name,
|
||||||
|
seg->area[s].u.lv.le,
|
||||||
|
(s == seg->area_count - 1) ? "" : ",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_dec_indent(f);
|
||||||
|
outf(f, "]");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int _count_segments(struct logical_volume *lv)
|
static int _count_segments(struct logical_volume *lv)
|
||||||
{
|
{
|
||||||
int r = 0;
|
int r = 0;
|
||||||
@@ -499,7 +485,7 @@ static int _print_snapshot(struct formatter *f, struct snapshot *snap,
|
|||||||
|
|
||||||
f->nl(f);
|
f->nl(f);
|
||||||
|
|
||||||
_outf(f, "snapshot%u {", count);
|
outf(f, "snapshot%u {", count);
|
||||||
_inc_indent(f);
|
_inc_indent(f);
|
||||||
|
|
||||||
if (!id_write_format(&snap->id, buffer, sizeof(buffer))) {
|
if (!id_write_format(&snap->id, buffer, sizeof(buffer))) {
|
||||||
@@ -507,25 +493,39 @@ static int _print_snapshot(struct formatter *f, struct snapshot *snap,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
_outf(f, "id = \"%s\"", buffer);
|
outf(f, "id = \"%s\"", buffer);
|
||||||
if (!print_flags(LVM_READ | LVM_WRITE | VISIBLE_LV, LV_FLAGS,
|
|
||||||
buffer, sizeof(buffer))) {
|
seg.status = LVM_READ | LVM_WRITE | VISIBLE_LV;
|
||||||
|
if (!print_flags(seg.status, LV_FLAGS, buffer, sizeof(buffer))) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
_outf(f, "status = %s", buffer);
|
outf(f, "status = %s", buffer);
|
||||||
_outf(f, "segment_count = 1");
|
outf(f, "segment_count = 1");
|
||||||
|
|
||||||
f->nl(f);
|
f->nl(f);
|
||||||
|
|
||||||
seg.type = SEG_SNAPSHOT;
|
if (!(seg.segtype = get_segtype_from_string(snap->origin->vg->cmd,
|
||||||
|
"snapshot"))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
seg.le = 0;
|
seg.le = 0;
|
||||||
seg.len = snap->origin->le_count;
|
seg.len = snap->origin->le_count;
|
||||||
seg.origin = snap->origin;
|
seg.origin = snap->origin;
|
||||||
seg.cow = snap->cow;
|
seg.cow = snap->cow;
|
||||||
seg.chunk_size = snap->chunk_size;
|
seg.chunk_size = snap->chunk_size;
|
||||||
|
|
||||||
|
/* FIXME Dummy values */
|
||||||
|
list_init(&seg.list);
|
||||||
|
seg.lv = snap->cow;
|
||||||
|
seg.stripe_size = 0;
|
||||||
|
seg.area_count = 0;
|
||||||
|
seg.area_len = 0;
|
||||||
|
seg.extents_copied = 0;
|
||||||
|
|
||||||
/* Can't tag a snapshot independently of its origin */
|
/* Can't tag a snapshot independently of its origin */
|
||||||
list_init(&seg.tags);
|
list_init(&seg.tags);
|
||||||
|
|
||||||
@@ -535,7 +535,7 @@ static int _print_snapshot(struct formatter *f, struct snapshot *snap,
|
|||||||
}
|
}
|
||||||
|
|
||||||
_dec_indent(f);
|
_dec_indent(f);
|
||||||
_outf(f, "}");
|
outf(f, "}");
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -572,14 +572,14 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg)
|
|||||||
if (list_empty(&vg->lvs))
|
if (list_empty(&vg->lvs))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
_outf(f, "logical_volumes {");
|
outf(f, "logical_volumes {");
|
||||||
_inc_indent(f);
|
_inc_indent(f);
|
||||||
|
|
||||||
list_iterate(lvh, &vg->lvs) {
|
list_iterate(lvh, &vg->lvs) {
|
||||||
lv = list_item(lvh, struct lv_list)->lv;
|
lv = list_item(lvh, struct lv_list)->lv;
|
||||||
|
|
||||||
f->nl(f);
|
f->nl(f);
|
||||||
_outf(f, "%s {", lv->name);
|
outf(f, "%s {", lv->name);
|
||||||
_inc_indent(f);
|
_inc_indent(f);
|
||||||
|
|
||||||
/* FIXME: Write full lvid */
|
/* FIXME: Write full lvid */
|
||||||
@@ -588,32 +588,33 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
_outf(f, "id = \"%s\"", buffer);
|
outf(f, "id = \"%s\"", buffer);
|
||||||
|
|
||||||
if (!print_flags(lv->status, LV_FLAGS, buffer, sizeof(buffer))) {
|
if (!print_flags(lv->status, LV_FLAGS, buffer, sizeof(buffer))) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
_outf(f, "status = %s", buffer);
|
outf(f, "status = %s", buffer);
|
||||||
|
|
||||||
if (!list_empty(&lv->tags)) {
|
if (!list_empty(&lv->tags)) {
|
||||||
if (!print_tags(&lv->tags, buffer, sizeof(buffer))) {
|
if (!print_tags(&lv->tags, buffer, sizeof(buffer))) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
_outf(f, "tags = %s", buffer);
|
outf(f, "tags = %s", buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lv->alloc != ALLOC_DEFAULT)
|
if (lv->alloc != ALLOC_INHERIT)
|
||||||
_outf(f, "allocation_policy = \"%s\"",
|
outf(f, "allocation_policy = \"%s\"",
|
||||||
get_alloc_string(lv->alloc));
|
get_alloc_string(lv->alloc));
|
||||||
|
|
||||||
if (lv->read_ahead)
|
if (lv->read_ahead)
|
||||||
_outf(f, "read_ahead = %u", lv->read_ahead);
|
outf(f, "read_ahead = %u", lv->read_ahead);
|
||||||
if (lv->major >= 0)
|
if (lv->major >= 0)
|
||||||
_outf(f, "major = %d", lv->major);
|
outf(f, "major = %d", lv->major);
|
||||||
if (lv->minor >= 0)
|
if (lv->minor >= 0)
|
||||||
_outf(f, "minor = %d", lv->minor);
|
outf(f, "minor = %d", lv->minor);
|
||||||
_outf(f, "segment_count = %u", _count_segments(lv));
|
outf(f, "segment_count = %u", _count_segments(lv));
|
||||||
f->nl(f);
|
f->nl(f);
|
||||||
|
|
||||||
seg_count = 1;
|
seg_count = 1;
|
||||||
@@ -625,7 +626,7 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
_dec_indent(f);
|
_dec_indent(f);
|
||||||
_outf(f, "}");
|
outf(f, "}");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_print_snapshots(f, vg)) {
|
if (!_print_snapshots(f, vg)) {
|
||||||
@@ -634,7 +635,7 @@ static int _print_lvs(struct formatter *f, struct volume_group *vg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
_dec_indent(f);
|
_dec_indent(f);
|
||||||
_outf(f, "}");
|
outf(f, "}");
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -707,7 +708,7 @@ static int _text_vg_export(struct formatter *f,
|
|||||||
if (f->header && !_print_header(f, vg, desc))
|
if (f->header && !_print_header(f, vg, desc))
|
||||||
fail;
|
fail;
|
||||||
|
|
||||||
if (!_out(f, "%s {", vg->name))
|
if (!out_text(f, "%s {", vg->name))
|
||||||
fail;
|
fail;
|
||||||
|
|
||||||
_inc_indent(f);
|
_inc_indent(f);
|
||||||
@@ -724,7 +725,7 @@ static int _text_vg_export(struct formatter *f,
|
|||||||
fail;
|
fail;
|
||||||
|
|
||||||
_dec_indent(f);
|
_dec_indent(f);
|
||||||
if (!_out(f, "}"))
|
if (!out_text(f, "}"))
|
||||||
fail;
|
fail;
|
||||||
|
|
||||||
if (!f->header && !_print_header(f, vg, desc))
|
if (!f->header && !_print_header(f, vg, desc))
|
||||||
@@ -804,4 +805,4 @@ int text_vg_export_raw(struct volume_group *vg, const char *desc, char *buf,
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef _outf
|
#undef outf
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ static struct flag _lv_flags[] = {
|
|||||||
{VISIBLE_LV, "VISIBLE"},
|
{VISIBLE_LV, "VISIBLE"},
|
||||||
{PVMOVE, "PVMOVE"},
|
{PVMOVE, "PVMOVE"},
|
||||||
{LOCKED, "LOCKED"},
|
{LOCKED, "LOCKED"},
|
||||||
|
{MIRRORED, NULL},
|
||||||
|
{VIRTUAL, NULL},
|
||||||
{0, NULL}
|
{0, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -92,18 +94,21 @@ int print_flags(uint32_t status, int type, char *buffer, size_t size)
|
|||||||
|
|
||||||
for (f = 0; flags[f].mask; f++) {
|
for (f = 0; flags[f].mask; f++) {
|
||||||
if (status & flags[f].mask) {
|
if (status & flags[f].mask) {
|
||||||
|
status &= ~flags[f].mask;
|
||||||
|
|
||||||
|
/* Internal-only flag? */
|
||||||
|
if (!flags[f].description)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (!first) {
|
if (!first) {
|
||||||
if (!emit_to_buffer(&buffer, &size, ", "))
|
if (!emit_to_buffer(&buffer, &size, ", "))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
} else
|
} else
|
||||||
first = 0;
|
first = 0;
|
||||||
|
|
||||||
if (!emit_to_buffer(&buffer, &size, "\"%s\"",
|
if (!emit_to_buffer(&buffer, &size, "\"%s\"",
|
||||||
flags[f].description))
|
flags[f].description))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
status &= ~flags[f].mask;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
#include "xlate.h"
|
#include "xlate.h"
|
||||||
#include "label.h"
|
#include "label.h"
|
||||||
#include "memlock.h"
|
#include "memlock.h"
|
||||||
|
#include "lvmcache.h"
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/file.h>
|
#include <sys/file.h>
|
||||||
@@ -80,7 +81,7 @@ static int _lv_setup(struct format_instance *fid, struct logical_volume *lv)
|
|||||||
uint64_t max_size = UINT_MAX;
|
uint64_t max_size = UINT_MAX;
|
||||||
|
|
||||||
if (lv->size > max_size) {
|
if (lv->size > max_size) {
|
||||||
char *dummy = display_size(max_size / 2, SIZE_SHORT);
|
char *dummy = display_size(max_size, SIZE_SHORT);
|
||||||
log_error("logical volumes cannot be larger than %s", dummy);
|
log_error("logical volumes cannot be larger than %s", dummy);
|
||||||
dbg_free(dummy);
|
dbg_free(dummy);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -928,8 +929,7 @@ static int _mda_setup(const struct format_type *fmt,
|
|||||||
/* FIXME If creating new mdas, wipe them! */
|
/* FIXME If creating new mdas, wipe them! */
|
||||||
if (mda_size1) {
|
if (mda_size1) {
|
||||||
if (!add_mda(fmt, fmt->cmd->mem, mdas, pv->dev, start1,
|
if (!add_mda(fmt, fmt->cmd->mem, mdas, pv->dev, start1,
|
||||||
mda_size1))
|
mda_size1)) return 0;
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!dev_zero((struct device *) pv->dev, start1,
|
if (!dev_zero((struct device *) pv->dev, start1,
|
||||||
(size_t) (mda_size1 >
|
(size_t) (mda_size1 >
|
||||||
@@ -976,8 +976,7 @@ static int _mda_setup(const struct format_type *fmt,
|
|||||||
|
|
||||||
if (mda_size2) {
|
if (mda_size2) {
|
||||||
if (!add_mda(fmt, fmt->cmd->mem, mdas, pv->dev, start2,
|
if (!add_mda(fmt, fmt->cmd->mem, mdas, pv->dev, start2,
|
||||||
mda_size2))
|
mda_size2)) return 0;
|
||||||
return 0;
|
|
||||||
if (!dev_zero(pv->dev, start2,
|
if (!dev_zero(pv->dev, start2,
|
||||||
(size_t) (mda_size1 >
|
(size_t) (mda_size1 >
|
||||||
wipe_size ? wipe_size : mda_size1))) {
|
wipe_size ? wipe_size : mda_size1))) {
|
||||||
@@ -1066,8 +1065,7 @@ static int _pv_write(const struct format_type *fmt, struct physical_volume *pv,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!add_da
|
if (!add_da
|
||||||
(fmt, NULL, &info->das, pv->pe_start << SECTOR_SHIFT,
|
(fmt, NULL, &info->das, pv->pe_start << SECTOR_SHIFT, UINT64_C(0))) {
|
||||||
UINT64_C(0))) {
|
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1139,8 +1137,7 @@ static int _add_raw(struct list *raw_list, struct device_area *dev_area)
|
|||||||
rl = list_item(rlh, struct raw_list);
|
rl = list_item(rlh, struct raw_list);
|
||||||
/* FIXME Check size/overlap consistency too */
|
/* FIXME Check size/overlap consistency too */
|
||||||
if (rl->dev_area.dev == dev_area->dev &&
|
if (rl->dev_area.dev == dev_area->dev &&
|
||||||
rl->dev_area.start == dev_area->start)
|
rl->dev_area.start == dev_area->start) return 1;
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(rl = dbg_malloc(sizeof(struct raw_list)))) {
|
if (!(rl = dbg_malloc(sizeof(struct raw_list)))) {
|
||||||
@@ -1334,11 +1331,10 @@ static int _pv_setup(const struct format_type *fmt,
|
|||||||
list_item(mdash,
|
list_item(mdash,
|
||||||
struct metadata_area);
|
struct metadata_area);
|
||||||
if (mda2->ops !=
|
if (mda2->ops !=
|
||||||
&_metadata_text_raw_ops)
|
&_metadata_text_raw_ops) continue;
|
||||||
continue;
|
|
||||||
mdac2 =
|
mdac2 =
|
||||||
(struct mda_context *) mda2->
|
(struct mda_context *)
|
||||||
metadata_locn;
|
mda2->metadata_locn;
|
||||||
if (!memcmp
|
if (!memcmp
|
||||||
(&mdac2->area, &mdac->area,
|
(&mdac2->area, &mdac->area,
|
||||||
sizeof(mdac->area))) {
|
sizeof(mdac->area))) {
|
||||||
@@ -1356,8 +1352,7 @@ static int _pv_setup(const struct format_type *fmt,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!(mdac_new = pool_alloc(fmt->cmd->mem,
|
if (!(mdac_new = pool_alloc(fmt->cmd->mem,
|
||||||
sizeof(*mdac_new))))
|
sizeof(*mdac_new)))) {
|
||||||
{
|
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1486,8 +1481,7 @@ static struct format_instance *_create_text_instance(const struct format_type
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!(mdac_new = pool_alloc(fmt->cmd->mem,
|
if (!(mdac_new = pool_alloc(fmt->cmd->mem,
|
||||||
sizeof(*mdac_new))))
|
sizeof(*mdac_new)))) {
|
||||||
{
|
|
||||||
stack;
|
stack;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1649,7 +1643,7 @@ struct format_type *create_text_format(struct cmd_context *cmd)
|
|||||||
fmt->ops = &_text_handler;
|
fmt->ops = &_text_handler;
|
||||||
fmt->name = FMT_TEXT_NAME;
|
fmt->name = FMT_TEXT_NAME;
|
||||||
fmt->alias = FMT_TEXT_ALIAS;
|
fmt->alias = FMT_TEXT_ALIAS;
|
||||||
fmt->features = FMT_SEGMENTS | FMT_MDAS | FMT_TAGS;
|
fmt->features = FMT_SEGMENTS | FMT_MDAS | FMT_TAGS | FMT_UNLIMITED_VOLS;
|
||||||
|
|
||||||
if (!(mda_lists = dbg_malloc(sizeof(struct mda_lists)))) {
|
if (!(mda_lists = dbg_malloc(sizeof(struct mda_lists)))) {
|
||||||
log_error("Failed to allocate dir_list");
|
log_error("Failed to allocate dir_list");
|
||||||
@@ -1688,14 +1682,15 @@ struct format_type *create_text_format(struct cmd_context *cmd)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(cn = find_config_node(cmd->cft->root, "metadata/disk_areas")))
|
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))
|
||||||
for (cn = cn->child; cn; cn = cn->sib) {
|
goto err;
|
||||||
if (!_get_config_disk_area(cmd, cn, &mda_lists->raws))
|
}
|
||||||
goto err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log_very_verbose("Initialised format: %s", fmt->name);
|
||||||
|
|
||||||
return fmt;
|
return fmt;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
|
|||||||
@@ -49,12 +49,12 @@ struct volume_group *text_vg_import_fd(struct format_instance *fid,
|
|||||||
*desc = NULL;
|
*desc = NULL;
|
||||||
*when = 0;
|
*when = 0;
|
||||||
|
|
||||||
if (!(cft = create_config_tree())) {
|
if (!(cft = create_config_tree(file))) {
|
||||||
stack;
|
stack;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((!dev && !read_config_file(cft, file)) ||
|
if ((!dev && !read_config_file(cft)) ||
|
||||||
(dev && !read_config_fd(cft, dev, offset, size,
|
(dev && !read_config_fd(cft, dev, offset, size,
|
||||||
offset2, size2, checksum_fn, checksum))) {
|
offset2, size2, checksum_fn, checksum))) {
|
||||||
log_error("Couldn't read volume group metadata.");
|
log_error("Couldn't read volume group metadata.");
|
||||||
|
|||||||
@@ -22,6 +22,8 @@
|
|||||||
#include "toolcontext.h"
|
#include "toolcontext.h"
|
||||||
#include "lvmcache.h"
|
#include "lvmcache.h"
|
||||||
#include "lv_alloc.h"
|
#include "lv_alloc.h"
|
||||||
|
#include "segtype.h"
|
||||||
|
#include "text_import.h"
|
||||||
|
|
||||||
typedef int (*section_fn) (struct format_instance * fid, struct pool * mem,
|
typedef int (*section_fn) (struct format_instance * fid, struct pool * mem,
|
||||||
struct volume_group * vg, struct config_node * pvn,
|
struct volume_group * vg, struct config_node * pvn,
|
||||||
@@ -234,17 +236,13 @@ static int _read_segment(struct pool *mem, struct volume_group *vg,
|
|||||||
struct logical_volume *lv, struct config_node *sn,
|
struct logical_volume *lv, struct config_node *sn,
|
||||||
struct hash_table *pv_hash)
|
struct hash_table *pv_hash)
|
||||||
{
|
{
|
||||||
unsigned int s;
|
uint32_t area_count = 0u;
|
||||||
uint32_t area_count = 0;
|
|
||||||
struct lv_segment *seg;
|
struct lv_segment *seg;
|
||||||
struct config_node *cn;
|
struct config_node *cn;
|
||||||
struct config_value *cv;
|
struct config_value *cv;
|
||||||
const char *seg_name = sn->key;
|
|
||||||
uint32_t start_extent, extent_count;
|
uint32_t start_extent, extent_count;
|
||||||
uint32_t chunk_size, extents_moved = 0u, seg_status = 0u;
|
struct segment_type *segtype;
|
||||||
const char *org_name, *cow_name;
|
const char *segtype_str;
|
||||||
struct logical_volume *org, *cow, *lv1;
|
|
||||||
segment_type_t segtype;
|
|
||||||
|
|
||||||
if (!(sn = sn->child)) {
|
if (!(sn = sn->child)) {
|
||||||
log_error("Empty segment section.");
|
log_error("Empty segment section.");
|
||||||
@@ -263,40 +261,26 @@ static int _read_segment(struct pool *mem, struct volume_group *vg,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
segtype = SEG_STRIPED; /* Default */
|
segtype_str = "striped";
|
||||||
|
|
||||||
if ((cn = find_config_node(sn, "type"))) {
|
if ((cn = find_config_node(sn, "type"))) {
|
||||||
cv = cn->v;
|
cv = cn->v;
|
||||||
if (!cv || !cv->v.str) {
|
if (!cv || !cv->v.str) {
|
||||||
log_error("Segment type must be a string.");
|
log_error("Segment type must be a string.");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
segtype = get_segtype_from_string(cv->v.str);
|
segtype_str = cv->v.str;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (segtype == SEG_STRIPED) {
|
if (!(segtype = get_segtype_from_string(vg->cmd, segtype_str))) {
|
||||||
if (!_read_int32(sn, "stripe_count", &area_count)) {
|
stack;
|
||||||
log_error("Couldn't read 'stripe_count' for "
|
return 0;
|
||||||
"segment '%s'.", sn->key);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (segtype == SEG_MIRRORED) {
|
if (segtype->ops->text_import_area_count &&
|
||||||
if (!_read_int32(sn, "mirror_count", &area_count)) {
|
!segtype->ops->text_import_area_count(sn, &area_count)) {
|
||||||
log_error("Couldn't read 'mirror_count' for "
|
stack;
|
||||||
"segment '%s'.", sn->key);
|
return 0;
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (find_config_node(sn, "extents_moved")) {
|
|
||||||
if (_read_uint32(sn, "extents_moved", &extents_moved))
|
|
||||||
seg_status |= PVMOVE;
|
|
||||||
else {
|
|
||||||
log_error("Couldn't read 'extents_moved' for "
|
|
||||||
"segment '%s'.", sn->key);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(seg = alloc_lv_segment(mem, area_count))) {
|
if (!(seg = alloc_lv_segment(mem, area_count))) {
|
||||||
@@ -308,9 +292,15 @@ static int _read_segment(struct pool *mem, struct volume_group *vg,
|
|||||||
seg->le = start_extent;
|
seg->le = start_extent;
|
||||||
seg->len = extent_count;
|
seg->len = extent_count;
|
||||||
seg->area_len = extent_count;
|
seg->area_len = extent_count;
|
||||||
seg->type = segtype;
|
seg->status = 0u;
|
||||||
seg->status = seg_status;
|
seg->segtype = segtype;
|
||||||
seg->extents_moved = extents_moved;
|
seg->extents_copied = 0u;
|
||||||
|
|
||||||
|
if (seg->segtype->ops->text_import &&
|
||||||
|
!seg->segtype->ops->text_import(seg, sn, pv_hash)) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Optional tags */
|
/* Optional tags */
|
||||||
if ((cn = find_config_node(sn, "tags")) &&
|
if ((cn = find_config_node(sn, "tags")) &&
|
||||||
@@ -320,145 +310,89 @@ static int _read_segment(struct pool *mem, struct volume_group *vg,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (segtype) {
|
|
||||||
case SEG_SNAPSHOT:
|
|
||||||
lv->status |= SNAPSHOT;
|
|
||||||
|
|
||||||
if (!_read_uint32(sn, "chunk_size", &chunk_size)) {
|
|
||||||
log_error("Couldn't read chunk size for snapshot.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
log_suppress(1);
|
|
||||||
|
|
||||||
if (!(cow_name = find_config_str(sn, "cow_store", NULL))) {
|
|
||||||
log_suppress(0);
|
|
||||||
log_error("Snapshot cow storage not specified.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(org_name = find_config_str(sn, "origin", NULL))) {
|
|
||||||
log_suppress(0);
|
|
||||||
log_error("Snapshot origin not specified.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
log_suppress(0);
|
|
||||||
|
|
||||||
if (!(cow = find_lv(vg, cow_name))) {
|
|
||||||
log_error("Unknown logical volume specified for "
|
|
||||||
"snapshot cow store.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(org = find_lv(vg, org_name))) {
|
|
||||||
log_error("Unknown logical volume specified for "
|
|
||||||
"snapshot origin.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!vg_add_snapshot(org, cow, 1, &lv->lvid.id[1], chunk_size)) {
|
|
||||||
stack;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SEG_STRIPED:
|
|
||||||
if ((area_count != 1) &&
|
|
||||||
!_read_int32(sn, "stripe_size", &seg->stripe_size)) {
|
|
||||||
log_error("Couldn't read stripe_size for segment '%s'.",
|
|
||||||
sn->key);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(cn = find_config_node(sn, "stripes"))) {
|
|
||||||
log_error("Couldn't find stripes array for segment "
|
|
||||||
"'%s'.", sn->key);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
seg->area_len /= area_count;
|
|
||||||
|
|
||||||
case SEG_MIRRORED:
|
|
||||||
seg->area_count = area_count;
|
|
||||||
|
|
||||||
if (!seg->area_count) {
|
|
||||||
log_error("Zero areas not allowed for segment '%s'",
|
|
||||||
sn->key);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((seg->type == SEG_MIRRORED) &&
|
|
||||||
!(cn = find_config_node(sn, "mirrors"))) {
|
|
||||||
log_error("Couldn't find mirrors array for segment "
|
|
||||||
"'%s'.", sn->key);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (cv = cn->v, s = 0; cv && s < seg->area_count;
|
|
||||||
s++, cv = cv->next) {
|
|
||||||
|
|
||||||
/* first we read the pv */
|
|
||||||
const char *bad = "Badly formed areas array for "
|
|
||||||
"segment '%s'.";
|
|
||||||
struct physical_volume *pv;
|
|
||||||
|
|
||||||
if (cv->type != CFG_STRING) {
|
|
||||||
log_error(bad, sn->key);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!cv->next) {
|
|
||||||
log_error(bad, sn->key);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cv->next->type != CFG_INT) {
|
|
||||||
log_error(bad, sn->key);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* FIXME Cope if LV not yet read in */
|
|
||||||
if ((pv = hash_lookup(pv_hash, cv->v.str))) {
|
|
||||||
seg->area[s].type = AREA_PV;
|
|
||||||
seg->area[s].u.pv.pv = pv;
|
|
||||||
seg->area[s].u.pv.pe = cv->next->v.i;
|
|
||||||
/*
|
|
||||||
* Adjust extent counts in the pv and vg.
|
|
||||||
*/
|
|
||||||
pv->pe_alloc_count += seg->area_len;
|
|
||||||
vg->free_count -= seg->area_len;
|
|
||||||
|
|
||||||
} else if ((lv1 = find_lv(vg, cv->v.str))) {
|
|
||||||
seg->area[s].type = AREA_LV;
|
|
||||||
seg->area[s].u.lv.lv = lv1;
|
|
||||||
seg->area[s].u.lv.le = cv->next->v.i;
|
|
||||||
} else {
|
|
||||||
log_error("Couldn't find volume '%s' "
|
|
||||||
"for segment '%s'.",
|
|
||||||
cv->v.str ? cv->v.str : "NULL",
|
|
||||||
seg_name);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
cv = cv->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check we read the correct number of stripes.
|
|
||||||
*/
|
|
||||||
if (cv || (s < seg->area_count)) {
|
|
||||||
log_error("Incorrect number of areas in area array "
|
|
||||||
"for segment '%s'.", seg_name);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Insert into correct part of segment list.
|
* Insert into correct part of segment list.
|
||||||
*/
|
*/
|
||||||
_insert_segment(lv, seg);
|
_insert_segment(lv, seg);
|
||||||
|
|
||||||
|
if (seg->segtype->flags & SEG_AREAS_MIRRORED)
|
||||||
|
lv->status |= MIRRORED;
|
||||||
|
|
||||||
|
if (seg->segtype->flags & SEG_VIRTUAL)
|
||||||
|
lv->status |= VIRTUAL;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int text_import_areas(struct lv_segment *seg, const struct config_node *sn,
|
||||||
|
const struct config_node *cn, struct hash_table *pv_hash)
|
||||||
|
{
|
||||||
|
unsigned int s;
|
||||||
|
struct config_value *cv;
|
||||||
|
struct logical_volume *lv1;
|
||||||
|
const char *seg_name = sn->key;
|
||||||
|
|
||||||
|
if (!seg->area_count) {
|
||||||
|
log_error("Zero areas not allowed for segment '%s'", sn->key);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (cv = cn->v, s = 0; cv && s < seg->area_count; s++, cv = cv->next) {
|
||||||
|
|
||||||
|
/* first we read the pv */
|
||||||
|
const char *bad = "Badly formed areas array for "
|
||||||
|
"segment '%s'.";
|
||||||
|
struct physical_volume *pv;
|
||||||
|
|
||||||
|
if (cv->type != CFG_STRING) {
|
||||||
|
log_error(bad, sn->key);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cv->next) {
|
||||||
|
log_error(bad, sn->key);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cv->next->type != CFG_INT) {
|
||||||
|
log_error(bad, sn->key);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME Cope if LV not yet read in */
|
||||||
|
if ((pv = hash_lookup(pv_hash, cv->v.str))) {
|
||||||
|
seg->area[s].type = AREA_PV;
|
||||||
|
seg->area[s].u.pv.pv = pv;
|
||||||
|
seg->area[s].u.pv.pe = cv->next->v.i;
|
||||||
|
/*
|
||||||
|
* Adjust extent counts in the pv and vg.
|
||||||
|
*/
|
||||||
|
pv->pe_alloc_count += seg->area_len;
|
||||||
|
seg->lv->vg->free_count -= seg->area_len;
|
||||||
|
|
||||||
|
} else if ((lv1 = find_lv(seg->lv->vg, cv->v.str))) {
|
||||||
|
seg->area[s].type = AREA_LV;
|
||||||
|
seg->area[s].u.lv.lv = lv1;
|
||||||
|
seg->area[s].u.lv.le = cv->next->v.i;
|
||||||
|
} else {
|
||||||
|
log_error("Couldn't find volume '%s' "
|
||||||
|
"for segment '%s'.",
|
||||||
|
cv->v.str ? cv->v.str : "NULL", seg_name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cv = cv->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check we read the correct number of stripes.
|
||||||
|
*/
|
||||||
|
if (cv || (s < seg->area_count)) {
|
||||||
|
log_error("Incorrect number of areas in area array "
|
||||||
|
"for segment '%s'.", seg_name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -555,7 +489,7 @@ static int _read_lvnames(struct format_instance *fid, struct pool *mem,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
lv->alloc = ALLOC_DEFAULT;
|
lv->alloc = ALLOC_INHERIT;
|
||||||
if ((cn = find_config_node(lvn, "allocation_policy"))) {
|
if ((cn = find_config_node(lvn, "allocation_policy"))) {
|
||||||
struct config_value *cv = cn->v;
|
struct config_value *cv = cn->v;
|
||||||
if (!cv || !cv->v.str) {
|
if (!cv || !cv->v.str) {
|
||||||
@@ -564,6 +498,10 @@ static int _read_lvnames(struct format_instance *fid, struct pool *mem,
|
|||||||
}
|
}
|
||||||
|
|
||||||
lv->alloc = get_alloc_from_string(cv->v.str);
|
lv->alloc = get_alloc_from_string(cv->v.str);
|
||||||
|
if (lv->alloc == ALLOC_INVALID) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read_ahead defaults to 0 */
|
/* read_ahead defaults to 0 */
|
||||||
@@ -765,6 +703,21 @@ static struct volume_group *_read_vg(struct format_instance *fid,
|
|||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vg->alloc = ALLOC_NORMAL;
|
||||||
|
if ((cn = find_config_node(vgn, "allocation_policy"))) {
|
||||||
|
struct config_value *cv = cn->v;
|
||||||
|
if (!cv || !cv->v.str) {
|
||||||
|
log_error("allocation_policy must be a string.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
vg->alloc = get_alloc_from_string(cv->v.str);
|
||||||
|
if (vg->alloc == ALLOC_INVALID) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The pv hash memoises the pv section names -> pv
|
* The pv hash memoises the pv section names -> pv
|
||||||
* structures.
|
* structures.
|
||||||
|
|||||||
36
lib/format_text/text_export.h
Normal file
36
lib/format_text/text_export.h
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LVM_TEXT_EXPORT_H
|
||||||
|
#define _LVM_TEXT_EXPORT_H
|
||||||
|
|
||||||
|
#define outf(args...) do {if (!out_text(args)) {stack; return 0;}} while (0)
|
||||||
|
|
||||||
|
struct formatter;
|
||||||
|
struct lv_segment;
|
||||||
|
|
||||||
|
int out_size(struct formatter *f, uint64_t size, const char *fmt, ...)
|
||||||
|
__attribute__ ((format(printf, 3, 4)));
|
||||||
|
|
||||||
|
int out_hint(struct formatter *f, const char *fmt, ...)
|
||||||
|
__attribute__ ((format(printf, 2, 3)));
|
||||||
|
|
||||||
|
int out_text(struct formatter *f, const char *fmt, ...)
|
||||||
|
__attribute__ ((format(printf, 2, 3)));
|
||||||
|
|
||||||
|
int out_areas(struct formatter *f, const struct lv_segment *seg,
|
||||||
|
const char *type);
|
||||||
|
|
||||||
|
#endif
|
||||||
25
lib/format_text/text_import.h
Normal file
25
lib/format_text/text_import.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LVM_TEXT_IMPORT_H
|
||||||
|
#define _LVM_TEXT_IMPORT_H
|
||||||
|
|
||||||
|
struct lv_segment;
|
||||||
|
struct config_node;
|
||||||
|
|
||||||
|
int text_import_areas(struct lv_segment *seg, const struct config_node *sn,
|
||||||
|
const struct config_node *cn, struct hash_table *pv_hash);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -18,6 +18,7 @@
|
|||||||
#include "layout.h"
|
#include "layout.h"
|
||||||
#include "label.h"
|
#include "label.h"
|
||||||
#include "xlate.h"
|
#include "xlate.h"
|
||||||
|
#include "lvmcache.h"
|
||||||
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include "crc.h"
|
#include "crc.h"
|
||||||
#include "xlate.h"
|
#include "xlate.h"
|
||||||
#include "lvmcache.h"
|
#include "lvmcache.h"
|
||||||
|
#include "metadata.h"
|
||||||
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@@ -78,6 +79,8 @@ void label_exit(void)
|
|||||||
li->l->ops->destroy(li->l);
|
li->l->ops->destroy(li->l);
|
||||||
_free_li(li);
|
_free_li(li);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
list_init(&_labellers);
|
||||||
}
|
}
|
||||||
|
|
||||||
int label_register_handler(const char *name, struct labeller *handler)
|
int label_register_handler(const char *name, struct labeller *handler)
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
#ifndef _LVM_LABEL_H
|
#ifndef _LVM_LABEL_H
|
||||||
#define _LVM_LABEL_H
|
#define _LVM_LABEL_H
|
||||||
|
|
||||||
#include "lvmcache.h"
|
|
||||||
#include "uuid.h"
|
#include "uuid.h"
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
|
|
||||||
@@ -25,6 +24,8 @@
|
|||||||
#define LABEL_SCAN_SECTORS 4L
|
#define LABEL_SCAN_SECTORS 4L
|
||||||
#define LABEL_SCAN_SIZE (LABEL_SCAN_SECTORS << SECTOR_SHIFT)
|
#define LABEL_SCAN_SIZE (LABEL_SCAN_SECTORS << SECTOR_SHIFT)
|
||||||
|
|
||||||
|
struct labeller;
|
||||||
|
|
||||||
/* On disk - 32 bytes */
|
/* On disk - 32 bytes */
|
||||||
struct label_header {
|
struct label_header {
|
||||||
uint8_t id[8]; /* LABELONE */
|
uint8_t id[8]; /* LABELONE */
|
||||||
|
|||||||
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
|
||||||
@@ -19,6 +19,7 @@
|
|||||||
#include "sharedlib.h"
|
#include "sharedlib.h"
|
||||||
|
|
||||||
static void *_locking_lib = NULL;
|
static void *_locking_lib = NULL;
|
||||||
|
static void (*_reset_fn) (void) = NULL;
|
||||||
static void (*_end_fn) (void) = NULL;
|
static void (*_end_fn) (void) = NULL;
|
||||||
static int (*_lock_fn) (struct cmd_context * cmd, const char *resource,
|
static int (*_lock_fn) (struct cmd_context * cmd, const char *resource,
|
||||||
int flags) = NULL;
|
int flags) = NULL;
|
||||||
@@ -45,6 +46,13 @@ static void _fin_external_locking(void)
|
|||||||
_init_fn = NULL;
|
_init_fn = NULL;
|
||||||
_end_fn = NULL;
|
_end_fn = NULL;
|
||||||
_lock_fn = NULL;
|
_lock_fn = NULL;
|
||||||
|
_reset_fn = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _reset_external_locking(void)
|
||||||
|
{
|
||||||
|
if (_reset_fn)
|
||||||
|
_reset_fn();
|
||||||
}
|
}
|
||||||
|
|
||||||
int init_external_locking(struct locking_type *locking, struct config_tree *cft)
|
int init_external_locking(struct locking_type *locking, struct config_tree *cft)
|
||||||
@@ -58,6 +66,7 @@ int init_external_locking(struct locking_type *locking, struct config_tree *cft)
|
|||||||
|
|
||||||
locking->lock_resource = _lock_resource;
|
locking->lock_resource = _lock_resource;
|
||||||
locking->fin_locking = _fin_external_locking;
|
locking->fin_locking = _fin_external_locking;
|
||||||
|
locking->reset_locking = _reset_external_locking;
|
||||||
locking->flags = 0;
|
locking->flags = 0;
|
||||||
|
|
||||||
libname = find_config_str(cft->root, "global/locking_library",
|
libname = find_config_str(cft->root, "global/locking_library",
|
||||||
@@ -71,6 +80,7 @@ int init_external_locking(struct locking_type *locking, struct config_tree *cft)
|
|||||||
/* Get the functions we need */
|
/* Get the functions we need */
|
||||||
if (!(_init_fn = dlsym(_locking_lib, "locking_init")) ||
|
if (!(_init_fn = dlsym(_locking_lib, "locking_init")) ||
|
||||||
!(_lock_fn = dlsym(_locking_lib, "lock_resource")) ||
|
!(_lock_fn = dlsym(_locking_lib, "lock_resource")) ||
|
||||||
|
!(_reset_fn = dlsym(_locking_lib, "reset_locking")) ||
|
||||||
!(_end_fn = dlsym(_locking_lib, "locking_end"))) {
|
!(_end_fn = dlsym(_locking_lib, "locking_end"))) {
|
||||||
log_error("Shared library %s does not contain locking "
|
log_error("Shared library %s does not contain locking "
|
||||||
"functions", libname);
|
"functions", libname);
|
||||||
|
|||||||
@@ -232,9 +232,14 @@ static int _file_lock_resource(struct cmd_context *cmd, const char *resource,
|
|||||||
if (!lv_resume_if_active(cmd, resource))
|
if (!lv_resume_if_active(cmd, resource))
|
||||||
return 0;
|
return 0;
|
||||||
break;
|
break;
|
||||||
|
case LCK_NULL:
|
||||||
|
log_debug("Locking LV %s (NL)", resource);
|
||||||
|
if (!lv_deactivate(cmd, resource))
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
case LCK_READ:
|
case LCK_READ:
|
||||||
log_debug("Locking LV %s (R)", resource);
|
log_debug("Locking LV %s (R)", resource);
|
||||||
if (!lv_activate(cmd, resource))
|
if (!lv_activate_with_filter(cmd, resource))
|
||||||
return 0;
|
return 0;
|
||||||
break;
|
break;
|
||||||
case LCK_WRITE:
|
case LCK_WRITE:
|
||||||
@@ -244,7 +249,7 @@ static int _file_lock_resource(struct cmd_context *cmd, const char *resource,
|
|||||||
break;
|
break;
|
||||||
case LCK_EXCL:
|
case LCK_EXCL:
|
||||||
log_debug("Locking LV %s (EX)", resource);
|
log_debug("Locking LV %s (EX)", resource);
|
||||||
if (!lv_deactivate(cmd, resource))
|
if (!lv_activate_with_filter(cmd, resource))
|
||||||
return 0;
|
return 0;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -145,6 +145,14 @@ int init_locking(int type, struct config_tree *cft)
|
|||||||
return 1;
|
return 1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CLUSTER_LOCKING_INTERNAL
|
||||||
|
case 3:
|
||||||
|
if (!init_cluster_locking(&_locking, cft))
|
||||||
|
break;
|
||||||
|
log_very_verbose("Cluster locking enabled.");
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
default:
|
default:
|
||||||
log_error("Unknown locking type requested.");
|
log_error("Unknown locking type requested.");
|
||||||
return 0;
|
return 0;
|
||||||
@@ -252,32 +260,54 @@ int lock_vol(struct cmd_context *cmd, const char *vol, int flags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Unlock list of LVs */
|
/* Unlock list of LVs */
|
||||||
int unlock_lvs(struct cmd_context *cmd, struct list *lvs)
|
int resume_lvs(struct cmd_context *cmd, struct list *lvs)
|
||||||
{
|
{
|
||||||
struct list *lvh;
|
struct list *lvh;
|
||||||
struct logical_volume *lv;
|
struct logical_volume *lv;
|
||||||
|
|
||||||
list_iterate(lvh, lvs) {
|
list_iterate(lvh, lvs) {
|
||||||
lv = list_item(lvh, struct lv_list)->lv;
|
lv = list_item(lvh, struct lv_list)->lv;
|
||||||
unlock_lv(cmd, lv->lvid.s);
|
resume_lv(cmd, lv->lvid.s);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Lock a list of LVs */
|
/* Lock a list of LVs */
|
||||||
int lock_lvs(struct cmd_context *cmd, struct list *lvs, int flags)
|
int suspend_lvs(struct cmd_context *cmd, struct list *lvs)
|
||||||
{
|
{
|
||||||
struct list *lvh;
|
struct list *lvh;
|
||||||
struct logical_volume *lv;
|
struct logical_volume *lv;
|
||||||
|
|
||||||
list_iterate(lvh, lvs) {
|
list_iterate(lvh, lvs) {
|
||||||
lv = list_item(lvh, struct lv_list)->lv;
|
lv = list_item(lvh, struct lv_list)->lv;
|
||||||
if (!lock_vol(cmd, lv->lvid.s, flags)) {
|
if (!suspend_lv(cmd, lv->lvid.s)) {
|
||||||
log_error("Failed to suspend %s", lv->name);
|
log_error("Failed to suspend %s", lv->name);
|
||||||
list_uniterate(lvh, lvs, lvh) {
|
list_uniterate(lvh, lvs, lvh) {
|
||||||
lv = list_item(lvh, struct lv_list)->lv;
|
lv = list_item(lvh, struct lv_list)->lv;
|
||||||
unlock_lv(cmd, lv->lvid.s);
|
resume_lv(cmd, lv->lvid.s);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Lock a list of LVs */
|
||||||
|
int activate_lvs_excl(struct cmd_context *cmd, struct list *lvs)
|
||||||
|
{
|
||||||
|
struct list *lvh;
|
||||||
|
struct logical_volume *lv;
|
||||||
|
|
||||||
|
list_iterate(lvh, lvs) {
|
||||||
|
lv = list_item(lvh, struct lv_list)->lv;
|
||||||
|
if (!activate_lv_excl(cmd, lv->lvid.s)) {
|
||||||
|
log_error("Failed to activate %s", lv->name);
|
||||||
|
list_uniterate(lvh, lvs, lvh) {
|
||||||
|
lv = list_item(lvh, struct lv_list)->lv;
|
||||||
|
activate_lv(cmd, lv->lvid.s);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -13,7 +13,6 @@
|
|||||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "metadata.h"
|
|
||||||
#include "uuid.h"
|
#include "uuid.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
@@ -64,6 +63,7 @@ int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname);
|
|||||||
*/
|
*/
|
||||||
#define LCK_NONBLOCK 0x00000010 /* Don't block waiting for lock? */
|
#define LCK_NONBLOCK 0x00000010 /* Don't block waiting for lock? */
|
||||||
#define LCK_HOLD 0x00000020 /* Hold lock when lock_vol returns? */
|
#define LCK_HOLD 0x00000020 /* Hold lock when lock_vol returns? */
|
||||||
|
#define LCK_LOCAL 0x00000040 /* Don't propagate to other nodes */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Common combinations
|
* Common combinations
|
||||||
@@ -72,16 +72,28 @@ int check_lvm1_vg_inactive(struct cmd_context *cmd, const char *vgname);
|
|||||||
#define LCK_VG_WRITE (LCK_VG | LCK_WRITE | LCK_HOLD)
|
#define LCK_VG_WRITE (LCK_VG | LCK_WRITE | LCK_HOLD)
|
||||||
#define LCK_VG_UNLOCK (LCK_VG | LCK_UNLOCK)
|
#define LCK_VG_UNLOCK (LCK_VG | LCK_UNLOCK)
|
||||||
|
|
||||||
#define LCK_LV_SUSPEND (LCK_LV | LCK_WRITE)
|
#define LCK_LV_EXCLUSIVE (LCK_LV | LCK_EXCL | LCK_NONBLOCK)
|
||||||
|
#define LCK_LV_SUSPEND (LCK_LV | LCK_WRITE | LCK_NONBLOCK)
|
||||||
#define LCK_LV_RESUME (LCK_LV | LCK_UNLOCK | LCK_NONBLOCK)
|
#define LCK_LV_RESUME (LCK_LV | LCK_UNLOCK | LCK_NONBLOCK)
|
||||||
#define LCK_LV_UNLOCK (LCK_LV | LCK_UNLOCK)
|
#define LCK_LV_ACTIVATE (LCK_LV | LCK_READ | LCK_NONBLOCK)
|
||||||
#define LCK_LV_ACTIVATE (LCK_LV | LCK_READ)
|
#define LCK_LV_DEACTIVATE (LCK_LV | LCK_NULL | LCK_NONBLOCK)
|
||||||
#define LCK_LV_DEACTIVATE (LCK_LV | LCK_EXCL)
|
|
||||||
|
|
||||||
#define unlock_lv(cmd, vol) lock_vol(cmd, vol, LCK_LV_UNLOCK)
|
|
||||||
#define unlock_vg(cmd, vol) lock_vol(cmd, vol, LCK_VG_UNLOCK)
|
#define unlock_vg(cmd, vol) lock_vol(cmd, vol, LCK_VG_UNLOCK)
|
||||||
|
|
||||||
/* Process list of LVs */
|
#define resume_lv(cmd, vol) lock_vol(cmd, vol, LCK_LV_RESUME)
|
||||||
int lock_lvs(struct cmd_context *cmd, struct list *lvs, int flags);
|
#define suspend_lv(cmd, vol) lock_vol(cmd, vol, LCK_LV_SUSPEND | LCK_HOLD)
|
||||||
int unlock_lvs(struct cmd_context *cmd, struct list *lvs);
|
#define deactivate_lv(cmd, vol) lock_vol(cmd, vol, LCK_LV_DEACTIVATE)
|
||||||
|
#define activate_lv(cmd, vol) lock_vol(cmd, vol, LCK_LV_ACTIVATE | LCK_HOLD)
|
||||||
|
#define activate_lv_excl(cmd, vol) \
|
||||||
|
lock_vol(cmd, vol, LCK_LV_EXCLUSIVE | LCK_HOLD)
|
||||||
|
#define activate_lv_local(cmd, vol) \
|
||||||
|
lock_vol(cmd, vol, LCK_LV_ACTIVATE | LCK_HOLD | LCK_LOCAL)
|
||||||
|
#define deactivate_lv_local(cmd, vol) \
|
||||||
|
lock_vol(cmd, vol, LCK_LV_DEACTIVATE | LCK_LOCAL)
|
||||||
|
|
||||||
|
/* Process list of LVs */
|
||||||
|
int suspend_lvs(struct cmd_context *cmd, struct list *lvs);
|
||||||
|
int resume_lvs(struct cmd_context *cmd, struct list *lvs);
|
||||||
|
int activate_lvs_excl(struct cmd_context *cmd, struct list *lvs);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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_file_locking(struct locking_type *locking, struct config_tree *cf);
|
||||||
|
|
||||||
int init_external_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);
|
||||||
|
|||||||
@@ -53,14 +53,16 @@ static int _no_lock_resource(struct cmd_context *cmd, const char *resource,
|
|||||||
break;
|
break;
|
||||||
case LCK_LV:
|
case LCK_LV:
|
||||||
switch (flags & LCK_TYPE_MASK) {
|
switch (flags & LCK_TYPE_MASK) {
|
||||||
|
case LCK_NULL:
|
||||||
|
return lv_deactivate(cmd, resource);
|
||||||
case LCK_UNLOCK:
|
case LCK_UNLOCK:
|
||||||
return lv_resume_if_active(cmd, resource);
|
return lv_resume_if_active(cmd, resource);
|
||||||
case LCK_READ:
|
case LCK_READ:
|
||||||
return lv_activate(cmd, resource);
|
return lv_activate_with_filter(cmd, resource);
|
||||||
case LCK_WRITE:
|
case LCK_WRITE:
|
||||||
return lv_suspend_if_active(cmd, resource);
|
return lv_suspend_if_active(cmd, resource);
|
||||||
case LCK_EXCL:
|
case LCK_EXCL:
|
||||||
return lv_deactivate(cmd, resource);
|
return lv_activate_with_filter(cmd, resource);
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ static int _indent = 1;
|
|||||||
static int _log_cmd_name = 0;
|
static int _log_cmd_name = 0;
|
||||||
static int _log_suppress = 0;
|
static int _log_suppress = 0;
|
||||||
static int _ignorelockingfailure = 0;
|
static int _ignorelockingfailure = 0;
|
||||||
|
static int _security_level = SECURITY_LEVEL;
|
||||||
static char _cmd_name[30] = "";
|
static char _cmd_name[30] = "";
|
||||||
static char _msg_prefix[30] = " ";
|
static char _msg_prefix[30] = " ";
|
||||||
static int _already_logging = 0;
|
static int _already_logging = 0;
|
||||||
@@ -147,6 +148,11 @@ void init_ignorelockingfailure(int level)
|
|||||||
_ignorelockingfailure = level;
|
_ignorelockingfailure = level;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void init_security_level(int level)
|
||||||
|
{
|
||||||
|
_security_level = level;
|
||||||
|
}
|
||||||
|
|
||||||
void init_cmd_name(int status)
|
void init_cmd_name(int status)
|
||||||
{
|
{
|
||||||
_log_cmd_name = status;
|
_log_cmd_name = status;
|
||||||
@@ -191,6 +197,11 @@ int ignorelockingfailure()
|
|||||||
return _ignorelockingfailure;
|
return _ignorelockingfailure;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int security_level()
|
||||||
|
{
|
||||||
|
return _security_level;
|
||||||
|
}
|
||||||
|
|
||||||
void init_debug(int level)
|
void init_debug(int level)
|
||||||
{
|
{
|
||||||
_debug_level = level;
|
_debug_level = level;
|
||||||
|
|||||||
@@ -49,6 +49,7 @@
|
|||||||
#define _LOG_FATAL 2
|
#define _LOG_FATAL 2
|
||||||
|
|
||||||
#define VERBOSE_BASE_LEVEL _LOG_WARN
|
#define VERBOSE_BASE_LEVEL _LOG_WARN
|
||||||
|
#define SECURITY_LEVEL 0
|
||||||
|
|
||||||
void init_log_file(const char *log_file, int append);
|
void init_log_file(const char *log_file, int append);
|
||||||
void init_log_direct(const char *log_file, int append);
|
void init_log_direct(const char *log_file, int append);
|
||||||
@@ -68,6 +69,7 @@ void init_cmd_name(int status);
|
|||||||
void init_msg_prefix(const char *prefix);
|
void init_msg_prefix(const char *prefix);
|
||||||
void init_indent(int indent);
|
void init_indent(int indent);
|
||||||
void init_ignorelockingfailure(int level);
|
void init_ignorelockingfailure(int level);
|
||||||
|
void init_security_level(int level);
|
||||||
|
|
||||||
void set_cmd_name(const char *cmd_name);
|
void set_cmd_name(const char *cmd_name);
|
||||||
|
|
||||||
@@ -76,6 +78,7 @@ int partial_mode(void);
|
|||||||
int pvmove_mode(void);
|
int pvmove_mode(void);
|
||||||
int debug_level(void);
|
int debug_level(void);
|
||||||
int ignorelockingfailure(void);
|
int ignorelockingfailure(void);
|
||||||
|
int security_level(void);
|
||||||
|
|
||||||
/* Suppress messages to stdout/stderr */
|
/* Suppress messages to stdout/stderr */
|
||||||
void log_suppress(int suppress);
|
void log_suppress(int suppress);
|
||||||
|
|||||||
@@ -20,6 +20,8 @@
|
|||||||
#include "lvm-string.h"
|
#include "lvm-string.h"
|
||||||
#include "toolcontext.h"
|
#include "toolcontext.h"
|
||||||
#include "lv_alloc.h"
|
#include "lv_alloc.h"
|
||||||
|
#include "display.h"
|
||||||
|
#include "segtype.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These functions adjust the pe counts in pv's
|
* These functions adjust the pe counts in pv's
|
||||||
@@ -69,6 +71,7 @@ struct lv_segment *alloc_lv_segment(struct pool *mem, uint32_t num_areas)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
seg->area_count = num_areas;
|
||||||
list_init(&seg->tags);
|
list_init(&seg->tags);
|
||||||
|
|
||||||
return seg;
|
return seg;
|
||||||
@@ -76,6 +79,7 @@ struct lv_segment *alloc_lv_segment(struct pool *mem, uint32_t num_areas)
|
|||||||
|
|
||||||
static int _alloc_parallel_area(struct logical_volume *lv, uint32_t area_count,
|
static int _alloc_parallel_area(struct logical_volume *lv, uint32_t area_count,
|
||||||
uint32_t stripe_size,
|
uint32_t stripe_size,
|
||||||
|
struct segment_type *segtype,
|
||||||
struct pv_area **areas, uint32_t *ix)
|
struct pv_area **areas, uint32_t *ix)
|
||||||
{
|
{
|
||||||
uint32_t count, area_len, smallest;
|
uint32_t count, area_len, smallest;
|
||||||
@@ -83,7 +87,9 @@ static int _alloc_parallel_area(struct logical_volume *lv, uint32_t area_count,
|
|||||||
struct lv_segment *seg;
|
struct lv_segment *seg;
|
||||||
int striped = 0;
|
int striped = 0;
|
||||||
|
|
||||||
striped = 1;
|
/* Striped or mirrored? */
|
||||||
|
if (segtype->flags & SEG_AREAS_STRIPED)
|
||||||
|
striped = 1;
|
||||||
|
|
||||||
count = lv->le_count - *ix;
|
count = lv->le_count - *ix;
|
||||||
area_len = count / (striped ? area_count : 1);
|
area_len = count / (striped ? area_count : 1);
|
||||||
@@ -98,13 +104,12 @@ static int _alloc_parallel_area(struct logical_volume *lv, uint32_t area_count,
|
|||||||
}
|
}
|
||||||
|
|
||||||
seg->lv = lv;
|
seg->lv = lv;
|
||||||
seg->type = SEG_STRIPED;
|
seg->segtype = segtype;
|
||||||
seg->le = *ix;
|
seg->le = *ix;
|
||||||
seg->len = area_len * (striped ? area_count : 1);
|
seg->len = area_len * (striped ? area_count : 1);
|
||||||
seg->area_len = area_len;
|
seg->area_len = area_len;
|
||||||
seg->area_count = area_count;
|
|
||||||
seg->stripe_size = stripe_size;
|
seg->stripe_size = stripe_size;
|
||||||
seg->extents_moved = 0u;
|
seg->extents_copied = 0u;
|
||||||
|
|
||||||
for (s = 0; s < area_count; s++) {
|
for (s = 0; s < area_count; s++) {
|
||||||
struct pv_area *pva = areas[s];
|
struct pv_area *pva = areas[s];
|
||||||
@@ -116,6 +121,10 @@ static int _alloc_parallel_area(struct logical_volume *lv, uint32_t area_count,
|
|||||||
|
|
||||||
list_add(&lv->segments, &seg->list);
|
list_add(&lv->segments, &seg->list);
|
||||||
*ix += seg->len;
|
*ix += seg->len;
|
||||||
|
|
||||||
|
if (!striped)
|
||||||
|
lv->status |= MIRRORED;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,7 +144,8 @@ static int _comp_area(const void *l, const void *r)
|
|||||||
|
|
||||||
static int _alloc_parallel(struct logical_volume *lv,
|
static int _alloc_parallel(struct logical_volume *lv,
|
||||||
struct list *pvms, uint32_t allocated,
|
struct list *pvms, uint32_t allocated,
|
||||||
uint32_t stripes, uint32_t stripe_size)
|
uint32_t stripes, uint32_t stripe_size,
|
||||||
|
uint32_t mirrors, struct segment_type *segtype)
|
||||||
{
|
{
|
||||||
int r = 0;
|
int r = 0;
|
||||||
struct list *pvmh;
|
struct list *pvmh;
|
||||||
@@ -145,7 +155,15 @@ static int _alloc_parallel(struct logical_volume *lv,
|
|||||||
size_t len;
|
size_t len;
|
||||||
uint32_t area_count;
|
uint32_t area_count;
|
||||||
|
|
||||||
area_count = stripes;
|
if (stripes > 1 && mirrors > 1) {
|
||||||
|
log_error("striped mirrors are not supported yet");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stripes > 1)
|
||||||
|
area_count = stripes;
|
||||||
|
else
|
||||||
|
area_count = mirrors;
|
||||||
|
|
||||||
list_iterate(pvmh, pvms)
|
list_iterate(pvmh, pvms)
|
||||||
pv_count++;
|
pv_count++;
|
||||||
@@ -179,8 +197,8 @@ static int _alloc_parallel(struct logical_volume *lv,
|
|||||||
/* sort the areas so we allocate from the biggest */
|
/* sort the areas so we allocate from the biggest */
|
||||||
qsort(areas, ix, sizeof(*areas), _comp_area);
|
qsort(areas, ix, sizeof(*areas), _comp_area);
|
||||||
|
|
||||||
if (!_alloc_parallel_area(lv, area_count, stripe_size, areas,
|
if (!_alloc_parallel_area(lv, area_count, stripe_size, segtype,
|
||||||
&allocated)) {
|
areas, &allocated)) {
|
||||||
stack;
|
stack;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@@ -215,12 +233,14 @@ static int _alloc_linear_area(struct logical_volume *lv, uint32_t *ix,
|
|||||||
}
|
}
|
||||||
|
|
||||||
seg->lv = lv;
|
seg->lv = lv;
|
||||||
seg->type = SEG_STRIPED;
|
if (!(seg->segtype = get_segtype_from_string(lv->vg->cmd, "striped"))) {
|
||||||
|
stack;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
seg->le = *ix;
|
seg->le = *ix;
|
||||||
seg->len = count;
|
seg->len = count;
|
||||||
seg->area_len = count;
|
seg->area_len = count;
|
||||||
seg->stripe_size = 0;
|
seg->stripe_size = 0;
|
||||||
seg->area_count = 1;
|
|
||||||
seg->area[0].type = AREA_PV;
|
seg->area[0].type = AREA_PV;
|
||||||
seg->area[0].u.pv.pv = map->pvl->pv;
|
seg->area[0].u.pv.pv = map->pvl->pv;
|
||||||
seg->area[0].u.pv.pe = pva->start;
|
seg->area[0].u.pv.pe = pva->start;
|
||||||
@@ -234,6 +254,7 @@ static int _alloc_linear_area(struct logical_volume *lv, uint32_t *ix,
|
|||||||
|
|
||||||
static int _alloc_mirrored_area(struct logical_volume *lv, uint32_t *ix,
|
static int _alloc_mirrored_area(struct logical_volume *lv, uint32_t *ix,
|
||||||
struct pv_map *map, struct pv_area *pva,
|
struct pv_map *map, struct pv_area *pva,
|
||||||
|
struct segment_type *segtype,
|
||||||
struct physical_volume *mirrored_pv,
|
struct physical_volume *mirrored_pv,
|
||||||
uint32_t mirrored_pe)
|
uint32_t mirrored_pe)
|
||||||
{
|
{
|
||||||
@@ -251,14 +272,13 @@ static int _alloc_mirrored_area(struct logical_volume *lv, uint32_t *ix,
|
|||||||
}
|
}
|
||||||
|
|
||||||
seg->lv = lv;
|
seg->lv = lv;
|
||||||
seg->type = SEG_MIRRORED;
|
seg->segtype = segtype;
|
||||||
seg->status = 0u;
|
|
||||||
seg->le = *ix;
|
seg->le = *ix;
|
||||||
|
seg->status = 0u;
|
||||||
seg->len = count;
|
seg->len = count;
|
||||||
seg->area_len = count;
|
seg->area_len = count;
|
||||||
seg->stripe_size = 0;
|
seg->stripe_size = 0;
|
||||||
seg->area_count = 2;
|
seg->extents_copied = 0u;
|
||||||
seg->extents_moved = 0u;
|
|
||||||
/* FIXME Remove AREA_PV restriction here? */
|
/* FIXME Remove AREA_PV restriction here? */
|
||||||
seg->area[0].type = AREA_PV;
|
seg->area[0].type = AREA_PV;
|
||||||
seg->area[0].u.pv.pv = mirrored_pv;
|
seg->area[0].u.pv.pv = mirrored_pv;
|
||||||
@@ -321,6 +341,7 @@ static int _alloc_contiguous(struct logical_volume *lv,
|
|||||||
/* FIXME Contiguous depends on *segment* (i.e. stripe) not LV */
|
/* FIXME Contiguous depends on *segment* (i.e. stripe) not LV */
|
||||||
static int _alloc_mirrored(struct logical_volume *lv,
|
static int _alloc_mirrored(struct logical_volume *lv,
|
||||||
struct list *pvms, uint32_t allocated,
|
struct list *pvms, uint32_t allocated,
|
||||||
|
struct segment_type *segtype,
|
||||||
struct physical_volume *mirrored_pv,
|
struct physical_volume *mirrored_pv,
|
||||||
uint32_t mirrored_pe)
|
uint32_t mirrored_pe)
|
||||||
{
|
{
|
||||||
@@ -343,7 +364,7 @@ static int _alloc_mirrored(struct logical_volume *lv,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_alloc_mirrored_area(lv, &allocated, pvm, pva,
|
if (!_alloc_mirrored_area(lv, &allocated, pvm, pva, segtype,
|
||||||
mirrored_pv, mirrored_pe)) {
|
mirrored_pv, mirrored_pe)) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
@@ -395,12 +416,37 @@ static int _alloc_next_free(struct logical_volume *lv,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int _alloc_virtual(struct logical_volume *lv,
|
||||||
|
uint32_t allocated, struct segment_type *segtype)
|
||||||
|
{
|
||||||
|
struct lv_segment *seg;
|
||||||
|
|
||||||
|
if (!(seg = alloc_lv_segment(lv->vg->cmd->mem, 0))) {
|
||||||
|
log_err("Couldn't allocate new zero segment.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
seg->lv = lv;
|
||||||
|
seg->segtype = segtype;
|
||||||
|
seg->status = 0u;
|
||||||
|
seg->le = allocated;
|
||||||
|
seg->len = lv->le_count - allocated;
|
||||||
|
seg->area_len = seg->len;
|
||||||
|
seg->stripe_size = 0;
|
||||||
|
seg->extents_copied = 0u;
|
||||||
|
list_add(&lv->segments, &seg->list);
|
||||||
|
lv->status |= VIRTUAL;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Chooses a correct allocation policy.
|
* Chooses a correct allocation policy.
|
||||||
*/
|
*/
|
||||||
static int _allocate(struct volume_group *vg, struct logical_volume *lv,
|
static int _allocate(struct volume_group *vg, struct logical_volume *lv,
|
||||||
struct list *allocatable_pvs, uint32_t allocated,
|
struct list *allocatable_pvs, uint32_t allocated,
|
||||||
uint32_t stripes, uint32_t stripe_size,
|
alloc_policy_t alloc, struct segment_type *segtype,
|
||||||
|
uint32_t stripes, uint32_t stripe_size, uint32_t mirrors,
|
||||||
struct physical_volume *mirrored_pv, uint32_t mirrored_pe,
|
struct physical_volume *mirrored_pv, uint32_t mirrored_pe,
|
||||||
uint32_t status)
|
uint32_t status)
|
||||||
{
|
{
|
||||||
@@ -409,32 +455,40 @@ static int _allocate(struct volume_group *vg, struct logical_volume *lv,
|
|||||||
struct list *pvms, *old_tail = lv->segments.p, *segh;
|
struct list *pvms, *old_tail = lv->segments.p, *segh;
|
||||||
struct lv_segment *seg;
|
struct lv_segment *seg;
|
||||||
|
|
||||||
|
if (segtype->flags & SEG_VIRTUAL)
|
||||||
|
return _alloc_virtual(lv, allocated, segtype);
|
||||||
|
|
||||||
if (!(scratch = pool_create(1024))) {
|
if (!(scratch = pool_create(1024))) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (alloc == ALLOC_INHERIT)
|
||||||
|
alloc = vg->alloc;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Build the sets of available areas on the pv's.
|
* Build the sets of available areas on the pv's.
|
||||||
*/
|
*/
|
||||||
if (!(pvms = create_pv_maps(scratch, vg, allocatable_pvs)))
|
if (!(pvms = create_pv_maps(scratch, vg, allocatable_pvs)))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (stripes > 1)
|
if (stripes > 1 || mirrors > 1)
|
||||||
r = _alloc_parallel(lv, pvms, allocated, stripes, stripe_size);
|
r = _alloc_parallel(lv, pvms, allocated, stripes, stripe_size,
|
||||||
|
mirrors, segtype);
|
||||||
|
|
||||||
else if (mirrored_pv)
|
else if (mirrored_pv)
|
||||||
r = _alloc_mirrored(lv, pvms, allocated, mirrored_pv,
|
r = _alloc_mirrored(lv, pvms, allocated, segtype, mirrored_pv,
|
||||||
mirrored_pe);
|
mirrored_pe);
|
||||||
else if (lv->alloc == ALLOC_CONTIGUOUS)
|
|
||||||
|
else if (alloc == ALLOC_CONTIGUOUS)
|
||||||
r = _alloc_contiguous(lv, pvms, allocated);
|
r = _alloc_contiguous(lv, pvms, allocated);
|
||||||
|
|
||||||
else if (lv->alloc == ALLOC_NEXT_FREE || lv->alloc == ALLOC_DEFAULT)
|
else if (alloc == ALLOC_NORMAL || alloc == ALLOC_ANYWHERE)
|
||||||
r = _alloc_next_free(lv, pvms, allocated);
|
r = _alloc_next_free(lv, pvms, allocated);
|
||||||
|
|
||||||
else {
|
else {
|
||||||
log_error("Unknown allocation policy: "
|
log_error("Unrecognised allocation policy: "
|
||||||
"unable to setup logical volume.");
|
"unable to set up logical volume.");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -554,57 +608,52 @@ struct logical_volume *lv_create_empty(struct format_instance *fi,
|
|||||||
return lv;
|
return lv;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct logical_volume *lv_create(struct format_instance *fi,
|
int lv_extend(struct format_instance *fid,
|
||||||
const char *name,
|
struct logical_volume *lv,
|
||||||
uint32_t status,
|
struct segment_type *segtype,
|
||||||
alloc_policy_t alloc,
|
uint32_t stripes, uint32_t stripe_size,
|
||||||
uint32_t stripes,
|
uint32_t mirrors, uint32_t extents,
|
||||||
uint32_t stripe_size,
|
struct physical_volume *mirrored_pv, uint32_t mirrored_pe,
|
||||||
uint32_t extents,
|
uint32_t status, struct list *allocatable_pvs,
|
||||||
struct volume_group *vg,
|
alloc_policy_t alloc)
|
||||||
struct list *allocatable_pvs)
|
|
||||||
{
|
{
|
||||||
struct logical_volume *lv;
|
uint32_t old_le_count = lv->le_count;
|
||||||
|
uint64_t old_size = lv->size;
|
||||||
|
|
||||||
if (!extents) {
|
lv->le_count += extents;
|
||||||
log_error("Unable to create logical volume %s with no extents",
|
lv->size += (uint64_t) extents *lv->vg->extent_size;
|
||||||
name);
|
|
||||||
return NULL;
|
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 (vg->free_count < extents) {
|
if (!_allocate(lv->vg, lv, allocatable_pvs, old_le_count, alloc,
|
||||||
log_error("Insufficient free extents (%u) in volume group %s: "
|
segtype, stripes, stripe_size, mirrors, mirrored_pv,
|
||||||
"%u required", vg->free_count, vg->name, extents);
|
mirrored_pe, status)) {
|
||||||
return NULL;
|
lv->le_count = old_le_count;
|
||||||
}
|
lv->size = old_size;
|
||||||
|
|
||||||
if (stripes > list_size(allocatable_pvs)) {
|
|
||||||
log_error("Number of stripes (%u) must not exceed "
|
|
||||||
"number of physical volumes (%d)", stripes,
|
|
||||||
list_size(allocatable_pvs));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(lv = lv_create_empty(fi, name, "lvol%d", status, alloc, vg))) {
|
|
||||||
stack;
|
stack;
|
||||||
return NULL;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
lv->size = (uint64_t) extents *vg->extent_size;
|
if ((segtype->flags & SEG_CAN_SPLIT) && !lv_merge_segments(lv)) {
|
||||||
lv->le_count = extents;
|
log_err("Couldn't merge segments after extending "
|
||||||
|
"logical volume.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (!_allocate(vg, lv, allocatable_pvs, 0u, stripes, stripe_size,
|
if (fid->fmt->ops->lv_setup && !fid->fmt->ops->lv_setup(fid, lv)) {
|
||||||
NULL, 0u, 0u)) {
|
|
||||||
stack;
|
stack;
|
||||||
return NULL;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fi->fmt->ops->lv_setup && !fi->fmt->ops->lv_setup(fi, lv)) {
|
return 1;
|
||||||
stack;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return lv;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int lv_reduce(struct format_instance *fi,
|
int lv_reduce(struct format_instance *fi,
|
||||||
@@ -628,7 +677,7 @@ int lv_reduce(struct format_instance *fi,
|
|||||||
/* reduce this segment */
|
/* reduce this segment */
|
||||||
_put_extents(seg);
|
_put_extents(seg);
|
||||||
seg->len -= count;
|
seg->len -= count;
|
||||||
striped = (seg->type == SEG_STRIPED);
|
striped = seg->segtype->flags & SEG_AREAS_STRIPED;
|
||||||
/* Caller must ensure exact divisibility */
|
/* Caller must ensure exact divisibility */
|
||||||
if (striped && (count % seg->area_count)) {
|
if (striped && (count % seg->area_count)) {
|
||||||
log_error("Segment extent reduction %" PRIu32
|
log_error("Segment extent reduction %" PRIu32
|
||||||
@@ -655,68 +704,6 @@ int lv_reduce(struct format_instance *fi,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lv_extend(struct format_instance *fi,
|
|
||||||
struct logical_volume *lv,
|
|
||||||
uint32_t stripes, uint32_t stripe_size,
|
|
||||||
uint32_t extents, struct list *allocatable_pvs)
|
|
||||||
{
|
|
||||||
uint32_t old_le_count = lv->le_count;
|
|
||||||
uint64_t old_size = lv->size;
|
|
||||||
|
|
||||||
lv->le_count += extents;
|
|
||||||
lv->size += (uint64_t) extents *lv->vg->extent_size;
|
|
||||||
|
|
||||||
if (!_allocate(lv->vg, lv, allocatable_pvs, old_le_count,
|
|
||||||
stripes, stripe_size, NULL, 0u, 0u)) {
|
|
||||||
lv->le_count = old_le_count;
|
|
||||||
lv->size = old_size;
|
|
||||||
stack;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!lv_merge_segments(lv)) {
|
|
||||||
log_err("Couldn't merge segments after extending "
|
|
||||||
"logical volume.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fi->fmt->ops->lv_setup && !fi->fmt->ops->lv_setup(fi, lv)) {
|
|
||||||
stack;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lv_extend_mirror(struct format_instance *fid,
|
|
||||||
struct logical_volume *lv,
|
|
||||||
struct physical_volume *mirrored_pv,
|
|
||||||
uint32_t mirrored_pe,
|
|
||||||
uint32_t extents, struct list *allocatable_pvs,
|
|
||||||
uint32_t status)
|
|
||||||
{
|
|
||||||
uint32_t old_le_count = lv->le_count;
|
|
||||||
uint64_t old_size = lv->size;
|
|
||||||
|
|
||||||
lv->le_count += extents;
|
|
||||||
lv->size += (uint64_t) extents *lv->vg->extent_size;
|
|
||||||
|
|
||||||
if (!_allocate(lv->vg, lv, allocatable_pvs, old_le_count,
|
|
||||||
1, extents, mirrored_pv, mirrored_pe, status)) {
|
|
||||||
lv->le_count = old_le_count;
|
|
||||||
lv->size = old_size;
|
|
||||||
stack;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fid->fmt->ops->lv_setup && !fid->fmt->ops->lv_setup(fid, lv)) {
|
|
||||||
stack;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lv_remove(struct volume_group *vg, struct logical_volume *lv)
|
int lv_remove(struct volume_group *vg, struct logical_volume *lv)
|
||||||
{
|
{
|
||||||
struct list *segh;
|
struct list *segh;
|
||||||
|
|||||||
@@ -18,60 +18,20 @@
|
|||||||
#include "toolcontext.h"
|
#include "toolcontext.h"
|
||||||
#include "lv_alloc.h"
|
#include "lv_alloc.h"
|
||||||
#include "str_list.h"
|
#include "str_list.h"
|
||||||
|
#include "segtype.h"
|
||||||
/*
|
|
||||||
* Test whether two segments could be merged by the current merging code
|
|
||||||
*/
|
|
||||||
static int _segments_compatible(struct lv_segment *first,
|
|
||||||
struct lv_segment *second)
|
|
||||||
{
|
|
||||||
uint32_t width;
|
|
||||||
unsigned s;
|
|
||||||
|
|
||||||
/* FIXME Relax the seg type restriction */
|
|
||||||
if (!first || !second ||
|
|
||||||
(first->type != SEG_STRIPED) || (second->type != first->type) ||
|
|
||||||
(first->area_count != second->area_count) ||
|
|
||||||
(first->stripe_size != second->stripe_size))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
for (s = 0; s < first->area_count; s++) {
|
|
||||||
|
|
||||||
/* FIXME Relax this to first area type != second area type */
|
|
||||||
/* plus the additional AREA_LV checks needed */
|
|
||||||
if ((first->area[s].type != AREA_PV) ||
|
|
||||||
(second->area[s].type != AREA_PV))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
width = first->area_len;
|
|
||||||
|
|
||||||
if ((first->area[s].u.pv.pv != second->area[s].u.pv.pv) ||
|
|
||||||
(first->area[s].u.pv.pe + width != second->area[s].u.pv.pe))
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!str_list_lists_equal(&first->tags, &second->tags))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Attempt to merge two adjacent segments.
|
* Attempt to merge two adjacent segments.
|
||||||
* Currently only supports SEG_STRIPED on AREA_PV.
|
* Currently only supports striped segments on AREA_PV.
|
||||||
* Returns success if successful, in which case 'first'
|
* Returns success if successful, in which case 'first'
|
||||||
* gets adjusted to contain both areas.
|
* gets adjusted to contain both areas.
|
||||||
*/
|
*/
|
||||||
static int _merge(struct lv_segment *first, struct lv_segment *second)
|
static int _merge(struct lv_segment *first, struct lv_segment *second)
|
||||||
{
|
{
|
||||||
|
if (!first || !second || first->segtype != second->segtype ||
|
||||||
|
!first->segtype->ops->merge_segments) return 0;
|
||||||
|
|
||||||
if (!_segments_compatible(first, second))
|
return first->segtype->ops->merge_segments(first, second);
|
||||||
return 0;
|
|
||||||
|
|
||||||
first->len += second->len;
|
|
||||||
first->area_len += second->area_len;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int lv_merge_segments(struct logical_volume *lv)
|
int lv_merge_segments(struct logical_volume *lv)
|
||||||
@@ -79,6 +39,9 @@ int lv_merge_segments(struct logical_volume *lv)
|
|||||||
struct list *segh, *t;
|
struct list *segh, *t;
|
||||||
struct lv_segment *current, *prev = NULL;
|
struct lv_segment *current, *prev = NULL;
|
||||||
|
|
||||||
|
if (lv->status & LOCKED || lv->status & PVMOVE)
|
||||||
|
return 1;
|
||||||
|
|
||||||
list_iterate_safe(segh, t, &lv->segments) {
|
list_iterate_safe(segh, t, &lv->segments) {
|
||||||
current = list_item(segh, struct lv_segment);
|
current = list_item(segh, struct lv_segment);
|
||||||
|
|
||||||
@@ -117,6 +80,7 @@ int lv_check_segments(struct logical_volume *lv)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Split the supplied segment at the supplied logical extent
|
* 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,
|
static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg,
|
||||||
uint32_t le)
|
uint32_t le)
|
||||||
@@ -125,16 +89,16 @@ static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg,
|
|||||||
struct lv_segment *split_seg;
|
struct lv_segment *split_seg;
|
||||||
uint32_t s;
|
uint32_t s;
|
||||||
uint32_t offset = le - seg->le;
|
uint32_t offset = le - seg->le;
|
||||||
|
uint32_t area_offset;
|
||||||
|
|
||||||
if (seg->type == SEG_SNAPSHOT) {
|
if (!(seg->segtype->flags & SEG_CAN_SPLIT)) {
|
||||||
log_error("Unable to split the snapshot segment at LE %" PRIu32
|
log_error("Unable to split the %s segment at LE %" PRIu32
|
||||||
" in LV %s", le, lv->name);
|
" in LV %s", seg->segtype->name, le, lv->name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clone the existing segment */
|
/* Clone the existing segment */
|
||||||
if (!(split_seg = alloc_lv_segment(lv->vg->cmd->mem,
|
if (!(split_seg = alloc_lv_segment(lv->vg->cmd->mem, seg->area_count))) {
|
||||||
seg->area_count))) {
|
|
||||||
log_error("Couldn't allocate new LV segment.");
|
log_error("Couldn't allocate new LV segment.");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -148,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 */
|
/* In case of a striped segment, the offset has to be / stripes */
|
||||||
if (seg->type == SEG_STRIPED)
|
area_offset = offset;
|
||||||
offset /= seg->area_count;
|
if (seg->segtype->flags & SEG_AREAS_STRIPED)
|
||||||
|
area_offset /= seg->area_count;
|
||||||
|
|
||||||
/* Adjust the PV mapping */
|
/* Adjust the PV mapping */
|
||||||
for (s = 0; s < seg->area_count; s++) {
|
for (s = 0; s < seg->area_count; s++) {
|
||||||
@@ -157,12 +122,19 @@ static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg,
|
|||||||
switch (seg->area[s].type) {
|
switch (seg->area[s].type) {
|
||||||
case AREA_LV:
|
case AREA_LV:
|
||||||
split_seg->area[s].u.lv.le =
|
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;
|
break;
|
||||||
|
|
||||||
case AREA_PV:
|
case AREA_PV:
|
||||||
split_seg->area[s].u.pv.pe =
|
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;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -172,8 +144,13 @@ static int _lv_split_segment(struct logical_volume *lv, struct lv_segment *seg,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
split_seg->area_len = seg->area_len - offset;
|
split_seg->area_len -= area_offset;
|
||||||
seg->area_len = 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 */
|
/* Add split off segment to the list _after_ the original one */
|
||||||
list_add_h(&seg->list, &split_seg->list);
|
list_add_h(&seg->list, &split_seg->list);
|
||||||
@@ -205,4 +182,3 @@ int lv_split_segment(struct logical_volume *lv, uint32_t le)
|
|||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ static int _add_pv_to_vg(struct format_instance *fid, struct volume_group *vg,
|
|||||||
}
|
}
|
||||||
|
|
||||||
list_init(&mdas);
|
list_init(&mdas);
|
||||||
if (!(pv = pv_read(fid->fmt->cmd, pv_name, &mdas, NULL))) {
|
if (!(pv = pv_read(fid->fmt->cmd, pv_name, &mdas, NULL, 1))) {
|
||||||
log_error("%s not identified as an existing physical volume",
|
log_error("%s not identified as an existing physical volume",
|
||||||
pv_name);
|
pv_name);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -162,7 +162,8 @@ const char *strip_dir(const char *vg_name, const char *dev_dir)
|
|||||||
|
|
||||||
struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
|
struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
|
||||||
uint32_t extent_size, uint32_t max_pv,
|
uint32_t extent_size, uint32_t max_pv,
|
||||||
uint32_t max_lv, int pv_count, char **pv_names)
|
uint32_t max_lv, alloc_policy_t alloc,
|
||||||
|
int pv_count, char **pv_names)
|
||||||
{
|
{
|
||||||
struct volume_group *vg;
|
struct volume_group *vg;
|
||||||
struct pool *mem = cmd->mem;
|
struct pool *mem = cmd->mem;
|
||||||
@@ -211,6 +212,8 @@ struct volume_group *vg_create(struct cmd_context *cmd, const char *vg_name,
|
|||||||
vg->max_lv = max_lv;
|
vg->max_lv = max_lv;
|
||||||
vg->max_pv = max_pv;
|
vg->max_pv = max_pv;
|
||||||
|
|
||||||
|
vg->alloc = alloc;
|
||||||
|
|
||||||
vg->pv_count = 0;
|
vg->pv_count = 0;
|
||||||
list_init(&vg->pvs);
|
list_init(&vg->pvs);
|
||||||
|
|
||||||
@@ -418,6 +421,24 @@ struct physical_volume *find_pv(struct volume_group *vg, struct device *dev)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct physical_volume *find_pv_by_name(struct cmd_context *cmd,
|
||||||
|
const char *pv_name)
|
||||||
|
{
|
||||||
|
struct physical_volume *pv;
|
||||||
|
|
||||||
|
if (!(pv = pv_read(cmd, pv_name, NULL, NULL, 1))) {
|
||||||
|
log_error("Physical volume %s not found", pv_name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pv->vg_name[0]) {
|
||||||
|
log_error("Physical volume %s not in a volume group", pv_name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pv;
|
||||||
|
}
|
||||||
|
|
||||||
/* Find segment at a given logical extent in an LV */
|
/* Find segment at a given logical extent in an LV */
|
||||||
struct lv_segment *find_seg_by_le(struct logical_volume *lv, uint32_t le)
|
struct lv_segment *find_seg_by_le(struct logical_volume *lv, uint32_t le)
|
||||||
{
|
{
|
||||||
@@ -584,7 +605,7 @@ static struct volume_group *_vg_read_orphans(struct cmd_context *cmd)
|
|||||||
|
|
||||||
list_iterate(ih, &vginfo->infos) {
|
list_iterate(ih, &vginfo->infos) {
|
||||||
dev = list_item(ih, struct lvmcache_info)->dev;
|
dev = list_item(ih, struct lvmcache_info)->dev;
|
||||||
if (!(pv = pv_read(cmd, dev_name(dev), NULL, NULL))) {
|
if (!(pv = pv_read(cmd, dev_name(dev), NULL, NULL, 1))) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!(pvl = pool_zalloc(cmd->mem, sizeof(*pvl)))) {
|
if (!(pvl = pool_zalloc(cmd->mem, sizeof(*pvl)))) {
|
||||||
@@ -793,7 +814,8 @@ struct logical_volume *lv_from_lvid(struct cmd_context *cmd, const char *lvid_s)
|
|||||||
|
|
||||||
/* FIXME Use label functions instead of PV functions */
|
/* FIXME Use label functions instead of PV functions */
|
||||||
struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name,
|
struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name,
|
||||||
struct list *mdas, uint64_t *label_sector)
|
struct list *mdas, uint64_t *label_sector,
|
||||||
|
int warnings)
|
||||||
{
|
{
|
||||||
struct physical_volume *pv;
|
struct physical_volume *pv;
|
||||||
struct label *label;
|
struct label *label;
|
||||||
@@ -806,7 +828,9 @@ struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!(label_read(dev, &label))) {
|
if (!(label_read(dev, &label))) {
|
||||||
log_error("No physical volume label read from %s", pv_name);
|
if (warnings)
|
||||||
|
log_error("No physical volume label read from %s",
|
||||||
|
pv_name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,6 +53,8 @@
|
|||||||
#define SNAPSHOT 0x00001000 /* LV - tmp internal use only */
|
#define SNAPSHOT 0x00001000 /* LV - tmp internal use only */
|
||||||
#define PVMOVE 0x00002000 /* VG LV SEG */
|
#define PVMOVE 0x00002000 /* VG LV SEG */
|
||||||
#define LOCKED 0x00004000 /* LV */
|
#define LOCKED 0x00004000 /* LV */
|
||||||
|
#define MIRRORED 0x00008000 /* LV - internal use only */
|
||||||
|
#define VIRTUAL 0x00010000 /* LV - internal use only */
|
||||||
|
|
||||||
#define LVM_READ 0x00000100 /* LV VG */
|
#define LVM_READ 0x00000100 /* LV VG */
|
||||||
#define LVM_WRITE 0x00000200 /* LV VG */
|
#define LVM_WRITE 0x00000200 /* LV VG */
|
||||||
@@ -66,18 +68,14 @@
|
|||||||
#define FMT_UNLIMITED_VOLS 0x00000008 /* Unlimited PVs/LVs? */
|
#define FMT_UNLIMITED_VOLS 0x00000008 /* Unlimited PVs/LVs? */
|
||||||
#define FMT_RESTRICTED_LVIDS 0x00000010 /* LVID <= 255 */
|
#define FMT_RESTRICTED_LVIDS 0x00000010 /* LVID <= 255 */
|
||||||
#define FMT_ORPHAN_ALLOCATABLE 0x00000020 /* Orphan PV allocatable? */
|
#define FMT_ORPHAN_ALLOCATABLE 0x00000020 /* Orphan PV allocatable? */
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
ALLOC_DEFAULT,
|
|
||||||
ALLOC_NEXT_FREE,
|
|
||||||
ALLOC_CONTIGUOUS
|
|
||||||
} alloc_policy_t;
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SEG_STRIPED,
|
ALLOC_INVALID,
|
||||||
SEG_SNAPSHOT,
|
ALLOC_INHERIT,
|
||||||
SEG_MIRRORED
|
ALLOC_CONTIGUOUS,
|
||||||
} segment_type_t;
|
ALLOC_NORMAL,
|
||||||
|
ALLOC_ANYWHERE
|
||||||
|
} alloc_policy_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
AREA_PV,
|
AREA_PV,
|
||||||
@@ -171,6 +169,7 @@ struct volume_group {
|
|||||||
char *system_id;
|
char *system_id;
|
||||||
|
|
||||||
uint32_t status;
|
uint32_t status;
|
||||||
|
alloc_policy_t alloc;
|
||||||
|
|
||||||
uint32_t extent_size;
|
uint32_t extent_size;
|
||||||
uint32_t extent_count;
|
uint32_t extent_count;
|
||||||
@@ -194,11 +193,12 @@ struct volume_group {
|
|||||||
struct list tags;
|
struct list tags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct segment_type;
|
||||||
struct lv_segment {
|
struct lv_segment {
|
||||||
struct list list;
|
struct list list;
|
||||||
struct logical_volume *lv;
|
struct logical_volume *lv;
|
||||||
|
|
||||||
segment_type_t type;
|
struct segment_type *segtype;
|
||||||
uint32_t le;
|
uint32_t le;
|
||||||
uint32_t len;
|
uint32_t len;
|
||||||
|
|
||||||
@@ -211,7 +211,7 @@ struct lv_segment {
|
|||||||
struct logical_volume *origin;
|
struct logical_volume *origin;
|
||||||
struct logical_volume *cow;
|
struct logical_volume *cow;
|
||||||
uint32_t chunk_size;
|
uint32_t chunk_size;
|
||||||
uint32_t extents_moved;
|
uint32_t extents_copied;
|
||||||
|
|
||||||
struct list tags;
|
struct list tags;
|
||||||
|
|
||||||
@@ -265,7 +265,7 @@ struct name_list {
|
|||||||
char *name;
|
char *name;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct alloc_area {
|
struct pe_range {
|
||||||
struct list list;
|
struct list list;
|
||||||
uint32_t start; /* PEs */
|
uint32_t start; /* PEs */
|
||||||
uint32_t count; /* PEs */
|
uint32_t count; /* PEs */
|
||||||
@@ -275,7 +275,7 @@ struct pv_list {
|
|||||||
struct list list;
|
struct list list;
|
||||||
struct physical_volume *pv;
|
struct physical_volume *pv;
|
||||||
struct list *mdas; /* Metadata areas */
|
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 {
|
struct lv_list {
|
||||||
@@ -341,6 +341,12 @@ struct format_handler {
|
|||||||
*/
|
*/
|
||||||
int (*vg_setup) (struct format_instance * fi, struct volume_group * vg);
|
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
|
* Create format instance with a particular metadata area
|
||||||
*/
|
*/
|
||||||
@@ -369,7 +375,8 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name,
|
|||||||
int *consistent);
|
int *consistent);
|
||||||
struct volume_group *vg_read_by_vgid(struct cmd_context *cmd, const char *vgid);
|
struct volume_group *vg_read_by_vgid(struct cmd_context *cmd, const char *vgid);
|
||||||
struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name,
|
struct physical_volume *pv_read(struct cmd_context *cmd, const char *pv_name,
|
||||||
struct list *mdas, uint64_t *label_sector);
|
struct list *mdas, uint64_t *label_sector,
|
||||||
|
int warnings);
|
||||||
struct list *get_pvs(struct cmd_context *cmd);
|
struct list *get_pvs(struct cmd_context *cmd);
|
||||||
|
|
||||||
/* Set full_scan to 1 to re-read every (filtered) device label */
|
/* Set full_scan to 1 to re-read every (filtered) device label */
|
||||||
@@ -392,27 +399,15 @@ struct physical_volume *pv_create(const struct format_type *fmt,
|
|||||||
|
|
||||||
struct volume_group *vg_create(struct cmd_context *cmd, const char *name,
|
struct volume_group *vg_create(struct cmd_context *cmd, const char *name,
|
||||||
uint32_t extent_size, uint32_t max_pv,
|
uint32_t extent_size, uint32_t max_pv,
|
||||||
uint32_t max_lv, int pv_count, char **pv_names);
|
uint32_t max_lv, alloc_policy_t alloc,
|
||||||
|
int pv_count, char **pv_names);
|
||||||
int vg_remove(struct volume_group *vg);
|
int vg_remove(struct volume_group *vg);
|
||||||
int vg_rename(struct cmd_context *cmd, struct volume_group *vg,
|
int vg_rename(struct cmd_context *cmd, struct volume_group *vg,
|
||||||
const char *new_name);
|
const char *new_name);
|
||||||
int vg_extend(struct format_instance *fi, struct volume_group *vg,
|
int vg_extend(struct format_instance *fi, struct volume_group *vg,
|
||||||
int pv_count, char **pv_names);
|
int pv_count, char **pv_names);
|
||||||
|
|
||||||
/*
|
/* Manipulate LVs */
|
||||||
* Create a new LV within a given volume group.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
struct logical_volume *lv_create(struct format_instance *fi,
|
|
||||||
const char *name,
|
|
||||||
uint32_t status,
|
|
||||||
alloc_policy_t alloc,
|
|
||||||
uint32_t stripes,
|
|
||||||
uint32_t stripe_size,
|
|
||||||
uint32_t extents,
|
|
||||||
struct volume_group *vg,
|
|
||||||
struct list *allocatable_pvs);
|
|
||||||
|
|
||||||
struct logical_volume *lv_create_empty(struct format_instance *fi,
|
struct logical_volume *lv_create_empty(struct format_instance *fi,
|
||||||
const char *name,
|
const char *name,
|
||||||
const char *name_format,
|
const char *name_format,
|
||||||
@@ -420,22 +415,17 @@ struct logical_volume *lv_create_empty(struct format_instance *fi,
|
|||||||
alloc_policy_t alloc,
|
alloc_policy_t alloc,
|
||||||
struct volume_group *vg);
|
struct volume_group *vg);
|
||||||
|
|
||||||
/* Manipulate LVs */
|
|
||||||
int lv_reduce(struct format_instance *fi,
|
int lv_reduce(struct format_instance *fi,
|
||||||
struct logical_volume *lv, uint32_t extents);
|
struct logical_volume *lv, uint32_t extents);
|
||||||
|
|
||||||
int lv_extend(struct format_instance *fi,
|
int lv_extend(struct format_instance *fid,
|
||||||
struct logical_volume *lv,
|
struct logical_volume *lv,
|
||||||
uint32_t stripes,
|
struct segment_type *segtype,
|
||||||
uint32_t stripe_size,
|
uint32_t stripes, uint32_t stripe_size,
|
||||||
uint32_t extents, struct list *allocatable_pvs);
|
uint32_t mirrors, uint32_t extents,
|
||||||
|
struct physical_volume *mirrored_pv, uint32_t mirrored_pe,
|
||||||
int lv_extend_mirror(struct format_instance *fid,
|
uint32_t status, struct list *allocatable_pvs,
|
||||||
struct logical_volume *lv,
|
alloc_policy_t alloc);
|
||||||
struct physical_volume *mirrored_pv,
|
|
||||||
uint32_t mirrored_pe,
|
|
||||||
uint32_t extents, struct list *allocatable_pvs,
|
|
||||||
uint32_t status);
|
|
||||||
|
|
||||||
/* lv must be part of vg->lvs */
|
/* lv must be part of vg->lvs */
|
||||||
int lv_remove(struct volume_group *vg, struct logical_volume *lv);
|
int lv_remove(struct volume_group *vg, struct logical_volume *lv);
|
||||||
@@ -466,6 +456,8 @@ struct logical_volume *lv_from_lvid(struct cmd_context *cmd,
|
|||||||
/* FIXME Merge these functions with ones above */
|
/* FIXME Merge these functions with ones above */
|
||||||
struct physical_volume *find_pv(struct volume_group *vg, struct device *dev);
|
struct physical_volume *find_pv(struct volume_group *vg, struct device *dev);
|
||||||
struct logical_volume *find_lv(struct volume_group *vg, const char *lv_name);
|
struct logical_volume *find_lv(struct volume_group *vg, const char *lv_name);
|
||||||
|
struct physical_volume *find_pv_by_name(struct cmd_context *cmd,
|
||||||
|
const char *pv_name);
|
||||||
|
|
||||||
/* Find LV segment containing given LE */
|
/* Find LV segment containing given LE */
|
||||||
struct lv_segment *find_seg_by_le(struct logical_volume *lv, uint32_t le);
|
struct lv_segment *find_seg_by_le(struct logical_volume *lv, uint32_t le);
|
||||||
@@ -515,18 +507,21 @@ int vg_remove_snapshot(struct volume_group *vg, struct logical_volume *cow);
|
|||||||
*/
|
*/
|
||||||
int insert_pvmove_mirrors(struct cmd_context *cmd,
|
int insert_pvmove_mirrors(struct cmd_context *cmd,
|
||||||
struct logical_volume *lv_mirr,
|
struct logical_volume *lv_mirr,
|
||||||
struct physical_volume *pv,
|
struct list *source_pvl,
|
||||||
struct logical_volume *lv,
|
struct logical_volume *lv,
|
||||||
struct list *allocatable_pvs,
|
struct list *allocatable_pvs,
|
||||||
struct list *lvs_changed);
|
struct list *lvs_changed);
|
||||||
int remove_pvmove_mirrors(struct volume_group *vg,
|
int remove_pvmove_mirrors(struct volume_group *vg,
|
||||||
struct logical_volume *lv_mirr);
|
struct logical_volume *lv_mirr);
|
||||||
struct logical_volume *find_pvmove_lv(struct volume_group *vg,
|
struct logical_volume *find_pvmove_lv(struct volume_group *vg,
|
||||||
struct device *dev);
|
struct device *dev, uint32_t lv_type);
|
||||||
struct physical_volume *get_pvmove_pv_from_lv(struct logical_volume *lv);
|
struct logical_volume *find_pvmove_lv_from_pvname(struct cmd_context *cmd,
|
||||||
struct physical_volume *get_pvmove_pv_from_lv_mirr(struct logical_volume
|
struct volume_group *vg,
|
||||||
*lv_mirr);
|
const char *name,
|
||||||
float pvmove_percent(struct logical_volume *lv_mirr);
|
uint32_t lv_type);
|
||||||
|
const char *get_pvmove_pvname_from_lv(struct logical_volume *lv);
|
||||||
|
const char *get_pvmove_pvname_from_lv_mirr(struct logical_volume *lv_mirr);
|
||||||
|
float copy_percent(struct logical_volume *lv_mirr);
|
||||||
struct list *lvs_using_lv(struct cmd_context *cmd, struct volume_group *vg,
|
struct list *lvs_using_lv(struct cmd_context *cmd, struct volume_group *vg,
|
||||||
struct logical_volume *lv);
|
struct logical_volume *lv);
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,9 @@
|
|||||||
#include "lib.h"
|
#include "lib.h"
|
||||||
#include "metadata.h"
|
#include "metadata.h"
|
||||||
#include "toolcontext.h"
|
#include "toolcontext.h"
|
||||||
|
#include "segtype.h"
|
||||||
|
#include "display.h"
|
||||||
|
#include "activate.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Replace any LV segments on given PV with temporary mirror.
|
* Replace any LV segments on given PV with temporary mirror.
|
||||||
@@ -23,7 +26,7 @@
|
|||||||
*/
|
*/
|
||||||
int insert_pvmove_mirrors(struct cmd_context *cmd,
|
int insert_pvmove_mirrors(struct cmd_context *cmd,
|
||||||
struct logical_volume *lv_mirr,
|
struct logical_volume *lv_mirr,
|
||||||
struct physical_volume *pv,
|
struct list *source_pvl,
|
||||||
struct logical_volume *lv,
|
struct logical_volume *lv,
|
||||||
struct list *allocatable_pvs,
|
struct list *allocatable_pvs,
|
||||||
struct list *lvs_changed)
|
struct list *lvs_changed)
|
||||||
@@ -31,43 +34,135 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
|
|||||||
struct list *segh;
|
struct list *segh;
|
||||||
struct lv_segment *seg;
|
struct lv_segment *seg;
|
||||||
struct lv_list *lvl;
|
struct lv_list *lvl;
|
||||||
|
struct pv_list *pvl;
|
||||||
int lv_used = 0;
|
int lv_used = 0;
|
||||||
uint32_t s, start_le, extent_count = 0u;
|
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;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activation() && segtype->ops->target_present &&
|
||||||
|
!segtype->ops->target_present()) {
|
||||||
|
log_error("%s: Required device-mapper target(s) not "
|
||||||
|
"detected in your kernel", segtype->name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Split LV segments to match PE ranges */
|
||||||
list_iterate(segh, &lv->segments) {
|
list_iterate(segh, &lv->segments) {
|
||||||
seg = list_item(segh, struct lv_segment);
|
seg = list_item(segh, struct lv_segment);
|
||||||
for (s = 0; s < seg->area_count; s++) {
|
for (s = 0; s < seg->area_count; s++) {
|
||||||
if (seg->area[s].type != AREA_PV ||
|
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;
|
continue;
|
||||||
|
|
||||||
if (!lv_used) {
|
/* Do these PEs need moving? */
|
||||||
if (!(lvl = pool_alloc(cmd->mem, sizeof(*lvl)))) {
|
list_iterate_items(per, pvl->pe_ranges) {
|
||||||
log_error("lv_list alloc failed");
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
lvl->lv = lv;
|
|
||||||
list_add(lvs_changed, &lvl->list);
|
|
||||||
lv_used = 1;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
start_le = lv_mirr->le_count;
|
/* Work through all segments on the supplied PV */
|
||||||
if (!lv_extend_mirror(lv->vg->fid, lv_mirr,
|
list_iterate(segh, &lv->segments) {
|
||||||
seg->area[s].u.pv.pv,
|
seg = list_item(segh, struct lv_segment);
|
||||||
seg->area[s].u.pv.pe,
|
for (s = 0; s < seg->area_count; s++) {
|
||||||
seg->area_len, allocatable_pvs,
|
if (seg->area[s].type != AREA_PV ||
|
||||||
PVMOVE)) {
|
seg->area[s].u.pv.pv->dev != pvl->pv->dev)
|
||||||
log_error("Allocation for temporary "
|
continue;
|
||||||
"pvmove LV failed");
|
|
||||||
return 0;
|
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;
|
||||||
|
}
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,6 +172,7 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Remove a temporary mirror */
|
||||||
int remove_pvmove_mirrors(struct volume_group *vg,
|
int remove_pvmove_mirrors(struct volume_group *vg,
|
||||||
struct logical_volume *lv_mirr)
|
struct logical_volume *lv_mirr)
|
||||||
{
|
{
|
||||||
@@ -85,11 +181,13 @@ int remove_pvmove_mirrors(struct volume_group *vg,
|
|||||||
struct lv_segment *seg, *mir_seg;
|
struct lv_segment *seg, *mir_seg;
|
||||||
uint32_t s, c;
|
uint32_t s, c;
|
||||||
|
|
||||||
|
/* Loop through all LVs except the temporary mirror */
|
||||||
list_iterate(lvh, &vg->lvs) {
|
list_iterate(lvh, &vg->lvs) {
|
||||||
lv1 = list_item(lvh, struct lv_list)->lv;
|
lv1 = list_item(lvh, struct lv_list)->lv;
|
||||||
if (lv1 == lv_mirr)
|
if (lv1 == lv_mirr)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/* Find all segments that point at the temporary mirror */
|
||||||
list_iterate(segh, &lv1->segments) {
|
list_iterate(segh, &lv1->segments) {
|
||||||
seg = list_item(segh, struct lv_segment);
|
seg = list_item(segh, struct lv_segment);
|
||||||
for (s = 0; s < seg->area_count; s++) {
|
for (s = 0; s < seg->area_count; s++) {
|
||||||
@@ -97,14 +195,19 @@ int remove_pvmove_mirrors(struct volume_group *vg,
|
|||||||
seg->area[s].u.lv.lv != lv_mirr)
|
seg->area[s].u.lv.lv != lv_mirr)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/* Find the mirror segment pointed at */
|
||||||
if (!(mir_seg = find_seg_by_le(lv_mirr,
|
if (!(mir_seg = find_seg_by_le(lv_mirr,
|
||||||
seg->area[s].u.
|
seg->area[s].
|
||||||
lv.le))) {
|
u.lv.le))) {
|
||||||
|
/* FIXME Error message */
|
||||||
log_error("No segment found with LE");
|
log_error("No segment found with LE");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mir_seg->type != SEG_MIRRORED ||
|
/* Check the segment params are compatible */
|
||||||
|
/* FIXME Improve error mesg & remove restrcn */
|
||||||
|
if ((!(mir_seg->segtype->flags
|
||||||
|
& SEG_AREAS_MIRRORED)) ||
|
||||||
!(mir_seg->status & PVMOVE) ||
|
!(mir_seg->status & PVMOVE) ||
|
||||||
mir_seg->le != seg->area[s].u.lv.le ||
|
mir_seg->le != seg->area[s].u.lv.le ||
|
||||||
mir_seg->area_count != 2 ||
|
mir_seg->area_count != 2 ||
|
||||||
@@ -113,7 +216,11 @@ int remove_pvmove_mirrors(struct volume_group *vg,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mir_seg->extents_moved == mir_seg->area_len)
|
/* Replace original segment with newly-mirrored
|
||||||
|
* area (or original if reverting)
|
||||||
|
*/
|
||||||
|
if (mir_seg->extents_copied ==
|
||||||
|
mir_seg->area_len)
|
||||||
c = 1;
|
c = 1;
|
||||||
else
|
else
|
||||||
c = 0;
|
c = 0;
|
||||||
@@ -122,36 +229,47 @@ int remove_pvmove_mirrors(struct volume_group *vg,
|
|||||||
seg->area[s].u.pv.pv = mir_seg->area[c].u.pv.pv;
|
seg->area[s].u.pv.pv = mir_seg->area[c].u.pv.pv;
|
||||||
seg->area[s].u.pv.pe = mir_seg->area[c].u.pv.pe;
|
seg->area[s].u.pv.pe = mir_seg->area[c].u.pv.pe;
|
||||||
|
|
||||||
mir_seg->type = SEG_STRIPED;
|
/* Replace mirror with old area */
|
||||||
|
if (!
|
||||||
|
(mir_seg->segtype =
|
||||||
|
get_segtype_from_string(vg->cmd,
|
||||||
|
"striped"))) {
|
||||||
|
log_error("Missing striped segtype");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
mir_seg->area_count = 1;
|
mir_seg->area_count = 1;
|
||||||
|
|
||||||
|
/* FIXME Assumes only one pvmove at a time! */
|
||||||
lv1->status &= ~LOCKED;
|
lv1->status &= ~LOCKED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!lv_merge_segments(lv1))
|
||||||
|
stack;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct physical_volume *get_pvmove_pv_from_lv_mirr(struct logical_volume
|
const char *get_pvmove_pvname_from_lv_mirr(struct logical_volume *lv_mirr)
|
||||||
*lv_mirr)
|
|
||||||
{
|
{
|
||||||
struct list *segh;
|
struct list *segh;
|
||||||
struct lv_segment *seg;
|
struct lv_segment *seg;
|
||||||
|
|
||||||
list_iterate(segh, &lv_mirr->segments) {
|
list_iterate(segh, &lv_mirr->segments) {
|
||||||
seg = list_item(segh, struct lv_segment);
|
seg = list_item(segh, struct lv_segment);
|
||||||
if (seg->type != SEG_MIRRORED)
|
if (!(seg->segtype->flags & SEG_AREAS_MIRRORED))
|
||||||
continue;
|
continue;
|
||||||
if (seg->area[0].type != AREA_PV)
|
if (seg->area[0].type != AREA_PV)
|
||||||
continue;
|
continue;
|
||||||
return seg->area[0].u.pv.pv;
|
return dev_name(seg->area[0].u.pv.pv->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct physical_volume *get_pvmove_pv_from_lv(struct logical_volume *lv)
|
const char *get_pvmove_pvname_from_lv(struct logical_volume *lv)
|
||||||
{
|
{
|
||||||
struct list *segh;
|
struct list *segh;
|
||||||
struct lv_segment *seg;
|
struct lv_segment *seg;
|
||||||
@@ -162,7 +280,7 @@ struct physical_volume *get_pvmove_pv_from_lv(struct logical_volume *lv)
|
|||||||
for (s = 0; s < seg->area_count; s++) {
|
for (s = 0; s < seg->area_count; s++) {
|
||||||
if (seg->area[s].type != AREA_LV)
|
if (seg->area[s].type != AREA_LV)
|
||||||
continue;
|
continue;
|
||||||
return get_pvmove_pv_from_lv_mirr(seg->area[s].u.lv.lv);
|
return get_pvmove_pvname_from_lv_mirr(seg->area[s].u.lv.lv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,7 +288,8 @@ struct physical_volume *get_pvmove_pv_from_lv(struct logical_volume *lv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct logical_volume *find_pvmove_lv(struct volume_group *vg,
|
struct logical_volume *find_pvmove_lv(struct volume_group *vg,
|
||||||
struct device *dev)
|
struct device *dev,
|
||||||
|
uint32_t lv_type)
|
||||||
{
|
{
|
||||||
struct list *lvh, *segh;
|
struct list *lvh, *segh;
|
||||||
struct logical_volume *lv;
|
struct logical_volume *lv;
|
||||||
@@ -180,9 +299,10 @@ struct logical_volume *find_pvmove_lv(struct volume_group *vg,
|
|||||||
list_iterate(lvh, &vg->lvs) {
|
list_iterate(lvh, &vg->lvs) {
|
||||||
lv = list_item(lvh, struct lv_list)->lv;
|
lv = list_item(lvh, struct lv_list)->lv;
|
||||||
|
|
||||||
if (!(lv->status & PVMOVE))
|
if (!(lv->status & lv_type))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/* Check segment origins point to pvname */
|
||||||
list_iterate(segh, &lv->segments) {
|
list_iterate(segh, &lv->segments) {
|
||||||
seg = list_item(segh, struct lv_segment);
|
seg = list_item(segh, struct lv_segment);
|
||||||
if (seg->area[0].type != AREA_PV)
|
if (seg->area[0].type != AREA_PV)
|
||||||
@@ -196,6 +316,21 @@ struct logical_volume *find_pvmove_lv(struct volume_group *vg,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct logical_volume *find_pvmove_lv_from_pvname(struct cmd_context *cmd,
|
||||||
|
struct volume_group *vg,
|
||||||
|
const char *name,
|
||||||
|
uint32_t lv_type)
|
||||||
|
{
|
||||||
|
struct physical_volume *pv;
|
||||||
|
|
||||||
|
if (!(pv = find_pv_by_name(cmd, name))) {
|
||||||
|
stack;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return find_pvmove_lv(vg, pv->dev, lv_type);
|
||||||
|
}
|
||||||
|
|
||||||
struct list *lvs_using_lv(struct cmd_context *cmd, struct volume_group *vg,
|
struct list *lvs_using_lv(struct cmd_context *cmd, struct volume_group *vg,
|
||||||
struct logical_volume *lv)
|
struct logical_volume *lv)
|
||||||
{
|
{
|
||||||
@@ -218,6 +353,7 @@ struct list *lvs_using_lv(struct cmd_context *cmd, struct volume_group *vg,
|
|||||||
if (lv1 == lv)
|
if (lv1 == lv)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/* Find whether any segment points at the supplied LV */
|
||||||
list_iterate(segh, &lv1->segments) {
|
list_iterate(segh, &lv1->segments) {
|
||||||
seg = list_item(segh, struct lv_segment);
|
seg = list_item(segh, struct lv_segment);
|
||||||
for (s = 0; s < seg->area_count; s++) {
|
for (s = 0; s < seg->area_count; s++) {
|
||||||
@@ -240,7 +376,7 @@ struct list *lvs_using_lv(struct cmd_context *cmd, struct volume_group *vg,
|
|||||||
return lvs;
|
return lvs;
|
||||||
}
|
}
|
||||||
|
|
||||||
float pvmove_percent(struct logical_volume *lv_mirr)
|
float copy_percent(struct logical_volume *lv_mirr)
|
||||||
{
|
{
|
||||||
uint32_t numerator = 0u, denominator = 0u;
|
uint32_t numerator = 0u, denominator = 0u;
|
||||||
struct list *segh;
|
struct list *segh;
|
||||||
@@ -248,11 +384,13 @@ float pvmove_percent(struct logical_volume *lv_mirr)
|
|||||||
|
|
||||||
list_iterate(segh, &lv_mirr->segments) {
|
list_iterate(segh, &lv_mirr->segments) {
|
||||||
seg = list_item(segh, struct lv_segment);
|
seg = list_item(segh, struct lv_segment);
|
||||||
if (!(seg->status & PVMOVE))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
numerator += seg->extents_moved;
|
|
||||||
denominator += seg->area_len;
|
denominator += seg->area_len;
|
||||||
|
|
||||||
|
if (seg->segtype->flags & SEG_AREAS_MIRRORED)
|
||||||
|
numerator += seg->extents_copied;
|
||||||
|
else
|
||||||
|
numerator += seg->area_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
return denominator ? (float) numerator *100 / denominator : 100.0;
|
return denominator ? (float) numerator *100 / denominator : 100.0;
|
||||||
|
|||||||
@@ -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)
|
static int _create_allocatable_areas(struct pool *mem, struct pv_map *pvm)
|
||||||
{
|
{
|
||||||
struct list *alloc_areas, *aah;
|
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) {
|
if (alloc_areas) {
|
||||||
list_iterate(aah, 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)) {
|
if (!_create_areas(mem, pvm, aa->start, aa->count)) {
|
||||||
stack;
|
stack;
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
32
lib/metadata/segtype.c
Normal file
32
lib/metadata/segtype.c
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* 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 "lib.h"
|
||||||
|
#include "toolcontext.h"
|
||||||
|
#include "segtype.h"
|
||||||
|
|
||||||
|
struct segment_type *get_segtype_from_string(struct cmd_context *cmd,
|
||||||
|
const char *str)
|
||||||
|
{
|
||||||
|
struct segment_type *segtype;
|
||||||
|
|
||||||
|
list_iterate_items(segtype, &cmd->segtypes) {
|
||||||
|
if (!strcmp(segtype->name, str))
|
||||||
|
return segtype;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_error("Unrecognised segment type %s", str);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
92
lib/metadata/segtype.h
Normal file
92
lib/metadata/segtype.h
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2001-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 _SEGTYPES_H
|
||||||
|
#define _SEGTYPES_H
|
||||||
|
|
||||||
|
struct segtype_handler;
|
||||||
|
struct cmd_context;
|
||||||
|
struct config_tree;
|
||||||
|
struct lv_segment;
|
||||||
|
struct formatter;
|
||||||
|
struct config_node;
|
||||||
|
struct hash_table;
|
||||||
|
struct dev_manager;
|
||||||
|
|
||||||
|
/* Feature flags */
|
||||||
|
#define SEG_CAN_SPLIT 0x00000001
|
||||||
|
#define SEG_AREAS_STRIPED 0x00000002
|
||||||
|
#define SEG_AREAS_MIRRORED 0x00000004
|
||||||
|
#define SEG_SNAPSHOT 0x00000008
|
||||||
|
#define SEG_FORMAT1_SUPPORT 0x00000010
|
||||||
|
#define SEG_VIRTUAL 0x00000020
|
||||||
|
|
||||||
|
struct segment_type {
|
||||||
|
struct list list;
|
||||||
|
struct cmd_context *cmd;
|
||||||
|
uint32_t flags;
|
||||||
|
struct segtype_handler *ops;
|
||||||
|
const char *name;
|
||||||
|
void *library;
|
||||||
|
void *private;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct segtype_handler {
|
||||||
|
const char *(*name) (const struct lv_segment * seg);
|
||||||
|
void (*display) (const struct lv_segment * seg);
|
||||||
|
int (*text_export) (const struct lv_segment * seg,
|
||||||
|
struct formatter * f);
|
||||||
|
int (*text_import_area_count) (struct config_node * sn,
|
||||||
|
uint32_t *area_count);
|
||||||
|
int (*text_import) (struct lv_segment * seg,
|
||||||
|
const struct config_node * sn,
|
||||||
|
struct hash_table * pv_hash);
|
||||||
|
int (*merge_segments) (struct lv_segment * seg1,
|
||||||
|
struct lv_segment * seg2);
|
||||||
|
int (*compose_target_line) (struct dev_manager * dm, struct pool * mem,
|
||||||
|
struct config_tree * cft,
|
||||||
|
void **target_state,
|
||||||
|
struct lv_segment * seg, char *params,
|
||||||
|
size_t paramsize, const char **target,
|
||||||
|
int *pos, uint32_t *pvmove_mirror_count);
|
||||||
|
int (*target_percent) (void **target_state, struct pool * mem,
|
||||||
|
struct config_tree * cft,
|
||||||
|
struct lv_segment * seg, char *params,
|
||||||
|
uint64_t *total_numerator,
|
||||||
|
uint64_t *total_denominator, float *percent);
|
||||||
|
int (*target_present) (void);
|
||||||
|
void (*destroy) (const struct segment_type * segtype);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct segment_type *get_segtype_from_string(struct cmd_context *cmd,
|
||||||
|
const char *str);
|
||||||
|
|
||||||
|
struct segment_type *init_striped_segtype(struct cmd_context *cmd);
|
||||||
|
struct segment_type *init_zero_segtype(struct cmd_context *cmd);
|
||||||
|
struct segment_type *init_error_segtype(struct cmd_context *cmd);
|
||||||
|
|
||||||
|
#ifdef SNAPSHOT_INTERNAL
|
||||||
|
struct segment_type *init_snapshot_segtype(struct cmd_context *cmd);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef MIRRORED_INTERNAL
|
||||||
|
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
|
||||||
1
lib/mirror/.exported_symbols
Normal file
1
lib/mirror/.exported_symbols
Normal file
@@ -0,0 +1 @@
|
|||||||
|
init_segtype
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user