qemu/tests/qemu-iotests/common.rc
Thomas Huth 059f708d0c iotests: Provide a function for checking the creation of huge files
Some tests create huge (but sparse) files, and to be able to run those
tests in certain limited environments (like CI containers), we have to
check for the possibility to create such files first. Thus let's introduce
a common function to check for large files, and replace the already
existing checks in the iotests 005 and 220 with this function.

Signed-off-by: Thomas Huth <thuth@redhat.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2019-12-18 11:20:57 +01:00

658 lines
17 KiB
Bash

#!/usr/bin/env bash
#
# Copyright (C) 2009 Red Hat, Inc.
# Copyright (c) 2000-2006 Silicon Graphics, Inc. All Rights Reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
SED=
for sed in sed gsed; do
($sed --version | grep 'GNU sed') > /dev/null 2>&1
if [ "$?" -eq 0 ]; then
SED=$sed
break
fi
done
if [ -z "$SED" ]; then
echo "$0: GNU sed not found"
exit 1
fi
dd()
{
if [ "$HOSTOS" == "Linux" ]
then
command dd --help | grep noxfer > /dev/null 2>&1
if [ "$?" -eq 0 ]
then
command dd status=noxfer $@
else
command dd $@
fi
else
command dd $@
fi
}
# poke_file 'test.img' 512 '\xff\xfe'
poke_file()
{
printf "$3" | dd "of=$1" bs=1 "seek=$2" conv=notrunc &>/dev/null
}
# peek_file_le 'test.img' 512 2 => 65534
peek_file_le()
{
# Wrap in echo $() to strip spaces
echo $(od -j"$2" -N"$3" --endian=little -An -vtu"$3" "$1")
}
# peek_file_be 'test.img' 512 2 => 65279
peek_file_be()
{
# Wrap in echo $() to strip spaces
echo $(od -j"$2" -N"$3" --endian=big -An -vtu"$3" "$1")
}
# peek_file_raw 'test.img' 512 2 => '\xff\xfe'
peek_file_raw()
{
dd if="$1" bs=1 skip="$2" count="$3" status=none
}
if ! . ./common.config
then
echo "$0: failed to source common.config"
exit 1
fi
# Set the variables to the empty string to turn Valgrind off
# for specific processes, e.g.
# $ VALGRIND_QEMU_IO= ./check -qcow2 -valgrind 015
: ${VALGRIND_QEMU_VM=$VALGRIND_QEMU}
: ${VALGRIND_QEMU_IMG=$VALGRIND_QEMU}
: ${VALGRIND_QEMU_IO=$VALGRIND_QEMU}
: ${VALGRIND_QEMU_NBD=$VALGRIND_QEMU}
: ${VALGRIND_QEMU_VXHS=$VALGRIND_QEMU}
# The Valgrind own parameters may be set with
# its environment variable VALGRIND_OPTS, e.g.
# $ VALGRIND_OPTS="--leak-check=yes" ./check -qcow2 -valgrind 015
_qemu_proc_exec()
{
local VALGRIND_LOGFILE="$1"
shift
if [[ "${VALGRIND_QEMU}" == "y" && "${NO_VALGRIND}" != "y" ]]; then
exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$@"
else
exec "$@"
fi
}
_qemu_proc_valgrind_log()
{
local VALGRIND_LOGFILE="$1"
local RETVAL="$2"
if [[ "${VALGRIND_QEMU}" == "y" && "${NO_VALGRIND}" != "y" ]]; then
if [ $RETVAL == 99 ]; then
cat "${VALGRIND_LOGFILE}"
fi
rm -f "${VALGRIND_LOGFILE}"
fi
}
_qemu_wrapper()
{
local VALGRIND_LOGFILE="${TEST_DIR}"/$$.valgrind
(
if [ -n "${QEMU_NEED_PID}" ]; then
echo $BASHPID > "${QEMU_TEST_DIR}/qemu-${_QEMU_HANDLE}.pid"
fi
VALGRIND_QEMU="${VALGRIND_QEMU_VM}" _qemu_proc_exec "${VALGRIND_LOGFILE}" \
"$QEMU_PROG" $QEMU_OPTIONS "$@"
)
RETVAL=$?
_qemu_proc_valgrind_log "${VALGRIND_LOGFILE}" $RETVAL
return $RETVAL
}
_qemu_img_wrapper()
{
local VALGRIND_LOGFILE="${TEST_DIR}"/$$.valgrind
(
VALGRIND_QEMU="${VALGRIND_QEMU_IMG}" _qemu_proc_exec "${VALGRIND_LOGFILE}" \
"$QEMU_IMG_PROG" $QEMU_IMG_OPTIONS "$@"
)
RETVAL=$?
_qemu_proc_valgrind_log "${VALGRIND_LOGFILE}" $RETVAL
return $RETVAL
}
_qemu_io_wrapper()
{
local VALGRIND_LOGFILE="${TEST_DIR}"/$$.valgrind
local QEMU_IO_ARGS="$QEMU_IO_OPTIONS"
if [ "$IMGOPTSSYNTAX" = "true" ]; then
QEMU_IO_ARGS="--image-opts $QEMU_IO_ARGS"
if [ -n "$IMGKEYSECRET" ]; then
QEMU_IO_ARGS="--object secret,id=keysec0,data=$IMGKEYSECRET $QEMU_IO_ARGS"
fi
fi
(
VALGRIND_QEMU="${VALGRIND_QEMU_IO}" _qemu_proc_exec "${VALGRIND_LOGFILE}" \
"$QEMU_IO_PROG" $QEMU_IO_ARGS "$@"
)
RETVAL=$?
_qemu_proc_valgrind_log "${VALGRIND_LOGFILE}" $RETVAL
return $RETVAL
}
_qemu_nbd_wrapper()
{
local VALGRIND_LOGFILE="${TEST_DIR}"/$$.valgrind
(
VALGRIND_QEMU="${VALGRIND_QEMU_NBD}" _qemu_proc_exec "${VALGRIND_LOGFILE}" \
"$QEMU_NBD_PROG" --pid-file="${QEMU_TEST_DIR}/qemu-nbd.pid" \
$QEMU_NBD_OPTIONS "$@"
)
RETVAL=$?
_qemu_proc_valgrind_log "${VALGRIND_LOGFILE}" $RETVAL
return $RETVAL
}
_qemu_vxhs_wrapper()
{
local VALGRIND_LOGFILE="${TEST_DIR}"/$$.valgrind
(
echo $BASHPID > "${TEST_DIR}/qemu-vxhs.pid"
VALGRIND_QEMU="${VALGRIND_QEMU_VXHS}" _qemu_proc_exec "${VALGRIND_LOGFILE}" \
"$QEMU_VXHS_PROG" $QEMU_VXHS_OPTIONS "$@"
)
RETVAL=$?
_qemu_proc_valgrind_log "${VALGRIND_LOGFILE}" $RETVAL
return $RETVAL
}
# Valgrind bug #409141 https://bugs.kde.org/show_bug.cgi?id=409141
# Until valgrind 3.16+ is ubiquitous, we must work around a hang in
# valgrind when issuing sigkill. Disable valgrind for this invocation.
_NO_VALGRIND()
{
NO_VALGRIND="y" "$@"
}
export QEMU=_qemu_wrapper
export QEMU_IMG=_qemu_img_wrapper
export QEMU_IO=_qemu_io_wrapper
export QEMU_NBD=_qemu_nbd_wrapper
export QEMU_VXHS=_qemu_vxhs_wrapper
if [ "$IMGOPTSSYNTAX" = "true" ]; then
DRIVER="driver=$IMGFMT"
QEMU_IMG_EXTRA_ARGS="--image-opts $QEMU_IMG_EXTRA_ARGS"
if [ -n "$IMGKEYSECRET" ]; then
QEMU_IMG_EXTRA_ARGS="--object secret,id=keysec0,data=$IMGKEYSECRET $QEMU_IMG_EXTRA_ARGS"
fi
if [ "$IMGFMT" = "luks" ]; then
DRIVER="$DRIVER,key-secret=keysec0"
fi
if [ "$IMGPROTO" = "file" ]; then
TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
TEST_IMG="$DRIVER,file.filename=$TEST_DIR/t.$IMGFMT"
elif [ "$IMGPROTO" = "nbd" ]; then
TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
TEST_IMG="$DRIVER,file.driver=nbd,file.type=unix,file.path=$SOCKDIR/nbd"
elif [ "$IMGPROTO" = "ssh" ]; then
TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
TEST_IMG="$DRIVER,file.driver=ssh,file.host=127.0.0.1,file.path=$TEST_IMG_FILE"
elif [ "$IMGPROTO" = "nfs" ]; then
TEST_DIR="$DRIVER,file.driver=nfs,file.filename=nfs://127.0.0.1/$TEST_DIR"
TEST_IMG=$TEST_DIR/t.$IMGFMT
else
TEST_IMG="$DRIVER,file.driver=$IMGPROTO,file.filename=$TEST_DIR/t.$IMGFMT"
fi
else
QEMU_IMG_EXTRA_ARGS=
if [ "$IMGPROTO" = "file" ]; then
TEST_IMG=$TEST_DIR/t.$IMGFMT
elif [ "$IMGPROTO" = "nbd" ]; then
TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
TEST_IMG="nbd+unix:///?socket=$SOCK_DIR/nbd"
elif [ "$IMGPROTO" = "ssh" ]; then
TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
REMOTE_TEST_DIR="ssh://\\($USER@\\)\\?127.0.0.1\\(:[0-9]\\+\\)\\?$TEST_DIR"
TEST_IMG="ssh://127.0.0.1$TEST_IMG_FILE"
elif [ "$IMGPROTO" = "nfs" ]; then
TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
REMOTE_TEST_DIR="nfs://127.0.0.1$TEST_DIR"
TEST_IMG="nfs://127.0.0.1$TEST_IMG_FILE"
elif [ "$IMGPROTO" = "vxhs" ]; then
TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
TEST_IMG="vxhs://127.0.0.1:9999/t.$IMGFMT"
else
TEST_IMG=$IMGPROTO:$TEST_DIR/t.$IMGFMT
fi
fi
ORIG_TEST_IMG="$TEST_IMG"
if [ -z "$TEST_DIR" ]; then
TEST_DIR=$PWD/scratch
fi
QEMU_TEST_DIR="${TEST_DIR}"
if [ ! -e "$TEST_DIR" ]; then
mkdir "$TEST_DIR"
fi
if [ ! -d "$TEST_DIR" ]; then
echo "common.rc: Error: \$TEST_DIR ($TEST_DIR) is not a directory"
exit 1
fi
if [ -z "$REMOTE_TEST_DIR" ]; then
REMOTE_TEST_DIR="$TEST_DIR"
fi
if [ ! -d "$SAMPLE_IMG_DIR" ]; then
echo "common.rc: Error: \$SAMPLE_IMG_DIR ($SAMPLE_IMG_DIR) is not a directory"
exit 1
fi
_use_sample_img()
{
SAMPLE_IMG_FILE="${1%\.bz2}"
TEST_IMG="$TEST_DIR/$SAMPLE_IMG_FILE"
bzcat "$SAMPLE_IMG_DIR/$1" > "$TEST_IMG"
if [ $? -ne 0 ]
then
echo "_use_sample_img error, cannot extract '$SAMPLE_IMG_DIR/$1'"
exit 1
fi
}
_stop_nbd_server()
{
if [ -f "${QEMU_TEST_DIR}/qemu-nbd.pid" ]; then
local QEMU_NBD_PID
read QEMU_NBD_PID < "${QEMU_TEST_DIR}/qemu-nbd.pid"
kill ${QEMU_NBD_PID}
rm -f "${QEMU_TEST_DIR}/qemu-nbd.pid" "$SOCK_DIR/nbd"
fi
}
_make_test_img()
{
# extra qemu-img options can be added by tests
# at least one argument (the image size) needs to be added
local extra_img_options=""
local image_size=$*
local optstr=""
local img_name=""
local use_backing=0
local backing_file=""
local object_options=""
if [ -n "$TEST_IMG_FILE" ]; then
img_name=$TEST_IMG_FILE
else
img_name=$TEST_IMG
fi
if [ -n "$IMGOPTS" ]; then
optstr=$(_optstr_add "$optstr" "$IMGOPTS")
fi
if [ -n "$IMGKEYSECRET" ]; then
object_options="--object secret,id=keysec0,data=$IMGKEYSECRET"
optstr=$(_optstr_add "$optstr" "key-secret=keysec0")
fi
if [ "$1" = "-b" ]; then
use_backing=1
backing_file=$2
image_size=$3
fi
if [ \( "$IMGFMT" = "qcow2" -o "$IMGFMT" = "qed" \) -a -n "$CLUSTER_SIZE" ]; then
optstr=$(_optstr_add "$optstr" "cluster_size=$CLUSTER_SIZE")
fi
if [ -n "$optstr" ]; then
extra_img_options="-o $optstr $extra_img_options"
fi
if [ $IMGPROTO = "nbd" ]; then
_stop_nbd_server
fi
# XXX(hch): have global image options?
(
if [ $use_backing = 1 ]; then
$QEMU_IMG create $object_options -f $IMGFMT $extra_img_options -b "$backing_file" "$img_name" $image_size 2>&1
else
$QEMU_IMG create $object_options -f $IMGFMT $extra_img_options "$img_name" $image_size 2>&1
fi
) | _filter_img_create
# Start an NBD server on the image file, which is what we'll be talking to.
# Once NBD gains resize support, we may also want to use -f raw at the
# server and interpret format over NBD, but for now, the format is
# interpreted at the server and raw data sent over NBD.
if [ $IMGPROTO = "nbd" ]; then
# Pass a sufficiently high number to -e that should be enough for all
# tests
eval "$QEMU_NBD -v -t -k '$SOCK_DIR/nbd' -f $IMGFMT -e 42 -x '' $TEST_IMG_FILE >/dev/null &"
sleep 1 # FIXME: qemu-nbd needs to be listening before we continue
fi
# Start QNIO server on image directory for vxhs protocol
if [ $IMGPROTO = "vxhs" ]; then
eval "$QEMU_VXHS -d $TEST_DIR > /dev/null &"
sleep 1 # Wait for server to come up.
fi
}
_rm_test_img()
{
local img=$1
if [ "$IMGFMT" = "vmdk" ]; then
# Remove all the extents for vmdk
"$QEMU_IMG" info "$img" 2>/dev/null | grep 'filename:' | cut -f 2 -d: \
| xargs -I {} rm -f "{}"
fi
rm -f "$img"
}
_cleanup_test_img()
{
case "$IMGPROTO" in
nbd)
_stop_nbd_server
rm -f "$TEST_IMG_FILE"
;;
vxhs)
if [ -f "${TEST_DIR}/qemu-vxhs.pid" ]; then
local QEMU_VXHS_PID
read QEMU_VXHS_PID < "${TEST_DIR}/qemu-vxhs.pid"
kill ${QEMU_VXHS_PID} >/dev/null 2>&1
rm -f "${TEST_DIR}/qemu-vxhs.pid"
fi
rm -f "$TEST_IMG_FILE"
;;
file)
_rm_test_img "$TEST_DIR/t.$IMGFMT"
_rm_test_img "$TEST_DIR/t.$IMGFMT.orig"
_rm_test_img "$TEST_DIR/t.$IMGFMT.base"
if [ -n "$SAMPLE_IMG_FILE" ]
then
rm -f "$TEST_DIR/$SAMPLE_IMG_FILE"
SAMPLE_IMG_FILE=
TEST_IMG="$ORIG_TEST_IMG"
fi
;;
rbd)
rbd --no-progress rm "$TEST_DIR/t.$IMGFMT" > /dev/null
;;
sheepdog)
collie vdi delete "$TEST_DIR/t.$IMGFMT"
;;
esac
}
_check_test_img()
{
(
if [ "$IMGOPTSSYNTAX" = "true" ]; then
$QEMU_IMG check $QEMU_IMG_EXTRA_ARGS "$@" "$TEST_IMG" 2>&1
else
$QEMU_IMG check "$@" -f $IMGFMT "$TEST_IMG" 2>&1
fi
) | _filter_testdir | _filter_qemu_img_check
# return real qemu_img check status, to analyze in
# _check_test_img_ignore_leaks
return ${PIPESTATUS[0]}
}
_check_test_img_ignore_leaks()
{
out=$(_check_test_img "$@")
status=$?
if [ $status = 3 ]; then
# This must correspond to success output in dump_human_image_check()
echo "No errors were found on the image."
return 0
fi
echo "$out"
return $status
}
_img_info()
{
if [[ "$1" == "--format-specific" ]]; then
local format_specific=1
shift
else
local format_specific=0
fi
discard=0
regex_json_spec_start='^ *"format-specific": \{'
$QEMU_IMG info $QEMU_IMG_EXTRA_ARGS "$@" "$TEST_IMG" 2>&1 | \
sed -e "s#$REMOTE_TEST_DIR#TEST_DIR#g" \
-e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \
-e "s#$TEST_DIR#TEST_DIR#g" \
-e "s#$IMGFMT#IMGFMT#g" \
-e "/^disk size:/ D" \
-e "/actual-size/ D" | \
while IFS='' read -r line; do
if [[ $format_specific == 1 ]]; then
discard=0
elif [[ $line == "Format specific information:" ]]; then
discard=1
elif [[ $line =~ $regex_json_spec_start ]]; then
discard=2
regex_json_spec_end="^${line%%[^ ]*}\\},? *$"
fi
if [[ $discard == 0 ]]; then
echo "$line"
elif [[ $discard == 1 && ! $line ]]; then
echo
discard=0
elif [[ $discard == 2 && $line =~ $regex_json_spec_end ]]; then
discard=0
fi
done
}
# bail out, setting up .notrun file
#
_notrun()
{
echo "$*" >"$OUTPUT_DIR/$seq.notrun"
echo "$seq not run: $*"
status=0
exit
}
# bail out, setting up .casenotrun file
# The function _casenotrun() is used as a notifier. It is the
# caller's responsibility to make skipped a particular test.
#
_casenotrun()
{
echo " [case not run] $*" >>"$OUTPUT_DIR/$seq.casenotrun"
}
# just plain bail out
#
_fail()
{
echo "$*" | tee -a "$OUTPUT_DIR/$seq.full"
echo "(see $seq.full for details)"
status=1
exit 1
}
# tests whether $IMGFMT is one of the supported image formats for a test
#
_supported_fmt()
{
# "generic" is suitable for most image formats. For some formats it doesn't
# work, however (most notably read-only formats), so they can opt out by
# setting IMGFMT_GENERIC to false.
for f; do
if [ "$f" = "$IMGFMT" -o "$f" = "generic" -a "$IMGFMT_GENERIC" = "true" ]; then
return
fi
done
_notrun "not suitable for this image format: $IMGFMT"
}
# tests whether $IMGFMT is one of the unsupported image format for a test
#
_unsupported_fmt()
{
for f; do
if [ "$f" = "$IMGFMT" ]; then
_notrun "not suitable for this image format: $IMGFMT"
fi
done
}
# tests whether $IMGPROTO is one of the supported image protocols for a test
#
_supported_proto()
{
for f; do
if [ "$f" = "$IMGPROTO" -o "$f" = "generic" ]; then
return
fi
done
_notrun "not suitable for this image protocol: $IMGPROTO"
}
# tests whether $IMGPROTO is specified as an unsupported image protocol for a test
#
_unsupported_proto()
{
for f; do
if [ "$f" = "$IMGPROTO" ]; then
_notrun "not suitable for this image protocol: $IMGPROTO"
return
fi
done
}
# tests whether the host OS is one of the supported OSes for a test
#
_supported_os()
{
for h
do
if [ "$h" = "$HOSTOS" ]
then
return
fi
done
_notrun "not suitable for this OS: $HOSTOS"
}
_supported_cache_modes()
{
for mode; do
if [ "$mode" = "$CACHEMODE" ]; then
return
fi
done
_notrun "not suitable for cache mode: $CACHEMODE"
}
_default_cache_mode()
{
if $CACHEMODE_IS_DEFAULT; then
CACHEMODE="$1"
QEMU_IO="$QEMU_IO --cache $1"
return
fi
}
_unsupported_imgopts()
{
for bad_opt
do
if echo "$IMGOPTS" | grep -q 2>/dev/null "$bad_opt"
then
_notrun "not suitable for image option: $bad_opt"
fi
done
}
# this test requires that a specified command (executable) exists
#
_require_command()
{
if [ "$1" = "QEMU" ]; then
c=$QEMU_PROG
elif [ "$1" = "QEMU_IMG" ]; then
c=$QEMU_IMG_PROG
elif [ "$1" = "QEMU_IO" ]; then
c=$QEMU_IO_PROG
elif [ "$1" = "QEMU_NBD" ]; then
c=$QEMU_NBD_PROG
else
eval c=\$$1
fi
[ -x "$c" ] || _notrun "$1 utility required, skipped this test"
}
# Check that a set of drivers has been whitelisted in the QEMU binary
#
_require_drivers()
{
available=$($QEMU -drive format=help | \
sed -e '/Supported formats:/!d' -e 's/Supported formats://')
for driver
do
if ! echo "$available" | grep -q " $driver\( \|$\)"; then
_notrun "$driver not available"
fi
done
}
# Check that we have a file system that allows huge (but very sparse) files
#
_require_large_file()
{
if ! truncate --size="$1" "$TEST_IMG"; then
_notrun "file system on $TEST_DIR does not support large enough files"
fi
rm "$TEST_IMG"
}
# make sure this script returns success
true