提交 6377af48 编写于 作者: K Kevin Wolf

qcow2: Support reading zero clusters

This adds support for reading zero clusters in version 3 images.
Signed-off-by: NKevin Wolf <kwolf@redhat.com>
上级 6744cbab
...@@ -453,6 +453,12 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset, ...@@ -453,6 +453,12 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
c = 1; c = 1;
*cluster_offset &= L2E_COMPRESSED_OFFSET_SIZE_MASK; *cluster_offset &= L2E_COMPRESSED_OFFSET_SIZE_MASK;
break; break;
case QCOW2_CLUSTER_ZERO:
c = count_contiguous_clusters(nb_clusters, s->cluster_size,
&l2_table[l2_index], 0,
QCOW_OFLAG_COMPRESSED | QCOW_OFLAG_ZERO);
*cluster_offset = 0;
break;
case QCOW2_CLUSTER_UNALLOCATED: case QCOW2_CLUSTER_UNALLOCATED:
/* how many empty clusters ? */ /* how many empty clusters ? */
c = count_contiguous_free_clusters(nb_clusters, &l2_table[l2_index]); c = count_contiguous_free_clusters(nb_clusters, &l2_table[l2_index]);
...@@ -461,7 +467,8 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset, ...@@ -461,7 +467,8 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
case QCOW2_CLUSTER_NORMAL: case QCOW2_CLUSTER_NORMAL:
/* how many allocated clusters ? */ /* how many allocated clusters ? */
c = count_contiguous_clusters(nb_clusters, s->cluster_size, c = count_contiguous_clusters(nb_clusters, s->cluster_size,
&l2_table[l2_index], 0, QCOW_OFLAG_COMPRESSED); &l2_table[l2_index], 0,
QCOW_OFLAG_COMPRESSED | QCOW_OFLAG_ZERO);
*cluster_offset &= L2E_OFFSET_MASK; *cluster_offset &= L2E_OFFSET_MASK;
break; break;
} }
...@@ -720,6 +727,7 @@ static int count_cow_clusters(BDRVQcowState *s, int nb_clusters, ...@@ -720,6 +727,7 @@ static int count_cow_clusters(BDRVQcowState *s, int nb_clusters,
break; break;
case QCOW2_CLUSTER_UNALLOCATED: case QCOW2_CLUSTER_UNALLOCATED:
case QCOW2_CLUSTER_COMPRESSED: case QCOW2_CLUSTER_COMPRESSED:
case QCOW2_CLUSTER_ZERO:
break; break;
default: default:
abort(); abort();
...@@ -868,9 +876,10 @@ again: ...@@ -868,9 +876,10 @@ again:
&& (cluster_offset & QCOW_OFLAG_COPIED)) && (cluster_offset & QCOW_OFLAG_COPIED))
{ {
/* We keep all QCOW_OFLAG_COPIED clusters */ /* We keep all QCOW_OFLAG_COPIED clusters */
keep_clusters = count_contiguous_clusters(nb_clusters, s->cluster_size, keep_clusters =
&l2_table[l2_index], 0, count_contiguous_clusters(nb_clusters, s->cluster_size,
QCOW_OFLAG_COPIED); &l2_table[l2_index], 0,
QCOW_OFLAG_COPIED | QCOW_OFLAG_ZERO);
assert(keep_clusters <= nb_clusters); assert(keep_clusters <= nb_clusters);
nb_clusters -= keep_clusters; nb_clusters -= keep_clusters;
} else { } else {
......
...@@ -703,6 +703,7 @@ void qcow2_free_any_clusters(BlockDriverState *bs, ...@@ -703,6 +703,7 @@ void qcow2_free_any_clusters(BlockDriverState *bs,
nb_clusters << s->cluster_bits); nb_clusters << s->cluster_bits);
break; break;
case QCOW2_CLUSTER_UNALLOCATED: case QCOW2_CLUSTER_UNALLOCATED:
case QCOW2_CLUSTER_ZERO:
break; break;
default: default:
abort(); abort();
...@@ -973,6 +974,12 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res, ...@@ -973,6 +974,12 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
l2_entry & ~511, nb_csectors * 512); l2_entry & ~511, nb_csectors * 512);
break; break;
case QCOW2_CLUSTER_ZERO:
if ((l2_entry & L2E_OFFSET_MASK) == 0) {
break;
}
/* fall through */
case QCOW2_CLUSTER_NORMAL: case QCOW2_CLUSTER_NORMAL:
{ {
/* QCOW_OFLAG_COPIED must be set iff refcount == 1 */ /* QCOW_OFLAG_COPIED must be set iff refcount == 1 */
......
...@@ -536,6 +536,14 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num, ...@@ -536,6 +536,14 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num,
} }
break; break;
case QCOW2_CLUSTER_ZERO:
if (s->qcow_version < 3) {
ret = -EIO;
goto fail;
}
qemu_iovec_memset(&hd_qiov, 0, 512 * cur_nr_sectors);
break;
case QCOW2_CLUSTER_COMPRESSED: case QCOW2_CLUSTER_COMPRESSED:
/* add AIO support for compressed blocks ? */ /* add AIO support for compressed blocks ? */
ret = qcow2_decompress_cluster(bs, cluster_offset); ret = qcow2_decompress_cluster(bs, cluster_offset);
......
...@@ -43,6 +43,8 @@ ...@@ -43,6 +43,8 @@
#define QCOW_OFLAG_COPIED (1LL << 63) #define QCOW_OFLAG_COPIED (1LL << 63)
/* indicate that the cluster is compressed (they never have the copied flag) */ /* indicate that the cluster is compressed (they never have the copied flag) */
#define QCOW_OFLAG_COMPRESSED (1LL << 62) #define QCOW_OFLAG_COMPRESSED (1LL << 62)
/* The cluster reads as all zeros */
#define QCOW_OFLAG_ZERO (1LL << 0)
#define REFCOUNT_SHIFT 1 /* refcount size is 2 bytes */ #define REFCOUNT_SHIFT 1 /* refcount size is 2 bytes */
...@@ -184,6 +186,7 @@ enum { ...@@ -184,6 +186,7 @@ enum {
QCOW2_CLUSTER_UNALLOCATED, QCOW2_CLUSTER_UNALLOCATED,
QCOW2_CLUSTER_NORMAL, QCOW2_CLUSTER_NORMAL,
QCOW2_CLUSTER_COMPRESSED, QCOW2_CLUSTER_COMPRESSED,
QCOW2_CLUSTER_ZERO
}; };
#define L1E_OFFSET_MASK 0x00ffffffffffff00ULL #define L1E_OFFSET_MASK 0x00ffffffffffff00ULL
...@@ -213,6 +216,8 @@ static inline int qcow2_get_cluster_type(uint64_t l2_entry) ...@@ -213,6 +216,8 @@ static inline int qcow2_get_cluster_type(uint64_t l2_entry)
{ {
if (l2_entry & QCOW_OFLAG_COMPRESSED) { if (l2_entry & QCOW_OFLAG_COMPRESSED) {
return QCOW2_CLUSTER_COMPRESSED; return QCOW2_CLUSTER_COMPRESSED;
} else if (l2_entry & QCOW_OFLAG_ZERO) {
return QCOW2_CLUSTER_ZERO;
} else if (!(l2_entry & L2E_OFFSET_MASK)) { } else if (!(l2_entry & L2E_OFFSET_MASK)) {
return QCOW2_CLUSTER_UNALLOCATED; return QCOW2_CLUSTER_UNALLOCATED;
} else { } else {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册