* [Qemu-devel] [PATCH v2] qemu-img fails to delete last snapshot
@ 2014-05-12 20:27 Mike Day
2014-05-14 15:15 ` Kevin Wolf
2014-05-14 23:54 ` Max Reitz
0 siblings, 2 replies; 5+ messages in thread
From: Mike Day @ 2014-05-12 20:27 UTC (permalink / raw)
To: qemu-devel; +Cc: kwolf, Mike Day, stefanha
When deleting the last snapshot, copying the resulting snapshot table
currently fails, causing the delete operation to also fail. Fix the
failure by skipping the copy and just writing the snapshot header and
freeing the extra clusters.
There are two specific problems in the current code. First is a lack of
parenthesis in the calculation of the memmove size parameter:
s->nb_snapshots - snapshot_index - 1
When s->nb_snapshots is 0, snapshot_index is 1.
0 - 1 - 1 = 0xfffffffe
it should be:
0 - (1 - 1) = 0x00
The second problem is shifting the snapshot table to the left. After
removing the last snapshot there are no existing snapshots to be
shifted. All that needs to be done is to write the header and
unallocate the blocks.
Signed-off-by: Mike Day <ncmike@ncultra.org>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
v2: improved the git log entry
added Eric Blake as a reviewer
block/qcow2-snapshot.c | 25 +++++++++++++++----------
1 file changed, 15 insertions(+), 10 deletions(-)
diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
index 0aa9def..c8b842c 100644
--- a/block/qcow2-snapshot.c
+++ b/block/qcow2-snapshot.c
@@ -165,9 +165,11 @@ static int qcow2_write_snapshots(BlockDriverState *bs)
assert(offset <= INT_MAX);
snapshots_size = offset;
-
/* Allocate space for the new snapshot list */
- snapshots_offset = qcow2_alloc_clusters(bs, snapshots_size);
+ snapshots_offset = 0;
+ if (snapshots_size) {
+ snapshots_offset = qcow2_alloc_clusters(bs, snapshots_size);
+ }
offset = snapshots_offset;
if (offset < 0) {
ret = offset;
@@ -180,12 +182,13 @@ static int qcow2_write_snapshots(BlockDriverState *bs)
/* The snapshot list position has not yet been updated, so these clusters
* must indeed be completely free */
- ret = qcow2_pre_write_overlap_check(bs, 0, offset, snapshots_size);
- if (ret < 0) {
- goto fail;
+ if (snapshots_size) {
+ ret = qcow2_pre_write_overlap_check(bs, 0, offset, snapshots_size);
+ if (ret < 0) {
+ goto fail;
+ }
}
-
/* Write all snapshots to the new list */
for(i = 0; i < s->nb_snapshots; i++) {
sn = s->snapshots + i;
@@ -590,12 +593,14 @@ int qcow2_snapshot_delete(BlockDriverState *bs,
return -ENOENT;
}
sn = s->snapshots[snapshot_index];
-
/* Remove it from the snapshot list */
- memmove(s->snapshots + snapshot_index,
- s->snapshots + snapshot_index + 1,
- (s->nb_snapshots - snapshot_index - 1) * sizeof(sn));
s->nb_snapshots--;
+ if (s->nb_snapshots) {
+ memmove(s->snapshots + snapshot_index,
+ s->snapshots + snapshot_index + 1,
+ (s->nb_snapshots - (snapshot_index - 1)) * sizeof(sn));
+ }
+
ret = qcow2_write_snapshots(bs);
if (ret < 0) {
error_setg_errno(errp, -ret,
--
1.9.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [Qemu-devel] [PATCH v2] qemu-img fails to delete last snapshot
2014-05-12 20:27 [Qemu-devel] [PATCH v2] qemu-img fails to delete last snapshot Mike Day
@ 2014-05-14 15:15 ` Kevin Wolf
2014-05-15 13:07 ` Mike Day
2014-05-14 23:54 ` Max Reitz
1 sibling, 1 reply; 5+ messages in thread
From: Kevin Wolf @ 2014-05-14 15:15 UTC (permalink / raw)
To: Mike Day; +Cc: qemu-devel, stefanha
Am 12.05.2014 um 22:27 hat Mike Day geschrieben:
> When deleting the last snapshot, copying the resulting snapshot table
> currently fails, causing the delete operation to also fail. Fix the
> failure by skipping the copy and just writing the snapshot header and
> freeing the extra clusters.
Do you have an easy reproducer? Because I can't see the bug.
> There are two specific problems in the current code. First is a lack of
> parenthesis in the calculation of the memmove size parameter:
>
> s->nb_snapshots - snapshot_index - 1
>
> When s->nb_snapshots is 0, snapshot_index is 1.
>
> 0 - 1 - 1 = 0xfffffffe
>
> it should be:
>
> 0 - (1 - 1) = 0x00
Not really. With s->nb_snapshots == 0, there is no snapshot to delete to
start with. Therefore find_snapshot_by_id_and_name() returns -1 and we
return immediately.
> The second problem is shifting the snapshot table to the left. After
> removing the last snapshot there are no existing snapshots to be
> shifted. All that needs to be done is to write the header and
> unallocate the blocks.
When removing the last snapshot, we have:
nb_snapshots = 1
snapshot_index = 0
memmove(..., (1 - 0 - 1) * sizeof(sn));
So we're not moving anything, which is what you correctly said needs to
happen.
Kevin
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [Qemu-devel] [PATCH v2] qemu-img fails to delete last snapshot
2014-05-12 20:27 [Qemu-devel] [PATCH v2] qemu-img fails to delete last snapshot Mike Day
2014-05-14 15:15 ` Kevin Wolf
@ 2014-05-14 23:54 ` Max Reitz
1 sibling, 0 replies; 5+ messages in thread
From: Max Reitz @ 2014-05-14 23:54 UTC (permalink / raw)
To: Mike Day, qemu-devel; +Cc: kwolf, stefanha
On 12.05.2014 22:27, Mike Day wrote:
> When deleting the last snapshot, copying the resulting snapshot table
> currently fails, causing the delete operation to also fail. Fix the
> failure by skipping the copy and just writing the snapshot header and
> freeing the extra clusters.
>
> There are two specific problems in the current code. First is a lack of
> parenthesis in the calculation of the memmove size parameter:
>
> s->nb_snapshots - snapshot_index - 1
>
> When s->nb_snapshots is 0, snapshot_index is 1.
Before this patch is applied, s->nb_snapshots is only increased after
the memmove(). Therefore, it can never be 0 – snapshot_index on the
other hand needs to be 0, as find_snapshot_by_id_and_name() forces it to
be less than s->nb_snapshots (to elaborate on Kevin's review).
> 0 - 1 - 1 = 0xfffffffe
>
> it should be:
>
> 0 - (1 - 1) = 0x00
>
> The second problem is shifting the snapshot table to the left. After
> removing the last snapshot there are no existing snapshots to be
> shifted. All that needs to be done is to write the header and
> unallocate the blocks.
>
> Signed-off-by: Mike Day <ncmike@ncultra.org>
> Reviewed-by: Eric Blake <eblake@redhat.com>
> ---
> v2: improved the git log entry
> added Eric Blake as a reviewer
I do agree that this code is rather ugly and I had problems with it on
more than one occasion (which should be speaking for itself, considering
that I have not worked that long on qemu). On the other hand it is
always a nice test case whether one broke zero-size allocations, though
(while I'm not sure whether these should be allowed in the first place,
though…).
Considering that this code indeed does perform a zero-size allocation
reproducably, I'm rather surprised that we actually do not have a test
case yet for snapshot deletion, though (as far as I can see).
So, all in all, I am kind of in favor of making the deletion of the last
snapshot a special case as this would probably greatly improve
readability; but on the other hand, it actually is a good test as it is
right now.
Max
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [Qemu-devel] [PATCH v2] qemu-img fails to delete last snapshot
2014-05-14 15:15 ` Kevin Wolf
@ 2014-05-15 13:07 ` Mike Day
2014-05-15 13:26 ` Kevin Wolf
0 siblings, 1 reply; 5+ messages in thread
From: Mike Day @ 2014-05-15 13:07 UTC (permalink / raw)
To: Kevin Wolf; +Cc: qemu-devel@nongnu.org, Stefan Hajnoczi
On Wed, May 14, 2014 at 11:15 AM, Kevin Wolf <kwolf@redhat.com> wrote:
>> freeing the extra clusters.
>
> Do you have an easy reproducer? Because I can't see the bug.
Thanks for the review! I was having a hard time reproducing this until
I did a bisect. This bug was fixed by 65f33bc which was merged at or
after the time I submitted the patch:
qcow2: Fix alloc_clusters_noref() overflow detection
I can reproduce the bug by checking out the immediate ancestor
43cbeffb1, creating a single snapshot in a qcow2 image, and then
attempting to delete that snapshot.
The error I get is:
qemu-img: Could not delete snapshot 'snapone': (Failed to remove
snapshot from snapshot list: File too large)
This is the error that is fixed by 65f33bc
Mike
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [Qemu-devel] [PATCH v2] qemu-img fails to delete last snapshot
2014-05-15 13:07 ` Mike Day
@ 2014-05-15 13:26 ` Kevin Wolf
0 siblings, 0 replies; 5+ messages in thread
From: Kevin Wolf @ 2014-05-15 13:26 UTC (permalink / raw)
To: Mike Day; +Cc: qemu-devel@nongnu.org, Stefan Hajnoczi
Am 15.05.2014 um 15:07 hat Mike Day geschrieben:
> On Wed, May 14, 2014 at 11:15 AM, Kevin Wolf <kwolf@redhat.com> wrote:
> >> freeing the extra clusters.
> >
> > Do you have an easy reproducer? Because I can't see the bug.
>
> Thanks for the review! I was having a hard time reproducing this until
> I did a bisect. This bug was fixed by 65f33bc which was merged at or
> after the time I submitted the patch:
>
> qcow2: Fix alloc_clusters_noref() overflow detection
>
> I can reproduce the bug by checking out the immediate ancestor
> 43cbeffb1, creating a single snapshot in a qcow2 image, and then
> attempting to delete that snapshot.
>
> The error I get is:
> qemu-img: Could not delete snapshot 'snapone': (Failed to remove
> snapshot from snapshot list: File too large)
>
> This is the error that is fixed by 65f33bc
Yes, that makes sense. Thanks Mike. I think we can disregard your patch
then and consider the problem fixed.
Kevin
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2014-05-15 13:26 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-05-12 20:27 [Qemu-devel] [PATCH v2] qemu-img fails to delete last snapshot Mike Day
2014-05-14 15:15 ` Kevin Wolf
2014-05-15 13:07 ` Mike Day
2014-05-15 13:26 ` Kevin Wolf
2014-05-14 23:54 ` Max Reitz
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).