From patchwork Fri Sep 10 00:08:23 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: disheng.su@gmail.com X-Patchwork-Id: 64341 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id AA79FB712F for ; Fri, 10 Sep 2010 10:14:43 +1000 (EST) Received: from localhost ([127.0.0.1]:43353 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OtrGK-0008H4-HJ for incoming@patchwork.ozlabs.org; Thu, 09 Sep 2010 20:14:40 -0400 Received: from [140.186.70.92] (port=37105 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OtrEF-0007W5-9q for qemu-devel@nongnu.org; Thu, 09 Sep 2010 20:12:32 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.69) (envelope-from ) id 1OtrED-0000R9-PG for qemu-devel@nongnu.org; Thu, 09 Sep 2010 20:12:31 -0400 Received: from mail-pz0-f45.google.com ([209.85.210.45]:45588) by eggs.gnu.org with esmtp (Exim 4.69) (envelope-from ) id 1OtrED-0000Qp-GS for qemu-devel@nongnu.org; Thu, 09 Sep 2010 20:12:29 -0400 Received: by pzk12 with SMTP id 12so213234pzk.4 for ; Thu, 09 Sep 2010 17:12:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:from:to:cc:subject:date :message-id:x-mailer; bh=2cd/0ekMs6z16KG1TqKuwfERDdnU9Kjo4VVyY73dGgA=; b=irIIFso0+JnRbIo2uvP9tzAEhGUlVQs2ktfHizPZTzrncLP7QNEvHcTYGFcvEmOTDc UHi5TfrCaTtX/oZ0w54FmSYkYW4daIdlQf+SM5zfpkdhVK03R4Ey3Qh/gITO8D/rMYLg /eV8yrwVvk1uXNt8YLO3rd3vBJ3I6rwO9maF0= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=from:to:cc:subject:date:message-id:x-mailer; b=haaQxvvLjoI9yJIOVIPU6p/5l9+AIgBAQpIBZNZhW83Sszh4UCm55HgbMsTxrOu5gM 3R3LlB8Bwne4H2d9UJP0YbfGZIy3gT8woXJx7I4FVc0DXiDjQfs9/xQG3Wb468xVg/ER wveIQMCH4YYgAmc6FVrenMIS3/odYoBWsSnLY= Received: by 10.143.5.6 with SMTP id h6mr138964wfi.135.1284077548024; Thu, 09 Sep 2010 17:12:28 -0700 (PDT) Received: from localhost.localdomain (adsl-99-57-184-141.dsl.pltn13.sbcglobal.net [99.57.184.141]) by mx.google.com with ESMTPS id q23sm2207107wfc.18.2010.09.09.17.12.25 (version=TLSv1/SSLv3 cipher=RC4-MD5); Thu, 09 Sep 2010 17:12:26 -0700 (PDT) From: disheng.su@gmail.com To: kwolf@redhat.com Date: Thu, 9 Sep 2010 17:08:23 -0700 Message-Id: <1284077303-2266-1-git-send-email-disheng.su@gmail.com> X-Mailer: git-send-email 1.7.2.2 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 2) Cc: qemu-devel@nongnu.org, edison Subject: [Qemu-devel] [PATCH] Copy snapshots out of QCOW2 disk X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: edison In order to backup snapshots, created from QCOW2 iamge, we want to copy snapshots out of QCOW2 disk to a seperate storage. The following patch adds a new option in "qemu-img": qemu-img convert -f qcow2 -O qcow2 -s snapshot_name src_img bck_img. Right now, it only supports to copy the full snapshot, delta snapshot is on the way. Signed-off-by: Disheng Su --- block.c | 11 +++++++++++ block.h | 2 ++ block/qcow2-snapshot.c | 26 ++++++++++++++++++++++++++ block/qcow2.c | 1 + block/qcow2.h | 1 + block_int.h | 2 ++ qemu-img-cmds.hx | 4 ++-- qemu-img.c | 19 ++++++++++++++++++- 8 files changed, 63 insertions(+), 3 deletions(-) diff --git a/block.c b/block.c index ebbc376..eaf78f6 100644 --- a/block.c +++ b/block.c @@ -1899,6 +1899,17 @@ int bdrv_snapshot_list(BlockDriverState *bs, return -ENOTSUP; } +int bdrv_snapshot_load(BlockDriverState *bs, + const char *snapshot_name) +{ + BlockDriver *drv = bs->drv; + if (!drv) + return -ENOMEDIUM; + if (drv->bdrv_snapshot_load) + return drv->bdrv_snapshot_load(bs, snapshot_name); + return -ENOTSUP; +} + #define NB_SUFFIXES 4 char *get_human_readable_size(char *buf, int buf_size, int64_t size) diff --git a/block.h b/block.h index 5f64380..9ec6219 100644 --- a/block.h +++ b/block.h @@ -211,6 +211,8 @@ int bdrv_snapshot_goto(BlockDriverState *bs, int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id); int bdrv_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_info); +int bdrv_snapshot_load(BlockDriverState *bs, + const char *snapshot_name); char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn); char *get_human_readable_size(char *buf, int buf_size, int64_t size); diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c index 6228612..e663e8b 100644 --- a/block/qcow2-snapshot.c +++ b/block/qcow2-snapshot.c @@ -416,3 +416,29 @@ int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab) return s->nb_snapshots; } +int qcow2_snapshot_load(BlockDriverState *bs, const char *snapshot_name) { + int i, snapshot_index, l1_size2; + BDRVQcowState *s = bs->opaque; + QCowSnapshot *sn; + snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_name); + if (snapshot_index < 0) + return -ENOENT; + sn = &s->snapshots[snapshot_index]; + s->l1_size = sn->l1_size; + l1_size2 = s->l1_size * sizeof(uint64_t); + if (s->l1_table != NULL) { + qemu_free(s->l1_table); + } + s->l1_table_offset = sn->l1_table_offset; + s->l1_table = qemu_mallocz( + align_offset(l1_size2, 512)); + /* copy the snapshot l1 table to the current l1 table */ + if (bdrv_pread(bs->file, sn->l1_table_offset, + s->l1_table, l1_size2) != l1_size2) { + return -1; + } + for(i = 0;i < s->l1_size; i++) { + be64_to_cpus(&s->l1_table[i]); + } + return 0; +} diff --git a/block/qcow2.c b/block/qcow2.c index a53014d..da98a01 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -1352,6 +1352,7 @@ static BlockDriver bdrv_qcow2 = { .bdrv_snapshot_goto = qcow2_snapshot_goto, .bdrv_snapshot_delete = qcow2_snapshot_delete, .bdrv_snapshot_list = qcow2_snapshot_list, + .bdrv_snapshot_load = qcow2_snapshot_load, .bdrv_get_info = qcow_get_info, .bdrv_save_vmstate = qcow_save_vmstate, diff --git a/block/qcow2.h b/block/qcow2.h index 3ff162e..cbbba48 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -211,6 +211,7 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info); int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id); int qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id); int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab); +int qcow2_snapshot_load(BlockDriverState *bs, const char *snapshot_name); void qcow2_free_snapshots(BlockDriverState *bs); int qcow2_read_snapshots(BlockDriverState *bs); diff --git a/block_int.h b/block_int.h index e8e7156..93d5a1b 100644 --- a/block_int.h +++ b/block_int.h @@ -93,6 +93,8 @@ struct BlockDriver { int (*bdrv_snapshot_delete)(BlockDriverState *bs, const char *snapshot_id); int (*bdrv_snapshot_list)(BlockDriverState *bs, QEMUSnapshotInfo **psn_info); + int (*bdrv_snapshot_load)(BlockDriverState *bs, + const char *snapshot_name); int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi); int (*bdrv_save_vmstate)(BlockDriverState *bs, const uint8_t *buf, diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx index 6d3e5f8..6c7176f 100644 --- a/qemu-img-cmds.hx +++ b/qemu-img-cmds.hx @@ -28,9 +28,9 @@ STEXI ETEXI DEF("convert", img_convert, - "convert [-c] [-f fmt] [-O output_fmt] [-o options] filename [filename2 [...]] output_filename") + "convert [-c] [-f fmt] [-O output_fmt] [-o options] [-s snapshot_name] filename [filename2 [...]] output_filename") STEXI -@item convert [-c] [-f @var{fmt}] [-O @var{output_fmt}] [-o @var{options}] @var{filename} [@var{filename2} [...]] @var{output_filename} +@item convert [-c] [-f @var{fmt}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_name}] @var{filename} [@var{filename2} [...]] @var{output_filename} ETEXI DEF("info", img_info, diff --git a/qemu-img.c b/qemu-img.c index 4e035e4..7ff015d 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -646,13 +646,14 @@ static int img_convert(int argc, char **argv) BlockDriverInfo bdi; QEMUOptionParameter *param = NULL, *create_options = NULL; char *options = NULL; + const char *snapshot_name = NULL; fmt = NULL; out_fmt = "raw"; out_baseimg = NULL; flags = 0; for(;;) { - c = getopt(argc, argv, "f:O:B:hce6o:"); + c = getopt(argc, argv, "f:O:B:s:hce6o:"); if (c == -1) break; switch(c) { @@ -680,6 +681,9 @@ static int img_convert(int argc, char **argv) case 'o': options = optarg; break; + case 's': + snapshot_name = optarg; + break; } } @@ -711,6 +715,19 @@ static int img_convert(int argc, char **argv) total_sectors += bs_sectors; } + if (snapshot_name != NULL) { + if (bs_n > 1) { + error("No support for concatenating multiple snapshot\n"); + ret = -1; + goto out; + } + if (bdrv_snapshot_load(bs[0], snapshot_name) < 0) { + error("Failed to load snapshot\n"); + ret = -1; + goto out; + } + } + /* Find driver and parse its options */ drv = bdrv_find_format(out_fmt); if (!drv) {