| 1 | #!/usr/bin/env python3 |
| 2 | # group: rw quick |
| 3 | # |
| 4 | # Test for qcow2 bitmap printed information |
| 5 | # |
| 6 | # Copyright (c) 2019 Virtuozzo International GmbH |
| 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 iotests |
| 23 | import json |
| 24 | import struct |
| 25 | from iotests import qemu_img_create, qemu_io_log, qemu_img_info, \ |
| 26 | file_path, img_info_log, log |
| 27 | |
| 28 | iotests.script_initialize(supported_fmts=['qcow2'], |
| 29 | supported_protocols=['file'], |
| 30 | unsupported_imgopts=['refcount_bits', 'compat']) |
| 31 | |
| 32 | disk = file_path('disk') |
| 33 | chunk = 256 * 1024 |
| 34 | bitmap_flag_unknown = 1 << 2 |
| 35 | # flag_offset = 5*cluster_size + flag_offset_in_bitmap_directory_entry |
| 36 | flag_offset = 0x5000f |
| 37 | |
| 38 | |
| 39 | def print_bitmap(extra_args): |
| 40 | log('qemu-img info dump:\n') |
| 41 | img_info_log(disk, extra_args=extra_args) |
| 42 | result = qemu_img_info('--force-share', disk) |
| 43 | if 'bitmaps' in result['format-specific']['data']: |
| 44 | bitmaps = result['format-specific']['data']['bitmaps'] |
| 45 | log('The same bitmaps in JSON format:') |
| 46 | log(bitmaps, indent=2) |
| 47 | else: |
| 48 | log('No bitmap in JSON format output') |
| 49 | |
| 50 | |
| 51 | def add_bitmap(bitmap_number, persistent, disabled): |
| 52 | granularity = 1 << (13 + bitmap_number) |
| 53 | bitmap_name = 'bitmap-' + str(bitmap_number-1) |
| 54 | vm = iotests.VM().add_drive(disk) |
| 55 | vm.launch() |
| 56 | vm.qmp_log('block-dirty-bitmap-add', node='drive0', name=bitmap_name, |
| 57 | granularity=granularity, persistent=persistent, |
| 58 | disabled=disabled) |
| 59 | vm.shutdown() |
| 60 | |
| 61 | |
| 62 | def write_to_disk(offset, size): |
| 63 | write = 'write {} {}'.format(offset, size) |
| 64 | qemu_io_log('-c', write, disk) |
| 65 | |
| 66 | |
| 67 | def toggle_flag(offset): |
| 68 | with open(disk, "r+b") as f: |
| 69 | f.seek(offset, 0) |
| 70 | # Read one byte in a way compatible with Python 2 |
| 71 | flags = struct.unpack("B", f.read(1)) |
| 72 | toggled = flags[0] ^ bitmap_flag_unknown |
| 73 | f.seek(-1, 1) |
| 74 | f.write(struct.pack("B", toggled)) |
| 75 | |
| 76 | |
| 77 | qemu_img_create('-f', iotests.imgfmt, disk, '1M') |
| 78 | |
| 79 | for num in range(1, 4): |
| 80 | disabled = False |
| 81 | if num == 2: |
| 82 | disabled = True |
| 83 | log('Test {}'.format(num)) |
| 84 | add_bitmap(num, num > 1, disabled) |
| 85 | write_to_disk((num-1) * chunk, chunk) |
| 86 | print_bitmap([]) |
| 87 | log('') |
| 88 | |
| 89 | vm = iotests.VM().add_drive(disk) |
| 90 | vm.launch() |
| 91 | num += 1 |
| 92 | log('Test {}\nChecking "in-use" flag...'.format(num)) |
| 93 | print_bitmap(['--force-share']) |
| 94 | vm.shutdown() |
| 95 | |
| 96 | num += 1 |
| 97 | log('\nTest {}'.format(num)) |
| 98 | qemu_img_create('-f', iotests.imgfmt, disk, '1M') |
| 99 | add_bitmap(1, True, False) |
| 100 | log('Write an unknown bitmap flag \'{}\' into a new QCOW2 image at offset {}' |
| 101 | .format(hex(bitmap_flag_unknown), flag_offset)) |
| 102 | toggle_flag(flag_offset) |
| 103 | img_info_log(disk, check=False) |
| 104 | toggle_flag(flag_offset) |
| 105 | log('Unset the unknown bitmap flag \'{}\' in the bitmap directory entry:\n' |
| 106 | .format(hex(bitmap_flag_unknown))) |
| 107 | img_info_log(disk) |
| 108 | log('Test complete') |