diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2023-02-20 13:39:18 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2023-02-20 13:39:18 +0000 |
commit | 2d89cb1fe5c778f51b5fdc6878adacdb0d908949 (patch) | |
tree | e3b0b88e9b4ac29d4f5b894511bed8728fbfd7da | |
parent | d8d20b38ec5875b98cfdae52c1f2132540cd65b5 (diff) | |
parent | a4d5224c2cb650b5a401d626d3f36e42e6987aa7 (diff) |
Merge tag 'for-upstream' of https://repo.or.cz/qemu/kevin into staging
Block layer patches
- configure: Enable -Wthread-safety if present
- no_co_wrapper to fix bdrv_open*() calls from coroutine context
- curl fixes, including enablement of newer libcurl versions
- MAINTAINERS: drop Vladimir from parallels block driver
- hbitmap: fix hbitmap_status() return value for first dirty bit case
- file-posix: Fix assertion failure in write_zeroes after moving
bdrv_getlength() to co_wrapper
# -----BEGIN PGP SIGNATURE-----
#
# iQJFBAABCAAvFiEE3D3rFZqa+V09dFb+fwmycsiPL9YFAmPvgm0RHGt3b2xmQHJl
# ZGhhdC5jb20ACgkQfwmycsiPL9ZxQg//ZWwwh/s/P1PnKAjInNZZNklAWKThNEbZ
# cF1S94w26IhEQqM0i6MflqcDsPU5t4xZtBUOizx++9M4G8amWnomJSdczUcKULla
# Az9yweFC1Gu6ENdw+ql5VOzCfpdH5Bn9Jkly5fxuI4vmnBz1PH1Dnd3P4wuLq2sL
# xna5dijVEhRc5mTKWjbp4nFfvQhucuEBPSNjgnZwEPbhciWxTMmB1GmyRvTxZy8v
# UY8PcoTlxdKeVQ6DTmkOirphpGj7HeNCEQnZppWs7vHys2oGi9kmR5qTKUNZxGrY
# 8yWiCiVDqbb50fhEC1srhph79bCij87QC1N33Bm+NuGjnjG4bKVx2B9DC8+6S/JS
# e3x6u+r0dd6/t0rjKnt1+inYqmM+i5lBJ7+R0yhWUQ+DYkvttNf5yiotD8qvccWJ
# Kcx14lfjPLK7siAMEY5K0bNMimhN4RR9oCLoPTOHei+vlxdfiMm2XPN61NNht5gD
# lYZ8JMBsEF/o2ebqTgsJrIHS+Q/8MqcwSunBc54fcXZoF+eiza3W2ArXLNfAEfGE
# U4JowNK2PrTIrpEjD+Vs0RsBBSmN5PcYIAz04ioODpDnYMq73/t3x9MKdVoxOT64
# AM7w58fSyWu8iwvkeA0d3XeVtSHFqZ49PqqIem4IegtnC/AXMUNrJ/VT99xHjeJY
# oLhOJz7LUg0=
# =FtaA
# -----END PGP SIGNATURE-----
# gpg: Signature made Fri 17 Feb 2023 13:34:37 GMT
# gpg: using RSA key DC3DEB159A9AF95D3D7456FE7F09B272C88F2FD6
# gpg: issuer "kwolf@redhat.com"
# gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" [full]
# Primary key fingerprint: DC3D EB15 9A9A F95D 3D74 56FE 7F09 B272 C88F 2FD6
* tag 'for-upstream' of https://repo.or.cz/qemu/kevin: (22 commits)
hbitmap: fix hbitmap_status() return value for first dirty bit case
block/file-posix: don't use functions calling AIO_WAIT_WHILE in worker threads
MAINTAINERS: drop Vladimir from parallels block driver
block: temporarily hold the new AioContext of bs_top in bdrv_append()
block: Handle curl 7.55.0, 7.85.0 version changes
block: Assert non-coroutine context for bdrv_open_inherit()
block: Fix bdrv_co_create_opts_simple() to open images with no_co_wrapper
vpc: Fix .bdrv_co_create(_opts) to open images with no_co_wrapper
vmdk: Fix .bdrv_co_create(_opts) to open images with no_co_wrapper
vhdx: Fix .bdrv_co_create(_opts) to open images with no_co_wrapper
vdi: Fix .bdrv_co_create(_opts) to open images with no_co_wrapper
qed: Fix .bdrv_co_create(_opts) to open images with no_co_wrapper
qcow2: Fix open/create to open images with no_co_wrapper
qcow: Fix .bdrv_co_create(_opts) to open images with no_co_wrapper
parallels: Fix .bdrv_co_create(_opts) to open images with no_co_wrapper
luks: Fix .bdrv_co_create(_opts) to open images with no_co_wrapper
block: Create no_co_wrappers for open functions
block-coroutine-wrapper: Introduce no_co_wrapper
curl: Fix error path in curl_open()
configure: Enable -Wthread-safety if present
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | MAINTAINERS | 2 | ||||
-rw-r--r-- | block.c | 40 | ||||
-rw-r--r-- | block/crypto.c | 19 | ||||
-rw-r--r-- | block/curl.c | 50 | ||||
-rw-r--r-- | block/file-posix.c | 2 | ||||
-rw-r--r-- | block/meson.build | 1 | ||||
-rw-r--r-- | block/parallels.c | 10 | ||||
-rw-r--r-- | block/qcow.c | 10 | ||||
-rw-r--r-- | block/qcow2.c | 43 | ||||
-rw-r--r-- | block/qed.c | 10 | ||||
-rw-r--r-- | block/vdi.c | 10 | ||||
-rw-r--r-- | block/vhdx.c | 10 | ||||
-rw-r--r-- | block/vmdk.c | 22 | ||||
-rw-r--r-- | block/vpc.c | 10 | ||||
-rw-r--r-- | bsd-user/qemu.h | 5 | ||||
-rwxr-xr-x | configure | 1 | ||||
-rw-r--r-- | include/block/block-common.h | 14 | ||||
-rw-r--r-- | include/block/block-global-state.h | 35 | ||||
-rw-r--r-- | include/exec/exec-all.h | 5 | ||||
-rw-r--r-- | include/qemu/hbitmap.h | 2 | ||||
-rw-r--r-- | include/qemu/thread.h | 14 | ||||
-rw-r--r-- | include/sysemu/block-backend-global-state.h | 21 | ||||
-rw-r--r-- | scripts/block-coroutine-wrapper.py | 83 | ||||
-rw-r--r-- | util/hbitmap.c | 2 | ||||
-rw-r--r-- | util/qemu-thread-posix.c | 2 |
25 files changed, 295 insertions, 128 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 21595f0aad..869a4013be 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3579,13 +3579,11 @@ F: block/dmg.c parallels M: Stefan Hajnoczi <stefanha@redhat.com> M: Denis V. Lunev <den@openvz.org> -M: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> L: qemu-block@nongnu.org S: Supported F: block/parallels.c F: block/parallels-ext.c F: docs/interop/parallels.txt -T: git https://gitlab.com/vsementsov/qemu.git block qed M: Stefan Hajnoczi <stefanha@redhat.com> @@ -657,8 +657,8 @@ int coroutine_fn bdrv_co_create_opts_simple(BlockDriver *drv, options = qdict_new(); qdict_put_str(options, "driver", drv->format_name); - blk = blk_new_open(filename, NULL, options, - BDRV_O_RDWR | BDRV_O_RESIZE, errp); + blk = blk_co_new_open(filename, NULL, options, + BDRV_O_RDWR | BDRV_O_RESIZE, errp); if (!blk) { error_prepend(errp, "Protocol driver '%s' does not support image " "creation, and opening the image failed: ", @@ -3807,13 +3807,11 @@ out: * function eventually calls bdrv_refresh_total_sectors() which polls * when called from non-coroutine context. */ -static BlockDriverState *bdrv_open_inherit(const char *filename, - const char *reference, - QDict *options, int flags, - BlockDriverState *parent, - const BdrvChildClass *child_class, - BdrvChildRole child_role, - Error **errp) +static BlockDriverState * no_coroutine_fn +bdrv_open_inherit(const char *filename, const char *reference, QDict *options, + int flags, BlockDriverState *parent, + const BdrvChildClass *child_class, BdrvChildRole child_role, + Error **errp) { int ret; BlockBackend *file = NULL; @@ -3829,6 +3827,7 @@ static BlockDriverState *bdrv_open_inherit(const char *filename, assert(!child_class || !flags); assert(!child_class == !parent); GLOBAL_STATE_CODE(); + assert(!qemu_in_coroutine()); if (reference) { bool options_non_empty = options ? qdict_size(options) : false; @@ -5266,6 +5265,8 @@ int bdrv_drop_filter(BlockDriverState *bs, Error **errp) * child. * * This function does not create any image files. + * + * The caller must hold the AioContext lock for @bs_top. */ int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top, Error **errp) @@ -5273,11 +5274,14 @@ int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top, int ret; BdrvChild *child; Transaction *tran = tran_new(); + AioContext *old_context, *new_context = NULL; GLOBAL_STATE_CODE(); assert(!bs_new->backing); + old_context = bdrv_get_aio_context(bs_top); + child = bdrv_attach_child_noperm(bs_new, bs_top, "backing", &child_of_bds, bdrv_backing_role(bs_new), tran, errp); @@ -5286,6 +5290,19 @@ int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top, goto out; } + /* + * bdrv_attach_child_noperm could change the AioContext of bs_top. + * bdrv_replace_node_noperm calls bdrv_drained_begin, so let's temporarily + * hold the new AioContext, since bdrv_drained_begin calls BDRV_POLL_WHILE + * that assumes the new lock is taken. + */ + new_context = bdrv_get_aio_context(bs_top); + + if (old_context != new_context) { + aio_context_release(old_context); + aio_context_acquire(new_context); + } + ret = bdrv_replace_node_noperm(bs_top, bs_new, true, tran, errp); if (ret < 0) { goto out; @@ -5297,6 +5314,11 @@ out: bdrv_refresh_limits(bs_top, NULL, NULL); + if (new_context && old_context != new_context) { + aio_context_release(new_context); + aio_context_acquire(old_context); + } + return ret; } diff --git a/block/crypto.c b/block/crypto.c index b70cec97c7..72ac30568c 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -314,19 +314,18 @@ static int block_crypto_open_generic(QCryptoBlockFormat format, } -static int block_crypto_co_create_generic(BlockDriverState *bs, - int64_t size, - QCryptoBlockCreateOptions *opts, - PreallocMode prealloc, - Error **errp) +static int coroutine_fn +block_crypto_co_create_generic(BlockDriverState *bs, int64_t size, + QCryptoBlockCreateOptions *opts, + PreallocMode prealloc, Error **errp) { int ret; BlockBackend *blk; QCryptoBlock *crypto = NULL; struct BlockCryptoCreateData data; - blk = blk_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL, - errp); + blk = blk_co_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL, + errp); if (!blk) { ret = -EPERM; goto cleanup; @@ -639,7 +638,7 @@ block_crypto_co_create_luks(BlockdevCreateOptions *create_options, Error **errp) assert(create_options->driver == BLOCKDEV_DRIVER_LUKS); luks_opts = &create_options->u.luks; - bs = bdrv_open_blockdev_ref(luks_opts->file, errp); + bs = bdrv_co_open_blockdev_ref(luks_opts->file, errp); if (bs == NULL) { return -EIO; } @@ -708,8 +707,8 @@ static int coroutine_fn block_crypto_co_create_opts_luks(BlockDriver *drv, goto fail; } - bs = bdrv_open(filename, NULL, NULL, - BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp); + bs = bdrv_co_open(filename, NULL, NULL, + BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp); if (!bs) { ret = -EINVAL; goto fail; diff --git a/block/curl.c b/block/curl.c index cbada22e9e..8bb39a134e 100644 --- a/block/curl.c +++ b/block/curl.c @@ -38,8 +38,15 @@ // #define DEBUG_VERBOSE +/* CURL 7.85.0 switches to a string based API for specifying + * the desired protocols. + */ +#if LIBCURL_VERSION_NUM >= 0x075500 +#define PROTOCOLS "HTTP,HTTPS,FTP,FTPS" +#else #define PROTOCOLS (CURLPROTO_HTTP | CURLPROTO_HTTPS | \ CURLPROTO_FTP | CURLPROTO_FTPS) +#endif #define CURL_NUM_STATES 8 #define CURL_NUM_ACB 8 @@ -510,9 +517,18 @@ static int curl_init_state(BDRVCURLState *s, CURLState *state) * obscure protocols. For example, do not allow POP3/SMTP/IMAP see * CVE-2013-0249. * - * Restricting protocols is only supported from 7.19.4 upwards. + * Restricting protocols is only supported from 7.19.4 upwards. Note: + * version 7.85.0 deprecates CURLOPT_*PROTOCOLS in favour of a string + * based CURLOPT_*PROTOCOLS_STR API. */ -#if LIBCURL_VERSION_NUM >= 0x071304 +#if LIBCURL_VERSION_NUM >= 0x075500 + if (curl_easy_setopt(state->curl, + CURLOPT_PROTOCOLS_STR, PROTOCOLS) || + curl_easy_setopt(state->curl, + CURLOPT_REDIR_PROTOCOLS_STR, PROTOCOLS)) { + goto err; + } +#elif LIBCURL_VERSION_NUM >= 0x071304 if (curl_easy_setopt(state->curl, CURLOPT_PROTOCOLS, PROTOCOLS) || curl_easy_setopt(state->curl, CURLOPT_REDIR_PROTOCOLS, PROTOCOLS)) { goto err; @@ -670,7 +686,12 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags, const char *file; const char *cookie; const char *cookie_secret; - double d; + /* CURL >= 7.55.0 uses curl_off_t for content length instead of a double */ +#if LIBCURL_VERSION_NUM >= 0x073700 + curl_off_t cl; +#else + double cl; +#endif const char *secretid; const char *protocol_delimiter; int ret; @@ -797,27 +818,36 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags, } if (curl_easy_perform(state->curl)) goto out; - if (curl_easy_getinfo(state->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d)) { + /* CURL 7.55.0 deprecates CURLINFO_CONTENT_LENGTH_DOWNLOAD in favour of + * the *_T version which returns a more sensible type for content length. + */ +#if LIBCURL_VERSION_NUM >= 0x073700 + if (curl_easy_getinfo(state->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &cl)) { goto out; } +#else + if (curl_easy_getinfo(state->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &cl)) { + goto out; + } +#endif /* Prior CURL 7.19.4 return value of 0 could mean that the file size is not * know or the size is zero. From 7.19.4 CURL returns -1 if size is not * known and zero if it is really zero-length file. */ #if LIBCURL_VERSION_NUM >= 0x071304 - if (d < 0) { + if (cl < 0) { pstrcpy(state->errmsg, CURL_ERROR_SIZE, "Server didn't report file size."); goto out; } #else - if (d <= 0) { + if (cl <= 0) { pstrcpy(state->errmsg, CURL_ERROR_SIZE, "Unknown file size or zero-length file."); goto out; } #endif - s->len = d; + s->len = cl; if ((!strncasecmp(s->url, "http://", strlen("http://")) || !strncasecmp(s->url, "https://", strlen("https://"))) @@ -850,8 +880,10 @@ out_noclean: g_free(s->username); g_free(s->proxyusername); g_free(s->proxypassword); - curl_drop_all_sockets(s->sockets); - g_hash_table_destroy(s->sockets); + if (s->sockets) { + curl_drop_all_sockets(s->sockets); + g_hash_table_destroy(s->sockets); + } qemu_opts_del(opts); return -EINVAL; } diff --git a/block/file-posix.c b/block/file-posix.c index d3073a7caa..9a99111f45 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -1738,7 +1738,7 @@ static int handle_aiocb_write_zeroes(void *opaque) #ifdef CONFIG_FALLOCATE /* Last resort: we are trying to extend the file with zeroed data. This * can be done via fallocate(fd, 0) */ - len = bdrv_getlength(aiocb->bs); + len = raw_co_getlength(aiocb->bs); if (s->has_fallocate && len >= 0 && aiocb->aio_offset >= len) { int ret = do_fallocate(s->fd, 0, aiocb->aio_offset, aiocb->aio_nbytes); if (ret == 0 || ret != -ENOTSUP) { diff --git a/block/meson.build b/block/meson.build index 3662852dc2..382bec0e7d 100644 --- a/block/meson.build +++ b/block/meson.build @@ -141,6 +141,7 @@ block_gen_c = custom_target('block-gen.c', '../include/block/dirty-bitmap.h', '../include/block/block_int-io.h', '../include/block/block-global-state.h', + '../include/sysemu/block-backend-global-state.h', '../include/sysemu/block-backend-io.h', 'coroutines.h' ), diff --git a/block/parallels.c b/block/parallels.c index bbea2f2221..d4378e09de 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -565,13 +565,13 @@ static int coroutine_fn parallels_co_create(BlockdevCreateOptions* opts, } /* Create BlockBackend to write to the image */ - bs = bdrv_open_blockdev_ref(parallels_opts->file, errp); + bs = bdrv_co_open_blockdev_ref(parallels_opts->file, errp); if (bs == NULL) { return -EIO; } - blk = blk_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL, - errp); + blk = blk_co_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL, + errp); if (!blk) { ret = -EPERM; goto out; @@ -651,8 +651,8 @@ static int coroutine_fn parallels_co_create_opts(BlockDriver *drv, goto done; } - bs = bdrv_open(filename, NULL, NULL, - BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp); + bs = bdrv_co_open(filename, NULL, NULL, + BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp); if (bs == NULL) { ret = -EIO; goto done; diff --git a/block/qcow.c b/block/qcow.c index 5f0801f545..20c53b447b 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -833,13 +833,13 @@ static int coroutine_fn qcow_co_create(BlockdevCreateOptions *opts, } /* Create BlockBackend to write to the image */ - bs = bdrv_open_blockdev_ref(qcow_opts->file, errp); + bs = bdrv_co_open_blockdev_ref(qcow_opts->file, errp); if (bs == NULL) { return -EIO; } - qcow_blk = blk_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, - BLK_PERM_ALL, errp); + qcow_blk = blk_co_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, + BLK_PERM_ALL, errp); if (!qcow_blk) { ret = -EPERM; goto exit; @@ -978,8 +978,8 @@ static int coroutine_fn qcow_co_create_opts(BlockDriver *drv, goto fail; } - bs = bdrv_open(filename, NULL, NULL, - BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp); + bs = bdrv_co_open(filename, NULL, NULL, + BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp); if (bs == NULL) { ret = -EIO; goto fail; diff --git a/block/qcow2.c b/block/qcow2.c index 21aa4c6b7a..ee0e5b45cc 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1617,9 +1617,9 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, if (open_data_file) { /* Open external data file */ - s->data_file = bdrv_open_child(NULL, options, "data-file", bs, - &child_of_bds, BDRV_CHILD_DATA, - true, errp); + s->data_file = bdrv_co_open_child(NULL, options, "data-file", bs, + &child_of_bds, BDRV_CHILD_DATA, + true, errp); if (*errp) { ret = -EINVAL; goto fail; @@ -1627,9 +1627,10 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, if (s->incompatible_features & QCOW2_INCOMPAT_DATA_FILE) { if (!s->data_file && s->image_data_file) { - s->data_file = bdrv_open_child(s->image_data_file, options, - "data-file", bs, &child_of_bds, - BDRV_CHILD_DATA, false, errp); + s->data_file = bdrv_co_open_child(s->image_data_file, options, + "data-file", bs, + &child_of_bds, + BDRV_CHILD_DATA, false, errp); if (!s->data_file) { ret = -EINVAL; goto fail; @@ -3454,7 +3455,7 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) assert(create_options->driver == BLOCKDEV_DRIVER_QCOW2); qcow2_opts = &create_options->u.qcow2; - bs = bdrv_open_blockdev_ref(qcow2_opts->file, errp); + bs = bdrv_co_open_blockdev_ref(qcow2_opts->file, errp); if (bs == NULL) { return -EIO; } @@ -3596,7 +3597,7 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) ret = -EINVAL; goto out; } - data_bs = bdrv_open_blockdev_ref(qcow2_opts->data_file, errp); + data_bs = bdrv_co_open_blockdev_ref(qcow2_opts->data_file, errp); if (data_bs == NULL) { ret = -EIO; goto out; @@ -3629,8 +3630,8 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) } /* Create BlockBackend to write to the image */ - blk = blk_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL, - errp); + blk = blk_co_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL, + errp); if (!blk) { ret = -EPERM; goto out; @@ -3712,9 +3713,9 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) if (data_bs) { qdict_put_str(options, "data-file", data_bs->node_name); } - blk = blk_new_open(NULL, NULL, options, - BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_NO_FLUSH, - errp); + blk = blk_co_new_open(NULL, NULL, options, + BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_NO_FLUSH, + errp); if (blk == NULL) { ret = -EIO; goto out; @@ -3793,9 +3794,9 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) if (data_bs) { qdict_put_str(options, "data-file", data_bs->node_name); } - blk = blk_new_open(NULL, NULL, options, - BDRV_O_RDWR | BDRV_O_NO_BACKING | BDRV_O_NO_IO, - errp); + blk = blk_co_new_open(NULL, NULL, options, + BDRV_O_RDWR | BDRV_O_NO_BACKING | BDRV_O_NO_IO, + errp); if (blk == NULL) { ret = -EIO; goto out; @@ -3877,8 +3878,8 @@ static int coroutine_fn qcow2_co_create_opts(BlockDriver *drv, goto finish; } - bs = bdrv_open(filename, NULL, NULL, - BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp); + bs = bdrv_co_open(filename, NULL, NULL, + BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp); if (bs == NULL) { ret = -EIO; goto finish; @@ -3892,9 +3893,9 @@ static int coroutine_fn qcow2_co_create_opts(BlockDriver *drv, goto finish; } - data_bs = bdrv_open(val, NULL, NULL, - BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, - errp); + data_bs = bdrv_co_open(val, NULL, NULL, + BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, + errp); if (data_bs == NULL) { ret = -EIO; goto finish; diff --git a/block/qed.c b/block/qed.c index 4473465bba..175a46c67b 100644 --- a/block/qed.c +++ b/block/qed.c @@ -676,13 +676,13 @@ static int coroutine_fn bdrv_qed_co_create(BlockdevCreateOptions *opts, } /* Create BlockBackend to write to the image */ - bs = bdrv_open_blockdev_ref(qed_opts->file, errp); + bs = bdrv_co_open_blockdev_ref(qed_opts->file, errp); if (bs == NULL) { return -EIO; } - blk = blk_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL, - errp); + blk = blk_co_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL, + errp); if (!blk) { ret = -EPERM; goto out; @@ -783,8 +783,8 @@ static int coroutine_fn bdrv_qed_co_create_opts(BlockDriver *drv, goto fail; } - bs = bdrv_open(filename, NULL, NULL, - BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp); + bs = bdrv_co_open(filename, NULL, NULL, + BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp); if (bs == NULL) { ret = -EIO; goto fail; diff --git a/block/vdi.c b/block/vdi.c index 9c8736b26f..27db67d493 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -800,14 +800,14 @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options, } /* Create BlockBackend to write to the image */ - bs_file = bdrv_open_blockdev_ref(vdi_opts->file, errp); + bs_file = bdrv_co_open_blockdev_ref(vdi_opts->file, errp); if (!bs_file) { ret = -EIO; goto exit; } - blk = blk_new_with_bs(bs_file, BLK_PERM_WRITE | BLK_PERM_RESIZE, - BLK_PERM_ALL, errp); + blk = blk_co_new_with_bs(bs_file, BLK_PERM_WRITE | BLK_PERM_RESIZE, + BLK_PERM_ALL, errp); if (!blk) { ret = -EPERM; goto exit; @@ -940,8 +940,8 @@ static int coroutine_fn vdi_co_create_opts(BlockDriver *drv, goto done; } - bs_file = bdrv_open(filename, NULL, NULL, - BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp); + bs_file = bdrv_co_open(filename, NULL, NULL, + BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp); if (!bs_file) { ret = -EIO; goto done; diff --git a/block/vhdx.c b/block/vhdx.c index ef1f65d917..59fbdb413b 100644 --- a/block/vhdx.c +++ b/block/vhdx.c @@ -1991,13 +1991,13 @@ static int coroutine_fn vhdx_co_create(BlockdevCreateOptions *opts, } /* Create BlockBackend to write to the image */ - bs = bdrv_open_blockdev_ref(vhdx_opts->file, errp); + bs = bdrv_co_open_blockdev_ref(vhdx_opts->file, errp); if (bs == NULL) { return -EIO; } - blk = blk_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL, - errp); + blk = blk_co_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL, + errp); if (!blk) { ret = -EPERM; goto delete_and_exit; @@ -2090,8 +2090,8 @@ static int coroutine_fn vhdx_co_create_opts(BlockDriver *drv, goto fail; } - bs = bdrv_open(filename, NULL, NULL, - BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp); + bs = bdrv_co_open(filename, NULL, NULL, + BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp); if (bs == NULL) { ret = -EIO; goto fail; diff --git a/block/vmdk.c b/block/vmdk.c index 5b0eae877e..171c9272ca 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -2299,9 +2299,9 @@ static int coroutine_fn vmdk_create_extent(const char *filename, goto exit; } - blk = blk_new_open(filename, NULL, NULL, - BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, - errp); + blk = blk_co_new_open(filename, NULL, NULL, + BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, + errp); if (blk == NULL) { ret = -EIO; goto exit; @@ -2518,8 +2518,8 @@ static int coroutine_fn vmdk_co_do_create(int64_t size, } assert(full_backing); - backing = blk_new_open(full_backing, NULL, NULL, - BDRV_O_NO_BACKING, errp); + backing = blk_co_new_open(full_backing, NULL, NULL, + BDRV_O_NO_BACKING, errp); g_free(full_backing); if (backing == NULL) { ret = -EIO; @@ -2781,7 +2781,7 @@ static BlockBackend * coroutine_fn vmdk_co_create_cb(int64_t size, int idx, BlockdevCreateOptionsVmdk *opts = opaque; if (idx == 0) { - bs = bdrv_open_blockdev_ref(opts->file, errp); + bs = bdrv_co_open_blockdev_ref(opts->file, errp); } else { int i; BlockdevRefList *list = opts->extents; @@ -2796,14 +2796,16 @@ static BlockBackend * coroutine_fn vmdk_co_create_cb(int64_t size, int idx, error_setg(errp, "Extent [%d] not specified", idx - 1); return NULL; } - bs = bdrv_open_blockdev_ref(list->value, errp); + bs = bdrv_co_open_blockdev_ref(list->value, errp); } if (!bs) { return NULL; } - blk = blk_new_with_bs(bs, - BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE | BLK_PERM_RESIZE, - BLK_PERM_ALL, errp); + blk = blk_co_new_with_bs(bs, + BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE | + BLK_PERM_RESIZE, + BLK_PERM_ALL, + errp); if (!blk) { return NULL; } diff --git a/block/vpc.c b/block/vpc.c index cfdea7db80..3c256fc5a4 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -1005,13 +1005,13 @@ static int coroutine_fn vpc_co_create(BlockdevCreateOptions *opts, } /* Create BlockBackend to write to the image */ - bs = bdrv_open_blockdev_ref(vpc_opts->file, errp); + bs = bdrv_co_open_blockdev_ref(vpc_opts->file, errp); if (bs == NULL) { return -EIO; } - blk = blk_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL, - errp); + blk = blk_co_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL, + errp); if (!blk) { ret = -EPERM; goto out; @@ -1117,8 +1117,8 @@ static int coroutine_fn vpc_co_create_opts(BlockDriver *drv, goto fail; } - bs = bdrv_open(filename, NULL, NULL, - BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp); + bs = bdrv_co_open(filename, NULL, NULL, + BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp); if (bs == NULL) { ret = -EIO; goto fail; diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index 0ceecfb6df..4e7b8b1c06 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -36,6 +36,7 @@ extern char **environ; #include "target_os_signal.h" #include "target.h" #include "exec/gdbstub.h" +#include "qemu/clang-tsa.h" /* * This struct is used to hold certain information about the image. Basically, @@ -234,8 +235,8 @@ int target_msync(abi_ulong start, abi_ulong len, int flags); extern unsigned long last_brk; extern abi_ulong mmap_next_start; abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size); -void mmap_fork_start(void); -void mmap_fork_end(int child); +void TSA_NO_TSA mmap_fork_start(void); +void TSA_NO_TSA mmap_fork_end(int child); /* main.c */ extern char qemu_proc_pathname[]; @@ -1184,6 +1184,7 @@ add_to warn_flags -Wendif-labels add_to warn_flags -Wexpansion-to-defined add_to warn_flags -Wimplicit-fallthrough=2 add_to warn_flags -Wmissing-format-attribute +add_to warn_flags -Wthread-safety nowarn_flags= add_to nowarn_flags -Wno-initializer-overrides diff --git a/include/block/block-common.h b/include/block/block-common.h index 469300fe8d..b5122ef8ab 100644 --- a/include/block/block-common.h +++ b/include/block/block-common.h @@ -54,6 +54,20 @@ #define co_wrapper_bdrv_rdlock no_coroutine_fn #define co_wrapper_mixed_bdrv_rdlock no_coroutine_fn coroutine_mixed_fn +/* + * no_co_wrapper: Function specifier used by block-coroutine-wrapper.py + * + * Function specifier which does nothing but mark functions to be generated by + * scripts/block-coroutine-wrapper.py. + * + * A no_co_wrapper function declaration creates a coroutine_fn wrapper around + * functions that must not be called in coroutine context. It achieves this by + * scheduling a BH in the bottom half that runs the respective non-coroutine + * function. The coroutine yields after scheduling the BH and is reentered when + * the wrapped function returns. + */ +#define no_co_wrapper + #include "block/blockjob.h" /* block.c */ diff --git a/include/block/block-global-state.h b/include/block/block-global-state.h index a38f86dc15..447176414e 100644 --- a/include/block/block-global-state.h +++ b/include/block/block-global-state.h @@ -77,16 +77,26 @@ BlockDriverState *bdrv_insert_node(BlockDriverState *bs, QDict *node_options, int flags, Error **errp); int bdrv_drop_filter(BlockDriverState *bs, Error **errp); -BdrvChild *bdrv_open_child(const char *filename, - QDict *options, const char *bdref_key, - BlockDriverState *parent, - const BdrvChildClass *child_class, - BdrvChildRole child_role, - bool allow_none, Error **errp); +BdrvChild * no_coroutine_fn +bdrv_open_child(const char *filename, QDict *options, const char *bdref_key, + BlockDriverState *parent, const BdrvChildClass *child_class, + BdrvChildRole child_role, bool allow_none, Error **errp); + +BdrvChild * coroutine_fn no_co_wrapper +bdrv_co_open_child(const char *filename, QDict *options, const char *bdref_key, + BlockDriverState *parent, const BdrvChildClass *child_class, + BdrvChildRole child_role, bool allow_none, Error **errp); + int bdrv_open_file_child(const char *filename, QDict *options, const char *bdref_key, BlockDriverState *parent, Error **errp); -BlockDriverState *bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp); + +BlockDriverState * no_coroutine_fn +bdrv_open_blockdev_ref(BlockdevRef *ref, Error **errp); + +BlockDriverState * coroutine_fn no_co_wrapper +bdrv_co_open_blockdev_ref(BlockdevRef *ref, Error **errp); + int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd, Error **errp); int bdrv_set_backing_hd_drained(BlockDriverState *bs, @@ -94,8 +104,15 @@ int bdrv_set_backing_hd_drained(BlockDriverState *bs, Error **errp); int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options, const char *bdref_key, Error **errp); -BlockDriverState *bdrv_open(const char *filename, const char *reference, - QDict *options, int flags, Error **errp); + +BlockDriverState * no_coroutine_fn +bdrv_open(const char *filename, const char *reference, QDict *options, + int flags, Error **errp); + +BlockDriverState * coroutine_fn no_co_wrapper +bdrv_co_open(const char *filename, const char *reference, + QDict *options, int flags, Error **errp); + BlockDriverState *bdrv_new_open_driver_opts(BlockDriver *drv, const char *node_name, QDict *options, int flags, diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 54585a9954..0e36f4d063 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -25,6 +25,7 @@ #include "exec/cpu_ldst.h" #endif #include "qemu/interval-tree.h" +#include "qemu/clang-tsa.h" /* allow to see translation results - the slowdown should be negligible, so we leave it */ #define DEBUG_DISAS @@ -759,8 +760,8 @@ static inline tb_page_addr_t get_page_addr_code(CPUArchState *env, } #if defined(CONFIG_USER_ONLY) -void mmap_lock(void); -void mmap_unlock(void); +void TSA_NO_TSA mmap_lock(void); +void TSA_NO_TSA mmap_unlock(void); bool have_mmap_lock(void); /** diff --git a/include/qemu/hbitmap.h b/include/qemu/hbitmap.h index af4e4ab746..8136e33674 100644 --- a/include/qemu/hbitmap.h +++ b/include/qemu/hbitmap.h @@ -330,7 +330,7 @@ bool hbitmap_next_dirty_area(const HBitmap *hb, int64_t start, int64_t end, int64_t *dirty_start, int64_t *dirty_count); /* - * bdrv_dirty_bitmap_status: + * hbitmap_status: * @hb: The HBitmap to operate on * @start: The bit to start from * @count: Number of bits to proceed diff --git a/include/qemu/thread.h b/include/qemu/thread.h index 7841084199..dd3822d7ce 100644 --- a/include/qemu/thread.h +++ b/include/qemu/thread.h @@ -3,6 +3,7 @@ #include "qemu/processor.h" #include "qemu/atomic.h" +#include "qemu/clang-tsa.h" typedef struct QemuCond QemuCond; typedef struct QemuSemaphore QemuSemaphore; @@ -24,9 +25,12 @@ typedef struct QemuThread QemuThread; void qemu_mutex_init(QemuMutex *mutex); void qemu_mutex_destroy(QemuMutex *mutex); -int qemu_mutex_trylock_impl(QemuMutex *mutex, const char *file, const int line); -void qemu_mutex_lock_impl(QemuMutex *mutex, const char *file, const int line); -void qemu_mutex_unlock_impl(QemuMutex *mutex, const char *file, const int line); +int TSA_NO_TSA qemu_mutex_trylock_impl(QemuMutex *mutex, const char *file, + const int line); +void TSA_NO_TSA qemu_mutex_lock_impl(QemuMutex *mutex, const char *file, + const int line); +void TSA_NO_TSA qemu_mutex_unlock_impl(QemuMutex *mutex, const char *file, + const int line); void qemu_rec_mutex_init(QemuRecMutex *mutex); void qemu_rec_mutex_destroy(QemuRecMutex *mutex); @@ -153,8 +157,8 @@ void qemu_cond_destroy(QemuCond *cond); */ void qemu_cond_signal(QemuCond *cond); void qemu_cond_broadcast(QemuCond *cond); -void qemu_cond_wait_impl(QemuCond *cond, QemuMutex *mutex, - const char *file, const int line); +void TSA_NO_TSA qemu_cond_wait_impl(QemuCond *cond, QemuMutex *mutex, + const char *file, const int line); bool qemu_cond_timedwait_impl(QemuCond *cond, QemuMutex *mutex, int ms, const char *file, const int line); diff --git a/include/sysemu/block-backend-global-state.h b/include/sysemu/block-backend-global-state.h index 6858e39cb6..2b6d27db7c 100644 --- a/include/sysemu/block-backend-global-state.h +++ b/include/sysemu/block-backend-global-state.h @@ -23,10 +23,23 @@ */ BlockBackend *blk_new(AioContext *ctx, uint64_t perm, uint64_t shared_perm); -BlockBackend *blk_new_with_bs(BlockDriverState *bs, uint64_t perm, - uint64_t shared_perm, Error **errp); -BlockBackend *blk_new_open(const char *filename, const char *reference, - QDict *options, int flags, Error **errp); + +BlockBackend * no_coroutine_fn +blk_new_with_bs(BlockDriverState *bs, uint64_t perm, uint64_t shared_perm, + Error **errp); + +BlockBackend * coroutine_fn no_co_wrapper +blk_co_new_with_bs(BlockDriverState *bs, uint64_t perm, uint64_t shared_perm, + Error **errp); + +BlockBackend * no_coroutine_fn +blk_new_open(const char *filename, const char *reference, QDict *options, + int flags, Error **errp); + +BlockBackend * coroutine_fn no_co_wrapper +blk_co_new_open(const char *filename, const char *reference, QDict *options, + int flags, Error **errp); + int blk_get_refcnt(BlockBackend *blk); void blk_ref(BlockBackend *blk); void blk_unref(BlockBackend *blk); diff --git a/scripts/block-coroutine-wrapper.py b/scripts/block-coroutine-wrapper.py index e82b648127..60e9b3107c 100644 --- a/scripts/block-coroutine-wrapper.py +++ b/scripts/block-coroutine-wrapper.py @@ -63,8 +63,8 @@ class ParamDecl: class FuncDecl: - def __init__(self, return_type: str, name: str, args: str, - variant: str) -> None: + def __init__(self, wrapper_type: str, return_type: str, name: str, + args: str, variant: str) -> None: self.return_type = return_type.strip() self.name = name.strip() self.struct_name = snake_to_camel(self.name) @@ -72,8 +72,21 @@ class FuncDecl: self.create_only_co = 'mixed' not in variant self.graph_rdlock = 'bdrv_rdlock' in variant - subsystem, subname = self.name.split('_', 1) - self.co_name = f'{subsystem}_co_{subname}' + self.wrapper_type = wrapper_type + + if wrapper_type == 'co': + subsystem, subname = self.name.split('_', 1) + self.target_name = f'{subsystem}_co_{subname}' + else: + assert wrapper_type == 'no_co' + subsystem, co_infix, subname = self.name.split('_', 2) + if co_infix != 'co': + raise ValueError(f"Invalid no_co function name: {self.name}") + if not self.create_only_co: + raise ValueError(f"no_co function can't be mixed: {self.name}") + if self.graph_rdlock: + raise ValueError(f"no_co function can't be rdlock: {self.name}") + self.target_name = f'{subsystem}_{subname}' t = self.args[0].type if t == 'BlockDriverState *': @@ -105,7 +118,8 @@ class FuncDecl: # Match wrappers declared with a co_wrapper mark func_decl_re = re.compile(r'^(?P<return_type>[a-zA-Z][a-zA-Z0-9_]* [\*]?)' - r'\s*co_wrapper' + r'(\s*coroutine_fn)?' + r'\s*(?P<wrapper_type>(no_)?co)_wrapper' r'(?P<variant>(_[a-z][a-z0-9_]*)?)\s*' r'(?P<wrapper_name>[a-z][a-z0-9_]*)' r'\((?P<args>[^)]*)\);$', re.MULTILINE) @@ -113,7 +127,8 @@ func_decl_re = re.compile(r'^(?P<return_type>[a-zA-Z][a-zA-Z0-9_]* [\*]?)' def func_decl_iter(text: str) -> Iterator: for m in func_decl_re.finditer(text): - yield FuncDecl(return_type=m.group('return_type'), + yield FuncDecl(wrapper_type=m.group('wrapper_type'), + return_type=m.group('return_type'), name=m.group('wrapper_name'), args=m.group('args'), variant=m.group('variant')) @@ -133,7 +148,7 @@ def create_mixed_wrapper(func: FuncDecl) -> str: """ Checks if we are already in coroutine """ - name = func.co_name + name = func.target_name struct_name = func.struct_name graph_assume_lock = 'assume_graph_lock();' if func.graph_rdlock else '' @@ -163,7 +178,7 @@ def create_co_wrapper(func: FuncDecl) -> str: """ Assumes we are not in coroutine, and creates one """ - name = func.co_name + name = func.target_name struct_name = func.struct_name return f"""\ {func.return_type} {func.name}({ func.gen_list('{decl}') }) @@ -183,10 +198,11 @@ def create_co_wrapper(func: FuncDecl) -> str: }}""" -def gen_wrapper(func: FuncDecl) -> str: +def gen_co_wrapper(func: FuncDecl) -> str: assert not '_co_' in func.name + assert func.wrapper_type == 'co' - name = func.co_name + name = func.target_name struct_name = func.struct_name graph_lock='' @@ -225,11 +241,56 @@ static void coroutine_fn {name}_entry(void *opaque) {creation_function(func)}""" +def gen_no_co_wrapper(func: FuncDecl) -> str: + assert '_co_' in func.name + assert func.wrapper_type == 'no_co' + + name = func.target_name + struct_name = func.struct_name + + return f"""\ +/* + * Wrappers for {name} + */ + +typedef struct {struct_name} {{ + Coroutine *co; + {func.return_field} +{ func.gen_block(' {decl};') } +}} {struct_name}; + +static void {name}_bh(void *opaque) +{{ + {struct_name} *s = opaque; + + {func.get_result}{name}({ func.gen_list('s->{name}') }); + + aio_co_wake(s->co); +}} + +{func.return_type} coroutine_fn {func.name}({ func.gen_list('{decl}') }) +{{ + {struct_name} s = {{ + .co = qemu_coroutine_self(), +{ func.gen_block(' .{name} = {name},') } + }}; + assert(qemu_in_coroutine()); + + aio_bh_schedule_oneshot(qemu_get_aio_context(), {name}_bh, &s); + qemu_coroutine_yield(); + + {func.ret} +}}""" + + def gen_wrappers(input_code: str) -> str: res = '' for func in func_decl_iter(input_code): res += '\n\n\n' - res += gen_wrapper(func) + if func.wrapper_type == 'co': + res += gen_co_wrapper(func) + else: + res += gen_no_co_wrapper(func) return res diff --git a/util/hbitmap.c b/util/hbitmap.c index 297db35fb1..6d6e1b595d 100644 --- a/util/hbitmap.c +++ b/util/hbitmap.c @@ -331,7 +331,7 @@ bool hbitmap_status(const HBitmap *hb, int64_t start, int64_t count, assert(next_zero > start); *pnum = next_zero - start; - return false; + return true; } bool hbitmap_empty(const HBitmap *hb) diff --git a/util/qemu-thread-posix.c b/util/qemu-thread-posix.c index bae938c670..2dd1069cd3 100644 --- a/util/qemu-thread-posix.c +++ b/util/qemu-thread-posix.c @@ -223,7 +223,7 @@ void qemu_cond_wait_impl(QemuCond *cond, QemuMutex *mutex, const char *file, con error_exit(err, __func__); } -static bool +static bool TSA_NO_TSA qemu_cond_timedwait_ts(QemuCond *cond, QemuMutex *mutex, struct timespec *ts, const char *file, const int line) { |