4 # Test for backup-top filter permission activation failure
6 # Copyright (c) 2019 Virtuozzo International GmbH.
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.
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.
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/>.
24 # The test is unrelated to formats, restrict it to qcow2 to avoid extra runs
25 iotests.script_initialize(
26 supported_fmts=['qcow2'],
33 When performing a backup, all writes on the source subtree must go through the
34 backup-top filter so it can copy all data to the target before it is changed.
35 backup-top filter is appended above source node, to achieve this thing, so all
36 parents of source node are handled. A configuration with side parents of source
37 sub-tree with write permission is unsupported (we'd have append several
38 backup-top filter like nodes to handle such parents). The test create an
39 example of such configuration and checks that a backup is then not allowed
40 (blockdev-backup command should fail).
44 ┌────────┐ target ┌─────────────┐
45 │ target │ ◀─────── │ backup_top │
46 └────────┘ └─────────────┘
56 ┌─────────────┐ write perm ┌───────┐
57 │ base │ ◀──────────── │ other │
58 └─────────────┘ └───────┘
60 On activation (see .active field of backup-top state in block/backup-top.c),
61 backup-top is going to unshare write permission on its source child. Write
62 unsharing will be propagated to the "source->base" link and will conflict with
63 other node write permission. So permission update will fail and backup job will
66 Note, that the only thing which prevents backup of running on such
67 configuration is default permission propagation scheme. It may be altered by
68 different block drivers, so backup will run in invalid configuration. But
69 something is better than nothing. Also, before the previous commit (commit
70 preceding this test creation), starting backup on such configuration led to
71 crash, so current "something" is a lot better, and this test actual goal is
72 to check that crash is fixed :)
78 vm.qmp_log('blockdev-add', **{
79 'node-name': 'target',
84 vm.qmp_log('blockdev-add', **{
85 'node-name': 'source',
87 'image': {'node-name': 'base', 'driver': 'null-co', 'size': size}
90 vm.qmp_log('blockdev-add', **{
94 'take-child-perms': ['write']
97 vm.qmp_log('blockdev-backup', sync='full', device='source', target='target')
102 print('\n=== backup-top should be gone after job-finalize ===\n')
104 # Check that the backup-top node is gone after job-finalize.
106 # During finalization, the node becomes inactive and can no longer
107 # function. If it is still present, new parents might be attached, and
108 # there would be no meaningful way to handle their I/O requests.
113 vm.qmp_log('blockdev-add', **{
114 'node-name': 'source',
118 vm.qmp_log('blockdev-add', **{
119 'node-name': 'target',
123 vm.qmp_log('blockdev-backup',
128 filter_node_name='backup-filter',
132 vm.event_wait('BLOCK_JOB_PENDING', 5.0)
134 # The backup-top filter should still be present prior to finalization
135 assert vm.node_info('backup-filter') is not None
137 vm.qmp_log('job-finalize', id='backup')
138 vm.event_wait('BLOCK_JOB_COMPLETED', 5.0)
140 # The filter should be gone now. Check that by trying to access it
141 # with qemu-io (which will most likely crash qemu if it is still
143 vm.qmp_log('human-monitor-command',
144 command_line='qemu-io backup-filter "write 0 1M"')
146 # (Also, do an explicit check.)
147 assert vm.node_info('backup-filter') is None
149 vm.qmp_log('job-dismiss', id='backup')
150 vm.event_wait('JOB_STATUS_CHANGE', 5.0, {'data': {'status': 'null'}})