diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index c4752ee812..c2b59e7d6a 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -652,9 +652,7 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m) uint64_t cluster_offset = m->alloc_offset; trace_qcow2_cluster_link_l2(qemu_coroutine_self(), m->nb_clusters); - - if (m->nb_clusters == 0) - return 0; + assert(m->nb_clusters > 0); old_cluster = g_malloc(m->nb_clusters * sizeof(uint64_t)); @@ -856,7 +854,7 @@ static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset, * Return 0 on success and -errno in error cases */ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset, - int n_start, int n_end, int *num, uint64_t *host_offset, QCowL2Meta *m) + int n_start, int n_end, int *num, uint64_t *host_offset, QCowL2Meta **m) { BDRVQcowState *s = bs->opaque; int l2_index, ret, sectors; @@ -928,11 +926,6 @@ again: } /* If there is something left to allocate, do that now */ - *m = (QCowL2Meta) { - .nb_clusters = 0, - }; - qemu_co_queue_init(&m->dependent_requests); - if (nb_clusters > 0) { uint64_t alloc_offset; uint64_t alloc_cluster_offset; @@ -980,7 +973,9 @@ again: cluster_offset = alloc_cluster_offset; } - *m = (QCowL2Meta) { + *m = g_malloc0(sizeof(**m)); + + **m = (QCowL2Meta) { .alloc_offset = alloc_cluster_offset, .offset = alloc_offset & ~(s->cluster_size - 1), .nb_clusters = nb_clusters, @@ -995,8 +990,8 @@ again: .nb_sectors = avail_sectors - nb_sectors, }, }; - qemu_co_queue_init(&m->dependent_requests); - QLIST_INSERT_HEAD(&s->cluster_allocs, m, next_in_flight); + qemu_co_queue_init(&(*m)->dependent_requests); + QLIST_INSERT_HEAD(&s->cluster_allocs, *m, next_in_flight); } } @@ -1013,8 +1008,8 @@ again: return 0; fail: - if (m->nb_clusters > 0) { - QLIST_REMOVE(m, next_in_flight); + if (*m && (*m)->nb_clusters > 0) { + QLIST_REMOVE(*m, next_in_flight); } return ret; } diff --git a/block/qcow2.c b/block/qcow2.c index 66ca12f94e..08d92cc6e3 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -787,8 +787,7 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs, 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 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs, } 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 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs, 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 @@ static int preallocate(BlockDriverState *bs) 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 @@ static int preallocate(BlockDriverState *bs) 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 */ diff --git a/block/qcow2.h b/block/qcow2.h index 24f100125c..6dc79b5af4 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -207,7 +207,10 @@ typedef struct Qcow2COWRegion { int nb_sectors; } Qcow2COWRegion; -/* XXX This could be private for qcow2-cluster.c */ +/** + * Describes an in-flight (part of a) write request that writes to clusters + * that are not referenced in their L2 table yet. + */ typedef struct QCowL2Meta { /** Guest offset of the first newly allocated cluster */ @@ -333,7 +336,7 @@ void qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num, int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset, int *num, uint64_t *cluster_offset); int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset, - int n_start, int n_end, int *num, uint64_t *host_offset, QCowL2Meta *m); + int n_start, int n_end, int *num, uint64_t *host_offset, QCowL2Meta **m); uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, uint64_t offset, int compressed_size);