Blame SOURCES/kvm-block-don-t-keep-AioContext-acquired-after-external_.patch

4a2fec
From 618ad78b4afa654623057234db339c8cbcfb7392 Mon Sep 17 00:00:00 2001
4a2fec
From: Stefan Hajnoczi <stefanha@redhat.com>
4a2fec
Date: Fri, 22 Dec 2017 11:08:50 +0100
4a2fec
Subject: [PATCH 32/42] block: don't keep AioContext acquired after
4a2fec
 external_snapshot_prepare()
4a2fec
4a2fec
RH-Author: Stefan Hajnoczi <stefanha@redhat.com>
4a2fec
Message-id: <20171222110900.24813-11-stefanha@redhat.com>
4a2fec
Patchwork-id: 78492
4a2fec
O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 10/20] block: don't keep AioContext acquired after external_snapshot_prepare()
4a2fec
Bugzilla: 1519721
4a2fec
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
4a2fec
RH-Acked-by: Jeffrey Cody <jcody@redhat.com>
4a2fec
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
4a2fec
4a2fec
It is not necessary to hold AioContext across transactions anymore since
4a2fec
bdrv_drained_begin/end() is used to keep the nodes quiesced.  In fact,
4a2fec
using the AioContext lock for this purpose was always buggy.
4a2fec
4a2fec
This patch reduces the scope of AioContext locked regions.  This is not
4a2fec
just a cleanup but also fixes hangs that occur in BDRV_POLL_WHILE()
4a2fec
because it is unware of recursive locking and does not release the
4a2fec
AioContext the necessary number of times to allow progress to be made.
4a2fec
4a2fec
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
4a2fec
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
4a2fec
Reviewed-by: Eric Blake <eblake@redhat.com>
4a2fec
Message-id: 20171206144550.22295-3-stefanha@redhat.com
4a2fec
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
4a2fec
(cherry picked from commit 2d24b60b7747f7bf40fd00b0375b6bd988d4f0d9)
4a2fec
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
4a2fec
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
4a2fec
---
4a2fec
 blockdev.c | 71 ++++++++++++++++++++++++++++++++++++++++++--------------------
4a2fec
 1 file changed, 48 insertions(+), 23 deletions(-)
4a2fec
4a2fec
diff --git a/blockdev.c b/blockdev.c
4a2fec
index c6978a5..8bb23e9 100644
4a2fec
--- a/blockdev.c
4a2fec
+++ b/blockdev.c
4a2fec
@@ -1649,7 +1649,6 @@ typedef struct ExternalSnapshotState {
4a2fec
     BlkActionState common;
4a2fec
     BlockDriverState *old_bs;
4a2fec
     BlockDriverState *new_bs;
4a2fec
-    AioContext *aio_context;
4a2fec
     bool overlay_appended;
4a2fec
 } ExternalSnapshotState;
4a2fec
 
4a2fec
@@ -1669,6 +1668,7 @@ static void external_snapshot_prepare(BlkActionState *common,
4a2fec
     ExternalSnapshotState *state =
4a2fec
                              DO_UPCAST(ExternalSnapshotState, common, common);
4a2fec
     TransactionAction *action = common->action;
4a2fec
+    AioContext *aio_context;
4a2fec
 
4a2fec
     /* 'blockdev-snapshot' and 'blockdev-snapshot-sync' have similar
4a2fec
      * purpose but a different set of parameters */
4a2fec
@@ -1705,31 +1705,32 @@ static void external_snapshot_prepare(BlkActionState *common,
4a2fec
         return;
4a2fec
     }
4a2fec
 
4a2fec
-    /* Acquire AioContext now so any threads operating on old_bs stop */
4a2fec
-    state->aio_context = bdrv_get_aio_context(state->old_bs);
4a2fec
-    aio_context_acquire(state->aio_context);
4a2fec
+    aio_context = bdrv_get_aio_context(state->old_bs);
4a2fec
+    aio_context_acquire(aio_context);
4a2fec
+
4a2fec
+    /* Paired with .clean() */
4a2fec
     bdrv_drained_begin(state->old_bs);
4a2fec
 
4a2fec
     if (!bdrv_is_inserted(state->old_bs)) {
4a2fec
         error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
4a2fec
-        return;
4a2fec
+        goto out;
4a2fec
     }
4a2fec
 
4a2fec
     if (bdrv_op_is_blocked(state->old_bs,
4a2fec
                            BLOCK_OP_TYPE_EXTERNAL_SNAPSHOT, errp)) {
4a2fec
-        return;
4a2fec
+        goto out;
4a2fec
     }
4a2fec
 
4a2fec
     if (!bdrv_is_read_only(state->old_bs)) {
4a2fec
         if (bdrv_flush(state->old_bs)) {
4a2fec
             error_setg(errp, QERR_IO_ERROR);
4a2fec
-            return;
4a2fec
+            goto out;
4a2fec
         }
4a2fec
     }
4a2fec
 
4a2fec
     if (!bdrv_is_first_non_filter(state->old_bs)) {
4a2fec
         error_setg(errp, QERR_FEATURE_DISABLED, "snapshot");
4a2fec
-        return;
4a2fec
+        goto out;
4a2fec
     }
4a2fec
 
4a2fec
     if (action->type == TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC) {
4a2fec
@@ -1741,13 +1742,13 @@ static void external_snapshot_prepare(BlkActionState *common,
4a2fec
 
4a2fec
         if (node_name && !snapshot_node_name) {
4a2fec
             error_setg(errp, "New snapshot node name missing");
4a2fec
-            return;
4a2fec
+            goto out;
4a2fec
         }
4a2fec
 
4a2fec
         if (snapshot_node_name &&
4a2fec
             bdrv_lookup_bs(snapshot_node_name, snapshot_node_name, NULL)) {
4a2fec
             error_setg(errp, "New snapshot node name already in use");
4a2fec
-            return;
4a2fec
+            goto out;
4a2fec
         }
4a2fec
 
4a2fec
         flags = state->old_bs->open_flags;
4a2fec
@@ -1760,7 +1761,7 @@ static void external_snapshot_prepare(BlkActionState *common,
4a2fec
             int64_t size = bdrv_getlength(state->old_bs);
4a2fec
             if (size < 0) {
4a2fec
                 error_setg_errno(errp, -size, "bdrv_getlength failed");
4a2fec
-                return;
4a2fec
+                goto out;
4a2fec
             }
4a2fec
             bdrv_img_create(new_image_file, format,
4a2fec
                             state->old_bs->filename,
4a2fec
@@ -1768,7 +1769,7 @@ static void external_snapshot_prepare(BlkActionState *common,
4a2fec
                             NULL, size, flags, false, &local_err);
4a2fec
             if (local_err) {
4a2fec
                 error_propagate(errp, local_err);
4a2fec
-                return;
4a2fec
+                goto out;
4a2fec
             }
4a2fec
         }
4a2fec
 
4a2fec
@@ -1783,30 +1784,30 @@ static void external_snapshot_prepare(BlkActionState *common,
4a2fec
                               errp);
4a2fec
     /* We will manually add the backing_hd field to the bs later */
4a2fec
     if (!state->new_bs) {
4a2fec
-        return;
4a2fec
+        goto out;
4a2fec
     }
4a2fec
 
4a2fec
     if (bdrv_has_blk(state->new_bs)) {
4a2fec
         error_setg(errp, "The snapshot is already in use");
4a2fec
-        return;
4a2fec
+        goto out;
4a2fec
     }
4a2fec
 
4a2fec
     if (bdrv_op_is_blocked(state->new_bs, BLOCK_OP_TYPE_EXTERNAL_SNAPSHOT,
4a2fec
                            errp)) {
4a2fec
-        return;
4a2fec
+        goto out;
4a2fec
     }
4a2fec
 
4a2fec
     if (state->new_bs->backing != NULL) {
4a2fec
         error_setg(errp, "The snapshot already has a backing image");
4a2fec
-        return;
4a2fec
+        goto out;
4a2fec
     }
4a2fec
 
4a2fec
     if (!state->new_bs->drv->supports_backing) {
4a2fec
         error_setg(errp, "The snapshot does not support backing images");
4a2fec
-        return;
4a2fec
+        goto out;
4a2fec
     }
4a2fec
 
4a2fec
-    bdrv_set_aio_context(state->new_bs, state->aio_context);
4a2fec
+    bdrv_set_aio_context(state->new_bs, aio_context);
4a2fec
 
4a2fec
     /* This removes our old bs and adds the new bs. This is an operation that
4a2fec
      * can fail, so we need to do it in .prepare; undoing it for abort is
4a2fec
@@ -1815,15 +1816,22 @@ static void external_snapshot_prepare(BlkActionState *common,
4a2fec
     bdrv_append(state->new_bs, state->old_bs, &local_err);
4a2fec
     if (local_err) {
4a2fec
         error_propagate(errp, local_err);
4a2fec
-        return;
4a2fec
+        goto out;
4a2fec
     }
4a2fec
     state->overlay_appended = true;
4a2fec
+
4a2fec
+out:
4a2fec
+    aio_context_release(aio_context);
4a2fec
 }
4a2fec
 
4a2fec
 static void external_snapshot_commit(BlkActionState *common)
4a2fec
 {
4a2fec
     ExternalSnapshotState *state =
4a2fec
                              DO_UPCAST(ExternalSnapshotState, common, common);
4a2fec
+    AioContext *aio_context;
4a2fec
+
4a2fec
+    aio_context = bdrv_get_aio_context(state->old_bs);
4a2fec
+    aio_context_acquire(aio_context);
4a2fec
 
4a2fec
     /* We don't need (or want) to use the transactional
4a2fec
      * bdrv_reopen_multiple() across all the entries at once, because we
4a2fec
@@ -1832,6 +1840,8 @@ static void external_snapshot_commit(BlkActionState *common)
4a2fec
         bdrv_reopen(state->old_bs, state->old_bs->open_flags & ~BDRV_O_RDWR,
4a2fec
                     NULL);
4a2fec
     }
4a2fec
+
4a2fec
+    aio_context_release(aio_context);
4a2fec
 }
4a2fec
 
4a2fec
 static void external_snapshot_abort(BlkActionState *common)
4a2fec
@@ -1840,11 +1850,18 @@ static void external_snapshot_abort(BlkActionState *common)
4a2fec
                              DO_UPCAST(ExternalSnapshotState, common, common);
4a2fec
     if (state->new_bs) {
4a2fec
         if (state->overlay_appended) {
4a2fec
+            AioContext *aio_context;
4a2fec
+
4a2fec
+            aio_context = bdrv_get_aio_context(state->old_bs);
4a2fec
+            aio_context_acquire(aio_context);
4a2fec
+
4a2fec
             bdrv_ref(state->old_bs);   /* we can't let bdrv_set_backind_hd()
4a2fec
                                           close state->old_bs; we need it */
4a2fec
             bdrv_set_backing_hd(state->new_bs, NULL, &error_abort);
4a2fec
             bdrv_replace_node(state->new_bs, state->old_bs, &error_abort);
4a2fec
             bdrv_unref(state->old_bs); /* bdrv_replace_node() ref'ed old_bs */
4a2fec
+
4a2fec
+            aio_context_release(aio_context);
4a2fec
         }
4a2fec
     }
4a2fec
 }
4a2fec
@@ -1853,11 +1870,19 @@ static void external_snapshot_clean(BlkActionState *common)
4a2fec
 {
4a2fec
     ExternalSnapshotState *state =
4a2fec
                              DO_UPCAST(ExternalSnapshotState, common, common);
4a2fec
-    if (state->aio_context) {
4a2fec
-        bdrv_drained_end(state->old_bs);
4a2fec
-        bdrv_unref(state->new_bs);
4a2fec
-        aio_context_release(state->aio_context);
4a2fec
+    AioContext *aio_context;
4a2fec
+
4a2fec
+    if (!state->old_bs) {
4a2fec
+        return;
4a2fec
     }
4a2fec
+
4a2fec
+    aio_context = bdrv_get_aio_context(state->old_bs);
4a2fec
+    aio_context_acquire(aio_context);
4a2fec
+
4a2fec
+    bdrv_drained_end(state->old_bs);
4a2fec
+    bdrv_unref(state->new_bs);
4a2fec
+
4a2fec
+    aio_context_release(aio_context);
4a2fec
 }
4a2fec
 
4a2fec
 typedef struct DriveBackupState {
4a2fec
-- 
4a2fec
1.8.3.1
4a2fec