Merge remote-tracking branch 'qemu-project/master'
[qemu/ar7.git] / tests / qemu-iotests / tests / backing-file-invalidation
blobb0e19839db9e2683e6f0b5008c726e6e43bed372
1 #!/usr/bin/env python3
2 # group: rw migration
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/>.
25 import json
26 import os
27 from typing import Optional
29 import iotests
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))
47         for i in range(1, 3):
48             backing = {
49                 'driver': iotests.imgfmt,
50                 'file': {
51                     'driver': 'file',
52                     'filename': imgs[i - 1]
53                 }
54             }
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:
61             self.vm_s.shutdown()
62         if self.vm_d is not None:
63             self.vm_d.shutdown()
65         for img in imgs:
66             try:
67                 os.remove(img)
68             except OSError:
69                 pass
70         try:
71             os.remove(mig_sock)
72         except OSError:
73             pass
75     def test_migration(self) -> None:
76         """
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
86         true.
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
90         node's filename.
91         """
93         blockdev = {
94             'node-name': 'node0',
95             'driver': iotests.imgfmt,
96             'file': {
97                 'driver': 'file',
98                 'filename': imgs[2]
99             }
100         }
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
111         self.vm_s.launch()
112         self.vm_d.launch()
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)
127         self.vm_s.shutdown()
128         self.vm_s = None
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],
135                       node_name='node0',
136                       snapshot_node_name='node0-overlay')
138         self.vm_d.shutdown()
139         self.vm_d = None
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'])