@@ -47,7 +47,8 @@ bdrv_co_common_block_status_above(BlockDriverState *bs,
int64_t bytes,
int64_t *pnum,
int64_t *map,
- BlockDriverState **file);
+ BlockDriverState **file,
+ int *depth);
int generated_co_wrapper
bdrv_common_block_status_above(BlockDriverState *bs,
BlockDriverState *base,
@@ -57,7 +58,8 @@ bdrv_common_block_status_above(BlockDriverState *bs,
int64_t bytes,
int64_t *pnum,
int64_t *map,
- BlockDriverState **file);
+ BlockDriverState **file,
+ int *depth);
int coroutine_fn bdrv_co_readv_vmstate(BlockDriverState *bs,
QEMUIOVector *qiov, int64_t pos);
@@ -2349,20 +2349,28 @@ bdrv_co_common_block_status_above(BlockDriverState *bs,
int64_t bytes,
int64_t *pnum,
int64_t *map,
- BlockDriverState **file)
+ BlockDriverState **file,
+ int *depth)
{
int ret;
BlockDriverState *p;
int64_t eof = 0;
+ int dummy;
assert(!include_base || base); /* Can't include NULL base */
+ if (!depth) {
+ depth = &dummy;
+ }
+ *depth = 0;
+
if (!include_base && bs == base) {
*pnum = bytes;
return 0;
}
ret = bdrv_co_block_status(bs, want_zero, offset, bytes, pnum, map, file);
+ ++*depth;
if (ret < 0 || *pnum == 0 || ret & BDRV_BLOCK_ALLOCATED || bs == base) {
return ret;
}
@@ -2379,6 +2387,7 @@ bdrv_co_common_block_status_above(BlockDriverState *bs,
{
ret = bdrv_co_block_status(p, want_zero, offset, bytes, pnum, map,
file);
+ ++*depth;
if (ret < 0) {
return ret;
}
@@ -2437,7 +2446,7 @@ int bdrv_block_status_above(BlockDriverState *bs, BlockDriverState *base,
int64_t *map, BlockDriverState **file)
{
return bdrv_common_block_status_above(bs, base, false, true, offset, bytes,
- pnum, map, file);
+ pnum, map, file, NULL);
}
int bdrv_block_status(BlockDriverState *bs, int64_t offset, int64_t bytes,
@@ -2455,7 +2464,7 @@ int coroutine_fn bdrv_is_allocated(BlockDriverState *bs, int64_t offset,
ret = bdrv_common_block_status_above(bs, bs, true, false, offset,
bytes, pnum ? pnum : &dummy, NULL,
- NULL);
+ NULL, NULL);
if (ret < 0) {
return ret;
}
@@ -2465,8 +2474,9 @@ int coroutine_fn bdrv_is_allocated(BlockDriverState *bs, int64_t offset,
/*
* Given an image chain: ... -> [BASE] -> [INTER1] -> [INTER2] -> [TOP]
*
- * Return 1 if (a prefix of) the given range is allocated in any image
- * between BASE and TOP (BASE is only included if include_base is set).
+ * Return a positive depth if (a prefix of) the given range is allocated
+ * in any image between BASE and TOP (BASE is only included if include_base
+ * is set). Depth 1 is TOP, 2 is the first backing layer, and so forth.
* BASE can be NULL to check if the given offset is allocated in any
* image of the chain. Return 0 otherwise, or negative errno on
* failure.
@@ -2483,13 +2493,18 @@ int bdrv_is_allocated_above(BlockDriverState *top,
bool include_base, int64_t offset,
int64_t bytes, int64_t *pnum)
{
+ int depth;
int ret = bdrv_common_block_status_above(top, base, include_base, false,
- offset, bytes, pnum, NULL, NULL);
+ offset, bytes, pnum, NULL, NULL,
+ &depth);
if (ret < 0) {
return ret;
}
- return !!(ret & BDRV_BLOCK_ALLOCATED);
+ if (ret & BDRV_BLOCK_ALLOCATED) {
+ return depth;
+ }
+ return 0;
}
int coroutine_fn
@@ -156,7 +156,7 @@ static int coroutine_fn commit_run(Job *job, Error **errp)
/* Copy if allocated above the base */
ret = bdrv_is_allocated_above(blk_bs(s->top), s->base_overlay, true,
offset, COMMIT_BUFFER_SIZE, &n);
- copy = (ret == 1);
+ copy = (ret > 0);
trace_commit_one_iteration(s, offset, n, ret);
if (copy) {
assert(n < SIZE_MAX);
@@ -846,7 +846,7 @@ static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s)
}
assert(count);
- if (ret == 1) {
+ if (ret > 0) {
bdrv_set_dirty_bitmap(s->dirty_bitmap, offset, count);
}
offset += count;
@@ -167,7 +167,7 @@ static int coroutine_fn stream_run(Job *job, Error **errp)
n = len - offset;
}
- copy = (ret == 1);
+ copy = (ret > 0);
}
trace_stream_one_iteration(s, offset, n, ret);
if (copy) {