[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [RFC PATCH 02/16] qcow2: Ignore reserved bits in get_cluste
From: |
Kevin Wolf |
Subject: |
[Qemu-devel] [RFC PATCH 02/16] qcow2: Ignore reserved bits in get_cluster_offset |
Date: |
Tue, 27 Mar 2012 17:03:21 +0200 |
With this change, reading from a qcow2 image ignores all reserved bits
that are set in an L1 or L2 table entry.
Now get_cluster_offset() assigns *cluster_offset only the offset without
any other flags. The cluster type is not longer encoded in the offset,
but a positive return value in case of success.
Signed-off-by: Kevin Wolf <address@hidden>
---
block/qcow2-cluster.c | 41 +++++++++++++++++++++++++----------------
block/qcow2.c | 17 ++++++++++++++---
block/qcow2.h | 21 +++++++++++++++++++++
3 files changed, 60 insertions(+), 19 deletions(-)
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index cbd224d..44d13de 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -367,11 +367,9 @@ out:
*
* on exit, *num is the number of contiguous sectors we can read.
*
- * Return 0, if the offset is found
- * Return -errno, otherwise.
- *
+ * Returns the cluster type (QCOW2_CLUSTER_*) on success, -errno in error
+ * cases.
*/
-
int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
int *num, uint64_t *cluster_offset)
{
@@ -407,19 +405,19 @@ int qcow2_get_cluster_offset(BlockDriverState *bs,
uint64_t offset,
/* seek the the l2 offset in the l1 table */
l1_index = offset >> l1_bits;
- if (l1_index >= s->l1_size)
+ if (l1_index >= s->l1_size) {
+ ret = QCOW2_CLUSTER_UNALLOCATED;
goto out;
+ }
- l2_offset = s->l1_table[l1_index];
-
- /* seek the l2 table of the given l2 offset */
-
- if (!l2_offset)
+ l2_offset = s->l1_table[l1_index] & L1E_OFFSET_MASK;
+ if (!l2_offset) {
+ ret = QCOW2_CLUSTER_UNALLOCATED;
goto out;
+ }
/* load the l2 table in memory */
- l2_offset &= ~QCOW_OFLAG_COPIED;
ret = l2_load(bs, l2_offset, &l2_table);
if (ret < 0) {
return ret;
@@ -431,26 +429,37 @@ int qcow2_get_cluster_offset(BlockDriverState *bs,
uint64_t offset,
*cluster_offset = be64_to_cpu(l2_table[l2_index]);
nb_clusters = size_to_clusters(s, nb_needed << 9);
- if (!*cluster_offset) {
+ ret = qcow2_get_cluster_type(*cluster_offset);
+ switch (ret) {
+ case QCOW2_CLUSTER_COMPRESSED:
+ /* Compressed clusters can only be processed one by one */
+ c = 1;
+ *cluster_offset &= L2E_COMPRESSED_OFFSET_SIZE_MASK;
+ break;
+ case QCOW2_CLUSTER_UNALLOCATED:
/* how many empty clusters ? */
c = count_contiguous_free_clusters(nb_clusters, &l2_table[l2_index]);
- } else {
+ *cluster_offset = 0;
+ break;
+ case QCOW2_CLUSTER_NORMAL:
/* how many allocated clusters ? */
c = count_contiguous_clusters(nb_clusters, s->cluster_size,
&l2_table[l2_index], 0, QCOW_OFLAG_COPIED);
+ *cluster_offset &= L2E_OFFSET_MASK;
+ break;
}
qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
- nb_available = (c * s->cluster_sectors);
+ nb_available = (c * s->cluster_sectors);
+
out:
if (nb_available > nb_needed)
nb_available = nb_needed;
*num = nb_available - index_in_cluster;
- *cluster_offset &=~QCOW_OFLAG_COPIED;
- return 0;
+ return ret;
}
/*
diff --git a/block/qcow2.c b/block/qcow2.c
index 70d3141..4c82adc 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -449,7 +449,8 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState
*bs, int64_t sector_num,
qemu_iovec_copy(&hd_qiov, qiov, bytes_done,
cur_nr_sectors * 512);
- if (!cluster_offset) {
+ switch (ret) {
+ case QCOW2_CLUSTER_UNALLOCATED:
if (bs->backing_hd) {
/* read from the base image */
@@ -469,7 +470,9 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState
*bs, int64_t sector_num,
/* Note: in this case, no need to wait */
qemu_iovec_memset(&hd_qiov, 0, 512 * cur_nr_sectors);
}
- } else if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
+ break;
+
+ case QCOW2_CLUSTER_COMPRESSED:
/* add AIO support for compressed blocks ? */
ret = qcow2_decompress_cluster(bs, cluster_offset);
if (ret < 0) {
@@ -479,7 +482,9 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState
*bs, int64_t sector_num,
qemu_iovec_from_buffer(&hd_qiov,
s->cluster_cache + index_in_cluster * 512,
512 * cur_nr_sectors);
- } else {
+ break;
+
+ case QCOW2_CLUSTER_NORMAL:
if ((cluster_offset & 511) != 0) {
ret = -EIO;
goto fail;
@@ -520,6 +525,12 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState
*bs, int64_t sector_num,
qemu_iovec_from_buffer(&hd_qiov, cluster_data,
512 * cur_nr_sectors);
}
+ break;
+
+ default:
+ g_assert_not_reached();
+ ret = -EIO;
+ goto fail;
}
remaining_sectors -= cur_nr_sectors;
diff --git a/block/qcow2.h b/block/qcow2.h
index e4ac366..bad5448 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -164,6 +164,16 @@ typedef struct QCowL2Meta
QLIST_ENTRY(QCowL2Meta) next_in_flight;
} QCowL2Meta;
+enum {
+ QCOW2_CLUSTER_UNALLOCATED,
+ QCOW2_CLUSTER_NORMAL,
+ QCOW2_CLUSTER_COMPRESSED,
+};
+
+#define L1E_OFFSET_MASK 0x00ffffffffffff00ULL
+#define L2E_OFFSET_MASK 0x00ffffffffffff00ULL
+#define L2E_COMPRESSED_OFFSET_SIZE_MASK 0x3fffffffffffffffULL
+
static inline int size_to_clusters(BDRVQcowState *s, int64_t size)
{
return (size + (s->cluster_size - 1)) >> s->cluster_bits;
@@ -181,6 +191,17 @@ static inline int64_t align_offset(int64_t offset, int n)
return offset;
}
+static inline int qcow2_get_cluster_type(uint64_t l2_entry)
+{
+ if (l2_entry & QCOW_OFLAG_COMPRESSED) {
+ return QCOW2_CLUSTER_COMPRESSED;
+ } else if (!(l2_entry & L2E_OFFSET_MASK)) {
+ return QCOW2_CLUSTER_UNALLOCATED;
+ } else {
+ return QCOW2_CLUSTER_NORMAL;
+ }
+}
+
// FIXME Need qcow2_ prefix to global functions
--
1.7.6.5
- [Qemu-devel] [RFC PATCH 00/16] qcow2: Basic version 3 support, Kevin Wolf, 2012/03/27
- [Qemu-devel] [RFC PATCH 08/16] qcow2: Ignore reserved bits in refcount table entries, Kevin Wolf, 2012/03/27
- [Qemu-devel] [RFC PATCH 03/16] qcow2: Ignore reserved bits in count_contiguous_clusters(), Kevin Wolf, 2012/03/27
- [Qemu-devel] [RFC PATCH 05/16] qcow2: Ignore reserved bits in L1/L2 entries, Kevin Wolf, 2012/03/27
- [Qemu-devel] [RFC PATCH 12/16] qcow2: Support for feature table header extension, Kevin Wolf, 2012/03/27
- [Qemu-devel] [RFC PATCH 01/16] Specification for qcow2 version 3, Kevin Wolf, 2012/03/27
- [Qemu-devel] [RFC PATCH 04/16] qcow2: Fail write_compressed when overwriting data, Kevin Wolf, 2012/03/27
- [Qemu-devel] [RFC PATCH 06/16] qcow2: Refactor qcow2_free_any_clusters, Kevin Wolf, 2012/03/27
- [Qemu-devel] [RFC PATCH 09/16] qcow2: Ignore reserved bits in check_refcounts, Kevin Wolf, 2012/03/27
- [Qemu-devel] [RFC PATCH 02/16] qcow2: Ignore reserved bits in get_cluster_offset,
Kevin Wolf <=
- [Qemu-devel] [RFC PATCH 14/16] qemu-iotests: Test COW with zero clusters, Kevin Wolf, 2012/03/27
- [Qemu-devel] [RFC PATCH 11/16] qcow2: Support reading zero clusters, Kevin Wolf, 2012/03/27
- [Qemu-devel] [RFC PATCH 13/16] qemu-iotests: add a simple test for write_zeroes, Kevin Wolf, 2012/03/27
- [Qemu-devel] [RFC PATCH 15/16] qcow2: Zero write support, Kevin Wolf, 2012/03/27
- [Qemu-devel] [RFC PATCH 16/16] qemu-iotests: use qcow3, Kevin Wolf, 2012/03/27
- [Qemu-devel] [RFC PATCH 10/16] qcow2: Version 3 images, Kevin Wolf, 2012/03/27
- [Qemu-devel] [RFC PATCH 07/16] qcow2: Simplify count_cow_clusters, Kevin Wolf, 2012/03/27