4 # Migrate a VM with a BDS with backing nodes, which runs
5 # bdrv_invalidate_cache(), which for qcow2 and qed triggers reading the
6 # backing file string from the image header. Check whether this
7 # interferes with bdrv_backing_overridden().
9 # Copyright (C) 2022 Red Hat, Inc.
11 # This program is free software; you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published by
13 # the Free Software Foundation; either version 2 of the License, or
14 # (at your option) any later version.
16 # This program is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 # GNU General Public License for more details.
21 # You should have received a copy of the GNU General Public License
22 # along with this program. If not, see <http://www.gnu.org/licenses/>.
27 from typing import Optional
30 from iotests import qemu_img_create, qemu_img_info
33 image_size = 1 * 1024 * 1024
34 imgs = [os.path.join(iotests.test_dir, f'{i}.img') for i in range(0, 4)]
36 mig_sock = os.path.join(iotests.sock_dir, 'mig.sock')
39 class TestPostMigrateFilename(iotests.QMPTestCase):
40 vm_s: Optional[iotests.VM] = None
41 vm_d: Optional[iotests.VM] = None
43 def setUp(self) -> None:
44 # Create backing chain of three images, where the backing file strings
45 # are json:{} filenames
46 qemu_img_create('-f', iotests.imgfmt, imgs[0], str(image_size))
49 'driver': iotests.imgfmt,
52 'filename': imgs[i - 1]
55 qemu_img_create('-f', iotests.imgfmt, '-F', iotests.imgfmt,
56 '-b', 'json:' + json.dumps(backing),
57 imgs[i], str(image_size))
59 def tearDown(self) -> None:
60 if self.vm_s is not None:
62 if self.vm_d is not None:
75 def test_migration(self) -> None:
77 Migrate a VM with the backing chain created in setUp() attached. At
78 the end of the migration process, the destination will run
79 bdrv_invalidate_cache(), which for some image formats (qcow2 and qed)
80 means the backing file string is re-read from the image header. If
81 this overwrites bs->auto_backing_file, doing so may cause
82 bdrv_backing_overridden() to become true: The image header reports a
83 json:{} filename, but when opening it, bdrv_refresh_filename() will
84 simplify it to a plain simple filename; and when bs->auto_backing_file
85 and bs->backing->bs->filename differ, bdrv_backing_overridden() becomes
87 If bdrv_backing_overridden() is true, the BDS will be forced to get a
88 json:{} filename, which in general is not the end of the world, but not
89 great. Check whether that happens, i.e. whether migration changes the
95 'driver': iotests.imgfmt,
102 self.vm_s = iotests.VM(path_suffix='a') \
103 .add_blockdev(json.dumps(blockdev))
104 self.vm_d = iotests.VM(path_suffix='b') \
105 .add_blockdev(json.dumps(blockdev)) \
106 .add_incoming(f'unix:{mig_sock}')
108 assert self.vm_s is not None
109 assert self.vm_d is not None
114 pre_mig_filename = self.vm_s.node_info('node0')['file']
116 self.vm_s.qmp('migrate', uri=f'unix:{mig_sock}')
118 # Wait for migration to be done
119 self.vm_s.event_wait('STOP')
120 self.vm_d.event_wait('RESUME')
122 post_mig_filename = self.vm_d.node_info('node0')['file']
124 # Verify that the filename hasn't changed from before the migration
125 self.assertEqual(pre_mig_filename, post_mig_filename)
130 # For good measure, try creating an overlay and check its backing
131 # chain below. This is how the issue was originally found.
132 self.vm_d.cmd('blockdev-snapshot-sync',
133 format=iotests.imgfmt,
134 snapshot_file=imgs[3],
136 snapshot_node_name='node0-overlay')
141 # Check the newly created overlay's backing chain
142 chain = qemu_img_info('--backing-chain', imgs[3])
143 for index, image in enumerate(chain):
144 self.assertEqual(image['filename'], imgs[3 - index])
147 if __name__ == '__main__':
148 # These are the image formats that run their open() function from their
149 # .bdrv_co_invaliate_cache() implementations, so test them
150 iotests.main(supported_fmts=['qcow2', 'qed'],
151 supported_protocols=['file'])