1*3e7a95feSMax Reitz#!/usr/bin/env python 2*3e7a95feSMax Reitz# 3*3e7a95feSMax Reitz# Copy-on-read tests using a COR filter node 4*3e7a95feSMax Reitz# 5*3e7a95feSMax Reitz# Copyright (C) 2018 Red Hat, Inc. 6*3e7a95feSMax Reitz# 7*3e7a95feSMax Reitz# This program is free software; you can redistribute it and/or modify 8*3e7a95feSMax Reitz# it under the terms of the GNU General Public License as published by 9*3e7a95feSMax Reitz# the Free Software Foundation; either version 2 of the License, or 10*3e7a95feSMax Reitz# (at your option) any later version. 11*3e7a95feSMax Reitz# 12*3e7a95feSMax Reitz# This program is distributed in the hope that it will be useful, 13*3e7a95feSMax Reitz# but WITHOUT ANY WARRANTY; without even the implied warranty of 14*3e7a95feSMax Reitz# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15*3e7a95feSMax Reitz# GNU General Public License for more details. 16*3e7a95feSMax Reitz# 17*3e7a95feSMax Reitz# You should have received a copy of the GNU General Public License 18*3e7a95feSMax Reitz# along with this program. If not, see <http://www.gnu.org/licenses/>. 19*3e7a95feSMax Reitz# 20*3e7a95feSMax Reitz# Creator/Owner: Max Reitz <mreitz@redhat.com> 21*3e7a95feSMax Reitz 22*3e7a95feSMax Reitzimport iotests 23*3e7a95feSMax Reitzfrom iotests import log, qemu_img_pipe, qemu_io, filter_qemu_io 24*3e7a95feSMax Reitz 25*3e7a95feSMax Reitz# Need backing file support 26*3e7a95feSMax Reitziotests.verify_image_format(supported_fmts=['qcow2', 'qcow', 'qed', 'vmdk']) 27*3e7a95feSMax Reitziotests.verify_platform(['linux']) 28*3e7a95feSMax Reitz 29*3e7a95feSMax Reitzlog('') 30*3e7a95feSMax Reitzlog('=== Copy-on-read across nodes ===') 31*3e7a95feSMax Reitzlog('') 32*3e7a95feSMax Reitz 33*3e7a95feSMax Reitz# The old copy-on-read mechanism without a filter node cannot request 34*3e7a95feSMax Reitz# WRITE_UNCHANGED permissions for its child. Therefore it just tries 35*3e7a95feSMax Reitz# to sneak its write by the usual permission system and holds its 36*3e7a95feSMax Reitz# fingers crossed. However, that sneaking does not work so well when 37*3e7a95feSMax Reitz# there is a filter node in the way: That will receive the write 38*3e7a95feSMax Reitz# request and re-issue a new one to its child, which this time is a 39*3e7a95feSMax Reitz# proper write request that will make the permission system cough -- 40*3e7a95feSMax Reitz# unless there is someone at the top (like a guest device) that has 41*3e7a95feSMax Reitz# requested write permissions. 42*3e7a95feSMax Reitz# 43*3e7a95feSMax Reitz# A COR filter node, however, can request the proper permissions for 44*3e7a95feSMax Reitz# its child and therefore is not hit by this issue. 45*3e7a95feSMax Reitz 46*3e7a95feSMax Reitzwith iotests.FilePath('base.img') as base_img_path, \ 47*3e7a95feSMax Reitz iotests.FilePath('top.img') as top_img_path, \ 48*3e7a95feSMax Reitz iotests.VM() as vm: 49*3e7a95feSMax Reitz 50*3e7a95feSMax Reitz log('--- Setting up images ---') 51*3e7a95feSMax Reitz log('') 52*3e7a95feSMax Reitz 53*3e7a95feSMax Reitz qemu_img_pipe('create', '-f', iotests.imgfmt, base_img_path, '64M') 54*3e7a95feSMax Reitz 55*3e7a95feSMax Reitz log(filter_qemu_io(qemu_io(base_img_path, '-c', 'write -P 1 0M 1M'))) 56*3e7a95feSMax Reitz 57*3e7a95feSMax Reitz qemu_img_pipe('create', '-f', iotests.imgfmt, '-b', base_img_path, 58*3e7a95feSMax Reitz top_img_path) 59*3e7a95feSMax Reitz 60*3e7a95feSMax Reitz log(filter_qemu_io(qemu_io(top_img_path, '-c', 'write -P 2 1M 1M'))) 61*3e7a95feSMax Reitz 62*3e7a95feSMax Reitz log('') 63*3e7a95feSMax Reitz log('--- Doing COR ---') 64*3e7a95feSMax Reitz log('') 65*3e7a95feSMax Reitz 66*3e7a95feSMax Reitz # Compare with e.g. the following: 67*3e7a95feSMax Reitz # vm.add_drive_raw('if=none,node-name=node0,copy-on-read=on,driver=raw,' \ 68*3e7a95feSMax Reitz # 'file.driver=%s,file.file.filename=%s' % 69*3e7a95feSMax Reitz # (iotests.imgfmt, top_img_path)) 70*3e7a95feSMax Reitz # (Remove the blockdev-add instead.) 71*3e7a95feSMax Reitz # ((Not tested here because it hits an assertion in the permission 72*3e7a95feSMax Reitz # system.)) 73*3e7a95feSMax Reitz 74*3e7a95feSMax Reitz vm.launch() 75*3e7a95feSMax Reitz 76*3e7a95feSMax Reitz log(vm.qmp('blockdev-add', 77*3e7a95feSMax Reitz node_name='node0', 78*3e7a95feSMax Reitz driver='copy-on-read', 79*3e7a95feSMax Reitz file={ 80*3e7a95feSMax Reitz 'driver': 'raw', 81*3e7a95feSMax Reitz 'file': { 82*3e7a95feSMax Reitz 'driver': 'copy-on-read', 83*3e7a95feSMax Reitz 'file': { 84*3e7a95feSMax Reitz 'driver': 'raw', 85*3e7a95feSMax Reitz 'file': { 86*3e7a95feSMax Reitz 'driver': iotests.imgfmt, 87*3e7a95feSMax Reitz 'file': { 88*3e7a95feSMax Reitz 'driver': 'file', 89*3e7a95feSMax Reitz 'filename': top_img_path 90*3e7a95feSMax Reitz }, 91*3e7a95feSMax Reitz 'backing': { 92*3e7a95feSMax Reitz 'driver': iotests.imgfmt, 93*3e7a95feSMax Reitz 'file': { 94*3e7a95feSMax Reitz 'driver': 'file', 95*3e7a95feSMax Reitz 'filename': base_img_path 96*3e7a95feSMax Reitz } 97*3e7a95feSMax Reitz } 98*3e7a95feSMax Reitz } 99*3e7a95feSMax Reitz } 100*3e7a95feSMax Reitz } 101*3e7a95feSMax Reitz })) 102*3e7a95feSMax Reitz 103*3e7a95feSMax Reitz # Trigger COR 104*3e7a95feSMax Reitz log(vm.qmp('human-monitor-command', 105*3e7a95feSMax Reitz command_line='qemu-io node0 "read 0 64M"')) 106*3e7a95feSMax Reitz 107*3e7a95feSMax Reitz vm.shutdown() 108*3e7a95feSMax Reitz 109*3e7a95feSMax Reitz log('') 110*3e7a95feSMax Reitz log('--- Checking COR result ---') 111*3e7a95feSMax Reitz log('') 112*3e7a95feSMax Reitz 113*3e7a95feSMax Reitz log(filter_qemu_io(qemu_io(base_img_path, '-c', 'discard 0 64M'))) 114*3e7a95feSMax Reitz log(filter_qemu_io(qemu_io(top_img_path, '-c', 'read -P 1 0M 1M'))) 115*3e7a95feSMax Reitz log(filter_qemu_io(qemu_io(top_img_path, '-c', 'read -P 2 1M 1M'))) 116