- kvm-virtio-introduce-macro-VIRTIO_CONFIG_IRQ_IDX.patch [bz#1905805] - kvm-virtio-pci-decouple-notifier-from-interrupt-process.patch [bz#1905805] - kvm-virtio-pci-decouple-the-single-vector-from-the-inter.patch [bz#1905805] - kvm-vhost-introduce-new-VhostOps-vhost_set_config_call.patch [bz#1905805] - kvm-vhost-vdpa-add-support-for-config-interrupt.patch [bz#1905805] - kvm-virtio-add-support-for-configure-interrupt.patch [bz#1905805] - kvm-vhost-add-support-for-configure-interrupt.patch [bz#1905805] - kvm-virtio-net-add-support-for-configure-interrupt.patch [bz#1905805] - kvm-virtio-mmio-add-support-for-configure-interrupt.patch [bz#1905805] - kvm-virtio-pci-add-support-for-configure-interrupt.patch [bz#1905805] - kvm-s390x-s390-virtio-ccw-Activate-zPCI-features-on-s390.patch [bz#2159408] - kvm-vhost-fix-vq-dirty-bitmap-syncing-when-vIOMMU-is-ena.patch [bz#2124856] - kvm-block-drop-bdrv_remove_filter_or_cow_child.patch [bz#2155112] - kvm-qed-Don-t-yield-in-bdrv_qed_co_drain_begin.patch [bz#2155112] - kvm-test-bdrv-drain-Don-t-yield-in-.bdrv_co_drained_begi.patch [bz#2155112] - kvm-block-Revert-.bdrv_drained_begin-end-to-non-coroutin.patch [bz#2155112] - kvm-block-Remove-drained_end_counter.patch [bz#2155112] - kvm-block-Inline-bdrv_drain_invoke.patch [bz#2155112] - kvm-block-Fix-locking-for-bdrv_reopen_queue_child.patch [bz#2155112] - kvm-block-Drain-individual-nodes-during-reopen.patch [bz#2155112] - kvm-block-Don-t-use-subtree-drains-in-bdrv_drop_intermed.patch [bz#2155112] - kvm-stream-Replace-subtree-drain-with-a-single-node-drai.patch [bz#2155112] - kvm-block-Remove-subtree-drains.patch [bz#2155112] - kvm-block-Call-drain-callbacks-only-once.patch [bz#2155112] - kvm-block-Remove-ignore_bds_parents-parameter-from-drain.patch [bz#2155112] - kvm-block-Drop-out-of-coroutine-in-bdrv_do_drained_begin.patch [bz#2155112] - kvm-block-Don-t-poll-in-bdrv_replace_child_noperm.patch [bz#2155112] - kvm-block-Remove-poll-parameter-from-bdrv_parent_drained.patch [bz#2155112] - kvm-accel-introduce-accelerator-blocker-API.patch [bz#1979276] - kvm-KVM-keep-track-of-running-ioctls.patch [bz#1979276] - kvm-kvm-Atomic-memslot-updates.patch [bz#1979276] - Resolves: bz#1905805 (support config interrupt in vhost-vdpa qemu) - Resolves: bz#2159408 ([s390x] VMs with ISM passthrough don't autostart after leapp upgrade from RHEL 8) - Resolves: bz#2124856 (VM with virtio interface and iommu=on will crash when try to migrate) - Resolves: bz#2155112 (Qemu coredump after do snapshot of mirrored top image and its converted base image(iothread enabled)) - Resolves: bz#1979276 (SVM: non atomic memslot updates cause boot failure with seabios and cpu-pm=on)
		
			
				
	
	
		
			251 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			251 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| From 9bb9cafd736057fd2a8ebfa6f5769668f125fbe6 Mon Sep 17 00:00:00 2001
 | |
| From: Kevin Wolf <kwolf@redhat.com>
 | |
| Date: Fri, 18 Nov 2022 18:41:06 +0100
 | |
| Subject: [PATCH 24/31] block: Call drain callbacks only once
 | |
| 
 | |
| RH-Author: Stefano Garzarella <sgarzare@redhat.com>
 | |
| RH-MergeRequest: 135: block: Simplify drain to prevent QEMU from crashing during snapshot
 | |
| RH-Bugzilla: 2155112
 | |
| RH-Acked-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
 | |
| RH-Acked-by: Hanna Czenczek <hreitz@redhat.com>
 | |
| RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
 | |
| RH-Commit: [12/16] ea9a433dc01d1b8539a2d4ea12887f2a3ce830ea (sgarzarella/qemu-kvm-c-9-s)
 | |
| 
 | |
| We only need to call both the BlockDriver's callback and the parent
 | |
| callbacks when going from undrained to drained or vice versa. A second
 | |
| drain section doesn't make a difference for the driver or the parent,
 | |
| they weren't supposed to send new requests before and after the second
 | |
| drain.
 | |
| 
 | |
| One thing that gets in the way is the 'ignore_bds_parents' parameter in
 | |
| bdrv_do_drained_begin_quiesce() and bdrv_do_drained_end(): It means that
 | |
| bdrv_drain_all_begin() increases bs->quiesce_counter, but does not
 | |
| quiesce the parent through BdrvChildClass callbacks. If an additional
 | |
| drain section is started now, bs->quiesce_counter will be non-zero, but
 | |
| we would still need to quiesce the parent through BdrvChildClass in
 | |
| order to keep things consistent (and unquiesce it on the matching
 | |
| bdrv_drained_end(), even though the counter would not reach 0 yet as
 | |
| long as the bdrv_drain_all() section is still active).
 | |
| 
 | |
| Instead of keeping track of this, let's just get rid of the parameter.
 | |
| It was introduced in commit 6cd5c9d7b2d as an optimisation so that
 | |
| during bdrv_drain_all(), we wouldn't recursively drain all parents up to
 | |
| the root for each node, resulting in quadratic complexity. As it happens,
 | |
| calling the callbacks only once solves the same problem, so as of this
 | |
| patch, we'll still have O(n) complexity and ignore_bds_parents is not
 | |
| needed any more.
 | |
| 
 | |
| This patch only ignores the 'ignore_bds_parents' parameter. It will be
 | |
| removed in a separate patch.
 | |
| 
 | |
| Signed-off-by: Kevin Wolf <kwolf@redhat.com>
 | |
| Reviewed-by: Hanna Reitz <hreitz@redhat.com>
 | |
| Message-Id: <20221118174110.55183-12-kwolf@redhat.com>
 | |
| Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
 | |
| Signed-off-by: Kevin Wolf <kwolf@redhat.com>
 | |
| (cherry picked from commit 57e05be343f33f4e5899a8d8946a8596d68424a1)
 | |
| Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
 | |
| ---
 | |
|  block.c                          | 25 +++++++------------------
 | |
|  block/io.c                       | 30 ++++++++++++++++++------------
 | |
|  include/block/block_int-common.h |  8 ++++----
 | |
|  tests/unit/test-bdrv-drain.c     | 16 ++++++++++------
 | |
|  4 files changed, 39 insertions(+), 40 deletions(-)
 | |
| 
 | |
| diff --git a/block.c b/block.c
 | |
| index e0e3b21790..5a583e260d 100644
 | |
| --- a/block.c
 | |
| +++ b/block.c
 | |
| @@ -2824,7 +2824,6 @@ static void bdrv_replace_child_noperm(BdrvChild *child,
 | |
|  {
 | |
|      BlockDriverState *old_bs = child->bs;
 | |
|      int new_bs_quiesce_counter;
 | |
| -    int drain_saldo;
 | |
|  
 | |
|      assert(!child->frozen);
 | |
|      assert(old_bs != new_bs);
 | |
| @@ -2834,16 +2833,13 @@ static void bdrv_replace_child_noperm(BdrvChild *child,
 | |
|          assert(bdrv_get_aio_context(old_bs) == bdrv_get_aio_context(new_bs));
 | |
|      }
 | |
|  
 | |
| -    new_bs_quiesce_counter = (new_bs ? new_bs->quiesce_counter : 0);
 | |
| -    drain_saldo = new_bs_quiesce_counter - child->parent_quiesce_counter;
 | |
| -
 | |
|      /*
 | |
|       * If the new child node is drained but the old one was not, flush
 | |
|       * all outstanding requests to the old child node.
 | |
|       */
 | |
| -    while (drain_saldo > 0 && child->klass->drained_begin) {
 | |
| +    new_bs_quiesce_counter = (new_bs ? new_bs->quiesce_counter : 0);
 | |
| +    if (new_bs_quiesce_counter && !child->quiesced_parent) {
 | |
|          bdrv_parent_drained_begin_single(child, true);
 | |
| -        drain_saldo--;
 | |
|      }
 | |
|  
 | |
|      if (old_bs) {
 | |
| @@ -2859,16 +2855,6 @@ static void bdrv_replace_child_noperm(BdrvChild *child,
 | |
|      if (new_bs) {
 | |
|          assert_bdrv_graph_writable(new_bs);
 | |
|          QLIST_INSERT_HEAD(&new_bs->parents, child, next_parent);
 | |
| -
 | |
| -        /*
 | |
| -         * Polling in bdrv_parent_drained_begin_single() may have led to the new
 | |
| -         * node's quiesce_counter having been decreased.  Not a problem, we just
 | |
| -         * need to recognize this here and then invoke drained_end appropriately
 | |
| -         * more often.
 | |
| -         */
 | |
| -        assert(new_bs->quiesce_counter <= new_bs_quiesce_counter);
 | |
| -        drain_saldo += new_bs->quiesce_counter - new_bs_quiesce_counter;
 | |
| -
 | |
|          if (child->klass->attach) {
 | |
|              child->klass->attach(child);
 | |
|          }
 | |
| @@ -2877,10 +2863,13 @@ static void bdrv_replace_child_noperm(BdrvChild *child,
 | |
|      /*
 | |
|       * If the old child node was drained but the new one is not, allow
 | |
|       * requests to come in only after the new node has been attached.
 | |
| +     *
 | |
| +     * Update new_bs_quiesce_counter because bdrv_parent_drained_begin_single()
 | |
| +     * polls, which could have changed the value.
 | |
|       */
 | |
| -    while (drain_saldo < 0 && child->klass->drained_end) {
 | |
| +    new_bs_quiesce_counter = (new_bs ? new_bs->quiesce_counter : 0);
 | |
| +    if (!new_bs_quiesce_counter && child->quiesced_parent) {
 | |
|          bdrv_parent_drained_end_single(child);
 | |
| -        drain_saldo++;
 | |
|      }
 | |
|  }
 | |
|  
 | |
| diff --git a/block/io.c b/block/io.c
 | |
| index 75224480d0..87d6f22ec4 100644
 | |
| --- a/block/io.c
 | |
| +++ b/block/io.c
 | |
| @@ -62,8 +62,9 @@ void bdrv_parent_drained_end_single(BdrvChild *c)
 | |
|  {
 | |
|      IO_OR_GS_CODE();
 | |
|  
 | |
| -    assert(c->parent_quiesce_counter > 0);
 | |
| -    c->parent_quiesce_counter--;
 | |
| +    assert(c->quiesced_parent);
 | |
| +    c->quiesced_parent = false;
 | |
| +
 | |
|      if (c->klass->drained_end) {
 | |
|          c->klass->drained_end(c);
 | |
|      }
 | |
| @@ -110,7 +111,10 @@ void bdrv_parent_drained_begin_single(BdrvChild *c, bool poll)
 | |
|  {
 | |
|      AioContext *ctx = bdrv_child_get_parent_aio_context(c);
 | |
|      IO_OR_GS_CODE();
 | |
| -    c->parent_quiesce_counter++;
 | |
| +
 | |
| +    assert(!c->quiesced_parent);
 | |
| +    c->quiesced_parent = true;
 | |
| +
 | |
|      if (c->klass->drained_begin) {
 | |
|          c->klass->drained_begin(c);
 | |
|      }
 | |
| @@ -358,11 +362,12 @@ void bdrv_do_drained_begin_quiesce(BlockDriverState *bs,
 | |
|      /* Stop things in parent-to-child order */
 | |
|      if (qatomic_fetch_inc(&bs->quiesce_counter) == 0) {
 | |
|          aio_disable_external(bdrv_get_aio_context(bs));
 | |
| -    }
 | |
|  
 | |
| -    bdrv_parent_drained_begin(bs, parent, ignore_bds_parents);
 | |
| -    if (bs->drv && bs->drv->bdrv_drain_begin) {
 | |
| -        bs->drv->bdrv_drain_begin(bs);
 | |
| +        /* TODO Remove ignore_bds_parents, we don't consider it any more */
 | |
| +        bdrv_parent_drained_begin(bs, parent, false);
 | |
| +        if (bs->drv && bs->drv->bdrv_drain_begin) {
 | |
| +            bs->drv->bdrv_drain_begin(bs);
 | |
| +        }
 | |
|      }
 | |
|  }
 | |
|  
 | |
| @@ -413,13 +418,14 @@ static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent,
 | |
|      assert(bs->quiesce_counter > 0);
 | |
|  
 | |
|      /* Re-enable things in child-to-parent order */
 | |
| -    if (bs->drv && bs->drv->bdrv_drain_end) {
 | |
| -        bs->drv->bdrv_drain_end(bs);
 | |
| -    }
 | |
| -    bdrv_parent_drained_end(bs, parent, ignore_bds_parents);
 | |
| -
 | |
|      old_quiesce_counter = qatomic_fetch_dec(&bs->quiesce_counter);
 | |
|      if (old_quiesce_counter == 1) {
 | |
| +        if (bs->drv && bs->drv->bdrv_drain_end) {
 | |
| +            bs->drv->bdrv_drain_end(bs);
 | |
| +        }
 | |
| +        /* TODO Remove ignore_bds_parents, we don't consider it any more */
 | |
| +        bdrv_parent_drained_end(bs, parent, false);
 | |
| +
 | |
|          aio_enable_external(bdrv_get_aio_context(bs));
 | |
|      }
 | |
|  }
 | |
| diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h
 | |
| index 791dddfd7d..a6bc6b7fe9 100644
 | |
| --- a/include/block/block_int-common.h
 | |
| +++ b/include/block/block_int-common.h
 | |
| @@ -980,13 +980,13 @@ struct BdrvChild {
 | |
|      bool frozen;
 | |
|  
 | |
|      /*
 | |
| -     * How many times the parent of this child has been drained
 | |
| +     * True if the parent of this child has been drained by this BdrvChild
 | |
|       * (through klass->drained_*).
 | |
| -     * Usually, this is equal to bs->quiesce_counter (potentially
 | |
| -     * reduced by bdrv_drain_all_count).  It may differ while the
 | |
| +     *
 | |
| +     * It is generally true if bs->quiesce_counter > 0. It may differ while the
 | |
|       * child is entering or leaving a drained section.
 | |
|       */
 | |
| -    int parent_quiesce_counter;
 | |
| +    bool quiesced_parent;
 | |
|  
 | |
|      QLIST_ENTRY(BdrvChild) next;
 | |
|      QLIST_ENTRY(BdrvChild) next_parent;
 | |
| diff --git a/tests/unit/test-bdrv-drain.c b/tests/unit/test-bdrv-drain.c
 | |
| index dda08de8db..172bc6debc 100644
 | |
| --- a/tests/unit/test-bdrv-drain.c
 | |
| +++ b/tests/unit/test-bdrv-drain.c
 | |
| @@ -296,7 +296,11 @@ static void test_quiesce_common(enum drain_type drain_type, bool recursive)
 | |
|  
 | |
|      do_drain_begin(drain_type, bs);
 | |
|  
 | |
| -    g_assert_cmpint(bs->quiesce_counter, ==, 1);
 | |
| +    if (drain_type == BDRV_DRAIN_ALL) {
 | |
| +        g_assert_cmpint(bs->quiesce_counter, ==, 2);
 | |
| +    } else {
 | |
| +        g_assert_cmpint(bs->quiesce_counter, ==, 1);
 | |
| +    }
 | |
|      g_assert_cmpint(backing->quiesce_counter, ==, !!recursive);
 | |
|  
 | |
|      do_drain_end(drain_type, bs);
 | |
| @@ -348,8 +352,8 @@ static void test_nested(void)
 | |
|  
 | |
|      for (outer = 0; outer < DRAIN_TYPE_MAX; outer++) {
 | |
|          for (inner = 0; inner < DRAIN_TYPE_MAX; inner++) {
 | |
| -            int backing_quiesce = (outer != BDRV_DRAIN) +
 | |
| -                                  (inner != BDRV_DRAIN);
 | |
| +            int backing_quiesce = (outer == BDRV_DRAIN_ALL) +
 | |
| +                                  (inner == BDRV_DRAIN_ALL);
 | |
|  
 | |
|              g_assert_cmpint(bs->quiesce_counter, ==, 0);
 | |
|              g_assert_cmpint(backing->quiesce_counter, ==, 0);
 | |
| @@ -359,10 +363,10 @@ static void test_nested(void)
 | |
|              do_drain_begin(outer, bs);
 | |
|              do_drain_begin(inner, bs);
 | |
|  
 | |
| -            g_assert_cmpint(bs->quiesce_counter, ==, 2);
 | |
| +            g_assert_cmpint(bs->quiesce_counter, ==, 2 + !!backing_quiesce);
 | |
|              g_assert_cmpint(backing->quiesce_counter, ==, backing_quiesce);
 | |
| -            g_assert_cmpint(s->drain_count, ==, 2);
 | |
| -            g_assert_cmpint(backing_s->drain_count, ==, backing_quiesce);
 | |
| +            g_assert_cmpint(s->drain_count, ==, 1);
 | |
| +            g_assert_cmpint(backing_s->drain_count, ==, !!backing_quiesce);
 | |
|  
 | |
|              do_drain_end(inner, bs);
 | |
|              do_drain_end(outer, bs);
 | |
| -- 
 | |
| 2.31.1
 | |
| 
 |