static void internal_snapshot_prepare(BlkActionState *common, Error **errp) { Error *local_err = NULL; const char *device; const char *name; BlockBackend *blk; BlockDriverState *bs; QEMUSnapshotInfo old_sn, *sn; bool ret; qemu_timeval tv; BlockdevSnapshotInternal *internal; InternalSnapshotState *state; int ret1; g_assert(common->action->type == TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_INTERNAL_SYNC); internal = common->action->u.blockdev_snapshot_internal_sync.data; state = DO_UPCAST(InternalSnapshotState, common, common); /* 1. parse input */ device = internal->device; 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, "Device '%s' not found", device); return; } /* AioContext is released in .clean() */ state->aio_context = blk_get_aio_context(blk); aio_context_acquire(state->aio_context); if (!blk_is_available(blk)) { error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, device); return; } bs = blk_bs(blk); state->bs = bs; bdrv_drained_begin(bs); if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT, errp)) { return; } if (bdrv_is_read_only(bs)) { error_setg(errp, "Device '%s' is read only", device); return; } if (!bdrv_can_snapshot(bs)) { error_setg(errp, "Block format '%s' used by device '%s' " "does not support internal snapshots", bs->drv->format_name, device); return; } if (!strlen(name)) { error_setg(errp, "Name is empty"); return; } /* check whether a snapshot with name exist */ ret = bdrv_snapshot_find_by_id_and_name(bs, NULL, name, &old_sn, &local_err); if (local_err) { error_propagate(errp, local_err); return; } else if (ret) { error_setg(errp, "Snapshot with name '%s' already exists on device '%s'", name, device); return; } /* 3. take the snapshot */ sn = &state->sn; pstrcpy(sn->name, sizeof(sn->name), name); qemu_gettimeofday(&tv); sn->date_sec = tv.tv_sec; sn->date_nsec = tv.tv_usec * 1000; sn->vm_clock_nsec = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); ret1 = bdrv_snapshot_create(bs, sn); if (ret1 < 0) { error_setg_errno(errp, -ret1, "Failed to create snapshot '%s' on device '%s'", name, device); return; } /* 4. succeed, mark a snapshot is created */ state->created = true; }