Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/813570/?format=api
{ "id": 813570, "url": "http://patchwork.ozlabs.org/api/patches/813570/?format=api", "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20170913181910.29688-11-mreitz@redhat.com/", "project": { "id": 14, "url": "http://patchwork.ozlabs.org/api/projects/14/?format=api", "name": "QEMU Development", "link_name": "qemu-devel", "list_id": "qemu-devel.nongnu.org", "list_email": "qemu-devel@nongnu.org", "web_url": "", "scm_url": "", "webscm_url": "", "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20170913181910.29688-11-mreitz@redhat.com>", "list_archive_url": null, "date": "2017-09-13T18:19:02", "name": "[10/18] block/mirror: Make source the file child", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "dc999ba4c908e8365b4fa07b6efb1df6f3332fc9", "submitter": { "id": 36836, "url": "http://patchwork.ozlabs.org/api/people/36836/?format=api", "name": "Max Reitz", "email": "mreitz@redhat.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/qemu-devel/patch/20170913181910.29688-11-mreitz@redhat.com/mbox/", "series": [ { "id": 2960, "url": "http://patchwork.ozlabs.org/api/series/2960/?format=api", "web_url": "http://patchwork.ozlabs.org/project/qemu-devel/list/?series=2960", "date": "2017-09-13T18:18:52", "name": "block/mirror: Add active-sync mirroring", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/2960/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/813570/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/813570/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>", "X-Original-To": "incoming@patchwork.ozlabs.org", "Delivered-To": "patchwork-incoming@bilbo.ozlabs.org", "Authentication-Results": [ "ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=nongnu.org\n\t(client-ip=2001:4830:134:3::11; helo=lists.gnu.org;\n\tenvelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org;\n\treceiver=<UNKNOWN>)", "ext-mx07.extmail.prod.ext.phx2.redhat.com;\n\tdmarc=none (p=none dis=none) header.from=redhat.com", "ext-mx07.extmail.prod.ext.phx2.redhat.com;\n\tspf=fail smtp.mailfrom=mreitz@redhat.com" ], "Received": [ "from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11])\n\t(using TLSv1 with cipher AES256-SHA (256/256 bits))\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3xsqzB4dRMz9rxl\n\tfor <incoming@patchwork.ozlabs.org>;\n\tThu, 14 Sep 2017 04:32:54 +1000 (AEST)", "from localhost ([::1]:44063 helo=lists.gnu.org)\n\tby lists.gnu.org with esmtp (Exim 4.71) (envelope-from\n\t<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>)\n\tid 1dsCSy-0002RA-Jd\n\tfor incoming@patchwork.ozlabs.org; Wed, 13 Sep 2017 14:32:52 -0400", "from eggs.gnu.org ([2001:4830:134:3::10]:37181)\n\tby lists.gnu.org with esmtp (Exim 4.71)\n\t(envelope-from <mreitz@redhat.com>) id 1dsCHV-0000LU-7D\n\tfor qemu-devel@nongnu.org; Wed, 13 Sep 2017 14:21:03 -0400", "from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71)\n\t(envelope-from <mreitz@redhat.com>) id 1dsCHS-0005fV-W3\n\tfor qemu-devel@nongnu.org; Wed, 13 Sep 2017 14:21:01 -0400", "from mx1.redhat.com ([209.132.183.28]:51504)\n\tby eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32)\n\t(Exim 4.71) (envelope-from <mreitz@redhat.com>)\n\tid 1dsCHM-0005YV-BH; Wed, 13 Sep 2017 14:20:52 -0400", "from smtp.corp.redhat.com\n\t(int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15])\n\t(using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))\n\t(No client certificate requested)\n\tby mx1.redhat.com (Postfix) with ESMTPS id 6A118C047B88;\n\tWed, 13 Sep 2017 18:20:51 +0000 (UTC)", "from localhost (ovpn-204-23.brq.redhat.com [10.40.204.23])\n\tby smtp.corp.redhat.com (Postfix) with ESMTPS id 202205D763;\n\tWed, 13 Sep 2017 18:20:43 +0000 (UTC)" ], "DMARC-Filter": "OpenDMARC Filter v1.3.2 mx1.redhat.com 6A118C047B88", "From": "Max Reitz <mreitz@redhat.com>", "To": "qemu-block@nongnu.org", "Date": "Wed, 13 Sep 2017 20:19:02 +0200", "Message-Id": "<20170913181910.29688-11-mreitz@redhat.com>", "In-Reply-To": "<20170913181910.29688-1-mreitz@redhat.com>", "References": "<20170913181910.29688-1-mreitz@redhat.com>", "X-Scanned-By": "MIMEDefang 2.79 on 10.5.11.15", "X-Greylist": "Sender IP whitelisted, not delayed by milter-greylist-4.5.16\n\t(mx1.redhat.com [10.5.110.31]);\n\tWed, 13 Sep 2017 18:20:51 +0000 (UTC)", "X-detected-operating-system": "by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic]\n\t[fuzzy]", "X-Received-From": "209.132.183.28", "Subject": "[Qemu-devel] [PATCH 10/18] block/mirror: Make source the file child", "X-BeenThere": "qemu-devel@nongnu.org", "X-Mailman-Version": "2.1.21", "Precedence": "list", "List-Id": "<qemu-devel.nongnu.org>", "List-Unsubscribe": "<https://lists.nongnu.org/mailman/options/qemu-devel>,\n\t<mailto:qemu-devel-request@nongnu.org?subject=unsubscribe>", "List-Archive": "<http://lists.nongnu.org/archive/html/qemu-devel/>", "List-Post": "<mailto:qemu-devel@nongnu.org>", "List-Help": "<mailto:qemu-devel-request@nongnu.org?subject=help>", "List-Subscribe": "<https://lists.nongnu.org/mailman/listinfo/qemu-devel>,\n\t<mailto:qemu-devel-request@nongnu.org?subject=subscribe>", "Cc": "Kevin Wolf <kwolf@redhat.com>, Fam Zheng <famz@redhat.com>,\n\tqemu-devel@nongnu.org, Max Reitz <mreitz@redhat.com>,\n\tStefan Hajnoczi <stefanha@redhat.com>, John Snow <jsnow@redhat.com>", "Errors-To": "qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org", "Sender": "\"Qemu-devel\"\n\t<qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org>" }, "content": "Regarding the source BDS, the mirror BDS is arguably a filter node.\nTherefore, the source BDS should be its \"file\" child.\n\nSigned-off-by: Max Reitz <mreitz@redhat.com>\n---\n block/mirror.c | 127 ++++++++++++++++++++++++++++++++++-----------\n block/qapi.c | 25 ++++++---\n tests/qemu-iotests/141.out | 4 +-\n 3 files changed, 119 insertions(+), 37 deletions(-)", "diff": "diff --git a/block/mirror.c b/block/mirror.c\nindex 9df4157511..05410c94ca 100644\n--- a/block/mirror.c\n+++ b/block/mirror.c\n@@ -77,8 +77,16 @@ typedef struct MirrorBlockJob {\n int target_cluster_size;\n int max_iov;\n bool initial_zeroing_ongoing;\n+\n+ /* Signals that we are no longer accessing source and target and the mirror\n+ * BDS should thus relinquish all permissions */\n+ bool exiting;\n } MirrorBlockJob;\n \n+typedef struct MirrorBDSOpaque {\n+ MirrorBlockJob *job;\n+} MirrorBDSOpaque;\n+\n struct MirrorOp {\n MirrorBlockJob *s;\n QEMUIOVector qiov;\n@@ -595,12 +603,15 @@ static void mirror_exit(BlockJob *job, void *opaque)\n {\n MirrorBlockJob *s = container_of(job, MirrorBlockJob, common);\n MirrorExitData *data = opaque;\n+ MirrorBDSOpaque *bs_opaque = s->mirror_top_bs->opaque;\n AioContext *replace_aio_context = NULL;\n BlockDriverState *src = s->source->bs;\n BlockDriverState *target_bs = blk_bs(s->target);\n BlockDriverState *mirror_top_bs = s->mirror_top_bs;\n Error *local_err = NULL;\n \n+ s->exiting = true;\n+\n bdrv_release_dirty_bitmap(src, s->dirty_bitmap);\n \n /* Make sure that the source BDS doesn't go away before we called\n@@ -622,7 +633,7 @@ static void mirror_exit(BlockJob *job, void *opaque)\n \n /* We don't access the source any more. Dropping any WRITE/RESIZE is\n * required before it could become a backing file of target_bs. */\n- bdrv_child_try_set_perm(mirror_top_bs->backing, 0, BLK_PERM_ALL,\n+ bdrv_child_try_set_perm(mirror_top_bs->file, 0, BLK_PERM_ALL,\n &error_abort);\n if (s->backing_mode == MIRROR_SOURCE_BACKING_CHAIN) {\n BlockDriverState *backing = s->is_none_mode ? src : s->base;\n@@ -673,12 +684,11 @@ static void mirror_exit(BlockJob *job, void *opaque)\n \n /* Remove the mirror filter driver from the graph. Before this, get rid of\n * the blockers on the intermediate nodes so that the resulting state is\n- * valid. Also give up permissions on mirror_top_bs->backing, which might\n+ * valid. Also give up permissions on mirror_top_bs->file, which might\n * block the removal. */\n block_job_remove_all_bdrv(job);\n- bdrv_child_try_set_perm(mirror_top_bs->backing, 0, BLK_PERM_ALL,\n- &error_abort);\n- bdrv_replace_node(mirror_top_bs, backing_bs(mirror_top_bs), &error_abort);\n+ bdrv_child_try_set_perm(mirror_top_bs->file, 0, BLK_PERM_ALL, &error_abort);\n+ bdrv_replace_node(mirror_top_bs, mirror_top_bs->file->bs, &error_abort);\n \n /* We just changed the BDS the job BB refers to (with either or both of the\n * bdrv_replace_node() calls), so switch the BB back so the cleanup does\n@@ -687,6 +697,7 @@ static void mirror_exit(BlockJob *job, void *opaque)\n blk_set_perm(job->blk, 0, BLK_PERM_ALL, &error_abort);\n blk_insert_bs(job->blk, mirror_top_bs, &error_abort);\n \n+ bs_opaque->job = NULL;\n block_job_completed(&s->common, data->ret);\n \n g_free(data);\n@@ -1102,7 +1113,7 @@ static void mirror_drain(BlockJob *job)\n {\n MirrorBlockJob *s = container_of(job, MirrorBlockJob, common);\n \n- /* Need to keep a reference in case blk_drain triggers execution\n+ /* Need to keep a reference in case bdrv_drain triggers execution\n * of mirror_complete...\n */\n if (s->target) {\n@@ -1135,44 +1146,88 @@ static const BlockJobDriver commit_active_job_driver = {\n .drain = mirror_drain,\n };\n \n+static void source_child_inherit_fmt_options(int *child_flags,\n+ QDict *child_options,\n+ int parent_flags,\n+ QDict *parent_options)\n+{\n+ child_backing.inherit_options(child_flags, child_options,\n+ parent_flags, parent_options);\n+}\n+\n+static char *source_child_get_parent_desc(BdrvChild *c)\n+{\n+ return child_backing.get_parent_desc(c);\n+}\n+\n+static void source_child_cb_drained_begin(BdrvChild *c)\n+{\n+ BlockDriverState *bs = c->opaque;\n+ MirrorBDSOpaque *s = bs->opaque;\n+\n+ if (s && s->job) {\n+ block_job_drained_begin(&s->job->common);\n+ }\n+ bdrv_drained_begin(bs);\n+}\n+\n+static void source_child_cb_drained_end(BdrvChild *c)\n+{\n+ BlockDriverState *bs = c->opaque;\n+ MirrorBDSOpaque *s = bs->opaque;\n+\n+ if (s && s->job) {\n+ block_job_drained_end(&s->job->common);\n+ }\n+ bdrv_drained_end(bs);\n+}\n+\n+static BdrvChildRole source_child_role = {\n+ .inherit_options = source_child_inherit_fmt_options,\n+ .get_parent_desc = source_child_get_parent_desc,\n+ .drained_begin = source_child_cb_drained_begin,\n+ .drained_end = source_child_cb_drained_end,\n+};\n+\n static int coroutine_fn bdrv_mirror_top_preadv(BlockDriverState *bs,\n uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags)\n {\n- return bdrv_co_preadv(bs->backing, offset, bytes, qiov, flags);\n+ return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);\n }\n \n static int coroutine_fn bdrv_mirror_top_pwritev(BlockDriverState *bs,\n uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags)\n {\n- return bdrv_co_pwritev(bs->backing, offset, bytes, qiov, flags);\n+ return bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags);\n }\n \n static int coroutine_fn bdrv_mirror_top_flush(BlockDriverState *bs)\n {\n- return bdrv_co_flush(bs->backing->bs);\n+ return bdrv_co_flush(bs->file->bs);\n }\n \n static int coroutine_fn bdrv_mirror_top_pwrite_zeroes(BlockDriverState *bs,\n int64_t offset, int bytes, BdrvRequestFlags flags)\n {\n- return bdrv_co_pwrite_zeroes(bs->backing, offset, bytes, flags);\n+ return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags);\n }\n \n static int coroutine_fn bdrv_mirror_top_pdiscard(BlockDriverState *bs,\n int64_t offset, int bytes)\n {\n- return bdrv_co_pdiscard(bs->backing->bs, offset, bytes);\n+ return bdrv_co_pdiscard(bs->file->bs, offset, bytes);\n }\n \n static void bdrv_mirror_top_refresh_filename(BlockDriverState *bs, QDict *opts)\n {\n- bdrv_refresh_filename(bs->backing->bs);\n pstrcpy(bs->exact_filename, sizeof(bs->exact_filename),\n- bs->backing->bs->filename);\n+ bs->file->bs->filename);\n }\n \n static void bdrv_mirror_top_close(BlockDriverState *bs)\n {\n+ bdrv_unref_child(bs, bs->file);\n+ bs->file = NULL;\n }\n \n static void bdrv_mirror_top_child_perm(BlockDriverState *bs, BdrvChild *c,\n@@ -1180,6 +1235,14 @@ static void bdrv_mirror_top_child_perm(BlockDriverState *bs, BdrvChild *c,\n uint64_t perm, uint64_t shared,\n uint64_t *nperm, uint64_t *nshared)\n {\n+ MirrorBDSOpaque *s = bs->opaque;\n+\n+ if (s->job && s->job->exiting) {\n+ *nperm = 0;\n+ *nshared = BLK_PERM_ALL;\n+ return;\n+ }\n+\n /* Must be able to forward guest writes to the real image */\n *nperm = 0;\n if (perm & BLK_PERM_WRITE) {\n@@ -1190,7 +1253,7 @@ static void bdrv_mirror_top_child_perm(BlockDriverState *bs, BdrvChild *c,\n }\n \n /* Dummy node that provides consistent read to its users without requiring it\n- * from its backing file and that allows writes on the backing file chain. */\n+ * from its source file and that allows writes on the source file. */\n static BlockDriver bdrv_mirror_top = {\n .format_name = \"mirror_top\",\n .bdrv_co_preadv = bdrv_mirror_top_preadv,\n@@ -1198,7 +1261,7 @@ static BlockDriver bdrv_mirror_top = {\n .bdrv_co_pwrite_zeroes = bdrv_mirror_top_pwrite_zeroes,\n .bdrv_co_pdiscard = bdrv_mirror_top_pdiscard,\n .bdrv_co_flush = bdrv_mirror_top_flush,\n- .bdrv_co_get_block_status = bdrv_co_get_block_status_from_backing,\n+ .bdrv_co_get_block_status = bdrv_co_get_block_status_from_file,\n .bdrv_refresh_filename = bdrv_mirror_top_refresh_filename,\n .bdrv_close = bdrv_mirror_top_close,\n .bdrv_child_perm = bdrv_mirror_top_child_perm,\n@@ -1221,6 +1284,7 @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,\n Error **errp)\n {\n MirrorBlockJob *s;\n+ MirrorBDSOpaque *bs_opaque;\n BlockDriverState *mirror_top_bs;\n bool target_graph_mod;\n bool target_is_backing;\n@@ -1244,9 +1308,7 @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,\n buf_size = DEFAULT_MIRROR_BUF_SIZE;\n }\n \n- /* In the case of active commit, add dummy driver to provide consistent\n- * reads on the top, while disabling it in the intermediate nodes, and make\n- * the backing chain writable. */\n+ /* Create mirror BDS */\n mirror_top_bs = bdrv_new_open_driver(&bdrv_mirror_top, filter_node_name,\n BDRV_O_RDWR, errp);\n if (mirror_top_bs == NULL) {\n@@ -1256,14 +1318,19 @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,\n mirror_top_bs->implicit = true;\n }\n mirror_top_bs->total_sectors = bs->total_sectors;\n+ bs_opaque = g_new0(MirrorBDSOpaque, 1);\n+ mirror_top_bs->opaque = bs_opaque;\n bdrv_set_aio_context(mirror_top_bs, bdrv_get_aio_context(bs));\n \n- /* bdrv_append takes ownership of the mirror_top_bs reference, need to keep\n- * it alive until block_job_create() succeeds even if bs has no parent. */\n- bdrv_ref(mirror_top_bs);\n- bdrv_drained_begin(bs);\n- bdrv_append(mirror_top_bs, bs, &local_err);\n- bdrv_drained_end(bs);\n+ /* Create reference for bdrv_attach_child() */\n+ bdrv_ref(bs);\n+ mirror_top_bs->file = bdrv_attach_child(mirror_top_bs, bs, \"file\",\n+ &source_child_role, &local_err);\n+ if (!local_err) {\n+ bdrv_drained_begin(bs);\n+ bdrv_replace_node(bs, mirror_top_bs, &local_err);\n+ bdrv_drained_end(bs);\n+ }\n \n if (local_err) {\n bdrv_unref(mirror_top_bs);\n@@ -1280,6 +1347,8 @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,\n if (!s) {\n goto fail;\n }\n+ bs_opaque->job = s;\n+\n /* The block job now has a reference to this node */\n bdrv_unref(mirror_top_bs);\n \n@@ -1329,7 +1398,7 @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,\n s->should_complete = true;\n }\n \n- s->source = mirror_top_bs->backing;\n+ s->source = mirror_top_bs->file;\n s->mirror_top_bs = mirror_top_bs;\n \n s->dirty_bitmap = bdrv_create_dirty_bitmap(bs, granularity, NULL, errp);\n@@ -1373,12 +1442,12 @@ fail:\n \n g_free(s->replaces);\n blk_unref(s->target);\n- block_job_early_fail(&s->common);\n+ bs_opaque->job = NULL;\n+ block_job_unref(&s->common);\n }\n \n- bdrv_child_try_set_perm(mirror_top_bs->backing, 0, BLK_PERM_ALL,\n- &error_abort);\n- bdrv_replace_node(mirror_top_bs, backing_bs(mirror_top_bs), &error_abort);\n+ bdrv_child_try_set_perm(mirror_top_bs->file, 0, BLK_PERM_ALL, &error_abort);\n+ bdrv_replace_node(mirror_top_bs, mirror_top_bs->file->bs, &error_abort);\n \n bdrv_unref(mirror_top_bs);\n }\ndiff --git a/block/qapi.c b/block/qapi.c\nindex 7fa2437923..ee792d0cbc 100644\n--- a/block/qapi.c\n+++ b/block/qapi.c\n@@ -147,9 +147,13 @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk,\n \n /* Skip automatically inserted nodes that the user isn't aware of for\n * query-block (blk != NULL), but not for query-named-block-nodes */\n- while (blk && bs0->drv && bs0->implicit) {\n- bs0 = backing_bs(bs0);\n- assert(bs0);\n+ while (blk && bs0 && bs0->drv && bs0->implicit) {\n+ if (bs0->backing) {\n+ bs0 = backing_bs(bs0);\n+ } else {\n+ assert(bs0->file);\n+ bs0 = bs0->file->bs;\n+ }\n }\n }\n \n@@ -337,7 +341,12 @@ static void bdrv_query_info(BlockBackend *blk, BlockInfo **p_info,\n \n /* Skip automatically inserted nodes that the user isn't aware of */\n while (bs && bs->drv && bs->implicit) {\n- bs = backing_bs(bs);\n+ if (bs->backing) {\n+ bs = backing_bs(bs);\n+ } else {\n+ assert(bs->file);\n+ bs = bs->file->bs;\n+ }\n }\n \n info->device = g_strdup(blk_name(blk));\n@@ -466,8 +475,12 @@ static BlockStats *bdrv_query_bds_stats(BlockDriverState *bs,\n * a BlockBackend-level command. Stay at the exact node for a node-level\n * command. */\n while (blk_level && bs->drv && bs->implicit) {\n- bs = backing_bs(bs);\n- assert(bs);\n+ if (bs->backing) {\n+ bs = backing_bs(bs);\n+ } else {\n+ assert(bs->file);\n+ bs = bs->file->bs;\n+ }\n }\n \n if (bdrv_get_node_name(bs)[0]) {\ndiff --git a/tests/qemu-iotests/141.out b/tests/qemu-iotests/141.out\nindex 82e763b68d..8c4dd6d531 100644\n--- a/tests/qemu-iotests/141.out\n+++ b/tests/qemu-iotests/141.out\n@@ -20,7 +20,7 @@ Formatting 'TEST_DIR/o.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.\n Formatting 'TEST_DIR/o.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT backing_fmt=IMGFMT\n {\"timestamp\": {\"seconds\": TIMESTAMP, \"microseconds\": TIMESTAMP}, \"event\": \"BLOCK_JOB_READY\", \"data\": {\"device\": \"job0\", \"len\": 0, \"offset\": 0, \"speed\": 0, \"type\": \"mirror\"}}\n {\"return\": {}}\n-{\"error\": {\"class\": \"GenericError\", \"desc\": \"Node 'drv0' is busy: node is used as backing hd of 'NODE_NAME'\"}}\n+{\"error\": {\"class\": \"GenericError\", \"desc\": \"Block device drv0 is in use\"}}\n {\"return\": {}}\n {\"timestamp\": {\"seconds\": TIMESTAMP, \"microseconds\": TIMESTAMP}, \"event\": \"BLOCK_JOB_COMPLETED\", \"data\": {\"device\": \"job0\", \"len\": 0, \"offset\": 0, \"speed\": 0, \"type\": \"mirror\"}}\n {\"return\": {}}\n@@ -30,7 +30,7 @@ Formatting 'TEST_DIR/o.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.\n {\"return\": {}}\n {\"timestamp\": {\"seconds\": TIMESTAMP, \"microseconds\": TIMESTAMP}, \"event\": \"BLOCK_JOB_READY\", \"data\": {\"device\": \"job0\", \"len\": 0, \"offset\": 0, \"speed\": 0, \"type\": \"commit\"}}\n {\"return\": {}}\n-{\"error\": {\"class\": \"GenericError\", \"desc\": \"Node 'drv0' is busy: node is used as backing hd of 'NODE_NAME'\"}}\n+{\"error\": {\"class\": \"GenericError\", \"desc\": \"Block device drv0 is in use\"}}\n {\"return\": {}}\n {\"timestamp\": {\"seconds\": TIMESTAMP, \"microseconds\": TIMESTAMP}, \"event\": \"BLOCK_JOB_COMPLETED\", \"data\": {\"device\": \"job0\", \"len\": 0, \"offset\": 0, \"speed\": 0, \"type\": \"commit\"}}\n {\"return\": {}}\n", "prefixes": [ "10/18" ] }