@@ -288,6 +288,8 @@ static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
goto fail;
}
+ qcow2_metadata_list_enter(bs, l2_offset, 1, QCOW2_OL_ACTIVE_L2);
+
*table = l2_table;
trace_qcow2_l2_allocate_done(bs, l1_index, 0);
return 0;
@@ -1040,6 +1040,12 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
if (addend != 0) {
refcount = qcow2_update_cluster_refcount(bs, l2_offset >>
s->cluster_bits, addend, QCOW2_DISCARD_SNAPSHOT);
+ if (addend < 0) {
+ if (active_l1) {
+ qcow2_metadata_list_remove(bs, l2_offset, 1,
+ QCOW2_OL_ACTIVE_L2);
+ }
+ }
} else {
refcount = qcow2_get_refcount(bs, l2_offset >> s->cluster_bits);
}
@@ -561,6 +561,13 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
g_free(sn_l1_table);
sn_l1_table = NULL;
+ for (i = 0; i < s->l1_size; i++) {
+ uint64_t l2_offset = s->l1_table[i] & L1E_OFFSET_MASK;
+ if (l2_offset) {
+ qcow2_metadata_list_enter(bs, l2_offset, 1, QCOW2_OL_ACTIVE_L2);
+ }
+ }
+
/*
* Update QCOW_OFLAG_COPIED in the active L1 table (it may have changed
* when we decreased the refcount of the old snapshot.
@@ -725,6 +732,13 @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs,
sizeof(uint64_t)),
QCOW2_OL_ACTIVE_L1);
+ for (i = 0; i < s->l1_size; i++) {
+ uint64_t l2_offset = s->l1_table[i] & L1E_OFFSET_MASK;
+ if (l2_offset) {
+ qcow2_metadata_list_remove(bs, l2_offset, 1, QCOW2_OL_ACTIVE_L2);
+ }
+ }
+
/* Switch the L1 table */
qemu_vfree(s->l1_table);
@@ -741,5 +755,12 @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs,
sizeof(uint64_t)),
QCOW2_OL_ACTIVE_L1);
+ for (i = 0; i < s->l1_size; i++) {
+ uint64_t l2_offset = s->l1_table[i] & L1E_OFFSET_MASK;
+ if (l2_offset) {
+ qcow2_metadata_list_enter(bs, l2_offset, 1, QCOW2_OL_ACTIVE_L2);
+ }
+ }
+
return 0;
}
@@ -850,8 +850,14 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
error_setg_errno(errp, -ret, "Could not read L1 table");
goto fail;
}
- for(i = 0;i < s->l1_size; i++) {
+ for (i = 0; i < s->l1_size; i++) {
+ uint64_t l2_offset;
+
be64_to_cpus(&s->l1_table[i]);
+ l2_offset = s->l1_table[i] & L1E_OFFSET_MASK;
+ if (l2_offset) {
+ qcow2_metadata_list_enter(bs, l2_offset, 1, QCOW2_OL_ACTIVE_L2);
+ }
}
}
Keep track of the active L2 tables in the metadata list to protect them against accidental modifications. Signed-off-by: Max Reitz <mreitz@redhat.com> --- block/qcow2-cluster.c | 2 ++ block/qcow2-refcount.c | 6 ++++++ block/qcow2-snapshot.c | 21 +++++++++++++++++++++ block/qcow2.c | 8 +++++++- 4 files changed, 36 insertions(+), 1 deletion(-)