#include "qemu/osdep.h"
#include <zlib.h>
-#include "qapi/error.h"
#include "qemu-common.h"
#include "block/block_int.h"
#include "block/qcow2.h"
#include "qemu/bswap.h"
#include "trace.h"
+int qcow2_shrink_l1_table(BlockDriverState *bs, uint64_t exact_size)
+{
+ BDRVQcow2State *s = bs->opaque;
+ int new_l1_size, i, ret;
+
+ if (exact_size >= s->l1_size) {
+ return 0;
+ }
+
+ new_l1_size = exact_size;
+
+#ifdef DEBUG_ALLOC2
+ fprintf(stderr, "shrink l1_table from %d to %d\n", s->l1_size, new_l1_size);
+#endif
+
+ BLKDBG_EVENT(bs->file, BLKDBG_L1_SHRINK_WRITE_TABLE);
+ ret = bdrv_pwrite_zeroes(bs->file, s->l1_table_offset +
+ new_l1_size * sizeof(uint64_t),
+ (s->l1_size - new_l1_size) * sizeof(uint64_t), 0);
+ if (ret < 0) {
+ goto fail;
+ }
+
+ ret = bdrv_flush(bs->file->bs);
+ if (ret < 0) {
+ goto fail;
+ }
+
+ BLKDBG_EVENT(bs->file, BLKDBG_L1_SHRINK_FREE_L2_CLUSTERS);
+ for (i = s->l1_size - 1; i > new_l1_size - 1; i--) {
+ if ((s->l1_table[i] & L1E_OFFSET_MASK) == 0) {
+ continue;
+ }
+ qcow2_free_clusters(bs, s->l1_table[i] & L1E_OFFSET_MASK,
+ s->cluster_size, QCOW2_DISCARD_ALWAYS);
+ s->l1_table[i] = 0;
+ }
+ return 0;
+
+fail:
+ /*
+ * If the write in the l1_table failed the image may contain a partially
+ * overwritten l1_table. In this case it would be better to clear the
+ * l1_table in memory to avoid possible image corruption.
+ */
+ memset(s->l1_table + new_l1_size, 0,
+ (s->l1_size - new_l1_size) * sizeof(uint64_t));
+ return ret;
+}
+
int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
bool exact_size)
{
new_l1_size = 1;
}
while (min_size > new_l1_size) {
- new_l1_size = (new_l1_size * 3 + 1) / 2;
+ new_l1_size = DIV_ROUND_UP(new_l1_size * 3, 2);
}
}
goto fail;
}
+ /* If we're allocating the table at offset 0 then something is wrong */
+ if (l2_offset == 0) {
+ qcow2_signal_corruption(bs, true, -1, -1, "Preventing invalid "
+ "allocation of L2 table at offset 0");
+ ret = -EIO;
+ goto fail;
+ }
+
ret = qcow2_cache_flush(bs, s->refcount_block_cache);
if (ret < 0) {
goto fail;
BLKDBG_EVENT(bs->file, BLKDBG_L2_ALLOC_WRITE);
trace_qcow2_l2_allocate_write_l2(bs, l1_index);
- qcow2_cache_entry_mark_dirty(bs, s->l2_table_cache, l2_table);
+ qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
ret = qcow2_cache_flush(bs, s->l2_table_cache);
if (ret < 0) {
goto fail;
return i;
}
-/* The crypt function is compatible with the linux cryptoloop
- algorithm for < 4 GB images. NOTE: out_buf == in_buf is
- supported */
-int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num,
- uint8_t *out_buf, const uint8_t *in_buf,
- int nb_sectors, bool enc,
- Error **errp)
-{
- union {
- uint64_t ll[2];
- uint8_t b[16];
- } ivec;
- int i;
- int ret;
-
- for(i = 0; i < nb_sectors; i++) {
- ivec.ll[0] = cpu_to_le64(sector_num);
- ivec.ll[1] = 0;
- if (qcrypto_cipher_setiv(s->cipher,
- ivec.b, G_N_ELEMENTS(ivec.b),
- errp) < 0) {
- return -1;
- }
- if (enc) {
- ret = qcrypto_cipher_encrypt(s->cipher,
- in_buf,
- out_buf,
- 512,
- errp);
- } else {
- ret = qcrypto_cipher_decrypt(s->cipher,
- in_buf,
- out_buf,
- 512,
- errp);
- }
- if (ret < 0) {
- return -1;
- }
- sector_num++;
- in_buf += 512;
- out_buf += 512;
- }
- return 0;
-}
-
static int coroutine_fn do_perform_cow_read(BlockDriverState *bs,
uint64_t src_cluster_offset,
unsigned offset_in_cluster,
static bool coroutine_fn do_perform_cow_encrypt(BlockDriverState *bs,
uint64_t src_cluster_offset,
+ uint64_t cluster_offset,
unsigned offset_in_cluster,
uint8_t *buffer,
unsigned bytes)
{
if (bytes && bs->encrypted) {
BDRVQcow2State *s = bs->opaque;
- int64_t sector = (src_cluster_offset + offset_in_cluster)
- >> BDRV_SECTOR_BITS;
- assert(s->cipher);
+ int64_t offset = (s->crypt_physical_offset ?
+ (cluster_offset + offset_in_cluster) :
+ (src_cluster_offset + offset_in_cluster));
assert((offset_in_cluster & ~BDRV_SECTOR_MASK) == 0);
assert((bytes & ~BDRV_SECTOR_MASK) == 0);
- if (qcow2_encrypt_sectors(s, sector, buffer, buffer,
- bytes >> BDRV_SECTOR_BITS, true, NULL) < 0) {
+ assert(s->crypto);
+ if (qcrypto_block_encrypt(s->crypto, offset, buffer, bytes, NULL) < 0) {
return false;
}
}
* for a given disk offset, load (and allocate if needed)
* the l2 table.
*
- * the l2 table offset in the qcow2 file and the cluster index
- * in the l2 table are given to the caller.
+ * the cluster index in the l2 table is given to the caller.
*
* Returns 0 on success, -errno in failure case
*/
/* compressed clusters never have the copied flag */
BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE_COMPRESSED);
- qcow2_cache_entry_mark_dirty(bs, s->l2_table_cache, l2_table);
+ qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
l2_table[l2_index] = cpu_to_be64(cluster_offset);
qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
/* Encrypt the data if necessary before writing it */
if (bs->encrypted) {
- if (!do_perform_cow_encrypt(bs, m->offset, start->offset,
- start_buffer, start->nb_bytes) ||
- !do_perform_cow_encrypt(bs, m->offset, end->offset,
- end_buffer, end->nb_bytes)) {
+ if (!do_perform_cow_encrypt(bs, m->offset, m->alloc_offset,
+ start->offset, start_buffer,
+ start->nb_bytes) ||
+ !do_perform_cow_encrypt(bs, m->offset, m->alloc_offset,
+ end->offset, end_buffer, end->nb_bytes)) {
ret = -EIO;
goto fail;
}
if (ret < 0) {
goto err;
}
- qcow2_cache_entry_mark_dirty(bs, s->l2_table_cache, l2_table);
+ qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
assert(l2_index + m->nb_clusters <= s->l2_size);
for (i = 0; i < m->nb_clusters; i++) {
(!*host_offset ||
start_of_cluster(s, *host_offset) == (entry & L2E_OFFSET_MASK)))
{
+ int preallocated_nb_clusters;
+
+ if (offset_into_cluster(s, entry & L2E_OFFSET_MASK)) {
+ qcow2_signal_corruption(bs, true, -1, -1, "Preallocated zero "
+ "cluster offset %#llx unaligned (guest "
+ "offset: %#" PRIx64 ")",
+ entry & L2E_OFFSET_MASK, guest_offset);
+ ret = -EIO;
+ goto fail;
+ }
+
/* Try to reuse preallocated zero clusters; contiguous normal clusters
* would be fine, too, but count_cow_clusters() above has limited
* nb_clusters already to a range of COW clusters */
- int preallocated_nb_clusters =
+ preallocated_nb_clusters =
count_contiguous_clusters(nb_clusters, s->cluster_size,
&l2_table[l2_index], QCOW_OFLAG_COPIED);
assert(preallocated_nb_clusters > 0);
nb_csectors = ((cluster_offset >> s->csize_shift) & s->csize_mask) + 1;
sector_offset = coffset & 511;
csize = nb_csectors * 512 - sector_offset;
+
+ /* Allocate buffers on first decompress operation, most images are
+ * uncompressed and the memory overhead can be avoided. The buffers
+ * are freed in .bdrv_close().
+ */
+ if (!s->cluster_data) {
+ /* one more sector for decompressed data alignment */
+ s->cluster_data = qemu_try_blockalign(bs->file->bs,
+ QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size + 512);
+ if (!s->cluster_data) {
+ return -ENOMEM;
+ }
+ }
+ if (!s->cluster_cache) {
+ s->cluster_cache = g_malloc(s->cluster_size);
+ }
+
BLKDBG_EVENT(bs->file, BLKDBG_READ_COMPRESSED);
ret = bdrv_read(bs->file, coffset >> 9, s->cluster_data,
nb_csectors);
* cluster is already marked as zero, or if it's unallocated and we
* don't have a backing file.
*
- * TODO We might want to use bdrv_get_block_status(bs) here, but we're
+ * TODO We might want to use bdrv_block_status(bs) here, but we're
* holding s->lock, so that doesn't work today.
*
* If full_discard is true, the sector should not read back as zeroes,
}
/* First remove L2 entries */
- qcow2_cache_entry_mark_dirty(bs, s->l2_table_cache, l2_table);
+ qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
if (!full_discard && s->qcow_version >= 3) {
l2_table[l2_index + i] = cpu_to_be64(QCOW_OFLAG_ZERO);
} else {
continue;
}
- qcow2_cache_entry_mark_dirty(bs, s->l2_table_cache, l2_table);
+ qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
if (cluster_type == QCOW2_CLUSTER_COMPRESSED || unmap) {
l2_table[l2_index + i] = cpu_to_be64(QCOW_OFLAG_ZERO);
qcow2_free_any_clusters(bs, old_offset, 1, QCOW2_DISCARD_REQUEST);
if (is_active_l1) {
if (l2_dirty) {
- qcow2_cache_entry_mark_dirty(bs, s->l2_table_cache, l2_table);
+ qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
qcow2_cache_depends_on_flush(s->l2_table_cache);
}
qcow2_cache_put(bs, s->l2_table_cache, (void **) &l2_table);
int l1_sectors = DIV_ROUND_UP(s->snapshots[i].l1_size *
sizeof(uint64_t), BDRV_SECTOR_SIZE);
- l1_table = g_realloc(l1_table, l1_sectors * BDRV_SECTOR_SIZE);
+ uint64_t *new_l1_table =
+ g_try_realloc(l1_table, l1_sectors * BDRV_SECTOR_SIZE);
+
+ if (!new_l1_table) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ l1_table = new_l1_table;
ret = bdrv_read(bs->file,
s->snapshots[i].l1_table_offset / BDRV_SECTOR_SIZE,