summaryrefslogtreecommitdiff
path: root/tests/qemu-iotests
diff options
context:
space:
mode:
Diffstat (limited to 'tests/qemu-iotests')
-rw-r--r--tests/qemu-iotests/017.out2
-rw-r--r--tests/qemu-iotests/018.out2
-rw-r--r--tests/qemu-iotests/019.out2
-rw-r--r--tests/qemu-iotests/020.out2
-rw-r--r--tests/qemu-iotests/024.out2
-rw-r--r--tests/qemu-iotests/028.out4
-rwxr-xr-xtests/qemu-iotests/0305
-rw-r--r--tests/qemu-iotests/034.out2
-rw-r--r--tests/qemu-iotests/037.out2
-rw-r--r--tests/qemu-iotests/038.out2
-rwxr-xr-xtests/qemu-iotests/03946
-rw-r--r--tests/qemu-iotests/039.out46
-rwxr-xr-xtests/qemu-iotests/04030
-rw-r--r--tests/qemu-iotests/040.out4
-rwxr-xr-xtests/qemu-iotests/04124
-rw-r--r--tests/qemu-iotests/043.out12
-rw-r--r--tests/qemu-iotests/046.out2
-rw-r--r--tests/qemu-iotests/049.out33
-rw-r--r--tests/qemu-iotests/050.out2
-rwxr-xr-xtests/qemu-iotests/0513
-rw-r--r--tests/qemu-iotests/051.out4
-rwxr-xr-xtests/qemu-iotests/05519
-rwxr-xr-xtests/qemu-iotests/05625
-rw-r--r--tests/qemu-iotests/056.out4
-rwxr-xr-xtests/qemu-iotests/05812
-rw-r--r--tests/qemu-iotests/059.out12
-rwxr-xr-xtests/qemu-iotests/0616
-rw-r--r--tests/qemu-iotests/061.out20
-rwxr-xr-xtests/qemu-iotests/06711
-rw-r--r--tests/qemu-iotests/067.out271
-rw-r--r--tests/qemu-iotests/069.out2
-rwxr-xr-xtests/qemu-iotests/07154
-rw-r--r--tests/qemu-iotests/071.out16
-rw-r--r--tests/qemu-iotests/073.out2
-rw-r--r--tests/qemu-iotests/079.out18
-rwxr-xr-xtests/qemu-iotests/08121
-rw-r--r--tests/qemu-iotests/081.out7
-rw-r--r--tests/qemu-iotests/082.out4
-rwxr-xr-xtests/qemu-iotests/085120
-rw-r--r--tests/qemu-iotests/085.out72
-rwxr-xr-xtests/qemu-iotests/0872
-rw-r--r--tests/qemu-iotests/087.out16
-rw-r--r--tests/qemu-iotests/095.out4
-rw-r--r--tests/qemu-iotests/09669
-rw-r--r--tests/qemu-iotests/096.out5
-rw-r--r--tests/qemu-iotests/097.out16
-rw-r--r--tests/qemu-iotests/098.out8
-rw-r--r--tests/qemu-iotests/110.out4
-rw-r--r--tests/qemu-iotests/112.out4
-rw-r--r--tests/qemu-iotests/114.out2
-rw-r--r--tests/qemu-iotests/115.out2
-rwxr-xr-xtests/qemu-iotests/118720
-rw-r--r--tests/qemu-iotests/118.out5
-rwxr-xr-xtests/qemu-iotests/1192
-rwxr-xr-xtests/qemu-iotests/1202
-rw-r--r--tests/qemu-iotests/121.out4
-rw-r--r--tests/qemu-iotests/122.out6
-rw-r--r--tests/qemu-iotests/124182
-rw-r--r--tests/qemu-iotests/124.out4
-rwxr-xr-xtests/qemu-iotests/1289
-rwxr-xr-xtests/qemu-iotests/1308
-rw-r--r--tests/qemu-iotests/130.out8
-rw-r--r--tests/qemu-iotests/136349
-rw-r--r--tests/qemu-iotests/136.out5
-rwxr-xr-xtests/qemu-iotests/137145
-rw-r--r--tests/qemu-iotests/137.out46
-rwxr-xr-xtests/qemu-iotests/13873
-rw-r--r--tests/qemu-iotests/138.out9
-rw-r--r--tests/qemu-iotests/139416
-rw-r--r--tests/qemu-iotests/139.out5
-rwxr-xr-xtests/qemu-iotests/144114
-rw-r--r--tests/qemu-iotests/144.out24
-rwxr-xr-xtests/qemu-iotests/check13
-rw-r--r--tests/qemu-iotests/common10
-rw-r--r--tests/qemu-iotests/common.config64
-rw-r--r--tests/qemu-iotests/common.filter7
-rw-r--r--tests/qemu-iotests/common.qemu20
-rw-r--r--tests/qemu-iotests/common.rc30
-rw-r--r--tests/qemu-iotests/group7
-rw-r--r--tests/qemu-iotests/iotests.py57
80 files changed, 2877 insertions, 526 deletions
diff --git a/tests/qemu-iotests/017.out b/tests/qemu-iotests/017.out
index 7c409fc5b..8fc924194 100644
--- a/tests/qemu-iotests/017.out
+++ b/tests/qemu-iotests/017.out
@@ -269,7 +269,7 @@ wrote 65536/65536 bytes at offset 4295032832
No errors were found on the image.
Creating test image with backing file
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file='TEST_DIR/t.IMGFMT.base'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file=TEST_DIR/t.IMGFMT.base
Filling test image
=== IO: pattern 1
diff --git a/tests/qemu-iotests/018.out b/tests/qemu-iotests/018.out
index 39a6011d2..d66bd6343 100644
--- a/tests/qemu-iotests/018.out
+++ b/tests/qemu-iotests/018.out
@@ -269,7 +269,7 @@ wrote 65536/65536 bytes at offset 4295032832
No errors were found on the image.
Creating test image with backing file
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file='TEST_DIR/t.IMGFMT.base'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file=TEST_DIR/t.IMGFMT.base
Filling test image
=== IO: pattern 1
diff --git a/tests/qemu-iotests/019.out b/tests/qemu-iotests/019.out
index 4695b972d..615450a53 100644
--- a/tests/qemu-iotests/019.out
+++ b/tests/qemu-iotests/019.out
@@ -269,7 +269,7 @@ wrote 65536/65536 bytes at offset 4296015872
No errors were found on the image.
Creating test image with backing file
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file='TEST_DIR/t.IMGFMT.base'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file=TEST_DIR/t.IMGFMT.base
Filling test image
=== IO: pattern 43
diff --git a/tests/qemu-iotests/020.out b/tests/qemu-iotests/020.out
index 71aab1c74..134aa293e 100644
--- a/tests/qemu-iotests/020.out
+++ b/tests/qemu-iotests/020.out
@@ -269,7 +269,7 @@ wrote 65536/65536 bytes at offset 4295032832
No errors were found on the image.
Creating test image with backing file
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file='TEST_DIR/t.IMGFMT.base'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file=TEST_DIR/t.IMGFMT.base
Filling test image
=== IO: pattern 1
diff --git a/tests/qemu-iotests/024.out b/tests/qemu-iotests/024.out
index 521d46942..9b9ef3a34 100644
--- a/tests/qemu-iotests/024.out
+++ b/tests/qemu-iotests/024.out
@@ -33,7 +33,7 @@ wrote 131072/131072 bytes at offset 786432
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
Creating COW image
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 backing_file='TEST_DIR/t.IMGFMT.base_old'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 backing_file=TEST_DIR/t.IMGFMT.base_old
=== IO: pattern 0x33
wrote 262144/262144 bytes at offset 0
256 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
diff --git a/tests/qemu-iotests/028.out b/tests/qemu-iotests/028.out
index 5db167ce7..29c9972e2 100644
--- a/tests/qemu-iotests/028.out
+++ b/tests/qemu-iotests/028.out
@@ -70,7 +70,7 @@ wrote 512/512 bytes at offset 3221225984
No errors were found on the image.
Creating test image with backing file
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294968832 backing_file='TEST_DIR/t.IMGFMT.base'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294968832 backing_file=TEST_DIR/t.IMGFMT.base
Filling test image
=== IO: pattern 196
@@ -468,7 +468,7 @@ No errors were found on the image.
block-backup
-Formatting 'TEST_DIR/t.IMGFMT.copy', fmt=IMGFMT size=4294968832 backing_file='TEST_DIR/t.IMGFMT.base' backing_fmt='IMGFMT'
+Formatting 'TEST_DIR/t.IMGFMT.copy', fmt=IMGFMT size=4294968832 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT
(qemu)
(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block-info block-jinfo block-joinfo block-jobinfo block-jobs
Type backup, device disk: Completed 0 of 4294968832 bytes, speed limit 0 bytes/s
diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030
index 952a524ec..32469efd7 100755
--- a/tests/qemu-iotests/030
+++ b/tests/qemu-iotests/030
@@ -245,6 +245,7 @@ class TestEIO(TestErrors):
while not completed:
for event in self.vm.get_qmp_events(wait=True):
if event['event'] == 'BLOCK_JOB_ERROR':
+ error = True
self.assert_qmp(event, 'data/device', 'drive0')
self.assert_qmp(event, 'data/operation', 'read')
@@ -257,9 +258,11 @@ class TestEIO(TestErrors):
self.assert_qmp(result, 'return', {})
result = self.vm.qmp('query-block-jobs')
+ if result == {'return': []}:
+ # Race; likely already finished. Check.
+ continue
self.assert_qmp(result, 'return[0]/paused', False)
self.assert_qmp(result, 'return[0]/io-status', 'ok')
- error = True
elif event['event'] == 'BLOCK_JOB_COMPLETED':
self.assertTrue(error, 'job completed unexpectedly')
self.assert_qmp(event, 'data/type', 'stream')
diff --git a/tests/qemu-iotests/034.out b/tests/qemu-iotests/034.out
index d12daf206..34fda80c8 100644
--- a/tests/qemu-iotests/034.out
+++ b/tests/qemu-iotests/034.out
@@ -4,7 +4,7 @@ QA output created by 034
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
wrote 1048576/1048576 bytes at offset 0
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file='TEST_DIR/t.IMGFMT.base'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file=TEST_DIR/t.IMGFMT.base
== zero write with backing file ==
wrote 196608/196608 bytes at offset 65536
diff --git a/tests/qemu-iotests/037.out b/tests/qemu-iotests/037.out
index dc40a021a..55b30fdc6 100644
--- a/tests/qemu-iotests/037.out
+++ b/tests/qemu-iotests/037.out
@@ -514,7 +514,7 @@ wrote 512/512 bytes at offset 130048
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 512/512 bytes at offset 130560
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file='TEST_DIR/t.IMGFMT.base'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file=TEST_DIR/t.IMGFMT.base
== COW in a single cluster ==
wrote 2048/2048 bytes at offset 0
diff --git a/tests/qemu-iotests/038.out b/tests/qemu-iotests/038.out
index e1a7e9441..ecb656e08 100644
--- a/tests/qemu-iotests/038.out
+++ b/tests/qemu-iotests/038.out
@@ -514,7 +514,7 @@ wrote 65536/65536 bytes at offset 16646144
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 65536/65536 bytes at offset 16711680
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file='TEST_DIR/t.IMGFMT.base'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file=TEST_DIR/t.IMGFMT.base
== Some concurrent requests touching the same cluster ==
wrote 65536/65536 bytes at offset XXX
diff --git a/tests/qemu-iotests/039 b/tests/qemu-iotests/039
index 859705f84..9e9b379ba 100755
--- a/tests/qemu-iotests/039
+++ b/tests/qemu-iotests/039
@@ -47,13 +47,6 @@ _supported_os Linux
_default_cache_mode "writethrough"
_supported_cache_modes "writethrough"
-_subshell_exec()
-{
- # Executing crashing commands in a subshell prevents information like the
- # "Killed" line from being lost
- (exec "$@")
-}
-
size=128M
echo
@@ -74,8 +67,8 @@ echo "== Creating a dirty image file =="
IMGOPTS="compat=1.1,lazy_refcounts=on"
_make_test_img $size
-_subshell_exec $QEMU_IO -c "write -P 0x5a 0 512" \
- -c "sigraise $(kill -l KILL)" "$TEST_IMG" 2>&1 \
+$QEMU_IO -c "write -P 0x5a 0 512" \
+ -c "sigraise $(kill -l KILL)" "$TEST_IMG" 2>&1 \
| _filter_qemu_io
# The dirty bit must be set
@@ -109,8 +102,8 @@ echo "== Opening a dirty image read/write should repair it =="
IMGOPTS="compat=1.1,lazy_refcounts=on"
_make_test_img $size
-_subshell_exec $QEMU_IO -c "write -P 0x5a 0 512" \
- -c "sigraise $(kill -l KILL)" "$TEST_IMG" 2>&1 \
+$QEMU_IO -c "write -P 0x5a 0 512" \
+ -c "sigraise $(kill -l KILL)" "$TEST_IMG" 2>&1 \
| _filter_qemu_io
# The dirty bit must be set
@@ -127,8 +120,8 @@ echo "== Creating an image file with lazy_refcounts=off =="
IMGOPTS="compat=1.1,lazy_refcounts=off"
_make_test_img $size
-_subshell_exec $QEMU_IO -c "write -P 0x5a 0 512" \
- -c "sigraise $(kill -l KILL)" "$TEST_IMG" 2>&1 \
+$QEMU_IO -c "write -P 0x5a 0 512" \
+ -c "sigraise $(kill -l KILL)" "$TEST_IMG" 2>&1 \
| _filter_qemu_io
# The dirty bit must not be set since lazy_refcounts=off
@@ -154,6 +147,33 @@ $PYTHON qcow2.py "$TEST_IMG".base dump-header | grep incompatible_features
_check_test_img
TEST_IMG="$TEST_IMG".base _check_test_img
+echo
+echo "== Changing lazy_refcounts setting at runtime =="
+
+IMGOPTS="compat=1.1,lazy_refcounts=off"
+_make_test_img $size
+
+$QEMU_IO -c "reopen -o lazy-refcounts=on" \
+ -c "write -P 0x5a 0 512" \
+ -c "sigraise $(kill -l KILL)" "$TEST_IMG" 2>&1 \
+ | _filter_qemu_io
+
+# The dirty bit must be set
+$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
+_check_test_img
+
+IMGOPTS="compat=1.1,lazy_refcounts=on"
+_make_test_img $size
+
+$QEMU_IO -c "reopen -o lazy-refcounts=off" \
+ -c "write -P 0x5a 0 512" \
+ -c "sigraise $(kill -l KILL)" "$TEST_IMG" 2>&1 \
+ | _filter_qemu_io
+
+# The dirty bit must not be set
+$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
+_check_test_img
+
# success, all done
echo "*** done"
diff --git a/tests/qemu-iotests/039.out b/tests/qemu-iotests/039.out
index d09751f9c..32c884694 100644
--- a/tests/qemu-iotests/039.out
+++ b/tests/qemu-iotests/039.out
@@ -11,7 +11,11 @@ No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-./039: Killed ( exec "$@" )
+./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
+ exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@";
+else
+ exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@";
+fi )
incompatible_features 0x1
ERROR cluster 5 refcount=0 reference=1
ERROR OFLAG_COPIED data cluster: l2_entry=8000000000050000 refcount=0
@@ -46,7 +50,11 @@ read 512/512 bytes at offset 0
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-./039: Killed ( exec "$@" )
+./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
+ exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@";
+else
+ exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@";
+fi )
incompatible_features 0x1
ERROR cluster 5 refcount=0 reference=1
Rebuilding refcount structure
@@ -60,13 +68,17 @@ incompatible_features 0x0
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-./039: Killed ( exec "$@" )
+./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
+ exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@";
+else
+ exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@";
+fi )
incompatible_features 0x0
No errors were found on the image.
== Committing to a backing file with lazy_refcounts=on ==
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file='TEST_DIR/t.IMGFMT.base'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base
wrote 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
Image committed.
@@ -74,4 +86,30 @@ incompatible_features 0x0
incompatible_features 0x0
No errors were found on the image.
No errors were found on the image.
+
+== Changing lazy_refcounts setting at runtime ==
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
+wrote 512/512 bytes at offset 0
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
+ exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@";
+else
+ exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@";
+fi )
+incompatible_features 0x1
+ERROR cluster 5 refcount=0 reference=1
+ERROR OFLAG_COPIED data cluster: l2_entry=8000000000050000 refcount=0
+
+2 errors were found on the image.
+Data may be corrupted, or further writes to the image may corrupt it.
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
+wrote 512/512 bytes at offset 0
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
+ exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@";
+else
+ exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@";
+fi )
+incompatible_features 0x0
+No errors were found on the image.
*** done
diff --git a/tests/qemu-iotests/040 b/tests/qemu-iotests/040
index ea2f98e51..5bdaf3d48 100755
--- a/tests/qemu-iotests/040
+++ b/tests/qemu-iotests/040
@@ -41,6 +41,7 @@ class ImageCommitTestCase(iotests.QMPTestCase):
while not completed:
for event in self.vm.get_qmp_events(wait=True):
if event['event'] == 'BLOCK_JOB_COMPLETED':
+ self.assert_qmp_absent(event, 'data/error')
self.assert_qmp(event, 'data/type', 'commit')
self.assert_qmp(event, 'data/device', 'drive0')
self.assert_qmp(event, 'data/offset', event['data']['len'])
@@ -251,5 +252,34 @@ class TestSetSpeed(ImageCommitTestCase):
class TestActiveZeroLengthImage(TestSingleDrive):
image_len = 0
+class TestReopenOverlay(ImageCommitTestCase):
+ image_len = 1024 * 1024
+ img0 = os.path.join(iotests.test_dir, '0.img')
+ img1 = os.path.join(iotests.test_dir, '1.img')
+ img2 = os.path.join(iotests.test_dir, '2.img')
+ img3 = os.path.join(iotests.test_dir, '3.img')
+
+ def setUp(self):
+ iotests.create_image(self.img0, self.image_len)
+ qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % self.img0, self.img1)
+ qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % self.img1, self.img2)
+ qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % self.img2, self.img3)
+ qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0xab 0 128K', self.img1)
+ self.vm = iotests.VM().add_drive(self.img3)
+ self.vm.launch()
+
+ def tearDown(self):
+ self.vm.shutdown()
+ os.remove(self.img0)
+ os.remove(self.img1)
+ os.remove(self.img2)
+ os.remove(self.img3)
+
+ # This tests what happens when the overlay image of the 'top' node
+ # needs to be reopened in read-write mode in order to update the
+ # backing image string.
+ def test_reopen_overlay(self):
+ self.run_commit_test(self.img1, self.img0)
+
if __name__ == '__main__':
iotests.main(supported_fmts=['qcow2', 'qed'])
diff --git a/tests/qemu-iotests/040.out b/tests/qemu-iotests/040.out
index 42314e9c0..4fd1c2dcd 100644
--- a/tests/qemu-iotests/040.out
+++ b/tests/qemu-iotests/040.out
@@ -1,5 +1,5 @@
-........................
+.........................
----------------------------------------------------------------------
-Ran 24 tests
+Ran 25 tests
OK
diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041
index 3d46ed705..05b5962ce 100755
--- a/tests/qemu-iotests/041
+++ b/tests/qemu-iotests/041
@@ -42,6 +42,8 @@ class TestSingleDrive(iotests.QMPTestCase):
iotests.create_image(backing_img, self.image_len)
qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
self.vm = iotests.VM().add_drive(test_img)
+ if iotests.qemu_default_machine == 'pc':
+ self.vm.add_drive(None, 'media=cdrom', 'ide')
self.vm.launch()
def tearDown(self):
@@ -167,8 +169,11 @@ class TestSingleDrive(iotests.QMPTestCase):
'target image does not match source after mirroring')
def test_medium_not_found(self):
- result = self.vm.qmp('drive-mirror', device='ide1-cd0', sync='full',
- target=target_img)
+ if iotests.qemu_default_machine != 'pc':
+ return
+
+ result = self.vm.qmp('drive-mirror', device='drive1', # CD-ROM
+ sync='full', target=target_img)
self.assert_qmp(result, 'error/class', 'GenericError')
def test_image_not_found(self):
@@ -707,6 +712,9 @@ class TestRepairQuorum(iotests.QMPTestCase):
def setUp(self):
self.vm = iotests.VM()
+ if iotests.qemu_default_machine == 'pc':
+ self.vm.add_drive(None, 'media=cdrom', 'ide')
+
# Add each individual quorum images
for i in self.IMAGES:
qemu_img('create', '-f', iotests.imgfmt, i,
@@ -772,7 +780,7 @@ class TestRepairQuorum(iotests.QMPTestCase):
# here we check that the last registered quorum file has not been
# swapped out and unref
result = self.vm.qmp('query-named-block-nodes')
- self.assert_qmp(result, 'return[0]/file', quorum_img3)
+ self.assert_qmp(result, 'return[1]/file', quorum_img3)
self.vm.shutdown()
def test_cancel_after_ready(self):
@@ -791,7 +799,7 @@ class TestRepairQuorum(iotests.QMPTestCase):
result = self.vm.qmp('query-named-block-nodes')
# here we check that the last registered quorum file has not been
# swapped out and unref
- self.assert_qmp(result, 'return[0]/file', quorum_img3)
+ self.assert_qmp(result, 'return[1]/file', quorum_img3)
self.vm.shutdown()
self.assertTrue(iotests.compare_images(quorum_img2, quorum_repair_img),
'target image does not match source after mirroring')
@@ -831,7 +839,11 @@ class TestRepairQuorum(iotests.QMPTestCase):
if not self.has_quorum():
return
- result = self.vm.qmp('drive-mirror', device='ide1-cd0', sync='full',
+ if iotests.qemu_default_machine != 'pc':
+ return
+
+ result = self.vm.qmp('drive-mirror', device='drive0', # CD-ROM
+ sync='full',
node_name='repair0',
replaces='img1',
target=quorum_repair_img, format=iotests.imgfmt)
@@ -877,7 +889,7 @@ class TestRepairQuorum(iotests.QMPTestCase):
target=quorum_repair_img, format=iotests.imgfmt)
self.assert_qmp(result, 'error/class', 'GenericError')
- def test_unexistant_replaces(self):
+ def test_nonexistent_replaces(self):
if not self.has_quorum():
return
diff --git a/tests/qemu-iotests/043.out b/tests/qemu-iotests/043.out
index 012cc008e..33f8cc37d 100644
--- a/tests/qemu-iotests/043.out
+++ b/tests/qemu-iotests/043.out
@@ -4,20 +4,20 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
== backing file references self ==
qemu-img: Backing file 'TEST_DIR/t.IMGFMT' creates an infinite loop.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file='TEST_DIR/t.IMGFMT.base'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base
== parent references self ==
qemu-img: Backing file 'TEST_DIR/t.IMGFMT' creates an infinite loop.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file='TEST_DIR/t.IMGFMT.1.base'
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file='TEST_DIR/t.IMGFMT.2.base'
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file='TEST_DIR/t.IMGFMT.3.base'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.1.base
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.2.base
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.3.base
== ancestor references another ancestor ==
qemu-img: Backing file 'TEST_DIR/t.IMGFMT.2.base' creates an infinite loop.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file='TEST_DIR/t.IMGFMT.1.base'
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file='TEST_DIR/t.IMGFMT.2.base'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.1.base
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.2.base
== finite chain of length 3 (human) ==
image: TEST_DIR/t.IMGFMT
diff --git a/tests/qemu-iotests/046.out b/tests/qemu-iotests/046.out
index 9d18af53a..ca2c7404a 100644
--- a/tests/qemu-iotests/046.out
+++ b/tests/qemu-iotests/046.out
@@ -66,7 +66,7 @@ wrote 65536/65536 bytes at offset 1966080
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 65536/65536 bytes at offset 2031616
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file='TEST_DIR/t.IMGFMT.base'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file=TEST_DIR/t.IMGFMT.base
== Some concurrent requests touching the same cluster ==
blkdebug: Suspended request 'A'
diff --git a/tests/qemu-iotests/049.out b/tests/qemu-iotests/049.out
index 9f93666c5..a2b670395 100644
--- a/tests/qemu-iotests/049.out
+++ b/tests/qemu-iotests/049.out
@@ -95,17 +95,15 @@ qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- -1024
qemu-img: Image size must be less than 8 EiB!
qemu-img create -f qcow2 -o size=-1024 TEST_DIR/t.qcow2
-qemu-img: qcow2 doesn't support shrinking images yet
-qemu-img: TEST_DIR/t.qcow2: Could not resize image: Operation not supported
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=-1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+qemu-img: Parameter 'size' expects a non-negative number below 2^64
+qemu-img: TEST_DIR/t.qcow2: Invalid options for file format 'qcow2'
qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- -1k
qemu-img: Image size must be less than 8 EiB!
qemu-img create -f qcow2 -o size=-1k TEST_DIR/t.qcow2
-qemu-img: qcow2 doesn't support shrinking images yet
-qemu-img: TEST_DIR/t.qcow2: Could not resize image: Operation not supported
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=-1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+qemu-img: Parameter 'size' expects a non-negative number below 2^64
+qemu-img: TEST_DIR/t.qcow2: Invalid options for file format 'qcow2'
qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- 1kilobyte
qemu-img: Invalid image size specified! You may use k, M, G, T, P or E suffixes for
@@ -120,6 +118,7 @@ qemu-img: kilobytes, megabytes, gigabytes, terabytes, petabytes and exabytes.
qemu-img create -f qcow2 -o size=foobar TEST_DIR/t.qcow2
qemu-img: Parameter 'size' expects a size
+You may use k, M, G or T suffixes for kilobytes, megabytes, gigabytes and terabytes.
qemu-img: TEST_DIR/t.qcow2: Invalid options for file format 'qcow2'
== Check correct interpretation of suffixes for cluster size ==
@@ -157,30 +156,30 @@ Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_si
== Check compat level option ==
qemu-img create -f qcow2 -o compat=0.10 TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='0.10' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.10 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o compat=1.1 TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='1.1' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=1.1 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o compat=0.42 TEST_DIR/t.qcow2 64M
qemu-img: TEST_DIR/t.qcow2: Invalid compatibility level: '0.42'
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='0.42' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.42 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o compat=foobar TEST_DIR/t.qcow2 64M
qemu-img: TEST_DIR/t.qcow2: Invalid compatibility level: 'foobar'
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='foobar' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=foobar encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
== Check preallocation option ==
qemu-img create -f qcow2 -o preallocation=off TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 preallocation='off' lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 preallocation=off lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o preallocation=metadata TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 preallocation='metadata' lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 preallocation=metadata lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o preallocation=1234 TEST_DIR/t.qcow2 64M
qemu-img: TEST_DIR/t.qcow2: invalid parameter value: 1234
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 preallocation='1234' lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 preallocation=1234 lazy_refcounts=off refcount_bits=16
== Check encryption option ==
@@ -199,16 +198,16 @@ Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=on cluster_siz
== Check lazy_refcounts option (only with v3) ==
qemu-img create -f qcow2 -o compat=1.1,lazy_refcounts=off TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='1.1' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=1.1 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o compat=1.1,lazy_refcounts=on TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='1.1' encryption=off cluster_size=65536 lazy_refcounts=on refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=1.1 encryption=off cluster_size=65536 lazy_refcounts=on refcount_bits=16
qemu-img create -f qcow2 -o compat=0.10,lazy_refcounts=off TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='0.10' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.10 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o compat=0.10,lazy_refcounts=on TEST_DIR/t.qcow2 64M
qemu-img: TEST_DIR/t.qcow2: Lazy refcounts only supported with compatibility level 1.1 and above (use compat=1.1 or greater)
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='0.10' encryption=off cluster_size=65536 lazy_refcounts=on refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat=0.10 encryption=off cluster_size=65536 lazy_refcounts=on refcount_bits=16
*** done
diff --git a/tests/qemu-iotests/050.out b/tests/qemu-iotests/050.out
index a6cb2e686..397cf7f39 100644
--- a/tests/qemu-iotests/050.out
+++ b/tests/qemu-iotests/050.out
@@ -7,7 +7,7 @@ wrote 1048576/1048576 bytes at offset 0
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=10485760
wrote 1048576/1048576 bytes at offset 0
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=10485760 backing_file='TEST_DIR/t.IMGFMT.old'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=10485760 backing_file=TEST_DIR/t.IMGFMT.old
wrote 1048576/1048576 bytes at offset 0
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051
index 4a8055b67..17dbf04af 100755
--- a/tests/qemu-iotests/051
+++ b/tests/qemu-iotests/051
@@ -108,7 +108,8 @@ echo
echo === Overriding backing file ===
echo
-echo "info block" | run_qemu -drive file="$TEST_IMG",driver=qcow2,backing.file.filename="$TEST_IMG.orig" -nodefaults
+echo "info block" | run_qemu -drive file="$TEST_IMG",driver=qcow2,backing.file.filename="$TEST_IMG.orig" -nodefaults\
+ | _filter_generated_node_ids
# Drivers that don't support backing files
run_qemu -drive file="$TEST_IMG",driver=raw,backing.file.filename="$TEST_IMG.orig"
diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out
index 23c282357..7765aa0bb 100644
--- a/tests/qemu-iotests/051.out
+++ b/tests/qemu-iotests/051.out
@@ -1,6 +1,6 @@
QA output created by 051
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file='TEST_DIR/t.IMGFMT.base'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base
=== Unknown option ===
@@ -59,7 +59,7 @@ QEMU X.Y.Z monitor - type 'help' for more information
Testing: -drive file=TEST_DIR/t.qcow2,driver=qcow2,backing.file.filename=TEST_DIR/t.qcow2.orig -nodefaults
QEMU X.Y.Z monitor - type 'help' for more information
(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo block
-ide0-hd0: TEST_DIR/t.qcow2 (qcow2)
+ide0-hd0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Cache mode: writeback
Backing file: TEST_DIR/t.qcow2.orig (chain depth: 1)
(qemu) qququiquit
diff --git a/tests/qemu-iotests/055 b/tests/qemu-iotests/055
index 017a609f3..c8e357870 100755
--- a/tests/qemu-iotests/055
+++ b/tests/qemu-iotests/055
@@ -42,6 +42,8 @@ class TestSingleDrive(iotests.QMPTestCase):
qemu_img('create', '-f', iotests.imgfmt, blockdev_target_img, str(TestSingleDrive.image_len))
self.vm = iotests.VM().add_drive(test_img).add_drive(blockdev_target_img)
+ if iotests.qemu_default_machine == 'pc':
+ self.vm.add_drive(None, 'media=cdrom', 'ide')
self.vm.launch()
def tearDown(self):
@@ -104,12 +106,18 @@ class TestSingleDrive(iotests.QMPTestCase):
self.do_test_pause('blockdev-backup', 'drive1', blockdev_target_img)
def test_medium_not_found(self):
- result = self.vm.qmp('drive-backup', device='ide1-cd0',
+ if iotests.qemu_default_machine != 'pc':
+ return
+
+ result = self.vm.qmp('drive-backup', device='drive2', # CD-ROM
target=target_img, sync='full')
self.assert_qmp(result, 'error/class', 'GenericError')
def test_medium_not_found_blockdev_backup(self):
- result = self.vm.qmp('blockdev-backup', device='ide1-cd0',
+ if iotests.qemu_default_machine != 'pc':
+ return
+
+ result = self.vm.qmp('blockdev-backup', device='drive2', # CD-ROM
target='drive1', sync='full')
self.assert_qmp(result, 'error/class', 'GenericError')
@@ -249,6 +257,8 @@ class TestSingleTransaction(iotests.QMPTestCase):
qemu_img('create', '-f', iotests.imgfmt, blockdev_target_img, str(TestSingleDrive.image_len))
self.vm = iotests.VM().add_drive(test_img).add_drive(blockdev_target_img)
+ if iotests.qemu_default_machine == 'pc':
+ self.vm.add_drive(None, 'media=cdrom', 'ide')
self.vm.launch()
def tearDown(self):
@@ -323,9 +333,12 @@ class TestSingleTransaction(iotests.QMPTestCase):
self.do_test_pause('blockdev-backup', 'drive1', blockdev_target_img)
def do_test_medium_not_found(self, cmd, target):
+ if iotests.qemu_default_machine != 'pc':
+ return
+
result = self.vm.qmp('transaction', actions=[{
'type': cmd,
- 'data': { 'device': 'ide1-cd0',
+ 'data': { 'device': 'drive2', # CD-ROM
'target': target,
'sync': 'full' },
}
diff --git a/tests/qemu-iotests/056 b/tests/qemu-iotests/056
index 54e4bd069..04f2c3c84 100755
--- a/tests/qemu-iotests/056
+++ b/tests/qemu-iotests/056
@@ -82,6 +82,31 @@ class TestSyncModesNoneAndTop(iotests.QMPTestCase):
time.sleep(1)
self.assertEqual(-1, qemu_io('-c', 'read -P0x41 0 512', target_img).find("verification failed"))
+class TestBeforeWriteNotifier(iotests.QMPTestCase):
+ def setUp(self):
+ self.vm = iotests.VM().add_drive_raw("file=blkdebug::null-co://,id=drive0,align=65536,driver=blkdebug")
+ self.vm.launch()
+
+ def tearDown(self):
+ self.vm.shutdown()
+ os.remove(target_img)
+
+ def test_before_write_notifier(self):
+ self.vm.pause_drive("drive0")
+ result = self.vm.qmp('drive-backup', device='drive0',
+ sync='full', target=target_img,
+ format="file", speed=1)
+ self.assert_qmp(result, 'return', {})
+ result = self.vm.qmp('block-job-pause', device="drive0")
+ self.assert_qmp(result, 'return', {})
+ # Speed is low enough that this must be an uncopied range, which will
+ # trigger the before write notifier
+ self.vm.hmp_qemu_io('drive0', 'aio_write -P 1 512512 512')
+ self.vm.resume_drive("drive0")
+ result = self.vm.qmp('block-job-resume', device="drive0")
+ self.assert_qmp(result, 'return', {})
+ event = self.cancel_and_wait()
+ self.assert_qmp(event, 'data/type', 'backup')
if __name__ == '__main__':
iotests.main(supported_fmts=['qcow2', 'qed'])
diff --git a/tests/qemu-iotests/056.out b/tests/qemu-iotests/056.out
index fbc63e62f..8d7e99670 100644
--- a/tests/qemu-iotests/056.out
+++ b/tests/qemu-iotests/056.out
@@ -1,5 +1,5 @@
-..
+...
----------------------------------------------------------------------
-Ran 2 tests
+Ran 3 tests
OK
diff --git a/tests/qemu-iotests/058 b/tests/qemu-iotests/058
index f2bdd0bff..63a659878 100755
--- a/tests/qemu-iotests/058
+++ b/tests/qemu-iotests/058
@@ -32,11 +32,17 @@ status=1 # failure is the default!
nbd_unix_socket=$TEST_DIR/test_qemu_nbd_socket
nbd_snapshot_img="nbd:unix:$nbd_unix_socket"
+rm -f "${TEST_DIR}/qemu-nbd.pid"
_cleanup_nbd()
{
- if [ -n "$NBD_SNAPSHOT_PID" ]; then
- kill "$NBD_SNAPSHOT_PID"
+ local NBD_SNAPSHOT_PID
+ if [ -f "${TEST_DIR}/qemu-nbd.pid" ]; then
+ read NBD_SNAPSHOT_PID < "${TEST_DIR}/qemu-nbd.pid"
+ rm -f "${TEST_DIR}/qemu-nbd.pid"
+ if [ -n "$NBD_SNAPSHOT_PID" ]; then
+ kill "$NBD_SNAPSHOT_PID"
+ fi
fi
rm -f "$nbd_unix_socket"
}
@@ -60,7 +66,6 @@ _export_nbd_snapshot()
{
_cleanup_nbd
$QEMU_NBD -v -t -k "$nbd_unix_socket" "$TEST_IMG" -l $1 &
- NBD_SNAPSHOT_PID=$!
_wait_for_nbd
}
@@ -68,7 +73,6 @@ _export_nbd_snapshot1()
{
_cleanup_nbd
$QEMU_NBD -v -t -k "$nbd_unix_socket" "$TEST_IMG" -l snapshot.name=$1 &
- NBD_SNAPSHOT_PID=$!
_wait_for_nbd
}
diff --git a/tests/qemu-iotests/059.out b/tests/qemu-iotests/059.out
index 67e3cf57e..00057fef9 100644
--- a/tests/qemu-iotests/059.out
+++ b/tests/qemu-iotests/059.out
@@ -16,17 +16,17 @@ qemu-io: can't open device TEST_DIR/t.vmdk: L1 size too big
no file open, try 'help open'
=== Testing monolithicFlat creation and opening ===
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2147483648
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2147483648 subformat=monolithicFlat
image: TEST_DIR/t.IMGFMT
file format: IMGFMT
virtual size: 2.0G (2147483648 bytes)
=== Testing monolithicFlat with zeroed_grain ===
qemu-img: TEST_DIR/t.IMGFMT: Flat image can't enable zeroed grain
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2147483648
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=2147483648 subformat=monolithicFlat
=== Testing big twoGbMaxExtentFlat ===
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824000
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824000 subformat=twoGbMaxExtentFlat
image: TEST_DIR/t.vmdk
file format: vmdk
virtual size: 1.0T (1073741824000 bytes)
@@ -2043,7 +2043,7 @@ RW 12582912 VMFS "dummy.IMGFMT" 1
=== Testing truncated sparse ===
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=107374182400
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=107374182400 subformat=monolithicSparse
qemu-img: Could not open 'TEST_DIR/t.IMGFMT': File truncated, expecting at least 13172736 bytes
=== Converting to streamOptimized from image with small cluster size===
@@ -2054,7 +2054,7 @@ wrote 512/512 bytes at offset 10240
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
=== Testing monolithicFlat with internally generated JSON file name ===
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 subformat=monolithicFlat
qemu-io: can't open: Cannot use relative extent paths with VMDK descriptor file 'json:{"image": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "driver": "blkdebug", "inject-error.0.event": "read_aio"}'
=== Testing version 3 ===
@@ -2264,7 +2264,7 @@ read 512/512 bytes at offset 64931328
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
=== Testing 4TB monolithicFlat creation and IO ===
-Formatting 'TEST_DIR/iotest-version3.IMGFMT', fmt=IMGFMT size=4398046511104
+Formatting 'TEST_DIR/iotest-version3.IMGFMT', fmt=IMGFMT size=4398046511104 subformat=monolithicFlat
image: TEST_DIR/iotest-version3.IMGFMT
file format: IMGFMT
virtual size: 4.0T (4398046511104 bytes)
diff --git a/tests/qemu-iotests/061 b/tests/qemu-iotests/061
index 8d37f8a65..e191e65d5 100755
--- a/tests/qemu-iotests/061
+++ b/tests/qemu-iotests/061
@@ -58,7 +58,8 @@ echo
echo "=== Testing dirty version downgrade ==="
echo
IMGOPTS="compat=1.1,lazy_refcounts=on" _make_test_img 64M
-$QEMU_IO -c "write -P 0x2a 0 128k" -c flush -c abort "$TEST_IMG" | _filter_qemu_io
+$QEMU_IO -c "write -P 0x2a 0 128k" -c flush \
+ -c "sigraise $(kill -l KILL)" "$TEST_IMG" 2>&1 | _filter_qemu_io
$PYTHON qcow2.py "$TEST_IMG" dump-header
$QEMU_IMG amend -o "compat=0.10" "$TEST_IMG"
$PYTHON qcow2.py "$TEST_IMG" dump-header
@@ -91,7 +92,8 @@ echo
echo "=== Testing dirty lazy_refcounts=off ==="
echo
IMGOPTS="compat=1.1,lazy_refcounts=on" _make_test_img 64M
-$QEMU_IO -c "write -P 0x2a 0 128k" -c flush -c abort "$TEST_IMG" | _filter_qemu_io
+$QEMU_IO -c "write -P 0x2a 0 128k" -c flush \
+ -c "sigraise $(kill -l KILL)" "$TEST_IMG" 2>&1 | _filter_qemu_io
$PYTHON qcow2.py "$TEST_IMG" dump-header
$QEMU_IMG amend -o "lazy_refcounts=off" "$TEST_IMG"
$PYTHON qcow2.py "$TEST_IMG" dump-header
diff --git a/tests/qemu-iotests/061.out b/tests/qemu-iotests/061.out
index 5ec248f79..f2598a8f9 100644
--- a/tests/qemu-iotests/061.out
+++ b/tests/qemu-iotests/061.out
@@ -57,6 +57,11 @@ No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
wrote 131072/131072 bytes at offset 0
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
+ exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@";
+else
+ exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@";
+fi )
magic 0x514649fb
version 3
backing_file_offset 0x0
@@ -214,6 +219,11 @@ No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
wrote 131072/131072 bytes at offset 0
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
+ exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@";
+else
+ exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@";
+fi )
magic 0x514649fb
version 3
backing_file_offset 0x0
@@ -334,7 +344,7 @@ read 131072/131072 bytes at offset 0
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
wrote 131072/131072 bytes at offset 0
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file='TEST_DIR/t.IMGFMT.base'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base
read 131072/131072 bytes at offset 0
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 65536/65536 bytes at offset 0
@@ -350,7 +360,7 @@ read 65536/65536 bytes at offset 65536
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
wrote 131072/131072 bytes at offset 0
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file='TEST_DIR/t.IMGFMT.base'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base
wrote 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 131072/131072 bytes at offset 0
@@ -369,7 +379,7 @@ read 65536/65536 bytes at offset 65536
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
wrote 131072/131072 bytes at offset 0
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file='TEST_DIR/t.IMGFMT.base'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base
wrote 131072/131072 bytes at offset 0
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
No errors were found on the image.
@@ -393,7 +403,7 @@ read 67108864/67108864 bytes at offset 0
=== Testing progress report without snapshot ===
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=4294967296
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 backing_file='TEST_DIR/t.IMGFMT.base'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 backing_file=TEST_DIR/t.IMGFMT.base
wrote 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 65536/65536 bytes at offset 1073741824
@@ -408,7 +418,7 @@ No errors were found on the image.
=== Testing progress report with snapshot ===
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=4294967296
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 backing_file='TEST_DIR/t.IMGFMT.base'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 backing_file=TEST_DIR/t.IMGFMT.base
wrote 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 65536/65536 bytes at offset 1073741824
diff --git a/tests/qemu-iotests/067 b/tests/qemu-iotests/067
index 83eefa394..3788534d6 100755
--- a/tests/qemu-iotests/067
+++ b/tests/qemu-iotests/067
@@ -48,7 +48,8 @@ function do_run_qemu()
function run_qemu()
{
do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp | _filter_qemu \
- | sed -e 's/\("actual-size":\s*\)[0-9]\+/\1SIZE/g'
+ | sed -e 's/\("actual-size":\s*\)[0-9]\+/\1SIZE/g' \
+ | _filter_generated_node_ids
}
size=128M
@@ -59,7 +60,7 @@ echo
echo === -drive/-device and device_del ===
echo
-run_qemu -drive file=$TEST_IMG,format=$IMGFMT,if=none,id=disk -device virtio-blk-pci,drive=disk,id=virtio0 <<EOF
+run_qemu -drive file=$TEST_IMG,format=$IMGFMT,if=none,id=disk -device virtio-blk,drive=disk,id=virtio0 <<EOF
{ "execute": "qmp_capabilities" }
{ "execute": "query-block" }
{ "execute": "device_del", "arguments": { "id": "virtio0" } }
@@ -76,7 +77,7 @@ run_qemu -drive file=$TEST_IMG,format=$IMGFMT,if=none,id=disk <<EOF
{ "execute": "qmp_capabilities" }
{ "execute": "query-block" }
{ "execute": "device_add",
- "arguments": { "driver": "virtio-blk-pci", "drive": "disk",
+ "arguments": { "driver": "virtio-blk", "drive": "disk",
"id": "virtio0" } }
{ "execute": "device_del", "arguments": { "id": "virtio0" } }
{ "execute": "system_reset" }
@@ -94,7 +95,7 @@ run_qemu <<EOF
"arguments": { "command-line": "drive_add 0 file=$TEST_IMG,format=$IMGFMT,if=none,id=disk" } }
{ "execute": "query-block" }
{ "execute": "device_add",
- "arguments": { "driver": "virtio-blk-pci", "drive": "disk",
+ "arguments": { "driver": "virtio-blk", "drive": "disk",
"id": "virtio0" } }
{ "execute": "device_del", "arguments": { "id": "virtio0" } }
{ "execute": "system_reset" }
@@ -122,7 +123,7 @@ run_qemu <<EOF
}
{ "execute": "query-block" }
{ "execute": "device_add",
- "arguments": { "driver": "virtio-blk-pci", "drive": "disk",
+ "arguments": { "driver": "virtio-blk", "drive": "disk",
"id": "virtio0" } }
{ "execute": "device_del", "arguments": { "id": "virtio0" } }
{ "execute": "system_reset" }
diff --git a/tests/qemu-iotests/067.out b/tests/qemu-iotests/067.out
index 6ff41bc7a..27ad56fe2 100644
--- a/tests/qemu-iotests/067.out
+++ b/tests/qemu-iotests/067.out
@@ -3,7 +3,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
=== -drive/-device and device_del ===
-Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk -device virtio-blk-pci,drive=disk,id=virtio0
+Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk -device virtio-blk,drive=disk,id=virtio0
{
QMP_VERSION
}
@@ -40,6 +40,7 @@ Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk -device virti
},
"iops_wr": 0,
"ro": false,
+ "node-name": "NODE_NAME",
"backing_file_depth": 0,
"drv": "qcow2",
"iops": 0,
@@ -57,28 +58,6 @@ Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk -device virti
"encryption_key_missing": false
},
"type": "unknown"
- },
- {
- "io-status": "ok",
- "device": "ide1-cd0",
- "locked": false,
- "removable": true,
- "tray_open": false,
- "type": "unknown"
- },
- {
- "device": "floppy0",
- "locked": false,
- "removable": true,
- "tray_open": false,
- "type": "unknown"
- },
- {
- "device": "sd0",
- "locked": false,
- "removable": true,
- "tray_open": false,
- "type": "unknown"
}
]
}
@@ -120,28 +99,6 @@ Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk -device virti
}
{
"return": [
- {
- "io-status": "ok",
- "device": "ide1-cd0",
- "locked": false,
- "removable": true,
- "tray_open": false,
- "type": "unknown"
- },
- {
- "device": "floppy0",
- "locked": false,
- "removable": true,
- "tray_open": false,
- "type": "unknown"
- },
- {
- "device": "sd0",
- "locked": false,
- "removable": true,
- "tray_open": false,
- "type": "unknown"
- }
]
}
{
@@ -155,28 +112,6 @@ Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk -device virti
},
"event": "SHUTDOWN"
}
-{
- "timestamp": {
- "seconds": TIMESTAMP,
- "microseconds": TIMESTAMP
- },
- "event": "DEVICE_TRAY_MOVED",
- "data": {
- "device": "ide1-cd0",
- "tray-open": true
- }
-}
-{
- "timestamp": {
- "seconds": TIMESTAMP,
- "microseconds": TIMESTAMP
- },
- "event": "DEVICE_TRAY_MOVED",
- "data": {
- "device": "floppy0",
- "tray-open": true
- }
-}
=== -drive/device_add and device_del ===
@@ -217,6 +152,7 @@ Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk
},
"iops_wr": 0,
"ro": false,
+ "node-name": "NODE_NAME",
"backing_file_depth": 0,
"drv": "qcow2",
"iops": 0,
@@ -235,28 +171,6 @@ Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk
},
"tray_open": false,
"type": "unknown"
- },
- {
- "io-status": "ok",
- "device": "ide1-cd0",
- "locked": false,
- "removable": true,
- "tray_open": false,
- "type": "unknown"
- },
- {
- "device": "floppy0",
- "locked": false,
- "removable": true,
- "tray_open": false,
- "type": "unknown"
- },
- {
- "device": "sd0",
- "locked": false,
- "removable": true,
- "tray_open": false,
- "type": "unknown"
}
]
}
@@ -302,28 +216,6 @@ Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk
}
{
"return": [
- {
- "io-status": "ok",
- "device": "ide1-cd0",
- "locked": false,
- "removable": true,
- "tray_open": false,
- "type": "unknown"
- },
- {
- "device": "floppy0",
- "locked": false,
- "removable": true,
- "tray_open": false,
- "type": "unknown"
- },
- {
- "device": "sd0",
- "locked": false,
- "removable": true,
- "tray_open": false,
- "type": "unknown"
- }
]
}
{
@@ -337,28 +229,6 @@ Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk
},
"event": "SHUTDOWN"
}
-{
- "timestamp": {
- "seconds": TIMESTAMP,
- "microseconds": TIMESTAMP
- },
- "event": "DEVICE_TRAY_MOVED",
- "data": {
- "device": "ide1-cd0",
- "tray-open": true
- }
-}
-{
- "timestamp": {
- "seconds": TIMESTAMP,
- "microseconds": TIMESTAMP
- },
- "event": "DEVICE_TRAY_MOVED",
- "data": {
- "device": "floppy0",
- "tray-open": true
- }
-}
=== drive_add/device_add and device_del ===
@@ -377,28 +247,6 @@ Testing:
{
"return": [
{
- "io-status": "ok",
- "device": "ide1-cd0",
- "locked": false,
- "removable": true,
- "tray_open": false,
- "type": "unknown"
- },
- {
- "device": "floppy0",
- "locked": false,
- "removable": true,
- "tray_open": false,
- "type": "unknown"
- },
- {
- "device": "sd0",
- "locked": false,
- "removable": true,
- "tray_open": false,
- "type": "unknown"
- },
- {
"device": "disk",
"locked": false,
"removable": true,
@@ -424,6 +272,7 @@ Testing:
},
"iops_wr": 0,
"ro": false,
+ "node-name": "NODE_NAME",
"backing_file_depth": 0,
"drv": "qcow2",
"iops": 0,
@@ -487,28 +336,6 @@ Testing:
}
{
"return": [
- {
- "io-status": "ok",
- "device": "ide1-cd0",
- "locked": false,
- "removable": true,
- "tray_open": false,
- "type": "unknown"
- },
- {
- "device": "floppy0",
- "locked": false,
- "removable": true,
- "tray_open": false,
- "type": "unknown"
- },
- {
- "device": "sd0",
- "locked": false,
- "removable": true,
- "tray_open": false,
- "type": "unknown"
- }
]
}
{
@@ -522,28 +349,6 @@ Testing:
},
"event": "SHUTDOWN"
}
-{
- "timestamp": {
- "seconds": TIMESTAMP,
- "microseconds": TIMESTAMP
- },
- "event": "DEVICE_TRAY_MOVED",
- "data": {
- "device": "ide1-cd0",
- "tray-open": true
- }
-}
-{
- "timestamp": {
- "seconds": TIMESTAMP,
- "microseconds": TIMESTAMP
- },
- "event": "DEVICE_TRAY_MOVED",
- "data": {
- "device": "floppy0",
- "tray-open": true
- }
-}
=== blockdev_add/device_add and device_del ===
@@ -563,28 +368,6 @@ Testing:
{
"return": [
{
- "io-status": "ok",
- "device": "ide1-cd0",
- "locked": false,
- "removable": true,
- "tray_open": false,
- "type": "unknown"
- },
- {
- "device": "floppy0",
- "locked": false,
- "removable": true,
- "tray_open": false,
- "type": "unknown"
- },
- {
- "device": "sd0",
- "locked": false,
- "removable": true,
- "tray_open": false,
- "type": "unknown"
- },
- {
"device": "disk",
"locked": false,
"removable": true,
@@ -610,6 +393,7 @@ Testing:
},
"iops_wr": 0,
"ro": false,
+ "node-name": "NODE_NAME",
"backing_file_depth": 0,
"drv": "qcow2",
"iops": 0,
@@ -675,28 +459,6 @@ Testing:
"return": [
{
"io-status": "ok",
- "device": "ide1-cd0",
- "locked": false,
- "removable": true,
- "tray_open": false,
- "type": "unknown"
- },
- {
- "device": "floppy0",
- "locked": false,
- "removable": true,
- "tray_open": false,
- "type": "unknown"
- },
- {
- "device": "sd0",
- "locked": false,
- "removable": true,
- "tray_open": false,
- "type": "unknown"
- },
- {
- "io-status": "ok",
"device": "disk",
"locked": false,
"removable": true,
@@ -722,6 +484,7 @@ Testing:
},
"iops_wr": 0,
"ro": false,
+ "node-name": "NODE_NAME",
"backing_file_depth": 0,
"drv": "qcow2",
"iops": 0,
@@ -754,27 +517,5 @@ Testing:
},
"event": "SHUTDOWN"
}
-{
- "timestamp": {
- "seconds": TIMESTAMP,
- "microseconds": TIMESTAMP
- },
- "event": "DEVICE_TRAY_MOVED",
- "data": {
- "device": "ide1-cd0",
- "tray-open": true
- }
-}
-{
- "timestamp": {
- "seconds": TIMESTAMP,
- "microseconds": TIMESTAMP
- },
- "event": "DEVICE_TRAY_MOVED",
- "data": {
- "device": "floppy0",
- "tray-open": true
- }
-}
*** done
diff --git a/tests/qemu-iotests/069.out b/tests/qemu-iotests/069.out
index 4d7e63cf8..c78e8c2b7 100644
--- a/tests/qemu-iotests/069.out
+++ b/tests/qemu-iotests/069.out
@@ -3,6 +3,6 @@ QA output created by 069
=== Creating an image with a backing file and deleting that file ===
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=131072
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072 backing_file='TEST_DIR/t.IMGFMT.base'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072 backing_file=TEST_DIR/t.IMGFMT.base
qemu-io: can't open device TEST_DIR/t.IMGFMT: Could not open backing file: Could not open 'TEST_DIR/t.IMGFMT.base': No such file or directory
*** done
diff --git a/tests/qemu-iotests/071 b/tests/qemu-iotests/071
index 9eaa49b41..92ab99145 100755
--- a/tests/qemu-iotests/071
+++ b/tests/qemu-iotests/071
@@ -104,11 +104,20 @@ echo
echo "=== Testing blkdebug on existing block device ==="
echo
-run_qemu -drive "file=$TEST_IMG,format=raw,if=none,id=drive0" <<EOF
+run_qemu <<EOF
{ "execute": "qmp_capabilities" }
{ "execute": "blockdev-add",
"arguments": {
"options": {
+ "node-name": "drive0",
+ "driver": "file",
+ "filename": "$TEST_IMG"
+ }
+ }
+}
+{ "execute": "blockdev-add",
+ "arguments": {
+ "options": {
"driver": "$IMGFMT",
"id": "drive0-debug",
"file": {
@@ -133,20 +142,29 @@ echo
echo "=== Testing blkverify on existing block device ==="
echo
-run_qemu -drive "file=$TEST_IMG,format=$IMGFMT,if=none,id=drive0" <<EOF
+run_qemu <<EOF
{ "execute": "qmp_capabilities" }
{ "execute": "blockdev-add",
"arguments": {
"options": {
+ "node-name": "drive0",
+ "driver": "$IMGFMT",
+ "file": {
+ "driver": "file",
+ "filename": "$TEST_IMG"
+ }
+ }
+ }
+}
+{ "execute": "blockdev-add",
+ "arguments": {
+ "options": {
"driver": "blkverify",
"id": "drive0-verify",
"test": "drive0",
"raw": {
- "driver": "raw",
- "file": {
- "driver": "file",
- "filename": "$TEST_IMG.base"
- }
+ "driver": "file",
+ "filename": "$TEST_IMG.base"
}
}
}
@@ -163,11 +181,20 @@ echo
echo "=== Testing blkverify on existing raw block device ==="
echo
-run_qemu -drive "file=$TEST_IMG.base,format=raw,if=none,id=drive0" <<EOF
+run_qemu <<EOF
{ "execute": "qmp_capabilities" }
{ "execute": "blockdev-add",
"arguments": {
"options": {
+ "node-name": "drive0",
+ "driver": "file",
+ "filename": "$TEST_IMG.base"
+ }
+ }
+}
+{ "execute": "blockdev-add",
+ "arguments": {
+ "options": {
"driver": "blkverify",
"id": "drive0-verify",
"test": {
@@ -193,11 +220,20 @@ echo
echo "=== Testing blkdebug's set-state through QMP ==="
echo
-run_qemu -drive "file=$TEST_IMG,format=raw,if=none,id=drive0" <<EOF
+run_qemu <<EOF
{ "execute": "qmp_capabilities" }
{ "execute": "blockdev-add",
"arguments": {
"options": {
+ "node-name": "drive0",
+ "driver": "file",
+ "filename": "$TEST_IMG"
+ }
+ }
+}
+{ "execute": "blockdev-add",
+ "arguments": {
+ "options": {
"driver": "$IMGFMT",
"id": "drive0-debug",
"file": {
diff --git a/tests/qemu-iotests/071.out b/tests/qemu-iotests/071.out
index 9205ce251..2b40eadae 100644
--- a/tests/qemu-iotests/071.out
+++ b/tests/qemu-iotests/071.out
@@ -42,44 +42,46 @@ read failed: Input/output error
=== Testing blkdebug on existing block device ===
-Testing: -drive file=TEST_DIR/t.IMGFMT,format=raw,if=none,id=drive0
+Testing:
QMP_VERSION
{"return": {}}
{"return": {}}
+{"return": {}}
read failed: Input/output error
{"return": ""}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "floppy0", "tray-open": true}}
QEMU_PROG: Failed to flush the L2 table cache: Input/output error
QEMU_PROG: Failed to flush the refcount block cache: Input/output error
=== Testing blkverify on existing block device ===
-Testing: -drive file=TEST_DIR/t.IMGFMT,format=IMGFMT,if=none,id=drive0
+Testing:
QMP_VERSION
{"return": {}}
{"return": {}}
+{"return": {}}
blkverify: read sector_num=0 nb_sectors=1 contents mismatch in sector 0
=== Testing blkverify on existing raw block device ===
-Testing: -drive file=TEST_DIR/t.IMGFMT.base,format=raw,if=none,id=drive0
+Testing:
QMP_VERSION
{"return": {}}
{"return": {}}
+{"return": {}}
blkverify: read sector_num=0 nb_sectors=1 contents mismatch in sector 0
=== Testing blkdebug's set-state through QMP ===
-Testing: -drive file=TEST_DIR/t.IMGFMT,format=raw,if=none,id=drive0
+Testing:
QMP_VERSION
{"return": {}}
{"return": {}}
+{"return": {}}
read 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{"return": ""}
@@ -90,8 +92,6 @@ read failed: Input/output error
{"return": ""}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "floppy0", "tray-open": true}}
QEMU_PROG: Failed to flush the L2 table cache: Input/output error
QEMU_PROG: Failed to flush the refcount block cache: Input/output error
diff --git a/tests/qemu-iotests/073.out b/tests/qemu-iotests/073.out
index 733d79ca9..de5452492 100644
--- a/tests/qemu-iotests/073.out
+++ b/tests/qemu-iotests/073.out
@@ -2,7 +2,7 @@ QA output created by 073
== creating backing file ==
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file='TEST_DIR/t.IMGFMT.base'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base
wrote 134217728/134217728 bytes at offset 0
128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
diff --git a/tests/qemu-iotests/079.out b/tests/qemu-iotests/079.out
index 6dc5d5763..aab922fb3 100644
--- a/tests/qemu-iotests/079.out
+++ b/tests/qemu-iotests/079.out
@@ -1,14 +1,14 @@
QA output created by 079
=== Check option preallocation and cluster_size ===
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 preallocation='metadata'
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 preallocation='metadata'
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 preallocation='metadata'
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 preallocation='metadata'
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 preallocation='metadata'
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 preallocation='metadata'
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 preallocation='metadata'
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 preallocation='metadata'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 preallocation=metadata
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 preallocation=metadata
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 preallocation=metadata
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 preallocation=metadata
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 preallocation=metadata
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 preallocation=metadata
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 preallocation=metadata
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 preallocation=metadata
qemu-img: TEST_DIR/t.IMGFMT: Cluster size must be a power of two between 512 and 2048k
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 preallocation='metadata'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 preallocation=metadata
*** done
diff --git a/tests/qemu-iotests/081 b/tests/qemu-iotests/081
index d9b042cfc..e4b4c6cbf 100755
--- a/tests/qemu-iotests/081
+++ b/tests/qemu-iotests/081
@@ -53,7 +53,8 @@ function do_run_qemu()
function run_qemu()
{
- do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_qmp | _filter_qemu_io
+ do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_qmp\
+ | _filter_qemu_io | _filter_generated_node_ids
}
test_quorum=$($QEMU_IMG --help|grep quorum)
@@ -101,17 +102,29 @@ $QEMU_IO -c "open -o $quorum" -c "read -P 0x32 0 $size" | _filter_qemu_io
echo
echo "== checking mixed reference/option specification =="
-run_qemu -drive "file=$TEST_DIR/2.raw,format=$IMGFMT,if=none,id=drive2" <<EOF
+run_qemu <<EOF
{ "execute": "qmp_capabilities" }
{ "execute": "blockdev-add",
"arguments": {
"options": {
+ "node-name": "drive2",
+ "driver": "$IMGFMT",
+ "file": {
+ "driver": "file",
+ "filename": "$TEST_DIR/2.raw"
+ }
+ }
+ }
+}
+{ "execute": "blockdev-add",
+ "arguments": {
+ "options": {
"driver": "quorum",
"id": "drive0-quorum",
"vote-threshold": 2,
"children": [
{
- "driver": "raw",
+ "driver": "$IMGFMT",
"file": {
"driver": "file",
"filename": "$TEST_DIR/1.raw"
@@ -119,7 +132,7 @@ run_qemu -drive "file=$TEST_DIR/2.raw,format=$IMGFMT,if=none,id=drive2" <<EOF
},
"drive2",
{
- "driver": "raw",
+ "driver": "$IMGFMT",
"file": {
"driver": "file",
"filename": "$TEST_DIR/3.raw"
diff --git a/tests/qemu-iotests/081.out b/tests/qemu-iotests/081.out
index 9f57d9d3b..70632314c 100644
--- a/tests/qemu-iotests/081.out
+++ b/tests/qemu-iotests/081.out
@@ -26,18 +26,17 @@ read 10485760/10485760 bytes at offset 0
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
== checking mixed reference/option specification ==
-Testing: -drive file=TEST_DIR/2.IMGFMT,format=IMGFMT,if=none,id=drive2
+Testing:
QMP_VERSION
{"return": {}}
{"return": {}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "QUORUM_REPORT_BAD", "data": {"node-name": "", "sectors-count": 20480, "sector-num": 0}}
+{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "QUORUM_REPORT_BAD", "data": {"node-name": "drive2", "sectors-count": 20480, "sector-num": 0}}
read 10485760/10485760 bytes at offset 0
10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{"return": ""}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "floppy0", "tray-open": true}}
== using quorum rewrite corrupted mode ==
diff --git a/tests/qemu-iotests/082.out b/tests/qemu-iotests/082.out
index 3a749b825..a952330ba 100644
--- a/tests/qemu-iotests/082.out
+++ b/tests/qemu-iotests/082.out
@@ -147,10 +147,10 @@ refcount_bits Width of a reference count entry in bits
nocow Turn off copy-on-write (valid only on btrfs)
Testing: create -f qcow2 -o backing_file=TEST_DIR/t.qcow2,,help TEST_DIR/t.qcow2 128M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/t.qcow2,help' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2,,help encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Testing: create -f qcow2 -o backing_file=TEST_DIR/t.qcow2,,? TEST_DIR/t.qcow2 128M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/t.qcow2,?' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2,,? encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Testing: create -f qcow2 -o backing_file=TEST_DIR/t.qcow2, -o help TEST_DIR/t.qcow2 128M
qemu-img: Invalid option list: backing_file=TEST_DIR/t.qcow2,
diff --git a/tests/qemu-iotests/085 b/tests/qemu-iotests/085
index 56cd6f89b..aa77eca77 100755
--- a/tests/qemu-iotests/085
+++ b/tests/qemu-iotests/085
@@ -7,6 +7,7 @@
# snapshots are performed.
#
# Copyright (C) 2014 Red Hat, Inc.
+# Copyright (C) 2015 Igalia, S.L.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -34,17 +35,17 @@ status=1 # failure is the default!
snapshot_virt0="snapshot-v0.qcow2"
snapshot_virt1="snapshot-v1.qcow2"
-MAX_SNAPSHOTS=10
+SNAPSHOTS=10
_cleanup()
{
_cleanup_qemu
- for i in $(seq 1 ${MAX_SNAPSHOTS})
+ for i in $(seq 1 ${SNAPSHOTS})
do
rm -f "${TEST_DIR}/${i}-${snapshot_virt0}"
rm -f "${TEST_DIR}/${i}-${snapshot_virt1}"
done
- _cleanup_test_img
+ rm -f "${TEST_IMG}.1" "${TEST_IMG}.2"
}
trap "_cleanup; exit \$status" 0 1 2 3 15
@@ -64,7 +65,7 @@ function create_single_snapshot()
{
cmd="{ 'execute': 'blockdev-snapshot-sync',
'arguments': { 'device': 'virtio0',
- 'snapshot-file':'"${TEST_DIR}/${1}-${snapshot_virt0}"',
+ 'snapshot-file':'${TEST_DIR}/${1}-${snapshot_virt0}',
'format': 'qcow2' } }"
_send_qemu_cmd $h "${cmd}" "return"
}
@@ -76,27 +77,60 @@ function create_group_snapshot()
{'actions': [
{ 'type': 'blockdev-snapshot-sync', 'data' :
{ 'device': 'virtio0',
- 'snapshot-file': '"${TEST_DIR}/${1}-${snapshot_virt0}"' } },
+ 'snapshot-file': '${TEST_DIR}/${1}-${snapshot_virt0}' } },
{ 'type': 'blockdev-snapshot-sync', 'data' :
{ 'device': 'virtio1',
- 'snapshot-file': '"${TEST_DIR}/${1}-${snapshot_virt1}"' } } ]
+ 'snapshot-file': '${TEST_DIR}/${1}-${snapshot_virt1}' } } ]
} }"
_send_qemu_cmd $h "${cmd}" "return"
}
+# ${1}: unique identifier for the snapshot filename
+# ${2}: true: open backing images; false: don't open them (default)
+function add_snapshot_image()
+{
+ if [ "${2}" = "true" ]; then
+ extra_params=""
+ else
+ extra_params="'backing': '', "
+ fi
+ base_image="${TEST_DIR}/$((${1}-1))-${snapshot_virt0}"
+ snapshot_file="${TEST_DIR}/${1}-${snapshot_virt0}"
+ _make_test_img -b "${base_image}" "$size"
+ mv "${TEST_IMG}" "${snapshot_file}"
+ cmd="{ 'execute': 'blockdev-add', 'arguments':
+ { 'options':
+ { 'driver': 'qcow2', 'node-name': 'snap_${1}', ${extra_params}
+ 'file':
+ { 'driver': 'file', 'filename': '${snapshot_file}',
+ 'node-name': 'file_${1}' } } } }"
+ _send_qemu_cmd $h "${cmd}" "return"
+}
+
+# ${1}: unique identifier for the snapshot filename
+# ${2}: expected response, defaults to 'return'
+function blockdev_snapshot()
+{
+ cmd="{ 'execute': 'blockdev-snapshot',
+ 'arguments': { 'node': 'virtio0',
+ 'overlay':'snap_${1}' } }"
+ _send_qemu_cmd $h "${cmd}" "${2:-return}"
+}
+
size=128M
_make_test_img $size
-mv "${TEST_IMG}" "${TEST_IMG}.orig"
+mv "${TEST_IMG}" "${TEST_IMG}.1"
_make_test_img $size
+mv "${TEST_IMG}" "${TEST_IMG}.2"
echo
echo === Running QEMU ===
echo
qemu_comm_method="qmp"
-_launch_qemu -drive file="${TEST_IMG}.orig",if=virtio -drive file="${TEST_IMG}",if=virtio
+_launch_qemu -drive file="${TEST_IMG}.1",if=virtio -drive file="${TEST_IMG}.2",if=virtio
h=$QEMU_HANDLE
echo
@@ -105,6 +139,8 @@ echo
_send_qemu_cmd $h "{ 'execute': 'qmp_capabilities' }" "return"
+# Tests for the blockdev-snapshot-sync command
+
echo
echo === Create a single snapshot on virtio0 ===
echo
@@ -117,7 +153,7 @@ echo === Invalid command - missing device and nodename ===
echo
_send_qemu_cmd $h "{ 'execute': 'blockdev-snapshot-sync',
- 'arguments': { 'snapshot-file':'"${TEST_DIR}/1-${snapshot_virt0}"',
+ 'arguments': { 'snapshot-file':'${TEST_DIR}/1-${snapshot_virt0}',
'format': 'qcow2' } }" "error"
echo
@@ -132,11 +168,75 @@ echo
echo === Create several transactional group snapshots ===
echo
-for i in $(seq 2 ${MAX_SNAPSHOTS})
+for i in $(seq 2 ${SNAPSHOTS})
do
create_group_snapshot ${i}
done
+# Tests for the blockdev-snapshot command
+
+echo
+echo === Create a couple of snapshots using blockdev-snapshot ===
+echo
+
+SNAPSHOTS=$((${SNAPSHOTS}+1))
+add_snapshot_image ${SNAPSHOTS}
+blockdev_snapshot ${SNAPSHOTS}
+
+SNAPSHOTS=$((${SNAPSHOTS}+1))
+add_snapshot_image ${SNAPSHOTS}
+blockdev_snapshot ${SNAPSHOTS}
+
+echo
+echo === Invalid command - cannot create a snapshot using a file BDS ===
+echo
+
+_send_qemu_cmd $h "{ 'execute': 'blockdev-snapshot',
+ 'arguments': { 'node':'virtio0',
+ 'overlay':'file_${SNAPSHOTS}' }
+ }" "error"
+
+echo
+echo === Invalid command - snapshot node used as active layer ===
+echo
+
+blockdev_snapshot ${SNAPSHOTS} error
+
+_send_qemu_cmd $h "{ 'execute': 'blockdev-snapshot',
+ 'arguments': { 'node':'virtio0',
+ 'overlay':'virtio0' }
+ }" "error"
+
+_send_qemu_cmd $h "{ 'execute': 'blockdev-snapshot',
+ 'arguments': { 'node':'virtio0',
+ 'overlay':'virtio1' }
+ }" "error"
+
+echo
+echo === Invalid command - snapshot node used as backing hd ===
+echo
+
+blockdev_snapshot $((${SNAPSHOTS}-1)) error
+
+echo
+echo === Invalid command - snapshot node has a backing image ===
+echo
+
+SNAPSHOTS=$((${SNAPSHOTS}+1))
+add_snapshot_image ${SNAPSHOTS} true
+blockdev_snapshot ${SNAPSHOTS} error
+
+echo
+echo === Invalid command - The node does not exist ===
+echo
+
+blockdev_snapshot $((${SNAPSHOTS}+1)) error
+
+_send_qemu_cmd $h "{ 'execute': 'blockdev-snapshot',
+ 'arguments': { 'node':'nodevice',
+ 'overlay':'snap_${SNAPSHOTS}' }
+ }" "error"
+
# success, all done
echo "*** done"
rm -f $seq.full
diff --git a/tests/qemu-iotests/085.out b/tests/qemu-iotests/085.out
index 5eb8b947c..01c78d689 100644
--- a/tests/qemu-iotests/085.out
+++ b/tests/qemu-iotests/085.out
@@ -11,7 +11,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
=== Create a single snapshot on virtio0 ===
-Formatting 'TEST_DIR/1-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/t.qcow2.orig' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/1-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2.1 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
=== Invalid command - missing device and nodename ===
@@ -25,31 +25,65 @@ Formatting 'TEST_DIR/1-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file
=== Create several transactional group snapshots ===
-Formatting 'TEST_DIR/2-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/1-snapshot-v0.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
-Formatting 'TEST_DIR/2-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/t.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/2-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/1-snapshot-v0.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/2-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/t.qcow2.2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
-Formatting 'TEST_DIR/3-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/2-snapshot-v0.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
-Formatting 'TEST_DIR/3-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/2-snapshot-v1.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/3-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/2-snapshot-v0.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/3-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/2-snapshot-v1.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
-Formatting 'TEST_DIR/4-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/3-snapshot-v0.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
-Formatting 'TEST_DIR/4-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/3-snapshot-v1.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/4-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/3-snapshot-v0.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/4-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/3-snapshot-v1.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
-Formatting 'TEST_DIR/5-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/4-snapshot-v0.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
-Formatting 'TEST_DIR/5-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/4-snapshot-v1.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/5-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/4-snapshot-v0.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/5-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/4-snapshot-v1.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
-Formatting 'TEST_DIR/6-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/5-snapshot-v0.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
-Formatting 'TEST_DIR/6-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/5-snapshot-v1.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/6-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/5-snapshot-v0.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/6-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/5-snapshot-v1.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
-Formatting 'TEST_DIR/7-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/6-snapshot-v0.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
-Formatting 'TEST_DIR/7-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/6-snapshot-v1.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/7-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/6-snapshot-v0.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/7-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/6-snapshot-v1.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
-Formatting 'TEST_DIR/8-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/7-snapshot-v0.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
-Formatting 'TEST_DIR/8-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/7-snapshot-v1.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/8-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/7-snapshot-v0.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/8-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/7-snapshot-v1.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
-Formatting 'TEST_DIR/9-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/8-snapshot-v0.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
-Formatting 'TEST_DIR/9-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/8-snapshot-v1.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/9-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/8-snapshot-v0.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/9-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/8-snapshot-v1.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
-Formatting 'TEST_DIR/10-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/9-snapshot-v0.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
-Formatting 'TEST_DIR/10-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/9-snapshot-v1.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/10-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/9-snapshot-v0.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/10-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file=TEST_DIR/9-snapshot-v1.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
+
+=== Create a couple of snapshots using blockdev-snapshot ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/10-snapshot-v0.IMGFMT
+{"return": {}}
+{"return": {}}
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/11-snapshot-v0.IMGFMT
+{"return": {}}
+{"return": {}}
+
+=== Invalid command - cannot create a snapshot using a file BDS ===
+
+{"error": {"class": "GenericError", "desc": "The snapshot does not support backing images"}}
+
+=== Invalid command - snapshot node used as active layer ===
+
+{"error": {"class": "GenericError", "desc": "The snapshot is already in use by virtio0"}}
+{"error": {"class": "GenericError", "desc": "The snapshot is already in use by virtio0"}}
+{"error": {"class": "GenericError", "desc": "The snapshot is already in use by virtio1"}}
+
+=== Invalid command - snapshot node used as backing hd ===
+
+{"error": {"class": "GenericError", "desc": "Node 'snap_11' is busy: node is used as backing hd of 'virtio0'"}}
+
+=== Invalid command - snapshot node has a backing image ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/12-snapshot-v0.IMGFMT
+{"return": {}}
+{"error": {"class": "GenericError", "desc": "The snapshot already has a backing image"}}
+
+=== Invalid command - The node does not exist ===
+
+{"error": {"class": "GenericError", "desc": "Cannot find device=snap_14 nor node_name=snap_14"}}
+{"error": {"class": "GenericError", "desc": "Cannot find device=nodevice nor node_name=nodevice"}}
*** done
diff --git a/tests/qemu-iotests/087 b/tests/qemu-iotests/087
index 869474994..af44299e0 100755
--- a/tests/qemu-iotests/087
+++ b/tests/qemu-iotests/087
@@ -54,7 +54,7 @@ size=128M
_make_test_img $size
echo
-echo === Missing ID ===
+echo === Missing ID and node-name ===
echo
run_qemu <<EOF
diff --git a/tests/qemu-iotests/087.out b/tests/qemu-iotests/087.out
index c71bb3aa4..7d62cd584 100644
--- a/tests/qemu-iotests/087.out
+++ b/tests/qemu-iotests/087.out
@@ -1,16 +1,14 @@
QA output created by 087
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
-=== Missing ID ===
+=== Missing ID and node-name ===
Testing:
QMP_VERSION
{"return": {}}
-{"error": {"class": "GenericError", "desc": "Block device needs an ID"}}
+{"error": {"class": "GenericError", "desc": "'id' and/or 'node-name' need to be specified for the root node"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "floppy0", "tray-open": true}}
=== Duplicate ID ===
@@ -26,8 +24,6 @@ QMP_VERSION
{"error": {"class": "GenericError", "desc": "node-name=disk3 is conflicting with a device id"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "floppy0", "tray-open": true}}
=== aio=native without O_DIRECT ===
@@ -38,8 +34,6 @@ QMP_VERSION
{"error": {"class": "GenericError", "desc": "aio=native requires cache.direct=true"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "floppy0", "tray-open": true}}
=== Encrypted image ===
@@ -60,8 +54,6 @@ You can use 'qemu-img convert' to convert your image to an unencrypted one.
{"error": {"class": "GenericError", "desc": "blockdev-add doesn't support encrypted devices"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "floppy0", "tray-open": true}}
Testing:
QMP_VERSION
@@ -72,8 +64,6 @@ You can use 'qemu-img convert' to convert your image to an unencrypted one.
{"error": {"class": "GenericError", "desc": "Guest must be stopped for opening of encrypted image"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "floppy0", "tray-open": true}}
=== Missing driver ===
@@ -91,7 +81,5 @@ QMP_VERSION
{"error": {"class": "GenericError", "desc": "Invalid parameter type for 'driver', expected: string"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "floppy0", "tray-open": true}}
*** done
diff --git a/tests/qemu-iotests/095.out b/tests/qemu-iotests/095.out
index 267c4836e..236006162 100644
--- a/tests/qemu-iotests/095.out
+++ b/tests/qemu-iotests/095.out
@@ -1,7 +1,7 @@
QA output created by 095
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=5242880
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=104857600 backing_file='TEST_DIR/t.IMGFMT.base'
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=104857600 backing_file='TEST_DIR/t.IMGFMT.snp1'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=104857600 backing_file=TEST_DIR/t.IMGFMT.base
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=104857600 backing_file=TEST_DIR/t.IMGFMT.snp1
=== Base image info before commit and resize ===
image: TEST_DIR/t.IMGFMT.base
diff --git a/tests/qemu-iotests/096 b/tests/qemu-iotests/096
new file mode 100644
index 000000000..e34204b8f
--- /dev/null
+++ b/tests/qemu-iotests/096
@@ -0,0 +1,69 @@
+#!/usr/bin/env python
+#
+# Test that snapshots move the throttling configuration to the active
+# layer
+#
+# Copyright (C) 2015 Igalia, S.L.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+import iotests
+import os
+
+class TestLiveSnapshot(iotests.QMPTestCase):
+ base_img = os.path.join(iotests.test_dir, 'base.img')
+ target_img = os.path.join(iotests.test_dir, 'target.img')
+ group = 'mygroup'
+ iops = 6000
+ iops_size = 1024
+
+ def setUp(self):
+ opts = []
+ opts.append('node-name=base')
+ opts.append('throttling.group=%s' % self.group)
+ opts.append('throttling.iops-total=%d' % self.iops)
+ opts.append('throttling.iops-size=%d' % self.iops_size)
+ iotests.qemu_img('create', '-f', iotests.imgfmt, self.base_img, '100M')
+ self.vm = iotests.VM().add_drive(self.base_img, ','.join(opts))
+ self.vm.launch()
+
+ def tearDown(self):
+ self.vm.shutdown()
+ os.remove(self.base_img)
+ os.remove(self.target_img)
+
+ def checkConfig(self, active_layer):
+ result = self.vm.qmp('query-named-block-nodes')
+ for r in result['return']:
+ if r['node-name'] == active_layer:
+ self.assertEqual(r['group'], self.group)
+ self.assertEqual(r['iops'], self.iops)
+ self.assertEqual(r['iops_size'], self.iops_size)
+ else:
+ self.assertFalse(r.has_key('group'))
+ self.assertEqual(r['iops'], 0)
+ self.assertFalse(r.has_key('iops_size'))
+
+ def testSnapshot(self):
+ self.checkConfig('base')
+ self.vm.qmp('blockdev-snapshot-sync',
+ node_name = 'base',
+ snapshot_node_name = 'target',
+ snapshot_file = self.target_img,
+ format = iotests.imgfmt)
+ self.checkConfig('target')
+
+if __name__ == '__main__':
+ iotests.main(supported_fmts=['qcow2'])
diff --git a/tests/qemu-iotests/096.out b/tests/qemu-iotests/096.out
new file mode 100644
index 000000000..ae1213e6f
--- /dev/null
+++ b/tests/qemu-iotests/096.out
@@ -0,0 +1,5 @@
+.
+----------------------------------------------------------------------
+Ran 1 tests
+
+OK
diff --git a/tests/qemu-iotests/097.out b/tests/qemu-iotests/097.out
index 81651f496..48abd2e64 100644
--- a/tests/qemu-iotests/097.out
+++ b/tests/qemu-iotests/097.out
@@ -3,8 +3,8 @@ QA output created by 097
=== Test pass 0 ===
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
-Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=67108864 backing_file='TEST_DIR/t.IMGFMT.base'
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file='TEST_DIR/t.IMGFMT.itmd'
+Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.itmd
wrote 196608/196608 bytes at offset 0
192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 131072/131072 bytes at offset 65536
@@ -32,8 +32,8 @@ Offset Length File
=== Test pass 1 ===
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
-Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=67108864 backing_file='TEST_DIR/t.IMGFMT.base'
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file='TEST_DIR/t.IMGFMT.itmd'
+Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.itmd
wrote 196608/196608 bytes at offset 0
192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 131072/131072 bytes at offset 65536
@@ -62,8 +62,8 @@ Offset Length File
=== Test pass 2 ===
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
-Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=67108864 backing_file='TEST_DIR/t.IMGFMT.base'
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file='TEST_DIR/t.IMGFMT.itmd'
+Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.itmd
wrote 196608/196608 bytes at offset 0
192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 131072/131072 bytes at offset 65536
@@ -92,8 +92,8 @@ Offset Length File
=== Test pass 3 ===
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
-Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=67108864 backing_file='TEST_DIR/t.IMGFMT.base'
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file='TEST_DIR/t.IMGFMT.itmd'
+Formatting 'TEST_DIR/t.IMGFMT.itmd', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.itmd
wrote 196608/196608 bytes at offset 0
192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 131072/131072 bytes at offset 65536
diff --git a/tests/qemu-iotests/098.out b/tests/qemu-iotests/098.out
index e08a189b4..7634d0e8b 100644
--- a/tests/qemu-iotests/098.out
+++ b/tests/qemu-iotests/098.out
@@ -3,7 +3,7 @@ QA output created by 098
=== l1_update ===
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file='TEST_DIR/t.IMGFMT.base'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base
wrote 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
qemu-img: Could not empty blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error
@@ -12,7 +12,7 @@ No errors were found on the image.
=== empty_image_prepare ===
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file='TEST_DIR/t.IMGFMT.base'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base
wrote 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
qemu-img: Could not empty blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error
@@ -25,7 +25,7 @@ No errors were found on the image.
=== reftable_update ===
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file='TEST_DIR/t.IMGFMT.base'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base
wrote 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
qemu-img: Could not empty blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error
@@ -39,7 +39,7 @@ No errors were found on the image.
=== refblock_alloc ===
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file='TEST_DIR/t.IMGFMT.base'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base
wrote 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
qemu-img: Could not empty blkdebug:TEST_DIR/blkdebug.conf:TEST_DIR/t.IMGFMT: Input/output error
diff --git a/tests/qemu-iotests/110.out b/tests/qemu-iotests/110.out
index 152bacf41..0270980c2 100644
--- a/tests/qemu-iotests/110.out
+++ b/tests/qemu-iotests/110.out
@@ -3,7 +3,7 @@ QA output created by 110
=== Reconstructable filename ===
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file='t.IMGFMT.base'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=t.IMGFMT.base
image: TEST_DIR/t.IMGFMT
file format: IMGFMT
virtual size: 64M (67108864 bytes)
@@ -15,5 +15,5 @@ qemu-img: Cannot use relative backing file names for 'json:{"driver": "IMGFMT",
=== Backing name is always relative to the backed image ===
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file='t.IMGFMT.base'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=t.IMGFMT.base
*** done
diff --git a/tests/qemu-iotests/112.out b/tests/qemu-iotests/112.out
index 9a98633f6..8dd3df087 100644
--- a/tests/qemu-iotests/112.out
+++ b/tests/qemu-iotests/112.out
@@ -21,9 +21,9 @@ refcount bits: 16
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
refcount bits: 16
-qemu-img: TEST_DIR/t.IMGFMT: Different refcount widths than 16 bits require compatibility level 1.1 or above (use compat=1.1 or greater)
+qemu-img: TEST_DIR/t.IMGFMT: Different refcount widths than 16 bits require compatibility level 1.1 or above (use or greater)
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
-qemu-img: TEST_DIR/t.IMGFMT: Different refcount widths than 16 bits require compatibility level 1.1 or above (use compat=1.1 or greater)
+qemu-img: TEST_DIR/t.IMGFMT: Different refcount widths than 16 bits require compatibility level 1.1 or above (use or greater)
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
=== Snapshot limit on refcount_bits=1 ===
diff --git a/tests/qemu-iotests/114.out b/tests/qemu-iotests/114.out
index 6c6b21085..6a2c75056 100644
--- a/tests/qemu-iotests/114.out
+++ b/tests/qemu-iotests/114.out
@@ -1,6 +1,6 @@
QA output created by 114
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file='TEST_DIR/t.IMGFMT.base'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base
image: TEST_DIR/t.IMGFMT
file format: IMGFMT
virtual size: 64M (67108864 bytes)
diff --git a/tests/qemu-iotests/115.out b/tests/qemu-iotests/115.out
index 7b2c5e02f..dbdad17b2 100644
--- a/tests/qemu-iotests/115.out
+++ b/tests/qemu-iotests/115.out
@@ -2,7 +2,7 @@ QA output created by 115
=== Testing large refcount and L1 table ===
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=268435456 preallocation='metadata'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=268435456 preallocation=metadata
No errors were found on the image.
100.00% allocated clusters
*** done
diff --git a/tests/qemu-iotests/118 b/tests/qemu-iotests/118
new file mode 100755
index 000000000..114d0e2de
--- /dev/null
+++ b/tests/qemu-iotests/118
@@ -0,0 +1,720 @@
+#!/usr/bin/env python
+#
+# Test case for the QMP 'change' command and all other associated
+# commands
+#
+# Copyright (C) 2015 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+import os
+import stat
+import time
+import iotests
+from iotests import qemu_img
+
+old_img = os.path.join(iotests.test_dir, 'test0.img')
+new_img = os.path.join(iotests.test_dir, 'test1.img')
+
+class ChangeBaseClass(iotests.QMPTestCase):
+ has_opened = False
+ has_closed = False
+
+ def process_events(self):
+ for event in self.vm.get_qmp_events(wait=False):
+ if (event['event'] == 'DEVICE_TRAY_MOVED' and
+ event['data']['device'] == 'drive0'):
+ if event['data']['tray-open'] == False:
+ self.has_closed = True
+ else:
+ self.has_opened = True
+
+ def wait_for_open(self):
+ timeout = time.clock() + 3
+ while not self.has_opened and time.clock() < timeout:
+ self.process_events()
+ if not self.has_opened:
+ self.fail('Timeout while waiting for the tray to open')
+
+ def wait_for_close(self):
+ timeout = time.clock() + 3
+ while not self.has_closed and time.clock() < timeout:
+ self.process_events()
+ if not self.has_opened:
+ self.fail('Timeout while waiting for the tray to close')
+
+class GeneralChangeTestsBaseClass(ChangeBaseClass):
+ def test_change(self):
+ result = self.vm.qmp('change', device='drive0', target=new_img,
+ arg=iotests.imgfmt)
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_open()
+ self.wait_for_close()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+ def test_blockdev_change_medium(self):
+ result = self.vm.qmp('blockdev-change-medium', device='drive0',
+ filename=new_img,
+ format=iotests.imgfmt)
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_open()
+ self.wait_for_close()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+ def test_eject(self):
+ result = self.vm.qmp('eject', device='drive0', force=True)
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_open()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', True)
+ self.assert_qmp_absent(result, 'return[0]/inserted')
+
+ def test_tray_eject_change(self):
+ result = self.vm.qmp('eject', device='drive0', force=True)
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_open()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', True)
+ self.assert_qmp_absent(result, 'return[0]/inserted')
+
+ result = self.vm.qmp('blockdev-change-medium', device='drive0',
+ filename=new_img,
+ format=iotests.imgfmt)
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_close()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+ def test_tray_open_close(self):
+ result = self.vm.qmp('blockdev-open-tray', device='drive0', force=True)
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_open()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', True)
+ if self.was_empty == True:
+ self.assert_qmp_absent(result, 'return[0]/inserted')
+ else:
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+ result = self.vm.qmp('blockdev-close-tray', device='drive0')
+ self.assert_qmp(result, 'return', {})
+
+ if self.has_real_tray or not self.was_empty:
+ self.wait_for_close()
+
+ result = self.vm.qmp('query-block')
+ if self.has_real_tray or not self.was_empty:
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ else:
+ self.assert_qmp(result, 'return[0]/tray_open', True)
+ if self.was_empty == True:
+ self.assert_qmp_absent(result, 'return[0]/inserted')
+ else:
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+ def test_tray_eject_close(self):
+ result = self.vm.qmp('eject', device='drive0', force=True)
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_open()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', True)
+ self.assert_qmp_absent(result, 'return[0]/inserted')
+
+ result = self.vm.qmp('blockdev-close-tray', device='drive0')
+ self.assert_qmp(result, 'return', {})
+
+ if self.has_real_tray:
+ self.wait_for_close()
+
+ result = self.vm.qmp('query-block')
+ if self.has_real_tray:
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ else:
+ self.assert_qmp(result, 'return[0]/tray_open', True)
+ self.assert_qmp_absent(result, 'return[0]/inserted')
+
+ def test_tray_open_change(self):
+ result = self.vm.qmp('blockdev-open-tray', device='drive0', force=True)
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_open()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', True)
+ if self.was_empty == True:
+ self.assert_qmp_absent(result, 'return[0]/inserted')
+ else:
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+ result = self.vm.qmp('blockdev-change-medium', device='drive0',
+ filename=new_img,
+ format=iotests.imgfmt)
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_close()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+ def test_cycle(self):
+ result = self.vm.qmp('blockdev-add',
+ options={'node-name': 'new',
+ 'driver': iotests.imgfmt,
+ 'file': {'filename': new_img,
+ 'driver': 'file'}})
+ self.assert_qmp(result, 'return', {})
+
+ result = self.vm.qmp('blockdev-open-tray', device='drive0', force=True)
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_open()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', True)
+ if self.was_empty == True:
+ self.assert_qmp_absent(result, 'return[0]/inserted')
+ else:
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+ result = self.vm.qmp('x-blockdev-remove-medium', device='drive0')
+ self.assert_qmp(result, 'return', {})
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', True)
+ self.assert_qmp_absent(result, 'return[0]/inserted')
+
+ result = self.vm.qmp('x-blockdev-insert-medium', device='drive0',
+ node_name='new')
+ self.assert_qmp(result, 'return', {})
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', True)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+ result = self.vm.qmp('blockdev-close-tray', device='drive0')
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_close()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+ def test_close_on_closed(self):
+ result = self.vm.qmp('blockdev-close-tray', device='drive0')
+ # Should be a no-op
+ self.assert_qmp(result, 'return', {})
+ self.assertEquals(self.vm.get_qmp_events(wait=False), [])
+
+ def test_remove_on_closed(self):
+ if self.has_opened:
+ # Empty floppy drive
+ return
+
+ result = self.vm.qmp('x-blockdev-remove-medium', device='drive0')
+ self.assert_qmp(result, 'error/class', 'GenericError')
+
+ def test_insert_on_closed(self):
+ if self.has_opened:
+ # Empty floppy drive
+ return
+
+ result = self.vm.qmp('blockdev-add',
+ options={'node-name': 'new',
+ 'driver': iotests.imgfmt,
+ 'file': {'filename': new_img,
+ 'driver': 'file'}})
+ self.assert_qmp(result, 'return', {})
+
+ result = self.vm.qmp('x-blockdev-insert-medium', device='drive0',
+ node_name='new')
+ self.assert_qmp(result, 'error/class', 'GenericError')
+
+class TestInitiallyFilled(GeneralChangeTestsBaseClass):
+ was_empty = False
+
+ def setUp(self, media, interface):
+ qemu_img('create', '-f', iotests.imgfmt, old_img, '1440k')
+ qemu_img('create', '-f', iotests.imgfmt, new_img, '1440k')
+ self.vm = iotests.VM().add_drive(old_img, 'media=%s' % media, interface)
+ self.vm.launch()
+
+ def tearDown(self):
+ self.vm.shutdown()
+ os.remove(old_img)
+ os.remove(new_img)
+
+ def test_insert_on_filled(self):
+ result = self.vm.qmp('blockdev-add',
+ options={'node-name': 'new',
+ 'driver': iotests.imgfmt,
+ 'file': {'filename': new_img,
+ 'driver': 'file'}})
+ self.assert_qmp(result, 'return', {})
+
+ result = self.vm.qmp('blockdev-open-tray', device='drive0')
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_open()
+
+ result = self.vm.qmp('x-blockdev-insert-medium', device='drive0',
+ node_name='new')
+ self.assert_qmp(result, 'error/class', 'GenericError')
+
+class TestInitiallyEmpty(GeneralChangeTestsBaseClass):
+ was_empty = True
+
+ def setUp(self, media, interface):
+ qemu_img('create', '-f', iotests.imgfmt, new_img, '1440k')
+ self.vm = iotests.VM().add_drive(None, 'media=%s' % media, interface)
+ self.vm.launch()
+
+ def tearDown(self):
+ self.vm.shutdown()
+ os.remove(new_img)
+
+ def test_remove_on_empty(self):
+ result = self.vm.qmp('blockdev-open-tray', device='drive0')
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_open()
+
+ result = self.vm.qmp('x-blockdev-remove-medium', device='drive0')
+ # Should be a no-op
+ self.assert_qmp(result, 'return', {})
+
+class TestCDInitiallyFilled(TestInitiallyFilled):
+ TestInitiallyFilled = TestInitiallyFilled
+ has_real_tray = True
+
+ def setUp(self):
+ self.TestInitiallyFilled.setUp(self, 'cdrom', 'ide')
+
+class TestCDInitiallyEmpty(TestInitiallyEmpty):
+ TestInitiallyEmpty = TestInitiallyEmpty
+ has_real_tray = True
+
+ def setUp(self):
+ self.TestInitiallyEmpty.setUp(self, 'cdrom', 'ide')
+
+class TestFloppyInitiallyFilled(TestInitiallyFilled):
+ TestInitiallyFilled = TestInitiallyFilled
+ has_real_tray = False
+
+ def setUp(self):
+ self.TestInitiallyFilled.setUp(self, 'disk', 'floppy')
+
+class TestFloppyInitiallyEmpty(TestInitiallyEmpty):
+ TestInitiallyEmpty = TestInitiallyEmpty
+ has_real_tray = False
+
+ def setUp(self):
+ self.TestInitiallyEmpty.setUp(self, 'disk', 'floppy')
+ # FDDs not having a real tray and there not being a medium inside the
+ # tray at startup means the tray will be considered open
+ self.has_opened = True
+
+class TestChangeReadOnly(ChangeBaseClass):
+ def setUp(self):
+ qemu_img('create', '-f', iotests.imgfmt, old_img, '1440k')
+ qemu_img('create', '-f', iotests.imgfmt, new_img, '1440k')
+ self.vm = iotests.VM()
+
+ def tearDown(self):
+ self.vm.shutdown()
+ os.chmod(old_img, 0666)
+ os.chmod(new_img, 0666)
+ os.remove(old_img)
+ os.remove(new_img)
+
+ def test_ro_ro_retain(self):
+ os.chmod(old_img, 0444)
+ os.chmod(new_img, 0444)
+ self.vm.add_drive(old_img, 'media=disk,read-only=on', 'floppy')
+ self.vm.launch()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/ro', True)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+ result = self.vm.qmp('blockdev-change-medium', device='drive0',
+ filename=new_img,
+ format=iotests.imgfmt,
+ read_only_mode='retain')
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_open()
+ self.wait_for_close()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/ro', True)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+ def test_ro_rw_retain(self):
+ os.chmod(old_img, 0444)
+ self.vm.add_drive(old_img, 'media=disk,read-only=on', 'floppy')
+ self.vm.launch()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/ro', True)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+ result = self.vm.qmp('blockdev-change-medium', device='drive0',
+ filename=new_img,
+ format=iotests.imgfmt,
+ read_only_mode='retain')
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_open()
+ self.wait_for_close()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/ro', True)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+ def test_rw_ro_retain(self):
+ os.chmod(new_img, 0444)
+ self.vm.add_drive(old_img, 'media=disk', 'floppy')
+ self.vm.launch()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/ro', False)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+ result = self.vm.qmp('blockdev-change-medium', device='drive0',
+ filename=new_img,
+ format=iotests.imgfmt,
+ read_only_mode='retain')
+ self.assert_qmp(result, 'error/class', 'GenericError')
+
+ self.assertEquals(self.vm.get_qmp_events(wait=False), [])
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/ro', False)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+ def test_ro_rw(self):
+ os.chmod(old_img, 0444)
+ self.vm.add_drive(old_img, 'media=disk,read-only=on', 'floppy')
+ self.vm.launch()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/ro', True)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+ result = self.vm.qmp('blockdev-change-medium',
+ device='drive0',
+ filename=new_img,
+ format=iotests.imgfmt,
+ read_only_mode='read-write')
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_open()
+ self.wait_for_close()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/ro', False)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+ def test_rw_ro(self):
+ os.chmod(new_img, 0444)
+ self.vm.add_drive(old_img, 'media=disk', 'floppy')
+ self.vm.launch()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/ro', False)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+ result = self.vm.qmp('blockdev-change-medium',
+ device='drive0',
+ filename=new_img,
+ format=iotests.imgfmt,
+ read_only_mode='read-only')
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_open()
+ self.wait_for_close()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/ro', True)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+ def test_make_rw_ro(self):
+ self.vm.add_drive(old_img, 'media=disk', 'floppy')
+ self.vm.launch()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/ro', False)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+ result = self.vm.qmp('blockdev-change-medium',
+ device='drive0',
+ filename=new_img,
+ format=iotests.imgfmt,
+ read_only_mode='read-only')
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_open()
+ self.wait_for_close()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/ro', True)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+ def test_make_ro_rw(self):
+ os.chmod(new_img, 0444)
+ self.vm.add_drive(old_img, 'media=disk', 'floppy')
+ self.vm.launch()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/ro', False)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+ result = self.vm.qmp('blockdev-change-medium',
+ device='drive0',
+ filename=new_img,
+ format=iotests.imgfmt,
+ read_only_mode='read-write')
+ self.assert_qmp(result, 'error/class', 'GenericError')
+
+ self.assertEquals(self.vm.get_qmp_events(wait=False), [])
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/ro', False)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+ def test_make_rw_ro_by_retain(self):
+ os.chmod(old_img, 0444)
+ self.vm.add_drive(old_img, 'media=disk,read-only=on', 'floppy')
+ self.vm.launch()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/ro', True)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+ result = self.vm.qmp('blockdev-change-medium', device='drive0',
+ filename=new_img,
+ format=iotests.imgfmt,
+ read_only_mode='retain')
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_open()
+ self.wait_for_close()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/ro', True)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+ def test_make_ro_rw_by_retain(self):
+ os.chmod(new_img, 0444)
+ self.vm.add_drive(old_img, 'media=disk', 'floppy')
+ self.vm.launch()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/ro', False)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+ result = self.vm.qmp('blockdev-change-medium', device='drive0',
+ filename=new_img,
+ format=iotests.imgfmt,
+ read_only_mode='retain')
+ self.assert_qmp(result, 'error/class', 'GenericError')
+
+ self.assertEquals(self.vm.get_qmp_events(wait=False), [])
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/ro', False)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+ def test_rw_ro_cycle(self):
+ os.chmod(new_img, 0444)
+ self.vm.add_drive(old_img, 'media=disk', 'floppy')
+ self.vm.launch()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/ro', False)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+ result = self.vm.qmp('blockdev-add',
+ options={'node-name': 'new',
+ 'driver': iotests.imgfmt,
+ 'read-only': True,
+ 'file': {'filename': new_img,
+ 'driver': 'file'}})
+ self.assert_qmp(result, 'return', {})
+
+ result = self.vm.qmp('blockdev-open-tray', device='drive0', force=True)
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_open()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', True)
+ self.assert_qmp(result, 'return[0]/inserted/ro', False)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+ result = self.vm.qmp('x-blockdev-remove-medium', device='drive0')
+ self.assert_qmp(result, 'return', {})
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', True)
+ self.assert_qmp_absent(result, 'return[0]/inserted')
+
+ result = self.vm.qmp('x-blockdev-insert-medium', device='drive0',
+ node_name='new')
+ self.assert_qmp(result, 'return', {})
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', True)
+ self.assert_qmp(result, 'return[0]/inserted/ro', True)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+ result = self.vm.qmp('blockdev-close-tray', device='drive0')
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_close()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/ro', True)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+GeneralChangeTestsBaseClass = None
+TestInitiallyFilled = None
+TestInitiallyEmpty = None
+
+
+class TestBlockJobsAfterCycle(ChangeBaseClass):
+ def setUp(self):
+ qemu_img('create', '-f', iotests.imgfmt, old_img, '1M')
+
+ self.vm = iotests.VM()
+ self.vm.launch()
+
+ result = self.vm.qmp('blockdev-add',
+ options={'id': 'drive0',
+ 'driver': 'null-co'})
+ self.assert_qmp(result, 'return', {})
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/image/format', 'null-co')
+
+ # For device-less BBs, calling blockdev-open-tray or blockdev-close-tray
+ # is not necessary
+ result = self.vm.qmp('x-blockdev-remove-medium', device='drive0')
+ self.assert_qmp(result, 'return', {})
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp_absent(result, 'return[0]/inserted')
+
+ result = self.vm.qmp('blockdev-add',
+ options={'node-name': 'node0',
+ 'driver': iotests.imgfmt,
+ 'file': {'filename': old_img,
+ 'driver': 'file'}})
+ self.assert_qmp(result, 'return', {})
+
+ result = self.vm.qmp('x-blockdev-insert-medium', device='drive0',
+ node_name='node0')
+ self.assert_qmp(result, 'return', {})
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+ def tearDown(self):
+ self.vm.shutdown()
+ os.remove(old_img)
+ try:
+ os.remove(new_img)
+ except OSError:
+ pass
+
+ def test_snapshot_and_commit(self):
+ # We need backing file support
+ if iotests.imgfmt != 'qcow2' and iotests.imgfmt != 'qed':
+ return
+
+ result = self.vm.qmp('blockdev-snapshot-sync', device='drive0',
+ snapshot_file=new_img,
+ format=iotests.imgfmt)
+ self.assert_qmp(result, 'return', {})
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+ self.assert_qmp(result,
+ 'return[0]/inserted/image/backing-image/filename',
+ old_img)
+
+ result = self.vm.qmp('block-commit', device='drive0')
+ self.assert_qmp(result, 'return', {})
+
+ self.vm.event_wait(name='BLOCK_JOB_READY')
+
+ result = self.vm.qmp('query-block-jobs')
+ self.assert_qmp(result, 'return[0]/device', 'drive0')
+
+ result = self.vm.qmp('block-job-complete', device='drive0')
+ self.assert_qmp(result, 'return', {})
+
+ self.vm.event_wait(name='BLOCK_JOB_COMPLETED')
+
+
+if __name__ == '__main__':
+ if iotests.qemu_default_machine != 'pc':
+ # We need floppy and IDE CD-ROM
+ iotests.notrun('not suitable for this machine type: %s' %
+ iotests.qemu_default_machine)
+ iotests.main()
diff --git a/tests/qemu-iotests/118.out b/tests/qemu-iotests/118.out
new file mode 100644
index 000000000..6a917130b
--- /dev/null
+++ b/tests/qemu-iotests/118.out
@@ -0,0 +1,5 @@
+...........................................................
+----------------------------------------------------------------------
+Ran 59 tests
+
+OK
diff --git a/tests/qemu-iotests/119 b/tests/qemu-iotests/119
index 9a11f1b92..cc6ec0770 100755
--- a/tests/qemu-iotests/119
+++ b/tests/qemu-iotests/119
@@ -49,7 +49,7 @@ echo "{'execute': 'qmp_capabilities'}
{'execute': 'human-monitor-command',
'arguments': {'command-line': 'qemu-io drv \"read -P 0 0 64k\"'}}
{'execute': 'quit'}" \
- | $QEMU -drive id=drv,if=none,file="$TEST_IMG",driver=nbd \
+ | $QEMU -nographic -drive id=drv,if=none,file="$TEST_IMG",driver=nbd \
-qmp stdio -nodefaults \
| _filter_qmp | _filter_qemu_io
diff --git a/tests/qemu-iotests/120 b/tests/qemu-iotests/120
index 9f1307876..d899a3f52 100755
--- a/tests/qemu-iotests/120
+++ b/tests/qemu-iotests/120
@@ -49,7 +49,7 @@ echo "{'execute': 'qmp_capabilities'}
{'execute': 'human-monitor-command',
'arguments': {'command-line': 'qemu-io drv \"write -P 42 0 64k\"'}}
{'execute': 'quit'}" \
- | $QEMU -qmp stdio -nodefaults \
+ | $QEMU -qmp stdio -nographic -nodefaults \
-drive id=drv,if=none,file="$TEST_IMG",driver=raw,file.driver=$IMGFMT \
| _filter_qmp | _filter_qemu_io
$QEMU_IO -c 'read -P 42 0 64k' "$TEST_IMG" | _filter_qemu_io
diff --git a/tests/qemu-iotests/121.out b/tests/qemu-iotests/121.out
index ff18e2c61..5961a44cd 100644
--- a/tests/qemu-iotests/121.out
+++ b/tests/qemu-iotests/121.out
@@ -4,7 +4,7 @@ QA output created by 121
--- Test 1 ---
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=66060288 preallocation='metadata'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=66060288 preallocation=metadata
Image resized.
wrote 1049600/1049600 bytes at offset 65011712
1.001 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -14,7 +14,7 @@ No errors were found on the image.
--- Test 2 ---
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=66061312 preallocation='metadata'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=66061312 preallocation=metadata
Image resized.
wrote 133120/133120 bytes at offset 66060288
130 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
diff --git a/tests/qemu-iotests/122.out b/tests/qemu-iotests/122.out
index 1f853b9e9..0068e9674 100644
--- a/tests/qemu-iotests/122.out
+++ b/tests/qemu-iotests/122.out
@@ -5,7 +5,7 @@ wrote 67108864/67108864 bytes at offset 0
=== Check allocation status regression with -B ===
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file='TEST_DIR/t.IMGFMT.base'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base
wrote 3145728/3145728 bytes at offset 0
3 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
Offset Length File
@@ -14,7 +14,7 @@ Offset Length File
=== Check that zero clusters are kept in overlay ===
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file='TEST_DIR/t.IMGFMT.base'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base
wrote 3145728/3145728 bytes at offset 0
3 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
read 3145728/3145728 bytes at offset 0
@@ -125,7 +125,7 @@ read 63963136/63963136 bytes at offset 3145728
Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864
wrote 33554432/33554432 bytes at offset 0
32 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file='TEST_DIR/t.IMGFMT.base'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.base
wrote 3145728/3145728 bytes at offset 0
3 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
diff --git a/tests/qemu-iotests/124 b/tests/qemu-iotests/124
index 9ccd11809..c928f0101 100644
--- a/tests/qemu-iotests/124
+++ b/tests/qemu-iotests/124
@@ -36,6 +36,23 @@ def try_remove(img):
pass
+def transaction_action(action, **kwargs):
+ return {
+ 'type': action,
+ 'data': dict((k.replace('_', '-'), v) for k, v in kwargs.iteritems())
+ }
+
+
+def transaction_bitmap_clear(node, name, **kwargs):
+ return transaction_action('block-dirty-bitmap-clear',
+ node=node, name=name, **kwargs)
+
+
+def transaction_drive_backup(device, target, **kwargs):
+ return transaction_action('drive-backup', device=device, target=target,
+ **kwargs)
+
+
class Bitmap:
def __init__(self, name, drive):
self.name = name
@@ -122,9 +139,12 @@ class TestIncrementalBackup(iotests.QMPTestCase):
def do_qmp_backup(self, error='Input/output error', **kwargs):
res = self.vm.qmp('drive-backup', **kwargs)
self.assert_qmp(res, 'return', {})
+ return self.wait_qmp_backup(kwargs['device'], error)
+
+ def wait_qmp_backup(self, device, error='Input/output error'):
event = self.vm.event_wait(name="BLOCK_JOB_COMPLETED",
- match={'data': {'device': kwargs['device']}})
+ match={'data': {'device': device}})
self.assertNotEqual(event, None)
try:
@@ -139,6 +159,12 @@ class TestIncrementalBackup(iotests.QMPTestCase):
return False
+ def wait_qmp_backup_cancelled(self, device):
+ event = self.vm.event_wait(name='BLOCK_JOB_CANCELLED',
+ match={'data': {'device': device}})
+ self.assertNotEqual(event, None)
+
+
def create_anchor_backup(self, drive=None):
if drive is None:
drive = self.drives[-1]
@@ -264,6 +290,43 @@ class TestIncrementalBackup(iotests.QMPTestCase):
return self.do_incremental_simple(granularity=131072)
+ def test_incremental_transaction(self):
+ '''Test: Verify backups made from transactionally created bitmaps.
+
+ Create a bitmap "before" VM execution begins, then create a second
+ bitmap AFTER writes have already occurred. Use transactions to create
+ a full backup and synchronize both bitmaps to this backup.
+ Create an incremental backup through both bitmaps and verify that
+ both backups match the current drive0 image.
+ '''
+
+ drive0 = self.drives[0]
+ bitmap0 = self.add_bitmap('bitmap0', drive0)
+ self.hmp_io_writes(drive0['id'], (('0xab', 0, 512),
+ ('0xfe', '16M', '256k'),
+ ('0x64', '32736k', '64k')))
+ bitmap1 = self.add_bitmap('bitmap1', drive0)
+
+ result = self.vm.qmp('transaction', actions=[
+ transaction_bitmap_clear(bitmap0.drive['id'], bitmap0.name),
+ transaction_bitmap_clear(bitmap1.drive['id'], bitmap1.name),
+ transaction_drive_backup(drive0['id'], drive0['backup'],
+ sync='full', format=drive0['fmt'])
+ ])
+ self.assert_qmp(result, 'return', {})
+ self.wait_until_completed(drive0['id'])
+ self.files.append(drive0['backup'])
+
+ self.hmp_io_writes(drive0['id'], (('0x9a', 0, 512),
+ ('0x55', '8M', '352k'),
+ ('0x78', '15872k', '1M')))
+ # Both bitmaps should be correctly in sync.
+ self.create_incremental(bitmap0)
+ self.create_incremental(bitmap1)
+ self.vm.shutdown()
+ self.check_backups()
+
+
def test_incremental_failure(self):
'''Test: Verify backups made after a failure are correct.
@@ -321,6 +384,123 @@ class TestIncrementalBackup(iotests.QMPTestCase):
self.check_backups()
+ def test_transaction_failure(self):
+ '''Test: Verify backups made from a transaction that partially fails.
+
+ Add a second drive with its own unique pattern, and add a bitmap to each
+ drive. Use blkdebug to interfere with the backup on just one drive and
+ attempt to create a coherent incremental backup across both drives.
+
+ verify a failure in one but not both, then delete the failed stubs and
+ re-run the same transaction.
+
+ verify that both incrementals are created successfully.
+ '''
+
+ # Create a second drive, with pattern:
+ drive1 = self.add_node('drive1')
+ self.img_create(drive1['file'], drive1['fmt'])
+ io_write_patterns(drive1['file'], (('0x14', 0, 512),
+ ('0x5d', '1M', '32k'),
+ ('0xcd', '32M', '124k')))
+
+ # Create a blkdebug interface to this img as 'drive1'
+ result = self.vm.qmp('blockdev-add', options={
+ 'id': drive1['id'],
+ 'driver': drive1['fmt'],
+ 'file': {
+ 'driver': 'blkdebug',
+ 'image': {
+ 'driver': 'file',
+ 'filename': drive1['file']
+ },
+ 'set-state': [{
+ 'event': 'flush_to_disk',
+ 'state': 1,
+ 'new_state': 2
+ }],
+ 'inject-error': [{
+ 'event': 'read_aio',
+ 'errno': 5,
+ 'state': 2,
+ 'immediately': False,
+ 'once': True
+ }],
+ }
+ })
+ self.assert_qmp(result, 'return', {})
+
+ # Create bitmaps and full backups for both drives
+ drive0 = self.drives[0]
+ dr0bm0 = self.add_bitmap('bitmap0', drive0)
+ dr1bm0 = self.add_bitmap('bitmap0', drive1)
+ self.create_anchor_backup(drive0)
+ self.create_anchor_backup(drive1)
+ self.assert_no_active_block_jobs()
+ self.assertFalse(self.vm.get_qmp_events(wait=False))
+
+ # Emulate some writes
+ self.hmp_io_writes(drive0['id'], (('0xab', 0, 512),
+ ('0xfe', '16M', '256k'),
+ ('0x64', '32736k', '64k')))
+ self.hmp_io_writes(drive1['id'], (('0xba', 0, 512),
+ ('0xef', '16M', '256k'),
+ ('0x46', '32736k', '64k')))
+
+ # Create incremental backup targets
+ target0 = self.prepare_backup(dr0bm0)
+ target1 = self.prepare_backup(dr1bm0)
+
+ # Ask for a new incremental backup per-each drive,
+ # expecting drive1's backup to fail:
+ transaction = [
+ transaction_drive_backup(drive0['id'], target0, sync='incremental',
+ format=drive0['fmt'], mode='existing',
+ bitmap=dr0bm0.name),
+ transaction_drive_backup(drive1['id'], target1, sync='incremental',
+ format=drive1['fmt'], mode='existing',
+ bitmap=dr1bm0.name)
+ ]
+ result = self.vm.qmp('transaction', actions=transaction,
+ properties={'completion-mode': 'grouped'} )
+ self.assert_qmp(result, 'return', {})
+
+ # Observe that drive0's backup is cancelled and drive1 completes with
+ # an error.
+ self.wait_qmp_backup_cancelled(drive0['id'])
+ self.assertFalse(self.wait_qmp_backup(drive1['id']))
+ error = self.vm.event_wait('BLOCK_JOB_ERROR')
+ self.assert_qmp(error, 'data', {'device': drive1['id'],
+ 'action': 'report',
+ 'operation': 'read'})
+ self.assertFalse(self.vm.get_qmp_events(wait=False))
+ self.assert_no_active_block_jobs()
+
+ # Delete drive0's successful target and eliminate our record of the
+ # unsuccessful drive1 target. Then re-run the same transaction.
+ dr0bm0.del_target()
+ dr1bm0.del_target()
+ target0 = self.prepare_backup(dr0bm0)
+ target1 = self.prepare_backup(dr1bm0)
+
+ # Re-run the exact same transaction.
+ result = self.vm.qmp('transaction', actions=transaction,
+ properties={'completion-mode':'grouped'})
+ self.assert_qmp(result, 'return', {})
+
+ # Both should complete successfully this time.
+ self.assertTrue(self.wait_qmp_backup(drive0['id']))
+ self.assertTrue(self.wait_qmp_backup(drive1['id']))
+ self.make_reference_backup(dr0bm0)
+ self.make_reference_backup(dr1bm0)
+ self.assertFalse(self.vm.get_qmp_events(wait=False))
+ self.assert_no_active_block_jobs()
+
+ # And the images should of course validate.
+ self.vm.shutdown()
+ self.check_backups()
+
+
def test_sync_dirty_bitmap_missing(self):
self.assert_no_active_block_jobs()
self.files.append(self.err_img)
diff --git a/tests/qemu-iotests/124.out b/tests/qemu-iotests/124.out
index 2f7d3902f..dae404e27 100644
--- a/tests/qemu-iotests/124.out
+++ b/tests/qemu-iotests/124.out
@@ -1,5 +1,5 @@
-.......
+.........
----------------------------------------------------------------------
-Ran 7 tests
+Ran 9 tests
OK
diff --git a/tests/qemu-iotests/128 b/tests/qemu-iotests/128
index e2a0f2f89..3d8107d2a 100755
--- a/tests/qemu-iotests/128
+++ b/tests/qemu-iotests/128
@@ -31,6 +31,11 @@ status=1 # failure is the default!
devname="eiodev$$"
sudo=""
+_sudo_qemu_io_wrapper()
+{
+ (exec $sudo "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@")
+}
+
_setup_eiodev()
{
# This test should either be run as root or with passwordless sudo
@@ -76,7 +81,9 @@ TEST_IMG="/dev/mapper/$devname"
echo
echo "== reading from error device =="
# Opening image should succeed but the read operation should fail
-$sudo $QEMU_IO --format "$IMGFMT" --nocache -c "read 0 65536" "$TEST_IMG" | _filter_qemu_io
+_sudo_qemu_io_wrapper --format "$IMGFMT" --nocache \
+ -c "read 0 65536" "$TEST_IMG" \
+ | _filter_qemu_io
# success, all done
echo "*** done"
diff --git a/tests/qemu-iotests/130 b/tests/qemu-iotests/130
index bc26247e3..9209992da 100755
--- a/tests/qemu-iotests/130
+++ b/tests/qemu-iotests/130
@@ -59,8 +59,8 @@ echo
# bdrv_make_empty() involves a header update for qcow2
# Test that a backing file isn't written
-_launch_qemu -drive file="$TEST_IMG",backing.file.filename="$TEST_IMG.base"
-_send_qemu_cmd $QEMU_HANDLE "commit ide0-hd0" "(qemu)"
+_launch_qemu -drive id=testdisk,file="$TEST_IMG",backing.file.filename="$TEST_IMG.base"
+_send_qemu_cmd $QEMU_HANDLE "commit testdisk" "(qemu)"
_send_qemu_cmd $QEMU_HANDLE '' '(qemu)'
_cleanup_qemu
_img_info | _filter_img_info
@@ -68,8 +68,8 @@ _img_info | _filter_img_info
# Make sure that if there was a backing file that was just overridden on the
# command line, that backing file is retained, with the right format
_make_test_img -F raw -b "$TEST_IMG.orig" 64M
-_launch_qemu -drive file="$TEST_IMG",backing.file.filename="$TEST_IMG.base",backing.driver=$IMGFMT
-_send_qemu_cmd $QEMU_HANDLE "commit ide0-hd0" "(qemu)"
+_launch_qemu -drive id=testdisk,file="$TEST_IMG",backing.file.filename="$TEST_IMG.base",backing.driver=$IMGFMT
+_send_qemu_cmd $QEMU_HANDLE "commit testdisk" "(qemu)"
_send_qemu_cmd $QEMU_HANDLE '' '(qemu)'
_cleanup_qemu
_img_info | _filter_img_info
diff --git a/tests/qemu-iotests/130.out b/tests/qemu-iotests/130.out
index ea68b5d28..ae95b5027 100644
--- a/tests/qemu-iotests/130.out
+++ b/tests/qemu-iotests/130.out
@@ -9,14 +9,14 @@ virtual size: 64M (67108864 bytes)
=== HMP commit ===
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) ccocomcommcommicommitcommit commit icommit idcommit idecommit ide0commit ide0-commit ide0-hcommit ide0-hdcommit ide0-hd0
+(qemu) ccocomcommcommicommitcommit commit tcommit tecommit tescommit testcommit testdcommit testdicommit testdiscommit testdisk
(qemu)
image: TEST_DIR/t.IMGFMT
file format: IMGFMT
virtual size: 64M (67108864 bytes)
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file='TEST_DIR/t.IMGFMT.orig' backing_fmt='raw'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.orig backing_fmt=raw
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) ccocomcommcommicommitcommit commit icommit idcommit idecommit ide0commit ide0-commit ide0-hcommit ide0-hdcommit ide0-hd0
+(qemu) ccocomcommcommicommitcommit commit tcommit tecommit tescommit testcommit testdcommit testdicommit testdiscommit testdisk
(qemu)
image: TEST_DIR/t.IMGFMT
file format: IMGFMT
@@ -32,7 +32,7 @@ wrote 4096/4096 bytes at offset 0
image: TEST_DIR/t.IMGFMT
file format: IMGFMT
virtual size: 64M (67108864 bytes)
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file='TEST_DIR/t.IMGFMT.orig' backing_fmt='raw'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.orig backing_fmt=raw
wrote 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
image: TEST_DIR/t.IMGFMT
diff --git a/tests/qemu-iotests/136 b/tests/qemu-iotests/136
new file mode 100644
index 000000000..e8c6937fc
--- /dev/null
+++ b/tests/qemu-iotests/136
@@ -0,0 +1,349 @@
+#!/usr/bin/env python
+#
+# Tests for block device statistics
+#
+# Copyright (C) 2015 Igalia, S.L.
+# Author: Alberto Garcia <berto@igalia.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+import iotests
+import os
+
+interval_length = 10
+nsec_per_sec = 1000000000
+op_latency = nsec_per_sec / 1000 # See qtest_latency_ns in accounting.c
+bad_sector = 8192
+bad_offset = bad_sector * 512
+blkdebug_file = os.path.join(iotests.test_dir, 'blkdebug.conf')
+
+class BlockDeviceStatsTestCase(iotests.QMPTestCase):
+ test_img = "null-aio://"
+ total_rd_bytes = 0
+ total_rd_ops = 0
+ total_wr_bytes = 0
+ total_wr_ops = 0
+ total_wr_merged = 0
+ total_flush_ops = 0
+ failed_rd_ops = 0
+ failed_wr_ops = 0
+ invalid_rd_ops = 0
+ invalid_wr_ops = 0
+ wr_highest_offset = 0
+ account_invalid = False
+ account_failed = False
+
+ def blockstats(self, device):
+ result = self.vm.qmp("query-blockstats")
+ for r in result['return']:
+ if r['device'] == device:
+ return r['stats']
+ raise Exception("Device not found for blockstats: %s" % device)
+
+ def create_blkdebug_file(self):
+ file = open(blkdebug_file, 'w')
+ file.write('''
+[inject-error]
+event = "read_aio"
+errno = "5"
+sector = "%d"
+
+[inject-error]
+event = "write_aio"
+errno = "5"
+sector = "%d"
+''' % (bad_sector, bad_sector))
+ file.close()
+
+ def setUp(self):
+ drive_args = []
+ drive_args.append("stats-intervals.0=%d" % interval_length)
+ drive_args.append("stats-account-invalid=%s" %
+ (self.account_invalid and "on" or "off"))
+ drive_args.append("stats-account-failed=%s" %
+ (self.account_failed and "on" or "off"))
+ self.create_blkdebug_file()
+ self.vm = iotests.VM().add_drive('blkdebug:%s:%s ' %
+ (blkdebug_file, self.test_img),
+ ','.join(drive_args))
+ self.vm.launch()
+ # Set an initial value for the clock
+ self.vm.qtest("clock_step %d" % nsec_per_sec)
+
+ def tearDown(self):
+ self.vm.shutdown()
+ os.remove(blkdebug_file)
+
+ def accounted_ops(self, read = False, write = False, flush = False):
+ ops = 0
+ if write:
+ ops += self.total_wr_ops
+ if self.account_failed:
+ ops += self.failed_wr_ops
+ if self.account_invalid:
+ ops += self.invalid_wr_ops
+ if read:
+ ops += self.total_rd_ops
+ if self.account_failed:
+ ops += self.failed_rd_ops
+ if self.account_invalid:
+ ops += self.invalid_rd_ops
+ if flush:
+ ops += self.total_flush_ops
+ return ops
+
+ def accounted_latency(self, read = False, write = False, flush = False):
+ latency = 0
+ if write:
+ latency += self.total_wr_ops * op_latency
+ if self.account_failed:
+ latency += self.failed_wr_ops * op_latency
+ if read:
+ latency += self.total_rd_ops * op_latency
+ if self.account_failed:
+ latency += self.failed_rd_ops * op_latency
+ if flush:
+ latency += self.total_flush_ops * op_latency
+ return latency
+
+ def check_values(self):
+ stats = self.blockstats('drive0')
+
+ # Check that the totals match with what we have calculated
+ self.assertEqual(self.total_rd_bytes, stats['rd_bytes'])
+ self.assertEqual(self.total_wr_bytes, stats['wr_bytes'])
+ self.assertEqual(self.total_rd_ops, stats['rd_operations'])
+ self.assertEqual(self.total_wr_ops, stats['wr_operations'])
+ self.assertEqual(self.total_flush_ops, stats['flush_operations'])
+ self.assertEqual(self.wr_highest_offset, stats['wr_highest_offset'])
+ self.assertEqual(self.failed_rd_ops, stats['failed_rd_operations'])
+ self.assertEqual(self.failed_wr_ops, stats['failed_wr_operations'])
+ self.assertEqual(self.invalid_rd_ops, stats['invalid_rd_operations'])
+ self.assertEqual(self.invalid_wr_ops, stats['invalid_wr_operations'])
+ self.assertEqual(self.account_invalid, stats['account_invalid'])
+ self.assertEqual(self.account_failed, stats['account_failed'])
+ self.assertEqual(self.total_wr_merged, stats['wr_merged'])
+
+ # Check that there's exactly one interval with the length we defined
+ self.assertEqual(1, len(stats['timed_stats']))
+ timed_stats = stats['timed_stats'][0]
+ self.assertEqual(interval_length, timed_stats['interval_length'])
+
+ total_rd_latency = self.accounted_latency(read = True)
+ if (total_rd_latency != 0):
+ self.assertEqual(total_rd_latency, stats['rd_total_time_ns'])
+ self.assertEqual(op_latency, timed_stats['min_rd_latency_ns'])
+ self.assertEqual(op_latency, timed_stats['max_rd_latency_ns'])
+ self.assertEqual(op_latency, timed_stats['avg_rd_latency_ns'])
+ self.assertLess(0, timed_stats['avg_rd_queue_depth'])
+ else:
+ self.assertEqual(0, stats['rd_total_time_ns'])
+ self.assertEqual(0, timed_stats['min_rd_latency_ns'])
+ self.assertEqual(0, timed_stats['max_rd_latency_ns'])
+ self.assertEqual(0, timed_stats['avg_rd_latency_ns'])
+ self.assertEqual(0, timed_stats['avg_rd_queue_depth'])
+
+ # min read latency <= avg read latency <= max read latency
+ self.assertLessEqual(timed_stats['min_rd_latency_ns'],
+ timed_stats['avg_rd_latency_ns'])
+ self.assertLessEqual(timed_stats['avg_rd_latency_ns'],
+ timed_stats['max_rd_latency_ns'])
+
+ total_wr_latency = self.accounted_latency(write = True)
+ if (total_wr_latency != 0):
+ self.assertEqual(total_wr_latency, stats['wr_total_time_ns'])
+ self.assertEqual(op_latency, timed_stats['min_wr_latency_ns'])
+ self.assertEqual(op_latency, timed_stats['max_wr_latency_ns'])
+ self.assertEqual(op_latency, timed_stats['avg_wr_latency_ns'])
+ self.assertLess(0, timed_stats['avg_wr_queue_depth'])
+ else:
+ self.assertEqual(0, stats['wr_total_time_ns'])
+ self.assertEqual(0, timed_stats['min_wr_latency_ns'])
+ self.assertEqual(0, timed_stats['max_wr_latency_ns'])
+ self.assertEqual(0, timed_stats['avg_wr_latency_ns'])
+ self.assertEqual(0, timed_stats['avg_wr_queue_depth'])
+
+ # min write latency <= avg write latency <= max write latency
+ self.assertLessEqual(timed_stats['min_wr_latency_ns'],
+ timed_stats['avg_wr_latency_ns'])
+ self.assertLessEqual(timed_stats['avg_wr_latency_ns'],
+ timed_stats['max_wr_latency_ns'])
+
+ total_flush_latency = self.accounted_latency(flush = True)
+ if (total_flush_latency != 0):
+ self.assertEqual(total_flush_latency, stats['flush_total_time_ns'])
+ self.assertEqual(op_latency, timed_stats['min_flush_latency_ns'])
+ self.assertEqual(op_latency, timed_stats['max_flush_latency_ns'])
+ self.assertEqual(op_latency, timed_stats['avg_flush_latency_ns'])
+ else:
+ self.assertEqual(0, stats['flush_total_time_ns'])
+ self.assertEqual(0, timed_stats['min_flush_latency_ns'])
+ self.assertEqual(0, timed_stats['max_flush_latency_ns'])
+ self.assertEqual(0, timed_stats['avg_flush_latency_ns'])
+
+ # min flush latency <= avg flush latency <= max flush latency
+ self.assertLessEqual(timed_stats['min_flush_latency_ns'],
+ timed_stats['avg_flush_latency_ns'])
+ self.assertLessEqual(timed_stats['avg_flush_latency_ns'],
+ timed_stats['max_flush_latency_ns'])
+
+ # idle_time_ns must be > 0 if we have performed any operation
+ if (self.accounted_ops(read = True, write = True, flush = True) != 0):
+ self.assertLess(0, stats['idle_time_ns'])
+ else:
+ self.assertFalse(stats.has_key('idle_time_ns'))
+
+ # This test does not alter these, so they must be all 0
+ self.assertEqual(0, stats['rd_merged'])
+ self.assertEqual(0, stats['failed_flush_operations'])
+ self.assertEqual(0, stats['invalid_flush_operations'])
+
+ def do_test_stats(self, rd_size = 0, rd_ops = 0, wr_size = 0, wr_ops = 0,
+ flush_ops = 0, invalid_rd_ops = 0, invalid_wr_ops = 0,
+ failed_rd_ops = 0, failed_wr_ops = 0, wr_merged = 0):
+ # The 'ops' list will contain all the requested I/O operations
+ ops = []
+ for i in range(rd_ops):
+ ops.append("aio_read %d %d" % (i * rd_size, rd_size))
+
+ for i in range(wr_ops):
+ ops.append("aio_write %d %d" % (i * wr_size, wr_size))
+
+ for i in range(flush_ops):
+ ops.append("aio_flush")
+
+ highest_offset = wr_ops * wr_size
+
+ # Two types of invalid operations: unaligned length and unaligned offset
+ for i in range(invalid_rd_ops / 2):
+ ops.append("aio_read 0 511")
+
+ for i in range(invalid_rd_ops / 2, invalid_rd_ops):
+ ops.append("aio_read 13 512")
+
+ for i in range(invalid_wr_ops / 2):
+ ops.append("aio_write 0 511")
+
+ for i in range(invalid_wr_ops / 2, invalid_wr_ops):
+ ops.append("aio_write 13 512")
+
+ for i in range(failed_rd_ops):
+ ops.append("aio_read %d 512" % bad_offset)
+
+ for i in range(failed_wr_ops):
+ ops.append("aio_write %d 512" % bad_offset)
+
+ if failed_wr_ops > 0:
+ highest_offset = max(highest_offset, bad_offset + 512)
+
+ for i in range(wr_merged):
+ first = i * wr_size * 2
+ second = first + wr_size
+ ops.append("multiwrite %d %d ; %d %d" %
+ (first, wr_size, second, wr_size))
+
+ highest_offset = max(highest_offset, wr_merged * wr_size * 2)
+
+ # Now perform all operations
+ for op in ops:
+ self.vm.hmp_qemu_io("drive0", op)
+
+ # Update the expected totals
+ self.total_rd_bytes += rd_ops * rd_size
+ self.total_rd_ops += rd_ops
+ self.total_wr_bytes += wr_ops * wr_size
+ self.total_wr_ops += wr_ops
+ self.total_wr_merged += wr_merged
+ self.total_flush_ops += flush_ops
+ self.invalid_rd_ops += invalid_rd_ops
+ self.invalid_wr_ops += invalid_wr_ops
+ self.failed_rd_ops += failed_rd_ops
+ self.failed_wr_ops += failed_wr_ops
+
+ self.wr_highest_offset = max(self.wr_highest_offset, highest_offset)
+
+ # Advance the clock so idle_time_ns has a meaningful value
+ self.vm.qtest("clock_step %d" % nsec_per_sec)
+
+ # And check that the actual statistics match the expected ones
+ self.check_values()
+
+ def test_read_only(self):
+ test_values = [[512, 1],
+ [65536, 1],
+ [512, 12],
+ [65536, 12]]
+ for i in test_values:
+ self.do_test_stats(rd_size = i[0], rd_ops = i[1])
+
+ def test_write_only(self):
+ test_values = [[512, 1],
+ [65536, 1],
+ [512, 12],
+ [65536, 12]]
+ for i in test_values:
+ self.do_test_stats(wr_size = i[0], wr_ops = i[1])
+
+ def test_invalid(self):
+ self.do_test_stats(invalid_rd_ops = 7)
+ self.do_test_stats(invalid_wr_ops = 3)
+ self.do_test_stats(invalid_rd_ops = 4, invalid_wr_ops = 5)
+
+ def test_failed(self):
+ self.do_test_stats(failed_rd_ops = 8)
+ self.do_test_stats(failed_wr_ops = 6)
+ self.do_test_stats(failed_rd_ops = 5, failed_wr_ops = 12)
+
+ def test_flush(self):
+ self.do_test_stats(flush_ops = 8)
+
+ def test_merged(self):
+ for i in range(5):
+ self.do_test_stats(wr_merged = i * 3)
+
+ def test_all(self):
+ # rd_size, rd_ops, wr_size, wr_ops, flush_ops
+ # invalid_rd_ops, invalid_wr_ops,
+ # failed_rd_ops, failed_wr_ops
+ # wr_merged
+ test_values = [[512, 1, 512, 1, 1, 4, 7, 5, 2, 1],
+ [65536, 1, 2048, 12, 7, 7, 5, 2, 5, 5],
+ [32768, 9, 8192, 1, 4, 3, 2, 4, 6, 4],
+ [16384, 11, 3584, 16, 9, 8, 6, 7, 3, 4]]
+ for i in test_values:
+ self.do_test_stats(*i)
+
+ def test_no_op(self):
+ # All values must be sane before doing any I/O
+ self.check_values()
+
+
+class BlockDeviceStatsTestAccountInvalid(BlockDeviceStatsTestCase):
+ account_invalid = True
+ account_failed = False
+
+class BlockDeviceStatsTestAccountFailed(BlockDeviceStatsTestCase):
+ account_invalid = False
+ account_failed = True
+
+class BlockDeviceStatsTestAccountBoth(BlockDeviceStatsTestCase):
+ account_invalid = True
+ account_failed = True
+
+class BlockDeviceStatsTestCoroutine(BlockDeviceStatsTestCase):
+ test_img = "null-co://"
+
+if __name__ == '__main__':
+ iotests.main(supported_fmts=["raw"])
diff --git a/tests/qemu-iotests/136.out b/tests/qemu-iotests/136.out
new file mode 100644
index 000000000..0a5e9583a
--- /dev/null
+++ b/tests/qemu-iotests/136.out
@@ -0,0 +1,5 @@
+........................................
+----------------------------------------------------------------------
+Ran 40 tests
+
+OK
diff --git a/tests/qemu-iotests/137 b/tests/qemu-iotests/137
new file mode 100755
index 000000000..9a6597cf9
--- /dev/null
+++ b/tests/qemu-iotests/137
@@ -0,0 +1,145 @@
+#!/bin/bash
+#
+# Test qcow2 reopen
+#
+# Copyright (C) 2015 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner=kwolf@redhat.com
+
+seq="$(basename $0)"
+echo "QA output created by $seq"
+
+here="$PWD"
+tmp=/tmp/$$
+status=1 # failure is the default!
+
+_cleanup()
+{
+ _cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+. ./common.qemu
+
+_supported_fmt qcow2
+_supported_proto generic
+_supported_os Linux
+
+
+_make_test_img 64M
+
+echo === Try setting valid values for all options ===
+echo
+
+# Try all options and then check that all of the basic I/O operations still
+# work on this image.
+$QEMU_IO \
+ -c "reopen -o lazy-refcounts=on,pass-discard-request=on" \
+ -c "reopen -o lazy-refcounts=off,pass-discard-request=off" \
+ -c "reopen -o pass-discard-snapshot=on,pass-discard-other=on" \
+ -c "reopen -o pass-discard-snapshot=off,pass-discard-other=off" \
+ -c "reopen -o overlap-check=all" \
+ -c "reopen -o overlap-check=none" \
+ -c "reopen -o overlap-check=cached" \
+ -c "reopen -o overlap-check=constant" \
+ -c "reopen -o overlap-check.template=all" \
+ -c "reopen -o overlap-check.template=none" \
+ -c "reopen -o overlap-check.template=cached" \
+ -c "reopen -o overlap-check.template=constant" \
+ -c "reopen -o overlap-check.main-header=on" \
+ -c "reopen -o overlap-check.main-header=off" \
+ -c "reopen -o overlap-check.active-l1=on" \
+ -c "reopen -o overlap-check.active-l1=off" \
+ -c "reopen -o overlap-check.active-l2=on" \
+ -c "reopen -o overlap-check.active-l2=off" \
+ -c "reopen -o overlap-check.refcount-table=on" \
+ -c "reopen -o overlap-check.refcount-table=off" \
+ -c "reopen -o overlap-check.refcount-block=on" \
+ -c "reopen -o overlap-check.refcount-block=off" \
+ -c "reopen -o overlap-check.snapshot-table=on" \
+ -c "reopen -o overlap-check.snapshot-table=off" \
+ -c "reopen -o overlap-check.inactive-l1=on" \
+ -c "reopen -o overlap-check.inactive-l1=off" \
+ -c "reopen -o overlap-check.inactive-l2=on" \
+ -c "reopen -o overlap-check.inactive-l2=off" \
+ -c "reopen -o cache-size=1M" \
+ -c "reopen -o l2-cache-size=512k" \
+ -c "reopen -o refcount-cache-size=128k" \
+ -c "reopen -o cache-clean-interval=5" \
+ -c "reopen -o cache-clean-interval=0" \
+ -c "reopen -o cache-clean-interval=10" \
+ \
+ -c "write -P 55 0 32M" \
+ -c "read -P 55 0 32M" \
+ -c "discard 0 32M" \
+ -c "write -z 0 32M" \
+ -c "read -P 0 0 32M" \
+ \
+ "$TEST_IMG" | _filter_qemu_io
+
+
+echo
+echo === Try setting some invalid values ===
+echo
+
+$QEMU_IO \
+ -c "reopen -o lazy-refcounts=42" \
+ -c "reopen -o cache-size=1M,l2-cache-size=64k,refcount-cache-size=64k" \
+ -c "reopen -o cache-size=1M,l2-cache-size=2M" \
+ -c "reopen -o cache-size=1M,refcount-cache-size=2M" \
+ -c "reopen -o l2-cache-size=256T" \
+ -c "reopen -o refcount-cache-size=256T" \
+ -c "reopen -o overlap-check=constant,overlap-check.template=all" \
+ -c "reopen -o overlap-check=blubb" \
+ -c "reopen -o overlap-check.template=blubb" \
+ -c "reopen -o cache-clean-interval=-1" \
+ "$TEST_IMG" | _filter_qemu_io
+
+echo
+echo === Test transaction semantics ===
+echo
+
+# Whether lazy-refcounts was actually enabled can easily be tested: Check if
+# the dirty bit is set after a crash
+$QEMU_IO \
+ -c "reopen -o lazy-refcounts=on,overlap-check=blubb" \
+ -c "write -P 0x5a 0 512" \
+ -c "sigraise $(kill -l KILL)" \
+ "$TEST_IMG" 2>&1 | _filter_qemu_io
+
+# The dirty bit must not be set
+$PYTHON qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
+
+# Similarly we can test whether corruption detection has been enabled:
+# Create L1/L2, overwrite first entry in refcount block, allocate something.
+# Disabling the checks should fail, so the corruption must be detected.
+_make_test_img 64M
+$QEMU_IO -c "write 0 64k" "$TEST_IMG" | _filter_qemu_io
+poke_file "$TEST_IMG" "$((0x20000))" "\x00\x00"
+$QEMU_IO \
+ -c "reopen -o overlap-check=none,lazy-refcounts=42" \
+ -c "write 64k 64k" \
+ "$TEST_IMG" 2>&1 | _filter_qemu_io
+
+# success, all done
+echo '*** done'
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/137.out b/tests/qemu-iotests/137.out
new file mode 100644
index 000000000..88c702cf7
--- /dev/null
+++ b/tests/qemu-iotests/137.out
@@ -0,0 +1,46 @@
+QA output created by 137
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+=== Try setting valid values for all options ===
+
+wrote 33554432/33554432 bytes at offset 0
+32 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 33554432/33554432 bytes at offset 0
+32 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+discard 33554432/33554432 bytes at offset 0
+32 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 33554432/33554432 bytes at offset 0
+32 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 33554432/33554432 bytes at offset 0
+32 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+=== Try setting some invalid values ===
+
+Parameter 'lazy-refcounts' expects 'on' or 'off'
+cache-size, l2-cache-size and refcount-cache-size may not be set the same time
+l2-cache-size may not exceed cache-size
+refcount-cache-size may not exceed cache-size
+L2 cache size too big
+L2 cache size too big
+Conflicting values for qcow2 options 'overlap-check' ('constant') and 'overlap-check.template' ('all')
+Unsupported value 'blubb' for qcow2 option 'overlap-check'. Allowed are any of the following: none, constant, cached, all
+Unsupported value 'blubb' for qcow2 option 'overlap-check'. Allowed are any of the following: none, constant, cached, all
+Cache clean interval too big
+
+=== Test transaction semantics ===
+
+Unsupported value 'blubb' for qcow2 option 'overlap-check'. Allowed are any of the following: none, constant, cached, all
+wrote 512/512 bytes at offset 0
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+./common.config: Killed ( if [ "${VALGRIND_QEMU}" == "y" ]; then
+ exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@";
+else
+ exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@";
+fi )
+incompatible_features 0x0
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+wrote 65536/65536 bytes at offset 0
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Parameter 'lazy-refcounts' expects 'on' or 'off'
+qcow2: Marking image as corrupt: Preventing invalid write on metadata (overlaps with qcow2_header); further corruption events will be suppressed
+write failed: Input/output error
+*** done
diff --git a/tests/qemu-iotests/138 b/tests/qemu-iotests/138
new file mode 100755
index 000000000..a5c3464d5
--- /dev/null
+++ b/tests/qemu-iotests/138
@@ -0,0 +1,73 @@
+#!/bin/bash
+#
+# General test case for qcow2's image check
+#
+# Copyright (C) 2015 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner=mreitz@redhat.com
+
+seq="$(basename $0)"
+echo "QA output created by $seq"
+
+here="$PWD"
+tmp=/tmp/$$
+status=1 # failure is the default!
+
+_cleanup()
+{
+ _cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+# This tests qocw2-specific low-level functionality
+_supported_fmt qcow2
+_supported_proto file
+_supported_os Linux
+
+echo
+echo '=== Check on an image with a multiple of 2^32 clusters ==='
+echo
+
+IMGOPTS=$(_optstr_add "$IMGOPTS" "cluster_size=512") \
+ _make_test_img 512
+
+# Allocate L2 table
+$QEMU_IO -c 'write 0 512' "$TEST_IMG" | _filter_qemu_io
+
+# Put the data cluster at a multiple of 2 TB, resulting in the image apparently
+# having a multiple of 2^32 clusters
+# (To be more specific: It is at 32 PB)
+poke_file "$TEST_IMG" 2048 "\x80\x80\x00\x00\x00\x00\x00\x00"
+
+# An offset of 32 PB results in qemu-img check having to allocate an in-memory
+# refcount table of 128 TB (16 bit refcounts, 512 byte clusters).
+# This should be generally too much for any system and thus fail.
+# What this test is checking is that the qcow2 driver actually tries to allocate
+# such a large amount of memory (and is consequently aborting) instead of having
+# truncated the cluster count somewhere (which would result in much less memory
+# being allocated and then a segfault occurring).
+_check_test_img
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/138.out b/tests/qemu-iotests/138.out
new file mode 100644
index 000000000..3fe911f85
--- /dev/null
+++ b/tests/qemu-iotests/138.out
@@ -0,0 +1,9 @@
+QA output created by 138
+
+=== Check on an image with a multiple of 2^32 clusters ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=512
+wrote 512/512 bytes at offset 0
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-img: Check failed: Cannot allocate memory
+*** done
diff --git a/tests/qemu-iotests/139 b/tests/qemu-iotests/139
new file mode 100644
index 000000000..a4b969499
--- /dev/null
+++ b/tests/qemu-iotests/139
@@ -0,0 +1,416 @@
+#!/usr/bin/env python
+#
+# Test cases for the QMP 'x-blockdev-del' command
+#
+# Copyright (C) 2015 Igalia, S.L.
+# Author: Alberto Garcia <berto@igalia.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+import os
+import iotests
+import time
+
+base_img = os.path.join(iotests.test_dir, 'base.img')
+new_img = os.path.join(iotests.test_dir, 'new.img')
+
+class TestBlockdevDel(iotests.QMPTestCase):
+
+ def setUp(self):
+ iotests.qemu_img('create', '-f', iotests.imgfmt, base_img, '1M')
+ self.vm = iotests.VM()
+ self.vm.launch()
+
+ def tearDown(self):
+ self.vm.shutdown()
+ os.remove(base_img)
+ if os.path.isfile(new_img):
+ os.remove(new_img)
+
+ # Check whether a BlockBackend exists
+ def checkBlockBackend(self, backend, node, must_exist = True):
+ result = self.vm.qmp('query-block')
+ backends = filter(lambda x: x['device'] == backend, result['return'])
+ self.assertLessEqual(len(backends), 1)
+ self.assertEqual(must_exist, len(backends) == 1)
+ if must_exist:
+ if node:
+ self.assertEqual(backends[0]['inserted']['node-name'], node)
+ else:
+ self.assertFalse(backends[0].has_key('inserted'))
+
+ # Check whether a BlockDriverState exists
+ def checkBlockDriverState(self, node, must_exist = True):
+ result = self.vm.qmp('query-named-block-nodes')
+ nodes = filter(lambda x: x['node-name'] == node, result['return'])
+ self.assertLessEqual(len(nodes), 1)
+ self.assertEqual(must_exist, len(nodes) == 1)
+
+ # Add a new BlockBackend (with its attached BlockDriverState)
+ def addBlockBackend(self, backend, node):
+ file_node = '%s_file' % node
+ self.checkBlockBackend(backend, node, False)
+ self.checkBlockDriverState(node, False)
+ self.checkBlockDriverState(file_node, False)
+ opts = {'driver': iotests.imgfmt,
+ 'id': backend,
+ 'node-name': node,
+ 'file': {'driver': 'file',
+ 'node-name': file_node,
+ 'filename': base_img}}
+ result = self.vm.qmp('blockdev-add', conv_keys = False, options = opts)
+ self.assert_qmp(result, 'return', {})
+ self.checkBlockBackend(backend, node)
+ self.checkBlockDriverState(node)
+ self.checkBlockDriverState(file_node)
+
+ # Add a BlockDriverState without a BlockBackend
+ def addBlockDriverState(self, node):
+ file_node = '%s_file' % node
+ self.checkBlockDriverState(node, False)
+ self.checkBlockDriverState(file_node, False)
+ opts = {'driver': iotests.imgfmt,
+ 'node-name': node,
+ 'file': {'driver': 'file',
+ 'node-name': file_node,
+ 'filename': base_img}}
+ result = self.vm.qmp('blockdev-add', conv_keys = False, options = opts)
+ self.assert_qmp(result, 'return', {})
+ self.checkBlockDriverState(node)
+ self.checkBlockDriverState(file_node)
+
+ # Add a BlockDriverState that will be used as overlay for the base_img BDS
+ def addBlockDriverStateOverlay(self, node):
+ self.checkBlockDriverState(node, False)
+ iotests.qemu_img('create', '-f', iotests.imgfmt,
+ '-b', base_img, new_img, '1M')
+ opts = {'driver': iotests.imgfmt,
+ 'node-name': node,
+ 'backing': '',
+ 'file': {'driver': 'file',
+ 'filename': new_img}}
+ result = self.vm.qmp('blockdev-add', conv_keys = False, options = opts)
+ self.assert_qmp(result, 'return', {})
+ self.checkBlockDriverState(node)
+
+ # Delete a BlockBackend
+ def delBlockBackend(self, backend, node, expect_error = False,
+ destroys_media = True):
+ self.checkBlockBackend(backend, node)
+ if node:
+ self.checkBlockDriverState(node)
+ result = self.vm.qmp('x-blockdev-del', id = backend)
+ if expect_error:
+ self.assert_qmp(result, 'error/class', 'GenericError')
+ if node:
+ self.checkBlockDriverState(node)
+ else:
+ self.assert_qmp(result, 'return', {})
+ if node:
+ self.checkBlockDriverState(node, not destroys_media)
+ self.checkBlockBackend(backend, node, must_exist = expect_error)
+
+ # Delete a BlockDriverState
+ def delBlockDriverState(self, node, expect_error = False):
+ self.checkBlockDriverState(node)
+ result = self.vm.qmp('x-blockdev-del', node_name = node)
+ if expect_error:
+ self.assert_qmp(result, 'error/class', 'GenericError')
+ else:
+ self.assert_qmp(result, 'return', {})
+ self.checkBlockDriverState(node, expect_error)
+
+ # Add a device model
+ def addDeviceModel(self, device, backend):
+ result = self.vm.qmp('device_add', id = device,
+ driver = 'virtio-blk-pci', drive = backend)
+ self.assert_qmp(result, 'return', {})
+
+ # Delete a device model
+ def delDeviceModel(self, device):
+ result = self.vm.qmp('device_del', id = device)
+ self.assert_qmp(result, 'return', {})
+
+ result = self.vm.qmp('system_reset')
+ self.assert_qmp(result, 'return', {})
+
+ device_path = '/machine/peripheral/%s/virtio-backend' % device
+ event = self.vm.event_wait(name="DEVICE_DELETED",
+ match={'data': {'path': device_path}})
+ self.assertNotEqual(event, None)
+
+ event = self.vm.event_wait(name="DEVICE_DELETED",
+ match={'data': {'device': device}})
+ self.assertNotEqual(event, None)
+
+ # Remove a BlockDriverState
+ def ejectDrive(self, backend, node, expect_error = False,
+ destroys_media = True):
+ self.checkBlockBackend(backend, node)
+ self.checkBlockDriverState(node)
+ result = self.vm.qmp('eject', device = backend)
+ if expect_error:
+ self.assert_qmp(result, 'error/class', 'GenericError')
+ self.checkBlockDriverState(node)
+ self.checkBlockBackend(backend, node)
+ else:
+ self.assert_qmp(result, 'return', {})
+ self.checkBlockDriverState(node, not destroys_media)
+ self.checkBlockBackend(backend, None)
+
+ # Insert a BlockDriverState
+ def insertDrive(self, backend, node):
+ self.checkBlockBackend(backend, None)
+ self.checkBlockDriverState(node)
+ result = self.vm.qmp('x-blockdev-insert-medium',
+ device = backend, node_name = node)
+ self.assert_qmp(result, 'return', {})
+ self.checkBlockBackend(backend, node)
+ self.checkBlockDriverState(node)
+
+ # Create a snapshot using 'blockdev-snapshot-sync'
+ def createSnapshotSync(self, node, overlay):
+ self.checkBlockDriverState(node)
+ self.checkBlockDriverState(overlay, False)
+ opts = {'node-name': node,
+ 'snapshot-file': new_img,
+ 'snapshot-node-name': overlay,
+ 'format': iotests.imgfmt}
+ result = self.vm.qmp('blockdev-snapshot-sync', conv_keys=False, **opts)
+ self.assert_qmp(result, 'return', {})
+ self.checkBlockDriverState(node)
+ self.checkBlockDriverState(overlay)
+
+ # Create a snapshot using 'blockdev-snapshot'
+ def createSnapshot(self, node, overlay):
+ self.checkBlockDriverState(node)
+ self.checkBlockDriverState(overlay)
+ result = self.vm.qmp('blockdev-snapshot',
+ node = node, overlay = overlay)
+ self.assert_qmp(result, 'return', {})
+ self.checkBlockDriverState(node)
+ self.checkBlockDriverState(overlay)
+
+ # Create a mirror
+ def createMirror(self, backend, node, new_node):
+ self.checkBlockBackend(backend, node)
+ self.checkBlockDriverState(new_node, False)
+ opts = {'device': backend,
+ 'target': new_img,
+ 'node-name': new_node,
+ 'sync': 'top',
+ 'format': iotests.imgfmt}
+ result = self.vm.qmp('drive-mirror', conv_keys=False, **opts)
+ self.assert_qmp(result, 'return', {})
+ self.checkBlockBackend(backend, node)
+ self.checkBlockDriverState(new_node)
+
+ # Complete an existing block job
+ def completeBlockJob(self, backend, node_before, node_after):
+ self.checkBlockBackend(backend, node_before)
+ result = self.vm.qmp('block-job-complete', device=backend)
+ self.assert_qmp(result, 'return', {})
+ self.wait_until_completed(backend)
+ self.checkBlockBackend(backend, node_after)
+
+ # Add a BlkDebug node
+ # Note that the purpose of this is to test the x-blockdev-del
+ # sanity checks, not to create a usable blkdebug drive
+ def addBlkDebug(self, debug, node):
+ self.checkBlockDriverState(node, False)
+ self.checkBlockDriverState(debug, False)
+ image = {'driver': iotests.imgfmt,
+ 'node-name': node,
+ 'file': {'driver': 'file',
+ 'filename': base_img}}
+ opts = {'driver': 'blkdebug',
+ 'node-name': debug,
+ 'image': image}
+ result = self.vm.qmp('blockdev-add', conv_keys = False, options = opts)
+ self.assert_qmp(result, 'return', {})
+ self.checkBlockDriverState(node)
+ self.checkBlockDriverState(debug)
+
+ # Add a BlkVerify node
+ # Note that the purpose of this is to test the x-blockdev-del
+ # sanity checks, not to create a usable blkverify drive
+ def addBlkVerify(self, blkverify, test, raw):
+ self.checkBlockDriverState(test, False)
+ self.checkBlockDriverState(raw, False)
+ self.checkBlockDriverState(blkverify, False)
+ iotests.qemu_img('create', '-f', iotests.imgfmt, new_img, '1M')
+ node_0 = {'driver': iotests.imgfmt,
+ 'node-name': test,
+ 'file': {'driver': 'file',
+ 'filename': base_img}}
+ node_1 = {'driver': iotests.imgfmt,
+ 'node-name': raw,
+ 'file': {'driver': 'file',
+ 'filename': new_img}}
+ opts = {'driver': 'blkverify',
+ 'node-name': blkverify,
+ 'test': node_0,
+ 'raw': node_1}
+ result = self.vm.qmp('blockdev-add', conv_keys = False, options = opts)
+ self.assert_qmp(result, 'return', {})
+ self.checkBlockDriverState(test)
+ self.checkBlockDriverState(raw)
+ self.checkBlockDriverState(blkverify)
+
+ # Add a Quorum node
+ def addQuorum(self, quorum, child0, child1):
+ self.checkBlockDriverState(child0, False)
+ self.checkBlockDriverState(child1, False)
+ self.checkBlockDriverState(quorum, False)
+ iotests.qemu_img('create', '-f', iotests.imgfmt, new_img, '1M')
+ child_0 = {'driver': iotests.imgfmt,
+ 'node-name': child0,
+ 'file': {'driver': 'file',
+ 'filename': base_img}}
+ child_1 = {'driver': iotests.imgfmt,
+ 'node-name': child1,
+ 'file': {'driver': 'file',
+ 'filename': new_img}}
+ opts = {'driver': 'quorum',
+ 'node-name': quorum,
+ 'vote-threshold': 1,
+ 'children': [ child_0, child_1 ]}
+ result = self.vm.qmp('blockdev-add', conv_keys = False, options = opts)
+ self.assert_qmp(result, 'return', {})
+ self.checkBlockDriverState(child0)
+ self.checkBlockDriverState(child1)
+ self.checkBlockDriverState(quorum)
+
+ ########################
+ # The tests start here #
+ ########################
+
+ def testWrongParameters(self):
+ self.addBlockBackend('drive0', 'node0')
+ result = self.vm.qmp('x-blockdev-del')
+ self.assert_qmp(result, 'error/class', 'GenericError')
+ result = self.vm.qmp('x-blockdev-del', id='drive0', node_name='node0')
+ self.assert_qmp(result, 'error/class', 'GenericError')
+ self.delBlockBackend('drive0', 'node0')
+
+ def testBlockBackend(self):
+ self.addBlockBackend('drive0', 'node0')
+ # You cannot delete a BDS that is attached to a backend
+ self.delBlockDriverState('node0', expect_error = True)
+ self.delBlockBackend('drive0', 'node0')
+
+ def testBlockDriverState(self):
+ self.addBlockDriverState('node0')
+ # You cannot delete a file BDS directly
+ self.delBlockDriverState('node0_file', expect_error = True)
+ self.delBlockDriverState('node0')
+
+ def testEject(self):
+ self.addBlockBackend('drive0', 'node0')
+ self.ejectDrive('drive0', 'node0')
+ self.delBlockBackend('drive0', None)
+
+ def testDeviceModel(self):
+ self.addBlockBackend('drive0', 'node0')
+ self.addDeviceModel('device0', 'drive0')
+ self.ejectDrive('drive0', 'node0', expect_error = True)
+ self.delBlockBackend('drive0', 'node0', expect_error = True)
+ self.delDeviceModel('device0')
+ self.delBlockBackend('drive0', 'node0')
+
+ def testAttachMedia(self):
+ # This creates a BlockBackend and removes its media
+ self.addBlockBackend('drive0', 'node0')
+ self.ejectDrive('drive0', 'node0')
+ # This creates a new BlockDriverState and inserts it into the backend
+ self.addBlockDriverState('node1')
+ self.insertDrive('drive0', 'node1')
+ # The backend can't be removed: the new BDS has an extra reference
+ self.delBlockBackend('drive0', 'node1', expect_error = True)
+ self.delBlockDriverState('node1', expect_error = True)
+ # The BDS still exists after being ejected, but now it can be removed
+ self.ejectDrive('drive0', 'node1', destroys_media = False)
+ self.delBlockDriverState('node1')
+ self.delBlockBackend('drive0', None)
+
+ def testSnapshotSync(self):
+ self.addBlockBackend('drive0', 'node0')
+ self.createSnapshotSync('node0', 'overlay0')
+ # This fails because node0 is now being used as a backing image
+ self.delBlockDriverState('node0', expect_error = True)
+ # This succeeds because overlay0 only has the backend reference
+ self.delBlockBackend('drive0', 'overlay0')
+ self.checkBlockDriverState('node0', False)
+
+ def testSnapshot(self):
+ self.addBlockBackend('drive0', 'node0')
+ self.addBlockDriverStateOverlay('overlay0')
+ self.createSnapshot('node0', 'overlay0')
+ self.delBlockBackend('drive0', 'overlay0', expect_error = True)
+ self.delBlockDriverState('node0', expect_error = True)
+ self.delBlockDriverState('overlay0', expect_error = True)
+ self.ejectDrive('drive0', 'overlay0', destroys_media = False)
+ self.delBlockBackend('drive0', None)
+ self.delBlockDriverState('node0', expect_error = True)
+ self.delBlockDriverState('overlay0')
+ self.checkBlockDriverState('node0', False)
+
+ def testMirror(self):
+ self.addBlockBackend('drive0', 'node0')
+ self.createMirror('drive0', 'node0', 'mirror0')
+ # The block job prevents removing the device
+ self.delBlockBackend('drive0', 'node0', expect_error = True)
+ self.delBlockDriverState('node0', expect_error = True)
+ self.delBlockDriverState('mirror0', expect_error = True)
+ self.wait_ready('drive0')
+ self.completeBlockJob('drive0', 'node0', 'mirror0')
+ self.assert_no_active_block_jobs()
+ self.checkBlockDriverState('node0', False)
+ # This succeeds because the backend now points to mirror0
+ self.delBlockBackend('drive0', 'mirror0')
+
+ def testBlkDebug(self):
+ self.addBlkDebug('debug0', 'node0')
+ # 'node0' is used by the blkdebug node
+ self.delBlockDriverState('node0', expect_error = True)
+ # But we can remove the blkdebug node directly
+ self.delBlockDriverState('debug0')
+ self.checkBlockDriverState('node0', False)
+
+ def testBlkVerify(self):
+ self.addBlkVerify('verify0', 'node0', 'node1')
+ # We cannot remove the children of a blkverify device
+ self.delBlockDriverState('node0', expect_error = True)
+ self.delBlockDriverState('node1', expect_error = True)
+ # But we can remove the blkverify node directly
+ self.delBlockDriverState('verify0')
+ self.checkBlockDriverState('node0', False)
+ self.checkBlockDriverState('node1', False)
+
+ def testQuorum(self):
+ if not 'quorum' in iotests.qemu_img_pipe('--help'):
+ return
+ self.addQuorum('quorum0', 'node0', 'node1')
+ # We cannot remove the children of a Quorum device
+ self.delBlockDriverState('node0', expect_error = True)
+ self.delBlockDriverState('node1', expect_error = True)
+ # But we can remove the Quorum node directly
+ self.delBlockDriverState('quorum0')
+ self.checkBlockDriverState('node0', False)
+ self.checkBlockDriverState('node1', False)
+
+
+if __name__ == '__main__':
+ iotests.main(supported_fmts=["qcow2"])
diff --git a/tests/qemu-iotests/139.out b/tests/qemu-iotests/139.out
new file mode 100644
index 000000000..281b69efe
--- /dev/null
+++ b/tests/qemu-iotests/139.out
@@ -0,0 +1,5 @@
+............
+----------------------------------------------------------------------
+Ran 12 tests
+
+OK
diff --git a/tests/qemu-iotests/144 b/tests/qemu-iotests/144
new file mode 100755
index 000000000..00de3c33c
--- /dev/null
+++ b/tests/qemu-iotests/144
@@ -0,0 +1,114 @@
+#!/bin/bash
+# Check live snapshot, followed by active commit, and another snapshot.
+#
+# This test is to catch the error case of BZ #1300209:
+# https://bugzilla.redhat.com/show_bug.cgi?id=1300209
+#
+# Copyright (C) 2016 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner=jcody@redhat.com
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+status=1 # failure is the default!
+
+TMP_SNAP1=${TEST_DIR}/tmp.qcow2
+TMP_SNAP2=${TEST_DIR}/tmp2.qcow2
+
+_cleanup()
+{
+ _cleanup_qemu
+ rm -f "${TEST_IMG}" "${TMP_SNAP1}" "${TMP_SNAP2}"
+}
+
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+. ./common.qemu
+
+_supported_fmt qcow2
+_supported_proto file
+_supported_os Linux
+
+size=512M
+
+_make_test_img $size
+
+echo
+echo === Launching QEMU ===
+echo
+
+qemu_comm_method="qmp"
+_launch_qemu -drive file="${TEST_IMG}",if=virtio
+h=$QEMU_HANDLE
+
+
+echo
+echo === Performing Live Snapshot 1 ===
+echo
+
+_send_qemu_cmd $h "{ 'execute': 'qmp_capabilities' }" "return"
+
+
+# First live snapshot, new overlay as active layer
+_send_qemu_cmd $h "{ 'execute': 'blockdev-snapshot-sync',
+ 'arguments': {
+ 'device': 'virtio0',
+ 'snapshot-file':'${TMP_SNAP1}',
+ 'format': 'qcow2'
+ }
+ }" "return"
+
+echo
+echo === Performing block-commit on active layer ===
+echo
+
+# Block commit on active layer, push the new overlay into base
+_send_qemu_cmd $h "{ 'execute': 'block-commit',
+ 'arguments': {
+ 'device': 'virtio0'
+ }
+ }" "READY"
+
+_send_qemu_cmd $h "{ 'execute': 'block-job-complete',
+ 'arguments': {
+ 'device': 'virtio0'
+ }
+ }" "COMPLETED"
+
+echo
+echo === Performing Live Snapshot 2 ===
+echo
+
+# New live snapshot, new overlays as active layer
+_send_qemu_cmd $h "{ 'execute': 'blockdev-snapshot-sync',
+ 'arguments': {
+ 'device': 'virtio0',
+ 'snapshot-file':'${TMP_SNAP2}',
+ 'format': 'qcow2'
+ }
+ }" "return"
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/144.out b/tests/qemu-iotests/144.out
new file mode 100644
index 000000000..410d74180
--- /dev/null
+++ b/tests/qemu-iotests/144.out
@@ -0,0 +1,24 @@
+QA output created by 144
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=536870912
+
+=== Launching QEMU ===
+
+
+=== Performing Live Snapshot 1 ===
+
+{"return": {}}
+Formatting 'TEST_DIR/tmp.qcow2', fmt=qcow2 size=536870912 backing_file=TEST_DIR/t.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+{"return": {}}
+
+=== Performing block-commit on active layer ===
+
+{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "virtio0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}}
+{"return": {}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "virtio0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}}
+
+=== Performing Live Snapshot 2 ===
+
+Formatting 'TEST_DIR/tmp2.qcow2', fmt=qcow2 size=536870912 backing_file=TEST_DIR/t.qcow2 backing_fmt=qcow2 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+{"return": {}}
+*** done
diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check
index 1fa63193b..c350f16b6 100755
--- a/tests/qemu-iotests/check
+++ b/tests/qemu-iotests/check
@@ -231,10 +231,10 @@ FULL_HOST_DETAILS=`_full_platform_details`
#FULL_MOUNT_OPTIONS=`_scratch_mount_options`
cat <<EOF
-QEMU -- $QEMU
-QEMU_IMG -- $QEMU_IMG
-QEMU_IO -- $QEMU_IO
-QEMU_NBD -- $QEMU_NBD
+QEMU -- "$QEMU_PROG" $QEMU_OPTIONS
+QEMU_IMG -- "$QEMU_IMG_PROG" $QEMU_IMG_OPTIONS
+QEMU_IO -- "$QEMU_IO_PROG" $QEMU_IO_OPTIONS
+QEMU_NBD -- "$QEMU_NBD_PROG" $QEMU_NBD_OPTIONS
IMGFMT -- $FULL_IMGFMT_DETAILS
IMGPROTO -- $FULL_IMGPROTO_DETAILS
PLATFORM -- $FULL_HOST_DETAILS
@@ -330,6 +330,11 @@ do
fi
reference="$source_iotests/$seq.out"
+ reference_machine="$source_iotests/$seq.$QEMU_DEFAULT_MACHINE.out"
+ if [ -f "$reference_machine" ]; then
+ reference="$reference_machine"
+ fi
+
if [ "$CACHEMODE" = "none" ]; then
[ -f "$source_iotests/$seq.out.nocache" ] && reference="$source_iotests/$seq.out.nocache"
fi
diff --git a/tests/qemu-iotests/common b/tests/qemu-iotests/common
index 1030aaf25..ff84f4b0d 100644
--- a/tests/qemu-iotests/common
+++ b/tests/qemu-iotests/common
@@ -41,7 +41,6 @@ sortme=false
expunge=true
have_test_arg=false
randomize=false
-valgrind=false
cachemode=false
rm -f $tmp.list $tmp.tmp $tmp.sed
@@ -52,6 +51,8 @@ export IMGOPTS=""
export CACHEMODE="writeback"
export QEMU_IO_OPTIONS=""
export CACHEMODE_IS_DEFAULT=true
+export QEMU_OPTIONS="-nodefaults"
+export VALGRIND_QEMU=
for r
do
@@ -277,7 +278,7 @@ testlist options
;;
-valgrind)
- valgrind=true
+ VALGRIND_QEMU='y'
xpand=false
;;
@@ -435,8 +436,3 @@ fi
if [ "$IMGPROTO" = "nbd" ] ; then
[ "$QEMU_NBD" = "" ] && _fatal "qemu-nbd not found"
fi
-
-if $valgrind; then
- export REAL_QEMU_IO="$QEMU_IO_PROG"
- export QEMU_IO_PROG=valgrind_qemu_io
-fi
diff --git a/tests/qemu-iotests/common.config b/tests/qemu-iotests/common.config
index a1973ad9d..3ed51b8ba 100644
--- a/tests/qemu-iotests/common.config
+++ b/tests/qemu-iotests/common.config
@@ -44,6 +44,8 @@ export HOST_OPTIONS=${HOST_OPTIONS:=local.config}
export CHECK_OPTIONS=${CHECK_OPTIONS:="-g auto"}
export PWD=`pwd`
+export _QEMU_HANDLE=0
+
# $1 = prog to look for, $2* = default pathnames if not found in $PATH
set_prog_path()
{
@@ -103,10 +105,64 @@ if [ -z "$QEMU_NBD_PROG" ]; then
export QEMU_NBD_PROG="`set_prog_path qemu-nbd`"
fi
-export QEMU=$QEMU_PROG
-export QEMU_IMG=$QEMU_IMG_PROG
-export QEMU_IO="$QEMU_IO_PROG $QEMU_IO_OPTIONS"
-export QEMU_NBD=$QEMU_NBD_PROG
+_qemu_wrapper()
+{
+ (
+ if [ -n "${QEMU_NEED_PID}" ]; then
+ echo $BASHPID > "${TEST_DIR}/qemu-${_QEMU_HANDLE}.pid"
+ fi
+ exec "$QEMU_PROG" $QEMU_OPTIONS "$@"
+ )
+}
+
+_qemu_img_wrapper()
+{
+ (exec "$QEMU_IMG_PROG" $QEMU_IMG_OPTIONS "$@")
+}
+
+_qemu_io_wrapper()
+{
+ local VALGRIND_LOGFILE=/tmp/$$.valgrind
+ local RETVAL
+ (
+ if [ "${VALGRIND_QEMU}" == "y" ]; then
+ exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@"
+ else
+ exec "$QEMU_IO_PROG" $QEMU_IO_OPTIONS "$@"
+ fi
+ )
+ RETVAL=$?
+ if [ "${VALGRIND_QEMU}" == "y" ]; then
+ if [ $RETVAL == 99 ]; then
+ cat "${VALGRIND_LOGFILE}"
+ fi
+ rm -f "${VALGRIND_LOGFILE}"
+ fi
+ (exit $RETVAL)
+}
+
+_qemu_nbd_wrapper()
+{
+ (
+ echo $BASHPID > "${TEST_DIR}/qemu-nbd.pid"
+ exec "$QEMU_NBD_PROG" $QEMU_NBD_OPTIONS "$@"
+ )
+}
+
+export QEMU=_qemu_wrapper
+export QEMU_IMG=_qemu_img_wrapper
+export QEMU_IO=_qemu_io_wrapper
+export QEMU_NBD=_qemu_nbd_wrapper
+
+default_machine=$($QEMU -machine \? | awk '/(default)/{print $1}')
+default_alias_machine=$($QEMU -machine \? |\
+ awk -v var_default_machine="$default_machine"\)\
+ '{if ($(NF-2)=="(alias"&&$(NF-1)=="of"&&$(NF)==var_default_machine){print $1}}')
+if [ ! -z "$default_alias_machine" ]; then
+ default_machine="$default_alias_machine"
+fi
+
+export QEMU_DEFAULT_MACHINE="$default_machine"
[ -f /etc/qemu-iotest.config ] && . /etc/qemu-iotest.config
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
index 012a8122d..cfdb6338a 100644
--- a/tests/qemu-iotests/common.filter
+++ b/tests/qemu-iotests/common.filter
@@ -128,6 +128,11 @@ _filter_date()
-e 's/[A-Z][a-z][a-z] [A-z][a-z][a-z] *[0-9][0-9]* [0-9][0-9]:[0-9][0-9]:[0-9][0-9] [0-9][0-9][0-9][0-9]$/DATE/'
}
+_filter_generated_node_ids()
+{
+ sed -re 's/\#block[0-9]{3,}/NODE_NAME/'
+}
+
# replace occurrences of the actual TEST_DIR value with TEST_DIR
_filter_testdir()
{
@@ -182,7 +187,7 @@ _filter_img_create()
-e "s# encryption=off##g" \
-e "s# cluster_size=[0-9]\\+##g" \
-e "s# table_size=[0-9]\\+##g" \
- -e "s# compat='[^']*'##g" \
+ -e "s# compat=[^ ]*##g" \
-e "s# compat6=\\(on\\|off\\)##g" \
-e "s# static=\\(on\\|off\\)##g" \
-e "s# zeroed_grain=\\(on\\|off\\)##g" \
diff --git a/tests/qemu-iotests/common.qemu b/tests/qemu-iotests/common.qemu
index 4e1996c3e..8bf396941 100644
--- a/tests/qemu-iotests/common.qemu
+++ b/tests/qemu-iotests/common.qemu
@@ -30,8 +30,6 @@ QEMU_COMM_TIMEOUT=10
QEMU_FIFO_IN="${TEST_DIR}/qmp-in-$$"
QEMU_FIFO_OUT="${TEST_DIR}/qmp-out-$$"
-QEMU_PID=
-_QEMU_HANDLE=0
QEMU_HANDLE=0
# If bash version is >= 4.1, these will be overwritten and dynamic
@@ -153,11 +151,11 @@ function _launch_qemu()
mkfifo "${fifo_out}"
mkfifo "${fifo_in}"
- "${QEMU}" -nographic -serial none ${comm} -machine accel=qtest "${@}" \
+ QEMU_NEED_PID='y'\
+ ${QEMU} -nographic -serial none ${comm} -machine accel=qtest "${@}" \
>"${fifo_out}" \
2>&1 \
<"${fifo_in}" &
- QEMU_PID[${_QEMU_HANDLE}]=$!
if [[ "${BASH_VERSINFO[0]}" -ge "5" ||
("${BASH_VERSINFO[0]}" -ge "4" && "${BASH_VERSINFO[1]}" -ge "1") ]]
@@ -196,10 +194,18 @@ function _cleanup_qemu()
# QEMU_PID[], QEMU_IN[], QEMU_OUT[] all use same indices
for i in "${!QEMU_OUT[@]}"
do
- if [ -z "${wait}" ]; then
- kill -KILL ${QEMU_PID[$i]} 2>/dev/null
+ local QEMU_PID
+ if [ -f "${TEST_DIR}/qemu-${i}.pid" ]; then
+ read QEMU_PID < "${TEST_DIR}/qemu-${i}.pid"
+ rm -f "${TEST_DIR}/qemu-${i}.pid"
+ if [ -z "${wait}" ] && [ -n "${QEMU_PID}" ]; then
+ kill -KILL ${QEMU_PID} 2>/dev/null
+ fi
+ if [ -n "${QEMU_PID}" ]; then
+ wait ${QEMU_PID} 2>/dev/null # silent kill
+ fi
fi
- wait ${QEMU_PID[$i]} 2>/dev/null # silent kill
+
if [ -n "${wait}" ]; then
cat <&${QEMU_OUT[$i]} | _filter_testdir | _filter_qemu \
| _filter_qemu_io | _filter_qmp
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
index 22d351404..d9913f849 100644
--- a/tests/qemu-iotests/common.rc
+++ b/tests/qemu-iotests/common.rc
@@ -70,16 +70,6 @@ else
TEST_IMG=$IMGPROTO:$TEST_DIR/t.$IMGFMT
fi
-function valgrind_qemu_io()
-{
- valgrind --log-file=/tmp/$$.valgrind --error-exitcode=99 $REAL_QEMU_IO "$@"
- if [ $? != 0 ]; then
- cat /tmp/$$.valgrind
- fi
- rm -f /tmp/$$.valgrind
-}
-
-
_optstr_add()
{
if [ -n "$1" ]; then
@@ -154,7 +144,6 @@ _make_test_img()
# Start an NBD server on the image file, which is what we'll be talking to
if [ $IMGPROTO = "nbd" ]; then
eval "$QEMU_NBD -v -t -b 127.0.0.1 -p 10810 -f $IMGFMT $TEST_IMG_FILE &"
- QEMU_NBD_PID=$!
sleep 1 # FIXME: qemu-nbd needs to be listening before we continue
fi
}
@@ -175,8 +164,11 @@ _cleanup_test_img()
case "$IMGPROTO" in
nbd)
- if [ -n "$QEMU_NBD_PID" ]; then
- kill $QEMU_NBD_PID
+ if [ -f "${TEST_DIR}/qemu-nbd.pid" ]; then
+ local QEMU_NBD_PID
+ read QEMU_NBD_PID < "${TEST_DIR}/qemu-nbd.pid"
+ kill ${QEMU_NBD_PID}
+ rm -f "${TEST_DIR}/qemu-nbd.pid"
fi
rm -f "$TEST_IMG_FILE"
;;
@@ -439,7 +431,17 @@ _unsupported_imgopts()
#
_require_command()
{
- eval c=\$$1
+ if [ "$1" = "QEMU" ]; then
+ c=$QEMU_PROG
+ elif [ "$1" = "QEMU_IMG" ]; then
+ c=$QEMU_IMG_PROG
+ elif [ "$1" = "QEMU_IO" ]; then
+ c=$QEMU_IO_PROG
+ elif [ "$1" = "QEMU_NBD" ]; then
+ c=$QEMU_NBD_PROG
+ else
+ eval c=\$$1
+ fi
[ -x "$c" ] || _notrun "$1 utility required, skipped this test"
}
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index c430b6c23..d90629fc3 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -102,6 +102,7 @@
093 auto
094 rw auto quick
095 rw auto quick
+096 rw auto quick
097 rw auto backing
098 rw auto backing quick
099 rw auto quick
@@ -121,6 +122,7 @@
114 rw auto quick
115 rw auto
116 rw auto quick
+118 rw auto
119 rw auto quick
120 rw auto quick
121 rw auto
@@ -134,3 +136,8 @@
132 rw auto quick
134 rw auto quick
135 rw auto
+136 rw auto
+137 rw auto
+138 rw auto quick
+139 rw auto quick
+144 rw auto quick
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
index 8615b1075..e02245ed0 100644
--- a/tests/qemu-iotests/iotests.py
+++ b/tests/qemu-iotests/iotests.py
@@ -31,37 +31,60 @@ import struct
__all__ = ['imgfmt', 'imgproto', 'test_dir' 'qemu_img', 'qemu_io',
'VM', 'QMPTestCase', 'notrun', 'main']
-# This will not work if arguments or path contain spaces but is necessary if we
+# This will not work if arguments contain spaces but is necessary if we
# want to support the override options that ./check supports.
-qemu_img_args = os.environ.get('QEMU_IMG', 'qemu-img').strip().split(' ')
-qemu_io_args = os.environ.get('QEMU_IO', 'qemu-io').strip().split(' ')
-qemu_args = os.environ.get('QEMU', 'qemu').strip().split(' ')
+qemu_img_args = [os.environ.get('QEMU_IMG_PROG', 'qemu-img')]
+if os.environ.get('QEMU_IMG_OPTIONS'):
+ qemu_img_args += os.environ['QEMU_IMG_OPTIONS'].strip().split(' ')
+
+qemu_io_args = [os.environ.get('QEMU_IO_PROG', 'qemu-io')]
+if os.environ.get('QEMU_IO_OPTIONS'):
+ qemu_io_args += os.environ['QEMU_IO_OPTIONS'].strip().split(' ')
+
+qemu_args = [os.environ.get('QEMU_PROG', 'qemu')]
+if os.environ.get('QEMU_OPTIONS'):
+ qemu_args += os.environ['QEMU_OPTIONS'].strip().split(' ')
imgfmt = os.environ.get('IMGFMT', 'raw')
imgproto = os.environ.get('IMGPROTO', 'file')
test_dir = os.environ.get('TEST_DIR', '/var/tmp')
output_dir = os.environ.get('OUTPUT_DIR', '.')
cachemode = os.environ.get('CACHEMODE')
+qemu_default_machine = os.environ.get('QEMU_DEFAULT_MACHINE')
socket_scm_helper = os.environ.get('SOCKET_SCM_HELPER', 'socket_scm_helper')
def qemu_img(*args):
'''Run qemu-img and return the exit code'''
devnull = open('/dev/null', 'r+')
- return subprocess.call(qemu_img_args + list(args), stdin=devnull, stdout=devnull)
+ exitcode = subprocess.call(qemu_img_args + list(args), stdin=devnull, stdout=devnull)
+ if exitcode < 0:
+ sys.stderr.write('qemu-img received signal %i: %s\n' % (-exitcode, ' '.join(qemu_img_args + list(args))))
+ return exitcode
def qemu_img_verbose(*args):
'''Run qemu-img without suppressing its output and return the exit code'''
- return subprocess.call(qemu_img_args + list(args))
+ exitcode = subprocess.call(qemu_img_args + list(args))
+ if exitcode < 0:
+ sys.stderr.write('qemu-img received signal %i: %s\n' % (-exitcode, ' '.join(qemu_img_args + list(args))))
+ return exitcode
def qemu_img_pipe(*args):
'''Run qemu-img and return its output'''
- return subprocess.Popen(qemu_img_args + list(args), stdout=subprocess.PIPE).communicate()[0]
+ subp = subprocess.Popen(qemu_img_args + list(args), stdout=subprocess.PIPE)
+ exitcode = subp.wait()
+ if exitcode < 0:
+ sys.stderr.write('qemu-img received signal %i: %s\n' % (-exitcode, ' '.join(qemu_img_args + list(args))))
+ return subp.communicate()[0]
def qemu_io(*args):
'''Run qemu-io and return the stdout data'''
args = qemu_io_args + list(args)
- return subprocess.Popen(args, stdout=subprocess.PIPE).communicate()[0]
+ subp = subprocess.Popen(args, stdout=subprocess.PIPE)
+ exitcode = subp.wait()
+ if exitcode < 0:
+ sys.stderr.write('qemu-io received signal %i: %s\n' % (-exitcode, ' '.join(args)))
+ return subp.communicate()[0]
def compare_images(img1, img2):
'''Return True if two image files are identical'''
@@ -117,13 +140,21 @@ class VM(object):
self._args.append('-monitor')
self._args.append(args)
- def add_drive(self, path, opts=''):
+ def add_drive_raw(self, opts):
+ self._args.append('-drive')
+ self._args.append(opts)
+ return self
+
+ def add_drive(self, path, opts='', interface='virtio'):
'''Add a virtio-blk drive to the VM'''
- options = ['if=virtio',
+ options = ['if=%s' % interface,
'format=%s' % imgfmt,
'cache=%s' % cachemode,
- 'file=%s' % path,
'id=drive%d' % self._num_drives]
+
+ if path is not None:
+ options.append('file=%s' % path)
+
if opts:
options.append(opts)
@@ -196,7 +227,9 @@ class VM(object):
'''Terminate the VM and clean up'''
if not self._popen is None:
self._qmp.cmd('quit')
- self._popen.wait()
+ exitcode = self._popen.wait()
+ if exitcode < 0:
+ sys.stderr.write('qemu received signal %i: %s\n' % (-exitcode, ' '.join(self._args)))
os.remove(self._monitor_path)
os.remove(self._qtest_path)
os.remove(self._qemu_log_path)