From 8c0dcbc4ad2bf4f9f3b27c637b357e87cad70ec7 Mon Sep 17 00:00:00 2001 From: Daniel P. Berrange Date: Mon, 13 Jun 2016 12:30:09 +0100 Subject: block: drop support for using qcow[2] encryption with system emulators Back in the 2.3.0 release we declared qcow[2] encryption as deprecated, warning people that it would be removed in a future release. commit a1f688f4152e65260b94f37543521ceff8bfebe4 Author: Markus Armbruster Date: Fri Mar 13 21:09:40 2015 +0100 block: Deprecate QCOW/QCOW2 encryption The code still exists today, but by a (happy?) accident we entirely broke the ability to use qcow[2] encryption in the system emulators in the 2.4.0 release due to commit 8336aafae1451d54c81dd2b187b45f7c45d2428e Author: Daniel P. Berrange Date: Tue May 12 17:09:18 2015 +0100 qcow2/qcow: protect against uninitialized encryption key This commit was designed to prevent future coding bugs which might cause QEMU to read/write data on an encrypted block device in plain text mode before a decryption key is set. It turns out this preventative measure was a little too good, because we already had a long standing bug where QEMU read encrypted data in plain text mode during system emulator startup, in order to guess disk geometry: Thread 10 (Thread 0x7fffd3fff700 (LWP 30373)): #0 0x00007fffe90b1a28 in raise () at /lib64/libc.so.6 #1 0x00007fffe90b362a in abort () at /lib64/libc.so.6 #2 0x00007fffe90aa227 in __assert_fail_base () at /lib64/libc.so.6 #3 0x00007fffe90aa2d2 in () at /lib64/libc.so.6 #4 0x000055555587ae19 in qcow2_co_readv (bs=0x5555562accb0, sector_num=0, remaining_sectors=1, qiov=0x7fffffffd260) at block/qcow2.c:1229 #5 0x000055555589b60d in bdrv_aligned_preadv (bs=bs@entry=0x5555562accb0, req=req@entry=0x7fffd3ffea50, offset=offset@entry=0, bytes=bytes@entry=512, align=align@entry=512, qiov=qiov@entry=0x7fffffffd260, flags=0) at block/io.c:908 #6 0x000055555589b8bc in bdrv_co_do_preadv (bs=0x5555562accb0, offset=0, bytes=512, qiov=0x7fffffffd260, flags=) at block/io.c:999 #7 0x000055555589c375 in bdrv_rw_co_entry (opaque=0x7fffffffd210) at block/io.c:544 #8 0x000055555586933b in coroutine_thread (opaque=0x555557876310) at coroutine-gthread.c:134 #9 0x00007ffff64e1835 in g_thread_proxy (data=0x5555562b5590) at gthread.c:778 #10 0x00007ffff6bb760a in start_thread () at /lib64/libpthread.so.0 #11 0x00007fffe917f59d in clone () at /lib64/libc.so.6 Thread 1 (Thread 0x7ffff7ecab40 (LWP 30343)): #0 0x00007fffe91797a9 in syscall () at /lib64/libc.so.6 #1 0x00007ffff64ff87f in g_cond_wait (cond=cond@entry=0x555555e085f0 , mutex=mutex@entry=0x555555e08600 ) at gthread-posix.c:1397 #2 0x00005555558692c3 in qemu_coroutine_switch (co=) at coroutine-gthread.c:117 #3 0x00005555558692c3 in qemu_coroutine_switch (from_=0x5555562b5e30, to_=to_@entry=0x555557876310, action=action@entry=COROUTINE_ENTER) at coroutine-gthread.c:175 #4 0x0000555555868a90 in qemu_coroutine_enter (co=0x555557876310, opaque=0x0) at qemu-coroutine.c:116 #5 0x0000555555859b84 in thread_pool_completion_bh (opaque=0x7fffd40010e0) at thread-pool.c:187 #6 0x0000555555859514 in aio_bh_poll (ctx=ctx@entry=0x5555562953b0) at async.c:85 #7 0x0000555555864d10 in aio_dispatch (ctx=ctx@entry=0x5555562953b0) at aio-posix.c:135 #8 0x0000555555864f75 in aio_poll (ctx=ctx@entry=0x5555562953b0, blocking=blocking@entry=true) at aio-posix.c:291 #9 0x000055555589c40d in bdrv_prwv_co (bs=bs@entry=0x5555562accb0, offset=offset@entry=0, qiov=qiov@entry=0x7fffffffd260, is_write=is_write@entry=false, flags=flags@entry=(unknown: 0)) at block/io.c:591 #10 0x000055555589c503 in bdrv_rw_co (bs=bs@entry=0x5555562accb0, sector_num=sector_num@entry=0, buf=buf@entry=0x7fffffffd2e0 "\321,", nb_sectors=nb_sectors@entry=21845, is_write=is_write@entry=false, flags=flags@entry=(unknown: 0)) at block/io.c:614 #11 0x000055555589c562 in bdrv_read_unthrottled (nb_sectors=21845, buf=0x7fffffffd2e0 "\321,", sector_num=0, bs=0x5555562accb0) at block/io.c:622 #12 0x000055555589c562 in bdrv_read_unthrottled (bs=0x5555562accb0, sector_num=sector_num@entry=0, buf=buf@entry=0x7fffffffd2e0 "\321,", nb_sectors=nb_sectors@entry=21845) at block/io.c:634 nb_sectors@entry=1) at block/block-backend.c:504 #14 0x0000555555752e9f in guess_disk_lchs (blk=blk@entry=0x5555562a5290, pcylinders=pcylinders@entry=0x7fffffffd52c, pheads=pheads@entry=0x7fffffffd530, psectors=psectors@entry=0x7fffffffd534) at hw/block/hd-geometry.c:68 #15 0x0000555555752ff7 in hd_geometry_guess (blk=0x5555562a5290, pcyls=pcyls@entry=0x555557875d1c, pheads=pheads@entry=0x555557875d20, psecs=psecs@entry=0x555557875d24, ptrans=ptrans@entry=0x555557875d28) at hw/block/hd-geometry.c:133 #16 0x0000555555752b87 in blkconf_geometry (conf=conf@entry=0x555557875d00, ptrans=ptrans@entry=0x555557875d28, cyls_max=cyls_max@entry=65536, heads_max=heads_max@entry=16, secs_max=secs_max@entry=255, errp=errp@entry=0x7fffffffd5e0) at hw/block/block.c:71 #17 0x0000555555799bc4 in ide_dev_initfn (dev=0x555557875c80, kind=IDE_HD) at hw/ide/qdev.c:174 #18 0x0000555555768394 in device_realize (dev=0x555557875c80, errp=0x7fffffffd640) at hw/core/qdev.c:247 #19 0x0000555555769a81 in device_set_realized (obj=0x555557875c80, value=, errp=0x7fffffffd730) at hw/core/qdev.c:1058 #20 0x00005555558240ce in property_set_bool (obj=0x555557875c80, v=, opaque=0x555557875de0, name=, errp=0x7fffffffd730) at qom/object.c:1514 #21 0x0000555555826c87 in object_property_set_qobject (obj=obj@entry=0x555557875c80, value=value@entry=0x55555784bcb0, name=name@entry=0x55555591cb3d "realized", errp=errp@entry=0x7fffffffd730) at qom/qom-qobject.c:24 #22 0x0000555555825760 in object_property_set_bool (obj=obj@entry=0x555557875c80, value=value@entry=true, name=name@entry=0x55555591cb3d "realized", errp=errp@entry=0x7fffffffd730) at qom/object.c:905 #23 0x000055555576897b in qdev_init_nofail (dev=dev@entry=0x555557875c80) at hw/core/qdev.c:380 #24 0x0000555555799ead in ide_create_drive (bus=bus@entry=0x555557629630, unit=unit@entry=0, drive=0x5555562b77e0) at hw/ide/qdev.c:122 #25 0x000055555579a746 in pci_ide_create_devs (dev=dev@entry=0x555557628db0, hd_table=hd_table@entry=0x7fffffffd830) at hw/ide/pci.c:440 #26 0x000055555579b165 in pci_piix3_ide_init (bus=, hd_table=0x7fffffffd830, devfn=) at hw/ide/piix.c:218 #27 0x000055555568ca55 in pc_init1 (machine=0x5555562960a0, pci_enabled=1, kvmclock_enabled=) at /home/berrange/src/virt/qemu/hw/i386/pc_piix.c:256 #28 0x0000555555603ab2 in main (argc=, argv=, envp=) at vl.c:4249 So the safety net is correctly preventing QEMU reading cipher text as if it were plain text, during startup and aborting QEMU to avoid bad usage of this data. For added fun this bug only happens if the encrypted qcow2 file happens to have data written to the first cluster, otherwise the cluster won't be allocated and so qcow2 would not try the decryption routines at all, just return all 0's. That no one even noticed, let alone reported, this bug that has shipped in 2.4.0, 2.5.0 and 2.6.0 shows that the number of actual users of encrypted qcow2 is approximately zero. So rather than fix the crash, and backport it to stable releases, just go ahead with what we have warned users about and disable any use of qcow2 encryption in the system emulators. qemu-img/qemu-io/qemu-nbd are still able to access qcow2 encrypted images for the sake of data conversion. In the future, qcow2 will gain support for the alternative luks format, but when this happens it'll be using the '-object secret' infrastructure for getting keys, which avoids this problematic scenario entirely. Signed-off-by: Daniel P. Berrange Reviewed-by: Eric Blake Signed-off-by: Kevin Wolf --- tests/qemu-iotests/087.out | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'tests') diff --git a/tests/qemu-iotests/087.out b/tests/qemu-iotests/087.out index 055c553cdb..a95c4b0be8 100644 --- a/tests/qemu-iotests/087.out +++ b/tests/qemu-iotests/087.out @@ -42,22 +42,14 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on Testing: -S QMP_VERSION {"return": {}} -IMGFMT built-in AES encryption is deprecated -Support for it will be removed in a future release. -You can use 'qemu-img convert' to switch to an -unencrypted IMGFMT image, or a LUKS raw image. -{"error": {"class": "GenericError", "desc": "blockdev-add doesn't support encrypted devices"}} +{"error": {"class": "GenericError", "desc": "Use of AES-CBC encrypted IMGFMT images is no longer supported in system emulators"}} {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"} Testing: QMP_VERSION {"return": {}} -IMGFMT built-in AES encryption is deprecated -Support for it will be removed in a future release. -You can use 'qemu-img convert' to switch to an -unencrypted IMGFMT image, or a LUKS raw image. -{"error": {"class": "GenericError", "desc": "Guest must be stopped for opening of encrypted image"}} +{"error": {"class": "GenericError", "desc": "Use of AES-CBC encrypted IMGFMT images is no longer supported in system emulators"}} {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"} -- cgit v1.2.3-55-g7522 From 48bea965724fafd51b395f4c0b5a0c173de46c2b Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 16 Jun 2016 09:53:53 +0200 Subject: doc: Fix mailing list address in tests/qemu-iotests/README The address of the mailing list is qemu-devel@nongnu.org instead of qemu-devel@savannah.nongnu.org. And while we're at it, also mention the qemu-block mailing list here. Signed-off-by: Thomas Huth Signed-off-by: Kevin Wolf --- tests/qemu-iotests/README | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/qemu-iotests/README b/tests/qemu-iotests/README index 4ccfdd1cc0..6079b401ae 100644 --- a/tests/qemu-iotests/README +++ b/tests/qemu-iotests/README @@ -17,4 +17,5 @@ additional options to test further image formats or I/O methods. * Feedback and patches Please send improvements to the test suite, general feedback or just -reports of failing tests cases to qemu-devel@savannah.nongnu.org. +reports of failing tests cases to qemu-devel@nongnu.org with a CC: +to qemu-block@nongnu.org. -- cgit v1.2.3-55-g7522 From 6ea66b590cda71bddc3112b40a5c13378c1a3445 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Fri, 3 Jun 2016 17:07:52 +0800 Subject: iotests: 095: Clean up QEMU before showing image info Signed-off-by: Fam Zheng Message-id: 1464944872-24484-1-git-send-email-famz@redhat.com Signed-off-by: Max Reitz --- tests/qemu-iotests/095 | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tests') diff --git a/tests/qemu-iotests/095 b/tests/qemu-iotests/095 index dad04b9ac9..030adb22e1 100755 --- a/tests/qemu-iotests/095 +++ b/tests/qemu-iotests/095 @@ -74,6 +74,8 @@ _send_qemu_cmd $h "{ 'execute': 'block-commit', 'arguments': { 'device': 'test', 'top': '"${TEST_IMG}.snp1"' } }" "BLOCK_JOB_COMPLETED" +_cleanup_qemu + echo echo "=== Base image info after commit and resize ===" TEST_IMG="${TEST_IMG}.base" _img_info | _filter_img_info -- cgit v1.2.3-55-g7522 From 298c6009dc79dc0cc71cab4a1ad9f8231c1ae858 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Fri, 10 Jun 2016 20:57:49 +0200 Subject: iotests: Add test for post-mirror backing chains Signed-off-by: Max Reitz Message-id: 20160610185750.30956-5-mreitz@redhat.com Reviewed-by: Fam Zheng [mreitz@redhat.com: Removed unnecessary imports] Signed-off-by: Max Reitz --- tests/qemu-iotests/155 | 261 +++++++++++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/155.out | 5 + tests/qemu-iotests/group | 1 + 3 files changed, 267 insertions(+) create mode 100755 tests/qemu-iotests/155 create mode 100644 tests/qemu-iotests/155.out (limited to 'tests') diff --git a/tests/qemu-iotests/155 b/tests/qemu-iotests/155 new file mode 100755 index 0000000000..4057b5e2aa --- /dev/null +++ b/tests/qemu-iotests/155 @@ -0,0 +1,261 @@ +#!/usr/bin/env python +# +# Test whether the backing BDSs are correct after completion of a +# mirror block job; in "existing" modes (drive-mirror with +# mode=existing and blockdev-mirror) the backing chain should not be +# overridden. +# +# Copyright (C) 2016 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 . +# + +import os +import iotests +from iotests import qemu_img + +back0_img = os.path.join(iotests.test_dir, 'back0.' + iotests.imgfmt) +back1_img = os.path.join(iotests.test_dir, 'back1.' + iotests.imgfmt) +back2_img = os.path.join(iotests.test_dir, 'back2.' + iotests.imgfmt) +source_img = os.path.join(iotests.test_dir, 'source.' + iotests.imgfmt) +target_img = os.path.join(iotests.test_dir, 'target.' + iotests.imgfmt) + + +# Class variables for controlling its behavior: +# +# existing: If True, explicitly create the target image and blockdev-add it +# target_backing: If existing is True: Use this filename as the backing file +# of the target image +# (None: no backing file) +# target_blockdev_backing: If existing is True: Pass this dict as "backing" +# for the blockdev-add command +# (None: do not pass "backing") +# target_real_backing: If existing is True: The real filename of the backing +# image during runtime, only makes sense if +# target_blockdev_backing is not None +# (None: same as target_backing) + +class BaseClass(iotests.QMPTestCase): + target_blockdev_backing = None + target_real_backing = None + + def setUp(self): + qemu_img('create', '-f', iotests.imgfmt, back0_img, '1M') + qemu_img('create', '-f', iotests.imgfmt, '-b', back0_img, back1_img) + qemu_img('create', '-f', iotests.imgfmt, '-b', back1_img, back2_img) + qemu_img('create', '-f', iotests.imgfmt, '-b', back2_img, source_img) + + self.vm = iotests.VM() + self.vm.add_drive(None, '', 'none') + self.vm.launch() + + # Add the BDS via blockdev-add so it stays around after the mirror block + # job has been completed + result = self.vm.qmp('blockdev-add', + options={'node-name': 'source', + 'driver': iotests.imgfmt, + 'file': {'driver': 'file', + 'filename': source_img}}) + self.assert_qmp(result, 'return', {}) + + result = self.vm.qmp('x-blockdev-insert-medium', + device='drive0', node_name='source') + self.assert_qmp(result, 'return', {}) + + self.assertIntactSourceBackingChain() + + if self.existing: + if self.target_backing: + qemu_img('create', '-f', iotests.imgfmt, + '-b', self.target_backing, target_img, '1M') + else: + qemu_img('create', '-f', iotests.imgfmt, target_img, '1M') + + if self.cmd == 'blockdev-mirror': + options = { 'node-name': 'target', + 'driver': iotests.imgfmt, + 'file': { 'driver': 'file', + 'filename': target_img } } + if self.target_blockdev_backing: + options['backing'] = self.target_blockdev_backing + + result = self.vm.qmp('blockdev-add', options=options) + self.assert_qmp(result, 'return', {}) + + def tearDown(self): + self.vm.shutdown() + os.remove(source_img) + os.remove(back2_img) + os.remove(back1_img) + os.remove(back0_img) + try: + os.remove(target_img) + except OSError: + pass + + def findBlockNode(self, node_name, id=None): + if id: + result = self.vm.qmp('query-block') + for device in result['return']: + if device['device'] == id: + if node_name: + self.assert_qmp(device, 'inserted/node-name', node_name) + return device['inserted'] + else: + result = self.vm.qmp('query-named-block-nodes') + for node in result['return']: + if node['node-name'] == node_name: + return node + + self.fail('Cannot find node %s/%s' % (id, node_name)) + + def assertIntactSourceBackingChain(self): + node = self.findBlockNode('source') + + self.assert_qmp(node, 'image' + '/backing-image' * 0 + '/filename', + source_img) + self.assert_qmp(node, 'image' + '/backing-image' * 1 + '/filename', + back2_img) + self.assert_qmp(node, 'image' + '/backing-image' * 2 + '/filename', + back1_img) + self.assert_qmp(node, 'image' + '/backing-image' * 3 + '/filename', + back0_img) + self.assert_qmp_absent(node, 'image' + '/backing-image' * 4) + + def assertCorrectBackingImage(self, node, default_image): + if self.existing: + if self.target_real_backing: + image = self.target_real_backing + else: + image = self.target_backing + else: + image = default_image + + if image: + self.assert_qmp(node, 'image/backing-image/filename', image) + else: + self.assert_qmp_absent(node, 'image/backing-image') + + +# Class variables for controlling its behavior: +# +# cmd: Mirroring command to execute, either drive-mirror or blockdev-mirror + +class MirrorBaseClass(BaseClass): + def runMirror(self, sync): + if self.cmd == 'blockdev-mirror': + result = self.vm.qmp(self.cmd, device='drive0', sync=sync, + target='target') + else: + if self.existing: + mode = 'existing' + else: + mode = 'absolute-paths' + result = self.vm.qmp(self.cmd, device='drive0', sync=sync, + target=target_img, format=iotests.imgfmt, + mode=mode, node_name='target') + + self.assert_qmp(result, 'return', {}) + + self.vm.event_wait('BLOCK_JOB_READY') + + result = self.vm.qmp('block-job-complete', device='drive0') + self.assert_qmp(result, 'return', {}) + + self.vm.event_wait('BLOCK_JOB_COMPLETED') + + def testFull(self): + self.runMirror('full') + + node = self.findBlockNode('target', 'drive0') + self.assertCorrectBackingImage(node, None) + self.assertIntactSourceBackingChain() + + def testTop(self): + self.runMirror('top') + + node = self.findBlockNode('target', 'drive0') + self.assertCorrectBackingImage(node, back2_img) + self.assertIntactSourceBackingChain() + + def testNone(self): + self.runMirror('none') + + node = self.findBlockNode('target', 'drive0') + self.assertCorrectBackingImage(node, source_img) + self.assertIntactSourceBackingChain() + + +class TestDriveMirrorAbsolutePaths(MirrorBaseClass): + cmd = 'drive-mirror' + existing = False + +class TestDriveMirrorExistingNoBacking(MirrorBaseClass): + cmd = 'drive-mirror' + existing = True + target_backing = None + +class TestDriveMirrorExistingBacking(MirrorBaseClass): + cmd = 'drive-mirror' + existing = True + target_backing = 'null-co://' + +class TestBlockdevMirrorNoBacking(MirrorBaseClass): + cmd = 'blockdev-mirror' + existing = True + target_backing = None + +class TestBlockdevMirrorBacking(MirrorBaseClass): + cmd = 'blockdev-mirror' + existing = True + target_backing = 'null-co://' + +class TestBlockdevMirrorForcedBacking(MirrorBaseClass): + cmd = 'blockdev-mirror' + existing = True + target_backing = None + target_blockdev_backing = { 'driver': 'null-co' } + target_real_backing = 'null-co://' + + +class TestCommit(BaseClass): + existing = False + + def testCommit(self): + result = self.vm.qmp('block-commit', device='drive0', base=back1_img) + self.assert_qmp(result, 'return', {}) + + self.vm.event_wait('BLOCK_JOB_READY') + + result = self.vm.qmp('block-job-complete', device='drive0') + self.assert_qmp(result, 'return', {}) + + self.vm.event_wait('BLOCK_JOB_COMPLETED') + + node = self.findBlockNode(None, 'drive0') + self.assert_qmp(node, 'image' + '/backing-image' * 0 + '/filename', + back1_img) + self.assert_qmp(node, 'image' + '/backing-image' * 1 + '/filename', + back0_img) + self.assert_qmp_absent(node, 'image' + '/backing-image' * 2 + + '/filename') + + self.assertIntactSourceBackingChain() + + +BaseClass = None +MirrorBaseClass = None + +if __name__ == '__main__': + iotests.main(supported_fmts=['qcow2']) diff --git a/tests/qemu-iotests/155.out b/tests/qemu-iotests/155.out new file mode 100644 index 0000000000..4176bb9402 --- /dev/null +++ b/tests/qemu-iotests/155.out @@ -0,0 +1,5 @@ +................... +---------------------------------------------------------------------- +Ran 19 tests + +OK diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index ab1d76efdf..9f1f2c0d9e 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -154,3 +154,4 @@ 150 rw auto quick 152 rw auto quick 154 rw auto backing quick +155 rw auto -- cgit v1.2.3-55-g7522 From 3dd48fdc55613c102f2811c63ceefd9aebcd44ca Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Fri, 10 Jun 2016 20:57:50 +0200 Subject: iotests: Add test for oVirt-like storage migration Signed-off-by: Max Reitz Message-id: 20160610185750.30956-6-mreitz@redhat.com Reviewed-by: Kevin Wolf Reviewed-by: Fam Zheng Signed-off-by: Max Reitz --- tests/qemu-iotests/156 | 174 +++++++++++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/156.out | 48 +++++++++++++ tests/qemu-iotests/group | 1 + 3 files changed, 223 insertions(+) create mode 100755 tests/qemu-iotests/156 create mode 100644 tests/qemu-iotests/156.out (limited to 'tests') diff --git a/tests/qemu-iotests/156 b/tests/qemu-iotests/156 new file mode 100755 index 0000000000..cc95ff1f98 --- /dev/null +++ b/tests/qemu-iotests/156 @@ -0,0 +1,174 @@ +#!/bin/bash +# +# Tests oVirt-like storage migration: +# - Create snapshot +# - Create target image with (not yet existing) target backing chain +# (i.e. just write the name of a soon-to-be-copied-over backing file into it) +# - drive-mirror the snapshot to the target with mode=existing and sync=top +# - In the meantime, copy the original source files to the destination via +# conventional means (i.e. outside of qemu) +# - Complete the drive-mirror job +# - Delete all source images +# +# Copyright (C) 2016 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=mreitz@redhat.com + +seq="$(basename $0)" +echo "QA output created by $seq" + +here="$PWD" +status=1 # failure is the default! + +_cleanup() +{ + rm -f "$TEST_IMG{,.target}{,.backing,.overlay}" +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter +. ./common.qemu + +_supported_fmt qcow2 qed +_supported_proto generic +_supported_os Linux + +# Create source disk +TEST_IMG="$TEST_IMG.backing" _make_test_img 1M +_make_test_img -b "$TEST_IMG.backing" 1M + +$QEMU_IO -c 'write -P 1 0 256k' "$TEST_IMG.backing" | _filter_qemu_io +$QEMU_IO -c 'write -P 2 64k 192k' "$TEST_IMG" | _filter_qemu_io + +_launch_qemu -drive if=none,id=source,file="$TEST_IMG" + +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'qmp_capabilities' }" \ + 'return' + +# Create snapshot +TEST_IMG="$TEST_IMG.overlay" _make_test_img -b "$TEST_IMG" 1M +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'blockdev-snapshot-sync', + 'arguments': { 'device': 'source', + 'snapshot-file': '$TEST_IMG.overlay', + 'format': '$IMGFMT', + 'mode': 'existing' } }" \ + 'return' + +# Write something to the snapshot +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'human-monitor-command', + 'arguments': { 'command-line': + 'qemu-io source \"write -P 3 128k 128k\"' } }" \ + 'return' + +# Create target image +TEST_IMG="$TEST_IMG.target.overlay" _make_test_img -b "$TEST_IMG.target" 1M + +# Mirror snapshot +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'drive-mirror', + 'arguments': { 'device': 'source', + 'target': '$TEST_IMG.target.overlay', + 'mode': 'existing', + 'sync': 'top' } }" \ + 'return' + +# Wait for convergence +_send_qemu_cmd $QEMU_HANDLE \ + '' \ + 'BLOCK_JOB_READY' + +# Write some more +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'human-monitor-command', + 'arguments': { 'command-line': + 'qemu-io source \"write -P 4 192k 64k\"' } }" \ + 'return' + +# Copy source backing chain to the target before completing the job +cp "$TEST_IMG.backing" "$TEST_IMG.target.backing" +cp "$TEST_IMG" "$TEST_IMG.target" +$QEMU_IMG rebase -u -b "$TEST_IMG.target.backing" "$TEST_IMG.target" + +# Complete block job +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'block-job-complete', + 'arguments': { 'device': 'source' } }" \ + '' + +_send_qemu_cmd $QEMU_HANDLE \ + '' \ + 'BLOCK_JOB_COMPLETED' + +# Remove the source images +rm -f "$TEST_IMG{,.backing,.overlay}" + +echo + +# Check online disk contents +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'human-monitor-command', + 'arguments': { 'command-line': + 'qemu-io source \"read -P 1 0k 64k\"' } }" \ + 'return' + +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'human-monitor-command', + 'arguments': { 'command-line': + 'qemu-io source \"read -P 2 64k 64k\"' } }" \ + 'return' + +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'human-monitor-command', + 'arguments': { 'command-line': + 'qemu-io source \"read -P 3 128k 64k\"' } }" \ + 'return' + +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'human-monitor-command', + 'arguments': { 'command-line': + 'qemu-io source \"read -P 4 192k 64k\"' } }" \ + 'return' + +echo + +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'quit' }" \ + 'return' + +wait=1 _cleanup_qemu + +echo + +# Check offline disk contents +$QEMU_IO -c 'read -P 1 0k 64k' \ + -c 'read -P 2 64k 64k' \ + -c 'read -P 3 128k 64k' \ + -c 'read -P 4 192k 64k' \ + "$TEST_IMG.target.overlay" | _filter_qemu_io + +echo + +# success, all done +echo '*** done' +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/156.out b/tests/qemu-iotests/156.out new file mode 100644 index 0000000000..3af82ae540 --- /dev/null +++ b/tests/qemu-iotests/156.out @@ -0,0 +1,48 @@ +QA output created by 156 +Formatting 'TEST_DIR/t.IMGFMT.backing', fmt=IMGFMT size=1048576 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT.backing +wrote 262144/262144 bytes at offset 0 +256 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 196608/196608 bytes at offset 65536 +192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{"return": {}} +Formatting 'TEST_DIR/t.IMGFMT.overlay', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT +{"return": {}} +wrote 131072/131072 bytes at offset 131072 +128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{"return": ""} +Formatting 'TEST_DIR/t.IMGFMT.target.overlay', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT.target +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "source", "len": 131072, "offset": 131072, "speed": 0, "type": "mirror"}} +wrote 65536/65536 bytes at offset 196608 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{"return": ""} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "source", "len": 196608, "offset": 196608, "speed": 0, "type": "mirror"}} + +read 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{"return": ""} +read 65536/65536 bytes at offset 65536 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{"return": ""} +read 65536/65536 bytes at offset 131072 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{"return": ""} +read 65536/65536 bytes at offset 196608 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{"return": ""} + +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"} + +read 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 65536/65536 bytes at offset 65536 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 65536/65536 bytes at offset 131072 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 65536/65536 bytes at offset 196608 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +*** done diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 9f1f2c0d9e..1c6fcb6018 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -155,3 +155,4 @@ 152 rw auto quick 154 rw auto backing quick 155 rw auto +156 rw auto quick -- cgit v1.2.3-55-g7522