qcow2: Allocate l2meta only for cluster allocations
Even for writes to already allocated clusters, an l2meta is allocated,
though it stays effectively unused. After this patch, only allocating
requests still have one. Each l2meta now describes an in-flight request
that writes to clusters that are not yet hooked up in the L2 table.
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
diff --git a/block/qcow2.c b/block/qcow2.c
index 66ca12f..08d92cc 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -787,8 +787,7 @@
while (remaining_sectors != 0) {
- l2meta = g_malloc0(sizeof(*l2meta));
- qemu_co_queue_init(&l2meta->dependent_requests);
+ l2meta = NULL;
trace_qcow2_writev_start_part(qemu_coroutine_self());
index_in_cluster = sector_num & (s->cluster_sectors - 1);
@@ -799,7 +798,7 @@
}
ret = qcow2_alloc_cluster_offset(bs, sector_num << 9,
- index_in_cluster, n_end, &cur_nr_sectors, &cluster_offset, l2meta);
+ index_in_cluster, n_end, &cur_nr_sectors, &cluster_offset, &l2meta);
if (ret < 0) {
goto fail;
}
@@ -845,14 +844,16 @@
goto fail;
}
- ret = qcow2_alloc_cluster_link_l2(bs, l2meta);
- if (ret < 0) {
- goto fail;
- }
+ if (l2meta != NULL) {
+ ret = qcow2_alloc_cluster_link_l2(bs, l2meta);
+ if (ret < 0) {
+ goto fail;
+ }
- run_dependent_requests(s, l2meta);
- g_free(l2meta);
- l2meta = NULL;
+ run_dependent_requests(s, l2meta);
+ g_free(l2meta);
+ l2meta = NULL;
+ }
remaining_sectors -= cur_nr_sectors;
sector_num += cur_nr_sectors;
@@ -1134,11 +1135,10 @@
uint64_t host_offset = 0;
int num;
int ret;
- QCowL2Meta meta;
+ QCowL2Meta *meta;
nb_sectors = bdrv_getlength(bs) >> 9;
offset = 0;
- qemu_co_queue_init(&meta.dependent_requests);
while (nb_sectors) {
num = MIN(nb_sectors, INT_MAX >> 9);
@@ -1148,15 +1148,17 @@
return ret;
}
- ret = qcow2_alloc_cluster_link_l2(bs, &meta);
+ ret = qcow2_alloc_cluster_link_l2(bs, meta);
if (ret < 0) {
- qcow2_free_any_clusters(bs, meta.alloc_offset, meta.nb_clusters);
+ qcow2_free_any_clusters(bs, meta->alloc_offset, meta->nb_clusters);
return ret;
}
/* There are no dependent requests, but we need to remove our request
* from the list of in-flight requests */
- run_dependent_requests(bs->opaque, &meta);
+ if (meta != NULL) {
+ run_dependent_requests(bs->opaque, meta);
+ }
/* TODO Preallocate data if requested */