From patchwork Mon Jul 29 04:25:31 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Fam Zheng X-Patchwork-Id: 262665 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 000D62C00FE for ; Mon, 29 Jul 2013 14:27:52 +1000 (EST) Received: from localhost ([::1]:51999 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1V3f3n-0007qV-3r for incoming@patchwork.ozlabs.org; Mon, 29 Jul 2013 00:27:51 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:54810) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1V3f29-0005QJ-Em for qemu-devel@nongnu.org; Mon, 29 Jul 2013 00:26:16 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1V3f23-0005xg-6l for qemu-devel@nongnu.org; Mon, 29 Jul 2013 00:26:09 -0400 Received: from mx1.redhat.com ([209.132.183.28]:4365) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1V3f22-0005xY-Vb for qemu-devel@nongnu.org; Mon, 29 Jul 2013 00:26:03 -0400 Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id r6T4Q2fd027055 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Mon, 29 Jul 2013 00:26:02 -0400 Received: from T430s.nay.redhat.com ([10.66.6.13]) by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id r6T4PnIw000956; Mon, 29 Jul 2013 00:25:59 -0400 From: Fam Zheng To: qemu-devel@nongnu.org Date: Mon, 29 Jul 2013 12:25:31 +0800 Message-Id: <1375071932-31627-4-git-send-email-famz@redhat.com> In-Reply-To: <1375071932-31627-1-git-send-email-famz@redhat.com> References: <1375071932-31627-1-git-send-email-famz@redhat.com> X-Scanned-By: MIMEDefang 2.67 on 10.5.11.11 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 Cc: kwolf@redhat.com, famz@redhat.com, imain@redhat.com, stefanha@redhat.com, pbonzini@redhat.com Subject: [Qemu-devel] [RFC PATCH 3/4] qmp: Add "snapshot=" option to nbd-server-add 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 With drive-backup block job, we can have a point-in-time snapshot of a device. With snapshot=on, a backup block job is started on the device to do CoW to a temporary image and this image is exported to nbd. The image is deleted after nbd server stops. Signed-off-by: Fam Zheng --- blockdev-nbd.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- hmp.c | 5 ++-- qapi-schema.json | 3 ++- qmp-commands.hx | 2 +- 4 files changed, 80 insertions(+), 6 deletions(-) diff --git a/blockdev-nbd.c b/blockdev-nbd.c index c75df19..f12b57c 100644 --- a/blockdev-nbd.c +++ b/blockdev-nbd.c @@ -17,6 +17,8 @@ #include "qmp-commands.h" #include "trace.h" #include "block/nbd.h" +#include "block/block_int.h" +#include "block/block.h" #include "qemu/sockets.h" static int server_fd = -1; @@ -78,8 +80,62 @@ static void nbd_server_put_ref(NBDExport *exp) } } +static void snapshot_drive_backup_cb(void *opaque, int ret) +{ + BlockDriverState *bs = opaque; + bs->backing_hd = NULL; +} + +/* create a point-in-time snapshot BDS from an existing BDS */ +static BlockDriverState *nbd_create_snapshot(BlockDriverState *orig_bs) +{ + int ret; + char filename[1024]; + BlockDriver *drv; + BlockDriverState *bs; + QEMUOptionParameter *options; + Error *local_err = NULL; + + bs = bdrv_new(""); + ret = get_tmp_filename(filename, sizeof(filename)); + if (ret < 0) { + goto err; + } + drv = bdrv_find_format("qcow2"); + if (drv < 0) { + goto err; + } + options = parse_option_parameters("", drv->create_options, NULL); + set_option_parameter_int(options, BLOCK_OPT_SIZE, bdrv_getlength(orig_bs)); + + ret = bdrv_create(drv, filename, options); + if (ret < 0) { + goto err; + } + ret = bdrv_open(bs, filename, NULL, BDRV_O_RDWR, drv); + if (ret < 0) { + goto err; + } + bs->backing_hd = orig_bs; + + backup_start(orig_bs, bs, 1, + MIRROR_SYNC_MODE_NONE, + BLOCKDEV_ON_ERROR_REPORT, + BLOCKDEV_ON_ERROR_REPORT, + snapshot_drive_backup_cb, bs, &local_err); + if (error_is_set(&local_err)) { + goto err; + } + return bs; + +err: + bdrv_delete(bs); + unlink(filename); + return NULL; +} + void qmp_nbd_server_add(const char *device, bool has_writable, bool writable, - Error **errp) + bool has_snapshot, bool snapshot, Error **errp) { BlockDriverState *bs; NBDExport *exp; @@ -104,21 +160,37 @@ void qmp_nbd_server_add(const char *device, bool has_writable, bool writable, if (!has_writable) { writable = false; } + + if (!has_snapshot) { + snapshot = false; + } + if (bdrv_is_read_only(bs)) { writable = false; } + if (snapshot) { + bs = nbd_create_snapshot(bs); + if (!bs) { + error_setg(errp, "Can't create snapshot for device"); + return; + } + } + exp = nbd_export_new(bs, 0, -1, writable ? 0 : NBD_FLAG_READ_ONLY, nbd_server_put_ref); nbd_export_set_name(exp, device); - drive_get_ref(drive_get_by_blockdev(bs)); + if (!snapshot) { + drive_get_ref(drive_get_by_blockdev(bs)); + } n = g_malloc0(sizeof(NBDCloseNotifier)); n->n.notify = nbd_close_notifier; n->exp = exp; bdrv_add_close_notifier(bs, &n->n); QTAILQ_INSERT_TAIL(&close_notifiers, n, next); + return; } void qmp_nbd_server_stop(Error **errp) diff --git a/hmp.c b/hmp.c index c45514b..5cc97fe 100644 --- a/hmp.c +++ b/hmp.c @@ -1440,7 +1440,8 @@ void hmp_nbd_server_start(Monitor *mon, const QDict *qdict) continue; } - qmp_nbd_server_add(info->value->device, true, writable, &local_err); + qmp_nbd_server_add(info->value->device, true, writable, false, false, + &local_err); if (local_err != NULL) { qmp_nbd_server_stop(NULL); @@ -1460,7 +1461,7 @@ void hmp_nbd_server_add(Monitor *mon, const QDict *qdict) int writable = qdict_get_try_bool(qdict, "writable", 0); Error *local_err = NULL; - qmp_nbd_server_add(device, true, writable, &local_err); + qmp_nbd_server_add(device, true, writable, false, false, &local_err); if (local_err != NULL) { hmp_handle_error(mon, &local_err); diff --git a/qapi-schema.json b/qapi-schema.json index f82d829..bfdbe33 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3225,7 +3225,8 @@ # # Since: 1.3.0 ## -{ 'command': 'nbd-server-add', 'data': {'device': 'str', '*writable': 'bool'} } +{ 'command': 'nbd-server-add', 'data': {'device': 'str', '*writable': 'bool', + '*snapshot': 'bool'} } ## # @nbd-server-stop: diff --git a/qmp-commands.hx b/qmp-commands.hx index 2e59b0d..e398d88 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -2871,7 +2871,7 @@ EQMP }, { .name = "nbd-server-add", - .args_type = "device:B,writable:b?", + .args_type = "device:B,writable:b?,snapshot:b?", .mhandler.cmd_new = qmp_marshal_input_nbd_server_add, }, {