diff options
author | Peter Maydell | 2021-06-02 20:34:03 +0200 |
---|---|---|
committer | Peter Maydell | 2021-06-02 20:34:03 +0200 |
commit | 8e6dad2028d01b7f9ec76cf3b83457fab57fa1eb (patch) | |
tree | ac09be5943257532c1ea60ed028f501fd76d8eab /block | |
parent | Merge remote-tracking branch 'remotes/thuth-gitlab/tags/pull-request-2021-06-... (diff) | |
parent | docs/secure-coding-practices: Describe how to use 'null-co' block driver (diff) | |
download | qemu-8e6dad2028d01b7f9ec76cf3b83457fab57fa1eb.tar.gz qemu-8e6dad2028d01b7f9ec76cf3b83457fab57fa1eb.tar.xz qemu-8e6dad2028d01b7f9ec76cf3b83457fab57fa1eb.zip |
Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging
Block layer patches
- NBD server: Fix crashes related to switching between AioContexts
- file-posix: Workaround for discard/write_zeroes on buggy filesystems
- Follow-up fixes for the reopen vs. permission changes
- quorum: Fix error handling for flush
- block-copy: Refactor copy_range handling
- docs: Describe how to use 'null-co' block driver
# gpg: Signature made Wed 02 Jun 2021 14:44:15 BST
# 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
* remotes/kevin/tags/for-upstream:
docs/secure-coding-practices: Describe how to use 'null-co' block driver
block-copy: refactor copy_range handling
block-copy: fix block_copy_task_entry() progress update
nbd/server: Use drained block ops to quiesce the server
block-backend: add drained_poll
block: improve permission conflict error message
block: simplify bdrv_child_user_desc()
block/vvfat: inherit child_vvfat_qcow from child_of_bds
block: improve bdrv_child_get_parent_desc()
block-backend: improve blk_root_get_parent_desc()
block: document child argument of bdrv_attach_child_common()
block/file-posix: Try other fallbacks after invalid FALLOC_FL_ZERO_RANGE
block/file-posix: Fix problem with fallocate(PUNCH_HOLE) on GPFS
block: drop BlockBackendRootState::read_only
block: drop BlockDriverState::read_only
block: consistently use bdrv_is_read_only()
block/vvfat: fix vvfat_child_perm crash
block/vvfat: child_vvfat_qcow: add .get_parent_aio_context, fix crash
qemu-io-cmds: assert that we don't have .perm requested in no-blk case
block/quorum: Provide .bdrv_co_flush instead of .bdrv_co_flush_to_disk
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'block')
-rw-r--r-- | block/block-backend.c | 26 | ||||
-rw-r--r-- | block/block-copy.c | 80 | ||||
-rw-r--r-- | block/commit.c | 2 | ||||
-rw-r--r-- | block/file-posix.c | 29 | ||||
-rw-r--r-- | block/io.c | 4 | ||||
-rw-r--r-- | block/qapi.c | 2 | ||||
-rw-r--r-- | block/qcow2-snapshot.c | 2 | ||||
-rw-r--r-- | block/qcow2.c | 5 | ||||
-rw-r--r-- | block/quorum.c | 2 | ||||
-rw-r--r-- | block/snapshot.c | 2 | ||||
-rw-r--r-- | block/vhdx-log.c | 2 | ||||
-rw-r--r-- | block/vvfat.c | 14 |
12 files changed, 101 insertions, 69 deletions
diff --git a/block/block-backend.c b/block/block-backend.c index de5496af66..15f1ea4288 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -141,19 +141,18 @@ static void blk_root_set_aio_ctx(BdrvChild *child, AioContext *ctx, static char *blk_root_get_parent_desc(BdrvChild *child) { BlockBackend *blk = child->opaque; - char *dev_id; + g_autofree char *dev_id = NULL; if (blk->name) { - return g_strdup(blk->name); + return g_strdup_printf("block device '%s'", blk->name); } dev_id = blk_get_attached_dev_id(blk); if (*dev_id) { - return dev_id; + return g_strdup_printf("block device '%s'", dev_id); } else { /* TODO Callback into the BB owner for something more detailed */ - g_free(dev_id); - return g_strdup("a block device"); + return g_strdup("an unnamed block device"); } } @@ -1852,7 +1851,7 @@ bool blk_supports_write_perm(BlockBackend *blk) if (bs) { return !bdrv_is_read_only(bs); } else { - return !blk->root_state.read_only; + return blk->root_state.open_flags & BDRV_O_RDWR; } } @@ -2269,7 +2268,6 @@ void blk_update_root_state(BlockBackend *blk) assert(blk->root); blk->root_state.open_flags = blk->root->bs->open_flags; - blk->root_state.read_only = blk->root->bs->read_only; blk->root_state.detect_zeroes = blk->root->bs->detect_zeroes; } @@ -2288,12 +2286,7 @@ bool blk_get_detect_zeroes_from_root_state(BlockBackend *blk) */ int blk_get_open_flags_from_root_state(BlockBackend *blk) { - int bs_flags; - - bs_flags = blk->root_state.read_only ? 0 : BDRV_O_RDWR; - bs_flags |= blk->root_state.open_flags & ~BDRV_O_RDWR; - - return bs_flags; + return blk->root_state.open_flags; } BlockBackendRootState *blk_get_root_state(BlockBackend *blk) @@ -2393,8 +2386,13 @@ static void blk_root_drained_begin(BdrvChild *child) static bool blk_root_drained_poll(BdrvChild *child) { BlockBackend *blk = child->opaque; + bool busy = false; assert(blk->quiesce_counter); - return !!blk->in_flight; + + if (blk->dev_ops && blk->dev_ops->drained_poll) { + busy = blk->dev_ops->drained_poll(blk->dev_opaque); + } + return busy || !!blk->in_flight; } static void blk_root_drained_end(BdrvChild *child, int *drained_end_counter) diff --git a/block/block-copy.c b/block/block-copy.c index c2e5090412..5808cfe657 100644 --- a/block/block-copy.c +++ b/block/block-copy.c @@ -65,6 +65,7 @@ typedef struct BlockCopyTask { int64_t offset; int64_t bytes; bool zeroes; + bool copy_range; QLIST_ENTRY(BlockCopyTask) list; CoQueue wait_queue; /* coroutines blocked on this task */ } BlockCopyTask; @@ -183,6 +184,7 @@ static BlockCopyTask *block_copy_task_create(BlockCopyState *s, .call_state = call_state, .offset = offset, .bytes = bytes, + .copy_range = s->use_copy_range, }; qemu_co_queue_init(&task->wait_queue); QLIST_INSERT_HEAD(&s->tasks, task, list); @@ -342,11 +344,18 @@ static coroutine_fn int block_copy_task_run(AioTaskPool *pool, * * No sync here: nor bitmap neighter intersecting requests handling, only copy. * + * @copy_range is an in-out argument: if *copy_range is false, copy_range is not + * done. If *copy_range is true, copy_range is attempted. If the copy_range + * attempt fails, the function falls back to the usual read+write and + * *copy_range is set to false. *copy_range and zeroes must not be true + * simultaneously. + * * Returns 0 on success. */ static int coroutine_fn block_copy_do_copy(BlockCopyState *s, int64_t offset, int64_t bytes, - bool zeroes, bool *error_is_read) + bool zeroes, bool *copy_range, + bool *error_is_read) { int ret; int64_t nbytes = MIN(offset + bytes, s->len) - offset; @@ -359,6 +368,7 @@ static int coroutine_fn block_copy_do_copy(BlockCopyState *s, assert(offset + bytes <= s->len || offset + bytes == QEMU_ALIGN_UP(s->len, s->cluster_size)); assert(nbytes < INT_MAX); + assert(!(*copy_range && zeroes)); if (zeroes) { ret = bdrv_co_pwrite_zeroes(s->target, offset, nbytes, s->write_flags & @@ -370,32 +380,15 @@ static int coroutine_fn block_copy_do_copy(BlockCopyState *s, return ret; } - if (s->use_copy_range) { + if (*copy_range) { ret = bdrv_co_copy_range(s->source, offset, s->target, offset, nbytes, 0, s->write_flags); if (ret < 0) { trace_block_copy_copy_range_fail(s, offset, ret); - s->use_copy_range = false; - s->copy_size = MAX(s->cluster_size, BLOCK_COPY_MAX_BUFFER); + *copy_range = false; /* Fallback to read+write with allocated buffer */ } else { - if (s->use_copy_range) { - /* - * Successful copy-range. Now increase copy_size. copy_range - * does not respect max_transfer (it's a TODO), so we factor - * that in here. - * - * Note: we double-check s->use_copy_range for the case when - * parallel block-copy request unsets it during previous - * bdrv_co_copy_range call. - */ - s->copy_size = - MIN(MAX(s->cluster_size, BLOCK_COPY_MAX_COPY_RANGE), - QEMU_ALIGN_DOWN(block_copy_max_transfer(s->source, - s->target), - s->cluster_size)); - } - goto out; + return 0; } } @@ -431,17 +424,49 @@ out: return ret; } +static void block_copy_handle_copy_range_result(BlockCopyState *s, + bool is_success) +{ + if (!s->use_copy_range) { + /* already disabled */ + return; + } + + if (is_success) { + /* + * Successful copy-range. Now increase copy_size. copy_range + * does not respect max_transfer (it's a TODO), so we factor + * that in here. + */ + s->copy_size = + MIN(MAX(s->cluster_size, BLOCK_COPY_MAX_COPY_RANGE), + QEMU_ALIGN_DOWN(block_copy_max_transfer(s->source, + s->target), + s->cluster_size)); + } else { + /* Copy-range failed, disable it. */ + s->use_copy_range = false; + s->copy_size = MAX(s->cluster_size, BLOCK_COPY_MAX_BUFFER); + } +} + static coroutine_fn int block_copy_task_entry(AioTask *task) { BlockCopyTask *t = container_of(task, BlockCopyTask, task); bool error_is_read = false; + bool copy_range = t->copy_range; int ret; ret = block_copy_do_copy(t->s, t->offset, t->bytes, t->zeroes, - &error_is_read); - if (ret < 0 && !t->call_state->ret) { - t->call_state->ret = ret; - t->call_state->error_is_read = error_is_read; + ©_range, &error_is_read); + if (t->copy_range) { + block_copy_handle_copy_range_result(t->s, copy_range); + } + if (ret < 0) { + if (!t->call_state->ret) { + t->call_state->ret = ret; + t->call_state->error_is_read = error_is_read; + } } else { progress_work_done(t->s->progress, t->bytes); } @@ -617,7 +642,10 @@ block_copy_dirty_clusters(BlockCopyCallState *call_state) g_free(task); continue; } - task->zeroes = ret & BDRV_BLOCK_ZERO; + if (ret & BDRV_BLOCK_ZERO) { + task->zeroes = true; + task->copy_range = false; + } if (s->speed) { if (!call_state->ignore_ratelimit) { diff --git a/block/commit.c b/block/commit.c index b89bb20b75..b7f0c7c061 100644 --- a/block/commit.c +++ b/block/commit.c @@ -453,7 +453,7 @@ int bdrv_commit(BlockDriverState *bs) return -EBUSY; } - ro = backing_file_bs->read_only; + ro = bdrv_is_read_only(backing_file_bs); if (ro) { if (bdrv_reopen_set_read_only(backing_file_bs, false, NULL)) { diff --git a/block/file-posix.c b/block/file-posix.c index 10b71d9a13..f37dfc10b3 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -1625,17 +1625,17 @@ static int handle_aiocb_write_zeroes(void *opaque) if (s->has_write_zeroes) { int ret = do_fallocate(s->fd, FALLOC_FL_ZERO_RANGE, aiocb->aio_offset, aiocb->aio_nbytes); - if (ret == -EINVAL) { - /* - * Allow falling back to pwrite for file systems that - * do not support fallocate() for an unaligned byte range. - */ - return -ENOTSUP; - } - if (ret == 0 || ret != -ENOTSUP) { + if (ret == -ENOTSUP) { + s->has_write_zeroes = false; + } else if (ret == 0 || ret != -EINVAL) { return ret; } - s->has_write_zeroes = false; + /* + * Note: Some file systems do not like unaligned byte ranges, and + * return EINVAL in such a case, though they should not do it according + * to the man-page of fallocate(). Thus we simply ignore this return + * value and try the other fallbacks instead. + */ } #endif @@ -1650,6 +1650,17 @@ static int handle_aiocb_write_zeroes(void *opaque) return ret; } s->has_fallocate = false; + } else if (ret == -EINVAL) { + /* + * Some file systems like older versions of GPFS do not like un- + * aligned byte ranges, and return EINVAL in such a case, though + * they should not do it according to the man-page of fallocate(). + * Warn about the bad filesystem and try the final fallback instead. + */ + warn_report_once("Your file system is misbehaving: " + "fallocate(FALLOC_FL_PUNCH_HOLE) returned EINVAL. " + "Please report this bug to your file sytem " + "vendor."); } else if (ret != -ENOTSUP) { return ret; } else { diff --git a/block/io.c b/block/io.c index 1e826ba9e8..323854d063 100644 --- a/block/io.c +++ b/block/io.c @@ -1973,7 +1973,7 @@ bdrv_co_write_req_prepare(BdrvChild *child, int64_t offset, int64_t bytes, bdrv_check_request(offset, bytes, &error_abort); - if (bs->read_only) { + if (bdrv_is_read_only(bs)) { return -EPERM; } @@ -3406,7 +3406,7 @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact, if (new_bytes) { bdrv_make_request_serialising(&req, 1); } - if (bs->read_only) { + if (bdrv_is_read_only(bs)) { error_setg(errp, "Image is read-only"); ret = -EACCES; goto out; diff --git a/block/qapi.c b/block/qapi.c index 943e7b15ad..dc69341bfe 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -59,7 +59,7 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk, info = g_malloc0(sizeof(*info)); info->file = g_strdup(bs->filename); - info->ro = bs->read_only; + info->ro = bdrv_is_read_only(bs); info->drv = g_strdup(bs->drv->format_name); info->encrypted = bs->encrypted; diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c index 2e98c7f4b6..71ddb08c21 100644 --- a/block/qcow2-snapshot.c +++ b/block/qcow2-snapshot.c @@ -1026,7 +1026,7 @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs, int new_l1_bytes; int ret; - assert(bs->read_only); + assert(bdrv_is_read_only(bs)); /* Search the snapshot */ snapshot_index = find_snapshot_by_id_and_name(bs, snapshot_id, name); diff --git a/block/qcow2.c b/block/qcow2.c index 39b91ef940..ee4530cdbd 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1723,8 +1723,7 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, /* Clear unknown autoclear feature bits */ update_header |= s->autoclear_features & ~QCOW2_AUTOCLEAR_MASK; - update_header = - update_header && !bs->read_only && !(flags & BDRV_O_INACTIVE); + update_header = update_header && bdrv_is_writable(bs); if (update_header) { s->autoclear_features &= QCOW2_AUTOCLEAR_MASK; } @@ -1811,7 +1810,7 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options, bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE; /* Repair image if dirty */ - if (!(flags & (BDRV_O_CHECK | BDRV_O_INACTIVE)) && !bs->read_only && + if (!(flags & BDRV_O_CHECK) && bdrv_is_writable(bs) && (s->incompatible_features & QCOW2_INCOMPAT_DIRTY)) { BdrvCheckResult result = {0}; diff --git a/block/quorum.c b/block/quorum.c index cfc1436abb..f2c0805000 100644 --- a/block/quorum.c +++ b/block/quorum.c @@ -1279,7 +1279,7 @@ static BlockDriver bdrv_quorum = { .bdrv_dirname = quorum_dirname, .bdrv_co_block_status = quorum_co_block_status, - .bdrv_co_flush_to_disk = quorum_co_flush, + .bdrv_co_flush = quorum_co_flush, .bdrv_getlength = quorum_getlength, diff --git a/block/snapshot.c b/block/snapshot.c index e8ae9a28c1..6702c75e42 100644 --- a/block/snapshot.c +++ b/block/snapshot.c @@ -415,7 +415,7 @@ int bdrv_snapshot_load_tmp(BlockDriverState *bs, error_setg(errp, "snapshot_id and name are both NULL"); return -EINVAL; } - if (!bs->read_only) { + if (!bdrv_is_read_only(bs)) { error_setg(errp, "Device is not readonly"); return -EINVAL; } diff --git a/block/vhdx-log.c b/block/vhdx-log.c index 404fb5f3cb..7672161d95 100644 --- a/block/vhdx-log.c +++ b/block/vhdx-log.c @@ -801,7 +801,7 @@ int vhdx_parse_log(BlockDriverState *bs, BDRVVHDXState *s, bool *flushed, } if (logs.valid) { - if (bs->read_only) { + if (bdrv_is_read_only(bs)) { bdrv_refresh_filename(bs); ret = -EPERM; error_setg(errp, diff --git a/block/vvfat.c b/block/vvfat.c index 54807f82ca..ae9d387da7 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -3127,10 +3127,7 @@ static void vvfat_qcow_options(BdrvChildRole role, bool parent_is_format, qdict_set_default_str(child_options, BDRV_OPT_CACHE_NO_FLUSH, "on"); } -static const BdrvChildClass child_vvfat_qcow = { - .parent_is_bds = true, - .inherit_options = vvfat_qcow_options, -}; +static BdrvChildClass child_vvfat_qcow; static int enable_write_target(BlockDriverState *bs, Error **errp) { @@ -3208,15 +3205,12 @@ static void vvfat_child_perm(BlockDriverState *bs, BdrvChild *c, uint64_t perm, uint64_t shared, uint64_t *nperm, uint64_t *nshared) { - BDRVVVFATState *s = bs->opaque; - - assert(c == s->qcow || (role & BDRV_CHILD_COW)); - - if (c == s->qcow) { + if (role & BDRV_CHILD_DATA) { /* This is a private node, nobody should try to attach to it */ *nperm = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE; *nshared = BLK_PERM_WRITE_UNCHANGED; } else { + assert(role & BDRV_CHILD_COW); /* The backing file is there so 'commit' can use it. vvfat doesn't * access it in any way. */ *nperm = 0; @@ -3270,6 +3264,8 @@ static BlockDriver bdrv_vvfat = { static void bdrv_vvfat_init(void) { + child_vvfat_qcow = child_of_bds; + child_vvfat_qcow.inherit_options = vvfat_qcow_options; bdrv_register(&bdrv_vvfat); } |