}
}
+typedef struct DriveBackupState {
+ BlkTransactionState common;
+ BlockDriverState *bs;
+ BlockJob *job;
+} DriveBackupState;
+
+static void drive_backup_prepare(BlkTransactionState *common, Error **errp)
+{
+ DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common);
+ DriveBackup *backup;
+ Error *local_err = NULL;
+
+ assert(common->action->kind == TRANSACTION_ACTION_KIND_DRIVE_BACKUP);
+ backup = common->action->drive_backup;
+
+ qmp_drive_backup(backup->device, backup->target,
+ backup->has_format, backup->format,
+ backup->sync,
+ backup->has_mode, backup->mode,
+ backup->has_speed, backup->speed,
+ backup->has_on_source_error, backup->on_source_error,
+ backup->has_on_target_error, backup->on_target_error,
+ &local_err);
+ if (error_is_set(&local_err)) {
+ error_propagate(errp, local_err);
+ state->bs = NULL;
+ state->job = NULL;
+ return;
+ }
+
+ state->bs = bdrv_find(backup->device);
+ state->job = state->bs->job;
+}
+
+static void drive_backup_abort(BlkTransactionState *common)
+{
+ DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common);
+ BlockDriverState *bs = state->bs;
+
+ /* Only cancel if it's the job we started */
+ if (bs && bs->job && bs->job == state->job) {
+ block_job_cancel_sync(bs->job);
+ }
+}
+
+static void abort_prepare(BlkTransactionState *common, Error **errp)
+{
+ error_setg(errp, "Transaction aborted using Abort action");
+}
+
+static void abort_commit(BlkTransactionState *common)
+{
+ assert(false); /* this action never succeeds */
+}
+
static const BdrvActionOps actions[] = {
[TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC] = {
.instance_size = sizeof(ExternalSnapshotState),
.commit = external_snapshot_commit,
.abort = external_snapshot_abort,
},
+ [TRANSACTION_ACTION_KIND_DRIVE_BACKUP] = {
+ .instance_size = sizeof(DriveBackupState),
+ .prepare = drive_backup_prepare,
+ .abort = drive_backup_abort,
+ },
+ [TRANSACTION_ACTION_KIND_ABORT] = {
+ .instance_size = sizeof(BlkTransactionState),
+ .prepare = abort_prepare,
+ .commit = abort_commit,
+ },
};
/*
void qmp_drive_backup(const char *device, const char *target,
bool has_format, const char *format,
+ enum MirrorSyncMode sync,
bool has_mode, enum NewImageMode mode,
bool has_speed, int64_t speed,
bool has_on_source_error, BlockdevOnError on_source_error,
int64_t size;
int ret;
+ if (sync != MIRROR_SYNC_MODE_FULL) {
+ error_setg(errp, "only sync mode 'full' is currently supported");
+ return;
+ }
if (!has_speed) {
speed = 0;
}