qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 0/5] blockdev: avoid acquiring AioContext lock twice at do_drive_backup and do_blockdev_backup
@ 2019-11-21 13:57 Sergio Lopez
  2019-11-21 13:57 ` [PATCH v4 1/5] blockdev: fix coding style issues in drive_backup_prepare Sergio Lopez
                   ` (4 more replies)
  0 siblings, 5 replies; 11+ messages in thread
From: Sergio Lopez @ 2019-11-21 13:57 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Sergio Lopez, Markus Armbruster, qemu-block, Max Reitz

do_drive_backup() acquires the AioContext lock of the corresponding
BlockDriverState. This is not a problem when it's called from
qmp_drive_backup(), but drive_backup_prepare() also acquires the lock
before calling it. The same things happens with do_blockdev_backup()
and blockdev_backup_prepare().

This patch series merges do_drive_backup() with drive_backup_prepare()
and do_blockdev_backup() with blockdev_backup_prepare(), and ensures
they're only getting called from a transaction context. This way,
there's a single code path for both transaction requests and qmp
commands, as suggested by Kevin Wolf.

We also take this opportunity to ensure we're honoring the context
acquisition semantics required by bdrv_try_set_aio_context, as
suggested by Max Reitz.

---
Changelog:

v4:
 - Unify patches 1-4 and 5-7 to avoid producing broken interim
   states. (thanks Max Reitz)
 - Include a fix for iotest 141. (thanks Kevin Wolf)

v3:
 - Rework the whole patch series to fix the issue by consolidating all
   operations in the transaction model. (thanks Kevin Wolf)

v2:
 - Honor bdrv_try_set_aio_context() context acquisition requirements
   (thanks Max Reitz).
 - Release the context at drive_backup_prepare() instead of avoiding
   re-acquiring it at do_drive_baclup(). (thanks Max Reitz)
 - Convert a single patch into a two-patch series.
---

Sergio Lopez (5):
  blockdev: fix coding style issues in drive_backup_prepare
  blockdev: unify qmp_drive_backup and drive-backup transaction paths
  blockdev: unify qmp_blockdev_backup and blockdev-backup transaction
    paths
  blockdev: honor bdrv_try_set_aio_context() context requirements
  iotests: fix 141 after qmp_drive_backup with transactions

 blockdev.c                 | 349 ++++++++++++++++++-------------------
 tests/qemu-iotests/141.out |   2 +
 2 files changed, 173 insertions(+), 178 deletions(-)

-- 
2.23.0



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

* [PATCH v4 1/5] blockdev: fix coding style issues in drive_backup_prepare
  2019-11-21 13:57 [PATCH v4 0/5] blockdev: avoid acquiring AioContext lock twice at do_drive_backup and do_blockdev_backup Sergio Lopez
@ 2019-11-21 13:57 ` Sergio Lopez
  2019-11-27 15:53   ` Max Reitz
  2019-11-21 13:57 ` [PATCH v4 2/5] blockdev: unify qmp_drive_backup and drive-backup transaction paths Sergio Lopez
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 11+ messages in thread
From: Sergio Lopez @ 2019-11-21 13:57 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Sergio Lopez, Markus Armbruster, qemu-block, Max Reitz

Fix a couple of minor coding style issues in drive_backup_prepare.

Signed-off-by: Sergio Lopez <slp@redhat.com>
---
 blockdev.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/blockdev.c b/blockdev.c
index 8e029e9c01..553e315972 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -3620,7 +3620,7 @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn,
 
     if (!backup->has_format) {
         backup->format = backup->mode == NEW_IMAGE_MODE_EXISTING ?
-                         NULL : (char*) bs->drv->format_name;
+                         NULL : (char *) bs->drv->format_name;
     }
 
     /* Early check to avoid creating target */
@@ -3630,8 +3630,10 @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn,
 
     flags = bs->open_flags | BDRV_O_RDWR;
 
-    /* See if we have a backing HD we can use to create our new image
-     * on top of. */
+    /*
+     * See if we have a backing HD we can use to create our new image
+     * on top of.
+     */
     if (backup->sync == MIRROR_SYNC_MODE_TOP) {
         source = backing_bs(bs);
         if (!source) {
-- 
2.23.0



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

* [PATCH v4 2/5] blockdev: unify qmp_drive_backup and drive-backup transaction paths
  2019-11-21 13:57 [PATCH v4 0/5] blockdev: avoid acquiring AioContext lock twice at do_drive_backup and do_blockdev_backup Sergio Lopez
  2019-11-21 13:57 ` [PATCH v4 1/5] blockdev: fix coding style issues in drive_backup_prepare Sergio Lopez
@ 2019-11-21 13:57 ` Sergio Lopez
  2019-11-27 16:37   ` Max Reitz
  2019-11-21 13:57 ` [PATCH v4 3/5] blockdev: unify qmp_blockdev_backup and blockdev-backup " Sergio Lopez
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 11+ messages in thread
From: Sergio Lopez @ 2019-11-21 13:57 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Sergio Lopez, Markus Armbruster, qemu-block, Max Reitz

Issuing a drive-backup from qmp_drive_backup takes a slightly
different path than when it's issued from a transaction. In the code,
this is manifested as some redundancy between do_drive_backup() and
drive_backup_prepare().

This change unifies both paths, merging do_drive_backup() and
drive_backup_prepare(), and changing qmp_drive_backup() to create a
transaction instead of calling do_backup_common() direcly.

As a side-effect, now qmp_drive_backup() is executed inside a drained
section, as it happens when creating a drive-backup transaction. This
change is visible from the user's perspective, as the job gets paused
and immediately resumed before starting the actual work.

Signed-off-by: Sergio Lopez <slp@redhat.com>
---
 blockdev.c | 224 ++++++++++++++++++++++++-----------------------------
 1 file changed, 100 insertions(+), 124 deletions(-)

diff --git a/blockdev.c b/blockdev.c
index 553e315972..5e85fc042e 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1761,39 +1761,128 @@ typedef struct DriveBackupState {
     BlockJob *job;
 } DriveBackupState;
 
-static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn,
-                            Error **errp);
+static BlockJob *do_backup_common(BackupCommon *backup,
+                                  BlockDriverState *bs,
+                                  BlockDriverState *target_bs,
+                                  AioContext *aio_context,
+                                  JobTxn *txn, Error **errp);
 
 static void drive_backup_prepare(BlkActionState *common, Error **errp)
 {
     DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common);
-    BlockDriverState *bs;
     DriveBackup *backup;
+    BlockDriverState *bs;
+    BlockDriverState *target_bs;
+    BlockDriverState *source = NULL;
     AioContext *aio_context;
+    QDict *options;
     Error *local_err = NULL;
+    int flags;
+    int64_t size;
+    bool set_backing_hd = false;
 
     assert(common->action->type == TRANSACTION_ACTION_KIND_DRIVE_BACKUP);
     backup = common->action->u.drive_backup.data;
 
+    if (!backup->has_mode) {
+        backup->mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS;
+    }
+
     bs = bdrv_lookup_bs(backup->device, backup->device, errp);
     if (!bs) {
         return;
     }
 
+    if (!bs->drv) {
+        error_setg(errp, "Device has no medium");
+        return;
+    }
+
     aio_context = bdrv_get_aio_context(bs);
     aio_context_acquire(aio_context);
 
     /* Paired with .clean() */
     bdrv_drained_begin(bs);
 
-    state->bs = bs;
+    if (!backup->has_format) {
+        backup->format = backup->mode == NEW_IMAGE_MODE_EXISTING ?
+                         NULL : (char *) bs->drv->format_name;
+    }
+
+    /* Early check to avoid creating target */
+    if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) {
+        goto out;
+    }
+
+    flags = bs->open_flags | BDRV_O_RDWR;
+
+    /*
+     * See if we have a backing HD we can use to create our new image
+     * on top of.
+     */
+    if (backup->sync == MIRROR_SYNC_MODE_TOP) {
+        source = backing_bs(bs);
+        if (!source) {
+            backup->sync = MIRROR_SYNC_MODE_FULL;
+        }
+    }
+    if (backup->sync == MIRROR_SYNC_MODE_NONE) {
+        source = bs;
+        flags |= BDRV_O_NO_BACKING;
+        set_backing_hd = true;
+    }
+
+    size = bdrv_getlength(bs);
+    if (size < 0) {
+        error_setg_errno(errp, -size, "bdrv_getlength failed");
+        goto out;
+    }
+
+    if (backup->mode != NEW_IMAGE_MODE_EXISTING) {
+        assert(backup->format);
+        if (source) {
+            bdrv_refresh_filename(source);
+            bdrv_img_create(backup->target, backup->format, source->filename,
+                            source->drv->format_name, NULL,
+                            size, flags, false, &local_err);
+        } else {
+            bdrv_img_create(backup->target, backup->format, NULL, NULL, NULL,
+                            size, flags, false, &local_err);
+        }
+    }
 
-    state->job = do_drive_backup(backup, common->block_job_txn, &local_err);
     if (local_err) {
         error_propagate(errp, local_err);
         goto out;
     }
 
+    options = qdict_new();
+    qdict_put_str(options, "discard", "unmap");
+    qdict_put_str(options, "detect-zeroes", "unmap");
+    if (backup->format) {
+        qdict_put_str(options, "driver", backup->format);
+    }
+
+    target_bs = bdrv_open(backup->target, NULL, options, flags, errp);
+    if (!target_bs) {
+        goto out;
+    }
+
+    if (set_backing_hd) {
+        bdrv_set_backing_hd(target_bs, source, &local_err);
+        if (local_err) {
+            goto unref;
+        }
+    }
+
+    state->bs = bs;
+
+    state->job = do_backup_common(qapi_DriveBackup_base(backup),
+                                  bs, target_bs, aio_context,
+                                  common->block_job_txn, errp);
+
+unref:
+    bdrv_unref(target_bs);
 out:
     aio_context_release(aio_context);
 }
@@ -3587,126 +3676,13 @@ static BlockJob *do_backup_common(BackupCommon *backup,
     return job;
 }
 
-static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn,
-                                 Error **errp)
-{
-    BlockDriverState *bs;
-    BlockDriverState *target_bs;
-    BlockDriverState *source = NULL;
-    BlockJob *job = NULL;
-    AioContext *aio_context;
-    QDict *options;
-    Error *local_err = NULL;
-    int flags;
-    int64_t size;
-    bool set_backing_hd = false;
-
-    if (!backup->has_mode) {
-        backup->mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS;
-    }
-
-    bs = bdrv_lookup_bs(backup->device, backup->device, errp);
-    if (!bs) {
-        return NULL;
-    }
-
-    if (!bs->drv) {
-        error_setg(errp, "Device has no medium");
-        return NULL;
-    }
-
-    aio_context = bdrv_get_aio_context(bs);
-    aio_context_acquire(aio_context);
-
-    if (!backup->has_format) {
-        backup->format = backup->mode == NEW_IMAGE_MODE_EXISTING ?
-                         NULL : (char *) bs->drv->format_name;
-    }
-
-    /* Early check to avoid creating target */
-    if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) {
-        goto out;
-    }
-
-    flags = bs->open_flags | BDRV_O_RDWR;
-
-    /*
-     * See if we have a backing HD we can use to create our new image
-     * on top of.
-     */
-    if (backup->sync == MIRROR_SYNC_MODE_TOP) {
-        source = backing_bs(bs);
-        if (!source) {
-            backup->sync = MIRROR_SYNC_MODE_FULL;
-        }
-    }
-    if (backup->sync == MIRROR_SYNC_MODE_NONE) {
-        source = bs;
-        flags |= BDRV_O_NO_BACKING;
-        set_backing_hd = true;
-    }
-
-    size = bdrv_getlength(bs);
-    if (size < 0) {
-        error_setg_errno(errp, -size, "bdrv_getlength failed");
-        goto out;
-    }
-
-    if (backup->mode != NEW_IMAGE_MODE_EXISTING) {
-        assert(backup->format);
-        if (source) {
-            bdrv_refresh_filename(source);
-            bdrv_img_create(backup->target, backup->format, source->filename,
-                            source->drv->format_name, NULL,
-                            size, flags, false, &local_err);
-        } else {
-            bdrv_img_create(backup->target, backup->format, NULL, NULL, NULL,
-                            size, flags, false, &local_err);
-        }
-    }
-
-    if (local_err) {
-        error_propagate(errp, local_err);
-        goto out;
-    }
-
-    options = qdict_new();
-    qdict_put_str(options, "discard", "unmap");
-    qdict_put_str(options, "detect-zeroes", "unmap");
-    if (backup->format) {
-        qdict_put_str(options, "driver", backup->format);
-    }
-
-    target_bs = bdrv_open(backup->target, NULL, options, flags, errp);
-    if (!target_bs) {
-        goto out;
-    }
-
-    if (set_backing_hd) {
-        bdrv_set_backing_hd(target_bs, source, &local_err);
-        if (local_err) {
-            goto unref;
-        }
-    }
-
-    job = do_backup_common(qapi_DriveBackup_base(backup),
-                           bs, target_bs, aio_context, txn, errp);
-
-unref:
-    bdrv_unref(target_bs);
-out:
-    aio_context_release(aio_context);
-    return job;
-}
-
-void qmp_drive_backup(DriveBackup *arg, Error **errp)
+void qmp_drive_backup(DriveBackup *backup, Error **errp)
 {
-
-    BlockJob *job;
-    job = do_drive_backup(arg, NULL, errp);
-    if (job) {
-        job_start(&job->job);
-    }
+    TransactionAction action = {
+        .type = TRANSACTION_ACTION_KIND_DRIVE_BACKUP,
+        .u.drive_backup.data = backup,
+    };
+    blockdev_do_action(&action, errp);
 }
 
 BlockDeviceInfoList *qmp_query_named_block_nodes(Error **errp)
-- 
2.23.0



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

* [PATCH v4 3/5] blockdev: unify qmp_blockdev_backup and blockdev-backup transaction paths
  2019-11-21 13:57 [PATCH v4 0/5] blockdev: avoid acquiring AioContext lock twice at do_drive_backup and do_blockdev_backup Sergio Lopez
  2019-11-21 13:57 ` [PATCH v4 1/5] blockdev: fix coding style issues in drive_backup_prepare Sergio Lopez
  2019-11-21 13:57 ` [PATCH v4 2/5] blockdev: unify qmp_drive_backup and drive-backup transaction paths Sergio Lopez
@ 2019-11-21 13:57 ` Sergio Lopez
  2019-11-27 16:49   ` Max Reitz
  2019-11-21 13:57 ` [PATCH v4 4/5] blockdev: honor bdrv_try_set_aio_context() context requirements Sergio Lopez
  2019-11-21 13:57 ` [PATCH v4 5/5] iotests: fix 141 after qmp_drive_backup with transactions Sergio Lopez
  4 siblings, 1 reply; 11+ messages in thread
From: Sergio Lopez @ 2019-11-21 13:57 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Sergio Lopez, Markus Armbruster, qemu-block, Max Reitz

Issuing a blockdev-backup from qmp_blockdev_backup takes a slightly
different path than when it's issued from a transaction. In the code,
this is manifested as some redundancy between do_blockdev_backup() and
blockdev_backup_prepare().

This change unifies both paths, merging do_blockdev_backup() and
blockdev_backup_prepare(), and changing qmp_blockdev_backup() to
create a transaction instead of calling do_backup_common() direcly.

As a side-effect, now qmp_blockdev_backup() is executed inside a
drained section, as it happens when creating a blockdev-backup
transaction. This change is visible from the user's perspective, as
the job gets paused and immediately resumed before starting the actual
work.

Signed-off-by: Sergio Lopez <slp@redhat.com>
---
 blockdev.c | 60 ++++++++++++------------------------------------------
 1 file changed, 13 insertions(+), 47 deletions(-)

diff --git a/blockdev.c b/blockdev.c
index 5e85fc042e..152a0f7454 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1940,16 +1940,13 @@ typedef struct BlockdevBackupState {
     BlockJob *job;
 } BlockdevBackupState;
 
-static BlockJob *do_blockdev_backup(BlockdevBackup *backup, JobTxn *txn,
-                                    Error **errp);
-
 static void blockdev_backup_prepare(BlkActionState *common, Error **errp)
 {
     BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common);
     BlockdevBackup *backup;
-    BlockDriverState *bs, *target;
+    BlockDriverState *bs;
+    BlockDriverState *target_bs;
     AioContext *aio_context;
-    Error *local_err = NULL;
 
     assert(common->action->type == TRANSACTION_ACTION_KIND_BLOCKDEV_BACKUP);
     backup = common->action->u.blockdev_backup.data;
@@ -1959,8 +1956,8 @@ static void blockdev_backup_prepare(BlkActionState *common, Error **errp)
         return;
     }
 
-    target = bdrv_lookup_bs(backup->target, backup->target, errp);
-    if (!target) {
+    target_bs = bdrv_lookup_bs(backup->target, backup->target, errp);
+    if (!target_bs) {
         return;
     }
 
@@ -1971,13 +1968,10 @@ static void blockdev_backup_prepare(BlkActionState *common, Error **errp)
     /* Paired with .clean() */
     bdrv_drained_begin(state->bs);
 
-    state->job = do_blockdev_backup(backup, common->block_job_txn, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
-        goto out;
-    }
+    state->job = do_backup_common(qapi_BlockdevBackup_base(backup),
+                                  bs, target_bs, aio_context,
+                                  common->block_job_txn, errp);
 
-out:
     aio_context_release(aio_context);
 }
 
@@ -3695,41 +3689,13 @@ XDbgBlockGraph *qmp_x_debug_query_block_graph(Error **errp)
     return bdrv_get_xdbg_block_graph(errp);
 }
 
-BlockJob *do_blockdev_backup(BlockdevBackup *backup, JobTxn *txn,
-                             Error **errp)
+void qmp_blockdev_backup(BlockdevBackup *backup, Error **errp)
 {
-    BlockDriverState *bs;
-    BlockDriverState *target_bs;
-    AioContext *aio_context;
-    BlockJob *job;
-
-    bs = bdrv_lookup_bs(backup->device, backup->device, errp);
-    if (!bs) {
-        return NULL;
-    }
-
-    target_bs = bdrv_lookup_bs(backup->target, backup->target, errp);
-    if (!target_bs) {
-        return NULL;
-    }
-
-    aio_context = bdrv_get_aio_context(bs);
-    aio_context_acquire(aio_context);
-
-    job = do_backup_common(qapi_BlockdevBackup_base(backup),
-                           bs, target_bs, aio_context, txn, errp);
-
-    aio_context_release(aio_context);
-    return job;
-}
-
-void qmp_blockdev_backup(BlockdevBackup *arg, Error **errp)
-{
-    BlockJob *job;
-    job = do_blockdev_backup(arg, NULL, errp);
-    if (job) {
-        job_start(&job->job);
-    }
+    TransactionAction action = {
+        .type = TRANSACTION_ACTION_KIND_BLOCKDEV_BACKUP,
+        .u.blockdev_backup.data = backup,
+    };
+    blockdev_do_action(&action, errp);
 }
 
 /* Parameter check and block job starting for drive mirroring.
-- 
2.23.0



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

* [PATCH v4 4/5] blockdev: honor bdrv_try_set_aio_context() context requirements
  2019-11-21 13:57 [PATCH v4 0/5] blockdev: avoid acquiring AioContext lock twice at do_drive_backup and do_blockdev_backup Sergio Lopez
                   ` (2 preceding siblings ...)
  2019-11-21 13:57 ` [PATCH v4 3/5] blockdev: unify qmp_blockdev_backup and blockdev-backup " Sergio Lopez
@ 2019-11-21 13:57 ` Sergio Lopez
  2019-11-27 17:10   ` Max Reitz
  2019-11-21 13:57 ` [PATCH v4 5/5] iotests: fix 141 after qmp_drive_backup with transactions Sergio Lopez
  4 siblings, 1 reply; 11+ messages in thread
From: Sergio Lopez @ 2019-11-21 13:57 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Sergio Lopez, Markus Armbruster, qemu-block, Max Reitz

bdrv_try_set_aio_context() requires that the old context is held, and
the new context is not held. Fix all the occurrences where it's not
done this way.

Suggested-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Sergio Lopez <slp@redhat.com>
---
 blockdev.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 58 insertions(+), 9 deletions(-)

diff --git a/blockdev.c b/blockdev.c
index 152a0f7454..b0647d8d33 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1535,6 +1535,7 @@ static void external_snapshot_prepare(BlkActionState *common,
                              DO_UPCAST(ExternalSnapshotState, common, common);
     TransactionAction *action = common->action;
     AioContext *aio_context;
+    AioContext *old_context;
     int ret;
 
     /* 'blockdev-snapshot' and 'blockdev-snapshot-sync' have similar
@@ -1675,11 +1676,20 @@ static void external_snapshot_prepare(BlkActionState *common,
         goto out;
     }
 
+    /* Honor bdrv_try_set_aio_context() context acquisition requirements. */
+    old_context = bdrv_get_aio_context(state->new_bs);
+    aio_context_release(aio_context);
+    aio_context_acquire(old_context);
+
     ret = bdrv_try_set_aio_context(state->new_bs, aio_context, errp);
     if (ret < 0) {
-        goto out;
+        aio_context_release(old_context);
+        return;
     }
 
+    aio_context_release(old_context);
+    aio_context_acquire(aio_context);
+
     /* This removes our old bs and adds the new bs. This is an operation that
      * can fail, so we need to do it in .prepare; undoing it for abort is
      * always possible. */
@@ -1775,11 +1785,13 @@ static void drive_backup_prepare(BlkActionState *common, Error **errp)
     BlockDriverState *target_bs;
     BlockDriverState *source = NULL;
     AioContext *aio_context;
+    AioContext *old_context;
     QDict *options;
     Error *local_err = NULL;
     int flags;
     int64_t size;
     bool set_backing_hd = false;
+    int ret;
 
     assert(common->action->type == TRANSACTION_ACTION_KIND_DRIVE_BACKUP);
     backup = common->action->u.drive_backup.data;
@@ -1868,6 +1880,20 @@ static void drive_backup_prepare(BlkActionState *common, Error **errp)
         goto out;
     }
 
+    /* Honor bdrv_try_set_aio_context() context acquisition requirements. */
+    old_context = bdrv_get_aio_context(target_bs);
+    aio_context_release(aio_context);
+    aio_context_acquire(old_context);
+
+    ret = bdrv_try_set_aio_context(target_bs, aio_context, errp);
+    if (ret < 0) {
+        aio_context_release(old_context);
+        return;
+     }
+
+    aio_context_release(old_context);
+    aio_context_acquire(aio_context);
+
     if (set_backing_hd) {
         bdrv_set_backing_hd(target_bs, source, &local_err);
         if (local_err) {
@@ -1947,6 +1973,8 @@ static void blockdev_backup_prepare(BlkActionState *common, Error **errp)
     BlockDriverState *bs;
     BlockDriverState *target_bs;
     AioContext *aio_context;
+    AioContext *old_context;
+    int ret;
 
     assert(common->action->type == TRANSACTION_ACTION_KIND_BLOCKDEV_BACKUP);
     backup = common->action->u.blockdev_backup.data;
@@ -1961,7 +1989,18 @@ static void blockdev_backup_prepare(BlkActionState *common, Error **errp)
         return;
     }
 
+    /* Honor bdrv_try_set_aio_context() context acquisition requirements. */
     aio_context = bdrv_get_aio_context(bs);
+    old_context = bdrv_get_aio_context(target_bs);
+    aio_context_acquire(old_context);
+
+    ret = bdrv_try_set_aio_context(target_bs, aio_context, errp);
+    if (ret < 0) {
+        aio_context_release(old_context);
+        return;
+    }
+
+    aio_context_release(old_context);
     aio_context_acquire(aio_context);
     state->bs = bs;
 
@@ -3562,7 +3601,6 @@ static BlockJob *do_backup_common(BackupCommon *backup,
     BlockJob *job = NULL;
     BdrvDirtyBitmap *bmap = NULL;
     int job_flags = JOB_DEFAULT;
-    int ret;
 
     if (!backup->has_speed) {
         backup->speed = 0;
@@ -3586,11 +3624,6 @@ static BlockJob *do_backup_common(BackupCommon *backup,
         backup->compress = false;
     }
 
-    ret = bdrv_try_set_aio_context(target_bs, aio_context, errp);
-    if (ret < 0) {
-        return NULL;
-    }
-
     if ((backup->sync == MIRROR_SYNC_MODE_BITMAP) ||
         (backup->sync == MIRROR_SYNC_MODE_INCREMENTAL)) {
         /* done before desugaring 'incremental' to print the right message */
@@ -3825,6 +3858,7 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
     BlockDriverState *bs;
     BlockDriverState *source, *target_bs;
     AioContext *aio_context;
+    AioContext *old_context;
     BlockMirrorBackingMode backing_mode;
     Error *local_err = NULL;
     QDict *options = NULL;
@@ -3937,12 +3971,22 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
                    (arg->mode == NEW_IMAGE_MODE_EXISTING ||
                     !bdrv_has_zero_init(target_bs)));
 
+
+    /* Honor bdrv_try_set_aio_context() context acquisition requirements. */
+    old_context = bdrv_get_aio_context(target_bs);
+    aio_context_release(aio_context);
+    aio_context_acquire(old_context);
+
     ret = bdrv_try_set_aio_context(target_bs, aio_context, errp);
     if (ret < 0) {
         bdrv_unref(target_bs);
-        goto out;
+        aio_context_release(old_context);
+        return;
     }
 
+    aio_context_release(old_context);
+    aio_context_acquire(aio_context);
+
     blockdev_mirror_common(arg->has_job_id ? arg->job_id : NULL, bs, target_bs,
                            arg->has_replaces, arg->replaces, arg->sync,
                            backing_mode, zero_target,
@@ -3984,6 +4028,7 @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id,
     BlockDriverState *bs;
     BlockDriverState *target_bs;
     AioContext *aio_context;
+    AioContext *old_context;
     BlockMirrorBackingMode backing_mode = MIRROR_LEAVE_BACKING_CHAIN;
     Error *local_err = NULL;
     bool zero_target;
@@ -4001,14 +4046,18 @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id,
 
     zero_target = (sync == MIRROR_SYNC_MODE_FULL);
 
+    /* Honor bdrv_try_set_aio_context() context acquisition requirements. */
+    old_context = bdrv_get_aio_context(target_bs);
     aio_context = bdrv_get_aio_context(bs);
-    aio_context_acquire(aio_context);
+    aio_context_acquire(old_context);
 
     ret = bdrv_try_set_aio_context(target_bs, aio_context, errp);
     if (ret < 0) {
         goto out;
     }
 
+    aio_context_acquire(aio_context);
+
     blockdev_mirror_common(has_job_id ? job_id : NULL, bs, target_bs,
                            has_replaces, replaces, sync, backing_mode,
                            zero_target, has_speed, speed,
-- 
2.23.0



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

* [PATCH v4 5/5] iotests: fix 141 after qmp_drive_backup with transactions
  2019-11-21 13:57 [PATCH v4 0/5] blockdev: avoid acquiring AioContext lock twice at do_drive_backup and do_blockdev_backup Sergio Lopez
                   ` (3 preceding siblings ...)
  2019-11-21 13:57 ` [PATCH v4 4/5] blockdev: honor bdrv_try_set_aio_context() context requirements Sergio Lopez
@ 2019-11-21 13:57 ` Sergio Lopez
  2019-11-27 16:19   ` Max Reitz
  4 siblings, 1 reply; 11+ messages in thread
From: Sergio Lopez @ 2019-11-21 13:57 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Sergio Lopez, Markus Armbruster, qemu-block, Max Reitz

qmp_drive_backup now creates and starts a transactions, which implies
that the job will transition to pause and running twice. Fix test 141
to be aware of this change.

Signed-off-by: Sergio Lopez <slp@redhat.com>
---
 tests/qemu-iotests/141.out | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/tests/qemu-iotests/141.out b/tests/qemu-iotests/141.out
index 3645675ce8..263b680bdf 100644
--- a/tests/qemu-iotests/141.out
+++ b/tests/qemu-iotests/141.out
@@ -13,6 +13,8 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/m.
 Formatting 'TEST_DIR/o.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT backing_fmt=IMGFMT
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job0"}}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}}
+{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "paused", "id": "job0"}}
+{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}}
 {'execute': 'blockdev-del', 'arguments': {'node-name': 'drv0'}}
 {"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: node is used as backing hd of 'NODE_NAME'"}}
 {'execute': 'block-job-cancel', 'arguments': {'device': 'job0'}}
-- 
2.23.0



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

* Re: [PATCH v4 1/5] blockdev: fix coding style issues in drive_backup_prepare
  2019-11-21 13:57 ` [PATCH v4 1/5] blockdev: fix coding style issues in drive_backup_prepare Sergio Lopez
@ 2019-11-27 15:53   ` Max Reitz
  0 siblings, 0 replies; 11+ messages in thread
From: Max Reitz @ 2019-11-27 15:53 UTC (permalink / raw)
  To: Sergio Lopez, qemu-devel; +Cc: Kevin Wolf, Markus Armbruster, qemu-block


[-- Attachment #1.1: Type: text/plain, Size: 297 bytes --]

On 21.11.19 14:57, Sergio Lopez wrote:
> Fix a couple of minor coding style issues in drive_backup_prepare.
> 
> Signed-off-by: Sergio Lopez <slp@redhat.com>
> ---
>  blockdev.c | 8 +++++---
>  1 file changed, 5 insertions(+), 3 deletions(-)

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


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

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

* Re: [PATCH v4 5/5] iotests: fix 141 after qmp_drive_backup with transactions
  2019-11-21 13:57 ` [PATCH v4 5/5] iotests: fix 141 after qmp_drive_backup with transactions Sergio Lopez
@ 2019-11-27 16:19   ` Max Reitz
  0 siblings, 0 replies; 11+ messages in thread
From: Max Reitz @ 2019-11-27 16:19 UTC (permalink / raw)
  To: Sergio Lopez, qemu-devel; +Cc: Kevin Wolf, Markus Armbruster, qemu-block


[-- Attachment #1.1: Type: text/plain, Size: 587 bytes --]

On 21.11.19 14:57, Sergio Lopez wrote:
> qmp_drive_backup now creates and starts a transactions, which implies
> that the job will transition to pause and running twice. Fix test 141
> to be aware of this change.
> 
> Signed-off-by: Sergio Lopez <slp@redhat.com>
> ---
>  tests/qemu-iotests/141.out | 2 ++
>  1 file changed, 2 insertions(+)

Test reference output adjustments belong in the patches that caused them
so as not to break bisecting.  So this should be part of patch 2.

Furthermore, 185 fails of the very same reason, and 219 now runs into a
timeout.

Max


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

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

* Re: [PATCH v4 2/5] blockdev: unify qmp_drive_backup and drive-backup transaction paths
  2019-11-21 13:57 ` [PATCH v4 2/5] blockdev: unify qmp_drive_backup and drive-backup transaction paths Sergio Lopez
@ 2019-11-27 16:37   ` Max Reitz
  0 siblings, 0 replies; 11+ messages in thread
From: Max Reitz @ 2019-11-27 16:37 UTC (permalink / raw)
  To: Sergio Lopez, qemu-devel; +Cc: Kevin Wolf, Markus Armbruster, qemu-block


[-- Attachment #1.1: Type: text/plain, Size: 1042 bytes --]

On 21.11.19 14:57, Sergio Lopez wrote:
> Issuing a drive-backup from qmp_drive_backup takes a slightly
> different path than when it's issued from a transaction. In the code,
> this is manifested as some redundancy between do_drive_backup() and
> drive_backup_prepare().
> 
> This change unifies both paths, merging do_drive_backup() and
> drive_backup_prepare(), and changing qmp_drive_backup() to create a
> transaction instead of calling do_backup_common() direcly.
> 
> As a side-effect, now qmp_drive_backup() is executed inside a drained
> section, as it happens when creating a drive-backup transaction. This
> change is visible from the user's perspective, as the job gets paused
> and immediately resumed before starting the actual work.
> 
> Signed-off-by: Sergio Lopez <slp@redhat.com>
> ---
>  blockdev.c | 224 ++++++++++++++++++++++++-----------------------------
>  1 file changed, 100 insertions(+), 124 deletions(-)

Looks good to me, although it needs to keep the tests passing that now
break.

Max


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

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

* Re: [PATCH v4 3/5] blockdev: unify qmp_blockdev_backup and blockdev-backup transaction paths
  2019-11-21 13:57 ` [PATCH v4 3/5] blockdev: unify qmp_blockdev_backup and blockdev-backup " Sergio Lopez
@ 2019-11-27 16:49   ` Max Reitz
  0 siblings, 0 replies; 11+ messages in thread
From: Max Reitz @ 2019-11-27 16:49 UTC (permalink / raw)
  To: Sergio Lopez, qemu-devel; +Cc: Kevin Wolf, Markus Armbruster, qemu-block


[-- Attachment #1.1: Type: text/plain, Size: 2133 bytes --]

On 21.11.19 14:57, Sergio Lopez wrote:
> Issuing a blockdev-backup from qmp_blockdev_backup takes a slightly
> different path than when it's issued from a transaction. In the code,
> this is manifested as some redundancy between do_blockdev_backup() and
> blockdev_backup_prepare().
> 
> This change unifies both paths, merging do_blockdev_backup() and
> blockdev_backup_prepare(), and changing qmp_blockdev_backup() to
> create a transaction instead of calling do_backup_common() direcly.
> 
> As a side-effect, now qmp_blockdev_backup() is executed inside a
> drained section, as it happens when creating a blockdev-backup
> transaction. This change is visible from the user's perspective, as
> the job gets paused and immediately resumed before starting the actual
> work.
> 
> Signed-off-by: Sergio Lopez <slp@redhat.com>
> ---
>  blockdev.c | 60 ++++++++++++------------------------------------------
>  1 file changed, 13 insertions(+), 47 deletions(-)
> 
> diff --git a/blockdev.c b/blockdev.c
> index 5e85fc042e..152a0f7454 100644
> --- a/blockdev.c
> +++ b/blockdev.c

[...]

>  static void blockdev_backup_prepare(BlkActionState *common, Error **errp)
>  {
>      BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common);
>      BlockdevBackup *backup;
> -    BlockDriverState *bs, *target;
> +    BlockDriverState *bs;
> +    BlockDriverState *target_bs;

The diff stat could have been a bit smaller by keeping this as it was,
but either way:

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

>      AioContext *aio_context;
> -    Error *local_err = NULL;
>  
>      assert(common->action->type == TRANSACTION_ACTION_KIND_BLOCKDEV_BACKUP);
>      backup = common->action->u.blockdev_backup.data;
> @@ -1959,8 +1956,8 @@ static void blockdev_backup_prepare(BlkActionState *common, Error **errp)
>          return;
>      }
>  
> -    target = bdrv_lookup_bs(backup->target, backup->target, errp);
> -    if (!target) {
> +    target_bs = bdrv_lookup_bs(backup->target, backup->target, errp);
> +    if (!target_bs) {
>          return;
>      }
>  


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

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

* Re: [PATCH v4 4/5] blockdev: honor bdrv_try_set_aio_context() context requirements
  2019-11-21 13:57 ` [PATCH v4 4/5] blockdev: honor bdrv_try_set_aio_context() context requirements Sergio Lopez
@ 2019-11-27 17:10   ` Max Reitz
  0 siblings, 0 replies; 11+ messages in thread
From: Max Reitz @ 2019-11-27 17:10 UTC (permalink / raw)
  To: Sergio Lopez, qemu-devel; +Cc: Kevin Wolf, Markus Armbruster, qemu-block


[-- Attachment #1.1: Type: text/plain, Size: 2616 bytes --]

On 21.11.19 14:57, Sergio Lopez wrote:
> bdrv_try_set_aio_context() requires that the old context is held, and
> the new context is not held. Fix all the occurrences where it's not
> done this way.
> 
> Suggested-by: Max Reitz <mreitz@redhat.com>
> Signed-off-by: Sergio Lopez <slp@redhat.com>
> ---
>  blockdev.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++--------
>  1 file changed, 58 insertions(+), 9 deletions(-)

I wonder whether we even need to set the target’s context, because I
suppose it should be done automatically when it is attached to the
backup job with bdrv_attach_child() in bdrv_backup_top_append().  *shrug*

> diff --git a/blockdev.c b/blockdev.c
> index 152a0f7454..b0647d8d33 100644
> --- a/blockdev.c
> +++ b/blockdev.c

[...]

> @@ -1868,6 +1880,20 @@ static void drive_backup_prepare(BlkActionState *common, Error **errp)
>          goto out;
>      }
>  
> +    /* Honor bdrv_try_set_aio_context() context acquisition requirements. */
> +    old_context = bdrv_get_aio_context(target_bs);
> +    aio_context_release(aio_context);
> +    aio_context_acquire(old_context);
> +
> +    ret = bdrv_try_set_aio_context(target_bs, aio_context, errp);
> +    if (ret < 0) {
> +        aio_context_release(old_context);
> +        return;
> +     }
> +
> +    aio_context_release(old_context);
> +    aio_context_acquire(aio_context);

Would it work to put the error block after these two calls so it can
just goto out again?  (Which would help if someone were to e.g.
introduce a new resource that is to be freed behind the out label.)

>      if (set_backing_hd) {
>          bdrv_set_backing_hd(target_bs, source, &local_err);
>          if (local_err) {

[...]

> @@ -4001,14 +4046,18 @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id,
>  
>      zero_target = (sync == MIRROR_SYNC_MODE_FULL);
>  
> +    /* Honor bdrv_try_set_aio_context() context acquisition requirements. */
> +    old_context = bdrv_get_aio_context(target_bs);
>      aio_context = bdrv_get_aio_context(bs);
> -    aio_context_acquire(aio_context);
> +    aio_context_acquire(old_context);
>  
>      ret = bdrv_try_set_aio_context(target_bs, aio_context, errp);
>      if (ret < 0) {
>          goto out;
>      }
>  
> +    aio_context_acquire(aio_context);
> +

old_context is never released here.

Max

>      blockdev_mirror_common(has_job_id ? job_id : NULL, bs, target_bs,
>                             has_replaces, replaces, sync, backing_mode,
>                             zero_target, has_speed, speed,
> 



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

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

end of thread, other threads:[~2019-11-27 17:12 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-11-21 13:57 [PATCH v4 0/5] blockdev: avoid acquiring AioContext lock twice at do_drive_backup and do_blockdev_backup Sergio Lopez
2019-11-21 13:57 ` [PATCH v4 1/5] blockdev: fix coding style issues in drive_backup_prepare Sergio Lopez
2019-11-27 15:53   ` Max Reitz
2019-11-21 13:57 ` [PATCH v4 2/5] blockdev: unify qmp_drive_backup and drive-backup transaction paths Sergio Lopez
2019-11-27 16:37   ` Max Reitz
2019-11-21 13:57 ` [PATCH v4 3/5] blockdev: unify qmp_blockdev_backup and blockdev-backup " Sergio Lopez
2019-11-27 16:49   ` Max Reitz
2019-11-21 13:57 ` [PATCH v4 4/5] blockdev: honor bdrv_try_set_aio_context() context requirements Sergio Lopez
2019-11-27 17:10   ` Max Reitz
2019-11-21 13:57 ` [PATCH v4 5/5] iotests: fix 141 after qmp_drive_backup with transactions Sergio Lopez
2019-11-27 16:19   ` 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).