cow_co_is_allocated() only checks one sector's worth of allocated bits before 
returning. This is
allowed but (slightly) inefficient, so extend it to check all of the file's 
metadata sectors.

Signed-off-by: Charlie Shepherd <char...@ctshepherd.com>
Reviewed-by: Paolo Bonzini <pbonz...@redhat.com>
---
 block/cow.c | 36 ++++++++++++++++++++++++++----------
 1 file changed, 26 insertions(+), 10 deletions(-)

diff --git a/block/cow.c b/block/cow.c
index 5dfffb0..41097d8 100644
--- a/block/cow.c
+++ b/block/cow.c
@@ -152,18 +152,34 @@ static int coroutine_fn 
cow_co_is_allocated(BlockDriverState *bs,
 {
     int64_t bitnum = sector_num + sizeof(struct cow_header_v2) * 8;
     uint64_t offset = (bitnum / 8) & -BDRV_SECTOR_SIZE;
-    uint8_t bitmap[BDRV_SECTOR_SIZE];
-    int ret;
-    int changed;
+    bool first = true;
+    int changed, same = 0;
 
-    ret = bdrv_pread(bs->file, offset, &bitmap, sizeof(bitmap));
-    if (ret < 0) {
-        return ret;
-    }
+    do {
+        int ret;
+        uint8_t bitmap[BDRV_SECTOR_SIZE];
+
+        bitnum &= BITS_PER_BITMAP_SECTOR - 1;
+        int sector_bits = MIN(nb_sectors, BITS_PER_BITMAP_SECTOR - bitnum);
+
+        ret = bdrv_pread(bs->file, offset, &bitmap, sizeof(bitmap));
+        if (ret < 0) {
+            return ret;
+        }
+
+        if (first) {
+            changed = cow_test_bit(bitnum, bitmap);
+            first = false;
+        }
+
+        same += cow_find_streak(bitmap, changed, bitnum, nb_sectors);
+
+        bitnum += sector_bits;
+        nb_sectors -= sector_bits;
+        offset += BDRV_SECTOR_SIZE;
+    } while (nb_sectors);
 
-    bitnum &= BITS_PER_BITMAP_SECTOR - 1;
-    changed = cow_test_bit(bitnum, bitmap);
-    *num_same = cow_find_streak(bitmap, changed, bitnum, nb_sectors);
+    *num_same = same;
     return changed;
 }
 
-- 
1.8.4.rc3


Reply via email to