Test the connect thread starting condition with reconnect-delay=0 when the server disconnects after a successful handshake but before running operations. Prior to the change to nbd_co_establish_connection(), this test would demonstrate two I/O errors. The tests 264 and 277 covering reconnection do not use reconnect-delay=0 so this case is not exercised.
Add a test that provokes multiple errors in order to put an NBD client in the above-mentioned situation and shows that the first operation starts the connect thread and leads to successful subsequent I/O. Signed-off-by: Guillaume Vincke <[email protected]> --- tests/qemu-iotests/tests/nbd-stale-connection | 62 +++++++++++++++++++ .../tests/nbd-stale-connection.out | 17 +++++ 2 files changed, 79 insertions(+) create mode 100755 tests/qemu-iotests/tests/nbd-stale-connection create mode 100644 tests/qemu-iotests/tests/nbd-stale-connection.out diff --git a/tests/qemu-iotests/tests/nbd-stale-connection b/tests/qemu-iotests/tests/nbd-stale-connection new file mode 100755 index 0000000000..6f6fb6ef1b --- /dev/null +++ b/tests/qemu-iotests/tests/nbd-stale-connection @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 +# group: quick +# +# Test the NBD client stale channel discard +# +# Copyright (C) 2026 OVHcloud +# +# SPDX-License-Identifier: GPL-2.0-or-later + +import time +import iotests +from iotests import qemu_nbd_popen, qemu_img_create, file_path, log + + +# estimated duration required by the connect thread to reach a running server +MAX_NBD_HANDSHAKE_DURATION = 0.5 +# sleep duration of the connection retry in nbd client +CONNECT_RETRY_DELAY = 1 + +iotests.script_initialize() +nbd_sock = file_path('nbd-sock', base_dir=iotests.sock_dir) +disk = file_path('disk') +qemu_img_create('-f', iotests.imgfmt, disk, '1M') + +with iotests.VM() as vm: + + vm.launch() + + with qemu_nbd_popen('-k', nbd_sock, '-f', iotests.imgfmt, disk): + vm.cmd('blockdev-add', { + 'driver': 'nbd', + 'node-name': 'nbd0', + 'server': {'type': 'unix', 'path': nbd_sock}, + }) + iotests.log('=== NBD Device connected ===') + log(vm.qmp('x-qemu-io', device='nbd0', command='write -P 0x5a 0 64k')) + + iotests.log('=== NBD server down. Detect the break and start the connect ' + 'thread ===') + # client was in CONNECTED state a new operation updates to CONNECTING + log(vm.qmp('x-qemu-io', device='nbd0', command='write -P 0x5a 0 64k')) + # in CONNECTING, the operation starts the connect thread + log(vm.qmp('x-qemu-io', device='nbd0', command='write -P 0x5a 0 64k')) + + with qemu_nbd_popen('-k', nbd_sock, '-f', iotests.imgfmt, disk): + iotests.log('=== NBD server up. Wait for the connect thread to park ' + 'the channel ===') + # wait for the connect thread to get a new channel and stop + time.sleep(CONNECT_RETRY_DELAY + MAX_NBD_HANDSHAKE_DURATION) + + iotests.log('=== NBD server down. The parked channel is closed ===') + + with qemu_nbd_popen('-k', nbd_sock, '-f', iotests.imgfmt, disk): + iotests.log('=== NBD server up. Restart the connect thread ===') + # operation will determine that the channel got closed and restart the + # connect thread + log(vm.qmp('x-qemu-io', device='nbd0', command='write -P 0x5a 0 64k')) + # Wait for it to succeed + iotests.log('=== Wait for the connect thread to park the new channel. ' + 'Subsequent operations are successful ===') + time.sleep(MAX_NBD_HANDSHAKE_DURATION) + log(vm.qmp('x-qemu-io', device='nbd0', command='write -P 0x5a 0 64k')) diff --git a/tests/qemu-iotests/tests/nbd-stale-connection.out b/tests/qemu-iotests/tests/nbd-stale-connection.out new file mode 100644 index 0000000000..50f80e2305 --- /dev/null +++ b/tests/qemu-iotests/tests/nbd-stale-connection.out @@ -0,0 +1,17 @@ +Start NBD server +=== NBD Device connected === +{"return": {}} +Kill NBD server +=== NBD server down. Detect the break and start the connect thread === +{"error": {"class": "GenericError", "desc": "write failed: Input/output error"}} +{"error": {"class": "GenericError", "desc": "write failed: Input/output error"}} +Start NBD server +=== NBD server up. Wait for the connect thread to park the channel === +Kill NBD server +=== NBD server down. The parked channel is closed === +Start NBD server +=== NBD server up. Restart the connect thread === +{"error": {"class": "GenericError", "desc": "write failed: Input/output error"}} +=== Wait for the connect thread to park the new channel. Subsequent operations are successful === +{"return": {}} +Kill NBD server -- 2.43.0
