提交 ac5b787a 编写于 作者: M Max Reitz

qcow2: Repair unaligned preallocated zero clusters

We can easily repair unaligned preallocated zero clusters by discarding
them, so why not do it?
Signed-off-by: NMax Reitz <mreitz@redhat.com>
Message-id: 20171110203759.14018-2-mreitz@redhat.com
Reviewed-by: NEric Blake <eblake@redhat.com>
Signed-off-by: NMax Reitz <mreitz@redhat.com>
上级 7c3a3028
......@@ -1508,7 +1508,7 @@ enum {
static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
void **refcount_table,
int64_t *refcount_table_size, int64_t l2_offset,
int flags)
int flags, BdrvCheckMode fix)
{
BDRVQcow2State *s = bs->opaque;
uint64_t *l2_table, l2_entry;
......@@ -1579,6 +1579,57 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
next_contiguous_offset = offset + s->cluster_size;
}
/* Correct offsets are cluster aligned */
if (offset_into_cluster(s, offset)) {
if (qcow2_get_cluster_type(l2_entry) ==
QCOW2_CLUSTER_ZERO_ALLOC)
{
fprintf(stderr, "%s offset=%" PRIx64 ": Preallocated zero "
"cluster is not properly aligned; L2 entry "
"corrupted.\n",
fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR",
offset);
if (fix & BDRV_FIX_ERRORS) {
uint64_t l2e_offset =
l2_offset + (uint64_t)i * sizeof(uint64_t);
l2_entry = QCOW_OFLAG_ZERO;
l2_table[i] = cpu_to_be64(l2_entry);
ret = qcow2_pre_write_overlap_check(bs,
QCOW2_OL_ACTIVE_L2 | QCOW2_OL_INACTIVE_L2,
l2e_offset, sizeof(uint64_t));
if (ret < 0) {
fprintf(stderr, "ERROR: Overlap check failed\n");
res->check_errors++;
/* Something is seriously wrong, so abort checking
* this L2 table */
goto fail;
}
ret = bdrv_pwrite_sync(bs->file, l2e_offset,
&l2_table[i], sizeof(uint64_t));
if (ret < 0) {
fprintf(stderr, "ERROR: Failed to overwrite L2 "
"table entry: %s\n", strerror(-ret));
res->check_errors++;
/* Do not abort, continue checking the rest of this
* L2 table's entries */
} else {
res->corruptions_fixed++;
/* Skip marking the cluster as used
* (it is unused now) */
continue;
}
} else {
res->corruptions++;
}
} else {
fprintf(stderr, "ERROR offset=%" PRIx64 ": Data cluster is "
"not properly aligned; L2 entry corrupted.\n", offset);
res->corruptions++;
}
}
/* Mark cluster as used */
ret = qcow2_inc_refcounts_imrt(bs, res,
refcount_table, refcount_table_size,
......@@ -1586,13 +1637,6 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
if (ret < 0) {
goto fail;
}
/* Correct offsets are cluster aligned */
if (offset_into_cluster(s, offset)) {
fprintf(stderr, "ERROR offset=%" PRIx64 ": Cluster is not "
"properly aligned; L2 entry corrupted.\n", offset);
res->corruptions++;
}
break;
}
......@@ -1626,7 +1670,7 @@ static int check_refcounts_l1(BlockDriverState *bs,
void **refcount_table,
int64_t *refcount_table_size,
int64_t l1_table_offset, int l1_size,
int flags)
int flags, BdrvCheckMode fix)
{
BDRVQcow2State *s = bs->opaque;
uint64_t *l1_table = NULL, l2_offset, l1_size2;
......@@ -1681,7 +1725,8 @@ static int check_refcounts_l1(BlockDriverState *bs,
/* Process and check L2 entries */
ret = check_refcounts_l2(bs, res, refcount_table,
refcount_table_size, l2_offset, flags);
refcount_table_size, l2_offset, flags,
fix);
if (ret < 0) {
goto fail;
}
......@@ -1957,7 +2002,8 @@ static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
/* current L1 table */
ret = check_refcounts_l1(bs, res, refcount_table, nb_clusters,
s->l1_table_offset, s->l1_size, CHECK_FRAG_INFO);
s->l1_table_offset, s->l1_size, CHECK_FRAG_INFO,
fix);
if (ret < 0) {
return ret;
}
......@@ -1966,7 +2012,7 @@ static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
for (i = 0; i < s->nb_snapshots; i++) {
sn = s->snapshots + i;
ret = check_refcounts_l1(bs, res, refcount_table, nb_clusters,
sn->l1_table_offset, sn->l1_size, 0);
sn->l1_table_offset, sn->l1_size, 0, fix);
if (ret < 0) {
return ret;
}
......
......@@ -335,7 +335,8 @@ poke_file "$TEST_IMG" "$l2_offset" "\x80\x00\x00\x00\x00\x00\x2a\x01"
# Let's write to it!
$QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io
# Can't repair this yet (TODO: We can just deallocate the cluster)
echo '--- Repairing ---'
_check_test_img -r all
echo
echo '=== Discarding with an unaligned refblock ==='
......
......@@ -317,6 +317,15 @@ discard 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
qcow2: Marking image as corrupt: Preallocated zero cluster offset 0x2a00 unaligned (guest offset: 0); further corruption events will be suppressed
write failed: Input/output error
--- Repairing ---
Repairing offset=2a00: Preallocated zero cluster is not properly aligned; L2 entry corrupted.
The following inconsistencies were found and repaired:
0 leaked clusters
1 corruptions
Double checking the fixed image now...
No errors were found on the image.
=== Discarding with an unaligned refblock ===
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册