From ec8057f43c44075e02b59078b38b40340220f955 Mon Sep 17 00:00:00 2001 From: Max Reitz Date: Mon, 18 Jun 2018 17:24:53 +0200 Subject: [PATCH 05/17] qcow2: Repair OFLAG_COPIED when fixing leaks RH-Author: Max Reitz Message-id: <20180618172454.27434-2-mreitz@redhat.com> Patchwork-id: 80785 O-Subject: [RHEL-7.6 qemu-kvm PATCH 1/2] qcow2: Repair OFLAG_COPIED when fixing leaks Bugzilla: 1527122 RH-Acked-by: John Snow RH-Acked-by: Kevin Wolf RH-Acked-by: Stefan Hajnoczi Repairing OFLAG_COPIED is usually safe because it is done after the refcounts have been repaired. Therefore, it we did not find anyone else referencing a data or L2 cluster, it makes no sense to not set OFLAG_COPIED -- and the other direction (clearing OFLAG_COPIED) is always safe, anyway, it may just induce leaks. Furthermore, if OFLAG_COPIED is actually consistent with a wrong (leaky) refcount, we will decrement the refcount with -r leaks, but OFLAG_COPIED will then be wrong. qemu-img check should not produce images that are more corrupted afterwards then they were before. Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1527085 Signed-off-by: Max Reitz Reviewed-by: Eric Blake Message-id: 20180509200059.31125-2-mreitz@redhat.com Signed-off-by: Max Reitz (cherry picked from commit 3cce51c919c7b4028cf6676dfcb80a45741b5117) Signed-off-by: Miroslav Rezanina Conflicts: block/qcow2-refcount.c Conflicts due to refcounts being fixed to 16 bit downstream, which means that every instance of the "refcount" variable is an int instead of uint64_t. This results in contextual conflicts in the corruption printf()s. Signed-off-by: Max Reitz --- block/qcow2-refcount.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 848fd31..7a69bcd 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -1333,6 +1333,19 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res, int ret; int refcount; int i, j; + bool repair; + + if (fix & BDRV_FIX_ERRORS) { + /* Always repair */ + repair = true; + } else if (fix & BDRV_FIX_LEAKS) { + /* Repair only if that seems safe: This function is always + * called after the refcounts have been fixed, so the refcount + * is accurate if that repair was successful */ + repair = !res->check_errors && !res->corruptions && !res->leaks; + } else { + repair = false; + } for (i = 0; i < s->l1_size; i++) { uint64_t l1_entry = s->l1_table[i]; @@ -1351,10 +1364,8 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res, if ((refcount == 1) != ((l1_entry & QCOW_OFLAG_COPIED) != 0)) { fprintf(stderr, "%s OFLAG_COPIED L2 cluster: l1_index=%d " "l1_entry=%" PRIx64 " refcount=%d\n", - fix & BDRV_FIX_ERRORS ? "Repairing" : - "ERROR", - i, l1_entry, refcount); - if (fix & BDRV_FIX_ERRORS) { + repair ? "Repairing" : "ERROR", i, l1_entry, refcount); + if (repair) { s->l1_table[i] = refcount == 1 ? l1_entry | QCOW_OFLAG_COPIED : l1_entry & ~QCOW_OFLAG_COPIED; @@ -1393,10 +1404,8 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res, if ((refcount == 1) != ((l2_entry & QCOW_OFLAG_COPIED) != 0)) { fprintf(stderr, "%s OFLAG_COPIED data cluster: " "l2_entry=%" PRIx64 " refcount=%d\n", - fix & BDRV_FIX_ERRORS ? "Repairing" : - "ERROR", - l2_entry, refcount); - if (fix & BDRV_FIX_ERRORS) { + repair ? "Repairing" : "ERROR", l2_entry, refcount); + if (repair) { l2_table[j] = cpu_to_be64(refcount == 1 ? l2_entry | QCOW_OFLAG_COPIED : l2_entry & ~QCOW_OFLAG_COPIED); -- 1.8.3.1