From 959bdfbcbc3cc4469e1dc3f6a3fec70ee5062fe7 Mon Sep 17 00:00:00 2001 Message-Id: <959bdfbcbc3cc4469e1dc3f6a3fec70ee5062fe7.1334231944.git.minovotn@redhat.com> In-Reply-To: <50c33b164bbd7fa0d613bd09b072ef7deb09168c.1334231944.git.minovotn@redhat.com> References: <50c33b164bbd7fa0d613bd09b072ef7deb09168c.1334231944.git.minovotn@redhat.com> From: Paolo Bonzini Date: Fri, 30 Mar 2012 18:32:02 +0200 Subject: [PATCH 2/4] blockdev: make image streaming safe across hotplug RH-Author: Paolo Bonzini Message-id: <1333132324-20958-3-git-send-email-pbonzini@redhat.com> Patchwork-id: 39051 O-Subject: [RHEL 6.3 qemu-kvm PATCH v2 2/4] blockdev: make image streaming safe across hotplug Bugzilla: 807898 RH-Acked-by: Jeffrey Cody RH-Acked-by: Kevin Wolf RH-Acked-by: Laszlo Ersek From: Stefan Hajnoczi Unplugging a storage interface like virtio-blk causes the host block device to be deleted too. Long-running operations like block migration must take a DriveInfo reference to prevent the BlockDriverState from being freed. For image streaming we can do the same thing. Note that it is not possible to acquire/release the drive reference in block.c where the block job functions live because drive_get_ref()/drive_put_ref() are blockdev.c functions. Calling them from block.c would be a layering violation - tools like qemu-img don't even link against blockdev.c. Signed-off-by: Stefan Hajnoczi Signed-off-by: Kevin Wolf Signed-off-by: Paolo Bonzini (cherry-picked from upstream commit aa398a5c3a4c0fc29baf02aee5283a7fa0f202a3) Conflicts: blockdev.c --- blockdev.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 files changed, 38 insertions(+), 0 deletions(-) Signed-off-by: Michal Novotny --- blockdev.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 files changed, 38 insertions(+), 0 deletions(-) diff --git a/blockdev.c b/blockdev.c index d82268b..488b30f 100644 --- a/blockdev.c +++ b/blockdev.c @@ -218,6 +218,37 @@ void drive_get_ref(DriveInfo *dinfo) dinfo->refcount++; } +typedef struct { + QEMUBH *bh; + DriveInfo *dinfo; +} DrivePutRefBH; + +static void drive_put_ref_bh(void *opaque) +{ + DrivePutRefBH *s = opaque; + + drive_put_ref(s->dinfo); + qemu_bh_delete(s->bh); + g_free(s); +} + +/* + * Release a drive reference in a BH + * + * It is not possible to use drive_put_ref() from a callback function when the + * callers still need the drive. In such cases we schedule a BH to release the + * reference. + */ +static void drive_put_ref_bh_schedule(DriveInfo *dinfo) +{ + DrivePutRefBH *s; + + s = g_new(DrivePutRefBH, 1); + s->bh = qemu_bh_new(drive_put_ref_bh, s); + s->dinfo = dinfo; + qemu_bh_schedule(s->bh); +} + static int parse_block_error_action(const char *buf, int is_read) { if (!strcmp(buf, "ignore")) { @@ -1142,6 +1173,8 @@ static void block_stream_cb(void *opaque, int ret) monitor_protocol_event(QEVENT_BLOCK_JOB_COMPLETED, obj); } qobject_decref(obj); + + drive_put_ref_bh_schedule(drive_get_by_blockdev(bs)); } int do_block_stream(Monitor *mon, const QDict *params, QObject **ret_data) @@ -1178,6 +1211,11 @@ int do_block_stream(Monitor *mon, const QDict *params, QObject **ret_data) } } + /* Grab a reference so hotplug does not delete the BlockDriverState from + * underneath us. + */ + drive_get_ref(drive_get_by_blockdev(bs)); + trace_do_block_stream(bs, bs->job); return 0; } -- 1.7.7.6