| #!/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 <http://www.gnu.org/licenses/>. |
| # |
| |
| 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 |
| import sys |
| |
| if sys.version_info.major == 2: |
| range = xrange |
| |
| 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 range(0, h.refcount_table_clusters): |
| sector = b''.join(struct.pack('>Q', |
| off_refblock + i * 64 * 512 + j * 512) |
| for j in range(0, 64)) |
| fd.write(sector) |
| |
| # Write the refcount blocks |
| assert(fd.tell() == off_refblock) |
| sector = b''.join(struct.pack('>H', 1) for j in range(0, 64 * 256)) |
| for block in range(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 = b''.join(struct.pack('>Q', (1 << 63) | off_l2 + 512 * j) |
| for j in range(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 range(0, 1024)) |
| table = struct.pack('>1024Q', *pytable) |
| fd.write(table) |
| remaining = remaining - 1024 * 512 |
| off = off + 1024 * 512 |
| |
| table = b''.join(struct.pack('>Q', (1 << 63) | off + 512 * j) |
| for j in range(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']) |