qemu-devel
[Top][All Lists]
Advanced

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

[PATCH 2/6] block: truncate: Don't make backing file data visible


From: Kevin Wolf
Subject: [PATCH 2/6] block: truncate: Don't make backing file data visible
Date: Wed, 20 Nov 2019 15:03:15 +0100

When extending the size of an image that has a backing file larger than
its old size, make sure that the backing file data doesn't become
visible in the guest, but the added area is properly zeroed out.

The old behaviour made a difference in 'block_resize' (where showing the
backing file data from an old snapshot rather than zeros is
questionable) as well as in commit block jobs (both from active and
intermediate nodes) and HMP 'commit', where committing to a short
backing file would incorrectly omit writing zeroes for unallocated
blocks on the top layer after the EOF of the short backing file.

Signed-off-by: Kevin Wolf <address@hidden>
---
 block/io.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/block/io.c b/block/io.c
index 003f4ea38c..8683f7a4bd 100644
--- a/block/io.c
+++ b/block/io.c
@@ -3382,6 +3382,31 @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, 
int64_t offset, bool exact,
         goto out;
     }
 
+    /*
+     * If the image has a backing file that is large enough that it would
+     * provide data for the new area, we cannot leave it unallocated because
+     * then the backing file content would become visible. Instead, zero-fill
+     * the area where backing file and new area overlap.
+     */
+    if (new_bytes && bs->backing && prealloc == PREALLOC_MODE_OFF) {
+        int64_t backing_len;
+
+        backing_len = bdrv_getlength(backing_bs(bs));
+        if (backing_len < 0) {
+            ret = backing_len;
+            goto out;
+        }
+
+        if (backing_len > old_size) {
+            ret = bdrv_co_do_pwrite_zeroes(bs, old_size,
+                                           MIN(new_bytes, backing_len - 
old_size),
+                                           BDRV_REQ_ZERO_WRITE | 
BDRV_REQ_MAY_UNMAP);
+            if (ret < 0) {
+                goto out;
+            }
+        }
+    }
+
     ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
     if (ret < 0) {
         error_setg_errno(errp, -ret, "Could not refresh total sector count");
-- 
2.20.1




reply via email to

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