1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-11-27 20:24:16 +03:00

Compare commits

..

5 Commits

Author SHA1 Message Date
Zdenek Kabelac
afd51f3f23 makefile: update 2025-11-26 13:02:09 +01:00
Zdenek Kabelac
90d7a77abf makefile: stop building not,should,fail,invalid
Since we have now these tools as shell function, there
is no need to build these binaries for testing.
But still keep removing them if they existed in old builds.
2025-11-26 13:02:09 +01:00
Zdenek Kabelac
d77820af6b test: implement aux/get/check/not/should/fail/invalid as shell functions
Replace external script wrappers with native bash functions to eliminate
process forking overhead. This improves test execution performance by
keeping everything in the same shell process.

Implementation:
  - Source lib/aux, lib/get, lib/check into utils.sh
  - Create dispatcher functions (aux, get, check) that call namespaced
    internal functions (__aux__*, __get__*, __check__*)
  - Add test assertion helpers: not, should, fail, invalid
  - Dispatcher functions clear environment variables (LVM_EXPECTED_EXIT_STATUS,
    LVM_LOG_FILE_EPOCH, LVM_VALGRIND) to isolate helper function execution
  - Preserve/restore shell trace state (set -x) across function calls
  - Support trace debugging via LVM_TEST_*_TRACE variables

This eliminates subshell overhead while maintaining backward compatibility
with existing test syntax.
2025-11-26 13:02:09 +01:00
Zdenek Kabelac
b44ea62c7c test: add namespace prefixes to library functions
Prefix test helper functions with `__aux__`, `__check__`, and `__get__`
to establish clear namespacing and avoid conflicts. This makes it
explicit which functions belong to the test framework internals.
2025-11-26 13:02:06 +01:00
Zdenek Kabelac
de559e4348 test: lvm-wrapper refactoring with sourcing support
Refactoring of lvm-wrapper.sh to support both direct execution
and sourcing modes.

Key changes:

Sourcing support:
- Add ability to source script to generate shell function wrappers
- Dynamically create wrapper functions for all LVM commands
- Preserve 'set -x' trace state across wrapper calls
- Eliminate bash fork overhead during test execution

Code organization:
- Introduce __lvm_command_wrapper() as core wrapper function
- Refactor command name resolution using FUNCNAME[1]
- Separate direct execution vs sourced modes

Debug improvements:
- Change LVM_VALGRIND to numeric value (0=disabled, non-zero=enabled)
- Maintain LVM_DEBUG_LEVEL filtering for selective tracing
- Disable debug tracing during command discovery

Command discovery:
- Use 'lvm help' to dynamically discover available commands
- Filter based on lib/ symlink existence
- Generate wrappers only for available commands
2025-11-26 13:01:13 +01:00
6 changed files with 677 additions and 433 deletions

View File

@@ -41,6 +41,7 @@ CLEAN_TARGETS += $(shell find -H lib -type l 2>/dev/null) \
CLEAN_TARGETS += .lib-dir-stamp .tests-stamp $(LIB) $(addprefix lib/,\
clvmd harness dmeventd dmsetup dmstats lvmpolld \
$(LIB_LINK_NOT) $(LIB_NOT) \
$(LVM_PROFILES) $(LVM_SCRIPTS) \
paths-installed paths-installed-t paths-common paths-common-t)
@@ -85,55 +86,58 @@ all: .tests-stamp
help:
@echo -e "\nAvailable targets:"
@echo " all Default target, run check."
@echo " check Run all tests."
@echo " check_system Run all tests using udev."
@echo " check_local Run tests."
@echo " check_lvmpolld Run tests with lvmpolld daemon."
@echo " check_devicesfile Run tests using a devices file."
@echo " check_all_lvmpolld Run all tests with lvmpolld daemon."
@echo " check_lvmlockd_sanlock Run tests with lvmlockd and sanlock."
@echo " check_lvmlockd_dlm Run tests with lvmlockd and dlm."
@echo " check_lvmlockd_idm Run tests with lvmlockd and idm."
@echo " check_lvmlockd_test Run tests with lvmlockd --test."
@echo " run-unit-test Run only unit tests (root not needed)."
@echo " clean Clean dir."
@echo " help Display callable targets."
@echo " all Default target, run check."
@echo " check Run all tests."
@echo " check_system Run all tests using udev."
@echo " check_local Run tests."
@echo " check_lvmpolld Run tests with lvmpolld daemon."
@echo " check_devicesfile Run tests using a devices file."
@echo " check_all_lvmpolld Run all tests with lvmpolld daemon."
@echo " check_lvmlockd_sanlock Run tests with lvmlockd and sanlock."
@echo " check_lvmlockd_dlm Run tests with lvmlockd and dlm."
@echo " check_lvmlockd_idm Run tests with lvmlockd and idm."
@echo " check_lvmlockd_test Run tests with lvmlockd --test."
@echo " run-unit-test Run only unit tests (root not needed)."
@echo " clean Clean dir."
@echo " help Display callable targets."
@echo -e "\nSupported variables:"
@echo " LVM_TEST_AUX_TRACE Set for verbose messages for aux scripts []."
@echo " LVM_TEST_BACKING_DEVICE Set device used for testing (see also LVM_TEST_DIR)."
@echo " LVM_TEST_MULTI_HOST Set multiple hosts used for testing."
@echo " LVM_TEST_CAN_CLOBBER_DMESG Allow to clobber dmesg buffer without /dev/kmsg. (1)"
@echo " LVM_TEST_DEVDIR Set to '/dev' to run on real /dev."
@echo " LVM_TEST_PREFER_BRD Prefer using brd (ramdisk) over loop for testing [1]."
@echo " LVM_TEST_DIR Where to create test files [$(LVM_TEST_DIR)]."
@echo " LVM_TEST_LOCKING Normal (1), Cluster (3)."
@echo " LVM_TEST_LVMPOLLD Start lvmpolld"
@echo " LVM_TEST_NODEBUG Do not debug lvm commands."
@echo " LVM_TEST_PARALLEL May skip aggressive wipe of LVMTEST resources."
@echo " LVM_TEST_RESULTS Where to create result files [results]."
@echo " LVM_TEST_THIN_CHECK_CMD Command for thin_check [$(LVM_TEST_THIN_CHECK_CMD)]."
@echo " LVM_TEST_THIN_DUMP_CMD Command for thin_dump [$(LVM_TEST_THIN_DUMP_CMD)]."
@echo " LVM_TEST_THIN_REPAIR_CMD Command for thin_repair [$(LVM_TEST_THIN_REPAIR_CMD)]."
@echo " LVM_TEST_THIN_RESTORE_CMD Command for thin_restore [$(LVM_TEST_THIN_RESTORE_CMD)]."
@echo " LVM_TEST_CACHE_CHECK_CMD Command for cache_check [$(LVM_TEST_CACHE_CHECK_CMD)]."
@echo " LVM_TEST_CACHE_DUMP_CMD Command for cache_dump [$(LVM_TEST_CACHE_DUMP_CMD)]."
@echo " LVM_TEST_CACHE_REPAIR_CMD Command for cache_repair [$(LVM_TEST_CACHE_REPAIR_CMD)]."
@echo " LVM_TEST_CACHE_RESTORE_CMD Command for cache_restore [$(LVM_TEST_CACHE_RESTORE_CMD)]."
@echo " LVM_TEST_UNLIMITED Set to get unlimited test log (>32MB)"
@echo " LVM_TEST_DEVICE_LIST File path listing real devs that tests can use."
@echo " LVM_VALGRIND Enable valgrind testing, execs $$"VALGRIND.
@echo " LVM_VALGRIND_DMEVENTD Enable valgrind testing of dmeventd (1)."
@echo " LVM_VALGRIND_LVMPOLLD Enable valgrind testing of lvmpolld (1)."
@echo " LVM_STRACE Enable strace logging."
@echo " LVM_DEBUG_LEVEL Sets debugging level for valgrind/strace (use > 0)."
@echo " LVM_DEBUG_LVMDBUSD Run lvmdbusd with --debug option."
@echo " LVM_LVMDBUSD_MAX_WAIT Max wait time in seconds for lvmdbus udev updates [5]."
@echo " LVM_VERIFY_UDEV Default verify state for lvm.conf."
@echo " LVM_TEST_AUX_TRACE Set for verbose messages for aux scripts [0]."
@echo " LVM_TEST_CHECK_TRACE Set for verbose messages for check scripts [0]."
@echo " LVM_TEST_GET_TRACE Set for verbose messages for get scripts [0]."
@echo " LVM_TEST_BACKING_DEVICE Set device used for testing (see also LVM_TEST_DIR)."
@echo " LVM_TEST_MULTI_HOST Set multiple hosts used for testing [0]."
@echo " LVM_TEST_FAILURE Set idm failure used for testing [0]."
@echo " LVM_TEST_CAN_CLOBBER_DMESG Allow to clobber dmesg buffer without /dev/kmsg. (1)"
@echo " LVM_TEST_DEVDIR Set to '/dev' to run on real /dev [$(LVM_TEST_DIR)/dev]."
@echo " LVM_TEST_PREFER_BRD Prefer using brd (ramdisk) over loop for testing [1]."
@echo " LVM_TEST_DIR Where to create test files [$(LVM_TEST_DIR)]."
@echo " LVM_TEST_LOCKING Normal (1), Cluster (3)."
@echo " LVM_TEST_LVMPOLLD Start lvmpolld"
@echo " LVM_TEST_NODEBUG Do not debug lvm commands."
@echo " LVM_TEST_PARALLEL May skip aggressive wipe of LVMTEST resources."
@echo " LVM_TEST_RESULTS Where to create result files [results]."
@echo " LVM_TEST_THIN_CHECK_CMD Command for thin_check [$(LVM_TEST_THIN_CHECK_CMD)]."
@echo " LVM_TEST_THIN_DUMP_CMD Command for thin_dump [$(LVM_TEST_THIN_DUMP_CMD)]."
@echo " LVM_TEST_THIN_REPAIR_CMD Command for thin_repair [$(LVM_TEST_THIN_REPAIR_CMD)]."
@echo " LVM_TEST_THIN_RESTORE_CMD Command for thin_restore [$(LVM_TEST_THIN_RESTORE_CMD)]."
@echo " LVM_TEST_CACHE_CHECK_CMD Command for cache_check [$(LVM_TEST_CACHE_CHECK_CMD)]."
@echo " LVM_TEST_CACHE_DUMP_CMD Command for cache_dump [$(LVM_TEST_CACHE_DUMP_CMD)]."
@echo " LVM_TEST_CACHE_REPAIR_CMD Command for cache_repair [$(LVM_TEST_CACHE_REPAIR_CMD)]."
@echo " LVM_TEST_CACHE_RESTORE_CMD Command for cache_restore [$(LVM_TEST_CACHE_RESTORE_CMD)]."
@echo " LVM_TEST_UNLIMITED Set to get unlimited test log (>32MB)"
@echo " LVM_TEST_DEVICE_LIST File path listing real devs that tests can use."
@echo " LVM_VALGRIND Enable valgrind testing, execs $$"VALGRIND [0].
@echo " LVM_VALGRIND_DMEVENTD Enable valgrind testing of dmeventd [0]."
@echo " LVM_VALGRIND_LVMPOLLD Enable valgrind testing of lvmpolld [0]."
@echo " LVM_STRACE Enable strace logging."
@echo " LVM_DEBUG_LEVEL Sets debugging level for valgrind/strace (use > 0) [0]."
@echo " LVM_DEBUG_LVMDBUSD Run lvmdbusd with --debug option []."
@echo " LVM_LVMDBUSD_MAX_WAIT Max wait time in seconds for lvmdbus udev updates [5]."
@echo " LVM_VERIFY_UDEV Default verify state for lvm.conf."
@echo " LVM_LOG_FILE_MAX_LINES Maximum number of logged lines for lvm2 command [1000000]."
@echo " S Skip given test(s) (regex)."
@echo " T Run given test(s) (regex)."
@echo " VERBOSE Verbose output (1), timing (2)."
@echo " S Skip given test(s) (regex)."
@echo " T Run given test(s) (regex)."
@echo " VERBOSE Verbose output (1), timing (2)."
check: .tests-stamp
VERBOSE=$(VERBOSE) ./lib/runner \
@@ -233,7 +237,7 @@ LIB_NOT := not
LIB_SHARED := check aux inittest utils get lvm-wrapper lvm_vdo_wrapper
LIB_CONF := $(LIB_LVMLOCKD_CONF) $(LIB_MKE2FS_CONF)
LIB_DATA := $(LIB_FLAVOURS) dm-version-expected version-expected
LIB_EXEC := $(LIB_NOT) dmsecuretest securetest
LIB_EXEC := dmsecuretest securetest
LVM_SCRIPTS := fsadm lvresize_fs_helper lvm_import_vdo
install: .tests-stamp lib/paths-installed
@@ -255,8 +259,6 @@ install: .tests-stamp lib/paths-installed
$(INSTALL_DATA) $(LVM_PROFILES) $(DATADIR)/lib
$(Q) cd $(DATADIR)/lib &&\
$(foreach FILE, $(CMDS), $(LN_S) -f lvm-wrapper $(FILE) $(newline))
$(Q) cd $(EXECDIR) &&\
$(foreach FILE, $(LIB_LINK_NOT), $(LN_S) -f $(LIB_NOT) $(FILE) $(newline))
$(Q) $(INSTALL_PROGRAM) -D lib/runner $(bindir)/lvm2-testsuite
lib/should lib/invalid lib/fail: lib/not
@@ -348,7 +350,7 @@ lib/dm-version-expected: $(top_srcdir)/VERSION_DM .lib-dir-stamp
$(Q) cut -f 1 -d ' ' <$< >$@
CMDS := lvm $(shell cat $(abs_top_builddir)/tools/.commands 2>/dev/null)
LIB := $(addprefix lib/, $(LVM_SCRIPTS) $(LIB_SHARED) $(LIB_LOCAL) $(LIB_EXEC) $(LIB_LINK_NOT) $(LIB_DATA))
LIB := $(addprefix lib/, $(LVM_SCRIPTS) $(LIB_SHARED) $(LIB_LOCAL) $(LIB_EXEC) $(LIB_DATA))
.tests-stamp: .lib-dir-stamp $(LIB) $(SUBDIRS)
$(SHOW) " [TESTS-STAMP]"

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env bash
# Copyright (C) 2010-2013 Red Hat, Inc. All rights reserved.
# Copyright (C) 2010-2025 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
@@ -22,43 +22,31 @@
# ...
[[ -z "$BASH" ]] || set -e -o pipefail
die() {
rm -f debug.log
echo -e "$@" >&2
return 1
}
lvl() {
__check__lvl() {
lvs -a --noheadings "$@"
}
lvdevices() {
get lv_devices "$@"
}
mirror_images_redundant() {
__check__mirror_images_redundant() {
local vg=$1
local lv="$vg/$2"
for i in $(lvdevices "$lv"); do
for i in $(__get__lv_devices "$lv"); do
echo "# $i:"
lvdevices "$vg/$i" | sort -u
__get__lv_devices "$vg/$i" | sort -u
done > check.tmp.all
(grep -v ^# check.tmp.all || true) | sort | uniq -d > check.tmp
(grep -v '^#' check.tmp.all || true) | sort | uniq -d > check.tmp
[[ "$(wc -l < check.tmp)" -eq 0 ]] || \
die "mirror images of $lv expected redundant, but are not:" \
"$(cat check.tmp.all)"
}
lv_err_list_() {
__check__lv_err_list_() {
(echo "$2" | not grep -m 1 -q "$1") || \
echo "$3 on [ $(echo "$2" | grep "$1" | cut -b3- | tr '\n' ' ')] "
}
lv_on_diff_() {
__check__lv_on_diff_() {
declare -a xdevs=("${!1}") # pass in shell array
local expect=( "${@:4}" ) # make an array starting from 4th args...
local diff_e
@@ -67,32 +55,32 @@ lv_on_diff_() {
printf "%s\\n" "${expect[@]}" | sort -u >_lv_on_diff1
printf "%s\\n" "${xdevs[@]}" >_lv_on_diff2
diff_e=$(diff _lv_on_diff1 _lv_on_diff2) ||
die "LV $2/$3 $(lv_err_list_ "^>" "${diff_e}" found)$(lv_err_list_ "^<" "${diff_e}" "not found")."
die "LV $2/$3 $(__check__lv_err_list_ "^>" "${diff_e}" found)$(__check__lv_err_list_ "^<" "${diff_e}" "not found")."
}
# list devices for given LV
lv_on() {
__check__lv_on() {
local devs
devs=( $(lvdevices "$1/$2" | sort -u ) )
devs=( $(__get__lv_devices "$1/$2" | sort -u) ) || true
lv_on_diff_ devs[@] "$@"
__check__lv_on_diff_ devs[@] "$@"
}
# list devices for given LV and all its subdevices
lv_tree_on() {
__check__lv_tree_on() {
local devs
# Get sorted list of devices
devs=( $(get lv_tree_devices "$1" "$2") )
devs=( $(__get__lv_tree_devices "$1" "$2") ) || true
lv_on_diff_ devs[@] "$@"
__check__lv_on_diff_ devs[@] "$@"
}
# Test if all mimage_X LV legs are sitting on given ordered list of PVs
# When LV is composed of imagetmp, such leg is decomposed so only
# real _mimage LVs are always checked
mirror_images_on() {
__check__mirror_images_on() {
local vg=$1
local lv=$2
shift 2
@@ -104,57 +92,57 @@ mirror_images_on() {
done < <( get lv_field_lv_ "$vg" lv_name -a | grep "${lv}_mimage_" )
for i in "${mimages[@]}"; do
lv_on "$vg" "$i" "$1"
__check__lv_on "$vg" "$i" "$1"
shift
done
}
mirror_log_on() {
__check__mirror_log_on() {
local vg=$1
local lv=$2
local where=$3
if [[ "$where" = "core" ]]; then
get lv_field "$vg/$lv" mirror_log | not grep mlog
else
lv_on "$vg" "${lv}_mlog" "$where"
__check__lv_on "$vg" "${lv}_mlog" "$where"
fi
}
lv_is_contiguous() {
__check__lv_is_contiguous() {
local lv="$1/$2"
[[ "$(lvl --segments "$lv" | wc -l)" -eq 1 ]] || \
[[ "$(__check__lvl --segments "$lv" | wc -l)" -eq 1 ]] || \
die "LV $lv expected to be contiguous, but is not:" \
"$(lvl --segments "$lv")"
"$(__check__lvl --segments "$lv")"
}
lv_is_clung() {
__check__lv_is_clung() {
local lv="$1/$2"
[[ "$(lvdevices "$lv" | sort -u | wc -l)" -eq 1 ]] || \
[[ "$(__get__lv_devices "$lv" | sort -u | wc -l)" -eq 1 ]] || \
die "LV $lv expected to be clung, but is not:" \
"$(lvdevices "$lv" | sort -u)"
"$(__get__lv_devices "$lv" | sort -u)"
}
mirror_images_contiguous() {
for i in $(lvdevices "$1/$2"); do
lv_is_contiguous "$1" "$i"
__check__mirror_images_contiguous() {
for i in $(__get__lv_devices "$1/$2"); do
__check__lv_is_contiguous "$1" "$i"
done
}
mirror_images_clung() {
for i in $(lvdevices "$1/$2"); do
lv_is_clung "$1" "$i"
__check__mirror_images_clung() {
for i in $(__get__lv_devices "$1/$2"); do
__check__lv_is_clung "$1" "$i"
done
}
mirror() {
mirror_nonredundant "$@"
mirror_images_redundant "$1" "$2"
__check__mirror() {
__check__mirror_nonredundant "$@"
__check__mirror_images_redundant "$1" "$2"
}
mirror_nonredundant() {
__check__mirror_nonredundant() {
local lv="$1/$2"
local attr
attr=$(get lv_field "$lv" attr)
attr=$(__get__lv_field "$lv" attr)
(echo "$attr" | grep "^......m...$" >/dev/null) || {
if (echo "$attr" | grep "^o.........$" >/dev/null) &&
lvs -a "$1" | grep -F "[${2}_mimage" >/dev/null; then
@@ -165,32 +153,32 @@ mirror_nonredundant() {
"$(lvs "$lv")"
fi
}
[[ -z "$3" ]] || mirror_log_on "$1" "$2" "$3"
[[ -z "${3-}" ]] || __check__mirror_log_on "$1" "$2" "$3"
}
mirror_legs() {
__check__mirror_legs() {
local expect_legs=$3
[[ "$expect_legs" -eq "$(lvdevices "$1/$2" | wc -w)" ]]
[[ "$expect_legs" -eq "$(__get__lv_devices "$1/$2" | wc -w)" ]]
}
mirror_no_temporaries() {
__check__mirror_no_temporaries() {
local vg=$1
local lv=$2
(lvl -o name "$vg" | grep "$lv" | not grep "tmp") || \
die "$lv has temporary mirror images unexpectedly:" \
"$(lvl "$vg" | grep "$lv")"
(__check__lvl -o name "$vg" | grep "$lv" | not grep "tmp") || \
die "$lv has temporary __check__mirror images unexpectedly:" \
"$(__check__lvl "$vg" | grep "$lv")"
}
linear() {
__check__linear() {
local lv="$1/$2"
[[ "$(get lv_field "$lv" stripes -a)" -eq 1 ]] || \
[[ "$(__get__lv_field "$lv" stripes -a)" -eq 1 ]] || \
die "$lv expected linear, but is not:" \
"$(lvl "$lv" -o+devices)"
"$(__check__lvl "$lv" -o+devices)"
}
# check in_sync <VG> <LV> <ignore 'a'>
# Works for "mirror" and "raid*"
in_sync() {
__check__in_sync() {
local a
local b
local c
@@ -249,26 +237,26 @@ in_sync() {
echo "$lvm_name ($type$snap) is in-sync " "${a[@]}"
}
active() {
__check__active() {
local lv="$1/$2"
(get lv_field "$lv" attr | grep "^....a.....$" >/dev/null) || \
die "$lv expected active, but lvs says it's not:" \
"$(lvl "$lv" -o+devices)"
"$(__check__lvl "$lv" -o+devices)"
dmsetup info "$1-$2" >/dev/null ||
die "$lv expected active, lvs thinks it is but there are no mappings!"
}
inactive() {
__check__inactive() {
local lv="$1/$2"
(get lv_field "$lv" attr | grep "^....[-isd].....$" >/dev/null) || \
die "$lv expected inactive, but lvs says it's not:" \
"$(lvl "$lv" -o+devices)"
"$(__check__lvl "$lv" -o+devices)"
not dmsetup info "$1-$2" 2>/dev/null || \
die "$lv expected inactive, lvs thinks it is but there are mappings!"
}
# Check for list of LVs from given VG
lv_exists() {
__check__lv_exists() {
local vg=$1
declare -a list=()
while [ $# -gt 1 ]; do
@@ -276,43 +264,43 @@ lv_exists() {
list+=( "$vg/$1" )
done
[[ "${#list[@]}" -gt 0 ]] || list=( "$vg" )
lvl "${list[@]}" &>/dev/null || \
__check__lvl "${list[@]}" &>/dev/null || \
die "${list[@]}" "expected to exist, but does not!"
}
lv_not_exists() {
__check__lv_not_exists() {
local vg=$1
if [[ $# -le 1 ]]; then
if lvl "$vg" &>/dev/null ; then
if __check__lvl "$vg" &>/dev/null ; then
die "$vg expected to not exist but it does!"
fi
else
while [ $# -gt 1 ]; do
shift
lvl "$vg/$1" &>/dev/null && die "$vg/$1 expected to not exist but it does!"
__check__lvl "$vg/$1" &>/dev/null && die "$vg/$1 expected to not exist but it does!"
done
fi
rm -f debug.log
}
pv_field() {
__check__pv_field() {
local actual
actual=$(get pv_field "$1" "$2" "${@:4}")
actual=$(__get__pv_field "$1" "$2" "${@:4}")
[[ "$actual" = "$3" ]] || \
die "pv_field: PV=\"$1\", field=\"$2\", actual=\"$actual\", expected=\"$3\""
}
vg_field() {
__check__vg_field() {
local actual
actual=$(get vg_field "$1" "$2" "${@:4}")
actual=$(__get__vg_field "$1" "$2" "${@:4}")
[[ "$actual" = "$3" ]] || \
die "vg_field: vg=$1, field=\"$2\", actual=\"$actual\", expected=\"$3\""
}
vg_attr_bit() {
__check__vg_attr_bit() {
local actual
local offset=$1
actual=$(get vg_field "$2" vg_attr "${@:4}")
actual=$(__get__vg_field "$2" vg_attr "${@:4}")
case "$offset" in
perm*) offset=0 ;;
resiz*) offset=1 ;;
@@ -325,38 +313,38 @@ vg_attr_bit() {
die "vg_attr_bit: vg=$2, ${offset} bit of \"$actual\" is \"${actual:$offset:1}\", but expected \"$3\""
}
lv_field() {
__check__lv_field() {
local actual
actual=$(get lv_field "$1" "$2" "${@:4}")
actual=$(__get__lv_field "$1" "$2" "${@:4}")
[[ "$actual" = "$3" ]] || \
die "lv_field: lv=$1, field=\"$2\", actual=\"$actual\", expected=\"$3\""
}
lv_first_seg_field() {
__check__lv_first_seg_field() {
local actual
actual=$(get lv_first_seg_field "$1" "$2" "${@:4}")
actual=$(__get__lv_first_seg_field "$1" "$2" "${@:4}")
[[ "$actual" = "$3" ]] || \
die "lv_field: lv=$1, field=\"$2\", actual=\"$actual\", expected=\"$3\""
}
lvh_field() {
__check__lvh_field() {
local actual
actual=$(get lvh_field "$1" "$2" "${@:4}")
actual=$(__get__lvh_field "$1" "$2" "${@:4}")
[[ "$actual" = "$3" ]] || \
die "lvh_field: lv=$1, field=\"$2\", actual=\"$actual\", expected=\"$3\""
}
lva_field() {
__check__lva_field() {
local actual
actual=$(get lva_field "$1" "$2" "${@:4}")
actual=$(__get__lva_field "$1" "$2" "${@:4}")
[[ "$actual" = "$3" ]] || \
die "lva_field: lv=$1, field=\"$2\", actual=\"$actual\", expected=\"$3\""
}
lv_attr_bit() {
__check__lv_attr_bit() {
local actual
local offset=$1
actual=$(get lv_field "$2" lv_attr "${@:4}")
actual=$(__get__lv_field "$2" lv_attr "${@:4}")
case "$offset" in
type) offset=0 ;;
perm*) offset=1 ;;
@@ -373,7 +361,7 @@ lv_attr_bit() {
die "lv_attr_bit: lv=$2, ${offset} bit of \"$actual\" is \"${actual:$offset:1}\", but expected \"$3\""
}
compare_fields() {
__check__compare_fields() {
local cmd1=$1
local obj1=$2
local field1=$3
@@ -385,10 +373,10 @@ compare_fields() {
val1=$("$cmd1" --noheadings -o "$field1" "$obj1")
val2=$("$cmd2" --noheadings -o "$field2" "$obj2")
[[ "$val1" = "$val2" ]] || \
die "compare_fields $obj1($field1): $val1 $obj2($field2): $val2"
die "__check__compare_fields $obj1($field1): $val1 $obj2($field2): $val2"
}
compare_vg_field() {
__check__compare_vg_field() {
local vg1=$1
local vg2=$2
local field=$3
@@ -400,7 +388,7 @@ compare_vg_field() {
die "compare_vg_field: $vg1: $val1, $vg2: $val2"
}
pvlv_counts() {
__check__pvlv_counts() {
local local_vg=$1
local num_pvs=$2
local num_lvs=$3
@@ -416,13 +404,13 @@ pvlv_counts() {
}
# Compare md5 check generated from get dev_md5sum
dev_md5sum() {
__check__dev_md5sum() {
md5sum -c "md5.$1-$2" || \
(get lv_field "$1/$2" "name,size,seg_pe_ranges"
die "LV $1/$2 has different MD5 check sum!")
}
sysfs() {
__check__sysfs() {
# read maj min and also convert hex to decimal
local maj
local min
@@ -437,7 +425,7 @@ sysfs() {
}
# check raid_leg_status $vg $lv "Aaaaa"
raid_leg_status() {
__check__raid_leg_status() {
local st
local val
@@ -458,16 +446,12 @@ raid_leg_status() {
die "$1-$2 status ${st[5]} != $3 (${st[*]})"
}
grep_dmsetup() {
__check__grep_dmsetup() {
dmsetup "$1" "$2" | tee out
grep -q "${@:3}" out || die "Expected output \"" "${@:3}" "\" from dmsetup $1 not found!"
}
grep_lvmlockd_dump() {
__check__grep_lvmlockd_dump() {
lvmlockctl --dump | tee out
grep -q "${@:1}" out || die "Expected output \"" "${@:1}" "\" from lvmlockctl --dump not found!"
}
#set -x
unset LVM_VALGRIND
"$@"

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env bash
# Copyright (C) 2011-2017 Red Hat, Inc. All rights reserved.
# Copyright (C) 2011-2025 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
@@ -18,105 +18,97 @@
#
# get lv_devices LV [lvs params]
test -z "$BASH" || set -e -o pipefail
# trims only leading prefix and suffix
trim_() {
rm -f debug.log # drop log, command was ok
__get__trim_() {
local var=${1%"${1##*[! ]}"} # remove trailing space characters
echo "${var#"${var%%[! ]*}"}" # remove leading space characters
}
pv_field() {
__get__pv_field() {
local r
r=$(pvs --config 'log{prefix=""}' --noheadings -o "$2" "${@:3}" "$1")
trim_ "$r"
__get__trim_ "$r"
}
vg_field() {
__get__vg_field() {
local r
r=$(vgs --config 'log{prefix=""}' --noheadings -o "$2" "${@:3}" "$1")
trim_ "$r"
__get__trim_ "$r"
}
lv_field() {
__get__lv_field() {
local r
r=$(lvs --config 'log{prefix=""}' --noheadings -o "$2" "${@:3}" "$1")
trim_ "$r"
__get__trim_ "$r"
}
lv_first_seg_field() {
__get__lv_first_seg_field() {
local r
read -r r < <(lvs --config 'log{prefix=""}' --unbuffered --noheadings -o "$2" "${@:3}" "$1")
trim_ "$r"
__get__trim_ "$r"
}
lvh_field() {
__get__lvh_field() {
local r
r=$(lvs -H --config 'log{prefix=""}' --noheadings -o "$2" "${@:3}" "$1")
trim_ "$r"
__get__trim_ "$r"
}
lva_field() {
__get__lva_field() {
local r
r=$(lvs -a --config 'log{prefix=""}' --noheadings -o "$2" "${@:3}" "$1")
trim_ "$r"
__get__trim_ "$r"
}
lv_devices() {
lv_field "$1" devices -a "${@:2}" | sed 's/([^)]*)//g; s/,/\n/g'
__get__lv_devices() {
__get__lv_field "$1" devices -a "${@:2}" | sed 's/([^)]*)//g; s/,/\n/g'
}
lv_field_lv_() {
lv_field "$1" "$2" -a --unbuffered | tr -d '[]'
__get__lv_field_lv_() {
__get__lv_field "$1" "$2" -a --unbuffered | tr -d '[]'
}
lv_tree_devices_() {
__get__lv_tree_devices_() {
local lv="$1/$2"
local type
type=$(lv_first_seg_field "$lv" segtype -a)
type=$(__get__lv_first_seg_field "$lv" segtype -a)
#local orig
#orig=$(lv_field_lv_ "$lv" origin)
#orig=$(__get__lv_field_lv_ "$lv" origin)
# FIXME: should we count in also origins ?
#test -z "$orig" || lv_tree_devices_ $1 $orig
#test -z "$orig" || __get__lv_tree_devices_ $1 $orig
case "$type" in
linear|striped)
lv_devices "$lv"
__get__lv_devices "$lv"
;;
mirror|raid*)
local log
log=$(lv_field_lv_ "$lv" mirror_log)
test -z "$log" || lv_tree_devices_ "$1" "$log"
for i in $(lv_devices "$lv"); do
lv_tree_devices_ "$1" "$i"
log=$(__get__lv_field_lv_ "$lv" mirror_log)
test -z "$log" || __get__lv_tree_devices_ "$1" "$log"
for i in $(__get__lv_devices "$lv"); do
__get__lv_tree_devices_ "$1" "$i"
done
;;
thin)
lv_tree_devices_ "$1" "$(lv_field_lv_ "$lv" pool_lv)"
__get__lv_tree_devices_ "$1" "$(__get__lv_field_lv_ "$lv" pool_lv)"
;;
thin-pool)
lv_tree_devices_ "$1" "$(lv_field_lv_ "$lv" data_lv)"
lv_tree_devices_ "$1" "$(lv_field_lv_ "$lv" metadata_lv)"
__get__lv_tree_devices_ "$1" "$(__get__lv_field_lv_ "$lv" data_lv)"
__get__lv_tree_devices_ "$1" "$(__get__lv_field_lv_ "$lv" metadata_lv)"
;;
cache)
lv_tree_devices_ "$1" "$(lv_devices "$lv")"
__get__lv_tree_devices_ "$1" "$(__get__lv_devices "$lv")"
;;
cache-pool)
lv_tree_devices_ "$1" "$(lv_field_lv_ "$lv" data_lv)"
lv_tree_devices_ "$1" "$(lv_field_lv_ "$lv" metadata_lv)"
__get__lv_tree_devices_ "$1" "$(__get__lv_field_lv_ "$lv" data_lv)"
__get__lv_tree_devices_ "$1" "$(__get__lv_field_lv_ "$lv" metadata_lv)"
;;
esac
}
lv_tree_devices() {
lv_tree_devices_ "$@" | sort -u
__get__lv_tree_devices() {
__get__lv_tree_devices_ "$@" | sort -u
}
first_extent_sector() {
pv_field "$@" pe_start --units s --nosuffix
__get__first_extent_sector() {
__get__pv_field "$@" pe_start --units s --nosuffix
}
#set -x
unset LVM_VALGRIND
unset LVM_LOG_FILE_EPOCH
"$@"

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env bash
# Copyright (C) 2011-2017 Red Hat, Inc.
# Copyright (C) 2011-2025 Red Hat, Inc.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
@@ -9,41 +9,174 @@
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
. lib/paths
#
# LVM Command Wrapper for Test Suite
# ===================================
#
# This wrapper provides efficient LVM command execution for the test suite by:
# - Avoiding bash fork overhead through shell function wrapping
# - Supporting debug tools (GDB, Valgrind, strace)
# - Working in both build-time and installed test environments
# - Dynamically generating wrapper functions for LVM commands
#
# Usage:
# Source this script to get LVM command wrappers (lvcreate, pvs, vgs, etc.)
# Run directly to execute a single LVM command via wrapper
#
CMD=${0##*/}
[[ "$CMD" != lvm ]] || unset CMD
#
# __lvm_command_wrapper - Core wrapper function for LVM command execution
#
# This function is called by all generated LVM command wrappers (lvcreate, pvs, etc.)
# It determines which LVM command to execute and handles debug environments.
#
# Command name resolution:
# - When sourced: Uses FUNCNAME[1] to get calling function name
# - When executed directly: Uses script basename
# - Special cases where command is passed as $1:
# * lvm() function: enables "lvm <command>" syntax
# * Internal use: FUNCNAME[1]="source" during wrapper generation
#
# Debug environment support:
# - LVM_GDB: Run command under GDB debugger
# - LVM_VALGRIND: Numeric value, non-zero enables Valgrind (filtered by LVM_DEBUG_LEVEL)
# - LVM_STRACE: Run command under strace with specified options
# - LVM_DEBUG_LEVEL: Controls which commands get traced (0=none, 1=modifiers, 2=all)
#
# Note: Trace disable/restore for 'set -x' is handled in generated wrapper functions
#
__lvm_command_wrapper() {
# Initialize variables with defaults for sourced mode
local CMD=${FUNCNAME[1]} # Calling function name (e.g., lvcreate, pvs)
local EXEC= # Empty - no exec needed when sourced
local CALL=()
local RUN_DBG=
# When needed to trace command from test suite use env var before program
# and run program directly via shell in test dir i.e.:
# sh shell/activate-mirror.sh
# 'LVM_GDB=1 lvcreate -l1 $vg'
# > run
[[ -z "$LVM_GDB" ]] || exec gdb --readnow --args "$abs_top_builddir/tools/lvm" $CMD "$@"
# Override defaults if script is executed directly (not sourced)
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
CMD=${0##*/} # Use script basename as command name
EXEC=exec # Use exec to replace shell process
fi
# Multiple level of LVM_VALGRIND support
# the higher level the more commands are traced
[[ -n "$LVM_VALGRIND" ]] && RUN_DBG="${VALGRIND:-valgrind}";
# Special handling: extract actual command from $1
# - Called via lvm() function: enables "lvm <command>" syntax
# - Called during sourcing: FUNCNAME[1]="source" for command discovery
if [[ "$CMD" = "lvm" || "$CMD" = "source" ]]; then
CMD=$1
shift
fi
[[ -n "$LVM_STRACE" ]] && RUN_DBG="strace $LVM_STRACE -o strace.log"
#
# Debug mode: GDB
#
# When LVM_GDB is set, run command under GDB debugger.
# Usage from test:
# LVM_GDB=1 sh shell/test-name.sh
# Then in gdb prompt: run
#
if [[ -n "${LVM_GDB-}" ]]; then
$EXEC gdb --readnow --args "$abs_top_builddir/tools/lvm" "$CMD" "$@"
return
fi
case "$CMD" in
lvs|pvs|vgs|vgck|vgscan)
[[ "${LVM_DEBUG_LEVEL:-0}" -lt 2 ]] && RUN_DBG="" ;;
pvcreate|pvremove|lvremove|vgcreate|vgremove)
[[ "${LVM_DEBUG_LEVEL:-0}" -lt 1 ]] && RUN_DBG="" ;;
esac
#
# Debug mode: Valgrind/strace setup
#
# Configure debug tool based on environment variables.
# Debug level filtering prevents excessive tracing of read-only commands.
#
# Valgrind: Enabled when LVM_VALGRIND is non-zero
# Uses VALGRIND variable if set, otherwise defaults to 'valgrind'
[[ "${LVM_VALGRIND:-0}" -ne 0 ]] && RUN_DBG="${VALGRIND:-valgrind}"
# Capture parallel users of debug.log file
#test -z "$(fuser debug.log 2>/dev/null)" || {
# echo "TEST WARNING: \"debug.log\" is still in use while running $CMD $@" >&2
# fuser -v debug.log >&2
#}
# Strace: Enabled when LVM_STRACE is set (overrides Valgrind if both set)
[[ -n "${LVM_STRACE-}" ]] && RUN_DBG="strace $LVM_STRACE -o strace.log"
# Filter debug tracing based on LVM_DEBUG_LEVEL
# Level 0 (default): No tracing
# Level 1: Trace modifying commands only (pvcreate, vgremove, etc.)
# Level 2+: Trace all commands including read-only (lvs, pvs, vgs, etc.)
case "${CMD-}" in
lvs|pvs|vgs|vgck|vgscan)
# Read-only commands - only trace at level 2+
[[ "${LVM_DEBUG_LEVEL:-0}" -lt 2 ]] && RUN_DBG="" ;;
pvcreate|pvremove|lvremove|vgcreate|vgremove)
# Modifying commands - only trace at level 1+
[[ "${LVM_DEBUG_LEVEL:-0}" -lt 1 ]] && RUN_DBG="" ;;
esac
# the exec is important, because otherwise fatal signals inside "not" go unnoticed
if [[ -n "$abs_top_builddir" ]]; then
exec $RUN_DBG "$abs_top_builddir/tools/lvm" $CMD "$@"
else # we are testing the lvm on $PATH
PATH=$(echo "$PATH" | sed -e 's,[^:]*lvm2-testsuite[^:]*:,,g')
exec $RUN_DBG lvm $CMD "$@"
#
# Determine LVM binary path
#
# Build directory testing: Use $abs_top_builddir/tools/lvm
# Installed testsuite: Use system 'lvm' command
#
if [[ -n "${abs_top_builddir-}" ]]; then
CALL=( "$abs_top_builddir/tools/lvm" )
else
CALL=( "command" "lvm" )
fi
# Execute the LVM command with optional debug wrapper
$EXEC $RUN_DBG "${CALL[@]}" "$CMD" "$@"
}
#
# Script execution mode handling
#
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
#
# Direct execution mode
#
# Script is being run directly (not sourced).
# Load paths and execute the requested command via wrapper.
#
. lib/paths
__lvm_command_wrapper "$@"
else
#
# Source mode - Generate LVM command wrapper functions
#
# When sourced, this script dynamically creates wrapper functions for all
# LVM commands. Each wrapper function:
# 1. Preserves and temporarily disables 'set -x' trace mode if active
# 2. Calls __lvm_command_wrapper with the command arguments
# 3. Restores the original trace mode state
#
# This approach avoids bash fork overhead.
#
#
# Discover available LVM commands
#
# Query available commands using '__lvm_command_wrapper help'.
# This ensures proper path handling for both build directory and installed scenarios.
# LVM_VALGRIND=0 disables debug tracing during command discovery.
#
__lvm_cmd=
__lvm_rest=
__lvm_cmds=( lvm )
while read -r __lvm_cmd __lvm_rest; do
# Filter: only commands starting with lowercase letter
# and only if corresponding symlink exists in lib/ directory
[[ "$__lvm_cmd" =~ ^[a-z] && -e "lib/$__lvm_cmd" ]] && __lvm_cmds+=("$__lvm_cmd")
done < <(LVM_VALGRIND=0 __lvm_command_wrapper help 2>&1)
#
# Generate wrapper function for each LVM command
#
# Creates functions like lvm(), lvcreate(), pvs(), vgs(), etc.
# Each function preserves trace state, calls the wrapper, and restores state.
#
for __lvm_cmd in "${__lvm_cmds[@]}"; do
eval "${__lvm_cmd}() {
{ local r=0; case \$- in *x*) r=1; set +x ;; esac; } 2>/dev/null
__lvm_command_wrapper \"\$@\"
local s=\$?
{ [[ \"\$r\" -eq 0 ]] || set -x; return \$s; } 2>/dev/null
}"
done
# Clean up temporary variables
unset __lvm_cmd __lvm_rest __lvm_cmds
fi

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env bash
# Copyright (C) 2011-2012 Red Hat, Inc. All rights reserved.
# Copyright (C) 2011-2025 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
@@ -20,6 +20,148 @@ die() {
return 1
}
# Source test library functions with internal namespacing
. lib/aux
. lib/get
. lib/check
. lib/lvm-wrapper
# Create dispatcher functions to maintain backward compatibility
# and provide namespace protection. Functions are called as:
# aux function_name args...
# get function_name args...
# check function_name args...
# which internally call __aux__function_name, __get__function_name, __check__function_name
#
# Each dispatcher unsets variables that should not affect the helper functions
# (matching behavior of old wrapper scripts)
aux() {
{ local r=0; case $- in *x*) r=1; set +x ;; esac; } 2>/dev/null
# Clear LVM_EXPECTED_EXIT_STATUS so nested calls work normally
local LVM_EXPECTED_EXIT_STATUS
local LVM_LOG_FILE_EPOCH=
local LVM_VALGRIND=
local devs
[[ -f DEVICES ]] && devs=( $(< DEVICES) ) || true
local s=0
local cmd="__aux__$1"
# Check if function exists, otherwise run command directly
declare -f "$cmd" >/dev/null 2>&1 || cmd=$1
# Only restore trace if explicitly requested via LVM_TEST_AUX_TRACE
[[ "${LVM_TEST_AUX_TRACE:-0}" != 0 ]] && set -x
"$cmd" "${@:2}" || s=$?
{ [[ "$r" -eq 0 ]] || set -x; return "$s"; } 2>/dev/null
}
get() {
{ local r=0; case $- in *x*) r=1; set +x ;; esac; } 2>/dev/null
# Clear LVM_EXPECTED_EXIT_STATUS so nested calls work normally
local LVM_EXPECTED_EXIT_STATUS
local LVM_LOG_FILE_EPOCH=
local LVM_VALGRIND=
local s=0
# Set trace if explicitly requested
[[ "${LVM_TEST_GET_TRACE:-0}" != 0 ]] && set -x
"__get__$1" "${@:2}" || s=$?
{ [[ "$r" -eq 0 ]] || set -x; return "$s"; } 2>/dev/null
}
check() {
{ local r=0; case $- in *x*) r=1; set +x ;; esac; } 2>/dev/null
# Clear LVM_EXPECTED_EXIT_STATUS so nested calls work normally
local LVM_EXPECTED_EXIT_STATUS
local LVM_LOG_FILE_EPOCH=
local LVM_VALGRIND=
local s=0
# Restore trace if explicitly requested
[[ "${LVM_TEST_CHECK_TRACE:-0}" != 0 ]] && set -x
"__check__$1" "${@:2}" || s=$?
{ [[ "$r" -eq 0 ]] || set -x; return "$s"; } 2>/dev/null
}
fail() {
{ local r=0; case $- in *x*) r=1; set +x ;; esac; } 2>/dev/null
local s=0
#local debug_files="debug.log*"
#[[ "$debug_files" = "debug.log*" ]] || rm -f debug.log*
LVM_EXPECTED_EXIT_STATUS=5 "$@" || s=$?
if [[ "$s" -ne 5 ]]; then
echo "Test expected fail exit code 5, but got $s." >&2
{ [[ "$r" -eq 0 ]] || set -x; return 1; } 2>/dev/null
fi
{ [[ "$r" -eq 0 ]] || set -x; return 0; } 2>/dev/null
}
invalid() {
{ local r=0; case $- in *x*) r=1; set +x ;; esac; } 2>/dev/null
local s=0
#local debug_files="debug.log*"
#[[ "$debug_files" = "debug.log*" ]] || rm -f debug.log*
LVM_EXPECTED_EXIT_STATUS=3 "$@" || s=$?
if [[ "$s" -ne 3 ]]; then
echo "Test expected invalid exit code 3, but got $s." >&2
{ [[ "$r" -eq 0 ]] || set -x; return 1; } 2>/dev/null
fi
{ [[ "$r" -eq 0 ]] || set -x; return 0; } 2>/dev/null
}
not() {
{ local r=0; case $- in *x*) r=1; set +x ;; esac; } 2>/dev/null
local s=0
#local debug_files="debug.log*"
#[[ "$debug_files" = "debug.log*" ]] || rm -f debug.log*
LVM_EXPECTED_EXIT_STATUS=">1" "$@" || s=$?
if [[ "$s" -eq 0 ]]; then
echo "Test not expected success exit code." >&2
{ [[ "$r" -eq 0 ]] || set -x; return 1; } 2>/dev/null
fi
{ [[ "$r" -eq 0 ]] || set -x; return 0; } 2>/dev/null
}
should() {
{ local r=0; case $- in *x*) r=1; set +x ;; esac; } 2>/dev/null
#rm -f debug.log*
if ! "$@"; then
echo "TEST WARNING: Ignoring command failure." >&2
local pattern="debug.log*${LVM_LOG_FILE_EPOCH}*"
# Use glob expansion to check if any files match
local files=( $pattern )
if [[ -e "${files[0]}" ]]; then
echo "## timing off"
echo "<======== Debug log ========>"
sed -e 's,^,## SHOULD DEBUG: ,' "${files[@]}" 2>/dev/null || true
echo "## timing on"
rm -f "$pattern" || true
fi
fi
{ [[ "$r" -eq 0 ]] || set -x; return 0; } 2>/dev/null
}
rand_bytes() {
n=$1