qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/2] commit: Fix crash on job start with active I/O
@ 2019-05-21 19:16 Kevin Wolf
  2019-05-21 19:16 ` [Qemu-devel] [PATCH 1/2] block: Drain source node in bdrv_replace_node() Kevin Wolf
  2019-05-21 19:16 ` [Qemu-devel] [PATCH 2/2] iotests: Test commit job start with concurrent I/O Kevin Wolf
  0 siblings, 2 replies; 5+ messages in thread
From: Kevin Wolf @ 2019-05-21 19:16 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, qemu-devel, mreitz

Kevin Wolf (2):
  block: Drain source node in bdrv_replace_node()
  iotests: Test commit job start with concurrent I/O

 block.c                       |  7 +--
 tests/qemu-iotests/255        | 83 +++++++++++++++++++++++++++++++++++
 tests/qemu-iotests/255.out    | 16 +++++++
 tests/qemu-iotests/group      |  1 +
 tests/qemu-iotests/iotests.py | 10 ++++-
 5 files changed, 113 insertions(+), 4 deletions(-)
 create mode 100755 tests/qemu-iotests/255
 create mode 100644 tests/qemu-iotests/255.out

-- 
2.20.1



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

* [Qemu-devel] [PATCH 1/2] block: Drain source node in bdrv_replace_node()
  2019-05-21 19:16 [Qemu-devel] [PATCH 0/2] commit: Fix crash on job start with active I/O Kevin Wolf
@ 2019-05-21 19:16 ` Kevin Wolf
  2019-05-22 11:28   ` Max Reitz
  2019-05-21 19:16 ` [Qemu-devel] [PATCH 2/2] iotests: Test commit job start with concurrent I/O Kevin Wolf
  1 sibling, 1 reply; 5+ messages in thread
From: Kevin Wolf @ 2019-05-21 19:16 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, qemu-devel, mreitz

Instead of just asserting that no requests are in flight in
bdrv_replace_node(), which is a requirement that most callers ignore, we
can just drain the source node right there. This fixes at least starting
a commit job while I/O is active on the backing chain, but probably
other callers, too.

Having requests in flight on the target node isn't a problem because the
target just gets new parents, but the call path of running requests
isn't modified. So we can just drop this assertion without a replacement.

Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1711643
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/block.c b/block.c
index cb11537029..75f370dbba 100644
--- a/block.c
+++ b/block.c
@@ -4021,13 +4021,13 @@ void bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
     uint64_t perm = 0, shared = BLK_PERM_ALL;
     int ret;
 
-    assert(!atomic_read(&from->in_flight));
-    assert(!atomic_read(&to->in_flight));
-
     /* Make sure that @from doesn't go away until we have successfully attached
      * all of its parents to @to. */
     bdrv_ref(from);
 
+    assert(qemu_get_current_aio_context() == qemu_get_aio_context());
+    bdrv_drained_begin(from);
+
     /* Put all parents into @list and calculate their cumulative permissions */
     QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) {
         assert(c->bs == from);
@@ -4068,6 +4068,7 @@ void bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
 
 out:
     g_slist_free(list);
+    bdrv_drained_end(from);
     bdrv_unref(from);
 }
 
-- 
2.20.1



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

* [Qemu-devel] [PATCH 2/2] iotests: Test commit job start with concurrent I/O
  2019-05-21 19:16 [Qemu-devel] [PATCH 0/2] commit: Fix crash on job start with active I/O Kevin Wolf
  2019-05-21 19:16 ` [Qemu-devel] [PATCH 1/2] block: Drain source node in bdrv_replace_node() Kevin Wolf
@ 2019-05-21 19:16 ` Kevin Wolf
  2019-05-22 11:48   ` Max Reitz
  1 sibling, 1 reply; 5+ messages in thread
From: Kevin Wolf @ 2019-05-21 19:16 UTC (permalink / raw)
  To: qemu-block; +Cc: kwolf, qemu-devel, mreitz

This tests that concurrent requests are correctly drained before making
graph modifications instead of running into assertions in
bdrv_replace_node().

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 tests/qemu-iotests/255        | 83 +++++++++++++++++++++++++++++++++++
 tests/qemu-iotests/255.out    | 16 +++++++
 tests/qemu-iotests/group      |  1 +
 tests/qemu-iotests/iotests.py | 10 ++++-
 4 files changed, 109 insertions(+), 1 deletion(-)
 create mode 100755 tests/qemu-iotests/255
 create mode 100644 tests/qemu-iotests/255.out

diff --git a/tests/qemu-iotests/255 b/tests/qemu-iotests/255
new file mode 100755
index 0000000000..c0bb37a9b0
--- /dev/null
+++ b/tests/qemu-iotests/255
@@ -0,0 +1,83 @@
+#!/usr/bin/env python
+#
+# Test commit job graph modifications while requests are active
+#
+# Copyright (C) 2019 Red Hat, Inc.
+#
+# Creator/Owner: Kevin Wolf <kwolf@redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+import iotests
+from iotests import imgfmt
+
+iotests.verify_image_format(supported_fmts=['qcow2'])
+
+def blockdev_create(vm, options):
+    result = vm.qmp_log('blockdev-create',
+                        filters=[iotests.filter_qmp_testfiles],
+                        job_id='job0', options=options)
+
+    if 'return' in result:
+        assert result['return'] == {}
+        vm.run_job('job0')
+    iotests.log("")
+
+with iotests.FilePath('t.qcow2') as disk_path, \
+     iotests.FilePath('t.qcow2.mid') as mid_path, \
+     iotests.FilePath('t.qcow2.base') as base_path, \
+     iotests.VM() as vm:
+
+    iotests.log("=== Create backing chain and start VM ===")
+    iotests.log("")
+
+    size = 128 * 1024 * 1024
+    size_str = str(size)
+
+    iotests.create_image(base_path, size)
+    iotests.qemu_img_log('create', '-f', iotests.imgfmt, mid_path, size_str)
+    iotests.qemu_img_log('create', '-f', iotests.imgfmt, disk_path, size_str)
+
+    # Create a backing chain like this:
+    # base <- [throttled: bps-read=4096] <- mid <- overlay
+
+    vm.add_object('throttle-group,x-bps-read=4096,id=throttle0')
+    vm.add_blockdev('file,filename=%s,node-name=base' % (base_path))
+    vm.add_blockdev('throttle,throttle-group=throttle0,file=base,node-name=throttled')
+    vm.add_blockdev('file,filename=%s,node-name=mid-file' % (mid_path))
+    vm.add_blockdev('qcow2,file=mid-file,node-name=mid,backing=throttled')
+    vm.add_drive_raw('if=none,id=overlay,driver=qcow2,file=%s,backing=mid' % (disk_path))
+
+    vm.launch()
+
+    iotests.log("=== Start background read requests ===")
+    iotests.log("")
+
+    def start_requests():
+        vm.hmp_qemu_io('overlay', 'aio_read 0 4k')
+        vm.hmp_qemu_io('overlay', 'aio_read 0 4k')
+
+    start_requests()
+
+    iotests.log("=== Run a commit job ===")
+    iotests.log("")
+
+    result = vm.qmp_log('block-commit', job_id='job0', auto_finalize=False,
+                        device='overlay', top_node='mid')
+
+    vm.run_job('job0', auto_finalize=False, pre_finalize=start_requests,
+                auto_dismiss=True)
+
+    vm.shutdown()
diff --git a/tests/qemu-iotests/255.out b/tests/qemu-iotests/255.out
new file mode 100644
index 0000000000..9a2d7cbb77
--- /dev/null
+++ b/tests/qemu-iotests/255.out
@@ -0,0 +1,16 @@
+=== Create backing chain and start VM ===
+
+Formatting 'TEST_DIR/PID-t.qcow2.mid', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16
+
+Formatting 'TEST_DIR/PID-t.qcow2', fmt=qcow2 size=134217728 cluster_size=65536 lazy_refcounts=off refcount_bits=16
+
+=== Start background read requests ===
+
+=== Run a commit job ===
+
+{"execute": "block-commit", "arguments": {"auto-finalize": false, "device": "overlay", "job-id": "job0", "top-node": "mid"}}
+{"return": {}}
+{"execute": "job-finalize", "arguments": {"id": "job0"}}
+{"return": {}}
+{"data": {"id": "job0", "type": "commit"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
+{"data": {"device": "job0", "len": 134217728, "offset": 134217728, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 52b7c16e15..2758f48143 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -251,3 +251,4 @@
 249 rw auto quick
 252 rw auto backing quick
 253 rw auto quick
+255 rw auto quick
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
index 7bde380d96..6bcddd8870 100644
--- a/tests/qemu-iotests/iotests.py
+++ b/tests/qemu-iotests/iotests.py
@@ -126,6 +126,11 @@ def qemu_img_pipe(*args):
         sys.stderr.write('qemu-img received signal %i: %s\n' % (-exitcode, ' '.join(qemu_img_args + list(args))))
     return subp.communicate()[0]
 
+def qemu_img_log(*args):
+    result = qemu_img_pipe(*args)
+    log(result, filters=[filter_testfiles])
+    return result
+
 def img_info_log(filename, filter_path=None, imgopts=False, extra_args=[]):
     args = [ 'info' ]
     if imgopts:
@@ -533,7 +538,8 @@ class VM(qtest.QEMUQtestMachine):
         return result
 
     # Returns None on success, and an error string on failure
-    def run_job(self, job, auto_finalize=True, auto_dismiss=False):
+    def run_job(self, job, auto_finalize=True, auto_dismiss=False,
+                pre_finalize=None):
         error = None
         while True:
             for ev in self.get_qmp_events_filtered(wait=True):
@@ -546,6 +552,8 @@ class VM(qtest.QEMUQtestMachine):
                                 error = j['error']
                                 log('Job failed: %s' % (j['error']))
                     elif status == 'pending' and not auto_finalize:
+                        if pre_finalize:
+                            pre_finalize()
                         self.qmp_log('job-finalize', id=job)
                     elif status == 'concluded' and not auto_dismiss:
                         self.qmp_log('job-dismiss', id=job)
-- 
2.20.1



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

* Re: [Qemu-devel] [PATCH 1/2] block: Drain source node in bdrv_replace_node()
  2019-05-21 19:16 ` [Qemu-devel] [PATCH 1/2] block: Drain source node in bdrv_replace_node() Kevin Wolf
@ 2019-05-22 11:28   ` Max Reitz
  0 siblings, 0 replies; 5+ messages in thread
From: Max Reitz @ 2019-05-22 11:28 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: qemu-devel

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

On 21.05.19 21:16, Kevin Wolf wrote:
> Instead of just asserting that no requests are in flight in
> bdrv_replace_node(), which is a requirement that most callers ignore, we
> can just drain the source node right there. This fixes at least starting
> a commit job while I/O is active on the backing chain, but probably
> other callers, too.
> 
> Having requests in flight on the target node isn't a problem because the
> target just gets new parents, but the call path of running requests
> isn't modified. So we can just drop this assertion without a replacement.
> 
> Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1711643
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  block.c | 7 ++++---
>  1 file changed, 4 insertions(+), 3 deletions(-)

I had a similar problem with throttle on a blockdev-mirror job.  I
suppose this is more general than my “Don’t increment in_flight in
bdrv_drain_invoke()” solution, that probably doesn’t even work for your
case. :-)

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


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* Re: [Qemu-devel] [PATCH 2/2] iotests: Test commit job start with concurrent I/O
  2019-05-21 19:16 ` [Qemu-devel] [PATCH 2/2] iotests: Test commit job start with concurrent I/O Kevin Wolf
@ 2019-05-22 11:48   ` Max Reitz
  0 siblings, 0 replies; 5+ messages in thread
From: Max Reitz @ 2019-05-22 11:48 UTC (permalink / raw)
  To: Kevin Wolf, qemu-block; +Cc: qemu-devel

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

On 21.05.19 21:16, Kevin Wolf wrote:
> This tests that concurrent requests are correctly drained before making
> graph modifications instead of running into assertions in
> bdrv_replace_node().
> 
> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
> ---
>  tests/qemu-iotests/255        | 83 +++++++++++++++++++++++++++++++++++
>  tests/qemu-iotests/255.out    | 16 +++++++
>  tests/qemu-iotests/group      |  1 +
>  tests/qemu-iotests/iotests.py | 10 ++++-
>  4 files changed, 109 insertions(+), 1 deletion(-)
>  create mode 100755 tests/qemu-iotests/255
>  create mode 100644 tests/qemu-iotests/255.out
Reviewed-by: Max Reitz <mreitz@redhat.com>

(By the way, because I see throttle on mirror, here, too: My problem
involves a concurrent bdrv_drain_all(), that’s the slight difference.
But your patch 1 works well for me.)

(Max)


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

end of thread, other threads:[~2019-05-22 11:49 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-05-21 19:16 [Qemu-devel] [PATCH 0/2] commit: Fix crash on job start with active I/O Kevin Wolf
2019-05-21 19:16 ` [Qemu-devel] [PATCH 1/2] block: Drain source node in bdrv_replace_node() Kevin Wolf
2019-05-22 11:28   ` Max Reitz
2019-05-21 19:16 ` [Qemu-devel] [PATCH 2/2] iotests: Test commit job start with concurrent I/O Kevin Wolf
2019-05-22 11:48   ` Max Reitz

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).