[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-block] [PATCH 5/7] qcow2: Allow reading both COW regions with only
From: |
Alberto Garcia |
Subject: |
[Qemu-block] [PATCH 5/7] qcow2: Allow reading both COW regions with only one request |
Date: |
Tue, 23 May 2017 13:23:00 +0200 |
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>
---
block/qcow2-cluster.c | 41 ++++++++++++++++++++++++++++++-----------
1 file changed, 30 insertions(+), 11 deletions(-)
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 643c48088b..67a761731d 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -777,34 +777,53 @@ static int perform_cow(BlockDriverState *bs, QCowL2Meta
*m)
Qcow2COWRegion *start = &m->cow_start;
Qcow2COWRegion *end = &m->cow_end;
unsigned buffer_size = start->nb_bytes + end->nb_bytes;
+ unsigned data_bytes = end->offset - (start->offset + start->nb_bytes);
+ bool merge_reads = false;
uint8_t *start_buffer, *end_buffer;
int ret;
assert(start->nb_bytes <= UINT_MAX - end->nb_bytes);
+ assert(buffer_size <= 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 */
+ /* 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 */
+ if (start->nb_bytes && end->nb_bytes && data_bytes <= 16384) {
+ merge_reads = true;
+ buffer_size += data_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;
}
/* The part of the buffer where the end region is located */
- end_buffer = start_buffer + start->nb_bytes;
+ 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;
}
--
2.11.0
- [Qemu-block] [PATCH 0/7] qcow2: Reduce the number of I/O ops when doing COW, Alberto Garcia, 2017/05/23
- [Qemu-block] [PATCH 1/7] qcow2: Remove unused Error in do_perform_cow(), Alberto Garcia, 2017/05/23
- [Qemu-block] [PATCH 5/7] qcow2: Allow reading both COW regions with only one request,
Alberto Garcia <=
- [Qemu-block] [PATCH 6/7] qcow2: Pass a QEMUIOVector to do_perform_cow_{read, write}(), Alberto Garcia, 2017/05/23
- [Qemu-block] [PATCH 2/7] qcow2: Use unsigned int for both members of Qcow2COWRegion, Alberto Garcia, 2017/05/23
- [Qemu-block] [PATCH 7/7] qcow2: Merge the writing of the COW regions with the guest data, Alberto Garcia, 2017/05/23
- Re: [Qemu-block] [PATCH 7/7] qcow2: Merge the writing of the COW regions with the guest data, Alberto Garcia, 2017/05/26
[Qemu-block] [PATCH 3/7] qcow2: Make perform_cow() call do_perform_cow() twice, Alberto Garcia, 2017/05/23