All of lore.kernel.org
 help / color / mirror / Atom feed
From: Stefan Hajnoczi <stefanha@redhat.com>
To: qemu-devel@nongnu.org
Cc: Fam Zheng <famz@redhat.com>,
	Peter Maydell <peter.maydell@linaro.org>,
	John Snow <jsnow@redhat.com>,
	Stefan Hajnoczi <stefanha@redhat.com>
Subject: [Qemu-devel] [PULL 21/44] block: add transactional properties
Date: Tue, 10 Nov 2015 14:14:16 +0000	[thread overview]
Message-ID: <1447164879-6756-22-git-send-email-stefanha@redhat.com> (raw)
In-Reply-To: <1447164879-6756-1-git-send-email-stefanha@redhat.com>

From: John Snow <jsnow@redhat.com>

Add both transactional properties to the QMP transactional interface,
and add the BlockJobTxn that we create as a result of the err-cancel
property to the BlkActionState structure.

[split up from a patch originally by Stefan and Fam. --js]
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Fam Zheng <famz@redhat.com>
Signed-off-by: John Snow <jsnow@redhat.com>

Signed-off-by: John Snow <jsnow@redhat.com>
Message-id: 1446765200-3054-13-git-send-email-jsnow@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 blockdev.c       | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
 qapi-schema.json | 50 +++++++++++++++++++++++++++++++++---
 qmp-commands.hx  |  2 +-
 3 files changed, 122 insertions(+), 8 deletions(-)

diff --git a/blockdev.c b/blockdev.c
index 03b637b..9907822 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1131,7 +1131,7 @@ static void blockdev_do_action(TransactionActionKind type, void *data,
     action.u.data = data;
     list.value = &action;
     list.next = NULL;
-    qmp_transaction(&list, errp);
+    qmp_transaction(&list, false, NULL, errp);
 }
 
 void qmp_blockdev_snapshot_sync(bool has_device, const char *device,
@@ -1351,6 +1351,7 @@ typedef struct BlkActionOps {
  *
  * @action: QAPI-defined enum identifying which Action to perform.
  * @ops: Table of ActionOps this Action can perform.
+ * @block_job_txn: Transaction which this action belongs to.
  * @entry: List membership for all Actions in this Transaction.
  *
  * This structure must be arranged as first member in a subclassed type,
@@ -1360,6 +1361,8 @@ typedef struct BlkActionOps {
 struct BlkActionState {
     TransactionAction *action;
     const BlkActionOps *ops;
+    BlockJobTxn *block_job_txn;
+    TransactionProperties *txn_props;
     QSIMPLEQ_ENTRY(BlkActionState) entry;
 };
 
@@ -1372,6 +1375,20 @@ typedef struct InternalSnapshotState {
     bool created;
 } InternalSnapshotState;
 
+
+static int action_check_completion_mode(BlkActionState *s, Error **errp)
+{
+    if (s->txn_props->completion_mode != ACTION_COMPLETION_MODE_INDIVIDUAL) {
+        error_setg(errp,
+                   "Action '%s' does not support Transaction property "
+                   "completion-mode = %s",
+                   TransactionActionKind_lookup[s->action->type],
+                   ActionCompletionMode_lookup[s->txn_props->completion_mode]);
+        return -1;
+    }
+    return 0;
+}
+
 static void internal_snapshot_prepare(BlkActionState *common,
                                       Error **errp)
 {
@@ -1397,6 +1414,10 @@ static void internal_snapshot_prepare(BlkActionState *common,
     name = internal->name;
 
     /* 2. check for validation */
+    if (action_check_completion_mode(common, errp) < 0) {
+        return;
+    }
+
     blk = blk_by_name(device);
     if (!blk) {
         error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
@@ -1554,6 +1575,10 @@ static void external_snapshot_prepare(BlkActionState *common,
     }
 
     /* start processing */
+    if (action_check_completion_mode(common, errp) < 0) {
+        return;
+    }
+
     state->old_bs = bdrv_lookup_bs(has_device ? device : NULL,
                                    has_node_name ? node_name : NULL,
                                    &local_err);
@@ -1721,7 +1746,7 @@ static void drive_backup_prepare(BlkActionState *common, Error **errp)
                     backup->has_bitmap, backup->bitmap,
                     backup->has_on_source_error, backup->on_source_error,
                     backup->has_on_target_error, backup->on_target_error,
-                    NULL, &local_err);
+                    common->block_job_txn, &local_err);
     if (local_err) {
         error_propagate(errp, local_err);
         return;
@@ -1810,7 +1835,7 @@ static void blockdev_backup_prepare(BlkActionState *common, Error **errp)
                        backup->has_speed, backup->speed,
                        backup->has_on_source_error, backup->on_source_error,
                        backup->has_on_target_error, backup->on_target_error,
-                       NULL, &local_err);
+                       common->block_job_txn, &local_err);
     if (local_err) {
         error_propagate(errp, local_err);
         return;
@@ -1857,6 +1882,10 @@ static void block_dirty_bitmap_add_prepare(BlkActionState *common,
     BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
                                              common, common);
 
+    if (action_check_completion_mode(common, errp) < 0) {
+        return;
+    }
+
     action = common->action->u.block_dirty_bitmap_add;
     /* AIO context taken and released within qmp_block_dirty_bitmap_add */
     qmp_block_dirty_bitmap_add(action->node, action->name,
@@ -1892,6 +1921,10 @@ static void block_dirty_bitmap_clear_prepare(BlkActionState *common,
                                              common, common);
     BlockDirtyBitmap *action;
 
+    if (action_check_completion_mode(common, errp) < 0) {
+        return;
+    }
+
     action = common->action->u.block_dirty_bitmap_clear;
     state->bitmap = block_dirty_bitmap_lookup(action->node,
                                               action->name,
@@ -1995,19 +2028,50 @@ static const BlkActionOps actions[] = {
     }
 };
 
+/**
+ * Allocate a TransactionProperties structure if necessary, and fill
+ * that structure with desired defaults if they are unset.
+ */
+static TransactionProperties *get_transaction_properties(
+    TransactionProperties *props)
+{
+    if (!props) {
+        props = g_new0(TransactionProperties, 1);
+    }
+
+    if (!props->has_completion_mode) {
+        props->has_completion_mode = true;
+        props->completion_mode = ACTION_COMPLETION_MODE_INDIVIDUAL;
+    }
+
+    return props;
+}
+
 /*
  * 'Atomic' group operations.  The operations are performed as a set, and if
  * any fail then we roll back all operations in the group.
  */
-void qmp_transaction(TransactionActionList *dev_list, Error **errp)
+void qmp_transaction(TransactionActionList *dev_list,
+                     bool has_props,
+                     struct TransactionProperties *props,
+                     Error **errp)
 {
     TransactionActionList *dev_entry = dev_list;
+    BlockJobTxn *block_job_txn = NULL;
     BlkActionState *state, *next;
     Error *local_err = NULL;
 
     QSIMPLEQ_HEAD(snap_bdrv_states, BlkActionState) snap_bdrv_states;
     QSIMPLEQ_INIT(&snap_bdrv_states);
 
+    /* Does this transaction get canceled as a group on failure?
+     * If not, we don't really need to make a BlockJobTxn.
+     */
+    props = get_transaction_properties(props);
+    if (props->completion_mode != ACTION_COMPLETION_MODE_INDIVIDUAL) {
+        block_job_txn = block_job_txn_new();
+    }
+
     /* drain all i/o before any operations */
     bdrv_drain_all();
 
@@ -2027,6 +2091,8 @@ void qmp_transaction(TransactionActionList *dev_list, Error **errp)
         state = g_malloc0(ops->instance_size);
         state->ops = ops;
         state->action = dev_info;
+        state->block_job_txn = block_job_txn;
+        state->txn_props = props;
         QSIMPLEQ_INSERT_TAIL(&snap_bdrv_states, state, entry);
 
         state->ops->prepare(state, &local_err);
@@ -2059,6 +2125,10 @@ exit:
         }
         g_free(state);
     }
+    if (!has_props) {
+        qapi_free_TransactionProperties(props);
+    }
+    block_job_txn_unref(block_job_txn);
 }
 
 
diff --git a/qapi-schema.json b/qapi-schema.json
index dbab843..b9d02f4 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1520,6 +1520,26 @@
   'data': { } }
 
 ##
+# @ActionCompletionMode
+#
+# An enumeration of Transactional completion modes.
+#
+# @individual: Do not attempt to cancel any other Actions if any Actions fail
+#              after the Transaction request succeeds. All Actions that
+#              can complete successfully will do so without waiting on others.
+#              This is the default.
+#
+# @grouped: If any Action fails after the Transaction succeeds, cancel all
+#           Actions. Actions do not complete until all Actions are ready to
+#           complete. May be rejected by Actions that do not support this
+#           completion mode.
+#
+# Since: 2.5
+##
+{ 'enum': 'ActionCompletionMode',
+  'data': [ 'individual', 'grouped' ] }
+
+##
 # @TransactionAction
 #
 # A discriminated record of operations that can be performed with
@@ -1546,14 +1566,35 @@
    } }
 
 ##
+# @TransactionProperties
+#
+# Optional arguments to modify the behavior of a Transaction.
+#
+# @completion-mode: #optional Controls how jobs launched asynchronously by
+#                   Actions will complete or fail as a group.
+#                   See @ActionCompletionMode for details.
+#
+# Since: 2.5
+##
+{ 'struct': 'TransactionProperties',
+  'data': {
+       '*completion-mode': 'ActionCompletionMode'
+  }
+}
+
+##
 # @transaction
 #
 # Executes a number of transactionable QMP commands atomically. If any
 # operation fails, then the entire set of actions will be abandoned and the
 # appropriate error returned.
 #
-#  List of:
-#  @TransactionAction: information needed for the respective operation
+# @actions: List of @TransactionAction;
+#           information needed for the respective operations.
+#
+# @properties: #optional structure of additional options to control the
+#              execution of the transaction. See @TransactionProperties
+#              for additional detail.
 #
 # Returns: nothing on success
 #          Errors depend on the operations of the transaction
@@ -1565,7 +1606,10 @@
 # Since 1.1
 ##
 { 'command': 'transaction',
-  'data': { 'actions': [ 'TransactionAction' ] } }
+  'data': { 'actions': [ 'TransactionAction' ],
+            '*properties': 'TransactionProperties'
+          }
+}
 
 ##
 # @human-monitor-command:
diff --git a/qmp-commands.hx b/qmp-commands.hx
index d7cf0ff..7ba693a 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -1262,7 +1262,7 @@ EQMP
     },
     {
         .name       = "transaction",
-        .args_type  = "actions:q",
+        .args_type  = "actions:q,properties:q?",
         .mhandler.cmd_new = qmp_marshal_transaction,
     },
 
-- 
2.5.0

  parent reply	other threads:[~2015-11-10 14:15 UTC|newest]

Thread overview: 50+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-11-10 14:13 [Qemu-devel] [PULL 00/44] Block patches Stefan Hajnoczi
2015-11-10 14:13 ` [Qemu-devel] [PULL 01/44] block: Add more types for tracked request Stefan Hajnoczi
2015-11-10 14:13 ` [Qemu-devel] [PULL 02/44] block: Track flush requests Stefan Hajnoczi
2015-11-10 14:13 ` [Qemu-devel] [PULL 03/44] block: Track discard requests Stefan Hajnoczi
2015-11-10 14:13 ` [Qemu-devel] [PULL 04/44] iscsi: Emulate commands in iscsi_aio_ioctl as iscsi_ioctl Stefan Hajnoczi
2015-11-10 14:14 ` [Qemu-devel] [PULL 05/44] block: Add ioctl parameter fields to BlockRequest Stefan Hajnoczi
2015-11-10 14:14 ` [Qemu-devel] [PULL 06/44] block: Emulate bdrv_ioctl with bdrv_aio_ioctl and track both Stefan Hajnoczi
2015-11-10 14:14 ` [Qemu-devel] [PULL 07/44] block: Drop BlockDriver.bdrv_ioctl Stefan Hajnoczi
2015-11-10 14:14 ` [Qemu-devel] [PULL 08/44] block: Introduce BlockDriver.bdrv_drain callback Stefan Hajnoczi
2015-11-10 14:14 ` [Qemu-devel] [PULL 09/44] qed: Implement .bdrv_drain Stefan Hajnoczi
2015-11-10 14:14 ` [Qemu-devel] [PULL 10/44] qapi: Add transaction support to block-dirty-bitmap operations Stefan Hajnoczi
2015-11-10 14:14 ` [Qemu-devel] [PULL 11/44] iotests: add transactional incremental backup test Stefan Hajnoczi
2015-11-10 14:14 ` [Qemu-devel] [PULL 12/44] block: rename BlkTransactionState and BdrvActionOps Stefan Hajnoczi
2015-11-10 14:14 ` [Qemu-devel] [PULL 13/44] backup: Extract dirty bitmap handling as a separate function Stefan Hajnoczi
2015-11-10 14:14 ` [Qemu-devel] [PULL 14/44] blockjob: Introduce reference count and fix reference to job->bs Stefan Hajnoczi
2015-11-10 14:14 ` [Qemu-devel] [PULL 15/44] blockjob: Add .commit and .abort block job actions Stefan Hajnoczi
2015-11-10 14:14 ` [Qemu-devel] [PULL 16/44] blockjob: Add "completed" and "ret" in BlockJob Stefan Hajnoczi
2015-11-10 14:14 ` [Qemu-devel] [PULL 17/44] blockjob: Simplify block_job_finish_sync Stefan Hajnoczi
2015-11-10 14:14 ` [Qemu-devel] [PULL 18/44] block: Add block job transactions Stefan Hajnoczi
2015-11-10 14:14 ` [Qemu-devel] [PULL 19/44] block/backup: Rely on commit/abort for cleanup Stefan Hajnoczi
2015-11-10 14:14 ` [Qemu-devel] [PULL 20/44] block: Add BlockJobTxn support to backup_run Stefan Hajnoczi
2015-11-10 14:14 ` Stefan Hajnoczi [this message]
2015-11-10 14:14 ` [Qemu-devel] [PULL 22/44] iotests: 124 - transactional failure test Stefan Hajnoczi
2015-11-10 14:14 ` [Qemu-devel] [PULL 23/44] tests: add BlockJobTxn unit test Stefan Hajnoczi
2015-11-12 18:26   ` Eric Blake
2015-11-10 14:14 ` [Qemu-devel] [PULL 24/44] xen_disk: Account for flush operations Stefan Hajnoczi
2015-11-10 14:14 ` [Qemu-devel] [PULL 25/44] ide: Account for write operations correctly Stefan Hajnoczi
2015-11-10 14:14 ` [Qemu-devel] [PULL 26/44] block: define 'clock_type' for the accounting code Stefan Hajnoczi
2015-11-10 14:14 ` [Qemu-devel] [PULL 27/44] util: Infrastructure for computing recent averages Stefan Hajnoczi
2015-11-10 14:14 ` [Qemu-devel] [PULL 28/44] block: Add idle_time_ns to BlockDeviceStats Stefan Hajnoczi
2015-11-10 14:14 ` [Qemu-devel] [PULL 29/44] block: Add statistics for failed and invalid I/O operations Stefan Hajnoczi
2015-11-10 14:14 ` [Qemu-devel] [PULL 30/44] block: Allow configuring whether to account failed and invalid ops Stefan Hajnoczi
2015-11-10 14:14 ` [Qemu-devel] [PULL 31/44] block: Compute minimum, maximum and average I/O latencies Stefan Hajnoczi
2015-11-10 14:14 ` [Qemu-devel] [PULL 32/44] block: Add average I/O queue depth to BlockDeviceTimedStats Stefan Hajnoczi
2015-11-10 14:14 ` [Qemu-devel] [PULL 33/44] block: New option to define the intervals for collecting I/O statistics Stefan Hajnoczi
2015-11-10 17:23   ` Eric Blake
2015-11-10 18:49     ` Markus Armbruster
2015-11-11 11:10     ` Alberto Garcia
2015-11-10 14:14 ` [Qemu-devel] [PULL 34/44] qemu-io: Account for failed, invalid and flush operations Stefan Hajnoczi
2015-11-10 14:14 ` [Qemu-devel] [PULL 35/44] block: Use QEMU_CLOCK_VIRTUAL for the accounting code in qtest mode Stefan Hajnoczi
2015-11-10 15:08   ` Paolo Bonzini
2015-11-10 14:14 ` [Qemu-devel] [PULL 36/44] iotests: Add test for the block device statistics Stefan Hajnoczi
2015-11-10 14:14 ` [Qemu-devel] [PULL 37/44] nvme: Account for failed and invalid operations Stefan Hajnoczi
2015-11-10 14:14 ` [Qemu-devel] [PULL 38/44] virtio-blk: " Stefan Hajnoczi
2015-11-10 14:14 ` [Qemu-devel] [PULL 39/44] xen_disk: " Stefan Hajnoczi
2015-11-10 14:14 ` [Qemu-devel] [PULL 40/44] atapi: " Stefan Hajnoczi
2015-11-10 14:14 ` [Qemu-devel] [PULL 41/44] ide: " Stefan Hajnoczi
2015-11-10 14:14 ` [Qemu-devel] [PULL 42/44] macio: Account for failed operations Stefan Hajnoczi
2015-11-10 14:14 ` [Qemu-devel] [PULL 43/44] scsi-disk: " Stefan Hajnoczi
2015-11-10 14:14 ` [Qemu-devel] [PULL 44/44] block: Update copyright of the accounting code Stefan Hajnoczi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1447164879-6756-22-git-send-email-stefanha@redhat.com \
    --to=stefanha@redhat.com \
    --cc=famz@redhat.com \
    --cc=jsnow@redhat.com \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.