summaryrefslogtreecommitdiff
path: root/blockdev.c
diff options
context:
space:
mode:
authorStefan Hajnoczi <stefanha@linux.vnet.ibm.com>2012-01-18 14:40:46 +0000
committerKevin Wolf <kwolf@redhat.com>2012-01-26 14:49:14 +0100
commit12bd451fe0be83474910bb63b5874458141d4230 (patch)
tree2aec25bd837004ae1fac7a4951f824a7e0b2f9d7 /blockdev.c
parent5094a6c016f6e7a4fc800816d716e10ce2331396 (diff)
qmp: add block_stream command
Add the block_stream command, which starts copy backing file contents into the image file. Also add the BLOCK_JOB_COMPLETED QMP event which is emitted when image streaming completes. Later patches add control over the background copy speed, cancelation, and querying running streaming operations. Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com> Acked-by: Luiz Capitulino <lcapitulino@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Diffstat (limited to 'blockdev.c')
-rw-r--r--blockdev.c67
1 files changed, 67 insertions, 0 deletions
diff --git a/blockdev.c b/blockdev.c
index 0499ee6aea..06f179ef87 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -13,9 +13,11 @@
#include "qerror.h"
#include "qemu-option.h"
#include "qemu-config.h"
+#include "qemu-objects.h"
#include "sysemu.h"
#include "block_int.h"
#include "qmp-commands.h"
+#include "trace.h"
static QTAILQ_HEAD(drivelist, DriveInfo) drives = QTAILQ_HEAD_INITIALIZER(drives);
@@ -897,3 +899,68 @@ void qmp_block_resize(const char *device, int64_t size, Error **errp)
break;
}
}
+
+static QObject *qobject_from_block_job(BlockJob *job)
+{
+ return qobject_from_jsonf("{ 'type': %s,"
+ "'device': %s,"
+ "'len': %" PRId64 ","
+ "'offset': %" PRId64 ","
+ "'speed': %" PRId64 " }",
+ job->job_type->job_type,
+ bdrv_get_device_name(job->bs),
+ job->len,
+ job->offset,
+ job->speed);
+}
+
+static void block_stream_cb(void *opaque, int ret)
+{
+ BlockDriverState *bs = opaque;
+ QObject *obj;
+
+ trace_block_stream_cb(bs, bs->job, ret);
+
+ assert(bs->job);
+ obj = qobject_from_block_job(bs->job);
+ if (ret < 0) {
+ QDict *dict = qobject_to_qdict(obj);
+ qdict_put(dict, "error", qstring_from_str(strerror(-ret)));
+ }
+
+ monitor_protocol_event(QEVENT_BLOCK_JOB_COMPLETED, obj);
+ qobject_decref(obj);
+}
+
+void qmp_block_stream(const char *device, bool has_base,
+ const char *base, Error **errp)
+{
+ BlockDriverState *bs;
+ int ret;
+
+ bs = bdrv_find(device);
+ if (!bs) {
+ error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+ return;
+ }
+
+ /* Base device not supported */
+ if (base) {
+ error_set(errp, QERR_NOT_SUPPORTED);
+ return;
+ }
+
+ ret = stream_start(bs, NULL, block_stream_cb, bs);
+ if (ret < 0) {
+ switch (ret) {
+ case -EBUSY:
+ error_set(errp, QERR_DEVICE_IN_USE, device);
+ return;
+ default:
+ error_set(errp, QERR_NOT_SUPPORTED);
+ return;
+ }
+ }
+
+ trace_qmp_block_stream(bs, bs->job);
+}