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>
diff --git a/block.c b/block.c
index 4c65035..feda755 100644
--- a/block.c
+++ b/block.c
@@ -63,6 +63,9 @@
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 @@
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 @@
bdrv_delete(bs->file);
}
+ assert(bs != bs_snapshots);
qemu_free(bs);
}
@@ -1778,6 +1785,25 @@
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)
{