From 155aebda2944dc4b19ab932526bd90545e70c69d Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 4 Oct 2011 16:23:48 +0200 Subject: [PATCH 13/76] savevm: Survive hot-unplug of snapshot device RH-Author: Markus Armbruster Message-id: <1317745491-18401-6-git-send-email-armbru@redhat.com> Patchwork-id: 33604 O-Subject: [PATCH RHEL-6.2 qemu-kvm 05/68] savevm: Survive hot-unplug of snapshot device Bugzilla: 743269 RH-Acked-by: Paolo Bonzini RH-Acked-by: Amit Shah RH-Acked-by: Markus Armbruster RH-Acked-by: Juan Quintela 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 Signed-off-by: Kevin Wolf (cherry picked from commit f9092b108f7b35e463e58bd3dd348ff002ba9e63) Conflicts: block.c block.h Conflicts because commit 76a4a8cf overtook this one in RHEL-6. --- block.c | 29 ++++++++++++++++++++++++++++- block.h | 1 + savevm.c | 31 ++++--------------------------- 3 files changed, 33 insertions(+), 28 deletions(-) Signed-off-by: Michal Novotny --- block.c | 29 ++++++++++++++++++++++++++++- block.h | 1 + savevm.c | 31 ++++--------------------------- 3 files changed, 33 insertions(+), 28 deletions(-) diff --git a/block.c b/block.c index dff305b..c6c31ea 100644 --- a/block.c +++ b/block.c @@ -64,6 +64,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; @@ -640,8 +643,12 @@ unlink_and_fail: void bdrv_close(BlockDriverState *bs) { if (bs->drv) { - if (bs->backing_hd) + if (bs == bs_snapshots) { + bs_snapshots = NULL; + } + if (bs->backing_hd) { bdrv_delete(bs->backing_hd); + } bs->drv->bdrv_close(bs); qemu_free(bs->opaque); #ifdef _WIN32 @@ -694,6 +701,7 @@ void bdrv_delete(BlockDriverState *bs) bdrv_delete(bs->file); } + assert(bs != bs_snapshots); qemu_free(bs); } @@ -1879,6 +1887,25 @@ int bdrv_is_snapshot(BlockDriverState *bs) return !!(bs->open_flags & BDRV_O_SNAPSHOT); } +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) { diff --git a/block.h b/block.h index de6f312..1594049 100644 --- a/block.h +++ b/block.h @@ -215,6 +215,7 @@ void bdrv_get_backing_filename(BlockDriverState *bs, char *filename, int filename_size); int bdrv_can_snapshot(BlockDriverState *bs); int bdrv_is_snapshot(BlockDriverState *bs); +BlockDriverState *bdrv_snapshots(void); int bdrv_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info); int bdrv_snapshot_goto(BlockDriverState *bs, diff --git a/savevm.c b/savevm.c index 6b24e9e..0928e3a 100644 --- a/savevm.c +++ b/savevm.c @@ -83,9 +83,6 @@ #include "qemu_socket.h" #include "qemu-queue.h" -/* point to the block driver where the snapshots are managed */ -static BlockDriverState *bs_snapshots; - #define SELF_ANNOUNCE_ROUNDS 5 #ifndef ETH_P_RARP @@ -1875,26 +1872,6 @@ out: return ret; } -static BlockDriverState *get_bs_snapshots(void) -{ - BlockDriverState *bs; - - if (bs_snapshots) - return bs_snapshots; - /* FIXME what if bs_snapshots gets hot-unplugged? */ - - bs = NULL; - while ((bs = bdrv_next(bs))) { - if (bdrv_can_snapshot(bs)) { - goto ok; - } - } - return NULL; - ok: - bs_snapshots = bs; - return bs; -} - static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info, const char *name) { @@ -1974,7 +1951,7 @@ void do_savevm(Monitor *mon, const QDict *qdict) } } - bs = get_bs_snapshots(); + bs = bdrv_snapshots(); if (!bs) { monitor_printf(mon, "No block device can accept snapshots\n"); return; @@ -2069,7 +2046,7 @@ int load_vmstate(const char *name) } } - bs = get_bs_snapshots(); + bs = bdrv_snapshots(); if (!bs) { error_report("No block device supports snapshots"); return -EINVAL; @@ -2136,7 +2113,7 @@ void do_delvm(Monitor *mon, const QDict *qdict) int ret; const char *name = qdict_get_str(qdict, "name"); - bs = get_bs_snapshots(); + bs = bdrv_snapshots(); if (!bs) { monitor_printf(mon, "No block device supports snapshots\n"); return; @@ -2166,7 +2143,7 @@ void do_info_snapshots(Monitor *mon) int nb_sns, i; char buf[256]; - bs = get_bs_snapshots(); + bs = bdrv_snapshots(); if (!bs) { monitor_printf(mon, "No available block device supports snapshots\n"); return; -- 1.7.4.4