xref: /openbmc/qemu/tests/qemu-iotests/274 (revision 41bcea7b)
1#!/usr/bin/env python3
2# group: rw backing
3#
4# Copyright (C) 2019 Red Hat, Inc.
5#
6# This program is free software; you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation; either version 2 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program.  If not, see <http://www.gnu.org/licenses/>.
18#
19# Creator/Owner: Kevin Wolf <kwolf@redhat.com>
20#
21# Some tests for short backing files and short overlays
22
23import iotests
24
25iotests.script_initialize(supported_fmts=['qcow2'],
26                          supported_platforms=['linux'],
27                          unsupported_imgopts=['refcount_bits', 'compat'])
28
29size_short = 1 * 1024 * 1024
30size_long = 2 * 1024 * 1024
31size_diff = size_long - size_short
32
33def create_chain() -> None:
34    iotests.qemu_img_log('create', '-f', iotests.imgfmt, base,
35                         str(size_long))
36    iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', base,
37                         '-F', iotests.imgfmt, mid, str(size_short))
38    iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', mid,
39                         '-F', iotests.imgfmt, top, str(size_long))
40
41    iotests.qemu_io_log('-c', 'write -P 1 0 %d' % size_long, base)
42
43def create_vm() -> iotests.VM:
44    vm = iotests.VM()
45    vm.add_blockdev('file,filename=%s,node-name=base-file' % base)
46    vm.add_blockdev('%s,file=base-file,node-name=base' % iotests.imgfmt)
47    vm.add_blockdev('file,filename=%s,node-name=mid-file' % mid)
48    vm.add_blockdev('%s,file=mid-file,node-name=mid,backing=base'
49                    % iotests.imgfmt)
50    vm.add_drive(top, 'backing=mid,node-name=top')
51    return vm
52
53with iotests.FilePath('base') as base, \
54     iotests.FilePath('mid') as mid, \
55     iotests.FilePath('top') as top:
56
57    iotests.log('== Commit tests ==')
58
59    create_chain()
60
61    iotests.log('=== Check visible data ===')
62
63    iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, top)
64    iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), top)
65
66    iotests.log('=== Checking allocation status ===')
67
68    iotests.qemu_io_log('-c', 'alloc 0 %d' % size_short,
69                        '-c', 'alloc %d %d' % (size_short, size_diff),
70                        base)
71
72    iotests.qemu_io_log('-c', 'alloc 0 %d' % size_short,
73                        '-c', 'alloc %d %d' % (size_short, size_diff),
74                        mid)
75
76    iotests.qemu_io_log('-c', 'alloc 0 %d' % size_short,
77                        '-c', 'alloc %d %d' % (size_short, size_diff),
78                        top)
79
80    iotests.log('=== Checking map ===')
81
82    iotests.qemu_img_log('map', '--output=json', base)
83    iotests.qemu_img_log('map', '--output=human', base)
84    iotests.qemu_img_log('map', '--output=json', mid)
85    iotests.qemu_img_log('map', '--output=human', mid)
86    iotests.qemu_img_log('map', '--output=json', top)
87    iotests.qemu_img_log('map', '--output=human', top)
88
89    iotests.log('=== Testing qemu-img commit (top -> mid) ===')
90
91    iotests.qemu_img_log('commit', top)
92    iotests.img_info_log(mid)
93    iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, mid)
94    iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), mid)
95
96    iotests.log('=== Testing HMP commit (top -> mid) ===')
97
98    create_chain()
99    with create_vm() as vm:
100        vm.launch()
101        vm.qmp_log('human-monitor-command', command_line='commit drive0')
102
103    iotests.img_info_log(mid)
104    iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, mid)
105    iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), mid)
106
107    iotests.log('=== Testing QMP active commit (top -> mid) ===')
108
109    create_chain()
110    with create_vm() as vm:
111        vm.launch()
112        vm.qmp_log('block-commit', device='top', base_node='mid',
113                   job_id='job0', auto_dismiss=False)
114        vm.run_job('job0', wait=5)
115
116    iotests.img_info_log(mid)
117    iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, mid)
118    iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), mid)
119
120    iotests.log('=== Testing qemu-img commit (top -> base) ===')
121
122    create_chain()
123    iotests.qemu_img_log('commit', '-b', base, top)
124    iotests.img_info_log(base)
125    iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, base)
126    iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), base)
127
128    iotests.log('=== Testing QMP active commit (top -> base) ===')
129
130    create_chain()
131    with create_vm() as vm:
132        vm.launch()
133        vm.qmp_log('block-commit', device='top', base_node='base',
134                   job_id='job0', auto_dismiss=False)
135        vm.run_job('job0', wait=5)
136
137    iotests.img_info_log(mid)
138    iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, base)
139    iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), base)
140
141    iotests.log('== Resize tests ==')
142
143    # Use different sizes for different allocation modes:
144    #
145    # We want to have at least one test where 32 bit truncation in the size of
146    # the overlapping area becomes visible. This is covered by the
147    # prealloc='off' case (1G to 6G is an overlap of 5G).
148    #
149    # However, we can only do this for modes that don't preallocate data
150    # because otherwise we might run out of space on the test host.
151    #
152    # We also want to test some unaligned combinations.
153    for (prealloc, base_size, top_size_old, top_size_new, off) in [
154            ('off',       '6G',    '1G',   '8G',   '5G'),
155            ('metadata', '32G',   '30G',  '33G',  '31G'),
156            ('falloc',   '10M',    '5M',  '15M',   '9M'),
157            ('full',     '16M',    '8M',  '12M',  '11M'),
158            ('off',      '384k', '253k', '512k', '253k'),
159            ('off',      '400k', '256k', '512k', '336k'),
160            ('off',      '512k', '256k', '500k', '436k')]:
161
162        iotests.log('=== preallocation=%s ===' % prealloc)
163        iotests.qemu_img_log('create', '-f', iotests.imgfmt, base, base_size)
164        iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', base,
165                             '-F', iotests.imgfmt, top, top_size_old)
166        iotests.qemu_io_log('-c', 'write -P 1 %s 64k' % off, base)
167
168        # After this, top_size_old to base_size should be allocated/zeroed.
169        #
170        # In theory, leaving base_size to top_size_new unallocated would be
171        # correct, but in practice, if we zero out anything, we zero out
172        # everything up to top_size_new.
173        iotests.qemu_img_log('resize', '-f', iotests.imgfmt,
174                             '--preallocation', prealloc, top, top_size_new)
175        iotests.qemu_io_log('-c', 'read -P 0 %s 64k' % off, top)
176        iotests.qemu_io_log('-c', 'map', top)
177        iotests.qemu_img_log('map', '--output=json', top)
178