#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)
+static int coroutine_fn do_perform_cow_read(BlockDriverState *bs,
+ uint64_t src_cluster_offset,
+ unsigned offset_in_cluster,
+ QEMUIOVector *qiov)
{
- 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(BlockDriverState *bs,
- uint64_t src_cluster_offset,
- uint64_t cluster_offset,
- int offset_in_cluster,
- int bytes)
-{
- BDRVQcow2State *s = bs->opaque;
- QEMUIOVector qiov;
- struct iovec iov;
- int ret;
-
- iov.iov_len = bytes;
- iov.iov_base = qemu_try_blockalign(bs, iov.iov_len);
- if (iov.iov_base == NULL) {
- return -ENOMEM;
+ if (qiov->size == 0) {
+ return 0;
}
- qemu_iovec_init_external(&qiov, &iov, 1);
-
BLKDBG_EVENT(bs->file, BLKDBG_COW_READ);
if (!bs->drv) {
- ret = -ENOMEDIUM;
- goto out;
+ return -ENOMEDIUM;
}
/* Call .bdrv_co_readv() directly instead of using the public block-layer
* which can lead to deadlock when block layer copy-on-read is enabled.
*/
ret = bs->drv->bdrv_co_preadv(bs, src_cluster_offset + offset_in_cluster,
- bytes, &qiov, 0);
+ qiov->size, qiov, 0);
if (ret < 0) {
- goto out;
+ return ret;
}
- if (bs->encrypted) {
- Error *err = NULL;
- int64_t sector = (src_cluster_offset + offset_in_cluster)
- >> BDRV_SECTOR_BITS;
- assert(s->cipher);
+ return 0;
+}
+
+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 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, iov.iov_base, iov.iov_base,
- bytes >> BDRV_SECTOR_BITS, true, &err) < 0) {
- ret = -EIO;
- error_free(err);
- goto out;
+ assert(s->crypto);
+ if (qcrypto_block_encrypt(s->crypto, offset, buffer, bytes, NULL) < 0) {
+ return false;
}
}
+ return true;
+}
+
+static int coroutine_fn do_perform_cow_write(BlockDriverState *bs,
+ uint64_t cluster_offset,
+ unsigned offset_in_cluster,
+ QEMUIOVector *qiov)
+{
+ int ret;
+
+ if (qiov->size == 0) {
+ return 0;
+ }
ret = qcow2_pre_write_overlap_check(bs, 0,
- cluster_offset + offset_in_cluster, bytes);
+ cluster_offset + offset_in_cluster, qiov->size);
if (ret < 0) {
- goto out;
+ return ret;
}
BLKDBG_EVENT(bs->file, BLKDBG_COW_WRITE);
ret = bdrv_co_pwritev(bs->file, cluster_offset + offset_in_cluster,
- bytes, &qiov, 0);
+ qiov->size, qiov, 0);
if (ret < 0) {
- goto out;
+ return ret;
}
- ret = 0;
-out:
- qemu_vfree(iov.iov_base);
- return ret;
+ return 0;
}
/* find the cluster offset for the given disk offset */
- l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1);
+ l2_index = offset_to_l2_index(s, offset);
*cluster_offset = be64_to_cpu(l2_table[l2_index]);
nb_clusters = size_to_clusters(s, bytes_needed);
* 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
*/
/* find the cluster offset for the given disk offset */
- l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1);
+ l2_index = offset_to_l2_index(s, offset);
*new_l2_table = l2_table;
*new_l2_index = l2_index;
/* 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);
return cluster_offset;
}
-static int perform_cow(BlockDriverState *bs, QCowL2Meta *m, Qcow2COWRegion *r)
+static int perform_cow(BlockDriverState *bs, QCowL2Meta *m)
{
BDRVQcow2State *s = bs->opaque;
+ Qcow2COWRegion *start = &m->cow_start;
+ Qcow2COWRegion *end = &m->cow_end;
+ unsigned buffer_size;
+ unsigned data_bytes = end->offset - (start->offset + start->nb_bytes);
+ bool merge_reads;
+ uint8_t *start_buffer, *end_buffer;
+ QEMUIOVector qiov;
int ret;
- if (r->nb_bytes == 0) {
+ assert(start->nb_bytes <= UINT_MAX - end->nb_bytes);
+ assert(start->nb_bytes + end->nb_bytes <= UINT_MAX - data_bytes);
+ assert(start->offset + start->nb_bytes <= end->offset);
+ assert(!m->data_qiov || m->data_qiov->size == data_bytes);
+
+ if (start->nb_bytes == 0 && end->nb_bytes == 0) {
return 0;
}
+ /* If we have to read both the start and end COW regions and the
+ * middle region is not too large then perform just one read
+ * operation */
+ merge_reads = start->nb_bytes && end->nb_bytes && data_bytes <= 16384;
+ if (merge_reads) {
+ buffer_size = start->nb_bytes + data_bytes + end->nb_bytes;
+ } else {
+ /* If we have to do two reads, add some padding in the middle
+ * if necessary to make sure that the end region is optimally
+ * aligned. */
+ size_t align = bdrv_opt_mem_align(bs);
+ assert(align > 0 && align <= UINT_MAX);
+ assert(QEMU_ALIGN_UP(start->nb_bytes, align) <=
+ UINT_MAX - end->nb_bytes);
+ buffer_size = QEMU_ALIGN_UP(start->nb_bytes, align) + end->nb_bytes;
+ }
+
+ /* Reserve a buffer large enough to store all the data that we're
+ * going to read */
+ start_buffer = qemu_try_blockalign(bs, buffer_size);
+ if (start_buffer == NULL) {
+ return -ENOMEM;
+ }
+ /* The part of the buffer where the end region is located */
+ end_buffer = start_buffer + buffer_size - end->nb_bytes;
+
+ qemu_iovec_init(&qiov, 2 + (m->data_qiov ? m->data_qiov->niov : 0));
+
qemu_co_mutex_unlock(&s->lock);
- ret = do_perform_cow(bs, m->offset, m->alloc_offset, r->offset, r->nb_bytes);
- qemu_co_mutex_lock(&s->lock);
+ /* First we read the existing data from both COW regions. We
+ * either read the whole region in one go, or the start and end
+ * regions separately. */
+ if (merge_reads) {
+ qemu_iovec_add(&qiov, start_buffer, buffer_size);
+ ret = do_perform_cow_read(bs, m->offset, start->offset, &qiov);
+ } else {
+ qemu_iovec_add(&qiov, start_buffer, start->nb_bytes);
+ ret = do_perform_cow_read(bs, m->offset, start->offset, &qiov);
+ if (ret < 0) {
+ goto fail;
+ }
+ qemu_iovec_reset(&qiov);
+ qemu_iovec_add(&qiov, end_buffer, end->nb_bytes);
+ ret = do_perform_cow_read(bs, m->offset, end->offset, &qiov);
+ }
if (ret < 0) {
- return ret;
+ goto fail;
}
+ /* Encrypt the data if necessary before writing it */
+ if (bs->encrypted) {
+ 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;
+ }
+ }
+
+ /* And now we can write everything. If we have the guest data we
+ * can write everything in one single operation */
+ if (m->data_qiov) {
+ qemu_iovec_reset(&qiov);
+ if (start->nb_bytes) {
+ qemu_iovec_add(&qiov, start_buffer, start->nb_bytes);
+ }
+ qemu_iovec_concat(&qiov, m->data_qiov, 0, data_bytes);
+ if (end->nb_bytes) {
+ qemu_iovec_add(&qiov, end_buffer, end->nb_bytes);
+ }
+ /* NOTE: we have a write_aio blkdebug event here followed by
+ * a cow_write one in do_perform_cow_write(), but there's only
+ * one single I/O operation */
+ BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
+ ret = do_perform_cow_write(bs, m->alloc_offset, start->offset, &qiov);
+ } else {
+ /* If there's no guest data then write both COW regions separately */
+ qemu_iovec_reset(&qiov);
+ qemu_iovec_add(&qiov, start_buffer, start->nb_bytes);
+ ret = do_perform_cow_write(bs, m->alloc_offset, start->offset, &qiov);
+ if (ret < 0) {
+ goto fail;
+ }
+
+ qemu_iovec_reset(&qiov);
+ qemu_iovec_add(&qiov, end_buffer, end->nb_bytes);
+ ret = do_perform_cow_write(bs, m->alloc_offset, end->offset, &qiov);
+ }
+
+fail:
+ qemu_co_mutex_lock(&s->lock);
+
/*
* Before we update the L2 table to actually point to the new cluster, we
* need to be sure that the refcounts have been increased and COW was
* handled.
*/
- qcow2_cache_depends_on_flush(s->l2_table_cache);
+ if (ret == 0) {
+ qcow2_cache_depends_on_flush(s->l2_table_cache);
+ }
- return 0;
+ qemu_vfree(start_buffer);
+ qemu_iovec_destroy(&qiov);
+ return ret;
}
int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
}
/* copy content of unmodified sectors */
- ret = perform_cow(bs, m, &m->cow_start);
- if (ret < 0) {
- goto err;
- }
-
- ret = perform_cow(bs, m, &m->cow_end);
+ ret = perform_cow(bs, m);
if (ret < 0) {
goto err;
}
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,