1#!/usr/bin/env bash
2# group: rw quick
3#
4# Test case for internal snapshots in qcow2
5#
6# Copyright (C) 2023 Red Hat, Inc.
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
22# creator
23owner=kwolf@redhat.com
24
25seq="$(basename $0)"
26echo "QA output created by $seq"
27
28status=1	# failure is the default!
29
30_cleanup()
31{
32	_cleanup_test_img
33}
34trap "_cleanup; exit \$status" 0 1 2 3 15
35
36# get standard environment, filters and checks
37. ../common.rc
38. ../common.filter
39
40# This tests qcow2-specific low-level functionality
41_supported_fmt qcow2
42_supported_proto generic
43# Internal snapshots are (currently) impossible with refcount_bits=1,
44# and generally impossible with external data files
45_unsupported_imgopts 'compat=0.10' 'refcount_bits=1[^0-9]' data_file
46
47IMG_SIZE=64M
48
49_qemu()
50{
51    $QEMU -no-shutdown -nographic -monitor stdio -serial none \
52          -blockdev file,filename="$TEST_IMG",node-name=disk0-file \
53          -blockdev "$IMGFMT",file=disk0-file,node-name=disk0 \
54          -object iothread,id=iothread0 \
55          -device virtio-scsi,iothread=iothread0 \
56          -device scsi-hd,drive=disk0,share-rw=on \
57          "$@" 2>&1 |\
58    _filter_qemu | _filter_hmp | _filter_qemu_io
59}
60
61_make_test_img $IMG_SIZE
62
63echo
64echo "=== Write some data, take a snapshot and overwrite part of it ==="
65echo
66
67{
68    echo 'qemu-io disk0 "write -P0x11 0 1M"'
69    # Give qemu some time to boot before saving the VM state
70    sleep 0.5
71    echo "savevm snap0"
72    echo 'qemu-io disk0 "write -P0x22 0 512k"'
73    echo "quit"
74} | _qemu
75
76echo
77$QEMU_IMG snapshot -l "$TEST_IMG" | _filter_date | _filter_vmstate_size
78_check_test_img
79
80echo
81echo "=== Verify that loading the snapshot reverts to the old content ==="
82echo
83
84{
85    # -loadvm reverted the write from the previous QEMU instance
86    echo 'qemu-io disk0 "read -P0x11 0 1M"'
87
88    # Verify that it works without restarting QEMU, too
89    echo 'qemu-io disk0 "write -P0x33 512k 512k"'
90    echo "loadvm snap0"
91    echo 'qemu-io disk0 "read -P0x11 0 1M"'
92
93    # Verify COW by writing a partial cluster
94    echo 'qemu-io disk0 "write -P0x33 63k 2k"'
95    echo 'qemu-io disk0 "read -P0x11 0 63k"'
96    echo 'qemu-io disk0 "read -P0x33 63k 2k"'
97    echo 'qemu-io disk0 "read -P0x11 65k 63k"'
98
99    # Take a second snapshot
100    echo "savevm snap1"
101
102    echo "quit"
103} | _qemu -loadvm snap0
104
105echo
106$QEMU_IMG snapshot -l "$TEST_IMG" | _filter_date | _filter_vmstate_size
107_check_test_img
108
109echo
110echo "=== qemu-img snapshot can revert to snapshots ==="
111echo
112
113$QEMU_IMG snapshot -a snap0 "$TEST_IMG"
114$QEMU_IO -c "read -P0x11 0 1M" "$TEST_IMG" | _filter_qemu_io
115$QEMU_IMG snapshot -a snap1 "$TEST_IMG"
116$QEMU_IO \
117    -c "read -P0x11 0 63k" \
118    -c "read -P0x33 63k 2k" \
119    -c "read -P0x11 65k 63k" \
120    "$TEST_IMG" | _filter_qemu_io
121
122echo
123echo "=== Deleting snapshots ==="
124echo
125{
126    # The active layer stays unaffected by deleting the snapshot
127    echo "delvm snap1"
128    echo 'qemu-io disk0 "read -P0x11 0 63k"'
129    echo 'qemu-io disk0 "read -P0x33 63k 2k"'
130    echo 'qemu-io disk0 "read -P0x11 65k 63k"'
131
132    echo "quit"
133} | _qemu
134
135
136echo
137$QEMU_IMG snapshot -l "$TEST_IMG" | _filter_date | _filter_vmstate_size
138_check_test_img
139
140echo
141echo "=== Error cases ==="
142echo
143
144# snap1 should not exist any more
145_qemu -loadvm snap1
146
147echo
148{
149    echo "loadvm snap1"
150    echo "quit"
151} | _qemu
152
153# Snapshot operations and inactive images are incompatible
154echo
155_qemu -loadvm snap0 -incoming defer
156{
157    echo "loadvm snap0"
158    echo "delvm snap0"
159    echo "savevm snap1"
160    echo "quit"
161} | _qemu -incoming defer
162
163# -loadvm and -preconfig are incompatible
164echo
165_qemu -loadvm snap0 -preconfig
166
167# success, all done
168echo "*** done"
169rm -f $seq.full
170status=0
171