diff options
author | Peter Wu <peter@lekensteyn.nl> | 2014-12-25 22:33:56 +0100 |
---|---|---|
committer | Peter Wu <peter@lekensteyn.nl> | 2014-12-25 22:33:56 +0100 |
commit | 984a6899dcffc94ea0e28f1116a233bd3d6cd51f (patch) | |
tree | a09ff841b54bfe69672f888bce0051b12b878355 | |
parent | e8815356e6b7988edd523163ff72a8f2a8cacc8b (diff) | |
download | qemu-984a6899dcffc94ea0e28f1116a233bd3d6cd51f.tar.gz |
block/dmg: avoid huge allocation for zeroes
Disk images may contain large all-zeroes gaps (1.66k sectors or 812 MiB
is seen in the real world). To avoid having to take such an amount from
the heap, treat this case specially. This lowers the maximum memory need
to 1054371 bytes (probably for a bzip2-compressed block).
Signed-off-by: Peter Wu <peter@lekensteyn.nl>
-rw-r--r-- | block/dmg.c | 14 |
1 files changed, 10 insertions, 4 deletions
diff --git a/block/dmg.c b/block/dmg.c index 362e6747d4..f94b6d96ed 100644 --- a/block/dmg.c +++ b/block/dmg.c @@ -137,7 +137,9 @@ static void update_max_chunk_size(BDRVDMGState *s, uint32_t chunk, uncompressed_sectors = (s->lengths[chunk] + 511) / 512; break; case 2: /* zero */ - uncompressed_sectors = s->sectorcounts[chunk]; + /* as the all-zeroes block may be large, it is treated specially: the + * sector is not copied from a large buffer, a simple memset is used + * instead. Therefore uncompressed_sectors does not need to be set. */ break; } @@ -574,9 +576,6 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num) return -1; } break; - case 2: /* zero */ - memset(s->uncompressed_chunk, 0, 512 * s->sectorcounts[chunk]); - break; } s->current_chunk = chunk; } @@ -594,6 +593,13 @@ static int dmg_read(BlockDriverState *bs, int64_t sector_num, if (dmg_read_chunk(bs, sector_num + i) != 0) { return -1; } + /* Special case: current chunk is all zeroes. Do not perform a memcpy as + * s->uncompressed_chunk may be too small to cover the large all-zeroes + * section. */ + if (s->types[s->current_chunk] == 2) { /* all zeroes block entry */ + memset(buf + i * 512, 0, 512); + continue; + } sector_offset_in_chunk = sector_num + i - s->sectors[s->current_chunk]; memcpy(buf + i * 512, s->uncompressed_chunk + sector_offset_in_chunk * 512, 512); |