qcow2: Handle failure for potentially large allocations
Some code in the block layer makes potentially huge allocations. Failure is not completely unexpected there, so avoid aborting qemu and handle out-of-memory situations gracefully. This patch addresses the allocations in the qcow2 block driver. Signed-off-by: Kevin Wolf <kwolf@redhat.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
parent
0df93305f2
commit
de82815db1
@ -53,10 +53,21 @@ Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables)
|
|||||||
c->entries = g_malloc0(sizeof(*c->entries) * num_tables);
|
c->entries = g_malloc0(sizeof(*c->entries) * num_tables);
|
||||||
|
|
||||||
for (i = 0; i < c->size; i++) {
|
for (i = 0; i < c->size; i++) {
|
||||||
c->entries[i].table = qemu_blockalign(bs, s->cluster_size);
|
c->entries[i].table = qemu_try_blockalign(bs->file, s->cluster_size);
|
||||||
|
if (c->entries[i].table == NULL) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
for (i = 0; i < c->size; i++) {
|
||||||
|
qemu_vfree(c->entries[i].table);
|
||||||
|
}
|
||||||
|
g_free(c->entries);
|
||||||
|
g_free(c);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int qcow2_cache_destroy(BlockDriverState* bs, Qcow2Cache *c)
|
int qcow2_cache_destroy(BlockDriverState* bs, Qcow2Cache *c)
|
||||||
|
@ -72,14 +72,20 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
new_l1_size2 = sizeof(uint64_t) * new_l1_size;
|
new_l1_size2 = sizeof(uint64_t) * new_l1_size;
|
||||||
new_l1_table = g_malloc0(align_offset(new_l1_size2, 512));
|
new_l1_table = qemu_try_blockalign(bs->file,
|
||||||
|
align_offset(new_l1_size2, 512));
|
||||||
|
if (new_l1_table == NULL) {
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
memset(new_l1_table, 0, align_offset(new_l1_size2, 512));
|
||||||
|
|
||||||
memcpy(new_l1_table, s->l1_table, s->l1_size * sizeof(uint64_t));
|
memcpy(new_l1_table, s->l1_table, s->l1_size * sizeof(uint64_t));
|
||||||
|
|
||||||
/* write new table (align to cluster) */
|
/* write new table (align to cluster) */
|
||||||
BLKDBG_EVENT(bs->file, BLKDBG_L1_GROW_ALLOC_TABLE);
|
BLKDBG_EVENT(bs->file, BLKDBG_L1_GROW_ALLOC_TABLE);
|
||||||
new_l1_table_offset = qcow2_alloc_clusters(bs, new_l1_size2);
|
new_l1_table_offset = qcow2_alloc_clusters(bs, new_l1_size2);
|
||||||
if (new_l1_table_offset < 0) {
|
if (new_l1_table_offset < 0) {
|
||||||
g_free(new_l1_table);
|
qemu_vfree(new_l1_table);
|
||||||
return new_l1_table_offset;
|
return new_l1_table_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,7 +119,7 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
|
|||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
g_free(s->l1_table);
|
qemu_vfree(s->l1_table);
|
||||||
old_l1_table_offset = s->l1_table_offset;
|
old_l1_table_offset = s->l1_table_offset;
|
||||||
s->l1_table_offset = new_l1_table_offset;
|
s->l1_table_offset = new_l1_table_offset;
|
||||||
s->l1_table = new_l1_table;
|
s->l1_table = new_l1_table;
|
||||||
@ -123,7 +129,7 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
|
|||||||
QCOW2_DISCARD_OTHER);
|
QCOW2_DISCARD_OTHER);
|
||||||
return 0;
|
return 0;
|
||||||
fail:
|
fail:
|
||||||
g_free(new_l1_table);
|
qemu_vfree(new_l1_table);
|
||||||
qcow2_free_clusters(bs, new_l1_table_offset, new_l1_size2,
|
qcow2_free_clusters(bs, new_l1_table_offset, new_l1_size2,
|
||||||
QCOW2_DISCARD_OTHER);
|
QCOW2_DISCARD_OTHER);
|
||||||
return ret;
|
return ret;
|
||||||
@ -372,7 +378,10 @@ static int coroutine_fn copy_sectors(BlockDriverState *bs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
iov.iov_len = n * BDRV_SECTOR_SIZE;
|
iov.iov_len = n * BDRV_SECTOR_SIZE;
|
||||||
iov.iov_base = qemu_blockalign(bs, iov.iov_len);
|
iov.iov_base = qemu_try_blockalign(bs, iov.iov_len);
|
||||||
|
if (iov.iov_base == NULL) {
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
qemu_iovec_init_external(&qiov, &iov, 1);
|
qemu_iovec_init_external(&qiov, &iov, 1);
|
||||||
|
|
||||||
@ -702,7 +711,11 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
|
|||||||
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);
|
assert(m->nb_clusters > 0);
|
||||||
|
|
||||||
old_cluster = g_malloc(m->nb_clusters * sizeof(uint64_t));
|
old_cluster = g_try_malloc(m->nb_clusters * sizeof(uint64_t));
|
||||||
|
if (old_cluster == NULL) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
/* copy content of unmodified sectors */
|
/* copy content of unmodified sectors */
|
||||||
ret = perform_cow(bs, m, &m->cow_start);
|
ret = perform_cow(bs, m, &m->cow_start);
|
||||||
@ -1562,7 +1575,10 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
|
|||||||
if (!is_active_l1) {
|
if (!is_active_l1) {
|
||||||
/* inactive L2 tables require a buffer to be stored in when loading
|
/* inactive L2 tables require a buffer to be stored in when loading
|
||||||
* them from disk */
|
* them from disk */
|
||||||
l2_table = qemu_blockalign(bs, s->cluster_size);
|
l2_table = qemu_try_blockalign(bs->file, s->cluster_size);
|
||||||
|
if (l2_table == NULL) {
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < l1_size; i++) {
|
for (i = 0; i < l1_size; i++) {
|
||||||
@ -1740,7 +1756,11 @@ int qcow2_expand_zero_clusters(BlockDriverState *bs)
|
|||||||
|
|
||||||
nb_clusters = size_to_clusters(s, bs->file->total_sectors *
|
nb_clusters = size_to_clusters(s, bs->file->total_sectors *
|
||||||
BDRV_SECTOR_SIZE);
|
BDRV_SECTOR_SIZE);
|
||||||
expanded_clusters = g_malloc0((nb_clusters + 7) / 8);
|
expanded_clusters = g_try_malloc0((nb_clusters + 7) / 8);
|
||||||
|
if (expanded_clusters == NULL) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
ret = expand_zero_clusters_in_l1(bs, s->l1_table, s->l1_size,
|
ret = expand_zero_clusters_in_l1(bs, s->l1_table, s->l1_size,
|
||||||
&expanded_clusters, &nb_clusters);
|
&expanded_clusters, &nb_clusters);
|
||||||
|
@ -46,8 +46,12 @@ int qcow2_refcount_init(BlockDriverState *bs)
|
|||||||
|
|
||||||
assert(s->refcount_table_size <= INT_MAX / sizeof(uint64_t));
|
assert(s->refcount_table_size <= INT_MAX / sizeof(uint64_t));
|
||||||
refcount_table_size2 = s->refcount_table_size * sizeof(uint64_t);
|
refcount_table_size2 = s->refcount_table_size * sizeof(uint64_t);
|
||||||
s->refcount_table = g_malloc(refcount_table_size2);
|
s->refcount_table = g_try_malloc(refcount_table_size2);
|
||||||
|
|
||||||
if (s->refcount_table_size > 0) {
|
if (s->refcount_table_size > 0) {
|
||||||
|
if (s->refcount_table == NULL) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
BLKDBG_EVENT(bs->file, BLKDBG_REFTABLE_LOAD);
|
BLKDBG_EVENT(bs->file, BLKDBG_REFTABLE_LOAD);
|
||||||
ret = bdrv_pread(bs->file, s->refcount_table_offset,
|
ret = bdrv_pread(bs->file, s->refcount_table_offset,
|
||||||
s->refcount_table, refcount_table_size2);
|
s->refcount_table, refcount_table_size2);
|
||||||
@ -344,8 +348,14 @@ static int alloc_refcount_block(BlockDriverState *bs,
|
|||||||
uint64_t meta_offset = (blocks_used * refcount_block_clusters) *
|
uint64_t meta_offset = (blocks_used * refcount_block_clusters) *
|
||||||
s->cluster_size;
|
s->cluster_size;
|
||||||
uint64_t table_offset = meta_offset + blocks_clusters * s->cluster_size;
|
uint64_t table_offset = meta_offset + blocks_clusters * s->cluster_size;
|
||||||
uint16_t *new_blocks = g_malloc0(blocks_clusters * s->cluster_size);
|
uint64_t *new_table = g_try_malloc0(table_size * sizeof(uint64_t));
|
||||||
uint64_t *new_table = g_malloc0(table_size * sizeof(uint64_t));
|
uint16_t *new_blocks = g_try_malloc0(blocks_clusters * s->cluster_size);
|
||||||
|
|
||||||
|
assert(table_size > 0 && blocks_clusters > 0);
|
||||||
|
if (new_table == NULL || new_blocks == NULL) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto fail_table;
|
||||||
|
}
|
||||||
|
|
||||||
/* Fill the new refcount table */
|
/* Fill the new refcount table */
|
||||||
memcpy(new_table, s->refcount_table,
|
memcpy(new_table, s->refcount_table,
|
||||||
@ -424,6 +434,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
|
|||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
|
|
||||||
fail_table:
|
fail_table:
|
||||||
|
g_free(new_blocks);
|
||||||
g_free(new_table);
|
g_free(new_table);
|
||||||
fail_block:
|
fail_block:
|
||||||
if (*refcount_block != NULL) {
|
if (*refcount_block != NULL) {
|
||||||
@ -847,7 +858,8 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
|||||||
int64_t l1_table_offset, int l1_size, int addend)
|
int64_t l1_table_offset, int l1_size, int addend)
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2, l1_allocated;
|
uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2;
|
||||||
|
bool l1_allocated = false;
|
||||||
int64_t old_offset, old_l2_offset;
|
int64_t old_offset, old_l2_offset;
|
||||||
int i, j, l1_modified = 0, nb_csectors, refcount;
|
int i, j, l1_modified = 0, nb_csectors, refcount;
|
||||||
int ret;
|
int ret;
|
||||||
@ -862,8 +874,12 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
|||||||
* l1_table_offset when it is the current s->l1_table_offset! Be careful
|
* l1_table_offset when it is the current s->l1_table_offset! Be careful
|
||||||
* when changing this! */
|
* when changing this! */
|
||||||
if (l1_table_offset != s->l1_table_offset) {
|
if (l1_table_offset != s->l1_table_offset) {
|
||||||
l1_table = g_malloc0(align_offset(l1_size2, 512));
|
l1_table = g_try_malloc0(align_offset(l1_size2, 512));
|
||||||
l1_allocated = 1;
|
if (l1_size2 && l1_table == NULL) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
l1_allocated = true;
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file, l1_table_offset, l1_table, l1_size2);
|
ret = bdrv_pread(bs->file, l1_table_offset, l1_table, l1_size2);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@ -875,7 +891,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
|
|||||||
} else {
|
} else {
|
||||||
assert(l1_size == s->l1_size);
|
assert(l1_size == s->l1_size);
|
||||||
l1_table = s->l1_table;
|
l1_table = s->l1_table;
|
||||||
l1_allocated = 0;
|
l1_allocated = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i = 0; i < l1_size; i++) {
|
for(i = 0; i < l1_size; i++) {
|
||||||
@ -1197,7 +1213,11 @@ static int check_refcounts_l1(BlockDriverState *bs,
|
|||||||
if (l1_size2 == 0) {
|
if (l1_size2 == 0) {
|
||||||
l1_table = NULL;
|
l1_table = NULL;
|
||||||
} else {
|
} else {
|
||||||
l1_table = g_malloc(l1_size2);
|
l1_table = g_try_malloc(l1_size2);
|
||||||
|
if (l1_table == NULL) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
if (bdrv_pread(bs->file, l1_table_offset,
|
if (bdrv_pread(bs->file, l1_table_offset,
|
||||||
l1_table, l1_size2) != l1_size2)
|
l1_table, l1_size2) != l1_size2)
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -1501,7 +1521,11 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
|
|||||||
return -EFBIG;
|
return -EFBIG;
|
||||||
}
|
}
|
||||||
|
|
||||||
refcount_table = g_malloc0(nb_clusters * sizeof(uint16_t));
|
refcount_table = g_try_malloc0(nb_clusters * sizeof(uint16_t));
|
||||||
|
if (nb_clusters && refcount_table == NULL) {
|
||||||
|
res->check_errors++;
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
res->bfi.total_clusters =
|
res->bfi.total_clusters =
|
||||||
size_to_clusters(s, bs->total_sectors * BDRV_SECTOR_SIZE);
|
size_to_clusters(s, bs->total_sectors * BDRV_SECTOR_SIZE);
|
||||||
@ -1753,9 +1777,13 @@ int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset,
|
|||||||
uint64_t l1_ofs = s->snapshots[i].l1_table_offset;
|
uint64_t l1_ofs = s->snapshots[i].l1_table_offset;
|
||||||
uint32_t l1_sz = s->snapshots[i].l1_size;
|
uint32_t l1_sz = s->snapshots[i].l1_size;
|
||||||
uint64_t l1_sz2 = l1_sz * sizeof(uint64_t);
|
uint64_t l1_sz2 = l1_sz * sizeof(uint64_t);
|
||||||
uint64_t *l1 = g_malloc(l1_sz2);
|
uint64_t *l1 = g_try_malloc(l1_sz2);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (l1_sz2 && l1 == NULL) {
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file, l1_ofs, l1, l1_sz2);
|
ret = bdrv_pread(bs->file, l1_ofs, l1, l1_sz2);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
g_free(l1);
|
g_free(l1);
|
||||||
|
@ -381,7 +381,12 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
|
|||||||
sn->l1_table_offset = l1_table_offset;
|
sn->l1_table_offset = l1_table_offset;
|
||||||
sn->l1_size = s->l1_size;
|
sn->l1_size = s->l1_size;
|
||||||
|
|
||||||
l1_table = g_malloc(s->l1_size * sizeof(uint64_t));
|
l1_table = g_try_malloc(s->l1_size * sizeof(uint64_t));
|
||||||
|
if (s->l1_size && l1_table == NULL) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
for(i = 0; i < s->l1_size; i++) {
|
for(i = 0; i < s->l1_size; i++) {
|
||||||
l1_table[i] = cpu_to_be64(s->l1_table[i]);
|
l1_table[i] = cpu_to_be64(s->l1_table[i]);
|
||||||
}
|
}
|
||||||
@ -499,7 +504,11 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
|
|||||||
* Decrease the refcount referenced by the old one only when the L1
|
* Decrease the refcount referenced by the old one only when the L1
|
||||||
* table is overwritten.
|
* table is overwritten.
|
||||||
*/
|
*/
|
||||||
sn_l1_table = g_malloc0(cur_l1_bytes);
|
sn_l1_table = g_try_malloc0(cur_l1_bytes);
|
||||||
|
if (cur_l1_bytes && sn_l1_table == NULL) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file, sn->l1_table_offset, sn_l1_table, sn_l1_bytes);
|
ret = bdrv_pread(bs->file, sn->l1_table_offset, sn_l1_table, sn_l1_bytes);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@ -698,17 +707,21 @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs,
|
|||||||
return -EFBIG;
|
return -EFBIG;
|
||||||
}
|
}
|
||||||
new_l1_bytes = sn->l1_size * sizeof(uint64_t);
|
new_l1_bytes = sn->l1_size * sizeof(uint64_t);
|
||||||
new_l1_table = g_malloc0(align_offset(new_l1_bytes, 512));
|
new_l1_table = qemu_try_blockalign(bs->file,
|
||||||
|
align_offset(new_l1_bytes, 512));
|
||||||
|
if (new_l1_table == NULL) {
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
ret = bdrv_pread(bs->file, sn->l1_table_offset, new_l1_table, new_l1_bytes);
|
ret = bdrv_pread(bs->file, sn->l1_table_offset, new_l1_table, new_l1_bytes);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
error_setg(errp, "Failed to read l1 table for snapshot");
|
error_setg(errp, "Failed to read l1 table for snapshot");
|
||||||
g_free(new_l1_table);
|
qemu_vfree(new_l1_table);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Switch the L1 table */
|
/* Switch the L1 table */
|
||||||
g_free(s->l1_table);
|
qemu_vfree(s->l1_table);
|
||||||
|
|
||||||
s->l1_size = sn->l1_size;
|
s->l1_size = sn->l1_size;
|
||||||
s->l1_table_offset = sn->l1_table_offset;
|
s->l1_table_offset = sn->l1_table_offset;
|
||||||
|
@ -688,8 +688,13 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
|
|
||||||
|
|
||||||
if (s->l1_size > 0) {
|
if (s->l1_size > 0) {
|
||||||
s->l1_table = g_malloc0(
|
s->l1_table = qemu_try_blockalign(bs->file,
|
||||||
align_offset(s->l1_size * sizeof(uint64_t), 512));
|
align_offset(s->l1_size * sizeof(uint64_t), 512));
|
||||||
|
if (s->l1_table == NULL) {
|
||||||
|
error_setg(errp, "Could not allocate L1 table");
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
ret = bdrv_pread(bs->file, s->l1_table_offset, s->l1_table,
|
ret = bdrv_pread(bs->file, s->l1_table_offset, s->l1_table,
|
||||||
s->l1_size * sizeof(uint64_t));
|
s->l1_size * sizeof(uint64_t));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@ -704,11 +709,22 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
/* alloc L2 table/refcount block cache */
|
/* alloc L2 table/refcount block cache */
|
||||||
s->l2_table_cache = qcow2_cache_create(bs, L2_CACHE_SIZE);
|
s->l2_table_cache = qcow2_cache_create(bs, L2_CACHE_SIZE);
|
||||||
s->refcount_block_cache = qcow2_cache_create(bs, REFCOUNT_CACHE_SIZE);
|
s->refcount_block_cache = qcow2_cache_create(bs, REFCOUNT_CACHE_SIZE);
|
||||||
|
if (s->l2_table_cache == NULL || s->refcount_block_cache == NULL) {
|
||||||
|
error_setg(errp, "Could not allocate metadata caches");
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
s->cluster_cache = g_malloc(s->cluster_size);
|
s->cluster_cache = g_malloc(s->cluster_size);
|
||||||
/* one more sector for decompressed data alignment */
|
/* one more sector for decompressed data alignment */
|
||||||
s->cluster_data = qemu_blockalign(bs, QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size
|
s->cluster_data = qemu_try_blockalign(bs->file, QCOW_MAX_CRYPT_CLUSTERS
|
||||||
+ 512);
|
* s->cluster_size + 512);
|
||||||
|
if (s->cluster_data == NULL) {
|
||||||
|
error_setg(errp, "Could not allocate temporary cluster buffer");
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
s->cluster_cache_offset = -1;
|
s->cluster_cache_offset = -1;
|
||||||
s->flags = flags;
|
s->flags = flags;
|
||||||
|
|
||||||
@ -852,7 +868,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
|||||||
cleanup_unknown_header_ext(bs);
|
cleanup_unknown_header_ext(bs);
|
||||||
qcow2_free_snapshots(bs);
|
qcow2_free_snapshots(bs);
|
||||||
qcow2_refcount_close(bs);
|
qcow2_refcount_close(bs);
|
||||||
g_free(s->l1_table);
|
qemu_vfree(s->l1_table);
|
||||||
/* else pre-write overlap checks in cache_destroy may crash */
|
/* else pre-write overlap checks in cache_destroy may crash */
|
||||||
s->l1_table = NULL;
|
s->l1_table = NULL;
|
||||||
if (s->l2_table_cache) {
|
if (s->l2_table_cache) {
|
||||||
@ -1082,7 +1098,12 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num,
|
|||||||
*/
|
*/
|
||||||
if (!cluster_data) {
|
if (!cluster_data) {
|
||||||
cluster_data =
|
cluster_data =
|
||||||
qemu_blockalign(bs, QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size);
|
qemu_try_blockalign(bs->file, QCOW_MAX_CRYPT_CLUSTERS
|
||||||
|
* s->cluster_size);
|
||||||
|
if (cluster_data == NULL) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(cur_nr_sectors <=
|
assert(cur_nr_sectors <=
|
||||||
@ -1182,8 +1203,13 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
|
|||||||
|
|
||||||
if (s->crypt_method) {
|
if (s->crypt_method) {
|
||||||
if (!cluster_data) {
|
if (!cluster_data) {
|
||||||
cluster_data = qemu_blockalign(bs, QCOW_MAX_CRYPT_CLUSTERS *
|
cluster_data = qemu_try_blockalign(bs->file,
|
||||||
s->cluster_size);
|
QCOW_MAX_CRYPT_CLUSTERS
|
||||||
|
* s->cluster_size);
|
||||||
|
if (cluster_data == NULL) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(hd_qiov.size <=
|
assert(hd_qiov.size <=
|
||||||
@ -1270,7 +1296,7 @@ fail:
|
|||||||
static void qcow2_close(BlockDriverState *bs)
|
static void qcow2_close(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
g_free(s->l1_table);
|
qemu_vfree(s->l1_table);
|
||||||
/* else pre-write overlap checks in cache_destroy may crash */
|
/* else pre-write overlap checks in cache_destroy may crash */
|
||||||
s->l1_table = NULL;
|
s->l1_table = NULL;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user