10b1eb0ceSMax Reitz#!/usr/bin/env bash 20b1eb0ceSMax Reitz# 30b1eb0ceSMax Reitz# Test qemu-img convert --salvage 40b1eb0ceSMax Reitz# 50b1eb0ceSMax Reitz# Copyright (C) 2019 Red Hat, Inc. 60b1eb0ceSMax Reitz# 70b1eb0ceSMax Reitz# This program is free software; you can redistribute it and/or modify 80b1eb0ceSMax Reitz# it under the terms of the GNU General Public License as published by 90b1eb0ceSMax Reitz# the Free Software Foundation; either version 2 of the License, or 100b1eb0ceSMax Reitz# (at your option) any later version. 110b1eb0ceSMax Reitz# 120b1eb0ceSMax Reitz# This program is distributed in the hope that it will be useful, 130b1eb0ceSMax Reitz# but WITHOUT ANY WARRANTY; without even the implied warranty of 140b1eb0ceSMax Reitz# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 150b1eb0ceSMax Reitz# GNU General Public License for more details. 160b1eb0ceSMax Reitz# 170b1eb0ceSMax Reitz# You should have received a copy of the GNU General Public License 180b1eb0ceSMax Reitz# along with this program. If not, see <http://www.gnu.org/licenses/>. 190b1eb0ceSMax Reitz# 200b1eb0ceSMax Reitz 210b1eb0ceSMax Reitz# creator 220b1eb0ceSMax Reitzowner=mreitz@redhat.com 230b1eb0ceSMax Reitz 240b1eb0ceSMax Reitzseq=$(basename $0) 250b1eb0ceSMax Reitzecho "QA output created by $seq" 260b1eb0ceSMax Reitz 270b1eb0ceSMax Reitzstatus=1 # failure is the default! 280b1eb0ceSMax Reitz 290b1eb0ceSMax Reitz_cleanup() 300b1eb0ceSMax Reitz{ 310b1eb0ceSMax Reitz _cleanup_test_img 320b1eb0ceSMax Reitz} 330b1eb0ceSMax Reitztrap "_cleanup; exit \$status" 0 1 2 3 15 340b1eb0ceSMax Reitz 350b1eb0ceSMax Reitz# get standard environment, filters and checks 360b1eb0ceSMax Reitz. ./common.rc 370b1eb0ceSMax Reitz. ./common.filter 380b1eb0ceSMax Reitz. ./common.qemu 390b1eb0ceSMax Reitz 400b1eb0ceSMax Reitz_supported_fmt generic 410b1eb0ceSMax Reitz_supported_proto file 420b1eb0ceSMax Reitz_supported_os Linux 43325dd915SMax Reitz_unsupported_imgopts "subformat=streamOptimized" 440b1eb0ceSMax Reitz 450b1eb0ceSMax Reitzif [ "$IMGOPTSSYNTAX" = "true" ]; then 460b1eb0ceSMax Reitz # We use json:{} filenames here, so we cannot work with additional options. 470b1eb0ceSMax Reitz _unsupported_fmt $IMGFMT 480b1eb0ceSMax Reitzelse 49*af8d43d3SPeter Lieven # - With VDI, the output is ordered differently. Just disable it. 50*af8d43d3SPeter Lieven # - VHDX has large clusters; because qemu-img convert tries to 51*af8d43d3SPeter Lieven # align the requests to the cluster size, the output is ordered 52*af8d43d3SPeter Lieven # differently, so disable it, too. 53*af8d43d3SPeter Lieven _unsupported_fmt vdi vhdx 540b1eb0ceSMax Reitzfi 550b1eb0ceSMax Reitz 560b1eb0ceSMax Reitz 570b1eb0ceSMax ReitzTEST_IMG="$TEST_IMG.orig" _make_test_img 64M 580b1eb0ceSMax Reitz 590b1eb0ceSMax Reitz$QEMU_IO -c 'write -P 42 0 64M' "$TEST_IMG.orig" | _filter_qemu_io 600b1eb0ceSMax Reitz 610b1eb0ceSMax Reitz 620b1eb0ceSMax Reitzsector_size=512 630b1eb0ceSMax Reitz 640b1eb0ceSMax Reitz# Offsets on which to fail block-status. Keep in ascending order so 650b1eb0ceSMax Reitz# the indexing done by _filter_offsets will appear in ascending order 660b1eb0ceSMax Reitz# in the output as well. 670b1eb0ceSMax Reitzstatus_fail_offsets="$((16 * 1024 * 1024 + 8192)) 680b1eb0ceSMax Reitz $((33 * 1024 * 1024 + 512))" 690b1eb0ceSMax Reitz 700b1eb0ceSMax Reitz# Offsets on which to fail reads. Keep in ascending order for the 710b1eb0ceSMax Reitz# same reason. 720b1eb0ceSMax Reitz# The second element is shared with $status_fail_offsets on purpose. 730b1eb0ceSMax Reitz# Starting with the third element, we test what happens when a 740b1eb0ceSMax Reitz# continuous range of sectors is inaccessible. 750b1eb0ceSMax Reitzread_fail_offsets="$((32 * 1024 * 1024 - 65536)) 760b1eb0ceSMax Reitz $((33 * 1024 * 1024 + 512)) 770b1eb0ceSMax Reitz $(seq $((34 * 1024 * 1024)) $sector_size \ 780b1eb0ceSMax Reitz $((34 * 1024 * 1024 + 4096 - $sector_size)))" 790b1eb0ceSMax Reitz 800b1eb0ceSMax Reitz 810b1eb0ceSMax Reitz# blkdebug must be above the format layer so it can intercept all 820b1eb0ceSMax Reitz# block-status events 830b1eb0ceSMax Reitzsource_img="json:{'driver': 'blkdebug', 840b1eb0ceSMax Reitz 'image': { 850b1eb0ceSMax Reitz 'driver': '$IMGFMT', 860b1eb0ceSMax Reitz 'file': { 870b1eb0ceSMax Reitz 'driver': 'file', 880b1eb0ceSMax Reitz 'filename': '$TEST_IMG.orig' 890b1eb0ceSMax Reitz } 900b1eb0ceSMax Reitz }, 910b1eb0ceSMax Reitz 'inject-error': [" 920b1eb0ceSMax Reitz 930b1eb0ceSMax Reitzfor ofs in $status_fail_offsets 940b1eb0ceSMax Reitzdo 950b1eb0ceSMax Reitz source_img+="{ 'event': 'none', 960b1eb0ceSMax Reitz 'iotype': 'block-status', 970b1eb0ceSMax Reitz 'errno': 5, 980b1eb0ceSMax Reitz 'sector': $((ofs / sector_size)) }," 990b1eb0ceSMax Reitzdone 1000b1eb0ceSMax Reitz 1010b1eb0ceSMax Reitzfor ofs in $read_fail_offsets 1020b1eb0ceSMax Reitzdo 1030b1eb0ceSMax Reitz source_img+="{ 'event': 'none', 1040b1eb0ceSMax Reitz 'iotype': 'read', 1050b1eb0ceSMax Reitz 'errno': 5, 1060b1eb0ceSMax Reitz 'sector': $((ofs / sector_size)) }," 1070b1eb0ceSMax Reitzdone 1080b1eb0ceSMax Reitz 1090b1eb0ceSMax Reitz# Remove the trailing comma and terminate @inject-error and json:{} 1100b1eb0ceSMax Reitzsource_img="${source_img%,} ] }" 1110b1eb0ceSMax Reitz 1120b1eb0ceSMax Reitz 1130b1eb0ceSMax Reitzecho 1140b1eb0ceSMax Reitz 1150b1eb0ceSMax Reitz 1160b1eb0ceSMax Reitz_filter_offsets() { 1170b1eb0ceSMax Reitz filters= 1180b1eb0ceSMax Reitz 1190b1eb0ceSMax Reitz index=0 1200b1eb0ceSMax Reitz for ofs in $1 1210b1eb0ceSMax Reitz do 1220b1eb0ceSMax Reitz filters+=" -e s/$ofs/status_fail_offset_$index/" 1230b1eb0ceSMax Reitz index=$((index + 1)) 1240b1eb0ceSMax Reitz done 1250b1eb0ceSMax Reitz 1260b1eb0ceSMax Reitz index=0 1270b1eb0ceSMax Reitz for ofs in $2 1280b1eb0ceSMax Reitz do 1290b1eb0ceSMax Reitz filters+=" -e s/$ofs/read_fail_offset_$index/" 1300b1eb0ceSMax Reitz index=$((index + 1)) 1310b1eb0ceSMax Reitz done 1320b1eb0ceSMax Reitz 1330b1eb0ceSMax Reitz sed $filters 1340b1eb0ceSMax Reitz} 1350b1eb0ceSMax Reitz 1360b1eb0ceSMax Reitz# While determining the number of allocated sectors in the input 1370b1eb0ceSMax Reitz# image, we should see one block status warning per element of 1380b1eb0ceSMax Reitz# $status_fail_offsets. 1390b1eb0ceSMax Reitz# 1400b1eb0ceSMax Reitz# Then, the image is read. Since the block status is queried in 1410b1eb0ceSMax Reitz# basically the same way, the same warnings as in the previous step 1420b1eb0ceSMax Reitz# should reappear. Interleaved with those we should see a read 1430b1eb0ceSMax Reitz# warning per element of $read_fail_offsets. 1440b1eb0ceSMax Reitz# Note that $read_fail_offsets and $status_fail_offsets share an 1450b1eb0ceSMax Reitz# element (read_fail_offset_1 == status_fail_offset_1), so 1460b1eb0ceSMax Reitz# "status_fail_offset_1" in the output is the same as 1470b1eb0ceSMax Reitz# "read_fail_offset_1". 1480b1eb0ceSMax Reitz$QEMU_IMG convert --salvage "$source_img" "$TEST_IMG" 2>&1 \ 1490b1eb0ceSMax Reitz | _filter_offsets "$status_fail_offsets" "$read_fail_offsets" 1500b1eb0ceSMax Reitz 1510b1eb0ceSMax Reitzecho 1520b1eb0ceSMax Reitz 1530b1eb0ceSMax Reitz# The offsets where the block status could not be determined should 1540b1eb0ceSMax Reitz# have been treated as containing data and thus should be correct in 1550b1eb0ceSMax Reitz# the output image. 1560b1eb0ceSMax Reitz# The offsets where reading failed altogether should be 0. Make them 1570b1eb0ceSMax Reitz# 0 in the input image, too, so we can compare both images. 1580b1eb0ceSMax Reitzfor ofs in $read_fail_offsets 1590b1eb0ceSMax Reitzdo 1600b1eb0ceSMax Reitz $QEMU_IO -c "write -z $ofs $sector_size" "$TEST_IMG.orig" \ 1610b1eb0ceSMax Reitz | _filter_qemu_io \ 1620b1eb0ceSMax Reitz | _filter_offsets '' "$read_fail_offsets" 1630b1eb0ceSMax Reitzdone 1640b1eb0ceSMax Reitz 1650b1eb0ceSMax Reitzecho 1660b1eb0ceSMax Reitz 1670b1eb0ceSMax Reitz# These should be equal now. 1680b1eb0ceSMax Reitz$QEMU_IMG compare "$TEST_IMG.orig" "$TEST_IMG" 1690b1eb0ceSMax Reitz 1700b1eb0ceSMax Reitz 1710b1eb0ceSMax Reitz# success, all done 1720b1eb0ceSMax Reitzecho "*** done" 1730b1eb0ceSMax Reitzrm -f $seq.full 1740b1eb0ceSMax Reitzstatus=0 175