aboutsummaryrefslogtreecommitdiff
path: root/block
diff options
context:
space:
mode:
authorVladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>2019-09-16 20:53:22 +0300
committerMax Reitz <mreitz@redhat.com>2019-10-10 10:56:17 +0200
commit88f468e54696cd9ffc28ecf96f18f04125402541 (patch)
tree6c460d5526009f18fb4a8f214f5a5fe298496463 /block
parent6e9b225f737d53afae8160d73da72ee8f38eb1a6 (diff)
block/qcow2: refactor qcow2_co_preadv_part
Further patch will run partial requests of iterations of qcow2_co_preadv in parallel for performance reasons. To prepare for this, separate part which may be parallelized into separate function (qcow2_co_preadv_task). While being here, also separate encrypted clusters reading to own function, like it is done for compressed reading. Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> Reviewed-by: Max Reitz <mreitz@redhat.com> Message-id: 20190916175324.18478-4-vsementsov@virtuozzo.com Signed-off-by: Max Reitz <mreitz@redhat.com>
Diffstat (limited to 'block')
-rw-r--r--block/qcow2.c209
1 files changed, 113 insertions, 96 deletions
diff --git a/block/qcow2.c b/block/qcow2.c
index 4d16393e61..6feb169f7c 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -1972,17 +1972,117 @@ out:
return ret;
}
+static coroutine_fn int
+qcow2_co_preadv_encrypted(BlockDriverState *bs,
+ uint64_t file_cluster_offset,
+ uint64_t offset,
+ uint64_t bytes,
+ QEMUIOVector *qiov,
+ uint64_t qiov_offset)
+{
+ int ret;
+ BDRVQcow2State *s = bs->opaque;
+ uint8_t *buf;
+
+ assert(bs->encrypted && s->crypto);
+ assert(bytes <= QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size);
+
+ /*
+ * For encrypted images, read everything into a temporary
+ * contiguous buffer on which the AES functions can work.
+ * Also, decryption in a separate buffer is better as it
+ * prevents the guest from learning information about the
+ * encrypted nature of the virtual disk.
+ */
+
+ buf = qemu_try_blockalign(s->data_file->bs, bytes);
+ if (buf == NULL) {
+ return -ENOMEM;
+ }
+
+ BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
+ ret = bdrv_co_pread(s->data_file,
+ file_cluster_offset + offset_into_cluster(s, offset),
+ bytes, buf, 0);
+ if (ret < 0) {
+ goto fail;
+ }
+
+ assert(QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE));
+ assert(QEMU_IS_ALIGNED(bytes, BDRV_SECTOR_SIZE));
+ if (qcow2_co_decrypt(bs,
+ file_cluster_offset + offset_into_cluster(s, offset),
+ offset, buf, bytes) < 0)
+ {
+ ret = -EIO;
+ goto fail;
+ }
+ qemu_iovec_from_buf(qiov, qiov_offset, buf, bytes);
+
+fail:
+ qemu_vfree(buf);
+
+ return ret;
+}
+
+static coroutine_fn int qcow2_co_preadv_task(BlockDriverState *bs,
+ QCow2ClusterType cluster_type,
+ uint64_t file_cluster_offset,
+ uint64_t offset, uint64_t bytes,
+ QEMUIOVector *qiov,
+ size_t qiov_offset)
+{
+ BDRVQcow2State *s = bs->opaque;
+ int offset_in_cluster = offset_into_cluster(s, offset);
+
+ switch (cluster_type) {
+ case QCOW2_CLUSTER_ZERO_PLAIN:
+ case QCOW2_CLUSTER_ZERO_ALLOC:
+ /* Both zero types are handled in qcow2_co_preadv_part */
+ g_assert_not_reached();
+
+ case QCOW2_CLUSTER_UNALLOCATED:
+ assert(bs->backing); /* otherwise handled in qcow2_co_preadv_part */
+
+ BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
+ return bdrv_co_preadv_part(bs->backing, offset, bytes,
+ qiov, qiov_offset, 0);
+
+ case QCOW2_CLUSTER_COMPRESSED:
+ return qcow2_co_preadv_compressed(bs, file_cluster_offset,
+ offset, bytes, qiov, qiov_offset);
+
+ case QCOW2_CLUSTER_NORMAL:
+ if ((file_cluster_offset & 511) != 0) {
+ return -EIO;
+ }
+
+ if (bs->encrypted) {
+ return qcow2_co_preadv_encrypted(bs, file_cluster_offset,
+ offset, bytes, qiov, qiov_offset);
+ }
+
+ BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
+ return bdrv_co_preadv_part(s->data_file,
+ file_cluster_offset + offset_in_cluster,
+ bytes, qiov, qiov_offset, 0);
+
+ default:
+ g_assert_not_reached();
+ }
+
+ g_assert_not_reached();
+}
+
static coroutine_fn int qcow2_co_preadv_part(BlockDriverState *bs,
uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov,
size_t qiov_offset, int flags)
{
BDRVQcow2State *s = bs->opaque;
- int offset_in_cluster;
int ret;
unsigned int cur_bytes; /* number of bytes in current iteration */
uint64_t cluster_offset = 0;
- uint8_t *cluster_data = NULL;
while (bytes != 0) {
@@ -1997,112 +2097,29 @@ static coroutine_fn int qcow2_co_preadv_part(BlockDriverState *bs,
ret = qcow2_get_cluster_offset(bs, offset, &cur_bytes, &cluster_offset);
qemu_co_mutex_unlock(&s->lock);
if (ret < 0) {
- goto fail;
+ return ret;
}
- offset_in_cluster = offset_into_cluster(s, offset);
-
- switch (ret) {
- case QCOW2_CLUSTER_UNALLOCATED:
-
- if (bs->backing) {
- BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
- ret = bdrv_co_preadv_part(bs->backing, offset, cur_bytes,
- qiov, qiov_offset, 0);
- if (ret < 0) {
- goto fail;
- }
- } else {
- /* Note: in this case, no need to wait */
- qemu_iovec_memset(qiov, qiov_offset, 0, cur_bytes);
- }
- break;
-
- case QCOW2_CLUSTER_ZERO_PLAIN:
- case QCOW2_CLUSTER_ZERO_ALLOC:
+ if (ret == QCOW2_CLUSTER_ZERO_PLAIN ||
+ ret == QCOW2_CLUSTER_ZERO_ALLOC ||
+ (ret == QCOW2_CLUSTER_UNALLOCATED && !bs->backing))
+ {
qemu_iovec_memset(qiov, qiov_offset, 0, cur_bytes);
- break;
-
- case QCOW2_CLUSTER_COMPRESSED:
- ret = qcow2_co_preadv_compressed(bs, cluster_offset,
- offset, cur_bytes,
- qiov, qiov_offset);
+ } else {
+ ret = qcow2_co_preadv_task(bs, ret,
+ cluster_offset, offset, cur_bytes,
+ qiov, qiov_offset);
if (ret < 0) {
- goto fail;
- }
-
- break;
-
- case QCOW2_CLUSTER_NORMAL:
- if ((cluster_offset & 511) != 0) {
- ret = -EIO;
- goto fail;
- }
-
- if (bs->encrypted) {
- assert(s->crypto);
-
- /*
- * For encrypted images, read everything into a temporary
- * contiguous buffer on which the AES functions can work.
- */
- if (!cluster_data) {
- cluster_data =
- qemu_try_blockalign(s->data_file->bs,
- QCOW_MAX_CRYPT_CLUSTERS
- * s->cluster_size);
- if (cluster_data == NULL) {
- ret = -ENOMEM;
- goto fail;
- }
- }
-
- assert(cur_bytes <= QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size);
-
- BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
- ret = bdrv_co_pread(s->data_file,
- cluster_offset + offset_in_cluster,
- cur_bytes, cluster_data, 0);
- if (ret < 0) {
- goto fail;
- }
-
- assert(QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE));
- assert(QEMU_IS_ALIGNED(cur_bytes, BDRV_SECTOR_SIZE));
- if (qcow2_co_decrypt(bs, cluster_offset + offset_in_cluster,
- offset,
- cluster_data, cur_bytes) < 0) {
- ret = -EIO;
- goto fail;
- }
- qemu_iovec_from_buf(qiov, qiov_offset, cluster_data, cur_bytes);
- } else {
- BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
- ret = bdrv_co_preadv_part(s->data_file,
- cluster_offset + offset_in_cluster,
- cur_bytes, qiov, qiov_offset, 0);
- if (ret < 0) {
- goto fail;
- }
+ return ret;
}
- break;
-
- default:
- g_assert_not_reached();
- ret = -EIO;
- goto fail;
}
bytes -= cur_bytes;
offset += cur_bytes;
qiov_offset += cur_bytes;
}
- ret = 0;
-
-fail:
- qemu_vfree(cluster_data);
- return ret;
+ return 0;
}
/* Check if it's possible to merge a write request with the writing of