mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-04 08:13:54 -06:00
qcow2: Order concurrent AIO requests on the same unallocated cluster
When two AIO requests write to the same cluster, and this cluster is unallocated, currently both requests allocate a new cluster and the second one merges the first one when it is completed. This means an cluster allocation, a read and a cluster deallocation which cause some overhead. If we simply let the second request wait until the first one is done, we improve overall performance with AIO requests (specifially, qcow2/virtio combinations). This patch maintains a list of in-flight requests that have allocated new clusters. A second request touching the same cluster is limited so that it either doesn't touch the allocation of the first request (so it can have a non-overlapping allocation) or it waits for the first request to complete. Signed-off-by: Kevin Wolf <kwolf@redhat.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
parent
ea80b906f4
commit
f214978a42
3 changed files with 96 additions and 5 deletions
|
@ -684,6 +684,7 @@ uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs,
|
|||
int l2_index, ret;
|
||||
uint64_t l2_offset, *l2_table, cluster_offset;
|
||||
int nb_clusters, i = 0;
|
||||
QCowL2Meta *old_alloc;
|
||||
|
||||
ret = get_cluster_table(bs, offset, &l2_table, &l2_offset, &l2_index);
|
||||
if (ret == 0)
|
||||
|
@ -732,6 +733,44 @@ uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs,
|
|||
}
|
||||
nb_clusters = i;
|
||||
|
||||
/*
|
||||
* Check if there already is an AIO write request in flight which allocates
|
||||
* the same cluster. In this case we need to wait until the previous
|
||||
* request has completed and updated the L2 table accordingly.
|
||||
*/
|
||||
LIST_FOREACH(old_alloc, &s->cluster_allocs, next_in_flight) {
|
||||
|
||||
uint64_t end_offset = offset + nb_clusters * s->cluster_size;
|
||||
uint64_t old_offset = old_alloc->offset;
|
||||
uint64_t old_end_offset = old_alloc->offset +
|
||||
old_alloc->nb_clusters * s->cluster_size;
|
||||
|
||||
if (end_offset < old_offset || offset > old_end_offset) {
|
||||
/* No intersection */
|
||||
} else {
|
||||
if (offset < old_offset) {
|
||||
/* Stop at the start of a running allocation */
|
||||
nb_clusters = (old_offset - offset) >> s->cluster_bits;
|
||||
} else {
|
||||
nb_clusters = 0;
|
||||
}
|
||||
|
||||
if (nb_clusters == 0) {
|
||||
/* Set dependency and wait for a callback */
|
||||
m->depends_on = old_alloc;
|
||||
m->nb_clusters = 0;
|
||||
*num = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!nb_clusters) {
|
||||
abort();
|
||||
}
|
||||
|
||||
LIST_INSERT_HEAD(&s->cluster_allocs, m, next_in_flight);
|
||||
|
||||
/* allocate a new cluster */
|
||||
|
||||
cluster_offset = qcow2_alloc_clusters(bs, nb_clusters * s->cluster_size);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue