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-Ogievskiy │ 48a541fcc2SVladimir Sementsov-Ogievskiy │ backing 49a541fcc2SVladimir Sementsov-Ogievskiy ▼ 50a541fcc2SVladimir Sementsov-Ogievskiy ┌─────────────┐ 51a541fcc2SVladimir Sementsov-Ogievskiy │ source │ 52a541fcc2SVladimir Sementsov-Ogievskiy └─────────────┘ 53a541fcc2SVladimir Sementsov-Ogievskiy │ 54a541fcc2SVladimir Sementsov-Ogievskiy │ file 55a541fcc2SVladimir Sementsov-Ogievskiy ▼ 56a541fcc2SVladimir 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