qcow2: Fix order in qcow2_snapshot_delete
First the snapshot must be deleted and only then the refcounts can be decreased. Signed-off-by: Kevin Wolf <kwolf@redhat.com> Reviewed-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
This commit is contained in:
parent
43a0cac465
commit
9a4767809f
|
@ -489,32 +489,50 @@ fail:
|
||||||
int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
|
int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id)
|
||||||
{
|
{
|
||||||
BDRVQcowState *s = bs->opaque;
|
BDRVQcowState *s = bs->opaque;
|
||||||
QCowSnapshot *sn;
|
QCowSnapshot sn;
|
||||||
int snapshot_index, ret;
|
int snapshot_index, ret;
|
||||||
|
|
||||||
|
/* Search the snapshot */
|
||||||
snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
|
snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
|
||||||
if (snapshot_index < 0)
|
if (snapshot_index < 0) {
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
sn = &s->snapshots[snapshot_index];
|
}
|
||||||
|
sn = s->snapshots[snapshot_index];
|
||||||
|
|
||||||
ret = qcow2_update_snapshot_refcount(bs, sn->l1_table_offset, sn->l1_size, -1);
|
/* Remove it from the snapshot list */
|
||||||
if (ret < 0)
|
memmove(s->snapshots + snapshot_index,
|
||||||
return ret;
|
s->snapshots + snapshot_index + 1,
|
||||||
/* must update the copied flag on the current cluster offsets */
|
(s->nb_snapshots - snapshot_index - 1) * sizeof(sn));
|
||||||
ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 0);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
qcow2_free_clusters(bs, sn->l1_table_offset, sn->l1_size * sizeof(uint64_t));
|
|
||||||
|
|
||||||
g_free(sn->id_str);
|
|
||||||
g_free(sn->name);
|
|
||||||
memmove(sn, sn + 1, (s->nb_snapshots - snapshot_index - 1) * sizeof(*sn));
|
|
||||||
s->nb_snapshots--;
|
s->nb_snapshots--;
|
||||||
ret = qcow2_write_snapshots(bs);
|
ret = qcow2_write_snapshots(bs);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
/* XXX: restore snapshot if error ? */
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The snapshot is now unused, clean up. If we fail after this point, we
|
||||||
|
* won't recover but just leak clusters.
|
||||||
|
*/
|
||||||
|
g_free(sn.id_str);
|
||||||
|
g_free(sn.name);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now decrease the refcounts of clusters referenced by the snapshot and
|
||||||
|
* free the L1 table.
|
||||||
|
*/
|
||||||
|
ret = qcow2_update_snapshot_refcount(bs, sn.l1_table_offset,
|
||||||
|
sn.l1_size, -1);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
qcow2_free_clusters(bs, sn.l1_table_offset, sn.l1_size * sizeof(uint64_t));
|
||||||
|
|
||||||
|
/* must update the copied flag on the current cluster offsets */
|
||||||
|
ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_ALLOC
|
#ifdef DEBUG_ALLOC
|
||||||
{
|
{
|
||||||
BdrvCheckResult result = {0};
|
BdrvCheckResult result = {0};
|
||||||
|
|
Loading…
Reference in New Issue