@@ -2461,25 +2461,46 @@ static int coroutine_fn bdrv_co_block_status_above(BlockDriverState *bs,
ret = bdrv_co_block_status(p, want_zero, offset, bytes, pnum, map,
file);
if (ret < 0) {
- break;
+ return ret;
}
- if (ret & BDRV_BLOCK_ZERO && ret & BDRV_BLOCK_EOF && !first) {
+ if (*pnum == 0) {
+ if (first) {
+ return ret;
+ }
+
/*
- * Reading beyond the end of the file continues to read
- * zeroes, but we can only widen the result to the
- * unallocated length we learned from an earlier
- * iteration.
+ * The top layer deferred to this layer, and because this layer is
+ * short, any zeroes that we synthesize beyond EOF behave as if they
+ * were allocated at this layer
*/
+ assert(ret & BDRV_BLOCK_EOF);
*pnum = bytes;
+ if (file) {
+ *file = p;
+ }
+ return BDRV_BLOCK_ZERO | BDRV_BLOCK_ALLOCATED;
}
- if (ret & (BDRV_BLOCK_ZERO | BDRV_BLOCK_DATA)) {
- break;
+ if (ret & BDRV_BLOCK_ALLOCATED) {
+ /* We've found the node and the status, we must return. */
+
+ if (ret & BDRV_BLOCK_ZERO && ret & BDRV_BLOCK_EOF && !first) {
+ /*
+ * This level is also responsible for reads after EOF inside
+ * the unallocated region in the previous level.
+ */
+ *pnum = bytes;
+ }
+
+ return ret;
}
+
/* [offset, pnum] unallocated on this layer, which could be only
* the first part of [offset, bytes]. */
- bytes = MIN(bytes, *pnum);
+ assert(*pnum <= bytes);
+ bytes = *pnum;
first = false;
}
+
return ret;
}
@@ -3827,8 +3827,20 @@ static bool is_zero(BlockDriverState *bs, int64_t offset, int64_t bytes)
if (!bytes) {
return true;
}
- res = bdrv_block_status_above(bs, NULL, offset, bytes, &nr, NULL, NULL);
- return res >= 0 && (res & BDRV_BLOCK_ZERO) && nr == bytes;
+
+ /*
+ * bdrv_block_status_above doesn't merge different types of zeros, for
+ * example, zeros which come from the region which is unallocated in
+ * the whole backing chain, and zeros which comes because of a short
+ * backing file. So, we need a loop.
+ */
+ do {
+ res = bdrv_block_status_above(bs, NULL, offset, bytes, &nr, NULL, NULL);
+ offset += nr;
+ bytes -= nr;
+ } while (res >= 0 && (res & BDRV_BLOCK_ZERO) && nr && bytes);
+
+ return res >= 0 && (res & BDRV_BLOCK_ZERO) && bytes == 0;
}
static coroutine_fn int qcow2_co_pwrite_zeroes(BlockDriverState *bs,