| From 27042ff7aca4366c50e8ed66b47487d46774d16a Mon Sep 17 00:00:00 2001 |
| From: Hanna Reitz <hreitz@redhat.com> |
| Date: Wed, 16 Feb 2022 11:53:55 +0100 |
| Subject: [PATCH 24/24] iotests/graph-changes-while-io: New test |
| |
| RH-Author: Hanna Reitz <hreitz@redhat.com> |
| RH-MergeRequest: 189: block: Make bdrv_refresh_limits() non-recursive |
| RH-Commit: [3/3] b9dffe09bef6cf9b2f0aad69b327ea1df92e847a |
| RH-Bugzilla: 2072932 |
| RH-Acked-by: Eric Blake <eblake@redhat.com> |
| RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com> |
| RH-Acked-by: Kevin Wolf <kwolf@redhat.com> |
| |
| Test the following scenario: |
| 1. Some block node (null-co) attached to a user (here: NBD server) that |
| performs I/O and keeps the node in an I/O thread |
| 2. Repeatedly run blockdev-add/blockdev-del to add/remove an overlay |
| to/from that node |
| |
| Each blockdev-add triggers bdrv_refresh_limits(), and because |
| blockdev-add runs in the main thread, it does not stop the I/O requests. |
| I/O can thus happen while the limits are refreshed, and when such a |
| request sees a temporarily invalid block limit (e.g. alignment is 0), |
| this may easily crash qemu (or the storage daemon in this case). |
| |
| The block layer needs to ensure that I/O requests to a node are paused |
| while that node's BlockLimits are refreshed. |
| |
| Signed-off-by: Hanna Reitz <hreitz@redhat.com> |
| Reviewed-by: Eric Blake <eblake@redhat.com> |
| Message-Id: <20220216105355.30729-4-hreitz@redhat.com> |
| Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> |
| Signed-off-by: Kevin Wolf <kwolf@redhat.com> |
| (cherry picked from commit 971bea8089531af56b1bbd9ce62e756bdf006711) |
| Signed-off-by: Hanna Reitz <hreitz@redhat.com> |
| |
| .../qemu-iotests/tests/graph-changes-while-io | 91 +++++++++++++++++++ |
| .../tests/graph-changes-while-io.out | 5 + |
| 2 files changed, 96 insertions(+) |
| create mode 100755 tests/qemu-iotests/tests/graph-changes-while-io |
| create mode 100644 tests/qemu-iotests/tests/graph-changes-while-io.out |
| |
| diff --git a/tests/qemu-iotests/tests/graph-changes-while-io b/tests/qemu-iotests/tests/graph-changes-while-io |
| new file mode 100755 |
| index 0000000000..567e8cf21e |
| |
| |
| @@ -0,0 +1,91 @@ |
| +#!/usr/bin/env python3 |
| +# group: rw |
| +# |
| +# Test graph changes while I/O is happening |
| +# |
| +# Copyright (C) 2022 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 <http://www.gnu.org/licenses/>. |
| +# |
| + |
| +import os |
| +from threading import Thread |
| +import iotests |
| +from iotests import imgfmt, qemu_img, qemu_img_create, QMPTestCase, \ |
| + QemuStorageDaemon |
| + |
| + |
| +top = os.path.join(iotests.test_dir, 'top.img') |
| +nbd_sock = os.path.join(iotests.sock_dir, 'nbd.sock') |
| + |
| + |
| +def do_qemu_img_bench() -> None: |
| + """ |
| + Do some I/O requests on `nbd_sock`. |
| + """ |
| + assert qemu_img('bench', '-f', 'raw', '-c', '2000000', |
| + f'nbd+unix:///node0?socket={nbd_sock}') == 0 |
| + |
| + |
| +class TestGraphChangesWhileIO(QMPTestCase): |
| + def setUp(self) -> None: |
| + # Create an overlay that can be added at runtime on top of the |
| + # null-co block node that will receive I/O |
| + assert qemu_img_create('-f', imgfmt, '-F', 'raw', '-b', 'null-co://', |
| + top) == 0 |
| + |
| + # QSD instance with a null-co block node in an I/O thread, |
| + # exported over NBD (on `nbd_sock`, export name "node0") |
| + self.qsd = QemuStorageDaemon( |
| + '--object', 'iothread,id=iothread0', |
| + '--blockdev', 'null-co,node-name=node0,read-zeroes=true', |
| + '--nbd-server', f'addr.type=unix,addr.path={nbd_sock}', |
| + '--export', 'nbd,id=exp0,node-name=node0,iothread=iothread0,' + |
| + 'fixed-iothread=true,writable=true', |
| + qmp=True |
| + ) |
| + |
| + def tearDown(self) -> None: |
| + self.qsd.stop() |
| + |
| + def test_blockdev_add_while_io(self) -> None: |
| + # Run qemu-img bench in the background |
| + bench_thr = Thread(target=do_qemu_img_bench) |
| + bench_thr.start() |
| + |
| + # While qemu-img bench is running, repeatedly add and remove an |
| + # overlay to/from node0 |
| + while bench_thr.is_alive(): |
| + result = self.qsd.qmp('blockdev-add', { |
| + 'driver': imgfmt, |
| + 'node-name': 'overlay', |
| + 'backing': 'node0', |
| + 'file': { |
| + 'driver': 'file', |
| + 'filename': top |
| + } |
| + }) |
| + self.assert_qmp(result, 'return', {}) |
| + |
| + result = self.qsd.qmp('blockdev-del', { |
| + 'node-name': 'overlay' |
| + }) |
| + self.assert_qmp(result, 'return', {}) |
| + |
| + bench_thr.join() |
| + |
| +if __name__ == '__main__': |
| + # Format must support raw backing files |
| + iotests.main(supported_fmts=['qcow', 'qcow2', 'qed'], |
| + supported_protocols=['file']) |
| diff --git a/tests/qemu-iotests/tests/graph-changes-while-io.out b/tests/qemu-iotests/tests/graph-changes-while-io.out |
| new file mode 100644 |
| index 0000000000..ae1213e6f8 |
| |
| |
| @@ -0,0 +1,5 @@ |
| +. |
| +---------------------------------------------------------------------- |
| +Ran 1 tests |
| + |
| +OK |
| -- |
| 2.35.3 |
| |