mirror of https://github.com/ceph/ceph
678 lines
17 KiB
Bash
Executable File
678 lines
17 KiB
Bash
Executable File
#!/bin/bash -e
|
|
|
|
# Copyright (C) 2013 Inktank Storage, Inc.
|
|
#
|
|
# This is free software; see the source for copying conditions.
|
|
# There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR
|
|
# A PARTICULAR PURPOSE.
|
|
#
|
|
# This 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 version 2.
|
|
|
|
# Alex Elder <elder@inktank.com>
|
|
# April 10, 2013
|
|
|
|
################################################################
|
|
|
|
# The purpose of this test is to validate that data read from a
|
|
# mapped rbd image is what it's expected to be.
|
|
#
|
|
# By default it creates an image and fills it with some data. It
|
|
# then reads back the data at a series of offsets known to cover
|
|
# various situations (such as reading the beginning, end, or the
|
|
# entirety of an object, or doing a read that spans multiple
|
|
# objects), and stashes the results in a set of local files.
|
|
#
|
|
# It also creates and maps a snapshot of the original image after
|
|
# it's been filled, and reads back the same ranges of data from the
|
|
# snapshot. It then compares the data read back with what was read
|
|
# back from the original image, verifying they match.
|
|
#
|
|
# Clone functionality is tested as well, in which case a clone is
|
|
# made of the snapshot, and the same ranges of data are again read
|
|
# and compared with the original. In addition, a snapshot of that
|
|
# clone is created, and a clone of *that* snapshot is put through
|
|
# the same set of tests. (Clone testing can be optionally skipped.)
|
|
|
|
################################################################
|
|
|
|
# Default parameter values. Environment variables, if set, will
|
|
# supercede these defaults. Such variables have names that begin
|
|
# with "IMAGE_READ_", for e.g. use IMAGE_READ_PAGE_SIZE=65536
|
|
# to use 65536 as the page size.
|
|
|
|
DEFAULT_VERBOSE=true
|
|
DEFAULT_TEST_CLONES=true
|
|
DEFAULT_LOCAL_FILES=false
|
|
DEFAULT_FORMAT=2
|
|
DEFAULT_DOUBLE_ORDER=true
|
|
DEFAULT_HALF_ORDER=false
|
|
DEFAULT_PAGE_SIZE=4096
|
|
DEFAULT_OBJECT_ORDER=22
|
|
MIN_OBJECT_ORDER=12 # technically 9, but the rbd CLI enforces 12
|
|
MAX_OBJECT_ORDER=32
|
|
|
|
PROGNAME=$(basename $0)
|
|
|
|
ORIGINAL=original-$$
|
|
SNAP1=snap1-$$
|
|
CLONE1=clone1-$$
|
|
SNAP2=snap2-$$
|
|
CLONE2=clone2-$$
|
|
|
|
function err() {
|
|
if [ $# -gt 0 ]; then
|
|
echo "${PROGNAME}: $@" >&2
|
|
fi
|
|
exit 2
|
|
}
|
|
|
|
function usage() {
|
|
if [ $# -gt 0 ]; then
|
|
echo "" >&2
|
|
echo "${PROGNAME}: $@" >&2
|
|
fi
|
|
echo "" >&2
|
|
echo "Usage: ${PROGNAME} [<options>]" >&2
|
|
echo "" >&2
|
|
echo "options are:" >&2
|
|
echo " -o object_order" >&2
|
|
echo " must be ${MIN_OBJECT_ORDER}..${MAX_OBJECT_ORDER}" >&2
|
|
echo " -p page_size (in bytes)" >&2
|
|
echo " note: there must be at least 4 pages per object" >&2
|
|
echo " -1" >&2
|
|
echo " test using format 1 rbd images (default)" >&2
|
|
echo " -2" >&2
|
|
echo " test using format 2 rbd images" >&2
|
|
echo " -c" >&2
|
|
echo " also test rbd clone images (implies format 2)" >&2
|
|
echo " -d" >&2
|
|
echo " clone object order double its parent's (format 2)" >&2
|
|
echo " -h" >&2
|
|
echo " clone object order half of its parent's (format 2)" >&2
|
|
echo " -l" >&2
|
|
echo " use local files rather than rbd images" >&2
|
|
echo " -v" >&2
|
|
echo " disable reporting of what's going on" >&2
|
|
echo "" >&2
|
|
exit 1
|
|
}
|
|
|
|
function verbose() {
|
|
[ "${VERBOSE}" = true ] && echo "$@"
|
|
true # Don't let the verbose test spoil our return value
|
|
}
|
|
|
|
function quiet() {
|
|
"$@" 2> /dev/null
|
|
}
|
|
|
|
function boolean_toggle() {
|
|
[ $# -eq 1 ] || exit 99
|
|
test "$1" = "true" && echo false || echo true
|
|
}
|
|
|
|
function parseargs() {
|
|
local opts="o:p:12clv"
|
|
local lopts="order:,page_size:,local,clone,verbose"
|
|
local parsed
|
|
local clone_order_msg
|
|
|
|
# use values from environment if available
|
|
VERBOSE="${IMAGE_READ_VERBOSE:-${DEFAULT_VERBOSE}}"
|
|
TEST_CLONES="${IMAGE_READ_TEST_CLONES:-${DEFAULT_TEST_CLONES}}"
|
|
LOCAL_FILES="${IMAGE_READ_LOCAL_FILES:-${DEFAULT_LOCAL_FILES}}"
|
|
DOUBLE_ORDER="${IMAGE_READ_DOUBLE_ORDER:-${DEFAULT_DOUBLE_ORDER}}"
|
|
HALF_ORDER="${IMAGE_READ_HALF_ORDER:-${DEFAULT_HALF_ORDER}}"
|
|
FORMAT="${IMAGE_READ_FORMAT:-${DEFAULT_FORMAT}}"
|
|
PAGE_SIZE="${IMAGE_READ_PAGE_SIZE:-${DEFAULT_PAGE_SIZE}}"
|
|
OBJECT_ORDER="${IMAGE_READ_OBJECT_ORDER:-${DEFAULT_OBJECT_ORDER}}"
|
|
|
|
parsed=$(getopt -o "${opts}" -l "${lopts}" -n "${PROGNAME}" -- "$@") ||
|
|
usage
|
|
eval set -- "${parsed}"
|
|
while true; do
|
|
case "$1" in
|
|
-v|--verbose)
|
|
VERBOSE=$(boolean_toggle "${VERBOSE}");;
|
|
-c|--clone)
|
|
TEST_CLONES=$(boolean_toggle "${TEST_CLONES}");;
|
|
-d|--double)
|
|
DOUBLE_ORDER=$(boolean_toggle "${DOUBLE_ORDER}");;
|
|
-h|--half)
|
|
HALF_ORDER=$(boolean_toggle "${HALF_ORDER}");;
|
|
-l|--local)
|
|
LOCAL_FILES=$(boolean_toggle "${LOCAL_FILES}");;
|
|
-1|-2)
|
|
FORMAT="${1:1}";;
|
|
-p|--page_size)
|
|
PAGE_SIZE="$2"; shift;;
|
|
-o|--order)
|
|
OBJECT_ORDER="$2"; shift;;
|
|
--)
|
|
shift; break;;
|
|
*)
|
|
err "getopt internal error"
|
|
esac
|
|
shift
|
|
done
|
|
[ $# -gt 0 ] && usage "excess arguments ($*)"
|
|
|
|
if [ "${TEST_CLONES}" = true ]; then
|
|
# If we're using different object orders for clones,
|
|
# make sure the limits are updated accordingly. If
|
|
# both "half" and "double" are specified, just
|
|
# ignore them both.
|
|
if [ "${DOUBLE_ORDER}" = true ]; then
|
|
if [ "${HALF_ORDER}" = true ]; then
|
|
DOUBLE_ORDER=false
|
|
HALF_ORDER=false
|
|
else
|
|
((MAX_OBJECT_ORDER -= 2))
|
|
fi
|
|
elif [ "${HALF_ORDER}" = true ]; then
|
|
((MIN_OBJECT_ORDER += 2))
|
|
fi
|
|
fi
|
|
|
|
[ "${OBJECT_ORDER}" -lt "${MIN_OBJECT_ORDER}" ] &&
|
|
usage "object order (${OBJECT_ORDER}) must be" \
|
|
"at least ${MIN_OBJECT_ORDER}"
|
|
[ "${OBJECT_ORDER}" -gt "${MAX_OBJECT_ORDER}" ] &&
|
|
usage "object order (${OBJECT_ORDER}) must be" \
|
|
"at most ${MAX_OBJECT_ORDER}"
|
|
|
|
if [ "${TEST_CLONES}" = true ]; then
|
|
if [ "${DOUBLE_ORDER}" = true ]; then
|
|
((CLONE1_ORDER = OBJECT_ORDER + 1))
|
|
((CLONE2_ORDER = OBJECT_ORDER + 2))
|
|
clone_order_msg="double"
|
|
elif [ "${HALF_ORDER}" = true ]; then
|
|
((CLONE1_ORDER = OBJECT_ORDER - 1))
|
|
((CLONE2_ORDER = OBJECT_ORDER - 2))
|
|
clone_order_msg="half of"
|
|
else
|
|
CLONE1_ORDER="${OBJECT_ORDER}"
|
|
CLONE2_ORDER="${OBJECT_ORDER}"
|
|
clone_order_msg="the same as"
|
|
fi
|
|
fi
|
|
|
|
[ "${TEST_CLONES}" != true ] || FORMAT=2
|
|
|
|
OBJECT_SIZE=$(echo "2 ^ ${OBJECT_ORDER}" | bc)
|
|
OBJECT_PAGES=$(echo "${OBJECT_SIZE} / ${PAGE_SIZE}" | bc)
|
|
IMAGE_SIZE=$((2 * 16 * OBJECT_SIZE / (1024 * 1024)))
|
|
[ "${IMAGE_SIZE}" -lt 1 ] && IMAGE_SIZE=1
|
|
IMAGE_OBJECTS=$((IMAGE_SIZE * (1024 * 1024) / OBJECT_SIZE))
|
|
|
|
[ "${OBJECT_PAGES}" -lt 4 ] &&
|
|
usage "object size (${OBJECT_SIZE}) must be" \
|
|
"at least 4 * page size (${PAGE_SIZE})"
|
|
|
|
echo "parameters for this run:"
|
|
echo " format ${FORMAT} images will be tested"
|
|
echo " object order is ${OBJECT_ORDER}, so" \
|
|
"objects are ${OBJECT_SIZE} bytes"
|
|
echo " page size is ${PAGE_SIZE} bytes, so" \
|
|
"there are are ${OBJECT_PAGES} pages in an object"
|
|
echo " derived image size is ${IMAGE_SIZE} MB, so" \
|
|
"there are ${IMAGE_OBJECTS} objects in an image"
|
|
if [ "${TEST_CLONES}" = true ]; then
|
|
echo " clone functionality will be tested"
|
|
echo " object size for a clone will be ${clone_order_msg}"
|
|
echo " the object size of its parent image"
|
|
fi
|
|
|
|
true # Don't let the clones test spoil our return value
|
|
}
|
|
|
|
function image_dev_path() {
|
|
[ $# -eq 1 ] || exit 99
|
|
local image_name="$1"
|
|
|
|
if [ "${LOCAL_FILES}" = true ]; then
|
|
echo "${TEMP}/${image_name}"
|
|
return
|
|
fi
|
|
|
|
echo "/dev/rbd/rbd/${image_name}"
|
|
}
|
|
|
|
function out_data_dir() {
|
|
[ $# -lt 2 ] || exit 99
|
|
local out_data="${TEMP}/data"
|
|
local image_name
|
|
|
|
if [ $# -eq 1 ]; then
|
|
image_name="$1"
|
|
echo "${out_data}/${image_name}"
|
|
else
|
|
echo "${out_data}"
|
|
fi
|
|
}
|
|
|
|
function setup() {
|
|
verbose "===== setting up ====="
|
|
TEMP=$(mktemp -d /tmp/rbd_image_read.XXXXX)
|
|
mkdir -p $(out_data_dir)
|
|
|
|
# create and fill the original image with some data
|
|
create_image "${ORIGINAL}"
|
|
map_image "${ORIGINAL}"
|
|
fill_original
|
|
|
|
# create a snapshot of the original
|
|
create_image_snap "${ORIGINAL}" "${SNAP1}"
|
|
map_image_snap "${ORIGINAL}" "${SNAP1}"
|
|
|
|
if [ "${TEST_CLONES}" = true ]; then
|
|
# create a clone of the original snapshot
|
|
create_snap_clone "${ORIGINAL}" "${SNAP1}" \
|
|
"${CLONE1}" "${CLONE1_ORDER}"
|
|
map_image "${CLONE1}"
|
|
|
|
# create a snapshot of that clone
|
|
create_image_snap "${CLONE1}" "${SNAP2}"
|
|
map_image_snap "${CLONE1}" "${SNAP2}"
|
|
|
|
# create a clone of that clone's snapshot
|
|
create_snap_clone "${CLONE1}" "${SNAP2}" \
|
|
"${CLONE2}" "${CLONE2_ORDER}"
|
|
map_image "${CLONE2}"
|
|
fi
|
|
}
|
|
|
|
function teardown() {
|
|
verbose "===== cleaning up ====="
|
|
if [ "${TEST_CLONES}" = true ]; then
|
|
unmap_image "${CLONE2}" || true
|
|
destroy_snap_clone "${CLONE1}" "${SNAP2}" "${CLONE2}" || true
|
|
|
|
unmap_image_snap "${CLONE1}" "${SNAP2}" || true
|
|
destroy_image_snap "${CLONE1}" "${SNAP2}" || true
|
|
|
|
unmap_image "${CLONE1}" || true
|
|
destroy_snap_clone "${ORIGINAL}" "${SNAP1}" "${CLONE1}" || true
|
|
fi
|
|
unmap_image_snap "${ORIGINAL}" "${SNAP1}" || true
|
|
destroy_image_snap "${ORIGINAL}" "${SNAP1}" || true
|
|
unmap_image "${ORIGINAL}" || true
|
|
destroy_image "${ORIGINAL}" || true
|
|
|
|
rm -rf $(out_data_dir)
|
|
rmdir "${TEMP}"
|
|
}
|
|
|
|
function create_image() {
|
|
[ $# -eq 1 ] || exit 99
|
|
local image_name="$1"
|
|
local image_path
|
|
local bytes
|
|
|
|
verbose "creating image \"${image_name}\""
|
|
if [ "${LOCAL_FILES}" = true ]; then
|
|
image_path=$(image_dev_path "${image_name}")
|
|
bytes=$(echo "${IMAGE_SIZE} * 1024 * 1024 - 1" | bc)
|
|
quiet dd if=/dev/zero bs=1 count=1 seek="${bytes}" \
|
|
of="${image_path}"
|
|
return
|
|
fi
|
|
|
|
rbd create "${image_name}" --image-format "${FORMAT}" \
|
|
--size "${IMAGE_SIZE}" --order "${OBJECT_ORDER}" \
|
|
--image-shared
|
|
}
|
|
|
|
function destroy_image() {
|
|
[ $# -eq 1 ] || exit 99
|
|
local image_name="$1"
|
|
local image_path
|
|
|
|
verbose "destroying image \"${image_name}\""
|
|
if [ "${LOCAL_FILES}" = true ]; then
|
|
image_path=$(image_dev_path "${image_name}")
|
|
rm -f "${image_path}"
|
|
return
|
|
fi
|
|
|
|
rbd rm "${image_name}"
|
|
}
|
|
|
|
function map_image() {
|
|
[ $# -eq 1 ] || exit 99
|
|
local image_name="$1" # can be image@snap too
|
|
|
|
if [ "${LOCAL_FILES}" = true ]; then
|
|
return
|
|
fi
|
|
|
|
sudo rbd map "${image_name}"
|
|
}
|
|
|
|
function unmap_image() {
|
|
[ $# -eq 1 ] || exit 99
|
|
local image_name="$1" # can be image@snap too
|
|
local image_path
|
|
|
|
if [ "${LOCAL_FILES}" = true ]; then
|
|
return
|
|
fi
|
|
image_path=$(image_dev_path "${image_name}")
|
|
|
|
if [ -e "${image_path}" ]; then
|
|
sudo rbd unmap "${image_path}"
|
|
fi
|
|
}
|
|
|
|
function map_image_snap() {
|
|
[ $# -eq 2 ] || exit 99
|
|
local image_name="$1"
|
|
local snap_name="$2"
|
|
local image_snap
|
|
|
|
if [ "${LOCAL_FILES}" = true ]; then
|
|
return
|
|
fi
|
|
|
|
image_snap="${image_name}@${snap_name}"
|
|
map_image "${image_snap}"
|
|
}
|
|
|
|
function unmap_image_snap() {
|
|
[ $# -eq 2 ] || exit 99
|
|
local image_name="$1"
|
|
local snap_name="$2"
|
|
local image_snap
|
|
|
|
if [ "${LOCAL_FILES}" = true ]; then
|
|
return
|
|
fi
|
|
|
|
image_snap="${image_name}@${snap_name}"
|
|
unmap_image "${image_snap}"
|
|
}
|
|
|
|
function create_image_snap() {
|
|
[ $# -eq 2 ] || exit 99
|
|
local image_name="$1"
|
|
local snap_name="$2"
|
|
local image_snap="${image_name}@${snap_name}"
|
|
local image_path
|
|
local snap_path
|
|
|
|
verbose "creating snapshot \"${snap_name}\"" \
|
|
"of image \"${image_name}\""
|
|
if [ "${LOCAL_FILES}" = true ]; then
|
|
image_path=$(image_dev_path "${image_name}")
|
|
snap_path=$(image_dev_path "${image_snap}")
|
|
|
|
cp "${image_path}" "${snap_path}"
|
|
return
|
|
fi
|
|
|
|
rbd snap create "${image_snap}"
|
|
}
|
|
|
|
function destroy_image_snap() {
|
|
[ $# -eq 2 ] || exit 99
|
|
local image_name="$1"
|
|
local snap_name="$2"
|
|
local image_snap="${image_name}@${snap_name}"
|
|
local snap_path
|
|
|
|
verbose "destroying snapshot \"${snap_name}\"" \
|
|
"of image \"${image_name}\""
|
|
if [ "${LOCAL_FILES}" = true ]; then
|
|
snap_path=$(image_dev_path "${image_snap}")
|
|
rm -rf "${snap_path}"
|
|
return
|
|
fi
|
|
|
|
rbd snap rm "${image_snap}"
|
|
}
|
|
|
|
function create_snap_clone() {
|
|
[ $# -eq 4 ] || exit 99
|
|
local image_name="$1"
|
|
local snap_name="$2"
|
|
local clone_name="$3"
|
|
local clone_order="$4"
|
|
local image_snap="${image_name}@${snap_name}"
|
|
local snap_path
|
|
local clone_path
|
|
|
|
verbose "creating clone image \"${clone_name}\"" \
|
|
"of image snapshot \"${image_name}@${snap_name}\""
|
|
if [ "${LOCAL_FILES}" = true ]; then
|
|
snap_path=$(image_dev_path "${image_name}@${snap_name}")
|
|
clone_path=$(image_dev_path "${clone_name}")
|
|
|
|
cp "${snap_path}" "${clone_path}"
|
|
return
|
|
fi
|
|
|
|
rbd snap protect "${image_snap}"
|
|
rbd clone --order "${clone_order}" --image-shared \
|
|
"${image_snap}" "${clone_name}"
|
|
}
|
|
|
|
function destroy_snap_clone() {
|
|
[ $# -eq 3 ] || exit 99
|
|
local image_name="$1"
|
|
local snap_name="$2"
|
|
local clone_name="$3"
|
|
local image_snap="${image_name}@${snap_name}"
|
|
local clone_path
|
|
|
|
verbose "destroying clone image \"${clone_name}\""
|
|
if [ "${LOCAL_FILES}" = true ]; then
|
|
clone_path=$(image_dev_path "${clone_name}")
|
|
|
|
rm -rf "${clone_path}"
|
|
return
|
|
fi
|
|
|
|
rbd rm "${clone_name}"
|
|
rbd snap unprotect "${image_snap}"
|
|
}
|
|
|
|
# function that produces "random" data with which to fill the image
|
|
function source_data() {
|
|
while quiet dd if=/bin/bash skip=$(($$ % 199)) bs="${PAGE_SIZE}"; do
|
|
: # Just do the dd
|
|
done
|
|
}
|
|
|
|
function fill_original() {
|
|
local image_path=$(image_dev_path "${ORIGINAL}")
|
|
|
|
verbose "filling original image"
|
|
# Fill 16 objects worth of "random" data
|
|
source_data |
|
|
quiet dd bs="${PAGE_SIZE}" count=$((16 * OBJECT_PAGES)) \
|
|
of="${image_path}"
|
|
}
|
|
|
|
function do_read() {
|
|
[ $# -eq 3 -o $# -eq 4 ] || exit 99
|
|
local image_name="$1"
|
|
local offset="$2"
|
|
local length="$3"
|
|
[ "${length}" -gt 0 ] || err "do_read: length must be non-zero"
|
|
local image_path=$(image_dev_path "${image_name}")
|
|
local out_data=$(out_data_dir "${image_name}")
|
|
local range=$(printf "%06u~%04u" "${offset}" "${length}")
|
|
local out_file
|
|
|
|
[ $# -eq 4 ] && offset=$((offset + 16 * OBJECT_PAGES))
|
|
|
|
verbose "reading \"${image_name}\" pages ${range}"
|
|
|
|
out_file="${out_data}/pages_${range}"
|
|
|
|
quiet dd bs="${PAGE_SIZE}" skip="${offset}" count="${length}" \
|
|
if="${image_path}" of="${out_file}"
|
|
}
|
|
|
|
function one_pass() {
|
|
[ $# -eq 1 -o $# -eq 2 ] || exit 99
|
|
local image_name="$1"
|
|
local extended
|
|
[ $# -eq 2 ] && extended="true"
|
|
local offset
|
|
local length
|
|
|
|
offset=0
|
|
|
|
# +-----------+-----------+---
|
|
# |X:X:X...X:X| : : ... : | :
|
|
# +-----------+-----------+---
|
|
length="${OBJECT_PAGES}"
|
|
do_read "${image_name}" "${offset}" "${length}" ${extended}
|
|
offset=$((offset + length))
|
|
|
|
# ---+-----------+---
|
|
# : |X: : ... : | :
|
|
# ---+-----------+---
|
|
length=1
|
|
do_read "${image_name}" "${offset}" "${length}" ${extended}
|
|
offset=$((offset + length))
|
|
|
|
# ---+-----------+---
|
|
# : | :X: ... : | :
|
|
# ---+-----------+---
|
|
length=1
|
|
do_read "${image_name}" "${offset}" "${length}" ${extended}
|
|
offset=$((offset + length))
|
|
|
|
# ---+-----------+---
|
|
# : | : :X...X: | :
|
|
# ---+-----------+---
|
|
length=$((OBJECT_PAGES - 3))
|
|
do_read "${image_name}" "${offset}" "${length}" ${extended}
|
|
offset=$((offset + length))
|
|
|
|
# ---+-----------+---
|
|
# : | : : ... :X| :
|
|
# ---+-----------+---
|
|
length=1
|
|
do_read "${image_name}" "${offset}" "${length}" ${extended}
|
|
offset=$((offset + length))
|
|
|
|
# ---+-----------+---
|
|
# : |X:X:X...X:X| :
|
|
# ---+-----------+---
|
|
length="${OBJECT_PAGES}"
|
|
do_read "${image_name}" "${offset}" "${length}" ${extended}
|
|
offset=$((offset + length))
|
|
|
|
offset=$((offset + 1)) # skip 1
|
|
|
|
# ---+-----------+---
|
|
# : | :X:X...X:X| :
|
|
# ---+-----------+---
|
|
length=$((OBJECT_PAGES - 1))
|
|
do_read "${image_name}" "${offset}" "${length}" ${extended}
|
|
offset=$((offset + length))
|
|
|
|
# ---+-----------+-----------+---
|
|
# : |X:X:X...X:X|X: : ... : | :
|
|
# ---+-----------+-----------+---
|
|
length=$((OBJECT_PAGES + 1))
|
|
do_read "${image_name}" "${offset}" "${length}" ${extended}
|
|
offset=$((offset + length))
|
|
|
|
# ---+-----------+-----------+---
|
|
# : | :X:X...X:X|X: : ... : | :
|
|
# ---+-----------+-----------+---
|
|
length="${OBJECT_PAGES}"
|
|
do_read "${image_name}" "${offset}" "${length}" ${extended}
|
|
offset=$((offset + length))
|
|
|
|
# ---+-----------+-----------+---
|
|
# : | :X:X...X:X|X:X: ... : | :
|
|
# ---+-----------+-----------+---
|
|
length=$((OBJECT_PAGES + 1))
|
|
do_read "${image_name}" "${offset}" "${length}" ${extended}
|
|
offset=$((offset + length))
|
|
|
|
# ---+-----------+-----------+---
|
|
# : | : :X...X:X|X:X:X...X:X| :
|
|
# ---+-----------+-----------+---
|
|
length=$((2 * OBJECT_PAGES + 2))
|
|
do_read "${image_name}" "${offset}" "${length}" ${extended}
|
|
offset=$((offset + length))
|
|
|
|
offset=$((offset + 1)) # skip 1
|
|
|
|
# ---+-----------+-----------+-----
|
|
# : | :X:X...X:X|X:X:X...X:X|X: :
|
|
# ---+-----------+-----------+-----
|
|
length=$((2 * OBJECT_PAGES))
|
|
do_read "${image_name}" "${offset}" "${length}" ${extended}
|
|
offset=$((offset + length))
|
|
|
|
# --+-----------+-----------+--------
|
|
# : | :X:X...X:X|X:X:X...X:X|X:X: :
|
|
# --+-----------+-----------+--------
|
|
length=2049
|
|
length=$((2 * OBJECT_PAGES + 1))
|
|
do_read "${image_name}" "${offset}" "${length}" ${extended}
|
|
# offset=$((offset + length))
|
|
}
|
|
|
|
function run_using() {
|
|
[ $# -eq 1 ] || exit 99
|
|
local image_name="$1"
|
|
local out_data=$(out_data_dir "${image_name}")
|
|
|
|
verbose "===== running using \"${image_name}\" ====="
|
|
mkdir -p "${out_data}"
|
|
one_pass "${image_name}"
|
|
one_pass "${image_name}" extended
|
|
}
|
|
|
|
function compare() {
|
|
[ $# -eq 1 ] || exit 99
|
|
local image_name="$1"
|
|
local out_data=$(out_data_dir "${image_name}")
|
|
local original=$(out_data_dir "${ORIGINAL}")
|
|
|
|
verbose "===== comparing \"${image_name}\" ====="
|
|
for i in $(ls "${original}"); do
|
|
verbose compare "\"${image_name}\" \"${i}\""
|
|
cmp "${original}/${i}" "${out_data}/${i}"
|
|
done
|
|
[ "${image_name}" = "${ORIGINAL}" ] || rm -rf "${out_data}"
|
|
}
|
|
|
|
function doit() {
|
|
[ $# -eq 1 ] || exit 99
|
|
local image_name="$1"
|
|
|
|
run_using "${image_name}"
|
|
compare "${image_name}"
|
|
}
|
|
|
|
########## Start
|
|
|
|
parseargs "$@"
|
|
|
|
trap teardown EXIT HUP INT
|
|
setup
|
|
|
|
run_using "${ORIGINAL}"
|
|
doit "${ORIGINAL}@${SNAP1}"
|
|
if [ "${TEST_CLONES}" = true ]; then
|
|
doit "${CLONE1}"
|
|
doit "${CLONE1}@${SNAP2}"
|
|
doit "${CLONE2}"
|
|
fi
|
|
rm -rf $(out_data_dir "${ORIGINAL}")
|
|
|
|
echo "Success!"
|
|
|
|
exit 0
|