@@ -588,16 +588,49 @@ static void qcow2_add_check_result(BdrvCheckResult *out,
}
}
+static int qcow2_check_header(BlockDriverState *bs, BdrvCheckResult *result,
+ BdrvCheckMode fix)
+{
+ BDRVQcow2State *s = bs->opaque;
+ int ret;
+
+ if (bs->backing && data_file_is_raw(bs)) {
+ fprintf(stderr, "%s header: data-file-raw cannot be set "
+ "when there is a backing file.\n",
+ fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR in");
+ if (fix & BDRV_FIX_ERRORS) {
+ s->autoclear_features &= ~QCOW2_AUTOCLEAR_DATA_FILE_RAW;
+ ret = qcow2_update_header(bs);
+ if (ret < 0) {
+ result->check_errors++;
+ return ret;
+ }
+ result->corruptions_fixed++;
+ } else {
+ result->corruptions++;
+ }
+ }
+
+ return 0;
+}
+
static int coroutine_fn qcow2_co_check_locked(BlockDriverState *bs,
BdrvCheckResult *result,
BdrvCheckMode fix)
{
+ BdrvCheckResult header_res = {};
BdrvCheckResult snapshot_res = {};
BdrvCheckResult refcount_res = {};
int ret;
memset(result, 0, sizeof(*result));
+ ret = qcow2_check_header(bs, &header_res, fix);
+ qcow2_add_check_result(result, &header_res, false);
+ if (ret < 0) {
+ return ret;
+ }
+
ret = qcow2_check_read_snapshot_table(bs, &snapshot_res, fix);
if (ret < 0) {
qcow2_add_check_result(result, &snapshot_res, false);
@@ -1604,6 +1637,12 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
/* read the backing file name */
if (header.backing_file_offset != 0) {
+ if (data_file_is_raw(bs) && (!(flags & BDRV_O_CHECK))) {
+ error_setg(errp, "data-file-raw cannot be set when "
+ "there is a backing file");
+ ret = -EINVAL;
+ goto fail;
+ }
len = header.backing_file_size;
if (len > MIN(1023, s->cluster_size - header.backing_file_offset) ||
len >= sizeof(bs->backing_file)) {
@@ -211,6 +211,19 @@ $QEMU_IMG amend -f $IMGFMT -o "data_file=blkdebug::$TEST_IMG.data" "$TEST_IMG"
$QEMU_IMG convert -f $IMGFMT -O $IMGFMT -n -C "$TEST_IMG.src" "$TEST_IMG"
$QEMU_IMG compare -f $IMGFMT -F $IMGFMT "$TEST_IMG.src" "$TEST_IMG"
+echo
+echo "=== Using and repairing an image with backing file and the data_file_raw bit ==="
+echo
+
+# Create an image with a backing file and an external data file
+TEST_IMG_FILE="$TEST_IMG.base" _make_test_img 1M
+_make_test_img -o "data_file=$TEST_IMG.data" -b "$TEST_IMG.base"
+# Set 'data_file_raw' directly on the header (qemu-img amend won't let us)
+poke_file "$TEST_IMG" 95 "\x02"
+# Trying to open the image should produce an error
+$QEMU_IMG info "$TEST_IMG" 2>&1 | _filter_testdir
+_check_test_img -r all
+
# success, all done
echo "*** done"
rm -f $seq.full
@@ -128,4 +128,18 @@ Offset Length Mapped to File
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data
Images are identical.
Images are identical.
+
+=== Using and repairing an image with backing file and the data_file_raw bit ===
+
+Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=1048576
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT.base data_file=TEST_DIR/t.IMGFMT.data
+qemu-img: Could not open 'TEST_DIR/t.qcow2': data-file-raw cannot be set when there is a backing file
+Repairing header: data-file-raw cannot be set when there is a backing file.
+The following inconsistencies were found and repaired:
+
+ 0 leaked clusters
+ 1 corruptions
+
+Double checking the fixed image now...
+No errors were found on the image.
*** done
Although we cannot create these images with qemu-img it is still possible to do it using an external tool. QEMU should refuse to open them until the data-file-raw bit is cleared with 'qemu-img check'. Signed-off-by: Alberto Garcia <berto@igalia.com> --- block/qcow2.c | 39 ++++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/244 | 13 +++++++++++++ tests/qemu-iotests/244.out | 14 ++++++++++++++ 3 files changed, 66 insertions(+)