mirror of https://github.com/proxmox/mirror_qemu
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>master
parent
060bee8943
commit
f50f88b9fe
|
@ -652,9 +652,7 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
|
||||||
uint64_t cluster_offset = m->alloc_offset;
|
uint64_t cluster_offset = m->alloc_offset;
|
||||||
|
|
||||||
trace_qcow2_cluster_link_l2(qemu_coroutine_self(), m->nb_clusters);
|
trace_qcow2_cluster_link_l2(qemu_coroutine_self(), m->nb_clusters);
|
||||||
|
assert(m->nb_clusters > 0);
|
||||||
if (m->nb_clusters == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
old_cluster = g_malloc(m->nb_clusters * sizeof(uint64_t));
|
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
|
* Return 0 on success and -errno in error cases
|
||||||
*/
|
*/
|
||||||
int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t 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)
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
int l2_index, ret, sectors;
|
int l2_index, ret, sectors;
|
||||||
|
@ -928,11 +926,6 @@ again:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If there is something left to allocate, do that now */
|
/* 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) {
|
if (nb_clusters > 0) {
|
||||||
uint64_t alloc_offset;
|
uint64_t alloc_offset;
|
||||||
uint64_t alloc_cluster_offset;
|
uint64_t alloc_cluster_offset;
|
||||||
|
@ -980,7 +973,9 @@ again:
|
||||||
cluster_offset = alloc_cluster_offset;
|
cluster_offset = alloc_cluster_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
*m = (QCowL2Meta) {
|
*m = g_malloc0(sizeof(**m));
|
||||||
|
|
||||||
|
**m = (QCowL2Meta) {
|
||||||
.alloc_offset = alloc_cluster_offset,
|
.alloc_offset = alloc_cluster_offset,
|
||||||
.offset = alloc_offset & ~(s->cluster_size - 1),
|
.offset = alloc_offset & ~(s->cluster_size - 1),
|
||||||
.nb_clusters = nb_clusters,
|
.nb_clusters = nb_clusters,
|
||||||
|
@ -995,8 +990,8 @@ again:
|
||||||
.nb_sectors = avail_sectors - nb_sectors,
|
.nb_sectors = avail_sectors - nb_sectors,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
qemu_co_queue_init(&m->dependent_requests);
|
qemu_co_queue_init(&(*m)->dependent_requests);
|
||||||
QLIST_INSERT_HEAD(&s->cluster_allocs, m, next_in_flight);
|
QLIST_INSERT_HEAD(&s->cluster_allocs, *m, next_in_flight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1013,8 +1008,8 @@ again:
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
if (m->nb_clusters > 0) {
|
if (*m && (*m)->nb_clusters > 0) {
|
||||||
QLIST_REMOVE(m, next_in_flight);
|
QLIST_REMOVE(*m, next_in_flight);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -787,8 +787,7 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
|
||||||
|
|
||||||
while (remaining_sectors != 0) {
|
while (remaining_sectors != 0) {
|
||||||
|
|
||||||
l2meta = g_malloc0(sizeof(*l2meta));
|
l2meta = NULL;
|
||||||
qemu_co_queue_init(&l2meta->dependent_requests);
|
|
||||||
|
|
||||||
trace_qcow2_writev_start_part(qemu_coroutine_self());
|
trace_qcow2_writev_start_part(qemu_coroutine_self());
|
||||||
index_in_cluster = sector_num & (s->cluster_sectors - 1);
|
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,
|
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) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
@ -845,6 +844,7 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (l2meta != NULL) {
|
||||||
ret = qcow2_alloc_cluster_link_l2(bs, l2meta);
|
ret = qcow2_alloc_cluster_link_l2(bs, l2meta);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -853,6 +853,7 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
|
||||||
run_dependent_requests(s, l2meta);
|
run_dependent_requests(s, l2meta);
|
||||||
g_free(l2meta);
|
g_free(l2meta);
|
||||||
l2meta = NULL;
|
l2meta = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
remaining_sectors -= cur_nr_sectors;
|
remaining_sectors -= cur_nr_sectors;
|
||||||
sector_num += cur_nr_sectors;
|
sector_num += cur_nr_sectors;
|
||||||
|
@ -1134,11 +1135,10 @@ static int preallocate(BlockDriverState *bs)
|
||||||
uint64_t host_offset = 0;
|
uint64_t host_offset = 0;
|
||||||
int num;
|
int num;
|
||||||
int ret;
|
int ret;
|
||||||
QCowL2Meta meta;
|
QCowL2Meta *meta;
|
||||||
|
|
||||||
nb_sectors = bdrv_getlength(bs) >> 9;
|
nb_sectors = bdrv_getlength(bs) >> 9;
|
||||||
offset = 0;
|
offset = 0;
|
||||||
qemu_co_queue_init(&meta.dependent_requests);
|
|
||||||
|
|
||||||
while (nb_sectors) {
|
while (nb_sectors) {
|
||||||
num = MIN(nb_sectors, INT_MAX >> 9);
|
num = MIN(nb_sectors, INT_MAX >> 9);
|
||||||
|
@ -1148,15 +1148,17 @@ static int preallocate(BlockDriverState *bs)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = qcow2_alloc_cluster_link_l2(bs, &meta);
|
ret = qcow2_alloc_cluster_link_l2(bs, meta);
|
||||||
if (ret < 0) {
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* There are no dependent requests, but we need to remove our request
|
/* There are no dependent requests, but we need to remove our request
|
||||||
* from the list of in-flight requests */
|
* 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 */
|
/* TODO Preallocate data if requested */
|
||||||
|
|
||||||
|
|
|
@ -207,7 +207,10 @@ typedef struct Qcow2COWRegion {
|
||||||
int nb_sectors;
|
int nb_sectors;
|
||||||
} Qcow2COWRegion;
|
} 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
|
typedef struct QCowL2Meta
|
||||||
{
|
{
|
||||||
/** Guest offset of the first newly allocated cluster */
|
/** 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 qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||||
int *num, uint64_t *cluster_offset);
|
int *num, uint64_t *cluster_offset);
|
||||||
int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t 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 qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
|
||||||
uint64_t offset,
|
uint64_t offset,
|
||||||
int compressed_size);
|
int compressed_size);
|
||||||
|
|
Loading…
Reference in New Issue