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 <pbonzini@redhat.com>
Date: Fri, 30 Mar 2012 18:32:02 +0200
Subject: [PATCH 2/4] blockdev: make image streaming safe across hotplug

RH-Author: Paolo Bonzini <pbonzini@redhat.com>
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 <jcody@redhat.com>
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>

From: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>

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 <stefanha@linux.vnet.ibm.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry-picked from upstream commit aa398a5c3a4c0fc29baf02aee5283a7fa0f202a3)

Conflicts:

	blockdev.c
---
 blockdev.c |   38 ++++++++++++++++++++++++++++++++++++++
 1 files changed, 38 insertions(+), 0 deletions(-)

Signed-off-by: Michal Novotny <minovotn@redhat.com>
---
 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

