qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [PATCH 2/4] qcow2: Allow update_cluster_refcount() to updat


From: Laurent Vivier
Subject: [Qemu-devel] [PATCH 2/4] qcow2: Allow update_cluster_refcount() to update several clusters refcount.
Date: Thu, 06 Nov 2008 17:55:58 +0100

pièce jointe document texte brut
(0002-Allow-update_cluster_refcount-to-update-several-cl.patch)
To improve performance when the qcow2 file is empty, this patch
allows update_cluster_refcount() to update refcount of
several clusters.

Signed-off-by: Laurent Vivier <address@hidden>
---
 block-qcow2.c |  107 ++++++++++++++++++++++++++++++++++++----------------------
 1 file changed, 68 insertions(+), 39 deletions(-)

Index: qemu/block-qcow2.c
===================================================================
--- qemu.orig/block-qcow2.c     2008-11-06 16:40:44.000000000 +0100
+++ qemu/block-qcow2.c  2008-11-06 16:40:45.000000000 +0100
@@ -159,6 +159,7 @@ static void refcount_close(BlockDriverSt
 static int get_refcount(BlockDriverState *bs, int64_t cluster_index);
 static int update_cluster_refcount(BlockDriverState *bs,
                                    int64_t cluster_index,
+                                   int nb_clusters,
                                    int addend);
 static void update_refcount(BlockDriverState *bs,
                             int64_t offset, int64_t length,
@@ -1711,7 +1712,7 @@ static int update_snapshot_refcount(Bloc
                         refcount = 2;
                     } else {
                         if (addend != 0) {
-                            refcount = update_cluster_refcount(bs, offset >> 
s->cluster_bits, addend);
+                            refcount = update_cluster_refcount(bs, offset >> 
s->cluster_bits, 1, addend);
                         } else {
                             refcount = get_refcount(bs, offset >> 
s->cluster_bits);
                         }
@@ -1733,7 +1734,7 @@ static int update_snapshot_refcount(Bloc
             }
 
             if (addend != 0) {
-                refcount = update_cluster_refcount(bs, l2_offset >> 
s->cluster_bits, addend);
+                refcount = update_cluster_refcount(bs, l2_offset >> 
s->cluster_bits, 1, addend);
             } else {
                 refcount = get_refcount(bs, l2_offset >> s->cluster_bits);
             }
@@ -2292,14 +2293,14 @@ static int64_t alloc_bytes(BlockDriverSt
         if (free_in_cluster == 0)
             s->free_byte_offset = 0;
         if ((offset & (s->cluster_size - 1)) != 0)
-            update_cluster_refcount(bs, offset >> s->cluster_bits, 1);
+            update_cluster_refcount(bs, offset >> s->cluster_bits, 1, 1);
     } else {
         offset = alloc_clusters(bs, s->cluster_size);
         cluster_offset = s->free_byte_offset & ~(s->cluster_size - 1);
         if ((cluster_offset + s->cluster_size) == offset) {
             /* we are lucky: contiguous data */
             offset = s->free_byte_offset;
-            update_cluster_refcount(bs, offset >> s->cluster_bits, 1);
+            update_cluster_refcount(bs, offset >> s->cluster_bits, 1, 1);
             s->free_byte_offset += size;
         } else {
             s->free_byte_offset = offset;
@@ -2389,46 +2390,77 @@ static int grow_refcount_table(BlockDriv
 /* XXX: cache several refcount block clusters ? */
 static int update_cluster_refcount(BlockDriverState *bs,
                                    int64_t cluster_index,
+                                   int nb_clusters,
                                    int addend)
 {
     BDRVQcowState *s = bs->opaque;
     int64_t refcount_block_offset;
-    int ret, refcount_table_index, block_index, refcount;
+    int ret, refcount_table_index, refcount_table_last_index, block_index, 
refcount;
+    int nb_block_index;
+    int refcount_cache_size;
 
-    refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
-    if (refcount_table_index >= s->refcount_table_size) {
+    if (nb_clusters == 0)
+        return 0;
+
+    refcount_table_last_index = (cluster_index + nb_clusters - 1) >>
+                                (s->cluster_bits - REFCOUNT_SHIFT);
+
+    /* grow the refcount table if needed */
+
+    if (refcount_table_last_index >= s->refcount_table_size) {
         if (addend < 0)
             return -EINVAL;
-        ret = grow_refcount_table(bs, refcount_table_index + 1);
+        ret = grow_refcount_table(bs, refcount_table_last_index + 1);
         if (ret < 0)
             return ret;
     }
-    refcount_block_offset = s->refcount_table[refcount_table_index];
-    if (!refcount_block_offset) {
-        if (addend < 0)
-            return -EINVAL;
-        refcount_block_offset = alloc_refcount_block(bs, refcount_table_index);
-        if (refcount_block_offset < 0)
-            return -EINVAL;
-    } else {
-        if (load_refcount_block(bs, refcount_block_offset) < 0)
+
+    while (nb_clusters) {
+        refcount_table_index = cluster_index >>
+                               (s->cluster_bits - REFCOUNT_SHIFT);
+        refcount_block_offset = s->refcount_table[refcount_table_index];
+
+        if (!refcount_block_offset) {
+            if (addend < 0)
+                return -EINVAL;
+            refcount_block_offset = alloc_refcount_block(bs, 
refcount_table_index);
+            if (refcount_block_offset < 0)
+                   return -EINVAL;
+        } else {
+            if (load_refcount_block(bs, refcount_block_offset) < 0)
+                return -EIO;
+        }
+
+        /* we can update the count and save it */
+
+        refcount_cache_size = 1 << (s->cluster_bits - REFCOUNT_SHIFT);
+        nb_block_index = 0;
+        block_index = cluster_index & (refcount_cache_size - 1);
+        refcount = 0;
+        while (nb_clusters &&
+               block_index + nb_block_index < refcount_cache_size) {
+
+            refcount = be16_to_cpu(
+                         s->refcount_block_cache[block_index + 
nb_block_index]);
+            refcount += addend;
+            if (refcount < 0 || refcount > 0xffff)
+                return -EINVAL;
+            if (refcount == 0 &&
+                cluster_index + nb_block_index < s->free_cluster_index) {
+                s->free_cluster_index = cluster_index + nb_block_index;
+            }
+            s->refcount_block_cache[block_index + nb_block_index] =
+                                                          
cpu_to_be16(refcount);
+            nb_block_index++;
+            nb_clusters--;
+        }
+        if (bdrv_pwrite(s->hd,
+                        refcount_block_offset + (block_index << 
REFCOUNT_SHIFT),
+                        s->refcount_block_cache + block_index,
+                        nb_block_index * sizeof(uint16_t)) !=
+                        nb_block_index * sizeof(uint16_t))
             return -EIO;
     }
-    /* we can update the count and save it */
-    block_index = cluster_index &
-        ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
-    refcount = be16_to_cpu(s->refcount_block_cache[block_index]);
-    refcount += addend;
-    if (refcount < 0 || refcount > 0xffff)
-        return -EINVAL;
-    if (refcount == 0 && cluster_index < s->free_cluster_index) {
-        s->free_cluster_index = cluster_index;
-    }
-    s->refcount_block_cache[block_index] = cpu_to_be16(refcount);
-    if (bdrv_pwrite(s->hd,
-                    refcount_block_offset + (block_index << REFCOUNT_SHIFT),
-                    &s->refcount_block_cache[block_index], 2) != 2)
-        return -EIO;
     return refcount;
 }
 
@@ -2437,7 +2469,7 @@ static void update_refcount(BlockDriverS
                             int addend)
 {
     BDRVQcowState *s = bs->opaque;
-    int64_t start, last, cluster_offset;
+    int64_t start, last;
 
 #ifdef DEBUG_ALLOC2
     printf("update_refcount: offset=%lld size=%lld addend=%d\n",
@@ -2445,12 +2477,9 @@ static void update_refcount(BlockDriverS
 #endif
     if (length <= 0)
         return;
-    start = offset & ~(s->cluster_size - 1);
-    last = (offset + length - 1) & ~(s->cluster_size - 1);
-    for(cluster_offset = start; cluster_offset <= last;
-        cluster_offset += s->cluster_size) {
-        update_cluster_refcount(bs, cluster_offset >> s->cluster_bits, addend);
-    }
+    start = offset >> s->cluster_bits;
+    last = (offset + length) >> s->cluster_bits;
+    update_cluster_refcount(bs, start, last - start + 1, addend);
 }
 
 #ifdef DEBUG_ALLOC

-- 






reply via email to

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