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