@@ -497,21 +497,22 @@ static int coroutine_fn do_perform_cow_write(BlockDriverState *bs,
/*
* get_cluster_offset
*
- * For a given offset of the virtual disk, find the cluster type and offset in
- * the qcow2 file. The offset is stored in *cluster_offset.
+ * For a given offset of the virtual disk, find the cluster offset in
+ * the qcow2 file and store it in *cluster_offset.
*
* On entry, *bytes is the maximum number of contiguous bytes starting at
* offset that we are interested in.
*
* On exit, *bytes is the number of bytes starting at offset that have the same
- * cluster type and (if applicable) are stored contiguously in the image file.
- * Compressed clusters are always returned one by one.
+ * subcluster type and (if applicable) are stored contiguously in the image
+ * file. The subcluster type is stored in *subcluster_type. Compressed clusters
+ * are always processed one by one.
*
- * Returns the cluster type (QCOW2_CLUSTER_*) on success, -errno in error
- * cases.
+ * Returns 0 on success, -errno in error cases.
*/
int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
- unsigned int *bytes, uint64_t *cluster_offset)
+ unsigned int *bytes, uint64_t *cluster_offset,
+ QCow2SubclusterType *subcluster_type)
{
BDRVQcow2State *s = bs->opaque;
unsigned int l2_index;
@@ -653,7 +654,9 @@ out:
assert(bytes_available - offset_in_cluster <= UINT_MAX);
*bytes = bytes_available - offset_in_cluster;
- return type;
+ *subcluster_type = qcow2_cluster_to_subcluster_type(type);
+
+ return 0;
fail:
qcow2_cache_put(s->l2_table_cache, (void **)&l2_slice);
@@ -1964,6 +1964,7 @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs,
BDRVQcow2State *s = bs->opaque;
uint64_t cluster_offset;
unsigned int bytes;
+ QCow2SubclusterType type;
int ret, status = 0;
qemu_co_mutex_lock(&s->lock);
@@ -1975,7 +1976,7 @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs,
}
bytes = MIN(INT_MAX, count);
- ret = qcow2_get_cluster_offset(bs, offset, &bytes, &cluster_offset);
+ ret = qcow2_get_cluster_offset(bs, offset, &bytes, &cluster_offset, &type);
qemu_co_mutex_unlock(&s->lock);
if (ret < 0) {
return ret;
@@ -1983,15 +1984,16 @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs,
*pnum = bytes;
- if ((ret == QCOW2_CLUSTER_NORMAL || ret == QCOW2_CLUSTER_ZERO_ALLOC) &&
- !s->crypto) {
+ if ((type == QCOW2_SUBCLUSTER_NORMAL ||
+ type == QCOW2_SUBCLUSTER_ZERO_ALLOC) && !s->crypto) {
*map = cluster_offset | offset_into_cluster(s, offset);
*file = s->data_file->bs;
status |= BDRV_BLOCK_OFFSET_VALID;
}
- if (ret == QCOW2_CLUSTER_ZERO_PLAIN || ret == QCOW2_CLUSTER_ZERO_ALLOC) {
+ if (type == QCOW2_SUBCLUSTER_ZERO_PLAIN ||
+ type == QCOW2_SUBCLUSTER_ZERO_ALLOC) {
status |= BDRV_BLOCK_ZERO;
- } else if (ret != QCOW2_CLUSTER_UNALLOCATED) {
+ } else if (type != QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN) {
status |= BDRV_BLOCK_DATA;
}
if (s->metadata_preallocation && (status & BDRV_BLOCK_DATA) &&
@@ -2094,7 +2096,7 @@ typedef struct Qcow2AioTask {
AioTask task;
BlockDriverState *bs;
- QCow2ClusterType cluster_type; /* only for read */
+ QCow2SubclusterType subcluster_type; /* only for read */
uint64_t file_cluster_offset;
uint64_t offset;
uint64_t bytes;
@@ -2107,7 +2109,7 @@ static coroutine_fn int qcow2_co_preadv_task_entry(AioTask *task);
static coroutine_fn int qcow2_add_task(BlockDriverState *bs,
AioTaskPool *pool,
AioTaskFunc func,
- QCow2ClusterType cluster_type,
+ QCow2SubclusterType subcluster_type,
uint64_t file_cluster_offset,
uint64_t offset,
uint64_t bytes,
@@ -2121,7 +2123,7 @@ static coroutine_fn int qcow2_add_task(BlockDriverState *bs,
*task = (Qcow2AioTask) {
.task.func = func,
.bs = bs,
- .cluster_type = cluster_type,
+ .subcluster_type = subcluster_type,
.qiov = qiov,
.file_cluster_offset = file_cluster_offset,
.offset = offset,
@@ -2132,7 +2134,7 @@ static coroutine_fn int qcow2_add_task(BlockDriverState *bs,
trace_qcow2_add_task(qemu_coroutine_self(), bs, pool,
func == qcow2_co_preadv_task_entry ? "read" : "write",
- cluster_type, file_cluster_offset, offset, bytes,
+ subcluster_type, file_cluster_offset, offset, bytes,
qiov, qiov_offset);
if (!pool) {
@@ -2145,7 +2147,7 @@ static coroutine_fn int qcow2_add_task(BlockDriverState *bs,
}
static coroutine_fn int qcow2_co_preadv_task(BlockDriverState *bs,
- QCow2ClusterType cluster_type,
+ QCow2SubclusterType subc_type,
uint64_t file_cluster_offset,
uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov,
@@ -2154,24 +2156,24 @@ static coroutine_fn int qcow2_co_preadv_task(BlockDriverState *bs,
BDRVQcow2State *s = bs->opaque;
int offset_in_cluster = offset_into_cluster(s, offset);
- switch (cluster_type) {
- case QCOW2_CLUSTER_ZERO_PLAIN:
- case QCOW2_CLUSTER_ZERO_ALLOC:
+ switch (subc_type) {
+ case QCOW2_SUBCLUSTER_ZERO_PLAIN:
+ case QCOW2_SUBCLUSTER_ZERO_ALLOC:
/* Both zero types are handled in qcow2_co_preadv_part */
g_assert_not_reached();
- case QCOW2_CLUSTER_UNALLOCATED:
+ case QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN:
assert(bs->backing); /* otherwise handled in qcow2_co_preadv_part */
BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
return bdrv_co_preadv_part(bs->backing, offset, bytes,
qiov, qiov_offset, 0);
- case QCOW2_CLUSTER_COMPRESSED:
+ case QCOW2_SUBCLUSTER_COMPRESSED:
return qcow2_co_preadv_compressed(bs, file_cluster_offset,
offset, bytes, qiov, qiov_offset);
- case QCOW2_CLUSTER_NORMAL:
+ case QCOW2_SUBCLUSTER_NORMAL:
if ((file_cluster_offset & 511) != 0) {
return -EIO;
}
@@ -2199,8 +2201,9 @@ static coroutine_fn int qcow2_co_preadv_task_entry(AioTask *task)
assert(!t->l2meta);
- return qcow2_co_preadv_task(t->bs, t->cluster_type, t->file_cluster_offset,
- t->offset, t->bytes, t->qiov, t->qiov_offset);
+ return qcow2_co_preadv_task(t->bs, t->subcluster_type,
+ t->file_cluster_offset, t->offset, t->bytes,
+ t->qiov, t->qiov_offset);
}
static coroutine_fn int qcow2_co_preadv_part(BlockDriverState *bs,
@@ -2212,6 +2215,7 @@ static coroutine_fn int qcow2_co_preadv_part(BlockDriverState *bs,
int ret = 0;
unsigned int cur_bytes; /* number of bytes in current iteration */
uint64_t cluster_offset = 0;
+ QCow2SubclusterType type;
AioTaskPool *aio = NULL;
while (bytes != 0 && aio_task_pool_status(aio) == 0) {
@@ -2223,22 +2227,23 @@ static coroutine_fn int qcow2_co_preadv_part(BlockDriverState *bs,
}
qemu_co_mutex_lock(&s->lock);
- ret = qcow2_get_cluster_offset(bs, offset, &cur_bytes, &cluster_offset);
+ ret = qcow2_get_cluster_offset(bs, offset, &cur_bytes,
+ &cluster_offset, &type);
qemu_co_mutex_unlock(&s->lock);
if (ret < 0) {
goto out;
}
- if (ret == QCOW2_CLUSTER_ZERO_PLAIN ||
- ret == QCOW2_CLUSTER_ZERO_ALLOC ||
- (ret == QCOW2_CLUSTER_UNALLOCATED && !bs->backing))
+ if (type == QCOW2_SUBCLUSTER_ZERO_PLAIN ||
+ type == QCOW2_SUBCLUSTER_ZERO_ALLOC ||
+ (type == QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN && !bs->backing))
{
qemu_iovec_memset(qiov, qiov_offset, 0, cur_bytes);
} else {
if (!aio && cur_bytes != bytes) {
aio = aio_task_pool_new(QCOW2_MAX_WORKERS);
}
- ret = qcow2_add_task(bs, aio, qcow2_co_preadv_task_entry, ret,
+ ret = qcow2_add_task(bs, aio, qcow2_co_preadv_task_entry, type,
cluster_offset, offset, cur_bytes,
qiov, qiov_offset, NULL);
if (ret < 0) {
@@ -2469,7 +2474,7 @@ static coroutine_fn int qcow2_co_pwritev_task_entry(AioTask *task)
{
Qcow2AioTask *t = container_of(task, Qcow2AioTask, task);
- assert(!t->cluster_type);
+ assert(!t->subcluster_type);
return qcow2_co_pwritev_task(t->bs, t->file_cluster_offset,
t->offset, t->bytes, t->qiov, t->qiov_offset,
@@ -3723,6 +3728,7 @@ static coroutine_fn int qcow2_co_pwrite_zeroes(BlockDriverState *bs,
if (head || tail) {
uint64_t off;
unsigned int nr;
+ QCow2SubclusterType type;
assert(head + bytes <= s->cluster_size);
@@ -3738,10 +3744,14 @@ static coroutine_fn int qcow2_co_pwrite_zeroes(BlockDriverState *bs,
offset = QEMU_ALIGN_DOWN(offset, s->cluster_size);
bytes = s->cluster_size;
nr = s->cluster_size;
- ret = qcow2_get_cluster_offset(bs, offset, &nr, &off);
- if (ret != QCOW2_CLUSTER_UNALLOCATED &&
- ret != QCOW2_CLUSTER_ZERO_PLAIN &&
- ret != QCOW2_CLUSTER_ZERO_ALLOC) {
+ ret = qcow2_get_cluster_offset(bs, offset, &nr, &off, &type);
+ if (ret < 0) {
+ qemu_co_mutex_unlock(&s->lock);
+ return -ENOTSUP;
+ }
+ if (type != QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN &&
+ type != QCOW2_SUBCLUSTER_ZERO_PLAIN &&
+ type != QCOW2_SUBCLUSTER_ZERO_ALLOC) {
qemu_co_mutex_unlock(&s->lock);
return -ENOTSUP;
}
@@ -3799,17 +3809,19 @@ qcow2_co_copy_range_from(BlockDriverState *bs,
while (bytes != 0) {
uint64_t copy_offset = 0;
+ QCow2SubclusterType type;
/* prepare next request */
cur_bytes = MIN(bytes, INT_MAX);
cur_write_flags = write_flags;
- ret = qcow2_get_cluster_offset(bs, src_offset, &cur_bytes, ©_offset);
+ ret = qcow2_get_cluster_offset(bs, src_offset, &cur_bytes,
+ ©_offset, &type);
if (ret < 0) {
goto out;
}
- switch (ret) {
- case QCOW2_CLUSTER_UNALLOCATED:
+ switch (type) {
+ case QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN:
if (bs->backing && bs->backing->bs) {
int64_t backing_length = bdrv_getlength(bs->backing->bs);
if (src_offset >= backing_length) {
@@ -3824,16 +3836,16 @@ qcow2_co_copy_range_from(BlockDriverState *bs,
}
break;
- case QCOW2_CLUSTER_ZERO_PLAIN:
- case QCOW2_CLUSTER_ZERO_ALLOC:
+ case QCOW2_SUBCLUSTER_ZERO_PLAIN:
+ case QCOW2_SUBCLUSTER_ZERO_ALLOC:
cur_write_flags |= BDRV_REQ_ZERO_WRITE;
break;
- case QCOW2_CLUSTER_COMPRESSED:
+ case QCOW2_SUBCLUSTER_COMPRESSED:
ret = -ENOTSUP;
goto out;
- case QCOW2_CLUSTER_NORMAL:
+ case QCOW2_SUBCLUSTER_NORMAL:
child = s->data_file;
copy_offset += offset_into_cluster(s, src_offset);
if ((copy_offset & 511) != 0) {
@@ -831,7 +831,8 @@ int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num,
uint8_t *buf, int nb_sectors, bool enc, Error **errp);
int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
- unsigned int *bytes, uint64_t *cluster_offset);
+ unsigned int *bytes, uint64_t *cluster_offset,
+ QCow2SubclusterType *subcluster_type);
int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
unsigned int *bytes, uint64_t *host_offset,
QCowL2Meta **m);
In order to support extended L2 entries some functions of the qcow2 driver need to start dealing with subclusters instead of clusters. qcow2_get_cluster_offset() is modified to return the subcluster type instead of the cluster type, and all callers are updated to replace all values of QCow2ClusterType with their QCow2SubclusterType equivalents (as returned by qcow2_cluster_to_subcluster_type()). This patch only changes the data types, there are no semantic changes. Signed-off-by: Alberto Garcia <berto@igalia.com> --- block/qcow2-cluster.c | 19 +++++----- block/qcow2.c | 82 +++++++++++++++++++++++++------------------ block/qcow2.h | 3 +- 3 files changed, 60 insertions(+), 44 deletions(-)