From: Fiona Ebner <[email protected]> With 'qemu-img convert', when using a cache mode with 'cache.no-flush = off', the expectation is that the data is flushed to the disk, which happens since commit 80ccf93b88 ("qemu-img: let 'qemu-img convert' flush data"). This expectation also encompasses that failure to do so is properly reported, so ensure that 'qemu-img convert' exits with a non-zero status code when the target image cannot be flushed.
In particular, the reproducer below [0], based on a report by Ing. Alfonso Kuen Arroyo [1], would result in > rc=0 > Content mismatch at offset XYZ! before this change, and in > rc=1 > Content mismatch at offset XYZ! after this change. Note that this change does not affect the (default) 'unsafe' cache mode, because bdrv_co_flush() still skips flush to disk for that cache mode. [0]: > #!/bin/bash -x > dd if=/dev/urandom of=src.raw bs=1M count=500 > truncate -s 500M dst.img > LOOP=$(losetup --find --show dst.img) > SIZE=$(blockdev --getsz $LOOP) > dd if=/dev/zero of=$LOOP bs=1M count=500 conv=fsync status=none > sync > echo 3 > /proc/sys/vm/drop_caches > dmsetup create flk --table "0 $SIZE flakey $LOOP 0 5 5" > qemu-img convert -t writeback -p -r 100M -f raw -O raw src.raw /dev/mapper/flk > echo rc=$? > sleep 5 > dmsetup remove flk > qemu-img compare src.raw $LOOP > losetup -d $LOOP > rm src.raw dst.img [1]: https://lore.proxmox.com/pve-devel/[email protected]/ Signed-off-by: Fiona Ebner <[email protected]> Message-ID: <[email protected]> Reviewed-by: Eric Blake <[email protected]> Signed-off-by: Eric Blake <[email protected]> (cherry picked from commit 901ac73874c2129a17b6e54482aee800a0f9b2d2) Signed-off-by: Michael Tokarev <[email protected]> diff --git a/qemu-img.c b/qemu-img.c index a7ae3bd121a..e4961a90777 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -2248,7 +2248,7 @@ static int img_convert(int argc, char **argv) Error *local_err = NULL; bool writethrough, src_writethrough, image_opts = false, skip_create = false, progress = false, tgt_image_opts = false; - int64_t ret = -EINVAL; + int64_t ret = -EINVAL, ret2; bool force_share = false; bool explict_min_sparse = false; bool bitmaps = false; @@ -2790,6 +2790,12 @@ static int img_convert(int argc, char **argv) ret = convert_copy_bitmaps(blk_bs(s.src[0]), out_bs, skip_broken); } + ret2 = blk_flush(s.target); + if (ret2 < 0) { + error_report("Failed to flush target image: %s", strerror(-ret2)); + ret = ret != 0 ? ret : ret2; + } + out: if (!ret) { qemu_progress_print(100, 0); diff --git a/tests/qemu-iotests/122.out b/tests/qemu-iotests/122.out index 84283f24343..38794f96ac2 100644 --- a/tests/qemu-iotests/122.out +++ b/tests/qemu-iotests/122.out @@ -267,9 +267,10 @@ qemu-img convert exited with status 0 === failing flush after convert with 'writeback' cache mode === +qemu-img: Failed to flush target image: Input/output error qemu-img: Failed flush for 'json:{ /* filtered */ }' during close: Input/output error qemu-img: Failed to flush the L2 table cache: Input/output error qemu-img: Failed to flush the refcount block cache: Input/output error qemu-img: Failed flush for 'json:{ /* filtered */ }' during close: Input/output error -qemu-img convert exited with status 0 +qemu-img convert exited with status 1 *** done -- 2.47.3
