qcow: Tolerate backing_fmt=

qcow has no space in the metadata to store a backing format, and there
are existing qcow images backed both by raw or by other formats
(usually qcow) images, reliant on probing to tell the difference.  On
the bright side, because we probe every time, raw files are marked as
probed and we thus forbid a commit action into the backing file where
guest-controlled contents could change the result of the probe next
time around (the iotest added here proves that).

Still, allowing the user to specify the backing format during
creation, even if we can't record it, is a good thing.  This patch
blindly allows any value that resolves to a known driver, even if the
user's request is a mismatch from what probing finds; then the next
patch will further enhance things to verify that the user's request
matches what we actually probe.  With this and the next patch in
place, we will finally be ready to deprecate the creation of images
where a backing format was not explicitly specified by the user.

Note that this is only for QemuOpts usage; there is no change to the
QAPI to allow a format through -blockdev.

Add a new iotest 301 just for qcow, to demonstrate the latest
behavior, and to make it easier to show the improvements made in the
next patch.

Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <20200706203954.341758-6-eblake@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
Eric Blake 2020-07-06 15:39:49 -05:00 committed by Kevin Wolf
parent d51a814cf4
commit 344acbd62f
4 changed files with 168 additions and 1 deletions

View File

@ -938,10 +938,11 @@ static int coroutine_fn qcow_co_create_opts(BlockDriver *drv,
{
BlockdevCreateOptions *create_options = NULL;
BlockDriverState *bs = NULL;
QDict *qdict;
QDict *qdict = NULL;
Visitor *v;
const char *val;
int ret;
char *backing_fmt;
static const QDictRenames opt_renames[] = {
{ BLOCK_OPT_BACKING_FILE, "backing-file" },
@ -949,6 +950,17 @@ static int coroutine_fn qcow_co_create_opts(BlockDriver *drv,
{ NULL, NULL },
};
/*
* We can't actually store a backing format, but can check that
* the user's request made sense.
*/
backing_fmt = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FMT);
if (backing_fmt && !bdrv_find_format(backing_fmt)) {
error_setg(errp, "unrecognized backing format '%s'", backing_fmt);
ret = -EINVAL;
goto fail;
}
/* Parse options and convert legacy syntax */
qdict = qemu_opts_to_qdict_filtered(opts, NULL, &qcow_create_opts, true);
@ -1012,6 +1024,7 @@ static int coroutine_fn qcow_co_create_opts(BlockDriver *drv,
ret = 0;
fail:
g_free(backing_fmt);
qobject_unref(qdict);
bdrv_unref(bs);
qapi_free_BlockdevCreateOptions(create_options);
@ -1146,6 +1159,11 @@ static QemuOptsList qcow_create_opts = {
.type = QEMU_OPT_STRING,
.help = "File name of a base image"
},
{
.name = BLOCK_OPT_BACKING_FMT,
.type = QEMU_OPT_STRING,
.help = "Format of the backing image",
},
{
.name = BLOCK_OPT_ENCRYPT,
.type = QEMU_OPT_BOOL,

88
tests/qemu-iotests/301 Executable file
View File

@ -0,0 +1,88 @@
#!/usr/bin/env bash
#
# Test qcow backing file warnings
#
# Copyright (C) 2020 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/>.
#
seq=`basename $0`
echo "QA output created by $seq"
status=1 # failure is the default!
_cleanup()
{
_cleanup_test_img
_rm_test_img "$TEST_IMG.qcow2"
}
trap "_cleanup; exit \$status" 0 1 2 3 15
# get standard environment, filters and checks
. ./common.rc
. ./common.filter
_supported_fmt qcow
_supported_proto file
_supported_os Linux
size=32M
echo
echo "== qcow backed by qcow =="
TEST_IMG="$TEST_IMG.base" _make_test_img $size
_make_test_img -b "$TEST_IMG.base" $size
_img_info
_make_test_img -b "$TEST_IMG.base" -F $IMGFMT $size
_img_info
echo
echo "== mismatched command line detection =="
_make_test_img -b "$TEST_IMG.base" -F vmdk
_make_test_img -b "$TEST_IMG.base" -F vmdk $size
echo
# Use of -u bypasses the backing format sanity check
_make_test_img -u -b "$TEST_IMG.base" -F vmdk
_make_test_img -u -b "$TEST_IMG.base" -F vmdk $size
echo
# But the format must still be recognized
_make_test_img -b "$TEST_IMG.base" -F garbage $size
_make_test_img -u -b "$TEST_IMG.base" -F garbage $size
_img_info
echo
echo "== qcow backed by raw =="
rm "$TEST_IMG.base"
truncate --size=$size "$TEST_IMG.base"
_make_test_img -b "$TEST_IMG.base" $size
_img_info
_make_test_img -b "$TEST_IMG.base" -F raw $size
_img_info
echo
echo "== commit cannot change type of raw backing file =="
TEST_IMG="$TEST_IMG.qcow2" IMGFMT=qcow2 _make_test_img $size
truncate --size=$size "$TEST_IMG.qcow2"
$QEMU_IMG convert -n -f raw -O $IMGFMT "$TEST_IMG.qcow2" "$TEST_IMG"
$QEMU_IMG commit -f $IMGFMT "$TEST_IMG" && echo "unexpected success"
TEST_IMG="$TEST_IMG.base" _img_info
# success, all done
echo "*** done"
rm -f $seq.full
status=0

View File

@ -0,0 +1,60 @@
QA output created by 301
== qcow backed by qcow ==
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=33554432
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.base
image: TEST_DIR/t.IMGFMT
file format: IMGFMT
virtual size: 32 MiB (33554432 bytes)
cluster_size: 512
backing file: TEST_DIR/t.IMGFMT.base
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT
image: TEST_DIR/t.IMGFMT
file format: IMGFMT
virtual size: 32 MiB (33554432 bytes)
cluster_size: 512
backing file: TEST_DIR/t.IMGFMT.base
== mismatched command line detection ==
qemu-img: TEST_DIR/t.IMGFMT: invalid VMDK image descriptor
Could not open backing image to determine size.
qemu-img: warning: Could not verify backing image. This may become an error in future versions.
invalid VMDK image descriptor
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=vmdk
qemu-img: TEST_DIR/t.IMGFMT: Image creation needs a size parameter
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=vmdk
qemu-img: warning: Could not verify backing image. This may become an error in future versions.
Unknown driver 'garbage'
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=garbage
qemu-img: TEST_DIR/t.IMGFMT: unrecognized backing format 'garbage'
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=garbage
qemu-img: TEST_DIR/t.IMGFMT: unrecognized backing format 'garbage'
image: TEST_DIR/t.IMGFMT
file format: IMGFMT
virtual size: 32 MiB (33554432 bytes)
cluster_size: 512
backing file: TEST_DIR/t.IMGFMT.base
== qcow backed by raw ==
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.base
image: TEST_DIR/t.IMGFMT
file format: IMGFMT
virtual size: 32 MiB (33554432 bytes)
cluster_size: 512
backing file: TEST_DIR/t.IMGFMT.base
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=33554432 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=raw
image: TEST_DIR/t.IMGFMT
file format: IMGFMT
virtual size: 32 MiB (33554432 bytes)
cluster_size: 512
backing file: TEST_DIR/t.IMGFMT.base
== commit cannot change type of raw backing file ==
Formatting 'TEST_DIR/t.qcow.IMGFMT', fmt=IMGFMT size=33554432
qemu-img: Block job failed: Operation not permitted
image: TEST_DIR/t.IMGFMT.base
file format: raw
virtual size: 32 MiB (33554432 bytes)
*** done

View File

@ -306,3 +306,4 @@
295 rw
296 rw
297 meta
301 backing quick