From patchwork Sat Jun 8 06:58:03 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wayne Xia X-Patchwork-Id: 249922 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 702322C0182 for ; Sat, 8 Jun 2013 17:02:08 +1000 (EST) Received: from localhost ([::1]:43181 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UlDA6-0004PD-GV for incoming@patchwork.ozlabs.org; Sat, 08 Jun 2013 03:02:06 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:53589) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UlD9Y-0004I8-I2 for qemu-devel@nongnu.org; Sat, 08 Jun 2013 03:01:35 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1UlD9W-0000b4-EB for qemu-devel@nongnu.org; Sat, 08 Jun 2013 03:01:32 -0400 Received: from e23smtp04.au.ibm.com ([202.81.31.146]:59648) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UlD9V-0000aN-Ku for qemu-devel@nongnu.org; Sat, 08 Jun 2013 03:01:30 -0400 Received: from /spool/local by e23smtp04.au.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Sat, 8 Jun 2013 16:47:40 +1000 Received: from d23dlp01.au.ibm.com (202.81.31.203) by e23smtp04.au.ibm.com (202.81.31.210) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Sat, 8 Jun 2013 16:47:38 +1000 Received: from d23relay05.au.ibm.com (d23relay05.au.ibm.com [9.190.235.152]) by d23dlp01.au.ibm.com (Postfix) with ESMTP id 7A66C2CE804A for ; Sat, 8 Jun 2013 17:01:23 +1000 (EST) Received: from d23av03.au.ibm.com (d23av03.au.ibm.com [9.190.234.97]) by d23relay05.au.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id r586kj1s46727288 for ; Sat, 8 Jun 2013 16:46:45 +1000 Received: from d23av03.au.ibm.com (loopback [127.0.0.1]) by d23av03.au.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id r5871M7E027801 for ; Sat, 8 Jun 2013 17:01:22 +1000 Received: from RH63Wenchao.localdomain ([9.125.31.72]) by d23av03.au.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with ESMTP id r586w9J1018747; Sat, 8 Jun 2013 17:01:19 +1000 From: Wenchao Xia To: qemu-devel@nongnu.org Date: Sat, 8 Jun 2013 14:58:03 +0800 Message-Id: <1370674687-13849-8-git-send-email-xiawenc@linux.vnet.ibm.com> X-Mailer: git-send-email 1.7.1 In-Reply-To: <1370674687-13849-1-git-send-email-xiawenc@linux.vnet.ibm.com> References: <1370674687-13849-1-git-send-email-xiawenc@linux.vnet.ibm.com> X-Content-Scanned: Fidelis XPS MAILER x-cbid: 13060806-9264-0000-0000-000003E65778 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.4.x-2.6.x [generic] X-Received-From: 202.81.31.146 Cc: kwolf@redhat.com, phrdina@redhat.com, Wenchao Xia , armbru@redhat.com, lcapitulino@redhat.com, stefanha@redhat.com, pbonzini@redhat.com, dietmar@proxmox.com Subject: [Qemu-devel] [PATCH 07/11] 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. The snapshot name should not mess up with snapshot ID, there is a check for it. 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. Snapshot ID can't be specified in this interface. Signed-off-by: Wenchao Xia --- blockdev.c | 118 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ qapi-schema.json | 16 +++++++ qmp-commands.hx | 32 +++++++++++--- 3 files changed, 159 insertions(+), 7 deletions(-) diff --git a/blockdev.c b/blockdev.c index 4bd6cbc..aaeb0e8 100644 --- a/blockdev.c +++ b/blockdev.c @@ -808,6 +808,119 @@ 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 sn, *sn1; + bool ret; + qemu_timeval tv; + BlockdevSnapshotInternal *internal; + InternalSnapshotState *state; + + 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; + } + + /* check whether a snapshot with name exist, no need to check id, since + name will be checked later to make sure it does not mess up with id. */ + ret = bdrv_snapshot_find_by_id_and_name(bs, NULL, name, &sn, errp); + if (error_is_set(errp)) { + return; + } + if (ret) { + error_setg(errp, "Snapshot with name %s already exist on device %s", + name, device); + return; + } + + /* Forbid having a name similar to id, empty name is also forbidden. */ + if (!snapshot_name_wellformed(name)) { + error_setg(errp, "Name %s on device %s is not a valid one", + name, device); + return; + } + + /* 3. take the snapshot */ + sn1 = &state->sn; + pstrcpy(sn1->name, sizeof(sn1->name), name); + qemu_gettimeofday(&tv); + sn1->date_sec = tv.tv_sec; + sn1->date_nsec = tv.tv_usec * 1000; + /* not good to use vm_clock in block layer, but that is what we can do now, + or drop it later, since it is an emulater concept. */ + sn1->vm_clock_nsec = qemu_get_clock_ns(vm_clock); + + if (bdrv_snapshot_create(bs, sn1) < 0) { + error_setg(errp, "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, reason is: %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; @@ -926,6 +1039,11 @@ static const BdrvActionOps actions[] = { .commit = external_snapshot_commit, .abort = external_snapshot_abort, }, + [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 5ad6894..9e143a8 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -1613,6 +1613,21 @@ { 'type': 'BlockdevSnapshot', 'data': { 'device': 'str', 'snapshot-file': 'str', '*format': 'str', '*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 any snapshot matching @name exist, the operation +# will fail. If the name is a numeric string, it will also fail. Only +# some image format support it, for example, qcow2, rbd, and sheepdog. +# +# Since: 1.6 +## +{ 'type': 'BlockdevSnapshotInternal', + 'data': { 'device': 'str', 'name': 'str' } } ## # @TransactionAction @@ -1623,6 +1638,7 @@ { 'union': 'TransactionAction', 'data': { 'blockdev-snapshot-sync': 'BlockdevSnapshot' + 'blockdev-snapshot-internal-sync': 'BlockdevSnapshotInternal' } } ## diff --git a/qmp-commands.hx b/qmp-commands.hx index 8cea5e5..d31f518 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -948,13 +948,13 @@ 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. +operations for now are internal and external snapshotting. A list of +dictionaries is accepted, that contains the actions to be performed. The +sequence of the requests will not affect the result. 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 snapshot, The dictionary is 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 @@ -963,6 +963,18 @@ 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 fail the original disks pre-snapshot attempt will be used. + +For internal snapshot, The dictionary is the device and the snapshot's name. +If name is a numeric string which will mess up with ID, the request will be +rejected. For example, name "99" is not a valid name. If an internal snapshot +matching name already exist, the request will be also rejected. Only some +image format support it, for example, qcow2, rbd, and sheepdog. + +On fail, qemu will try delete new created internal snapshot in the +transaction. When I/O error make delete fail, user need to fix it later +with qemu-img or other command. + Arguments: actions array: @@ -975,6 +987,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: @@ -986,7 +1001,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