mirror of https://github.com/xqemu/xqemu.git
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:
parent
8db520cee8
commit
f9092b108f
26
block.c
26
block.c
|
@ -63,6 +63,9 @@ static QTAILQ_HEAD(, BlockDriverState) bdrv_states =
|
||||||
static QLIST_HEAD(, BlockDriver) bdrv_drivers =
|
static QLIST_HEAD(, BlockDriver) bdrv_drivers =
|
||||||
QLIST_HEAD_INITIALIZER(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 */
|
/* If non-zero, use only whitelisted block drivers */
|
||||||
static int use_bdrv_whitelist;
|
static int use_bdrv_whitelist;
|
||||||
|
|
||||||
|
@ -629,6 +632,9 @@ unlink_and_fail:
|
||||||
void bdrv_close(BlockDriverState *bs)
|
void bdrv_close(BlockDriverState *bs)
|
||||||
{
|
{
|
||||||
if (bs->drv) {
|
if (bs->drv) {
|
||||||
|
if (bs == bs_snapshots) {
|
||||||
|
bs_snapshots = NULL;
|
||||||
|
}
|
||||||
if (bs->backing_hd) {
|
if (bs->backing_hd) {
|
||||||
bdrv_delete(bs->backing_hd);
|
bdrv_delete(bs->backing_hd);
|
||||||
bs->backing_hd = NULL;
|
bs->backing_hd = NULL;
|
||||||
|
@ -677,6 +683,7 @@ void bdrv_delete(BlockDriverState *bs)
|
||||||
bdrv_delete(bs->file);
|
bdrv_delete(bs->file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(bs != bs_snapshots);
|
||||||
qemu_free(bs);
|
qemu_free(bs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1778,6 +1785,25 @@ int bdrv_can_snapshot(BlockDriverState *bs)
|
||||||
return 1;
|
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,
|
int bdrv_snapshot_create(BlockDriverState *bs,
|
||||||
QEMUSnapshotInfo *sn_info)
|
QEMUSnapshotInfo *sn_info)
|
||||||
{
|
{
|
||||||
|
|
1
block.h
1
block.h
|
@ -193,6 +193,7 @@ const char *bdrv_get_encrypted_filename(BlockDriverState *bs);
|
||||||
void bdrv_get_backing_filename(BlockDriverState *bs,
|
void bdrv_get_backing_filename(BlockDriverState *bs,
|
||||||
char *filename, int filename_size);
|
char *filename, int filename_size);
|
||||||
int bdrv_can_snapshot(BlockDriverState *bs);
|
int bdrv_can_snapshot(BlockDriverState *bs);
|
||||||
|
BlockDriverState *bdrv_snapshots(void);
|
||||||
int bdrv_snapshot_create(BlockDriverState *bs,
|
int bdrv_snapshot_create(BlockDriverState *bs,
|
||||||
QEMUSnapshotInfo *sn_info);
|
QEMUSnapshotInfo *sn_info);
|
||||||
int bdrv_snapshot_goto(BlockDriverState *bs,
|
int bdrv_snapshot_goto(BlockDriverState *bs,
|
||||||
|
|
31
savevm.c
31
savevm.c
|
@ -83,9 +83,6 @@
|
||||||
#include "qemu_socket.h"
|
#include "qemu_socket.h"
|
||||||
#include "qemu-queue.h"
|
#include "qemu-queue.h"
|
||||||
|
|
||||||
/* point to the block driver where the snapshots are managed */
|
|
||||||
static BlockDriverState *bs_snapshots;
|
|
||||||
|
|
||||||
#define SELF_ANNOUNCE_ROUNDS 5
|
#define SELF_ANNOUNCE_ROUNDS 5
|
||||||
|
|
||||||
#ifndef ETH_P_RARP
|
#ifndef ETH_P_RARP
|
||||||
|
@ -1575,26 +1572,6 @@ out:
|
||||||
return ret;
|
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,
|
static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
|
||||||
const char *name)
|
const char *name)
|
||||||
{
|
{
|
||||||
|
@ -1674,7 +1651,7 @@ void do_savevm(Monitor *mon, const QDict *qdict)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bs = get_bs_snapshots();
|
bs = bdrv_snapshots();
|
||||||
if (!bs) {
|
if (!bs) {
|
||||||
monitor_printf(mon, "No block device can accept snapshots\n");
|
monitor_printf(mon, "No block device can accept snapshots\n");
|
||||||
return;
|
return;
|
||||||
|
@ -1769,7 +1746,7 @@ int load_vmstate(const char *name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bs = get_bs_snapshots();
|
bs = bdrv_snapshots();
|
||||||
if (!bs) {
|
if (!bs) {
|
||||||
error_report("No block device supports snapshots");
|
error_report("No block device supports snapshots");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -1833,7 +1810,7 @@ void do_delvm(Monitor *mon, const QDict *qdict)
|
||||||
int ret;
|
int ret;
|
||||||
const char *name = qdict_get_str(qdict, "name");
|
const char *name = qdict_get_str(qdict, "name");
|
||||||
|
|
||||||
bs = get_bs_snapshots();
|
bs = bdrv_snapshots();
|
||||||
if (!bs) {
|
if (!bs) {
|
||||||
monitor_printf(mon, "No block device supports snapshots\n");
|
monitor_printf(mon, "No block device supports snapshots\n");
|
||||||
return;
|
return;
|
||||||
|
@ -1863,7 +1840,7 @@ void do_info_snapshots(Monitor *mon)
|
||||||
int nb_sns, i;
|
int nb_sns, i;
|
||||||
char buf[256];
|
char buf[256];
|
||||||
|
|
||||||
bs = get_bs_snapshots();
|
bs = bdrv_snapshots();
|
||||||
if (!bs) {
|
if (!bs) {
|
||||||
monitor_printf(mon, "No available block device supports snapshots\n");
|
monitor_printf(mon, "No available block device supports snapshots\n");
|
||||||
return;
|
return;
|
||||||
|
|
Loading…
Reference in New Issue