1e6c79647SMax Reitz#!/usr/bin/env bash 29dd003a9SVladimir Sementsov-Ogievskiy# group: rw 3e6c79647SMax Reitz# 4e6c79647SMax Reitz# Test FUSE exports (in ways that are not captured by the generic 5e6c79647SMax Reitz# tests) 6e6c79647SMax Reitz# 7e6c79647SMax Reitz# Copyright (C) 2020 Red Hat, Inc. 8e6c79647SMax Reitz# 9e6c79647SMax Reitz# This program is free software; you can redistribute it and/or modify 10e6c79647SMax Reitz# it under the terms of the GNU General Public License as published by 11e6c79647SMax Reitz# the Free Software Foundation; either version 2 of the License, or 12e6c79647SMax Reitz# (at your option) any later version. 13e6c79647SMax Reitz# 14e6c79647SMax Reitz# This program is distributed in the hope that it will be useful, 15e6c79647SMax Reitz# but WITHOUT ANY WARRANTY; without even the implied warranty of 16e6c79647SMax Reitz# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17e6c79647SMax Reitz# GNU General Public License for more details. 18e6c79647SMax Reitz# 19e6c79647SMax Reitz# You should have received a copy of the GNU General Public License 20e6c79647SMax Reitz# along with this program. If not, see <http://www.gnu.org/licenses/>. 21e6c79647SMax Reitz# 22e6c79647SMax Reitz 23e6c79647SMax Reitzseq=$(basename "$0") 24e6c79647SMax Reitzecho "QA output created by $seq" 25e6c79647SMax Reitz 26e6c79647SMax Reitzstatus=1 # failure is the default! 27e6c79647SMax Reitz 28e6c79647SMax Reitz_cleanup() 29e6c79647SMax Reitz{ 30e6c79647SMax Reitz _cleanup_qemu 31e6c79647SMax Reitz _cleanup_test_img 32e6c79647SMax Reitz rmdir "$EXT_MP" 2>/dev/null 33e6c79647SMax Reitz rm -f "$EXT_MP" 34e6c79647SMax Reitz rm -f "$COPIED_IMG" 35e6c79647SMax Reitz} 36e6c79647SMax Reitztrap "_cleanup; exit \$status" 0 1 2 3 15 37e6c79647SMax Reitz 38e6c79647SMax Reitz# get standard environment, filters and checks 39e6c79647SMax Reitz. ./common.rc 40e6c79647SMax Reitz. ./common.filter 41e6c79647SMax Reitz. ./common.qemu 42e6c79647SMax Reitz 43e6c79647SMax Reitz# Generic format, but needs a plain filename 44e6c79647SMax Reitz_supported_fmt generic 45e6c79647SMax Reitzif [ "$IMGOPTSSYNTAX" = "true" ]; then 46e6c79647SMax Reitz _unsupported_fmt $IMGFMT 47e6c79647SMax Reitzfi 48e6c79647SMax Reitz# We need the image to have exactly the specified size, and VPC does 49e6c79647SMax Reitz# not allow that by default 50e6c79647SMax Reitz_unsupported_fmt vpc 51e6c79647SMax Reitz 52e6c79647SMax Reitz_supported_proto file # We create the FUSE export manually 53e6c79647SMax Reitz_supported_os Linux # We need /dev/urandom 54*c49dda72SEric Blake_require_disk_usage 55e6c79647SMax Reitz 56e6c79647SMax Reitz# $1: Export ID 57e6c79647SMax Reitz# $2: Options (beyond the node-name and ID) 58e6c79647SMax Reitz# $3: Expected return value (defaults to 'return') 59e6c79647SMax Reitz# $4: Node to export (defaults to 'node-format') 60e6c79647SMax Reitzfuse_export_add() 61e6c79647SMax Reitz{ 628fc54f94SMax Reitz # The grep -v is a filter for errors when /etc/fuse.conf does not contain 638fc54f94SMax Reitz # user_allow_other. (The error is benign, but it is printed by fusermount 648fc54f94SMax Reitz # on the first mount attempt, so our export code cannot hide it.) 65e6c79647SMax Reitz _send_qemu_cmd $QEMU_HANDLE \ 66e6c79647SMax Reitz "{'execute': 'block-export-add', 67e6c79647SMax Reitz 'arguments': { 68e6c79647SMax Reitz 'type': 'fuse', 69e6c79647SMax Reitz 'id': '$1', 70e6c79647SMax Reitz 'node-name': '${4:-node-format}', 71e6c79647SMax Reitz $2 72e6c79647SMax Reitz } }" \ 73e6c79647SMax Reitz "${3:-return}" \ 748fc54f94SMax Reitz | _filter_imgfmt \ 758fc54f94SMax Reitz | grep -v 'option allow_other only allowed if' 76e6c79647SMax Reitz} 77e6c79647SMax Reitz 78e6c79647SMax Reitz# $1: Export ID 79e6c79647SMax Reitzfuse_export_del() 80e6c79647SMax Reitz{ 81effd60c8SStefan Hajnoczi capture_events="BLOCK_EXPORT_DELETED" \ 82e6c79647SMax Reitz _send_qemu_cmd $QEMU_HANDLE \ 83e6c79647SMax Reitz "{'execute': 'block-export-del', 84e6c79647SMax Reitz 'arguments': { 85e6c79647SMax Reitz 'id': '$1' 86e6c79647SMax Reitz } }" \ 87e6c79647SMax Reitz 'return' 88e6c79647SMax Reitz 89effd60c8SStefan Hajnoczi _wait_event $QEMU_HANDLE \ 90e6c79647SMax Reitz 'BLOCK_EXPORT_DELETED' 91e6c79647SMax Reitz} 92e6c79647SMax Reitz 93e6c79647SMax Reitz# Return the length of the protocol file 94e6c79647SMax Reitz# $1: Protocol node export mount point 95e6c79647SMax Reitz# $2: Original file (to compare) 96e6c79647SMax Reitzget_proto_len() 97e6c79647SMax Reitz{ 98e6c79647SMax Reitz len1=$(stat -c '%s' "$1") 99e6c79647SMax Reitz len2=$(stat -c '%s' "$2") 100e6c79647SMax Reitz 101e6c79647SMax Reitz if [ "$len1" != "$len2" ]; then 102e6c79647SMax Reitz echo 'ERROR: Length of export and original differ:' >&2 103e6c79647SMax Reitz echo "$len1 != $len2" >&2 104e6c79647SMax Reitz else 105e6c79647SMax Reitz echo '(OK: Lengths of export and original are the same)' >&2 106e6c79647SMax Reitz fi 107e6c79647SMax Reitz 108e6c79647SMax Reitz echo "$len1" 109e6c79647SMax Reitz} 110e6c79647SMax Reitz 111e6c79647SMax ReitzCOPIED_IMG="$TEST_IMG.copy" 112e6c79647SMax ReitzEXT_MP="$TEST_IMG.fuse" 113e6c79647SMax Reitz 114e6c79647SMax Reitzecho '=== Set up ===' 115e6c79647SMax Reitz 116e6c79647SMax Reitz# Create image with random data 117e6c79647SMax Reitz_make_test_img 64M 118e6c79647SMax Reitz$QEMU_IO -c 'write -s /dev/urandom 0 64M' "$TEST_IMG" | _filter_qemu_io 119e6c79647SMax Reitz 120e6c79647SMax Reitz_launch_qemu 121e6c79647SMax Reitz_send_qemu_cmd $QEMU_HANDLE \ 122e6c79647SMax Reitz "{'execute': 'qmp_capabilities'}" \ 123e6c79647SMax Reitz 'return' 124e6c79647SMax Reitz 125e6c79647SMax Reitz# Separate blockdev-add calls for format and protocol so we can remove 126e6c79647SMax Reitz# the format layer later on 127e6c79647SMax Reitz_send_qemu_cmd $QEMU_HANDLE \ 128e6c79647SMax Reitz "{'execute': 'blockdev-add', 129e6c79647SMax Reitz 'arguments': { 130e6c79647SMax Reitz 'driver': 'file', 131e6c79647SMax Reitz 'node-name': 'node-protocol', 132e6c79647SMax Reitz 'filename': '$TEST_IMG' 133e6c79647SMax Reitz } }" \ 134e6c79647SMax Reitz 'return' 135e6c79647SMax Reitz 136e6c79647SMax Reitz_send_qemu_cmd $QEMU_HANDLE \ 137e6c79647SMax Reitz "{'execute': 'blockdev-add', 138e6c79647SMax Reitz 'arguments': { 139e6c79647SMax Reitz 'driver': '$IMGFMT', 140e6c79647SMax Reitz 'node-name': 'node-format', 141e6c79647SMax Reitz 'file': 'node-protocol' 142e6c79647SMax Reitz } }" \ 143e6c79647SMax Reitz 'return' 144e6c79647SMax Reitz 145e6c79647SMax Reitzecho 146e6c79647SMax Reitzecho '=== Mountpoint not present ===' 147e6c79647SMax Reitz 148e6c79647SMax Reitzrmdir "$EXT_MP" 2>/dev/null 149e6c79647SMax Reitzrm -f "$EXT_MP" 150e6c79647SMax Reitzoutput=$(fuse_export_add 'export-err' "'mountpoint': '$EXT_MP'" error) 151e6c79647SMax Reitz 152ea29331bSMarkus Armbrusterif echo "$output" | grep -q "Parameter 'type' does not accept value 'fuse'"; then 153e6c79647SMax Reitz _notrun 'No FUSE support' 154e6c79647SMax Reitzfi 155e6c79647SMax Reitz 156e6c79647SMax Reitzecho "$output" 157e6c79647SMax Reitz 158e6c79647SMax Reitzecho 159e6c79647SMax Reitzecho '=== Mountpoint is a directory ===' 160e6c79647SMax Reitz 161e6c79647SMax Reitzmkdir "$EXT_MP" 162e6c79647SMax Reitzfuse_export_add 'export-err' "'mountpoint': '$EXT_MP'" error 163e6c79647SMax Reitzrmdir "$EXT_MP" 164e6c79647SMax Reitz 165e6c79647SMax Reitzecho 166e6c79647SMax Reitzecho '=== Mountpoint is a regular file ===' 167e6c79647SMax Reitz 168e6c79647SMax Reitztouch "$EXT_MP" 169e6c79647SMax Reitzfuse_export_add 'export-mp' "'mountpoint': '$EXT_MP'" 170e6c79647SMax Reitz 171e6c79647SMax Reitz# Check that the export presents the same data as the original image 172e6c79647SMax Reitz$QEMU_IMG compare -f raw -F $IMGFMT -U "$EXT_MP" "$TEST_IMG" 173e6c79647SMax Reitz 174f29add26SMax Reitz# Some quick chmod tests 175f29add26SMax Reitzstat -c 'Permissions pre-chmod: %a' "$EXT_MP" 176f29add26SMax Reitz 177f29add26SMax Reitz# Verify that we cannot set +w 178f29add26SMax Reitzchmod u+w "$EXT_MP" 2>&1 | _filter_testdir | _filter_imgfmt 179f29add26SMax Reitzstat -c 'Permissions post-+w: %a' "$EXT_MP" 180f29add26SMax Reitz 181f29add26SMax Reitz# But that we can set, say, +x (if we are so inclined) 182f29add26SMax Reitzchmod u+x "$EXT_MP" 2>&1 | _filter_testdir | _filter_imgfmt 183f29add26SMax Reitzstat -c 'Permissions post-+x: %a' "$EXT_MP" 184f29add26SMax Reitz 185e6c79647SMax Reitzecho 186e6c79647SMax Reitzecho '=== Mount over existing file ===' 187e6c79647SMax Reitz 188e6c79647SMax Reitz# This is the coolest feature of FUSE exports: You can transparently 189e6c79647SMax Reitz# make images in any format appear as raw images 190e6c79647SMax Reitzfuse_export_add 'export-img' "'mountpoint': '$TEST_IMG'" 191e6c79647SMax Reitz 192e6c79647SMax Reitz# Accesses both exports at the same time, so we get a concurrency test 193e6c79647SMax Reitz$QEMU_IMG compare -f raw -F raw -U "$EXT_MP" "$TEST_IMG" 194e6c79647SMax Reitz 195e6c79647SMax Reitz# Just to be sure, we later want to compare the data offline. Also, 196e6c79647SMax Reitz# this allows us to see that cp works without complaining. 197e6c79647SMax Reitz# (This is not a given, because cp will expect a short read at EOF. 198e6c79647SMax Reitz# Internally, qemu does not allow short reads, so we have to check 199e6c79647SMax Reitz# whether the FUSE export driver lets them work.) 200e6c79647SMax Reitzcp "$TEST_IMG" "$COPIED_IMG" 201e6c79647SMax Reitz 202e6c79647SMax Reitz# $TEST_IMG will be in mode 0400 because it is read-only; we are going 203e6c79647SMax Reitz# to write to the copy, so make it writable 204e6c79647SMax Reitzchmod 0600 "$COPIED_IMG" 205e6c79647SMax Reitz 206e6c79647SMax Reitzecho 207e6c79647SMax Reitzecho '=== Double export ===' 208e6c79647SMax Reitz 209e6c79647SMax Reitz# We have already seen that exporting a node twice works fine, but you 210e6c79647SMax Reitz# cannot export anything twice on the same mount point. The reason is 211e6c79647SMax Reitz# that qemu has to stat the given mount point, and this would have to 212e6c79647SMax Reitz# be answered by the same qemu instance if it already has an export 213e6c79647SMax Reitz# there. However, it cannot answer the stat because it is itself 214e6c79647SMax Reitz# caught up in that same stat. 215e6c79647SMax Reitzfuse_export_add 'export-err' "'mountpoint': '$EXT_MP'" error 216e6c79647SMax Reitz 217e6c79647SMax Reitzecho 218e6c79647SMax Reitzecho '=== Remove export ===' 219e6c79647SMax Reitz 220e6c79647SMax Reitz# Double-check that $EXT_MP appears as a non-empty file (the raw image) 22174163addSHanna Reitz$QEMU_IMG info -f raw "$EXT_MP" | grep 'virtual size' | head -n 1 222e6c79647SMax Reitz 223e6c79647SMax Reitzfuse_export_del 'export-mp' 224e6c79647SMax Reitz 225e6c79647SMax Reitz# See that the file appears empty again 22674163addSHanna Reitz$QEMU_IMG info -f raw "$EXT_MP" | grep 'virtual size' | head -n 1 227e6c79647SMax Reitz 228e6c79647SMax Reitzecho 229e6c79647SMax Reitzecho '=== Writable export ===' 230e6c79647SMax Reitz 231e6c79647SMax Reitzfuse_export_add 'export-mp' "'mountpoint': '$EXT_MP', 'writable': true" 232e6c79647SMax Reitz 233e6c79647SMax Reitz# Check that writing to the read-only export fails 234e2eec281SHanna Reitzoutput=$($QEMU_IO -f raw -c 'write -P 42 1M 64k' "$TEST_IMG" 2>&1 \ 235e2eec281SHanna Reitz | _filter_qemu_io | _filter_testdir | _filter_imgfmt) 236e2eec281SHanna Reitz 237e2eec281SHanna Reitz# Expected reference output: Opening the file fails because it has no 238e2eec281SHanna Reitz# write permission 239e2eec281SHanna Reitzreference="Could not open 'TEST_DIR/t.IMGFMT': Permission denied" 240e2eec281SHanna Reitz 241e2eec281SHanna Reitzif echo "$output" | grep -q "$reference"; then 242e2eec281SHanna Reitz echo "Writing to read-only export failed: OK" 243e2eec281SHanna Reitzelif echo "$output" | grep -q "write failed: Permission denied"; then 244e2eec281SHanna Reitz # With CAP_DAC_OVERRIDE (e.g. when running this test as root), the export 245e2eec281SHanna Reitz # can be opened regardless of its file permissions, but writing will then 246e2eec281SHanna Reitz # fail. This is not the result for which we want to test, so count this as 247e2eec281SHanna Reitz # a SKIP. 248e2eec281SHanna Reitz _casenotrun "Opening RO export as R/W succeeded, perhaps because of" \ 249e2eec281SHanna Reitz "CAP_DAC_OVERRIDE" 250e2eec281SHanna Reitz 251e2eec281SHanna Reitz # Still, write this to the reference output to make the test pass 252e2eec281SHanna Reitz echo "Writing to read-only export failed: OK" 253e2eec281SHanna Reitzelse 254e2eec281SHanna Reitz echo "Writing to read-only export failed: ERROR" 255e2eec281SHanna Reitz echo "$output" 256e2eec281SHanna Reitzfi 257e6c79647SMax Reitz 258e6c79647SMax Reitz# But here it should work 259e6c79647SMax Reitz$QEMU_IO -f raw -c 'write -P 42 1M 64k' "$EXT_MP" | _filter_qemu_io 260e6c79647SMax Reitz 261e6c79647SMax Reitz# (Adjust the copy, too) 262e6c79647SMax Reitz$QEMU_IO -f raw -c 'write -P 42 1M 64k' "$COPIED_IMG" | _filter_qemu_io 263e6c79647SMax Reitz 264e6c79647SMax Reitzecho 265e6c79647SMax Reitzecho '=== Resizing exports ===' 266e6c79647SMax Reitz 267e6c79647SMax Reitz# Here, we need to export the protocol node -- the format layer may 268e6c79647SMax Reitz# not be growable, simply because the format does not support it. 269e6c79647SMax Reitz 270e6c79647SMax Reitz# Remove all exports and the format node first so permissions will not 271e6c79647SMax Reitz# get in the way 272e6c79647SMax Reitzfuse_export_del 'export-mp' 273e6c79647SMax Reitzfuse_export_del 'export-img' 274e6c79647SMax Reitz 275e6c79647SMax Reitz_send_qemu_cmd $QEMU_HANDLE \ 276e6c79647SMax Reitz "{'execute': 'blockdev-del', 277e6c79647SMax Reitz 'arguments': { 278e6c79647SMax Reitz 'node-name': 'node-format' 279e6c79647SMax Reitz } }" \ 280e6c79647SMax Reitz 'return' 281e6c79647SMax Reitz 282e6c79647SMax Reitz# Now export the protocol node 283e6c79647SMax Reitzfuse_export_add \ 284e6c79647SMax Reitz 'export-mp' \ 285e6c79647SMax Reitz "'mountpoint': '$EXT_MP', 'writable': true" \ 286e6c79647SMax Reitz 'return' \ 287e6c79647SMax Reitz 'node-protocol' 288e6c79647SMax Reitz 289e6c79647SMax Reitzecho 290e6c79647SMax Reitzecho '--- Try growing non-growable export ---' 291e6c79647SMax Reitz 292e6c79647SMax Reitz# Get the current size so we can write beyond the EOF 293e6c79647SMax Reitzorig_len=$(get_proto_len "$EXT_MP" "$TEST_IMG") 294d2b3e32bSEric Blakeorig_disk_usage=$(disk_usage "$TEST_IMG") 295e6c79647SMax Reitz 296e6c79647SMax Reitz# Should fail (exports are non-growable by default) 297e6c79647SMax Reitz# (Note that qemu-io can never write beyond the EOF, so we have to use 298e6c79647SMax Reitz# dd here) 299e6c79647SMax Reitzdd if=/dev/zero of="$EXT_MP" bs=1 count=64k seek=$orig_len 2>&1 \ 300e6c79647SMax Reitz | _filter_testdir | _filter_imgfmt 301e6c79647SMax Reitz 302e6c79647SMax Reitzecho 303e6c79647SMax Reitzecho '--- Resize export ---' 304e6c79647SMax Reitz 305e6c79647SMax Reitz# But we can truncate it explicitly; even with fallocate 306e6c79647SMax Reitzfallocate -o "$orig_len" -l 64k "$EXT_MP" 307e6c79647SMax Reitz 308e6c79647SMax Reitznew_len=$(get_proto_len "$EXT_MP" "$TEST_IMG") 309e6c79647SMax Reitzif [ "$new_len" != "$((orig_len + 65536))" ]; then 310e6c79647SMax Reitz echo 'ERROR: Unexpected post-truncate image size:' 311e6c79647SMax Reitz echo "$new_len != $((orig_len + 65536))" 312e6c79647SMax Reitzelse 313e6c79647SMax Reitz echo 'OK: Post-truncate image size is as expected' 314e6c79647SMax Reitzfi 315e6c79647SMax Reitz 316d2b3e32bSEric Blakenew_disk_usage=$(disk_usage "$TEST_IMG") 317e6c79647SMax Reitzif [ "$new_disk_usage" -gt "$orig_disk_usage" ]; then 318e6c79647SMax Reitz echo 'OK: Disk usage grew with fallocate' 319e6c79647SMax Reitzelse 320e6c79647SMax Reitz echo 'ERROR: Disk usage did not grow despite fallocate:' 321e6c79647SMax Reitz echo "$orig_disk_usage => $new_disk_usage" 322e6c79647SMax Reitzfi 323e6c79647SMax Reitz 324e6c79647SMax Reitzecho 325e6c79647SMax Reitzecho '--- Try growing growable export ---' 326e6c79647SMax Reitz 327e6c79647SMax Reitz# Now export as growable 328e6c79647SMax Reitzfuse_export_del 'export-mp' 329e6c79647SMax Reitzfuse_export_add \ 330e6c79647SMax Reitz 'export-mp' \ 331e6c79647SMax Reitz "'mountpoint': '$EXT_MP', 'writable': true, 'growable': true" \ 332e6c79647SMax Reitz 'return' \ 333e6c79647SMax Reitz 'node-protocol' 334e6c79647SMax Reitz 335e6c79647SMax Reitz# Now we should be able to write beyond the EOF 336e6c79647SMax Reitzdd if=/dev/zero of="$EXT_MP" bs=1 count=64k seek=$new_len 2>&1 \ 337e6c79647SMax Reitz | _filter_testdir | _filter_imgfmt 338e6c79647SMax Reitz 339e6c79647SMax Reitznew_len=$(get_proto_len "$EXT_MP" "$TEST_IMG") 340e6c79647SMax Reitzif [ "$new_len" != "$((orig_len + 131072))" ]; then 341e6c79647SMax Reitz echo 'ERROR: Unexpected post-grow image size:' 342e6c79647SMax Reitz echo "$new_len != $((orig_len + 131072))" 343e6c79647SMax Reitzelse 344e6c79647SMax Reitz echo 'OK: Post-grow image size is as expected' 345e6c79647SMax Reitzfi 346e6c79647SMax Reitz 347e6c79647SMax Reitzecho 348e6c79647SMax Reitzecho '--- Shrink export ---' 349e6c79647SMax Reitz 350e6c79647SMax Reitz# Now go back to the original size 351e6c79647SMax Reitztruncate -s "$orig_len" "$EXT_MP" 352e6c79647SMax Reitz 353e6c79647SMax Reitznew_len=$(get_proto_len "$EXT_MP" "$TEST_IMG") 354e6c79647SMax Reitzif [ "$new_len" != "$orig_len" ]; then 355e6c79647SMax Reitz echo 'ERROR: Unexpected post-truncate image size:' 356e6c79647SMax Reitz echo "$new_len != $orig_len" 357e6c79647SMax Reitzelse 358e6c79647SMax Reitz echo 'OK: Post-truncate image size is as expected' 359e6c79647SMax Reitzfi 360e6c79647SMax Reitz 361e6c79647SMax Reitzecho 362e6c79647SMax Reitzecho '=== Tear down ===' 363e6c79647SMax Reitz 364e6c79647SMax Reitz_send_qemu_cmd $QEMU_HANDLE \ 365e6c79647SMax Reitz "{'execute': 'quit'}" \ 366e6c79647SMax Reitz 'return' 367e6c79647SMax Reitz 368e6c79647SMax Reitzwait=yes _cleanup_qemu 369e6c79647SMax Reitz 370e6c79647SMax Reitzecho 371e6c79647SMax Reitzecho '=== Compare copy with original ===' 372e6c79647SMax Reitz 373e6c79647SMax Reitz$QEMU_IMG compare -f raw -F $IMGFMT "$COPIED_IMG" "$TEST_IMG" 37427e0d8b5SHanna Czenczek_cleanup_test_img 37527e0d8b5SHanna Czenczek 37627e0d8b5SHanna Czenczekecho 37727e0d8b5SHanna Czenczekecho '=== Writing zeroes while unmapping ===' 37827e0d8b5SHanna Czenczek# Regression test for https://gitlab.com/qemu-project/qemu/-/issues/1507 37927e0d8b5SHanna Czenczek_make_test_img 64M 38027e0d8b5SHanna Czenczek$QEMU_IO -c 'write -s /dev/urandom 0 64M' "$TEST_IMG" | _filter_qemu_io 38127e0d8b5SHanna Czenczek 38227e0d8b5SHanna Czenczek_launch_qemu 38327e0d8b5SHanna Czenczek_send_qemu_cmd $QEMU_HANDLE \ 38427e0d8b5SHanna Czenczek "{'execute': 'qmp_capabilities'}" \ 38527e0d8b5SHanna Czenczek 'return' 38627e0d8b5SHanna Czenczek 38727e0d8b5SHanna Czenczek_send_qemu_cmd $QEMU_HANDLE \ 38827e0d8b5SHanna Czenczek "{'execute': 'blockdev-add', 38927e0d8b5SHanna Czenczek 'arguments': { 39027e0d8b5SHanna Czenczek 'driver': '$IMGFMT', 39127e0d8b5SHanna Czenczek 'node-name': 'node-format', 39227e0d8b5SHanna Czenczek 'file': { 39327e0d8b5SHanna Czenczek 'driver': 'file', 39427e0d8b5SHanna Czenczek 'filename': '$TEST_IMG' 39527e0d8b5SHanna Czenczek } 39627e0d8b5SHanna Czenczek } }" \ 39727e0d8b5SHanna Czenczek 'return' 39827e0d8b5SHanna Czenczek 39927e0d8b5SHanna Czenczekfuse_export_add 'export' "'mountpoint': '$EXT_MP', 'writable': true" 40027e0d8b5SHanna Czenczek 40127e0d8b5SHanna Czenczek# Try writing zeroes by unmapping 40227e0d8b5SHanna Czenczek$QEMU_IO -f raw -c 'write -zu 0 64M' "$EXT_MP" | _filter_qemu_io 40327e0d8b5SHanna Czenczek 40427e0d8b5SHanna Czenczek# Check the result 40527e0d8b5SHanna Czenczek$QEMU_IO -f raw -c 'read -P 0 0 64M' "$EXT_MP" | _filter_qemu_io 40627e0d8b5SHanna Czenczek 40727e0d8b5SHanna Czenczek_send_qemu_cmd $QEMU_HANDLE \ 40827e0d8b5SHanna Czenczek "{'execute': 'quit'}" \ 40927e0d8b5SHanna Czenczek 'return' 41027e0d8b5SHanna Czenczek 41127e0d8b5SHanna Czenczekwait=yes _cleanup_qemu 41227e0d8b5SHanna Czenczek 41327e0d8b5SHanna Czenczek# Check the original image 41427e0d8b5SHanna Czenczek$QEMU_IO -c 'read -P 0 0 64M' "$TEST_IMG" | _filter_qemu_io 41527e0d8b5SHanna Czenczek 41627e0d8b5SHanna Czenczek_cleanup_test_img 417e6c79647SMax Reitz 418e6c79647SMax Reitz# success, all done 419e6c79647SMax Reitzecho "*** done" 420e6c79647SMax Reitzrm -f $seq.full 421e6c79647SMax Reitzstatus=0 422