All of lore.kernel.org
 help / color / mirror / Atom feed
From: Kevin Wolf <kwolf@redhat.com>
To: qemu-block@nongnu.org
Cc: kwolf@redhat.com, qemu-devel@nongnu.org
Subject: [PULL 27/27] iotests: add test for changing mirror's copy_mode
Date: Tue, 31 Oct 2023 19:59:18 +0100	[thread overview]
Message-ID: <20231031185918.346940-28-kwolf@redhat.com> (raw)
In-Reply-To: <20231031185918.346940-1-kwolf@redhat.com>

From: Fiona Ebner <f.ebner@proxmox.com>

One part of the test is using a throttled source to ensure that there
are no obvious issues when changing the copy_mode while there are
ongoing requests (source and target images are compared at the very
end).

The other part of the test is using a throttled target to ensure that
the change to active mode actually happened. This is done by hitting
the throttling limit, issuing a synchronous write and then immediately
verifying the target side. QSD is used, because otherwise, a
synchronous write would hang there.

Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
Message-ID: <20231031135431.393137-11-f.ebner@proxmox.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 .../tests/mirror-change-copy-mode             | 193 ++++++++++++++++++
 .../tests/mirror-change-copy-mode.out         |   5 +
 2 files changed, 198 insertions(+)
 create mode 100755 tests/qemu-iotests/tests/mirror-change-copy-mode
 create mode 100644 tests/qemu-iotests/tests/mirror-change-copy-mode.out

diff --git a/tests/qemu-iotests/tests/mirror-change-copy-mode b/tests/qemu-iotests/tests/mirror-change-copy-mode
new file mode 100755
index 0000000000..51788b85c7
--- /dev/null
+++ b/tests/qemu-iotests/tests/mirror-change-copy-mode
@@ -0,0 +1,193 @@
+#!/usr/bin/env python3
+# group: rw
+#
+# Test for changing mirror copy mode from background to active
+#
+# Copyright (C) 2023 Proxmox Server Solutions GmbH
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+import os
+import time
+
+import iotests
+from iotests import qemu_img, QemuStorageDaemon
+
+iops_target = 8
+iops_source = iops_target * 2
+image_size = 1 * 1024 * 1024
+source_img = os.path.join(iotests.test_dir, 'source.' + iotests.imgfmt)
+target_img = os.path.join(iotests.test_dir, 'target.' + iotests.imgfmt)
+nbd_sock = os.path.join(iotests.sock_dir, 'nbd.sock')
+
+class TestMirrorChangeCopyMode(iotests.QMPTestCase):
+
+    def setUp(self):
+        qemu_img('create', '-f', iotests.imgfmt, source_img, str(image_size))
+        qemu_img('create', '-f', iotests.imgfmt, target_img, str(image_size))
+
+        self.qsd = QemuStorageDaemon('--nbd-server',
+                                     f'addr.type=unix,addr.path={nbd_sock}',
+                                     qmp=True)
+
+        self.qsd.cmd('object-add', {
+            'qom-type': 'throttle-group',
+            'id': 'thrgr-target',
+            'limits': {
+                'iops-write': iops_target,
+                'iops-write-max': iops_target
+            }
+        })
+
+        self.qsd.cmd('blockdev-add', {
+            'node-name': 'target',
+            'driver': 'throttle',
+            'throttle-group': 'thrgr-target',
+            'file': {
+                'driver': iotests.imgfmt,
+                'file': {
+                    'driver': 'file',
+                    'filename': target_img
+                }
+            }
+        })
+
+        self.qsd.cmd('block-export-add', {
+            'id': 'exp0',
+            'type': 'nbd',
+            'node-name': 'target',
+            'writable': True
+        })
+
+        self.vm = iotests.VM()
+        self.vm.add_args('-drive',
+                         f'file={source_img},if=none,format={iotests.imgfmt},'
+                         f'iops_wr={iops_source},'
+                         f'iops_wr_max={iops_source},'
+                         'id=source')
+        self.vm.launch()
+
+        self.vm.cmd('blockdev-add', {
+            'node-name': 'target',
+            'driver': 'nbd',
+            'export': 'target',
+            'server': {
+                'type': 'unix',
+                'path': nbd_sock
+            }
+        })
+
+
+    def tearDown(self):
+        self.vm.shutdown()
+        self.qsd.stop()
+        self.check_qemu_io_errors()
+        self.check_images_identical()
+        os.remove(source_img)
+        os.remove(target_img)
+
+    # Once the VM is shut down we can parse the log and see if qemu-io ran
+    # without errors.
+    def check_qemu_io_errors(self):
+        self.assertFalse(self.vm.is_running())
+        log = self.vm.get_log()
+        for line in log.split("\n"):
+            assert not line.startswith("Pattern verification failed")
+
+    def check_images_identical(self):
+        qemu_img('compare', '-f', iotests.imgfmt, source_img, target_img)
+
+    def start_mirror(self):
+        self.vm.cmd('blockdev-mirror',
+                    job_id='mirror',
+                    device='source',
+                    target='target',
+                    filter_node_name='mirror-top',
+                    sync='full',
+                    copy_mode='background')
+
+    def test_background_to_active(self):
+        self.vm.hmp_qemu_io('source', f'write 0 {image_size}')
+        self.vm.hmp_qemu_io('target', f'write 0 {image_size}')
+
+        self.start_mirror()
+
+        result = self.vm.cmd('query-block-jobs')
+        assert not result[0]['actively-synced']
+
+        self.vm.event_wait('BLOCK_JOB_READY')
+
+        result = self.vm.cmd('query-block-jobs')
+        assert not result[0]['actively-synced']
+
+        # Start some background requests.
+        reqs = 4 * iops_source
+        req_size = image_size // reqs
+        for i in range(0, reqs):
+            req = f'aio_write -P 7 {req_size * i} {req_size}'
+            self.vm.hmp_qemu_io('source', req)
+
+        # Wait for the first few requests.
+        time.sleep(1)
+        self.vm.qtest(f'clock_step {1 * 1000 * 1000 * 1000}')
+
+        result = self.vm.cmd('query-block-jobs')
+        # There should've been new requests.
+        assert result[0]['len'] > image_size
+        # To verify later that not all requests were completed at this point.
+        len_before_change = result[0]['len']
+
+        # Change the copy mode while requests are happening.
+        self.vm.cmd('block-job-change',
+                    id='mirror',
+                    type='mirror',
+                    copy_mode='write-blocking')
+
+        # Wait until image is actively synced.
+        while True:
+            time.sleep(0.1)
+            self.vm.qtest(f'clock_step {100 * 1000 * 1000}')
+            result = self.vm.cmd('query-block-jobs')
+            if result[0]['actively-synced']:
+                break
+
+        # Because of throttling, not all requests should have been completed
+        # above.
+        result = self.vm.cmd('query-block-jobs')
+        assert result[0]['len'] > len_before_change
+
+        # Issue enough requests for a few seconds only touching the first half
+        # of the image.
+        reqs = 4 * iops_target
+        req_size = image_size // 2 // reqs
+        for i in range(0, reqs):
+            req = f'aio_write -P 19 {req_size * i} {req_size}'
+            self.vm.hmp_qemu_io('source', req)
+
+        # Now issue a synchronous write in the second half of the image and
+        # immediately verify that it was written to the target too. This would
+        # fail without switching the copy mode. Note that this only produces a
+        # log line and the actual checking happens during tearDown().
+        req_args = f'-P 37 {3 * (image_size // 4)} {req_size}'
+        self.vm.hmp_qemu_io('source', f'write {req_args}')
+        self.vm.hmp_qemu_io('target', f'read {req_args}')
+
+        self.vm.cmd('block-job-cancel', device='mirror')
+        while len(self.vm.cmd('query-block-jobs')) > 0:
+            time.sleep(0.1)
+
+if __name__ == '__main__':
+    iotests.main(supported_fmts=['qcow2', 'raw'],
+                 supported_protocols=['file'])
diff --git a/tests/qemu-iotests/tests/mirror-change-copy-mode.out b/tests/qemu-iotests/tests/mirror-change-copy-mode.out
new file mode 100644
index 0000000000..ae1213e6f8
--- /dev/null
+++ b/tests/qemu-iotests/tests/mirror-change-copy-mode.out
@@ -0,0 +1,5 @@
+.
+----------------------------------------------------------------------
+Ran 1 tests
+
+OK
-- 
2.41.0



  parent reply	other threads:[~2023-10-31 19:02 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-10-31 18:58 [PULL 00/27] Block layer patches Kevin Wolf
2023-10-31 18:58 ` [PULL 01/27] qemu-img: rebase: stop when reaching EOF of old backing file Kevin Wolf
2023-10-31 18:58 ` [PULL 02/27] qemu-iotests: 024: add rebasing test case for overlay_size > backing_size Kevin Wolf
2023-10-31 18:58 ` [PULL 03/27] qemu-img: rebase: use backing files' BlockBackend for buffer alignment Kevin Wolf
2023-10-31 18:58 ` [PULL 04/27] qemu-img: add chunk size parameter to compare_buffers() Kevin Wolf
2023-10-31 18:58 ` [PULL 05/27] qemu-img: rebase: avoid unnecessary COW operations Kevin Wolf
2023-10-31 18:58 ` [PULL 06/27] iotests/{024, 271}: add testcases for qemu-img rebase Kevin Wolf
2023-10-31 18:58 ` [PULL 07/27] qemu-img: add compression option to rebase subcommand Kevin Wolf
2023-10-31 18:58 ` [PULL 08/27] iotests: add tests for "qemu-img rebase" with compression Kevin Wolf
2023-10-31 18:59 ` [PULL 09/27] block: Fix locking in media change monitor commands Kevin Wolf
2023-10-31 18:59 ` [PULL 10/27] iotests: Test media change with iothreads Kevin Wolf
2023-10-31 18:59 ` [PULL 11/27] blockjob: drop AioContext lock before calling bdrv_graph_wrlock() Kevin Wolf
2023-10-31 18:59 ` [PULL 12/27] block: avoid potential deadlock during bdrv_graph_wrlock() in bdrv_close() Kevin Wolf
2023-10-31 18:59 ` [PULL 13/27] blockdev: mirror: avoid potential deadlock when using iothread Kevin Wolf
2023-10-31 18:59 ` [PULL 14/27] block: rename blk_io_plug_call() API to defer_call() Kevin Wolf
2023-10-31 18:59 ` [PULL 15/27] util/defer-call: move defer_call() to util/ Kevin Wolf
2023-10-31 18:59 ` [PULL 16/27] virtio: use defer_call() in virtio_irqfd_notify() Kevin Wolf
2023-10-31 18:59 ` [PULL 17/27] virtio-blk: remove batch notification BH Kevin Wolf
2023-10-31 18:59 ` [PULL 18/27] blockjob: introduce block-job-change QMP command Kevin Wolf
2023-10-31 18:59 ` [PULL 19/27] block/mirror: set actively_synced even after the job is ready Kevin Wolf
2023-10-31 18:59 ` [PULL 20/27] block/mirror: move dirty bitmap to filter Kevin Wolf
2023-10-31 18:59 ` [PULL 21/27] block/mirror: determine copy_to_target only once Kevin Wolf
2023-10-31 18:59 ` [PULL 22/27] mirror: implement mirror_change method Kevin Wolf
2023-10-31 18:59 ` [PULL 23/27] qapi/block-core: use JobType for BlockJobInfo's type Kevin Wolf
2023-10-31 18:59 ` [PULL 24/27] qapi/block-core: turn BlockJobInfo into a union Kevin Wolf
2023-10-31 18:59 ` [PULL 25/27] blockjob: query driver-specific info via a new 'query' driver method Kevin Wolf
2023-10-31 18:59 ` [PULL 26/27] mirror: return mirror-specific information upon query Kevin Wolf
2023-10-31 18:59 ` Kevin Wolf [this message]
2023-10-31 23:31 ` [PULL 00/27] Block layer patches Stefan Hajnoczi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20231031185918.346940-28-kwolf@redhat.com \
    --to=kwolf@redhat.com \
    --cc=qemu-block@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.