@@ -1587,6 +1587,54 @@ enum {
1587
1587
CHECK_FRAG_INFO = 0x2 , /* update BlockFragInfo counters */
1588
1588
};
1589
1589
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
+
1590
1638
/*
1591
1639
* Increases the refcount in the given refcount table for the all clusters
1592
1640
* 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,
1606
1654
int i , ret ;
1607
1655
size_t l2_size_bytes = s -> l2_size * l2_entry_size (s );
1608
1656
g_autofree uint64_t * l2_table = g_malloc (l2_size_bytes );
1657
+ bool metadata_overlap ;
1609
1658
1610
1659
/* Read L2 table from disk */
1611
1660
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,
1685
1734
fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR" ,
1686
1735
offset );
1687
1736
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 ) {
1701
1741
/*
1702
1742
* Something is seriously wrong, so abort checking
1703
1743
* this L2 table.
1704
1744
*/
1705
1745
return ret ;
1706
1746
}
1707
1747
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 ) {
1722
1749
/*
1723
1750
* Skip marking the cluster as used
1724
1751
* (it is unused now).
1725
1752
*/
1726
1753
continue ;
1727
1754
}
1755
+
1756
+ /*
1757
+ * Failed to fix.
1758
+ * Do not abort, continue checking the rest of this
1759
+ * L2 table's entries.
1760
+ */
1728
1761
}
1729
1762
} else {
1730
1763
fprintf (stderr , "ERROR offset=%" PRIx64 ": Data cluster is "
0 commit comments