From patchwork Wed Sep 11 06:04:34 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wayne Xia X-Patchwork-Id: 274125 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id ED7A22C008A for ; Wed, 11 Sep 2013 16:07:48 +1000 (EST) Received: from localhost ([::1]:33137 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VJdac-0001fT-VN for incoming@patchwork.ozlabs.org; Wed, 11 Sep 2013 02:07:46 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:51329) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VJdY6-0007C0-AR for qemu-devel@nongnu.org; Wed, 11 Sep 2013 02:05:20 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1VJdXv-00055Q-5D for qemu-devel@nongnu.org; Wed, 11 Sep 2013 02:05:10 -0400 Received: from e28smtp06.in.ibm.com ([122.248.162.6]:56394) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1VJdXu-000556-7K for qemu-devel@nongnu.org; Wed, 11 Sep 2013 02:04:59 -0400 Received: from /spool/local by e28smtp06.in.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Wed, 11 Sep 2013 11:24:38 +0530 Received: from d28dlp03.in.ibm.com (9.184.220.128) by e28smtp06.in.ibm.com (192.168.1.136) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Wed, 11 Sep 2013 11:24:36 +0530 Received: from d28relay05.in.ibm.com (d28relay05.in.ibm.com [9.184.220.62]) by d28dlp03.in.ibm.com (Postfix) with ESMTP id B0FEB1258043 for ; Wed, 11 Sep 2013 11:34:55 +0530 (IST) Received: from d28av02.in.ibm.com (d28av02.in.ibm.com [9.184.220.64]) by d28relay05.in.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id r8B64pMS42664130 for ; Wed, 11 Sep 2013 11:34:51 +0530 Received: from d28av02.in.ibm.com (localhost [127.0.0.1]) by d28av02.in.ibm.com (8.14.4/8.14.4/NCO v10.0 AVout) with ESMTP id r8B64qEF018224 for ; Wed, 11 Sep 2013 11:34:52 +0530 Received: from RH64wenchao ([9.181.129.59]) by d28av02.in.ibm.com (8.14.4/8.14.4/NCO v10.0 AVin) with ESMTP id r8B64iZ7017691; Wed, 11 Sep 2013 11:34:51 +0530 From: Wenchao Xia To: qemu-devel@nongnu.org Date: Wed, 11 Sep 2013 14:04:34 +0800 Message-Id: <1378879479-10068-4-git-send-email-xiawenc@linux.vnet.ibm.com> X-Mailer: git-send-email 1.7.1 In-Reply-To: <1378879479-10068-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1378879479-10068-1-git-send-email-xiawenc@linux.vnet.ibm.com> X-TM-AS-MML: No X-Content-Scanned: Fidelis XPS MAILER x-cbid: 13091105-9574-0000-0000-000009932953 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.4.x-2.6.x [generic] X-Received-From: 122.248.162.6 Cc: kwolf@redhat.com, phrdina@redhat.com, famz@redhat.com, Wenchao Xia , armbru@redhat.com, lcapitulino@redhat.com, stefanha@redhat.com, pbonzini@redhat.com, dietmar@proxmox.com Subject: [Qemu-devel] [PATCH V8 3/8] qmp: add internal snapshot support in qmp_transaction X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Unlike savevm, the qmp_transaction interface will not generate snapshot name automatically, saving trouble to return information of the new created snapshot. Although qcow2 support storing multiple snapshots with same name but different ID, here it will fail when an snapshot with that name already exist before the operation. Format such as rbd do not support ID at all, and in most case, it means trouble to user when he faces multiple snapshots with same name, so ban that case. Request with empty name will be rejected. Snapshot ID can't be specified in this interface. Signed-off-by: Wenchao Xia --- blockdev.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ qapi-schema.json | 19 ++++++++- qmp-commands.hx | 34 ++++++++++++---- 3 files changed, 160 insertions(+), 9 deletions(-) diff --git a/blockdev.c b/blockdev.c index e70e16e..b30c541 100644 --- a/blockdev.c +++ b/blockdev.c @@ -875,6 +875,117 @@ struct BlkTransactionState { QSIMPLEQ_ENTRY(BlkTransactionState) entry; }; +/* internal snapshot private data */ +typedef struct InternalSnapshotState { + BlkTransactionState common; + BlockDriverState *bs; + QEMUSnapshotInfo sn; +} InternalSnapshotState; + +static void internal_snapshot_prepare(BlkTransactionState *common, + Error **errp) +{ + const char *device; + const char *name; + BlockDriverState *bs; + QEMUSnapshotInfo old_sn, *sn; + bool ret; + qemu_timeval tv; + BlockdevSnapshotInternal *internal; + InternalSnapshotState *state; + int ret1; + + g_assert(common->action->kind == + TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_INTERNAL_SYNC); + internal = common->action->blockdev_snapshot_internal_sync; + state = DO_UPCAST(InternalSnapshotState, common, common); + + /* 1. parse input */ + device = internal->device; + name = internal->name; + + /* 2. check for validation */ + bs = bdrv_find(device); + if (!bs) { + error_set(errp, QERR_DEVICE_NOT_FOUND, device); + return; + } + + if (!bdrv_is_inserted(bs)) { + error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device); + return; + } + + if (bdrv_is_read_only(bs)) { + error_set(errp, QERR_DEVICE_IS_READ_ONLY, device); + return; + } + + if (!bdrv_can_snapshot(bs)) { + error_set(errp, QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED, + bs->drv->format_name, device, "internal snapshot"); + 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, errp); + if (error_is_set(errp)) { + 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->bs = bs; +} + +static void internal_snapshot_abort(BlkTransactionState *common) +{ + InternalSnapshotState *state = + DO_UPCAST(InternalSnapshotState, common, common); + BlockDriverState *bs = state->bs; + QEMUSnapshotInfo *sn = &state->sn; + Error *local_error = NULL; + + if (!bs) { + return; + } + + if (bdrv_snapshot_delete(bs, sn->id_str, sn->name, &local_error) < 0) { + error_report("Failed to delete snapshot with id '%s' and name '%s' on " + "device '%s' in abort: %s", + sn->id_str, + sn->name, + bdrv_get_device_name(bs), + error_get_pretty(local_error)); + error_free(local_error); + } +} + /* external snapshot private data */ typedef struct ExternalSnapshotState { BlkTransactionState common; @@ -1058,6 +1169,11 @@ static const BdrvActionOps actions[] = { .prepare = abort_prepare, .commit = abort_commit, }, + [TRANSACTION_ACTION_KIND_BLOCKDEV_SNAPSHOT_INTERNAL_SYNC] = { + .instance_size = sizeof(InternalSnapshotState), + .prepare = internal_snapshot_prepare, + .abort = internal_snapshot_abort, + }, }; /* diff --git a/qapi-schema.json b/qapi-schema.json index a51f7d2..38663c5 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -1639,6 +1639,22 @@ '*mode': 'NewImageMode' } } ## +# @BlockdevSnapshotInternal +# +# @device: the name of the device to generate the snapshot from +# +# @name: the name of the internal snapshot to be created +# +# Notes: In transaction, if @name is empty, or any snapshot matching @name +# exists, the operation will fail. Only some image formats support it, +# for example, qcow2, rbd, and sheepdog. +# +# Since: 1.7 +## +{ 'type': 'BlockdevSnapshotInternal', + 'data': { 'device': 'str', 'name': 'str' } } + +## # @DriveBackup # # @device: the name of the device which should be copied. @@ -1700,7 +1716,8 @@ 'data': { 'blockdev-snapshot-sync': 'BlockdevSnapshot', 'drive-backup': 'DriveBackup', - 'abort': 'Abort' + 'abort': 'Abort', + 'blockdev-snapshot-internal-sync': 'BlockdevSnapshotInternal' } } ## diff --git a/qmp-commands.hx b/qmp-commands.hx index 8a8f342..59a38b5 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -1001,14 +1001,15 @@ SQMP transaction ----------- -Atomically operate on one or more block devices. The only supported -operation for now is snapshotting. If there is any failure performing -any of the operations, all snapshots for the group are abandoned, and -the original disks pre-snapshot attempt are used. +Atomically operate on one or more block devices. The only supported operations +for now are drive-backup, internal and external snapshotting. A list of +dictionaries is accepted, that contains the actions to be performed. +If there is any failure performing any of the operations, all operations +for the group are abandoned. -A list of dictionaries is accepted, that contains the actions to be performed. -For snapshots this is the device, the file to use for the new snapshot, -and the format. The default format, if not specified, is qcow2. +For external snapshots, the dictionary contains the device, the file to use for +the new snapshot, and the format. The default format, if not specified, is +qcow2. Each new snapshot defaults to being created by QEMU (wiping any contents if the file already exists), but it is also possible to reuse @@ -1017,6 +1018,17 @@ the new image file has the same contents as the current one; QEMU cannot perform any meaningful check. Typically this is achieved by using the current image file as the backing file for the new image. +On failure, the original disks pre-snapshot attempt will be used. + +For internal snapshots, the dictionary contains the device and the snapshot's +name. If an internal snapshot matching name already exists, the request will +be rejected. Only some image formats support it, for example, qcow2, rbd, +and sheepdog. + +On failure, qemu will try delete the newly created internal snapshot in the +transaction. When an I/O error occurs during deletion, the user needs to fix +it later with qemu-img or other command. + Arguments: actions array: @@ -1029,6 +1041,9 @@ actions array: - "format": format of new image (json-string, optional) - "mode": whether and how QEMU should create the snapshot file (NewImageMode, optional, default "absolute-paths") + When "type" is "blockdev-snapshot-internal-sync": + - "device": device name to snapshot (json-string) + - "name": name of the new snapshot (json-string) Example: @@ -1040,7 +1055,10 @@ Example: { 'type': 'blockdev-snapshot-sync', 'data' : { "device": "ide-hd1", "snapshot-file": "/some/place/my-image2", "mode": "existing", - "format": "qcow2" } } ] } } + "format": "qcow2" } }, + { 'type': 'blockdev-snapshot-internal-sync', 'data' : { + "device": "ide-hd2", + "name": "snapshot0" } } ] } } <- { "return": {} } EQMP