Block layer patches

- Graph locking, part 3 (more block drivers)
 - Compile out assert_bdrv_graph_readable() by default
 - Add configure options for vmdk, vhdx and vpc
 - Fix use after free in blockdev_mark_auto_del()
 - migration: Attempt disk reactivation in more failure scenarios
 - Coroutine correctness fixes
 -----BEGIN PGP SIGNATURE-----
 
 iQJFBAABCAAvFiEE3D3rFZqa+V09dFb+fwmycsiPL9YFAmRbi6ERHGt3b2xmQHJl
 ZGhhdC5jb20ACgkQfwmycsiPL9Y66A//ZRk/0M6EZUJPAKG6m/XLTDNrOCNBZ1Tu
 kBGvxXsVQZMt4gGpBad4l2INN6IQKTIdIf+lK71EpxMPmFG6xK32btn38yywCAfQ
 lr1p5nR0Y/zSlT+XzP4yKy/CtQl6U0rkysmjCIk35bZc7uLy6eo4oFR4vmhRRt2M
 UGltB50/Nicx12YFufVjodbhv+apxTGwS2XHatmwqtjKeYReSz8mJHslEy6DvC8m
 ziNThD6YBy7hMktAhNaqUqtZD0OSWz66VMObco/4i2++sOAMZIspXQkjv3AjH74e
 lmgMhNc/xgJKPwFBPsj6F7dOKxwhdKD9jzZlx3yaBtAU18hpWX54QWuA3/CFlySc
 5QbbqIstFTC8lqoRWThQrcHHRKbDBJCP4ImRXUIKhuPaxEzXA9zb3+f3QPTIjLSA
 KO7nxuSmO+tC7hQ1K9kAjRZHWlxxAk4clk+7UrK4UrWgGxfCUKgFg4Tyx7RrpwA6
 j4L5vwAY60LW74tikWe9xJx2QbdRoWBTTZhUyirbO7rLX1e8mS1nUWmtIsFSQxAq
 Z7nX7ygN0WEF+8qIsk3jTGaEeJoCM7+7B+X2RpSy0sftFjFYmybIiUgLMO7e+ozK
 rvUPnwlHAbGCVIJOKrUDj3cGt6k3/xnrTajUc7pCB3KKqG4pe+IlZuHyKIUMActb
 dBLaBnj0M2o=
 =hw9E
 -----END PGP SIGNATURE-----

Merge tag 'for-upstream' of https://repo.or.cz/qemu/kevin into staging

Block layer patches

- Graph locking, part 3 (more block drivers)
- Compile out assert_bdrv_graph_readable() by default
- Add configure options for vmdk, vhdx and vpc
- Fix use after free in blockdev_mark_auto_del()
- migration: Attempt disk reactivation in more failure scenarios
- Coroutine correctness fixes

# -----BEGIN PGP SIGNATURE-----
#
# iQJFBAABCAAvFiEE3D3rFZqa+V09dFb+fwmycsiPL9YFAmRbi6ERHGt3b2xmQHJl
# ZGhhdC5jb20ACgkQfwmycsiPL9Y66A//ZRk/0M6EZUJPAKG6m/XLTDNrOCNBZ1Tu
# kBGvxXsVQZMt4gGpBad4l2INN6IQKTIdIf+lK71EpxMPmFG6xK32btn38yywCAfQ
# lr1p5nR0Y/zSlT+XzP4yKy/CtQl6U0rkysmjCIk35bZc7uLy6eo4oFR4vmhRRt2M
# UGltB50/Nicx12YFufVjodbhv+apxTGwS2XHatmwqtjKeYReSz8mJHslEy6DvC8m
# ziNThD6YBy7hMktAhNaqUqtZD0OSWz66VMObco/4i2++sOAMZIspXQkjv3AjH74e
# lmgMhNc/xgJKPwFBPsj6F7dOKxwhdKD9jzZlx3yaBtAU18hpWX54QWuA3/CFlySc
# 5QbbqIstFTC8lqoRWThQrcHHRKbDBJCP4ImRXUIKhuPaxEzXA9zb3+f3QPTIjLSA
# KO7nxuSmO+tC7hQ1K9kAjRZHWlxxAk4clk+7UrK4UrWgGxfCUKgFg4Tyx7RrpwA6
# j4L5vwAY60LW74tikWe9xJx2QbdRoWBTTZhUyirbO7rLX1e8mS1nUWmtIsFSQxAq
# Z7nX7ygN0WEF+8qIsk3jTGaEeJoCM7+7B+X2RpSy0sftFjFYmybIiUgLMO7e+ozK
# rvUPnwlHAbGCVIJOKrUDj3cGt6k3/xnrTajUc7pCB3KKqG4pe+IlZuHyKIUMActb
# dBLaBnj0M2o=
# =hw9E
# -----END PGP SIGNATURE-----
# gpg: Signature made Wed 10 May 2023 01:18:41 PM BST
# gpg:                using RSA key DC3DEB159A9AF95D3D7456FE7F09B272C88F2FD6
# gpg:                issuer "kwolf@redhat.com"
# gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" [full]

* tag 'for-upstream' of https://repo.or.cz/qemu/kevin: (28 commits)
  block: compile out assert_bdrv_graph_readable() by default
  block: Mark bdrv_refresh_limits() and callers GRAPH_RDLOCK
  block: Mark bdrv_recurse_can_replace() and callers GRAPH_RDLOCK
  block: Mark bdrv_query_block_graph_info() and callers GRAPH_RDLOCK
  block: Mark bdrv_query_bds_stats() and callers GRAPH_RDLOCK
  block: Mark BlockDriver callbacks for amend job GRAPH_RDLOCK
  block: Mark bdrv_co_debug_event() GRAPH_RDLOCK
  block: Mark bdrv_co_get_info() and callers GRAPH_RDLOCK
  block: Mark bdrv_co_get_allocated_file_size() and callers GRAPH_RDLOCK
  mirror: Require GRAPH_RDLOCK for accessing a node's parent list
  vhdx: Require GRAPH_RDLOCK for accessing a node's parent list
  nbd: Mark nbd_co_do_establish_connection() and callers GRAPH_RDLOCK
  nbd: Remove nbd_co_flush() wrapper function
  block: .bdrv_open is non-coroutine and unlocked
  graph-lock: Fix GRAPH_RDLOCK_GUARD*() to be reader lock
  graph-lock: Add GRAPH_UNLOCKED(_PTR)
  test-bdrv-drain: Don't modify the graph in coroutines
  iotests: Test resizing image attached to an iothread
  block: Don't call no_coroutine_fns in qmp_block_resize()
  block: bdrv/blk_co_unref() for calls in coroutine context
  ...

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2023-05-10 14:52:03 +01:00
commit caa9cbd566
47 changed files with 474 additions and 240 deletions

View file

@ -0,0 +1,71 @@
#!/usr/bin/env bash
# group: rw auto quick
#
# Test resizing an image that is attached to a separate iothread
#
# Copyright (C) 2023 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/>.
#
# creator
owner=kwolf@redhat.com
seq=`basename $0`
echo "QA output created by $seq"
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
cd ..
. ./common.rc
. ./common.filter
# Resizing images is only supported by a few block drivers
_supported_fmt raw qcow2 qed
_supported_proto file
_require_devices virtio-scsi-pci
size=64M
_make_test_img $size
qmp() {
cat <<EOF
{"execute":"qmp_capabilities"}
{'execute': 'block_resize',
'arguments': {'node-name': 'img', 'size': 134217728}}
{"execute":"quit"}
EOF
}
qmp | $QEMU -S -display none \
-drive if=none,format=$IMGFMT,file="$TEST_IMG",node-name=img \
-object iothread,id=t0 \
-device virtio-scsi-pci,iothread=t0 \
-device scsi-hd,drive=none0 \
-qmp stdio \
| _filter_qmp
_img_info | _filter_img_info
# success, all done
echo "*** done"
rm -f $seq.full
status=0

View file

@ -0,0 +1,11 @@
QA output created by iothreads-resize
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
QMP_VERSION
{"return": {}}
{"return": {}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
image: TEST_DIR/t.IMGFMT
file format: IMGFMT
virtual size: 128 MiB (134217728 bytes)
*** done

View file

@ -26,7 +26,8 @@ from iotests import qemu_img_create, file_path, qemu_io_popen, qemu_nbd, \
iotests.script_initialize(supported_fmts=['qcow2'])
disk, nbd_sock = file_path('disk', 'nbd-sock')
disk = file_path('disk')
nbd_sock = file_path('nbd-sock', base_dir=iotests.sock_dir)
def create_args(open_timeout):

View file

@ -2,10 +2,10 @@ read 1048576/1048576 bytes at offset 0
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
Check fail to connect with 0 seconds of timeout
qemu-io: can't open: Failed to connect to 'TEST_DIR/PID-nbd-sock': No such file or directory
qemu-io: can't open: Failed to connect to 'SOCK_DIR/PID-nbd-sock': No such file or directory
qemu_io finished in 0..0.2 seconds, OK
Check fail to connect with 1 seconds of timeout
qemu-io: can't open: Failed to connect to 'TEST_DIR/PID-nbd-sock': No such file or directory
qemu-io: can't open: Failed to connect to 'SOCK_DIR/PID-nbd-sock': No such file or directory
qemu_io finished in 1..1.2 seconds, OK

View file

@ -188,6 +188,25 @@ static void do_drain_begin_unlocked(enum drain_type drain_type, BlockDriverState
}
}
static BlockBackend * no_coroutine_fn test_setup(void)
{
BlockBackend *blk;
BlockDriverState *bs, *backing;
blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR,
&error_abort);
blk_insert_bs(blk, bs, &error_abort);
backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort);
bdrv_set_backing_hd(bs, backing, &error_abort);
bdrv_unref(backing);
bdrv_unref(bs);
return blk;
}
static void do_drain_end_unlocked(enum drain_type drain_type, BlockDriverState *bs)
{
if (drain_type != BDRV_DRAIN_ALL) {
@ -199,25 +218,19 @@ static void do_drain_end_unlocked(enum drain_type drain_type, BlockDriverState *
}
}
static void test_drv_cb_common(enum drain_type drain_type, bool recursive)
static void test_drv_cb_common(BlockBackend *blk, enum drain_type drain_type,
bool recursive)
{
BlockBackend *blk;
BlockDriverState *bs, *backing;
BlockDriverState *bs = blk_bs(blk);
BlockDriverState *backing = bs->backing->bs;
BDRVTestState *s, *backing_s;
BlockAIOCB *acb;
int aio_ret;
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, NULL, 0);
blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR,
&error_abort);
s = bs->opaque;
blk_insert_bs(blk, bs, &error_abort);
backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort);
backing_s = backing->opaque;
bdrv_set_backing_hd(bs, backing, &error_abort);
/* Simple bdrv_drain_all_begin/end pair, check that CBs are called */
g_assert_cmpint(s->drain_count, ==, 0);
@ -252,44 +265,53 @@ static void test_drv_cb_common(enum drain_type drain_type, bool recursive)
g_assert_cmpint(s->drain_count, ==, 0);
g_assert_cmpint(backing_s->drain_count, ==, 0);
bdrv_unref(backing);
bdrv_unref(bs);
blk_unref(blk);
}
static void test_drv_cb_drain_all(void)
{
test_drv_cb_common(BDRV_DRAIN_ALL, true);
BlockBackend *blk = test_setup();
test_drv_cb_common(blk, BDRV_DRAIN_ALL, true);
blk_unref(blk);
}
static void test_drv_cb_drain(void)
{
test_drv_cb_common(BDRV_DRAIN, false);
BlockBackend *blk = test_setup();
test_drv_cb_common(blk, BDRV_DRAIN, false);
blk_unref(blk);
}
static void coroutine_fn test_drv_cb_co_drain_all_entry(void)
{
BlockBackend *blk = blk_all_next(NULL);
test_drv_cb_common(blk, BDRV_DRAIN_ALL, true);
}
static void test_drv_cb_co_drain_all(void)
{
call_in_coroutine(test_drv_cb_drain_all);
BlockBackend *blk = test_setup();
call_in_coroutine(test_drv_cb_co_drain_all_entry);
blk_unref(blk);
}
static void coroutine_fn test_drv_cb_co_drain_entry(void)
{
BlockBackend *blk = blk_all_next(NULL);
test_drv_cb_common(blk, BDRV_DRAIN, false);
}
static void test_drv_cb_co_drain(void)
{
call_in_coroutine(test_drv_cb_drain);
BlockBackend *blk = test_setup();
call_in_coroutine(test_drv_cb_co_drain_entry);
blk_unref(blk);
}
static void test_quiesce_common(enum drain_type drain_type, bool recursive)
static void test_quiesce_common(BlockBackend *blk, enum drain_type drain_type,
bool recursive)
{
BlockBackend *blk;
BlockDriverState *bs, *backing;
blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR,
&error_abort);
blk_insert_bs(blk, bs, &error_abort);
backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort);
bdrv_set_backing_hd(bs, backing, &error_abort);
BlockDriverState *bs = blk_bs(blk);
BlockDriverState *backing = bs->backing->bs;
g_assert_cmpint(bs->quiesce_counter, ==, 0);
g_assert_cmpint(backing->quiesce_counter, ==, 0);
@ -307,30 +329,46 @@ static void test_quiesce_common(enum drain_type drain_type, bool recursive)
g_assert_cmpint(bs->quiesce_counter, ==, 0);
g_assert_cmpint(backing->quiesce_counter, ==, 0);
bdrv_unref(backing);
bdrv_unref(bs);
blk_unref(blk);
}
static void test_quiesce_drain_all(void)
{
test_quiesce_common(BDRV_DRAIN_ALL, true);
BlockBackend *blk = test_setup();
test_quiesce_common(blk, BDRV_DRAIN_ALL, true);
blk_unref(blk);
}
static void test_quiesce_drain(void)
{
test_quiesce_common(BDRV_DRAIN, false);
BlockBackend *blk = test_setup();
test_quiesce_common(blk, BDRV_DRAIN, false);
blk_unref(blk);
}
static void coroutine_fn test_quiesce_co_drain_all_entry(void)
{
BlockBackend *blk = blk_all_next(NULL);
test_quiesce_common(blk, BDRV_DRAIN_ALL, true);
}
static void test_quiesce_co_drain_all(void)
{
call_in_coroutine(test_quiesce_drain_all);
BlockBackend *blk = test_setup();
call_in_coroutine(test_quiesce_co_drain_all_entry);
blk_unref(blk);
}
static void coroutine_fn test_quiesce_co_drain_entry(void)
{
BlockBackend *blk = blk_all_next(NULL);
test_quiesce_common(blk, BDRV_DRAIN, false);
}
static void test_quiesce_co_drain(void)
{
call_in_coroutine(test_quiesce_drain);
BlockBackend *blk = test_setup();
call_in_coroutine(test_quiesce_co_drain_entry);
blk_unref(blk);
}
static void test_nested(void)