| 1 | #!/usr/bin/env python3 |
| 2 | # group: rw |
| 3 | # |
| 4 | # Tests growing a large refcount table. |
| 5 | # |
| 6 | # Copyright (C) 2012 Red Hat, Inc. |
| 7 | # |
| 8 | # This program is free software; you can redistribute it and/or modify |
| 9 | # it under the terms of the GNU General Public License as published by |
| 10 | # the Free Software Foundation; either version 2 of the License, or |
| 11 | # (at your option) any later version. |
| 12 | # |
| 13 | # This program is distributed in the hope that it will be useful, |
| 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 16 | # GNU General Public License for more details. |
| 17 | # |
| 18 | # You should have received a copy of the GNU General Public License |
| 19 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 20 | # |
| 21 | |
| 22 | import time |
| 23 | import os |
| 24 | import qcow2 |
| 25 | from qcow2 import QcowHeader |
| 26 | import iotests |
| 27 | from iotests import qemu_img, qemu_img_log, qemu_io |
| 28 | import struct |
| 29 | import subprocess |
| 30 | import sys |
| 31 | |
| 32 | test_img = os.path.join(iotests.test_dir, 'test.img') |
| 33 | |
| 34 | class TestRefcountTableGrowth(iotests.QMPTestCase): |
| 35 | '''Abstract base class for image mirroring test cases''' |
| 36 | |
| 37 | def preallocate(self, name): |
| 38 | fd = open(name, "r+b") |
| 39 | try: |
| 40 | off_reftable = 512 |
| 41 | off_refblock = off_reftable + (512 * 512) |
| 42 | off_l1 = off_refblock + (512 * 512 * 64) |
| 43 | off_l2 = off_l1 + (512 * 512 * 4 * 8) |
| 44 | off_data = off_l2 + (512 * 512 * 4 * 512) |
| 45 | |
| 46 | # Write a new header |
| 47 | h = QcowHeader(fd) |
| 48 | h.refcount_table_offset = off_reftable |
| 49 | h.refcount_table_clusters = 512 |
| 50 | h.l1_table_offset = off_l1 |
| 51 | h.l1_size = 512 * 512 * 4 |
| 52 | h.update(fd) |
| 53 | |
| 54 | # Write a refcount table |
| 55 | fd.seek(off_reftable) |
| 56 | |
| 57 | for i in range(0, h.refcount_table_clusters): |
| 58 | sector = b''.join(struct.pack('>Q', |
| 59 | off_refblock + i * 64 * 512 + j * 512) |
| 60 | for j in range(0, 64)) |
| 61 | fd.write(sector) |
| 62 | |
| 63 | # Write the refcount blocks |
| 64 | assert(fd.tell() == off_refblock) |
| 65 | sector = b''.join(struct.pack('>H', 1) for j in range(0, 64 * 256)) |
| 66 | for block in range(0, h.refcount_table_clusters): |
| 67 | fd.write(sector) |
| 68 | |
| 69 | # Write the L1 table |
| 70 | assert(fd.tell() == off_l1) |
| 71 | assert(off_l2 + 512 * h.l1_size == off_data) |
| 72 | table = b''.join(struct.pack('>Q', (1 << 63) | off_l2 + 512 * j) |
| 73 | for j in range(0, h.l1_size)) |
| 74 | fd.write(table) |
| 75 | |
| 76 | # Write the L2 tables |
| 77 | assert(fd.tell() == off_l2) |
| 78 | img_file_size = h.refcount_table_clusters * 64 * 256 * 512 |
| 79 | remaining = img_file_size - off_data |
| 80 | |
| 81 | off = off_data |
| 82 | while remaining > 1024 * 512: |
| 83 | pytable = list((1 << 63) | off + 512 * j |
| 84 | for j in range(0, 1024)) |
| 85 | table = struct.pack('>1024Q', *pytable) |
| 86 | fd.write(table) |
| 87 | remaining = remaining - 1024 * 512 |
| 88 | off = off + 1024 * 512 |
| 89 | |
| 90 | table = b''.join(struct.pack('>Q', (1 << 63) | off + 512 * j) |
| 91 | for j in range(0, remaining // 512)) |
| 92 | fd.write(table) |
| 93 | |
| 94 | |
| 95 | # Data |
| 96 | fd.truncate(img_file_size) |
| 97 | |
| 98 | |
| 99 | finally: |
| 100 | fd.close() |
| 101 | |
| 102 | |
| 103 | def setUp(self): |
| 104 | qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=512', test_img, '16G') |
| 105 | self.preallocate(test_img) |
| 106 | pass |
| 107 | |
| 108 | |
| 109 | def tearDown(self): |
| 110 | os.remove(test_img) |
| 111 | pass |
| 112 | |
| 113 | def test_grow_refcount_table(self): |
| 114 | qemu_io('-c', 'write 3800M 1M', test_img) |
| 115 | qemu_img_log('check' , test_img) |
| 116 | pass |
| 117 | |
| 118 | if __name__ == '__main__': |
| 119 | iotests.activate_logging() |
| 120 | iotests.main(supported_fmts=['qcow2'], |
| 121 | supported_protocols=['file'], |
| 122 | unsupported_imgopts=['refcount_bits']) |