| #!/usr/bin/env python3 | |
| # group: rw backing | |
| # | |
| # Copyright (C) 2019 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/>. | |
| # | |
| # Creator/Owner: Kevin Wolf <kwolf@redhat.com> | |
| # | |
| # Some tests for short backing files and short overlays | |
| import iotests | |
| iotests.script_initialize(supported_fmts=['qcow2'], | |
| supported_platforms=['linux'], | |
| unsupported_imgopts=['refcount_bits', 'compat']) | |
| size_short = 1 * 1024 * 1024 | |
| size_long = 2 * 1024 * 1024 | |
| size_diff = size_long - size_short | |
| def create_chain() -> None: | |
| iotests.qemu_img_create('-f', iotests.imgfmt, base, str(size_long)) | |
| iotests.qemu_img_create('-f', iotests.imgfmt, '-b', base, | |
| '-F', iotests.imgfmt, mid, str(size_short)) | |
| iotests.qemu_img_create('-f', iotests.imgfmt, '-b', mid, | |
| '-F', iotests.imgfmt, top, str(size_long)) | |
| iotests.qemu_io_log('-c', 'write -P 1 0 %d' % size_long, base) | |
| def create_vm() -> iotests.VM: | |
| vm = iotests.VM() | |
| vm.add_blockdev('file,filename=%s,node-name=base-file' % base) | |
| vm.add_blockdev('%s,file=base-file,node-name=base' % iotests.imgfmt) | |
| vm.add_blockdev('file,filename=%s,node-name=mid-file' % mid) | |
| vm.add_blockdev('%s,file=mid-file,node-name=mid,backing=base' | |
| % iotests.imgfmt) | |
| vm.add_drive(top, 'backing=mid,node-name=top') | |
| return vm | |
| with iotests.FilePath('base') as base, \ | |
| iotests.FilePath('mid') as mid, \ | |
| iotests.FilePath('top') as top: | |
| iotests.log('== Commit tests ==') | |
| create_chain() | |
| iotests.log('=== Check visible data ===') | |
| iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, top) | |
| iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), top) | |
| iotests.log('=== Checking allocation status ===') | |
| iotests.qemu_io_log('-c', 'alloc 0 %d' % size_short, | |
| '-c', 'alloc %d %d' % (size_short, size_diff), | |
| base) | |
| iotests.qemu_io_log('-c', 'alloc 0 %d' % size_short, | |
| '-c', 'alloc %d %d' % (size_short, size_diff), | |
| mid) | |
| iotests.qemu_io_log('-c', 'alloc 0 %d' % size_short, | |
| '-c', 'alloc %d %d' % (size_short, size_diff), | |
| top) | |
| iotests.log('=== Checking map ===') | |
| iotests.qemu_img_log('map', '--output=json', base) | |
| iotests.qemu_img_log('map', '--output=human', base) | |
| iotests.qemu_img_log('map', '--output=json', mid) | |
| iotests.qemu_img_log('map', '--output=human', mid) | |
| iotests.qemu_img_log('map', '--output=json', top) | |
| iotests.qemu_img_log('map', '--output=human', top) | |
| iotests.log('=== Testing qemu-img commit (top -> mid) ===') | |
| iotests.qemu_img_log('commit', top) | |
| iotests.img_info_log(mid) | |
| iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, mid) | |
| iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), mid) | |
| iotests.log('=== Testing HMP commit (top -> mid) ===') | |
| create_chain() | |
| with create_vm() as vm: | |
| vm.launch() | |
| vm.qmp_log('human-monitor-command', command_line='commit drive0') | |
| iotests.img_info_log(mid) | |
| iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, mid) | |
| iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), mid) | |
| iotests.log('=== Testing QMP active commit (top -> mid) ===') | |
| create_chain() | |
| with create_vm() as vm: | |
| vm.launch() | |
| vm.qmp_log('block-commit', device='top', base_node='mid', | |
| job_id='job0', auto_dismiss=False) | |
| vm.run_job('job0', wait=5) | |
| iotests.img_info_log(mid) | |
| iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, mid) | |
| iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), mid) | |
| iotests.log('=== Testing qemu-img commit (top -> base) ===') | |
| create_chain() | |
| iotests.qemu_img_log('commit', '-b', base, top) | |
| iotests.img_info_log(base) | |
| iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, base) | |
| iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), base) | |
| iotests.log('=== Testing QMP active commit (top -> base) ===') | |
| create_chain() | |
| with create_vm() as vm: | |
| vm.launch() | |
| vm.qmp_log('block-commit', device='top', base_node='base', | |
| job_id='job0', auto_dismiss=False) | |
| vm.run_job('job0', wait=5) | |
| iotests.img_info_log(mid) | |
| iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, base) | |
| iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), base) | |
| iotests.log('== Resize tests ==') | |
| # Use different sizes for different allocation modes: | |
| # | |
| # We want to have at least one test where 32 bit truncation in the size of | |
| # the overlapping area becomes visible. This is covered by the | |
| # prealloc='off' case (1G to 6G is an overlap of 5G). | |
| # | |
| # However, we can only do this for modes that don't preallocate data | |
| # because otherwise we might run out of space on the test host. | |
| # | |
| # We also want to test some unaligned combinations. | |
| for (prealloc, base_size, top_size_old, top_size_new, off) in [ | |
| ('off', '6G', '1G', '8G', '5G'), | |
| ('metadata', '32G', '30G', '33G', '31G'), | |
| ('falloc', '10M', '5M', '15M', '9M'), | |
| ('full', '16M', '8M', '12M', '11M'), | |
| ('off', '384k', '253k', '512k', '253k'), | |
| ('off', '400k', '256k', '512k', '336k'), | |
| ('off', '512k', '256k', '500k', '436k')]: | |
| iotests.log('=== preallocation=%s ===' % prealloc) | |
| iotests.qemu_img_create('-f', iotests.imgfmt, base, base_size) | |
| iotests.qemu_img_create('-f', iotests.imgfmt, '-b', base, | |
| '-F', iotests.imgfmt, top, top_size_old) | |
| iotests.qemu_io_log('-c', 'write -P 1 %s 64k' % off, base) | |
| # After this, top_size_old to base_size should be allocated/zeroed. | |
| # | |
| # In theory, leaving base_size to top_size_new unallocated would be | |
| # correct, but in practice, if we zero out anything, we zero out | |
| # everything up to top_size_new. | |
| iotests.qemu_img_log('resize', '-f', iotests.imgfmt, | |
| '--preallocation', prealloc, top, top_size_new) | |
| iotests.qemu_io_log('-c', 'read -P 0 %s 64k' % off, top) | |
| iotests.qemu_io_log('-c', 'map', top) | |
| iotests.qemu_img_log('map', '--output=json', top) |