@@ -676,8 +676,8 @@ int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index);
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);
+int qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset,
+ unsigned int *bytes, uint64_t *host_offset);
int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
unsigned int *bytes, uint64_t *host_offset,
QCowL2Meta **m);
@@ -496,10 +496,15 @@ static int coroutine_fn do_perform_cow_write(BlockDriverState *bs,
/*
- * get_cluster_offset
+ * get_host_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 equivalent host
+ * offset in the qcow2 file and store it in *host_offset. Neither
+ * offset needs to be aligned to a cluster boundary.
+ *
+ * If the cluster is unallocated then *host_offset will be 0.
+ * If the cluster is compressed then *host_offset will contain the
+ * complete compressed cluster descriptor.
*
* On entry, *bytes is the maximum number of contiguous bytes starting at
* offset that we are interested in.
@@ -511,12 +516,12 @@ static int coroutine_fn do_perform_cow_write(BlockDriverState *bs,
* Returns the cluster type (QCOW2_CLUSTER_*) on success, -errno in error
* cases.
*/
-int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
- unsigned int *bytes, uint64_t *cluster_offset)
+int qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset,
+ unsigned int *bytes, uint64_t *host_offset)
{
BDRVQcow2State *s = bs->opaque;
unsigned int l2_index;
- uint64_t l1_index, l2_offset, *l2_slice;
+ uint64_t l1_index, l2_offset, *l2_slice, l2_entry;
int c;
unsigned int offset_in_cluster;
uint64_t bytes_available, bytes_needed, nb_clusters;
@@ -537,8 +542,6 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
bytes_needed = bytes_available;
}
- *cluster_offset = 0;
-
/* seek to the l2 offset in the l1 table */
l1_index = offset_to_l1_index(s, offset);
@@ -570,7 +573,7 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
/* find the cluster offset for the given disk offset */
l2_index = offset_to_l2_slice_index(s, offset);
- *cluster_offset = be64_to_cpu(l2_slice[l2_index]);
+ l2_entry = be64_to_cpu(l2_slice[l2_index]);
nb_clusters = size_to_clusters(s, bytes_needed);
/* bytes_needed <= *bytes + offset_in_cluster, both of which are unsigned
@@ -578,7 +581,7 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
* true */
assert(nb_clusters <= INT_MAX);
- type = qcow2_get_cluster_type(bs, *cluster_offset);
+ type = qcow2_get_cluster_type(bs, l2_entry);
if (s->qcow_version < 3 && (type == QCOW2_CLUSTER_ZERO_PLAIN ||
type == QCOW2_CLUSTER_ZERO_ALLOC)) {
qcow2_signal_corruption(bs, true, -1, -1, "Zero cluster entry found"
@@ -599,42 +602,43 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
}
/* Compressed clusters can only be processed one by one */
c = 1;
- *cluster_offset &= L2E_COMPRESSED_OFFSET_SIZE_MASK;
+ *host_offset = l2_entry & L2E_COMPRESSED_OFFSET_SIZE_MASK;
break;
case QCOW2_CLUSTER_ZERO_PLAIN:
case QCOW2_CLUSTER_UNALLOCATED:
/* how many empty clusters ? */
c = count_contiguous_clusters_unallocated(bs, nb_clusters,
&l2_slice[l2_index], type);
- *cluster_offset = 0;
+ *host_offset = 0;
break;
case QCOW2_CLUSTER_ZERO_ALLOC:
- case QCOW2_CLUSTER_NORMAL:
+ case QCOW2_CLUSTER_NORMAL: {
+ uint64_t host_cluster_offset = l2_entry & L2E_OFFSET_MASK;
+ *host_offset = host_cluster_offset + offset_in_cluster;
/* how many allocated clusters ? */
c = count_contiguous_clusters(bs, nb_clusters, s->cluster_size,
&l2_slice[l2_index], QCOW_OFLAG_ZERO);
- *cluster_offset &= L2E_OFFSET_MASK;
- if (offset_into_cluster(s, *cluster_offset)) {
+ if (offset_into_cluster(s, host_cluster_offset)) {
qcow2_signal_corruption(bs, true, -1, -1,
"Cluster allocation offset %#"
PRIx64 " unaligned (L2 offset: %#" PRIx64
- ", L2 index: %#x)", *cluster_offset,
+ ", L2 index: %#x)", host_cluster_offset,
l2_offset, l2_index);
ret = -EIO;
goto fail;
}
- if (has_data_file(bs) && *cluster_offset != offset - offset_in_cluster)
- {
+ if (has_data_file(bs) && *host_offset != offset) {
qcow2_signal_corruption(bs, true, -1, -1,
"External data file host cluster offset %#"
PRIx64 " does not match guest cluster "
"offset: %#" PRIx64
- ", L2 index: %#x)", *cluster_offset,
+ ", L2 index: %#x)", host_cluster_offset,
offset - offset_in_cluster, l2_index);
ret = -EIO;
goto fail;
}
break;
+ }
default:
abort();
}
@@ -1966,7 +1966,7 @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs,
BlockDriverState **file)
{
BDRVQcow2State *s = bs->opaque;
- uint64_t cluster_offset;
+ uint64_t host_offset;
unsigned int bytes;
int ret, status = 0;
@@ -1979,7 +1979,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_host_offset(bs, offset, &bytes, &host_offset);
qemu_co_mutex_unlock(&s->lock);
if (ret < 0) {
return ret;
@@ -1989,7 +1989,7 @@ static int coroutine_fn qcow2_co_block_status(BlockDriverState *bs,
if ((ret == QCOW2_CLUSTER_NORMAL || ret == QCOW2_CLUSTER_ZERO_ALLOC) &&
!s->crypto) {
- *map = cluster_offset | offset_into_cluster(s, offset);
+ *map = host_offset;
*file = s->data_file->bs;
status |= BDRV_BLOCK_OFFSET_VALID;
}
@@ -2203,7 +2203,7 @@ static coroutine_fn int qcow2_co_preadv_part(BlockDriverState *bs,
BDRVQcow2State *s = bs->opaque;
int ret = 0;
unsigned int cur_bytes; /* number of bytes in current iteration */
- uint64_t cluster_offset = 0;
+ uint64_t host_offset = 0;
AioTaskPool *aio = NULL;
while (bytes != 0 && aio_task_pool_status(aio) == 0) {
@@ -2215,7 +2215,7 @@ 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_host_offset(bs, offset, &cur_bytes, &host_offset);
qemu_co_mutex_unlock(&s->lock);
if (ret < 0) {
goto out;
@@ -2227,15 +2227,6 @@ static coroutine_fn int qcow2_co_preadv_part(BlockDriverState *bs,
{
qemu_iovec_memset(qiov, qiov_offset, 0, cur_bytes);
} else {
- /*
- * For compressed clusters the variable cluster_offset
- * does not actually store the offset but the full
- * descriptor. We need to leave it unchanged because
- * that's what qcow2_co_preadv_compressed() expects.
- */
- uint64_t host_offset = (ret == QCOW2_CLUSTER_COMPRESSED) ?
- cluster_offset :
- cluster_offset + offset_into_cluster(s, offset);
if (!aio && cur_bytes != bytes) {
aio = aio_task_pool_new(QCOW2_MAX_WORKERS);
}
@@ -3756,7 +3747,7 @@ 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);
+ ret = qcow2_get_host_offset(bs, offset, &nr, &off);
if (ret != QCOW2_CLUSTER_UNALLOCATED &&
ret != QCOW2_CLUSTER_ZERO_PLAIN &&
ret != QCOW2_CLUSTER_ZERO_ALLOC) {
@@ -3827,7 +3818,7 @@ qcow2_co_copy_range_from(BlockDriverState *bs,
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_host_offset(bs, src_offset, &cur_bytes, ©_offset);
if (ret < 0) {
goto out;
}
@@ -3859,7 +3850,6 @@ qcow2_co_copy_range_from(BlockDriverState *bs,
case QCOW2_CLUSTER_NORMAL:
child = s->data_file;
- copy_offset += offset_into_cluster(s, src_offset);
break;
default: