diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2019-02-26 19:04:47 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2019-02-26 19:04:47 +0000 |
commit | adf2e451f357e993f173ba9b4176dbf3e65fee7e (patch) | |
tree | a47e711a00afacbafaa685da880fbfce0a6da700 /block | |
parent | 86c7e2f4a93322a76afea5ee6806a83420d1dfea (diff) | |
parent | 1b967e9f348d48788a2ab481d45398b80ce71fa6 (diff) |
Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging
Block layer patches:
- Block graph change fixes (avoid loops, cope with non-tree graphs)
- bdrv_set_aio_context() related fixes
- HMP snapshot commands: Use only tag, not the ID to identify snapshots
- qmeu-img, commit: Error path fixes
- block/nvme: Build fix for gcc 9
- MAINTAINERS updates
- Fix various issues with bdrv_refresh_filename()
- Fix various iotests
- Include LUKS overhead in qemu-img measure for qcow2
- A fix for vmdk's image creation interface
# gpg: Signature made Mon 25 Feb 2019 14:18:15 GMT
# gpg: using RSA key 7F09B272C88F2FD6
# gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" [full]
# Primary key fingerprint: DC3D EB15 9A9A F95D 3D74 56FE 7F09 B272 C88F 2FD6
* remotes/kevin/tags/for-upstream: (71 commits)
iotests: Skip 211 on insufficient memory
vmdk: false positive of compat6 with hwversion not set
iotests: add LUKS payload overhead to 178 qemu-img measure test
qcow2: include LUKS payload overhead in qemu-img measure
iotests.py: s/_/-/g on keys in qmp_log()
iotests: Let 045 be run concurrently
iotests: Filter SSH paths
iotests.py: Filter filename in any string value
iotests.py: Add is_str()
iotests: Fix 207 to use QMP filters for qmp_log
iotests: Fix 232 for LUKS
iotests: Remove superfluous rm from 232
iotests: Fix 237 for Python 2.x
iotests: Re-add filename filters
iotests: Test json:{} filenames of internal BDSs
block: BDS options may lack the "driver" option
block/null: Generate filename even with latency-ns
block/curl: Implement bdrv_refresh_filename()
block/curl: Harmonize option defaults
block/nvme: Fix bdrv_refresh_filename()
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'block')
-rw-r--r-- | block/blkdebug.c | 70 | ||||
-rw-r--r-- | block/blklogwrites.c | 33 | ||||
-rw-r--r-- | block/blkverify.c | 29 | ||||
-rw-r--r-- | block/block-backend.c | 4 | ||||
-rw-r--r-- | block/commit.c | 7 | ||||
-rw-r--r-- | block/crypto.c | 8 | ||||
-rw-r--r-- | block/curl.c | 55 | ||||
-rw-r--r-- | block/gluster.c | 19 | ||||
-rw-r--r-- | block/iscsi.c | 18 | ||||
-rw-r--r-- | block/mirror.c | 3 | ||||
-rw-r--r-- | block/nbd-client.c | 36 | ||||
-rw-r--r-- | block/nbd-client.h | 1 | ||||
-rw-r--r-- | block/nbd.c | 46 | ||||
-rw-r--r-- | block/nfs.c | 54 | ||||
-rw-r--r-- | block/null.c | 32 | ||||
-rw-r--r-- | block/nvme.c | 29 | ||||
-rw-r--r-- | block/qapi.c | 16 | ||||
-rw-r--r-- | block/qcow.c | 14 | ||||
-rw-r--r-- | block/qcow2-cluster.c | 3 | ||||
-rw-r--r-- | block/qcow2-snapshot.c | 5 | ||||
-rw-r--r-- | block/qcow2.c | 89 | ||||
-rw-r--r-- | block/qed.c | 7 | ||||
-rw-r--r-- | block/quorum.c | 71 | ||||
-rw-r--r-- | block/raw-format.c | 11 | ||||
-rw-r--r-- | block/rbd.c | 14 | ||||
-rw-r--r-- | block/replication.c | 10 | ||||
-rw-r--r-- | block/sheepdog.c | 12 | ||||
-rw-r--r-- | block/snapshot.c | 25 | ||||
-rw-r--r-- | block/ssh.c | 12 | ||||
-rw-r--r-- | block/throttle.c | 7 | ||||
-rw-r--r-- | block/vhdx-log.c | 1 | ||||
-rw-r--r-- | block/vmdk.c | 46 | ||||
-rw-r--r-- | block/vpc.c | 7 | ||||
-rw-r--r-- | block/vvfat.c | 12 | ||||
-rw-r--r-- | block/vxhs.c | 11 |
35 files changed, 579 insertions, 238 deletions
diff --git a/block/blkdebug.c b/block/blkdebug.c index 0759452925..1ea835c2b9 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -811,51 +811,37 @@ static int64_t blkdebug_getlength(BlockDriverState *bs) return bdrv_getlength(bs->file->bs); } -static void blkdebug_refresh_filename(BlockDriverState *bs, QDict *options) +static void blkdebug_refresh_filename(BlockDriverState *bs) { BDRVBlkdebugState *s = bs->opaque; - QDict *opts; const QDictEntry *e; - bool force_json = false; - - for (e = qdict_first(options); e; e = qdict_next(options, e)) { - if (strcmp(qdict_entry_key(e), "config") && - strcmp(qdict_entry_key(e), "x-image")) - { - force_json = true; - break; - } - } + int ret; - if (force_json && !bs->file->bs->full_open_options) { - /* The config file cannot be recreated, so creating a plain filename - * is impossible */ + if (!bs->file->bs->exact_filename[0]) { return; } - if (!force_json && bs->file->bs->exact_filename[0]) { - int ret = snprintf(bs->exact_filename, sizeof(bs->exact_filename), - "blkdebug:%s:%s", s->config_file ?: "", - bs->file->bs->exact_filename); - if (ret >= sizeof(bs->exact_filename)) { - /* An overflow makes the filename unusable, so do not report any */ - bs->exact_filename[0] = 0; + for (e = qdict_first(bs->full_open_options); e; + e = qdict_next(bs->full_open_options, e)) + { + /* Real child options are under "image", but "x-image" may + * contain a filename */ + if (strcmp(qdict_entry_key(e), "config") && + strcmp(qdict_entry_key(e), "image") && + strcmp(qdict_entry_key(e), "x-image") && + strcmp(qdict_entry_key(e), "driver")) + { + return; } } - opts = qdict_new(); - qdict_put_str(opts, "driver", "blkdebug"); - - qdict_put(opts, "image", qobject_ref(bs->file->bs->full_open_options)); - - for (e = qdict_first(options); e; e = qdict_next(options, e)) { - if (strcmp(qdict_entry_key(e), "x-image")) { - qdict_put_obj(opts, qdict_entry_key(e), - qobject_ref(qdict_entry_value(e))); - } + ret = snprintf(bs->exact_filename, sizeof(bs->exact_filename), + "blkdebug:%s:%s", + s->config_file ?: "", bs->file->bs->exact_filename); + if (ret >= sizeof(bs->exact_filename)) { + /* An overflow makes the filename unusable, so do not report any */ + bs->exact_filename[0] = 0; } - - bs->full_open_options = opts; } static void blkdebug_refresh_limits(BlockDriverState *bs, Error **errp) @@ -888,6 +874,20 @@ static int blkdebug_reopen_prepare(BDRVReopenState *reopen_state, return 0; } +static const char *const blkdebug_strong_runtime_opts[] = { + "config", + "inject-error.", + "set-state.", + "align", + "max-transfer", + "opt-write-zero", + "max-write-zero", + "opt-discard", + "max-discard", + + NULL +}; + static BlockDriver bdrv_blkdebug = { .format_name = "blkdebug", .protocol_name = "blkdebug", @@ -917,6 +917,8 @@ static BlockDriver bdrv_blkdebug = { = blkdebug_debug_remove_breakpoint, .bdrv_debug_resume = blkdebug_debug_resume, .bdrv_debug_is_suspended = blkdebug_debug_is_suspended, + + .strong_runtime_opts = blkdebug_strong_runtime_opts, }; static void bdrv_blkdebug_init(void) diff --git a/block/blklogwrites.c b/block/blklogwrites.c index d2e01bdb1d..eb2b4901a5 100644 --- a/block/blklogwrites.c +++ b/block/blklogwrites.c @@ -280,30 +280,6 @@ static int64_t blk_log_writes_getlength(BlockDriverState *bs) return bdrv_getlength(bs->file->bs); } -static void blk_log_writes_refresh_filename(BlockDriverState *bs, - QDict *options) -{ - BDRVBlkLogWritesState *s = bs->opaque; - - /* bs->file->bs has already been refreshed */ - bdrv_refresh_filename(s->log_file->bs); - - if (bs->file->bs->full_open_options - && s->log_file->bs->full_open_options) - { - QDict *opts = qdict_new(); - qdict_put_str(opts, "driver", "blklogwrites"); - - qobject_ref(bs->file->bs->full_open_options); - qdict_put(opts, "file", bs->file->bs->full_open_options); - qobject_ref(s->log_file->bs->full_open_options); - qdict_put(opts, "log", s->log_file->bs->full_open_options); - qdict_put_int(opts, "log-sector-size", s->sectorsize); - - bs->full_open_options = opts; - } -} - static void blk_log_writes_child_perm(BlockDriverState *bs, BdrvChild *c, const BdrvChildRole *role, BlockReopenQueue *ro_q, @@ -520,6 +496,13 @@ blk_log_writes_co_pdiscard(BlockDriverState *bs, int64_t offset, int count) LOG_DISCARD_FLAG, false); } +static const char *const blk_log_writes_strong_runtime_opts[] = { + "log-append", + "log-sector-size", + + NULL +}; + static BlockDriver bdrv_blk_log_writes = { .format_name = "blklogwrites", .instance_size = sizeof(BDRVBlkLogWritesState), @@ -527,7 +510,6 @@ static BlockDriver bdrv_blk_log_writes = { .bdrv_open = blk_log_writes_open, .bdrv_close = blk_log_writes_close, .bdrv_getlength = blk_log_writes_getlength, - .bdrv_refresh_filename = blk_log_writes_refresh_filename, .bdrv_child_perm = blk_log_writes_child_perm, .bdrv_refresh_limits = blk_log_writes_refresh_limits, @@ -539,6 +521,7 @@ static BlockDriver bdrv_blk_log_writes = { .bdrv_co_block_status = bdrv_co_block_status_from_file, .is_filter = true, + .strong_runtime_opts = blk_log_writes_strong_runtime_opts, }; static void bdrv_blk_log_writes_init(void) diff --git a/block/blkverify.c b/block/blkverify.c index 89bf4386e3..3ff77ff49a 100644 --- a/block/blkverify.c +++ b/block/blkverify.c @@ -281,27 +281,10 @@ static bool blkverify_recurse_is_first_non_filter(BlockDriverState *bs, return bdrv_recurse_is_first_non_filter(s->test_file->bs, candidate); } -static void blkverify_refresh_filename(BlockDriverState *bs, QDict *options) +static void blkverify_refresh_filename(BlockDriverState *bs) { BDRVBlkverifyState *s = bs->opaque; - /* bs->file->bs has already been refreshed */ - bdrv_refresh_filename(s->test_file->bs); - - if (bs->file->bs->full_open_options - && s->test_file->bs->full_open_options) - { - QDict *opts = qdict_new(); - qdict_put_str(opts, "driver", "blkverify"); - - qdict_put(opts, "raw", - qobject_ref(bs->file->bs->full_open_options)); - qdict_put(opts, "test", - qobject_ref(s->test_file->bs->full_open_options)); - - bs->full_open_options = opts; - } - if (bs->file->bs->exact_filename[0] && s->test_file->bs->exact_filename[0]) { @@ -316,6 +299,15 @@ static void blkverify_refresh_filename(BlockDriverState *bs, QDict *options) } } +static char *blkverify_dirname(BlockDriverState *bs, Error **errp) +{ + /* In general, there are two BDSs with different dirnames below this one; + * so there is no unique dirname we could return (unless both are equal by + * chance). Therefore, to be consistent, just always return NULL. */ + error_setg(errp, "Cannot generate a base directory for blkverify nodes"); + return NULL; +} + static BlockDriver bdrv_blkverify = { .format_name = "blkverify", .protocol_name = "blkverify", @@ -327,6 +319,7 @@ static BlockDriver bdrv_blkverify = { .bdrv_child_perm = bdrv_filter_default_perms, .bdrv_getlength = blkverify_getlength, .bdrv_refresh_filename = blkverify_refresh_filename, + .bdrv_dirname = blkverify_dirname, .bdrv_co_preadv = blkverify_co_preadv, .bdrv_co_pwritev = blkverify_co_pwritev, diff --git a/block/block-backend.c b/block/block-backend.c index 6cc25569ef..edad02a0f2 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -1253,12 +1253,12 @@ int blk_make_zero(BlockBackend *blk, BdrvRequestFlags flags) return bdrv_make_zero(blk->root, flags); } -static void blk_inc_in_flight(BlockBackend *blk) +void blk_inc_in_flight(BlockBackend *blk) { atomic_inc(&blk->in_flight); } -static void blk_dec_in_flight(BlockBackend *blk) +void blk_dec_in_flight(BlockBackend *blk) { atomic_dec(&blk->in_flight); aio_wait_kick(); diff --git a/block/commit.c b/block/commit.c index d500a93068..3b46ca7f97 100644 --- a/block/commit.c +++ b/block/commit.c @@ -225,9 +225,8 @@ static int coroutine_fn bdrv_commit_top_preadv(BlockDriverState *bs, return bdrv_co_preadv(bs->backing, offset, bytes, qiov, flags); } -static void bdrv_commit_top_refresh_filename(BlockDriverState *bs, QDict *opts) +static void bdrv_commit_top_refresh_filename(BlockDriverState *bs) { - bdrv_refresh_filename(bs->backing->bs); pstrcpy(bs->exact_filename, sizeof(bs->exact_filename), bs->backing->bs->filename); } @@ -369,10 +368,12 @@ fail: if (s->top) { blk_unref(s->top); } + job_early_fail(&s->common.job); + /* commit_top_bs has to be replaced after deleting the block job, + * otherwise this would fail because of lack of permissions. */ if (commit_top_bs) { bdrv_replace_node(commit_top_bs, top, &error_abort); } - job_early_fail(&s->common.job); } diff --git a/block/crypto.c b/block/crypto.c index d5b1da66a1..fd8c7cfac6 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -619,6 +619,12 @@ block_crypto_get_specific_info_luks(BlockDriverState *bs, Error **errp) return spec_info; } +static const char *const block_crypto_strong_runtime_opts[] = { + BLOCK_CRYPTO_OPT_LUKS_KEY_SECRET, + + NULL +}; + BlockDriver bdrv_crypto_luks = { .format_name = "luks", .instance_size = sizeof(BlockCrypto), @@ -640,6 +646,8 @@ BlockDriver bdrv_crypto_luks = { .bdrv_getlength = block_crypto_getlength, .bdrv_get_info = block_crypto_get_info_luks, .bdrv_get_specific_info = block_crypto_get_specific_info_luks, + + .strong_runtime_opts = block_crypto_strong_runtime_opts, }; static void block_crypto_init(void) diff --git a/block/curl.c b/block/curl.c index b7ac265d3a..606709fea4 100644 --- a/block/curl.c +++ b/block/curl.c @@ -61,8 +61,6 @@ static CURLMcode __curl_multi_socket_action(CURLM *multi_handle, #define CURL_NUM_STATES 8 #define CURL_NUM_ACB 8 -#define READ_AHEAD_DEFAULT (256 * 1024) -#define CURL_TIMEOUT_DEFAULT 5 #define CURL_TIMEOUT_MAX 10000 #define CURL_BLOCK_OPT_URL "url" @@ -76,6 +74,10 @@ static CURLMcode __curl_multi_socket_action(CURLM *multi_handle, #define CURL_BLOCK_OPT_PROXY_USERNAME "proxy-username" #define CURL_BLOCK_OPT_PROXY_PASSWORD_SECRET "proxy-password-secret" +#define CURL_BLOCK_OPT_READAHEAD_DEFAULT (256 * 1024) +#define CURL_BLOCK_OPT_SSLVERIFY_DEFAULT true +#define CURL_BLOCK_OPT_TIMEOUT_DEFAULT 5 + struct BDRVCURLState; static bool libcurl_initialized; @@ -696,7 +698,7 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags, } s->readahead_size = qemu_opt_get_size(opts, CURL_BLOCK_OPT_READAHEAD, - READ_AHEAD_DEFAULT); + CURL_BLOCK_OPT_READAHEAD_DEFAULT); if ((s->readahead_size & 0x1ff) != 0) { error_setg(errp, "HTTP_READAHEAD_SIZE %zd is not a multiple of 512", s->readahead_size); @@ -704,13 +706,14 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags, } s->timeout = qemu_opt_get_number(opts, CURL_BLOCK_OPT_TIMEOUT, - CURL_TIMEOUT_DEFAULT); + CURL_BLOCK_OPT_TIMEOUT_DEFAULT); if (s->timeout > CURL_TIMEOUT_MAX) { error_setg(errp, "timeout parameter is too large or negative"); goto out_noclean; } - s->sslverify = qemu_opt_get_bool(opts, CURL_BLOCK_OPT_SSLVERIFY, true); + s->sslverify = qemu_opt_get_bool(opts, CURL_BLOCK_OPT_SSLVERIFY, + CURL_BLOCK_OPT_SSLVERIFY_DEFAULT); cookie = qemu_opt_get(opts, CURL_BLOCK_OPT_COOKIE); cookie_secret = qemu_opt_get(opts, CURL_BLOCK_OPT_COOKIE_SECRET); @@ -947,6 +950,36 @@ static int64_t curl_getlength(BlockDriverState *bs) return s->len; } +static void curl_refresh_filename(BlockDriverState *bs) +{ + BDRVCURLState *s = bs->opaque; + + /* "readahead" and "timeout" do not change the guest-visible data, + * so ignore them */ + if (s->sslverify != CURL_BLOCK_OPT_SSLVERIFY_DEFAULT || + s->cookie || s->username || s->password || s->proxyusername || + s->proxypassword) + { + return; + } + + pstrcpy(bs->exact_filename, sizeof(bs->exact_filename), s->url); +} + + +static const char *const curl_strong_runtime_opts[] = { + CURL_BLOCK_OPT_URL, + CURL_BLOCK_OPT_SSLVERIFY, + CURL_BLOCK_OPT_COOKIE, + CURL_BLOCK_OPT_COOKIE_SECRET, + CURL_BLOCK_OPT_USERNAME, + CURL_BLOCK_OPT_PASSWORD_SECRET, + CURL_BLOCK_OPT_PROXY_USERNAME, + CURL_BLOCK_OPT_PROXY_PASSWORD_SECRET, + + NULL +}; + static BlockDriver bdrv_http = { .format_name = "http", .protocol_name = "http", @@ -961,6 +994,9 @@ static BlockDriver bdrv_http = { .bdrv_detach_aio_context = curl_detach_aio_context, .bdrv_attach_aio_context = curl_attach_aio_context, + + .bdrv_refresh_filename = curl_refresh_filename, + .strong_runtime_opts = curl_strong_runtime_opts, }; static BlockDriver bdrv_https = { @@ -977,6 +1013,9 @@ static BlockDriver bdrv_https = { .bdrv_detach_aio_context = curl_detach_aio_context, .bdrv_attach_aio_context = curl_attach_aio_context, + + .bdrv_refresh_filename = curl_refresh_filename, + .strong_runtime_opts = curl_strong_runtime_opts, }; static BlockDriver bdrv_ftp = { @@ -993,6 +1032,9 @@ static BlockDriver bdrv_ftp = { .bdrv_detach_aio_context = curl_detach_aio_context, .bdrv_attach_aio_context = curl_attach_aio_context, + + .bdrv_refresh_filename = curl_refresh_filename, + .strong_runtime_opts = curl_strong_runtime_opts, }; static BlockDriver bdrv_ftps = { @@ -1009,6 +1051,9 @@ static BlockDriver bdrv_ftps = { .bdrv_detach_aio_context = curl_detach_aio_context, .bdrv_attach_aio_context = curl_attach_aio_context, + + .bdrv_refresh_filename = curl_refresh_filename, + .strong_runtime_opts = curl_strong_runtime_opts, }; static void curl_block_init(void) diff --git a/block/gluster.c b/block/gluster.c index 72891060e3..af64330211 100644 --- a/block/gluster.c +++ b/block/gluster.c @@ -1495,6 +1495,21 @@ static int coroutine_fn qemu_gluster_co_block_status(BlockDriverState *bs, } +static const char *const gluster_strong_open_opts[] = { + GLUSTER_OPT_VOLUME, + GLUSTER_OPT_PATH, + GLUSTER_OPT_TYPE, + GLUSTER_OPT_SERVER_PATTERN, + GLUSTER_OPT_HOST, + GLUSTER_OPT_PORT, + GLUSTER_OPT_TO, + GLUSTER_OPT_IPV4, + GLUSTER_OPT_IPV6, + GLUSTER_OPT_SOCKET, + + NULL +}; + static BlockDriver bdrv_gluster = { .format_name = "gluster", .protocol_name = "gluster", @@ -1522,6 +1537,7 @@ static BlockDriver bdrv_gluster = { #endif .bdrv_co_block_status = qemu_gluster_co_block_status, .create_opts = &qemu_gluster_create_opts, + .strong_runtime_opts = gluster_strong_open_opts, }; static BlockDriver bdrv_gluster_tcp = { @@ -1551,6 +1567,7 @@ static BlockDriver bdrv_gluster_tcp = { #endif .bdrv_co_block_status = qemu_gluster_co_block_status, .create_opts = &qemu_gluster_create_opts, + .strong_runtime_opts = gluster_strong_open_opts, }; static BlockDriver bdrv_gluster_unix = { @@ -1580,6 +1597,7 @@ static BlockDriver bdrv_gluster_unix = { #endif .bdrv_co_block_status = qemu_gluster_co_block_status, .create_opts = &qemu_gluster_create_opts, + .strong_runtime_opts = gluster_strong_open_opts, }; /* rdma is deprecated (actually never supported for volfile fetch). @@ -1615,6 +1633,7 @@ static BlockDriver bdrv_gluster_rdma = { #endif .bdrv_co_block_status = qemu_gluster_co_block_status, .create_opts = &qemu_gluster_create_opts, + .strong_runtime_opts = gluster_strong_open_opts, }; static void bdrv_gluster_init(void) diff --git a/block/iscsi.c b/block/iscsi.c index ff473206e6..a0c0084837 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -2448,6 +2448,20 @@ static QemuOptsList iscsi_create_opts = { } }; +static const char *const iscsi_strong_runtime_opts[] = { + "transport", + "portal", + "target", + "user", + "password", + "password-secret", + "lun", + "initiator-name", + "header-digest", + + NULL +}; + static BlockDriver bdrv_iscsi = { .format_name = "iscsi", .protocol_name = "iscsi", @@ -2482,6 +2496,8 @@ static BlockDriver bdrv_iscsi = { .bdrv_detach_aio_context = iscsi_detach_aio_context, .bdrv_attach_aio_context = iscsi_attach_aio_context, + + .strong_runtime_opts = iscsi_strong_runtime_opts, }; #if LIBISCSI_API_VERSION >= (20160603) @@ -2519,6 +2535,8 @@ static BlockDriver bdrv_iser = { .bdrv_detach_aio_context = iscsi_detach_aio_context, .bdrv_attach_aio_context = iscsi_attach_aio_context, + + .strong_runtime_opts = iscsi_strong_runtime_opts, }; #endif diff --git a/block/mirror.c b/block/mirror.c index b67b0120f8..726d3c27fb 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -1431,14 +1431,13 @@ static int coroutine_fn bdrv_mirror_top_pdiscard(BlockDriverState *bs, NULL, 0); } -static void bdrv_mirror_top_refresh_filename(BlockDriverState *bs, QDict *opts) +static void bdrv_mirror_top_refresh_filename(BlockDriverState *bs) { if (bs->backing == NULL) { /* we can be here after failed bdrv_attach_child in * bdrv_set_backing_hd */ return; } - bdrv_refresh_filename(bs->backing->bs); pstrcpy(bs->exact_filename, sizeof(bs->exact_filename), bs->backing->bs->filename); } diff --git a/block/nbd-client.c b/block/nbd-client.c index f0ad54ce21..bfbaf7ebe9 100644 --- a/block/nbd-client.c +++ b/block/nbd-client.c @@ -76,8 +76,18 @@ static coroutine_fn void nbd_connection_entry(void *opaque) Error *local_err = NULL; while (!s->quit) { + /* + * The NBD client can only really be considered idle when it has + * yielded from qio_channel_readv_all_eof(), waiting for data. This is + * the point where the additional scheduled coroutine entry happens + * after nbd_client_attach_aio_context(). + * + * Therefore we keep an additional in_flight reference all the time and + * only drop it temporarily here. + */ assert(s->reply.handle == 0); - ret = nbd_receive_reply(s->ioc, &s->reply, &local_err); + ret = nbd_receive_reply(s->bs, s->ioc, &s->reply, &local_err); + if (local_err) { trace_nbd_read_reply_entry_fail(ret, error_get_pretty(local_err)); error_free(local_err); @@ -116,6 +126,8 @@ static coroutine_fn void nbd_connection_entry(void *opaque) s->quit = true; nbd_recv_coroutines_wake_all(s); + bdrv_dec_in_flight(s->bs); + s->connection_co = NULL; aio_wait_kick(); } @@ -965,12 +977,30 @@ void nbd_client_detach_aio_context(BlockDriverState *bs) qio_channel_detach_aio_context(QIO_CHANNEL(client->ioc)); } +static void nbd_client_attach_aio_context_bh(void *opaque) +{ + BlockDriverState *bs = opaque; + NBDClientSession *client = nbd_get_client_session(bs); + + /* The node is still drained, so we know the coroutine has yielded in + * nbd_read_eof(), the only place where bs->in_flight can reach 0, or it is + * entered for the first time. Both places are safe for entering the + * coroutine.*/ + qemu_aio_coroutine_enter(bs->aio_context, client->connection_co); + bdrv_dec_in_flight(bs); +} + void nbd_client_attach_aio_context(BlockDriverState *bs, AioContext *new_context) { NBDClientSession *client = nbd_get_client_session(bs); qio_channel_attach_aio_context(QIO_CHANNEL(client->ioc), new_context); - aio_co_schedule(new_context, client->connection_co); + + bdrv_inc_in_flight(bs); + + /* Need to wait here for the BH to run because the BH must run while the + * node is still drained. */ + aio_wait_bh_oneshot(new_context, nbd_client_attach_aio_context_bh, bs); } void nbd_client_close(BlockDriverState *bs) @@ -1076,6 +1106,7 @@ static int nbd_client_connect(BlockDriverState *bs, * kick the reply mechanism. */ qio_channel_set_blocking(QIO_CHANNEL(sioc), false, NULL); client->connection_co = qemu_coroutine_create(nbd_connection_entry, client); + bdrv_inc_in_flight(bs); nbd_client_attach_aio_context(bs, bdrv_get_aio_context(bs)); logout("Established connection with NBD server\n"); @@ -1108,6 +1139,7 @@ int nbd_client_init(BlockDriverState *bs, { NBDClientSession *client = nbd_get_client_session(bs); + client->bs = bs; qemu_co_mutex_init(&client->send_mutex); qemu_co_queue_init(&client->free_sema); diff --git a/block/nbd-client.h b/block/nbd-client.h index d990207a5c..09e03013d2 100644 --- a/block/nbd-client.h +++ b/block/nbd-client.h @@ -35,6 +35,7 @@ typedef struct NBDClientSession { NBDClientRequest requests[MAX_NBD_REQUESTS]; NBDReply reply; + BlockDriverState *bs; bool quit; } NBDClientSession; diff --git a/block/nbd.c b/block/nbd.c index 9db5eded89..2e72df528a 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -477,12 +477,9 @@ static void nbd_attach_aio_context(BlockDriverState *bs, nbd_client_attach_aio_context(bs, new_context); } -static void nbd_refresh_filename(BlockDriverState *bs, QDict *options) +static void nbd_refresh_filename(BlockDriverState *bs) { BDRVNBDState *s = bs->opaque; - QDict *opts = qdict_new(); - QObject *saddr_qdict; - Visitor *ov; const char *host = NULL, *port = NULL, *path = NULL; if (s->saddr->type == SOCKET_ADDRESS_TYPE_INET) { @@ -495,8 +492,6 @@ static void nbd_refresh_filename(BlockDriverState *bs, QDict *options) path = s->saddr->u.q_unix.path; } /* else can't represent as pseudo-filename */ - qdict_put_str(opts, "driver", "nbd"); - if (path && s->export) { snprintf(bs->exact_filename, sizeof(bs->exact_filename), "nbd+unix:///%s?socket=%s", s->export, path); @@ -510,23 +505,28 @@ static void nbd_refresh_filename(BlockDriverState *bs, QDict *options) snprintf(bs->exact_filename, sizeof(bs->exact_filename), "nbd://%s:%s", host, port); } +} - ov = qobject_output_visitor_new(&saddr_qdict); - visit_type_SocketAddress(ov, NULL, &s->saddr, &error_abort); - visit_complete(ov, &saddr_qdict); - visit_free(ov); - qdict_put_obj(opts, "server", saddr_qdict); +static char *nbd_dirname(BlockDriverState *bs, Error **errp) +{ + /* The generic bdrv_dirname() implementation is able to work out some + * directory name for NBD nodes, but that would be wrong. So far there is no + * specification for how "export paths" would work, so NBD does not have + * directory names. */ + error_setg(errp, "Cannot generate a base directory for NBD nodes"); + return NULL; +} - if (s->export) { - qdict_put_str(opts, "export", s->export); - } - if (s->tlscredsid) { - qdict_put_str(opts, "tls-creds", s->tlscredsid); - } +static const char *const nbd_strong_runtime_opts[] = { + "path", + "host", + "port", + "export", + "tls-creds", + "server.", - qdict_flatten(opts); - bs->full_open_options = opts; -} + NULL +}; static BlockDriver bdrv_nbd = { .format_name = "nbd", @@ -546,6 +546,8 @@ static BlockDriver bdrv_nbd = { .bdrv_attach_aio_context = nbd_attach_aio_context, .bdrv_refresh_filename = nbd_refresh_filename, .bdrv_co_block_status = nbd_client_co_block_status, + .bdrv_dirname = nbd_dirname, + .strong_runtime_opts = nbd_strong_runtime_opts, }; static BlockDriver bdrv_nbd_tcp = { @@ -566,6 +568,8 @@ static BlockDriver bdrv_nbd_tcp = { .bdrv_attach_aio_context = nbd_attach_aio_context, .bdrv_refresh_filename = nbd_refresh_filename, .bdrv_co_block_status = nbd_client_co_block_status, + .bdrv_dirname = nbd_dirname, + .strong_runtime_opts = nbd_strong_runtime_opts, }; static BlockDriver bdrv_nbd_unix = { @@ -586,6 +590,8 @@ static BlockDriver bdrv_nbd_unix = { .bdrv_attach_aio_context = nbd_attach_aio_context, .bdrv_refresh_filename = nbd_refresh_filename, .bdrv_co_block_status = nbd_client_co_block_status, + .bdrv_dirname = nbd_dirname, + .strong_runtime_opts = nbd_strong_runtime_opts, }; static void bdrv_nbd_init(void) diff --git a/block/nfs.c b/block/nfs.c index eab1a2c408..531903610b 100644 --- a/block/nfs.c +++ b/block/nfs.c @@ -799,14 +799,9 @@ static int nfs_reopen_prepare(BDRVReopenState *state, return 0; } -static void nfs_refresh_filename(BlockDriverState *bs, QDict *options) +static void nfs_refresh_filename(BlockDriverState *bs) { NFSClient *client = bs->opaque; - QDict *opts = qdict_new(); - QObject *server_qdict; - Visitor *ov; - - qdict_put_str(opts, "driver", "nfs"); if (client->uid && !client->gid) { snprintf(bs->exact_filename, sizeof(bs->exact_filename), @@ -824,35 +819,20 @@ static void nfs_refresh_filename(BlockDriverState *bs, QDict *options) snprintf(bs->exact_filename, sizeof(bs->exact_filename), "nfs://%s%s", client->server->host, client->path); } +} - ov = qobject_output_visitor_new(&server_qdict); - visit_type_NFSServer(ov, NULL, &client->server, &error_abort); - visit_complete(ov, &server_qdict); - qdict_put_obj(opts, "server", server_qdict); - qdict_put_str(opts, "path", client->path); +static char *nfs_dirname(BlockDriverState *bs, Error **errp) +{ + NFSClient *client = bs->opaque; - if (client->uid) { - qdict_put_int(opts, "user", client->uid); - } - if (client->gid) { - qdict_put_int(opts, "group", client->gid); - } - if (client->tcp_syncnt) { - qdict_put_int(opts, "tcp-syn-cnt", client->tcp_syncnt); - } - if (client->readahead) { - qdict_put_int(opts, "readahead-size", client->readahead); - } - if (client->pagecache) { - qdict_put_int(opts, "page-cache-size", client->pagecache); - } - if (client->debug) { - qdict_put_int(opts, "debug", client->debug); + if (client->uid || client->gid) { + bdrv_refresh_filename(bs); + error_setg(errp, "Cannot generate a base directory for NFS node '%s'", + bs->filename); + return NULL; } - visit_free(ov); - qdict_flatten(opts); - bs->full_open_options = opts; + return g_strdup_printf("nfs://%s%s/", client->server->host, client->path); } #ifdef LIBNFS_FEATURE_PAGECACHE @@ -864,6 +844,15 @@ static void coroutine_fn nfs_co_invalidate_cache(BlockDriverState *bs, } #endif +static const char *nfs_strong_runtime_opts[] = { + "path", + "user", + "group", + "server.", + + NULL +}; + static BlockDriver bdrv_nfs = { .format_name = "nfs", .protocol_name = "nfs", @@ -889,6 +878,9 @@ static BlockDriver bdrv_nfs = { .bdrv_detach_aio_context = nfs_detach_aio_context, .bdrv_attach_aio_context = nfs_attach_aio_context, .bdrv_refresh_filename = nfs_refresh_filename, + .bdrv_dirname = nfs_dirname, + + .strong_runtime_opts = nfs_strong_runtime_opts, #ifdef LIBNFS_FEATURE_PAGECACHE .bdrv_co_invalidate_cache = nfs_co_invalidate_cache, diff --git a/block/null.c b/block/null.c index d442d3e901..a322929478 100644 --- a/block/null.c +++ b/block/null.c @@ -239,19 +239,33 @@ static int coroutine_fn null_co_block_status(BlockDriverState *bs, return ret; } -static void null_refresh_filename(BlockDriverState *bs, QDict *opts) +static void null_refresh_filename(BlockDriverState *bs) { - qdict_del(opts, "filename"); - - if (!qdict_size(opts)) { - snprintf(bs->exact_filename, sizeof(bs->exact_filename), "%s://", - bs->drv->format_name); + const QDictEntry *e; + + for (e = qdict_first(bs->full_open_options); e; + e = qdict_next(bs->full_open_options, e)) + { + /* These options can be ignored */ + if (strcmp(qdict_entry_key(e), "filename") && + strcmp(qdict_entry_key(e), "driver") && + strcmp(qdict_entry_key(e), NULL_OPT_LATENCY)) + { + return; + } } - qdict_put_str(opts, "driver", bs->drv->format_name); - bs->full_open_options = qobject_ref(opts); + snprintf(bs->exact_filename, sizeof(bs->exact_filename), "%s://", + bs->drv->format_name); } +static const char *const null_strong_runtime_opts[] = { + BLOCK_OPT_SIZE, + NULL_OPT_ZEROES, + + NULL +}; + static BlockDriver bdrv_null_co = { .format_name = "null-co", .protocol_name = "null-co", @@ -269,6 +283,7 @@ static BlockDriver bdrv_null_co = { .bdrv_co_block_status = null_co_block_status, .bdrv_refresh_filename = null_refresh_filename, + .strong_runtime_opts = null_strong_runtime_opts, }; static BlockDriver bdrv_null_aio = { @@ -288,6 +303,7 @@ static BlockDriver bdrv_null_aio = { .bdrv_co_block_status = null_co_block_status, .bdrv_refresh_filename = null_refresh_filename, + .strong_runtime_opts = null_strong_runtime_opts, }; static void bdrv_null_init(void) diff --git a/block/nvme.c b/block/nvme.c index b5952c9b08..0684bbd077 100644 --- a/block/nvme.c +++ b/block/nvme.c @@ -82,7 +82,7 @@ typedef volatile struct { uint8_t reserved1[0xec0]; uint8_t cmd_set_specfic[0x100]; uint32_t doorbells[]; -} QEMU_PACKED NVMeRegs; +} NVMeRegs; QEMU_BUILD_BUG_ON(offsetof(NVMeRegs, doorbells) != 0x1000); @@ -111,6 +111,9 @@ typedef struct { /* Total size of mapped qiov, accessed under dma_map_lock */ int dma_map_count; + + /* PCI address (required for nvme_refresh_filename()) */ + char *device; } BDRVNVMeState; #define NVME_BLOCK_OPT_DEVICE "device" @@ -557,6 +560,7 @@ static int nvme_init(BlockDriverState *bs, const char *device, int namespace, qemu_co_mutex_init(&s->dma_map_lock); qemu_co_queue_init(&s->dma_flush_queue); + s->device = g_strdup(device); s->nsid = namespace; s->aio_context = bdrv_get_aio_context(bs); ret = event_notifier_init(&s->irq_notifier, 0); @@ -729,6 +733,8 @@ static void nvme_close(BlockDriverState *bs) event_notifier_cleanup(&s->irq_notifier); qemu_vfio_pci_unmap_bar(s->vfio, 0, (void *)s->regs, 0, NVME_BAR_SIZE); qemu_vfio_close(s->vfio); + + g_free(s->device); } static int nvme_file_open(BlockDriverState *bs, QDict *options, int flags, @@ -1053,17 +1059,12 @@ static int nvme_reopen_prepare(BDRVReopenState *reopen_state, return 0; } -static void nvme_refresh_filename(BlockDriverState *bs, QDict *opts) +static void nvme_refresh_filename(BlockDriverState *bs) { - qdict_del(opts, "filename"); - - if (!qdict_size(opts)) { - snprintf(bs->exact_filename, sizeof(bs->exact_filename), "%s://", - bs->drv->format_name); - } + BDRVNVMeState *s = bs->opaque; - qdict_put_str(opts, "driver", bs->drv->format_name); - bs->full_open_options = qobject_ref(opts); + snprintf(bs->exact_filename, sizeof(bs->exact_filename), "nvme://%s/%i", + s->device, s->nsid); } static void nvme_refresh_limits(BlockDriverState *bs, Error **errp) @@ -1136,6 +1137,13 @@ static void nvme_unregister_buf(BlockDriverState *bs, void *host) qemu_vfio_dma_unmap(s->vfio, host); } +static const char *const nvme_strong_runtime_opts[] = { + NVME_BLOCK_OPT_DEVICE, + NVME_BLOCK_OPT_NAMESPACE, + + NULL +}; + static BlockDriver bdrv_nvme = { .format_name = "nvme", .protocol_name = "nvme", @@ -1153,6 +1161,7 @@ static BlockDriver bdrv_nvme = { .bdrv_refresh_filename = nvme_refresh_filename, .bdrv_refresh_limits = nvme_refresh_limits, + .strong_runtime_opts = nvme_strong_runtime_opts, .bdrv_detach_aio_context = nvme_detach_aio_context, .bdrv_attach_aio_context = nvme_attach_aio_context, diff --git a/block/qapi.c b/block/qapi.c index 00291f9105..6002a768f8 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -51,6 +51,8 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk, return NULL; } + bdrv_refresh_filename(bs); + info = g_malloc0(sizeof(*info)); info->file = g_strdup(bs->filename); info->ro = bs->read_only; @@ -264,6 +266,8 @@ void bdrv_query_image_info(BlockDriverState *bs, goto out; } + bdrv_refresh_filename(bs); + info = g_new0(ImageInfo, 1); info->filename = g_strdup(bs->filename); info->format = g_strdup(bdrv_get_format_name(bs)); @@ -292,18 +296,10 @@ void bdrv_query_image_info(BlockDriverState *bs, backing_filename = bs->backing_file; if (backing_filename[0] != '\0') { - char *backing_filename2 = g_malloc0(PATH_MAX); + char *backing_filename2; info->backing_filename = g_strdup(backing_filename); info->has_backing_filename = true; - bdrv_get_full_backing_filename(bs, backing_filename2, PATH_MAX, &err); - if (err) { - /* Can't reconstruct the full backing filename, so we must omit - * this field and apply a Best Effort to this query. */ - g_free(backing_filename2); - backing_filename2 = NULL; - error_free(err); - err = NULL; - } + backing_filename2 = bdrv_get_full_backing_filename(bs, NULL); /* Always report the full_backing_filename if present, even if it's the * same as backing_filename. That they are same is useful info. */ diff --git a/block/qcow.c b/block/qcow.c index 409c700d33..10d2cf14b3 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -31,6 +31,7 @@ #include "qemu/module.h" #include "qemu/option.h" #include "qemu/bswap.h" +#include "qemu/cutils.h" #include <zlib.h> #include "qapi/qmp/qdict.h" #include "qapi/qmp/qstring.h" @@ -295,11 +296,13 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags, goto fail; } ret = bdrv_pread(bs->file, header.backing_file_offset, - bs->backing_file, len); + bs->auto_backing_file, len); if (ret < 0) { goto fail; } - bs->backing_file[len] = '\0'; + bs->auto_backing_file[len] = '\0'; + pstrcpy(bs->backing_file, sizeof(bs->backing_file), + bs->auto_backing_file); } /* Disable migration when qcow images are used */ @@ -1170,6 +1173,12 @@ static QemuOptsList qcow_create_opts = { } }; +static const char *const qcow_strong_runtime_opts[] = { + "encrypt." BLOCK_CRYPTO_OPT_QCOW_KEY_SECRET, + + NULL +}; + static BlockDriver bdrv_qcow = { .format_name = "qcow", .instance_size = sizeof(BDRVQcowState), @@ -1193,6 +1202,7 @@ static BlockDriver bdrv_qcow = { .bdrv_get_info = qcow_get_info, .create_opts = &qcow_create_opts, + .strong_runtime_opts = qcow_strong_runtime_opts, }; static void bdrv_qcow_init(void) diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 30eca26c47..179aa2c728 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -285,6 +285,9 @@ static int l2_allocate(BlockDriverState *bs, int l1_index) goto fail; } + /* The offset must fit in the offset field of the L1 table entry */ + assert((l2_offset & L1E_OFFSET_MASK) == l2_offset); + /* If we're allocating the table at offset 0 then something is wrong */ if (l2_offset == 0) { qcow2_signal_corruption(bs, true, -1, -1, "Preventing invalid " diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c index bb6a5b7516..20e8472191 100644 --- a/block/qcow2-snapshot.c +++ b/block/qcow2-snapshot.c @@ -358,11 +358,6 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) /* Generate an ID */ find_new_snapshot_id(bs, sn_info->id_str, sizeof(sn_info->id_str)); - /* Check that the ID is unique */ - if (find_snapshot_by_id_and_name(bs, sn_info->id_str, NULL) >= 0) { - return -EEXIST; - } - /* Populate sn with passed data */ sn->id_str = g_strdup(sn_info->id_str); sn->name = g_strdup(sn_info->name); diff --git a/block/qcow2.c b/block/qcow2.c index b6d475229e..7fb2730f09 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1474,13 +1474,15 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, goto fail; } ret = bdrv_pread(bs->file, header.backing_file_offset, - bs->backing_file, len); + bs->auto_backing_file, len); if (ret < 0) { error_setg_errno(errp, -ret, "Could not read backing file name"); goto fail; } - bs->backing_file[len] = '\0'; - s->image_backing_file = g_strdup(bs->backing_file); + bs->auto_backing_file[len] = '\0'; + pstrcpy(bs->backing_file, sizeof(bs->backing_file), + bs->auto_backing_file); + s->image_backing_file = g_strdup(bs->auto_backing_file); } /* Internal snapshots */ @@ -2518,6 +2520,8 @@ static int qcow2_change_backing_file(BlockDriverState *bs, return -EINVAL; } + pstrcpy(bs->auto_backing_file, sizeof(bs->auto_backing_file), + backing_file ?: ""); pstrcpy(bs->backing_file, sizeof(bs->backing_file), backing_file ?: ""); pstrcpy(bs->backing_format, sizeof(bs->backing_format), backing_fmt ?: ""); @@ -4224,6 +4228,60 @@ static coroutine_fn int qcow2_co_flush_to_os(BlockDriverState *bs) return ret; } +static ssize_t qcow2_measure_crypto_hdr_init_func(QCryptoBlock *block, + size_t headerlen, void *opaque, Error **errp) +{ + size_t *headerlenp = opaque; + + /* Stash away the payload size */ + *headerlenp = headerlen; + return 0; +} + +static ssize_t qcow2_measure_crypto_hdr_write_func(QCryptoBlock *block, + size_t offset, const uint8_t *buf, size_t buflen, + void *opaque, Error **errp) +{ + /* Discard the bytes, we're not actually writing to an image */ + return buflen; +} + +/* Determine the number of bytes for the LUKS payload */ +static bool qcow2_measure_luks_headerlen(QemuOpts *opts, size_t *len, + Error **errp) +{ + QDict *opts_qdict; + QDict *cryptoopts_qdict; + QCryptoBlockCreateOptions *cryptoopts; + QCryptoBlock *crypto; + + /* Extract "encrypt." options into a qdict */ + opts_qdict = qemu_opts_to_qdict(opts, NULL); + qdict_extract_subqdict(opts_qdict, &cryptoopts_qdict, "encrypt."); + qobject_unref(opts_qdict); + + /* Build QCryptoBlockCreateOptions object from qdict */ + qdict_put_str(cryptoopts_qdict, "format", "luks"); + cryptoopts = block_crypto_create_opts_init(cryptoopts_qdict, errp); + qobject_unref(cryptoopts_qdict); + if (!cryptoopts) { + return false; + } + + /* Fake LUKS creation in order to determine the payload size */ + crypto = qcrypto_block_create(cryptoopts, "encrypt.", + qcow2_measure_crypto_hdr_init_func, + qcow2_measure_crypto_hdr_write_func, + len, errp); + qapi_free_QCryptoBlockCreateOptions(cryptoopts); + if (!crypto) { + return false; + } + + qcrypto_block_free(crypto); + return true; +} + static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs, Error **errp) { @@ -4233,11 +4291,13 @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs, uint64_t virtual_size; /* disk size as seen by guest */ uint64_t refcount_bits; uint64_t l2_tables; + uint64_t luks_payload_size = 0; size_t cluster_size; int version; char *optstr; PreallocMode prealloc; bool has_backing_file; + bool has_luks; /* Parse image creation options */ cluster_size = qcow2_opt_get_cluster_size_del(opts, &local_err); @@ -4267,6 +4327,20 @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs, has_backing_file = !!optstr; g_free(optstr); + optstr = qemu_opt_get_del(opts, BLOCK_OPT_ENCRYPT_FORMAT); + has_luks = optstr && strcmp(optstr, "luks") == 0; + g_free(optstr); + + if (has_luks) { + size_t headerlen; + + if (!qcow2_measure_luks_headerlen(opts, &headerlen, &local_err)) { + goto err; + } + + luks_payload_size = ROUND_UP(headerlen, cluster_size); + } + virtual_size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0); virtual_size = ROUND_UP(virtual_size, cluster_size); @@ -4337,7 +4411,7 @@ static BlockMeasureInfo *qcow2_measure(QemuOpts *opts, BlockDriverState *in_bs, info = g_new(BlockMeasureInfo, 1); info->fully_allocated = qcow2_calc_prealloc_size(virtual_size, cluster_size, - ctz32(refcount_bits)); + ctz32(refcount_bits)) + luks_payload_size; /* Remove data clusters that are not required. This overestimates the * required size because metadata needed for the fully allocated file is @@ -4924,6 +4998,12 @@ static QemuOptsList qcow2_create_opts = { } }; +static const char *const qcow2_strong_runtime_opts[] = { + "encrypt." BLOCK_CRYPTO_OPT_QCOW_KEY_SECRET, + + NULL +}; + BlockDriver bdrv_qcow2 = { .format_name = "qcow2", .instance_size = sizeof(BDRVQcow2State), @@ -4972,6 +5052,7 @@ BlockDriver bdrv_qcow2 = { .bdrv_inactivate = qcow2_inactivate, .create_opts = &qcow2_create_opts, + .strong_runtime_opts = qcow2_strong_runtime_opts, .bdrv_co_check = qcow2_co_check, .bdrv_amend_options = qcow2_amend_options, diff --git a/block/qed.c b/block/qed.c index c5e6d6ad41..89af05d524 100644 --- a/block/qed.c +++ b/block/qed.c @@ -449,11 +449,14 @@ static int coroutine_fn bdrv_qed_do_open(BlockDriverState *bs, QDict *options, } ret = qed_read_string(bs->file, s->header.backing_filename_offset, - s->header.backing_filename_size, bs->backing_file, - sizeof(bs->backing_file)); + s->header.backing_filename_size, + bs->auto_backing_file, + sizeof(bs->auto_backing_file)); if (ret < 0) { return ret; } + pstrcpy(bs->backing_file, sizeof(bs->backing_file), + bs->auto_backing_file); if (s->header.features & QED_F_BACKING_FORMAT_NO_PROBE) { pstrcpy(bs->backing_format, sizeof(bs->backing_format), "raw"); diff --git a/block/quorum.c b/block/quorum.c index 16b3c8067c..352f729136 100644 --- a/block/quorum.c +++ b/block/quorum.c @@ -1065,36 +1065,64 @@ static void quorum_del_child(BlockDriverState *bs, BdrvChild *child, bdrv_drained_end(bs); } -static void quorum_refresh_filename(BlockDriverState *bs, QDict *options) +static void quorum_gather_child_options(BlockDriverState *bs, QDict *target, + bool backing_overridden) { BDRVQuorumState *s = bs->opaque; - QDict *opts; - QList *children; + QList *children_list; int i; - for (i = 0; i < s->num_children; i++) { - bdrv_refresh_filename(s->children[i]->bs); - if (!s->children[i]->bs->full_open_options) { - return; - } - } + /* + * The generic implementation for gathering child options in + * bdrv_refresh_filename() would use the names of the children + * as specified for bdrv_open_child() or bdrv_attach_child(), + * which is "children.%u" with %u being a value + * (s->next_child_index) that is incremented each time a new child + * is added (and never decremented). Since children can be + * deleted at runtime, there may be gaps in that enumeration. + * When creating a new quorum BDS and specifying the children for + * it through runtime options, the enumeration used there may not + * have any gaps, though. + * + * Therefore, we have to create a new gap-less enumeration here + * (which we can achieve by simply putting all of the children's + * full_open_options into a QList). + * + * XXX: Note that there are issues with the current child option + * structure quorum uses (such as the fact that children do + * not really have unique permanent names). Therefore, this + * is going to have to change in the future and ideally we + * want quorum to be covered by the generic implementation. + */ + + children_list = qlist_new(); + qdict_put(target, "children", children_list); - children = qlist_new(); for (i = 0; i < s->num_children; i++) { - qlist_append(children, + qlist_append(children_list, qobject_ref(s->children[i]->bs->full_open_options)); } +} - opts = qdict_new(); - qdict_put_str(opts, "driver", "quorum"); - qdict_put_int(opts, QUORUM_OPT_VOTE_THRESHOLD, s->threshold); - qdict_put_bool(opts, QUORUM_OPT_BLKVERIFY, s->is_blkverify); - qdict_put_bool(opts, QUORUM_OPT_REWRITE, s->rewrite_corrupted); - qdict_put(opts, "children", children); - - bs->full_open_options = opts; +static char *quorum_dirname(BlockDriverState *bs, Error **errp) +{ + /* In general, there are multiple BDSs with different dirnames below this + * one; so there is no unique dirname we could return (unless all are equal + * by chance, or there is only one). Therefore, to be consistent, just + * always return NULL. */ + error_setg(errp, "Cannot generate a base directory for quorum nodes"); + return NULL; } +static const char *const quorum_strong_runtime_opts[] = { + QUORUM_OPT_VOTE_THRESHOLD, + QUORUM_OPT_BLKVERIFY, + QUORUM_OPT_REWRITE, + QUORUM_OPT_READ_PATTERN, + + NULL +}; + static BlockDriver bdrv_quorum = { .format_name = "quorum", @@ -1102,7 +1130,8 @@ static BlockDriver bdrv_quorum = { .bdrv_open = quorum_open, .bdrv_close = quorum_close, - .bdrv_refresh_filename = quorum_refresh_filename, + .bdrv_gather_child_options = quorum_gather_child_options, + .bdrv_dirname = quorum_dirname, .bdrv_co_flush_to_disk = quorum_co_flush, @@ -1118,6 +1147,8 @@ static BlockDriver bdrv_quorum = { .is_filter = true, .bdrv_recurse_is_first_non_filter = quorum_recurse_is_first_non_filter, + + .strong_runtime_opts = quorum_strong_runtime_opts, }; static void bdrv_quorum_init(void) diff --git a/block/raw-format.c b/block/raw-format.c index 6f6dc99b2c..e3e5ba2c8a 100644 --- a/block/raw-format.c +++ b/block/raw-format.c @@ -436,6 +436,7 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags, bs->file->bs->supported_zero_flags); if (bs->probed && !bdrv_is_read_only(bs)) { + bdrv_refresh_filename(bs->file->bs); fprintf(stderr, "WARNING: Image format was not specified for '%s' and probing " "guessed raw.\n" @@ -531,6 +532,13 @@ static int coroutine_fn raw_co_copy_range_to(BlockDriverState *bs, read_flags, write_flags); } +static const char *const raw_strong_runtime_opts[] = { + "offset", + "size", + + NULL +}; + BlockDriver bdrv_raw = { .format_name = "raw", .instance_size = sizeof(BDRVRawState), @@ -560,7 +568,8 @@ BlockDriver bdrv_raw = { .bdrv_lock_medium = &raw_lock_medium, .bdrv_co_ioctl = &raw_co_ioctl, .create_opts = &raw_create_opts, - .bdrv_has_zero_init = &raw_has_zero_init + .bdrv_has_zero_init = &raw_has_zero_init, + .strong_runtime_opts = raw_strong_runtime_opts, }; static void bdrv_raw_init(void) diff --git a/block/rbd.c b/block/rbd.c index 8a1a9f4b6e..0c549c9935 100644 --- a/block/rbd.c +++ b/block/rbd.c @@ -1228,6 +1228,18 @@ static QemuOptsList qemu_rbd_create_opts = { } }; +static const char *const qemu_rbd_strong_runtime_opts[] = { + "pool", + "image", + "conf", + "snapshot", + "user", + "server.", + "password-secret", + + NULL +}; + static BlockDriver bdrv_rbd = { .format_name = "rbd", .instance_size = sizeof(BDRVRBDState), @@ -1265,6 +1277,8 @@ static BlockDriver bdrv_rbd = { #ifdef LIBRBD_SUPPORTS_INVALIDATE .bdrv_co_invalidate_cache = qemu_rbd_co_invalidate_cache, #endif + + .strong_runtime_opts = qemu_rbd_strong_runtime_opts, }; static void bdrv_rbd_init(void) diff --git a/block/replication.c b/block/replication.c index e70dd95001..4c80b54daf 100644 --- a/block/replication.c +++ b/block/replication.c @@ -616,8 +616,6 @@ static void replication_done(void *opaque, int ret) if (ret == 0) { s->stage = BLOCK_REPLICATION_DONE; - /* refresh top bs's filename */ - bdrv_refresh_filename(bs); s->active_disk = NULL; s->secondary_disk = NULL; s->hidden_disk = NULL; @@ -678,6 +676,13 @@ static void replication_stop(ReplicationState *rs, bool failover, Error **errp) aio_context_release(aio_context); } +static const char *const replication_strong_runtime_opts[] = { + REPLICATION_MODE, + REPLICATION_TOP_ID, + + NULL +}; + BlockDriver bdrv_replication = { .format_name = "replication", .instance_size = sizeof(BDRVReplicationState), @@ -694,6 +699,7 @@ BlockDriver bdrv_replication = { .bdrv_recurse_is_first_non_filter = replication_recurse_is_first_non_filter, .has_variable_length = true, + .strong_runtime_opts = replication_strong_runtime_opts, }; static void bdrv_replication_init(void) diff --git a/block/sheepdog.c b/block/sheepdog.c index b916ba07bf..cbdfe9ab6e 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -3203,6 +3203,15 @@ static QemuOptsList sd_create_opts = { } }; +static const char *const sd_strong_runtime_opts[] = { + "vdi", + "snap-id", + "tag", + "server.", + + NULL +}; + static BlockDriver bdrv_sheepdog = { .format_name = "sheepdog", .protocol_name = "sheepdog", @@ -3238,6 +3247,7 @@ static BlockDriver bdrv_sheepdog = { .bdrv_attach_aio_context = sd_attach_aio_context, .create_opts = &sd_create_opts, + .strong_runtime_opts = sd_strong_runtime_opts, }; static BlockDriver bdrv_sheepdog_tcp = { @@ -3275,6 +3285,7 @@ static BlockDriver bdrv_sheepdog_tcp = { .bdrv_attach_aio_context = sd_attach_aio_context, .create_opts = &sd_create_opts, + .strong_runtime_opts = sd_strong_runtime_opts, }; static BlockDriver bdrv_sheepdog_unix = { @@ -3312,6 +3323,7 @@ static BlockDriver bdrv_sheepdog_unix = { .bdrv_attach_aio_context = sd_attach_aio_context, .create_opts = &sd_create_opts, + .strong_runtime_opts = sd_strong_runtime_opts, }; static void bdrv_sheepdog_init(void) diff --git a/block/snapshot.c b/block/snapshot.c index 3218a542df..f2f48f926a 100644 --- a/block/snapshot.c +++ b/block/snapshot.c @@ -63,7 +63,7 @@ int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info, } for (i = 0; i < nb_sns; i++) { sn = &sn_tab[i]; - if (!strcmp(sn->id_str, name) || !strcmp(sn->name, name)) { + if (!strcmp(sn->name, name)) { *sn_info = *sn; ret = 0; break; @@ -301,26 +301,6 @@ int bdrv_snapshot_delete(BlockDriverState *bs, return ret; } -int bdrv_snapshot_delete_by_id_or_name(BlockDriverState *bs, - const char *id_or_name, - Error **errp) -{ - int ret; - Error *local_err = NULL; - - ret = bdrv_snapshot_delete(bs, id_or_name, NULL, &local_err); - if (ret == -ENOENT || ret == -EINVAL) { - error_free(local_err); - local_err = NULL; - ret = bdrv_snapshot_delete(bs, NULL, id_or_name, &local_err); - } - - if (ret < 0) { - error_propagate(errp, local_err); - } - return ret; -} - int bdrv_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_info) { @@ -448,7 +428,8 @@ int bdrv_all_delete_snapshot(const char *name, BlockDriverState **first_bad_bs, aio_context_acquire(ctx); if (bdrv_can_snapshot(bs) && bdrv_snapshot_find(bs, snapshot, name) >= 0) { - ret = bdrv_snapshot_delete_by_id_or_name(bs, name, err); + ret = bdrv_snapshot_delete(bs, snapshot->id_str, + snapshot->name, err); } aio_context_release(ctx); if (ret < 0) { diff --git a/block/ssh.c b/block/ssh.c index bbc513e095..190ef95300 100644 --- a/block/ssh.c +++ b/block/ssh.c @@ -1254,6 +1254,17 @@ static int coroutine_fn ssh_co_truncate(BlockDriverState *bs, int64_t offset, return ssh_grow_file(s, offset, errp); } +static const char *const ssh_strong_runtime_opts[] = { + "host", + "port", + "path", + "user", + "host_key_check", + "server.", + + NULL +}; + static BlockDriver bdrv_ssh = { .format_name = "ssh", .protocol_name = "ssh", @@ -1270,6 +1281,7 @@ static BlockDriver bdrv_ssh = { .bdrv_co_truncate = ssh_co_truncate, .bdrv_co_flush_to_disk = ssh_co_flush, .create_opts = &ssh_create_opts, + .strong_runtime_opts = ssh_strong_runtime_opts, }; static void bdrv_ssh_init(void) diff --git a/block/throttle.c b/block/throttle.c index 636c9764aa..f64dcc27b9 100644 --- a/block/throttle.c +++ b/block/throttle.c @@ -227,6 +227,12 @@ static void coroutine_fn throttle_co_drain_end(BlockDriverState *bs) atomic_dec(&tgm->io_limits_disabled); } +static const char *const throttle_strong_runtime_opts[] = { + QEMU_OPT_THROTTLE_GROUP_NAME, + + NULL +}; + static BlockDriver bdrv_throttle = { .format_name = "throttle", .instance_size = sizeof(ThrottleGroupMember), @@ -259,6 +265,7 @@ static BlockDriver bdrv_throttle = { .bdrv_co_drain_end = throttle_co_drain_end, .is_filter = true, + .strong_runtime_opts = throttle_strong_runtime_opts, }; static void bdrv_throttle_init(void) diff --git a/block/vhdx-log.c b/block/vhdx-log.c index ecd64266c5..3149ff08d8 100644 --- a/block/vhdx-log.c +++ b/block/vhdx-log.c @@ -803,6 +803,7 @@ int vhdx_parse_log(BlockDriverState *bs, BDRVVHDXState *s, bool *flushed, if (logs.valid) { if (bs->read_only) { + bdrv_refresh_filename(bs); ret = -EPERM; error_setg(errp, "VHDX image file '%s' opened read-only, but " diff --git a/block/vmdk.c b/block/vmdk.c index 41048741cd..d8c0c50390 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -27,6 +27,7 @@ #include "qapi/error.h" #include "block/block_int.h" #include "sysemu/block-backend.h" +#include "qapi/qmp/qdict.h" #include "qapi/qmp/qerror.h" #include "qemu/error-report.h" #include "qemu/module.h" @@ -386,12 +387,14 @@ static int vmdk_parent_open(BlockDriverState *bs) ret = -EINVAL; goto out; } - if ((end_name - p_name) > sizeof(bs->backing_file) - 1) { + if ((end_name - p_name) > sizeof(bs->auto_backing_file) - 1) { ret = -EINVAL; goto out; } - pstrcpy(bs->backing_file, end_name - p_name + 1, p_name); + pstrcpy(bs->auto_backing_file, end_name - p_name + 1, p_name); + pstrcpy(bs->backing_file, sizeof(bs->backing_file), + bs->auto_backing_file); } out: @@ -479,6 +482,7 @@ static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent, extent->l1_table, l1_size); if (ret < 0) { + bdrv_refresh_filename(extent->file->bs); error_setg_errno(errp, -ret, "Could not read l1 table from extent '%s'", extent->file->bs->filename); @@ -499,6 +503,7 @@ static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent, extent->l1_backup_table, l1_size); if (ret < 0) { + bdrv_refresh_filename(extent->file->bs); error_setg_errno(errp, -ret, "Could not read l1 backup table from extent '%s'", extent->file->bs->filename); @@ -530,6 +535,7 @@ static int vmdk_open_vmfs_sparse(BlockDriverState *bs, ret = bdrv_pread(file, sizeof(magic), &header, sizeof(header)); if (ret < 0) { + bdrv_refresh_filename(file->bs); error_setg_errno(errp, -ret, "Could not read header from file '%s'", file->bs->filename); @@ -607,6 +613,7 @@ static int vmdk_open_vmdk4(BlockDriverState *bs, ret = bdrv_pread(file, sizeof(magic), &header, sizeof(header)); if (ret < 0) { + bdrv_refresh_filename(file->bs); error_setg_errno(errp, -ret, "Could not read header from file '%s'", file->bs->filename); @@ -861,13 +868,13 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, if (!path_is_absolute(fname) && !path_has_protocol(fname) && !desc_file_path[0]) { + bdrv_refresh_filename(bs->file->bs); error_setg(errp, "Cannot use relative extent paths with VMDK " "descriptor file '%s'", bs->file->bs->filename); return -EINVAL; } - extent_path = g_malloc0(PATH_MAX); - path_combine(extent_path, PATH_MAX, desc_file_path, fname); + extent_path = path_combine(desc_file_path, fname); ret = snprintf(extent_opt_prefix, 32, "extents.%d", s->num_extents); assert(ret < 32); @@ -2067,16 +2074,16 @@ static int coroutine_fn vmdk_co_do_create(int64_t size, if (backing_file) { BlockBackend *backing; - char *full_backing = g_new0(char, PATH_MAX); - bdrv_get_full_backing_filename_from_filename(blk_bs(blk)->filename, backing_file, - full_backing, PATH_MAX, - &local_err); + char *full_backing = + bdrv_get_full_backing_filename_from_filename(blk_bs(blk)->filename, + backing_file, + &local_err); if (local_err) { - g_free(full_backing); error_propagate(errp, local_err); ret = -ENOENT; goto exit; } + assert(full_backing); backing = blk_new_open(full_backing, NULL, NULL, BDRV_O_NO_BACKING, errp); @@ -2255,7 +2262,7 @@ static int coroutine_fn vmdk_co_create_opts(const char *filename, QemuOpts *opts compat6 = qemu_opt_get_bool_del(opts, BLOCK_OPT_COMPAT6, false); if (strcmp(hw_version, "undefined") == 0) { g_free(hw_version); - hw_version = g_strdup("4"); + hw_version = NULL; } fmt = qemu_opt_get_del(opts, BLOCK_OPT_SUBFMT); zeroed_grain = qemu_opt_get_bool_del(opts, BLOCK_OPT_ZEROED_GRAIN, false); @@ -2465,6 +2472,7 @@ static ImageInfo *vmdk_get_extent_info(VmdkExtent *extent) { ImageInfo *info = g_new0(ImageInfo, 1); + bdrv_refresh_filename(extent->file->bs); *info = (ImageInfo){ .filename = g_strdup(extent->file->bs->filename), .format = g_strdup(extent->type), @@ -2596,6 +2604,23 @@ static int vmdk_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) return 0; } +static void vmdk_gather_child_options(BlockDriverState *bs, QDict *target, + bool backing_overridden) +{ + /* No children but file and backing can be explicitly specified (TODO) */ + qdict_put(target, "file", + qobject_ref(bs->file->bs->full_open_options)); + + if (backing_overridden) { + if (bs->backing) { + qdict_put(target, "backing", + qobject_ref(bs->backing->bs->full_open_options)); + } else { + qdict_put_null(target, "backing"); + } + } +} + static QemuOptsList vmdk_create_opts = { .name = "vmdk-create-opts", .head = QTAILQ_HEAD_INITIALIZER(vmdk_create_opts.head), @@ -2667,6 +2692,7 @@ static BlockDriver bdrv_vmdk = { .bdrv_get_specific_info = vmdk_get_specific_info, .bdrv_refresh_limits = vmdk_refresh_limits, .bdrv_get_info = vmdk_get_info, + .bdrv_gather_child_options = vmdk_gather_child_options, .supports_backing = true, .create_opts = &vmdk_create_opts, diff --git a/block/vpc.c b/block/vpc.c index 52ab717642..a902a4c54d 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -1218,6 +1218,12 @@ static QemuOptsList vpc_create_opts = { } }; +static const char *const vpc_strong_runtime_opts[] = { + VPC_OPT_SIZE_CALC, + + NULL +}; + static BlockDriver bdrv_vpc = { .format_name = "vpc", .instance_size = sizeof(BDRVVPCState), @@ -1238,6 +1244,7 @@ static BlockDriver bdrv_vpc = { .create_opts = &vpc_create_opts, .bdrv_has_zero_init = vpc_has_zero_init, + .strong_runtime_opts = vpc_strong_runtime_opts, }; static void bdrv_vpc_init(void) diff --git a/block/vvfat.c b/block/vvfat.c index b7b61ea8b7..5f66787890 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -3253,6 +3253,16 @@ static void vvfat_close(BlockDriverState *bs) } } +static const char *const vvfat_strong_runtime_opts[] = { + "dir", + "fat-type", + "floppy", + "label", + "rw", + + NULL +}; + static BlockDriver bdrv_vvfat = { .format_name = "vvfat", .protocol_name = "fat", @@ -3267,6 +3277,8 @@ static BlockDriver bdrv_vvfat = { .bdrv_co_preadv = vvfat_co_preadv, .bdrv_co_pwritev = vvfat_co_pwritev, .bdrv_co_block_status = vvfat_co_block_status, + + .strong_runtime_opts = vvfat_strong_runtime_opts, }; static void bdrv_vvfat_init(void) diff --git a/block/vxhs.c b/block/vxhs.c index 0cb0a007e9..2e18229ba4 100644 --- a/block/vxhs.c +++ b/block/vxhs.c @@ -556,6 +556,16 @@ static int64_t vxhs_getlength(BlockDriverState *bs) return vdisk_size; } +static const char *const vxhs_strong_runtime_opts[] = { + VXHS_OPT_VDISK_ID, + "tls-creds", + VXHS_OPT_HOST, + VXHS_OPT_PORT, + VXHS_OPT_SERVER".", + + NULL +}; + static BlockDriver bdrv_vxhs = { .format_name = "vxhs", .protocol_name = "vxhs", @@ -567,6 +577,7 @@ static BlockDriver bdrv_vxhs = { .bdrv_getlength = vxhs_getlength, .bdrv_aio_preadv = vxhs_aio_preadv, .bdrv_aio_pwritev = vxhs_aio_pwritev, + .strong_runtime_opts = vxhs_strong_runtime_opts, }; static void bdrv_vxhs_init(void) |