Skip to content

Commit a2debf6

Browse files
Vladimir Sementsov-OgievskiyXanClic
authored andcommitted
qcow2-refcount: introduce fix_l2_entry_by_zero()
Split fix_l2_entry_by_zero() out of check_refcounts_l2() to be reused in further patch. Signed-off-by: Vladimir Sementsov-Ogievskiy <[email protected]> Reviewed-by: Eric Blake <[email protected]> Reviewed-by: Hanna Reitz <[email protected]> Message-Id: <[email protected]> Signed-off-by: Hanna Reitz <[email protected]>
1 parent a6e0984 commit a2debf6

File tree

1 file changed

+60
-27
lines changed

1 file changed

+60
-27
lines changed

block/qcow2-refcount.c

Lines changed: 60 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1587,6 +1587,54 @@ enum {
15871587
CHECK_FRAG_INFO = 0x2, /* update BlockFragInfo counters */
15881588
};
15891589

1590+
/*
1591+
* Fix L2 entry by making it QCOW2_CLUSTER_ZERO_PLAIN.
1592+
*
1593+
* This function decrements res->corruptions on success, so the caller is
1594+
* responsible to increment res->corruptions prior to the call.
1595+
*
1596+
* On failure in-memory @l2_table may be modified.
1597+
*/
1598+
static int fix_l2_entry_by_zero(BlockDriverState *bs, BdrvCheckResult *res,
1599+
uint64_t l2_offset,
1600+
uint64_t *l2_table, int l2_index, bool active,
1601+
bool *metadata_overlap)
1602+
{
1603+
BDRVQcow2State *s = bs->opaque;
1604+
int ret;
1605+
int idx = l2_index * (l2_entry_size(s) / sizeof(uint64_t));
1606+
uint64_t l2e_offset = l2_offset + (uint64_t)l2_index * l2_entry_size(s);
1607+
int ign = active ? QCOW2_OL_ACTIVE_L2 : QCOW2_OL_INACTIVE_L2;
1608+
uint64_t l2_entry = has_subclusters(s) ? 0 : QCOW_OFLAG_ZERO;
1609+
1610+
set_l2_entry(s, l2_table, l2_index, l2_entry);
1611+
ret = qcow2_pre_write_overlap_check(bs, ign, l2e_offset, l2_entry_size(s),
1612+
false);
1613+
if (metadata_overlap) {
1614+
*metadata_overlap = ret < 0;
1615+
}
1616+
if (ret < 0) {
1617+
fprintf(stderr, "ERROR: Overlap check failed\n");
1618+
goto fail;
1619+
}
1620+
1621+
ret = bdrv_pwrite_sync(bs->file, l2e_offset, &l2_table[idx],
1622+
l2_entry_size(s));
1623+
if (ret < 0) {
1624+
fprintf(stderr, "ERROR: Failed to overwrite L2 "
1625+
"table entry: %s\n", strerror(-ret));
1626+
goto fail;
1627+
}
1628+
1629+
res->corruptions--;
1630+
res->corruptions_fixed++;
1631+
return 0;
1632+
1633+
fail:
1634+
res->check_errors++;
1635+
return ret;
1636+
}
1637+
15901638
/*
15911639
* Increases the refcount in the given refcount table for the all clusters
15921640
* referenced in the L2 table. While doing so, performs some checks on L2
@@ -1606,6 +1654,7 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
16061654
int i, ret;
16071655
size_t l2_size_bytes = s->l2_size * l2_entry_size(s);
16081656
g_autofree uint64_t *l2_table = g_malloc(l2_size_bytes);
1657+
bool metadata_overlap;
16091658

16101659
/* Read L2 table from disk */
16111660
ret = bdrv_pread(bs->file, l2_offset, l2_table, l2_size_bytes);
@@ -1685,46 +1734,30 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
16851734
fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR",
16861735
offset);
16871736
if (fix & BDRV_FIX_ERRORS) {
1688-
int idx = i * (l2_entry_size(s) / sizeof(uint64_t));
1689-
uint64_t l2e_offset =
1690-
l2_offset + (uint64_t)i * l2_entry_size(s);
1691-
int ign = active ? QCOW2_OL_ACTIVE_L2 :
1692-
QCOW2_OL_INACTIVE_L2;
1693-
1694-
l2_entry = has_subclusters(s) ? 0 : QCOW_OFLAG_ZERO;
1695-
set_l2_entry(s, l2_table, i, l2_entry);
1696-
ret = qcow2_pre_write_overlap_check(bs, ign,
1697-
l2e_offset, l2_entry_size(s), false);
1698-
if (ret < 0) {
1699-
fprintf(stderr, "ERROR: Overlap check failed\n");
1700-
res->check_errors++;
1737+
ret = fix_l2_entry_by_zero(bs, res, l2_offset,
1738+
l2_table, i, active,
1739+
&metadata_overlap);
1740+
if (metadata_overlap) {
17011741
/*
17021742
* Something is seriously wrong, so abort checking
17031743
* this L2 table.
17041744
*/
17051745
return ret;
17061746
}
17071747

1708-
ret = bdrv_pwrite_sync(bs->file, l2e_offset,
1709-
&l2_table[idx],
1710-
l2_entry_size(s));
1711-
if (ret < 0) {
1712-
fprintf(stderr, "ERROR: Failed to overwrite L2 "
1713-
"table entry: %s\n", strerror(-ret));
1714-
res->check_errors++;
1715-
/*
1716-
* Do not abort, continue checking the rest of this
1717-
* L2 table's entries.
1718-
*/
1719-
} else {
1720-
res->corruptions--;
1721-
res->corruptions_fixed++;
1748+
if (ret == 0) {
17221749
/*
17231750
* Skip marking the cluster as used
17241751
* (it is unused now).
17251752
*/
17261753
continue;
17271754
}
1755+
1756+
/*
1757+
* Failed to fix.
1758+
* Do not abort, continue checking the rest of this
1759+
* L2 table's entries.
1760+
*/
17281761
}
17291762
} else {
17301763
fprintf(stderr, "ERROR offset=%" PRIx64 ": Data cluster is "

0 commit comments

Comments
 (0)