From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([208.118.235.92]:57388) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SCXsl-0001fk-4S for qemu-devel@nongnu.org; Tue, 27 Mar 2012 11:00:32 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1SCXse-0007Iq-5Q for qemu-devel@nongnu.org; Tue, 27 Mar 2012 11:00:22 -0400 Received: from mx1.redhat.com ([209.132.183.28]:50362) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SCXsd-0007IC-UI for qemu-devel@nongnu.org; Tue, 27 Mar 2012 11:00:16 -0400 From: Kevin Wolf Date: Tue, 27 Mar 2012 17:03:30 +0200 Message-Id: <1332860615-3047-12-git-send-email-kwolf@redhat.com> In-Reply-To: <1332860615-3047-1-git-send-email-kwolf@redhat.com> References: <1332860615-3047-1-git-send-email-kwolf@redhat.com> Subject: [Qemu-devel] [RFC PATCH 11/16] qcow2: Support reading zero clusters List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: kwolf@redhat.com, stefanha@gmail.com This adds support for reading zero clusters in version 3 images. Signed-off-by: Kevin Wolf --- block/qcow2-cluster.c | 17 +++++++++++++---- block/qcow2-refcount.c | 7 +++++++ block/qcow2.c | 8 ++++++++ block/qcow2.h | 5 +++++ 4 files changed, 33 insertions(+), 4 deletions(-) diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index b120b92..4853f1f 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -453,6 +453,12 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset, c = 1; *cluster_offset &= L2E_COMPRESSED_OFFSET_SIZE_MASK; 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: /* how many empty clusters ? */ 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, case QCOW2_CLUSTER_NORMAL: /* how many allocated clusters ? */ 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; break; } @@ -720,6 +727,7 @@ static int count_cow_clusters(BDRVQcowState *s, int nb_clusters, break; case QCOW2_CLUSTER_UNALLOCATED: case QCOW2_CLUSTER_COMPRESSED: + case QCOW2_CLUSTER_ZERO: break; default: abort(); @@ -868,9 +876,10 @@ again: && (cluster_offset & QCOW_OFLAG_COPIED)) { /* We keep all QCOW_OFLAG_COPIED clusters */ - keep_clusters = count_contiguous_clusters(nb_clusters, s->cluster_size, - &l2_table[l2_index], 0, - QCOW_OFLAG_COPIED); + keep_clusters = + count_contiguous_clusters(nb_clusters, s->cluster_size, + &l2_table[l2_index], 0, + QCOW_OFLAG_COPIED | QCOW_OFLAG_ZERO); assert(keep_clusters <= nb_clusters); nb_clusters -= keep_clusters; } else { diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index c5d3171..60e2fb5 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -697,6 +697,7 @@ void qcow2_free_any_clusters(BlockDriverState *bs, nb_clusters << s->cluster_bits); break; case QCOW2_CLUSTER_UNALLOCATED: + case QCOW2_CLUSTER_ZERO: break; default: abort(); @@ -967,6 +968,12 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res, l2_entry & ~511, nb_csectors * 512); break; + case QCOW2_CLUSTER_ZERO: + if ((l2_entry & L2E_OFFSET_MASK) == 0) { + break; + } + /* fall through */ + case QCOW2_CLUSTER_NORMAL: { /* QCOW_OFLAG_COPIED must be set iff refcount == 1 */ diff --git a/block/qcow2.c b/block/qcow2.c index c1f113d..aef8282 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -536,6 +536,14 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num, } 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: /* add AIO support for compressed blocks ? */ ret = qcow2_decompress_cluster(bs, cluster_offset); diff --git a/block/qcow2.h b/block/qcow2.h index 71b8d88..64cfa69 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -43,6 +43,8 @@ #define QCOW_OFLAG_COPIED (1LL << 63) /* indicate that the cluster is compressed (they never have the copied flag) */ #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 */ @@ -183,6 +185,7 @@ enum { QCOW2_CLUSTER_UNALLOCATED, QCOW2_CLUSTER_NORMAL, QCOW2_CLUSTER_COMPRESSED, + QCOW2_CLUSTER_ZERO }; #define L1E_OFFSET_MASK 0x00ffffffffffff00ULL @@ -212,6 +215,8 @@ 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 & QCOW_OFLAG_ZERO) { + return QCOW2_CLUSTER_ZERO; } else if (!(l2_entry & L2E_OFFSET_MASK)) { return QCOW2_CLUSTER_UNALLOCATED; } else { -- 1.7.6.5