1#!/usr/bin/env python3 2# group: auto quick 3# 4# Test for backup-top filter permission activation failure 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 22import iotests 23 24# The test is unrelated to formats, restrict it to qcow2 to avoid extra runs 25iotests.script_initialize( 26 supported_fmts=['qcow2'], 27) 28 29size = 1024 * 1024 30 31""" Test description 32 33When performing a backup, all writes on the source subtree must go through the 34backup-top filter so it can copy all data to the target before it is changed. 35backup-top filter is appended above source node, to achieve this thing, so all 36parents of source node are handled. A configuration with side parents of source 37sub-tree with write permission is unsupported (we'd have append several 38backup-top filter like nodes to handle such parents). The test create an 39example of such configuration and checks that a backup is then not allowed 40(blockdev-backup command should fail). 41 42The configuration: 43 44 ┌────────┐ target ┌─────────────┐ 45 │ target │ ◀─────── │ backup_top │ 46 └────────┘ └─────────────┘ 47 │ 48 │ backing 49 ▼ 50 ┌─────────────┐ 51 │ source │ 52 └─────────────┘ 53 │ 54 │ file 55 ▼ 56 ┌─────────────┐ write perm ┌───────┐ 57 │ base │ ◀──────────── │ other │ 58 └─────────────┘ └───────┘ 59 60On activation (see .active field of backup-top state in block/backup-top.c), 61backup-top is going to unshare write permission on its source child. Write 62unsharing will be propagated to the "source->base" link and will conflict with 63other node write permission. So permission update will fail and backup job will 64not be started. 65 66Note, that the only thing which prevents backup of running on such 67configuration is default permission propagation scheme. It may be altered by 68different block drivers, so backup will run in invalid configuration. But 69something is better than nothing. Also, before the previous commit (commit 70preceding this test creation), starting backup on such configuration led to 71crash, so current "something" is a lot better, and this test actual goal is 72to check that crash is fixed :) 73""" 74 75vm = iotests.VM() 76vm.launch() 77 78vm.qmp_log('blockdev-add', **{ 79 'node-name': 'target', 80 'driver': 'null-co', 81 'size': size, 82}) 83 84vm.qmp_log('blockdev-add', **{ 85 'node-name': 'source', 86 'driver': 'blkdebug', 87 'image': {'node-name': 'base', 'driver': 'null-co', 'size': size} 88}) 89 90vm.qmp_log('blockdev-add', **{ 91 'node-name': 'other', 92 'driver': 'blkdebug', 93 'image': 'base', 94 'take-child-perms': ['write'] 95}) 96 97vm.qmp_log('blockdev-backup', sync='full', device='source', target='target') 98 99vm.shutdown() 100 101 102print('\n=== backup-top should be gone after job-finalize ===\n') 103 104# Check that the backup-top node is gone after job-finalize. 105# 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. 109 110vm = iotests.VM() 111vm.launch() 112 113vm.qmp_log('blockdev-add', **{ 114 'node-name': 'source', 115 'driver': 'null-co', 116}) 117 118vm.qmp_log('blockdev-add', **{ 119 'node-name': 'target', 120 'driver': 'null-co', 121}) 122 123vm.qmp_log('blockdev-backup', 124 job_id='backup', 125 device='source', 126 target='target', 127 sync='full', 128 filter_node_name='backup-filter', 129 auto_finalize=False, 130 auto_dismiss=False) 131 132vm.event_wait('BLOCK_JOB_PENDING', 5.0) 133 134# The backup-top filter should still be present prior to finalization 135assert vm.node_info('backup-filter') is not None 136 137vm.qmp_log('job-finalize', id='backup') 138vm.event_wait('BLOCK_JOB_COMPLETED', 5.0) 139 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 142# there.). 143vm.qmp_log('human-monitor-command', 144 command_line='qemu-io backup-filter "write 0 1M"') 145 146# (Also, do an explicit check.) 147assert vm.node_info('backup-filter') is None 148 149vm.qmp_log('job-dismiss', id='backup') 150vm.event_wait('JOB_STATUS_CHANGE', 5.0, {'data': {'status': 'null'}}) 151 152vm.shutdown() 153