diff options
author | Kevin Wolf <kwolf@redhat.com> | 2014-05-20 17:12:47 +0200 |
---|---|---|
committer | Kevin Wolf <kwolf@redhat.com> | 2014-08-15 15:07:15 +0200 |
commit | de82815db1c89da058b7fb941dab137d6d9ab738 (patch) | |
tree | 782b541f1a0c5d154d2c8a166306e7407094bf9a /block/qcow2-snapshot.c | |
parent | 0df93305f21712e975ab5df260cc5a91e5daafca (diff) | |
download | qemu-de82815db1c89da058b7fb941dab137d6d9ab738.zip |
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>
Diffstat (limited to 'block/qcow2-snapshot.c')
-rw-r--r-- | block/qcow2-snapshot.c | 23 |
1 files changed, 18 insertions, 5 deletions
diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c index 0aa9defbe2..f67b47282f 100644 --- a/block/qcow2-snapshot.c +++ b/block/qcow2-snapshot.c @@ -381,7 +381,12 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) sn->l1_table_offset = l1_table_offset; 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++) { 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 * 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); if (ret < 0) { @@ -698,17 +707,21 @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs, return -EFBIG; } 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); if (ret < 0) { error_setg(errp, "Failed to read l1 table for snapshot"); - g_free(new_l1_table); + qemu_vfree(new_l1_table); return ret; } /* Switch the L1 table */ - g_free(s->l1_table); + qemu_vfree(s->l1_table); s->l1_size = sn->l1_size; s->l1_table_offset = sn->l1_table_offset; |