savevm: Survive hot-unplug of snapshot device

savevm.c keeps a pointer to the snapshot block device.  If you manage
to get that device deleted, the pointer dangles, and the next snapshot
operation will crash & burn.  Unplugging a guest device that uses it
does the trick:

    $ MALLOC_PERTURB_=234 qemu-system-x86_64 [...]
    QEMU 0.12.50 monitor - type 'help' for more information
    (qemu) info snapshots
    No available block device supports snapshots
    (qemu) drive_add auto if=none,file=tmp.qcow2
    OK
    (qemu) device_add usb-storage,id=foo,drive=none1
    (qemu) info snapshots
    Snapshot devices: none1
    Snapshot list (from none1):
    ID        TAG                 VM SIZE                DATE       VM CLOCK
    (qemu) device_del foo
    (qemu) info snapshots
    Snapshot devices:
    Segmentation fault (core dumped)

Move management of that pointer to block.c, and zap it when the device
it points becomes unusable.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
Markus Armbruster 2010-06-25 10:33:39 +02:00 committed by Kevin Wolf
parent 8db520cee8
commit f9092b108f
3 changed files with 31 additions and 27 deletions

26
block.c
View file

@ -63,6 +63,9 @@ static QTAILQ_HEAD(, BlockDriverState) bdrv_states =
static QLIST_HEAD(, BlockDriver) bdrv_drivers =
QLIST_HEAD_INITIALIZER(bdrv_drivers);
/* The device to use for VM snapshots */
static BlockDriverState *bs_snapshots;
/* If non-zero, use only whitelisted block drivers */
static int use_bdrv_whitelist;
@ -629,6 +632,9 @@ unlink_and_fail:
void bdrv_close(BlockDriverState *bs)
{
if (bs->drv) {
if (bs == bs_snapshots) {
bs_snapshots = NULL;
}
if (bs->backing_hd) {
bdrv_delete(bs->backing_hd);
bs->backing_hd = NULL;
@ -677,6 +683,7 @@ void bdrv_delete(BlockDriverState *bs)
bdrv_delete(bs->file);
}
assert(bs != bs_snapshots);
qemu_free(bs);
}
@ -1778,6 +1785,25 @@ int bdrv_can_snapshot(BlockDriverState *bs)
return 1;
}
BlockDriverState *bdrv_snapshots(void)
{
BlockDriverState *bs;
if (bs_snapshots)
return bs_snapshots;
bs = NULL;
while ((bs = bdrv_next(bs))) {
if (bdrv_can_snapshot(bs)) {
goto ok;
}
}
return NULL;
ok:
bs_snapshots = bs;
return bs;
}
int bdrv_snapshot_create(BlockDriverState *bs,
QEMUSnapshotInfo *sn_info)
{