[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-block] [PULL 21/61] qcow2: Allow reading both COW regions with onl
From: |
Kevin Wolf |
Subject: |
[Qemu-block] [PULL 21/61] qcow2: Allow reading both COW regions with only one request |
Date: |
Fri, 23 Jun 2017 18:21:19 +0200 |
From: Alberto Garcia <address@hidden>
Reading both COW regions requires two separate requests, but it's
perfectly possible to merge them and perform only one. This generally
improves performance, particularly on rotating disk drives. The
downside is that the data in the middle region is read but discarded.
This patch takes a conservative approach and only merges reads when
the size of the middle region is <= 16KB.
Signed-off-by: Alberto Garcia <address@hidden>
Reviewed-by: Kevin Wolf <address@hidden>
Signed-off-by: Kevin Wolf <address@hidden>
---
block/qcow2-cluster.c | 51 ++++++++++++++++++++++++++++++++++++++-------------
1 file changed, 38 insertions(+), 13 deletions(-)
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 3c9ace8..20fb531 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -777,20 +777,38 @@ static int perform_cow(BlockDriverState *bs, QCowL2Meta
*m)
Qcow2COWRegion *start = &m->cow_start;
Qcow2COWRegion *end = &m->cow_end;
unsigned buffer_size;
+ unsigned data_bytes = end->offset - (start->offset + start->nb_bytes);
+ bool merge_reads;
uint8_t *start_buffer, *end_buffer;
int ret;
assert(start->nb_bytes <= UINT_MAX - end->nb_bytes);
+ assert(start->nb_bytes + end->nb_bytes <= UINT_MAX - data_bytes);
+ assert(start->offset + start->nb_bytes <= end->offset);
if (start->nb_bytes == 0 && end->nb_bytes == 0) {
return 0;
}
- /* Reserve a buffer large enough to store the data from both the
- * start and end COW regions. Add some padding in the middle if
- * necessary to make sure that the end region is optimally aligned */
- buffer_size = QEMU_ALIGN_UP(start->nb_bytes, bdrv_opt_mem_align(bs)) +
- end->nb_bytes;
+ /* If we have to read both the start and end COW regions and the
+ * middle region is not too large then perform just one read
+ * operation */
+ merge_reads = start->nb_bytes && end->nb_bytes && data_bytes <= 16384;
+ if (merge_reads) {
+ buffer_size = start->nb_bytes + data_bytes + end->nb_bytes;
+ } else {
+ /* If we have to do two reads, add some padding in the middle
+ * if necessary to make sure that the end region is optimally
+ * aligned. */
+ size_t align = bdrv_opt_mem_align(bs);
+ assert(align > 0 && align <= UINT_MAX);
+ assert(QEMU_ALIGN_UP(start->nb_bytes, align) <=
+ UINT_MAX - end->nb_bytes);
+ buffer_size = QEMU_ALIGN_UP(start->nb_bytes, align) + end->nb_bytes;
+ }
+
+ /* Reserve a buffer large enough to store all the data that we're
+ * going to read */
start_buffer = qemu_try_blockalign(bs, buffer_size);
if (start_buffer == NULL) {
return -ENOMEM;
@@ -799,15 +817,22 @@ static int perform_cow(BlockDriverState *bs, QCowL2Meta
*m)
end_buffer = start_buffer + buffer_size - end->nb_bytes;
qemu_co_mutex_unlock(&s->lock);
- /* First we read the existing data from both COW regions */
- ret = do_perform_cow_read(bs, m->offset, start->offset,
- start_buffer, start->nb_bytes);
- if (ret < 0) {
- goto fail;
- }
+ /* First we read the existing data from both COW regions. We
+ * either read the whole region in one go, or the start and end
+ * regions separately. */
+ if (merge_reads) {
+ ret = do_perform_cow_read(bs, m->offset, start->offset,
+ start_buffer, buffer_size);
+ } else {
+ ret = do_perform_cow_read(bs, m->offset, start->offset,
+ start_buffer, start->nb_bytes);
+ if (ret < 0) {
+ goto fail;
+ }
- ret = do_perform_cow_read(bs, m->offset, end->offset,
- end_buffer, end->nb_bytes);
+ ret = do_perform_cow_read(bs, m->offset, end->offset,
+ end_buffer, end->nb_bytes);
+ }
if (ret < 0) {
goto fail;
}
--
1.8.3.1
- [Qemu-block] [PULL 12/61] migration: hold AioContext lock for loadvm qemu_fclose(), (continued)
- [Qemu-block] [PULL 12/61] migration: hold AioContext lock for loadvm qemu_fclose(), Kevin Wolf, 2017/06/23
- [Qemu-block] [PULL 13/61] qemu-iotests: 068: extract _qemu() function, Kevin Wolf, 2017/06/23
- [Qemu-block] [PULL 14/61] qemu-iotests: 068: use -drive/-device instead of -hda, Kevin Wolf, 2017/06/23
- [Qemu-block] [PULL 11/61] virtio-pci: use ioeventfd even when KVM is disabled, Kevin Wolf, 2017/06/23
- [Qemu-block] [PULL 15/61] qemu-iotests: 068: test iothread mode, Kevin Wolf, 2017/06/23
- [Qemu-block] [PULL 17/61] qcow2: Remove unused Error variable in do_perform_cow(), Kevin Wolf, 2017/06/23
- [Qemu-block] [PULL 18/61] qcow2: Use unsigned int for both members of Qcow2COWRegion, Kevin Wolf, 2017/06/23
- [Qemu-block] [PULL 20/61] qcow2: Split do_perform_cow() into _read(), _encrypt() and _write(), Kevin Wolf, 2017/06/23
- [Qemu-block] [PULL 16/61] nvme: Add support for Read Data and Write Data in CMBs., Kevin Wolf, 2017/06/23
- [Qemu-block] [PULL 19/61] qcow2: Make perform_cow() call do_perform_cow() twice, Kevin Wolf, 2017/06/23
- [Qemu-block] [PULL 21/61] qcow2: Allow reading both COW regions with only one request,
Kevin Wolf <=
- [Qemu-block] [PULL 22/61] qcow2: Pass a QEMUIOVector to do_perform_cow_{read, write}(), Kevin Wolf, 2017/06/23
- [Qemu-block] [PULL 26/61] qed: Make qed_read_table() synchronous, Kevin Wolf, 2017/06/23
- [Qemu-block] [PULL 24/61] qcow2: Use offset_into_cluster() and offset_to_l2_index(), Kevin Wolf, 2017/06/23
- [Qemu-block] [PULL 25/61] qed: Use bottom half to resume waiting requests, Kevin Wolf, 2017/06/23
- [Qemu-block] [PULL 27/61] qed: Remove callback from qed_read_table(), Kevin Wolf, 2017/06/23
- [Qemu-block] [PULL 23/61] qcow2: Merge the writing of the COW regions with the guest data, Kevin Wolf, 2017/06/23
- [Qemu-block] [PULL 28/61] qed: Remove callback from qed_read_l2_table(), Kevin Wolf, 2017/06/23
- [Qemu-block] [PULL 29/61] qed: Remove callback from qed_find_cluster(), Kevin Wolf, 2017/06/23
- [Qemu-block] [PULL 30/61] qed: Make qed_read_backing_file() synchronous, Kevin Wolf, 2017/06/23
- [Qemu-block] [PULL 31/61] qed: Make qed_copy_from_backing_file() synchronous, Kevin Wolf, 2017/06/23