diff options
author | Max Reitz <mreitz@redhat.com> | 2019-10-11 17:28:06 +0200 |
---|---|---|
committer | Max Reitz <mreitz@redhat.com> | 2019-10-28 11:54:00 +0100 |
commit | 8bc584fe035d98b8aca4fcc818617c91df0ed925 (patch) | |
tree | f88aa3e4d673fce26ed685a6a9eca498527928e7 /block/qcow2-snapshot.c | |
parent | 0a85af351d90e1ae9e06b3bb5290ddf2d5d8b950 (diff) | |
download | qemu-8bc584fe035d98b8aca4fcc818617c91df0ed925.zip qemu-8bc584fe035d98b8aca4fcc818617c91df0ed925.tar.gz qemu-8bc584fe035d98b8aca4fcc818617c91df0ed925.tar.bz2 |
qcow2: Separate qcow2_check_read_snapshot_table()
Reading the snapshot table can fail. That is a problem when we want to
repair the image.
Therefore, stop reading the snapshot table in qcow2_do_open() in check
mode. Instead, add a new function qcow2_check_read_snapshot_table()
that reads the snapshot table at a later point. In the future, we want
to handle errors here and fix them.
Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-id: 20191011152814.14791-9-mreitz@redhat.com
Signed-off-by: Max Reitz <mreitz@redhat.com>
Diffstat (limited to 'block/qcow2-snapshot.c')
-rw-r--r-- | block/qcow2-snapshot.c | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c index e3bf4c9..d667bfd 100644 --- a/block/qcow2-snapshot.c +++ b/block/qcow2-snapshot.c @@ -322,6 +322,64 @@ fail: return ret; } +int coroutine_fn qcow2_check_read_snapshot_table(BlockDriverState *bs, + BdrvCheckResult *result, + BdrvCheckMode fix) +{ + BDRVQcow2State *s = bs->opaque; + Error *local_err = NULL; + int ret; + struct { + uint32_t nb_snapshots; + uint64_t snapshots_offset; + } QEMU_PACKED snapshot_table_pointer; + + /* qcow2_do_open() discards this information in check mode */ + ret = bdrv_pread(bs->file, offsetof(QCowHeader, nb_snapshots), + &snapshot_table_pointer, sizeof(snapshot_table_pointer)); + if (ret < 0) { + result->check_errors++; + fprintf(stderr, "ERROR failed to read the snapshot table pointer from " + "the image header: %s\n", strerror(-ret)); + return ret; + } + + s->snapshots_offset = be64_to_cpu(snapshot_table_pointer.snapshots_offset); + s->nb_snapshots = be32_to_cpu(snapshot_table_pointer.nb_snapshots); + + ret = qcow2_validate_table(bs, s->snapshots_offset, s->nb_snapshots, + sizeof(QCowSnapshotHeader), + sizeof(QCowSnapshotHeader) * QCOW_MAX_SNAPSHOTS, + "snapshot table", &local_err); + if (ret < 0) { + result->check_errors++; + error_reportf_err(local_err, "ERROR "); + + /* We did not read the snapshot table, so invalidate this information */ + s->snapshots_offset = 0; + s->nb_snapshots = 0; + + return ret; + } + + qemu_co_mutex_unlock(&s->lock); + ret = qcow2_read_snapshots(bs, &local_err); + qemu_co_mutex_lock(&s->lock); + if (ret < 0) { + result->check_errors++; + error_reportf_err(local_err, + "ERROR failed to read the snapshot table: "); + + /* We did not read the snapshot table, so invalidate this information */ + s->snapshots_offset = 0; + s->nb_snapshots = 0; + + return ret; + } + + return 0; +} + static void find_new_snapshot_id(BlockDriverState *bs, char *id_str, int id_str_size) { |