bdrv_co_truncate() checks that BDRV_O_NO_IO is not set and that the RESIZE permission is available. However, after this series: - We want to set the BDRV_O_NO_IO flag in cases where we can ensure that no I/O will occur to/from the data file, to allow concurrent use of the data file while a qcow2 metadata image is put on top. - We want to take the RESIZE permission only when we are actually going to resize the data file, i.e. when it is not big enough yet.
By calling qcow2_co_truncate() directly, we bypass these checks. That is OK because qcow2_co_create() is the sole owner and user of this qcow2 BDS. (For example, taking the right permissions on it does not matter if it is impossible for there to be another user.) Note that qcow2_co_truncate() takes a signed int64_t, whereas qcow2_opts->size is uint64_t, so we should add an explicit check for overflow. iotest 206's output changes accordingly. Signed-off-by: Hanna Czenczek <[email protected]> --- block/qcow2.c | 17 +++++++++++++++-- tests/qemu-iotests/206.out | 6 +++--- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index 2ab5a9e0f1..dd0f47c0ff 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -82,6 +82,10 @@ qcow2_co_preadv_compressed(BlockDriverState *bs, QEMUIOVector *qiov, size_t qiov_offset); +static int coroutine_fn GRAPH_RDLOCK +qcow2_co_truncate(BlockDriverState *bs, int64_t offset, bool exact, + PreallocMode prealloc, BdrvRequestFlags flags, Error **errp); + static int qcow2_probe(const uint8_t *buf, int buf_size, const char *filename) { const QCowHeader *cow_header = (const void *)buf; @@ -3657,6 +3661,13 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) goto out; } + if (qcow2_opts->size > BDRV_MAX_LENGTH) { + error_setg(errp, "Image size must not exceed %" PRId64 " bytes", + BDRV_MAX_LENGTH); + ret = -EINVAL; + goto out; + } + if (qcow2_opts->has_version) { switch (qcow2_opts->version) { case BLOCKDEV_QCOW2_VERSION_V2: @@ -3939,8 +3950,10 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp) } /* Okay, now that we have a valid image, let's give it the right size */ - ret = blk_co_truncate(blk, qcow2_opts->size, false, - qcow2_opts->preallocation, 0, errp); + bdrv_graph_co_rdlock(); + ret = qcow2_co_truncate(blk_bs(blk), qcow2_opts->size, false, + qcow2_opts->preallocation, 0, errp); + bdrv_graph_co_rdunlock(); if (ret < 0) { error_prepend(errp, "Could not resize image: "); goto out; diff --git a/tests/qemu-iotests/206.out b/tests/qemu-iotests/206.out index 979f00f9bf..46c2d8db97 100644 --- a/tests/qemu-iotests/206.out +++ b/tests/qemu-iotests/206.out @@ -169,19 +169,19 @@ Job failed: Image size must be a multiple of 512 bytes {"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 18446744073709551104}}} {"return": {}} -Job failed: Could not resize image: Image size cannot be negative +Job failed: Image size must not exceed 9223372035781033984 bytes {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} {"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 9223372036854775808}}} {"return": {}} -Job failed: Could not resize image: Image size cannot be negative +Job failed: Image size must not exceed 9223372035781033984 bytes {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} {"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "qcow2", "file": "node0", "size": 9223372036854775296}}} {"return": {}} -Job failed: Could not resize image: offset(9223372036854775296) exceeds maximum(9223372035781033984) +Job failed: Image size must not exceed 9223372035781033984 bytes {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -- 2.53.0
