qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [RFC PATCH 11/16] qcow2: Support reading zero clusters


From: Kevin Wolf
Subject: [Qemu-devel] [RFC PATCH 11/16] qcow2: Support reading zero clusters
Date: Tue, 27 Mar 2012 17:03:30 +0200

This adds support for reading zero clusters in version 3 images.

Signed-off-by: Kevin Wolf <address@hidden>
---
 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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]