From patchwork Wed Nov 14 18:47:04 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Wolf X-Patchwork-Id: 199001 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id EA2802C0080 for ; Thu, 15 Nov 2012 06:51:25 +1100 (EST) Received: from localhost ([::1]:40152 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TYi0c-0001AP-8L for incoming@patchwork.ozlabs.org; Wed, 14 Nov 2012 13:48:22 -0500 Received: from eggs.gnu.org ([208.118.235.92]:59877) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TYhzw-0007na-Vv for qemu-devel@nongnu.org; Wed, 14 Nov 2012 13:47:44 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1TYhzt-0000RI-SF for qemu-devel@nongnu.org; Wed, 14 Nov 2012 13:47:40 -0500 Received: from mx1.redhat.com ([209.132.183.28]:27850) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TYhzt-0000RE-KN for qemu-devel@nongnu.org; Wed, 14 Nov 2012 13:47:37 -0500 Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id qAEIlZ7v010099 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Wed, 14 Nov 2012 13:47:36 -0500 Received: from dhcp-5-188.str.redhat.com (vpn1-4-191.ams2.redhat.com [10.36.4.191]) by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id qAEIlTlF028359; Wed, 14 Nov 2012 13:47:33 -0500 From: Kevin Wolf To: anthony@codemonkey.ws Date: Wed, 14 Nov 2012 19:47:04 +0100 Message-Id: <1352918847-3696-4-git-send-email-kwolf@redhat.com> In-Reply-To: <1352918847-3696-1-git-send-email-kwolf@redhat.com> References: <1352918847-3696-1-git-send-email-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.25 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 Cc: kwolf@redhat.com, qemu-devel@nongnu.org Subject: [Qemu-devel] [PATCH 03/26] qemu-iotests: qcow2: Test growing large refcount table 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 Actually writing all the content with 512 byte sector size would take forever, therefore build the image file with a Python script and use qemu-io for the last write that actually triggers the refcount table growth. Signed-off-by: Kevin Wolf --- tests/qemu-iotests/044 | 117 +++++++++++++++++++++++++++++++++++++++++ tests/qemu-iotests/044.out | 6 ++ tests/qemu-iotests/group | 1 + tests/qemu-iotests/iotests.py | 6 ++- tests/qemu-iotests/qcow2.py | 9 ++-- 5 files changed, 134 insertions(+), 5 deletions(-) create mode 100755 tests/qemu-iotests/044 create mode 100644 tests/qemu-iotests/044.out diff --git a/tests/qemu-iotests/044 b/tests/qemu-iotests/044 new file mode 100755 index 0000000..11ea0f4 --- /dev/null +++ b/tests/qemu-iotests/044 @@ -0,0 +1,117 @@ +#!/usr/bin/env python +# +# Tests growing a large refcount table. +# +# Copyright (C) 2012 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +import time +import os +import qcow2 +from qcow2 import QcowHeader +import iotests +from iotests import qemu_img, qemu_img_verbose, qemu_io +import struct +import subprocess + +test_img = os.path.join(iotests.test_dir, 'test.img') + +class TestRefcountTableGrowth(iotests.QMPTestCase): + '''Abstract base class for image mirroring test cases''' + + def preallocate(self, name): + fd = open(name, "r+b") + try: + off_reftable = 512 + off_refblock = off_reftable + (512 * 512) + off_l1 = off_refblock + (512 * 512 * 64) + off_l2 = off_l1 + (512 * 512 * 4 * 8) + off_data = off_l2 + (512 * 512 * 4 * 512) + + # Write a new header + h = QcowHeader(fd) + h.refcount_table_offset = off_reftable + h.refcount_table_clusters = 512 + h.l1_table_offset = off_l1 + h.l1_size = 512 * 512 * 4 + h.update(fd) + + # Write a refcount table + fd.seek(off_reftable) + + for i in xrange(0, h.refcount_table_clusters): + sector = ''.join(struct.pack('>Q', + off_refblock + i * 64 * 512 + j * 512) + for j in xrange(0, 64)) + fd.write(sector) + + # Write the refcount blocks + assert(fd.tell() == off_refblock) + sector = ''.join(struct.pack('>H', 1) for j in xrange(0, 64 * 256)) + for block in xrange(0, h.refcount_table_clusters): + fd.write(sector) + + # Write the L1 table + assert(fd.tell() == off_l1) + assert(off_l2 + 512 * h.l1_size == off_data) + table = ''.join(struct.pack('>Q', (1 << 63) | off_l2 + 512 * j) + for j in xrange(0, h.l1_size)) + fd.write(table) + + # Write the L2 tables + assert(fd.tell() == off_l2) + img_file_size = h.refcount_table_clusters * 64 * 256 * 512 + remaining = img_file_size - off_data + + off = off_data + while remaining > 1024 * 512: + pytable = list((1 << 63) | off + 512 * j + for j in xrange(0, 1024)) + table = struct.pack('>1024Q', *pytable) + fd.write(table) + remaining = remaining - 1024 * 512 + off = off + 1024 * 512 + + table = ''.join(struct.pack('>Q', (1 << 63) | off + 512 * j) + for j in xrange(0, remaining / 512)) + fd.write(table) + + + # Data + fd.truncate(img_file_size) + + + finally: + fd.close() + + + def setUp(self): + qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=512', test_img, '16G') + self.preallocate(test_img) + pass + + + def tearDown(self): + os.remove(test_img) + pass + + def test_grow_refcount_table(self): + qemu_io('-c', 'write 3800M 1M', test_img) + qemu_img_verbose('check' , test_img) + pass + +if __name__ == '__main__': + iotests.main(supported_fmts=['qcow2']) diff --git a/tests/qemu-iotests/044.out b/tests/qemu-iotests/044.out new file mode 100644 index 0000000..7a40071 --- /dev/null +++ b/tests/qemu-iotests/044.out @@ -0,0 +1,6 @@ +No errors were found on the image. +. +---------------------------------------------------------------------- +Ran 1 tests + +OK diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index ac86f54..a4a9044 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -50,3 +50,4 @@ 041 rw auto backing 042 rw auto quick 043 rw auto backing +044 rw auto diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 735c674..b2eaf20 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -42,6 +42,10 @@ def qemu_img(*args): devnull = open('/dev/null', 'r+') return subprocess.call(qemu_img_args + list(args), stdin=devnull, stdout=devnull) +def qemu_img_verbose(*args): + '''Run qemu-img without supressing its output and return the exit code''' + return subprocess.call(qemu_img_args + list(args)) + def qemu_io(*args): '''Run qemu-io and return the stdout data''' args = qemu_io_args + list(args) @@ -182,4 +186,4 @@ def main(supported_fmts=[]): try: unittest.main(testRunner=MyTestRunner) finally: - sys.stderr.write(re.sub(r'Ran (\d+) test[s] in [\d.]+s', r'Ran \1 tests', output.getvalue())) + sys.stderr.write(re.sub(r'Ran (\d+) tests? in [\d.]+s', r'Ran \1 tests', output.getvalue())) diff --git a/tests/qemu-iotests/qcow2.py b/tests/qemu-iotests/qcow2.py index 97f3770..fecf5b9 100755 --- a/tests/qemu-iotests/qcow2.py +++ b/tests/qemu-iotests/qcow2.py @@ -233,8 +233,9 @@ def usage(): for name, handler, num_args, desc in cmds: print " %-20s - %s" % (name, desc) -if len(sys.argv) < 3: - usage() - sys.exit(1) +if __name__ == '__main__': + if len(sys.argv) < 3: + usage() + sys.exit(1) -main(sys.argv[1], sys.argv[2], sys.argv[3:]) + main(sys.argv[1], sys.argv[2], sys.argv[3:])