From b74b1adef00504c0df2d9600cec9ea824349952c Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 27 Feb 2019 14:44:13 +0000 Subject: [PATCH 01/33] iotests: use iotests.VM in 238 Test 238 does not require the kvm accelerator. Using the qtest accelerator allows the test to run in both non-kvm and non-tcg environments. iotests.VM implicitly uses the qtest accelerator and is really the class that this test should be using. Switch to that instead of qemu.QEMUMachine. Suggested-by: Thomas Huth Signed-off-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- tests/qemu-iotests/238 | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/tests/qemu-iotests/238 b/tests/qemu-iotests/238 index 688abc9acb..1c0a46fa90 100755 --- a/tests/qemu-iotests/238 +++ b/tests/qemu-iotests/238 @@ -23,17 +23,12 @@ import os import iotests from iotests import log -sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python')) - -from qemu import QEMUMachine - if iotests.qemu_default_machine == 's390-ccw-virtio': virtio_scsi_device = 'virtio-scsi-ccw' else: virtio_scsi_device = 'virtio-scsi-pci' -vm = QEMUMachine(iotests.qemu_prog) -vm.add_args('-machine', 'accel=kvm') +vm = iotests.VM() vm.launch() log(vm.qmp('blockdev-add', node_name='hd0', driver='null-co')) From af39bd0d9a889ac6a412dafd50aee0e84ccfa291 Mon Sep 17 00:00:00 2001 From: Alberto Garcia Date: Wed, 13 Feb 2019 18:48:53 +0200 Subject: [PATCH 02/33] qcow2: Default to 4KB for the qcow2 cache entry size QEMU 2.12 (commit 1221fe6f636754ab5f2c1c87caa77633e9123622) introduced a new setting called l2-cache-entry-size that allows making entries on the qcow2 L2 cache smaller than the cluster size. I have been performing several tests with different cluster and entry sizes and all of them show that reducing the entry size (aka L2 slice) consistently improves I/O performance, notably during random I/O (all tests done with sequential I/O show similar results). This is to be expected because loading and evicting an L2 slice is more expensive the larger the slice is. Here are some numbers on fully populated 40GB qcow2 images. The rightmost column represents the maximum L2 cache size in both cases. Cluster size = 64 KB |-------------+--------------+--------------+--------------| | | 1MB L2 cache | 3MB L2 cache | 5MB L2 cache | |-------------+--------------+--------------+--------------| | 4KB slices | 6545 IOPS | 12045 IOPS | 55680 IOPS | | 16KB slices | 5177 IOPS | 9798 IOPS | 56278 IOPS | | 64KB slices | 2718 IOPS | 5326 IOPS | 57355 IOPS | |-------------+--------------+--------------+--------------| Cluster size = 256 KB |--------------+----------------+--------------+-----------------| | | 512KB L2 cache | 1MB L2 cache | 1280KB L2 cache | |--------------+----------------+--------------+-----------------| | 4KB slices | 8539 IOPS | 21071 IOPS | 55417 IOPS | | 64KB slices | 3598 IOPS | 9772 IOPS | 57687 IOPS | | 256KB slices | 1415 IOPS | 4120 IOPS | 58001 IOPS | |--------------+----------------+--------------+-----------------| As can be seen in the numbers, the only exception to the rule is when the cache is large enough to hold all L2 tables. This is also to be expected because in this case no cache entry is ever evicted so reducing its size doesn't bring any benefit. This patch sets the default L2 cache entry size to 4KB except when the cache is large enough for the whole disk. Signed-off-by: Alberto Garcia Signed-off-by: Kevin Wolf --- block/qcow2.c | 12 ++++++++++++ docs/qcow2-cache.txt | 17 +++++++++++------ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index 7fb2730f09..48d22f48d5 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -788,6 +788,7 @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts, BDRVQcow2State *s = bs->opaque; uint64_t combined_cache_size, l2_cache_max_setting; bool l2_cache_size_set, refcount_cache_size_set, combined_cache_size_set; + bool l2_cache_entry_size_set; int min_refcount_cache = MIN_REFCOUNT_CACHE_SIZE * s->cluster_size; uint64_t virtual_disk_size = bs->total_sectors * BDRV_SECTOR_SIZE; uint64_t max_l2_cache = virtual_disk_size / (s->cluster_size / 8); @@ -795,6 +796,7 @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts, combined_cache_size_set = qemu_opt_get(opts, QCOW2_OPT_CACHE_SIZE); l2_cache_size_set = qemu_opt_get(opts, QCOW2_OPT_L2_CACHE_SIZE); refcount_cache_size_set = qemu_opt_get(opts, QCOW2_OPT_REFCOUNT_CACHE_SIZE); + l2_cache_entry_size_set = qemu_opt_get(opts, QCOW2_OPT_L2_CACHE_ENTRY_SIZE); combined_cache_size = qemu_opt_get_size(opts, QCOW2_OPT_CACHE_SIZE, 0); l2_cache_max_setting = qemu_opt_get_size(opts, QCOW2_OPT_L2_CACHE_SIZE, @@ -841,6 +843,16 @@ static void read_cache_sizes(BlockDriverState *bs, QemuOpts *opts, } } } + + /* + * If the L2 cache is not enough to cover the whole disk then + * default to 4KB entries. Smaller entries reduce the cost of + * loads and evictions and increase I/O performance. + */ + if (*l2_cache_size < max_l2_cache && !l2_cache_entry_size_set) { + *l2_cache_entry_size = MIN(s->cluster_size, 4096); + } + /* l2_cache_size and refcount_cache_size are ensured to have at least * their minimum values in qcow2_update_options_prepare() */ diff --git a/docs/qcow2-cache.txt b/docs/qcow2-cache.txt index c1e7751fea..d57f409861 100644 --- a/docs/qcow2-cache.txt +++ b/docs/qcow2-cache.txt @@ -158,10 +158,10 @@ refcount cache is as small as possible unless overridden by the user. Using smaller cache entries --------------------------- -The qcow2 L2 cache stores complete tables by default. This means that -if QEMU needs an entry from an L2 table then the whole table is read -from disk and is kept in the cache. If the cache is full then a -complete table needs to be evicted first. +The qcow2 L2 cache can store complete tables. This means that if QEMU +needs an entry from an L2 table then the whole table is read from disk +and is kept in the cache. If the cache is full then a complete table +needs to be evicted first. This can be inefficient with large cluster sizes since it results in more disk I/O and wastes more cache memory. @@ -172,6 +172,9 @@ it smaller than the cluster size. This can be configured using the -drive file=hd.qcow2,l2-cache-size=2097152,l2-cache-entry-size=4096 +Since QEMU 4.0 the value of l2-cache-entry-size defaults to 4KB (or +the cluster size if it's smaller). + Some things to take into account: - The L2 cache entry size has the same restrictions as the cluster @@ -185,7 +188,8 @@ Some things to take into account: - Try different entry sizes to see which one gives faster performance in your case. The block size of the host filesystem is generally a - good default (usually 4096 bytes in the case of ext4). + good default (usually 4096 bytes in the case of ext4, hence the + default). - Only the L2 cache can be configured this way. The refcount cache always uses the cluster size as the entry size. @@ -194,7 +198,8 @@ Some things to take into account: (as explained in the "Choosing the right cache sizes" and "How to configure the cache sizes" sections in this document) then none of this is necessary and you can omit the "l2-cache-entry-size" - parameter altogether. + parameter altogether. In this case QEMU makes the entry size + equal to the cluster size by default. Reducing the memory usage From ce090f656c44b357f6caf8f6000648744fbb655b Mon Sep 17 00:00:00 2001 From: Andrey Shinkevich Date: Thu, 7 Mar 2019 16:33:57 +0300 Subject: [PATCH 03/33] iotests: open notrun files in text mode Replace the binary mode with the default text one when *.notrun files are opened for skipped tests. That change is made for the compatibility with Python 3 which returns error otherwise. Signed-off-by: Kevin Wolf Signed-off-by: Andrey Shinkevich Signed-off-by: Kevin Wolf --- tests/qemu-iotests/iotests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 3d15571688..46fad4ce81 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -712,7 +712,7 @@ def notrun(reason): # Each test in qemu-iotests has a number ("seq") seq = os.path.basename(sys.argv[0]) - open('%s/%s.notrun' % (output_dir, seq), 'wb').write(reason + '\n') + open('%s/%s.notrun' % (output_dir, seq), 'w').write(reason + '\n') print('%s not run: %s' % (seq, reason)) sys.exit(0) From 9ac404c5233f3033435ab250d30ea9f776188a01 Mon Sep 17 00:00:00 2001 From: Andrey Shinkevich Date: Thu, 7 Mar 2019 16:33:58 +0300 Subject: [PATCH 04/33] block: iterate_format with account of whitelisting bdrv_iterate_format (which is currently only used for printing out the formats supported by the block layer) doesn't take format whitelisting into account. This creates a problem for tests: they enumerate supported formats to decide which tests to enable, but then discover that QEMU doesn't let them actually use some of those formats. To avoid that, exclude formats that are not whitelisted from enumeration, if whitelisting is in use. Since we have separate whitelists for r/w and r/o, take this a parameter to bdrv_iterate_format, and print two lists of supported formats (r/w and r/o) in main qemu. Signed-off-by: Roman Kagan Signed-off-by: Andrey Shinkevich Signed-off-by: Kevin Wolf --- block.c | 23 +++++++++++++++++++---- blockdev.c | 4 +++- include/block/block.h | 2 +- qemu-img.c | 2 +- 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/block.c b/block.c index 35e78e2172..ccf008c177 100644 --- a/block.c +++ b/block.c @@ -426,7 +426,7 @@ BlockDriver *bdrv_find_format(const char *format_name) return bdrv_do_find_format(format_name); } -int bdrv_is_whitelisted(BlockDriver *drv, bool read_only) +static int bdrv_format_is_whitelisted(const char *format_name, bool read_only) { static const char *whitelist_rw[] = { CONFIG_BDRV_RW_WHITELIST @@ -441,13 +441,13 @@ int bdrv_is_whitelisted(BlockDriver *drv, bool read_only) } for (p = whitelist_rw; *p; p++) { - if (!strcmp(drv->format_name, *p)) { + if (!strcmp(format_name, *p)) { return 1; } } if (read_only) { for (p = whitelist_ro; *p; p++) { - if (!strcmp(drv->format_name, *p)) { + if (!strcmp(format_name, *p)) { return 1; } } @@ -455,6 +455,11 @@ int bdrv_is_whitelisted(BlockDriver *drv, bool read_only) return 0; } +int bdrv_is_whitelisted(BlockDriver *drv, bool read_only) +{ + return bdrv_format_is_whitelisted(drv->format_name, read_only); +} + bool bdrv_uses_whitelist(void) { return use_bdrv_whitelist; @@ -4147,7 +4152,7 @@ static int qsort_strcmp(const void *a, const void *b) } void bdrv_iterate_format(void (*it)(void *opaque, const char *name), - void *opaque) + void *opaque, bool read_only) { BlockDriver *drv; int count = 0; @@ -4158,6 +4163,11 @@ void bdrv_iterate_format(void (*it)(void *opaque, const char *name), if (drv->format_name) { bool found = false; int i = count; + + if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv, read_only)) { + continue; + } + while (formats && i && !found) { found = !strcmp(formats[--i], drv->format_name); } @@ -4176,6 +4186,11 @@ void bdrv_iterate_format(void (*it)(void *opaque, const char *name), bool found = false; int j = count; + if (use_bdrv_whitelist && + !bdrv_format_is_whitelisted(format_name, read_only)) { + continue; + } + while (formats && j && !found) { found = !strcmp(formats[--j], format_name); } diff --git a/blockdev.c b/blockdev.c index 7e6bf9955c..871966ca13 100644 --- a/blockdev.c +++ b/blockdev.c @@ -531,7 +531,9 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, if ((buf = qemu_opt_get(opts, "format")) != NULL) { if (is_help_option(buf)) { error_printf("Supported formats:"); - bdrv_iterate_format(bdrv_format_print, NULL); + bdrv_iterate_format(bdrv_format_print, NULL, false); + error_printf("\nSupported formats (read-only):"); + bdrv_iterate_format(bdrv_format_print, NULL, true); error_printf("\n"); goto early_err; } diff --git a/include/block/block.h b/include/block/block.h index 5b5cf868df..6a758a76f8 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -472,7 +472,7 @@ void bdrv_next_cleanup(BdrvNextIterator *it); BlockDriverState *bdrv_next_monitor_owned(BlockDriverState *bs); bool bdrv_is_encrypted(BlockDriverState *bs); void bdrv_iterate_format(void (*it)(void *opaque, const char *name), - void *opaque); + void *opaque, bool read_only); const char *bdrv_get_node_name(const BlockDriverState *bs); const char *bdrv_get_device_name(const BlockDriverState *bs); const char *bdrv_get_device_or_node_name(const BlockDriverState *bs); diff --git a/qemu-img.c b/qemu-img.c index 660c01898e..5fac840742 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -198,7 +198,7 @@ static void QEMU_NORETURN help(void) " 'skip=N' skip N bs-sized blocks at the start of input\n"; printf("%s\nSupported formats:", help_msg); - bdrv_iterate_format(format_print, NULL); + bdrv_iterate_format(format_print, NULL, false); printf("\n\n" QEMU_HELP_BOTTOM "\n"); exit(EXIT_SUCCESS); } From 57ed557f03e162904d6b137d315526304ac2083b Mon Sep 17 00:00:00 2001 From: Andrey Shinkevich Date: Thu, 7 Mar 2019 16:33:59 +0300 Subject: [PATCH 05/33] iotests: ask QEMU for supported formats Supported formats listed by 'qemu' may differ from those listed by 'qemu-img' due to whitelists. Some test cases require specific formats that may be used with qemu. They can be inquired directly by running 'qemu -drive format=help'. The response takes whitelists into account. The method supported_formats() serves for that. The method decorator skip_if_unsupported() checks if all requested formats are whitelisted. If not, the test case will be skipped. That has been implemented in the 'check' file in the way similar to the 'test notrun' mechanism. Suggested-by: Roman Kagan Suggested-by: Vladimir Sementsov-Ogievskiy Suggested-by: Kevin Wolf Signed-off-by: Andrey Shinkevich Signed-off-by: Kevin Wolf --- tests/qemu-iotests/check | 13 ++++++++++- tests/qemu-iotests/iotests.py | 43 +++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check index 895e1e3dcb..1016887438 100755 --- a/tests/qemu-iotests/check +++ b/tests/qemu-iotests/check @@ -25,6 +25,7 @@ try=0 n_bad=0 bad="" notrun="" +casenotrun="" interrupt=true # by default don't output timestamps @@ -664,6 +665,11 @@ END { if (NR > 0) { echo "Not run:$notrun" echo "Not run:$notrun" >>check.log fi + if [ ! -z "$casenotrun" ] + then + echo "Some cases not run in:$casenotrun" + echo "Some cases not run in:$casenotrun" >>check.log + fi if [ ! -z "$n_bad" -a $n_bad != 0 ] then echo "Failures:$bad" @@ -743,6 +749,7 @@ do printf " " # prettier output with timestamps. fi rm -f core $seq.notrun + rm -f $seq.casenotrun start=$(_wallclock) $timestamp && printf %s " [$(date "+%T")]" @@ -823,7 +830,11 @@ do fi fi fi - + if [ -f $seq.casenotrun ] + then + cat $seq.casenotrun + casenotrun="$casenotrun $seq" + fi fi # come here for each test, except when $showme is true diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 46fad4ce81..997dc910cb 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -716,6 +716,14 @@ def notrun(reason): print('%s not run: %s' % (seq, reason)) sys.exit(0) +def case_notrun(reason): + '''Skip this test case''' + # Each test in qemu-iotests has a number ("seq") + seq = os.path.basename(sys.argv[0]) + + open('%s/%s.casenotrun' % (output_dir, seq), 'a').write( + ' [case not run] ' + reason + '\n') + def verify_image_format(supported_fmts=[], unsupported_fmts=[]): assert not (supported_fmts and unsupported_fmts) @@ -756,6 +764,41 @@ def verify_quorum(): if not supports_quorum(): notrun('quorum support missing') +def qemu_pipe(*args): + '''Run qemu with an option to print something and exit (e.g. a help option), + and return its output''' + args = [qemu_prog] + qemu_opts + list(args) + subp = subprocess.Popen(args, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + universal_newlines=True) + exitcode = subp.wait() + if exitcode < 0: + sys.stderr.write('qemu received signal %i: %s\n' % (-exitcode, + ' '.join(args))) + return subp.communicate()[0] + +def supported_formats(read_only=False): + '''Set 'read_only' to True to check ro-whitelist + Otherwise, rw-whitelist is checked''' + format_message = qemu_pipe("-drive", "format=help") + line = 1 if read_only else 0 + return format_message.splitlines()[line].split(":")[1].split() + +def skip_if_unsupported(required_formats=[], read_only=False): + '''Skip Test Decorator + Runs the test if all the required formats are whitelisted''' + def skip_test_decorator(func): + def func_wrapper(*args, **kwargs): + usf_list = list(set(required_formats) - + set(supported_formats(read_only))) + if usf_list: + case_notrun('{}: formats {} are not whitelisted'.format( + args[0], usf_list)) + else: + return func(*args, **kwargs) + return func_wrapper + return skip_test_decorator + def main(supported_fmts=[], supported_oses=['linux'], supported_cache_modes=[], unsupported_fmts=[]): '''Run tests''' From d9df28e7b07e842798dff9f8b24af2d78911dbb6 Mon Sep 17 00:00:00 2001 From: Andrey Shinkevich Date: Thu, 7 Mar 2019 16:34:00 +0300 Subject: [PATCH 06/33] iotests: check whitelisted formats Some test cases require specific formats. The method decorator skip_if_unsupported() checks if requested formats are whitelisted. The test #139 was selected for a sample output, after running $ ./check -qcow2 131-140 137 3s ... 138 0s ... 139 2s ... [case not run] testBlkDebug (__main__.TestBlockdevDel): formats ['blkdebug'] are not whitelisted [case not run] testBlkVerify (__main__.TestBlockdevDel): formats ['blkverify'] are not whitelisted [case not run] testQuorum (__main__.TestBlockdevDel): formats ['quorum'] are not whitelisted 140 0s ... Not run: 131 135 136 Some cases not run in: 139 Passed all 7 tests Signed-off-by: Andrey Shinkevich Signed-off-by: Kevin Wolf --- tests/qemu-iotests/139 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/qemu-iotests/139 b/tests/qemu-iotests/139 index 62402c1c35..933b45121a 100755 --- a/tests/qemu-iotests/139 +++ b/tests/qemu-iotests/139 @@ -325,6 +325,7 @@ class TestBlockdevDel(iotests.QMPTestCase): # FIXME mirror0 disappears, drive-mirror doesn't take a reference #self.delBlockDriverState('mirror0') + @iotests.skip_if_unsupported(['blkdebug']) def testBlkDebug(self): self.addBlkDebug('debug0', 'node0') # 'node0' is used by the blkdebug node @@ -333,6 +334,7 @@ class TestBlockdevDel(iotests.QMPTestCase): self.delBlockDriverState('debug0') self.checkBlockDriverState('node0', False) + @iotests.skip_if_unsupported(['blkverify']) def testBlkVerify(self): self.addBlkVerify('verify0', 'node0', 'node1') # We cannot remove the children of a blkverify device @@ -343,6 +345,7 @@ class TestBlockdevDel(iotests.QMPTestCase): self.checkBlockDriverState('node0', False) self.checkBlockDriverState('node1', False) + @iotests.skip_if_unsupported(['quorum']) def testQuorum(self): if not iotests.supports_quorum(): return From a03700fd3efdc7cff0e6310047e624d906645e46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 7 Mar 2019 15:58:36 +0100 Subject: [PATCH 07/33] tests/multiboot: Improve portability by searching bash in the $PATH MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bash is not always installed as /bin/bash. In particular on OpenBSD, the package installs it in /usr/local/bin. Use the 'env' shebang to search bash in the $PATH. Reviewed-by: Kamil Rytarowski Reviewed-by: Eric Blake Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Kevin Wolf --- tests/multiboot/run_test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/multiboot/run_test.sh b/tests/multiboot/run_test.sh index 6c33003e71..98df91e6af 100755 --- a/tests/multiboot/run_test.sh +++ b/tests/multiboot/run_test.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # Copyright (c) 2013 Kevin Wolf # From d68375816eca9e60d7c7edb290b1964d4d83e346 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 7 Mar 2019 15:58:37 +0100 Subject: [PATCH 08/33] tests/bios-tables: Improve portability by searching bash in the $PATH MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bash is not always installed as /bin/bash. In particular on OpenBSD, the package installs it in /usr/local/bin. Use the 'env' shebang to search bash in the $PATH. Reviewed-by: Kamil Rytarowski Reviewed-by: Igor Mammedov Reviewed-by: Michael S. Tsirkin Signed-off-by: Philippe Mathieu-Daudé Acked-by: Thomas Huth Signed-off-by: Kevin Wolf --- tests/data/acpi/rebuild-expected-aml.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/data/acpi/rebuild-expected-aml.sh b/tests/data/acpi/rebuild-expected-aml.sh index bf9ba242ad..abdff70a0d 100755 --- a/tests/data/acpi/rebuild-expected-aml.sh +++ b/tests/data/acpi/rebuild-expected-aml.sh @@ -1,4 +1,4 @@ -#! /bin/bash +#!/usr/bin/env bash # # Rebuild expected AML files for acpi unit-test From 11a82d14293cd66f428f535741717ff338c0722b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 7 Mar 2019 15:58:38 +0100 Subject: [PATCH 09/33] qemu-iotests: Improve portability by searching bash in the $PATH MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bash is not always installed as /bin/bash. In particular on OpenBSD, the package installs it in /usr/local/bin. Use the 'env' shebang to search bash in the $PATH. Patch created mechanically by running: $ git grep -lE '#! ?/bin/bash' -- tests/qemu-iotests \ | while read f; do \ sed -i 's|^#!.\?/bin/bash$|#!/usr/bin/env bash|' $f; \ done Reviewed-by: Eric Blake Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Kevin Wolf --- tests/qemu-iotests/001 | 2 +- tests/qemu-iotests/002 | 2 +- tests/qemu-iotests/003 | 2 +- tests/qemu-iotests/004 | 2 +- tests/qemu-iotests/005 | 2 +- tests/qemu-iotests/007 | 2 +- tests/qemu-iotests/008 | 2 +- tests/qemu-iotests/009 | 2 +- tests/qemu-iotests/010 | 2 +- tests/qemu-iotests/011 | 2 +- tests/qemu-iotests/012 | 2 +- tests/qemu-iotests/013 | 2 +- tests/qemu-iotests/014 | 2 +- tests/qemu-iotests/015 | 2 +- tests/qemu-iotests/017 | 2 +- tests/qemu-iotests/018 | 2 +- tests/qemu-iotests/019 | 2 +- tests/qemu-iotests/020 | 2 +- tests/qemu-iotests/021 | 2 +- tests/qemu-iotests/022 | 2 +- tests/qemu-iotests/023 | 2 +- tests/qemu-iotests/024 | 2 +- tests/qemu-iotests/025 | 2 +- tests/qemu-iotests/026 | 2 +- tests/qemu-iotests/027 | 2 +- tests/qemu-iotests/028 | 2 +- tests/qemu-iotests/029 | 2 +- tests/qemu-iotests/031 | 2 +- tests/qemu-iotests/032 | 2 +- tests/qemu-iotests/033 | 2 +- tests/qemu-iotests/034 | 2 +- tests/qemu-iotests/035 | 2 +- tests/qemu-iotests/036 | 2 +- tests/qemu-iotests/037 | 2 +- tests/qemu-iotests/038 | 2 +- tests/qemu-iotests/039 | 2 +- tests/qemu-iotests/042 | 2 +- tests/qemu-iotests/043 | 2 +- tests/qemu-iotests/046 | 2 +- tests/qemu-iotests/047 | 2 +- tests/qemu-iotests/048 | 2 +- tests/qemu-iotests/049 | 2 +- tests/qemu-iotests/050 | 2 +- tests/qemu-iotests/051 | 2 +- tests/qemu-iotests/052 | 2 +- tests/qemu-iotests/053 | 2 +- tests/qemu-iotests/054 | 2 +- tests/qemu-iotests/058 | 2 +- tests/qemu-iotests/059 | 2 +- tests/qemu-iotests/060 | 2 +- tests/qemu-iotests/061 | 2 +- tests/qemu-iotests/062 | 2 +- tests/qemu-iotests/063 | 2 +- tests/qemu-iotests/064 | 2 +- tests/qemu-iotests/066 | 2 +- tests/qemu-iotests/067 | 2 +- tests/qemu-iotests/068 | 2 +- tests/qemu-iotests/069 | 2 +- tests/qemu-iotests/070 | 2 +- tests/qemu-iotests/071 | 2 +- tests/qemu-iotests/072 | 2 +- tests/qemu-iotests/073 | 2 +- tests/qemu-iotests/074 | 2 +- tests/qemu-iotests/075 | 2 +- tests/qemu-iotests/076 | 2 +- tests/qemu-iotests/077 | 2 +- tests/qemu-iotests/078 | 2 +- tests/qemu-iotests/079 | 2 +- tests/qemu-iotests/080 | 2 +- tests/qemu-iotests/081 | 2 +- tests/qemu-iotests/082 | 2 +- tests/qemu-iotests/083 | 2 +- tests/qemu-iotests/084 | 2 +- tests/qemu-iotests/085 | 2 +- tests/qemu-iotests/086 | 2 +- tests/qemu-iotests/087 | 2 +- tests/qemu-iotests/088 | 2 +- tests/qemu-iotests/089 | 2 +- tests/qemu-iotests/090 | 2 +- tests/qemu-iotests/091 | 2 +- tests/qemu-iotests/092 | 2 +- tests/qemu-iotests/094 | 2 +- tests/qemu-iotests/095 | 2 +- tests/qemu-iotests/097 | 2 +- tests/qemu-iotests/098 | 2 +- tests/qemu-iotests/099 | 2 +- tests/qemu-iotests/101 | 2 +- tests/qemu-iotests/102 | 2 +- tests/qemu-iotests/103 | 2 +- tests/qemu-iotests/104 | 2 +- tests/qemu-iotests/105 | 2 +- tests/qemu-iotests/106 | 2 +- tests/qemu-iotests/107 | 2 +- tests/qemu-iotests/108 | 2 +- tests/qemu-iotests/109 | 2 +- tests/qemu-iotests/110 | 2 +- tests/qemu-iotests/111 | 2 +- tests/qemu-iotests/112 | 2 +- tests/qemu-iotests/113 | 2 +- tests/qemu-iotests/114 | 2 +- tests/qemu-iotests/115 | 2 +- tests/qemu-iotests/116 | 2 +- tests/qemu-iotests/117 | 2 +- tests/qemu-iotests/119 | 2 +- tests/qemu-iotests/120 | 2 +- tests/qemu-iotests/121 | 2 +- tests/qemu-iotests/122 | 2 +- tests/qemu-iotests/123 | 2 +- tests/qemu-iotests/125 | 2 +- tests/qemu-iotests/126 | 2 +- tests/qemu-iotests/127 | 2 +- tests/qemu-iotests/128 | 2 +- tests/qemu-iotests/130 | 2 +- tests/qemu-iotests/131 | 2 +- tests/qemu-iotests/133 | 2 +- tests/qemu-iotests/134 | 2 +- tests/qemu-iotests/135 | 2 +- tests/qemu-iotests/137 | 2 +- tests/qemu-iotests/138 | 2 +- tests/qemu-iotests/140 | 2 +- tests/qemu-iotests/141 | 2 +- tests/qemu-iotests/142 | 2 +- tests/qemu-iotests/143 | 2 +- tests/qemu-iotests/144 | 2 +- tests/qemu-iotests/145 | 2 +- tests/qemu-iotests/146 | 2 +- tests/qemu-iotests/150 | 2 +- tests/qemu-iotests/153 | 2 +- tests/qemu-iotests/154 | 2 +- tests/qemu-iotests/156 | 2 +- tests/qemu-iotests/157 | 2 +- tests/qemu-iotests/158 | 2 +- tests/qemu-iotests/159 | 2 +- tests/qemu-iotests/160 | 2 +- tests/qemu-iotests/161 | 2 +- tests/qemu-iotests/162 | 2 +- tests/qemu-iotests/170 | 2 +- tests/qemu-iotests/171 | 2 +- tests/qemu-iotests/172 | 2 +- tests/qemu-iotests/173 | 2 +- tests/qemu-iotests/174 | 2 +- tests/qemu-iotests/175 | 2 +- tests/qemu-iotests/176 | 2 +- tests/qemu-iotests/177 | 2 +- tests/qemu-iotests/178 | 2 +- tests/qemu-iotests/179 | 2 +- tests/qemu-iotests/181 | 2 +- tests/qemu-iotests/182 | 2 +- tests/qemu-iotests/183 | 2 +- tests/qemu-iotests/184 | 2 +- tests/qemu-iotests/185 | 2 +- tests/qemu-iotests/186 | 2 +- tests/qemu-iotests/187 | 2 +- tests/qemu-iotests/188 | 2 +- tests/qemu-iotests/189 | 2 +- tests/qemu-iotests/190 | 2 +- tests/qemu-iotests/191 | 2 +- tests/qemu-iotests/192 | 2 +- tests/qemu-iotests/195 | 2 +- tests/qemu-iotests/197 | 2 +- tests/qemu-iotests/198 | 2 +- tests/qemu-iotests/200 | 2 +- tests/qemu-iotests/201 | 2 +- tests/qemu-iotests/204 | 2 +- tests/qemu-iotests/214 | 2 +- tests/qemu-iotests/215 | 2 +- tests/qemu-iotests/217 | 2 +- tests/qemu-iotests/220 | 2 +- tests/qemu-iotests/221 | 2 +- tests/qemu-iotests/223 | 2 +- tests/qemu-iotests/225 | 2 +- tests/qemu-iotests/226 | 2 +- tests/qemu-iotests/227 | 2 +- tests/qemu-iotests/229 | 2 +- tests/qemu-iotests/231 | 2 +- tests/qemu-iotests/232 | 2 +- tests/qemu-iotests/233 | 2 +- tests/qemu-iotests/check | 2 +- tests/qemu-iotests/common.config | 2 +- tests/qemu-iotests/common.filter | 2 +- tests/qemu-iotests/common.nbd | 2 +- tests/qemu-iotests/common.pattern | 2 +- tests/qemu-iotests/common.qemu | 2 +- tests/qemu-iotests/common.rc | 2 +- tests/qemu-iotests/common.tls | 2 +- 185 files changed, 185 insertions(+), 185 deletions(-) diff --git a/tests/qemu-iotests/001 b/tests/qemu-iotests/001 index 55dcbb71d9..5d266e170a 100755 --- a/tests/qemu-iotests/001 +++ b/tests/qemu-iotests/001 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test simple read/write using plain bdrv_read/bdrv_write # diff --git a/tests/qemu-iotests/002 b/tests/qemu-iotests/002 index 74572b4711..7fb85084a1 100755 --- a/tests/qemu-iotests/002 +++ b/tests/qemu-iotests/002 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test simple read/write using plain bdrv_pread/bdrv_pwrite # diff --git a/tests/qemu-iotests/003 b/tests/qemu-iotests/003 index bf2595559b..f008c57cdc 100755 --- a/tests/qemu-iotests/003 +++ b/tests/qemu-iotests/003 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test simple read/write using bdrv_aio_readv/bdrv_aio_writev # diff --git a/tests/qemu-iotests/004 b/tests/qemu-iotests/004 index 841b15dfac..64fab3e714 100755 --- a/tests/qemu-iotests/004 +++ b/tests/qemu-iotests/004 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Make sure we can't read and write outside of the image size. # diff --git a/tests/qemu-iotests/005 b/tests/qemu-iotests/005 index 8aa4283a4d..2fef63af88 100755 --- a/tests/qemu-iotests/005 +++ b/tests/qemu-iotests/005 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Make sure qemu-img can create 5TB images # diff --git a/tests/qemu-iotests/007 b/tests/qemu-iotests/007 index b983022a7f..3ab5490db3 100755 --- a/tests/qemu-iotests/007 +++ b/tests/qemu-iotests/007 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Check for one possible case of qcow2 refcount corruption. # diff --git a/tests/qemu-iotests/008 b/tests/qemu-iotests/008 index 8dfa10bcb8..75067e36ad 100755 --- a/tests/qemu-iotests/008 +++ b/tests/qemu-iotests/008 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test simple asynchronous read/write operations. # diff --git a/tests/qemu-iotests/009 b/tests/qemu-iotests/009 index 73ae09db69..bc4b461122 100755 --- a/tests/qemu-iotests/009 +++ b/tests/qemu-iotests/009 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Nolan I qcow2 corruption - incorrectly reports free clusters # diff --git a/tests/qemu-iotests/010 b/tests/qemu-iotests/010 index 751aca9813..6920408d28 100755 --- a/tests/qemu-iotests/010 +++ b/tests/qemu-iotests/010 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Nolan II qcow2 corruption - wrong used cluster # diff --git a/tests/qemu-iotests/011 b/tests/qemu-iotests/011 index 35909564a9..b4c7e8f799 100755 --- a/tests/qemu-iotests/011 +++ b/tests/qemu-iotests/011 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test for AIO allocation on the same cluster # diff --git a/tests/qemu-iotests/012 b/tests/qemu-iotests/012 index de9a5fb4d5..2c3b42d9dd 100755 --- a/tests/qemu-iotests/012 +++ b/tests/qemu-iotests/012 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Make sure we can open read-only images # diff --git a/tests/qemu-iotests/013 b/tests/qemu-iotests/013 index 5e1efcee28..5cb9032f16 100755 --- a/tests/qemu-iotests/013 +++ b/tests/qemu-iotests/013 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # qcow2 pattern test, empty and compressed image - 4k cluster patterns # diff --git a/tests/qemu-iotests/014 b/tests/qemu-iotests/014 index 9ade571a95..2f728a1956 100755 --- a/tests/qemu-iotests/014 +++ b/tests/qemu-iotests/014 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # qcow2 pattern test, complex patterns including compression and snapshots # Using patterns for 4k cluster size. diff --git a/tests/qemu-iotests/015 b/tests/qemu-iotests/015 index 21f7d42c84..5a4063e4f5 100755 --- a/tests/qemu-iotests/015 +++ b/tests/qemu-iotests/015 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Combined test to grow the refcount table and test snapshots. # diff --git a/tests/qemu-iotests/017 b/tests/qemu-iotests/017 index 1ac6f74502..83744f29a3 100755 --- a/tests/qemu-iotests/017 +++ b/tests/qemu-iotests/017 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Simple backing file reads # diff --git a/tests/qemu-iotests/018 b/tests/qemu-iotests/018 index bba30a1be2..78169838ba 100755 --- a/tests/qemu-iotests/018 +++ b/tests/qemu-iotests/018 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Merge backing file into test image when converting the image # diff --git a/tests/qemu-iotests/019 b/tests/qemu-iotests/019 index 8f911a79c1..a56dd30bed 100755 --- a/tests/qemu-iotests/019 +++ b/tests/qemu-iotests/019 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # When using a backing file for the output image in qemu-img convert, # the backing file clusters must not copied. The data must still be diff --git a/tests/qemu-iotests/020 b/tests/qemu-iotests/020 index 6b972d082f..71fa753b4e 100755 --- a/tests/qemu-iotests/020 +++ b/tests/qemu-iotests/020 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Commit changes to backing file # diff --git a/tests/qemu-iotests/021 b/tests/qemu-iotests/021 index c15ebf9eb8..f6555f3b74 100755 --- a/tests/qemu-iotests/021 +++ b/tests/qemu-iotests/021 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test handling of invalid patterns arguments to qemu-io # diff --git a/tests/qemu-iotests/022 b/tests/qemu-iotests/022 index 44765c7b7a..b68cd64b33 100755 --- a/tests/qemu-iotests/022 +++ b/tests/qemu-iotests/022 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test bdrv_load/save_vmstate using the usual patterns # diff --git a/tests/qemu-iotests/023 b/tests/qemu-iotests/023 index c8e1b9a761..02ed047820 100755 --- a/tests/qemu-iotests/023 +++ b/tests/qemu-iotests/023 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # qcow2 pattern test with various cluster sizes # diff --git a/tests/qemu-iotests/024 b/tests/qemu-iotests/024 index 428b5c815d..23298c6f59 100755 --- a/tests/qemu-iotests/024 +++ b/tests/qemu-iotests/024 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Rebasing COW images # diff --git a/tests/qemu-iotests/025 b/tests/qemu-iotests/025 index fcd4d97c17..d9a4ebc5e7 100755 --- a/tests/qemu-iotests/025 +++ b/tests/qemu-iotests/025 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Resizing images # diff --git a/tests/qemu-iotests/026 b/tests/qemu-iotests/026 index 31276d9027..ca89ad7048 100755 --- a/tests/qemu-iotests/026 +++ b/tests/qemu-iotests/026 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # qcow2 error path testing # diff --git a/tests/qemu-iotests/027 b/tests/qemu-iotests/027 index 2c46ae1457..b7df9701f7 100755 --- a/tests/qemu-iotests/027 +++ b/tests/qemu-iotests/027 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test that sub-cluster allocating writes zero the rest of the cluster # diff --git a/tests/qemu-iotests/028 b/tests/qemu-iotests/028 index a2a7c93bcd..01f495912f 100755 --- a/tests/qemu-iotests/028 +++ b/tests/qemu-iotests/028 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test that backing files can be smaller than the image # diff --git a/tests/qemu-iotests/029 b/tests/qemu-iotests/029 index cf0fe0f6a6..5f42f76cc6 100755 --- a/tests/qemu-iotests/029 +++ b/tests/qemu-iotests/029 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # qcow2 internal snapshots/VM state tests # diff --git a/tests/qemu-iotests/031 b/tests/qemu-iotests/031 index ac0dfaed7d..ef92d8eee3 100755 --- a/tests/qemu-iotests/031 +++ b/tests/qemu-iotests/031 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test that all qcow2 header extensions survive a header rewrite # diff --git a/tests/qemu-iotests/032 b/tests/qemu-iotests/032 index 3e86bb0111..a1757bb15e 100755 --- a/tests/qemu-iotests/032 +++ b/tests/qemu-iotests/032 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test that AIO requests are drained before an image is closed. This used # to segfault because the request coroutine kept running even after the diff --git a/tests/qemu-iotests/033 b/tests/qemu-iotests/033 index 46b91388ef..cfdf1ec2ba 100755 --- a/tests/qemu-iotests/033 +++ b/tests/qemu-iotests/033 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test aligned and misaligned write zeroes operations. # diff --git a/tests/qemu-iotests/034 b/tests/qemu-iotests/034 index 62812cd53c..324bed28c6 100755 --- a/tests/qemu-iotests/034 +++ b/tests/qemu-iotests/034 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test bdrv_pwrite_zeroes with backing files (see also 154) # diff --git a/tests/qemu-iotests/035 b/tests/qemu-iotests/035 index 85d9ef7f8e..46aa835936 100755 --- a/tests/qemu-iotests/035 +++ b/tests/qemu-iotests/035 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Let a few AIO requests run in parallel and have them access different L2 # tables so that the cache has a chance to get used up. diff --git a/tests/qemu-iotests/036 b/tests/qemu-iotests/036 index 4e76602a93..1b56394129 100755 --- a/tests/qemu-iotests/036 +++ b/tests/qemu-iotests/036 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test qcow2 feature bits # diff --git a/tests/qemu-iotests/037 b/tests/qemu-iotests/037 index a11992dad2..0781bebefe 100755 --- a/tests/qemu-iotests/037 +++ b/tests/qemu-iotests/037 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test COW from backing files # diff --git a/tests/qemu-iotests/038 b/tests/qemu-iotests/038 index 575093e8cf..707e2d72e9 100755 --- a/tests/qemu-iotests/038 +++ b/tests/qemu-iotests/038 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test COW from backing files with AIO # diff --git a/tests/qemu-iotests/039 b/tests/qemu-iotests/039 index b3c344cb27..0d4e963bd4 100755 --- a/tests/qemu-iotests/039 +++ b/tests/qemu-iotests/039 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test qcow2 lazy refcounts # diff --git a/tests/qemu-iotests/042 b/tests/qemu-iotests/042 index beaa339000..a9a7fc3041 100755 --- a/tests/qemu-iotests/042 +++ b/tests/qemu-iotests/042 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test qemu-img operation on zero size images # diff --git a/tests/qemu-iotests/043 b/tests/qemu-iotests/043 index fc9005b28f..9894b154ec 100755 --- a/tests/qemu-iotests/043 +++ b/tests/qemu-iotests/043 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test that qemu-img info --backing-chain detects infinite loops # diff --git a/tests/qemu-iotests/046 b/tests/qemu-iotests/046 index 5e41d96daa..95160bea4c 100755 --- a/tests/qemu-iotests/046 +++ b/tests/qemu-iotests/046 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test concurrent cluster allocations # diff --git a/tests/qemu-iotests/047 b/tests/qemu-iotests/047 index 6e776d2ce5..ce81fc6fa7 100755 --- a/tests/qemu-iotests/047 +++ b/tests/qemu-iotests/047 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Regression test for commit b7ab0fea (which was a corruption fix, # despite the commit message claiming otherwise) diff --git a/tests/qemu-iotests/048 b/tests/qemu-iotests/048 index 9ed04a068d..bde408ca92 100755 --- a/tests/qemu-iotests/048 +++ b/tests/qemu-iotests/048 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash ## ## qemu-img compare test ## diff --git a/tests/qemu-iotests/049 b/tests/qemu-iotests/049 index 97d8a64697..bc09cd6717 100755 --- a/tests/qemu-iotests/049 +++ b/tests/qemu-iotests/049 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Check qemu-img option parsing # diff --git a/tests/qemu-iotests/050 b/tests/qemu-iotests/050 index 963a0db97f..dd7b2c72eb 100755 --- a/tests/qemu-iotests/050 +++ b/tests/qemu-iotests/050 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test qemu-img rebase with zero clusters # diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051 index 32741d7efd..3b50c7f188 100755 --- a/tests/qemu-iotests/051 +++ b/tests/qemu-iotests/051 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test command line configuration of block devices and driver-specific options # diff --git a/tests/qemu-iotests/052 b/tests/qemu-iotests/052 index b992adf4ff..b3a2dc1143 100755 --- a/tests/qemu-iotests/052 +++ b/tests/qemu-iotests/052 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test bdrv_read/bdrv_write using BDRV_O_SNAPSHOT # diff --git a/tests/qemu-iotests/053 b/tests/qemu-iotests/053 index afa109c950..50c62f0f56 100755 --- a/tests/qemu-iotests/053 +++ b/tests/qemu-iotests/053 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test qemu-img convert when image length is not a multiple of cluster size # diff --git a/tests/qemu-iotests/054 b/tests/qemu-iotests/054 index cf88a7c76e..0d5e14f847 100755 --- a/tests/qemu-iotests/054 +++ b/tests/qemu-iotests/054 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test huge qcow2 images # diff --git a/tests/qemu-iotests/058 b/tests/qemu-iotests/058 index d6d4f94d5d..8c3212a72f 100755 --- a/tests/qemu-iotests/058 +++ b/tests/qemu-iotests/058 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test export internal snapshot by qemu-nbd, convert it by qemu-img. # diff --git a/tests/qemu-iotests/059 b/tests/qemu-iotests/059 index 54d5567acc..279aee6815 100755 --- a/tests/qemu-iotests/059 +++ b/tests/qemu-iotests/059 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for vmdk # diff --git a/tests/qemu-iotests/060 b/tests/qemu-iotests/060 index af0588ae9a..89e911400c 100755 --- a/tests/qemu-iotests/060 +++ b/tests/qemu-iotests/060 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for image corruption (overlapping data structures) in qcow2 # diff --git a/tests/qemu-iotests/061 b/tests/qemu-iotests/061 index 1a50163419..d2e68c0203 100755 --- a/tests/qemu-iotests/061 +++ b/tests/qemu-iotests/061 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for image option amendment in qcow2. # diff --git a/tests/qemu-iotests/062 b/tests/qemu-iotests/062 index 985fbef41e..ed7400fed2 100755 --- a/tests/qemu-iotests/062 +++ b/tests/qemu-iotests/062 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for snapshotting images with unallocated zero clusters in # qcow2 diff --git a/tests/qemu-iotests/063 b/tests/qemu-iotests/063 index 041fb5c1ac..2d5c0ce9fb 100755 --- a/tests/qemu-iotests/063 +++ b/tests/qemu-iotests/063 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # test of qemu-img convert -n - convert without creation # diff --git a/tests/qemu-iotests/064 b/tests/qemu-iotests/064 index f55ff37ca7..90673186ec 100755 --- a/tests/qemu-iotests/064 +++ b/tests/qemu-iotests/064 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test VHDX read/write from a sample image created with Hyper-V # diff --git a/tests/qemu-iotests/066 b/tests/qemu-iotests/066 index 26c043711b..f480986e35 100755 --- a/tests/qemu-iotests/066 +++ b/tests/qemu-iotests/066 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for preallocated zero clusters in qcow2 # diff --git a/tests/qemu-iotests/067 b/tests/qemu-iotests/067 index 342b2b0a30..fda16a6b0d 100755 --- a/tests/qemu-iotests/067 +++ b/tests/qemu-iotests/067 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test automatic deletion of BDSes created by -drive/drive_add # diff --git a/tests/qemu-iotests/068 b/tests/qemu-iotests/068 index f0583d52ae..881a022107 100755 --- a/tests/qemu-iotests/068 +++ b/tests/qemu-iotests/068 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for loading a saved VM state from a qcow2 image # diff --git a/tests/qemu-iotests/069 b/tests/qemu-iotests/069 index fdee121f43..6a8e4aa22e 100755 --- a/tests/qemu-iotests/069 +++ b/tests/qemu-iotests/069 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for deleting a backing file # diff --git a/tests/qemu-iotests/070 b/tests/qemu-iotests/070 index 78e0390f5f..cb0f927c16 100755 --- a/tests/qemu-iotests/070 +++ b/tests/qemu-iotests/070 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test VHDX log replay from an image with a journal that needs to be # replayed diff --git a/tests/qemu-iotests/071 b/tests/qemu-iotests/071 index 6e467dc1da..7f3e5abd57 100755 --- a/tests/qemu-iotests/071 +++ b/tests/qemu-iotests/071 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for the QMP blkdebug and blkverify interfaces # diff --git a/tests/qemu-iotests/072 b/tests/qemu-iotests/072 index 08ef29f5b4..6f9f247fa5 100755 --- a/tests/qemu-iotests/072 +++ b/tests/qemu-iotests/072 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for nested image formats # diff --git a/tests/qemu-iotests/073 b/tests/qemu-iotests/073 index 5e7f76cb7f..990f90acbd 100755 --- a/tests/qemu-iotests/073 +++ b/tests/qemu-iotests/073 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test count_contiguous_clusters in qcow2 # diff --git a/tests/qemu-iotests/074 b/tests/qemu-iotests/074 index b17866bd34..bb4ad1cc08 100755 --- a/tests/qemu-iotests/074 +++ b/tests/qemu-iotests/074 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash ## ## qemu-img compare test (qcow2 only ones) ## diff --git a/tests/qemu-iotests/075 b/tests/qemu-iotests/075 index 45b8901ef0..389d5675fa 100755 --- a/tests/qemu-iotests/075 +++ b/tests/qemu-iotests/075 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # cloop format input validation tests # diff --git a/tests/qemu-iotests/076 b/tests/qemu-iotests/076 index 3b5ab3fd08..0d405ef3f2 100755 --- a/tests/qemu-iotests/076 +++ b/tests/qemu-iotests/076 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # parallels format input validation tests # diff --git a/tests/qemu-iotests/077 b/tests/qemu-iotests/077 index 58fe8932b3..c284952082 100755 --- a/tests/qemu-iotests/077 +++ b/tests/qemu-iotests/077 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test concurrent pread/pwrite # diff --git a/tests/qemu-iotests/078 b/tests/qemu-iotests/078 index 68d0ea8802..54fc654d8e 100755 --- a/tests/qemu-iotests/078 +++ b/tests/qemu-iotests/078 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # bochs format input validation tests # diff --git a/tests/qemu-iotests/079 b/tests/qemu-iotests/079 index fca2f77d37..1b6594ebef 100755 --- a/tests/qemu-iotests/079 +++ b/tests/qemu-iotests/079 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test qcow2 preallocation with different cluster_sizes # diff --git a/tests/qemu-iotests/080 b/tests/qemu-iotests/080 index cec2376f59..4bcb5021e8 100755 --- a/tests/qemu-iotests/080 +++ b/tests/qemu-iotests/080 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # qcow2 format input validation tests # diff --git a/tests/qemu-iotests/081 b/tests/qemu-iotests/081 index edf6e6172a..c418bab093 100755 --- a/tests/qemu-iotests/081 +++ b/tests/qemu-iotests/081 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test Quorum block driver # diff --git a/tests/qemu-iotests/082 b/tests/qemu-iotests/082 index 61eec63797..d0afa46e9a 100755 --- a/tests/qemu-iotests/082 +++ b/tests/qemu-iotests/082 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test qemu-img command line parsing # diff --git a/tests/qemu-iotests/083 b/tests/qemu-iotests/083 index 89f67db70f..b270550d3e 100755 --- a/tests/qemu-iotests/083 +++ b/tests/qemu-iotests/083 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test NBD client unexpected disconnect # diff --git a/tests/qemu-iotests/084 b/tests/qemu-iotests/084 index e131fa9642..c29d7395e9 100755 --- a/tests/qemu-iotests/084 +++ b/tests/qemu-iotests/084 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for VDI header corruption; image too large, and too many blocks. # Also simple test for creating dynamic and static VDI images. diff --git a/tests/qemu-iotests/085 b/tests/qemu-iotests/085 index ade68ef853..68cb665987 100755 --- a/tests/qemu-iotests/085 +++ b/tests/qemu-iotests/085 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Live snapshot tests # diff --git a/tests/qemu-iotests/086 b/tests/qemu-iotests/086 index 3cca3687ea..fea1a7bd8a 100755 --- a/tests/qemu-iotests/086 +++ b/tests/qemu-iotests/086 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test qemu-img progress output # diff --git a/tests/qemu-iotests/087 b/tests/qemu-iotests/087 index f625887082..d6c8613419 100755 --- a/tests/qemu-iotests/087 +++ b/tests/qemu-iotests/087 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test unsupported blockdev-add cases # diff --git a/tests/qemu-iotests/088 b/tests/qemu-iotests/088 index c5e9ab42c7..b44edd0cf9 100755 --- a/tests/qemu-iotests/088 +++ b/tests/qemu-iotests/088 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # vpc (VHD) format input validation tests # diff --git a/tests/qemu-iotests/089 b/tests/qemu-iotests/089 index 3165d79e2a..6609954908 100755 --- a/tests/qemu-iotests/089 +++ b/tests/qemu-iotests/089 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for support of JSON filenames # diff --git a/tests/qemu-iotests/090 b/tests/qemu-iotests/090 index 1450993e15..193bae7d77 100755 --- a/tests/qemu-iotests/090 +++ b/tests/qemu-iotests/090 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test for discarding compressed clusters on qcow2 images # diff --git a/tests/qemu-iotests/091 b/tests/qemu-iotests/091 index 2f2f98ee64..d62ef18a02 100755 --- a/tests/qemu-iotests/091 +++ b/tests/qemu-iotests/091 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Live migration test # diff --git a/tests/qemu-iotests/092 b/tests/qemu-iotests/092 index 8e318f10b9..e2e0726de1 100755 --- a/tests/qemu-iotests/092 +++ b/tests/qemu-iotests/092 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # qcow1 format input validation tests # diff --git a/tests/qemu-iotests/094 b/tests/qemu-iotests/094 index 7adc9b9138..0bcca77261 100755 --- a/tests/qemu-iotests/094 +++ b/tests/qemu-iotests/094 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for drive-mirror to NBD # diff --git a/tests/qemu-iotests/095 b/tests/qemu-iotests/095 index 9fc47f6b87..18505b7181 100755 --- a/tests/qemu-iotests/095 +++ b/tests/qemu-iotests/095 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test for commit of larger active layer # diff --git a/tests/qemu-iotests/097 b/tests/qemu-iotests/097 index 7234b16053..690f3d3ce1 100755 --- a/tests/qemu-iotests/097 +++ b/tests/qemu-iotests/097 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Commit changes into backing chains and empty the top image if the # backing image is not explicitly specified diff --git a/tests/qemu-iotests/098 b/tests/qemu-iotests/098 index c7977da99a..461144c831 100755 --- a/tests/qemu-iotests/098 +++ b/tests/qemu-iotests/098 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test qcow2's bdrv_make_empty for images without internal snapshots # diff --git a/tests/qemu-iotests/099 b/tests/qemu-iotests/099 index 578808b747..ae02f27afe 100755 --- a/tests/qemu-iotests/099 +++ b/tests/qemu-iotests/099 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test valid filenames for blkdebug and blkverify representatively for # other protocols (such as NBD) when queried diff --git a/tests/qemu-iotests/101 b/tests/qemu-iotests/101 index 3001ba3c0a..a4c1b6366a 100755 --- a/tests/qemu-iotests/101 +++ b/tests/qemu-iotests/101 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test short file I/O # diff --git a/tests/qemu-iotests/102 b/tests/qemu-iotests/102 index 29a6a940e2..cedd2b25dc 100755 --- a/tests/qemu-iotests/102 +++ b/tests/qemu-iotests/102 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for qemu-io -c map and qemu-img map # diff --git a/tests/qemu-iotests/103 b/tests/qemu-iotests/103 index 66f8167f02..6773e94d9f 100755 --- a/tests/qemu-iotests/103 +++ b/tests/qemu-iotests/103 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for qcow2 metadata cache size specification # diff --git a/tests/qemu-iotests/104 b/tests/qemu-iotests/104 index 34bb0d23ba..390167bad4 100755 --- a/tests/qemu-iotests/104 +++ b/tests/qemu-iotests/104 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test image creation with aligned and unaligned sizes # diff --git a/tests/qemu-iotests/105 b/tests/qemu-iotests/105 index 943bda2f4f..3b5a596844 100755 --- a/tests/qemu-iotests/105 +++ b/tests/qemu-iotests/105 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Create, read, write big image # diff --git a/tests/qemu-iotests/106 b/tests/qemu-iotests/106 index 4129fee6bc..ac47eaa0f5 100755 --- a/tests/qemu-iotests/106 +++ b/tests/qemu-iotests/106 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test preallocated resize of raw images # diff --git a/tests/qemu-iotests/107 b/tests/qemu-iotests/107 index 5d70ad2007..fcd5a24dfe 100755 --- a/tests/qemu-iotests/107 +++ b/tests/qemu-iotests/107 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Tests updates of the qcow2 L1 table # diff --git a/tests/qemu-iotests/108 b/tests/qemu-iotests/108 index 58e8ad7636..9c08172237 100755 --- a/tests/qemu-iotests/108 +++ b/tests/qemu-iotests/108 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for repairing qcow2 images which cannot be repaired using # the on-disk refcount structures diff --git a/tests/qemu-iotests/109 b/tests/qemu-iotests/109 index b51e4616c6..9897ceb6cd 100755 --- a/tests/qemu-iotests/109 +++ b/tests/qemu-iotests/109 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test writing image headers of other formats into raw images # diff --git a/tests/qemu-iotests/110 b/tests/qemu-iotests/110 index 185ad5437e..fad672c1ae 100755 --- a/tests/qemu-iotests/110 +++ b/tests/qemu-iotests/110 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for relative backing file names in complex BDS trees # diff --git a/tests/qemu-iotests/111 b/tests/qemu-iotests/111 index e15e66ac5d..57395be64c 100755 --- a/tests/qemu-iotests/111 +++ b/tests/qemu-iotests/111 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for non-existing backing file when creating a qcow2 image # and not specifying the size diff --git a/tests/qemu-iotests/112 b/tests/qemu-iotests/112 index d67e6ebe9c..6d81c75a9c 100755 --- a/tests/qemu-iotests/112 +++ b/tests/qemu-iotests/112 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test cases for different refcount_bits values # diff --git a/tests/qemu-iotests/113 b/tests/qemu-iotests/113 index d8d78c46dc..f2703a2c50 100755 --- a/tests/qemu-iotests/113 +++ b/tests/qemu-iotests/113 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for accessing creation options on image formats and # protocols not supporting image creation diff --git a/tests/qemu-iotests/114 b/tests/qemu-iotests/114 index e17fb514cb..f36b88f3f3 100755 --- a/tests/qemu-iotests/114 +++ b/tests/qemu-iotests/114 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test invalid backing file format in qcow2 images # diff --git a/tests/qemu-iotests/115 b/tests/qemu-iotests/115 index 0581e03c26..7ed347010f 100755 --- a/tests/qemu-iotests/115 +++ b/tests/qemu-iotests/115 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for non-self-referential qcow2 refcount blocks # diff --git a/tests/qemu-iotests/116 b/tests/qemu-iotests/116 index f8a27b9c02..941b07a1a9 100755 --- a/tests/qemu-iotests/116 +++ b/tests/qemu-iotests/116 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test error code paths for invalid QED images # diff --git a/tests/qemu-iotests/117 b/tests/qemu-iotests/117 index e533e230a3..0af0f31c5a 100755 --- a/tests/qemu-iotests/117 +++ b/tests/qemu-iotests/117 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for shared BDS between backend trees # diff --git a/tests/qemu-iotests/119 b/tests/qemu-iotests/119 index 32810d52c9..ea6770a484 100755 --- a/tests/qemu-iotests/119 +++ b/tests/qemu-iotests/119 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # NBD test case for overriding BDRV_O_PROTOCOL by explicitly specifying # a driver diff --git a/tests/qemu-iotests/120 b/tests/qemu-iotests/120 index 76afdf449b..ca95b9276e 100755 --- a/tests/qemu-iotests/120 +++ b/tests/qemu-iotests/120 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Non-NBD test cases for overriding BDRV_O_PROTOCOL by explicitly # specifying a driver diff --git a/tests/qemu-iotests/121 b/tests/qemu-iotests/121 index d2885c700f..90a0424edb 100755 --- a/tests/qemu-iotests/121 +++ b/tests/qemu-iotests/121 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test cases for qcow2 refcount table growth # diff --git a/tests/qemu-iotests/122 b/tests/qemu-iotests/122 index eab3399dd6..85c3a8d047 100755 --- a/tests/qemu-iotests/122 +++ b/tests/qemu-iotests/122 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test some qemu-img convert cases # diff --git a/tests/qemu-iotests/123 b/tests/qemu-iotests/123 index 168b985c8b..d33950eb54 100755 --- a/tests/qemu-iotests/123 +++ b/tests/qemu-iotests/123 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for qemu-img convert to NBD # diff --git a/tests/qemu-iotests/125 b/tests/qemu-iotests/125 index 778c874933..212dcd8f0d 100755 --- a/tests/qemu-iotests/125 +++ b/tests/qemu-iotests/125 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test preallocated growth of qcow2 images # diff --git a/tests/qemu-iotests/126 b/tests/qemu-iotests/126 index 91148383ad..96dc048d59 100755 --- a/tests/qemu-iotests/126 +++ b/tests/qemu-iotests/126 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Tests handling of colons in filenames (which may be confused with protocol # prefixes) diff --git a/tests/qemu-iotests/127 b/tests/qemu-iotests/127 index c9139ed5e6..3e941f74d4 100755 --- a/tests/qemu-iotests/127 +++ b/tests/qemu-iotests/127 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for mirroring with dataplane # diff --git a/tests/qemu-iotests/128 b/tests/qemu-iotests/128 index 925f5c7e98..3606c41760 100755 --- a/tests/qemu-iotests/128 +++ b/tests/qemu-iotests/128 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test that opening O_DIRECT succeeds when image file I/O produces EIO # diff --git a/tests/qemu-iotests/130 b/tests/qemu-iotests/130 index f2f2706b28..77ad2aa13a 100755 --- a/tests/qemu-iotests/130 +++ b/tests/qemu-iotests/130 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test that temporary backing file overrides (on the command line or in # blockdev-add) don't replace the original path stored in the image during diff --git a/tests/qemu-iotests/131 b/tests/qemu-iotests/131 index 58c25f7abe..27870231cf 100755 --- a/tests/qemu-iotests/131 +++ b/tests/qemu-iotests/131 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # parallels format validation tests (created by QEMU) # diff --git a/tests/qemu-iotests/133 b/tests/qemu-iotests/133 index 565e0b1b6e..1f6056d144 100755 --- a/tests/qemu-iotests/133 +++ b/tests/qemu-iotests/133 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test for reopen # diff --git a/tests/qemu-iotests/134 b/tests/qemu-iotests/134 index cacabcd28b..e9e3e84c2a 100755 --- a/tests/qemu-iotests/134 +++ b/tests/qemu-iotests/134 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test encrypted read/write using plain bdrv_read/bdrv_write # diff --git a/tests/qemu-iotests/135 b/tests/qemu-iotests/135 index a18a0c7230..3b3d1dc2a5 100755 --- a/tests/qemu-iotests/135 +++ b/tests/qemu-iotests/135 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test VPC open of image with large Max Table Entries value. # diff --git a/tests/qemu-iotests/137 b/tests/qemu-iotests/137 index 09cd4450ca..0c3d2a1cf0 100755 --- a/tests/qemu-iotests/137 +++ b/tests/qemu-iotests/137 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test qcow2 reopen # diff --git a/tests/qemu-iotests/138 b/tests/qemu-iotests/138 index eccbcae3a6..f353ac8219 100755 --- a/tests/qemu-iotests/138 +++ b/tests/qemu-iotests/138 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # General test case for qcow2's image check # diff --git a/tests/qemu-iotests/140 b/tests/qemu-iotests/140 index d4623b5a5d..b965b1dd5d 100755 --- a/tests/qemu-iotests/140 +++ b/tests/qemu-iotests/140 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for ejecting a BlockBackend with an NBD server attached to it # diff --git a/tests/qemu-iotests/141 b/tests/qemu-iotests/141 index e2408c7988..2197a82d45 100755 --- a/tests/qemu-iotests/141 +++ b/tests/qemu-iotests/141 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for ejecting BDSs with block jobs still running on them # diff --git a/tests/qemu-iotests/142 b/tests/qemu-iotests/142 index 5fc488f5d2..d9b98cf60a 100755 --- a/tests/qemu-iotests/142 +++ b/tests/qemu-iotests/142 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test for configuring cache modes of arbitrary nodes (requires O_DIRECT) # diff --git a/tests/qemu-iotests/143 b/tests/qemu-iotests/143 index d6302cc06d..c223867cb3 100755 --- a/tests/qemu-iotests/143 +++ b/tests/qemu-iotests/143 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for connecting to a non-existing NBD export name # diff --git a/tests/qemu-iotests/144 b/tests/qemu-iotests/144 index 118c099994..15157f33d7 100755 --- a/tests/qemu-iotests/144 +++ b/tests/qemu-iotests/144 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # Check live snapshot, followed by active commit, and another snapshot. # # This test is to catch the error case of BZ #1300209: diff --git a/tests/qemu-iotests/145 b/tests/qemu-iotests/145 index 6ce8a46f92..28878dc8a1 100755 --- a/tests/qemu-iotests/145 +++ b/tests/qemu-iotests/145 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test the combination of -incoming and snapshot=on # diff --git a/tests/qemu-iotests/146 b/tests/qemu-iotests/146 index 3f61351ffe..2e43abddfc 100755 --- a/tests/qemu-iotests/146 +++ b/tests/qemu-iotests/146 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test VHD image format creator detection and override # diff --git a/tests/qemu-iotests/150 b/tests/qemu-iotests/150 index 955b877efa..3b1f32197a 100755 --- a/tests/qemu-iotests/150 +++ b/tests/qemu-iotests/150 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test that qemu-img convert -S 0 fully allocates the target image # diff --git a/tests/qemu-iotests/153 b/tests/qemu-iotests/153 index 3120a61da4..c989c2495f 100755 --- a/tests/qemu-iotests/153 +++ b/tests/qemu-iotests/153 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test image locking # diff --git a/tests/qemu-iotests/154 b/tests/qemu-iotests/154 index 4a4abf0589..d68f66b9e0 100755 --- a/tests/qemu-iotests/154 +++ b/tests/qemu-iotests/154 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # qcow2 specific bdrv_pwrite_zeroes tests with backing files (complements 034) # diff --git a/tests/qemu-iotests/156 b/tests/qemu-iotests/156 index f97f96f666..8d134029c6 100755 --- a/tests/qemu-iotests/156 +++ b/tests/qemu-iotests/156 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Tests oVirt-like storage migration: # - Create snapshot diff --git a/tests/qemu-iotests/157 b/tests/qemu-iotests/157 index 6fb26596ad..69b25cab30 100755 --- a/tests/qemu-iotests/157 +++ b/tests/qemu-iotests/157 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test command line configuration of block devices with qdev # diff --git a/tests/qemu-iotests/158 b/tests/qemu-iotests/158 index d277ddcc94..8c0928a7f9 100755 --- a/tests/qemu-iotests/158 +++ b/tests/qemu-iotests/158 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test encrypted read/write using backing files # diff --git a/tests/qemu-iotests/159 b/tests/qemu-iotests/159 index e74b2739de..29066eebde 100755 --- a/tests/qemu-iotests/159 +++ b/tests/qemu-iotests/159 @@ -1,4 +1,4 @@ -#! /bin/bash +#!/usr/bin/env bash # # qemu-img dd test with different block sizes # diff --git a/tests/qemu-iotests/160 b/tests/qemu-iotests/160 index 92fff45d10..df89d3864b 100755 --- a/tests/qemu-iotests/160 +++ b/tests/qemu-iotests/160 @@ -1,4 +1,4 @@ -#! /bin/bash +#!/usr/bin/env bash # # qemu-img dd test for the skip option # diff --git a/tests/qemu-iotests/161 b/tests/qemu-iotests/161 index 180df17ad6..456a4bd8c4 100755 --- a/tests/qemu-iotests/161 +++ b/tests/qemu-iotests/161 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test reopening a backing image after block-stream and block-commit # diff --git a/tests/qemu-iotests/162 b/tests/qemu-iotests/162 index ef02d844a2..2e9947fd9a 100755 --- a/tests/qemu-iotests/162 +++ b/tests/qemu-iotests/162 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for specifying runtime options of the wrong type to some # block drivers diff --git a/tests/qemu-iotests/170 b/tests/qemu-iotests/170 index 861eabf5cc..7deb7563c9 100755 --- a/tests/qemu-iotests/170 +++ b/tests/qemu-iotests/170 @@ -1,4 +1,4 @@ -#! /bin/bash +#!/usr/bin/env bash # # qemu-img dd test # diff --git a/tests/qemu-iotests/171 b/tests/qemu-iotests/171 index 5b46069fde..341064a1c6 100755 --- a/tests/qemu-iotests/171 +++ b/tests/qemu-iotests/171 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test 'offset' and 'size' options of the raw driver. Make sure we can't # (or can) read and write outside of the image size. diff --git a/tests/qemu-iotests/172 b/tests/qemu-iotests/172 index 1e60a7e3d6..ba7dad9057 100755 --- a/tests/qemu-iotests/172 +++ b/tests/qemu-iotests/172 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test floppy configuration # diff --git a/tests/qemu-iotests/173 b/tests/qemu-iotests/173 index 1fe8c5d738..47036a5564 100755 --- a/tests/qemu-iotests/173 +++ b/tests/qemu-iotests/173 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test QAPI commands looking up protocol based images with relative # filename backing strings diff --git a/tests/qemu-iotests/174 b/tests/qemu-iotests/174 index d8bb05c4e2..0a952a73fd 100755 --- a/tests/qemu-iotests/174 +++ b/tests/qemu-iotests/174 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test that qemu-io fail with non-zero exit code # diff --git a/tests/qemu-iotests/175 b/tests/qemu-iotests/175 index ebbeb6e74c..d0ffc495c2 100755 --- a/tests/qemu-iotests/175 +++ b/tests/qemu-iotests/175 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test creating raw image preallocation mode # diff --git a/tests/qemu-iotests/176 b/tests/qemu-iotests/176 index 4ecd5894a3..50df4c00fa 100755 --- a/tests/qemu-iotests/176 +++ b/tests/qemu-iotests/176 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Commit changes into backing chains and empty the top image if the # backing image is not explicitly specified. diff --git a/tests/qemu-iotests/177 b/tests/qemu-iotests/177 index f0c1155e80..752d29f8ad 100755 --- a/tests/qemu-iotests/177 +++ b/tests/qemu-iotests/177 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test corner cases with unusual block geometries # diff --git a/tests/qemu-iotests/178 b/tests/qemu-iotests/178 index 927bf06e4d..21231cadd3 100755 --- a/tests/qemu-iotests/178 +++ b/tests/qemu-iotests/178 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # qemu-img measure sub-command tests # diff --git a/tests/qemu-iotests/179 b/tests/qemu-iotests/179 index 3040631636..9372dc30ef 100755 --- a/tests/qemu-iotests/179 +++ b/tests/qemu-iotests/179 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for write zeroes with unmap # diff --git a/tests/qemu-iotests/181 b/tests/qemu-iotests/181 index 0c44108dac..e317e63422 100755 --- a/tests/qemu-iotests/181 +++ b/tests/qemu-iotests/181 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test postcopy live migration with shared storage # diff --git a/tests/qemu-iotests/182 b/tests/qemu-iotests/182 index 9e078c5484..ff3d7e7ec1 100755 --- a/tests/qemu-iotests/182 +++ b/tests/qemu-iotests/182 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test image locking for POSIX locks # diff --git a/tests/qemu-iotests/183 b/tests/qemu-iotests/183 index ebb5e304ac..93b7bd798a 100755 --- a/tests/qemu-iotests/183 +++ b/tests/qemu-iotests/183 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test old-style block migration (migrate -b) # diff --git a/tests/qemu-iotests/184 b/tests/qemu-iotests/184 index 0af7a73aca..cb0c181228 100755 --- a/tests/qemu-iotests/184 +++ b/tests/qemu-iotests/184 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test I/O throttle block filter driver interface # diff --git a/tests/qemu-iotests/185 b/tests/qemu-iotests/185 index d8f1505cd8..454ff600cc 100755 --- a/tests/qemu-iotests/185 +++ b/tests/qemu-iotests/185 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test exiting qemu while jobs are still running # diff --git a/tests/qemu-iotests/186 b/tests/qemu-iotests/186 index c27dc953b6..5dd2177b89 100755 --- a/tests/qemu-iotests/186 +++ b/tests/qemu-iotests/186 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test 'info block' with all kinds of configurations # diff --git a/tests/qemu-iotests/187 b/tests/qemu-iotests/187 index 1feddca508..a45addde09 100755 --- a/tests/qemu-iotests/187 +++ b/tests/qemu-iotests/187 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test switching between read-only and read-write # diff --git a/tests/qemu-iotests/188 b/tests/qemu-iotests/188 index af40e496ee..be7278aa65 100755 --- a/tests/qemu-iotests/188 +++ b/tests/qemu-iotests/188 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test encrypted read/write using plain bdrv_read/bdrv_write # diff --git a/tests/qemu-iotests/189 b/tests/qemu-iotests/189 index 222bec133b..c9ce9d3bed 100755 --- a/tests/qemu-iotests/189 +++ b/tests/qemu-iotests/189 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test encrypted read/write using backing files # diff --git a/tests/qemu-iotests/190 b/tests/qemu-iotests/190 index 95ba06d8f4..e1c1d407f0 100755 --- a/tests/qemu-iotests/190 +++ b/tests/qemu-iotests/190 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # qemu-img measure sub-command tests on huge qcow2 files # diff --git a/tests/qemu-iotests/191 b/tests/qemu-iotests/191 index 198272ea3b..1ea908ce3d 100755 --- a/tests/qemu-iotests/191 +++ b/tests/qemu-iotests/191 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test commit block job where top has two parents # diff --git a/tests/qemu-iotests/192 b/tests/qemu-iotests/192 index 415c706db5..158086f9d2 100755 --- a/tests/qemu-iotests/192 +++ b/tests/qemu-iotests/192 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test NBD export with -incoming (non-shared storage migration use case from # libvirt) diff --git a/tests/qemu-iotests/195 b/tests/qemu-iotests/195 index a977c9798e..bd1b71ae5e 100755 --- a/tests/qemu-iotests/195 +++ b/tests/qemu-iotests/195 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test change-backing-file command # diff --git a/tests/qemu-iotests/197 b/tests/qemu-iotests/197 index 8170f5d4ab..2c664793f4 100755 --- a/tests/qemu-iotests/197 +++ b/tests/qemu-iotests/197 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for copy-on-read into qcow2 # diff --git a/tests/qemu-iotests/198 b/tests/qemu-iotests/198 index 4d961f4f3a..c8f824cfae 100755 --- a/tests/qemu-iotests/198 +++ b/tests/qemu-iotests/198 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test commit of encrypted qcow2 files # diff --git a/tests/qemu-iotests/200 b/tests/qemu-iotests/200 index b9ebd5a8c7..12d25f4a1c 100755 --- a/tests/qemu-iotests/200 +++ b/tests/qemu-iotests/200 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Block job co-routine race condition test. # diff --git a/tests/qemu-iotests/201 b/tests/qemu-iotests/201 index c1a1e00077..7abf740fe4 100755 --- a/tests/qemu-iotests/201 +++ b/tests/qemu-iotests/201 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test savevm and loadvm after live migration with postcopy flag # diff --git a/tests/qemu-iotests/204 b/tests/qemu-iotests/204 index 30f0653ce9..abb73dc381 100755 --- a/tests/qemu-iotests/204 +++ b/tests/qemu-iotests/204 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test corner cases with unusual block geometries # diff --git a/tests/qemu-iotests/214 b/tests/qemu-iotests/214 index 7a2d5391bb..c1a452ff9a 100755 --- a/tests/qemu-iotests/214 +++ b/tests/qemu-iotests/214 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test qcow2 image compression # diff --git a/tests/qemu-iotests/215 b/tests/qemu-iotests/215 index 230fd2551a..7b063d7cfa 100755 --- a/tests/qemu-iotests/215 +++ b/tests/qemu-iotests/215 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test case for copy-on-read into qcow2, using the COR filter driver # diff --git a/tests/qemu-iotests/217 b/tests/qemu-iotests/217 index d3ab5d72be..f5482bb669 100755 --- a/tests/qemu-iotests/217 +++ b/tests/qemu-iotests/217 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # I/O errors when working with internal qcow2 snapshots, and repairing # the result diff --git a/tests/qemu-iotests/220 b/tests/qemu-iotests/220 index 0c5682bda0..2d62c5dcac 100755 --- a/tests/qemu-iotests/220 +++ b/tests/qemu-iotests/220 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # max limits on compression in huge qcow2 files # diff --git a/tests/qemu-iotests/221 b/tests/qemu-iotests/221 index 06f48f1f23..808cd9a289 100755 --- a/tests/qemu-iotests/221 +++ b/tests/qemu-iotests/221 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test qemu-img vs. unaligned images # diff --git a/tests/qemu-iotests/223 b/tests/qemu-iotests/223 index f120a01646..98b6cc73af 100755 --- a/tests/qemu-iotests/223 +++ b/tests/qemu-iotests/223 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test reading dirty bitmap over NBD # diff --git a/tests/qemu-iotests/225 b/tests/qemu-iotests/225 index e42ee94ff0..fbd7404791 100755 --- a/tests/qemu-iotests/225 +++ b/tests/qemu-iotests/225 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test vmdk backing file correlation # diff --git a/tests/qemu-iotests/226 b/tests/qemu-iotests/226 index aec413b23c..c1e1fb2b1c 100755 --- a/tests/qemu-iotests/226 +++ b/tests/qemu-iotests/226 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # This test covers expected filetypes for the file, host_cdrom and # host_device drivers. diff --git a/tests/qemu-iotests/227 b/tests/qemu-iotests/227 index be1b636af0..10cf144eb0 100755 --- a/tests/qemu-iotests/227 +++ b/tests/qemu-iotests/227 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test query-blockstats with different ways to create a BB # diff --git a/tests/qemu-iotests/229 b/tests/qemu-iotests/229 index b0d4885fa6..e18a464fe0 100755 --- a/tests/qemu-iotests/229 +++ b/tests/qemu-iotests/229 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test for force canceling a running blockjob that is paused in # an error state. diff --git a/tests/qemu-iotests/231 b/tests/qemu-iotests/231 index e9f8aaacd3..5b2cbab9ac 100755 --- a/tests/qemu-iotests/231 +++ b/tests/qemu-iotests/231 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test legacy and modern option parsing for rbd/ceph. This will not # actually connect to a ceph server, but rather looks for the appropriate diff --git a/tests/qemu-iotests/232 b/tests/qemu-iotests/232 index e48bc8f5db..71fd48eff0 100755 --- a/tests/qemu-iotests/232 +++ b/tests/qemu-iotests/232 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test for auto-read-only # diff --git a/tests/qemu-iotests/233 b/tests/qemu-iotests/233 index adb742fafb..876cd5997b 100755 --- a/tests/qemu-iotests/233 +++ b/tests/qemu-iotests/233 @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Test NBD TLS certificate / authorization integration # diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check index 1016887438..f9c24b6753 100755 --- a/tests/qemu-iotests/check +++ b/tests/qemu-iotests/check @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Copyright (C) 2009 Red Hat, Inc. # Copyright (c) 2000-2002,2006 Silicon Graphics, Inc. All Rights Reserved. diff --git a/tests/qemu-iotests/common.config b/tests/qemu-iotests/common.config index 9f460f203d..9bd1a5a6fc 100644 --- a/tests/qemu-iotests/common.config +++ b/tests/qemu-iotests/common.config @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Copyright (C) 2009 Red Hat, Inc. # Copyright (c) 2000-2003,2006 Silicon Graphics, Inc. All Rights Reserved. diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter index 1aa7d57140..c282bc24f0 100644 --- a/tests/qemu-iotests/common.filter +++ b/tests/qemu-iotests/common.filter @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Copyright (C) 2009 Red Hat, Inc. # Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. diff --git a/tests/qemu-iotests/common.nbd b/tests/qemu-iotests/common.nbd index 233187a25c..25fc9ffaa4 100644 --- a/tests/qemu-iotests/common.nbd +++ b/tests/qemu-iotests/common.nbd @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # -*- shell-script-mode -*- # # Helpers for NBD server related config diff --git a/tests/qemu-iotests/common.pattern b/tests/qemu-iotests/common.pattern index b67bb34136..25aa0d01c1 100644 --- a/tests/qemu-iotests/common.pattern +++ b/tests/qemu-iotests/common.pattern @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Copyright (C) 2009 Red Hat, Inc. # diff --git a/tests/qemu-iotests/common.qemu b/tests/qemu-iotests/common.qemu index 7c87b897fa..8d2021a7eb 100644 --- a/tests/qemu-iotests/common.qemu +++ b/tests/qemu-iotests/common.qemu @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # This allows for launching of multiple QEMU instances, with independent # communication possible to each instance. diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc index 09a27f02d0..f21020eba6 100644 --- a/tests/qemu-iotests/common.rc +++ b/tests/qemu-iotests/common.rc @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Copyright (C) 2009 Red Hat, Inc. # Copyright (c) 2000-2006 Silicon Graphics, Inc. All Rights Reserved. diff --git a/tests/qemu-iotests/common.tls b/tests/qemu-iotests/common.tls index 3caf989d28..54c331d7a5 100644 --- a/tests/qemu-iotests/common.tls +++ b/tests/qemu-iotests/common.tls @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Helpers for TLS related config # From bde36af1ab4f476d38bfbcc1d890b08b7164a8f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 7 Mar 2019 15:58:39 +0100 Subject: [PATCH 10/33] qemu-iotests: Ensure GNU sed is used MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Various sed regexp from common.filter use sed GNU extensions. Instead of spending time to write these regex to be POSIX compliant, verify the GNU sed is available and use it. Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Kevin Wolf --- tests/qemu-iotests/common.filter | 36 ++++++++++++++++---------------- tests/qemu-iotests/common.rc | 13 ++++++++++++ 2 files changed, 31 insertions(+), 18 deletions(-) diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter index c282bc24f0..35fddc746f 100644 --- a/tests/qemu-iotests/common.filter +++ b/tests/qemu-iotests/common.filter @@ -23,37 +23,37 @@ # _filter_date() { - sed \ + $SED \ -e 's/[A-Z][a-z][a-z] [A-z][a-z][a-z] *[0-9][0-9]* [0-9][0-9]:[0-9][0-9]:[0-9][0-9] [0-9][0-9][0-9][0-9]$/DATE/' } _filter_generated_node_ids() { - sed -re 's/\#block[0-9]{3,}/NODE_NAME/' + $SED -re 's/\#block[0-9]{3,}/NODE_NAME/' } _filter_qom_path() { - sed -e 's#\(Attached to: *\) /.*#\1 PATH#' + $SED -e 's#\(Attached to: *\) /.*#\1 PATH#' } # replace occurrences of the actual TEST_DIR value with TEST_DIR _filter_testdir() { - sed -e "s#$TEST_DIR/#TEST_DIR/#g" + $SED -e "s#$TEST_DIR/#TEST_DIR/#g" } # replace occurrences of the actual IMGFMT value with IMGFMT _filter_imgfmt() { - sed -e "s#$IMGFMT#IMGFMT#g" + $SED -e "s#$IMGFMT#IMGFMT#g" } # Replace error message when the format is not supported and delete # the output lines after the first one _filter_qemu_img_check() { - sed -e '/allocated.*fragmented.*compressed clusters/d' \ + $SED -e '/allocated.*fragmented.*compressed clusters/d' \ -e 's/qemu-img: This image format does not support checks/No errors were found on the image./' \ -e '/Image end offset: [0-9]\+/d' } @@ -61,13 +61,13 @@ _filter_qemu_img_check() # Removes \r from messages _filter_win32() { - sed -e 's/\r//g' + $SED -e 's/\r//g' } # sanitize qemu-io output _filter_qemu_io() { - _filter_win32 | sed -e "s/[0-9]* ops\; [0-9/:. sec]* ([0-9/.inf]* [EPTGMKiBbytes]*\/sec and [0-9/.inf]* ops\/sec)/X ops\; XX:XX:XX.X (XXX YYY\/sec and XXX ops\/sec)/" \ + _filter_win32 | $SED -e "s/[0-9]* ops\; [0-9/:. sec]* ([0-9/.inf]* [EPTGMKiBbytes]*\/sec and [0-9/.inf]* ops\/sec)/X ops\; XX:XX:XX.X (XXX YYY\/sec and XXX ops\/sec)/" \ -e "s/: line [0-9][0-9]*: *[0-9][0-9]*\( Aborted\| Killed\)/:\1/" \ -e "s/qemu-io> //g" } @@ -75,7 +75,7 @@ _filter_qemu_io() # replace occurrences of QEMU_PROG with "qemu" _filter_qemu() { - sed -e "s#\\(^\\|(qemu) \\)$(basename $QEMU_PROG):#\1QEMU_PROG:#" \ + $SED -e "s#\\(^\\|(qemu) \\)$(basename $QEMU_PROG):#\1QEMU_PROG:#" \ -e 's#^QEMU [0-9]\+\.[0-9]\+\.[0-9]\+ monitor#QEMU X.Y.Z monitor#' \ -e $'s#\r##' # QEMU monitor uses \r\n line endings } @@ -84,7 +84,7 @@ _filter_qemu() _filter_qmp() { _filter_win32 | \ - sed -e 's#\("\(micro\)\?seconds": \)[0-9]\+#\1 TIMESTAMP#g' \ + $SED -e 's#\("\(micro\)\?seconds": \)[0-9]\+#\1 TIMESTAMP#g' \ -e 's#^{"QMP":.*}$#QMP_VERSION#' \ -e '/^ "QMP": {\s*$/, /^ }\s*$/ c\' \ -e ' QMP_VERSION' @@ -93,32 +93,32 @@ _filter_qmp() # readline makes HMP command strings so long that git complains _filter_hmp() { - sed -e $'s/^\\((qemu) \\)\\?.*\e\\[D/\\1/g' \ + $SED -e $'s/^\\((qemu) \\)\\?.*\e\\[D/\\1/g' \ -e $'s/\e\\[K//g' } # replace block job offset _filter_block_job_offset() { - sed -e 's/, "offset": [0-9]\+,/, "offset": OFFSET,/' + $SED -e 's/, "offset": [0-9]\+,/, "offset": OFFSET,/' } # replace block job len _filter_block_job_len() { - sed -e 's/, "len": [0-9]\+,/, "len": LEN,/g' + $SED -e 's/, "len": [0-9]\+,/, "len": LEN,/g' } # replace actual image size (depends on the host filesystem) _filter_actual_image_size() { - sed -s 's/\("actual-size":\s*\)[0-9]\+/\1SIZE/g' + $SED -s 's/\("actual-size":\s*\)[0-9]\+/\1SIZE/g' } # replace driver-specific options in the "Formatting..." line _filter_img_create() { - sed -e "s#$REMOTE_TEST_DIR#TEST_DIR#g" \ + $SED -e "s#$REMOTE_TEST_DIR#TEST_DIR#g" \ -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \ -e "s#$TEST_DIR#TEST_DIR#g" \ -e "s#$IMGFMT#IMGFMT#g" \ @@ -154,7 +154,7 @@ _filter_img_info() discard=0 regex_json_spec_start='^ *"format-specific": \{' - sed -e "s#$REMOTE_TEST_DIR#TEST_DIR#g" \ + $SED -e "s#$REMOTE_TEST_DIR#TEST_DIR#g" \ -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \ -e "s#$TEST_DIR#TEST_DIR#g" \ -e "s#$IMGFMT#IMGFMT#g" \ @@ -201,7 +201,7 @@ _filter_img_info() # human and json output _filter_qemu_img_map() { - sed -e 's/\([0-9a-fx]* *[0-9a-fx]* *\)[0-9a-fx]* */\1/g' \ + $SED -e 's/\([0-9a-fx]* *[0-9a-fx]* *\)[0-9a-fx]* */\1/g' \ -e 's/"offset": [0-9]\+/"offset": OFFSET/g' \ -e 's/Mapped to *//' | _filter_testdir | _filter_imgfmt } @@ -213,7 +213,7 @@ _filter_nbd() # receive callbacks sometimes, making them unreliable. # # Filter out the TCP port number since this changes between runs. - sed -e '/nbd\/.*\.c:/d' \ + $SED -e '/nbd\/.*\.c:/d' \ -e 's#127\.0\.0\.1:[0-9]*#127.0.0.1:PORT#g' \ -e "s#?socket=$TEST_DIR#?socket=TEST_DIR#g" \ -e 's#\(foo\|PORT/\?\|.sock\): Failed to .*$#\1#' diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc index f21020eba6..a543e546c2 100644 --- a/tests/qemu-iotests/common.rc +++ b/tests/qemu-iotests/common.rc @@ -17,6 +17,19 @@ # along with this program. If not, see . # +SED= +for sed in sed gsed; do + ($sed --version | grep 'GNU sed') > /dev/null 2>&1 + if [ "$?" -eq 0 ]; then + SED=$sed + break + fi +done +if [ -z "$SED" ]; then + echo "$0: GNU sed not found" + exit 1 +fi + dd() { if [ "$HOSTOS" == "Linux" ] From 97f94cb4f842ff43e21e990e59a3ca01708e76d0 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 21 Feb 2019 16:30:33 +0100 Subject: [PATCH 11/33] qemu-iotests: Test qcow2 preallocation modes Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake --- tests/qemu-iotests/243 | 63 ++++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/243.out | 26 ++++++++++++++++ tests/qemu-iotests/group | 1 + 3 files changed, 90 insertions(+) create mode 100755 tests/qemu-iotests/243 create mode 100644 tests/qemu-iotests/243.out diff --git a/tests/qemu-iotests/243 b/tests/qemu-iotests/243 new file mode 100755 index 0000000000..6a19919add --- /dev/null +++ b/tests/qemu-iotests/243 @@ -0,0 +1,63 @@ +#!/bin/bash +# +# Test qcow2 preallocation +# +# Copyright (C) 2019 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 . +# + +# creator +owner=kwolf@redhat.com + +seq=$(basename $0) +echo "QA output created by $seq" + +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_supported_fmt qcow2 +_supported_proto file +_supported_os Linux + +for mode in off metadata falloc full; do + + echo + echo "=== preallocation=$mode ===" + echo + + IMGOPTS="preallocation=$mode" _make_test_img 64M + + printf "File size: " + du -b $TEST_IMG | cut -f1 + + # Can't use precise numbers here because they differ between filesystems + printf "Disk usage: " + [ $(du -B1 $TEST_IMG | cut -f1) -lt 1048576 ] && echo "low" || echo "high" + +done + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/243.out b/tests/qemu-iotests/243.out new file mode 100644 index 0000000000..e531753ad1 --- /dev/null +++ b/tests/qemu-iotests/243.out @@ -0,0 +1,26 @@ +QA output created by 243 + +=== preallocation=off === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 preallocation=off +File size: 196616 +Disk usage: low + +=== preallocation=metadata === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 preallocation=metadata +File size: 67436544 +Disk usage: low + +=== preallocation=falloc === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 preallocation=falloc +File size: 67436544 +Disk usage: high + +=== preallocation=full === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 preallocation=full +File size: 67436544 +Disk usage: high +*** done diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index b5ca63cf72..03aa93dbf5 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -241,3 +241,4 @@ 239 rw auto quick 240 auto quick 242 rw auto quick +243 rw auto quick From c5e86ebc113407dce87b813d68ff3abe9496f422 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 21 Feb 2019 15:48:11 +0100 Subject: [PATCH 12/33] qcow2: Simplify preallocation code Image creation already involves a bdrv_co_truncate() call, which allows to specify a preallocation mode. Just pass the right mode there and remove the code that is made redundant by this. Signed-off-by: Kevin Wolf --- block/qcow2.c | 28 +--------------------------- 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index 48d22f48d5..9489d795e5 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -2952,19 +2952,6 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) goto out; } - if (qcow2_opts->preallocation == PREALLOC_MODE_FULL || - qcow2_opts->preallocation == PREALLOC_MODE_FALLOC) - { - int64_t prealloc_size = - qcow2_calc_prealloc_size(qcow2_opts->size, cluster_size, - refcount_order); - - ret = blk_truncate(blk, prealloc_size, qcow2_opts->preallocation, errp); - if (ret < 0) { - goto out; - } - } - /* Write the header */ QEMU_BUILD_BUG_ON((1 << MIN_CLUSTER_BITS) < sizeof(*header)); header = g_malloc0(cluster_size); @@ -3046,7 +3033,7 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) } /* Okay, now that we have a valid image, let's give it the right size */ - ret = blk_truncate(blk, qcow2_opts->size, PREALLOC_MODE_OFF, errp); + ret = blk_truncate(blk, qcow2_opts->size, qcow2_opts->preallocation, errp); if (ret < 0) { error_prepend(errp, "Could not resize image: "); goto out; @@ -3078,19 +3065,6 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) } } - /* And if we're supposed to preallocate metadata, do that now */ - if (qcow2_opts->preallocation != PREALLOC_MODE_OFF) { - BDRVQcow2State *s = blk_bs(blk)->opaque; - qemu_co_mutex_lock(&s->lock); - ret = preallocate_co(blk_bs(blk), 0, qcow2_opts->size); - qemu_co_mutex_unlock(&s->lock); - - if (ret < 0) { - error_setg_errno(errp, -ret, "Could not preallocate metadata"); - goto out; - } - } - blk_unref(blk); blk = NULL; From 65a3d073e9766ed878474525118dbf0c7233caab Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 29 Jan 2019 15:25:21 +0100 Subject: [PATCH 13/33] qcow2: Extend spec for external data files This adds external data file to the qcow2 spec as a new incompatible feature. Signed-off-by: Kevin Wolf --- docs/interop/qcow2.txt | 42 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt index fb5cb47245..bfb97cfde3 100644 --- a/docs/interop/qcow2.txt +++ b/docs/interop/qcow2.txt @@ -97,7 +97,19 @@ in the description of a field. be written to (unless for regaining consistency). - Bits 2-63: Reserved (set to 0) + Bit 2: External data file bit. If this bit is set, an + external data file is used. Guest clusters are + then stored in the external data file. For such + images, clusters in the external data file are + not refcounted. The offset field in the + Standard Cluster Descriptor must match the + guest offset and neither compressed clusters + nor internal snapshots are supported. + + An External Data File Name header extension may + be present if this bit is set. + + Bits 3-63: Reserved (set to 0) 80 - 87: compatible_features Bitmask of compatible features. An implementation can @@ -126,7 +138,21 @@ in the description of a field. bit is unset, the bitmaps extension data must be considered inconsistent. - Bits 1-63: Reserved (set to 0) + Bit 1: If this bit is set, the external data file can + be read as a consistent standalone raw image + without looking at the qcow2 metadata. + + Setting this bit has a performance impact for + some operations on the image (e.g. writing + zeros requires writing to the data file instead + of only setting the zero flag in the L2 table + entry) and conflicts with backing files. + + This bit may only be set if the External Data + File bit (incompatible feature bit 1) is also + set. + + Bits 2-63: Reserved (set to 0) 96 - 99: refcount_order Describes the width of a reference count block entry (width @@ -148,6 +174,7 @@ be stored. Each extension has a structure like the following: 0x6803f857 - Feature name table 0x23852875 - Bitmaps extension 0x0537be77 - Full disk encryption header pointer + 0x44415441 - External data file name other - Unknown header extension, can be safely ignored @@ -437,6 +464,11 @@ L2 table entry: This information is only accurate in L2 tables that are reachable from the active L1 table. + With external data files, all guest clusters have an + implicit refcount of 1 (because of the fixed host = guest + mapping for guest cluster offsets), so this bit should be 1 + for all allocated clusters. + Standard Cluster Descriptor: Bit 0: If set to 1, the cluster reads as all zeros. The host @@ -450,8 +482,10 @@ Standard Cluster Descriptor: 1 - 8: Reserved (set to 0) 9 - 55: Bits 9-55 of host cluster offset. Must be aligned to a - cluster boundary. If the offset is 0, the cluster is - unallocated. + cluster boundary. If the offset is 0 and bit 63 is clear, + the cluster is unallocated. The offset may only be 0 with + bit 63 set (indicating a host cluster offset of 0) when an + external data file is used. 56 - 61: Reserved (set to 0) From 93c2493646a063a0b0660b47647badf3c43108c7 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Mon, 14 Jan 2019 16:48:25 +0100 Subject: [PATCH 14/33] qcow2: Basic definitions for external data files This adds basic constants, struct fields and helper function for external data file support to the implementation. QCOW2_INCOMPAT_MASK and QCOW2_AUTOCLEAR_MASK are not updated yet so that opening images with an external data file still fails (we don't handle them correctly yet). Signed-off-by: Kevin Wolf --- block/qcow2.c | 9 +++++++++ block/qcow2.h | 30 +++++++++++++++++++++--------- tests/qemu-iotests/031.out | 8 ++++---- tests/qemu-iotests/036.out | 4 ++-- tests/qemu-iotests/061.out | 14 +++++++------- 5 files changed, 43 insertions(+), 22 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index 9489d795e5..59cf706dc2 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -73,6 +73,7 @@ typedef struct { #define QCOW2_EXT_MAGIC_FEATURE_TABLE 0x6803f857 #define QCOW2_EXT_MAGIC_CRYPTO_HEADER 0x0537be77 #define QCOW2_EXT_MAGIC_BITMAPS 0x23852875 +#define QCOW2_EXT_MAGIC_DATA_FILE 0x44415441 static int coroutine_fn qcow2_co_preadv_compressed(BlockDriverState *bs, @@ -1452,6 +1453,9 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, goto fail; } + /* TODO Open external data file */ + s->data_file = bs->file; + /* qcow2_read_extension may have set up the crypto context * if the crypt method needs a header region, some methods * don't need header extensions, so must check here @@ -2440,6 +2444,11 @@ int qcow2_update_header(BlockDriverState *bs) .bit = QCOW2_INCOMPAT_CORRUPT_BITNR, .name = "corrupt bit", }, + { + .type = QCOW2_FEAT_TYPE_INCOMPATIBLE, + .bit = QCOW2_INCOMPAT_DATA_FILE_BITNR, + .name = "external data file", + }, { .type = QCOW2_FEAT_TYPE_COMPATIBLE, .bit = QCOW2_COMPAT_LAZY_REFCOUNTS_BITNR, diff --git a/block/qcow2.h b/block/qcow2.h index 9dd02df831..c63c3959f7 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -197,13 +197,15 @@ enum { /* Incompatible feature bits */ enum { - QCOW2_INCOMPAT_DIRTY_BITNR = 0, - QCOW2_INCOMPAT_CORRUPT_BITNR = 1, - QCOW2_INCOMPAT_DIRTY = 1 << QCOW2_INCOMPAT_DIRTY_BITNR, - QCOW2_INCOMPAT_CORRUPT = 1 << QCOW2_INCOMPAT_CORRUPT_BITNR, + QCOW2_INCOMPAT_DIRTY_BITNR = 0, + QCOW2_INCOMPAT_CORRUPT_BITNR = 1, + QCOW2_INCOMPAT_DATA_FILE_BITNR = 2, + QCOW2_INCOMPAT_DIRTY = 1 << QCOW2_INCOMPAT_DIRTY_BITNR, + QCOW2_INCOMPAT_CORRUPT = 1 << QCOW2_INCOMPAT_CORRUPT_BITNR, + QCOW2_INCOMPAT_DATA_FILE = 1 << QCOW2_INCOMPAT_DATA_FILE_BITNR, - QCOW2_INCOMPAT_MASK = QCOW2_INCOMPAT_DIRTY - | QCOW2_INCOMPAT_CORRUPT, + QCOW2_INCOMPAT_MASK = QCOW2_INCOMPAT_DIRTY + | QCOW2_INCOMPAT_CORRUPT, }; /* Compatible feature bits */ @@ -216,10 +218,12 @@ enum { /* Autoclear feature bits */ enum { - QCOW2_AUTOCLEAR_BITMAPS_BITNR = 0, - QCOW2_AUTOCLEAR_BITMAPS = 1 << QCOW2_AUTOCLEAR_BITMAPS_BITNR, + QCOW2_AUTOCLEAR_BITMAPS_BITNR = 0, + QCOW2_AUTOCLEAR_DATA_FILE_RAW_BITNR = 1, + QCOW2_AUTOCLEAR_BITMAPS = 1 << QCOW2_AUTOCLEAR_BITMAPS_BITNR, + QCOW2_AUTOCLEAR_DATA_FILE_RAW = 1 << QCOW2_AUTOCLEAR_DATA_FILE_RAW_BITNR, - QCOW2_AUTOCLEAR_MASK = QCOW2_AUTOCLEAR_BITMAPS, + QCOW2_AUTOCLEAR_MASK = QCOW2_AUTOCLEAR_BITMAPS, }; enum qcow2_discard_type { @@ -340,6 +344,8 @@ typedef struct BDRVQcow2State { CoQueue compress_wait_queue; int nb_compress_threads; + + BdrvChild *data_file; } BDRVQcow2State; typedef struct Qcow2COWRegion { @@ -457,6 +463,12 @@ typedef enum QCow2MetadataOverlap { #define REFT_OFFSET_MASK 0xfffffffffffffe00ULL +static inline bool has_data_file(BlockDriverState *bs) +{ + BDRVQcow2State *s = bs->opaque; + return (s->data_file != bs->file); +} + static inline int64_t start_of_cluster(BDRVQcow2State *s, int64_t offset) { return offset & ~(s->cluster_size - 1); diff --git a/tests/qemu-iotests/031.out b/tests/qemu-iotests/031.out index 7f5050b816..68a74d03b9 100644 --- a/tests/qemu-iotests/031.out +++ b/tests/qemu-iotests/031.out @@ -117,7 +117,7 @@ header_length 104 Header extension: magic 0x6803f857 -length 144 +length 192 data Header extension: @@ -150,7 +150,7 @@ header_length 104 Header extension: magic 0x6803f857 -length 144 +length 192 data Header extension: @@ -164,7 +164,7 @@ No errors were found on the image. magic 0x514649fb version 3 -backing_file_offset 0x148 +backing_file_offset 0x178 backing_file_size 0x17 cluster_bits 16 size 67108864 @@ -188,7 +188,7 @@ data 'host_device' Header extension: magic 0x6803f857 -length 144 +length 192 data Header extension: diff --git a/tests/qemu-iotests/036.out b/tests/qemu-iotests/036.out index 9b009b8c15..e489b44386 100644 --- a/tests/qemu-iotests/036.out +++ b/tests/qemu-iotests/036.out @@ -58,7 +58,7 @@ header_length 104 Header extension: magic 0x6803f857 -length 144 +length 192 data @@ -86,7 +86,7 @@ header_length 104 Header extension: magic 0x6803f857 -length 144 +length 192 data *** done diff --git a/tests/qemu-iotests/061.out b/tests/qemu-iotests/061.out index 183f7dd690..758284011b 100644 --- a/tests/qemu-iotests/061.out +++ b/tests/qemu-iotests/061.out @@ -26,7 +26,7 @@ header_length 104 Header extension: magic 0x6803f857 -length 144 +length 192 data magic 0x514649fb @@ -84,7 +84,7 @@ header_length 104 Header extension: magic 0x6803f857 -length 144 +length 192 data magic 0x514649fb @@ -144,7 +144,7 @@ header_length 104 Header extension: magic 0x6803f857 -length 144 +length 192 data ERROR cluster 5 refcount=0 reference=1 @@ -199,7 +199,7 @@ header_length 104 Header extension: magic 0x6803f857 -length 144 +length 192 data magic 0x514649fb @@ -268,7 +268,7 @@ header_length 104 Header extension: magic 0x6803f857 -length 144 +length 192 data read 65536/65536 bytes at offset 44040192 @@ -306,7 +306,7 @@ header_length 104 Header extension: magic 0x6803f857 -length 144 +length 192 data ERROR cluster 5 refcount=0 reference=1 @@ -335,7 +335,7 @@ header_length 104 Header extension: magic 0x6803f857 -length 144 +length 192 data read 131072/131072 bytes at offset 0 From 808c2bb4c4b46733c0983ee7f0bfabf9a2f83c25 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 17 Jan 2019 18:42:40 +0100 Subject: [PATCH 15/33] qcow2: Pass bs to qcow2_get_cluster_type() Signed-off-by: Kevin Wolf --- block/qcow2-cluster.c | 37 +++++++++++++++++++------------------ block/qcow2-refcount.c | 10 +++++----- block/qcow2.h | 3 ++- 3 files changed, 26 insertions(+), 24 deletions(-) diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 179aa2c728..9cc8f0f3e4 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -380,8 +380,8 @@ fail: * as contiguous. (This allows it, for example, to stop at the first compressed * cluster which may require a different handling) */ -static int count_contiguous_clusters(int nb_clusters, int cluster_size, - uint64_t *l2_slice, uint64_t stop_flags) +static int count_contiguous_clusters(BlockDriverState *bs, int nb_clusters, + int cluster_size, uint64_t *l2_slice, uint64_t stop_flags) { int i; QCow2ClusterType first_cluster_type; @@ -394,7 +394,7 @@ static int count_contiguous_clusters(int nb_clusters, int cluster_size, } /* must be allocated */ - first_cluster_type = qcow2_get_cluster_type(first_entry); + first_cluster_type = qcow2_get_cluster_type(bs, first_entry); assert(first_cluster_type == QCOW2_CLUSTER_NORMAL || first_cluster_type == QCOW2_CLUSTER_ZERO_ALLOC); @@ -412,7 +412,8 @@ static int count_contiguous_clusters(int nb_clusters, int cluster_size, * Checks how many consecutive unallocated clusters in a given L2 * slice have the same cluster type. */ -static int count_contiguous_clusters_unallocated(int nb_clusters, +static int count_contiguous_clusters_unallocated(BlockDriverState *bs, + int nb_clusters, uint64_t *l2_slice, QCow2ClusterType wanted_type) { @@ -422,7 +423,7 @@ static int count_contiguous_clusters_unallocated(int nb_clusters, wanted_type == QCOW2_CLUSTER_UNALLOCATED); for (i = 0; i < nb_clusters; i++) { uint64_t entry = be64_to_cpu(l2_slice[i]); - QCow2ClusterType type = qcow2_get_cluster_type(entry); + QCow2ClusterType type = qcow2_get_cluster_type(bs, entry); if (type != wanted_type) { break; @@ -595,7 +596,7 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset, * true */ assert(nb_clusters <= INT_MAX); - type = qcow2_get_cluster_type(*cluster_offset); + type = qcow2_get_cluster_type(bs, *cluster_offset); if (s->qcow_version < 3 && (type == QCOW2_CLUSTER_ZERO_PLAIN || type == QCOW2_CLUSTER_ZERO_ALLOC)) { qcow2_signal_corruption(bs, true, -1, -1, "Zero cluster entry found" @@ -613,14 +614,14 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset, case QCOW2_CLUSTER_ZERO_PLAIN: case QCOW2_CLUSTER_UNALLOCATED: /* how many empty clusters ? */ - c = count_contiguous_clusters_unallocated(nb_clusters, + c = count_contiguous_clusters_unallocated(bs, nb_clusters, &l2_slice[l2_index], type); *cluster_offset = 0; break; case QCOW2_CLUSTER_ZERO_ALLOC: case QCOW2_CLUSTER_NORMAL: /* how many allocated clusters ? */ - c = count_contiguous_clusters(nb_clusters, s->cluster_size, + c = count_contiguous_clusters(bs, nb_clusters, s->cluster_size, &l2_slice[l2_index], QCOW_OFLAG_ZERO); *cluster_offset &= L2E_OFFSET_MASK; if (offset_into_cluster(s, *cluster_offset)) { @@ -1013,14 +1014,14 @@ void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m) * write, but require COW to be performed (this includes yet unallocated space, * which must copy from the backing file) */ -static int count_cow_clusters(BDRVQcow2State *s, int nb_clusters, +static int count_cow_clusters(BlockDriverState *bs, int nb_clusters, uint64_t *l2_slice, int l2_index) { int i; for (i = 0; i < nb_clusters; i++) { uint64_t l2_entry = be64_to_cpu(l2_slice[l2_index + i]); - QCow2ClusterType cluster_type = qcow2_get_cluster_type(l2_entry); + QCow2ClusterType cluster_type = qcow2_get_cluster_type(bs, l2_entry); switch(cluster_type) { case QCOW2_CLUSTER_NORMAL: @@ -1165,7 +1166,7 @@ static int handle_copied(BlockDriverState *bs, uint64_t guest_offset, cluster_offset = be64_to_cpu(l2_slice[l2_index]); /* Check how many clusters are already allocated and don't need COW */ - if (qcow2_get_cluster_type(cluster_offset) == QCOW2_CLUSTER_NORMAL + if (qcow2_get_cluster_type(bs, cluster_offset) == QCOW2_CLUSTER_NORMAL && (cluster_offset & QCOW_OFLAG_COPIED)) { /* If a specific host_offset is required, check it */ @@ -1189,7 +1190,7 @@ static int handle_copied(BlockDriverState *bs, uint64_t guest_offset, /* We keep all QCOW_OFLAG_COPIED clusters */ keep_clusters = - count_contiguous_clusters(nb_clusters, s->cluster_size, + count_contiguous_clusters(bs, nb_clusters, s->cluster_size, &l2_slice[l2_index], QCOW_OFLAG_COPIED | QCOW_OFLAG_ZERO); assert(keep_clusters <= nb_clusters); @@ -1324,7 +1325,7 @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset, if (entry & QCOW_OFLAG_COMPRESSED) { nb_clusters = 1; } else { - nb_clusters = count_cow_clusters(s, nb_clusters, l2_slice, l2_index); + nb_clusters = count_cow_clusters(bs, nb_clusters, l2_slice, l2_index); } /* This function is only called when there were no non-COW clusters, so if @@ -1332,7 +1333,7 @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset, * wrong with our code. */ assert(nb_clusters > 0); - if (qcow2_get_cluster_type(entry) == QCOW2_CLUSTER_ZERO_ALLOC && + if (qcow2_get_cluster_type(bs, entry) == QCOW2_CLUSTER_ZERO_ALLOC && (entry & QCOW_OFLAG_COPIED) && (!*host_offset || start_of_cluster(s, *host_offset) == (entry & L2E_OFFSET_MASK))) @@ -1352,7 +1353,7 @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset, * would be fine, too, but count_cow_clusters() above has limited * nb_clusters already to a range of COW clusters */ preallocated_nb_clusters = - count_contiguous_clusters(nb_clusters, s->cluster_size, + count_contiguous_clusters(bs, nb_clusters, s->cluster_size, &l2_slice[l2_index], QCOW_OFLAG_COPIED); assert(preallocated_nb_clusters > 0); @@ -1616,7 +1617,7 @@ static int discard_in_l2_slice(BlockDriverState *bs, uint64_t offset, * If full_discard is true, the sector should not read back as zeroes, * but rather fall through to the backing file. */ - switch (qcow2_get_cluster_type(old_l2_entry)) { + switch (qcow2_get_cluster_type(bs, old_l2_entry)) { case QCOW2_CLUSTER_UNALLOCATED: if (full_discard || !bs->backing) { continue; @@ -1729,7 +1730,7 @@ static int zero_in_l2_slice(BlockDriverState *bs, uint64_t offset, * Minimize L2 changes if the cluster already reads back as * zeroes with correct allocation. */ - cluster_type = qcow2_get_cluster_type(old_offset); + cluster_type = qcow2_get_cluster_type(bs, old_offset); if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN || (cluster_type == QCOW2_CLUSTER_ZERO_ALLOC && !unmap)) { continue; @@ -1871,7 +1872,7 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table, uint64_t l2_entry = be64_to_cpu(l2_slice[j]); int64_t offset = l2_entry & L2E_OFFSET_MASK; QCow2ClusterType cluster_type = - qcow2_get_cluster_type(l2_entry); + qcow2_get_cluster_type(bs, l2_entry); if (cluster_type != QCOW2_CLUSTER_ZERO_PLAIN && cluster_type != QCOW2_CLUSTER_ZERO_ALLOC) { diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 6f13d470d3..05e7974d7e 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -1157,7 +1157,7 @@ void qcow2_free_any_clusters(BlockDriverState *bs, uint64_t l2_entry, { BDRVQcow2State *s = bs->opaque; - switch (qcow2_get_cluster_type(l2_entry)) { + switch (qcow2_get_cluster_type(bs, l2_entry)) { case QCOW2_CLUSTER_COMPRESSED: { int nb_csectors; @@ -1300,7 +1300,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs, entry &= ~QCOW_OFLAG_COPIED; offset = entry & L2E_OFFSET_MASK; - switch (qcow2_get_cluster_type(entry)) { + switch (qcow2_get_cluster_type(bs, entry)) { case QCOW2_CLUSTER_COMPRESSED: nb_csectors = ((entry >> s->csize_shift) & s->csize_mask) + 1; @@ -1582,7 +1582,7 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res, for(i = 0; i < s->l2_size; i++) { l2_entry = be64_to_cpu(l2_table[i]); - switch (qcow2_get_cluster_type(l2_entry)) { + switch (qcow2_get_cluster_type(bs, l2_entry)) { case QCOW2_CLUSTER_COMPRESSED: /* Compressed clusters don't have QCOW_OFLAG_COPIED */ if (l2_entry & QCOW_OFLAG_COPIED) { @@ -1633,7 +1633,7 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res, /* Correct offsets are cluster aligned */ if (offset_into_cluster(s, offset)) { - if (qcow2_get_cluster_type(l2_entry) == + if (qcow2_get_cluster_type(bs, l2_entry) == QCOW2_CLUSTER_ZERO_ALLOC) { fprintf(stderr, "%s offset=%" PRIx64 ": Preallocated zero " @@ -1868,7 +1868,7 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res, for (j = 0; j < s->l2_size; j++) { uint64_t l2_entry = be64_to_cpu(l2_table[j]); uint64_t data_offset = l2_entry & L2E_OFFSET_MASK; - QCow2ClusterType cluster_type = qcow2_get_cluster_type(l2_entry); + QCow2ClusterType cluster_type = qcow2_get_cluster_type(bs, l2_entry); if (cluster_type == QCOW2_CLUSTER_NORMAL || cluster_type == QCOW2_CLUSTER_ZERO_ALLOC) { diff --git a/block/qcow2.h b/block/qcow2.h index c63c3959f7..7a34bd0c53 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -510,7 +510,8 @@ static inline int64_t qcow2_vm_state_offset(BDRVQcow2State *s) return (int64_t)s->l1_vm_state_index << (s->cluster_bits + s->l2_bits); } -static inline QCow2ClusterType qcow2_get_cluster_type(uint64_t l2_entry) +static inline QCow2ClusterType qcow2_get_cluster_type(BlockDriverState *bs, + uint64_t l2_entry) { if (l2_entry & QCOW_OFLAG_COMPRESSED) { return QCOW2_CLUSTER_COMPRESSED; From a4ea184d8af936cdc4bea4afdb5c30ffaed0c4f7 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 29 Jan 2019 13:47:24 +0100 Subject: [PATCH 16/33] qcow2: Prepare qcow2_get_cluster_type() for external data file Signed-off-by: Kevin Wolf --- block/qcow2.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/block/qcow2.h b/block/qcow2.h index 7a34bd0c53..8fe2d55005 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -521,7 +521,15 @@ static inline QCow2ClusterType qcow2_get_cluster_type(BlockDriverState *bs, } return QCOW2_CLUSTER_ZERO_PLAIN; } else if (!(l2_entry & L2E_OFFSET_MASK)) { - return QCOW2_CLUSTER_UNALLOCATED; + /* Offset 0 generally means unallocated, but it is ambiguous with + * external data files because 0 is a valid offset there. However, all + * clusters in external data files always have refcount 1, so we can + * rely on QCOW_OFLAG_COPIED to disambiguate. */ + if (has_data_file(bs) && (l2_entry & QCOW_OFLAG_COPIED)) { + return QCOW2_CLUSTER_NORMAL; + } else { + return QCOW2_CLUSTER_UNALLOCATED; + } } else { return QCOW2_CLUSTER_NORMAL; } From b8c8353a38296fbb92e05a2843e853c1ddfc2674 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 18 Jan 2019 13:44:40 +0100 Subject: [PATCH 17/33] qcow2: Prepare count_contiguous_clusters() for external data file Offset 0 can be valid for normal (allocated) clusters now, so use qcow2_get_cluster_type() instead. Signed-off-by: Kevin Wolf --- block/qcow2-cluster.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 9cc8f0f3e4..660161bf00 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -389,12 +389,12 @@ static int count_contiguous_clusters(BlockDriverState *bs, int nb_clusters, uint64_t first_entry = be64_to_cpu(l2_slice[0]); uint64_t offset = first_entry & mask; - if (!offset) { + first_cluster_type = qcow2_get_cluster_type(bs, first_entry); + if (first_cluster_type == QCOW2_CLUSTER_UNALLOCATED) { return 0; } /* must be allocated */ - first_cluster_type = qcow2_get_cluster_type(bs, first_entry); assert(first_cluster_type == QCOW2_CLUSTER_NORMAL || first_cluster_type == QCOW2_CLUSTER_ZERO_ALLOC); From c6d619cc12813acb2b1198f28cf2256ea9a30107 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 18 Jan 2019 14:40:36 +0100 Subject: [PATCH 18/33] qcow2: Don't assume 0 is an invalid cluster offset The cluster allocation code uses 0 as an invalid offset that is used in case of errors or as "offset not yet determined". With external data files, a host cluster offset of 0 becomes valid, though. Define a constant INV_OFFSET (which is not cluster aligned and will therefore never be a valid offset) that can be used for such purposes. This removes the additional host_offset == 0 check that commit ff52aab2df5 introduced; the confusion between an invalid offset and (erroneous) allocation at offset 0 is removed with this change. Signed-off-by: Kevin Wolf --- block/qcow2-cluster.c | 59 ++++++++++++++++++++----------------------- block/qcow2.h | 2 ++ 2 files changed, 29 insertions(+), 32 deletions(-) diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 660161bf00..1d09f5454e 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -1109,9 +1109,9 @@ static int handle_dependencies(BlockDriverState *bs, uint64_t guest_offset, /* * Checks how many already allocated clusters that don't require a copy on - * write there are at the given guest_offset (up to *bytes). If - * *host_offset is not zero, only physically contiguous clusters beginning at - * this host offset are counted. + * write there are at the given guest_offset (up to *bytes). If *host_offset is + * not INV_OFFSET, only physically contiguous clusters beginning at this host + * offset are counted. * * Note that guest_offset may not be cluster aligned. In this case, the * returned *host_offset points to exact byte referenced by guest_offset and @@ -1143,8 +1143,8 @@ static int handle_copied(BlockDriverState *bs, uint64_t guest_offset, trace_qcow2_handle_copied(qemu_coroutine_self(), guest_offset, *host_offset, *bytes); - assert(*host_offset == 0 || offset_into_cluster(s, guest_offset) - == offset_into_cluster(s, *host_offset)); + assert(*host_offset == INV_OFFSET || offset_into_cluster(s, guest_offset) + == offset_into_cluster(s, *host_offset)); /* * Calculate the number of clusters to look for. We stop at L2 slice @@ -1182,7 +1182,7 @@ static int handle_copied(BlockDriverState *bs, uint64_t guest_offset, goto out; } - if (*host_offset != 0 && !offset_matches) { + if (*host_offset != INV_OFFSET && !offset_matches) { *bytes = 0; ret = 0; goto out; @@ -1225,10 +1225,10 @@ out: * contain the number of clusters that have been allocated and are contiguous * in the image file. * - * If *host_offset is non-zero, it specifies the offset in the image file at - * which the new clusters must start. *nb_clusters can be 0 on return in this - * case if the cluster at host_offset is already in use. If *host_offset is - * zero, the clusters can be allocated anywhere in the image file. + * If *host_offset is not INV_OFFSET, it specifies the offset in the image file + * at which the new clusters must start. *nb_clusters can be 0 on return in + * this case if the cluster at host_offset is already in use. If *host_offset + * is INV_OFFSET, the clusters can be allocated anywhere in the image file. * * *host_offset is updated to contain the offset into the image file at which * the first allocated cluster starts. @@ -1247,7 +1247,7 @@ static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset, /* Allocate new clusters */ trace_qcow2_cluster_alloc_phys(qemu_coroutine_self()); - if (*host_offset == 0) { + if (*host_offset == INV_OFFSET) { int64_t cluster_offset = qcow2_alloc_clusters(bs, *nb_clusters * s->cluster_size); if (cluster_offset < 0) { @@ -1267,8 +1267,8 @@ static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset, /* * Allocates new clusters for an area that either is yet unallocated or needs a - * copy on write. If *host_offset is non-zero, clusters are only allocated if - * the new allocation can match the specified host offset. + * copy on write. If *host_offset is not INV_OFFSET, clusters are only + * allocated if the new allocation can match the specified host offset. * * Note that guest_offset may not be cluster aligned. In this case, the * returned *host_offset points to exact byte referenced by guest_offset and @@ -1296,7 +1296,7 @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset, int ret; bool keep_old_clusters = false; - uint64_t alloc_cluster_offset = 0; + uint64_t alloc_cluster_offset = INV_OFFSET; trace_qcow2_handle_alloc(qemu_coroutine_self(), guest_offset, *host_offset, *bytes); @@ -1335,7 +1335,7 @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset, if (qcow2_get_cluster_type(bs, entry) == QCOW2_CLUSTER_ZERO_ALLOC && (entry & QCOW_OFLAG_COPIED) && - (!*host_offset || + (*host_offset == INV_OFFSET || start_of_cluster(s, *host_offset) == (entry & L2E_OFFSET_MASK))) { int preallocated_nb_clusters; @@ -1367,9 +1367,10 @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset, qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice); - if (!alloc_cluster_offset) { + if (alloc_cluster_offset == INV_OFFSET) { /* Allocate, if necessary at a given offset in the image file */ - alloc_cluster_offset = start_of_cluster(s, *host_offset); + alloc_cluster_offset = *host_offset == INV_OFFSET ? INV_OFFSET : + start_of_cluster(s, *host_offset); ret = do_alloc_cluster_offset(bs, guest_offset, &alloc_cluster_offset, &nb_clusters); if (ret < 0) { @@ -1382,16 +1383,7 @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset, return 0; } - /* !*host_offset would overwrite the image header and is reserved for - * "no host offset preferred". If 0 was a valid host offset, it'd - * trigger the following overlap check; do that now to avoid having an - * invalid value in *host_offset. */ - if (!alloc_cluster_offset) { - ret = qcow2_pre_write_overlap_check(bs, 0, alloc_cluster_offset, - nb_clusters * s->cluster_size); - assert(ret < 0); - goto fail; - } + assert(alloc_cluster_offset != INV_OFFSET); } /* @@ -1483,14 +1475,14 @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset, again: start = offset; remaining = *bytes; - cluster_offset = 0; - *host_offset = 0; + cluster_offset = INV_OFFSET; + *host_offset = INV_OFFSET; cur_bytes = 0; *m = NULL; while (true) { - if (!*host_offset) { + if (*host_offset == INV_OFFSET && cluster_offset != INV_OFFSET) { *host_offset = start_of_cluster(s, cluster_offset); } @@ -1498,7 +1490,10 @@ again: start += cur_bytes; remaining -= cur_bytes; - cluster_offset += cur_bytes; + + if (cluster_offset != INV_OFFSET) { + cluster_offset += cur_bytes; + } if (remaining == 0) { break; @@ -1570,7 +1565,7 @@ again: *bytes -= remaining; assert(*bytes > 0); - assert(*host_offset != 0); + assert(*host_offset != INV_OFFSET); return 0; } diff --git a/block/qcow2.h b/block/qcow2.h index 8fe2d55005..e3bf322be1 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -463,6 +463,8 @@ typedef enum QCow2MetadataOverlap { #define REFT_OFFSET_MASK 0xfffffffffffffe00ULL +#define INV_OFFSET (-1ULL) + static inline bool has_data_file(BlockDriverState *bs) { BDRVQcow2State *s = bs->opaque; From 77e023ff79222191e8cc3d377504da8f19926837 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Wed, 27 Feb 2019 10:26:24 +0100 Subject: [PATCH 19/33] qcow2: Return 0/-errno in qcow2_alloc_compressed_cluster_offset() qcow2_alloc_compressed_cluster_offset() used to return the cluster offset for success and 0 for error. This doesn't only conflict with 0 as a valid host offset, but also loses the error code. Similar to the change made to qcow2_alloc_cluster_offset() for uncompressed clusters in commit 148da7ea9d6, make the function return 0/-errno and return the allocated cluster offset in a by-reference parameter. Signed-off-by: Kevin Wolf --- block/qcow2-cluster.c | 28 +++++++++++++--------------- block/qcow2.c | 19 ++++++++----------- block/qcow2.h | 7 ++++--- tests/qemu-iotests/220.out | 2 +- 4 files changed, 26 insertions(+), 30 deletions(-) diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 1d09f5454e..8c4b4005ff 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -736,19 +736,16 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset, /* * alloc_compressed_cluster_offset * - * For a given offset of the disk image, return cluster offset in - * qcow2 file. - * - * If the offset is not found, allocate a new compressed cluster. - * - * Return the cluster offset if successful, - * Return 0, otherwise. + * For a given offset on the virtual disk, allocate a new compressed cluster + * and put the host offset of the cluster into *host_offset. If a cluster is + * already allocated at the offset, return an error. * + * Return 0 on success and -errno in error cases */ - -uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, - uint64_t offset, - int compressed_size) +int qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, + uint64_t offset, + int compressed_size, + uint64_t *host_offset) { BDRVQcow2State *s = bs->opaque; int l2_index, ret; @@ -758,7 +755,7 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, ret = get_cluster_table(bs, offset, &l2_slice, &l2_index); if (ret < 0) { - return 0; + return ret; } /* Compression can't overwrite anything. Fail if the cluster was already @@ -766,13 +763,13 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, cluster_offset = be64_to_cpu(l2_slice[l2_index]); if (cluster_offset & L2E_OFFSET_MASK) { qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice); - return 0; + return -EIO; } cluster_offset = qcow2_alloc_bytes(bs, compressed_size); if (cluster_offset < 0) { qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice); - return 0; + return cluster_offset; } nb_csectors = ((cluster_offset + compressed_size - 1) >> 9) - @@ -790,7 +787,8 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, l2_slice[l2_index] = cpu_to_be64(cluster_offset); qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice); - return cluster_offset; + *host_offset = cluster_offset & s->cluster_offset_mask; + return 0; } static int perform_cow(BlockDriverState *bs, QCowL2Meta *m) diff --git a/block/qcow2.c b/block/qcow2.c index 59cf706dc2..eaccd1c11a 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -3896,17 +3896,16 @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset, int ret; size_t out_len; uint8_t *buf, *out_buf; - int64_t cluster_offset; + uint64_t cluster_offset; if (bytes == 0) { /* align end of file to a sector boundary to ease reading with sector based I/Os */ - cluster_offset = bdrv_getlength(bs->file->bs); - if (cluster_offset < 0) { - return cluster_offset; + int64_t len = bdrv_getlength(bs->file->bs); + if (len < 0) { + return len; } - return bdrv_co_truncate(bs->file, cluster_offset, PREALLOC_MODE_OFF, - NULL); + return bdrv_co_truncate(bs->file, len, PREALLOC_MODE_OFF, NULL); } if (offset_into_cluster(s, offset)) { @@ -3943,14 +3942,12 @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset, } qemu_co_mutex_lock(&s->lock); - cluster_offset = - qcow2_alloc_compressed_cluster_offset(bs, offset, out_len); - if (!cluster_offset) { + ret = qcow2_alloc_compressed_cluster_offset(bs, offset, out_len, + &cluster_offset); + if (ret < 0) { qemu_co_mutex_unlock(&s->lock); - ret = -EIO; goto fail; } - cluster_offset &= s->cluster_offset_mask; ret = qcow2_pre_write_overlap_check(bs, 0, cluster_offset, out_len); qemu_co_mutex_unlock(&s->lock); diff --git a/block/qcow2.h b/block/qcow2.h index e3bf322be1..fad6abf602 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -647,9 +647,10 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset, int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset, unsigned int *bytes, uint64_t *host_offset, QCowL2Meta **m); -uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, - uint64_t offset, - int compressed_size); +int qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, + uint64_t offset, + int compressed_size, + uint64_t *host_offset); int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m); void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m); diff --git a/tests/qemu-iotests/220.out b/tests/qemu-iotests/220.out index af3021fd88..33b994b8a1 100644 --- a/tests/qemu-iotests/220.out +++ b/tests/qemu-iotests/220.out @@ -38,7 +38,7 @@ wrote 2097152/2097152 bytes at offset 37748736 No errors were found on the image. image size 39845888 == Trying to write compressed cluster == -write failed: Input/output error +write failed: File too large image size 562949957615616 == Writing normal cluster == wrote 2097152/2097152 bytes at offset 0 From 37be14036b1a7ae066f76d3296bbd37b0c697637 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Wed, 27 Feb 2019 13:22:56 +0100 Subject: [PATCH 20/33] qcow2: Prepare qcow2_co_block_status() for data file Offset 0 cannot be assumed to mean an unallocated cluster any more. Instead, the cluster type needs to be checked. *file must refer to the data file instead of the image file if a valid offset is returned from qcow2_co_block_status(). Signed-off-by: Kevin Wolf --- block/qcow2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index eaccd1c11a..8d1f667e91 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1829,11 +1829,11 @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs, *pnum = bytes; - if (cluster_offset != 0 && ret != QCOW2_CLUSTER_COMPRESSED && + if ((ret == QCOW2_CLUSTER_NORMAL || ret == QCOW2_CLUSTER_ZERO_ALLOC) && !s->crypto) { index_in_cluster = offset & (s->cluster_size - 1); *map = cluster_offset | index_in_cluster; - *file = bs->file->bs; + *file = s->data_file->bs; status |= BDRV_BLOCK_OFFSET_VALID; } if (ret == QCOW2_CLUSTER_ZERO_PLAIN || ret == QCOW2_CLUSTER_ZERO_ALLOC) { From 966b000f49c3f44d2853d691f6bbc2a4e1f2d0b0 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 15 Jan 2019 20:39:06 +0100 Subject: [PATCH 21/33] qcow2: External file I/O This changes the qcow2 implementation to direct all guest data I/O to s->data_file rather than bs->file, while metadata I/O still uses bs->file. At the moment, this is still always the same, but soon we'll add options to set s->data_file to an external data file. Signed-off-by: Kevin Wolf --- block/qcow2-bitmap.c | 7 +++--- block/qcow2-cache.c | 6 ++--- block/qcow2-cluster.c | 46 +++++++++++++++++++++++++++++++------ block/qcow2-refcount.c | 39 +++++++++++++++++++++++-------- block/qcow2-snapshot.c | 7 +++--- block/qcow2.c | 52 +++++++++++++++++++++++++++++++++--------- block/qcow2.h | 2 +- 7 files changed, 122 insertions(+), 37 deletions(-) diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c index 3ee524da4b..9d968bdcda 100644 --- a/block/qcow2-bitmap.c +++ b/block/qcow2-bitmap.c @@ -778,7 +778,8 @@ static int bitmap_list_store(BlockDriverState *bs, Qcow2BitmapList *bm_list, * directory in-place (actually, turn-off the extension), which is checked * in qcow2_check_metadata_overlap() */ ret = qcow2_pre_write_overlap_check( - bs, in_place ? QCOW2_OL_BITMAP_DIRECTORY : 0, dir_offset, dir_size); + bs, in_place ? QCOW2_OL_BITMAP_DIRECTORY : 0, dir_offset, dir_size, + false); if (ret < 0) { goto fail; } @@ -1224,7 +1225,7 @@ static uint64_t *store_bitmap_data(BlockDriverState *bs, memset(buf + write_size, 0, s->cluster_size - write_size); } - ret = qcow2_pre_write_overlap_check(bs, 0, off, s->cluster_size); + ret = qcow2_pre_write_overlap_check(bs, 0, off, s->cluster_size, false); if (ret < 0) { error_setg_errno(errp, -ret, "Qcow2 overlap check failed"); goto fail; @@ -1292,7 +1293,7 @@ static int store_bitmap(BlockDriverState *bs, Qcow2Bitmap *bm, Error **errp) } ret = qcow2_pre_write_overlap_check(bs, 0, tb_offset, - tb_size * sizeof(tb[0])); + tb_size * sizeof(tb[0]), false); if (ret < 0) { error_setg_errno(errp, -ret, "Qcow2 overlap check failed"); goto fail; diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c index d9dafa31e5..df02e7b20a 100644 --- a/block/qcow2-cache.c +++ b/block/qcow2-cache.c @@ -205,13 +205,13 @@ static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i) if (c == s->refcount_block_cache) { ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_REFCOUNT_BLOCK, - c->entries[i].offset, c->table_size); + c->entries[i].offset, c->table_size, false); } else if (c == s->l2_table_cache) { ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_ACTIVE_L2, - c->entries[i].offset, c->table_size); + c->entries[i].offset, c->table_size, false); } else { ret = qcow2_pre_write_overlap_check(bs, 0, - c->entries[i].offset, c->table_size); + c->entries[i].offset, c->table_size, false); } if (ret < 0) { diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 8c4b4005ff..7579f5a5ae 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -153,7 +153,7 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size, /* the L1 position has not yet been updated, so these clusters must * indeed be completely free */ ret = qcow2_pre_write_overlap_check(bs, 0, new_l1_table_offset, - new_l1_size2); + new_l1_size2, false); if (ret < 0) { goto fail; } @@ -238,7 +238,7 @@ int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index) } ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_ACTIVE_L1, - s->l1_table_offset + 8 * l1_start_index, sizeof(buf)); + s->l1_table_offset + 8 * l1_start_index, sizeof(buf), false); if (ret < 0) { return ret; } @@ -490,6 +490,7 @@ static int coroutine_fn do_perform_cow_write(BlockDriverState *bs, unsigned offset_in_cluster, QEMUIOVector *qiov) { + BDRVQcow2State *s = bs->opaque; int ret; if (qiov->size == 0) { @@ -497,13 +498,13 @@ static int coroutine_fn do_perform_cow_write(BlockDriverState *bs, } ret = qcow2_pre_write_overlap_check(bs, 0, - cluster_offset + offset_in_cluster, qiov->size); + cluster_offset + offset_in_cluster, qiov->size, true); if (ret < 0) { return ret; } BLKDBG_EVENT(bs->file, BLKDBG_COW_WRITE); - ret = bdrv_co_pwritev(bs->file, cluster_offset + offset_in_cluster, + ret = bdrv_co_pwritev(s->data_file, cluster_offset + offset_in_cluster, qiov->size, qiov, 0); if (ret < 0) { return ret; @@ -607,6 +608,14 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset, } switch (type) { case QCOW2_CLUSTER_COMPRESSED: + if (has_data_file(bs)) { + qcow2_signal_corruption(bs, true, -1, -1, "Compressed cluster " + "entry found in image with external data " + "file (L2 offset: %#" PRIx64 ", L2 index: " + "%#x)", l2_offset, l2_index); + ret = -EIO; + goto fail; + } /* Compressed clusters can only be processed one by one */ c = 1; *cluster_offset &= L2E_COMPRESSED_OFFSET_SIZE_MASK; @@ -633,6 +642,17 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset, ret = -EIO; goto fail; } + if (has_data_file(bs) && *cluster_offset != offset - offset_in_cluster) + { + qcow2_signal_corruption(bs, true, -1, -1, + "External data file host cluster offset %#" + PRIx64 " does not match guest cluster " + "offset: %#" PRIx64 + ", L2 index: %#x)", *cluster_offset, + offset - offset_in_cluster, l2_index); + ret = -EIO; + goto fail; + } break; default: abort(); @@ -753,6 +773,10 @@ int qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, int64_t cluster_offset; int nb_csectors; + if (has_data_file(bs)) { + return 0; + } + ret = get_cluster_table(bs, offset, &l2_slice, &l2_index); if (ret < 0) { return ret; @@ -1243,6 +1267,13 @@ static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset, trace_qcow2_do_alloc_clusters_offset(qemu_coroutine_self(), guest_offset, *host_offset, *nb_clusters); + if (has_data_file(bs)) { + assert(*host_offset == INV_OFFSET || + *host_offset == start_of_cluster(s, guest_offset)); + *host_offset = start_of_cluster(s, guest_offset); + return 0; + } + /* Allocate new clusters */ trace_qcow2_cluster_alloc_phys(qemu_coroutine_self()); if (*host_offset == INV_OFFSET) { @@ -1919,7 +1950,7 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table, } ret = qcow2_pre_write_overlap_check(bs, 0, offset, - s->cluster_size); + s->cluster_size, true); if (ret < 0) { if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN) { qcow2_free_clusters(bs, offset, s->cluster_size, @@ -1928,7 +1959,8 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table, goto fail; } - ret = bdrv_pwrite_zeroes(bs->file, offset, s->cluster_size, 0); + ret = bdrv_pwrite_zeroes(s->data_file, offset, + s->cluster_size, 0); if (ret < 0) { if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN) { qcow2_free_clusters(bs, offset, s->cluster_size, @@ -1955,7 +1987,7 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table, if (l2_dirty) { ret = qcow2_pre_write_overlap_check( bs, QCOW2_OL_INACTIVE_L2 | QCOW2_OL_ACTIVE_L2, - slice_offset, slice_size2); + slice_offset, slice_size2, false); if (ret < 0) { goto fail; } diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 05e7974d7e..df73580e5d 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -1156,8 +1156,20 @@ void qcow2_free_any_clusters(BlockDriverState *bs, uint64_t l2_entry, int nb_clusters, enum qcow2_discard_type type) { BDRVQcow2State *s = bs->opaque; + QCow2ClusterType ctype = qcow2_get_cluster_type(bs, l2_entry); - switch (qcow2_get_cluster_type(bs, l2_entry)) { + if (has_data_file(bs)) { + if (s->discard_passthrough[type] && + (ctype == QCOW2_CLUSTER_NORMAL || + ctype == QCOW2_CLUSTER_ZERO_ALLOC)) + { + bdrv_pdiscard(s->data_file, l2_entry & L2E_OFFSET_MASK, + nb_clusters << s->cluster_bits); + } + return; + } + + switch (ctype) { case QCOW2_CLUSTER_COMPRESSED: { int nb_csectors; @@ -1649,7 +1661,7 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res, l2_table[i] = cpu_to_be64(l2_entry); ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_ACTIVE_L2 | QCOW2_OL_INACTIVE_L2, - l2e_offset, sizeof(uint64_t)); + l2e_offset, sizeof(uint64_t), false); if (ret < 0) { fprintf(stderr, "ERROR: Overlap check failed\n"); res->check_errors++; @@ -1898,7 +1910,8 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res, if (l2_dirty) { ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_ACTIVE_L2, - l2_offset, s->cluster_size); + l2_offset, s->cluster_size, + false); if (ret < 0) { fprintf(stderr, "ERROR: Could not write L2 table; metadata " "overlap check failed: %s\n", strerror(-ret)); @@ -2366,7 +2379,7 @@ write_refblocks: } ret = qcow2_pre_write_overlap_check(bs, 0, refblock_offset, - s->cluster_size); + s->cluster_size, false); if (ret < 0) { fprintf(stderr, "ERROR writing refblock: %s\n", strerror(-ret)); goto fail; @@ -2417,7 +2430,8 @@ write_refblocks: } ret = qcow2_pre_write_overlap_check(bs, 0, reftable_offset, - reftable_size * sizeof(uint64_t)); + reftable_size * sizeof(uint64_t), + false); if (ret < 0) { fprintf(stderr, "ERROR writing reftable: %s\n", strerror(-ret)); goto fail; @@ -2751,10 +2765,15 @@ QEMU_BUILD_BUG_ON(QCOW2_OL_MAX_BITNR != ARRAY_SIZE(metadata_ol_names)); * overlaps; or a negative value (-errno) on error. */ int qcow2_pre_write_overlap_check(BlockDriverState *bs, int ign, int64_t offset, - int64_t size) + int64_t size, bool data_file) { - int ret = qcow2_check_metadata_overlap(bs, ign, offset, size); + int ret; + if (data_file && has_data_file(bs)) { + return 0; + } + + ret = qcow2_check_metadata_overlap(bs, ign, offset, size); if (ret < 0) { return ret; } else if (ret > 0) { @@ -2855,7 +2874,8 @@ static int flush_refblock(BlockDriverState *bs, uint64_t **reftable, if (reftable_index < *reftable_size && (*reftable)[reftable_index]) { offset = (*reftable)[reftable_index]; - ret = qcow2_pre_write_overlap_check(bs, 0, offset, s->cluster_size); + ret = qcow2_pre_write_overlap_check(bs, 0, offset, s->cluster_size, + false); if (ret < 0) { error_setg_errno(errp, -ret, "Overlap check failed"); return ret; @@ -3121,7 +3141,8 @@ int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order, /* Write the new reftable */ ret = qcow2_pre_write_overlap_check(bs, 0, new_reftable_offset, - new_reftable_size * sizeof(uint64_t)); + new_reftable_size * sizeof(uint64_t), + false); if (ret < 0) { error_setg_errno(errp, -ret, "Overlap check failed"); goto done; diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c index 20e8472191..5ae3407f68 100644 --- a/block/qcow2-snapshot.c +++ b/block/qcow2-snapshot.c @@ -184,7 +184,7 @@ static int qcow2_write_snapshots(BlockDriverState *bs) /* The snapshot list position has not yet been updated, so these clusters * must indeed be completely free */ - ret = qcow2_pre_write_overlap_check(bs, 0, offset, snapshots_size); + ret = qcow2_pre_write_overlap_check(bs, 0, offset, snapshots_size, false); if (ret < 0) { goto fail; } @@ -389,7 +389,7 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) } ret = qcow2_pre_write_overlap_check(bs, 0, sn->l1_table_offset, - s->l1_size * sizeof(uint64_t)); + s->l1_size * sizeof(uint64_t), false); if (ret < 0) { goto fail; } @@ -528,7 +528,8 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id) } ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_ACTIVE_L1, - s->l1_table_offset, cur_l1_bytes); + s->l1_table_offset, cur_l1_bytes, + false); if (ret < 0) { goto fail; } diff --git a/block/qcow2.c b/block/qcow2.c index 8d1f667e91..f048763e10 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -140,7 +140,7 @@ static ssize_t qcow2_crypto_hdr_init_func(QCryptoBlock *block, size_t headerlen, /* Zero fill remaining space in cluster so it has predictable * content in case of future spec changes */ clusterlen = size_to_clusters(s, headerlen) * s->cluster_size; - assert(qcow2_pre_write_overlap_check(bs, 0, ret, clusterlen) == 0); + assert(qcow2_pre_write_overlap_check(bs, 0, ret, clusterlen, false) == 0); ret = bdrv_pwrite_zeroes(bs->file, ret + headerlen, clusterlen - headerlen, 0); @@ -1965,7 +1965,7 @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset, */ if (!cluster_data) { cluster_data = - qemu_try_blockalign(bs->file->bs, + qemu_try_blockalign(s->data_file->bs, QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size); if (cluster_data == NULL) { @@ -1981,7 +1981,7 @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset, BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO); qemu_co_mutex_unlock(&s->lock); - ret = bdrv_co_preadv(bs->file, + ret = bdrv_co_preadv(s->data_file, cluster_offset + offset_in_cluster, cur_bytes, &hd_qiov, 0); qemu_co_mutex_lock(&s->lock); @@ -2140,7 +2140,7 @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset, } ret = qcow2_pre_write_overlap_check(bs, 0, - cluster_offset + offset_in_cluster, cur_bytes); + cluster_offset + offset_in_cluster, cur_bytes, true); if (ret < 0) { goto fail; } @@ -2154,7 +2154,7 @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset, BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO); trace_qcow2_writev_data(qemu_coroutine_self(), cluster_offset + offset_in_cluster); - ret = bdrv_co_pwritev(bs->file, + ret = bdrv_co_pwritev(s->data_file, cluster_offset + offset_in_cluster, cur_bytes, &hd_qiov, 0); qemu_co_mutex_lock(&s->lock); @@ -3356,7 +3356,7 @@ qcow2_co_copy_range_from(BlockDriverState *bs, goto out; case QCOW2_CLUSTER_NORMAL: - child = bs->file; + child = s->data_file; copy_offset += offset_into_cluster(s, src_offset); if ((copy_offset & 511) != 0) { ret = -EIO; @@ -3426,14 +3426,14 @@ qcow2_co_copy_range_to(BlockDriverState *bs, assert((cluster_offset & 511) == 0); ret = qcow2_pre_write_overlap_check(bs, 0, - cluster_offset + offset_in_cluster, cur_bytes); + cluster_offset + offset_in_cluster, cur_bytes, true); if (ret < 0) { goto fail; } qemu_co_mutex_unlock(&s->lock); ret = bdrv_co_copy_range_to(src, src_offset, - bs->file, + s->data_file, cluster_offset + offset_in_cluster, cur_bytes, read_flags, write_flags); qemu_co_mutex_lock(&s->lock); @@ -3588,6 +3588,17 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset, int64_t old_file_size, new_file_size; uint64_t nb_new_data_clusters, nb_new_l2_tables; + /* With a data file, preallocation means just allocating the metadata + * and forwarding the truncate request to the data file */ + if (has_data_file(bs)) { + ret = preallocate_co(bs, old_length, offset); + if (ret < 0) { + error_setg_errno(errp, -ret, "Preallocation failed"); + goto fail; + } + break; + } + old_file_size = bdrv_getlength(bs->file->bs); if (old_file_size < 0) { error_setg_errno(errp, -old_file_size, @@ -3696,6 +3707,16 @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset, bs->total_sectors = offset / BDRV_SECTOR_SIZE; + if (has_data_file(bs)) { + if (prealloc == PREALLOC_MODE_METADATA) { + prealloc = PREALLOC_MODE_OFF; + } + ret = bdrv_co_truncate(s->data_file, offset, prealloc, errp); + if (ret < 0) { + goto fail; + } + } + /* write updated header.size */ offset = cpu_to_be64(offset); ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, size), @@ -3898,6 +3919,10 @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset, uint8_t *buf, *out_buf; uint64_t cluster_offset; + if (has_data_file(bs)) { + return -ENOTSUP; + } + if (bytes == 0) { /* align end of file to a sector boundary to ease reading with sector based I/Os */ @@ -3949,7 +3974,7 @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset, goto fail; } - ret = qcow2_pre_write_overlap_check(bs, 0, cluster_offset, out_len); + ret = qcow2_pre_write_overlap_check(bs, 0, cluster_offset, out_len, true); qemu_co_mutex_unlock(&s->lock); if (ret < 0) { goto fail; @@ -3957,8 +3982,8 @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset, qemu_iovec_init_buf(&hd_qiov, out_buf, out_len); - BLKDBG_EVENT(bs->file, BLKDBG_WRITE_COMPRESSED); - ret = bdrv_co_pwritev(bs->file, cluster_offset, out_len, &hd_qiov, 0); + BLKDBG_EVENT(s->data_file, BLKDBG_WRITE_COMPRESSED); + ret = bdrv_co_pwritev(s->data_file, cluster_offset, out_len, &hd_qiov, 0); if (ret < 0) { goto fail; } @@ -4547,6 +4572,11 @@ static int qcow2_downgrade(BlockDriverState *bs, int target_version, return -ENOTSUP; } + if (has_data_file(bs)) { + error_setg(errp, "Cannot downgrade an image with a data file"); + return -ENOTSUP; + } + /* clear incompatible features */ if (s->incompatible_features & QCOW2_INCOMPAT_DIRTY) { ret = qcow2_mark_clean(bs); diff --git a/block/qcow2.h b/block/qcow2.h index fad6abf602..aac7fc4348 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -622,7 +622,7 @@ void qcow2_process_discards(BlockDriverState *bs, int ret); int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset, int64_t size); int qcow2_pre_write_overlap_check(BlockDriverState *bs, int ign, int64_t offset, - int64_t size); + int64_t size, bool data_file); int qcow2_inc_refcounts_imrt(BlockDriverState *bs, BdrvCheckResult *res, void **refcount_table, int64_t *refcount_table_size, From aa8b34c1b21b8a977de0293cfba9fb91ed14350d Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Wed, 27 Feb 2019 17:25:08 +0100 Subject: [PATCH 22/33] qcow2: Return error for snapshot operation with data file Internal snapshots and an external data file are incompatible because snapshots require refcounting and non-linear mapping. Return an error for all of the snapshot operations if an external data file is in use. Signed-off-by: Kevin Wolf --- block/qcow2-snapshot.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c index 5ae3407f68..a6ffae89a6 100644 --- a/block/qcow2-snapshot.c +++ b/block/qcow2-snapshot.c @@ -353,6 +353,10 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) return -EFBIG; } + if (has_data_file(bs)) { + return -ENOTSUP; + } + memset(sn, 0, sizeof(*sn)); /* Generate an ID */ @@ -466,6 +470,10 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id) int ret; uint64_t *sn_l1_table = NULL; + if (has_data_file(bs)) { + return -ENOTSUP; + } + /* Search the snapshot */ snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id); if (snapshot_index < 0) { @@ -599,6 +607,10 @@ int qcow2_snapshot_delete(BlockDriverState *bs, QCowSnapshot sn; int snapshot_index, ret; + if (has_data_file(bs)) { + return -ENOTSUP; + } + /* Search the snapshot */ snapshot_index = find_snapshot_by_id_and_name(bs, snapshot_id, name); if (snapshot_index < 0) { @@ -670,6 +682,9 @@ int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab) QCowSnapshot *sn; int i; + if (has_data_file(bs)) { + return -ENOTSUP; + } if (!s->nb_snapshots) { *psn_tab = NULL; return s->nb_snapshots; From e9f5b6deaa865e5265327de42b77553840c94880 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Wed, 27 Feb 2019 17:26:40 +0100 Subject: [PATCH 23/33] qcow2: Support external data file in qemu-img check For external data files, data clusters must be excluded from the refcount calculations. Instead, an implicit refcount of 1 is assumed for the COPIED flag. Compressed clusters and internal snapshots are incompatible with external data files, so print an error if they are in use for images with an external data file. Signed-off-by: Kevin Wolf --- block/qcow2-refcount.c | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index df73580e5d..e0fe322500 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -1605,6 +1605,13 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res, res->corruptions++; } + if (has_data_file(bs)) { + fprintf(stderr, "ERROR compressed cluster %d with data file, " + "entry=0x%" PRIx64 "\n", i, l2_entry); + res->corruptions++; + break; + } + /* Mark cluster as used */ nb_csectors = ((l2_entry >> s->csize_shift) & s->csize_mask) + 1; @@ -1695,11 +1702,13 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res, } /* Mark cluster as used */ - ret = qcow2_inc_refcounts_imrt(bs, res, - refcount_table, refcount_table_size, - offset, s->cluster_size); - if (ret < 0) { - goto fail; + if (!has_data_file(bs)) { + ret = qcow2_inc_refcounts_imrt(bs, res, refcount_table, + refcount_table_size, + offset, s->cluster_size); + if (ret < 0) { + goto fail; + } } break; } @@ -1884,12 +1893,16 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res, if (cluster_type == QCOW2_CLUSTER_NORMAL || cluster_type == QCOW2_CLUSTER_ZERO_ALLOC) { - ret = qcow2_get_refcount(bs, - data_offset >> s->cluster_bits, - &refcount); - if (ret < 0) { - /* don't print message nor increment check_errors */ - continue; + if (has_data_file(bs)) { + refcount = 1; + } else { + ret = qcow2_get_refcount(bs, + data_offset >> s->cluster_bits, + &refcount); + if (ret < 0) { + /* don't print message nor increment check_errors */ + continue; + } } if ((refcount == 1) != ((l2_entry & QCOW_OFLAG_COPIED) != 0)) { fprintf(stderr, "%s OFLAG_COPIED data cluster: " @@ -2083,6 +2096,12 @@ static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res, } /* snapshots */ + if (has_data_file(bs) && s->nb_snapshots) { + fprintf(stderr, "ERROR %d snapshots in image with data file\n", + s->nb_snapshots); + res->corruptions++; + } + for (i = 0; i < s->nb_snapshots; i++) { sn = s->snapshots + i; if (offset_into_cluster(s, sn->l1_table_offset)) { From 0e8c08be276637a7339a05a4646b6eb8428ee802 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 29 Jan 2019 17:13:57 +0100 Subject: [PATCH 24/33] qcow2: Add basic data-file infrastructure This adds a .bdrv_open option to specify the external data file node. Signed-off-by: Kevin Wolf --- block/qcow2.c | 34 ++++++++++++++++++++++++++++++++-- block/qcow2.h | 4 +++- qapi/block-core.json | 7 ++++++- 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index f048763e10..ddbf8731bd 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1453,8 +1453,31 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, goto fail; } - /* TODO Open external data file */ - s->data_file = bs->file; + /* Open external data file */ + s->data_file = bdrv_open_child(NULL, options, "data-file", bs, &child_file, + true, &local_err); + if (local_err) { + error_propagate(errp, local_err); + ret = -EINVAL; + goto fail; + } + + if (s->incompatible_features & QCOW2_INCOMPAT_DATA_FILE) { + if (!s->data_file) { + error_setg(errp, "'data-file' is required for this image"); + ret = -EINVAL; + goto fail; + } + } else { + if (s->data_file) { + error_setg(errp, "'data-file' can only be set for images with an " + "external data file"); + ret = -EINVAL; + goto fail; + } else { + s->data_file = bs->file; + } + } /* qcow2_read_extension may have set up the crypto context * if the crypt method needs a header region, some methods @@ -1627,6 +1650,9 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, return ret; fail: + if (has_data_file(bs)) { + bdrv_unref_child(bs, s->data_file); + } g_free(s->unknown_header_fields); cleanup_unknown_header_ext(bs); qcow2_free_snapshots(bs); @@ -2246,6 +2272,10 @@ static void qcow2_close(BlockDriverState *bs) g_free(s->image_backing_file); g_free(s->image_backing_format); + if (has_data_file(bs)) { + bdrv_unref_child(bs, s->data_file); + } + qcow2_refcount_close(bs); qcow2_free_snapshots(bs); } diff --git a/block/qcow2.h b/block/qcow2.h index aac7fc4348..f23c003a46 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -91,6 +91,7 @@ #define DEFAULT_CLUSTER_SIZE 65536 +#define QCOW2_OPT_DATA_FILE "data-file" #define QCOW2_OPT_LAZY_REFCOUNTS "lazy-refcounts" #define QCOW2_OPT_DISCARD_REQUEST "pass-discard-request" #define QCOW2_OPT_DISCARD_SNAPSHOT "pass-discard-snapshot" @@ -205,7 +206,8 @@ enum { QCOW2_INCOMPAT_DATA_FILE = 1 << QCOW2_INCOMPAT_DATA_FILE_BITNR, QCOW2_INCOMPAT_MASK = QCOW2_INCOMPAT_DIRTY - | QCOW2_INCOMPAT_CORRUPT, + | QCOW2_INCOMPAT_CORRUPT + | QCOW2_INCOMPAT_DATA_FILE, }; /* Compatible feature bits */ diff --git a/qapi/block-core.json b/qapi/block-core.json index 2b8afbb924..de4d4fd0e4 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -3080,6 +3080,10 @@ # encrypted images, except when doing a metadata-only # probe of the image. (since 2.10) # +# @data-file: reference to or definition of the external data file. +# This may only be specified for images that require an +# external data file. (since 4.0) +# # Since: 2.9 ## { 'struct': 'BlockdevOptionsQcow2', @@ -3094,7 +3098,8 @@ '*l2-cache-entry-size': 'int', '*refcount-cache-size': 'int', '*cache-clean-interval': 'int', - '*encrypt': 'BlockdevQcow2Encryption' } } + '*encrypt': 'BlockdevQcow2Encryption', + '*data-file': 'BlockdevRef' } } ## # @SshHostKeyCheckMode: From dcc98687f82b8a8d58d0eb7bc15c95d28f35708f Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Mon, 14 Jan 2019 16:57:27 +0100 Subject: [PATCH 25/33] qcow2: Creating images with external data file This adds a .bdrv_create option to use an external data file. Signed-off-by: Kevin Wolf --- block/qcow2.c | 26 ++++++++++++++++++++++++++ include/block/block_int.h | 1 + qapi/block-core.json | 4 ++++ 3 files changed, 31 insertions(+) diff --git a/block/qcow2.c b/block/qcow2.c index ddbf8731bd..c20141b4e7 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -2880,6 +2880,7 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) */ BlockBackend *blk = NULL; BlockDriverState *bs = NULL; + BlockDriverState *data_bs = NULL; QCowHeader *header; size_t cluster_size; int version; @@ -2976,6 +2977,20 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) } refcount_order = ctz32(qcow2_opts->refcount_bits); + if (qcow2_opts->data_file) { + if (version < 3) { + error_setg(errp, "External data files are only supported with " + "compatibility level 1.1 and above (use version=v3 or " + "greater)"); + ret = -EINVAL; + goto out; + } + data_bs = bdrv_open_blockdev_ref(qcow2_opts->data_file, errp); + if (bs == NULL) { + ret = -EIO; + goto out; + } + } /* Create BlockBackend to write to the image */ blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL); @@ -3014,6 +3029,10 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) header->compatible_features |= cpu_to_be64(QCOW2_COMPAT_LAZY_REFCOUNTS); } + if (data_bs) { + header->incompatible_features |= + cpu_to_be64(QCOW2_INCOMPAT_DATA_FILE); + } ret = blk_pwrite(blk, 0, header, cluster_size, 0); g_free(header); @@ -3044,6 +3063,9 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) options = qdict_new(); qdict_put_str(options, "driver", "qcow2"); qdict_put_str(options, "file", bs->node_name); + if (data_bs) { + qdict_put_str(options, "data-file", data_bs->node_name); + } blk = blk_new_open(NULL, NULL, options, BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_NO_FLUSH, &local_err); @@ -3116,6 +3138,9 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) options = qdict_new(); qdict_put_str(options, "driver", "qcow2"); qdict_put_str(options, "file", bs->node_name); + if (data_bs) { + qdict_put_str(options, "data-file", data_bs->node_name); + } blk = blk_new_open(NULL, NULL, options, BDRV_O_RDWR | BDRV_O_NO_BACKING | BDRV_O_NO_IO, &local_err); @@ -3129,6 +3154,7 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) out: blk_unref(blk); bdrv_unref(bs); + bdrv_unref(data_bs); return ret; } diff --git a/include/block/block_int.h b/include/block/block_int.h index 836d67c1ae..acd29ce521 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -56,6 +56,7 @@ #define BLOCK_OPT_NOCOW "nocow" #define BLOCK_OPT_OBJECT_SIZE "object_size" #define BLOCK_OPT_REFCOUNT_BITS "refcount_bits" +#define BLOCK_OPT_DATA_FILE "data_file" #define BLOCK_PROBE_BUF_SIZE 512 diff --git a/qapi/block-core.json b/qapi/block-core.json index de4d4fd0e4..2303266bc4 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -4135,6 +4135,9 @@ # Driver specific image creation options for qcow2. # # @file Node to create the image format on +# @data-file Node to use as an external data file in which all guest +# data is stored so that only metadata remains in the qcow2 +# file (since: 4.0) # @size Size of the virtual disk in bytes # @version Compatibility level (default: v3) # @backing-file File name of the backing file if a backing file @@ -4150,6 +4153,7 @@ ## { 'struct': 'BlockdevCreateOptionsQcow2', 'data': { 'file': 'BlockdevRef', + '*data-file': 'BlockdevRef', 'size': 'size', '*version': 'BlockdevQcow2Version', '*backing-file': 'str', From 9b890bdcb6ec11868da92c1daeb51c69d9483da8 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 15 Jan 2019 19:02:40 +0100 Subject: [PATCH 26/33] qcow2: Store data file name in the image Rather than requiring that the external data file node is passed explicitly when creating the qcow2 node, store the filename in the designated header extension during .bdrv_create and read it from there as a default during .bdrv_open. Signed-off-by: Kevin Wolf --- block/qcow2.c | 94 +++++++++++++++++++++++++++++++++++++- block/qcow2.h | 1 + qapi/block-core.json | 8 +++- tests/qemu-iotests/082.out | 27 +++++++++++ 4 files changed, 128 insertions(+), 2 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index c20141b4e7..f32ddda2a7 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -398,6 +398,21 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset, #endif break; + case QCOW2_EXT_MAGIC_DATA_FILE: + { + s->image_data_file = g_malloc0(ext.len + 1); + ret = bdrv_pread(bs->file, offset, s->image_data_file, ext.len); + if (ret < 0) { + error_setg_errno(errp, -ret, + "ERROR: Could not read data file name"); + return ret; + } +#ifdef DEBUG_EXT + printf("Qcow2: Got external data file %s\n", s->image_data_file); +#endif + break; + } + default: /* unknown magic - save it in case we need to rewrite the header */ /* If you add a new feature, make sure to also update the fast @@ -1463,6 +1478,15 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, } if (s->incompatible_features & QCOW2_INCOMPAT_DATA_FILE) { + if (!s->data_file && s->image_data_file) { + s->data_file = bdrv_open_child(s->image_data_file, options, + "data-file", bs, &child_file, + false, errp); + if (!s->data_file) { + ret = -EINVAL; + goto fail; + } + } if (!s->data_file) { error_setg(errp, "'data-file' is required for this image"); ret = -EINVAL; @@ -1650,6 +1674,7 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, return ret; fail: + g_free(s->image_data_file); if (has_data_file(bs)) { bdrv_unref_child(bs, s->data_file); } @@ -2269,6 +2294,7 @@ static void qcow2_close(BlockDriverState *bs) g_free(s->unknown_header_fields); cleanup_unknown_header_ext(bs); + g_free(s->image_data_file); g_free(s->image_backing_file); g_free(s->image_backing_format); @@ -2445,6 +2471,19 @@ int qcow2_update_header(BlockDriverState *bs) buflen -= ret; } + /* External data file header extension */ + if (has_data_file(bs) && s->image_data_file) { + ret = header_ext_add(buf, QCOW2_EXT_MAGIC_DATA_FILE, + s->image_data_file, strlen(s->image_data_file), + buflen); + if (ret < 0) { + goto fail; + } + + buf += ret; + buflen -= ret; + } + /* Full disk encryption header pointer extension */ if (s->crypto_header.offset != 0) { s->crypto_header.offset = cpu_to_be64(s->crypto_header.offset); @@ -3086,6 +3125,12 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) abort(); } + /* Set the external data file if necessary */ + if (data_bs) { + BDRVQcow2State *s = blk_bs(blk)->opaque; + s->image_data_file = g_strdup(data_bs->filename); + } + /* Create a full header (including things like feature table) */ ret = qcow2_update_header(blk_bs(blk)); if (ret < 0) { @@ -3165,6 +3210,7 @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt QDict *qdict; Visitor *v; BlockDriverState *bs = NULL; + BlockDriverState *data_bs = NULL; Error *local_err = NULL; const char *val; int ret; @@ -3228,6 +3274,26 @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt goto finish; } + /* Create and open an external data file (protocol layer) */ + val = qdict_get_try_str(qdict, BLOCK_OPT_DATA_FILE); + if (val) { + ret = bdrv_create_file(val, opts, errp); + if (ret < 0) { + goto finish; + } + + data_bs = bdrv_open(val, NULL, NULL, + BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, + errp); + if (data_bs == NULL) { + ret = -EIO; + goto finish; + } + + qdict_del(qdict, BLOCK_OPT_DATA_FILE); + qdict_put_str(qdict, "data-file", data_bs->node_name); + } + /* Set 'driver' and 'node' options */ qdict_put_str(qdict, "driver", "qcow2"); qdict_put_str(qdict, "file", bs->node_name); @@ -3262,6 +3328,7 @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt finish: qobject_unref(qdict); bdrv_unref(bs); + bdrv_unref(data_bs); qapi_free_BlockdevCreateOptions(create_options); return ret; } @@ -4552,6 +4619,8 @@ static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs, .refcount_bits = s->refcount_bits, .has_bitmaps = !!bitmaps, .bitmaps = bitmaps, + .has_data_file = !!s->image_data_file, + .data_file = g_strdup(s->image_data_file), }; } else { /* if this assertion fails, this probably means a new version was @@ -4754,7 +4823,7 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, BDRVQcow2State *s = bs->opaque; int old_version = s->qcow_version, new_version = old_version; uint64_t new_size = 0; - const char *backing_file = NULL, *backing_format = NULL; + const char *backing_file = NULL, *backing_format = NULL, *data_file = NULL; bool lazy_refcounts = s->use_lazy_refcounts; const char *compat = NULL; uint64_t cluster_size = s->cluster_size; @@ -4836,6 +4905,13 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, "may not exceed 64 bits"); return -EINVAL; } + } else if (!strcmp(desc->name, BLOCK_OPT_DATA_FILE)) { + data_file = qemu_opt_get(opts, BLOCK_OPT_DATA_FILE); + if (data_file && !has_data_file(bs)) { + error_setg(errp, "data-file can only be set for images that " + "use an external data file"); + return -EINVAL; + } } else { /* if this point is reached, this probably means a new option was * added without having it covered here */ @@ -4882,6 +4958,17 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, } } + if (data_file) { + g_free(s->image_data_file); + s->image_data_file = *data_file ? g_strdup(data_file) : NULL; + } + + ret = qcow2_update_header(bs); + if (ret < 0) { + error_setg_errno(errp, -ret, "Failed to update the image header"); + return ret; + } + if (backing_file || backing_format) { ret = qcow2_change_backing_file(bs, backing_file ?: s->image_backing_file, @@ -5029,6 +5116,11 @@ static QemuOptsList qcow2_create_opts = { .type = QEMU_OPT_STRING, .help = "Image format of the base image" }, + { + .name = BLOCK_OPT_DATA_FILE, + .type = QEMU_OPT_STRING, + .help = "File name of an external data file" + }, { .name = BLOCK_OPT_ENCRYPT, .type = QEMU_OPT_BOOL, diff --git a/block/qcow2.h b/block/qcow2.h index f23c003a46..a9c9cb4a26 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -343,6 +343,7 @@ typedef struct BDRVQcow2State { * override) */ char *image_backing_file; char *image_backing_format; + char *image_data_file; CoQueue compress_wait_queue; int nb_compress_threads; diff --git a/qapi/block-core.json b/qapi/block-core.json index 2303266bc4..e6faa94fa2 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -59,6 +59,9 @@ # # @compat: compatibility level # +# @data-file: the filename of the external data file that is stored in the +# image and used as a default for opening the image (since: 4.0) +# # @lazy-refcounts: on or off; only valid for compat >= 1.1 # # @corrupt: true if the image has been marked corrupt; only valid for @@ -76,6 +79,7 @@ { 'struct': 'ImageInfoSpecificQCow2', 'data': { 'compat': 'str', + '*data-file': 'str', '*lazy-refcounts': 'bool', '*corrupt': 'bool', 'refcount-bits': 'int', @@ -3082,7 +3086,9 @@ # # @data-file: reference to or definition of the external data file. # This may only be specified for images that require an -# external data file. (since 4.0) +# external data file. If it is not specified for such +# an image, the data file name is loaded from the image +# file. (since 4.0) # # Since: 2.9 ## diff --git a/tests/qemu-iotests/082.out b/tests/qemu-iotests/082.out index 0ce18c075b..7dc59f6075 100644 --- a/tests/qemu-iotests/082.out +++ b/tests/qemu-iotests/082.out @@ -48,6 +48,7 @@ Supported options: backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) + data_file= - File name of an external data file encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -69,6 +70,7 @@ Supported options: backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) + data_file= - File name of an external data file encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -90,6 +92,7 @@ Supported options: backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) + data_file= - File name of an external data file encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -111,6 +114,7 @@ Supported options: backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) + data_file= - File name of an external data file encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -132,6 +136,7 @@ Supported options: backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) + data_file= - File name of an external data file encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -153,6 +158,7 @@ Supported options: backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) + data_file= - File name of an external data file encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -174,6 +180,7 @@ Supported options: backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) + data_file= - File name of an external data file encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -195,6 +202,7 @@ Supported options: backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) + data_file= - File name of an external data file encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -231,6 +239,7 @@ Supported options: backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) + data_file= - File name of an external data file encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -304,6 +313,7 @@ Supported options: backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) + data_file= - File name of an external data file encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -325,6 +335,7 @@ Supported options: backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) + data_file= - File name of an external data file encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -346,6 +357,7 @@ Supported options: backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) + data_file= - File name of an external data file encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -367,6 +379,7 @@ Supported options: backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) + data_file= - File name of an external data file encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -388,6 +401,7 @@ Supported options: backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) + data_file= - File name of an external data file encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -409,6 +423,7 @@ Supported options: backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) + data_file= - File name of an external data file encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -430,6 +445,7 @@ Supported options: backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) + data_file= - File name of an external data file encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -451,6 +467,7 @@ Supported options: backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) + data_file= - File name of an external data file encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -487,6 +504,7 @@ Supported options: backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) + data_file= - File name of an external data file encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -568,6 +586,7 @@ Creation options for 'qcow2': backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) + data_file= - File name of an external data file encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -590,6 +609,7 @@ Creation options for 'qcow2': backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) + data_file= - File name of an external data file encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -612,6 +632,7 @@ Creation options for 'qcow2': backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) + data_file= - File name of an external data file encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -634,6 +655,7 @@ Creation options for 'qcow2': backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) + data_file= - File name of an external data file encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -656,6 +678,7 @@ Creation options for 'qcow2': backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) + data_file= - File name of an external data file encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -678,6 +701,7 @@ Creation options for 'qcow2': backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) + data_file= - File name of an external data file encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -700,6 +724,7 @@ Creation options for 'qcow2': backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) + data_file= - File name of an external data file encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -722,6 +747,7 @@ Creation options for 'qcow2': backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) + data_file= - File name of an external data file encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -761,6 +787,7 @@ Creation options for 'qcow2': backing_fmt= - Image format of the base image cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) + data_file= - File name of an external data file encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' From 6c3944dc6219cefef6a968cf300d227fe3f92388 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 22 Feb 2019 14:29:38 +0100 Subject: [PATCH 27/33] qcow2: Implement data-file-raw create option Provide an option to force QEMU to always keep the external data file consistent as a standalone read-only raw image. At the moment, this means making sure that write_zeroes requests are forwarded to the data file instead of just updating the metadata, and checking that no backing file is used. Signed-off-by: Kevin Wolf --- block/qcow2-cluster.c | 10 +++++++ block/qcow2.c | 56 ++++++++++++++++++++++++++++++++++++-- block/qcow2.h | 9 +++++- include/block/block_int.h | 1 + qapi/block-core.json | 9 ++++++ tests/qemu-iotests/082.out | 27 ++++++++++++++++++ 6 files changed, 109 insertions(+), 3 deletions(-) diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 7579f5a5ae..974a4e8656 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -1783,6 +1783,16 @@ int qcow2_cluster_zeroize(BlockDriverState *bs, uint64_t offset, int64_t cleared; int ret; + /* If we have to stay in sync with an external data file, zero out + * s->data_file first. */ + if (data_file_is_raw(bs)) { + assert(has_data_file(bs)); + ret = bdrv_co_pwrite_zeroes(s->data_file, offset, bytes, flags); + if (ret < 0) { + return ret; + } + } + /* Caller must pass aligned values, except at image end */ assert(QEMU_IS_ALIGNED(offset, s->cluster_size)); assert(QEMU_IS_ALIGNED(end_offset, s->cluster_size) || diff --git a/block/qcow2.c b/block/qcow2.c index f32ddda2a7..c4dd876fb4 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1498,8 +1498,14 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, "external data file"); ret = -EINVAL; goto fail; - } else { - s->data_file = bs->file; + } + + s->data_file = bs->file; + + if (data_file_is_raw(bs)) { + error_setg(errp, "data-file-raw requires a data file"); + ret = -EINVAL; + goto fail; } } @@ -2606,6 +2612,12 @@ static int qcow2_change_backing_file(BlockDriverState *bs, { BDRVQcow2State *s = bs->opaque; + /* Adding a backing file means that the external data file alone won't be + * enough to make sense of the content */ + if (backing_file && data_file_is_raw(bs)) { + return -EINVAL; + } + if (backing_file && strlen(backing_file) > 1023) { return -EINVAL; } @@ -3016,6 +3028,18 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) } refcount_order = ctz32(qcow2_opts->refcount_bits); + if (qcow2_opts->data_file_raw && !qcow2_opts->data_file) { + error_setg(errp, "data-file-raw requires data-file"); + ret = -EINVAL; + goto out; + } + if (qcow2_opts->data_file_raw && qcow2_opts->has_backing_file) { + error_setg(errp, "Backing file and data-file-raw cannot be used at " + "the same time"); + ret = -EINVAL; + goto out; + } + if (qcow2_opts->data_file) { if (version < 3) { error_setg(errp, "External data files are only supported with " @@ -3072,6 +3096,10 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) header->incompatible_features |= cpu_to_be64(QCOW2_INCOMPAT_DATA_FILE); } + if (qcow2_opts->data_file_raw) { + header->autoclear_features |= + cpu_to_be64(QCOW2_AUTOCLEAR_DATA_FILE_RAW); + } ret = blk_pwrite(blk, 0, header, cluster_size, 0); g_free(header); @@ -3253,6 +3281,7 @@ static int coroutine_fn qcow2_co_create_opts(const char *filename, QemuOpts *opt { BLOCK_OPT_REFCOUNT_BITS, "refcount-bits" }, { BLOCK_OPT_ENCRYPT, BLOCK_OPT_ENCRYPT_FORMAT }, { BLOCK_OPT_COMPAT_LEVEL, "version" }, + { BLOCK_OPT_DATA_FILE_RAW, "data-file-raw" }, { NULL, NULL }, }; @@ -4621,6 +4650,8 @@ static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs, .bitmaps = bitmaps, .has_data_file = !!s->image_data_file, .data_file = g_strdup(s->image_data_file), + .has_data_file_raw = has_data_file(bs), + .data_file_raw = data_file_is_raw(bs), }; } else { /* if this assertion fails, this probably means a new version was @@ -4825,6 +4856,7 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, uint64_t new_size = 0; const char *backing_file = NULL, *backing_format = NULL, *data_file = NULL; bool lazy_refcounts = s->use_lazy_refcounts; + bool data_file_raw = data_file_is_raw(bs); const char *compat = NULL; uint64_t cluster_size = s->cluster_size; bool encrypt; @@ -4912,6 +4944,14 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, "use an external data file"); return -EINVAL; } + } else if (!strcmp(desc->name, BLOCK_OPT_DATA_FILE_RAW)) { + data_file_raw = qemu_opt_get_bool(opts, BLOCK_OPT_DATA_FILE_RAW, + data_file_raw); + if (data_file_raw && !data_file_is_raw(bs)) { + error_setg(errp, "data-file-raw cannot be set on existing " + "images"); + return -EINVAL; + } } else { /* if this point is reached, this probably means a new option was * added without having it covered here */ @@ -4958,6 +4998,13 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, } } + /* data-file-raw blocks backing files, so clear it first if requested */ + if (data_file_raw) { + s->autoclear_features |= QCOW2_AUTOCLEAR_DATA_FILE_RAW; + } else { + s->autoclear_features &= ~QCOW2_AUTOCLEAR_DATA_FILE_RAW; + } + if (data_file) { g_free(s->image_data_file); s->image_data_file = *data_file ? g_strdup(data_file) : NULL; @@ -5121,6 +5168,11 @@ static QemuOptsList qcow2_create_opts = { .type = QEMU_OPT_STRING, .help = "File name of an external data file" }, + { + .name = BLOCK_OPT_DATA_FILE_RAW, + .type = QEMU_OPT_BOOL, + .help = "The external data file must stay valid as a raw image" + }, { .name = BLOCK_OPT_ENCRYPT, .type = QEMU_OPT_BOOL, diff --git a/block/qcow2.h b/block/qcow2.h index a9c9cb4a26..de2a3bdfc5 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -225,7 +225,8 @@ enum { QCOW2_AUTOCLEAR_BITMAPS = 1 << QCOW2_AUTOCLEAR_BITMAPS_BITNR, QCOW2_AUTOCLEAR_DATA_FILE_RAW = 1 << QCOW2_AUTOCLEAR_DATA_FILE_RAW_BITNR, - QCOW2_AUTOCLEAR_MASK = QCOW2_AUTOCLEAR_BITMAPS, + QCOW2_AUTOCLEAR_MASK = QCOW2_AUTOCLEAR_BITMAPS + | QCOW2_AUTOCLEAR_DATA_FILE_RAW, }; enum qcow2_discard_type { @@ -474,6 +475,12 @@ static inline bool has_data_file(BlockDriverState *bs) return (s->data_file != bs->file); } +static inline bool data_file_is_raw(BlockDriverState *bs) +{ + BDRVQcow2State *s = bs->opaque; + return !!(s->autoclear_features & QCOW2_AUTOCLEAR_DATA_FILE_RAW); +} + static inline int64_t start_of_cluster(BDRVQcow2State *s, int64_t offset) { return offset & ~(s->cluster_size - 1); diff --git a/include/block/block_int.h b/include/block/block_int.h index acd29ce521..a23cabaddd 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -57,6 +57,7 @@ #define BLOCK_OPT_OBJECT_SIZE "object_size" #define BLOCK_OPT_REFCOUNT_BITS "refcount_bits" #define BLOCK_OPT_DATA_FILE "data_file" +#define BLOCK_OPT_DATA_FILE_RAW "data_file_raw" #define BLOCK_PROBE_BUF_SIZE 512 diff --git a/qapi/block-core.json b/qapi/block-core.json index e6faa94fa2..919d0530b2 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -62,6 +62,10 @@ # @data-file: the filename of the external data file that is stored in the # image and used as a default for opening the image (since: 4.0) # +# @data-file-raw: True if the external data file must stay valid as a +# standalone (read-only) raw image without looking at qcow2 +# metadata (since: 4.0) +# # @lazy-refcounts: on or off; only valid for compat >= 1.1 # # @corrupt: true if the image has been marked corrupt; only valid for @@ -80,6 +84,7 @@ 'data': { 'compat': 'str', '*data-file': 'str', + '*data-file-raw': 'bool', '*lazy-refcounts': 'bool', '*corrupt': 'bool', 'refcount-bits': 'int', @@ -4144,6 +4149,9 @@ # @data-file Node to use as an external data file in which all guest # data is stored so that only metadata remains in the qcow2 # file (since: 4.0) +# @data-file-raw True if the external data file must stay valid as a +# standalone (read-only) raw image without looking at qcow2 +# metadata (default: false; since: 4.0) # @size Size of the virtual disk in bytes # @version Compatibility level (default: v3) # @backing-file File name of the backing file if a backing file @@ -4160,6 +4168,7 @@ { 'struct': 'BlockdevCreateOptionsQcow2', 'data': { 'file': 'BlockdevRef', '*data-file': 'BlockdevRef', + '*data-file-raw': 'bool', 'size': 'size', '*version': 'BlockdevQcow2Version', '*backing-file': 'str', diff --git a/tests/qemu-iotests/082.out b/tests/qemu-iotests/082.out index 7dc59f6075..915640613f 100644 --- a/tests/qemu-iotests/082.out +++ b/tests/qemu-iotests/082.out @@ -49,6 +49,7 @@ Supported options: cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) data_file= - File name of an external data file + data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -71,6 +72,7 @@ Supported options: cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) data_file= - File name of an external data file + data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -93,6 +95,7 @@ Supported options: cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) data_file= - File name of an external data file + data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -115,6 +118,7 @@ Supported options: cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) data_file= - File name of an external data file + data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -137,6 +141,7 @@ Supported options: cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) data_file= - File name of an external data file + data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -159,6 +164,7 @@ Supported options: cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) data_file= - File name of an external data file + data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -181,6 +187,7 @@ Supported options: cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) data_file= - File name of an external data file + data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -203,6 +210,7 @@ Supported options: cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) data_file= - File name of an external data file + data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -240,6 +248,7 @@ Supported options: cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) data_file= - File name of an external data file + data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -314,6 +323,7 @@ Supported options: cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) data_file= - File name of an external data file + data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -336,6 +346,7 @@ Supported options: cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) data_file= - File name of an external data file + data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -358,6 +369,7 @@ Supported options: cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) data_file= - File name of an external data file + data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -380,6 +392,7 @@ Supported options: cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) data_file= - File name of an external data file + data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -402,6 +415,7 @@ Supported options: cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) data_file= - File name of an external data file + data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -424,6 +438,7 @@ Supported options: cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) data_file= - File name of an external data file + data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -446,6 +461,7 @@ Supported options: cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) data_file= - File name of an external data file + data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -468,6 +484,7 @@ Supported options: cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) data_file= - File name of an external data file + data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -505,6 +522,7 @@ Supported options: cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) data_file= - File name of an external data file + data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -587,6 +605,7 @@ Creation options for 'qcow2': cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) data_file= - File name of an external data file + data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -610,6 +629,7 @@ Creation options for 'qcow2': cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) data_file= - File name of an external data file + data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -633,6 +653,7 @@ Creation options for 'qcow2': cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) data_file= - File name of an external data file + data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -656,6 +677,7 @@ Creation options for 'qcow2': cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) data_file= - File name of an external data file + data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -679,6 +701,7 @@ Creation options for 'qcow2': cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) data_file= - File name of an external data file + data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -702,6 +725,7 @@ Creation options for 'qcow2': cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) data_file= - File name of an external data file + data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -725,6 +749,7 @@ Creation options for 'qcow2': cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) data_file= - File name of an external data file + data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -748,6 +773,7 @@ Creation options for 'qcow2': cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) data_file= - File name of an external data file + data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' @@ -788,6 +814,7 @@ Creation options for 'qcow2': cluster_size= - qcow2 cluster size compat= - Compatibility level (0.10 or 1.1) data_file= - File name of an external data file + data_file_raw= - The external data file must stay valid as a raw image encrypt.cipher-alg= - Name of encryption cipher algorithm encrypt.cipher-mode= - Name of encryption cipher mode encrypt.format= - Encrypt the image, format choices: 'aes', 'luks' From c35896c5e85d783a7248ef5cb12a9a82dbb7d5d6 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 21 Feb 2019 16:35:52 +0100 Subject: [PATCH 28/33] qemu-iotests: Preallocation with external data file Test that preallocating metadata results in a somewhat larger qcow2 file, but preallocating data only affects the disk usage of the data file and the qcow2 file stays small. Signed-off-by: Kevin Wolf --- tests/qemu-iotests/243 | 22 ++++++++++++++++++++++ tests/qemu-iotests/243.out | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/tests/qemu-iotests/243 b/tests/qemu-iotests/243 index 6a19919add..5838c6e89c 100755 --- a/tests/qemu-iotests/243 +++ b/tests/qemu-iotests/243 @@ -29,6 +29,7 @@ status=1 # failure is the default! _cleanup() { _cleanup_test_img + rm -f $TEST_IMG.data } trap "_cleanup; exit \$status" 0 1 2 3 15 @@ -57,6 +58,27 @@ for mode in off metadata falloc full; do done +for mode in off metadata falloc full; do + + echo + echo "=== External data file: preallocation=$mode ===" + echo + + IMGOPTS="data_file=$TEST_IMG.data,preallocation=$mode" _make_test_img 64M + + echo -n "qcow2 file size: " + du -b $TEST_IMG | cut -f1 + echo -n "data file size: " + du -b $TEST_IMG.data | cut -f1 + + # Can't use precise numbers here because they differ between filesystems + echo -n "qcow2 disk usage: " + [ $(du -B1 $TEST_IMG | cut -f1) -lt 1048576 ] && echo "low" || echo "high" + echo -n "data disk usage: " + [ $(du -B1 $TEST_IMG.data | cut -f1) -lt 1048576 ] && echo "low" || echo "high" + +done + # success, all done echo "*** done" rm -f $seq.full diff --git a/tests/qemu-iotests/243.out b/tests/qemu-iotests/243.out index e531753ad1..dcb33fac32 100644 --- a/tests/qemu-iotests/243.out +++ b/tests/qemu-iotests/243.out @@ -23,4 +23,36 @@ Disk usage: high Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 preallocation=full File size: 67436544 Disk usage: high + +=== External data file: preallocation=off === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data preallocation=off +qcow2 file size: 196616 +data file size: 67108864 +qcow2 disk usage: low +data disk usage: low + +=== External data file: preallocation=metadata === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data preallocation=metadata +qcow2 file size: 327680 +data file size: 67108864 +qcow2 disk usage: low +data disk usage: low + +=== External data file: preallocation=falloc === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data preallocation=falloc +qcow2 file size: 327680 +data file size: 67108864 +qcow2 disk usage: low +data disk usage: high + +=== External data file: preallocation=full === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data preallocation=full +qcow2 file size: 327680 +data file size: 67108864 +qcow2 disk usage: low +data disk usage: high *** done From 76b90e23e71ecdbfba1ea6bea88502bd9d1fd82f Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 22 Feb 2019 11:45:50 +0100 Subject: [PATCH 29/33] qemu-iotests: General tests for qcow2 with external data file Signed-off-by: Kevin Wolf --- tests/qemu-iotests/244 | 200 +++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/244.out | 125 +++++++++++++++++++++++ tests/qemu-iotests/group | 1 + 3 files changed, 326 insertions(+) create mode 100755 tests/qemu-iotests/244 create mode 100644 tests/qemu-iotests/244.out diff --git a/tests/qemu-iotests/244 b/tests/qemu-iotests/244 new file mode 100755 index 0000000000..d8e7122305 --- /dev/null +++ b/tests/qemu-iotests/244 @@ -0,0 +1,200 @@ +#!/bin/bash +# +# Test qcow2 with external data files +# +# Copyright (C) 2019 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 . +# + +# creator +owner=kwolf@redhat.com + +seq=$(basename $0) +echo "QA output created by $seq" + +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img + rm -f $TEST_IMG.data + rm -f $TEST_IMG.src +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_supported_fmt qcow2 +_supported_proto file +_supported_os Linux + +echo +echo "=== Create and open image with external data file ===" +echo + +echo "With data file name in the image:" +IMGOPTS="data_file=$TEST_IMG.data" _make_test_img 64M +_check_test_img + +$QEMU_IO -c "open $TEST_IMG" -c "read -P 0 0 64k" 2>&1 | _filter_qemu_io | _filter_testdir +$QEMU_IO -c "open -odata-file.filename=$TEST_IMG.data $TEST_IMG" -c "read -P 0 0 64k" 2>&1 | _filter_qemu_io | _filter_testdir +$QEMU_IO -c "open -odata-file.filename=inexistent $TEST_IMG" -c "read -P 0 0 64k" 2>&1 | _filter_qemu_io | _filter_testdir + +echo +echo "Data file required, but without data file name in the image:" +$QEMU_IMG amend -odata_file= $TEST_IMG + +$QEMU_IO -c "open $TEST_IMG" -c "read -P 0 0 64k" 2>&1 | _filter_qemu_io | _filter_testdir +$QEMU_IO -c "open -odata-file.filename=$TEST_IMG.data $TEST_IMG" -c "read -P 0 0 64k" 2>&1 | _filter_qemu_io | _filter_testdir +$QEMU_IO -c "open -odata-file.filename=inexistent $TEST_IMG" -c "read -P 0 0 64k" 2>&1 | _filter_qemu_io | _filter_testdir + +echo +echo "Setting data-file for an image with internal data:" +_make_test_img 64M + +$QEMU_IO -c "open -odata-file.filename=$TEST_IMG.data $TEST_IMG" -c "read -P 0 0 64k" 2>&1 | _filter_qemu_io | _filter_testdir +$QEMU_IO -c "open -odata-file.filename=inexistent $TEST_IMG" -c "read -P 0 0 64k" 2>&1 | _filter_qemu_io | _filter_testdir + +echo +echo "=== Conflicting features ===" +echo + +echo "Convert to compressed target with data file:" +TEST_IMG="$TEST_IMG.src" _make_test_img 64M + +$QEMU_IO -c 'write -P 0x11 0 1M' \ + -f $IMGFMT "$TEST_IMG.src" | + _filter_qemu_io + +$QEMU_IMG convert -f $IMGFMT -O $IMGFMT -c -odata_file="$TEST_IMG.data" \ + "$TEST_IMG.src" "$TEST_IMG" + +echo +echo "Convert uncompressed, then write compressed data manually:" +$QEMU_IMG convert -f $IMGFMT -O $IMGFMT -odata_file="$TEST_IMG.data" \ + "$TEST_IMG.src" "$TEST_IMG" +$QEMU_IMG compare "$TEST_IMG.src" "$TEST_IMG" + +$QEMU_IO -c 'write -c -P 0x22 0 1M' \ + -f $IMGFMT "$TEST_IMG" | + _filter_qemu_io +_check_test_img + +echo +echo "Take an internal snapshot:" + +$QEMU_IMG snapshot -c test "$TEST_IMG" +_check_test_img + +echo +echo "=== Standalone image with external data file (efficient) ===" +echo + +IMGOPTS="data_file=$TEST_IMG.data" _make_test_img 64M + +echo -n "qcow2 file size before I/O: " +du -b $TEST_IMG | cut -f1 + +# Create image with the following layout +# 0-1 MB: Unallocated +# 1-2 MB: Written (pattern 0x11) +# 2-3 MB: Discarded +# 3-4 MB: Zero write over discarded space +# 4-5 MB: Zero write over written space +# 5-6 MB: Zero write over unallocated space + +echo +$QEMU_IO -c 'write -P 0x11 1M 4M' \ + -c 'discard 2M 2M' \ + -c 'write -z 3M 3M' \ + -f $IMGFMT "$TEST_IMG" | + _filter_qemu_io +_check_test_img + +echo +$QEMU_IMG map --output=json "$TEST_IMG" + +echo +$QEMU_IO -c 'read -P 0 0 1M' \ + -c 'read -P 0x11 1M 1M' \ + -c 'read -P 0 2M 4M' \ + -f $IMGFMT "$TEST_IMG" | + _filter_qemu_io + +# Zero clusters are only marked as such in the qcow2 metadata, but contain +# stale data in the external data file +echo +$QEMU_IO -c 'read -P 0 0 1M' \ + -c 'read -P 0x11 1M 1M' \ + -c 'read -P 0 2M 2M' \ + -c 'read -P 0x11 4M 1M' \ + -c 'read -P 0 5M 1M' \ + -f raw "$TEST_IMG.data" | + _filter_qemu_io + + +echo -n "qcow2 file size after I/O: " +du -b $TEST_IMG | cut -f1 + +echo +echo "=== Standalone image with external data file (valid raw) ===" +echo + +IMGOPTS="data_file=$TEST_IMG.data,data_file_raw=on" _make_test_img 64M + +echo -n "qcow2 file size before I/O: " +du -b $TEST_IMG | cut -f1 + +echo +$QEMU_IO -c 'write -P 0x11 1M 4M' \ + -c 'discard 2M 2M' \ + -c 'write -z 3M 3M' \ + -f $IMGFMT "$TEST_IMG" | + _filter_qemu_io +_check_test_img + +echo +$QEMU_IMG map --output=json "$TEST_IMG" + +echo +$QEMU_IO -c 'read -P 0 0 1M' \ + -c 'read -P 0x11 1M 1M' \ + -c 'read -P 0 2M 4M' \ + -f $IMGFMT "$TEST_IMG" | + _filter_qemu_io + +echo +$QEMU_IMG compare "$TEST_IMG" "$TEST_IMG.data" + +echo -n "qcow2 file size after I/O: " +du -b $TEST_IMG | cut -f1 + +echo +echo "=== bdrv_co_block_status test for file and offset=0 ===" +echo + +IMGOPTS="data_file=$TEST_IMG.data" _make_test_img 64M + +$QEMU_IO -c 'write -P 0x11 0 1M' -f $IMGFMT "$TEST_IMG" | _filter_qemu_io +$QEMU_IO -c 'read -P 0x11 0 1M' -f $IMGFMT "$TEST_IMG" | _filter_qemu_io +$QEMU_IMG map --output=human "$TEST_IMG" | _filter_testdir +$QEMU_IMG map --output=json "$TEST_IMG" + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/244.out b/tests/qemu-iotests/244.out new file mode 100644 index 0000000000..98e5946976 --- /dev/null +++ b/tests/qemu-iotests/244.out @@ -0,0 +1,125 @@ +QA output created by 244 + +=== Create and open image with external data file === + +With data file name in the image: +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data +No errors were found on the image. +read 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +can't open device TEST_DIR/t.qcow2: Could not open 'inexistent': No such file or directory +no file open, try 'help open' + +Data file required, but without data file name in the image: +can't open device TEST_DIR/t.qcow2: 'data-file' is required for this image +no file open, try 'help open' +read 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +can't open device TEST_DIR/t.qcow2: Could not open 'inexistent': No such file or directory +no file open, try 'help open' + +Setting data-file for an image with internal data: +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +can't open device TEST_DIR/t.qcow2: 'data-file' can only be set for images with an external data file +no file open, try 'help open' +can't open device TEST_DIR/t.qcow2: Could not open 'inexistent': No such file or directory +no file open, try 'help open' + +=== Conflicting features === + +Convert to compressed target with data file: +Formatting 'TEST_DIR/t.IMGFMT.src', fmt=IMGFMT size=67108864 +wrote 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +qemu-img: error while writing sector 0: Operation not supported + +Convert uncompressed, then write compressed data manually: +Images are identical. +write failed: Operation not supported +No errors were found on the image. + +Take an internal snapshot: +qemu-img: Could not create snapshot 'test': -95 (Operation not supported) +No errors were found on the image. + +=== Standalone image with external data file (efficient) === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data +qcow2 file size before I/O: 196616 + +wrote 4194304/4194304 bytes at offset 1048576 +4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +discard 2097152/2097152 bytes at offset 2097152 +2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 3145728/3145728 bytes at offset 3145728 +3 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +No errors were found on the image. + +[{ "start": 0, "length": 1048576, "depth": 0, "zero": true, "data": false}, +{ "start": 1048576, "length": 1048576, "depth": 0, "zero": false, "data": true, "offset": 1048576}, +{ "start": 2097152, "length": 2097152, "depth": 0, "zero": true, "data": false}, +{ "start": 4194304, "length": 1048576, "depth": 0, "zero": true, "data": false, "offset": 4194304}, +{ "start": 5242880, "length": 61865984, "depth": 0, "zero": true, "data": false}] + +read 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 1048576/1048576 bytes at offset 1048576 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 4194304/4194304 bytes at offset 2097152 +4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +read 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 1048576/1048576 bytes at offset 1048576 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 2097152/2097152 bytes at offset 2097152 +2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 1048576/1048576 bytes at offset 4194304 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 1048576/1048576 bytes at offset 5242880 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +qcow2 file size after I/O: 327680 + +=== Standalone image with external data file (valid raw) === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data data_file_raw=on +qcow2 file size before I/O: 196616 + +wrote 4194304/4194304 bytes at offset 1048576 +4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +discard 2097152/2097152 bytes at offset 2097152 +2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 3145728/3145728 bytes at offset 3145728 +3 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +No errors were found on the image. + +[{ "start": 0, "length": 1048576, "depth": 0, "zero": true, "data": false}, +{ "start": 1048576, "length": 1048576, "depth": 0, "zero": false, "data": true, "offset": 1048576}, +{ "start": 2097152, "length": 2097152, "depth": 0, "zero": true, "data": false}, +{ "start": 4194304, "length": 1048576, "depth": 0, "zero": true, "data": false, "offset": 4194304}, +{ "start": 5242880, "length": 61865984, "depth": 0, "zero": true, "data": false}] + +read 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 1048576/1048576 bytes at offset 1048576 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 4194304/4194304 bytes at offset 2097152 +4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +Images are identical. +qcow2 file size after I/O: 327680 + +=== bdrv_co_block_status test for file and offset=0 === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data +wrote 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +Offset Length Mapped to File +0 0x100000 0 TEST_DIR/t.qcow2.data +[{ "start": 0, "length": 1048576, "depth": 0, "zero": false, "data": true, "offset": 0}, +{ "start": 1048576, "length": 66060288, "depth": 0, "zero": true, "data": false}] +*** done diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 03aa93dbf5..36100b803c 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -242,3 +242,4 @@ 240 auto quick 242 rw auto quick 243 rw auto quick +244 rw auto quick From ac40260dc554f20f06f23d458ec726360ddf8e39 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 26 Feb 2019 15:00:29 +0100 Subject: [PATCH 30/33] qemu-iotests: amend with external data file Signed-off-by: Kevin Wolf --- tests/qemu-iotests/061 | 45 ++++++++++++++++++- tests/qemu-iotests/061.out | 89 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+), 1 deletion(-) diff --git a/tests/qemu-iotests/061 b/tests/qemu-iotests/061 index d2e68c0203..d7dbd7e2c7 100755 --- a/tests/qemu-iotests/061 +++ b/tests/qemu-iotests/061 @@ -28,7 +28,8 @@ status=1 # failure is the default! _cleanup() { - _cleanup_test_img + _cleanup_test_img + rm -f $TEST_IMG.data } trap "_cleanup; exit \$status" 0 1 2 3 15 @@ -250,6 +251,48 @@ $QEMU_IMG snapshot -c foo "$TEST_IMG" $QEMU_IMG amend -p -o "compat=0.10" "$TEST_IMG" _check_test_img +echo +echo "=== Testing version downgrade with external data file ===" +echo +IMGOPTS="compat=1.1,data_file=$TEST_IMG.data" _make_test_img 64M +$QEMU_IMG amend -o "compat=0.10" "$TEST_IMG" +_img_info --format-specific +_check_test_img + +echo +echo "=== Try changing the external data file ===" +echo +IMGOPTS="compat=1.1" _make_test_img 64M +$QEMU_IMG amend -o "data_file=foo" "$TEST_IMG" + +echo +IMGOPTS="compat=1.1,data_file=$TEST_IMG.data" _make_test_img 64M +$QEMU_IMG amend -o "data_file=foo" "$TEST_IMG" +_img_info --format-specific +TEST_IMG="data-file.filename=$TEST_IMG.data,file.filename=$TEST_IMG" _img_info --format-specific --image-opts + +echo +$QEMU_IMG amend -o "data_file=" --image-opts "data-file.filename=$TEST_IMG.data,file.filename=$TEST_IMG" +_img_info --format-specific +TEST_IMG="data-file.filename=$TEST_IMG.data,file.filename=$TEST_IMG" _img_info --format-specific --image-opts + +echo +echo "=== Clearing and setting data-file-raw ===" +echo +IMGOPTS="compat=1.1,data_file=$TEST_IMG.data,data_file_raw=on" _make_test_img 64M +$QEMU_IMG amend -o "data_file_raw=on" "$TEST_IMG" +_img_info --format-specific +_check_test_img + +$QEMU_IMG amend -o "data_file_raw=off" "$TEST_IMG" +_img_info --format-specific +_check_test_img + +$QEMU_IMG amend -o "data_file_raw=on" "$TEST_IMG" +_img_info --format-specific +_check_test_img + + # success, all done echo "*** done" rm -f $seq.full diff --git a/tests/qemu-iotests/061.out b/tests/qemu-iotests/061.out index 758284011b..9fe1ec702f 100644 --- a/tests/qemu-iotests/061.out +++ b/tests/qemu-iotests/061.out @@ -488,4 +488,93 @@ wrote 65536/65536 bytes at offset 3221225472 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) (0.00/100%) (6.25/100%) (12.50/100%) (18.75/100%) (25.00/100%) (31.25/100%) (37.50/100%) (43.75/100%) (50.00/100%) (56.25/100%) (62.50/100%) (68.75/100%) (75.00/100%) (81.25/100%) (87.50/100%) (93.75/100%) (100.00/100%) (100.00/100%) No errors were found on the image. + +=== Testing version downgrade with external data file === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data +qemu-img: Cannot downgrade an image with a data file +image: TEST_DIR/t.IMGFMT +file format: IMGFMT +virtual size: 64M (67108864 bytes) +cluster_size: 65536 +Format specific information: + compat: 1.1 + lazy refcounts: false + refcount bits: 16 + data file: TEST_DIR/t.IMGFMT.data + data file raw: false + corrupt: false +No errors were found on the image. + +=== Try changing the external data file === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +qemu-img: data-file can only be set for images that use an external data file + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Could not open 'foo': No such file or directory +image: TEST_DIR/t.IMGFMT +file format: IMGFMT +virtual size: 64M (67108864 bytes) +cluster_size: 65536 +Format specific information: + compat: 1.1 + lazy refcounts: false + refcount bits: 16 + data file: foo + data file raw: false + corrupt: false + +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'data-file' is required for this image +image: TEST_DIR/t.IMGFMT +file format: IMGFMT +virtual size: 64M (67108864 bytes) +cluster_size: 65536 +Format specific information: + compat: 1.1 + lazy refcounts: false + refcount bits: 16 + data file raw: false + corrupt: false + +=== Clearing and setting data-file-raw === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 data_file=TEST_DIR/t.IMGFMT.data data_file_raw=on +image: TEST_DIR/t.IMGFMT +file format: IMGFMT +virtual size: 64M (67108864 bytes) +cluster_size: 65536 +Format specific information: + compat: 1.1 + lazy refcounts: false + refcount bits: 16 + data file: TEST_DIR/t.IMGFMT.data + data file raw: true + corrupt: false +No errors were found on the image. +image: TEST_DIR/t.IMGFMT +file format: IMGFMT +virtual size: 64M (67108864 bytes) +cluster_size: 65536 +Format specific information: + compat: 1.1 + lazy refcounts: false + refcount bits: 16 + data file: TEST_DIR/t.IMGFMT.data + data file raw: false + corrupt: false +No errors were found on the image. +qemu-img: data-file-raw cannot be set on existing images +image: TEST_DIR/t.IMGFMT +file format: IMGFMT +virtual size: 64M (67108864 bytes) +cluster_size: 65536 +Format specific information: + compat: 1.1 + lazy refcounts: false + refcount bits: 16 + data file: TEST_DIR/t.IMGFMT.data + data file raw: false + corrupt: false +No errors were found on the image. *** done From 377213f4d1373feee1621e32870f19eb515b7388 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 7 Mar 2019 16:10:45 +0100 Subject: [PATCH 31/33] ahci-test: Add dependency to qemu-img tool MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the ahci-test uses qemu-img, add a dependency to build it before using it. This fixes: $ gmake check-qtest V=1 QTEST_QEMU_BINARY=x86_64-softmmu/qemu-system-x86_64 QTEST_QEMU_IMG=qemu-img tests/ahci-test Failed to execute child process "/tmp/qemu-test.19tMRF/qemu-img" (No such file or directory) ERROR:tests/libqos/libqos.c:192:mkimg: assertion failed: (ret && !err) Reviewed-by: John Snow Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Kevin Wolf --- tests/Makefile.include | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Makefile.include b/tests/Makefile.include index 97e1cb90a3..b6bd0a5ed8 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -758,7 +758,7 @@ tests/prom-env-test$(EXESUF): tests/prom-env-test.o $(libqos-obj-y) tests/rtas-test$(EXESUF): tests/rtas-test.o $(libqos-spapr-obj-y) tests/fdc-test$(EXESUF): tests/fdc-test.o tests/ide-test$(EXESUF): tests/ide-test.o $(libqos-pc-obj-y) -tests/ahci-test$(EXESUF): tests/ahci-test.o $(libqos-pc-obj-y) +tests/ahci-test$(EXESUF): tests/ahci-test.o $(libqos-pc-obj-y) qemu-img$(EXESUF) tests/ipmi-kcs-test$(EXESUF): tests/ipmi-kcs-test.o tests/ipmi-bt-test$(EXESUF): tests/ipmi-bt-test.o tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o From 9c2b28e4584f51896e4889239464ec0e469b96fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 7 Mar 2019 16:10:46 +0100 Subject: [PATCH 32/33] qemu-iotests: Add dependency to qemu-nbd tool MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since a9660664fde, some iotests use qemu-nbd. Add a dependency to build it before using it. This fixes: $ make check-block GEN qemu-img-cmds.h CC qemu-img.o LINK qemu-img CC qemu-io.o LINK qemu-io CC tests/qemu-iotests/socket_scm_helper.o LINK tests/qemu-iotests/socket_scm_helper tests/qemu-iotests-quick.sh check: qemu-nbd not found make: *** [tests/Makefile.include:1059: check-tests/qemu-iotests-quick.sh] Error 1 Reviewed-by: Eric Blake Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Kevin Wolf --- tests/Makefile.include | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Makefile.include b/tests/Makefile.include index b6bd0a5ed8..45a4302103 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -1104,7 +1104,7 @@ clean-tcg: $(CLEAN_TCG_TARGET_RULES) QEMU_IOTESTS_HELPERS-$(call land,$(CONFIG_SOFTMMU),$(CONFIG_LINUX)) = tests/qemu-iotests/socket_scm_helper$(EXESUF) .PHONY: check-tests/qemu-iotests-quick.sh -check-tests/qemu-iotests-quick.sh: tests/qemu-iotests-quick.sh qemu-img$(EXESUF) qemu-io$(EXESUF) $(QEMU_IOTESTS_HELPERS-y) +check-tests/qemu-iotests-quick.sh: tests/qemu-iotests-quick.sh qemu-img$(EXESUF) qemu-io$(EXESUF) qemu-nbd$(EXESUF) $(QEMU_IOTESTS_HELPERS-y) $< .PHONY: $(patsubst %, check-%, $(check-qapi-schema-y)) From e88153ea9a40009a8ae7648282c0eac1b7f5494f Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 7 Mar 2019 17:49:55 +0100 Subject: [PATCH 33/33] qcow2 spec: Describe string header extensions Be more specific about the string representation in header extensions. Suggested-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake Reviewed-by: Stefan Hajnoczi --- docs/interop/qcow2.txt | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt index bfb97cfde3..8c3098d8d9 100644 --- a/docs/interop/qcow2.txt +++ b/docs/interop/qcow2.txt @@ -170,11 +170,11 @@ be stored. Each extension has a structure like the following: Byte 0 - 3: Header extension type: 0x00000000 - End of the header extension area - 0xE2792ACA - Backing file format name + 0xE2792ACA - Backing file format name string 0x6803f857 - Feature name table 0x23852875 - Bitmaps extension 0x0537be77 - Full disk encryption header pointer - 0x44415441 - External data file name + 0x44415441 - External data file name string other - Unknown header extension, can be safely ignored @@ -196,6 +196,16 @@ data of compatible features that it doesn't support. Compatible features that need space for additional data can use a header extension. +== String header extensions == + +Some header extensions (such as the backing file format name and the external +data file name) are just a single string. In this case, the header extension +length is the string length and the string is not '\0' terminated. (The header +extension padding can make it look like a string is '\0' terminated, but +neither is padding always necessary nor is there a guarantee that zero bytes +are used for padding.) + + == Feature name table == The feature name table is an optional header extension that contains the name