# Copyright (C) 2008 Red Hat, Inc. All rights reserved. # # This copyrighted material is made available to anyone wishing to use, # modify, copy, or redistribute it subject to the terms and conditions # of the GNU General Public License v.2. # # 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 aux() { # use just "$@" for verbose operation "$@" > /dev/null 2> /dev/null #"$@" } STACKTRACE() { trap - ERR; i=0; while FUNC=${FUNCNAME[$i]}; test "$FUNC" != "main"; do echo "$i ${FUNC}() called from ${BASH_SOURCE[$i]}:${BASH_LINENO[$i]}" i=$(($i + 1)); done # Get backtraces from coredumps TEST_LVM_BINARY=$(dirname $(which lvm))/../../tools/lvm if which gdb >& /dev/null; then echo bt full > gdb_commands.txt echo l >> gdb_commands.txt echo quit >> gdb_commands.txt for core in core*; do bin=$(gdb -batch -c $core 2>&1 | grep "generated by" | \ sed -e "s,.*generated by \`\([^ ']*\).*,\1,") gdb -batch -c $core -x gdb_commands.txt `which $bin` done fi } init_udev_transaction() { if test "$DM_UDEV_SYNCHRONISATION" = 1; then COOKIE=$(dmsetup udevcreatecookie) # Cookie is not generated if udev is not running! if test -n "$COOKIE"; then export DM_UDEV_COOKIE=$COOKIE fi fi } finish_udev_transaction() { if test "$DM_UDEV_SYNCHRONISATION" = 1 -a -n "$DM_UDEV_COOKIE"; then dmsetup udevreleasecookie unset DM_UDEV_COOKIE fi } prepare_clvmd() { if test -z "$LVM_TEST_LOCKING" || test "$LVM_TEST_LOCKING" -ne 3 ; then return 0 # not needed fi if pgrep clvmd ; then echo "Cannot use fake cluster locking with real clvmd ($(pgrep clvmd)) running." exit 200 fi # skip if we don't have our own clvmd... (which clvmd | grep $abs_builddir) || exit 200 trap_teardown clvmd -Isinglenode -d 1 & LOCAL_CLVMD="$!" } prepare_dmeventd() { if pgrep dmeventd ; then echo "Cannot test dmeventd with real dmeventd ($(pgrep clvmd)) running." exit 200 fi # skip if we don't have our own dmeventd... (which dmeventd | grep $abs_builddir) || exit 200 trap_teardown dmeventd -d & LOCAL_DMEVENTD="$!" strace -p $LOCAL_DMEVENTD & } prepare_testroot() { OLDPWD="`pwd`" PREFIX="LVMTEST$$" trap_teardown TESTDIR=$($abs_srcdir/mkdtemp ${LVM_TEST_DIR-$(pwd)} $PREFIX.XXXXXXXXXX) \ || { echo "failed to create temporary directory in $test_dir_"; exit 1; } export LVM_SYSTEM_DIR=$TESTDIR/etc export DM_DEV_DIR=$TESTDIR/dev mkdir $LVM_SYSTEM_DIR $DM_DEV_DIR $DM_DEV_DIR/mapper $TESTDIR/lib cd $TESTDIR for i in `find $abs_top_builddir/daemons/dmeventd/plugins/ -name \*.so`; do echo Setting up symlink from $i to $TESTDIR/lib ln -s $i $TESTDIR/lib done } teardown_devs() { test -n "$PREFIX" && { rm -rf $TESTDIR/dev/$PREFIX* init_udev_transaction while dmsetup table | grep -q ^$PREFIX; do for s in `dmsetup info -c -o name --noheading | grep ^$PREFIX`; do dmsetup remove $s >& /dev/null || true done done finish_udev_transaction } # NOTE: SCSI_DEBUG_DEV test must come before the LOOP test because # prepare_scsi_debug_dev() also sets LOOP to short-circuit prepare_loop() if [ -n "$SCSI_DEBUG_DEV" ] ; then modprobe -r scsi_debug else test -n "$LOOP" && losetup -d $LOOP test -n "$LOOPFILE" && rm -f $LOOPFILE fi unset devs # devs is set in prepare_devs() } teardown() { echo $LOOP echo $PREFIX test -n "$LOCAL_CLVMD" && { kill "$LOCAL_CLVMD" sleep .1 kill -9 "$LOCAL_CLVMD" || true } test -n "$LOCAL_DMEVENTD" && kill -9 "$LOCAL_DMEVENTD" teardown_devs test -n "$TESTDIR" && { cd $OLDPWD rm -rf $TESTDIR || echo BLA } } trap_teardown() { trap 'set +vx; STACKTRACE; set -vx' ERR trap 'aux teardown' EXIT # don't forget to clean up } make_ioerror() { echo 0 10000000 error | dmsetup create ioerror ln -s $DM_DEV_DIR/mapper/ioerror $DM_DEV_DIR/ioerror } prepare_loop() { size=$1 test -n "$size" || size=32 # skip if prepare_scsi_debug_dev() was used if [ -n "$SCSI_DEBUG_DEV" -a -n "$LOOP" ]; then return 0 fi test -z "$LOOP" test -n "$DM_DEV_DIR" trap_teardown for i in 0 1 2 3 4 5 6 7; do mknod $DM_DEV_DIR/loop$i b 7 $i done LOOPFILE="$PWD/test.img" dd if=/dev/zero of="$LOOPFILE" bs=$((1024*1024)) count=1 seek=$(($size-1)) if LOOP=`losetup -s -f "$LOOPFILE" 2>/dev/null`; then return 0 elif LOOP=`losetup -f` && losetup $LOOP "$LOOPFILE"; then # no -s support return 0 else # no -f support # Iterate through $DM_DEV_DIR/loop{,/}{0,1,2,3,4,5,6,7} for slash in '' /; do for i in 0 1 2 3 4 5 6 7; do local dev=$DM_DEV_DIR/loop$slash$i ! losetup $dev >/dev/null 2>&1 || continue # got a free losetup "$dev" "$LOOPFILE" LOOP=$dev break done if [ -n "$LOOP" ]; then break fi done test -n "$LOOP" # confirm or fail return 0 fi exit 1 # should not happen } # A drop-in replacement for prepare_loop() that uses scsi_debug to create # a ramdisk-based SCSI device upon which all LVM devices will be created # - scripts must take care not to use a DEV_SIZE that will enduce OOM-killer prepare_scsi_debug_dev() { local DEV_SIZE="$1" shift local SCSI_DEBUG_PARAMS="$@" test -n "$SCSI_DEBUG_DEV" && return 0 test -z "$LOOP" test -n "$DM_DEV_DIR" trap_teardown # Skip test if awk isn't available (required for get_sd_devs_) which awk || exit 200 # Skip test if scsi_debug module is unavailable or is already in use modprobe --dry-run scsi_debug || exit 200 lsmod | grep -q scsi_debug && exit 200 # Create the scsi_debug device and determine the new scsi device's name # NOTE: it will _never_ make sense to pass num_tgts param; # last param wins.. so num_tgts=1 is imposed modprobe scsi_debug dev_size_mb=$DEV_SIZE $SCSI_DEBUG_PARAMS num_tgts=1 || exit 200 sleep 2 # allow for async Linux SCSI device registration local DEBUG_DEV=/dev/$(grep scsi_debug /sys/block/*/device/model | cut -f4 -d /) [ -b $DEBUG_DEV ] || exit 1 # should not happen # Create symlink to scsi_debug device in $DM_DEV_DIR SCSI_DEBUG_DEV=$DM_DEV_DIR/$(basename $DEBUG_DEV) # Setting $LOOP provides means for prepare_devs() override LOOP=$SCSI_DEBUG_DEV ln -snf $DEBUG_DEV $SCSI_DEBUG_DEV return 0 } cleanup_scsi_debug_dev() { aux teardown_devs unset SCSI_DEBUG_DEV unset LOOP } prepare_devs() { local n="$1" test -z "$n" && n=3 local devsize="$2" test -z "$devsize" && devsize=33 local pvname="$3" test -z "$pvname" && pvname="pv" prepare_loop $(($n*$devsize)) if ! loopsz=`blockdev --getsz $LOOP 2>/dev/null`; then loopsz=`blockdev --getsize $LOOP 2>/dev/null` fi local size=$(($loopsz/$n)) init_udev_transaction for i in `seq 1 $n`; do local name="${PREFIX}$pvname$i" local dev="$DM_DEV_DIR/mapper/$name" eval "dev$i=$dev" devs="$devs $dev" echo 0 $size linear $LOOP $((($i-1)*$size)) > $name.table dmsetup create $name $name.table done finish_udev_transaction for i in `seq 1 $n`; do local name="${PREFIX}$pvname$i" dmsetup info -c $name done for i in `seq 1 $n`; do local name="${PREFIX}$pvname$i" dmsetup table $name done # set up some default names vg=${PREFIX}vg vg1=${PREFIX}vg1 vg2=${PREFIX}vg2 lv=LV lv1=LV1 lv2=LV2 lv3=LV3 lv4=LV4 } disable_dev() { init_udev_transaction for dev in "$@"; do # first we make the device inaccessible echo 0 10000000 error | dmsetup load $dev dmsetup resume $dev # now let's try to get rid of it if it's unused #dmsetup remove $dev done finish_udev_transaction } enable_dev() { init_udev_transaction for dev in "$@"; do local name=`echo "$dev" | sed -e 's,.*/,,'` dmsetup create $name $name.table || dmsetup load $name $name.table dmsetup resume $dev done finish_udev_transaction } backup_dev() { for dev in "$@"; do dd if=$dev of=$dev.backup bs=1024 done } restore_dev() { for dev in "$@"; do test -e $dev.backup || { echo "Internal error: $dev not backed up, can't restore!" exit 1 } dd of=$dev if=$dev.backup bs=1024 done } prepare_pvs() { prepare_devs "$@" pvcreate $devs } prepare_vg() { prepare_pvs "$@" vgcreate -c n $vg $devs pvs -v } prepare_lvmconf() { local filter="$1" test -z "$filter" && \ filter='[ "a/dev\/mirror/", "a/dev\/mapper\/.*pv[0-9_]*$/", "r/.*/" ]' locktype= if test -n "$LVM_TEST_LOCKING"; then locktype="locking_type = $LVM_TEST_LOCKING"; fi cat > $TESTDIR/etc/lvm.conf <<-EOF $LVM_TEST_CONFIG devices { dir = "$DM_DEV_DIR" scan = "$DM_DEV_DIR" filter = $filter cache_dir = "$TESTDIR/etc" sysfs_scan = 0 } log { syslog = 0 indent = 1 } backup { backup = 0 archive = 0 } global { abort_on_internal_errors = 1 library_dir = "$TESTDIR/lib" locking_dir = "$TESTDIR/var/lock/lvm" $locktype } activation { udev_sync = 1 udev_rules = 1 polling_interval = 0 } EOF cat $TESTDIR/etc/lvm.conf } prepare() { ulimit -c unlimited # FIXME any way to set this just for our children? # echo 1 > /proc/sys/kernel/core_uses_pid prepare_testroot prepare_lvmconf prepare_clvmd } LANG=C LC_ALL=C TZ=UTC unset CDPATH . ./init.sh || { echo >&2 you must run make first; exit 1; } . ./lvm-utils.sh set -vexE -o pipefail aux prepare