mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-07 01:33:56 -06:00
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
5 changed files with 130 additions and 32 deletions
|
@ -72,14 +72,20 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
|
|||
#endif
|
||||
|
||||
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));
|
||||
|
||||
/* write new table (align to cluster) */
|
||||
BLKDBG_EVENT(bs->file, BLKDBG_L1_GROW_ALLOC_TABLE);
|
||||
new_l1_table_offset = qcow2_alloc_clusters(bs, new_l1_size2);
|
||||
if (new_l1_table_offset < 0) {
|
||||
g_free(new_l1_table);
|
||||
qemu_vfree(new_l1_table);
|
||||
return new_l1_table_offset;
|
||||
}
|
||||
|
||||
|
@ -113,7 +119,7 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
|
|||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
g_free(s->l1_table);
|
||||
qemu_vfree(s->l1_table);
|
||||
old_l1_table_offset = s->l1_table_offset;
|
||||
s->l1_table_offset = new_l1_table_offset;
|
||||
s->l1_table = new_l1_table;
|
||||
|
@ -123,7 +129,7 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
|
|||
QCOW2_DISCARD_OTHER);
|
||||
return 0;
|
||||
fail:
|
||||
g_free(new_l1_table);
|
||||
qemu_vfree(new_l1_table);
|
||||
qcow2_free_clusters(bs, new_l1_table_offset, new_l1_size2,
|
||||
QCOW2_DISCARD_OTHER);
|
||||
return ret;
|
||||
|
@ -372,7 +378,10 @@ static int coroutine_fn copy_sectors(BlockDriverState *bs,
|
|||
}
|
||||
|
||||
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);
|
||||
|
||||
|
@ -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);
|
||||
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 */
|
||||
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) {
|
||||
/* inactive L2 tables require a buffer to be stored in when loading
|
||||
* 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++) {
|
||||
|
@ -1740,7 +1756,11 @@ int qcow2_expand_zero_clusters(BlockDriverState *bs)
|
|||
|
||||
nb_clusters = size_to_clusters(s, bs->file->total_sectors *
|
||||
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,
|
||||
&expanded_clusters, &nb_clusters);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue