xref: /openbmc/qemu/tests/qemu-iotests/283 (revision e41799409281eab19c17692d1c52cb4cef7f5494)
17c477526SPhilippe Mathieu-Daudé#!/usr/bin/env python3
29dd003a9SVladimir Sementsov-Ogievskiy# group: auto quick
3a541fcc2SVladimir Sementsov-Ogievskiy#
4a541fcc2SVladimir Sementsov-Ogievskiy# Test for backup-top filter permission activation failure
5a541fcc2SVladimir Sementsov-Ogievskiy#
6a541fcc2SVladimir Sementsov-Ogievskiy# Copyright (c) 2019 Virtuozzo International GmbH.
7a541fcc2SVladimir Sementsov-Ogievskiy#
8a541fcc2SVladimir Sementsov-Ogievskiy# This program is free software; you can redistribute it and/or modify
9a541fcc2SVladimir Sementsov-Ogievskiy# it under the terms of the GNU General Public License as published by
10a541fcc2SVladimir Sementsov-Ogievskiy# the Free Software Foundation; either version 2 of the License, or
11a541fcc2SVladimir Sementsov-Ogievskiy# (at your option) any later version.
12a541fcc2SVladimir Sementsov-Ogievskiy#
13a541fcc2SVladimir Sementsov-Ogievskiy# This program is distributed in the hope that it will be useful,
14a541fcc2SVladimir Sementsov-Ogievskiy# but WITHOUT ANY WARRANTY; without even the implied warranty of
15a541fcc2SVladimir Sementsov-Ogievskiy# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16a541fcc2SVladimir Sementsov-Ogievskiy# GNU General Public License for more details.
17a541fcc2SVladimir Sementsov-Ogievskiy#
18a541fcc2SVladimir Sementsov-Ogievskiy# You should have received a copy of the GNU General Public License
19a541fcc2SVladimir Sementsov-Ogievskiy# along with this program.  If not, see <http://www.gnu.org/licenses/>.
20a541fcc2SVladimir Sementsov-Ogievskiy#
21a541fcc2SVladimir Sementsov-Ogievskiy
22a541fcc2SVladimir Sementsov-Ogievskiyimport iotests
23a541fcc2SVladimir Sementsov-Ogievskiy
24a541fcc2SVladimir Sementsov-Ogievskiy# The test is unrelated to formats, restrict it to qcow2 to avoid extra runs
257d814059SJohn Snowiotests.script_initialize(
267d814059SJohn Snow    supported_fmts=['qcow2'],
277d814059SJohn Snow)
28a541fcc2SVladimir Sementsov-Ogievskiy
29a541fcc2SVladimir Sementsov-Ogievskiysize = 1024 * 1024
30a541fcc2SVladimir Sementsov-Ogievskiy
31a541fcc2SVladimir Sementsov-Ogievskiy""" Test description
32a541fcc2SVladimir Sementsov-Ogievskiy
33a541fcc2SVladimir Sementsov-OgievskiyWhen performing a backup, all writes on the source subtree must go through the
34a541fcc2SVladimir Sementsov-Ogievskiybackup-top filter so it can copy all data to the target before it is changed.
35a541fcc2SVladimir Sementsov-Ogievskiybackup-top filter is appended above source node, to achieve this thing, so all
36a541fcc2SVladimir Sementsov-Ogievskiyparents of source node are handled. A configuration with side parents of source
37a541fcc2SVladimir Sementsov-Ogievskiysub-tree with write permission is unsupported (we'd have append several
38a541fcc2SVladimir Sementsov-Ogievskiybackup-top filter like nodes to handle such parents). The test create an
39a541fcc2SVladimir Sementsov-Ogievskiyexample of such configuration and checks that a backup is then not allowed
40a541fcc2SVladimir Sementsov-Ogievskiy(blockdev-backup command should fail).
41a541fcc2SVladimir Sementsov-Ogievskiy
42a541fcc2SVladimir Sementsov-OgievskiyThe configuration:
43a541fcc2SVladimir Sementsov-Ogievskiy
44a541fcc2SVladimir Sementsov-Ogievskiy    ┌────────┐  target  ┌─────────────┐
45a541fcc2SVladimir Sementsov-Ogievskiy    │ target │ ◀─────── │ backup_top  │
46a541fcc2SVladimir Sementsov-Ogievskiy    └────────┘          └─────────────┘
47a541fcc2SVladimir Sementsov-Ogievskiy48a541fcc2SVladimir Sementsov-Ogievskiy                            │ backing
49a541fcc2SVladimir Sementsov-Ogievskiy50a541fcc2SVladimir Sementsov-Ogievskiy                        ┌─────────────┐
51a541fcc2SVladimir Sementsov-Ogievskiy                        │   source    │
52a541fcc2SVladimir Sementsov-Ogievskiy                        └─────────────┘
53a541fcc2SVladimir Sementsov-Ogievskiy54a541fcc2SVladimir Sementsov-Ogievskiy                            │ file
55a541fcc2SVladimir Sementsov-Ogievskiy56a541fcc2SVladimir Sementsov-Ogievskiy                        ┌─────────────┐  write perm   ┌───────┐
57a541fcc2SVladimir Sementsov-Ogievskiy                        │    base     │ ◀──────────── │ other │
58a541fcc2SVladimir Sementsov-Ogievskiy                        └─────────────┘               └───────┘
59a541fcc2SVladimir Sementsov-Ogievskiy
60a541fcc2SVladimir Sementsov-OgievskiyOn activation (see .active field of backup-top state in block/backup-top.c),
61a541fcc2SVladimir Sementsov-Ogievskiybackup-top is going to unshare write permission on its source child. Write
62a541fcc2SVladimir Sementsov-Ogievskiyunsharing will be propagated to the "source->base" link and will conflict with
63a541fcc2SVladimir Sementsov-Ogievskiyother node write permission. So permission update will fail and backup job will
64a541fcc2SVladimir Sementsov-Ogievskiynot be started.
65a541fcc2SVladimir Sementsov-Ogievskiy
66a541fcc2SVladimir Sementsov-OgievskiyNote, that the only thing which prevents backup of running on such
67a541fcc2SVladimir Sementsov-Ogievskiyconfiguration is default permission propagation scheme. It may be altered by
68a541fcc2SVladimir Sementsov-Ogievskiydifferent block drivers, so backup will run in invalid configuration. But
69a541fcc2SVladimir Sementsov-Ogievskiysomething is better than nothing. Also, before the previous commit (commit
70a541fcc2SVladimir Sementsov-Ogievskiypreceding this test creation), starting backup on such configuration led to
71a541fcc2SVladimir Sementsov-Ogievskiycrash, so current "something" is a lot better, and this test actual goal is
72a541fcc2SVladimir Sementsov-Ogievskiyto check that crash is fixed :)
73a541fcc2SVladimir Sementsov-Ogievskiy"""
74a541fcc2SVladimir Sementsov-Ogievskiy
75a541fcc2SVladimir Sementsov-Ogievskiyvm = iotests.VM()
76a541fcc2SVladimir Sementsov-Ogievskiyvm.launch()
77a541fcc2SVladimir Sementsov-Ogievskiy
78813cc254SKevin Wolfvm.qmp_log('blockdev-add', **{
79813cc254SKevin Wolf    'node-name': 'target',
80813cc254SKevin Wolf    'driver': 'null-co',
81813cc254SKevin Wolf    'size': size,
82813cc254SKevin Wolf})
83a541fcc2SVladimir Sementsov-Ogievskiy
84a541fcc2SVladimir Sementsov-Ogievskiyvm.qmp_log('blockdev-add', **{
85a541fcc2SVladimir Sementsov-Ogievskiy    'node-name': 'source',
86a541fcc2SVladimir Sementsov-Ogievskiy    'driver': 'blkdebug',
87a541fcc2SVladimir Sementsov-Ogievskiy    'image': {'node-name': 'base', 'driver': 'null-co', 'size': size}
88a541fcc2SVladimir Sementsov-Ogievskiy})
89a541fcc2SVladimir Sementsov-Ogievskiy
90a541fcc2SVladimir Sementsov-Ogievskiyvm.qmp_log('blockdev-add', **{
91a541fcc2SVladimir Sementsov-Ogievskiy    'node-name': 'other',
92a541fcc2SVladimir Sementsov-Ogievskiy    'driver': 'blkdebug',
93a541fcc2SVladimir Sementsov-Ogievskiy    'image': 'base',
94a541fcc2SVladimir Sementsov-Ogievskiy    'take-child-perms': ['write']
95a541fcc2SVladimir Sementsov-Ogievskiy})
96a541fcc2SVladimir Sementsov-Ogievskiy
97a541fcc2SVladimir Sementsov-Ogievskiyvm.qmp_log('blockdev-backup', sync='full', device='source', target='target')
98a541fcc2SVladimir Sementsov-Ogievskiy
99a541fcc2SVladimir Sementsov-Ogievskiyvm.shutdown()
100*e4179940SMax Reitz
101*e4179940SMax Reitz
102*e4179940SMax Reitzprint('\n=== backup-top should be gone after job-finalize ===\n')
103*e4179940SMax Reitz
104*e4179940SMax Reitz# Check that the backup-top node is gone after job-finalize.
105*e4179940SMax Reitz#
106*e4179940SMax Reitz# During finalization, the node becomes inactive and can no longer
107*e4179940SMax Reitz# function.  If it is still present, new parents might be attached, and
108*e4179940SMax Reitz# there would be no meaningful way to handle their I/O requests.
109*e4179940SMax Reitz
110*e4179940SMax Reitzvm = iotests.VM()
111*e4179940SMax Reitzvm.launch()
112*e4179940SMax Reitz
113*e4179940SMax Reitzvm.qmp_log('blockdev-add', **{
114*e4179940SMax Reitz    'node-name': 'source',
115*e4179940SMax Reitz    'driver': 'null-co',
116*e4179940SMax Reitz})
117*e4179940SMax Reitz
118*e4179940SMax Reitzvm.qmp_log('blockdev-add', **{
119*e4179940SMax Reitz    'node-name': 'target',
120*e4179940SMax Reitz    'driver': 'null-co',
121*e4179940SMax Reitz})
122*e4179940SMax Reitz
123*e4179940SMax Reitzvm.qmp_log('blockdev-backup',
124*e4179940SMax Reitz           job_id='backup',
125*e4179940SMax Reitz           device='source',
126*e4179940SMax Reitz           target='target',
127*e4179940SMax Reitz           sync='full',
128*e4179940SMax Reitz           filter_node_name='backup-filter',
129*e4179940SMax Reitz           auto_finalize=False,
130*e4179940SMax Reitz           auto_dismiss=False)
131*e4179940SMax Reitz
132*e4179940SMax Reitzvm.event_wait('BLOCK_JOB_PENDING', 5.0)
133*e4179940SMax Reitz
134*e4179940SMax Reitz# The backup-top filter should still be present prior to finalization
135*e4179940SMax Reitzassert vm.node_info('backup-filter') is not None
136*e4179940SMax Reitz
137*e4179940SMax Reitzvm.qmp_log('job-finalize', id='backup')
138*e4179940SMax Reitzvm.event_wait('BLOCK_JOB_COMPLETED', 5.0)
139*e4179940SMax Reitz
140*e4179940SMax Reitz# The filter should be gone now.  Check that by trying to access it
141*e4179940SMax Reitz# with qemu-io (which will most likely crash qemu if it is still
142*e4179940SMax Reitz# there.).
143*e4179940SMax Reitzvm.qmp_log('human-monitor-command',
144*e4179940SMax Reitz           command_line='qemu-io backup-filter "write 0 1M"')
145*e4179940SMax Reitz
146*e4179940SMax Reitz# (Also, do an explicit check.)
147*e4179940SMax Reitzassert vm.node_info('backup-filter') is None
148*e4179940SMax Reitz
149*e4179940SMax Reitzvm.qmp_log('job-dismiss', id='backup')
150*e4179940SMax Reitzvm.event_wait('JOB_STATUS_CHANGE', 5.0, {'data': {'status': 'null'}})
151*e4179940SMax Reitz
152*e4179940SMax Reitzvm.shutdown()
153