This patch switch to internal common API to take group external snapshots from qmp_transaction interface. qmp layer simply does a translation from user input.
Signed-off-by: Wenchao Xia <xiaw...@linux.vnet.ibm.com> --- blockdev.c | 215 ++++++++++++++++++++++++------------------------------------ 1 files changed, 87 insertions(+), 128 deletions(-) diff --git a/blockdev.c b/blockdev.c index 668506d..299039f 100644 --- a/blockdev.c +++ b/blockdev.c @@ -1173,157 +1173,116 @@ void qmp_blockdev_snapshot_sync(const char *device, const char *snapshot_file, errp); } - -/* New and old BlockDriverState structs for group snapshots */ -typedef struct BlkTransactionStates { - BlockDriverState *old_bs; - BlockDriverState *new_bs; - QSIMPLEQ_ENTRY(BlkTransactionStates) entry; -} BlkTransactionStates; - -/* - * 'Atomic' group snapshots. The snapshots are taken as a set, and if any fail - * then we do not pivot any of the devices in the group, and abandon the - * snapshots - */ -void qmp_transaction(BlockdevActionList *dev_list, Error **errp) +/* translation from qmp commands */ +static int fill_blk_trs_ext_create_sync(BlockdevSnapshot *create_sync, + BlkTransStatesSync *st_sync, + Error **errp) { - int ret = 0; - BlockdevActionList *dev_entry = dev_list; - BlkTransactionStates *states, *next; - Error *local_err = NULL; - - QSIMPLEQ_HEAD(snap_bdrv_states, BlkTransactionStates) snap_bdrv_states; - QSIMPLEQ_INIT(&snap_bdrv_states); + const char *format = "qcow2"; + enum NewImageMode mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS; + BlockDriverState *bs; + const char *device = create_sync->device; + const char *name = create_sync->snapshot_file; - /* drain all i/o before any snapshots */ - bdrv_drain_all(); + if (create_sync->has_mode) { + mode = create_sync->mode; + } + if (create_sync->has_format) { + format = create_sync->format; + } - /* We don't do anything in this loop that commits us to the snapshot */ - while (NULL != dev_entry) { - BlockdevAction *dev_info = NULL; - BlockDriver *proto_drv; - BlockDriver *drv; - int flags; - enum NewImageMode mode; - const char *new_image_file; - const char *device; - const char *format = "qcow2"; + /* find the target bs */ + bs = bdrv_find(device); + if (!bs) { + error_set(errp, QERR_DEVICE_NOT_FOUND, device); + return -1; + } - dev_info = dev_entry->value; - dev_entry = dev_entry->next; + switch (mode) { + case NEW_IMAGE_MODE_EXISTING: + st_sync->use_existing = true; + break; + case NEW_IMAGE_MODE_ABSOLUTE_PATHS: + st_sync->use_existing = false; + break; + default: + error_setg(errp, "Device %s requested invalid snapshot" + " mode %d.", device, mode); + return -1; + } - states = g_malloc0(sizeof(BlkTransactionStates)); - QSIMPLEQ_INSERT_TAIL(&snap_bdrv_states, states, entry); + st_sync->external.new_image_file = name; + st_sync->external.format = format; + st_sync->external.old_bs = bs; - switch (dev_info->kind) { - case BLOCKDEV_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC: - device = dev_info->blockdev_snapshot_sync->device; - if (!dev_info->blockdev_snapshot_sync->has_mode) { - dev_info->blockdev_snapshot_sync->mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS; - } - new_image_file = dev_info->blockdev_snapshot_sync->snapshot_file; - if (dev_info->blockdev_snapshot_sync->has_format) { - format = dev_info->blockdev_snapshot_sync->format; - } - mode = dev_info->blockdev_snapshot_sync->mode; - break; - default: - abort(); - } + return 0; +} - drv = bdrv_find_format(format); - if (!drv) { - error_set(errp, QERR_INVALID_BLOCK_FORMAT, format); - goto delete_and_fail; - } +static int fill_blk_trs(BlockdevAction *dev_info, + BlkTransStates *states, + SNTime *time, + const char *time_str, + Error **errp) +{ + int ret = 0; - states->old_bs = bdrv_find(device); - if (!states->old_bs) { - error_set(errp, QERR_DEVICE_NOT_FOUND, device); - goto delete_and_fail; - } + switch (dev_info->kind) { + case BLOCKDEV_ACTION_KIND_BLOCKDEV_SNAPSHOT_SYNC: + states->st_sync.type = BLK_SNAPSHOT_EXTERNAL; + states->st_sync.op = BLK_SN_SYNC_CREATE; + ret = fill_blk_trs_ext_create_sync(dev_info->blockdev_snapshot_sync, + &states->st_sync, + errp); + break; + default: + abort(); + } - if (!bdrv_is_inserted(states->old_bs)) { - error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device); - goto delete_and_fail; - } + return ret; +} - if (bdrv_in_use(states->old_bs)) { - error_set(errp, QERR_DEVICE_IN_USE, device); - goto delete_and_fail; - } +/* Here this funtion prepare the request list, submit for atomic snapshot. */ +void qmp_transaction(BlockdevActionList *dev_list, Error **errp) +{ + BlockdevActionList *dev_entry = dev_list; + BlkTransStates *states; + int ret; - if (!bdrv_is_read_only(states->old_bs)) { - if (bdrv_flush(states->old_bs)) { - error_set(errp, QERR_IO_ERROR); - goto delete_and_fail; - } - } + BlkTransStatesList *snap_bdrv_states = blk_trans_st_list_new(); - flags = states->old_bs->open_flags; + /* translate qmp request */ + /* for group snapshot create we use same time stamp here */ + SNTime time = get_sn_time(); + char time_str[256]; + generate_sn_name_from_time(&time, time_str, sizeof(time_str)); + while (NULL != dev_entry) { + BlockdevAction *dev_info = NULL; - proto_drv = bdrv_find_protocol(new_image_file); - if (!proto_drv) { - error_set(errp, QERR_INVALID_BLOCK_FORMAT, format); - goto delete_and_fail; - } + dev_info = dev_entry->value; + dev_entry = dev_entry->next; - /* create new image w/backing file */ - if (mode != NEW_IMAGE_MODE_EXISTING) { - bdrv_img_create(new_image_file, format, - states->old_bs->filename, - states->old_bs->drv->format_name, - NULL, -1, flags, &local_err); - if (error_is_set(&local_err)) { - error_propagate(errp, local_err); - goto delete_and_fail; - } + states = blk_trans_st_new(); + ret = fill_blk_trs(dev_info, states, &time, time_str, errp); + if (ret < 0) { + blk_trans_st_delete(&states); + goto exit; } - /* We will manually add the backing_hd field to the bs later */ - states->new_bs = bdrv_new(""); - ret = bdrv_open(states->new_bs, new_image_file, - flags | BDRV_O_NO_BACKING, drv); - if (ret != 0) { - error_set(errp, QERR_OPEN_FILE_FAILED, new_image_file); - goto delete_and_fail; + ret = add_transaction(snap_bdrv_states, states, errp); + if (ret < 0) { + blk_trans_st_delete(&states); + goto exit; } } + /* submit to internal API, no need to check return for no following + action now. */ + submit_transaction(snap_bdrv_states, errp); - /* Now we are going to do the actual pivot. Everything up to this point - * is reversible, but we are committed at this point */ - QSIMPLEQ_FOREACH(states, &snap_bdrv_states, entry) { - /* This removes our old bs from the bdrv_states, and adds the new bs */ - bdrv_append(states->new_bs, states->old_bs); - /* We don't need (or want) to use the transactional - * bdrv_reopen_multiple() across all the entries at once, because we - * don't want to abort all of them if one of them fails the reopen */ - bdrv_reopen(states->new_bs, states->new_bs->open_flags & ~BDRV_O_RDWR, - NULL); - } - - /* success */ - goto exit; - -delete_and_fail: - /* - * failure, and it is all-or-none; abandon each new bs, and keep using - * the original bs for all images - */ - QSIMPLEQ_FOREACH(states, &snap_bdrv_states, entry) { - if (states->new_bs) { - bdrv_delete(states->new_bs); - } - } exit: - QSIMPLEQ_FOREACH_SAFE(states, &snap_bdrv_states, entry, next) { - g_free(states); - } + blk_trans_st_list_delete(&snap_bdrv_states); } - static void eject_device(BlockDriverState *bs, int force, Error **errp) { if (bdrv_in_use(bs)) { -- 1.7.1