diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2019-02-01 17:58:27 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2019-02-01 17:58:27 +0000 |
commit | b3fc0af1ff5e922d4dd7c875394dbd26dc7313b4 (patch) | |
tree | 2c59c91e8112e0be05a43543f7d11394f2d52653 /tests | |
parent | e83d74286cad2b9b967e1ba0ce5c8d16cba9679f (diff) | |
parent | 7471a649fc3a391dd497297013fb2525ca9821ba (diff) |
Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging
Block layer patches:
- vmdk: Support for blockdev-create
- block: Apply auto-read-only for ro-whitelist drivers
- virtio-scsi: Fixes related to attaching/detaching iothreads
- scsi-disk: Fixed erroneously detected multipath setup with multiple
disks created with node-names. Added device_id property.
- block: Fix hangs in synchronous APIs with iothreads
- block: Fix invalidate_cache error path for parent activation
- block-backend, mirror, qcow2, vpc, vdi, qemu-iotests:
Minor fixes and code improvements
# gpg: Signature made Fri 01 Feb 2019 15:23:10 GMT
# gpg: using RSA key 7F09B272C88F2FD6
# gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" [full]
# Primary key fingerprint: DC3D EB15 9A9A F95D 3D74 56FE 7F09 B272 C88F 2FD6
* remotes/kevin/tags/for-upstream: (27 commits)
scsi-disk: Add device_id property
scsi-disk: Don't use empty string as device id
qtest.py: Wait for the result of qtest commands
block: Fix invalidate_cache error path for parent activation
iotests/236: fix transaction kwarg order
iotests: Filter second BLOCK_JOB_ERROR from 229
virtio-scsi: Forbid devices with different iothreads sharing a blockdev
scsi-disk: Acquire the AioContext in scsi_*_realize()
virtio-scsi: Move BlockBackend back to the main AioContext on unplug
block: Eliminate the S_1KiB, S_2KiB, ... macros
block: Remove blk_attach_dev_legacy() / legacy_dev code
block: Apply auto-read-only for ro-whitelist drivers
uuid: Make qemu_uuid_bswap() take and return a QemuUUID
block/vdi: Don't take address of fields in packed structs
block/vpc: Don't take address of fields in packed structs
vmdk: Reject excess extents in blockdev-create
iotests: Add VMDK tests for blockdev-create
iotests: Filter cid numbers in VMDK extent info
vmdk: Implement .bdrv_co_create callback
vmdk: Refactor vmdk_create_extent
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'tests')
-rw-r--r-- | tests/Makefile.include | 2 | ||||
-rw-r--r-- | tests/qemu-iotests/141.out | 4 | ||||
-rwxr-xr-x | tests/qemu-iotests/229 | 6 | ||||
-rw-r--r-- | tests/qemu-iotests/229.out | 1 | ||||
-rwxr-xr-x | tests/qemu-iotests/234 | 56 | ||||
-rw-r--r-- | tests/qemu-iotests/234.out | 10 | ||||
-rw-r--r-- | tests/qemu-iotests/236.out | 56 | ||||
-rwxr-xr-x | tests/qemu-iotests/237 | 237 | ||||
-rw-r--r-- | tests/qemu-iotests/237.out | 348 | ||||
-rwxr-xr-x | tests/qemu-iotests/239 | 53 | ||||
-rw-r--r-- | tests/qemu-iotests/239.out | 4 | ||||
-rwxr-xr-x | tests/qemu-iotests/240 | 129 | ||||
-rw-r--r-- | tests/qemu-iotests/240.out | 54 | ||||
-rwxr-xr-x | tests/qemu-iotests/check | 7 | ||||
-rw-r--r-- | tests/qemu-iotests/common.filter | 1 | ||||
-rw-r--r-- | tests/qemu-iotests/group | 3 | ||||
-rw-r--r-- | tests/qemu-iotests/iotests.py | 22 | ||||
-rw-r--r-- | tests/qemu-iotests/sample_images/simple-dmg.dmg.bz2 | bin | 0 -> 3479 bytes | |||
-rw-r--r-- | tests/test-block-iothread.c | 372 | ||||
-rw-r--r-- | tests/vmgenid-test.c | 2 |
20 files changed, 1296 insertions, 71 deletions
diff --git a/tests/Makefile.include b/tests/Makefile.include index 19b4c0a696..75ad9c0dd3 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -73,6 +73,7 @@ check-unit-y += tests/test-bdrv-drain$(EXESUF) check-unit-y += tests/test-blockjob$(EXESUF) check-unit-y += tests/test-blockjob-txn$(EXESUF) check-unit-y += tests/test-block-backend$(EXESUF) +check-unit-y += tests/test-block-iothread$(EXESUF) check-unit-y += tests/test-image-locking$(EXESUF) check-unit-y += tests/test-x86-cpuid$(EXESUF) # all code tested by test-x86-cpuid is inside topology.h @@ -557,6 +558,7 @@ tests/test-bdrv-drain$(EXESUF): tests/test-bdrv-drain.o $(test-block-obj-y) $(te tests/test-blockjob$(EXESUF): tests/test-blockjob.o $(test-block-obj-y) $(test-util-obj-y) tests/test-blockjob-txn$(EXESUF): tests/test-blockjob-txn.o $(test-block-obj-y) $(test-util-obj-y) tests/test-block-backend$(EXESUF): tests/test-block-backend.o $(test-block-obj-y) $(test-util-obj-y) +tests/test-block-iothread$(EXESUF): tests/test-block-iothread.o $(test-block-obj-y) $(test-util-obj-y) tests/test-image-locking$(EXESUF): tests/test-image-locking.o $(test-block-obj-y) $(test-util-obj-y) tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(test-block-obj-y) tests/test-iov$(EXESUF): tests/test-iov.o $(test-util-obj-y) diff --git a/tests/qemu-iotests/141.out b/tests/qemu-iotests/141.out index f252c86875..41c7291258 100644 --- a/tests/qemu-iotests/141.out +++ b/tests/qemu-iotests/141.out @@ -28,7 +28,7 @@ Formatting 'TEST_DIR/o.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t. {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "job0"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "mirror"}} {"return": {}} -{"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: node is used as backing hd of 'NODE_NAME'"}} +{"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: block device is in use by block job: mirror"}} {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job0"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job0"}} @@ -45,7 +45,7 @@ Formatting 'TEST_DIR/o.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t. {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "job0"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}} {"return": {}} -{"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: node is used as backing hd of 'NODE_NAME'"}} +{"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: block device is in use by block job: commit"}} {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job0"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job0"}} diff --git a/tests/qemu-iotests/229 b/tests/qemu-iotests/229 index 893d098ad2..b0d4885fa6 100755 --- a/tests/qemu-iotests/229 +++ b/tests/qemu-iotests/229 @@ -81,11 +81,15 @@ echo echo '=== Force cancel job paused in error state ===' echo +# Filter out BLOCK_JOB_ERROR events because they may or may not occur. +# Cancelling the job means resuming it for a bit before it is actually +# aborted, and in that time it may or may not re-encounter the error. success_or_failure="y" _send_qemu_cmd $QEMU_HANDLE \ "{'execute': 'block-job-cancel', 'arguments': { 'device': 'testdisk', 'force': true}}" \ - "BLOCK_JOB_CANCELLED" "Assertion" + "BLOCK_JOB_CANCELLED" "Assertion" \ + | grep -v '"BLOCK_JOB_ERROR"' # success, all done echo "*** done" diff --git a/tests/qemu-iotests/229.out b/tests/qemu-iotests/229.out index 4c4112805f..a3eb33788a 100644 --- a/tests/qemu-iotests/229.out +++ b/tests/qemu-iotests/229.out @@ -17,7 +17,6 @@ wrote 2097152/2097152 bytes at offset 0 {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "testdisk"}} {"return": {}} -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "testdisk", "operation": "write", "action": "stop"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "testdisk"}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "testdisk", "len": 2097152, "offset": 1048576, "speed": 0, "type": "mirror"}} *** done diff --git a/tests/qemu-iotests/234 b/tests/qemu-iotests/234 index a8185b4360..c4c26bc21e 100755 --- a/tests/qemu-iotests/234 +++ b/tests/qemu-iotests/234 @@ -26,6 +26,22 @@ import os iotests.verify_image_format(supported_fmts=['qcow2']) iotests.verify_platform(['linux']) +def enable_migration_events(vm, name): + iotests.log('Enabling migration QMP events on %s...' % name) + iotests.log(vm.qmp('migrate-set-capabilities', capabilities=[ + { + 'capability': 'events', + 'state': True + } + ])) + +def wait_migration(vm): + while True: + event = vm.event_wait('MIGRATION') + iotests.log(event, filters=[iotests.filter_qmp_event]) + if event['data']['status'] == 'completed': + break + with iotests.FilePath('img') as img_path, \ iotests.FilePath('backing') as backing_path, \ iotests.FilePath('mig_fifo_a') as fifo_a, \ @@ -46,6 +62,8 @@ with iotests.FilePath('img') as img_path, \ .add_blockdev('%s,file=drive0-backing-file,node-name=drive0-backing' % (iotests.imgfmt)) .launch()) + enable_migration_events(vm_a, 'A') + iotests.log('Launching destination VM...') (vm_b.add_blockdev('file,filename=%s,node-name=drive0-file' % (img_path)) .add_blockdev('%s,file=drive0-file,node-name=drive0' % (iotests.imgfmt)) @@ -54,6 +72,8 @@ with iotests.FilePath('img') as img_path, \ .add_incoming("exec: cat '%s'" % (fifo_a)) .launch()) + enable_migration_events(vm_b, 'B') + # Add a child node that was created after the parent node. The reverse case # is covered by the -blockdev options above. iotests.log(vm_a.qmp('blockdev-snapshot', node='drive0-backing', @@ -61,22 +81,13 @@ with iotests.FilePath('img') as img_path, \ iotests.log(vm_b.qmp('blockdev-snapshot', node='drive0-backing', overlay='drive0')) - iotests.log('Enabling migration QMP events on A...') - iotests.log(vm_a.qmp('migrate-set-capabilities', capabilities=[ - { - 'capability': 'events', - 'state': True - } - ])) - iotests.log('Starting migration to B...') iotests.log(vm_a.qmp('migrate', uri='exec:cat >%s' % (fifo_a))) with iotests.Timeout(3, 'Migration does not complete'): - while True: - event = vm_a.event_wait('MIGRATION') - iotests.log(event, filters=[iotests.filter_qmp_event]) - if event['data']['status'] == 'completed': - break + # Wait for the source first (which includes setup=setup) + wait_migration(vm_a) + # Wait for the destination second (which does not) + wait_migration(vm_b) iotests.log(vm_a.qmp('query-migrate')['return']['status']) iotests.log(vm_b.qmp('query-migrate')['return']['status']) @@ -94,25 +105,18 @@ with iotests.FilePath('img') as img_path, \ .add_incoming("exec: cat '%s'" % (fifo_b)) .launch()) + enable_migration_events(vm_a, 'A') + iotests.log(vm_a.qmp('blockdev-snapshot', node='drive0-backing', overlay='drive0')) - iotests.log('Enabling migration QMP events on B...') - iotests.log(vm_b.qmp('migrate-set-capabilities', capabilities=[ - { - 'capability': 'events', - 'state': True - } - ])) - iotests.log('Starting migration back to A...') iotests.log(vm_b.qmp('migrate', uri='exec:cat >%s' % (fifo_b))) with iotests.Timeout(3, 'Migration does not complete'): - while True: - event = vm_b.event_wait('MIGRATION') - iotests.log(event, filters=[iotests.filter_qmp_event]) - if event['data']['status'] == 'completed': - break + # Wait for the source first (which includes setup=setup) + wait_migration(vm_b) + # Wait for the destination second (which does not) + wait_migration(vm_a) iotests.log(vm_a.qmp('query-migrate')['return']['status']) iotests.log(vm_b.qmp('query-migrate')['return']['status']) diff --git a/tests/qemu-iotests/234.out b/tests/qemu-iotests/234.out index b9ed910b1a..692976d1c6 100644 --- a/tests/qemu-iotests/234.out +++ b/tests/qemu-iotests/234.out @@ -1,14 +1,18 @@ Launching source VM... +Enabling migration QMP events on A... +{"return": {}} Launching destination VM... +Enabling migration QMP events on B... {"return": {}} {"return": {}} -Enabling migration QMP events on A... {"return": {}} Starting migration to B... {"return": {}} {"data": {"status": "setup"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} {"data": {"status": "active"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} {"data": {"status": "completed"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} +{"data": {"status": "active"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} +{"data": {"status": "completed"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} completed completed {"return": {"running": false, "singlestep": false, "status": "postmigrate"}} @@ -16,14 +20,16 @@ completed Add a second parent to drive0-file... {"return": {}} Restart A with -incoming and second parent... +Enabling migration QMP events on A... {"return": {}} -Enabling migration QMP events on B... {"return": {}} Starting migration back to A... {"return": {}} {"data": {"status": "setup"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} {"data": {"status": "active"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} {"data": {"status": "completed"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} +{"data": {"status": "active"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} +{"data": {"status": "completed"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} completed completed {"return": {"running": true, "singlestep": false, "status": "running"}} diff --git a/tests/qemu-iotests/236.out b/tests/qemu-iotests/236.out index 1dad24db0d..bb2d71ea5e 100644 --- a/tests/qemu-iotests/236.out +++ b/tests/qemu-iotests/236.out @@ -45,23 +45,23 @@ write -P0xcd 0x3ff0000 64k "actions": [ { "data": { - "node": "drive0", - "name": "bitmapB" + "name": "bitmapB", + "node": "drive0" }, "type": "block-dirty-bitmap-disable" }, { "data": { - "node": "drive0", + "granularity": 65536, "name": "bitmapC", - "granularity": 65536 + "node": "drive0" }, "type": "block-dirty-bitmap-add" }, { "data": { - "node": "drive0", - "name": "bitmapA" + "name": "bitmapA", + "node": "drive0" }, "type": "block-dirty-bitmap-clear" }, @@ -105,30 +105,30 @@ write -P0xcd 0x3ff0000 64k "actions": [ { "data": { - "node": "drive0", - "name": "bitmapB" + "name": "bitmapB", + "node": "drive0" }, "type": "block-dirty-bitmap-disable" }, { "data": { - "node": "drive0", + "granularity": 65536, "name": "bitmapC", - "granularity": 65536 + "node": "drive0" }, "type": "block-dirty-bitmap-add" }, { "data": { - "node": "drive0", - "name": "bitmapC" + "name": "bitmapC", + "node": "drive0" }, "type": "block-dirty-bitmap-disable" }, { "data": { - "node": "drive0", - "name": "bitmapC" + "name": "bitmapC", + "node": "drive0" }, "type": "block-dirty-bitmap-enable" } @@ -158,15 +158,15 @@ write -P0xea 0x3fe0000 64k "actions": [ { "data": { - "node": "drive0", - "name": "bitmapA" + "name": "bitmapA", + "node": "drive0" }, "type": "block-dirty-bitmap-disable" }, { "data": { - "node": "drive0", - "name": "bitmapC" + "name": "bitmapC", + "node": "drive0" }, "type": "block-dirty-bitmap-disable" } @@ -209,21 +209,21 @@ write -P0xea 0x3fe0000 64k "actions": [ { "data": { - "node": "drive0", "disabled": true, + "granularity": 65536, "name": "bitmapD", - "granularity": 65536 + "node": "drive0" }, "type": "block-dirty-bitmap-add" }, { "data": { - "node": "drive0", - "target": "bitmapD", "bitmaps": [ "bitmapB", "bitmapC" - ] + ], + "node": "drive0", + "target": "bitmapD" }, "type": "block-dirty-bitmap-merge" }, @@ -273,21 +273,21 @@ write -P0xea 0x3fe0000 64k "actions": [ { "data": { - "node": "drive0", "disabled": true, + "granularity": 65536, "name": "bitmapD", - "granularity": 65536 + "node": "drive0" }, "type": "block-dirty-bitmap-add" }, { "data": { - "node": "drive0", - "target": "bitmapD", "bitmaps": [ "bitmapB", "bitmapC" - ] + ], + "node": "drive0", + "target": "bitmapD" }, "type": "block-dirty-bitmap-merge" } diff --git a/tests/qemu-iotests/237 b/tests/qemu-iotests/237 new file mode 100755 index 0000000000..251771d7fb --- /dev/null +++ b/tests/qemu-iotests/237 @@ -0,0 +1,237 @@ +#!/usr/bin/env python +# +# Test vmdk and file image creation +# +# Copyright (C) 2018 Red Hat, Inc. +# +# Creator/Owner: Kevin Wolf <kwolf@redhat.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 math +import iotests +from iotests import imgfmt + +iotests.verify_image_format(supported_fmts=['vmdk']) + +def blockdev_create(vm, options): + result = vm.qmp_log('blockdev-create', job_id='job0', options=options) + + if 'return' in result: + assert result['return'] == {} + vm.run_job('job0') + iotests.log("") + +with iotests.FilePath('t.vmdk') as disk_path, \ + iotests.FilePath('t.vmdk.1') as extent1_path, \ + iotests.FilePath('t.vmdk.2') as extent2_path, \ + iotests.FilePath('t.vmdk.3') as extent3_path, \ + iotests.VM() as vm: + + # + # Successful image creation (defaults) + # + iotests.log("=== Successful image creation (defaults) ===") + iotests.log("") + + size = 5 * 1024 * 1024 * 1024 + + vm.launch() + blockdev_create(vm, { 'driver': 'file', + 'filename': disk_path, + 'size': 0 }) + + vm.qmp_log('blockdev-add', driver='file', filename=disk_path, + node_name='imgfile') + + blockdev_create(vm, { 'driver': imgfmt, + 'file': 'imgfile', + 'size': size }) + vm.shutdown() + + iotests.img_info_log(disk_path) + + # + # Successful image creation (inline blockdev-add, explicit defaults) + # + iotests.log("=== Successful image creation (inline blockdev-add, explicit defaults) ===") + iotests.log("") + + # Choose a different size to show that we got a new image + size = 64 * 1024 * 1024 + + vm.launch() + blockdev_create(vm, { 'driver': 'file', + 'filename': disk_path, + 'size': 0 }) + + blockdev_create(vm, { 'driver': imgfmt, + 'file': { + 'driver': 'file', + 'filename': disk_path, + }, + 'size': size, + 'extents': [], + 'subformat': 'monolithicSparse', + 'adapter-type': 'ide', + 'hwversion': '4', + 'zeroed-grain': False }) + vm.shutdown() + + iotests.img_info_log(disk_path) + + # + # Successful image creation (non-default options) + # + iotests.log("=== Successful image creation (with non-default options) ===") + iotests.log("") + + # Choose a different size to show that we got a new image + size = 32 * 1024 * 1024 + + vm.launch() + blockdev_create(vm, { 'driver': 'file', + 'filename': disk_path, + 'size': 0 }) + + blockdev_create(vm, { 'driver': imgfmt, + 'file': { + 'driver': 'file', + 'filename': disk_path, + }, + 'size': size, + 'extents': [], + 'subformat': 'monolithicSparse', + 'adapter-type': 'buslogic', + 'zeroed-grain': True }) + vm.shutdown() + + iotests.img_info_log(disk_path) + + # + # Invalid BlockdevRef + # + iotests.log("=== Invalid BlockdevRef ===") + iotests.log("") + + vm.launch() + blockdev_create(vm, { 'driver': imgfmt, + 'file': "this doesn't exist", + 'size': size }) + vm.shutdown() + + # + # Adapter types + # + + iotests.log("=== Adapter types ===") + iotests.log("") + + vm.add_blockdev('driver=file,filename=%s,node-name=node0' % (disk_path)) + + # Valid + iotests.log("== Valid adapter types ==") + iotests.log("") + + vm.launch() + for adapter_type in [ 'ide', 'buslogic', 'lsilogic', 'legacyESX' ]: + blockdev_create(vm, { 'driver': imgfmt, + 'file': 'node0', + 'size': size, + 'adapter-type': adapter_type }) + vm.shutdown() + + # Invalid + iotests.log("== Invalid adapter types ==") + iotests.log("") + + vm.launch() + for adapter_type in [ 'foo', 'IDE', 'legacyesx', 1 ]: + blockdev_create(vm, { 'driver': imgfmt, + 'file': 'node0', + 'size': size, + 'adapter-type': adapter_type }) + vm.shutdown() + + # + # Other subformats + # + iotests.log("=== Other subformats ===") + iotests.log("") + + for path in [ extent1_path, extent2_path, extent3_path ]: + msg = iotests.qemu_img_pipe('create', '-f', imgfmt, path, '0') + iotests.log(msg, [iotests.filter_testfiles]) + + vm.add_blockdev('driver=file,filename=%s,node-name=ext1' % (extent1_path)) + vm.add_blockdev('driver=file,filename=%s,node-name=ext2' % (extent2_path)) + vm.add_blockdev('driver=file,filename=%s,node-name=ext3' % (extent3_path)) + + # Missing extent + iotests.log("== Missing extent ==") + iotests.log("") + + vm.launch() + blockdev_create(vm, { 'driver': imgfmt, + 'file': 'node0', + 'size': size, + 'subformat': 'monolithicFlat' }) + vm.shutdown() + + # Correct extent + iotests.log("== Correct extent ==") + iotests.log("") + + vm.launch() + blockdev_create(vm, { 'driver': imgfmt, + 'file': 'node0', + 'size': size, + 'subformat': 'monolithicFlat', + 'extents': ['ext1'] }) + vm.shutdown() + + # Extra extent + iotests.log("== Extra extent ==") + iotests.log("") + + vm.launch() + blockdev_create(vm, { 'driver': imgfmt, + 'file': 'node0', + 'size': 512, + 'subformat': 'monolithicFlat', + 'extents': ['ext1', 'ext2', 'ext3'] }) + vm.shutdown() + + # Split formats + iotests.log("== Split formats ==") + iotests.log("") + + for size in [ 512, 1073741824, 2147483648, 5368709120 ]: + for subfmt in [ 'twoGbMaxExtentFlat', 'twoGbMaxExtentSparse' ]: + iotests.log("= %s %d =" % (subfmt, size)) + iotests.log("") + + num_extents = math.ceil(size / 2.0**31) + extents = [ "ext%d" % (i) for i in range(1, num_extents + 1) ] + + vm.launch() + blockdev_create(vm, { 'driver': imgfmt, + 'file': 'node0', + 'size': size, + 'subformat': subfmt, + 'extents': extents }) + vm.shutdown() + + iotests.img_info_log(disk_path) diff --git a/tests/qemu-iotests/237.out b/tests/qemu-iotests/237.out new file mode 100644 index 0000000000..241c864369 --- /dev/null +++ b/tests/qemu-iotests/237.out @@ -0,0 +1,348 @@ +=== Successful image creation (defaults) === + +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk", "size": 0}}} +{"return": {}} +{"execute": "job-dismiss", "arguments": {"id": "job0"}} +{"return": {}} + +{"execute": "blockdev-add", "arguments": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk", "node_name": "imgfile"}} +{"return": {}} +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "file": "imgfile", "size": 5368709120}}} +{"return": {}} +{"execute": "job-dismiss", "arguments": {"id": "job0"}} +{"return": {}} + +image: TEST_IMG +file format: IMGFMT +virtual size: 5.0G (5368709120 bytes) +cluster_size: 65536 +Format specific information: + cid: XXXXXXXXXX + parent cid: XXXXXXXXXX + create type: monolithicSparse + extents: + [0]: + virtual size: 5368709120 + filename: TEST_IMG + cluster size: 65536 + format: + +=== Successful image creation (inline blockdev-add, explicit defaults) === + +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk", "size": 0}}} +{"return": {}} +{"execute": "job-dismiss", "arguments": {"id": "job0"}} +{"return": {}} + +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "ide", "driver": "vmdk", "extents": [], "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk"}, "hwversion": "4", "size": 67108864, "subformat": "monolithicSparse", "zeroed-grain": false}}} +{"return": {}} +{"execute": "job-dismiss", "arguments": {"id": "job0"}} +{"return": {}} + +image: TEST_IMG +file format: IMGFMT +virtual size: 64M (67108864 bytes) +cluster_size: 65536 +Format specific information: + cid: XXXXXXXXXX + parent cid: XXXXXXXXXX + create type: monolithicSparse + extents: + [0]: + virtual size: 67108864 + filename: TEST_IMG + cluster size: 65536 + format: + +=== Successful image creation (with non-default options) === + +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk", "size": 0}}} +{"return": {}} +{"execute": "job-dismiss", "arguments": {"id": "job0"}} +{"return": {}} + +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "buslogic", "driver": "vmdk", "extents": [], "file": {"driver": "file", "filename": "TEST_DIR/PID-t.vmdk"}, "size": 33554432, "subformat": "monolithicSparse", "zeroed-grain": true}}} +{"return": {}} +{"execute": "job-dismiss", "arguments": {"id": "job0"}} +{"return": {}} + +image: TEST_IMG +file format: IMGFMT +virtual size: 32M (33554432 bytes) +cluster_size: 65536 +Format specific information: + cid: XXXXXXXXXX + parent cid: XXXXXXXXXX + create type: monolithicSparse + extents: + [0]: + virtual size: 33554432 + filename: TEST_IMG + cluster size: 65536 + format: + +=== Invalid BlockdevRef === + +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "file": "this doesn't exist", "size": 33554432}}} +{"return": {}} +Job failed: Cannot find device=this doesn't exist nor node_name=this doesn't exist +{"execute": "job-dismiss", "arguments": {"id": "job0"}} +{"return": {}} + +=== Adapter types === + +== Valid adapter types == + +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "ide", "driver": "vmdk", "file": "node0", "size": 33554432}}} +{"return": {}} +{"execute": "job-dismiss", "arguments": {"id": "job0"}} +{"return": {}} + +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "buslogic", "driver": "vmdk", "file": "node0", "size": 33554432}}} +{"return": {}} +{"execute": "job-dismiss", "arguments": {"id": "job0"}} +{"return": {}} + +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "lsilogic", "driver": "vmdk", "file": "node0", "size": 33554432}}} +{"return": {}} +{"execute": "job-dismiss", "arguments": {"id": "job0"}} +{"return": {}} + +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "legacyESX", "driver": "vmdk", "file": "node0", "size": 33554432}}} +{"return": {}} +{"execute": "job-dismiss", "arguments": {"id": "job0"}} +{"return": {}} + +== Invalid adapter types == + +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "foo", "driver": "vmdk", "file": "node0", "size": 33554432}}} +{"error": {"class": "GenericError", "desc": "Invalid parameter 'foo'"}} + +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "IDE", "driver": "vmdk", "file": "node0", "size": 33554432}}} +{"error": {"class": "GenericError", "desc": "Invalid parameter 'IDE'"}} + +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": "legacyesx", "driver": "vmdk", "file": "node0", "size": 33554432}}} +{"error": {"class": "GenericError", "desc": "Invalid parameter 'legacyesx'"}} + +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"adapter-type": 1, "driver": "vmdk", "file": "node0", "size": 33554432}}} +{"error": {"class": "GenericError", "desc": "Invalid parameter type for 'options.adapter-type', expected: string"}} + +=== Other subformats === + +Formatting 'TEST_DIR/PID-t.vmdk.1', fmt=vmdk size=0 compat6=off hwversion=undefined + +Formatting 'TEST_DIR/PID-t.vmdk.2', fmt=vmdk size=0 compat6=off hwversion=undefined + +Formatting 'TEST_DIR/PID-t.vmdk.3', fmt=vmdk size=0 compat6=off hwversion=undefined + +== Missing extent == + +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "file": "node0", "size": 33554432, "subformat": "monolithicFlat"}}} +{"return": {}} +Job failed: Extent [0] not specified +{"execute": "job-dismiss", "arguments": {"id": "job0"}} +{"return": {}} + +== Correct extent == + +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 33554432, "subformat": "monolithicFlat"}}} +{"return": {}} +{"execute": "job-dismiss", "arguments": {"id": "job0"}} +{"return": {}} + +== Extra extent == + +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 512, "subformat": "monolithicFlat"}}} +{"return": {}} +Job failed: List of extents contains unused extents +{"execute": "job-dismiss", "arguments": {"id": "job0"}} +{"return": {}} + +== Split formats == + += twoGbMaxExtentFlat 512 = + +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 512, "subformat": "twoGbMaxExtentFlat"}}} +{"return": {}} +{"execute": "job-dismiss", "arguments": {"id": "job0"}} +{"return": {}} + +image: TEST_IMG +file format: IMGFMT +virtual size: 512 (512 bytes) +Format specific information: + cid: XXXXXXXXXX + parent cid: XXXXXXXXXX + create type: twoGbMaxExtentFlat + extents: + [0]: + virtual size: 512 + filename: TEST_IMG.1 + format: FLAT + += twoGbMaxExtentSparse 512 = + +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 512, "subformat": "twoGbMaxExtentSparse"}}} +{"return": {}} +{"execute": "job-dismiss", "arguments": {"id": "job0"}} +{"return": {}} + +image: TEST_IMG +file format: IMGFMT +virtual size: 512 (512 bytes) +cluster_size: 65536 +Format specific information: + cid: XXXXXXXXXX + parent cid: XXXXXXXXXX + create type: twoGbMaxExtentSparse + extents: + [0]: + virtual size: 512 + filename: TEST_IMG.1 + cluster size: 65536 + format: SPARSE + += twoGbMaxExtentFlat 1073741824 = + +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 1073741824, "subformat": "twoGbMaxExtentFlat"}}} +{"return": {}} +{"execute": "job-dismiss", "arguments": {"id": "job0"}} +{"return": {}} + +image: TEST_IMG +file format: IMGFMT +virtual size: 1.0G (1073741824 bytes) +Format specific information: + cid: XXXXXXXXXX + parent cid: XXXXXXXXXX + create type: twoGbMaxExtentFlat + extents: + [0]: + virtual size: 1073741824 + filename: TEST_IMG.1 + format: FLAT + += twoGbMaxExtentSparse 1073741824 = + +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 1073741824, "subformat": "twoGbMaxExtentSparse"}}} +{"return": {}} +{"execute": "job-dismiss", "arguments": {"id": "job0"}} +{"return": {}} + +image: TEST_IMG +file format: IMGFMT +virtual size: 1.0G (1073741824 bytes) +cluster_size: 65536 +Format specific information: + cid: XXXXXXXXXX + parent cid: XXXXXXXXXX + create type: twoGbMaxExtentSparse + extents: + [0]: + virtual size: 1073741824 + filename: TEST_IMG.1 + cluster size: 65536 + format: SPARSE + += twoGbMaxExtentFlat 2147483648 = + +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 2147483648, "subformat": "twoGbMaxExtentFlat"}}} +{"return": {}} +{"execute": "job-dismiss", "arguments": {"id": "job0"}} +{"return": {}} + +image: TEST_IMG +file format: IMGFMT +virtual size: 2.0G (2147483648 bytes) +Format specific information: + cid: XXXXXXXXXX + parent cid: XXXXXXXXXX + create type: twoGbMaxExtentFlat + extents: + [0]: + virtual size: 2147483648 + filename: TEST_IMG.1 + format: FLAT + += twoGbMaxExtentSparse 2147483648 = + +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1"], "file": "node0", "size": 2147483648, "subformat": "twoGbMaxExtentSparse"}}} +{"return": {}} +{"execute": "job-dismiss", "arguments": {"id": "job0"}} +{"return": {}} + +image: TEST_IMG +file format: IMGFMT +virtual size: 2.0G (2147483648 bytes) +cluster_size: 65536 +Format specific information: + cid: XXXXXXXXXX + parent cid: XXXXXXXXXX + create type: twoGbMaxExtentSparse + extents: + [0]: + virtual size: 2147483648 + filename: TEST_IMG.1 + cluster size: 65536 + format: SPARSE + += twoGbMaxExtentFlat 5368709120 = + +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 5368709120, "subformat": "twoGbMaxExtentFlat"}}} +{"return": {}} +{"execute": "job-dismiss", "arguments": {"id": "job0"}} +{"return": {}} + +image: TEST_IMG +file format: IMGFMT +virtual size: 5.0G (5368709120 bytes) +Format specific information: + cid: XXXXXXXXXX + parent cid: XXXXXXXXXX + create type: twoGbMaxExtentFlat + extents: + [0]: + virtual size: 2147483648 + filename: TEST_IMG.1 + format: FLAT + [1]: + virtual size: 2147483648 + filename: TEST_IMG.2 + format: FLAT + [2]: + virtual size: 1073741824 + filename: TEST_IMG.3 + format: FLAT + += twoGbMaxExtentSparse 5368709120 = + +{"execute": "blockdev-create", "arguments": {"job_id": "job0", "options": {"driver": "vmdk", "extents": ["ext1", "ext2", "ext3"], "file": "node0", "size": 5368709120, "subformat": "twoGbMaxExtentSparse"}}} +{"return": {}} +{"execute": "job-dismiss", "arguments": {"id": "job0"}} +{"return": {}} + +image: TEST_IMG +file format: IMGFMT +virtual size: 5.0G (5368709120 bytes) +cluster_size: 65536 +Format specific information: + cid: XXXXXXXXXX + parent cid: XXXXXXXXXX + create type: twoGbMaxExtentSparse + extents: + [0]: + virtual size: 2147483648 + filename: TEST_IMG.1 + cluster size: 65536 + format: SPARSE + [1]: + virtual size: 2147483648 + filename: TEST_IMG.2 + cluster size: 65536 + format: SPARSE + [2]: + virtual size: 1073741824 + filename: TEST_IMG.3 + cluster size: 65536 + format: SPARSE + diff --git a/tests/qemu-iotests/239 b/tests/qemu-iotests/239 new file mode 100755 index 0000000000..6f085d573d --- /dev/null +++ b/tests/qemu-iotests/239 @@ -0,0 +1,53 @@ +#!/bin/bash +# +# Test case for dmg +# +# Copyright (C) 2019 yuchenlin <npes87184@gmail.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/>. +# + +# creator +owner=npes87184@gmail.com + +seq=`basename $0` +echo "QA output created by $seq" + +status=1 # failure is the default! + +_cleanup() +{ + rm -f "$TEST_IMG.raw" + _cleanup_test_img +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc + +_supported_fmt dmg +_supported_proto file +_supported_os Linux + +echo +echo "== Testing conversion to raw should success ==" +_use_sample_img simple-dmg.dmg.bz2 +if ! $QEMU_IMG convert -f $IMGFMT -O raw "$TEST_IMG" "$TEST_IMG.raw" ; then + exit 1 +fi + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/239.out b/tests/qemu-iotests/239.out new file mode 100644 index 0000000000..bedbad065b --- /dev/null +++ b/tests/qemu-iotests/239.out @@ -0,0 +1,4 @@ +QA output created by 239 + +== Testing conversion to raw should success == +*** done diff --git a/tests/qemu-iotests/240 b/tests/qemu-iotests/240 new file mode 100755 index 0000000000..65cc3b39b1 --- /dev/null +++ b/tests/qemu-iotests/240 @@ -0,0 +1,129 @@ +#!/bin/bash +# +# Test hot plugging and unplugging with iothreads +# +# Copyright (C) 2019 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/>. +# + +# creator +owner=berto@igalia.com + +seq=`basename $0` +echo "QA output created by $seq" + +status=1 # failure is the default! + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_supported_fmt generic +_supported_proto generic +_supported_os Linux + +do_run_qemu() +{ + echo Testing: "$@" + $QEMU -nographic -qmp stdio -serial none "$@" + echo +} + +# Remove QMP events from (pretty-printed) output. Doesn't handle +# nested dicts correctly, but we don't get any of those in this test. +_filter_qmp_events() +{ + tr '\n' '\t' | sed -e \ + 's/{\s*"timestamp":\s*{[^}]*},\s*"event":[^,}]*\(,\s*"data":\s*{[^}]*}\)\?\s*}\s*//g' \ + | tr '\t' '\n' +} + +run_qemu() +{ + do_run_qemu "$@" 2>&1 | _filter_qmp | _filter_qmp_events +} + +case "$QEMU_DEFAULT_MACHINE" in + s390-ccw-virtio) + virtio_scsi=virtio-scsi-ccw + ;; + *) + virtio_scsi=virtio-scsi-pci + ;; +esac + +echo +echo === Unplug a SCSI disk and then plug it again === +echo + +run_qemu <<EOF +{ "execute": "qmp_capabilities" } +{ "execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "hd0"}} +{ "execute": "object-add", "arguments": {"qom-type": "iothread", "id": "iothread0"}} +{ "execute": "device_add", "arguments": {"id": "scsi0", "driver": "${virtio_scsi}", "iothread": "iothread0"}} +{ "execute": "device_add", "arguments": {"id": "scsi-hd0", "driver": "scsi-hd", "drive": "hd0"}} +{ "execute": "device_del", "arguments": {"id": "scsi-hd0"}} +{ "execute": "device_add", "arguments": {"id": "scsi-hd0", "driver": "scsi-hd", "drive": "hd0"}} +{ "execute": "device_del", "arguments": {"id": "scsi-hd0"}} +{ "execute": "device_del", "arguments": {"id": "scsi0"}} +{ "execute": "blockdev-del", "arguments": {"node-name": "hd0"}} +{ "execute": "quit"} +EOF + +echo +echo === Attach two SCSI disks using the same block device and the same iothread === +echo + +run_qemu <<EOF +{ "execute": "qmp_capabilities" } +{ "execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "hd0", "read-only": true}} +{ "execute": "object-add", "arguments": {"qom-type": "iothread", "id": "iothread0"}} +{ "execute": "device_add", "arguments": {"id": "scsi0", "driver": "${virtio_scsi}", "iothread": "iothread0"}} +{ "execute": "device_add", "arguments": {"id": "scsi-hd0", "driver": "scsi-hd", "drive": "hd0"}} +{ "execute": "device_add", "arguments": {"id": "scsi-hd1", "driver": "scsi-hd", "drive": "hd0"}} +{ "execute": "device_del", "arguments": {"id": "scsi-hd0"}} +{ "execute": "device_del", "arguments": {"id": "scsi-hd1"}} +{ "execute": "device_del", "arguments": {"id": "scsi0"}} +{ "execute": "blockdev-del", "arguments": {"node-name": "hd0"}} +{ "execute": "quit"} +EOF + +echo +echo === Attach two SCSI disks using the same block device but different iothreads === +echo + +run_qemu <<EOF +{ "execute": "qmp_capabilities" } +{ "execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "hd0", "read-only": true}} +{ "execute": "object-add", "arguments": {"qom-type": "iothread", "id": "iothread0"}} +{ "execute": "object-add", "arguments": {"qom-type": "iothread", "id": "iothread1"}} +{ "execute": "device_add", "arguments": {"id": "scsi0", "driver": "${virtio_scsi}", "iothread": "iothread0"}} +{ "execute": "device_add", "arguments": {"id": "scsi1", "driver": "${virtio_scsi}", "iothread": "iothread1"}} +{ "execute": "device_add", "arguments": {"id": "scsi-hd0", "driver": "scsi-hd", "drive": "hd0", "bus": "scsi0.0"}} +{ "execute": "device_add", "arguments": {"id": "scsi-hd1", "driver": "scsi-hd", "drive": "hd0", "bus": "scsi1.0"}} +{ "execute": "device_del", "arguments": {"id": "scsi-hd0"}} +{ "execute": "device_add", "arguments": {"id": "scsi-hd1", "driver": "scsi-hd", "drive": "hd0", "bus": "scsi1.0"}} +{ "execute": "device_del", "arguments": {"id": "scsi-hd1"}} +{ "execute": "device_del", "arguments": {"id": "scsi0"}} +{ "execute": "device_del", "arguments": {"id": "scsi1"}} +{ "execute": "blockdev-del", "arguments": {"node-name": "hd0"}} +{ "execute": "quit"} +EOF + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/240.out b/tests/qemu-iotests/240.out new file mode 100644 index 0000000000..d76392966c --- /dev/null +++ b/tests/qemu-iotests/240.out @@ -0,0 +1,54 @@ +QA output created by 240 + +=== Unplug a SCSI disk and then plug it again === + +Testing: +QMP_VERSION +{"return": {}} +{"return": {}} +{"return": {}} +{"return": {}} +{"return": {}} +{"return": {}} +{"return": {}} +{"return": {}} +{"return": {}} +{"return": {}} +{"return": {}} + +=== Attach two SCSI disks using the same block device and the same iothread === + +Testing: +QMP_VERSION +{"return": {}} +{"return": {}} +{"return": {}} +{"return": {}} +{"return": {}} +{"return": {}} +{"return": {}} +{"return": {}} +{"return": {}} +{"return": {}} +{"return": {}} + +=== Attach two SCSI disks using the same block device but different iothreads === + +Testing: +QMP_VERSION +{"return": {}} +{"return": {}} +{"return": {}} +{"return": {}} +{"return": {}} +{"return": {}} +{"return": {}} +{"error": {"class": "GenericError", "desc": "Cannot attach a blockdev that is using a different iothread"}} +{"return": {}} +{"return": {}} +{"return": {}} +{"return": {}} +{"return": {}} +{"return": {}} +{"return": {}} +*** done diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check index 89ed275988..895e1e3dcb 100755 --- a/tests/qemu-iotests/check +++ b/tests/qemu-iotests/check @@ -237,6 +237,7 @@ image format options -vhdx test vhdx -vmdk test vmdk -luks test luks + -dmg test dmg image protocol options -file test file (default) @@ -304,6 +305,12 @@ testlist options xpand=false ;; + -dmg) + IMGFMT=dmg + IMGFMT_GENERIC=false + xpand=false + ;; + -qed) IMGFMT=qed xpand=false diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter index 2031e353a5..1aa7d57140 100644 --- a/tests/qemu-iotests/common.filter +++ b/tests/qemu-iotests/common.filter @@ -165,6 +165,7 @@ _filter_img_info() -e "/table_size: [0-9]\\+/d" \ -e "/compat: '[^']*'/d" \ -e "/compat6: \\(on\\|off\\)/d" \ + -e "s/cid: [0-9]\+/cid: XXXXXXXXXX/" \ -e "/static: \\(on\\|off\\)/d" \ -e "/zeroed_grain: \\(on\\|off\\)/d" \ -e "/subformat: '[^']*'/d" \ diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 0f1c3f9cdf..959ffe85fc 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -234,4 +234,7 @@ 234 auto quick migration 235 auto quick 236 auto quick +237 rw auto quick 238 auto quick +239 rw auto quick +240 auto quick diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 009c614ef7..b461f53abf 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -76,15 +76,16 @@ def qemu_img(*args): sys.stderr.write('qemu-img received signal %i: %s\n' % (-exitcode, ' '.join(qemu_img_args + list(args)))) return exitcode -def ordered_kwargs(kwargs): - # kwargs prior to 3.6 are not ordered, so: - od = OrderedDict() - for k, v in sorted(kwargs.items()): - if isinstance(v, dict): - od[k] = ordered_kwargs(v) - else: - od[k] = v - return od +def ordered_qmp(qmsg): + # Dictionaries are not ordered prior to 3.6, therefore: + if isinstance(qmsg, list): + return [ordered_qmp(atom) for atom in qmsg] + if isinstance(qmsg, dict): + od = OrderedDict() + for k, v in sorted(qmsg.items()): + od[k] = ordered_qmp(v) + return od + return qmsg def qemu_img_create(*args): args = list(args) @@ -299,6 +300,7 @@ def filter_img_info(output, filename): .replace(imgfmt, 'IMGFMT') line = re.sub('iters: [0-9]+', 'iters: XXX', line) line = re.sub('uuid: [-a-f0-9]+', 'uuid: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX', line) + line = re.sub('cid: [0-9]+', 'cid: XXXXXXXXXX', line) lines.append(line) return '\n'.join(lines) @@ -505,7 +507,7 @@ class VM(qtest.QEMUQtestMachine): def qmp_log(self, cmd, filters=[], indent=None, **kwargs): full_cmd = OrderedDict(( ("execute", cmd), - ("arguments", ordered_kwargs(kwargs)) + ("arguments", ordered_qmp(kwargs)) )) log(full_cmd, filters, indent=indent) result = self.qmp(cmd, **kwargs) diff --git a/tests/qemu-iotests/sample_images/simple-dmg.dmg.bz2 b/tests/qemu-iotests/sample_images/simple-dmg.dmg.bz2 Binary files differnew file mode 100644 index 0000000000..05e719d03d --- /dev/null +++ b/tests/qemu-iotests/sample_images/simple-dmg.dmg.bz2 diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c new file mode 100644 index 0000000000..97ac0b159d --- /dev/null +++ b/tests/test-block-iothread.c @@ -0,0 +1,372 @@ +/* + * Block tests for iothreads + * + * Copyright (c) 2018 Kevin Wolf <kwolf@redhat.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "block/block.h" +#include "block/blockjob_int.h" +#include "sysemu/block-backend.h" +#include "qapi/error.h" +#include "iothread.h" + +static int coroutine_fn bdrv_test_co_prwv(BlockDriverState *bs, + uint64_t offset, uint64_t bytes, + QEMUIOVector *qiov, int flags) +{ + return 0; +} + +static int coroutine_fn bdrv_test_co_pdiscard(BlockDriverState *bs, + int64_t offset, int bytes) +{ + return 0; +} + +static int coroutine_fn +bdrv_test_co_truncate(BlockDriverState *bs, int64_t offset, + PreallocMode prealloc, Error **errp) +{ + return 0; +} + +static int coroutine_fn bdrv_test_co_block_status(BlockDriverState *bs, + bool want_zero, + int64_t offset, int64_t count, + int64_t *pnum, int64_t *map, + BlockDriverState **file) +{ + *pnum = count; + return 0; +} + +static BlockDriver bdrv_test = { + .format_name = "test", + .instance_size = 1, + + .bdrv_co_preadv = bdrv_test_co_prwv, + .bdrv_co_pwritev = bdrv_test_co_prwv, + .bdrv_co_pdiscard = bdrv_test_co_pdiscard, + .bdrv_co_truncate = bdrv_test_co_truncate, + .bdrv_co_block_status = bdrv_test_co_block_status, +}; + +static void test_sync_op_pread(BdrvChild *c) +{ + uint8_t buf[512]; + int ret; + + /* Success */ + ret = bdrv_pread(c, 0, buf, sizeof(buf)); + g_assert_cmpint(ret, ==, 512); + + /* Early error: Negative offset */ + ret = bdrv_pread(c, -2, buf, sizeof(buf)); + g_assert_cmpint(ret, ==, -EIO); +} + +static void test_sync_op_pwrite(BdrvChild *c) +{ + uint8_t buf[512]; + int ret; + + /* Success */ + ret = bdrv_pwrite(c, 0, buf, sizeof(buf)); + g_assert_cmpint(ret, ==, 512); + + /* Early error: Negative offset */ + ret = bdrv_pwrite(c, -2, buf, sizeof(buf)); + g_assert_cmpint(ret, ==, -EIO); +} + +static void test_sync_op_blk_pread(BlockBackend *blk) +{ + uint8_t buf[512]; + int ret; + + /* Success */ + ret = blk_pread(blk, 0, buf, sizeof(buf)); + g_assert_cmpint(ret, ==, 512); + + /* Early error: Negative offset */ + ret = blk_pread(blk, -2, buf, sizeof(buf)); + g_assert_cmpint(ret, ==, -EIO); +} + +static void test_sync_op_blk_pwrite(BlockBackend *blk) +{ + uint8_t buf[512]; + int ret; + + /* Success */ + ret = blk_pwrite(blk, 0, buf, sizeof(buf), 0); + g_assert_cmpint(ret, ==, 512); + + /* Early error: Negative offset */ + ret = blk_pwrite(blk, -2, buf, sizeof(buf), 0); + g_assert_cmpint(ret, ==, -EIO); +} + +static void test_sync_op_load_vmstate(BdrvChild *c) +{ + uint8_t buf[512]; + int ret; + + /* Error: Driver does not support snapshots */ + ret = bdrv_load_vmstate(c->bs, buf, 0, sizeof(buf)); + g_assert_cmpint(ret, ==, -ENOTSUP); +} + +static void test_sync_op_save_vmstate(BdrvChild *c) +{ + uint8_t buf[512]; + int ret; + + /* Error: Driver does not support snapshots */ + ret = bdrv_save_vmstate(c->bs, buf, 0, sizeof(buf)); + g_assert_cmpint(ret, ==, -ENOTSUP); +} + +static void test_sync_op_pdiscard(BdrvChild *c) +{ + int ret; + + /* Normal success path */ + c->bs->open_flags |= BDRV_O_UNMAP; + ret = bdrv_pdiscard(c, 0, 512); + g_assert_cmpint(ret, ==, 0); + + /* Early success: UNMAP not supported */ + c->bs->open_flags &= ~BDRV_O_UNMAP; + ret = bdrv_pdiscard(c, 0, 512); + g_assert_cmpint(ret, ==, 0); + + /* Early error: Negative offset */ + ret = bdrv_pdiscard(c, -2, 512); + g_assert_cmpint(ret, ==, -EIO); +} + +static void test_sync_op_blk_pdiscard(BlockBackend *blk) +{ + int ret; + + /* Early success: UNMAP not supported */ + ret = blk_pdiscard(blk, 0, 512); + g_assert_cmpint(ret, ==, 0); + + /* Early error: Negative offset */ + ret = blk_pdiscard(blk, -2, 512); + g_assert_cmpint(ret, ==, -EIO); +} + +static void test_sync_op_truncate(BdrvChild *c) +{ + int ret; + + /* Normal success path */ + ret = bdrv_truncate(c, 65536, PREALLOC_MODE_OFF, NULL); + g_assert_cmpint(ret, ==, 0); + + /* Early error: Negative offset */ + ret = bdrv_truncate(c, -2, PREALLOC_MODE_OFF, NULL); + g_assert_cmpint(ret, ==, -EINVAL); + + /* Error: Read-only image */ + c->bs->read_only = true; + c->bs->open_flags &= ~BDRV_O_RDWR; + + ret = bdrv_truncate(c, 65536, PREALLOC_MODE_OFF, NULL); + g_assert_cmpint(ret, ==, -EACCES); + + c->bs->read_only = false; + c->bs->open_flags |= BDRV_O_RDWR; +} + +static void test_sync_op_block_status(BdrvChild *c) +{ + int ret; + int64_t n; + + /* Normal success path */ + ret = bdrv_is_allocated(c->bs, 0, 65536, &n); + g_assert_cmpint(ret, ==, 0); + + /* Early success: No driver support */ + bdrv_test.bdrv_co_block_status = NULL; + ret = bdrv_is_allocated(c->bs, 0, 65536, &n); + g_assert_cmpint(ret, ==, 1); + + /* Early success: bytes = 0 */ + ret = bdrv_is_allocated(c->bs, 0, 0, &n); + g_assert_cmpint(ret, ==, 0); + + /* Early success: Offset > image size*/ + ret = bdrv_is_allocated(c->bs, 0x1000000, 0x1000000, &n); + g_assert_cmpint(ret, ==, 0); +} + +static void test_sync_op_flush(BdrvChild *c) +{ + int ret; + + /* Normal success path */ + ret = bdrv_flush(c->bs); + g_assert_cmpint(ret, ==, 0); + + /* Early success: Read-only image */ + c->bs->read_only = true; + c->bs->open_flags &= ~BDRV_O_RDWR; + + ret = bdrv_flush(c->bs); + g_assert_cmpint(ret, ==, 0); + + c->bs->read_only = false; + c->bs->open_flags |= BDRV_O_RDWR; +} + +static void test_sync_op_blk_flush(BlockBackend *blk) +{ + BlockDriverState *bs = blk_bs(blk); + int ret; + + /* Normal success path */ + ret = blk_flush(blk); + g_assert_cmpint(ret, ==, 0); + + /* Early success: Read-only image */ + bs->read_only = true; + bs->open_flags &= ~BDRV_O_RDWR; + + ret = blk_flush(blk); + g_assert_cmpint(ret, ==, 0); + + bs->read_only = false; + bs->open_flags |= BDRV_O_RDWR; +} + +static void test_sync_op_check(BdrvChild *c) +{ + BdrvCheckResult result; + int ret; + + /* Error: Driver does not implement check */ + ret = bdrv_check(c->bs, &result, 0); + g_assert_cmpint(ret, ==, -ENOTSUP); +} + +static void test_sync_op_invalidate_cache(BdrvChild *c) +{ + /* Early success: Image is not inactive */ + bdrv_invalidate_cache(c->bs, NULL); +} + + +typedef struct SyncOpTest { + const char *name; + void (*fn)(BdrvChild *c); + void (*blkfn)(BlockBackend *blk); +} SyncOpTest; + +const SyncOpTest sync_op_tests[] = { + { + .name = "/sync-op/pread", + .fn = test_sync_op_pread, + .blkfn = test_sync_op_blk_pread, + }, { + .name = "/sync-op/pwrite", + .fn = test_sync_op_pwrite, + .blkfn = test_sync_op_blk_pwrite, + }, { + .name = "/sync-op/load_vmstate", + .fn = test_sync_op_load_vmstate, + }, { + .name = "/sync-op/save_vmstate", + .fn = test_sync_op_save_vmstate, + }, { + .name = "/sync-op/pdiscard", + .fn = test_sync_op_pdiscard, + .blkfn = test_sync_op_blk_pdiscard, + }, { + .name = "/sync-op/truncate", + .fn = test_sync_op_truncate, + }, { + .name = "/sync-op/block_status", + .fn = test_sync_op_block_status, + }, { + .name = "/sync-op/flush", + .fn = test_sync_op_flush, + .blkfn = test_sync_op_blk_flush, + }, { + .name = "/sync-op/check", + .fn = test_sync_op_check, + }, { + .name = "/sync-op/invalidate_cache", + .fn = test_sync_op_invalidate_cache, + }, +}; + +/* Test synchronous operations that run in a different iothread, so we have to + * poll for the coroutine there to return. */ +static void test_sync_op(const void *opaque) +{ + const SyncOpTest *t = opaque; + IOThread *iothread = iothread_new(); + AioContext *ctx = iothread_get_aio_context(iothread); + BlockBackend *blk; + BlockDriverState *bs; + BdrvChild *c; + + blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL); + bs = bdrv_new_open_driver(&bdrv_test, "base", BDRV_O_RDWR, &error_abort); + bs->total_sectors = 65536 / BDRV_SECTOR_SIZE; + blk_insert_bs(blk, bs, &error_abort); + c = QLIST_FIRST(&bs->parents); + + blk_set_aio_context(blk, ctx); + aio_context_acquire(ctx); + t->fn(c); + if (t->blkfn) { + t->blkfn(blk); + } + aio_context_release(ctx); + blk_set_aio_context(blk, qemu_get_aio_context()); + + bdrv_unref(bs); + blk_unref(blk); +} + +int main(int argc, char **argv) +{ + int i; + + bdrv_init(); + qemu_init_main_loop(&error_abort); + + g_test_init(&argc, &argv, NULL); + + for (i = 0; i < ARRAY_SIZE(sync_op_tests); i++) { + const SyncOpTest *t = &sync_op_tests[i]; + g_test_add_data_func(t->name, t, test_sync_op); + } + + return g_test_run(); +} diff --git a/tests/vmgenid-test.c b/tests/vmgenid-test.c index 52cdd83ec0..ae38ee5ac0 100644 --- a/tests/vmgenid-test.c +++ b/tests/vmgenid-test.c @@ -88,7 +88,7 @@ static void read_guid_from_memory(QTestState *qts, QemuUUID *guid) /* The GUID is in little-endian format in the guest, while QEMU * uses big-endian. Swap after reading. */ - qemu_uuid_bswap(guid); + *guid = qemu_uuid_bswap(*guid); } static void read_guid_from_monitor(QTestState *qts, QemuUUID *guid) |