From patchwork Sat Feb 28 00:47:56 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Snow X-Patchwork-Id: 444553 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)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id DFE22140146 for ; Sat, 28 Feb 2015 11:56:00 +1100 (AEDT) Received: from localhost ([::1]:39659 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YRVhH-0000nM-76 for incoming@patchwork.ozlabs.org; Fri, 27 Feb 2015 19:55:59 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:36460) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YRVa3-0002Zd-Ut for qemu-devel@nongnu.org; Fri, 27 Feb 2015 19:48:33 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YRVa0-0000WE-Or for qemu-devel@nongnu.org; Fri, 27 Feb 2015 19:48:31 -0500 Received: from mx1.redhat.com ([209.132.183.28]:60819) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YRVZq-0000Qb-Kp; Fri, 27 Feb 2015 19:48:18 -0500 Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id t1S0mHPu016161 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Fri, 27 Feb 2015 19:48:18 -0500 Received: from scv.usersys.redhat.com (dhcp-17-38.bos.redhat.com [10.18.17.38]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t1S0lwNo014604; Fri, 27 Feb 2015 19:48:16 -0500 From: John Snow To: qemu-block@nongnu.org Date: Fri, 27 Feb 2015 19:47:56 -0500 Message-Id: <1425084477-31602-17-git-send-email-jsnow@redhat.com> In-Reply-To: <1425084477-31602-1-git-send-email-jsnow@redhat.com> References: <1425084477-31602-1-git-send-email-jsnow@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.27 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, John Snow , qemu-devel@nongnu.org, armbru@redhat.com, vsementsov@parallels.com, stefanha@redhat.com, mreitz@redhat.com Subject: [Qemu-devel] [PATCH RESEND 16/17] iotests: add simple incremental backup case 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 Reviewed-by: Max Reitz Signed-off-by: John Snow --- tests/qemu-iotests/124 | 122 +++++++++++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/124.out | 4 +- 2 files changed, 124 insertions(+), 2 deletions(-) diff --git a/tests/qemu-iotests/124 b/tests/qemu-iotests/124 index 7985cd1..da8f0e0 100644 --- a/tests/qemu-iotests/124 +++ b/tests/qemu-iotests/124 @@ -28,6 +28,36 @@ def io_write_patterns(img, patterns): for pattern in patterns: iotests.qemu_io('-c', 'write -P%s %s %s' % pattern, img) +class Bitmap: + def __init__(self, name, node): + self.name = name + self.node = node + self.pattern = os.path.join(iotests.test_dir.replace('%', '%%'), + '%s.backup.%%i.img' % name) + self.num = 0 + self.backups = list() + + def new_target(self, num=None): + if num is None: + num = self.num + self.num = num + 1 + target = self.pattern % num + self.backups.append(target) + return target + + def last_target(self): + return self.backups[-1] + + def del_target(self): + os.remove(self.backups.pop()) + self.num -= 1 + + def __del__(self): + for backup in self.backups: + try: + os.remove(backup) + except OSError: + pass class TestIncrementalBackup(iotests.QMPTestCase): def setUp(self): @@ -58,6 +88,98 @@ class TestIncrementalBackup(iotests.QMPTestCase): iotests.qemu_img('create', '-f', fmt, img, size) self.files.append(img) + + def create_full_backup(self, drive='drive0'): + res = self.vm.qmp('drive-backup', device=drive, + sync='full', format=iotests.imgfmt, + target=self.full_bak) + self.assert_qmp(res, 'return', {}) + self.wait_until_completed(drive) + self.check_full_backup() + self.files.append(self.full_bak) + + + def check_full_backup(self): + self.assertTrue(iotests.compare_images(self.test_img, self.full_bak)) + + + def add_bitmap(self, name, node='drive0'): + bitmap = Bitmap(name, node) + self.bitmaps.append(bitmap) + result = self.vm.qmp('block-dirty-bitmap-add', node=bitmap.node, + name=bitmap.name) + self.assert_qmp(result, 'return', {}) + return bitmap + + + def create_incremental(self, bitmap=None, num=None, + parent=None, parentFormat=None, validate=True): + if bitmap is None: + bitmap = self.bitmaps[-1] + + # If this is the first incremental backup for a bitmap, + # use the full backup as a backing image. Otherwise, use + # the last incremental backup. + if parent is None: + if bitmap.num == 0: + parent = self.full_bak + else: + parent = bitmap.last_target() + + target = bitmap.new_target(num) + self.img_create(target, iotests.imgfmt, parent=parent) + + result = self.vm.qmp('drive-backup', device=bitmap.node, + sync='dirty-bitmap', bitmap=bitmap.name, + format=iotests.imgfmt, target=target, + mode='existing') + self.assert_qmp(result, 'return', {}) + + event = self.wait_until_completed(bitmap.node, check_offset=validate) + if validate: + return self.check_incremental(target) + + + def check_incremental(self, target=None): + if target is None: + target = self.bitmaps[-1].last_target() + self.assertTrue(iotests.compare_images(self.test_img, target)) + return True + + + def hmp_io_writes(self, drive, patterns): + for pattern in patterns: + self.vm.hmp_qemu_io(drive, 'write -P%s %s %s' % pattern) + self.vm.hmp_qemu_io(drive, 'flush') + + + def test_incremental_simple(self): + ''' + Test: Create and verify three incremental backups. + + Create a bitmap and a full backup before VM execution begins, + then create a series of three incremental backups "during execution," + i.e.; after IO requests begin modifying the drive. + ''' + self.create_full_backup() + self.add_bitmap('bitmap0', 'drive0') + + # Sanity: Create a "hollow" incremental backup + self.create_incremental() + # Three writes: One complete overwrite, one new segment, + # and one partial overlap. + self.hmp_io_writes('drive0', (('0xab', 0, 512), + ('0xfe', '16M', '256k'), + ('0x64', '32736k', '64k'))) + self.create_incremental() + # Three more writes, one of each kind, like above + self.hmp_io_writes('drive0', (('0x9a', 0, 512), + ('0x55', '8M', '352k'), + ('0x78', '15872k', '1M'))) + self.create_incremental() + return True + + def test_sync_dirty_bitmap_missing(self): self.assert_no_active_block_jobs() self.files.append(self.foo_img) diff --git a/tests/qemu-iotests/124.out b/tests/qemu-iotests/124.out index fbc63e6..8d7e996 100644 --- a/tests/qemu-iotests/124.out +++ b/tests/qemu-iotests/124.out @@ -1,5 +1,5 @@ -.. +... ---------------------------------------------------------------------- -Ran 2 tests +Ran 3 tests OK