| #!/usr/bin/env bash | 
 | # group: rw quick | 
 | # | 
 | # Test case for copy-on-read into qcow2 | 
 | # | 
 | # Copyright (C) 2017 Red Hat, Inc. | 
 | # | 
 | # 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/>. | 
 | # | 
 |  | 
 | # creator | 
 | owner=eblake@redhat.com | 
 |  | 
 | seq="$(basename $0)" | 
 | echo "QA output created by $seq" | 
 |  | 
 | status=1 # failure is the default! | 
 |  | 
 | # get standard environment, filters and checks | 
 | . ./common.rc | 
 | . ./common.filter | 
 |  | 
 | TEST_WRAP="$TEST_DIR/t.wrap.qcow2" | 
 | BLKDBG_CONF="$TEST_DIR/blkdebug.conf" | 
 |  | 
 | # Sanity check: our use of blkdebug fails if $TEST_DIR contains spaces | 
 | # or other problems | 
 | case "$TEST_DIR" in | 
 |     *[^-_a-zA-Z0-9/]*) | 
 |         _notrun "Suspicious TEST_DIR='$TEST_DIR', cowardly refusing to run" ;; | 
 | esac | 
 |  | 
 | _cleanup() | 
 | { | 
 |     _cleanup_test_img | 
 |     _rm_test_img "$TEST_WRAP" | 
 |     rm -f "$BLKDBG_CONF" | 
 | } | 
 | trap "_cleanup; exit \$status" 0 1 2 3 15 | 
 |  | 
 | # Test is supported for any backing file; but we force qcow2 for our wrapper. | 
 | _supported_fmt generic | 
 | _supported_proto generic | 
 | # LUKS support may be possible, but it complicates things. | 
 | _unsupported_fmt luks | 
 | _unsupported_imgopts "subformat=streamOptimized" | 
 |  | 
 | echo | 
 | echo '=== Copy-on-read ===' | 
 | echo | 
 |  | 
 | # Prep the images | 
 | # VPC rounds image sizes to a specific geometry, force a specific size. | 
 | if [ "$IMGFMT" = "vpc" ]; then | 
 |     IMGOPTS=$(_optstr_add "$IMGOPTS" "force_size") | 
 | fi | 
 | _make_test_img 4G | 
 | $QEMU_IO -c "write -P 55 3G 1k" "$TEST_IMG" | _filter_qemu_io | 
 | IMGPROTO=file IMGFMT=qcow2 TEST_IMG_FILE="$TEST_WRAP" \ | 
 |     _make_test_img --no-opts -F "$IMGFMT" -b "$TEST_IMG" | _filter_img_create | 
 | $QEMU_IO -f qcow2 -c "write -z -u 1M 64k" "$TEST_WRAP" | _filter_qemu_io | 
 |  | 
 | # Ensure that a read of two clusters, but where one is already allocated, | 
 | # does not re-write the allocated cluster | 
 | cat > "$BLKDBG_CONF" <<EOF | 
 | [inject-error] | 
 | event = "cor_write" | 
 | sector = "2048" | 
 | EOF | 
 | $QEMU_IO -c "open -C \ | 
 |  -o driver=blkdebug,config=$BLKDBG_CONF,image.driver=qcow2 $TEST_WRAP" \ | 
 |  -c "read -P 0 1M 128k" | _filter_qemu_io | 
 |  | 
 | # Read the areas we want copied. A zero-length read should still be a | 
 | # no-op.  The next read is under 2G, but aligned so that rounding to | 
 | # clusters copies more than 2G of zeroes. The final read will pick up | 
 | # the non-zero data in the same cluster.  Since a 2G read may exhaust | 
 | # memory on some machines (particularly 32-bit), we skip the test if | 
 | # that fails due to memory pressure. | 
 | $QEMU_IO -f qcow2 -C -c "read 0 0" "$TEST_WRAP" | _filter_qemu_io | 
 | output=$($QEMU_IO -f qcow2 -C -c "read -P 0 1k $((2*1024*1024*1024 - 512))" \ | 
 |         "$TEST_WRAP" 2>&1 | _filter_qemu_io) | 
 | case $output in | 
 |     *allocate*) | 
 |         _notrun "Insufficient memory to run test" ;; | 
 |     *) printf '%s\n' "$output" ;; | 
 | esac | 
 | $QEMU_IO -f qcow2 -C -c "read -P 0 $((3*1024*1024*1024 + 1024)) 1k" \ | 
 |     "$TEST_WRAP" | _filter_qemu_io | 
 |  | 
 | # Copy-on-read is incompatible with read-only | 
 | $QEMU_IO -f qcow2 -C -r "$TEST_WRAP" 2>&1 | _filter_testdir | 
 |  | 
 | # Break the backing chain, and show that images are identical, and that | 
 | # we properly copied over explicit zeros. | 
 | $QEMU_IMG rebase -u -b "" -f qcow2 "$TEST_WRAP" | 
 | $QEMU_IO -f qcow2 -c map "$TEST_WRAP" | 
 | _check_test_img | 
 | $QEMU_IMG compare -f $IMGFMT -F qcow2 "$TEST_IMG" "$TEST_WRAP" | 
 |  | 
 | echo | 
 | echo '=== Partial final cluster ===' | 
 | echo | 
 |  | 
 | # Force compat=1.1, because writing zeroes on a v2 image without a | 
 | # backing file would just result in an unallocated cluster | 
 | # (Also, note that this is really a pure qcow2 test.) | 
 | IMGPROTO=file IMGFMT=qcow2 TEST_IMG_FILE="$TEST_WRAP" \ | 
 |     _make_test_img --no-opts -o compat=1.1 1024 | 
 | $QEMU_IO -f qcow2 -C -c 'read 0 1024' "$TEST_WRAP" | _filter_qemu_io | 
 | $QEMU_IO -f qcow2 -c map "$TEST_WRAP" | 
 | _check_test_img | 
 |  | 
 | echo | 
 | echo '=== Copy-on-read with subclusters ===' | 
 | echo | 
 |  | 
 | # Create base and top images 64K (1 cluster) each.  Make subclusters enabled | 
 | # for the top image | 
 | _make_test_img 64K | 
 | IMGPROTO=file IMGFMT=qcow2 TEST_IMG_FILE="$TEST_WRAP" \ | 
 |     _make_test_img --no-opts -o extended_l2=true -F "$IMGFMT" -b "$TEST_IMG" \ | 
 |     64K | _filter_img_create | 
 |  | 
 | $QEMU_IO -c "write -P 0xaa 0 64k" "$TEST_IMG" | _filter_qemu_io | 
 |  | 
 | # Allocate individual subclusters in the top image, and not the whole cluster | 
 | $QEMU_IO -f qcow2 -c "write -P 0xbb 28K 2K" -c "write -P 0xcc 34K 2K" "$TEST_WRAP" \ | 
 |     | _filter_qemu_io | 
 |  | 
 | # Only 2 subclusters should be allocated in the top image at this point | 
 | $QEMU_IO -f qcow2 -c map "$TEST_WRAP" | 
 |  | 
 | # Actual copy-on-read operation | 
 | $QEMU_IO -f qcow2 -C -c "read -P 0xaa 30K 4K" "$TEST_WRAP" | _filter_qemu_io | 
 |  | 
 | # And here we should have 4 subclusters allocated right in the middle of the | 
 | # top image. Make sure the whole cluster remains unallocated | 
 | $QEMU_IO -f qcow2 -c map "$TEST_WRAP" | 
 |  | 
 | _check_test_img | 
 |  | 
 | # success, all done | 
 | echo '*** done' | 
 | status=0 |