[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-block] [RFC] transactions: add transaction-wide property
From: |
Fam Zheng |
Subject: |
Re: [Qemu-block] [RFC] transactions: add transaction-wide property |
Date: |
Tue, 20 Oct 2015 15:26:33 +0800 |
User-agent: |
Mutt/1.5.21 (2010-09-15) |
On Thu, 09/24 17:40, John Snow wrote:
> This replaces the per-action property as in Fam's series.
> Instead, we have a transaction-wide property that is shared
> with each action.
>
> At the action level, if a property supplied transaction-wide
> is disagreeable, we return error and the transaction is aborted.
>
> RFC:
>
> Where this makes sense: Any transactional actions that aren't
> prepared to accept this new paradigm of transactional behavior
> can error_setg and return.
>
> Where this may not make sense: consider the transactions which
> do not use BlockJobs to perform their actions, i.e. they are
> synchronous during the transactional phase. Because they either
> fail or succeed so early, we might say that of course they can
> support this property ...
>
> ...however, consider the case where we create a new bitmap and
> perform a full backup, using allow_partial=false. If the backup
> fails, we might well expect the bitmap to be deleted because a
> member of the transaction ultimately/eventually failed. However,
> the bitmap creation was not undone because it does not have a
> pending/delayed abort/commit action -- those are only for jobs
> in this implementation.
>
> How do we fix this?
>
> (1) We just say "No, you can't use the new block job transaction
> completion mechanic in conjunction with these commands,"
>
> (2) We make Bitmap creation/resetting small, synchronous blockjobs
> that can join the BlockJobTxn
We could categorize commands as synchronous ones and long running ones, and
make it explicit that only long running jobs are affected by "allow_partial".
>
> Signed-off-by: John Snow <address@hidden>
> ---
> blockdev.c | 87
> ++++++++++++++++++++++++++++++++++++--------------
> blockjob.c | 2 +-
> qapi-schema.json | 15 +++++++--
> qapi/block-core.json | 26 ---------------
> qmp-commands.hx | 2 +-
> tests/qemu-iotests/124 | 12 +++----
> 6 files changed, 83 insertions(+), 61 deletions(-)
>
> diff --git a/blockdev.c b/blockdev.c
> index 45a9fe7..02b1a83 100644
> --- a/blockdev.c
> +++ b/blockdev.c
> @@ -1061,7 +1061,7 @@ static void blockdev_do_action(int kind, void *data,
> Error **errp)
> action.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,
> @@ -1286,6 +1286,7 @@ struct BlkActionState {
> TransactionAction *action;
> const BlkActionOps *ops;
> BlockJobTxn *block_job_txn;
> + TransactionProperties *txn_props;
> QSIMPLEQ_ENTRY(BlkActionState) entry;
> };
>
> @@ -1322,6 +1323,12 @@ static void internal_snapshot_prepare(BlkActionState
> *common,
> name = internal->name;
>
> /* 2. check for validation */
> + if (!common->txn_props->allow_partial) {
> + error_setg(errp,
> + "internal_snapshot does not support allow_partial =
> false");
> + return;
> + }
> +
> blk = blk_by_name(device);
> if (!blk) {
> error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
> @@ -1473,6 +1480,12 @@ static void external_snapshot_prepare(BlkActionState
> *common,
> }
>
> /* start processing */
> + if (!common->txn_props->allow_partial) {
> + error_setg(errp,
> + "external_snapshot does not support allow_partial =
> false");
> + return;
> + }
> +
> state->old_bs = bdrv_lookup_bs(has_device ? device : NULL,
> has_node_name ? node_name : NULL,
> &local_err);
> @@ -1603,14 +1616,11 @@ static void drive_backup_prepare(BlkActionState
> *common, Error **errp)
> DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common);
> BlockDriverState *bs;
> BlockBackend *blk;
> - DriveBackupTxn *backup_txn;
> DriveBackup *backup;
> - BlockJobTxn *txn = NULL;
> Error *local_err = NULL;
>
> assert(common->action->kind == TRANSACTION_ACTION_KIND_DRIVE_BACKUP);
> - backup_txn = common->action->drive_backup;
> - backup = backup_txn->base;
> + backup = common->action->drive_backup->base;
>
> blk = blk_by_name(backup->device);
> if (!blk) {
> @@ -1624,11 +1634,6 @@ static void drive_backup_prepare(BlkActionState
> *common, Error **errp)
> state->aio_context = bdrv_get_aio_context(bs);
> aio_context_acquire(state->aio_context);
>
> - if (backup_txn->has_transactional_cancel &&
> - backup_txn->transactional_cancel) {
> - txn = common->block_job_txn;
> - }
> -
> do_drive_backup(backup->device, backup->target,
> backup->has_format, backup->format,
> backup->sync,
> @@ -1637,7 +1642,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,
> - txn, &local_err);
> + common->block_job_txn, &local_err);
> if (local_err) {
> error_propagate(errp, local_err);
> return;
> @@ -1686,16 +1691,13 @@ static void do_blockdev_backup(const char *device,
> const char *target,
> static void blockdev_backup_prepare(BlkActionState *common, Error **errp)
> {
> BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common,
> common);
> - BlockdevBackupTxn *backup_txn;
> BlockdevBackup *backup;
> BlockDriverState *bs, *target;
> BlockBackend *blk;
> - BlockJobTxn *txn = NULL;
> Error *local_err = NULL;
>
> assert(common->action->kind == TRANSACTION_ACTION_KIND_BLOCKDEV_BACKUP);
> - backup_txn = common->action->blockdev_backup;
> - backup = backup_txn->base;
> + backup = common->action->blockdev_backup->base;
>
> blk = blk_by_name(backup->device);
> if (!blk) {
> @@ -1720,17 +1722,12 @@ static void blockdev_backup_prepare(BlkActionState
> *common, Error **errp)
> }
> aio_context_acquire(state->aio_context);
>
> - if (backup_txn->has_transactional_cancel &&
> - backup_txn->transactional_cancel) {
> - txn = common->block_job_txn;
> - }
> -
> do_blockdev_backup(backup->device, backup->target,
> backup->sync,
> backup->has_speed, backup->speed,
> backup->has_on_source_error, backup->on_source_error,
> backup->has_on_target_error, backup->on_target_error,
> - txn, &local_err);
> + common->block_job_txn, &local_err);
> if (local_err) {
> error_propagate(errp, local_err);
> return;
> @@ -1777,6 +1774,13 @@ static void
> block_dirty_bitmap_add_prepare(BlkActionState *common,
> BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
> common, common);
>
> + if (!common->txn_props->allow_partial) {
> + error_setg(errp,
> + "block_dirty_bitmap_add does not support "
> + "allow_partial = false");
> + return;
> + }
> +
> action = common->action->block_dirty_bitmap_add;
> /* AIO context taken and released within qmp_block_dirty_bitmap_add */
> qmp_block_dirty_bitmap_add(action->node, action->name,
> @@ -1812,6 +1816,13 @@ static void
> block_dirty_bitmap_clear_prepare(BlkActionState *common,
> common, common);
> BlockDirtyBitmap *action;
>
> + if (!common->txn_props->allow_partial) {
> + error_setg(errp,
> + "block_dirty_bitmap_clear does not support "
> + "allow_partial = false");
> + return;
> + }
> +
> action = common->action->block_dirty_bitmap_clear;
> state->bitmap = block_dirty_bitmap_lookup(action->node,
> action->name,
> @@ -1914,21 +1925,45 @@ 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)
Is this line too long?
> +{
> + if (!props) {
> + props = g_new0(TransactionProperties, 1);
> + }
> +
> + if (!props->has_allow_partial) {
> + props->allow_partial = true;
> + }
> +
> + 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 hasTransactionProperties,
Better as has_transaction_properties.
> + struct TransactionProperties *props,
> + Error **errp)
> {
> TransactionActionList *dev_entry = dev_list;
> - BlockJobTxn *block_job_txn;
> + 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);
>
> - block_job_txn = block_job_txn_new();
> + /* Does this transaction get *canceled* as a group on failure? */
> + props = get_transaction_properties(props);
> + if (props->allow_partial == false) {
> + block_job_txn = block_job_txn_new();
> + }
>
> /* drain all i/o before any operations */
> bdrv_drain_all();
> @@ -1950,6 +1985,7 @@ void qmp_transaction(TransactionActionList *dev_list,
> Error **errp)
> state->ops = ops;
> state->action = dev_info;
> state->block_job_txn = block_job_txn;
> + state->txn_props = props;
Is it better to make @props a member of BlockJobTxn instead? Or is there a new
way in QAPI to do this?
> QSIMPLEQ_INSERT_TAIL(&snap_bdrv_states, state, entry);
>
> state->ops->prepare(state, &local_err);
> @@ -1982,6 +2018,9 @@ exit:
> }
> g_free(state);
> }
> + if (!hasTransactionProperties) {
> + g_free(props);
> + }
> block_job_txn_unref(block_job_txn);
> }
>
Fam
- Re: [Qemu-block] [RFC] transactions: add transaction-wide property,
Fam Zheng <=