diff mbox series

[v2,08/11] block/backup: add backup_is_cluster_allocated

Message ID 20190716000117.25219-9-jsnow@redhat.com (mailing list archive)
State New, archived
Headers show
Series bitmaps: allow bitmaps to be used with full and top | expand

Commit Message

John Snow July 16, 2019, 12:01 a.m. UTC
Modify the existing bdrv_is_unallocated_range to utilize the pnum return
from bdrv_is_allocated; optionally returning a full number of clusters
that share the same allocation status.

This will be used to carefully toggle bits in the bitmap for sync=top
initialization in the following commits.

Signed-off-by: John Snow <jsnow@redhat.com>
---
 block/backup.c | 62 +++++++++++++++++++++++++++++++++++---------------
 1 file changed, 44 insertions(+), 18 deletions(-)

Comments

Max Reitz July 16, 2019, 11:07 a.m. UTC | #1
On 16.07.19 02:01, John Snow wrote:
> Modify the existing bdrv_is_unallocated_range to utilize the pnum return
> from bdrv_is_allocated; optionally returning a full number of clusters
> that share the same allocation status.
> 
> This will be used to carefully toggle bits in the bitmap for sync=top
> initialization in the following commits.
> 
> Signed-off-by: John Snow <jsnow@redhat.com>
> ---
>  block/backup.c | 62 +++++++++++++++++++++++++++++++++++---------------
>  1 file changed, 44 insertions(+), 18 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>
diff mbox series

Patch

diff --git a/block/backup.c b/block/backup.c
index c88a70fe10..b407d57954 100644
--- a/block/backup.c
+++ b/block/backup.c
@@ -185,6 +185,48 @@  static int coroutine_fn backup_cow_with_offload(BackupBlockJob *job,
     return nbytes;
 }
 
+/*
+ * Check if the cluster starting at offset is allocated or not.
+ * return via pnum the number of contiguous clusters sharing this allocation.
+ */
+static int backup_is_cluster_allocated(BackupBlockJob *s, int64_t offset,
+                                       int64_t *pnum)
+{
+    BlockDriverState *bs = blk_bs(s->common.blk);
+    int64_t count, total_count = 0;
+    int64_t bytes = s->len - offset;
+    int ret;
+
+    assert(QEMU_IS_ALIGNED(offset, s->cluster_size));
+
+    while (true) {
+        ret = bdrv_is_allocated(bs, offset, bytes, &count);
+        if (ret < 0) {
+            return ret;
+        }
+
+        total_count += count;
+
+        if (ret || count == 0) {
+            /*
+             * ret: partial segment(s) are considered allocated.
+             * otherwise: unallocated tail is treated as an entire segment.
+             */
+            *pnum = DIV_ROUND_UP(total_count, s->cluster_size);
+            return ret;
+        }
+
+        /* Unallocated segment(s) with uncertain following segment(s) */
+        if (total_count >= s->cluster_size) {
+            *pnum = total_count / s->cluster_size;
+            return 0;
+        }
+
+        offset += count;
+        bytes -= count;
+    }
+}
+
 static int coroutine_fn backup_do_cow(BackupBlockJob *job,
                                       int64_t offset, uint64_t bytes,
                                       bool *error_is_read,
@@ -388,34 +430,18 @@  static bool coroutine_fn yield_and_check(BackupBlockJob *job)
     return false;
 }
 
-static bool bdrv_is_unallocated_range(BlockDriverState *bs,
-                                      int64_t offset, int64_t bytes)
-{
-    int64_t end = offset + bytes;
-
-    while (offset < end && !bdrv_is_allocated(bs, offset, bytes, &bytes)) {
-        if (bytes == 0) {
-            return true;
-        }
-        offset += bytes;
-        bytes = end - offset;
-    }
-
-    return offset >= end;
-}
-
 static int coroutine_fn backup_loop(BackupBlockJob *job)
 {
     bool error_is_read;
     int64_t offset;
     BdrvDirtyBitmapIter *bdbi;
-    BlockDriverState *bs = blk_bs(job->common.blk);
     int ret = 0;
+    int64_t dummy;
 
     bdbi = bdrv_dirty_iter_new(job->copy_bitmap);
     while ((offset = bdrv_dirty_iter_next(bdbi)) != -1) {
         if (job->sync_mode == MIRROR_SYNC_MODE_TOP &&
-            bdrv_is_unallocated_range(bs, offset, job->cluster_size))
+            !backup_is_cluster_allocated(job, offset, &dummy))
         {
             bdrv_reset_dirty_bitmap(job->copy_bitmap, offset,
                                     job->cluster_size);