mirror of
git://sourceware.org/git/lvm2.git
synced 2025-12-28 04:23:49 +03:00
Compare commits
108 Commits
dm_v1_02_1
...
dm_v1_02_1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e8e00630d3 | ||
|
|
e33720c854 | ||
|
|
bd8a4e0d17 | ||
|
|
586a2aef76 | ||
|
|
ce1d8f6754 | ||
|
|
7b0f401065 | ||
|
|
8387016eef | ||
|
|
4e1342b641 | ||
|
|
e45a184d90 | ||
|
|
979e1012d2 | ||
|
|
fe10a50e23 | ||
|
|
8ab6d72519 | ||
|
|
3aada6dd1d | ||
|
|
0933036366 | ||
|
|
05f5abdc06 | ||
|
|
fb875e0709 | ||
|
|
9acdc2f6bf | ||
|
|
028ce4bff6 | ||
|
|
3f245ad6db | ||
|
|
23115f4116 | ||
|
|
cf5f48e6cc | ||
|
|
997fa756ad | ||
|
|
e23f75b1cc | ||
|
|
6531e88761 | ||
|
|
e76a9c2618 | ||
|
|
45be8a836b | ||
|
|
954b6032e7 | ||
|
|
bd95416f27 | ||
|
|
df2577ace2 | ||
|
|
720e6558c9 | ||
|
|
c239f15d8a | ||
|
|
dfa1f80a57 | ||
|
|
15dfb93b17 | ||
|
|
0ec8488c2b | ||
|
|
94b2e29cb1 | ||
|
|
fefa8e9b4d | ||
|
|
32c4c44812 | ||
|
|
05195e2b1d | ||
|
|
4c2ff675b8 | ||
|
|
e5692a4721 | ||
|
|
312e6a0d31 | ||
|
|
5bb8efa41f | ||
|
|
949a835f4a | ||
|
|
85e6042941 | ||
|
|
3cd2f28975 | ||
|
|
2179a72c3a | ||
|
|
a5f282f156 | ||
|
|
40e8631f63 | ||
|
|
9ded05bb97 | ||
|
|
ec8efa35a1 | ||
|
|
f72bf20482 | ||
|
|
ebde2002e8 | ||
|
|
352a66f46f | ||
|
|
d84c5391f7 | ||
|
|
f4c582472b | ||
|
|
1485586f7e | ||
|
|
d5c9024335 | ||
|
|
860cf80703 | ||
|
|
897ff3161f | ||
|
|
b356b2e501 | ||
|
|
1d2733c893 | ||
|
|
32d9126094 | ||
|
|
db43314e50 | ||
|
|
68d2baeb65 | ||
|
|
1fd5f562d3 | ||
|
|
48e02f2086 | ||
|
|
eab7b2b581 | ||
|
|
45abade7fc | ||
|
|
5372fc4b43 | ||
|
|
4e2f240c98 | ||
|
|
bb3605518d | ||
|
|
3ef6d37f27 | ||
|
|
88e9f2f7f4 | ||
|
|
704a447df9 | ||
|
|
a5fcb26a33 | ||
|
|
2491a61481 | ||
|
|
91831d51ed | ||
|
|
174f0c19f7 | ||
|
|
de6fadfb4f | ||
|
|
f946db3e00 | ||
|
|
8d05e5bc31 | ||
|
|
cfb46820e4 | ||
|
|
081f1cbcc2 | ||
|
|
7bc6da326f | ||
|
|
cd95a0df7b | ||
|
|
82fa497c16 | ||
|
|
44fd345206 | ||
|
|
088e1c9db4 | ||
|
|
d4f16e666e | ||
|
|
8233cfd371 | ||
|
|
ff05e2e30d | ||
|
|
a8ea7dd3fb | ||
|
|
96f70a5303 | ||
|
|
f1604c3e69 | ||
|
|
c42c8c5192 | ||
|
|
5facb53a41 | ||
|
|
d039ce89af | ||
|
|
bc7605103f | ||
|
|
d305d655d4 | ||
|
|
4ef1220b16 | ||
|
|
a4fef143cd | ||
|
|
74ecb724a9 | ||
|
|
af235897ab | ||
|
|
5ec4e458b5 | ||
|
|
2dae63ce21 | ||
|
|
be748fe33b | ||
|
|
7408340b6a | ||
|
|
29eb92446e |
@@ -16,7 +16,7 @@ srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
SUBDIRS = doc include man
|
||||
SUBDIRS = doc include man scripts
|
||||
|
||||
ifeq ("@INTL@", "yes")
|
||||
SUBDIRS += po
|
||||
|
||||
83
WHATS_NEW
83
WHATS_NEW
@@ -1,5 +1,84 @@
|
||||
Version 2.02.10 -
|
||||
==================================
|
||||
Version 2.02.16 -
|
||||
====================================
|
||||
Improve lvm_dump.sh robustness.
|
||||
Update lvm2create_initrd to support gentoo.
|
||||
|
||||
Version 2.02.15 - 21st November 2006
|
||||
====================================
|
||||
Fix clvmd_init_rhel4 line truncation (2.02.14).
|
||||
Install lvmdump by default.
|
||||
Fix check for snapshot module when activating snapshot.
|
||||
Fix pvremove error path for case when PV is in use.
|
||||
Warn if certain duplicate config file entries are seen.
|
||||
Enhance lvm_dump.sh for sysreport integration and add man page.
|
||||
Fix --autobackup argument which could never disable backups.
|
||||
Fix a label_verify error path.
|
||||
|
||||
Version 2.02.14 - 10th November 2006
|
||||
====================================
|
||||
Fix adjusted_mirror_region_size() to handle 64-bit size.
|
||||
Add some missing bounds checks on 32-bit extent counters.
|
||||
Add Petabyte and Exabyte support.
|
||||
Fix lvcreate error message when 0 extents requested.
|
||||
lvremove man page: volumes must be cluster inactive before being removed.
|
||||
Protect .cache manipulations with fcntl locking.
|
||||
Change .cache timestamp comparisons to use ctime.
|
||||
Fix mirror log LV writing to set all bits in whole LV.
|
||||
Fix clustered VG detection and default runlevels in clvmd_init_rhel4.
|
||||
Fix high-level free space check for partial allocations.
|
||||
|
||||
Version 2.02.13 - 27th October 2006
|
||||
===================================
|
||||
Add couple of missing files to tools/Makefile CLEAN_TARGETS.
|
||||
When adding snapshot leave cow LV mapped device active after zeroing.
|
||||
Fix a clvmd debug message.
|
||||
Add dev_flush() to set_lv().
|
||||
Add lvchange --resync.
|
||||
Perform high-level free space check before each allocation attempt.
|
||||
Don't allow a node to remove an LV that's exclusively active on anther node.
|
||||
Cope if same PV is included more than once in cmdline PE range list.
|
||||
Set PV size to current device size if it is found to be zero.
|
||||
Add segment parameter to target_present functions.
|
||||
|
||||
Version 2.02.12 - 16th October 2006
|
||||
===================================
|
||||
Fix pvdisplay to use vg_read() for non-orphans.
|
||||
Fall back to internal locking if external locking lib is missing or fails.
|
||||
Retain activation state after changing LV minor number with --force.
|
||||
Propagate clustered flag in vgsplit and require resizeable flag.
|
||||
|
||||
Version 2.02.11 - 12th October 2006
|
||||
===================================
|
||||
Add clvmd function to return the cluster name. not used by LVM yet.
|
||||
Add cling allocation policy.
|
||||
Change _check_contiguous() to use _for_each_pv().
|
||||
Extend _for_each_pv() to allow termination without error.
|
||||
Abstract _is_contiguous().
|
||||
Remove duplicated pv arg from _check_contiguous().
|
||||
Accept regionsize with lvconvert.
|
||||
Add report columns with underscore before field names ending 'size'.
|
||||
Correct regionsize default on lvcreate man page (MB).
|
||||
Fix clvmd bug that could cause it to die when a node with a long name crashed.
|
||||
Add device size to text metadata.
|
||||
Fix format_text mda_setup pv->size and pv_setup pe_count calculations.
|
||||
Fix _for_each_pv() for mirror with core log.
|
||||
Add lvm_dump.sh script to create a tarball of debugging info from a system.
|
||||
Capture error messages in clvmd and pass them back to the user.
|
||||
Remove unused #defines from filter-md.c.
|
||||
Make clvmd restart init script wait until clvmd has died before starting it.
|
||||
Add -R to clvmd which tells running clvmds to reload their device cache.
|
||||
Add LV column to reports listing kernel modules needed for activation.
|
||||
Show available fields if report given invalid field. (e.g. lvs -o list)
|
||||
Add timestamp functions with --disable-realtime configure option.
|
||||
Add %VG, %LV and %FREE suffices to lvcreate/lvresize --extents arg.
|
||||
Fix two potential NULL pointer derefs in error cases in vg_read().
|
||||
Separate --enable-cluster from locking lib options in lvmconf.sh.
|
||||
Add a missing comma in lvcreate man page.
|
||||
|
||||
Version 2.02.10 - 19th September 2006
|
||||
=====================================
|
||||
Fix lvconvert mirror change case detection logic.
|
||||
Fix mirror log detachment so it correctly becomes a standalone LV.
|
||||
Extend _check_contiguous() to detect single-area LVs.
|
||||
Include mirror log (untested) in _for_each_pv() processing.
|
||||
Use MIRROR_LOG_SIZE constant.
|
||||
|
||||
16
WHATS_NEW_DM
16
WHATS_NEW_DM
@@ -1,3 +1,19 @@
|
||||
Version 1.02.13 - 28 Nov 2006
|
||||
=============================
|
||||
Update dmsetup man page (setgeometry & message).
|
||||
Fix dmsetup free after getline with debug.
|
||||
Suppress encryption key in 'dmsetup table' output unless --showkeys supplied.
|
||||
|
||||
Version 1.02.12 - 13 Oct 2006
|
||||
=============================
|
||||
Avoid deptree attempting to suspend a device that's already suspended.
|
||||
|
||||
Version 1.02.11 - 12 Oct 2006
|
||||
==============================
|
||||
Add suspend noflush support.
|
||||
Add basic dmsetup loop support.
|
||||
Switch dmsetup to use dm_malloc and dm_free.
|
||||
|
||||
Version 1.02.10 - 19 Sep 2006
|
||||
=============================
|
||||
Add dm_snprintf(), dm_split_words() and dm_split_lvm_name() to libdevmapper.
|
||||
|
||||
111
configure
vendored
111
configure
vendored
@@ -310,7 +310,7 @@ ac_includes_default="\
|
||||
#endif"
|
||||
|
||||
ac_default_prefix=/usr
|
||||
ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os AWK CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S SET_MAKE RANLIB ac_ct_RANLIB CFLOW_CMD CSCOPE_CMD CPP EGREP ALLOCA LIBOBJS POW_LIB MSGFMT MODPROBE_CMD JOBS STATIC_LINK LVM1 POOL SNAPSHOTS MIRRORS OWNER GROUP COPTIMISE_FLAG CLDFLAGS CLDWHOLEARCHIVE CLDNOWHOLEARCHIVE LDDEPS LIB_SUFFIX LVM_VERSION LVM1_FALLBACK DEBUG DEVMAPPER HAVE_LIBDL HAVE_SELINUX CMDLIB LOCALEDIR CONFDIR STATICDIR INTL_PACKAGE INTL CLVMD CLUSTER FSADM DMEVENTD LTLIBOBJS'
|
||||
ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os AWK CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S SET_MAKE RANLIB ac_ct_RANLIB CFLOW_CMD CSCOPE_CMD CPP EGREP ALLOCA LIBOBJS POW_LIB MSGFMT MODPROBE_CMD JOBS STATIC_LINK LVM1 POOL SNAPSHOTS MIRRORS OWNER GROUP COPTIMISE_FLAG CLDFLAGS CLDWHOLEARCHIVE CLDNOWHOLEARCHIVE LDDEPS LIB_SUFFIX LVM_VERSION LVM1_FALLBACK DEBUG DEVMAPPER HAVE_LIBDL HAVE_SELINUX HAVE_REALTIME CMDLIB LOCALEDIR CONFDIR STATICDIR INTL_PACKAGE INTL CLVMD CLUSTER FSADM DMEVENTD LTLIBOBJS'
|
||||
ac_subst_files=''
|
||||
|
||||
# Initialize some variables set by options.
|
||||
@@ -853,6 +853,7 @@ Optional Features:
|
||||
statically. Default is dynamic linking
|
||||
--enable-readline Enable readline support
|
||||
--disable-selinux Disable selinux support
|
||||
--disable-realtime Disable realtime clock support
|
||||
--enable-debug Enable debugging
|
||||
--disable-devmapper Disable device-mapper interaction
|
||||
--disable-o_direct Disable O_DIRECT
|
||||
@@ -1459,6 +1460,7 @@ case "$host_os" in
|
||||
DEVMAPPER=yes
|
||||
ODIRECT=yes
|
||||
SELINUX=yes
|
||||
REALTIME=yes
|
||||
CLUSTER=internal
|
||||
FSADM=no ;;
|
||||
darwin*)
|
||||
@@ -1473,6 +1475,7 @@ case "$host_os" in
|
||||
DEVMAPPER=yes
|
||||
ODIRECT=no
|
||||
SELINUX=no
|
||||
REALTIME=no
|
||||
CLUSTER=none
|
||||
FSADM=no ;;
|
||||
esac
|
||||
@@ -7431,6 +7434,17 @@ fi;
|
||||
echo "$as_me:$LINENO: result: $SELINUX" >&5
|
||||
echo "${ECHO_T}$SELINUX" >&6
|
||||
|
||||
################################################################################
|
||||
echo "$as_me:$LINENO: checking whether to enable realtime support" >&5
|
||||
echo $ECHO_N "checking whether to enable realtime support... $ECHO_C" >&6
|
||||
# Check whether --enable-realtime or --disable-realtime was given.
|
||||
if test "${enable_realtime+set}" = set; then
|
||||
enableval="$enable_realtime"
|
||||
REALTIME=$enableval
|
||||
fi;
|
||||
echo "$as_me:$LINENO: result: $REALTIME" >&5
|
||||
echo "${ECHO_T}$REALTIME" >&6
|
||||
|
||||
################################################################################
|
||||
echo "$as_me:$LINENO: checking whether to build cluster LVM daemon" >&5
|
||||
echo $ECHO_N "checking whether to build cluster LVM daemon... $ECHO_C" >&6
|
||||
@@ -8420,6 +8434,96 @@ echo "$as_me: WARNING: Disabling selinux" >&2;}
|
||||
fi
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
if test x$REALTIME = xyes; then
|
||||
echo "$as_me:$LINENO: checking for clock_gettime function" >&5
|
||||
echo $ECHO_N "checking for clock_gettime function... $ECHO_C" >&6
|
||||
echo "$as_me:$LINENO: checking for clock_gettime in -lrt" >&5
|
||||
echo $ECHO_N "checking for clock_gettime in -lrt... $ECHO_C" >&6
|
||||
if test "${ac_cv_lib_rt_clock_gettime+set}" = set; then
|
||||
echo $ECHO_N "(cached) $ECHO_C" >&6
|
||||
else
|
||||
ac_check_lib_save_LIBS=$LIBS
|
||||
LIBS="-lrt $LIBS"
|
||||
cat >conftest.$ac_ext <<_ACEOF
|
||||
/* confdefs.h. */
|
||||
_ACEOF
|
||||
cat confdefs.h >>conftest.$ac_ext
|
||||
cat >>conftest.$ac_ext <<_ACEOF
|
||||
/* end confdefs.h. */
|
||||
|
||||
/* Override any gcc2 internal prototype to avoid an error. */
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
/* We use char because int might match the return type of a gcc2
|
||||
builtin and then its argument prototype would still apply. */
|
||||
char clock_gettime ();
|
||||
int
|
||||
main ()
|
||||
{
|
||||
clock_gettime ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
rm -f conftest.$ac_objext conftest$ac_exeext
|
||||
if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
|
||||
(eval $ac_link) 2>conftest.er1
|
||||
ac_status=$?
|
||||
grep -v '^ *+' conftest.er1 >conftest.err
|
||||
rm -f conftest.er1
|
||||
cat conftest.err >&5
|
||||
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||
(exit $ac_status); } &&
|
||||
{ ac_try='test -z "$ac_c_werror_flag"
|
||||
|| test ! -s conftest.err'
|
||||
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
|
||||
(eval $ac_try) 2>&5
|
||||
ac_status=$?
|
||||
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||
(exit $ac_status); }; } &&
|
||||
{ ac_try='test -s conftest$ac_exeext'
|
||||
{ (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
|
||||
(eval $ac_try) 2>&5
|
||||
ac_status=$?
|
||||
echo "$as_me:$LINENO: \$? = $ac_status" >&5
|
||||
(exit $ac_status); }; }; then
|
||||
ac_cv_lib_rt_clock_gettime=yes
|
||||
else
|
||||
echo "$as_me: failed program was:" >&5
|
||||
sed 's/^/| /' conftest.$ac_ext >&5
|
||||
|
||||
ac_cv_lib_rt_clock_gettime=no
|
||||
fi
|
||||
rm -f conftest.err conftest.$ac_objext \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
LIBS=$ac_check_lib_save_LIBS
|
||||
fi
|
||||
echo "$as_me:$LINENO: result: $ac_cv_lib_rt_clock_gettime" >&5
|
||||
echo "${ECHO_T}$ac_cv_lib_rt_clock_gettime" >&6
|
||||
if test $ac_cv_lib_rt_clock_gettime = yes; then
|
||||
HAVE_REALTIME=yes
|
||||
else
|
||||
HAVE_REALTIME=no
|
||||
fi
|
||||
|
||||
echo "$as_me:$LINENO: result: $HAVE_REALTIME" >&5
|
||||
echo "${ECHO_T}$HAVE_REALTIME" >&6
|
||||
|
||||
if test x$HAVE_REALTIME = xyes; then
|
||||
|
||||
cat >>confdefs.h <<\_ACEOF
|
||||
#define HAVE_REALTIME 1
|
||||
_ACEOF
|
||||
|
||||
LIBS="-lrt $LIBS"
|
||||
else
|
||||
{ echo "$as_me:$LINENO: WARNING: Disabling realtime clock" >&5
|
||||
echo "$as_me: WARNING: Disabling realtime clock" >&2;}
|
||||
fi
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
|
||||
for ac_header in getopt.h
|
||||
@@ -11095,10 +11199,11 @@ fi
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
################################################################################
|
||||
ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile dmeventd/Makefile dmeventd/mirror/Makefile doc/Makefile include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile lib/snapshot/Makefile man/Makefile po/Makefile tools/Makefile tools/version.h tools/fsadm/Makefile test/mm/Makefile test/device/Makefile test/format1/Makefile test/regex/Makefile test/filters/Makefile"
|
||||
ac_config_files="$ac_config_files Makefile make.tmpl daemons/Makefile daemons/clvmd/Makefile dmeventd/Makefile dmeventd/mirror/Makefile doc/Makefile include/Makefile lib/Makefile lib/format1/Makefile lib/format_pool/Makefile lib/locking/Makefile lib/mirror/Makefile lib/snapshot/Makefile man/Makefile po/Makefile scripts/Makefile tools/Makefile tools/version.h tools/fsadm/Makefile test/mm/Makefile test/device/Makefile test/format1/Makefile test/regex/Makefile test/filters/Makefile"
|
||||
cat >confcache <<\_ACEOF
|
||||
# This file is a shell script that caches the results of configure
|
||||
# tests run on this system so they can be shared between configure
|
||||
@@ -11640,6 +11745,7 @@ do
|
||||
"lib/snapshot/Makefile" ) CONFIG_FILES="$CONFIG_FILES lib/snapshot/Makefile" ;;
|
||||
"man/Makefile" ) CONFIG_FILES="$CONFIG_FILES man/Makefile" ;;
|
||||
"po/Makefile" ) CONFIG_FILES="$CONFIG_FILES po/Makefile" ;;
|
||||
"scripts/Makefile" ) CONFIG_FILES="$CONFIG_FILES scripts/Makefile" ;;
|
||||
"tools/Makefile" ) CONFIG_FILES="$CONFIG_FILES tools/Makefile" ;;
|
||||
"tools/version.h" ) CONFIG_FILES="$CONFIG_FILES tools/version.h" ;;
|
||||
"tools/fsadm/Makefile" ) CONFIG_FILES="$CONFIG_FILES tools/fsadm/Makefile" ;;
|
||||
@@ -11789,6 +11895,7 @@ s,@DEBUG@,$DEBUG,;t t
|
||||
s,@DEVMAPPER@,$DEVMAPPER,;t t
|
||||
s,@HAVE_LIBDL@,$HAVE_LIBDL,;t t
|
||||
s,@HAVE_SELINUX@,$HAVE_SELINUX,;t t
|
||||
s,@HAVE_REALTIME@,$HAVE_REALTIME,;t t
|
||||
s,@CMDLIB@,$CMDLIB,;t t
|
||||
s,@LOCALEDIR@,$LOCALEDIR,;t t
|
||||
s,@CONFDIR@,$CONFDIR,;t t
|
||||
|
||||
26
configure.in
26
configure.in
@@ -42,6 +42,7 @@ case "$host_os" in
|
||||
DEVMAPPER=yes
|
||||
ODIRECT=yes
|
||||
SELINUX=yes
|
||||
REALTIME=yes
|
||||
CLUSTER=internal
|
||||
FSADM=no ;;
|
||||
darwin*)
|
||||
@@ -56,6 +57,7 @@ case "$host_os" in
|
||||
DEVMAPPER=yes
|
||||
ODIRECT=no
|
||||
SELINUX=no
|
||||
REALTIME=no
|
||||
CLUSTER=none
|
||||
FSADM=no ;;
|
||||
esac
|
||||
@@ -282,6 +284,13 @@ AC_ARG_ENABLE(selinux, [ --disable-selinux Disable selinux support],
|
||||
SELINUX=$enableval)
|
||||
AC_MSG_RESULT($SELINUX)
|
||||
|
||||
################################################################################
|
||||
dnl -- Disable realtime clock support
|
||||
AC_MSG_CHECKING(whether to enable realtime support)
|
||||
AC_ARG_ENABLE(realtime, [ --disable-realtime Disable realtime clock support],
|
||||
REALTIME=$enableval)
|
||||
AC_MSG_RESULT($REALTIME)
|
||||
|
||||
################################################################################
|
||||
dnl -- Build cluster LVM daemon
|
||||
AC_MSG_CHECKING(whether to build cluster LVM daemon)
|
||||
@@ -449,6 +458,21 @@ if test x$SELINUX = xyes; then
|
||||
fi
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Check for realtime clock support
|
||||
if test x$REALTIME = xyes; then
|
||||
AC_MSG_CHECKING(for clock_gettime function)
|
||||
AC_CHECK_LIB(rt, clock_gettime, HAVE_REALTIME=yes, HAVE_REALTIME=no)
|
||||
AC_MSG_RESULT($HAVE_REALTIME)
|
||||
|
||||
if test x$HAVE_REALTIME = xyes; then
|
||||
AC_DEFINE([HAVE_REALTIME], 1, [Define to 1 to include support for realtime clock.])
|
||||
LIBS="-lrt $LIBS"
|
||||
else
|
||||
AC_MSG_WARN(Disabling realtime clock)
|
||||
fi
|
||||
fi
|
||||
|
||||
################################################################################
|
||||
dnl -- Check for getopt
|
||||
AC_CHECK_HEADERS(getopt.h, AC_DEFINE([HAVE_GETOPTLONG], 1, [Define to 1 to if getopt_long is available.]))
|
||||
@@ -578,6 +602,7 @@ AC_SUBST(DEBUG)
|
||||
AC_SUBST(DEVMAPPER)
|
||||
AC_SUBST(HAVE_LIBDL)
|
||||
AC_SUBST(HAVE_SELINUX)
|
||||
AC_SUBST(HAVE_REALTIME)
|
||||
AC_SUBST(CMDLIB)
|
||||
AC_SUBST(MSGFMT)
|
||||
AC_SUBST(LOCALEDIR)
|
||||
@@ -612,6 +637,7 @@ lib/mirror/Makefile \
|
||||
lib/snapshot/Makefile \
|
||||
man/Makefile \
|
||||
po/Makefile \
|
||||
scripts/Makefile \
|
||||
tools/Makefile \
|
||||
tools/version.h \
|
||||
tools/fsadm/Makefile \
|
||||
|
||||
@@ -19,6 +19,7 @@ SOURCES = \
|
||||
clvmd-command.c \
|
||||
clvmd.c \
|
||||
lvm-functions.c \
|
||||
refresh_clvmd.c \
|
||||
system-lv.c
|
||||
|
||||
ifeq ("@CLVMD@", "gulm")
|
||||
|
||||
@@ -63,4 +63,8 @@ static const char CLVMD_SOCKNAME[] = "\0clvmd";
|
||||
#define CLVMD_CMD_LOCK_LV 50
|
||||
#define CLVMD_CMD_LOCK_VG 51
|
||||
|
||||
/* Misc functions */
|
||||
#define CLVMD_CMD_REFRESH 40
|
||||
#define CLVMD_CMD_GET_CLUSTERNAME 41
|
||||
|
||||
#endif
|
||||
|
||||
@@ -172,7 +172,7 @@ static int _cluster_do_node_callback(struct local_client *client,
|
||||
this currently just means that a node has stopped listening on our port */
|
||||
static void event_callback(cman_handle_t handle, void *private, int reason, int arg)
|
||||
{
|
||||
char namebuf[MAX_CLUSTER_NAME_LEN];
|
||||
char namebuf[MAX_CLUSTER_MEMBER_NAME_LEN];
|
||||
|
||||
switch (reason) {
|
||||
case CMAN_REASON_PORTCLOSED:
|
||||
@@ -471,6 +471,18 @@ static int _sync_unlock(const char *resource /* UNUSED */, int lockid)
|
||||
|
||||
}
|
||||
|
||||
static int _get_cluster_name(char *buf, int buflen)
|
||||
{
|
||||
cman_cluster_t cluster_info;
|
||||
int status;
|
||||
|
||||
status = cman_get_cluster(c_handle, &cluster_info);
|
||||
if (!status) {
|
||||
strncpy(buf, cluster_info.ci_name, buflen);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static struct cluster_ops _cluster_cman_ops = {
|
||||
.cluster_init_completed = _cluster_init_completed,
|
||||
.cluster_send_message = _cluster_send_message,
|
||||
@@ -484,6 +496,7 @@ static struct cluster_ops _cluster_cman_ops = {
|
||||
.get_our_csid = _get_our_csid,
|
||||
.add_up_node = _add_up_node,
|
||||
.cluster_closedown = _cluster_closedown,
|
||||
.get_cluster_name = _get_cluster_name,
|
||||
.sync_lock = _sync_lock,
|
||||
.sync_unlock = _sync_unlock,
|
||||
};
|
||||
|
||||
@@ -75,6 +75,8 @@
|
||||
#include "clvmd.h"
|
||||
#include "libdlm.h"
|
||||
|
||||
extern struct cluster_ops *clops;
|
||||
|
||||
/* 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,
|
||||
@@ -117,11 +119,21 @@ int do_command(struct local_client *client, struct clvm_header *msg, int msglen,
|
||||
if (status == EIO) {
|
||||
*retlen =
|
||||
1 + snprintf(*buf, buflen,
|
||||
"Internal lvm error, check syslog");
|
||||
get_last_lvm_error());
|
||||
return EIO;
|
||||
}
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_REFRESH:
|
||||
do_refresh_cache();
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_GET_CLUSTERNAME:
|
||||
status = clops->get_cluster_name(*buf, buflen);
|
||||
if (!status)
|
||||
*retlen = strlen(*buf);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Won't get here because command is validated in pre_command */
|
||||
break;
|
||||
@@ -222,6 +234,10 @@ int do_pre_command(struct local_client *client)
|
||||
status = pre_lock_lv(lock_cmd, lock_flags, lockname);
|
||||
break;
|
||||
|
||||
case CLVMD_CMD_REFRESH:
|
||||
case CLVMD_CMD_GET_CLUSTERNAME:
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error("Unknown command %d received\n", header->cmd);
|
||||
status = EINVAL;
|
||||
|
||||
@@ -43,6 +43,8 @@ struct cluster_ops {
|
||||
void (*reread_config) (void);
|
||||
void (*cluster_closedown) (void);
|
||||
|
||||
int (*get_cluster_name)(char *buf, int buflen);
|
||||
|
||||
int (*sync_lock) (const char *resource, int mode, int flags, int *lockid);
|
||||
int (*sync_unlock) (const char *resource, int lockid);
|
||||
|
||||
|
||||
@@ -973,6 +973,12 @@ static int _cluster_send_message(void *buf, int msglen, char *csid, const char *
|
||||
return gulm_cluster_send_message(buf, msglen, csid, errtext);
|
||||
}
|
||||
|
||||
static int _get_cluster_name(char *buf, int buflen)
|
||||
{
|
||||
strncpy(buf, cluster_name, buflen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct cluster_ops _cluster_gulm_ops = {
|
||||
.cluster_init_completed = NULL,
|
||||
.cluster_send_message = _cluster_send_message,
|
||||
@@ -987,6 +993,7 @@ static struct cluster_ops _cluster_gulm_ops = {
|
||||
.add_up_node = gulm_add_up_node,
|
||||
.reread_config = _reread_config,
|
||||
.cluster_closedown = _cluster_closedown,
|
||||
.get_cluster_name = _get_cluster_name,
|
||||
.sync_lock = _sync_lock,
|
||||
.sync_unlock = _sync_unlock,
|
||||
};
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include "clvm.h"
|
||||
#include "version.h"
|
||||
#include "clvmd.h"
|
||||
#include "refresh_clvmd.h"
|
||||
#include "libdlm.h"
|
||||
#include "system-lv.h"
|
||||
#include "list.h"
|
||||
@@ -66,7 +67,7 @@ static struct local_client local_client_head;
|
||||
|
||||
static unsigned short global_xid = 0; /* Last transaction ID issued */
|
||||
|
||||
static struct cluster_ops *clops = NULL;
|
||||
struct cluster_ops *clops = NULL;
|
||||
|
||||
static char our_csid[MAX_CSID_LEN];
|
||||
static unsigned max_csid_len;
|
||||
@@ -143,6 +144,7 @@ static void usage(char *prog, FILE *file)
|
||||
fprintf(file, " -V Show version of clvmd\n");
|
||||
fprintf(file, " -h Show this help information\n");
|
||||
fprintf(file, " -d Don't fork, run in the foreground\n");
|
||||
fprintf(file, " -R Tell all running clvmds in the cluster to reload their device cache\n");
|
||||
fprintf(file, " -t<secs> Command timeout (default 60 seconds)\n");
|
||||
fprintf(file, "\n");
|
||||
}
|
||||
@@ -173,7 +175,7 @@ int main(int argc, char *argv[])
|
||||
/* Deal with command-line arguments */
|
||||
opterr = 0;
|
||||
optind = 0;
|
||||
while ((opt = getopt(argc, argv, "?vVhdt:")) != EOF) {
|
||||
while ((opt = getopt(argc, argv, "?vVhdt:R")) != EOF) {
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
usage(argv[0], stdout);
|
||||
@@ -183,6 +185,9 @@ int main(int argc, char *argv[])
|
||||
usage(argv[0], stderr);
|
||||
exit(0);
|
||||
|
||||
case 'R':
|
||||
return refresh_clvmd();
|
||||
|
||||
case 'd':
|
||||
debug++;
|
||||
break;
|
||||
@@ -1684,6 +1689,7 @@ static void *lvm_thread_fn(void *arg)
|
||||
}
|
||||
pthread_mutex_unlock(&lvm_thread_mutex);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Pass down some work to the LVM thread */
|
||||
|
||||
@@ -50,12 +50,18 @@
|
||||
static struct cmd_context *cmd = NULL;
|
||||
static struct dm_hash_table *lv_hash = NULL;
|
||||
static pthread_mutex_t lv_hash_lock;
|
||||
static char last_error[1024];
|
||||
|
||||
struct lv_info {
|
||||
int lock_id;
|
||||
int lock_mode;
|
||||
};
|
||||
|
||||
char *get_last_lvm_error()
|
||||
{
|
||||
return last_error;
|
||||
}
|
||||
|
||||
/* Return the mode a lock is currently held at (or -1 if not held) */
|
||||
static int get_current_lock(char *resource)
|
||||
{
|
||||
@@ -201,8 +207,17 @@ static int do_activate_lv(char *resource, unsigned char lock_flags, int mode)
|
||||
/* Try to get the lock if it's a clustered volume group */
|
||||
if (lock_flags & LCK_CLUSTER_VG) {
|
||||
status = hold_lock(resource, mode, LKF_NOQUEUE);
|
||||
if (status)
|
||||
if (status) {
|
||||
/* Return an LVM-sensible error for this.
|
||||
* Forcing EIO makes the upper level return this text
|
||||
* rather than the strerror text for EAGAIN.
|
||||
*/
|
||||
if (errno == EAGAIN) {
|
||||
sprintf(last_error, "Volume is busy on another node");
|
||||
errno = EIO;
|
||||
}
|
||||
return errno;
|
||||
}
|
||||
}
|
||||
|
||||
/* If it's suspended then resume it */
|
||||
@@ -228,7 +243,7 @@ static int do_resume_lv(char *resource)
|
||||
/* Is it open ? */
|
||||
oldmode = get_current_lock(resource);
|
||||
if (oldmode == -1) {
|
||||
DEBUGLOG("do_deactivate_lock, lock not already held\n");
|
||||
DEBUGLOG("do_resume_lv, lock not already held\n");
|
||||
return 0; /* We don't need to do anything */
|
||||
}
|
||||
|
||||
@@ -416,6 +431,13 @@ int do_check_lvm1(char *vgname)
|
||||
return status == 1 ? 0 : EBUSY;
|
||||
}
|
||||
|
||||
int do_refresh_cache()
|
||||
{
|
||||
DEBUGLOG("Refreshing context\n");
|
||||
log_notice("Refreshing context");
|
||||
return refresh_toolcontext(cmd)==1?0:-1;
|
||||
}
|
||||
|
||||
|
||||
/* Only called at gulm startup. Drop any leftover VG or P_orphan locks
|
||||
that might be hanging around if we died for any reason
|
||||
@@ -505,6 +527,20 @@ static void *get_initial_state()
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void lvm2_log_fn(int level, const char *file, int line,
|
||||
const char *message)
|
||||
{
|
||||
/*
|
||||
* Ignore non-error messages, but store the latest one for returning
|
||||
* to the user.
|
||||
*/
|
||||
if (level != _LOG_ERR && level != _LOG_FATAL)
|
||||
return;
|
||||
|
||||
strncpy(last_error, message, sizeof(last_error));
|
||||
last_error[sizeof(last_error)-1] = '\0';
|
||||
}
|
||||
|
||||
/* This checks some basic cluster-LVM configuration stuff */
|
||||
static void check_config()
|
||||
{
|
||||
@@ -557,5 +593,8 @@ int init_lvm(int using_gulm)
|
||||
|
||||
get_initial_state();
|
||||
|
||||
/* Trap log messages so we can pass them back to the user */
|
||||
init_log_fn(lvm2_log_fn);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -25,11 +25,13 @@ extern int do_lock_lv(unsigned char lock_cmd, unsigned char lock_flags,
|
||||
extern int post_lock_lv(unsigned char lock_cmd, unsigned char lock_flags,
|
||||
char *resource);
|
||||
extern int do_check_lvm1(char *vgname);
|
||||
extern int do_refresh_cache(void);
|
||||
extern int init_lvm(int using_gulm);
|
||||
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);
|
||||
extern char *get_last_lvm_error(void);
|
||||
|
||||
#endif
|
||||
|
||||
334
daemons/clvmd/refresh_clvmd.c
Normal file
334
daemons/clvmd/refresh_clvmd.c
Normal file
@@ -0,0 +1,334 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* Tell all clvmds in a cluster to refresh their toolcontext
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <libdevmapper.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "clvm.h"
|
||||
#include "refresh_clvmd.h"
|
||||
|
||||
typedef struct lvm_response {
|
||||
char node[255];
|
||||
char *response;
|
||||
int status;
|
||||
int len;
|
||||
} lvm_response_t;
|
||||
|
||||
/*
|
||||
* This gets stuck at the start of memory we allocate so we
|
||||
* can sanity-check it at deallocation time
|
||||
*/
|
||||
#define LVM_SIGNATURE 0x434C564D
|
||||
|
||||
static int _clvmd_sock = -1;
|
||||
|
||||
/* Open connection to the 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) {
|
||||
fprintf(stderr, "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;
|
||||
|
||||
fprintf(stderr, "connect() failed on local socket: %s\n",
|
||||
strerror(errno));
|
||||
if (close(local_socket))
|
||||
return -1;
|
||||
|
||||
errno = saved_errno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return local_socket;
|
||||
}
|
||||
|
||||
/* Send a request and return the status */
|
||||
static int _send_request(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;
|
||||
fprintf(stderr, "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;
|
||||
fprintf(stderr, "Error reading data from clvmd: %s", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
fprintf(stderr, "EOF reading CLVMD");
|
||||
errno = ENOTCONN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Allocate buffer */
|
||||
buflen = len + outheader->arglen;
|
||||
*retbuf = dm_malloc(buflen);
|
||||
if (!*retbuf) {
|
||||
errno = ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Copy the header */
|
||||
memcpy(*retbuf, outbuf, len);
|
||||
outheader = (struct clvm_header *) *retbuf;
|
||||
|
||||
/* Read the returned values */
|
||||
off = 1; /* we've already read the first byte */
|
||||
while (off <= outheader->arglen && len > 0) {
|
||||
len = read(_clvmd_sock, outheader->args + off,
|
||||
buflen - off - offsetof(struct clvm_header, args));
|
||||
if (len > 0)
|
||||
off += len;
|
||||
}
|
||||
|
||||
/* Was it an error ? */
|
||||
if (outheader->status != 0) {
|
||||
errno = outheader->status;
|
||||
|
||||
/* Only return an error here if there are no node-specific
|
||||
errors present in the message that might have more detail */
|
||||
if (!(outheader->flags & CLVMD_FLAG_NODEERRS)) {
|
||||
fprintf(stderr, "cluster request failed: %s\n", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Build the structure header and parse-out wildcard node names */
|
||||
static void _build_header(struct clvm_header *head, int cmd, const char *node,
|
||||
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 = dm_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;
|
||||
|
||||
memcpy(&rarray[i].status, inptr, sizeof(int));
|
||||
inptr += sizeof(int);
|
||||
|
||||
rarray[i].response = dm_malloc(strlen(inptr) + 1);
|
||||
if (rarray[i].response == NULL) {
|
||||
/* Free up everything else and return error */
|
||||
int j;
|
||||
for (j = 0; j < i; j++)
|
||||
dm_free(rarray[i].response);
|
||||
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)
|
||||
dm_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++) {
|
||||
dm_free(response[i].response);
|
||||
}
|
||||
|
||||
dm_free(ptr);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int refresh_clvmd()
|
||||
{
|
||||
int num_responses;
|
||||
char args[1]; // No args really.
|
||||
lvm_response_t *response;
|
||||
int saved_errno;
|
||||
int status;
|
||||
int i;
|
||||
|
||||
status = _cluster_request(CLVMD_CMD_REFRESH, "*", args, 0, &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) {
|
||||
fprintf(stderr, "clvmd not running on node %s",
|
||||
response[i].node);
|
||||
status = 0;
|
||||
errno = response[i].status;
|
||||
} else if (response[i].status) {
|
||||
fprintf(stderr, "Error resetting node %s: %s",
|
||||
response[i].node,
|
||||
response[i].response[0] ?
|
||||
response[i].response :
|
||||
strerror(response[i].status));
|
||||
status = 0;
|
||||
errno = response[i].status;
|
||||
}
|
||||
}
|
||||
|
||||
saved_errno = errno;
|
||||
_cluster_free_request(response);
|
||||
errno = saved_errno;
|
||||
|
||||
return status;
|
||||
}
|
||||
2
daemons/clvmd/refresh_clvmd.h
Normal file
2
daemons/clvmd/refresh_clvmd.h
Normal file
@@ -0,0 +1,2 @@
|
||||
int refresh_clvmd(void);
|
||||
|
||||
@@ -79,6 +79,7 @@ SOURCES =\
|
||||
misc/lvm-file.c \
|
||||
misc/lvm-string.c \
|
||||
misc/lvm-wrappers.c \
|
||||
misc/timestamp.c \
|
||||
mm/memlock.c \
|
||||
regex/matcher.c \
|
||||
regex/parse_rx.c \
|
||||
|
||||
@@ -51,6 +51,66 @@ int lvm1_present(struct cmd_context *cmd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int list_segment_modules(struct dm_pool *mem, const struct lv_segment *seg,
|
||||
struct list *modules)
|
||||
{
|
||||
unsigned int s;
|
||||
struct lv_segment *seg2, *snap_seg;
|
||||
struct list *snh;
|
||||
|
||||
if (seg->segtype->ops->modules_needed &&
|
||||
!seg->segtype->ops->modules_needed(mem, seg, modules)) {
|
||||
log_error("module string allocation failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lv_is_origin(seg->lv))
|
||||
list_iterate(snh, &seg->lv->snapshot_segs)
|
||||
if (!list_lv_modules(mem,
|
||||
list_struct_base(snh,
|
||||
struct lv_segment,
|
||||
origin_list)->cow,
|
||||
modules))
|
||||
return_0;
|
||||
|
||||
if (lv_is_cow(seg->lv)) {
|
||||
snap_seg = find_cow(seg->lv);
|
||||
if (snap_seg->segtype->ops->modules_needed &&
|
||||
!snap_seg->segtype->ops->modules_needed(mem, snap_seg,
|
||||
modules)) {
|
||||
log_error("snap_seg module string allocation failed");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
switch (seg_type(seg, s)) {
|
||||
case AREA_LV:
|
||||
seg2 = find_seg_by_le(seg_lv(seg, s), seg_le(seg, s));
|
||||
if (seg2 && !list_segment_modules(mem, seg2, modules))
|
||||
return_0;
|
||||
break;
|
||||
case AREA_PV:
|
||||
case AREA_UNASSIGNED:
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int list_lv_modules(struct dm_pool *mem, const struct logical_volume *lv,
|
||||
struct list *modules)
|
||||
{
|
||||
struct lv_segment *seg;
|
||||
|
||||
list_iterate_items(seg, &lv->segments)
|
||||
if (!list_segment_modules(mem, seg, modules))
|
||||
return_0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifndef DEVMAPPER_SUPPORT
|
||||
void set_activation(int act)
|
||||
{
|
||||
|
||||
@@ -39,6 +39,10 @@ int lvm1_present(struct cmd_context *cmd);
|
||||
int target_present(const char *target_name, int use_modprobe);
|
||||
int target_version(const char *target_name, uint32_t *maj,
|
||||
uint32_t *min, uint32_t *patchlevel);
|
||||
int list_segment_modules(struct dm_pool *mem, const struct lv_segment *seg,
|
||||
struct list *modules);
|
||||
int list_lv_modules(struct dm_pool *mem, const struct logical_volume *lv,
|
||||
struct list *modules);
|
||||
|
||||
void activation_release(void);
|
||||
void activation_exit(void);
|
||||
|
||||
@@ -782,12 +782,19 @@ static int _add_segment_to_dtree(struct dev_manager *dm,
|
||||
{
|
||||
uint32_t s;
|
||||
struct list *snh;
|
||||
struct lv_segment *seg_present;
|
||||
|
||||
/* Ensure required device-mapper targets are loaded */
|
||||
if (seg->segtype->ops->target_present &&
|
||||
!seg->segtype->ops->target_present()) {
|
||||
seg_present = find_cow(seg->lv) ? : seg;
|
||||
|
||||
log_debug("Checking kernel supports %s segment type for %s%s%s",
|
||||
seg_present->segtype->name, seg->lv->name,
|
||||
layer ? "-" : "", layer ? : "");
|
||||
|
||||
if (seg_present->segtype->ops->target_present &&
|
||||
!seg_present->segtype->ops->target_present(seg_present)) {
|
||||
log_error("Can't expand LV %s: %s target support missing "
|
||||
"from kernel?", seg->lv->name, seg->segtype->name);
|
||||
"from kernel?", seg->lv->name, seg_present->segtype->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -330,7 +330,7 @@ static int _load_config_file(struct cmd_context *cmd, const char *tag)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(cfl->cft = create_config_tree(config_file))) {
|
||||
if (!(cfl->cft = create_config_tree(config_file, 0))) {
|
||||
log_error("config_tree allocation failed");
|
||||
return 0;
|
||||
}
|
||||
@@ -370,7 +370,7 @@ 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))) {
|
||||
if (!(cmd->cft = create_config_tree(NULL, 0))) {
|
||||
log_error("Failed to create config tree");
|
||||
return 0;
|
||||
}
|
||||
@@ -408,7 +408,7 @@ static int _merge_config_files(struct cmd_context *cmd)
|
||||
|
||||
/* Replace temporary duplicate copy of lvm.conf */
|
||||
if (cmd->cft->root) {
|
||||
if (!(cmd->cft = create_config_tree(NULL))) {
|
||||
if (!(cmd->cft = create_config_tree(NULL, 0))) {
|
||||
log_error("Failed to create config tree");
|
||||
return 0;
|
||||
}
|
||||
@@ -609,8 +609,8 @@ static int _init_filters(struct cmd_context *cmd)
|
||||
cmd->dump_filter = 0;
|
||||
|
||||
if (!stat(dev_cache, &st) &&
|
||||
(st.st_mtime > config_file_timestamp(cmd->cft)) &&
|
||||
!persistent_filter_load(f4))
|
||||
(st.st_ctime != config_file_timestamp(cmd->cft)) &&
|
||||
!persistent_filter_load(f4, NULL))
|
||||
log_verbose("Failed to load existing device cache from %s",
|
||||
dev_cache);
|
||||
|
||||
|
||||
@@ -58,6 +58,8 @@ struct cs {
|
||||
time_t timestamp;
|
||||
char *filename;
|
||||
int exists;
|
||||
int keep_open;
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
static void _get_token(struct parser *p, int tok_prev);
|
||||
@@ -95,7 +97,7 @@ static int _tok_match(const char *str, const char *b, const char *e)
|
||||
/*
|
||||
* public interface
|
||||
*/
|
||||
struct config_tree *create_config_tree(const char *filename)
|
||||
struct config_tree *create_config_tree(const char *filename, int keep_open)
|
||||
{
|
||||
struct cs *c;
|
||||
struct dm_pool *mem = dm_pool_create("config", 10 * 1024);
|
||||
@@ -115,6 +117,8 @@ struct config_tree *create_config_tree(const char *filename)
|
||||
c->cft.root = (struct config_node *) NULL;
|
||||
c->timestamp = 0;
|
||||
c->exists = 0;
|
||||
c->keep_open = keep_open;
|
||||
c->dev = 0;
|
||||
if (filename)
|
||||
c->filename = dm_pool_strdup(c->mem, filename);
|
||||
return &c->cft;
|
||||
@@ -122,7 +126,12 @@ struct config_tree *create_config_tree(const char *filename)
|
||||
|
||||
void destroy_config_tree(struct config_tree *cft)
|
||||
{
|
||||
dm_pool_destroy(((struct cs *) cft)->mem);
|
||||
struct cs *c = (struct cs *) cft;
|
||||
|
||||
if (c->dev)
|
||||
dev_close(c->dev);
|
||||
|
||||
dm_pool_destroy(c->mem);
|
||||
}
|
||||
|
||||
static int _parse_config_file(struct parser *p, struct config_tree *cft)
|
||||
@@ -143,7 +152,7 @@ struct config_tree *create_config_tree_from_string(struct cmd_context *cmd,
|
||||
struct config_tree *cft;
|
||||
struct parser *p;
|
||||
|
||||
if (!(cft = create_config_tree(NULL)))
|
||||
if (!(cft = create_config_tree(NULL, 0)))
|
||||
return_NULL;
|
||||
|
||||
c = (struct cs *) cft;
|
||||
@@ -250,7 +259,6 @@ int read_config_file(struct config_tree *cft)
|
||||
{
|
||||
struct cs *c = (struct cs *) cft;
|
||||
struct stat info;
|
||||
struct device *dev;
|
||||
int r = 1;
|
||||
|
||||
if (stat(c->filename, &info)) {
|
||||
@@ -272,22 +280,23 @@ int read_config_file(struct config_tree *cft)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!(dev = dev_create_file(c->filename, NULL, NULL, 1))) {
|
||||
stack;
|
||||
return 0;
|
||||
if (!c->dev) {
|
||||
if (!(c->dev = dev_create_file(c->filename, NULL, NULL, 1)))
|
||||
return_0;
|
||||
|
||||
if (!dev_open_flags(c->dev, O_RDONLY, 0, 0))
|
||||
return_0;
|
||||
}
|
||||
|
||||
if (!dev_open_flags(dev, O_RDONLY, 0, 0)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = read_config_fd(cft, dev, 0, (size_t) info.st_size, 0, 0,
|
||||
r = read_config_fd(cft, c->dev, 0, (size_t) info.st_size, 0, 0,
|
||||
(checksum_fn_t) NULL, 0);
|
||||
|
||||
dev_close(dev);
|
||||
if (!c->keep_open) {
|
||||
dev_close(c->dev);
|
||||
c->dev = 0;
|
||||
}
|
||||
|
||||
c->timestamp = info.st_mtime;
|
||||
c->timestamp = info.st_ctime;
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -331,7 +340,7 @@ int config_file_changed(struct config_tree *cft)
|
||||
}
|
||||
|
||||
/* Unchanged? */
|
||||
if (c->timestamp == info.st_mtime)
|
||||
if (c->timestamp == info.st_ctime)
|
||||
return 0;
|
||||
|
||||
reload:
|
||||
@@ -763,6 +772,7 @@ static struct config_node *_find_config_node(const struct config_node *cn,
|
||||
const char *path)
|
||||
{
|
||||
const char *e;
|
||||
const struct config_node *cn_found = NULL;
|
||||
|
||||
while (cn) {
|
||||
/* trim any leading slashes */
|
||||
@@ -773,22 +783,30 @@ static struct config_node *_find_config_node(const struct config_node *cn,
|
||||
for (e = path; *e && (*e != sep); e++) ;
|
||||
|
||||
/* hunt for the node */
|
||||
cn_found = NULL;
|
||||
while (cn) {
|
||||
if (_tok_match(cn->key, path, e))
|
||||
break;
|
||||
if (_tok_match(cn->key, path, e)) {
|
||||
/* Inefficient */
|
||||
if (!cn_found)
|
||||
cn_found = cn;
|
||||
else
|
||||
log_error("WARNING: Ignoring duplicate"
|
||||
" config node: %s ("
|
||||
"seeking %s)", cn->key, path);
|
||||
}
|
||||
|
||||
cn = cn->sib;
|
||||
}
|
||||
|
||||
if (cn && *e)
|
||||
cn = cn->child;
|
||||
if (cn_found && *e)
|
||||
cn = cn_found->child;
|
||||
else
|
||||
break; /* don't move into the last node */
|
||||
|
||||
path = e;
|
||||
}
|
||||
|
||||
return (struct config_node *) cn;
|
||||
return (struct config_node *) cn_found;
|
||||
}
|
||||
|
||||
static struct config_node *_find_first_config_node(const struct config_node *cn1,
|
||||
|
||||
@@ -53,7 +53,7 @@ struct config_tree_list {
|
||||
struct config_tree *cft;
|
||||
};
|
||||
|
||||
struct config_tree *create_config_tree(const char *filename);
|
||||
struct config_tree *create_config_tree(const char *filename, int keep_open);
|
||||
struct config_tree *create_config_tree_from_string(struct cmd_context *cmd,
|
||||
const char *config_settings);
|
||||
void destroy_config_tree(struct config_tree *cft);
|
||||
|
||||
@@ -30,6 +30,7 @@ static struct {
|
||||
} _policies[] = {
|
||||
{
|
||||
ALLOC_CONTIGUOUS, "contiguous"}, {
|
||||
ALLOC_CLING, "cling"}, {
|
||||
ALLOC_NORMAL, "normal"}, {
|
||||
ALLOC_ANYWHERE, "anywhere"}, {
|
||||
ALLOC_INHERIT, "inherit"}
|
||||
@@ -81,6 +82,12 @@ uint64_t units_to_bytes(const char *units, char *unit_type)
|
||||
case 't':
|
||||
v *= KILO * KILO * KILO * KILO;
|
||||
break;
|
||||
case 'p':
|
||||
v *= KILO * KILO * KILO * KILO * KILO;
|
||||
break;
|
||||
case 'e':
|
||||
v *= KILO * KILO * KILO * KILO * KILO * KILO;
|
||||
break;
|
||||
#undef KILO
|
||||
#define KILO UINT64_C(1000)
|
||||
case 'K':
|
||||
@@ -95,6 +102,12 @@ uint64_t units_to_bytes(const char *units, char *unit_type)
|
||||
case 'T':
|
||||
v *= KILO * KILO * KILO * KILO;
|
||||
break;
|
||||
case 'P':
|
||||
v *= KILO * KILO * KILO * KILO * KILO;
|
||||
break;
|
||||
case 'E':
|
||||
v *= KILO * KILO * KILO * KILO * KILO * KILO;
|
||||
break;
|
||||
#undef KILO
|
||||
default:
|
||||
return 0;
|
||||
@@ -142,6 +155,8 @@ static const char *_display_size(struct cmd_context *cmd, uint64_t size, size_le
|
||||
uint64_t units = UINT64_C(1024);
|
||||
char *size_buf = NULL;
|
||||
const char *size_str[][3] = {
|
||||
{" Exabyte", " EB", "E"},
|
||||
{" Petabyte", " PB", "P"},
|
||||
{" Terabyte", " TB", "T"},
|
||||
{" Gigabyte", " GB", "G"},
|
||||
{" Megabyte", " MB", "M"},
|
||||
@@ -160,7 +175,7 @@ static const char *_display_size(struct cmd_context *cmd, uint64_t size, size_le
|
||||
|
||||
suffix = cmd->current_settings.suffix;
|
||||
|
||||
for (s = 0; s < 8; s++)
|
||||
for (s = 0; s < 10; s++)
|
||||
if (toupper((int) cmd->current_settings.unit_type) ==
|
||||
*size_str[s][2])
|
||||
break;
|
||||
@@ -170,7 +185,7 @@ static const char *_display_size(struct cmd_context *cmd, uint64_t size, size_le
|
||||
return size_buf;
|
||||
}
|
||||
|
||||
if (s < 8) {
|
||||
if (s < 10) {
|
||||
byte = cmd->current_settings.unit_factor;
|
||||
size *= UINT64_C(512);
|
||||
} else {
|
||||
@@ -180,7 +195,7 @@ static const char *_display_size(struct cmd_context *cmd, uint64_t size, size_le
|
||||
units = UINT64_C(1000);
|
||||
else
|
||||
units = UINT64_C(1024);
|
||||
byte = units * units * units;
|
||||
byte = units * units * units * units * units;
|
||||
s = 0;
|
||||
while (size_str[s] && size < byte)
|
||||
s++, byte /= units;
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "targets.h"
|
||||
#include "lvm-string.h"
|
||||
#include "activate.h"
|
||||
#include "str_list.h"
|
||||
|
||||
static const char *_errseg_name(const struct lv_segment *seg)
|
||||
{
|
||||
@@ -49,7 +50,7 @@ static int _errseg_add_target_line(struct dev_manager *dm __attribute((unused)),
|
||||
return dm_tree_node_add_error_target(node, len);
|
||||
}
|
||||
|
||||
static int _errseg_target_present(void)
|
||||
static int _errseg_target_present(const struct lv_segment *seg __attribute((unused)))
|
||||
{
|
||||
static int _errseg_checked = 0;
|
||||
static int _errseg_present = 0;
|
||||
@@ -64,6 +65,18 @@ static int _errseg_target_present(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
static int _errseg_modules_needed(struct dm_pool *mem,
|
||||
const struct lv_segment *seg,
|
||||
struct list *modules)
|
||||
{
|
||||
if (!str_list_add(mem, modules, "error")) {
|
||||
log_error("error module string list allocation failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _errseg_destroy(const struct segment_type *segtype)
|
||||
{
|
||||
dm_free((void *)segtype);
|
||||
@@ -76,6 +89,7 @@ static struct segtype_handler _error_ops = {
|
||||
.add_target_line = _errseg_add_target_line,
|
||||
.target_present = _errseg_target_present,
|
||||
#endif
|
||||
.modules_needed = _errseg_modules_needed,
|
||||
.destroy = _errseg_destroy,
|
||||
};
|
||||
|
||||
|
||||
@@ -18,14 +18,6 @@
|
||||
|
||||
#ifdef linux
|
||||
|
||||
/* Lifted from <linux/raid/md_p.h> because of difficulty including it */
|
||||
|
||||
#define MD_SB_MAGIC 0xa92b4efc
|
||||
#define MD_RESERVED_BYTES (64 * 1024)
|
||||
#define MD_RESERVED_SECTORS (MD_RESERVED_BYTES / 512)
|
||||
#define MD_NEW_SIZE_SECTORS(x) ((x & ~(MD_RESERVED_SECTORS - 1)) \
|
||||
- MD_RESERVED_SECTORS)
|
||||
|
||||
static int _ignore_md(struct dev_filter *f, struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "config.h"
|
||||
#include "dev-cache.h"
|
||||
#include "filter-persistent.h"
|
||||
#include "lvm-file.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
@@ -26,11 +27,12 @@ struct pfilter {
|
||||
char *file;
|
||||
struct dm_hash_table *devices;
|
||||
struct dev_filter *real;
|
||||
time_t ctime;
|
||||
};
|
||||
|
||||
/*
|
||||
* entries in the table can be in one of these
|
||||
* states.
|
||||
* The hash table holds one of these two states
|
||||
* against each entry.
|
||||
*/
|
||||
#define PF_BAD_DEVICE ((void *) 1)
|
||||
#define PF_GOOD_DEVICE ((void *) 2)
|
||||
@@ -93,22 +95,26 @@ static int _read_array(struct pfilter *pf, struct config_tree *cft,
|
||||
return 1;
|
||||
}
|
||||
|
||||
int persistent_filter_load(struct dev_filter *f)
|
||||
int persistent_filter_load(struct dev_filter *f, struct config_tree **cft_out)
|
||||
{
|
||||
struct pfilter *pf = (struct pfilter *) f->private;
|
||||
|
||||
int r = 0;
|
||||
struct config_tree *cft;
|
||||
struct stat info;
|
||||
int r = 0;
|
||||
|
||||
if (!(cft = create_config_tree(pf->file))) {
|
||||
stack;
|
||||
return 0;
|
||||
if (!stat(pf->file, &info))
|
||||
pf->ctime = info.st_ctime;
|
||||
else {
|
||||
log_very_verbose("%s: stat failed: %s", pf->file,
|
||||
strerror(errno));
|
||||
return_0;
|
||||
}
|
||||
|
||||
if (!read_config_file(cft)) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
if (!(cft = create_config_tree(pf->file, 1)))
|
||||
return_0;
|
||||
|
||||
if (!read_config_file(cft))
|
||||
goto_out;
|
||||
|
||||
_read_array(pf, cft, "persistent_filter_cache/valid_devices",
|
||||
PF_GOOD_DEVICE);
|
||||
@@ -126,7 +132,10 @@ int persistent_filter_load(struct dev_filter *f)
|
||||
log_very_verbose("Loaded persistent filter cache from %s", pf->file);
|
||||
|
||||
out:
|
||||
destroy_config_tree(cft);
|
||||
if (r && cft_out)
|
||||
*cft_out = cft;
|
||||
else
|
||||
destroy_config_tree(cft);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -163,8 +172,12 @@ static void _write_array(struct pfilter *pf, FILE *fp, const char *path,
|
||||
int persistent_filter_dump(struct dev_filter *f)
|
||||
{
|
||||
struct pfilter *pf = (struct pfilter *) f->private;
|
||||
|
||||
char *tmp_file;
|
||||
struct stat info, info2;
|
||||
struct config_tree *cft = NULL;
|
||||
FILE *fp;
|
||||
int lockfd;
|
||||
int r = 0;
|
||||
|
||||
if (!dm_hash_get_num_entries(pf->devices)) {
|
||||
log_very_verbose("Internal persistent device cache empty "
|
||||
@@ -179,11 +192,43 @@ int persistent_filter_dump(struct dev_filter *f)
|
||||
|
||||
log_very_verbose("Dumping persistent device cache to %s", pf->file);
|
||||
|
||||
fp = fopen(pf->file, "w");
|
||||
if (!fp) {
|
||||
if (errno != EROFS)
|
||||
log_sys_error("fopen", pf->file);
|
||||
return 0;
|
||||
while (1) {
|
||||
if ((lockfd = fcntl_lock_file(pf->file, F_WRLCK, 0)) < 0)
|
||||
return_0;
|
||||
|
||||
/*
|
||||
* Ensure we locked the file we expected
|
||||
*/
|
||||
if (fstat(lockfd, &info)) {
|
||||
log_sys_error("fstat", pf->file);
|
||||
goto out;
|
||||
}
|
||||
if (stat(pf->file, &info2)) {
|
||||
log_sys_error("stat", pf->file);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!memcmp(&info.st_ino, &info2.st_ino, sizeof(ino_t)))
|
||||
break;
|
||||
|
||||
fcntl_unlock_file(lockfd);
|
||||
}
|
||||
|
||||
/*
|
||||
* If file contents changed since we loaded it, merge new contents
|
||||
*/
|
||||
if (info.st_ctime != pf->ctime)
|
||||
/* Keep cft open to avoid losing lock */
|
||||
persistent_filter_load(f, &cft);
|
||||
|
||||
tmp_file = alloca(strlen(pf->file) + 5);
|
||||
sprintf(tmp_file, "%s.tmp", pf->file);
|
||||
|
||||
if (!(fp = fopen(tmp_file, "w"))) {
|
||||
/* EACCES has been reported over NFS */
|
||||
if (errno != EROFS && errno != EACCES)
|
||||
log_sys_error("fopen", tmp_file);
|
||||
goto out;
|
||||
}
|
||||
|
||||
fprintf(fp, "# This file is automatically maintained by lvm.\n\n");
|
||||
@@ -195,7 +240,20 @@ int persistent_filter_dump(struct dev_filter *f)
|
||||
|
||||
fprintf(fp, "}\n");
|
||||
fclose(fp);
|
||||
return 1;
|
||||
|
||||
if (rename(tmp_file, pf->file))
|
||||
log_error("%s: rename to %s failed: %s", tmp_file, pf->file,
|
||||
strerror(errno));
|
||||
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
fcntl_unlock_file(lockfd);
|
||||
|
||||
if (cft)
|
||||
destroy_config_tree(cft);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _lookup_p(struct dev_filter *f, struct device *dev)
|
||||
|
||||
@@ -22,7 +22,7 @@ struct dev_filter *persistent_filter_create(struct dev_filter *f,
|
||||
const char *file);
|
||||
|
||||
int persistent_filter_wipe(struct dev_filter *f);
|
||||
int persistent_filter_load(struct dev_filter *f);
|
||||
int persistent_filter_load(struct dev_filter *f, struct config_tree **cft_out);
|
||||
int persistent_filter_dump(struct dev_filter *f);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -203,8 +203,8 @@ int write_disks(const struct format_type *fmt, struct list *pvds);
|
||||
* Functions to translate to between disk and in
|
||||
* core structures.
|
||||
*/
|
||||
int import_pv(struct dm_pool *mem, struct device *dev,
|
||||
struct volume_group *vg,
|
||||
int import_pv(const struct format_type *fmt, struct dm_pool *mem,
|
||||
struct device *dev, struct volume_group *vg,
|
||||
struct physical_volume *pv, struct pv_disk *pvd,
|
||||
struct vg_disk *vgd);
|
||||
int export_pv(struct cmd_context *cmd, struct dm_pool *mem,
|
||||
|
||||
@@ -312,7 +312,7 @@ static int _format1_pv_read(const struct format_type *fmt, const char *pv_name,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!import_pv(fmt->cmd->mem, dl->dev, NULL, pv, &dl->pvd, &dl->vgd)) {
|
||||
if (!import_pv(fmt, fmt->cmd->mem, dl->dev, NULL, pv, &dl->pvd, &dl->vgd)) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "toolcontext.h"
|
||||
#include "segtype.h"
|
||||
#include "pv_alloc.h"
|
||||
#include "display.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
@@ -47,11 +48,13 @@ static char *_create_lv_name(struct dm_pool *mem, const char *full_name)
|
||||
return dm_pool_strdup(mem, ptr);
|
||||
}
|
||||
|
||||
int import_pv(struct dm_pool *mem, struct device *dev,
|
||||
struct volume_group *vg,
|
||||
int import_pv(const struct format_type *fmt, struct dm_pool *mem,
|
||||
struct device *dev, struct volume_group *vg,
|
||||
struct physical_volume *pv, struct pv_disk *pvd,
|
||||
struct vg_disk *vgd)
|
||||
{
|
||||
uint64_t size;
|
||||
|
||||
memset(pv, 0, sizeof(*pv));
|
||||
memcpy(&pv->id, pvd->pv_uuid, ID_LEN);
|
||||
|
||||
@@ -89,6 +92,25 @@ int import_pv(struct dm_pool *mem, struct device *dev,
|
||||
pv->pe_count = pvd->pe_total;
|
||||
pv->pe_alloc_count = 0;
|
||||
|
||||
/* Fix up pv size if missing */
|
||||
if (!pv->size) {
|
||||
if (!dev_get_size(dev, &pv->size)) {
|
||||
log_error("%s: Couldn't get size.", dev_name(pv->dev));
|
||||
return 0;
|
||||
}
|
||||
log_verbose("Fixing up missing format1 size (%s) "
|
||||
"for PV %s", display_size(fmt->cmd, pv->size),
|
||||
dev_name(pv->dev));
|
||||
if (vg) {
|
||||
size = pv->pe_count * (uint64_t) vg->extent_size +
|
||||
pv->pe_start;
|
||||
if (size > pv->size)
|
||||
log_error("WARNING: Physical Volume %s is too "
|
||||
"large for underlying device",
|
||||
dev_name(pv->dev));
|
||||
}
|
||||
}
|
||||
|
||||
list_init(&pv->tags);
|
||||
list_init(&pv->segments);
|
||||
|
||||
@@ -427,7 +449,7 @@ int import_pvs(const struct format_type *fmt, struct dm_pool *mem,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!import_pv(mem, dl->dev, vg, pvl->pv, &dl->pvd, &dl->vgd)) {
|
||||
if (!import_pv(fmt, mem, dl->dev, vg, pvl->pv, &dl->pvd, &dl->vgd)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -221,6 +221,8 @@ static int _sectors_to_units(uint64_t sectors, char *buffer, size_t s)
|
||||
"Megabytes",
|
||||
"Gigabytes",
|
||||
"Terabytes",
|
||||
"Petabytes",
|
||||
"Exabytes",
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -409,6 +411,11 @@ static int _print_pvs(struct formatter *f, struct volume_group *vg)
|
||||
outf(f, "tags = %s", buffer);
|
||||
}
|
||||
|
||||
if (!out_size(f, pv->size, "dev_size = %" PRIu64, pv->size)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
outf(f, "pe_start = %" PRIu64, pv->pe_start);
|
||||
if (!out_size(f, vg->extent_size * (uint64_t) pv->pe_count,
|
||||
"pe_count = %u", pv->pe_count)) {
|
||||
|
||||
@@ -1007,11 +1007,8 @@ static int _mda_setup(const struct format_type *fmt,
|
||||
uint64_t wipe_size = 8 << SECTOR_SHIFT;
|
||||
size_t pagesize = lvm_getpagesize();
|
||||
|
||||
if (!pvmetadatacopies) {
|
||||
/* Space available for PEs */
|
||||
pv->size -= pe_align();
|
||||
if (!pvmetadatacopies)
|
||||
return 1;
|
||||
}
|
||||
|
||||
alignment = pe_align() << SECTOR_SHIFT;
|
||||
disk_size = pv->size << SECTOR_SHIFT;
|
||||
@@ -1027,9 +1024,6 @@ static int _mda_setup(const struct format_type *fmt,
|
||||
/* Requested metadatasize */
|
||||
mda_size1 = pvmetadatasize << SECTOR_SHIFT;
|
||||
|
||||
/* Space available for PEs (before any mdas created) */
|
||||
pv->size -= LABEL_SCAN_SECTORS;
|
||||
|
||||
/* Place mda straight after label area at start of disk */
|
||||
start1 = LABEL_SCAN_SIZE;
|
||||
|
||||
@@ -1037,11 +1031,8 @@ static int _mda_setup(const struct format_type *fmt,
|
||||
if ((!pe_start && !pe_end) ||
|
||||
((pe_start > start1) && (pe_start - start1 >= MDA_SIZE_MIN))) {
|
||||
mda_adjustment = start1 % pagesize;
|
||||
if (mda_adjustment) {
|
||||
if (mda_adjustment)
|
||||
start1 += (pagesize - mda_adjustment);
|
||||
pv->size -= ((pagesize - mda_adjustment) >>
|
||||
SECTOR_SHIFT);
|
||||
}
|
||||
}
|
||||
|
||||
/* Ensure it's not going to be bigger than the disk! */
|
||||
@@ -1071,7 +1062,8 @@ static int _mda_setup(const struct format_type *fmt,
|
||||
/* FIXME If creating new mdas, wipe them! */
|
||||
if (mda_size1) {
|
||||
if (!add_mda(fmt, fmt->cmd->mem, mdas, pv->dev, start1,
|
||||
mda_size1)) return 0;
|
||||
mda_size1))
|
||||
return 0;
|
||||
|
||||
if (!dev_set((struct device *) pv->dev, start1,
|
||||
(size_t) (mda_size1 >
|
||||
@@ -1080,7 +1072,6 @@ static int _mda_setup(const struct format_type *fmt,
|
||||
return 0;
|
||||
}
|
||||
|
||||
pv->size -= mda_size1 >> SECTOR_SHIFT;
|
||||
if (pvmetadatacopies == 1)
|
||||
return 1;
|
||||
} else
|
||||
@@ -1125,7 +1116,6 @@ static int _mda_setup(const struct format_type *fmt,
|
||||
log_error("Failed to wipe new metadata area");
|
||||
return 0;
|
||||
}
|
||||
pv->size -= mda_size2 >> SECTOR_SHIFT;
|
||||
} else
|
||||
return 0;
|
||||
|
||||
@@ -1416,8 +1406,9 @@ static int _text_pv_setup(const struct format_type *fmt,
|
||||
struct lvmcache_info *info;
|
||||
int found;
|
||||
uint64_t pe_end = 0;
|
||||
|
||||
/* FIXME if vg, adjust start/end of pe area to avoid mdas! */
|
||||
unsigned mda_count = 0;
|
||||
uint64_t mda_size2 = 0;
|
||||
uint64_t pe_count;
|
||||
|
||||
/* FIXME Cope with pvchange */
|
||||
/* FIXME Merge code with _text_create_text_instance */
|
||||
@@ -1428,11 +1419,16 @@ static int _text_pv_setup(const struct format_type *fmt,
|
||||
if ((info = info_from_pvid(pv->dev->pvid))) {
|
||||
pvmdas = &info->mdas;
|
||||
list_iterate_items(mda, pvmdas) {
|
||||
mda_count++;
|
||||
mdac =
|
||||
(struct mda_context *) mda->metadata_locn;
|
||||
|
||||
/* FIXME Check it isn't already in use */
|
||||
|
||||
/* Reduce usable device size */
|
||||
if (mda_count > 1)
|
||||
mda_size2 = mdac->area.size >> SECTOR_SHIFT;
|
||||
|
||||
/* Ensure it isn't already on list */
|
||||
found = 0;
|
||||
list_iterate_items(mda2, mdas) {
|
||||
@@ -1470,6 +1466,26 @@ static int _text_pv_setup(const struct format_type *fmt,
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME Cope with genuine pe_count 0 */
|
||||
|
||||
/* If missing, estimate pv->size from file-based metadata */
|
||||
if (!pv->size && pv->pe_count)
|
||||
pv->size = pv->pe_count * (uint64_t) vg->extent_size +
|
||||
pv->pe_start + mda_size2;
|
||||
|
||||
/* Recalculate number of extents that will fit */
|
||||
if (!pv->pe_count) {
|
||||
pe_count = (pv->size - pv->pe_start - mda_size2) /
|
||||
vg->extent_size;
|
||||
if (pe_count > UINT32_MAX) {
|
||||
log_error("PV %s too large for extent size %s.",
|
||||
dev_name(pv->dev),
|
||||
display_size(vg->cmd, (uint64_t) vg->extent_size));
|
||||
return 0;
|
||||
}
|
||||
pv->pe_count = (uint32_t) pe_count;
|
||||
}
|
||||
|
||||
/* Unlike LVM1, we don't store this outside a VG */
|
||||
/* FIXME Default from config file? vgextend cmdline flag? */
|
||||
pv->status |= ALLOCATABLE_PV;
|
||||
|
||||
@@ -43,7 +43,7 @@ const char *text_vgname_import(const struct format_type *fmt,
|
||||
_text_import_initialised = 1;
|
||||
}
|
||||
|
||||
if (!(cft = create_config_tree(NULL)))
|
||||
if (!(cft = create_config_tree(NULL, 0)))
|
||||
return_NULL;
|
||||
|
||||
if ((!dev && !read_config_file(cft)) ||
|
||||
@@ -94,7 +94,7 @@ struct volume_group *text_vg_import_fd(struct format_instance *fid,
|
||||
*desc = NULL;
|
||||
*when = 0;
|
||||
|
||||
if (!(cft = create_config_tree(file)))
|
||||
if (!(cft = create_config_tree(file, 0)))
|
||||
return_NULL;
|
||||
|
||||
if ((!dev && !read_config_file(cft)) ||
|
||||
|
||||
@@ -116,6 +116,7 @@ static int _read_pv(struct format_instance *fid, struct dm_pool *mem,
|
||||
struct physical_volume *pv;
|
||||
struct pv_list *pvl;
|
||||
struct config_node *cn;
|
||||
uint64_t size;
|
||||
|
||||
if (!(pvl = dm_pool_zalloc(mem, sizeof(*pvl))) ||
|
||||
!(pvl->pv = dm_pool_zalloc(mem, sizeof(*pvl->pv)))) {
|
||||
@@ -179,6 +180,9 @@ static int _read_pv(struct format_instance *fid, struct dm_pool *mem,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Late addition */
|
||||
_read_int64(pvn, "dev_size", &pv->size);
|
||||
|
||||
if (!_read_int64(pvn, "pe_start", &pv->pe_start)) {
|
||||
log_error("Couldn't read extent size for volume group.");
|
||||
return 0;
|
||||
@@ -206,10 +210,29 @@ static int _read_pv(struct format_instance *fid, struct dm_pool *mem,
|
||||
vg->free_count += pv->pe_count;
|
||||
|
||||
pv->pe_size = vg->extent_size;
|
||||
pv->size = vg->extent_size * (uint64_t) pv->pe_count;
|
||||
|
||||
pv->pe_alloc_count = 0;
|
||||
pv->fmt = fid->fmt;
|
||||
|
||||
/* Fix up pv size if missing */
|
||||
if (!pv->size && pv->dev) {
|
||||
if (!dev_get_size(pv->dev, &pv->size)) {
|
||||
log_error("%s: Couldn't get size.", dev_name(pv->dev));
|
||||
return 0;
|
||||
}
|
||||
log_verbose("Fixing up missing format1 size (%s) "
|
||||
"for PV %s", display_size(fid->fmt->cmd, pv->size),
|
||||
dev_name(pv->dev));
|
||||
if (vg) {
|
||||
size = pv->pe_count * (uint64_t) vg->extent_size +
|
||||
pv->pe_start;
|
||||
if (size > pv->size)
|
||||
log_error("WARNING: Physical Volume %s is too "
|
||||
"large for underlying device",
|
||||
dev_name(pv->dev));
|
||||
}
|
||||
}
|
||||
|
||||
if (!alloc_pv_segment_whole_pv(mem, pv)) {
|
||||
stack;
|
||||
return 0;
|
||||
|
||||
@@ -347,13 +347,11 @@ int label_verify(struct device *dev)
|
||||
int r = 0;
|
||||
|
||||
if (!dev_open(dev)) {
|
||||
stack;
|
||||
|
||||
if ((info = info_from_pvid(dev->pvid)))
|
||||
lvmcache_update_vgname_and_id(info, ORPHAN, ORPHAN,
|
||||
0, NULL);
|
||||
|
||||
goto out;
|
||||
return_0;
|
||||
}
|
||||
|
||||
if (!(l = _find_labeller(dev, buf, §or)))
|
||||
|
||||
@@ -144,18 +144,18 @@ int init_locking(int type, struct cmd_context *cmd)
|
||||
case 2:
|
||||
if (!cmd->is_static) {
|
||||
log_very_verbose("External locking selected.");
|
||||
if (!init_external_locking(&_locking, cmd))
|
||||
break;
|
||||
return 1;
|
||||
if (init_external_locking(&_locking, cmd))
|
||||
return 1;
|
||||
}
|
||||
if (!find_config_tree_int(cmd, "locking/fallback_to_clustered_locking",
|
||||
DEFAULT_FALLBACK_TO_CLUSTERED_LOCKING))
|
||||
break;
|
||||
log_very_verbose("Falling back to clustered locking.");
|
||||
/* Fall through */
|
||||
#endif
|
||||
|
||||
#ifdef CLUSTER_LOCKING_INTERNAL
|
||||
log_very_verbose("Falling back to internal clustered locking.");
|
||||
/* Fall through */
|
||||
|
||||
case 3:
|
||||
log_very_verbose("Cluster locking selected.");
|
||||
if (!init_cluster_locking(&_locking, cmd))
|
||||
|
||||
@@ -398,6 +398,7 @@ struct alloced_area {
|
||||
* Details of an allocation attempt
|
||||
*/
|
||||
struct alloc_handle {
|
||||
struct cmd_context *cmd;
|
||||
struct dm_pool *mem;
|
||||
|
||||
alloc_policy_t alloc; /* Overall policy */
|
||||
@@ -417,7 +418,8 @@ struct alloc_handle {
|
||||
/*
|
||||
* Preparation for a specific allocation attempt
|
||||
*/
|
||||
static struct alloc_handle *_alloc_init(struct dm_pool *mem,
|
||||
static struct alloc_handle *_alloc_init(struct cmd_context *cmd,
|
||||
struct dm_pool *mem,
|
||||
const struct segment_type *segtype,
|
||||
alloc_policy_t alloc,
|
||||
uint32_t mirrors,
|
||||
@@ -464,6 +466,8 @@ static struct alloc_handle *_alloc_init(struct dm_pool *mem,
|
||||
if (segtype_is_virtual(segtype))
|
||||
return ah;
|
||||
|
||||
ah->cmd = cmd;
|
||||
|
||||
if (!(ah->mem = dm_pool_create("allocation", 1024))) {
|
||||
log_error("allocation pool creation failed");
|
||||
return NULL;
|
||||
@@ -666,6 +670,82 @@ static int _alloc_parallel_area(struct alloc_handle *ah, uint32_t needed,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Call fn for each AREA_PV used by the LV segment at lv:le of length *max_seg_len.
|
||||
* If any constituent area contains more than one segment, max_seg_len is
|
||||
* reduced to cover only the first.
|
||||
* fn should return 0 on error, 1 to continue scanning or >1 to terminate without error.
|
||||
* In the last case, this function passes on the return code.
|
||||
*/
|
||||
static int _for_each_pv(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
uint32_t le, uint32_t len, uint32_t *max_seg_len,
|
||||
uint32_t first_area, uint32_t max_areas,
|
||||
int top_level_area_index,
|
||||
int only_single_area_segments,
|
||||
int (*fn)(struct cmd_context *cmd,
|
||||
struct pv_segment *peg, uint32_t s,
|
||||
void *data),
|
||||
void *data)
|
||||
{
|
||||
struct lv_segment *seg;
|
||||
uint32_t s;
|
||||
uint32_t remaining_seg_len, area_len, area_multiple;
|
||||
int r = 1;
|
||||
|
||||
if (!(seg = find_seg_by_le(lv, le))) {
|
||||
log_error("Failed to find segment for %s extent %" PRIu32,
|
||||
lv->name, le);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Remaining logical length of segment */
|
||||
remaining_seg_len = seg->len - (le - seg->le);
|
||||
|
||||
if (remaining_seg_len > len)
|
||||
remaining_seg_len = len;
|
||||
|
||||
if (max_seg_len && *max_seg_len > remaining_seg_len)
|
||||
*max_seg_len = remaining_seg_len;
|
||||
|
||||
area_multiple = segtype_is_striped(seg->segtype) ? seg->area_count : 1;
|
||||
area_len = remaining_seg_len / area_multiple ? : 1;
|
||||
|
||||
for (s = first_area;
|
||||
s < seg->area_count && (!max_areas || s <= max_areas);
|
||||
s++) {
|
||||
if (seg_type(seg, s) == AREA_LV) {
|
||||
if (!(r = _for_each_pv(cmd, seg_lv(seg, s),
|
||||
seg_le(seg, s) +
|
||||
(le - seg->le) / area_multiple,
|
||||
area_len, max_seg_len,
|
||||
only_single_area_segments ? 0 : 0,
|
||||
only_single_area_segments ? 1 : 0,
|
||||
top_level_area_index != -1 ? top_level_area_index : s,
|
||||
only_single_area_segments, fn,
|
||||
data)))
|
||||
stack;
|
||||
} else if (seg_type(seg, s) == AREA_PV)
|
||||
if (!(r = fn(cmd, seg_pvseg(seg, s), top_level_area_index != -1 ? top_level_area_index : s, data)))
|
||||
stack;
|
||||
if (r != 1)
|
||||
return r;
|
||||
}
|
||||
|
||||
/* FIXME only_single_area_segments used as workaround to skip log LV - needs new param? */
|
||||
if (!only_single_area_segments && seg_is_mirrored(seg) && seg->log_lv) {
|
||||
if (!(r = _for_each_pv(cmd, seg->log_lv, 0, MIRROR_LOG_SIZE,
|
||||
NULL, 0, 0, 0, only_single_area_segments,
|
||||
fn, data)))
|
||||
stack;
|
||||
if (r != 1)
|
||||
return r;
|
||||
}
|
||||
|
||||
/* FIXME Add snapshot cow LVs etc. */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _comp_area(const void *l, const void *r)
|
||||
{
|
||||
const struct pv_area *lhs = *((const struct pv_area **) l);
|
||||
@@ -680,40 +760,114 @@ static int _comp_area(const void *l, const void *r)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Search for pvseg that matches condition
|
||||
*/
|
||||
struct pv_match {
|
||||
int (*condition)(struct pv_segment *pvseg, struct pv_area *pva);
|
||||
|
||||
struct pv_area **areas;
|
||||
struct pv_area *pva;
|
||||
uint32_t areas_size;
|
||||
int s; /* Area index of match */
|
||||
};
|
||||
|
||||
/*
|
||||
* Is PV area on the same PV?
|
||||
*/
|
||||
static int _is_same_pv(struct pv_segment *pvseg, struct pv_area *pva)
|
||||
{
|
||||
if (pvseg->pv != pva->map->pv)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Is PV area contiguous to PV segment?
|
||||
*/
|
||||
static int _is_contiguous(struct pv_segment *pvseg, struct pv_area *pva)
|
||||
{
|
||||
if (pvseg->pv != pva->map->pv)
|
||||
return 0;
|
||||
|
||||
if (pvseg->pe + pvseg->len != pva->start)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _is_condition(struct cmd_context *cmd,
|
||||
struct pv_segment *pvseg, uint32_t s,
|
||||
void *data)
|
||||
{
|
||||
struct pv_match *pvmatch = data;
|
||||
|
||||
if (!pvmatch->condition(pvseg, pvmatch->pva))
|
||||
return 1; /* Continue */
|
||||
|
||||
if (s >= pvmatch->areas_size)
|
||||
return 1;
|
||||
|
||||
pvmatch->areas[s] = pvmatch->pva;
|
||||
|
||||
return 2; /* Finished */
|
||||
}
|
||||
|
||||
/*
|
||||
* Is pva on same PV as any existing areas?
|
||||
*/
|
||||
static int _check_cling(struct cmd_context *cmd,
|
||||
struct lv_segment *prev_lvseg, struct pv_area *pva,
|
||||
struct pv_area **areas, uint32_t areas_size)
|
||||
{
|
||||
struct pv_match pvmatch;
|
||||
int r;
|
||||
|
||||
pvmatch.condition = _is_same_pv;
|
||||
pvmatch.areas = areas;
|
||||
pvmatch.areas_size = areas_size;
|
||||
pvmatch.pva = pva;
|
||||
|
||||
/* FIXME Cope with stacks by flattening */
|
||||
if (!(r = _for_each_pv(cmd, prev_lvseg->lv,
|
||||
prev_lvseg->le + prev_lvseg->len - 1, 1, NULL,
|
||||
0, 0, -1, 1,
|
||||
_is_condition, &pvmatch)))
|
||||
stack;
|
||||
|
||||
if (r != 2)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Is pva contiguous to any existing areas or on the same PV?
|
||||
*/
|
||||
static int _check_contiguous(struct lv_segment *prev_lvseg,
|
||||
struct physical_volume *pv, struct pv_area *pva,
|
||||
static int _check_contiguous(struct cmd_context *cmd,
|
||||
struct lv_segment *prev_lvseg, struct pv_area *pva,
|
||||
struct pv_area **areas, uint32_t areas_size)
|
||||
{
|
||||
struct pv_segment *prev_pvseg;
|
||||
struct lv_segment *lastseg;
|
||||
uint32_t s;
|
||||
struct pv_match pvmatch;
|
||||
int r;
|
||||
|
||||
for (s = 0; s < prev_lvseg->area_count && s < areas_size; s++) {
|
||||
if (seg_type(prev_lvseg, s) == AREA_LV) {
|
||||
lastseg = list_item(list_last(&seg_lv(prev_lvseg, s)->segments), struct lv_segment);
|
||||
/* FIXME For more areas supply flattened prev_lvseg to ensure consistency */
|
||||
if (lastseg->area_count == 1 &&
|
||||
_check_contiguous(lastseg, pv, pva, &areas[s], 1))
|
||||
return 1;
|
||||
continue;
|
||||
}
|
||||
pvmatch.condition = _is_contiguous;
|
||||
pvmatch.areas = areas;
|
||||
pvmatch.areas_size = areas_size;
|
||||
pvmatch.pva = pva;
|
||||
|
||||
if (!(prev_pvseg = seg_pvseg(prev_lvseg, s)))
|
||||
continue; /* FIXME Broken */
|
||||
/* FIXME Cope with stacks by flattening */
|
||||
if (!(r = _for_each_pv(cmd, prev_lvseg->lv,
|
||||
prev_lvseg->le + prev_lvseg->len - 1, 1, NULL,
|
||||
0, 0, -1, 1,
|
||||
_is_condition, &pvmatch)))
|
||||
stack;
|
||||
|
||||
if ((prev_pvseg->pv != pv))
|
||||
continue;
|
||||
if (r != 2)
|
||||
return 0;
|
||||
|
||||
if (prev_pvseg->pe + prev_pvseg->len == pva->start) {
|
||||
areas[s] = pva;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -729,21 +883,35 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc,
|
||||
struct pv_area *pva;
|
||||
struct pv_list *pvl;
|
||||
unsigned already_found_one = 0;
|
||||
unsigned contiguous = 0, contiguous_count = 0;
|
||||
unsigned contiguous = 0, cling = 0, preferred_count = 0;
|
||||
unsigned ix;
|
||||
unsigned ix_offset = 0; /* Offset for non-contiguous allocations */
|
||||
unsigned ix_offset = 0; /* Offset for non-preferred allocations */
|
||||
uint32_t max_parallel; /* Maximum extents to allocate */
|
||||
uint32_t next_le;
|
||||
struct seg_pvs *spvs;
|
||||
struct list *parallel_pvs;
|
||||
uint32_t free_pes;
|
||||
|
||||
/* Is there enough total space? */
|
||||
free_pes = pv_maps_size(pvms);
|
||||
if (needed - *allocated > free_pes) {
|
||||
log_error("Insufficient free space: %" PRIu32 " extents needed,"
|
||||
" but only %" PRIu32 " available",
|
||||
needed - *allocated, free_pes);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME Do calculations on free extent counts before selecting space */
|
||||
/* FIXME Select log PV appropriately if there isn't one yet */
|
||||
|
||||
/* Are there any preceding segments we must follow on from? */
|
||||
if ((alloc == ALLOC_CONTIGUOUS) && prev_lvseg) {
|
||||
contiguous = 1;
|
||||
if (prev_lvseg) {
|
||||
ix_offset = prev_lvseg->area_count;
|
||||
if ((alloc == ALLOC_CONTIGUOUS))
|
||||
contiguous = 1;
|
||||
else if ((alloc == ALLOC_CLING))
|
||||
cling = 1;
|
||||
else
|
||||
ix_offset = 0;
|
||||
}
|
||||
|
||||
/* FIXME This algorithm needs a lot of cleaning up! */
|
||||
@@ -752,6 +920,7 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc,
|
||||
/* ix holds the number of areas found on other PVs */
|
||||
do {
|
||||
ix = 0;
|
||||
preferred_count = 0;
|
||||
|
||||
parallel_pvs = NULL;
|
||||
max_parallel = needed;
|
||||
@@ -801,16 +970,27 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc,
|
||||
list_iterate_items(pva, &pvm->areas) {
|
||||
if (contiguous) {
|
||||
if (prev_lvseg &&
|
||||
_check_contiguous(prev_lvseg,
|
||||
pvm->pv,
|
||||
_check_contiguous(ah->cmd,
|
||||
prev_lvseg,
|
||||
pva, areas,
|
||||
areas_size)) {
|
||||
contiguous_count++;
|
||||
preferred_count++;
|
||||
goto next_pv;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cling) {
|
||||
if (prev_lvseg &&
|
||||
_check_cling(ah->cmd,
|
||||
prev_lvseg,
|
||||
pva, areas,
|
||||
areas_size)) {
|
||||
preferred_count++;
|
||||
}
|
||||
goto next_pv;
|
||||
}
|
||||
|
||||
/* Is it big enough on its own? */
|
||||
if (pva->count * ah->area_multiple <
|
||||
max_parallel - *allocated &&
|
||||
@@ -834,7 +1014,7 @@ static int _find_parallel_space(struct alloc_handle *ah, alloc_policy_t alloc,
|
||||
break;
|
||||
}
|
||||
|
||||
if (contiguous && (contiguous_count < ix_offset))
|
||||
if ((contiguous || cling) && (preferred_count < ix_offset))
|
||||
break;
|
||||
|
||||
/* Only allocate log_area the first time around */
|
||||
@@ -943,6 +1123,18 @@ static int _allocate(struct alloc_handle *ah,
|
||||
(!can_split && (allocated != old_allocated)))
|
||||
goto finished;
|
||||
|
||||
old_allocated = allocated;
|
||||
if (!_find_parallel_space(ah, ALLOC_CLING, pvms, areas,
|
||||
areas_size, can_split,
|
||||
prev_lvseg, &allocated, new_extents)) {
|
||||
stack;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((allocated == new_extents) || (ah->alloc == ALLOC_CLING) ||
|
||||
(!can_split && (allocated != old_allocated)))
|
||||
goto finished;
|
||||
|
||||
old_allocated = allocated;
|
||||
if (!_find_parallel_space(ah, ALLOC_NORMAL, pvms, areas,
|
||||
areas_size, can_split,
|
||||
@@ -1038,7 +1230,7 @@ struct alloc_handle *allocate_extents(struct volume_group *vg,
|
||||
if (alloc == ALLOC_INHERIT)
|
||||
alloc = vg->alloc;
|
||||
|
||||
if (!(ah = _alloc_init(vg->cmd->mem, segtype, alloc, mirrors,
|
||||
if (!(ah = _alloc_init(vg->cmd, vg->cmd->mem, segtype, alloc, mirrors,
|
||||
stripes, log_count, mirrored_pv,
|
||||
mirrored_pe, parallel_areas))) {
|
||||
stack;
|
||||
@@ -1382,59 +1574,8 @@ struct logical_volume *lv_create_empty(struct format_instance *fi,
|
||||
return lv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Call fn for each AREA_PV used by the LV segment at lv:le of length *max_seg_len.
|
||||
* If any constituent area contains more than one segment, max_seg_len is
|
||||
* reduced to cover only the first.
|
||||
*/
|
||||
static int _for_each_pv(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
uint32_t le, uint32_t len, uint32_t *max_seg_len,
|
||||
int (*fn)(struct cmd_context *cmd, struct pv_segment *peg, void *data),
|
||||
void *data)
|
||||
{
|
||||
struct lv_segment *seg;
|
||||
uint32_t s;
|
||||
uint32_t remaining_seg_len, area_len, area_multiple;
|
||||
|
||||
if (!(seg = find_seg_by_le(lv, le))) {
|
||||
log_error("Failed to find segment for %s extent %" PRIu32,
|
||||
lv->name, le);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Remaining logical length of segment */
|
||||
remaining_seg_len = seg->len - (le - seg->le);
|
||||
|
||||
if (remaining_seg_len > len)
|
||||
remaining_seg_len = len;
|
||||
|
||||
if (max_seg_len && *max_seg_len > remaining_seg_len)
|
||||
*max_seg_len = remaining_seg_len;
|
||||
|
||||
area_multiple = segtype_is_striped(seg->segtype) ? seg->area_count : 1;
|
||||
area_len = remaining_seg_len / area_multiple ? : 1;
|
||||
|
||||
for (s = 0; s < seg->area_count; s++)
|
||||
if (seg_type(seg, s) == AREA_LV) {
|
||||
if (!_for_each_pv(cmd, seg_lv(seg, s),
|
||||
seg_le(seg, s) + (le - seg->le) / area_multiple,
|
||||
area_len, max_seg_len, fn, data))
|
||||
return_0;
|
||||
} else if ((seg_type(seg, s) == AREA_PV) &&
|
||||
!fn(cmd, seg_pvseg(seg, s), data))
|
||||
return_0;
|
||||
|
||||
if (seg_is_mirrored(seg) &&
|
||||
!_for_each_pv(cmd, seg->log_lv, 0, MIRROR_LOG_SIZE,
|
||||
NULL, fn, data))
|
||||
return_0;
|
||||
|
||||
/* FIXME Add snapshot cow LVs etc. */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _add_pvs(struct cmd_context *cmd, struct pv_segment *peg, void *data)
|
||||
static int _add_pvs(struct cmd_context *cmd, struct pv_segment *peg,
|
||||
uint32_t s __attribute((unused)), void *data)
|
||||
{
|
||||
struct seg_pvs *spvs = (struct seg_pvs *) data;
|
||||
struct pv_list *pvl;
|
||||
@@ -1488,7 +1629,8 @@ struct list *build_parallel_areas_from_lv(struct cmd_context *cmd,
|
||||
|
||||
/* Find next segment end */
|
||||
/* FIXME Unnecessary nesting! */
|
||||
if (!_for_each_pv(cmd, lv, current_le, spvs->len, &spvs->len, _add_pvs, (void *) spvs)) {
|
||||
if (!_for_each_pv(cmd, lv, current_le, spvs->len, &spvs->len,
|
||||
0, 0, -1, 0, _add_pvs, (void *) spvs)) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "str_list.h"
|
||||
#include "pv_alloc.h"
|
||||
#include "activate.h"
|
||||
#include "display.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
@@ -89,11 +90,8 @@ static int _add_pv_to_vg(struct format_instance *fid, struct volume_group *vg,
|
||||
pv->pe_start = pe_align();
|
||||
|
||||
/*
|
||||
* The next two fields should be corrected
|
||||
* by fid->pv_setup.
|
||||
* pe_count must always be calculated by pv_setup
|
||||
*/
|
||||
pv->pe_count = (pv->size - pv->pe_start) / vg->extent_size;
|
||||
|
||||
pv->pe_alloc_count = 0;
|
||||
|
||||
if (!fid->fmt->ops->pv_setup(fid->fmt, UINT64_C(0), 0,
|
||||
@@ -125,6 +123,15 @@ static int _add_pv_to_vg(struct format_instance *fid, struct volume_group *vg,
|
||||
pvl->pv = pv;
|
||||
list_add(&vg->pvs, &pvl->list);
|
||||
|
||||
if ((uint64_t) vg->extent_count + pv->pe_count > UINT32_MAX) {
|
||||
log_error("Unable to add %s to %s: new extent count (%"
|
||||
PRIu64 ") exceeds limit (%" PRIu32 ").",
|
||||
pv_name, vg->name,
|
||||
(uint64_t) vg->extent_count + pv->pe_count,
|
||||
UINT32_MAX);
|
||||
return 0;
|
||||
}
|
||||
|
||||
vg->pv_count++;
|
||||
vg->extent_count += pv->pe_count;
|
||||
vg->free_count += pv->pe_count;
|
||||
@@ -734,6 +741,8 @@ int vg_validate(struct volume_group *vg)
|
||||
char uuid[64];
|
||||
int r = 1;
|
||||
|
||||
/* FIXME Also check there's no data/metadata overlap */
|
||||
|
||||
list_iterate_items(pvl, &vg->pvs) {
|
||||
list_iterate_items(pvl2, &vg->pvs) {
|
||||
if (pvl == pvl2)
|
||||
@@ -1044,7 +1053,7 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
if (correct_vg) {
|
||||
if (list_size(&correct_vg->pvs) != list_size(pvids)) {
|
||||
log_debug("Cached VG %s had incorrect PV list",
|
||||
vg->name);
|
||||
vgname);
|
||||
|
||||
if (memlock())
|
||||
inconsistent = 1;
|
||||
@@ -1053,7 +1062,7 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
|
||||
} else list_iterate_items(pvl, &correct_vg->pvs) {
|
||||
if (!str_list_match_item(pvids, pvl->pv->dev->pvid)) {
|
||||
log_debug("Cached VG %s had incorrect PV list",
|
||||
vg->name);
|
||||
vgname);
|
||||
correct_vg = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -82,6 +82,7 @@ typedef enum {
|
||||
ALLOC_INVALID = 0,
|
||||
ALLOC_INHERIT,
|
||||
ALLOC_CONTIGUOUS,
|
||||
ALLOC_CLING,
|
||||
ALLOC_NORMAL,
|
||||
ALLOC_ANYWHERE
|
||||
} alloc_policy_t;
|
||||
@@ -284,7 +285,7 @@ struct logical_volume {
|
||||
int32_t major;
|
||||
int32_t minor;
|
||||
|
||||
uint64_t size;
|
||||
uint64_t size; /* Sectors */
|
||||
uint32_t le_count;
|
||||
|
||||
uint32_t origin_count;
|
||||
|
||||
@@ -36,20 +36,20 @@ struct lv_segment *find_mirror_seg(struct lv_segment *seg)
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure region size is compatible with volume size.
|
||||
* Reduce the region size if necessary to ensure
|
||||
* the volume size is a multiple of the region size.
|
||||
*/
|
||||
uint32_t adjusted_mirror_region_size(uint32_t extent_size, uint32_t extents,
|
||||
uint32_t region_size)
|
||||
{
|
||||
uint32_t region_max;
|
||||
uint64_t region_max;
|
||||
|
||||
region_max = (1 << (ffs((int)extents) - 1)) * extent_size;
|
||||
region_max = (1 << (ffs((int)extents) - 1)) * (uint64_t) extent_size;
|
||||
|
||||
if (region_max < region_size) {
|
||||
region_size = region_max;
|
||||
if (region_max < UINT32_MAX && region_size > region_max) {
|
||||
region_size = (uint32_t) region_max;
|
||||
log_print("Using reduced mirror region size of %" PRIu32
|
||||
" sectors", region_max);
|
||||
return region_max;
|
||||
" sectors", region_size);
|
||||
}
|
||||
|
||||
return region_size;
|
||||
@@ -161,9 +161,11 @@ int remove_mirror_images(struct lv_segment *mirrored_seg, uint32_t num_mirrors,
|
||||
remove_log = 1;
|
||||
}
|
||||
|
||||
if (remove_log) {
|
||||
if (remove_log && mirrored_seg->log_lv) {
|
||||
log_lv = mirrored_seg->log_lv;
|
||||
mirrored_seg->log_lv = NULL;
|
||||
log_lv->status &= ~MIRROR_LOG;
|
||||
log_lv->status |= VISIBLE_LV;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -560,7 +562,7 @@ int insert_pvmove_mirrors(struct cmd_context *cmd,
|
||||
}
|
||||
|
||||
if (activation() && segtype->ops->target_present &&
|
||||
!segtype->ops->target_present()) {
|
||||
!segtype->ops->target_present(NULL)) {
|
||||
log_error("%s: Required device-mapper target(s) not "
|
||||
"detected in your kernel", segtype->name);
|
||||
return 0;
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
/*
|
||||
* Areas are maintained in size order, largest first.
|
||||
*
|
||||
* FIXME Cope with overlap.
|
||||
*/
|
||||
static void _insert_area(struct list *head, struct pv_area *a)
|
||||
{
|
||||
@@ -30,6 +32,7 @@ static void _insert_area(struct list *head, struct pv_area *a)
|
||||
}
|
||||
|
||||
list_add(&pva->list, &a->list);
|
||||
a->map->pe_count += a->count;
|
||||
}
|
||||
|
||||
static int _create_single_area(struct dm_pool *mem, struct pv_map *pvm,
|
||||
@@ -126,23 +129,32 @@ static int _create_all_areas_for_pv(struct dm_pool *mem, struct pv_map *pvm,
|
||||
|
||||
static int _create_maps(struct dm_pool *mem, struct list *pvs, struct list *pvms)
|
||||
{
|
||||
struct pv_map *pvm;
|
||||
struct pv_map *pvm, *pvm2;
|
||||
struct pv_list *pvl;
|
||||
|
||||
list_iterate_items(pvl, pvs) {
|
||||
if (!(pvl->pv->status & ALLOCATABLE_PV))
|
||||
continue;
|
||||
|
||||
if (!(pvm = dm_pool_zalloc(mem, sizeof(*pvm)))) {
|
||||
stack;
|
||||
return 0;
|
||||
pvm = NULL;
|
||||
|
||||
list_iterate_items(pvm2, pvms)
|
||||
if (pvm2->pv->dev == pvl->pv->dev) {
|
||||
pvm = pvm2;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!pvm) {
|
||||
if (!(pvm = dm_pool_zalloc(mem, sizeof(*pvm)))) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
pvm->pv = pvl->pv;
|
||||
list_init(&pvm->areas);
|
||||
list_add(pvms, &pvm->list);
|
||||
}
|
||||
|
||||
pvm->pv = pvl->pv;
|
||||
|
||||
list_init(&pvm->areas);
|
||||
list_add(pvms, &pvm->list);
|
||||
|
||||
if (!_create_all_areas_for_pv(mem, pvm, pvl->pe_ranges)) {
|
||||
stack;
|
||||
return 0;
|
||||
@@ -180,6 +192,7 @@ struct list *create_pv_maps(struct dm_pool *mem, struct volume_group *vg,
|
||||
void consume_pv_area(struct pv_area *pva, uint32_t to_go)
|
||||
{
|
||||
list_del(&pva->list);
|
||||
pva->map->pe_count -= pva->count;
|
||||
|
||||
assert(to_go <= pva->count);
|
||||
|
||||
@@ -190,3 +203,14 @@ void consume_pv_area(struct pv_area *pva, uint32_t to_go)
|
||||
_insert_area(&pva->map->areas, pva);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t pv_maps_size(struct list *pvms)
|
||||
{
|
||||
struct pv_map *pvm;
|
||||
uint32_t pe_count = 0;
|
||||
|
||||
list_iterate_items(pvm, pvms)
|
||||
pe_count += pvm->pe_count;
|
||||
|
||||
return pe_count;
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ struct pv_area {
|
||||
struct pv_map {
|
||||
struct physical_volume *pv;
|
||||
struct list areas; /* struct pv_areas */
|
||||
uint32_t pe_count; /* Total number of PEs */
|
||||
|
||||
struct list list;
|
||||
};
|
||||
@@ -49,4 +50,6 @@ struct list *create_pv_maps(struct dm_pool *mem, struct volume_group *vg,
|
||||
|
||||
void consume_pv_area(struct pv_area *area, uint32_t to_go);
|
||||
|
||||
uint32_t pv_maps_size(struct list *pvms);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -76,7 +76,10 @@ struct segtype_handler {
|
||||
struct lv_segment *seg, char *params,
|
||||
uint64_t *total_numerator,
|
||||
uint64_t *total_denominator, float *percent);
|
||||
int (*target_present) (void);
|
||||
int (*target_present) (const struct lv_segment *seg);
|
||||
int (*modules_needed) (struct dm_pool *mem,
|
||||
const struct lv_segment *seg,
|
||||
struct list *modules);
|
||||
void (*destroy) (const struct segment_type * segtype);
|
||||
int (*target_register_events) (struct lv_segment *seg, int events);
|
||||
int (*target_unregister_events) (struct lv_segment *seg, int events);
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "targets.h"
|
||||
#include "activate.h"
|
||||
#include "sharedlib.h"
|
||||
#include "str_list.h"
|
||||
|
||||
#ifdef DMEVENTD
|
||||
# include <libdevmapper-event.h>
|
||||
@@ -335,7 +336,7 @@ static int _mirrored_add_target_line(struct dev_manager *dm, struct dm_pool *mem
|
||||
return add_areas_line(dm, seg, node, start_area, area_count);
|
||||
}
|
||||
|
||||
static int _mirrored_target_present(void)
|
||||
static int _mirrored_target_present(const struct lv_segment *seg __attribute((unused)))
|
||||
{
|
||||
static int _mirrored_checked = 0;
|
||||
static int _mirrored_present = 0;
|
||||
@@ -447,6 +448,28 @@ static int _target_unregister_events(struct lv_segment *seg,
|
||||
#endif /* DMEVENTD */
|
||||
#endif /* DEVMAPPER_SUPPORT */
|
||||
|
||||
static int _mirrored_modules_needed(struct dm_pool *mem,
|
||||
const struct lv_segment *seg,
|
||||
struct list *modules)
|
||||
{
|
||||
if (seg->log_lv &&
|
||||
!list_segment_modules(mem, first_seg(seg->log_lv), modules))
|
||||
return_0;
|
||||
|
||||
if ((seg->lv->vg->status & CLUSTERED) &&
|
||||
!str_list_add(mem, modules, "clog")) {
|
||||
log_error("cluster log string list allocation failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!str_list_add(mem, modules, "mirror")) {
|
||||
log_error("mirror string list allocation failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _mirrored_destroy(const struct segment_type *segtype)
|
||||
{
|
||||
dm_free((void *) segtype);
|
||||
@@ -467,6 +490,7 @@ static struct segtype_handler _mirrored_ops = {
|
||||
.target_unregister_events = _target_unregister_events,
|
||||
#endif
|
||||
#endif
|
||||
.modules_needed = _mirrored_modules_needed,
|
||||
.destroy = _mirrored_destroy,
|
||||
};
|
||||
|
||||
|
||||
@@ -174,6 +174,9 @@
|
||||
/* Define to 1 if you have the <selinux/selinux.h> header file. */
|
||||
#undef HAVE_SELINUX_SELINUX_H
|
||||
|
||||
/* define to 1 to include support for realtime clock */
|
||||
#undef HAVE_REALTIME
|
||||
|
||||
/* Define to 1 if you have the `setlocale' function. */
|
||||
#undef HAVE_SETLOCALE
|
||||
|
||||
|
||||
@@ -244,3 +244,61 @@ void sync_dir(const char *file)
|
||||
out:
|
||||
dm_free(dir);
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to obtain fcntl lock on a file, if necessary creating file first
|
||||
* or waiting.
|
||||
* Returns file descriptor on success, else -1.
|
||||
* mode is F_WRLCK or F_RDLCK
|
||||
*/
|
||||
int fcntl_lock_file(const char *file, short lock_type, int warn_if_read_only)
|
||||
{
|
||||
int lockfd;
|
||||
struct flock lock = {
|
||||
.l_type = lock_type,
|
||||
.l_whence = 0,
|
||||
.l_start = 0,
|
||||
.l_len = 0
|
||||
};
|
||||
|
||||
log_very_verbose("Locking %s (%s, %hd)", file,
|
||||
(lock_type == F_WRLCK) ? "F_WRLCK" : "F_RDLCK",
|
||||
lock_type);
|
||||
if ((lockfd = open(file, O_RDWR | O_CREAT, 0777)) < 0) {
|
||||
/* EACCES has been reported on NFS */
|
||||
if (warn_if_read_only || (errno != EROFS && errno != EACCES))
|
||||
log_sys_error("open", file);
|
||||
else
|
||||
stack;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fcntl(lockfd, F_SETLKW, &lock)) {
|
||||
log_sys_error("fcntl", file);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return lockfd;
|
||||
}
|
||||
|
||||
void fcntl_unlock_file(int lockfd)
|
||||
{
|
||||
struct flock lock = {
|
||||
.l_type = F_UNLCK,
|
||||
.l_whence = 0,
|
||||
.l_start = 0,
|
||||
.l_len = 0
|
||||
};
|
||||
|
||||
log_very_verbose("Unlocking fd %d", lockfd);
|
||||
|
||||
if (fcntl(lockfd, F_SETLK, &lock) == -1)
|
||||
log_error("fcntl unlock failed on fd %d: %s", lockfd,
|
||||
strerror(errno));
|
||||
|
||||
if (close(lockfd))
|
||||
log_error("lock file close failed on fd %d: %s", lockfd,
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
|
||||
@@ -48,4 +48,8 @@ int create_dir(const char *dir);
|
||||
/* Sync directory changes */
|
||||
void sync_dir(const char *file);
|
||||
|
||||
/* fcntl locking wrappers */
|
||||
int fcntl_lock_file(const char *file, short lock_type, int warn_if_read_only);
|
||||
void fcntl_unlock_file(int lockfd);
|
||||
|
||||
#endif
|
||||
|
||||
130
lib/misc/timestamp.c
Normal file
130
lib/misc/timestamp.c
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Rackable Systems 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* Abstract out the time methods used so they can be adjusted later -
|
||||
* the results of these routines should stay in-core. This implementation
|
||||
* requires librt.
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "timestamp.h"
|
||||
|
||||
/*
|
||||
* The realtime section uses clock_gettime with the CLOCK_MONOTONIC
|
||||
* parameter to prevent issues with time warps
|
||||
*/
|
||||
#ifdef HAVE_REALTIME
|
||||
|
||||
#include <time.h>
|
||||
#include <bits/time.h>
|
||||
|
||||
struct timestamp {
|
||||
struct timespec t;
|
||||
};
|
||||
|
||||
struct timestamp *get_timestamp(void)
|
||||
{
|
||||
struct timestamp *ts = NULL;
|
||||
|
||||
if (!(ts = dm_malloc(sizeof(*ts))))
|
||||
return_NULL;
|
||||
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &ts->t)) {
|
||||
log_sys_error("clock_gettime", "get_timestamp");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ts;
|
||||
}
|
||||
|
||||
/* cmp_timestamp: Compare two timestamps
|
||||
*
|
||||
* Return: -1 if t1 is less than t2
|
||||
* 0 if t1 is equal to t2
|
||||
* 1 if t1 is greater than t2
|
||||
*/
|
||||
int cmp_timestamp(struct timestamp *t1, struct timestamp *t2)
|
||||
{
|
||||
if(t1->t.tv_sec < t2->t.tv_sec)
|
||||
return -1;
|
||||
if(t1->t.tv_sec > t2->t.tv_sec)
|
||||
return 1;
|
||||
|
||||
if(t1->t.tv_nsec < t2->t.tv_nsec)
|
||||
return -1;
|
||||
if(t1->t.tv_nsec > t2->t.tv_nsec)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* ! HAVE_REALTIME */
|
||||
|
||||
/*
|
||||
* The !realtime section just uses gettimeofday and is therefore subject
|
||||
* to ntp-type time warps - not sure if should allow that.
|
||||
*/
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
struct timestamp {
|
||||
struct timeval t;
|
||||
};
|
||||
|
||||
struct timestamp *get_timestamp(void)
|
||||
{
|
||||
struct timestamp *ts = NULL;
|
||||
|
||||
if (!(ts = dm_malloc(sizeof(*ts))))
|
||||
return_NULL;
|
||||
|
||||
if (gettimeofday(&ts->t, NULL)) {
|
||||
log_sys_error("gettimeofday", "get_timestamp");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ts;
|
||||
}
|
||||
|
||||
/* cmp_timestamp: Compare two timestamps
|
||||
*
|
||||
* Return: -1 if t1 is less than t2
|
||||
* 0 if t1 is equal to t2
|
||||
* 1 if t1 is greater than t2
|
||||
*/
|
||||
int cmp_timestamp(struct timestamp *t1, struct timestamp *t2)
|
||||
{
|
||||
if(t1->t.tv_sec < t2->t.tv_sec)
|
||||
return -1;
|
||||
if(t1->t.tv_sec > t2->t.tv_sec)
|
||||
return 1;
|
||||
|
||||
if(t1->t.tv_usec < t2->t.tv_usec)
|
||||
return -1;
|
||||
if(t1->t.tv_usec > t2->t.tv_usec)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* HAVE_REALTIME */
|
||||
|
||||
void destroy_timestamp(struct timestamp *t)
|
||||
{
|
||||
if (t)
|
||||
dm_free(t);
|
||||
}
|
||||
33
lib/misc/timestamp.h
Normal file
33
lib/misc/timestamp.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Rackable Systems 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_TIMESTAMP_H
|
||||
#define _LVM_TIMESTAMP_H
|
||||
|
||||
struct timestamp;
|
||||
|
||||
struct timestamp *get_timestamp(void);
|
||||
|
||||
/* cmp_timestamp: Compare two timestamps
|
||||
*
|
||||
* Return: -1 if t1 is less than t2
|
||||
* 0 if t1 is equal to t2
|
||||
* 1 if t1 is greater than t2
|
||||
*/
|
||||
int cmp_timestamp(struct timestamp *t1, struct timestamp *t2);
|
||||
|
||||
void destroy_timestamp(struct timestamp *t);
|
||||
|
||||
#endif /* _LVM_TIMESTAMP_H */
|
||||
|
||||
@@ -33,6 +33,7 @@ FIELD(LVS, lv, NUM, "Copy%", lvid, 6, copypercent, "copy_percent")
|
||||
FIELD(LVS, lv, STR, "Move", lvid, 4, movepv, "move_pv")
|
||||
FIELD(LVS, lv, STR, "LV Tags", tags, 7, tags, "lv_tags")
|
||||
FIELD(LVS, lv, STR, "Log", lvid, 3, loglv, "mirror_log")
|
||||
FIELD(LVS, lv, STR, "Modules", lvid, 7, modules, "modules")
|
||||
|
||||
FIELD(PVS, pv, STR, "Fmt", id, 3, pvfmt, "pv_fmt")
|
||||
FIELD(PVS, pv, STR, "PV UUID", id, 38, uuid, "pv_uuid")
|
||||
@@ -68,8 +69,11 @@ FIELD(VGS, vg, STR, "VG Tags", tags, 7, tags, "vg_tags")
|
||||
FIELD(SEGS, seg, STR, "Type", list, 4, segtype, "segtype")
|
||||
FIELD(SEGS, seg, NUM, "#Str", area_count, 4, uint32, "stripes")
|
||||
FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, "stripesize")
|
||||
FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, "stripe_size")
|
||||
FIELD(SEGS, seg, NUM, "Chunk", list, 5, chunksize, "chunksize")
|
||||
FIELD(SEGS, seg, NUM, "Chunk", list, 5, chunksize, "chunk_size")
|
||||
FIELD(SEGS, seg, NUM, "Region", region_size, 6, size32, "regionsize")
|
||||
FIELD(SEGS, seg, NUM, "Region", region_size, 6, size32, "region_size")
|
||||
FIELD(SEGS, seg, NUM, "Start", list, 5, segstart, "seg_start")
|
||||
FIELD(SEGS, seg, NUM, "SSize", list, 5, segsize, "seg_size")
|
||||
FIELD(SEGS, seg, STR, "Seg Tags", tags, 8, tags, "seg_tags")
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "display.h"
|
||||
#include "activate.h"
|
||||
#include "segtype.h"
|
||||
#include "str_list.h"
|
||||
|
||||
/*
|
||||
* For macro use
|
||||
@@ -103,6 +104,8 @@ static char _alloc_policy_char(alloc_policy_t alloc)
|
||||
switch (alloc) {
|
||||
case ALLOC_CONTIGUOUS:
|
||||
return 'c';
|
||||
case ALLOC_CLING:
|
||||
return 'C';
|
||||
case ALLOC_NORMAL:
|
||||
return 'n';
|
||||
case ALLOC_ANYWHERE:
|
||||
@@ -200,6 +203,7 @@ static int _devices_disp(struct report_handle *rh, struct field *field,
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _tags_disp(struct report_handle *rh, struct field *field,
|
||||
const void *data)
|
||||
{
|
||||
@@ -230,6 +234,23 @@ static int _tags_disp(struct report_handle *rh, struct field *field,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _modules_disp(struct report_handle *rh, struct field *field,
|
||||
const void *data)
|
||||
{
|
||||
const struct logical_volume *lv = (const struct logical_volume *) data;
|
||||
struct list *modules;
|
||||
|
||||
if (!(modules = str_list_create(rh->mem))) {
|
||||
log_error("modules str_list allocation failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!list_lv_modules(rh->mem, lv, modules))
|
||||
return_0;
|
||||
|
||||
return _tags_disp(rh, field, modules);
|
||||
}
|
||||
|
||||
static int _vgfmt_disp(struct report_handle *rh, struct field *field,
|
||||
const void *data)
|
||||
{
|
||||
@@ -948,6 +969,44 @@ static struct {
|
||||
|
||||
const unsigned int _num_fields = sizeof(_fields) / sizeof(_fields[0]);
|
||||
|
||||
static void _display_fields(void)
|
||||
{
|
||||
uint32_t f;
|
||||
const char *type, *last_type = "";
|
||||
|
||||
for (f = 0; f < _num_fields; f++) {
|
||||
switch (_fields[f].type) {
|
||||
case PVS:
|
||||
type = "Physical Volume";
|
||||
break;
|
||||
case LVS:
|
||||
type = "Logical Volume";
|
||||
break;
|
||||
case VGS:
|
||||
type = "Volume Group";
|
||||
break;
|
||||
case SEGS:
|
||||
type = "Logical Volume Segment";
|
||||
break;
|
||||
case PVSEGS:
|
||||
type = "Physical Volume Segment";
|
||||
break;
|
||||
default:
|
||||
type = " ";
|
||||
}
|
||||
|
||||
if (type != last_type) {
|
||||
if (*last_type)
|
||||
log_print(" ");
|
||||
log_print("%s Fields", type);
|
||||
}
|
||||
|
||||
log_print("- %s", _fields[f].id);
|
||||
|
||||
last_type = type;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialise report handle
|
||||
*/
|
||||
@@ -1080,6 +1139,8 @@ static int _parse_options(struct report_handle *rh, const char *format)
|
||||
while (*we && *we != ',')
|
||||
we++;
|
||||
if (!_field_match(rh, ws, (size_t) (we - ws))) {
|
||||
_display_fields();
|
||||
log_print(" ");
|
||||
log_error("Unrecognised field: %.*s", (int) (we - ws),
|
||||
ws);
|
||||
return 0;
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "text_export.h"
|
||||
#include "config.h"
|
||||
#include "activate.h"
|
||||
#include "str_list.h"
|
||||
|
||||
static const char *_snap_name(const struct lv_segment *seg)
|
||||
{
|
||||
@@ -111,7 +112,7 @@ static int _snap_target_percent(void **target_state __attribute((unused)),
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _snap_target_present(void)
|
||||
static int _snap_target_present(const struct lv_segment *seg __attribute((unused)))
|
||||
{
|
||||
static int _snap_checked = 0;
|
||||
static int _snap_present = 0;
|
||||
@@ -126,6 +127,18 @@ static int _snap_target_present(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
static int _snap_modules_needed(struct dm_pool *mem,
|
||||
const struct lv_segment *seg,
|
||||
struct list *modules)
|
||||
{
|
||||
if (!str_list_add(mem, modules, "snapshot")) {
|
||||
log_error("snapshot string list allocation failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _snap_destroy(const struct segment_type *segtype)
|
||||
{
|
||||
dm_free((void *)segtype);
|
||||
@@ -139,6 +152,7 @@ static struct segtype_handler _snapshot_ops = {
|
||||
.target_percent = _snap_target_percent,
|
||||
.target_present = _snap_target_present,
|
||||
#endif
|
||||
.modules_needed = _snap_modules_needed,
|
||||
.destroy = _snap_destroy,
|
||||
};
|
||||
|
||||
|
||||
@@ -174,7 +174,7 @@ static int _striped_add_target_line(struct dev_manager *dm,
|
||||
return add_areas_line(dm, seg, node, 0u, seg->area_count);
|
||||
}
|
||||
|
||||
static int _striped_target_present(void)
|
||||
static int _striped_target_present(const struct lv_segment *seg __attribute((unused)))
|
||||
{
|
||||
static int _striped_checked = 0;
|
||||
static int _striped_present = 0;
|
||||
|
||||
@@ -49,7 +49,7 @@ static int _zero_add_target_line(struct dev_manager *dm __attribute((unused)),
|
||||
return dm_tree_node_add_zero_target(node, len);
|
||||
}
|
||||
|
||||
static int _zero_target_present(void)
|
||||
static int _zero_target_present(const struct lv_segment *seg __attribute((unused)))
|
||||
{
|
||||
static int _zero_checked = 0;
|
||||
static int _zero_present = 0;
|
||||
@@ -63,6 +63,18 @@ static int _zero_target_present(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
static int _zero_modules_needed(struct dm_pool *mem,
|
||||
const struct lv_segment *seg,
|
||||
struct list *modules)
|
||||
{
|
||||
if (!str_list_add(mem, modules, "zero")) {
|
||||
log_error("zero module string list allocation failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _zero_destroy(const struct segment_type *segtype)
|
||||
{
|
||||
dm_free((void *) segtype);
|
||||
@@ -75,6 +87,7 @@ static struct segtype_handler _zero_ops = {
|
||||
.add_target_line = _zero_add_target_line,
|
||||
.target_present = _zero_target_present,
|
||||
#endif
|
||||
.modules_needed = _zero_modules_needed,
|
||||
.destroy = _zero_destroy,
|
||||
};
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ dm_task_set_gid
|
||||
dm_task_set_mode
|
||||
dm_task_suppress_identical_reload
|
||||
dm_task_add_target
|
||||
dm_task_no_flush
|
||||
dm_task_no_open_count
|
||||
dm_task_skip_lockfs
|
||||
dm_task_update_nodes
|
||||
|
||||
@@ -1026,6 +1026,13 @@ int dm_task_set_geometry(struct dm_task *dmt, const char *cylinders, const char
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_task_no_flush(struct dm_task *dmt)
|
||||
{
|
||||
dmt->no_flush = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_task_no_open_count(struct dm_task *dmt)
|
||||
{
|
||||
dmt->no_open_count = 1;
|
||||
@@ -1270,6 +1277,8 @@ static struct dm_ioctl *_flatten(struct dm_task *dmt, unsigned repeat_count)
|
||||
|
||||
if (dmt->type == DM_DEVICE_SUSPEND)
|
||||
dmi->flags |= DM_SUSPEND_FLAG;
|
||||
if (dmt->no_flush)
|
||||
dmi->flags |= DM_NOFLUSH_FLAG;
|
||||
if (dmt->read_only)
|
||||
dmi->flags |= DM_READONLY_FLAG;
|
||||
if (dmt->skip_lockfs)
|
||||
@@ -1543,7 +1552,7 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
|
||||
dmi->flags |= DM_SKIP_BDGET_FLAG;
|
||||
|
||||
log_debug("dm %s %s %s%s%s %s%.0d%s%.0d%s"
|
||||
"%s%c%s %.0llu %s [%u]",
|
||||
"%s%c%c%s %.0llu %s [%u]",
|
||||
_cmd_data_v4[dmt->type].name,
|
||||
dmi->name, dmi->uuid, dmt->newname ? " " : "",
|
||||
dmt->newname ? dmt->newname : "",
|
||||
@@ -1554,6 +1563,7 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
|
||||
dmt->major > 0 && dmt->minor == 0 ? "0" : "",
|
||||
dmt->major > 0 ? ") " : "",
|
||||
dmt->no_open_count ? 'N' : 'O',
|
||||
dmt->no_flush ? 'N' : 'F',
|
||||
dmt->skip_lockfs ? "S " : "",
|
||||
dmt->sector, dmt->message ? dmt->message : "",
|
||||
dmi->data_size);
|
||||
|
||||
@@ -52,6 +52,7 @@ struct dm_task {
|
||||
char *message;
|
||||
char *geometry;
|
||||
uint64_t sector;
|
||||
int no_flush;
|
||||
int no_open_count;
|
||||
int skip_lockfs;
|
||||
int suppress_identical_reload;
|
||||
|
||||
@@ -151,6 +151,7 @@ int dm_task_set_event_nr(struct dm_task *dmt, uint32_t event_nr);
|
||||
int dm_task_set_geometry(struct dm_task *dmt, const char *cylinders, const char *heads, const char *sectors, const char *start);
|
||||
int dm_task_set_message(struct dm_task *dmt, const char *message);
|
||||
int dm_task_set_sector(struct dm_task *dmt, uint64_t sector);
|
||||
int dm_task_no_flush(struct dm_task *dmt);
|
||||
int dm_task_no_open_count(struct dm_task *dmt);
|
||||
int dm_task_skip_lockfs(struct dm_task *dmt);
|
||||
int dm_task_suppress_identical_reload(struct dm_task *dmt);
|
||||
|
||||
@@ -1028,7 +1028,7 @@ int dm_tree_suspend_children(struct dm_tree_node *dnode,
|
||||
continue;
|
||||
|
||||
if (!_info_by_dev(dinfo->major, dinfo->minor, 0, &info) ||
|
||||
!info.exists)
|
||||
!info.exists || info.suspended)
|
||||
continue;
|
||||
|
||||
if (!_suspend_node(name, info.major, info.minor,
|
||||
|
||||
@@ -18,8 +18,8 @@ VPATH = @srcdir@
|
||||
|
||||
MAN5=lvm.conf.5
|
||||
MAN8=lvchange.8 lvconvert.8 lvcreate.8 lvdisplay.8 lvextend.8 lvm.8 \
|
||||
lvmchange.8 \
|
||||
lvmdiskscan.8 lvreduce.8 lvremove.8 lvrename.8 lvresize.8 lvs.8 \
|
||||
lvmchange.8 lvmdiskscan.8 lvmdump.8 \
|
||||
lvreduce.8 lvremove.8 lvrename.8 lvresize.8 lvs.8 \
|
||||
lvscan.8 pvchange.8 pvcreate.8 pvdisplay.8 pvmove.8 pvremove.8 \
|
||||
pvresize.8 pvs.8 pvscan.8 vgcfgbackup.8 vgcfgrestore.8 vgchange.8 \
|
||||
vgck.8 vgcreate.8 vgconvert.8 vgdisplay.8 vgexport.8 vgextend.8 \
|
||||
|
||||
@@ -4,6 +4,7 @@ clvmd \- cluster LVM daemon
|
||||
.SH SYNOPSIS
|
||||
.B clvmd
|
||||
[\-d] [\-h]
|
||||
[\-R]
|
||||
[\-t <timeout>]
|
||||
[\-V]
|
||||
.SH DESCRIPTION
|
||||
@@ -22,6 +23,11 @@ be so small that commands with many disk updates to do will fail, so you
|
||||
may need to increase this on systems with very large disk farms.
|
||||
The default is 30 seconds.
|
||||
.TP
|
||||
.I \-R
|
||||
Tells all the running clvmd in the cluster to reload their device cache and
|
||||
re-read the lvm configuration file. This command should be run whenever the
|
||||
devices on a cluster system are changed.
|
||||
.TP
|
||||
.I \-V
|
||||
Display the version of the cluster LVM daemon.
|
||||
.SH SEE ALSO
|
||||
|
||||
@@ -13,7 +13,7 @@ dmsetup \- low level logical volume management
|
||||
.I [-f|--force]
|
||||
.br
|
||||
.B dmsetup suspend
|
||||
.I [--nolockfs] device_name
|
||||
.I [--nolockfs] [--noflush] device_name
|
||||
.br
|
||||
.B dmsetup resume
|
||||
.I device_name
|
||||
@@ -30,6 +30,9 @@ dmsetup \- low level logical volume management
|
||||
.B dmsetup rename
|
||||
.I device_name new_name
|
||||
.br
|
||||
.B dmsetup message
|
||||
.I device_name sector message
|
||||
.br
|
||||
.B dmsetup ls [--target target_type] [--exec command] [--tree [-o options]]
|
||||
.br
|
||||
.B dmsetup info
|
||||
@@ -58,6 +61,9 @@ dmsetup \- low level logical volume management
|
||||
.br
|
||||
.B dmsetup version
|
||||
.br
|
||||
.B dmsetup setgeometry
|
||||
.I device_name cyl head sect start
|
||||
.br
|
||||
|
||||
.B devmap_name
|
||||
.I major minor
|
||||
@@ -167,6 +173,10 @@ ascii, utf, vt100; compact, inverted, notrunc.
|
||||
.br
|
||||
Loads <table> or table_file into the inactive table slot for device_name.
|
||||
If neither is supplied, reads a table from standard input.
|
||||
.IP \fBmessage
|
||||
.I device_name sector message
|
||||
.br
|
||||
Send message to target. If sector not needed use 0.
|
||||
.IP \fBmknodes
|
||||
.I [device_name]
|
||||
.br
|
||||
@@ -205,6 +215,10 @@ Renames a device.
|
||||
Un-suspends a device.
|
||||
If an inactive table has been loaded, it becomes live.
|
||||
Postponed I/O then gets re-queued for processing.
|
||||
.IP \fBsetgeometry
|
||||
.I device_name cyl head sect start
|
||||
.br
|
||||
Sets the device geometry to C/H/S.
|
||||
.IP \fBstatus
|
||||
.I [--target target_type]
|
||||
.I [device_name]
|
||||
@@ -213,7 +227,7 @@ Outputs status information for each of the device's targets.
|
||||
With --target, only information relating to the specified target type
|
||||
is displayed.
|
||||
.IP \fBsuspend
|
||||
.I [--nolockfs]
|
||||
.I [--nolockfs] [--noflush]
|
||||
.I device_name
|
||||
.br
|
||||
Suspends a device. Any I/O that has already been mapped by the device
|
||||
@@ -221,6 +235,9 @@ but has not yet completed will be flushed. Any further I/O to that
|
||||
device will be postponed for as long as the device is suspended.
|
||||
If there's a filesystem on the device which supports the operation,
|
||||
an attempt will be made to sync it first unless --nolockfs is specified.
|
||||
Some targets such as recent (October 2006) versions of multipath may support
|
||||
the --noflush option. This lets outstanding I/O that has not yet reached the
|
||||
device to remain unflushed.
|
||||
.IP \fBtable
|
||||
.I [--target target_type]
|
||||
.I [device_name]
|
||||
|
||||
@@ -7,6 +7,7 @@ lvchange \- change attributes of a logical volume
|
||||
[\-A/\-\-autobackup y/n] [\-a/\-\-available y/n/ey/en/ly/ln]
|
||||
[\-\-alloc AllocationPolicy]
|
||||
[\-C/\-\-contiguous y/n] [\-d/\-\-debug] [\-\-deltag Tag]
|
||||
[\-\-resync]
|
||||
[\-h/\-?/\-\-help]
|
||||
[\-\-ignorelockingfailure]
|
||||
[\-\-monitor {y|n}]
|
||||
@@ -40,6 +41,14 @@ logical volumes. It's only possible to change a non-contiguous
|
||||
logical volume's allocation policy to contiguous, if all of the
|
||||
allocated physical extents are already contiguous.
|
||||
.TP
|
||||
.I \-\-resync
|
||||
Forces the complete resynchronization of a mirror. In normal
|
||||
circumstances you should not need this option because synchronization
|
||||
happens automatically. Data is read from the primary mirror device
|
||||
and copied to the others, so this can take a considerable amount of
|
||||
time - and during this time you are without a complete redundant copy
|
||||
of your data.
|
||||
.TP
|
||||
.I \-\-minor minor
|
||||
Set the minor number.
|
||||
.TP
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
lvconvert \- convert a logical volume between linear and mirror
|
||||
.SH SYNOPSIS
|
||||
.B lvconvert
|
||||
[\-m/\-\-mirrors Mirrors [\-\-corelog]]
|
||||
[\-m/\-\-mirrors Mirrors [\-\-corelog] [\-R/\-\-regionsize MirrorLogRegionSize]]
|
||||
[\-A/\-\-alloc AllocationPolicy]
|
||||
[\-h/\-?/\-\-help]
|
||||
[\-v/\-\-verbose]
|
||||
@@ -28,6 +28,10 @@ mirror from using a disk-based (persistent) log to
|
||||
an in-memory log. You may only specify this option
|
||||
when the \-\-mirror argument is the same degree of
|
||||
the mirror you are changing.
|
||||
.TP
|
||||
.I \-R, \-\-regionsize MirrorLogRegionSize
|
||||
A mirror is divided into regions of this size (in MB), and the mirror log
|
||||
uses this granularity to track which regions are in sync.
|
||||
.SH Examples
|
||||
"lvconvert -m1 vg00/lvol1"
|
||||
.br
|
||||
|
||||
@@ -8,13 +8,13 @@ lvcreate \- create a logical volume in an existing volume group
|
||||
[\-A/\-\-autobackup y/n] [\-C/\-\-contiguous y/n] [\-d/\-\-debug]
|
||||
[\-h/\-?/\-\-help]
|
||||
[\-i/\-\-stripes Stripes [\-I/\-\-stripesize StripeSize]]
|
||||
{\-l/\-\-extents LogicalExtentsNumber |
|
||||
{\-l/\-\-extents LogicalExtentsNumber[%{VG|FREE}] |
|
||||
\-L/\-\-size LogicalVolumeSize[kKmMgGtT]}
|
||||
[\-M/\-\-persistent y/n] [\-\-minor minor]
|
||||
[\-m/\-\-mirrors Mirrors [\-\-nosync] [\-\-corelog]]
|
||||
[\-m/\-\-mirrors Mirrors [\-\-nosync] [\-\-corelog]
|
||||
[\-R/\-\-regionsize MirrorLogRegionSize]]
|
||||
[\-n/\-\-name LogicalVolumeName]
|
||||
[\-p/\-\-permission r/rw] [\-r/\-\-readahead ReadAheadSectors]
|
||||
[-R|--regionsize MirrorLogRegionSize]
|
||||
[\-t/\-\-test]
|
||||
[\-v/\-\-verbose] [\-Z/\-\-zero y/n]
|
||||
VolumeGroupName [PhysicalVolumePath...]
|
||||
@@ -22,7 +22,7 @@ VolumeGroupName [PhysicalVolumePath...]
|
||||
|
||||
.br
|
||||
.B lvcreate
|
||||
{\-l/\-\-extents LogicalExtentsNumber |
|
||||
{\-l/\-\-extents LogicalExtentsNumber[%{VG|FREE}] |
|
||||
\-L/\-\-size LogicalVolumeSize[kKmMgGtT]}
|
||||
[\-c/\-\-chunksize ChunkSize]
|
||||
\-s/\-\-snapshot \-n/\-\-name SnapshotLogicalVolumeName OriginalLogicalVolumePath
|
||||
@@ -63,14 +63,18 @@ StripeSize must be 2^n (n = 2 to 9) for metadata in LVM1 format.
|
||||
For metadata in LVM2 format, the stripe size may be a larger
|
||||
power of 2 but must not exceed the physical extent size.
|
||||
.TP
|
||||
.I \-l, \-\-extents LogicalExtentsNumber
|
||||
.I \-l, \-\-extents LogicalExtentsNumber[%{VG|FREE}]
|
||||
Gives the number of logical extents to allocate for the new
|
||||
logical volume.
|
||||
This can also be expressed as a percentage of the total space
|
||||
in the Volume Group with the suffix %VG or of the remaining free space
|
||||
with the suffix %FREE.
|
||||
.TP
|
||||
.I \-L, \-\-size LogicalVolumeSize[kKmMgGtT]
|
||||
.I \-L, \-\-size LogicalVolumeSize[kKmMgGtTpPeE]
|
||||
Gives the size to allocate for the new logical volume.
|
||||
A size suffix of K for kilobytes, M for megabytes,
|
||||
G for gigabytes or T for terabytes is optional.
|
||||
G for gigabytes, T for terabytes, P for petabytes
|
||||
or E for exabytes is optional.
|
||||
.br
|
||||
Default unit is megabytes.
|
||||
.TP
|
||||
@@ -112,8 +116,8 @@ Default is read and write.
|
||||
Set read ahead sector count of this logical volume to a value between 2 and 120.
|
||||
Ignored by device-mapper.
|
||||
.TP
|
||||
.I \-R \-\-regionsize MirrorLogRegionSize
|
||||
A mirror is divided into regions of this size (in KB), and the mirror log
|
||||
.I \-R, \-\-regionsize MirrorLogRegionSize
|
||||
A mirror is divided into regions of this size (in MB), and the mirror log
|
||||
uses this granularity to track which regions are in sync.
|
||||
.TP
|
||||
.I \-s, \-\-snapshot
|
||||
|
||||
@@ -6,7 +6,7 @@ lvextend \- extend the size of a logical volume
|
||||
[\-\-alloc AllocationPolicy]
|
||||
[\-A/\-\-autobackup y/n] [\-d/\-\-debug] [\-h/\-?/\-\-help]
|
||||
[\-i/\-\-stripes Stripes [\-I/\-\-stripesize StripeSize]]
|
||||
{\-l/\-\-extents [+]LogicalExtentsNumber |
|
||||
{\-l/\-\-extents [+]LogicalExtentsNumber[%{VG|LV|FREE}] |
|
||||
\-L/\-\-size [+]LogicalVolumeSize[kKmMgGtT]}
|
||||
[\-t/\-\-test]
|
||||
[\-v/\-\-verbose] LogicalVolumePath [PhysicalVolumePath...]
|
||||
@@ -21,15 +21,21 @@ volume use
|
||||
.SH OPTIONS
|
||||
See \fBlvm\fP for common options.
|
||||
.TP
|
||||
.I \-l, \-\-extents [+]LogicalExtentsNumber
|
||||
.I \-l, \-\-extents [+]LogicalExtentsNumber[%{VG|LV|FREE}]
|
||||
Extend or set the logical volume size in units of logical extents.
|
||||
With the + sign the value is added to the actual size
|
||||
of the logical volume and without it, the value is taken as an absolute one.
|
||||
The number can also be expressed as a percentage of the total space
|
||||
in the Volume Group with the suffix %VG or relative to the existing
|
||||
size of the Logical Volume with the suffix %LV or as a percentage of the remaining
|
||||
free space in the Volume Group with the suffix %FREE.
|
||||
.TP
|
||||
.I \-L, \-\-size [+]LogicalVolumeSize[kKmMgGtT]
|
||||
.I \-L, \-\-size [+]LogicalVolumeSize[kKmMgGtTpPeE]
|
||||
Extend or set the logical volume size in units in units of megabytes.
|
||||
A size suffix of M for megabytes, G for gigabytes or T for terabytes is
|
||||
optional. With the + sign the value is added to the actual size
|
||||
A size suffix of M for megabytes,
|
||||
G for gigabytes, T for terabytes, P for petabytes
|
||||
or E for exabytes is optional.
|
||||
With the + sign the value is added to the actual size
|
||||
of the logical volume and without it, the value is taken as an absolute one.
|
||||
.TP
|
||||
.I \-i, \-\-stripes Stripes
|
||||
|
||||
13
man/lvm.8
13
man/lvm.8
@@ -136,7 +136,7 @@ Characters allowed in tags are: A-Z a-z 0-9 _ + . -
|
||||
Delete the tag \fBtag\fP from a PV, VG or LV, if it's present.
|
||||
.TP
|
||||
\fB--alloc AllocationPolicy\fP
|
||||
The allocation policy to use: \fBcontiguous\fP, \fBnormal\fP, \fBanywhere\fP or \fBinherit\fP.
|
||||
The allocation policy to use: \fBcontiguous\fP, \fBcling\fP, \fBnormal\fP, \fBanywhere\fP or \fBinherit\fP.
|
||||
When a command needs to allocate physical extents from the volume group,
|
||||
the allocation policy controls how they are chosen.
|
||||
Each volume group and logical volume has an allocation policy.
|
||||
@@ -146,15 +146,18 @@ physical volume. The default for a logical volume is \fBinherit\fP
|
||||
which applies the same policy as for the volume group. These policies can
|
||||
be changed using \fBlvchange\fP (8) and \fBvgchange\fP (8) or over-ridden
|
||||
on the command line of any command that performs allocation.
|
||||
The \fBcontiguous\fP policy requires that new extents are adjacent to
|
||||
existing extents. If there are sufficient free extents to satisfy
|
||||
The \fBcontiguous\fP policy requires that new extents be placed adjacent
|
||||
to existing extents.
|
||||
The \fBcling\fP policy places new extents on the same physical
|
||||
volume as existing extents in the same stripe of the Logical Volume.
|
||||
If there are sufficient free extents to satisfy
|
||||
an allocation request but \fBnormal\fP doesn't use them,
|
||||
\fBanywhere\fP will - even if that reduces performance by
|
||||
placing two stripes on the same physical volume.
|
||||
.IP
|
||||
N.B. The policies described above are not implemented fully yet.
|
||||
In particular, \fBcontiguous\fP does not place new extents adjacent to existing
|
||||
extents and \fBanywhere\fP is not implemented at all.
|
||||
In particular, contiguous free space cannot be broken up to
|
||||
satisfy allocation attempts.
|
||||
.SH ENVIRONMENT VARIABLES
|
||||
.TP
|
||||
\fBLVM_SYSTEM_DIR\fP
|
||||
|
||||
50
man/lvmdump.8
Normal file
50
man/lvmdump.8
Normal file
@@ -0,0 +1,50 @@
|
||||
.TH LVMDUMP "8" "" "Red Hat, Inc."
|
||||
.SH NAME
|
||||
lvmdump - create lvm2 information dumps for diagnostic purposes
|
||||
.SH SYNOPSIS
|
||||
\fBlvmdump\fP [options] [-d directory]
|
||||
.SH DESCRIPTION
|
||||
\fBlvmdump\fP is a tool to dump various information concerning LVM2. By default, it creates a tarball suitable for submission along with a problem report.
|
||||
.PP
|
||||
The content of the tarball is as follows:
|
||||
.br
|
||||
- dmsetup info
|
||||
.br
|
||||
- table of currently running processes
|
||||
.br
|
||||
- recent entries from /var/log/messages (containing system messages)
|
||||
.br
|
||||
- complete lvm configuration and cache
|
||||
.br
|
||||
- list of device nodes present under /dev
|
||||
.br
|
||||
- if enabled with -m, metadata dump will be also included
|
||||
.br
|
||||
- if enabled with -a, debug output of vgscan, pvscan and list of all available volume groups, physical volumes and logical volumes will be included
|
||||
.br
|
||||
- if enabled with -c, cluster status info
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
\fB\-h\fR \(em print help message
|
||||
.TP
|
||||
\fB\-a\fR \(em advanced collection
|
||||
\fBWARNING\fR: if lvm is already hung, then this script may hang as well if \fB\-a\fR is used
|
||||
.TP
|
||||
\fB\-m\fR \(em gather LVM metadata from the PVs
|
||||
This option generates a 1:1 dump of the metadata area from all PVs visible to the system, which can cause the dump to increase in size considerably. However, the metadata dump may represent a valuable diagnostic resource.
|
||||
.TP
|
||||
\fB\-d\fR directory \(em dump into a directory instead of tarball
|
||||
By default, lvmdump will produce a single compressed tarball containing all the information. Using this option, it can be instructed to only produce the raw dump tree, rooted in \fBdirectory\fP.
|
||||
.TP
|
||||
\fB\-c\fR \(em if clvmd is running, gather cluster data as well
|
||||
.SH ENVIRONMENT VARIABLES
|
||||
.TP
|
||||
\fBLVM_BINARY\fP
|
||||
The LVM2 binary to use.
|
||||
Defaults to "lvm".
|
||||
Sometimes you might need to set this to "/sbin/lvm.static", for example.
|
||||
.TP
|
||||
\fBDMSETUP_BINARY\fP
|
||||
The dmsetup binary to use.
|
||||
Defaults to "dmsetup".
|
||||
.PP
|
||||
@@ -4,7 +4,8 @@ lvreduce \- reduce the size of a logical volume
|
||||
.SH SYNOPSIS
|
||||
.B lvreduce
|
||||
[\-A/\-\-autobackup y/n] [\-d/\-\-debug] [\-f/\-\-force]
|
||||
[\-h/\-?/\-\-help] {\-l/\-\-extents [\-]LogicalExtentsNumber |
|
||||
[\-h/\-?/\-\-help]
|
||||
{\-l/\-\-extents [\-]LogicalExtentsNumber[%{VG|LV|FREE}] |
|
||||
\-L/\-\-size [\-]LogicalVolumeSize[kKmMgGtT]}
|
||||
[\-t/\-\-test]
|
||||
[\-v/\-\-verbose] LogicalVolume[Path]
|
||||
@@ -35,16 +36,21 @@ See \fBlvm\fP for common options.
|
||||
.I \-f, \-\-force
|
||||
Force size reduction without any question.
|
||||
.TP
|
||||
.I \-l, \-\-extents [\-]LogicalExtentsNumber
|
||||
.I \-l, \-\-extents [\-]LogicalExtentsNumber[%{VG|LV|FREE}]
|
||||
Reduce or set the logical volume size in units of logical extents.
|
||||
With the - sign the value will be subtracted from
|
||||
the logical volume's actual size and without it the will be taken as
|
||||
an absolute size.
|
||||
The number can also be expressed as a percentage of the total space
|
||||
in the Volume Group with the suffix %VG or relative to the existing
|
||||
size of the Logical Volume with the suffix %LV or as a percentage of the remaining
|
||||
free space in the Volume Group with the suffix %FREE.
|
||||
.TP
|
||||
.I \-L, \-\-size [\-]LogicalVolumeSize[kKmMgGtT]
|
||||
.I \-L, \-\-size [\-]LogicalVolumeSize[kKmMgGtTpPeE]
|
||||
Reduce or set the logical volume size in units of megabyte by default.
|
||||
A size suffix of k for kilobyte, m for megabyte, g for gigabyte or
|
||||
t for terabyte is optional.
|
||||
A size suffix of k for kilobyte, m for megabyte,
|
||||
g for gigabytes, t for terabytes, p for petabytes
|
||||
or e for exabytes is optional.
|
||||
With the - sign the value will be subtracted from
|
||||
the logical volume's actual size and without it it will be taken as
|
||||
an absolute size.
|
||||
|
||||
@@ -12,6 +12,10 @@ lvremove \- remove a logical volume
|
||||
Confirmation will be requested before deactivating any active logical
|
||||
volume prior to removal. Logical volumes cannot be deactivated
|
||||
or removed while they are open (e.g. if they contain a mounted filesystem).
|
||||
.sp
|
||||
If the logical volume is clustered then it must be deactivated on all
|
||||
nodes in the cluster before it can be removed. A single lvchange command
|
||||
issued from one node can do this.
|
||||
.SH OPTIONS
|
||||
See \fBlvm\fP(8) for common options.
|
||||
.TP
|
||||
@@ -28,7 +32,8 @@ Remove all logical volumes in volume group vg00:
|
||||
\ \fBlvremove vg00\fP
|
||||
.SH SEE ALSO
|
||||
.BR lvcreate (8),
|
||||
.BR lvdisplay (8),
|
||||
.BR lvdisplay (8),
|
||||
.BR lvchange (8),
|
||||
.BR lvm (8),
|
||||
.BR lvs (8),
|
||||
.BR lvscan (8),
|
||||
|
||||
@@ -6,7 +6,7 @@ lvresize \- resize a logical volume
|
||||
[\-\-alloc AllocationPolicy]
|
||||
[\-A/\-\-autobackup y/n] [\-d/\-\-debug] [\-h/\-?/\-\-help]
|
||||
[\-i/\-\-stripes Stripes [\-I/\-\-stripesize StripeSize]]
|
||||
{\-l/\-\-extents [+]LogicalExtentsNumber |
|
||||
{\-l/\-\-extents [+]LogicalExtentsNumber[%{VG|LV|FREE}] |
|
||||
\-L/\-\-size [+]LogicalVolumeSize[kKmMgGtT]}
|
||||
[\-t/\-\-test]
|
||||
[\-v/\-\-verbose] LogicalVolumePath [PhysicalVolumePath...]
|
||||
@@ -25,15 +25,21 @@ volume use
|
||||
.SH OPTIONS
|
||||
See \fBlvm\fP for common options.
|
||||
.TP
|
||||
.I \-l, \-\-extents [+/-]LogicalExtentsNumber
|
||||
.I \-l, \-\-extents [+/-]LogicalExtentsNumber[%{VG|LV|FREE}]
|
||||
Change or set the logical volume size in units of logical extents.
|
||||
With the + or - sign the value is added to or subtracted from the actual size
|
||||
of the logical volume and without it, the value is taken as an absolute one.
|
||||
The number can also be expressed as a percentage of the total space
|
||||
in the Volume Group with the suffix %VG or relative to the existing
|
||||
size of the Logical Volume with the suffix %LV or as a percentage of the remaining
|
||||
free space in the Volume Group with the suffix %FREE.
|
||||
.TP
|
||||
.I \-L, \-\-size [+/-]LogicalVolumeSize[kKmMgGtT]
|
||||
.I \-L, \-\-size [+/-]LogicalVolumeSize[kKmMgGtTpPeE]
|
||||
Change or set the logical volume size in units of megabytes.
|
||||
A size suffix of M for megabytes, G for gigabytes or T for terabytes is
|
||||
optional. With the + or - sign the value is added to or subtracted from
|
||||
A size suffix of M for megabytes,
|
||||
G for gigabytes, T for terabytes, P for petabytes
|
||||
or E for exabytes is optional.
|
||||
With the + or - sign the value is added to or subtracted from
|
||||
the actual size of the logical volume and without it, the value is taken as an
|
||||
absolute one.
|
||||
.TP
|
||||
|
||||
23
scripts/Makefile.in
Normal file
23
scripts/Makefile.in
Normal file
@@ -0,0 +1,23 @@
|
||||
#
|
||||
# Copyright (C) 2006 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@
|
||||
|
||||
include $(top_srcdir)/make.tmpl
|
||||
|
||||
install:
|
||||
$(INSTALL) -D $(OWNER) $(GROUP) -m 555 $(STRIP) lvm_dump.sh \
|
||||
$(sbindir)/lvmdump
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# chkconfig: 345 24 76
|
||||
# chkconfig: - 24 76
|
||||
# description: Starts and stops clvmd
|
||||
#
|
||||
#
|
||||
@@ -73,7 +73,7 @@ stop()
|
||||
done
|
||||
else
|
||||
# Hack to only deactivate clustered volumes
|
||||
clustervgs=`$VGDISPLAY \`$VGS --noheadings -o name\` | awk 'BEGIN {RS="VG Name"} {if (/Clustered/) print $1;}'`
|
||||
clustervgs=`$VGDISPLAY 2> /dev/null | awk 'BEGIN {RS="VG Name"} {if (/Clustered/) print $1;}'`
|
||||
for vg in $clustervgs; do
|
||||
if ! action "Deactivating VG $vg:" $VGCHANGE -anl $vg
|
||||
then
|
||||
@@ -93,6 +93,24 @@ stop()
|
||||
return $rtrn
|
||||
}
|
||||
|
||||
wait_for_finish()
|
||||
{
|
||||
count=0
|
||||
|
||||
while [ "$count" -le 10 -a -n "`pidof clvmd`" ]
|
||||
do
|
||||
sleep 1
|
||||
count=$((count + 1))
|
||||
done
|
||||
|
||||
if [ `pidof clvmd` ]
|
||||
then
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
rtrn=1
|
||||
|
||||
# See how we were called.
|
||||
@@ -112,6 +130,7 @@ case "$1" in
|
||||
restart)
|
||||
if stop
|
||||
then
|
||||
wait_for_finish
|
||||
start
|
||||
fi
|
||||
rtrn=$?
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
# PATH entries to /sbin/init shell script so chroot works without /usr mounted. Remove
|
||||
# mkdir /initrd so we don't cause problems if root filesystem is corrupted. -- Jeff Layton
|
||||
# 15/05/2004 initial support for modules, create lvm.conf from lvm dumpconfig, other cleanups -- Jeff Layton
|
||||
# 14/11/2006 Update handling of ldd output to handle hardcoded library links and virtual dll linux-gate.
|
||||
# Add support for Gentoo-style MAKEDEV. Remove hardcoded BINUTILS paths -- Douglas Mayle
|
||||
#
|
||||
# Copyright Miguel Cabeca, Jeffrey Layton, 2004
|
||||
#
|
||||
@@ -52,7 +54,7 @@ TMPMNT=/tmp/mnt.$$
|
||||
DEVRAM=/tmp/initrd.$$
|
||||
|
||||
# set defaults
|
||||
BINFILES=${BINFILES:-"/lib/lvm-200/lvm /bin/bash /bin/busybox /sbin/pivot_root"}
|
||||
BINFILES=${BINFILES:-"`which lvm` `which bash` `which busybox` `which pivot_root`"}
|
||||
BASICDEVICES=${BASICDEVICES:-"std consoleonly fd"}
|
||||
BLOCKDEVICES=${BLOCKDEVICES:-"md hda hdb hdc hdd sda sdb sdc sdd"}
|
||||
MAKEDEV=${MAKEDEV:-"debian"}
|
||||
@@ -269,7 +271,27 @@ done
|
||||
# Figure out which shared libraries we actually need in our initrd
|
||||
echo "$cmd -- finding required shared libraries"
|
||||
verbose "BINFILES: `echo $BINFILES`"
|
||||
LIBFILES=`ldd $BINFILES 2>/dev/null | awk '{if (/=>/) { print $3 }}' | sort -u`
|
||||
|
||||
# We need to strip certain lines from ldd output. This is the full output of an example ldd:
|
||||
#lvmhost~ # ldd /sbin/lvm /bin/bash
|
||||
#/sbin/lvm:
|
||||
# not a dynamic executable
|
||||
#/bin/bash:
|
||||
# linux-gate.so.1 => (0xbfffe000)
|
||||
# libncurses.so.5 => /lib/libncurses.so.5 (0xb7ee3000)
|
||||
# libdl.so.2 => /lib/libdl.so.2 (0xb7edf000)
|
||||
# libc.so.6 => /lib/libc.so.6 (0xb7dc1000)
|
||||
# /lib/ld-linux.so.2 (0xb7f28000)
|
||||
#
|
||||
# 1) Lines with a ":" contain the name of the original binary we're examining, and so are unnecessary.
|
||||
# We need to strip them because they contain "/", and can be confused with links with a hardcoded path.
|
||||
# 2) The linux-gate library is a virtual dll that does not exist on disk, but is instead loaded automatically
|
||||
# into the process space, and can't be copied to the ramdisk
|
||||
#
|
||||
# After these lines have been stripped, we're interested in the lines remaining if they
|
||||
# 1) Contain "=>" because they are pathless links, and the value following the token is the path on the disk
|
||||
# 2) Contain "/" because it's a link with a hardcoded path, and so we're interested in the link itself.
|
||||
LIBFILES=`ldd $BINFILES 2>/dev/null |grep -v -E \(linux-gate\|:\) | awk '{if (/=>/) { print $3 } else if (/\//) { print $1 }}' | sort -u`
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "$cmd -- ERROR figuring out needed shared libraries"
|
||||
exit 1
|
||||
@@ -356,6 +378,10 @@ redhat)
|
||||
(cd $TMPMNT/dev; /dev/MAKEDEV $OPT_Q -d $TMPMNT/dev -m 2)
|
||||
RETCODE=$?
|
||||
;;
|
||||
gentoo)
|
||||
(cd $TMPMNT/dev; /usr/sbin/MAKEDEV $OPT_Q $BASICDEVICES $BLOCKDEVICES)
|
||||
RETCODE=$?
|
||||
;;
|
||||
*)
|
||||
echo "$cmd -- ERROR: $MAKEDEV is not a known MAKEDEV style."
|
||||
RETCODE=1
|
||||
|
||||
185
scripts/lvm_dump.sh
Executable file
185
scripts/lvm_dump.sh
Executable file
@@ -0,0 +1,185 @@
|
||||
#!/bin/bash
|
||||
# we use some bash-isms (getopts?)
|
||||
|
||||
# lvm_dump: This script is used to collect pertinent information for
|
||||
# the debugging of lvm issues.
|
||||
|
||||
# following external commands are used throughout the script
|
||||
# which, echo and test are internal in bash at least
|
||||
MKDIR=mkdir # need -p
|
||||
TAR=tar # need czf
|
||||
RM=rm # need -rf
|
||||
CP=cp
|
||||
TAIL=tail # we need -n
|
||||
LS=ls # need -la
|
||||
PS=ps # need alx
|
||||
SED=sed
|
||||
DD=dd
|
||||
CUT=cut
|
||||
DATE=date
|
||||
BASENAME=basename
|
||||
|
||||
# user may override lvm and dmsetup location by setting LVM_BINARY
|
||||
# and DMSETUP_BINARY respectively
|
||||
LVM=${LVM_BINARY-lvm}
|
||||
DMSETUP=${DMSETUP_BINARY-dmsetup}
|
||||
|
||||
die() {
|
||||
code=$1; shift
|
||||
echo "$@" 1>&2
|
||||
exit $code
|
||||
}
|
||||
|
||||
# which should error out if the binary is not executable, although i
|
||||
# am not sure we can rely on this
|
||||
which $LVM >& /dev/null || die 2 "Fatal: could not find lvm binary '$LVM'"
|
||||
test -x `which $LVM` || die 2 "Fatal: lvm binary '$LVM' not executable"
|
||||
which $DMSETUP >& /dev/null || die 2 "Fatal: could not find dmsetup binary '$DMSETUP'"
|
||||
test -x `which $DMSETUP` || die 2 "Fatal: dmsetup binary '$DMSETUP' not executable"
|
||||
|
||||
function usage {
|
||||
echo "$0 [options]"
|
||||
echo " -h print this message"
|
||||
echo " -a advanced collection - warning: if lvm is already hung,"
|
||||
echo " then this script may hang as well if -a is used"
|
||||
echo " -m gather LVM metadata from the PVs"
|
||||
echo " -d <directory> dump into a directory instead of tarball"
|
||||
echo " -c if running clvmd, gather cluster data as well"
|
||||
echo ""
|
||||
|
||||
exit 1
|
||||
}
|
||||
|
||||
advanced=0
|
||||
clustered=0
|
||||
metadata=0
|
||||
while getopts :acd:hm opt; do
|
||||
case $opt in
|
||||
s) sysreport=1 ;;
|
||||
a) advanced=1 ;;
|
||||
c) clustered=1 ;;
|
||||
d) userdir=$OPTARG ;;
|
||||
h) usage ;;
|
||||
m) metadata=1 ;;
|
||||
:) echo "$0: $OPTARG requires a value:"; usage ;;
|
||||
\?) echo "$0: unknown option $OPTARG"; usage ;;
|
||||
*) usage ;;
|
||||
esac
|
||||
done
|
||||
|
||||
NOW=`$DATE -u +%G%m%d%k%M%S | /usr/bin/tr -d ' '`
|
||||
if test -n "$userdir"; then
|
||||
dir="$userdir"
|
||||
else
|
||||
dirbase="lvmdump-$HOSTNAME-$NOW"
|
||||
dir="$HOME/$dirbase"
|
||||
fi
|
||||
|
||||
test -e $dir && die 3 "Fatal: $dir already exists"
|
||||
$MKDIR -p $dir || die 4 "Fatal: could not create $dir"
|
||||
|
||||
log="$dir/lvmdump.log"
|
||||
|
||||
myecho() {
|
||||
echo "$@"
|
||||
echo "$@" >> $log
|
||||
}
|
||||
|
||||
log() {
|
||||
echo "$@" >> $log
|
||||
eval "$@"
|
||||
}
|
||||
|
||||
echo " "
|
||||
myecho "Creating dump directory: $dir"
|
||||
echo " "
|
||||
|
||||
if (( $advanced )); then
|
||||
myecho "Gathering LVM volume info..."
|
||||
|
||||
myecho " vgscan..."
|
||||
log "$LVM vgscan -vvvv > $dir/vgscan 2>&1"
|
||||
|
||||
myecho " pvscan..."
|
||||
log "$LVM pvscan -v >> $dir/pvscan 2>> $log"
|
||||
|
||||
myecho " lvs..."
|
||||
log "$LVM lvs -a -o +devices >> $dir/lvs 2>> $log"
|
||||
|
||||
myecho " pvs..."
|
||||
log "$LVM pvs -a -v > $dir/pvs 2>> $log"
|
||||
|
||||
echo " vgs..."
|
||||
log "$LVM vgs -v > $dir/vgs 2>> $log"
|
||||
fi
|
||||
|
||||
if (( $clustered )); then
|
||||
myecho "Gathering cluster info..."
|
||||
echo "STATUS: " > $dir/cluster_info
|
||||
echo "----------------------------------" >> $dir/cluster_info
|
||||
log "cman_tool status >> $dir/cluster_info 2>> $log"
|
||||
echo " " >> $dir/lvm_info
|
||||
|
||||
echo "SERVICES: " >> $dir/cluster_info
|
||||
echo "----------------------------------" >> $dir/cluster_info
|
||||
log "cman_tool services >> $dir/cluster_info 2>> $log"
|
||||
echo " " >> $dir/lvm_info
|
||||
fi
|
||||
|
||||
myecho "Gathering LVM & device-mapper version info..."
|
||||
echo "LVM VERSION:" > $dir/versions
|
||||
$LVM lvs --version >> $dir/versions 2>> $log
|
||||
echo "DEVICE MAPPER VERSION:" >> $dir/versions
|
||||
$DMSETUP --version >> $dir/versions 2>> $log
|
||||
|
||||
myecho "Gathering dmsetup info..."
|
||||
log "$DMSETUP info -c > $dir/dmsetup_info 2>> $log"
|
||||
log "$DMSETUP table > $dir/dmsetup_table 2>> $log"
|
||||
log "$DMSETUP status > $dir/dmsetup_status 2>> $log"
|
||||
|
||||
myecho "Gathering process info..."
|
||||
log "$PS alx > $dir/ps_info 2>> $log"
|
||||
|
||||
myecho "Gathering console messages..."
|
||||
log "$TAIL -n 75 /var/log/messages > $dir/messages 2>> $log"
|
||||
|
||||
myecho "Gathering /etc/lvm info..."
|
||||
log "$CP -a /etc/lvm $dir/lvm 2>> $log"
|
||||
|
||||
myecho "Gathering /dev listing..."
|
||||
log "$LS -la /dev > $dir/dev_listing 2>> $log"
|
||||
|
||||
if (( $metadata )); then
|
||||
myecho "Gathering LVM metadata from Physical Volumes..."
|
||||
|
||||
log "$MKDIR -p $dir/metadata"
|
||||
|
||||
pvs="$($LVM pvs --separator , --noheadings --units s --nosuffix -o \
|
||||
name,pe_start 2>> $log | $SED -e 's/^ *//')"
|
||||
for line in "$pvs"
|
||||
do
|
||||
test -z "$line" && continue
|
||||
pv="$(echo $line | $CUT -d, -f1)"
|
||||
pe_start="$(echo $line | $CUT -d, -f2)"
|
||||
name="$($BASENAME $pv)"
|
||||
myecho " $pv"
|
||||
log "$DD if=$pv of=$dir/metadata/$name bs=512 count=$pe_start 2>> $log"
|
||||
done
|
||||
fi
|
||||
|
||||
if test -z "$userdir"; then
|
||||
lvm_dump="$dirbase.tgz"
|
||||
myecho "Creating report tarball in $HOME/$lvm_dump..."
|
||||
cd $HOME
|
||||
$TAR czf $lvm_dump $dirbase 2>/dev/null
|
||||
$RM -rf $dir
|
||||
fi
|
||||
|
||||
if test "$UID" != "0" && test "$EUID" != "0"; then
|
||||
myecho
|
||||
myecho "WARNING! Running as non-privileged user, dump is likely incomplete!"
|
||||
myecho
|
||||
fi
|
||||
|
||||
exit 0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
|
||||
# Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This file is part of the lvm2-cluster package.
|
||||
#
|
||||
@@ -21,8 +21,9 @@ function usage
|
||||
echo "usage: $0 <command>"
|
||||
echo ""
|
||||
echo "Commands:"
|
||||
echo "Enable clvm: --enable-cluster --lockinglibdir <dir> [--lockinglib <lib>]"
|
||||
echo "Enable clvm: --enable-cluster [--lockinglibdir <dir>] [--lockinglib <lib>]"
|
||||
echo "Disable clvm: --disable-cluster"
|
||||
echo "Set locking library: --lockinglibdir <dir> [--lockinglib <lib>]"
|
||||
echo ""
|
||||
echo "Global options:"
|
||||
echo "Config file location: --file <configfile>"
|
||||
@@ -86,14 +87,13 @@ function validate_args
|
||||
exit 10
|
||||
fi
|
||||
|
||||
if [ -z "$LOCKING_TYPE" ]; then
|
||||
if [ -z "$LOCKING_TYPE" ] && [ -z "$LOCKINGLIBDIR" ]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$LOCKING_TYPE" == "2" ]; then
|
||||
if [ -n "$LOCKINGLIBDIR" ]; then
|
||||
|
||||
[ -z "$LOCKINGLIBDIR" ] && usage && exit 1
|
||||
[ -z "$LOCKINGLIB" ] && LOCKINGLIB="liblvm2clusterlock.so"
|
||||
|
||||
if [ "${LOCKINGLIBDIR:0:1}" != "/" ]
|
||||
@@ -109,6 +109,10 @@ function validate_args
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
if [ "$LOCKING_TYPE" = "1" ] && [ -n "$LOCKINGLIBDIR" -o -n "$LOCKINGLIB" ]; then
|
||||
echo "Superfluous locking lib parameter, ignoring"
|
||||
fi
|
||||
}
|
||||
|
||||
umask 0077
|
||||
@@ -153,11 +157,19 @@ then
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$LOCKING_TYPE" = "2" ] && [ -z "$LOCKINGLIBDIR" ] && [ "$have_dir" = "1" ]; then
|
||||
echo "no library_dir specified in $CONFIGFILE"
|
||||
exit 16
|
||||
fi
|
||||
|
||||
# So if we don't have "global {" we need to create one and
|
||||
# populate it
|
||||
|
||||
if [ "$have_global" = "1" ]
|
||||
then
|
||||
if [ -z "$LOCKING_TYPE" ]; then
|
||||
LOCKING_TYPE=1
|
||||
fi
|
||||
if [ "$LOCKING_TYPE" = "2" ]; then
|
||||
cat $CONFIGFILE - <<EOF > $TMPFILE
|
||||
global {
|
||||
@@ -180,14 +192,16 @@ else
|
||||
# locking entries as appropriate
|
||||
#
|
||||
|
||||
if [ "$have_type" = "0" ]
|
||||
then
|
||||
SEDCMD=" s/^[[:blank:]]*locking_type[[:blank:]]*=.*/\ \ \ \ locking_type = $LOCKING_TYPE/g"
|
||||
else
|
||||
SEDCMD=" /global[[:blank:]]*{/a\ \ \ \ locking_type = $LOCKING_TYPE"
|
||||
if [ -n "$LOCKING_TYPE" ]; then
|
||||
if [ "$have_type" = "0" ]
|
||||
then
|
||||
SEDCMD=" s/^[[:blank:]]*locking_type[[:blank:]]*=.*/\ \ \ \ locking_type = $LOCKING_TYPE/g"
|
||||
else
|
||||
SEDCMD=" /global[[:blank:]]*{/a\ \ \ \ locking_type = $LOCKING_TYPE"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$LOCKING_TYPE" = "2" ]; then
|
||||
if [ -n "$LOCKINGLIBDIR" ]; then
|
||||
if [ "$have_dir" = "0" ]
|
||||
then
|
||||
SEDCMD="${SEDCMD}\ns'^[[:blank:]]*library_dir[[:blank:]]*=.*'\ \ \ \ library_dir = \"$LOCKINGLIBDIR\"'g"
|
||||
@@ -201,7 +215,9 @@ else
|
||||
else
|
||||
SEDCMD="${SEDCMD}\n/global[[:blank:]]*{/a\ \ \ \ locking_library = \"$LOCKINGLIB\""
|
||||
fi
|
||||
else
|
||||
fi
|
||||
|
||||
if [ "$LOCKING_TYPE" = "1" ]; then
|
||||
# if we're not using cluster locking, remove the library dir and locking library name
|
||||
if [ "$have_dir" = "0" ]
|
||||
then
|
||||
|
||||
@@ -82,7 +82,8 @@ LVMLIBS = -llvm
|
||||
|
||||
CLEAN_TARGETS = liblvm2cmd.so liblvm2cmd.a liblvm2cmd-static.a lvm lvm.o \
|
||||
lvm2cmd.o lvm2cmd-static.o lvm2cmdlib.o lvm.static \
|
||||
lvm.cflow lvm.xref lvm.tree lvm.rxref lvm.rtree
|
||||
lvm.cflow lvm.xref lvm.tree lvm.rxref lvm.rtree \
|
||||
lvmcmdlib.o lvm-static.o
|
||||
|
||||
ifeq ("@CMDLIB@", "yes")
|
||||
TARGETS += liblvm2cmd.so
|
||||
|
||||
@@ -46,6 +46,7 @@ arg(alloc_ARG, '\0', "alloc", alloc_arg)
|
||||
arg(separator_ARG, '\0', "separator", string_arg)
|
||||
arg(mirrorsonly_ARG, '\0', "mirrorsonly", NULL)
|
||||
arg(nosync_ARG, '\0', "nosync", NULL)
|
||||
arg(resync_ARG, '\0', "resync", NULL)
|
||||
arg(corelog_ARG, '\0', "corelog", NULL)
|
||||
arg(monitor_ARG, '\0', "monitor", yes_no_arg)
|
||||
arg(config_ARG, '\0', "config", string_arg)
|
||||
@@ -84,7 +85,7 @@ arg(interval_ARG, 'i', "interval", int_arg)
|
||||
arg(iop_version_ARG, 'i', "iop_version", NULL)
|
||||
arg(logicalvolume_ARG, 'l', "logicalvolume", int_arg)
|
||||
arg(maxlogicalvolumes_ARG, 'l', "maxlogicalvolumes", int_arg)
|
||||
arg(extents_ARG, 'l', "extents", int_arg_with_sign)
|
||||
arg(extents_ARG, 'l', "extents", int_arg_with_sign_and_percent)
|
||||
arg(lvmpartition_ARG, 'l', "lvmpartition", NULL)
|
||||
arg(list_ARG, 'l', "list", NULL)
|
||||
arg(size_ARG, 'L', "size", size_mb_arg)
|
||||
|
||||
@@ -19,7 +19,7 @@ xx(e2fsadm,
|
||||
"e2fsadm "
|
||||
"[-d|--debug] " "[-h|--help] " "[-n|--nofsck]" "\n"
|
||||
"\t{[-l|--extents] [+|-]LogicalExtentsNumber |" "\n"
|
||||
"\t [-L|--size] [+|-]LogicalVolumeSize[kKmMgGtT]}" "\n"
|
||||
"\t [-L|--size] [+|-]LogicalVolumeSize[kKmMgGtTpPeE]}" "\n"
|
||||
"\t[-t|--test] " "\n"
|
||||
"\t[-v|--verbose] " "\n"
|
||||
"\t[--version] " "\n"
|
||||
@@ -69,20 +69,23 @@ xx(lvchange,
|
||||
"\t[-p|--permission r|rw]\n"
|
||||
"\t[-r|--readahead ReadAheadSectors]\n"
|
||||
"\t[--refresh]\n"
|
||||
"\t[--resync]\n"
|
||||
"\t[-t|--test]\n"
|
||||
"\t[-v|--verbose]\n"
|
||||
"\t[-y|--yes]\n"
|
||||
"\t[--version]" "\n"
|
||||
"\tLogicalVolume[Path] [LogicalVolume[Path]...]\n",
|
||||
|
||||
alloc_ARG, autobackup_ARG, available_ARG, contiguous_ARG, force_ARG,
|
||||
ignorelockingfailure_ARG, major_ARG, minor_ARG, monitor_ARG,
|
||||
partial_ARG, permission_ARG, persistent_ARG, readahead_ARG,
|
||||
refresh_ARG, addtag_ARG, deltag_ARG, test_ARG)
|
||||
partial_ARG, permission_ARG, persistent_ARG, readahead_ARG, resync_ARG,
|
||||
refresh_ARG, addtag_ARG, deltag_ARG, test_ARG, yes_ARG)
|
||||
|
||||
xx(lvconvert,
|
||||
"Change logical volume layout",
|
||||
"lvconvert "
|
||||
"[-m|--mirrors Mirrors [--corelog]]\n"
|
||||
"\t[-R|--regionsize MirrorLogRegionSize]\n"
|
||||
"\t[--alloc AllocationPolicy]\n"
|
||||
"\t[-d|--debug]\n"
|
||||
"\t[-h|-?|--help]\n"
|
||||
@@ -100,7 +103,7 @@ xx(lvconvert,
|
||||
"\t[--version]" "\n"
|
||||
"\tOriginalLogicalVolume[Path] SnapshotLogicalVolume[Path]\n",
|
||||
|
||||
alloc_ARG, chunksize_ARG, mirrors_ARG, corelog_ARG,
|
||||
alloc_ARG, chunksize_ARG, mirrors_ARG, corelog_ARG, regionsize_ARG,
|
||||
snapshot_ARG, test_ARG, zero_ARG)
|
||||
|
||||
xx(lvcreate,
|
||||
@@ -114,7 +117,7 @@ xx(lvcreate,
|
||||
"\t[-h|-?|--help]\n"
|
||||
"\t[-i|--stripes Stripes [-I|--stripesize StripeSize]]\n"
|
||||
"\t{-l|--extents LogicalExtentsNumber |\n"
|
||||
"\t -L|--size LogicalVolumeSize[kKmMgGtT]}\n"
|
||||
"\t -L|--size LogicalVolumeSize[kKmMgGtTpPeE]}\n"
|
||||
"\t[-M|--persistent {y|n}] [--major major] [--minor minor]\n"
|
||||
"\t[-m|--mirrors Mirrors [--nosync] [--corelog]]\n"
|
||||
"\t[-n|--name LogicalVolumeName]\n"
|
||||
@@ -137,8 +140,8 @@ xx(lvcreate,
|
||||
"\t[-d|--debug]\n"
|
||||
"\t[-h|-?|--help]\n"
|
||||
"\t[-i|--stripes Stripes [-I|--stripesize StripeSize]]\n"
|
||||
"\t{-l|--extents LogicalExtentsNumber |\n"
|
||||
"\t -L|--size LogicalVolumeSize[kKmMgGtT]}\n"
|
||||
"\t{-l|--extents LogicalExtentsNumber[%{VG|LV|FREE}] |\n"
|
||||
"\t -L|--size LogicalVolumeSize[kKmMgGtTpPeE]}\n"
|
||||
"\t[-M|--persistent {y|n}] [--major major] [--minor minor]\n"
|
||||
"\t[-n|--name LogicalVolumeName]\n"
|
||||
"\t[-p|--permission {r|rw}]\n"
|
||||
@@ -202,8 +205,8 @@ xx(lvextend,
|
||||
"\t[-d|--debug]\n"
|
||||
"\t[-h|--help]\n"
|
||||
"\t[-i|--stripes Stripes [-I|--stripesize StripeSize]]\n"
|
||||
"\t{-l|--extents [+]LogicalExtentsNumber |\n"
|
||||
"\t -L|--size [+]LogicalVolumeSize[kKmMgGtT]}\n"
|
||||
"\t{-l|--extents [+]LogicalExtentsNumber[%{VG|FREE}] |\n"
|
||||
"\t -L|--size [+]LogicalVolumeSize[kKmMgGtTpPeE]}\n"
|
||||
"\t[-m|--mirrors Mirrors]\n"
|
||||
"\t[-n|--nofsck]\n"
|
||||
"\t[-r|--resizefs]\n"
|
||||
@@ -267,12 +270,13 @@ xx(lvreduce,
|
||||
"\t[-d|--debug]\n"
|
||||
"\t[-f|--force]\n"
|
||||
"\t[-h|--help]\n"
|
||||
"\t{-l|--extents [-]LogicalExtentsNumber |\n"
|
||||
"\t -L|--size [-]LogicalVolumeSize[kKmMgGtT]}\n"
|
||||
"\t{-l|--extents [-]LogicalExtentsNumber[%{VG|LV|FREE}] |\n"
|
||||
"\t -L|--size [-]LogicalVolumeSize[kKmMgGtTpPeE]}\n"
|
||||
"\t[-n|--nofsck]\n"
|
||||
"\t[-r|--resizefs]\n"
|
||||
"\t[-t|--test]\n"
|
||||
"\t[-v|--verbose]\n"
|
||||
"\t[-y|--yes]\n"
|
||||
"\t[--version]" "\n"
|
||||
"\tLogicalVolume[Path]\n",
|
||||
|
||||
@@ -315,8 +319,8 @@ xx(lvresize,
|
||||
"\t[-d|--debug]\n"
|
||||
"\t[-h|--help]\n"
|
||||
"\t[-i|--stripes Stripes [-I|--stripesize StripeSize]]\n"
|
||||
"\t{-l|--extents [+|-]LogicalExtentsNumber |\n"
|
||||
"\t -L|--size [+|-]LogicalVolumeSize[kKmMgGtT]}\n"
|
||||
"\t{-l|--extents [+|-]LogicalExtentsNumber[%{VG|LV|FREE}] |\n"
|
||||
"\t -L|--size [+|-]LogicalVolumeSize[kKmMgGtTpPeE]}\n"
|
||||
"\t[-n|--nofsck]\n"
|
||||
"\t[-r|--resizefs]\n"
|
||||
"\t[-t|--test]\n"
|
||||
@@ -392,7 +396,7 @@ xx(pvresize,
|
||||
"pvresize " "\n"
|
||||
"\t[-d|--debug]" "\n"
|
||||
"\t[-h|-?|--help] " "\n"
|
||||
"\t[--setphysicalvolumesize PhysicalVolumeSize[kKmMgGtT]" "\n"
|
||||
"\t[--setphysicalvolumesize PhysicalVolumeSize[kKmMgGtTpPeE]" "\n"
|
||||
"\t[-t|--test] " "\n"
|
||||
"\t[-v|--verbose] " "\n"
|
||||
"\t[--version] " "\n"
|
||||
@@ -410,8 +414,8 @@ xx(pvcreate,
|
||||
"\t[--labelsector sector] " "\n"
|
||||
"\t[-M|--metadatatype 1|2]" "\n"
|
||||
"\t[--metadatacopies #copies]" "\n"
|
||||
"\t[--metadatasize MetadataSize[kKmMgGtT]]" "\n"
|
||||
"\t[--setphysicalvolumesize PhysicalVolumeSize[kKmMgGtT]" "\n"
|
||||
"\t[--metadatasize MetadataSize[kKmMgGtTpPeE]]" "\n"
|
||||
"\t[--setphysicalvolumesize PhysicalVolumeSize[kKmMgGtTpPeE]" "\n"
|
||||
"\t[-t|--test] " "\n"
|
||||
"\t[-u|--uuid uuid] " "\n"
|
||||
"\t[-v|--verbose] " "\n"
|
||||
@@ -608,7 +612,7 @@ xx(vgchange,
|
||||
"\t -x|--resizeable {y|n} |" "\n"
|
||||
"\t -l|--logicalvolume MaxLogicalVolumes |" "\n"
|
||||
"\t -p|--maxphysicalvolumes MaxPhysicalVolumes |" "\n"
|
||||
"\t -s|--physicalextentsize PhysicalExtentSize[kKmMgGtT] |" "\n"
|
||||
"\t -s|--physicalextentsize PhysicalExtentSize[kKmMgGtTpPeE] |" "\n"
|
||||
"\t --addtag Tag |\n"
|
||||
"\t --deltag Tag}\n"
|
||||
"\t[VolumeGroupName...]\n",
|
||||
@@ -635,7 +639,7 @@ xx(vgconvert,
|
||||
"\t[--labelsector sector] " "\n"
|
||||
"\t[-M|--metadatatype 1|2]" "\n"
|
||||
"\t[--metadatacopies #copies]" "\n"
|
||||
"\t[--metadatasize MetadataSize[kKmMgGtT]]" "\n"
|
||||
"\t[--metadatasize MetadataSize[kKmMgGtTpPeE]]" "\n"
|
||||
"\t[-t|--test] " "\n"
|
||||
"\t[-v|--verbose] " "\n"
|
||||
"\t[--version] " "\n"
|
||||
@@ -656,7 +660,7 @@ xx(vgcreate,
|
||||
"\t[-l|--maxlogicalvolumes MaxLogicalVolumes]" "\n"
|
||||
"\t[-M|--metadatatype 1|2] " "\n"
|
||||
"\t[-p|--maxphysicalvolumes MaxPhysicalVolumes] " "\n"
|
||||
"\t[-s|--physicalextentsize PhysicalExtentSize[kKmMgGtT]] " "\n"
|
||||
"\t[-s|--physicalextentsize PhysicalExtentSize[kKmMgGtTpPeE]] " "\n"
|
||||
"\t[-t|--test] " "\n"
|
||||
"\t[-v|--verbose]" "\n"
|
||||
"\t[--version] " "\n"
|
||||
|
||||
300
tools/dmsetup.c
300
tools/dmsetup.c
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2005 NEC Corperation
|
||||
*
|
||||
* This file is part of the device-mapper userspace tools.
|
||||
@@ -38,6 +38,16 @@
|
||||
#include <locale.h>
|
||||
#include <langinfo.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
/* FIXME Unused so far */
|
||||
#undef HAVE_SYS_STATVFS_H
|
||||
|
||||
#ifdef HAVE_SYS_STATVFS_H
|
||||
# include <sys/statvfs.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
# include <sys/ioctl.h>
|
||||
#endif
|
||||
@@ -78,6 +88,11 @@ extern char *optarg;
|
||||
|
||||
#define LINE_SIZE 4096
|
||||
#define ARGS_MAX 256
|
||||
#define LOOP_TABLE_SIZE (PATH_MAX + 255)
|
||||
|
||||
/* FIXME Should be elsewhere */
|
||||
#define SECTOR_SHIFT 9L
|
||||
#define DEV_PATH "/dev/"
|
||||
|
||||
#define err(msg, x...) fprintf(stderr, msg "\n", ##x)
|
||||
|
||||
@@ -93,11 +108,13 @@ enum {
|
||||
MAJOR_ARG,
|
||||
MINOR_ARG,
|
||||
MODE_ARG,
|
||||
NOFLUSH_ARG,
|
||||
NOHEADINGS_ARG,
|
||||
NOLOCKFS_ARG,
|
||||
NOOPENCOUNT_ARG,
|
||||
NOTABLE_ARG,
|
||||
OPTIONS_ARG,
|
||||
SHOWKEYS_ARG,
|
||||
TABLE_ARG,
|
||||
TARGET_ARG,
|
||||
TREE_ARG,
|
||||
@@ -180,7 +197,7 @@ static int _parse_file(struct dm_task *dmt, const char *file)
|
||||
|
||||
#ifndef HAVE_GETLINE
|
||||
buffer_size = LINE_SIZE;
|
||||
if (!(buffer = malloc(buffer_size))) {
|
||||
if (!(buffer = dm_malloc(buffer_size))) {
|
||||
err("Failed to malloc line buffer.");
|
||||
return 0;
|
||||
}
|
||||
@@ -195,7 +212,11 @@ static int _parse_file(struct dm_task *dmt, const char *file)
|
||||
r = 1;
|
||||
|
||||
out:
|
||||
#ifndef HAVE_GETLINE
|
||||
dm_free(buffer);
|
||||
#else
|
||||
free(buffer);
|
||||
#endif
|
||||
if (file)
|
||||
fclose(fp);
|
||||
return r;
|
||||
@@ -512,7 +533,7 @@ static int _message(int argc, char **argv, void *data __attribute((unused)))
|
||||
for (i = 0; i < argc; i++)
|
||||
sz += strlen(argv[i]) + 1;
|
||||
|
||||
str = malloc(sz);
|
||||
str = dm_malloc(sz);
|
||||
memset(str, 0, sz);
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
@@ -524,7 +545,7 @@ static int _message(int argc, char **argv, void *data __attribute((unused)))
|
||||
if (!dm_task_set_message(dmt, str))
|
||||
goto out;
|
||||
|
||||
free(str);
|
||||
dm_free(str);
|
||||
|
||||
if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
|
||||
goto out;
|
||||
@@ -603,6 +624,9 @@ static int _simple(int task, const char *name, uint32_t event_nr, int display)
|
||||
if (event_nr && !dm_task_set_event_nr(dmt, event_nr))
|
||||
goto out;
|
||||
|
||||
if (_switches[NOFLUSH_ARG] && !dm_task_no_flush(dmt))
|
||||
goto out;
|
||||
|
||||
if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
|
||||
goto out;
|
||||
|
||||
@@ -744,28 +768,28 @@ static int _error_device(int argc __attribute((unused)), char **argv __attribute
|
||||
return 0;
|
||||
|
||||
if (!_set_task_device(dmt, name, 0))
|
||||
goto err;
|
||||
goto error;
|
||||
|
||||
if (!dm_task_add_target(dmt, 0, size, "error", ""))
|
||||
goto err;
|
||||
goto error;
|
||||
|
||||
if (_switches[READ_ONLY] && !dm_task_set_ro(dmt))
|
||||
goto err;
|
||||
goto error;
|
||||
|
||||
if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
|
||||
goto err;
|
||||
goto error;
|
||||
|
||||
if (!dm_task_run(dmt))
|
||||
goto err;
|
||||
goto error;
|
||||
|
||||
if (!_simple(DM_DEVICE_RESUME, name, 0, 0)) {
|
||||
_simple(DM_DEVICE_CLEAR, name, 0, 0);
|
||||
goto err;
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = 1;
|
||||
|
||||
err:
|
||||
error:
|
||||
dm_task_destroy(dmt);
|
||||
return r;
|
||||
}
|
||||
@@ -896,7 +920,7 @@ static int _status(int argc, char **argv, void *data)
|
||||
void *next = NULL;
|
||||
uint64_t start, length;
|
||||
char *target_type = NULL;
|
||||
char *params;
|
||||
char *params, *c;
|
||||
int cmd;
|
||||
struct dm_names *names = (struct dm_names *) data;
|
||||
const char *name = NULL;
|
||||
@@ -959,6 +983,17 @@ static int _status(int argc, char **argv, void *data)
|
||||
if (data && !_switches[VERBOSE_ARG])
|
||||
printf("%s: ", name);
|
||||
if (target_type) {
|
||||
|
||||
/* Suppress encryption key */
|
||||
if (!_switches[SHOWKEYS_ARG] &&
|
||||
!strcmp(target_type, "crypt")) {
|
||||
c = params;
|
||||
while (*c && *c != ' ')
|
||||
c++;
|
||||
c++;
|
||||
while (*c && *c != ' ')
|
||||
*c++ = '0';
|
||||
}
|
||||
printf("%" PRIu64 " %" PRIu64 " %s %s",
|
||||
start, length, target_type, params);
|
||||
}
|
||||
@@ -1487,12 +1522,12 @@ struct command {
|
||||
static struct command _commands[] = {
|
||||
{"create", "<dev_name> [-j|--major <major> -m|--minor <minor>]\n"
|
||||
"\t [-U|--uid <uid>] [-G|--gid <gid>] [-M|--mode <octal_mode>]\n"
|
||||
"\t [-u|uuid <uuid>]"
|
||||
"\t [-u|uuid <uuid>]\n"
|
||||
"\t [--notable | --table <table> | <table_file>]",
|
||||
1, 2, _create},
|
||||
{"remove", "[-f|--force] <device>", 0, 1, _remove},
|
||||
{"remove_all", "[-f|--force]", 0, 0, _remove_all},
|
||||
{"suspend", "<device>", 0, 1, _suspend},
|
||||
{"suspend", "[--noflush] <device>", 0, 1, _suspend},
|
||||
{"resume", "<device>", 0, 1, _resume},
|
||||
{"load", "<device> [<table_file>]", 0, 2, _load},
|
||||
{"clear", "<device>", 0, 1, _clear},
|
||||
@@ -1503,7 +1538,7 @@ static struct command _commands[] = {
|
||||
{"info", "[<device>]", 0, 1, _info},
|
||||
{"deps", "[<device>]", 0, 1, _deps},
|
||||
{"status", "[<device>] [--target <target_type>]", 0, 1, _status},
|
||||
{"table", "[<device>] [--target <target_type>]", 0, 1, _status},
|
||||
{"table", "[<device>] [--target <target_type>] [--showkeys]", 0, 1, _status},
|
||||
{"wait", "<device> [<event_nr>]", 0, 2, _wait},
|
||||
{"mknodes", "[<device>]", 0, 1, _mknodes},
|
||||
{"targets", "", 0, 0, _targets},
|
||||
@@ -1529,6 +1564,13 @@ static void _usage(FILE *out)
|
||||
return;
|
||||
}
|
||||
|
||||
static void _losetup_usage(FILE *out)
|
||||
{
|
||||
fprintf(out, "Usage:\n\n");
|
||||
fprintf(out, "losetup [-d|-a] [-e encryption] "
|
||||
"[-o offset] [-f|loop_device] [file]\n\n");
|
||||
}
|
||||
|
||||
static struct command *_find_command(const char *name)
|
||||
{
|
||||
int i;
|
||||
@@ -1606,11 +1648,225 @@ static int _process_tree_options(const char *options)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the full absolute path, or NULL if the path could
|
||||
* not be resolved.
|
||||
*/
|
||||
static char *_get_abspath(char *path)
|
||||
{
|
||||
char *_path;
|
||||
|
||||
#ifdef HAVE_CANONICALIZE_FILE_NAME
|
||||
_path = canonicalize_file_name(path);
|
||||
#else
|
||||
/* FIXME Provide alternative */
|
||||
#endif
|
||||
return _path;
|
||||
}
|
||||
|
||||
static char *parse_loop_device_name(char *dev)
|
||||
{
|
||||
char *buf;
|
||||
char *device;
|
||||
|
||||
if (!(buf = dm_malloc(PATH_MAX)));
|
||||
return NULL;
|
||||
|
||||
if (dev[0] == '/') {
|
||||
if (!(device = _get_abspath(dev)))
|
||||
goto error;
|
||||
|
||||
if (strncmp(device, DEV_PATH, strlen(DEV_PATH)))
|
||||
goto error;
|
||||
|
||||
strncpy(buf, strrchr(device, '/') + 1, PATH_MAX);
|
||||
dm_free(device);
|
||||
|
||||
} else {
|
||||
/* check for device number */
|
||||
if (!strncmp(dev, "loop", strlen("loop")))
|
||||
strncpy(buf, dev, PATH_MAX);
|
||||
else
|
||||
goto error;
|
||||
}
|
||||
|
||||
return buf;
|
||||
|
||||
error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* create a table for a mapped device using the loop target.
|
||||
*/
|
||||
static int _loop_table(char *table, size_t tlen, char *file, char *dev, off_t off)
|
||||
{
|
||||
struct stat fbuf;
|
||||
off_t size, sectors;
|
||||
int fd = -1;
|
||||
#ifdef HAVE_SYS_STATVFS_H
|
||||
struct statvfs fsbuf;
|
||||
off_t blksize;
|
||||
#endif
|
||||
|
||||
if (!_switches[READ_ONLY])
|
||||
fd = open(file, O_RDWR);
|
||||
|
||||
if (fd < 0) {
|
||||
_switches[READ_ONLY]++;
|
||||
fd = open(file, O_RDONLY);
|
||||
}
|
||||
|
||||
if (fd < 0)
|
||||
goto error;
|
||||
|
||||
if (fstat(fd, &fbuf))
|
||||
goto error;
|
||||
|
||||
size = (fbuf.st_size - off);
|
||||
sectors = size >> SECTOR_SHIFT;
|
||||
|
||||
if (_switches[VERBOSE_ARG])
|
||||
fprintf(stderr, "losetup: set loop size to %llukB (%llu sectors)\n",
|
||||
sectors >> 1, sectors);
|
||||
|
||||
#ifdef HAVE_SYS_STATVFS_H
|
||||
if (fstatvfs(fd, &fsbuf))
|
||||
goto error;
|
||||
|
||||
/* FIXME Fragment size currently unused */
|
||||
blksize = fsbuf.f_frsize;
|
||||
#endif
|
||||
|
||||
close(fd);
|
||||
|
||||
if (dm_snprintf(table, tlen, "%llu %llu loop %s %llu\n", 0ULL,
|
||||
(long long unsigned)sectors, file, off) < 0)
|
||||
return 0;
|
||||
|
||||
if (_switches[VERBOSE_ARG] > 1)
|
||||
fprintf(stderr, "Table: %s\n", table);
|
||||
|
||||
return 1;
|
||||
|
||||
error:
|
||||
if (fd > -1)
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _process_losetup_switches(const char *base, int *argc, char ***argv)
|
||||
{
|
||||
static int ind;
|
||||
int c;
|
||||
int encrypt_loop = 0, delete = 0, find = 0, show_all = 0;
|
||||
char *device_name = NULL;
|
||||
char *loop_file = NULL;
|
||||
off_t offset = 0;
|
||||
|
||||
#ifdef HAVE_GETOPTLONG
|
||||
static struct option long_options[] = {
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
#endif
|
||||
|
||||
optarg = 0;
|
||||
optind = OPTIND_INIT;
|
||||
while ((ind = -1, c = GETOPTLONG_FN(*argc, *argv, "ade:fo:v",
|
||||
long_options, NULL)) != -1 ) {
|
||||
if (c == ':' || c == '?')
|
||||
return 0;
|
||||
if (c == 'a')
|
||||
show_all++;
|
||||
if (c == 'd')
|
||||
delete++;
|
||||
if (c == 'e')
|
||||
encrypt_loop++;
|
||||
if (c == 'f')
|
||||
find++;
|
||||
if (c == 'o')
|
||||
offset = atoi(optarg);
|
||||
if (c == 'v')
|
||||
_switches[VERBOSE_ARG]++;
|
||||
}
|
||||
|
||||
*argv += optind ;
|
||||
*argc -= optind ;
|
||||
|
||||
if (encrypt_loop){
|
||||
fprintf(stderr, "%s: Sorry, cryptoloop is not yet implemented "
|
||||
"in this version.\n", base);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (show_all) {
|
||||
fprintf(stderr, "%s: Sorry, show all is not yet implemented "
|
||||
"in this version.\n", base);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (find) {
|
||||
fprintf(stderr, "%s: Sorry, find is not yet implemented "
|
||||
"in this version.\n", base);
|
||||
if (!*argc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!*argc) {
|
||||
fprintf(stderr, "%s: Please specify loop_device.\n", base);
|
||||
_losetup_usage(stderr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(device_name = parse_loop_device_name((*argv)[0]))) {
|
||||
fprintf(stderr, "%s: Could not parse loop_device %s\n",
|
||||
base, (*argv)[0]);
|
||||
_losetup_usage(stderr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (delete) {
|
||||
*argc = 2;
|
||||
|
||||
(*argv)[1] = device_name;
|
||||
(*argv)[0] = (char *) "remove";
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (*argc != 2) {
|
||||
fprintf(stderr, "%s: Too few arguments\n", base);
|
||||
_losetup_usage(stderr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME move these to make them available to native dmsetup */
|
||||
if (!(loop_file = _get_abspath((*argv)[(find) ? 0 : 1]))) {
|
||||
fprintf(stderr, "%s: Could not parse loop file name %s\n",
|
||||
base, (*argv)[1]);
|
||||
_losetup_usage(stderr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME Missing free */
|
||||
_table = dm_malloc(LOOP_TABLE_SIZE);
|
||||
if (!_loop_table(_table, LOOP_TABLE_SIZE, loop_file, device_name, offset)) {
|
||||
fprintf(stderr, "Could not build device-mapper table for %s\n", (*argv)[0]);
|
||||
return 0;
|
||||
}
|
||||
_switches[TABLE_ARG]++;
|
||||
|
||||
(*argv)[0] = (char *) "create";
|
||||
(*argv)[1] = device_name ;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _process_switches(int *argc, char ***argv)
|
||||
{
|
||||
char *base, *namebase;
|
||||
static int ind;
|
||||
int c;
|
||||
int c, r;
|
||||
|
||||
#ifdef HAVE_GETOPTLONG
|
||||
static struct option long_options[] = {
|
||||
@@ -1622,11 +1878,13 @@ static int _process_switches(int *argc, char ***argv)
|
||||
{"major", 1, &ind, MAJOR_ARG},
|
||||
{"minor", 1, &ind, MINOR_ARG},
|
||||
{"mode", 1, &ind, MODE_ARG},
|
||||
{"noflush", 0, &ind, NOFLUSH_ARG},
|
||||
{"noheadings", 0, &ind, NOHEADINGS_ARG},
|
||||
{"nolockfs", 0, &ind, NOLOCKFS_ARG},
|
||||
{"noopencount", 0, &ind, NOOPENCOUNT_ARG},
|
||||
{"notable", 0, &ind, NOTABLE_ARG},
|
||||
{"options", 1, &ind, OPTIONS_ARG},
|
||||
{"showkeys", 0, &ind, SHOWKEYS_ARG},
|
||||
{"table", 1, &ind, TABLE_ARG},
|
||||
{"target", 1, &ind, TARGET_ARG},
|
||||
{"tree", 0, &ind, TREE_ARG},
|
||||
@@ -1678,6 +1936,12 @@ static int _process_switches(int *argc, char ***argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(!strcmp(base, "losetup") || !strcmp(base, "dmlosetup")){
|
||||
r = _process_losetup_switches(base, argc, argv);
|
||||
free(namebase);
|
||||
return r;
|
||||
}
|
||||
|
||||
free(namebase);
|
||||
|
||||
optarg = 0;
|
||||
@@ -1733,12 +1997,16 @@ static int _process_switches(int *argc, char ***argv)
|
||||
_switches[TARGET_ARG]++;
|
||||
_target = optarg;
|
||||
}
|
||||
if ((ind == NOFLUSH_ARG))
|
||||
_switches[NOFLUSH_ARG]++;
|
||||
if ((ind == NOHEADINGS_ARG))
|
||||
_switches[NOHEADINGS_ARG]++;
|
||||
if ((ind == NOLOCKFS_ARG))
|
||||
_switches[NOLOCKFS_ARG]++;
|
||||
if ((ind == NOOPENCOUNT_ARG))
|
||||
_switches[NOOPENCOUNT_ARG]++;
|
||||
if ((ind == SHOWKEYS_ARG))
|
||||
_switches[SHOWKEYS_ARG]++;
|
||||
if ((ind == TABLE_ARG)) {
|
||||
_switches[TABLE_ARG]++;
|
||||
_table = optarg;
|
||||
|
||||
185
tools/lvchange.c
185
tools/lvchange.c
@@ -127,10 +127,10 @@ static int lvchange_availability(struct cmd_context *cmd,
|
||||
}
|
||||
} else {
|
||||
if (lockingfailed() && (lv->vg->status & CLUSTERED)) {
|
||||
log_verbose("Locking failed: ignoring clustered "
|
||||
log_verbose("Locking failed: ignoring clustered "
|
||||
"logical volume %s", lv->name);
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lv_is_origin(lv) || (activate == CHANGE_AE)) {
|
||||
log_verbose("Activating logical volume \"%s\" "
|
||||
@@ -175,6 +175,159 @@ static int lvchange_refresh(struct cmd_context *cmd, struct logical_volume *lv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lvchange_resync(struct cmd_context *cmd,
|
||||
struct logical_volume *lv)
|
||||
{
|
||||
int active = 0;
|
||||
struct lvinfo info;
|
||||
struct logical_volume *log_lv;
|
||||
|
||||
if (!(lv->status & MIRRORED)) {
|
||||
log_error("Unable to resync %s because it is not mirrored.",
|
||||
lv->name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (lv->status & PVMOVE) {
|
||||
log_error("Unable to resync pvmove volume %s", lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lv->status & LOCKED) {
|
||||
log_error("Unable to resync locked volume %s", lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lv_info(cmd, lv, &info, 1)) {
|
||||
if (info.open_count) {
|
||||
log_error("Can't resync open logical volume \"%s\"",
|
||||
lv->name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (info.exists) {
|
||||
if (!arg_count(cmd, yes_ARG) &&
|
||||
yes_no_prompt("Do you really want to deactivate "
|
||||
"logical volume %s to resync it? [y/n]: ",
|
||||
lv->name) == 'n') {
|
||||
log_print("Logical volume \"%s\" not resynced",
|
||||
lv->name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
active = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ((lv->vg->status & CLUSTERED) && !activate_lv_excl(cmd, lv)) {
|
||||
log_error("Can't get exclusive access to clustered volume %s",
|
||||
lv->name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!deactivate_lv(cmd, lv)) {
|
||||
log_error("Unable to deactivate %s for resync", lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_lv = first_seg(lv)->log_lv;
|
||||
|
||||
log_very_verbose("Starting resync of %s%s%s mirror \"%s\"",
|
||||
(active) ? "active " : "",
|
||||
(lv->vg->status & CLUSTERED) ? "clustered " : "",
|
||||
(log_lv) ? "disk-logged" : "core-logged",
|
||||
lv->name);
|
||||
|
||||
/*
|
||||
* If this mirror has a core log (i.e. !log_lv),
|
||||
* then simply deactivating/activating will cause
|
||||
* it to reset the sync status. We only need to
|
||||
* worry about persistent logs.
|
||||
*/
|
||||
if (!log_lv && !(lv->status & MIRROR_NOTSYNCED)) {
|
||||
if (active && !activate_lv(cmd, lv)) {
|
||||
log_error("Failed to reactivate %s to resynchronize "
|
||||
"mirror", lv->name);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
lv->status &= ~MIRROR_NOTSYNCED;
|
||||
|
||||
if (log_lv) {
|
||||
/* Separate mirror log so we can clear it */
|
||||
first_seg(lv)->log_lv = NULL;
|
||||
log_lv->status &= ~MIRROR_LOG;
|
||||
log_lv->status |= VISIBLE_LV;
|
||||
|
||||
if (!vg_write(lv->vg)) {
|
||||
log_error("Failed to write intermediate VG metadata.");
|
||||
if (active) {
|
||||
first_seg(lv)->log_lv = log_lv;
|
||||
log_lv->status |= MIRROR_LOG;
|
||||
log_lv->status &= ~VISIBLE_LV;
|
||||
if (!activate_lv(cmd, lv))
|
||||
stack;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
backup(lv->vg);
|
||||
|
||||
if (!vg_commit(lv->vg)) {
|
||||
log_error("Failed to commit intermediate VG metadata.");
|
||||
if (active) {
|
||||
first_seg(lv)->log_lv = log_lv;
|
||||
log_lv->status |= MIRROR_LOG;
|
||||
log_lv->status &= ~VISIBLE_LV;
|
||||
if (!activate_lv(cmd, lv))
|
||||
stack;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!activate_lv(cmd, log_lv)) {
|
||||
log_error("Unable to activate %s for mirror log resync",
|
||||
log_lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_very_verbose("Clearing log device %s", log_lv->name);
|
||||
if (!set_lv(cmd, log_lv, log_lv->size, 0)) {
|
||||
log_error("Unable to reset sync status for %s", lv->name);
|
||||
if (!deactivate_lv(cmd, log_lv))
|
||||
log_error("Failed to deactivate log LV after "
|
||||
"wiping failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!deactivate_lv(cmd, log_lv)) {
|
||||
log_error("Unable to deactivate log LV %s after wiping "
|
||||
"for resync", log_lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Put mirror log back in place */
|
||||
first_seg(lv)->log_lv = log_lv;
|
||||
log_lv->status |= MIRROR_LOG;
|
||||
log_lv->status &= ~VISIBLE_LV;
|
||||
}
|
||||
|
||||
log_very_verbose("Updating logical volume \"%s\" on disk(s)", lv->name);
|
||||
if (!vg_write(lv->vg) || !vg_commit(lv->vg)) {
|
||||
log_error("Failed to update metadata on disk.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (active && !activate_lv(cmd, lv)) {
|
||||
log_error("Failed to reactivate %s after resync", lv->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int lvchange_alloc(struct cmd_context *cmd, struct logical_volume *lv)
|
||||
{
|
||||
int want_contiguous = 0;
|
||||
@@ -294,16 +447,15 @@ static int lvchange_persistent(struct cmd_context *cmd,
|
||||
log_error("Major number must be specified with -My");
|
||||
return 0;
|
||||
}
|
||||
if (lv_info(cmd, lv, &info, 0) && info.exists &&
|
||||
!arg_count(cmd, force_ARG)) {
|
||||
if (yes_no_prompt("Logical volume %s will be "
|
||||
"deactivated temporarily. "
|
||||
"Continue? [y/n]: ", lv->name) == 'n') {
|
||||
log_print("%s device number not changed.",
|
||||
lv->name);
|
||||
return 0;
|
||||
}
|
||||
if (lv_info(cmd, lv, &info, 0) && info.exists)
|
||||
active = 1;
|
||||
if (active && !arg_count(cmd, force_ARG) &&
|
||||
yes_no_prompt("Logical volume %s will be "
|
||||
"deactivated temporarily. "
|
||||
"Continue? [y/n]: ", lv->name) == 'n') {
|
||||
log_print("%s device number not changed.",
|
||||
lv->name);
|
||||
return 0;
|
||||
}
|
||||
log_verbose("Ensuring %s is inactive.", lv->name);
|
||||
if (!deactivate_lv(cmd, lv)) {
|
||||
@@ -496,6 +648,10 @@ static int lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
if (doit)
|
||||
log_print("Logical volume \"%s\" changed", lv->name);
|
||||
|
||||
if (arg_count(cmd, resync_ARG))
|
||||
if (!lvchange_resync(cmd, lv))
|
||||
return ECMD_FAILED;
|
||||
|
||||
/* availability change */
|
||||
if (arg_count(cmd, available_ARG)) {
|
||||
if (!lvchange_availability(cmd, lv))
|
||||
@@ -523,9 +679,10 @@ int lvchange(struct cmd_context *cmd, int argc, char **argv)
|
||||
&& !arg_count(cmd, minor_ARG) && !arg_count(cmd, major_ARG)
|
||||
&& !arg_count(cmd, persistent_ARG) && !arg_count(cmd, addtag_ARG)
|
||||
&& !arg_count(cmd, deltag_ARG) && !arg_count(cmd, refresh_ARG)
|
||||
&& !arg_count(cmd, alloc_ARG) && !arg_count(cmd, monitor_ARG)) {
|
||||
&& !arg_count(cmd, alloc_ARG) && !arg_count(cmd, monitor_ARG)
|
||||
&& !arg_count(cmd, resync_ARG)) {
|
||||
log_error("Need 1 or more of -a, -C, -j, -m, -M, -p, -r, "
|
||||
"--refresh, --alloc, --addtag, --deltag "
|
||||
"--resync, --refresh, --alloc, --addtag, --deltag "
|
||||
"or --monitor");
|
||||
return EINVALID_CMD_LINE;
|
||||
}
|
||||
|
||||
@@ -212,7 +212,7 @@ static int _read_params(struct lvconvert_params *lp, struct cmd_context *cmd,
|
||||
}
|
||||
|
||||
if (activation() && lp->segtype->ops->target_present &&
|
||||
!lp->segtype->ops->target_present()) {
|
||||
!lp->segtype->ops->target_present(NULL)) {
|
||||
log_error("%s: Required device-mapper target(s) not "
|
||||
"detected in your kernel", lp->segtype->name);
|
||||
return 0;
|
||||
@@ -344,8 +344,7 @@ static int lvconvert_mirrors(struct cmd_context * cmd, struct logical_volume * l
|
||||
lp->mirrors - 1);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (lp->mirrors > existing_mirrors) {
|
||||
} else if (lp->mirrors > existing_mirrors) {
|
||||
/* FIXME Unless anywhere, remove PV of log_lv
|
||||
* from allocatable_pvs & allocate
|
||||
* (mirrors - existing_mirrors) new areas
|
||||
@@ -456,7 +455,7 @@ static int lvconvert_snapshot(struct cmd_context *cmd,
|
||||
|
||||
if (!lp->zero)
|
||||
log_error("WARNING: \"%s\" not zeroed", lv->name);
|
||||
else if (!set_lv(cmd, lv, 0)) {
|
||||
else if (!set_lv(cmd, lv, 0, 0)) {
|
||||
log_error("Aborting. Failed to wipe snapshot "
|
||||
"exception store.");
|
||||
return 0;
|
||||
|
||||
@@ -43,6 +43,7 @@ struct lvcreate_params {
|
||||
/* size */
|
||||
uint32_t extents;
|
||||
uint64_t size;
|
||||
percent_t percent;
|
||||
|
||||
uint32_t permission;
|
||||
uint32_t read_ahead;
|
||||
@@ -157,6 +158,7 @@ static int _read_size_params(struct lvcreate_params *lp,
|
||||
return 0;
|
||||
}
|
||||
lp->extents = arg_uint_value(cmd, extents_ARG, 0);
|
||||
lp->percent = arg_percent_value(cmd, extents_ARG, PERCENT_NONE);
|
||||
}
|
||||
|
||||
/* Size returned in kilobyte units; held in sectors */
|
||||
@@ -166,6 +168,7 @@ static int _read_size_params(struct lvcreate_params *lp,
|
||||
return 0;
|
||||
}
|
||||
lp->size = arg_uint64_value(cmd, size_ARG, UINT64_C(0)) * 2;
|
||||
lp->percent = PERCENT_NONE;
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -383,7 +386,7 @@ static int _lvcreate_params(struct lvcreate_params *lp, struct cmd_context *cmd,
|
||||
}
|
||||
|
||||
if (activation() && lp->segtype->ops->target_present &&
|
||||
!lp->segtype->ops->target_present()) {
|
||||
!lp->segtype->ops->target_present(NULL)) {
|
||||
log_error("%s: Required device-mapper target(s) not "
|
||||
"detected in your kernel", lp->segtype->name);
|
||||
return 0;
|
||||
@@ -553,7 +556,30 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
|
||||
display_size(cmd, tmp_size));
|
||||
}
|
||||
|
||||
lp->extents = tmp_size / vg->extent_size;
|
||||
if (tmp_size > (uint64_t) UINT32_MAX * vg->extent_size) {
|
||||
log_error("Volume too large (%s) for extent size %s. "
|
||||
"Upper limit is %s.",
|
||||
display_size(cmd, tmp_size),
|
||||
display_size(cmd, vg->extent_size),
|
||||
display_size(cmd, (uint64_t) UINT32_MAX *
|
||||
vg->extent_size));
|
||||
return 0;
|
||||
}
|
||||
lp->extents = (uint64_t) tmp_size / vg->extent_size;
|
||||
}
|
||||
|
||||
switch(lp->percent) {
|
||||
case PERCENT_VG:
|
||||
lp->extents = lp->extents * vg->extent_count / 100;
|
||||
break;
|
||||
case PERCENT_FREE:
|
||||
lp->extents = lp->extents * vg->free_count / 100;
|
||||
break;
|
||||
case PERCENT_LV:
|
||||
log_error("Please express size as %%VG or %%FREE.");
|
||||
return 0;
|
||||
case PERCENT_NONE:
|
||||
break;
|
||||
}
|
||||
|
||||
if ((size_rest = lp->extents % lp->stripes)) {
|
||||
@@ -601,8 +627,7 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
|
||||
}
|
||||
|
||||
if (!lp->extents) {
|
||||
log_error("Unable to create logical volume %s with no extents",
|
||||
lp->lv_name);
|
||||
log_error("Unable to create new logical volume with no extents");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -744,18 +769,19 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!activate_lv(cmd, lv)) {
|
||||
if (lp->snapshot)
|
||||
/* FIXME Remove the failed lv we just added */
|
||||
if (lp->snapshot) {
|
||||
if (!activate_lv_excl(cmd, lv)) {
|
||||
log_error("Aborting. Failed to activate snapshot "
|
||||
"exception store. Remove new LV and retry.");
|
||||
else
|
||||
log_error("Failed to activate new LV.");
|
||||
return 0;
|
||||
}
|
||||
} else if (!activate_lv(cmd, lv)) {
|
||||
log_error("Failed to activate new LV.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((lp->zero || lp->snapshot) && activation()) {
|
||||
if (!set_lv(cmd, lv, 0) && lp->snapshot) {
|
||||
if (!set_lv(cmd, lv, 0, 0) && lp->snapshot) {
|
||||
/* FIXME Remove the failed lv we just added */
|
||||
log_error("Aborting. Failed to wipe snapshot "
|
||||
"exception store. Remove new LV and retry.");
|
||||
@@ -770,10 +796,8 @@ static int _lvcreate(struct cmd_context *cmd, struct lvcreate_params *lp)
|
||||
/* Reset permission after zeroing */
|
||||
if (!(lp->permission & LVM_WRITE))
|
||||
lv->status &= ~LVM_WRITE;
|
||||
if (!deactivate_lv(cmd, lv)) {
|
||||
log_err("Couldn't deactivate new snapshot.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* cow LV remains active and becomes snapshot LV */
|
||||
|
||||
if (!vg_add_snapshot(vg->fid, NULL, org, lv, NULL,
|
||||
org->le_count, lp->chunk_size)) {
|
||||
|
||||
@@ -54,7 +54,7 @@ extern char *optarg;
|
||||
*/
|
||||
struct arg the_args[ARG_COUNT + 1] = {
|
||||
|
||||
#define arg(a, b, c, d) {b, "", "--" c, d, 0, NULL, 0, 0, INT64_C(0), UINT64_C(0), 0, NULL},
|
||||
#define arg(a, b, c, d) {b, "", "--" c, d, 0, NULL, 0, 0, INT64_C(0), UINT64_C(0), SIGN_NONE, PERCENT_NONE, NULL},
|
||||
#include "args.h"
|
||||
#undef arg
|
||||
|
||||
@@ -69,6 +69,7 @@ static int _interactive;
|
||||
int yes_no_arg(struct cmd_context *cmd __attribute((unused)), struct arg *a)
|
||||
{
|
||||
a->sign = SIGN_NONE;
|
||||
a->percent = PERCENT_NONE;
|
||||
|
||||
if (!strcmp(a->value, "y")) {
|
||||
a->i_value = 1;
|
||||
@@ -90,6 +91,7 @@ int yes_no_excl_arg(struct cmd_context *cmd __attribute((unused)),
|
||||
struct arg *a)
|
||||
{
|
||||
a->sign = SIGN_NONE;
|
||||
a->percent = PERCENT_NONE;
|
||||
|
||||
if (!strcmp(a->value, "e") || !strcmp(a->value, "ey") ||
|
||||
!strcmp(a->value, "ye")) {
|
||||
@@ -148,6 +150,8 @@ static int _get_int_arg(struct arg *a, char **ptr)
|
||||
char *val;
|
||||
long v;
|
||||
|
||||
a->percent = PERCENT_NONE;
|
||||
|
||||
val = a->value;
|
||||
switch (*val) {
|
||||
case '+':
|
||||
@@ -182,10 +186,12 @@ static int _size_arg(struct cmd_context *cmd __attribute((unused)), struct arg *
|
||||
{
|
||||
char *ptr;
|
||||
int i;
|
||||
static const char *suffixes = "kmgt";
|
||||
static const char *suffixes = "kmgtpe";
|
||||
char *val;
|
||||
double v;
|
||||
|
||||
a->percent = PERCENT_NONE;
|
||||
|
||||
val = a->value;
|
||||
switch (*val) {
|
||||
case '+':
|
||||
@@ -259,6 +265,33 @@ int int_arg_with_sign(struct cmd_context *cmd __attribute((unused)), struct arg
|
||||
return 1;
|
||||
}
|
||||
|
||||
int int_arg_with_sign_and_percent(struct cmd_context *cmd __attribute((unused)),
|
||||
struct arg *a)
|
||||
{
|
||||
char *ptr;
|
||||
|
||||
if (!_get_int_arg(a, &ptr))
|
||||
return 0;
|
||||
|
||||
if (!*ptr)
|
||||
return 1;
|
||||
|
||||
if (*ptr++ != '%')
|
||||
return 0;
|
||||
|
||||
if (!strcasecmp(ptr, "V") || !strcasecmp(ptr, "VG"))
|
||||
a->percent = PERCENT_VG;
|
||||
else if (!strcasecmp(ptr, "L") || !strcasecmp(ptr, "LV"))
|
||||
a->percent = PERCENT_LV;
|
||||
else if (!strcasecmp(ptr, "F") || !strcasecmp(ptr, "FR") ||
|
||||
!strcasecmp(ptr, "FREE"))
|
||||
a->percent = PERCENT_FREE;
|
||||
else
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int minor_arg(struct cmd_context *cmd __attribute((unused)), struct arg *a)
|
||||
{
|
||||
char *ptr;
|
||||
@@ -679,10 +712,8 @@ static int _get_settings(struct cmd_context *cmd)
|
||||
cmd->default_settings.activation);
|
||||
}
|
||||
|
||||
if (arg_count(cmd, autobackup_ARG)) {
|
||||
cmd->current_settings.archive = 1;
|
||||
cmd->current_settings.backup = 1;
|
||||
}
|
||||
cmd->current_settings.archive = arg_int_value(cmd, autobackup_ARG, cmd->current_settings.archive);
|
||||
cmd->current_settings.backup = arg_int_value(cmd, autobackup_ARG, cmd->current_settings.backup);
|
||||
|
||||
if (arg_count(cmd, partial_ARG)) {
|
||||
init_partial(1);
|
||||
|
||||
@@ -75,6 +75,16 @@ static int lvremove_single(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
if (!archive(vg))
|
||||
return ECMD_FAILED;
|
||||
|
||||
/* If the VG is clustered then make sure no-one else is using the LV
|
||||
we are about to remove */
|
||||
if (vg->status & CLUSTERED) {
|
||||
if (!activate_lv_excl(cmd, lv)) {
|
||||
log_error("Can't get exclusive access to volume \"%s\"",
|
||||
lv->name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME Snapshot commit out of sequence if it fails after here? */
|
||||
if (!deactivate_lv(cmd, lv)) {
|
||||
log_error("Unable to deactivate logical volume \"%s\"",
|
||||
|
||||
@@ -31,6 +31,7 @@ struct lvresize_params {
|
||||
uint32_t extents;
|
||||
uint64_t size;
|
||||
sign_t sign;
|
||||
percent_t percent;
|
||||
|
||||
enum {
|
||||
LV_ANY = 0,
|
||||
@@ -68,12 +69,14 @@ static int _lvresize_params(struct cmd_context *cmd, int argc, char **argv,
|
||||
if (arg_count(cmd, extents_ARG)) {
|
||||
lp->extents = arg_uint_value(cmd, extents_ARG, 0);
|
||||
lp->sign = arg_sign_value(cmd, extents_ARG, SIGN_NONE);
|
||||
lp->percent = arg_percent_value(cmd, extents_ARG, PERCENT_NONE);
|
||||
}
|
||||
|
||||
/* Size returned in kilobyte units; held in sectors */
|
||||
if (arg_count(cmd, size_ARG)) {
|
||||
lp->size = arg_uint64_value(cmd, size_ARG, UINT64_C(0)) * 2;
|
||||
lp->sign = arg_sign_value(cmd, size_ARG, SIGN_NONE);
|
||||
lp->percent = PERCENT_NONE;
|
||||
}
|
||||
|
||||
if (lp->resize == LV_EXTEND && lp->sign == SIGN_MINUS) {
|
||||
@@ -238,6 +241,20 @@ static int _lvresize(struct cmd_context *cmd, struct lvresize_params *lp)
|
||||
lp->extents = lp->size / vg->extent_size;
|
||||
}
|
||||
|
||||
switch(lp->percent) {
|
||||
case PERCENT_VG:
|
||||
lp->extents = lp->extents * vg->extent_count / 100;
|
||||
break;
|
||||
case PERCENT_FREE:
|
||||
lp->extents = lp->extents * vg->free_count / 100;
|
||||
break;
|
||||
case PERCENT_LV:
|
||||
lp->extents = lp->extents * lv->le_count / 100;
|
||||
break;
|
||||
case PERCENT_NONE:
|
||||
break;
|
||||
}
|
||||
|
||||
if (lp->sign == SIGN_PLUS)
|
||||
lp->extents += lv->le_count;
|
||||
|
||||
|
||||
@@ -19,10 +19,32 @@ static int _pvdisplay_single(struct cmd_context *cmd,
|
||||
struct volume_group *vg __attribute((unused)),
|
||||
struct physical_volume *pv, void *handle)
|
||||
{
|
||||
int consistent = 0;
|
||||
int ret = ECMD_PROCESSED;
|
||||
uint64_t size;
|
||||
|
||||
const char *pv_name = dev_name(pv->dev);
|
||||
|
||||
if (pv->vg_name) {
|
||||
if (!lock_vol(cmd, pv->vg_name, LCK_VG_READ)) {
|
||||
log_error("Can't lock %s: skipping", pv->vg_name);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!(vg = vg_read(cmd, pv->vg_name, (char *)&pv->vgid, &consistent))) {
|
||||
log_error("Can't read %s: skipping", pv->vg_name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((vg->status & CLUSTERED) && !locking_is_clustered() &&
|
||||
!lockingfailed()) {
|
||||
log_error("Skipping clustered volume group %s",
|
||||
vg->name);
|
||||
ret = ECMD_FAILED;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!*pv->vg_name)
|
||||
size = pv->size;
|
||||
else
|
||||
@@ -31,7 +53,7 @@ static int _pvdisplay_single(struct cmd_context *cmd,
|
||||
if (arg_count(cmd, short_ARG)) {
|
||||
log_print("Device \"%s\" has a capacity of %s", pv_name,
|
||||
display_size(cmd, size));
|
||||
return ECMD_PROCESSED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (pv->status & EXPORTED_VG)
|
||||
@@ -44,15 +66,19 @@ static int _pvdisplay_single(struct cmd_context *cmd,
|
||||
|
||||
if (arg_count(cmd, colon_ARG)) {
|
||||
pvdisplay_colons(pv);
|
||||
return ECMD_PROCESSED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
pvdisplay_full(cmd, pv, handle);
|
||||
|
||||
if (!arg_count(cmd, maps_ARG))
|
||||
return ECMD_PROCESSED;
|
||||
goto out;
|
||||
|
||||
return ECMD_PROCESSED;
|
||||
out:
|
||||
if (pv->vg_name)
|
||||
unlock_vg(cmd, pv->vg_name);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int pvdisplay(struct cmd_context *cmd, int argc, char **argv)
|
||||
|
||||
@@ -92,9 +92,9 @@ static int pvremove_single(struct cmd_context *cmd, const char *pv_name,
|
||||
}
|
||||
|
||||
if (!dev_test_excl(dev)) {
|
||||
log_error("Can't open %s exclusively. Mounted filesystem?",
|
||||
dev_name(dev));
|
||||
return 0;
|
||||
log_error("Can't open %s exclusively - not removing. "
|
||||
"Mounted filesystem?", dev_name(dev));
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Wipe existing label(s) */
|
||||
|
||||
@@ -70,6 +70,11 @@ sign_t arg_sign_value(struct cmd_context *cmd, int a, const sign_t def)
|
||||
return arg_count(cmd, a) ? cmd->args[a].sign : def;
|
||||
}
|
||||
|
||||
percent_t arg_percent_value(struct cmd_context *cmd, int a, const percent_t def)
|
||||
{
|
||||
return arg_count(cmd, a) ? cmd->args[a].percent : def;
|
||||
}
|
||||
|
||||
int arg_count_increment(struct cmd_context *cmd, int a)
|
||||
{
|
||||
return cmd->args[a].count++;
|
||||
@@ -839,23 +844,24 @@ char *default_vgname(struct cmd_context *cmd)
|
||||
/*
|
||||
* Process physical extent range specifiers
|
||||
*/
|
||||
static int _add_pe_range(struct dm_pool *mem, struct list *pe_ranges,
|
||||
uint32_t start, uint32_t count)
|
||||
static int _add_pe_range(struct dm_pool *mem, const char *pvname,
|
||||
struct list *pe_ranges, uint32_t start, uint32_t count)
|
||||
{
|
||||
struct pe_range *per;
|
||||
|
||||
log_debug("Adding PE range: start PE %" PRIu32 " length %" PRIu32,
|
||||
start, count);
|
||||
log_debug("Adding PE range: start PE %" PRIu32 " length %" PRIu32
|
||||
" on %s", start, count, pvname);
|
||||
|
||||
/* Ensure no overlap with existing areas */
|
||||
list_iterate_items(per, pe_ranges) {
|
||||
if (((start < per->start) && (start + count - 1 >= per->start))
|
||||
|| ((start >= per->start) &&
|
||||
(per->start + per->count - 1) >= start)) {
|
||||
log_error("Overlapping PE ranges detected (%" PRIu32
|
||||
"-%" PRIu32 ", %" PRIu32 "-%" PRIu32 ")",
|
||||
log_error("Overlapping PE ranges specified (%" PRIu32
|
||||
"-%" PRIu32 ", %" PRIu32 "-%" PRIu32 ")"
|
||||
" on %s",
|
||||
start, start + count - 1, per->start,
|
||||
per->start + per->count - 1);
|
||||
per->start + per->count - 1, pvname);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -873,14 +879,14 @@ static int _add_pe_range(struct dm_pool *mem, struct list *pe_ranges,
|
||||
}
|
||||
|
||||
static int _parse_pes(struct dm_pool *mem, char *c, struct list *pe_ranges,
|
||||
uint32_t size)
|
||||
const char *pvname, uint32_t size)
|
||||
{
|
||||
char *endptr;
|
||||
uint32_t start, end;
|
||||
|
||||
/* Default to whole PV */
|
||||
if (!c) {
|
||||
if (!_add_pe_range(mem, pe_ranges, UINT32_C(0), size)) {
|
||||
if (!_add_pe_range(mem, pvname, pe_ranges, UINT32_C(0), size)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -930,7 +936,7 @@ static int _parse_pes(struct dm_pool *mem, char *c, struct list *pe_ranges,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_add_pe_range(mem, pe_ranges, start, end - start + 1)) {
|
||||
if (!_add_pe_range(mem, pvname, pe_ranges, start, end - start + 1)) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
@@ -944,46 +950,56 @@ static int _parse_pes(struct dm_pool *mem, char *c, struct list *pe_ranges,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _create_pv_entry(struct dm_pool *mem, struct pv_list *pvl,
|
||||
static int _create_pv_entry(struct dm_pool *mem, struct pv_list *pvl,
|
||||
char *colon, int allocatable_only, struct list *r)
|
||||
{
|
||||
const char *pvname;
|
||||
struct pv_list *new_pvl;
|
||||
struct pv_list *new_pvl = NULL, *pvl2;
|
||||
struct list *pe_ranges;
|
||||
|
||||
pvname = dev_name(pvl->pv->dev);
|
||||
if (allocatable_only && !(pvl->pv->status & ALLOCATABLE_PV)) {
|
||||
log_error("Physical volume %s not allocatable", pvname);
|
||||
return;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (allocatable_only &&
|
||||
(pvl->pv->pe_count == pvl->pv->pe_alloc_count)) {
|
||||
log_err("No free extents on physical volume \"%s\"", pvname);
|
||||
return;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!(new_pvl = dm_pool_alloc(mem, sizeof(*new_pvl)))) {
|
||||
log_err("Unable to allocate physical volume list.");
|
||||
return;
|
||||
}
|
||||
list_iterate_items(pvl2, r)
|
||||
if (pvl->pv->dev == pvl2->pv->dev) {
|
||||
new_pvl = pvl2;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!new_pvl) {
|
||||
if (!(new_pvl = dm_pool_alloc(mem, sizeof(*new_pvl)))) {
|
||||
log_err("Unable to allocate physical volume list.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(new_pvl, pvl, sizeof(*new_pvl));
|
||||
memcpy(new_pvl, pvl, sizeof(*new_pvl));
|
||||
|
||||
if (!(pe_ranges = dm_pool_alloc(mem, sizeof(*pe_ranges)))) {
|
||||
log_error("Allocation of pe_ranges list failed");
|
||||
return;
|
||||
if (!(pe_ranges = dm_pool_alloc(mem, sizeof(*pe_ranges)))) {
|
||||
log_error("Allocation of pe_ranges list failed");
|
||||
return 0;
|
||||
}
|
||||
list_init(pe_ranges);
|
||||
new_pvl->pe_ranges = pe_ranges;
|
||||
list_add(r, &new_pvl->list);
|
||||
}
|
||||
list_init(pe_ranges);
|
||||
|
||||
/* Determine selected physical extents */
|
||||
if (!_parse_pes(mem, colon, pe_ranges, pvl->pv->pe_count)) {
|
||||
if (!_parse_pes(mem, colon, pe_ranges, dev_name(pvl->pv->dev),
|
||||
pvl->pv->pe_count)) {
|
||||
stack;
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
new_pvl->pe_ranges = pe_ranges;
|
||||
|
||||
list_add(r, &new_pvl->list);
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct list *create_pv_list(struct dm_pool *mem, struct volume_group *vg, int argc,
|
||||
@@ -1016,8 +1032,12 @@ struct list *create_pv_list(struct dm_pool *mem, struct volume_group *vg, int ar
|
||||
list_iterate_items(pvl, &vg->pvs) {
|
||||
if (str_list_match_item(&pvl->pv->tags,
|
||||
tagname)) {
|
||||
_create_pv_entry(mem, pvl, NULL,
|
||||
allocatable_only, r);
|
||||
if (!_create_pv_entry(mem, pvl, NULL,
|
||||
allocatable_only,
|
||||
r)) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
@@ -1039,7 +1059,10 @@ struct list *create_pv_list(struct dm_pool *mem, struct volume_group *vg, int ar
|
||||
"Volume Group \"%s\"", pvname, vg->name);
|
||||
return NULL;
|
||||
}
|
||||
_create_pv_entry(mem, pvl, colon, allocatable_only, r);
|
||||
if (!_create_pv_entry(mem, pvl, colon, allocatable_only, r)) {
|
||||
stack;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (list_empty(r))
|
||||
@@ -1165,7 +1188,8 @@ int generate_log_name_format(struct volume_group *vg __attribute((unused)),
|
||||
/*
|
||||
* Initialize the LV with 'value'.
|
||||
*/
|
||||
int set_lv(struct cmd_context *cmd, struct logical_volume *lv, int value)
|
||||
int set_lv(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
uint64_t sectors, int value)
|
||||
{
|
||||
struct device *dev;
|
||||
char *name;
|
||||
@@ -1198,7 +1222,10 @@ int set_lv(struct cmd_context *cmd, struct logical_volume *lv, int value)
|
||||
if (!dev_open_quiet(dev))
|
||||
return 0;
|
||||
|
||||
dev_set(dev, UINT64_C(0), (size_t) 4096, value);
|
||||
dev_set(dev, UINT64_C(0),
|
||||
sectors ? (size_t) sectors << SECTOR_SHIFT : (size_t) 4096,
|
||||
value);
|
||||
dev_flush(dev);
|
||||
dev_close_immediate(dev);
|
||||
|
||||
return 1;
|
||||
@@ -1312,7 +1339,8 @@ struct logical_volume *create_mirror_log(struct cmd_context *cmd,
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (activation() && !set_lv(cmd, log_lv, in_sync)) {
|
||||
if (activation() && !set_lv(cmd, log_lv, log_lv->size,
|
||||
in_sync ? -1 : 0)) {
|
||||
log_error("Aborting. Failed to wipe mirror log. "
|
||||
"Remove new LV and retry.");
|
||||
goto error;
|
||||
|
||||
@@ -101,6 +101,7 @@ struct logical_volume *create_mirror_log(struct cmd_context *cmd,
|
||||
const char *lv_name,
|
||||
int in_sync);
|
||||
|
||||
int set_lv(struct cmd_context *cmd, struct logical_volume *lv, int value);
|
||||
int set_lv(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
uint64_t sectors, int value);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -80,6 +80,13 @@ typedef enum {
|
||||
SIGN_MINUS = 2
|
||||
} sign_t;
|
||||
|
||||
typedef enum {
|
||||
PERCENT_NONE = 0,
|
||||
PERCENT_VG,
|
||||
PERCENT_FREE,
|
||||
PERCENT_LV
|
||||
} percent_t;
|
||||
|
||||
enum {
|
||||
CHANGE_AY = 0,
|
||||
CHANGE_AN = 1,
|
||||
@@ -103,6 +110,7 @@ struct arg {
|
||||
int64_t i64_value;
|
||||
uint64_t ui64_value;
|
||||
sign_t sign;
|
||||
percent_t percent;
|
||||
void *ptr;
|
||||
};
|
||||
|
||||
@@ -126,6 +134,7 @@ int size_kb_arg(struct cmd_context *cmd, struct arg *a);
|
||||
int size_mb_arg(struct cmd_context *cmd, struct arg *a);
|
||||
int int_arg(struct cmd_context *cmd, struct arg *a);
|
||||
int int_arg_with_sign(struct cmd_context *cmd, struct arg *a);
|
||||
int int_arg_with_sign_and_percent(struct cmd_context *cmd, struct arg *a);
|
||||
int major_arg(struct cmd_context *cmd, struct arg *a);
|
||||
int minor_arg(struct cmd_context *cmd, struct arg *a);
|
||||
int string_arg(struct cmd_context *cmd, struct arg *a);
|
||||
@@ -148,6 +157,7 @@ int64_t arg_int64_value(struct cmd_context *cmd, int a, const int64_t def);
|
||||
uint64_t arg_uint64_value(struct cmd_context *cmd, int a, const uint64_t def);
|
||||
const void *arg_ptr_value(struct cmd_context *cmd, int a, const void *def);
|
||||
sign_t arg_sign_value(struct cmd_context *cmd, int a, const sign_t def);
|
||||
percent_t arg_percent_value(struct cmd_context *cmd, int a, const percent_t def);
|
||||
int arg_count_increment(struct cmd_context *cmd, int a);
|
||||
|
||||
const char *command_name(struct cmd_context *cmd);
|
||||
|
||||
@@ -209,6 +209,12 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv)
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!(vg_from->status & RESIZEABLE_VG)) {
|
||||
log_error("Volume group \"%s\" is not resizeable", vg_from->name);
|
||||
unlock_vg(cmd, vg_name_from);
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!(vg_from->status & LVM_WRITE)) {
|
||||
log_error("Volume group \"%s\" is read-only", vg_from->name);
|
||||
unlock_vg(cmd, vg_name_from);
|
||||
@@ -248,6 +254,9 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv)
|
||||
vg_from->alloc, 0, NULL)))
|
||||
goto error;
|
||||
|
||||
if (vg_from->status & CLUSTERED)
|
||||
vg_to->status |= CLUSTERED;
|
||||
|
||||
/* Archive vg_from before changing it */
|
||||
if (!archive(vg_from))
|
||||
goto error;
|
||||
|
||||
Reference in New Issue
Block a user