All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v8 00/11] Support streaming to an intermediate layer
@ 2015-06-22 21:32 Alberto Garcia
  2015-06-22 21:32 ` [Qemu-devel] [PATCH v8 01/11] block: keep a list of block jobs Alberto Garcia
                   ` (11 more replies)
  0 siblings, 12 replies; 20+ messages in thread
From: Alberto Garcia @ 2015-06-22 21:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Alberto Garcia, Stefan Hajnoczi, qemu-block

v8:
- Rebased on top of Stefan's block branch (0a35bce416)
- The loop that pauses the block jobs in bdrv_drain_all() is now split
  in two: one that iterates the list of block jobs to stop them, and
  one that iterates the root bds in order to get the aio contexts.

v7: https://lists.gnu.org/archive/html/qemu-devel/2015-05/msg02580.html
- Rebased against the current master
- Updated bdrv_drain_all() to use the new block_job_next() API.

v6: https://lists.gnu.org/archive/html/qemu-devel/2015-04/msg03046.html
- fix the no-op test following Max's suggestions

v5: https://lists.gnu.org/archive/html/qemu-devel/2015-04/msg03006.html
- Fix a few typos
- Minor documentation updates
- Update test_stream_partial() to test no-ops
- New test case: test_stream_parallel()
- New test case: test_stream_overlapping()

v4: https://lists.gnu.org/archive/html/qemu-devel/2015-04/msg01878.html
- Refactor find_block_job to use the error from bdrv_lookup_bs()
- Don't use QERR_DEVICE_IN_USE in block_job_create() since we can be
  dealing with nodes now.
- Fix @device comment in the BlockJobInfo documentation
- stream_start(): simplify the bdrv_reopen() call and use
  bdrv_get_device_or_node_name() for error messages.
- Use a different variable name for BlockDriverState *i
- Documentation fixes in docs/live-block-ops.txt
- Update iotest 30 since now test_device_not_found() returns
  GenericError
- Fix test case test_stream_partial()
- Add new test case test_stream_intermediate()
- Fix typos

v3: https://lists.gnu.org/archive/html/qemu-devel/2015-04/msg00806.html
- Keep a list of block jobs and make qmp_query_block_jobs() iterate
  over it.

v2: https://lists.gnu.org/archive/html/qemu-devel/2015-03/msg04798.html
- The 'block-stream' command does not have a 'node-name' parameter
  anymore and reuses 'device' for that purpose.
- Block jobs can now be owned by any intermediate node, and not just
  by the ones at the root. query-block-jobs is updated to reflect that
  change.
- The 'device' parameter of all 'block-job-*' commands can now take a
  node name.
- The BlockJobInfo type and all BLOCK_JOB_* events report the node
  name in the 'device' field if the node does not have a device name.
- All intermediate nodes are blocked (and checked for blockers) during
  the streaming operation.

v1: https://lists.gnu.org/archive/html/qemu-devel/2015-02/msg04116.html

=== git backport-diff against v7 ===

Key:
[----] : patches are identical
[####] : number of functional differences between upstream/downstream patch
[down] : patch is downstream-only
The flags [FC] indicate (F)unctional and (C)ontextual differences, respectively

001/11:[0007] [FC] 'block: keep a list of block jobs'
002/11:[----] [--] 'block: allow block jobs in any arbitrary node'
003/11:[----] [--] 'block: never cancel a streaming job without running stream_complete()'
004/11:[----] [--] 'block: Support streaming to an intermediate layer'
005/11:[----] [--] 'block: Add QMP support for streaming to an intermediate layer'
006/11:[----] [--] 'docs: Document how to stream to an intermediate layer'
007/11:[----] [--] 'qemu-iotests: fix test_stream_partial()'
008/11:[----] [--] 'qemu-iotests: add no-op streaming test'
009/11:[----] [--] 'qemu-iotests: test streaming to an intermediate layer'
010/11:[----] [--] 'qemu-iotests: test block-stream operations in parallel'
011/11:[----] [--] 'qemu-iotests: test overlapping block-stream operations'

Alberto Garcia (11):
  block: keep a list of block jobs
  block: allow block jobs in any arbitrary node
  block: never cancel a streaming job without running stream_complete()
  block: Support streaming to an intermediate layer
  block: Add QMP support for streaming to an intermediate layer
  docs: Document how to stream to an intermediate layer
  qemu-iotests: fix test_stream_partial()
  qemu-iotests: add no-op streaming test
  qemu-iotests: test streaming to an intermediate layer
  qemu-iotests: test block-stream operations in parallel
  qemu-iotests: test overlapping block-stream operations

 block.c                    |   4 +-
 block/io.c                 |  22 +++----
 block/mirror.c             |   5 +-
 block/stream.c             |  44 ++++++++++++--
 blockdev.c                 |  55 ++++++++---------
 blockjob.c                 |  31 +++++++---
 docs/live-block-ops.txt    |  31 ++++++----
 docs/qmp/qmp-events.txt    |   8 +--
 include/block/blockjob.h   |  14 +++++
 include/qapi/qmp/qerror.h  |   3 -
 qapi/block-core.json       |  30 +++++----
 tests/qemu-iotests/030     | 148 ++++++++++++++++++++++++++++++++++++++++++++-
 tests/qemu-iotests/030.out |   4 +-
 13 files changed, 307 insertions(+), 92 deletions(-)

-- 
2.1.4

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [Qemu-devel] [PATCH v8 01/11] block: keep a list of block jobs
  2015-06-22 21:32 [Qemu-devel] [PATCH v8 00/11] Support streaming to an intermediate layer Alberto Garcia
@ 2015-06-22 21:32 ` Alberto Garcia
  2015-06-24 15:45   ` Max Reitz
  2015-06-22 21:32 ` [Qemu-devel] [PATCH v8 02/11] block: allow block jobs in any arbitrary node Alberto Garcia
                   ` (10 subsequent siblings)
  11 siblings, 1 reply; 20+ messages in thread
From: Alberto Garcia @ 2015-06-22 21:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: Alberto Garcia, qemu-block, Alexander Yarygin, Max Reitz,
	Stefan Hajnoczi

The current way to obtain the list of existing block jobs is to
iterate over all root nodes and check which ones own a job.

Since we want to be able to support block jobs in other nodes as well,
this patch keeps a list of jobs that is updated every time one is
created or destroyed.

This also updates qmp_query_block_jobs() and bdrv_drain_all() to use
this new list.

Signed-off-by: Alberto Garcia <berto@igalia.com>
Cc: Max Reitz <mreitz@redhat.com>
Cc: Eric Blake <eblake@redhat.com>
Cc: Alexander Yarygin <yarygin@linux.vnet.ibm.com>
---
 block/io.c               | 22 +++++++++++-----------
 blockdev.c               | 19 ++++++++-----------
 blockjob.c               | 13 +++++++++++++
 include/block/blockjob.h | 14 ++++++++++++++
 4 files changed, 46 insertions(+), 22 deletions(-)

diff --git a/block/io.c b/block/io.c
index 4a7a969..2fb89f2 100644
--- a/block/io.c
+++ b/block/io.c
@@ -271,16 +271,19 @@ void bdrv_drain_all(void)
     /* Always run first iteration so any pending completion BHs run */
     bool busy = true;
     BlockDriverState *bs = NULL;
+    BlockJob *job = NULL;
     GSList *aio_ctxs = NULL, *ctx;
 
-    while ((bs = bdrv_next(bs))) {
-        AioContext *aio_context = bdrv_get_aio_context(bs);
+    while ((job = block_job_next(job))) {
+        AioContext *aio_context = bdrv_get_aio_context(job->bs);
 
         aio_context_acquire(aio_context);
-        if (bs->job) {
-            block_job_pause(bs->job);
-        }
+        block_job_pause(job);
         aio_context_release(aio_context);
+    }
+
+    while ((bs = bdrv_next(bs))) {
+        AioContext *aio_context = bdrv_get_aio_context(bs);
 
         if (!aio_ctxs || !g_slist_find(aio_ctxs, aio_context)) {
             aio_ctxs = g_slist_prepend(aio_ctxs, aio_context);
@@ -309,14 +312,11 @@ void bdrv_drain_all(void)
         }
     }
 
-    bs = NULL;
-    while ((bs = bdrv_next(bs))) {
-        AioContext *aio_context = bdrv_get_aio_context(bs);
+    while ((job = block_job_next(job))) {
+        AioContext *aio_context = bdrv_get_aio_context(job->bs);
 
         aio_context_acquire(aio_context);
-        if (bs->job) {
-            block_job_resume(bs->job);
-        }
+        block_job_resume(job);
         aio_context_release(aio_context);
     }
     g_slist_free(aio_ctxs);
diff --git a/blockdev.c b/blockdev.c
index 41d7e0f..66f8515 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -3088,21 +3088,18 @@ fail:
 BlockJobInfoList *qmp_query_block_jobs(Error **errp)
 {
     BlockJobInfoList *head = NULL, **p_next = &head;
-    BlockDriverState *bs;
+    BlockJob *job;
 
-    for (bs = bdrv_next(NULL); bs; bs = bdrv_next(bs)) {
-        AioContext *aio_context = bdrv_get_aio_context(bs);
+    for (job = block_job_next(NULL); job; job = block_job_next(job)) {
+        BlockJobInfoList *elem = g_new0(BlockJobInfoList, 1);
+        AioContext *aio_context = bdrv_get_aio_context(job->bs);
 
         aio_context_acquire(aio_context);
-
-        if (bs->job) {
-            BlockJobInfoList *elem = g_new0(BlockJobInfoList, 1);
-            elem->value = block_job_query(bs->job);
-            *p_next = elem;
-            p_next = &elem->next;
-        }
-
+        elem->value = block_job_query(job);
         aio_context_release(aio_context);
+
+        *p_next = elem;
+        p_next = &elem->next;
     }
 
     return head;
diff --git a/blockjob.c b/blockjob.c
index 2755465..c46984d 100644
--- a/blockjob.c
+++ b/blockjob.c
@@ -35,6 +35,16 @@
 #include "qemu/timer.h"
 #include "qapi-event.h"
 
+static QLIST_HEAD(, BlockJob) block_jobs = QLIST_HEAD_INITIALIZER(block_jobs);
+
+BlockJob *block_job_next(BlockJob *job)
+{
+    if (!job) {
+        return QLIST_FIRST(&block_jobs);
+    }
+    return QLIST_NEXT(job, job_list);
+}
+
 void *block_job_create(const BlockJobDriver *driver, BlockDriverState *bs,
                        int64_t speed, BlockCompletionFunc *cb,
                        void *opaque, Error **errp)
@@ -73,6 +83,8 @@ void *block_job_create(const BlockJobDriver *driver, BlockDriverState *bs,
             return NULL;
         }
     }
+
+    QLIST_INSERT_HEAD(&block_jobs, job, job_list);
     return job;
 }
 
@@ -85,6 +97,7 @@ void block_job_completed(BlockJob *job, int ret)
     bs->job = NULL;
     bdrv_op_unblock_all(bs, job->blocker);
     error_free(job->blocker);
+    QLIST_REMOVE(job, job_list);
     g_free(job);
 }
 
diff --git a/include/block/blockjob.h b/include/block/blockjob.h
index 57d8ef1..5431dd2 100644
--- a/include/block/blockjob.h
+++ b/include/block/blockjob.h
@@ -102,6 +102,9 @@ struct BlockJob {
      */
     bool ready;
 
+    /** Element of the list of block jobs */
+    QLIST_ENTRY(BlockJob) job_list;
+
     /** Status that is published by the query-block-jobs QMP API */
     BlockDeviceIoStatus iostatus;
 
@@ -125,6 +128,17 @@ struct BlockJob {
 };
 
 /**
+ * block_job_next:
+ * @job: A block job, or %NULL.
+ *
+ * Get the next element from the list of block jobs after @job, or the
+ * first one if @job is %NULL.
+ *
+ * Returns the requested job, or %NULL if there are no more jobs left.
+ */
+BlockJob *block_job_next(BlockJob *job);
+
+/**
  * block_job_create:
  * @job_type: The class object for the newly-created job.
  * @bs: The block
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [Qemu-devel] [PATCH v8 02/11] block: allow block jobs in any arbitrary node
  2015-06-22 21:32 [Qemu-devel] [PATCH v8 00/11] Support streaming to an intermediate layer Alberto Garcia
  2015-06-22 21:32 ` [Qemu-devel] [PATCH v8 01/11] block: keep a list of block jobs Alberto Garcia
@ 2015-06-22 21:32 ` Alberto Garcia
  2015-06-22 21:32 ` [Qemu-devel] [PATCH v8 03/11] block: never cancel a streaming job without running stream_complete() Alberto Garcia
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 20+ messages in thread
From: Alberto Garcia @ 2015-06-22 21:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Alberto Garcia, Stefan Hajnoczi, qemu-block

Currently, block jobs can only be owned by root nodes. This patch
allows block jobs to be in any arbitrary node, by making the following
changes:

- Block jobs can now be identified by the node name of their
  BlockDriverState in addition to the device name. Since both device
  and node names live in the same namespace there's no ambiguity.

- The "device" parameter used by all commands that operate on block
  jobs can also be a node name now.

- The node name is used as a fallback to fill in the BlockJobInfo
  structure and all BLOCK_JOB_* events if there is no device name for
  that job.

Signed-off-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 block/mirror.c            |  5 +++--
 blockdev.c                | 16 ++++++++--------
 blockjob.c                | 18 ++++++++++--------
 docs/qmp/qmp-events.txt   |  8 ++++----
 include/qapi/qmp/qerror.h |  3 ---
 qapi/block-core.json      | 20 ++++++++++----------
 6 files changed, 35 insertions(+), 35 deletions(-)

diff --git a/block/mirror.c b/block/mirror.c
index 58f391a..4b36e0b 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -598,8 +598,9 @@ static void mirror_complete(BlockJob *job, Error **errp)
         return;
     }
     if (!s->synced) {
-        error_set(errp, QERR_BLOCK_JOB_NOT_READY,
-                  bdrv_get_device_name(job->bs));
+        error_setg(errp,
+                   "The active block job for device '%s' cannot be completed",
+                   bdrv_get_device_name(job->bs));
         return;
     }
 
diff --git a/blockdev.c b/blockdev.c
index 66f8515..f3c2a01 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -2828,32 +2828,32 @@ out:
     aio_context_release(aio_context);
 }
 
-/* Get the block job for a given device name and acquire its AioContext */
-static BlockJob *find_block_job(const char *device, AioContext **aio_context,
+/* Get the block job for a given device or node name
+ * and acquire its AioContext */
+static BlockJob *find_block_job(const char *device_or_node,
+                                AioContext **aio_context,
                                 Error **errp)
 {
-    BlockBackend *blk;
     BlockDriverState *bs;
 
-    blk = blk_by_name(device);
-    if (!blk) {
+    bs = bdrv_lookup_bs(device_or_node, device_or_node, errp);
+    if (!bs) {
         goto notfound;
     }
-    bs = blk_bs(blk);
 
     *aio_context = bdrv_get_aio_context(bs);
     aio_context_acquire(*aio_context);
 
     if (!bs->job) {
         aio_context_release(*aio_context);
+        error_set(errp, ERROR_CLASS_DEVICE_NOT_ACTIVE,
+              "No active block job on node '%s'", device_or_node);
         goto notfound;
     }
 
     return bs->job;
 
 notfound:
-    error_set(errp, ERROR_CLASS_DEVICE_NOT_ACTIVE,
-              "No active block job on device '%s'", device);
     *aio_context = NULL;
     return NULL;
 }
diff --git a/blockjob.c b/blockjob.c
index c46984d..96471c6 100644
--- a/blockjob.c
+++ b/blockjob.c
@@ -52,7 +52,8 @@ void *block_job_create(const BlockJobDriver *driver, BlockDriverState *bs,
     BlockJob *job;
 
     if (bs->job) {
-        error_set(errp, QERR_DEVICE_IN_USE, bdrv_get_device_name(bs));
+        error_setg(errp, "Node '%s' is in use",
+                   bdrv_get_device_or_node_name(bs));
         return NULL;
     }
     bdrv_ref(bs);
@@ -121,8 +122,9 @@ void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
 void block_job_complete(BlockJob *job, Error **errp)
 {
     if (job->pause_count || job->cancelled || !job->driver->complete) {
-        error_set(errp, QERR_BLOCK_JOB_NOT_READY,
-                  bdrv_get_device_name(job->bs));
+        error_setg(errp,
+                   "The active block job for node '%s' cannot be completed",
+                   bdrv_get_device_or_node_name(job->bs));
         return;
     }
 
@@ -277,7 +279,7 @@ BlockJobInfo *block_job_query(BlockJob *job)
 {
     BlockJobInfo *info = g_new0(BlockJobInfo, 1);
     info->type      = g_strdup(BlockJobType_lookup[job->driver->job_type]);
-    info->device    = g_strdup(bdrv_get_device_name(job->bs));
+    info->device    = g_strdup(bdrv_get_device_or_node_name(job->bs));
     info->len       = job->len;
     info->busy      = job->busy;
     info->paused    = job->pause_count > 0;
@@ -299,7 +301,7 @@ static void block_job_iostatus_set_err(BlockJob *job, int error)
 void block_job_event_cancelled(BlockJob *job)
 {
     qapi_event_send_block_job_cancelled(job->driver->job_type,
-                                        bdrv_get_device_name(job->bs),
+                                        bdrv_get_device_or_node_name(job->bs),
                                         job->len,
                                         job->offset,
                                         job->speed,
@@ -309,7 +311,7 @@ void block_job_event_cancelled(BlockJob *job)
 void block_job_event_completed(BlockJob *job, const char *msg)
 {
     qapi_event_send_block_job_completed(job->driver->job_type,
-                                        bdrv_get_device_name(job->bs),
+                                        bdrv_get_device_or_node_name(job->bs),
                                         job->len,
                                         job->offset,
                                         job->speed,
@@ -323,7 +325,7 @@ void block_job_event_ready(BlockJob *job)
     job->ready = true;
 
     qapi_event_send_block_job_ready(job->driver->job_type,
-                                    bdrv_get_device_name(job->bs),
+                                    bdrv_get_device_or_node_name(job->bs),
                                     job->len,
                                     job->offset,
                                     job->speed, &error_abort);
@@ -352,7 +354,7 @@ BlockErrorAction block_job_error_action(BlockJob *job, BlockDriverState *bs,
     default:
         abort();
     }
-    qapi_event_send_block_job_error(bdrv_get_device_name(job->bs),
+    qapi_event_send_block_job_error(bdrv_get_device_or_node_name(job->bs),
                                     is_read ? IO_OPERATION_TYPE_READ :
                                     IO_OPERATION_TYPE_WRITE,
                                     action, &error_abort);
diff --git a/docs/qmp/qmp-events.txt b/docs/qmp/qmp-events.txt
index 4c13d48..725f860 100644
--- a/docs/qmp/qmp-events.txt
+++ b/docs/qmp/qmp-events.txt
@@ -90,7 +90,7 @@ Data:
 
 - "type":     Job type (json-string; "stream" for image streaming
                                      "commit" for block commit)
-- "device":   Device name (json-string)
+- "device":   Device name, or node name if not present (json-string)
 - "len":      Maximum progress value (json-int)
 - "offset":   Current progress value (json-int)
               On success this is equal to len.
@@ -114,7 +114,7 @@ Data:
 
 - "type":     Job type (json-string; "stream" for image streaming
                                      "commit" for block commit)
-- "device":   Device name (json-string)
+- "device":   Device name, or node name if not present (json-string)
 - "len":      Maximum progress value (json-int)
 - "offset":   Current progress value (json-int)
               On success this is equal to len.
@@ -141,7 +141,7 @@ Emitted when a block job encounters an error.
 
 Data:
 
-- "device": device name (json-string)
+- "device": device name, or node name if not present (json-string)
 - "operation": I/O operation (json-string, "read" or "write")
 - "action": action that has been taken, it's one of the following (json-string):
     "ignore": error has been ignored, the job may fail later
@@ -165,7 +165,7 @@ Data:
 
 - "type":     Job type (json-string; "stream" for image streaming
                                      "commit" for block commit)
-- "device":   Device name (json-string)
+- "device":   Device name, or node name if not present (json-string)
 - "len":      Maximum progress value (json-int)
 - "offset":   Current progress value (json-int)
               On success this is equal to len.
diff --git a/include/qapi/qmp/qerror.h b/include/qapi/qmp/qerror.h
index e567339..4ba442e 100644
--- a/include/qapi/qmp/qerror.h
+++ b/include/qapi/qmp/qerror.h
@@ -37,9 +37,6 @@ void qerror_report_err(Error *err);
 #define QERR_BASE_NOT_FOUND \
     ERROR_CLASS_GENERIC_ERROR, "Base '%s' not found"
 
-#define QERR_BLOCK_JOB_NOT_READY \
-    ERROR_CLASS_GENERIC_ERROR, "The active block job for device '%s' cannot be completed"
-
 #define QERR_BUS_NO_HOTPLUG \
     ERROR_CLASS_GENERIC_ERROR, "Bus '%s' does not support hotplugging"
 
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 766d690..29cdd72 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -568,7 +568,7 @@
 #
 # @type: the job type ('stream' for image streaming)
 #
-# @device: the block device name
+# @device: the block device name, or node name if not present
 #
 # @len: the maximum progress value
 #
@@ -1190,7 +1190,7 @@
 #
 # Throttling can be disabled by setting the speed to 0.
 #
-# @device: the device name
+# @device: the device or node name of the owner of the block job.
 #
 # @speed:  the maximum speed, in bytes per second, or 0 for unlimited.
 #          Defaults to 0.
@@ -1221,7 +1221,7 @@
 # operation can be started at a later time to finish copying all data from the
 # backing file.
 #
-# @device: the device name
+# @device: the device or node name of the owner of the block job.
 #
 # @force: #optional whether to allow cancellation of a paused job (default
 #         false).  Since 1.3.
@@ -1247,7 +1247,7 @@
 # the operation is actually paused.  Cancelling a paused job automatically
 # resumes it.
 #
-# @device: the device name
+# @device: the device or node name of the owner of the block job.
 #
 # Returns: Nothing on success
 #          If no background operation is active on this device, DeviceNotActive
@@ -1267,7 +1267,7 @@
 #
 # This command also clears the error status of the job.
 #
-# @device: the device name
+# @device: the device or node name of the owner of the block job.
 #
 # Returns: Nothing on success
 #          If no background operation is active on this device, DeviceNotActive
@@ -1293,7 +1293,7 @@
 #
 # A cancelled or paused job cannot be completed.
 #
-# @device: the device name
+# @device: the device or node name of the owner of the block job.
 #
 # Returns: Nothing on success
 #          If no background operation is active on this device, DeviceNotActive
@@ -1951,7 +1951,7 @@
 #
 # @type: job type
 #
-# @device: device name
+# @device: device name, or node name if not present
 #
 # @len: maximum progress value
 #
@@ -1982,7 +1982,7 @@
 #
 # @type: job type
 #
-# @device: device name
+# @device: device name, or node name if not present
 #
 # @len: maximum progress value
 #
@@ -2005,7 +2005,7 @@
 #
 # Emitted when a block job encounters an error
 #
-# @device: device name
+# @device: device name, or node name if not present
 #
 # @operation: I/O operation
 #
@@ -2025,7 +2025,7 @@
 #
 # @type: job type
 #
-# @device: device name
+# @device: device name, or node name if not present
 #
 # @len: maximum progress value
 #
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [Qemu-devel] [PATCH v8 03/11] block: never cancel a streaming job without running stream_complete()
  2015-06-22 21:32 [Qemu-devel] [PATCH v8 00/11] Support streaming to an intermediate layer Alberto Garcia
  2015-06-22 21:32 ` [Qemu-devel] [PATCH v8 01/11] block: keep a list of block jobs Alberto Garcia
  2015-06-22 21:32 ` [Qemu-devel] [PATCH v8 02/11] block: allow block jobs in any arbitrary node Alberto Garcia
@ 2015-06-22 21:32 ` Alberto Garcia
  2015-10-16  8:35   ` Stefan Hajnoczi
  2015-06-22 21:32 ` [Qemu-devel] [PATCH v8 04/11] block: Support streaming to an intermediate layer Alberto Garcia
                   ` (8 subsequent siblings)
  11 siblings, 1 reply; 20+ messages in thread
From: Alberto Garcia @ 2015-06-22 21:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Alberto Garcia, Stefan Hajnoczi, qemu-block

We need to call stream_complete() in order to do all the necessary
clean-ups, even if there's an early failure. At the moment it's only
useful to make sure that s->backing_file_str is not leaked, but it
will become more important as we introduce support for streaming to
any intermediate node.

Signed-off-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
 block/stream.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/block/stream.c b/block/stream.c
index a628901..37bfd8b 100644
--- a/block/stream.c
+++ b/block/stream.c
@@ -114,21 +114,21 @@ static void coroutine_fn stream_run(void *opaque)
     StreamCompleteData *data;
     BlockDriverState *bs = s->common.bs;
     BlockDriverState *base = s->base;
-    int64_t sector_num, end;
+    int64_t sector_num = 0;
+    int64_t end = -1;
     int error = 0;
     int ret = 0;
     int n = 0;
     void *buf;
 
     if (!bs->backing_hd) {
-        block_job_completed(&s->common, 0);
-        return;
+        goto out;
     }
 
     s->common.len = bdrv_getlength(bs);
     if (s->common.len < 0) {
-        block_job_completed(&s->common, s->common.len);
-        return;
+        ret = s->common.len;
+        goto out;
     }
 
     end = s->common.len >> BDRV_SECTOR_BITS;
@@ -215,6 +215,7 @@ wait:
 
     qemu_vfree(buf);
 
+out:
     /* Modify backing chain and close BDSes in main loop */
     data = g_malloc(sizeof(*data));
     data->ret = ret;
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [Qemu-devel] [PATCH v8 04/11] block: Support streaming to an intermediate layer
  2015-06-22 21:32 [Qemu-devel] [PATCH v8 00/11] Support streaming to an intermediate layer Alberto Garcia
                   ` (2 preceding siblings ...)
  2015-06-22 21:32 ` [Qemu-devel] [PATCH v8 03/11] block: never cancel a streaming job without running stream_complete() Alberto Garcia
@ 2015-06-22 21:32 ` Alberto Garcia
  2015-06-22 21:32 ` [Qemu-devel] [PATCH v8 05/11] block: Add QMP support for " Alberto Garcia
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 20+ messages in thread
From: Alberto Garcia @ 2015-06-22 21:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Alberto Garcia, Stefan Hajnoczi, qemu-block

This makes sure that the image we are steaming into is open in
read-write mode during the operation.

Operation blockers are also set in all intermediate nodes, since they
will be removed from the chain afterwards.

Finally, this also unblocks the stream operation in backing files.

Signed-off-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
 block.c        |  4 +++-
 block/stream.c | 33 +++++++++++++++++++++++++++++++++
 2 files changed, 36 insertions(+), 1 deletion(-)

diff --git a/block.c b/block.c
index 0ffb855..bc5d002 100644
--- a/block.c
+++ b/block.c
@@ -1124,9 +1124,11 @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd)
             backing_hd->drv ? backing_hd->drv->format_name : "");
 
     bdrv_op_block_all(bs->backing_hd, bs->backing_blocker);
-    /* Otherwise we won't be able to commit due to check in bdrv_commit */
+    /* Otherwise we won't be able to commit or stream */
     bdrv_op_unblock(bs->backing_hd, BLOCK_OP_TYPE_COMMIT_TARGET,
                     bs->backing_blocker);
+    bdrv_op_unblock(bs->backing_hd, BLOCK_OP_TYPE_STREAM,
+                    bs->backing_blocker);
 out:
     bdrv_refresh_limits(bs, NULL);
 }
diff --git a/block/stream.c b/block/stream.c
index 37bfd8b..8ba5a24 100644
--- a/block/stream.c
+++ b/block/stream.c
@@ -33,6 +33,8 @@ typedef struct StreamBlockJob {
     BlockDriverState *base;
     BlockdevOnError on_error;
     char *backing_file_str;
+    int bs_flags;
+    Error *blocker;
 } StreamBlockJob;
 
 static int coroutine_fn stream_populate(BlockDriverState *bs,
@@ -89,6 +91,13 @@ static void stream_complete(BlockJob *job, void *opaque)
     StreamBlockJob *s = container_of(job, StreamBlockJob, common);
     StreamCompleteData *data = opaque;
     BlockDriverState *base = s->base;
+    BlockDriverState *bs;
+
+    /* Remove all blockers set in stream_start() */
+    for (bs = job->bs->backing_hd; bs && bs != s->base; bs = bs->backing_hd) {
+        bdrv_op_unblock_all(bs, s->blocker);
+    }
+    error_free(s->blocker);
 
     if (!block_job_is_cancelled(&s->common) && data->reached_end &&
         data->ret == 0) {
@@ -103,6 +112,11 @@ static void stream_complete(BlockJob *job, void *opaque)
         close_unused_images(job->bs, base, base_id);
     }
 
+    /* Reopen the image back in read-only mode if necessary */
+    if (s->bs_flags != bdrv_get_flags(job->bs)) {
+        bdrv_reopen(job->bs, s->bs_flags, NULL);
+    }
+
     g_free(s->backing_file_str);
     block_job_completed(&s->common, data->ret);
     g_free(data);
@@ -246,7 +260,9 @@ void stream_start(BlockDriverState *bs, BlockDriverState *base,
                   BlockCompletionFunc *cb,
                   void *opaque, Error **errp)
 {
+    BlockDriverState *iter;
     StreamBlockJob *s;
+    int orig_bs_flags;
 
     if ((on_error == BLOCKDEV_ON_ERROR_STOP ||
          on_error == BLOCKDEV_ON_ERROR_ENOSPC) &&
@@ -255,13 +271,30 @@ void stream_start(BlockDriverState *bs, BlockDriverState *base,
         return;
     }
 
+    /* Make sure that the image is opened in read-write mode */
+    orig_bs_flags = bdrv_get_flags(bs);
+    if (!(orig_bs_flags & BDRV_O_RDWR)) {
+        if (bdrv_reopen(bs, orig_bs_flags | BDRV_O_RDWR, errp) != 0) {
+            return;
+        }
+    }
+
     s = block_job_create(&stream_job_driver, bs, speed, cb, opaque, errp);
     if (!s) {
         return;
     }
 
+    /* Block all intermediate nodes between bs and base, because they
+     * will disappear from the chain after this operation */
+    error_setg(&s->blocker, "blocked by the block-stream operation in '%s'",
+               bdrv_get_device_or_node_name(bs));
+    for (iter = bs->backing_hd; iter && iter != base; iter = iter->backing_hd) {
+        bdrv_op_block_all(iter, s->blocker);
+    }
+
     s->base = base;
     s->backing_file_str = g_strdup(backing_file_str);
+    s->bs_flags = orig_bs_flags;
 
     s->on_error = on_error;
     s->common.co = qemu_coroutine_create(stream_run);
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [Qemu-devel] [PATCH v8 05/11] block: Add QMP support for streaming to an intermediate layer
  2015-06-22 21:32 [Qemu-devel] [PATCH v8 00/11] Support streaming to an intermediate layer Alberto Garcia
                   ` (3 preceding siblings ...)
  2015-06-22 21:32 ` [Qemu-devel] [PATCH v8 04/11] block: Support streaming to an intermediate layer Alberto Garcia
@ 2015-06-22 21:32 ` Alberto Garcia
  2015-06-22 21:32 ` [Qemu-devel] [PATCH v8 06/11] docs: Document how to stream " Alberto Garcia
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 20+ messages in thread
From: Alberto Garcia @ 2015-06-22 21:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Alberto Garcia, Stefan Hajnoczi, qemu-block

This patch makes the 'device' parameter of the 'block-stream' command
accept a node name as well as a device name.

In addition to that, operation blockers will be checked in all
intermediate nodes between the top and the base node.

Since qmp_block_stream() now uses the error from bdrv_lookup_bs() and
no longer returns DeviceNotFound, iotest 030 is updated to expect
GenericError instead.

Signed-off-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 blockdev.c             | 20 ++++++++++----------
 qapi/block-core.json   | 10 +++++++---
 tests/qemu-iotests/030 |  2 +-
 3 files changed, 18 insertions(+), 14 deletions(-)

diff --git a/blockdev.c b/blockdev.c
index f3c2a01..c00fb29 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -2278,8 +2278,7 @@ void qmp_block_stream(const char *device,
                       bool has_on_error, BlockdevOnError on_error,
                       Error **errp)
 {
-    BlockBackend *blk;
-    BlockDriverState *bs;
+    BlockDriverState *bs, *iter;
     BlockDriverState *base_bs = NULL;
     AioContext *aio_context;
     Error *local_err = NULL;
@@ -2289,20 +2288,14 @@ void qmp_block_stream(const char *device,
         on_error = BLOCKDEV_ON_ERROR_REPORT;
     }
 
-    blk = blk_by_name(device);
-    if (!blk) {
-        error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+    bs = bdrv_lookup_bs(device, device, errp);
+    if (!bs) {
         return;
     }
-    bs = blk_bs(blk);
 
     aio_context = bdrv_get_aio_context(bs);
     aio_context_acquire(aio_context);
 
-    if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_STREAM, errp)) {
-        goto out;
-    }
-
     if (has_base) {
         base_bs = bdrv_find_backing_image(bs, base);
         if (base_bs == NULL) {
@@ -2313,6 +2306,13 @@ void qmp_block_stream(const char *device,
         base_name = base;
     }
 
+    /* Check for op blockers in the whole chain between bs and base */
+    for (iter = bs; iter && iter != base_bs; iter = iter->backing_hd) {
+        if (bdrv_op_is_blocked(iter, BLOCK_OP_TYPE_STREAM, errp)) {
+            goto out;
+        }
+    }
+
     /* if we are streaming the entire chain, the result will have no backing
      * file, and specifying one is therefore an error */
     if (base_bs == NULL && has_backing_file) {
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 29cdd72..cec5bed 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1139,6 +1139,10 @@
 # with query-block-jobs.  The operation can be stopped before it has completed
 # using the block-job-cancel command.
 #
+# The node that receives the data is called the top image, can be located
+# in any part of the whole chain and can be specified using its device
+# or node name.
+#
 # If a base file is specified then sectors are not copied from that base file and
 # its backing chain.  When streaming completes the image file will have the base
 # file as its backing file.  This can be used to stream a subset of the backing
@@ -1147,12 +1151,12 @@
 # On successful completion the image file is updated to drop the backing file
 # and the BLOCK_JOB_COMPLETED event is emitted.
 #
-# @device: the device name
+# @device: the device or node name of the top image
 #
 # @base:   #optional the common backing file name
 #
-# @backing-file: #optional The backing file string to write into the active
-#                          layer. This filename is not validated.
+# @backing-file: #optional The backing file string to write into the top
+#                          image. This filename is not validated.
 #
 #                          If a pathname string is such that it cannot be
 #                          resolved by QEMU, that means that subsequent QMP or
diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030
index 952a524..7ca9b25 100755
--- a/tests/qemu-iotests/030
+++ b/tests/qemu-iotests/030
@@ -107,7 +107,7 @@ class TestSingleDrive(iotests.QMPTestCase):
 
     def test_device_not_found(self):
         result = self.vm.qmp('block-stream', device='nonexistent')
-        self.assert_qmp(result, 'error/class', 'DeviceNotFound')
+        self.assert_qmp(result, 'error/class', 'GenericError')
 
 
 class TestSmallerBackingFile(iotests.QMPTestCase):
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [Qemu-devel] [PATCH v8 06/11] docs: Document how to stream to an intermediate layer
  2015-06-22 21:32 [Qemu-devel] [PATCH v8 00/11] Support streaming to an intermediate layer Alberto Garcia
                   ` (4 preceding siblings ...)
  2015-06-22 21:32 ` [Qemu-devel] [PATCH v8 05/11] block: Add QMP support for " Alberto Garcia
@ 2015-06-22 21:32 ` Alberto Garcia
  2015-06-22 21:32 ` [Qemu-devel] [PATCH v8 07/11] qemu-iotests: fix test_stream_partial() Alberto Garcia
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 20+ messages in thread
From: Alberto Garcia @ 2015-06-22 21:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Alberto Garcia, Stefan Hajnoczi, qemu-block

Signed-off-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 docs/live-block-ops.txt | 31 ++++++++++++++++++++-----------
 1 file changed, 20 insertions(+), 11 deletions(-)

diff --git a/docs/live-block-ops.txt b/docs/live-block-ops.txt
index a257087..a05d869 100644
--- a/docs/live-block-ops.txt
+++ b/docs/live-block-ops.txt
@@ -10,9 +10,9 @@ Snapshot live merge
 Given a snapshot chain, described in this document in the following
 format:
 
-[A] -> [B] -> [C] -> [D]
+[A] <- [B] <- [C] <- [D] <- [E]
 
-Where the rightmost object ([D] in the example) described is the current
+Where the rightmost object ([E] in the example) described is the current
 image which the guest OS has write access to. To the left of it is its base
 image, and so on accordingly until the leftmost image, which has no
 base.
@@ -21,11 +21,14 @@ The snapshot live merge operation transforms such a chain into a
 smaller one with fewer elements, such as this transformation relative
 to the first example:
 
-[A] -> [D]
+[A] <- [E]
 
-Currently only forward merge with target being the active image is
-supported, that is, data copy is performed in the right direction with
-destination being the rightmost image.
+Data is copied in the right direction with destination being the
+rightmost image, but any other intermediate image can be specified
+instead. In this example data is copied from [C] into [D], so [D] can
+be backed by [B]:
+
+[A] <- [B] <- [D] <- [E]
 
 The operation is implemented in QEMU through image streaming facilities.
 
@@ -35,14 +38,20 @@ streaming operation completes it raises a QMP event. 'block_stream'
 copies data from the backing file(s) into the active image. When finished,
 it adjusts the backing file pointer.
 
-The 'base' parameter specifies an image which data need not be streamed from.
-This image will be used as the backing file for the active image when the
-operation is finished.
+The 'base' parameter specifies an image which data need not be
+streamed from. This image will be used as the backing file for the
+destination image when the operation is finished.
 
-In the example above, the command would be:
+In the first example above, the command would be:
 
-(qemu) block_stream virtio0 A
+(qemu) block_stream virtio0 file-A.img
 
+In order to specify a destination image different from the active
+(rightmost) one we can use its (previously set) node name instead.
+
+In the second example above, the command would be:
+
+(qemu) block_stream node-D file-B.img
 
 Live block copy
 ===============
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [Qemu-devel] [PATCH v8 07/11] qemu-iotests: fix test_stream_partial()
  2015-06-22 21:32 [Qemu-devel] [PATCH v8 00/11] Support streaming to an intermediate layer Alberto Garcia
                   ` (5 preceding siblings ...)
  2015-06-22 21:32 ` [Qemu-devel] [PATCH v8 06/11] docs: Document how to stream " Alberto Garcia
@ 2015-06-22 21:32 ` Alberto Garcia
  2015-06-22 21:32 ` [Qemu-devel] [PATCH v8 08/11] qemu-iotests: add no-op streaming test Alberto Garcia
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 20+ messages in thread
From: Alberto Garcia @ 2015-06-22 21:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Alberto Garcia, Stefan Hajnoczi, qemu-block

This test is streaming to the top layer using the intermediate image
as the base. This is a mistake since block-stream never copies data
from the base image and its backing chain, so this is effectively a
no-op.

In addition to fixing the base parameter, this patch also writes some
data to the intermediate image before the test, so there's something
to copy and the test is meaningful.

Signed-off-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
 tests/qemu-iotests/030 | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030
index 7ca9b25..6e6cb5a 100755
--- a/tests/qemu-iotests/030
+++ b/tests/qemu-iotests/030
@@ -35,6 +35,7 @@ class TestSingleDrive(iotests.QMPTestCase):
         qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, mid_img)
         qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % mid_img, test_img)
         qemu_io('-f', 'raw', '-c', 'write -P 0x1 0 512', backing_img)
+        qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0x1 524288 512', mid_img)
         self.vm = iotests.VM().add_drive("blkdebug::" + test_img)
         self.vm.launch()
 
@@ -93,7 +94,7 @@ class TestSingleDrive(iotests.QMPTestCase):
     def test_stream_partial(self):
         self.assert_no_active_block_jobs()
 
-        result = self.vm.qmp('block-stream', device='drive0', base=mid_img)
+        result = self.vm.qmp('block-stream', device='drive0', base=backing_img)
         self.assert_qmp(result, 'return', {})
 
         self.wait_until_completed()
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [Qemu-devel] [PATCH v8 08/11] qemu-iotests: add no-op streaming test
  2015-06-22 21:32 [Qemu-devel] [PATCH v8 00/11] Support streaming to an intermediate layer Alberto Garcia
                   ` (6 preceding siblings ...)
  2015-06-22 21:32 ` [Qemu-devel] [PATCH v8 07/11] qemu-iotests: fix test_stream_partial() Alberto Garcia
@ 2015-06-22 21:32 ` Alberto Garcia
  2015-06-22 21:32 ` [Qemu-devel] [PATCH v8 09/11] qemu-iotests: test streaming to an intermediate layer Alberto Garcia
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 20+ messages in thread
From: Alberto Garcia @ 2015-06-22 21:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Alberto Garcia, Stefan Hajnoczi, qemu-block

This patch tests that in a partial block-stream operation, no data is
ever copied from the base image.

Signed-off-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
 tests/qemu-iotests/030     | 18 ++++++++++++++++++
 tests/qemu-iotests/030.out |  4 ++--
 2 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030
index 6e6cb5a..bc53885 100755
--- a/tests/qemu-iotests/030
+++ b/tests/qemu-iotests/030
@@ -91,6 +91,24 @@ class TestSingleDrive(iotests.QMPTestCase):
                          qemu_io('-f', iotests.imgfmt, '-c', 'map', test_img),
                          'image file map does not match backing file after streaming')
 
+    def test_stream_no_op(self):
+        self.assert_no_active_block_jobs()
+
+        # The image map is empty before the operation
+        empty_map = qemu_io('-f', iotests.imgfmt, '-c', 'map', test_img)
+
+        # This is a no-op: no data should ever be copied from the base image
+        result = self.vm.qmp('block-stream', device='drive0', base=mid_img)
+        self.assert_qmp(result, 'return', {})
+
+        self.wait_until_completed()
+
+        self.assert_no_active_block_jobs()
+        self.vm.shutdown()
+
+        self.assertEqual(qemu_io('-f', iotests.imgfmt, '-c', 'map', test_img),
+                         empty_map, 'image file map changed after a no-op')
+
     def test_stream_partial(self):
         self.assert_no_active_block_jobs()
 
diff --git a/tests/qemu-iotests/030.out b/tests/qemu-iotests/030.out
index fa16b5c..6323079 100644
--- a/tests/qemu-iotests/030.out
+++ b/tests/qemu-iotests/030.out
@@ -1,5 +1,5 @@
-.............
+..............
 ----------------------------------------------------------------------
-Ran 13 tests
+Ran 14 tests
 
 OK
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [Qemu-devel] [PATCH v8 09/11] qemu-iotests: test streaming to an intermediate layer
  2015-06-22 21:32 [Qemu-devel] [PATCH v8 00/11] Support streaming to an intermediate layer Alberto Garcia
                   ` (7 preceding siblings ...)
  2015-06-22 21:32 ` [Qemu-devel] [PATCH v8 08/11] qemu-iotests: add no-op streaming test Alberto Garcia
@ 2015-06-22 21:32 ` Alberto Garcia
  2015-06-22 21:32 ` [Qemu-devel] [PATCH v8 10/11] qemu-iotests: test block-stream operations in parallel Alberto Garcia
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 20+ messages in thread
From: Alberto Garcia @ 2015-06-22 21:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Alberto Garcia, Stefan Hajnoczi, qemu-block

This adds test_stream_intermediate(), similar to test_stream() but
streams to the intermediate image instead.

Signed-off-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
 tests/qemu-iotests/030     | 18 +++++++++++++++++-
 tests/qemu-iotests/030.out |  4 ++--
 2 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030
index bc53885..0927457 100755
--- a/tests/qemu-iotests/030
+++ b/tests/qemu-iotests/030
@@ -36,7 +36,8 @@ class TestSingleDrive(iotests.QMPTestCase):
         qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % mid_img, test_img)
         qemu_io('-f', 'raw', '-c', 'write -P 0x1 0 512', backing_img)
         qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0x1 524288 512', mid_img)
-        self.vm = iotests.VM().add_drive("blkdebug::" + test_img)
+        opts = "backing.node-name=mid"
+        self.vm = iotests.VM().add_drive("blkdebug::" + test_img, opts)
         self.vm.launch()
 
     def tearDown(self):
@@ -60,6 +61,21 @@ class TestSingleDrive(iotests.QMPTestCase):
                          qemu_io('-f', iotests.imgfmt, '-c', 'map', test_img),
                          'image file map does not match backing file after streaming')
 
+    def test_stream_intermediate(self):
+        self.assert_no_active_block_jobs()
+
+        result = self.vm.qmp('block-stream', device='mid')
+        self.assert_qmp(result, 'return', {})
+
+        self.wait_until_completed(drive='mid')
+
+        self.assert_no_active_block_jobs()
+        self.vm.shutdown()
+
+        self.assertEqual(qemu_io('-f', 'raw', '-c', 'map', backing_img),
+                         qemu_io('-f', iotests.imgfmt, '-c', 'map', mid_img),
+                         'image file map does not match backing file after streaming')
+
     def test_stream_pause(self):
         self.assert_no_active_block_jobs()
 
diff --git a/tests/qemu-iotests/030.out b/tests/qemu-iotests/030.out
index 6323079..96961ed 100644
--- a/tests/qemu-iotests/030.out
+++ b/tests/qemu-iotests/030.out
@@ -1,5 +1,5 @@
-..............
+...............
 ----------------------------------------------------------------------
-Ran 14 tests
+Ran 15 tests
 
 OK
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [Qemu-devel] [PATCH v8 10/11] qemu-iotests: test block-stream operations in parallel
  2015-06-22 21:32 [Qemu-devel] [PATCH v8 00/11] Support streaming to an intermediate layer Alberto Garcia
                   ` (8 preceding siblings ...)
  2015-06-22 21:32 ` [Qemu-devel] [PATCH v8 09/11] qemu-iotests: test streaming to an intermediate layer Alberto Garcia
@ 2015-06-22 21:32 ` Alberto Garcia
  2015-06-22 21:32 ` [Qemu-devel] [PATCH v8 11/11] qemu-iotests: test overlapping block-stream operations Alberto Garcia
  2015-06-23 15:36 ` [Qemu-devel] [PATCH v8 00/11] Support streaming to an intermediate layer Stefan Hajnoczi
  11 siblings, 0 replies; 20+ messages in thread
From: Alberto Garcia @ 2015-06-22 21:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Alberto Garcia, Stefan Hajnoczi, qemu-block

This test case checks that it's possible to launch several stream
operations in parallel in the same snapshot chain, each one involving
a different set of nodes.

Signed-off-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
 tests/qemu-iotests/030     | 80 ++++++++++++++++++++++++++++++++++++++++++++++
 tests/qemu-iotests/030.out |  4 +--
 2 files changed, 82 insertions(+), 2 deletions(-)

diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030
index 0927457..c199cef 100755
--- a/tests/qemu-iotests/030
+++ b/tests/qemu-iotests/030
@@ -145,6 +145,86 @@ class TestSingleDrive(iotests.QMPTestCase):
         self.assert_qmp(result, 'error/class', 'GenericError')
 
 
+class TestParallelOps(iotests.QMPTestCase):
+    image_len = 2 * 1024 * 1024 # MB
+    num_ops = 4 # Number of parallel block-stream operations
+    num_imgs = num_ops * 2 + 1
+    imgs = []
+
+    def setUp(self):
+        opts = []
+        self.imgs = []
+
+        # Initialize file names and command-line options
+        for i in range(self.num_imgs):
+            img_depth = self.num_imgs - i - 1
+            opts.append("backing." * img_depth + "node-name=node%d" % i)
+            self.imgs.append(os.path.join(iotests.test_dir, 'img-%d.img' % i))
+
+        # Create all images
+        iotests.create_image(self.imgs[0], self.image_len)
+        for i in range(1, self.num_imgs):
+            qemu_img('create', '-f', iotests.imgfmt,
+                     '-o', 'backing_file=%s' % self.imgs[i-1], self.imgs[i])
+
+        # Put data into the images we are copying data from
+        for i in range(1, self.num_imgs, 2):
+            qemu_io('-f', iotests.imgfmt,
+                    '-c', 'write -P %d %d 128K' % (i, i*128*1024), self.imgs[i])
+
+        # Attach the drive to the VM
+        self.vm = iotests.VM()
+        self.vm.add_drive("blkdebug::" + self.imgs[-1], ','.join(opts))
+        self.vm.launch()
+
+    def tearDown(self):
+        self.vm.shutdown()
+        for img in self.imgs:
+            os.remove(img)
+
+    # Test that it's possible to run several block-stream operations
+    # in parallel in the same snapshot chain
+    def test_stream_parallel(self):
+        self.assert_no_active_block_jobs()
+
+        # Check that the maps don't match before the streaming operations
+        for i in range(2, self.num_imgs, 2):
+            self.assertNotEqual(qemu_io('-f', iotests.imgfmt, '-c', 'map', self.imgs[i]),
+                                qemu_io('-f', iotests.imgfmt, '-c', 'map', self.imgs[i-1]),
+                                'image file map matches backing file before streaming')
+
+        # Create all streaming jobs
+        pending_jobs = []
+        for i in range(2, self.num_imgs, 2):
+            node_name = 'node%d' % i
+            pending_jobs.append(node_name)
+            result = self.vm.qmp('block-stream', device=node_name, base=self.imgs[i-2], speed=32768)
+            self.assert_qmp(result, 'return', {})
+
+        # The block job on the active image is always referenced by
+        # its device name. Therefore we have to replace the node name
+        # with the device name in the list of pending jobs
+        pending_jobs.pop()
+        pending_jobs.append("drive0")
+
+        # Wait for all jobs to be finished.
+        while len(pending_jobs) > 0:
+            for event in self.vm.get_qmp_events(wait=True):
+                if event['event'] == 'BLOCK_JOB_COMPLETED':
+                    node_name = self.dictpath(event, 'data/device')
+                    self.assertTrue(node_name in pending_jobs)
+                    self.assert_qmp_absent(event, 'data/error')
+                    pending_jobs.remove(node_name)
+
+        self.assert_no_active_block_jobs()
+        self.vm.shutdown()
+
+        # Check that all maps match now
+        for i in range(2, self.num_imgs, 2):
+            self.assertEqual(qemu_io('-f', iotests.imgfmt, '-c', 'map', self.imgs[i]),
+                             qemu_io('-f', iotests.imgfmt, '-c', 'map', self.imgs[i-1]),
+                             'image file map does not match backing file after streaming')
+
 class TestSmallerBackingFile(iotests.QMPTestCase):
     backing_len = 1 * 1024 * 1024 # MB
     image_len = 2 * backing_len
diff --git a/tests/qemu-iotests/030.out b/tests/qemu-iotests/030.out
index 96961ed..b6f2576 100644
--- a/tests/qemu-iotests/030.out
+++ b/tests/qemu-iotests/030.out
@@ -1,5 +1,5 @@
-...............
+................
 ----------------------------------------------------------------------
-Ran 15 tests
+Ran 16 tests
 
 OK
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [Qemu-devel] [PATCH v8 11/11] qemu-iotests: test overlapping block-stream operations
  2015-06-22 21:32 [Qemu-devel] [PATCH v8 00/11] Support streaming to an intermediate layer Alberto Garcia
                   ` (9 preceding siblings ...)
  2015-06-22 21:32 ` [Qemu-devel] [PATCH v8 10/11] qemu-iotests: test block-stream operations in parallel Alberto Garcia
@ 2015-06-22 21:32 ` Alberto Garcia
  2015-06-23 15:36 ` [Qemu-devel] [PATCH v8 00/11] Support streaming to an intermediate layer Stefan Hajnoczi
  11 siblings, 0 replies; 20+ messages in thread
From: Alberto Garcia @ 2015-06-22 21:32 UTC (permalink / raw)
  To: qemu-devel; +Cc: Alberto Garcia, Stefan Hajnoczi, qemu-block

This test case checks that it's not possible to perform two
block-stream operations if there are nodes involved in both.

Signed-off-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
 tests/qemu-iotests/030     | 27 +++++++++++++++++++++++++++
 tests/qemu-iotests/030.out |  4 ++--
 2 files changed, 29 insertions(+), 2 deletions(-)

diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030
index c199cef..f898c92 100755
--- a/tests/qemu-iotests/030
+++ b/tests/qemu-iotests/030
@@ -225,6 +225,33 @@ class TestParallelOps(iotests.QMPTestCase):
                              qemu_io('-f', iotests.imgfmt, '-c', 'map', self.imgs[i-1]),
                              'image file map does not match backing file after streaming')
 
+    # Test that it's not possible to perform two block-stream
+    # operations if there are nodes involved in both.
+    def test_stream_overlapping(self):
+        self.assert_no_active_block_jobs()
+
+        # Set a speed limit to make sure that this job blocks the rest
+        result = self.vm.qmp('block-stream', device='node4', base=self.imgs[0], speed=32768)
+        self.assert_qmp(result, 'return', {})
+
+        result = self.vm.qmp('block-stream', device='node5', base=self.imgs[1])
+        self.assert_qmp(result, 'error/class', 'GenericError')
+
+        result = self.vm.qmp('block-stream', device='node3', base=self.imgs[2])
+        self.assert_qmp(result, 'error/class', 'GenericError')
+
+        result = self.vm.qmp('block-stream', device='node4')
+        self.assert_qmp(result, 'error/class', 'GenericError')
+
+        # If node4 is the active node, the id of the block job is drive0
+        if self.num_imgs == 5:
+            self.wait_until_completed(drive='drive0')
+        else:
+            self.wait_until_completed(drive='node4')
+        self.assert_no_active_block_jobs()
+
+        self.vm.shutdown()
+
 class TestSmallerBackingFile(iotests.QMPTestCase):
     backing_len = 1 * 1024 * 1024 # MB
     image_len = 2 * backing_len
diff --git a/tests/qemu-iotests/030.out b/tests/qemu-iotests/030.out
index b6f2576..52d796e 100644
--- a/tests/qemu-iotests/030.out
+++ b/tests/qemu-iotests/030.out
@@ -1,5 +1,5 @@
-................
+.................
 ----------------------------------------------------------------------
-Ran 16 tests
+Ran 17 tests
 
 OK
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] [PATCH v8 00/11] Support streaming to an intermediate layer
  2015-06-22 21:32 [Qemu-devel] [PATCH v8 00/11] Support streaming to an intermediate layer Alberto Garcia
                   ` (10 preceding siblings ...)
  2015-06-22 21:32 ` [Qemu-devel] [PATCH v8 11/11] qemu-iotests: test overlapping block-stream operations Alberto Garcia
@ 2015-06-23 15:36 ` Stefan Hajnoczi
  2015-06-23 16:09   ` Alberto Garcia
  11 siblings, 1 reply; 20+ messages in thread
From: Stefan Hajnoczi @ 2015-06-23 15:36 UTC (permalink / raw)
  To: Alberto Garcia; +Cc: qemu-devel, qemu-block

[-- Attachment #1: Type: text/plain, Size: 1430 bytes --]

On Tue, Jun 23, 2015 at 12:32:15AM +0300, Alberto Garcia wrote:
> v8:
> - Rebased on top of Stefan's block branch (0a35bce416)
> - The loop that pauses the block jobs in bdrv_drain_all() is now split
>   in two: one that iterates the list of block jobs to stop them, and
>   one that iterates the root bds in order to get the aio contexts.

Did you try qemu-iotests?  I'm still getting:

030 11s ... [failed, exit status 1] - output mismatch (see 030.out.bad)
--- 030.out	2015-06-23 16:10:53.315110375 +0100
+++ 030.out.bad	2015-06-23 16:20:49.649709419 +0100
@@ -1,5 +1,17 @@
-.................
+......F..........
+======================================================================
+FAIL: test_stream_parallel (__main__.TestParallelOps)
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "030", line 202, in test_stream_parallel
+    self.assert_qmp(result, 'return', {})
+  File "/home/stefanha/qemu/tests/qemu-iotests/iotests.py", line 286, in assert_qmp
+    result = self.dictpath(d, path)
+  File "/home/stefanha/qemu/tests/qemu-iotests/iotests.py", line 265, in dictpath
+    self.fail('failed path traversal for "%s" in "%s"' % (path, str(d)))
+AssertionError: failed path traversal for "return" in "None"
+
 ----------------------------------------------------------------------
 Ran 17 tests
 
-OK
+FAILED (failures=1)

[-- Attachment #2: Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] [PATCH v8 00/11] Support streaming to an intermediate layer
  2015-06-23 15:36 ` [Qemu-devel] [PATCH v8 00/11] Support streaming to an intermediate layer Stefan Hajnoczi
@ 2015-06-23 16:09   ` Alberto Garcia
  2015-06-23 16:48     ` [Qemu-devel] [Qemu-block] " Stefan Hajnoczi
  0 siblings, 1 reply; 20+ messages in thread
From: Alberto Garcia @ 2015-06-23 16:09 UTC (permalink / raw)
  To: Stefan Hajnoczi; +Cc: qemu-devel, qemu-block

On Tue 23 Jun 2015 05:36:32 PM CEST, Stefan Hajnoczi wrote:

> Did you try qemu-iotests?  I'm still getting:
>
> 030 11s ... [failed, exit status 1] - output mismatch (see
> 030.out.bad)

Yes, it works fine here.

> +Traceback (most recent call last):
> +  File "030", line 202, in test_stream_parallel
> +    self.assert_qmp(result, 'return', {})

This creates several streaming operations in parallel. That particular
line just checks the return value of each block-stream command.

> +  File "/home/stefanha/qemu/tests/qemu-iotests/iotests.py", line 286, in assert_qmp
> +    result = self.dictpath(d, path)
> +  File "/home/stefanha/qemu/tests/qemu-iotests/iotests.py", line 265, in dictpath
> +    self.fail('failed path traversal for "%s" in "%s"' % (path, str(d)))
> +AssertionError: failed path traversal for "return" in "None"
> +
>  ----------------------------------------------------------------------
>  Ran 17 tests

It seems that self.vm.qmp('block-stream', ...) is returning None in your
case. Is that the only test that is failing?

Berto

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] [Qemu-block] [PATCH v8 00/11] Support streaming to an intermediate layer
  2015-06-23 16:09   ` Alberto Garcia
@ 2015-06-23 16:48     ` Stefan Hajnoczi
  2015-06-24  8:02       ` Alberto Garcia
  0 siblings, 1 reply; 20+ messages in thread
From: Stefan Hajnoczi @ 2015-06-23 16:48 UTC (permalink / raw)
  To: Alberto Garcia; +Cc: qemu block, qemu-devel, Stefan Hajnoczi

On Tue, Jun 23, 2015 at 5:09 PM, Alberto Garcia <berto@igalia.com> wrote:
> On Tue 23 Jun 2015 05:36:32 PM CEST, Stefan Hajnoczi wrote:
>
>> Did you try qemu-iotests?  I'm still getting:
>>
>> 030 11s ... [failed, exit status 1] - output mismatch (see
>> 030.out.bad)
>
> Yes, it works fine here.
>
>> +Traceback (most recent call last):
>> +  File "030", line 202, in test_stream_parallel
>> +    self.assert_qmp(result, 'return', {})
>
> This creates several streaming operations in parallel. That particular
> line just checks the return value of each block-stream command.
>
>> +  File "/home/stefanha/qemu/tests/qemu-iotests/iotests.py", line 286, in assert_qmp
>> +    result = self.dictpath(d, path)
>> +  File "/home/stefanha/qemu/tests/qemu-iotests/iotests.py", line 265, in dictpath
>> +    self.fail('failed path traversal for "%s" in "%s"' % (path, str(d)))
>> +AssertionError: failed path traversal for "return" in "None"
>> +
>>  ----------------------------------------------------------------------
>>  Ran 17 tests
>
> It seems that self.vm.qmp('block-stream', ...) is returning None in your
> case. Is that the only test that is failing?

Yes, only this test fails.  I have pushed my tree here:
https://github.com/stefanha/qemu/commits/berto-intermediate-streaming

I wonder if you see this failure on your machine with my tree.

Stefan

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] [Qemu-block] [PATCH v8 00/11] Support streaming to an intermediate layer
  2015-06-23 16:48     ` [Qemu-devel] [Qemu-block] " Stefan Hajnoczi
@ 2015-06-24  8:02       ` Alberto Garcia
  2015-06-24 10:02         ` Alberto Garcia
  0 siblings, 1 reply; 20+ messages in thread
From: Alberto Garcia @ 2015-06-24  8:02 UTC (permalink / raw)
  To: Stefan Hajnoczi; +Cc: Kevin Wolf, qemu-devel, qemu block

On Tue 23 Jun 2015 06:48:39 PM CEST, Stefan Hajnoczi wrote:

>> It seems that self.vm.qmp('block-stream', ...) is returning None in
>> your case. Is that the only test that is failing?
>
> Yes, only this test fails.  I have pushed my tree here:
> https://github.com/stefanha/qemu/commits/berto-intermediate-streaming
>
> I wonder if you see this failure on your machine with my tree.

I was debugging the problem. So we have this scenario:

[A] <- [B] <- [C] <- [D] <- [E] <- [F] <- [G]

The test that is failing is test_stream_parallel(), that creates
several concurrent streaming operations, in this order:

 a) [B] => [C]
 b) [D] => [E]
 c) [F] => [G]

The way it works is that stream_start() reopens the destination image
in read-write mode (if needed), creates the stream_run() coroutine to
copy the data, and finally stream_complete() puts it back in read-only
mode and closes the images that are removed from the chain.

This was not causing problems earlier because each operation works on a
different set of images, but it seems that things have changed since the
reopen overhaul patches:

   https://lists.gnu.org/archive/html/qemu-devel/2015-05/msg01587.html
   https://lists.gnu.org/archive/html/qemu-devel/2015-05/msg01592.html

Here's what happens:

 - We launch block job a).
 - While a) is ongoing, b) enters and tries to reopen [E] in
   read-write mode.
 - With the reopen overhaul patches, the BlockReopenQueue no longer
   contains just [E] but also all its backing chain up to [A].
 - bdrv_reopen_multiple() calls bdrv_reopen_prepare() and flushes all
   images.
 - At this point job a) takes over and finishes, reopening [C] again
   in read-only mode and closing [B], removing it from memory.
 - When b) continues (still in bdrv_reopen_multiple) the queue still
   contains [B], which is no longer a valid pointer.

My first reaction was to keep a reference to each BDS in the
BlockReopenQueue during the operation, but I don't know why that queue
needs to contain all the backing chain in the first place.

Berto

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] [Qemu-block] [PATCH v8 00/11] Support streaming to an intermediate layer
  2015-06-24  8:02       ` Alberto Garcia
@ 2015-06-24 10:02         ` Alberto Garcia
  2015-06-26  8:01           ` Alberto Garcia
  0 siblings, 1 reply; 20+ messages in thread
From: Alberto Garcia @ 2015-06-24 10:02 UTC (permalink / raw)
  To: Stefan Hajnoczi; +Cc: Kevin Wolf, qemu-devel, qemu block

On Wed 24 Jun 2015 10:02:03 AM CEST, Alberto Garcia wrote:

> [A] <- [B] <- [C] <- [D] <- [E] <- [F] <- [G]
>
> [...]
>
> The way it works is that stream_start() reopens the destination image
> in read-write mode (if needed), creates the stream_run() coroutine to
> copy the data, and finally stream_complete() puts it back in read-only
> mode and closes the images that are removed from the chain.

There's more. If I perform a single streaming operation [A] => [D] this
also crashes, although in a different way.

   block.c:1764: bdrv_reopen_prepare: Assertion `reopen_state->bs->drv != ((void *)0)' failed.

What happens is that in stream_complete() all images that have been
removed from the chain ([A], [B] and [C]) are closed, and then [D] is
reopened in read-only mode.

The reopen queue contains [C], that is still listed as a child of [D]
although it's no longer a valid pointer.

[C] is opened using bdrv_open_backing_file() and attached to [D] with
bdrv_attach_child(), but never detached afterwards.

Berto

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] [PATCH v8 01/11] block: keep a list of block jobs
  2015-06-22 21:32 ` [Qemu-devel] [PATCH v8 01/11] block: keep a list of block jobs Alberto Garcia
@ 2015-06-24 15:45   ` Max Reitz
  0 siblings, 0 replies; 20+ messages in thread
From: Max Reitz @ 2015-06-24 15:45 UTC (permalink / raw)
  To: Alberto Garcia, qemu-devel; +Cc: Stefan Hajnoczi, qemu-block, Alexander Yarygin

On 22.06.2015 23:32, Alberto Garcia wrote:
> The current way to obtain the list of existing block jobs is to
> iterate over all root nodes and check which ones own a job.
>
> Since we want to be able to support block jobs in other nodes as well,
> this patch keeps a list of jobs that is updated every time one is
> created or destroyed.
>
> This also updates qmp_query_block_jobs() and bdrv_drain_all() to use
> this new list.
>
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> Cc: Max Reitz <mreitz@redhat.com>
> Cc: Eric Blake <eblake@redhat.com>
> Cc: Alexander Yarygin <yarygin@linux.vnet.ibm.com>
> ---
>   block/io.c               | 22 +++++++++++-----------
>   blockdev.c               | 19 ++++++++-----------
>   blockjob.c               | 13 +++++++++++++
>   include/block/blockjob.h | 14 ++++++++++++++
>   4 files changed, 46 insertions(+), 22 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] [Qemu-block] [PATCH v8 00/11] Support streaming to an intermediate layer
  2015-06-24 10:02         ` Alberto Garcia
@ 2015-06-26  8:01           ` Alberto Garcia
  0 siblings, 0 replies; 20+ messages in thread
From: Alberto Garcia @ 2015-06-26  8:01 UTC (permalink / raw)
  To: Stefan Hajnoczi; +Cc: Kevin Wolf, qemu-devel, qemu block

On Wed 24 Jun 2015 12:02:35 PM CEST, Alberto Garcia <berto@igalia.com> wrote:

> What happens is that in stream_complete() all images that have been
> removed from the chain ([A], [B] and [C]) are closed, and then [D] is
> reopened in read-only mode.
>
> The reopen queue contains [C], that is still listed as a child of [D]
> although it's no longer a valid pointer.

Here's a simple way to access freed memory with the current master:

$ qemu-img create -f qcow2 base.qcow2 100M
$ qemu-img create -f qcow2 -o backing_file="base.qcow2" hd.qcow2
$ valgrind qemu-system-x86_64 -enable-kvm -monitor stdio -drive if=virtio,file=hd.qcow2

(qemu) block_stream virtio0 
(qemu) drive_del virtio0 
==15925== Thread 1:
==15925== Invalid read of size 8
==15925==    at 0x4C0C55: bdrv_close (block.c:1853)
==15925==    by 0x2E12C7: hmp_drive_del (blockdev.c:2173)
==15925==    by 0x1E72D5: handle_hmp_command (monitor.c:4058)
==15925==    by 0x1E9A44: monitor_command_cb (monitor.c:5081)
==15925==    by 0x578443: readline_handle_byte (readline.c:391)
==15925==    by 0x1E999E: monitor_read (monitor.c:5064)
==15925==    by 0x2E7064: qemu_chr_be_write (qemu-char.c:306)
==15925==    by 0x2E88AA: fd_chr_read (qemu-char.c:1012)
==15925==    by 0x9B6DB4C: g_main_context_dispatch (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4400.1)
==15925==    by 0x4C6D7C: glib_pollfds_poll (main-loop.c:199)
==15925==    by 0x4C6E59: os_host_main_loop_wait (main-loop.c:244)
==15925==    by 0x4C6F18: main_loop_wait (main-loop.c:493)
==15925==  Address 0x1a86f2a0 is 16 bytes after a block of size 256 free'd
==15925==    at 0x4C29E90: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==15925==    by 0x6215767: pixman_image_unref (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.32.6)
==15925==    by 0x490131: qemu_pixman_glyph_render (qemu-pixman.c:250)
==15925==    by 0x48AC70: vga_putcharxy (console.c:435)
==15925==    by 0x48B38C: console_refresh (console.c:567)
==15925==    by 0x48CC57: text_console_invalidate (console.c:1155)
==15925==    by 0x48A6A2: graphic_hw_invalidate (console.c:269)
==15925==    by 0x48E71D: text_console_update_cursor (console.c:1831)
==15925==    by 0x4C8245: timerlist_run_timers (qemu-timer.c:502)
==15925==    by 0x4C828D: qemu_clock_run_timers (qemu-timer.c:513)
==15925==    by 0x4C8596: qemu_clock_run_all_timers (qemu-timer.c:621)
==15925==    by 0x4C6F4E: main_loop_wait (main-loop.c:499)
==15925== 

As explained in my previous e-mail, the problem is that after the
block_stream operation, the bs->children list in hd.qcow2 still keeps a
pointer to base.qcow2 even when its memory has been freed.

Berto

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [Qemu-devel] [PATCH v8 03/11] block: never cancel a streaming job without running stream_complete()
  2015-06-22 21:32 ` [Qemu-devel] [PATCH v8 03/11] block: never cancel a streaming job without running stream_complete() Alberto Garcia
@ 2015-10-16  8:35   ` Stefan Hajnoczi
  0 siblings, 0 replies; 20+ messages in thread
From: Stefan Hajnoczi @ 2015-10-16  8:35 UTC (permalink / raw)
  To: Alberto Garcia; +Cc: qemu-devel, qemu-block

On Tue, Jun 23, 2015 at 12:32:18AM +0300, Alberto Garcia wrote:
> We need to call stream_complete() in order to do all the necessary
> clean-ups, even if there's an early failure. At the moment it's only
> useful to make sure that s->backing_file_str is not leaked, but it
> will become more important as we introduce support for streaming to
> any intermediate node.
> 
> Signed-off-by: Alberto Garcia <berto@igalia.com>
> Reviewed-by: Max Reitz <mreitz@redhat.com>
> ---
>  block/stream.c | 11 ++++++-----
>  1 file changed, 6 insertions(+), 5 deletions(-)

Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>

^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2015-10-16  8:35 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-06-22 21:32 [Qemu-devel] [PATCH v8 00/11] Support streaming to an intermediate layer Alberto Garcia
2015-06-22 21:32 ` [Qemu-devel] [PATCH v8 01/11] block: keep a list of block jobs Alberto Garcia
2015-06-24 15:45   ` Max Reitz
2015-06-22 21:32 ` [Qemu-devel] [PATCH v8 02/11] block: allow block jobs in any arbitrary node Alberto Garcia
2015-06-22 21:32 ` [Qemu-devel] [PATCH v8 03/11] block: never cancel a streaming job without running stream_complete() Alberto Garcia
2015-10-16  8:35   ` Stefan Hajnoczi
2015-06-22 21:32 ` [Qemu-devel] [PATCH v8 04/11] block: Support streaming to an intermediate layer Alberto Garcia
2015-06-22 21:32 ` [Qemu-devel] [PATCH v8 05/11] block: Add QMP support for " Alberto Garcia
2015-06-22 21:32 ` [Qemu-devel] [PATCH v8 06/11] docs: Document how to stream " Alberto Garcia
2015-06-22 21:32 ` [Qemu-devel] [PATCH v8 07/11] qemu-iotests: fix test_stream_partial() Alberto Garcia
2015-06-22 21:32 ` [Qemu-devel] [PATCH v8 08/11] qemu-iotests: add no-op streaming test Alberto Garcia
2015-06-22 21:32 ` [Qemu-devel] [PATCH v8 09/11] qemu-iotests: test streaming to an intermediate layer Alberto Garcia
2015-06-22 21:32 ` [Qemu-devel] [PATCH v8 10/11] qemu-iotests: test block-stream operations in parallel Alberto Garcia
2015-06-22 21:32 ` [Qemu-devel] [PATCH v8 11/11] qemu-iotests: test overlapping block-stream operations Alberto Garcia
2015-06-23 15:36 ` [Qemu-devel] [PATCH v8 00/11] Support streaming to an intermediate layer Stefan Hajnoczi
2015-06-23 16:09   ` Alberto Garcia
2015-06-23 16:48     ` [Qemu-devel] [Qemu-block] " Stefan Hajnoczi
2015-06-24  8:02       ` Alberto Garcia
2015-06-24 10:02         ` Alberto Garcia
2015-06-26  8:01           ` Alberto Garcia

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.