From 1b19bb9d17052def5ec39c2fdb2b09066bd086ec Mon Sep 17 00:00:00 2001 From: John Snow Date: Tue, 1 Dec 2015 18:16:37 -0500 Subject: iotests: 124: Split into two test classes Split it into an abstract test class and an implementation class. The split is primarily to facilitate more flexible setUp variations for other kinds of tests without having to rewrite or shuffle around all of these helpers. See the following two patches for more of the "why." Signed-off-by: John Snow Signed-off-by: Kevin Wolf --- tests/qemu-iotests/124 | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/tests/qemu-iotests/124 b/tests/qemu-iotests/124 index c928f01..778bfdd 100644 --- a/tests/qemu-iotests/124 +++ b/tests/qemu-iotests/124 @@ -91,24 +91,31 @@ class Bitmap: try_remove(image) -class TestIncrementalBackup(iotests.QMPTestCase): - def setUp(self): +class TestIncrementalBackupBase(iotests.QMPTestCase): + def __init__(self, *args): + super(TestIncrementalBackupBase, self).__init__(*args) self.bitmaps = list() self.files = list() self.drives = list() self.vm = iotests.VM() self.err_img = os.path.join(iotests.test_dir, 'err.%s' % iotests.imgfmt) + + def setUp(self): # Create a base image with a distinctive patterning drive0 = self.add_node('drive0') self.img_create(drive0['file'], drive0['fmt']) self.vm.add_drive(drive0['file']) - io_write_patterns(drive0['file'], (('0x41', 0, 512), - ('0xd5', '1M', '32k'), - ('0xdc', '32M', '124k'))) + self.write_default_pattern(drive0['file']) self.vm.launch() + def write_default_pattern(self, target): + io_write_patterns(target, (('0x41', 0, 512), + ('0xd5', '1M', '32k'), + ('0xdc', '32M', '124k'))) + + def add_node(self, node_id, fmt=iotests.imgfmt, path=None, backup=None): if path is None: path = os.path.join(iotests.test_dir, '%s.%s' % (node_id, fmt)) @@ -259,6 +266,16 @@ class TestIncrementalBackup(iotests.QMPTestCase): self.check_backups() + def tearDown(self): + self.vm.shutdown() + for bitmap in self.bitmaps: + bitmap.cleanup() + for filename in self.files: + try_remove(filename) + + + +class TestIncrementalBackup(TestIncrementalBackupBase): def test_incremental_simple(self): ''' Test: Create and verify three incremental backups. @@ -531,13 +548,5 @@ class TestIncrementalBackup(iotests.QMPTestCase): granularity=64000) - def tearDown(self): - self.vm.shutdown() - for bitmap in self.bitmaps: - bitmap.cleanup() - for filename in self.files: - try_remove(filename) - - if __name__ == '__main__': iotests.main(supported_fmts=['qcow2']) -- cgit v1.1 From ce2cbc49102c684d6d6014085447e208f2cbfb21 Mon Sep 17 00:00:00 2001 From: John Snow Date: Tue, 1 Dec 2015 18:16:38 -0500 Subject: iotests: 124: move incremental failure test Code motion only, in preparation for adjusting the setUp procedure for this test. Signed-off-by: John Snow Signed-off-by: Kevin Wolf --- tests/qemu-iotests/124 | 117 +++++++++++++++++++++++++------------------------ 1 file changed, 60 insertions(+), 57 deletions(-) diff --git a/tests/qemu-iotests/124 b/tests/qemu-iotests/124 index 778bfdd..2a0119d 100644 --- a/tests/qemu-iotests/124 +++ b/tests/qemu-iotests/124 @@ -344,63 +344,6 @@ class TestIncrementalBackup(TestIncrementalBackupBase): self.check_backups() - def test_incremental_failure(self): - '''Test: Verify backups made after a failure are correct. - - Simulate a failure during an incremental backup block job, - emulate additional writes, then create another incremental backup - afterwards and verify that the backup created is correct. - ''' - - # Create a blkdebug interface to this img as 'drive1', - # but don't actually create a new image. - drive1 = self.add_node('drive1', self.drives[0]['fmt'], - path=self.drives[0]['file'], - backup=self.drives[0]['backup']) - result = self.vm.qmp('blockdev-add', options={ - 'id': drive1['id'], - 'driver': drive1['fmt'], - 'file': { - 'driver': 'blkdebug', - 'image': { - 'driver': 'file', - 'filename': drive1['file'] - }, - 'set-state': [{ - 'event': 'flush_to_disk', - 'state': 1, - 'new_state': 2 - }], - 'inject-error': [{ - 'event': 'read_aio', - 'errno': 5, - 'state': 2, - 'immediately': False, - 'once': True - }], - } - }) - self.assert_qmp(result, 'return', {}) - - self.create_anchor_backup(self.drives[0]) - self.add_bitmap('bitmap0', drive1) - # Note: at this point, during a normal execution, - # Assume that the VM resumes and begins issuing IO requests here. - - self.hmp_io_writes(drive1['id'], (('0xab', 0, 512), - ('0xfe', '16M', '256k'), - ('0x64', '32736k', '64k'))) - - result = self.create_incremental(validate=False) - self.assertFalse(result) - self.hmp_io_writes(drive1['id'], (('0x9a', 0, 512), - ('0x55', '8M', '352k'), - ('0x78', '15872k', '1M'))) - self.create_incremental() - self.vm.shutdown() - self.check_backups() - - def test_transaction_failure(self): '''Test: Verify backups made from a transaction that partially fails. @@ -548,5 +491,65 @@ class TestIncrementalBackup(TestIncrementalBackupBase): granularity=64000) +class TestIncrementalBackupBlkdebug(TestIncrementalBackupBase): + '''Incremental backup tests that utilize a BlkDebug filter on drive0.''' + + def test_incremental_failure(self): + '''Test: Verify backups made after a failure are correct. + + Simulate a failure during an incremental backup block job, + emulate additional writes, then create another incremental backup + afterwards and verify that the backup created is correct. + ''' + + # Create a blkdebug interface to this img as 'drive1', + # but don't actually create a new image. + drive1 = self.add_node('drive1', self.drives[0]['fmt'], + path=self.drives[0]['file'], + backup=self.drives[0]['backup']) + result = self.vm.qmp('blockdev-add', options={ + 'id': drive1['id'], + 'driver': drive1['fmt'], + 'file': { + 'driver': 'blkdebug', + 'image': { + 'driver': 'file', + 'filename': drive1['file'] + }, + 'set-state': [{ + 'event': 'flush_to_disk', + 'state': 1, + 'new_state': 2 + }], + 'inject-error': [{ + 'event': 'read_aio', + 'errno': 5, + 'state': 2, + 'immediately': False, + 'once': True + }], + } + }) + self.assert_qmp(result, 'return', {}) + + self.create_anchor_backup(self.drives[0]) + self.add_bitmap('bitmap0', drive1) + # Note: at this point, during a normal execution, + # Assume that the VM resumes and begins issuing IO requests here. + + self.hmp_io_writes(drive1['id'], (('0xab', 0, 512), + ('0xfe', '16M', '256k'), + ('0x64', '32736k', '64k'))) + + result = self.create_incremental(validate=False) + self.assertFalse(result) + self.hmp_io_writes(drive1['id'], (('0x9a', 0, 512), + ('0x55', '8M', '352k'), + ('0x78', '15872k', '1M'))) + self.create_incremental() + self.vm.shutdown() + self.check_backups() + + if __name__ == '__main__': iotests.main(supported_fmts=['qcow2']) -- cgit v1.1 From 35cea22373fd8ec10575cb218304bea9b162447f Mon Sep 17 00:00:00 2001 From: John Snow Date: Tue, 1 Dec 2015 18:16:39 -0500 Subject: iotests: 124: don't reopen qcow2 Don't create two interfaces to the same drive in the recently moved failure test. Signed-off-by: John Snow Signed-off-by: Kevin Wolf --- tests/qemu-iotests/124 | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/tests/qemu-iotests/124 b/tests/qemu-iotests/124 index 2a0119d..7d33422 100644 --- a/tests/qemu-iotests/124 +++ b/tests/qemu-iotests/124 @@ -494,6 +494,12 @@ class TestIncrementalBackup(TestIncrementalBackupBase): class TestIncrementalBackupBlkdebug(TestIncrementalBackupBase): '''Incremental backup tests that utilize a BlkDebug filter on drive0.''' + def setUp(self): + drive0 = self.add_node('drive0') + self.img_create(drive0['file'], drive0['fmt']) + self.write_default_pattern(drive0['file']) + self.vm.launch() + def test_incremental_failure(self): '''Test: Verify backups made after a failure are correct. @@ -502,19 +508,15 @@ class TestIncrementalBackupBlkdebug(TestIncrementalBackupBase): afterwards and verify that the backup created is correct. ''' - # Create a blkdebug interface to this img as 'drive1', - # but don't actually create a new image. - drive1 = self.add_node('drive1', self.drives[0]['fmt'], - path=self.drives[0]['file'], - backup=self.drives[0]['backup']) + drive0 = self.drives[0] result = self.vm.qmp('blockdev-add', options={ - 'id': drive1['id'], - 'driver': drive1['fmt'], + 'id': drive0['id'], + 'driver': drive0['fmt'], 'file': { 'driver': 'blkdebug', 'image': { 'driver': 'file', - 'filename': drive1['file'] + 'filename': drive0['file'] }, 'set-state': [{ 'event': 'flush_to_disk', @@ -532,18 +534,18 @@ class TestIncrementalBackupBlkdebug(TestIncrementalBackupBase): }) self.assert_qmp(result, 'return', {}) - self.create_anchor_backup(self.drives[0]) - self.add_bitmap('bitmap0', drive1) + self.create_anchor_backup(drive0) + self.add_bitmap('bitmap0', drive0) # Note: at this point, during a normal execution, # Assume that the VM resumes and begins issuing IO requests here. - self.hmp_io_writes(drive1['id'], (('0xab', 0, 512), + self.hmp_io_writes(drive0['id'], (('0xab', 0, 512), ('0xfe', '16M', '256k'), ('0x64', '32736k', '64k'))) result = self.create_incremental(validate=False) self.assertFalse(result) - self.hmp_io_writes(drive1['id'], (('0x9a', 0, 512), + self.hmp_io_writes(drive0['id'], (('0x9a', 0, 512), ('0x55', '8M', '352k'), ('0x78', '15872k', '1M'))) self.create_incremental() -- cgit v1.1 From 5365f44dfa4669a8d37ec309c421c7512959d509 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Mon, 16 Nov 2015 15:34:59 +0100 Subject: qcow2: Add .bdrv_join_options callback qcow2 accepts a few driver-specific options that overlap semantically (e.g. "overlap-check" is an alias of "overlap-check.template", and any missing cache size option is derived from the given ones). When bdrv_reopen() merges the set of updated options with left out options that should be kept at their old value, we need to consider this and filter out any duplicates (which would generally cause errors because new and old value would contradict each other). This patch adds a .bdrv_join_options callback to BlockDriver and implements it for qcow2. Signed-off-by: Kevin Wolf Reviewed-by: Max Reitz Reviewed-by: Alberto Garcia --- block/qcow2.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ include/block/block_int.h | 1 + 2 files changed, 48 insertions(+) diff --git a/block/qcow2.c b/block/qcow2.c index 5b59fa3..fda1562 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1282,6 +1282,52 @@ static void qcow2_reopen_abort(BDRVReopenState *state) g_free(state->opaque); } +static void qcow2_join_options(QDict *options, QDict *old_options) +{ + bool has_new_overlap_template = + qdict_haskey(options, QCOW2_OPT_OVERLAP) || + qdict_haskey(options, QCOW2_OPT_OVERLAP_TEMPLATE); + bool has_new_total_cache_size = + qdict_haskey(options, QCOW2_OPT_CACHE_SIZE); + bool has_all_cache_options; + + /* New overlap template overrides all old overlap options */ + if (has_new_overlap_template) { + qdict_del(old_options, QCOW2_OPT_OVERLAP); + qdict_del(old_options, QCOW2_OPT_OVERLAP_TEMPLATE); + qdict_del(old_options, QCOW2_OPT_OVERLAP_MAIN_HEADER); + qdict_del(old_options, QCOW2_OPT_OVERLAP_ACTIVE_L1); + qdict_del(old_options, QCOW2_OPT_OVERLAP_ACTIVE_L2); + qdict_del(old_options, QCOW2_OPT_OVERLAP_REFCOUNT_TABLE); + qdict_del(old_options, QCOW2_OPT_OVERLAP_REFCOUNT_BLOCK); + qdict_del(old_options, QCOW2_OPT_OVERLAP_SNAPSHOT_TABLE); + qdict_del(old_options, QCOW2_OPT_OVERLAP_INACTIVE_L1); + qdict_del(old_options, QCOW2_OPT_OVERLAP_INACTIVE_L2); + } + + /* New total cache size overrides all old options */ + if (qdict_haskey(options, QCOW2_OPT_CACHE_SIZE)) { + qdict_del(old_options, QCOW2_OPT_L2_CACHE_SIZE); + qdict_del(old_options, QCOW2_OPT_REFCOUNT_CACHE_SIZE); + } + + qdict_join(options, old_options, false); + + /* + * If after merging all cache size options are set, an old total size is + * overwritten. Do keep all options, however, if all three are new. The + * resulting error message is what we want to happen. + */ + has_all_cache_options = + qdict_haskey(options, QCOW2_OPT_CACHE_SIZE) || + qdict_haskey(options, QCOW2_OPT_L2_CACHE_SIZE) || + qdict_haskey(options, QCOW2_OPT_REFCOUNT_CACHE_SIZE); + + if (has_all_cache_options && !has_new_total_cache_size) { + qdict_del(options, QCOW2_OPT_CACHE_SIZE); + } +} + static int64_t coroutine_fn qcow2_co_get_block_status(BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum) { @@ -3145,6 +3191,7 @@ BlockDriver bdrv_qcow2 = { .bdrv_reopen_prepare = qcow2_reopen_prepare, .bdrv_reopen_commit = qcow2_reopen_commit, .bdrv_reopen_abort = qcow2_reopen_abort, + .bdrv_join_options = qcow2_join_options, .bdrv_create = qcow2_create, .bdrv_has_zero_init = bdrv_has_zero_init_1, .bdrv_co_get_block_status = qcow2_co_get_block_status, diff --git a/include/block/block_int.h b/include/block/block_int.h index 66e208d..c2ce965 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -121,6 +121,7 @@ struct BlockDriver { BlockReopenQueue *queue, Error **errp); void (*bdrv_reopen_commit)(BDRVReopenState *reopen_state); void (*bdrv_reopen_abort)(BDRVReopenState *reopen_state); + void (*bdrv_join_options)(QDict *options, QDict *old_options); int (*bdrv_open)(BlockDriverState *bs, QDict *options, int flags, Error **errp); -- cgit v1.1 From cddff5bae1c8e0e21a5e6da04eff1d0a4423e5f3 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Mon, 16 Nov 2015 16:43:27 +0100 Subject: block: Fix reopen with semantically overlapping options This fixes bdrv_reopen() calls like the following one: qemu-io -c 'open -o overlap-check.template=all /tmp/test.qcow2' \ -c 'reopen -o overlap-check=none' The approach taken so far would result in an options QDict that has both "overlap-check.template=all" and "overlap-check=none", which obviously conflicts. In this case, the old option should be overridden by the newly specified option. Signed-off-by: Kevin Wolf Reviewed-by: Max Reitz Reviewed-by: Alberto Garcia --- block.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/block.c b/block.c index 9971976..57bf8fc 100644 --- a/block.c +++ b/block.c @@ -624,6 +624,20 @@ static int refresh_total_sectors(BlockDriverState *bs, int64_t hint) } /** + * Combines a QDict of new block driver @options with any missing options taken + * from @old_options, so that leaving out an option defaults to its old value. + */ +static void bdrv_join_options(BlockDriverState *bs, QDict *options, + QDict *old_options) +{ + if (bs->drv && bs->drv->bdrv_join_options) { + bs->drv->bdrv_join_options(options, old_options); + } else { + qdict_join(options, old_options, false); + } +} + +/** * Set open flags for a given discard mode * * Return 0 on success, -1 if the discard mode was invalid. @@ -1663,7 +1677,7 @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue, } old_options = qdict_clone_shallow(bs->options); - qdict_join(options, old_options, false); + bdrv_join_options(bs, options, old_options); QDECREF(old_options); /* bdrv_open() masks this flag out */ -- cgit v1.1 From 40365552c2fceacc9800ec9a87b9ead516a9a6ce Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Wed, 28 Oct 2015 13:24:26 +0100 Subject: mirror: Error out when a BDS would get two BBs bdrv_replace_in_backing_chain() asserts that not both old and new BlockDdriverState have a BlockBackend attached to them because both would have to end up pointing to the new BDS and we don't support more than one BB per BDS yet. Before we can safely allow references to existing nodes as backing files, we need to make sure that even if a backing file has a BB on it, this doesn't crash qemu. There are probably also some cases with the 'replaces' option set where drive-mirror could fail this assertion today. They are fixed with this error check as well. Signed-off-by: Kevin Wolf Reviewed-by: Max Reitz --- block/mirror.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/block/mirror.c b/block/mirror.c index 0e8f556..8e3f524 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -18,6 +18,7 @@ #include "qapi/qmp/qerror.h" #include "qemu/ratelimit.h" #include "qemu/bitmap.h" +#include "qemu/error-report.h" #define SLICE_TIME 100000000ULL /* ns */ #define MAX_IN_FLIGHT 16 @@ -370,11 +371,22 @@ static void mirror_exit(BlockJob *job, void *opaque) if (s->to_replace) { to_replace = s->to_replace; } + + /* This was checked in mirror_start_job(), but meanwhile one of the + * nodes could have been newly attached to a BlockBackend. */ + if (to_replace->blk && s->target->blk) { + error_report("block job: Can't create node with two BlockBackends"); + data->ret = -EINVAL; + goto out; + } + if (bdrv_get_flags(s->target) != bdrv_get_flags(to_replace)) { bdrv_reopen(s->target, bdrv_get_flags(to_replace), NULL); } bdrv_replace_in_backing_chain(to_replace, s->target); } + +out: if (s->to_replace) { bdrv_op_unblock_all(s->to_replace, s->replace_blocker); error_free(s->replace_blocker); @@ -705,6 +717,7 @@ static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target, bool is_none_mode, BlockDriverState *base) { MirrorBlockJob *s; + BlockDriverState *replaced_bs; if (granularity == 0) { granularity = bdrv_get_default_bitmap_granularity(target); @@ -728,6 +741,21 @@ static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target, buf_size = DEFAULT_MIRROR_BUF_SIZE; } + /* We can't support this case as long as the block layer can't handle + * multiple BlockBackends per BlockDriverState. */ + if (replaces) { + replaced_bs = bdrv_lookup_bs(replaces, replaces, errp); + if (replaced_bs == NULL) { + return; + } + } else { + replaced_bs = bs; + } + if (replaced_bs->blk && target->blk) { + error_setg(errp, "Can't create node with two BlockBackends"); + return; + } + s = block_job_create(driver, bs, speed, cb, opaque, errp); if (!s) { return; -- cgit v1.1 From d9b7b05703399fbc9b87553d7f164ffba1db4aa4 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 16 Jan 2015 18:23:41 +0100 Subject: block: Allow references for backing files For bs->file, using references to existing BDSes has been possible for a while already. This patch enables the same for bs->backing. Signed-off-by: Kevin Wolf Reviewed-by: Max Reitz --- block.c | 48 +++++++++++++++++++++++++++++------------------- block/mirror.c | 2 +- include/block/block.h | 3 ++- 3 files changed, 32 insertions(+), 21 deletions(-) diff --git a/block.c b/block.c index 57bf8fc..84b9bf4 100644 --- a/block.c +++ b/block.c @@ -1182,30 +1182,43 @@ out: /* * Opens the backing file for a BlockDriverState if not yet open * - * options is a QDict of options to pass to the block drivers, or NULL for an - * empty set of options. The reference to the QDict is transferred to this - * function (even on failure), so if the caller intends to reuse the dictionary, - * it needs to use QINCREF() before calling bdrv_file_open. + * bdref_key specifies the key for the image's BlockdevRef in the options QDict. + * That QDict has to be flattened; therefore, if the BlockdevRef is a QDict + * itself, all options starting with "${bdref_key}." are considered part of the + * BlockdevRef. + * + * TODO Can this be unified with bdrv_open_image()? */ -int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp) +int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options, + const char *bdref_key, Error **errp) { char *backing_filename = g_malloc0(PATH_MAX); + char *bdref_key_dot; + const char *reference = NULL; int ret = 0; BlockDriverState *backing_hd; + QDict *options; + QDict *tmp_parent_options = NULL; Error *local_err = NULL; if (bs->backing != NULL) { - QDECREF(options); goto free_exit; } /* NULL means an empty set of options */ - if (options == NULL) { - options = qdict_new(); + if (parent_options == NULL) { + tmp_parent_options = qdict_new(); + parent_options = tmp_parent_options; } bs->open_flags &= ~BDRV_O_NO_BACKING; - if (qdict_haskey(options, "file.filename")) { + + bdref_key_dot = g_strdup_printf("%s.", bdref_key); + qdict_extract_subqdict(parent_options, &options, bdref_key_dot); + g_free(bdref_key_dot); + + reference = qdict_get_try_str(parent_options, bdref_key); + if (reference || qdict_haskey(options, "file.filename")) { backing_filename[0] = '\0'; } else if (bs->backing_file[0] == '\0' && qdict_size(options) == 0) { QDECREF(options); @@ -1228,19 +1241,16 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp) goto free_exit; } - backing_hd = bdrv_new(); - if (bs->backing_format[0] != '\0' && !qdict_haskey(options, "driver")) { qdict_put(options, "driver", qstring_from_str(bs->backing_format)); } - assert(bs->backing == NULL); + backing_hd = NULL; ret = bdrv_open_inherit(&backing_hd, *backing_filename ? backing_filename : NULL, - NULL, options, 0, bs, &child_backing, &local_err); + reference, options, 0, bs, &child_backing, + &local_err); if (ret < 0) { - bdrv_unref(backing_hd); - backing_hd = NULL; bs->open_flags |= BDRV_O_NO_BACKING; error_setg(errp, "Could not open backing file: %s", error_get_pretty(local_err)); @@ -1253,8 +1263,11 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp) bdrv_set_backing_hd(bs, backing_hd); bdrv_unref(backing_hd); + qdict_del(parent_options, bdref_key); + free_exit: g_free(backing_filename); + QDECREF(tmp_parent_options); return ret; } @@ -1537,10 +1550,7 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename, /* If there is a backing file, use it */ if ((flags & BDRV_O_NO_BACKING) == 0) { - QDict *backing_options; - - qdict_extract_subqdict(options, &backing_options, "backing."); - ret = bdrv_open_backing_file(bs, backing_options, &local_err); + ret = bdrv_open_backing_file(bs, options, "backing", &local_err); if (ret < 0) { goto close_and_fail; } diff --git a/block/mirror.c b/block/mirror.c index 8e3f524..fc34a9c 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -652,7 +652,7 @@ static void mirror_complete(BlockJob *job, Error **errp) Error *local_err = NULL; int ret; - ret = bdrv_open_backing_file(s->target, NULL, &local_err); + ret = bdrv_open_backing_file(s->target, NULL, "backing", &local_err); if (ret < 0) { error_propagate(errp, local_err); return; diff --git a/include/block/block.h b/include/block/block.h index d048bbf..2e77288 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -210,7 +210,8 @@ BdrvChild *bdrv_open_child(const char *filename, const BdrvChildRole *child_role, bool allow_none, Error **errp); void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd); -int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp); +int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options, + const char *bdref_key, Error **errp); int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp); int bdrv_open(BlockDriverState **pbs, const char *filename, const char *reference, QDict *options, int flags, Error **errp); -- cgit v1.1 From 9e700c1ac6337e448e75e66a5753a9d2168d06c2 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 24 Apr 2015 15:20:28 +0200 Subject: block: Consider all block layer options in append_open_options The code already special-cased "node-name", which is currently the only option passed in the QDict that isn't driver-specific. Generalise the code to take all general block layer options into consideration. Signed-off-by: Kevin Wolf Reviewed-by: Eric Blake Reviewed-by: Max Reitz Reviewed-by: Alberto Garcia --- block.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/block.c b/block.c index 84b9bf4..0cc3c8b 100644 --- a/block.c +++ b/block.c @@ -3950,20 +3950,30 @@ out: static bool append_open_options(QDict *d, BlockDriverState *bs) { const QDictEntry *entry; + QemuOptDesc *desc; bool found_any = false; for (entry = qdict_first(bs->options); entry; entry = qdict_next(bs->options, entry)) { - /* Only take options for this level and exclude all non-driver-specific - * options */ - if (!strchr(qdict_entry_key(entry), '.') && - strcmp(qdict_entry_key(entry), "node-name")) - { - qobject_incref(qdict_entry_value(entry)); - qdict_put_obj(d, qdict_entry_key(entry), qdict_entry_value(entry)); - found_any = true; + /* Only take options for this level */ + if (strchr(qdict_entry_key(entry), '.')) { + continue; } + + /* And exclude all non-driver-specific options */ + for (desc = bdrv_runtime_opts.desc; desc->name; desc++) { + if (!strcmp(qdict_entry_key(entry), desc->name)) { + break; + } + } + if (desc->name) { + continue; + } + + qobject_incref(qdict_entry_value(entry)); + qdict_put_obj(d, qdict_entry_key(entry), qdict_entry_value(entry)); + found_any = true; } return found_any; -- cgit v1.1 From 260fecf13b0d30621dc88da03dc1b502b7358c6b Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Mon, 27 Apr 2015 13:46:22 +0200 Subject: block: Exclude nested options only for children in append_open_options() Some drivers have nested options (e.g. blkdebug rule arrays), which don't belong to a child node and shouldn't be removed. Don't remove all options with "." in their name, but check for the complete prefixes of actually existing child nodes. Signed-off-by: Kevin Wolf Reviewed-by: Max Reitz --- block.c | 20 ++++++++++++++++---- include/block/block_int.h | 1 + 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/block.c b/block.c index 0cc3c8b..fa351ac 100644 --- a/block.c +++ b/block.c @@ -1101,11 +1101,13 @@ static int bdrv_fill_options(QDict **options, const char **pfilename, static BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs, BlockDriverState *child_bs, + const char *child_name, const BdrvChildRole *child_role) { BdrvChild *child = g_new(BdrvChild, 1); *child = (BdrvChild) { .bs = child_bs, + .name = g_strdup(child_name), .role = child_role, }; @@ -1119,6 +1121,7 @@ static void bdrv_detach_child(BdrvChild *child) { QLIST_REMOVE(child, next); QLIST_REMOVE(child, next_parent); + g_free(child->name); g_free(child); } @@ -1165,7 +1168,7 @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd) bs->backing = NULL; goto out; } - bs->backing = bdrv_attach_child(bs, backing_hd, &child_backing); + bs->backing = bdrv_attach_child(bs, backing_hd, "backing", &child_backing); bs->open_flags &= ~BDRV_O_NO_BACKING; pstrcpy(bs->backing_file, sizeof(bs->backing_file), backing_hd->filename); pstrcpy(bs->backing_format, sizeof(bs->backing_format), @@ -1321,7 +1324,7 @@ BdrvChild *bdrv_open_child(const char *filename, goto done; } - c = bdrv_attach_child(parent, bs, child_role); + c = bdrv_attach_child(parent, bs, bdref_key, child_role); done: qdict_del(options, bdref_key); @@ -3951,13 +3954,22 @@ static bool append_open_options(QDict *d, BlockDriverState *bs) { const QDictEntry *entry; QemuOptDesc *desc; + BdrvChild *child; bool found_any = false; + const char *p; for (entry = qdict_first(bs->options); entry; entry = qdict_next(bs->options, entry)) { - /* Only take options for this level */ - if (strchr(qdict_entry_key(entry), '.')) { + /* Exclude options for children */ + QLIST_FOREACH(child, &bs->children, next) { + if (strstart(qdict_entry_key(entry), child->name, &p) + && (!*p || *p == '.')) + { + break; + } + } + if (child) { continue; } diff --git a/include/block/block_int.h b/include/block/block_int.h index c2ce965..0284f81 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -351,6 +351,7 @@ extern const BdrvChildRole child_format; struct BdrvChild { BlockDriverState *bs; + char *name; const BdrvChildRole *role; QLIST_ENTRY(BdrvChild) next; QLIST_ENTRY(BdrvChild) next_parent; -- cgit v1.1 From 4cdd01d32ee6fe04f8d909bfd3708be6864873a2 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Mon, 27 Apr 2015 13:50:54 +0200 Subject: block: Pass driver-specific options to .bdrv_refresh_filename() In order to decide whether a blkdebug: filename can be produced or a json: one is necessary, blkdebug checked whether bs->options had more options than just "config", "x-image" or "image" (the latter including nested options). That doesn't work well when generic block layer options are present. This patch passes an option QDict to the driver that contains only driver-specific options, i.e. the options for the general block layer as well as child nodes are already filtered out. Works much better this way. Signed-off-by: Kevin Wolf Reviewed-by: Max Reitz Reviewed-by: Alberto Garcia --- block.c | 5 ++++- block/blkdebug.c | 17 ++++++----------- block/blkverify.c | 2 +- block/nbd.c | 10 +++++----- block/quorum.c | 2 +- include/block/block_int.h | 2 +- 6 files changed, 18 insertions(+), 20 deletions(-) diff --git a/block.c b/block.c index fa351ac..c204d13 100644 --- a/block.c +++ b/block.c @@ -4027,7 +4027,10 @@ void bdrv_refresh_filename(BlockDriverState *bs) bs->full_open_options = NULL; } - drv->bdrv_refresh_filename(bs); + opts = qdict_new(); + append_open_options(opts, bs); + drv->bdrv_refresh_filename(bs, opts); + QDECREF(opts); } else if (bs->file) { /* Try to reconstruct valid information from the underlying file */ bool has_open_options; diff --git a/block/blkdebug.c b/block/blkdebug.c index 59c61eb..ba89e17 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -674,17 +674,15 @@ static int blkdebug_truncate(BlockDriverState *bs, int64_t offset) return bdrv_truncate(bs->file->bs, offset); } -static void blkdebug_refresh_filename(BlockDriverState *bs) +static void blkdebug_refresh_filename(BlockDriverState *bs, QDict *options) { QDict *opts; const QDictEntry *e; bool force_json = false; - for (e = qdict_first(bs->options); e; e = qdict_next(bs->options, e)) { + for (e = qdict_first(options); e; e = qdict_next(options, e)) { if (strcmp(qdict_entry_key(e), "config") && - strcmp(qdict_entry_key(e), "x-image") && - strcmp(qdict_entry_key(e), "image") && - strncmp(qdict_entry_key(e), "image.", strlen("image."))) + strcmp(qdict_entry_key(e), "x-image")) { force_json = true; break; @@ -700,7 +698,7 @@ static void blkdebug_refresh_filename(BlockDriverState *bs) if (!force_json && bs->file->bs->exact_filename[0]) { snprintf(bs->exact_filename, sizeof(bs->exact_filename), "blkdebug:%s:%s", - qdict_get_try_str(bs->options, "config") ?: "", + qdict_get_try_str(options, "config") ?: "", bs->file->bs->exact_filename); } @@ -710,11 +708,8 @@ static void blkdebug_refresh_filename(BlockDriverState *bs) QINCREF(bs->file->bs->full_open_options); qdict_put_obj(opts, "image", QOBJECT(bs->file->bs->full_open_options)); - for (e = qdict_first(bs->options); e; e = qdict_next(bs->options, e)) { - if (strcmp(qdict_entry_key(e), "x-image") && - strcmp(qdict_entry_key(e), "image") && - strncmp(qdict_entry_key(e), "image.", strlen("image."))) - { + for (e = qdict_first(options); e; e = qdict_next(options, e)) { + if (strcmp(qdict_entry_key(e), "x-image")) { qobject_incref(qdict_entry_value(e)); qdict_put_obj(opts, qdict_entry_key(e), qdict_entry_value(e)); } diff --git a/block/blkverify.c b/block/blkverify.c index c5f8e8d..1d75449 100644 --- a/block/blkverify.c +++ b/block/blkverify.c @@ -307,7 +307,7 @@ static void blkverify_attach_aio_context(BlockDriverState *bs, bdrv_attach_aio_context(s->test_file->bs, new_context); } -static void blkverify_refresh_filename(BlockDriverState *bs) +static void blkverify_refresh_filename(BlockDriverState *bs, QDict *options) { BDRVBlkverifyState *s = bs->opaque; diff --git a/block/nbd.c b/block/nbd.c index cd6a587..416f42b 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -342,13 +342,13 @@ static void nbd_attach_aio_context(BlockDriverState *bs, nbd_client_attach_aio_context(bs, new_context); } -static void nbd_refresh_filename(BlockDriverState *bs) +static void nbd_refresh_filename(BlockDriverState *bs, QDict *options) { QDict *opts = qdict_new(); - const char *path = qdict_get_try_str(bs->options, "path"); - const char *host = qdict_get_try_str(bs->options, "host"); - const char *port = qdict_get_try_str(bs->options, "port"); - const char *export = qdict_get_try_str(bs->options, "export"); + const char *path = qdict_get_try_str(options, "path"); + const char *host = qdict_get_try_str(options, "host"); + const char *port = qdict_get_try_str(options, "port"); + const char *export = qdict_get_try_str(options, "export"); qdict_put_obj(opts, "driver", QOBJECT(qstring_from_str("nbd"))); diff --git a/block/quorum.c b/block/quorum.c index d162459..6793f12 100644 --- a/block/quorum.c +++ b/block/quorum.c @@ -997,7 +997,7 @@ static void quorum_attach_aio_context(BlockDriverState *bs, } } -static void quorum_refresh_filename(BlockDriverState *bs) +static void quorum_refresh_filename(BlockDriverState *bs, QDict *options) { BDRVQuorumState *s = bs->opaque; QDict *opts; diff --git a/include/block/block_int.h b/include/block/block_int.h index 0284f81..98336f6 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -136,7 +136,7 @@ struct BlockDriver { int (*bdrv_set_key)(BlockDriverState *bs, const char *key); int (*bdrv_make_empty)(BlockDriverState *bs); - void (*bdrv_refresh_filename)(BlockDriverState *bs); + void (*bdrv_refresh_filename)(BlockDriverState *bs, QDict *options); /* aio */ BlockAIOCB *(*bdrv_aio_readv)(BlockDriverState *bs, -- cgit v1.1 From 62392ebb09fc6e87626aa151a616f24c4e921493 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 24 Apr 2015 16:38:02 +0200 Subject: block: Keep "driver" in bs->options Instead of passing a separate drv argument to bdrv_open_common(), just make sure that a "driver" option is set in the QDict. This also means that a "driver" entry is consistently present in bs->options now. This is another step towards keeping all options in the QDict (which is the represenation of the blockdev-add QMP command). Signed-off-by: Kevin Wolf Reviewed-by: Max Reitz --- block.c | 57 ++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/block.c b/block.c index c204d13..2c41fff 100644 --- a/block.c +++ b/block.c @@ -817,6 +817,11 @@ static QemuOptsList bdrv_runtime_opts = { .type = QEMU_OPT_STRING, .help = "Node name of the block device node", }, + { + .name = "driver", + .type = QEMU_OPT_STRING, + .help = "Block driver to use for the node", + }, { /* end of list */ } }, }; @@ -827,18 +832,31 @@ static QemuOptsList bdrv_runtime_opts = { * Removes all processed options from *options. */ static int bdrv_open_common(BlockDriverState *bs, BdrvChild *file, - QDict *options, int flags, BlockDriver *drv, Error **errp) + QDict *options, int flags, Error **errp) { int ret, open_flags; const char *filename; + const char *driver_name = NULL; const char *node_name = NULL; QemuOpts *opts; + BlockDriver *drv; Error *local_err = NULL; - assert(drv != NULL); assert(bs->file == NULL); assert(options != NULL && bs->options != options); + opts = qemu_opts_create(&bdrv_runtime_opts, NULL, 0, &error_abort); + qemu_opts_absorb_qdict(opts, options, &local_err); + if (local_err) { + error_propagate(errp, local_err); + ret = -EINVAL; + goto fail_opts; + } + + driver_name = qemu_opt_get(opts, "driver"); + drv = bdrv_find_format(driver_name); + assert(drv != NULL); + if (file != NULL) { filename = file->bs->filename; } else { @@ -848,19 +866,12 @@ static int bdrv_open_common(BlockDriverState *bs, BdrvChild *file, if (drv->bdrv_needs_filename && !filename) { error_setg(errp, "The '%s' block driver requires a file name", drv->format_name); - return -EINVAL; - } - - trace_bdrv_open_common(bs, filename ?: "", flags, drv->format_name); - - opts = qemu_opts_create(&bdrv_runtime_opts, NULL, 0, &error_abort); - qemu_opts_absorb_qdict(opts, options, &local_err); - if (local_err) { - error_propagate(errp, local_err); ret = -EINVAL; goto fail_opts; } + trace_bdrv_open_common(bs, filename ?: "", flags, drv->format_name); + node_name = qemu_opt_get(opts, "node-name"); bdrv_assign_node_name(bs, node_name, &local_err); if (local_err) { @@ -1477,11 +1488,14 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename, goto fail; } + bs->open_flags = flags; + bs->options = options; + options = qdict_clone_shallow(options); + /* Find the right image format driver */ drvname = qdict_get_try_str(options, "driver"); if (drvname) { drv = bdrv_find_format(drvname); - qdict_del(options, "driver"); if (!drv) { error_setg(errp, "Unknown driver: '%s'", drvname); ret = -EINVAL; @@ -1497,10 +1511,6 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename, qdict_del(options, "backing"); } - bs->open_flags = flags; - bs->options = options; - options = qdict_clone_shallow(options); - /* Open image file without format layer */ if ((flags & BDRV_O_PROTOCOL) == 0) { if (flags & BDRV_O_RDWR) { @@ -1528,6 +1538,19 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename, if (ret < 0) { goto fail; } + /* + * This option update would logically belong in bdrv_fill_options(), + * but we first need to open bs->file for the probing to work, while + * opening bs->file already requires the (mostly) final set of options + * so that cache mode etc. can be inherited. + * + * Adding the driver later is somewhat ugly, but it's not an option + * that would ever be inherited, so it's correct. We just need to make + * sure to update both bs->options (which has the full effective + * options for bs) and options (which has file.* already removed). + */ + qdict_put(bs->options, "driver", qstring_from_str(drv->format_name)); + qdict_put(options, "driver", qstring_from_str(drv->format_name)); } else if (!drv) { error_setg(errp, "Must specify either driver or file"); ret = -EINVAL; @@ -1541,7 +1564,7 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename, assert(!(flags & BDRV_O_PROTOCOL) || !file); /* Open the image */ - ret = bdrv_open_common(bs, file, options, flags, drv, &local_err); + ret = bdrv_open_common(bs, file, options, flags, &local_err); if (ret < 0) { goto fail; } -- cgit v1.1 From 4c9dfe5d8a7eb956513593720b8d1a9ca2c5a7f9 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 8 May 2015 15:14:15 +0200 Subject: block: Allow specifying child options in reopen If the child was defined in the same context (-drive argument or blockdev-add QMP command) as its parent, a reopen of the parent should work the same and allow changing options of the child. Signed-off-by: Kevin Wolf Reviewed-by: Max Reitz Reviewed-by: Alberto Garcia --- block.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/block.c b/block.c index 2c41fff..9c42b17 100644 --- a/block.c +++ b/block.c @@ -1720,15 +1720,23 @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue, flags &= ~BDRV_O_PROTOCOL; QLIST_FOREACH(child, &bs->children, next) { + QDict *new_child_options; + char *child_key_dot; int child_flags; + /* reopen can only change the options of block devices that were + * implicitly created and inherited options. For other (referenced) + * block devices, a syntax like "backing.foo" results in an error. */ if (child->bs->inherits_from != bs) { continue; } + child_key_dot = g_strdup_printf("%s.", child->name); + qdict_extract_subqdict(options, &new_child_options, child_key_dot); + g_free(child_key_dot); + child_flags = child->role->inherit_flags(flags); - /* TODO Pass down child flags (backing.*, extents.*, ...) */ - bdrv_reopen_queue(bs_queue, child->bs, NULL, child_flags); + bdrv_reopen_queue(bs_queue, child->bs, new_child_options, child_flags); } bs_entry = g_new0(BlockReopenQueueEntry, 1); -- cgit v1.1 From 2851810223a6f2a3f6c00613477feb6e33c10d34 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 8 May 2015 17:07:31 +0200 Subject: block: reopen: Document option precedence and refactor accordingly The interesting part of reopening an image is from which sources the effective options should be taken, i.e. which options take precedence over which other options. This patch documents the precedence that will be implemented in the following patches. It also refactors bdrv_reopen_queue(), so that the top-level reopened node is handled the same way as children are. Option/flag inheritance from the parent becomes just one item in the list and is done at the beginning of the function, similar to how the other items are/will be handled. Signed-off-by: Kevin Wolf Reviewed-by: Max Reitz --- block.c | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/block.c b/block.c index 9c42b17..5fd6c44 100644 --- a/block.c +++ b/block.c @@ -1693,9 +1693,13 @@ typedef struct BlockReopenQueueEntry { * bs_queue, or the existing bs_queue being used. * */ -BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue, - BlockDriverState *bs, - QDict *options, int flags) +static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, + BlockDriverState *bs, + QDict *options, + int flags, + const BdrvChildRole *role, + QDict *parent_options, + int parent_flags) { assert(bs != NULL); @@ -1712,6 +1716,22 @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue, options = qdict_new(); } + /* + * Precedence of options: + * 1. Explicitly passed in options (highest) + * 2. TODO Set in flags (only for top level) + * 3. TODO Retained from explicitly set options of bs + * 4. TODO Inherited from parent node + * 5. Retained from effective options of bs + */ + + /* Inherit from parent node */ + if (parent_options) { + assert(!flags); + flags = role->inherit_flags(parent_flags); + } + + /* Old values are used for options that aren't set yet */ old_options = qdict_clone_shallow(bs->options); bdrv_join_options(bs, options, old_options); QDECREF(old_options); @@ -1722,7 +1742,6 @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue, QLIST_FOREACH(child, &bs->children, next) { QDict *new_child_options; char *child_key_dot; - int child_flags; /* reopen can only change the options of block devices that were * implicitly created and inherited options. For other (referenced) @@ -1735,8 +1754,8 @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue, qdict_extract_subqdict(options, &new_child_options, child_key_dot); g_free(child_key_dot); - child_flags = child->role->inherit_flags(flags); - bdrv_reopen_queue(bs_queue, child->bs, new_child_options, child_flags); + bdrv_reopen_queue_child(bs_queue, child->bs, new_child_options, 0, + child->role, options, flags); } bs_entry = g_new0(BlockReopenQueueEntry, 1); @@ -1749,6 +1768,14 @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue, return bs_queue; } +BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue, + BlockDriverState *bs, + QDict *options, int flags) +{ + return bdrv_reopen_queue_child(bs_queue, bs, options, flags, + NULL, NULL, 0); +} + /* * Reopen multiple BlockDriverStates atomically & transactionally. * -- cgit v1.1 From 8e2160e2c75522554647e197e8b61622d6cf076f Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Wed, 29 Apr 2015 17:29:39 +0200 Subject: block: Add infrastructure for option inheritance Options are not actually inherited from the parent node yet, but this commit lays the grounds for doing so. Signed-off-by: Kevin Wolf Reviewed-by: Max Reitz --- block.c | 52 ++++++++++++++++++++++++++++------------------- include/block/block_int.h | 3 ++- 2 files changed, 33 insertions(+), 22 deletions(-) diff --git a/block.c b/block.c index 5fd6c44..6c940a7 100644 --- a/block.c +++ b/block.c @@ -695,11 +695,14 @@ static int bdrv_temp_snapshot_flags(int flags) } /* - * Returns the flags that bs->file should get if a protocol driver is expected, - * based on the given flags for the parent BDS + * Returns the options and flags that bs->file should get if a protocol driver + * is expected, based on the given options and flags for the parent BDS */ -static int bdrv_inherited_flags(int flags) +static void bdrv_inherited_options(int *child_flags, QDict *child_options, + int parent_flags, QDict *parent_options) { + int flags = parent_flags; + /* Enable protocol handling, disable format probing for bs->file */ flags |= BDRV_O_PROTOCOL; @@ -710,45 +713,51 @@ static int bdrv_inherited_flags(int flags) /* Clear flags that only apply to the top layer */ flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING | BDRV_O_COPY_ON_READ); - return flags; + *child_flags = flags; } const BdrvChildRole child_file = { - .inherit_flags = bdrv_inherited_flags, + .inherit_options = bdrv_inherited_options, }; /* - * Returns the flags that bs->file should get if the use of formats (and not - * only protocols) is permitted for it, based on the given flags for the parent - * BDS + * Returns the options and flags that bs->file should get if the use of formats + * (and not only protocols) is permitted for it, based on the given options and + * flags for the parent BDS */ -static int bdrv_inherited_fmt_flags(int parent_flags) +static void bdrv_inherited_fmt_options(int *child_flags, QDict *child_options, + int parent_flags, QDict *parent_options) { - int flags = child_file.inherit_flags(parent_flags); - return flags & ~BDRV_O_PROTOCOL; + child_file.inherit_options(child_flags, child_options, + parent_flags, parent_options); + + *child_flags &= ~BDRV_O_PROTOCOL; } const BdrvChildRole child_format = { - .inherit_flags = bdrv_inherited_fmt_flags, + .inherit_options = bdrv_inherited_fmt_options, }; /* - * Returns the flags that bs->backing should get, based on the given flags - * for the parent BDS + * Returns the options and flags that bs->backing should get, based on the + * given options and flags for the parent BDS */ -static int bdrv_backing_flags(int flags) +static void bdrv_backing_options(int *child_flags, QDict *child_options, + int parent_flags, QDict *parent_options) { + int flags = parent_flags; + /* backing files always opened read-only */ flags &= ~(BDRV_O_RDWR | BDRV_O_COPY_ON_READ); /* snapshot=on is handled on the top layer */ flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_TEMPORARY); - return flags; + *child_flags = flags; } static const BdrvChildRole child_backing = { - .inherit_flags = bdrv_backing_flags, + .inherit_options = bdrv_backing_options, }; static int bdrv_open_flags(BlockDriverState *bs, int flags) @@ -1480,7 +1489,8 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename, if (child_role) { bs->inherits_from = parent; - flags = child_role->inherit_flags(parent->open_flags); + child_role->inherit_options(&flags, options, + parent->open_flags, parent->options); } ret = bdrv_fill_options(&options, &filename, &flags, &local_err); @@ -1518,7 +1528,7 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename, } if (flags & BDRV_O_SNAPSHOT) { snapshot_flags = bdrv_temp_snapshot_flags(flags); - flags = bdrv_backing_flags(flags); + bdrv_backing_options(&flags, options, flags, options); } bs->open_flags = flags; @@ -1721,14 +1731,14 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, * 1. Explicitly passed in options (highest) * 2. TODO Set in flags (only for top level) * 3. TODO Retained from explicitly set options of bs - * 4. TODO Inherited from parent node + * 4. Inherited from parent node * 5. Retained from effective options of bs */ /* Inherit from parent node */ if (parent_options) { assert(!flags); - flags = role->inherit_flags(parent_flags); + role->inherit_options(&flags, options, parent_flags, parent_options); } /* Old values are used for options that aren't set yet */ diff --git a/include/block/block_int.h b/include/block/block_int.h index 98336f6..abb6224 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -343,7 +343,8 @@ typedef struct BdrvAioNotifier { } BdrvAioNotifier; struct BdrvChildRole { - int (*inherit_flags)(int parent_flags); + void (*inherit_options)(int *child_flags, QDict *child_options, + int parent_flags, QDict *parent_options); }; extern const BdrvChildRole child_file; -- cgit v1.1 From de3b53f00761d32b7363f25135b0807d8927c0ec Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 29 Oct 2015 15:24:41 +0100 Subject: block: Split out parse_json_protocol() The next patch distinguishes options that were explicitly set and options that were derived. bdrv_fill_option() added options of both types: Options given by json: syntax should be counted as explicit, but the rest is derived. In preparation for the distinction, move json: parse to a separate function. Signed-off-by: Kevin Wolf Reviewed-by: Max Reitz --- block.c | 50 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/block.c b/block.c index 6c940a7..5bf3e22 100644 --- a/block.c +++ b/block.c @@ -1018,37 +1018,45 @@ static QDict *parse_json_filename(const char *filename, Error **errp) return options; } +static void parse_json_protocol(QDict *options, const char **pfilename, + Error **errp) +{ + QDict *json_options; + Error *local_err = NULL; + + /* Parse json: pseudo-protocol */ + if (!*pfilename || !g_str_has_prefix(*pfilename, "json:")) { + return; + } + + json_options = parse_json_filename(*pfilename, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + + /* Options given in the filename have lower priority than options + * specified directly */ + qdict_join(options, json_options, false); + QDECREF(json_options); + *pfilename = NULL; +} + /* * Fills in default options for opening images and converts the legacy * filename/flags pair to option QDict entries. * The BDRV_O_PROTOCOL flag in *flags will be set or cleared accordingly if a * block driver has been specified explicitly. */ -static int bdrv_fill_options(QDict **options, const char **pfilename, +static int bdrv_fill_options(QDict **options, const char *filename, int *flags, Error **errp) { - const char *filename = *pfilename; const char *drvname; bool protocol = *flags & BDRV_O_PROTOCOL; bool parse_filename = false; BlockDriver *drv = NULL; Error *local_err = NULL; - /* Parse json: pseudo-protocol */ - if (filename && g_str_has_prefix(filename, "json:")) { - QDict *json_options = parse_json_filename(filename, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return -EINVAL; - } - - /* Options given in the filename have lower priority than options - * specified directly */ - qdict_join(*options, json_options, false); - QDECREF(json_options); - *pfilename = filename = NULL; - } - drvname = qdict_get_try_str(*options, "driver"); if (drvname) { drv = bdrv_find_format(drvname); @@ -1487,13 +1495,19 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename, options = qdict_new(); } + parse_json_protocol(options, &filename, &local_err); + if (local_err) { + ret = -EINVAL; + goto fail; + } + if (child_role) { bs->inherits_from = parent; child_role->inherit_options(&flags, options, parent->open_flags, parent->options); } - ret = bdrv_fill_options(&options, &filename, &flags, &local_err); + ret = bdrv_fill_options(&options, filename, &flags, &local_err); if (local_err) { goto fail; } -- cgit v1.1 From 145f598e4a96f6bb78664852bd589e4ea326be94 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 8 May 2015 16:15:03 +0200 Subject: block: Introduce bs->explicit_options bs->options doesn't only contain options that the user explicitly requested, but also option that were derived from flags, the filename or inherited from the parent node. For reopen, it is important to know the difference because reopening the parent can change inherited values in child nodes, but it shouldn't change any options that were explicitly specified for the child. Signed-off-by: Kevin Wolf Reviewed-by: Max Reitz --- block.c | 24 ++++++++++++++++++++++-- include/block/block.h | 1 + include/block/block_int.h | 1 + 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/block.c b/block.c index 5bf3e22..a22c47c 100644 --- a/block.c +++ b/block.c @@ -1495,12 +1495,15 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename, options = qdict_new(); } + /* json: syntax counts as explicit options, as if in the QDict */ parse_json_protocol(options, &filename, &local_err); if (local_err) { ret = -EINVAL; goto fail; } + bs->explicit_options = qdict_clone_shallow(options); + if (child_role) { bs->inherits_from = parent; child_role->inherit_options(&flags, options, @@ -1655,6 +1658,7 @@ fail: if (file != NULL) { bdrv_unref_child(bs, file); } + QDECREF(bs->explicit_options); QDECREF(bs->options); QDECREF(options); bs->options = NULL; @@ -1729,7 +1733,7 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, BlockReopenQueueEntry *bs_entry; BdrvChild *child; - QDict *old_options; + QDict *old_options, *explicit_options; if (bs_queue == NULL) { bs_queue = g_new0(BlockReopenQueue, 1); @@ -1744,11 +1748,18 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, * Precedence of options: * 1. Explicitly passed in options (highest) * 2. TODO Set in flags (only for top level) - * 3. TODO Retained from explicitly set options of bs + * 3. Retained from explicitly set options of bs * 4. Inherited from parent node * 5. Retained from effective options of bs */ + /* Old explicitly set values (don't overwrite by inherited value) */ + old_options = qdict_clone_shallow(bs->explicit_options); + bdrv_join_options(bs, options, old_options); + QDECREF(old_options); + + explicit_options = qdict_clone_shallow(options); + /* Inherit from parent node */ if (parent_options) { assert(!flags); @@ -1787,6 +1798,7 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, bs_entry->state.bs = bs; bs_entry->state.options = options; + bs_entry->state.explicit_options = explicit_options; bs_entry->state.flags = flags; return bs_queue; @@ -1846,6 +1858,8 @@ cleanup: QSIMPLEQ_FOREACH_SAFE(bs_entry, bs_queue, entry, next) { if (ret && bs_entry->prepared) { bdrv_reopen_abort(&bs_entry->state); + } else if (ret) { + QDECREF(bs_entry->state.explicit_options); } QDECREF(bs_entry->state.options); g_free(bs_entry); @@ -1980,6 +1994,9 @@ void bdrv_reopen_commit(BDRVReopenState *reopen_state) } /* set BDS specific flags now */ + QDECREF(reopen_state->bs->explicit_options); + + reopen_state->bs->explicit_options = reopen_state->explicit_options; reopen_state->bs->open_flags = reopen_state->flags; reopen_state->bs->enable_write_cache = !!(reopen_state->flags & BDRV_O_CACHE_WB); @@ -2003,6 +2020,8 @@ void bdrv_reopen_abort(BDRVReopenState *reopen_state) if (drv->bdrv_reopen_abort) { drv->bdrv_reopen_abort(reopen_state); } + + QDECREF(reopen_state->explicit_options); } @@ -2061,6 +2080,7 @@ void bdrv_close(BlockDriverState *bs) bs->sg = 0; bs->zero_beyond_eof = false; QDECREF(bs->options); + QDECREF(bs->explicit_options); bs->options = NULL; QDECREF(bs->full_open_options); bs->full_open_options = NULL; diff --git a/include/block/block.h b/include/block/block.h index 2e77288..121544b 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -150,6 +150,7 @@ typedef struct BDRVReopenState { BlockDriverState *bs; int flags; QDict *options; + QDict *explicit_options; void *opaque; } BDRVReopenState; diff --git a/include/block/block_int.h b/include/block/block_int.h index abb6224..edfe376 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -459,6 +459,7 @@ struct BlockDriverState { QLIST_HEAD(, BdrvChild) parents; QDict *options; + QDict *explicit_options; BlockdevDetectZeroesOptions detect_zeroes; /* The error object in use for blocking operations on backing_hd */ -- cgit v1.1 From 39c4ae941ed992a3bb5647fe7fafdd66d9278f43 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 13 Nov 2015 14:45:42 +0100 Subject: blockdev: Set 'format' indicates non-empty drive Creating an empty drive while specifying 'format' doesn't make sense. The specified format driver would simply be ignored. Make a set 'format' option an indication that a non-empty drive should be created. This makes 'format' consistent with 'driver' and allows using it with a block driver that doesn't need any other options (like null-co/null-aio). Signed-off-by: Kevin Wolf Reviewed-by: Max Reitz --- blockdev.c | 5 +---- tests/hd-geo-test.c | 4 ++-- tests/qemu-iotests/iotests.py | 2 +- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/blockdev.c b/blockdev.c index 13eaa77..2f88004 100644 --- a/blockdev.c +++ b/blockdev.c @@ -490,7 +490,6 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, QDict *interval_dict = NULL; QList *interval_list = NULL; const char *id; - bool has_driver_specific_opts; BlockdevDetectZeroesOptions detect_zeroes = BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF; const char *throttling_group = NULL; @@ -514,8 +513,6 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, qdict_del(bs_opts, "id"); } - has_driver_specific_opts = !!qdict_size(bs_opts); - /* extract parameters */ snapshot = qemu_opt_get_bool(opts, "snapshot", 0); @@ -578,7 +575,7 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, } /* init */ - if ((!file || !*file) && !has_driver_specific_opts) { + if ((!file || !*file) && !qdict_size(bs_opts)) { BlockBackendRootState *blk_rs; blk = blk_new(qemu_opts_id(opts), errp); diff --git a/tests/hd-geo-test.c b/tests/hd-geo-test.c index 00afc20..13b763d 100644 --- a/tests/hd-geo-test.c +++ b/tests/hd-geo-test.c @@ -206,13 +206,13 @@ static int setup_ide(int argc, char *argv[], int argv_sz, { char *s1, *s2, *s3; - s1 = g_strdup_printf("-drive id=drive%d,if=%s,format=raw", + s1 = g_strdup_printf("-drive id=drive%d,if=%s", ide_idx, dev ? "none" : "ide"); s2 = dev ? g_strdup("") : g_strdup_printf(",index=%d", ide_idx); if (img_secs[img_idx] >= 0) { setup_mbr(img_idx, mbr); - s3 = g_strdup_printf(",file=%s", img_file_name[img_idx]); + s3 = g_strdup_printf(",format=raw,file=%s", img_file_name[img_idx]); } else { s3 = g_strdup(",media=cdrom"); } diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index e02245e..27eddec 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -148,12 +148,12 @@ class VM(object): def add_drive(self, path, opts='', interface='virtio'): '''Add a virtio-blk drive to the VM''' options = ['if=%s' % interface, - 'format=%s' % imgfmt, 'cache=%s' % cachemode, 'id=drive%d' % self._num_drives] if path is not None: options.append('file=%s' % path) + options.append('format=%s' % imgfmt) if opts: options.append(opts) -- cgit v1.1 From fc17c259314d066109eb3810e2a83348d531426a Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 7 May 2015 14:41:30 +0200 Subject: qemu-iotests: Remove cache mode test without medium Specifying the cache mode for a driver without a medium is not a useful thing to do: As long as there is no medium, the cache mode doesn't make a difference, and once the 'change' command is used to insert a medium, it ignores the old cache mode and makes the new medium use cache=writethrough. Later patches will make it an error to specify the cache mode for an empty drive. Remove the corresponding test case. Signed-off-by: Kevin Wolf Reviewed-by: Max Reitz --- tests/qemu-iotests/051 | 12 ++++++------ tests/qemu-iotests/051.out | 14 +++++++------- tests/qemu-iotests/iotests.py | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051 index 17dbf04..f6f0f4d 100755 --- a/tests/qemu-iotests/051 +++ b/tests/qemu-iotests/051 @@ -183,12 +183,12 @@ echo # Cannot use the test image because cache=none might not work on the host FS # Use cdrom so that we won't get errors about missing media -run_qemu -drive media=cdrom,cache=none -run_qemu -drive media=cdrom,cache=directsync -run_qemu -drive media=cdrom,cache=writeback -run_qemu -drive media=cdrom,cache=writethrough -run_qemu -drive media=cdrom,cache=unsafe -run_qemu -drive media=cdrom,cache=invalid_value +run_qemu -drive driver=null-co,cache=none +run_qemu -drive driver=null-co,cache=directsync +run_qemu -drive driver=null-co,cache=writeback +run_qemu -drive driver=null-co,cache=writethrough +run_qemu -drive driver=null-co,cache=unsafe +run_qemu -drive driver=null-co,cache=invalid_value echo echo === Specifying the protocol layer === diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out index 7765aa0..7a459a3 100644 --- a/tests/qemu-iotests/051.out +++ b/tests/qemu-iotests/051.out @@ -215,28 +215,28 @@ QEMU X.Y.Z monitor - type 'help' for more information === Cache modes === -Testing: -drive media=cdrom,cache=none +Testing: -drive driver=null-co,cache=none QEMU X.Y.Z monitor - type 'help' for more information (qemu) qququiquit -Testing: -drive media=cdrom,cache=directsync +Testing: -drive driver=null-co,cache=directsync QEMU X.Y.Z monitor - type 'help' for more information (qemu) qququiquit -Testing: -drive media=cdrom,cache=writeback +Testing: -drive driver=null-co,cache=writeback QEMU X.Y.Z monitor - type 'help' for more information (qemu) qququiquit -Testing: -drive media=cdrom,cache=writethrough +Testing: -drive driver=null-co,cache=writethrough QEMU X.Y.Z monitor - type 'help' for more information (qemu) qququiquit -Testing: -drive media=cdrom,cache=unsafe +Testing: -drive driver=null-co,cache=unsafe QEMU X.Y.Z monitor - type 'help' for more information (qemu) qququiquit -Testing: -drive media=cdrom,cache=invalid_value -QEMU_PROG: -drive media=cdrom,cache=invalid_value: invalid cache option +Testing: -drive driver=null-co,cache=invalid_value +QEMU_PROG: -drive driver=null-co,cache=invalid_value: invalid cache option === Specifying the protocol layer === diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 27eddec..0a238ec 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -148,12 +148,12 @@ class VM(object): def add_drive(self, path, opts='', interface='virtio'): '''Add a virtio-blk drive to the VM''' options = ['if=%s' % interface, - 'cache=%s' % cachemode, 'id=drive%d' % self._num_drives] if path is not None: options.append('file=%s' % path) options.append('format=%s' % imgfmt) + options.append('cache=%s' % cachemode) if opts: options.append(opts) -- cgit v1.1 From ccf9dc07b5c8f3b927d53e9ef8c712c2973d79c7 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 8 May 2015 17:24:56 +0200 Subject: block: reopen: Extract QemuOpts for generic block layer options This patch adds a QemuOpts for generic block layer options to bdrv_reopen_prepare(). The only two options that currently exist (node-name and driver) cannot be changed, so the only thing we do is putting them right back into the QDict so that we check at the end that they are indeed unchanged. We will add new options soon that can actually be changed. Signed-off-by: Kevin Wolf Reviewed-by: Max Reitz --- block.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/block.c b/block.c index a22c47c..d0d9669 100644 --- a/block.c +++ b/block.c @@ -1907,11 +1907,34 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue, int ret = -1; Error *local_err = NULL; BlockDriver *drv; + QemuOpts *opts; + const char *value; assert(reopen_state != NULL); assert(reopen_state->bs->drv != NULL); drv = reopen_state->bs->drv; + /* Process generic block layer options */ + opts = qemu_opts_create(&bdrv_runtime_opts, NULL, 0, &error_abort); + qemu_opts_absorb_qdict(opts, reopen_state->options, &local_err); + if (local_err) { + error_propagate(errp, local_err); + ret = -EINVAL; + goto error; + } + + /* node-name and driver must be unchanged. Put them back into the QDict, so + * that they are checked at the end of this function. */ + value = qemu_opt_get(opts, "node-name"); + if (value) { + qdict_put(reopen_state->options, "node-name", qstring_from_str(value)); + } + + value = qemu_opt_get(opts, "driver"); + if (value) { + qdict_put(reopen_state->options, "driver", qstring_from_str(value)); + } + /* if we are to stay read-only, do not allow permission change * to r/w */ if (!(reopen_state->bs->open_flags & BDRV_O_ALLOW_RDWR) && @@ -1972,6 +1995,7 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue, ret = 0; error: + qemu_opts_del(opts); return ret; } -- cgit v1.1 From 91a097e7478940483e76d52217f05bc05b98d5a5 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 8 May 2015 17:49:53 +0200 Subject: block: Move cache options into options QDict This adds the cache mode options to the QDict, so that they can be specified for child nodes (e.g. backing.cache.direct=off). The cache modes are not removed from the flags at this point; instead, options and flags are kept in sync. If the user specifies both flags and options, the options take precedence. Child node inherit cache modes as options now, they don't use flags any more. Note that this forbids specifying the cache mode for empty drives. It didn't make sense anyway to specify it there, because it didn't have any effect. blockdev_init() considers the cache options now bdrv_open() options and therefore doesn't create an empty drive any more but calls into bdrv_open(). This in turn will fail with no driver and filename specified. Signed-off-by: Kevin Wolf Reviewed-by: Max Reitz --- block.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- blockdev.c | 52 ++++++++++---------------------- 2 files changed, 111 insertions(+), 41 deletions(-) diff --git a/block.c b/block.c index d0d9669..1894f1b 100644 --- a/block.c +++ b/block.c @@ -29,6 +29,7 @@ #include "qemu/error-report.h" #include "qemu/module.h" #include "qapi/qmp/qerror.h" +#include "qapi/qmp/qbool.h" #include "qapi/qmp/qjson.h" #include "sysemu/block-backend.h" #include "sysemu/sysemu.h" @@ -706,9 +707,16 @@ static void bdrv_inherited_options(int *child_flags, QDict *child_options, /* Enable protocol handling, disable format probing for bs->file */ flags |= BDRV_O_PROTOCOL; + /* If the cache mode isn't explicitly set, inherit direct and no-flush from + * the parent. */ + qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_DIRECT); + qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_NO_FLUSH); + /* Our block drivers take care to send flushes and respect unmap policy, - * so we can enable both unconditionally on lower layers. */ - flags |= BDRV_O_CACHE_WB | BDRV_O_UNMAP; + * so we can default to enable both on lower layers regardless of the + * corresponding parent options. */ + qdict_set_default_str(child_options, BDRV_OPT_CACHE_WB, "on"); + flags |= BDRV_O_UNMAP; /* Clear flags that only apply to the top layer */ flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING | BDRV_O_COPY_ON_READ); @@ -747,6 +755,11 @@ static void bdrv_backing_options(int *child_flags, QDict *child_options, { int flags = parent_flags; + /* The cache mode is inherited unmodified for backing files */ + qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_WB); + qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_DIRECT); + qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_NO_FLUSH); + /* backing files always opened read-only */ flags &= ~(BDRV_O_RDWR | BDRV_O_COPY_ON_READ); @@ -780,6 +793,42 @@ static int bdrv_open_flags(BlockDriverState *bs, int flags) return open_flags; } +static void update_flags_from_options(int *flags, QemuOpts *opts) +{ + *flags &= ~BDRV_O_CACHE_MASK; + + assert(qemu_opt_find(opts, BDRV_OPT_CACHE_WB)); + if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_WB, false)) { + *flags |= BDRV_O_CACHE_WB; + } + + assert(qemu_opt_find(opts, BDRV_OPT_CACHE_NO_FLUSH)); + if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_NO_FLUSH, false)) { + *flags |= BDRV_O_NO_FLUSH; + } + + assert(qemu_opt_find(opts, BDRV_OPT_CACHE_DIRECT)); + if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_DIRECT, false)) { + *flags |= BDRV_O_NOCACHE; + } +} + +static void update_options_from_flags(QDict *options, int flags) +{ + if (!qdict_haskey(options, BDRV_OPT_CACHE_WB)) { + qdict_put(options, BDRV_OPT_CACHE_WB, + qbool_from_bool(flags & BDRV_O_CACHE_WB)); + } + if (!qdict_haskey(options, BDRV_OPT_CACHE_DIRECT)) { + qdict_put(options, BDRV_OPT_CACHE_DIRECT, + qbool_from_bool(flags & BDRV_O_NOCACHE)); + } + if (!qdict_haskey(options, BDRV_OPT_CACHE_NO_FLUSH)) { + qdict_put(options, BDRV_OPT_CACHE_NO_FLUSH, + qbool_from_bool(flags & BDRV_O_NO_FLUSH)); + } +} + static void bdrv_assign_node_name(BlockDriverState *bs, const char *node_name, Error **errp) @@ -831,6 +880,21 @@ static QemuOptsList bdrv_runtime_opts = { .type = QEMU_OPT_STRING, .help = "Block driver to use for the node", }, + { + .name = BDRV_OPT_CACHE_WB, + .type = QEMU_OPT_BOOL, + .help = "Enable writeback mode", + }, + { + .name = BDRV_OPT_CACHE_DIRECT, + .type = QEMU_OPT_BOOL, + .help = "Bypass software writeback cache on the host", + }, + { + .name = BDRV_OPT_CACHE_NO_FLUSH, + .type = QEMU_OPT_BOOL, + .help = "Ignore flush requests", + }, { /* end of list */ } }, }; @@ -925,7 +989,9 @@ static int bdrv_open_common(BlockDriverState *bs, BdrvChild *file, bs->drv = drv; bs->opaque = g_malloc0(drv->instance_size); - bs->enable_write_cache = !!(flags & BDRV_O_CACHE_WB); + /* Apply cache mode options */ + update_flags_from_options(&bs->open_flags, opts); + bdrv_set_enable_write_cache(bs, bs->open_flags & BDRV_O_CACHE_WB); /* Open the image, either directly or using a protocol */ if (drv->bdrv_file_open) { @@ -1075,6 +1141,9 @@ static int bdrv_fill_options(QDict **options, const char *filename, *flags &= ~BDRV_O_PROTOCOL; } + /* Translate cache options from flags into options */ + update_options_from_flags(*options, *flags); + /* Fetch the file name from the options QDict if necessary */ if (protocol && filename) { if (!qdict_haskey(*options, "filename")) { @@ -1747,12 +1816,22 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, /* * Precedence of options: * 1. Explicitly passed in options (highest) - * 2. TODO Set in flags (only for top level) + * 2. Set in flags (only for top level) * 3. Retained from explicitly set options of bs * 4. Inherited from parent node * 5. Retained from effective options of bs */ + if (!parent_options) { + /* + * Any setting represented by flags is always updated. If the + * corresponding QDict option is set, it takes precedence. Otherwise + * the flag is translated into a QDict option. The old setting of bs is + * not considered. + */ + update_options_from_flags(options, flags); + } + /* Old explicitly set values (don't overwrite by inherited value) */ old_options = qdict_clone_shallow(bs->explicit_options); bdrv_join_options(bs, options, old_options); @@ -1923,6 +2002,19 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue, goto error; } + update_flags_from_options(&reopen_state->flags, opts); + + /* If a guest device is attached, it owns WCE */ + if (reopen_state->bs->blk && blk_get_attached_dev(reopen_state->bs->blk)) { + bool old_wce = bdrv_enable_write_cache(reopen_state->bs); + bool new_wce = (reopen_state->flags & BDRV_O_CACHE_WB); + if (old_wce != new_wce) { + error_setg(errp, "Cannot change cache.writeback: Device attached"); + ret = -EINVAL; + goto error; + } + } + /* node-name and driver must be unchanged. Put them back into the QDict, so * that they are checked at the end of this function. */ value = qemu_opt_get(opts, "node-name"); diff --git a/blockdev.c b/blockdev.c index 2f88004..64dbfeb 100644 --- a/blockdev.c +++ b/blockdev.c @@ -387,16 +387,6 @@ static void extract_common_blockdev_options(QemuOpts *opts, int *bdrv_flags, } } - if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_WB, true)) { - *bdrv_flags |= BDRV_O_CACHE_WB; - } - if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_DIRECT, false)) { - *bdrv_flags |= BDRV_O_NOCACHE; - } - if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_NO_FLUSH, false)) { - *bdrv_flags |= BDRV_O_NO_FLUSH; - } - if ((aio = qemu_opt_get(opts, "aio")) != NULL) { if (!strcmp(aio, "native")) { *bdrv_flags |= BDRV_O_NATIVE_AIO; @@ -569,9 +559,7 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, } if (snapshot) { - /* always use cache=unsafe with snapshot */ - bdrv_flags &= ~BDRV_O_CACHE_MASK; - bdrv_flags |= (BDRV_O_SNAPSHOT|BDRV_O_CACHE_WB|BDRV_O_NO_FLUSH); + bdrv_flags |= BDRV_O_SNAPSHOT; } /* init */ @@ -603,6 +591,20 @@ static BlockBackend *blockdev_init(const char *file, QDict *bs_opts, file = NULL; } + /* bdrv_open() defaults to the values in bdrv_flags (for compatibility + * with other callers) rather than what we want as the real defaults. + * Apply the defaults here instead. */ + qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_WB, "on"); + qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_DIRECT, "off"); + qdict_set_default_str(bs_opts, BDRV_OPT_CACHE_NO_FLUSH, "off"); + + if (snapshot) { + /* always use cache=unsafe with snapshot */ + qdict_put(bs_opts, BDRV_OPT_CACHE_WB, qstring_from_str("on")); + qdict_put(bs_opts, BDRV_OPT_CACHE_DIRECT, qstring_from_str("off")); + qdict_put(bs_opts, BDRV_OPT_CACHE_NO_FLUSH, qstring_from_str("on")); + } + blk = blk_new_open(qemu_opts_id(opts), file, NULL, bs_opts, bdrv_flags, errp); if (!blk) { @@ -3870,18 +3872,6 @@ QemuOptsList qemu_common_drive_opts = { .type = QEMU_OPT_STRING, .help = "discard operation (ignore/off, unmap/on)", },{ - .name = BDRV_OPT_CACHE_WB, - .type = QEMU_OPT_BOOL, - .help = "enables writeback mode for any caches", - },{ - .name = BDRV_OPT_CACHE_DIRECT, - .type = QEMU_OPT_BOOL, - .help = "enables use of O_DIRECT (bypass the host page cache)", - },{ - .name = BDRV_OPT_CACHE_NO_FLUSH, - .type = QEMU_OPT_BOOL, - .help = "ignore any flush requests for the device", - },{ .name = "aio", .type = QEMU_OPT_STRING, .help = "host AIO implementation (threads, native)", @@ -3989,18 +3979,6 @@ static QemuOptsList qemu_root_bds_opts = { .type = QEMU_OPT_STRING, .help = "discard operation (ignore/off, unmap/on)", },{ - .name = "cache.writeback", - .type = QEMU_OPT_BOOL, - .help = "enables writeback mode for any caches", - },{ - .name = "cache.direct", - .type = QEMU_OPT_BOOL, - .help = "enables use of O_DIRECT (bypass the host page cache)", - },{ - .name = "cache.no-flush", - .type = QEMU_OPT_BOOL, - .help = "ignore any flush requests for the device", - },{ .name = "aio", .type = QEMU_OPT_STRING, .help = "host AIO implementation (threads, native)", -- cgit v1.1 From c5e8bfb7cdc1859d7c34565a5f39231f0809fcd4 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 29 Oct 2015 15:22:27 +0100 Subject: blkdebug: Enable reopen Just reopening the children (as block.c does now) is enough. Signed-off-by: Kevin Wolf Reviewed-by: Max Reitz Reviewed-by: Alberto Garcia --- block/blkdebug.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/block/blkdebug.c b/block/blkdebug.c index ba89e17..86b143d 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -718,6 +718,12 @@ static void blkdebug_refresh_filename(BlockDriverState *bs, QDict *options) bs->full_open_options = opts; } +static int blkdebug_reopen_prepare(BDRVReopenState *reopen_state, + BlockReopenQueue *queue, Error **errp) +{ + return 0; +} + static BlockDriver bdrv_blkdebug = { .format_name = "blkdebug", .protocol_name = "blkdebug", @@ -726,6 +732,7 @@ static BlockDriver bdrv_blkdebug = { .bdrv_parse_filename = blkdebug_parse_filename, .bdrv_file_open = blkdebug_open, .bdrv_close = blkdebug_close, + .bdrv_reopen_prepare = blkdebug_reopen_prepare, .bdrv_getlength = blkdebug_getlength, .bdrv_truncate = blkdebug_truncate, .bdrv_refresh_filename = blkdebug_refresh_filename, -- cgit v1.1 From 768ee459f5d1c1bbff432e3a3737543d4132461b Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 8 May 2015 18:03:15 +0200 Subject: qemu-iotests: Try setting cache mode for children This is a basic test for specifying cache modes for child nodes on the command line. It doesn't take much time and works without O_DIRECT support. Signed-off-by: Kevin Wolf Reviewed-by: Max Reitz --- tests/qemu-iotests/051 | 10 +++++++- tests/qemu-iotests/051.out | 60 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051 index f6f0f4d..da90f59 100755 --- a/tests/qemu-iotests/051 +++ b/tests/qemu-iotests/051 @@ -61,7 +61,7 @@ function do_run_qemu() function run_qemu() { - do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu + do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_generated_node_ids } size=128M @@ -190,6 +190,14 @@ run_qemu -drive driver=null-co,cache=writethrough run_qemu -drive driver=null-co,cache=unsafe run_qemu -drive driver=null-co,cache=invalid_value +# Can't test direct=on here because O_DIRECT might not be supported on this FS +# Test 142 checks the direct=on cases + +for cache in writeback writethrough unsafe invalid_value; do + echo -e "info block\ninfo block file\ninfo block backing\ninfo block backing-file" | \ + run_qemu -drive file="$TEST_IMG",cache=$cache,backing.file.filename="$TEST_IMG.base",backing.cache.no-flush=on,backing.cache.writeback=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file -nodefaults +done + echo echo === Specifying the protocol layer === echo diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out index 7a459a3..070d318 100644 --- a/tests/qemu-iotests/051.out +++ b/tests/qemu-iotests/051.out @@ -238,6 +238,66 @@ QEMU X.Y.Z monitor - type 'help' for more information Testing: -drive driver=null-co,cache=invalid_value QEMU_PROG: -drive driver=null-co,cache=invalid_value: invalid cache option +Testing: -drive file=TEST_DIR/t.qcow2,cache=writeback,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.cache.writeback=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file -nodefaults +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo block +ide0-hd0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Cache mode: writeback + Backing file: TEST_DIR/t.qcow2.base (chain depth: 1) +(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block finfo block fiinfo block filinfo block file + +file: TEST_DIR/t.qcow2 (file) + Cache mode: writeback +(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block binfo block bainfo block bacinfo block backinfo block backiinfo block backininfo block backing +backing: TEST_DIR/t.qcow2.base (qcow2, read-only) + Cache mode: writeback, ignore flushes +(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block binfo block bainfo block bacinfo block backinfo block backiinfo block backininfo block backinginfo block backing-info block backing-finfo block backing-fiinfo block backing-filinfo block backing-file + +backing-file: TEST_DIR/t.qcow2.base (file, read-only) + Cache mode: writeback, ignore flushes +(qemu) qququiquit + +Testing: -drive file=TEST_DIR/t.qcow2,cache=writethrough,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.cache.writeback=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file -nodefaults +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo block +ide0-hd0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Cache mode: writethrough + Backing file: TEST_DIR/t.qcow2.base (chain depth: 1) +(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block finfo block fiinfo block filinfo block file + +file: TEST_DIR/t.qcow2 (file) + Cache mode: writeback +(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block binfo block bainfo block bacinfo block backinfo block backiinfo block backininfo block backing +backing: TEST_DIR/t.qcow2.base (qcow2, read-only) + Cache mode: writeback, ignore flushes +(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block binfo block bainfo block bacinfo block backinfo block backiinfo block backininfo block backinginfo block backing-info block backing-finfo block backing-fiinfo block backing-filinfo block backing-file + +backing-file: TEST_DIR/t.qcow2.base (file, read-only) + Cache mode: writeback, ignore flushes +(qemu) qququiquit + +Testing: -drive file=TEST_DIR/t.qcow2,cache=unsafe,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.cache.writeback=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file -nodefaults +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo block +ide0-hd0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Cache mode: writeback, ignore flushes + Backing file: TEST_DIR/t.qcow2.base (chain depth: 1) +(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block finfo block fiinfo block filinfo block file + +file: TEST_DIR/t.qcow2 (file) + Cache mode: writeback, ignore flushes +(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block binfo block bainfo block bacinfo block backinfo block backiinfo block backininfo block backing +backing: TEST_DIR/t.qcow2.base (qcow2, read-only) + Cache mode: writeback, ignore flushes +(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block binfo block bainfo block bacinfo block backinfo block backiinfo block backininfo block backinginfo block backing-info block backing-finfo block backing-fiinfo block backing-filinfo block backing-file + +backing-file: TEST_DIR/t.qcow2.base (file, read-only) + Cache mode: writeback, ignore flushes +(qemu) qququiquit + +Testing: -drive file=TEST_DIR/t.qcow2,cache=invalid_value,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.cache.writeback=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file -nodefaults +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,cache=invalid_value,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.cache.writeback=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file: invalid cache option + === Specifying the protocol layer === -- cgit v1.1 From 8f7acbe6ea30de29e11f595242de89845f771ea1 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 8 May 2015 18:06:47 +0200 Subject: qemu-iotests: Test cache mode option inheritance This is doing a more complete test on setting cache modes both while opening an image (i.e. in a -drive command line) and in reopen situations. It checks that reopen can specify options for child nodes and that cache modes are correctly inherited from parent nodes where they are not specified. Signed-off-by: Kevin Wolf Reviewed-by: Max Reitz --- tests/qemu-iotests/142 | 354 +++++++++++++++++++++ tests/qemu-iotests/142.out | 773 +++++++++++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/group | 1 + 3 files changed, 1128 insertions(+) create mode 100755 tests/qemu-iotests/142 create mode 100644 tests/qemu-iotests/142.out diff --git a/tests/qemu-iotests/142 b/tests/qemu-iotests/142 new file mode 100755 index 0000000..8aa50f8 --- /dev/null +++ b/tests/qemu-iotests/142 @@ -0,0 +1,354 @@ +#!/bin/bash +# +# Test for configuring cache modes of arbitrary nodes (requires O_DIRECT) +# +# Copyright (C) 2015 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" + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img + rm -f $TEST_IMG.snap +} +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 + +# We test all cache modes anyway, but O_DIRECT needs to be supported +_default_cache_mode none +_supported_cache_modes none directsync + +function do_run_qemu() +{ + echo Testing: "$@" + ( + if ! test -t 0; then + while read cmd; do + echo $cmd + done + fi + echo quit + ) | $QEMU -nographic -monitor stdio -nodefaults "$@" + echo +} + +function run_qemu() +{ + do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu +} + +size=128M + +TEST_IMG="$TEST_IMG.base" _make_test_img $size +TEST_IMG="$TEST_IMG.snap" _make_test_img $size +_make_test_img -b "$TEST_IMG.base" $size + +echo +echo === Simple test for all cache modes === +echo + +run_qemu -drive file="$TEST_IMG",cache=none +run_qemu -drive file="$TEST_IMG",cache=directsync +run_qemu -drive file="$TEST_IMG",cache=writeback +run_qemu -drive file="$TEST_IMG",cache=writethrough +run_qemu -drive file="$TEST_IMG",cache=unsafe +run_qemu -drive file="$TEST_IMG",cache=invalid_value + +echo +echo === Check inheritance of cache modes === +echo + +files="if=none,file=$TEST_IMG,backing.file.filename=$TEST_IMG.base" +ids="node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file" + +function check_cache_all() +{ + # cache.direct is supposed to be inherited by both bs->file and + # bs->backing + + echo -e "cache.direct=on on none0" + echo "$hmp_cmds" | run_qemu -drive "$files","$ids",cache.direct=on | grep "Cache" + echo -e "\ncache.direct=on on file" + echo "$hmp_cmds" | run_qemu -drive "$files","$ids",file.cache.direct=on | grep "Cache" + echo -e "\ncache.direct=on on backing" + echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.cache.direct=on | grep "Cache" + echo -e "\ncache.direct=on on backing-file" + echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.file.cache.direct=on | grep "Cache" + + # cache.writeback is supposed to be inherited by bs->backing; bs->file + # always gets cache.writeback=on + + echo -e "\n\ncache.writeback=off on none0" + echo "$hmp_cmds" | run_qemu -drive "$files","$ids",cache.writeback=off | grep "Cache" + echo -e "\ncache.writeback=off on file" + echo "$hmp_cmds" | run_qemu -drive "$files","$ids",file.cache.writeback=off | grep "Cache" + echo -e "\ncache.writeback=off on backing" + echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.cache.writeback=off | grep "Cache" + echo -e "\ncache.writeback=off on backing-file" + echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.file.cache.writeback=off | grep "Cache" + + # cache.no-flush is supposed to be inherited by both bs->file and bs->backing + + echo -e "\n\ncache.no-flush=on on none0" + echo "$hmp_cmds" | run_qemu -drive "$files","$ids",cache.no-flush=on | grep "Cache" + echo -e "\ncache.no-flush=on on file" + echo "$hmp_cmds" | run_qemu -drive "$files","$ids",file.cache.no-flush=on | grep "Cache" + echo -e "\ncache.no-flush=on on backing" + echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.cache.no-flush=on | grep "Cache" + echo -e "\ncache.no-flush=on on backing-file" + echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.file.cache.no-flush=on | grep "Cache" +} + +echo +echo "--- Configure cache modes on the command line ---" +echo + +# First check the inherited cache mode after opening the image. + +hmp_cmds="info block image +info block file +info block backing +info block backing-file" + +check_cache_all + +echo +echo "--- Cache modes after reopen (live snapshot) ---" +echo + +# Then trigger a reopen and check that the cache modes are still the same. + +hmp_cmds="snapshot_blkdev -n none0 $TEST_IMG.snap $IMGFMT +info block +info block image +info block file +info block backing +info block backing-file" + +check_cache_all + +echo +echo "--- Change cache modes with reopen (qemu-io command, flags) ---" +echo + +# This one actually changes the cache mode with the reopen. For this test, the +# new cache mode is specified in the flags, not as an option. + +hmp_cmds='qemu-io none0 "reopen -c none" +info block image +info block file +info block backing +info block backing-file' + +check_cache_all + +echo +echo "--- Change cache modes with reopen (qemu-io command, options) ---" +echo + +# This one actually changes the cache mode with the reopen. For this test, the +# new cache mode is specified as an option, not in the flags. + +hmp_cmds='qemu-io none0 "reopen -o cache.direct=on" +info block image +info block file +info block backing +info block backing-file' + +check_cache_all + +echo +echo "--- Change cache modes after snapshot ---" +echo + +# This checks that the original image doesn't inherit from the snapshot + +hmp_cmds="snapshot_blkdev -n none0 $TEST_IMG.snap $IMGFMT +qemu-io none0 \"reopen -c none\" +info block none0 +info block image +info block file +info block backing +info block backing-file" + +check_cache_all + +echo +echo "--- Change cache mode in parent, child has explicit option in JSON ---" +echo + +# This checks that children with options explicitly set by the json: +# pseudo-protocol don't inherit these options from their parents. +# +# Yes, blkdebug::json:... is criminal, but I can't see another way to have a +# BDS initialised with the json: pseudo-protocol, but still have it inherit +# options from its parent node. + +hmp_cmds="qemu-io none0 \"reopen -o cache.writeback=off,cache.direct=on,cache.no-flush=on\" +info block image +info block blkdebug +info block file" + +echo "$hmp_cmds" | run_qemu -drive if=none,file="blkdebug::json:{\"filename\":\"$TEST_IMG\",,\"cache\":{\"writeback\":false,,\"direct\":false}}",node-name=image,file.node-name=blkdebug,file.image.node-name=file | grep "Cache" + +echo +echo "=== Check that referenced BDSes don't inherit ===" +echo + +drv_bkfile="if=none,driver=file,filename=$TEST_IMG.base,node-name=backing-file" +drv_bk="if=none,file=json:{'driver':'$IMGFMT',,'file':'backing-file',,'node-name':'backing'}" +drv_file="if=none,driver=file,filename=$TEST_IMG,node-name=file" +drv_img="if=none,id=blk,file=json:{'driver':'$IMGFMT',,'file':'file',,'backing':'backing',,'node-name':'image'}" + +function check_cache_all_separate() +{ + # Check cache.direct + + echo -e "cache.direct=on on blk" + echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img",cache.direct=on | grep "Cache" + echo -e "\ncache.direct=on on file" + echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file",cache.direct=on -drive "$drv_img" | grep "Cache" + echo -e "\ncache.direct=on on backing" + echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk",cache.direct=on -drive "$drv_file" -drive "$drv_img" | grep "Cache" + echo -e "\ncache.direct=on on backing-file" + echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile",cache.direct=on -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img" | grep "Cache" + + # Check cache.writeback + + echo -e "\n\ncache.writeback=off on blk" + echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img",cache.writeback=off | grep "Cache" + echo -e "\ncache.writeback=off on file" + echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file",cache.writeback=off -drive "$drv_img" | grep "Cache" + echo -e "\ncache.writeback=off on backing" + echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk",cache.writeback=off -drive "$drv_file" -drive "$drv_img" | grep "Cache" + echo -e "\ncache.writeback=off on backing-file" + echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile",cache.writeback=off -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img" | grep "Cache" + + # Check cache.no-flush + + echo -e "\n\ncache.no-flush=on on blk" + echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img",cache.no-flush=on | grep "Cache" + echo -e "\ncache.no-flush=on on file" + echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file",cache.no-flush=on -drive "$drv_img" | grep "Cache" + echo -e "\ncache.no-flush=on on backing" + echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk",cache.no-flush=on -drive "$drv_file" -drive "$drv_img" | grep "Cache" + echo -e "\ncache.no-flush=on on backing-file" + echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile",cache.no-flush=on -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img" | grep "Cache" +} + +echo +echo "--- Configure cache modes on the command line ---" +echo + +# First check the inherited cache mode after opening the image. + +hmp_cmds="info block image +info block file +info block backing +info block backing-file" + +check_cache_all_separate + +echo +echo "--- Cache modes after reopen (live snapshot) ---" +echo + +# Then trigger a reopen and check that the cache modes are still the same. + +hmp_cmds="snapshot_blkdev -n blk $TEST_IMG.snap $IMGFMT +info block blk +info block image +info block file +info block backing +info block backing-file" + +check_cache_all_separate + +echo +echo "--- Change cache modes with reopen (qemu-io command, flags) ---" +echo + +# This one actually changes the cache mode with the reopen. For this test, the +# new cache mode is specified as flags, not as option. + +hmp_cmds='qemu-io blk "reopen -c none" +info block image +info block file +info block backing +info block backing-file' + +check_cache_all_separate + + +echo +echo "=== Reopening children instead of the root ===" +echo + +files="if=none,file=$TEST_IMG,backing.file.filename=$TEST_IMG.base" +ids="node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file" + +echo +echo "--- Basic reopen ---" +echo + +hmp_cmds='qemu-io none0 "reopen -o backing.cache.direct=on" +info block image +info block file +info block backing +info block backing-file' + +check_cache_all + +echo +echo "--- Change cache mode after reopening child ---" +echo + +# This checks that children with options explicitly set with reopen don't +# inherit these options from their parents any more + +# TODO Implement node-name support for 'qemu-io' HMP command for -c +# Can use only -o to access child node options for now + +hmp_cmds="qemu-io none0 \"reopen -o file.cache.writeback=off,file.cache.direct=off,file.cache.no-flush=off\" +qemu-io none0 \"reopen -o backing.file.cache.writeback=on,backing.file.cache.direct=off,backing.file.cache.no-flush=on\" +qemu-io none0 \"reopen -c none\" +info block image +info block file +info block backing +info block backing-file" + +echo "$hmp_cmds" | run_qemu -drive "$files","$ids" | grep "Cache" + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/142.out b/tests/qemu-iotests/142.out new file mode 100644 index 0000000..b555d5a --- /dev/null +++ b/tests/qemu-iotests/142.out @@ -0,0 +1,773 @@ +QA output created by 142 +Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728 +Formatting 'TEST_DIR/t.IMGFMT.snap', fmt=IMGFMT size=134217728 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base + +=== Simple test for all cache modes === + +Testing: -drive file=TEST_DIR/t.qcow2,cache=none +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit + +Testing: -drive file=TEST_DIR/t.qcow2,cache=directsync +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit + +Testing: -drive file=TEST_DIR/t.qcow2,cache=writeback +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit + +Testing: -drive file=TEST_DIR/t.qcow2,cache=writethrough +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit + +Testing: -drive file=TEST_DIR/t.qcow2,cache=unsafe +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit + +Testing: -drive file=TEST_DIR/t.qcow2,cache=invalid_value +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,cache=invalid_value: invalid cache option + + +=== Check inheritance of cache modes === + + +--- Configure cache modes on the command line --- + +cache.direct=on on none0 + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.direct=on on file + Cache mode: writeback + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback + +cache.direct=on on backing + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.direct=on on backing-file + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, direct + + +cache.writeback=off on none0 + Cache mode: writethrough + Cache mode: writeback + Cache mode: writethrough + Cache mode: writeback + +cache.writeback=off on file + Cache mode: writeback + Cache mode: writethrough + Cache mode: writeback + Cache mode: writeback + +cache.writeback=off on backing + Cache mode: writeback + Cache mode: writeback + Cache mode: writethrough + Cache mode: writeback + +cache.writeback=off on backing-file + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writethrough + + +cache.no-flush=on on none0 + Cache mode: writeback, ignore flushes + Cache mode: writeback, ignore flushes + Cache mode: writeback, ignore flushes + Cache mode: writeback, ignore flushes + +cache.no-flush=on on file + Cache mode: writeback + Cache mode: writeback, ignore flushes + Cache mode: writeback + Cache mode: writeback + +cache.no-flush=on on backing + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, ignore flushes + Cache mode: writeback, ignore flushes + +cache.no-flush=on on backing-file + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, ignore flushes + +--- Cache modes after reopen (live snapshot) --- + +cache.direct=on on none0 + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.direct=on on file + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback + +cache.direct=on on backing + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.direct=on on backing-file + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, direct + + +cache.writeback=off on none0 + Cache mode: writethrough + Cache mode: writethrough + Cache mode: writeback + Cache mode: writethrough + Cache mode: writeback + +cache.writeback=off on file + Cache mode: writeback + Cache mode: writeback + Cache mode: writethrough + Cache mode: writeback + Cache mode: writeback + +cache.writeback=off on backing + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writethrough + Cache mode: writeback + +cache.writeback=off on backing-file + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writethrough + + +cache.no-flush=on on none0 + Cache mode: writeback, ignore flushes + Cache mode: writeback, ignore flushes + Cache mode: writeback, ignore flushes + Cache mode: writeback, ignore flushes + Cache mode: writeback, ignore flushes + +cache.no-flush=on on file + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, ignore flushes + Cache mode: writeback + Cache mode: writeback + +cache.no-flush=on on backing + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, ignore flushes + Cache mode: writeback, ignore flushes + +cache.no-flush=on on backing-file + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, ignore flushes + +--- Change cache modes with reopen (qemu-io command, flags) --- + +cache.direct=on on none0 + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.direct=on on file + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.direct=on on backing + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.direct=on on backing-file + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + + +cache.writeback=off on none0 + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.writeback=off on file + Cache mode: writeback, direct + Cache mode: writethrough, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.writeback=off on backing + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writethrough, direct + Cache mode: writeback, direct + +cache.writeback=off on backing-file + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writethrough, direct + + +cache.no-flush=on on none0 + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.no-flush=on on file + Cache mode: writeback, direct + Cache mode: writeback, direct, ignore flushes + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.no-flush=on on backing + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct, ignore flushes + Cache mode: writeback, direct, ignore flushes + +cache.no-flush=on on backing-file + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct, ignore flushes + +--- Change cache modes with reopen (qemu-io command, options) --- + +cache.direct=on on none0 + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.direct=on on file + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.direct=on on backing + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.direct=on on backing-file + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + + +cache.writeback=off on none0 + Cache mode: writethrough, direct + Cache mode: writeback, direct + Cache mode: writethrough, direct + Cache mode: writeback, direct + +cache.writeback=off on file + Cache mode: writeback, direct + Cache mode: writethrough, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.writeback=off on backing + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writethrough, direct + Cache mode: writeback, direct + +cache.writeback=off on backing-file + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writethrough, direct + + +cache.no-flush=on on none0 + Cache mode: writeback, direct, ignore flushes + Cache mode: writeback, direct, ignore flushes + Cache mode: writeback, direct, ignore flushes + Cache mode: writeback, direct, ignore flushes + +cache.no-flush=on on file + Cache mode: writeback, direct + Cache mode: writeback, direct, ignore flushes + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.no-flush=on on backing + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct, ignore flushes + Cache mode: writeback, direct, ignore flushes + +cache.no-flush=on on backing-file + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct, ignore flushes + +--- Change cache modes after snapshot --- + +cache.direct=on on none0 + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.direct=on on file + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback + +cache.direct=on on backing + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.direct=on on backing-file + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, direct + + +cache.writeback=off on none0 + Cache mode: writeback, direct + Cache mode: writethrough + Cache mode: writeback + Cache mode: writethrough + Cache mode: writeback + +cache.writeback=off on file + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writethrough + Cache mode: writeback + Cache mode: writeback + +cache.writeback=off on backing + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback + Cache mode: writethrough + Cache mode: writeback + +cache.writeback=off on backing-file + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writethrough + + +cache.no-flush=on on none0 + Cache mode: writeback, direct + Cache mode: writeback, ignore flushes + Cache mode: writeback, ignore flushes + Cache mode: writeback, ignore flushes + Cache mode: writeback, ignore flushes + +cache.no-flush=on on file + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback, ignore flushes + Cache mode: writeback + Cache mode: writeback + +cache.no-flush=on on backing + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, ignore flushes + Cache mode: writeback, ignore flushes + +cache.no-flush=on on backing-file + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, ignore flushes + +--- Change cache mode in parent, child has explicit option in JSON --- + + Cache mode: writethrough, direct, ignore flushes + Cache mode: writeback, direct, ignore flushes + Cache mode: writethrough, ignore flushes + +=== Check that referenced BDSes don't inherit === + + +--- Configure cache modes on the command line --- + +cache.direct=on on blk + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + +cache.direct=on on file + Cache mode: writeback + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback + +cache.direct=on on backing + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, direct + Cache mode: writeback + +cache.direct=on on backing-file + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, direct + + +cache.writeback=off on blk + Cache mode: writethrough + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + +cache.writeback=off on file + Cache mode: writeback + Cache mode: writethrough + Cache mode: writeback + Cache mode: writeback + +cache.writeback=off on backing + Cache mode: writeback + Cache mode: writeback + Cache mode: writethrough + Cache mode: writeback + +cache.writeback=off on backing-file + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writethrough + + +cache.no-flush=on on blk + Cache mode: writeback, ignore flushes + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + +cache.no-flush=on on file + Cache mode: writeback + Cache mode: writeback, ignore flushes + Cache mode: writeback + Cache mode: writeback + +cache.no-flush=on on backing + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, ignore flushes + Cache mode: writeback + +cache.no-flush=on on backing-file + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, ignore flushes + +--- Cache modes after reopen (live snapshot) --- + +cache.direct=on on blk + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + +cache.direct=on on file + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback + +cache.direct=on on backing + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, direct + Cache mode: writeback + +cache.direct=on on backing-file + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, direct + + +cache.writeback=off on blk + Cache mode: writethrough + Cache mode: writethrough + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + +cache.writeback=off on file + Cache mode: writeback + Cache mode: writeback + Cache mode: writethrough + Cache mode: writeback + Cache mode: writeback + +cache.writeback=off on backing + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writethrough + Cache mode: writeback + +cache.writeback=off on backing-file + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writethrough + + +cache.no-flush=on on blk + Cache mode: writeback, ignore flushes + Cache mode: writeback, ignore flushes + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + +cache.no-flush=on on file + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, ignore flushes + Cache mode: writeback + Cache mode: writeback + +cache.no-flush=on on backing + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, ignore flushes + Cache mode: writeback + +cache.no-flush=on on backing-file + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, ignore flushes + +--- Change cache modes with reopen (qemu-io command, flags) --- + +cache.direct=on on blk + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + +cache.direct=on on file + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback + +cache.direct=on on backing + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback, direct + Cache mode: writeback + +cache.direct=on on backing-file + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, direct + + +cache.writeback=off on blk + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + +cache.writeback=off on file + Cache mode: writeback, direct + Cache mode: writethrough + Cache mode: writeback + Cache mode: writeback + +cache.writeback=off on backing + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writethrough + Cache mode: writeback + +cache.writeback=off on backing-file + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback + Cache mode: writethrough + + +cache.no-flush=on on blk + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + +cache.no-flush=on on file + Cache mode: writeback, direct + Cache mode: writeback, ignore flushes + Cache mode: writeback + Cache mode: writeback + +cache.no-flush=on on backing + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback, ignore flushes + Cache mode: writeback + +cache.no-flush=on on backing-file + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, ignore flushes + +=== Reopening children instead of the root === + + +--- Basic reopen --- + +cache.direct=on on none0 + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.direct=on on file + Cache mode: writeback + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.direct=on on backing + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.direct=on on backing-file + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, direct + Cache mode: writeback, direct + + +cache.writeback=off on none0 + Cache mode: writethrough + Cache mode: writeback + Cache mode: writethrough, direct + Cache mode: writeback, direct + +cache.writeback=off on file + Cache mode: writeback + Cache mode: writethrough + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.writeback=off on backing + Cache mode: writeback + Cache mode: writeback + Cache mode: writethrough, direct + Cache mode: writeback, direct + +cache.writeback=off on backing-file + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, direct + Cache mode: writethrough, direct + + +cache.no-flush=on on none0 + Cache mode: writeback, ignore flushes + Cache mode: writeback, ignore flushes + Cache mode: writeback, direct, ignore flushes + Cache mode: writeback, direct, ignore flushes + +cache.no-flush=on on file + Cache mode: writeback + Cache mode: writeback, ignore flushes + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.no-flush=on on backing + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, direct, ignore flushes + Cache mode: writeback, direct, ignore flushes + +cache.no-flush=on on backing-file + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, direct + Cache mode: writeback, direct, ignore flushes + +--- Change cache mode after reopening child --- + + Cache mode: writeback, direct + Cache mode: writethrough + Cache mode: writeback, direct + Cache mode: writeback, ignore flushes +*** done diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 5a08808..ed6ce09 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -140,3 +140,4 @@ 137 rw auto 138 rw auto quick 139 rw auto quick +142 auto -- cgit v1.1 From 0a8111e0fbeccdf94ee011bc3b3013a45166a9a8 Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Fri, 8 May 2015 18:11:08 +0200 Subject: qemu-iotests: Test reopen with node-name/driver options 'node-name' and 'driver' should not be changed during a reopen operation. It is, however, valid to specify them with the same value as they already had. Signed-off-by: Kevin Wolf Reviewed-by: Max Reitz --- tests/qemu-iotests/133 | 90 ++++++++++++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/133.out | 22 ++++++++++++ tests/qemu-iotests/group | 1 + 3 files changed, 113 insertions(+) create mode 100755 tests/qemu-iotests/133 create mode 100644 tests/qemu-iotests/133.out diff --git a/tests/qemu-iotests/133 b/tests/qemu-iotests/133 new file mode 100755 index 0000000..8587102 --- /dev/null +++ b/tests/qemu-iotests/133 @@ -0,0 +1,90 @@ +#!/bin/bash +# +# Test for reopen +# +# Copyright (C) 2015 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" + +here=`pwd` +tmp=/tmp/$$ +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 + +TEST_IMG="$TEST_IMG.base" _make_test_img 64M +_make_test_img -b "$TEST_IMG.base" + +echo +echo "=== Check that node-name can't be changed ===" +echo + +$QEMU_IO -c 'reopen -o node-name=foo' $TEST_IMG +$QEMU_IO -c 'reopen -o file.node-name=foo' $TEST_IMG +$QEMU_IO -c 'reopen -o backing.node-name=foo' $TEST_IMG + +echo +echo "=== Check that unchanged node-name is okay ===" +echo + +# Explicitly repeated +$QEMU_IO -c "open -o node-name=foo $TEST_IMG" -c 'reopen -o node-name=foo' +$QEMU_IO -c "open -o file.node-name=foo $TEST_IMG" -c 'reopen -o file.node-name=foo' +$QEMU_IO -c "open -o backing.node-name=foo $TEST_IMG" -c 'reopen -o backing.node-name=foo' + +# Implicitly retained +$QEMU_IO -c "open -o node-name=foo $TEST_IMG" -c 'reopen' +$QEMU_IO -c "open -o file.node-name=foo $TEST_IMG" -c 'reopen' +$QEMU_IO -c "open -o backing.node-name=foo $TEST_IMG" -c 'reopen' + +echo +echo "=== Check that driver can't be changed ===" +echo + +$QEMU_IO -c 'reopen -o driver=raw' $TEST_IMG +$QEMU_IO -c 'reopen -o file.driver=qcow2' $TEST_IMG +$QEMU_IO -c 'reopen -o backing.driver=file' $TEST_IMG + +echo +echo "=== Check that unchanged driver is okay ===" +echo + +# Explicitly repeated (implicit case is covered in node-name test) +$QEMU_IO -c 'reopen -o driver=qcow2' $TEST_IMG +$QEMU_IO -c 'reopen -o file.driver=file' $TEST_IMG +$QEMU_IO -c 'reopen -o backing.driver=qcow2' $TEST_IMG + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/133.out b/tests/qemu-iotests/133.out new file mode 100644 index 0000000..cc86b94 --- /dev/null +++ b/tests/qemu-iotests/133.out @@ -0,0 +1,22 @@ +QA output created by 133 +Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base + +=== Check that node-name can't be changed === + +Cannot change the option 'node-name' +Cannot change the option 'node-name' +Cannot change the option 'node-name' + +=== Check that unchanged node-name is okay === + + +=== Check that driver can't be changed === + +Cannot change the option 'driver' +Cannot change the option 'driver' +Cannot change the option 'driver' + +=== Check that unchanged driver is okay === + +*** done diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index ed6ce09..d6e9219 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -134,6 +134,7 @@ 130 rw auto quick 131 rw auto quick 132 rw auto quick +133 auto quick 134 rw auto quick 135 rw auto 136 rw auto -- cgit v1.1 From bd5072d75622c3a702741064df87ea8911bae1a4 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Mon, 27 Jul 2015 17:51:31 +0200 Subject: progress: Allow regressing progress Progress may regress; this should be displayed correctly by qemu_progress_print(). While touching that area of code, drop the redundant parentheses in the same condition. Signed-off-by: Max Reitz Reviewed-by: Eric Blake Reviewed-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- util/qemu-progress.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/util/qemu-progress.c b/util/qemu-progress.c index 4ee5cd0..532333e 100644 --- a/util/qemu-progress.c +++ b/util/qemu-progress.c @@ -152,7 +152,8 @@ void qemu_progress_print(float delta, int max) state.current = current; if (current > (state.last_print + state.min_skip) || - (current == 100) || (current == 0)) { + current < (state.last_print - state.min_skip) || + current == 100 || current == 0) { state.last_print = state.current; state.print(); } -- cgit v1.1 From 8b13976d3fabee2f2900a9fb51c85b27ba4516b9 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Mon, 27 Jul 2015 17:51:32 +0200 Subject: block: Add opaque value to the amend CB Add an opaque value which is to be passed to the bdrv_amend_options() status callback. Signed-off-by: Max Reitz Reviewed-by: Eric Blake Reviewed-by: Stefan Hajnoczi Reviewed-by: Alberto Garcia Signed-off-by: Kevin Wolf --- block.c | 4 ++-- block/qcow2-cluster.c | 14 ++++++++------ block/qcow2.c | 9 +++++---- block/qcow2.h | 3 ++- include/block/block.h | 4 ++-- include/block/block_int.h | 3 ++- qemu-img.c | 5 +++-- 7 files changed, 24 insertions(+), 18 deletions(-) diff --git a/block.c b/block.c index 1894f1b..411edbf 100644 --- a/block.c +++ b/block.c @@ -4068,12 +4068,12 @@ void bdrv_remove_aio_context_notifier(BlockDriverState *bs, } int bdrv_amend_options(BlockDriverState *bs, QemuOpts *opts, - BlockDriverAmendStatusCB *status_cb) + BlockDriverAmendStatusCB *status_cb, void *cb_opaque) { if (!bs->drv->bdrv_amend_options) { return -ENOTSUP; } - return bs->drv->bdrv_amend_options(bs, opts, status_cb); + return bs->drv->bdrv_amend_options(bs, opts, status_cb, cb_opaque); } /* This function will be called by the bdrv_recurse_is_first_non_filter method diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 24a60e2..34112c3 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -1641,7 +1641,8 @@ fail: static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table, int l1_size, int64_t *visited_l1_entries, int64_t l1_entries, - BlockDriverAmendStatusCB *status_cb) + BlockDriverAmendStatusCB *status_cb, + void *cb_opaque) { BDRVQcow2State *s = bs->opaque; bool is_active_l1 = (l1_table == s->l1_table); @@ -1667,7 +1668,7 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table, /* unallocated */ (*visited_l1_entries)++; if (status_cb) { - status_cb(bs, *visited_l1_entries, l1_entries); + status_cb(bs, *visited_l1_entries, l1_entries, cb_opaque); } continue; } @@ -1804,7 +1805,7 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table, (*visited_l1_entries)++; if (status_cb) { - status_cb(bs, *visited_l1_entries, l1_entries); + status_cb(bs, *visited_l1_entries, l1_entries, cb_opaque); } } @@ -1828,7 +1829,8 @@ fail: * qcow2 version which doesn't yet support metadata zero clusters. */ int qcow2_expand_zero_clusters(BlockDriverState *bs, - BlockDriverAmendStatusCB *status_cb) + BlockDriverAmendStatusCB *status_cb, + void *cb_opaque) { BDRVQcow2State *s = bs->opaque; uint64_t *l1_table = NULL; @@ -1845,7 +1847,7 @@ int qcow2_expand_zero_clusters(BlockDriverState *bs, ret = expand_zero_clusters_in_l1(bs, s->l1_table, s->l1_size, &visited_l1_entries, l1_entries, - status_cb); + status_cb, cb_opaque); if (ret < 0) { goto fail; } @@ -1881,7 +1883,7 @@ int qcow2_expand_zero_clusters(BlockDriverState *bs, ret = expand_zero_clusters_in_l1(bs, l1_table, s->snapshots[i].l1_size, &visited_l1_entries, l1_entries, - status_cb); + status_cb, cb_opaque); if (ret < 0) { goto fail; } diff --git a/block/qcow2.c b/block/qcow2.c index fda1562..4be2c61 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -2870,7 +2870,7 @@ static int qcow2_load_vmstate(BlockDriverState *bs, uint8_t *buf, * have to be removed. */ static int qcow2_downgrade(BlockDriverState *bs, int target_version, - BlockDriverAmendStatusCB *status_cb) + BlockDriverAmendStatusCB *status_cb, void *cb_opaque) { BDRVQcow2State *s = bs->opaque; int current_version = s->qcow_version; @@ -2919,7 +2919,7 @@ static int qcow2_downgrade(BlockDriverState *bs, int target_version, /* clearing autoclear features is trivial */ s->autoclear_features = 0; - ret = qcow2_expand_zero_clusters(bs, status_cb); + ret = qcow2_expand_zero_clusters(bs, status_cb, cb_opaque); if (ret < 0) { return ret; } @@ -2934,7 +2934,8 @@ static int qcow2_downgrade(BlockDriverState *bs, int target_version, } static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, - BlockDriverAmendStatusCB *status_cb) + BlockDriverAmendStatusCB *status_cb, + void *cb_opaque) { BDRVQcow2State *s = bs->opaque; int old_version = s->qcow_version, new_version = old_version; @@ -3017,7 +3018,7 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, return ret; } } else { - ret = qcow2_downgrade(bs, new_version, status_cb); + ret = qcow2_downgrade(bs, new_version, status_cb, cb_opaque); if (ret < 0) { return ret; } diff --git a/block/qcow2.h b/block/qcow2.h index b8c500b..a9794de 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -553,7 +553,8 @@ int qcow2_discard_clusters(BlockDriverState *bs, uint64_t offset, int qcow2_zero_clusters(BlockDriverState *bs, uint64_t offset, int nb_sectors); int qcow2_expand_zero_clusters(BlockDriverState *bs, - BlockDriverAmendStatusCB *status_cb); + BlockDriverAmendStatusCB *status_cb, + void *cb_opaque); /* qcow2-snapshot.c functions */ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info); diff --git a/include/block/block.h b/include/block/block.h index 121544b..bce0d86 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -306,9 +306,9 @@ int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix); * block driver; total_work_size may change during the course of the amendment * operation */ typedef void BlockDriverAmendStatusCB(BlockDriverState *bs, int64_t offset, - int64_t total_work_size); + int64_t total_work_size, void *opaque); int bdrv_amend_options(BlockDriverState *bs_new, QemuOpts *opts, - BlockDriverAmendStatusCB *status_cb); + BlockDriverAmendStatusCB *status_cb, void *cb_opaque); /* external snapshots */ bool bdrv_recurse_is_first_non_filter(BlockDriverState *bs, diff --git a/include/block/block_int.h b/include/block/block_int.h index edfe376..9a1c466 100644 --- a/include/block/block_int.h +++ b/include/block/block_int.h @@ -243,7 +243,8 @@ struct BlockDriver { BdrvCheckMode fix); int (*bdrv_amend_options)(BlockDriverState *bs, QemuOpts *opts, - BlockDriverAmendStatusCB *status_cb); + BlockDriverAmendStatusCB *status_cb, + void *cb_opaque); void (*bdrv_debug_event)(BlockDriverState *bs, BlkdebugEvent event); diff --git a/qemu-img.c b/qemu-img.c index 033011c..b6b4c9e 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -2896,7 +2896,8 @@ out: } static void amend_status_cb(BlockDriverState *bs, - int64_t offset, int64_t total_work_size) + int64_t offset, int64_t total_work_size, + void *opaque) { qemu_progress_print(100.f * offset / total_work_size, 0); } @@ -3020,7 +3021,7 @@ static int img_amend(int argc, char **argv) /* In case the driver does not call amend_status_cb() */ qemu_progress_print(0.f, 0); - ret = bdrv_amend_options(bs, opts, &amend_status_cb); + ret = bdrv_amend_options(bs, opts, &amend_status_cb, NULL); qemu_progress_print(100.f, 0); if (ret < 0) { error_report("Error while amending options: %s", strerror(-ret)); -- cgit v1.1 From 29d72431ef7a68977a809727988285654887263f Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Mon, 27 Jul 2015 17:51:33 +0200 Subject: qcow2: Use error_report() in qcow2_amend_options() Signed-off-by: Max Reitz Reviewed-by: Eric Blake Reviewed-by: Alberto Garcia Signed-off-by: Kevin Wolf --- block/qcow2.c | 14 ++++++-------- tests/qemu-iotests/061.out | 14 +++++++------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index 4be2c61..01b20d9 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -2964,11 +2964,11 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, } else if (!strcmp(compat, "1.1")) { new_version = 3; } else { - fprintf(stderr, "Unknown compatibility level %s.\n", compat); + error_report("Unknown compatibility level %s", compat); return -EINVAL; } } else if (!strcmp(desc->name, BLOCK_OPT_PREALLOC)) { - fprintf(stderr, "Cannot change preallocation mode.\n"); + error_report("Cannot change preallocation mode"); return -ENOTSUP; } else if (!strcmp(desc->name, BLOCK_OPT_SIZE)) { new_size = qemu_opt_get_size(opts, BLOCK_OPT_SIZE, 0); @@ -2981,16 +2981,14 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, !!s->cipher); if (encrypt != !!s->cipher) { - fprintf(stderr, "Changing the encryption flag is not " - "supported.\n"); + error_report("Changing the encryption flag is not supported"); return -ENOTSUP; } } else if (!strcmp(desc->name, BLOCK_OPT_CLUSTER_SIZE)) { cluster_size = qemu_opt_get_size(opts, BLOCK_OPT_CLUSTER_SIZE, cluster_size); if (cluster_size != s->cluster_size) { - fprintf(stderr, "Changing the cluster size is not " - "supported.\n"); + error_report("Changing the cluster size is not supported"); return -ENOTSUP; } } else if (!strcmp(desc->name, BLOCK_OPT_LAZY_REFCOUNTS)) { @@ -3037,8 +3035,8 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, if (s->use_lazy_refcounts != lazy_refcounts) { if (lazy_refcounts) { if (s->qcow_version < 3) { - fprintf(stderr, "Lazy refcounts only supported with compatibility " - "level 1.1 and above (use compat=1.1 or greater)\n"); + error_report("Lazy refcounts only supported with compatibility " + "level 1.1 and above (use compat=1.1 or greater)"); return -EINVAL; } s->compatible_features |= QCOW2_COMPAT_LAZY_REFCOUNTS; diff --git a/tests/qemu-iotests/061.out b/tests/qemu-iotests/061.out index f2598a8..57aae28 100644 --- a/tests/qemu-iotests/061.out +++ b/tests/qemu-iotests/061.out @@ -291,18 +291,18 @@ No errors were found on the image. === Testing invalid configurations === Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 -Lazy refcounts only supported with compatibility level 1.1 and above (use compat=1.1 or greater) +qemu-img: Lazy refcounts only supported with compatibility level 1.1 and above (use compat=1.1 or greater) qemu-img: Error while amending options: Invalid argument -Lazy refcounts only supported with compatibility level 1.1 and above (use compat=1.1 or greater) +qemu-img: Lazy refcounts only supported with compatibility level 1.1 and above (use compat=1.1 or greater) qemu-img: Error while amending options: Invalid argument -Unknown compatibility level 0.42. +qemu-img: Unknown compatibility level 0.42 qemu-img: Error while amending options: Invalid argument qemu-img: Invalid parameter 'foo' -Changing the cluster size is not supported. +qemu-img: Changing the cluster size is not supported qemu-img: Error while amending options: Operation not supported -Changing the encryption flag is not supported. +qemu-img: Changing the encryption flag is not supported qemu-img: Error while amending options: Operation not supported -Cannot change preallocation mode. +qemu-img: Cannot change preallocation mode qemu-img: Error while amending options: Operation not supported === Testing correct handling of unset value === @@ -310,7 +310,7 @@ qemu-img: Error while amending options: Operation not supported Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 Should work: Should not work: -Changing the cluster size is not supported. +qemu-img: Changing the cluster size is not supported qemu-img: Error while amending options: Operation not supported === Testing zero expansion on inactive clusters === -- cgit v1.1 From 164e0f89cc825bf2a83b20451643db333d2891a7 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Mon, 27 Jul 2015 17:51:34 +0200 Subject: qcow2: Use abort() instead of assert(false) Signed-off-by: Max Reitz Reviewed-by: Eric Blake Reviewed-by: Stefan Hajnoczi Reviewed-by: Alberto Garcia 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 01b20d9..381b4f7 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -2998,9 +2998,9 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, error_report("Cannot change refcount entry width"); return -ENOTSUP; } else { - /* if this assertion fails, this probably means a new option was + /* if this point is reached, this probably means a new option was * added without having it covered here */ - assert(false); + abort(); } desc++; -- cgit v1.1 From 1038bbb803b1630a5d9b91d185b5957a25d4710d Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Mon, 27 Jul 2015 17:51:35 +0200 Subject: qcow2: Split upgrade/downgrade paths for amend If the image version should be upgraded, that is the first we should do; if it should be downgraded, that is the last we should do. So split the version change block into an upgrade part at the start and a downgrade part at the end. Signed-off-by: Max Reitz Reviewed-by: Eric Blake Reviewed-by: Stefan Hajnoczi Reviewed-by: Alberto Garcia Signed-off-by: Kevin Wolf --- block/qcow2.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index 381b4f7..07a4f0b 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -3006,20 +3006,13 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, desc++; } - if (new_version != old_version) { - if (new_version > old_version) { - /* Upgrade */ - s->qcow_version = new_version; - ret = qcow2_update_header(bs); - if (ret < 0) { - s->qcow_version = old_version; - return ret; - } - } else { - ret = qcow2_downgrade(bs, new_version, status_cb, cb_opaque); - if (ret < 0) { - return ret; - } + /* Upgrade first (some features may require compat=1.1) */ + if (new_version > old_version) { + s->qcow_version = new_version; + ret = qcow2_update_header(bs); + if (ret < 0) { + s->qcow_version = old_version; + return ret; } } @@ -3034,7 +3027,7 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, if (s->use_lazy_refcounts != lazy_refcounts) { if (lazy_refcounts) { - if (s->qcow_version < 3) { + if (new_version < 3) { error_report("Lazy refcounts only supported with compatibility " "level 1.1 and above (use compat=1.1 or greater)"); return -EINVAL; @@ -3070,6 +3063,14 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, } } + /* Downgrade last (so unsupported features can be removed before) */ + if (new_version < old_version) { + ret = qcow2_downgrade(bs, new_version, status_cb, cb_opaque); + if (ret < 0) { + return ret; + } + } + return 0; } -- cgit v1.1 From c293a8092743aa0e4982067465d6eea6854d6d0c Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Mon, 27 Jul 2015 17:51:36 +0200 Subject: qcow2: Use intermediate helper CB for amend If there is more than one time-consuming operation to be performed for qcow2_amend_options(), we need an intermediate CB which coordinates the progress of the individual operations and passes the result to the original status callback. Signed-off-by: Max Reitz Reviewed-by: Eric Blake Reviewed-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- block/qcow2.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/block/qcow2.c b/block/qcow2.c index 07a4f0b..851de25 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -2933,6 +2933,75 @@ static int qcow2_downgrade(BlockDriverState *bs, int target_version, return 0; } +typedef enum Qcow2AmendOperation { + /* This is the value Qcow2AmendHelperCBInfo::last_operation will be + * statically initialized to so that the helper CB can discern the first + * invocation from an operation change */ + QCOW2_NO_OPERATION = 0, + + QCOW2_DOWNGRADING, +} Qcow2AmendOperation; + +typedef struct Qcow2AmendHelperCBInfo { + /* The code coordinating the amend operations should only modify + * these four fields; the rest will be managed by the CB */ + BlockDriverAmendStatusCB *original_status_cb; + void *original_cb_opaque; + + Qcow2AmendOperation current_operation; + + /* Total number of operations to perform (only set once) */ + int total_operations; + + /* The following fields are managed by the CB */ + + /* Number of operations completed */ + int operations_completed; + + /* Cumulative offset of all completed operations */ + int64_t offset_completed; + + Qcow2AmendOperation last_operation; + int64_t last_work_size; +} Qcow2AmendHelperCBInfo; + +static void qcow2_amend_helper_cb(BlockDriverState *bs, + int64_t operation_offset, + int64_t operation_work_size, void *opaque) +{ + Qcow2AmendHelperCBInfo *info = opaque; + int64_t current_work_size; + int64_t projected_work_size; + + if (info->current_operation != info->last_operation) { + if (info->last_operation != QCOW2_NO_OPERATION) { + info->offset_completed += info->last_work_size; + info->operations_completed++; + } + + info->last_operation = info->current_operation; + } + + assert(info->total_operations > 0); + assert(info->operations_completed < info->total_operations); + + info->last_work_size = operation_work_size; + + current_work_size = info->offset_completed + operation_work_size; + + /* current_work_size is the total work size for (operations_completed + 1) + * operations (which includes this one), so multiply it by the number of + * operations not covered and divide it by the number of operations + * covered to get a projection for the operations not covered */ + projected_work_size = current_work_size * (info->total_operations - + info->operations_completed - 1) + / (info->operations_completed + 1); + + info->original_status_cb(bs, info->offset_completed + operation_offset, + current_work_size + projected_work_size, + info->original_cb_opaque); +} + static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, BlockDriverAmendStatusCB *status_cb, void *cb_opaque) @@ -2947,6 +3016,7 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, bool encrypt; int ret; QemuOptDesc *desc = opts->list->desc; + Qcow2AmendHelperCBInfo helper_cb_info; while (desc && desc->name) { if (!qemu_opt_find(opts, desc->name)) { @@ -3006,6 +3076,12 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, desc++; } + helper_cb_info = (Qcow2AmendHelperCBInfo){ + .original_status_cb = status_cb, + .original_cb_opaque = cb_opaque, + .total_operations = (new_version < old_version) + }; + /* Upgrade first (some features may require compat=1.1) */ if (new_version > old_version) { s->qcow_version = new_version; @@ -3065,7 +3141,9 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, /* Downgrade last (so unsupported features can be removed before) */ if (new_version < old_version) { - ret = qcow2_downgrade(bs, new_version, status_cb, cb_opaque); + helper_cb_info.current_operation = QCOW2_DOWNGRADING; + ret = qcow2_downgrade(bs, new_version, &qcow2_amend_helper_cb, + &helper_cb_info); if (ret < 0) { return ret; } -- cgit v1.1 From 791c9a004efbcff57c72dc83d19eb2bab0889d45 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Mon, 27 Jul 2015 17:51:37 +0200 Subject: qcow2: Add function for refcount order amendment Add a function qcow2_change_refcount_order() which allows changing the refcount order of a qcow2 image. Signed-off-by: Max Reitz Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block/qcow2-refcount.c | 447 +++++++++++++++++++++++++++++++++++++++++++++++++ block/qcow2.h | 4 + 2 files changed, 451 insertions(+) diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 820f412..e4020c6 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -2467,3 +2467,450 @@ int qcow2_pre_write_overlap_check(BlockDriverState *bs, int ign, int64_t offset, return 0; } + +/* A pointer to a function of this type is given to walk_over_reftable(). That + * function will create refblocks and pass them to a RefblockFinishOp once they + * are completed (@refblock). @refblock_empty is set if the refblock is + * completely empty. + * + * Along with the refblock, a corresponding reftable entry is passed, in the + * reftable @reftable (which may be reallocated) at @reftable_index. + * + * @allocated should be set to true if a new cluster has been allocated. + */ +typedef int (RefblockFinishOp)(BlockDriverState *bs, uint64_t **reftable, + uint64_t reftable_index, uint64_t *reftable_size, + void *refblock, bool refblock_empty, + bool *allocated, Error **errp); + +/** + * This "operation" for walk_over_reftable() allocates the refblock on disk (if + * it is not empty) and inserts its offset into the new reftable. The size of + * this new reftable is increased as required. + */ +static int alloc_refblock(BlockDriverState *bs, uint64_t **reftable, + uint64_t reftable_index, uint64_t *reftable_size, + void *refblock, bool refblock_empty, bool *allocated, + Error **errp) +{ + BDRVQcow2State *s = bs->opaque; + int64_t offset; + + if (!refblock_empty && reftable_index >= *reftable_size) { + uint64_t *new_reftable; + uint64_t new_reftable_size; + + new_reftable_size = ROUND_UP(reftable_index + 1, + s->cluster_size / sizeof(uint64_t)); + if (new_reftable_size > QCOW_MAX_REFTABLE_SIZE / sizeof(uint64_t)) { + error_setg(errp, + "This operation would make the refcount table grow " + "beyond the maximum size supported by QEMU, aborting"); + return -ENOTSUP; + } + + new_reftable = g_try_realloc(*reftable, new_reftable_size * + sizeof(uint64_t)); + if (!new_reftable) { + error_setg(errp, "Failed to increase reftable buffer size"); + return -ENOMEM; + } + + memset(new_reftable + *reftable_size, 0, + (new_reftable_size - *reftable_size) * sizeof(uint64_t)); + + *reftable = new_reftable; + *reftable_size = new_reftable_size; + } + + if (!refblock_empty && !(*reftable)[reftable_index]) { + offset = qcow2_alloc_clusters(bs, s->cluster_size); + if (offset < 0) { + error_setg_errno(errp, -offset, "Failed to allocate refblock"); + return offset; + } + (*reftable)[reftable_index] = offset; + *allocated = true; + } + + return 0; +} + +/** + * This "operation" for walk_over_reftable() writes the refblock to disk at the + * offset specified by the new reftable's entry. It does not modify the new + * reftable or change any refcounts. + */ +static int flush_refblock(BlockDriverState *bs, uint64_t **reftable, + uint64_t reftable_index, uint64_t *reftable_size, + void *refblock, bool refblock_empty, bool *allocated, + Error **errp) +{ + BDRVQcow2State *s = bs->opaque; + int64_t offset; + int ret; + + if (reftable_index < *reftable_size && (*reftable)[reftable_index]) { + offset = (*reftable)[reftable_index]; + + ret = qcow2_pre_write_overlap_check(bs, 0, offset, s->cluster_size); + if (ret < 0) { + error_setg_errno(errp, -ret, "Overlap check failed"); + return ret; + } + + ret = bdrv_pwrite(bs->file->bs, offset, refblock, s->cluster_size); + if (ret < 0) { + error_setg_errno(errp, -ret, "Failed to write refblock"); + return ret; + } + } else { + assert(refblock_empty); + } + + return 0; +} + +/** + * This function walks over the existing reftable and every referenced refblock; + * if @new_set_refcount is non-NULL, it is called for every refcount entry to + * create an equal new entry in the passed @new_refblock. Once that + * @new_refblock is completely filled, @operation will be called. + * + * @status_cb and @cb_opaque are used for the amend operation's status callback. + * @index is the index of the walk_over_reftable() calls and @total is the total + * number of walk_over_reftable() calls per amend operation. Both are used for + * calculating the parameters for the status callback. + * + * @allocated is set to true if a new cluster has been allocated. + */ +static int walk_over_reftable(BlockDriverState *bs, uint64_t **new_reftable, + uint64_t *new_reftable_index, + uint64_t *new_reftable_size, + void *new_refblock, int new_refblock_size, + int new_refcount_bits, + RefblockFinishOp *operation, bool *allocated, + Qcow2SetRefcountFunc *new_set_refcount, + BlockDriverAmendStatusCB *status_cb, + void *cb_opaque, int index, int total, + Error **errp) +{ + BDRVQcow2State *s = bs->opaque; + uint64_t reftable_index; + bool new_refblock_empty = true; + int refblock_index; + int new_refblock_index = 0; + int ret; + + for (reftable_index = 0; reftable_index < s->refcount_table_size; + reftable_index++) + { + uint64_t refblock_offset = s->refcount_table[reftable_index] + & REFT_OFFSET_MASK; + + status_cb(bs, (uint64_t)index * s->refcount_table_size + reftable_index, + (uint64_t)total * s->refcount_table_size, cb_opaque); + + if (refblock_offset) { + void *refblock; + + if (offset_into_cluster(s, refblock_offset)) { + qcow2_signal_corruption(bs, true, -1, -1, "Refblock offset %#" + PRIx64 " unaligned (reftable index: %#" + PRIx64 ")", refblock_offset, + reftable_index); + error_setg(errp, + "Image is corrupt (unaligned refblock offset)"); + return -EIO; + } + + ret = qcow2_cache_get(bs, s->refcount_block_cache, refblock_offset, + &refblock); + if (ret < 0) { + error_setg_errno(errp, -ret, "Failed to retrieve refblock"); + return ret; + } + + for (refblock_index = 0; refblock_index < s->refcount_block_size; + refblock_index++) + { + uint64_t refcount; + + if (new_refblock_index >= new_refblock_size) { + /* new_refblock is now complete */ + ret = operation(bs, new_reftable, *new_reftable_index, + new_reftable_size, new_refblock, + new_refblock_empty, allocated, errp); + if (ret < 0) { + qcow2_cache_put(bs, s->refcount_block_cache, &refblock); + return ret; + } + + (*new_reftable_index)++; + new_refblock_index = 0; + new_refblock_empty = true; + } + + refcount = s->get_refcount(refblock, refblock_index); + if (new_refcount_bits < 64 && refcount >> new_refcount_bits) { + uint64_t offset; + + qcow2_cache_put(bs, s->refcount_block_cache, &refblock); + + offset = ((reftable_index << s->refcount_block_bits) + + refblock_index) << s->cluster_bits; + + error_setg(errp, "Cannot decrease refcount entry width to " + "%i bits: Cluster at offset %#" PRIx64 " has a " + "refcount of %" PRIu64, new_refcount_bits, + offset, refcount); + return -EINVAL; + } + + if (new_set_refcount) { + new_set_refcount(new_refblock, new_refblock_index++, + refcount); + } else { + new_refblock_index++; + } + new_refblock_empty = new_refblock_empty && refcount == 0; + } + + qcow2_cache_put(bs, s->refcount_block_cache, &refblock); + } else { + /* No refblock means every refcount is 0 */ + for (refblock_index = 0; refblock_index < s->refcount_block_size; + refblock_index++) + { + if (new_refblock_index >= new_refblock_size) { + /* new_refblock is now complete */ + ret = operation(bs, new_reftable, *new_reftable_index, + new_reftable_size, new_refblock, + new_refblock_empty, allocated, errp); + if (ret < 0) { + return ret; + } + + (*new_reftable_index)++; + new_refblock_index = 0; + new_refblock_empty = true; + } + + if (new_set_refcount) { + new_set_refcount(new_refblock, new_refblock_index++, 0); + } else { + new_refblock_index++; + } + } + } + } + + if (new_refblock_index > 0) { + /* Complete the potentially existing partially filled final refblock */ + if (new_set_refcount) { + for (; new_refblock_index < new_refblock_size; + new_refblock_index++) + { + new_set_refcount(new_refblock, new_refblock_index, 0); + } + } + + ret = operation(bs, new_reftable, *new_reftable_index, + new_reftable_size, new_refblock, new_refblock_empty, + allocated, errp); + if (ret < 0) { + return ret; + } + + (*new_reftable_index)++; + } + + status_cb(bs, (uint64_t)(index + 1) * s->refcount_table_size, + (uint64_t)total * s->refcount_table_size, cb_opaque); + + return 0; +} + +int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order, + BlockDriverAmendStatusCB *status_cb, + void *cb_opaque, Error **errp) +{ + BDRVQcow2State *s = bs->opaque; + Qcow2GetRefcountFunc *new_get_refcount; + Qcow2SetRefcountFunc *new_set_refcount; + void *new_refblock = qemu_blockalign(bs->file->bs, s->cluster_size); + uint64_t *new_reftable = NULL, new_reftable_size = 0; + uint64_t *old_reftable, old_reftable_size, old_reftable_offset; + uint64_t new_reftable_index = 0; + uint64_t i; + int64_t new_reftable_offset = 0, allocated_reftable_size = 0; + int new_refblock_size, new_refcount_bits = 1 << refcount_order; + int old_refcount_order; + int walk_index = 0; + int ret; + bool new_allocation; + + assert(s->qcow_version >= 3); + assert(refcount_order >= 0 && refcount_order <= 6); + + /* see qcow2_open() */ + new_refblock_size = 1 << (s->cluster_bits - (refcount_order - 3)); + + new_get_refcount = get_refcount_funcs[refcount_order]; + new_set_refcount = set_refcount_funcs[refcount_order]; + + + do { + int total_walks; + + new_allocation = false; + + /* At least we have to do this walk and the one which writes the + * refblocks; also, at least we have to do this loop here at least + * twice (normally), first to do the allocations, and second to + * determine that everything is correctly allocated, this then makes + * three walks in total */ + total_walks = MAX(walk_index + 2, 3); + + /* First, allocate the structures so they are present in the refcount + * structures */ + ret = walk_over_reftable(bs, &new_reftable, &new_reftable_index, + &new_reftable_size, NULL, new_refblock_size, + new_refcount_bits, &alloc_refblock, + &new_allocation, NULL, status_cb, cb_opaque, + walk_index++, total_walks, errp); + if (ret < 0) { + goto done; + } + + new_reftable_index = 0; + + if (new_allocation) { + if (new_reftable_offset) { + qcow2_free_clusters(bs, new_reftable_offset, + allocated_reftable_size * sizeof(uint64_t), + QCOW2_DISCARD_NEVER); + } + + new_reftable_offset = qcow2_alloc_clusters(bs, new_reftable_size * + sizeof(uint64_t)); + if (new_reftable_offset < 0) { + error_setg_errno(errp, -new_reftable_offset, + "Failed to allocate the new reftable"); + ret = new_reftable_offset; + goto done; + } + allocated_reftable_size = new_reftable_size; + } + } while (new_allocation); + + /* Second, write the new refblocks */ + ret = walk_over_reftable(bs, &new_reftable, &new_reftable_index, + &new_reftable_size, new_refblock, + new_refblock_size, new_refcount_bits, + &flush_refblock, &new_allocation, new_set_refcount, + status_cb, cb_opaque, walk_index, walk_index + 1, + errp); + if (ret < 0) { + goto done; + } + assert(!new_allocation); + + + /* Write the new reftable */ + ret = qcow2_pre_write_overlap_check(bs, 0, new_reftable_offset, + new_reftable_size * sizeof(uint64_t)); + if (ret < 0) { + error_setg_errno(errp, -ret, "Overlap check failed"); + goto done; + } + + for (i = 0; i < new_reftable_size; i++) { + cpu_to_be64s(&new_reftable[i]); + } + + ret = bdrv_pwrite(bs->file->bs, new_reftable_offset, new_reftable, + new_reftable_size * sizeof(uint64_t)); + + for (i = 0; i < new_reftable_size; i++) { + be64_to_cpus(&new_reftable[i]); + } + + if (ret < 0) { + error_setg_errno(errp, -ret, "Failed to write the new reftable"); + goto done; + } + + + /* Empty the refcount cache */ + ret = qcow2_cache_flush(bs, s->refcount_block_cache); + if (ret < 0) { + error_setg_errno(errp, -ret, "Failed to flush the refblock cache"); + goto done; + } + + /* Update the image header to point to the new reftable; this only updates + * the fields which are relevant to qcow2_update_header(); other fields + * such as s->refcount_table or s->refcount_bits stay stale for now + * (because we have to restore everything if qcow2_update_header() fails) */ + old_refcount_order = s->refcount_order; + old_reftable_size = s->refcount_table_size; + old_reftable_offset = s->refcount_table_offset; + + s->refcount_order = refcount_order; + s->refcount_table_size = new_reftable_size; + s->refcount_table_offset = new_reftable_offset; + + ret = qcow2_update_header(bs); + if (ret < 0) { + s->refcount_order = old_refcount_order; + s->refcount_table_size = old_reftable_size; + s->refcount_table_offset = old_reftable_offset; + error_setg_errno(errp, -ret, "Failed to update the qcow2 header"); + goto done; + } + + /* Now update the rest of the in-memory information */ + old_reftable = s->refcount_table; + s->refcount_table = new_reftable; + + s->refcount_bits = 1 << refcount_order; + s->refcount_max = UINT64_C(1) << (s->refcount_bits - 1); + s->refcount_max += s->refcount_max - 1; + + s->refcount_block_bits = s->cluster_bits - (refcount_order - 3); + s->refcount_block_size = 1 << s->refcount_block_bits; + + s->get_refcount = new_get_refcount; + s->set_refcount = new_set_refcount; + + /* For cleaning up all old refblocks and the old reftable below the "done" + * label */ + new_reftable = old_reftable; + new_reftable_size = old_reftable_size; + new_reftable_offset = old_reftable_offset; + +done: + if (new_reftable) { + /* On success, new_reftable actually points to the old reftable (and + * new_reftable_size is the old reftable's size); but that is just + * fine */ + for (i = 0; i < new_reftable_size; i++) { + uint64_t offset = new_reftable[i] & REFT_OFFSET_MASK; + if (offset) { + qcow2_free_clusters(bs, offset, s->cluster_size, + QCOW2_DISCARD_OTHER); + } + } + g_free(new_reftable); + + if (new_reftable_offset > 0) { + qcow2_free_clusters(bs, new_reftable_offset, + new_reftable_size * sizeof(uint64_t), + QCOW2_DISCARD_OTHER); + } + } + + qemu_vfree(new_refblock); + return ret; +} diff --git a/block/qcow2.h b/block/qcow2.h index a9794de..a063a3c 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -529,6 +529,10 @@ int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset, int qcow2_pre_write_overlap_check(BlockDriverState *bs, int ign, int64_t offset, int64_t size); +int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order, + BlockDriverAmendStatusCB *status_cb, + void *cb_opaque, Error **errp); + /* qcow2-cluster.c functions */ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size, bool exact_size); -- cgit v1.1 From 61ce55fc02c57b5ec61e4b3a75dfab7ef6a92bd8 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Mon, 27 Jul 2015 17:51:38 +0200 Subject: qcow2: Invoke refcount order amendment function Make use of qcow2_change_refcount_order() to support changing the refcount order with qemu-img amend. Signed-off-by: Max Reitz Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block/qcow2.c | 44 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index 851de25..0304de6 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -2885,13 +2885,7 @@ static int qcow2_downgrade(BlockDriverState *bs, int target_version, } if (s->refcount_order != 4) { - /* we would have to convert the image to a refcount_order == 4 image - * here; however, since qemu (at the time of writing this) does not - * support anything different than 4 anyway, there is no point in doing - * so right now; however, we should error out (if qemu supports this in - * the future and this code has not been adapted) */ - error_report("qcow2_downgrade: Image refcount orders other than 4 are " - "currently not supported."); + error_report("compat=0.10 requires refcount_bits=16"); return -ENOTSUP; } @@ -2939,6 +2933,7 @@ typedef enum Qcow2AmendOperation { * invocation from an operation change */ QCOW2_NO_OPERATION = 0, + QCOW2_CHANGING_REFCOUNT_ORDER, QCOW2_DOWNGRADING, } Qcow2AmendOperation; @@ -3014,6 +3009,7 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, const char *compat = NULL; uint64_t cluster_size = s->cluster_size; bool encrypt; + int refcount_bits = s->refcount_bits; int ret; QemuOptDesc *desc = opts->list->desc; Qcow2AmendHelperCBInfo helper_cb_info; @@ -3065,8 +3061,16 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, lazy_refcounts = qemu_opt_get_bool(opts, BLOCK_OPT_LAZY_REFCOUNTS, lazy_refcounts); } else if (!strcmp(desc->name, BLOCK_OPT_REFCOUNT_BITS)) { - error_report("Cannot change refcount entry width"); - return -ENOTSUP; + refcount_bits = qemu_opt_get_number(opts, BLOCK_OPT_REFCOUNT_BITS, + refcount_bits); + + if (refcount_bits <= 0 || refcount_bits > 64 || + !is_power_of_2(refcount_bits)) + { + error_report("Refcount width must be a power of two and may " + "not exceed 64 bits"); + return -EINVAL; + } } else { /* if this point is reached, this probably means a new option was * added without having it covered here */ @@ -3080,6 +3084,7 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, .original_status_cb = status_cb, .original_cb_opaque = cb_opaque, .total_operations = (new_version < old_version) + + (s->refcount_bits != refcount_bits) }; /* Upgrade first (some features may require compat=1.1) */ @@ -3092,6 +3097,27 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, } } + if (s->refcount_bits != refcount_bits) { + int refcount_order = ctz32(refcount_bits); + Error *local_error = NULL; + + if (new_version < 3 && refcount_bits != 16) { + error_report("Different refcount widths than 16 bits require " + "compatibility level 1.1 or above (use compat=1.1 or " + "greater)"); + return -EINVAL; + } + + helper_cb_info.current_operation = QCOW2_CHANGING_REFCOUNT_ORDER; + ret = qcow2_change_refcount_order(bs, refcount_order, + &qcow2_amend_helper_cb, + &helper_cb_info, &local_error); + if (ret < 0) { + error_report_err(local_error); + return ret; + } + } + if (backing_file || backing_format) { ret = qcow2_change_backing_file(bs, backing_file ?: s->image_backing_file, -- cgit v1.1 From 03bb78ed250874f76e0854aa4d5d95af1e12613e Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Mon, 27 Jul 2015 17:51:39 +0200 Subject: qcow2: Point to amend function in check If a reference count is not representable with the current refcount order, the image check should point to qemu-img amend for increasing the refcount order. However, qemu-img amend needs write access to the image which cannot be provided if the image is marked corrupt; and the image check will not mark the image consistent unless everything actually is consistent. Therefore, if an image is marked corrupt and the image check encounters a reference count overflow, it cannot be fixed by using qemu-img amend to increase the refcount order. Instead, one has to use qemu-img convert to create a completely new copy of the image in this case. Alternatively, we may want to give the user a way of manually removing the corrupt flag, maybe through qemu-img amend, but this is not part of this patch. Signed-off-by: Max Reitz Reviewed-by: Eric Blake Reviewed-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf --- block/qcow2-refcount.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index e4020c6..af493f8 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -1345,6 +1345,9 @@ static int inc_refcounts(BlockDriverState *bs, if (refcount == s->refcount_max) { fprintf(stderr, "ERROR: overflow cluster offset=0x%" PRIx64 "\n", cluster_offset); + fprintf(stderr, "Use qemu-img amend to increase the refcount entry " + "width or qemu-img convert to create a clean copy if the " + "image cannot be opened for writing\n"); res->corruptions++; continue; } -- cgit v1.1 From e9dbdc5e46054c4660b4c4f705ce8ff6aeb4959b Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Mon, 27 Jul 2015 17:51:40 +0200 Subject: iotests: Extend test 112 for qemu-img amend Add tests for conversion between different refcount widths. Signed-off-by: Max Reitz Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- tests/qemu-iotests/112 | 109 +++++++++++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/112.out | 71 +++++++++++++++++++++++++++++ 2 files changed, 180 insertions(+) diff --git a/tests/qemu-iotests/112 b/tests/qemu-iotests/112 index 3f054a3..34ba06a 100755 --- a/tests/qemu-iotests/112 +++ b/tests/qemu-iotests/112 @@ -180,6 +180,115 @@ $QEMU_IMG snapshot -c foo "$TEST_IMG" # leaked (refcount=UINT64_MAX reference=1) _check_test_img +echo +echo '=== Amend from refcount_bits=16 to refcount_bits=1 ===' +echo + +_make_test_img 64M +print_refcount_bits + +$QEMU_IO -c 'write 16M 32M' "$TEST_IMG" | _filter_qemu_io +$QEMU_IMG amend -o refcount_bits=1 "$TEST_IMG" +_check_test_img +print_refcount_bits + +echo +echo '=== Amend from refcount_bits=1 to refcount_bits=64 ===' +echo + +$QEMU_IMG amend -o refcount_bits=64 "$TEST_IMG" +_check_test_img +print_refcount_bits + +echo +echo '=== Amend to compat=0.10 ===' +echo + +# Should not work because refcount_bits needs to be 16 for compat=0.10 +$QEMU_IMG amend -o compat=0.10 "$TEST_IMG" +print_refcount_bits +# Should work +$QEMU_IMG amend -o compat=0.10,refcount_bits=16 "$TEST_IMG" +_check_test_img +print_refcount_bits + +# Get back to compat=1.1 and refcount_bits=16 +$QEMU_IMG amend -o compat=1.1 "$TEST_IMG" +print_refcount_bits +# Should not work +$QEMU_IMG amend -o refcount_bits=32,compat=0.10 "$TEST_IMG" +print_refcount_bits + +echo +echo '=== Amend with snapshot ===' +echo + +$QEMU_IMG snapshot -c foo "$TEST_IMG" +# Just to have different refcounts across the image +$QEMU_IO -c 'write 0 16M' "$TEST_IMG" | _filter_qemu_io + +# Should not work (may work in the future by first decreasing all refcounts so +# they fit into the target range by copying them) +$QEMU_IMG amend -o refcount_bits=1 "$TEST_IMG" +_check_test_img +print_refcount_bits + +# Should work +$QEMU_IMG amend -o refcount_bits=2 "$TEST_IMG" +_check_test_img +print_refcount_bits + +echo +echo '=== Testing too many references for check ===' +echo + +IMGOPTS="$IMGOPTS,refcount_bits=1" _make_test_img 64M +print_refcount_bits + +# This cluster should be created at 0x50000 +$QEMU_IO -c 'write 0 64k' "$TEST_IMG" | _filter_qemu_io +# Now make the second L2 entry (the L2 table should be at 0x40000) point to that +# cluster, so we have two references +poke_file "$TEST_IMG" $((0x40008)) "\x80\x00\x00\x00\x00\x05\x00\x00" + +# This should say "please use amend" +_check_test_img -r all + +# So we do that +$QEMU_IMG amend -o refcount_bits=2 "$TEST_IMG" +print_refcount_bits + +# And try again +_check_test_img -r all + +echo +echo '=== Multiple walks necessary during amend ===' +echo + +IMGOPTS="$IMGOPTS,refcount_bits=1,cluster_size=512" _make_test_img 64k + +# Cluster 0 is the image header, clusters 1 to 4 are used by the L1 table, a +# single L2 table, the reftable and a single refblock. This creates 58 data +# clusters (actually, the L2 table is created here, too), so in total there are +# then 63 used clusters in the image. With a refcount width of 64, one refblock +# describes 64 clusters (512 bytes / 64 bits/entry = 64 entries), so this will +# make the first refblock in the amended image have exactly one free entry. +$QEMU_IO -c "write 0 $((58 * 512))" "$TEST_IMG" | _filter_qemu_io + +# Now change the refcount width; since the first new refblock will have exactly +# one free entry, that entry will be used to store its own reference. No other +# refblocks are needed, so then the new reftable will be allocated; since the +# first new refblock is completely filled up, this will require a new refblock +# which is why the refcount width changing function will need to run through +# everything one more time until the allocations are stable. +# Having more walks than usual should be visible as regressing progress (from +# 66.67 % (2/3 walks) to 50.00 % (2/4 walks)). +$QEMU_IMG amend -o refcount_bits=64 -p "$TEST_IMG" | tr '\r' '\n' \ + | grep -A 1 '66.67' +print_refcount_bits + +_check_test_img + # success, all done echo '*** done' diff --git a/tests/qemu-iotests/112.out b/tests/qemu-iotests/112.out index 8dd3df0..81b04d1 100644 --- a/tests/qemu-iotests/112.out +++ b/tests/qemu-iotests/112.out @@ -81,4 +81,75 @@ Leaked cluster 6 refcount=1 reference=0 2 leaked clusters were found on the image. This means waste of disk space, but no harm to data. + +=== Amend from refcount_bits=16 to refcount_bits=1 === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +refcount bits: 16 +wrote 33554432/33554432 bytes at offset 16777216 +32 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +No errors were found on the image. +refcount bits: 1 + +=== Amend from refcount_bits=1 to refcount_bits=64 === + +No errors were found on the image. +refcount bits: 64 + +=== Amend to compat=0.10 === + +qemu-img: compat=0.10 requires refcount_bits=16 +qemu-img: Error while amending options: Operation not supported +refcount bits: 64 +No errors were found on the image. +refcount bits: 16 +refcount bits: 16 +qemu-img: Different refcount widths than 16 bits require compatibility level 1.1 or above (use compat=1.1 or greater) +qemu-img: Error while amending options: Invalid argument +refcount bits: 16 + +=== Amend with snapshot === + +wrote 16777216/16777216 bytes at offset 0 +16 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +qemu-img: Cannot decrease refcount entry width to 1 bits: Cluster at offset 0x50000 has a refcount of 2 +qemu-img: Error while amending options: Invalid argument +No errors were found on the image. +refcount bits: 16 +No errors were found on the image. +refcount bits: 2 + +=== Testing too many references for check === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +refcount bits: 1 +wrote 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +ERROR: overflow cluster offset=0x50000 +Use qemu-img amend to increase the refcount entry width or qemu-img convert to create a clean copy if the image cannot be opened for writing + +1 errors were found on the image. +Data may be corrupted, or further writes to the image may corrupt it. +refcount bits: 2 +ERROR cluster 5 refcount=1 reference=2 +Repairing cluster 5 refcount=1 reference=2 +Repairing OFLAG_COPIED data cluster: l2_entry=8000000000050000 refcount=2 +Repairing OFLAG_COPIED data cluster: l2_entry=8000000000050000 refcount=2 +The following inconsistencies were found and repaired: + + 0 leaked clusters + 3 corruptions + +Double checking the fixed image now... +No errors were found on the image. + +=== Multiple walks necessary during amend === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=65536 +wrote 29696/29696 bytes at offset 0 +29 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + (66.67/100%) + (50.00/100%) +refcount bits: 64 +No errors were found on the image. *** done -- cgit v1.1 From b1fc8f934ba3fcdc8381b89413ad4df2e90d5312 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 10 Dec 2015 12:55:48 +0300 Subject: qcow2: insert assert into qcow2_get_specific_info() s->qcow_version is always set to 2 or 3. Let's assert if this is wrong. Signed-off-by: Denis V. Lunev CC: Roman Kagan CC: Max Reitz CC: Kevin Wolf Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- block/qcow2.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/block/qcow2.c b/block/qcow2.c index 0304de6..1789af4 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -2803,6 +2803,10 @@ static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs) .has_corrupt = true, .refcount_bits = s->refcount_bits, }; + } else { + /* if this assertion fails, this probably means a new version was + * added without having it covered here */ + assert(false); } return spec_info; -- cgit v1.1 From d657c0c289e944fc22289f5c318f48da87d79dcb Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 15 Dec 2015 11:35:36 +0100 Subject: raw-posix: Make aio=native option binding Traditionally, aio=native was treated as an advice that could simply be ignored if an error occurs while initialising Linux AIO or the feature wasn't compiled in. This behaviour was deprecated in commit 96518254 (qemu 2.3; error during init) and commit 1501ecc1 (qemu 2.5; not compiled in). This patch changes raw-posix to error out in these cases instead of printing a deprecation warning. Signed-off-by: Kevin Wolf Acked-by: Christian Borntraeger Reviewed-by: Stefan Hajnoczi --- block/raw-posix.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/block/raw-posix.c b/block/raw-posix.c index ffeebe1..076d070 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -500,21 +500,17 @@ static int raw_open_common(BlockDriverState *bs, QDict *options, goto fail; } if (!s->use_aio && (bdrv_flags & BDRV_O_NATIVE_AIO)) { - error_printf("WARNING: aio=native was specified for '%s', but " - "it requires cache.direct=on, which was not " - "specified. Falling back to aio=threads.\n" - " This will become an error condition in " - "future QEMU versions.\n", - bs->filename); + error_setg(errp, "aio=native was specified, but it requires " + "cache.direct=on, which was not specified."); + ret = -EINVAL; + goto fail; } #else if (bdrv_flags & BDRV_O_NATIVE_AIO) { - error_printf("WARNING: aio=native was specified for '%s', but " - "is not supported in this build. Falling back to " - "aio=threads.\n" - " This will become an error condition in " - "future QEMU versions.\n", - bs->filename); + error_setg(errp, "aio=native was specified, but is not supported " + "in this build."); + ret = -EINVAL; + goto fail; } #endif /* !defined(CONFIG_LINUX_AIO) */ -- cgit v1.1 From bbe1ef2686ff66f76427b9c1cb42f4b8a4b82556 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Fri, 18 Dec 2015 09:04:35 +0800 Subject: block: Remove prototype of bdrv_swap from header The function has gone. Signed-off-by: Fam Zheng Signed-off-by: Kevin Wolf --- include/block/block.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/block/block.h b/include/block/block.h index bce0d86..db8e096 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -198,7 +198,6 @@ int bdrv_create_file(const char *filename, QemuOpts *opts, Error **errp); BlockDriverState *bdrv_new_root(void); BlockDriverState *bdrv_new(void); void bdrv_make_anon(BlockDriverState *bs); -void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old); void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top); void bdrv_replace_in_backing_chain(BlockDriverState *old, BlockDriverState *new); -- cgit v1.1 From 8382ba615376dc1b7dc6e08525765f6d534e780d Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Fri, 18 Dec 2015 09:04:36 +0800 Subject: iotests: Update comments for bdrv_swap() in 094 Signed-off-by: Fam Zheng Signed-off-by: Kevin Wolf --- tests/qemu-iotests/094 | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/qemu-iotests/094 b/tests/qemu-iotests/094 index 27a2be2..57a68f8 100755 --- a/tests/qemu-iotests/094 +++ b/tests/qemu-iotests/094 @@ -1,6 +1,6 @@ #!/bin/bash # -# Test case for drive-mirror to NBD (especially bdrv_swap() on NBD BDS) +# Test case for drive-mirror to NBD # # Copyright (C) 2015 Red Hat, Inc. # @@ -50,8 +50,10 @@ _send_qemu_cmd $QEMU_HANDLE \ "{'execute': 'qmp_capabilities'}" \ 'return' -# 'format': 'nbd' is not actually "correct", but this is probably the only way -# to test bdrv_swap() on an NBD BDS +# 'format': 'nbd' is not actually "correct", but this was the only way to +# test the bug fixed in commit f53a829. Though the bug's related code +# bdrv_swap() was replaced later, let's make sure we don't fall in the same +# pit again. _send_qemu_cmd $QEMU_HANDLE \ "{'execute': 'drive-mirror', 'arguments': {'device': 'src', -- cgit v1.1 From 27a7649a48f9019fa5bd2998d8e342791397bdda Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 16 Dec 2015 19:33:45 +0100 Subject: block: use drained section around bdrv_snapshot_delete Do not use bdrv_drain, since by itself it does not guarantee anything. Signed-off-by: Paolo Bonzini Reviewed-by: Fam Zheng Signed-off-by: Kevin Wolf --- block/snapshot.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/block/snapshot.c b/block/snapshot.c index 6e9fa8d..2d86b88 100644 --- a/block/snapshot.c +++ b/block/snapshot.c @@ -229,6 +229,8 @@ int bdrv_snapshot_delete(BlockDriverState *bs, Error **errp) { BlockDriver *drv = bs->drv; + int ret; + if (!drv) { error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, bdrv_get_device_name(bs)); return -ENOMEDIUM; @@ -239,18 +241,21 @@ int bdrv_snapshot_delete(BlockDriverState *bs, } /* drain all pending i/o before deleting snapshot */ - bdrv_drain(bs); + bdrv_drained_begin(bs); if (drv->bdrv_snapshot_delete) { - return drv->bdrv_snapshot_delete(bs, snapshot_id, name, errp); + ret = drv->bdrv_snapshot_delete(bs, snapshot_id, name, errp); + } else if (bs->file) { + ret = bdrv_snapshot_delete(bs->file->bs, snapshot_id, name, errp); + } else { + error_setg(errp, "Block format '%s' used by device '%s' " + "does not support internal snapshot deletion", + drv->format_name, bdrv_get_device_name(bs)); + ret = -ENOTSUP; } - if (bs->file) { - return bdrv_snapshot_delete(bs->file->bs, snapshot_id, name, errp); - } - error_setg(errp, "Block format '%s' used by device '%s' " - "does not support internal snapshot deletion", - drv->format_name, bdrv_get_device_name(bs)); - return -ENOTSUP; + + bdrv_drained_end(bs); + return ret; } int bdrv_snapshot_delete_by_id_or_name(BlockDriverState *bs, -- cgit v1.1 From ba889444957aaeb073a3a95f5cb2794aa1b222f5 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 16 Dec 2015 19:33:47 +0100 Subject: block: fix bdrv_ioctl called from coroutine When called from a coroutine, bdrv_ioctl must be asynchronous just like e.g. bdrv_flush. The code was incorrectly making it synchronous, fix it. Signed-off-by: Paolo Bonzini Reviewed-by: Fam Zheng Signed-off-by: Kevin Wolf --- block/io.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/block/io.c b/block/io.c index e00fb5d..841f5b5 100644 --- a/block/io.c +++ b/block/io.c @@ -2614,10 +2614,11 @@ int bdrv_ioctl(BlockDriverState *bs, unsigned long int req, void *buf) bdrv_co_ioctl_entry(&data); } else { Coroutine *co = qemu_coroutine_create(bdrv_co_ioctl_entry); + qemu_coroutine_enter(co, &data); - } - while (data.ret == -EINPROGRESS) { - aio_poll(bdrv_get_aio_context(bs), true); + while (data.ret == -EINPROGRESS) { + aio_poll(bdrv_get_aio_context(bs), true); + } } return data.ret; } -- cgit v1.1 From 8a7607c2e201f22aa73df03661c23c7d1fbd7540 Mon Sep 17 00:00:00 2001 From: Bo Tu Date: Thu, 3 Dec 2015 18:01:29 +0800 Subject: qemu-iotests: refine common.config Replacing awk with sed, then it's easier to read. Replacing "[ ! -z "$default_alias_machine" ]" with "[[ $default_alias_machine ]]", then it's slightly shorter. Reviewed-by: Max Reitz Suggested-By: Sascha Silbe Reviewed-by: Sascha Silbe Reviewed-by: Eric Blake Signed-off-by: Bo Tu Message-id: 1449136891-26850-2-git-send-email-tubo@linux.vnet.ibm.com Signed-off-by: Max Reitz --- tests/qemu-iotests/common.config | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tests/qemu-iotests/common.config b/tests/qemu-iotests/common.config index 3ed51b8..60bfabf 100644 --- a/tests/qemu-iotests/common.config +++ b/tests/qemu-iotests/common.config @@ -154,11 +154,10 @@ export QEMU_IMG=_qemu_img_wrapper export QEMU_IO=_qemu_io_wrapper export QEMU_NBD=_qemu_nbd_wrapper -default_machine=$($QEMU -machine \? | awk '/(default)/{print $1}') -default_alias_machine=$($QEMU -machine \? |\ - awk -v var_default_machine="$default_machine"\)\ - '{if ($(NF-2)=="(alias"&&$(NF-1)=="of"&&$(NF)==var_default_machine){print $1}}') -if [ ! -z "$default_alias_machine" ]; then +default_machine=$($QEMU -machine help | sed -n '/(default)/ s/ .*//p') +default_alias_machine=$($QEMU -machine help | \ + sed -n "/(alias of $default_machine)/ { s/ .*//p; q; }") +if [[ "$default_alias_machine" ]]; then default_machine="$default_alias_machine" fi -- cgit v1.1 From 289f3ebae85f28082960317f2a4271bc3c03df10 Mon Sep 17 00:00:00 2001 From: Bo Tu Date: Thu, 3 Dec 2015 18:01:30 +0800 Subject: qemu-iotests: s390x: fix test 051 The tests for ide device should only be tested for the pc platform. Set device_id to "drive0", and replace every "-drive file..." by "-drive file=...,if=none,id=$device_id", then x86 and s390x can get the common output in the test of "Snapshot mode". Warning message expected for s390x when drive without device. A x86 platform specific output file is also needed. Reviewed-by: Sascha Silbe Signed-off-by: Bo Tu Message-id: 1449136891-26850-3-git-send-email-tubo@linux.vnet.ibm.com Signed-off-by: Max Reitz --- tests/qemu-iotests/051 | 77 ++++--- tests/qemu-iotests/051.out | 140 ++++-------- tests/qemu-iotests/051.pc.out | 482 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 569 insertions(+), 130 deletions(-) create mode 100644 tests/qemu-iotests/051.pc.out diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051 index da90f59..75713c2 100755 --- a/tests/qemu-iotests/051 +++ b/tests/qemu-iotests/051 @@ -148,33 +148,49 @@ run_qemu -drive if=ide run_qemu -drive if=virtio run_qemu -drive if=scsi -run_qemu -drive if=none,id=disk -device ide-cd,drive=disk -run_qemu -drive if=none,id=disk -device lsi53c895a -device scsi-cd,drive=disk - -run_qemu -drive if=none,id=disk -device ide-drive,drive=disk -run_qemu -drive if=none,id=disk -device ide-hd,drive=disk -run_qemu -drive if=none,id=disk -device lsi53c895a -device scsi-disk,drive=disk -run_qemu -drive if=none,id=disk -device lsi53c895a -device scsi-hd,drive=disk +case "$QEMU_DEFAULT_MACHINE" in + pc) + run_qemu -drive if=none,id=disk -device ide-cd,drive=disk + run_qemu -drive if=none,id=disk -device lsi53c895a -device scsi-cd,drive=disk + run_qemu -drive if=none,id=disk -device ide-drive,drive=disk + run_qemu -drive if=none,id=disk -device ide-hd,drive=disk + run_qemu -drive if=none,id=disk -device lsi53c895a -device scsi-disk,drive=disk + run_qemu -drive if=none,id=disk -device lsi53c895a -device scsi-hd,drive=disk + ;; + *) + ;; +esac echo echo === Read-only === echo -run_qemu -drive file="$TEST_IMG",if=floppy,readonly=on -run_qemu -drive file="$TEST_IMG",if=ide,media=cdrom,readonly=on -run_qemu -drive file="$TEST_IMG",if=scsi,media=cdrom,readonly=on +case "$QEMU_DEFAULT_MACHINE" in + pc) + run_qemu -drive file="$TEST_IMG",if=floppy,readonly=on + run_qemu -drive file="$TEST_IMG",if=ide,media=cdrom,readonly=on + run_qemu -drive file="$TEST_IMG",if=scsi,media=cdrom,readonly=on + run_qemu -drive file="$TEST_IMG",if=ide,readonly=on + ;; + *) + ;; +esac -run_qemu -drive file="$TEST_IMG",if=ide,readonly=on run_qemu -drive file="$TEST_IMG",if=virtio,readonly=on run_qemu -drive file="$TEST_IMG",if=scsi,readonly=on -run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device ide-cd,drive=disk -run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device lsi53c895a -device scsi-cd,drive=disk - -run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device ide-drive,drive=disk -run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device ide-hd,drive=disk -run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device lsi53c895a -device scsi-disk,drive=disk -run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device lsi53c895a -device scsi-hd,drive=disk +case "$QEMU_DEFAULT_MACHINE" in + pc) + run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device ide-cd,drive=disk + run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device lsi53c895a -device scsi-cd,drive=disk + run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device ide-drive,drive=disk + run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device ide-hd,drive=disk + run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device lsi53c895a -device scsi-disk,drive=disk + run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device lsi53c895a -device scsi-hd,drive=disk + ;; + *) + ;; +esac echo echo === Cache modes === @@ -261,26 +277,31 @@ echo $QEMU_IO -c "write -P 0x11 0 4k" "$TEST_IMG" | _filter_qemu_io -echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive file="$TEST_IMG" -snapshot | _filter_qemu_io -echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive file="$TEST_IMG",snapshot=on | _filter_qemu_io -echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive file.filename="$TEST_IMG",driver=qcow2,snapshot=on | _filter_qemu_io -echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive file.filename="$TEST_IMG",driver=qcow2 -snapshot | _filter_qemu_io -echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive file="file:$TEST_IMG" -snapshot | _filter_qemu_io -echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive file="file:$TEST_IMG",snapshot=on | _filter_qemu_io +device_id="drive0" + +echo "qemu-io $device_id \"write -P 0x22 0 4k\"" | run_qemu -drive file="$TEST_IMG",if=none,id=$device_id -snapshot | _filter_qemu_io +echo "qemu-io $device_id \"write -P 0x22 0 4k\"" | run_qemu -drive file="$TEST_IMG",snapshot=on,if=none,id=$device_id | _filter_qemu_io +echo "qemu-io $device_id \"write -P 0x22 0 4k\"" | run_qemu -drive file.filename="$TEST_IMG",driver=qcow2,snapshot=on,if=none,id=$device_id\ + | _filter_qemu_io +echo "qemu-io $device_id \"write -P 0x22 0 4k\"" | run_qemu -drive file.filename="$TEST_IMG",driver=qcow2,if=none,id=$device_id -snapshot\ + | _filter_qemu_io +echo "qemu-io $device_id \"write -P 0x22 0 4k\"" | run_qemu -drive file="file:$TEST_IMG",if=none,id=$device_id -snapshot | _filter_qemu_io +echo "qemu-io $device_id \"write -P 0x22 0 4k\"" | run_qemu -drive file="file:$TEST_IMG",snapshot=on,if=none,id=$device_id | _filter_qemu_io # Opening a read-only file r/w with snapshot=on chmod u-w "$TEST_IMG" -echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive file="$TEST_IMG" -snapshot | _filter_qemu_io -echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive file="$TEST_IMG",snapshot=on | _filter_qemu_io +echo "qemu-io $device_id \"write -P 0x22 0 4k\"" | run_qemu -drive file="$TEST_IMG",if=none,id=$device_id -snapshot | _filter_qemu_io +echo "qemu-io $device_id \"write -P 0x22 0 4k\"" | run_qemu -drive file="$TEST_IMG",snapshot=on,if=none,id=$device_id | _filter_qemu_io chmod u+w "$TEST_IMG" $QEMU_IO -c "read -P 0x11 0 4k" "$TEST_IMG" | _filter_qemu_io -echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive file="$TEST_IMG",snapshot=off | _filter_qemu_io +echo "qemu-io $device_id \"write -P 0x22 0 4k\"" | run_qemu -drive file="$TEST_IMG",snapshot=off,if=none,id=$device_id | _filter_qemu_io $QEMU_IO -c "read -P 0x22 0 4k" "$TEST_IMG" | _filter_qemu_io -echo -e 'qemu-io ide0-hd0 "write -P 0x33 0 4k"\ncommit ide0-hd0' | run_qemu -drive file="$TEST_IMG",snapshot=on | _filter_qemu_io +echo -e "qemu-io $device_id \"write -P 0x33 0 4k\"\ncommit $device_id" | run_qemu -drive file="$TEST_IMG",snapshot=on,if=none,id=$device_id\ + | _filter_qemu_io $QEMU_IO -c "read -P 0x33 0 4k" "$TEST_IMG" | _filter_qemu_io diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out index 070d318..143e3ea 100644 --- a/tests/qemu-iotests/051.out +++ b/tests/qemu-iotests/051.out @@ -5,16 +5,16 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/ === Unknown option === Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt= -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=: Block format 'qcow2' used by device 'ide0-hd0' doesn't support the option 'unknown_opt' +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=: Block format 'qcow2' used by device 'virtio0' doesn't support the option 'unknown_opt' Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=on -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=on: Block format 'qcow2' used by device 'ide0-hd0' doesn't support the option 'unknown_opt' +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=on: Block format 'qcow2' used by device 'virtio0' doesn't support the option 'unknown_opt' Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=1234 -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=1234: Block format 'qcow2' used by device 'ide0-hd0' doesn't support the option 'unknown_opt' +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=1234: Block format 'qcow2' used by device 'virtio0' doesn't support the option 'unknown_opt' Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=foo -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=foo: Block format 'qcow2' used by device 'ide0-hd0' doesn't support the option 'unknown_opt' +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=foo: Block format 'qcow2' used by device 'virtio0' doesn't support the option 'unknown_opt' === Unknown protocol option === @@ -59,7 +59,7 @@ QEMU X.Y.Z monitor - type 'help' for more information Testing: -drive file=TEST_DIR/t.qcow2,driver=qcow2,backing.file.filename=TEST_DIR/t.qcow2.orig -nodefaults QEMU X.Y.Z monitor - type 'help' for more information (qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo block -ide0-hd0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) +virtio0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) Cache mode: writeback Backing file: TEST_DIR/t.qcow2.orig (chain depth: 1) (qemu) qququiquit @@ -109,20 +109,23 @@ QEMU X.Y.Z monitor - type 'help' for more information Testing: -drive if=floppy QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qququiquit +(qemu) Warning: Orphaned drive without device: id=floppy0,file=,if=floppy,bus=0,unit=0 +qququiquit Testing: -drive if=ide,media=cdrom QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qququiquit +(qemu) Warning: Orphaned drive without device: id=ide0-cd0,file=,if=ide,bus=0,unit=0 +qququiquit Testing: -drive if=scsi,media=cdrom QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qququiquit +(qemu) Warning: Orphaned drive without device: id=scsi0-cd0,file=,if=scsi,bus=0,unit=0 +qququiquit Testing: -drive if=ide QEMU X.Y.Z monitor - type 'help' for more information -(qemu) QEMU_PROG: Device needs media, but drive is empty -QEMU_PROG: Initialization of device ide-hd failed: Device initialization failed. +(qemu) Warning: Orphaned drive without device: id=ide0-hd0,file=,if=ide,bus=0,unit=0 +qququiquit Testing: -drive if=virtio QEMU X.Y.Z monitor - type 'help' for more information @@ -130,87 +133,20 @@ QEMU X.Y.Z monitor - type 'help' for more information Testing: -drive if=scsi QEMU X.Y.Z monitor - type 'help' for more information -(qemu) QEMU_PROG: Initialization of device lsi53c895a failed: Device needs media, but drive is empty - -Testing: -drive if=none,id=disk -device ide-cd,drive=disk -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qququiquit - -Testing: -drive if=none,id=disk -device lsi53c895a -device scsi-cd,drive=disk -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qququiquit - -Testing: -drive if=none,id=disk -device ide-drive,drive=disk -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) QEMU_PROG: -device ide-drive,drive=disk: Device needs media, but drive is empty -QEMU_PROG: -device ide-drive,drive=disk: Device initialization failed. - -Testing: -drive if=none,id=disk -device ide-hd,drive=disk -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) QEMU_PROG: -device ide-hd,drive=disk: Device needs media, but drive is empty -QEMU_PROG: -device ide-hd,drive=disk: Device initialization failed. - -Testing: -drive if=none,id=disk -device lsi53c895a -device scsi-disk,drive=disk -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) QEMU_PROG: -device scsi-disk,drive=disk: Device needs media, but drive is empty - -Testing: -drive if=none,id=disk -device lsi53c895a -device scsi-hd,drive=disk -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) QEMU_PROG: -device scsi-hd,drive=disk: Device needs media, but drive is empty +(qemu) Warning: Orphaned drive without device: id=scsi0-hd0,file=,if=scsi,bus=0,unit=0 +qququiquit === Read-only === -Testing: -drive file=TEST_DIR/t.qcow2,if=floppy,readonly=on -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qququiquit - -Testing: -drive file=TEST_DIR/t.qcow2,if=ide,media=cdrom,readonly=on -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qququiquit - -Testing: -drive file=TEST_DIR/t.qcow2,if=scsi,media=cdrom,readonly=on -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qququiquit - -Testing: -drive file=TEST_DIR/t.qcow2,if=ide,readonly=on -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) QEMU_PROG: Can't use a read-only drive -QEMU_PROG: Initialization of device ide-hd failed: Device initialization failed. - Testing: -drive file=TEST_DIR/t.qcow2,if=virtio,readonly=on QEMU X.Y.Z monitor - type 'help' for more information (qemu) qququiquit Testing: -drive file=TEST_DIR/t.qcow2,if=scsi,readonly=on QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qququiquit - -Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-cd,drive=disk -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qququiquit - -Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-cd,drive=disk -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qququiquit - -Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-drive,drive=disk -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) QEMU_PROG: -device ide-drive,drive=disk: Can't use a read-only drive -QEMU_PROG: -device ide-drive,drive=disk: Device initialization failed. - -Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-hd,drive=disk -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) QEMU_PROG: -device ide-hd,drive=disk: Can't use a read-only drive -QEMU_PROG: -device ide-hd,drive=disk: Device initialization failed. - -Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-disk,drive=disk -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qququiquit - -Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-hd,drive=disk -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qququiquit +(qemu) Warning: Orphaned drive without device: id=scsi0-hd0,file=TEST_DIR/t.qcow2,if=scsi,bus=0,unit=0 +qququiquit === Cache modes === @@ -402,79 +338,79 @@ QEMU_PROG: -drive file.filename=file:TEST_DIR/t.qcow2: Could not open 'file:TEST wrote 4096/4096 bytes at offset 0 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -Testing: -drive file=TEST_DIR/t.qcow2 -snapshot +Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=drive0 -snapshot QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io iqemu-io idqemu-io ideqemu-io ide0qemu-io ide0-qemu-io ide0-hqemu-io ide0-hdqemu-io ide0-hd0qemu-io ide0-hd0 qemu-io ide0-hd0 "qemu-io ide0-hd0 "wqemu-io ide0-hd0 "wrqemu-io ide0-hd0 "wriqemu-io ide0-hd0 "writqemu-io ide0-hd0 "writeqemu-io ide0-hd0 "write qemu-io ide0-hd0 "write -qemu-io ide0-hd0 "write -Pqemu-io ide0-hd0 "write -P qemu-io ide0-hd0 "write -P 0qemu-io ide0-hd0 "write -P 0xqemu-io ide0-hd0 "write -P 0x2qemu-io ide0-hd0 "write -P 0x22qemu-io ide0-hd0 "write -P 0x22 qemu-io ide0-hd0 "write -P 0x22 0qemu-io ide0-hd0 "write -P 0x22 0 qemu-io ide0-hd0 "write -P 0x22 0 4qemu-io ide0-hd0 "write -P 0x22 0 4kqemu-io ide0-hd0 "write -P 0x22 0 4k" +(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k" wrote 4096/4096 bytes at offset 0 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) (qemu) qququiquit -Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on +Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,if=none,id=drive0 QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io iqemu-io idqemu-io ideqemu-io ide0qemu-io ide0-qemu-io ide0-hqemu-io ide0-hdqemu-io ide0-hd0qemu-io ide0-hd0 qemu-io ide0-hd0 "qemu-io ide0-hd0 "wqemu-io ide0-hd0 "wrqemu-io ide0-hd0 "wriqemu-io ide0-hd0 "writqemu-io ide0-hd0 "writeqemu-io ide0-hd0 "write qemu-io ide0-hd0 "write -qemu-io ide0-hd0 "write -Pqemu-io ide0-hd0 "write -P qemu-io ide0-hd0 "write -P 0qemu-io ide0-hd0 "write -P 0xqemu-io ide0-hd0 "write -P 0x2qemu-io ide0-hd0 "write -P 0x22qemu-io ide0-hd0 "write -P 0x22 qemu-io ide0-hd0 "write -P 0x22 0qemu-io ide0-hd0 "write -P 0x22 0 qemu-io ide0-hd0 "write -P 0x22 0 4qemu-io ide0-hd0 "write -P 0x22 0 4kqemu-io ide0-hd0 "write -P 0x22 0 4k" +(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k" wrote 4096/4096 bytes at offset 0 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) (qemu) qququiquit -Testing: -drive file.filename=TEST_DIR/t.qcow2,driver=qcow2,snapshot=on +Testing: -drive file.filename=TEST_DIR/t.qcow2,driver=qcow2,snapshot=on,if=none,id=drive0 QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io iqemu-io idqemu-io ideqemu-io ide0qemu-io ide0-qemu-io ide0-hqemu-io ide0-hdqemu-io ide0-hd0qemu-io ide0-hd0 qemu-io ide0-hd0 "qemu-io ide0-hd0 "wqemu-io ide0-hd0 "wrqemu-io ide0-hd0 "wriqemu-io ide0-hd0 "writqemu-io ide0-hd0 "writeqemu-io ide0-hd0 "write qemu-io ide0-hd0 "write -qemu-io ide0-hd0 "write -Pqemu-io ide0-hd0 "write -P qemu-io ide0-hd0 "write -P 0qemu-io ide0-hd0 "write -P 0xqemu-io ide0-hd0 "write -P 0x2qemu-io ide0-hd0 "write -P 0x22qemu-io ide0-hd0 "write -P 0x22 qemu-io ide0-hd0 "write -P 0x22 0qemu-io ide0-hd0 "write -P 0x22 0 qemu-io ide0-hd0 "write -P 0x22 0 4qemu-io ide0-hd0 "write -P 0x22 0 4kqemu-io ide0-hd0 "write -P 0x22 0 4k" +(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k" wrote 4096/4096 bytes at offset 0 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) (qemu) qququiquit -Testing: -drive file.filename=TEST_DIR/t.qcow2,driver=qcow2 -snapshot +Testing: -drive file.filename=TEST_DIR/t.qcow2,driver=qcow2,if=none,id=drive0 -snapshot QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io iqemu-io idqemu-io ideqemu-io ide0qemu-io ide0-qemu-io ide0-hqemu-io ide0-hdqemu-io ide0-hd0qemu-io ide0-hd0 qemu-io ide0-hd0 "qemu-io ide0-hd0 "wqemu-io ide0-hd0 "wrqemu-io ide0-hd0 "wriqemu-io ide0-hd0 "writqemu-io ide0-hd0 "writeqemu-io ide0-hd0 "write qemu-io ide0-hd0 "write -qemu-io ide0-hd0 "write -Pqemu-io ide0-hd0 "write -P qemu-io ide0-hd0 "write -P 0qemu-io ide0-hd0 "write -P 0xqemu-io ide0-hd0 "write -P 0x2qemu-io ide0-hd0 "write -P 0x22qemu-io ide0-hd0 "write -P 0x22 qemu-io ide0-hd0 "write -P 0x22 0qemu-io ide0-hd0 "write -P 0x22 0 qemu-io ide0-hd0 "write -P 0x22 0 4qemu-io ide0-hd0 "write -P 0x22 0 4kqemu-io ide0-hd0 "write -P 0x22 0 4k" +(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k" wrote 4096/4096 bytes at offset 0 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) (qemu) qququiquit -Testing: -drive file=file:TEST_DIR/t.qcow2 -snapshot +Testing: -drive file=file:TEST_DIR/t.qcow2,if=none,id=drive0 -snapshot QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io iqemu-io idqemu-io ideqemu-io ide0qemu-io ide0-qemu-io ide0-hqemu-io ide0-hdqemu-io ide0-hd0qemu-io ide0-hd0 qemu-io ide0-hd0 "qemu-io ide0-hd0 "wqemu-io ide0-hd0 "wrqemu-io ide0-hd0 "wriqemu-io ide0-hd0 "writqemu-io ide0-hd0 "writeqemu-io ide0-hd0 "write qemu-io ide0-hd0 "write -qemu-io ide0-hd0 "write -Pqemu-io ide0-hd0 "write -P qemu-io ide0-hd0 "write -P 0qemu-io ide0-hd0 "write -P 0xqemu-io ide0-hd0 "write -P 0x2qemu-io ide0-hd0 "write -P 0x22qemu-io ide0-hd0 "write -P 0x22 qemu-io ide0-hd0 "write -P 0x22 0qemu-io ide0-hd0 "write -P 0x22 0 qemu-io ide0-hd0 "write -P 0x22 0 4qemu-io ide0-hd0 "write -P 0x22 0 4kqemu-io ide0-hd0 "write -P 0x22 0 4k" +(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k" wrote 4096/4096 bytes at offset 0 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) (qemu) qququiquit -Testing: -drive file=file:TEST_DIR/t.qcow2,snapshot=on +Testing: -drive file=file:TEST_DIR/t.qcow2,snapshot=on,if=none,id=drive0 QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io iqemu-io idqemu-io ideqemu-io ide0qemu-io ide0-qemu-io ide0-hqemu-io ide0-hdqemu-io ide0-hd0qemu-io ide0-hd0 qemu-io ide0-hd0 "qemu-io ide0-hd0 "wqemu-io ide0-hd0 "wrqemu-io ide0-hd0 "wriqemu-io ide0-hd0 "writqemu-io ide0-hd0 "writeqemu-io ide0-hd0 "write qemu-io ide0-hd0 "write -qemu-io ide0-hd0 "write -Pqemu-io ide0-hd0 "write -P qemu-io ide0-hd0 "write -P 0qemu-io ide0-hd0 "write -P 0xqemu-io ide0-hd0 "write -P 0x2qemu-io ide0-hd0 "write -P 0x22qemu-io ide0-hd0 "write -P 0x22 qemu-io ide0-hd0 "write -P 0x22 0qemu-io ide0-hd0 "write -P 0x22 0 qemu-io ide0-hd0 "write -P 0x22 0 4qemu-io ide0-hd0 "write -P 0x22 0 4kqemu-io ide0-hd0 "write -P 0x22 0 4k" +(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k" wrote 4096/4096 bytes at offset 0 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) (qemu) qququiquit -Testing: -drive file=TEST_DIR/t.qcow2 -snapshot +Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=drive0 -snapshot QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io iqemu-io idqemu-io ideqemu-io ide0qemu-io ide0-qemu-io ide0-hqemu-io ide0-hdqemu-io ide0-hd0qemu-io ide0-hd0 qemu-io ide0-hd0 "qemu-io ide0-hd0 "wqemu-io ide0-hd0 "wrqemu-io ide0-hd0 "wriqemu-io ide0-hd0 "writqemu-io ide0-hd0 "writeqemu-io ide0-hd0 "write qemu-io ide0-hd0 "write -qemu-io ide0-hd0 "write -Pqemu-io ide0-hd0 "write -P qemu-io ide0-hd0 "write -P 0qemu-io ide0-hd0 "write -P 0xqemu-io ide0-hd0 "write -P 0x2qemu-io ide0-hd0 "write -P 0x22qemu-io ide0-hd0 "write -P 0x22 qemu-io ide0-hd0 "write -P 0x22 0qemu-io ide0-hd0 "write -P 0x22 0 qemu-io ide0-hd0 "write -P 0x22 0 4qemu-io ide0-hd0 "write -P 0x22 0 4kqemu-io ide0-hd0 "write -P 0x22 0 4k" +(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k" wrote 4096/4096 bytes at offset 0 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) (qemu) qququiquit -Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on +Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,if=none,id=drive0 QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io iqemu-io idqemu-io ideqemu-io ide0qemu-io ide0-qemu-io ide0-hqemu-io ide0-hdqemu-io ide0-hd0qemu-io ide0-hd0 qemu-io ide0-hd0 "qemu-io ide0-hd0 "wqemu-io ide0-hd0 "wrqemu-io ide0-hd0 "wriqemu-io ide0-hd0 "writqemu-io ide0-hd0 "writeqemu-io ide0-hd0 "write qemu-io ide0-hd0 "write -qemu-io ide0-hd0 "write -Pqemu-io ide0-hd0 "write -P qemu-io ide0-hd0 "write -P 0qemu-io ide0-hd0 "write -P 0xqemu-io ide0-hd0 "write -P 0x2qemu-io ide0-hd0 "write -P 0x22qemu-io ide0-hd0 "write -P 0x22 qemu-io ide0-hd0 "write -P 0x22 0qemu-io ide0-hd0 "write -P 0x22 0 qemu-io ide0-hd0 "write -P 0x22 0 4qemu-io ide0-hd0 "write -P 0x22 0 4kqemu-io ide0-hd0 "write -P 0x22 0 4k" +(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k" wrote 4096/4096 bytes at offset 0 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) (qemu) qququiquit read 4096/4096 bytes at offset 0 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -Testing: -drive file=TEST_DIR/t.qcow2,snapshot=off +Testing: -drive file=TEST_DIR/t.qcow2,snapshot=off,if=none,id=drive0 QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io iqemu-io idqemu-io ideqemu-io ide0qemu-io ide0-qemu-io ide0-hqemu-io ide0-hdqemu-io ide0-hd0qemu-io ide0-hd0 qemu-io ide0-hd0 "qemu-io ide0-hd0 "wqemu-io ide0-hd0 "wrqemu-io ide0-hd0 "wriqemu-io ide0-hd0 "writqemu-io ide0-hd0 "writeqemu-io ide0-hd0 "write qemu-io ide0-hd0 "write -qemu-io ide0-hd0 "write -Pqemu-io ide0-hd0 "write -P qemu-io ide0-hd0 "write -P 0qemu-io ide0-hd0 "write -P 0xqemu-io ide0-hd0 "write -P 0x2qemu-io ide0-hd0 "write -P 0x22qemu-io ide0-hd0 "write -P 0x22 qemu-io ide0-hd0 "write -P 0x22 0qemu-io ide0-hd0 "write -P 0x22 0 qemu-io ide0-hd0 "write -P 0x22 0 4qemu-io ide0-hd0 "write -P 0x22 0 4kqemu-io ide0-hd0 "write -P 0x22 0 4k" +(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k" wrote 4096/4096 bytes at offset 0 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) (qemu) qququiquit read 4096/4096 bytes at offset 0 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on +Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,if=none,id=drive0 QEMU X.Y.Z monitor - type 'help' for more information -(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io iqemu-io idqemu-io ideqemu-io ide0qemu-io ide0-qemu-io ide0-hqemu-io ide0-hdqemu-io ide0-hd0qemu-io ide0-hd0 qemu-io ide0-hd0 "qemu-io ide0-hd0 "wqemu-io ide0-hd0 "wrqemu-io ide0-hd0 "wriqemu-io ide0-hd0 "writqemu-io ide0-hd0 "writeqemu-io ide0-hd0 "write qemu-io ide0-hd0 "write -qemu-io ide0-hd0 "write -Pqemu-io ide0-hd0 "write -P qemu-io ide0-hd0 "write -P 0qemu-io ide0-hd0 "write -P 0xqemu-io ide0-hd0 "write -P 0x3qemu-io ide0-hd0 "write -P 0x33qemu-io ide0-hd0 "write -P 0x33 qemu-io ide0-hd0 "write -P 0x33 0qemu-io ide0-hd0 "write -P 0x33 0 qemu-io ide0-hd0 "write -P 0x33 0 4qemu-io ide0-hd0 "write -P 0x33 0 4kqemu-io ide0-hd0 "write -P 0x33 0 4k" +(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x3qemu-io drive0 "write -P 0x33qemu-io drive0 "write -P 0x33 qemu-io drive0 "write -P 0x33 0qemu-io drive0 "write -P 0x33 0 qemu-io drive0 "write -P 0x33 0 4qemu-io drive0 "write -P 0x33 0 4kqemu-io drive0 "write -P 0x33 0 4k" wrote 4096/4096 bytes at offset 0 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -(qemu) ccocomcommcommicommitcommit commit icommit idcommit idecommit ide0commit ide0-commit ide0-hcommit ide0-hdcommit ide0-hd0 +(qemu) ccocomcommcommicommitcommit commit dcommit drcommit dricommit drivcommit drivecommit drive0 (qemu) qququiquit read 4096/4096 bytes at offset 0 diff --git a/tests/qemu-iotests/051.pc.out b/tests/qemu-iotests/051.pc.out new file mode 100644 index 0000000..05c925a --- /dev/null +++ b/tests/qemu-iotests/051.pc.out @@ -0,0 +1,482 @@ +QA output created by 051 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base + +=== Unknown option === + +Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt= +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=: Block format 'qcow2' used by device 'ide0-hd0' doesn't support the option 'unknown_opt' + +Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=on +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=on: Block format 'qcow2' used by device 'ide0-hd0' doesn't support the option 'unknown_opt' + +Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=1234 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=1234: Block format 'qcow2' used by device 'ide0-hd0' doesn't support the option 'unknown_opt' + +Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=foo +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=foo: Block format 'qcow2' used by device 'ide0-hd0' doesn't support the option 'unknown_opt' + + +=== Unknown protocol option === + +Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt= +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=: Block protocol 'file' doesn't support the option 'unknown_opt' + +Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=on +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=on: Block protocol 'file' doesn't support the option 'unknown_opt' + +Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=1234 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=1234: Block protocol 'file' doesn't support the option 'unknown_opt' + +Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=foo +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=foo: Block protocol 'file' doesn't support the option 'unknown_opt' + + +=== Invalid format === + +Testing: -drive file=TEST_DIR/t.qcow2,format=foo +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=foo: Unknown driver 'foo' + +Testing: -drive file=TEST_DIR/t.qcow2,driver=foo +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=foo: Unknown driver 'foo' + +Testing: -drive file=TEST_DIR/t.qcow2,driver=raw,format=qcow2 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=raw,format=qcow2: Cannot specify both 'driver' and 'format' + +Testing: -drive file=TEST_DIR/t.qcow2,driver=qcow2,format=qcow2 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=qcow2,format=qcow2: Cannot specify both 'driver' and 'format' + + +=== Device without drive === + +Testing: -device virtio-scsi-pci -device scsi-hd +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) QEMU_PROG: -device scsi-hd: drive property not set + + +=== Overriding backing file === + +Testing: -drive file=TEST_DIR/t.qcow2,driver=qcow2,backing.file.filename=TEST_DIR/t.qcow2.orig -nodefaults +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo block +ide0-hd0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Cache mode: writeback + Backing file: TEST_DIR/t.qcow2.orig (chain depth: 1) +(qemu) qququiquit + +Testing: -drive file=TEST_DIR/t.qcow2,driver=raw,backing.file.filename=TEST_DIR/t.qcow2.orig +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=raw,backing.file.filename=TEST_DIR/t.qcow2.orig: Driver doesn't support backing files + +Testing: -drive file=TEST_DIR/t.qcow2,file.backing.driver=file,file.backing.filename=TEST_DIR/t.qcow2.orig +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,file.backing.driver=file,file.backing.filename=TEST_DIR/t.qcow2.orig: Driver doesn't support backing files + +Testing: -drive file=TEST_DIR/t.qcow2,file.backing.driver=qcow2,file.backing.file.filename=TEST_DIR/t.qcow2.orig +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,file.backing.driver=qcow2,file.backing.file.filename=TEST_DIR/t.qcow2.orig: Driver doesn't support backing files + + +=== Enable and disable lazy refcounting on the command line, plus some invalid values === + +Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit + +Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=off +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit + +Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts= +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=: Parameter 'lazy-refcounts' expects 'on' or 'off' + +Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=42 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=42: Parameter 'lazy-refcounts' expects 'on' or 'off' + +Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=foo +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=foo: Parameter 'lazy-refcounts' expects 'on' or 'off' + + +=== With version 2 images enabling lazy refcounts must fail === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 +Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on: Lazy refcounts require a qcow2 image with at least qemu 1.1 compatibility level + +Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=off +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit + + +=== No medium === + +Testing: -drive if=floppy +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit + +Testing: -drive if=ide,media=cdrom +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit + +Testing: -drive if=scsi,media=cdrom +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit + +Testing: -drive if=ide +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) QEMU_PROG: Device needs media, but drive is empty +QEMU_PROG: Initialization of device ide-hd failed: Device initialization failed. + +Testing: -drive if=virtio +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) QEMU_PROG: -drive if=virtio: Device needs media, but drive is empty + +Testing: -drive if=scsi +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) QEMU_PROG: Initialization of device lsi53c895a failed: Device needs media, but drive is empty + +Testing: -drive if=none,id=disk -device ide-cd,drive=disk +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit + +Testing: -drive if=none,id=disk -device lsi53c895a -device scsi-cd,drive=disk +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit + +Testing: -drive if=none,id=disk -device ide-drive,drive=disk +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) QEMU_PROG: -device ide-drive,drive=disk: Device needs media, but drive is empty +QEMU_PROG: -device ide-drive,drive=disk: Device initialization failed. + +Testing: -drive if=none,id=disk -device ide-hd,drive=disk +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) QEMU_PROG: -device ide-hd,drive=disk: Device needs media, but drive is empty +QEMU_PROG: -device ide-hd,drive=disk: Device initialization failed. + +Testing: -drive if=none,id=disk -device lsi53c895a -device scsi-disk,drive=disk +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) QEMU_PROG: -device scsi-disk,drive=disk: Device needs media, but drive is empty + +Testing: -drive if=none,id=disk -device lsi53c895a -device scsi-hd,drive=disk +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) QEMU_PROG: -device scsi-hd,drive=disk: Device needs media, but drive is empty + + +=== Read-only === + +Testing: -drive file=TEST_DIR/t.qcow2,if=floppy,readonly=on +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit + +Testing: -drive file=TEST_DIR/t.qcow2,if=ide,media=cdrom,readonly=on +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit + +Testing: -drive file=TEST_DIR/t.qcow2,if=scsi,media=cdrom,readonly=on +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit + +Testing: -drive file=TEST_DIR/t.qcow2,if=ide,readonly=on +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) QEMU_PROG: Can't use a read-only drive +QEMU_PROG: Initialization of device ide-hd failed: Device initialization failed. + +Testing: -drive file=TEST_DIR/t.qcow2,if=virtio,readonly=on +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit + +Testing: -drive file=TEST_DIR/t.qcow2,if=scsi,readonly=on +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit + +Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-cd,drive=disk +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit + +Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-cd,drive=disk +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit + +Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-drive,drive=disk +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) QEMU_PROG: -device ide-drive,drive=disk: Can't use a read-only drive +QEMU_PROG: -device ide-drive,drive=disk: Device initialization failed. + +Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-hd,drive=disk +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) QEMU_PROG: -device ide-hd,drive=disk: Can't use a read-only drive +QEMU_PROG: -device ide-hd,drive=disk: Device initialization failed. + +Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-disk,drive=disk +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit + +Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-hd,drive=disk +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit + + +=== Cache modes === + +Testing: -drive driver=null-co,cache=none +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit + +Testing: -drive driver=null-co,cache=directsync +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit + +Testing: -drive driver=null-co,cache=writeback +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit + +Testing: -drive driver=null-co,cache=writethrough +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit + +Testing: -drive driver=null-co,cache=unsafe +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit + +Testing: -drive driver=null-co,cache=invalid_value +QEMU_PROG: -drive driver=null-co,cache=invalid_value: invalid cache option + +Testing: -drive file=TEST_DIR/t.qcow2,cache=writeback,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.cache.writeback=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file -nodefaults +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo block +ide0-hd0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Cache mode: writeback + Backing file: TEST_DIR/t.qcow2.base (chain depth: 1) +(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block finfo block fiinfo block filinfo block file + +file: TEST_DIR/t.qcow2 (file) + Cache mode: writeback +(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block binfo block bainfo block bacinfo block backinfo block backiinfo block backininfo block backing +backing: TEST_DIR/t.qcow2.base (qcow2, read-only) + Cache mode: writeback, ignore flushes +(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block binfo block bainfo block bacinfo block backinfo block backiinfo block backininfo block backinginfo block backing-info block backing-finfo block backing-fiinfo block backing-filinfo block backing-file + +backing-file: TEST_DIR/t.qcow2.base (file, read-only) + Cache mode: writeback, ignore flushes +(qemu) qququiquit + +Testing: -drive file=TEST_DIR/t.qcow2,cache=writethrough,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.cache.writeback=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file -nodefaults +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo block +ide0-hd0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Cache mode: writethrough + Backing file: TEST_DIR/t.qcow2.base (chain depth: 1) +(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block finfo block fiinfo block filinfo block file + +file: TEST_DIR/t.qcow2 (file) + Cache mode: writeback +(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block binfo block bainfo block bacinfo block backinfo block backiinfo block backininfo block backing +backing: TEST_DIR/t.qcow2.base (qcow2, read-only) + Cache mode: writeback, ignore flushes +(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block binfo block bainfo block bacinfo block backinfo block backiinfo block backininfo block backinginfo block backing-info block backing-finfo block backing-fiinfo block backing-filinfo block backing-file + +backing-file: TEST_DIR/t.qcow2.base (file, read-only) + Cache mode: writeback, ignore flushes +(qemu) qququiquit + +Testing: -drive file=TEST_DIR/t.qcow2,cache=unsafe,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.cache.writeback=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file -nodefaults +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo block +ide0-hd0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Cache mode: writeback, ignore flushes + Backing file: TEST_DIR/t.qcow2.base (chain depth: 1) +(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block finfo block fiinfo block filinfo block file + +file: TEST_DIR/t.qcow2 (file) + Cache mode: writeback, ignore flushes +(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block binfo block bainfo block bacinfo block backinfo block backiinfo block backininfo block backing +backing: TEST_DIR/t.qcow2.base (qcow2, read-only) + Cache mode: writeback, ignore flushes +(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block binfo block bainfo block bacinfo block backinfo block backiinfo block backininfo block backinginfo block backing-info block backing-finfo block backing-fiinfo block backing-filinfo block backing-file + +backing-file: TEST_DIR/t.qcow2.base (file, read-only) + Cache mode: writeback, ignore flushes +(qemu) qququiquit + +Testing: -drive file=TEST_DIR/t.qcow2,cache=invalid_value,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.cache.writeback=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file -nodefaults +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,cache=invalid_value,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.cache.writeback=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file: invalid cache option + + +=== Specifying the protocol layer === + +Testing: -drive file=TEST_DIR/t.qcow2,file.driver=file +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit + + +=== Leaving out required options === + +Testing: -drive driver=file +QEMU_PROG: -drive driver=file: The 'file' block driver requires a file name + +Testing: -drive driver=nbd +QEMU_PROG: -drive driver=nbd: one of path and host must be specified. + +Testing: -drive driver=raw +QEMU_PROG: -drive driver=raw: Can't use 'raw' as a block driver for the protocol level + +Testing: -drive file.driver=file +QEMU_PROG: -drive file.driver=file: The 'file' block driver requires a file name + +Testing: -drive file.driver=nbd +QEMU_PROG: -drive file.driver=nbd: one of path and host must be specified. + +Testing: -drive file.driver=raw +QEMU_PROG: -drive file.driver=raw: Can't use 'raw' as a block driver for the protocol level + +Testing: -drive foo=bar +QEMU_PROG: -drive foo=bar: Must specify either driver or file + + +=== Specifying both an option and its legacy alias === + +Testing: -drive file=TEST_DIR/t.qcow2,iops=1234,throttling.iops-total=5678 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,iops=1234,throttling.iops-total=5678: 'throttling.iops-total' and its alias 'iops' can't be used at the same time + +Testing: -drive file=TEST_DIR/t.qcow2,iops_rd=1234,throttling.iops-read=5678 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,iops_rd=1234,throttling.iops-read=5678: 'throttling.iops-read' and its alias 'iops_rd' can't be used at the same time + +Testing: -drive file=TEST_DIR/t.qcow2,iops_wr=1234,throttling.iops-write=5678 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,iops_wr=1234,throttling.iops-write=5678: 'throttling.iops-write' and its alias 'iops_wr' can't be used at the same time + +Testing: -drive file=TEST_DIR/t.qcow2,bps=1234,throttling.bps-total=5678 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,bps=1234,throttling.bps-total=5678: 'throttling.bps-total' and its alias 'bps' can't be used at the same time + +Testing: -drive file=TEST_DIR/t.qcow2,bps_rd=1234,throttling.bps-read=5678 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,bps_rd=1234,throttling.bps-read=5678: 'throttling.bps-read' and its alias 'bps_rd' can't be used at the same time + +Testing: -drive file=TEST_DIR/t.qcow2,bps_wr=1234,throttling.bps-write=5678 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,bps_wr=1234,throttling.bps-write=5678: 'throttling.bps-write' and its alias 'bps_wr' can't be used at the same time + +Testing: -drive file=TEST_DIR/t.qcow2,iops_max=1234,throttling.iops-total-max=5678 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,iops_max=1234,throttling.iops-total-max=5678: 'throttling.iops-total-max' and its alias 'iops_max' can't be used at the same time + +Testing: -drive file=TEST_DIR/t.qcow2,iops_rd_max=1234,throttling.iops-read-max=5678 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,iops_rd_max=1234,throttling.iops-read-max=5678: 'throttling.iops-read-max' and its alias 'iops_rd_max' can't be used at the same time + +Testing: -drive file=TEST_DIR/t.qcow2,iops_wr_max=1234,throttling.iops-write-max=5678 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,iops_wr_max=1234,throttling.iops-write-max=5678: 'throttling.iops-write-max' and its alias 'iops_wr_max' can't be used at the same time + +Testing: -drive file=TEST_DIR/t.qcow2,bps_max=1234,throttling.bps-total-max=5678 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,bps_max=1234,throttling.bps-total-max=5678: 'throttling.bps-total-max' and its alias 'bps_max' can't be used at the same time + +Testing: -drive file=TEST_DIR/t.qcow2,bps_rd_max=1234,throttling.bps-read-max=5678 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,bps_rd_max=1234,throttling.bps-read-max=5678: 'throttling.bps-read-max' and its alias 'bps_rd_max' can't be used at the same time + +Testing: -drive file=TEST_DIR/t.qcow2,bps_wr_max=1234,throttling.bps-write-max=5678 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,bps_wr_max=1234,throttling.bps-write-max=5678: 'throttling.bps-write-max' and its alias 'bps_wr_max' can't be used at the same time + +Testing: -drive file=TEST_DIR/t.qcow2,iops_size=1234,throttling.iops-size=5678 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,iops_size=1234,throttling.iops-size=5678: 'throttling.iops-size' and its alias 'iops_size' can't be used at the same time + +Testing: -drive file=TEST_DIR/t.qcow2,readonly=on,read-only=off +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,readonly=on,read-only=off: 'read-only' and its alias 'readonly' can't be used at the same time + + +=== Parsing protocol from file name === + +Testing: -hda foo:bar +QEMU_PROG: -hda foo:bar: Unknown protocol 'foo' + +Testing: -drive file=foo:bar +QEMU_PROG: -drive file=foo:bar: Unknown protocol 'foo' + +Testing: -drive file.filename=foo:bar +QEMU_PROG: -drive file.filename=foo:bar: Could not open 'foo:bar': No such file or directory + +Testing: -hda file:TEST_DIR/t.qcow2 +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit + +Testing: -drive file=file:TEST_DIR/t.qcow2 +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qququiquit + +Testing: -drive file.filename=file:TEST_DIR/t.qcow2 +QEMU_PROG: -drive file.filename=file:TEST_DIR/t.qcow2: Could not open 'file:TEST_DIR/t.qcow2': No such file or directory + + +=== Snapshot mode === + +wrote 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=drive0 -snapshot +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k" +wrote 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +(qemu) qququiquit + +Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,if=none,id=drive0 +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k" +wrote 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +(qemu) qququiquit + +Testing: -drive file.filename=TEST_DIR/t.qcow2,driver=qcow2,snapshot=on,if=none,id=drive0 +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k" +wrote 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +(qemu) qququiquit + +Testing: -drive file.filename=TEST_DIR/t.qcow2,driver=qcow2,if=none,id=drive0 -snapshot +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k" +wrote 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +(qemu) qququiquit + +Testing: -drive file=file:TEST_DIR/t.qcow2,if=none,id=drive0 -snapshot +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k" +wrote 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +(qemu) qququiquit + +Testing: -drive file=file:TEST_DIR/t.qcow2,snapshot=on,if=none,id=drive0 +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k" +wrote 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +(qemu) qququiquit + +Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=drive0 -snapshot +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k" +wrote 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +(qemu) qququiquit + +Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,if=none,id=drive0 +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k" +wrote 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +(qemu) qququiquit + +read 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +Testing: -drive file=TEST_DIR/t.qcow2,snapshot=off,if=none,id=drive0 +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k" +wrote 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +(qemu) qququiquit + +read 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,if=none,id=drive0 +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x3qemu-io drive0 "write -P 0x33qemu-io drive0 "write -P 0x33 qemu-io drive0 "write -P 0x33 0qemu-io drive0 "write -P 0x33 0 qemu-io drive0 "write -P 0x33 0 4qemu-io drive0 "write -P 0x33 0 4kqemu-io drive0 "write -P 0x33 0 4k" +wrote 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +(qemu) ccocomcommcommicommitcommit commit dcommit drcommit dricommit drivcommit drivecommit drive0 +(qemu) qququiquit + +read 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +*** done -- cgit v1.1 From a41aa71c15fc8e8289acebd3330257bee0b8e11c Mon Sep 17 00:00:00 2001 From: Bo Tu Date: Thu, 3 Dec 2015 18:01:31 +0800 Subject: qemu-iotests: s390x: fix test 068 Now, s390-virtio-ccw is default machine and s390-ccw.img is default boot loader. If the s390-virtio-ccw machine finds no device to load from and errors out, then emits a panic and exits the vm. This breaks test cases 068 for s390x. Adding the parameter of "-no-shutdown" for s390-ccw-virtio will pause VM before shutdown. Acked-by: Max Reitz Reviewed-by: Sascha Silbe Signed-off-by: Bo Tu Message-id: 1449136891-26850-4-git-send-email-tubo@linux.vnet.ibm.com Signed-off-by: Max Reitz --- tests/qemu-iotests/068 | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/tests/qemu-iotests/068 b/tests/qemu-iotests/068 index b72e555..58d1d80 100755 --- a/tests/qemu-iotests/068 +++ b/tests/qemu-iotests/068 @@ -50,13 +50,23 @@ echo echo "=== Saving and reloading a VM state to/from a qcow2 image ===" echo _make_test_img $IMG_SIZE + +case "$QEMU_DEFAULT_MACHINE" in + s390-ccw-virtio) + platform_parm="-no-shutdown -machine accel=kvm" + ;; + *) + platform_parm="" + ;; +esac + # Give qemu some time to boot before saving the VM state bash -c 'sleep 1; echo -e "savevm 0\nquit"' |\ - $QEMU -nographic -monitor stdio -serial none -hda "$TEST_IMG" |\ + $QEMU $platform_parm -nographic -monitor stdio -serial none -hda "$TEST_IMG" |\ _filter_qemu # Now try to continue from that VM state (this should just work) echo quit |\ - $QEMU -nographic -monitor stdio -serial none -hda "$TEST_IMG" -loadvm 0 |\ + $QEMU $platform_parm -nographic -monitor stdio -serial none -hda "$TEST_IMG" -loadvm 0 |\ _filter_qemu # success, all done -- cgit v1.1 From 548e1ff37982424f5c605c67471b691ab5c8d1b1 Mon Sep 17 00:00:00 2001 From: John Snow Date: Mon, 14 Dec 2015 14:55:12 -0500 Subject: block/qapi: do not redundantly print "actual path" If it happens to match the backing path, that was the actual path. Signed-off-by: John Snow Reviewed-by: Max Reitz Message-id: 1450122916-4706-2-git-send-email-jsnow@redhat.com Signed-off-by: Max Reitz --- block/qapi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/block/qapi.c b/block/qapi.c index c0e877e..563dd31 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -676,7 +676,9 @@ void bdrv_image_info_dump(fprintf_function func_fprintf, void *f, if (info->has_backing_filename) { func_fprintf(f, "backing file: %s", info->backing_filename); - if (info->has_full_backing_filename) { + if (info->has_full_backing_filename && + (strcmp(info->backing_filename, + info->full_backing_filename) != 0)) { func_fprintf(f, " (actual path: %s)", info->full_backing_filename); } func_fprintf(f, "\n"); -- cgit v1.1 From 12dcb1c0183bba4499d9c8bd37fa7112549cafd7 Mon Sep 17 00:00:00 2001 From: John Snow Date: Mon, 14 Dec 2015 14:55:13 -0500 Subject: block/qapi: always report full_backing_filename Always report full_backing_filename, even if it's the same as backing_filename. In the next patch, full_backing_filename may be omitted if it cannot be generated instead of allowing e.g. drive_query to abort if it runs into this scenario. The presence or absence of the "full" field becomes useful information. Signed-off-by: John Snow Reviewed-by: Max Reitz Message-id: 1450122916-4706-3-git-send-email-jsnow@redhat.com Signed-off-by: Max Reitz --- block/qapi.c | 7 ++++--- tests/qemu-iotests/043.out | 2 ++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/block/qapi.c b/block/qapi.c index 563dd31..3d8e434 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -251,9 +251,10 @@ void bdrv_query_image_info(BlockDriverState *bs, return; } - if (strcmp(backing_filename, backing_filename2) != 0) { - info->full_backing_filename = - g_strdup(backing_filename2); + /* Always report the full_backing_filename if present, even if it's the + * same as backing_filename. That they are same is useful info. */ + if (backing_filename2) { + info->full_backing_filename = g_strdup(backing_filename2); info->has_full_backing_filename = true; } diff --git a/tests/qemu-iotests/043.out b/tests/qemu-iotests/043.out index 33f8cc3..b37d2a3 100644 --- a/tests/qemu-iotests/043.out +++ b/tests/qemu-iotests/043.out @@ -44,6 +44,7 @@ cluster_size: 65536 "filename": "TEST_DIR/t.IMGFMT", "cluster-size": 65536, "format": "IMGFMT", + "full-backing-filename": "TEST_DIR/t.IMGFMT.2.base", "backing-filename": "TEST_DIR/t.IMGFMT.2.base", "dirty-flag": false }, @@ -52,6 +53,7 @@ cluster_size: 65536 "filename": "TEST_DIR/t.IMGFMT.2.base", "cluster-size": 65536, "format": "IMGFMT", + "full-backing-filename": "TEST_DIR/t.IMGFMT.1.base", "backing-filename": "TEST_DIR/t.IMGFMT.1.base", "dirty-flag": false }, -- cgit v1.1 From 5c9d9ca59735d245599884cf1db744c2b403367c Mon Sep 17 00:00:00 2001 From: John Snow Date: Mon, 14 Dec 2015 14:55:14 -0500 Subject: block/qapi: explicitly warn if !has_full_backing_filename Disambiguate "Backing filename and full backing filename are equivalent" from "full backing filename could not be determined." Signed-off-by: John Snow Message-id: 1450122916-4706-4-git-send-email-jsnow@redhat.com Reviewed-by: Max Reitz Signed-off-by: Max Reitz --- block/qapi.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/block/qapi.c b/block/qapi.c index 3d8e434..5587c64 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -677,9 +677,10 @@ void bdrv_image_info_dump(fprintf_function func_fprintf, void *f, if (info->has_backing_filename) { func_fprintf(f, "backing file: %s", info->backing_filename); - if (info->has_full_backing_filename && - (strcmp(info->backing_filename, - info->full_backing_filename) != 0)) { + if (!info->has_full_backing_filename) { + func_fprintf(f, " (cannot determine actual path)"); + } else if (strcmp(info->backing_filename, + info->full_backing_filename) != 0) { func_fprintf(f, " (actual path: %s)", info->full_backing_filename); } func_fprintf(f, "\n"); -- cgit v1.1 From 92d617abc53180cbfa88482382e8f0c13853cc1d Mon Sep 17 00:00:00 2001 From: John Snow Date: Mon, 14 Dec 2015 14:55:15 -0500 Subject: qemu-img: abort when full_backing_filename not present ...But only if we have the backing_filename. It means something Scary happened and we can't really be quite exactly sure if we can trust the backing_filename. Signed-off-by: John Snow Reviewed-by: Max Reitz Message-id: 1450122916-4706-5-git-send-email-jsnow@redhat.com Signed-off-by: Max Reitz --- qemu-img.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/qemu-img.c b/qemu-img.c index b6b4c9e..3d48b4f 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -2040,7 +2040,10 @@ static ImageInfoList *collect_image_info_list(const char *filename, if (info->has_full_backing_filename) { filename = info->full_backing_filename; } else if (info->has_backing_filename) { - filename = info->backing_filename; + error_report("Could not determine absolute backing filename," + " but backing filename '%s' present", + info->backing_filename); + goto err; } if (info->has_backing_filename_format) { fmt = info->backing_filename_format; -- cgit v1.1 From a5002d53029df4d7ebaf87c821b3dc07b65e5e52 Mon Sep 17 00:00:00 2001 From: John Snow Date: Mon, 14 Dec 2015 14:55:16 -0500 Subject: block/qapi: allow best-effort query For more complex BDS trees that can be created under normal circumstances, we lose the ability to issue query commands because of our inability to re-construct the absolute filename. Instead, omit this field when it is a problem and present as much information as we can. This will change the expected output in iotest 110, where we will now see a json filename and the lack of an absolute filename instead of an error. Signed-off-by: John Snow Message-id: 1450122916-4706-6-git-send-email-jsnow@redhat.com Reviewed-by: Max Reitz Signed-off-by: Max Reitz --- block/qapi.c | 7 ++++--- tests/qemu-iotests/110.out | 5 ++++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/block/qapi.c b/block/qapi.c index 5587c64..fecac25 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -245,10 +245,11 @@ void bdrv_query_image_info(BlockDriverState *bs, info->has_backing_filename = true; bdrv_get_full_backing_filename(bs, backing_filename2, PATH_MAX, &err); if (err) { - error_propagate(errp, err); - qapi_free_ImageInfo(info); + /* Can't reconstruct the full backing filename, so we must omit + * this field and apply a Best Effort to this query. */ g_free(backing_filename2); - return; + backing_filename2 = NULL; + error_free(err); } /* Always report the full_backing_filename if present, even if it's the diff --git a/tests/qemu-iotests/110.out b/tests/qemu-iotests/110.out index 0270980..b3584ff 100644 --- a/tests/qemu-iotests/110.out +++ b/tests/qemu-iotests/110.out @@ -11,7 +11,10 @@ backing file: t.IMGFMT.base (actual path: TEST_DIR/t.IMGFMT.base) === Non-reconstructable filename === -qemu-img: Cannot use relative backing file names for 'json:{"driver": "IMGFMT", "file": {"set-state.0.event": "read_aio", "image": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "driver": "blkdebug", "set-state.0.new_state": 42}}' +image: json:{"driver": "IMGFMT", "file": {"set-state.0.event": "read_aio", "image": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "driver": "blkdebug", "set-state.0.new_state": 42}} +file format: IMGFMT +virtual size: 64M (67108864 bytes) +backing file: t.IMGFMT.base (cannot determine actual path) === Backing name is always relative to the backed image === -- cgit v1.1