master
text 149 lines 5.06 KB
Raw
1 #!/usr/bin/env python3
2 # group: auto quick
3 #
4 # Test for copy-before-write filter permission conflict
5 #
6 # Copyright (c) 2019 Virtuozzo International GmbH.
7 #
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.
12 #
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.
17 #
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/>.
20 #
21
22 import iotests
23
24 # The test is unrelated to formats, restrict it to qcow2 to avoid extra runs
25 iotests.script_initialize(
26 supported_fmts=['qcow2'],
27 require_hmp=True,
28 )
29
30 size = 1024 * 1024
31
32 """ Test description
33
34 When performing a backup, all writes on the source subtree must go through the
35 copy-before-write filter so it can copy all data to the target before it is
36 changed. copy-before-write filter is appended above source node, to achieve
37 this thing, so all parents of source node are handled. A configuration with
38 side parents of source sub-tree with write permission is unsupported (we'd have
39 append several copy-before-write filter like nodes to handle such parents). The
40 test create an example of such configuration and checks that a backup is then
41 not allowed (blockdev-backup command should fail).
42
43 The configuration:
44
45 ┌────────┐ target ┌─────────────┐
46 │ target │ ◀─────── │ backup_top │
47 └────────┘ └─────────────┘
48
49 │ backing
50
51 ┌─────────────┐
52 │ source │
53 └─────────────┘
54
55 │ file
56
57 ┌─────────────┐ write perm ┌───────┐
58 │ base │ ◀──────────── │ other │
59 └─────────────┘ └───────┘
60
61 copy-before-write filter wants to unshare write permission on its source child.
62 Write unsharing will be propagated to the "source->base" link and will conflict
63 with other node write permission. So permission update will fail and backup job
64 will not be started.
65
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 :)
73 """
74
75 vm = iotests.VM()
76 vm.launch()
77
78 vm.qmp_log('blockdev-add', **{
79 'node-name': 'target',
80 'driver': 'null-co',
81 'size': size,
82 })
83
84 vm.qmp_log('blockdev-add', **{
85 'node-name': 'source',
86 'driver': 'blkdebug',
87 'image': {'node-name': 'base', 'driver': 'null-co', 'size': size}
88 })
89
90 vm.qmp_log('blockdev-add', **{
91 'node-name': 'other',
92 'driver': 'blkdebug',
93 'image': 'base',
94 'take-child-perms': ['write']
95 })
96
97 vm.qmp_log('blockdev-backup', sync='full', device='source', target='target',
98 job_id="backup0")
99
100 vm.shutdown()
101
102
103 print('\n=== copy-before-write filter should be gone after job-finalize ===\n')
104
105 # Check that the copy-before-write node is gone after job-finalize.
106
107 vm = iotests.VM()
108 vm.launch()
109
110 vm.qmp_log('blockdev-add', **{
111 'node-name': 'source',
112 'driver': 'null-co',
113 })
114
115 vm.qmp_log('blockdev-add', **{
116 'node-name': 'target',
117 'driver': 'null-co',
118 })
119
120 vm.qmp_log('blockdev-backup',
121 job_id='backup',
122 device='source',
123 target='target',
124 sync='full',
125 filter_node_name='backup-filter',
126 auto_finalize=False,
127 auto_dismiss=False)
128
129 vm.event_wait('BLOCK_JOB_PENDING', 5.0)
130
131 # The copy-before-write filter should still be present prior to finalization
132 assert vm.node_info('backup-filter') is not None
133
134 vm.qmp_log('job-finalize', id='backup')
135 vm.event_wait('BLOCK_JOB_COMPLETED', 5.0)
136
137 # The filter should be gone now. Check that by trying to access it
138 # with qemu-io (which will most likely crash qemu if it is still
139 # there.).
140 vm.qmp_log('human-monitor-command',
141 command_line='qemu-io backup-filter "write 0 1M"')
142
143 # (Also, do an explicit check.)
144 assert vm.node_info('backup-filter') is None
145
146 vm.qmp_log('job-dismiss', id='backup')
147 vm.event_wait('JOB_STATUS_CHANGE', 5.0, {'data': {'status': 'null'}})
148
149 vm.shutdown()