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 43*325dd915SMax 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 490b1eb0ceSMax Reitz # With VDI, the output is ordered differently. Just disable it. 500b1eb0ceSMax Reitz _unsupported_fmt vdi 510b1eb0ceSMax Reitzfi 520b1eb0ceSMax Reitz 530b1eb0ceSMax Reitz 540b1eb0ceSMax ReitzTEST_IMG="$TEST_IMG.orig" _make_test_img 64M 550b1eb0ceSMax Reitz 560b1eb0ceSMax Reitz$QEMU_IO -c 'write -P 42 0 64M' "$TEST_IMG.orig" | _filter_qemu_io 570b1eb0ceSMax Reitz 580b1eb0ceSMax Reitz 590b1eb0ceSMax Reitzsector_size=512 600b1eb0ceSMax Reitz 610b1eb0ceSMax Reitz# Offsets on which to fail block-status. Keep in ascending order so 620b1eb0ceSMax Reitz# the indexing done by _filter_offsets will appear in ascending order 630b1eb0ceSMax Reitz# in the output as well. 640b1eb0ceSMax Reitzstatus_fail_offsets="$((16 * 1024 * 1024 + 8192)) 650b1eb0ceSMax Reitz $((33 * 1024 * 1024 + 512))" 660b1eb0ceSMax Reitz 670b1eb0ceSMax Reitz# Offsets on which to fail reads. Keep in ascending order for the 680b1eb0ceSMax Reitz# same reason. 690b1eb0ceSMax Reitz# The second element is shared with $status_fail_offsets on purpose. 700b1eb0ceSMax Reitz# Starting with the third element, we test what happens when a 710b1eb0ceSMax Reitz# continuous range of sectors is inaccessible. 720b1eb0ceSMax Reitzread_fail_offsets="$((32 * 1024 * 1024 - 65536)) 730b1eb0ceSMax Reitz $((33 * 1024 * 1024 + 512)) 740b1eb0ceSMax Reitz $(seq $((34 * 1024 * 1024)) $sector_size \ 750b1eb0ceSMax Reitz $((34 * 1024 * 1024 + 4096 - $sector_size)))" 760b1eb0ceSMax Reitz 770b1eb0ceSMax Reitz 780b1eb0ceSMax Reitz# blkdebug must be above the format layer so it can intercept all 790b1eb0ceSMax Reitz# block-status events 800b1eb0ceSMax Reitzsource_img="json:{'driver': 'blkdebug', 810b1eb0ceSMax Reitz 'image': { 820b1eb0ceSMax Reitz 'driver': '$IMGFMT', 830b1eb0ceSMax Reitz 'file': { 840b1eb0ceSMax Reitz 'driver': 'file', 850b1eb0ceSMax Reitz 'filename': '$TEST_IMG.orig' 860b1eb0ceSMax Reitz } 870b1eb0ceSMax Reitz }, 880b1eb0ceSMax Reitz 'inject-error': [" 890b1eb0ceSMax Reitz 900b1eb0ceSMax Reitzfor ofs in $status_fail_offsets 910b1eb0ceSMax Reitzdo 920b1eb0ceSMax Reitz source_img+="{ 'event': 'none', 930b1eb0ceSMax Reitz 'iotype': 'block-status', 940b1eb0ceSMax Reitz 'errno': 5, 950b1eb0ceSMax Reitz 'sector': $((ofs / sector_size)) }," 960b1eb0ceSMax Reitzdone 970b1eb0ceSMax Reitz 980b1eb0ceSMax Reitzfor ofs in $read_fail_offsets 990b1eb0ceSMax Reitzdo 1000b1eb0ceSMax Reitz source_img+="{ 'event': 'none', 1010b1eb0ceSMax Reitz 'iotype': 'read', 1020b1eb0ceSMax Reitz 'errno': 5, 1030b1eb0ceSMax Reitz 'sector': $((ofs / sector_size)) }," 1040b1eb0ceSMax Reitzdone 1050b1eb0ceSMax Reitz 1060b1eb0ceSMax Reitz# Remove the trailing comma and terminate @inject-error and json:{} 1070b1eb0ceSMax Reitzsource_img="${source_img%,} ] }" 1080b1eb0ceSMax Reitz 1090b1eb0ceSMax Reitz 1100b1eb0ceSMax Reitzecho 1110b1eb0ceSMax Reitz 1120b1eb0ceSMax Reitz 1130b1eb0ceSMax Reitz_filter_offsets() { 1140b1eb0ceSMax Reitz filters= 1150b1eb0ceSMax Reitz 1160b1eb0ceSMax Reitz index=0 1170b1eb0ceSMax Reitz for ofs in $1 1180b1eb0ceSMax Reitz do 1190b1eb0ceSMax Reitz filters+=" -e s/$ofs/status_fail_offset_$index/" 1200b1eb0ceSMax Reitz index=$((index + 1)) 1210b1eb0ceSMax Reitz done 1220b1eb0ceSMax Reitz 1230b1eb0ceSMax Reitz index=0 1240b1eb0ceSMax Reitz for ofs in $2 1250b1eb0ceSMax Reitz do 1260b1eb0ceSMax Reitz filters+=" -e s/$ofs/read_fail_offset_$index/" 1270b1eb0ceSMax Reitz index=$((index + 1)) 1280b1eb0ceSMax Reitz done 1290b1eb0ceSMax Reitz 1300b1eb0ceSMax Reitz sed $filters 1310b1eb0ceSMax Reitz} 1320b1eb0ceSMax Reitz 1330b1eb0ceSMax Reitz# While determining the number of allocated sectors in the input 1340b1eb0ceSMax Reitz# image, we should see one block status warning per element of 1350b1eb0ceSMax Reitz# $status_fail_offsets. 1360b1eb0ceSMax Reitz# 1370b1eb0ceSMax Reitz# Then, the image is read. Since the block status is queried in 1380b1eb0ceSMax Reitz# basically the same way, the same warnings as in the previous step 1390b1eb0ceSMax Reitz# should reappear. Interleaved with those we should see a read 1400b1eb0ceSMax Reitz# warning per element of $read_fail_offsets. 1410b1eb0ceSMax Reitz# Note that $read_fail_offsets and $status_fail_offsets share an 1420b1eb0ceSMax Reitz# element (read_fail_offset_1 == status_fail_offset_1), so 1430b1eb0ceSMax Reitz# "status_fail_offset_1" in the output is the same as 1440b1eb0ceSMax Reitz# "read_fail_offset_1". 1450b1eb0ceSMax Reitz$QEMU_IMG convert --salvage "$source_img" "$TEST_IMG" 2>&1 \ 1460b1eb0ceSMax Reitz | _filter_offsets "$status_fail_offsets" "$read_fail_offsets" 1470b1eb0ceSMax Reitz 1480b1eb0ceSMax Reitzecho 1490b1eb0ceSMax Reitz 1500b1eb0ceSMax Reitz# The offsets where the block status could not be determined should 1510b1eb0ceSMax Reitz# have been treated as containing data and thus should be correct in 1520b1eb0ceSMax Reitz# the output image. 1530b1eb0ceSMax Reitz# The offsets where reading failed altogether should be 0. Make them 1540b1eb0ceSMax Reitz# 0 in the input image, too, so we can compare both images. 1550b1eb0ceSMax Reitzfor ofs in $read_fail_offsets 1560b1eb0ceSMax Reitzdo 1570b1eb0ceSMax Reitz $QEMU_IO -c "write -z $ofs $sector_size" "$TEST_IMG.orig" \ 1580b1eb0ceSMax Reitz | _filter_qemu_io \ 1590b1eb0ceSMax Reitz | _filter_offsets '' "$read_fail_offsets" 1600b1eb0ceSMax Reitzdone 1610b1eb0ceSMax Reitz 1620b1eb0ceSMax Reitzecho 1630b1eb0ceSMax Reitz 1640b1eb0ceSMax Reitz# These should be equal now. 1650b1eb0ceSMax Reitz$QEMU_IMG compare "$TEST_IMG.orig" "$TEST_IMG" 1660b1eb0ceSMax Reitz 1670b1eb0ceSMax Reitz 1680b1eb0ceSMax Reitz# success, all done 1690b1eb0ceSMax Reitzecho "*** done" 1700b1eb0ceSMax Reitzrm -f $seq.full 1710b1eb0ceSMax Reitzstatus=0 172