diff options
author | Don Dugger <n0ano@n0ano.com> | 2016-06-03 03:33:22 +0000 |
---|---|---|
committer | Gerrit Code Review <gerrit@172.30.200.206> | 2016-06-03 03:33:23 +0000 |
commit | da27230f80795d0028333713f036d44c53cb0e68 (patch) | |
tree | b3d379eaf000adf72b36cb01cdf4d79c3e3f064c /qemu/tests | |
parent | 0e68cb048bb8aadb14675f5d4286d8ab2fc35449 (diff) | |
parent | 437fd90c0250dee670290f9b714253671a990160 (diff) |
Merge "These changes are the raw update to qemu-2.6."
Diffstat (limited to 'qemu/tests')
612 files changed, 27067 insertions, 3296 deletions
diff --git a/qemu/tests/.gitignore b/qemu/tests/.gitignore index ccc92e476..9eed22988 100644 --- a/qemu/tests/.gitignore +++ b/qemu/tests/.gitignore @@ -8,14 +8,38 @@ check-qom-interface check-qom-proplist rcutorture test-aio +test-base64 test-bitops +test-blockjob-txn test-coroutine +test-crypto-afsplit +test-crypto-block test-crypto-cipher test-crypto-hash +test-crypto-ivgen +test-crypto-pbkdf +test-crypto-secret +test-crypto-tlscredsx509 +test-crypto-tlscredsx509-work/ +test-crypto-tlscredsx509-certs/ +test-crypto-tlssession +test-crypto-tlssession-work/ +test-crypto-tlssession-client/ +test-crypto-tlssession-server/ +test-crypto-xts test-cutils test-hbitmap test-int128 test-iov +test-io-channel-buffer +test-io-channel-command +test-io-channel-command.fifo +test-io-channel-file +test-io-channel-file.txt +test-io-channel-socket +test-io-channel-tls +test-io-task +test-logging test-mul64 test-opts-visitor test-qapi-event.[ch] @@ -23,11 +47,13 @@ test-qapi-types.[ch] test-qapi-visit.[ch] test-qdev-global-props test-qemu-opts +test-qga test-qmp-commands test-qmp-commands.h test-qmp-event test-qmp-input-strict test-qmp-input-visitor +test-qmp-introspect.[ch] test-qmp-marshal.c test-qmp-output-visitor test-rcu-list @@ -36,10 +62,14 @@ test-string-input-visitor test-string-output-visitor test-thread-pool test-throttle +test-timed-average test-visitor-serialization test-vmstate test-write-threshold test-x86-cpuid test-xbzrle +test-netfilter +test-filter-mirror +test-filter-redirector *-test qapi-schema/*.test.* diff --git a/qemu/tests/Makefile b/qemu/tests/Makefile index 749458224..9194f1850 100644 --- a/qemu/tests/Makefile +++ b/qemu/tests/Makefile @@ -1,5 +1,7 @@ export SRC_PATH +qapi-py = $(SRC_PATH)/scripts/qapi.py $(SRC_PATH)/scripts/ordereddict.py + # Get the list of all supported sysemu targets SYSEMU_TARGET_LIST := $(subst -softmmu.mak,,$(notdir \ $(wildcard $(SRC_PATH)/default-configs/*-softmmu.mak))) @@ -45,6 +47,8 @@ check-unit-y += tests/test-thread-pool$(EXESUF) gcov-files-test-thread-pool-y = thread-pool.c gcov-files-test-hbitmap-y = util/hbitmap.c check-unit-y += tests/test-hbitmap$(EXESUF) +gcov-files-test-hbitmap-y = blockjob.c +check-unit-y += tests/test-blockjob-txn$(EXESUF) check-unit-y += tests/test-x86-cpuid$(EXESUF) # all code tested by test-x86-cpuid is inside topology.h gcov-files-test-x86-cpuid-y = @@ -76,12 +80,36 @@ check-unit-y += tests/test-write-threshold$(EXESUF) gcov-files-test-write-threshold-y = block/write-threshold.c check-unit-$(CONFIG_GNUTLS_HASH) += tests/test-crypto-hash$(EXESUF) check-unit-y += tests/test-crypto-cipher$(EXESUF) +check-unit-y += tests/test-crypto-secret$(EXESUF) +check-unit-$(CONFIG_GNUTLS) += tests/test-crypto-tlscredsx509$(EXESUF) +check-unit-$(CONFIG_GNUTLS) += tests/test-crypto-tlssession$(EXESUF) +ifneq (,$(findstring qemu-ga,$(TOOLS))) +check-unit-$(CONFIG_LINUX) += tests/test-qga$(EXESUF) +endif +check-unit-y += tests/test-timed-average$(EXESUF) +check-unit-y += tests/test-io-task$(EXESUF) +check-unit-y += tests/test-io-channel-socket$(EXESUF) +check-unit-y += tests/test-io-channel-file$(EXESUF) +check-unit-$(CONFIG_GNUTLS) += tests/test-io-channel-tls$(EXESUF) +check-unit-y += tests/test-io-channel-command$(EXESUF) +check-unit-y += tests/test-io-channel-buffer$(EXESUF) +check-unit-y += tests/test-base64$(EXESUF) +check-unit-$(if $(CONFIG_NETTLE_KDF),y,$(CONFIG_GCRYPT_KDF)) += tests/test-crypto-pbkdf$(EXESUF) +check-unit-y += tests/test-crypto-ivgen$(EXESUF) +check-unit-y += tests/test-crypto-afsplit$(EXESUF) +check-unit-y += tests/test-crypto-xts$(EXESUF) +check-unit-y += tests/test-crypto-block$(EXESUF) +gcov-files-test-logging-y = tests/test-logging.c +check-unit-y += tests/test-logging$(EXESUF) check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh # All QTests for now are POSIX-only, but the dependencies are # really in libqtest, not in the testcases themselves. +check-qtest-generic-y = tests/device-introspect-test$(EXESUF) +gcov-files-generic-y = qdev-monitor.c qmp.c + gcov-files-ipack-y += hw/ipack/ipack.c check-qtest-ipack-y += tests/ipoctal232-test$(EXESUF) gcov-files-ipack-y += hw/char/ipoctal232.c @@ -142,6 +170,8 @@ gcov-files-pci-y += hw/display/virtio-gpu-pci.c gcov-files-pci-$(CONFIG_VIRTIO_VGA) += hw/display/virtio-vga.c check-qtest-pci-y += tests/intel-hda-test$(EXESUF) gcov-files-pci-y += hw/audio/intel-hda.c hw/audio/hda-codec.c +check-qtest-pci-$(CONFIG_EVENTFD) += tests/ivshmem-test$(EXESUF) +gcov-files-pci-y += hw/misc/ivshmem.c check-qtest-i386-y = tests/endianness-test$(EXESUF) check-qtest-i386-y += tests/fdc-test$(EXESUF) @@ -152,7 +182,10 @@ check-qtest-i386-y += tests/hd-geo-test$(EXESUF) gcov-files-i386-y += hw/block/hd-geometry.c check-qtest-i386-y += tests/boot-order-test$(EXESUF) check-qtest-i386-y += tests/bios-tables-test$(EXESUF) +check-qtest-i386-y += tests/pxe-test$(EXESUF) check-qtest-i386-y += tests/rtc-test$(EXESUF) +check-qtest-i386-y += tests/ipmi-kcs-test$(EXESUF) +check-qtest-i386-y += tests/ipmi-bt-test$(EXESUF) check-qtest-i386-y += tests/i440fx-test$(EXESUF) check-qtest-i386-y += tests/fw_cfg-test$(EXESUF) check-qtest-i386-y += tests/drive_del-test$(EXESUF) @@ -184,7 +217,13 @@ gcov-files-i386-y += hw/usb/hcd-xhci.c check-qtest-i386-y += tests/pc-cpu-test$(EXESUF) check-qtest-i386-y += tests/q35-test$(EXESUF) gcov-files-i386-y += hw/pci-host/q35.c -check-qtest-i386-$(CONFIG_LINUX) += tests/vhost-user-test$(EXESUF) +check-qtest-i386-$(CONFIG_VHOST_NET_TEST_i386) += tests/vhost-user-test$(EXESUF) +ifeq ($(CONFIG_VHOST_NET_TEST_i386),) +check-qtest-x86_64-$(CONFIG_VHOST_NET_TEST_x86_64) += tests/vhost-user-test$(EXESUF) +endif +check-qtest-i386-y += tests/test-netfilter$(EXESUF) +check-qtest-i386-y += tests/test-filter-mirror$(EXESUF) +check-qtest-i386-y += tests/test-filter-redirector$(EXESUF) check-qtest-x86_64-y = $(check-qtest-i386-y) gcov-files-i386-y += i386-softmmu/hw/timer/mc146818rtc.c gcov-files-x86_64-y = $(subst i386-softmmu/,x86_64-softmmu/,$(gcov-files-i386-y)) @@ -201,6 +240,7 @@ check-qtest-sparc64-y = tests/endianness-test$(EXESUF) gcov-files-sparc-y += hw/timer/m48t59.c gcov-files-sparc64-y += hw/timer/m48t59.c check-qtest-arm-y = tests/tmp105-test$(EXESUF) +check-qtest-arm-y = tests/ds1338-test$(EXESUF) gcov-files-arm-y += hw/misc/tmp105.c check-qtest-arm-y += tests/virtio-blk-test$(EXESUF) gcov-files-arm-y += arm-softmmu/hw/block/virtio-blk.c @@ -211,54 +251,135 @@ gcov-files-ppc64-y += ppc64-softmmu/hw/ppc/spapr_pci.c check-qtest-microblazeel-y = $(check-qtest-microblaze-y) check-qtest-xtensaeb-y = $(check-qtest-xtensa-y) -# qom-test works for all sysemu architectures: -$(foreach target,$(SYSEMU_TARGET_LIST), \ - $(if $(findstring tests/qom-test$(EXESUF), $(check-qtest-$(target)-y)),, \ - $(eval check-qtest-$(target)-y += tests/qom-test$(EXESUF)))) - -check-qapi-schema-y := $(addprefix tests/qapi-schema/, \ - comments.json empty.json enum-empty.json enum-missing-data.json \ - enum-wrong-data.json enum-int-member.json enum-dict-member.json \ - enum-clash-member.json enum-max-member.json enum-union-clash.json \ - enum-bad-name.json funny-char.json indented-expr.json \ - missing-type.json bad-ident.json ident-with-escape.json \ - escape-outside-string.json unknown-escape.json \ - escape-too-short.json escape-too-big.json unicode-str.json \ - double-type.json bad-base.json bad-type-bool.json bad-type-int.json \ - bad-type-dict.json double-data.json unknown-expr-key.json \ - redefined-type.json redefined-command.json redefined-builtin.json \ - redefined-event.json command-int.json bad-data.json event-max.json \ - type-bypass.json type-bypass-no-gen.json type-bypass-bad-gen.json \ - data-array-empty.json data-array-unknown.json data-int.json \ - data-unknown.json data-member-unknown.json data-member-array.json \ - data-member-array-bad.json returns-array-bad.json returns-int.json \ - returns-unknown.json returns-alternate.json returns-whitelist.json \ - missing-colon.json missing-comma-list.json missing-comma-object.json \ - nested-struct-data.json nested-struct-returns.json non-objects.json \ - qapi-schema-test.json quoted-structural-chars.json \ - trailing-comma-list.json trailing-comma-object.json \ - unclosed-list.json unclosed-object.json unclosed-string.json \ - duplicate-key.json union-invalid-base.json union-bad-branch.json \ - union-optional-branch.json union-unknown.json union-max.json \ - flat-union-optional-discriminator.json flat-union-no-base.json \ - flat-union-invalid-discriminator.json flat-union-inline.json \ - flat-union-invalid-branch-key.json flat-union-reverse-define.json \ - flat-union-string-discriminator.json union-base-no-discriminator.json \ - flat-union-bad-discriminator.json flat-union-bad-base.json \ - flat-union-base-star.json \ - flat-union-array-branch.json flat-union-int-branch.json \ - flat-union-base-union.json flat-union-branch-clash.json \ - alternate-nested.json alternate-unknown.json alternate-clash.json \ - alternate-good.json alternate-base.json alternate-array.json \ - alternate-conflict-string.json alternate-conflict-dict.json \ - include-simple.json include-relpath.json include-format-err.json \ - include-non-file.json include-no-file.json include-before-err.json \ - include-nested-err.json include-self-cycle.json include-cycle.json \ - include-repetition.json event-nest-struct.json event-case.json \ - struct-base-clash.json struct-base-clash-deep.json ) +check-qtest-generic-y += tests/qom-test$(EXESUF) + +qapi-schema += alternate-any.json +qapi-schema += alternate-array.json +qapi-schema += alternate-base.json +qapi-schema += alternate-clash.json +qapi-schema += alternate-conflict-dict.json +qapi-schema += alternate-conflict-string.json +qapi-schema += alternate-empty.json +qapi-schema += alternate-nested.json +qapi-schema += alternate-unknown.json +qapi-schema += args-alternate.json +qapi-schema += args-any.json +qapi-schema += args-array-empty.json +qapi-schema += args-array-unknown.json +qapi-schema += args-int.json +qapi-schema += args-invalid.json +qapi-schema += args-member-array-bad.json +qapi-schema += args-member-case.json +qapi-schema += args-member-unknown.json +qapi-schema += args-name-clash.json +qapi-schema += args-union.json +qapi-schema += args-unknown.json +qapi-schema += bad-base.json +qapi-schema += bad-data.json +qapi-schema += bad-ident.json +qapi-schema += bad-type-bool.json +qapi-schema += bad-type-dict.json +qapi-schema += bad-type-int.json +qapi-schema += base-cycle-direct.json +qapi-schema += base-cycle-indirect.json +qapi-schema += command-int.json +qapi-schema += comments.json +qapi-schema += double-data.json +qapi-schema += double-type.json +qapi-schema += duplicate-key.json +qapi-schema += empty.json +qapi-schema += enum-bad-name.json +qapi-schema += enum-bad-prefix.json +qapi-schema += enum-clash-member.json +qapi-schema += enum-dict-member.json +qapi-schema += enum-int-member.json +qapi-schema += enum-member-case.json +qapi-schema += enum-missing-data.json +qapi-schema += enum-wrong-data.json +qapi-schema += escape-outside-string.json +qapi-schema += escape-too-big.json +qapi-schema += escape-too-short.json +qapi-schema += event-case.json +qapi-schema += event-nest-struct.json +qapi-schema += flat-union-array-branch.json +qapi-schema += flat-union-bad-base.json +qapi-schema += flat-union-bad-discriminator.json +qapi-schema += flat-union-base-any.json +qapi-schema += flat-union-base-union.json +qapi-schema += flat-union-clash-member.json +qapi-schema += flat-union-empty.json +qapi-schema += flat-union-inline.json +qapi-schema += flat-union-int-branch.json +qapi-schema += flat-union-invalid-branch-key.json +qapi-schema += flat-union-invalid-discriminator.json +qapi-schema += flat-union-no-base.json +qapi-schema += flat-union-optional-discriminator.json +qapi-schema += flat-union-string-discriminator.json +qapi-schema += funny-char.json +qapi-schema += ident-with-escape.json +qapi-schema += include-before-err.json +qapi-schema += include-cycle.json +qapi-schema += include-format-err.json +qapi-schema += include-nested-err.json +qapi-schema += include-no-file.json +qapi-schema += include-non-file.json +qapi-schema += include-relpath.json +qapi-schema += include-repetition.json +qapi-schema += include-self-cycle.json +qapi-schema += include-simple.json +qapi-schema += indented-expr.json +qapi-schema += leading-comma-list.json +qapi-schema += leading-comma-object.json +qapi-schema += missing-colon.json +qapi-schema += missing-comma-list.json +qapi-schema += missing-comma-object.json +qapi-schema += missing-type.json +qapi-schema += nested-struct-data.json +qapi-schema += non-objects.json +qapi-schema += qapi-schema-test.json +qapi-schema += quoted-structural-chars.json +qapi-schema += redefined-builtin.json +qapi-schema += redefined-command.json +qapi-schema += redefined-event.json +qapi-schema += redefined-type.json +qapi-schema += reserved-command-q.json +qapi-schema += reserved-enum-q.json +qapi-schema += reserved-member-has.json +qapi-schema += reserved-member-q.json +qapi-schema += reserved-member-u.json +qapi-schema += reserved-member-underscore.json +qapi-schema += reserved-type-kind.json +qapi-schema += reserved-type-list.json +qapi-schema += returns-alternate.json +qapi-schema += returns-array-bad.json +qapi-schema += returns-dict.json +qapi-schema += returns-unknown.json +qapi-schema += returns-whitelist.json +qapi-schema += struct-base-clash-deep.json +qapi-schema += struct-base-clash.json +qapi-schema += struct-data-invalid.json +qapi-schema += struct-member-invalid.json +qapi-schema += trailing-comma-list.json +qapi-schema += trailing-comma-object.json +qapi-schema += type-bypass-bad-gen.json +qapi-schema += unclosed-list.json +qapi-schema += unclosed-object.json +qapi-schema += unclosed-string.json +qapi-schema += unicode-str.json +qapi-schema += union-base-no-discriminator.json +qapi-schema += union-branch-case.json +qapi-schema += union-clash-branches.json +qapi-schema += union-empty.json +qapi-schema += union-invalid-base.json +qapi-schema += union-optional-branch.json +qapi-schema += union-unknown.json +qapi-schema += unknown-escape.json +qapi-schema += unknown-expr-key.json +check-qapi-schema-y := $(addprefix tests/qapi-schema/, $(qapi-schema)) GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h \ - tests/test-qmp-commands.h tests/test-qapi-event.h + tests/test-qmp-commands.h tests/test-qapi-event.h \ + tests/test-qmp-introspect.h test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \ tests/check-qlist.o tests/check-qfloat.o tests/check-qjson.o \ @@ -270,48 +391,59 @@ test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \ tests/test-opts-visitor.o tests/test-qmp-event.o \ tests/rcutorture.o tests/test-rcu-list.o -test-qapi-obj-y = tests/test-qapi-visit.o tests/test-qapi-types.o \ - tests/test-qapi-event.o - $(test-obj-y): QEMU_INCLUDES += -Itests QEMU_CFLAGS += -I$(SRC_PATH)/tests -qom-core-obj = qom/object.o qom/qom-qobject.o qom/container.o qom/object_interfaces.o - -tests/check-qint$(EXESUF): tests/check-qint.o libqemuutil.a -tests/check-qstring$(EXESUF): tests/check-qstring.o libqemuutil.a -tests/check-qdict$(EXESUF): tests/check-qdict.o libqemuutil.a -tests/check-qlist$(EXESUF): tests/check-qlist.o libqemuutil.a -tests/check-qfloat$(EXESUF): tests/check-qfloat.o libqemuutil.a -tests/check-qjson$(EXESUF): tests/check-qjson.o libqemuutil.a libqemustub.a -tests/check-qom-interface$(EXESUF): tests/check-qom-interface.o $(qom-core-obj) libqemuutil.a libqemustub.a -tests/check-qom-proplist$(EXESUF): tests/check-qom-proplist.o $(qom-core-obj) libqemuutil.a libqemustub.a -tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(block-obj-y) libqemuutil.a libqemustub.a -tests/test-aio$(EXESUF): tests/test-aio.o $(block-obj-y) libqemuutil.a libqemustub.a -tests/test-rfifolock$(EXESUF): tests/test-rfifolock.o libqemuutil.a libqemustub.a -tests/test-throttle$(EXESUF): tests/test-throttle.o $(block-obj-y) libqemuutil.a libqemustub.a -tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(block-obj-y) libqemuutil.a libqemustub.a -tests/test-iov$(EXESUF): tests/test-iov.o libqemuutil.a -tests/test-hbitmap$(EXESUF): tests/test-hbitmap.o libqemuutil.a libqemustub.a + + +# Deps that are common to various different sets of tests below +test-util-obj-y = libqemuutil.a libqemustub.a +test-qom-obj-y = $(qom-obj-y) $(test-util-obj-y) +test-qapi-obj-y = tests/test-qapi-visit.o tests/test-qapi-types.o \ + tests/test-qapi-event.o tests/test-qmp-introspect.o \ + $(test-qom-obj-y) +test-crypto-obj-y = $(crypto-obj-y) $(test-qom-obj-y) +test-io-obj-y = $(io-obj-y) $(test-crypto-obj-y) +test-block-obj-y = $(block-obj-y) $(test-io-obj-y) + +tests/check-qint$(EXESUF): tests/check-qint.o $(test-util-obj-y) +tests/check-qstring$(EXESUF): tests/check-qstring.o $(test-util-obj-y) +tests/check-qdict$(EXESUF): tests/check-qdict.o $(test-util-obj-y) +tests/check-qlist$(EXESUF): tests/check-qlist.o $(test-util-obj-y) +tests/check-qfloat$(EXESUF): tests/check-qfloat.o $(test-util-obj-y) +tests/check-qjson$(EXESUF): tests/check-qjson.o $(test-util-obj-y) +tests/check-qom-interface$(EXESUF): tests/check-qom-interface.o $(test-qom-obj-y) +tests/check-qom-proplist$(EXESUF): tests/check-qom-proplist.o $(test-qom-obj-y) +tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(test-block-obj-y) +tests/test-aio$(EXESUF): tests/test-aio.o $(test-block-obj-y) +tests/test-rfifolock$(EXESUF): tests/test-rfifolock.o $(test-util-obj-y) +tests/test-throttle$(EXESUF): tests/test-throttle.o $(test-block-obj-y) +tests/test-blockjob-txn$(EXESUF): tests/test-blockjob-txn.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) +tests/test-hbitmap$(EXESUF): tests/test-hbitmap.o $(test-util-obj-y) tests/test-x86-cpuid$(EXESUF): tests/test-x86-cpuid.o -tests/test-xbzrle$(EXESUF): tests/test-xbzrle.o migration/xbzrle.o page_cache.o libqemuutil.a +tests/test-xbzrle$(EXESUF): tests/test-xbzrle.o migration/xbzrle.o page_cache.o $(test-util-obj-y) tests/test-cutils$(EXESUF): tests/test-cutils.o util/cutils.o tests/test-int128$(EXESUF): tests/test-int128.o -tests/rcutorture$(EXESUF): tests/rcutorture.o libqemuutil.a libqemustub.a -tests/test-rcu-list$(EXESUF): tests/test-rcu-list.o libqemuutil.a libqemustub.a +tests/rcutorture$(EXESUF): tests/rcutorture.o $(test-util-obj-y) +tests/test-rcu-list$(EXESUF): tests/test-rcu-list.o $(test-util-obj-y) tests/test-qdev-global-props$(EXESUF): tests/test-qdev-global-props.o \ hw/core/qdev.o hw/core/qdev-properties.o hw/core/hotplug.o\ hw/core/irq.o \ hw/core/fw-path-provider.o \ - $(qom-core-obj) \ - $(test-qapi-obj-y) \ - libqemuutil.a libqemustub.a + $(test-qapi-obj-y) tests/test-vmstate$(EXESUF): tests/test-vmstate.o \ migration/vmstate.o migration/qemu-file.o migration/qemu-file-buf.o \ migration/qemu-file-unix.o qjson.o \ - $(qom-core-obj) \ + $(test-qom-obj-y) +tests/test-timed-average$(EXESUF): tests/test-timed-average.o qemu-timer.o \ + $(test-util-obj-y) +tests/test-base64$(EXESUF): tests/test-base64.o \ libqemuutil.a libqemustub.a +tests/test-logging$(EXESUF): tests/test-logging.o $(test-util-obj-y) + tests/test-qapi-types.c tests/test-qapi-types.h :\ $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py) $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py \ @@ -332,21 +464,56 @@ $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-eve $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-event.py \ $(gen-out-type) -o tests -p "test-" $<, \ " GEN $@") +tests/test-qmp-introspect.c tests/test-qmp-introspect.h :\ +$(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-introspect.py $(qapi-py) + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-introspect.py \ + $(gen-out-type) -o tests -p "test-" $<, \ + " GEN $@") -tests/test-string-output-visitor$(EXESUF): tests/test-string-output-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a -tests/test-string-input-visitor$(EXESUF): tests/test-string-input-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a -tests/test-qmp-event$(EXESUF): tests/test-qmp-event.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a -tests/test-qmp-output-visitor$(EXESUF): tests/test-qmp-output-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a -tests/test-qmp-input-visitor$(EXESUF): tests/test-qmp-input-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a -tests/test-qmp-input-strict$(EXESUF): tests/test-qmp-input-strict.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a -tests/test-qmp-commands$(EXESUF): tests/test-qmp-commands.o tests/test-qmp-marshal.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a -tests/test-visitor-serialization$(EXESUF): tests/test-visitor-serialization.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a -tests/test-opts-visitor$(EXESUF): tests/test-opts-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a - -tests/test-mul64$(EXESUF): tests/test-mul64.o libqemuutil.a -tests/test-bitops$(EXESUF): tests/test-bitops.o libqemuutil.a -tests/test-crypto-hash$(EXESUF): tests/test-crypto-hash.o libqemuutil.a libqemustub.a -tests/test-crypto-cipher$(EXESUF): tests/test-crypto-cipher.o libqemuutil.a libqemustub.a +tests/test-string-output-visitor$(EXESUF): tests/test-string-output-visitor.o $(test-qapi-obj-y) +tests/test-string-input-visitor$(EXESUF): tests/test-string-input-visitor.o $(test-qapi-obj-y) +tests/test-qmp-event$(EXESUF): tests/test-qmp-event.o $(test-qapi-obj-y) +tests/test-qmp-output-visitor$(EXESUF): tests/test-qmp-output-visitor.o $(test-qapi-obj-y) +tests/test-qmp-input-visitor$(EXESUF): tests/test-qmp-input-visitor.o $(test-qapi-obj-y) +tests/test-qmp-input-strict$(EXESUF): tests/test-qmp-input-strict.o $(test-qapi-obj-y) +tests/test-qmp-commands$(EXESUF): tests/test-qmp-commands.o tests/test-qmp-marshal.o $(test-qapi-obj-y) +tests/test-visitor-serialization$(EXESUF): tests/test-visitor-serialization.o $(test-qapi-obj-y) +tests/test-opts-visitor$(EXESUF): tests/test-opts-visitor.o $(test-qapi-obj-y) + +tests/test-mul64$(EXESUF): tests/test-mul64.o $(test-util-obj-y) +tests/test-bitops$(EXESUF): tests/test-bitops.o $(test-util-obj-y) +tests/test-crypto-hash$(EXESUF): tests/test-crypto-hash.o $(test-crypto-obj-y) +tests/test-crypto-cipher$(EXESUF): tests/test-crypto-cipher.o $(test-crypto-obj-y) +tests/test-crypto-secret$(EXESUF): tests/test-crypto-secret.o $(test-crypto-obj-y) +tests/test-crypto-xts$(EXESUF): tests/test-crypto-xts.o $(test-crypto-obj-y) + +tests/crypto-tls-x509-helpers.o-cflags := $(TASN1_CFLAGS) +tests/crypto-tls-x509-helpers.o-libs := $(TASN1_LIBS) +tests/pkix_asn1_tab.o-cflags := $(TASN1_CFLAGS) + +tests/test-crypto-tlscredsx509.o-cflags := $(TASN1_CFLAGS) +tests/test-crypto-tlscredsx509$(EXESUF): tests/test-crypto-tlscredsx509.o \ + tests/crypto-tls-x509-helpers.o tests/pkix_asn1_tab.o $(test-crypto-obj-y) + +tests/test-crypto-tlssession.o-cflags := $(TASN1_CFLAGS) +tests/test-crypto-tlssession$(EXESUF): tests/test-crypto-tlssession.o \ + tests/crypto-tls-x509-helpers.o tests/pkix_asn1_tab.o $(test-crypto-obj-y) +tests/test-io-task$(EXESUF): tests/test-io-task.o $(test-io-obj-y) +tests/test-io-channel-socket$(EXESUF): tests/test-io-channel-socket.o \ + tests/io-channel-helpers.o $(test-io-obj-y) +tests/test-io-channel-file$(EXESUF): tests/test-io-channel-file.o \ + tests/io-channel-helpers.o $(test-io-obj-y) +tests/test-io-channel-tls$(EXESUF): tests/test-io-channel-tls.o \ + tests/crypto-tls-x509-helpers.o tests/pkix_asn1_tab.o \ + tests/io-channel-helpers.o $(test-io-obj-y) +tests/test-io-channel-command$(EXESUF): tests/test-io-channel-command.o \ + tests/io-channel-helpers.o $(test-io-obj-y) +tests/test-io-channel-buffer$(EXESUF): tests/test-io-channel-buffer.o \ + tests/io-channel-helpers.o $(test-io-obj-y) +tests/test-crypto-pbkdf$(EXESUF): tests/test-crypto-pbkdf.o $(test-crypto-obj-y) +tests/test-crypto-ivgen$(EXESUF): tests/test-crypto-ivgen.o $(test-crypto-obj-y) +tests/test-crypto-afsplit$(EXESUF): tests/test-crypto-afsplit.o $(test-crypto-obj-y) +tests/test-crypto-block$(EXESUF): tests/test-crypto-block.o $(test-crypto-obj-y) libqos-obj-y = tests/libqos/pci.o tests/libqos/fw_cfg.o tests/libqos/malloc.o libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o @@ -354,9 +521,11 @@ libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o libqos-pc-obj-y += tests/libqos/ahci.o libqos-omap-obj-y = $(libqos-obj-y) tests/libqos/i2c-omap.o +libqos-imx-obj-y = $(libqos-obj-y) tests/libqos/i2c-imx.o libqos-usb-obj-y = $(libqos-pc-obj-y) tests/libqos/usb.o libqos-virtio-obj-y = $(libqos-pc-obj-y) tests/libqos/virtio.o tests/libqos/virtio-pci.o tests/libqos/virtio-mmio.o tests/libqos/malloc-generic.o +tests/device-introspect-test$(EXESUF): tests/device-introspect-test.o tests/rtc-test$(EXESUF): tests/rtc-test.o tests/m48t59-test$(EXESUF): tests/m48t59-test.o tests/endianness-test$(EXESUF): tests/endianness-test.o @@ -364,10 +533,15 @@ tests/spapr-phb-test$(EXESUF): tests/spapr-phb-test.o $(libqos-obj-y) tests/fdc-test$(EXESUF): tests/fdc-test.o tests/ide-test$(EXESUF): tests/ide-test.o $(libqos-pc-obj-y) tests/ahci-test$(EXESUF): tests/ahci-test.o $(libqos-pc-obj-y) +tests/ipmi-kcs-test$(EXESUF): tests/ipmi-kcs-test.o +tests/ipmi-bt-test$(EXESUF): tests/ipmi-bt-test.o tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o tests/boot-order-test$(EXESUF): tests/boot-order-test.o $(libqos-obj-y) -tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o $(libqos-obj-y) +tests/bios-tables-test$(EXESUF): tests/bios-tables-test.o \ + tests/boot-sector.o $(libqos-obj-y) +tests/pxe-test$(EXESUF): tests/pxe-test.o tests/boot-sector.o $(libqos-obj-y) tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y) +tests/ds1338-test$(EXESUF): tests/ds1338-test.o $(libqos-imx-obj-y) tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y) tests/q35-test$(EXESUF): tests/q35-test.o $(libqos-pc-obj-y) tests/fw_cfg-test$(EXESUF): tests/fw_cfg-test.o $(libqos-pc-obj-y) @@ -381,7 +555,7 @@ tests/wdt_ib700-test$(EXESUF): tests/wdt_ib700-test.o tests/tco-test$(EXESUF): tests/tco-test.o $(libqos-pc-obj-y) tests/virtio-balloon-test$(EXESUF): tests/virtio-balloon-test.o tests/virtio-blk-test$(EXESUF): tests/virtio-blk-test.o $(libqos-virtio-obj-y) -tests/virtio-net-test$(EXESUF): tests/virtio-net-test.o $(libqos-pc-obj-y) +tests/virtio-net-test$(EXESUF): tests/virtio-net-test.o $(libqos-pc-obj-y) $(libqos-virtio-obj-y) tests/virtio-rng-test$(EXESUF): tests/virtio-rng-test.o $(libqos-pc-obj-y) tests/virtio-scsi-test$(EXESUF): tests/virtio-scsi-test.o $(libqos-virtio-obj-y) tests/virtio-9p-test$(EXESUF): tests/virtio-9p-test.o @@ -405,10 +579,15 @@ tests/usb-hcd-uhci-test$(EXESUF): tests/usb-hcd-uhci-test.o $(libqos-usb-obj-y) tests/usb-hcd-ehci-test$(EXESUF): tests/usb-hcd-ehci-test.o $(libqos-usb-obj-y) tests/usb-hcd-xhci-test$(EXESUF): tests/usb-hcd-xhci-test.o $(libqos-usb-obj-y) tests/pc-cpu-test$(EXESUF): tests/pc-cpu-test.o -tests/vhost-user-test$(EXESUF): tests/vhost-user-test.o qemu-char.o qemu-timer.o $(qtest-obj-y) +tests/vhost-user-test$(EXESUF): tests/vhost-user-test.o qemu-char.o qemu-timer.o $(qtest-obj-y) $(test-io-obj-y) tests/qemu-iotests/socket_scm_helper$(EXESUF): tests/qemu-iotests/socket_scm_helper.o -tests/test-qemu-opts$(EXESUF): tests/test-qemu-opts.o libqemuutil.a libqemustub.a -tests/test-write-threshold$(EXESUF): tests/test-write-threshold.o $(block-obj-y) libqemuutil.a libqemustub.a +tests/test-qemu-opts$(EXESUF): tests/test-qemu-opts.o $(test-util-obj-y) +tests/test-write-threshold$(EXESUF): tests/test-write-threshold.o $(test-block-obj-y) +tests/test-netfilter$(EXESUF): tests/test-netfilter.o $(qtest-obj-y) +tests/test-filter-mirror$(EXESUF): tests/test-filter-mirror.o $(qtest-obj-y) +tests/test-filter-redirector$(EXESUF): tests/test-filter-redirector.o $(qtest-obj-y) +tests/ivshmem-test$(EXESUF): tests/ivshmem-test.o contrib/ivshmem-server/ivshmem-server.o $(libqos-pc-obj-y) +tests/vhost-user-bridge$(EXESUF): tests/vhost-user-bridge.o ifeq ($(CONFIG_POSIX),y) LIBS += -lutil @@ -418,13 +597,18 @@ endif TARGETS=$(patsubst %-softmmu,%, $(filter %-softmmu,$(TARGET_DIRS))) ifeq ($(CONFIG_POSIX),y) -QTEST_TARGETS=$(foreach TARGET,$(TARGETS), $(if $(check-qtest-$(TARGET)-y), $(TARGET),)) +QTEST_TARGETS = $(TARGETS) check-qtest-y=$(foreach TARGET,$(TARGETS), $(check-qtest-$(TARGET)-y)) +check-qtest-y += $(check-qtest-generic-y) +else +QTEST_TARGETS = endif -qtest-obj-y = tests/libqtest.o libqemuutil.a libqemustub.a +qtest-obj-y = tests/libqtest.o $(test-util-obj-y) $(check-qtest-y): $(qtest-obj-y) +tests/test-qga: tests/test-qga.o $(qtest-obj-y) + .PHONY: check-help check-help: @echo "Regression testing targets:" @@ -457,8 +641,8 @@ $(patsubst %, check-qtest-%, $(QTEST_TARGETS)): check-qtest-%: $(check-qtest-y) $(call quiet-command,QTEST_QEMU_BINARY=$*-softmmu/qemu-system-$* \ QTEST_QEMU_IMG=qemu-img$(EXESUF) \ MALLOC_PERTURB_=$${MALLOC_PERTURB_:-$$((RANDOM % 255 + 1))} \ - gtester $(GTESTER_OPTIONS) -m=$(SPEED) $(check-qtest-$*-y),"GTESTER $@") - $(if $(CONFIG_GCOV),@for f in $(gcov-files-$*-y); do \ + gtester $(GTESTER_OPTIONS) -m=$(SPEED) $(check-qtest-$*-y) $(check-qtest-generic-y),"GTESTER $@") + $(if $(CONFIG_GCOV),@for f in $(gcov-files-$*-y) $(gcov-files-generic-y); do \ echo Gcov report for $$f:;\ $(GCOV) $(GCOV_OPTIONS) $$f -o `dirname $$f`; \ done,) @@ -469,7 +653,7 @@ $(patsubst %, check-%, $(check-unit-y)): check-%: % $(call quiet-command, \ MALLOC_PERTURB_=$${MALLOC_PERTURB_:-$$((RANDOM % 255 + 1))} \ gtester $(GTESTER_OPTIONS) -m=$(SPEED) $*,"GTESTER $*") - $(if $(CONFIG_GCOV),@for f in $(gcov-files-$(subst tests/,,$*)-y); do \ + $(if $(CONFIG_GCOV),@for f in $(gcov-files-$(subst tests/,,$*)-y) $(gcov-files-generic-y); do \ echo Gcov report for $$f:;\ $(GCOV) $(GCOV_OPTIONS) $$f -o `dirname $$f`; \ done,) @@ -479,7 +663,7 @@ $(patsubst %, check-%, $(check-unit-y)): check-%: % $(patsubst %, check-report-qtest-%.xml, $(QTEST_TARGETS)): check-report-qtest-%.xml: $(check-qtest-y) $(call quiet-command,QTEST_QEMU_BINARY=$*-softmmu/qemu-system-$* \ QTEST_QEMU_IMG=qemu-img$(EXESUF) \ - gtester -q $(GTESTER_OPTIONS) -o $@ -m=$(SPEED) $(check-qtest-$*-y),"GTESTER $@") + gtester -q $(GTESTER_OPTIONS) -o $@ -m=$(SPEED) $(check-qtest-$*-y) $(check-qtest-generic-y),"GTESTER $@") check-report-unit.xml: $(check-unit-y) $(call quiet-command,gtester -q $(GTESTER_OPTIONS) -o $@ -m=$(SPEED) $^, "GTESTER $@") @@ -527,7 +711,7 @@ check: check-qapi-schema check-unit check-qtest check-clean: $(MAKE) -C tests/tcg clean rm -rf $(check-unit-y) tests/*.o $(QEMU_IOTESTS_HELPERS-y) - rm -rf $(sort $(foreach target,$(SYSEMU_TARGET_LIST), $(check-qtest-$(target)-y))) + rm -rf $(sort $(foreach target,$(SYSEMU_TARGET_LIST), $(check-qtest-$(target)-y)) $(check-qtest-generic-y)) clean: check-clean diff --git a/qemu/tests/ac97-test.c b/qemu/tests/ac97-test.c index af30ea1dd..75cab8f98 100644 --- a/qemu/tests/ac97-test.c +++ b/qemu/tests/ac97-test.c @@ -7,10 +7,9 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <string.h> #include "libqtest.h" -#include "qemu/osdep.h" /* Tests only initialization so far. TODO: Replace with functional tests */ static void nop(void) diff --git a/qemu/tests/acpi-test-data/pc/DSDT b/qemu/tests/acpi-test-data/pc/DSDT Binary files differindex c658203db..9d1274d3c 100644 --- a/qemu/tests/acpi-test-data/pc/DSDT +++ b/qemu/tests/acpi-test-data/pc/DSDT diff --git a/qemu/tests/acpi-test-data/pc/SSDT.bridge b/qemu/tests/acpi-test-data/pc/DSDT.bridge Binary files differindex 6e6660b1f..cf48c62aa 100644 --- a/qemu/tests/acpi-test-data/pc/SSDT.bridge +++ b/qemu/tests/acpi-test-data/pc/DSDT.bridge diff --git a/qemu/tests/acpi-test-data/pc/SSDT b/qemu/tests/acpi-test-data/pc/SSDT Binary files differdeleted file mode 100644 index 210d6a71e..000000000 --- a/qemu/tests/acpi-test-data/pc/SSDT +++ /dev/null diff --git a/qemu/tests/acpi-test-data/q35/DSDT b/qemu/tests/acpi-test-data/q35/DSDT Binary files differindex 4723e5954..1c089c34b 100644 --- a/qemu/tests/acpi-test-data/q35/DSDT +++ b/qemu/tests/acpi-test-data/q35/DSDT diff --git a/qemu/tests/acpi-test-data/q35/DSDT.bridge b/qemu/tests/acpi-test-data/q35/DSDT.bridge Binary files differnew file mode 100644 index 000000000..b29fcda0b --- /dev/null +++ b/qemu/tests/acpi-test-data/q35/DSDT.bridge diff --git a/qemu/tests/acpi-test-data/q35/SSDT b/qemu/tests/acpi-test-data/q35/SSDT Binary files differdeleted file mode 100644 index 0970c67dd..000000000 --- a/qemu/tests/acpi-test-data/q35/SSDT +++ /dev/null diff --git a/qemu/tests/acpi-test-data/q35/SSDT.bridge b/qemu/tests/acpi-test-data/q35/SSDT.bridge Binary files differdeleted file mode 100644 index a77868861..000000000 --- a/qemu/tests/acpi-test-data/q35/SSDT.bridge +++ /dev/null diff --git a/qemu/tests/ahci-test.c b/qemu/tests/ahci-test.c index 87d769186..6869f7f46 100644 --- a/qemu/tests/ahci-test.c +++ b/qemu/tests/ahci-test.c @@ -22,9 +22,7 @@ * THE SOFTWARE. */ -#include <stdint.h> -#include <string.h> -#include <stdio.h> +#include "qemu/osdep.h" #include <getopt.h> #include <glib.h> @@ -39,15 +37,17 @@ #include "hw/pci/pci_ids.h" #include "hw/pci/pci_regs.h" -/* Test-specific defines -- in MiB */ -#define TEST_IMAGE_SIZE_MB (200 * 1024) -#define TEST_IMAGE_SECTORS ((TEST_IMAGE_SIZE_MB / AHCI_SECTOR_SIZE) \ - * 1024 * 1024) +/* Test images sizes in MB */ +#define TEST_IMAGE_SIZE_MB_LARGE (200 * 1024) +#define TEST_IMAGE_SIZE_MB_SMALL 64 /*** Globals ***/ static char tmp_path[] = "/tmp/qtest.XXXXXX"; static char debug_path[] = "/tmp/qtest-blkdebug.XXXXXX"; +static char mig_socket[] = "/tmp/qtest-migration.XXXXXX"; static bool ahci_pedantic; +static const char *imgfmt; +static unsigned test_image_size_mb; /*** Function Declarations ***/ static void ahci_test_port_spec(AHCIQState *ahci, uint8_t port); @@ -60,6 +60,11 @@ static void ahci_test_pmcap(AHCIQState *ahci, uint8_t offset); /*** Utilities ***/ +static uint64_t mb_to_sectors(uint64_t image_size_mb) +{ + return (image_size_mb * 1024 * 1024) / AHCI_SECTOR_SIZE; +} + static void string_bswap16(uint16_t *s, size_t bytes) { g_assert_cmphex((bytes & 1), ==, 0); @@ -71,32 +76,6 @@ static void string_bswap16(uint16_t *s, size_t bytes) } } -static void generate_pattern(void *buffer, size_t len, size_t cycle_len) -{ - int i, j; - unsigned char *tx = (unsigned char *)buffer; - unsigned char p; - size_t *sx; - - /* Write an indicative pattern that varies and is unique per-cycle */ - p = rand() % 256; - for (i = j = 0; i < len; i++, j++) { - tx[i] = p; - if (j % cycle_len == 0) { - p = rand() % 256; - } - } - - /* force uniqueness by writing an id per-cycle */ - for (i = 0; i < len / cycle_len; i++) { - j = i * cycle_len; - if (j + sizeof(*sx) <= len) { - sx = (size_t *)&tx[j]; - *sx = i; - } - } -} - /** * Verify that the transfer did not corrupt our state at all. */ @@ -140,8 +119,11 @@ static void ahci_migrate(AHCIQState *from, AHCIQState *to, const char *uri) { QOSState *tmp = to->parent; QPCIDevice *dev = to->dev; + char *uri_local = NULL; + if (uri == NULL) { - uri = "tcp:127.0.0.1:1234"; + uri_local = g_strdup_printf("%s%s", "unix:", mig_socket); + uri = uri_local; } /* context will be 'to' after completion. */ @@ -161,6 +143,7 @@ static void ahci_migrate(AHCIQState *from, AHCIQState *to, const char *uri) from->dev = dev; verify_state(to); + g_free(uri_local); } /*** Test Setup & Teardown ***/ @@ -196,11 +179,11 @@ static AHCIQState *ahci_boot(const char *cli, ...) va_end(ap); } else { cli = "-drive if=none,id=drive0,file=%s,cache=writeback,serial=%s" - ",format=qcow2" + ",format=%s" " -M q35 " "-device ide-hd,drive=drive0 " "-global ide-hd.ver=%s"; - s = ahci_boot(cli, tmp_path, "testdisk", "version"); + s = ahci_boot(cli, tmp_path, "testdisk", imgfmt, "version"); } return s; @@ -230,6 +213,7 @@ static AHCIQState *ahci_boot_and_enable(const char *cli, ...) va_list ap; uint16_t buff[256]; uint8_t port; + uint8_t hello; if (cli) { va_start(ap, cli); @@ -244,7 +228,12 @@ static AHCIQState *ahci_boot_and_enable(const char *cli, ...) /* Initialize test device */ port = ahci_port_select(ahci); ahci_port_clear(ahci, port); - ahci_io(ahci, port, CMD_IDENTIFY, &buff, sizeof(buff), 0); + if (is_atapi(ahci, port)) { + hello = CMD_PACKET_ID; + } else { + hello = CMD_IDENTIFY; + } + ahci_io(ahci, port, hello, &buff, sizeof(buff), 0); return ahci; } @@ -899,18 +888,12 @@ static void ahci_test_io_rw_simple(AHCIQState *ahci, unsigned bufsize, static uint8_t ahci_test_nondata(AHCIQState *ahci, uint8_t ide_cmd) { uint8_t port; - AHCICommand *cmd; /* Sanitize */ port = ahci_port_select(ahci); ahci_port_clear(ahci, port); - /* Issue Command */ - cmd = ahci_command_create(ide_cmd); - ahci_command_commit(ahci, cmd, port); - ahci_command_issue(ahci, cmd); - ahci_command_verify(ahci, cmd); - ahci_command_free(cmd); + ahci_io(ahci, port, ide_cmd, NULL, 0, 0); return port; } @@ -926,7 +909,7 @@ static void ahci_test_max(AHCIQState *ahci) uint64_t nsect; uint8_t port; uint8_t cmd; - uint64_t config_sect = TEST_IMAGE_SECTORS - 1; + uint64_t config_sect = mb_to_sectors(test_image_size_mb) - 1; if (config_sect > 0xFFFFFF) { cmd = CMD_READ_MAX_EXT; @@ -1060,14 +1043,14 @@ static void test_dma_fragmented(void) ahci_command_commit(ahci, cmd, px); ahci_command_issue(ahci, cmd); ahci_command_verify(ahci, cmd); - g_free(cmd); + ahci_command_free(cmd); cmd = ahci_command_create(CMD_READ_DMA); ahci_command_adjust(cmd, 0, ptr, bufsize, 32); ahci_command_commit(ahci, cmd, px); ahci_command_issue(ahci, cmd); ahci_command_verify(ahci, cmd); - g_free(cmd); + ahci_command_free(cmd); /* Read back the guest's receive buffer into local memory */ bufread(ptr, rx, bufsize); @@ -1095,33 +1078,23 @@ static void test_flush_retry(void) AHCIQState *ahci; AHCICommand *cmd; uint8_t port; - const char *s; prepare_blkdebug_script(debug_path, "flush_to_disk"); ahci = ahci_boot_and_enable("-drive file=blkdebug:%s:%s,if=none,id=drive0," - "format=qcow2,cache=writeback," + "format=%s,cache=writeback," "rerror=stop,werror=stop " "-M q35 " "-device ide-hd,drive=drive0 ", debug_path, - tmp_path); + tmp_path, imgfmt); /* Issue Flush Command and wait for error */ port = ahci_port_select(ahci); ahci_port_clear(ahci, port); - cmd = ahci_command_create(CMD_FLUSH_CACHE); - ahci_command_commit(ahci, cmd, port); - ahci_command_issue_async(ahci, cmd); - qmp_eventwait("STOP"); - /* Complete the command */ - s = "{'execute':'cont' }"; - qmp_async(s); - qmp_eventwait("RESUME"); - ahci_command_wait(ahci, cmd); - ahci_command_verify(ahci, cmd); + cmd = ahci_guest_io_halt(ahci, port, CMD_FLUSH_CACHE, 0, 0, 0); + ahci_guest_io_resume(ahci, cmd); - ahci_command_free(cmd); ahci_shutdown(ahci); } @@ -1131,18 +1104,19 @@ static void test_flush_retry(void) static void test_migrate_sanity(void) { AHCIQState *src, *dst; - const char *uri = "tcp:127.0.0.1:1234"; + char *uri = g_strdup_printf("unix:%s", mig_socket); src = ahci_boot("-m 1024 -M q35 " - "-hda %s ", tmp_path); + "-drive if=ide,file=%s,format=%s ", tmp_path, imgfmt); dst = ahci_boot("-m 1024 -M q35 " - "-hda %s " - "-incoming %s", tmp_path, uri); + "-drive if=ide,file=%s,format=%s " + "-incoming %s", tmp_path, imgfmt, uri); ahci_migrate(src, dst, uri); ahci_shutdown(src); ahci_shutdown(dst); + g_free(uri); } /** @@ -1155,14 +1129,14 @@ static void ahci_migrate_simple(uint8_t cmd_read, uint8_t cmd_write) size_t bufsize = 4096; unsigned char *tx = g_malloc(bufsize); unsigned char *rx = g_malloc0(bufsize); - unsigned i; - const char *uri = "tcp:127.0.0.1:1234"; + char *uri = g_strdup_printf("unix:%s", mig_socket); src = ahci_boot_and_enable("-m 1024 -M q35 " - "-hda %s ", tmp_path); + "-drive if=ide,format=%s,file=%s ", + imgfmt, tmp_path); dst = ahci_boot("-m 1024 -M q35 " - "-hda %s " - "-incoming %s", tmp_path, uri); + "-drive if=ide,format=%s,file=%s " + "-incoming %s", imgfmt, tmp_path, uri); set_context(src->parent); @@ -1171,9 +1145,7 @@ static void ahci_migrate_simple(uint8_t cmd_read, uint8_t cmd_write) ahci_port_clear(src, px); /* create pattern */ - for (i = 0; i < bufsize; i++) { - tx[i] = (bufsize - i); - } + generate_pattern(tx, bufsize, AHCI_SECTOR_SIZE); /* Write, migrate, then read. */ ahci_io(src, px, cmd_write, tx, bufsize, 0); @@ -1187,6 +1159,7 @@ static void ahci_migrate_simple(uint8_t cmd_read, uint8_t cmd_write) ahci_shutdown(dst); g_free(rx); g_free(tx); + g_free(uri); } static void test_migrate_dma(void) @@ -1213,29 +1186,25 @@ static void ahci_halted_io_test(uint8_t cmd_read, uint8_t cmd_write) size_t bufsize = 4096; unsigned char *tx = g_malloc(bufsize); unsigned char *rx = g_malloc0(bufsize); - unsigned i; uint64_t ptr; AHCICommand *cmd; prepare_blkdebug_script(debug_path, "write_aio"); ahci = ahci_boot_and_enable("-drive file=blkdebug:%s:%s,if=none,id=drive0," - "format=qcow2,cache=writeback," + "format=%s,cache=writeback," "rerror=stop,werror=stop " "-M q35 " "-device ide-hd,drive=drive0 ", debug_path, - tmp_path); + tmp_path, imgfmt); /* Initialize and prepare */ port = ahci_port_select(ahci); ahci_port_clear(ahci, port); - for (i = 0; i < bufsize; i++) { - tx[i] = (bufsize - i); - } - /* create DMA source buffer and write pattern */ + generate_pattern(tx, bufsize, AHCI_SECTOR_SIZE); ptr = ahci_alloc(ahci, bufsize); g_assert(ptr); memwrite(ptr, tx, bufsize); @@ -1282,38 +1251,34 @@ static void ahci_migrate_halted_io(uint8_t cmd_read, uint8_t cmd_write) size_t bufsize = 4096; unsigned char *tx = g_malloc(bufsize); unsigned char *rx = g_malloc0(bufsize); - unsigned i; uint64_t ptr; AHCICommand *cmd; - const char *uri = "tcp:127.0.0.1:1234"; + char *uri = g_strdup_printf("unix:%s", mig_socket); prepare_blkdebug_script(debug_path, "write_aio"); src = ahci_boot_and_enable("-drive file=blkdebug:%s:%s,if=none,id=drive0," - "format=qcow2,cache=writeback," + "format=%s,cache=writeback," "rerror=stop,werror=stop " "-M q35 " "-device ide-hd,drive=drive0 ", debug_path, - tmp_path); + tmp_path, imgfmt); dst = ahci_boot("-drive file=%s,if=none,id=drive0," - "format=qcow2,cache=writeback," + "format=%s,cache=writeback," "rerror=stop,werror=stop " "-M q35 " "-device ide-hd,drive=drive0 " "-incoming %s", - tmp_path, uri); + tmp_path, imgfmt, uri); set_context(src->parent); /* Initialize and prepare */ port = ahci_port_select(src); ahci_port_clear(src, port); - - for (i = 0; i < bufsize; i++) { - tx[i] = (bufsize - i); - } + generate_pattern(tx, bufsize, AHCI_SECTOR_SIZE); /* create DMA source buffer and write pattern */ ptr = ahci_alloc(src, bufsize); @@ -1338,6 +1303,7 @@ static void ahci_migrate_halted_io(uint8_t cmd_read, uint8_t cmd_write) ahci_shutdown(dst); g_free(rx); g_free(tx); + g_free(uri); } static void test_migrate_halted_dma(void) @@ -1359,20 +1325,22 @@ static void test_flush_migrate(void) AHCICommand *cmd; uint8_t px; const char *s; - const char *uri = "tcp:127.0.0.1:1234"; + char *uri = g_strdup_printf("unix:%s", mig_socket); prepare_blkdebug_script(debug_path, "flush_to_disk"); src = ahci_boot_and_enable("-drive file=blkdebug:%s:%s,if=none,id=drive0," - "cache=writeback,rerror=stop,werror=stop " + "cache=writeback,rerror=stop,werror=stop," + "format=%s " "-M q35 " "-device ide-hd,drive=drive0 ", - debug_path, tmp_path); + debug_path, tmp_path, imgfmt); dst = ahci_boot("-drive file=%s,if=none,id=drive0," - "cache=writeback,rerror=stop,werror=stop " + "cache=writeback,rerror=stop,werror=stop," + "format=%s " "-M q35 " "-device ide-hd,drive=drive0 " - "-incoming %s", tmp_path, uri); + "-incoming %s", tmp_path, imgfmt, uri); set_context(src->parent); @@ -1397,6 +1365,7 @@ static void test_flush_migrate(void) ahci_command_free(cmd); ahci_shutdown(src); ahci_shutdown(dst); + g_free(uri); } static void test_max(void) @@ -1442,6 +1411,98 @@ static void test_ncq_simple(void) ahci_shutdown(ahci); } +static int prepare_iso(size_t size, unsigned char **buf, char **name) +{ + char cdrom_path[] = "/tmp/qtest.iso.XXXXXX"; + unsigned char *patt; + ssize_t ret; + int fd = mkstemp(cdrom_path); + + g_assert(buf); + g_assert(name); + patt = g_malloc(size); + + /* Generate a pattern and build a CDROM image to read from */ + generate_pattern(patt, size, ATAPI_SECTOR_SIZE); + ret = write(fd, patt, size); + g_assert(ret == size); + + *name = g_strdup(cdrom_path); + *buf = patt; + return fd; +} + +static void remove_iso(int fd, char *name) +{ + unlink(name); + g_free(name); + close(fd); +} + +static int ahci_cb_cmp_buff(AHCIQState *ahci, AHCICommand *cmd, + const AHCIOpts *opts) +{ + unsigned char *tx = opts->opaque; + unsigned char *rx = g_malloc0(opts->size); + + bufread(opts->buffer, rx, opts->size); + g_assert_cmphex(memcmp(tx, rx, opts->size), ==, 0); + g_free(rx); + + return 0; +} + +static void ahci_test_cdrom(int nsectors, bool dma) +{ + AHCIQState *ahci; + unsigned char *tx; + char *iso; + int fd; + AHCIOpts opts = { + .size = (ATAPI_SECTOR_SIZE * nsectors), + .atapi = true, + .atapi_dma = dma, + .post_cb = ahci_cb_cmp_buff, + }; + + /* Prepare ISO and fill 'tx' buffer */ + fd = prepare_iso(1024 * 1024, &tx, &iso); + opts.opaque = tx; + + /* Standard startup wonkery, but use ide-cd and our special iso file */ + ahci = ahci_boot_and_enable("-drive if=none,id=drive0,file=%s,format=raw " + "-M q35 " + "-device ide-cd,drive=drive0 ", iso); + + /* Build & Send AHCI command */ + ahci_exec(ahci, ahci_port_select(ahci), CMD_ATAPI_READ_10, &opts); + + /* Cleanup */ + g_free(tx); + ahci_shutdown(ahci); + remove_iso(fd, iso); +} + +static void test_cdrom_dma(void) +{ + ahci_test_cdrom(1, true); +} + +static void test_cdrom_dma_multi(void) +{ + ahci_test_cdrom(3, true); +} + +static void test_cdrom_pio(void) +{ + ahci_test_cdrom(1, false); +} + +static void test_cdrom_pio_multi(void) +{ + ahci_test_cdrom(3, false); +} + /******************************************************************************/ /* AHCI I/O Test Matrix Definitions */ @@ -1513,7 +1574,7 @@ static uint64_t offset_sector(enum OffsetType ofst, return 1; case OFFSET_HIGH: ceil = (addr_type == ADDR_MODE_LBA28) ? 0xfffffff : 0xffffffffffff; - ceil = MIN(ceil, TEST_IMAGE_SECTORS - 1); + ceil = MIN(ceil, mb_to_sectors(test_image_size_mb) - 1); nsectors = buffsize / AHCI_SECTOR_SIZE; return ceil - nsectors + 1; default: @@ -1595,8 +1656,9 @@ static void create_ahci_io_test(enum IOMode type, enum AddrMode addr, enum BuffLen len, enum OffsetType offset) { char *name; - AHCIIOTestOptions *opts = g_malloc(sizeof(AHCIIOTestOptions)); + AHCIIOTestOptions *opts; + opts = g_malloc(sizeof(AHCIIOTestOptions)); opts->length = len; opts->address_type = addr; opts->io_type = type; @@ -1608,6 +1670,13 @@ static void create_ahci_io_test(enum IOMode type, enum AddrMode addr, buff_len_str[len], offset_str[offset]); + if ((addr == ADDR_MODE_LBA48) && (offset == OFFSET_HIGH) && + (mb_to_sectors(test_image_size_mb) <= 0xFFFFFFF)) { + g_test_message("%s: skipped; test image too small", name); + g_free(name); + return; + } + qtest_add_data_func(name, opts, test_io_interface); g_free(name); } @@ -1654,15 +1723,33 @@ int main(int argc, char **argv) return 0; } - /* Create a temporary qcow2 image */ - close(mkstemp(tmp_path)); - mkqcow2(tmp_path, TEST_IMAGE_SIZE_MB); + /* Create a temporary image */ + fd = mkstemp(tmp_path); + g_assert(fd >= 0); + if (have_qemu_img()) { + imgfmt = "qcow2"; + test_image_size_mb = TEST_IMAGE_SIZE_MB_LARGE; + mkqcow2(tmp_path, TEST_IMAGE_SIZE_MB_LARGE); + } else { + g_test_message("QTEST_QEMU_IMG not set or qemu-img missing; " + "skipping LBA48 high-sector tests"); + imgfmt = "raw"; + test_image_size_mb = TEST_IMAGE_SIZE_MB_SMALL; + ret = ftruncate(fd, test_image_size_mb * 1024 * 1024); + g_assert(ret == 0); + } + close(fd); /* Create temporary blkdebug instructions */ fd = mkstemp(debug_path); g_assert(fd >= 0); close(fd); + /* Reserve a hollow file to use as a socket for migration tests */ + fd = mkstemp(mig_socket); + g_assert(fd >= 0); + close(fd); + /* Run the tests */ qtest_add_func("/ahci/sanity", test_sanity); qtest_add_func("/ahci/pci_spec", test_pci_spec); @@ -1700,11 +1787,17 @@ int main(int argc, char **argv) qtest_add_func("/ahci/io/ncq/retry", test_halted_ncq); qtest_add_func("/ahci/migrate/ncq/halted", test_migrate_halted_ncq); + qtest_add_func("/ahci/cdrom/dma/single", test_cdrom_dma); + qtest_add_func("/ahci/cdrom/dma/multi", test_cdrom_dma_multi); + qtest_add_func("/ahci/cdrom/pio/single", test_cdrom_pio); + qtest_add_func("/ahci/cdrom/pio/multi", test_cdrom_pio_multi); + ret = g_test_run(); /* Cleanup */ unlink(tmp_path); unlink(debug_path); + unlink(mig_socket); return ret; } diff --git a/qemu/tests/bios-tables-test.c b/qemu/tests/bios-tables-test.c index 0de1742d7..03528140c 100644 --- a/qemu/tests/bios-tables-test.c +++ b/qemu/tests/bios-tables-test.c @@ -10,16 +10,15 @@ * See the COPYING file in the top-level directory. */ -#include <string.h> -#include <stdio.h> +#include "qemu/osdep.h" #include <glib.h> #include <glib/gstdio.h> #include "qemu-common.h" #include "libqtest.h" -#include "qemu/compiler.h" #include "hw/acpi/acpi-defs.h" -#include "hw/i386/smbios.h" +#include "hw/smbios/smbios.h" #include "qemu/bitmap.h" +#include "boot-sector.h" #define MACHINE_PC "pc" #define MACHINE_Q35 "q35" @@ -50,16 +49,9 @@ typedef struct { int rsdt_tables_nr; GArray *tables; uint32_t smbios_ep_addr; - struct smbios_entry_point smbios_ep_table; + struct smbios_21_entry_point smbios_ep_table; } test_data; -#define LOW(x) ((x) & 0xff) -#define HIGH(x) ((x) >> 8) - -#define SIGNATURE 0xdead -#define SIGNATURE_OFFSET 0x10 -#define BOOT_SECTOR_ADDRESS 0x7c00 - #define ACPI_READ_FIELD(field, addr) \ do { \ switch (sizeof(field)) { \ @@ -119,35 +111,6 @@ typedef struct { g_assert_cmpstr(ACPI_ASSERT_CMP_str, ==, expected); \ } while (0) -/* Boot sector code: write SIGNATURE into memory, - * then halt. - * Q35 machine requires a minimum 0x7e000 bytes disk. - * (bug or feature?) - */ -static uint8_t boot_sector[0x7e000] = { - /* 7c00: mov $0xdead,%ax */ - [0x00] = 0xb8, - [0x01] = LOW(SIGNATURE), - [0x02] = HIGH(SIGNATURE), - /* 7c03: mov %ax,0x7c10 */ - [0x03] = 0xa3, - [0x04] = LOW(BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET), - [0x05] = HIGH(BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET), - /* 7c06: cli */ - [0x06] = 0xfa, - /* 7c07: hlt */ - [0x07] = 0xf4, - /* 7c08: jmp 0x7c07=0x7c0a-3 */ - [0x08] = 0xeb, - [0x09] = LOW(-3), - /* We mov 0xdead here: set value to make debugging easier */ - [SIGNATURE_OFFSET] = LOW(0xface), - [SIGNATURE_OFFSET + 1] = HIGH(0xface), - /* End of boot sector marker */ - [0x1FE] = 0x55, - [0x1FF] = 0xAA, -}; - static const char *disk = "tests/acpi-test-disk.raw"; static const char *data_dir = "tests/acpi-test-data"; #ifdef CONFIG_IASL @@ -161,31 +124,23 @@ static void free_test_data(test_data *data) AcpiSdtTable *temp; int i; - if (data->rsdt_tables_addr) { - g_free(data->rsdt_tables_addr); - } + g_free(data->rsdt_tables_addr); for (i = 0; i < data->tables->len; ++i) { temp = &g_array_index(data->tables, AcpiSdtTable, i); - if (temp->aml) { - g_free(temp->aml); + g_free(temp->aml); + if (temp->aml_file && + !temp->tmp_files_retain && + g_strstr_len(temp->aml_file, -1, "aml-")) { + unlink(temp->aml_file); } - if (temp->aml_file) { - if (!temp->tmp_files_retain && - g_strstr_len(temp->aml_file, -1, "aml-")) { - unlink(temp->aml_file); - } - g_free(temp->aml_file); - } - if (temp->asl) { - g_free(temp->asl); - } - if (temp->asl_file) { - if (!temp->tmp_files_retain) { - unlink(temp->asl_file); - } - g_free(temp->asl_file); + g_free(temp->aml_file); + g_free(temp->asl); + if (temp->asl_file && + !temp->tmp_files_retain) { + unlink(temp->asl_file); } + g_free(temp->asl_file); } g_array_free(data->tables, false); @@ -420,9 +375,7 @@ static void dump_aml_files(test_data *data, bool rebuild) close(fd); - if (aml_file) { - g_free(aml_file); - } + g_free(aml_file); } } @@ -479,7 +432,7 @@ static bool load_asl(GArray *sdts, AcpiSdtTable *sdt) #define COMMENT_END "*/" #define DEF_BLOCK "DefinitionBlock (" -#define BLOCK_NAME_END ".aml" +#define BLOCK_NAME_END "," static GString *normalize_asl(gchar *asl_code) { @@ -590,6 +543,22 @@ static void test_acpi_asl(test_data *data) (gchar *)&signature, sdt->asl_file, sdt->aml_file, exp_sdt->asl_file, exp_sdt->aml_file); + if (getenv("V")) { + const char *diff_cmd = getenv("DIFF"); + if (diff_cmd) { + int ret G_GNUC_UNUSED; + char *diff = g_strdup_printf("%s %s %s", diff_cmd, + exp_sdt->asl_file, sdt->asl_file); + ret = system(diff) ; + g_free(diff); + } else { + fprintf(stderr, "acpi-test: Warning. not showing " + "difference since no diff utility is specified. " + "Set 'DIFF' environment variable to a preferred " + "diff utility and run 'make V=1 check' again to " + "see ASL difference."); + } + } } } g_string_free(asl, true); @@ -601,7 +570,7 @@ static void test_acpi_asl(test_data *data) static bool smbios_ep_table_ok(test_data *data) { - struct smbios_entry_point *ep_table = &data->smbios_ep_table; + struct smbios_21_entry_point *ep_table = &data->smbios_ep_table; uint32_t addr = data->smbios_ep_addr; ACPI_READ_ARRAY(ep_table->anchor_string, addr); @@ -681,7 +650,7 @@ static inline bool smbios_single_instance(uint8_t type) static void test_smbios_structs(test_data *data) { DECLARE_BITMAP(struct_bitmap, SMBIOS_MAX_TYPE+1) = { 0 }; - struct smbios_entry_point *ep_table = &data->smbios_ep_table; + struct smbios_21_entry_point *ep_table = &data->smbios_ep_table; uint32_t addr = ep_table->structure_table_address; int i, len, max_len = 0; uint8_t type, prv, crt; @@ -733,10 +702,6 @@ static void test_smbios_structs(test_data *data) static void test_acpi_one(const char *params, test_data *data) { char *args; - uint8_t signature_low; - uint8_t signature_high; - uint16_t signature; - int i; args = g_strdup_printf("-net none -display none %s " "-drive id=hd0,if=none,file=%s,format=raw " @@ -745,24 +710,7 @@ static void test_acpi_one(const char *params, test_data *data) qtest_start(args); - /* Wait at most 1 minute */ -#define TEST_DELAY (1 * G_USEC_PER_SEC / 10) -#define TEST_CYCLES MAX((60 * G_USEC_PER_SEC / TEST_DELAY), 1) - - /* Poll until code has run and modified memory. Once it has we know BIOS - * initialization is done. TODO: check that IP reached the halt - * instruction. - */ - for (i = 0; i < TEST_CYCLES; ++i) { - signature_low = readb(BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET); - signature_high = readb(BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET + 1); - signature = (signature_high << 8) | signature_low; - if (signature == SIGNATURE) { - break; - } - g_usleep(TEST_DELAY); - } - g_assert_cmphex(signature, ==, SIGNATURE); + boot_sector_test(); test_acpi_rsdp_address(data); test_acpi_rsdp_table(data); @@ -836,15 +784,11 @@ static void test_acpi_q35_tcg_bridge(void) int main(int argc, char *argv[]) { const char *arch = qtest_get_arch(); - FILE *f = fopen(disk, "w"); int ret; - if (!f) { - fprintf(stderr, "Couldn't open \"%s\": %s", disk, strerror(errno)); - return 1; - } - fwrite(boot_sector, 1, sizeof boot_sector, f); - fclose(f); + ret = boot_sector_init(disk); + if(ret) + return ret; g_test_init(&argc, &argv, NULL); @@ -855,6 +799,6 @@ int main(int argc, char *argv[]) qtest_add_func("acpi/q35/tcg/bridge", test_acpi_q35_tcg_bridge); } ret = g_test_run(); - unlink(disk); + boot_sector_cleanup(disk); return ret; } diff --git a/qemu/tests/boot-order-test.c b/qemu/tests/boot-order-test.c index 360a6911e..a6d8bd5cb 100644 --- a/qemu/tests/boot-order-test.c +++ b/qemu/tests/boot-order-test.c @@ -10,14 +10,12 @@ * See the COPYING file in the top-level directory. */ -#include <string.h> +#include "qemu/osdep.h" #include <glib.h> #include "libqos/fw_cfg.h" #include "libqtest.h" -#define NO_QEMU_PROTOS -#include "hw/nvram/fw_cfg.h" -#undef NO_QEMU_PROTOS +#include "hw/nvram/fw_cfg_keys.h" typedef struct { const char *args; diff --git a/qemu/tests/boot-sector.c b/qemu/tests/boot-sector.c new file mode 100644 index 000000000..3ffe2987f --- /dev/null +++ b/qemu/tests/boot-sector.c @@ -0,0 +1,118 @@ +/* + * QEMU boot sector testing helpers. + * + * Copyright (c) 2016 Red Hat Inc. + * + * Authors: + * Michael S. Tsirkin <mst@redhat.com> + * Victor Kaplansky <victork@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#include "qemu/osdep.h" +#include "boot-sector.h" +#include "qemu-common.h" +#include "libqtest.h" + +#define LOW(x) ((x) & 0xff) +#define HIGH(x) ((x) >> 8) + +#define SIGNATURE 0xdead +#define SIGNATURE_OFFSET 0x10 +#define BOOT_SECTOR_ADDRESS 0x7c00 + +/* Boot sector code: write SIGNATURE into memory, + * then halt. + * Q35 machine requires a minimum 0x7e000 bytes disk. + * (bug or feature?) + */ +static uint8_t boot_sector[0x7e000] = { + /* The first sector will be placed at RAM address 00007C00, and + * the BIOS transfers control to 00007C00 + */ + + /* Data Segment register should be initialized, since pxe + * boot loader can leave it dirty. + */ + + /* 7c00: move $0000,%ax */ + [0x00] = 0xb8, + [0x01] = 0x00, + [0x02] = 0x00, + /* 7c03: move %ax,%ds */ + [0x03] = 0x8e, + [0x04] = 0xd8, + + /* 7c05: mov $0xdead,%ax */ + [0x05] = 0xb8, + [0x06] = LOW(SIGNATURE), + [0x07] = HIGH(SIGNATURE), + /* 7c08: mov %ax,0x7c10 */ + [0x08] = 0xa3, + [0x09] = LOW(BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET), + [0x0a] = HIGH(BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET), + + /* 7c0b cli */ + [0x0b] = 0xfa, + /* 7c0c: hlt */ + [0x0c] = 0xf4, + /* 7c0e: jmp 0x7c07=0x7c0f-3 */ + [0x0d] = 0xeb, + [0x0e] = LOW(-3), + /* We mov 0xdead here: set value to make debugging easier */ + [SIGNATURE_OFFSET] = LOW(0xface), + [SIGNATURE_OFFSET + 1] = HIGH(0xface), + /* End of boot sector marker */ + [0x1FE] = 0x55, + [0x1FF] = 0xAA, +}; + +/* Create boot disk file. */ +int boot_sector_init(const char *fname) +{ + FILE *f = fopen(fname, "w"); + + if (!f) { + fprintf(stderr, "Couldn't open \"%s\": %s", fname, strerror(errno)); + return 1; + } + fwrite(boot_sector, 1, sizeof boot_sector, f); + fclose(f); + return 0; +} + +/* Loop until signature in memory is OK. */ +void boot_sector_test(void) +{ + uint8_t signature_low; + uint8_t signature_high; + uint16_t signature; + int i; + + /* Wait at most 1 minute */ +#define TEST_DELAY (1 * G_USEC_PER_SEC / 10) +#define TEST_CYCLES MAX((60 * G_USEC_PER_SEC / TEST_DELAY), 1) + + /* Poll until code has run and modified memory. Once it has we know BIOS + * initialization is done. TODO: check that IP reached the halt + * instruction. + */ + for (i = 0; i < TEST_CYCLES; ++i) { + signature_low = readb(BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET); + signature_high = readb(BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET + 1); + signature = (signature_high << 8) | signature_low; + if (signature == SIGNATURE) { + break; + } + g_usleep(TEST_DELAY); + } + + g_assert_cmphex(signature, ==, SIGNATURE); +} + +/* unlink boot disk file. */ +void boot_sector_cleanup(const char *fname) +{ + unlink(fname); +} diff --git a/qemu/tests/boot-sector.h b/qemu/tests/boot-sector.h new file mode 100644 index 000000000..38be0290e --- /dev/null +++ b/qemu/tests/boot-sector.h @@ -0,0 +1,26 @@ +/* + * QEMU boot sector testing helpers. + * + * Copyright (c) 2016 Red Hat Inc. + * + * Authors: + * Michael S. Tsirkin <mst@redhat.com> + * Victor Kaplansky <victork@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef TEST_BOOT_SECTOR +#define TEST_BOOT_SECTOR + +/* Create boot disk file. */ +int boot_sector_init(const char *fname); + +/* Loop until signature in memory is OK. */ +void boot_sector_test(void); + +/* unlink boot disk file. */ +void boot_sector_cleanup(const char *fname); + +#endif /* TEST_BOOT_SECTOR */ diff --git a/qemu/tests/check-block.sh b/qemu/tests/check-block.sh index b9d9c6a9f..a37797a49 100755 --- a/qemu/tests/check-block.sh +++ b/qemu/tests/check-block.sh @@ -9,7 +9,7 @@ if [ ! -x $QEMU_PROG ]; then exit 1 fi -cd $SRC_PATH/tests/qemu-iotests +cd tests/qemu-iotests ret=0 ./check -T -nocache -raw || ret=1 diff --git a/qemu/tests/check-qdict.c b/qemu/tests/check-qdict.c index a136f2add..a43056c5d 100644 --- a/qemu/tests/check-qdict.c +++ b/qemu/tests/check-qdict.c @@ -9,6 +9,7 @@ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. * See the COPYING.LIB file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> #include "qapi/qmp/qint.h" diff --git a/qemu/tests/check-qfloat.c b/qemu/tests/check-qfloat.c index 6404ac8df..3102608f5 100644 --- a/qemu/tests/check-qfloat.c +++ b/qemu/tests/check-qfloat.c @@ -10,6 +10,7 @@ * See the COPYING.LIB file in the top-level directory. * */ +#include "qemu/osdep.h" #include <glib.h> #include "qapi/qmp/qfloat.h" diff --git a/qemu/tests/check-qint.c b/qemu/tests/check-qint.c index 86868844a..c86f7dfa3 100644 --- a/qemu/tests/check-qint.c +++ b/qemu/tests/check-qint.c @@ -9,6 +9,7 @@ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. * See the COPYING.LIB file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> #include "qapi/qmp/qint.h" diff --git a/qemu/tests/check-qjson.c b/qemu/tests/check-qjson.c index 1cfffa593..99de6f525 100644 --- a/qemu/tests/check-qjson.c +++ b/qemu/tests/check-qjson.c @@ -10,6 +10,7 @@ * See the COPYING.LIB file in the top-level directory. * */ +#include "qemu/osdep.h" #include <glib.h> #include "qapi/qmp/qstring.h" @@ -1484,6 +1485,30 @@ static void unterminated_literal(void) g_assert(obj == NULL); } +static char *make_nest(char *buf, size_t cnt) +{ + memset(buf, '[', cnt - 1); + buf[cnt - 1] = '{'; + buf[cnt] = '}'; + memset(buf + cnt + 1, ']', cnt - 1); + buf[2 * cnt] = 0; + return buf; +} + +static void limits_nesting(void) +{ + enum { max_nesting = 1024 }; /* see qobject/json-streamer.c */ + char buf[2 * (max_nesting + 1) + 1]; + QObject *obj; + + obj = qobject_from_json(make_nest(buf, max_nesting)); + g_assert(obj != NULL); + qobject_decref(obj); + + obj = qobject_from_json(make_nest(buf, max_nesting + 1)); + g_assert(obj == NULL); +} + int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); @@ -1519,6 +1544,7 @@ int main(int argc, char **argv) g_test_add_func("/errors/invalid_array_comma", invalid_array_comma); g_test_add_func("/errors/invalid_dict_comma", invalid_dict_comma); g_test_add_func("/errors/unterminated/literal", unterminated_literal); + g_test_add_func("/errors/limits/nesting", limits_nesting); return g_test_run(); } diff --git a/qemu/tests/check-qlist.c b/qemu/tests/check-qlist.c index b9c05d43f..f231d5fa9 100644 --- a/qemu/tests/check-qlist.c +++ b/qemu/tests/check-qlist.c @@ -9,6 +9,7 @@ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. * See the COPYING.LIB file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> #include "qapi/qmp/qint.h" diff --git a/qemu/tests/check-qom-interface.c b/qemu/tests/check-qom-interface.c index f06380ef1..09354deb7 100644 --- a/qemu/tests/check-qom-interface.c +++ b/qemu/tests/check-qom-interface.c @@ -9,6 +9,7 @@ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. * See the COPYING.LIB file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> #include "qom/object.h" diff --git a/qemu/tests/check-qom-proplist.c b/qemu/tests/check-qom-proplist.c index 7400b1fce..ffffd872f 100644 --- a/qemu/tests/check-qom-proplist.c +++ b/qemu/tests/check-qom-proplist.c @@ -18,8 +18,10 @@ * Author: Daniel P. Berrange <berrange@redhat.com> */ +#include "qemu/osdep.h" #include <glib.h> +#include "qapi/error.h" #include "qom/object.h" #include "qemu/module.h" @@ -123,18 +125,28 @@ static void dummy_init(Object *obj) dummy_get_bv, dummy_set_bv, NULL); - object_property_add_str(obj, "sv", - dummy_get_sv, - dummy_set_sv, - NULL); - object_property_add_enum(obj, "av", - "DummyAnimal", - dummy_animal_map, - dummy_get_av, - dummy_set_av, - NULL); } + +static void dummy_class_init(ObjectClass *cls, void *data) +{ + object_class_property_add_bool(cls, "bv", + dummy_get_bv, + dummy_set_bv, + NULL); + object_class_property_add_str(cls, "sv", + dummy_get_sv, + dummy_set_sv, + NULL); + object_class_property_add_enum(cls, "av", + "DummyAnimal", + dummy_animal_map, + dummy_get_av, + dummy_set_av, + NULL); +} + + static void dummy_finalize(Object *obj) { DummyObject *dobj = DUMMY_OBJECT(obj); @@ -150,8 +162,151 @@ static const TypeInfo dummy_info = { .instance_init = dummy_init, .instance_finalize = dummy_finalize, .class_size = sizeof(DummyObjectClass), + .class_init = dummy_class_init, +}; + + +/* + * The following 3 object classes are used to + * simulate the kind of relationships seen in + * qdev, which result in complex object + * property destruction ordering. + * + * DummyDev has a 'bus' child to a DummyBus + * DummyBus has a 'backend' child to a DummyBackend + * DummyDev has a 'backend' link to DummyBackend + * + * When DummyDev is finalized, it unparents the + * DummyBackend, which unparents the DummyDev + * which deletes the 'backend' link from DummyDev + * to DummyBackend. This illustrates that the + * object_property_del_all() method needs to + * cope with the list of properties being changed + * while it iterates over them. + */ +typedef struct DummyDev DummyDev; +typedef struct DummyDevClass DummyDevClass; +typedef struct DummyBus DummyBus; +typedef struct DummyBusClass DummyBusClass; +typedef struct DummyBackend DummyBackend; +typedef struct DummyBackendClass DummyBackendClass; + +#define TYPE_DUMMY_DEV "qemu-dummy-dev" +#define TYPE_DUMMY_BUS "qemu-dummy-bus" +#define TYPE_DUMMY_BACKEND "qemu-dummy-backend" + +#define DUMMY_DEV(obj) \ + OBJECT_CHECK(DummyDev, (obj), TYPE_DUMMY_DEV) +#define DUMMY_BUS(obj) \ + OBJECT_CHECK(DummyBus, (obj), TYPE_DUMMY_BUS) +#define DUMMY_BACKEND(obj) \ + OBJECT_CHECK(DummyBackend, (obj), TYPE_DUMMY_BACKEND) + +struct DummyDev { + Object parent_obj; + + DummyBus *bus; +}; + +struct DummyDevClass { + ObjectClass parent_class; +}; + +struct DummyBus { + Object parent_obj; + + DummyBackend *backend; +}; + +struct DummyBusClass { + ObjectClass parent_class; +}; + +struct DummyBackend { + Object parent_obj; +}; + +struct DummyBackendClass { + ObjectClass parent_class; +}; + + +static void dummy_dev_init(Object *obj) +{ + DummyDev *dev = DUMMY_DEV(obj); + DummyBus *bus = DUMMY_BUS(object_new(TYPE_DUMMY_BUS)); + DummyBackend *backend = DUMMY_BACKEND(object_new(TYPE_DUMMY_BACKEND)); + + object_property_add_child(obj, "bus", OBJECT(bus), NULL); + dev->bus = bus; + object_property_add_child(OBJECT(bus), "backend", OBJECT(backend), NULL); + bus->backend = backend; + + object_property_add_link(obj, "backend", TYPE_DUMMY_BACKEND, + (Object **)&bus->backend, NULL, 0, NULL); +} + +static void dummy_dev_unparent(Object *obj) +{ + DummyDev *dev = DUMMY_DEV(obj); + object_unparent(OBJECT(dev->bus)); +} + +static void dummy_dev_class_init(ObjectClass *klass, void *opaque) +{ + klass->unparent = dummy_dev_unparent; +} + + +static void dummy_bus_init(Object *obj) +{ +} + +static void dummy_bus_unparent(Object *obj) +{ + DummyBus *bus = DUMMY_BUS(obj); + object_property_del(obj->parent, "backend", NULL); + object_unparent(OBJECT(bus->backend)); +} + +static void dummy_bus_class_init(ObjectClass *klass, void *opaque) +{ + klass->unparent = dummy_bus_unparent; +} + +static void dummy_backend_init(Object *obj) +{ +} + + +static const TypeInfo dummy_dev_info = { + .name = TYPE_DUMMY_DEV, + .parent = TYPE_OBJECT, + .instance_size = sizeof(DummyDev), + .instance_init = dummy_dev_init, + .class_size = sizeof(DummyDevClass), + .class_init = dummy_dev_class_init, +}; + +static const TypeInfo dummy_bus_info = { + .name = TYPE_DUMMY_BUS, + .parent = TYPE_OBJECT, + .instance_size = sizeof(DummyBus), + .instance_init = dummy_bus_init, + .class_size = sizeof(DummyBusClass), + .class_init = dummy_bus_class_init, +}; + +static const TypeInfo dummy_backend_info = { + .name = TYPE_DUMMY_BACKEND, + .parent = TYPE_OBJECT, + .instance_size = sizeof(DummyBackend), + .instance_init = dummy_backend_init, + .class_size = sizeof(DummyBackendClass), }; + + static void test_dummy_createv(void) { Error *err = NULL; @@ -283,20 +438,82 @@ static void test_dummy_getenum(void) &err); g_assert(err != NULL); error_free(err); + + object_unparent(OBJECT(dobj)); } +static void test_dummy_iterator(void) +{ + Object *parent = object_get_objects_root(); + DummyObject *dobj = DUMMY_OBJECT( + object_new_with_props(TYPE_DUMMY, + parent, + "dummy0", + &error_abort, + "bv", "yes", + "sv", "Hiss hiss hiss", + "av", "platypus", + NULL)); + + ObjectProperty *prop; + ObjectPropertyIterator iter; + bool seenbv = false, seensv = false, seenav = false, seentype; + + object_property_iter_init(&iter, OBJECT(dobj)); + while ((prop = object_property_iter_next(&iter))) { + if (g_str_equal(prop->name, "bv")) { + seenbv = true; + } else if (g_str_equal(prop->name, "sv")) { + seensv = true; + } else if (g_str_equal(prop->name, "av")) { + seenav = true; + } else if (g_str_equal(prop->name, "type")) { + /* This prop comes from the base Object class */ + seentype = true; + } else { + g_printerr("Found prop '%s'\n", prop->name); + g_assert_not_reached(); + } + } + g_assert(seenbv); + g_assert(seenav); + g_assert(seensv); + g_assert(seentype); + + object_unparent(OBJECT(dobj)); +} + + +static void test_dummy_delchild(void) +{ + Object *parent = object_get_objects_root(); + DummyDev *dev = DUMMY_DEV( + object_new_with_props(TYPE_DUMMY_DEV, + parent, + "dev0", + &error_abort, + NULL)); + + object_unparent(OBJECT(dev)); +} + int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); module_call_init(MODULE_INIT_QOM); type_register_static(&dummy_info); + type_register_static(&dummy_dev_info); + type_register_static(&dummy_bus_info); + type_register_static(&dummy_backend_info); g_test_add_func("/qom/proplist/createlist", test_dummy_createlist); g_test_add_func("/qom/proplist/createv", test_dummy_createv); g_test_add_func("/qom/proplist/badenum", test_dummy_badenum); g_test_add_func("/qom/proplist/getenum", test_dummy_getenum); + g_test_add_func("/qom/proplist/iterator", test_dummy_iterator); + g_test_add_func("/qom/proplist/delchild", test_dummy_delchild); return g_test_run(); } diff --git a/qemu/tests/check-qstring.c b/qemu/tests/check-qstring.c index 95dc9e3e7..9877b42c8 100644 --- a/qemu/tests/check-qstring.c +++ b/qemu/tests/check-qstring.c @@ -9,6 +9,7 @@ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. * See the COPYING.LIB file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> #include "qapi/qmp/qstring.h" diff --git a/qemu/tests/crypto-tls-x509-helpers.c b/qemu/tests/crypto-tls-x509-helpers.c new file mode 100644 index 000000000..64073d3bd --- /dev/null +++ b/qemu/tests/crypto-tls-x509-helpers.c @@ -0,0 +1,485 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Author: Daniel P. Berrange <berrange@redhat.com> + */ + +#include "qemu/osdep.h" + +#include "crypto-tls-x509-helpers.h" +#include "qemu/sockets.h" + +#ifdef QCRYPTO_HAVE_TLS_TEST_SUPPORT + +/* + * This stores some static data that is needed when + * encoding extensions in the x509 certs + */ +ASN1_TYPE pkix_asn1; + +/* + * To avoid consuming random entropy to generate keys, + * here's one we prepared earlier :-) + */ +gnutls_x509_privkey_t privkey; +# define PRIVATE_KEY \ + "-----BEGIN PRIVATE KEY-----\n" \ + "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBALVcr\n" \ + "BL40Tm6yq88FBhJNw1aaoCjmtg0l4dWQZ/e9Fimx4ARxFpT+ji4FE\n" \ + "Cgl9s/SGqC+1nvlkm9ViSo0j7MKDbnDB+VRHDvMAzQhA2X7e8M0n9\n" \ + "rPolUY2lIVC83q0BBaOBkCj2RSmT2xTEbbC2xLukSrg2WP/ihVOxc\n" \ + "kXRuyFtzAgMBAAECgYB7slBexDwXrtItAMIH6m/U+LUpNe0Xx48OL\n" \ + "IOn4a4whNgO/o84uIwygUK27ZGFZT0kAGAk8CdF9hA6ArcbQ62s1H\n" \ + "myxrUbF9/mrLsQw1NEqpuUk9Ay2Tx5U/wPx35S3W/X2AvR/ZpTnCn\n" \ + "2q/7ym9fyiSoj86drD7BTvmKXlOnOwQJBAPOFMp4mMa9NGpGuEssO\n" \ + "m3Uwbp6lhcP0cA9MK+iOmeANpoKWfBdk5O34VbmeXnGYWEkrnX+9J\n" \ + "bM4wVhnnBWtgBMCQQC+qAEmvwcfhauERKYznMVUVksyeuhxhCe7EK\n" \ + "mPh+U2+g0WwdKvGDgO0PPt1gq0ILEjspMDeMHVdTwkaVBo/uMhAkA\n" \ + "Z5SsZyCP2aTOPFDypXRdI4eqRcjaEPOUBq27r3uYb/jeboVb2weLa\n" \ + "L1MmVuHiIHoa5clswPdWVI2y0em2IGoDAkBPSp/v9VKJEZabk9Frd\n" \ + "a+7u4fanrM9QrEjY3KhduslSilXZZSxrWjjAJPyPiqFb3M8XXA26W\n" \ + "nz1KYGnqYKhLcBAkB7dt57n9xfrhDpuyVEv+Uv1D3VVAhZlsaZ5Pp\n" \ + "dcrhrkJn2sa/+O8OKvdrPSeeu/N5WwYhJf61+CPoenMp7IFci\n" \ + "-----END PRIVATE KEY-----\n" + +/* + * This loads the private key we defined earlier + */ +static gnutls_x509_privkey_t test_tls_load_key(void) +{ + gnutls_x509_privkey_t key; + const gnutls_datum_t data = { (unsigned char *)PRIVATE_KEY, + strlen(PRIVATE_KEY) }; + int err; + + err = gnutls_x509_privkey_init(&key); + if (err < 0) { + g_critical("Failed to init key %s", gnutls_strerror(err)); + abort(); + } + + err = gnutls_x509_privkey_import(key, &data, + GNUTLS_X509_FMT_PEM); + if (err < 0) { + if (err != GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR && + err != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { + g_critical("Failed to import key %s", gnutls_strerror(err)); + abort(); + } + + err = gnutls_x509_privkey_import_pkcs8( + key, &data, GNUTLS_X509_FMT_PEM, NULL, 0); + if (err < 0) { + g_critical("Failed to import PKCS8 key %s", gnutls_strerror(err)); + abort(); + } + } + + return key; +} + + +void test_tls_init(const char *keyfile) +{ + gnutls_global_init(); + + if (asn1_array2tree(pkix_asn1_tab, &pkix_asn1, NULL) != ASN1_SUCCESS) { + abort(); + } + + privkey = test_tls_load_key(); + if (!g_file_set_contents(keyfile, PRIVATE_KEY, -1, NULL)) { + abort(); + } +} + + +void test_tls_cleanup(const char *keyfile) +{ + asn1_delete_structure(&pkix_asn1); + unlink(keyfile); +} + +/* + * Turns an ASN1 object into a DER encoded byte array + */ +static void test_tls_der_encode(ASN1_TYPE src, + const char *src_name, + gnutls_datum_t *res) +{ + int size; + char *data = NULL; + + size = 0; + asn1_der_coding(src, src_name, NULL, &size, NULL); + + data = g_new0(char, size); + + asn1_der_coding(src, src_name, data, &size, NULL); + + res->data = (unsigned char *)data; + res->size = size; +} + + +static void +test_tls_get_ipaddr(const char *addrstr, + char **data, + int *datalen) +{ + struct addrinfo *res; + struct addrinfo hints; + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_NUMERICHOST; + g_assert(getaddrinfo(addrstr, NULL, &hints, &res) == 0); + + *datalen = res->ai_addrlen; + *data = g_new(char, *datalen); + memcpy(*data, res->ai_addr, *datalen); + freeaddrinfo(res); +} + +/* + * This is a fairly lame x509 certificate generator. + * + * Do not copy/use this code for generating real certificates + * since it leaves out many things that you would want in + * certificates for real world usage. + * + * This is good enough only for doing tests of the QEMU + * TLS certificate code + */ +void +test_tls_generate_cert(QCryptoTLSTestCertReq *req, + gnutls_x509_crt_t ca) +{ + gnutls_x509_crt_t crt; + int err; + static char buffer[1024 * 1024]; + size_t size = sizeof(buffer); + char serial[5] = { 1, 2, 3, 4, 0 }; + gnutls_datum_t der; + time_t start = time(NULL) + (60 * 60 * req->start_offset); + time_t expire = time(NULL) + (60 * 60 * (req->expire_offset + ? req->expire_offset : 24)); + + /* + * Prepare our new certificate object + */ + err = gnutls_x509_crt_init(&crt); + if (err < 0) { + g_critical("Failed to initialize certificate %s", gnutls_strerror(err)); + abort(); + } + err = gnutls_x509_crt_set_key(crt, privkey); + if (err < 0) { + g_critical("Failed to set certificate key %s", gnutls_strerror(err)); + abort(); + } + + /* + * A v3 certificate is required in order to be able + * set any of the basic constraints, key purpose and + * key usage data + */ + gnutls_x509_crt_set_version(crt, 3); + + if (req->country) { + err = gnutls_x509_crt_set_dn_by_oid( + crt, GNUTLS_OID_X520_COUNTRY_NAME, 0, + req->country, strlen(req->country)); + if (err < 0) { + g_critical("Failed to set certificate country name %s", + gnutls_strerror(err)); + abort(); + } + } + if (req->cn) { + err = gnutls_x509_crt_set_dn_by_oid( + crt, GNUTLS_OID_X520_COMMON_NAME, 0, + req->cn, strlen(req->cn)); + if (err < 0) { + g_critical("Failed to set certificate common name %s", + gnutls_strerror(err)); + abort(); + } + } + + /* + * Setup the subject altnames, which are used + * for hostname checks in live sessions + */ + if (req->altname1) { + err = gnutls_x509_crt_set_subject_alt_name( + crt, GNUTLS_SAN_DNSNAME, + req->altname1, + strlen(req->altname1), + GNUTLS_FSAN_APPEND); + if (err < 0) { + g_critical("Failed to set certificate alt name %s", + gnutls_strerror(err)); + abort(); + } + } + if (req->altname2) { + err = gnutls_x509_crt_set_subject_alt_name( + crt, GNUTLS_SAN_DNSNAME, + req->altname2, + strlen(req->altname2), + GNUTLS_FSAN_APPEND); + if (err < 0) { + g_critical("Failed to set certificate %s alt name", + gnutls_strerror(err)); + abort(); + } + } + + /* + * IP address need to be put into the cert in their + * raw byte form, not strings, hence this is a little + * more complicated + */ + if (req->ipaddr1) { + char *data; + int len; + + test_tls_get_ipaddr(req->ipaddr1, &data, &len); + + err = gnutls_x509_crt_set_subject_alt_name( + crt, GNUTLS_SAN_IPADDRESS, + data, len, GNUTLS_FSAN_APPEND); + if (err < 0) { + g_critical("Failed to set certificate alt name %s", + gnutls_strerror(err)); + abort(); + } + g_free(data); + } + if (req->ipaddr2) { + char *data; + int len; + + test_tls_get_ipaddr(req->ipaddr2, &data, &len); + + err = gnutls_x509_crt_set_subject_alt_name( + crt, GNUTLS_SAN_IPADDRESS, + data, len, GNUTLS_FSAN_APPEND); + if (err < 0) { + g_critical("Failed to set certificate alt name %s", + gnutls_strerror(err)); + abort(); + } + g_free(data); + } + + + /* + * Basic constraints are used to decide if the cert + * is for a CA or not. We can't use the convenient + * gnutls API for setting this, since it hardcodes + * the 'critical' field which we want control over + */ + if (req->basicConstraintsEnable) { + ASN1_TYPE ext = ASN1_TYPE_EMPTY; + + asn1_create_element(pkix_asn1, "PKIX1.BasicConstraints", &ext); + asn1_write_value(ext, "cA", + req->basicConstraintsIsCA ? "TRUE" : "FALSE", 1); + asn1_write_value(ext, "pathLenConstraint", NULL, 0); + test_tls_der_encode(ext, "", &der); + err = gnutls_x509_crt_set_extension_by_oid( + crt, "2.5.29.19", + der.data, der.size, + req->basicConstraintsCritical); + if (err < 0) { + g_critical("Failed to set certificate basic constraints %s", + gnutls_strerror(err)); + g_free(der.data); + abort(); + } + asn1_delete_structure(&ext); + g_free(der.data); + } + + /* + * Next up the key usage extension. Again we can't + * use the gnutls API since it hardcodes the extension + * to be 'critical' + */ + if (req->keyUsageEnable) { + ASN1_TYPE ext = ASN1_TYPE_EMPTY; + char str[2]; + + str[0] = req->keyUsageValue & 0xff; + str[1] = (req->keyUsageValue >> 8) & 0xff; + + asn1_create_element(pkix_asn1, "PKIX1.KeyUsage", &ext); + asn1_write_value(ext, "", str, 9); + test_tls_der_encode(ext, "", &der); + err = gnutls_x509_crt_set_extension_by_oid( + crt, "2.5.29.15", + der.data, der.size, + req->keyUsageCritical); + if (err < 0) { + g_critical("Failed to set certificate key usage %s", + gnutls_strerror(err)); + g_free(der.data); + abort(); + } + asn1_delete_structure(&ext); + g_free(der.data); + } + + /* + * Finally the key purpose extension. This time + * gnutls has the opposite problem, always hardcoding + * it to be non-critical. So once again we have to + * set this the hard way building up ASN1 data ourselves + */ + if (req->keyPurposeEnable) { + ASN1_TYPE ext = ASN1_TYPE_EMPTY; + + asn1_create_element(pkix_asn1, "PKIX1.ExtKeyUsageSyntax", &ext); + if (req->keyPurposeOID1) { + asn1_write_value(ext, "", "NEW", 1); + asn1_write_value(ext, "?LAST", req->keyPurposeOID1, 1); + } + if (req->keyPurposeOID2) { + asn1_write_value(ext, "", "NEW", 1); + asn1_write_value(ext, "?LAST", req->keyPurposeOID2, 1); + } + test_tls_der_encode(ext, "", &der); + err = gnutls_x509_crt_set_extension_by_oid( + crt, "2.5.29.37", + der.data, der.size, + req->keyPurposeCritical); + if (err < 0) { + g_critical("Failed to set certificate key purpose %s", + gnutls_strerror(err)); + g_free(der.data); + abort(); + } + asn1_delete_structure(&ext); + g_free(der.data); + } + + /* + * Any old serial number will do, so lets pick 5 + */ + err = gnutls_x509_crt_set_serial(crt, serial, 5); + if (err < 0) { + g_critical("Failed to set certificate serial %s", + gnutls_strerror(err)); + abort(); + } + + err = gnutls_x509_crt_set_activation_time(crt, start); + if (err < 0) { + g_critical("Failed to set certificate activation %s", + gnutls_strerror(err)); + abort(); + } + err = gnutls_x509_crt_set_expiration_time(crt, expire); + if (err < 0) { + g_critical("Failed to set certificate expiration %s", + gnutls_strerror(err)); + abort(); + } + + + /* + * If no 'ca' is set then we are self signing + * the cert. This is done for the root CA certs + */ + err = gnutls_x509_crt_sign(crt, ca ? ca : crt, privkey); + if (err < 0) { + g_critical("Failed to sign certificate %s", + gnutls_strerror(err)); + abort(); + } + + /* + * Finally write the new cert out to disk + */ + err = gnutls_x509_crt_export( + crt, GNUTLS_X509_FMT_PEM, buffer, &size); + if (err < 0) { + g_critical("Failed to export certificate %s: %d", + gnutls_strerror(err), err); + abort(); + } + + if (!g_file_set_contents(req->filename, buffer, -1, NULL)) { + g_critical("Failed to write certificate %s", + req->filename); + abort(); + } + + req->crt = crt; +} + + +void test_tls_write_cert_chain(const char *filename, + gnutls_x509_crt_t *certs, + size_t ncerts) +{ + size_t i; + size_t capacity = 1024, offset = 0; + char *buffer = g_new0(char, capacity); + int err; + + for (i = 0; i < ncerts; i++) { + size_t len = capacity - offset; + retry: + err = gnutls_x509_crt_export(certs[i], GNUTLS_X509_FMT_PEM, + buffer + offset, &len); + if (err < 0) { + if (err == GNUTLS_E_SHORT_MEMORY_BUFFER) { + buffer = g_renew(char, buffer, offset + len); + capacity = offset + len; + goto retry; + } + g_critical("Failed to export certificate chain %s: %d", + gnutls_strerror(err), err); + abort(); + } + offset += len; + } + + if (!g_file_set_contents(filename, buffer, offset, NULL)) { + abort(); + } + g_free(buffer); +} + + +void test_tls_discard_cert(QCryptoTLSTestCertReq *req) +{ + if (!req->crt) { + return; + } + + gnutls_x509_crt_deinit(req->crt); + req->crt = NULL; + + if (getenv("QEMU_TEST_DEBUG_CERTS") == NULL) { + unlink(req->filename); + } +} + +#endif /* QCRYPTO_HAVE_TLS_TEST_SUPPORT */ diff --git a/qemu/tests/crypto-tls-x509-helpers.h b/qemu/tests/crypto-tls-x509-helpers.h new file mode 100644 index 000000000..356b49cd5 --- /dev/null +++ b/qemu/tests/crypto-tls-x509-helpers.h @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Author: Daniel P. Berrange <berrange@redhat.com> + */ + +#include <gnutls/gnutls.h> +#include <gnutls/x509.h> + +#include <gnutls/gnutls.h> +#include <gnutls/x509.h> + +#if !(defined WIN32) && \ + defined(CONFIG_TASN1) && \ + defined(LIBGNUTLS_VERSION_NUMBER) && \ + (LIBGNUTLS_VERSION_NUMBER >= 0x020600) +# define QCRYPTO_HAVE_TLS_TEST_SUPPORT +#endif + +#ifdef QCRYPTO_HAVE_TLS_TEST_SUPPORT +# include <libtasn1.h> + +# include "qemu-common.h" + +/* + * This contains parameter about how to generate + * certificates. + */ +typedef struct QCryptoTLSTestCertReq QCryptoTLSTestCertReq; +struct QCryptoTLSTestCertReq { + gnutls_x509_crt_t crt; + + const char *filename; + + /* Identifying information */ + const char *country; + const char *cn; + const char *altname1; + const char *altname2; + const char *ipaddr1; + const char *ipaddr2; + + /* Basic constraints */ + bool basicConstraintsEnable; + bool basicConstraintsCritical; + bool basicConstraintsIsCA; + + /* Key usage */ + bool keyUsageEnable; + bool keyUsageCritical; + int keyUsageValue; + + /* Key purpose (aka Extended key usage) */ + bool keyPurposeEnable; + bool keyPurposeCritical; + const char *keyPurposeOID1; + const char *keyPurposeOID2; + + /* zero for current time, or non-zero for hours from now */ + int start_offset; + /* zero for 24 hours from now, or non-zero for hours from now */ + int expire_offset; +}; + +void test_tls_generate_cert(QCryptoTLSTestCertReq *req, + gnutls_x509_crt_t ca); +void test_tls_write_cert_chain(const char *filename, + gnutls_x509_crt_t *certs, + size_t ncerts); +void test_tls_discard_cert(QCryptoTLSTestCertReq *req); + +void test_tls_init(const char *keyfile); +void test_tls_cleanup(const char *keyfile); + +# define TLS_CERT_REQ(varname, cavarname, \ + country, commonname, \ + altname1, altname2, \ + ipaddr1, ipaddr2, \ + basicconsenable, basicconscritical, basicconsca, \ + keyusageenable, keyusagecritical, keyusagevalue, \ + keypurposeenable, keypurposecritical, \ + keypurposeoid1, keypurposeoid2, \ + startoffset, endoffset) \ + static QCryptoTLSTestCertReq varname = { \ + NULL, WORKDIR #varname "-ctx.pem", \ + country, commonname, altname1, altname2, \ + ipaddr1, ipaddr2, \ + basicconsenable, basicconscritical, basicconsca, \ + keyusageenable, keyusagecritical, keyusagevalue, \ + keypurposeenable, keypurposecritical, \ + keypurposeoid1, keypurposeoid2, \ + startoffset, endoffset \ + }; \ + test_tls_generate_cert(&varname, cavarname.crt) + +# define TLS_ROOT_REQ(varname, \ + country, commonname, \ + altname1, altname2, \ + ipaddr1, ipaddr2, \ + basicconsenable, basicconscritical, basicconsca, \ + keyusageenable, keyusagecritical, keyusagevalue, \ + keypurposeenable, keypurposecritical, \ + keypurposeoid1, keypurposeoid2, \ + startoffset, endoffset) \ + static QCryptoTLSTestCertReq varname = { \ + NULL, WORKDIR #varname "-ctx.pem", \ + country, commonname, altname1, altname2, \ + ipaddr1, ipaddr2, \ + basicconsenable, basicconscritical, basicconsca, \ + keyusageenable, keyusagecritical, keyusagevalue, \ + keypurposeenable, keypurposecritical, \ + keypurposeoid1, keypurposeoid2, \ + startoffset, endoffset \ + }; \ + test_tls_generate_cert(&varname, NULL) + +extern const ASN1_ARRAY_TYPE pkix_asn1_tab[]; + +#endif /* QCRYPTO_HAVE_TLS_TEST_SUPPORT */ diff --git a/qemu/tests/device-introspect-test.c b/qemu/tests/device-introspect-test.c new file mode 100644 index 000000000..447792601 --- /dev/null +++ b/qemu/tests/device-introspect-test.c @@ -0,0 +1,124 @@ +/* + * Device introspection test cases + * + * Copyright (c) 2015 Red Hat Inc. + * + * Authors: + * Markus Armbruster <armbru@redhat.com>, + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +/* + * Covers QMP device-list-properties and HMP device_add help. We + * currently don't check that their output makes sense, only that QEMU + * survives. Useful since we've had an astounding number of crash + * bugs around here. + */ + +#include "qemu/osdep.h" +#include <glib.h> +#include "qemu-common.h" +#include "qapi/qmp/qstring.h" +#include "libqtest.h" + +const char common_args[] = "-nodefaults -machine none"; + +static QList *device_type_list(bool abstract) +{ + QDict *resp; + QList *ret; + + resp = qmp("{'execute': 'qom-list-types'," + " 'arguments': {'implements': 'device', 'abstract': %i}}", + abstract); + g_assert(qdict_haskey(resp, "return")); + ret = qdict_get_qlist(resp, "return"); + QINCREF(ret); + QDECREF(resp); + return ret; +} + +static void test_one_device(const char *type) +{ + QDict *resp; + char *help, *qom_tree; + + resp = qmp("{'execute': 'device-list-properties'," + " 'arguments': {'typename': %s}}", + type); + QDECREF(resp); + + help = hmp("device_add \"%s,help\"", type); + g_free(help); + + /* + * Some devices leave dangling pointers in QOM behind. + * "info qom-tree" has a good chance at crashing then + */ + qom_tree = hmp("info qom-tree"); + g_free(qom_tree); +} + +static void test_device_intro_list(void) +{ + QList *types; + char *help; + + qtest_start(common_args); + + types = device_type_list(true); + QDECREF(types); + + help = hmp("device_add help"); + g_free(help); + + qtest_end(); +} + +static void test_device_intro_none(void) +{ + qtest_start(common_args); + test_one_device("nonexistent"); + qtest_end(); +} + +static void test_device_intro_abstract(void) +{ + qtest_start(common_args); + test_one_device("device"); + qtest_end(); +} + +static void test_device_intro_concrete(void) +{ + QList *types; + QListEntry *entry; + const char *type; + + qtest_start(common_args); + types = device_type_list(false); + + QLIST_FOREACH_ENTRY(types, entry) { + type = qdict_get_try_str(qobject_to_qdict(qlist_entry_obj(entry)), + "name"); + g_assert(type); + test_one_device(type); + } + + QDECREF(types); + qtest_end(); +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + qtest_add_func("device/introspect/list", test_device_intro_list); + qtest_add_func("device/introspect/none", test_device_intro_none); + qtest_add_func("device/introspect/abstract", test_device_intro_abstract); + qtest_add_func("device/introspect/concrete", test_device_intro_concrete); + + return g_test_run(); +} diff --git a/qemu/tests/display-vga-test.c b/qemu/tests/display-vga-test.c index 7694344ea..5706d338a 100644 --- a/qemu/tests/display-vga-test.c +++ b/qemu/tests/display-vga-test.c @@ -7,10 +7,9 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <string.h> #include "libqtest.h" -#include "qemu/osdep.h" static void pci_cirrus(void) { diff --git a/qemu/tests/drive_del-test.c b/qemu/tests/drive_del-test.c index 8951f6f61..fe03236f3 100644 --- a/qemu/tests/drive_del-test.c +++ b/qemu/tests/drive_del-test.c @@ -10,34 +10,24 @@ * See the COPYING.LIB file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <string.h> #include "libqtest.h" static void drive_add(void) { - QDict *response; + char *resp = hmp("drive_add 0 if=none,id=drive0"); - response = qmp("{'execute': 'human-monitor-command'," - " 'arguments': {" - " 'command-line': 'drive_add 0 if=none,id=drive0'" - "}}"); - g_assert(response); - g_assert_cmpstr(qdict_get_try_str(response, "return"), ==, "OK\r\n"); - QDECREF(response); + g_assert_cmpstr(resp, ==, "OK\r\n"); + g_free(resp); } static void drive_del(void) { - QDict *response; + char *resp = hmp("drive_del drive0"); - response = qmp("{'execute': 'human-monitor-command'," - " 'arguments': {" - " 'command-line': 'drive_del drive0'" - "}}"); - g_assert(response); - g_assert_cmpstr(qdict_get_try_str(response, "return"), ==, ""); - QDECREF(response); + g_assert_cmpstr(resp, ==, ""); + g_free(resp); } static void device_del(void) diff --git a/qemu/tests/ds1338-test.c b/qemu/tests/ds1338-test.c new file mode 100644 index 000000000..279241584 --- /dev/null +++ b/qemu/tests/ds1338-test.c @@ -0,0 +1,79 @@ +/* + * QTest testcase for the DS1338 RTC + * + * Copyright (c) 2013 Jean-Christophe Dubois + * + * 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/>. + */ + +#include "qemu/osdep.h" +#include "libqtest.h" +#include "libqos/i2c.h" + +#include <glib.h> + +#define IMX25_I2C_0_BASE 0x43F80000 + +#define DS1338_ADDR 0x68 + +static I2CAdapter *i2c; +static uint8_t addr; + +static inline uint8_t bcd2bin(uint8_t x) +{ + return ((x) & 0x0f) + ((x) >> 4) * 10; +} + +static void send_and_receive(void) +{ + uint8_t cmd[1]; + uint8_t resp[7]; + time_t now = time(NULL); + struct tm *tm_ptr = gmtime(&now); + + /* reset the index in the RTC memory */ + cmd[0] = 0; + i2c_send(i2c, addr, cmd, 1); + + /* retrieve the date */ + i2c_recv(i2c, addr, resp, 7); + + /* check retrieved time againt local time */ + g_assert_cmpuint(bcd2bin(resp[4]), == , tm_ptr->tm_mday); + g_assert_cmpuint(bcd2bin(resp[5]), == , 1 + tm_ptr->tm_mon); + g_assert_cmpuint(2000 + bcd2bin(resp[6]), == , 1900 + tm_ptr->tm_year); +} + +int main(int argc, char **argv) +{ + QTestState *s = NULL; + int ret; + + g_test_init(&argc, &argv, NULL); + + s = qtest_start("-display none -machine imx25-pdk"); + i2c = imx_i2c_create(IMX25_I2C_0_BASE); + addr = DS1338_ADDR; + + qtest_add_func("/ds1338/tx-rx", send_and_receive); + + ret = g_test_run(); + + if (s) { + qtest_quit(s); + } + g_free(i2c); + + return ret; +} diff --git a/qemu/tests/e1000-test.c b/qemu/tests/e1000-test.c index 7ca6d7e72..a42b3810c 100644 --- a/qemu/tests/e1000-test.c +++ b/qemu/tests/e1000-test.c @@ -7,10 +7,9 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <string.h> #include "libqtest.h" -#include "qemu/osdep.h" /* Tests only initialization so far. TODO: Replace with functional tests */ static void test_device(gconstpointer data) diff --git a/qemu/tests/eepro100-test.c b/qemu/tests/eepro100-test.c index 8bfaccdcb..e17eed0b7 100644 --- a/qemu/tests/eepro100-test.c +++ b/qemu/tests/eepro100-test.c @@ -7,10 +7,9 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <string.h> #include "libqtest.h" -#include "qemu/osdep.h" static void test_device(gconstpointer data) { diff --git a/qemu/tests/endianness-test.c b/qemu/tests/endianness-test.c index 2054338e1..cc5bccd88 100644 --- a/qemu/tests/endianness-test.c +++ b/qemu/tests/endianness-test.c @@ -11,11 +11,8 @@ * */ +#include "qemu/osdep.h" #include <glib.h> -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <unistd.h> #include "libqtest.h" #include "qemu/bswap.h" diff --git a/qemu/tests/es1370-test.c b/qemu/tests/es1370-test.c index cc23fb5c6..824dc31c6 100644 --- a/qemu/tests/es1370-test.c +++ b/qemu/tests/es1370-test.c @@ -7,10 +7,9 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <string.h> #include "libqtest.h" -#include "qemu/osdep.h" /* Tests only initialization so far. TODO: Replace with functional tests */ static void nop(void) diff --git a/qemu/tests/fdc-test.c b/qemu/tests/fdc-test.c index 416394fc7..53df1d0d8 100644 --- a/qemu/tests/fdc-test.c +++ b/qemu/tests/fdc-test.c @@ -22,9 +22,7 @@ * THE SOFTWARE. */ -#include <stdint.h> -#include <string.h> -#include <stdio.h> +#include "qemu/osdep.h" #include <glib.h> @@ -267,7 +265,7 @@ static void test_cmos(void) uint8_t cmos; cmos = cmos_read(CMOS_FLOPPY); - g_assert(cmos == 0x40); + g_assert(cmos == 0x40 || cmos == 0x50); } static void test_no_media_on_start(void) @@ -304,9 +302,6 @@ static void test_media_insert(void) qmp_discard_response("{'execute':'change', 'arguments':{" " 'device':'floppy0', 'target': %s, 'arg': 'raw' }}", test_image); - qmp_discard_response(""); /* ignore event - (FIXME open -> open transition?!) */ - qmp_discard_response(""); /* ignore event */ dir = inb(FLOPPY_BASE + reg_dir); assert_bit_set(dir, DSKCHG); @@ -337,7 +332,6 @@ static void test_media_change(void) * reset the bit. */ qmp_discard_response("{'execute':'eject', 'arguments':{" " 'device':'floppy0' }}"); - qmp_discard_response(""); /* ignore event */ dir = inb(FLOPPY_BASE + reg_dir); assert_bit_set(dir, DSKCHG); diff --git a/qemu/tests/fw_cfg-test.c b/qemu/tests/fw_cfg-test.c index 9be78e956..b4392c2d3 100644 --- a/qemu/tests/fw_cfg-test.c +++ b/qemu/tests/fw_cfg-test.c @@ -10,12 +10,11 @@ * See the COPYING file in the top-level directory. */ -#include <string.h> +#include "qemu/osdep.h" #include <glib.h> #include "libqtest.h" -#define NO_QEMU_PROTOS -#include "hw/nvram/fw_cfg.h" +#include "hw/nvram/fw_cfg_keys.h" #include "libqos/fw_cfg.h" static uint64_t ram_size = 128 << 20; @@ -37,7 +36,9 @@ static void test_fw_cfg_signature(void) static void test_fw_cfg_id(void) { - g_assert_cmpint(qfw_cfg_get_u32(fw_cfg, FW_CFG_ID), ==, 1); + uint32_t id = qfw_cfg_get_u32(fw_cfg, FW_CFG_ID); + g_assert((id == 1) || + (id == 3)); } static void test_fw_cfg_uuid(void) diff --git a/qemu/tests/guest-debug/test-gdbstub.py b/qemu/tests/guest-debug/test-gdbstub.py new file mode 100644 index 000000000..31ba6c943 --- /dev/null +++ b/qemu/tests/guest-debug/test-gdbstub.py @@ -0,0 +1,176 @@ +# +# This script needs to be run on startup +# qemu -kernel ${KERNEL} -s -S +# and then: +# gdb ${KERNEL}.vmlinux -x ${QEMU_SRC}/tests/guest-debug/test-gdbstub.py + +import gdb + +failcount = 0 + + +def report(cond, msg): + "Report success/fail of test" + if cond: + print ("PASS: %s" % (msg)) + else: + print ("FAIL: %s" % (msg)) + failcount += 1 + + +def check_step(): + "Step an instruction, check it moved." + start_pc = gdb.parse_and_eval('$pc') + gdb.execute("si") + end_pc = gdb.parse_and_eval('$pc') + + return not (start_pc == end_pc) + + +def check_break(sym_name): + "Setup breakpoint, continue and check we stopped." + sym, ok = gdb.lookup_symbol(sym_name) + bp = gdb.Breakpoint(sym_name) + + gdb.execute("c") + + # hopefully we came back + end_pc = gdb.parse_and_eval('$pc') + print ("%s == %s %d" % (end_pc, sym.value(), bp.hit_count)) + bp.delete() + + # can we test we hit bp? + return end_pc == sym.value() + + +# We need to do hbreak manually as the python interface doesn't export it +def check_hbreak(sym_name): + "Setup hardware breakpoint, continue and check we stopped." + sym, ok = gdb.lookup_symbol(sym_name) + gdb.execute("hbreak %s" % (sym_name)) + gdb.execute("c") + + # hopefully we came back + end_pc = gdb.parse_and_eval('$pc') + print ("%s == %s" % (end_pc, sym.value())) + + if end_pc == sym.value(): + gdb.execute("d 1") + return True + else: + return False + + +class WatchPoint(gdb.Breakpoint): + + def get_wpstr(self, sym_name): + "Setup sym and wp_str for given symbol." + self.sym, ok = gdb.lookup_symbol(sym_name) + wp_addr = gdb.parse_and_eval(sym_name).address + self.wp_str = '*(%(type)s)(&%(address)s)' % dict( + type = wp_addr.type, address = sym_name) + + return(self.wp_str) + + def __init__(self, sym_name, type): + wp_str = self.get_wpstr(sym_name) + super(WatchPoint, self).__init__(wp_str, gdb.BP_WATCHPOINT, type) + + def stop(self): + end_pc = gdb.parse_and_eval('$pc') + print ("HIT WP @ %s" % (end_pc)) + return True + + +def do_one_watch(sym, wtype, text): + + wp = WatchPoint(sym, wtype) + gdb.execute("c") + report_str = "%s for %s (%s)" % (text, sym, wp.sym.value()) + + if wp.hit_count > 0: + report(True, report_str) + wp.delete() + else: + report(False, report_str) + + +def check_watches(sym_name): + "Watch a symbol for any access." + + # Should hit for any read + do_one_watch(sym_name, gdb.WP_ACCESS, "awatch") + + # Again should hit for reads + do_one_watch(sym_name, gdb.WP_READ, "rwatch") + + # Finally when it is written + do_one_watch(sym_name, gdb.WP_WRITE, "watch") + + +class CatchBreakpoint(gdb.Breakpoint): + def __init__(self, sym_name): + super(CatchBreakpoint, self).__init__(sym_name) + self.sym, ok = gdb.lookup_symbol(sym_name) + + def stop(self): + end_pc = gdb.parse_and_eval('$pc') + print ("CB: %s == %s" % (end_pc, self.sym.value())) + if end_pc == self.sym.value(): + report(False, "Hit final catchpoint") + + +def run_test(): + "Run throught the tests one by one" + + print ("Checking we can step the first few instructions") + step_ok = 0 + for i in range(3): + if check_step(): + step_ok += 1 + + report(step_ok == 3, "single step in boot code") + + print ("Checking HW breakpoint works") + break_ok = check_hbreak("kernel_init") + report(break_ok, "hbreak @ kernel_init") + + # Can't set this up until we are in the kernel proper + # if we make it to run_init_process we've over-run and + # one of the tests failed + print ("Setup catch-all for run_init_process") + cbp = CatchBreakpoint("run_init_process") + cpb2 = CatchBreakpoint("try_to_run_init_process") + + print ("Checking Normal breakpoint works") + break_ok = check_break("wait_for_completion") + report(break_ok, "break @ wait_for_completion") + + print ("Checking watchpoint works") + check_watches("system_state") + +# +# This runs as the script it sourced (via -x) +# + +try: + print ("Connecting to remote") + gdb.execute("target remote localhost:1234") + + # These are not very useful in scripts + gdb.execute("set pagination off") + gdb.execute("set confirm off") + + # Run the actual tests + run_test() + +except: + print ("GDB Exception: %s" % (sys.exc_info()[0])) + failcount += 1 + import code + code.InteractiveConsole(locals=globals()).interact() + raise + +# Finally kill the inferior and exit gdb with a count of failures +gdb.execute("kill") +exit(failcount) diff --git a/qemu/tests/hd-geo-test.c b/qemu/tests/hd-geo-test.c index 00afc209e..c8e669ac2 100644 --- a/qemu/tests/hd-geo-test.c +++ b/qemu/tests/hd-geo-test.c @@ -15,10 +15,8 @@ * Improvements welcome. */ +#include "qemu/osdep.h" #include <glib.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> #include "qemu-common.h" #include "libqtest.h" @@ -206,13 +204,13 @@ static int setup_ide(int argc, char *argv[], int argv_sz, { char *s1, *s2, *s3; - s1 = g_strdup_printf("-drive id=drive%d,if=%s,format=raw", + s1 = g_strdup_printf("-drive id=drive%d,if=%s", ide_idx, dev ? "none" : "ide"); s2 = dev ? g_strdup("") : g_strdup_printf(",index=%d", ide_idx); if (img_secs[img_idx] >= 0) { setup_mbr(img_idx, mbr); - s3 = g_strdup_printf(",file=%s", img_file_name[img_idx]); + s3 = g_strdup_printf(",format=raw,file=%s", img_file_name[img_idx]); } else { s3 = g_strdup(",media=cdrom"); } diff --git a/qemu/tests/i440fx-test.c b/qemu/tests/i440fx-test.c index d0bc8de25..05029e90b 100644 --- a/qemu/tests/i440fx-test.c +++ b/qemu/tests/i440fx-test.c @@ -12,13 +12,9 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <string.h> -#include <stdio.h> -#include <unistd.h> -#include <errno.h> #include <sys/mman.h> -#include <stdlib.h> #include "libqtest.h" #include "libqos/pci.h" @@ -27,8 +23,6 @@ #define BROKEN 1 -#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) - typedef struct TestData { int num_cpus; @@ -191,7 +185,7 @@ static void write_area(uint32_t start, uint32_t end, uint8_t value) uint32_t size = end - start + 1; uint8_t *data; - data = g_malloc0(size); + data = g_malloc(size); memset(data, value, size); memwrite(start, data, size); diff --git a/qemu/tests/i82801b11-test.c b/qemu/tests/i82801b11-test.c index 78d9ce0e6..c3b5ebbca 100644 --- a/qemu/tests/i82801b11-test.c +++ b/qemu/tests/i82801b11-test.c @@ -7,10 +7,9 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <string.h> #include "libqtest.h" -#include "qemu/osdep.h" /* Tests only initialization so far. TODO: Replace with functional tests */ static void nop(void) diff --git a/qemu/tests/ide-test.c b/qemu/tests/ide-test.c index 4a07e3a9d..0d9ab4df9 100644 --- a/qemu/tests/ide-test.c +++ b/qemu/tests/ide-test.c @@ -22,9 +22,7 @@ * THE SOFTWARE. */ -#include <stdint.h> -#include <string.h> -#include <stdio.h> +#include "qemu/osdep.h" #include <glib.h> @@ -45,8 +43,15 @@ #define IDE_BASE 0x1f0 #define IDE_PRIMARY_IRQ 14 +#define ATAPI_BLOCK_SIZE 2048 + +/* How many bytes to receive via ATAPI PIO at one time. + * Must be less than 0xFFFF. */ +#define BYTE_COUNT_LIMIT 5120 + enum { reg_data = 0x0, + reg_feature = 0x1, reg_nsectors = 0x2, reg_lba_low = 0x3, reg_lba_middle = 0x4, @@ -80,6 +85,7 @@ enum { CMD_WRITE_DMA = 0xca, CMD_FLUSH_CACHE = 0xe7, CMD_IDENTIFY = 0xec, + CMD_PACKET = 0xa0, CMDF_ABORT = 0x100, CMDF_NO_BM = 0x200, @@ -172,7 +178,8 @@ typedef struct PrdtEntry { #define assert_bit_clear(data, mask) g_assert_cmphex((data) & (mask), ==, 0) static int send_dma_request(int cmd, uint64_t sector, int nb_sectors, - PrdtEntry *prdt, int prdt_entries) + PrdtEntry *prdt, int prdt_entries, + void(*post_exec)(uint64_t sector, int nb_sectors)) { QPCIDevice *dev; uint16_t bmdma_base; @@ -189,6 +196,9 @@ static int send_dma_request(int cmd, uint64_t sector, int nb_sectors, switch (cmd) { case CMD_READ_DMA: + case CMD_PACKET: + /* Assuming we only test data reads w/ ATAPI, otherwise we need to know + * the SCSI command being sent in the packet, too. */ from_dev = true; break; case CMD_WRITE_DMA: @@ -217,14 +227,22 @@ static int send_dma_request(int cmd, uint64_t sector, int nb_sectors, outl(bmdma_base + bmreg_prdt, guest_prdt); /* ATA DMA command */ - outb(IDE_BASE + reg_nsectors, nb_sectors); - - outb(IDE_BASE + reg_lba_low, sector & 0xff); - outb(IDE_BASE + reg_lba_middle, (sector >> 8) & 0xff); - outb(IDE_BASE + reg_lba_high, (sector >> 16) & 0xff); + if (cmd == CMD_PACKET) { + /* Enables ATAPI DMA; otherwise PIO is attempted */ + outb(IDE_BASE + reg_feature, 0x01); + } else { + outb(IDE_BASE + reg_nsectors, nb_sectors); + outb(IDE_BASE + reg_lba_low, sector & 0xff); + outb(IDE_BASE + reg_lba_middle, (sector >> 8) & 0xff); + outb(IDE_BASE + reg_lba_high, (sector >> 16) & 0xff); + } outb(IDE_BASE + reg_command, cmd); + if (post_exec) { + post_exec(sector, nb_sectors); + } + /* Start DMA transfer */ outb(bmdma_base + bmreg_cmd, BM_CMD_START | (from_dev ? BM_CMD_WRITE : 0)); @@ -278,7 +296,8 @@ static void test_bmdma_simple_rw(void) memset(buf, 0x55, len); memwrite(guest_buf, buf, len); - status = send_dma_request(CMD_WRITE_DMA, 0, 1, prdt, ARRAY_SIZE(prdt)); + status = send_dma_request(CMD_WRITE_DMA, 0, 1, prdt, + ARRAY_SIZE(prdt), NULL); g_assert_cmphex(status, ==, BM_STS_INTR); assert_bit_clear(inb(IDE_BASE + reg_status), DF | ERR); @@ -286,14 +305,15 @@ static void test_bmdma_simple_rw(void) memset(buf, 0xaa, len); memwrite(guest_buf, buf, len); - status = send_dma_request(CMD_WRITE_DMA, 1, 1, prdt, ARRAY_SIZE(prdt)); + status = send_dma_request(CMD_WRITE_DMA, 1, 1, prdt, + ARRAY_SIZE(prdt), NULL); g_assert_cmphex(status, ==, BM_STS_INTR); assert_bit_clear(inb(IDE_BASE + reg_status), DF | ERR); /* Read and verify 0x55 pattern in sector 0 */ memset(cmpbuf, 0x55, len); - status = send_dma_request(CMD_READ_DMA, 0, 1, prdt, ARRAY_SIZE(prdt)); + status = send_dma_request(CMD_READ_DMA, 0, 1, prdt, ARRAY_SIZE(prdt), NULL); g_assert_cmphex(status, ==, BM_STS_INTR); assert_bit_clear(inb(IDE_BASE + reg_status), DF | ERR); @@ -303,7 +323,7 @@ static void test_bmdma_simple_rw(void) /* Read and verify 0xaa pattern in sector 1 */ memset(cmpbuf, 0xaa, len); - status = send_dma_request(CMD_READ_DMA, 1, 1, prdt, ARRAY_SIZE(prdt)); + status = send_dma_request(CMD_READ_DMA, 1, 1, prdt, ARRAY_SIZE(prdt), NULL); g_assert_cmphex(status, ==, BM_STS_INTR); assert_bit_clear(inb(IDE_BASE + reg_status), DF | ERR); @@ -328,13 +348,13 @@ static void test_bmdma_short_prdt(void) /* Normal request */ status = send_dma_request(CMD_READ_DMA, 0, 1, - prdt, ARRAY_SIZE(prdt)); + prdt, ARRAY_SIZE(prdt), NULL); g_assert_cmphex(status, ==, 0); assert_bit_clear(inb(IDE_BASE + reg_status), DF | ERR); /* Abort the request before it completes */ status = send_dma_request(CMD_READ_DMA | CMDF_ABORT, 0, 1, - prdt, ARRAY_SIZE(prdt)); + prdt, ARRAY_SIZE(prdt), NULL); g_assert_cmphex(status, ==, 0); assert_bit_clear(inb(IDE_BASE + reg_status), DF | ERR); } @@ -353,13 +373,13 @@ static void test_bmdma_one_sector_short_prdt(void) /* Normal request */ status = send_dma_request(CMD_READ_DMA, 0, 2, - prdt, ARRAY_SIZE(prdt)); + prdt, ARRAY_SIZE(prdt), NULL); g_assert_cmphex(status, ==, 0); assert_bit_clear(inb(IDE_BASE + reg_status), DF | ERR); /* Abort the request before it completes */ status = send_dma_request(CMD_READ_DMA | CMDF_ABORT, 0, 2, - prdt, ARRAY_SIZE(prdt)); + prdt, ARRAY_SIZE(prdt), NULL); g_assert_cmphex(status, ==, 0); assert_bit_clear(inb(IDE_BASE + reg_status), DF | ERR); } @@ -377,13 +397,13 @@ static void test_bmdma_long_prdt(void) /* Normal request */ status = send_dma_request(CMD_READ_DMA, 0, 1, - prdt, ARRAY_SIZE(prdt)); + prdt, ARRAY_SIZE(prdt), NULL); g_assert_cmphex(status, ==, BM_STS_ACTIVE | BM_STS_INTR); assert_bit_clear(inb(IDE_BASE + reg_status), DF | ERR); /* Abort the request before it completes */ status = send_dma_request(CMD_READ_DMA | CMDF_ABORT, 0, 1, - prdt, ARRAY_SIZE(prdt)); + prdt, ARRAY_SIZE(prdt), NULL); g_assert_cmphex(status, ==, BM_STS_INTR); assert_bit_clear(inb(IDE_BASE + reg_status), DF | ERR); } @@ -399,7 +419,7 @@ static void test_bmdma_no_busmaster(void) PrdtEntry prdt[4096] = { }; status = send_dma_request(CMD_READ_DMA | CMDF_NO_BM, 0, 512, - prdt, ARRAY_SIZE(prdt)); + prdt, ARRAY_SIZE(prdt), NULL); /* Not entirely clear what the expected result is, but this is what we get * in practice. At least we want to be aware of any changes. */ @@ -488,9 +508,7 @@ static void test_flush(void) tmp_path); /* Delay the completion of the flush request until we explicitly do it */ - qmp_discard_response("{'execute':'human-monitor-command', 'arguments': {" - " 'command-line':" - " 'qemu-io ide0-hd0 \"break flush_to_os A\"'} }"); + g_free(hmp("qemu-io ide0-hd0 \"break flush_to_os A\"")); /* FLUSH CACHE command on device 0*/ outb(IDE_BASE + reg_device, 0); @@ -502,9 +520,7 @@ static void test_flush(void) assert_bit_clear(data, DF | ERR | DRQ); /* Complete the command */ - qmp_discard_response("{'execute':'human-monitor-command', 'arguments': {" - " 'command-line':" - " 'qemu-io ide0-hd0 \"resume A\"'} }"); + g_free(hmp("qemu-io ide0-hd0 \"resume A\"")); /* Check registers */ data = inb(IDE_BASE + reg_device); @@ -575,16 +591,215 @@ static void test_flush_nodev(void) ide_test_quit(); } -static void test_pci_retry_flush(const char *machine) +static void test_pci_retry_flush(void) { test_retry_flush("pc"); } -static void test_isa_retry_flush(const char *machine) +static void test_isa_retry_flush(void) { test_retry_flush("isapc"); } +typedef struct Read10CDB { + uint8_t opcode; + uint8_t flags; + uint32_t lba; + uint8_t reserved; + uint16_t nblocks; + uint8_t control; + uint16_t padding; +} __attribute__((__packed__)) Read10CDB; + +static void send_scsi_cdb_read10(uint64_t lba, int nblocks) +{ + Read10CDB pkt = { .padding = 0 }; + int i; + + g_assert_cmpint(lba, <=, UINT32_MAX); + g_assert_cmpint(nblocks, <=, UINT16_MAX); + g_assert_cmpint(nblocks, >=, 0); + + /* Construct SCSI CDB packet */ + pkt.opcode = 0x28; + pkt.lba = cpu_to_be32(lba); + pkt.nblocks = cpu_to_be16(nblocks); + + /* Send Packet */ + for (i = 0; i < sizeof(Read10CDB)/2; i++) { + outw(IDE_BASE + reg_data, cpu_to_le16(((uint16_t *)&pkt)[i])); + } +} + +static void nsleep(int64_t nsecs) +{ + const struct timespec val = { .tv_nsec = nsecs }; + nanosleep(&val, NULL); + clock_set(nsecs); +} + +static uint8_t ide_wait_clear(uint8_t flag) +{ + uint8_t data; + time_t st; + + /* Wait with a 5 second timeout */ + time(&st); + while (true) { + data = inb(IDE_BASE + reg_status); + if (!(data & flag)) { + return data; + } + if (difftime(time(NULL), st) > 5.0) { + break; + } + nsleep(400); + } + g_assert_not_reached(); +} + +static void ide_wait_intr(int irq) +{ + time_t st; + bool intr; + + time(&st); + while (true) { + intr = get_irq(irq); + if (intr) { + return; + } + if (difftime(time(NULL), st) > 5.0) { + break; + } + nsleep(400); + } + + g_assert_not_reached(); +} + +static void cdrom_pio_impl(int nblocks) +{ + FILE *fh; + int patt_blocks = MAX(16, nblocks); + size_t patt_len = ATAPI_BLOCK_SIZE * patt_blocks; + char *pattern = g_malloc(patt_len); + size_t rxsize = ATAPI_BLOCK_SIZE * nblocks; + uint16_t *rx = g_malloc0(rxsize); + int i, j; + uint8_t data; + uint16_t limit; + + /* Prepopulate the CDROM with an interesting pattern */ + generate_pattern(pattern, patt_len, ATAPI_BLOCK_SIZE); + fh = fopen(tmp_path, "w+"); + fwrite(pattern, ATAPI_BLOCK_SIZE, patt_blocks, fh); + fclose(fh); + + ide_test_start("-drive if=none,file=%s,media=cdrom,format=raw,id=sr0,index=0 " + "-device ide-cd,drive=sr0,bus=ide.0", tmp_path); + qtest_irq_intercept_in(global_qtest, "ioapic"); + + /* PACKET command on device 0 */ + outb(IDE_BASE + reg_device, 0); + outb(IDE_BASE + reg_lba_middle, BYTE_COUNT_LIMIT & 0xFF); + outb(IDE_BASE + reg_lba_high, (BYTE_COUNT_LIMIT >> 8 & 0xFF)); + outb(IDE_BASE + reg_command, CMD_PACKET); + /* HP0: Check_Status_A State */ + nsleep(400); + data = ide_wait_clear(BSY); + /* HP1: Send_Packet State */ + assert_bit_set(data, DRQ | DRDY); + assert_bit_clear(data, ERR | DF | BSY); + + /* SCSI CDB (READ10) -- read n*2048 bytes from block 0 */ + send_scsi_cdb_read10(0, nblocks); + + /* Read data back: occurs in bursts of 'BYTE_COUNT_LIMIT' bytes. + * If BYTE_COUNT_LIMIT is odd, we transfer BYTE_COUNT_LIMIT - 1 bytes. + * We allow an odd limit only when the remaining transfer size is + * less than BYTE_COUNT_LIMIT. However, SCSI's read10 command can only + * request n blocks, so our request size is always even. + * For this reason, we assume there is never a hanging byte to fetch. */ + g_assert(!(rxsize & 1)); + limit = BYTE_COUNT_LIMIT & ~1; + for (i = 0; i < DIV_ROUND_UP(rxsize, limit); i++) { + size_t offset = i * (limit / 2); + size_t rem = (rxsize / 2) - offset; + + /* HP3: INTRQ_Wait */ + ide_wait_intr(IDE_PRIMARY_IRQ); + + /* HP2: Check_Status_B (and clear IRQ) */ + data = ide_wait_clear(BSY); + assert_bit_set(data, DRQ | DRDY); + assert_bit_clear(data, ERR | DF | BSY); + + /* HP4: Transfer_Data */ + for (j = 0; j < MIN((limit / 2), rem); j++) { + rx[offset + j] = le16_to_cpu(inw(IDE_BASE + reg_data)); + } + } + + /* Check for final completion IRQ */ + ide_wait_intr(IDE_PRIMARY_IRQ); + + /* Sanity check final state */ + data = ide_wait_clear(DRQ); + assert_bit_set(data, DRDY); + assert_bit_clear(data, DRQ | ERR | DF | BSY); + + g_assert_cmpint(memcmp(pattern, rx, rxsize), ==, 0); + g_free(pattern); + g_free(rx); + test_bmdma_teardown(); +} + +static void test_cdrom_pio(void) +{ + cdrom_pio_impl(1); +} + +static void test_cdrom_pio_large(void) +{ + /* Test a few loops of the PIO DRQ mechanism. */ + cdrom_pio_impl(BYTE_COUNT_LIMIT * 4 / ATAPI_BLOCK_SIZE); +} + + +static void test_cdrom_dma(void) +{ + static const size_t len = ATAPI_BLOCK_SIZE; + char *pattern = g_malloc(ATAPI_BLOCK_SIZE * 16); + char *rx = g_malloc0(len); + uintptr_t guest_buf; + PrdtEntry prdt[1]; + FILE *fh; + + ide_test_start("-drive if=none,file=%s,media=cdrom,format=raw,id=sr0,index=0 " + "-device ide-cd,drive=sr0,bus=ide.0", tmp_path); + qtest_irq_intercept_in(global_qtest, "ioapic"); + + guest_buf = guest_alloc(guest_malloc, len); + prdt[0].addr = cpu_to_le32(guest_buf); + prdt[0].size = cpu_to_le32(len | PRDT_EOT); + + generate_pattern(pattern, ATAPI_BLOCK_SIZE * 16, ATAPI_BLOCK_SIZE); + fh = fopen(tmp_path, "w+"); + fwrite(pattern, ATAPI_BLOCK_SIZE, 16, fh); + fclose(fh); + + send_dma_request(CMD_PACKET, 0, 1, prdt, 1, send_scsi_cdb_read10); + + /* Read back data from guest memory into local qtest memory */ + memread(guest_buf, rx, len); + g_assert_cmpint(memcmp(pattern, rx, len), ==, 0); + + g_free(pattern); + g_free(rx); + test_bmdma_teardown(); +} + int main(int argc, char **argv) { const char *arch = qtest_get_arch(); @@ -628,6 +843,10 @@ int main(int argc, char **argv) qtest_add_func("/ide/flush/retry_pci", test_pci_retry_flush); qtest_add_func("/ide/flush/retry_isa", test_isa_retry_flush); + qtest_add_func("/ide/cdrom/pio", test_cdrom_pio); + qtest_add_func("/ide/cdrom/pio_large", test_cdrom_pio_large); + qtest_add_func("/ide/cdrom/dma", test_cdrom_dma); + ret = g_test_run(); /* Cleanup */ diff --git a/qemu/tests/image-fuzzer/runner.py b/qemu/tests/image-fuzzer/runner.py index 0a8743ef4..96a1c11b2 100755 --- a/qemu/tests/image-fuzzer/runner.py +++ b/qemu/tests/image-fuzzer/runner.py @@ -157,7 +157,7 @@ class TestEnv(object): try: os.makedirs(self.current_dir) - except OSError, e: + except OSError as e: print >>sys.stderr, \ "Error: The working directory '%s' cannot be used. Reason: %s"\ % (self.work_dir, e[1]) @@ -244,7 +244,7 @@ class TestEnv(object): temp_log = StringIO.StringIO() try: retcode = run_app(temp_log, current_cmd) - except OSError, e: + except OSError as e: multilog("%sError: Start of '%s' failed. Reason: %s\n\n" % (test_summary, os.path.basename(current_cmd[0]), e[1]), @@ -301,7 +301,7 @@ if __name__ == '__main__': JSON: '--command' accepts a JSON array of commands. Each command presents - an application under test with all its paramaters as a list of strings, + an application under test with all its parameters as a list of strings, e.g. ["qemu-io", "$test_img", "-c", "write $off $len"]. Supported application aliases: 'qemu-img' and 'qemu-io'. @@ -356,7 +356,7 @@ if __name__ == '__main__': opts, args = getopt.gnu_getopt(sys.argv[1:], 'c:hs:kvd:', ['command=', 'help', 'seed=', 'config=', 'keep_passed', 'verbose', 'duration=']) - except getopt.error, e: + except getopt.error as e: print >>sys.stderr, \ "Error: %s\n\nTry 'runner.py --help' for more information" % e sys.exit(1) @@ -374,7 +374,7 @@ if __name__ == '__main__': elif opt in ('-c', '--command'): try: command = json.loads(arg) - except (TypeError, ValueError, NameError), e: + except (TypeError, ValueError, NameError) as e: print >>sys.stderr, \ "Error: JSON array of test commands cannot be loaded.\n" \ "Reason: %s" % e @@ -390,7 +390,7 @@ if __name__ == '__main__': elif opt == '--config': try: config = json.loads(arg) - except (TypeError, ValueError, NameError), e: + except (TypeError, ValueError, NameError) as e: print >>sys.stderr, \ "Error: JSON array with the fuzzer configuration cannot" \ " be loaded\nReason: %s" % e @@ -414,7 +414,7 @@ if __name__ == '__main__': try: image_generator = __import__(generator_name) - except ImportError, e: + except ImportError as e: print >>sys.stderr, \ "Error: The image generator '%s' cannot be imported.\n" \ "Reason: %s" % (generator_name, e) diff --git a/qemu/tests/intel-hda-test.c b/qemu/tests/intel-hda-test.c index d89b407dc..1be6add9b 100644 --- a/qemu/tests/intel-hda-test.c +++ b/qemu/tests/intel-hda-test.c @@ -7,10 +7,9 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <string.h> #include "libqtest.h" -#include "qemu/osdep.h" #define HDA_ID "hda0" #define CODEC_DEVICES " -device hda-output,bus=" HDA_ID ".0" \ diff --git a/qemu/tests/io-channel-helpers.c b/qemu/tests/io-channel-helpers.c new file mode 100644 index 000000000..05e5579cf --- /dev/null +++ b/qemu/tests/io-channel-helpers.c @@ -0,0 +1,248 @@ +/* + * QEMU I/O channel test helpers + * + * Copyright (c) 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "qemu/osdep.h" +#include "io-channel-helpers.h" +#include "qapi/error.h" + +struct QIOChannelTest { + QIOChannel *src; + QIOChannel *dst; + bool blocking; + size_t len; + size_t niov; + char *input; + struct iovec *inputv; + char *output; + struct iovec *outputv; + Error *writeerr; + Error *readerr; +}; + + +static void test_skip_iovec(struct iovec **iov, + size_t *niov, + size_t skip, + struct iovec *old) +{ + size_t offset = 0; + size_t i; + + for (i = 0; i < *niov; i++) { + if (skip < (*iov)[i].iov_len) { + old->iov_len = (*iov)[i].iov_len; + old->iov_base = (*iov)[i].iov_base; + + (*iov)[i].iov_len -= skip; + (*iov)[i].iov_base += skip; + break; + } else { + skip -= (*iov)[i].iov_len; + + if (i == 0 && old->iov_base) { + (*iov)[i].iov_len = old->iov_len; + (*iov)[i].iov_base = old->iov_base; + old->iov_len = 0; + old->iov_base = NULL; + } + + offset++; + } + } + + *iov = *iov + offset; + *niov -= offset; +} + + +/* This thread sends all data using iovecs */ +static gpointer test_io_thread_writer(gpointer opaque) +{ + QIOChannelTest *data = opaque; + struct iovec *iov = data->inputv; + size_t niov = data->niov; + struct iovec old = { 0 }; + + qio_channel_set_blocking(data->src, data->blocking, NULL); + + while (niov) { + ssize_t ret; + ret = qio_channel_writev(data->src, + iov, + niov, + &data->writeerr); + if (ret == QIO_CHANNEL_ERR_BLOCK) { + if (data->blocking) { + error_setg(&data->writeerr, + "Unexpected I/O blocking"); + break; + } else { + qio_channel_wait(data->src, + G_IO_OUT); + continue; + } + } else if (ret < 0) { + break; + } else if (ret == 0) { + error_setg(&data->writeerr, + "Unexpected zero length write"); + break; + } + + test_skip_iovec(&iov, &niov, ret, &old); + } + + return NULL; +} + + +/* This thread receives all data using iovecs */ +static gpointer test_io_thread_reader(gpointer opaque) +{ + QIOChannelTest *data = opaque; + struct iovec *iov = data->outputv; + size_t niov = data->niov; + struct iovec old = { 0 }; + + qio_channel_set_blocking(data->dst, data->blocking, NULL); + + while (niov) { + ssize_t ret; + + ret = qio_channel_readv(data->dst, + iov, + niov, + &data->readerr); + + if (ret == QIO_CHANNEL_ERR_BLOCK) { + if (data->blocking) { + error_setg(&data->readerr, + "Unexpected I/O blocking"); + break; + } else { + qio_channel_wait(data->dst, + G_IO_IN); + continue; + } + } else if (ret < 0) { + break; + } else if (ret == 0) { + break; + } + + test_skip_iovec(&iov, &niov, ret, &old); + } + + return NULL; +} + + +QIOChannelTest *qio_channel_test_new(void) +{ + QIOChannelTest *data = g_new0(QIOChannelTest, 1); + size_t i; + size_t offset; + + + /* We'll send 1 MB of data */ +#define CHUNK_COUNT 250 +#define CHUNK_LEN 4194 + + data->len = CHUNK_COUNT * CHUNK_LEN; + data->input = g_new0(char, data->len); + data->output = g_new0(gchar, data->len); + + /* Fill input with a pattern */ + for (i = 0; i < data->len; i += CHUNK_LEN) { + memset(data->input + i, (i / CHUNK_LEN), CHUNK_LEN); + } + + /* We'll split the data across a bunch of IO vecs */ + data->niov = CHUNK_COUNT; + data->inputv = g_new0(struct iovec, data->niov); + data->outputv = g_new0(struct iovec, data->niov); + + for (i = 0, offset = 0; i < data->niov; i++, offset += CHUNK_LEN) { + data->inputv[i].iov_base = data->input + offset; + data->outputv[i].iov_base = data->output + offset; + data->inputv[i].iov_len = CHUNK_LEN; + data->outputv[i].iov_len = CHUNK_LEN; + } + + return data; +} + +void qio_channel_test_run_threads(QIOChannelTest *test, + bool blocking, + QIOChannel *src, + QIOChannel *dst) +{ + GThread *reader, *writer; + + test->src = src; + test->dst = dst; + test->blocking = blocking; + + reader = g_thread_new("reader", + test_io_thread_reader, + test); + writer = g_thread_new("writer", + test_io_thread_writer, + test); + + g_thread_join(reader); + g_thread_join(writer); + + test->dst = test->src = NULL; +} + + +void qio_channel_test_run_writer(QIOChannelTest *test, + QIOChannel *src) +{ + test->src = src; + test_io_thread_writer(test); + test->src = NULL; +} + + +void qio_channel_test_run_reader(QIOChannelTest *test, + QIOChannel *dst) +{ + test->dst = dst; + test_io_thread_reader(test); + test->dst = NULL; +} + + +void qio_channel_test_validate(QIOChannelTest *test) +{ + g_assert(test->readerr == NULL); + g_assert(test->writeerr == NULL); + g_assert_cmpint(memcmp(test->input, + test->output, + test->len), ==, 0); + + g_free(test->inputv); + g_free(test->outputv); + g_free(test->input); + g_free(test->output); + g_free(test); +} diff --git a/qemu/tests/io-channel-helpers.h b/qemu/tests/io-channel-helpers.h new file mode 100644 index 000000000..fedc64fd5 --- /dev/null +++ b/qemu/tests/io-channel-helpers.h @@ -0,0 +1,42 @@ +/* + * QEMU I/O channel test helpers + * + * Copyright (c) 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "io/channel.h" + +#ifndef TEST_IO_CHANNEL_HELPERS +#define TEST_IO_CHANNEL_HELPERS + +typedef struct QIOChannelTest QIOChannelTest; + +QIOChannelTest *qio_channel_test_new(void); + +void qio_channel_test_run_threads(QIOChannelTest *test, + bool blocking, + QIOChannel *src, + QIOChannel *dst); + +void qio_channel_test_run_writer(QIOChannelTest *test, + QIOChannel *src); +void qio_channel_test_run_reader(QIOChannelTest *test, + QIOChannel *dst); + +void qio_channel_test_validate(QIOChannelTest *test); + +#endif /* TEST_IO_CHANNEL_HELPERS */ diff --git a/qemu/tests/ioh3420-test.c b/qemu/tests/ioh3420-test.c index c991a5f87..93eb2f750 100644 --- a/qemu/tests/ioh3420-test.c +++ b/qemu/tests/ioh3420-test.c @@ -7,10 +7,9 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <string.h> #include "libqtest.h" -#include "qemu/osdep.h" /* Tests only initialization so far. TODO: Replace with functional tests */ static void nop(void) diff --git a/qemu/tests/ipmi-bt-test.c b/qemu/tests/ipmi-bt-test.c new file mode 100644 index 000000000..812907fb7 --- /dev/null +++ b/qemu/tests/ipmi-bt-test.c @@ -0,0 +1,433 @@ +/* + * IPMI BT test cases, using the external interface for checking + * + * Copyright (c) 2012 Corey Minyard <cminyard@mvista.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 <sys/socket.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/tcp.h> + +#include <glib.h> + +#include "libqtest.h" +#include "qemu-common.h" + +#define IPMI_IRQ 5 + +#define IPMI_BT_BASE 0xe4 + +#define IPMI_BT_CTLREG_CLR_WR_PTR 0 +#define IPMI_BT_CTLREG_CLR_RD_PTR 1 +#define IPMI_BT_CTLREG_H2B_ATN 2 +#define IPMI_BT_CTLREG_B2H_ATN 3 +#define IPMI_BT_CTLREG_SMS_ATN 4 +#define IPMI_BT_CTLREG_H_BUSY 6 +#define IPMI_BT_CTLREG_B_BUSY 7 + +#define IPMI_BT_CTLREG_GET(b) ((bt_get_ctrlreg() >> (b)) & 1) +#define IPMI_BT_CTLREG_GET_H2B_ATN() IPMI_BT_CTLREG_GET(IPMI_BT_CTLREG_H2B_ATN) +#define IPMI_BT_CTLREG_GET_B2H_ATN() IPMI_BT_CTLREG_GET(IPMI_BT_CTLREG_B2H_ATN) +#define IPMI_BT_CTLREG_GET_SMS_ATN() IPMI_BT_CTLREG_GET(IPMI_BT_CTLREG_SMS_ATN) +#define IPMI_BT_CTLREG_GET_H_BUSY() IPMI_BT_CTLREG_GET(IPMI_BT_CTLREG_H_BUSY) +#define IPMI_BT_CTLREG_GET_B_BUSY() IPMI_BT_CTLREG_GET(IPMI_BT_CTLREG_B_BUSY) + +#define IPMI_BT_CTLREG_SET(b) bt_write_ctrlreg(1 << (b)) +#define IPMI_BT_CTLREG_SET_CLR_WR_PTR() IPMI_BT_CTLREG_SET( \ + IPMI_BT_CTLREG_CLR_WR_PTR) +#define IPMI_BT_CTLREG_SET_CLR_RD_PTR() IPMI_BT_CTLREG_SET( \ + IPMI_BT_CTLREG_CLR_RD_PTR) +#define IPMI_BT_CTLREG_SET_H2B_ATN() IPMI_BT_CTLREG_SET(IPMI_BT_CTLREG_H2B_ATN) +#define IPMI_BT_CTLREG_SET_B2H_ATN() IPMI_BT_CTLREG_SET(IPMI_BT_CTLREG_B2H_ATN) +#define IPMI_BT_CTLREG_SET_SMS_ATN() IPMI_BT_CTLREG_SET(IPMI_BT_CTLREG_SMS_ATN) +#define IPMI_BT_CTLREG_SET_H_BUSY() IPMI_BT_CTLREG_SET(IPMI_BT_CTLREG_H_BUSY) + +static int bt_ints_enabled; + +static uint8_t bt_get_ctrlreg(void) +{ + return inb(IPMI_BT_BASE); +} + +static void bt_write_ctrlreg(uint8_t val) +{ + outb(IPMI_BT_BASE, val); +} + +static uint8_t bt_get_buf(void) +{ + return inb(IPMI_BT_BASE + 1); +} + +static void bt_write_buf(uint8_t val) +{ + outb(IPMI_BT_BASE + 1, val); +} + +static uint8_t bt_get_irqreg(void) +{ + return inb(IPMI_BT_BASE + 2); +} + +static void bt_write_irqreg(uint8_t val) +{ + outb(IPMI_BT_BASE + 2, val); +} + +static void bt_wait_b_busy(void) +{ + unsigned int count = 1000; + while (IPMI_BT_CTLREG_GET_B_BUSY() != 0) { + g_assert(--count != 0); + } +} + +static void bt_wait_b2h_atn(void) +{ + unsigned int count = 1000; + while (IPMI_BT_CTLREG_GET_B2H_ATN() == 0) { + g_assert(--count != 0); + } +} + + +static int emu_lfd; +static int emu_fd; +static in_port_t emu_port; +static uint8_t inbuf[100]; +static unsigned int inbuf_len; +static unsigned int inbuf_pos; +static int last_was_aa; + +static void read_emu_data(void) +{ + fd_set readfds; + int rv; + struct timeval tv; + + FD_ZERO(&readfds); + FD_SET(emu_fd, &readfds); + tv.tv_sec = 10; + tv.tv_usec = 0; + rv = select(emu_fd + 1, &readfds, NULL, NULL, &tv); + if (rv == -1) { + perror("select"); + } + g_assert(rv == 1); + rv = read(emu_fd, inbuf, sizeof(inbuf)); + if (rv == -1) { + perror("read"); + } + g_assert(rv > 0); + inbuf_len = rv; + inbuf_pos = 0; +} + +static void write_emu_msg(uint8_t *msg, unsigned int len) +{ + int rv; + +#ifdef DEBUG_TEST + { + unsigned int i; + printf("sending:"); + for (i = 0; i < len; i++) { + printf(" %2.2x", msg[i]); + } + printf("\n"); + } +#endif + rv = write(emu_fd, msg, len); + g_assert(rv == len); +} + +static void get_emu_msg(uint8_t *msg, unsigned int *len) +{ + unsigned int outpos = 0; + + for (;;) { + while (inbuf_pos < inbuf_len) { + uint8_t ch = inbuf[inbuf_pos++]; + + g_assert(outpos < *len); + if (last_was_aa) { + assert(ch & 0x10); + msg[outpos++] = ch & ~0x10; + last_was_aa = 0; + } else if (ch == 0xaa) { + last_was_aa = 1; + } else { + msg[outpos++] = ch; + if ((ch == 0xa0) || (ch == 0xa1)) { + /* Message complete */ + *len = outpos; + goto done; + } + } + } + read_emu_data(); + } + done: +#ifdef DEBUG_TEST + { + unsigned int i; + printf("Msg:"); + for (i = 0; i < outpos; i++) { + printf(" %2.2x", msg[i]); + } + printf("\n"); + } +#endif + return; +} + +static uint8_t +ipmb_checksum(const unsigned char *data, int size, unsigned char start) +{ + unsigned char csum = start; + + for (; size > 0; size--, data++) { + csum += *data; + } + return csum; +} + +static uint8_t get_dev_id_cmd[] = { 0x18, 0x01 }; +static uint8_t get_dev_id_rsp[] = { 0x1c, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x02, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +static uint8_t set_bmc_globals_cmd[] = { 0x18, 0x2e, 0x0f }; +static uint8_t set_bmc_globals_rsp[] = { 0x1c, 0x2e, 0x00 }; +static uint8_t enable_irq_cmd[] = { 0x05, 0xa1 }; + +static void emu_msg_handler(void) +{ + uint8_t msg[100]; + unsigned int msg_len = sizeof(msg); + + get_emu_msg(msg, &msg_len); + g_assert(msg_len >= 5); + g_assert(msg[msg_len - 1] == 0xa0); + msg_len--; + g_assert(ipmb_checksum(msg, msg_len, 0) == 0); + msg_len--; + if ((msg[1] == get_dev_id_cmd[0]) && (msg[2] == get_dev_id_cmd[1])) { + memcpy(msg + 1, get_dev_id_rsp, sizeof(get_dev_id_rsp)); + msg_len = sizeof(get_dev_id_rsp) + 1; + msg[msg_len] = -ipmb_checksum(msg, msg_len, 0); + msg_len++; + msg[msg_len++] = 0xa0; + write_emu_msg(msg, msg_len); + } else if ((msg[1] == set_bmc_globals_cmd[0]) && + (msg[2] == set_bmc_globals_cmd[1])) { + memcpy(msg + 1, set_bmc_globals_rsp, sizeof(set_bmc_globals_rsp)); + msg_len = sizeof(set_bmc_globals_rsp) + 1; + msg[msg_len] = -ipmb_checksum(msg, msg_len, 0); + msg_len++; + msg[msg_len++] = 0xa0; + write_emu_msg(msg, msg_len); + write_emu_msg(enable_irq_cmd, sizeof(enable_irq_cmd)); + } else { + g_assert(0); + } +} + +static void bt_cmd(uint8_t *cmd, unsigned int cmd_len, + uint8_t *rsp, unsigned int *rsp_len) +{ + unsigned int i, len, j = 0; + uint8_t seq = 5; + + /* Should be idle */ + g_assert(bt_get_ctrlreg() == 0); + + bt_wait_b_busy(); + IPMI_BT_CTLREG_SET_CLR_WR_PTR(); + bt_write_buf(cmd_len + 1); + bt_write_buf(cmd[0]); + bt_write_buf(seq); + for (i = 1; i < cmd_len; i++) { + bt_write_buf(cmd[i]); + } + IPMI_BT_CTLREG_SET_H2B_ATN(); + + emu_msg_handler(); /* We should get a message on the socket here. */ + + bt_wait_b2h_atn(); + if (bt_ints_enabled) { + g_assert((bt_get_irqreg() & 0x02) == 0x02); + g_assert(get_irq(IPMI_IRQ)); + bt_write_irqreg(0x03); + } else { + g_assert(!get_irq(IPMI_IRQ)); + } + IPMI_BT_CTLREG_SET_H_BUSY(); + IPMI_BT_CTLREG_SET_B2H_ATN(); + IPMI_BT_CTLREG_SET_CLR_RD_PTR(); + len = bt_get_buf(); + g_assert(len >= 4); + rsp[0] = bt_get_buf(); + assert(bt_get_buf() == seq); + len--; + for (j = 1; j < len; j++) { + rsp[j] = bt_get_buf(); + } + IPMI_BT_CTLREG_SET_H_BUSY(); + *rsp_len = j; +} + + +/* + * We should get a connect request and a short message with capabilities. + */ +static void test_connect(void) +{ + fd_set readfds; + int rv; + int val; + struct timeval tv; + uint8_t msg[100]; + unsigned int msglen; + static uint8_t exp1[] = { 0xff, 0x01, 0xa1 }; /* A protocol version */ + static uint8_t exp2[] = { 0x08, 0x1f, 0xa1 }; /* A capabilities cmd */ + + FD_ZERO(&readfds); + FD_SET(emu_lfd, &readfds); + tv.tv_sec = 10; + tv.tv_usec = 0; + rv = select(emu_lfd + 1, &readfds, NULL, NULL, &tv); + g_assert(rv == 1); + emu_fd = accept(emu_lfd, NULL, 0); + if (emu_fd < 0) { + perror("accept"); + } + g_assert(emu_fd >= 0); + + val = 1; + rv = setsockopt(emu_fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)); + g_assert(rv != -1); + + /* Report our version */ + write_emu_msg(exp1, sizeof(exp1)); + + /* Validate that we get the info we expect. */ + msglen = sizeof(msg); + get_emu_msg(msg, &msglen); + g_assert(msglen == sizeof(exp1)); + g_assert(memcmp(msg, exp1, msglen) == 0); + msglen = sizeof(msg); + get_emu_msg(msg, &msglen); + g_assert(msglen == sizeof(exp2)); + g_assert(memcmp(msg, exp2, msglen) == 0); +} + +/* + * Send a get_device_id to do a basic test. + */ +static void test_bt_base(void) +{ + uint8_t rsp[20]; + unsigned int rsplen = sizeof(rsp); + + bt_cmd(get_dev_id_cmd, sizeof(get_dev_id_cmd), rsp, &rsplen); + g_assert(rsplen == sizeof(get_dev_id_rsp)); + g_assert(memcmp(get_dev_id_rsp, rsp, rsplen) == 0); +} + +/* + * Enable IRQs for the interface. + */ +static void test_enable_irq(void) +{ + uint8_t rsp[20]; + unsigned int rsplen = sizeof(rsp); + + bt_cmd(set_bmc_globals_cmd, sizeof(set_bmc_globals_cmd), rsp, &rsplen); + g_assert(rsplen == sizeof(set_bmc_globals_rsp)); + g_assert(memcmp(set_bmc_globals_rsp, rsp, rsplen) == 0); + bt_write_irqreg(0x01); + bt_ints_enabled = 1; +} + +/* + * Create a local TCP socket with any port, then save off the port we got. + */ +static void open_socket(void) +{ + struct sockaddr_in myaddr; + socklen_t addrlen; + + myaddr.sin_family = AF_INET; + myaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + myaddr.sin_port = 0; + emu_lfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (emu_lfd == -1) { + perror("socket"); + exit(1); + } + if (bind(emu_lfd, (struct sockaddr *) &myaddr, sizeof(myaddr)) == -1) { + perror("bind"); + exit(1); + } + addrlen = sizeof(myaddr); + if (getsockname(emu_lfd, (struct sockaddr *) &myaddr , &addrlen) == -1) { + perror("getsockname"); + exit(1); + } + emu_port = ntohs(myaddr.sin_port); + assert(listen(emu_lfd, 1) != -1); +} + +int main(int argc, char **argv) +{ + const char *arch = qtest_get_arch(); + char *cmdline; + int ret; + + /* Check architecture */ + if (strcmp(arch, "i386") && strcmp(arch, "x86_64")) { + g_test_message("Skipping test for non-x86\n"); + return 0; + } + + open_socket(); + + /* Run the tests */ + g_test_init(&argc, &argv, NULL); + + cmdline = g_strdup_printf("-vnc none" + " -chardev socket,id=ipmi0,host=localhost,port=%d,reconnect=10" + " -device ipmi-bmc-extern,chardev=ipmi0,id=bmc0" + " -device isa-ipmi-bt,bmc=bmc0", emu_port); + qtest_start(cmdline); + qtest_irq_intercept_in(global_qtest, "ioapic"); + qtest_add_func("/ipmi/extern/connect", test_connect); + qtest_add_func("/ipmi/extern/bt_base", test_bt_base); + qtest_add_func("/ipmi/extern/bt_enable_irq", test_enable_irq); + qtest_add_func("/ipmi/extern/bt_base_irq", test_bt_base); + ret = g_test_run(); + qtest_quit(global_qtest); + + return ret; +} diff --git a/qemu/tests/ipmi-kcs-test.c b/qemu/tests/ipmi-kcs-test.c new file mode 100644 index 000000000..42c4b974c --- /dev/null +++ b/qemu/tests/ipmi-kcs-test.c @@ -0,0 +1,293 @@ +/* + * IPMI KCS test cases, using the local interface. + * + * Copyright (c) 2012 Corey Minyard <cminyard@mvista.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 <glib.h> + +#include "libqtest.h" + +#define IPMI_IRQ 5 + +#define IPMI_KCS_BASE 0xca2 + +#define IPMI_KCS_STATUS_ABORT 0x60 +#define IPMI_KCS_CMD_WRITE_START 0x61 +#define IPMI_KCS_CMD_WRITE_END 0x62 +#define IPMI_KCS_CMD_READ 0x68 + +#define IPMI_KCS_ABORTED_BY_CMD 0x01 + +#define IPMI_KCS_CMDREG_GET_STATE() ((kcs_get_cmdreg() >> 6) & 3) +#define IPMI_KCS_STATE_IDLE 0 +#define IPMI_KCS_STATE_READ 1 +#define IPMI_KCS_STATE_WRITE 2 +#define IPMI_KCS_STATE_ERROR 3 +#define IPMI_KCS_CMDREG_GET_CD() ((kcs_get_cmdreg() >> 3) & 1) +#define IPMI_KCS_CMDREG_GET_ATN() ((kcs_get_cmdreg() >> 2) & 1) +#define IPMI_KCS_CMDREG_GET_IBF() ((kcs_get_cmdreg() >> 1) & 1) +#define IPMI_KCS_CMDREG_GET_OBF() ((kcs_get_cmdreg() >> 0) & 1) + +static int kcs_ints_enabled; + +static uint8_t kcs_get_cmdreg(void) +{ + return inb(IPMI_KCS_BASE + 1); +} + +static void kcs_write_cmdreg(uint8_t val) +{ + outb(IPMI_KCS_BASE + 1, val); +} + +static uint8_t kcs_get_datareg(void) +{ + return inb(IPMI_KCS_BASE); +} + +static void kcs_write_datareg(uint8_t val) +{ + outb(IPMI_KCS_BASE, val); +} + +static void kcs_wait_ibf(void) +{ + unsigned int count = 1000; + while (IPMI_KCS_CMDREG_GET_IBF() != 0) { + g_assert(--count != 0); + } +} + +static void kcs_wait_obf(void) +{ + unsigned int count = 1000; + while (IPMI_KCS_CMDREG_GET_OBF() == 0) { + g_assert(--count != 0); + } +} + +static void kcs_clear_obf(void) +{ + if (kcs_ints_enabled) { + g_assert(get_irq(IPMI_IRQ)); + } else { + g_assert(!get_irq(IPMI_IRQ)); + } + g_assert(IPMI_KCS_CMDREG_GET_OBF() == 1); + kcs_get_datareg(); + g_assert(IPMI_KCS_CMDREG_GET_OBF() == 0); + g_assert(!get_irq(IPMI_IRQ)); +} + +static void kcs_check_state(uint8_t state) +{ + g_assert(IPMI_KCS_CMDREG_GET_STATE() == state); +} + +static void kcs_cmd(uint8_t *cmd, unsigned int cmd_len, + uint8_t *rsp, unsigned int *rsp_len) +{ + unsigned int i, j = 0; + + /* Should be idle */ + g_assert(kcs_get_cmdreg() == 0); + + kcs_write_cmdreg(IPMI_KCS_CMD_WRITE_START); + kcs_wait_ibf(); + kcs_check_state(IPMI_KCS_STATE_WRITE); + kcs_clear_obf(); + for (i = 0; i < cmd_len; i++) { + kcs_write_datareg(cmd[i]); + kcs_wait_ibf(); + kcs_check_state(IPMI_KCS_STATE_WRITE); + kcs_clear_obf(); + } + kcs_write_cmdreg(IPMI_KCS_CMD_WRITE_END); + kcs_wait_ibf(); + kcs_check_state(IPMI_KCS_STATE_WRITE); + kcs_clear_obf(); + kcs_write_datareg(0); + next_read_byte: + kcs_wait_ibf(); + switch (IPMI_KCS_CMDREG_GET_STATE()) { + case IPMI_KCS_STATE_READ: + kcs_wait_obf(); + g_assert(j < *rsp_len); + rsp[j++] = kcs_get_datareg(); + kcs_write_datareg(IPMI_KCS_CMD_READ); + goto next_read_byte; + break; + + case IPMI_KCS_STATE_IDLE: + kcs_wait_obf(); + kcs_get_datareg(); + break; + + default: + g_assert(0); + } + *rsp_len = j; +} + +static void kcs_abort(uint8_t *cmd, unsigned int cmd_len, + uint8_t *rsp, unsigned int *rsp_len) +{ + unsigned int i, j = 0; + unsigned int retries = 4; + + /* Should be idle */ + g_assert(kcs_get_cmdreg() == 0); + + kcs_write_cmdreg(IPMI_KCS_CMD_WRITE_START); + kcs_wait_ibf(); + kcs_check_state(IPMI_KCS_STATE_WRITE); + kcs_clear_obf(); + for (i = 0; i < cmd_len; i++) { + kcs_write_datareg(cmd[i]); + kcs_wait_ibf(); + kcs_check_state(IPMI_KCS_STATE_WRITE); + kcs_clear_obf(); + } + kcs_write_cmdreg(IPMI_KCS_CMD_WRITE_END); + kcs_wait_ibf(); + kcs_check_state(IPMI_KCS_STATE_WRITE); + kcs_clear_obf(); + kcs_write_datareg(0); + kcs_wait_ibf(); + switch (IPMI_KCS_CMDREG_GET_STATE()) { + case IPMI_KCS_STATE_READ: + kcs_wait_obf(); + g_assert(j < *rsp_len); + rsp[j++] = kcs_get_datareg(); + kcs_write_datareg(IPMI_KCS_CMD_READ); + break; + + default: + g_assert(0); + } + + /* Start the abort here */ + retry_abort: + g_assert(retries > 0); + + kcs_wait_ibf(); + kcs_write_cmdreg(IPMI_KCS_STATUS_ABORT); + kcs_wait_ibf(); + kcs_clear_obf(); + kcs_write_datareg(0); + kcs_wait_ibf(); + if (IPMI_KCS_CMDREG_GET_STATE() != IPMI_KCS_STATE_READ) { + retries--; + goto retry_abort; + } + kcs_wait_obf(); + rsp[0] = kcs_get_datareg(); + kcs_write_datareg(IPMI_KCS_CMD_READ); + kcs_wait_ibf(); + if (IPMI_KCS_CMDREG_GET_STATE() != IPMI_KCS_STATE_IDLE) { + retries--; + goto retry_abort; + } + kcs_wait_obf(); + kcs_clear_obf(); + + *rsp_len = j; +} + + +static uint8_t get_dev_id_cmd[] = { 0x18, 0x01 }; +static uint8_t get_dev_id_rsp[] = { 0x1c, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x02, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +/* + * Send a get_device_id to do a basic test. + */ +static void test_kcs_base(void) +{ + uint8_t rsp[20]; + unsigned int rsplen = sizeof(rsp); + + kcs_cmd(get_dev_id_cmd, sizeof(get_dev_id_cmd), rsp, &rsplen); + g_assert(rsplen == sizeof(get_dev_id_rsp)); + g_assert(memcmp(get_dev_id_rsp, rsp, rsplen) == 0); +} + +/* + * Abort a kcs operation while reading + */ +static void test_kcs_abort(void) +{ + uint8_t rsp[20]; + unsigned int rsplen = sizeof(rsp); + + kcs_abort(get_dev_id_cmd, sizeof(get_dev_id_cmd), rsp, &rsplen); + g_assert(rsp[0] == IPMI_KCS_ABORTED_BY_CMD); +} + +static uint8_t set_bmc_globals_cmd[] = { 0x18, 0x2e, 0x0f }; +static uint8_t set_bmc_globals_rsp[] = { 0x1c, 0x2e, 0x00 }; + +/* + * Enable interrupts + */ +static void test_enable_irq(void) +{ + uint8_t rsp[20]; + unsigned int rsplen = sizeof(rsp); + + kcs_cmd(set_bmc_globals_cmd, sizeof(set_bmc_globals_cmd), rsp, &rsplen); + g_assert(rsplen == sizeof(set_bmc_globals_rsp)); + g_assert(memcmp(set_bmc_globals_rsp, rsp, rsplen) == 0); + kcs_ints_enabled = 1; +} + +int main(int argc, char **argv) +{ + const char *arch = qtest_get_arch(); + char *cmdline; + int ret; + + /* Check architecture */ + if (strcmp(arch, "i386") && strcmp(arch, "x86_64")) { + g_test_message("Skipping test for non-x86\n"); + return 0; + } + + /* Run the tests */ + g_test_init(&argc, &argv, NULL); + + cmdline = g_strdup_printf("-vnc none -device ipmi-bmc-sim,id=bmc0" + " -device isa-ipmi-kcs,bmc=bmc0"); + qtest_start(cmdline); + qtest_irq_intercept_in(global_qtest, "ioapic"); + qtest_add_func("/ipmi/local/kcs_base", test_kcs_base); + qtest_add_func("/ipmi/local/kcs_abort", test_kcs_abort); + qtest_add_func("/ipmi/local/kcs_enable_irq", test_enable_irq); + qtest_add_func("/ipmi/local/kcs_base_irq", test_kcs_base); + qtest_add_func("/ipmi/local/kcs_abort_irq", test_kcs_abort); + ret = g_test_run(); + qtest_quit(global_qtest); + + return ret; +} diff --git a/qemu/tests/ipoctal232-test.c b/qemu/tests/ipoctal232-test.c index 3ac1714b4..846aaf571 100644 --- a/qemu/tests/ipoctal232-test.c +++ b/qemu/tests/ipoctal232-test.c @@ -7,10 +7,9 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <string.h> #include "libqtest.h" -#include "qemu/osdep.h" /* Tests only initialization so far. TODO: Replace with functional tests */ static void nop(void) diff --git a/qemu/tests/ivshmem-test.c b/qemu/tests/ivshmem-test.c new file mode 100644 index 000000000..c027ff1e0 --- /dev/null +++ b/qemu/tests/ivshmem-test.c @@ -0,0 +1,518 @@ +/* + * QTest testcase for ivshmem + * + * Copyright (c) 2014 SUSE LINUX Products GmbH + * Copyright (c) 2015 Red Hat, Inc. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include <glib.h> +#include <glib/gstdio.h> +#include <sys/mman.h> +#include "contrib/ivshmem-server/ivshmem-server.h" +#include "libqos/pci-pc.h" +#include "libqtest.h" +#include "qemu-common.h" + +#define TMPSHMSIZE (1 << 20) +static char *tmpshm; +static void *tmpshmem; +static char *tmpdir; +static char *tmpserver; + +static void save_fn(QPCIDevice *dev, int devfn, void *data) +{ + QPCIDevice **pdev = (QPCIDevice **) data; + + *pdev = dev; +} + +static QPCIDevice *get_device(QPCIBus *pcibus) +{ + QPCIDevice *dev; + + dev = NULL; + qpci_device_foreach(pcibus, 0x1af4, 0x1110, save_fn, &dev); + g_assert(dev != NULL); + + return dev; +} + +typedef struct _IVState { + QTestState *qtest; + void *reg_base, *mem_base; + QPCIBus *pcibus; + QPCIDevice *dev; +} IVState; + +enum Reg { + INTRMASK = 0, + INTRSTATUS = 4, + IVPOSITION = 8, + DOORBELL = 12, +}; + +static const char* reg2str(enum Reg reg) { + switch (reg) { + case INTRMASK: + return "IntrMask"; + case INTRSTATUS: + return "IntrStatus"; + case IVPOSITION: + return "IVPosition"; + case DOORBELL: + return "DoorBell"; + default: + return NULL; + } +} + +static inline unsigned in_reg(IVState *s, enum Reg reg) +{ + const char *name = reg2str(reg); + QTestState *qtest = global_qtest; + unsigned res; + + global_qtest = s->qtest; + res = qpci_io_readl(s->dev, s->reg_base + reg); + g_test_message("*%s -> %x\n", name, res); + global_qtest = qtest; + + return res; +} + +static inline void out_reg(IVState *s, enum Reg reg, unsigned v) +{ + const char *name = reg2str(reg); + QTestState *qtest = global_qtest; + + global_qtest = s->qtest; + g_test_message("%x -> *%s\n", v, name); + qpci_io_writel(s->dev, s->reg_base + reg, v); + global_qtest = qtest; +} + +static void cleanup_vm(IVState *s) +{ + g_free(s->dev); + qpci_free_pc(s->pcibus); + qtest_quit(s->qtest); +} + +static void setup_vm_cmd(IVState *s, const char *cmd, bool msix) +{ + uint64_t barsize; + + s->qtest = qtest_start(cmd); + s->pcibus = qpci_init_pc(); + s->dev = get_device(s->pcibus); + + s->reg_base = qpci_iomap(s->dev, 0, &barsize); + g_assert_nonnull(s->reg_base); + g_assert_cmpuint(barsize, ==, 256); + + if (msix) { + qpci_msix_enable(s->dev); + } + + s->mem_base = qpci_iomap(s->dev, 2, &barsize); + g_assert_nonnull(s->mem_base); + g_assert_cmpuint(barsize, ==, TMPSHMSIZE); + + qpci_device_enable(s->dev); +} + +static void setup_vm(IVState *s) +{ + char *cmd = g_strdup_printf("-object memory-backend-file" + ",id=mb1,size=1M,share,mem-path=/dev/shm%s" + " -device ivshmem-plain,memdev=mb1", tmpshm); + + setup_vm_cmd(s, cmd, false); + + g_free(cmd); +} + +static void test_ivshmem_single(void) +{ + IVState state, *s; + uint32_t data[1024]; + int i; + + setup_vm(&state); + s = &state; + + /* initial state of readable registers */ + g_assert_cmpuint(in_reg(s, INTRMASK), ==, 0); + g_assert_cmpuint(in_reg(s, INTRSTATUS), ==, 0); + g_assert_cmpuint(in_reg(s, IVPOSITION), ==, 0); + + /* trigger interrupt via registers */ + out_reg(s, INTRMASK, 0xffffffff); + g_assert_cmpuint(in_reg(s, INTRMASK), ==, 0xffffffff); + out_reg(s, INTRSTATUS, 1); + /* check interrupt status */ + g_assert_cmpuint(in_reg(s, INTRSTATUS), ==, 1); + /* reading clears */ + g_assert_cmpuint(in_reg(s, INTRSTATUS), ==, 0); + /* TODO intercept actual interrupt (needs qtest work) */ + + /* invalid register access */ + out_reg(s, IVPOSITION, 1); + in_reg(s, DOORBELL); + + /* ring the (non-functional) doorbell */ + out_reg(s, DOORBELL, 8 << 16); + + /* write shared memory */ + for (i = 0; i < G_N_ELEMENTS(data); i++) { + data[i] = i; + } + qtest_memwrite(s->qtest, (uintptr_t)s->mem_base, data, sizeof(data)); + + /* verify write */ + for (i = 0; i < G_N_ELEMENTS(data); i++) { + g_assert_cmpuint(((uint32_t *)tmpshmem)[i], ==, i); + } + + /* read it back and verify read */ + memset(data, 0, sizeof(data)); + qtest_memread(s->qtest, (uintptr_t)s->mem_base, data, sizeof(data)); + for (i = 0; i < G_N_ELEMENTS(data); i++) { + g_assert_cmpuint(data[i], ==, i); + } + + cleanup_vm(s); +} + +static void test_ivshmem_pair(void) +{ + IVState state1, state2, *s1, *s2; + char *data; + int i; + + setup_vm(&state1); + s1 = &state1; + setup_vm(&state2); + s2 = &state2; + + data = g_malloc0(TMPSHMSIZE); + + /* host write, guest 1 & 2 read */ + memset(tmpshmem, 0x42, TMPSHMSIZE); + qtest_memread(s1->qtest, (uintptr_t)s1->mem_base, data, TMPSHMSIZE); + for (i = 0; i < TMPSHMSIZE; i++) { + g_assert_cmpuint(data[i], ==, 0x42); + } + qtest_memread(s2->qtest, (uintptr_t)s2->mem_base, data, TMPSHMSIZE); + for (i = 0; i < TMPSHMSIZE; i++) { + g_assert_cmpuint(data[i], ==, 0x42); + } + + /* guest 1 write, guest 2 read */ + memset(data, 0x43, TMPSHMSIZE); + qtest_memwrite(s1->qtest, (uintptr_t)s1->mem_base, data, TMPSHMSIZE); + memset(data, 0, TMPSHMSIZE); + qtest_memread(s2->qtest, (uintptr_t)s2->mem_base, data, TMPSHMSIZE); + for (i = 0; i < TMPSHMSIZE; i++) { + g_assert_cmpuint(data[i], ==, 0x43); + } + + /* guest 2 write, guest 1 read */ + memset(data, 0x44, TMPSHMSIZE); + qtest_memwrite(s2->qtest, (uintptr_t)s2->mem_base, data, TMPSHMSIZE); + memset(data, 0, TMPSHMSIZE); + qtest_memread(s1->qtest, (uintptr_t)s2->mem_base, data, TMPSHMSIZE); + for (i = 0; i < TMPSHMSIZE; i++) { + g_assert_cmpuint(data[i], ==, 0x44); + } + + cleanup_vm(s1); + cleanup_vm(s2); + g_free(data); +} + +typedef struct ServerThread { + GThread *thread; + IvshmemServer *server; + int pipe[2]; /* to handle quit */ +} ServerThread; + +static void *server_thread(void *data) +{ + ServerThread *t = data; + IvshmemServer *server = t->server; + + while (true) { + fd_set fds; + int maxfd, ret; + + FD_ZERO(&fds); + FD_SET(t->pipe[0], &fds); + maxfd = t->pipe[0] + 1; + + ivshmem_server_get_fds(server, &fds, &maxfd); + + ret = select(maxfd, &fds, NULL, NULL, NULL); + + if (ret < 0) { + if (errno == EINTR) { + continue; + } + + g_critical("select error: %s\n", strerror(errno)); + break; + } + if (ret == 0) { + continue; + } + + if (FD_ISSET(t->pipe[0], &fds)) { + break; + } + + if (ivshmem_server_handle_fds(server, &fds, maxfd) < 0) { + g_critical("ivshmem_server_handle_fds() failed\n"); + break; + } + } + + return NULL; +} + +static void setup_vm_with_server(IVState *s, int nvectors, bool msi) +{ + char *cmd = g_strdup_printf("-chardev socket,id=chr0,path=%s,nowait " + "-device ivshmem%s,chardev=chr0,vectors=%d", + tmpserver, + msi ? "-doorbell" : ",size=1M,msi=off", + nvectors); + + setup_vm_cmd(s, cmd, msi); + + g_free(cmd); +} + +static void test_ivshmem_server(bool msi) +{ + IVState state1, state2, *s1, *s2; + ServerThread thread; + IvshmemServer server; + int ret, vm1, vm2; + int nvectors = 2; + guint64 end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND; + + ret = ivshmem_server_init(&server, tmpserver, tmpshm, true, + TMPSHMSIZE, nvectors, + g_test_verbose()); + g_assert_cmpint(ret, ==, 0); + + ret = ivshmem_server_start(&server); + g_assert_cmpint(ret, ==, 0); + + thread.server = &server; + ret = pipe(thread.pipe); + g_assert_cmpint(ret, ==, 0); + thread.thread = g_thread_new("ivshmem-server", server_thread, &thread); + g_assert(thread.thread != NULL); + + setup_vm_with_server(&state1, nvectors, msi); + s1 = &state1; + setup_vm_with_server(&state2, nvectors, msi); + s2 = &state2; + + /* check got different VM ids */ + vm1 = in_reg(s1, IVPOSITION); + vm2 = in_reg(s2, IVPOSITION); + g_assert_cmpint(vm1, >=, 0); + g_assert_cmpint(vm2, >=, 0); + g_assert_cmpint(vm1, !=, vm2); + + /* check number of MSI-X vectors */ + global_qtest = s1->qtest; + if (msi) { + ret = qpci_msix_table_size(s1->dev); + g_assert_cmpuint(ret, ==, nvectors); + } + + /* TODO test behavior before MSI-X is enabled */ + + /* ping vm2 -> vm1 on vector 0 */ + if (msi) { + ret = qpci_msix_pending(s1->dev, 0); + g_assert_cmpuint(ret, ==, 0); + } else { + g_assert_cmpuint(in_reg(s1, INTRSTATUS), ==, 0); + } + out_reg(s2, DOORBELL, vm1 << 16); + do { + g_usleep(10000); + ret = msi ? qpci_msix_pending(s1->dev, 0) : in_reg(s1, INTRSTATUS); + } while (ret == 0 && g_get_monotonic_time() < end_time); + g_assert_cmpuint(ret, !=, 0); + + /* ping vm1 -> vm2 on vector 1 */ + global_qtest = s2->qtest; + if (msi) { + ret = qpci_msix_pending(s2->dev, 1); + g_assert_cmpuint(ret, ==, 0); + } else { + g_assert_cmpuint(in_reg(s2, INTRSTATUS), ==, 0); + } + out_reg(s1, DOORBELL, vm2 << 16 | 1); + do { + g_usleep(10000); + ret = msi ? qpci_msix_pending(s2->dev, 1) : in_reg(s2, INTRSTATUS); + } while (ret == 0 && g_get_monotonic_time() < end_time); + g_assert_cmpuint(ret, !=, 0); + + cleanup_vm(s2); + cleanup_vm(s1); + + if (qemu_write_full(thread.pipe[1], "q", 1) != 1) { + g_error("qemu_write_full: %s", g_strerror(errno)); + } + + g_thread_join(thread.thread); + + ivshmem_server_close(&server); + close(thread.pipe[1]); + close(thread.pipe[0]); +} + +static void test_ivshmem_server_msi(void) +{ + test_ivshmem_server(true); +} + +static void test_ivshmem_server_irq(void) +{ + test_ivshmem_server(false); +} + +#define PCI_SLOT_HP 0x06 + +static void test_ivshmem_hotplug(void) +{ + gchar *opts; + + qtest_start(""); + + opts = g_strdup_printf("'shm': '%s', 'size': '1M'", tmpshm); + + qpci_plug_device_test("ivshmem", "iv1", PCI_SLOT_HP, opts); + qpci_unplug_acpi_device_test("iv1", PCI_SLOT_HP); + + qtest_end(); + g_free(opts); +} + +static void test_ivshmem_memdev(void) +{ + IVState state; + + /* just for the sake of checking memory-backend property */ + setup_vm_cmd(&state, "-object memory-backend-ram,size=1M,id=mb1" + " -device ivshmem-plain,memdev=mb1", false); + + cleanup_vm(&state); +} + +static void cleanup(void) +{ + if (tmpshmem) { + munmap(tmpshmem, TMPSHMSIZE); + tmpshmem = NULL; + } + + if (tmpshm) { + shm_unlink(tmpshm); + g_free(tmpshm); + tmpshm = NULL; + } + + if (tmpserver) { + g_unlink(tmpserver); + g_free(tmpserver); + tmpserver = NULL; + } + + if (tmpdir) { + g_rmdir(tmpdir); + tmpdir = NULL; + } +} + +static void abrt_handler(void *data) +{ + cleanup(); +} + +static gchar *mktempshm(int size, int *fd) +{ + while (true) { + gchar *name; + + name = g_strdup_printf("/qtest-%u-%u", getpid(), g_random_int()); + *fd = shm_open(name, O_CREAT|O_RDWR|O_EXCL, + S_IRWXU|S_IRWXG|S_IRWXO); + if (*fd > 0) { + g_assert(ftruncate(*fd, size) == 0); + return name; + } + + g_free(name); + + if (errno != EEXIST) { + perror("shm_open"); + return NULL; + } + } +} + +int main(int argc, char **argv) +{ + int ret, fd; + gchar dir[] = "/tmp/ivshmem-test.XXXXXX"; + +#if !GLIB_CHECK_VERSION(2, 31, 0) + if (!g_thread_supported()) { + g_thread_init(NULL); + } +#endif + + g_test_init(&argc, &argv, NULL); + + qtest_add_abrt_handler(abrt_handler, NULL); + /* shm */ + tmpshm = mktempshm(TMPSHMSIZE, &fd); + if (!tmpshm) { + return 0; + } + tmpshmem = mmap(0, TMPSHMSIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + g_assert(tmpshmem != MAP_FAILED); + /* server */ + if (mkdtemp(dir) == NULL) { + g_error("mkdtemp: %s", g_strerror(errno)); + } + tmpdir = dir; + tmpserver = g_strconcat(tmpdir, "/server", NULL); + + qtest_add_func("/ivshmem/single", test_ivshmem_single); + qtest_add_func("/ivshmem/hotplug", test_ivshmem_hotplug); + qtest_add_func("/ivshmem/memdev", test_ivshmem_memdev); + if (g_test_slow()) { + qtest_add_func("/ivshmem/pair", test_ivshmem_pair); + qtest_add_func("/ivshmem/server-msi", test_ivshmem_server_msi); + qtest_add_func("/ivshmem/server-irq", test_ivshmem_server_irq); + } + + ret = g_test_run(); + + cleanup(); + + return ret; +} diff --git a/qemu/tests/libqos/ahci.c b/qemu/tests/libqos/ahci.c index cf66b3e32..ac6c155c8 100644 --- a/qemu/tests/libqos/ahci.c +++ b/qemu/tests/libqos/ahci.c @@ -22,6 +22,7 @@ * THE SOFTWARE. */ +#include "qemu/osdep.h" #include <glib.h> #include "libqtest.h" @@ -74,7 +75,11 @@ AHCICommandProp ahci_command_properties[] = { .lba48 = true, .write = true, .ncq = true }, { .cmd = CMD_READ_MAX, .lba28 = true }, { .cmd = CMD_READ_MAX_EXT, .lba48 = true }, - { .cmd = CMD_FLUSH_CACHE, .data = false } + { .cmd = CMD_FLUSH_CACHE, .data = false }, + { .cmd = CMD_PACKET, .data = true, .size = 16, + .atapi = true, .pio = true }, + { .cmd = CMD_PACKET_ID, .data = true, .pio = true, + .size = 512, .read = true } }; struct AHCICommand { @@ -90,7 +95,7 @@ struct AHCICommand { /* Data to be transferred to the guest */ AHCICommandHeader header; RegH2DFIS fis; - void *atapi_cmd; + unsigned char *atapi_cmd; }; /** @@ -110,6 +115,11 @@ void ahci_free(AHCIQState *ahci, uint64_t addr) qfree(ahci->parent, addr); } +bool is_atapi(AHCIQState *ahci, uint8_t port) +{ + return ahci_px_rreg(ahci, port, AHCI_PX_SIG) == AHCI_SIGNATURE_CDROM; +} + /** * Locate, verify, and return a handle to the AHCI device. */ @@ -592,6 +602,82 @@ inline unsigned size_to_prdtl(unsigned bytes, unsigned bytes_per_prd) return (bytes + bytes_per_prd - 1) / bytes_per_prd; } +const AHCIOpts default_opts = { .size = 0 }; + +/** + * ahci_exec: execute a given command on a specific + * AHCI port. + * + * @ahci: The device to send the command to + * @port: The port number of the SATA device we wish + * to have execute this command + * @op: The S/ATA command to execute, or if opts.atapi + * is true, the SCSI command code. + * @opts: Optional arguments to modify execution behavior. + */ +void ahci_exec(AHCIQState *ahci, uint8_t port, + uint8_t op, const AHCIOpts *opts_in) +{ + AHCICommand *cmd; + int rc; + AHCIOpts *opts; + + opts = g_memdup((opts_in == NULL ? &default_opts : opts_in), + sizeof(AHCIOpts)); + + /* No guest buffer provided, create one. */ + if (opts->size && !opts->buffer) { + opts->buffer = ahci_alloc(ahci, opts->size); + g_assert(opts->buffer); + qmemset(opts->buffer, 0x00, opts->size); + } + + /* Command creation */ + if (opts->atapi) { + cmd = ahci_atapi_command_create(op); + if (opts->atapi_dma) { + ahci_command_enable_atapi_dma(cmd); + } + } else { + cmd = ahci_command_create(op); + } + ahci_command_adjust(cmd, opts->lba, opts->buffer, + opts->size, opts->prd_size); + + if (opts->pre_cb) { + rc = opts->pre_cb(ahci, cmd, opts); + g_assert_cmpint(rc, ==, 0); + } + + /* Write command to memory and issue it */ + ahci_command_commit(ahci, cmd, port); + ahci_command_issue_async(ahci, cmd); + if (opts->error) { + qmp_eventwait("STOP"); + } + if (opts->mid_cb) { + rc = opts->mid_cb(ahci, cmd, opts); + g_assert_cmpint(rc, ==, 0); + } + if (opts->error) { + qmp_async("{'execute':'cont' }"); + qmp_eventwait("RESUME"); + } + + /* Wait for command to complete and verify sanity */ + ahci_command_wait(ahci, cmd); + ahci_command_verify(ahci, cmd); + if (opts->post_cb) { + rc = opts->post_cb(ahci, cmd, opts); + g_assert_cmpint(rc, ==, 0); + } + ahci_command_free(cmd); + if (opts->buffer != opts_in->buffer) { + ahci_free(ahci, opts->buffer); + } + g_free(opts); +} + /* Issue a command, expecting it to fail and STOP the VM */ AHCICommand *ahci_guest_io_halt(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd, uint64_t buffer, @@ -659,16 +745,16 @@ void ahci_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd, props = ahci_command_find(ide_cmd); g_assert(props); ptr = ahci_alloc(ahci, bufsize); - g_assert(ptr); + g_assert(!bufsize || ptr); qmemset(ptr, 0x00, bufsize); - if (props->write) { + if (bufsize && props->write) { bufwrite(ptr, buffer, bufsize); } ahci_guest_io(ahci, port, ide_cmd, ptr, bufsize, sector); - if (props->read) { + if (bufsize && props->read) { bufread(ptr, buffer, bufsize); } @@ -731,6 +817,18 @@ static void command_table_init(AHCICommand *cmd) memset(fis->aux, 0x00, ARRAY_SIZE(fis->aux)); } +void ahci_command_enable_atapi_dma(AHCICommand *cmd) +{ + RegH2DFIS *fis = &(cmd->fis); + g_assert(cmd->props->atapi); + fis->feature_low |= 0x01; + cmd->interrupts &= ~AHCI_PX_IS_PSS; + cmd->props->dma = true; + cmd->props->pio = false; + /* BUG: We expect the DMA Setup interrupt for DMA commands */ + /* cmd->interrupts |= AHCI_PX_IS_DSS; */ +} + AHCICommand *ahci_command_create(uint8_t command_name) { AHCICommandProp *props = ahci_command_find(command_name); @@ -742,10 +840,10 @@ AHCICommand *ahci_command_create(uint8_t command_name) g_assert(!(props->lba28 && props->lba48)); g_assert(!(props->read && props->write)); g_assert(!props->size || props->data); - g_assert(!props->ncq || (props->ncq && props->lba48)); + g_assert(!props->ncq || props->lba48); /* Defaults and book-keeping */ - cmd->props = props; + cmd->props = g_memdup(props, sizeof(AHCICommandProp)); cmd->name = command_name; cmd->xbytes = props->size; cmd->prd_size = 4096; @@ -767,8 +865,23 @@ AHCICommand *ahci_command_create(uint8_t command_name) return cmd; } +AHCICommand *ahci_atapi_command_create(uint8_t scsi_cmd) +{ + AHCICommand *cmd = ahci_command_create(CMD_PACKET); + cmd->atapi_cmd = g_malloc0(16); + cmd->atapi_cmd[0] = scsi_cmd; + /* ATAPI needs a PIO transfer chunk size set inside of the LBA registers. + * The block/sector size is a natural default. */ + cmd->fis.lba_lo[1] = ATAPI_SECTOR_SIZE >> 8 & 0xFF; + cmd->fis.lba_lo[2] = ATAPI_SECTOR_SIZE & 0xFF; + + return cmd; +} + void ahci_command_free(AHCICommand *cmd) { + g_free(cmd->atapi_cmd); + g_free(cmd->props); g_free(cmd); } @@ -782,10 +895,34 @@ void ahci_command_clr_flags(AHCICommand *cmd, uint16_t cmdh_flags) cmd->header.flags &= ~cmdh_flags; } +static void ahci_atapi_command_set_offset(AHCICommand *cmd, uint64_t lba) +{ + unsigned char *cbd = cmd->atapi_cmd; + g_assert(cbd); + + switch (cbd[0]) { + case CMD_ATAPI_READ_10: + g_assert_cmpuint(lba, <=, UINT32_MAX); + stl_be_p(&cbd[2], lba); + break; + default: + /* SCSI doesn't have uniform packet formats, + * so you have to add support for it manually. Sorry! */ + g_assert_not_reached(); + } +} + void ahci_command_set_offset(AHCICommand *cmd, uint64_t lba_sect) { RegH2DFIS *fis = &(cmd->fis); - if (cmd->props->lba28) { + + if (cmd->props->atapi) { + ahci_atapi_command_set_offset(cmd, lba_sect); + return; + } else if (!cmd->props->data && !lba_sect) { + /* Not meaningful, ignore. */ + return; + } else if (cmd->props->lba28) { g_assert_cmphex(lba_sect, <=, 0xFFFFFFF); } else if (cmd->props->lba48 || cmd->props->ncq) { g_assert_cmphex(lba_sect, <=, 0xFFFFFFFFFFFF); @@ -811,6 +948,24 @@ void ahci_command_set_buffer(AHCICommand *cmd, uint64_t buffer) cmd->buffer = buffer; } +static void ahci_atapi_set_size(AHCICommand *cmd, uint64_t xbytes) +{ + unsigned char *cbd = cmd->atapi_cmd; + uint64_t nsectors = xbytes / 2048; + g_assert(cbd); + + switch (cbd[0]) { + case CMD_ATAPI_READ_10: + g_assert_cmpuint(nsectors, <=, UINT16_MAX); + stw_be_p(&cbd[7], nsectors); + break; + default: + /* SCSI doesn't have uniform packet formats, + * so you have to add support for it manually. Sorry! */ + g_assert_not_reached(); + } +} + void ahci_command_set_sizes(AHCICommand *cmd, uint64_t xbytes, unsigned prd_size) { @@ -829,6 +984,8 @@ void ahci_command_set_sizes(AHCICommand *cmd, uint64_t xbytes, NCQFIS *nfis = (NCQFIS *)&(cmd->fis); nfis->sector_low = sect_count & 0xFF; nfis->sector_hi = (sect_count >> 8) & 0xFF; + } else if (cmd->props->atapi) { + ahci_atapi_set_size(cmd, xbytes); } else { cmd->fis.count = sect_count; } @@ -877,9 +1034,14 @@ void ahci_command_commit(AHCIQState *ahci, AHCICommand *cmd, uint8_t port) g_assert((table_ptr & 0x7F) == 0x00); cmd->header.ctba = table_ptr; - /* Commit the command header and command FIS */ + /* Commit the command header (part of the Command List Buffer) */ ahci_set_command_header(ahci, port, cmd->slot, &(cmd->header)); + /* Now, write the command table (FIS, ACMD, and PRDT) -- FIS first, */ ahci_write_fis(ahci, cmd); + /* Then ATAPI CMD, if needed */ + if (cmd->props->atapi) { + memwrite(table_ptr + 0x40, cmd->atapi_cmd, 16); + } /* Construct and write the PRDs to the command table */ g_assert_cmphex(prdtl, ==, cmd->header.prdtl); diff --git a/qemu/tests/libqos/ahci.h b/qemu/tests/libqos/ahci.h index cffc2c351..71dd7a6e5 100644 --- a/qemu/tests/libqos/ahci.h +++ b/qemu/tests/libqos/ahci.h @@ -25,9 +25,6 @@ * THE SOFTWARE. */ -#include <stdint.h> -#include <stdlib.h> -#include <stdbool.h> #include "libqos/libqos.h" #include "libqos/pci.h" #include "libqos/malloc-pc.h" @@ -244,6 +241,10 @@ #define AHCI_VERSION_1_3 (0x00010300) #define AHCI_SECTOR_SIZE (512) +#define ATAPI_SECTOR_SIZE (2048) + +#define AHCI_SIGNATURE_CDROM (0xeb140101) +#define AHCI_SIGNATURE_DISK (0x00000101) /* FIS types */ enum { @@ -277,11 +278,18 @@ enum { CMD_READ_MAX_EXT = 0x27, CMD_FLUSH_CACHE = 0xE7, CMD_IDENTIFY = 0xEC, + CMD_PACKET = 0xA0, + CMD_PACKET_ID = 0xA1, /* NCQ */ READ_FPDMA_QUEUED = 0x60, WRITE_FPDMA_QUEUED = 0x61, }; +/* ATAPI Commands */ +enum { + CMD_ATAPI_READ_10 = 0x28, +}; + /* AHCI Command Header Flags & Masks*/ #define CMDH_CFL (0x1F) #define CMDH_ATAPI (0x20) @@ -451,6 +459,21 @@ typedef struct PRD { /* Opaque, defined within ahci.c */ typedef struct AHCICommand AHCICommand; +/* Options to ahci_exec */ +typedef struct AHCIOpts { + size_t size; + unsigned prd_size; + uint64_t lba; + uint64_t buffer; + bool atapi; + bool atapi_dma; + bool error; + int (*pre_cb)(AHCIQState*, AHCICommand*, const struct AHCIOpts *); + int (*mid_cb)(AHCIQState*, AHCICommand*, const struct AHCIOpts *); + int (*post_cb)(AHCIQState*, AHCICommand*, const struct AHCIOpts *); + void *opaque; +} AHCIOpts; + /*** Macro Utilities ***/ #define BITANY(data, mask) (((data) & (mask)) != 0) #define BITSET(data, mask) (((data) & (mask)) == (mask)) @@ -527,14 +550,28 @@ static inline void ahci_px_clr(AHCIQState *ahci, uint8_t port, /*** Prototypes ***/ uint64_t ahci_alloc(AHCIQState *ahci, size_t bytes); void ahci_free(AHCIQState *ahci, uint64_t addr); +void ahci_clean_mem(AHCIQState *ahci); + +/* Device management */ QPCIDevice *get_ahci_device(uint32_t *fingerprint); void free_ahci_device(QPCIDevice *dev); -void ahci_clean_mem(AHCIQState *ahci); void ahci_pci_enable(AHCIQState *ahci); void start_ahci_device(AHCIQState *ahci); void ahci_hba_enable(AHCIQState *ahci); + +/* Port Management */ unsigned ahci_port_select(AHCIQState *ahci); void ahci_port_clear(AHCIQState *ahci, uint8_t port); + +/* Command header / table management */ +unsigned ahci_pick_cmd(AHCIQState *ahci, uint8_t port); +void ahci_get_command_header(AHCIQState *ahci, uint8_t port, + uint8_t slot, AHCICommandHeader *cmd); +void ahci_set_command_header(AHCIQState *ahci, uint8_t port, + uint8_t slot, AHCICommandHeader *cmd); +void ahci_destroy_command(AHCIQState *ahci, uint8_t port, uint8_t slot); + +/* AHCI sanity check routines */ void ahci_port_check_error(AHCIQState *ahci, uint8_t port); void ahci_port_check_interrupts(AHCIQState *ahci, uint8_t port, uint32_t intr_mask); @@ -543,14 +580,12 @@ void ahci_port_check_d2h_sanity(AHCIQState *ahci, uint8_t port, uint8_t slot); void ahci_port_check_pio_sanity(AHCIQState *ahci, uint8_t port, uint8_t slot, size_t buffsize); void ahci_port_check_cmd_sanity(AHCIQState *ahci, AHCICommand *cmd); -void ahci_get_command_header(AHCIQState *ahci, uint8_t port, - uint8_t slot, AHCICommandHeader *cmd); -void ahci_set_command_header(AHCIQState *ahci, uint8_t port, - uint8_t slot, AHCICommandHeader *cmd); -void ahci_destroy_command(AHCIQState *ahci, uint8_t port, uint8_t slot); -void ahci_write_fis(AHCIQState *ahci, AHCICommand *cmd); -unsigned ahci_pick_cmd(AHCIQState *ahci, uint8_t port); + +/* Misc */ +bool is_atapi(AHCIQState *ahci, uint8_t port); unsigned size_to_prdtl(unsigned bytes, unsigned bytes_per_prd); + +/* Command: Macro level execution */ void ahci_guest_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd, uint64_t gbuffer, size_t size, uint64_t sector); AHCICommand *ahci_guest_io_halt(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd, @@ -558,9 +593,12 @@ AHCICommand *ahci_guest_io_halt(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd, void ahci_guest_io_resume(AHCIQState *ahci, AHCICommand *cmd); void ahci_io(AHCIQState *ahci, uint8_t port, uint8_t ide_cmd, void *buffer, size_t bufsize, uint64_t sector); +void ahci_exec(AHCIQState *ahci, uint8_t port, + uint8_t op, const AHCIOpts *opts); -/* Command Lifecycle */ +/* Command: Fine-grained lifecycle */ AHCICommand *ahci_command_create(uint8_t command_name); +AHCICommand *ahci_atapi_command_create(uint8_t scsi_cmd); void ahci_command_commit(AHCIQState *ahci, AHCICommand *cmd, uint8_t port); void ahci_command_issue(AHCIQState *ahci, AHCICommand *cmd); void ahci_command_issue_async(AHCIQState *ahci, AHCICommand *cmd); @@ -568,7 +606,7 @@ void ahci_command_wait(AHCIQState *ahci, AHCICommand *cmd); void ahci_command_verify(AHCIQState *ahci, AHCICommand *cmd); void ahci_command_free(AHCICommand *cmd); -/* Command adjustments */ +/* Command: adjustments */ void ahci_command_set_flags(AHCICommand *cmd, uint16_t cmdh_flags); void ahci_command_clr_flags(AHCICommand *cmd, uint16_t cmdh_flags); void ahci_command_set_offset(AHCICommand *cmd, uint64_t lba_sect); @@ -577,10 +615,13 @@ void ahci_command_set_size(AHCICommand *cmd, uint64_t xbytes); void ahci_command_set_prd_size(AHCICommand *cmd, unsigned prd_size); void ahci_command_set_sizes(AHCICommand *cmd, uint64_t xbytes, unsigned prd_size); +void ahci_command_set_acmd(AHCICommand *cmd, void *acmd); +void ahci_command_enable_atapi_dma(AHCICommand *cmd); void ahci_command_adjust(AHCICommand *cmd, uint64_t lba_sect, uint64_t gbuffer, uint64_t xbytes, unsigned prd_size); -/* Command Misc */ +/* Command: Misc */ uint8_t ahci_command_slot(AHCICommand *cmd); +void ahci_write_fis(AHCIQState *ahci, AHCICommand *cmd); #endif diff --git a/qemu/tests/libqos/fw_cfg.c b/qemu/tests/libqos/fw_cfg.c index ef00fedf1..76894d575 100644 --- a/qemu/tests/libqos/fw_cfg.c +++ b/qemu/tests/libqos/fw_cfg.c @@ -12,6 +12,7 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> #include "libqos/fw_cfg.h" #include "libqtest.h" diff --git a/qemu/tests/libqos/fw_cfg.h b/qemu/tests/libqos/fw_cfg.h index 61b1548b4..e8371b231 100644 --- a/qemu/tests/libqos/fw_cfg.h +++ b/qemu/tests/libqos/fw_cfg.h @@ -13,8 +13,6 @@ #ifndef LIBQOS_FW_CFG_H #define LIBQOS_FW_CFG_H -#include <stdint.h> -#include <sys/types.h> typedef struct QFWCFG QFWCFG; diff --git a/qemu/tests/libqos/i2c-imx.c b/qemu/tests/libqos/i2c-imx.c new file mode 100644 index 000000000..51c3468f9 --- /dev/null +++ b/qemu/tests/libqos/i2c-imx.c @@ -0,0 +1,208 @@ +/* + * QTest i.MX I2C driver + * + * Copyright (c) 2013 Jean-Christophe Dubois + * + * 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/>. + */ + +#include "qemu/osdep.h" +#include "libqos/i2c.h" + +#include <glib.h> + +#include "libqtest.h" + +#include "hw/i2c/imx_i2c.h" + +enum IMXI2CDirection { + IMX_I2C_READ, + IMX_I2C_WRITE, +}; + +typedef struct IMXI2C { + I2CAdapter parent; + + uint64_t addr; +} IMXI2C; + + +static void imx_i2c_set_slave_addr(IMXI2C *s, uint8_t addr, + enum IMXI2CDirection direction) +{ + writeb(s->addr + I2DR_ADDR, (addr << 1) | + (direction == IMX_I2C_READ ? 1 : 0)); +} + +static void imx_i2c_send(I2CAdapter *i2c, uint8_t addr, + const uint8_t *buf, uint16_t len) +{ + IMXI2C *s = (IMXI2C *)i2c; + uint8_t data; + uint8_t status; + uint16_t size = 0; + + if (!len) { + return; + } + + /* set the bus for write */ + data = I2CR_IEN | + I2CR_IIEN | + I2CR_MSTA | + I2CR_MTX | + I2CR_TXAK; + + writeb(s->addr + I2CR_ADDR, data); + status = readb(s->addr + I2SR_ADDR); + g_assert((status & I2SR_IBB) != 0); + + /* set the slave address */ + imx_i2c_set_slave_addr(s, addr, IMX_I2C_WRITE); + status = readb(s->addr + I2SR_ADDR); + g_assert((status & I2SR_IIF) != 0); + g_assert((status & I2SR_RXAK) == 0); + + /* ack the interrupt */ + writeb(s->addr + I2SR_ADDR, 0); + status = readb(s->addr + I2SR_ADDR); + g_assert((status & I2SR_IIF) == 0); + + while (size < len) { + /* check we are still busy */ + status = readb(s->addr + I2SR_ADDR); + g_assert((status & I2SR_IBB) != 0); + + /* write the data */ + writeb(s->addr + I2DR_ADDR, buf[size]); + status = readb(s->addr + I2SR_ADDR); + g_assert((status & I2SR_IIF) != 0); + g_assert((status & I2SR_RXAK) == 0); + + /* ack the interrupt */ + writeb(s->addr + I2SR_ADDR, 0); + status = readb(s->addr + I2SR_ADDR); + g_assert((status & I2SR_IIF) == 0); + + size++; + } + + /* release the bus */ + data &= ~(I2CR_MSTA | I2CR_MTX); + writeb(s->addr + I2CR_ADDR, data); + status = readb(s->addr + I2SR_ADDR); + g_assert((status & I2SR_IBB) == 0); +} + +static void imx_i2c_recv(I2CAdapter *i2c, uint8_t addr, + uint8_t *buf, uint16_t len) +{ + IMXI2C *s = (IMXI2C *)i2c; + uint8_t data; + uint8_t status; + uint16_t size = 0; + + if (!len) { + return; + } + + /* set the bus for write */ + data = I2CR_IEN | + I2CR_IIEN | + I2CR_MSTA | + I2CR_MTX | + I2CR_TXAK; + + writeb(s->addr + I2CR_ADDR, data); + status = readb(s->addr + I2SR_ADDR); + g_assert((status & I2SR_IBB) != 0); + + /* set the slave address */ + imx_i2c_set_slave_addr(s, addr, IMX_I2C_READ); + status = readb(s->addr + I2SR_ADDR); + g_assert((status & I2SR_IIF) != 0); + g_assert((status & I2SR_RXAK) == 0); + + /* ack the interrupt */ + writeb(s->addr + I2SR_ADDR, 0); + status = readb(s->addr + I2SR_ADDR); + g_assert((status & I2SR_IIF) == 0); + + /* set the bus for read */ + data &= ~I2CR_MTX; + /* if only one byte don't ack */ + if (len != 1) { + data &= ~I2CR_TXAK; + } + writeb(s->addr + I2CR_ADDR, data); + status = readb(s->addr + I2SR_ADDR); + g_assert((status & I2SR_IBB) != 0); + + /* dummy read */ + readb(s->addr + I2DR_ADDR); + status = readb(s->addr + I2SR_ADDR); + g_assert((status & I2SR_IIF) != 0); + + /* ack the interrupt */ + writeb(s->addr + I2SR_ADDR, 0); + status = readb(s->addr + I2SR_ADDR); + g_assert((status & I2SR_IIF) == 0); + + while (size < len) { + /* check we are still busy */ + status = readb(s->addr + I2SR_ADDR); + g_assert((status & I2SR_IBB) != 0); + + if (size == (len - 1)) { + /* stop the read transaction */ + data &= ~(I2CR_MSTA | I2CR_MTX); + } else { + /* ack the data read */ + data |= I2CR_TXAK; + } + writeb(s->addr + I2CR_ADDR, data); + + /* read the data */ + buf[size] = readb(s->addr + I2DR_ADDR); + + if (size != (len - 1)) { + status = readb(s->addr + I2SR_ADDR); + g_assert((status & I2SR_IIF) != 0); + + /* ack the interrupt */ + writeb(s->addr + I2SR_ADDR, 0); + } + + status = readb(s->addr + I2SR_ADDR); + g_assert((status & I2SR_IIF) == 0); + + size++; + } + + status = readb(s->addr + I2SR_ADDR); + g_assert((status & I2SR_IBB) == 0); +} + +I2CAdapter *imx_i2c_create(uint64_t addr) +{ + IMXI2C *s = g_malloc0(sizeof(*s)); + I2CAdapter *i2c = (I2CAdapter *)s; + + s->addr = addr; + + i2c->send = imx_i2c_send; + i2c->recv = imx_i2c_recv; + + return i2c; +} diff --git a/qemu/tests/libqos/i2c-omap.c b/qemu/tests/libqos/i2c-omap.c index 3d4d45d84..2028f2f14 100644 --- a/qemu/tests/libqos/i2c-omap.c +++ b/qemu/tests/libqos/i2c-omap.c @@ -6,12 +6,11 @@ * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include "libqos/i2c.h" #include <glib.h> -#include <string.h> -#include "qemu/osdep.h" #include "qemu/bswap.h" #include "libqtest.h" diff --git a/qemu/tests/libqos/i2c.c b/qemu/tests/libqos/i2c.c index da7592f71..23bc2a3eb 100644 --- a/qemu/tests/libqos/i2c.c +++ b/qemu/tests/libqos/i2c.c @@ -6,6 +6,7 @@ * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include "libqos/i2c.h" #include "libqtest.h" diff --git a/qemu/tests/libqos/i2c.h b/qemu/tests/libqos/i2c.h index 1ce9af405..6e648f922 100644 --- a/qemu/tests/libqos/i2c.h +++ b/qemu/tests/libqos/i2c.h @@ -9,7 +9,6 @@ #ifndef LIBQOS_I2C_H #define LIBQOS_I2C_H -#include <stdint.h> typedef struct I2CAdapter I2CAdapter; struct I2CAdapter { @@ -27,4 +26,7 @@ void i2c_recv(I2CAdapter *i2c, uint8_t addr, /* libi2c-omap.c */ I2CAdapter *omap_i2c_create(uint64_t addr); +/* libi2c-imx.c */ +I2CAdapter *imx_i2c_create(uint64_t addr); + #endif diff --git a/qemu/tests/libqos/libqos-pc.c b/qemu/tests/libqos/libqos-pc.c index 140369937..72b5e3ba0 100644 --- a/qemu/tests/libqos/libqos-pc.c +++ b/qemu/tests/libqos/libqos-pc.c @@ -1,3 +1,4 @@ +#include "qemu/osdep.h" #include "libqos/libqos-pc.h" #include "libqos/malloc-pc.h" diff --git a/qemu/tests/libqos/libqos.c b/qemu/tests/libqos/libqos.c index fce625b18..79b0b29b4 100644 --- a/qemu/tests/libqos/libqos.c +++ b/qemu/tests/libqos/libqos.c @@ -1,9 +1,5 @@ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> +#include "qemu/osdep.h" #include <glib.h> -#include <unistd.h> -#include <fcntl.h> #include <sys/wait.h> #include "libqtest.h" @@ -147,6 +143,23 @@ void migrate(QOSState *from, QOSState *to, const char *uri) set_context(to); } +bool have_qemu_img(void) +{ + char *rpath; + const char *path = getenv("QTEST_QEMU_IMG"); + if (!path) { + return false; + } + + rpath = realpath(path, NULL); + if (!rpath) { + return false; + } else { + free(rpath); + return true; + } +} + void mkimg(const char *file, const char *fmt, unsigned size_mb) { gchar *cli; @@ -155,13 +168,14 @@ void mkimg(const char *file, const char *fmt, unsigned size_mb) GError *err = NULL; char *qemu_img_path; gchar *out, *out2; - char *abs_path; + char *qemu_img_abs_path; qemu_img_path = getenv("QTEST_QEMU_IMG"); - abs_path = realpath(qemu_img_path, NULL); - assert(qemu_img_path); + g_assert(qemu_img_path); + qemu_img_abs_path = realpath(qemu_img_path, NULL); + g_assert(qemu_img_abs_path); - cli = g_strdup_printf("%s create -f %s %s %uM", abs_path, + cli = g_strdup_printf("%s create -f %s %s %uM", qemu_img_abs_path, fmt, file, size_mb); ret = g_spawn_command_line_sync(cli, &out, &out2, &rc, &err); if (err) { @@ -183,7 +197,7 @@ void mkimg(const char *file, const char *fmt, unsigned size_mb) g_free(out); g_free(out2); g_free(cli); - free(abs_path); + free(qemu_img_abs_path); } void mkqcow2(const char *file, unsigned size_mb) @@ -212,3 +226,29 @@ void prepare_blkdebug_script(const char *debug_fn, const char *event) ret = fclose(debug_file); g_assert(ret == 0); } + +void generate_pattern(void *buffer, size_t len, size_t cycle_len) +{ + int i, j; + unsigned char *tx = (unsigned char *)buffer; + unsigned char p; + size_t *sx; + + /* Write an indicative pattern that varies and is unique per-cycle */ + p = rand() % 256; + for (i = 0; i < len; i++) { + tx[i] = p++ % 256; + if (i % cycle_len == 0) { + p = rand() % 256; + } + } + + /* force uniqueness by writing an id per-cycle */ + for (i = 0; i < len / cycle_len; i++) { + j = i * cycle_len; + if (j + sizeof(*sx) <= len) { + sx = (size_t *)&tx[j]; + *sx = i; + } + } +} diff --git a/qemu/tests/libqos/libqos.h b/qemu/tests/libqos/libqos.h index e1f14ea6f..ca14d2e9f 100644 --- a/qemu/tests/libqos/libqos.h +++ b/qemu/tests/libqos/libqos.h @@ -19,11 +19,13 @@ typedef struct QOSState { QOSState *qtest_vboot(QOSOps *ops, const char *cmdline_fmt, va_list ap); QOSState *qtest_boot(QOSOps *ops, const char *cmdline_fmt, ...); void qtest_shutdown(QOSState *qs); +bool have_qemu_img(void); void mkimg(const char *file, const char *fmt, unsigned size_mb); void mkqcow2(const char *file, unsigned size_mb); void set_context(QOSState *s); void migrate(QOSState *from, QOSState *to, const char *uri); void prepare_blkdebug_script(const char *debug_fn, const char *event); +void generate_pattern(void *buffer, size_t len, size_t cycle_len); static inline uint64_t qmalloc(QOSState *q, size_t bytes) { diff --git a/qemu/tests/libqos/malloc-generic.c b/qemu/tests/libqos/malloc-generic.c index d30a2f424..6000df2b8 100644 --- a/qemu/tests/libqos/malloc-generic.c +++ b/qemu/tests/libqos/malloc-generic.c @@ -7,6 +7,7 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> #include "libqos/malloc-generic.h" #include "libqos/malloc.h" diff --git a/qemu/tests/libqos/malloc-pc.c b/qemu/tests/libqos/malloc-pc.c index 6e253b687..eee706bd6 100644 --- a/qemu/tests/libqos/malloc-pc.c +++ b/qemu/tests/libqos/malloc-pc.c @@ -10,11 +10,11 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include "libqos/malloc-pc.h" #include "libqos/fw_cfg.h" -#define NO_QEMU_PROTOS -#include "hw/nvram/fw_cfg.h" +#include "hw/nvram/fw_cfg_keys.h" #include "qemu-common.h" #include <glib.h> diff --git a/qemu/tests/libqos/malloc.c b/qemu/tests/libqos/malloc.c index 82b9df537..c0df52f33 100644 --- a/qemu/tests/libqos/malloc.c +++ b/qemu/tests/libqos/malloc.c @@ -10,10 +10,9 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include "libqos/malloc.h" #include "qemu-common.h" -#include <stdio.h> -#include <inttypes.h> #include <glib.h> typedef QTAILQ_HEAD(MemList, MemBlock) MemList; @@ -270,6 +269,10 @@ uint64_t guest_alloc(QGuestAllocator *allocator, size_t size) uint64_t rsize = size; uint64_t naddr; + if (!size) { + return 0; + } + rsize += (allocator->page_size - 1); rsize &= -allocator->page_size; g_assert_cmpint((allocator->start + rsize), <=, allocator->end); diff --git a/qemu/tests/libqos/malloc.h b/qemu/tests/libqos/malloc.h index 0c6c9b7f3..ae9dac8f6 100644 --- a/qemu/tests/libqos/malloc.h +++ b/qemu/tests/libqos/malloc.h @@ -13,8 +13,6 @@ #ifndef LIBQOS_MALLOC_H #define LIBQOS_MALLOC_H -#include <stdint.h> -#include <sys/types.h> #include "qemu/queue.h" typedef enum { diff --git a/qemu/tests/libqos/pci-pc.c b/qemu/tests/libqos/pci-pc.c index 6dba0db00..77f15e5a0 100644 --- a/qemu/tests/libqos/pci-pc.c +++ b/qemu/tests/libqos/pci-pc.c @@ -10,6 +10,7 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include "libqtest.h" #include "libqos/pci-pc.h" @@ -183,7 +184,9 @@ static void *qpci_pc_iomap(QPCIBus *bus, QPCIDevice *dev, int barno, uint64_t *s if (io_type == PCI_BASE_ADDRESS_SPACE_IO) { uint16_t loc; - g_assert((s->pci_iohole_alloc + size) <= s->pci_iohole_size); + g_assert(QEMU_ALIGN_UP(s->pci_iohole_alloc, size) + size + <= s->pci_iohole_size); + s->pci_iohole_alloc = QEMU_ALIGN_UP(s->pci_iohole_alloc, size); loc = s->pci_iohole_start + s->pci_iohole_alloc; s->pci_iohole_alloc += size; @@ -193,7 +196,9 @@ static void *qpci_pc_iomap(QPCIBus *bus, QPCIDevice *dev, int barno, uint64_t *s } else { uint64_t loc; - g_assert((s->pci_hole_alloc + size) <= s->pci_hole_size); + g_assert(QEMU_ALIGN_UP(s->pci_hole_alloc, size) + size + <= s->pci_hole_size); + s->pci_hole_alloc = QEMU_ALIGN_UP(s->pci_hole_alloc, size); loc = s->pci_hole_start + s->pci_hole_alloc; s->pci_hole_alloc += size; diff --git a/qemu/tests/libqos/pci.c b/qemu/tests/libqos/pci.c index 4e630c250..0e104e14e 100644 --- a/qemu/tests/libqos/pci.c +++ b/qemu/tests/libqos/pci.c @@ -10,6 +10,7 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include "libqos/pci.h" #include "hw/pci/pci_regs.h" @@ -34,11 +35,13 @@ void qpci_device_foreach(QPCIBus *bus, int vendor_id, int device_id, if (vendor_id != -1 && qpci_config_readw(dev, PCI_VENDOR_ID) != vendor_id) { + g_free(dev); continue; } if (device_id != -1 && qpci_config_readw(dev, PCI_DEVICE_ID) != device_id) { + g_free(dev); continue; } diff --git a/qemu/tests/libqos/pci.h b/qemu/tests/libqos/pci.h index dfaee9ec3..c06add8db 100644 --- a/qemu/tests/libqos/pci.h +++ b/qemu/tests/libqos/pci.h @@ -13,7 +13,6 @@ #ifndef LIBQOS_PCI_H #define LIBQOS_PCI_H -#include <stdint.h> #include "libqtest.h" #define QPCI_DEVFN(dev, fn) (((dev) << 3) | (fn)) diff --git a/qemu/tests/libqos/usb.c b/qemu/tests/libqos/usb.c index 41d89b848..87efb9078 100644 --- a/qemu/tests/libqos/usb.c +++ b/qemu/tests/libqos/usb.c @@ -11,10 +11,9 @@ * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <string.h> #include "libqtest.h" -#include "qemu/osdep.h" #include "hw/usb/uhci-regs.h" #include "libqos/usb.h" diff --git a/qemu/tests/libqos/virtio-mmio.c b/qemu/tests/libqos/virtio-mmio.c index b3e62e77d..a4382f366 100644 --- a/qemu/tests/libqos/virtio-mmio.c +++ b/qemu/tests/libqos/virtio-mmio.c @@ -7,8 +7,8 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <stdio.h> #include "libqtest.h" #include "libqos/virtio.h" #include "libqos/virtio-mmio.h" diff --git a/qemu/tests/libqos/virtio-pci.c b/qemu/tests/libqos/virtio-pci.c index f9fb924b8..fde2ff0bc 100644 --- a/qemu/tests/libqos/virtio-pci.c +++ b/qemu/tests/libqos/virtio-pci.c @@ -7,8 +7,8 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <stdio.h> #include "libqtest.h" #include "libqos/virtio.h" #include "libqos/virtio-pci.h" diff --git a/qemu/tests/libqos/virtio.c b/qemu/tests/libqos/virtio.c index 3205b88d9..613decea5 100644 --- a/qemu/tests/libqos/virtio.c +++ b/qemu/tests/libqos/virtio.c @@ -7,6 +7,7 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> #include "libqtest.h" #include "libqos/virtio.h" diff --git a/qemu/tests/libqtest.c b/qemu/tests/libqtest.c index e5188e032..b12a9e4ca 100644 --- a/qemu/tests/libqtest.c +++ b/qemu/tests/libqtest.c @@ -14,22 +14,14 @@ * See the COPYING file in the top-level directory. * */ +#include "qemu/osdep.h" #include "libqtest.h" #include <glib.h> -#include <sys/types.h> #include <sys/socket.h> #include <sys/wait.h> #include <sys/un.h> -#include <inttypes.h> -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> - -#include "qemu/compiler.h" -#include "qemu/osdep.h" + #include "qapi/qmp/json-parser.h" #include "qapi/qmp/json-streamer.h" #include "qapi/qmp/qjson.h" @@ -46,9 +38,9 @@ struct QTestState bool irq_level[MAX_IRQ]; GString *rx; pid_t qemu_pid; /* our child QEMU process */ - struct sigaction sigact_old; /* restored on exit */ }; +static GHookList abrt_hooks; static GList *qtest_instances; static struct sigaction sigact_old; @@ -110,12 +102,14 @@ static void kill_qemu(QTestState *s) } } +static void kill_qemu_hook_func(void *s) +{ + kill_qemu(s); +} + static void sigabrt_handler(int signo) { - GList *elem; - for (elem = qtest_instances; elem; elem = elem->next) { - kill_qemu(elem->data); - } + g_hook_list_invoke(&abrt_hooks, FALSE); } static void setup_sigabrt_handler(void) @@ -136,6 +130,23 @@ static void cleanup_sigabrt_handler(void) sigaction(SIGABRT, &sigact_old, NULL); } +void qtest_add_abrt_handler(GHookFunc fn, const void *data) +{ + GHook *hook; + + /* Only install SIGABRT handler once */ + if (!abrt_hooks.is_setup) { + g_hook_list_init(&abrt_hooks, sizeof(GHook)); + setup_sigabrt_handler(); + } + + hook = g_hook_alloc(&abrt_hooks); + hook->func = fn; + hook->data = (void *)data; + + g_hook_prepend(&abrt_hooks, hook); +} + QTestState *qtest_init(const char *extra_args) { QTestState *s; @@ -156,12 +167,7 @@ QTestState *qtest_init(const char *extra_args) sock = init_socket(socket_path); qmpsock = init_socket(qmp_socket_path); - /* Only install SIGABRT handler once */ - if (!qtest_instances) { - setup_sigabrt_handler(); - } - - qtest_instances = g_list_prepend(qtest_instances, s); + qtest_add_abrt_handler(kill_qemu_hook_func, s); s->qemu_pid = fork(); if (s->qemu_pid == 0) { @@ -209,13 +215,14 @@ QTestState *qtest_init(const char *extra_args) void qtest_quit(QTestState *s) { + qtest_instances = g_list_remove(qtest_instances, s); + g_hook_destroy_link(&abrt_hooks, g_hook_find_data(&abrt_hooks, TRUE, s)); + /* Uninstall SIGABRT handler on last instance */ - if (qtest_instances && !qtest_instances->next) { + if (!qtest_instances) { cleanup_sigabrt_handler(); } - qtest_instances = g_list_remove(qtest_instances, s); - kill_qemu(s); close(s->fd); close(s->qmp_fd); @@ -341,7 +348,7 @@ typedef struct { QDict *response; } QMPResponseParser; -static void qmp_response(JSONMessageParser *parser, QList *tokens) +static void qmp_response(JSONMessageParser *parser, GQueue *tokens) { QMPResponseParser *qmp = container_of(parser, QMPResponseParser, parser); QObject *obj; @@ -357,7 +364,7 @@ static void qmp_response(JSONMessageParser *parser, QList *tokens) qmp->response = (QDict *)obj; } -QDict *qtest_qmp_receive(QTestState *s) +QDict *qmp_fd_receive(int fd) { QMPResponseParser qmp; bool log = getenv("QTEST_LOG") != NULL; @@ -368,7 +375,7 @@ QDict *qtest_qmp_receive(QTestState *s) ssize_t len; char c; - len = read(s->qmp_fd, &c, 1); + len = read(fd, &c, 1); if (len == -1 && errno == EINTR) { continue; } @@ -388,12 +395,17 @@ QDict *qtest_qmp_receive(QTestState *s) return qmp.response; } +QDict *qtest_qmp_receive(QTestState *s) +{ + return qmp_fd_receive(s->qmp_fd); +} + /** * Allow users to send a message without waiting for the reply, * in the case that they choose to discard all replies up until * a particular EVENT is received. */ -void qtest_async_qmpv(QTestState *s, const char *fmt, va_list ap) +void qmp_fd_sendv(int fd, const char *fmt, va_list ap) { va_list ap_copy; QObject *qobj; @@ -417,13 +429,25 @@ void qtest_async_qmpv(QTestState *s, const char *fmt, va_list ap) fprintf(stderr, "%s", str); } /* Send QMP request */ - socket_send(s->qmp_fd, str, size); + socket_send(fd, str, size); QDECREF(qstr); qobject_decref(qobj); } } +void qtest_async_qmpv(QTestState *s, const char *fmt, va_list ap) +{ + qmp_fd_sendv(s->qmp_fd, fmt, ap); +} + +QDict *qmp_fdv(int fd, const char *fmt, va_list ap) +{ + qmp_fd_sendv(fd, fmt, ap); + + return qmp_fd_receive(fd); +} + QDict *qtest_qmpv(QTestState *s, const char *fmt, va_list ap) { qtest_async_qmpv(s, fmt, ap); @@ -432,6 +456,26 @@ QDict *qtest_qmpv(QTestState *s, const char *fmt, va_list ap) return qtest_qmp_receive(s); } +QDict *qmp_fd(int fd, const char *fmt, ...) +{ + va_list ap; + QDict *response; + + va_start(ap, fmt); + response = qmp_fdv(fd, fmt, ap); + va_end(ap); + return response; +} + +void qmp_fd_send(int fd, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + qmp_fd_sendv(fd, fmt, ap); + va_end(ap); +} + QDict *qtest_qmp(QTestState *s, const char *fmt, ...) { va_list ap; @@ -484,6 +528,33 @@ void qtest_qmp_eventwait(QTestState *s, const char *event) } } +char *qtest_hmpv(QTestState *s, const char *fmt, va_list ap) +{ + char *cmd; + QDict *resp; + char *ret; + + cmd = g_strdup_vprintf(fmt, ap); + resp = qtest_qmp(s, "{'execute': 'human-monitor-command'," + " 'arguments': {'command-line': %s}}", + cmd); + ret = g_strdup(qdict_get_try_str(resp, "return")); + g_assert(ret); + QDECREF(resp); + g_free(cmd); + return ret; +} + +char *qtest_hmp(QTestState *s, const char *fmt, ...) +{ + va_list ap; + char *ret; + + va_start(ap, fmt); + ret = qtest_hmpv(s, fmt, ap); + va_end(ap); + return ret; +} const char *qtest_get_arch(void) { @@ -681,14 +752,15 @@ void qtest_memread(QTestState *s, uint64_t addr, void *data, size_t size) g_strfreev(args); } -void qtest_add_func(const char *str, void (*fn)) +void qtest_add_func(const char *str, void (*fn)(void)) { gchar *path = g_strdup_printf("/%s/%s", qtest_get_arch(), str); g_test_add_func(path, fn); g_free(path); } -void qtest_add_data_func(const char *str, const void *data, void (*fn)) +void qtest_add_data_func(const char *str, const void *data, + void (*fn)(const void *)) { gchar *path = g_strdup_printf("/%s/%s", qtest_get_arch(), str); g_test_add_data_func(path, data, fn); @@ -775,6 +847,16 @@ void qmp_discard_response(const char *fmt, ...) qtest_qmpv_discard_response(global_qtest, fmt, ap); va_end(ap); } +char *hmp(const char *fmt, ...) +{ + va_list ap; + char *ret; + + va_start(ap, fmt); + ret = qtest_hmpv(global_qtest, fmt, ap); + va_end(ap); + return ret; +} bool qtest_big_endian(void) { diff --git a/qemu/tests/libqtest.h b/qemu/tests/libqtest.h index ec4203152..37f37adbf 100644 --- a/qemu/tests/libqtest.h +++ b/qemu/tests/libqtest.h @@ -17,13 +17,7 @@ #ifndef LIBQTEST_H #define LIBQTEST_H -#include <stddef.h> -#include <stdint.h> -#include <stdbool.h> -#include <stdarg.h> -#include <sys/types.h> #include "qapi/qmp/qdict.h" -#include "glib-compat.h" typedef struct QTestState QTestState; @@ -120,6 +114,29 @@ QDict *qtest_qmp_receive(QTestState *s); void qtest_qmp_eventwait(QTestState *s, const char *event); /** + * qtest_hmpv: + * @s: #QTestState instance to operate on. + * @fmt...: HMP command to send to QEMU + * + * Send HMP command to QEMU via QMP's human-monitor-command. + * + * Returns: the command's output. The caller should g_free() it. + */ +char *qtest_hmp(QTestState *s, const char *fmt, ...); + +/** + * qtest_hmpv: + * @s: #QTestState instance to operate on. + * @fmt: HMP command to send to QEMU + * @ap: HMP command arguments + * + * Send HMP command to QEMU via QMP's human-monitor-command. + * + * Returns: the command's output. The caller should g_free() it. + */ +char *qtest_hmpv(QTestState *s, const char *fmt, va_list ap); + +/** * qtest_get_irq: * @s: #QTestState instance to operate on. * @num: Interrupt to observe. @@ -393,7 +410,7 @@ const char *qtest_get_arch(void); * The path is prefixed with the architecture under test, as * returned by qtest_get_arch(). */ -void qtest_add_func(const char *str, void (*fn)); +void qtest_add_func(const char *str, void (*fn)(void)); /** * qtest_add_data_func: @@ -405,7 +422,8 @@ void qtest_add_func(const char *str, void (*fn)); * The path is prefixed with the architecture under test, as * returned by qtest_get_arch(). */ -void qtest_add_data_func(const char *str, const void *data, void (*fn)); +void qtest_add_data_func(const char *str, const void *data, + void (*fn)(const void *)); /** * qtest_add: @@ -427,6 +445,8 @@ void qtest_add_data_func(const char *str, const void *data, void (*fn)); g_free(path); \ } while (0) +void qtest_add_abrt_handler(GHookFunc fn, const void *data); + /** * qtest_start: * @args: other arguments to pass to QEMU @@ -499,6 +519,16 @@ static inline void qmp_eventwait(const char *event) } /** + * hmp: + * @fmt...: HMP command to send to QEMU + * + * Send HMP command to QEMU via QMP's human-monitor-command. + * + * Returns: the command's output. The caller should g_free() it. + */ +char *hmp(const char *fmt, ...); + +/** * get_irq: * @num: Interrupt to observe. * @@ -818,4 +848,11 @@ static inline int64_t clock_set(int64_t val) */ bool qtest_big_endian(void); + +QDict *qmp_fd_receive(int fd); +void qmp_fd_sendv(int fd, const char *fmt, va_list ap); +void qmp_fd_send(int fd, const char *fmt, ...); +QDict *qmp_fdv(int fd, const char *fmt, va_list ap); +QDict *qmp_fd(int fd, const char *fmt, ...); + #endif diff --git a/qemu/tests/m48t59-test.c b/qemu/tests/m48t59-test.c index 71b4f2805..a751fd350 100644 --- a/qemu/tests/m48t59-test.c +++ b/qemu/tests/m48t59-test.c @@ -12,11 +12,8 @@ * */ +#include "qemu/osdep.h" #include <glib.h> -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <unistd.h> #include "libqtest.h" diff --git a/qemu/tests/ne2000-test.c b/qemu/tests/ne2000-test.c index 61a678ad3..3727875f2 100644 --- a/qemu/tests/ne2000-test.c +++ b/qemu/tests/ne2000-test.c @@ -7,10 +7,9 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <string.h> #include "libqtest.h" -#include "qemu/osdep.h" /* Tests only initialization so far. TODO: Replace with functional tests */ static void pci_nop(void) diff --git a/qemu/tests/nvme-test.c b/qemu/tests/nvme-test.c index ff38b5e48..ec06893ee 100644 --- a/qemu/tests/nvme-test.c +++ b/qemu/tests/nvme-test.c @@ -7,10 +7,9 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <string.h> #include "libqtest.h" -#include "qemu/osdep.h" /* Tests only initialization so far. TODO: Replace with functional tests */ static void nop(void) diff --git a/qemu/tests/pc-cpu-test.c b/qemu/tests/pc-cpu-test.c index 3505c7c43..6b34ca588 100644 --- a/qemu/tests/pc-cpu-test.c +++ b/qemu/tests/pc-cpu-test.c @@ -7,12 +7,11 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <string.h> #include "qemu-common.h" #include "libqtest.h" -#include "qemu/osdep.h" #include "qapi/qmp/types.h" struct PCTestData { diff --git a/qemu/tests/pcnet-test.c b/qemu/tests/pcnet-test.c index 84af4f327..2ddf4965c 100644 --- a/qemu/tests/pcnet-test.c +++ b/qemu/tests/pcnet-test.c @@ -7,10 +7,9 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <string.h> #include "libqtest.h" -#include "qemu/osdep.h" /* Tests only initialization so far. TODO: Replace with functional tests */ static void pci_nop(void) diff --git a/qemu/tests/pkix_asn1_tab.c b/qemu/tests/pkix_asn1_tab.c new file mode 100644 index 000000000..903bc0251 --- /dev/null +++ b/qemu/tests/pkix_asn1_tab.c @@ -0,0 +1,1105 @@ +/* + * This file is taken from gnutls 1.6.3 under the GPLv2+ + * and is under copyright of various GNUTLS contributors. + */ + +#include "qemu/osdep.h" +#include <libtasn1.h> + +const ASN1_ARRAY_TYPE pkix_asn1_tab[] = { + {"PKIX1", 536875024, 0}, + {0, 1073741836, 0}, + {"id-ce", 1879048204, 0}, + {"joint-iso-ccitt", 1073741825, "2"}, + {"ds", 1073741825, "5"}, + {0, 1, "29"}, + {"id-ce-authorityKeyIdentifier", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "35"}, + {"AuthorityKeyIdentifier", 1610612741, 0}, + {"keyIdentifier", 1610637314, "KeyIdentifier"}, + {0, 4104, "0"}, + {"authorityCertIssuer", 1610637314, "GeneralNames"}, + {0, 4104, "1"}, + {"authorityCertSerialNumber", 536895490, "CertificateSerialNumber"}, + {0, 4104, "2"}, + {"KeyIdentifier", 1073741831, 0}, + {"id-ce-subjectKeyIdentifier", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "14"}, + {"SubjectKeyIdentifier", 1073741826, "KeyIdentifier"}, + {"id-ce-keyUsage", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "15"}, + {"KeyUsage", 1610874886, 0}, + {"digitalSignature", 1073741825, "0"}, + {"nonRepudiation", 1073741825, "1"}, + {"keyEncipherment", 1073741825, "2"}, + {"dataEncipherment", 1073741825, "3"}, + {"keyAgreement", 1073741825, "4"}, + {"keyCertSign", 1073741825, "5"}, + {"cRLSign", 1073741825, "6"}, + {"encipherOnly", 1073741825, "7"}, + {"decipherOnly", 1, "8"}, + {"id-ce-privateKeyUsagePeriod", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "16"}, + {"PrivateKeyUsagePeriod", 1610612741, 0}, + {"notBefore", 1619025937, 0}, + {0, 4104, "0"}, + {"notAfter", 545284113, 0}, + {0, 4104, "1"}, + {"id-ce-certificatePolicies", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "32"}, + {"CertificatePolicies", 1612709899, 0}, + {"MAX", 1074266122, "1"}, + {0, 2, "PolicyInformation"}, + {"PolicyInformation", 1610612741, 0}, + {"policyIdentifier", 1073741826, "CertPolicyId"}, + {"policyQualifiers", 538984459, 0}, + {"MAX", 1074266122, "1"}, + {0, 2, "PolicyQualifierInfo"}, + {"CertPolicyId", 1073741836, 0}, + {"PolicyQualifierInfo", 1610612741, 0}, + {"policyQualifierId", 1073741826, "PolicyQualifierId"}, + {"qualifier", 541065229, 0}, + {"policyQualifierId", 1, 0}, + {"PolicyQualifierId", 1073741836, 0}, + {"CPSuri", 1073741826, "IA5String"}, + {"UserNotice", 1610612741, 0}, + {"noticeRef", 1073758210, "NoticeReference"}, + {"explicitText", 16386, "DisplayText"}, + {"NoticeReference", 1610612741, 0}, + {"organization", 1073741826, "DisplayText"}, + {"noticeNumbers", 536870923, 0}, + {0, 3, 0}, + {"DisplayText", 1610612754, 0}, + {"visibleString", 1612709890, "VisibleString"}, + {"200", 524298, "1"}, + {"bmpString", 1612709890, "BMPString"}, + {"200", 524298, "1"}, + {"utf8String", 538968066, "UTF8String"}, + {"200", 524298, "1"}, + {"id-ce-policyMappings", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "33"}, + {"PolicyMappings", 1612709899, 0}, + {"MAX", 1074266122, "1"}, + {0, 536870917, 0}, + {"issuerDomainPolicy", 1073741826, "CertPolicyId"}, + {"subjectDomainPolicy", 2, "CertPolicyId"}, + {"DirectoryString", 1610612754, 0}, + {"teletexString", 1612709890, "TeletexString"}, + {"MAX", 524298, "1"}, + {"printableString", 1612709890, "PrintableString"}, + {"MAX", 524298, "1"}, + {"universalString", 1612709890, "UniversalString"}, + {"MAX", 524298, "1"}, + {"utf8String", 1612709890, "UTF8String"}, + {"MAX", 524298, "1"}, + {"bmpString", 1612709890, "BMPString"}, + {"MAX", 524298, "1"}, + {"ia5String", 538968066, "IA5String"}, + {"MAX", 524298, "1"}, + {"id-ce-subjectAltName", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "17"}, + {"SubjectAltName", 1073741826, "GeneralNames"}, + {"GeneralNames", 1612709899, 0}, + {"MAX", 1074266122, "1"}, + {0, 2, "GeneralName"}, + {"GeneralName", 1610612754, 0}, + {"otherName", 1610620930, "AnotherName"}, + {0, 4104, "0"}, + {"rfc822Name", 1610620930, "IA5String"}, + {0, 4104, "1"}, + {"dNSName", 1610620930, "IA5String"}, + {0, 4104, "2"}, + {"x400Address", 1610620930, "ORAddress"}, + {0, 4104, "3"}, + {"directoryName", 1610620930, "RDNSequence"}, + {0, 2056, "4"}, + {"ediPartyName", 1610620930, "EDIPartyName"}, + {0, 4104, "5"}, + {"uniformResourceIdentifier", 1610620930, "IA5String"}, + {0, 4104, "6"}, + {"iPAddress", 1610620935, 0}, + {0, 4104, "7"}, + {"registeredID", 536879116, 0}, + {0, 4104, "8"}, + {"AnotherName", 1610612741, 0}, + {"type-id", 1073741836, 0}, + {"value", 541073421, 0}, + {0, 1073743880, "0"}, + {"type-id", 1, 0}, + {"EDIPartyName", 1610612741, 0}, + {"nameAssigner", 1610637314, "DirectoryString"}, + {0, 4104, "0"}, + {"partyName", 536879106, "DirectoryString"}, + {0, 4104, "1"}, + {"id-ce-issuerAltName", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "18"}, + {"IssuerAltName", 1073741826, "GeneralNames"}, + {"id-ce-subjectDirectoryAttributes", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "9"}, + {"SubjectDirectoryAttributes", 1612709899, 0}, + {"MAX", 1074266122, "1"}, + {0, 2, "Attribute"}, + {"id-ce-basicConstraints", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "19"}, + {"BasicConstraints", 1610612741, 0}, + {"cA", 1610645508, 0}, + {0, 131081, 0}, + {"pathLenConstraint", 537411587, 0}, + {"0", 10, "MAX"}, + {"id-ce-nameConstraints", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "30"}, + {"NameConstraints", 1610612741, 0}, + {"permittedSubtrees", 1610637314, "GeneralSubtrees"}, + {0, 4104, "0"}, + {"excludedSubtrees", 536895490, "GeneralSubtrees"}, + {0, 4104, "1"}, + {"GeneralSubtrees", 1612709899, 0}, + {"MAX", 1074266122, "1"}, + {0, 2, "GeneralSubtree"}, + {"GeneralSubtree", 1610612741, 0}, + {"base", 1073741826, "GeneralName"}, + {"minimum", 1610653698, "BaseDistance"}, + {0, 1073741833, "0"}, + {0, 4104, "0"}, + {"maximum", 536895490, "BaseDistance"}, + {0, 4104, "1"}, + {"BaseDistance", 1611137027, 0}, + {"0", 10, "MAX"}, + {"id-ce-policyConstraints", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "36"}, + {"PolicyConstraints", 1610612741, 0}, + {"requireExplicitPolicy", 1610637314, "SkipCerts"}, + {0, 4104, "0"}, + {"inhibitPolicyMapping", 536895490, "SkipCerts"}, + {0, 4104, "1"}, + {"SkipCerts", 1611137027, 0}, + {"0", 10, "MAX"}, + {"id-ce-cRLDistributionPoints", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "31"}, + {"CRLDistributionPoints", 1612709899, 0}, + {"MAX", 1074266122, "1"}, + {0, 2, "DistributionPoint"}, + {"DistributionPoint", 1610612741, 0}, + {"distributionPoint", 1610637314, "DistributionPointName"}, + {0, 2056, "0"}, + {"reasons", 1610637314, "ReasonFlags"}, + {0, 4104, "1"}, + {"cRLIssuer", 536895490, "GeneralNames"}, + {0, 4104, "2"}, + {"DistributionPointName", 1610612754, 0}, + {"fullName", 1610620930, "GeneralNames"}, + {0, 4104, "0"}, + {"nameRelativeToCRLIssuer", 536879106, "RelativeDistinguishedName"}, + {0, 4104, "1"}, + {"ReasonFlags", 1610874886, 0}, + {"unused", 1073741825, "0"}, + {"keyCompromise", 1073741825, "1"}, + {"cACompromise", 1073741825, "2"}, + {"affiliationChanged", 1073741825, "3"}, + {"superseded", 1073741825, "4"}, + {"cessationOfOperation", 1073741825, "5"}, + {"certificateHold", 1073741825, "6"}, + {"privilegeWithdrawn", 1073741825, "7"}, + {"aACompromise", 1, "8"}, + {"id-ce-extKeyUsage", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "37"}, + {"ExtKeyUsageSyntax", 1612709899, 0}, + {"MAX", 1074266122, "1"}, + {0, 2, "KeyPurposeId"}, + {"KeyPurposeId", 1073741836, 0}, + {"id-kp-serverAuth", 1879048204, 0}, + {0, 1073741825, "id-kp"}, + {0, 1, "1"}, + {"id-kp-clientAuth", 1879048204, 0}, + {0, 1073741825, "id-kp"}, + {0, 1, "2"}, + {"id-kp-codeSigning", 1879048204, 0}, + {0, 1073741825, "id-kp"}, + {0, 1, "3"}, + {"id-kp-emailProtection", 1879048204, 0}, + {0, 1073741825, "id-kp"}, + {0, 1, "4"}, + {"id-kp-ipsecEndSystem", 1879048204, 0}, + {0, 1073741825, "id-kp"}, + {0, 1, "5"}, + {"id-kp-ipsecTunnel", 1879048204, 0}, + {0, 1073741825, "id-kp"}, + {0, 1, "6"}, + {"id-kp-ipsecUser", 1879048204, 0}, + {0, 1073741825, "id-kp"}, + {0, 1, "7"}, + {"id-kp-timeStamping", 1879048204, 0}, + {0, 1073741825, "id-kp"}, + {0, 1, "8"}, + {"id-pe-authorityInfoAccess", 1879048204, 0}, + {0, 1073741825, "id-pe"}, + {0, 1, "1"}, + {"AuthorityInfoAccessSyntax", 1612709899, 0}, + {"MAX", 1074266122, "1"}, + {0, 2, "AccessDescription"}, + {"AccessDescription", 1610612741, 0}, + {"accessMethod", 1073741836, 0}, + {"accessLocation", 2, "GeneralName"}, + {"id-ce-cRLNumber", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "20"}, + {"CRLNumber", 1611137027, 0}, + {"0", 10, "MAX"}, + {"id-ce-issuingDistributionPoint", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "28"}, + {"IssuingDistributionPoint", 1610612741, 0}, + {"distributionPoint", 1610637314, "DistributionPointName"}, + {0, 4104, "0"}, + {"onlyContainsUserCerts", 1610653700, 0}, + {0, 1073872905, 0}, + {0, 4104, "1"}, + {"onlyContainsCACerts", 1610653700, 0}, + {0, 1073872905, 0}, + {0, 4104, "2"}, + {"onlySomeReasons", 1610637314, "ReasonFlags"}, + {0, 4104, "3"}, + {"indirectCRL", 536911876, 0}, + {0, 1073872905, 0}, + {0, 4104, "4"}, + {"id-ce-deltaCRLIndicator", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "27"}, + {"BaseCRLNumber", 1073741826, "CRLNumber"}, + {"id-ce-cRLReasons", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "21"}, + {"CRLReason", 1610874901, 0}, + {"unspecified", 1073741825, "0"}, + {"keyCompromise", 1073741825, "1"}, + {"cACompromise", 1073741825, "2"}, + {"affiliationChanged", 1073741825, "3"}, + {"superseded", 1073741825, "4"}, + {"cessationOfOperation", 1073741825, "5"}, + {"certificateHold", 1073741825, "6"}, + {"removeFromCRL", 1, "8"}, + {"id-ce-certificateIssuer", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "29"}, + {"CertificateIssuer", 1073741826, "GeneralNames"}, + {"id-ce-holdInstructionCode", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "23"}, + {"HoldInstructionCode", 1073741836, 0}, + {"holdInstruction", 1879048204, 0}, + {"joint-iso-itu-t", 1073741825, "2"}, + {"member-body", 1073741825, "2"}, + {"us", 1073741825, "840"}, + {"x9cm", 1073741825, "10040"}, + {0, 1, "2"}, + {"id-holdinstruction-none", 1879048204, 0}, + {0, 1073741825, "holdInstruction"}, + {0, 1, "1"}, + {"id-holdinstruction-callissuer", 1879048204, 0}, + {0, 1073741825, "holdInstruction"}, + {0, 1, "2"}, + {"id-holdinstruction-reject", 1879048204, 0}, + {0, 1073741825, "holdInstruction"}, + {0, 1, "3"}, + {"id-ce-invalidityDate", 1879048204, 0}, + {0, 1073741825, "id-ce"}, + {0, 1, "24"}, + {"InvalidityDate", 1082130449, 0}, + {"VisibleString", 1610620935, 0}, + {0, 4360, "26"}, + {"NumericString", 1610620935, 0}, + {0, 4360, "18"}, + {"IA5String", 1610620935, 0}, + {0, 4360, "22"}, + {"TeletexString", 1610620935, 0}, + {0, 4360, "20"}, + {"PrintableString", 1610620935, 0}, + {0, 4360, "19"}, + {"UniversalString", 1610620935, 0}, + {0, 4360, "28"}, + {"BMPString", 1610620935, 0}, + {0, 4360, "30"}, + {"UTF8String", 1610620935, 0}, + {0, 4360, "12"}, + {"id-pkix", 1879048204, 0}, + {"iso", 1073741825, "1"}, + {"identified-organization", 1073741825, "3"}, + {"dod", 1073741825, "6"}, + {"internet", 1073741825, "1"}, + {"security", 1073741825, "5"}, + {"mechanisms", 1073741825, "5"}, + {"pkix", 1, "7"}, + {"id-pe", 1879048204, 0}, + {0, 1073741825, "id-pkix"}, + {0, 1, "1"}, + {"id-qt", 1879048204, 0}, + {0, 1073741825, "id-pkix"}, + {0, 1, "2"}, + {"id-kp", 1879048204, 0}, + {0, 1073741825, "id-pkix"}, + {0, 1, "3"}, + {"id-ad", 1879048204, 0}, + {0, 1073741825, "id-pkix"}, + {0, 1, "48"}, + {"id-qt-cps", 1879048204, 0}, + {0, 1073741825, "id-qt"}, + {0, 1, "1"}, + {"id-qt-unotice", 1879048204, 0}, + {0, 1073741825, "id-qt"}, + {0, 1, "2"}, + {"id-ad-ocsp", 1879048204, 0}, + {0, 1073741825, "id-ad"}, + {0, 1, "1"}, + {"id-ad-caIssuers", 1879048204, 0}, + {0, 1073741825, "id-ad"}, + {0, 1, "2"}, + {"Attribute", 1610612741, 0}, + {"type", 1073741826, "AttributeType"}, + {"values", 536870927, 0}, + {0, 2, "AttributeValue"}, + {"AttributeType", 1073741836, 0}, + {"AttributeValue", 1614807053, 0}, + {"type", 1, 0}, + {"AttributeTypeAndValue", 1610612741, 0}, + {"type", 1073741826, "AttributeType"}, + {"value", 2, "AttributeValue"}, + {"id-at", 1879048204, 0}, + {"joint-iso-ccitt", 1073741825, "2"}, + {"ds", 1073741825, "5"}, + {0, 1, "4"}, + {"id-at-initials", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "43"}, + {"X520initials", 1073741826, "DirectoryString"}, + {"id-at-generationQualifier", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "44"}, + {"X520generationQualifier", 1073741826, "DirectoryString"}, + {"id-at-surname", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "4"}, + {"X520surName", 1073741826, "DirectoryString"}, + {"id-at-givenName", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "42"}, + {"X520givenName", 1073741826, "DirectoryString"}, + {"id-at-name", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "41"}, + {"X520name", 1073741826, "DirectoryString"}, + {"id-at-commonName", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "3"}, + {"X520CommonName", 1073741826, "DirectoryString"}, + {"id-at-localityName", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "7"}, + {"X520LocalityName", 1073741826, "DirectoryString"}, + {"id-at-stateOrProvinceName", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "8"}, + {"X520StateOrProvinceName", 1073741826, "DirectoryString"}, + {"id-at-organizationName", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "10"}, + {"X520OrganizationName", 1073741826, "DirectoryString"}, + {"id-at-organizationalUnitName", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "11"}, + {"X520OrganizationalUnitName", 1073741826, "DirectoryString"}, + {"id-at-title", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "12"}, + {"X520Title", 1073741826, "DirectoryString"}, + {"id-at-description", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "13"}, + {"X520Description", 1073741826, "DirectoryString"}, + {"id-at-dnQualifier", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "46"}, + {"X520dnQualifier", 1073741826, "PrintableString"}, + {"id-at-countryName", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "6"}, + {"X520countryName", 1612709890, "PrintableString"}, + {0, 1048586, "2"}, + {"id-at-serialNumber", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "5"}, + {"X520serialNumber", 1073741826, "PrintableString"}, + {"id-at-telephoneNumber", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "20"}, + {"X520telephoneNumber", 1073741826, "PrintableString"}, + {"id-at-facsimileTelephoneNumber", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "23"}, + {"X520facsimileTelephoneNumber", 1073741826, "PrintableString"}, + {"id-at-pseudonym", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "65"}, + {"X520pseudonym", 1073741826, "DirectoryString"}, + {"id-at-name", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "41"}, + {"X520name", 1073741826, "DirectoryString"}, + {"id-at-streetAddress", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "9"}, + {"X520streetAddress", 1073741826, "DirectoryString"}, + {"id-at-postalAddress", 1880096780, "AttributeType"}, + {0, 1073741825, "id-at"}, + {0, 1, "16"}, + {"X520postalAddress", 1073741826, "PostalAddress"}, + {"PostalAddress", 1610612747, 0}, + {0, 2, "DirectoryString"}, + {"pkcs", 1879048204, 0}, + {"iso", 1073741825, "1"}, + {"member-body", 1073741825, "2"}, + {"us", 1073741825, "840"}, + {"rsadsi", 1073741825, "113549"}, + {"pkcs", 1, "1"}, + {"pkcs-9", 1879048204, 0}, + {0, 1073741825, "pkcs"}, + {0, 1, "9"}, + {"emailAddress", 1880096780, "AttributeType"}, + {0, 1073741825, "pkcs-9"}, + {0, 1, "1"}, + {"Pkcs9email", 1612709890, "IA5String"}, + {"ub-emailaddress-length", 524298, "1"}, + {"Name", 1610612754, 0}, + {"rdnSequence", 2, "RDNSequence"}, + {"RDNSequence", 1610612747, 0}, + {0, 2, "RelativeDistinguishedName"}, + {"DistinguishedName", 1073741826, "RDNSequence"}, + {"RelativeDistinguishedName", 1612709903, 0}, + {"MAX", 1074266122, "1"}, + {0, 2, "AttributeTypeAndValue"}, + {"Certificate", 1610612741, 0}, + {"tbsCertificate", 1073741826, "TBSCertificate"}, + {"signatureAlgorithm", 1073741826, "AlgorithmIdentifier"}, + {"signature", 6, 0}, + {"TBSCertificate", 1610612741, 0}, + {"version", 1610653698, "Version"}, + {0, 1073741833, "v1"}, + {0, 2056, "0"}, + {"serialNumber", 1073741826, "CertificateSerialNumber"}, + {"signature", 1073741826, "AlgorithmIdentifier"}, + {"issuer", 1073741826, "Name"}, + {"validity", 1073741826, "Validity"}, + {"subject", 1073741826, "Name"}, + {"subjectPublicKeyInfo", 1073741826, "SubjectPublicKeyInfo"}, + {"issuerUniqueID", 1610637314, "UniqueIdentifier"}, + {0, 4104, "1"}, + {"subjectUniqueID", 1610637314, "UniqueIdentifier"}, + {0, 4104, "2"}, + {"extensions", 536895490, "Extensions"}, + {0, 2056, "3"}, + {"Version", 1610874883, 0}, + {"v1", 1073741825, "0"}, + {"v2", 1073741825, "1"}, + {"v3", 1, "2"}, + {"CertificateSerialNumber", 1073741827, 0}, + {"Validity", 1610612741, 0}, + {"notBefore", 1073741826, "Time"}, + {"notAfter", 2, "Time"}, + {"Time", 1610612754, 0}, + {"utcTime", 1090519057, 0}, + {"generalTime", 8388625, 0}, + {"UniqueIdentifier", 1073741830, 0}, + {"SubjectPublicKeyInfo", 1610612741, 0}, + {"algorithm", 1073741826, "AlgorithmIdentifier"}, + {"subjectPublicKey", 6, 0}, + {"Extensions", 1612709899, 0}, + {"MAX", 1074266122, "1"}, + {0, 2, "Extension"}, + {"Extension", 1610612741, 0}, + {"extnID", 1073741836, 0}, + {"critical", 1610645508, 0}, + {0, 131081, 0}, + {"extnValue", 7, 0}, + {"CertificateList", 1610612741, 0}, + {"tbsCertList", 1073741826, "TBSCertList"}, + {"signatureAlgorithm", 1073741826, "AlgorithmIdentifier"}, + {"signature", 6, 0}, + {"TBSCertList", 1610612741, 0}, + {"version", 1073758210, "Version"}, + {"signature", 1073741826, "AlgorithmIdentifier"}, + {"issuer", 1073741826, "Name"}, + {"thisUpdate", 1073741826, "Time"}, + {"nextUpdate", 1073758210, "Time"}, + {"revokedCertificates", 1610629131, 0}, + {0, 536870917, 0}, + {"userCertificate", 1073741826, "CertificateSerialNumber"}, + {"revocationDate", 1073741826, "Time"}, + {"crlEntryExtensions", 16386, "Extensions"}, + {"crlExtensions", 536895490, "Extensions"}, + {0, 2056, "0"}, + {"AlgorithmIdentifier", 1610612741, 0}, + {"algorithm", 1073741836, 0}, + {"parameters", 541081613, 0}, + {"algorithm", 1, 0}, + {"pkcs-1", 1879048204, 0}, + {0, 1073741825, "pkcs"}, + {0, 1, "1"}, + {"rsaEncryption", 1879048204, 0}, + {0, 1073741825, "pkcs-1"}, + {0, 1, "1"}, + {"md2WithRSAEncryption", 1879048204, 0}, + {0, 1073741825, "pkcs-1"}, + {0, 1, "2"}, + {"md5WithRSAEncryption", 1879048204, 0}, + {0, 1073741825, "pkcs-1"}, + {0, 1, "4"}, + {"sha1WithRSAEncryption", 1879048204, 0}, + {0, 1073741825, "pkcs-1"}, + {0, 1, "5"}, + {"id-dsa-with-sha1", 1879048204, 0}, + {"iso", 1073741825, "1"}, + {"member-body", 1073741825, "2"}, + {"us", 1073741825, "840"}, + {"x9-57", 1073741825, "10040"}, + {"x9algorithm", 1073741825, "4"}, + {0, 1, "3"}, + {"Dss-Sig-Value", 1610612741, 0}, + {"r", 1073741827, 0}, + {"s", 3, 0}, + {"dhpublicnumber", 1879048204, 0}, + {"iso", 1073741825, "1"}, + {"member-body", 1073741825, "2"}, + {"us", 1073741825, "840"}, + {"ansi-x942", 1073741825, "10046"}, + {"number-type", 1073741825, "2"}, + {0, 1, "1"}, + {"DomainParameters", 1610612741, 0}, + {"p", 1073741827, 0}, + {"g", 1073741827, 0}, + {"q", 1073741827, 0}, + {"j", 1073758211, 0}, + {"validationParms", 16386, "ValidationParms"}, + {"ValidationParms", 1610612741, 0}, + {"seed", 1073741830, 0}, + {"pgenCounter", 3, 0}, + {"id-dsa", 1879048204, 0}, + {"iso", 1073741825, "1"}, + {"member-body", 1073741825, "2"}, + {"us", 1073741825, "840"}, + {"x9-57", 1073741825, "10040"}, + {"x9algorithm", 1073741825, "4"}, + {0, 1, "1"}, + {"Dss-Parms", 1610612741, 0}, + {"p", 1073741827, 0}, + {"q", 1073741827, 0}, + {"g", 3, 0}, + {"ORAddress", 1610612741, 0}, + {"built-in-standard-attributes", 1073741826, "BuiltInStandardAttributes"}, + {"built-in-domain-defined-attributes", 1073758210, + "BuiltInDomainDefinedAttributes"}, + {"extension-attributes", 16386, "ExtensionAttributes"}, + {"BuiltInStandardAttributes", 1610612741, 0}, + {"country-name", 1073758210, "CountryName"}, + {"administration-domain-name", 1073758210, "AdministrationDomainName"}, + {"network-address", 1610637314, "NetworkAddress"}, + {0, 2056, "0"}, + {"terminal-identifier", 1610637314, "TerminalIdentifier"}, + {0, 2056, "1"}, + {"private-domain-name", 1610637314, "PrivateDomainName"}, + {0, 2056, "2"}, + {"organization-name", 1610637314, "OrganizationName"}, + {0, 2056, "3"}, + {"numeric-user-identifier", 1610637314, "NumericUserIdentifier"}, + {0, 2056, "4"}, + {"personal-name", 1610637314, "PersonalName"}, + {0, 2056, "5"}, + {"organizational-unit-names", 536895490, "OrganizationalUnitNames"}, + {0, 2056, "6"}, + {"CountryName", 1610620946, 0}, + {0, 1073746952, "1"}, + {"x121-dcc-code", 1612709890, "NumericString"}, + {0, 1048586, "ub-country-name-numeric-length"}, + {"iso-3166-alpha2-code", 538968066, "PrintableString"}, + {0, 1048586, "ub-country-name-alpha-length"}, + {"AdministrationDomainName", 1610620946, 0}, + {0, 1073744904, "2"}, + {"numeric", 1612709890, "NumericString"}, + {"ub-domain-name-length", 524298, "0"}, + {"printable", 538968066, "PrintableString"}, + {"ub-domain-name-length", 524298, "0"}, + {"NetworkAddress", 1073741826, "X121Address"}, + {"X121Address", 1612709890, "NumericString"}, + {"ub-x121-address-length", 524298, "1"}, + {"TerminalIdentifier", 1612709890, "PrintableString"}, + {"ub-terminal-id-length", 524298, "1"}, + {"PrivateDomainName", 1610612754, 0}, + {"numeric", 1612709890, "NumericString"}, + {"ub-domain-name-length", 524298, "1"}, + {"printable", 538968066, "PrintableString"}, + {"ub-domain-name-length", 524298, "1"}, + {"OrganizationName", 1612709890, "PrintableString"}, + {"ub-organization-name-length", 524298, "1"}, + {"NumericUserIdentifier", 1612709890, "NumericString"}, + {"ub-numeric-user-id-length", 524298, "1"}, + {"PersonalName", 1610612750, 0}, + {"surname", 1814044674, "PrintableString"}, + {0, 1073745928, "0"}, + {"ub-surname-length", 524298, "1"}, + {"given-name", 1814061058, "PrintableString"}, + {0, 1073745928, "1"}, + {"ub-given-name-length", 524298, "1"}, + {"initials", 1814061058, "PrintableString"}, + {0, 1073745928, "2"}, + {"ub-initials-length", 524298, "1"}, + {"generation-qualifier", 740319234, "PrintableString"}, + {0, 1073745928, "3"}, + {"ub-generation-qualifier-length", 524298, "1"}, + {"OrganizationalUnitNames", 1612709899, 0}, + {"ub-organizational-units", 1074266122, "1"}, + {0, 2, "OrganizationalUnitName"}, + {"OrganizationalUnitName", 1612709890, "PrintableString"}, + {"ub-organizational-unit-name-length", 524298, "1"}, + {"BuiltInDomainDefinedAttributes", 1612709899, 0}, + {"ub-domain-defined-attributes", 1074266122, "1"}, + {0, 2, "BuiltInDomainDefinedAttribute"}, + {"BuiltInDomainDefinedAttribute", 1610612741, 0}, + {"type", 1612709890, "PrintableString"}, + {"ub-domain-defined-attribute-type-length", 524298, "1"}, + {"value", 538968066, "PrintableString"}, + {"ub-domain-defined-attribute-value-length", 524298, "1"}, + {"ExtensionAttributes", 1612709903, 0}, + {"ub-extension-attributes", 1074266122, "1"}, + {0, 2, "ExtensionAttribute"}, + {"ExtensionAttribute", 1610612741, 0}, + {"extension-attribute-type", 1611145219, 0}, + {0, 1073743880, "0"}, + {"0", 10, "ub-extension-attributes"}, + {"extension-attribute-value", 541073421, 0}, + {0, 1073743880, "1"}, + {"extension-attribute-type", 1, 0}, + {"common-name", 1342177283, "1"}, + {"CommonName", 1612709890, "PrintableString"}, + {"ub-common-name-length", 524298, "1"}, + {"teletex-common-name", 1342177283, "2"}, + {"TeletexCommonName", 1612709890, "TeletexString"}, + {"ub-common-name-length", 524298, "1"}, + {"teletex-organization-name", 1342177283, "3"}, + {"TeletexOrganizationName", 1612709890, "TeletexString"}, + {"ub-organization-name-length", 524298, "1"}, + {"teletex-personal-name", 1342177283, "4"}, + {"TeletexPersonalName", 1610612750, 0}, + {"surname", 1814044674, "TeletexString"}, + {0, 1073743880, "0"}, + {"ub-surname-length", 524298, "1"}, + {"given-name", 1814061058, "TeletexString"}, + {0, 1073743880, "1"}, + {"ub-given-name-length", 524298, "1"}, + {"initials", 1814061058, "TeletexString"}, + {0, 1073743880, "2"}, + {"ub-initials-length", 524298, "1"}, + {"generation-qualifier", 740319234, "TeletexString"}, + {0, 1073743880, "3"}, + {"ub-generation-qualifier-length", 524298, "1"}, + {"teletex-organizational-unit-names", 1342177283, "5"}, + {"TeletexOrganizationalUnitNames", 1612709899, 0}, + {"ub-organizational-units", 1074266122, "1"}, + {0, 2, "TeletexOrganizationalUnitName"}, + {"TeletexOrganizationalUnitName", 1612709890, "TeletexString"}, + {"ub-organizational-unit-name-length", 524298, "1"}, + {"pds-name", 1342177283, "7"}, + {"PDSName", 1612709890, "PrintableString"}, + {"ub-pds-name-length", 524298, "1"}, + {"physical-delivery-country-name", 1342177283, "8"}, + {"PhysicalDeliveryCountryName", 1610612754, 0}, + {"x121-dcc-code", 1612709890, "NumericString"}, + {0, 1048586, "ub-country-name-numeric-length"}, + {"iso-3166-alpha2-code", 538968066, "PrintableString"}, + {0, 1048586, "ub-country-name-alpha-length"}, + {"postal-code", 1342177283, "9"}, + {"PostalCode", 1610612754, 0}, + {"numeric-code", 1612709890, "NumericString"}, + {"ub-postal-code-length", 524298, "1"}, + {"printable-code", 538968066, "PrintableString"}, + {"ub-postal-code-length", 524298, "1"}, + {"physical-delivery-office-name", 1342177283, "10"}, + {"PhysicalDeliveryOfficeName", 1073741826, "PDSParameter"}, + {"physical-delivery-office-number", 1342177283, "11"}, + {"PhysicalDeliveryOfficeNumber", 1073741826, "PDSParameter"}, + {"extension-OR-address-components", 1342177283, "12"}, + {"ExtensionORAddressComponents", 1073741826, "PDSParameter"}, + {"physical-delivery-personal-name", 1342177283, "13"}, + {"PhysicalDeliveryPersonalName", 1073741826, "PDSParameter"}, + {"physical-delivery-organization-name", 1342177283, "14"}, + {"PhysicalDeliveryOrganizationName", 1073741826, "PDSParameter"}, + {"extension-physical-delivery-address-components", 1342177283, "15"}, + {"ExtensionPhysicalDeliveryAddressComponents", 1073741826, "PDSParameter"}, + {"unformatted-postal-address", 1342177283, "16"}, + {"UnformattedPostalAddress", 1610612750, 0}, + {"printable-address", 1814052875, 0}, + {"ub-pds-physical-address-lines", 1074266122, "1"}, + {0, 538968066, "PrintableString"}, + {"ub-pds-parameter-length", 524298, "1"}, + {"teletex-string", 740311042, "TeletexString"}, + {"ub-unformatted-address-length", 524298, "1"}, + {"street-address", 1342177283, "17"}, + {"StreetAddress", 1073741826, "PDSParameter"}, + {"post-office-box-address", 1342177283, "18"}, + {"PostOfficeBoxAddress", 1073741826, "PDSParameter"}, + {"poste-restante-address", 1342177283, "19"}, + {"PosteRestanteAddress", 1073741826, "PDSParameter"}, + {"unique-postal-name", 1342177283, "20"}, + {"UniquePostalName", 1073741826, "PDSParameter"}, + {"local-postal-attributes", 1342177283, "21"}, + {"LocalPostalAttributes", 1073741826, "PDSParameter"}, + {"PDSParameter", 1610612750, 0}, + {"printable-string", 1814052866, "PrintableString"}, + {"ub-pds-parameter-length", 524298, "1"}, + {"teletex-string", 740311042, "TeletexString"}, + {"ub-pds-parameter-length", 524298, "1"}, + {"extended-network-address", 1342177283, "22"}, + {"ExtendedNetworkAddress", 1610612754, 0}, + {"e163-4-address", 1610612741, 0}, + {"number", 1612718082, "NumericString"}, + {0, 1073743880, "0"}, + {"ub-e163-4-number-length", 524298, "1"}, + {"sub-address", 538992642, "NumericString"}, + {0, 1073743880, "1"}, + {"ub-e163-4-sub-address-length", 524298, "1"}, + {"psap-address", 536879106, "PresentationAddress"}, + {0, 2056, "0"}, + {"PresentationAddress", 1610612741, 0}, + {"pSelector", 1610637319, 0}, + {0, 2056, "0"}, + {"sSelector", 1610637319, 0}, + {0, 2056, "1"}, + {"tSelector", 1610637319, 0}, + {0, 2056, "2"}, + {"nAddresses", 538976271, 0}, + {0, 1073743880, "3"}, + {"MAX", 1074266122, "1"}, + {0, 7, 0}, + {"terminal-type", 1342177283, "23"}, + {"TerminalType", 1610874883, 0}, + {"telex", 1073741825, "3"}, + {"teletex", 1073741825, "4"}, + {"g3-facsimile", 1073741825, "5"}, + {"g4-facsimile", 1073741825, "6"}, + {"ia5-terminal", 1073741825, "7"}, + {"videotex", 1, "8"}, + {"teletex-domain-defined-attributes", 1342177283, "6"}, + {"TeletexDomainDefinedAttributes", 1612709899, 0}, + {"ub-domain-defined-attributes", 1074266122, "1"}, + {0, 2, "TeletexDomainDefinedAttribute"}, + {"TeletexDomainDefinedAttribute", 1610612741, 0}, + {"type", 1612709890, "TeletexString"}, + {"ub-domain-defined-attribute-type-length", 524298, "1"}, + {"value", 538968066, "TeletexString"}, + {"ub-domain-defined-attribute-value-length", 524298, "1"}, + {"ub-name", 1342177283, "32768"}, + {"ub-common-name", 1342177283, "64"}, + {"ub-locality-name", 1342177283, "128"}, + {"ub-state-name", 1342177283, "128"}, + {"ub-organization-name", 1342177283, "64"}, + {"ub-organizational-unit-name", 1342177283, "64"}, + {"ub-title", 1342177283, "64"}, + {"ub-match", 1342177283, "128"}, + {"ub-emailaddress-length", 1342177283, "128"}, + {"ub-common-name-length", 1342177283, "64"}, + {"ub-country-name-alpha-length", 1342177283, "2"}, + {"ub-country-name-numeric-length", 1342177283, "3"}, + {"ub-domain-defined-attributes", 1342177283, "4"}, + {"ub-domain-defined-attribute-type-length", 1342177283, "8"}, + {"ub-domain-defined-attribute-value-length", 1342177283, "128"}, + {"ub-domain-name-length", 1342177283, "16"}, + {"ub-extension-attributes", 1342177283, "256"}, + {"ub-e163-4-number-length", 1342177283, "15"}, + {"ub-e163-4-sub-address-length", 1342177283, "40"}, + {"ub-generation-qualifier-length", 1342177283, "3"}, + {"ub-given-name-length", 1342177283, "16"}, + {"ub-initials-length", 1342177283, "5"}, + {"ub-integer-options", 1342177283, "256"}, + {"ub-numeric-user-id-length", 1342177283, "32"}, + {"ub-organization-name-length", 1342177283, "64"}, + {"ub-organizational-unit-name-length", 1342177283, "32"}, + {"ub-organizational-units", 1342177283, "4"}, + {"ub-pds-name-length", 1342177283, "16"}, + {"ub-pds-parameter-length", 1342177283, "30"}, + {"ub-pds-physical-address-lines", 1342177283, "6"}, + {"ub-postal-code-length", 1342177283, "16"}, + {"ub-surname-length", 1342177283, "40"}, + {"ub-terminal-id-length", 1342177283, "24"}, + {"ub-unformatted-address-length", 1342177283, "180"}, + {"ub-x121-address-length", 1342177283, "16"}, + {"pkcs-7-ContentInfo", 1610612741, 0}, + {"contentType", 1073741826, "pkcs-7-ContentType"}, + {"content", 541073421, 0}, + {0, 1073743880, "0"}, + {"contentType", 1, 0}, + {"pkcs-7-DigestInfo", 1610612741, 0}, + {"digestAlgorithm", 1073741826, "pkcs-7-DigestAlgorithmIdentifier"}, + {"digest", 2, "pkcs-7-Digest"}, + {"pkcs-7-Digest", 1073741831, 0}, + {"pkcs-7-ContentType", 1073741836, 0}, + {"pkcs-7-SignedData", 1610612741, 0}, + {"version", 1073741826, "pkcs-7-CMSVersion"}, + {"digestAlgorithms", 1073741826, "pkcs-7-DigestAlgorithmIdentifiers"}, + {"encapContentInfo", 1073741826, "pkcs-7-EncapsulatedContentInfo"}, + {"certificates", 1610637314, "pkcs-7-CertificateSet"}, + {0, 4104, "0"}, + {"crls", 1610637314, "pkcs-7-CertificateRevocationLists"}, + {0, 4104, "1"}, + {"signerInfos", 2, "pkcs-7-SignerInfos"}, + {"pkcs-7-CMSVersion", 1610874883, 0}, + {"v0", 1073741825, "0"}, + {"v1", 1073741825, "1"}, + {"v2", 1073741825, "2"}, + {"v3", 1073741825, "3"}, + {"v4", 1, "4"}, + {"pkcs-7-DigestAlgorithmIdentifiers", 1610612751, 0}, + {0, 2, "pkcs-7-DigestAlgorithmIdentifier"}, + {"pkcs-7-DigestAlgorithmIdentifier", 1073741826, "AlgorithmIdentifier"}, + {"pkcs-7-EncapsulatedContentInfo", 1610612741, 0}, + {"eContentType", 1073741826, "pkcs-7-ContentType"}, + {"eContent", 536895495, 0}, + {0, 2056, "0"}, + {"pkcs-7-CertificateRevocationLists", 1610612751, 0}, + {0, 13, 0}, + {"pkcs-7-CertificateChoices", 1610612754, 0}, + {"certificate", 13, 0}, + {"pkcs-7-CertificateSet", 1610612751, 0}, + {0, 2, "pkcs-7-CertificateChoices"}, + {"pkcs-7-SignerInfos", 1610612751, 0}, + {0, 13, 0}, + {"pkcs-10-CertificationRequestInfo", 1610612741, 0}, + {"version", 1610874883, 0}, + {"v1", 1, "0"}, + {"subject", 1073741826, "Name"}, + {"subjectPKInfo", 1073741826, "SubjectPublicKeyInfo"}, + {"attributes", 536879106, "Attributes"}, + {0, 4104, "0"}, + {"Attributes", 1610612751, 0}, + {0, 2, "Attribute"}, + {"pkcs-10-CertificationRequest", 1610612741, 0}, + {"certificationRequestInfo", 1073741826, "pkcs-10-CertificationRequestInfo"}, + {"signatureAlgorithm", 1073741826, "AlgorithmIdentifier"}, + {"signature", 6, 0}, + {"pkcs-9-ub-challengePassword", 1342177283, "255"}, + {"pkcs-9-certTypes", 1879048204, 0}, + {0, 1073741825, "pkcs-9"}, + {0, 1, "22"}, + {"pkcs-9-crlTypes", 1879048204, 0}, + {0, 1073741825, "pkcs-9"}, + {0, 1, "23"}, + {"pkcs-9-at-challengePassword", 1879048204, 0}, + {0, 1073741825, "pkcs-9"}, + {0, 1, "7"}, + {"pkcs-9-challengePassword", 1610612754, 0}, + {"printableString", 1612709890, "PrintableString"}, + {"pkcs-9-ub-challengePassword", 524298, "1"}, + {"utf8String", 538968066, "UTF8String"}, + {"pkcs-9-ub-challengePassword", 524298, "1"}, + {"pkcs-9-at-localKeyId", 1879048204, 0}, + {0, 1073741825, "pkcs-9"}, + {0, 1, "21"}, + {"pkcs-9-localKeyId", 1073741831, 0}, + {"pkcs-9-at-friendlyName", 1879048204, 0}, + {0, 1073741825, "pkcs-9"}, + {0, 1, "20"}, + {"pkcs-9-friendlyName", 1612709890, "BMPString"}, + {"255", 524298, "1"}, + {"pkcs-8-PrivateKeyInfo", 1610612741, 0}, + {"version", 1073741826, "pkcs-8-Version"}, + {"privateKeyAlgorithm", 1073741826, "AlgorithmIdentifier"}, + {"privateKey", 1073741826, "pkcs-8-PrivateKey"}, + {"attributes", 536895490, "Attributes"}, + {0, 4104, "0"}, + {"pkcs-8-Version", 1610874883, 0}, + {"v1", 1, "0"}, + {"pkcs-8-PrivateKey", 1073741831, 0}, + {"pkcs-8-Attributes", 1610612751, 0}, + {0, 2, "Attribute"}, + {"pkcs-8-EncryptedPrivateKeyInfo", 1610612741, 0}, + {"encryptionAlgorithm", 1073741826, "AlgorithmIdentifier"}, + {"encryptedData", 2, "pkcs-8-EncryptedData"}, + {"pkcs-8-EncryptedData", 1073741831, 0}, + {"pkcs-5", 1879048204, 0}, + {0, 1073741825, "pkcs"}, + {0, 1, "5"}, + {"pkcs-5-encryptionAlgorithm", 1879048204, 0}, + {"iso", 1073741825, "1"}, + {"member-body", 1073741825, "2"}, + {"us", 1073741825, "840"}, + {"rsadsi", 1073741825, "113549"}, + {0, 1, "3"}, + {"pkcs-5-des-EDE3-CBC", 1879048204, 0}, + {0, 1073741825, "pkcs-5-encryptionAlgorithm"}, + {0, 1, "7"}, + {"pkcs-5-des-EDE3-CBC-params", 1612709895, 0}, + {0, 1048586, "8"}, + {"pkcs-5-id-PBES2", 1879048204, 0}, + {0, 1073741825, "pkcs-5"}, + {0, 1, "13"}, + {"pkcs-5-PBES2-params", 1610612741, 0}, + {"keyDerivationFunc", 1073741826, "AlgorithmIdentifier"}, + {"encryptionScheme", 2, "AlgorithmIdentifier"}, + {"pkcs-5-id-PBKDF2", 1879048204, 0}, + {0, 1073741825, "pkcs-5"}, + {0, 1, "12"}, + {"pkcs-5-PBKDF2-params", 1610612741, 0}, + {"salt", 1610612754, 0}, + {"specified", 1073741831, 0}, + {"otherSource", 2, "AlgorithmIdentifier"}, + {"iterationCount", 1611137027, 0}, + {"1", 10, "MAX"}, + {"keyLength", 1611153411, 0}, + {"1", 10, "MAX"}, + {"prf", 16386, "AlgorithmIdentifier"}, + {"pkcs-12", 1879048204, 0}, + {0, 1073741825, "pkcs"}, + {0, 1, "12"}, + {"pkcs-12-PFX", 1610612741, 0}, + {"version", 1610874883, 0}, + {"v3", 1, "3"}, + {"authSafe", 1073741826, "pkcs-7-ContentInfo"}, + {"macData", 16386, "pkcs-12-MacData"}, + {"pkcs-12-PbeParams", 1610612741, 0}, + {"salt", 1073741831, 0}, + {"iterations", 3, 0}, + {"pkcs-12-MacData", 1610612741, 0}, + {"mac", 1073741826, "pkcs-7-DigestInfo"}, + {"macSalt", 1073741831, 0}, + {"iterations", 536903683, 0}, + {0, 9, "1"}, + {"pkcs-12-AuthenticatedSafe", 1610612747, 0}, + {0, 2, "pkcs-7-ContentInfo"}, + {"pkcs-12-SafeContents", 1610612747, 0}, + {0, 2, "pkcs-12-SafeBag"}, + {"pkcs-12-SafeBag", 1610612741, 0}, + {"bagId", 1073741836, 0}, + {"bagValue", 1614815245, 0}, + {0, 1073743880, "0"}, + {"badId", 1, 0}, + {"bagAttributes", 536887311, 0}, + {0, 2, "pkcs-12-PKCS12Attribute"}, + {"pkcs-12-bagtypes", 1879048204, 0}, + {0, 1073741825, "pkcs-12"}, + {0, 1073741825, "10"}, + {0, 1, "1"}, + {"pkcs-12-keyBag", 1879048204, 0}, + {0, 1073741825, "pkcs-12-bagtypes"}, + {0, 1, "1"}, + {"pkcs-12-pkcs8ShroudedKeyBag", 1879048204, 0}, + {0, 1073741825, "pkcs-12-bagtypes"}, + {0, 1, "2"}, + {"pkcs-12-certBag", 1879048204, 0}, + {0, 1073741825, "pkcs-12-bagtypes"}, + {0, 1, "3"}, + {"pkcs-12-crlBag", 1879048204, 0}, + {0, 1073741825, "pkcs-12-bagtypes"}, + {0, 1, "4"}, + {"pkcs-12-KeyBag", 1073741826, "pkcs-8-PrivateKeyInfo"}, + {"pkcs-12-PKCS8ShroudedKeyBag", 1073741826, "pkcs-8-EncryptedPrivateKeyInfo"}, + {"pkcs-12-CertBag", 1610612741, 0}, + {"certId", 1073741836, 0}, + {"certValue", 541073421, 0}, + {0, 1073743880, "0"}, + {"certId", 1, 0}, + {"pkcs-12-CRLBag", 1610612741, 0}, + {"crlId", 1073741836, 0}, + {"crlValue", 541073421, 0}, + {0, 1073743880, "0"}, + {"crlId", 1, 0}, + {"pkcs-12-PKCS12Attribute", 1073741826, "Attribute"}, + {"pkcs-7-data", 1879048204, 0}, + {"iso", 1073741825, "1"}, + {"member-body", 1073741825, "2"}, + {"us", 1073741825, "840"}, + {"rsadsi", 1073741825, "113549"}, + {"pkcs", 1073741825, "1"}, + {"pkcs7", 1073741825, "7"}, + {0, 1, "1"}, + {"pkcs-7-encryptedData", 1879048204, 0}, + {"iso", 1073741825, "1"}, + {"member-body", 1073741825, "2"}, + {"us", 1073741825, "840"}, + {"rsadsi", 1073741825, "113549"}, + {"pkcs", 1073741825, "1"}, + {"pkcs7", 1073741825, "7"}, + {0, 1, "6"}, + {"pkcs-7-Data", 1073741831, 0}, + {"pkcs-7-EncryptedData", 1610612741, 0}, + {"version", 1073741826, "pkcs-7-CMSVersion"}, + {"encryptedContentInfo", 1073741826, "pkcs-7-EncryptedContentInfo"}, + {"unprotectedAttrs", 536895490, "pkcs-7-UnprotectedAttributes"}, + {0, 4104, "1"}, + {"pkcs-7-EncryptedContentInfo", 1610612741, 0}, + {"contentType", 1073741826, "pkcs-7-ContentType"}, + {"contentEncryptionAlgorithm", 1073741826, + "pkcs-7-ContentEncryptionAlgorithmIdentifier"}, + {"encryptedContent", 536895490, "pkcs-7-EncryptedContent"}, + {0, 4104, "0"}, + {"pkcs-7-ContentEncryptionAlgorithmIdentifier", 1073741826, + "AlgorithmIdentifier"}, + {"pkcs-7-EncryptedContent", 1073741831, 0}, + {"pkcs-7-UnprotectedAttributes", 1612709903, 0}, + {"MAX", 1074266122, "1"}, + {0, 2, "Attribute"}, + {"id-at-ldap-DC", 1880096780, "AttributeType"}, + {0, 1073741825, "0"}, + {0, 1073741825, "9"}, + {0, 1073741825, "2342"}, + {0, 1073741825, "19200300"}, + {0, 1073741825, "100"}, + {0, 1073741825, "1"}, + {0, 1, "25"}, + {"ldap-DC", 1073741826, "IA5String"}, + {"id-at-ldap-UID", 1880096780, "AttributeType"}, + {0, 1073741825, "0"}, + {0, 1073741825, "9"}, + {0, 1073741825, "2342"}, + {0, 1073741825, "19200300"}, + {0, 1073741825, "100"}, + {0, 1073741825, "1"}, + {0, 1, "1"}, + {"ldap-UID", 1073741826, "DirectoryString"}, + {"id-pda", 1879048204, 0}, + {0, 1073741825, "id-pkix"}, + {0, 1, "9"}, + {"id-pda-dateOfBirth", 1880096780, "AttributeType"}, + {0, 1073741825, "id-pda"}, + {0, 1, "1"}, + {"DateOfBirth", 1082130449, 0}, + {"id-pda-placeOfBirth", 1880096780, "AttributeType"}, + {0, 1073741825, "id-pda"}, + {0, 1, "2"}, + {"PlaceOfBirth", 1073741826, "DirectoryString"}, + {"id-pda-gender", 1880096780, "AttributeType"}, + {0, 1073741825, "id-pda"}, + {0, 1, "3"}, + {"Gender", 1612709890, "PrintableString"}, + {0, 1048586, "1"}, + {"id-pda-countryOfCitizenship", 1880096780, "AttributeType"}, + {0, 1073741825, "id-pda"}, + {0, 1, "4"}, + {"CountryOfCitizenship", 1612709890, "PrintableString"}, + {0, 1048586, "2"}, + {"id-pda-countryOfResidence", 1880096780, "AttributeType"}, + {0, 1073741825, "id-pda"}, + {0, 1, "5"}, + {"CountryOfResidence", 538968066, "PrintableString"}, + {0, 1048586, "2"}, + {0, 0, 0} +}; diff --git a/qemu/tests/pvpanic-test.c b/qemu/tests/pvpanic-test.c index a7ad6b306..d435833f7 100644 --- a/qemu/tests/pvpanic-test.c +++ b/qemu/tests/pvpanic-test.c @@ -7,10 +7,9 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <string.h> #include "libqtest.h" -#include "qemu/osdep.h" static void test_panic(void) { diff --git a/qemu/tests/pxe-test.c b/qemu/tests/pxe-test.c new file mode 100644 index 000000000..875e4c4a2 --- /dev/null +++ b/qemu/tests/pxe-test.c @@ -0,0 +1,68 @@ +/* + * PXE test cases. + * + * Copyright (c) 2016 Red Hat Inc. + * + * Authors: + * Michael S. Tsirkin <mst@redhat.com>, + * Victor Kaplansky <victork@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include <glib.h> +#include <glib/gstdio.h> +#include "qemu-common.h" +#include "libqtest.h" +#include "boot-sector.h" + +#define NETNAME "net0" + +static const char *disk = "tests/pxe-test-disk.raw"; + +static void test_pxe_one(const char *params) +{ + char *args; + + args = g_strdup_printf("-machine accel=tcg " + "-netdev user,id=" NETNAME ",tftp=./,bootfile=%s " + "%s ", + disk, params); + + qtest_start(args); + boot_sector_test(); + qtest_quit(global_qtest); + g_free(args); +} + +static void test_pxe_e1000(void) +{ + test_pxe_one("-device e1000,netdev=" NETNAME); +} + +static void test_pxe_virtio_pci(void) +{ + test_pxe_one("-device virtio-net-pci,netdev=" NETNAME); +} + +int main(int argc, char *argv[]) +{ + int ret; + const char *arch = qtest_get_arch(); + + ret = boot_sector_init(disk); + if(ret) + return ret; + + g_test_init(&argc, &argv, NULL); + + if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { + qtest_add_func("pxe/e1000", test_pxe_e1000); + qtest_add_func("pxe/virtio", test_pxe_virtio_pci); + } + ret = g_test_run(); + boot_sector_cleanup(disk); + return ret; +} diff --git a/qemu/tests/q35-test.c b/qemu/tests/q35-test.c index 812abe548..a105f1078 100644 --- a/qemu/tests/q35-test.c +++ b/qemu/tests/q35-test.c @@ -9,12 +9,11 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <string.h> #include "libqtest.h" #include "libqos/pci.h" #include "libqos/pci-pc.h" -#include "qemu/osdep.h" #include "hw/pci-host/q35.h" static void smram_set_bit(QPCIDevice *pcidev, uint8_t mask, bool enabled) diff --git a/qemu/tests/qapi-schema/alternate-any.err b/qemu/tests/qapi-schema/alternate-any.err new file mode 100644 index 000000000..aaa015473 --- /dev/null +++ b/qemu/tests/qapi-schema/alternate-any.err @@ -0,0 +1 @@ +tests/qapi-schema/alternate-any.json:2: Alternate 'Alt' member 'one' cannot use type 'any' diff --git a/qemu/tests/qapi-schema/data-array-empty.exit b/qemu/tests/qapi-schema/alternate-any.exit index d00491fd7..d00491fd7 100644 --- a/qemu/tests/qapi-schema/data-array-empty.exit +++ b/qemu/tests/qapi-schema/alternate-any.exit diff --git a/qemu/tests/qapi-schema/alternate-any.json b/qemu/tests/qapi-schema/alternate-any.json new file mode 100644 index 000000000..e47a73a11 --- /dev/null +++ b/qemu/tests/qapi-schema/alternate-any.json @@ -0,0 +1,4 @@ +# we do not allow the 'any' type as an alternate branch +{ 'alternate': 'Alt', + 'data': { 'one': 'any', + 'two': 'int' } } diff --git a/qemu/tests/qapi-schema/alternate-good.err b/qemu/tests/qapi-schema/alternate-any.out index e69de29bb..e69de29bb 100644 --- a/qemu/tests/qapi-schema/alternate-good.err +++ b/qemu/tests/qapi-schema/alternate-any.out diff --git a/qemu/tests/qapi-schema/alternate-clash.err b/qemu/tests/qapi-schema/alternate-clash.err index 51bea3e27..604d8495e 100644 --- a/qemu/tests/qapi-schema/alternate-clash.err +++ b/qemu/tests/qapi-schema/alternate-clash.err @@ -1 +1 @@ -tests/qapi-schema/alternate-clash.json:2: Alternate 'Alt1' member 'ONE' clashes with 'one' +tests/qapi-schema/alternate-clash.json:7: 'a_b' (branch of Alt1) collides with 'a-b' (branch of Alt1) diff --git a/qemu/tests/qapi-schema/alternate-clash.json b/qemu/tests/qapi-schema/alternate-clash.json index 39479353b..6d73bc527 100644 --- a/qemu/tests/qapi-schema/alternate-clash.json +++ b/qemu/tests/qapi-schema/alternate-clash.json @@ -1,3 +1,8 @@ -# we detect C enum collisions in an alternate +# Alternate branch name collision +# Reject an alternate that would result in a collision in generated C +# names (this would try to generate two enum values 'ALT1_KIND_A_B'). +# TODO: In the future, if alternates are simplified to not generate +# the implicit Alt1Kind enum, we would still have a collision with the +# resulting C union trying to have two members named 'a_b'. { 'alternate': 'Alt1', - 'data': { 'one': 'str', 'ONE': 'int' } } + 'data': { 'a-b': 'str', 'a_b': 'int' } } diff --git a/qemu/tests/qapi-schema/alternate-empty.err b/qemu/tests/qapi-schema/alternate-empty.err new file mode 100644 index 000000000..bb06c5bfe --- /dev/null +++ b/qemu/tests/qapi-schema/alternate-empty.err @@ -0,0 +1 @@ +tests/qapi-schema/alternate-empty.json:2: Alternate 'Alt' should have at least two branches in 'data' diff --git a/qemu/tests/qapi-schema/data-array-unknown.exit b/qemu/tests/qapi-schema/alternate-empty.exit index d00491fd7..d00491fd7 100644 --- a/qemu/tests/qapi-schema/data-array-unknown.exit +++ b/qemu/tests/qapi-schema/alternate-empty.exit diff --git a/qemu/tests/qapi-schema/alternate-empty.json b/qemu/tests/qapi-schema/alternate-empty.json new file mode 100644 index 000000000..fff15baf1 --- /dev/null +++ b/qemu/tests/qapi-schema/alternate-empty.json @@ -0,0 +1,2 @@ +# alternates must list at least two types to be useful +{ 'alternate': 'Alt', 'data': { 'i': 'int' } } diff --git a/qemu/tests/qapi-schema/data-array-empty.out b/qemu/tests/qapi-schema/alternate-empty.out index e69de29bb..e69de29bb 100644 --- a/qemu/tests/qapi-schema/data-array-empty.out +++ b/qemu/tests/qapi-schema/alternate-empty.out diff --git a/qemu/tests/qapi-schema/alternate-good.exit b/qemu/tests/qapi-schema/alternate-good.exit deleted file mode 100644 index 573541ac9..000000000 --- a/qemu/tests/qapi-schema/alternate-good.exit +++ /dev/null @@ -1 +0,0 @@ -0 diff --git a/qemu/tests/qapi-schema/alternate-good.json b/qemu/tests/qapi-schema/alternate-good.json deleted file mode 100644 index 33717704c..000000000 --- a/qemu/tests/qapi-schema/alternate-good.json +++ /dev/null @@ -1,9 +0,0 @@ -# Working example of alternate -{ 'struct': 'Data', - 'data': { '*number': 'int', '*name': 'str' } } -{ 'enum': 'Enum', - 'data': [ 'hello', 'world' ] } -{ 'alternate': 'Alt', - 'data': { 'value': 'int', - 'string': 'Enum', - 'struct': 'Data' } } diff --git a/qemu/tests/qapi-schema/alternate-good.out b/qemu/tests/qapi-schema/alternate-good.out deleted file mode 100644 index 99848eefb..000000000 --- a/qemu/tests/qapi-schema/alternate-good.out +++ /dev/null @@ -1,6 +0,0 @@ -[OrderedDict([('struct', 'Data'), ('data', OrderedDict([('*number', 'int'), ('*name', 'str')]))]), - OrderedDict([('enum', 'Enum'), ('data', ['hello', 'world'])]), - OrderedDict([('alternate', 'Alt'), ('data', OrderedDict([('value', 'int'), ('string', 'Enum'), ('struct', 'Data')]))])] -[{'enum_name': 'Enum', 'enum_values': ['hello', 'world']}, - {'enum_name': 'AltKind', 'enum_values': None}] -[OrderedDict([('struct', 'Data'), ('data', OrderedDict([('*number', 'int'), ('*name', 'str')]))])] diff --git a/qemu/tests/qapi-schema/alternate-nested.json b/qemu/tests/qapi-schema/alternate-nested.json index c4233b9f3..8e2218649 100644 --- a/qemu/tests/qapi-schema/alternate-nested.json +++ b/qemu/tests/qapi-schema/alternate-nested.json @@ -2,4 +2,4 @@ { 'alternate': 'Alt1', 'data': { 'name': 'str', 'value': 'int' } } { 'alternate': 'Alt2', - 'data': { 'nested': 'Alt1' } } + 'data': { 'nested': 'Alt1', 'b': 'bool' } } diff --git a/qemu/tests/qapi-schema/alternate-unknown.json b/qemu/tests/qapi-schema/alternate-unknown.json index ad5c10302..08c80dced 100644 --- a/qemu/tests/qapi-schema/alternate-unknown.json +++ b/qemu/tests/qapi-schema/alternate-unknown.json @@ -1,3 +1,3 @@ # we reject an alternate with unknown type in branch { 'alternate': 'Alt', - 'data': { 'unknown': 'MissingType' } } + 'data': { 'unknown': 'MissingType', 'i': 'int' } } diff --git a/qemu/tests/qapi-schema/args-alternate.err b/qemu/tests/qapi-schema/args-alternate.err new file mode 100644 index 000000000..3086eae56 --- /dev/null +++ b/qemu/tests/qapi-schema/args-alternate.err @@ -0,0 +1 @@ +tests/qapi-schema/args-alternate.json:3: 'data' for command 'oops' cannot use alternate type 'Alt' diff --git a/qemu/tests/qapi-schema/data-int.exit b/qemu/tests/qapi-schema/args-alternate.exit index d00491fd7..d00491fd7 100644 --- a/qemu/tests/qapi-schema/data-int.exit +++ b/qemu/tests/qapi-schema/args-alternate.exit diff --git a/qemu/tests/qapi-schema/args-alternate.json b/qemu/tests/qapi-schema/args-alternate.json new file mode 100644 index 000000000..69e94d481 --- /dev/null +++ b/qemu/tests/qapi-schema/args-alternate.json @@ -0,0 +1,3 @@ +# we do not allow alternate arguments +{ 'alternate': 'Alt', 'data': { 'case1': 'int', 'case2': 'str' } } +{ 'command': 'oops', 'data': 'Alt' } diff --git a/qemu/tests/qapi-schema/data-array-unknown.out b/qemu/tests/qapi-schema/args-alternate.out index e69de29bb..e69de29bb 100644 --- a/qemu/tests/qapi-schema/data-array-unknown.out +++ b/qemu/tests/qapi-schema/args-alternate.out diff --git a/qemu/tests/qapi-schema/args-any.err b/qemu/tests/qapi-schema/args-any.err new file mode 100644 index 000000000..bf9b5e073 --- /dev/null +++ b/qemu/tests/qapi-schema/args-any.err @@ -0,0 +1 @@ +tests/qapi-schema/args-any.json:2: 'data' for command 'oops' cannot use built-in type 'any' diff --git a/qemu/tests/qapi-schema/data-member-array-bad.exit b/qemu/tests/qapi-schema/args-any.exit index d00491fd7..d00491fd7 100644 --- a/qemu/tests/qapi-schema/data-member-array-bad.exit +++ b/qemu/tests/qapi-schema/args-any.exit diff --git a/qemu/tests/qapi-schema/args-any.json b/qemu/tests/qapi-schema/args-any.json new file mode 100644 index 000000000..58fe5e470 --- /dev/null +++ b/qemu/tests/qapi-schema/args-any.json @@ -0,0 +1,2 @@ +# we do not allow an 'any' argument +{ 'command': 'oops', 'data': 'any' } diff --git a/qemu/tests/qapi-schema/data-int.out b/qemu/tests/qapi-schema/args-any.out index e69de29bb..e69de29bb 100644 --- a/qemu/tests/qapi-schema/data-int.out +++ b/qemu/tests/qapi-schema/args-any.out diff --git a/qemu/tests/qapi-schema/data-array-empty.err b/qemu/tests/qapi-schema/args-array-empty.err index f713f1489..cb7ed33b3 100644 --- a/qemu/tests/qapi-schema/data-array-empty.err +++ b/qemu/tests/qapi-schema/args-array-empty.err @@ -1 +1 @@ -tests/qapi-schema/data-array-empty.json:2: Member 'empty' of 'data' for command 'oops': array type must contain single type name +tests/qapi-schema/args-array-empty.json:2: Member 'empty' of 'data' for command 'oops': array type must contain single type name diff --git a/qemu/tests/qapi-schema/data-member-unknown.exit b/qemu/tests/qapi-schema/args-array-empty.exit index d00491fd7..d00491fd7 100644 --- a/qemu/tests/qapi-schema/data-member-unknown.exit +++ b/qemu/tests/qapi-schema/args-array-empty.exit diff --git a/qemu/tests/qapi-schema/data-array-empty.json b/qemu/tests/qapi-schema/args-array-empty.json index 652dcfb24..652dcfb24 100644 --- a/qemu/tests/qapi-schema/data-array-empty.json +++ b/qemu/tests/qapi-schema/args-array-empty.json diff --git a/qemu/tests/qapi-schema/data-member-array-bad.out b/qemu/tests/qapi-schema/args-array-empty.out index e69de29bb..e69de29bb 100644 --- a/qemu/tests/qapi-schema/data-member-array-bad.out +++ b/qemu/tests/qapi-schema/args-array-empty.out diff --git a/qemu/tests/qapi-schema/args-array-unknown.err b/qemu/tests/qapi-schema/args-array-unknown.err new file mode 100644 index 000000000..cd7a0f98d --- /dev/null +++ b/qemu/tests/qapi-schema/args-array-unknown.err @@ -0,0 +1 @@ +tests/qapi-schema/args-array-unknown.json:2: Member 'array' of 'data' for command 'oops' uses unknown type 'NoSuchType' diff --git a/qemu/tests/qapi-schema/data-unknown.exit b/qemu/tests/qapi-schema/args-array-unknown.exit index d00491fd7..d00491fd7 100644 --- a/qemu/tests/qapi-schema/data-unknown.exit +++ b/qemu/tests/qapi-schema/args-array-unknown.exit diff --git a/qemu/tests/qapi-schema/data-array-unknown.json b/qemu/tests/qapi-schema/args-array-unknown.json index 6f3e88331..6f3e88331 100644 --- a/qemu/tests/qapi-schema/data-array-unknown.json +++ b/qemu/tests/qapi-schema/args-array-unknown.json diff --git a/qemu/tests/qapi-schema/data-member-array.err b/qemu/tests/qapi-schema/args-array-unknown.out index e69de29bb..e69de29bb 100644 --- a/qemu/tests/qapi-schema/data-member-array.err +++ b/qemu/tests/qapi-schema/args-array-unknown.out diff --git a/qemu/tests/qapi-schema/args-int.err b/qemu/tests/qapi-schema/args-int.err new file mode 100644 index 000000000..dc1d2504f --- /dev/null +++ b/qemu/tests/qapi-schema/args-int.err @@ -0,0 +1 @@ +tests/qapi-schema/args-int.json:2: 'data' for command 'oops' cannot use built-in type 'int' diff --git a/qemu/tests/qapi-schema/enum-max-member.exit b/qemu/tests/qapi-schema/args-int.exit index d00491fd7..d00491fd7 100644 --- a/qemu/tests/qapi-schema/enum-max-member.exit +++ b/qemu/tests/qapi-schema/args-int.exit diff --git a/qemu/tests/qapi-schema/data-int.json b/qemu/tests/qapi-schema/args-int.json index a334d92e8..a334d92e8 100644 --- a/qemu/tests/qapi-schema/data-int.json +++ b/qemu/tests/qapi-schema/args-int.json diff --git a/qemu/tests/qapi-schema/data-member-unknown.out b/qemu/tests/qapi-schema/args-int.out index e69de29bb..e69de29bb 100644 --- a/qemu/tests/qapi-schema/data-member-unknown.out +++ b/qemu/tests/qapi-schema/args-int.out diff --git a/qemu/tests/qapi-schema/args-invalid.err b/qemu/tests/qapi-schema/args-invalid.err new file mode 100644 index 000000000..fe1e94975 --- /dev/null +++ b/qemu/tests/qapi-schema/args-invalid.err @@ -0,0 +1 @@ +tests/qapi-schema/args-invalid.json:1: 'data' for command 'foo' should be a dictionary or type name diff --git a/qemu/tests/qapi-schema/enum-union-clash.exit b/qemu/tests/qapi-schema/args-invalid.exit index d00491fd7..d00491fd7 100644 --- a/qemu/tests/qapi-schema/enum-union-clash.exit +++ b/qemu/tests/qapi-schema/args-invalid.exit diff --git a/qemu/tests/qapi-schema/args-invalid.json b/qemu/tests/qapi-schema/args-invalid.json new file mode 100644 index 000000000..db0981341 --- /dev/null +++ b/qemu/tests/qapi-schema/args-invalid.json @@ -0,0 +1,2 @@ +{ 'command': 'foo', + 'data': false } diff --git a/qemu/tests/qapi-schema/data-unknown.out b/qemu/tests/qapi-schema/args-invalid.out index e69de29bb..e69de29bb 100644 --- a/qemu/tests/qapi-schema/data-unknown.out +++ b/qemu/tests/qapi-schema/args-invalid.out diff --git a/qemu/tests/qapi-schema/data-member-array-bad.err b/qemu/tests/qapi-schema/args-member-array-bad.err index 2c072d598..881b4d954 100644 --- a/qemu/tests/qapi-schema/data-member-array-bad.err +++ b/qemu/tests/qapi-schema/args-member-array-bad.err @@ -1 +1 @@ -tests/qapi-schema/data-member-array-bad.json:2: Member 'member' of 'data' for command 'oops': array type must contain single type name +tests/qapi-schema/args-member-array-bad.json:2: Member 'member' of 'data' for command 'oops': array type must contain single type name diff --git a/qemu/tests/qapi-schema/event-max.exit b/qemu/tests/qapi-schema/args-member-array-bad.exit index d00491fd7..d00491fd7 100644 --- a/qemu/tests/qapi-schema/event-max.exit +++ b/qemu/tests/qapi-schema/args-member-array-bad.exit diff --git a/qemu/tests/qapi-schema/data-member-array-bad.json b/qemu/tests/qapi-schema/args-member-array-bad.json index b2ff144ec..b2ff144ec 100644 --- a/qemu/tests/qapi-schema/data-member-array-bad.json +++ b/qemu/tests/qapi-schema/args-member-array-bad.json diff --git a/qemu/tests/qapi-schema/enum-empty.err b/qemu/tests/qapi-schema/args-member-array-bad.out index e69de29bb..e69de29bb 100644 --- a/qemu/tests/qapi-schema/enum-empty.err +++ b/qemu/tests/qapi-schema/args-member-array-bad.out diff --git a/qemu/tests/qapi-schema/args-member-case.err b/qemu/tests/qapi-schema/args-member-case.err new file mode 100644 index 000000000..19c442660 --- /dev/null +++ b/qemu/tests/qapi-schema/args-member-case.err @@ -0,0 +1 @@ +tests/qapi-schema/args-member-case.json:2: 'Arg' (parameter of no-way-this-will-get-whitelisted) should not use uppercase diff --git a/qemu/tests/qapi-schema/flat-union-base-star.exit b/qemu/tests/qapi-schema/args-member-case.exit index d00491fd7..d00491fd7 100644 --- a/qemu/tests/qapi-schema/flat-union-base-star.exit +++ b/qemu/tests/qapi-schema/args-member-case.exit diff --git a/qemu/tests/qapi-schema/args-member-case.json b/qemu/tests/qapi-schema/args-member-case.json new file mode 100644 index 000000000..93439bee8 --- /dev/null +++ b/qemu/tests/qapi-schema/args-member-case.json @@ -0,0 +1,2 @@ +# Member names should be 'lower-case' unless the struct/command is whitelisted +{ 'command': 'no-way-this-will-get-whitelisted', 'data': { 'Arg': 'int' } } diff --git a/qemu/tests/qapi-schema/enum-max-member.out b/qemu/tests/qapi-schema/args-member-case.out index e69de29bb..e69de29bb 100644 --- a/qemu/tests/qapi-schema/enum-max-member.out +++ b/qemu/tests/qapi-schema/args-member-case.out diff --git a/qemu/tests/qapi-schema/args-member-unknown.err b/qemu/tests/qapi-schema/args-member-unknown.err new file mode 100644 index 000000000..f6f82828c --- /dev/null +++ b/qemu/tests/qapi-schema/args-member-unknown.err @@ -0,0 +1 @@ +tests/qapi-schema/args-member-unknown.json:2: Member 'member' of 'data' for command 'oops' uses unknown type 'NoSuchType' diff --git a/qemu/tests/qapi-schema/flat-union-branch-clash.exit b/qemu/tests/qapi-schema/args-member-unknown.exit index d00491fd7..d00491fd7 100644 --- a/qemu/tests/qapi-schema/flat-union-branch-clash.exit +++ b/qemu/tests/qapi-schema/args-member-unknown.exit diff --git a/qemu/tests/qapi-schema/data-member-unknown.json b/qemu/tests/qapi-schema/args-member-unknown.json index 342a41ec9..342a41ec9 100644 --- a/qemu/tests/qapi-schema/data-member-unknown.json +++ b/qemu/tests/qapi-schema/args-member-unknown.json diff --git a/qemu/tests/qapi-schema/enum-union-clash.out b/qemu/tests/qapi-schema/args-member-unknown.out index e69de29bb..e69de29bb 100644 --- a/qemu/tests/qapi-schema/enum-union-clash.out +++ b/qemu/tests/qapi-schema/args-member-unknown.out diff --git a/qemu/tests/qapi-schema/args-name-clash.err b/qemu/tests/qapi-schema/args-name-clash.err new file mode 100644 index 000000000..d953e8d24 --- /dev/null +++ b/qemu/tests/qapi-schema/args-name-clash.err @@ -0,0 +1 @@ +tests/qapi-schema/args-name-clash.json:4: 'a_b' (parameter of oops) collides with 'a-b' (parameter of oops) diff --git a/qemu/tests/qapi-schema/nested-struct-returns.exit b/qemu/tests/qapi-schema/args-name-clash.exit index d00491fd7..d00491fd7 100644 --- a/qemu/tests/qapi-schema/nested-struct-returns.exit +++ b/qemu/tests/qapi-schema/args-name-clash.exit diff --git a/qemu/tests/qapi-schema/args-name-clash.json b/qemu/tests/qapi-schema/args-name-clash.json new file mode 100644 index 000000000..61423cb89 --- /dev/null +++ b/qemu/tests/qapi-schema/args-name-clash.json @@ -0,0 +1,4 @@ +# C member name collision +# Reject members that clash when mapped to C names (we would have two 'a_b' +# members). +{ 'command': 'oops', 'data': { 'a-b': 'str', 'a_b': 'str' } } diff --git a/qemu/tests/qapi-schema/event-max.out b/qemu/tests/qapi-schema/args-name-clash.out index e69de29bb..e69de29bb 100644 --- a/qemu/tests/qapi-schema/event-max.out +++ b/qemu/tests/qapi-schema/args-name-clash.out diff --git a/qemu/tests/qapi-schema/args-union.err b/qemu/tests/qapi-schema/args-union.err new file mode 100644 index 000000000..1d693d74d --- /dev/null +++ b/qemu/tests/qapi-schema/args-union.err @@ -0,0 +1 @@ +tests/qapi-schema/args-union.json:4: 'data' for command 'oops' cannot use union type 'Uni' diff --git a/qemu/tests/qapi-schema/type-bypass-no-gen.exit b/qemu/tests/qapi-schema/args-union.exit index d00491fd7..d00491fd7 100644 --- a/qemu/tests/qapi-schema/type-bypass-no-gen.exit +++ b/qemu/tests/qapi-schema/args-union.exit diff --git a/qemu/tests/qapi-schema/args-union.json b/qemu/tests/qapi-schema/args-union.json new file mode 100644 index 000000000..7bdcbb7f0 --- /dev/null +++ b/qemu/tests/qapi-schema/args-union.json @@ -0,0 +1,4 @@ +# we do not allow union arguments +# TODO should we support this? +{ 'union': 'Uni', 'data': { 'case1': 'int', 'case2': 'str' } } +{ 'command': 'oops', 'data': 'Uni' } diff --git a/qemu/tests/qapi-schema/flat-union-base-star.out b/qemu/tests/qapi-schema/args-union.out index e69de29bb..e69de29bb 100644 --- a/qemu/tests/qapi-schema/flat-union-base-star.out +++ b/qemu/tests/qapi-schema/args-union.out diff --git a/qemu/tests/qapi-schema/args-unknown.err b/qemu/tests/qapi-schema/args-unknown.err new file mode 100644 index 000000000..4d91ec869 --- /dev/null +++ b/qemu/tests/qapi-schema/args-unknown.err @@ -0,0 +1 @@ +tests/qapi-schema/args-unknown.json:2: 'data' for command 'oops' uses unknown type 'NoSuchType' diff --git a/qemu/tests/qapi-schema/union-bad-branch.exit b/qemu/tests/qapi-schema/args-unknown.exit index d00491fd7..d00491fd7 100644 --- a/qemu/tests/qapi-schema/union-bad-branch.exit +++ b/qemu/tests/qapi-schema/args-unknown.exit diff --git a/qemu/tests/qapi-schema/data-unknown.json b/qemu/tests/qapi-schema/args-unknown.json index 32aba43b3..32aba43b3 100644 --- a/qemu/tests/qapi-schema/data-unknown.json +++ b/qemu/tests/qapi-schema/args-unknown.json diff --git a/qemu/tests/qapi-schema/flat-union-branch-clash.out b/qemu/tests/qapi-schema/args-unknown.out index e69de29bb..e69de29bb 100644 --- a/qemu/tests/qapi-schema/flat-union-branch-clash.out +++ b/qemu/tests/qapi-schema/args-unknown.out diff --git a/qemu/tests/qapi-schema/base-cycle-direct.err b/qemu/tests/qapi-schema/base-cycle-direct.err new file mode 100644 index 000000000..9c68f6543 --- /dev/null +++ b/qemu/tests/qapi-schema/base-cycle-direct.err @@ -0,0 +1 @@ +tests/qapi-schema/base-cycle-direct.json:2: Object Loopy contains itself diff --git a/qemu/tests/qapi-schema/union-max.exit b/qemu/tests/qapi-schema/base-cycle-direct.exit index d00491fd7..d00491fd7 100644 --- a/qemu/tests/qapi-schema/union-max.exit +++ b/qemu/tests/qapi-schema/base-cycle-direct.exit diff --git a/qemu/tests/qapi-schema/base-cycle-direct.json b/qemu/tests/qapi-schema/base-cycle-direct.json new file mode 100644 index 000000000..4fc66d051 --- /dev/null +++ b/qemu/tests/qapi-schema/base-cycle-direct.json @@ -0,0 +1,2 @@ +# we reject a loop in base classes +{ 'struct': 'Loopy', 'base': 'Loopy', 'data': {} } diff --git a/qemu/tests/qapi-schema/flat-union-reverse-define.err b/qemu/tests/qapi-schema/base-cycle-direct.out index e69de29bb..e69de29bb 100644 --- a/qemu/tests/qapi-schema/flat-union-reverse-define.err +++ b/qemu/tests/qapi-schema/base-cycle-direct.out diff --git a/qemu/tests/qapi-schema/base-cycle-indirect.err b/qemu/tests/qapi-schema/base-cycle-indirect.err new file mode 100644 index 000000000..fc92fe47f --- /dev/null +++ b/qemu/tests/qapi-schema/base-cycle-indirect.err @@ -0,0 +1 @@ +tests/qapi-schema/base-cycle-indirect.json:2: Object Base1 contains itself diff --git a/qemu/tests/qapi-schema/base-cycle-indirect.exit b/qemu/tests/qapi-schema/base-cycle-indirect.exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/qemu/tests/qapi-schema/base-cycle-indirect.exit @@ -0,0 +1 @@ +1 diff --git a/qemu/tests/qapi-schema/base-cycle-indirect.json b/qemu/tests/qapi-schema/base-cycle-indirect.json new file mode 100644 index 000000000..28667721a --- /dev/null +++ b/qemu/tests/qapi-schema/base-cycle-indirect.json @@ -0,0 +1,3 @@ +# we reject a loop in base classes +{ 'struct': 'Base1', 'base': 'Base2', 'data': {} } +{ 'struct': 'Base2', 'base': 'Base1', 'data': {} } diff --git a/qemu/tests/qapi-schema/nested-struct-returns.out b/qemu/tests/qapi-schema/base-cycle-indirect.out index e69de29bb..e69de29bb 100644 --- a/qemu/tests/qapi-schema/nested-struct-returns.out +++ b/qemu/tests/qapi-schema/base-cycle-indirect.out diff --git a/qemu/tests/qapi-schema/command-int.json b/qemu/tests/qapi-schema/command-int.json index c90d408ab..9a62554fc 100644 --- a/qemu/tests/qapi-schema/command-int.json +++ b/qemu/tests/qapi-schema/command-int.json @@ -1,3 +1,2 @@ # we reject collisions between commands and types -{ 'command': 'int', 'data': { 'character': 'str' }, - 'returns': { 'value': 'int' } } +{ 'command': 'int', 'data': { 'character': 'str' } } diff --git a/qemu/tests/qapi-schema/comments.out b/qemu/tests/qapi-schema/comments.out index 4ce3dcf12..5d7c13cad 100644 --- a/qemu/tests/qapi-schema/comments.out +++ b/qemu/tests/qapi-schema/comments.out @@ -1,3 +1,4 @@ -[OrderedDict([('enum', 'Status'), ('data', ['good', 'bad', 'ugly'])])] -[{'enum_name': 'Status', 'enum_values': ['good', 'bad', 'ugly']}] -[] +enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool'] + prefix QTYPE +enum Status ['good', 'bad', 'ugly'] +object q_empty diff --git a/qemu/tests/qapi-schema/data-array-unknown.err b/qemu/tests/qapi-schema/data-array-unknown.err deleted file mode 100644 index 8b731bbcc..000000000 --- a/qemu/tests/qapi-schema/data-array-unknown.err +++ /dev/null @@ -1 +0,0 @@ -tests/qapi-schema/data-array-unknown.json:2: Member 'array' of 'data' for command 'oops' uses unknown type 'array of NoSuchType' diff --git a/qemu/tests/qapi-schema/data-int.err b/qemu/tests/qapi-schema/data-int.err deleted file mode 100644 index 1a9b077c0..000000000 --- a/qemu/tests/qapi-schema/data-int.err +++ /dev/null @@ -1 +0,0 @@ -tests/qapi-schema/data-int.json:2: 'data' for command 'oops' cannot use built-in type 'int' diff --git a/qemu/tests/qapi-schema/data-member-array.exit b/qemu/tests/qapi-schema/data-member-array.exit deleted file mode 100644 index 573541ac9..000000000 --- a/qemu/tests/qapi-schema/data-member-array.exit +++ /dev/null @@ -1 +0,0 @@ -0 diff --git a/qemu/tests/qapi-schema/data-member-array.json b/qemu/tests/qapi-schema/data-member-array.json deleted file mode 100644 index e6f7f5da1..000000000 --- a/qemu/tests/qapi-schema/data-member-array.json +++ /dev/null @@ -1,4 +0,0 @@ -# valid array members -{ 'enum': 'abc', 'data': [ 'a', 'b', 'c' ] } -{ 'struct': 'def', 'data': { 'array': [ 'abc' ] } } -{ 'command': 'okay', 'data': { 'member1': [ 'int' ], 'member2': [ 'def' ] } } diff --git a/qemu/tests/qapi-schema/data-member-array.out b/qemu/tests/qapi-schema/data-member-array.out deleted file mode 100644 index c39fa2548..000000000 --- a/qemu/tests/qapi-schema/data-member-array.out +++ /dev/null @@ -1,5 +0,0 @@ -[OrderedDict([('enum', 'abc'), ('data', ['a', 'b', 'c'])]), - OrderedDict([('struct', 'def'), ('data', OrderedDict([('array', ['abc'])]))]), - OrderedDict([('command', 'okay'), ('data', OrderedDict([('member1', ['int']), ('member2', ['def'])]))])] -[{'enum_name': 'abc', 'enum_values': ['a', 'b', 'c']}] -[OrderedDict([('struct', 'def'), ('data', OrderedDict([('array', ['abc'])]))])] diff --git a/qemu/tests/qapi-schema/data-member-unknown.err b/qemu/tests/qapi-schema/data-member-unknown.err deleted file mode 100644 index ab905db80..000000000 --- a/qemu/tests/qapi-schema/data-member-unknown.err +++ /dev/null @@ -1 +0,0 @@ -tests/qapi-schema/data-member-unknown.json:2: Member 'member' of 'data' for command 'oops' uses unknown type 'NoSuchType' diff --git a/qemu/tests/qapi-schema/data-unknown.err b/qemu/tests/qapi-schema/data-unknown.err deleted file mode 100644 index 5b07277a9..000000000 --- a/qemu/tests/qapi-schema/data-unknown.err +++ /dev/null @@ -1 +0,0 @@ -tests/qapi-schema/data-unknown.json:2: 'data' for command 'oops' uses unknown type 'NoSuchType' diff --git a/qemu/tests/qapi-schema/duplicate-key.err b/qemu/tests/qapi-schema/duplicate-key.err index 768b276f8..6d02f8353 100644 --- a/qemu/tests/qapi-schema/duplicate-key.err +++ b/qemu/tests/qapi-schema/duplicate-key.err @@ -1 +1 @@ -tests/qapi-schema/duplicate-key.json:2:10: Duplicate key "key" +tests/qapi-schema/duplicate-key.json:3:10: Duplicate key "key" diff --git a/qemu/tests/qapi-schema/duplicate-key.json b/qemu/tests/qapi-schema/duplicate-key.json index 1b55d8810..14ac0e8a4 100644 --- a/qemu/tests/qapi-schema/duplicate-key.json +++ b/qemu/tests/qapi-schema/duplicate-key.json @@ -1,2 +1,3 @@ +# QAPI cannot include the same key more than once in any {} { 'key': 'value', 'key': 'value' } diff --git a/qemu/tests/qapi-schema/empty.out b/qemu/tests/qapi-schema/empty.out index b7f89a45c..8a5b03442 100644 --- a/qemu/tests/qapi-schema/empty.out +++ b/qemu/tests/qapi-schema/empty.out @@ -1,3 +1,3 @@ -[] -[] -[] +enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool'] + prefix QTYPE +object q_empty diff --git a/qemu/tests/qapi-schema/enum-bad-prefix.err b/qemu/tests/qapi-schema/enum-bad-prefix.err new file mode 100644 index 000000000..399f5f7af --- /dev/null +++ b/qemu/tests/qapi-schema/enum-bad-prefix.err @@ -0,0 +1 @@ +tests/qapi-schema/enum-bad-prefix.json:2: Enum 'MyEnum' requires a string for 'prefix' diff --git a/qemu/tests/qapi-schema/enum-bad-prefix.exit b/qemu/tests/qapi-schema/enum-bad-prefix.exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/qemu/tests/qapi-schema/enum-bad-prefix.exit @@ -0,0 +1 @@ +1 diff --git a/qemu/tests/qapi-schema/enum-bad-prefix.json b/qemu/tests/qapi-schema/enum-bad-prefix.json new file mode 100644 index 000000000..996f628f6 --- /dev/null +++ b/qemu/tests/qapi-schema/enum-bad-prefix.json @@ -0,0 +1,2 @@ +# The prefix must be a string type +{ 'enum': 'MyEnum', 'data': [ 'one' ], 'prefix': [ 'fish' ] } diff --git a/qemu/tests/qapi-schema/returns-int.err b/qemu/tests/qapi-schema/enum-bad-prefix.out index e69de29bb..e69de29bb 100644 --- a/qemu/tests/qapi-schema/returns-int.err +++ b/qemu/tests/qapi-schema/enum-bad-prefix.out diff --git a/qemu/tests/qapi-schema/enum-clash-member.err b/qemu/tests/qapi-schema/enum-clash-member.err index 48bd1360e..5403c7850 100644 --- a/qemu/tests/qapi-schema/enum-clash-member.err +++ b/qemu/tests/qapi-schema/enum-clash-member.err @@ -1 +1 @@ -tests/qapi-schema/enum-clash-member.json:2: Enum 'MyEnum' member 'ONE' clashes with 'one' +tests/qapi-schema/enum-clash-member.json:2: 'one_two' (member of MyEnum) collides with 'one-two' (member of MyEnum) diff --git a/qemu/tests/qapi-schema/enum-clash-member.json b/qemu/tests/qapi-schema/enum-clash-member.json index b7dc02a28..b6928b8bf 100644 --- a/qemu/tests/qapi-schema/enum-clash-member.json +++ b/qemu/tests/qapi-schema/enum-clash-member.json @@ -1,2 +1,2 @@ # we reject enums where members will clash when mapped to C enum -{ 'enum': 'MyEnum', 'data': [ 'one', 'ONE' ] } +{ 'enum': 'MyEnum', 'data': [ 'one-two', 'one_two' ] } diff --git a/qemu/tests/qapi-schema/enum-empty.exit b/qemu/tests/qapi-schema/enum-empty.exit deleted file mode 100644 index 573541ac9..000000000 --- a/qemu/tests/qapi-schema/enum-empty.exit +++ /dev/null @@ -1 +0,0 @@ -0 diff --git a/qemu/tests/qapi-schema/enum-empty.json b/qemu/tests/qapi-schema/enum-empty.json deleted file mode 100644 index 40d4e85a2..000000000 --- a/qemu/tests/qapi-schema/enum-empty.json +++ /dev/null @@ -1,2 +0,0 @@ -# An empty enum, although unusual, is currently acceptable -{ 'enum': 'MyEnum', 'data': [ ] } diff --git a/qemu/tests/qapi-schema/enum-empty.out b/qemu/tests/qapi-schema/enum-empty.out deleted file mode 100644 index 3b75c1613..000000000 --- a/qemu/tests/qapi-schema/enum-empty.out +++ /dev/null @@ -1,3 +0,0 @@ -[OrderedDict([('enum', 'MyEnum'), ('data', [])])] -[{'enum_name': 'MyEnum', 'enum_values': []}] -[] diff --git a/qemu/tests/qapi-schema/enum-max-member.err b/qemu/tests/qapi-schema/enum-max-member.err deleted file mode 100644 index f77837fb4..000000000 --- a/qemu/tests/qapi-schema/enum-max-member.err +++ /dev/null @@ -1 +0,0 @@ -tests/qapi-schema/enum-max-member.json:3: Enum 'MyEnum' member 'max' clashes with '(automatic)' diff --git a/qemu/tests/qapi-schema/enum-max-member.json b/qemu/tests/qapi-schema/enum-max-member.json deleted file mode 100644 index 4bcda0bf0..000000000 --- a/qemu/tests/qapi-schema/enum-max-member.json +++ /dev/null @@ -1,3 +0,0 @@ -# we reject user-supplied 'max' for clashing with implicit enum end -# TODO: should we instead munge the implicit value to avoid the clash? -{ 'enum': 'MyEnum', 'data': [ 'max' ] } diff --git a/qemu/tests/qapi-schema/enum-member-case.err b/qemu/tests/qapi-schema/enum-member-case.err new file mode 100644 index 000000000..b652e9aac --- /dev/null +++ b/qemu/tests/qapi-schema/enum-member-case.err @@ -0,0 +1 @@ +tests/qapi-schema/enum-member-case.json:3: 'Value' (member of NoWayThisWillGetWhitelisted) should not use uppercase diff --git a/qemu/tests/qapi-schema/enum-member-case.exit b/qemu/tests/qapi-schema/enum-member-case.exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/qemu/tests/qapi-schema/enum-member-case.exit @@ -0,0 +1 @@ +1 diff --git a/qemu/tests/qapi-schema/enum-member-case.json b/qemu/tests/qapi-schema/enum-member-case.json new file mode 100644 index 000000000..2096b350c --- /dev/null +++ b/qemu/tests/qapi-schema/enum-member-case.json @@ -0,0 +1,3 @@ +# Member names should be 'lower-case' unless the enum is whitelisted +{ 'enum': 'UuidInfo', 'data': [ 'Value' ] } # UuidInfo is whitelisted +{ 'enum': 'NoWayThisWillGetWhitelisted', 'data': [ 'Value' ] } diff --git a/qemu/tests/qapi-schema/type-bypass-no-gen.out b/qemu/tests/qapi-schema/enum-member-case.out index e69de29bb..e69de29bb 100644 --- a/qemu/tests/qapi-schema/type-bypass-no-gen.out +++ b/qemu/tests/qapi-schema/enum-member-case.out diff --git a/qemu/tests/qapi-schema/enum-union-clash.err b/qemu/tests/qapi-schema/enum-union-clash.err deleted file mode 100644 index c04e1a806..000000000 --- a/qemu/tests/qapi-schema/enum-union-clash.err +++ /dev/null @@ -1 +0,0 @@ -tests/qapi-schema/enum-union-clash.json:2: enum 'UnionKind' should not end in 'Kind' diff --git a/qemu/tests/qapi-schema/event-case.out b/qemu/tests/qapi-schema/event-case.out index 3764bc781..b6b4134a8 100644 --- a/qemu/tests/qapi-schema/event-case.out +++ b/qemu/tests/qapi-schema/event-case.out @@ -1,3 +1,4 @@ -[OrderedDict([('event', 'oops')])] -[] -[] +enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool'] + prefix QTYPE +event oops None +object q_empty diff --git a/qemu/tests/qapi-schema/event-max.err b/qemu/tests/qapi-schema/event-max.err deleted file mode 100644 index c85653437..000000000 --- a/qemu/tests/qapi-schema/event-max.err +++ /dev/null @@ -1 +0,0 @@ -tests/qapi-schema/event-max.json:2: Event name 'MAX' cannot be created diff --git a/qemu/tests/qapi-schema/event-max.json b/qemu/tests/qapi-schema/event-max.json deleted file mode 100644 index f3d7de2a3..000000000 --- a/qemu/tests/qapi-schema/event-max.json +++ /dev/null @@ -1,2 +0,0 @@ -# an event named 'MAX' would conflict with implicit C enum -{ 'event': 'MAX' } diff --git a/qemu/tests/qapi-schema/flat-union-bad-base.err b/qemu/tests/qapi-schema/flat-union-bad-base.err index f9c31b2bf..bee24a217 100644 --- a/qemu/tests/qapi-schema/flat-union-bad-base.err +++ b/qemu/tests/qapi-schema/flat-union-bad-base.err @@ -1 +1 @@ -tests/qapi-schema/flat-union-bad-base.json:9: Flat union 'TestUnion' must have a string base field +tests/qapi-schema/flat-union-bad-base.json:8: 'string' (member of TestTypeA) collides with 'string' (base of TestUnion) diff --git a/qemu/tests/qapi-schema/flat-union-bad-base.json b/qemu/tests/qapi-schema/flat-union-bad-base.json index e2e622bb6..74dd42170 100644 --- a/qemu/tests/qapi-schema/flat-union-bad-base.json +++ b/qemu/tests/qapi-schema/flat-union-bad-base.json @@ -1,5 +1,4 @@ -# we require the base to be an existing struct -# TODO: should we allow an anonymous inline base type? +# we allow anonymous base, but enforce no duplicate keys { 'enum': 'TestEnum', 'data': [ 'value1', 'value2' ] } { 'struct': 'TestTypeA', @@ -7,7 +6,7 @@ { 'struct': 'TestTypeB', 'data': { 'integer': 'int' } } { 'union': 'TestUnion', - 'base': { 'enum1': 'TestEnum', 'kind': 'str' }, + 'base': { 'enum1': 'TestEnum', 'string': 'str' }, 'discriminator': 'enum1', 'data': { 'value1': 'TestTypeA', 'value2': 'TestTypeB' } } diff --git a/qemu/tests/qapi-schema/flat-union-base-any.err b/qemu/tests/qapi-schema/flat-union-base-any.err new file mode 100644 index 000000000..646f1c9cd --- /dev/null +++ b/qemu/tests/qapi-schema/flat-union-base-any.err @@ -0,0 +1 @@ +tests/qapi-schema/flat-union-base-any.json:8: 'base' for union 'TestUnion' cannot use built-in type 'any' diff --git a/qemu/tests/qapi-schema/flat-union-base-any.exit b/qemu/tests/qapi-schema/flat-union-base-any.exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/qemu/tests/qapi-schema/flat-union-base-any.exit @@ -0,0 +1 @@ +1 diff --git a/qemu/tests/qapi-schema/flat-union-base-star.json b/qemu/tests/qapi-schema/flat-union-base-any.json index 5099439a9..fe66b713e 100644 --- a/qemu/tests/qapi-schema/flat-union-base-star.json +++ b/qemu/tests/qapi-schema/flat-union-base-any.json @@ -6,7 +6,7 @@ { 'struct': 'TestTypeB', 'data': { 'integer': 'int' } } { 'union': 'TestUnion', - 'base': '**', + 'base': 'any', 'discriminator': 'enum1', 'data': { 'value1': 'TestTypeA', 'value2': 'TestTypeB' } } diff --git a/qemu/tests/qapi-schema/type-bypass.err b/qemu/tests/qapi-schema/flat-union-base-any.out index e69de29bb..e69de29bb 100644 --- a/qemu/tests/qapi-schema/type-bypass.err +++ b/qemu/tests/qapi-schema/flat-union-base-any.out diff --git a/qemu/tests/qapi-schema/flat-union-base-star.err b/qemu/tests/qapi-schema/flat-union-base-star.err deleted file mode 100644 index b7748f08b..000000000 --- a/qemu/tests/qapi-schema/flat-union-base-star.err +++ /dev/null @@ -1 +0,0 @@ -tests/qapi-schema/flat-union-base-star.json:8: Base '**' is not a valid struct diff --git a/qemu/tests/qapi-schema/flat-union-base-union.err b/qemu/tests/qapi-schema/flat-union-base-union.err index ede9859a3..f138395e4 100644 --- a/qemu/tests/qapi-schema/flat-union-base-union.err +++ b/qemu/tests/qapi-schema/flat-union-base-union.err @@ -1 +1 @@ -tests/qapi-schema/flat-union-base-union.json:11: Base 'UnionBase' is not a valid struct +tests/qapi-schema/flat-union-base-union.json:14: 'base' for union 'TestUnion' cannot use union type 'UnionBase' diff --git a/qemu/tests/qapi-schema/flat-union-base-union.json b/qemu/tests/qapi-schema/flat-union-base-union.json index 6a8ea687a..98b4eba18 100644 --- a/qemu/tests/qapi-schema/flat-union-base-union.json +++ b/qemu/tests/qapi-schema/flat-union-base-union.json @@ -1,4 +1,7 @@ -# we require the base to be a struct +# For now, we require the base to be a struct without variants +# TODO: It would be possible to allow a union as a base, as long as all +# permutations of QMP names exposed by base do not clash with any QMP +# member names added by local variants. { 'enum': 'TestEnum', 'data': [ 'value1', 'value2' ] } { 'struct': 'TestTypeA', diff --git a/qemu/tests/qapi-schema/flat-union-branch-clash.err b/qemu/tests/qapi-schema/flat-union-branch-clash.err deleted file mode 100644 index f11276688..000000000 --- a/qemu/tests/qapi-schema/flat-union-branch-clash.err +++ /dev/null @@ -1 +0,0 @@ -tests/qapi-schema/flat-union-branch-clash.json:10: Member name 'name' of branch 'value1' clashes with base 'Base' diff --git a/qemu/tests/qapi-schema/flat-union-clash-member.err b/qemu/tests/qapi-schema/flat-union-clash-member.err new file mode 100644 index 000000000..2adf69755 --- /dev/null +++ b/qemu/tests/qapi-schema/flat-union-clash-member.err @@ -0,0 +1 @@ +tests/qapi-schema/flat-union-clash-member.json:11: 'name' (member of Branch1) collides with 'name' (member of Base) diff --git a/qemu/tests/qapi-schema/flat-union-clash-member.exit b/qemu/tests/qapi-schema/flat-union-clash-member.exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/qemu/tests/qapi-schema/flat-union-clash-member.exit @@ -0,0 +1 @@ +1 diff --git a/qemu/tests/qapi-schema/flat-union-branch-clash.json b/qemu/tests/qapi-schema/flat-union-clash-member.json index 8fb054f00..9efc7719b 100644 --- a/qemu/tests/qapi-schema/flat-union-branch-clash.json +++ b/qemu/tests/qapi-schema/flat-union-clash-member.json @@ -1,4 +1,5 @@ -# we check for no duplicate keys between branches and base +# We check for no duplicate keys between branch members and base +# base's member 'name' clashes with Branch1's { 'enum': 'TestEnum', 'data': [ 'value1', 'value2' ] } { 'struct': 'Base', diff --git a/qemu/tests/qapi-schema/union-bad-branch.out b/qemu/tests/qapi-schema/flat-union-clash-member.out index e69de29bb..e69de29bb 100644 --- a/qemu/tests/qapi-schema/union-bad-branch.out +++ b/qemu/tests/qapi-schema/flat-union-clash-member.out diff --git a/qemu/tests/qapi-schema/flat-union-empty.err b/qemu/tests/qapi-schema/flat-union-empty.err new file mode 100644 index 000000000..15754f54e --- /dev/null +++ b/qemu/tests/qapi-schema/flat-union-empty.err @@ -0,0 +1 @@ +tests/qapi-schema/flat-union-empty.json:4: Union 'Union' cannot have empty 'data' diff --git a/qemu/tests/qapi-schema/flat-union-empty.exit b/qemu/tests/qapi-schema/flat-union-empty.exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/qemu/tests/qapi-schema/flat-union-empty.exit @@ -0,0 +1 @@ +1 diff --git a/qemu/tests/qapi-schema/flat-union-empty.json b/qemu/tests/qapi-schema/flat-union-empty.json new file mode 100644 index 000000000..77f1d9abf --- /dev/null +++ b/qemu/tests/qapi-schema/flat-union-empty.json @@ -0,0 +1,4 @@ +# flat unions cannot be empty +{ 'enum': 'Empty', 'data': [ ] } +{ 'struct': 'Base', 'data': { 'type': 'Empty' } } +{ 'union': 'Union', 'base': 'Base', 'discriminator': 'type', 'data': { } } diff --git a/qemu/tests/qapi-schema/union-max.out b/qemu/tests/qapi-schema/flat-union-empty.out index e69de29bb..e69de29bb 100644 --- a/qemu/tests/qapi-schema/union-max.out +++ b/qemu/tests/qapi-schema/flat-union-empty.out diff --git a/qemu/tests/qapi-schema/flat-union-inline.err b/qemu/tests/qapi-schema/flat-union-inline.err index ec586277b..2333358d2 100644 --- a/qemu/tests/qapi-schema/flat-union-inline.err +++ b/qemu/tests/qapi-schema/flat-union-inline.err @@ -1 +1 @@ -tests/qapi-schema/flat-union-inline.json:7: Flat union 'TestUnion' must have a string base field +tests/qapi-schema/flat-union-inline.json:7: Member 'value1' of union 'TestUnion' should be a type name diff --git a/qemu/tests/qapi-schema/flat-union-inline.json b/qemu/tests/qapi-schema/flat-union-inline.json index 6bfdd6581..62c7cda61 100644 --- a/qemu/tests/qapi-schema/flat-union-inline.json +++ b/qemu/tests/qapi-schema/flat-union-inline.json @@ -1,11 +1,11 @@ # we require branches to be a struct name -# TODO: should we allow anonymous inline types? +# TODO: should we allow anonymous inline branch types? { 'enum': 'TestEnum', 'data': [ 'value1', 'value2' ] } { 'struct': 'Base', 'data': { 'enum1': 'TestEnum', 'kind': 'str' } } { 'union': 'TestUnion', - 'base': { 'enum1': 'TestEnum', 'kind': 'str' }, + 'base': 'Base', 'discriminator': 'enum1', 'data': { 'value1': { 'string': 'str' }, 'value2': { 'integer': 'int' } } } diff --git a/qemu/tests/qapi-schema/flat-union-no-base.err b/qemu/tests/qapi-schema/flat-union-no-base.err index bb3f70874..841c93b55 100644 --- a/qemu/tests/qapi-schema/flat-union-no-base.err +++ b/qemu/tests/qapi-schema/flat-union-no-base.err @@ -1 +1 @@ -tests/qapi-schema/flat-union-no-base.json:9: Flat union 'TestUnion' must have a string base field +tests/qapi-schema/flat-union-no-base.json:9: Flat union 'TestUnion' must have a base diff --git a/qemu/tests/qapi-schema/flat-union-reverse-define.exit b/qemu/tests/qapi-schema/flat-union-reverse-define.exit deleted file mode 100644 index 573541ac9..000000000 --- a/qemu/tests/qapi-schema/flat-union-reverse-define.exit +++ /dev/null @@ -1 +0,0 @@ -0 diff --git a/qemu/tests/qapi-schema/flat-union-reverse-define.json b/qemu/tests/qapi-schema/flat-union-reverse-define.json deleted file mode 100644 index 648bbfe2b..000000000 --- a/qemu/tests/qapi-schema/flat-union-reverse-define.json +++ /dev/null @@ -1,17 +0,0 @@ -{ 'union': 'TestUnion', - 'base': 'TestBase', - 'discriminator': 'enum1', - 'data': { 'value1': 'TestTypeA', - 'value2': 'TestTypeB' } } - -{ 'struct': 'TestBase', - 'data': { 'enum1': 'TestEnum' } } - -{ 'enum': 'TestEnum', - 'data': [ 'value1', 'value2' ] } - -{ 'struct': 'TestTypeA', - 'data': { 'string': 'str' } } - -{ 'struct': 'TestTypeB', - 'data': { 'integer': 'int' } } diff --git a/qemu/tests/qapi-schema/flat-union-reverse-define.out b/qemu/tests/qapi-schema/flat-union-reverse-define.out deleted file mode 100644 index 1ed7b8a51..000000000 --- a/qemu/tests/qapi-schema/flat-union-reverse-define.out +++ /dev/null @@ -1,9 +0,0 @@ -[OrderedDict([('union', 'TestUnion'), ('base', 'TestBase'), ('discriminator', 'enum1'), ('data', OrderedDict([('value1', 'TestTypeA'), ('value2', 'TestTypeB')]))]), - OrderedDict([('struct', 'TestBase'), ('data', OrderedDict([('enum1', 'TestEnum')]))]), - OrderedDict([('enum', 'TestEnum'), ('data', ['value1', 'value2'])]), - OrderedDict([('struct', 'TestTypeA'), ('data', OrderedDict([('string', 'str')]))]), - OrderedDict([('struct', 'TestTypeB'), ('data', OrderedDict([('integer', 'int')]))])] -[{'enum_name': 'TestEnum', 'enum_values': ['value1', 'value2']}] -[OrderedDict([('struct', 'TestBase'), ('data', OrderedDict([('enum1', 'TestEnum')]))]), - OrderedDict([('struct', 'TestTypeA'), ('data', OrderedDict([('string', 'str')]))]), - OrderedDict([('struct', 'TestTypeB'), ('data', OrderedDict([('integer', 'int')]))])] diff --git a/qemu/tests/qapi-schema/ident-with-escape.out b/qemu/tests/qapi-schema/ident-with-escape.out index 402843081..382ce2fa2 100644 --- a/qemu/tests/qapi-schema/ident-with-escape.out +++ b/qemu/tests/qapi-schema/ident-with-escape.out @@ -1,3 +1,7 @@ -[OrderedDict([('command', 'fooA'), ('data', OrderedDict([('bar1', 'str')]))])] -[] -[] +enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool'] + prefix QTYPE +command fooA q_obj_fooA-arg -> None + gen=True success_response=True +object q_empty +object q_obj_fooA-arg + member bar1: str optional=False diff --git a/qemu/tests/qapi-schema/include-non-file.err b/qemu/tests/qapi-schema/include-non-file.err index 9658c7880..faae1eacf 100644 --- a/qemu/tests/qapi-schema/include-non-file.err +++ b/qemu/tests/qapi-schema/include-non-file.err @@ -1 +1 @@ -tests/qapi-schema/include-non-file.json:1: Expected a file name (string), got: ['foo', 'bar'] +tests/qapi-schema/include-non-file.json:1: Value of 'include' must be a string diff --git a/qemu/tests/qapi-schema/include-non-file.json b/qemu/tests/qapi-schema/include-non-file.json index cd43c3f9d..4711aa42e 100644 --- a/qemu/tests/qapi-schema/include-non-file.json +++ b/qemu/tests/qapi-schema/include-non-file.json @@ -1 +1 @@ -{ 'include': [ 'foo', 'bar' ] } +{ 'include': {} } diff --git a/qemu/tests/qapi-schema/include-relpath.out b/qemu/tests/qapi-schema/include-relpath.out index 4ce3dcf12..5d7c13cad 100644 --- a/qemu/tests/qapi-schema/include-relpath.out +++ b/qemu/tests/qapi-schema/include-relpath.out @@ -1,3 +1,4 @@ -[OrderedDict([('enum', 'Status'), ('data', ['good', 'bad', 'ugly'])])] -[{'enum_name': 'Status', 'enum_values': ['good', 'bad', 'ugly']}] -[] +enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool'] + prefix QTYPE +enum Status ['good', 'bad', 'ugly'] +object q_empty diff --git a/qemu/tests/qapi-schema/include-repetition.out b/qemu/tests/qapi-schema/include-repetition.out index 4ce3dcf12..5d7c13cad 100644 --- a/qemu/tests/qapi-schema/include-repetition.out +++ b/qemu/tests/qapi-schema/include-repetition.out @@ -1,3 +1,4 @@ -[OrderedDict([('enum', 'Status'), ('data', ['good', 'bad', 'ugly'])])] -[{'enum_name': 'Status', 'enum_values': ['good', 'bad', 'ugly']}] -[] +enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool'] + prefix QTYPE +enum Status ['good', 'bad', 'ugly'] +object q_empty diff --git a/qemu/tests/qapi-schema/include-simple.out b/qemu/tests/qapi-schema/include-simple.out index 4ce3dcf12..5d7c13cad 100644 --- a/qemu/tests/qapi-schema/include-simple.out +++ b/qemu/tests/qapi-schema/include-simple.out @@ -1,3 +1,4 @@ -[OrderedDict([('enum', 'Status'), ('data', ['good', 'bad', 'ugly'])])] -[{'enum_name': 'Status', 'enum_values': ['good', 'bad', 'ugly']}] -[] +enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool'] + prefix QTYPE +enum Status ['good', 'bad', 'ugly'] +object q_empty diff --git a/qemu/tests/qapi-schema/indented-expr.out b/qemu/tests/qapi-schema/indented-expr.out index b5ce9151b..ae3293a3a 100644 --- a/qemu/tests/qapi-schema/indented-expr.out +++ b/qemu/tests/qapi-schema/indented-expr.out @@ -1,3 +1,7 @@ -[OrderedDict([('command', 'eins')]), OrderedDict([('command', 'zwei')])] -[] -[] +enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool'] + prefix QTYPE +command eins None -> None + gen=True success_response=True +object q_empty +command zwei None -> None + gen=True success_response=True diff --git a/qemu/tests/qapi-schema/leading-comma-list.err b/qemu/tests/qapi-schema/leading-comma-list.err new file mode 100644 index 000000000..f5c870bb9 --- /dev/null +++ b/qemu/tests/qapi-schema/leading-comma-list.err @@ -0,0 +1 @@ +tests/qapi-schema/leading-comma-list.json:2:13: Expected "{", "[", "]", string, boolean or "null" diff --git a/qemu/tests/qapi-schema/leading-comma-list.exit b/qemu/tests/qapi-schema/leading-comma-list.exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/qemu/tests/qapi-schema/leading-comma-list.exit @@ -0,0 +1 @@ +1 diff --git a/qemu/tests/qapi-schema/leading-comma-list.json b/qemu/tests/qapi-schema/leading-comma-list.json new file mode 100644 index 000000000..c5ba50159 --- /dev/null +++ b/qemu/tests/qapi-schema/leading-comma-list.json @@ -0,0 +1,2 @@ +{ 'enum': 'Status', + 'data': [ , 'good', 'bad', 'ugly' ] } diff --git a/qemu/tests/qapi-schema/leading-comma-list.out b/qemu/tests/qapi-schema/leading-comma-list.out new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/qemu/tests/qapi-schema/leading-comma-list.out diff --git a/qemu/tests/qapi-schema/leading-comma-object.err b/qemu/tests/qapi-schema/leading-comma-object.err new file mode 100644 index 000000000..f767b9554 --- /dev/null +++ b/qemu/tests/qapi-schema/leading-comma-object.err @@ -0,0 +1 @@ +tests/qapi-schema/leading-comma-object.json:1:3: Expected string or "}" diff --git a/qemu/tests/qapi-schema/leading-comma-object.exit b/qemu/tests/qapi-schema/leading-comma-object.exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/qemu/tests/qapi-schema/leading-comma-object.exit @@ -0,0 +1 @@ +1 diff --git a/qemu/tests/qapi-schema/leading-comma-object.json b/qemu/tests/qapi-schema/leading-comma-object.json new file mode 100644 index 000000000..c89023ff3 --- /dev/null +++ b/qemu/tests/qapi-schema/leading-comma-object.json @@ -0,0 +1,2 @@ +{ , 'enum': 'Status', + 'data': [ 'good', 'bad', 'ugly' ] } diff --git a/qemu/tests/qapi-schema/leading-comma-object.out b/qemu/tests/qapi-schema/leading-comma-object.out new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/qemu/tests/qapi-schema/leading-comma-object.out diff --git a/qemu/tests/qapi-schema/nested-struct-data.json b/qemu/tests/qapi-schema/nested-struct-data.json index 3d52d2b39..efbe773de 100644 --- a/qemu/tests/qapi-schema/nested-struct-data.json +++ b/qemu/tests/qapi-schema/nested-struct-data.json @@ -1,4 +1,3 @@ # inline subtypes collide with our desired future use of defaults { 'command': 'foo', - 'data': { 'a' : { 'string' : 'str', 'integer': 'int' }, 'b' : 'str' }, - 'returns': {} } + 'data': { 'a' : { 'string' : 'str', 'integer': 'int' }, 'b' : 'str' } } diff --git a/qemu/tests/qapi-schema/nested-struct-returns.err b/qemu/tests/qapi-schema/nested-struct-returns.err deleted file mode 100644 index 5238d075b..000000000 --- a/qemu/tests/qapi-schema/nested-struct-returns.err +++ /dev/null @@ -1 +0,0 @@ -tests/qapi-schema/nested-struct-returns.json:2: Member 'a' of 'returns' for command 'foo' should be a type name diff --git a/qemu/tests/qapi-schema/nested-struct-returns.json b/qemu/tests/qapi-schema/nested-struct-returns.json deleted file mode 100644 index d2cd047f0..000000000 --- a/qemu/tests/qapi-schema/nested-struct-returns.json +++ /dev/null @@ -1,3 +0,0 @@ -# inline subtypes collide with our desired future use of defaults -{ 'command': 'foo', - 'returns': { 'a' : { 'string' : 'str', 'integer': 'int' }, 'b' : 'str' } } diff --git a/qemu/tests/qapi-schema/qapi-schema-test.json b/qemu/tests/qapi-schema/qapi-schema-test.json index c7eaa865d..f571e1bb3 100644 --- a/qemu/tests/qapi-schema/qapi-schema-test.json +++ b/qemu/tests/qapi-schema/qapi-schema-test.json @@ -1,19 +1,42 @@ # *-*- Mode: Python -*-* +# This file is a stress test of supported qapi constructs that must +# parse and compile correctly. + +{ 'struct': 'TestStruct', + 'data': { 'integer': 'int', 'boolean': 'bool', 'string': 'str' } } + # for testing enums -{ 'enum': 'EnumOne', - 'data': [ 'value1', 'value2', 'value3' ] } { 'struct': 'NestedEnumsOne', - 'data': { 'enum1': 'EnumOne', '*enum2': 'EnumOne', 'enum3': 'EnumOne', '*enum4': 'EnumOne' } } + 'data': { 'enum1': 'EnumOne', # Intentional forward reference + '*enum2': 'EnumOne', 'enum3': 'EnumOne', '*enum4': 'EnumOne' } } + +# An empty enum, although unusual, is currently acceptable +{ 'enum': 'MyEnum', 'data': [ ] } + +# Likewise for an empty struct, including an empty base +{ 'struct': 'Empty1', 'data': { } } +{ 'struct': 'Empty2', 'base': 'Empty1', 'data': { } } + +{ 'command': 'user_def_cmd0', 'data': 'Empty2', 'returns': 'Empty2' } + +# for testing override of default naming heuristic +{ 'enum': 'QEnumTwo', + 'prefix': 'QENUM_TWO', + 'data': [ 'value1', 'value2' ] } # for testing nested structs +{ 'struct': 'UserDefOne', + 'base': 'UserDefZero', # intentional forward reference + 'data': { 'string': 'str', + '*enum1': 'EnumOne' } } # intentional forward reference + +{ 'enum': 'EnumOne', + 'data': [ 'value1', 'value2', 'value3' ] } + { 'struct': 'UserDefZero', 'data': { 'integer': 'int' } } -{ 'struct': 'UserDefOne', - 'base': 'UserDefZero', - 'data': { 'string': 'str', '*enum1': 'EnumOne' } } - { 'struct': 'UserDefTwoDictDict', 'data': { 'userdef': 'UserDefOne', 'string': 'str' } } @@ -26,35 +49,55 @@ 'data': { 'string0': 'str', 'dict1': 'UserDefTwoDict' } } +# dummy struct to force generation of array types not otherwise mentioned +{ 'struct': 'ForceArrays', + 'data': { 'unused1':['UserDefOne'], 'unused2':['UserDefTwo'], + 'unused3':['TestStruct'] } } + # for testing unions +# Among other things, test that a name collision between branches does +# not cause any problems (since only one branch can be in use at a time), +# by intentionally using two branches that both have a C member 'a_b' { 'struct': 'UserDefA', - 'data': { 'boolean': 'bool' } } + 'data': { 'boolean': 'bool', '*a_b': 'int' } } { 'struct': 'UserDefB', - 'data': { 'integer': 'int' } } + 'data': { 'intb': 'int', '*a-b': 'bool' } } -{ 'struct': 'UserDefC', - 'data': { 'string1': 'str', 'string2': 'str' } } +{ 'union': 'UserDefFlatUnion', + 'base': 'UserDefUnionBase', # intentional forward reference + 'discriminator': 'enum1', + 'data': { 'value1' : 'UserDefA', + 'value2' : 'UserDefB', + 'value3' : 'UserDefB' } } { 'struct': 'UserDefUnionBase', + 'base': 'UserDefZero', 'data': { 'string': 'str', 'enum1': 'EnumOne' } } -{ 'union': 'UserDefFlatUnion', - 'base': 'UserDefUnionBase', - 'discriminator': 'enum1', - 'data': { 'value1' : 'UserDefA', 'value2' : 'UserDefB', 'value3' : 'UserDefB' } } -# FIXME generated struct UserDefFlatUnion has members for direct base -# UserDefOne, but lacks members for indirect base UserDefZero - -# this variant of UserDefFlatUnion defaults to a union that uses fields with +# this variant of UserDefFlatUnion defaults to a union that uses members with # allocated types to test corner cases in the cleanup/dealloc visitor { 'union': 'UserDefFlatUnion2', - 'base': 'UserDefUnionBase', + 'base': { '*integer': 'int', 'string': 'str', 'enum1': 'QEnumTwo' }, 'discriminator': 'enum1', - 'data': { 'value1' : 'UserDefC', 'value2' : 'UserDefB', 'value3' : 'UserDefA' } } + 'data': { 'value1' : 'UserDefC', # intentional forward reference + 'value2' : 'UserDefB' } } +{ 'struct': 'WrapAlternate', + 'data': { 'alt': 'UserDefAlternate' } } { 'alternate': 'UserDefAlternate', - 'data': { 'uda': 'UserDefA', 's': 'str', 'i': 'int' } } + 'data': { 'udfu': 'UserDefFlatUnion', 's': 'str', 'i': 'int' } } + +{ 'struct': 'UserDefC', + 'data': { 'string1': 'str', 'string2': 'str' } } + +# for testing use of 'number' within alternates +{ 'alternate': 'AltStrBool', 'data': { 's': 'str', 'b': 'bool' } } +{ 'alternate': 'AltStrNum', 'data': { 's': 'str', 'n': 'number' } } +{ 'alternate': 'AltNumStr', 'data': { 'n': 'number', 's': 'str' } } +{ 'alternate': 'AltStrInt', 'data': { 's': 'str', 'i': 'int' } } +{ 'alternate': 'AltIntNum', 'data': { 'i': 'int', 'n': 'number' } } +{ 'alternate': 'AltNumInt', 'data': { 'n': 'number', 'i': 'int' } } # for testing native lists { 'union': 'UserDefNativeListUnion', @@ -70,7 +113,8 @@ 'number': ['number'], 'boolean': ['bool'], 'string': ['str'], - 'sizes': ['size'] } } + 'sizes': ['size'], + 'any': ['any'] } } # testing commands { 'command': 'user_def_cmd', 'data': {} } @@ -78,8 +122,11 @@ { 'command': 'user_def_cmd2', 'data': {'ud1a': 'UserDefOne', '*ud1b': 'UserDefOne'}, 'returns': 'UserDefTwo' } -{ 'command': 'user_def_cmd3', 'data': {'a': 'int', '*b': 'int' }, + +# Returning a non-dictionary requires a name from the whitelist +{ 'command': 'guest-get-time', 'data': {'a': 'int', '*b': 'int' }, 'returns': 'int' } +{ 'command': 'guest-sync', 'data': { 'arg': 'any' }, 'returns': 'any' } # For testing integer range flattening in opts-visitor. The following schema # corresponds to the option format: @@ -108,12 +155,13 @@ { 'event': 'EVENT_D', 'data': { 'a' : 'EventStructOne', 'b' : 'str', '*c': 'str', '*enum3': 'EnumOne' } } -# test that we correctly compile downstream extensions +# test that we correctly compile downstream extensions, as well as munge +# ticklish names { 'enum': '__org.qemu_x-Enum', 'data': [ '__org.qemu_x-value' ] } { 'struct': '__org.qemu_x-Base', 'data': { '__org.qemu_x-member1': '__org.qemu_x-Enum' } } { 'struct': '__org.qemu_x-Struct', 'base': '__org.qemu_x-Base', - 'data': { '__org.qemu_x-member2': 'str' } } + 'data': { '__org.qemu_x-member2': 'str', '*wchar-t': 'int' } } { 'union': '__org.qemu_x-Union1', 'data': { '__org.qemu_x-branch': 'str' } } { 'struct': '__org.qemu_x-Struct2', 'data': { 'array': ['__org.qemu_x-Union1'] } } diff --git a/qemu/tests/qapi-schema/qapi-schema-test.out b/qemu/tests/qapi-schema/qapi-schema-test.out index cf0ccc402..19cd214f6 100644 --- a/qemu/tests/qapi-schema/qapi-schema-test.out +++ b/qemu/tests/qapi-schema/qapi-schema-test.out @@ -1,55 +1,211 @@ -[OrderedDict([('enum', 'EnumOne'), ('data', ['value1', 'value2', 'value3'])]), - OrderedDict([('struct', 'NestedEnumsOne'), ('data', OrderedDict([('enum1', 'EnumOne'), ('*enum2', 'EnumOne'), ('enum3', 'EnumOne'), ('*enum4', 'EnumOne')]))]), - OrderedDict([('struct', 'UserDefZero'), ('data', OrderedDict([('integer', 'int')]))]), - OrderedDict([('struct', 'UserDefOne'), ('base', 'UserDefZero'), ('data', OrderedDict([('string', 'str'), ('*enum1', 'EnumOne')]))]), - OrderedDict([('struct', 'UserDefTwoDictDict'), ('data', OrderedDict([('userdef', 'UserDefOne'), ('string', 'str')]))]), - OrderedDict([('struct', 'UserDefTwoDict'), ('data', OrderedDict([('string1', 'str'), ('dict2', 'UserDefTwoDictDict'), ('*dict3', 'UserDefTwoDictDict')]))]), - OrderedDict([('struct', 'UserDefTwo'), ('data', OrderedDict([('string0', 'str'), ('dict1', 'UserDefTwoDict')]))]), - OrderedDict([('struct', 'UserDefA'), ('data', OrderedDict([('boolean', 'bool')]))]), - OrderedDict([('struct', 'UserDefB'), ('data', OrderedDict([('integer', 'int')]))]), - OrderedDict([('struct', 'UserDefC'), ('data', OrderedDict([('string1', 'str'), ('string2', 'str')]))]), - OrderedDict([('struct', 'UserDefUnionBase'), ('data', OrderedDict([('string', 'str'), ('enum1', 'EnumOne')]))]), - OrderedDict([('union', 'UserDefFlatUnion'), ('base', 'UserDefUnionBase'), ('discriminator', 'enum1'), ('data', OrderedDict([('value1', 'UserDefA'), ('value2', 'UserDefB'), ('value3', 'UserDefB')]))]), - OrderedDict([('union', 'UserDefFlatUnion2'), ('base', 'UserDefUnionBase'), ('discriminator', 'enum1'), ('data', OrderedDict([('value1', 'UserDefC'), ('value2', 'UserDefB'), ('value3', 'UserDefA')]))]), - OrderedDict([('alternate', 'UserDefAlternate'), ('data', OrderedDict([('uda', 'UserDefA'), ('s', 'str'), ('i', 'int')]))]), - OrderedDict([('union', 'UserDefNativeListUnion'), ('data', OrderedDict([('integer', ['int']), ('s8', ['int8']), ('s16', ['int16']), ('s32', ['int32']), ('s64', ['int64']), ('u8', ['uint8']), ('u16', ['uint16']), ('u32', ['uint32']), ('u64', ['uint64']), ('number', ['number']), ('boolean', ['bool']), ('string', ['str']), ('sizes', ['size'])]))]), - OrderedDict([('command', 'user_def_cmd'), ('data', OrderedDict())]), - OrderedDict([('command', 'user_def_cmd1'), ('data', OrderedDict([('ud1a', 'UserDefOne')]))]), - OrderedDict([('command', 'user_def_cmd2'), ('data', OrderedDict([('ud1a', 'UserDefOne'), ('*ud1b', 'UserDefOne')])), ('returns', 'UserDefTwo')]), - OrderedDict([('command', 'user_def_cmd3'), ('data', OrderedDict([('a', 'int'), ('*b', 'int')])), ('returns', 'int')]), - OrderedDict([('struct', 'UserDefOptions'), ('data', OrderedDict([('*i64', ['int']), ('*u64', ['uint64']), ('*u16', ['uint16']), ('*i64x', 'int'), ('*u64x', 'uint64')]))]), - OrderedDict([('struct', 'EventStructOne'), ('data', OrderedDict([('struct1', 'UserDefOne'), ('string', 'str'), ('*enum2', 'EnumOne')]))]), - OrderedDict([('event', 'EVENT_A')]), - OrderedDict([('event', 'EVENT_B'), ('data', OrderedDict())]), - OrderedDict([('event', 'EVENT_C'), ('data', OrderedDict([('*a', 'int'), ('*b', 'UserDefOne'), ('c', 'str')]))]), - OrderedDict([('event', 'EVENT_D'), ('data', OrderedDict([('a', 'EventStructOne'), ('b', 'str'), ('*c', 'str'), ('*enum3', 'EnumOne')]))]), - OrderedDict([('enum', '__org.qemu_x-Enum'), ('data', ['__org.qemu_x-value'])]), - OrderedDict([('struct', '__org.qemu_x-Base'), ('data', OrderedDict([('__org.qemu_x-member1', '__org.qemu_x-Enum')]))]), - OrderedDict([('struct', '__org.qemu_x-Struct'), ('base', '__org.qemu_x-Base'), ('data', OrderedDict([('__org.qemu_x-member2', 'str')]))]), - OrderedDict([('union', '__org.qemu_x-Union1'), ('data', OrderedDict([('__org.qemu_x-branch', 'str')]))]), - OrderedDict([('struct', '__org.qemu_x-Struct2'), ('data', OrderedDict([('array', ['__org.qemu_x-Union1'])]))]), - OrderedDict([('union', '__org.qemu_x-Union2'), ('base', '__org.qemu_x-Base'), ('discriminator', '__org.qemu_x-member1'), ('data', OrderedDict([('__org.qemu_x-value', '__org.qemu_x-Struct2')]))]), - OrderedDict([('alternate', '__org.qemu_x-Alt'), ('data', OrderedDict([('__org.qemu_x-branch', 'str'), ('b', '__org.qemu_x-Base')]))]), - OrderedDict([('event', '__ORG.QEMU_X-EVENT'), ('data', '__org.qemu_x-Struct')]), - OrderedDict([('command', '__org.qemu_x-command'), ('data', OrderedDict([('a', ['__org.qemu_x-Enum']), ('b', ['__org.qemu_x-Struct']), ('c', '__org.qemu_x-Union2'), ('d', '__org.qemu_x-Alt')])), ('returns', '__org.qemu_x-Union1')])] -[{'enum_name': 'EnumOne', 'enum_values': ['value1', 'value2', 'value3']}, - {'enum_name': '__org.qemu_x-Enum', 'enum_values': ['__org.qemu_x-value']}, - {'enum_name': 'UserDefAlternateKind', 'enum_values': None}, - {'enum_name': 'UserDefNativeListUnionKind', 'enum_values': None}, - {'enum_name': '__org.qemu_x-Union1Kind', 'enum_values': None}, - {'enum_name': '__org.qemu_x-AltKind', 'enum_values': None}] -[OrderedDict([('struct', 'NestedEnumsOne'), ('data', OrderedDict([('enum1', 'EnumOne'), ('*enum2', 'EnumOne'), ('enum3', 'EnumOne'), ('*enum4', 'EnumOne')]))]), - OrderedDict([('struct', 'UserDefZero'), ('data', OrderedDict([('integer', 'int')]))]), - OrderedDict([('struct', 'UserDefOne'), ('base', 'UserDefZero'), ('data', OrderedDict([('string', 'str'), ('*enum1', 'EnumOne')]))]), - OrderedDict([('struct', 'UserDefTwoDictDict'), ('data', OrderedDict([('userdef', 'UserDefOne'), ('string', 'str')]))]), - OrderedDict([('struct', 'UserDefTwoDict'), ('data', OrderedDict([('string1', 'str'), ('dict2', 'UserDefTwoDictDict'), ('*dict3', 'UserDefTwoDictDict')]))]), - OrderedDict([('struct', 'UserDefTwo'), ('data', OrderedDict([('string0', 'str'), ('dict1', 'UserDefTwoDict')]))]), - OrderedDict([('struct', 'UserDefA'), ('data', OrderedDict([('boolean', 'bool')]))]), - OrderedDict([('struct', 'UserDefB'), ('data', OrderedDict([('integer', 'int')]))]), - OrderedDict([('struct', 'UserDefC'), ('data', OrderedDict([('string1', 'str'), ('string2', 'str')]))]), - OrderedDict([('struct', 'UserDefUnionBase'), ('data', OrderedDict([('string', 'str'), ('enum1', 'EnumOne')]))]), - OrderedDict([('struct', 'UserDefOptions'), ('data', OrderedDict([('*i64', ['int']), ('*u64', ['uint64']), ('*u16', ['uint16']), ('*i64x', 'int'), ('*u64x', 'uint64')]))]), - OrderedDict([('struct', 'EventStructOne'), ('data', OrderedDict([('struct1', 'UserDefOne'), ('string', 'str'), ('*enum2', 'EnumOne')]))]), - OrderedDict([('struct', '__org.qemu_x-Base'), ('data', OrderedDict([('__org.qemu_x-member1', '__org.qemu_x-Enum')]))]), - OrderedDict([('struct', '__org.qemu_x-Struct'), ('base', '__org.qemu_x-Base'), ('data', OrderedDict([('__org.qemu_x-member2', 'str')]))]), - OrderedDict([('struct', '__org.qemu_x-Struct2'), ('data', OrderedDict([('array', ['__org.qemu_x-Union1'])]))])] +alternate AltIntNum + case i: int + case n: number +alternate AltNumInt + case n: number + case i: int +alternate AltNumStr + case n: number + case s: str +alternate AltStrBool + case s: str + case b: bool +alternate AltStrInt + case s: str + case i: int +alternate AltStrNum + case s: str + case n: number +event EVENT_A None +event EVENT_B None +event EVENT_C q_obj_EVENT_C-arg +event EVENT_D q_obj_EVENT_D-arg +object Empty1 +object Empty2 + base Empty1 +enum EnumOne ['value1', 'value2', 'value3'] +object EventStructOne + member struct1: UserDefOne optional=False + member string: str optional=False + member enum2: EnumOne optional=True +object ForceArrays + member unused1: UserDefOneList optional=False + member unused2: UserDefTwoList optional=False + member unused3: TestStructList optional=False +enum MyEnum [] +object NestedEnumsOne + member enum1: EnumOne optional=False + member enum2: EnumOne optional=True + member enum3: EnumOne optional=False + member enum4: EnumOne optional=True +enum QEnumTwo ['value1', 'value2'] + prefix QENUM_TWO +enum QType ['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', 'qfloat', 'qbool'] + prefix QTYPE +object TestStruct + member integer: int optional=False + member boolean: bool optional=False + member string: str optional=False +object UserDefA + member boolean: bool optional=False + member a_b: int optional=True +alternate UserDefAlternate + case udfu: UserDefFlatUnion + case s: str + case i: int +object UserDefB + member intb: int optional=False + member a-b: bool optional=True +object UserDefC + member string1: str optional=False + member string2: str optional=False +object UserDefFlatUnion + base UserDefUnionBase + tag enum1 + case value1: UserDefA + case value2: UserDefB + case value3: UserDefB +object UserDefFlatUnion2 + base q_obj_UserDefFlatUnion2-base + tag enum1 + case value1: UserDefC + case value2: UserDefB +object UserDefNativeListUnion + member type: UserDefNativeListUnionKind optional=False + case integer: q_obj_intList-wrapper + case s8: q_obj_int8List-wrapper + case s16: q_obj_int16List-wrapper + case s32: q_obj_int32List-wrapper + case s64: q_obj_int64List-wrapper + case u8: q_obj_uint8List-wrapper + case u16: q_obj_uint16List-wrapper + case u32: q_obj_uint32List-wrapper + case u64: q_obj_uint64List-wrapper + case number: q_obj_numberList-wrapper + case boolean: q_obj_boolList-wrapper + case string: q_obj_strList-wrapper + case sizes: q_obj_sizeList-wrapper + case any: q_obj_anyList-wrapper +enum UserDefNativeListUnionKind ['integer', 's8', 's16', 's32', 's64', 'u8', 'u16', 'u32', 'u64', 'number', 'boolean', 'string', 'sizes', 'any'] +object UserDefOne + base UserDefZero + member string: str optional=False + member enum1: EnumOne optional=True +object UserDefOptions + member i64: intList optional=True + member u64: uint64List optional=True + member u16: uint16List optional=True + member i64x: int optional=True + member u64x: uint64 optional=True +object UserDefTwo + member string0: str optional=False + member dict1: UserDefTwoDict optional=False +object UserDefTwoDict + member string1: str optional=False + member dict2: UserDefTwoDictDict optional=False + member dict3: UserDefTwoDictDict optional=True +object UserDefTwoDictDict + member userdef: UserDefOne optional=False + member string: str optional=False +object UserDefUnionBase + base UserDefZero + member string: str optional=False + member enum1: EnumOne optional=False +object UserDefZero + member integer: int optional=False +object WrapAlternate + member alt: UserDefAlternate optional=False +event __ORG.QEMU_X-EVENT __org.qemu_x-Struct +alternate __org.qemu_x-Alt + case __org.qemu_x-branch: str + case b: __org.qemu_x-Base +object __org.qemu_x-Base + member __org.qemu_x-member1: __org.qemu_x-Enum optional=False +enum __org.qemu_x-Enum ['__org.qemu_x-value'] +object __org.qemu_x-Struct + base __org.qemu_x-Base + member __org.qemu_x-member2: str optional=False + member wchar-t: int optional=True +object __org.qemu_x-Struct2 + member array: __org.qemu_x-Union1List optional=False +object __org.qemu_x-Union1 + member type: __org.qemu_x-Union1Kind optional=False + case __org.qemu_x-branch: q_obj_str-wrapper +enum __org.qemu_x-Union1Kind ['__org.qemu_x-branch'] +object __org.qemu_x-Union2 + base __org.qemu_x-Base + tag __org.qemu_x-member1 + case __org.qemu_x-value: __org.qemu_x-Struct2 +command __org.qemu_x-command q_obj___org.qemu_x-command-arg -> __org.qemu_x-Union1 + gen=True success_response=True +command guest-get-time q_obj_guest-get-time-arg -> int + gen=True success_response=True +command guest-sync q_obj_guest-sync-arg -> any + gen=True success_response=True +object q_empty +object q_obj_EVENT_C-arg + member a: int optional=True + member b: UserDefOne optional=True + member c: str optional=False +object q_obj_EVENT_D-arg + member a: EventStructOne optional=False + member b: str optional=False + member c: str optional=True + member enum3: EnumOne optional=True +object q_obj_UserDefFlatUnion2-base + member integer: int optional=True + member string: str optional=False + member enum1: QEnumTwo optional=False +object q_obj___org.qemu_x-command-arg + member a: __org.qemu_x-EnumList optional=False + member b: __org.qemu_x-StructList optional=False + member c: __org.qemu_x-Union2 optional=False + member d: __org.qemu_x-Alt optional=False +object q_obj_anyList-wrapper + member data: anyList optional=False +object q_obj_boolList-wrapper + member data: boolList optional=False +object q_obj_guest-get-time-arg + member a: int optional=False + member b: int optional=True +object q_obj_guest-sync-arg + member arg: any optional=False +object q_obj_int16List-wrapper + member data: int16List optional=False +object q_obj_int32List-wrapper + member data: int32List optional=False +object q_obj_int64List-wrapper + member data: int64List optional=False +object q_obj_int8List-wrapper + member data: int8List optional=False +object q_obj_intList-wrapper + member data: intList optional=False +object q_obj_numberList-wrapper + member data: numberList optional=False +object q_obj_sizeList-wrapper + member data: sizeList optional=False +object q_obj_str-wrapper + member data: str optional=False +object q_obj_strList-wrapper + member data: strList optional=False +object q_obj_uint16List-wrapper + member data: uint16List optional=False +object q_obj_uint32List-wrapper + member data: uint32List optional=False +object q_obj_uint64List-wrapper + member data: uint64List optional=False +object q_obj_uint8List-wrapper + member data: uint8List optional=False +object q_obj_user_def_cmd1-arg + member ud1a: UserDefOne optional=False +object q_obj_user_def_cmd2-arg + member ud1a: UserDefOne optional=False + member ud1b: UserDefOne optional=True +command user_def_cmd None -> None + gen=True success_response=True +command user_def_cmd0 Empty2 -> Empty2 + gen=True success_response=True +command user_def_cmd1 q_obj_user_def_cmd1-arg -> None + gen=True success_response=True +command user_def_cmd2 q_obj_user_def_cmd2-arg -> UserDefTwo + gen=True success_response=True diff --git a/qemu/tests/qapi-schema/reserved-command-q.err b/qemu/tests/qapi-schema/reserved-command-q.err new file mode 100644 index 000000000..f939e044e --- /dev/null +++ b/qemu/tests/qapi-schema/reserved-command-q.err @@ -0,0 +1 @@ +tests/qapi-schema/reserved-command-q.json:5: 'command' uses invalid name 'q-unix' diff --git a/qemu/tests/qapi-schema/reserved-command-q.exit b/qemu/tests/qapi-schema/reserved-command-q.exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/qemu/tests/qapi-schema/reserved-command-q.exit @@ -0,0 +1 @@ +1 diff --git a/qemu/tests/qapi-schema/reserved-command-q.json b/qemu/tests/qapi-schema/reserved-command-q.json new file mode 100644 index 000000000..99f8aae31 --- /dev/null +++ b/qemu/tests/qapi-schema/reserved-command-q.json @@ -0,0 +1,5 @@ +# C entity name collision +# We reject names like 'q-unix', because they can collide with the mangled +# name for 'unix' in generated C. +{ 'command': 'unix' } +{ 'command': 'q-unix' } diff --git a/qemu/tests/qapi-schema/reserved-command-q.out b/qemu/tests/qapi-schema/reserved-command-q.out new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/qemu/tests/qapi-schema/reserved-command-q.out diff --git a/qemu/tests/qapi-schema/reserved-enum-q.err b/qemu/tests/qapi-schema/reserved-enum-q.err new file mode 100644 index 000000000..e1c3480ee --- /dev/null +++ b/qemu/tests/qapi-schema/reserved-enum-q.err @@ -0,0 +1 @@ +tests/qapi-schema/reserved-enum-q.json:4: Member of enum 'Foo' uses invalid name 'q-Unix' diff --git a/qemu/tests/qapi-schema/reserved-enum-q.exit b/qemu/tests/qapi-schema/reserved-enum-q.exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/qemu/tests/qapi-schema/reserved-enum-q.exit @@ -0,0 +1 @@ +1 diff --git a/qemu/tests/qapi-schema/reserved-enum-q.json b/qemu/tests/qapi-schema/reserved-enum-q.json new file mode 100644 index 000000000..3593a765e --- /dev/null +++ b/qemu/tests/qapi-schema/reserved-enum-q.json @@ -0,0 +1,4 @@ +# C entity name collision +# We reject names like 'q-unix', because they can collide with the mangled +# name for 'unix' in generated C. +{ 'enum': 'Foo', 'data': [ 'unix', 'q-Unix' ] } diff --git a/qemu/tests/qapi-schema/reserved-enum-q.out b/qemu/tests/qapi-schema/reserved-enum-q.out new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/qemu/tests/qapi-schema/reserved-enum-q.out diff --git a/qemu/tests/qapi-schema/reserved-member-has.err b/qemu/tests/qapi-schema/reserved-member-has.err new file mode 100644 index 000000000..e75577144 --- /dev/null +++ b/qemu/tests/qapi-schema/reserved-member-has.err @@ -0,0 +1 @@ +tests/qapi-schema/reserved-member-has.json:5: Member of 'data' for command 'oops' uses reserved name 'has-a' diff --git a/qemu/tests/qapi-schema/reserved-member-has.exit b/qemu/tests/qapi-schema/reserved-member-has.exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/qemu/tests/qapi-schema/reserved-member-has.exit @@ -0,0 +1 @@ +1 diff --git a/qemu/tests/qapi-schema/reserved-member-has.json b/qemu/tests/qapi-schema/reserved-member-has.json new file mode 100644 index 000000000..45b9109bd --- /dev/null +++ b/qemu/tests/qapi-schema/reserved-member-has.json @@ -0,0 +1,5 @@ +# C member name collision +# We reject names like 'has-a', because they can collide with the flag +# for an optional 'a' in generated C. +# TODO we could munge the optional flag name to avoid the collision. +{ 'command': 'oops', 'data': { '*a': 'str', 'has-a': 'str' } } diff --git a/qemu/tests/qapi-schema/reserved-member-has.out b/qemu/tests/qapi-schema/reserved-member-has.out new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/qemu/tests/qapi-schema/reserved-member-has.out diff --git a/qemu/tests/qapi-schema/reserved-member-q.err b/qemu/tests/qapi-schema/reserved-member-q.err new file mode 100644 index 000000000..f3d5dd781 --- /dev/null +++ b/qemu/tests/qapi-schema/reserved-member-q.err @@ -0,0 +1 @@ +tests/qapi-schema/reserved-member-q.json:4: Member of 'data' for struct 'Foo' uses invalid name 'q-unix' diff --git a/qemu/tests/qapi-schema/reserved-member-q.exit b/qemu/tests/qapi-schema/reserved-member-q.exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/qemu/tests/qapi-schema/reserved-member-q.exit @@ -0,0 +1 @@ +1 diff --git a/qemu/tests/qapi-schema/reserved-member-q.json b/qemu/tests/qapi-schema/reserved-member-q.json new file mode 100644 index 000000000..62fed8fdd --- /dev/null +++ b/qemu/tests/qapi-schema/reserved-member-q.json @@ -0,0 +1,4 @@ +# C member name collision +# We reject names like 'q-unix', because they can collide with the mangled +# name for 'unix' in generated C. +{ 'struct': 'Foo', 'data': { 'unix':'int', 'q-unix':'bool' } } diff --git a/qemu/tests/qapi-schema/reserved-member-q.out b/qemu/tests/qapi-schema/reserved-member-q.out new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/qemu/tests/qapi-schema/reserved-member-q.out diff --git a/qemu/tests/qapi-schema/reserved-member-u.err b/qemu/tests/qapi-schema/reserved-member-u.err new file mode 100644 index 000000000..87d42296c --- /dev/null +++ b/qemu/tests/qapi-schema/reserved-member-u.err @@ -0,0 +1 @@ +tests/qapi-schema/reserved-member-u.json:7: Member of 'data' for struct 'Oops' uses reserved name 'u' diff --git a/qemu/tests/qapi-schema/reserved-member-u.exit b/qemu/tests/qapi-schema/reserved-member-u.exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/qemu/tests/qapi-schema/reserved-member-u.exit @@ -0,0 +1 @@ +1 diff --git a/qemu/tests/qapi-schema/reserved-member-u.json b/qemu/tests/qapi-schema/reserved-member-u.json new file mode 100644 index 000000000..1eaf0f301 --- /dev/null +++ b/qemu/tests/qapi-schema/reserved-member-u.json @@ -0,0 +1,7 @@ +# Potential C member name collision +# We reject use of 'u' as a member name, to allow it for internal use in +# putting union branch members in a separate namespace from QMP members. +# This is true even for non-unions, because it is possible to convert a +# struct to flat union while remaining backwards compatible in QMP. +# TODO - we could munge the member name to 'q_u' to avoid the collision +{ 'struct': 'Oops', 'data': { 'u': 'str' } } diff --git a/qemu/tests/qapi-schema/reserved-member-u.out b/qemu/tests/qapi-schema/reserved-member-u.out new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/qemu/tests/qapi-schema/reserved-member-u.out diff --git a/qemu/tests/qapi-schema/reserved-member-underscore.err b/qemu/tests/qapi-schema/reserved-member-underscore.err new file mode 100644 index 000000000..65ff0da8c --- /dev/null +++ b/qemu/tests/qapi-schema/reserved-member-underscore.err @@ -0,0 +1 @@ +tests/qapi-schema/reserved-member-underscore.json:4: Member of 'data' for struct 'Oops' uses invalid name '_oops' diff --git a/qemu/tests/qapi-schema/reserved-member-underscore.exit b/qemu/tests/qapi-schema/reserved-member-underscore.exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/qemu/tests/qapi-schema/reserved-member-underscore.exit @@ -0,0 +1 @@ +1 diff --git a/qemu/tests/qapi-schema/reserved-member-underscore.json b/qemu/tests/qapi-schema/reserved-member-underscore.json new file mode 100644 index 000000000..4a3a01763 --- /dev/null +++ b/qemu/tests/qapi-schema/reserved-member-underscore.json @@ -0,0 +1,4 @@ +# C member name collision +# We reject use of a single leading underscore in all names (names must +# begin with a letter or a downstream extension double-underscore prefix). +{ 'struct': 'Oops', 'data': { '_oops': 'str' } } diff --git a/qemu/tests/qapi-schema/reserved-member-underscore.out b/qemu/tests/qapi-schema/reserved-member-underscore.out new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/qemu/tests/qapi-schema/reserved-member-underscore.out diff --git a/qemu/tests/qapi-schema/reserved-type-kind.err b/qemu/tests/qapi-schema/reserved-type-kind.err new file mode 100644 index 000000000..0a38efaad --- /dev/null +++ b/qemu/tests/qapi-schema/reserved-type-kind.err @@ -0,0 +1 @@ +tests/qapi-schema/reserved-type-kind.json:2: enum 'UnionKind' should not end in 'Kind' diff --git a/qemu/tests/qapi-schema/reserved-type-kind.exit b/qemu/tests/qapi-schema/reserved-type-kind.exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/qemu/tests/qapi-schema/reserved-type-kind.exit @@ -0,0 +1 @@ +1 diff --git a/qemu/tests/qapi-schema/enum-union-clash.json b/qemu/tests/qapi-schema/reserved-type-kind.json index 593282b6c..9ecaba12b 100644 --- a/qemu/tests/qapi-schema/enum-union-clash.json +++ b/qemu/tests/qapi-schema/reserved-type-kind.json @@ -1,4 +1,2 @@ # we reject types that would conflict with implicit union enum { 'enum': 'UnionKind', 'data': [ 'oops' ] } -{ 'union': 'Union', - 'data': { 'a': 'int' } } diff --git a/qemu/tests/qapi-schema/reserved-type-kind.out b/qemu/tests/qapi-schema/reserved-type-kind.out new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/qemu/tests/qapi-schema/reserved-type-kind.out diff --git a/qemu/tests/qapi-schema/reserved-type-list.err b/qemu/tests/qapi-schema/reserved-type-list.err new file mode 100644 index 000000000..4510fa6d9 --- /dev/null +++ b/qemu/tests/qapi-schema/reserved-type-list.err @@ -0,0 +1 @@ +tests/qapi-schema/reserved-type-list.json:5: struct 'FooList' should not end in 'List' diff --git a/qemu/tests/qapi-schema/reserved-type-list.exit b/qemu/tests/qapi-schema/reserved-type-list.exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/qemu/tests/qapi-schema/reserved-type-list.exit @@ -0,0 +1 @@ +1 diff --git a/qemu/tests/qapi-schema/reserved-type-list.json b/qemu/tests/qapi-schema/reserved-type-list.json new file mode 100644 index 000000000..98d53bf80 --- /dev/null +++ b/qemu/tests/qapi-schema/reserved-type-list.json @@ -0,0 +1,5 @@ +# Potential C name collision +# We reserve names ending in 'List' for use by array types. +# TODO - we could choose array names to avoid collision with user types, +# in order to let this compile +{ 'struct': 'FooList', 'data': { 's': 'str' } } diff --git a/qemu/tests/qapi-schema/reserved-type-list.out b/qemu/tests/qapi-schema/reserved-type-list.out new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/qemu/tests/qapi-schema/reserved-type-list.out diff --git a/qemu/tests/qapi-schema/returns-dict.err b/qemu/tests/qapi-schema/returns-dict.err new file mode 100644 index 000000000..eb2d0c466 --- /dev/null +++ b/qemu/tests/qapi-schema/returns-dict.err @@ -0,0 +1 @@ +tests/qapi-schema/returns-dict.json:2: 'returns' for command 'oops' should be a type name diff --git a/qemu/tests/qapi-schema/returns-dict.exit b/qemu/tests/qapi-schema/returns-dict.exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/qemu/tests/qapi-schema/returns-dict.exit @@ -0,0 +1 @@ +1 diff --git a/qemu/tests/qapi-schema/returns-dict.json b/qemu/tests/qapi-schema/returns-dict.json new file mode 100644 index 000000000..1cfef3ede --- /dev/null +++ b/qemu/tests/qapi-schema/returns-dict.json @@ -0,0 +1,2 @@ +# we reject inline struct return type +{ 'command': 'oops', 'returns': { 'a': 'str' } } diff --git a/qemu/tests/qapi-schema/returns-dict.out b/qemu/tests/qapi-schema/returns-dict.out new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/qemu/tests/qapi-schema/returns-dict.out diff --git a/qemu/tests/qapi-schema/returns-int.exit b/qemu/tests/qapi-schema/returns-int.exit deleted file mode 100644 index 573541ac9..000000000 --- a/qemu/tests/qapi-schema/returns-int.exit +++ /dev/null @@ -1 +0,0 @@ -0 diff --git a/qemu/tests/qapi-schema/returns-int.json b/qemu/tests/qapi-schema/returns-int.json deleted file mode 100644 index 870ec6366..000000000 --- a/qemu/tests/qapi-schema/returns-int.json +++ /dev/null @@ -1,3 +0,0 @@ -# It is okay (although not extensible) to return a non-dictionary -# But to make it work, the name must be in a whitelist -{ 'command': 'guest-get-time', 'returns': 'int' } diff --git a/qemu/tests/qapi-schema/returns-int.out b/qemu/tests/qapi-schema/returns-int.out deleted file mode 100644 index 70b3ac5e6..000000000 --- a/qemu/tests/qapi-schema/returns-int.out +++ /dev/null @@ -1,3 +0,0 @@ -[OrderedDict([('command', 'guest-get-time'), ('returns', 'int')])] -[] -[] diff --git a/qemu/tests/qapi-schema/returns-whitelist.err b/qemu/tests/qapi-schema/returns-whitelist.err index a41f019a5..f47c1ee7c 100644 --- a/qemu/tests/qapi-schema/returns-whitelist.err +++ b/qemu/tests/qapi-schema/returns-whitelist.err @@ -1 +1 @@ -tests/qapi-schema/returns-whitelist.json:10: 'returns' for command 'no-way-this-will-get-whitelisted' cannot use built-in type 'array of int' +tests/qapi-schema/returns-whitelist.json:10: 'returns' for command 'no-way-this-will-get-whitelisted' cannot use built-in type 'int' diff --git a/qemu/tests/qapi-schema/struct-base-clash-deep.err b/qemu/tests/qapi-schema/struct-base-clash-deep.err index e3e9f8d28..e2d7943f2 100644 --- a/qemu/tests/qapi-schema/struct-base-clash-deep.err +++ b/qemu/tests/qapi-schema/struct-base-clash-deep.err @@ -1 +1 @@ -tests/qapi-schema/struct-base-clash-deep.json:7: Member name 'name' clashes with base 'Base' +tests/qapi-schema/struct-base-clash-deep.json:10: 'name' (member of Sub) collides with 'name' (member of Base) diff --git a/qemu/tests/qapi-schema/struct-base-clash-deep.json b/qemu/tests/qapi-schema/struct-base-clash-deep.json index 552fe9431..fa873ab5d 100644 --- a/qemu/tests/qapi-schema/struct-base-clash-deep.json +++ b/qemu/tests/qapi-schema/struct-base-clash-deep.json @@ -1,4 +1,7 @@ -# we check for no duplicate keys with indirect base +# Reject attempts to duplicate QMP members +# Here, 'name' would have to appear twice on the wire, locally and +# indirectly for the grandparent base; the collision doesn't care that +# one instance is optional. { 'struct': 'Base', 'data': { 'name': 'str' } } { 'struct': 'Mid', diff --git a/qemu/tests/qapi-schema/struct-base-clash.err b/qemu/tests/qapi-schema/struct-base-clash.err index 3ac37fb26..c52f33d27 100644 --- a/qemu/tests/qapi-schema/struct-base-clash.err +++ b/qemu/tests/qapi-schema/struct-base-clash.err @@ -1 +1 @@ -tests/qapi-schema/struct-base-clash.json:4: Member name 'name' clashes with base 'Base' +tests/qapi-schema/struct-base-clash.json:5: 'name' (member of Sub) collides with 'name' (member of Base) diff --git a/qemu/tests/qapi-schema/struct-base-clash.json b/qemu/tests/qapi-schema/struct-base-clash.json index f2afc9b6f..11aec80fe 100644 --- a/qemu/tests/qapi-schema/struct-base-clash.json +++ b/qemu/tests/qapi-schema/struct-base-clash.json @@ -1,4 +1,5 @@ -# we check for no duplicate keys with base +# Reject attempts to duplicate QMP members +# Here, 'name' would have to appear twice on the wire, locally and for base. { 'struct': 'Base', 'data': { 'name': 'str' } } { 'struct': 'Sub', diff --git a/qemu/tests/qapi-schema/struct-data-invalid.err b/qemu/tests/qapi-schema/struct-data-invalid.err new file mode 100644 index 000000000..6644f4c2a --- /dev/null +++ b/qemu/tests/qapi-schema/struct-data-invalid.err @@ -0,0 +1 @@ +tests/qapi-schema/struct-data-invalid.json:1: 'data' for struct 'foo' should be a dictionary or type name diff --git a/qemu/tests/qapi-schema/struct-data-invalid.exit b/qemu/tests/qapi-schema/struct-data-invalid.exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/qemu/tests/qapi-schema/struct-data-invalid.exit @@ -0,0 +1 @@ +1 diff --git a/qemu/tests/qapi-schema/struct-data-invalid.json b/qemu/tests/qapi-schema/struct-data-invalid.json new file mode 100644 index 000000000..9adbc3bb6 --- /dev/null +++ b/qemu/tests/qapi-schema/struct-data-invalid.json @@ -0,0 +1,2 @@ +{ 'struct': 'foo', + 'data': false } diff --git a/qemu/tests/qapi-schema/struct-data-invalid.out b/qemu/tests/qapi-schema/struct-data-invalid.out new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/qemu/tests/qapi-schema/struct-data-invalid.out diff --git a/qemu/tests/qapi-schema/struct-member-invalid.err b/qemu/tests/qapi-schema/struct-member-invalid.err new file mode 100644 index 000000000..69a326d45 --- /dev/null +++ b/qemu/tests/qapi-schema/struct-member-invalid.err @@ -0,0 +1 @@ +tests/qapi-schema/struct-member-invalid.json:1: Member 'a' of 'data' for struct 'foo' should be a type name diff --git a/qemu/tests/qapi-schema/struct-member-invalid.exit b/qemu/tests/qapi-schema/struct-member-invalid.exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/qemu/tests/qapi-schema/struct-member-invalid.exit @@ -0,0 +1 @@ +1 diff --git a/qemu/tests/qapi-schema/struct-member-invalid.json b/qemu/tests/qapi-schema/struct-member-invalid.json new file mode 100644 index 000000000..8f172f7a8 --- /dev/null +++ b/qemu/tests/qapi-schema/struct-member-invalid.json @@ -0,0 +1,2 @@ +{ 'struct': 'foo', + 'data': { 'a': false } } diff --git a/qemu/tests/qapi-schema/struct-member-invalid.out b/qemu/tests/qapi-schema/struct-member-invalid.out new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/qemu/tests/qapi-schema/struct-member-invalid.out diff --git a/qemu/tests/qapi-schema/test-qapi.py b/qemu/tests/qapi-schema/test-qapi.py index 634ef2d00..649677e01 100644 --- a/qemu/tests/qapi-schema/test-qapi.py +++ b/qemu/tests/qapi-schema/test-qapi.py @@ -15,11 +15,42 @@ from pprint import pprint import os import sys -try: - exprs = parse_schema(sys.argv[1]) -except SystemExit: - raise - -pprint(exprs) -pprint(enum_types) -pprint(struct_types) + +class QAPISchemaTestVisitor(QAPISchemaVisitor): + def visit_enum_type(self, name, info, values, prefix): + print 'enum %s %s' % (name, values) + if prefix: + print ' prefix %s' % prefix + + def visit_object_type(self, name, info, base, members, variants): + print 'object %s' % name + if base: + print ' base %s' % base.name + for m in members: + print ' member %s: %s optional=%s' % \ + (m.name, m.type.name, m.optional) + self._print_variants(variants) + + def visit_alternate_type(self, name, info, variants): + print 'alternate %s' % name + self._print_variants(variants) + + def visit_command(self, name, info, arg_type, ret_type, + gen, success_response): + print 'command %s %s -> %s' % \ + (name, arg_type and arg_type.name, ret_type and ret_type.name) + print ' gen=%s success_response=%s' % (gen, success_response) + + def visit_event(self, name, info, arg_type): + print 'event %s %s' % (name, arg_type and arg_type.name) + + @staticmethod + def _print_variants(variants): + if variants: + if variants.tag_name: + print ' tag %s' % variants.tag_name + for v in variants.variants: + print ' case %s: %s' % (v.name, v.type.name) + +schema = QAPISchema(sys.argv[1]) +schema.visit(QAPISchemaTestVisitor()) diff --git a/qemu/tests/qapi-schema/type-bypass-no-gen.err b/qemu/tests/qapi-schema/type-bypass-no-gen.err deleted file mode 100644 index 20cef0a8a..000000000 --- a/qemu/tests/qapi-schema/type-bypass-no-gen.err +++ /dev/null @@ -1 +0,0 @@ -tests/qapi-schema/type-bypass-no-gen.json:2: Member 'arg' of 'data' for command 'unsafe' uses '**' but did not request 'gen':false diff --git a/qemu/tests/qapi-schema/type-bypass-no-gen.json b/qemu/tests/qapi-schema/type-bypass-no-gen.json deleted file mode 100644 index 4feae3719..000000000 --- a/qemu/tests/qapi-schema/type-bypass-no-gen.json +++ /dev/null @@ -1,2 +0,0 @@ -# type bypass only works with 'gen':false -{ 'command': 'unsafe', 'data': { 'arg': '**' }, 'returns': '**' } diff --git a/qemu/tests/qapi-schema/type-bypass.exit b/qemu/tests/qapi-schema/type-bypass.exit deleted file mode 100644 index 573541ac9..000000000 --- a/qemu/tests/qapi-schema/type-bypass.exit +++ /dev/null @@ -1 +0,0 @@ -0 diff --git a/qemu/tests/qapi-schema/type-bypass.json b/qemu/tests/qapi-schema/type-bypass.json deleted file mode 100644 index 48b213783..000000000 --- a/qemu/tests/qapi-schema/type-bypass.json +++ /dev/null @@ -1,2 +0,0 @@ -# Use of 'gen':false allows bypassing type system -{ 'command': 'unsafe', 'data': { 'arg': '**' }, 'returns': '**', 'gen': false } diff --git a/qemu/tests/qapi-schema/type-bypass.out b/qemu/tests/qapi-schema/type-bypass.out deleted file mode 100644 index eaf20f834..000000000 --- a/qemu/tests/qapi-schema/type-bypass.out +++ /dev/null @@ -1,3 +0,0 @@ -[OrderedDict([('command', 'unsafe'), ('data', OrderedDict([('arg', '**')])), ('returns', '**'), ('gen', False)])] -[] -[] diff --git a/qemu/tests/qapi-schema/union-bad-branch.err b/qemu/tests/qapi-schema/union-bad-branch.err deleted file mode 100644 index 882273556..000000000 --- a/qemu/tests/qapi-schema/union-bad-branch.err +++ /dev/null @@ -1 +0,0 @@ -tests/qapi-schema/union-bad-branch.json:6: Union 'MyUnion' member 'ONE' clashes with 'one' diff --git a/qemu/tests/qapi-schema/union-bad-branch.json b/qemu/tests/qapi-schema/union-bad-branch.json deleted file mode 100644 index 913aa38bc..000000000 --- a/qemu/tests/qapi-schema/union-bad-branch.json +++ /dev/null @@ -1,8 +0,0 @@ -# we reject normal unions where branches would collide in C -{ 'struct': 'One', - 'data': { 'string': 'str' } } -{ 'struct': 'Two', - 'data': { 'number': 'int' } } -{ 'union': 'MyUnion', - 'data': { 'one': 'One', - 'ONE': 'Two' } } diff --git a/qemu/tests/qapi-schema/union-base-no-discriminator.err b/qemu/tests/qapi-schema/union-base-no-discriminator.err index fc8b79c45..8b7a24260 100644 --- a/qemu/tests/qapi-schema/union-base-no-discriminator.err +++ b/qemu/tests/qapi-schema/union-base-no-discriminator.err @@ -1 +1 @@ -tests/qapi-schema/union-base-no-discriminator.json:11: Union 'TestUnion' requires a discriminator to go along with base +tests/qapi-schema/union-base-no-discriminator.json:11: Simple union 'TestUnion' must not have a base diff --git a/qemu/tests/qapi-schema/union-branch-case.err b/qemu/tests/qapi-schema/union-branch-case.err new file mode 100644 index 000000000..11521901d --- /dev/null +++ b/qemu/tests/qapi-schema/union-branch-case.err @@ -0,0 +1 @@ +tests/qapi-schema/union-branch-case.json:2: 'Branch' (branch of NoWayThisWillGetWhitelisted) should not use uppercase diff --git a/qemu/tests/qapi-schema/union-branch-case.exit b/qemu/tests/qapi-schema/union-branch-case.exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/qemu/tests/qapi-schema/union-branch-case.exit @@ -0,0 +1 @@ +1 diff --git a/qemu/tests/qapi-schema/union-branch-case.json b/qemu/tests/qapi-schema/union-branch-case.json new file mode 100644 index 000000000..e6565dc3b --- /dev/null +++ b/qemu/tests/qapi-schema/union-branch-case.json @@ -0,0 +1,2 @@ +# Branch names should be 'lower-case' unless the union is whitelisted +{ 'union': 'NoWayThisWillGetWhitelisted', 'data': { 'Branch': 'int' } } diff --git a/qemu/tests/qapi-schema/union-branch-case.out b/qemu/tests/qapi-schema/union-branch-case.out new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/qemu/tests/qapi-schema/union-branch-case.out diff --git a/qemu/tests/qapi-schema/union-clash-branches.err b/qemu/tests/qapi-schema/union-clash-branches.err new file mode 100644 index 000000000..e5b21135b --- /dev/null +++ b/qemu/tests/qapi-schema/union-clash-branches.err @@ -0,0 +1 @@ +tests/qapi-schema/union-clash-branches.json:4: 'a_b' (branch of TestUnion) collides with 'a-b' (branch of TestUnion) diff --git a/qemu/tests/qapi-schema/union-clash-branches.exit b/qemu/tests/qapi-schema/union-clash-branches.exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/qemu/tests/qapi-schema/union-clash-branches.exit @@ -0,0 +1 @@ +1 diff --git a/qemu/tests/qapi-schema/union-clash-branches.json b/qemu/tests/qapi-schema/union-clash-branches.json new file mode 100644 index 000000000..3bece8c94 --- /dev/null +++ b/qemu/tests/qapi-schema/union-clash-branches.json @@ -0,0 +1,5 @@ +# Union branch name collision +# Reject a union that would result in a collision in generated C names (this +# would try to generate two members 'a_b'). +{ 'union': 'TestUnion', + 'data': { 'a-b': 'int', 'a_b': 'str' } } diff --git a/qemu/tests/qapi-schema/union-clash-branches.out b/qemu/tests/qapi-schema/union-clash-branches.out new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/qemu/tests/qapi-schema/union-clash-branches.out diff --git a/qemu/tests/qapi-schema/union-empty.err b/qemu/tests/qapi-schema/union-empty.err new file mode 100644 index 000000000..12c20221b --- /dev/null +++ b/qemu/tests/qapi-schema/union-empty.err @@ -0,0 +1 @@ +tests/qapi-schema/union-empty.json:2: Union 'Union' cannot have empty 'data' diff --git a/qemu/tests/qapi-schema/union-empty.exit b/qemu/tests/qapi-schema/union-empty.exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/qemu/tests/qapi-schema/union-empty.exit @@ -0,0 +1 @@ +1 diff --git a/qemu/tests/qapi-schema/union-empty.json b/qemu/tests/qapi-schema/union-empty.json new file mode 100644 index 000000000..1f0b13ca2 --- /dev/null +++ b/qemu/tests/qapi-schema/union-empty.json @@ -0,0 +1,2 @@ +# unions cannot be empty +{ 'union': 'Union', 'data': { } } diff --git a/qemu/tests/qapi-schema/union-empty.out b/qemu/tests/qapi-schema/union-empty.out new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/qemu/tests/qapi-schema/union-empty.out diff --git a/qemu/tests/qapi-schema/union-invalid-base.err b/qemu/tests/qapi-schema/union-invalid-base.err index 9f637963e..03d7b97a9 100644 --- a/qemu/tests/qapi-schema/union-invalid-base.err +++ b/qemu/tests/qapi-schema/union-invalid-base.err @@ -1 +1 @@ -tests/qapi-schema/union-invalid-base.json:8: Base 'int' is not a valid struct +tests/qapi-schema/union-invalid-base.json:8: 'base' for union 'TestUnion' cannot use built-in type 'int' diff --git a/qemu/tests/qapi-schema/union-max.err b/qemu/tests/qapi-schema/union-max.err deleted file mode 100644 index 55ce4399d..000000000 --- a/qemu/tests/qapi-schema/union-max.err +++ /dev/null @@ -1 +0,0 @@ -tests/qapi-schema/union-max.json:2: Union 'Union' member 'max' clashes with '(automatic)' diff --git a/qemu/tests/qapi-schema/union-max.json b/qemu/tests/qapi-schema/union-max.json deleted file mode 100644 index d6ad98699..000000000 --- a/qemu/tests/qapi-schema/union-max.json +++ /dev/null @@ -1,3 +0,0 @@ -# we reject 'max' branch in a union, for collision with C enum -{ 'union': 'Union', - 'data': { 'max': 'int' } } diff --git a/qemu/tests/qemu-iotests/001 b/qemu/tests/qemu-iotests/001 index 4e1646941..ffd14e2ce 100755 --- a/qemu/tests/qemu-iotests/001 +++ b/qemu/tests/qemu-iotests/001 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/002 b/qemu/tests/qemu-iotests/002 index 6a865aac7..d4f8e91b9 100755 --- a/qemu/tests/qemu-iotests/002 +++ b/qemu/tests/qemu-iotests/002 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/003 b/qemu/tests/qemu-iotests/003 index 98638d4ce..19889b9fc 100755 --- a/qemu/tests/qemu-iotests/003 +++ b/qemu/tests/qemu-iotests/003 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/004 b/qemu/tests/qemu-iotests/004 index 2ad77ed51..67e1beb20 100755 --- a/qemu/tests/qemu-iotests/004 +++ b/qemu/tests/qemu-iotests/004 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/005 b/qemu/tests/qemu-iotests/005 index ba1236dfb..444737751 100755 --- a/qemu/tests/qemu-iotests/005 +++ b/qemu/tests/qemu-iotests/005 @@ -28,7 +28,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/007 b/qemu/tests/qemu-iotests/007 index 7b5aff59b..fa543eeb7 100755 --- a/qemu/tests/qemu-iotests/007 +++ b/qemu/tests/qemu-iotests/007 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/008 b/qemu/tests/qemu-iotests/008 index 2d28efd42..8e89d74fe 100755 --- a/qemu/tests/qemu-iotests/008 +++ b/qemu/tests/qemu-iotests/008 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/009 b/qemu/tests/qemu-iotests/009 index 57a43f5a1..16e4475ca 100755 --- a/qemu/tests/qemu-iotests/009 +++ b/qemu/tests/qemu-iotests/009 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/010 b/qemu/tests/qemu-iotests/010 index 896a0058f..151dac238 100755 --- a/qemu/tests/qemu-iotests/010 +++ b/qemu/tests/qemu-iotests/010 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/011 b/qemu/tests/qemu-iotests/011 index 1c5158af4..f8d044ec8 100755 --- a/qemu/tests/qemu-iotests/011 +++ b/qemu/tests/qemu-iotests/011 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/012 b/qemu/tests/qemu-iotests/012 index 7c5b6892d..d1d3f2209 100755 --- a/qemu/tests/qemu-iotests/012 +++ b/qemu/tests/qemu-iotests/012 @@ -27,7 +27,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/013 b/qemu/tests/qemu-iotests/013 index ea3cab91d..d013f87da 100755 --- a/qemu/tests/qemu-iotests/013 +++ b/qemu/tests/qemu-iotests/013 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/014 b/qemu/tests/qemu-iotests/014 index b23c2db9b..2ea79e8c8 100755 --- a/qemu/tests/qemu-iotests/014 +++ b/qemu/tests/qemu-iotests/014 @@ -27,7 +27,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/015 b/qemu/tests/qemu-iotests/015 index 6f2609524..aaf9c3f41 100755 --- a/qemu/tests/qemu-iotests/015 +++ b/qemu/tests/qemu-iotests/015 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/017 b/qemu/tests/qemu-iotests/017 index 3af3cdfbc..e3f9e7596 100755 --- a/qemu/tests/qemu-iotests/017 +++ b/qemu/tests/qemu-iotests/017 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/017.out b/qemu/tests/qemu-iotests/017.out index 7c409fc5b..8fc924194 100644 --- a/qemu/tests/qemu-iotests/017.out +++ b/qemu/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/qemu/tests/qemu-iotests/018 b/qemu/tests/qemu-iotests/018 index d8a7d435a..1d39d35c4 100755 --- a/qemu/tests/qemu-iotests/018 +++ b/qemu/tests/qemu-iotests/018 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() @@ -66,8 +65,8 @@ _check_test_img echo "Creating test image with backing file" echo -TEST_IMG=$TEST_IMG_SAVE -_make_test_img -b "$TEST_IMG.base" 6G +TEST_IMG="$TEST_IMG_SAVE.orig" +_make_test_img -b "$TEST_IMG_SAVE.base" 6G echo "Filling test image" echo @@ -81,8 +80,8 @@ for offset in $TEST_OFFSETS; do done _check_test_img -mv "$TEST_IMG" "$TEST_IMG.orig" -$QEMU_IMG convert -O $IMGFMT "$TEST_IMG.orig" "$TEST_IMG" +TEST_IMG="$TEST_IMG_SAVE" +$QEMU_IMG convert -f $IMGFMT -O $IMGFMT "$TEST_IMG.orig" "$TEST_IMG" echo "Reading" echo diff --git a/qemu/tests/qemu-iotests/018.out b/qemu/tests/qemu-iotests/018.out index 39a6011d2..5df966727 100644 --- a/qemu/tests/qemu-iotests/018.out +++ b/qemu/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.orig', fmt=IMGFMT size=6442450944 backing_file=TEST_DIR/t.IMGFMT.base Filling test image === IO: pattern 1 diff --git a/qemu/tests/qemu-iotests/019 b/qemu/tests/qemu-iotests/019 index f5ecbf545..24a789a25 100755 --- a/qemu/tests/qemu-iotests/019 +++ b/qemu/tests/qemu-iotests/019 @@ -27,7 +27,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() @@ -54,6 +53,9 @@ _unsupported_imgopts "subformat=monolithicFlat" \ TEST_OFFSETS="0 4294967296" CLUSTER_SIZE=65536 +TEST_IMG_SAVE="$TEST_IMG" +TEST_IMG="$TEST_IMG.base" + _make_test_img 6G echo "Filling base image" @@ -71,8 +73,8 @@ _check_test_img echo "Creating test image with backing file" echo -mv "$TEST_IMG" "$TEST_IMG.base" -_make_test_img -b "$TEST_IMG.base" 6G +TEST_IMG="$TEST_IMG_SAVE.orig" +_make_test_img -b "$TEST_IMG_SAVE.base" 6G echo "Filling test image" echo @@ -86,9 +88,7 @@ for offset in $TEST_OFFSETS; do done _check_test_img -mv "$TEST_IMG" "$TEST_IMG.orig" - - +TEST_IMG="$TEST_IMG_SAVE" # Test the conversion twice: One test with the old-style -B option and another # one with -o backing_file @@ -98,7 +98,7 @@ for backing_option in "-B " "-o backing_file="; do echo echo Testing conversion with $backing_option"$TEST_IMG.base" | _filter_testdir | _filter_imgfmt echo - $QEMU_IMG convert -O $IMGFMT $backing_option"$TEST_IMG.base" "$TEST_IMG.orig" "$TEST_IMG" + $QEMU_IMG convert -f $IMGFMT -O $IMGFMT $backing_option"$TEST_IMG.base" "$TEST_IMG.orig" "$TEST_IMG" echo "Checking if backing clusters are allocated when they shouldn't" echo diff --git a/qemu/tests/qemu-iotests/019.out b/qemu/tests/qemu-iotests/019.out index 4695b972d..012426497 100644 --- a/qemu/tests/qemu-iotests/019.out +++ b/qemu/tests/qemu-iotests/019.out @@ -1,5 +1,5 @@ QA output created by 019 -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 +Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=6442450944 Filling base image === IO: pattern 42 @@ -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.orig', fmt=IMGFMT size=6442450944 backing_file=TEST_DIR/t.IMGFMT.base Filling test image === IO: pattern 43 diff --git a/qemu/tests/qemu-iotests/020 b/qemu/tests/qemu-iotests/020 index 2f258dc6e..9c4a68c97 100755 --- a/qemu/tests/qemu-iotests/020 +++ b/qemu/tests/qemu-iotests/020 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() @@ -56,6 +55,9 @@ fi TEST_OFFSETS="0 4294967296" +TEST_IMG_SAVE="$TEST_IMG" +TEST_IMG="$TEST_IMG.base" + _make_test_img 6G echo "Filling base image" @@ -73,7 +75,7 @@ _check_test_img echo "Creating test image with backing file" echo -mv "$TEST_IMG" "$TEST_IMG.base" +TEST_IMG="$TEST_IMG_SAVE" _make_test_img -b "$TEST_IMG.base" 6G echo "Filling test image" @@ -89,7 +91,7 @@ done _check_test_img $QEMU_IMG commit "$TEST_IMG" -mv "$TEST_IMG.base" "$TEST_IMG" +TEST_IMG="$TEST_IMG.base" echo "Reading from the backing file" echo diff --git a/qemu/tests/qemu-iotests/020.out b/qemu/tests/qemu-iotests/020.out index 71aab1c74..42f6c1b15 100644 --- a/qemu/tests/qemu-iotests/020.out +++ b/qemu/tests/qemu-iotests/020.out @@ -1,5 +1,5 @@ QA output created by 020 -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 +Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=6442450944 Filling base image === IO: pattern 0 @@ -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/qemu/tests/qemu-iotests/021 b/qemu/tests/qemu-iotests/021 index 1c69024cc..11e8ed718 100755 --- a/qemu/tests/qemu-iotests/021 +++ b/qemu/tests/qemu-iotests/021 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/022 b/qemu/tests/qemu-iotests/022 index d35b8162b..2452a9f86 100755 --- a/qemu/tests/qemu-iotests/022 +++ b/qemu/tests/qemu-iotests/022 @@ -27,7 +27,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/023 b/qemu/tests/qemu-iotests/023 index 9ad06b990..497ae1ed1 100755 --- a/qemu/tests/qemu-iotests/023 +++ b/qemu/tests/qemu-iotests/023 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/024 b/qemu/tests/qemu-iotests/024 index 9bf99e198..e0d77ce2f 100755 --- a/qemu/tests/qemu-iotests/024 +++ b/qemu/tests/qemu-iotests/024 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() @@ -60,16 +59,22 @@ CLUSTER_SIZE=65536 echo "Creating backing file" echo +TEST_IMG_SAVE="$TEST_IMG" +TEST_IMG="$TEST_IMG.base_old" + _make_test_img 1G io_pattern writev 0 $CLUSTER_SIZE $((2 * CLUSTER_SIZE)) 8 0x11 -mv "$TEST_IMG" "$TEST_IMG.base_old" + +TEST_IMG="$TEST_IMG_SAVE.base_new" echo "Creating new backing file" echo _make_test_img 1G io_pattern writev 0 $((2 * CLUSTER_SIZE)) $((4 * CLUSTER_SIZE)) 4 0x22 -mv "$TEST_IMG" "$TEST_IMG.base_new" + + +TEST_IMG="$TEST_IMG_SAVE" echo "Creating COW image" echo diff --git a/qemu/tests/qemu-iotests/024.out b/qemu/tests/qemu-iotests/024.out index 521d46942..33cfaf5cf 100644 --- a/qemu/tests/qemu-iotests/024.out +++ b/qemu/tests/qemu-iotests/024.out @@ -1,7 +1,7 @@ QA output created by 024 Creating backing file -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 +Formatting 'TEST_DIR/t.IMGFMT.base_old', fmt=IMGFMT size=1073741824 === IO: pattern 0x11 wrote 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -21,7 +21,7 @@ wrote 65536/65536 bytes at offset 917504 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) Creating new backing file -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 +Formatting 'TEST_DIR/t.IMGFMT.base_new', fmt=IMGFMT size=1073741824 === IO: pattern 0x22 wrote 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -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/qemu/tests/qemu-iotests/025 b/qemu/tests/qemu-iotests/025 index 467a4b709..c41370f3b 100755 --- a/qemu/tests/qemu-iotests/025 +++ b/qemu/tests/qemu-iotests/025 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/026 b/qemu/tests/qemu-iotests/026 index 0fc3244c7..f5a7f02b2 100755 --- a/qemu/tests/qemu-iotests/026 +++ b/qemu/tests/qemu-iotests/026 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() @@ -66,7 +65,7 @@ for event in \ \ l2_load \ l2_update \ - l2_alloc.write \ + l2_alloc_write \ \ write_aio \ \ @@ -126,11 +125,11 @@ CLUSTER_SIZE=512 for event in \ - refblock_alloc.hookup \ - refblock_alloc.write \ - refblock_alloc.write_blocks \ - refblock_alloc.write_table \ - refblock_alloc.switch_table \ + refblock_alloc_hookup \ + refblock_alloc_write \ + refblock_alloc_write_blocks \ + refblock_alloc_write_table \ + refblock_alloc_switch_table \ do @@ -170,9 +169,9 @@ CLUSTER_SIZE=1024 for event in \ - l1_grow.alloc_table \ - l1_grow.write_table \ - l1_grow.activate_table \ + l1_grow_alloc_table \ + l1_grow_write_table \ + l1_grow_activate_table \ do diff --git a/qemu/tests/qemu-iotests/026.out b/qemu/tests/qemu-iotests/026.out index 5e964fb5a..d84d82c11 100644 --- a/qemu/tests/qemu-iotests/026.out +++ b/qemu/tests/qemu-iotests/026.out @@ -195,24 +195,24 @@ write failed: No space left on device This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: l2_alloc.write; errno: 5; imm: off; once: on; write +Event: l2_alloc_write; errno: 5; imm: off; once: on; write write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: l2_alloc.write; errno: 5; imm: off; once: on; write -b +Event: l2_alloc_write; errno: 5; imm: off; once: on; write -b write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: l2_alloc.write; errno: 5; imm: off; once: off; write +Event: l2_alloc_write; errno: 5; imm: off; once: off; write Failed to flush the L2 table cache: Input/output error Failed to flush the refcount block cache: Input/output error write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: l2_alloc.write; errno: 5; imm: off; once: off; write -b +Event: l2_alloc_write; errno: 5; imm: off; once: off; write -b Failed to flush the L2 table cache: Input/output error Failed to flush the refcount block cache: Input/output error write failed: Input/output error @@ -221,24 +221,24 @@ write failed: Input/output error This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: l2_alloc.write; errno: 28; imm: off; once: on; write +Event: l2_alloc_write; errno: 28; imm: off; once: on; write write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: l2_alloc.write; errno: 28; imm: off; once: on; write -b +Event: l2_alloc_write; errno: 28; imm: off; once: on; write -b write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: l2_alloc.write; errno: 28; imm: off; once: off; write +Event: l2_alloc_write; errno: 28; imm: off; once: off; write Failed to flush the L2 table cache: No space left on device Failed to flush the refcount block cache: No space left on device write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: l2_alloc.write; errno: 28; imm: off; once: off; write -b +Event: l2_alloc_write; errno: 28; imm: off; once: off; write -b Failed to flush the L2 table cache: No space left on device Failed to flush the refcount block cache: No space left on device write failed: No space left on device @@ -490,17 +490,17 @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: refblock_alloc.hookup; errno: 28; imm: off; once: on; write +Event: refblock_alloc_hookup; errno: 28; imm: off; once: on; write write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: refblock_alloc.hookup; errno: 28; imm: off; once: on; write -b +Event: refblock_alloc_hookup; errno: 28; imm: off; once: on; write -b write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: refblock_alloc.hookup; errno: 28; imm: off; once: off; write +Event: refblock_alloc_hookup; errno: 28; imm: off; once: off; write Failed to flush the L2 table cache: No space left on device Failed to flush the refcount block cache: No space left on device write failed: No space left on device @@ -509,7 +509,7 @@ write failed: No space left on device This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: refblock_alloc.hookup; errno: 28; imm: off; once: off; write -b +Event: refblock_alloc_hookup; errno: 28; imm: off; once: off; write -b Failed to flush the L2 table cache: No space left on device Failed to flush the refcount block cache: No space left on device write failed: No space left on device @@ -518,41 +518,41 @@ write failed: No space left on device This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: refblock_alloc.write; errno: 28; imm: off; once: on; write +Event: refblock_alloc_write; errno: 28; imm: off; once: on; write write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: refblock_alloc.write; errno: 28; imm: off; once: on; write -b +Event: refblock_alloc_write; errno: 28; imm: off; once: on; write -b write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: refblock_alloc.write; errno: 28; imm: off; once: off; write +Event: refblock_alloc_write; errno: 28; imm: off; once: off; write Failed to flush the L2 table cache: No space left on device Failed to flush the refcount block cache: No space left on device write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: refblock_alloc.write; errno: 28; imm: off; once: off; write -b +Event: refblock_alloc_write; errno: 28; imm: off; once: off; write -b Failed to flush the L2 table cache: No space left on device Failed to flush the refcount block cache: No space left on device write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: refblock_alloc.write_blocks; errno: 28; imm: off; once: on; write +Event: refblock_alloc_write_blocks; errno: 28; imm: off; once: on; write write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: refblock_alloc.write_blocks; errno: 28; imm: off; once: on; write -b +Event: refblock_alloc_write_blocks; errno: 28; imm: off; once: on; write -b write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: refblock_alloc.write_blocks; errno: 28; imm: off; once: off; write +Event: refblock_alloc_write_blocks; errno: 28; imm: off; once: off; write Failed to flush the L2 table cache: No space left on device Failed to flush the refcount block cache: No space left on device write failed: No space left on device @@ -561,7 +561,7 @@ write failed: No space left on device This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: refblock_alloc.write_blocks; errno: 28; imm: off; once: off; write -b +Event: refblock_alloc_write_blocks; errno: 28; imm: off; once: off; write -b Failed to flush the L2 table cache: No space left on device Failed to flush the refcount block cache: No space left on device write failed: No space left on device @@ -570,17 +570,17 @@ write failed: No space left on device This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: refblock_alloc.write_table; errno: 28; imm: off; once: on; write +Event: refblock_alloc_write_table; errno: 28; imm: off; once: on; write write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: refblock_alloc.write_table; errno: 28; imm: off; once: on; write -b +Event: refblock_alloc_write_table; errno: 28; imm: off; once: on; write -b write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: refblock_alloc.write_table; errno: 28; imm: off; once: off; write +Event: refblock_alloc_write_table; errno: 28; imm: off; once: off; write Failed to flush the L2 table cache: No space left on device Failed to flush the refcount block cache: No space left on device write failed: No space left on device @@ -589,7 +589,7 @@ write failed: No space left on device This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: refblock_alloc.write_table; errno: 28; imm: off; once: off; write -b +Event: refblock_alloc_write_table; errno: 28; imm: off; once: off; write -b Failed to flush the L2 table cache: No space left on device Failed to flush the refcount block cache: No space left on device write failed: No space left on device @@ -598,17 +598,17 @@ write failed: No space left on device This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: refblock_alloc.switch_table; errno: 28; imm: off; once: on; write +Event: refblock_alloc_switch_table; errno: 28; imm: off; once: on; write write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: refblock_alloc.switch_table; errno: 28; imm: off; once: on; write -b +Event: refblock_alloc_switch_table; errno: 28; imm: off; once: on; write -b write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: refblock_alloc.switch_table; errno: 28; imm: off; once: off; write +Event: refblock_alloc_switch_table; errno: 28; imm: off; once: off; write Failed to flush the L2 table cache: No space left on device Failed to flush the refcount block cache: No space left on device write failed: No space left on device @@ -617,7 +617,7 @@ write failed: No space left on device This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: refblock_alloc.switch_table; errno: 28; imm: off; once: off; write -b +Event: refblock_alloc_switch_table; errno: 28; imm: off; once: off; write -b Failed to flush the L2 table cache: No space left on device Failed to flush the refcount block cache: No space left on device write failed: No space left on device @@ -629,60 +629,60 @@ This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: l1_grow.alloc_table; errno: 5; imm: off; once: on +Event: l1_grow_alloc_table; errno: 5; imm: off; once: on write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: l1_grow.alloc_table; errno: 5; imm: off; once: off +Event: l1_grow_alloc_table; errno: 5; imm: off; once: off Failed to flush the L2 table cache: Input/output error Failed to flush the refcount block cache: Input/output error write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: l1_grow.alloc_table; errno: 28; imm: off; once: on +Event: l1_grow_alloc_table; errno: 28; imm: off; once: on write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: l1_grow.alloc_table; errno: 28; imm: off; once: off +Event: l1_grow_alloc_table; errno: 28; imm: off; once: off Failed to flush the L2 table cache: No space left on device Failed to flush the refcount block cache: No space left on device write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: l1_grow.write_table; errno: 5; imm: off; once: on +Event: l1_grow_write_table; errno: 5; imm: off; once: on write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: l1_grow.write_table; errno: 5; imm: off; once: off +Event: l1_grow_write_table; errno: 5; imm: off; once: off Failed to flush the L2 table cache: Input/output error Failed to flush the refcount block cache: Input/output error write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: l1_grow.write_table; errno: 28; imm: off; once: on +Event: l1_grow_write_table; errno: 28; imm: off; once: on write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: l1_grow.write_table; errno: 28; imm: off; once: off +Event: l1_grow_write_table; errno: 28; imm: off; once: off Failed to flush the L2 table cache: No space left on device Failed to flush the refcount block cache: No space left on device write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: l1_grow.activate_table; errno: 5; imm: off; once: on +Event: l1_grow_activate_table; errno: 5; imm: off; once: on write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: l1_grow.activate_table; errno: 5; imm: off; once: off +Event: l1_grow_activate_table; errno: 5; imm: off; once: off Failed to flush the L2 table cache: Input/output error Failed to flush the refcount block cache: Input/output error write failed: Input/output error @@ -691,12 +691,12 @@ write failed: Input/output error This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: l1_grow.activate_table; errno: 28; imm: off; once: on +Event: l1_grow_activate_table; errno: 28; imm: off; once: on write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: l1_grow.activate_table; errno: 28; imm: off; once: off +Event: l1_grow_activate_table; errno: 28; imm: off; once: off Failed to flush the L2 table cache: No space left on device Failed to flush the refcount block cache: No space left on device write failed: No space left on device diff --git a/qemu/tests/qemu-iotests/026.out.nocache b/qemu/tests/qemu-iotests/026.out.nocache index c9d242e9e..9c2c8a948 100644 --- a/qemu/tests/qemu-iotests/026.out.nocache +++ b/qemu/tests/qemu-iotests/026.out.nocache @@ -14,6 +14,8 @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l1_update; errno: 5; imm: off; once: off; write +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error write failed: Input/output error 1 leaked clusters were found on the image. @@ -21,6 +23,8 @@ This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l1_update; errno: 5; imm: off; once: off; write -b +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error write failed: Input/output error 1 leaked clusters were found on the image. @@ -38,6 +42,8 @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l1_update; errno: 28; imm: off; once: off; write +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device 1 leaked clusters were found on the image. @@ -45,6 +51,8 @@ This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l1_update; errno: 28; imm: off; once: off; write -b +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device 1 leaked clusters were found on the image. @@ -70,7 +78,11 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_load; errno: 5; imm: off; once: off; write wrote 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error write failed: Input/output error +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error read failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 @@ -78,7 +90,11 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_load; errno: 5; imm: off; once: off; write -b wrote 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error write failed: Input/output error +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error read failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 @@ -102,7 +118,11 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_load; errno: 28; imm: off; once: off; write wrote 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device read failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 @@ -110,7 +130,11 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_load; errno: 28; imm: off; once: off; write -b wrote 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device read failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 @@ -118,20 +142,18 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_update; errno: 5; imm: off; once: on; write wrote 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - -127 leaked clusters were found on the image. -This means waste of disk space, but no harm to data. -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 +No errors were found on the image. +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_update; errno: 5; imm: off; once: on; write -b wrote 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - -127 leaked clusters were found on the image. -This means waste of disk space, but no harm to data. -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 +No errors were found on the image. +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_update; errno: 5; imm: off; once: off; write +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error wrote 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -140,6 +162,8 @@ This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_update; errno: 5; imm: off; once: off; write -b +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error wrote 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -150,20 +174,18 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_update; errno: 28; imm: off; once: on; write wrote 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - -127 leaked clusters were found on the image. -This means waste of disk space, but no harm to data. -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 +No errors were found on the image. +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_update; errno: 28; imm: off; once: on; write -b wrote 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) - -127 leaked clusters were found on the image. -This means waste of disk space, but no harm to data. -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 +No errors were found on the image. +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_update; errno: 28; imm: off; once: off; write +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device wrote 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -172,6 +194,8 @@ This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: l2_update; errno: 28; imm: off; once: off; write -b +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device wrote 131072/131072 bytes at offset 0 128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -179,44 +203,52 @@ wrote 131072/131072 bytes at offset 0 This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: l2_alloc.write; errno: 5; imm: off; once: on; write +Event: l2_alloc_write; errno: 5; imm: off; once: on; write write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: l2_alloc.write; errno: 5; imm: off; once: on; write -b +Event: l2_alloc_write; errno: 5; imm: off; once: on; write -b write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: l2_alloc.write; errno: 5; imm: off; once: off; write +Event: l2_alloc_write; errno: 5; imm: off; once: off; write +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: l2_alloc.write; errno: 5; imm: off; once: off; write -b +Event: l2_alloc_write; errno: 5; imm: off; once: off; write -b +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error write failed: Input/output error 1 leaked clusters were found on the image. This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: l2_alloc.write; errno: 28; imm: off; once: on; write +Event: l2_alloc_write; errno: 28; imm: off; once: on; write write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: l2_alloc.write; errno: 28; imm: off; once: on; write -b +Event: l2_alloc_write; errno: 28; imm: off; once: on; write -b write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: l2_alloc.write; errno: 28; imm: off; once: off; write +Event: l2_alloc_write; errno: 28; imm: off; once: off; write +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: l2_alloc.write; errno: 28; imm: off; once: off; write -b +Event: l2_alloc_write; errno: 28; imm: off; once: off; write -b +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device 1 leaked clusters were found on the image. @@ -234,11 +266,15 @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: write_aio; errno: 5; imm: off; once: off; write +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: write_aio; errno: 5; imm: off; once: off; write -b +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 @@ -254,11 +290,15 @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: write_aio; errno: 28; imm: off; once: off; write +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: write_aio; errno: 28; imm: off; once: off; write -b +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 @@ -274,11 +314,15 @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_load; errno: 5; imm: off; once: off; write +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_load; errno: 5; imm: off; once: off; write -b +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 @@ -294,11 +338,15 @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_load; errno: 28; imm: off; once: off; write +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_load; errno: 28; imm: off; once: off; write -b +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 @@ -314,11 +362,15 @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_update_part; errno: 5; imm: off; once: off; write +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_update_part; errno: 5; imm: off; once: off; write -b +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 @@ -334,11 +386,15 @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_update_part; errno: 28; imm: off; once: off; write +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_update_part; errno: 28; imm: off; once: off; write -b +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 @@ -354,11 +410,15 @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc; errno: 5; imm: off; once: off; write +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc; errno: 5; imm: off; once: off; write -b +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 @@ -374,11 +434,15 @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc; errno: 28; imm: off; once: off; write +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: refblock_alloc; errno: 28; imm: off; once: off; write -b +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 @@ -394,11 +458,15 @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: cluster_alloc; errno: 5; imm: off; once: off; write +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: cluster_alloc; errno: 5; imm: off; once: off; write -b +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 @@ -414,11 +482,15 @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: cluster_alloc; errno: 28; imm: off; once: off; write +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 Event: cluster_alloc; errno: 28; imm: off; once: off; write -b +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device No errors were found on the image. @@ -426,116 +498,136 @@ No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: refblock_alloc.hookup; errno: 28; imm: off; once: on; write +Event: refblock_alloc_hookup; errno: 28; imm: off; once: on; write write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: refblock_alloc.hookup; errno: 28; imm: off; once: on; write -b +Event: refblock_alloc_hookup; errno: 28; imm: off; once: on; write -b write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: refblock_alloc.hookup; errno: 28; imm: off; once: off; write +Event: refblock_alloc_hookup; errno: 28; imm: off; once: off; write +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device 55 leaked clusters were found on the image. This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: refblock_alloc.hookup; errno: 28; imm: off; once: off; write -b +Event: refblock_alloc_hookup; errno: 28; imm: off; once: off; write -b +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device 251 leaked clusters were found on the image. This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: refblock_alloc.write; errno: 28; imm: off; once: on; write +Event: refblock_alloc_write; errno: 28; imm: off; once: on; write write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: refblock_alloc.write; errno: 28; imm: off; once: on; write -b +Event: refblock_alloc_write; errno: 28; imm: off; once: on; write -b write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: refblock_alloc.write; errno: 28; imm: off; once: off; write +Event: refblock_alloc_write; errno: 28; imm: off; once: off; write +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: refblock_alloc.write; errno: 28; imm: off; once: off; write -b +Event: refblock_alloc_write; errno: 28; imm: off; once: off; write -b +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: refblock_alloc.write_blocks; errno: 28; imm: off; once: on; write +Event: refblock_alloc_write_blocks; errno: 28; imm: off; once: on; write write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: refblock_alloc.write_blocks; errno: 28; imm: off; once: on; write -b +Event: refblock_alloc_write_blocks; errno: 28; imm: off; once: on; write -b write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: refblock_alloc.write_blocks; errno: 28; imm: off; once: off; write +Event: refblock_alloc_write_blocks; errno: 28; imm: off; once: off; write +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device -10 leaked clusters were found on the image. +11 leaked clusters were found on the image. This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: refblock_alloc.write_blocks; errno: 28; imm: off; once: off; write -b +Event: refblock_alloc_write_blocks; errno: 28; imm: off; once: off; write -b +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device 23 leaked clusters were found on the image. This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: refblock_alloc.write_table; errno: 28; imm: off; once: on; write +Event: refblock_alloc_write_table; errno: 28; imm: off; once: on; write write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: refblock_alloc.write_table; errno: 28; imm: off; once: on; write -b +Event: refblock_alloc_write_table; errno: 28; imm: off; once: on; write -b write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: refblock_alloc.write_table; errno: 28; imm: off; once: off; write +Event: refblock_alloc_write_table; errno: 28; imm: off; once: off; write +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device -10 leaked clusters were found on the image. +11 leaked clusters were found on the image. This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: refblock_alloc.write_table; errno: 28; imm: off; once: off; write -b +Event: refblock_alloc_write_table; errno: 28; imm: off; once: off; write -b +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device 23 leaked clusters were found on the image. This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: refblock_alloc.switch_table; errno: 28; imm: off; once: on; write +Event: refblock_alloc_switch_table; errno: 28; imm: off; once: on; write write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: refblock_alloc.switch_table; errno: 28; imm: off; once: on; write -b +Event: refblock_alloc_switch_table; errno: 28; imm: off; once: on; write -b write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: refblock_alloc.switch_table; errno: 28; imm: off; once: off; write +Event: refblock_alloc_switch_table; errno: 28; imm: off; once: off; write +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device -10 leaked clusters were found on the image. +11 leaked clusters were found on the image. This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: refblock_alloc.switch_table; errno: 28; imm: off; once: off; write -b +Event: refblock_alloc_switch_table; errno: 28; imm: off; once: off; write -b +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device 23 leaked clusters were found on the image. @@ -545,64 +637,76 @@ This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: l1_grow.alloc_table; errno: 5; imm: off; once: on +Event: l1_grow_alloc_table; errno: 5; imm: off; once: on write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: l1_grow.alloc_table; errno: 5; imm: off; once: off +Event: l1_grow_alloc_table; errno: 5; imm: off; once: off +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: l1_grow.alloc_table; errno: 28; imm: off; once: on +Event: l1_grow_alloc_table; errno: 28; imm: off; once: on write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: l1_grow.alloc_table; errno: 28; imm: off; once: off +Event: l1_grow_alloc_table; errno: 28; imm: off; once: off +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: l1_grow.write_table; errno: 5; imm: off; once: on +Event: l1_grow_write_table; errno: 5; imm: off; once: on write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: l1_grow.write_table; errno: 5; imm: off; once: off +Event: l1_grow_write_table; errno: 5; imm: off; once: off +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: l1_grow.write_table; errno: 28; imm: off; once: on +Event: l1_grow_write_table; errno: 28; imm: off; once: on write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: l1_grow.write_table; errno: 28; imm: off; once: off +Event: l1_grow_write_table; errno: 28; imm: off; once: off +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: l1_grow.activate_table; errno: 5; imm: off; once: on +Event: l1_grow_activate_table; errno: 5; imm: off; once: on write failed: Input/output error No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: l1_grow.activate_table; errno: 5; imm: off; once: off +Event: l1_grow_activate_table; errno: 5; imm: off; once: off +Failed to flush the L2 table cache: Input/output error +Failed to flush the refcount block cache: Input/output error write failed: Input/output error 96 leaked clusters were found on the image. This means waste of disk space, but no harm to data. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: l1_grow.activate_table; errno: 28; imm: off; once: on +Event: l1_grow_activate_table; errno: 28; imm: off; once: on write failed: No space left on device No errors were found on the image. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 -Event: l1_grow.activate_table; errno: 28; imm: off; once: off +Event: l1_grow_activate_table; errno: 28; imm: off; once: off +Failed to flush the L2 table cache: No space left on device +Failed to flush the refcount block cache: No space left on device write failed: No space left on device 96 leaked clusters were found on the image. diff --git a/qemu/tests/qemu-iotests/027 b/qemu/tests/qemu-iotests/027 index 3fa81b83b..08593da77 100755 --- a/qemu/tests/qemu-iotests/027 +++ b/qemu/tests/qemu-iotests/027 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/028 b/qemu/tests/qemu-iotests/028 index a1f4423d4..7783e57c7 100755 --- a/qemu/tests/qemu-iotests/028 +++ b/qemu/tests/qemu-iotests/028 @@ -28,7 +28,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() @@ -60,6 +59,9 @@ base_size=$(( image_size - 1024 * 1024 * 1024 )) offset=$(( base_size - 32 * 1024 )) +TEST_IMG_SAVE="$TEST_IMG" +TEST_IMG="$TEST_IMG.base" + _make_test_img $base_size echo "Filling base image" @@ -73,7 +75,7 @@ _check_test_img echo "Creating test image with backing file" echo -mv "$TEST_IMG" "$TEST_IMG.base" +TEST_IMG="$TEST_IMG_SAVE" _make_test_img -b "$TEST_IMG.base" $image_size echo "Filling test image" @@ -111,10 +113,12 @@ h=$QEMU_HANDLE QEMU_COMM_TIMEOUT=1 # Silence output since it contains the disk image path and QEMU's readline -# character echoing makes it very hard to filter the output +# character echoing makes it very hard to filter the output. Plus, there +# is no telling how many times the command will repeat before succeeding. _send_qemu_cmd $h "drive_backup disk ${TEST_IMG}.copy" "(qemu)" >/dev/null _send_qemu_cmd $h "" "Formatting" | _filter_img_create -qemu_cmd_repeat=20 _send_qemu_cmd $h "info block-jobs" "No active jobs" +qemu_cmd_repeat=20 _send_qemu_cmd $h "info block-jobs" "No active jobs" >/dev/null +_send_qemu_cmd $h "info block-jobs" "No active jobs" _send_qemu_cmd $h 'quit' "" # Base image sectors diff --git a/qemu/tests/qemu-iotests/028.out b/qemu/tests/qemu-iotests/028.out index 5db167ce7..acd2870ba 100644 --- a/qemu/tests/qemu-iotests/028.out +++ b/qemu/tests/qemu-iotests/028.out @@ -1,5 +1,5 @@ QA output created by 028 -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=3221227008 +Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=3221227008 Filling base image === IO: pattern 195 @@ -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,11 +468,8 @@ 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' -(qemu) +Formatting 'TEST_DIR/t.IMGFMT.copy', fmt=IMGFMT size=4294968832 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT (qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K[D[D[D[D[D[D[D[D[D[Dinfo block-[K[D[D[D[D[D[D[D[D[D[D[Dinfo block-j[K[D[D[D[D[D[D[D[D[D[D[D[Dinfo block-jo[K[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block-job[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block-jobs[K -Type backup, device disk: Completed 0 of 4294968832 bytes, speed limit 0 bytes/s -i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K[D[D[D[D[D[D[D[D[D[Dinfo block-[K[D[D[D[D[D[D[D[D[D[D[Dinfo block-j[K[D[D[D[D[D[D[D[D[D[D[D[Dinfo block-jo[K[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block-job[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block-jobs[K No active jobs === IO: pattern 195 read 512/512 bytes at offset 3221194240 diff --git a/qemu/tests/qemu-iotests/029 b/qemu/tests/qemu-iotests/029 index b9cd826c7..e639ac0dd 100755 --- a/qemu/tests/qemu-iotests/029 +++ b/qemu/tests/qemu-iotests/029 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/030 b/qemu/tests/qemu-iotests/030 index 952a524ec..3ac2443e5 100755 --- a/qemu/tests/qemu-iotests/030 +++ b/qemu/tests/qemu-iotests/030 @@ -35,6 +35,7 @@ class TestSingleDrive(iotests.QMPTestCase): qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, mid_img) qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % mid_img, test_img) qemu_io('-f', 'raw', '-c', 'write -P 0x1 0 512', backing_img) + qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0x1 524288 512', mid_img) self.vm = iotests.VM().add_drive("blkdebug::" + test_img) self.vm.launch() @@ -90,9 +91,13 @@ class TestSingleDrive(iotests.QMPTestCase): qemu_io('-f', iotests.imgfmt, '-c', 'map', test_img), 'image file map does not match backing file after streaming') - def test_stream_partial(self): + def test_stream_no_op(self): self.assert_no_active_block_jobs() + # The image map is empty before the operation + empty_map = qemu_io('-f', iotests.imgfmt, '-c', 'map', test_img) + + # This is a no-op: no data should ever be copied from the base image result = self.vm.qmp('block-stream', device='drive0', base=mid_img) self.assert_qmp(result, 'return', {}) @@ -101,6 +106,20 @@ class TestSingleDrive(iotests.QMPTestCase): self.assert_no_active_block_jobs() self.vm.shutdown() + self.assertEqual(qemu_io('-f', iotests.imgfmt, '-c', 'map', test_img), + empty_map, 'image file map changed after a no-op') + + def test_stream_partial(self): + self.assert_no_active_block_jobs() + + result = self.vm.qmp('block-stream', device='drive0', base=backing_img) + self.assert_qmp(result, 'return', {}) + + self.wait_until_completed() + + self.assert_no_active_block_jobs() + self.vm.shutdown() + self.assertEqual(qemu_io('-f', iotests.imgfmt, '-c', 'map', mid_img), qemu_io('-f', iotests.imgfmt, '-c', 'map', test_img), 'image file map does not match backing file after streaming') @@ -245,6 +264,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 +277,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/qemu/tests/qemu-iotests/030.out b/qemu/tests/qemu-iotests/030.out index fa16b5cce..6323079e0 100644 --- a/qemu/tests/qemu-iotests/030.out +++ b/qemu/tests/qemu-iotests/030.out @@ -1,5 +1,5 @@ -............. +.............. ---------------------------------------------------------------------- -Ran 13 tests +Ran 14 tests OK diff --git a/qemu/tests/qemu-iotests/031 b/qemu/tests/qemu-iotests/031 index 2a77ba8cb..1e08abc5e 100755 --- a/qemu/tests/qemu-iotests/031 +++ b/qemu/tests/qemu-iotests/031 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/031.out b/qemu/tests/qemu-iotests/031.out index fce3ce098..7f5050b81 100644 --- a/qemu/tests/qemu-iotests/031.out +++ b/qemu/tests/qemu-iotests/031.out @@ -53,11 +53,6 @@ refcount_order 4 header_length 72 Header extension: -magic 0x6803f857 -length 144 -data <binary> - -Header extension: magic 0x12345678 length 31 data 'This is a test header extension' @@ -68,7 +63,7 @@ No errors were found on the image. magic 0x514649fb version 2 -backing_file_offset 0x128 +backing_file_offset 0x90 backing_file_size 0x17 cluster_bits 16 size 67108864 @@ -91,11 +86,6 @@ length 11 data 'host_device' Header extension: -magic 0x6803f857 -length 144 -data <binary> - -Header extension: magic 0x12345678 length 31 data 'This is a test header extension' @@ -126,6 +116,11 @@ refcount_order 4 header_length 104 Header extension: +magic 0x6803f857 +length 144 +data <binary> + +Header extension: magic 0x12345678 length 31 data 'This is a test header extension' diff --git a/qemu/tests/qemu-iotests/032 b/qemu/tests/qemu-iotests/032 index b1ba5c321..24bcb52fc 100755 --- a/qemu/tests/qemu-iotests/032 +++ b/qemu/tests/qemu-iotests/032 @@ -27,7 +27,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/033 b/qemu/tests/qemu-iotests/033 index a61d8ced1..16edcf2f0 100755 --- a/qemu/tests/qemu-iotests/033 +++ b/qemu/tests/qemu-iotests/033 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() @@ -57,12 +56,13 @@ do_test() } | $QEMU_IO } +for write_zero_cmd in "write -z" "aio_write -z"; do for align in 512 4k; do echo echo "== preparing image ==" do_test $align "write -P 0xa 0x200 0x400" "$TEST_IMG" | _filter_qemu_io do_test $align "write -P 0xa 0x20000 0x600" "$TEST_IMG" | _filter_qemu_io - do_test $align "write -z 0x400 0x20000" "$TEST_IMG" | _filter_qemu_io + do_test $align "$write_zero_cmd 0x400 0x20000" "$TEST_IMG" | _filter_qemu_io echo echo "== verifying patterns (1) ==" @@ -73,7 +73,7 @@ for align in 512 4k; do echo echo "== rewriting zeroes ==" do_test $align "write -P 0xb 0x10000 0x10000" "$TEST_IMG" | _filter_qemu_io - do_test $align "write -z 0x10000 0x10000" "$TEST_IMG" | _filter_qemu_io + do_test $align "$write_zero_cmd 0x10000 0x10000" "$TEST_IMG" | _filter_qemu_io echo echo "== verifying patterns (2) ==" @@ -82,7 +82,7 @@ for align in 512 4k; do echo echo "== rewriting unaligned zeroes ==" do_test $align "write -P 0xb 0x0 0x1000" "$TEST_IMG" | _filter_qemu_io - do_test $align "write -z 0x200 0x200" "$TEST_IMG" | _filter_qemu_io + do_test $align "$write_zero_cmd 0x200 0x200" "$TEST_IMG" | _filter_qemu_io echo echo "== verifying patterns (3) ==" @@ -92,6 +92,7 @@ for align in 512 4k; do echo done +done # success, all done echo "*** done" diff --git a/qemu/tests/qemu-iotests/033.out b/qemu/tests/qemu-iotests/033.out index c3d18aa45..95929eff7 100644 --- a/qemu/tests/qemu-iotests/033.out +++ b/qemu/tests/qemu-iotests/033.out @@ -82,4 +82,86 @@ read 512/512 bytes at offset 512 read 3072/3072 bytes at offset 1024 3 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== preparing image == +wrote 1024/1024 bytes at offset 512 +1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 1536/1536 bytes at offset 131072 +1.500 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 131072/131072 bytes at offset 1024 +128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== verifying patterns (1) == +read 512/512 bytes at offset 512 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 131072/131072 bytes at offset 1024 +128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 132096 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== rewriting zeroes == +wrote 65536/65536 bytes at offset 65536 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 65536/65536 bytes at offset 65536 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== verifying patterns (2) == +read 131072/131072 bytes at offset 1024 +128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== rewriting unaligned zeroes == +wrote 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 512/512 bytes at offset 512 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== verifying patterns (3) == +read 512/512 bytes at offset 0 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 512 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 3072/3072 bytes at offset 1024 +3 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + + +== preparing image == +wrote 1024/1024 bytes at offset 512 +1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 1536/1536 bytes at offset 131072 +1.500 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 131072/131072 bytes at offset 1024 +128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== verifying patterns (1) == +read 512/512 bytes at offset 512 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 131072/131072 bytes at offset 1024 +128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 132096 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== rewriting zeroes == +wrote 65536/65536 bytes at offset 65536 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 65536/65536 bytes at offset 65536 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== verifying patterns (2) == +read 131072/131072 bytes at offset 1024 +128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== rewriting unaligned zeroes == +wrote 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 512/512 bytes at offset 512 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +== verifying patterns (3) == +read 512/512 bytes at offset 0 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 512/512 bytes at offset 512 +512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 3072/3072 bytes at offset 1024 +3 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + *** done diff --git a/qemu/tests/qemu-iotests/034 b/qemu/tests/qemu-iotests/034 index 69c785858..c711cfce9 100755 --- a/qemu/tests/qemu-iotests/034 +++ b/qemu/tests/qemu-iotests/034 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() @@ -51,9 +50,13 @@ size=128M echo echo "== creating backing file for COW tests ==" +TEST_IMG_SAVE="$TEST_IMG" +TEST_IMG="$TEST_IMG.base" + _make_test_img $size $QEMU_IO -c "write -P 0x55 0 1M" "$TEST_IMG" | _filter_qemu_io -mv "$TEST_IMG" "$TEST_IMG.base" + +TEST_IMG="$TEST_IMG_SAVE" _make_test_img -b "$TEST_IMG.base" 6G diff --git a/qemu/tests/qemu-iotests/034.out b/qemu/tests/qemu-iotests/034.out index d12daf206..0764ead8b 100644 --- a/qemu/tests/qemu-iotests/034.out +++ b/qemu/tests/qemu-iotests/034.out @@ -1,10 +1,10 @@ QA output created by 034 == creating backing file for COW tests == -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 +Formatting 'TEST_DIR/t.IMGFMT.base', 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/qemu/tests/qemu-iotests/035 b/qemu/tests/qemu-iotests/035 index ebe9b8c92..efc38e4d4 100755 --- a/qemu/tests/qemu-iotests/035 +++ b/qemu/tests/qemu-iotests/035 @@ -26,7 +26,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/036 b/qemu/tests/qemu-iotests/036 index 392f1ef3e..ce638d607 100755 --- a/qemu/tests/qemu-iotests/036 +++ b/qemu/tests/qemu-iotests/036 @@ -28,7 +28,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() @@ -57,6 +56,7 @@ _make_test_img 64M $PYTHON qcow2.py "$TEST_IMG" set-feature-bit incompatible 63 # Without feature table +$PYTHON qcow2.py "$TEST_IMG" del-header-ext 0x6803f857 $PYTHON qcow2.py "$TEST_IMG" dump-header _img_info @@ -73,6 +73,7 @@ $PYTHON qcow2.py "$TEST_IMG" set-feature-bit incompatible 62 $PYTHON qcow2.py "$TEST_IMG" set-feature-bit incompatible 63 # Without feature table +$PYTHON qcow2.py "$TEST_IMG" del-header-ext 0x6803f857 _img_info # With feature table containing bit 63 diff --git a/qemu/tests/qemu-iotests/036.out b/qemu/tests/qemu-iotests/036.out index 5616e37b3..9b009b8c1 100644 --- a/qemu/tests/qemu-iotests/036.out +++ b/qemu/tests/qemu-iotests/036.out @@ -22,18 +22,18 @@ autoclear_features 0x0 refcount_order 4 header_length 104 -qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'image' uses a IMGFMT feature which is not supported by this qemu version: Unknown incompatible feature: 8000000000000000 -qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'image' uses a IMGFMT feature which is not supported by this qemu version: Test feature +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Unsupported IMGFMT feature(s): Unknown incompatible feature: 8000000000000000 +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Unsupported IMGFMT feature(s): Test feature === Image with multiple incompatible feature bits === Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 -qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'image' uses a IMGFMT feature which is not supported by this qemu version: Unknown incompatible feature: e000000000000000 -qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'image' uses a IMGFMT feature which is not supported by this qemu version: Test feature, Unknown incompatible feature: 6000000000000000 -qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'image' uses a IMGFMT feature which is not supported by this qemu version: Test feature, Unknown incompatible feature: c000000000000000 -qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'image' uses a IMGFMT feature which is not supported by this qemu version: test1, test2, Unknown incompatible feature: 8000000000000000 -qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'image' uses a IMGFMT feature which is not supported by this qemu version: test1, test2, test3 -qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'image' uses a IMGFMT feature which is not supported by this qemu version: test2, Unknown incompatible feature: a000000000000000 +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Unsupported IMGFMT feature(s): Unknown incompatible feature: e000000000000000 +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Unsupported IMGFMT feature(s): Test feature, Unknown incompatible feature: 6000000000000000 +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Unsupported IMGFMT feature(s): Test feature, Unknown incompatible feature: c000000000000000 +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Unsupported IMGFMT feature(s): test1, test2, Unknown incompatible feature: 8000000000000000 +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Unsupported IMGFMT feature(s): test1, test2, test3 +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Unsupported IMGFMT feature(s): test2, Unknown incompatible feature: a000000000000000 === Create image with unknown autoclear feature bit === Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 @@ -56,6 +56,11 @@ autoclear_features 0x8000000000000000 refcount_order 4 header_length 104 +Header extension: +magic 0x6803f857 +length 144 +data <binary> + === Repair image === diff --git a/qemu/tests/qemu-iotests/037 b/qemu/tests/qemu-iotests/037 index 9171d8c8a..c476b823d 100755 --- a/qemu/tests/qemu-iotests/037 +++ b/qemu/tests/qemu-iotests/037 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() @@ -51,6 +50,9 @@ size=128M echo echo "== creating backing file for COW tests ==" +TEST_IMG_SAVE="$TEST_IMG" +TEST_IMG="$TEST_IMG.base" + _make_test_img $size function backing_io() @@ -71,7 +73,7 @@ function backing_io() backing_io 0 256 write | $QEMU_IO "$TEST_IMG" | _filter_qemu_io -mv "$TEST_IMG" "$TEST_IMG.base" +TEST_IMG="$TEST_IMG_SAVE" _make_test_img -b "$TEST_IMG.base" 6G diff --git a/qemu/tests/qemu-iotests/037.out b/qemu/tests/qemu-iotests/037.out index dc40a021a..cd6710c90 100644 --- a/qemu/tests/qemu-iotests/037.out +++ b/qemu/tests/qemu-iotests/037.out @@ -1,7 +1,7 @@ QA output created by 037 == creating backing file for COW tests == -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 +Formatting 'TEST_DIR/t.IMGFMT.base', 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) wrote 512/512 bytes at offset 512 @@ -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/qemu/tests/qemu-iotests/038 b/qemu/tests/qemu-iotests/038 index cfaf00a78..d99a1501d 100755 --- a/qemu/tests/qemu-iotests/038 +++ b/qemu/tests/qemu-iotests/038 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() @@ -48,6 +47,9 @@ size=128M echo echo "== creating backing file for COW tests ==" +TEST_IMG_SAVE="$TEST_IMG" +TEST_IMG="$TEST_IMG.base" + _make_test_img $size function backing_io() @@ -68,7 +70,7 @@ function backing_io() backing_io 0 256 write | $QEMU_IO "$TEST_IMG" | _filter_qemu_io -mv "$TEST_IMG" "$TEST_IMG.base" +TEST_IMG="$TEST_IMG_SAVE" _make_test_img -b "$TEST_IMG.base" 6G diff --git a/qemu/tests/qemu-iotests/038.out b/qemu/tests/qemu-iotests/038.out index e1a7e9441..0bdfb19fa 100644 --- a/qemu/tests/qemu-iotests/038.out +++ b/qemu/tests/qemu-iotests/038.out @@ -1,7 +1,7 @@ QA output created by 038 == creating backing file for COW tests == -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 +Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728 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 65536 @@ -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/qemu/tests/qemu-iotests/039 b/qemu/tests/qemu-iotests/039 index 859705f84..1f4833969 100755 --- a/qemu/tests/qemu-iotests/039 +++ b/qemu/tests/qemu-iotests/039 @@ -28,7 +28,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() @@ -47,13 +46,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 +66,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 +101,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 +119,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 +146,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/qemu/tests/qemu-iotests/039.out b/qemu/tests/qemu-iotests/039.out index d09751f9c..32c884694 100644 --- a/qemu/tests/qemu-iotests/039.out +++ b/qemu/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/qemu/tests/qemu-iotests/040 b/qemu/tests/qemu-iotests/040 index ea2f98e51..5bdaf3d48 100755 --- a/qemu/tests/qemu-iotests/040 +++ b/qemu/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/qemu/tests/qemu-iotests/040.out b/qemu/tests/qemu-iotests/040.out index 42314e9c0..4fd1c2dcd 100644 --- a/qemu/tests/qemu-iotests/040.out +++ b/qemu/tests/qemu-iotests/040.out @@ -1,5 +1,5 @@ -........................ +......................... ---------------------------------------------------------------------- -Ran 24 tests +Ran 25 tests OK diff --git a/qemu/tests/qemu-iotests/041 b/qemu/tests/qemu-iotests/041 index 3d46ed705..b1c542f99 100755 --- a/qemu/tests/qemu-iotests/041 +++ b/qemu/tests/qemu-iotests/041 @@ -34,14 +34,18 @@ quorum_img3 = os.path.join(iotests.test_dir, 'quorum3.img') quorum_repair_img = os.path.join(iotests.test_dir, 'quorum_repair.img') quorum_snapshot_file = os.path.join(iotests.test_dir, 'quorum_snapshot.img') - class TestSingleDrive(iotests.QMPTestCase): image_len = 1 * 1024 * 1024 # MB + qmp_cmd = 'drive-mirror' + qmp_target = target_img + not_found_error = 'DeviceNotFound' def setUp(self): 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): @@ -56,8 +60,8 @@ class TestSingleDrive(iotests.QMPTestCase): def test_complete(self): self.assert_no_active_block_jobs() - result = self.vm.qmp('drive-mirror', device='drive0', sync='full', - target=target_img) + result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full', + target=self.qmp_target) self.assert_qmp(result, 'return', {}) self.complete_and_wait() @@ -70,8 +74,8 @@ class TestSingleDrive(iotests.QMPTestCase): def test_cancel(self): self.assert_no_active_block_jobs() - result = self.vm.qmp('drive-mirror', device='drive0', sync='full', - target=target_img) + result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full', + target=self.qmp_target) self.assert_qmp(result, 'return', {}) self.cancel_and_wait(force=True) @@ -82,8 +86,8 @@ class TestSingleDrive(iotests.QMPTestCase): def test_cancel_after_ready(self): self.assert_no_active_block_jobs() - result = self.vm.qmp('drive-mirror', device='drive0', sync='full', - target=target_img) + result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full', + target=self.qmp_target) self.assert_qmp(result, 'return', {}) self.wait_ready_and_cancel() @@ -96,8 +100,8 @@ class TestSingleDrive(iotests.QMPTestCase): def test_pause(self): self.assert_no_active_block_jobs() - result = self.vm.qmp('drive-mirror', device='drive0', sync='full', - target=target_img) + result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full', + target=self.qmp_target) self.assert_qmp(result, 'return', {}) result = self.vm.qmp('block-job-pause', device='drive0') @@ -123,8 +127,8 @@ class TestSingleDrive(iotests.QMPTestCase): self.assert_no_active_block_jobs() # A small buffer is rounded up automatically - result = self.vm.qmp('drive-mirror', device='drive0', sync='full', - buf_size=4096, target=target_img) + result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full', + buf_size=4096, target=self.qmp_target) self.assert_qmp(result, 'return', {}) self.complete_and_wait() @@ -139,8 +143,8 @@ class TestSingleDrive(iotests.QMPTestCase): qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,size=%d' % (self.image_len, self.image_len), target_img) - result = self.vm.qmp('drive-mirror', device='drive0', sync='full', - buf_size=65536, mode='existing', target=target_img) + result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full', + buf_size=65536, mode='existing', target=self.qmp_target) self.assert_qmp(result, 'return', {}) self.complete_and_wait() @@ -155,8 +159,8 @@ class TestSingleDrive(iotests.QMPTestCase): qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,backing_file=%s' % (self.image_len, backing_img), target_img) - result = self.vm.qmp('drive-mirror', device='drive0', sync='full', - mode='existing', target=target_img) + result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full', + mode='existing', target=self.qmp_target) self.assert_qmp(result, 'return', {}) self.complete_and_wait() @@ -167,30 +171,85 @@ 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) - self.assert_qmp(result, 'error/class', 'GenericError') + if iotests.qemu_default_machine != 'pc': + return + + result = self.vm.qmp(self.qmp_cmd, device='ide1-cd0', sync='full', + target=self.qmp_target) + self.assert_qmp(result, 'error/class', self.not_found_error) def test_image_not_found(self): - result = self.vm.qmp('drive-mirror', device='drive0', sync='full', - mode='existing', target=target_img) + result = self.vm.qmp(self.qmp_cmd, device='drive0', sync='full', + mode='existing', target=self.qmp_target) self.assert_qmp(result, 'error/class', 'GenericError') def test_device_not_found(self): - result = self.vm.qmp('drive-mirror', device='nonexistent', sync='full', - target=target_img) - self.assert_qmp(result, 'error/class', 'DeviceNotFound') + result = self.vm.qmp(self.qmp_cmd, device='nonexistent', sync='full', + target=self.qmp_target) + self.assert_qmp(result, 'error/class', self.not_found_error) + +class TestSingleBlockdev(TestSingleDrive): + qmp_cmd = 'blockdev-mirror' + qmp_target = 'node1' + not_found_error = 'GenericError' + + def setUp(self): + TestSingleDrive.setUp(self) + qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, target_img) + args = {'options': + {'driver': iotests.imgfmt, + 'node-name': self.qmp_target, + 'file': { 'filename': target_img, 'driver': 'file' } } } + result = self.vm.qmp("blockdev-add", **args) + self.assert_qmp(result, 'return', {}) + + test_large_cluster = None + test_image_not_found = None + test_small_buffer2 = None + +class TestBlockdevAttached(iotests.QMPTestCase): + image_len = 1 * 1024 * 1024 # MB + + def setUp(self): + iotests.create_image(backing_img, self.image_len) + qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img) + qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, target_img) + self.vm = iotests.VM().add_drive(test_img) + self.vm.launch() + + def tearDown(self): + self.vm.shutdown() + os.remove(test_img) + os.remove(target_img) + + def test_blockdev_attached(self): + self.assert_no_active_block_jobs() + args = {'options': + {'driver': iotests.imgfmt, + 'id': 'drive1', + 'file': { 'filename': target_img, 'driver': 'file' } } } + result = self.vm.qmp("blockdev-add", **args) + self.assert_qmp(result, 'return', {}) + result = self.vm.qmp('blockdev-mirror', device='drive0', sync='full', + target='drive1') + self.assert_qmp(result, 'error/class', 'GenericError') class TestSingleDriveZeroLength(TestSingleDrive): image_len = 0 test_small_buffer2 = None test_large_cluster = None +class TestSingleBlockdevZeroLength(TestSingleBlockdev): + image_len = 0 + class TestSingleDriveUnalignedLength(TestSingleDrive): image_len = 1025 * 1024 test_small_buffer2 = None test_large_cluster = None +class TestSingleBlockdevUnalignedLength(TestSingleBlockdev): + image_len = 1025 * 1024 + class TestMirrorNoBacking(iotests.QMPTestCase): image_len = 2 * 1024 * 1024 # MB @@ -707,6 +766,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, @@ -748,8 +810,7 @@ class TestRepairQuorum(iotests.QMPTestCase): self.assert_qmp(result, 'return', {}) self.complete_and_wait(drive="quorum0") - result = self.vm.qmp('query-named-block-nodes') - self.assert_qmp(result, 'return[0]/file', quorum_repair_img) + self.assert_has_block_node("repair0", quorum_repair_img) # TODO: a better test requiring some QEMU infrastructure will be added # to check that this file is really driven by quorum self.vm.shutdown() @@ -771,8 +832,7 @@ class TestRepairQuorum(iotests.QMPTestCase): self.cancel_and_wait(drive="quorum0", force=True) # 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_has_block_node(None, quorum_img3) self.vm.shutdown() def test_cancel_after_ready(self): @@ -788,10 +848,9 @@ class TestRepairQuorum(iotests.QMPTestCase): self.assert_qmp(result, 'return', {}) self.wait_ready_and_cancel(drive="quorum0") - 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_has_block_node(None, 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 +890,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 +940,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 @@ -908,8 +971,7 @@ class TestRepairQuorum(iotests.QMPTestCase): self.assert_qmp(result, 'return', {}) self.complete_and_wait(drive="quorum0") - result = self.vm.qmp('query-named-block-nodes') - self.assert_qmp(result, 'return[0]/file', quorum_repair_img) + self.assert_has_block_node("repair0", quorum_repair_img) # TODO: a better test requiring some QEMU infrastructure will be added # to check that this file is really driven by quorum self.vm.shutdown() diff --git a/qemu/tests/qemu-iotests/041.out b/qemu/tests/qemu-iotests/041.out index 24093bc63..b67d0504a 100644 --- a/qemu/tests/qemu-iotests/041.out +++ b/qemu/tests/qemu-iotests/041.out @@ -1,5 +1,5 @@ -...................................................... +............................................................................ ---------------------------------------------------------------------- -Ran 54 tests +Ran 76 tests OK diff --git a/qemu/tests/qemu-iotests/042 b/qemu/tests/qemu-iotests/042 index 94ce3a9cc..351b2830a 100755 --- a/qemu/tests/qemu-iotests/042 +++ b/qemu/tests/qemu-iotests/042 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/043 b/qemu/tests/qemu-iotests/043 index b316b97c0..1c6c22d92 100755 --- a/qemu/tests/qemu-iotests/043 +++ b/qemu/tests/qemu-iotests/043 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/043.out b/qemu/tests/qemu-iotests/043.out index 012cc008e..b37d2a380 100644 --- a/qemu/tests/qemu-iotests/043.out +++ b/qemu/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 @@ -44,6 +44,7 @@ cluster_size: 65536 "filename": "TEST_DIR/t.IMGFMT", "cluster-size": 65536, "format": "IMGFMT", + "full-backing-filename": "TEST_DIR/t.IMGFMT.2.base", "backing-filename": "TEST_DIR/t.IMGFMT.2.base", "dirty-flag": false }, @@ -52,6 +53,7 @@ cluster_size: 65536 "filename": "TEST_DIR/t.IMGFMT.2.base", "cluster-size": 65536, "format": "IMGFMT", + "full-backing-filename": "TEST_DIR/t.IMGFMT.1.base", "backing-filename": "TEST_DIR/t.IMGFMT.1.base", "dirty-flag": false }, diff --git a/qemu/tests/qemu-iotests/046 b/qemu/tests/qemu-iotests/046 index e0be46cf2..e528b67cc 100755 --- a/qemu/tests/qemu-iotests/046 +++ b/qemu/tests/qemu-iotests/046 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/046.out b/qemu/tests/qemu-iotests/046.out index 9d18af53a..ca2c7404a 100644 --- a/qemu/tests/qemu-iotests/046.out +++ b/qemu/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/qemu/tests/qemu-iotests/047 b/qemu/tests/qemu-iotests/047 index c35cd096b..1b8f3d4a6 100755 --- a/qemu/tests/qemu-iotests/047 +++ b/qemu/tests/qemu-iotests/047 @@ -26,7 +26,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/049 b/qemu/tests/qemu-iotests/049 index 93aa0ea55..fff07604f 100755 --- a/qemu/tests/qemu-iotests/049 +++ b/qemu/tests/qemu-iotests/049 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/049.out b/qemu/tests/qemu-iotests/049.out index 9f93666c5..4673b67f3 100644 --- a/qemu/tests/qemu-iotests/049.out +++ b/qemu/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 == @@ -188,27 +187,21 @@ qemu-img create -f qcow2 -o encryption=off TEST_DIR/t.qcow2 64M Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 qemu-img create -f qcow2 -o encryption=on TEST_DIR/t.qcow2 64M -qemu-img: Encrypted images are deprecated -Support for them will be removed in a future release. -You can use 'qemu-img convert' to convert your image to an unencrypted one. -qemu-img: Encrypted images are deprecated -Support for them will be removed in a future release. -You can use 'qemu-img convert' to convert your image to an unencrypted one. Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=on cluster_size=65536 lazy_refcounts=off refcount_bits=16 == 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/qemu/tests/qemu-iotests/050 b/qemu/tests/qemu-iotests/050 index 07802bc49..03b4a5d62 100755 --- a/qemu/tests/qemu-iotests/050 +++ b/qemu/tests/qemu-iotests/050 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() @@ -51,14 +50,19 @@ fi echo echo "== Creating images ==" +TEST_IMG_SAVE="$TEST_IMG" +TEST_IMG="$TEST_IMG.old" + size=10M _make_test_img $size $QEMU_IO -c "write -P 0x40 0 1048576" "$TEST_IMG" | _filter_qemu_io -mv "$TEST_IMG" "$TEST_IMG.old" + +TEST_IMG="$TEST_IMG_SAVE.new" _make_test_img $size $QEMU_IO -c "write -P 0x5a 0 1048576" "$TEST_IMG" | _filter_qemu_io -mv "$TEST_IMG" "$TEST_IMG.new" + +TEST_IMG="$TEST_IMG_SAVE" _make_test_img -b "$TEST_IMG.old" $size $QEMU_IO -c "write -z 0 1048576" "$TEST_IMG" | _filter_qemu_io diff --git a/qemu/tests/qemu-iotests/050.out b/qemu/tests/qemu-iotests/050.out index a6cb2e686..3602d580d 100644 --- a/qemu/tests/qemu-iotests/050.out +++ b/qemu/tests/qemu-iotests/050.out @@ -1,13 +1,13 @@ QA output created by 050 == Creating images == -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=10485760 +Formatting 'TEST_DIR/t.IMGFMT.old', 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 +Formatting 'TEST_DIR/t.IMGFMT.new', 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/qemu/tests/qemu-iotests/051 b/qemu/tests/qemu-iotests/051 index 4a8055b67..630cb7a11 100755 --- a/qemu/tests/qemu-iotests/051 +++ b/qemu/tests/qemu-iotests/051 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() @@ -61,10 +60,11 @@ function do_run_qemu() function run_qemu() { - do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu + do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_generated_node_ids } size=128M +device_id="drive0" _make_test_img $size cp "$TEST_IMG" "$TEST_IMG.orig" @@ -75,10 +75,10 @@ echo echo === Unknown option === echo -run_qemu -drive file="$TEST_IMG",format=qcow2,unknown_opt= -run_qemu -drive file="$TEST_IMG",format=qcow2,unknown_opt=on -run_qemu -drive file="$TEST_IMG",format=qcow2,unknown_opt=1234 -run_qemu -drive file="$TEST_IMG",format=qcow2,unknown_opt=foo +run_qemu -drive file="$TEST_IMG",format=qcow2,unknown_opt=,if=none,id=$device_id +run_qemu -drive file="$TEST_IMG",format=qcow2,unknown_opt=on,if=none,id=$device_id +run_qemu -drive file="$TEST_IMG",format=qcow2,unknown_opt=1234,if=none,id=$device_id +run_qemu -drive file="$TEST_IMG",format=qcow2,unknown_opt=foo,if=none,id=$device_id echo echo === Unknown protocol option === @@ -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",if=none,id=$device_id -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" @@ -139,41 +140,63 @@ echo echo === No medium === echo -run_qemu -drive if=floppy -run_qemu -drive if=ide,media=cdrom -run_qemu -drive if=scsi,media=cdrom +case "$QEMU_DEFAULT_MACHINE" in + pc) + run_qemu -drive if=floppy + run_qemu -drive if=ide,media=cdrom + run_qemu -drive if=scsi,media=cdrom + run_qemu -drive if=ide + run_qemu -drive if=scsi + ;; + *) + ;; +esac -run_qemu -drive if=ide run_qemu -drive if=virtio -run_qemu -drive if=scsi -run_qemu -drive if=none,id=disk -device ide-cd,drive=disk -run_qemu -drive if=none,id=disk -device lsi53c895a -device scsi-cd,drive=disk - -run_qemu -drive if=none,id=disk -device ide-drive,drive=disk -run_qemu -drive if=none,id=disk -device ide-hd,drive=disk -run_qemu -drive if=none,id=disk -device lsi53c895a -device scsi-disk,drive=disk -run_qemu -drive if=none,id=disk -device lsi53c895a -device scsi-hd,drive=disk +case "$QEMU_DEFAULT_MACHINE" in + pc) + run_qemu -drive if=none,id=disk -device ide-cd,drive=disk + run_qemu -drive if=none,id=disk -device lsi53c895a -device scsi-cd,drive=disk + run_qemu -drive if=none,id=disk -device ide-drive,drive=disk + run_qemu -drive if=none,id=disk -device ide-hd,drive=disk + run_qemu -drive if=none,id=disk -device lsi53c895a -device scsi-disk,drive=disk + run_qemu -drive if=none,id=disk -device lsi53c895a -device scsi-hd,drive=disk + ;; + *) + ;; +esac echo echo === Read-only === echo -run_qemu -drive file="$TEST_IMG",if=floppy,readonly=on -run_qemu -drive file="$TEST_IMG",if=ide,media=cdrom,readonly=on -run_qemu -drive file="$TEST_IMG",if=scsi,media=cdrom,readonly=on +case "$QEMU_DEFAULT_MACHINE" in + pc) + run_qemu -drive file="$TEST_IMG",if=floppy,readonly=on + run_qemu -drive file="$TEST_IMG",if=ide,media=cdrom,readonly=on + run_qemu -drive file="$TEST_IMG",if=scsi,media=cdrom,readonly=on + run_qemu -drive file="$TEST_IMG",if=ide,readonly=on + run_qemu -drive file="$TEST_IMG",if=scsi,readonly=on + ;; + *) + ;; +esac -run_qemu -drive file="$TEST_IMG",if=ide,readonly=on run_qemu -drive file="$TEST_IMG",if=virtio,readonly=on -run_qemu -drive file="$TEST_IMG",if=scsi,readonly=on - -run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device ide-cd,drive=disk -run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device lsi53c895a -device scsi-cd,drive=disk -run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device ide-drive,drive=disk -run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device ide-hd,drive=disk -run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device lsi53c895a -device scsi-disk,drive=disk -run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device lsi53c895a -device scsi-hd,drive=disk +case "$QEMU_DEFAULT_MACHINE" in + pc) + run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device ide-cd,drive=disk + run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device lsi53c895a -device scsi-cd,drive=disk + run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device ide-drive,drive=disk + run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device ide-hd,drive=disk + run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device lsi53c895a -device scsi-disk,drive=disk + run_qemu -drive file="$TEST_IMG",if=none,id=disk,readonly=on -device lsi53c895a -device scsi-hd,drive=disk + ;; + *) + ;; +esac echo echo === Cache modes === @@ -182,12 +205,20 @@ echo # Cannot use the test image because cache=none might not work on the host FS # Use cdrom so that we won't get errors about missing media -run_qemu -drive media=cdrom,cache=none -run_qemu -drive media=cdrom,cache=directsync -run_qemu -drive media=cdrom,cache=writeback -run_qemu -drive media=cdrom,cache=writethrough -run_qemu -drive media=cdrom,cache=unsafe -run_qemu -drive media=cdrom,cache=invalid_value +run_qemu -drive driver=null-co,cache=none +run_qemu -drive driver=null-co,cache=directsync +run_qemu -drive driver=null-co,cache=writeback +run_qemu -drive driver=null-co,cache=writethrough +run_qemu -drive driver=null-co,cache=unsafe +run_qemu -drive driver=null-co,cache=invalid_value + +# Can't test direct=on here because O_DIRECT might not be supported on this FS +# Test 142 checks the direct=on cases + +for cache in writeback writethrough unsafe invalid_value; do + echo -e "info block\ninfo block file\ninfo block backing\ninfo block backing-file" | \ + run_qemu -drive file="$TEST_IMG",cache=$cache,backing.file.filename="$TEST_IMG.base",backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=$device_id -nodefaults +done echo echo === Specifying the protocol layer === @@ -231,6 +262,24 @@ run_qemu -drive file="$TEST_IMG",iops_size=1234,throttling.iops-size=5678 run_qemu -drive file="$TEST_IMG",readonly=on,read-only=off echo +echo === Catching negative/large throttling values === +echo + +run_qemu -drive file="$TEST_IMG",iops=-1 +run_qemu -drive file="$TEST_IMG",bps=-2 +run_qemu -drive file="$TEST_IMG",bps_rd=-3 +run_qemu -drive file="$TEST_IMG",bps_rd_max=-3 +run_qemu -drive file="$TEST_IMG",throttling.iops-total=-4 +run_qemu -drive file="$TEST_IMG",throttling.bps-total=-5 +# These are accepted +run_qemu -drive file="$TEST_IMG",bps=0 +run_qemu -drive file="$TEST_IMG",bps=1 +run_qemu -drive file="$TEST_IMG",bps=1000000000000000 +# While these are not +run_qemu -drive file="$TEST_IMG",bps=1000000000000001 +run_qemu -drive file="$TEST_IMG",bps=9999999999999999 + +echo echo === Parsing protocol from file name === echo @@ -252,26 +301,30 @@ echo $QEMU_IO -c "write -P 0x11 0 4k" "$TEST_IMG" | _filter_qemu_io -echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive file="$TEST_IMG" -snapshot | _filter_qemu_io -echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive file="$TEST_IMG",snapshot=on | _filter_qemu_io -echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive file.filename="$TEST_IMG",driver=qcow2,snapshot=on | _filter_qemu_io -echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive file.filename="$TEST_IMG",driver=qcow2 -snapshot | _filter_qemu_io -echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive file="file:$TEST_IMG" -snapshot | _filter_qemu_io -echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive file="file:$TEST_IMG",snapshot=on | _filter_qemu_io + +echo "qemu-io $device_id \"write -P 0x22 0 4k\"" | run_qemu -drive file="$TEST_IMG",if=none,id=$device_id -snapshot | _filter_qemu_io +echo "qemu-io $device_id \"write -P 0x22 0 4k\"" | run_qemu -drive file="$TEST_IMG",snapshot=on,if=none,id=$device_id | _filter_qemu_io +echo "qemu-io $device_id \"write -P 0x22 0 4k\"" | run_qemu -drive file.filename="$TEST_IMG",driver=qcow2,snapshot=on,if=none,id=$device_id\ + | _filter_qemu_io +echo "qemu-io $device_id \"write -P 0x22 0 4k\"" | run_qemu -drive file.filename="$TEST_IMG",driver=qcow2,if=none,id=$device_id -snapshot\ + | _filter_qemu_io +echo "qemu-io $device_id \"write -P 0x22 0 4k\"" | run_qemu -drive file="file:$TEST_IMG",if=none,id=$device_id -snapshot | _filter_qemu_io +echo "qemu-io $device_id \"write -P 0x22 0 4k\"" | run_qemu -drive file="file:$TEST_IMG",snapshot=on,if=none,id=$device_id | _filter_qemu_io # Opening a read-only file r/w with snapshot=on chmod u-w "$TEST_IMG" -echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive file="$TEST_IMG" -snapshot | _filter_qemu_io -echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive file="$TEST_IMG",snapshot=on | _filter_qemu_io +echo "qemu-io $device_id \"write -P 0x22 0 4k\"" | run_qemu -drive file="$TEST_IMG",if=none,id=$device_id -snapshot | _filter_qemu_io +echo "qemu-io $device_id \"write -P 0x22 0 4k\"" | run_qemu -drive file="$TEST_IMG",snapshot=on,if=none,id=$device_id | _filter_qemu_io chmod u+w "$TEST_IMG" $QEMU_IO -c "read -P 0x11 0 4k" "$TEST_IMG" | _filter_qemu_io -echo 'qemu-io ide0-hd0 "write -P 0x22 0 4k"' | run_qemu -drive file="$TEST_IMG",snapshot=off | _filter_qemu_io +echo "qemu-io $device_id \"write -P 0x22 0 4k\"" | run_qemu -drive file="$TEST_IMG",snapshot=off,if=none,id=$device_id | _filter_qemu_io $QEMU_IO -c "read -P 0x22 0 4k" "$TEST_IMG" | _filter_qemu_io -echo -e 'qemu-io ide0-hd0 "write -P 0x33 0 4k"\ncommit ide0-hd0' | run_qemu -drive file="$TEST_IMG",snapshot=on | _filter_qemu_io +echo -e "qemu-io $device_id \"write -P 0x33 0 4k\"\ncommit $device_id" | run_qemu -drive file="$TEST_IMG",snapshot=on,if=none,id=$device_id\ + | _filter_qemu_io $QEMU_IO -c "read -P 0x33 0 4k" "$TEST_IMG" | _filter_qemu_io diff --git a/qemu/tests/qemu-iotests/051.out b/qemu/tests/qemu-iotests/051.out index 23c282357..408d613bc 100644 --- a/qemu/tests/qemu-iotests/051.out +++ b/qemu/tests/qemu-iotests/051.out @@ -1,20 +1,20 @@ 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 === -Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt= -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=: Block format 'qcow2' used by device 'ide0-hd0' doesn't support the option 'unknown_opt' +Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=,if=none,id=drive0 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=,if=none,id=drive0: Block format 'qcow2' does not support the option 'unknown_opt' -Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=on -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=on: Block format 'qcow2' used by device 'ide0-hd0' doesn't support the option 'unknown_opt' +Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=on,if=none,id=drive0 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=on,if=none,id=drive0: Block format 'qcow2' does not support the option 'unknown_opt' -Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=1234 -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=1234: Block format 'qcow2' used by device 'ide0-hd0' doesn't support the option 'unknown_opt' +Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=1234,if=none,id=drive0 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=1234,if=none,id=drive0: Block format 'qcow2' does not support the option 'unknown_opt' -Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=foo -QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=foo: Block format 'qcow2' used by device 'ide0-hd0' doesn't support the option 'unknown_opt' +Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=foo,if=none,id=drive0 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=foo,if=none,id=drive0: Block format 'qcow2' does not support the option 'unknown_opt' === Unknown protocol option === @@ -56,10 +56,11 @@ QEMU X.Y.Z monitor - type 'help' for more information === Overriding backing file === -Testing: -drive file=TEST_DIR/t.qcow2,driver=qcow2,backing.file.filename=TEST_DIR/t.qcow2.orig -nodefaults +Testing: -drive file=TEST_DIR/t.qcow2,driver=qcow2,backing.file.filename=TEST_DIR/t.qcow2.orig,if=none,id=drive0 -nodefaults QEMU X.Y.Z monitor - type 'help' for more information (qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K -ide0-hd0: TEST_DIR/t.qcow2 (qcow2) +drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Removable device: not locked, tray closed Cache mode: writeback Backing file: TEST_DIR/t.qcow2.orig (chain depth: 1) (qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K @@ -107,136 +108,105 @@ QEMU X.Y.Z monitor - type 'help' for more information === No medium === -Testing: -drive if=floppy -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K - -Testing: -drive if=ide,media=cdrom -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K - -Testing: -drive if=scsi,media=cdrom -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K - -Testing: -drive if=ide -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) QEMU_PROG: Device needs media, but drive is empty -QEMU_PROG: Initialization of device ide-hd failed: Device initialization failed. - Testing: -drive if=virtio QEMU X.Y.Z monitor - type 'help' for more information (qemu) QEMU_PROG: -drive if=virtio: Device needs media, but drive is empty -Testing: -drive if=scsi -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) QEMU_PROG: Initialization of device lsi53c895a failed: Device needs media, but drive is empty -Testing: -drive if=none,id=disk -device ide-cd,drive=disk -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K +=== Read-only === -Testing: -drive if=none,id=disk -device lsi53c895a -device scsi-cd,drive=disk +Testing: -drive file=TEST_DIR/t.qcow2,if=virtio,readonly=on QEMU X.Y.Z monitor - type 'help' for more information (qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K -Testing: -drive if=none,id=disk -device ide-drive,drive=disk -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) QEMU_PROG: -device ide-drive,drive=disk: Device needs media, but drive is empty -QEMU_PROG: -device ide-drive,drive=disk: Device initialization failed. - -Testing: -drive if=none,id=disk -device ide-hd,drive=disk -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) QEMU_PROG: -device ide-hd,drive=disk: Device needs media, but drive is empty -QEMU_PROG: -device ide-hd,drive=disk: Device initialization failed. - -Testing: -drive if=none,id=disk -device lsi53c895a -device scsi-disk,drive=disk -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) QEMU_PROG: -device scsi-disk,drive=disk: Device needs media, but drive is empty - -Testing: -drive if=none,id=disk -device lsi53c895a -device scsi-hd,drive=disk -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) QEMU_PROG: -device scsi-hd,drive=disk: Device needs media, but drive is empty +=== Cache modes === -=== Read-only === - -Testing: -drive file=TEST_DIR/t.qcow2,if=floppy,readonly=on -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K - -Testing: -drive file=TEST_DIR/t.qcow2,if=ide,media=cdrom,readonly=on +Testing: -drive driver=null-co,cache=none QEMU X.Y.Z monitor - type 'help' for more information (qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K -Testing: -drive file=TEST_DIR/t.qcow2,if=scsi,media=cdrom,readonly=on +Testing: -drive driver=null-co,cache=directsync QEMU X.Y.Z monitor - type 'help' for more information (qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K -Testing: -drive file=TEST_DIR/t.qcow2,if=ide,readonly=on -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) QEMU_PROG: Can't use a read-only drive -QEMU_PROG: Initialization of device ide-hd failed: Device initialization failed. - -Testing: -drive file=TEST_DIR/t.qcow2,if=virtio,readonly=on +Testing: -drive driver=null-co,cache=writeback QEMU X.Y.Z monitor - type 'help' for more information (qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K -Testing: -drive file=TEST_DIR/t.qcow2,if=scsi,readonly=on +Testing: -drive driver=null-co,cache=writethrough QEMU X.Y.Z monitor - type 'help' for more information (qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K -Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-cd,drive=disk +Testing: -drive driver=null-co,cache=unsafe QEMU X.Y.Z monitor - type 'help' for more information (qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K -Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-cd,drive=disk -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K +Testing: -drive driver=null-co,cache=invalid_value +QEMU_PROG: -drive driver=null-co,cache=invalid_value: invalid cache option -Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-drive,drive=disk +Testing: -drive file=TEST_DIR/t.qcow2,cache=writeback,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults QEMU X.Y.Z monitor - type 'help' for more information -(qemu) QEMU_PROG: -device ide-drive,drive=disk: Can't use a read-only drive -QEMU_PROG: -device ide-drive,drive=disk: Device initialization failed. +(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K +drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Removable device: not locked, tray closed + Cache mode: writeback + Backing file: TEST_DIR/t.qcow2.base (chain depth: 1) +(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K[D[D[D[D[D[D[D[D[D[Dinfo block [K[D[D[D[D[D[D[D[D[D[D[Dinfo block f[K[D[D[D[D[D[D[D[D[D[D[D[Dinfo block fi[K[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block fil[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block file[K -Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-hd,drive=disk -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) QEMU_PROG: -device ide-hd,drive=disk: Can't use a read-only drive -QEMU_PROG: -device ide-hd,drive=disk: Device initialization failed. +file: TEST_DIR/t.qcow2 (file) + Cache mode: writeback +(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K[D[D[D[D[D[D[D[D[D[Dinfo block [K[D[D[D[D[D[D[D[D[D[D[Dinfo block b[K[D[D[D[D[D[D[D[D[D[D[D[Dinfo block ba[K[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block bac[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block back[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backi[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backin[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing[K +backing: TEST_DIR/t.qcow2.base (qcow2, read-only) + Cache mode: writeback, ignore flushes +(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K[D[D[D[D[D[D[D[D[D[Dinfo block [K[D[D[D[D[D[D[D[D[D[D[Dinfo block b[K[D[D[D[D[D[D[D[D[D[D[D[Dinfo block ba[K[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block bac[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block back[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backi[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backin[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-f[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-fi[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-fil[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-file[K -Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-disk,drive=disk -QEMU X.Y.Z monitor - type 'help' for more information +backing-file: TEST_DIR/t.qcow2.base (file, read-only) + Cache mode: writeback, ignore flushes (qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K -Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-hd,drive=disk +Testing: -drive file=TEST_DIR/t.qcow2,cache=writethrough,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults QEMU X.Y.Z monitor - type 'help' for more information -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K - - -=== Cache modes === +(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K +drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Removable device: not locked, tray closed + Cache mode: writethrough + Backing file: TEST_DIR/t.qcow2.base (chain depth: 1) +(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K[D[D[D[D[D[D[D[D[D[Dinfo block [K[D[D[D[D[D[D[D[D[D[D[Dinfo block f[K[D[D[D[D[D[D[D[D[D[D[D[Dinfo block fi[K[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block fil[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block file[K -Testing: -drive media=cdrom,cache=none -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K +file: TEST_DIR/t.qcow2 (file) + Cache mode: writeback +(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K[D[D[D[D[D[D[D[D[D[Dinfo block [K[D[D[D[D[D[D[D[D[D[D[Dinfo block b[K[D[D[D[D[D[D[D[D[D[D[D[Dinfo block ba[K[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block bac[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block back[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backi[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backin[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing[K +backing: TEST_DIR/t.qcow2.base (qcow2, read-only) + Cache mode: writeback, ignore flushes +(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K[D[D[D[D[D[D[D[D[D[Dinfo block [K[D[D[D[D[D[D[D[D[D[D[Dinfo block b[K[D[D[D[D[D[D[D[D[D[D[D[Dinfo block ba[K[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block bac[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block back[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backi[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backin[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-f[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-fi[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-fil[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-file[K -Testing: -drive media=cdrom,cache=directsync -QEMU X.Y.Z monitor - type 'help' for more information +backing-file: TEST_DIR/t.qcow2.base (file, read-only) + Cache mode: writeback, ignore flushes (qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K -Testing: -drive media=cdrom,cache=writeback +Testing: -drive file=TEST_DIR/t.qcow2,cache=unsafe,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults QEMU X.Y.Z monitor - type 'help' for more information -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K +(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K +drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Removable device: not locked, tray closed + Cache mode: writeback, ignore flushes + Backing file: TEST_DIR/t.qcow2.base (chain depth: 1) +(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K[D[D[D[D[D[D[D[D[D[Dinfo block [K[D[D[D[D[D[D[D[D[D[D[Dinfo block f[K[D[D[D[D[D[D[D[D[D[D[D[Dinfo block fi[K[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block fil[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block file[K -Testing: -drive media=cdrom,cache=writethrough -QEMU X.Y.Z monitor - type 'help' for more information -(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K +file: TEST_DIR/t.qcow2 (file) + Cache mode: writeback, ignore flushes +(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K[D[D[D[D[D[D[D[D[D[Dinfo block [K[D[D[D[D[D[D[D[D[D[D[Dinfo block b[K[D[D[D[D[D[D[D[D[D[D[D[Dinfo block ba[K[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block bac[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block back[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backi[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backin[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing[K +backing: TEST_DIR/t.qcow2.base (qcow2, read-only) + Cache mode: writeback, ignore flushes +(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K[D[D[D[D[D[D[D[D[D[Dinfo block [K[D[D[D[D[D[D[D[D[D[D[Dinfo block b[K[D[D[D[D[D[D[D[D[D[D[D[Dinfo block ba[K[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block bac[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block back[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backi[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backin[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-f[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-fi[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-fil[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-file[K -Testing: -drive media=cdrom,cache=unsafe -QEMU X.Y.Z monitor - type 'help' for more information +backing-file: TEST_DIR/t.qcow2.base (file, read-only) + Cache mode: writeback, ignore flushes (qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K -Testing: -drive media=cdrom,cache=invalid_value -QEMU_PROG: -drive media=cdrom,cache=invalid_value: invalid cache option +Testing: -drive file=TEST_DIR/t.qcow2,cache=invalid_value,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,cache=invalid_value,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0: invalid cache option === Specifying the protocol layer === @@ -315,6 +285,45 @@ Testing: -drive file=TEST_DIR/t.qcow2,readonly=on,read-only=off QEMU_PROG: -drive file=TEST_DIR/t.qcow2,readonly=on,read-only=off: 'read-only' and its alias 'readonly' can't be used at the same time +=== Catching negative/large throttling values === + +Testing: -drive file=TEST_DIR/t.qcow2,iops=-1 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,iops=-1: bps/iops/max values must be within [0, 1000000000000000] + +Testing: -drive file=TEST_DIR/t.qcow2,bps=-2 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,bps=-2: bps/iops/max values must be within [0, 1000000000000000] + +Testing: -drive file=TEST_DIR/t.qcow2,bps_rd=-3 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,bps_rd=-3: bps/iops/max values must be within [0, 1000000000000000] + +Testing: -drive file=TEST_DIR/t.qcow2,bps_rd_max=-3 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,bps_rd_max=-3: bps/iops/max values must be within [0, 1000000000000000] + +Testing: -drive file=TEST_DIR/t.qcow2,throttling.iops-total=-4 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,throttling.iops-total=-4: bps/iops/max values must be within [0, 1000000000000000] + +Testing: -drive file=TEST_DIR/t.qcow2,throttling.bps-total=-5 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,throttling.bps-total=-5: bps/iops/max values must be within [0, 1000000000000000] + +Testing: -drive file=TEST_DIR/t.qcow2,bps=0 +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive file=TEST_DIR/t.qcow2,bps=1 +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive file=TEST_DIR/t.qcow2,bps=1000000000000000 +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive file=TEST_DIR/t.qcow2,bps=1000000000000001 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,bps=1000000000000001: bps/iops/max values must be within [0, 1000000000000000] + +Testing: -drive file=TEST_DIR/t.qcow2,bps=9999999999999999 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,bps=9999999999999999: bps/iops/max values must be within [0, 1000000000000000] + + === Parsing protocol from file name === Testing: -hda foo:bar @@ -342,79 +351,79 @@ QEMU_PROG: -drive file.filename=file:TEST_DIR/t.qcow2: Could not open 'file:TEST wrote 4096/4096 bytes at offset 0 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -Testing: -drive file=TEST_DIR/t.qcow2 -snapshot +Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=drive0 -snapshot QEMU X.Y.Z monitor - type 'help' for more information -(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io i[K[D[D[D[D[D[D[D[D[Dqemu-io id[K[D[D[D[D[D[D[D[D[D[Dqemu-io ide[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-h[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 4k"[K +(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io d[K[D[D[D[D[D[D[D[D[Dqemu-io dr[K[D[D[D[D[D[D[D[D[D[Dqemu-io dri[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io driv[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k"[K wrote 4096/4096 bytes at offset 0 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) (qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K -Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on +Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,if=none,id=drive0 QEMU X.Y.Z monitor - type 'help' for more information -(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io i[K[D[D[D[D[D[D[D[D[Dqemu-io id[K[D[D[D[D[D[D[D[D[D[Dqemu-io ide[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-h[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 4k"[K +(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io d[K[D[D[D[D[D[D[D[D[Dqemu-io dr[K[D[D[D[D[D[D[D[D[D[Dqemu-io dri[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io driv[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k"[K wrote 4096/4096 bytes at offset 0 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) (qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K -Testing: -drive file.filename=TEST_DIR/t.qcow2,driver=qcow2,snapshot=on +Testing: -drive file.filename=TEST_DIR/t.qcow2,driver=qcow2,snapshot=on,if=none,id=drive0 QEMU X.Y.Z monitor - type 'help' for more information -(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io i[K[D[D[D[D[D[D[D[D[Dqemu-io id[K[D[D[D[D[D[D[D[D[D[Dqemu-io ide[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-h[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 4k"[K +(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io d[K[D[D[D[D[D[D[D[D[Dqemu-io dr[K[D[D[D[D[D[D[D[D[D[Dqemu-io dri[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io driv[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k"[K wrote 4096/4096 bytes at offset 0 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) (qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K -Testing: -drive file.filename=TEST_DIR/t.qcow2,driver=qcow2 -snapshot +Testing: -drive file.filename=TEST_DIR/t.qcow2,driver=qcow2,if=none,id=drive0 -snapshot QEMU X.Y.Z monitor - type 'help' for more information -(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io i[K[D[D[D[D[D[D[D[D[Dqemu-io id[K[D[D[D[D[D[D[D[D[D[Dqemu-io ide[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-h[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 4k"[K +(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io d[K[D[D[D[D[D[D[D[D[Dqemu-io dr[K[D[D[D[D[D[D[D[D[D[Dqemu-io dri[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io driv[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k"[K wrote 4096/4096 bytes at offset 0 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) (qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K -Testing: -drive file=file:TEST_DIR/t.qcow2 -snapshot +Testing: -drive file=file:TEST_DIR/t.qcow2,if=none,id=drive0 -snapshot QEMU X.Y.Z monitor - type 'help' for more information -(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io i[K[D[D[D[D[D[D[D[D[Dqemu-io id[K[D[D[D[D[D[D[D[D[D[Dqemu-io ide[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-h[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 4k"[K +(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io d[K[D[D[D[D[D[D[D[D[Dqemu-io dr[K[D[D[D[D[D[D[D[D[D[Dqemu-io dri[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io driv[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k"[K wrote 4096/4096 bytes at offset 0 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) (qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K -Testing: -drive file=file:TEST_DIR/t.qcow2,snapshot=on +Testing: -drive file=file:TEST_DIR/t.qcow2,snapshot=on,if=none,id=drive0 QEMU X.Y.Z monitor - type 'help' for more information -(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io i[K[D[D[D[D[D[D[D[D[Dqemu-io id[K[D[D[D[D[D[D[D[D[D[Dqemu-io ide[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-h[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 4k"[K +(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io d[K[D[D[D[D[D[D[D[D[Dqemu-io dr[K[D[D[D[D[D[D[D[D[D[Dqemu-io dri[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io driv[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k"[K wrote 4096/4096 bytes at offset 0 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) (qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K -Testing: -drive file=TEST_DIR/t.qcow2 -snapshot +Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=drive0 -snapshot QEMU X.Y.Z monitor - type 'help' for more information -(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io i[K[D[D[D[D[D[D[D[D[Dqemu-io id[K[D[D[D[D[D[D[D[D[D[Dqemu-io ide[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-h[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 4k"[K +(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io d[K[D[D[D[D[D[D[D[D[Dqemu-io dr[K[D[D[D[D[D[D[D[D[D[Dqemu-io dri[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io driv[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k"[K wrote 4096/4096 bytes at offset 0 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) (qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K -Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on +Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,if=none,id=drive0 QEMU X.Y.Z monitor - type 'help' for more information -(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io i[K[D[D[D[D[D[D[D[D[Dqemu-io id[K[D[D[D[D[D[D[D[D[D[Dqemu-io ide[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-h[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 4k"[K +(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io d[K[D[D[D[D[D[D[D[D[Dqemu-io dr[K[D[D[D[D[D[D[D[D[D[Dqemu-io dri[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io driv[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k"[K wrote 4096/4096 bytes at offset 0 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) (qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K read 4096/4096 bytes at offset 0 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -Testing: -drive file=TEST_DIR/t.qcow2,snapshot=off +Testing: -drive file=TEST_DIR/t.qcow2,snapshot=off,if=none,id=drive0 QEMU X.Y.Z monitor - type 'help' for more information -(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io i[K[D[D[D[D[D[D[D[D[Dqemu-io id[K[D[D[D[D[D[D[D[D[D[Dqemu-io ide[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-h[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x22 0 4k"[K +(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io d[K[D[D[D[D[D[D[D[D[Dqemu-io dr[K[D[D[D[D[D[D[D[D[D[Dqemu-io dri[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io driv[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k"[K wrote 4096/4096 bytes at offset 0 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) (qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K read 4096/4096 bytes at offset 0 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on +Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,if=none,id=drive0 QEMU X.Y.Z monitor - type 'help' for more information -(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io i[K[D[D[D[D[D[D[D[D[Dqemu-io id[K[D[D[D[D[D[D[D[D[D[Dqemu-io ide[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-h[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x3[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x33[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x33 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x33 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x33 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x33 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x33 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io ide0-hd0 "write -P 0x33 0 4k"[K +(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io d[K[D[D[D[D[D[D[D[D[Dqemu-io dr[K[D[D[D[D[D[D[D[D[D[Dqemu-io dri[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io driv[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x3[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x33[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x33 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x33 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x33 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x33 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x33 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x33 0 4k"[K wrote 4096/4096 bytes at offset 0 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -(qemu) c[K[Dco[K[D[Dcom[K[D[D[Dcomm[K[D[D[D[Dcommi[K[D[D[D[D[Dcommit[K[D[D[D[D[D[Dcommit [K[D[D[D[D[D[D[Dcommit i[K[D[D[D[D[D[D[D[Dcommit id[K[D[D[D[D[D[D[D[D[Dcommit ide[K[D[D[D[D[D[D[D[D[D[Dcommit ide0[K[D[D[D[D[D[D[D[D[D[D[Dcommit ide0-[K[D[D[D[D[D[D[D[D[D[D[D[Dcommit ide0-h[K[D[D[D[D[D[D[D[D[D[D[D[D[Dcommit ide0-hd[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dcommit ide0-hd0[K +(qemu) c[K[Dco[K[D[Dcom[K[D[D[Dcomm[K[D[D[D[Dcommi[K[D[D[D[D[Dcommit[K[D[D[D[D[D[Dcommit [K[D[D[D[D[D[D[Dcommit d[K[D[D[D[D[D[D[D[Dcommit dr[K[D[D[D[D[D[D[D[D[Dcommit dri[K[D[D[D[D[D[D[D[D[D[Dcommit driv[K[D[D[D[D[D[D[D[D[D[D[Dcommit drive[K[D[D[D[D[D[D[D[D[D[D[D[Dcommit drive0[K (qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K read 4096/4096 bytes at offset 0 diff --git a/qemu/tests/qemu-iotests/051.pc.out b/qemu/tests/qemu-iotests/051.pc.out new file mode 100644 index 000000000..ec6d22229 --- /dev/null +++ b/qemu/tests/qemu-iotests/051.pc.out @@ -0,0 +1,525 @@ +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 + +=== Unknown option === + +Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=,if=none,id=drive0 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=,if=none,id=drive0: Block format 'qcow2' does not support the option 'unknown_opt' + +Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=on,if=none,id=drive0 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=on,if=none,id=drive0: Block format 'qcow2' does not support the option 'unknown_opt' + +Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=1234,if=none,id=drive0 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=1234,if=none,id=drive0: Block format 'qcow2' does not support the option 'unknown_opt' + +Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=foo,if=none,id=drive0 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=foo,if=none,id=drive0: Block format 'qcow2' does not support the option 'unknown_opt' + + +=== Unknown protocol option === + +Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt= +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=: Block protocol 'file' doesn't support the option 'unknown_opt' + +Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=on +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=on: Block protocol 'file' doesn't support the option 'unknown_opt' + +Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=1234 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=1234: Block protocol 'file' doesn't support the option 'unknown_opt' + +Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=foo +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,file.unknown_opt=foo: Block protocol 'file' doesn't support the option 'unknown_opt' + + +=== Invalid format === + +Testing: -drive file=TEST_DIR/t.qcow2,format=foo +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=foo: Unknown driver 'foo' + +Testing: -drive file=TEST_DIR/t.qcow2,driver=foo +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=foo: Unknown driver 'foo' + +Testing: -drive file=TEST_DIR/t.qcow2,driver=raw,format=qcow2 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=raw,format=qcow2: Cannot specify both 'driver' and 'format' + +Testing: -drive file=TEST_DIR/t.qcow2,driver=qcow2,format=qcow2 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=qcow2,format=qcow2: Cannot specify both 'driver' and 'format' + + +=== Device without drive === + +Testing: -device virtio-scsi-pci -device scsi-hd +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) QEMU_PROG: -device scsi-hd: drive property not set + + +=== Overriding backing file === + +Testing: -drive file=TEST_DIR/t.qcow2,driver=qcow2,backing.file.filename=TEST_DIR/t.qcow2.orig,if=none,id=drive0 -nodefaults +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K +drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Removable device: not locked, tray closed + Cache mode: writeback + Backing file: TEST_DIR/t.qcow2.orig (chain depth: 1) +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive file=TEST_DIR/t.qcow2,driver=raw,backing.file.filename=TEST_DIR/t.qcow2.orig +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=raw,backing.file.filename=TEST_DIR/t.qcow2.orig: Driver doesn't support backing files + +Testing: -drive file=TEST_DIR/t.qcow2,file.backing.driver=file,file.backing.filename=TEST_DIR/t.qcow2.orig +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,file.backing.driver=file,file.backing.filename=TEST_DIR/t.qcow2.orig: Driver doesn't support backing files + +Testing: -drive file=TEST_DIR/t.qcow2,file.backing.driver=qcow2,file.backing.file.filename=TEST_DIR/t.qcow2.orig +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,file.backing.driver=qcow2,file.backing.file.filename=TEST_DIR/t.qcow2.orig: Driver doesn't support backing files + + +=== Enable and disable lazy refcounting on the command line, plus some invalid values === + +Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=off +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts= +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=: Parameter 'lazy-refcounts' expects 'on' or 'off' + +Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=42 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=42: Parameter 'lazy-refcounts' expects 'on' or 'off' + +Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=foo +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=foo: Parameter 'lazy-refcounts' expects 'on' or 'off' + + +=== With version 2 images enabling lazy refcounts must fail === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 +Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on: Lazy refcounts require a qcow2 image with at least qemu 1.1 compatibility level + +Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=off +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + + +=== No medium === + +Testing: -drive if=floppy +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive if=ide,media=cdrom +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive if=scsi,media=cdrom +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive if=ide +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) QEMU_PROG: Device needs media, but drive is empty +QEMU_PROG: Initialization of device ide-hd failed: Device initialization failed. + +Testing: -drive if=scsi +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) QEMU_PROG: Initialization of device lsi53c895a failed: Device needs media, but drive is empty + +Testing: -drive if=virtio +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) QEMU_PROG: -drive if=virtio: Device needs media, but drive is empty + +Testing: -drive if=none,id=disk -device ide-cd,drive=disk +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive if=none,id=disk -device lsi53c895a -device scsi-cd,drive=disk +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive if=none,id=disk -device ide-drive,drive=disk +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) QEMU_PROG: -device ide-drive,drive=disk: Device needs media, but drive is empty +QEMU_PROG: -device ide-drive,drive=disk: Device initialization failed. + +Testing: -drive if=none,id=disk -device ide-hd,drive=disk +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) QEMU_PROG: -device ide-hd,drive=disk: Device needs media, but drive is empty +QEMU_PROG: -device ide-hd,drive=disk: Device initialization failed. + +Testing: -drive if=none,id=disk -device lsi53c895a -device scsi-disk,drive=disk +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) QEMU_PROG: -device scsi-disk,drive=disk: Device needs media, but drive is empty + +Testing: -drive if=none,id=disk -device lsi53c895a -device scsi-hd,drive=disk +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) QEMU_PROG: -device scsi-hd,drive=disk: Device needs media, but drive is empty + + +=== Read-only === + +Testing: -drive file=TEST_DIR/t.qcow2,if=floppy,readonly=on +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive file=TEST_DIR/t.qcow2,if=ide,media=cdrom,readonly=on +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive file=TEST_DIR/t.qcow2,if=scsi,media=cdrom,readonly=on +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive file=TEST_DIR/t.qcow2,if=ide,readonly=on +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) QEMU_PROG: Can't use a read-only drive +QEMU_PROG: Initialization of device ide-hd failed: Device initialization failed. + +Testing: -drive file=TEST_DIR/t.qcow2,if=scsi,readonly=on +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive file=TEST_DIR/t.qcow2,if=virtio,readonly=on +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-cd,drive=disk +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-cd,drive=disk +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-drive,drive=disk +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) QEMU_PROG: -device ide-drive,drive=disk: Can't use a read-only drive +QEMU_PROG: -device ide-drive,drive=disk: Device initialization failed. + +Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-hd,drive=disk +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) QEMU_PROG: -device ide-hd,drive=disk: Can't use a read-only drive +QEMU_PROG: -device ide-hd,drive=disk: Device initialization failed. + +Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-disk,drive=disk +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-hd,drive=disk +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + + +=== Cache modes === + +Testing: -drive driver=null-co,cache=none +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive driver=null-co,cache=directsync +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive driver=null-co,cache=writeback +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive driver=null-co,cache=writethrough +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive driver=null-co,cache=unsafe +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive driver=null-co,cache=invalid_value +QEMU_PROG: -drive driver=null-co,cache=invalid_value: invalid cache option + +Testing: -drive file=TEST_DIR/t.qcow2,cache=writeback,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K +drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Removable device: not locked, tray closed + Cache mode: writeback + Backing file: TEST_DIR/t.qcow2.base (chain depth: 1) +(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K[D[D[D[D[D[D[D[D[D[Dinfo block [K[D[D[D[D[D[D[D[D[D[D[Dinfo block f[K[D[D[D[D[D[D[D[D[D[D[D[Dinfo block fi[K[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block fil[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block file[K + +file: TEST_DIR/t.qcow2 (file) + Cache mode: writeback +(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K[D[D[D[D[D[D[D[D[D[Dinfo block [K[D[D[D[D[D[D[D[D[D[D[Dinfo block b[K[D[D[D[D[D[D[D[D[D[D[D[Dinfo block ba[K[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block bac[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block back[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backi[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backin[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing[K +backing: TEST_DIR/t.qcow2.base (qcow2, read-only) + Cache mode: writeback, ignore flushes +(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K[D[D[D[D[D[D[D[D[D[Dinfo block [K[D[D[D[D[D[D[D[D[D[D[Dinfo block b[K[D[D[D[D[D[D[D[D[D[D[D[Dinfo block ba[K[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block bac[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block back[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backi[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backin[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-f[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-fi[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-fil[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-file[K + +backing-file: TEST_DIR/t.qcow2.base (file, read-only) + Cache mode: writeback, ignore flushes +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive file=TEST_DIR/t.qcow2,cache=writethrough,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K +drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Removable device: not locked, tray closed + Cache mode: writethrough + Backing file: TEST_DIR/t.qcow2.base (chain depth: 1) +(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K[D[D[D[D[D[D[D[D[D[Dinfo block [K[D[D[D[D[D[D[D[D[D[D[Dinfo block f[K[D[D[D[D[D[D[D[D[D[D[D[Dinfo block fi[K[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block fil[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block file[K + +file: TEST_DIR/t.qcow2 (file) + Cache mode: writeback +(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K[D[D[D[D[D[D[D[D[D[Dinfo block [K[D[D[D[D[D[D[D[D[D[D[Dinfo block b[K[D[D[D[D[D[D[D[D[D[D[D[Dinfo block ba[K[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block bac[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block back[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backi[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backin[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing[K +backing: TEST_DIR/t.qcow2.base (qcow2, read-only) + Cache mode: writeback, ignore flushes +(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K[D[D[D[D[D[D[D[D[D[Dinfo block [K[D[D[D[D[D[D[D[D[D[D[Dinfo block b[K[D[D[D[D[D[D[D[D[D[D[D[Dinfo block ba[K[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block bac[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block back[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backi[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backin[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-f[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-fi[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-fil[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-file[K + +backing-file: TEST_DIR/t.qcow2.base (file, read-only) + Cache mode: writeback, ignore flushes +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive file=TEST_DIR/t.qcow2,cache=unsafe,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K +drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2) + Removable device: not locked, tray closed + Cache mode: writeback, ignore flushes + Backing file: TEST_DIR/t.qcow2.base (chain depth: 1) +(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K[D[D[D[D[D[D[D[D[D[Dinfo block [K[D[D[D[D[D[D[D[D[D[D[Dinfo block f[K[D[D[D[D[D[D[D[D[D[D[D[Dinfo block fi[K[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block fil[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block file[K + +file: TEST_DIR/t.qcow2 (file) + Cache mode: writeback, ignore flushes +(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K[D[D[D[D[D[D[D[D[D[Dinfo block [K[D[D[D[D[D[D[D[D[D[D[Dinfo block b[K[D[D[D[D[D[D[D[D[D[D[D[Dinfo block ba[K[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block bac[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block back[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backi[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backin[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing[K +backing: TEST_DIR/t.qcow2.base (qcow2, read-only) + Cache mode: writeback, ignore flushes +(qemu) i[K[Din[K[D[Dinf[K[D[D[Dinfo[K[D[D[D[Dinfo [K[D[D[D[D[Dinfo b[K[D[D[D[D[D[Dinfo bl[K[D[D[D[D[D[D[Dinfo blo[K[D[D[D[D[D[D[D[Dinfo bloc[K[D[D[D[D[D[D[D[D[Dinfo block[K[D[D[D[D[D[D[D[D[D[Dinfo block [K[D[D[D[D[D[D[D[D[D[D[Dinfo block b[K[D[D[D[D[D[D[D[D[D[D[D[Dinfo block ba[K[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block bac[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block back[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backi[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backin[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-f[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-fi[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-fil[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dinfo block backing-file[K + +backing-file: TEST_DIR/t.qcow2.base (file, read-only) + Cache mode: writeback, ignore flushes +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive file=TEST_DIR/t.qcow2,cache=invalid_value,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,cache=invalid_value,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0: invalid cache option + + +=== Specifying the protocol layer === + +Testing: -drive file=TEST_DIR/t.qcow2,file.driver=file +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + + +=== Leaving out required options === + +Testing: -drive driver=file +QEMU_PROG: -drive driver=file: The 'file' block driver requires a file name + +Testing: -drive driver=nbd +QEMU_PROG: -drive driver=nbd: one of path and host must be specified. + +Testing: -drive driver=raw +QEMU_PROG: -drive driver=raw: Can't use 'raw' as a block driver for the protocol level + +Testing: -drive file.driver=file +QEMU_PROG: -drive file.driver=file: The 'file' block driver requires a file name + +Testing: -drive file.driver=nbd +QEMU_PROG: -drive file.driver=nbd: one of path and host must be specified. + +Testing: -drive file.driver=raw +QEMU_PROG: -drive file.driver=raw: Can't use 'raw' as a block driver for the protocol level + +Testing: -drive foo=bar +QEMU_PROG: -drive foo=bar: Must specify either driver or file + + +=== Specifying both an option and its legacy alias === + +Testing: -drive file=TEST_DIR/t.qcow2,iops=1234,throttling.iops-total=5678 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,iops=1234,throttling.iops-total=5678: 'throttling.iops-total' and its alias 'iops' can't be used at the same time + +Testing: -drive file=TEST_DIR/t.qcow2,iops_rd=1234,throttling.iops-read=5678 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,iops_rd=1234,throttling.iops-read=5678: 'throttling.iops-read' and its alias 'iops_rd' can't be used at the same time + +Testing: -drive file=TEST_DIR/t.qcow2,iops_wr=1234,throttling.iops-write=5678 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,iops_wr=1234,throttling.iops-write=5678: 'throttling.iops-write' and its alias 'iops_wr' can't be used at the same time + +Testing: -drive file=TEST_DIR/t.qcow2,bps=1234,throttling.bps-total=5678 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,bps=1234,throttling.bps-total=5678: 'throttling.bps-total' and its alias 'bps' can't be used at the same time + +Testing: -drive file=TEST_DIR/t.qcow2,bps_rd=1234,throttling.bps-read=5678 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,bps_rd=1234,throttling.bps-read=5678: 'throttling.bps-read' and its alias 'bps_rd' can't be used at the same time + +Testing: -drive file=TEST_DIR/t.qcow2,bps_wr=1234,throttling.bps-write=5678 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,bps_wr=1234,throttling.bps-write=5678: 'throttling.bps-write' and its alias 'bps_wr' can't be used at the same time + +Testing: -drive file=TEST_DIR/t.qcow2,iops_max=1234,throttling.iops-total-max=5678 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,iops_max=1234,throttling.iops-total-max=5678: 'throttling.iops-total-max' and its alias 'iops_max' can't be used at the same time + +Testing: -drive file=TEST_DIR/t.qcow2,iops_rd_max=1234,throttling.iops-read-max=5678 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,iops_rd_max=1234,throttling.iops-read-max=5678: 'throttling.iops-read-max' and its alias 'iops_rd_max' can't be used at the same time + +Testing: -drive file=TEST_DIR/t.qcow2,iops_wr_max=1234,throttling.iops-write-max=5678 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,iops_wr_max=1234,throttling.iops-write-max=5678: 'throttling.iops-write-max' and its alias 'iops_wr_max' can't be used at the same time + +Testing: -drive file=TEST_DIR/t.qcow2,bps_max=1234,throttling.bps-total-max=5678 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,bps_max=1234,throttling.bps-total-max=5678: 'throttling.bps-total-max' and its alias 'bps_max' can't be used at the same time + +Testing: -drive file=TEST_DIR/t.qcow2,bps_rd_max=1234,throttling.bps-read-max=5678 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,bps_rd_max=1234,throttling.bps-read-max=5678: 'throttling.bps-read-max' and its alias 'bps_rd_max' can't be used at the same time + +Testing: -drive file=TEST_DIR/t.qcow2,bps_wr_max=1234,throttling.bps-write-max=5678 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,bps_wr_max=1234,throttling.bps-write-max=5678: 'throttling.bps-write-max' and its alias 'bps_wr_max' can't be used at the same time + +Testing: -drive file=TEST_DIR/t.qcow2,iops_size=1234,throttling.iops-size=5678 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,iops_size=1234,throttling.iops-size=5678: 'throttling.iops-size' and its alias 'iops_size' can't be used at the same time + +Testing: -drive file=TEST_DIR/t.qcow2,readonly=on,read-only=off +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,readonly=on,read-only=off: 'read-only' and its alias 'readonly' can't be used at the same time + + +=== Catching negative/large throttling values === + +Testing: -drive file=TEST_DIR/t.qcow2,iops=-1 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,iops=-1: bps/iops/max values must be within [0, 1000000000000000] + +Testing: -drive file=TEST_DIR/t.qcow2,bps=-2 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,bps=-2: bps/iops/max values must be within [0, 1000000000000000] + +Testing: -drive file=TEST_DIR/t.qcow2,bps_rd=-3 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,bps_rd=-3: bps/iops/max values must be within [0, 1000000000000000] + +Testing: -drive file=TEST_DIR/t.qcow2,bps_rd_max=-3 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,bps_rd_max=-3: bps/iops/max values must be within [0, 1000000000000000] + +Testing: -drive file=TEST_DIR/t.qcow2,throttling.iops-total=-4 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,throttling.iops-total=-4: bps/iops/max values must be within [0, 1000000000000000] + +Testing: -drive file=TEST_DIR/t.qcow2,throttling.bps-total=-5 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,throttling.bps-total=-5: bps/iops/max values must be within [0, 1000000000000000] + +Testing: -drive file=TEST_DIR/t.qcow2,bps=0 +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive file=TEST_DIR/t.qcow2,bps=1 +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive file=TEST_DIR/t.qcow2,bps=1000000000000000 +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive file=TEST_DIR/t.qcow2,bps=1000000000000001 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,bps=1000000000000001: bps/iops/max values must be within [0, 1000000000000000] + +Testing: -drive file=TEST_DIR/t.qcow2,bps=9999999999999999 +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,bps=9999999999999999: bps/iops/max values must be within [0, 1000000000000000] + + +=== Parsing protocol from file name === + +Testing: -hda foo:bar +QEMU_PROG: -hda foo:bar: Unknown protocol 'foo' + +Testing: -drive file=foo:bar +QEMU_PROG: -drive file=foo:bar: Unknown protocol 'foo' + +Testing: -drive file.filename=foo:bar +QEMU_PROG: -drive file.filename=foo:bar: Could not open 'foo:bar': No such file or directory + +Testing: -hda file:TEST_DIR/t.qcow2 +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive file=file:TEST_DIR/t.qcow2 +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive file.filename=file:TEST_DIR/t.qcow2 +QEMU_PROG: -drive file.filename=file:TEST_DIR/t.qcow2: Could not open 'file:TEST_DIR/t.qcow2': No such file or directory + + +=== Snapshot mode === + +wrote 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=drive0 -snapshot +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io d[K[D[D[D[D[D[D[D[D[Dqemu-io dr[K[D[D[D[D[D[D[D[D[D[Dqemu-io dri[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io driv[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k"[K +wrote 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,if=none,id=drive0 +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io d[K[D[D[D[D[D[D[D[D[Dqemu-io dr[K[D[D[D[D[D[D[D[D[D[Dqemu-io dri[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io driv[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k"[K +wrote 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive file.filename=TEST_DIR/t.qcow2,driver=qcow2,snapshot=on,if=none,id=drive0 +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io d[K[D[D[D[D[D[D[D[D[Dqemu-io dr[K[D[D[D[D[D[D[D[D[D[Dqemu-io dri[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io driv[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k"[K +wrote 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive file.filename=TEST_DIR/t.qcow2,driver=qcow2,if=none,id=drive0 -snapshot +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io d[K[D[D[D[D[D[D[D[D[Dqemu-io dr[K[D[D[D[D[D[D[D[D[D[Dqemu-io dri[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io driv[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k"[K +wrote 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive file=file:TEST_DIR/t.qcow2,if=none,id=drive0 -snapshot +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io d[K[D[D[D[D[D[D[D[D[Dqemu-io dr[K[D[D[D[D[D[D[D[D[D[Dqemu-io dri[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io driv[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k"[K +wrote 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive file=file:TEST_DIR/t.qcow2,snapshot=on,if=none,id=drive0 +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io d[K[D[D[D[D[D[D[D[D[Dqemu-io dr[K[D[D[D[D[D[D[D[D[D[Dqemu-io dri[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io driv[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k"[K +wrote 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=drive0 -snapshot +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io d[K[D[D[D[D[D[D[D[D[Dqemu-io dr[K[D[D[D[D[D[D[D[D[D[Dqemu-io dri[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io driv[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k"[K +wrote 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,if=none,id=drive0 +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io d[K[D[D[D[D[D[D[D[D[Dqemu-io dr[K[D[D[D[D[D[D[D[D[D[Dqemu-io dri[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io driv[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k"[K +wrote 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +read 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +Testing: -drive file=TEST_DIR/t.qcow2,snapshot=off,if=none,id=drive0 +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io d[K[D[D[D[D[D[D[D[D[Dqemu-io dr[K[D[D[D[D[D[D[D[D[D[Dqemu-io dri[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io driv[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x2[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x22 0 4k"[K +wrote 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +read 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,if=none,id=drive0 +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqe[K[D[Dqem[K[D[D[Dqemu[K[D[D[D[Dqemu-[K[D[D[D[D[Dqemu-i[K[D[D[D[D[D[Dqemu-io[K[D[D[D[D[D[D[Dqemu-io [K[D[D[D[D[D[D[D[Dqemu-io d[K[D[D[D[D[D[D[D[D[Dqemu-io dr[K[D[D[D[D[D[D[D[D[D[Dqemu-io dri[K[D[D[D[D[D[D[D[D[D[D[Dqemu-io driv[K[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive[K[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "w[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wr[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "wri[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "writ[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x3[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x33[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x33 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x33 0[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x33 0 [K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x33 0 4[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x33 0 4k[K[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[D[Dqemu-io drive0 "write -P 0x33 0 4k"[K +wrote 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +(qemu) c[K[Dco[K[D[Dcom[K[D[D[Dcomm[K[D[D[D[Dcommi[K[D[D[D[D[Dcommit[K[D[D[D[D[D[Dcommit [K[D[D[D[D[D[D[Dcommit d[K[D[D[D[D[D[D[D[Dcommit dr[K[D[D[D[D[D[D[D[D[Dcommit dri[K[D[D[D[D[D[D[D[D[D[Dcommit driv[K[D[D[D[D[D[D[D[D[D[D[Dcommit drive[K[D[D[D[D[D[D[D[D[D[D[D[Dcommit drive0[K +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +read 4096/4096 bytes at offset 0 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +*** done diff --git a/qemu/tests/qemu-iotests/052 b/qemu/tests/qemu-iotests/052 index 61959e286..4b647242d 100755 --- a/qemu/tests/qemu-iotests/052 +++ b/qemu/tests/qemu-iotests/052 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/053 b/qemu/tests/qemu-iotests/053 index e589e5f12..2a04f5f55 100755 --- a/qemu/tests/qemu-iotests/053 +++ b/qemu/tests/qemu-iotests/053 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/054 b/qemu/tests/qemu-iotests/054 index bd94153d6..bf47ef9fa 100755 --- a/qemu/tests/qemu-iotests/054 +++ b/qemu/tests/qemu-iotests/054 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/055 b/qemu/tests/qemu-iotests/055 index 017a609f3..c8e357870 100755 --- a/qemu/tests/qemu-iotests/055 +++ b/qemu/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/qemu/tests/qemu-iotests/056 b/qemu/tests/qemu-iotests/056 index 54e4bd069..04f2c3c84 100755 --- a/qemu/tests/qemu-iotests/056 +++ b/qemu/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/qemu/tests/qemu-iotests/056.out b/qemu/tests/qemu-iotests/056.out index fbc63e62f..8d7e99670 100644 --- a/qemu/tests/qemu-iotests/056.out +++ b/qemu/tests/qemu-iotests/056.out @@ -1,5 +1,5 @@ -.. +... ---------------------------------------------------------------------- -Ran 2 tests +Ran 3 tests OK diff --git a/qemu/tests/qemu-iotests/058 b/qemu/tests/qemu-iotests/058 index f2bdd0bff..2253c6a6d 100755 --- a/qemu/tests/qemu-iotests/058 +++ b/qemu/tests/qemu-iotests/058 @@ -27,16 +27,21 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ 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 +65,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 +72,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/qemu/tests/qemu-iotests/059 b/qemu/tests/qemu-iotests/059 index 0ded0c3da..6655aaf38 100755 --- a/qemu/tests/qemu-iotests/059 +++ b/qemu/tests/qemu-iotests/059 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() @@ -133,6 +132,16 @@ $QEMU_IO -c "write -P 0xa 900G 512" "$TEST_IMG" | _filter_qemu_io $QEMU_IO -c "read -v 900G 1024" "$TEST_IMG" | _filter_qemu_io echo +echo "=== Testing qemu-img map on extents ===" +for fmt in monolithicSparse twoGbMaxExtentSparse; do + IMGOPTS="subformat=$fmt" _make_test_img 31G + $QEMU_IO -c "write 65024 1k" "$TEST_IMG" | _filter_qemu_io + $QEMU_IO -c "write 2147483136 1k" "$TEST_IMG" | _filter_qemu_io + $QEMU_IO -c "write 5G 1k" "$TEST_IMG" | _filter_qemu_io + $QEMU_IMG map "$TEST_IMG" | _filter_testdir +done + +echo echo "=== Testing afl image with a very large capacity ===" _use_sample_img afl9.vmdk.bz2 _img_info diff --git a/qemu/tests/qemu-iotests/059.out b/qemu/tests/qemu-iotests/059.out index 67e3cf57e..678adb437 100644 --- a/qemu/tests/qemu-iotests/059.out +++ b/qemu/tests/qemu-iotests/059.out @@ -2,31 +2,31 @@ QA output created by 059 === Testing invalid granularity === Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 -qemu-io: can't open device TEST_DIR/t.vmdk: Invalid granularity, image may be corrupt +can't open device TEST_DIR/t.vmdk: Invalid granularity, image may be corrupt no file open, try 'help open' === Testing too big L2 table size === Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 -qemu-io: can't open device TEST_DIR/t.vmdk: L2 table size too big +can't open device TEST_DIR/t.vmdk: L2 table size too big no file open, try 'help open' === Testing too big L1 table size === Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 -qemu-io: can't open device TEST_DIR/t.vmdk: L1 size too big +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) @@ -2038,12 +2038,10 @@ Format specific information: format: FLAT === Testing malformed VMFS extent description line === -qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Invalid extent lines: -RW 12582912 VMFS "dummy.IMGFMT" 1 - +qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Invalid extent line: 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,8 +2052,8 @@ 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 -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"}' +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 subformat=monolithicFlat +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 === image: TEST_DIR/iotest-version3.IMGFMT @@ -2264,7 +2262,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) @@ -2337,6 +2335,31 @@ e1000003f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ read 1024/1024 bytes at offset 966367641600 1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +=== Testing qemu-img map on extents === +Formatting 'TEST_DIR/iotest-version3.IMGFMT', fmt=IMGFMT size=33285996544 subformat=monolithicSparse +wrote 1024/1024 bytes at offset 65024 +1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 1024/1024 bytes at offset 2147483136 +1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 1024/1024 bytes at offset 5368709120 +1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +Offset Length Mapped to File +0 0x20000 0x3f0000 TEST_DIR/iotest-version3.vmdk +0x7fff0000 0x20000 0x410000 TEST_DIR/iotest-version3.vmdk +0x140000000 0x10000 0x430000 TEST_DIR/iotest-version3.vmdk +Formatting 'TEST_DIR/iotest-version3.IMGFMT', fmt=IMGFMT size=33285996544 subformat=twoGbMaxExtentSparse +wrote 1024/1024 bytes at offset 65024 +1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 1024/1024 bytes at offset 2147483136 +1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +wrote 1024/1024 bytes at offset 5368709120 +1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +Offset Length Mapped to File +0 0x20000 0x50000 TEST_DIR/iotest-version3-s001.vmdk +0x7fff0000 0x10000 0x70000 TEST_DIR/iotest-version3-s001.vmdk +0x80000000 0x10000 0x50000 TEST_DIR/iotest-version3-s002.vmdk +0x140000000 0x10000 0x50000 TEST_DIR/iotest-version3-s003.vmdk + === Testing afl image with a very large capacity === qemu-img: Can't get size of device 'image': File too large *** done diff --git a/qemu/tests/qemu-iotests/060 b/qemu/tests/qemu-iotests/060 index c81319c16..8e95c450e 100755 --- a/qemu/tests/qemu-iotests/060 +++ b/qemu/tests/qemu-iotests/060 @@ -25,7 +25,6 @@ seq="$(basename $0)" echo "QA output created by $seq" here="$PWD" -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/060.out b/qemu/tests/qemu-iotests/060.out index 751118951..5d40206ef 100644 --- a/qemu/tests/qemu-iotests/060.out +++ b/qemu/tests/qemu-iotests/060.out @@ -20,7 +20,7 @@ Format specific information: lazy refcounts: false refcount bits: 16 corrupt: true -qemu-io: can't open device TEST_DIR/t.IMGFMT: IMGFMT: Image is corrupt; cannot be opened read/write +can't open device TEST_DIR/t.IMGFMT: IMGFMT: Image is corrupt; cannot be opened read/write read 512/512 bytes at offset 0 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) diff --git a/qemu/tests/qemu-iotests/061 b/qemu/tests/qemu-iotests/061 index 8d37f8a65..f5678b10c 100755 --- a/qemu/tests/qemu-iotests/061 +++ b/qemu/tests/qemu-iotests/061 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() @@ -58,7 +57,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 +91,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/qemu/tests/qemu-iotests/061.out b/qemu/tests/qemu-iotests/061.out index 5ec248f79..a03732e19 100644 --- a/qemu/tests/qemu-iotests/061.out +++ b/qemu/tests/qemu-iotests/061.out @@ -24,6 +24,11 @@ autoclear_features 0x0 refcount_order 4 header_length 104 +Header extension: +magic 0x6803f857 +length 144 +data <binary> + magic 0x514649fb version 2 backing_file_offset 0x0 @@ -43,11 +48,6 @@ autoclear_features 0x0 refcount_order 4 header_length 72 -Header extension: -magic 0x6803f857 -length 144 -data <binary> - read 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. @@ -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 @@ -76,6 +81,11 @@ autoclear_features 0x0 refcount_order 4 header_length 104 +Header extension: +magic 0x6803f857 +length 144 +data <binary> + ERROR cluster 5 refcount=0 reference=1 ERROR cluster 6 refcount=0 reference=1 Rebuilding refcount structure @@ -100,11 +110,6 @@ autoclear_features 0x0 refcount_order 4 header_length 72 -Header extension: -magic 0x6803f857 -length 144 -data <binary> - read 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. @@ -131,6 +136,11 @@ autoclear_features 0x40000000000 refcount_order 4 header_length 104 +Header extension: +magic 0x6803f857 +length 144 +data <binary> + magic 0x514649fb version 2 backing_file_offset 0x0 @@ -150,11 +160,6 @@ autoclear_features 0x0 refcount_order 4 header_length 72 -Header extension: -magic 0x6803f857 -length 144 -data <binary> - No errors were found on the image. === Testing version upgrade and resize === @@ -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 @@ -233,6 +243,11 @@ autoclear_features 0x0 refcount_order 4 header_length 104 +Header extension: +magic 0x6803f857 +length 144 +data <binary> + ERROR cluster 5 refcount=0 reference=1 ERROR cluster 6 refcount=0 reference=1 Rebuilding refcount structure @@ -281,18 +296,18 @@ No errors were found on the image. === Testing invalid configurations === Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 -Lazy refcounts only supported with compatibility level 1.1 and above (use compat=1.1 or greater) +qemu-img: Lazy refcounts only supported with compatibility level 1.1 and above (use compat=1.1 or greater) qemu-img: Error while amending options: Invalid argument -Lazy refcounts only supported with compatibility level 1.1 and above (use compat=1.1 or greater) +qemu-img: Lazy refcounts only supported with compatibility level 1.1 and above (use compat=1.1 or greater) qemu-img: Error while amending options: Invalid argument -Unknown compatibility level 0.42. +qemu-img: Unknown compatibility level 0.42 qemu-img: Error while amending options: Invalid argument qemu-img: Invalid parameter 'foo' -Changing the cluster size is not supported. +qemu-img: Changing the cluster size is not supported qemu-img: Error while amending options: Operation not supported -Changing the encryption flag is not supported. +qemu-img: Changing the encryption flag is not supported qemu-img: Error while amending options: Operation not supported -Cannot change preallocation mode. +qemu-img: Cannot change preallocation mode qemu-img: Error while amending options: Operation not supported === Testing correct handling of unset value === @@ -300,7 +315,7 @@ qemu-img: Error while amending options: Operation not supported Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 Should work: Should not work: -Changing the cluster size is not supported. +qemu-img: Changing the cluster size is not supported qemu-img: Error while amending options: Operation not supported === Testing zero expansion on inactive clusters === @@ -334,7 +349,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 +365,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 +384,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 +408,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 +423,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/qemu/tests/qemu-iotests/062 b/qemu/tests/qemu-iotests/062 index 0511246de..051fb9f41 100755 --- a/qemu/tests/qemu-iotests/062 +++ b/qemu/tests/qemu-iotests/062 @@ -26,7 +26,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/063 b/qemu/tests/qemu-iotests/063 index a47493a07..352e78c77 100755 --- a/qemu/tests/qemu-iotests/063 +++ b/qemu/tests/qemu-iotests/063 @@ -26,7 +26,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/064 b/qemu/tests/qemu-iotests/064 index 7564563ab..5792fbbc9 100755 --- a/qemu/tests/qemu-iotests/064 +++ b/qemu/tests/qemu-iotests/064 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/066 b/qemu/tests/qemu-iotests/066 index 1c2452b0c..364166d3b 100755 --- a/qemu/tests/qemu-iotests/066 +++ b/qemu/tests/qemu-iotests/066 @@ -25,7 +25,6 @@ seq="$(basename $0)" echo "QA output created by $seq" here="$PWD" -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/067 b/qemu/tests/qemu-iotests/067 index 83eefa394..c1df48ede 100755 --- a/qemu/tests/qemu-iotests/067 +++ b/qemu/tests/qemu-iotests/067 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! # get standard environment, filters and checks @@ -45,10 +44,20 @@ function do_run_qemu() 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' +} + 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 | _filter_qmp_events } size=128M @@ -59,7 +68,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 +85,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 +103,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 +131,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/qemu/tests/qemu-iotests/067.out b/qemu/tests/qemu-iotests/067.out index 6ff41bc7a..7e25a4902 100644 --- a/qemu/tests/qemu-iotests/067.out +++ b/qemu/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" } ] } @@ -91,93 +70,13 @@ Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk -device virti } } { - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "DEVICE_DELETED", - "data": { - "path": "/machine/peripheral/virtio0/virtio-backend" - } -} -{ - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "DEVICE_DELETED", - "data": { - "device": "virtio0", - "path": "/machine/peripheral/virtio0" - } -} -{ - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "RESET" -} -{ "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" - } ] } { "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 - } -} - === -drive/device_add and device_del === @@ -217,6 +116,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, @@ -233,29 +133,6 @@ Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false }, - "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" } ] @@ -273,93 +150,13 @@ Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk } } { - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "DEVICE_DELETED", - "data": { - "path": "/machine/peripheral/virtio0/virtio-backend" - } -} -{ - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "DEVICE_DELETED", - "data": { - "device": "virtio0", - "path": "/machine/peripheral/virtio0" - } -} -{ - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "RESET" -} -{ "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" - } ] } { "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 - } -} - === drive_add/device_add and device_del === @@ -377,28 +174,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 +199,7 @@ Testing: }, "iops_wr": 0, "ro": false, + "node-name": "NODE_NAME", "backing_file_depth": 0, "drv": "qcow2", "iops": 0, @@ -440,7 +216,6 @@ Testing: "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false }, - "tray_open": false, "type": "unknown" } ] @@ -458,93 +233,13 @@ Testing: } } { - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "DEVICE_DELETED", - "data": { - "path": "/machine/peripheral/virtio0/virtio-backend" - } -} -{ - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "DEVICE_DELETED", - "data": { - "device": "virtio0", - "path": "/machine/peripheral/virtio0" - } -} -{ - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "RESET" -} -{ "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" - } ] } { "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 - } -} - === blockdev_add/device_add and device_del === @@ -563,28 +258,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 +283,7 @@ Testing: }, "iops_wr": 0, "ro": false, + "node-name": "NODE_NAME", "backing_file_depth": 0, "drv": "qcow2", "iops": 0, @@ -626,7 +300,6 @@ Testing: "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false }, - "tray_open": false, "type": "unknown" } ] @@ -644,59 +317,9 @@ Testing: } } { - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "DEVICE_DELETED", - "data": { - "path": "/machine/peripheral/virtio0/virtio-backend" - } -} -{ - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "DEVICE_DELETED", - "data": { - "device": "virtio0", - "path": "/machine/peripheral/virtio0" - } -} -{ - "timestamp": { - "seconds": TIMESTAMP, - "microseconds": TIMESTAMP - }, - "event": "RESET" -} -{ "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 +345,7 @@ Testing: }, "iops_wr": 0, "ro": false, + "node-name": "NODE_NAME", "backing_file_depth": 0, "drv": "qcow2", "iops": 0, @@ -738,7 +362,6 @@ Testing: "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false }, - "tray_open": false, "type": "unknown" } ] @@ -747,34 +370,4 @@ Testing: "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/qemu/tests/qemu-iotests/068 b/qemu/tests/qemu-iotests/068 index b72e55599..68f6e825d 100755 --- a/qemu/tests/qemu-iotests/068 +++ b/qemu/tests/qemu-iotests/068 @@ -25,7 +25,6 @@ seq="$(basename $0)" echo "QA output created by $seq" here="$PWD" -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() @@ -50,13 +49,23 @@ echo echo "=== Saving and reloading a VM state to/from a qcow2 image ===" echo _make_test_img $IMG_SIZE + +case "$QEMU_DEFAULT_MACHINE" in + s390-ccw-virtio) + platform_parm="-no-shutdown" + ;; + *) + platform_parm="" + ;; +esac + # Give qemu some time to boot before saving the VM state bash -c 'sleep 1; echo -e "savevm 0\nquit"' |\ - $QEMU -nographic -monitor stdio -serial none -hda "$TEST_IMG" |\ + $QEMU $platform_parm -nographic -monitor stdio -serial none -hda "$TEST_IMG" |\ _filter_qemu # Now try to continue from that VM state (this should just work) echo quit |\ - $QEMU -nographic -monitor stdio -serial none -hda "$TEST_IMG" -loadvm 0 |\ + $QEMU $platform_parm -nographic -monitor stdio -serial none -hda "$TEST_IMG" -loadvm 0 |\ _filter_qemu # success, all done diff --git a/qemu/tests/qemu-iotests/069 b/qemu/tests/qemu-iotests/069 index ce9e0541b..96e55ef21 100755 --- a/qemu/tests/qemu-iotests/069 +++ b/qemu/tests/qemu-iotests/069 @@ -25,7 +25,6 @@ seq="$(basename $0)" echo "QA output created by $seq" here="$PWD" -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/069.out b/qemu/tests/qemu-iotests/069.out index 4d7e63cf8..f97585677 100644 --- a/qemu/tests/qemu-iotests/069.out +++ b/qemu/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' -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 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072 backing_file=TEST_DIR/t.IMGFMT.base +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/qemu/tests/qemu-iotests/070 b/qemu/tests/qemu-iotests/070 index d649ddf9b..8d08d74ff 100755 --- a/qemu/tests/qemu-iotests/070 +++ b/qemu/tests/qemu-iotests/070 @@ -26,7 +26,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/070.out b/qemu/tests/qemu-iotests/070.out index ca743831c..131a5b17d 100644 --- a/qemu/tests/qemu-iotests/070.out +++ b/qemu/tests/qemu-iotests/070.out @@ -1,8 +1,9 @@ QA output created by 070 === Verify open image read-only fails, due to dirty log === -qemu-io: can't open device TEST_DIR/iotest-dirtylog-10G-4M.vhdx: VHDX image file 'TEST_DIR/iotest-dirtylog-10G-4M.vhdx' opened read-only, but contains a log that needs to be replayed. To replay the log, execute: - qemu-img check -r all 'TEST_DIR/iotest-dirtylog-10G-4M.vhdx': Operation not permitted +can't open device TEST_DIR/iotest-dirtylog-10G-4M.vhdx: VHDX image file 'TEST_DIR/iotest-dirtylog-10G-4M.vhdx' opened read-only, but contains a log that needs to be replayed +To replay the log, run: +qemu-img check -r all 'TEST_DIR/iotest-dirtylog-10G-4M.vhdx' no file open, try 'help open' === Verify open image replays log === read 18874368/18874368 bytes at offset 0 diff --git a/qemu/tests/qemu-iotests/071 b/qemu/tests/qemu-iotests/071 index 9eaa49b41..bdfd91fef 100755 --- a/qemu/tests/qemu-iotests/071 +++ b/qemu/tests/qemu-iotests/071 @@ -25,7 +25,6 @@ seq="$(basename $0)" echo "QA output created by $seq" here="$PWD" -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() @@ -104,11 +103,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 +141,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 +180,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 +219,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/qemu/tests/qemu-iotests/071.out b/qemu/tests/qemu-iotests/071.out index 9205ce251..2b40eadae 100644 --- a/qemu/tests/qemu-iotests/071.out +++ b/qemu/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/qemu/tests/qemu-iotests/072 b/qemu/tests/qemu-iotests/072 index e4a723d73..aa027c7d2 100755 --- a/qemu/tests/qemu-iotests/072 +++ b/qemu/tests/qemu-iotests/072 @@ -25,7 +25,6 @@ seq="$(basename $0)" echo "QA output created by $seq" here="$PWD" -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/073 b/qemu/tests/qemu-iotests/073 index 392db5499..ad37a617b 100755 --- a/qemu/tests/qemu-iotests/073 +++ b/qemu/tests/qemu-iotests/073 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/073.out b/qemu/tests/qemu-iotests/073.out index 733d79ca9..de5452492 100644 --- a/qemu/tests/qemu-iotests/073.out +++ b/qemu/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/qemu/tests/qemu-iotests/075 b/qemu/tests/qemu-iotests/075 index 6117660c5..770d51c6c 100755 --- a/qemu/tests/qemu-iotests/075 +++ b/qemu/tests/qemu-iotests/075 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/075.out b/qemu/tests/qemu-iotests/075.out index 5f1d6c120..87beae4e3 100644 --- a/qemu/tests/qemu-iotests/075.out +++ b/qemu/tests/qemu-iotests/075.out @@ -9,30 +9,30 @@ read 512/512 bytes at offset 1048064 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) == block_size must be a multiple of 512 == -qemu-io: can't open device TEST_DIR/simple-pattern.cloop: block_size 513 must be a multiple of 512 +can't open device TEST_DIR/simple-pattern.cloop: block_size 513 must be a multiple of 512 no file open, try 'help open' == block_size cannot be zero == -qemu-io: can't open device TEST_DIR/simple-pattern.cloop: block_size cannot be zero +can't open device TEST_DIR/simple-pattern.cloop: block_size cannot be zero no file open, try 'help open' == huge block_size === -qemu-io: can't open device TEST_DIR/simple-pattern.cloop: block_size 4294966784 must be 64 MB or less +can't open device TEST_DIR/simple-pattern.cloop: block_size 4294966784 must be 64 MB or less no file open, try 'help open' == offsets_size overflow === -qemu-io: can't open device TEST_DIR/simple-pattern.cloop: n_blocks 4294967295 must be 536870911 or less +can't open device TEST_DIR/simple-pattern.cloop: n_blocks 4294967295 must be 536870911 or less no file open, try 'help open' == refuse images that require too many offsets === -qemu-io: can't open device TEST_DIR/simple-pattern.cloop: image requires too many offsets, try increasing block size +can't open device TEST_DIR/simple-pattern.cloop: image requires too many offsets, try increasing block size no file open, try 'help open' == refuse images with non-monotonically increasing offsets == -qemu-io: can't open device TEST_DIR/simple-pattern.cloop: offsets not monotonically increasing at index 1, image file is corrupt +can't open device TEST_DIR/simple-pattern.cloop: offsets not monotonically increasing at index 1, image file is corrupt no file open, try 'help open' == refuse images with invalid compressed block size == -qemu-io: can't open device TEST_DIR/simple-pattern.cloop: invalid compressed block size at index 1, image file is corrupt +can't open device TEST_DIR/simple-pattern.cloop: invalid compressed block size at index 1, image file is corrupt no file open, try 'help open' *** done diff --git a/qemu/tests/qemu-iotests/076 b/qemu/tests/qemu-iotests/076 index c9b55a980..ef9e6a4ff 100755 --- a/qemu/tests/qemu-iotests/076 +++ b/qemu/tests/qemu-iotests/076 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/076.out b/qemu/tests/qemu-iotests/076.out index b0000aeed..72645b252 100644 --- a/qemu/tests/qemu-iotests/076.out +++ b/qemu/tests/qemu-iotests/076.out @@ -5,15 +5,15 @@ read 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) == Negative catalog size == -qemu-io: can't open device TEST_DIR/parallels-v1: Catalog too large +can't open device TEST_DIR/parallels-v1: Catalog too large no file open, try 'help open' == Overflow in catalog allocation == -qemu-io: can't open device TEST_DIR/parallels-v1: Catalog too large +can't open device TEST_DIR/parallels-v1: Catalog too large no file open, try 'help open' == Zero sectors per track == -qemu-io: can't open device TEST_DIR/parallels-v1: Invalid image: Zero sectors per track +can't open device TEST_DIR/parallels-v1: Invalid image: Zero sectors per track no file open, try 'help open' == Read from a valid v2 image == diff --git a/qemu/tests/qemu-iotests/077 b/qemu/tests/qemu-iotests/077 index 42a90850c..4dc680b7f 100755 --- a/qemu/tests/qemu-iotests/077 +++ b/qemu/tests/qemu-iotests/077 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() @@ -63,7 +62,7 @@ EOF off=0x1000 for ev in "head" "after_head" "tail" "after_tail"; do cat <<EOF -break pwritev_rmw.$ev A +break pwritev_rmw_$ev A aio_write -P 10 $((off + 0x200)) 0x200 wait_break A aio_write -P 11 $((off + 0x400)) 0x200 @@ -76,7 +75,7 @@ done # Chained dependencies cat <<EOF -break pwritev_rmw.after_tail A +break pwritev_rmw_after_tail A aio_write -P 10 0x5000 0x200 wait_break A aio_write -P 11 0x5200 0x200 @@ -93,10 +92,10 @@ EOF # Overlapping multiple requests cat <<EOF -break pwritev_rmw.after_tail A +break pwritev_rmw_after_tail A aio_write -P 10 0x6000 0x200 wait_break A -break pwritev_rmw.after_head B +break pwritev_rmw_after_head B aio_write -P 10 0x7e00 0x200 wait_break B aio_write -P 11 0x6800 0x1000 @@ -107,10 +106,10 @@ aio_flush EOF cat <<EOF -break pwritev_rmw.after_tail A +break pwritev_rmw_after_tail A aio_write -P 10 0x8000 0x200 wait_break A -break pwritev_rmw.after_head B +break pwritev_rmw_after_head B aio_write -P 10 0x9e00 0x200 wait_break B aio_write -P 11 0x8800 0x1000 @@ -121,11 +120,11 @@ aio_flush EOF cat <<EOF -break pwritev_rmw.after_tail A +break pwritev_rmw_after_tail A aio_write -P 10 0xa000 0x200 wait_break A aio_write -P 11 0xa800 0x1000 -break pwritev_rmw.after_head B +break pwritev_rmw_after_head B aio_write -P 10 0xbe00 0x200 wait_break B resume A @@ -135,11 +134,11 @@ aio_flush EOF cat <<EOF -break pwritev_rmw.after_tail A +break pwritev_rmw_after_tail A aio_write -P 10 0xc000 0x200 wait_break A aio_write -P 11 0xc800 0x1000 -break pwritev_rmw.after_head B +break pwritev_rmw_after_head B aio_write -P 10 0xde00 0x200 wait_break B resume B @@ -150,7 +149,7 @@ EOF # Only RMW for the tail part cat <<EOF -break pwritev_rmw.after_tail A +break pwritev_rmw_after_tail A aio_write -P 10 0xe000 0x1800 wait_break A aio_write -P 11 0xf000 0xc00 @@ -163,7 +162,7 @@ cat <<EOF break pwritev A aio_write -P 10 0x10000 0x800 wait_break A -break pwritev_rmw.after_tail B +break pwritev_rmw_after_tail B aio_write -P 11 0x10000 0x400 break pwritev_done C resume A diff --git a/qemu/tests/qemu-iotests/078 b/qemu/tests/qemu-iotests/078 index 7be2c3f69..f333e9ac8 100755 --- a/qemu/tests/qemu-iotests/078 +++ b/qemu/tests/qemu-iotests/078 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/078.out b/qemu/tests/qemu-iotests/078.out index ca18d2ea3..42b8a8301 100644 --- a/qemu/tests/qemu-iotests/078.out +++ b/qemu/tests/qemu-iotests/078.out @@ -5,24 +5,24 @@ read 512/512 bytes at offset 0 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) == Negative catalog size == -qemu-io: can't open device TEST_DIR/empty.bochs: Catalog size is too large +can't open device TEST_DIR/empty.bochs: Catalog size is too large no file open, try 'help open' == Overflow for catalog size * sizeof(uint32_t) == -qemu-io: can't open device TEST_DIR/empty.bochs: Catalog size is too large +can't open device TEST_DIR/empty.bochs: Catalog size is too large no file open, try 'help open' == Too small catalog bitmap for image size == -qemu-io: can't open device TEST_DIR/empty.bochs: Catalog size is too small for this disk size +can't open device TEST_DIR/empty.bochs: Catalog size is too small for this disk size no file open, try 'help open' -qemu-io: can't open device TEST_DIR/empty.bochs: Catalog size is too small for this disk size +can't open device TEST_DIR/empty.bochs: Catalog size is too small for this disk size no file open, try 'help open' == Negative extent size == -qemu-io: can't open device TEST_DIR/empty.bochs: Extent size 2147483648 is too large +can't open device TEST_DIR/empty.bochs: Extent size 2147483648 is too large no file open, try 'help open' == Zero extent size == -qemu-io: can't open device TEST_DIR/empty.bochs: Extent size must be at least 512 +can't open device TEST_DIR/empty.bochs: Extent size must be at least 512 no file open, try 'help open' *** done diff --git a/qemu/tests/qemu-iotests/079 b/qemu/tests/qemu-iotests/079 index ade6efa0d..b2e3f7426 100755 --- a/qemu/tests/qemu-iotests/079 +++ b/qemu/tests/qemu-iotests/079 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/079.out b/qemu/tests/qemu-iotests/079.out index 6dc5d5763..aab922fb3 100644 --- a/qemu/tests/qemu-iotests/079.out +++ b/qemu/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/qemu/tests/qemu-iotests/080 b/qemu/tests/qemu-iotests/080 index a2c58aebd..55044c700 100755 --- a/qemu/tests/qemu-iotests/080 +++ b/qemu/tests/qemu-iotests/080 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/080.out b/qemu/tests/qemu-iotests/080.out index 6061d8443..0daac48b1 100644 --- a/qemu/tests/qemu-iotests/080.out +++ b/qemu/tests/qemu-iotests/080.out @@ -2,46 +2,46 @@ QA output created by 080 == Huge header size == Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 -qemu-io: can't open device TEST_DIR/t.qcow2: qcow2 header exceeds cluster size +can't open device TEST_DIR/t.qcow2: qcow2 header exceeds cluster size no file open, try 'help open' -qemu-io: can't open device TEST_DIR/t.qcow2: qcow2 header exceeds cluster size +can't open device TEST_DIR/t.qcow2: qcow2 header exceeds cluster size no file open, try 'help open' == Huge unknown header extension == Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 -qemu-io: can't open device TEST_DIR/t.qcow2: Invalid backing file offset +can't open device TEST_DIR/t.qcow2: Invalid backing file offset no file open, try 'help open' -qemu-io: can't open device TEST_DIR/t.qcow2: Header extension too large +can't open device TEST_DIR/t.qcow2: Header extension too large no file open, try 'help open' -qemu-io: can't open device TEST_DIR/t.qcow2: Header extension too large +can't open device TEST_DIR/t.qcow2: Header extension too large no file open, try 'help open' == Huge refcount table size == Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 -qemu-io: can't open device TEST_DIR/t.qcow2: Reference count table too large +can't open device TEST_DIR/t.qcow2: Reference count table too large no file open, try 'help open' -qemu-io: can't open device TEST_DIR/t.qcow2: Reference count table too large +can't open device TEST_DIR/t.qcow2: Reference count table too large no file open, try 'help open' == Misaligned refcount table == Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 -qemu-io: can't open device TEST_DIR/t.qcow2: Invalid reference count table offset +can't open device TEST_DIR/t.qcow2: Invalid reference count table offset no file open, try 'help open' == Huge refcount offset == Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 -qemu-io: can't open device TEST_DIR/t.qcow2: Invalid reference count table offset +can't open device TEST_DIR/t.qcow2: Invalid reference count table offset no file open, try 'help open' == Invalid snapshot table == Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 -qemu-io: can't open device TEST_DIR/t.qcow2: Too many snapshots +can't open device TEST_DIR/t.qcow2: Too many snapshots no file open, try 'help open' -qemu-io: can't open device TEST_DIR/t.qcow2: Too many snapshots +can't open device TEST_DIR/t.qcow2: Too many snapshots no file open, try 'help open' -qemu-io: can't open device TEST_DIR/t.qcow2: Invalid snapshot table offset +can't open device TEST_DIR/t.qcow2: Invalid snapshot table offset no file open, try 'help open' -qemu-io: can't open device TEST_DIR/t.qcow2: Invalid snapshot table offset +can't open device TEST_DIR/t.qcow2: Invalid snapshot table offset no file open, try 'help open' == Hitting snapshot table size limit == @@ -52,13 +52,13 @@ read 512/512 bytes at offset 0 == Invalid L1 table == Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 -qemu-io: can't open device TEST_DIR/t.qcow2: Active L1 table too large +can't open device TEST_DIR/t.qcow2: Active L1 table too large no file open, try 'help open' -qemu-io: can't open device TEST_DIR/t.qcow2: Active L1 table too large +can't open device TEST_DIR/t.qcow2: Active L1 table too large no file open, try 'help open' -qemu-io: can't open device TEST_DIR/t.qcow2: Invalid L1 table offset +can't open device TEST_DIR/t.qcow2: Invalid L1 table offset no file open, try 'help open' -qemu-io: can't open device TEST_DIR/t.qcow2: Invalid L1 table offset +can't open device TEST_DIR/t.qcow2: Invalid L1 table offset no file open, try 'help open' == Invalid L1 table (with internal snapshot in the image) == @@ -67,7 +67,7 @@ qemu-img: Could not open 'TEST_DIR/t.IMGFMT': L1 table is too small == Invalid backing file size == Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 -qemu-io: can't open device TEST_DIR/t.qcow2: Backing file name too long +can't open device TEST_DIR/t.qcow2: Backing file name too long no file open, try 'help open' == Invalid L2 entry (huge physical offset) == diff --git a/qemu/tests/qemu-iotests/081 b/qemu/tests/qemu-iotests/081 index d9b042cfc..d89fabcdb 100755 --- a/qemu/tests/qemu-iotests/081 +++ b/qemu/tests/qemu-iotests/081 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() @@ -53,7 +52,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 +101,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 +131,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/qemu/tests/qemu-iotests/081.out b/qemu/tests/qemu-iotests/081.out index 9f57d9d3b..97df69d71 100644 --- a/qemu/tests/qemu-iotests/081.out +++ b/qemu/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, "type": "read"}} 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/qemu/tests/qemu-iotests/082 b/qemu/tests/qemu-iotests/082 index c83e01e7c..ad1d9fadc 100755 --- a/qemu/tests/qemu-iotests/082 +++ b/qemu/tests/qemu-iotests/082 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/082.out b/qemu/tests/qemu-iotests/082.out index 3a749b825..a952330ba 100644 --- a/qemu/tests/qemu-iotests/082.out +++ b/qemu/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/qemu/tests/qemu-iotests/083 b/qemu/tests/qemu-iotests/083 index 1b2d3f115..bc724ae05 100755 --- a/qemu/tests/qemu-iotests/083 +++ b/qemu/tests/qemu-iotests/083 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! # get standard environment, filters and checks @@ -49,17 +48,6 @@ wait_for_tcp_port() { done } -filter_nbd() { - # nbd.c error messages contain function names and line numbers that are prone - # to change. Message ordering depends on timing between send and receive - # callbacks sometimes, making them unreliable. - # - # Filter out the TCP port number since this changes between runs. - sed -e 's#^.*nbd\.c:.*##g' \ - -e 's#nbd:127\.0\.0\.1:[^:]*:#nbd:127\.0\.0\.1:PORT:#g' \ - -e 's#\(exportname=foo\|PORT\): Failed to .*$#\1#' -} - check_disconnect() { event=$1 when=$2 @@ -84,7 +72,7 @@ EOF $PYTHON nbd-fault-injector.py $extra_args "127.0.0.1:$port" "$TEST_DIR/nbd-fault-injector.conf" 2>&1 >/dev/null & wait_for_tcp_port "127\\.0\\.0\\.1:$port" - $QEMU_IO -c "read 0 512" "$nbd_url" 2>&1 | _filter_qemu_io | filter_nbd + $QEMU_IO -c "read 0 512" "$nbd_url" 2>&1 | _filter_qemu_io | _filter_nbd echo } diff --git a/qemu/tests/qemu-iotests/083.out b/qemu/tests/qemu-iotests/083.out index 8c1441bf4..ef3d1e32a 100644 --- a/qemu/tests/qemu-iotests/083.out +++ b/qemu/tests/qemu-iotests/083.out @@ -1,138 +1,128 @@ QA output created by 083 === Check disconnect before neg1 === -qemu-io: can't open device nbd:127.0.0.1:PORT:exportname=foo +can't open device nbd:127.0.0.1:PORT:exportname=foo no file open, try 'help open' === Check disconnect after neg1 === -qemu-io: can't open device nbd:127.0.0.1:PORT:exportname=foo +can't open device nbd:127.0.0.1:PORT:exportname=foo no file open, try 'help open' === Check disconnect 8 neg1 === -qemu-io: can't open device nbd:127.0.0.1:PORT:exportname=foo +can't open device nbd:127.0.0.1:PORT:exportname=foo no file open, try 'help open' === Check disconnect 16 neg1 === -qemu-io: can't open device nbd:127.0.0.1:PORT:exportname=foo +can't open device nbd:127.0.0.1:PORT:exportname=foo no file open, try 'help open' === Check disconnect before export === -qemu-io: can't open device nbd:127.0.0.1:PORT:exportname=foo +can't open device nbd:127.0.0.1:PORT:exportname=foo no file open, try 'help open' === Check disconnect after export === -qemu-io: can't open device nbd:127.0.0.1:PORT:exportname=foo +can't open device nbd:127.0.0.1:PORT:exportname=foo no file open, try 'help open' === Check disconnect 4 export === -qemu-io: can't open device nbd:127.0.0.1:PORT:exportname=foo +can't open device nbd:127.0.0.1:PORT:exportname=foo no file open, try 'help open' === Check disconnect 12 export === -qemu-io: can't open device nbd:127.0.0.1:PORT:exportname=foo +can't open device nbd:127.0.0.1:PORT:exportname=foo no file open, try 'help open' === Check disconnect 16 export === -qemu-io: can't open device nbd:127.0.0.1:PORT:exportname=foo +can't open device nbd:127.0.0.1:PORT:exportname=foo no file open, try 'help open' === Check disconnect before neg2 === -qemu-io: can't open device nbd:127.0.0.1:PORT:exportname=foo +can't open device nbd:127.0.0.1:PORT:exportname=foo no file open, try 'help open' === Check disconnect after neg2 === - read failed: Input/output error === Check disconnect 8 neg2 === -qemu-io: can't open device nbd:127.0.0.1:PORT:exportname=foo +can't open device nbd:127.0.0.1:PORT:exportname=foo no file open, try 'help open' === Check disconnect 10 neg2 === -qemu-io: can't open device nbd:127.0.0.1:PORT:exportname=foo +can't open device nbd:127.0.0.1:PORT:exportname=foo no file open, try 'help open' === Check disconnect before request === - read failed: Input/output error === Check disconnect after request === - read failed: Input/output error === Check disconnect before reply === - read failed: Input/output error === Check disconnect after reply === - read failed: Input/output error === Check disconnect 4 reply === - read failed: Input/output error === Check disconnect 8 reply === - read failed: Input/output error === Check disconnect before data === - read failed: Input/output error === Check disconnect after data === - read 512/512 bytes at offset 0 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) === Check disconnect before neg-classic === -qemu-io: can't open device nbd:127.0.0.1:PORT +can't open device nbd:127.0.0.1:PORT no file open, try 'help open' === Check disconnect 8 neg-classic === -qemu-io: can't open device nbd:127.0.0.1:PORT +can't open device nbd:127.0.0.1:PORT no file open, try 'help open' === Check disconnect 16 neg-classic === -qemu-io: can't open device nbd:127.0.0.1:PORT +can't open device nbd:127.0.0.1:PORT no file open, try 'help open' === Check disconnect 24 neg-classic === -qemu-io: can't open device nbd:127.0.0.1:PORT +can't open device nbd:127.0.0.1:PORT no file open, try 'help open' === Check disconnect 28 neg-classic === -qemu-io: can't open device nbd:127.0.0.1:PORT +can't open device nbd:127.0.0.1:PORT no file open, try 'help open' === Check disconnect after neg-classic === - read failed: Input/output error *** done diff --git a/qemu/tests/qemu-iotests/084 b/qemu/tests/qemu-iotests/084 index 733018d4a..04f2aa9d7 100755 --- a/qemu/tests/qemu-iotests/084 +++ b/qemu/tests/qemu-iotests/084 @@ -26,7 +26,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/085 b/qemu/tests/qemu-iotests/085 index 56cd6f89b..aa77eca77 100755 --- a/qemu/tests/qemu-iotests/085 +++ b/qemu/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/qemu/tests/qemu-iotests/085.out b/qemu/tests/qemu-iotests/085.out index 5eb8b947c..01c78d689 100644 --- a/qemu/tests/qemu-iotests/085.out +++ b/qemu/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/qemu/tests/qemu-iotests/086 b/qemu/tests/qemu-iotests/086 index 234eb9a91..cd4494a66 100755 --- a/qemu/tests/qemu-iotests/086 +++ b/qemu/tests/qemu-iotests/086 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() @@ -38,7 +37,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 . ./common.rc . ./common.filter -_supported_fmt qcow2 +_supported_fmt qcow2 raw _supported_proto file nfs _supported_os Linux diff --git a/qemu/tests/qemu-iotests/087 b/qemu/tests/qemu-iotests/087 index 869474994..e7bca37ef 100755 --- a/qemu/tests/qemu-iotests/087 +++ b/qemu/tests/qemu-iotests/087 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! # get standard environment, filters and checks @@ -45,7 +44,8 @@ function do_run_qemu() function run_qemu() { - do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp | _filter_qemu \ + do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qmp \ + | _filter_qemu | _filter_imgfmt \ | sed -e 's/\("actual-size":\s*\)[0-9]\+/\1SIZE/g' } @@ -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/qemu/tests/qemu-iotests/087.out b/qemu/tests/qemu-iotests/087.out index c71bb3aa4..055c553cd 100644 --- a/qemu/tests/qemu-iotests/087.out +++ b/qemu/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 === @@ -23,11 +21,9 @@ QMP_VERSION {"error": {"class": "GenericError", "desc": "Device name 'test-node' conflicts with an existing node name"}} {"error": {"class": "GenericError", "desc": "node-name=disk is conflicting with a device id"}} {"error": {"class": "GenericError", "desc": "Duplicate node name"}} -{"error": {"class": "GenericError", "desc": "node-name=disk3 is conflicting with a device id"}} +{"error": {"class": "GenericError", "desc": "Device name 'disk3' conflicts with an existing node name"}} {"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,52 +34,36 @@ 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 === -qemu-img: Encrypted images are deprecated -Support for them will be removed in a future release. -You can use 'qemu-img convert' to convert your image to an unencrypted one. -qemu-img: Encrypted images are deprecated -Support for them will be removed in a future release. -You can use 'qemu-img convert' to convert your image to an unencrypted one. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on Testing: -S QMP_VERSION {"return": {}} -Encrypted images are deprecated -Support for them will be removed in a future release. -You can use 'qemu-img convert' to convert your image to an unencrypted one. +IMGFMT built-in AES encryption is deprecated +Support for it will be removed in a future release. +You can use 'qemu-img convert' to switch to an +unencrypted IMGFMT image, or a LUKS raw image. {"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 {"return": {}} -Encrypted images are deprecated -Support for them will be removed in a future release. -You can use 'qemu-img convert' to convert your image to an unencrypted one. +IMGFMT built-in AES encryption is deprecated +Support for it will be removed in a future release. +You can use 'qemu-img convert' to switch to an +unencrypted IMGFMT image, or a LUKS raw image. {"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 === -qemu-img: Encrypted images are deprecated -Support for them will be removed in a future release. -You can use 'qemu-img convert' to convert your image to an unencrypted one. -qemu-img: Encrypted images are deprecated -Support for them will be removed in a future release. -You can use 'qemu-img convert' to convert your image to an unencrypted one. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on Testing: -S QMP_VERSION @@ -91,7 +71,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/qemu/tests/qemu-iotests/088 b/qemu/tests/qemu-iotests/088 index f9c312918..b8076f216 100755 --- a/qemu/tests/qemu-iotests/088 +++ b/qemu/tests/qemu-iotests/088 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/088.out b/qemu/tests/qemu-iotests/088.out index 6e6bfcaf9..a2a83b8a1 100644 --- a/qemu/tests/qemu-iotests/088.out +++ b/qemu/tests/qemu-iotests/088.out @@ -2,16 +2,16 @@ QA output created by 088 == Invalid block size == Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 -qemu-io: can't open device TEST_DIR/t.vpc: Invalid block size 0 +can't open device TEST_DIR/t.vpc: Invalid block size 0 no file open, try 'help open' -qemu-io: can't open device TEST_DIR/t.vpc: Invalid block size 0 +can't open device TEST_DIR/t.vpc: Invalid block size 0 no file open, try 'help open' -qemu-io: can't open device TEST_DIR/t.vpc: Invalid block size 128 +can't open device TEST_DIR/t.vpc: Invalid block size 128 no file open, try 'help open' -qemu-io: can't open device TEST_DIR/t.vpc: Invalid block size 128 +can't open device TEST_DIR/t.vpc: Invalid block size 128 no file open, try 'help open' -qemu-io: can't open device TEST_DIR/t.vpc: Invalid block size 305419896 +can't open device TEST_DIR/t.vpc: Invalid block size 305419896 no file open, try 'help open' -qemu-io: can't open device TEST_DIR/t.vpc: Invalid block size 305419896 +can't open device TEST_DIR/t.vpc: Invalid block size 305419896 no file open, try 'help open' *** done diff --git a/qemu/tests/qemu-iotests/089 b/qemu/tests/qemu-iotests/089 index 3e0038dde..9bfe2307b 100755 --- a/qemu/tests/qemu-iotests/089 +++ b/qemu/tests/qemu-iotests/089 @@ -25,7 +25,6 @@ seq="$(basename $0)" echo "QA output created by $seq" here="$PWD" -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/090 b/qemu/tests/qemu-iotests/090 index 70b5a6fd7..7380503d5 100755 --- a/qemu/tests/qemu-iotests/090 +++ b/qemu/tests/qemu-iotests/090 @@ -25,7 +25,6 @@ seq="$(basename $0)" echo "QA output created by $seq" here="$PWD" -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/092 b/qemu/tests/qemu-iotests/092 index 52c529bae..5bbdd071d 100755 --- a/qemu/tests/qemu-iotests/092 +++ b/qemu/tests/qemu-iotests/092 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/092.out b/qemu/tests/qemu-iotests/092.out index c5c60f917..e18f54c20 100644 --- a/qemu/tests/qemu-iotests/092.out +++ b/qemu/tests/qemu-iotests/092.out @@ -2,37 +2,37 @@ QA output created by 092 == Invalid cluster size == Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 -qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k +can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k no file open, try 'help open' -qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k +can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k no file open, try 'help open' -qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k +can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k no file open, try 'help open' -qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k +can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k no file open, try 'help open' == Invalid L2 table size == Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 -qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k +can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k no file open, try 'help open' -qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k +can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k no file open, try 'help open' -qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k +can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k no file open, try 'help open' -qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k +can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k no file open, try 'help open' == Invalid size == Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 -qemu-io: can't open device TEST_DIR/t.qcow: Image too large +can't open device TEST_DIR/t.qcow: Image too large no file open, try 'help open' -qemu-io: can't open device TEST_DIR/t.qcow: Image too large +can't open device TEST_DIR/t.qcow: Image too large no file open, try 'help open' == Invalid backing file length == Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 -qemu-io: can't open device TEST_DIR/t.qcow: Backing file name too long +can't open device TEST_DIR/t.qcow: Backing file name too long no file open, try 'help open' -qemu-io: can't open device TEST_DIR/t.qcow: Backing file name too long +can't open device TEST_DIR/t.qcow: Backing file name too long no file open, try 'help open' *** done diff --git a/qemu/tests/qemu-iotests/093 b/qemu/tests/qemu-iotests/093 index c0e9e2b0b..ce8e13cb4 100755 --- a/qemu/tests/qemu-iotests/093 +++ b/qemu/tests/qemu-iotests/093 @@ -3,7 +3,7 @@ # Tests for IO throttling # # Copyright (C) 2015 Red Hat, Inc. -# Copyright (C) 2015 Igalia, S.L. +# Copyright (C) 2015-2016 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 @@ -21,6 +21,8 @@ import iotests +nsec_per_sec = 1000000000 + class ThrottleTestCase(iotests.QMPTestCase): test_img = "null-aio://" max_drives = 3 @@ -42,16 +44,7 @@ class ThrottleTestCase(iotests.QMPTestCase): def tearDown(self): self.vm.shutdown() - def do_test_throttle(self, ndrives, seconds, params): - def check_limit(limit, num): - # IO throttling algorithm is discrete, allow 10% error so the test - # is more robust - return limit == 0 or \ - (num < seconds * limit * 1.1 / ndrives - and num > seconds * limit * 0.9 / ndrives) - - nsec_per_sec = 1000000000 - + def configure_throttle(self, ndrives, params): params['group'] = 'test' # Set the I/O throttling parameters to all drives @@ -60,13 +53,21 @@ class ThrottleTestCase(iotests.QMPTestCase): result = self.vm.qmp("block_set_io_throttle", conv_keys=False, **params) self.assert_qmp(result, 'return', {}) + def do_test_throttle(self, ndrives, seconds, params): + def check_limit(limit, num): + # IO throttling algorithm is discrete, allow 10% error so the test + # is more robust + return limit == 0 or \ + (num < seconds * limit * 1.1 / ndrives + and num > seconds * limit * 0.9 / ndrives) + # Set vm clock to a known value ns = seconds * nsec_per_sec self.vm.qtest("clock_step %d" % ns) - # Submit enough requests. They will drain bps_max and iops_max, but the - # rest requests won't get executed until we advance the virtual clock - # with qtest interface + # Submit enough requests so the throttling mechanism kicks + # in. The throttled requests won't be executed until we + # advance the virtual clock. rq_size = 512 rd_nr = max(params['bps'] / rq_size / 2, params['bps_rd'] / rq_size, @@ -142,8 +143,44 @@ class ThrottleTestCase(iotests.QMPTestCase): for tk in params: limits = dict([(k, 0) for k in params]) limits[tk] = params[tk] * ndrives + self.configure_throttle(ndrives, limits) self.do_test_throttle(ndrives, 5, limits) + def test_burst(self): + params = {"bps": 4096, + "bps_rd": 4096, + "bps_wr": 4096, + "iops": 10, + "iops_rd": 10, + "iops_wr": 10, + } + ndrives = 1 + # Pick each out of all possible params and test + for tk in params: + rate = params[tk] * ndrives + burst_rate = rate * 7 + burst_length = 4 + + # Configure the throttling settings + settings = dict([(k, 0) for k in params]) + settings[tk] = rate + settings['%s_max' % tk] = burst_rate + settings['%s_max_length' % tk] = burst_length + self.configure_throttle(ndrives, settings) + + # Wait for the bucket to empty so we can do bursts + wait_ns = nsec_per_sec * burst_length * burst_rate / rate + self.vm.qtest("clock_step %d" % wait_ns) + + # Test I/O at the max burst rate + limits = dict([(k, 0) for k in params]) + limits[tk] = burst_rate + self.do_test_throttle(ndrives, burst_length, limits) + + # Now test I/O at the normal rate + limits[tk] = rate + self.do_test_throttle(ndrives, 5, limits) + class ThrottleTestCoroutine(ThrottleTestCase): test_img = "null-co://" diff --git a/qemu/tests/qemu-iotests/093.out b/qemu/tests/qemu-iotests/093.out index fbc63e62f..89968f35d 100644 --- a/qemu/tests/qemu-iotests/093.out +++ b/qemu/tests/qemu-iotests/093.out @@ -1,5 +1,5 @@ -.. +.... ---------------------------------------------------------------------- -Ran 2 tests +Ran 4 tests OK diff --git a/qemu/tests/qemu-iotests/094 b/qemu/tests/qemu-iotests/094 index 27a2be256..0ba0b0c36 100755 --- a/qemu/tests/qemu-iotests/094 +++ b/qemu/tests/qemu-iotests/094 @@ -1,6 +1,6 @@ #!/bin/bash # -# Test case for drive-mirror to NBD (especially bdrv_swap() on NBD BDS) +# Test case for drive-mirror to NBD # # Copyright (C) 2015 Red Hat, Inc. # @@ -25,7 +25,6 @@ seq="$(basename $0)" echo "QA output created by $seq" here="$PWD" -tmp=/tmp/$$ status=1 # failure is the default! trap "exit \$status" 0 1 2 3 15 @@ -50,8 +49,10 @@ _send_qemu_cmd $QEMU_HANDLE \ "{'execute': 'qmp_capabilities'}" \ 'return' -# 'format': 'nbd' is not actually "correct", but this is probably the only way -# to test bdrv_swap() on an NBD BDS +# 'format': 'nbd' is not actually "correct", but this was the only way to +# test the bug fixed in commit f53a829. Though the bug's related code +# bdrv_swap() was replaced later, let's make sure we don't fall in the same +# pit again. _send_qemu_cmd $QEMU_HANDLE \ "{'execute': 'drive-mirror', 'arguments': {'device': 'src', diff --git a/qemu/tests/qemu-iotests/095 b/qemu/tests/qemu-iotests/095 index 6630181a7..dad04b9ac 100755 --- a/qemu/tests/qemu-iotests/095 +++ b/qemu/tests/qemu-iotests/095 @@ -50,17 +50,15 @@ _supported_os Linux size_smaller=5M size_larger=100M -_make_test_img $size_smaller -mv "${TEST_IMG}" "${TEST_IMG}.base" +TEST_IMG="$TEST_IMG.base" _make_test_img $size_smaller -_make_test_img -b "${TEST_IMG}.base" $size_larger -mv "${TEST_IMG}" "${TEST_IMG}.snp1" +TEST_IMG="$TEST_IMG.snp1" _make_test_img -b "$TEST_IMG.base" $size_larger _make_test_img -b "${TEST_IMG}.snp1" $size_larger echo echo "=== Base image info before commit and resize ===" -TEST_IMG="${TEST_IMG}.base" _img_info +TEST_IMG="${TEST_IMG}.base" _img_info | _filter_img_info echo echo === Running QEMU Live Commit Test === @@ -78,7 +76,7 @@ _send_qemu_cmd $h "{ 'execute': 'block-commit', echo echo "=== Base image info after commit and resize ===" -TEST_IMG="${TEST_IMG}.base" _img_info +TEST_IMG="${TEST_IMG}.base" _img_info | _filter_img_info # success, all done echo "*** done" diff --git a/qemu/tests/qemu-iotests/095.out b/qemu/tests/qemu-iotests/095.out index 267c4836e..73875cab4 100644 --- a/qemu/tests/qemu-iotests/095.out +++ b/qemu/tests/qemu-iotests/095.out @@ -1,13 +1,12 @@ 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.base', fmt=IMGFMT size=5242880 +Formatting 'TEST_DIR/t.IMGFMT.snp1', 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 file format: IMGFMT virtual size: 5.0M (5242880 bytes) -cluster_size: 65536 === Running QEMU Live Commit Test === @@ -19,5 +18,4 @@ cluster_size: 65536 image: TEST_DIR/t.IMGFMT.base file format: IMGFMT virtual size: 100M (104857600 bytes) -cluster_size: 65536 *** done diff --git a/qemu/tests/qemu-iotests/096 b/qemu/tests/qemu-iotests/096 new file mode 100644 index 000000000..e34204b8f --- /dev/null +++ b/qemu/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/qemu/tests/qemu-iotests/096.out b/qemu/tests/qemu-iotests/096.out new file mode 100644 index 000000000..ae1213e6f --- /dev/null +++ b/qemu/tests/qemu-iotests/096.out @@ -0,0 +1,5 @@ +. +---------------------------------------------------------------------- +Ran 1 tests + +OK diff --git a/qemu/tests/qemu-iotests/097 b/qemu/tests/qemu-iotests/097 index c7a613b7e..01d8dd033 100755 --- a/qemu/tests/qemu-iotests/097 +++ b/qemu/tests/qemu-iotests/097 @@ -26,7 +26,6 @@ seq="$(basename $0)" echo "QA output created by $seq" here="$PWD" -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/097.out b/qemu/tests/qemu-iotests/097.out index 81651f496..48abd2e64 100644 --- a/qemu/tests/qemu-iotests/097.out +++ b/qemu/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/qemu/tests/qemu-iotests/098 b/qemu/tests/qemu-iotests/098 index e2230ad60..b002e969b 100755 --- a/qemu/tests/qemu-iotests/098 +++ b/qemu/tests/qemu-iotests/098 @@ -25,7 +25,6 @@ seq="$(basename $0)" echo "QA output created by $seq" here="$PWD" -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/098.out b/qemu/tests/qemu-iotests/098.out index e08a189b4..7634d0e8b 100644 --- a/qemu/tests/qemu-iotests/098.out +++ b/qemu/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/qemu/tests/qemu-iotests/099 b/qemu/tests/qemu-iotests/099 index 80f3d9aaf..caaf58eee 100755 --- a/qemu/tests/qemu-iotests/099 +++ b/qemu/tests/qemu-iotests/099 @@ -26,7 +26,6 @@ seq="$(basename $0)" echo "QA output created by $seq" here="$PWD" -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/100 b/qemu/tests/qemu-iotests/100 index 7c1b235b5..5b2fb3333 100755 --- a/qemu/tests/qemu-iotests/100 +++ b/qemu/tests/qemu-iotests/100 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/101 b/qemu/tests/qemu-iotests/101 index 70fbf25f6..ea53f8b8d 100755 --- a/qemu/tests/qemu-iotests/101 +++ b/qemu/tests/qemu-iotests/101 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/102 b/qemu/tests/qemu-iotests/102 index 161b1974c..64b4af944 100755 --- a/qemu/tests/qemu-iotests/102 +++ b/qemu/tests/qemu-iotests/102 @@ -25,7 +25,6 @@ seq=$(basename $0) echo "QA output created by $seq" here=$PWD -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/103 b/qemu/tests/qemu-iotests/103 index fa9a3c1fc..ecbd8ebd7 100755 --- a/qemu/tests/qemu-iotests/103 +++ b/qemu/tests/qemu-iotests/103 @@ -25,7 +25,6 @@ seq=$(basename $0) echo "QA output created by $seq" here=$PWD -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/103.out b/qemu/tests/qemu-iotests/103.out index d05f49fdb..b7aaadf89 100644 --- a/qemu/tests/qemu-iotests/103.out +++ b/qemu/tests/qemu-iotests/103.out @@ -5,10 +5,10 @@ wrote 65536/65536 bytes at offset 0 === Testing invalid option combinations === -qemu-io: can't open device TEST_DIR/t.IMGFMT: cache-size, l2-cache-size and refcount-cache-size may not be set the same time -qemu-io: can't open device TEST_DIR/t.IMGFMT: l2-cache-size may not exceed cache-size -qemu-io: can't open device TEST_DIR/t.IMGFMT: refcount-cache-size may not exceed cache-size -qemu-io: can't open device TEST_DIR/t.IMGFMT: cache-size, l2-cache-size and refcount-cache-size may not be set the same time +can't open device TEST_DIR/t.IMGFMT: cache-size, l2-cache-size and refcount-cache-size may not be set the same time +can't open device TEST_DIR/t.IMGFMT: l2-cache-size may not exceed cache-size +can't open device TEST_DIR/t.IMGFMT: refcount-cache-size may not exceed cache-size +can't open device TEST_DIR/t.IMGFMT: cache-size, l2-cache-size and refcount-cache-size may not be set the same time === Testing valid option combinations === diff --git a/qemu/tests/qemu-iotests/104 b/qemu/tests/qemu-iotests/104 index 2e35ea80d..726d46705 100755 --- a/qemu/tests/qemu-iotests/104 +++ b/qemu/tests/qemu-iotests/104 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! trap "exit \$status" 0 1 2 3 15 diff --git a/qemu/tests/qemu-iotests/105 b/qemu/tests/qemu-iotests/105 index 9bae49e32..3db4ce3cf 100755 --- a/qemu/tests/qemu-iotests/105 +++ b/qemu/tests/qemu-iotests/105 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/107 b/qemu/tests/qemu-iotests/107 index 986203046..d7222dc1c 100755 --- a/qemu/tests/qemu-iotests/107 +++ b/qemu/tests/qemu-iotests/107 @@ -25,7 +25,6 @@ seq="$(basename $0)" echo "QA output created by $seq" here="$PWD" -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/108 b/qemu/tests/qemu-iotests/108 index ce447498e..2355d98c1 100755 --- a/qemu/tests/qemu-iotests/108 +++ b/qemu/tests/qemu-iotests/108 @@ -26,7 +26,6 @@ seq="$(basename $0)" echo "QA output created by $seq" here="$PWD" -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/109 b/qemu/tests/qemu-iotests/109 index 0b668da85..f980b0c9e 100755 --- a/qemu/tests/qemu-iotests/109 +++ b/qemu/tests/qemu-iotests/109 @@ -25,7 +25,6 @@ seq="$(basename $0)" echo "QA output created by $seq" here="$PWD" -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/109.out b/qemu/tests/qemu-iotests/109.out index 7db92c9ce..38bc073a3 100644 --- a/qemu/tests/qemu-iotests/109.out +++ b/qemu/tests/qemu-iotests/109.out @@ -2,8 +2,8 @@ QA output created by 109 === Writing a qcow header into raw === -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 -Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864 {"return": {}} WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. @@ -23,15 +23,15 @@ Images are identical. === Writing a qcow2 header into raw === -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 -Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864 {"return": {}} WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. Specify the 'raw' format explicitly to remove the restrictions. {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}} -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 197120, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 197120, "offset": 512, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} {"return": []} read 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -44,15 +44,15 @@ Images are identical. === Writing a qed header into raw === -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 -Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864 {"return": {}} WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. Specify the 'raw' format explicitly to remove the restrictions. {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}} -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 327680, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 327680, "offset": 262144, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} {"return": []} read 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -65,8 +65,8 @@ Images are identical. === Writing a vdi header into raw === -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 -Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864 {"return": {}} WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. @@ -86,8 +86,8 @@ Images are identical. === Writing a vmdk header into raw === -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 -Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864 {"return": {}} WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. @@ -107,8 +107,8 @@ Images are identical. === Writing a vpc header into raw === -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 -Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.raw.src', fmt=IMGFMT size=67108864 {"return": {}} WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. @@ -128,7 +128,7 @@ Images are identical. === Copying sample image empty.bochs into raw === -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 {"return": {}} WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. @@ -149,7 +149,7 @@ Images are identical. === Copying sample image iotest-dirtylog-10G-4M.vhdx into raw === -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 {"return": {}} WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. @@ -170,7 +170,7 @@ Images are identical. === Copying sample image parallels-v1 into raw === -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 {"return": {}} WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. @@ -191,7 +191,7 @@ Images are identical. === Copying sample image simple-pattern.cloop into raw === -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 {"return": {}} WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. @@ -212,7 +212,7 @@ Images are identical. === Write legitimate MBR into raw === -Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 {"return": {}} WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed raw. Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted. diff --git a/qemu/tests/qemu-iotests/110 b/qemu/tests/qemu-iotests/110 index a687f9567..9de7369f3 100755 --- a/qemu/tests/qemu-iotests/110 +++ b/qemu/tests/qemu-iotests/110 @@ -25,7 +25,6 @@ seq="$(basename $0)" echo "QA output created by $seq" here="$PWD" -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/110.out b/qemu/tests/qemu-iotests/110.out index 152bacf41..b3584ff87 100644 --- a/qemu/tests/qemu-iotests/110.out +++ b/qemu/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) @@ -11,9 +11,12 @@ backing file: t.IMGFMT.base (actual path: TEST_DIR/t.IMGFMT.base) === Non-reconstructable filename === -qemu-img: Cannot use relative backing file names for 'json:{"driver": "IMGFMT", "file": {"set-state.0.event": "read_aio", "image": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "driver": "blkdebug", "set-state.0.new_state": 42}}' +image: json:{"driver": "IMGFMT", "file": {"set-state.0.event": "read_aio", "image": {"driver": "file", "filename": "TEST_DIR/t.IMGFMT"}, "driver": "blkdebug", "set-state.0.new_state": 42}} +file format: IMGFMT +virtual size: 64M (67108864 bytes) +backing file: t.IMGFMT.base (cannot determine actual path) === 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/qemu/tests/qemu-iotests/111 b/qemu/tests/qemu-iotests/111 index 6011c94b7..a1c152d0c 100755 --- a/qemu/tests/qemu-iotests/111 +++ b/qemu/tests/qemu-iotests/111 @@ -26,7 +26,6 @@ seq="$(basename $0)" echo "QA output created by $seq" here="$PWD" -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/112 b/qemu/tests/qemu-iotests/112 index 3f054a3fc..28eb9aae9 100755 --- a/qemu/tests/qemu-iotests/112 +++ b/qemu/tests/qemu-iotests/112 @@ -25,7 +25,6 @@ seq="$(basename $0)" echo "QA output created by $seq" here="$PWD" -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() @@ -180,6 +179,115 @@ $QEMU_IMG snapshot -c foo "$TEST_IMG" # leaked (refcount=UINT64_MAX reference=1) _check_test_img +echo +echo '=== Amend from refcount_bits=16 to refcount_bits=1 ===' +echo + +_make_test_img 64M +print_refcount_bits + +$QEMU_IO -c 'write 16M 32M' "$TEST_IMG" | _filter_qemu_io +$QEMU_IMG amend -o refcount_bits=1 "$TEST_IMG" +_check_test_img +print_refcount_bits + +echo +echo '=== Amend from refcount_bits=1 to refcount_bits=64 ===' +echo + +$QEMU_IMG amend -o refcount_bits=64 "$TEST_IMG" +_check_test_img +print_refcount_bits + +echo +echo '=== Amend to compat=0.10 ===' +echo + +# Should not work because refcount_bits needs to be 16 for compat=0.10 +$QEMU_IMG amend -o compat=0.10 "$TEST_IMG" +print_refcount_bits +# Should work +$QEMU_IMG amend -o compat=0.10,refcount_bits=16 "$TEST_IMG" +_check_test_img +print_refcount_bits + +# Get back to compat=1.1 and refcount_bits=16 +$QEMU_IMG amend -o compat=1.1 "$TEST_IMG" +print_refcount_bits +# Should not work +$QEMU_IMG amend -o refcount_bits=32,compat=0.10 "$TEST_IMG" +print_refcount_bits + +echo +echo '=== Amend with snapshot ===' +echo + +$QEMU_IMG snapshot -c foo "$TEST_IMG" +# Just to have different refcounts across the image +$QEMU_IO -c 'write 0 16M' "$TEST_IMG" | _filter_qemu_io + +# Should not work (may work in the future by first decreasing all refcounts so +# they fit into the target range by copying them) +$QEMU_IMG amend -o refcount_bits=1 "$TEST_IMG" +_check_test_img +print_refcount_bits + +# Should work +$QEMU_IMG amend -o refcount_bits=2 "$TEST_IMG" +_check_test_img +print_refcount_bits + +echo +echo '=== Testing too many references for check ===' +echo + +IMGOPTS="$IMGOPTS,refcount_bits=1" _make_test_img 64M +print_refcount_bits + +# This cluster should be created at 0x50000 +$QEMU_IO -c 'write 0 64k' "$TEST_IMG" | _filter_qemu_io +# Now make the second L2 entry (the L2 table should be at 0x40000) point to that +# cluster, so we have two references +poke_file "$TEST_IMG" $((0x40008)) "\x80\x00\x00\x00\x00\x05\x00\x00" + +# This should say "please use amend" +_check_test_img -r all + +# So we do that +$QEMU_IMG amend -o refcount_bits=2 "$TEST_IMG" +print_refcount_bits + +# And try again +_check_test_img -r all + +echo +echo '=== Multiple walks necessary during amend ===' +echo + +IMGOPTS="$IMGOPTS,refcount_bits=1,cluster_size=512" _make_test_img 64k + +# Cluster 0 is the image header, clusters 1 to 4 are used by the L1 table, a +# single L2 table, the reftable and a single refblock. This creates 58 data +# clusters (actually, the L2 table is created here, too), so in total there are +# then 63 used clusters in the image. With a refcount width of 64, one refblock +# describes 64 clusters (512 bytes / 64 bits/entry = 64 entries), so this will +# make the first refblock in the amended image have exactly one free entry. +$QEMU_IO -c "write 0 $((58 * 512))" "$TEST_IMG" | _filter_qemu_io + +# Now change the refcount width; since the first new refblock will have exactly +# one free entry, that entry will be used to store its own reference. No other +# refblocks are needed, so then the new reftable will be allocated; since the +# first new refblock is completely filled up, this will require a new refblock +# which is why the refcount width changing function will need to run through +# everything one more time until the allocations are stable. +# Having more walks than usual should be visible as regressing progress (from +# 66.67 % (2/3 walks) to 50.00 % (2/4 walks)). +$QEMU_IMG amend -o refcount_bits=64 -p "$TEST_IMG" | tr '\r' '\n' \ + | grep -A 1 '66.67' +print_refcount_bits + +_check_test_img + # success, all done echo '*** done' diff --git a/qemu/tests/qemu-iotests/112.out b/qemu/tests/qemu-iotests/112.out index 9a98633f6..81b04d145 100644 --- a/qemu/tests/qemu-iotests/112.out +++ b/qemu/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 === @@ -81,4 +81,75 @@ Leaked cluster 6 refcount=1 reference=0 2 leaked clusters were found on the image. This means waste of disk space, but no harm to data. + +=== Amend from refcount_bits=16 to refcount_bits=1 === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +refcount bits: 16 +wrote 33554432/33554432 bytes at offset 16777216 +32 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +No errors were found on the image. +refcount bits: 1 + +=== Amend from refcount_bits=1 to refcount_bits=64 === + +No errors were found on the image. +refcount bits: 64 + +=== Amend to compat=0.10 === + +qemu-img: compat=0.10 requires refcount_bits=16 +qemu-img: Error while amending options: Operation not supported +refcount bits: 64 +No errors were found on the image. +refcount bits: 16 +refcount bits: 16 +qemu-img: Different refcount widths than 16 bits require compatibility level 1.1 or above (use compat=1.1 or greater) +qemu-img: Error while amending options: Invalid argument +refcount bits: 16 + +=== Amend with snapshot === + +wrote 16777216/16777216 bytes at offset 0 +16 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +qemu-img: Cannot decrease refcount entry width to 1 bits: Cluster at offset 0x50000 has a refcount of 2 +qemu-img: Error while amending options: Invalid argument +No errors were found on the image. +refcount bits: 16 +No errors were found on the image. +refcount bits: 2 + +=== Testing too many references for check === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 +refcount bits: 1 +wrote 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +ERROR: overflow cluster offset=0x50000 +Use qemu-img amend to increase the refcount entry width or qemu-img convert to create a clean copy if the image cannot be opened for writing + +1 errors were found on the image. +Data may be corrupted, or further writes to the image may corrupt it. +refcount bits: 2 +ERROR cluster 5 refcount=1 reference=2 +Repairing cluster 5 refcount=1 reference=2 +Repairing OFLAG_COPIED data cluster: l2_entry=8000000000050000 refcount=2 +Repairing OFLAG_COPIED data cluster: l2_entry=8000000000050000 refcount=2 +The following inconsistencies were found and repaired: + + 0 leaked clusters + 3 corruptions + +Double checking the fixed image now... +No errors were found on the image. + +=== Multiple walks necessary during amend === + +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=65536 +wrote 29696/29696 bytes at offset 0 +29 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + (66.67/100%) + (50.00/100%) +refcount bits: 64 +No errors were found on the image. *** done diff --git a/qemu/tests/qemu-iotests/113 b/qemu/tests/qemu-iotests/113 index a2cd96b17..19b68b272 100755 --- a/qemu/tests/qemu-iotests/113 +++ b/qemu/tests/qemu-iotests/113 @@ -26,7 +26,6 @@ seq="$(basename $0)" echo "QA output created by $seq" here="$PWD" -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/114 b/qemu/tests/qemu-iotests/114 index d02e7ffbe..f110d4f65 100755 --- a/qemu/tests/qemu-iotests/114 +++ b/qemu/tests/qemu-iotests/114 @@ -25,7 +25,6 @@ seq="$(basename $0)" echo "QA output created by $seq" here="$PWD" -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/114.out b/qemu/tests/qemu-iotests/114.out index 6c6b21085..b6d10e480 100644 --- a/qemu/tests/qemu-iotests/114.out +++ b/qemu/tests/qemu-iotests/114.out @@ -1,13 +1,13 @@ 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) cluster_size: 65536 backing file: TEST_DIR/t.IMGFMT.base backing file format: foo -qemu-io: can't open device TEST_DIR/t.qcow2: Could not open backing file: Unknown driver 'foo' +can't open device TEST_DIR/t.qcow2: Could not open backing file: Unknown driver 'foo' read 4096/4096 bytes at offset 0 4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) *** done diff --git a/qemu/tests/qemu-iotests/115 b/qemu/tests/qemu-iotests/115 index a6be1876a..665c2ead4 100755 --- a/qemu/tests/qemu-iotests/115 +++ b/qemu/tests/qemu-iotests/115 @@ -25,7 +25,6 @@ seq="$(basename $0)" echo "QA output created by $seq" here="$PWD" -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/115.out b/qemu/tests/qemu-iotests/115.out index 7b2c5e02f..dbdad17b2 100644 --- a/qemu/tests/qemu-iotests/115.out +++ b/qemu/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/qemu/tests/qemu-iotests/116 b/qemu/tests/qemu-iotests/116 index 713ed484b..df0172fed 100755 --- a/qemu/tests/qemu-iotests/116 +++ b/qemu/tests/qemu-iotests/116 @@ -28,7 +28,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/116.out b/qemu/tests/qemu-iotests/116.out index b679ceea6..1f11d4446 100644 --- a/qemu/tests/qemu-iotests/116.out +++ b/qemu/tests/qemu-iotests/116.out @@ -2,36 +2,36 @@ QA output created by 116 == truncated header cluster == Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 -qemu-io: can't open device TEST_DIR/t.qed: Could not open 'TEST_DIR/t.qed': Invalid argument +can't open device TEST_DIR/t.qed: Could not open 'TEST_DIR/t.qed': Invalid argument no file open, try 'help open' == invalid header magic == Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 -qemu-io: can't open device TEST_DIR/t.qed: Image not in QED format +can't open device TEST_DIR/t.qed: Image not in QED format no file open, try 'help open' == invalid cluster size == Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 -qemu-io: can't open device TEST_DIR/t.qed: Could not open 'TEST_DIR/t.qed': Invalid argument +can't open device TEST_DIR/t.qed: Could not open 'TEST_DIR/t.qed': Invalid argument no file open, try 'help open' == invalid table size == Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 -qemu-io: can't open device TEST_DIR/t.qed: Could not open 'TEST_DIR/t.qed': Invalid argument +can't open device TEST_DIR/t.qed: Could not open 'TEST_DIR/t.qed': Invalid argument no file open, try 'help open' == invalid header size == Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 -qemu-io: can't open device TEST_DIR/t.qed: Could not open 'TEST_DIR/t.qed': Invalid argument +can't open device TEST_DIR/t.qed: Could not open 'TEST_DIR/t.qed': Invalid argument no file open, try 'help open' == invalid L1 table offset == Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 -qemu-io: can't open device TEST_DIR/t.qed: Could not open 'TEST_DIR/t.qed': Invalid argument +can't open device TEST_DIR/t.qed: Could not open 'TEST_DIR/t.qed': Invalid argument no file open, try 'help open' == invalid image size == Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 -qemu-io: can't open device TEST_DIR/t.qed: Could not open 'TEST_DIR/t.qed': Invalid argument +can't open device TEST_DIR/t.qed: Could not open 'TEST_DIR/t.qed': Invalid argument no file open, try 'help open' *** done diff --git a/qemu/tests/qemu-iotests/117 b/qemu/tests/qemu-iotests/117 new file mode 100755 index 000000000..9385b3f8d --- /dev/null +++ b/qemu/tests/qemu-iotests/117 @@ -0,0 +1,85 @@ +#!/bin/bash +# +# Test case for shared BDS between backend trees +# +# 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=mreitz@redhat.com + +seq="$(basename $0)" +echo "QA output created by $seq" + +here="$PWD" +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 file +_supported_os Linux + +_make_test_img 64k + +_launch_qemu + +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'qmp_capabilities' }" \ + 'return' + +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'blockdev-add', + 'arguments': { 'options': { 'id': 'protocol', + 'driver': 'file', + 'filename': '$TEST_IMG' } } }" \ + 'return' + +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'blockdev-add', + 'arguments': { 'options': { 'id': 'format', + 'driver': '$IMGFMT', + 'file': 'protocol' } } }" \ + 'return' + +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'human-monitor-command', + 'arguments': { 'command-line': 'qemu-io format \"write -P 42 0 64k\"' } }" \ + 'return' + +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'quit' }" \ + 'return' + +wait=1 _cleanup_qemu + +_check_test_img + +$QEMU_IO -c 'read -P 42 0 64k' "$TEST_IMG" | _filter_qemu_io + +# success, all done +echo '*** done' +rm -f $seq.full +status=0 diff --git a/qemu/tests/qemu-iotests/117.out b/qemu/tests/qemu-iotests/117.out new file mode 100644 index 000000000..f52dc1a35 --- /dev/null +++ b/qemu/tests/qemu-iotests/117.out @@ -0,0 +1,14 @@ +QA output created by 117 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=65536 +{"return": {}} +{"return": {}} +{"return": {}} +wrote 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{"return": ""} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"} +No errors were found on the image. +read 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +*** done diff --git a/qemu/tests/qemu-iotests/118 b/qemu/tests/qemu-iotests/118 new file mode 100755 index 000000000..9e5951f64 --- /dev/null +++ b/qemu/tests/qemu-iotests/118 @@ -0,0 +1,677 @@ +#!/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): + if not self.has_real_tray: + return + + 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): + if not self.has_real_tray: + return + + 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') + if self.has_real_tray: + 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') + if self.has_real_tray: + 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') + if self.has_real_tray: + 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') + if self.has_real_tray: + 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') + if self.has_real_tray: + 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') + if self.has_real_tray: + 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: + self.assert_qmp(result, 'return[0]/tray_open', False) + 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') + if self.has_real_tray: + 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', {}) + + self.wait_for_close() + + result = self.vm.qmp('query-block') + if self.has_real_tray: + self.assert_qmp(result, 'return[0]/tray_open', False) + 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') + if self.has_real_tray: + 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') + if self.has_real_tray: + 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') + if self.has_real_tray: + 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') + if self.has_real_tray: + 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') + if self.has_real_tray: + 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') + if self.has_real_tray: + 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 not self.has_real_tray: + 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 not self.has_real_tray: + 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]/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', {}) + + result = self.vm.qmp('query-block') + 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]/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', {}) + + result = self.vm.qmp('query-block') + 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]/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]/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]/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', {}) + + result = self.vm.qmp('query-block') + 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]/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', {}) + + result = self.vm.qmp('query-block') + 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]/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', {}) + + result = self.vm.qmp('query-block') + 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]/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') + + result = self.vm.qmp('query-block') + 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]/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', {}) + + result = self.vm.qmp('query-block') + 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]/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') + + result = self.vm.qmp('query-block') + 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]/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('query-block') + 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_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]/inserted/ro', True) + self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img) + + result = self.vm.qmp('query-block') + 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]/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]/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) + # Need to support image creation + iotests.main(supported_fmts=['vpc', 'parallels', 'qcow', 'vdi', 'qcow2', + 'vmdk', 'raw', 'vhdx', 'qed']) diff --git a/qemu/tests/qemu-iotests/118.out b/qemu/tests/qemu-iotests/118.out new file mode 100644 index 000000000..6a917130b --- /dev/null +++ b/qemu/tests/qemu-iotests/118.out @@ -0,0 +1,5 @@ +........................................................... +---------------------------------------------------------------------- +Ran 59 tests + +OK diff --git a/qemu/tests/qemu-iotests/119 b/qemu/tests/qemu-iotests/119 index 9a11f1b92..4f34fb434 100755 --- a/qemu/tests/qemu-iotests/119 +++ b/qemu/tests/qemu-iotests/119 @@ -26,7 +26,6 @@ seq="$(basename $0)" echo "QA output created by $seq" here="$PWD" -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() @@ -49,7 +48,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/qemu/tests/qemu-iotests/120 b/qemu/tests/qemu-iotests/120 index 9f1307876..4f88a67fe 100755 --- a/qemu/tests/qemu-iotests/120 +++ b/qemu/tests/qemu-iotests/120 @@ -26,7 +26,6 @@ seq="$(basename $0)" echo "QA output created by $seq" here="$PWD" -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() @@ -49,7 +48,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/qemu/tests/qemu-iotests/121 b/qemu/tests/qemu-iotests/121 index 0912c3f0c..1307b4e32 100755 --- a/qemu/tests/qemu-iotests/121 +++ b/qemu/tests/qemu-iotests/121 @@ -25,7 +25,6 @@ seq="$(basename $0)" echo "QA output created by $seq" here="$PWD" -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/121.out b/qemu/tests/qemu-iotests/121.out index ff18e2c61..5961a44cd 100644 --- a/qemu/tests/qemu-iotests/121.out +++ b/qemu/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/qemu/tests/qemu-iotests/122 b/qemu/tests/qemu-iotests/122 index 350ca9c46..45b359c2b 100755 --- a/qemu/tests/qemu-iotests/122 +++ b/qemu/tests/qemu-iotests/122 @@ -25,7 +25,6 @@ seq="$(basename $0)" echo "QA output created by $seq" here="$PWD" -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/122.out b/qemu/tests/qemu-iotests/122.out index 1f853b9e9..98814de5d 100644 --- a/qemu/tests/qemu-iotests/122.out +++ b/qemu/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 @@ -112,20 +112,18 @@ read 3145728/3145728 bytes at offset 0 3 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 63963136/63963136 bytes at offset 3145728 61 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -[{ "start": 0, "length": 6291456, "depth": 0, "zero": false, "data": true, "offset": 327680}, -{ "start": 6291456, "length": 60817408, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 67108864, "depth": 0, "zero": false, "data": true, "offset": 327680}] convert -c -S 0: read 3145728/3145728 bytes at offset 0 3 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 63963136/63963136 bytes at offset 3145728 61 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -[{ "start": 0, "length": 6291456, "depth": 0, "zero": false, "data": true}, -{ "start": 6291456, "length": 60817408, "depth": 0, "zero": true, "data": false}] +[{ "start": 0, "length": 67108864, "depth": 0, "zero": false, "data": true}] 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/qemu/tests/qemu-iotests/123 b/qemu/tests/qemu-iotests/123 index ad608035d..b18e3fca9 100755 --- a/qemu/tests/qemu-iotests/123 +++ b/qemu/tests/qemu-iotests/123 @@ -25,7 +25,6 @@ seq="$(basename $0)" echo "QA output created by $seq" here="$PWD" -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/124 b/qemu/tests/qemu-iotests/124 index 9ccd11809..de7cdbe00 100644 --- a/qemu/tests/qemu-iotests/124 +++ b/qemu/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 @@ -74,24 +91,31 @@ class Bitmap: try_remove(image) -class TestIncrementalBackup(iotests.QMPTestCase): - def setUp(self): +class TestIncrementalBackupBase(iotests.QMPTestCase): + def __init__(self, *args): + super(TestIncrementalBackupBase, self).__init__(*args) self.bitmaps = list() self.files = list() self.drives = list() self.vm = iotests.VM() self.err_img = os.path.join(iotests.test_dir, 'err.%s' % iotests.imgfmt) + + def setUp(self): # Create a base image with a distinctive patterning drive0 = self.add_node('drive0') self.img_create(drive0['file'], drive0['fmt']) self.vm.add_drive(drive0['file']) - io_write_patterns(drive0['file'], (('0x41', 0, 512), - ('0xd5', '1M', '32k'), - ('0xdc', '32M', '124k'))) + self.write_default_pattern(drive0['file']) self.vm.launch() + def write_default_pattern(self, target): + io_write_patterns(target, (('0x41', 0, 512), + ('0xd5', '1M', '32k'), + ('0xdc', '32M', '124k'))) + + def add_node(self, node_id, fmt=iotests.imgfmt, path=None, backup=None): if path is None: path = os.path.join(iotests.test_dir, '%s.%s' % (node_id, fmt)) @@ -108,23 +132,28 @@ class TestIncrementalBackup(iotests.QMPTestCase): def img_create(self, img, fmt=iotests.imgfmt, size='64M', - parent=None, parentFormat=None): + parent=None, parentFormat=None, **kwargs): + optargs = [] + for k,v in kwargs.iteritems(): + optargs = optargs + ['-o', '%s=%s' % (k,v)] + args = ['create', '-f', fmt] + optargs + [img, size] if parent: if parentFormat is None: parentFormat = fmt - iotests.qemu_img('create', '-f', fmt, img, size, - '-b', parent, '-F', parentFormat) - else: - iotests.qemu_img('create', '-f', fmt, img, size) + args = args + ['-b', parent, '-F', parentFormat] + iotests.qemu_img(*args) self.files.append(img) 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 +168,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] @@ -233,6 +268,16 @@ class TestIncrementalBackup(iotests.QMPTestCase): self.check_backups() + def tearDown(self): + self.vm.shutdown() + for bitmap in self.bitmaps: + bitmap.cleanup() + for filename in self.files: + try_remove(filename) + + + +class TestIncrementalBackup(TestIncrementalBackupBase): def test_incremental_simple(self): ''' Test: Create and verify three incremental backups. @@ -264,19 +309,110 @@ class TestIncrementalBackup(iotests.QMPTestCase): return self.do_incremental_simple(granularity=131072) - def test_incremental_failure(self): - '''Test: Verify backups made after a failure are correct. + def test_larger_cluster_target(self): + ''' + Test: Create and verify backups made to a larger cluster size target. - Simulate a failure during an incremental backup block job, - emulate additional writes, then create another incremental backup - afterwards and verify that the backup created is correct. + With a default granularity of 64KiB, verify that backups made to a + larger cluster size target of 128KiB without a backing file works. ''' + drive0 = self.drives[0] + + # Create a cluster_size=128k full backup / "anchor" backup + self.img_create(drive0['backup'], cluster_size='128k') + self.assertTrue(self.do_qmp_backup(device=drive0['id'], sync='full', + format=drive0['fmt'], + target=drive0['backup'], + mode='existing')) + + # Create bitmap and dirty it with some new writes. + # overwrite [32736, 32799] which will dirty bitmap clusters at + # 32M-64K and 32M. 32M+64K will be left undirtied. + bitmap0 = self.add_bitmap('bitmap0', drive0) + self.hmp_io_writes(drive0['id'], + (('0xab', 0, 512), + ('0xfe', '16M', '256k'), + ('0x64', '32736k', '64k'))) + + + # Prepare a cluster_size=128k backup target without a backing file. + (target, _) = bitmap0.new_target() + self.img_create(target, bitmap0.drive['fmt'], cluster_size='128k') + + # Perform Incremental Backup + self.assertTrue(self.do_qmp_backup(device=bitmap0.drive['id'], + sync='incremental', + bitmap=bitmap0.name, + format=bitmap0.drive['fmt'], + target=target, + mode='existing')) + self.make_reference_backup(bitmap0) + + # Add the backing file, then compare and exit. + iotests.qemu_img('rebase', '-f', drive0['fmt'], '-u', '-b', + drive0['backup'], '-F', drive0['fmt'], target) + self.vm.shutdown() + self.check_backups() + + + 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() - # Create a blkdebug interface to this img as 'drive1', - # but don't actually create a new image. - drive1 = self.add_node('drive1', self.drives[0]['fmt'], - path=self.drives[0]['file'], - backup=self.drives[0]['backup']) + + 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'], @@ -302,21 +438,73 @@ class TestIncrementalBackup(iotests.QMPTestCase): }) self.assert_qmp(result, 'return', {}) - self.create_anchor_backup(self.drives[0]) - self.add_bitmap('bitmap0', drive1) - # Note: at this point, during a normal execution, - # Assume that the VM resumes and begins issuing IO requests here. + # 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)) - self.hmp_io_writes(drive1['id'], (('0xab', 0, 512), + # 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', {}) - result = self.create_incremental(validate=False) - self.assertFalse(result) - self.hmp_io_writes(drive1['id'], (('0x9a', 0, 512), - ('0x55', '8M', '352k'), - ('0x78', '15872k', '1M'))) - self.create_incremental() + # 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() @@ -351,12 +539,66 @@ class TestIncrementalBackup(iotests.QMPTestCase): granularity=64000) - def tearDown(self): +class TestIncrementalBackupBlkdebug(TestIncrementalBackupBase): + '''Incremental backup tests that utilize a BlkDebug filter on drive0.''' + + def setUp(self): + drive0 = self.add_node('drive0') + self.img_create(drive0['file'], drive0['fmt']) + self.write_default_pattern(drive0['file']) + self.vm.launch() + + def test_incremental_failure(self): + '''Test: Verify backups made after a failure are correct. + + Simulate a failure during an incremental backup block job, + emulate additional writes, then create another incremental backup + afterwards and verify that the backup created is correct. + ''' + + drive0 = self.drives[0] + result = self.vm.qmp('blockdev-add', options={ + 'id': drive0['id'], + 'driver': drive0['fmt'], + 'file': { + 'driver': 'blkdebug', + 'image': { + 'driver': 'file', + 'filename': drive0['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', {}) + + self.create_anchor_backup(drive0) + self.add_bitmap('bitmap0', drive0) + # Note: at this point, during a normal execution, + # Assume that the VM resumes and begins issuing IO requests here. + + self.hmp_io_writes(drive0['id'], (('0xab', 0, 512), + ('0xfe', '16M', '256k'), + ('0x64', '32736k', '64k'))) + + result = self.create_incremental(validate=False) + self.assertFalse(result) + self.hmp_io_writes(drive0['id'], (('0x9a', 0, 512), + ('0x55', '8M', '352k'), + ('0x78', '15872k', '1M'))) + self.create_incremental() self.vm.shutdown() - for bitmap in self.bitmaps: - bitmap.cleanup() - for filename in self.files: - try_remove(filename) + self.check_backups() if __name__ == '__main__': diff --git a/qemu/tests/qemu-iotests/124.out b/qemu/tests/qemu-iotests/124.out index 2f7d3902f..36376bed8 100644 --- a/qemu/tests/qemu-iotests/124.out +++ b/qemu/tests/qemu-iotests/124.out @@ -1,5 +1,5 @@ -....... +.......... ---------------------------------------------------------------------- -Ran 7 tests +Ran 10 tests OK diff --git a/qemu/tests/qemu-iotests/128 b/qemu/tests/qemu-iotests/128 index e2a0f2f89..0976a1813 100755 --- a/qemu/tests/qemu-iotests/128 +++ b/qemu/tests/qemu-iotests/128 @@ -25,12 +25,16 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ 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 +80,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/qemu/tests/qemu-iotests/130 b/qemu/tests/qemu-iotests/130 index bc26247e3..ecc8a5ba1 100755 --- a/qemu/tests/qemu-iotests/130 +++ b/qemu/tests/qemu-iotests/130 @@ -27,7 +27,6 @@ seq="$(basename $0)" echo "QA output created by $seq" here="$PWD" -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() @@ -59,8 +58,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 +67,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/qemu/tests/qemu-iotests/130.out b/qemu/tests/qemu-iotests/130.out index ea68b5d28..ae95b5027 100644 --- a/qemu/tests/qemu-iotests/130.out +++ b/qemu/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) c[K[Dco[K[D[Dcom[K[D[D[Dcomm[K[D[D[D[Dcommi[K[D[D[D[D[Dcommit[K[D[D[D[D[D[Dcommit [K[D[D[D[D[D[D[Dcommit i[K[D[D[D[D[D[D[D[Dcommit id[K[D[D[D[D[D[D[D[D[Dcommit ide[K[D[D[D[D[D[D[D[D[D[Dcommit ide0[K[D[D[D[D[D[D[D[D[D[D[Dcommit ide0-[K[D[D[D[D[D[D[D[D[D[D[D[Dcommit ide0-h[K[D[D[D[D[D[D[D[D[D[D[D[D[Dcommit ide0-hd[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dcommit ide0-hd0[K +(qemu) c[K[Dco[K[D[Dcom[K[D[D[Dcomm[K[D[D[D[Dcommi[K[D[D[D[D[Dcommit[K[D[D[D[D[D[Dcommit [K[D[D[D[D[D[D[Dcommit t[K[D[D[D[D[D[D[D[Dcommit te[K[D[D[D[D[D[D[D[D[Dcommit tes[K[D[D[D[D[D[D[D[D[D[Dcommit test[K[D[D[D[D[D[D[D[D[D[D[Dcommit testd[K[D[D[D[D[D[D[D[D[D[D[D[Dcommit testdi[K[D[D[D[D[D[D[D[D[D[D[D[D[Dcommit testdis[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dcommit testdisk[K (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) c[K[Dco[K[D[Dcom[K[D[D[Dcomm[K[D[D[D[Dcommi[K[D[D[D[D[Dcommit[K[D[D[D[D[D[Dcommit [K[D[D[D[D[D[D[Dcommit i[K[D[D[D[D[D[D[D[Dcommit id[K[D[D[D[D[D[D[D[D[Dcommit ide[K[D[D[D[D[D[D[D[D[D[Dcommit ide0[K[D[D[D[D[D[D[D[D[D[D[Dcommit ide0-[K[D[D[D[D[D[D[D[D[D[D[D[Dcommit ide0-h[K[D[D[D[D[D[D[D[D[D[D[D[D[Dcommit ide0-hd[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dcommit ide0-hd0[K +(qemu) c[K[Dco[K[D[Dcom[K[D[D[Dcomm[K[D[D[D[Dcommi[K[D[D[D[D[Dcommit[K[D[D[D[D[D[Dcommit [K[D[D[D[D[D[D[Dcommit t[K[D[D[D[D[D[D[D[Dcommit te[K[D[D[D[D[D[D[D[D[Dcommit tes[K[D[D[D[D[D[D[D[D[D[Dcommit test[K[D[D[D[D[D[D[D[D[D[D[Dcommit testd[K[D[D[D[D[D[D[D[D[D[D[D[Dcommit testdi[K[D[D[D[D[D[D[D[D[D[D[D[D[Dcommit testdis[K[D[D[D[D[D[D[D[D[D[D[D[D[D[Dcommit testdisk[K (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/qemu/tests/qemu-iotests/131 b/qemu/tests/qemu-iotests/131 index 4873f40e9..94a9ae76a 100755 --- a/qemu/tests/qemu-iotests/131 +++ b/qemu/tests/qemu-iotests/131 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/131.out b/qemu/tests/qemu-iotests/131.out index 021a04c81..ae2412ebf 100644 --- a/qemu/tests/qemu-iotests/131.out +++ b/qemu/tests/qemu-iotests/131.out @@ -22,7 +22,7 @@ read 32768/32768 bytes at offset 163840 read 32768/32768 bytes at offset 0 32 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) == Corrupt image == -qemu-io: can't open device TEST_DIR/t.parallels: parallels: Image was not closed correctly; cannot be opened read/write +can't open device TEST_DIR/t.parallels: parallels: Image was not closed correctly; cannot be opened read/write no file open, try 'help open' ERROR image was not closed correctly diff --git a/qemu/tests/qemu-iotests/133 b/qemu/tests/qemu-iotests/133 new file mode 100755 index 000000000..9d35a6a1c --- /dev/null +++ b/qemu/tests/qemu-iotests/133 @@ -0,0 +1,89 @@ +#!/bin/bash +# +# Test for 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` +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 + +_supported_fmt qcow2 +_supported_proto file +_supported_os Linux + +TEST_IMG="$TEST_IMG.base" _make_test_img 64M +_make_test_img -b "$TEST_IMG.base" + +echo +echo "=== Check that node-name can't be changed ===" +echo + +$QEMU_IO -c 'reopen -o node-name=foo' $TEST_IMG +$QEMU_IO -c 'reopen -o file.node-name=foo' $TEST_IMG +$QEMU_IO -c 'reopen -o backing.node-name=foo' $TEST_IMG + +echo +echo "=== Check that unchanged node-name is okay ===" +echo + +# Explicitly repeated +$QEMU_IO -c "open -o node-name=foo $TEST_IMG" -c 'reopen -o node-name=foo' +$QEMU_IO -c "open -o file.node-name=foo $TEST_IMG" -c 'reopen -o file.node-name=foo' +$QEMU_IO -c "open -o backing.node-name=foo $TEST_IMG" -c 'reopen -o backing.node-name=foo' + +# Implicitly retained +$QEMU_IO -c "open -o node-name=foo $TEST_IMG" -c 'reopen' +$QEMU_IO -c "open -o file.node-name=foo $TEST_IMG" -c 'reopen' +$QEMU_IO -c "open -o backing.node-name=foo $TEST_IMG" -c 'reopen' + +echo +echo "=== Check that driver can't be changed ===" +echo + +$QEMU_IO -c 'reopen -o driver=raw' $TEST_IMG +$QEMU_IO -c 'reopen -o file.driver=qcow2' $TEST_IMG +$QEMU_IO -c 'reopen -o backing.driver=file' $TEST_IMG + +echo +echo "=== Check that unchanged driver is okay ===" +echo + +# Explicitly repeated (implicit case is covered in node-name test) +$QEMU_IO -c 'reopen -o driver=qcow2' $TEST_IMG +$QEMU_IO -c 'reopen -o file.driver=file' $TEST_IMG +$QEMU_IO -c 'reopen -o backing.driver=qcow2' $TEST_IMG + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/qemu/tests/qemu-iotests/133.out b/qemu/tests/qemu-iotests/133.out new file mode 100644 index 000000000..cc86b9488 --- /dev/null +++ b/qemu/tests/qemu-iotests/133.out @@ -0,0 +1,22 @@ +QA output created by 133 +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 + +=== Check that node-name can't be changed === + +Cannot change the option 'node-name' +Cannot change the option 'node-name' +Cannot change the option 'node-name' + +=== Check that unchanged node-name is okay === + + +=== Check that driver can't be changed === + +Cannot change the option 'driver' +Cannot change the option 'driver' +Cannot change the option 'driver' + +=== Check that unchanged driver is okay === + +*** done diff --git a/qemu/tests/qemu-iotests/134 b/qemu/tests/qemu-iotests/134 index 1c3820b17..af618b881 100755 --- a/qemu/tests/qemu-iotests/134 +++ b/qemu/tests/qemu-iotests/134 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/134.out b/qemu/tests/qemu-iotests/134.out index a16acb81c..6493704ec 100644 --- a/qemu/tests/qemu-iotests/134.out +++ b/qemu/tests/qemu-iotests/134.out @@ -1,43 +1,25 @@ QA output created by 134 -qemu-img: Encrypted images are deprecated -Support for them will be removed in a future release. -You can use 'qemu-img convert' to convert your image to an unencrypted one. -qemu-img: Encrypted images are deprecated -Support for them will be removed in a future release. -You can use 'qemu-img convert' to convert your image to an unencrypted one. Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on == reading whole image == -Encrypted images are deprecated -Support for them will be removed in a future release. -You can use 'qemu-img convert' to convert your image to an unencrypted one. Disk image 'TEST_DIR/t.qcow2' is encrypted. password: read 134217728/134217728 bytes at offset 0 128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) == rewriting whole image == -Encrypted images are deprecated -Support for them will be removed in a future release. -You can use 'qemu-img convert' to convert your image to an unencrypted one. Disk image 'TEST_DIR/t.qcow2' is encrypted. password: wrote 134217728/134217728 bytes at offset 0 128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) == verify pattern == -Encrypted images are deprecated -Support for them will be removed in a future release. -You can use 'qemu-img convert' to convert your image to an unencrypted one. Disk image 'TEST_DIR/t.qcow2' is encrypted. password: read 134217728/134217728 bytes at offset 0 128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) == verify pattern failure with wrong password == -Encrypted images are deprecated -Support for them will be removed in a future release. -You can use 'qemu-img convert' to convert your image to an unencrypted one. Disk image 'TEST_DIR/t.qcow2' is encrypted. password: Pattern verification failed at offset 0, 134217728 bytes diff --git a/qemu/tests/qemu-iotests/135 b/qemu/tests/qemu-iotests/135 index 16bf73656..ce608312f 100755 --- a/qemu/tests/qemu-iotests/135 +++ b/qemu/tests/qemu-iotests/135 @@ -25,7 +25,6 @@ seq=`basename $0` echo "QA output created by $seq" here=`pwd` -tmp=/tmp/$$ status=1 # failure is the default! _cleanup() diff --git a/qemu/tests/qemu-iotests/136 b/qemu/tests/qemu-iotests/136 new file mode 100644 index 000000000..e8c6937fc --- /dev/null +++ b/qemu/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/qemu/tests/qemu-iotests/136.out b/qemu/tests/qemu-iotests/136.out new file mode 100644 index 000000000..0a5e9583a --- /dev/null +++ b/qemu/tests/qemu-iotests/136.out @@ -0,0 +1,5 @@ +........................................ +---------------------------------------------------------------------- +Ran 40 tests + +OK diff --git a/qemu/tests/qemu-iotests/137 b/qemu/tests/qemu-iotests/137 new file mode 100755 index 000000000..e5e30de2f --- /dev/null +++ b/qemu/tests/qemu-iotests/137 @@ -0,0 +1,144 @@ +#!/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" +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/qemu/tests/qemu-iotests/137.out b/qemu/tests/qemu-iotests/137.out new file mode 100644 index 000000000..88c702cf7 --- /dev/null +++ b/qemu/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/qemu/tests/qemu-iotests/138 b/qemu/tests/qemu-iotests/138 new file mode 100755 index 000000000..21650d819 --- /dev/null +++ b/qemu/tests/qemu-iotests/138 @@ -0,0 +1,72 @@ +#!/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" +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/qemu/tests/qemu-iotests/138.out b/qemu/tests/qemu-iotests/138.out new file mode 100644 index 000000000..3fe911f85 --- /dev/null +++ b/qemu/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/qemu/tests/qemu-iotests/139 b/qemu/tests/qemu-iotests/139 new file mode 100644 index 000000000..a4b969499 --- /dev/null +++ b/qemu/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/qemu/tests/qemu-iotests/139.out b/qemu/tests/qemu-iotests/139.out new file mode 100644 index 000000000..281b69efe --- /dev/null +++ b/qemu/tests/qemu-iotests/139.out @@ -0,0 +1,5 @@ +............ +---------------------------------------------------------------------- +Ran 12 tests + +OK diff --git a/qemu/tests/qemu-iotests/140 b/qemu/tests/qemu-iotests/140 new file mode 100755 index 000000000..49f9df4eb --- /dev/null +++ b/qemu/tests/qemu-iotests/140 @@ -0,0 +1,95 @@ +#!/bin/bash +# +# Test case for ejecting a BlockBackend with an NBD server attached to it +# +# Verify that the NBD server stops offering the drive when ejecting a +# BlockDriverState tree from a BlockBackend (that is, a medium from a +# drive) exposed via an NBD server. +# +# 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=mreitz@redhat.com + +seq="$(basename $0)" +echo "QA output created by $seq" + +here="$PWD" +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img + rm -f "$TEST_DIR/nbd" +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter +. ./common.qemu + +_supported_fmt generic +_supported_proto file +_supported_os Linux + +_make_test_img 64k + +$QEMU_IO -c 'write -P 42 0 64k' "$TEST_IMG" | _filter_qemu_io + +keep_stderr=y \ +_launch_qemu -drive if=none,media=cdrom,id=drv,file="$TEST_IMG",format=$IMGFMT \ + 2> >(_filter_nbd) + +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'qmp_capabilities' }" \ + 'return' + +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'nbd-server-start', + 'arguments': { 'addr': { 'type': 'unix', + 'data': { 'path': '$TEST_DIR/nbd' }}}}" \ + 'return' + +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'nbd-server-add', + 'arguments': { 'device': 'drv' }}" \ + 'return' + +$QEMU_IO_PROG -f raw -c 'read -P 42 0 64k' \ + "nbd+unix:///drv?socket=$TEST_DIR/nbd" 2>&1 \ + | _filter_qemu_io | _filter_nbd + +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'eject', + 'arguments': { 'device': 'drv' }}" \ + 'return' + +$QEMU_IO_PROG -f raw -c close \ + "nbd+unix:///drv?socket=$TEST_DIR/nbd" 2>&1 \ + | _filter_qemu_io | _filter_nbd + +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'quit' }" \ + 'return' + +wait=1 _cleanup_qemu + +# success, all done +echo '*** done' +rm -f $seq.full +status=0 diff --git a/qemu/tests/qemu-iotests/140.out b/qemu/tests/qemu-iotests/140.out new file mode 100644 index 000000000..0409cd017 --- /dev/null +++ b/qemu/tests/qemu-iotests/140.out @@ -0,0 +1,15 @@ +QA output created by 140 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=65536 +wrote 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{"return": {}} +{"return": {}} +{"return": {}} +read 65536/65536 bytes at offset 0 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{"return": {}} +can't open device nbd+unix:///drv?socket=TEST_DIR/nbd: No export with name 'drv' available +no file open, try 'help open' +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"} +*** done diff --git a/qemu/tests/qemu-iotests/141 b/qemu/tests/qemu-iotests/141 new file mode 100755 index 000000000..b2617e5e2 --- /dev/null +++ b/qemu/tests/qemu-iotests/141 @@ -0,0 +1,185 @@ +#!/bin/bash +# +# Test case for ejecting BDSs with block jobs still running on them +# +# 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=mreitz@redhat.com + +seq="$(basename $0)" +echo "QA output created by $seq" + +here="$PWD" +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img + rm -f "$TEST_DIR/{b,m,o}.$IMGFMT" +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter +. ./common.qemu + +# Needs backing file and backing format support +_supported_fmt qcow2 qed +_supported_proto file +_supported_os Linux + + +test_blockjob() +{ + _send_qemu_cmd $QEMU_HANDLE \ + "{'execute': 'blockdev-add', + 'arguments': { + 'options': { + 'id': 'drv0', + 'driver': '$IMGFMT', + 'file': { + 'driver': 'file', + 'filename': '$TEST_IMG' + }}}}" \ + 'return' + + _send_qemu_cmd $QEMU_HANDLE \ + "$1" \ + "$2" \ + | _filter_img_create + + # We want this to return an error because the block job is still running + _send_qemu_cmd $QEMU_HANDLE \ + "{'execute': 'x-blockdev-remove-medium', + 'arguments': {'device': 'drv0'}}" \ + 'error' + + _send_qemu_cmd $QEMU_HANDLE \ + "{'execute': 'block-job-cancel', + 'arguments': {'device': 'drv0'}}" \ + "$3" + + _send_qemu_cmd $QEMU_HANDLE \ + "{'execute': 'x-blockdev-del', + 'arguments': {'id': 'drv0'}}" \ + 'return' +} + + +TEST_IMG="$TEST_DIR/b.$IMGFMT" _make_test_img 1M +TEST_IMG="$TEST_DIR/m.$IMGFMT" _make_test_img -b "$TEST_DIR/b.$IMGFMT" 1M +_make_test_img -b "$TEST_DIR/m.$IMGFMT" 1M + +_launch_qemu -nodefaults + +_send_qemu_cmd $QEMU_HANDLE \ + "{'execute': 'qmp_capabilities'}" \ + 'return' + +echo +echo '=== Testing drive-backup ===' +echo + +# drive-backup will not send BLOCK_JOB_READY by itself, and cancelling the job +# will consequently result in BLOCK_JOB_CANCELLED being emitted. + +test_blockjob \ + "{'execute': 'drive-backup', + 'arguments': {'device': 'drv0', + 'target': '$TEST_DIR/o.$IMGFMT', + 'format': '$IMGFMT', + 'sync': 'none'}}" \ + 'return' \ + 'BLOCK_JOB_CANCELLED' + +echo +echo '=== Testing drive-mirror ===' +echo + +# drive-mirror will send BLOCK_JOB_READY basically immediately, and cancelling +# the job will consequently result in BLOCK_JOB_COMPLETED being emitted. + +test_blockjob \ + "{'execute': 'drive-mirror', + 'arguments': {'device': 'drv0', + 'target': '$TEST_DIR/o.$IMGFMT', + 'format': '$IMGFMT', + 'sync': 'none'}}" \ + 'BLOCK_JOB_READY' \ + 'BLOCK_JOB_COMPLETED' + +echo +echo '=== Testing active block-commit ===' +echo + +# An active block-commit will send BLOCK_JOB_READY basically immediately, and +# cancelling the job will consequently result in BLOCK_JOB_COMPLETED being +# emitted. + +test_blockjob \ + "{'execute': 'block-commit', + 'arguments': {'device': 'drv0'}}" \ + 'BLOCK_JOB_READY' \ + 'BLOCK_JOB_COMPLETED' + +echo +echo '=== Testing non-active block-commit ===' +echo + +# Give block-commit something to work on, otherwise it would be done +# immediately, send a BLOCK_JOB_COMPLETED and ejecting the BDS would work just +# fine without the block job still running. + +$QEMU_IO -c 'write 0 1M' "$TEST_DIR/m.$IMGFMT" | _filter_qemu_io + +test_blockjob \ + "{'execute': 'block-commit', + 'arguments': {'device': 'drv0', + 'top': '$TEST_DIR/m.$IMGFMT', + 'speed': 1}}" \ + 'return' \ + 'BLOCK_JOB_CANCELLED' + +echo +echo '=== Testing block-stream ===' +echo + +# Give block-stream something to work on, otherwise it would be done +# immediately, send a BLOCK_JOB_COMPLETED and ejecting the BDS would work just +# fine without the block job still running. + +$QEMU_IO -c 'write 0 1M' "$TEST_DIR/b.$IMGFMT" | _filter_qemu_io + +# With some data to stream (and @speed set to 1), block-stream will not complete +# until we send the block-job-cancel command. Therefore, no event other than +# BLOCK_JOB_CANCELLED will be emitted. + +test_blockjob \ + "{'execute': 'block-stream', + 'arguments': {'device': 'drv0', + 'speed': 1}}" \ + 'return' \ + 'BLOCK_JOB_CANCELLED' + +_cleanup_qemu + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/qemu/tests/qemu-iotests/141.out b/qemu/tests/qemu-iotests/141.out new file mode 100644 index 000000000..adceac181 --- /dev/null +++ b/qemu/tests/qemu-iotests/141.out @@ -0,0 +1,59 @@ +QA output created by 141 +Formatting 'TEST_DIR/b.IMGFMT', fmt=IMGFMT size=1048576 +Formatting 'TEST_DIR/m.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/b.IMGFMT +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/m.IMGFMT +{"return": {}} + +=== Testing drive-backup === + +{"return": {}} +Formatting 'TEST_DIR/o.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT backing_fmt=IMGFMT +{"return": {}} +{"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: block device is in use by block job: backup"}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "drv0", "len": 1048576, "offset": 0, "speed": 0, "type": "backup"}} +{"return": {}} + +=== Testing drive-mirror === + +{"return": {}} +Formatting 'TEST_DIR/o.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT backing_fmt=IMGFMT +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "drv0", "len": 0, "offset": 0, "speed": 0, "type": "mirror"}} +{"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: block device is in use by block job: mirror"}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "drv0", "len": 0, "offset": 0, "speed": 0, "type": "mirror"}} +{"return": {}} + +=== Testing active block-commit === + +{"return": {}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "drv0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}} +{"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: block device is in use by block job: commit"}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "drv0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}} +{"return": {}} + +=== Testing non-active block-commit === + +wrote 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{"return": {}} +{"return": {}} +{"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: block device is in use by block job: commit"}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "drv0", "len": 1048576, "offset": 524288, "speed": 1, "type": "commit"}} +{"return": {}} + +=== Testing block-stream === + +wrote 1048576/1048576 bytes at offset 0 +1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{"return": {}} +{"return": {}} +{"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: block device is in use by block job: stream"}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "drv0", "len": 1048576, "offset": 524288, "speed": 1, "type": "stream"}} +{"return": {}} +*** done diff --git a/qemu/tests/qemu-iotests/142 b/qemu/tests/qemu-iotests/142 new file mode 100755 index 000000000..29c0606bd --- /dev/null +++ b/qemu/tests/qemu-iotests/142 @@ -0,0 +1,358 @@ +#!/bin/bash +# +# Test for configuring cache modes of arbitrary nodes (requires O_DIRECT) +# +# 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` +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img + rm -f $TEST_IMG.snap +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_supported_fmt qcow2 +_supported_proto file +_supported_os Linux + +# We test all cache modes anyway, but O_DIRECT needs to be supported +_default_cache_mode none +_supported_cache_modes none directsync + +function do_run_qemu() +{ + echo Testing: "$@" + ( + if ! test -t 0; then + while read cmd; do + echo $cmd + done + fi + echo quit + ) | $QEMU -nographic -monitor stdio -nodefaults "$@" + echo +} + +function run_qemu() +{ + do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu +} + +size=128M + +TEST_IMG="$TEST_IMG.base" _make_test_img $size +TEST_IMG="$TEST_IMG.snap" _make_test_img $size +_make_test_img -b "$TEST_IMG.base" $size + +echo +echo === Simple test for all cache modes === +echo + +run_qemu -drive file="$TEST_IMG",cache=none +run_qemu -drive file="$TEST_IMG",cache=directsync +run_qemu -drive file="$TEST_IMG",cache=writeback +run_qemu -drive file="$TEST_IMG",cache=writethrough +run_qemu -drive file="$TEST_IMG",cache=unsafe +run_qemu -drive file="$TEST_IMG",cache=invalid_value + +echo +echo === Check inheritance of cache modes === +echo + +files="if=none,file=$TEST_IMG,backing.file.filename=$TEST_IMG.base" +ids="node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file" + +function check_cache_all() +{ + # cache.direct is supposed to be inherited by both bs->file and + # bs->backing + + echo -e "cache.direct=on on none0" + echo "$hmp_cmds" | run_qemu -drive "$files","$ids",cache.direct=on | grep -e "Cache" -e "[Cc]annot|[Cc]ould not|[Cc]an't" + echo -e "\ncache.direct=on on file" + echo "$hmp_cmds" | run_qemu -drive "$files","$ids",file.cache.direct=on | grep -e "Cache" -e "[Cc]annot|[Cc]ould not|[Cc]an't" + echo -e "\ncache.direct=on on backing" + echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.cache.direct=on | grep -e "Cache" -e "[Cc]annot|[Cc]ould not|[Cc]an't" + echo -e "\ncache.direct=on on backing-file" + echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.file.cache.direct=on | grep -e "Cache" -e "[Cc]annot|[Cc]ould not|[Cc]an't" + + # cache.writeback is supposed to be inherited by bs->backing; bs->file + # always gets cache.writeback=on + + echo -e "\n\ncache.writeback=off on none0" + echo "$hmp_cmds" | run_qemu -drive "$files","$ids",cache.writeback=off | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't" + echo -e "\ncache.writeback=off on file" + echo "$hmp_cmds" | run_qemu -drive "$files","$ids",file.cache.writeback=off | grep -e "doesn't" -e "does not" + echo -e "\ncache.writeback=off on backing" + echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.cache.writeback=off | grep -e "doesn't" -e "does not" + echo -e "\ncache.writeback=off on backing-file" + echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.file.cache.writeback=off | grep -e "doesn't" -e "does not" + + # cache.no-flush is supposed to be inherited by both bs->file and bs->backing + + echo -e "\n\ncache.no-flush=on on none0" + echo "$hmp_cmds" | run_qemu -drive "$files","$ids",cache.no-flush=on | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't" + echo -e "\ncache.no-flush=on on file" + echo "$hmp_cmds" | run_qemu -drive "$files","$ids",file.cache.no-flush=on | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't" + echo -e "\ncache.no-flush=on on backing" + echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.cache.no-flush=on | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't" + echo -e "\ncache.no-flush=on on backing-file" + echo "$hmp_cmds" | run_qemu -drive "$files","$ids",backing.file.cache.no-flush=on | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't" +} + +echo +echo "--- Configure cache modes on the command line ---" +echo + +# First check the inherited cache mode after opening the image. + +hmp_cmds="info block none0 +info block image +info block file +info block backing +info block backing-file" + +check_cache_all + +echo +echo "--- Cache modes after reopen (live snapshot) ---" +echo + +# Then trigger a reopen and check that the cache modes are still the same. + +hmp_cmds="snapshot_blkdev -n none0 $TEST_IMG.snap $IMGFMT +info block +info block image +info block file +info block backing +info block backing-file" + +check_cache_all + +echo +echo "--- Change cache modes with reopen (qemu-io command, flags) ---" +echo + +# This one actually changes the cache mode with the reopen. For this test, the +# new cache mode is specified in the flags, not as an option. + +hmp_cmds='qemu-io none0 "reopen -c none" +info block none0 +info block image +info block file +info block backing +info block backing-file' + +check_cache_all + +echo +echo "--- Change cache modes with reopen (qemu-io command, options) ---" +echo + +# This one actually changes the cache mode with the reopen. For this test, the +# new cache mode is specified as an option, not in the flags. + +hmp_cmds='qemu-io none0 "reopen -o cache.direct=on" +info block none0 +info block image +info block file +info block backing +info block backing-file' + +check_cache_all + +echo +echo "--- Change cache modes after snapshot ---" +echo + +# This checks that the original image doesn't inherit from the snapshot + +hmp_cmds="snapshot_blkdev -n none0 $TEST_IMG.snap $IMGFMT +qemu-io none0 \"reopen -c none\" +info block none0 +info block image +info block file +info block backing +info block backing-file" + +check_cache_all + +echo +echo "--- Change cache mode in parent, child has explicit option in JSON ---" +echo + +# This checks that children with options explicitly set by the json: +# pseudo-protocol don't inherit these options from their parents. +# +# Yes, blkdebug::json:... is criminal, but I can't see another way to have a +# BDS initialised with the json: pseudo-protocol, but still have it inherit +# options from its parent node. + +hmp_cmds="qemu-io none0 \"reopen -o cache.direct=on,cache.no-flush=on\" +info block none0 +info block image +info block blkdebug +info block file" + +echo "$hmp_cmds" | run_qemu -drive if=none,file="blkdebug::json:{\"filename\":\"$TEST_IMG\",,\"cache\":{\"direct\":false}}",node-name=image,file.node-name=blkdebug,file.image.node-name=file | grep "Cache" + +echo +echo "=== Check that referenced BDSes don't inherit ===" +echo + +drv_bkfile="if=none,driver=file,filename=$TEST_IMG.base,node-name=backing-file" +drv_bk="if=none,file=json:{'driver':'$IMGFMT',,'file':'backing-file',,'node-name':'backing'}" +drv_file="if=none,driver=file,filename=$TEST_IMG,node-name=file" +drv_img="if=none,id=blk,file=json:{'driver':'$IMGFMT',,'file':'file',,'backing':'backing',,'node-name':'image'}" + +function check_cache_all_separate() +{ + # Check cache.direct + + echo -e "cache.direct=on on blk" + echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img",cache.direct=on | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't" + echo -e "\ncache.direct=on on file" + echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file",cache.direct=on -drive "$drv_img" | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't" + echo -e "\ncache.direct=on on backing" + echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk",cache.direct=on -drive "$drv_file" -drive "$drv_img" | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't" + echo -e "\ncache.direct=on on backing-file" + echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile",cache.direct=on -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img" | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't" + + # Check cache.writeback + + echo -e "\n\ncache.writeback=off on blk" + echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img",cache.writeback=off | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't" + echo -e "\ncache.writeback=off on file" + echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file",cache.writeback=off -drive "$drv_img" | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't" + echo -e "\ncache.writeback=off on backing" + echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk",cache.writeback=off -drive "$drv_file" -drive "$drv_img" | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't" + echo -e "\ncache.writeback=off on backing-file" + echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile",cache.writeback=off -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img" | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't" + + # Check cache.no-flush + + echo -e "\n\ncache.no-flush=on on blk" + echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img",cache.no-flush=on | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't" + echo -e "\ncache.no-flush=on on file" + echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk" -drive "$drv_file",cache.no-flush=on -drive "$drv_img" | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't" + echo -e "\ncache.no-flush=on on backing" + echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile" -drive "$drv_bk",cache.no-flush=on -drive "$drv_file" -drive "$drv_img" | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't" + echo -e "\ncache.no-flush=on on backing-file" + echo "$hmp_cmds" | run_qemu -drive "$drv_bkfile",cache.no-flush=on -drive "$drv_bk" -drive "$drv_file" -drive "$drv_img" | grep -e "Cache" -e "[Cc]annot\|[Cc]ould not\|[Cc]an't" +} + +echo +echo "--- Configure cache modes on the command line ---" +echo + +# First check the inherited cache mode after opening the image. + +hmp_cmds="info block image +info block file +info block backing +info block backing-file" + +check_cache_all_separate + +echo +echo "--- Cache modes after reopen (live snapshot) ---" +echo + +# Then trigger a reopen and check that the cache modes are still the same. + +hmp_cmds="snapshot_blkdev -n blk $TEST_IMG.snap $IMGFMT +info block blk +info block image +info block file +info block backing +info block backing-file" + +check_cache_all_separate + +echo +echo "--- Change cache modes with reopen (qemu-io command, flags) ---" +echo + +# This one actually changes the cache mode with the reopen. For this test, the +# new cache mode is specified as flags, not as option. + +hmp_cmds='qemu-io blk "reopen -c none" +info block image +info block file +info block backing +info block backing-file' + +check_cache_all_separate + + +echo +echo "=== Reopening children instead of the root ===" +echo + +files="if=none,file=$TEST_IMG,backing.file.filename=$TEST_IMG.base" +ids="node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file" + +echo +echo "--- Basic reopen ---" +echo + +hmp_cmds='qemu-io none0 "reopen -o backing.cache.direct=on" +info block none0 +info block image +info block file +info block backing +info block backing-file' + +check_cache_all + +echo +echo "--- Change cache mode after reopening child ---" +echo + +# This checks that children with options explicitly set with reopen don't +# inherit these options from their parents any more + +# TODO Implement node-name support for 'qemu-io' HMP command for -c +# Can use only -o to access child node options for now + +hmp_cmds="qemu-io none0 \"reopen -o file.cache.direct=off,file.cache.no-flush=off\" +qemu-io none0 \"reopen -o backing.file.cache.direct=off,backing.file.cache.no-flush=on\" +qemu-io none0 \"reopen -c none\" +info block image +info block file +info block backing +info block backing-file" + +echo "$hmp_cmds" | run_qemu -drive "$files","$ids" | grep "Cache" + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/qemu/tests/qemu-iotests/142.out b/qemu/tests/qemu-iotests/142.out new file mode 100644 index 000000000..600beca8f --- /dev/null +++ b/qemu/tests/qemu-iotests/142.out @@ -0,0 +1,750 @@ +QA output created by 142 +Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=134217728 +Formatting 'TEST_DIR/t.IMGFMT.snap', fmt=IMGFMT size=134217728 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/t.IMGFMT.base + +=== Simple test for all cache modes === + +Testing: -drive file=TEST_DIR/t.qcow2,cache=none +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive file=TEST_DIR/t.qcow2,cache=directsync +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive file=TEST_DIR/t.qcow2,cache=writeback +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive file=TEST_DIR/t.qcow2,cache=writethrough +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive file=TEST_DIR/t.qcow2,cache=unsafe +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K + +Testing: -drive file=TEST_DIR/t.qcow2,cache=invalid_value +QEMU_PROG: -drive file=TEST_DIR/t.qcow2,cache=invalid_value: invalid cache option + + +=== Check inheritance of cache modes === + + +--- Configure cache modes on the command line --- + +cache.direct=on on none0 + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.direct=on on file + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback + +cache.direct=on on backing + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.direct=on on backing-file + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, direct + + +cache.writeback=off on none0 + Cache mode: writethrough + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + +cache.writeback=off on file +QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,backing.file.filename=TEST_DIR/t.qcow2.base,node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,file.cache.writeback=off: Block protocol 'file' doesn't support the option 'cache.writeback' + +cache.writeback=off on backing +QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,backing.file.filename=TEST_DIR/t.qcow2.base,node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,backing.cache.writeback=off: Could not open backing file: Block format 'qcow2' does not support the option 'cache.writeback' + +cache.writeback=off on backing-file +QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,backing.file.filename=TEST_DIR/t.qcow2.base,node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,backing.file.cache.writeback=off: Could not open backing file: Block protocol 'file' doesn't support the option 'cache.writeback' + + +cache.no-flush=on on none0 + Cache mode: writeback, ignore flushes + Cache mode: writeback, ignore flushes + Cache mode: writeback, ignore flushes + Cache mode: writeback, ignore flushes + Cache mode: writeback, ignore flushes + +cache.no-flush=on on file + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, ignore flushes + Cache mode: writeback + Cache mode: writeback + +cache.no-flush=on on backing + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, ignore flushes + Cache mode: writeback, ignore flushes + +cache.no-flush=on on backing-file + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, ignore flushes + +--- Cache modes after reopen (live snapshot) --- + +cache.direct=on on none0 + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.direct=on on file + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback + +cache.direct=on on backing + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.direct=on on backing-file + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, direct + + +cache.writeback=off on none0 + Cache mode: writethrough + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + +cache.writeback=off on file +QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,backing.file.filename=TEST_DIR/t.qcow2.base,node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,file.cache.writeback=off: Block protocol 'file' doesn't support the option 'cache.writeback' + +cache.writeback=off on backing +QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,backing.file.filename=TEST_DIR/t.qcow2.base,node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,backing.cache.writeback=off: Could not open backing file: Block format 'qcow2' does not support the option 'cache.writeback' + +cache.writeback=off on backing-file +QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,backing.file.filename=TEST_DIR/t.qcow2.base,node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,backing.file.cache.writeback=off: Could not open backing file: Block protocol 'file' doesn't support the option 'cache.writeback' + + +cache.no-flush=on on none0 + Cache mode: writeback, ignore flushes + Cache mode: writeback, ignore flushes + Cache mode: writeback, ignore flushes + Cache mode: writeback, ignore flushes + Cache mode: writeback, ignore flushes + +cache.no-flush=on on file + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, ignore flushes + Cache mode: writeback + Cache mode: writeback + +cache.no-flush=on on backing + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, ignore flushes + Cache mode: writeback, ignore flushes + +cache.no-flush=on on backing-file + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, ignore flushes + +--- Change cache modes with reopen (qemu-io command, flags) --- + +cache.direct=on on none0 + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.direct=on on file + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.direct=on on backing + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.direct=on on backing-file + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + + +cache.writeback=off on none0 + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.writeback=off on file +QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,backing.file.filename=TEST_DIR/t.qcow2.base,node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,file.cache.writeback=off: Block protocol 'file' doesn't support the option 'cache.writeback' + +cache.writeback=off on backing +QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,backing.file.filename=TEST_DIR/t.qcow2.base,node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,backing.cache.writeback=off: Could not open backing file: Block format 'qcow2' does not support the option 'cache.writeback' + +cache.writeback=off on backing-file +QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,backing.file.filename=TEST_DIR/t.qcow2.base,node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,backing.file.cache.writeback=off: Could not open backing file: Block protocol 'file' doesn't support the option 'cache.writeback' + + +cache.no-flush=on on none0 + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.no-flush=on on file + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct, ignore flushes + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.no-flush=on on backing + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct, ignore flushes + Cache mode: writeback, direct, ignore flushes + +cache.no-flush=on on backing-file + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct, ignore flushes + +--- Change cache modes with reopen (qemu-io command, options) --- + +cache.direct=on on none0 + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.direct=on on file + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.direct=on on backing + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.direct=on on backing-file + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + + +cache.writeback=off on none0 + Cache mode: writethrough, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.writeback=off on file +QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,backing.file.filename=TEST_DIR/t.qcow2.base,node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,file.cache.writeback=off: Block protocol 'file' doesn't support the option 'cache.writeback' + +cache.writeback=off on backing +QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,backing.file.filename=TEST_DIR/t.qcow2.base,node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,backing.cache.writeback=off: Could not open backing file: Block format 'qcow2' does not support the option 'cache.writeback' + +cache.writeback=off on backing-file +QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,backing.file.filename=TEST_DIR/t.qcow2.base,node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,backing.file.cache.writeback=off: Could not open backing file: Block protocol 'file' doesn't support the option 'cache.writeback' + + +cache.no-flush=on on none0 + Cache mode: writeback, direct, ignore flushes + Cache mode: writeback, direct, ignore flushes + Cache mode: writeback, direct, ignore flushes + Cache mode: writeback, direct, ignore flushes + Cache mode: writeback, direct, ignore flushes + +cache.no-flush=on on file + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct, ignore flushes + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.no-flush=on on backing + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct, ignore flushes + Cache mode: writeback, direct, ignore flushes + +cache.no-flush=on on backing-file + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct, ignore flushes + +--- Change cache modes after snapshot --- + +cache.direct=on on none0 + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.direct=on on file + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback + +cache.direct=on on backing + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.direct=on on backing-file + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, direct + + +cache.writeback=off on none0 + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + +cache.writeback=off on file +QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,backing.file.filename=TEST_DIR/t.qcow2.base,node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,file.cache.writeback=off: Block protocol 'file' doesn't support the option 'cache.writeback' + +cache.writeback=off on backing +QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,backing.file.filename=TEST_DIR/t.qcow2.base,node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,backing.cache.writeback=off: Could not open backing file: Block format 'qcow2' does not support the option 'cache.writeback' + +cache.writeback=off on backing-file +QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,backing.file.filename=TEST_DIR/t.qcow2.base,node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,backing.file.cache.writeback=off: Could not open backing file: Block protocol 'file' doesn't support the option 'cache.writeback' + + +cache.no-flush=on on none0 + Cache mode: writeback, direct + Cache mode: writeback, ignore flushes + Cache mode: writeback, ignore flushes + Cache mode: writeback, ignore flushes + Cache mode: writeback, ignore flushes + +cache.no-flush=on on file + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback, ignore flushes + Cache mode: writeback + Cache mode: writeback + +cache.no-flush=on on backing + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, ignore flushes + Cache mode: writeback, ignore flushes + +cache.no-flush=on on backing-file + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, ignore flushes + +--- Change cache mode in parent, child has explicit option in JSON --- + + Cache mode: writeback, direct, ignore flushes + Cache mode: writeback, direct, ignore flushes + Cache mode: writeback, direct, ignore flushes + Cache mode: writeback, ignore flushes + +=== Check that referenced BDSes don't inherit === + + +--- Configure cache modes on the command line --- + +cache.direct=on on blk + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + +cache.direct=on on file + Cache mode: writeback + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback + +cache.direct=on on backing + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, direct + Cache mode: writeback + +cache.direct=on on backing-file + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, direct + + +cache.writeback=off on blk + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + +cache.writeback=off on file + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + +cache.writeback=off on backing + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + +cache.writeback=off on backing-file + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + + +cache.no-flush=on on blk + Cache mode: writeback, ignore flushes + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + +cache.no-flush=on on file + Cache mode: writeback + Cache mode: writeback, ignore flushes + Cache mode: writeback + Cache mode: writeback + +cache.no-flush=on on backing + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, ignore flushes + Cache mode: writeback + +cache.no-flush=on on backing-file + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, ignore flushes + +--- Cache modes after reopen (live snapshot) --- + +cache.direct=on on blk + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + +cache.direct=on on file + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback + +cache.direct=on on backing + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, direct + Cache mode: writeback + +cache.direct=on on backing-file + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, direct + + +cache.writeback=off on blk + Cache mode: writethrough + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + +cache.writeback=off on file + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + +cache.writeback=off on backing + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + +cache.writeback=off on backing-file + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + + +cache.no-flush=on on blk + Cache mode: writeback, ignore flushes + Cache mode: writeback, ignore flushes + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + +cache.no-flush=on on file + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, ignore flushes + Cache mode: writeback + Cache mode: writeback + +cache.no-flush=on on backing + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, ignore flushes + Cache mode: writeback + +cache.no-flush=on on backing-file + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, ignore flushes + +--- Change cache modes with reopen (qemu-io command, flags) --- + +cache.direct=on on blk + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + +cache.direct=on on file + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback + +cache.direct=on on backing + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback, direct + Cache mode: writeback + +cache.direct=on on backing-file + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, direct + + +cache.writeback=off on blk + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + +cache.writeback=off on file + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + +cache.writeback=off on backing + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + +cache.writeback=off on backing-file + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + + +cache.no-flush=on on blk + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + +cache.no-flush=on on file + Cache mode: writeback, direct + Cache mode: writeback, ignore flushes + Cache mode: writeback + Cache mode: writeback + +cache.no-flush=on on backing + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback, ignore flushes + Cache mode: writeback + +cache.no-flush=on on backing-file + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, ignore flushes + +=== Reopening children instead of the root === + + +--- Basic reopen --- + +cache.direct=on on none0 + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.direct=on on file + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, direct + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.direct=on on backing + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.direct=on on backing-file + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, direct + Cache mode: writeback, direct + + +cache.writeback=off on none0 + Cache mode: writethrough + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.writeback=off on file +QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,backing.file.filename=TEST_DIR/t.qcow2.base,node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,file.cache.writeback=off: Block protocol 'file' doesn't support the option 'cache.writeback' + +cache.writeback=off on backing +QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,backing.file.filename=TEST_DIR/t.qcow2.base,node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,backing.cache.writeback=off: Could not open backing file: Block format 'qcow2' does not support the option 'cache.writeback' + +cache.writeback=off on backing-file +QEMU_PROG: -drive if=none,file=TEST_DIR/t.qcow2,backing.file.filename=TEST_DIR/t.qcow2.base,node-name=image,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,backing.file.cache.writeback=off: Could not open backing file: Block protocol 'file' doesn't support the option 'cache.writeback' + + +cache.no-flush=on on none0 + Cache mode: writeback, ignore flushes + Cache mode: writeback, ignore flushes + Cache mode: writeback, ignore flushes + Cache mode: writeback, direct, ignore flushes + Cache mode: writeback, direct, ignore flushes + +cache.no-flush=on on file + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, ignore flushes + Cache mode: writeback, direct + Cache mode: writeback, direct + +cache.no-flush=on on backing + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, direct, ignore flushes + Cache mode: writeback, direct, ignore flushes + +cache.no-flush=on on backing-file + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback + Cache mode: writeback, direct + Cache mode: writeback, direct, ignore flushes + +--- Change cache mode after reopening child --- + + Cache mode: writeback, direct + Cache mode: writeback + Cache mode: writeback, direct + Cache mode: writeback, ignore flushes +*** done diff --git a/qemu/tests/qemu-iotests/143 b/qemu/tests/qemu-iotests/143 new file mode 100755 index 000000000..ec4ef2221 --- /dev/null +++ b/qemu/tests/qemu-iotests/143 @@ -0,0 +1,72 @@ +#!/bin/bash +# +# Test case for connecting to a non-existing NBD export name +# +# 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=mreitz@redhat.com + +seq="$(basename $0)" +echo "QA output created by $seq" + +here="$PWD" +status=1 # failure is the default! + +_cleanup() +{ + rm -f "$TEST_DIR/nbd" +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter +. ./common.qemu + +_supported_fmt generic +_supported_proto generic +_supported_os Linux + +keep_stderr=y \ +_launch_qemu 2> >(_filter_nbd) + +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'qmp_capabilities' }" \ + 'return' + +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'nbd-server-start', + 'arguments': { 'addr': { 'type': 'unix', + 'data': { 'path': '$TEST_DIR/nbd' }}}}" \ + 'return' + +# This should just result in a client error, not in the server crashing +$QEMU_IO_PROG -f raw -c quit \ + "nbd+unix:///no_such_export?socket=$TEST_DIR/nbd" 2>&1 \ + | _filter_qemu_io | _filter_nbd + +_send_qemu_cmd $QEMU_HANDLE \ + "{ 'execute': 'quit' }" \ + 'return' + +wait=1 _cleanup_qemu + +# success, all done +echo '*** done' +rm -f $seq.full +status=0 diff --git a/qemu/tests/qemu-iotests/143.out b/qemu/tests/qemu-iotests/143.out new file mode 100644 index 000000000..d24ad20db --- /dev/null +++ b/qemu/tests/qemu-iotests/143.out @@ -0,0 +1,7 @@ +QA output created by 143 +{"return": {}} +{"return": {}} +can't open device nbd+unix:///no_such_export?socket=TEST_DIR/nbd: No export with name 'no_such_export' available +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"} +*** done diff --git a/qemu/tests/qemu-iotests/144 b/qemu/tests/qemu-iotests/144 new file mode 100755 index 000000000..00de3c33c --- /dev/null +++ b/qemu/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/qemu/tests/qemu-iotests/144.out b/qemu/tests/qemu-iotests/144.out new file mode 100644 index 000000000..410d74180 --- /dev/null +++ b/qemu/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/qemu/tests/qemu-iotests/145 b/qemu/tests/qemu-iotests/145 new file mode 100755 index 000000000..1eca0e899 --- /dev/null +++ b/qemu/tests/qemu-iotests/145 @@ -0,0 +1,51 @@ +#!/bin/bash +# +# Test the combination of -incoming and snapshot=on +# +# 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=kwolf@redhat.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img + true +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_supported_fmt generic +_supported_proto generic +_supported_os Linux + +_make_test_img 1M +echo quit | $QEMU -nographic -hda "$TEST_IMG" -incoming 'exec:true' -snapshot -serial none -monitor stdio | _filter_qemu + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/qemu/tests/qemu-iotests/145.out b/qemu/tests/qemu-iotests/145.out new file mode 100644 index 000000000..75b5c8ac3 --- /dev/null +++ b/qemu/tests/qemu-iotests/145.out @@ -0,0 +1,5 @@ +QA output created by 145 +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 +QEMU X.Y.Z monitor - type 'help' for more information +(qemu) q[K[Dqu[K[D[Dqui[K[D[D[Dquit[K +*** done diff --git a/qemu/tests/qemu-iotests/146 b/qemu/tests/qemu-iotests/146 new file mode 100755 index 000000000..043711be6 --- /dev/null +++ b/qemu/tests/qemu-iotests/146 @@ -0,0 +1,165 @@ +#!/bin/bash +# +# Test VHD image format creator detection and override +# +# 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! + +_cleanup() +{ + _cleanup_qemu + _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 vpc +_supported_proto file +_supported_os Linux + + +qemu_comm_method="monitor" +silent= + +echo +echo === Testing VPC Autodetect === +echo +_use_sample_img virtualpc-dynamic.vhd.bz2 + +${QEMU_IO} -c "open -o driver=vpc ${TEST_IMG}" -c 'map' + +echo +echo === Testing VPC with current_size force === +echo + +${QEMU_IO} -c "open -o driver=vpc,force_size_calc=current_size ${TEST_IMG}" -c 'map' + +echo +echo === Testing VPC with chs force === +echo + +${QEMU_IO} -c "open -o driver=vpc,force_size_calc=chs ${TEST_IMG}" -c 'map' + +_cleanup_test_img + +echo +echo === Testing Hyper-V Autodetect === +echo +_use_sample_img hyperv2012r2-dynamic.vhd.bz2 + +${QEMU_IO} -c "open -o driver=vpc ${TEST_IMG}" -c 'map' + +echo +echo === Testing Hyper-V with current_size force === +echo + +${QEMU_IO} -c "open -o driver=vpc,force_size_calc=current_size ${TEST_IMG}" -c 'map' + +echo +echo === Testing Hyper-V with chs force === +echo + +${QEMU_IO} -c "open -o driver=vpc,force_size_calc=chs ${TEST_IMG}" -c 'map' + +_cleanup_test_img + +echo +echo === Testing d2v Autodetect === +echo +_use_sample_img d2v-zerofilled.vhd.bz2 + +${QEMU_IO} -c "open -o driver=vpc ${TEST_IMG}" -c 'map' + +echo +echo === Testing d2v with current_size force === +echo + +${QEMU_IO} -c "open -o driver=vpc,force_size_calc=current_size ${TEST_IMG}" -c 'map' + +echo +echo === Testing d2v with chs force === +echo + +${QEMU_IO} -c "open -o driver=vpc,force_size_calc=chs ${TEST_IMG}" -c 'map' + +_cleanup_test_img + +echo +echo === Testing Image create, default === +echo + +TEST_IMG="${TEST_DIR}/vpc-create-test.vpc" + +_make_test_img 4G + +echo +echo === Read created image, default opts ==== +echo + +${QEMU_IO} -c "open -o driver=vpc ${TEST_IMG}" -c 'map' + +echo +echo === Read created image, force_size_calc=chs ==== +echo + +${QEMU_IO} -c "open -o driver=vpc,force_size_calc=chs ${TEST_IMG}" -c 'map' + +echo +echo === Read created image, force_size_calc=current_size ==== +echo + +${QEMU_IO} -c "open -o driver=vpc,force_size_calc=current_size ${TEST_IMG}" -c 'map' + +echo +echo === Testing Image create, force_size === +echo + +_make_test_img -o force_size 4G + +echo +echo === Read created image, default opts ==== +echo + +${QEMU_IO} -c "open -o driver=vpc ${TEST_IMG}" -c 'map' + +echo +echo === Read created image, force_size_calc=chs ==== +echo + +${QEMU_IO} -c "open -o driver=vpc,force_size_calc=chs ${TEST_IMG}" -c 'map' + +echo +echo === Read created image, force_size_calc=current_size ==== +echo + +${QEMU_IO} -c "open -o driver=vpc,force_size_calc=current_size ${TEST_IMG}" -c 'map' + +echo "*** done" +rm -f $seq.full +status=0 diff --git a/qemu/tests/qemu-iotests/146.out b/qemu/tests/qemu-iotests/146.out new file mode 100644 index 000000000..4f334d86b --- /dev/null +++ b/qemu/tests/qemu-iotests/146.out @@ -0,0 +1,70 @@ +QA output created by 146 + +=== Testing VPC Autodetect === + +[ 0] 266334240/ 266334240 sectors not allocated at offset 0 bytes (0) + +=== Testing VPC with current_size force === + +[ 0] 266338304/ 266338304 sectors not allocated at offset 0 bytes (0) + +=== Testing VPC with chs force === + +[ 0] 266334240/ 266334240 sectors not allocated at offset 0 bytes (0) + +=== Testing Hyper-V Autodetect === + +[ 0] 266338304/ 266338304 sectors not allocated at offset 0 bytes (0) + +=== Testing Hyper-V with current_size force === + +[ 0] 266338304/ 266338304 sectors not allocated at offset 0 bytes (0) + +=== Testing Hyper-V with chs force === + +[ 0] 266334240/ 266334240 sectors not allocated at offset 0 bytes (0) + +=== Testing d2v Autodetect === + +[ 0] 514560/ 514560 sectors allocated at offset 0 bytes (1) + +=== Testing d2v with current_size force === + +[ 0] 514560/ 514560 sectors allocated at offset 0 bytes (1) + +=== Testing d2v with chs force === + +[ 0] 514560/ 514560 sectors allocated at offset 0 bytes (1) + +=== Testing Image create, default === + +Formatting 'TEST_DIR/IMGFMT-create-test.IMGFMT', fmt=IMGFMT size=4294967296 + +=== Read created image, default opts ==== + +[ 0] 8389584/ 8389584 sectors not allocated at offset 0 bytes (0) + +=== Read created image, force_size_calc=chs ==== + +[ 0] 8389584/ 8389584 sectors not allocated at offset 0 bytes (0) + +=== Read created image, force_size_calc=current_size ==== + +[ 0] 8389584/ 8389584 sectors not allocated at offset 0 bytes (0) + +=== Testing Image create, force_size === + +Formatting 'TEST_DIR/IMGFMT-create-test.IMGFMT', fmt=IMGFMT size=4294967296 force_size=on + +=== Read created image, default opts ==== + +[ 0] 8388608/ 8388608 sectors not allocated at offset 0 bytes (0) + +=== Read created image, force_size_calc=chs ==== + +[ 0] 8388608/ 8388608 sectors not allocated at offset 0 bytes (0) + +=== Read created image, force_size_calc=current_size ==== + +[ 0] 8388608/ 8388608 sectors not allocated at offset 0 bytes (0) +*** done diff --git a/qemu/tests/qemu-iotests/148 b/qemu/tests/qemu-iotests/148 new file mode 100644 index 000000000..e01b061fe --- /dev/null +++ b/qemu/tests/qemu-iotests/148 @@ -0,0 +1,140 @@ +#!/usr/bin/env python +# +# Test the rate limit of QMP events +# +# Copyright (C) 2016 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 + +imgs = (os.path.join(iotests.test_dir, 'quorum0.img'), + os.path.join(iotests.test_dir, 'quorum1.img'), + os.path.join(iotests.test_dir, 'quorum2.img')) + +img_conf = (os.path.join(iotests.test_dir, 'quorum0.conf'), + os.path.join(iotests.test_dir, 'quorum1.conf'), + os.path.join(iotests.test_dir, 'quorum2.conf')) + +event_rate = 1000000000 +sector_size = 512 +offset = 10 + +class TestQuorumEvents(iotests.QMPTestCase): + read_pattern = 'quorum' + + def create_blkdebug_file(self, blkdebug_file, bad_sector): + file = open(blkdebug_file, 'w') + file.write(''' +[inject-error] +event = "read_aio" +errno = "5" +sector = "%d" +''' % bad_sector) + file.close() + + def setUp(self): + driveopts = ['driver=quorum', 'vote-threshold=2'] + driveopts.append('read-pattern=%s' % self.read_pattern) + for i in range(len(imgs)): + iotests.qemu_img('create', '-f', iotests.imgfmt, imgs[i], '1M') + self.create_blkdebug_file(img_conf[i], i + offset) + driveopts.append('children.%d.driver=%s' % (i, iotests.imgfmt)) + driveopts.append('children.%d.file.driver=blkdebug' % i) + driveopts.append('children.%d.file.config=%s' % (i, img_conf[i])) + driveopts.append('children.%d.file.image.filename=%s' % (i, imgs[i])) + driveopts.append('children.%d.node-name=img%d' % (i, i)) + self.vm = iotests.VM() + self.vm.add_drive(None, opts = ','.join(driveopts)) + self.vm.launch() + + def tearDown(self): + self.vm.shutdown() + for i in range(len(imgs)): + os.remove(imgs[i]) + os.remove(img_conf[i]) + + def do_check_event(self, node, sector = 0): + if node == None: + self.assertEqual(self.vm.get_qmp_event(), None) + return + + for event in self.vm.get_qmp_events(wait=True): + if event['event'] == 'QUORUM_REPORT_BAD': + self.assert_qmp(event, 'data/node-name', node) + self.assert_qmp(event, 'data/sector-num', sector) + + def testQuorum(self): + # Generate an error and get an event + self.vm.hmp_qemu_io("drive0", "aio_read %d %d" % + (offset * sector_size, sector_size)) + self.vm.qtest("clock_step 10") + self.do_check_event('img0', offset) + + # I/O errors in the same child: only one event is emitted + delay = 10 + for i in range(3): + self.vm.hmp_qemu_io("drive0", "aio_read %d %d" % + (offset * sector_size, sector_size)) + self.vm.qtest("clock_step %d" % delay) + self.do_check_event(None) + + # Wait enough so the event is finally emitted + self.vm.qtest("clock_step %d" % (2 * event_rate)) + self.do_check_event('img0', offset) + + # I/O errors in the same child: all events are emitted + delay = 2 * event_rate + for i in range(3): + self.vm.hmp_qemu_io("drive0", "aio_read %d %d" % + (offset * sector_size, sector_size)) + self.vm.qtest("clock_step %d" % delay) + self.do_check_event('img0', offset) + + # I/O errors in different children: all events are emitted + delay = 10 + for i in range(len(imgs)): + self.vm.hmp_qemu_io("drive0", "aio_read %d %d" % + ((offset + i) * sector_size, sector_size)) + self.vm.qtest("clock_step %d" % delay) + # In fifo mode only errors in the first child are detected + if i > 0 and self.read_pattern == 'fifo': + self.do_check_event(None) + else: + self.do_check_event('img%d' % i, offset + i) + + # I/O errors in different children: all events are emitted + delay = 2 * event_rate + for i in range(len(imgs)): + self.vm.hmp_qemu_io("drive0", "aio_read %d %d" % + ((offset + i) * sector_size, sector_size)) + self.vm.qtest("clock_step %d" % delay) + # In fifo mode only errors in the first child are detected + if i > 0 and self.read_pattern == 'fifo': + self.do_check_event(None) + else: + self.do_check_event('img%d' % i, offset + i) + + # No more pending events + self.do_check_event(None) + +class TestFifoQuorumEvents(TestQuorumEvents): + read_pattern = 'fifo' + +if __name__ == '__main__': + iotests.verify_quorum() + iotests.main(supported_fmts=["raw"]) diff --git a/qemu/tests/qemu-iotests/148.out b/qemu/tests/qemu-iotests/148.out new file mode 100644 index 000000000..fbc63e62f --- /dev/null +++ b/qemu/tests/qemu-iotests/148.out @@ -0,0 +1,5 @@ +.. +---------------------------------------------------------------------- +Ran 2 tests + +OK diff --git a/qemu/tests/qemu-iotests/149 b/qemu/tests/qemu-iotests/149 new file mode 100755 index 000000000..52e23d294 --- /dev/null +++ b/qemu/tests/qemu-iotests/149 @@ -0,0 +1,519 @@ +#!/usr/bin/env python +# +# 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: Daniel P. Berrange <berrange@redhat.com> +# +# Exercise the QEMU 'luks' block driver to validate interoperability +# with the Linux dm-crypt + cryptsetup implementation + +import subprocess +import os +import os.path + +import base64 + +import iotests + + +class LUKSConfig(object): + """Represent configuration parameters for a single LUKS + setup to be tested""" + + def __init__(self, name, cipher, keylen, mode, ivgen, + ivgen_hash, hash, password=None, passwords=None): + + self.name = name + self.cipher = cipher + self.keylen = keylen + self.mode = mode + self.ivgen = ivgen + self.ivgen_hash = ivgen_hash + self.hash = hash + + if passwords is not None: + self.passwords = passwords + else: + self.passwords = {} + + if password is None: + self.passwords["0"] = "123456" + else: + self.passwords["0"] = password + + def __repr__(self): + return self.name + + def image_name(self): + return "luks-%s.img" % self.name + + def image_path(self): + return os.path.join(iotests.test_dir, self.image_name()) + + def device_name(self): + return "qiotest-145-%s" % self.name + + def device_path(self): + return "/dev/mapper/" + self.device_name() + + def first_password(self): + for i in range(8): + slot = str(i) + if slot in self.passwords: + return (self.passwords[slot], slot) + raise Exception("No password found") + + def first_password_base64(self): + (pw, slot) = self.first_password() + return base64.b64encode(pw) + + def active_slots(self): + slots = [] + for i in range(8): + slot = str(i) + if slot in self.passwords: + slots.append(slot) + return slots + +def verify_passwordless_sudo(): + """Check whether sudo is configured to allow + password-less access to commands""" + + args = ["sudo", "-n", "/bin/true"] + + proc = subprocess.Popen(args, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + + msg = proc.communicate()[0] + + if proc.returncode != 0: + iotests.notrun('requires password-less sudo access: %s' % msg) + + +def cryptsetup(args, password=None): + """Run the cryptsetup command in batch mode""" + + fullargs = ["sudo", "cryptsetup", "-q", "-v"] + fullargs.extend(args) + + iotests.log(" ".join(fullargs), filters=[iotests.filter_test_dir]) + proc = subprocess.Popen(fullargs, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + + msg = proc.communicate(password)[0] + + if proc.returncode != 0: + raise Exception(msg) + + +def cryptsetup_add_password(config, slot): + """Add another password to a LUKS key slot""" + + (password, mainslot) = config.first_password() + + pwfile = os.path.join(iotests.test_dir, "passwd.txt") + with open(pwfile, "w") as fh: + fh.write(config.passwords[slot]) + + try: + args = ["luksAddKey", config.image_path(), + "--key-slot", slot, + "--key-file", "-", + pwfile] + + cryptsetup(args, password) + finally: + os.unlink(pwfile) + + +def cryptsetup_format(config): + """Format a new LUKS volume with cryptsetup, adding the + first key slot only""" + + (password, slot) = config.first_password() + + args = ["luksFormat"] + cipher = config.cipher + "-" + config.mode + "-" + config.ivgen + if config.ivgen_hash is not None: + cipher = cipher + ":" + config.ivgen_hash + args.extend(["--cipher", cipher]) + if config.mode == "xts": + args.extend(["--key-size", str(config.keylen * 2)]) + else: + args.extend(["--key-size", str(config.keylen)]) + if config.hash is not None: + args.extend(["--hash", config.hash]) + args.extend(["--key-slot", slot]) + args.extend(["--key-file", "-"]) + args.append(config.image_path()) + + cryptsetup(args, password) + + +def chown(config): + """Set the ownership of a open LUKS device to this user""" + + path = config.device_path() + + args = ["sudo", "chown", "%d:%d" % (os.getuid(), os.getgid()), path] + iotests.log(" ".join(args), filters=[iotests.filter_chown]) + proc = subprocess.Popen(args, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + + msg = proc.communicate()[0] + + if proc.returncode != 0: + raise Exception("Cannot change owner on %s" % path) + + +def cryptsetup_open(config): + """Open an image as a LUKS device""" + + (password, slot) = config.first_password() + + args = ["luksOpen", config.image_path(), config.device_name()] + + cryptsetup(args, password) + + +def cryptsetup_close(config): + """Close an active LUKS device """ + + args = ["luksClose", config.device_name()] + cryptsetup(args) + + +def delete_image(config): + """Delete a disk image""" + + try: + os.unlink(config.image_path()) + iotests.log("unlink %s" % config.image_path(), + filters=[iotests.filter_test_dir]) + except Exception as e: + pass + + +def create_image(config, size_mb): + """Create a bare disk image with requested size""" + + delete_image(config) + iotests.log("truncate %s --size %dMB" % (config.image_path(), size_mb), + filters=[iotests.filter_test_dir]) + with open(config.image_path(), "w") as fn: + fn.truncate(size_mb * 1024 * 1024) + + +def qemu_img_create(config, size_mb): + """Create and format a disk image with LUKS using qemu-img""" + + opts = [ + "key-secret=sec0", + "cipher-alg=%s-%d" % (config.cipher, config.keylen), + "cipher-mode=%s" % config.mode, + "ivgen-alg=%s" % config.ivgen, + "hash-alg=%s" % config.hash, + ] + if config.ivgen_hash is not None: + opts.append("ivgen-hash-alg=%s" % config.ivgen_hash) + + args = ["create", "-f", "luks", + "--object", + ("secret,id=sec0,data=%s,format=base64" % + config.first_password_base64()), + "-o", ",".join(opts), + config.image_path(), + "%dM" % size_mb] + + iotests.log("qemu-img " + " ".join(args), filters=[iotests.filter_test_dir]) + iotests.log(iotests.qemu_img_pipe(*args), filters=[iotests.filter_test_dir]) + +def qemu_io_image_args(config, dev=False): + """Get the args for access an image or device with qemu-io""" + + if dev: + return [ + "--image-opts", + "driver=file,filename=%s" % config.device_path()] + else: + return [ + "--object", + ("secret,id=sec0,data=%s,format=base64" % + config.first_password_base64()), + "--image-opts", + ("driver=luks,key-secret=sec0,file.filename=%s" % + config.image_path())] + +def qemu_io_write_pattern(config, pattern, offset_mb, size_mb, dev=False): + """Write a pattern of data to a LUKS image or device""" + + args = ["-c", "write -P 0x%x %dM %dM" % (pattern, offset_mb, size_mb)] + args.extend(qemu_io_image_args(config, dev)) + iotests.log("qemu-io " + " ".join(args), filters=[iotests.filter_test_dir]) + iotests.log(iotests.qemu_io(*args), filters=[iotests.filter_test_dir, + iotests.filter_qemu_io]) + + +def qemu_io_read_pattern(config, pattern, offset_mb, size_mb, dev=False): + """Read a pattern of data to a LUKS image or device""" + + args = ["-c", "read -P 0x%x %dM %dM" % (pattern, offset_mb, size_mb)] + args.extend(qemu_io_image_args(config, dev)) + iotests.log("qemu-io " + " ".join(args), filters=[iotests.filter_test_dir]) + iotests.log(iotests.qemu_io(*args), filters=[iotests.filter_test_dir, + iotests.filter_qemu_io]) + + +def test_once(config, qemu_img=False): + """Run the test with a desired LUKS configuration. Can either + use qemu-img for creating the initial volume, or cryptsetup, + in order to test interoperability in both directions""" + + iotests.log("# ================= %s %s =================" % ( + "qemu-img" if qemu_img else "dm-crypt", config)) + + oneKB = 1024 + oneMB = oneKB * 1024 + oneGB = oneMB * 1024 + oneTB = oneGB * 1024 + + # 4 TB, so that we pass the 32-bit sector number boundary. + # Important for testing correctness of some IV generators + # The files are sparse, so not actually using this much space + image_size = 4 * oneTB + if qemu_img: + iotests.log("# Create image") + qemu_img_create(config, image_size / oneMB) + else: + iotests.log("# Create image") + create_image(config, image_size / oneMB) + + lowOffsetMB = 100 + highOffsetMB = 3 * oneTB / oneMB + + try: + if not qemu_img: + iotests.log("# Format image") + cryptsetup_format(config) + + for slot in config.active_slots()[1:]: + iotests.log("# Add password slot %s" % slot) + cryptsetup_add_password(config, slot) + + # First we'll open the image using cryptsetup and write a + # known pattern of data that we'll then verify with QEMU + + iotests.log("# Open dev") + cryptsetup_open(config) + + try: + iotests.log("# Set dev owner") + chown(config) + + iotests.log("# Write test pattern 0xa7") + qemu_io_write_pattern(config, 0xa7, lowOffsetMB, 10, dev=True) + iotests.log("# Write test pattern 0x13") + qemu_io_write_pattern(config, 0x13, highOffsetMB, 10, dev=True) + finally: + iotests.log("# Close dev") + cryptsetup_close(config) + + # Ok, now we're using QEMU to verify the pattern just + # written via dm-crypt + + iotests.log("# Read test pattern 0xa7") + qemu_io_read_pattern(config, 0xa7, lowOffsetMB, 10, dev=False) + iotests.log("# Read test pattern 0x13") + qemu_io_read_pattern(config, 0x13, highOffsetMB, 10, dev=False) + + + # Write a new pattern to the image, which we'll later + # verify with dm-crypt + iotests.log("# Write test pattern 0x91") + qemu_io_write_pattern(config, 0x91, lowOffsetMB, 10, dev=False) + iotests.log("# Write test pattern 0x5e") + qemu_io_write_pattern(config, 0x5e, highOffsetMB, 10, dev=False) + + + # Now we're opening the image with dm-crypt once more + # and verifying what QEMU wrote, completing the circle + iotests.log("# Open dev") + cryptsetup_open(config) + + try: + iotests.log("# Set dev owner") + chown(config) + + iotests.log("# Read test pattern 0x91") + qemu_io_read_pattern(config, 0x91, lowOffsetMB, 10, dev=True) + iotests.log("# Read test pattern 0x5e") + qemu_io_read_pattern(config, 0x5e, highOffsetMB, 10, dev=True) + finally: + iotests.log("# Close dev") + cryptsetup_close(config) + finally: + iotests.log("# Delete image") + delete_image(config) + print + + +# Obviously we only work with the luks image format +iotests.verify_image_format(supported_fmts=['luks']) +iotests.verify_platform() + +# We need sudo in order to run cryptsetup to create +# dm-crypt devices. This is safe to use on any +# machine, since all dm-crypt devices are backed +# by newly created plain files, and have a dm-crypt +# name prefix of 'qiotest' to avoid clashing with +# user LUKS volumes +verify_passwordless_sudo() + + +# If we look at all permutations of cipher, key size, +# mode, ivgen, hash, there are ~1000 possible configs. +# +# We certainly don't want/need to test every permutation +# to get good validation of interoperability between QEMU +# and dm-crypt/cryptsetup. +# +# The configs below are a representative set that aim to +# exercise each axis of configurability. +# +configs = [ + # A common LUKS default + LUKSConfig("aes-256-xts-plain64-sha1", + "aes", 256, "xts", "plain64", None, "sha1"), + + + # LUKS default but diff ciphers + LUKSConfig("twofish-256-xts-plain64-sha1", + "twofish", 256, "xts", "plain64", None, "sha1"), + LUKSConfig("serpent-256-xts-plain64-sha1", + "serpent", 256, "xts", "plain64", None, "sha1"), + # Should really be xts, but kernel doesn't support xts+cast5 + # nor does it do essiv+cast5 + LUKSConfig("cast5-128-cbc-plain64-sha1", + "cast5", 128, "cbc", "plain64", None, "sha1"), + LUKSConfig("cast6-256-xts-plain64-sha1", + "cast6", 256, "xts", "plain64", None, "sha1"), + + + # LUKS default but diff modes / ivgens + LUKSConfig("aes-256-cbc-plain-sha1", + "aes", 256, "cbc", "plain", None, "sha1"), + LUKSConfig("aes-256-cbc-plain64-sha1", + "aes", 256, "cbc", "plain64", None, "sha1"), + LUKSConfig("aes-256-cbc-essiv-sha256-sha1", + "aes", 256, "cbc", "essiv", "sha256", "sha1"), + LUKSConfig("aes-256-xts-essiv-sha256-sha1", + "aes", 256, "xts", "essiv", "sha256", "sha1"), + + + # LUKS default but smaller key sizes + LUKSConfig("aes-128-xts-plain64-sha256-sha1", + "aes", 128, "xts", "plain64", None, "sha1"), + LUKSConfig("aes-192-xts-plain64-sha256-sha1", + "aes", 192, "xts", "plain64", None, "sha1"), + + LUKSConfig("twofish-128-xts-plain64-sha1", + "twofish", 128, "xts", "plain64", None, "sha1"), + LUKSConfig("twofish-192-xts-plain64-sha1", + "twofish", 192, "xts", "plain64", None, "sha1"), + + LUKSConfig("serpent-128-xts-plain64-sha1", + "serpent", 128, "xts", "plain64", None, "sha1"), + LUKSConfig("serpent-192-xts-plain64-sha1", + "serpent", 192, "xts", "plain64", None, "sha1"), + + LUKSConfig("cast6-128-xts-plain64-sha1", + "cast6", 128, "xts", "plain", None, "sha1"), + LUKSConfig("cast6-192-xts-plain64-sha1", + "cast6", 192, "xts", "plain64", None, "sha1"), + + + # LUKS default but diff hash + LUKSConfig("aes-256-xts-plain64-sha256", + "aes", 256, "xts", "plain64", None, "sha256"), + LUKSConfig("aes-256-xts-plain64-sha512", + "aes", 256, "xts", "plain64", None, "sha512"), + LUKSConfig("aes-256-xts-plain64-ripemd160", + "aes", 256, "xts", "plain64", None, "ripemd160"), + + # Password in slot 3 + LUKSConfig("aes-256-xts-plain-sha1-pwslot3", + "aes", 256, "xts", "plain", None, "sha1", + passwords={ + "3": "slot3", + }), + + # Passwords in every slot + LUKSConfig("aes-256-xts-plain-sha1-pwallslots", + "aes", 256, "xts", "plain", None, "sha1", + passwords={ + "0": "slot1", + "1": "slot1", + "2": "slot2", + "3": "slot3", + "4": "slot4", + "5": "slot5", + "6": "slot6", + "7": "slot7", + }), +] + +blacklist = [ + # We don't have a cast-6 cipher impl for QEMU yet + "cast6-256-xts-plain64-sha1", + "cast6-128-xts-plain64-sha1", + "cast6-192-xts-plain64-sha1", + + # GCrypt doesn't support Twofish with 192 bit key + "twofish-192-xts-plain64-sha1", + + # We don't have sha512 hash wired up yet + "aes-256-xts-plain64-sha512", + + # We don't have ripemd160 hash wired up yet + "aes-256-xts-plain64-ripemd160", +] + +whitelist = [] +if "LUKS_CONFIG" in os.environ: + whitelist = os.environ["LUKS_CONFIG"].split(",") + +for config in configs: + if config.name in blacklist: + iotests.log("Skipping %s in blacklist" % config.name) + continue + + if len(whitelist) > 0 and config.name not in whitelist: + iotests.log("Skipping %s not in whitelist" % config.name) + continue + + test_once(config, qemu_img=False) + + # XXX we should support setting passwords in a non-0 + # key slot with 'qemu-img create' in future + (pw, slot) = config.first_password() + if slot == "0": + test_once(config, qemu_img=True) diff --git a/qemu/tests/qemu-iotests/149.out b/qemu/tests/qemu-iotests/149.out new file mode 100644 index 000000000..287f01301 --- /dev/null +++ b/qemu/tests/qemu-iotests/149.out @@ -0,0 +1,1880 @@ +# ================= dm-crypt aes-256-xts-plain64-sha1 ================= +# Create image +truncate TEST_DIR/luks-aes-256-xts-plain64-sha1.img --size 4194304MB +# Format image +sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 512 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-aes-256-xts-plain64-sha1.img +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha1.img qiotest-145-aes-256-xts-plain64-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 +# Write test pattern 0xa7 +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x13 +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha1 +# Read test pattern 0xa7 +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha1.img +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x13 +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha1.img +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x91 +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha1.img +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x5e +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha1.img +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha1.img qiotest-145-aes-256-xts-plain64-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 +# Read test pattern 0x91 +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x5e +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha1 +# Delete image +unlink TEST_DIR/luks-aes-256-xts-plain64-sha1.img + +# ================= qemu-img aes-256-xts-plain64-sha1 ================= +# Create image +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-aes-256-xts-plain64-sha1.img 4194304M +Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha1.img qiotest-145-aes-256-xts-plain64-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 +# Write test pattern 0xa7 +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x13 +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha1 +# Read test pattern 0xa7 +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha1.img +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x13 +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha1.img +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x91 +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha1.img +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x5e +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha1.img +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha1.img qiotest-145-aes-256-xts-plain64-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 +# Read test pattern 0x91 +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x5e +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha1 +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha1 +# Delete image +unlink TEST_DIR/luks-aes-256-xts-plain64-sha1.img + +# ================= dm-crypt twofish-256-xts-plain64-sha1 ================= +# Create image +truncate TEST_DIR/luks-twofish-256-xts-plain64-sha1.img --size 4194304MB +# Format image +sudo cryptsetup -q -v luksFormat --cipher twofish-xts-plain64 --key-size 512 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-twofish-256-xts-plain64-sha1.img +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-256-xts-plain64-sha1.img qiotest-145-twofish-256-xts-plain64-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 +# Write test pattern 0xa7 +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x13 +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-twofish-256-xts-plain64-sha1 +# Read test pattern 0xa7 +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-twofish-256-xts-plain64-sha1.img +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x13 +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-twofish-256-xts-plain64-sha1.img +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x91 +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-twofish-256-xts-plain64-sha1.img +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x5e +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-twofish-256-xts-plain64-sha1.img +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-256-xts-plain64-sha1.img qiotest-145-twofish-256-xts-plain64-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 +# Read test pattern 0x91 +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x5e +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-twofish-256-xts-plain64-sha1 +# Delete image +unlink TEST_DIR/luks-twofish-256-xts-plain64-sha1.img + +# ================= qemu-img twofish-256-xts-plain64-sha1 ================= +# Create image +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=twofish-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-twofish-256-xts-plain64-sha1.img 4194304M +Formatting 'TEST_DIR/luks-twofish-256-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=twofish-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-256-xts-plain64-sha1.img qiotest-145-twofish-256-xts-plain64-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 +# Write test pattern 0xa7 +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x13 +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-twofish-256-xts-plain64-sha1 +# Read test pattern 0xa7 +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-twofish-256-xts-plain64-sha1.img +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x13 +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-twofish-256-xts-plain64-sha1.img +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x91 +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-twofish-256-xts-plain64-sha1.img +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x5e +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-twofish-256-xts-plain64-sha1.img +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-256-xts-plain64-sha1.img qiotest-145-twofish-256-xts-plain64-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 +# Read test pattern 0x91 +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x5e +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-256-xts-plain64-sha1 +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-twofish-256-xts-plain64-sha1 +# Delete image +unlink TEST_DIR/luks-twofish-256-xts-plain64-sha1.img + +# ================= dm-crypt serpent-256-xts-plain64-sha1 ================= +# Create image +truncate TEST_DIR/luks-serpent-256-xts-plain64-sha1.img --size 4194304MB +# Format image +sudo cryptsetup -q -v luksFormat --cipher serpent-xts-plain64 --key-size 512 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-serpent-256-xts-plain64-sha1.img +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-256-xts-plain64-sha1.img qiotest-145-serpent-256-xts-plain64-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 +# Write test pattern 0xa7 +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x13 +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-serpent-256-xts-plain64-sha1 +# Read test pattern 0xa7 +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-serpent-256-xts-plain64-sha1.img +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x13 +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-serpent-256-xts-plain64-sha1.img +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x91 +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-serpent-256-xts-plain64-sha1.img +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x5e +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-serpent-256-xts-plain64-sha1.img +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-256-xts-plain64-sha1.img qiotest-145-serpent-256-xts-plain64-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 +# Read test pattern 0x91 +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x5e +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-serpent-256-xts-plain64-sha1 +# Delete image +unlink TEST_DIR/luks-serpent-256-xts-plain64-sha1.img + +# ================= qemu-img serpent-256-xts-plain64-sha1 ================= +# Create image +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=serpent-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-serpent-256-xts-plain64-sha1.img 4194304M +Formatting 'TEST_DIR/luks-serpent-256-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=serpent-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-256-xts-plain64-sha1.img qiotest-145-serpent-256-xts-plain64-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 +# Write test pattern 0xa7 +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x13 +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-serpent-256-xts-plain64-sha1 +# Read test pattern 0xa7 +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-serpent-256-xts-plain64-sha1.img +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x13 +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-serpent-256-xts-plain64-sha1.img +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x91 +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-serpent-256-xts-plain64-sha1.img +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x5e +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-serpent-256-xts-plain64-sha1.img +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-256-xts-plain64-sha1.img qiotest-145-serpent-256-xts-plain64-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 +# Read test pattern 0x91 +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x5e +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-256-xts-plain64-sha1 +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-serpent-256-xts-plain64-sha1 +# Delete image +unlink TEST_DIR/luks-serpent-256-xts-plain64-sha1.img + +# ================= dm-crypt cast5-128-cbc-plain64-sha1 ================= +# Create image +truncate TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img --size 4194304MB +# Format image +sudo cryptsetup -q -v luksFormat --cipher cast5-cbc-plain64 --key-size 128 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img qiotest-145-cast5-128-cbc-plain64-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 +# Write test pattern 0xa7 +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x13 +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-cast5-128-cbc-plain64-sha1 +# Read test pattern 0xa7 +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x13 +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x91 +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x5e +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img qiotest-145-cast5-128-cbc-plain64-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 +# Read test pattern 0x91 +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x5e +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-cast5-128-cbc-plain64-sha1 +# Delete image +unlink TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img + +# ================= qemu-img cast5-128-cbc-plain64-sha1 ================= +# Create image +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=cast5-128,cipher-mode=cbc,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img 4194304M +Formatting 'TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=cast5-128 cipher-mode=cbc ivgen-alg=plain64 hash-alg=sha1 + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img qiotest-145-cast5-128-cbc-plain64-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 +# Write test pattern 0xa7 +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x13 +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-cast5-128-cbc-plain64-sha1 +# Read test pattern 0xa7 +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x13 +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x91 +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x5e +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img qiotest-145-cast5-128-cbc-plain64-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 +# Read test pattern 0x91 +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x5e +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-cast5-128-cbc-plain64-sha1 +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-cast5-128-cbc-plain64-sha1 +# Delete image +unlink TEST_DIR/luks-cast5-128-cbc-plain64-sha1.img + +Skipping cast6-256-xts-plain64-sha1 in blacklist +# ================= dm-crypt aes-256-cbc-plain-sha1 ================= +# Create image +truncate TEST_DIR/luks-aes-256-cbc-plain-sha1.img --size 4194304MB +# Format image +sudo cryptsetup -q -v luksFormat --cipher aes-cbc-plain --key-size 256 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-aes-256-cbc-plain-sha1.img +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain-sha1.img qiotest-145-aes-256-cbc-plain-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 +# Write test pattern 0xa7 +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x13 +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-cbc-plain-sha1 +# Read test pattern 0xa7 +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-cbc-plain-sha1.img +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x13 +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-cbc-plain-sha1.img +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x91 +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-cbc-plain-sha1.img +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x5e +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-cbc-plain-sha1.img +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain-sha1.img qiotest-145-aes-256-cbc-plain-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 +# Read test pattern 0x91 +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x5e +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-cbc-plain-sha1 +# Delete image +unlink TEST_DIR/luks-aes-256-cbc-plain-sha1.img + +# ================= qemu-img aes-256-cbc-plain-sha1 ================= +# Create image +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=plain,hash-alg=sha1 TEST_DIR/luks-aes-256-cbc-plain-sha1.img 4194304M +Formatting 'TEST_DIR/luks-aes-256-cbc-plain-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=plain hash-alg=sha1 + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain-sha1.img qiotest-145-aes-256-cbc-plain-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 +# Write test pattern 0xa7 +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x13 +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-cbc-plain-sha1 +# Read test pattern 0xa7 +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-cbc-plain-sha1.img +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x13 +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-cbc-plain-sha1.img +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x91 +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-cbc-plain-sha1.img +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x5e +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-cbc-plain-sha1.img +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain-sha1.img qiotest-145-aes-256-cbc-plain-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 +# Read test pattern 0x91 +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x5e +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain-sha1 +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-cbc-plain-sha1 +# Delete image +unlink TEST_DIR/luks-aes-256-cbc-plain-sha1.img + +# ================= dm-crypt aes-256-cbc-plain64-sha1 ================= +# Create image +truncate TEST_DIR/luks-aes-256-cbc-plain64-sha1.img --size 4194304MB +# Format image +sudo cryptsetup -q -v luksFormat --cipher aes-cbc-plain64 --key-size 256 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-aes-256-cbc-plain64-sha1.img +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain64-sha1.img qiotest-145-aes-256-cbc-plain64-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 +# Write test pattern 0xa7 +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x13 +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-cbc-plain64-sha1 +# Read test pattern 0xa7 +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-cbc-plain64-sha1.img +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x13 +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-cbc-plain64-sha1.img +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x91 +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-cbc-plain64-sha1.img +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x5e +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-cbc-plain64-sha1.img +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain64-sha1.img qiotest-145-aes-256-cbc-plain64-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 +# Read test pattern 0x91 +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x5e +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-cbc-plain64-sha1 +# Delete image +unlink TEST_DIR/luks-aes-256-cbc-plain64-sha1.img + +# ================= qemu-img aes-256-cbc-plain64-sha1 ================= +# Create image +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-aes-256-cbc-plain64-sha1.img 4194304M +Formatting 'TEST_DIR/luks-aes-256-cbc-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=plain64 hash-alg=sha1 + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain64-sha1.img qiotest-145-aes-256-cbc-plain64-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 +# Write test pattern 0xa7 +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x13 +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-cbc-plain64-sha1 +# Read test pattern 0xa7 +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-cbc-plain64-sha1.img +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x13 +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-cbc-plain64-sha1.img +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x91 +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-cbc-plain64-sha1.img +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x5e +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-cbc-plain64-sha1.img +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-plain64-sha1.img qiotest-145-aes-256-cbc-plain64-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 +# Read test pattern 0x91 +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x5e +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-plain64-sha1 +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-cbc-plain64-sha1 +# Delete image +unlink TEST_DIR/luks-aes-256-cbc-plain64-sha1.img + +# ================= dm-crypt aes-256-cbc-essiv-sha256-sha1 ================= +# Create image +truncate TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img --size 4194304MB +# Format image +sudo cryptsetup -q -v luksFormat --cipher aes-cbc-essiv:sha256 --key-size 256 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img qiotest-145-aes-256-cbc-essiv-sha256-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 +# Write test pattern 0xa7 +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x13 +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-cbc-essiv-sha256-sha1 +# Read test pattern 0xa7 +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x13 +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x91 +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x5e +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img qiotest-145-aes-256-cbc-essiv-sha256-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 +# Read test pattern 0x91 +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x5e +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-cbc-essiv-sha256-sha1 +# Delete image +unlink TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img + +# ================= qemu-img aes-256-cbc-essiv-sha256-sha1 ================= +# Create image +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=aes-256,cipher-mode=cbc,ivgen-alg=essiv,hash-alg=sha1,ivgen-hash-alg=sha256 TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img 4194304M +Formatting 'TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=cbc ivgen-alg=essiv ivgen-hash-alg=sha256 hash-alg=sha1 + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img qiotest-145-aes-256-cbc-essiv-sha256-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 +# Write test pattern 0xa7 +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x13 +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-cbc-essiv-sha256-sha1 +# Read test pattern 0xa7 +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x13 +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x91 +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x5e +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img qiotest-145-aes-256-cbc-essiv-sha256-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 +# Read test pattern 0x91 +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x5e +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-cbc-essiv-sha256-sha1 +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-cbc-essiv-sha256-sha1 +# Delete image +unlink TEST_DIR/luks-aes-256-cbc-essiv-sha256-sha1.img + +# ================= dm-crypt aes-256-xts-essiv-sha256-sha1 ================= +# Create image +truncate TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img --size 4194304MB +# Format image +sudo cryptsetup -q -v luksFormat --cipher aes-xts-essiv:sha256 --key-size 512 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img qiotest-145-aes-256-xts-essiv-sha256-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 +# Write test pattern 0xa7 +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x13 +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-essiv-sha256-sha1 +# Read test pattern 0xa7 +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x13 +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x91 +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x5e +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img qiotest-145-aes-256-xts-essiv-sha256-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 +# Read test pattern 0x91 +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x5e +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-essiv-sha256-sha1 +# Delete image +unlink TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img + +# ================= qemu-img aes-256-xts-essiv-sha256-sha1 ================= +# Create image +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=essiv,hash-alg=sha1,ivgen-hash-alg=sha256 TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img 4194304M +Formatting 'TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=essiv ivgen-hash-alg=sha256 hash-alg=sha1 + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img qiotest-145-aes-256-xts-essiv-sha256-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 +# Write test pattern 0xa7 +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x13 +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-essiv-sha256-sha1 +# Read test pattern 0xa7 +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x13 +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x91 +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x5e +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img qiotest-145-aes-256-xts-essiv-sha256-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 +# Read test pattern 0x91 +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x5e +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-essiv-sha256-sha1 +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-essiv-sha256-sha1 +# Delete image +unlink TEST_DIR/luks-aes-256-xts-essiv-sha256-sha1.img + +# ================= dm-crypt aes-128-xts-plain64-sha256-sha1 ================= +# Create image +truncate TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img --size 4194304MB +# Format image +sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 256 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img qiotest-145-aes-128-xts-plain64-sha256-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 +# Write test pattern 0xa7 +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x13 +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-128-xts-plain64-sha256-sha1 +# Read test pattern 0xa7 +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x13 +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x91 +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x5e +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img qiotest-145-aes-128-xts-plain64-sha256-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 +# Read test pattern 0x91 +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x5e +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-128-xts-plain64-sha256-sha1 +# Delete image +unlink TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img + +# ================= qemu-img aes-128-xts-plain64-sha256-sha1 ================= +# Create image +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=aes-128,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img 4194304M +Formatting 'TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-128 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img qiotest-145-aes-128-xts-plain64-sha256-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 +# Write test pattern 0xa7 +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x13 +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-128-xts-plain64-sha256-sha1 +# Read test pattern 0xa7 +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x13 +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x91 +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x5e +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img qiotest-145-aes-128-xts-plain64-sha256-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 +# Read test pattern 0x91 +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x5e +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-128-xts-plain64-sha256-sha1 +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-128-xts-plain64-sha256-sha1 +# Delete image +unlink TEST_DIR/luks-aes-128-xts-plain64-sha256-sha1.img + +# ================= dm-crypt aes-192-xts-plain64-sha256-sha1 ================= +# Create image +truncate TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img --size 4194304MB +# Format image +sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 384 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img qiotest-145-aes-192-xts-plain64-sha256-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 +# Write test pattern 0xa7 +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x13 +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-192-xts-plain64-sha256-sha1 +# Read test pattern 0xa7 +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x13 +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x91 +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x5e +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img qiotest-145-aes-192-xts-plain64-sha256-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 +# Read test pattern 0x91 +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x5e +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-192-xts-plain64-sha256-sha1 +# Delete image +unlink TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img + +# ================= qemu-img aes-192-xts-plain64-sha256-sha1 ================= +# Create image +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=aes-192,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img 4194304M +Formatting 'TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-192 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img qiotest-145-aes-192-xts-plain64-sha256-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 +# Write test pattern 0xa7 +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x13 +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-192-xts-plain64-sha256-sha1 +# Read test pattern 0xa7 +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x13 +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x91 +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x5e +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img qiotest-145-aes-192-xts-plain64-sha256-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 +# Read test pattern 0x91 +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x5e +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-192-xts-plain64-sha256-sha1 +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-192-xts-plain64-sha256-sha1 +# Delete image +unlink TEST_DIR/luks-aes-192-xts-plain64-sha256-sha1.img + +# ================= dm-crypt twofish-128-xts-plain64-sha1 ================= +# Create image +truncate TEST_DIR/luks-twofish-128-xts-plain64-sha1.img --size 4194304MB +# Format image +sudo cryptsetup -q -v luksFormat --cipher twofish-xts-plain64 --key-size 256 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-twofish-128-xts-plain64-sha1.img +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-128-xts-plain64-sha1.img qiotest-145-twofish-128-xts-plain64-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 +# Write test pattern 0xa7 +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x13 +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-twofish-128-xts-plain64-sha1 +# Read test pattern 0xa7 +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-twofish-128-xts-plain64-sha1.img +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x13 +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-twofish-128-xts-plain64-sha1.img +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x91 +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-twofish-128-xts-plain64-sha1.img +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x5e +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-twofish-128-xts-plain64-sha1.img +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-128-xts-plain64-sha1.img qiotest-145-twofish-128-xts-plain64-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 +# Read test pattern 0x91 +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x5e +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-twofish-128-xts-plain64-sha1 +# Delete image +unlink TEST_DIR/luks-twofish-128-xts-plain64-sha1.img + +# ================= qemu-img twofish-128-xts-plain64-sha1 ================= +# Create image +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=twofish-128,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-twofish-128-xts-plain64-sha1.img 4194304M +Formatting 'TEST_DIR/luks-twofish-128-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=twofish-128 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-128-xts-plain64-sha1.img qiotest-145-twofish-128-xts-plain64-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 +# Write test pattern 0xa7 +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x13 +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-twofish-128-xts-plain64-sha1 +# Read test pattern 0xa7 +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-twofish-128-xts-plain64-sha1.img +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x13 +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-twofish-128-xts-plain64-sha1.img +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x91 +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-twofish-128-xts-plain64-sha1.img +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x5e +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-twofish-128-xts-plain64-sha1.img +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-twofish-128-xts-plain64-sha1.img qiotest-145-twofish-128-xts-plain64-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 +# Read test pattern 0x91 +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x5e +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-twofish-128-xts-plain64-sha1 +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-twofish-128-xts-plain64-sha1 +# Delete image +unlink TEST_DIR/luks-twofish-128-xts-plain64-sha1.img + +Skipping twofish-192-xts-plain64-sha1 in blacklist +# ================= dm-crypt serpent-128-xts-plain64-sha1 ================= +# Create image +truncate TEST_DIR/luks-serpent-128-xts-plain64-sha1.img --size 4194304MB +# Format image +sudo cryptsetup -q -v luksFormat --cipher serpent-xts-plain64 --key-size 256 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-serpent-128-xts-plain64-sha1.img +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-128-xts-plain64-sha1.img qiotest-145-serpent-128-xts-plain64-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 +# Write test pattern 0xa7 +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x13 +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-serpent-128-xts-plain64-sha1 +# Read test pattern 0xa7 +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-serpent-128-xts-plain64-sha1.img +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x13 +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-serpent-128-xts-plain64-sha1.img +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x91 +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-serpent-128-xts-plain64-sha1.img +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x5e +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-serpent-128-xts-plain64-sha1.img +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-128-xts-plain64-sha1.img qiotest-145-serpent-128-xts-plain64-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 +# Read test pattern 0x91 +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x5e +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-serpent-128-xts-plain64-sha1 +# Delete image +unlink TEST_DIR/luks-serpent-128-xts-plain64-sha1.img + +# ================= qemu-img serpent-128-xts-plain64-sha1 ================= +# Create image +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=serpent-128,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-serpent-128-xts-plain64-sha1.img 4194304M +Formatting 'TEST_DIR/luks-serpent-128-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=serpent-128 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-128-xts-plain64-sha1.img qiotest-145-serpent-128-xts-plain64-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 +# Write test pattern 0xa7 +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x13 +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-serpent-128-xts-plain64-sha1 +# Read test pattern 0xa7 +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-serpent-128-xts-plain64-sha1.img +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x13 +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-serpent-128-xts-plain64-sha1.img +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x91 +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-serpent-128-xts-plain64-sha1.img +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x5e +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-serpent-128-xts-plain64-sha1.img +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-128-xts-plain64-sha1.img qiotest-145-serpent-128-xts-plain64-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 +# Read test pattern 0x91 +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x5e +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-128-xts-plain64-sha1 +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-serpent-128-xts-plain64-sha1 +# Delete image +unlink TEST_DIR/luks-serpent-128-xts-plain64-sha1.img + +# ================= dm-crypt serpent-192-xts-plain64-sha1 ================= +# Create image +truncate TEST_DIR/luks-serpent-192-xts-plain64-sha1.img --size 4194304MB +# Format image +sudo cryptsetup -q -v luksFormat --cipher serpent-xts-plain64 --key-size 384 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-serpent-192-xts-plain64-sha1.img +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-192-xts-plain64-sha1.img qiotest-145-serpent-192-xts-plain64-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 +# Write test pattern 0xa7 +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x13 +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-serpent-192-xts-plain64-sha1 +# Read test pattern 0xa7 +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-serpent-192-xts-plain64-sha1.img +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x13 +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-serpent-192-xts-plain64-sha1.img +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x91 +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-serpent-192-xts-plain64-sha1.img +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x5e +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-serpent-192-xts-plain64-sha1.img +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-192-xts-plain64-sha1.img qiotest-145-serpent-192-xts-plain64-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 +# Read test pattern 0x91 +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x5e +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-serpent-192-xts-plain64-sha1 +# Delete image +unlink TEST_DIR/luks-serpent-192-xts-plain64-sha1.img + +# ================= qemu-img serpent-192-xts-plain64-sha1 ================= +# Create image +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=serpent-192,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha1 TEST_DIR/luks-serpent-192-xts-plain64-sha1.img 4194304M +Formatting 'TEST_DIR/luks-serpent-192-xts-plain64-sha1.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=serpent-192 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha1 + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-192-xts-plain64-sha1.img qiotest-145-serpent-192-xts-plain64-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 +# Write test pattern 0xa7 +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x13 +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-serpent-192-xts-plain64-sha1 +# Read test pattern 0xa7 +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-serpent-192-xts-plain64-sha1.img +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x13 +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-serpent-192-xts-plain64-sha1.img +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x91 +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-serpent-192-xts-plain64-sha1.img +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x5e +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-serpent-192-xts-plain64-sha1.img +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-serpent-192-xts-plain64-sha1.img qiotest-145-serpent-192-xts-plain64-sha1 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 +# Read test pattern 0x91 +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x5e +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-serpent-192-xts-plain64-sha1 +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-serpent-192-xts-plain64-sha1 +# Delete image +unlink TEST_DIR/luks-serpent-192-xts-plain64-sha1.img + +Skipping cast6-128-xts-plain64-sha1 in blacklist +Skipping cast6-192-xts-plain64-sha1 in blacklist +# ================= dm-crypt aes-256-xts-plain64-sha256 ================= +# Create image +truncate TEST_DIR/luks-aes-256-xts-plain64-sha256.img --size 4194304MB +# Format image +sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain64 --key-size 512 --hash sha256 --key-slot 0 --key-file - TEST_DIR/luks-aes-256-xts-plain64-sha256.img +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha256.img qiotest-145-aes-256-xts-plain64-sha256 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 +# Write test pattern 0xa7 +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x13 +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha256 +# Read test pattern 0xa7 +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha256.img +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x13 +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha256.img +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x91 +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha256.img +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x5e +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha256.img +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha256.img qiotest-145-aes-256-xts-plain64-sha256 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 +# Read test pattern 0x91 +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x5e +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha256 +# Delete image +unlink TEST_DIR/luks-aes-256-xts-plain64-sha256.img + +# ================= qemu-img aes-256-xts-plain64-sha256 ================= +# Create image +qemu-img create -f luks --object secret,id=sec0,data=MTIzNDU2,format=base64 -o key-secret=sec0,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain64,hash-alg=sha256 TEST_DIR/luks-aes-256-xts-plain64-sha256.img 4194304M +Formatting 'TEST_DIR/luks-aes-256-xts-plain64-sha256.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain64 hash-alg=sha256 + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha256.img qiotest-145-aes-256-xts-plain64-sha256 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 +# Write test pattern 0xa7 +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x13 +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha256 +# Read test pattern 0xa7 +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha256.img +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x13 +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha256.img +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x91 +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha256.img +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x5e +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=MTIzNDU2,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain64-sha256.img +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain64-sha256.img qiotest-145-aes-256-xts-plain64-sha256 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 +# Read test pattern 0x91 +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x5e +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain64-sha256 +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain64-sha256 +# Delete image +unlink TEST_DIR/luks-aes-256-xts-plain64-sha256.img + +Skipping aes-256-xts-plain64-sha512 in blacklist +Skipping aes-256-xts-plain64-ripemd160 in blacklist +# ================= dm-crypt aes-256-xts-plain-sha1-pwslot3 ================= +# Create image +truncate TEST_DIR/luks-aes-256-xts-plain-sha1-pwslot3.img --size 4194304MB +# Format image +sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain --key-size 512 --hash sha1 --key-slot 3 --key-file - TEST_DIR/luks-aes-256-xts-plain-sha1-pwslot3.img +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain-sha1-pwslot3.img qiotest-145-aes-256-xts-plain-sha1-pwslot3 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwslot3 +# Write test pattern 0xa7 +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwslot3 +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x13 +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwslot3 +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain-sha1-pwslot3 +# Read test pattern 0xa7 +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=c2xvdDM=,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain-sha1-pwslot3.img +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x13 +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=c2xvdDM=,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain-sha1-pwslot3.img +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x91 +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=c2xvdDM=,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain-sha1-pwslot3.img +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x5e +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=c2xvdDM=,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain-sha1-pwslot3.img +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain-sha1-pwslot3.img qiotest-145-aes-256-xts-plain-sha1-pwslot3 +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwslot3 +# Read test pattern 0x91 +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwslot3 +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x5e +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwslot3 +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain-sha1-pwslot3 +# Delete image +unlink TEST_DIR/luks-aes-256-xts-plain-sha1-pwslot3.img + +# ================= dm-crypt aes-256-xts-plain-sha1-pwallslots ================= +# Create image +truncate TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --size 4194304MB +# Format image +sudo cryptsetup -q -v luksFormat --cipher aes-xts-plain --key-size 512 --hash sha1 --key-slot 0 --key-file - TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img +# Add password slot 1 +sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 1 --key-file - TEST_DIR/passwd.txt +# Add password slot 2 +sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 2 --key-file - TEST_DIR/passwd.txt +# Add password slot 3 +sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 3 --key-file - TEST_DIR/passwd.txt +# Add password slot 4 +sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 4 --key-file - TEST_DIR/passwd.txt +# Add password slot 5 +sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 5 --key-file - TEST_DIR/passwd.txt +# Add password slot 6 +sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 6 --key-file - TEST_DIR/passwd.txt +# Add password slot 7 +sudo cryptsetup -q -v luksAddKey TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img --key-slot 7 --key-file - TEST_DIR/passwd.txt +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img qiotest-145-aes-256-xts-plain-sha1-pwallslots +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots +# Write test pattern 0xa7 +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x13 +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain-sha1-pwallslots +# Read test pattern 0xa7 +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=c2xvdDE=,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x13 +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=c2xvdDE=,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x91 +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=c2xvdDE=,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x5e +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=c2xvdDE=,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img qiotest-145-aes-256-xts-plain-sha1-pwallslots +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots +# Read test pattern 0x91 +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x5e +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain-sha1-pwallslots +# Delete image +unlink TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img + +# ================= qemu-img aes-256-xts-plain-sha1-pwallslots ================= +# Create image +qemu-img create -f luks --object secret,id=sec0,data=c2xvdDE=,format=base64 -o key-secret=sec0,cipher-alg=aes-256,cipher-mode=xts,ivgen-alg=plain,hash-alg=sha1 TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img 4194304M +Formatting 'TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img', fmt=luks size=4398046511104 key-secret=sec0 cipher-alg=aes-256 cipher-mode=xts ivgen-alg=plain hash-alg=sha1 + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img qiotest-145-aes-256-xts-plain-sha1-pwallslots +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots +# Write test pattern 0xa7 +qemu-io -c write -P 0xa7 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x13 +qemu-io -c write -P 0x13 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain-sha1-pwallslots +# Read test pattern 0xa7 +qemu-io -c read -P 0xa7 100M 10M --object secret,id=sec0,data=c2xvdDE=,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x13 +qemu-io -c read -P 0x13 3145728M 10M --object secret,id=sec0,data=c2xvdDE=,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x91 +qemu-io -c write -P 0x91 100M 10M --object secret,id=sec0,data=c2xvdDE=,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img +wrote 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Write test pattern 0x5e +qemu-io -c write -P 0x5e 3145728M 10M --object secret,id=sec0,data=c2xvdDE=,format=base64 --image-opts driver=luks,key-secret=sec0,file.filename=TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img +wrote 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Open dev +sudo cryptsetup -q -v luksOpen TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img qiotest-145-aes-256-xts-plain-sha1-pwallslots +# Set dev owner +sudo chown UID:GID /dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots +# Read test pattern 0x91 +qemu-io -c read -P 0x91 100M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots +read 10485760/10485760 bytes at offset 104857600 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Read test pattern 0x5e +qemu-io -c read -P 0x5e 3145728M 10M --image-opts driver=file,filename=/dev/mapper/qiotest-145-aes-256-xts-plain-sha1-pwallslots +read 10485760/10485760 bytes at offset 3298534883328 +10 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +# Close dev +sudo cryptsetup -q -v luksClose qiotest-145-aes-256-xts-plain-sha1-pwallslots +# Delete image +unlink TEST_DIR/luks-aes-256-xts-plain-sha1-pwallslots.img + diff --git a/qemu/tests/qemu-iotests/150 b/qemu/tests/qemu-iotests/150 new file mode 100755 index 000000000..ee8f6375f --- /dev/null +++ b/qemu/tests/qemu-iotests/150 @@ -0,0 +1,73 @@ +#!/bin/bash +# +# Test that qemu-img convert -S 0 fully allocates the target image +# +# 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=mreitz@redhat.com + +seq="$(basename $0)" +echo "QA output created by $seq" + +here="$PWD" +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 + +_supported_fmt raw qcow2 +_supported_proto file +_supported_os Linux + + +img_size=1048576 + + +echo +echo '=== Mapping sparse conversion ===' +echo + +$QEMU_IMG_PROG convert -O "$IMGFMT" -S 512 \ + "json:{ 'driver': 'null-co', 'size': $img_size, 'read-zeroes': true }" \ + "$TEST_IMG" + +$QEMU_IMG map "$TEST_IMG" | _filter_qemu_img_map + + +echo +echo '=== Mapping non-sparse conversion ===' +echo + +$QEMU_IMG convert -O "$IMGFMT" -S 0 \ + "json:{ 'driver': 'null-co', 'size': $img_size, 'read-zeroes': true }" \ + "$TEST_IMG" + +$QEMU_IMG map "$TEST_IMG" | _filter_qemu_img_map + + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/qemu/tests/qemu-iotests/150.out b/qemu/tests/qemu-iotests/150.out new file mode 100644 index 000000000..2a54e8dcf --- /dev/null +++ b/qemu/tests/qemu-iotests/150.out @@ -0,0 +1,11 @@ +QA output created by 150 + +=== Mapping sparse conversion === + +Offset Length File + +=== Mapping non-sparse conversion === + +Offset Length File +0 0x100000 TEST_DIR/t.IMGFMT +*** done diff --git a/qemu/tests/qemu-iotests/152 b/qemu/tests/qemu-iotests/152 new file mode 100644 index 000000000..fec546d03 --- /dev/null +++ b/qemu/tests/qemu-iotests/152 @@ -0,0 +1,62 @@ +#!/usr/bin/env python +# +# Tests for drive-mirror with source size unaligned to granularity +# +# 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/>. +# + +import os +import iotests +from iotests import qemu_img + +test_img = os.path.join(iotests.test_dir, 'test.img') +target_img = os.path.join(iotests.test_dir, 'target.img') + +class TestUnaligned(iotests.QMPTestCase): + def setUp(self): + qemu_img('create', '-f', iotests.imgfmt, test_img, '512') + self.vm = iotests.VM().add_drive(test_img) + self.vm.launch() + + def tearDown(self): + self.vm.shutdown() + os.remove(test_img) + try: + os.remove(target_img) + except OSError: + pass + + def test_unaligned(self): + result = self.vm.qmp('drive-mirror', device='drive0', sync='full', + granularity=65536, target=target_img) + self.complete_and_wait() + self.vm.shutdown() + self.assertEqual(iotests.image_size(test_img), iotests.image_size(target_img), + "Target size doesn't match source when granularity when unaligend") + + def test_unaligned_with_update(self): + result = self.vm.qmp('drive-mirror', device='drive0', sync='full', + granularity=65536, target=target_img) + self.wait_ready() + self.vm.hmp_qemu_io('drive0', 'write 0 512') + self.complete_and_wait(wait_ready=False) + self.vm.shutdown() + self.assertEqual(iotests.image_size(test_img), iotests.image_size(target_img), + "Target size doesn't match source when granularity when unaligend") + + +if __name__ == '__main__': + iotests.main(supported_fmts=['raw', 'qcow2']) diff --git a/qemu/tests/qemu-iotests/152.out b/qemu/tests/qemu-iotests/152.out new file mode 100644 index 000000000..fbc63e62f --- /dev/null +++ b/qemu/tests/qemu-iotests/152.out @@ -0,0 +1,5 @@ +.. +---------------------------------------------------------------------- +Ran 2 tests + +OK diff --git a/qemu/tests/qemu-iotests/check b/qemu/tests/qemu-iotests/check index 1fa63193b..4cba2151e 100755 --- a/qemu/tests/qemu-iotests/check +++ b/qemu/tests/qemu-iotests/check @@ -19,7 +19,6 @@ # Control script for QA # -tmp=/tmp/$$ status=0 needwrap=true try=0 @@ -130,6 +129,8 @@ fi # exit 1 #fi +tmp="${TEST_DIR}"/$$ + _wallclock() { date "+%H %M %S" | $AWK_PROG '{ print $1*3600 + $2*60 + $3 }' @@ -146,8 +147,8 @@ _wrapup() # for hangcheck ... # remove files that were used by hangcheck # - [ -f /tmp/check.pid ] && rm -rf /tmp/check.pid - [ -f /tmp/check.sts ] && rm -rf /tmp/check.sts + [ -f "${TEST_DIR}"/check.pid ] && rm -rf "${TEST_DIR}"/check.pid + [ -f "${TEST_DIR}"/check.sts ] && rm -rf "${TEST_DIR}"/check.sts if $showme then @@ -197,8 +198,8 @@ END { if (NR > 0) { needwrap=false fi - rm -f /tmp/*.out /tmp/*.err /tmp/*.time - rm -f /tmp/check.pid /tmp/check.sts + rm -f "${TEST_DIR}"/*.out "${TEST_DIR}"/*.err "${TEST_DIR}"/*.time + rm -f "${TEST_DIR}"/check.pid "${TEST_DIR}"/check.sts rm -f $tmp.* } @@ -208,16 +209,16 @@ trap "_wrapup; exit \$status" 0 1 2 3 15 # Save pid of check in a well known place, so that hangcheck can be sure it # has the right pid (getting the pid from ps output is not reliable enough). # -rm -rf /tmp/check.pid -echo $$ >/tmp/check.pid +rm -rf "${TEST_DIR}"/check.pid +echo $$ > "${TEST_DIR}"/check.pid # for hangcheck ... # Save the status of check in a well known place, so that hangcheck can be # sure to know where check is up to (getting test number from ps output is # not reliable enough since the trace stuff has been introduced). # -rm -rf /tmp/check.sts -echo "preamble" >/tmp/check.sts +rm -rf "${TEST_DIR}"/check.sts +echo "preamble" > "${TEST_DIR}"/check.sts # don't leave old full output behind on a clean run rm -f check.full @@ -231,10 +232,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 @@ -285,7 +286,7 @@ do rm -f core $seq.notrun # for hangcheck ... - echo "$seq" >/tmp/check.sts + echo "$seq" > "${TEST_DIR}"/check.sts start=`_wallclock` $timestamp && echo -n " ["`date "+%T"`"]" @@ -330,6 +331,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/qemu/tests/qemu-iotests/common b/qemu/tests/qemu-iotests/common index 1030aaf25..49e193112 100644 --- a/qemu/tests/qemu-iotests/common +++ b/qemu/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 @@ -154,6 +155,7 @@ check options -ssh test ssh -nfs test nfs -archipelago test archipelago + -luks test luks -xdiff graphical mode diff -nocache use O_DIRECT on backing file -misalign misalign memory allocations @@ -277,7 +279,7 @@ testlist options ;; -valgrind) - valgrind=true + VALGRIND_QEMU='y' xpand=false ;; @@ -435,8 +437,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/qemu/tests/qemu-iotests/common.config b/qemu/tests/qemu-iotests/common.config index a1973ad9d..f824651ba 100644 --- a/qemu/tests/qemu-iotests/common.config +++ b/qemu/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,63 @@ 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="${TEST_DIR}"/$$.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 help | sed -n '/(default)/ s/ .*//p') +default_alias_machine=$($QEMU -machine help | \ + sed -n "/(alias of $default_machine)/ { s/ .*//p; q; }") +if [[ "$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/qemu/tests/qemu-iotests/common.filter b/qemu/tests/qemu-iotests/common.filter index 012a8122d..8a6e1b57c 100644 --- a/qemu/tests/qemu-iotests/common.filter +++ b/qemu/tests/qemu-iotests/common.filter @@ -19,107 +19,6 @@ # standard filters # -# Checks that given_value is in range of correct_value +/- tolerance. -# Tolerance can be an absolute value or a percentage of the correct value -# (see examples with tolerances below). -# Outputs suitable message to stdout if it's not in range. -# -# A verbose option, -v, may be used as the LAST argument -# -# e.g. -# foo: 0.0298 = 0.03 +/- 5% -# _within_tolerance "foo" 0.0298 0.03 5% -# -# foo: 0.0298 = 0.03 +/- 0.01 -# _within_tolerance "foo" 0.0298 0.03 0.01 -# -# foo: 0.0298 = 0.03 -0.01 +0.002 -# _within_tolerance "foo" 0.0298 0.03 0.01 0.002 -# -# foo: verbose output of 0.0298 = 0.03 +/- 5% -# _within_tolerance "foo" 0.0298 0.03 5% -v -_within_tolerance() -{ - _name=$1 - _given_val=$2 - _correct_val=$3 - _mintol=$4 - _maxtol=$_mintol - _verbose=0 - _debug=false - - # maxtol arg is optional - # verbose arg is optional - if [ $# -ge 5 ] - then - if [ "$5" = "-v" ] - then - _verbose=1 - else - _maxtol=$5 - fi - fi - if [ $# -ge 6 ] - then - [ "$6" = "-v" ] && _verbose=1 - fi - - # find min with or without % - _mintolerance=`echo $_mintol | sed -e 's/%//'` - if [ $_mintol = $_mintolerance ] - then - _min=`echo "scale=5; $_correct_val-$_mintolerance" | bc` - else - _min=`echo "scale=5; $_correct_val-$_mintolerance*0.01*$_correct_val" | bc` - fi - - # find max with or without % - _maxtolerance=`echo $_maxtol | sed -e 's/%//'` - if [ $_maxtol = $_maxtolerance ] - then - _max=`echo "scale=5; $_correct_val+$_maxtolerance" | bc` - else - _max=`echo "scale=5; $_correct_val+$_maxtolerance*0.01*$_correct_val" | bc` - fi - - $_debug && echo "min = $_min" - $_debug && echo "max = $_max" - - cat <<EOF >$tmp.bc.1 -scale=5; -if ($_min <= $_given_val) 1; -if ($_min > $_given_val) 0; -EOF - - cat <<EOF >$tmp.bc.2 -scale=5; -if ($_given_val <= $_max) 1; -if ($_given_val > $_max) 0; -EOF - - _above_min=`bc <$tmp.bc.1` - _below_max=`bc <$tmp.bc.2` - - rm -f $tmp.bc.[12] - - _in_range=`expr $_above_min \& $_below_max` - - # fix up min, max precision for output - # can vary for 5.3, 6.2 - _min=`echo $_min | sed -e 's/0*$//'` # get rid of trailling zeroes - _max=`echo $_max | sed -e 's/0*$//'` # get rid of trailling zeroes - - if [ $_in_range -eq 1 ] - then - [ $_verbose -eq 1 ] && echo $_name is in range - return 0 - else - [ $_verbose -eq 1 ] && echo $_name has value of $_given_val - [ $_verbose -eq 1 ] && echo $_name is NOT in range $_min .. $_max - return 1 - fi -} - # ctime(3) dates # _filter_date() @@ -128,6 +27,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 +86,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" \ @@ -225,5 +129,18 @@ _filter_qemu_img_map() -e 's/Mapped to *//' | _filter_testdir | _filter_imgfmt } +_filter_nbd() +{ + # nbd.c error messages contain function names and line numbers that are + # prone to change. Message ordering depends on timing between send and + # receive callbacks sometimes, making them unreliable. + # + # Filter out the TCP port number since this changes between runs. + sed -e '/nbd\/.*\.c:/d' \ + -e 's#nbd:\(//\)\?127\.0\.0\.1:[0-9]*#nbd:\1127.0.0.1:PORT#g' \ + -e "s#?socket=$TEST_DIR#?socket=TEST_DIR#g" \ + -e 's#\(exportname=foo\|PORT\): Failed to .*$#\1#' +} + # make sure this script returns success true diff --git a/qemu/tests/qemu-iotests/common.qemu b/qemu/tests/qemu-iotests/common.qemu index 4e1996c3e..2548a8700 100644 --- a/qemu/tests/qemu-iotests/common.qemu +++ b/qemu/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 @@ -131,6 +129,8 @@ function _send_qemu_cmd() # $qemu_comm_method: set this variable to 'monitor' (case insensitive) # to use the QEMU HMP monitor for communication. # Otherwise, the default of QMP is used. +# $keep_stderr: Set this variable to 'y' to keep QEMU's stderr output on stderr. +# If this variable is empty, stderr will be redirected to stdout. # Returns: # $QEMU_HANDLE: set to a handle value to communicate with this QEMU instance. # @@ -153,11 +153,20 @@ function _launch_qemu() mkfifo "${fifo_out}" mkfifo "${fifo_in}" - "${QEMU}" -nographic -serial none ${comm} -machine accel=qtest "${@}" \ + if [ -z "$keep_stderr" ]; then + QEMU_NEED_PID='y'\ + ${QEMU} -nographic -serial none ${comm} -machine accel=qtest "${@}" \ >"${fifo_out}" \ 2>&1 \ <"${fifo_in}" & - QEMU_PID[${_QEMU_HANDLE}]=$! + elif [ "$keep_stderr" = "y" ]; then + QEMU_NEED_PID='y'\ + ${QEMU} -nographic -serial none ${comm} -machine accel=qtest "${@}" \ + >"${fifo_out}" \ + <"${fifo_in}" & + else + exit 1 + fi if [[ "${BASH_VERSINFO[0]}" -ge "5" || ("${BASH_VERSINFO[0]}" -ge "4" && "${BASH_VERSINFO[1]}" -ge "1") ]] @@ -196,10 +205,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/qemu/tests/qemu-iotests/common.rc b/qemu/tests/qemu-iotests/common.rc index 22d351404..5249ec592 100644 --- a/qemu/tests/qemu-iotests/common.rc +++ b/qemu/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" ;; @@ -295,52 +287,6 @@ _need_to_be_root() fi } - -# Do a command, log it to $seq.full, optionally test return status -# and die if command fails. If called with one argument _do executes the -# command, logs it, and returns its exit status. With two arguments _do -# first prints the message passed in the first argument, and then "done" -# or "fail" depending on the return status of the command passed in the -# second argument. If the command fails and the variable _do_die_on_error -# is set to "always" or the two argument form is used and _do_die_on_error -# is set to "message_only" _do will print an error message to -# $seq.out and exit. - -_do() -{ - if [ $# -eq 1 ]; then - _cmd=$1 - elif [ $# -eq 2 ]; then - _note=$1 - _cmd=$2 - echo -n "$_note... " - else - echo "Usage: _do [note] cmd" 1>&2 - status=1; exit - fi - - (eval "echo '---' \"$_cmd\"") >>"$OUTPUT_DIR/$seq.full" - (eval "$_cmd") >$tmp._out 2>&1; ret=$? - cat $tmp._out >>"$OUTPUT_DIR/$seq.full" - if [ $# -eq 2 ]; then - if [ $ret -eq 0 ]; then - echo "done" - else - echo "fail" - fi - fi - if [ $ret -ne 0 ] \ - && [ "$_do_die_on_error" = "always" \ - -o \( $# -eq 2 -a "$_do_die_on_error" = "message_only" \) ] - then - [ $# -ne 2 ] && echo - eval "echo \"$_cmd\" failed \(returned $ret\): see $seq.full" - status=1; exit - fi - - return $ret -} - # bail out, setting up .notrun file # _notrun() @@ -439,7 +385,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/qemu/tests/qemu-iotests/group b/qemu/tests/qemu-iotests/group index c430b6c23..822953b6f 100644 --- a/qemu/tests/qemu-iotests/group +++ b/qemu/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,8 @@ 114 rw auto quick 115 rw auto 116 rw auto quick +117 rw auto +118 rw auto 119 rw auto quick 120 rw auto quick 121 rw auto @@ -132,5 +135,21 @@ 130 rw auto quick 131 rw auto quick 132 rw auto quick +133 auto quick 134 rw auto quick 135 rw auto +136 rw auto +137 rw auto +138 rw auto quick +139 rw auto quick +140 rw auto quick +141 rw auto quick +142 auto +143 auto quick +144 rw auto quick +145 auto quick +146 auto quick +148 rw auto quick +149 rw auto sudo +150 rw auto quick +152 rw auto quick diff --git a/qemu/tests/qemu-iotests/iotests.py b/qemu/tests/qemu-iotests/iotests.py index 8615b1075..56f988ab3 100644 --- a/qemu/tests/qemu-iotests/iotests.py +++ b/qemu/tests/qemu-iotests/iotests.py @@ -16,6 +16,7 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # +import errno import os import re import subprocess @@ -27,41 +28,66 @@ sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'scripts', ' import qmp import qtest import struct +import json -__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, + stderr=subprocess.STDOUT) + 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, + stderr=subprocess.STDOUT) + 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''' @@ -78,6 +104,33 @@ def create_image(name, size): i = i + 512 file.close() +def image_size(img): + '''Return image's virtual size''' + r = qemu_img_pipe('info', '--output=json', '-f', imgfmt, img) + return json.loads(r)['virtual-size'] + +test_dir_re = re.compile(r"%s" % test_dir) +def filter_test_dir(msg): + return test_dir_re.sub("TEST_DIR", msg) + +win32_re = re.compile(r"\r") +def filter_win32(msg): + return win32_re.sub("", msg) + +qemu_io_re = re.compile(r"[0-9]* ops; [0-9\/:. sec]* \([0-9\/.inf]* [EPTGMKiBbytes]*\/sec and [0-9\/.inf]* ops\/sec\)") +def filter_qemu_io(msg): + msg = filter_win32(msg) + return qemu_io_re.sub("X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)", msg) + +chown_re = re.compile(r"chown [0-9]+:[0-9]+") +def filter_chown(msg): + return chown_re.sub("chown UID:GID", msg) + +def log(msg, filters=[]): + for flt in filters: + msg = flt(msg) + print msg + # Test if 'match' is a recursive subset of 'event' def event_match(event, match=None): if match is None: @@ -117,13 +170,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', - 'format=%s' % imgfmt, - 'cache=%s' % cachemode, - 'file=%s' % path, + options = ['if=%s' % interface, 'id=drive%d' % self._num_drives] + + if path is not None: + options.append('file=%s' % path) + options.append('format=%s' % imgfmt) + options.append('cache=%s' % cachemode) + if opts: options.append(opts) @@ -189,14 +250,17 @@ class VM(object): self._qmp.accept() self._qtest.accept() except: - os.remove(self._monitor_path) + _remove_if_exists(self._monitor_path) + _remove_if_exists(self._qtest_path) raise def shutdown(self): '''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) @@ -290,6 +354,20 @@ class QMPTestCase(unittest.TestCase): result = self.vm.qmp('query-block-jobs') self.assert_qmp(result, 'return', []) + def assert_has_block_node(self, node_name=None, file_name=None): + """Issue a query-named-block-nodes and assert node_name and/or + file_name is present in the result""" + def check_equal_or_none(a, b): + return a == None or b == None or a == b + assert node_name or file_name + result = self.vm.qmp('query-named-block-nodes') + for x in result["return"]: + if check_equal_or_none(x.get("node-name"), node_name) and \ + check_equal_or_none(x.get("file"), file_name): + return + self.assertTrue(False, "Cannot find %s %s in result:\n%s" % \ + (node_name, file_name, result)) + def cancel_and_wait(self, drive='drive0', force=False, resume=False): '''Cancel a block job and wait for it to finish, returning the event''' result = self.vm.qmp('block-job-cancel', device=drive, force=force) @@ -349,6 +427,15 @@ class QMPTestCase(unittest.TestCase): event = self.wait_until_completed(drive=drive) self.assert_qmp(event, 'data/type', 'mirror') +def _remove_if_exists(path): + '''Remove file object at path if it exists''' + try: + os.remove(path) + except OSError as exception: + if exception.errno == errno.ENOENT: + return + raise + def notrun(reason): '''Skip this test suite''' # Each test in qemu-iotests has a number ("seq") @@ -358,17 +445,27 @@ def notrun(reason): print '%s not run: %s' % (seq, reason) sys.exit(0) -def main(supported_fmts=[], supported_oses=['linux']): - '''Run tests''' - - debug = '-d' in sys.argv - verbosity = 1 +def verify_image_format(supported_fmts=[]): if supported_fmts and (imgfmt not in supported_fmts): notrun('not suitable for this image format: %s' % imgfmt) +def verify_platform(supported_oses=['linux']): if True not in [sys.platform.startswith(x) for x in supported_oses]: notrun('not suitable for this OS: %s' % sys.platform) +def verify_quorum(): + '''Skip test suite if quorum support is not available''' + if 'quorum' not in qemu_img_pipe('--help'): + notrun('quorum support missing') + +def main(supported_fmts=[], supported_oses=['linux']): + '''Run tests''' + + debug = '-d' in sys.argv + verbosity = 1 + verify_image_format(supported_fmts) + verify_platform(supported_oses) + # We need to filter out the time taken from the output so that qemu-iotest # can reliably diff the results against master output. import StringIO diff --git a/qemu/tests/qemu-iotests/qed.py b/qemu/tests/qemu-iotests/qed.py index 52ff84559..748068d7f 100755 --- a/qemu/tests/qemu-iotests/qed.py +++ b/qemu/tests/qemu-iotests/qed.py @@ -227,7 +227,7 @@ def main(): qed = QED(open(filename, 'r+b')) try: globals()[cmd](qed, *sys.argv[3:]) - except TypeError, e: + except TypeError as e: sys.stderr.write(globals()[cmd].__doc__ + '\n') sys.exit(1) diff --git a/qemu/tests/qemu-iotests/sample_images/d2v-zerofilled.vhd.bz2 b/qemu/tests/qemu-iotests/sample_images/d2v-zerofilled.vhd.bz2 Binary files differnew file mode 100644 index 000000000..f12cb9203 --- /dev/null +++ b/qemu/tests/qemu-iotests/sample_images/d2v-zerofilled.vhd.bz2 diff --git a/qemu/tests/qemu-iotests/sample_images/hyperv2012r2-dynamic.vhd.bz2 b/qemu/tests/qemu-iotests/sample_images/hyperv2012r2-dynamic.vhd.bz2 Binary files differnew file mode 100644 index 000000000..bfeccf7b9 --- /dev/null +++ b/qemu/tests/qemu-iotests/sample_images/hyperv2012r2-dynamic.vhd.bz2 diff --git a/qemu/tests/qemu-iotests/sample_images/virtualpc-dynamic.vhd.bz2 b/qemu/tests/qemu-iotests/sample_images/virtualpc-dynamic.vhd.bz2 Binary files differnew file mode 100644 index 000000000..783be3c8f --- /dev/null +++ b/qemu/tests/qemu-iotests/sample_images/virtualpc-dynamic.vhd.bz2 diff --git a/qemu/tests/qemu-iotests/socket_scm_helper.c b/qemu/tests/qemu-iotests/socket_scm_helper.c index 81959835e..80cadf43b 100644 --- a/qemu/tests/qemu-iotests/socket_scm_helper.c +++ b/qemu/tests/qemu-iotests/socket_scm_helper.c @@ -10,15 +10,9 @@ * See the COPYING.LIB file in the top-level directory. */ -#include <stdio.h> -#include <errno.h> +#include "qemu/osdep.h" #include <sys/socket.h> #include <sys/un.h> -#include <stdlib.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> /* #define SOCKET_SCM_DEBUG */ diff --git a/qemu/tests/qom-test.c b/qemu/tests/qom-test.c index fde04e7a1..bd5cdde26 100644 --- a/qemu/tests/qom-test.c +++ b/qemu/tests/qom-test.c @@ -7,12 +7,12 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <string.h> #include "qemu-common.h" +#include "qemu/cutils.h" #include "libqtest.h" -#include "qemu/osdep.h" #include "qapi/qmp/types.h" static const char *blacklist_x86[] = { @@ -47,7 +47,7 @@ static bool is_blacklisted(const char *arch, const char *mach) static void test_properties(const char *path, bool recurse) { char *child_path; - QDict *response, *tuple; + QDict *response, *tuple, *tmp; QList *list; QListEntry *entry; @@ -57,6 +57,7 @@ static void test_properties(const char *path, bool recurse) g_assert(response); if (!recurse) { + QDECREF(response); return; } @@ -75,14 +76,16 @@ static void test_properties(const char *path, bool recurse) } else { const char *prop = qdict_get_str(tuple, "name"); g_test_message("Testing property %s.%s", path, prop); - response = qmp("{ 'execute': 'qom-get'," - " 'arguments': { 'path': %s," - " 'property': %s } }", - path, prop); + tmp = qmp("{ 'execute': 'qom-get'," + " 'arguments': { 'path': %s," + " 'property': %s } }", + path, prop); /* qom-get may fail but should not, e.g., segfault. */ - g_assert(response); + g_assert(tmp); + QDECREF(tmp); } } + QDECREF(response); } static void test_machine(gconstpointer data) @@ -98,9 +101,11 @@ static void test_machine(gconstpointer data) response = qmp("{ 'execute': 'quit' }"); g_assert(qdict_haskey(response, "return")); + QDECREF(response); qtest_end(); g_free(args); + g_free((void *)machine); } static void add_machine_test_cases(void) @@ -129,10 +134,12 @@ static void add_machine_test_cases(void) mname = qstring_get_str(qstr); if (!is_blacklisted(arch, mname)) { path = g_strdup_printf("qom/%s", mname); - qtest_add_data_func(path, mname, test_machine); + qtest_add_data_func(path, g_strdup(mname), test_machine); } } + qtest_end(); + QDECREF(response); } int main(int argc, char **argv) diff --git a/qemu/tests/rcutorture.c b/qemu/tests/rcutorture.c index d6b304d00..244f0f28b 100644 --- a/qemu/tests/rcutorture.c +++ b/qemu/tests/rcutorture.c @@ -60,13 +60,10 @@ * Test variables. */ +#include "qemu/osdep.h" #include <glib.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> #include "qemu/atomic.h" #include "qemu/rcu.h" -#include "qemu/compiler.h" #include "qemu/thread.h" long long n_reads = 0LL; diff --git a/qemu/tests/rtc-test.c b/qemu/tests/rtc-test.c index 4243624de..fa7029aa8 100644 --- a/qemu/tests/rtc-test.c +++ b/qemu/tests/rtc-test.c @@ -11,11 +11,8 @@ * */ +#include "qemu/osdep.h" #include <glib.h> -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <unistd.h> #include "libqtest.h" #include "hw/timer/mc146818rtc_regs.h" diff --git a/qemu/tests/rtl8139-test.c b/qemu/tests/rtl8139-test.c index e749be38e..54e5aa7d0 100644 --- a/qemu/tests/rtl8139-test.c +++ b/qemu/tests/rtl8139-test.c @@ -7,11 +7,10 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <string.h> #include "libqtest.h" #include "libqos/pci-pc.h" -#include "qemu/osdep.h" #include "qemu/timer.h" #include "qemu-common.h" @@ -20,7 +19,7 @@ static void nop(void) { } -#define CLK 33000000 +#define CLK 33333333 static QPCIBus *pcibus; static QPCIDevice *dev; diff --git a/qemu/tests/spapr-phb-test.c b/qemu/tests/spapr-phb-test.c index b629de475..f53911d9f 100644 --- a/qemu/tests/spapr-phb-test.c +++ b/qemu/tests/spapr-phb-test.c @@ -7,6 +7,7 @@ * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> #include "libqtest.h" diff --git a/qemu/tests/tcg/linux-test.c b/qemu/tests/tcg/linux-test.c index 1c6c01318..5070d3144 100644 --- a/qemu/tests/tcg/linux-test.c +++ b/qemu/tests/tcg/linux-test.c @@ -39,6 +39,7 @@ #include <dirent.h> #include <setjmp.h> #include <sys/shm.h> +#include "qemu/cutils.h" #define TESTPATH "/tmp/linux-test.tmp" #define TESTPORT 7654 diff --git a/qemu/tests/tcg/test-i386-fprem.c b/qemu/tests/tcg/test-i386-fprem.c index e91fb1ae9..1a7162320 100644 --- a/qemu/tests/tcg/test-i386-fprem.c +++ b/qemu/tests/tcg/test-i386-fprem.c @@ -22,10 +22,8 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, see <http://www.gnu.org/licenses/>. */ -#include "qemu/compiler.h" + #include "qemu/osdep.h" -#include <stdio.h> -#include <inttypes.h> /* * Inspired by <ieee754.h>'s union ieee854_long_double, but with single diff --git a/qemu/tests/tcg/testthread.c b/qemu/tests/tcg/testthread.c index 2679af119..810ba5de6 100644 --- a/qemu/tests/tcg/testthread.c +++ b/qemu/tests/tcg/testthread.c @@ -2,7 +2,6 @@ #include <stdlib.h> #include <stdio.h> #include <string.h> -#include <signal.h> #include <unistd.h> #include <inttypes.h> #include <pthread.h> diff --git a/qemu/tests/tco-test.c b/qemu/tests/tco-test.c index 419f7cf46..ac11175e9 100644 --- a/qemu/tests/tco-test.c +++ b/qemu/tests/tco-test.c @@ -6,10 +6,8 @@ * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <string.h> -#include <stdio.h> -#include <stdlib.h> #include "libqtest.h" #include "libqos/pci.h" diff --git a/qemu/tests/test-aio.c b/qemu/tests/test-aio.c index 217e33772..687dfa062 100644 --- a/qemu/tests/test-aio.c +++ b/qemu/tests/test-aio.c @@ -10,8 +10,10 @@ * See the COPYING.LIB file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> #include "block/aio.h" +#include "qapi/error.h" #include "qemu/timer.h" #include "qemu/sockets.h" #include "qemu/error-report.h" @@ -118,6 +120,12 @@ static void *test_acquire_thread(void *opaque) return NULL; } +static void set_event_notifier(AioContext *ctx, EventNotifier *notifier, + EventNotifierHandler *handler) +{ + aio_set_event_notifier(ctx, notifier, false, handler); +} + static void dummy_notifier_read(EventNotifier *unused) { g_assert(false); /* should never be invoked */ @@ -131,7 +139,7 @@ static void test_acquire(void) /* Dummy event notifier ensures aio_poll() will block */ event_notifier_init(¬ifier, false); - aio_set_event_notifier(ctx, ¬ifier, dummy_notifier_read); + set_event_notifier(ctx, ¬ifier, dummy_notifier_read); g_assert(!aio_poll(ctx, false)); /* consume aio_notify() */ qemu_mutex_init(&data.start_lock); @@ -149,7 +157,7 @@ static void test_acquire(void) aio_context_release(ctx); qemu_thread_join(&thread); - aio_set_event_notifier(ctx, ¬ifier, NULL); + set_event_notifier(ctx, ¬ifier, NULL); event_notifier_cleanup(¬ifier); g_assert(data.thread_acquired); @@ -308,11 +316,11 @@ static void test_set_event_notifier(void) { EventNotifierTestData data = { .n = 0, .active = 0 }; event_notifier_init(&data.e, false); - aio_set_event_notifier(ctx, &data.e, event_ready_cb); + set_event_notifier(ctx, &data.e, event_ready_cb); g_assert(!aio_poll(ctx, false)); g_assert_cmpint(data.n, ==, 0); - aio_set_event_notifier(ctx, &data.e, NULL); + set_event_notifier(ctx, &data.e, NULL); g_assert(!aio_poll(ctx, false)); g_assert_cmpint(data.n, ==, 0); event_notifier_cleanup(&data.e); @@ -322,7 +330,7 @@ static void test_wait_event_notifier(void) { EventNotifierTestData data = { .n = 0, .active = 1 }; event_notifier_init(&data.e, false); - aio_set_event_notifier(ctx, &data.e, event_ready_cb); + set_event_notifier(ctx, &data.e, event_ready_cb); while (aio_poll(ctx, false)); g_assert_cmpint(data.n, ==, 0); g_assert_cmpint(data.active, ==, 1); @@ -336,7 +344,7 @@ static void test_wait_event_notifier(void) g_assert_cmpint(data.n, ==, 1); g_assert_cmpint(data.active, ==, 0); - aio_set_event_notifier(ctx, &data.e, NULL); + set_event_notifier(ctx, &data.e, NULL); g_assert(!aio_poll(ctx, false)); g_assert_cmpint(data.n, ==, 1); @@ -347,7 +355,7 @@ static void test_flush_event_notifier(void) { EventNotifierTestData data = { .n = 0, .active = 10, .auto_set = true }; event_notifier_init(&data.e, false); - aio_set_event_notifier(ctx, &data.e, event_ready_cb); + set_event_notifier(ctx, &data.e, event_ready_cb); while (aio_poll(ctx, false)); g_assert_cmpint(data.n, ==, 0); g_assert_cmpint(data.active, ==, 10); @@ -363,18 +371,42 @@ static void test_flush_event_notifier(void) g_assert_cmpint(data.active, ==, 0); g_assert(!aio_poll(ctx, false)); - aio_set_event_notifier(ctx, &data.e, NULL); + set_event_notifier(ctx, &data.e, NULL); g_assert(!aio_poll(ctx, false)); event_notifier_cleanup(&data.e); } +static void test_aio_external_client(void) +{ + int i, j; + + for (i = 1; i < 3; i++) { + EventNotifierTestData data = { .n = 0, .active = 10, .auto_set = true }; + event_notifier_init(&data.e, false); + aio_set_event_notifier(ctx, &data.e, true, event_ready_cb); + event_notifier_set(&data.e); + for (j = 0; j < i; j++) { + aio_disable_external(ctx); + } + for (j = 0; j < i; j++) { + assert(!aio_poll(ctx, false)); + assert(event_notifier_test_and_clear(&data.e)); + event_notifier_set(&data.e); + aio_enable_external(ctx); + } + assert(aio_poll(ctx, false)); + set_event_notifier(ctx, &data.e, NULL); + event_notifier_cleanup(&data.e); + } +} + static void test_wait_event_notifier_noflush(void) { EventNotifierTestData data = { .n = 0 }; EventNotifierTestData dummy = { .n = 0, .active = 1 }; event_notifier_init(&data.e, false); - aio_set_event_notifier(ctx, &data.e, event_ready_cb); + set_event_notifier(ctx, &data.e, event_ready_cb); g_assert(!aio_poll(ctx, false)); g_assert_cmpint(data.n, ==, 0); @@ -387,7 +419,7 @@ static void test_wait_event_notifier_noflush(void) /* An active event notifier forces aio_poll to look at EventNotifiers. */ event_notifier_init(&dummy.e, false); - aio_set_event_notifier(ctx, &dummy.e, event_ready_cb); + set_event_notifier(ctx, &dummy.e, event_ready_cb); event_notifier_set(&data.e); g_assert(aio_poll(ctx, false)); @@ -407,10 +439,10 @@ static void test_wait_event_notifier_noflush(void) g_assert_cmpint(dummy.n, ==, 1); g_assert_cmpint(dummy.active, ==, 0); - aio_set_event_notifier(ctx, &dummy.e, NULL); + set_event_notifier(ctx, &dummy.e, NULL); event_notifier_cleanup(&dummy.e); - aio_set_event_notifier(ctx, &data.e, NULL); + set_event_notifier(ctx, &data.e, NULL); g_assert(!aio_poll(ctx, false)); g_assert_cmpint(data.n, ==, 2); @@ -428,7 +460,7 @@ static void test_timer_schedule(void) * an fd to wait on. Fixing this breaks other tests. So create a dummy one. */ event_notifier_init(&e, false); - aio_set_event_notifier(ctx, &e, dummy_io_handler_read); + set_event_notifier(ctx, &e, dummy_io_handler_read); aio_poll(ctx, false); aio_timer_init(ctx, &data.timer, data.clock_type, @@ -467,7 +499,7 @@ static void test_timer_schedule(void) g_assert(!aio_poll(ctx, false)); g_assert_cmpint(data.n, ==, 2); - aio_set_event_notifier(ctx, &e, NULL); + set_event_notifier(ctx, &e, NULL); event_notifier_cleanup(&e); timer_del(&data.timer); @@ -638,11 +670,11 @@ static void test_source_set_event_notifier(void) { EventNotifierTestData data = { .n = 0, .active = 0 }; event_notifier_init(&data.e, false); - aio_set_event_notifier(ctx, &data.e, event_ready_cb); + set_event_notifier(ctx, &data.e, event_ready_cb); while (g_main_context_iteration(NULL, false)); g_assert_cmpint(data.n, ==, 0); - aio_set_event_notifier(ctx, &data.e, NULL); + set_event_notifier(ctx, &data.e, NULL); while (g_main_context_iteration(NULL, false)); g_assert_cmpint(data.n, ==, 0); event_notifier_cleanup(&data.e); @@ -652,7 +684,7 @@ static void test_source_wait_event_notifier(void) { EventNotifierTestData data = { .n = 0, .active = 1 }; event_notifier_init(&data.e, false); - aio_set_event_notifier(ctx, &data.e, event_ready_cb); + set_event_notifier(ctx, &data.e, event_ready_cb); while (g_main_context_iteration(NULL, false)); g_assert_cmpint(data.n, ==, 0); g_assert_cmpint(data.active, ==, 1); @@ -666,7 +698,7 @@ static void test_source_wait_event_notifier(void) g_assert_cmpint(data.n, ==, 1); g_assert_cmpint(data.active, ==, 0); - aio_set_event_notifier(ctx, &data.e, NULL); + set_event_notifier(ctx, &data.e, NULL); while (g_main_context_iteration(NULL, false)); g_assert_cmpint(data.n, ==, 1); @@ -677,7 +709,7 @@ static void test_source_flush_event_notifier(void) { EventNotifierTestData data = { .n = 0, .active = 10, .auto_set = true }; event_notifier_init(&data.e, false); - aio_set_event_notifier(ctx, &data.e, event_ready_cb); + set_event_notifier(ctx, &data.e, event_ready_cb); while (g_main_context_iteration(NULL, false)); g_assert_cmpint(data.n, ==, 0); g_assert_cmpint(data.active, ==, 10); @@ -693,7 +725,7 @@ static void test_source_flush_event_notifier(void) g_assert_cmpint(data.active, ==, 0); g_assert(!g_main_context_iteration(NULL, false)); - aio_set_event_notifier(ctx, &data.e, NULL); + set_event_notifier(ctx, &data.e, NULL); while (g_main_context_iteration(NULL, false)); event_notifier_cleanup(&data.e); } @@ -704,7 +736,7 @@ static void test_source_wait_event_notifier_noflush(void) EventNotifierTestData dummy = { .n = 0, .active = 1 }; event_notifier_init(&data.e, false); - aio_set_event_notifier(ctx, &data.e, event_ready_cb); + set_event_notifier(ctx, &data.e, event_ready_cb); while (g_main_context_iteration(NULL, false)); g_assert_cmpint(data.n, ==, 0); @@ -717,7 +749,7 @@ static void test_source_wait_event_notifier_noflush(void) /* An active event notifier forces aio_poll to look at EventNotifiers. */ event_notifier_init(&dummy.e, false); - aio_set_event_notifier(ctx, &dummy.e, event_ready_cb); + set_event_notifier(ctx, &dummy.e, event_ready_cb); event_notifier_set(&data.e); g_assert(g_main_context_iteration(NULL, false)); @@ -737,10 +769,10 @@ static void test_source_wait_event_notifier_noflush(void) g_assert_cmpint(dummy.n, ==, 1); g_assert_cmpint(dummy.active, ==, 0); - aio_set_event_notifier(ctx, &dummy.e, NULL); + set_event_notifier(ctx, &dummy.e, NULL); event_notifier_cleanup(&dummy.e); - aio_set_event_notifier(ctx, &data.e, NULL); + set_event_notifier(ctx, &data.e, NULL); while (g_main_context_iteration(NULL, false)); g_assert_cmpint(data.n, ==, 2); @@ -759,7 +791,7 @@ static void test_source_timer_schedule(void) * an fd to wait on. Fixing this breaks other tests. So create a dummy one. */ event_notifier_init(&e, false); - aio_set_event_notifier(ctx, &e, dummy_io_handler_read); + set_event_notifier(ctx, &e, dummy_io_handler_read); do {} while (g_main_context_iteration(NULL, false)); aio_timer_init(ctx, &data.timer, data.clock_type, @@ -784,7 +816,7 @@ static void test_source_timer_schedule(void) g_assert_cmpint(data.n, ==, 2); g_assert(qemu_clock_get_ns(data.clock_type) > expiry); - aio_set_event_notifier(ctx, &e, NULL); + set_event_notifier(ctx, &e, NULL); event_notifier_cleanup(&e); timer_del(&data.timer); @@ -802,9 +834,7 @@ int main(int argc, char **argv) ctx = aio_context_new(&local_error); if (!ctx) { - error_report("Failed to create AIO Context: '%s'", - error_get_pretty(local_error)); - error_free(local_error); + error_reportf_err(local_error, "Failed to create AIO Context: "); exit(1); } src = aio_get_g_source(ctx); @@ -826,6 +856,7 @@ int main(int argc, char **argv) g_test_add_func("/aio/event/wait", test_wait_event_notifier); g_test_add_func("/aio/event/wait/no-flush-cb", test_wait_event_notifier_noflush); g_test_add_func("/aio/event/flush", test_flush_event_notifier); + g_test_add_func("/aio/external-client", test_aio_external_client); g_test_add_func("/aio/timer/schedule", test_timer_schedule); g_test_add_func("/aio-gsource/flush", test_source_flush); diff --git a/qemu/tests/test-base64.c b/qemu/tests/test-base64.c new file mode 100644 index 000000000..922e839dd --- /dev/null +++ b/qemu/tests/test-base64.c @@ -0,0 +1,110 @@ +/* + * QEMU base64 helper test + * + * Copyright (c) 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "qemu/osdep.h" +#include <glib.h> + +#include "qapi/error.h" +#include "qemu/base64.h" + +static void test_base64_good(void) +{ + const char input[] = + "QmVjYXVzZSB3ZSBmb2N1c2VkIG9uIHRoZSBzbmFrZSwgd2UgbW\n" + "lzc2VkIHRoZSBzY29ycGlvbi4="; + const char expect[] = "Because we focused on the snake, " + "we missed the scorpion."; + + size_t len; + uint8_t *actual = qbase64_decode(input, + -1, + &len, + &error_abort); + + g_assert(actual != NULL); + g_assert_cmpint(len, ==, strlen(expect)); + g_assert_cmpstr((char *)actual, ==, expect); + g_free(actual); +} + + +static void test_base64_bad(const char *input, + size_t input_len) +{ + size_t len; + Error *err = NULL; + uint8_t *actual = qbase64_decode(input, + input_len, + &len, + &err); + + g_assert(err != NULL); + g_assert(actual == NULL); + g_assert_cmpint(len, ==, 0); + error_free(err); +} + + +static void test_base64_embedded_nul(void) +{ + /* We put a NUL character in the middle of the base64 + * text which is invalid data, given the expected length */ + const char input[] = + "QmVjYXVzZSB3ZSBmb2N1c2VkIG9uIHRoZSBzbmFrZSwgd2UgbW\0" + "lzc2VkIHRoZSBzY29ycGlvbi4="; + + test_base64_bad(input, G_N_ELEMENTS(input) - 1); +} + + +static void test_base64_not_nul_terminated(void) +{ + const char input[] = + "QmVjYXVzZSB3ZSBmb2N1c2VkIG9uIHRoZSBzbmFrZSwgd2UgbW\n" + "lzc2VkIHRoZSBzY29ycGlvbi4="; + + /* Using '-2' to make us drop the trailing NUL, thus + * creating an invalid base64 sequence for decoding */ + test_base64_bad(input, G_N_ELEMENTS(input) - 2); +} + + +static void test_base64_invalid_chars(void) +{ + /* We put a single quote character in the middle + * of the base64 text which is invalid data */ + const char input[] = + "QmVjYXVzZSB3ZSBmb2N1c2VkIG9uIHRoZSBzbmFrZSwgd2UgbW'" + "lzc2VkIHRoZSBzY29ycGlvbi4="; + + test_base64_bad(input, strlen(input)); +} + + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + g_test_add_func("/util/base64/good", test_base64_good); + g_test_add_func("/util/base64/embedded-nul", test_base64_embedded_nul); + g_test_add_func("/util/base64/not-nul-terminated", + test_base64_not_nul_terminated); + g_test_add_func("/util/base64/invalid-chars", test_base64_invalid_chars); + return g_test_run(); +} diff --git a/qemu/tests/test-bitops.c b/qemu/tests/test-bitops.c index 47b5d3ed9..505095060 100644 --- a/qemu/tests/test-bitops.c +++ b/qemu/tests/test-bitops.c @@ -6,9 +6,8 @@ * */ -#include <glib.h> -#include <stdint.h> #include "qemu/osdep.h" +#include <glib.h> #include "qemu/bitops.h" typedef struct { diff --git a/qemu/tests/test-blockjob-txn.c b/qemu/tests/test-blockjob-txn.c new file mode 100644 index 000000000..55fad9507 --- /dev/null +++ b/qemu/tests/test-blockjob-txn.c @@ -0,0 +1,251 @@ +/* + * Blockjob transactions tests + * + * Copyright Red Hat, Inc. 2015 + * + * Authors: + * Stefan Hajnoczi <stefanha@redhat.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2 or later. + * See the COPYING.LIB file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include <glib.h> +#include "qapi/error.h" +#include "qemu/main-loop.h" +#include "block/blockjob.h" + +typedef struct { + BlockJob common; + unsigned int iterations; + bool use_timer; + int rc; + int *result; +} TestBlockJob; + +static const BlockJobDriver test_block_job_driver = { + .instance_size = sizeof(TestBlockJob), +}; + +static void test_block_job_complete(BlockJob *job, void *opaque) +{ + BlockDriverState *bs = job->bs; + int rc = (intptr_t)opaque; + + if (block_job_is_cancelled(job)) { + rc = -ECANCELED; + } + + block_job_completed(job, rc); + bdrv_unref(bs); +} + +static void coroutine_fn test_block_job_run(void *opaque) +{ + TestBlockJob *s = opaque; + BlockJob *job = &s->common; + + while (s->iterations--) { + if (s->use_timer) { + block_job_sleep_ns(job, QEMU_CLOCK_REALTIME, 0); + } else { + block_job_yield(job); + } + + if (block_job_is_cancelled(job)) { + break; + } + } + + block_job_defer_to_main_loop(job, test_block_job_complete, + (void *)(intptr_t)s->rc); +} + +typedef struct { + TestBlockJob *job; + int *result; +} TestBlockJobCBData; + +static void test_block_job_cb(void *opaque, int ret) +{ + TestBlockJobCBData *data = opaque; + if (!ret && block_job_is_cancelled(&data->job->common)) { + ret = -ECANCELED; + } + *data->result = ret; + g_free(data); +} + +/* Create a block job that completes with a given return code after a given + * number of event loop iterations. The return code is stored in the given + * result pointer. + * + * The event loop iterations can either be handled automatically with a 0 delay + * timer, or they can be stepped manually by entering the coroutine. + */ +static BlockJob *test_block_job_start(unsigned int iterations, + bool use_timer, + int rc, int *result) +{ + BlockDriverState *bs; + TestBlockJob *s; + TestBlockJobCBData *data; + + data = g_new0(TestBlockJobCBData, 1); + bs = bdrv_new(); + s = block_job_create(&test_block_job_driver, bs, 0, test_block_job_cb, + data, &error_abort); + s->iterations = iterations; + s->use_timer = use_timer; + s->rc = rc; + s->result = result; + s->common.co = qemu_coroutine_create(test_block_job_run); + data->job = s; + data->result = result; + qemu_coroutine_enter(s->common.co, s); + return &s->common; +} + +static void test_single_job(int expected) +{ + BlockJob *job; + BlockJobTxn *txn; + int result = -EINPROGRESS; + + txn = block_job_txn_new(); + job = test_block_job_start(1, true, expected, &result); + block_job_txn_add_job(txn, job); + + if (expected == -ECANCELED) { + block_job_cancel(job); + } + + while (result == -EINPROGRESS) { + aio_poll(qemu_get_aio_context(), true); + } + g_assert_cmpint(result, ==, expected); + + block_job_txn_unref(txn); +} + +static void test_single_job_success(void) +{ + test_single_job(0); +} + +static void test_single_job_failure(void) +{ + test_single_job(-EIO); +} + +static void test_single_job_cancel(void) +{ + test_single_job(-ECANCELED); +} + +static void test_pair_jobs(int expected1, int expected2) +{ + BlockJob *job1; + BlockJob *job2; + BlockJobTxn *txn; + int result1 = -EINPROGRESS; + int result2 = -EINPROGRESS; + + txn = block_job_txn_new(); + job1 = test_block_job_start(1, true, expected1, &result1); + block_job_txn_add_job(txn, job1); + job2 = test_block_job_start(2, true, expected2, &result2); + block_job_txn_add_job(txn, job2); + + if (expected1 == -ECANCELED) { + block_job_cancel(job1); + } + if (expected2 == -ECANCELED) { + block_job_cancel(job2); + } + + while (result1 == -EINPROGRESS || result2 == -EINPROGRESS) { + aio_poll(qemu_get_aio_context(), true); + } + + /* Failure or cancellation of one job cancels the other job */ + if (expected1 != 0) { + expected2 = -ECANCELED; + } else if (expected2 != 0) { + expected1 = -ECANCELED; + } + + g_assert_cmpint(result1, ==, expected1); + g_assert_cmpint(result2, ==, expected2); + + block_job_txn_unref(txn); +} + +static void test_pair_jobs_success(void) +{ + test_pair_jobs(0, 0); +} + +static void test_pair_jobs_failure(void) +{ + /* Test both orderings. The two jobs run for a different number of + * iterations so the code path is different depending on which job fails + * first. + */ + test_pair_jobs(-EIO, 0); + test_pair_jobs(0, -EIO); +} + +static void test_pair_jobs_cancel(void) +{ + test_pair_jobs(-ECANCELED, 0); + test_pair_jobs(0, -ECANCELED); +} + +static void test_pair_jobs_fail_cancel_race(void) +{ + BlockJob *job1; + BlockJob *job2; + BlockJobTxn *txn; + int result1 = -EINPROGRESS; + int result2 = -EINPROGRESS; + + txn = block_job_txn_new(); + job1 = test_block_job_start(1, true, -ECANCELED, &result1); + block_job_txn_add_job(txn, job1); + job2 = test_block_job_start(2, false, 0, &result2); + block_job_txn_add_job(txn, job2); + + block_job_cancel(job1); + + /* Now make job2 finish before the main loop kicks jobs. This simulates + * the race between a pending kick and another job completing. + */ + block_job_enter(job2); + block_job_enter(job2); + + while (result1 == -EINPROGRESS || result2 == -EINPROGRESS) { + aio_poll(qemu_get_aio_context(), true); + } + + g_assert_cmpint(result1, ==, -ECANCELED); + g_assert_cmpint(result2, ==, -ECANCELED); + + block_job_txn_unref(txn); +} + +int main(int argc, char **argv) +{ + qemu_init_main_loop(&error_abort); + + g_test_init(&argc, &argv, NULL); + g_test_add_func("/single/success", test_single_job_success); + g_test_add_func("/single/failure", test_single_job_failure); + g_test_add_func("/single/cancel", test_single_job_cancel); + g_test_add_func("/pair/success", test_pair_jobs_success); + g_test_add_func("/pair/failure", test_pair_jobs_failure); + g_test_add_func("/pair/cancel", test_pair_jobs_cancel); + g_test_add_func("/pair/fail-cancel-race", test_pair_jobs_fail_cancel_race); + return g_test_run(); +} diff --git a/qemu/tests/test-coroutine.c b/qemu/tests/test-coroutine.c index b552d9f5e..dd4ced946 100644 --- a/qemu/tests/test-coroutine.c +++ b/qemu/tests/test-coroutine.c @@ -11,9 +11,10 @@ * */ +#include "qemu/osdep.h" #include <glib.h> -#include "block/coroutine.h" -#include "block/coroutine_int.h" +#include "qemu/coroutine.h" +#include "qemu/coroutine_int.h" /* * Check that qemu_in_coroutine() works diff --git a/qemu/tests/test-crypto-afsplit.c b/qemu/tests/test-crypto-afsplit.c new file mode 100644 index 000000000..f9f2fcd41 --- /dev/null +++ b/qemu/tests/test-crypto-afsplit.c @@ -0,0 +1,194 @@ +/* + * QEMU Crypto anti-forensic splitter + * + * Copyright (c) 2015-2016 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "crypto/init.h" +#include "crypto/afsplit.h" + +typedef struct QCryptoAFSplitTestData QCryptoAFSplitTestData; +struct QCryptoAFSplitTestData { + const char *path; + QCryptoHashAlgorithm hash; + uint32_t stripes; + size_t blocklen; + const uint8_t *key; + const uint8_t *splitkey; +}; + +static QCryptoAFSplitTestData test_data[] = { + { + .path = "/crypto/afsplit/sha256/5", + .hash = QCRYPTO_HASH_ALG_SHA256, + .stripes = 5, + .blocklen = 32, + .key = (const uint8_t *) + "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" + "\xa8\xa9\xaa\xab\xac\xad\xae\xaf", + .splitkey = (const uint8_t *) + "\xfd\xd2\x73\xb1\x7d\x99\x93\x34" + "\x70\xde\xfa\x07\xc5\xac\x58\xd2" + "\x30\x67\x2f\x1a\x35\x43\x60\x7d" + "\x77\x02\xdb\x62\x3c\xcb\x2c\x33" + "\x48\x08\xb6\xf1\x7c\xa3\x20\xa0" + "\xad\x2d\x4c\xf3\xcd\x18\x6f\x53" + "\xf9\xe8\xe7\x59\x27\x3c\xa9\x54" + "\x61\x87\xb3\xaf\xf6\xf7\x7e\x64" + "\x86\xaa\x89\x7f\x1f\x9f\xdb\x86" + "\xf4\xa2\x16\xff\xa3\x4f\x8c\xa1" + "\x59\xc4\x23\x34\x28\xc4\x77\x71" + "\x83\xd4\xcd\x8e\x89\x1b\xc7\xc5" + "\xae\x4d\xa9\xcd\xc9\x72\x85\x70" + "\x13\x68\x52\x83\xfc\xb8\x11\x72" + "\xba\x3d\xc6\x4a\x28\xfa\xe2\x86" + "\x7b\x27\xab\x58\xe1\xa4\xca\xf6" + "\x9e\xbc\xfe\x0c\x92\x79\xb3\xec" + "\x1c\x5f\x79\x3b\x0d\x1e\xaa\x1a" + "\x77\x0f\x70\x19\x4b\xc8\x80\xee" + "\x27\x7c\x6e\x4a\x91\x96\x5c\xf4" + }, + { + .path = "/crypto/afsplit/sha256/5000", + .hash = QCRYPTO_HASH_ALG_SHA256, + .stripes = 5000, + .blocklen = 16, + .key = (const uint8_t *) + "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + }, + { + .path = "/crypto/afsplit/sha1/1000", + .hash = QCRYPTO_HASH_ALG_SHA1, + .stripes = 1000, + .blocklen = 32, + .key = (const uint8_t *) + "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" + "\xa8\xa9\xaa\xab\xac\xad\xae\xaf", + }, + { + .path = "/crypto/afsplit/sha256/big", + .hash = QCRYPTO_HASH_ALG_SHA256, + .stripes = 1000, + .blocklen = 64, + .key = (const uint8_t *) + "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + }, +}; + + +static inline char hex(int i) +{ + if (i < 10) { + return '0' + i; + } + return 'a' + (i - 10); +} + +static char *hex_string(const uint8_t *bytes, + size_t len) +{ + char *hexstr = g_new0(char, len * 2 + 1); + size_t i; + + for (i = 0; i < len; i++) { + hexstr[i * 2] = hex((bytes[i] >> 4) & 0xf); + hexstr[i * 2 + 1] = hex(bytes[i] & 0xf); + } + hexstr[len * 2] = '\0'; + + return hexstr; +} + +static void test_afsplit(const void *opaque) +{ + const QCryptoAFSplitTestData *data = opaque; + size_t splitlen = data->blocklen * data->stripes; + uint8_t *splitkey = g_new0(uint8_t, splitlen); + uint8_t *key = g_new0(uint8_t, data->blocklen); + gchar *expect, *actual; + + /* First time we round-trip the key */ + qcrypto_afsplit_encode(data->hash, + data->blocklen, data->stripes, + data->key, splitkey, + &error_abort); + + qcrypto_afsplit_decode(data->hash, + data->blocklen, data->stripes, + splitkey, key, + &error_abort); + + expect = hex_string(data->key, data->blocklen); + actual = hex_string(key, data->blocklen); + + g_assert_cmpstr(actual, ==, expect); + + g_free(actual); + g_free(expect); + + /* Second time we merely try decoding a previous split */ + if (data->splitkey) { + memset(key, 0, data->blocklen); + + qcrypto_afsplit_decode(data->hash, + data->blocklen, data->stripes, + data->splitkey, key, + &error_abort); + + expect = hex_string(data->key, data->blocklen); + actual = hex_string(key, data->blocklen); + + g_assert_cmpstr(actual, ==, expect); + + g_free(actual); + g_free(expect); + } + + g_free(key); + g_free(splitkey); +} + +int main(int argc, char **argv) +{ + size_t i; + + g_test_init(&argc, &argv, NULL); + + g_assert(qcrypto_init(NULL) == 0); + + for (i = 0; i < G_N_ELEMENTS(test_data); i++) { + if (!qcrypto_hash_supports(test_data[i].hash)) { + continue; + } + g_test_add_data_func(test_data[i].path, &test_data[i], test_afsplit); + } + return g_test_run(); +} diff --git a/qemu/tests/test-crypto-block.c b/qemu/tests/test-crypto-block.c new file mode 100644 index 000000000..a38110d3f --- /dev/null +++ b/qemu/tests/test-crypto-block.c @@ -0,0 +1,363 @@ +/* + * QEMU Crypto block encryption + * + * Copyright (c) 2016 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "crypto/init.h" +#include "crypto/block.h" +#include "qemu/buffer.h" +#include "crypto/secret.h" +#ifndef _WIN32 +#include <sys/resource.h> +#endif + +#if defined(CONFIG_UUID) && (defined(_WIN32) || defined RUSAGE_THREAD) +#define TEST_LUKS +#else +#undef TEST_LUKS +#endif + +static QCryptoBlockCreateOptions qcow_create_opts = { + .format = Q_CRYPTO_BLOCK_FORMAT_QCOW, + .u.qcow = { + .has_key_secret = true, + .key_secret = (char *)"sec0", + }, +}; + +static QCryptoBlockOpenOptions qcow_open_opts = { + .format = Q_CRYPTO_BLOCK_FORMAT_QCOW, + .u.qcow = { + .has_key_secret = true, + .key_secret = (char *)"sec0", + }, +}; + + +#ifdef TEST_LUKS +static QCryptoBlockOpenOptions luks_open_opts = { + .format = Q_CRYPTO_BLOCK_FORMAT_LUKS, + .u.luks = { + .has_key_secret = true, + .key_secret = (char *)"sec0", + }, +}; + + +/* Creation with all default values */ +static QCryptoBlockCreateOptions luks_create_opts_default = { + .format = Q_CRYPTO_BLOCK_FORMAT_LUKS, + .u.luks = { + .has_key_secret = true, + .key_secret = (char *)"sec0", + }, +}; + + +/* ...and with explicit values */ +static QCryptoBlockCreateOptions luks_create_opts_aes256_cbc_plain64 = { + .format = Q_CRYPTO_BLOCK_FORMAT_LUKS, + .u.luks = { + .has_key_secret = true, + .key_secret = (char *)"sec0", + .has_cipher_alg = true, + .cipher_alg = QCRYPTO_CIPHER_ALG_AES_256, + .has_cipher_mode = true, + .cipher_mode = QCRYPTO_CIPHER_MODE_CBC, + .has_ivgen_alg = true, + .ivgen_alg = QCRYPTO_IVGEN_ALG_PLAIN64, + }, +}; + + +static QCryptoBlockCreateOptions luks_create_opts_aes256_cbc_essiv = { + .format = Q_CRYPTO_BLOCK_FORMAT_LUKS, + .u.luks = { + .has_key_secret = true, + .key_secret = (char *)"sec0", + .has_cipher_alg = true, + .cipher_alg = QCRYPTO_CIPHER_ALG_AES_256, + .has_cipher_mode = true, + .cipher_mode = QCRYPTO_CIPHER_MODE_CBC, + .has_ivgen_alg = true, + .ivgen_alg = QCRYPTO_IVGEN_ALG_ESSIV, + .has_ivgen_hash_alg = true, + .ivgen_hash_alg = QCRYPTO_HASH_ALG_SHA256, + .has_hash_alg = true, + .hash_alg = QCRYPTO_HASH_ALG_SHA1, + }, +}; +#endif /* TEST_LUKS */ + + +static struct QCryptoBlockTestData { + const char *path; + QCryptoBlockCreateOptions *create_opts; + QCryptoBlockOpenOptions *open_opts; + + bool expect_header; + + QCryptoCipherAlgorithm cipher_alg; + QCryptoCipherMode cipher_mode; + QCryptoHashAlgorithm hash_alg; + + QCryptoIVGenAlgorithm ivgen_alg; + QCryptoHashAlgorithm ivgen_hash; + + bool slow; +} test_data[] = { + { + .path = "/crypto/block/qcow", + .create_opts = &qcow_create_opts, + .open_opts = &qcow_open_opts, + + .expect_header = false, + + .cipher_alg = QCRYPTO_CIPHER_ALG_AES_128, + .cipher_mode = QCRYPTO_CIPHER_MODE_CBC, + + .ivgen_alg = QCRYPTO_IVGEN_ALG_PLAIN64, + }, +#ifdef TEST_LUKS + { + .path = "/crypto/block/luks/default", + .create_opts = &luks_create_opts_default, + .open_opts = &luks_open_opts, + + .expect_header = true, + + .cipher_alg = QCRYPTO_CIPHER_ALG_AES_256, + .cipher_mode = QCRYPTO_CIPHER_MODE_XTS, + .hash_alg = QCRYPTO_HASH_ALG_SHA256, + + .ivgen_alg = QCRYPTO_IVGEN_ALG_PLAIN64, + + .slow = true, + }, + { + .path = "/crypto/block/luks/aes-256-cbc-plain64", + .create_opts = &luks_create_opts_aes256_cbc_plain64, + .open_opts = &luks_open_opts, + + .expect_header = true, + + .cipher_alg = QCRYPTO_CIPHER_ALG_AES_256, + .cipher_mode = QCRYPTO_CIPHER_MODE_CBC, + .hash_alg = QCRYPTO_HASH_ALG_SHA256, + + .ivgen_alg = QCRYPTO_IVGEN_ALG_PLAIN64, + + .slow = true, + }, + { + .path = "/crypto/block/luks/aes-256-cbc-essiv", + .create_opts = &luks_create_opts_aes256_cbc_essiv, + .open_opts = &luks_open_opts, + + .expect_header = true, + + .cipher_alg = QCRYPTO_CIPHER_ALG_AES_256, + .cipher_mode = QCRYPTO_CIPHER_MODE_CBC, + .hash_alg = QCRYPTO_HASH_ALG_SHA1, + + .ivgen_alg = QCRYPTO_IVGEN_ALG_ESSIV, + .ivgen_hash = QCRYPTO_HASH_ALG_SHA256, + + .slow = true, + }, +#endif +}; + + +static ssize_t test_block_read_func(QCryptoBlock *block, + size_t offset, + uint8_t *buf, + size_t buflen, + Error **errp, + void *opaque) +{ + Buffer *header = opaque; + + g_assert_cmpint(offset + buflen, <=, header->capacity); + + memcpy(buf, header->buffer + offset, buflen); + + return buflen; +} + + +static ssize_t test_block_init_func(QCryptoBlock *block, + size_t headerlen, + Error **errp, + void *opaque) +{ + Buffer *header = opaque; + + g_assert_cmpint(header->capacity, ==, 0); + + buffer_reserve(header, headerlen); + + return headerlen; +} + + +static ssize_t test_block_write_func(QCryptoBlock *block, + size_t offset, + const uint8_t *buf, + size_t buflen, + Error **errp, + void *opaque) +{ + Buffer *header = opaque; + + g_assert_cmpint(buflen + offset, <=, header->capacity); + + memcpy(header->buffer + offset, buf, buflen); + header->offset = offset + buflen; + + return buflen; +} + + +static Object *test_block_secret(void) +{ + return object_new_with_props( + TYPE_QCRYPTO_SECRET, + object_get_objects_root(), + "sec0", + &error_abort, + "data", "123456", + NULL); +} + +static void test_block_assert_setup(const struct QCryptoBlockTestData *data, + QCryptoBlock *blk) +{ + QCryptoIVGen *ivgen; + QCryptoCipher *cipher; + + ivgen = qcrypto_block_get_ivgen(blk); + cipher = qcrypto_block_get_cipher(blk); + + g_assert(ivgen); + g_assert(cipher); + + g_assert_cmpint(data->cipher_alg, ==, cipher->alg); + g_assert_cmpint(data->cipher_mode, ==, cipher->mode); + g_assert_cmpint(data->hash_alg, ==, + qcrypto_block_get_kdf_hash(blk)); + + g_assert_cmpint(data->ivgen_alg, ==, + qcrypto_ivgen_get_algorithm(ivgen)); + g_assert_cmpint(data->ivgen_hash, ==, + qcrypto_ivgen_get_hash(ivgen)); +} + + +static void test_block(gconstpointer opaque) +{ + const struct QCryptoBlockTestData *data = opaque; + QCryptoBlock *blk; + Buffer header; + Object *sec = test_block_secret(); + + memset(&header, 0, sizeof(header)); + buffer_init(&header, "header"); + + blk = qcrypto_block_create(data->create_opts, + test_block_init_func, + test_block_write_func, + &header, + &error_abort); + g_assert(blk); + + if (data->expect_header) { + g_assert_cmpint(header.capacity, >, 0); + } else { + g_assert_cmpint(header.capacity, ==, 0); + } + + test_block_assert_setup(data, blk); + + qcrypto_block_free(blk); + object_unparent(sec); + + /* Ensure we can't open without the secret */ + blk = qcrypto_block_open(data->open_opts, + test_block_read_func, + &header, + 0, + NULL); + g_assert(blk == NULL); + + /* Ensure we can't open without the secret, unless NO_IO */ + blk = qcrypto_block_open(data->open_opts, + test_block_read_func, + &header, + QCRYPTO_BLOCK_OPEN_NO_IO, + &error_abort); + + g_assert(qcrypto_block_get_cipher(blk) == NULL); + g_assert(qcrypto_block_get_ivgen(blk) == NULL); + + qcrypto_block_free(blk); + + + /* Now open for real with secret */ + sec = test_block_secret(); + blk = qcrypto_block_open(data->open_opts, + test_block_read_func, + &header, + 0, + &error_abort); + g_assert(blk); + + test_block_assert_setup(data, blk); + + qcrypto_block_free(blk); + + object_unparent(sec); + + buffer_free(&header); +} + + +int main(int argc, char **argv) +{ + gsize i; + + module_call_init(MODULE_INIT_QOM); + g_test_init(&argc, &argv, NULL); + + g_assert(qcrypto_init(NULL) == 0); + + for (i = 0; i < G_N_ELEMENTS(test_data); i++) { + if (test_data[i].open_opts->format == Q_CRYPTO_BLOCK_FORMAT_LUKS && + !qcrypto_hash_supports(test_data[i].hash_alg)) { + continue; + } + if (!test_data[i].slow || + g_test_slow()) { + g_test_add_data_func(test_data[i].path, &test_data[i], test_block); + } + } + + return g_test_run(); +} diff --git a/qemu/tests/test-crypto-cipher.c b/qemu/tests/test-crypto-cipher.c index 9d38d2640..66d1c63fd 100644 --- a/qemu/tests/test-crypto-cipher.c +++ b/qemu/tests/test-crypto-cipher.c @@ -18,10 +18,12 @@ * */ +#include "qemu/osdep.h" #include <glib.h> #include "crypto/init.h" #include "crypto/cipher.h" +#include "qapi/error.h" typedef struct QCryptoCipherTestData QCryptoCipherTestData; struct QCryptoCipherTestData { @@ -164,6 +166,211 @@ static QCryptoCipherTestData test_data[] = { "ffd29f1bb5596ad94ea2d8e6196b7f09" "30d8ed0bf2773af36dd82a6280c20926", }, + { + /* RFC 2144, Appendix B.1 */ + .path = "/crypto/cipher/cast5-128", + .alg = QCRYPTO_CIPHER_ALG_CAST5_128, + .mode = QCRYPTO_CIPHER_MODE_ECB, + .key = "0123456712345678234567893456789A", + .plaintext = "0123456789abcdef", + .ciphertext = "238b4fe5847e44b2", + }, + { + /* libgcrypt serpent.c */ + .path = "/crypto/cipher/serpent-128", + .alg = QCRYPTO_CIPHER_ALG_SERPENT_128, + .mode = QCRYPTO_CIPHER_MODE_ECB, + .key = "00000000000000000000000000000000", + .plaintext = "d29d576fcea3a3a7ed9099f29273d78e", + .ciphertext = "b2288b968ae8b08648d1ce9606fd992d", + }, + { + /* libgcrypt serpent.c */ + .path = "/crypto/cipher/serpent-192", + .alg = QCRYPTO_CIPHER_ALG_SERPENT_192, + .mode = QCRYPTO_CIPHER_MODE_ECB, + .key = "00000000000000000000000000000000" + "0000000000000000", + .plaintext = "d29d576fceaba3a7ed9899f2927bd78e", + .ciphertext = "130e353e1037c22405e8faefb2c3c3e9", + }, + { + /* libgcrypt serpent.c */ + .path = "/crypto/cipher/serpent-256a", + .alg = QCRYPTO_CIPHER_ALG_SERPENT_256, + .mode = QCRYPTO_CIPHER_MODE_ECB, + .key = "00000000000000000000000000000000" + "00000000000000000000000000000000", + .plaintext = "d095576fcea3e3a7ed98d9f29073d78e", + .ciphertext = "b90ee5862de69168f2bdd5125b45472b", + }, + { + /* libgcrypt serpent.c */ + .path = "/crypto/cipher/serpent-256b", + .alg = QCRYPTO_CIPHER_ALG_SERPENT_256, + .mode = QCRYPTO_CIPHER_MODE_ECB, + .key = "00000000000000000000000000000000" + "00000000000000000000000000000000", + .plaintext = "00000000010000000200000003000000", + .ciphertext = "2061a42782bd52ec691ec383b03ba77c", + }, + { + /* Twofish paper "Known Answer Test" */ + .path = "/crypto/cipher/twofish-128", + .alg = QCRYPTO_CIPHER_ALG_TWOFISH_128, + .mode = QCRYPTO_CIPHER_MODE_ECB, + .key = "d491db16e7b1c39e86cb086b789f5419", + .plaintext = "019f9809de1711858faac3a3ba20fbc3", + .ciphertext = "6363977de839486297e661c6c9d668eb", + }, + { + /* Twofish paper "Known Answer Test", I=3 */ + .path = "/crypto/cipher/twofish-192", + .alg = QCRYPTO_CIPHER_ALG_TWOFISH_192, + .mode = QCRYPTO_CIPHER_MODE_ECB, + .key = "88b2b2706b105e36b446bb6d731a1e88" + "efa71f788965bd44", + .plaintext = "39da69d6ba4997d585b6dc073ca341b2", + .ciphertext = "182b02d81497ea45f9daacdc29193a65", + }, + { + /* Twofish paper "Known Answer Test", I=4 */ + .path = "/crypto/cipher/twofish-256", + .alg = QCRYPTO_CIPHER_ALG_TWOFISH_256, + .mode = QCRYPTO_CIPHER_MODE_ECB, + .key = "d43bb7556ea32e46f2a282b7d45b4e0d" + "57ff739d4dc92c1bd7fc01700cc8216f", + .plaintext = "90afe91bb288544f2c32dc239b2635e6", + .ciphertext = "6cb4561c40bf0a9705931cb6d408e7fa", + }, + { + /* #1 32 byte key, 32 byte PTX */ + .path = "/crypto/cipher/aes-xts-128-1", + .alg = QCRYPTO_CIPHER_ALG_AES_128, + .mode = QCRYPTO_CIPHER_MODE_XTS, + .key = + "00000000000000000000000000000000" + "00000000000000000000000000000000", + .iv = + "00000000000000000000000000000000", + .plaintext = + "00000000000000000000000000000000" + "00000000000000000000000000000000", + .ciphertext = + "917cf69ebd68b2ec9b9fe9a3eadda692" + "cd43d2f59598ed858c02c2652fbf922e", + }, + { + /* #2, 32 byte key, 32 byte PTX */ + .path = "/crypto/cipher/aes-xts-128-2", + .alg = QCRYPTO_CIPHER_ALG_AES_128, + .mode = QCRYPTO_CIPHER_MODE_XTS, + .key = + "11111111111111111111111111111111" + "22222222222222222222222222222222", + .iv = + "33333333330000000000000000000000", + .plaintext = + "44444444444444444444444444444444" + "44444444444444444444444444444444", + .ciphertext = + "c454185e6a16936e39334038acef838b" + "fb186fff7480adc4289382ecd6d394f0", + }, + { + /* #5 from xts.7, 32 byte key, 32 byte PTX */ + .path = "/crypto/cipher/aes-xts-128-3", + .alg = QCRYPTO_CIPHER_ALG_AES_128, + .mode = QCRYPTO_CIPHER_MODE_XTS, + .key = + "fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0" + "bfbebdbcbbbab9b8b7b6b5b4b3b2b1b0", + .iv = + "9a785634120000000000000000000000", + .plaintext = + "44444444444444444444444444444444" + "44444444444444444444444444444444", + .ciphertext = + "b01f86f8edc1863706fa8a4253e34f28" + "af319de38334870f4dd1f94cbe9832f1", + }, + { + /* #4, 32 byte key, 512 byte PTX */ + .path = "/crypto/cipher/aes-xts-128-4", + .alg = QCRYPTO_CIPHER_ALG_AES_128, + .mode = QCRYPTO_CIPHER_MODE_XTS, + .key = + "27182818284590452353602874713526" + "31415926535897932384626433832795", + .iv = + "00000000000000000000000000000000", + .plaintext = + "000102030405060708090a0b0c0d0e0f" + "101112131415161718191a1b1c1d1e1f" + "202122232425262728292a2b2c2d2e2f" + "303132333435363738393a3b3c3d3e3f" + "404142434445464748494a4b4c4d4e4f" + "505152535455565758595a5b5c5d5e5f" + "606162636465666768696a6b6c6d6e6f" + "707172737475767778797a7b7c7d7e7f" + "808182838485868788898a8b8c8d8e8f" + "909192939495969798999a9b9c9d9e9f" + "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf" + "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" + "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" + "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" + "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff" + "000102030405060708090a0b0c0d0e0f" + "101112131415161718191a1b1c1d1e1f" + "202122232425262728292a2b2c2d2e2f" + "303132333435363738393a3b3c3d3e3f" + "404142434445464748494a4b4c4d4e4f" + "505152535455565758595a5b5c5d5e5f" + "606162636465666768696a6b6c6d6e6f" + "707172737475767778797a7b7c7d7e7f" + "808182838485868788898a8b8c8d8e8f" + "909192939495969798999a9b9c9d9e9f" + "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf" + "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" + "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" + "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" + "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + .ciphertext = + "27a7479befa1d476489f308cd4cfa6e2" + "a96e4bbe3208ff25287dd3819616e89c" + "c78cf7f5e543445f8333d8fa7f560000" + "05279fa5d8b5e4ad40e736ddb4d35412" + "328063fd2aab53e5ea1e0a9f332500a5" + "df9487d07a5c92cc512c8866c7e860ce" + "93fdf166a24912b422976146ae20ce84" + "6bb7dc9ba94a767aaef20c0d61ad0265" + "5ea92dc4c4e41a8952c651d33174be51" + "a10c421110e6d81588ede82103a252d8" + "a750e8768defffed9122810aaeb99f91" + "72af82b604dc4b8e51bcb08235a6f434" + "1332e4ca60482a4ba1a03b3e65008fc5" + "da76b70bf1690db4eae29c5f1badd03c" + "5ccf2a55d705ddcd86d449511ceb7ec3" + "0bf12b1fa35b913f9f747a8afd1b130e" + "94bff94effd01a91735ca1726acd0b19" + "7c4e5b03393697e126826fb6bbde8ecc" + "1e08298516e2c9ed03ff3c1b7860f6de" + "76d4cecd94c8119855ef5297ca67e9f3" + "e7ff72b1e99785ca0a7e7720c5b36dc6" + "d72cac9574c8cbbc2f801e23e56fd344" + "b07f22154beba0f08ce8891e643ed995" + "c94d9a69c9f1b5f499027a78572aeebd" + "74d20cc39881c213ee770b1010e4bea7" + "18846977ae119f7a023ab58cca0ad752" + "afe656bb3c17256a9f6e9bf19fdd5a38" + "fc82bbe872c5539edb609ef4f79c203e" + "bb140f2e583cb2ad15b4aa5b655016a8" + "449277dbd477ef2c8d6c017db738b18d" + "eb4a427d1923ce3ff262735779a418f2" + "0a282df920147beabe421ee5319d0568", + }, }; @@ -229,6 +436,7 @@ static void test_cipher(const void *opaque) uint8_t *key, *iv, *ciphertext, *plaintext, *outtext; size_t nkey, niv, nciphertext, nplaintext; char *outtexthex; + size_t ivsize, keysize, blocksize; nkey = unhex_string(data->key, &key); niv = unhex_string(data->iv, &iv); @@ -245,6 +453,19 @@ static void test_cipher(const void *opaque) &error_abort); g_assert(cipher != NULL); + keysize = qcrypto_cipher_get_key_len(data->alg); + blocksize = qcrypto_cipher_get_block_len(data->alg); + ivsize = qcrypto_cipher_get_iv_len(data->alg, data->mode); + + if (data->mode == QCRYPTO_CIPHER_MODE_XTS) { + g_assert_cmpint(keysize * 2, ==, nkey); + } else { + g_assert_cmpint(keysize, ==, nkey); + } + g_assert_cmpint(ivsize, ==, niv); + if (niv) { + g_assert_cmpint(blocksize, ==, niv); + } if (iv) { g_assert(qcrypto_cipher_setiv(cipher, @@ -287,6 +508,79 @@ static void test_cipher(const void *opaque) qcrypto_cipher_free(cipher); } + +static void test_cipher_null_iv(void) +{ + QCryptoCipher *cipher; + uint8_t key[32] = { 0 }; + uint8_t plaintext[32] = { 0 }; + uint8_t ciphertext[32] = { 0 }; + + cipher = qcrypto_cipher_new( + QCRYPTO_CIPHER_ALG_AES_256, + QCRYPTO_CIPHER_MODE_CBC, + key, sizeof(key), + &error_abort); + g_assert(cipher != NULL); + + /* Don't call qcrypto_cipher_setiv */ + + qcrypto_cipher_encrypt(cipher, + plaintext, + ciphertext, + sizeof(plaintext), + &error_abort); + + qcrypto_cipher_free(cipher); +} + +static void test_cipher_short_plaintext(void) +{ + Error *err = NULL; + QCryptoCipher *cipher; + uint8_t key[32] = { 0 }; + uint8_t plaintext1[20] = { 0 }; + uint8_t ciphertext1[20] = { 0 }; + uint8_t plaintext2[40] = { 0 }; + uint8_t ciphertext2[40] = { 0 }; + int ret; + + cipher = qcrypto_cipher_new( + QCRYPTO_CIPHER_ALG_AES_256, + QCRYPTO_CIPHER_MODE_CBC, + key, sizeof(key), + &error_abort); + g_assert(cipher != NULL); + + /* Should report an error as plaintext is shorter + * than block size + */ + ret = qcrypto_cipher_encrypt(cipher, + plaintext1, + ciphertext1, + sizeof(plaintext1), + &err); + g_assert(ret == -1); + g_assert(err != NULL); + + error_free(err); + err = NULL; + + /* Should report an error as plaintext is larger than + * block size, but not a multiple of block size + */ + ret = qcrypto_cipher_encrypt(cipher, + plaintext2, + ciphertext2, + sizeof(plaintext2), + &err); + g_assert(ret == -1); + g_assert(err != NULL); + + error_free(err); + qcrypto_cipher_free(cipher); +} + int main(int argc, char **argv) { size_t i; @@ -296,7 +590,16 @@ int main(int argc, char **argv) g_assert(qcrypto_init(NULL) == 0); for (i = 0; i < G_N_ELEMENTS(test_data); i++) { - g_test_add_data_func(test_data[i].path, &test_data[i], test_cipher); + if (qcrypto_cipher_supports(test_data[i].alg)) { + g_test_add_data_func(test_data[i].path, &test_data[i], test_cipher); + } } + + g_test_add_func("/crypto/cipher/null-iv", + test_cipher_null_iv); + + g_test_add_func("/crypto/cipher/short-plaintext", + test_cipher_short_plaintext); + return g_test_run(); } diff --git a/qemu/tests/test-crypto-hash.c b/qemu/tests/test-crypto-hash.c index 911437e60..735d6d7e0 100644 --- a/qemu/tests/test-crypto-hash.c +++ b/qemu/tests/test-crypto-hash.c @@ -18,6 +18,7 @@ * */ +#include "qemu/osdep.h" #include <glib.h> #include "crypto/init.h" @@ -163,6 +164,11 @@ static void test_hash_digest(void) for (i = 0; i < G_N_ELEMENTS(expected_outputs) ; i++) { int ret; char *digest; + size_t digestsize; + + digestsize = qcrypto_hash_digest_len(i); + + g_assert_cmpint(digestsize * 2, ==, strlen(expected_outputs[i])); ret = qcrypto_hash_digest(i, INPUT_TEXT, diff --git a/qemu/tests/test-crypto-ivgen.c b/qemu/tests/test-crypto-ivgen.c new file mode 100644 index 000000000..a5ff5d3da --- /dev/null +++ b/qemu/tests/test-crypto-ivgen.c @@ -0,0 +1,174 @@ +/* + * QEMU Crypto IV generator algorithms + * + * Copyright (c) 2015-2016 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "crypto/ivgen.h" + + +struct QCryptoIVGenTestData { + const char *path; + uint64_t sector; + QCryptoIVGenAlgorithm ivalg; + QCryptoHashAlgorithm hashalg; + QCryptoCipherAlgorithm cipheralg; + const uint8_t *key; + size_t nkey; + const uint8_t *iv; + size_t niv; +} test_data[] = { + /* Small */ + { + "/crypto/ivgen/plain/1", + .sector = 0x1, + .ivalg = QCRYPTO_IVGEN_ALG_PLAIN, + .iv = (const uint8_t *)"\x01\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .niv = 16, + }, + /* Big ! */ + { + "/crypto/ivgen/plain/1f2e3d4c", + .sector = 0x1f2e3d4cULL, + .ivalg = QCRYPTO_IVGEN_ALG_PLAIN, + .iv = (const uint8_t *)"\x4c\x3d\x2e\x1f\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .niv = 16, + }, + /* Truncation */ + { + "/crypto/ivgen/plain/1f2e3d4c5b6a7988", + .sector = 0x1f2e3d4c5b6a7988ULL, + .ivalg = QCRYPTO_IVGEN_ALG_PLAIN, + .iv = (const uint8_t *)"\x88\x79\x6a\x5b\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .niv = 16, + }, + /* Small */ + { + "/crypto/ivgen/plain64/1", + .sector = 0x1, + .ivalg = QCRYPTO_IVGEN_ALG_PLAIN64, + .iv = (const uint8_t *)"\x01\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .niv = 16, + }, + /* Big ! */ + { + "/crypto/ivgen/plain64/1f2e3d4c", + .sector = 0x1f2e3d4cULL, + .ivalg = QCRYPTO_IVGEN_ALG_PLAIN64, + .iv = (const uint8_t *)"\x4c\x3d\x2e\x1f\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .niv = 16, + }, + /* No Truncation */ + { + "/crypto/ivgen/plain64/1f2e3d4c5b6a7988", + .sector = 0x1f2e3d4c5b6a7988ULL, + .ivalg = QCRYPTO_IVGEN_ALG_PLAIN64, + .iv = (const uint8_t *)"\x88\x79\x6a\x5b\x4c\x3d\x2e\x1f" + "\x00\x00\x00\x00\x00\x00\x00\x00", + .niv = 16, + }, + /* Small */ + { + "/crypto/ivgen/essiv/1", + .sector = 0x1, + .ivalg = QCRYPTO_IVGEN_ALG_ESSIV, + .cipheralg = QCRYPTO_CIPHER_ALG_AES_128, + .hashalg = QCRYPTO_HASH_ALG_SHA256, + .key = (const uint8_t *)"\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + .nkey = 16, + .iv = (const uint8_t *)"\xd4\x83\x71\xb2\xa1\x94\x53\x88" + "\x1c\x7a\x2d\06\x2d\x0b\x65\x46", + .niv = 16, + }, + /* Big ! */ + { + "/crypto/ivgen/essiv/1f2e3d4c", + .sector = 0x1f2e3d4cULL, + .ivalg = QCRYPTO_IVGEN_ALG_ESSIV, + .cipheralg = QCRYPTO_CIPHER_ALG_AES_128, + .hashalg = QCRYPTO_HASH_ALG_SHA256, + .key = (const uint8_t *)"\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + .nkey = 16, + .iv = (const uint8_t *)"\x5d\x36\x09\x5d\xc6\x9e\x5e\xe9" + "\xe3\x02\x8d\xd8\x7a\x3d\xe7\x8f", + .niv = 16, + }, + /* No Truncation */ + { + "/crypto/ivgen/essiv/1f2e3d4c5b6a7988", + .sector = 0x1f2e3d4c5b6a7988ULL, + .ivalg = QCRYPTO_IVGEN_ALG_ESSIV, + .cipheralg = QCRYPTO_CIPHER_ALG_AES_128, + .hashalg = QCRYPTO_HASH_ALG_SHA256, + .key = (const uint8_t *)"\x00\x01\x02\x03\x04\x05\x06\x07" + "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", + .nkey = 16, + .iv = (const uint8_t *)"\x58\xbb\x81\x94\x51\x83\x23\x23" + "\x7a\x08\x93\xa9\xdc\xd2\xd9\xab", + .niv = 16, + }, +}; + + +static void test_ivgen(const void *opaque) +{ + const struct QCryptoIVGenTestData *data = opaque; + uint8_t *iv = g_new0(uint8_t, data->niv); + QCryptoIVGen *ivgen = qcrypto_ivgen_new( + data->ivalg, + data->cipheralg, + data->hashalg, + data->key, + data->nkey, + &error_abort); + + qcrypto_ivgen_calculate(ivgen, + data->sector, + iv, + data->niv, + &error_abort); + + g_assert(memcmp(iv, data->iv, data->niv) == 0); + + qcrypto_ivgen_free(ivgen); + g_free(iv); +} + +int main(int argc, char **argv) +{ + size_t i; + g_test_init(&argc, &argv, NULL); + for (i = 0; i < G_N_ELEMENTS(test_data); i++) { + if (test_data[i].ivalg == QCRYPTO_IVGEN_ALG_ESSIV && + !qcrypto_hash_supports(test_data[i].hashalg)) { + continue; + } + g_test_add_data_func(test_data[i].path, + &(test_data[i]), + test_ivgen); + } + return g_test_run(); +} diff --git a/qemu/tests/test-crypto-pbkdf.c b/qemu/tests/test-crypto-pbkdf.c new file mode 100644 index 000000000..8ceceb182 --- /dev/null +++ b/qemu/tests/test-crypto-pbkdf.c @@ -0,0 +1,393 @@ +/* + * QEMU Crypto cipher algorithms + * + * Copyright (c) 2015-2016 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "crypto/init.h" +#ifndef _WIN32 +#include <sys/resource.h> +#endif + +#if ((defined(CONFIG_NETTLE) || defined(CONFIG_GCRYPT)) && \ + (defined(_WIN32) || defined(RUSAGE_THREAD))) +#include "crypto/pbkdf.h" + +typedef struct QCryptoPbkdfTestData QCryptoPbkdfTestData; +struct QCryptoPbkdfTestData { + const char *path; + QCryptoHashAlgorithm hash; + unsigned int iterations; + const char *key; + size_t nkey; + const char *salt; + size_t nsalt; + const char *out; + size_t nout; + bool slow; +}; + +/* This test data comes from cryptsetup package + * + * $SRC/lib/crypto_backend/pbkdf2_generic.c + * + * under LGPLv2.1+ license + */ +static QCryptoPbkdfTestData test_data[] = { + /* RFC 3962 test data */ + { + .path = "/crypto/pbkdf/rfc3962/sha1/iter1", + .hash = QCRYPTO_HASH_ALG_SHA1, + .iterations = 1, + .key = "password", + .nkey = 8, + .salt = "ATHENA.MIT.EDUraeburn", + .nsalt = 21, + .out = "\xcd\xed\xb5\x28\x1b\xb2\xf8\x01" + "\x56\x5a\x11\x22\xb2\x56\x35\x15" + "\x0a\xd1\xf7\xa0\x4b\xb9\xf3\xa3" + "\x33\xec\xc0\xe2\xe1\xf7\x08\x37", + .nout = 32 + }, + { + .path = "/crypto/pbkdf/rfc3962/sha1/iter2", + .hash = QCRYPTO_HASH_ALG_SHA1, + .iterations = 2, + .key = "password", + .nkey = 8, + .salt = "ATHENA.MIT.EDUraeburn", + .nsalt = 21, + .out = "\x01\xdb\xee\x7f\x4a\x9e\x24\x3e" + "\x98\x8b\x62\xc7\x3c\xda\x93\x5d" + "\xa0\x53\x78\xb9\x32\x44\xec\x8f" + "\x48\xa9\x9e\x61\xad\x79\x9d\x86", + .nout = 32 + }, + { + .path = "/crypto/pbkdf/rfc3962/sha1/iter1200a", + .hash = QCRYPTO_HASH_ALG_SHA1, + .iterations = 1200, + .key = "password", + .nkey = 8, + .salt = "ATHENA.MIT.EDUraeburn", + .nsalt = 21, + .out = "\x5c\x08\xeb\x61\xfd\xf7\x1e\x4e" + "\x4e\xc3\xcf\x6b\xa1\xf5\x51\x2b" + "\xa7\xe5\x2d\xdb\xc5\xe5\x14\x2f" + "\x70\x8a\x31\xe2\xe6\x2b\x1e\x13", + .nout = 32 + }, + { + .path = "/crypto/pbkdf/rfc3962/sha1/iter5", + .hash = QCRYPTO_HASH_ALG_SHA1, + .iterations = 5, + .key = "password", + .nkey = 8, + .salt = "\0224VxxV4\022", /* "\x1234567878563412 */ + .nsalt = 8, + .out = "\xd1\xda\xa7\x86\x15\xf2\x87\xe6" + "\xa1\xc8\xb1\x20\xd7\x06\x2a\x49" + "\x3f\x98\xd2\x03\xe6\xbe\x49\xa6" + "\xad\xf4\xfa\x57\x4b\x6e\x64\xee", + .nout = 32 + }, + { + .path = "/crypto/pbkdf/rfc3962/sha1/iter1200b", + .hash = QCRYPTO_HASH_ALG_SHA1, + .iterations = 1200, + .key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + .nkey = 64, + .salt = "pass phrase equals block size", + .nsalt = 29, + .out = "\x13\x9c\x30\xc0\x96\x6b\xc3\x2b" + "\xa5\x5f\xdb\xf2\x12\x53\x0a\xc9" + "\xc5\xec\x59\xf1\xa4\x52\xf5\xcc" + "\x9a\xd9\x40\xfe\xa0\x59\x8e\xd1", + .nout = 32 + }, + { + .path = "/crypto/pbkdf/rfc3962/sha1/iter1200c", + .hash = QCRYPTO_HASH_ALG_SHA1, + .iterations = 1200, + .key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + .nkey = 65, + .salt = "pass phrase exceeds block size", + .nsalt = 30, + .out = "\x9c\xca\xd6\xd4\x68\x77\x0c\xd5" + "\x1b\x10\xe6\xa6\x87\x21\xbe\x61" + "\x1a\x8b\x4d\x28\x26\x01\xdb\x3b" + "\x36\xbe\x92\x46\x91\x5e\xc8\x2a", + .nout = 32 + }, + { + .path = "/crypto/pbkdf/rfc3962/sha1/iter50", + .hash = QCRYPTO_HASH_ALG_SHA1, + .iterations = 50, + .key = "\360\235\204\236", /* g-clef ("\xf09d849e) */ + .nkey = 4, + .salt = "EXAMPLE.COMpianist", + .nsalt = 18, + .out = "\x6b\x9c\xf2\x6d\x45\x45\x5a\x43" + "\xa5\xb8\xbb\x27\x6a\x40\x3b\x39" + "\xe7\xfe\x37\xa0\xc4\x1e\x02\xc2" + "\x81\xff\x30\x69\xe1\xe9\x4f\x52", + .nout = 32 + }, + + /* RFC-6070 test data */ + { + .path = "/crypto/pbkdf/rfc6070/sha1/iter1", + .hash = QCRYPTO_HASH_ALG_SHA1, + .iterations = 1, + .key = "password", + .nkey = 8, + .salt = "salt", + .nsalt = 4, + .out = "\x0c\x60\xc8\x0f\x96\x1f\x0e\x71\xf3\xa9" + "\xb5\x24\xaf\x60\x12\x06\x2f\xe0\x37\xa6", + .nout = 20 + }, + { + .path = "/crypto/pbkdf/rfc6070/sha1/iter2", + .hash = QCRYPTO_HASH_ALG_SHA1, + .iterations = 2, + .key = "password", + .nkey = 8, + .salt = "salt", + .nsalt = 4, + .out = "\xea\x6c\x01\x4d\xc7\x2d\x6f\x8c\xcd\x1e" + "\xd9\x2a\xce\x1d\x41\xf0\xd8\xde\x89\x57", + .nout = 20 + }, + { + .path = "/crypto/pbkdf/rfc6070/sha1/iter4096", + .hash = QCRYPTO_HASH_ALG_SHA1, + .iterations = 4096, + .key = "password", + .nkey = 8, + .salt = "salt", + .nsalt = 4, + .out = "\x4b\x00\x79\x01\xb7\x65\x48\x9a\xbe\xad" + "\x49\xd9\x26\xf7\x21\xd0\x65\xa4\x29\xc1", + .nout = 20 + }, + { + .path = "/crypto/pbkdf/rfc6070/sha1/iter16777216", + .hash = QCRYPTO_HASH_ALG_SHA1, + .iterations = 16777216, + .key = "password", + .nkey = 8, + .salt = "salt", + .nsalt = 4, + .out = "\xee\xfe\x3d\x61\xcd\x4d\xa4\xe4\xe9\x94" + "\x5b\x3d\x6b\xa2\x15\x8c\x26\x34\xe9\x84", + .nout = 20, + .slow = true, + }, + { + .path = "/crypto/pbkdf/rfc6070/sha1/iter4096a", + .hash = QCRYPTO_HASH_ALG_SHA1, + .iterations = 4096, + .key = "passwordPASSWORDpassword", + .nkey = 24, + .salt = "saltSALTsaltSALTsaltSALTsaltSALTsalt", + .nsalt = 36, + .out = "\x3d\x2e\xec\x4f\xe4\x1c\x84\x9b\x80\xc8" + "\xd8\x36\x62\xc0\xe4\x4a\x8b\x29\x1a\x96" + "\x4c\xf2\xf0\x70\x38", + .nout = 25 + }, + { + .path = "/crypto/pbkdf/rfc6070/sha1/iter4096b", + .hash = QCRYPTO_HASH_ALG_SHA1, + .iterations = 4096, + .key = "pass\0word", + .nkey = 9, + .salt = "sa\0lt", + .nsalt = 5, + .out = "\x56\xfa\x6a\xa7\x55\x48\x09\x9d\xcc\x37" + "\xd7\xf0\x34\x25\xe0\xc3", + .nout = 16 + }, + + /* non-RFC misc test data */ +#ifdef CONFIG_NETTLE + { + /* empty password test. + * Broken with libgcrypt <= 1.5.0, hence CONFIG_NETTLE */ + .path = "/crypto/pbkdf/nonrfc/sha1/iter2", + .hash = QCRYPTO_HASH_ALG_SHA1, + .iterations = 2, + .key = "", + .nkey = 0, + .salt = "salt", + .nsalt = 4, + .out = "\x13\x3a\x4c\xe8\x37\xb4\xd2\x52\x1e\xe2" + "\xbf\x03\xe1\x1c\x71\xca\x79\x4e\x07\x97", + .nout = 20 + }, +#endif + { + /* Password exceeds block size test */ + .path = "/crypto/pbkdf/nonrfc/sha256/iter1200", + .hash = QCRYPTO_HASH_ALG_SHA256, + .iterations = 1200, + .key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + .nkey = 65, + .salt = "pass phrase exceeds block size", + .nsalt = 30, + .out = "\x22\x34\x4b\xc4\xb6\xe3\x26\x75" + "\xa8\x09\x0f\x3e\xa8\x0b\xe0\x1d" + "\x5f\x95\x12\x6a\x2c\xdd\xc3\xfa" + "\xcc\x4a\x5e\x6d\xca\x04\xec\x58", + .nout = 32 + }, +#if 0 + { + .path = "/crypto/pbkdf/nonrfc/sha512/iter1200", + .hash = QCRYPTO_HASH_ALG_SHA512, + .iterations = 1200, + .key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + .nkey = 129, + .salt = "pass phrase exceeds block size", + .nsalt = 30, + .out = "\x0f\xb2\xed\x2c\x0e\x6e\xfb\x7d" + "\x7d\x8e\xdd\x58\x01\xb4\x59\x72" + "\x99\x92\x16\x30\x5e\xa4\x36\x8d" + "\x76\x14\x80\xf3\xe3\x7a\x22\xb9", + .nout = 32 + }, + { + .path = "/crypto/pbkdf/nonrfc/whirlpool/iter1200", + .hash = QCRYPTO_HASH_ALG_WHIRLPOOL, + .iterations = 1200, + .key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + .nkey = 65, + .salt = "pass phrase exceeds block size", + .nsalt = 30, + .out = "\x9c\x1c\x74\xf5\x88\x26\xe7\x6a" + "\x53\x58\xf4\x0c\x39\xe7\x80\x89" + "\x07\xc0\x31\x19\x9a\x50\xa2\x48" + "\xf1\xd9\xfe\x78\x64\xe5\x84\x50", + .nout = 32 + } +#endif +}; + + +static inline char hex(int i) +{ + if (i < 10) { + return '0' + i; + } + return 'a' + (i - 10); +} + +static char *hex_string(const uint8_t *bytes, + size_t len) +{ + char *hexstr = g_new0(char, len * 2 + 1); + size_t i; + + for (i = 0; i < len; i++) { + hexstr[i * 2] = hex((bytes[i] >> 4) & 0xf); + hexstr[i * 2 + 1] = hex(bytes[i] & 0xf); + } + hexstr[len * 2] = '\0'; + + return hexstr; +} + +static void test_pbkdf(const void *opaque) +{ + const QCryptoPbkdfTestData *data = opaque; + size_t nout = data->nout; + uint8_t *out = g_new0(uint8_t, nout); + gchar *expect, *actual; + + qcrypto_pbkdf2(data->hash, + (uint8_t *)data->key, data->nkey, + (uint8_t *)data->salt, data->nsalt, + data->iterations, + (uint8_t *)out, nout, + &error_abort); + + expect = hex_string((const uint8_t *)data->out, data->nout); + actual = hex_string(out, nout); + + g_assert_cmpstr(actual, ==, expect); + + g_free(actual); + g_free(expect); + g_free(out); +} + + +static void test_pbkdf_timing(void) +{ + uint8_t key[32]; + uint8_t salt[32]; + int iters; + + memset(key, 0x5d, sizeof(key)); + memset(salt, 0x7c, sizeof(salt)); + + iters = qcrypto_pbkdf2_count_iters(QCRYPTO_HASH_ALG_SHA256, + key, sizeof(key), + salt, sizeof(salt), + &error_abort); + + g_assert(iters >= (1 << 15)); +} + + +int main(int argc, char **argv) +{ + size_t i; + + g_test_init(&argc, &argv, NULL); + + g_assert(qcrypto_init(NULL) == 0); + + for (i = 0; i < G_N_ELEMENTS(test_data); i++) { + if (!test_data[i].slow || + g_test_slow()) { + g_test_add_data_func(test_data[i].path, &test_data[i], test_pbkdf); + } + } + + if (g_test_slow()) { + g_test_add_func("/crypt0/pbkdf/timing", test_pbkdf_timing); + } + + return g_test_run(); +} +#else +int main(int argc, char **argv) +{ + return 0; +} +#endif diff --git a/qemu/tests/test-crypto-secret.c b/qemu/tests/test-crypto-secret.c new file mode 100644 index 000000000..aa26c2049 --- /dev/null +++ b/qemu/tests/test-crypto-secret.c @@ -0,0 +1,455 @@ +/* + * QEMU Crypto secret handling + * + * Copyright (c) 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "qemu/osdep.h" +#include <glib.h> + +#include "crypto/init.h" +#include "crypto/secret.h" +#include "qapi/error.h" +#include "qemu/module.h" + +static void test_secret_direct(void) +{ + Object *sec = object_new_with_props( + TYPE_QCRYPTO_SECRET, + object_get_objects_root(), + "sec0", + &error_abort, + "data", "123456", + NULL); + + char *pw = qcrypto_secret_lookup_as_utf8("sec0", + &error_abort); + + g_assert_cmpstr(pw, ==, "123456"); + + object_unparent(sec); + g_free(pw); +} + + +static void test_secret_indirect_good(void) +{ + Object *sec; + char *fname = NULL; + int fd = g_file_open_tmp("secretXXXXXX", + &fname, + NULL); + + g_assert(fd >= 0); + g_assert_nonnull(fname); + + g_assert(write(fd, "123456", 6) == 6); + + sec = object_new_with_props( + TYPE_QCRYPTO_SECRET, + object_get_objects_root(), + "sec0", + &error_abort, + "file", fname, + NULL); + + char *pw = qcrypto_secret_lookup_as_utf8("sec0", + &error_abort); + + g_assert_cmpstr(pw, ==, "123456"); + + object_unparent(sec); + g_free(pw); + close(fd); + g_free(fname); +} + + +static void test_secret_indirect_badfile(void) +{ + Object *sec = object_new_with_props( + TYPE_QCRYPTO_SECRET, + object_get_objects_root(), + "sec0", + NULL, + "file", "does-not-exist", + NULL); + + g_assert(sec == NULL); +} + + +static void test_secret_indirect_emptyfile(void) +{ + Object *sec; + char *fname = NULL; + int fd = g_file_open_tmp("secretXXXXXX", + &fname, + NULL); + + g_assert(fd >= 0); + g_assert_nonnull(fname); + + sec = object_new_with_props( + TYPE_QCRYPTO_SECRET, + object_get_objects_root(), + "sec0", + &error_abort, + "file", fname, + NULL); + + char *pw = qcrypto_secret_lookup_as_utf8("sec0", + &error_abort); + + g_assert_cmpstr(pw, ==, ""); + + object_unparent(sec); + g_free(pw); + close(fd); + g_free(fname); +} + + +static void test_secret_noconv_base64_good(void) +{ + Object *sec = object_new_with_props( + TYPE_QCRYPTO_SECRET, + object_get_objects_root(), + "sec0", + &error_abort, + "data", "MTIzNDU2", + "format", "base64", + NULL); + + char *pw = qcrypto_secret_lookup_as_base64("sec0", + &error_abort); + + g_assert_cmpstr(pw, ==, "MTIzNDU2"); + + object_unparent(sec); + g_free(pw); +} + + +static void test_secret_noconv_base64_bad(void) +{ + Object *sec = object_new_with_props( + TYPE_QCRYPTO_SECRET, + object_get_objects_root(), + "sec0", + NULL, + "data", "MTI$NDU2", + "format", "base64", + NULL); + + g_assert(sec == NULL); +} + + +static void test_secret_noconv_utf8(void) +{ + Object *sec = object_new_with_props( + TYPE_QCRYPTO_SECRET, + object_get_objects_root(), + "sec0", + &error_abort, + "data", "123456", + "format", "raw", + NULL); + + char *pw = qcrypto_secret_lookup_as_utf8("sec0", + &error_abort); + + g_assert_cmpstr(pw, ==, "123456"); + + object_unparent(sec); + g_free(pw); +} + + +static void test_secret_conv_base64_utf8valid(void) +{ + Object *sec = object_new_with_props( + TYPE_QCRYPTO_SECRET, + object_get_objects_root(), + "sec0", + &error_abort, + "data", "MTIzNDU2", + "format", "base64", + NULL); + + char *pw = qcrypto_secret_lookup_as_utf8("sec0", + &error_abort); + + g_assert_cmpstr(pw, ==, "123456"); + + object_unparent(sec); + g_free(pw); +} + + +static void test_secret_conv_base64_utf8invalid(void) +{ + Object *sec = object_new_with_props( + TYPE_QCRYPTO_SECRET, + object_get_objects_root(), + "sec0", + &error_abort, + "data", "f0VMRgIBAQAAAA==", + "format", "base64", + NULL); + + char *pw = qcrypto_secret_lookup_as_utf8("sec0", + NULL); + g_assert(pw == NULL); + + object_unparent(sec); +} + + +static void test_secret_conv_utf8_base64(void) +{ + Object *sec = object_new_with_props( + TYPE_QCRYPTO_SECRET, + object_get_objects_root(), + "sec0", + &error_abort, + "data", "123456", + NULL); + + char *pw = qcrypto_secret_lookup_as_base64("sec0", + &error_abort); + + g_assert_cmpstr(pw, ==, "MTIzNDU2"); + + object_unparent(sec); + g_free(pw); +} + + +static void test_secret_crypt_raw(void) +{ + Object *master = object_new_with_props( + TYPE_QCRYPTO_SECRET, + object_get_objects_root(), + "master", + &error_abort, + "data", "9miloPQCzGy+TL6aonfzVcptibCmCIhKzrnlfwiWivk=", + "format", "base64", + NULL); + Object *sec = object_new_with_props( + TYPE_QCRYPTO_SECRET, + object_get_objects_root(), + "sec0", + &error_abort, + "data", + "\xCC\xBF\xF7\x09\x46\x19\x0B\x52\x2A\x3A\xB4\x6B\xCD\x7A\xB0\xB0", + "format", "raw", + "keyid", "master", + "iv", "0I7Gw/TKuA+Old2W2apQ3g==", + NULL); + + char *pw = qcrypto_secret_lookup_as_utf8("sec0", + &error_abort); + + g_assert_cmpstr(pw, ==, "123456"); + + object_unparent(sec); + object_unparent(master); + g_free(pw); +} + + +static void test_secret_crypt_base64(void) +{ + Object *master = object_new_with_props( + TYPE_QCRYPTO_SECRET, + object_get_objects_root(), + "master", + &error_abort, + "data", "9miloPQCzGy+TL6aonfzVcptibCmCIhKzrnlfwiWivk=", + "format", "base64", + NULL); + Object *sec = object_new_with_props( + TYPE_QCRYPTO_SECRET, + object_get_objects_root(), + "sec0", + &error_abort, + "data", "zL/3CUYZC1IqOrRrzXqwsA==", + "format", "base64", + "keyid", "master", + "iv", "0I7Gw/TKuA+Old2W2apQ3g==", + NULL); + + char *pw = qcrypto_secret_lookup_as_utf8("sec0", + &error_abort); + + g_assert_cmpstr(pw, ==, "123456"); + + object_unparent(sec); + object_unparent(master); + g_free(pw); +} + + +static void test_secret_crypt_short_key(void) +{ + Object *master = object_new_with_props( + TYPE_QCRYPTO_SECRET, + object_get_objects_root(), + "master", + &error_abort, + "data", "9miloPQCzGy+TL6aonfzVc", + "format", "base64", + NULL); + Object *sec = object_new_with_props( + TYPE_QCRYPTO_SECRET, + object_get_objects_root(), + "sec0", + NULL, + "data", "zL/3CUYZC1IqOrRrzXqwsA==", + "format", "raw", + "keyid", "master", + "iv", "0I7Gw/TKuA+Old2W2apQ3g==", + NULL); + + g_assert(sec == NULL); + object_unparent(master); +} + + +static void test_secret_crypt_short_iv(void) +{ + Object *master = object_new_with_props( + TYPE_QCRYPTO_SECRET, + object_get_objects_root(), + "master", + &error_abort, + "data", "9miloPQCzGy+TL6aonfzVcptibCmCIhKzrnlfwiWivk=", + "format", "base64", + NULL); + Object *sec = object_new_with_props( + TYPE_QCRYPTO_SECRET, + object_get_objects_root(), + "sec0", + NULL, + "data", "zL/3CUYZC1IqOrRrzXqwsA==", + "format", "raw", + "keyid", "master", + "iv", "0I7Gw/TKuA+Old2W2a", + NULL); + + g_assert(sec == NULL); + object_unparent(master); +} + + +static void test_secret_crypt_missing_iv(void) +{ + Object *master = object_new_with_props( + TYPE_QCRYPTO_SECRET, + object_get_objects_root(), + "master", + &error_abort, + "data", "9miloPQCzGy+TL6aonfzVcptibCmCIhKzrnlfwiWivk=", + "format", "base64", + NULL); + Object *sec = object_new_with_props( + TYPE_QCRYPTO_SECRET, + object_get_objects_root(), + "sec0", + NULL, + "data", "zL/3CUYZC1IqOrRrzXqwsA==", + "format", "raw", + "keyid", "master", + NULL); + + g_assert(sec == NULL); + object_unparent(master); +} + + +static void test_secret_crypt_bad_iv(void) +{ + Object *master = object_new_with_props( + TYPE_QCRYPTO_SECRET, + object_get_objects_root(), + "master", + &error_abort, + "data", "9miloPQCzGy+TL6aonfzVcptibCmCIhKzrnlfwiWivk=", + "format", "base64", + NULL); + Object *sec = object_new_with_props( + TYPE_QCRYPTO_SECRET, + object_get_objects_root(), + "sec0", + NULL, + "data", "zL/3CUYZC1IqOrRrzXqwsA==", + "format", "raw", + "keyid", "master", + "iv", "0I7Gw/TK$$uA+Old2W2a", + NULL); + + g_assert(sec == NULL); + object_unparent(master); +} + + +int main(int argc, char **argv) +{ + module_call_init(MODULE_INIT_QOM); + g_test_init(&argc, &argv, NULL); + + g_assert(qcrypto_init(NULL) == 0); + + g_test_add_func("/crypto/secret/direct", + test_secret_direct); + g_test_add_func("/crypto/secret/indirect/good", + test_secret_indirect_good); + g_test_add_func("/crypto/secret/indirect/badfile", + test_secret_indirect_badfile); + g_test_add_func("/crypto/secret/indirect/emptyfile", + test_secret_indirect_emptyfile); + + g_test_add_func("/crypto/secret/noconv/base64/good", + test_secret_noconv_base64_good); + g_test_add_func("/crypto/secret/noconv/base64/bad", + test_secret_noconv_base64_bad); + g_test_add_func("/crypto/secret/noconv/utf8", + test_secret_noconv_utf8); + g_test_add_func("/crypto/secret/conv/base64/utf8valid", + test_secret_conv_base64_utf8valid); + g_test_add_func("/crypto/secret/conv/base64/utf8invalid", + test_secret_conv_base64_utf8invalid); + g_test_add_func("/crypto/secret/conv/utf8/base64", + test_secret_conv_utf8_base64); + + g_test_add_func("/crypto/secret/crypt/raw", + test_secret_crypt_raw); + g_test_add_func("/crypto/secret/crypt/base64", + test_secret_crypt_base64); + g_test_add_func("/crypto/secret/crypt/shortkey", + test_secret_crypt_short_key); + g_test_add_func("/crypto/secret/crypt/shortiv", + test_secret_crypt_short_iv); + g_test_add_func("/crypto/secret/crypt/missingiv", + test_secret_crypt_missing_iv); + g_test_add_func("/crypto/secret/crypt/badiv", + test_secret_crypt_bad_iv); + + return g_test_run(); +} diff --git a/qemu/tests/test-crypto-tlscredsx509.c b/qemu/tests/test-crypto-tlscredsx509.c new file mode 100644 index 000000000..af2f80e89 --- /dev/null +++ b/qemu/tests/test-crypto-tlscredsx509.c @@ -0,0 +1,730 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Author: Daniel P. Berrange <berrange@redhat.com> + */ + +#include "qemu/osdep.h" + +#include "crypto-tls-x509-helpers.h" +#include "crypto/tlscredsx509.h" +#include "qapi/error.h" + +#ifdef QCRYPTO_HAVE_TLS_TEST_SUPPORT + +#define WORKDIR "tests/test-crypto-tlscredsx509-work/" +#define KEYFILE WORKDIR "key-ctx.pem" + +struct QCryptoTLSCredsTestData { + bool isServer; + const char *cacrt; + const char *crt; + bool expectFail; +}; + + +static QCryptoTLSCreds *test_tls_creds_create(QCryptoTLSCredsEndpoint endpoint, + const char *certdir, + Error **errp) +{ + Object *parent = object_get_objects_root(); + Object *creds = object_new_with_props( + TYPE_QCRYPTO_TLS_CREDS_X509, + parent, + "testtlscreds", + errp, + "endpoint", (endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER ? + "server" : "client"), + "dir", certdir, + "verify-peer", "yes", + "sanity-check", "yes", + NULL); + + if (*errp) { + return NULL; + } + return QCRYPTO_TLS_CREDS(creds); +} + +/* + * This tests sanity checking of our own certificates + * + * The code being tested is used when TLS creds are created, + * and aim to ensure QMEU has been configured with sane + * certificates. This allows us to give much much much + * clearer error messages to the admin when they misconfigure + * things. + */ +static void test_tls_creds(const void *opaque) +{ + struct QCryptoTLSCredsTestData *data = + (struct QCryptoTLSCredsTestData *)opaque; + QCryptoTLSCreds *creds; + Error *err = NULL; + +#define CERT_DIR "tests/test-crypto-tlscredsx509-certs/" + mkdir(CERT_DIR, 0700); + + unlink(CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT); + if (data->isServer) { + unlink(CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_CERT); + unlink(CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_KEY); + } else { + unlink(CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_CERT); + unlink(CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_KEY); + } + + if (access(data->cacrt, R_OK) == 0) { + g_assert(link(data->cacrt, + CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT) == 0); + } + if (data->isServer) { + if (access(data->crt, R_OK) == 0) { + g_assert(link(data->crt, + CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_CERT) == 0); + } + g_assert(link(KEYFILE, + CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_KEY) == 0); + } else { + if (access(data->crt, R_OK) == 0) { + g_assert(link(data->crt, + CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_CERT) == 0); + } + g_assert(link(KEYFILE, + CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_KEY) == 0); + } + + creds = test_tls_creds_create( + (data->isServer ? + QCRYPTO_TLS_CREDS_ENDPOINT_SERVER : + QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT), + CERT_DIR, + &err); + + if (data->expectFail) { + error_free(err); + g_assert(creds == NULL); + } else { + if (err) { + g_printerr("Failed to generate creds: %s\n", + error_get_pretty(err)); + error_free(err); + } + g_assert(creds != NULL); + } + + unlink(CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT); + if (data->isServer) { + unlink(CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_CERT); + unlink(CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_KEY); + } else { + unlink(CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_CERT); + unlink(CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_KEY); + } + rmdir(CERT_DIR); + if (creds) { + object_unparent(OBJECT(creds)); + } +} + +int main(int argc, char **argv) +{ + int ret; + + module_call_init(MODULE_INIT_QOM); + g_test_init(&argc, &argv, NULL); + setenv("GNUTLS_FORCE_FIPS_MODE", "2", 1); + + mkdir(WORKDIR, 0700); + + test_tls_init(KEYFILE); + +# define TLS_TEST_REG(name, isServer, caCrt, crt, expectFail) \ + struct QCryptoTLSCredsTestData name = { \ + isServer, caCrt, crt, expectFail \ + }; \ + g_test_add_data_func("/qcrypto/tlscredsx509/" # name, \ + &name, test_tls_creds); \ + + /* A perfect CA, perfect client & perfect server */ + + /* Basic:CA:critical */ + TLS_ROOT_REQ(cacertreq, + "UK", "qemu CA", NULL, NULL, NULL, NULL, + true, true, true, + true, true, GNUTLS_KEY_KEY_CERT_SIGN, + false, false, NULL, NULL, + 0, 0); + + TLS_CERT_REQ(servercertreq, cacertreq, + "UK", "qemu.org", NULL, NULL, NULL, NULL, + true, true, false, + true, true, + GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, + true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL, + 0, 0); + TLS_CERT_REQ(clientcertreq, cacertreq, + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, false, + true, true, + GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, + true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL, + 0, 0); + + TLS_TEST_REG(perfectserver, true, + cacertreq.filename, servercertreq.filename, false); + TLS_TEST_REG(perfectclient, false, + cacertreq.filename, clientcertreq.filename, false); + + + /* Some other CAs which are good */ + + /* Basic:CA:critical */ + TLS_ROOT_REQ(cacert1req, + "UK", "qemu CA 1", NULL, NULL, NULL, NULL, + true, true, true, + false, false, 0, + false, false, NULL, NULL, + 0, 0); + TLS_CERT_REQ(servercert1req, cacert1req, + "UK", "qemu.org", NULL, NULL, NULL, NULL, + true, true, false, + true, true, + GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, + true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL, + 0, 0); + + /* Basic:CA:not-critical */ + TLS_ROOT_REQ(cacert2req, + "UK", "qemu CA 2", NULL, NULL, NULL, NULL, + true, false, true, + false, false, 0, + false, false, NULL, NULL, + 0, 0); + TLS_CERT_REQ(servercert2req, cacert2req, + "UK", "qemu.org", NULL, NULL, NULL, NULL, + true, true, false, + true, true, + GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, + true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL, + 0, 0); + + /* Key usage:cert-sign:critical */ + TLS_ROOT_REQ(cacert3req, + "UK", "qemu CA 3", NULL, NULL, NULL, NULL, + true, true, true, + true, true, GNUTLS_KEY_KEY_CERT_SIGN, + false, false, NULL, NULL, + 0, 0); + TLS_CERT_REQ(servercert3req, cacert3req, + "UK", "qemu.org", NULL, NULL, NULL, NULL, + true, true, false, + true, true, + GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, + true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL, + 0, 0); + + TLS_TEST_REG(goodca1, true, + cacert1req.filename, servercert1req.filename, false); + TLS_TEST_REG(goodca2, true, + cacert2req.filename, servercert2req.filename, false); + TLS_TEST_REG(goodca3, true, + cacert3req.filename, servercert3req.filename, false); + + /* Now some bad certs */ + + /* Key usage:dig-sig:not-critical */ + TLS_ROOT_REQ(cacert4req, + "UK", "qemu CA 4", NULL, NULL, NULL, NULL, + true, true, true, + true, false, GNUTLS_KEY_DIGITAL_SIGNATURE, + false, false, NULL, NULL, + 0, 0); + TLS_CERT_REQ(servercert4req, cacert4req, + "UK", "qemu.org", NULL, NULL, NULL, NULL, + true, true, false, + true, true, + GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, + true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL, + 0, 0); + /* no-basic */ + TLS_ROOT_REQ(cacert5req, + "UK", "qemu CA 5", NULL, NULL, NULL, NULL, + false, false, false, + false, false, 0, + false, false, NULL, NULL, + 0, 0); + TLS_CERT_REQ(servercert5req, cacert5req, + "UK", "qemu.org", NULL, NULL, NULL, NULL, + true, true, false, + true, true, + GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, + true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL, + 0, 0); + /* Key usage:dig-sig:critical */ + TLS_ROOT_REQ(cacert6req, + "UK", "qemu CA 6", NULL, NULL, NULL, NULL, + true, true, true, + true, true, GNUTLS_KEY_DIGITAL_SIGNATURE, + false, false, NULL, NULL, + 0, 0); + TLS_CERT_REQ(servercert6req, cacert6req, + "UK", "qemu.org", NULL, NULL, NULL, NULL, + true, true, false, + true, true, + GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, + true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL, + 0, 0); + + /* Technically a CA cert with basic constraints + * key purpose == key signing + non-critical should + * be rejected. GNUTLS < 3.1 does not reject it and + * we don't anticipate them changing this behaviour + */ + TLS_TEST_REG(badca1, true, cacert4req.filename, servercert4req.filename, + (GNUTLS_VERSION_MAJOR == 3 && GNUTLS_VERSION_MINOR >= 1) || + GNUTLS_VERSION_MAJOR > 3); + TLS_TEST_REG(badca2, true, + cacert5req.filename, servercert5req.filename, true); + TLS_TEST_REG(badca3, true, + cacert6req.filename, servercert6req.filename, true); + + + /* Various good servers */ + /* no usage or purpose */ + TLS_CERT_REQ(servercert7req, cacertreq, + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, false, + false, false, 0, + false, false, NULL, NULL, + 0, 0); + /* usage:cert-sign+dig-sig+encipher:critical */ + TLS_CERT_REQ(servercert8req, cacertreq, + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, false, + true, true, + GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT | + GNUTLS_KEY_KEY_CERT_SIGN, + false, false, NULL, NULL, + 0, 0); + /* usage:cert-sign:not-critical */ + TLS_CERT_REQ(servercert9req, cacertreq, + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, false, + true, false, GNUTLS_KEY_KEY_CERT_SIGN, + false, false, NULL, NULL, + 0, 0); + /* purpose:server:critical */ + TLS_CERT_REQ(servercert10req, cacertreq, + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, false, + false, false, 0, + true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL, + 0, 0); + /* purpose:server:not-critical */ + TLS_CERT_REQ(servercert11req, cacertreq, + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, false, + false, false, 0, + true, false, GNUTLS_KP_TLS_WWW_SERVER, NULL, + 0, 0); + /* purpose:client+server:critical */ + TLS_CERT_REQ(servercert12req, cacertreq, + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, false, + false, false, 0, + true, true, + GNUTLS_KP_TLS_WWW_CLIENT, GNUTLS_KP_TLS_WWW_SERVER, + 0, 0); + /* purpose:client+server:not-critical */ + TLS_CERT_REQ(servercert13req, cacertreq, + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, false, + false, false, 0, + true, false, + GNUTLS_KP_TLS_WWW_CLIENT, GNUTLS_KP_TLS_WWW_SERVER, + 0, 0); + + TLS_TEST_REG(goodserver1, true, + cacertreq.filename, servercert7req.filename, false); + TLS_TEST_REG(goodserver2, true, + cacertreq.filename, servercert8req.filename, false); + TLS_TEST_REG(goodserver3, true, + cacertreq.filename, servercert9req.filename, false); + TLS_TEST_REG(goodserver4, true, + cacertreq.filename, servercert10req.filename, false); + TLS_TEST_REG(goodserver5, true, + cacertreq.filename, servercert11req.filename, false); + TLS_TEST_REG(goodserver6, true, + cacertreq.filename, servercert12req.filename, false); + TLS_TEST_REG(goodserver7, true, + cacertreq.filename, servercert13req.filename, false); + + /* Bad servers */ + + /* usage:cert-sign:critical */ + TLS_CERT_REQ(servercert14req, cacertreq, + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, false, + true, true, GNUTLS_KEY_KEY_CERT_SIGN, + false, false, NULL, NULL, + 0, 0); + /* purpose:client:critical */ + TLS_CERT_REQ(servercert15req, cacertreq, + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, false, + false, false, 0, + true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL, + 0, 0); + /* usage: none:critical */ + TLS_CERT_REQ(servercert16req, cacertreq, + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, false, + true, true, 0, + false, false, NULL, NULL, + 0, 0); + + TLS_TEST_REG(badserver1, true, + cacertreq.filename, servercert14req.filename, true); + TLS_TEST_REG(badserver2, true, + cacertreq.filename, servercert15req.filename, true); + TLS_TEST_REG(badserver3, true, + cacertreq.filename, servercert16req.filename, true); + + + + /* Various good clients */ + /* no usage or purpose */ + TLS_CERT_REQ(clientcert1req, cacertreq, + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, false, + false, false, 0, + false, false, NULL, NULL, + 0, 0); + /* usage:cert-sign+dig-sig+encipher:critical */ + TLS_CERT_REQ(clientcert2req, cacertreq, + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, false, + true, true, + GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT | + GNUTLS_KEY_KEY_CERT_SIGN, + false, false, NULL, NULL, + 0, 0); + /* usage:cert-sign:not-critical */ + TLS_CERT_REQ(clientcert3req, cacertreq, + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, false, + true, false, GNUTLS_KEY_KEY_CERT_SIGN, + false, false, NULL, NULL, + 0, 0); + /* purpose:client:critical */ + TLS_CERT_REQ(clientcert4req, cacertreq, + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, false, + false, false, 0, + true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL, + 0, 0); + /* purpose:client:not-critical */ + TLS_CERT_REQ(clientcert5req, cacertreq, + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, false, + false, false, 0, + true, false, GNUTLS_KP_TLS_WWW_CLIENT, NULL, + 0, 0); + /* purpose:client+client:critical */ + TLS_CERT_REQ(clientcert6req, cacertreq, + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, false, + false, false, 0, + true, true, + GNUTLS_KP_TLS_WWW_CLIENT, GNUTLS_KP_TLS_WWW_SERVER, + 0, 0); + /* purpose:client+client:not-critical */ + TLS_CERT_REQ(clientcert7req, cacertreq, + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, false, + false, false, 0, + true, false, + GNUTLS_KP_TLS_WWW_CLIENT, GNUTLS_KP_TLS_WWW_SERVER, + 0, 0); + + TLS_TEST_REG(goodclient1, false, + cacertreq.filename, clientcert1req.filename, false); + TLS_TEST_REG(goodclient2, false, + cacertreq.filename, clientcert2req.filename, false); + TLS_TEST_REG(goodclient3, false, + cacertreq.filename, clientcert3req.filename, false); + TLS_TEST_REG(goodclient4, false, + cacertreq.filename, clientcert4req.filename, false); + TLS_TEST_REG(goodclient5, false, + cacertreq.filename, clientcert5req.filename, false); + TLS_TEST_REG(goodclient6, false, + cacertreq.filename, clientcert6req.filename, false); + TLS_TEST_REG(goodclient7, false, + cacertreq.filename, clientcert7req.filename, false); + + /* Bad clients */ + + /* usage:cert-sign:critical */ + TLS_CERT_REQ(clientcert8req, cacertreq, + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, false, + true, true, GNUTLS_KEY_KEY_CERT_SIGN, + false, false, NULL, NULL, + 0, 0); + /* purpose:client:critical */ + TLS_CERT_REQ(clientcert9req, cacertreq, + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, false, + false, false, 0, + true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL, + 0, 0); + /* usage: none:critical */ + TLS_CERT_REQ(clientcert10req, cacertreq, + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, false, + true, true, 0, + false, false, NULL, NULL, + 0, 0); + + TLS_TEST_REG(badclient1, false, + cacertreq.filename, clientcert8req.filename, true); + TLS_TEST_REG(badclient2, false, + cacertreq.filename, clientcert9req.filename, true); + TLS_TEST_REG(badclient3, false, + cacertreq.filename, clientcert10req.filename, true); + + + + /* Expired stuff */ + + TLS_ROOT_REQ(cacertexpreq, + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, true, + true, true, GNUTLS_KEY_KEY_CERT_SIGN, + false, false, NULL, NULL, + 0, -1); + TLS_CERT_REQ(servercertexpreq, cacertexpreq, + "UK", "qemu.org", NULL, NULL, NULL, NULL, + true, true, false, + true, true, + GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, + true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL, + 0, 0); + TLS_CERT_REQ(servercertexp1req, cacertreq, + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, false, + true, true, + GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, + true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL, + 0, -1); + TLS_CERT_REQ(clientcertexp1req, cacertreq, + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, false, + true, true, + GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, + true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL, + 0, -1); + + TLS_TEST_REG(expired1, true, + cacertexpreq.filename, servercertexpreq.filename, true); + TLS_TEST_REG(expired2, true, + cacertreq.filename, servercertexp1req.filename, true); + TLS_TEST_REG(expired3, false, + cacertreq.filename, clientcertexp1req.filename, true); + + + /* Not activated stuff */ + + TLS_ROOT_REQ(cacertnewreq, + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, true, + true, true, GNUTLS_KEY_KEY_CERT_SIGN, + false, false, NULL, NULL, + 1, 2); + TLS_CERT_REQ(servercertnewreq, cacertnewreq, + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, false, + true, true, + GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, + true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL, + 0, 0); + TLS_CERT_REQ(servercertnew1req, cacertreq, + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, false, + true, true, + GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, + true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL, + 1, 2); + TLS_CERT_REQ(clientcertnew1req, cacertreq, + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, false, + true, true, + GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, + true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL, + 1, 2); + + TLS_TEST_REG(inactive1, true, + cacertnewreq.filename, servercertnewreq.filename, true); + TLS_TEST_REG(inactive2, true, + cacertreq.filename, servercertnew1req.filename, true); + TLS_TEST_REG(inactive3, false, + cacertreq.filename, clientcertnew1req.filename, true); + + TLS_ROOT_REQ(cacertrootreq, + "UK", "qemu root", NULL, NULL, NULL, NULL, + true, true, true, + true, true, GNUTLS_KEY_KEY_CERT_SIGN, + false, false, NULL, NULL, + 0, 0); + TLS_CERT_REQ(cacertlevel1areq, cacertrootreq, + "UK", "qemu level 1a", NULL, NULL, NULL, NULL, + true, true, true, + true, true, GNUTLS_KEY_KEY_CERT_SIGN, + false, false, NULL, NULL, + 0, 0); + TLS_CERT_REQ(cacertlevel1breq, cacertrootreq, + "UK", "qemu level 1b", NULL, NULL, NULL, NULL, + true, true, true, + true, true, GNUTLS_KEY_KEY_CERT_SIGN, + false, false, NULL, NULL, + 0, 0); + TLS_CERT_REQ(cacertlevel2areq, cacertlevel1areq, + "UK", "qemu level 2a", NULL, NULL, NULL, NULL, + true, true, true, + true, true, GNUTLS_KEY_KEY_CERT_SIGN, + false, false, NULL, NULL, + 0, 0); + TLS_CERT_REQ(servercertlevel3areq, cacertlevel2areq, + "UK", "qemu.org", NULL, NULL, NULL, NULL, + true, true, false, + true, true, + GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, + true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL, + 0, 0); + TLS_CERT_REQ(clientcertlevel2breq, cacertlevel1breq, + "UK", "qemu client level 2b", NULL, NULL, NULL, NULL, + true, true, false, + true, true, + GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, + true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL, + 0, 0); + + gnutls_x509_crt_t certchain[] = { + cacertrootreq.crt, + cacertlevel1areq.crt, + cacertlevel1breq.crt, + cacertlevel2areq.crt, + }; + + test_tls_write_cert_chain(WORKDIR "cacertchain-ctx.pem", + certchain, + G_N_ELEMENTS(certchain)); + + TLS_TEST_REG(chain1, true, + WORKDIR "cacertchain-ctx.pem", + servercertlevel3areq.filename, false); + TLS_TEST_REG(chain2, false, + WORKDIR "cacertchain-ctx.pem", + clientcertlevel2breq.filename, false); + + /* Some missing certs - first two are fatal, the last + * is ok + */ + TLS_TEST_REG(missingca, true, + "cacertdoesnotexist.pem", + servercert1req.filename, true); + TLS_TEST_REG(missingserver, true, + cacert1req.filename, + "servercertdoesnotexist.pem", true); + TLS_TEST_REG(missingclient, false, + cacert1req.filename, + "clientcertdoesnotexist.pem", false); + + ret = g_test_run(); + + test_tls_discard_cert(&cacertreq); + test_tls_discard_cert(&cacert1req); + test_tls_discard_cert(&cacert2req); + test_tls_discard_cert(&cacert3req); + test_tls_discard_cert(&cacert4req); + test_tls_discard_cert(&cacert5req); + test_tls_discard_cert(&cacert6req); + + test_tls_discard_cert(&servercertreq); + test_tls_discard_cert(&servercert1req); + test_tls_discard_cert(&servercert2req); + test_tls_discard_cert(&servercert3req); + test_tls_discard_cert(&servercert4req); + test_tls_discard_cert(&servercert5req); + test_tls_discard_cert(&servercert6req); + test_tls_discard_cert(&servercert7req); + test_tls_discard_cert(&servercert8req); + test_tls_discard_cert(&servercert9req); + test_tls_discard_cert(&servercert10req); + test_tls_discard_cert(&servercert11req); + test_tls_discard_cert(&servercert12req); + test_tls_discard_cert(&servercert13req); + test_tls_discard_cert(&servercert14req); + test_tls_discard_cert(&servercert15req); + test_tls_discard_cert(&servercert16req); + + test_tls_discard_cert(&clientcertreq); + test_tls_discard_cert(&clientcert1req); + test_tls_discard_cert(&clientcert2req); + test_tls_discard_cert(&clientcert3req); + test_tls_discard_cert(&clientcert4req); + test_tls_discard_cert(&clientcert5req); + test_tls_discard_cert(&clientcert6req); + test_tls_discard_cert(&clientcert7req); + test_tls_discard_cert(&clientcert8req); + test_tls_discard_cert(&clientcert9req); + test_tls_discard_cert(&clientcert10req); + + test_tls_discard_cert(&cacertexpreq); + test_tls_discard_cert(&servercertexpreq); + test_tls_discard_cert(&servercertexp1req); + test_tls_discard_cert(&clientcertexp1req); + + test_tls_discard_cert(&cacertnewreq); + test_tls_discard_cert(&servercertnewreq); + test_tls_discard_cert(&servercertnew1req); + test_tls_discard_cert(&clientcertnew1req); + + test_tls_discard_cert(&cacertrootreq); + test_tls_discard_cert(&cacertlevel1areq); + test_tls_discard_cert(&cacertlevel1breq); + test_tls_discard_cert(&cacertlevel2areq); + test_tls_discard_cert(&servercertlevel3areq); + test_tls_discard_cert(&clientcertlevel2breq); + unlink(WORKDIR "cacertchain-ctx.pem"); + + test_tls_cleanup(KEYFILE); + rmdir(WORKDIR); + + return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; +} + +#else /* ! QCRYPTO_HAVE_TLS_TEST_SUPPORT */ + +int +main(void) +{ + return EXIT_SUCCESS; +} + +#endif /* ! QCRYPTO_HAVE_TLS_TEST_SUPPORT */ diff --git a/qemu/tests/test-crypto-tlssession.c b/qemu/tests/test-crypto-tlssession.c new file mode 100644 index 000000000..1a4a066d7 --- /dev/null +++ b/qemu/tests/test-crypto-tlssession.c @@ -0,0 +1,534 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Author: Daniel P. Berrange <berrange@redhat.com> + */ + +#include "qemu/osdep.h" + +#include "crypto-tls-x509-helpers.h" +#include "crypto/tlscredsx509.h" +#include "crypto/tlssession.h" +#include "qom/object_interfaces.h" +#include "qapi/error.h" +#include "qemu/sockets.h" +#include "qemu/acl.h" + +#ifdef QCRYPTO_HAVE_TLS_TEST_SUPPORT + +#define WORKDIR "tests/test-crypto-tlssession-work/" +#define KEYFILE WORKDIR "key-ctx.pem" + +struct QCryptoTLSSessionTestData { + const char *servercacrt; + const char *clientcacrt; + const char *servercrt; + const char *clientcrt; + bool expectServerFail; + bool expectClientFail; + const char *hostname; + const char *const *wildcards; +}; + + +static ssize_t testWrite(const char *buf, size_t len, void *opaque) +{ + int *fd = opaque; + + return write(*fd, buf, len); +} + +static ssize_t testRead(char *buf, size_t len, void *opaque) +{ + int *fd = opaque; + + return read(*fd, buf, len); +} + +static QCryptoTLSCreds *test_tls_creds_create(QCryptoTLSCredsEndpoint endpoint, + const char *certdir, + Error **errp) +{ + Error *err = NULL; + Object *parent = object_get_objects_root(); + Object *creds = object_new_with_props( + TYPE_QCRYPTO_TLS_CREDS_X509, + parent, + (endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER ? + "testtlscredsserver" : "testtlscredsclient"), + &err, + "endpoint", (endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER ? + "server" : "client"), + "dir", certdir, + "verify-peer", "yes", + /* We skip initial sanity checks here because we + * want to make sure that problems are being + * detected at the TLS session validation stage, + * and the test-crypto-tlscreds test already + * validate the sanity check code. + */ + "sanity-check", "no", + NULL + ); + + if (err) { + error_propagate(errp, err); + return NULL; + } + return QCRYPTO_TLS_CREDS(creds); +} + + +/* + * This tests validation checking of peer certificates + * + * This is replicating the checks that are done for an + * active TLS session after handshake completes. To + * simulate that we create our TLS contexts, skipping + * sanity checks. We then get a socketpair, and + * initiate a TLS session across them. Finally do + * do actual cert validation tests + */ +static void test_crypto_tls_session(const void *opaque) +{ + struct QCryptoTLSSessionTestData *data = + (struct QCryptoTLSSessionTestData *)opaque; + QCryptoTLSCreds *clientCreds; + QCryptoTLSCreds *serverCreds; + QCryptoTLSSession *clientSess = NULL; + QCryptoTLSSession *serverSess = NULL; + qemu_acl *acl; + const char * const *wildcards; + int channel[2]; + bool clientShake = false; + bool serverShake = false; + Error *err = NULL; + int ret; + + /* We'll use this for our fake client-server connection */ + ret = socketpair(AF_UNIX, SOCK_STREAM, 0, channel); + g_assert(ret == 0); + + /* + * We have an evil loop to do the handshake in a single + * thread, so we need these non-blocking to avoid deadlock + * of ourselves + */ + qemu_set_nonblock(channel[0]); + qemu_set_nonblock(channel[1]); + +#define CLIENT_CERT_DIR "tests/test-crypto-tlssession-client/" +#define SERVER_CERT_DIR "tests/test-crypto-tlssession-server/" + mkdir(CLIENT_CERT_DIR, 0700); + mkdir(SERVER_CERT_DIR, 0700); + + unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT); + unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_CERT); + unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_KEY); + + unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT); + unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_CERT); + unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_KEY); + + g_assert(link(data->servercacrt, + SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT) == 0); + g_assert(link(data->servercrt, + SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_CERT) == 0); + g_assert(link(KEYFILE, + SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_KEY) == 0); + + g_assert(link(data->clientcacrt, + CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT) == 0); + g_assert(link(data->clientcrt, + CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_CERT) == 0); + g_assert(link(KEYFILE, + CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_KEY) == 0); + + clientCreds = test_tls_creds_create( + QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT, + CLIENT_CERT_DIR, + &err); + g_assert(clientCreds != NULL); + + serverCreds = test_tls_creds_create( + QCRYPTO_TLS_CREDS_ENDPOINT_SERVER, + SERVER_CERT_DIR, + &err); + g_assert(serverCreds != NULL); + + acl = qemu_acl_init("tlssessionacl"); + qemu_acl_reset(acl); + wildcards = data->wildcards; + while (wildcards && *wildcards) { + qemu_acl_append(acl, 0, *wildcards); + wildcards++; + } + + /* Now the real part of the test, setup the sessions */ + clientSess = qcrypto_tls_session_new( + clientCreds, data->hostname, NULL, + QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT, &err); + serverSess = qcrypto_tls_session_new( + serverCreds, NULL, + data->wildcards ? "tlssessionacl" : NULL, + QCRYPTO_TLS_CREDS_ENDPOINT_SERVER, &err); + + g_assert(clientSess != NULL); + g_assert(serverSess != NULL); + + /* For handshake to work, we need to set the I/O callbacks + * to read/write over the socketpair + */ + qcrypto_tls_session_set_callbacks(serverSess, + testWrite, testRead, + &channel[0]); + qcrypto_tls_session_set_callbacks(clientSess, + testWrite, testRead, + &channel[1]); + + /* + * Finally we loop around & around doing handshake on each + * session until we get an error, or the handshake completes. + * This relies on the socketpair being nonblocking to avoid + * deadlocking ourselves upon handshake + */ + do { + int rv; + if (!serverShake) { + rv = qcrypto_tls_session_handshake(serverSess, + &err); + g_assert(rv >= 0); + if (qcrypto_tls_session_get_handshake_status(serverSess) == + QCRYPTO_TLS_HANDSHAKE_COMPLETE) { + serverShake = true; + } + } + if (!clientShake) { + rv = qcrypto_tls_session_handshake(clientSess, + &err); + g_assert(rv >= 0); + if (qcrypto_tls_session_get_handshake_status(clientSess) == + QCRYPTO_TLS_HANDSHAKE_COMPLETE) { + clientShake = true; + } + } + } while (!clientShake && !serverShake); + + + /* Finally make sure the server validation does what + * we were expecting + */ + if (qcrypto_tls_session_check_credentials(serverSess, &err) < 0) { + g_assert(data->expectServerFail); + error_free(err); + err = NULL; + } else { + g_assert(!data->expectServerFail); + } + + /* + * And the same for the client validation check + */ + if (qcrypto_tls_session_check_credentials(clientSess, &err) < 0) { + g_assert(data->expectClientFail); + error_free(err); + err = NULL; + } else { + g_assert(!data->expectClientFail); + } + + unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT); + unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_CERT); + unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_KEY); + + unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT); + unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_CERT); + unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_KEY); + + rmdir(CLIENT_CERT_DIR); + rmdir(SERVER_CERT_DIR); + + object_unparent(OBJECT(serverCreds)); + object_unparent(OBJECT(clientCreds)); + + qcrypto_tls_session_free(serverSess); + qcrypto_tls_session_free(clientSess); + + close(channel[0]); + close(channel[1]); +} + + +int main(int argc, char **argv) +{ + int ret; + + module_call_init(MODULE_INIT_QOM); + g_test_init(&argc, &argv, NULL); + setenv("GNUTLS_FORCE_FIPS_MODE", "2", 1); + + mkdir(WORKDIR, 0700); + + test_tls_init(KEYFILE); + +# define TEST_SESS_REG(name, caCrt, \ + serverCrt, clientCrt, \ + expectServerFail, expectClientFail, \ + hostname, wildcards) \ + struct QCryptoTLSSessionTestData name = { \ + caCrt, caCrt, serverCrt, clientCrt, \ + expectServerFail, expectClientFail, \ + hostname, wildcards \ + }; \ + g_test_add_data_func("/qcrypto/tlssession/" # name, \ + &name, test_crypto_tls_session); \ + + +# define TEST_SESS_REG_EXT(name, serverCaCrt, clientCaCrt, \ + serverCrt, clientCrt, \ + expectServerFail, expectClientFail, \ + hostname, wildcards) \ + struct QCryptoTLSSessionTestData name = { \ + serverCaCrt, clientCaCrt, serverCrt, clientCrt, \ + expectServerFail, expectClientFail, \ + hostname, wildcards \ + }; \ + g_test_add_data_func("/qcrypto/tlssession/" # name, \ + &name, test_crypto_tls_session); \ + + /* A perfect CA, perfect client & perfect server */ + + /* Basic:CA:critical */ + TLS_ROOT_REQ(cacertreq, + "UK", "qemu CA", NULL, NULL, NULL, NULL, + true, true, true, + true, true, GNUTLS_KEY_KEY_CERT_SIGN, + false, false, NULL, NULL, + 0, 0); + + TLS_ROOT_REQ(altcacertreq, + "UK", "qemu CA 1", NULL, NULL, NULL, NULL, + true, true, true, + false, false, 0, + false, false, NULL, NULL, + 0, 0); + + TLS_CERT_REQ(servercertreq, cacertreq, + "UK", "qemu.org", NULL, NULL, NULL, NULL, + true, true, false, + true, true, + GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, + true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL, + 0, 0); + TLS_CERT_REQ(clientcertreq, cacertreq, + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, false, + true, true, + GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, + true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL, + 0, 0); + + TLS_CERT_REQ(clientcertaltreq, altcacertreq, + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, false, + true, true, + GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, + true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL, + 0, 0); + + TEST_SESS_REG(basicca, cacertreq.filename, + servercertreq.filename, clientcertreq.filename, + false, false, "qemu.org", NULL); + TEST_SESS_REG_EXT(differentca, cacertreq.filename, + altcacertreq.filename, servercertreq.filename, + clientcertaltreq.filename, true, true, "qemu.org", NULL); + + + /* When an altname is set, the CN is ignored, so it must be duplicated + * as an altname for it to match */ + TLS_CERT_REQ(servercertalt1req, cacertreq, + "UK", "qemu.org", "www.qemu.org", "qemu.org", + "192.168.122.1", "fec0::dead:beaf", + true, true, false, + true, true, + GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, + true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL, + 0, 0); + /* This intentionally doesn't replicate */ + TLS_CERT_REQ(servercertalt2req, cacertreq, + "UK", "qemu.org", "www.qemu.org", "wiki.qemu.org", + "192.168.122.1", "fec0::dead:beaf", + true, true, false, + true, true, + GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, + true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL, + 0, 0); + + TEST_SESS_REG(altname1, cacertreq.filename, + servercertalt1req.filename, clientcertreq.filename, + false, false, "qemu.org", NULL); + TEST_SESS_REG(altname2, cacertreq.filename, + servercertalt1req.filename, clientcertreq.filename, + false, false, "www.qemu.org", NULL); + TEST_SESS_REG(altname3, cacertreq.filename, + servercertalt1req.filename, clientcertreq.filename, + false, true, "wiki.qemu.org", NULL); + + TEST_SESS_REG(altname4, cacertreq.filename, + servercertalt2req.filename, clientcertreq.filename, + false, true, "qemu.org", NULL); + TEST_SESS_REG(altname5, cacertreq.filename, + servercertalt2req.filename, clientcertreq.filename, + false, false, "www.qemu.org", NULL); + TEST_SESS_REG(altname6, cacertreq.filename, + servercertalt2req.filename, clientcertreq.filename, + false, false, "wiki.qemu.org", NULL); + + const char *const wildcards1[] = { + "C=UK,CN=dogfood", + NULL, + }; + const char *const wildcards2[] = { + "C=UK,CN=qemu", + NULL, + }; + const char *const wildcards3[] = { + "C=UK,CN=dogfood", + "C=UK,CN=qemu", + NULL, + }; + const char *const wildcards4[] = { + "C=UK,CN=qemustuff", + NULL, + }; + const char *const wildcards5[] = { + "C=UK,CN=qemu*", + NULL, + }; + const char *const wildcards6[] = { + "C=UK,CN=*emu*", + NULL, + }; + + TEST_SESS_REG(wildcard1, cacertreq.filename, + servercertreq.filename, clientcertreq.filename, + true, false, "qemu.org", wildcards1); + TEST_SESS_REG(wildcard2, cacertreq.filename, + servercertreq.filename, clientcertreq.filename, + false, false, "qemu.org", wildcards2); + TEST_SESS_REG(wildcard3, cacertreq.filename, + servercertreq.filename, clientcertreq.filename, + false, false, "qemu.org", wildcards3); + TEST_SESS_REG(wildcard4, cacertreq.filename, + servercertreq.filename, clientcertreq.filename, + true, false, "qemu.org", wildcards4); + TEST_SESS_REG(wildcard5, cacertreq.filename, + servercertreq.filename, clientcertreq.filename, + false, false, "qemu.org", wildcards5); + TEST_SESS_REG(wildcard6, cacertreq.filename, + servercertreq.filename, clientcertreq.filename, + false, false, "qemu.org", wildcards6); + + TLS_ROOT_REQ(cacertrootreq, + "UK", "qemu root", NULL, NULL, NULL, NULL, + true, true, true, + true, true, GNUTLS_KEY_KEY_CERT_SIGN, + false, false, NULL, NULL, + 0, 0); + TLS_CERT_REQ(cacertlevel1areq, cacertrootreq, + "UK", "qemu level 1a", NULL, NULL, NULL, NULL, + true, true, true, + true, true, GNUTLS_KEY_KEY_CERT_SIGN, + false, false, NULL, NULL, + 0, 0); + TLS_CERT_REQ(cacertlevel1breq, cacertrootreq, + "UK", "qemu level 1b", NULL, NULL, NULL, NULL, + true, true, true, + true, true, GNUTLS_KEY_KEY_CERT_SIGN, + false, false, NULL, NULL, + 0, 0); + TLS_CERT_REQ(cacertlevel2areq, cacertlevel1areq, + "UK", "qemu level 2a", NULL, NULL, NULL, NULL, + true, true, true, + true, true, GNUTLS_KEY_KEY_CERT_SIGN, + false, false, NULL, NULL, + 0, 0); + TLS_CERT_REQ(servercertlevel3areq, cacertlevel2areq, + "UK", "qemu.org", NULL, NULL, NULL, NULL, + true, true, false, + true, true, + GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, + true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL, + 0, 0); + TLS_CERT_REQ(clientcertlevel2breq, cacertlevel1breq, + "UK", "qemu client level 2b", NULL, NULL, NULL, NULL, + true, true, false, + true, true, + GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, + true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL, + 0, 0); + + gnutls_x509_crt_t certchain[] = { + cacertrootreq.crt, + cacertlevel1areq.crt, + cacertlevel1breq.crt, + cacertlevel2areq.crt, + }; + + test_tls_write_cert_chain(WORKDIR "cacertchain-sess.pem", + certchain, + G_N_ELEMENTS(certchain)); + + TEST_SESS_REG(cachain, WORKDIR "cacertchain-sess.pem", + servercertlevel3areq.filename, clientcertlevel2breq.filename, + false, false, "qemu.org", NULL); + + ret = g_test_run(); + + test_tls_discard_cert(&clientcertreq); + test_tls_discard_cert(&clientcertaltreq); + + test_tls_discard_cert(&servercertreq); + test_tls_discard_cert(&servercertalt1req); + test_tls_discard_cert(&servercertalt2req); + + test_tls_discard_cert(&cacertreq); + test_tls_discard_cert(&altcacertreq); + + test_tls_discard_cert(&cacertrootreq); + test_tls_discard_cert(&cacertlevel1areq); + test_tls_discard_cert(&cacertlevel1breq); + test_tls_discard_cert(&cacertlevel2areq); + test_tls_discard_cert(&servercertlevel3areq); + test_tls_discard_cert(&clientcertlevel2breq); + unlink(WORKDIR "cacertchain-sess.pem"); + + test_tls_cleanup(KEYFILE); + rmdir(WORKDIR); + + return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; +} + +#else /* ! QCRYPTO_HAVE_TLS_TEST_SUPPORT */ + +int +main(void) +{ + return EXIT_SUCCESS; +} + +#endif /* ! QCRYPTO_HAVE_TLS_TEST_SUPPORT */ diff --git a/qemu/tests/test-crypto-xts.c b/qemu/tests/test-crypto-xts.c new file mode 100644 index 000000000..7f68b063c --- /dev/null +++ b/qemu/tests/test-crypto-xts.c @@ -0,0 +1,423 @@ +/* + * QEMU Crypto XTS cipher mode + * + * Copyright (c) 2015-2016 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + * This code is originally derived from public domain / WTFPL code in + * LibTomCrypt crytographic library http://libtom.org. The XTS code + * was donated by Elliptic Semiconductor Inc (www.ellipticsemi.com) + * to the LibTom Projects + * + */ + +#include "qemu/osdep.h" +#include "crypto/init.h" +#include "crypto/xts.h" +#include "crypto/aes.h" + +typedef struct { + const char *path; + int keylen; + unsigned char key1[32]; + unsigned char key2[32]; + uint64_t seqnum; + unsigned long PTLEN; + unsigned char PTX[512], CTX[512]; +} QCryptoXTSTestData; + +static const QCryptoXTSTestData test_data[] = { + /* #1 32 byte key, 32 byte PTX */ + { + "/crypto/xts/t-1-key-32-ptx-32", + 32, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + 0, + 32, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x91, 0x7c, 0xf6, 0x9e, 0xbd, 0x68, 0xb2, 0xec, + 0x9b, 0x9f, 0xe9, 0xa3, 0xea, 0xdd, 0xa6, 0x92, + 0xcd, 0x43, 0xd2, 0xf5, 0x95, 0x98, 0xed, 0x85, + 0x8c, 0x02, 0xc2, 0x65, 0x2f, 0xbf, 0x92, 0x2e }, + }, + + /* #2, 32 byte key, 32 byte PTX */ + { + "/crypto/xts/t-2-key-32-ptx-32", + 32, + { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 }, + { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 }, + 0x3333333333LL, + 32, + { 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 }, + { 0xc4, 0x54, 0x18, 0x5e, 0x6a, 0x16, 0x93, 0x6e, + 0x39, 0x33, 0x40, 0x38, 0xac, 0xef, 0x83, 0x8b, + 0xfb, 0x18, 0x6f, 0xff, 0x74, 0x80, 0xad, 0xc4, + 0x28, 0x93, 0x82, 0xec, 0xd6, 0xd3, 0x94, 0xf0 }, + }, + + /* #5 from xts.7, 32 byte key, 32 byte PTX */ + { + "/crypto/xts/t-5-key-32-ptx-32", + 32, + { 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, + 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0 }, + { 0xbf, 0xbe, 0xbd, 0xbc, 0xbb, 0xba, 0xb9, 0xb8, + 0xb7, 0xb6, 0xb5, 0xb4, 0xb3, 0xb2, 0xb1, 0xb0 }, + 0x123456789aLL, + 32, + { 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 }, + { 0xb0, 0x1f, 0x86, 0xf8, 0xed, 0xc1, 0x86, 0x37, + 0x06, 0xfa, 0x8a, 0x42, 0x53, 0xe3, 0x4f, 0x28, + 0xaf, 0x31, 0x9d, 0xe3, 0x83, 0x34, 0x87, 0x0f, + 0x4d, 0xd1, 0xf9, 0x4c, 0xbe, 0x98, 0x32, 0xf1 }, + }, + + /* #4, 32 byte key, 512 byte PTX */ + { + "/crypto/xts/t-4-key-32-ptx-512", + 32, + { 0x27, 0x18, 0x28, 0x18, 0x28, 0x45, 0x90, 0x45, + 0x23, 0x53, 0x60, 0x28, 0x74, 0x71, 0x35, 0x26 }, + { 0x31, 0x41, 0x59, 0x26, 0x53, 0x58, 0x97, 0x93, + 0x23, 0x84, 0x62, 0x64, 0x33, 0x83, 0x27, 0x95 }, + 0, + 512, + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, + }, + { + 0x27, 0xa7, 0x47, 0x9b, 0xef, 0xa1, 0xd4, 0x76, + 0x48, 0x9f, 0x30, 0x8c, 0xd4, 0xcf, 0xa6, 0xe2, + 0xa9, 0x6e, 0x4b, 0xbe, 0x32, 0x08, 0xff, 0x25, + 0x28, 0x7d, 0xd3, 0x81, 0x96, 0x16, 0xe8, 0x9c, + 0xc7, 0x8c, 0xf7, 0xf5, 0xe5, 0x43, 0x44, 0x5f, + 0x83, 0x33, 0xd8, 0xfa, 0x7f, 0x56, 0x00, 0x00, + 0x05, 0x27, 0x9f, 0xa5, 0xd8, 0xb5, 0xe4, 0xad, + 0x40, 0xe7, 0x36, 0xdd, 0xb4, 0xd3, 0x54, 0x12, + 0x32, 0x80, 0x63, 0xfd, 0x2a, 0xab, 0x53, 0xe5, + 0xea, 0x1e, 0x0a, 0x9f, 0x33, 0x25, 0x00, 0xa5, + 0xdf, 0x94, 0x87, 0xd0, 0x7a, 0x5c, 0x92, 0xcc, + 0x51, 0x2c, 0x88, 0x66, 0xc7, 0xe8, 0x60, 0xce, + 0x93, 0xfd, 0xf1, 0x66, 0xa2, 0x49, 0x12, 0xb4, + 0x22, 0x97, 0x61, 0x46, 0xae, 0x20, 0xce, 0x84, + 0x6b, 0xb7, 0xdc, 0x9b, 0xa9, 0x4a, 0x76, 0x7a, + 0xae, 0xf2, 0x0c, 0x0d, 0x61, 0xad, 0x02, 0x65, + 0x5e, 0xa9, 0x2d, 0xc4, 0xc4, 0xe4, 0x1a, 0x89, + 0x52, 0xc6, 0x51, 0xd3, 0x31, 0x74, 0xbe, 0x51, + 0xa1, 0x0c, 0x42, 0x11, 0x10, 0xe6, 0xd8, 0x15, + 0x88, 0xed, 0xe8, 0x21, 0x03, 0xa2, 0x52, 0xd8, + 0xa7, 0x50, 0xe8, 0x76, 0x8d, 0xef, 0xff, 0xed, + 0x91, 0x22, 0x81, 0x0a, 0xae, 0xb9, 0x9f, 0x91, + 0x72, 0xaf, 0x82, 0xb6, 0x04, 0xdc, 0x4b, 0x8e, + 0x51, 0xbc, 0xb0, 0x82, 0x35, 0xa6, 0xf4, 0x34, + 0x13, 0x32, 0xe4, 0xca, 0x60, 0x48, 0x2a, 0x4b, + 0xa1, 0xa0, 0x3b, 0x3e, 0x65, 0x00, 0x8f, 0xc5, + 0xda, 0x76, 0xb7, 0x0b, 0xf1, 0x69, 0x0d, 0xb4, + 0xea, 0xe2, 0x9c, 0x5f, 0x1b, 0xad, 0xd0, 0x3c, + 0x5c, 0xcf, 0x2a, 0x55, 0xd7, 0x05, 0xdd, 0xcd, + 0x86, 0xd4, 0x49, 0x51, 0x1c, 0xeb, 0x7e, 0xc3, + 0x0b, 0xf1, 0x2b, 0x1f, 0xa3, 0x5b, 0x91, 0x3f, + 0x9f, 0x74, 0x7a, 0x8a, 0xfd, 0x1b, 0x13, 0x0e, + 0x94, 0xbf, 0xf9, 0x4e, 0xff, 0xd0, 0x1a, 0x91, + 0x73, 0x5c, 0xa1, 0x72, 0x6a, 0xcd, 0x0b, 0x19, + 0x7c, 0x4e, 0x5b, 0x03, 0x39, 0x36, 0x97, 0xe1, + 0x26, 0x82, 0x6f, 0xb6, 0xbb, 0xde, 0x8e, 0xcc, + 0x1e, 0x08, 0x29, 0x85, 0x16, 0xe2, 0xc9, 0xed, + 0x03, 0xff, 0x3c, 0x1b, 0x78, 0x60, 0xf6, 0xde, + 0x76, 0xd4, 0xce, 0xcd, 0x94, 0xc8, 0x11, 0x98, + 0x55, 0xef, 0x52, 0x97, 0xca, 0x67, 0xe9, 0xf3, + 0xe7, 0xff, 0x72, 0xb1, 0xe9, 0x97, 0x85, 0xca, + 0x0a, 0x7e, 0x77, 0x20, 0xc5, 0xb3, 0x6d, 0xc6, + 0xd7, 0x2c, 0xac, 0x95, 0x74, 0xc8, 0xcb, 0xbc, + 0x2f, 0x80, 0x1e, 0x23, 0xe5, 0x6f, 0xd3, 0x44, + 0xb0, 0x7f, 0x22, 0x15, 0x4b, 0xeb, 0xa0, 0xf0, + 0x8c, 0xe8, 0x89, 0x1e, 0x64, 0x3e, 0xd9, 0x95, + 0xc9, 0x4d, 0x9a, 0x69, 0xc9, 0xf1, 0xb5, 0xf4, + 0x99, 0x02, 0x7a, 0x78, 0x57, 0x2a, 0xee, 0xbd, + 0x74, 0xd2, 0x0c, 0xc3, 0x98, 0x81, 0xc2, 0x13, + 0xee, 0x77, 0x0b, 0x10, 0x10, 0xe4, 0xbe, 0xa7, + 0x18, 0x84, 0x69, 0x77, 0xae, 0x11, 0x9f, 0x7a, + 0x02, 0x3a, 0xb5, 0x8c, 0xca, 0x0a, 0xd7, 0x52, + 0xaf, 0xe6, 0x56, 0xbb, 0x3c, 0x17, 0x25, 0x6a, + 0x9f, 0x6e, 0x9b, 0xf1, 0x9f, 0xdd, 0x5a, 0x38, + 0xfc, 0x82, 0xbb, 0xe8, 0x72, 0xc5, 0x53, 0x9e, + 0xdb, 0x60, 0x9e, 0xf4, 0xf7, 0x9c, 0x20, 0x3e, + 0xbb, 0x14, 0x0f, 0x2e, 0x58, 0x3c, 0xb2, 0xad, + 0x15, 0xb4, 0xaa, 0x5b, 0x65, 0x50, 0x16, 0xa8, + 0x44, 0x92, 0x77, 0xdb, 0xd4, 0x77, 0xef, 0x2c, + 0x8d, 0x6c, 0x01, 0x7d, 0xb7, 0x38, 0xb1, 0x8d, + 0xeb, 0x4a, 0x42, 0x7d, 0x19, 0x23, 0xce, 0x3f, + 0xf2, 0x62, 0x73, 0x57, 0x79, 0xa4, 0x18, 0xf2, + 0x0a, 0x28, 0x2d, 0xf9, 0x20, 0x14, 0x7b, 0xea, + 0xbe, 0x42, 0x1e, 0xe5, 0x31, 0x9d, 0x05, 0x68, + } + }, + + /* #7, 32 byte key, 17 byte PTX */ + { + "/crypto/xts/t-7-key-32-ptx-17", + 32, + { 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, + 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0 }, + { 0xbf, 0xbe, 0xbd, 0xbc, 0xbb, 0xba, 0xb9, 0xb8, + 0xb7, 0xb6, 0xb5, 0xb4, 0xb3, 0xb2, 0xb1, 0xb0 }, + 0x123456789aLL, + 17, + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 }, + { 0x6c, 0x16, 0x25, 0xdb, 0x46, 0x71, 0x52, 0x2d, + 0x3d, 0x75, 0x99, 0x60, 0x1d, 0xe7, 0xca, 0x09, 0xed }, + }, + + /* #15, 32 byte key, 25 byte PTX */ + { + "/crypto/xts/t-15-key-32-ptx-25", + 32, + { 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, + 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0 }, + { 0xbf, 0xbe, 0xbd, 0xbc, 0xbb, 0xba, 0xb9, 0xb8, + 0xb7, 0xb6, 0xb5, 0xb4, 0xb3, 0xb2, 0xb1, 0xb0 }, + 0x123456789aLL, + 25, + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18 }, + { 0x8f, 0x4d, 0xcb, 0xad, 0x55, 0x55, 0x8d, 0x7b, + 0x4e, 0x01, 0xd9, 0x37, 0x9c, 0xd4, 0xea, 0x22, + 0xed, 0xbf, 0x9d, 0xac, 0xe4, 0x5d, 0x6f, 0x6a, 0x73 }, + }, + + /* #21, 32 byte key, 31 byte PTX */ + { + "/crypto/xts/t-21-key-32-ptx-31", + 32, + { 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, + 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0 }, + { 0xbf, 0xbe, 0xbd, 0xbc, 0xbb, 0xba, 0xb9, 0xb8, + 0xb7, 0xb6, 0xb5, 0xb4, 0xb3, 0xb2, 0xb1, 0xb0 }, + 0x123456789aLL, + 31, + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e }, + { 0xd0, 0x5b, 0xc0, 0x90, 0xa8, 0xe0, 0x4f, 0x1b, + 0x3d, 0x3e, 0xcd, 0xd5, 0xba, 0xec, 0x0f, 0xd4, + 0xed, 0xbf, 0x9d, 0xac, 0xe4, 0x5d, 0x6f, 0x6a, + 0x73, 0x06, 0xe6, 0x4b, 0xe5, 0xdd, 0x82 }, + }, +}; + +#define STORE64L(x, y) \ + do { \ + (y)[7] = (unsigned char)(((x) >> 56) & 255); \ + (y)[6] = (unsigned char)(((x) >> 48) & 255); \ + (y)[5] = (unsigned char)(((x) >> 40) & 255); \ + (y)[4] = (unsigned char)(((x) >> 32) & 255); \ + (y)[3] = (unsigned char)(((x) >> 24) & 255); \ + (y)[2] = (unsigned char)(((x) >> 16) & 255); \ + (y)[1] = (unsigned char)(((x) >> 8) & 255); \ + (y)[0] = (unsigned char)((x) & 255); \ + } while (0) + +struct TestAES { + AES_KEY enc; + AES_KEY dec; +}; + +static void test_xts_aes_encrypt(const void *ctx, + size_t length, + uint8_t *dst, + const uint8_t *src) +{ + const struct TestAES *aesctx = ctx; + + AES_encrypt(src, dst, &aesctx->enc); +} + + +static void test_xts_aes_decrypt(const void *ctx, + size_t length, + uint8_t *dst, + const uint8_t *src) +{ + const struct TestAES *aesctx = ctx; + + AES_decrypt(src, dst, &aesctx->dec); +} + + +static void test_xts(const void *opaque) +{ + const QCryptoXTSTestData *data = opaque; + unsigned char OUT[512], Torg[16], T[16]; + uint64_t seq; + int j; + unsigned long len; + struct TestAES aesdata; + struct TestAES aestweak; + + for (j = 0; j < 2; j++) { + /* skip the cases where + * the length is smaller than 2*blocklen + * or the length is not a multiple of 32 + */ + if ((j == 1) && ((data->PTLEN < 32) || (data->PTLEN % 32))) { + continue; + } + len = data->PTLEN / 2; + + AES_set_encrypt_key(data->key1, data->keylen / 2 * 8, &aesdata.enc); + AES_set_decrypt_key(data->key1, data->keylen / 2 * 8, &aesdata.dec); + AES_set_encrypt_key(data->key2, data->keylen / 2 * 8, &aestweak.enc); + AES_set_decrypt_key(data->key2, data->keylen / 2 * 8, &aestweak.dec); + + seq = data->seqnum; + STORE64L(seq, Torg); + memset(Torg + 8, 0, 8); + + memcpy(T, Torg, sizeof(T)); + if (j == 0) { + xts_encrypt(&aesdata, &aestweak, + test_xts_aes_encrypt, + test_xts_aes_decrypt, + T, data->PTLEN, OUT, data->PTX); + } else { + xts_encrypt(&aesdata, &aestweak, + test_xts_aes_encrypt, + test_xts_aes_decrypt, + T, len, OUT, data->PTX); + xts_encrypt(&aesdata, &aestweak, + test_xts_aes_encrypt, + test_xts_aes_decrypt, + T, len, &OUT[len], &data->PTX[len]); + } + + g_assert(memcmp(OUT, data->CTX, data->PTLEN) == 0); + + memcpy(T, Torg, sizeof(T)); + if (j == 0) { + xts_decrypt(&aesdata, &aestweak, + test_xts_aes_encrypt, + test_xts_aes_decrypt, + T, data->PTLEN, OUT, data->CTX); + } else { + xts_decrypt(&aesdata, &aestweak, + test_xts_aes_encrypt, + test_xts_aes_decrypt, + T, len, OUT, data->CTX); + xts_decrypt(&aesdata, &aestweak, + test_xts_aes_encrypt, + test_xts_aes_decrypt, + T, len, &OUT[len], &data->CTX[len]); + } + + g_assert(memcmp(OUT, data->PTX, data->PTLEN) == 0); + } +} + + +int main(int argc, char **argv) +{ + size_t i; + + g_test_init(&argc, &argv, NULL); + + g_assert(qcrypto_init(NULL) == 0); + + for (i = 0; i < G_N_ELEMENTS(test_data); i++) { + g_test_add_data_func(test_data[i].path, &test_data[i], test_xts); + } + + return g_test_run(); +} diff --git a/qemu/tests/test-cutils.c b/qemu/tests/test-cutils.c index 2a4556d3a..fb8f5b532 100644 --- a/qemu/tests/test-cutils.c +++ b/qemu/tests/test-cutils.c @@ -25,12 +25,10 @@ * THE SOFTWARE. */ +#include "qemu/osdep.h" #include <glib.h> -#include <errno.h> -#include <string.h> - -#include "qemu-common.h" +#include "qemu/cutils.h" static void test_parse_uint_null(void) { @@ -226,6 +224,1212 @@ static void test_parse_uint_full_correct(void) g_assert_cmpint(i, ==, 123); } +static void test_qemu_strtol_correct(void) +{ + const char *str = "12345 foo"; + char f = 'X'; + const char *endptr = &f; + long res = 999; + int err; + + err = qemu_strtol(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 12345); + g_assert(endptr == str + 5); +} + +static void test_qemu_strtol_null(void) +{ + char f = 'X'; + const char *endptr = &f; + long res = 999; + int err; + + err = qemu_strtol(NULL, &endptr, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); + g_assert(endptr == NULL); +} + +static void test_qemu_strtol_empty(void) +{ + const char *str = ""; + char f = 'X'; + const char *endptr = &f; + long res = 999; + int err; + + err = qemu_strtol(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); +} + +static void test_qemu_strtol_whitespace(void) +{ + const char *str = " \t "; + char f = 'X'; + const char *endptr = &f; + long res = 999; + int err; + + err = qemu_strtol(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); +} + +static void test_qemu_strtol_invalid(void) +{ + const char *str = " xxxx \t abc"; + char f = 'X'; + const char *endptr = &f; + long res = 999; + int err; + + err = qemu_strtol(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); +} + +static void test_qemu_strtol_trailing(void) +{ + const char *str = "123xxx"; + char f = 'X'; + const char *endptr = &f; + long res = 999; + int err; + + err = qemu_strtol(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 123); + g_assert(endptr == str + 3); +} + +static void test_qemu_strtol_octal(void) +{ + const char *str = "0123"; + char f = 'X'; + const char *endptr = &f; + long res = 999; + int err; + + err = qemu_strtol(str, &endptr, 8, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0123); + g_assert(endptr == str + strlen(str)); + + res = 999; + endptr = &f; + err = qemu_strtol(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0123); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtol_decimal(void) +{ + const char *str = "0123"; + char f = 'X'; + const char *endptr = &f; + long res = 999; + int err; + + err = qemu_strtol(str, &endptr, 10, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 123); + g_assert(endptr == str + strlen(str)); + + str = "123"; + res = 999; + endptr = &f; + err = qemu_strtol(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 123); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtol_hex(void) +{ + const char *str = "0123"; + char f = 'X'; + const char *endptr = &f; + long res = 999; + int err; + + err = qemu_strtol(str, &endptr, 16, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0x123); + g_assert(endptr == str + strlen(str)); + + str = "0x123"; + res = 999; + endptr = &f; + err = qemu_strtol(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0x123); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtol_max(void) +{ + const char *str = g_strdup_printf("%ld", LONG_MAX); + char f = 'X'; + const char *endptr = &f; + long res = 999; + int err; + + err = qemu_strtol(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, LONG_MAX); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtol_overflow(void) +{ + const char *str = "99999999999999999999999999999999999999999999"; + char f = 'X'; + const char *endptr = &f; + long res = 999; + int err; + + err = qemu_strtol(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, LONG_MAX); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtol_underflow(void) +{ + const char *str = "-99999999999999999999999999999999999999999999"; + char f = 'X'; + const char *endptr = &f; + long res = 999; + int err; + + err = qemu_strtol(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, LONG_MIN); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtol_negative(void) +{ + const char *str = " \t -321"; + char f = 'X'; + const char *endptr = &f; + long res = 999; + int err; + + err = qemu_strtol(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, -321); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtol_full_correct(void) +{ + const char *str = "123"; + long res = 999; + int err; + + err = qemu_strtol(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 123); +} + +static void test_qemu_strtol_full_null(void) +{ + char f = 'X'; + const char *endptr = &f; + long res = 999; + int err; + + err = qemu_strtol(NULL, &endptr, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); + g_assert(endptr == NULL); +} + +static void test_qemu_strtol_full_empty(void) +{ + const char *str = ""; + long res = 999L; + int err; + + err = qemu_strtol(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); +} + +static void test_qemu_strtol_full_negative(void) +{ + const char *str = " \t -321"; + long res = 999; + int err; + + err = qemu_strtol(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, -321); +} + +static void test_qemu_strtol_full_trailing(void) +{ + const char *str = "123xxx"; + long res; + int err; + + err = qemu_strtol(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); +} + +static void test_qemu_strtol_full_max(void) +{ + const char *str = g_strdup_printf("%ld", LONG_MAX); + long res; + int err; + + err = qemu_strtol(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, LONG_MAX); +} + +static void test_qemu_strtoul_correct(void) +{ + const char *str = "12345 foo"; + char f = 'X'; + const char *endptr = &f; + unsigned long res = 999; + int err; + + err = qemu_strtoul(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 12345); + g_assert(endptr == str + 5); +} + +static void test_qemu_strtoul_null(void) +{ + char f = 'X'; + const char *endptr = &f; + unsigned long res = 999; + int err; + + err = qemu_strtoul(NULL, &endptr, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); + g_assert(endptr == NULL); +} + +static void test_qemu_strtoul_empty(void) +{ + const char *str = ""; + char f = 'X'; + const char *endptr = &f; + unsigned long res = 999; + int err; + + err = qemu_strtoul(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); +} + +static void test_qemu_strtoul_whitespace(void) +{ + const char *str = " \t "; + char f = 'X'; + const char *endptr = &f; + unsigned long res = 999; + int err; + + err = qemu_strtoul(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); +} + +static void test_qemu_strtoul_invalid(void) +{ + const char *str = " xxxx \t abc"; + char f = 'X'; + const char *endptr = &f; + unsigned long res = 999; + int err; + + err = qemu_strtoul(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); +} + +static void test_qemu_strtoul_trailing(void) +{ + const char *str = "123xxx"; + char f = 'X'; + const char *endptr = &f; + unsigned long res = 999; + int err; + + err = qemu_strtoul(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 123); + g_assert(endptr == str + 3); +} + +static void test_qemu_strtoul_octal(void) +{ + const char *str = "0123"; + char f = 'X'; + const char *endptr = &f; + unsigned long res = 999; + int err; + + err = qemu_strtoul(str, &endptr, 8, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0123); + g_assert(endptr == str + strlen(str)); + + res = 999; + endptr = &f; + err = qemu_strtoul(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0123); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoul_decimal(void) +{ + const char *str = "0123"; + char f = 'X'; + const char *endptr = &f; + unsigned long res = 999; + int err; + + err = qemu_strtoul(str, &endptr, 10, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 123); + g_assert(endptr == str + strlen(str)); + + str = "123"; + res = 999; + endptr = &f; + err = qemu_strtoul(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 123); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoul_hex(void) +{ + const char *str = "0123"; + char f = 'X'; + const char *endptr = &f; + unsigned long res = 999; + int err; + + err = qemu_strtoul(str, &endptr, 16, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0x123); + g_assert(endptr == str + strlen(str)); + + str = "0x123"; + res = 999; + endptr = &f; + err = qemu_strtoul(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0x123); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoul_max(void) +{ + const char *str = g_strdup_printf("%lu", ULONG_MAX); + char f = 'X'; + const char *endptr = &f; + unsigned long res = 999; + int err; + + err = qemu_strtoul(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, ULONG_MAX); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoul_overflow(void) +{ + const char *str = "99999999999999999999999999999999999999999999"; + char f = 'X'; + const char *endptr = &f; + unsigned long res = 999; + int err; + + err = qemu_strtoul(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, ULONG_MAX); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoul_underflow(void) +{ + const char *str = "-99999999999999999999999999999999999999999999"; + char f = 'X'; + const char *endptr = &f; + unsigned long res = 999; + int err; + + err = qemu_strtoul(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, -1ul); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoul_negative(void) +{ + const char *str = " \t -321"; + char f = 'X'; + const char *endptr = &f; + unsigned long res = 999; + int err; + + err = qemu_strtoul(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, -321ul); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoul_full_correct(void) +{ + const char *str = "123"; + unsigned long res = 999; + int err; + + err = qemu_strtoul(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 123); +} + +static void test_qemu_strtoul_full_null(void) +{ + unsigned long res = 999; + int err; + + err = qemu_strtoul(NULL, NULL, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); +} + +static void test_qemu_strtoul_full_empty(void) +{ + const char *str = ""; + unsigned long res = 999; + int err; + + err = qemu_strtoul(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); +} +static void test_qemu_strtoul_full_negative(void) +{ + const char *str = " \t -321"; + unsigned long res = 999; + int err; + + err = qemu_strtoul(str, NULL, 0, &res); + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, -321ul); +} + +static void test_qemu_strtoul_full_trailing(void) +{ + const char *str = "123xxx"; + unsigned long res; + int err; + + err = qemu_strtoul(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); +} + +static void test_qemu_strtoul_full_max(void) +{ + const char *str = g_strdup_printf("%lu", ULONG_MAX); + unsigned long res = 999; + int err; + + err = qemu_strtoul(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, ULONG_MAX); +} + +static void test_qemu_strtoll_correct(void) +{ + const char *str = "12345 foo"; + char f = 'X'; + const char *endptr = &f; + int64_t res = 999; + int err; + + err = qemu_strtoll(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 12345); + g_assert(endptr == str + 5); +} + +static void test_qemu_strtoll_null(void) +{ + char f = 'X'; + const char *endptr = &f; + int64_t res = 999; + int err; + + err = qemu_strtoll(NULL, &endptr, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); + g_assert(endptr == NULL); +} + +static void test_qemu_strtoll_empty(void) +{ + const char *str = ""; + char f = 'X'; + const char *endptr = &f; + int64_t res = 999; + int err; + + err = qemu_strtoll(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); +} + +static void test_qemu_strtoll_whitespace(void) +{ + const char *str = " \t "; + char f = 'X'; + const char *endptr = &f; + int64_t res = 999; + int err; + + err = qemu_strtoll(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); +} + +static void test_qemu_strtoll_invalid(void) +{ + const char *str = " xxxx \t abc"; + char f = 'X'; + const char *endptr = &f; + int64_t res = 999; + int err; + + err = qemu_strtoll(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); +} + +static void test_qemu_strtoll_trailing(void) +{ + const char *str = "123xxx"; + char f = 'X'; + const char *endptr = &f; + int64_t res = 999; + int err; + + err = qemu_strtoll(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 123); + g_assert(endptr == str + 3); +} + +static void test_qemu_strtoll_octal(void) +{ + const char *str = "0123"; + char f = 'X'; + const char *endptr = &f; + int64_t res = 999; + int err; + + err = qemu_strtoll(str, &endptr, 8, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0123); + g_assert(endptr == str + strlen(str)); + + endptr = &f; + res = 999; + err = qemu_strtoll(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0123); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoll_decimal(void) +{ + const char *str = "0123"; + char f = 'X'; + const char *endptr = &f; + int64_t res = 999; + int err; + + err = qemu_strtoll(str, &endptr, 10, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 123); + g_assert(endptr == str + strlen(str)); + + str = "123"; + endptr = &f; + res = 999; + err = qemu_strtoll(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 123); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoll_hex(void) +{ + const char *str = "0123"; + char f = 'X'; + const char *endptr = &f; + int64_t res = 999; + int err; + + err = qemu_strtoll(str, &endptr, 16, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0x123); + g_assert(endptr == str + strlen(str)); + + str = "0x123"; + endptr = &f; + res = 999; + err = qemu_strtoll(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0x123); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoll_max(void) +{ + const char *str = g_strdup_printf("%lld", LLONG_MAX); + char f = 'X'; + const char *endptr = &f; + int64_t res = 999; + int err; + + err = qemu_strtoll(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, LLONG_MAX); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoll_overflow(void) +{ + const char *str = "99999999999999999999999999999999999999999999"; + char f = 'X'; + const char *endptr = &f; + int64_t res = 999; + int err; + + err = qemu_strtoll(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, LLONG_MAX); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoll_underflow(void) +{ + const char *str = "-99999999999999999999999999999999999999999999"; + char f = 'X'; + const char *endptr = &f; + int64_t res = 999; + int err; + + err = qemu_strtoll(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, LLONG_MIN); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoll_negative(void) +{ + const char *str = " \t -321"; + char f = 'X'; + const char *endptr = &f; + int64_t res = 999; + int err; + + err = qemu_strtoll(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, -321); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoll_full_correct(void) +{ + const char *str = "123"; + int64_t res = 999; + int err; + + err = qemu_strtoll(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 123); +} + +static void test_qemu_strtoll_full_null(void) +{ + int64_t res = 999; + int err; + + err = qemu_strtoll(NULL, NULL, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); +} + +static void test_qemu_strtoll_full_empty(void) +{ + const char *str = ""; + int64_t res = 999; + int err; + + err = qemu_strtoll(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); +} + +static void test_qemu_strtoll_full_negative(void) +{ + const char *str = " \t -321"; + int64_t res = 999; + int err; + + err = qemu_strtoll(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, -321); +} + +static void test_qemu_strtoll_full_trailing(void) +{ + const char *str = "123xxx"; + int64_t res = 999; + int err; + + err = qemu_strtoll(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); +} + +static void test_qemu_strtoll_full_max(void) +{ + + const char *str = g_strdup_printf("%lld", LLONG_MAX); + int64_t res; + int err; + + err = qemu_strtoll(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, LLONG_MAX); +} + +static void test_qemu_strtoull_correct(void) +{ + const char *str = "12345 foo"; + char f = 'X'; + const char *endptr = &f; + uint64_t res = 999; + int err; + + err = qemu_strtoull(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 12345); + g_assert(endptr == str + 5); +} + +static void test_qemu_strtoull_null(void) +{ + char f = 'X'; + const char *endptr = &f; + uint64_t res = 999; + int err; + + err = qemu_strtoull(NULL, &endptr, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); + g_assert(endptr == NULL); +} + +static void test_qemu_strtoull_empty(void) +{ + const char *str = ""; + char f = 'X'; + const char *endptr = &f; + uint64_t res = 999; + int err; + + err = qemu_strtoull(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); +} + +static void test_qemu_strtoull_whitespace(void) +{ + const char *str = " \t "; + char f = 'X'; + const char *endptr = &f; + uint64_t res = 999; + int err; + + err = qemu_strtoull(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); +} + +static void test_qemu_strtoull_invalid(void) +{ + const char *str = " xxxx \t abc"; + char f = 'X'; + const char *endptr = &f; + uint64_t res = 999; + int err; + + err = qemu_strtoull(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); +} + +static void test_qemu_strtoull_trailing(void) +{ + const char *str = "123xxx"; + char f = 'X'; + const char *endptr = &f; + uint64_t res = 999; + int err; + + err = qemu_strtoull(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 123); + g_assert(endptr == str + 3); +} + +static void test_qemu_strtoull_octal(void) +{ + const char *str = "0123"; + char f = 'X'; + const char *endptr = &f; + uint64_t res = 999; + int err; + + err = qemu_strtoull(str, &endptr, 8, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0123); + g_assert(endptr == str + strlen(str)); + + endptr = &f; + res = 999; + err = qemu_strtoull(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0123); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoull_decimal(void) +{ + const char *str = "0123"; + char f = 'X'; + const char *endptr = &f; + uint64_t res = 999; + int err; + + err = qemu_strtoull(str, &endptr, 10, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 123); + g_assert(endptr == str + strlen(str)); + + str = "123"; + endptr = &f; + res = 999; + err = qemu_strtoull(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 123); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoull_hex(void) +{ + const char *str = "0123"; + char f = 'X'; + const char *endptr = &f; + uint64_t res = 999; + int err; + + err = qemu_strtoull(str, &endptr, 16, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0x123); + g_assert(endptr == str + strlen(str)); + + str = "0x123"; + endptr = &f; + res = 999; + err = qemu_strtoull(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 0x123); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoull_max(void) +{ + const char *str = g_strdup_printf("%llu", ULLONG_MAX); + char f = 'X'; + const char *endptr = &f; + uint64_t res = 999; + int err; + + err = qemu_strtoull(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, ULLONG_MAX); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoull_overflow(void) +{ + const char *str = "99999999999999999999999999999999999999999999"; + char f = 'X'; + const char *endptr = &f; + uint64_t res = 999; + int err; + + err = qemu_strtoull(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, ULLONG_MAX); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoull_underflow(void) +{ + const char *str = "-99999999999999999999999999999999999999999999"; + char f = 'X'; + const char *endptr = &f; + uint64_t res = 999; + int err; + + err = qemu_strtoull(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, -ERANGE); + g_assert_cmpint(res, ==, -1); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoull_negative(void) +{ + const char *str = " \t -321"; + char f = 'X'; + const char *endptr = &f; + uint64_t res = 999; + int err; + + err = qemu_strtoull(str, &endptr, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, -321); + g_assert(endptr == str + strlen(str)); +} + +static void test_qemu_strtoull_full_correct(void) +{ + const char *str = "18446744073709551614"; + uint64_t res = 999; + int err; + + err = qemu_strtoull(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 18446744073709551614LLU); +} + +static void test_qemu_strtoull_full_null(void) +{ + uint64_t res = 999; + int err; + + err = qemu_strtoull(NULL, NULL, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); +} + +static void test_qemu_strtoull_full_empty(void) +{ + const char *str = ""; + uint64_t res = 999; + int err; + + err = qemu_strtoull(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); +} + +static void test_qemu_strtoull_full_negative(void) +{ + const char *str = " \t -321"; + uint64_t res = 999; + int err; + + err = qemu_strtoull(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, 18446744073709551295LLU); +} + +static void test_qemu_strtoull_full_trailing(void) +{ + const char *str = "18446744073709551614xxxxxx"; + uint64_t res = 999; + int err; + + err = qemu_strtoull(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, -EINVAL); +} + +static void test_qemu_strtoull_full_max(void) +{ + const char *str = g_strdup_printf("%lld", ULLONG_MAX); + uint64_t res = 999; + int err; + + err = qemu_strtoull(str, NULL, 0, &res); + + g_assert_cmpint(err, ==, 0); + g_assert_cmpint(res, ==, ULLONG_MAX); +} + +static void test_qemu_strtosz_simple(void) +{ + const char *str = "12345M"; + char *endptr = NULL; + int64_t res; + + res = qemu_strtosz(str, &endptr); + g_assert_cmpint(res, ==, 12345 * M_BYTE); + g_assert(endptr == str + 6); + + res = qemu_strtosz(str, NULL); + g_assert_cmpint(res, ==, 12345 * M_BYTE); +} + +static void test_qemu_strtosz_units(void) +{ + const char *none = "1"; + const char *b = "1B"; + const char *k = "1K"; + const char *m = "1M"; + const char *g = "1G"; + const char *t = "1T"; + const char *p = "1P"; + const char *e = "1E"; + int64_t res; + + /* default is M */ + res = qemu_strtosz(none, NULL); + g_assert_cmpint(res, ==, M_BYTE); + + res = qemu_strtosz(b, NULL); + g_assert_cmpint(res, ==, 1); + + res = qemu_strtosz(k, NULL); + g_assert_cmpint(res, ==, K_BYTE); + + res = qemu_strtosz(m, NULL); + g_assert_cmpint(res, ==, M_BYTE); + + res = qemu_strtosz(g, NULL); + g_assert_cmpint(res, ==, G_BYTE); + + res = qemu_strtosz(t, NULL); + g_assert_cmpint(res, ==, T_BYTE); + + res = qemu_strtosz(p, NULL); + g_assert_cmpint(res, ==, P_BYTE); + + res = qemu_strtosz(e, NULL); + g_assert_cmpint(res, ==, E_BYTE); +} + +static void test_qemu_strtosz_float(void) +{ + const char *str = "12.345M"; + int64_t res; + + res = qemu_strtosz(str, NULL); + g_assert_cmpint(res, ==, 12.345 * M_BYTE); +} + +static void test_qemu_strtosz_erange(void) +{ + const char *str = "10E"; + int64_t res; + + res = qemu_strtosz(str, NULL); + g_assert_cmpint(res, ==, -ERANGE); +} + +static void test_qemu_strtosz_suffix_unit(void) +{ + const char *str = "12345"; + int64_t res; + + res = qemu_strtosz_suffix_unit(str, NULL, + QEMU_STRTOSZ_DEFSUFFIX_KB, 1000); + g_assert_cmpint(res, ==, 12345000); +} + int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); @@ -247,5 +1451,145 @@ int main(int argc, char **argv) g_test_add_func("/cutils/parse_uint_full/correct", test_parse_uint_full_correct); + /* qemu_strtol() tests */ + g_test_add_func("/cutils/qemu_strtol/correct", test_qemu_strtol_correct); + g_test_add_func("/cutils/qemu_strtol/null", test_qemu_strtol_null); + g_test_add_func("/cutils/qemu_strtol/empty", test_qemu_strtol_empty); + g_test_add_func("/cutils/qemu_strtol/whitespace", + test_qemu_strtol_whitespace); + g_test_add_func("/cutils/qemu_strtol/invalid", test_qemu_strtol_invalid); + g_test_add_func("/cutils/qemu_strtol/trailing", test_qemu_strtol_trailing); + g_test_add_func("/cutils/qemu_strtol/octal", test_qemu_strtol_octal); + g_test_add_func("/cutils/qemu_strtol/decimal", test_qemu_strtol_decimal); + g_test_add_func("/cutils/qemu_strtol/hex", test_qemu_strtol_hex); + g_test_add_func("/cutils/qemu_strtol/max", test_qemu_strtol_max); + g_test_add_func("/cutils/qemu_strtol/overflow", test_qemu_strtol_overflow); + g_test_add_func("/cutils/qemu_strtol/underflow", + test_qemu_strtol_underflow); + g_test_add_func("/cutils/qemu_strtol/negative", test_qemu_strtol_negative); + g_test_add_func("/cutils/qemu_strtol_full/correct", + test_qemu_strtol_full_correct); + g_test_add_func("/cutils/qemu_strtol_full/null", + test_qemu_strtol_full_null); + g_test_add_func("/cutils/qemu_strtol_full/empty", + test_qemu_strtol_full_empty); + g_test_add_func("/cutils/qemu_strtol_full/negative", + test_qemu_strtol_full_negative); + g_test_add_func("/cutils/qemu_strtol_full/trailing", + test_qemu_strtol_full_trailing); + g_test_add_func("/cutils/qemu_strtol_full/max", + test_qemu_strtol_full_max); + + /* qemu_strtoul() tests */ + g_test_add_func("/cutils/qemu_strtoul/correct", test_qemu_strtoul_correct); + g_test_add_func("/cutils/qemu_strtoul/null", test_qemu_strtoul_null); + g_test_add_func("/cutils/qemu_strtoul/empty", test_qemu_strtoul_empty); + g_test_add_func("/cutils/qemu_strtoul/whitespace", + test_qemu_strtoul_whitespace); + g_test_add_func("/cutils/qemu_strtoul/invalid", test_qemu_strtoul_invalid); + g_test_add_func("/cutils/qemu_strtoul/trailing", + test_qemu_strtoul_trailing); + g_test_add_func("/cutils/qemu_strtoul/octal", test_qemu_strtoul_octal); + g_test_add_func("/cutils/qemu_strtoul/decimal", test_qemu_strtoul_decimal); + g_test_add_func("/cutils/qemu_strtoul/hex", test_qemu_strtoul_hex); + g_test_add_func("/cutils/qemu_strtoul/max", test_qemu_strtoul_max); + g_test_add_func("/cutils/qemu_strtoul/overflow", + test_qemu_strtoul_overflow); + g_test_add_func("/cutils/qemu_strtoul/underflow", + test_qemu_strtoul_underflow); + g_test_add_func("/cutils/qemu_strtoul/negative", + test_qemu_strtoul_negative); + g_test_add_func("/cutils/qemu_strtoul_full/correct", + test_qemu_strtoul_full_correct); + g_test_add_func("/cutils/qemu_strtoul_full/null", + test_qemu_strtoul_full_null); + g_test_add_func("/cutils/qemu_strtoul_full/empty", + test_qemu_strtoul_full_empty); + g_test_add_func("/cutils/qemu_strtoul_full/negative", + test_qemu_strtoul_full_negative); + g_test_add_func("/cutils/qemu_strtoul_full/trailing", + test_qemu_strtoul_full_trailing); + g_test_add_func("/cutils/qemu_strtoul_full/max", + test_qemu_strtoul_full_max); + + /* qemu_strtoll() tests */ + g_test_add_func("/cutils/qemu_strtoll/correct", test_qemu_strtoll_correct); + g_test_add_func("/cutils/qemu_strtoll/null", test_qemu_strtoll_null); + g_test_add_func("/cutils/qemu_strtoll/empty", test_qemu_strtoll_empty); + g_test_add_func("/cutils/qemu_strtoll/whitespace", + test_qemu_strtoll_whitespace); + g_test_add_func("/cutils/qemu_strtoll/invalid", test_qemu_strtoll_invalid); + g_test_add_func("/cutils/qemu_strtoll/trailing", + test_qemu_strtoll_trailing); + g_test_add_func("/cutils/qemu_strtoll/octal", test_qemu_strtoll_octal); + g_test_add_func("/cutils/qemu_strtoll/decimal", test_qemu_strtoll_decimal); + g_test_add_func("/cutils/qemu_strtoll/hex", test_qemu_strtoll_hex); + g_test_add_func("/cutils/qemu_strtoll/max", test_qemu_strtoll_max); + g_test_add_func("/cutils/qemu_strtoll/overflow", + test_qemu_strtoll_overflow); + g_test_add_func("/cutils/qemu_strtoll/underflow", + test_qemu_strtoll_underflow); + g_test_add_func("/cutils/qemu_strtoll/negative", + test_qemu_strtoll_negative); + g_test_add_func("/cutils/qemu_strtoll_full/correct", + test_qemu_strtoll_full_correct); + g_test_add_func("/cutils/qemu_strtoll_full/null", + test_qemu_strtoll_full_null); + g_test_add_func("/cutils/qemu_strtoll_full/empty", + test_qemu_strtoll_full_empty); + g_test_add_func("/cutils/qemu_strtoll_full/negative", + test_qemu_strtoll_full_negative); + g_test_add_func("/cutils/qemu_strtoll_full/trailing", + test_qemu_strtoll_full_trailing); + g_test_add_func("/cutils/qemu_strtoll_full/max", + test_qemu_strtoll_full_max); + + /* qemu_strtoull() tests */ + g_test_add_func("/cutils/qemu_strtoull/correct", + test_qemu_strtoull_correct); + g_test_add_func("/cutils/qemu_strtoull/null", + test_qemu_strtoull_null); + g_test_add_func("/cutils/qemu_strtoull/empty", test_qemu_strtoull_empty); + g_test_add_func("/cutils/qemu_strtoull/whitespace", + test_qemu_strtoull_whitespace); + g_test_add_func("/cutils/qemu_strtoull/invalid", + test_qemu_strtoull_invalid); + g_test_add_func("/cutils/qemu_strtoull/trailing", + test_qemu_strtoull_trailing); + g_test_add_func("/cutils/qemu_strtoull/octal", test_qemu_strtoull_octal); + g_test_add_func("/cutils/qemu_strtoull/decimal", + test_qemu_strtoull_decimal); + g_test_add_func("/cutils/qemu_strtoull/hex", test_qemu_strtoull_hex); + g_test_add_func("/cutils/qemu_strtoull/max", test_qemu_strtoull_max); + g_test_add_func("/cutils/qemu_strtoull/overflow", + test_qemu_strtoull_overflow); + g_test_add_func("/cutils/qemu_strtoull/underflow", + test_qemu_strtoull_underflow); + g_test_add_func("/cutils/qemu_strtoull/negative", + test_qemu_strtoull_negative); + g_test_add_func("/cutils/qemu_strtoull_full/correct", + test_qemu_strtoull_full_correct); + g_test_add_func("/cutils/qemu_strtoull_full/null", + test_qemu_strtoull_full_null); + g_test_add_func("/cutils/qemu_strtoull_full/empty", + test_qemu_strtoull_full_empty); + g_test_add_func("/cutils/qemu_strtoull_full/negative", + test_qemu_strtoull_full_negative); + g_test_add_func("/cutils/qemu_strtoull_full/trailing", + test_qemu_strtoull_full_trailing); + g_test_add_func("/cutils/qemu_strtoull_full/max", + test_qemu_strtoull_full_max); + + g_test_add_func("/cutils/strtosz/simple", + test_qemu_strtosz_simple); + g_test_add_func("/cutils/strtosz/units", + test_qemu_strtosz_units); + g_test_add_func("/cutils/strtosz/float", + test_qemu_strtosz_float); + g_test_add_func("/cutils/strtosz/erange", + test_qemu_strtosz_erange); + g_test_add_func("/cutils/strtosz/suffix-unit", + test_qemu_strtosz_suffix_unit); + return g_test_run(); } diff --git a/qemu/tests/test-filter-mirror.c b/qemu/tests/test-filter-mirror.c new file mode 100644 index 000000000..f60bf2adb --- /dev/null +++ b/qemu/tests/test-filter-mirror.c @@ -0,0 +1,93 @@ +/* + * QTest testcase for filter-mirror + * + * Copyright (c) 2016 FUJITSU LIMITED + * Author: Zhang Chen <zhangchen.fnst@cn.fujitsu.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * later. See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include <glib.h> +#include "libqtest.h" +#include "qemu/iov.h" +#include "qemu/sockets.h" +#include "qemu/error-report.h" +#include "qemu/main-loop.h" + +static void test_mirror(void) +{ +#ifndef _WIN32 +/* socketpair(PF_UNIX) which does not exist on windows */ + + int send_sock[2], recv_sock; + char *cmdline; + uint32_t ret = 0, len = 0; + char send_buf[] = "Hello! filter-mirror~"; + char sock_path[] = "filter-mirror.XXXXXX"; + char *recv_buf; + uint32_t size = sizeof(send_buf); + size = htonl(size); + + ret = socketpair(PF_UNIX, SOCK_STREAM, 0, send_sock); + g_assert_cmpint(ret, !=, -1); + + ret = mkstemp(sock_path); + g_assert_cmpint(ret, !=, -1); + + cmdline = g_strdup_printf("-netdev socket,id=qtest-bn0,fd=%d " + "-device e1000,netdev=qtest-bn0,id=qtest-e0 " + "-chardev socket,id=mirror0,path=%s,server,nowait " + "-object filter-mirror,id=qtest-f0,netdev=qtest-bn0,queue=tx,outdev=mirror0 " + , send_sock[1], sock_path); + qtest_start(cmdline); + g_free(cmdline); + + recv_sock = unix_connect(sock_path, NULL); + g_assert_cmpint(recv_sock, !=, -1); + + struct iovec iov[] = { + { + .iov_base = &size, + .iov_len = sizeof(size), + }, { + .iov_base = send_buf, + .iov_len = sizeof(send_buf), + }, + }; + + /* send a qmp command to guarantee that 'connected' is setting to true. */ + qmp("{ 'execute' : 'query-status'}"); + ret = iov_send(send_sock[0], iov, 2, 0, sizeof(size) + sizeof(send_buf)); + g_assert_cmpint(ret, ==, sizeof(send_buf) + sizeof(size)); + close(send_sock[0]); + + ret = qemu_recv(recv_sock, &len, sizeof(len), 0); + g_assert_cmpint(ret, ==, sizeof(len)); + len = ntohl(len); + + g_assert_cmpint(len, ==, sizeof(send_buf)); + recv_buf = g_malloc(len); + ret = qemu_recv(recv_sock, recv_buf, len, 0); + g_assert_cmpstr(recv_buf, ==, send_buf); + + g_free(recv_buf); + close(recv_sock); + unlink(sock_path); + +#endif +} + +int main(int argc, char **argv) +{ + int ret; + + g_test_init(&argc, &argv, NULL); + + qtest_add_func("/netfilter/mirror", test_mirror); + ret = g_test_run(); + qtest_end(); + + return ret; +} diff --git a/qemu/tests/test-filter-redirector.c b/qemu/tests/test-filter-redirector.c new file mode 100644 index 000000000..b93012cea --- /dev/null +++ b/qemu/tests/test-filter-redirector.c @@ -0,0 +1,221 @@ +/* + * QTest testcase for filter-redirector + * + * Copyright (c) 2016 FUJITSU LIMITED + * Author: Zhang Chen <zhangchen.fnst@cn.fujitsu.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * later. See the COPYING file in the top-level directory. + * + * Case 1, tx traffic flow: + * + * qemu side | test side + * | + * +---------+ | +-------+ + * | backend <---------------+ sock0 | + * +----+----+ | +-------+ + * | | + * +----v----+ +-------+ | + * | rd0 +->+chardev| | + * +---------+ +---+---+ | + * | | + * +---------+ | | + * | rd1 <------+ | + * +----+----+ | + * | | + * +----v----+ | +-------+ + * | rd2 +--------------->sock1 | + * +---------+ | +-------+ + * + + * + * -------------------------------------- + * Case 2, rx traffic flow + * qemu side | test side + * | + * +---------+ | +-------+ + * | backend +---------------> sock1 | + * +----^----+ | +-------+ + * | | + * +----+----+ +-------+ | + * | rd0 +<-+chardev| | + * +---------+ +---+---+ | + * ^ | + * +---------+ | | + * | rd1 +------+ | + * +----^----+ | + * | | + * +----+----+ | +-------+ + * | rd2 <---------------+sock0 | + * +---------+ | +-------+ + * + + */ + +#include "qemu/osdep.h" +#include <glib.h> +#include "libqtest.h" +#include "qemu/iov.h" +#include "qemu/sockets.h" +#include "qemu/error-report.h" +#include "qemu/main-loop.h" + +static void test_redirector_tx(void) +{ +#ifndef _WIN32 +/* socketpair(PF_UNIX) which does not exist on windows */ + + int backend_sock[2], recv_sock; + char *cmdline; + uint32_t ret = 0, len = 0; + char send_buf[] = "Hello!!"; + char sock_path0[] = "filter-redirector0.XXXXXX"; + char sock_path1[] = "filter-redirector1.XXXXXX"; + char *recv_buf; + uint32_t size = sizeof(send_buf); + size = htonl(size); + + ret = socketpair(PF_UNIX, SOCK_STREAM, 0, backend_sock); + g_assert_cmpint(ret, !=, -1); + + ret = mkstemp(sock_path0); + g_assert_cmpint(ret, !=, -1); + ret = mkstemp(sock_path1); + g_assert_cmpint(ret, !=, -1); + + cmdline = g_strdup_printf("-netdev socket,id=qtest-bn0,fd=%d " + "-device rtl8139,netdev=qtest-bn0,id=qtest-e0 " + "-chardev socket,id=redirector0,path=%s,server,nowait " + "-chardev socket,id=redirector1,path=%s,server,nowait " + "-chardev socket,id=redirector2,path=%s,nowait " + "-object filter-redirector,id=qtest-f0,netdev=qtest-bn0," + "queue=tx,outdev=redirector0 " + "-object filter-redirector,id=qtest-f1,netdev=qtest-bn0," + "queue=tx,indev=redirector2 " + "-object filter-redirector,id=qtest-f2,netdev=qtest-bn0," + "queue=tx,outdev=redirector1 " + , backend_sock[1], sock_path0, sock_path1, sock_path0); + qtest_start(cmdline); + g_free(cmdline); + + recv_sock = unix_connect(sock_path1, NULL); + g_assert_cmpint(recv_sock, !=, -1); + + /* send a qmp command to guarantee that 'connected' is setting to true. */ + qmp("{ 'execute' : 'query-status'}"); + + struct iovec iov[] = { + { + .iov_base = &size, + .iov_len = sizeof(size), + }, { + .iov_base = send_buf, + .iov_len = sizeof(send_buf), + }, + }; + + ret = iov_send(backend_sock[0], iov, 2, 0, sizeof(size) + sizeof(send_buf)); + g_assert_cmpint(ret, ==, sizeof(send_buf) + sizeof(size)); + close(backend_sock[0]); + + ret = qemu_recv(recv_sock, &len, sizeof(len), 0); + g_assert_cmpint(ret, ==, sizeof(len)); + len = ntohl(len); + + g_assert_cmpint(len, ==, sizeof(send_buf)); + recv_buf = g_malloc(len); + ret = qemu_recv(recv_sock, recv_buf, len, 0); + g_assert_cmpstr(recv_buf, ==, send_buf); + + g_free(recv_buf); + close(recv_sock); + unlink(sock_path0); + unlink(sock_path1); + qtest_end(); + +#endif +} + +static void test_redirector_rx(void) +{ +#ifndef _WIN32 +/* socketpair(PF_UNIX) which does not exist on windows */ + + int backend_sock[2], send_sock; + char *cmdline; + uint32_t ret = 0, len = 0; + char send_buf[] = "Hello!!"; + char sock_path0[] = "filter-redirector0.XXXXXX"; + char sock_path1[] = "filter-redirector1.XXXXXX"; + char *recv_buf; + uint32_t size = sizeof(send_buf); + size = htonl(size); + + ret = socketpair(PF_UNIX, SOCK_STREAM, 0, backend_sock); + g_assert_cmpint(ret, !=, -1); + + ret = mkstemp(sock_path0); + g_assert_cmpint(ret, !=, -1); + ret = mkstemp(sock_path1); + g_assert_cmpint(ret, !=, -1); + + cmdline = g_strdup_printf("-netdev socket,id=qtest-bn0,fd=%d " + "-device rtl8139,netdev=qtest-bn0,id=qtest-e0 " + "-chardev socket,id=redirector0,path=%s,server,nowait " + "-chardev socket,id=redirector1,path=%s,server,nowait " + "-chardev socket,id=redirector2,path=%s,nowait " + "-object filter-redirector,id=qtest-f0,netdev=qtest-bn0," + "queue=rx,indev=redirector0 " + "-object filter-redirector,id=qtest-f1,netdev=qtest-bn0," + "queue=rx,outdev=redirector2 " + "-object filter-redirector,id=qtest-f2,netdev=qtest-bn0," + "queue=rx,indev=redirector1 " + , backend_sock[1], sock_path0, sock_path1, sock_path0); + qtest_start(cmdline); + g_free(cmdline); + + struct iovec iov[] = { + { + .iov_base = &size, + .iov_len = sizeof(size), + }, { + .iov_base = send_buf, + .iov_len = sizeof(send_buf), + }, + }; + + send_sock = unix_connect(sock_path1, NULL); + g_assert_cmpint(send_sock, !=, -1); + /* send a qmp command to guarantee that 'connected' is setting to true. */ + qmp("{ 'execute' : 'query-status'}"); + + ret = iov_send(send_sock, iov, 2, 0, sizeof(size) + sizeof(send_buf)); + g_assert_cmpint(ret, ==, sizeof(send_buf) + sizeof(size)); + close(send_sock); + + ret = qemu_recv(backend_sock[0], &len, sizeof(len), 0); + g_assert_cmpint(ret, ==, sizeof(len)); + len = ntohl(len); + + g_assert_cmpint(len, ==, sizeof(send_buf)); + recv_buf = g_malloc(len); + ret = qemu_recv(backend_sock[0], recv_buf, len, 0); + g_assert_cmpstr(recv_buf, ==, send_buf); + + g_free(recv_buf); + unlink(sock_path0); + unlink(sock_path1); + qtest_end(); + +#endif +} + +int main(int argc, char **argv) +{ + int ret; + + g_test_init(&argc, &argv, NULL); + qtest_add_func("/netfilter/redirector_tx", test_redirector_tx); + qtest_add_func("/netfilter/redirector_rx", test_redirector_rx); + ret = g_test_run(); + + return ret; +} diff --git a/qemu/tests/test-hbitmap.c b/qemu/tests/test-hbitmap.c index 161eeb496..abe142791 100644 --- a/qemu/tests/test-hbitmap.c +++ b/qemu/tests/test-hbitmap.c @@ -9,10 +9,8 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <stdarg.h> -#include <string.h> -#include <sys/types.h> #include "qemu/hbitmap.h" #define LOG_BITS_PER_LONG (BITS_PER_LONG == 32 ? 5 : 6) @@ -139,10 +137,8 @@ static void hbitmap_test_teardown(TestHBitmapData *data, hbitmap_free(data->hb); data->hb = NULL; } - if (data->bits) { - g_free(data->bits); - data->bits = NULL; - } + g_free(data->bits); + data->bits = NULL; } /* Set a range in the HBitmap and in the shadow "simple" bitmap. diff --git a/qemu/tests/test-int128.c b/qemu/tests/test-int128.c index 0772ef753..cacf6beac 100644 --- a/qemu/tests/test-int128.c +++ b/qemu/tests/test-int128.c @@ -6,10 +6,9 @@ * */ +#include "qemu/osdep.h" #include <glib.h> -#include <stdio.h> #include "qemu/int128.h" -#include "qemu/osdep.h" /* clang doesn't support __noclone__ but it does have a mechanism for * telling us this. We assume that if we don't have __has_attribute() diff --git a/qemu/tests/test-io-channel-buffer.c b/qemu/tests/test-io-channel-buffer.c new file mode 100644 index 000000000..64722a214 --- /dev/null +++ b/qemu/tests/test-io-channel-buffer.c @@ -0,0 +1,51 @@ +/* + * QEMU I/O channel buffer test + * + * Copyright (c) 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "qemu/osdep.h" +#include "io/channel-buffer.h" +#include "io-channel-helpers.h" + + +static void test_io_channel_buf(void) +{ + QIOChannelBuffer *buf; + QIOChannelTest *test; + + buf = qio_channel_buffer_new(0); + + test = qio_channel_test_new(); + qio_channel_test_run_writer(test, QIO_CHANNEL(buf)); + buf->offset = 0; + qio_channel_test_run_reader(test, QIO_CHANNEL(buf)); + qio_channel_test_validate(test); + + object_unref(OBJECT(buf)); +} + + +int main(int argc, char **argv) +{ + module_call_init(MODULE_INIT_QOM); + + g_test_init(&argc, &argv, NULL); + + g_test_add_func("/io/channel/buf", test_io_channel_buf); + return g_test_run(); +} diff --git a/qemu/tests/test-io-channel-command.c b/qemu/tests/test-io-channel-command.c new file mode 100644 index 000000000..1d1f461be --- /dev/null +++ b/qemu/tests/test-io-channel-command.c @@ -0,0 +1,131 @@ +/* + * QEMU I/O channel command test + * + * Copyright (c) 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "qemu/osdep.h" +#include "io/channel-command.h" +#include "io-channel-helpers.h" +#include "qapi/error.h" + +#ifndef WIN32 +static void test_io_channel_command_fifo(bool async) +{ +#define TEST_FIFO "tests/test-io-channel-command.fifo" + QIOChannel *src, *dst; + QIOChannelTest *test; + char *srcfifo = g_strdup_printf("PIPE:%s,wronly", TEST_FIFO); + char *dstfifo = g_strdup_printf("PIPE:%s,rdonly", TEST_FIFO); + const char *srcargv[] = { + "/bin/socat", "-", srcfifo, NULL, + }; + const char *dstargv[] = { + "/bin/socat", dstfifo, "-", NULL, + }; + + unlink(TEST_FIFO); + if (access("/bin/socat", X_OK) < 0) { + return; /* Pretend success if socat is not present */ + } + if (mkfifo(TEST_FIFO, 0600) < 0) { + abort(); + } + src = QIO_CHANNEL(qio_channel_command_new_spawn(srcargv, + O_WRONLY, + &error_abort)); + dst = QIO_CHANNEL(qio_channel_command_new_spawn(dstargv, + O_RDONLY, + &error_abort)); + + test = qio_channel_test_new(); + qio_channel_test_run_threads(test, async, src, dst); + qio_channel_test_validate(test); + + object_unref(OBJECT(src)); + object_unref(OBJECT(dst)); + + g_free(srcfifo); + g_free(dstfifo); + unlink(TEST_FIFO); +} + + +static void test_io_channel_command_fifo_async(void) +{ + test_io_channel_command_fifo(true); +} + +static void test_io_channel_command_fifo_sync(void) +{ + test_io_channel_command_fifo(false); +} + + +static void test_io_channel_command_echo(bool async) +{ + QIOChannel *ioc; + QIOChannelTest *test; + const char *socatargv[] = { + "/bin/socat", "-", "-", NULL, + }; + + if (access("/bin/socat", X_OK) < 0) { + return; /* Pretend success if socat is not present */ + } + + ioc = QIO_CHANNEL(qio_channel_command_new_spawn(socatargv, + O_RDWR, + &error_abort)); + test = qio_channel_test_new(); + qio_channel_test_run_threads(test, async, ioc, ioc); + qio_channel_test_validate(test); + + object_unref(OBJECT(ioc)); +} + + +static void test_io_channel_command_echo_async(void) +{ + test_io_channel_command_echo(true); +} + +static void test_io_channel_command_echo_sync(void) +{ + test_io_channel_command_echo(false); +} +#endif + +int main(int argc, char **argv) +{ + module_call_init(MODULE_INIT_QOM); + + g_test_init(&argc, &argv, NULL); + +#ifndef WIN32 + g_test_add_func("/io/channel/command/fifo/sync", + test_io_channel_command_fifo_sync); + g_test_add_func("/io/channel/command/fifo/async", + test_io_channel_command_fifo_async); + g_test_add_func("/io/channel/command/echo/sync", + test_io_channel_command_echo_sync); + g_test_add_func("/io/channel/command/echo/async", + test_io_channel_command_echo_async); +#endif + + return g_test_run(); +} diff --git a/qemu/tests/test-io-channel-file.c b/qemu/tests/test-io-channel-file.c new file mode 100644 index 000000000..6bfede6bb --- /dev/null +++ b/qemu/tests/test-io-channel-file.c @@ -0,0 +1,123 @@ +/* + * QEMU I/O channel file test + * + * Copyright (c) 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "qemu/osdep.h" +#include "io/channel-file.h" +#include "io/channel-util.h" +#include "io-channel-helpers.h" +#include "qapi/error.h" + +static void test_io_channel_file(void) +{ + QIOChannel *src, *dst; + QIOChannelTest *test; + +#define TEST_FILE "tests/test-io-channel-file.txt" + unlink(TEST_FILE); + src = QIO_CHANNEL(qio_channel_file_new_path( + TEST_FILE, + O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0600, + &error_abort)); + dst = QIO_CHANNEL(qio_channel_file_new_path( + TEST_FILE, + O_RDONLY | O_BINARY, 0, + &error_abort)); + + test = qio_channel_test_new(); + qio_channel_test_run_writer(test, src); + qio_channel_test_run_reader(test, dst); + qio_channel_test_validate(test); + + unlink(TEST_FILE); + object_unref(OBJECT(src)); + object_unref(OBJECT(dst)); +} + + +static void test_io_channel_fd(void) +{ + QIOChannel *ioc; + int fd = -1; + +#define TEST_FILE "tests/test-io-channel-file.txt" + fd = open(TEST_FILE, O_CREAT | O_TRUNC | O_WRONLY, 0600); + g_assert_cmpint(fd, >, -1); + + ioc = qio_channel_new_fd(fd, &error_abort); + + g_assert_cmpstr(object_get_typename(OBJECT(ioc)), + ==, + TYPE_QIO_CHANNEL_FILE); + + unlink(TEST_FILE); + object_unref(OBJECT(ioc)); +} + + +#ifndef _WIN32 +static void test_io_channel_pipe(bool async) +{ + QIOChannel *src, *dst; + QIOChannelTest *test; + int fd[2]; + + if (pipe(fd) < 0) { + perror("pipe"); + abort(); + } + + src = QIO_CHANNEL(qio_channel_file_new_fd(fd[1])); + dst = QIO_CHANNEL(qio_channel_file_new_fd(fd[0])); + + test = qio_channel_test_new(); + qio_channel_test_run_threads(test, async, src, dst); + qio_channel_test_validate(test); + + object_unref(OBJECT(src)); + object_unref(OBJECT(dst)); +} + + +static void test_io_channel_pipe_async(void) +{ + test_io_channel_pipe(true); +} + +static void test_io_channel_pipe_sync(void) +{ + test_io_channel_pipe(false); +} +#endif /* ! _WIN32 */ + + +int main(int argc, char **argv) +{ + module_call_init(MODULE_INIT_QOM); + + g_test_init(&argc, &argv, NULL); + + g_test_add_func("/io/channel/file", test_io_channel_file); + g_test_add_func("/io/channel/file/fd", test_io_channel_fd); +#ifndef _WIN32 + g_test_add_func("/io/channel/pipe/sync", test_io_channel_pipe_sync); + g_test_add_func("/io/channel/pipe/async", test_io_channel_pipe_async); +#endif + return g_test_run(); +} diff --git a/qemu/tests/test-io-channel-socket.c b/qemu/tests/test-io-channel-socket.c new file mode 100644 index 000000000..855306b8d --- /dev/null +++ b/qemu/tests/test-io-channel-socket.c @@ -0,0 +1,568 @@ +/* + * QEMU I/O channel sockets test + * + * Copyright (c) 2015-2016 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "qemu/osdep.h" +#include "io/channel-socket.h" +#include "io/channel-util.h" +#include "io-channel-helpers.h" +#include "qapi/error.h" + +#ifndef AI_ADDRCONFIG +# define AI_ADDRCONFIG 0 +#endif +#ifndef EAI_ADDRFAMILY +# define EAI_ADDRFAMILY 0 +#endif + +static int check_bind(const char *hostname, bool *has_proto) +{ + int fd = -1; + struct addrinfo ai, *res = NULL; + int rc; + int ret = -1; + + memset(&ai, 0, sizeof(ai)); + ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG; + ai.ai_family = AF_UNSPEC; + ai.ai_socktype = SOCK_STREAM; + + /* lookup */ + rc = getaddrinfo(hostname, NULL, &ai, &res); + if (rc != 0) { + if (rc == EAI_ADDRFAMILY || + rc == EAI_FAMILY) { + *has_proto = false; + goto done; + } + goto cleanup; + } + + fd = qemu_socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if (fd < 0) { + goto cleanup; + } + + if (bind(fd, res->ai_addr, res->ai_addrlen) < 0) { + if (errno == EADDRNOTAVAIL) { + *has_proto = false; + goto done; + } + goto cleanup; + } + + *has_proto = true; + done: + ret = 0; + + cleanup: + if (fd != -1) { + close(fd); + } + if (res) { + freeaddrinfo(res); + } + return ret; +} + +static int check_protocol_support(bool *has_ipv4, bool *has_ipv6) +{ + if (check_bind("127.0.0.1", has_ipv4) < 0) { + return -1; + } + if (check_bind("::1", has_ipv6) < 0) { + return -1; + } + + return 0; +} + + +static void test_io_channel_set_socket_bufs(QIOChannel *src, + QIOChannel *dst) +{ + int buflen = 64 * 1024; + + /* + * Make the socket buffers small so that we see + * the effects of partial reads/writes + */ + setsockopt(((QIOChannelSocket *)src)->fd, + SOL_SOCKET, SO_SNDBUF, + (char *)&buflen, + sizeof(buflen)); + + setsockopt(((QIOChannelSocket *)dst)->fd, + SOL_SOCKET, SO_SNDBUF, + (char *)&buflen, + sizeof(buflen)); +} + + +static void test_io_channel_setup_sync(SocketAddress *listen_addr, + SocketAddress *connect_addr, + QIOChannel **src, + QIOChannel **dst) +{ + QIOChannelSocket *lioc; + + lioc = qio_channel_socket_new(); + qio_channel_socket_listen_sync(lioc, listen_addr, &error_abort); + + if (listen_addr->type == SOCKET_ADDRESS_KIND_INET) { + SocketAddress *laddr = qio_channel_socket_get_local_address( + lioc, &error_abort); + + g_free(connect_addr->u.inet.data->port); + connect_addr->u.inet.data->port = g_strdup(laddr->u.inet.data->port); + + qapi_free_SocketAddress(laddr); + } + + *src = QIO_CHANNEL(qio_channel_socket_new()); + qio_channel_socket_connect_sync( + QIO_CHANNEL_SOCKET(*src), connect_addr, &error_abort); + qio_channel_set_delay(*src, false); + + qio_channel_wait(QIO_CHANNEL(lioc), G_IO_IN); + *dst = QIO_CHANNEL(qio_channel_socket_accept(lioc, &error_abort)); + g_assert(*dst); + + test_io_channel_set_socket_bufs(*src, *dst); + + object_unref(OBJECT(lioc)); +} + + +struct TestIOChannelData { + bool err; + GMainLoop *loop; +}; + + +static void test_io_channel_complete(Object *src, + Error *err, + gpointer opaque) +{ + struct TestIOChannelData *data = opaque; + data->err = err != NULL; + g_main_loop_quit(data->loop); +} + + +static void test_io_channel_setup_async(SocketAddress *listen_addr, + SocketAddress *connect_addr, + QIOChannel **src, + QIOChannel **dst) +{ + QIOChannelSocket *lioc; + struct TestIOChannelData data; + + data.loop = g_main_loop_new(g_main_context_default(), + TRUE); + + lioc = qio_channel_socket_new(); + qio_channel_socket_listen_async( + lioc, listen_addr, + test_io_channel_complete, &data, NULL); + + g_main_loop_run(data.loop); + g_main_context_iteration(g_main_context_default(), FALSE); + + g_assert(!data.err); + + if (listen_addr->type == SOCKET_ADDRESS_KIND_INET) { + SocketAddress *laddr = qio_channel_socket_get_local_address( + lioc, &error_abort); + + g_free(connect_addr->u.inet.data->port); + connect_addr->u.inet.data->port = g_strdup(laddr->u.inet.data->port); + + qapi_free_SocketAddress(laddr); + } + + *src = QIO_CHANNEL(qio_channel_socket_new()); + + qio_channel_socket_connect_async( + QIO_CHANNEL_SOCKET(*src), connect_addr, + test_io_channel_complete, &data, NULL); + + g_main_loop_run(data.loop); + g_main_context_iteration(g_main_context_default(), FALSE); + + g_assert(!data.err); + + qio_channel_wait(QIO_CHANNEL(lioc), G_IO_IN); + *dst = QIO_CHANNEL(qio_channel_socket_accept(lioc, &error_abort)); + g_assert(*dst); + + qio_channel_set_delay(*src, false); + test_io_channel_set_socket_bufs(*src, *dst); + + object_unref(OBJECT(lioc)); + + g_main_loop_unref(data.loop); +} + + +static void test_io_channel(bool async, + SocketAddress *listen_addr, + SocketAddress *connect_addr, + bool passFD) +{ + QIOChannel *src, *dst; + QIOChannelTest *test; + if (async) { + test_io_channel_setup_async(listen_addr, connect_addr, &src, &dst); + + g_assert(!passFD || + qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS)); + g_assert(!passFD || + qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS)); + + test = qio_channel_test_new(); + qio_channel_test_run_threads(test, true, src, dst); + qio_channel_test_validate(test); + + object_unref(OBJECT(src)); + object_unref(OBJECT(dst)); + + test_io_channel_setup_async(listen_addr, connect_addr, &src, &dst); + + g_assert(!passFD || + qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS)); + g_assert(!passFD || + qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS)); + + test = qio_channel_test_new(); + qio_channel_test_run_threads(test, false, src, dst); + qio_channel_test_validate(test); + + object_unref(OBJECT(src)); + object_unref(OBJECT(dst)); + } else { + test_io_channel_setup_sync(listen_addr, connect_addr, &src, &dst); + + g_assert(!passFD || + qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS)); + g_assert(!passFD || + qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS)); + + test = qio_channel_test_new(); + qio_channel_test_run_threads(test, true, src, dst); + qio_channel_test_validate(test); + + object_unref(OBJECT(src)); + object_unref(OBJECT(dst)); + + test_io_channel_setup_sync(listen_addr, connect_addr, &src, &dst); + + g_assert(!passFD || + qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS)); + g_assert(!passFD || + qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS)); + + test = qio_channel_test_new(); + qio_channel_test_run_threads(test, false, src, dst); + qio_channel_test_validate(test); + + object_unref(OBJECT(src)); + object_unref(OBJECT(dst)); + } +} + + +static void test_io_channel_ipv4(bool async) +{ + SocketAddress *listen_addr = g_new0(SocketAddress, 1); + SocketAddress *connect_addr = g_new0(SocketAddress, 1); + + listen_addr->type = SOCKET_ADDRESS_KIND_INET; + listen_addr->u.inet.data = g_new(InetSocketAddress, 1); + *listen_addr->u.inet.data = (InetSocketAddress) { + .host = g_strdup("127.0.0.1"), + .port = NULL, /* Auto-select */ + }; + + connect_addr->type = SOCKET_ADDRESS_KIND_INET; + connect_addr->u.inet.data = g_new(InetSocketAddress, 1); + *connect_addr->u.inet.data = (InetSocketAddress) { + .host = g_strdup("127.0.0.1"), + .port = NULL, /* Filled in later */ + }; + + test_io_channel(async, listen_addr, connect_addr, false); + + qapi_free_SocketAddress(listen_addr); + qapi_free_SocketAddress(connect_addr); +} + + +static void test_io_channel_ipv4_sync(void) +{ + return test_io_channel_ipv4(false); +} + + +static void test_io_channel_ipv4_async(void) +{ + return test_io_channel_ipv4(true); +} + + +static void test_io_channel_ipv6(bool async) +{ + SocketAddress *listen_addr = g_new0(SocketAddress, 1); + SocketAddress *connect_addr = g_new0(SocketAddress, 1); + + listen_addr->type = SOCKET_ADDRESS_KIND_INET; + listen_addr->u.inet.data = g_new(InetSocketAddress, 1); + *listen_addr->u.inet.data = (InetSocketAddress) { + .host = g_strdup("::1"), + .port = NULL, /* Auto-select */ + }; + + connect_addr->type = SOCKET_ADDRESS_KIND_INET; + connect_addr->u.inet.data = g_new(InetSocketAddress, 1); + *connect_addr->u.inet.data = (InetSocketAddress) { + .host = g_strdup("::1"), + .port = NULL, /* Filled in later */ + }; + + test_io_channel(async, listen_addr, connect_addr, false); + + qapi_free_SocketAddress(listen_addr); + qapi_free_SocketAddress(connect_addr); +} + + +static void test_io_channel_ipv6_sync(void) +{ + return test_io_channel_ipv6(false); +} + + +static void test_io_channel_ipv6_async(void) +{ + return test_io_channel_ipv6(true); +} + + +#ifndef _WIN32 +static void test_io_channel_unix(bool async) +{ + SocketAddress *listen_addr = g_new0(SocketAddress, 1); + SocketAddress *connect_addr = g_new0(SocketAddress, 1); + +#define TEST_SOCKET "test-io-channel-socket.sock" + listen_addr->type = SOCKET_ADDRESS_KIND_UNIX; + listen_addr->u.q_unix.data = g_new0(UnixSocketAddress, 1); + listen_addr->u.q_unix.data->path = g_strdup(TEST_SOCKET); + + connect_addr->type = SOCKET_ADDRESS_KIND_UNIX; + connect_addr->u.q_unix.data = g_new0(UnixSocketAddress, 1); + connect_addr->u.q_unix.data->path = g_strdup(TEST_SOCKET); + + test_io_channel(async, listen_addr, connect_addr, true); + + qapi_free_SocketAddress(listen_addr); + qapi_free_SocketAddress(connect_addr); + unlink(TEST_SOCKET); +} + + +static void test_io_channel_unix_sync(void) +{ + return test_io_channel_unix(false); +} + + +static void test_io_channel_unix_async(void) +{ + return test_io_channel_unix(true); +} + +static void test_io_channel_unix_fd_pass(void) +{ + SocketAddress *listen_addr = g_new0(SocketAddress, 1); + SocketAddress *connect_addr = g_new0(SocketAddress, 1); + QIOChannel *src, *dst; + int testfd; + int fdsend[3]; + int *fdrecv = NULL; + size_t nfdrecv = 0; + size_t i; + char bufsend[12], bufrecv[12]; + struct iovec iosend[1], iorecv[1]; + +#define TEST_SOCKET "test-io-channel-socket.sock" +#define TEST_FILE "test-io-channel-socket.txt" + + testfd = open(TEST_FILE, O_RDWR|O_TRUNC|O_CREAT, 0700); + g_assert(testfd != -1); + fdsend[0] = testfd; + fdsend[1] = testfd; + fdsend[2] = testfd; + + listen_addr->type = SOCKET_ADDRESS_KIND_UNIX; + listen_addr->u.q_unix.data = g_new0(UnixSocketAddress, 1); + listen_addr->u.q_unix.data->path = g_strdup(TEST_SOCKET); + + connect_addr->type = SOCKET_ADDRESS_KIND_UNIX; + connect_addr->u.q_unix.data = g_new0(UnixSocketAddress, 1); + connect_addr->u.q_unix.data->path = g_strdup(TEST_SOCKET); + + test_io_channel_setup_sync(listen_addr, connect_addr, &src, &dst); + + memcpy(bufsend, "Hello World", G_N_ELEMENTS(bufsend)); + + iosend[0].iov_base = bufsend; + iosend[0].iov_len = G_N_ELEMENTS(bufsend); + + iorecv[0].iov_base = bufrecv; + iorecv[0].iov_len = G_N_ELEMENTS(bufrecv); + + g_assert(qio_channel_has_feature(src, QIO_CHANNEL_FEATURE_FD_PASS)); + g_assert(qio_channel_has_feature(dst, QIO_CHANNEL_FEATURE_FD_PASS)); + + qio_channel_writev_full(src, + iosend, + G_N_ELEMENTS(iosend), + fdsend, + G_N_ELEMENTS(fdsend), + &error_abort); + + qio_channel_readv_full(dst, + iorecv, + G_N_ELEMENTS(iorecv), + &fdrecv, + &nfdrecv, + &error_abort); + + g_assert(nfdrecv == G_N_ELEMENTS(fdsend)); + /* Each recvd FD should be different from sent FD */ + for (i = 0; i < nfdrecv; i++) { + g_assert_cmpint(fdrecv[i], !=, testfd); + } + /* Each recvd FD should be different from each other */ + g_assert_cmpint(fdrecv[0], !=, fdrecv[1]); + g_assert_cmpint(fdrecv[0], !=, fdrecv[2]); + g_assert_cmpint(fdrecv[1], !=, fdrecv[2]); + + /* Check the I/O buf we sent at the same time matches */ + g_assert(memcmp(bufsend, bufrecv, G_N_ELEMENTS(bufsend)) == 0); + + /* Write some data into the FD we received */ + g_assert(write(fdrecv[0], bufsend, G_N_ELEMENTS(bufsend)) == + G_N_ELEMENTS(bufsend)); + + /* Read data from the original FD and make sure it matches */ + memset(bufrecv, 0, G_N_ELEMENTS(bufrecv)); + g_assert(lseek(testfd, 0, SEEK_SET) == 0); + g_assert(read(testfd, bufrecv, G_N_ELEMENTS(bufrecv)) == + G_N_ELEMENTS(bufrecv)); + g_assert(memcmp(bufsend, bufrecv, G_N_ELEMENTS(bufsend)) == 0); + + object_unref(OBJECT(src)); + object_unref(OBJECT(dst)); + qapi_free_SocketAddress(listen_addr); + qapi_free_SocketAddress(connect_addr); + unlink(TEST_SOCKET); + unlink(TEST_FILE); + close(testfd); + for (i = 0; i < nfdrecv; i++) { + close(fdrecv[i]); + } + g_free(fdrecv); +} +#endif /* _WIN32 */ + + +static void test_io_channel_ipv4_fd(void) +{ + QIOChannel *ioc; + int fd = -1; + struct sockaddr_in sa = { + .sin_family = AF_INET, + .sin_addr = { + .s_addr = htonl(INADDR_LOOPBACK), + } + /* Leave port unset for auto-assign */ + }; + socklen_t salen = sizeof(sa); + + fd = socket(AF_INET, SOCK_STREAM, 0); + g_assert_cmpint(fd, >, -1); + + g_assert_cmpint(bind(fd, (struct sockaddr *)&sa, salen), ==, 0); + + ioc = qio_channel_new_fd(fd, &error_abort); + + g_assert_cmpstr(object_get_typename(OBJECT(ioc)), + ==, + TYPE_QIO_CHANNEL_SOCKET); + + object_unref(OBJECT(ioc)); +} + + +int main(int argc, char **argv) +{ + bool has_ipv4, has_ipv6; + + module_call_init(MODULE_INIT_QOM); + socket_init(); + + g_test_init(&argc, &argv, NULL); + + /* We're creating actual IPv4/6 sockets, so we should + * check if the host running tests actually supports + * each protocol to avoid breaking tests on machines + * with either IPv4 or IPv6 disabled. + */ + if (check_protocol_support(&has_ipv4, &has_ipv6) < 0) { + return 1; + } + + if (has_ipv4) { + g_test_add_func("/io/channel/socket/ipv4-sync", + test_io_channel_ipv4_sync); + g_test_add_func("/io/channel/socket/ipv4-async", + test_io_channel_ipv4_async); + g_test_add_func("/io/channel/socket/ipv4-fd", + test_io_channel_ipv4_fd); + } + if (has_ipv6) { + g_test_add_func("/io/channel/socket/ipv6-sync", + test_io_channel_ipv6_sync); + g_test_add_func("/io/channel/socket/ipv6-async", + test_io_channel_ipv6_async); + } + +#ifndef _WIN32 + g_test_add_func("/io/channel/socket/unix-sync", + test_io_channel_unix_sync); + g_test_add_func("/io/channel/socket/unix-async", + test_io_channel_unix_async); + g_test_add_func("/io/channel/socket/unix-fd-pass", + test_io_channel_unix_fd_pass); +#endif /* _WIN32 */ + + return g_test_run(); +} diff --git a/qemu/tests/test-io-channel-tls.c b/qemu/tests/test-io-channel-tls.c new file mode 100644 index 000000000..3c361a7be --- /dev/null +++ b/qemu/tests/test-io-channel-tls.c @@ -0,0 +1,340 @@ +/* + * QEMU I/O channel TLS test + * + * Copyright (C) 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Author: Daniel P. Berrange <berrange@redhat.com> + */ + + +#include "qemu/osdep.h" + +#include "crypto-tls-x509-helpers.h" +#include "io/channel-tls.h" +#include "io/channel-socket.h" +#include "io-channel-helpers.h" +#include "crypto/tlscredsx509.h" +#include "qemu/acl.h" +#include "qom/object_interfaces.h" + +#ifdef QCRYPTO_HAVE_TLS_TEST_SUPPORT + +#define WORKDIR "tests/test-io-channel-tls-work/" +#define KEYFILE WORKDIR "key-ctx.pem" + +struct QIOChannelTLSTestData { + const char *servercacrt; + const char *clientcacrt; + const char *servercrt; + const char *clientcrt; + bool expectServerFail; + bool expectClientFail; + const char *hostname; + const char *const *wildcards; +}; + +struct QIOChannelTLSHandshakeData { + bool finished; + bool failed; +}; + +static void test_tls_handshake_done(Object *source, + Error *err, + gpointer opaque) +{ + struct QIOChannelTLSHandshakeData *data = opaque; + + data->finished = true; + data->failed = err != NULL; +} + + +static QCryptoTLSCreds *test_tls_creds_create(QCryptoTLSCredsEndpoint endpoint, + const char *certdir, + Error **errp) +{ + Object *parent = object_get_objects_root(); + Object *creds = object_new_with_props( + TYPE_QCRYPTO_TLS_CREDS_X509, + parent, + (endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER ? + "testtlscredsserver" : "testtlscredsclient"), + errp, + "endpoint", (endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER ? + "server" : "client"), + "dir", certdir, + "verify-peer", "yes", + /* We skip initial sanity checks here because we + * want to make sure that problems are being + * detected at the TLS session validation stage, + * and the test-crypto-tlscreds test already + * validate the sanity check code. + */ + "sanity-check", "no", + NULL + ); + + if (*errp) { + return NULL; + } + return QCRYPTO_TLS_CREDS(creds); +} + + +/* + * This tests validation checking of peer certificates + * + * This is replicating the checks that are done for an + * active TLS session after handshake completes. To + * simulate that we create our TLS contexts, skipping + * sanity checks. When then get a socketpair, and + * initiate a TLS session across them. Finally do + * do actual cert validation tests + */ +static void test_io_channel_tls(const void *opaque) +{ + struct QIOChannelTLSTestData *data = + (struct QIOChannelTLSTestData *)opaque; + QCryptoTLSCreds *clientCreds; + QCryptoTLSCreds *serverCreds; + QIOChannelTLS *clientChanTLS; + QIOChannelTLS *serverChanTLS; + QIOChannelSocket *clientChanSock; + QIOChannelSocket *serverChanSock; + qemu_acl *acl; + const char * const *wildcards; + int channel[2]; + struct QIOChannelTLSHandshakeData clientHandshake = { false, false }; + struct QIOChannelTLSHandshakeData serverHandshake = { false, false }; + Error *err = NULL; + QIOChannelTest *test; + GMainContext *mainloop; + + /* We'll use this for our fake client-server connection */ + g_assert(socketpair(AF_UNIX, SOCK_STREAM, 0, channel) == 0); + +#define CLIENT_CERT_DIR "tests/test-crypto-tlssession-client/" +#define SERVER_CERT_DIR "tests/test-crypto-tlssession-server/" + mkdir(CLIENT_CERT_DIR, 0700); + mkdir(SERVER_CERT_DIR, 0700); + + unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT); + unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_CERT); + unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_KEY); + + unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT); + unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_CERT); + unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_KEY); + + g_assert(link(data->servercacrt, + SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT) == 0); + g_assert(link(data->servercrt, + SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_CERT) == 0); + g_assert(link(KEYFILE, + SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_KEY) == 0); + + g_assert(link(data->clientcacrt, + CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT) == 0); + g_assert(link(data->clientcrt, + CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_CERT) == 0); + g_assert(link(KEYFILE, + CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_KEY) == 0); + + clientCreds = test_tls_creds_create( + QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT, + CLIENT_CERT_DIR, + &err); + g_assert(clientCreds != NULL); + + serverCreds = test_tls_creds_create( + QCRYPTO_TLS_CREDS_ENDPOINT_SERVER, + SERVER_CERT_DIR, + &err); + g_assert(serverCreds != NULL); + + acl = qemu_acl_init("channeltlsacl"); + qemu_acl_reset(acl); + wildcards = data->wildcards; + while (wildcards && *wildcards) { + qemu_acl_append(acl, 0, *wildcards); + wildcards++; + } + + clientChanSock = qio_channel_socket_new_fd( + channel[0], &err); + g_assert(clientChanSock != NULL); + serverChanSock = qio_channel_socket_new_fd( + channel[1], &err); + g_assert(serverChanSock != NULL); + + /* + * We have an evil loop to do the handshake in a single + * thread, so we need these non-blocking to avoid deadlock + * of ourselves + */ + qio_channel_set_blocking(QIO_CHANNEL(clientChanSock), false, NULL); + qio_channel_set_blocking(QIO_CHANNEL(serverChanSock), false, NULL); + + /* Now the real part of the test, setup the sessions */ + clientChanTLS = qio_channel_tls_new_client( + QIO_CHANNEL(clientChanSock), clientCreds, + data->hostname, &err); + g_assert(clientChanTLS != NULL); + + serverChanTLS = qio_channel_tls_new_server( + QIO_CHANNEL(serverChanSock), serverCreds, + "channeltlsacl", &err); + g_assert(serverChanTLS != NULL); + + qio_channel_tls_handshake(clientChanTLS, + test_tls_handshake_done, + &clientHandshake, + NULL); + qio_channel_tls_handshake(serverChanTLS, + test_tls_handshake_done, + &serverHandshake, + NULL); + + /* + * Finally we loop around & around doing handshake on each + * session until we get an error, or the handshake completes. + * This relies on the socketpair being nonblocking to avoid + * deadlocking ourselves upon handshake + */ + mainloop = g_main_context_default(); + do { + g_main_context_iteration(mainloop, TRUE); + } while (!clientHandshake.finished && + !serverHandshake.finished); + + g_assert(clientHandshake.failed == data->expectClientFail); + g_assert(serverHandshake.failed == data->expectServerFail); + + test = qio_channel_test_new(); + qio_channel_test_run_threads(test, false, + QIO_CHANNEL(clientChanTLS), + QIO_CHANNEL(serverChanTLS)); + qio_channel_test_validate(test); + + test = qio_channel_test_new(); + qio_channel_test_run_threads(test, true, + QIO_CHANNEL(clientChanTLS), + QIO_CHANNEL(serverChanTLS)); + qio_channel_test_validate(test); + + unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT); + unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_CERT); + unlink(SERVER_CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_KEY); + + unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CA_CERT); + unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_CERT); + unlink(CLIENT_CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_KEY); + + rmdir(CLIENT_CERT_DIR); + rmdir(SERVER_CERT_DIR); + + object_unparent(OBJECT(serverCreds)); + object_unparent(OBJECT(clientCreds)); + + object_unref(OBJECT(serverChanTLS)); + object_unref(OBJECT(clientChanTLS)); + + object_unref(OBJECT(serverChanSock)); + object_unref(OBJECT(clientChanSock)); + + close(channel[0]); + close(channel[1]); +} + + +int main(int argc, char **argv) +{ + int ret; + + module_call_init(MODULE_INIT_QOM); + g_test_init(&argc, &argv, NULL); + setenv("GNUTLS_FORCE_FIPS_MODE", "2", 1); + + mkdir(WORKDIR, 0700); + + test_tls_init(KEYFILE); + +# define TEST_CHANNEL(name, caCrt, \ + serverCrt, clientCrt, \ + expectServerFail, expectClientFail, \ + hostname, wildcards) \ + struct QIOChannelTLSTestData name = { \ + caCrt, caCrt, serverCrt, clientCrt, \ + expectServerFail, expectClientFail, \ + hostname, wildcards \ + }; \ + g_test_add_data_func("/qio/channel/tls/" # name, \ + &name, test_io_channel_tls); + + /* A perfect CA, perfect client & perfect server */ + + /* Basic:CA:critical */ + TLS_ROOT_REQ(cacertreq, + "UK", "qemu CA", NULL, NULL, NULL, NULL, + true, true, true, + true, true, GNUTLS_KEY_KEY_CERT_SIGN, + false, false, NULL, NULL, + 0, 0); + TLS_CERT_REQ(servercertreq, cacertreq, + "UK", "qemu.org", NULL, NULL, NULL, NULL, + true, true, false, + true, true, + GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, + true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL, + 0, 0); + TLS_CERT_REQ(clientcertreq, cacertreq, + "UK", "qemu", NULL, NULL, NULL, NULL, + true, true, false, + true, true, + GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, + true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL, + 0, 0); + + const char *const wildcards[] = { + "C=UK,CN=qemu*", + NULL, + }; + TEST_CHANNEL(basic, cacertreq.filename, servercertreq.filename, + clientcertreq.filename, false, false, + "qemu.org", wildcards); + + ret = g_test_run(); + + test_tls_discard_cert(&clientcertreq); + test_tls_discard_cert(&servercertreq); + test_tls_discard_cert(&cacertreq); + + test_tls_cleanup(KEYFILE); + rmdir(WORKDIR); + + return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; +} + +#else /* ! QCRYPTO_HAVE_TLS_TEST_SUPPORT */ + +int +main(void) +{ + return EXIT_SUCCESS; +} + +#endif /* ! QCRYPTO_HAVE_TLS_TEST_SUPPORT */ diff --git a/qemu/tests/test-io-task.c b/qemu/tests/test-io-task.c new file mode 100644 index 000000000..5a9775086 --- /dev/null +++ b/qemu/tests/test-io-task.c @@ -0,0 +1,270 @@ +/* + * QEMU I/O task tests + * + * Copyright (c) 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "qemu/osdep.h" +#include <glib.h> + +#include "io/task.h" +#include "qapi/error.h" + +#define TYPE_DUMMY "qemu:dummy" + +typedef struct DummyObject DummyObject; +typedef struct DummyObjectClass DummyObjectClass; + +struct DummyObject { + Object parent; +}; + +struct DummyObjectClass { + ObjectClass parent; +}; + +static const TypeInfo dummy_info = { + .parent = TYPE_OBJECT, + .name = TYPE_DUMMY, + .instance_size = sizeof(DummyObject), + .class_size = sizeof(DummyObjectClass), +}; + +struct TestTaskData { + Object *source; + Error *err; + bool freed; +}; + + +static void task_callback(Object *source, + Error *err, + gpointer opaque) +{ + struct TestTaskData *data = opaque; + + data->source = source; + data->err = err; +} + + +static void test_task_complete(void) +{ + QIOTask *task; + Object *obj = object_new(TYPE_DUMMY); + Object *src; + struct TestTaskData data = { NULL, NULL, false }; + + task = qio_task_new(obj, task_callback, &data, NULL); + src = qio_task_get_source(task); + + qio_task_complete(task); + + g_assert(obj == src); + + object_unref(obj); + object_unref(src); + + g_assert(data.source == obj); + g_assert(data.err == NULL); + g_assert(data.freed == false); +} + + +static void task_data_free(gpointer opaque) +{ + struct TestTaskData *data = opaque; + + data->freed = true; +} + + +static void test_task_data_free(void) +{ + QIOTask *task; + Object *obj = object_new(TYPE_DUMMY); + struct TestTaskData data = { NULL, NULL, false }; + + task = qio_task_new(obj, task_callback, &data, task_data_free); + + qio_task_complete(task); + + object_unref(obj); + + g_assert(data.source == obj); + g_assert(data.err == NULL); + g_assert(data.freed == true); +} + + +static void test_task_error(void) +{ + QIOTask *task; + Object *obj = object_new(TYPE_DUMMY); + struct TestTaskData data = { NULL, NULL, false }; + Error *err = NULL; + + task = qio_task_new(obj, task_callback, &data, NULL); + + error_setg(&err, "Some error"); + + qio_task_abort(task, err); + + error_free(err); + object_unref(obj); + + g_assert(data.source == obj); + g_assert(data.err == err); + g_assert(data.freed == false); + +} + + +struct TestThreadWorkerData { + Object *source; + Error *err; + bool fail; + GThread *worker; + GThread *complete; + GMainLoop *loop; +}; + +static int test_task_thread_worker(QIOTask *task, + Error **errp, + gpointer opaque) +{ + struct TestThreadWorkerData *data = opaque; + + data->worker = g_thread_self(); + + if (data->fail) { + error_setg(errp, "Testing fail"); + return -1; + } + + return 0; +} + + +static void test_task_thread_callback(Object *source, + Error *err, + gpointer opaque) +{ + struct TestThreadWorkerData *data = opaque; + + data->source = source; + data->err = err; + + data->complete = g_thread_self(); + + g_main_loop_quit(data->loop); +} + + +static void test_task_thread_complete(void) +{ + QIOTask *task; + Object *obj = object_new(TYPE_DUMMY); + struct TestThreadWorkerData data = { 0 }; + GThread *self; + + data.loop = g_main_loop_new(g_main_context_default(), + TRUE); + + task = qio_task_new(obj, + test_task_thread_callback, + &data, + NULL); + + qio_task_run_in_thread(task, + test_task_thread_worker, + &data, + NULL); + + g_main_loop_run(data.loop); + + g_main_loop_unref(data.loop); + object_unref(obj); + + g_assert(data.source == obj); + g_assert(data.err == NULL); + + self = g_thread_self(); + + /* Make sure the test_task_thread_worker actually got + * run in a different thread */ + g_assert(data.worker != self); + + /* And that the test_task_thread_callback got rnu in + * the main loop thread (ie this one) */ + g_assert(data.complete == self); +} + + +static void test_task_thread_error(void) +{ + QIOTask *task; + Object *obj = object_new(TYPE_DUMMY); + struct TestThreadWorkerData data = { 0 }; + GThread *self; + + data.loop = g_main_loop_new(g_main_context_default(), + TRUE); + data.fail = true; + + task = qio_task_new(obj, + test_task_thread_callback, + &data, + NULL); + + qio_task_run_in_thread(task, + test_task_thread_worker, + &data, + NULL); + + g_main_loop_run(data.loop); + + g_main_loop_unref(data.loop); + object_unref(obj); + + g_assert(data.source == obj); + g_assert(data.err != NULL); + + self = g_thread_self(); + + /* Make sure the test_task_thread_worker actually got + * run in a different thread */ + g_assert(data.worker != self); + + /* And that the test_task_thread_callback got rnu in + * the main loop thread (ie this one) */ + g_assert(data.complete == self); +} + + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + module_call_init(MODULE_INIT_QOM); + type_register_static(&dummy_info); + g_test_add_func("/crypto/task/complete", test_task_complete); + g_test_add_func("/crypto/task/datafree", test_task_data_free); + g_test_add_func("/crypto/task/error", test_task_error); + g_test_add_func("/crypto/task/thread_complete", test_task_thread_complete); + g_test_add_func("/crypto/task/thread_error", test_task_thread_error); + return g_test_run(); +} diff --git a/qemu/tests/test-iov.c b/qemu/tests/test-iov.c index 46e4dddc5..3f25268dd 100644 --- a/qemu/tests/test-iov.c +++ b/qemu/tests/test-iov.c @@ -1,3 +1,4 @@ +#include "qemu/osdep.h" #include <glib.h> #include "qemu-common.h" #include "qemu/iov.h" diff --git a/qemu/tests/test-logging.c b/qemu/tests/test-logging.c new file mode 100644 index 000000000..ac8deedc9 --- /dev/null +++ b/qemu/tests/test-logging.c @@ -0,0 +1,141 @@ +/* + * logging unit-tests + * + * Copyright (C) 2016 Linaro Ltd. + * + * Author: Alex Bennée <alex.bennee@linaro.org> + * + * 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 <glib.h> + +#include "qemu-common.h" +#include "include/qemu/log.h" + +static void test_parse_range(void) +{ + qemu_set_dfilter_ranges("0x1000+0x100"); + + g_assert_false(qemu_log_in_addr_range(0xfff)); + g_assert(qemu_log_in_addr_range(0x1000)); + g_assert(qemu_log_in_addr_range(0x1001)); + g_assert(qemu_log_in_addr_range(0x10ff)); + g_assert_false(qemu_log_in_addr_range(0x1100)); + + qemu_set_dfilter_ranges("0x1000-0x100"); + + g_assert_false(qemu_log_in_addr_range(0x1001)); + g_assert(qemu_log_in_addr_range(0x1000)); + g_assert(qemu_log_in_addr_range(0x0f01)); + g_assert_false(qemu_log_in_addr_range(0x0f00)); + + qemu_set_dfilter_ranges("0x1000..0x1100"); + + g_assert_false(qemu_log_in_addr_range(0xfff)); + g_assert(qemu_log_in_addr_range(0x1000)); + g_assert(qemu_log_in_addr_range(0x1100)); + g_assert_false(qemu_log_in_addr_range(0x1101)); + + qemu_set_dfilter_ranges("0x1000..0x1000"); + + g_assert_false(qemu_log_in_addr_range(0xfff)); + g_assert(qemu_log_in_addr_range(0x1000)); + g_assert_false(qemu_log_in_addr_range(0x1001)); + + qemu_set_dfilter_ranges("0x1000+0x100,0x2100-0x100,0x3000..0x3100"); + g_assert(qemu_log_in_addr_range(0x1050)); + g_assert(qemu_log_in_addr_range(0x2050)); + g_assert(qemu_log_in_addr_range(0x3050)); +} + +#ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS +static void test_parse_invalid_range_subprocess(void) +{ + qemu_set_dfilter_ranges("0x1000+onehundred"); +} +static void test_parse_invalid_range(void) +{ + g_test_trap_subprocess("/logging/parse_invalid_range/subprocess", 0, 0); + g_test_trap_assert_failed(); + g_test_trap_assert_stdout(""); + g_test_trap_assert_stderr("*Failed to parse range in: 0x1000+onehundred\n"); +} +static void test_parse_zero_range_subprocess(void) +{ + qemu_set_dfilter_ranges("0x1000+0"); +} +static void test_parse_zero_range(void) +{ + g_test_trap_subprocess("/logging/parse_zero_range/subprocess", 0, 0); + g_test_trap_assert_failed(); + g_test_trap_assert_stdout(""); + g_test_trap_assert_stderr("*Failed to parse range in: 0x1000+0\n"); +} + +/* As the only real failure from a bad log filename path spec is + * reporting to the user we have to use the g_test_trap_subprocess + * mechanism and check no errors reported on stderr. + */ +static void test_parse_path_subprocess(void) +{ + /* All these should work without issue */ + qemu_set_log_filename("/tmp/qemu.log"); + qemu_set_log_filename("/tmp/qemu-%d.log"); + qemu_set_log_filename("/tmp/qemu.log.%d"); +} +static void test_parse_path(void) +{ + g_test_trap_subprocess ("/logging/parse_path/subprocess", 0, 0); + g_test_trap_assert_passed(); + g_test_trap_assert_stdout(""); + g_test_trap_assert_stderr(""); +} +static void test_parse_invalid_path_subprocess(void) +{ + qemu_set_log_filename("/tmp/qemu-%d%d.log"); +} +static void test_parse_invalid_path(void) +{ + g_test_trap_subprocess ("/logging/parse_invalid_path/subprocess", 0, 0); + g_test_trap_assert_passed(); + g_test_trap_assert_stdout(""); + g_test_trap_assert_stderr("Bad logfile format: /tmp/qemu-%d%d.log\n"); +} +#endif /* CONFIG_HAS_GLIB_SUBPROCESS_TESTS */ + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + g_test_add_func("/logging/parse_range", test_parse_range); +#ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS + g_test_add_func("/logging/parse_invalid_range/subprocess", test_parse_invalid_range_subprocess); + g_test_add_func("/logging/parse_invalid_range", test_parse_invalid_range); + g_test_add_func("/logging/parse_zero_range/subprocess", test_parse_zero_range_subprocess); + g_test_add_func("/logging/parse_zero_range", test_parse_zero_range); + g_test_add_func("/logging/parse_path", test_parse_path); + g_test_add_func("/logging/parse_path/subprocess", test_parse_path_subprocess); + g_test_add_func("/logging/parse_invalid_path", test_parse_invalid_path); + g_test_add_func("/logging/parse_invalid_path/subprocess", test_parse_invalid_path_subprocess); +#endif + + return g_test_run(); +} diff --git a/qemu/tests/test-mul64.c b/qemu/tests/test-mul64.c index a0a17f777..1282ec5a2 100644 --- a/qemu/tests/test-mul64.c +++ b/qemu/tests/test-mul64.c @@ -6,10 +6,9 @@ * */ +#include "qemu/osdep.h" #include <glib.h> -#include <stdint.h> #include "qemu/host-utils.h" -#include "qemu/osdep.h" typedef struct { diff --git a/qemu/tests/test-netfilter.c b/qemu/tests/test-netfilter.c new file mode 100644 index 000000000..7d105c323 --- /dev/null +++ b/qemu/tests/test-netfilter.c @@ -0,0 +1,201 @@ +/* + * QTest testcase for netfilter + * + * Copyright (c) 2015 FUJITSU LIMITED + * Author: Yang Hongyang <yanghy@cn.fujitsu.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * later. See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include <glib.h> +#include "libqtest.h" + +/* add a netfilter to a netdev and then remove it */ +static void add_one_netfilter(void) +{ + QDict *response; + + response = qmp("{'execute': 'object-add'," + " 'arguments': {" + " 'qom-type': 'filter-buffer'," + " 'id': 'qtest-f0'," + " 'props': {" + " 'netdev': 'qtest-bn0'," + " 'queue': 'rx'," + " 'interval': 1000" + "}}}"); + + g_assert(response); + g_assert(!qdict_haskey(response, "error")); + QDECREF(response); + + response = qmp("{'execute': 'object-del'," + " 'arguments': {" + " 'id': 'qtest-f0'" + "}}"); + g_assert(response); + g_assert(!qdict_haskey(response, "error")); + QDECREF(response); +} + +/* add a netfilter to a netdev and then remove the netdev */ +static void remove_netdev_with_one_netfilter(void) +{ + QDict *response; + + response = qmp("{'execute': 'object-add'," + " 'arguments': {" + " 'qom-type': 'filter-buffer'," + " 'id': 'qtest-f0'," + " 'props': {" + " 'netdev': 'qtest-bn0'," + " 'queue': 'rx'," + " 'interval': 1000" + "}}}"); + + g_assert(response); + g_assert(!qdict_haskey(response, "error")); + QDECREF(response); + + response = qmp("{'execute': 'netdev_del'," + " 'arguments': {" + " 'id': 'qtest-bn0'" + "}}"); + g_assert(response); + g_assert(!qdict_haskey(response, "error")); + QDECREF(response); + + /* add back the netdev */ + response = qmp("{'execute': 'netdev_add'," + " 'arguments': {" + " 'type': 'user'," + " 'id': 'qtest-bn0'" + "}}"); + g_assert(response); + g_assert(!qdict_haskey(response, "error")); + QDECREF(response); +} + +/* add multi(2) netfilters to a netdev and then remove them */ +static void add_multi_netfilter(void) +{ + QDict *response; + + response = qmp("{'execute': 'object-add'," + " 'arguments': {" + " 'qom-type': 'filter-buffer'," + " 'id': 'qtest-f0'," + " 'props': {" + " 'netdev': 'qtest-bn0'," + " 'queue': 'rx'," + " 'interval': 1000" + "}}}"); + + g_assert(response); + g_assert(!qdict_haskey(response, "error")); + QDECREF(response); + + response = qmp("{'execute': 'object-add'," + " 'arguments': {" + " 'qom-type': 'filter-buffer'," + " 'id': 'qtest-f1'," + " 'props': {" + " 'netdev': 'qtest-bn0'," + " 'queue': 'rx'," + " 'interval': 1000" + "}}}"); + + g_assert(response); + g_assert(!qdict_haskey(response, "error")); + QDECREF(response); + + response = qmp("{'execute': 'object-del'," + " 'arguments': {" + " 'id': 'qtest-f0'" + "}}"); + g_assert(response); + g_assert(!qdict_haskey(response, "error")); + QDECREF(response); + + response = qmp("{'execute': 'object-del'," + " 'arguments': {" + " 'id': 'qtest-f1'" + "}}"); + g_assert(response); + g_assert(!qdict_haskey(response, "error")); + QDECREF(response); +} + +/* add multi(2) netfilters to a netdev and then remove the netdev */ +static void remove_netdev_with_multi_netfilter(void) +{ + QDict *response; + + response = qmp("{'execute': 'object-add'," + " 'arguments': {" + " 'qom-type': 'filter-buffer'," + " 'id': 'qtest-f0'," + " 'props': {" + " 'netdev': 'qtest-bn0'," + " 'queue': 'rx'," + " 'interval': 1000" + "}}}"); + + g_assert(response); + g_assert(!qdict_haskey(response, "error")); + QDECREF(response); + + response = qmp("{'execute': 'object-add'," + " 'arguments': {" + " 'qom-type': 'filter-buffer'," + " 'id': 'qtest-f1'," + " 'props': {" + " 'netdev': 'qtest-bn0'," + " 'queue': 'rx'," + " 'interval': 1000" + "}}}"); + + g_assert(response); + g_assert(!qdict_haskey(response, "error")); + QDECREF(response); + + response = qmp("{'execute': 'netdev_del'," + " 'arguments': {" + " 'id': 'qtest-bn0'" + "}}"); + g_assert(response); + g_assert(!qdict_haskey(response, "error")); + QDECREF(response); + + /* add back the netdev */ + response = qmp("{'execute': 'netdev_add'," + " 'arguments': {" + " 'type': 'user'," + " 'id': 'qtest-bn0'" + "}}"); + g_assert(response); + g_assert(!qdict_haskey(response, "error")); + QDECREF(response); +} + +int main(int argc, char **argv) +{ + int ret; + + g_test_init(&argc, &argv, NULL); + qtest_add_func("/netfilter/addremove_one", add_one_netfilter); + qtest_add_func("/netfilter/remove_netdev_one", + remove_netdev_with_one_netfilter); + qtest_add_func("/netfilter/addremove_multi", add_multi_netfilter); + qtest_add_func("/netfilter/remove_netdev_multi", + remove_netdev_with_multi_netfilter); + + qtest_start("-netdev user,id=qtest-bn0 -device e1000,netdev=qtest-bn0"); + ret = g_test_run(); + + qtest_end(); + + return ret; +} diff --git a/qemu/tests/test-opts-visitor.c b/qemu/tests/test-opts-visitor.c index 1c753d982..008e67738 100644 --- a/qemu/tests/test-opts-visitor.c +++ b/qemu/tests/test-opts-visitor.c @@ -10,13 +10,14 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> #include "qemu/config-file.h" /* qemu_add_opts() */ #include "qemu/option.h" /* qemu_opts_parse() */ +#include "qapi/error.h" #include "qapi/opts-visitor.h" /* opts_visitor_new() */ #include "test-qapi-visit.h" /* visit_type_UserDefOptions() */ -#include "qapi/dealloc-visitor.h" /* qapi_dealloc_visitor_new() */ static QemuOptsList userdef_opts = { .name = "userdef", @@ -44,7 +45,7 @@ setup_fixture(OptsVisitorFixture *f, gconstpointer test_data) g_assert(opts != NULL); ov = opts_visitor_new(opts); - visit_type_UserDefOptions(opts_get_visitor(ov), &f->userdef, NULL, + visit_type_UserDefOptions(opts_get_visitor(ov), NULL, &f->userdef, &f->err); opts_visitor_cleanup(ov); qemu_opts_del(opts); @@ -54,14 +55,7 @@ setup_fixture(OptsVisitorFixture *f, gconstpointer test_data) static void teardown_fixture(OptsVisitorFixture *f, gconstpointer test_data) { - if (f->userdef != NULL) { - QapiDeallocVisitor *dv; - - dv = qapi_dealloc_visitor_new(); - visit_type_UserDefOptions(qapi_dealloc_get_visitor(dv), &f->userdef, - NULL, NULL); - qapi_dealloc_visitor_cleanup(dv); - } + qapi_free_UserDefOptions(f->userdef); error_free(f->err); } diff --git a/qemu/tests/test-qdev-global-props.c b/qemu/tests/test-qdev-global-props.c index 0be98355c..f0cc31e11 100644 --- a/qemu/tests/test-qdev-global-props.c +++ b/qemu/tests/test-qdev-global-props.c @@ -22,8 +22,8 @@ * THE SOFTWARE. */ +#include "qemu/osdep.h" #include <glib.h> -#include <stdint.h> #include "hw/qdev.h" #include "qom/object.h" @@ -116,26 +116,20 @@ static void test_static_globalprop(void) #define TYPE_UNUSED_HOTPLUG "hotplug-type" #define TYPE_UNUSED_NOHOTPLUG "nohotplug-type" -static void prop1_accessor(Object *obj, - Visitor *v, - void *opaque, - const char *name, - Error **errp) +static void prop1_accessor(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) { MyType *mt = DYNAMIC_TYPE(obj); - visit_type_uint32(v, &mt->prop1, name, errp); + visit_type_uint32(v, name, &mt->prop1, errp); } -static void prop2_accessor(Object *obj, - Visitor *v, - void *opaque, - const char *name, - Error **errp) +static void prop2_accessor(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) { MyType *mt = DYNAMIC_TYPE(obj); - visit_type_uint32(v, &mt->prop2, name, errp); + visit_type_uint32(v, name, &mt->prop2, errp); } static void dynamic_instance_init(Object *obj) diff --git a/qemu/tests/test-qemu-opts.c b/qemu/tests/test-qemu-opts.c index 0c1136d1b..32abed5ea 100644 --- a/qemu/tests/test-qemu-opts.c +++ b/qemu/tests/test-qemu-opts.c @@ -7,12 +7,12 @@ * See the COPYING.LIB file in the top-level directory. */ +#include "qemu/osdep.h" #include "qapi/error.h" #include "qapi/qmp/qstring.h" #include "qemu/config-file.h" #include <glib.h> -#include <string.h> static QemuOptsList opts_list_01 = { .name = "opts_list_01", diff --git a/qemu/tests/test-qga.c b/qemu/tests/test-qga.c new file mode 100644 index 000000000..72a89dec2 --- /dev/null +++ b/qemu/tests/test-qga.c @@ -0,0 +1,869 @@ +#include "qemu/osdep.h" +#include <locale.h> +#include <glib.h> +#include <glib/gstdio.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include "libqtest.h" + +typedef struct { + char *test_dir; + GMainLoop *loop; + int fd; + GPid pid; +} TestFixture; + +static int connect_qga(char *path) +{ + int s, ret, len, i = 0; + struct sockaddr_un remote; + + s = socket(AF_UNIX, SOCK_STREAM, 0); + g_assert(s != -1); + + remote.sun_family = AF_UNIX; + do { + strcpy(remote.sun_path, path); + len = strlen(remote.sun_path) + sizeof(remote.sun_family); + ret = connect(s, (struct sockaddr *)&remote, len); + if (ret == -1) { + g_usleep(G_USEC_PER_SEC); + } + if (i++ == 10) { + return -1; + } + } while (ret == -1); + + return s; +} + +static void qga_watch(GPid pid, gint status, gpointer user_data) +{ + TestFixture *fixture = user_data; + + g_assert_cmpint(status, ==, 0); + g_main_loop_quit(fixture->loop); +} + +static void +fixture_setup(TestFixture *fixture, gconstpointer data) +{ + const gchar *extra_arg = data; + GError *error = NULL; + gchar *cwd, *path, *cmd, **argv = NULL; + + fixture->loop = g_main_loop_new(NULL, FALSE); + + fixture->test_dir = g_strdup("/tmp/qgatest.XXXXXX"); + g_assert_nonnull(mkdtemp(fixture->test_dir)); + + path = g_build_filename(fixture->test_dir, "sock", NULL); + cwd = g_get_current_dir(); + cmd = g_strdup_printf("%s%cqemu-ga -m unix-listen -t %s -p %s %s %s", + cwd, G_DIR_SEPARATOR, + fixture->test_dir, path, + getenv("QTEST_LOG") ? "-v" : "", + extra_arg ?: ""); + g_shell_parse_argv(cmd, NULL, &argv, &error); + g_assert_no_error(error); + + g_spawn_async(fixture->test_dir, argv, NULL, + G_SPAWN_SEARCH_PATH|G_SPAWN_DO_NOT_REAP_CHILD, + NULL, NULL, &fixture->pid, &error); + g_assert_no_error(error); + + g_child_watch_add(fixture->pid, qga_watch, fixture); + + fixture->fd = connect_qga(path); + g_assert_cmpint(fixture->fd, !=, -1); + + g_strfreev(argv); + g_free(cmd); + g_free(cwd); + g_free(path); +} + +static void +fixture_tear_down(TestFixture *fixture, gconstpointer data) +{ + gchar *tmp; + + kill(fixture->pid, SIGTERM); + + g_main_loop_run(fixture->loop); + g_main_loop_unref(fixture->loop); + + g_spawn_close_pid(fixture->pid); + + tmp = g_build_filename(fixture->test_dir, "foo", NULL); + g_unlink(tmp); + g_free(tmp); + + tmp = g_build_filename(fixture->test_dir, "qga.state", NULL); + g_unlink(tmp); + g_free(tmp); + + tmp = g_build_filename(fixture->test_dir, "sock", NULL); + g_unlink(tmp); + g_free(tmp); + + g_rmdir(fixture->test_dir); + g_free(fixture->test_dir); +} + +static void qmp_assertion_message_error(const char *domain, + const char *file, + int line, + const char *func, + const char *expr, + QDict *dict) +{ + const char *class, *desc; + char *s; + QDict *error; + + error = qdict_get_qdict(dict, "error"); + class = qdict_get_try_str(error, "class"); + desc = qdict_get_try_str(error, "desc"); + + s = g_strdup_printf("assertion failed %s: %s %s", expr, class, desc); + g_assertion_message(domain, file, line, func, s); + g_free(s); +} + +#define qmp_assert_no_error(err) do { \ + if (qdict_haskey(err, "error")) { \ + qmp_assertion_message_error(G_LOG_DOMAIN, __FILE__, __LINE__, \ + G_STRFUNC, #err, err); \ + } \ +} while (0) + +static void test_qga_sync_delimited(gconstpointer fix) +{ + const TestFixture *fixture = fix; + guint32 v, r = g_random_int(); + unsigned char c; + QDict *ret; + gchar *cmd; + + cmd = g_strdup_printf("%c{'execute': 'guest-sync-delimited'," + " 'arguments': {'id': %u } }", 0xff, r); + qmp_fd_send(fixture->fd, cmd); + g_free(cmd); + + v = read(fixture->fd, &c, 1); + g_assert_cmpint(v, ==, 1); + g_assert_cmpint(c, ==, 0xff); + + ret = qmp_fd_receive(fixture->fd); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + + v = qdict_get_int(ret, "return"); + g_assert_cmpint(r, ==, v); + + QDECREF(ret); +} + +static void test_qga_sync(gconstpointer fix) +{ + const TestFixture *fixture = fix; + guint32 v, r = g_random_int(); + QDict *ret; + gchar *cmd; + + cmd = g_strdup_printf("%c{'execute': 'guest-sync'," + " 'arguments': {'id': %u } }", 0xff, r); + ret = qmp_fd(fixture->fd, cmd); + g_free(cmd); + + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + + v = qdict_get_int(ret, "return"); + g_assert_cmpint(r, ==, v); + + QDECREF(ret); +} + +static void test_qga_ping(gconstpointer fix) +{ + const TestFixture *fixture = fix; + QDict *ret; + + ret = qmp_fd(fixture->fd, "{'execute': 'guest-ping'}"); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + + QDECREF(ret); +} + +static void test_qga_invalid_cmd(gconstpointer fix) +{ + const TestFixture *fixture = fix; + QDict *ret, *error; + const gchar *class, *desc; + + ret = qmp_fd(fixture->fd, "{'execute': 'guest-invalid-cmd'}"); + g_assert_nonnull(ret); + + error = qdict_get_qdict(ret, "error"); + class = qdict_get_try_str(error, "class"); + desc = qdict_get_try_str(error, "desc"); + + g_assert_cmpstr(class, ==, "CommandNotFound"); + g_assert_cmpint(strlen(desc), >, 0); + + QDECREF(ret); +} + +static void test_qga_info(gconstpointer fix) +{ + const TestFixture *fixture = fix; + QDict *ret, *val; + const gchar *version; + + ret = qmp_fd(fixture->fd, "{'execute': 'guest-info'}"); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + + val = qdict_get_qdict(ret, "return"); + version = qdict_get_try_str(val, "version"); + g_assert_cmpstr(version, ==, QEMU_VERSION); + + QDECREF(ret); +} + +static void test_qga_get_vcpus(gconstpointer fix) +{ + const TestFixture *fixture = fix; + QDict *ret; + QList *list; + const QListEntry *entry; + + ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-vcpus'}"); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + + /* check there is at least a cpu */ + list = qdict_get_qlist(ret, "return"); + entry = qlist_first(list); + g_assert(qdict_haskey(qobject_to_qdict(entry->value), "online")); + g_assert(qdict_haskey(qobject_to_qdict(entry->value), "logical-id")); + + QDECREF(ret); +} + +static void test_qga_get_fsinfo(gconstpointer fix) +{ + const TestFixture *fixture = fix; + QDict *ret; + QList *list; + const QListEntry *entry; + + ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-fsinfo'}"); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + + /* sanity-check the response if there are any filesystems */ + list = qdict_get_qlist(ret, "return"); + entry = qlist_first(list); + if (entry) { + g_assert(qdict_haskey(qobject_to_qdict(entry->value), "name")); + g_assert(qdict_haskey(qobject_to_qdict(entry->value), "mountpoint")); + g_assert(qdict_haskey(qobject_to_qdict(entry->value), "type")); + g_assert(qdict_haskey(qobject_to_qdict(entry->value), "disk")); + } + + QDECREF(ret); +} + +static void test_qga_get_memory_block_info(gconstpointer fix) +{ + const TestFixture *fixture = fix; + QDict *ret, *val; + int64_t size; + + ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-memory-block-info'}"); + g_assert_nonnull(ret); + + /* some systems might not expose memory block info in sysfs */ + if (!qdict_haskey(ret, "error")) { + /* check there is at least some memory */ + val = qdict_get_qdict(ret, "return"); + size = qdict_get_int(val, "size"); + g_assert_cmpint(size, >, 0); + } + + QDECREF(ret); +} + +static void test_qga_get_memory_blocks(gconstpointer fix) +{ + const TestFixture *fixture = fix; + QDict *ret; + QList *list; + const QListEntry *entry; + + ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-memory-blocks'}"); + g_assert_nonnull(ret); + + /* some systems might not expose memory block info in sysfs */ + if (!qdict_haskey(ret, "error")) { + list = qdict_get_qlist(ret, "return"); + entry = qlist_first(list); + /* newer versions of qga may return empty list without error */ + if (entry) { + g_assert(qdict_haskey(qobject_to_qdict(entry->value), "phys-index")); + g_assert(qdict_haskey(qobject_to_qdict(entry->value), "online")); + } + } + + QDECREF(ret); +} + +static void test_qga_network_get_interfaces(gconstpointer fix) +{ + const TestFixture *fixture = fix; + QDict *ret; + QList *list; + const QListEntry *entry; + + ret = qmp_fd(fixture->fd, "{'execute': 'guest-network-get-interfaces'}"); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + + /* check there is at least an interface */ + list = qdict_get_qlist(ret, "return"); + entry = qlist_first(list); + g_assert(qdict_haskey(qobject_to_qdict(entry->value), "name")); + + QDECREF(ret); +} + +static void test_qga_file_ops(gconstpointer fix) +{ + const TestFixture *fixture = fix; + const unsigned char helloworld[] = "Hello World!\n"; + const char *b64; + gchar *cmd, *path, *enc; + unsigned char *dec; + QDict *ret, *val; + int64_t id, eof; + gsize count; + FILE *f; + char tmp[100]; + + /* open */ + ret = qmp_fd(fixture->fd, "{'execute': 'guest-file-open'," + " 'arguments': { 'path': 'foo', 'mode': 'w+' } }"); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + id = qdict_get_int(ret, "return"); + QDECREF(ret); + + enc = g_base64_encode(helloworld, sizeof(helloworld)); + /* write */ + cmd = g_strdup_printf("{'execute': 'guest-file-write'," + " 'arguments': { 'handle': %" PRId64 "," + " 'buf-b64': '%s' } }", id, enc); + ret = qmp_fd(fixture->fd, cmd); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + + val = qdict_get_qdict(ret, "return"); + count = qdict_get_int(val, "count"); + eof = qdict_get_bool(val, "eof"); + g_assert_cmpint(count, ==, sizeof(helloworld)); + g_assert_cmpint(eof, ==, 0); + QDECREF(ret); + g_free(cmd); + + /* flush */ + cmd = g_strdup_printf("{'execute': 'guest-file-flush'," + " 'arguments': {'handle': %" PRId64 "} }", + id); + ret = qmp_fd(fixture->fd, cmd); + QDECREF(ret); + g_free(cmd); + + /* close */ + cmd = g_strdup_printf("{'execute': 'guest-file-close'," + " 'arguments': {'handle': %" PRId64 "} }", + id); + ret = qmp_fd(fixture->fd, cmd); + QDECREF(ret); + g_free(cmd); + + /* check content */ + path = g_build_filename(fixture->test_dir, "foo", NULL); + f = fopen(path, "r"); + g_assert_nonnull(f); + count = fread(tmp, 1, sizeof(tmp), f); + g_assert_cmpint(count, ==, sizeof(helloworld)); + tmp[count] = 0; + g_assert_cmpstr(tmp, ==, (char *)helloworld); + fclose(f); + + /* open */ + ret = qmp_fd(fixture->fd, "{'execute': 'guest-file-open'," + " 'arguments': { 'path': 'foo', 'mode': 'r' } }"); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + id = qdict_get_int(ret, "return"); + QDECREF(ret); + + /* read */ + cmd = g_strdup_printf("{'execute': 'guest-file-read'," + " 'arguments': { 'handle': %" PRId64 "} }", + id); + ret = qmp_fd(fixture->fd, cmd); + val = qdict_get_qdict(ret, "return"); + count = qdict_get_int(val, "count"); + eof = qdict_get_bool(val, "eof"); + b64 = qdict_get_str(val, "buf-b64"); + g_assert_cmpint(count, ==, sizeof(helloworld)); + g_assert(eof); + g_assert_cmpstr(b64, ==, enc); + + QDECREF(ret); + g_free(cmd); + g_free(enc); + + /* read eof */ + cmd = g_strdup_printf("{'execute': 'guest-file-read'," + " 'arguments': { 'handle': %" PRId64 "} }", + id); + ret = qmp_fd(fixture->fd, cmd); + val = qdict_get_qdict(ret, "return"); + count = qdict_get_int(val, "count"); + eof = qdict_get_bool(val, "eof"); + b64 = qdict_get_str(val, "buf-b64"); + g_assert_cmpint(count, ==, 0); + g_assert(eof); + g_assert_cmpstr(b64, ==, ""); + QDECREF(ret); + g_free(cmd); + + /* seek */ + cmd = g_strdup_printf("{'execute': 'guest-file-seek'," + " 'arguments': { 'handle': %" PRId64 ", " + " 'offset': %d, 'whence': '%s' } }", + id, 6, "set"); + ret = qmp_fd(fixture->fd, cmd); + qmp_assert_no_error(ret); + val = qdict_get_qdict(ret, "return"); + count = qdict_get_int(val, "position"); + eof = qdict_get_bool(val, "eof"); + g_assert_cmpint(count, ==, 6); + g_assert(!eof); + QDECREF(ret); + g_free(cmd); + + /* partial read */ + cmd = g_strdup_printf("{'execute': 'guest-file-read'," + " 'arguments': { 'handle': %" PRId64 "} }", + id); + ret = qmp_fd(fixture->fd, cmd); + val = qdict_get_qdict(ret, "return"); + count = qdict_get_int(val, "count"); + eof = qdict_get_bool(val, "eof"); + b64 = qdict_get_str(val, "buf-b64"); + g_assert_cmpint(count, ==, sizeof(helloworld) - 6); + g_assert(eof); + dec = g_base64_decode(b64, &count); + g_assert_cmpint(count, ==, sizeof(helloworld) - 6); + g_assert_cmpmem(dec, count, helloworld + 6, sizeof(helloworld) - 6); + g_free(dec); + + QDECREF(ret); + g_free(cmd); + + /* close */ + cmd = g_strdup_printf("{'execute': 'guest-file-close'," + " 'arguments': {'handle': %" PRId64 "} }", + id); + ret = qmp_fd(fixture->fd, cmd); + QDECREF(ret); + g_free(cmd); +} + +static void test_qga_file_write_read(gconstpointer fix) +{ + const TestFixture *fixture = fix; + const unsigned char helloworld[] = "Hello World!\n"; + const char *b64; + gchar *cmd, *enc; + QDict *ret, *val; + int64_t id, eof; + gsize count; + + /* open */ + ret = qmp_fd(fixture->fd, "{'execute': 'guest-file-open'," + " 'arguments': { 'path': 'foo', 'mode': 'w+' } }"); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + id = qdict_get_int(ret, "return"); + QDECREF(ret); + + enc = g_base64_encode(helloworld, sizeof(helloworld)); + /* write */ + cmd = g_strdup_printf("{'execute': 'guest-file-write'," + " 'arguments': { 'handle': %" PRId64 "," + " 'buf-b64': '%s' } }", id, enc); + ret = qmp_fd(fixture->fd, cmd); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + + val = qdict_get_qdict(ret, "return"); + count = qdict_get_int(val, "count"); + eof = qdict_get_bool(val, "eof"); + g_assert_cmpint(count, ==, sizeof(helloworld)); + g_assert_cmpint(eof, ==, 0); + QDECREF(ret); + g_free(cmd); + + /* read (check implicit flush) */ + cmd = g_strdup_printf("{'execute': 'guest-file-read'," + " 'arguments': { 'handle': %" PRId64 "} }", + id); + ret = qmp_fd(fixture->fd, cmd); + val = qdict_get_qdict(ret, "return"); + count = qdict_get_int(val, "count"); + eof = qdict_get_bool(val, "eof"); + b64 = qdict_get_str(val, "buf-b64"); + g_assert_cmpint(count, ==, 0); + g_assert(eof); + g_assert_cmpstr(b64, ==, ""); + QDECREF(ret); + g_free(cmd); + + /* seek to 0 */ + cmd = g_strdup_printf("{'execute': 'guest-file-seek'," + " 'arguments': { 'handle': %" PRId64 ", " + " 'offset': %d, 'whence': '%s' } }", + id, 0, "set"); + ret = qmp_fd(fixture->fd, cmd); + qmp_assert_no_error(ret); + val = qdict_get_qdict(ret, "return"); + count = qdict_get_int(val, "position"); + eof = qdict_get_bool(val, "eof"); + g_assert_cmpint(count, ==, 0); + g_assert(!eof); + QDECREF(ret); + g_free(cmd); + + /* read */ + cmd = g_strdup_printf("{'execute': 'guest-file-read'," + " 'arguments': { 'handle': %" PRId64 "} }", + id); + ret = qmp_fd(fixture->fd, cmd); + val = qdict_get_qdict(ret, "return"); + count = qdict_get_int(val, "count"); + eof = qdict_get_bool(val, "eof"); + b64 = qdict_get_str(val, "buf-b64"); + g_assert_cmpint(count, ==, sizeof(helloworld)); + g_assert(eof); + g_assert_cmpstr(b64, ==, enc); + QDECREF(ret); + g_free(cmd); + g_free(enc); + + /* close */ + cmd = g_strdup_printf("{'execute': 'guest-file-close'," + " 'arguments': {'handle': %" PRId64 "} }", + id); + ret = qmp_fd(fixture->fd, cmd); + QDECREF(ret); + g_free(cmd); +} + +static void test_qga_get_time(gconstpointer fix) +{ + const TestFixture *fixture = fix; + QDict *ret; + int64_t time; + + ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-time'}"); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + + time = qdict_get_int(ret, "return"); + g_assert_cmpint(time, >, 0); + + QDECREF(ret); +} + +static void test_qga_set_time(gconstpointer fix) +{ + const TestFixture *fixture = fix; + QDict *ret; + int64_t current, time; + gchar *cmd; + + /* get current time */ + ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-time'}"); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + current = qdict_get_int(ret, "return"); + g_assert_cmpint(current, >, 0); + QDECREF(ret); + + /* set some old time */ + ret = qmp_fd(fixture->fd, "{'execute': 'guest-set-time'," + " 'arguments': { 'time': 1000 } }"); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + QDECREF(ret); + + /* check old time */ + ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-time'}"); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + time = qdict_get_int(ret, "return"); + g_assert_cmpint(time / 1000, <, G_USEC_PER_SEC * 10); + QDECREF(ret); + + /* set back current time */ + cmd = g_strdup_printf("{'execute': 'guest-set-time'," + " 'arguments': { 'time': %" PRId64 " } }", + current + time * 1000); + ret = qmp_fd(fixture->fd, cmd); + g_free(cmd); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + QDECREF(ret); +} + +static void test_qga_fstrim(gconstpointer fix) +{ + const TestFixture *fixture = fix; + QDict *ret; + QList *list; + const QListEntry *entry; + + ret = qmp_fd(fixture->fd, "{'execute': 'guest-fstrim'," + " arguments: { minimum: 4194304 } }"); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + list = qdict_get_qlist(ret, "return"); + entry = qlist_first(list); + g_assert(qdict_haskey(qobject_to_qdict(entry->value), "paths")); + + QDECREF(ret); +} + +static void test_qga_blacklist(gconstpointer data) +{ + TestFixture fix; + QDict *ret, *error; + const gchar *class, *desc; + + fixture_setup(&fix, "-b guest-ping,guest-get-time"); + + /* check blacklist */ + ret = qmp_fd(fix.fd, "{'execute': 'guest-ping'}"); + g_assert_nonnull(ret); + error = qdict_get_qdict(ret, "error"); + class = qdict_get_try_str(error, "class"); + desc = qdict_get_try_str(error, "desc"); + g_assert_cmpstr(class, ==, "GenericError"); + g_assert_nonnull(g_strstr_len(desc, -1, "has been disabled")); + QDECREF(ret); + + ret = qmp_fd(fix.fd, "{'execute': 'guest-get-time'}"); + g_assert_nonnull(ret); + error = qdict_get_qdict(ret, "error"); + class = qdict_get_try_str(error, "class"); + desc = qdict_get_try_str(error, "desc"); + g_assert_cmpstr(class, ==, "GenericError"); + g_assert_nonnull(g_strstr_len(desc, -1, "has been disabled")); + QDECREF(ret); + + /* check something work */ + ret = qmp_fd(fix.fd, "{'execute': 'guest-get-fsinfo'}"); + qmp_assert_no_error(ret); + QDECREF(ret); + + fixture_tear_down(&fix, NULL); +} + +static void test_qga_config(gconstpointer data) +{ + GError *error = NULL; + char *cwd, *cmd, *out, *err, *str, **strv, *conf, **argv = NULL; + char *env[2]; + int status, tmp; + gsize n; + GKeyFile *kf; + const char *qga_config = + "[general]\n" + "daemon=false\n" + "method=virtio-serial\n" + "path=/path/to/org.qemu.guest_agent.0\n" + "pidfile=/var/foo/qemu-ga.pid\n" + "statedir=/var/state\n" + "verbose=true\n" + "blacklist=guest-ping;guest-get-time\n"; + + tmp = g_file_open_tmp(NULL, &conf, &error); + g_assert_no_error(error); + g_assert_cmpint(tmp, >=, 0); + g_assert_cmpstr(conf, !=, ""); + + g_file_set_contents(conf, qga_config, -1, &error); + g_assert_no_error(error); + + cwd = g_get_current_dir(); + cmd = g_strdup_printf("%s%cqemu-ga -D", + cwd, G_DIR_SEPARATOR); + g_shell_parse_argv(cmd, NULL, &argv, &error); + g_assert_no_error(error); + + env[0] = g_strdup_printf("QGA_CONF=%s", conf); + env[1] = NULL; + g_spawn_sync(NULL, argv, env, 0, + NULL, NULL, &out, &err, &status, &error); + g_assert_no_error(error); + g_assert_cmpstr(err, ==, ""); + g_assert_cmpint(status, ==, 0); + + kf = g_key_file_new(); + g_key_file_load_from_data(kf, out, -1, G_KEY_FILE_NONE, &error); + g_assert_no_error(error); + + str = g_key_file_get_start_group(kf); + g_assert_cmpstr(str, ==, "general"); + g_free(str); + + g_assert_false(g_key_file_get_boolean(kf, "general", "daemon", &error)); + g_assert_no_error(error); + + str = g_key_file_get_string(kf, "general", "method", &error); + g_assert_no_error(error); + g_assert_cmpstr(str, ==, "virtio-serial"); + g_free(str); + + str = g_key_file_get_string(kf, "general", "path", &error); + g_assert_no_error(error); + g_assert_cmpstr(str, ==, "/path/to/org.qemu.guest_agent.0"); + g_free(str); + + str = g_key_file_get_string(kf, "general", "pidfile", &error); + g_assert_no_error(error); + g_assert_cmpstr(str, ==, "/var/foo/qemu-ga.pid"); + g_free(str); + + str = g_key_file_get_string(kf, "general", "statedir", &error); + g_assert_no_error(error); + g_assert_cmpstr(str, ==, "/var/state"); + g_free(str); + + g_assert_true(g_key_file_get_boolean(kf, "general", "verbose", &error)); + g_assert_no_error(error); + + strv = g_key_file_get_string_list(kf, "general", "blacklist", &n, &error); + g_assert_cmpint(n, ==, 2); +#if GLIB_CHECK_VERSION(2, 44, 0) + g_assert_true(g_strv_contains((const char * const *)strv, + "guest-ping")); + g_assert_true(g_strv_contains((const char * const *)strv, + "guest-get-time")); +#endif + g_assert_no_error(error); + g_strfreev(strv); + + g_free(out); + g_free(err); + g_free(conf); + g_free(env[0]); + g_key_file_free(kf); + + close(tmp); +} + +static void test_qga_fsfreeze_status(gconstpointer fix) +{ + const TestFixture *fixture = fix; + QDict *ret; + const gchar *status; + + ret = qmp_fd(fixture->fd, "{'execute': 'guest-fsfreeze-status'}"); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + + status = qdict_get_try_str(ret, "return"); + g_assert_cmpstr(status, ==, "thawed"); + + QDECREF(ret); +} + +static void test_qga_fsfreeze_and_thaw(gconstpointer fix) +{ + const TestFixture *fixture = fix; + QDict *ret; + const gchar *status; + + ret = qmp_fd(fixture->fd, "{'execute': 'guest-fsfreeze-freeze'}"); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + QDECREF(ret); + + ret = qmp_fd(fixture->fd, "{'execute': 'guest-fsfreeze-status'}"); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + status = qdict_get_try_str(ret, "return"); + g_assert_cmpstr(status, ==, "frozen"); + QDECREF(ret); + + ret = qmp_fd(fixture->fd, "{'execute': 'guest-fsfreeze-thaw'}"); + g_assert_nonnull(ret); + qmp_assert_no_error(ret); + QDECREF(ret); +} + +int main(int argc, char **argv) +{ + TestFixture fix; + int ret; + + setlocale (LC_ALL, ""); + g_test_init(&argc, &argv, NULL); + fixture_setup(&fix, NULL); + + g_test_add_data_func("/qga/sync-delimited", &fix, test_qga_sync_delimited); + g_test_add_data_func("/qga/sync", &fix, test_qga_sync); + g_test_add_data_func("/qga/ping", &fix, test_qga_ping); + g_test_add_data_func("/qga/info", &fix, test_qga_info); + g_test_add_data_func("/qga/network-get-interfaces", &fix, + test_qga_network_get_interfaces); + g_test_add_data_func("/qga/get-vcpus", &fix, test_qga_get_vcpus); + g_test_add_data_func("/qga/get-fsinfo", &fix, test_qga_get_fsinfo); + g_test_add_data_func("/qga/get-memory-block-info", &fix, + test_qga_get_memory_block_info); + g_test_add_data_func("/qga/get-memory-blocks", &fix, + test_qga_get_memory_blocks); + g_test_add_data_func("/qga/file-ops", &fix, test_qga_file_ops); + g_test_add_data_func("/qga/file-write-read", &fix, test_qga_file_write_read); + g_test_add_data_func("/qga/get-time", &fix, test_qga_get_time); + g_test_add_data_func("/qga/invalid-cmd", &fix, test_qga_invalid_cmd); + g_test_add_data_func("/qga/fsfreeze-status", &fix, + test_qga_fsfreeze_status); + + g_test_add_data_func("/qga/blacklist", NULL, test_qga_blacklist); + g_test_add_data_func("/qga/config", NULL, test_qga_config); + + if (g_getenv("QGA_TEST_SIDE_EFFECTING")) { + g_test_add_data_func("/qga/fsfreeze-and-thaw", &fix, + test_qga_fsfreeze_and_thaw); + g_test_add_data_func("/qga/set-time", &fix, test_qga_set_time); + g_test_add_data_func("/qga/fstrim", &fix, test_qga_fstrim); + } + + ret = g_test_run(); + + fixture_tear_down(&fix, NULL); + + return ret; +} diff --git a/qemu/tests/test-qmp-commands.c b/qemu/tests/test-qmp-commands.c index 9918f2306..14a9ebbd5 100644 --- a/qemu/tests/test-qmp-commands.c +++ b/qemu/tests/test-qmp-commands.c @@ -1,3 +1,4 @@ +#include "qemu/osdep.h" #include <glib.h> #include "qemu-common.h" #include "qapi/qmp/types.h" @@ -12,6 +13,11 @@ void qmp_user_def_cmd(Error **errp) { } +Empty2 *qmp_user_def_cmd0(Error **errp) +{ + return g_new0(Empty2, 1); +} + void qmp_user_def_cmd1(UserDefOne * ud1, Error **errp) { } @@ -25,11 +31,9 @@ UserDefTwo *qmp_user_def_cmd2(UserDefOne *ud1a, UserDefOne *ud1d = g_malloc0(sizeof(UserDefOne)); ud1c->string = strdup(ud1a->string); - ud1c->base = g_new0(UserDefZero, 1); - ud1c->base->integer = ud1a->base->integer; + ud1c->integer = ud1a->integer; ud1d->string = strdup(has_udb1 ? ud1b->string : "blah0"); - ud1d->base = g_new0(UserDefZero, 1); - ud1d->base->integer = has_udb1 ? ud1b->base->integer : 0; + ud1d->integer = has_udb1 ? ud1b->integer : 0; ret = g_new0(UserDefTwo, 1); ret->string0 = strdup("blah1"); @@ -46,11 +50,16 @@ UserDefTwo *qmp_user_def_cmd2(UserDefOne *ud1a, return ret; } -int64_t qmp_user_def_cmd3(int64_t a, bool has_b, int64_t b, Error **errp) +int64_t qmp_guest_get_time(int64_t a, bool has_b, int64_t b, Error **errp) { return a + (has_b ? b : 0); } +QObject *qmp_guest_sync(QObject *arg, Error **errp) +{ + return arg; +} + __org_qemu_x_Union1 *qmp___org_qemu_x_command(__org_qemu_x_EnumList *a, __org_qemu_x_StructList *b, __org_qemu_x_Union2 *c, @@ -59,9 +68,13 @@ __org_qemu_x_Union1 *qmp___org_qemu_x_command(__org_qemu_x_EnumList *a, { __org_qemu_x_Union1 *ret = g_new0(__org_qemu_x_Union1, 1); - ret->kind = ORG_QEMU_X_UNION1_KIND___ORG_QEMU_X_BRANCH; - ret->__org_qemu_x_branch = strdup("blah1"); + ret->type = ORG_QEMU_X_UNION1_KIND___ORG_QEMU_X_BRANCH; + ret->u.__org_qemu_x_branch.data = strdup("blah1"); + /* Also test that 'wchar-t' was munged to 'q_wchar_t' */ + if (b && b->value && !b->value->has_q_wchar_t) { + b->value->q_wchar_t = 1; + } return ret; } @@ -155,7 +168,7 @@ static void test_dispatch_cmd_io(void) qdict_put(args3, "a", qint_from_int(66)); qdict_put(req, "arguments", args3); - qdict_put(req, "execute", qstring_from_str("user_def_cmd3")); + qdict_put(req, "execute", qstring_from_str("guest-get-time")); ret3 = qobject_to_qint(test_qmp_dispatch(req)); assert(qint_get_int(ret3) == 66); @@ -171,20 +184,17 @@ static void test_dealloc_types(void) UserDefOneList *ud1list; ud1test = g_malloc0(sizeof(UserDefOne)); - ud1test->base = g_new0(UserDefZero, 1); - ud1test->base->integer = 42; + ud1test->integer = 42; ud1test->string = g_strdup("hi there 42"); qapi_free_UserDefOne(ud1test); ud1a = g_malloc0(sizeof(UserDefOne)); - ud1a->base = g_new0(UserDefZero, 1); - ud1a->base->integer = 43; + ud1a->integer = 43; ud1a->string = g_strdup("hi there 43"); ud1b = g_malloc0(sizeof(UserDefOne)); - ud1b->base = g_new0(UserDefZero, 1); - ud1b->base->integer = 44; + ud1b->integer = 44; ud1b->string = g_strdup("hi there 44"); ud1list = g_malloc0(sizeof(UserDefOneList)); @@ -213,7 +223,7 @@ static void test_dealloc_partial(void) qdict_put_obj(ud2_dict, "string0", QOBJECT(qstring_from_str(text))); qiv = qmp_input_visitor_new(QOBJECT(ud2_dict)); - visit_type_UserDefTwo(qmp_input_get_visitor(qiv), &ud2, NULL, &err); + visit_type_UserDefTwo(qmp_input_get_visitor(qiv), NULL, &ud2, &err); qmp_input_visitor_cleanup(qiv); QDECREF(ud2_dict); } @@ -225,8 +235,7 @@ static void test_dealloc_partial(void) assert(ud2->dict1 == NULL); /* confirm & release construction error */ - assert(err != NULL); - error_free(err); + error_free_or_abort(&err); /* tear down partial object */ qapi_free_UserDefTwo(ud2); diff --git a/qemu/tests/test-qmp-event.c b/qemu/tests/test-qmp-event.c index 1ee40e148..a296fdbac 100644 --- a/qemu/tests/test-qmp-event.c +++ b/qemu/tests/test-qmp-event.c @@ -11,8 +11,8 @@ * */ +#include "qemu/osdep.h" #include <glib.h> -#include <stdarg.h> #include "qemu-common.h" #include "test-qapi-types.h" @@ -94,7 +94,7 @@ static bool qdict_cmp_simple(QDict *a, QDict *b) /* This function is hooked as final emit function, which can verify the correctness. */ -static void event_test_emit(TEST_QAPIEvent event, QDict *d, Error **errp) +static void event_test_emit(test_QAPIEvent event, QDict *d, Error **errp) { QObject *obj; QDict *t; @@ -179,9 +179,7 @@ static void test_event_c(TestEventData *data, QDict *d, *d_data, *d_b; UserDefOne b; - UserDefZero z; - z.integer = 2; - b.base = &z; + b.integer = 2; b.string = g_strdup("test1"); b.has_enum1 = false; @@ -209,11 +207,9 @@ static void test_event_d(TestEventData *data, { UserDefOne struct1; EventStructOne a; - UserDefZero z; QDict *d, *d_data, *d_a, *d_struct1; - z.integer = 2; - struct1.base = &z; + struct1.integer = 2; struct1.string = g_strdup("test1"); struct1.has_enum1 = true; struct1.enum1 = ENUM_ONE_VALUE1; diff --git a/qemu/tests/test-qmp-input-strict.c b/qemu/tests/test-qmp-input-strict.c index 68f855bdf..d71727e27 100644 --- a/qemu/tests/test-qmp-input-strict.c +++ b/qemu/tests/test-qmp-input-strict.c @@ -11,14 +11,18 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <stdarg.h> #include "qemu-common.h" +#include "qapi/error.h" #include "qapi/qmp-input-visitor.h" #include "test-qapi-types.h" #include "test-qapi-visit.h" #include "qapi/qmp/types.h" +#include "test-qmp-introspect.h" +#include "qmp-introspect.h" +#include "qapi-visit.h" typedef struct TestInputVisitorData { QObject *obj; @@ -37,78 +41,65 @@ static void validate_teardown(TestInputVisitorData *data, } } -/* This is provided instead of a test setup function so that the JSON - string used by the tests are kept in the test functions (and not - int main()) */ -static GCC_FMT_ATTR(2, 3) -Visitor *validate_test_init(TestInputVisitorData *data, - const char *json_string, ...) +/* The various test_init functions are provided instead of a test setup + function so that the JSON string used by the tests are kept in the test + functions (and not in main()). */ +static Visitor *validate_test_init_internal(TestInputVisitorData *data, + const char *json_string, + va_list *ap) { Visitor *v; - va_list ap; - va_start(ap, json_string); - data->obj = qobject_from_jsonv(json_string, &ap); - va_end(ap); + validate_teardown(data, NULL); - g_assert(data->obj != NULL); + data->obj = qobject_from_jsonv(json_string, ap); + g_assert(data->obj); data->qiv = qmp_input_visitor_new_strict(data->obj); - g_assert(data->qiv != NULL); + g_assert(data->qiv); v = qmp_input_get_visitor(data->qiv); - g_assert(v != NULL); + g_assert(v); return v; } -typedef struct TestStruct -{ - int64_t integer; - bool boolean; - char *string; -} TestStruct; - -static void visit_type_TestStruct(Visitor *v, TestStruct **obj, - const char *name, Error **errp) +static GCC_FMT_ATTR(2, 3) +Visitor *validate_test_init(TestInputVisitorData *data, + const char *json_string, ...) { - Error *err = NULL; + Visitor *v; + va_list ap; - visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct), - &err); - if (err) { - goto out; - } + va_start(ap, json_string); + v = validate_test_init_internal(data, json_string, &ap); + va_end(ap); + return v; +} - visit_type_int(v, &(*obj)->integer, "integer", &err); - if (err) { - goto out_end; - } - visit_type_bool(v, &(*obj)->boolean, "boolean", &err); - if (err) { - goto out_end; - } - visit_type_str(v, &(*obj)->string, "string", &err); - -out_end: - error_propagate(errp, err); - err = NULL; - visit_end_struct(v, &err); -out: - error_propagate(errp, err); +/* similar to validate_test_init(), but does not expect a string + * literal/format json_string argument and so can be used for + * programatically generated strings (and we can't pass in programatically + * generated strings via %s format parameters since qobject_from_jsonv() + * will wrap those in double-quotes and treat the entire object as a + * string) + */ +static Visitor *validate_test_init_raw(TestInputVisitorData *data, + const char *json_string) +{ + return validate_test_init_internal(data, json_string, NULL); } + static void test_validate_struct(TestInputVisitorData *data, const void *unused) { TestStruct *p = NULL; - Error *err = NULL; Visitor *v; v = validate_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo' }"); - visit_type_TestStruct(v, &p, NULL, &err); - g_assert(!err); + visit_type_TestStruct(v, NULL, &p, &error_abort); g_free(p->string); g_free(p); } @@ -117,7 +108,6 @@ static void test_validate_struct_nested(TestInputVisitorData *data, const void *unused) { UserDefTwo *udp = NULL; - Error *err = NULL; Visitor *v; v = validate_test_init(data, "{ 'string0': 'string0', " @@ -125,8 +115,7 @@ static void test_validate_struct_nested(TestInputVisitorData *data, "'dict2': { 'userdef': { 'integer': 42, " "'string': 'string' }, 'string': 'string2'}}}"); - visit_type_UserDefTwo(v, &udp, NULL, &err); - g_assert(!err); + visit_type_UserDefTwo(v, NULL, &udp, &error_abort); qapi_free_UserDefTwo(udp); } @@ -134,13 +123,11 @@ static void test_validate_list(TestInputVisitorData *data, const void *unused) { UserDefOneList *head = NULL; - Error *err = NULL; Visitor *v; v = validate_test_init(data, "[ { 'string': 'string0', 'integer': 42 }, { 'string': 'string1', 'integer': 43 }, { 'string': 'string2', 'integer': 44 } ]"); - visit_type_UserDefOneList(v, &head, NULL, &err); - g_assert(!err); + visit_type_UserDefOneList(v, NULL, &head, &error_abort); qapi_free_UserDefOneList(head); } @@ -149,12 +136,10 @@ static void test_validate_union_native_list(TestInputVisitorData *data, { UserDefNativeListUnion *tmp = NULL; Visitor *v; - Error *err = NULL; v = validate_test_init(data, "{ 'type': 'integer', 'data' : [ 1, 2 ] }"); - visit_type_UserDefNativeListUnion(v, &tmp, NULL, &err); - g_assert(!err); + visit_type_UserDefNativeListUnion(v, NULL, &tmp, &error_abort); qapi_free_UserDefNativeListUnion(tmp); } @@ -163,16 +148,14 @@ static void test_validate_union_flat(TestInputVisitorData *data, { UserDefFlatUnion *tmp = NULL; Visitor *v; - Error *err = NULL; v = validate_test_init(data, "{ 'enum1': 'value1', " + "'integer': 41, " "'string': 'str', " "'boolean': true }"); - /* TODO when generator bug is fixed, add 'integer': 41 */ - visit_type_UserDefFlatUnion(v, &tmp, NULL, &err); - g_assert(!err); + visit_type_UserDefFlatUnion(v, NULL, &tmp, &error_abort); qapi_free_UserDefFlatUnion(tmp); } @@ -181,12 +164,10 @@ static void test_validate_alternate(TestInputVisitorData *data, { UserDefAlternate *tmp = NULL; Visitor *v; - Error *err = NULL; v = validate_test_init(data, "42"); - visit_type_UserDefAlternate(v, &tmp, NULL, &err); - g_assert(!err); + visit_type_UserDefAlternate(v, NULL, &tmp, &error_abort); qapi_free_UserDefAlternate(tmp); } @@ -199,8 +180,8 @@ static void test_validate_fail_struct(TestInputVisitorData *data, v = validate_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo', 'extra': 42 }"); - visit_type_TestStruct(v, &p, NULL, &err); - g_assert(err); + visit_type_TestStruct(v, NULL, &p, &err); + error_free_or_abort(&err); if (p) { g_free(p->string); } @@ -216,8 +197,8 @@ static void test_validate_fail_struct_nested(TestInputVisitorData *data, v = validate_test_init(data, "{ 'string0': 'string0', 'dict1': { 'string1': 'string1', 'dict2': { 'userdef1': { 'integer': 42, 'string': 'string', 'extra': [42, 23, {'foo':'bar'}] }, 'string2': 'string2'}}}"); - visit_type_UserDefTwo(v, &udp, NULL, &err); - g_assert(err); + visit_type_UserDefTwo(v, NULL, &udp, &err); + error_free_or_abort(&err); qapi_free_UserDefTwo(udp); } @@ -230,8 +211,8 @@ static void test_validate_fail_list(TestInputVisitorData *data, v = validate_test_init(data, "[ { 'string': 'string0', 'integer': 42 }, { 'string': 'string1', 'integer': 43 }, { 'string': 'string2', 'integer': 44, 'extra': 'ggg' } ]"); - visit_type_UserDefOneList(v, &head, NULL, &err); - g_assert(err); + visit_type_UserDefOneList(v, NULL, &head, &err); + error_free_or_abort(&err); qapi_free_UserDefOneList(head); } @@ -245,8 +226,8 @@ static void test_validate_fail_union_native_list(TestInputVisitorData *data, v = validate_test_init(data, "{ 'type': 'integer', 'data' : [ 'string' ] }"); - visit_type_UserDefNativeListUnion(v, &tmp, NULL, &err); - g_assert(err); + visit_type_UserDefNativeListUnion(v, NULL, &tmp, &err); + error_free_or_abort(&err); qapi_free_UserDefNativeListUnion(tmp); } @@ -259,8 +240,8 @@ static void test_validate_fail_union_flat(TestInputVisitorData *data, v = validate_test_init(data, "{ 'string': 'c', 'integer': 41, 'boolean': true }"); - visit_type_UserDefFlatUnion(v, &tmp, NULL, &err); - g_assert(err); + visit_type_UserDefFlatUnion(v, NULL, &tmp, &err); + error_free_or_abort(&err); qapi_free_UserDefFlatUnion(tmp); } @@ -272,10 +253,10 @@ static void test_validate_fail_union_flat_no_discrim(TestInputVisitorData *data, Visitor *v; /* test situation where discriminator field ('enum1' here) is missing */ - v = validate_test_init(data, "{ 'string': 'c', 'string1': 'd', 'string2': 'e' }"); + v = validate_test_init(data, "{ 'integer': 42, 'string': 'c', 'string1': 'd', 'string2': 'e' }"); - visit_type_UserDefFlatUnion2(v, &tmp, NULL, &err); - g_assert(err); + visit_type_UserDefFlatUnion2(v, NULL, &tmp, &err); + error_free_or_abort(&err); qapi_free_UserDefFlatUnion2(tmp); } @@ -288,11 +269,32 @@ static void test_validate_fail_alternate(TestInputVisitorData *data, v = validate_test_init(data, "3.14"); - visit_type_UserDefAlternate(v, &tmp, NULL, &err); - g_assert(err); + visit_type_UserDefAlternate(v, NULL, &tmp, &err); + error_free_or_abort(&err); qapi_free_UserDefAlternate(tmp); } +static void do_test_validate_qmp_introspect(TestInputVisitorData *data, + const char *schema_json) +{ + SchemaInfoList *schema = NULL; + Visitor *v; + + v = validate_test_init_raw(data, schema_json); + + visit_type_SchemaInfoList(v, NULL, &schema, &error_abort); + g_assert(schema); + + qapi_free_SchemaInfoList(schema); +} + +static void test_validate_qmp_introspect(TestInputVisitorData *data, + const void *unused) +{ + do_test_validate_qmp_introspect(data, test_qmp_schema_json); + do_test_validate_qmp_introspect(data, qmp_schema_json); +} + static void validate_test_add(const char *testpath, TestInputVisitorData *data, void (*test_func)(TestInputVisitorData *data, const void *user_data)) @@ -333,6 +335,8 @@ int main(int argc, char **argv) &testdata, test_validate_fail_alternate); validate_test_add("/visitor/input-strict/fail/union-native-list", &testdata, test_validate_fail_union_native_list); + validate_test_add("/visitor/input-strict/pass/qmp-introspect", + &testdata, test_validate_qmp_introspect); g_test_run(); diff --git a/qemu/tests/test-qmp-input-visitor.c b/qemu/tests/test-qmp-input-visitor.c index b96195309..80527eb85 100644 --- a/qemu/tests/test-qmp-input-visitor.c +++ b/qemu/tests/test-qmp-input-visitor.c @@ -1,7 +1,7 @@ /* * QMP Input Visitor unit-tests. * - * Copyright (C) 2011, 2015 Red Hat Inc. + * Copyright (C) 2011-2016 Red Hat Inc. * * Authors: * Luiz Capitulino <lcapitulino@redhat.com> @@ -10,10 +10,11 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <stdarg.h> #include "qemu-common.h" +#include "qapi/error.h" #include "qapi/qmp-input-visitor.h" #include "test-qapi-types.h" #include "test-qapi-visit.h" @@ -36,31 +37,42 @@ static void visitor_input_teardown(TestInputVisitorData *data, } } -/* This is provided instead of a test setup function so that the JSON - string used by the tests are kept in the test functions (and not - int main()) */ -static GCC_FMT_ATTR(2, 3) -Visitor *visitor_input_test_init(TestInputVisitorData *data, - const char *json_string, ...) +/* The various test_init functions are provided instead of a test setup + function so that the JSON string used by the tests are kept in the test + functions (and not in main()). */ +static Visitor *visitor_input_test_init_internal(TestInputVisitorData *data, + const char *json_string, + va_list *ap) { Visitor *v; - va_list ap; - va_start(ap, json_string); - data->obj = qobject_from_jsonv(json_string, &ap); - va_end(ap); + visitor_input_teardown(data, NULL); - g_assert(data->obj != NULL); + data->obj = qobject_from_jsonv(json_string, ap); + g_assert(data->obj); data->qiv = qmp_input_visitor_new(data->obj); - g_assert(data->qiv != NULL); + g_assert(data->qiv); v = qmp_input_get_visitor(data->qiv); - g_assert(v != NULL); + g_assert(v); return v; } +static GCC_FMT_ATTR(2, 3) +Visitor *visitor_input_test_init(TestInputVisitorData *data, + const char *json_string, ...) +{ + Visitor *v; + va_list ap; + + va_start(ap, json_string); + v = visitor_input_test_init_internal(data, json_string, &ap); + va_end(ap); + return v; +} + /* similar to visitor_input_test_init(), but does not expect a string * literal/format json_string argument and so can be used for * programatically generated strings (and we can't pass in programatically @@ -71,32 +83,18 @@ Visitor *visitor_input_test_init(TestInputVisitorData *data, static Visitor *visitor_input_test_init_raw(TestInputVisitorData *data, const char *json_string) { - Visitor *v; - - data->obj = qobject_from_json(json_string); - - g_assert(data->obj != NULL); - - data->qiv = qmp_input_visitor_new(data->obj); - g_assert(data->qiv != NULL); - - v = qmp_input_get_visitor(data->qiv); - g_assert(v != NULL); - - return v; + return visitor_input_test_init_internal(data, json_string, NULL); } static void test_visitor_in_int(TestInputVisitorData *data, const void *unused) { int64_t res = 0, value = -42; - Error *err = NULL; Visitor *v; v = visitor_input_test_init(data, "%" PRId64, value); - visit_type_int(v, &res, NULL, &err); - g_assert(!err); + visit_type_int(v, NULL, &res, &error_abort); g_assert_cmpint(res, ==, value); } @@ -113,22 +111,19 @@ static void test_visitor_in_int_overflow(TestInputVisitorData *data, */ v = visitor_input_test_init(data, "%f", DBL_MAX); - visit_type_int(v, &res, NULL, &err); - g_assert(err); - error_free(err); + visit_type_int(v, NULL, &res, &err); + error_free_or_abort(&err); } static void test_visitor_in_bool(TestInputVisitorData *data, const void *unused) { - Error *err = NULL; bool res = false; Visitor *v; v = visitor_input_test_init(data, "true"); - visit_type_bool(v, &res, NULL, &err); - g_assert(!err); + visit_type_bool(v, NULL, &res, &error_abort); g_assert_cmpint(res, ==, true); } @@ -136,13 +131,11 @@ static void test_visitor_in_number(TestInputVisitorData *data, const void *unused) { double res = 0, value = 3.14; - Error *err = NULL; Visitor *v; v = visitor_input_test_init(data, "%f", value); - visit_type_number(v, &res, NULL, &err); - g_assert(!err); + visit_type_number(v, NULL, &res, &error_abort); g_assert_cmpfloat(res, ==, value); } @@ -150,13 +143,11 @@ static void test_visitor_in_string(TestInputVisitorData *data, const void *unused) { char *res = NULL, *value = (char *) "Q E M U"; - Error *err = NULL; Visitor *v; v = visitor_input_test_init(data, "%s", value); - visit_type_str(v, &res, NULL, &err); - g_assert(!err); + visit_type_str(v, NULL, &res, &error_abort); g_assert_cmpstr(res, ==, value); g_free(res); @@ -165,7 +156,6 @@ static void test_visitor_in_string(TestInputVisitorData *data, static void test_visitor_in_enum(TestInputVisitorData *data, const void *unused) { - Error *err = NULL; Visitor *v; EnumOne i; @@ -174,63 +164,21 @@ static void test_visitor_in_enum(TestInputVisitorData *data, v = visitor_input_test_init(data, "%s", EnumOne_lookup[i]); - visit_type_EnumOne(v, &res, NULL, &err); - g_assert(!err); + visit_type_EnumOne(v, NULL, &res, &error_abort); g_assert_cmpint(i, ==, res); - - visitor_input_teardown(data, NULL); } - - data->obj = NULL; - data->qiv = NULL; } -typedef struct TestStruct -{ - int64_t integer; - bool boolean; - char *string; -} TestStruct; - -static void visit_type_TestStruct(Visitor *v, TestStruct **obj, - const char *name, Error **errp) -{ - Error *err = NULL; - - visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct), - &err); - if (err) { - goto out; - } - visit_type_int(v, &(*obj)->integer, "integer", &err); - if (err) { - goto out_end; - } - visit_type_bool(v, &(*obj)->boolean, "boolean", &err); - if (err) { - goto out_end; - } - visit_type_str(v, &(*obj)->string, "string", &err); - -out_end: - error_propagate(errp, err); - err = NULL; - visit_end_struct(v, &err); -out: - error_propagate(errp, err); -} static void test_visitor_in_struct(TestInputVisitorData *data, const void *unused) { TestStruct *p = NULL; - Error *err = NULL; Visitor *v; v = visitor_input_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo' }"); - visit_type_TestStruct(v, &p, NULL, &err); - g_assert(!err); + visit_type_TestStruct(v, NULL, &p, &error_abort); g_assert_cmpint(p->integer, ==, -42); g_assert(p->boolean == true); g_assert_cmpstr(p->string, ==, "foo"); @@ -239,17 +187,10 @@ static void test_visitor_in_struct(TestInputVisitorData *data, g_free(p); } -static void check_and_free_str(char *str, const char *cmp) -{ - g_assert_cmpstr(str, ==, cmp); - g_free(str); -} - static void test_visitor_in_struct_nested(TestInputVisitorData *data, const void *unused) { UserDefTwo *udp = NULL; - Error *err = NULL; Visitor *v; v = visitor_input_test_init(data, "{ 'string0': 'string0', " @@ -257,34 +198,28 @@ static void test_visitor_in_struct_nested(TestInputVisitorData *data, "'dict2': { 'userdef': { 'integer': 42, " "'string': 'string' }, 'string': 'string2'}}}"); - visit_type_UserDefTwo(v, &udp, NULL, &err); - g_assert(!err); + visit_type_UserDefTwo(v, NULL, &udp, &error_abort); - check_and_free_str(udp->string0, "string0"); - check_and_free_str(udp->dict1->string1, "string1"); - g_assert_cmpint(udp->dict1->dict2->userdef->base->integer, ==, 42); - check_and_free_str(udp->dict1->dict2->userdef->string, "string"); - check_and_free_str(udp->dict1->dict2->string, "string2"); + g_assert_cmpstr(udp->string0, ==, "string0"); + g_assert_cmpstr(udp->dict1->string1, ==, "string1"); + g_assert_cmpint(udp->dict1->dict2->userdef->integer, ==, 42); + g_assert_cmpstr(udp->dict1->dict2->userdef->string, ==, "string"); + g_assert_cmpstr(udp->dict1->dict2->string, ==, "string2"); g_assert(udp->dict1->has_dict3 == false); - g_free(udp->dict1->dict2->userdef); - g_free(udp->dict1->dict2); - g_free(udp->dict1); - g_free(udp); + qapi_free_UserDefTwo(udp); } static void test_visitor_in_list(TestInputVisitorData *data, const void *unused) { UserDefOneList *item, *head = NULL; - Error *err = NULL; Visitor *v; int i; v = visitor_input_test_init(data, "[ { 'string': 'string0', 'integer': 42 }, { 'string': 'string1', 'integer': 43 }, { 'string': 'string2', 'integer': 44 } ]"); - visit_type_UserDefOneList(v, &head, NULL, &err); - g_assert(!err); + visit_type_UserDefOneList(v, NULL, &head, &error_abort); g_assert(head != NULL); for (i = 0, item = head; item; item = item->next, i++) { @@ -292,31 +227,80 @@ static void test_visitor_in_list(TestInputVisitorData *data, snprintf(string, sizeof(string), "string%d", i); g_assert_cmpstr(item->value->string, ==, string); - g_assert_cmpint(item->value->base->integer, ==, 42 + i); + g_assert_cmpint(item->value->integer, ==, 42 + i); } qapi_free_UserDefOneList(head); + head = NULL; + + /* An empty list is valid */ + v = visitor_input_test_init(data, "[]"); + visit_type_UserDefOneList(v, NULL, &head, &error_abort); + g_assert(!head); +} + +static void test_visitor_in_any(TestInputVisitorData *data, + const void *unused) +{ + QObject *res = NULL; + Visitor *v; + QInt *qint; + QBool *qbool; + QString *qstring; + QDict *qdict; + QObject *qobj; + + v = visitor_input_test_init(data, "-42"); + visit_type_any(v, NULL, &res, &error_abort); + qint = qobject_to_qint(res); + g_assert(qint); + g_assert_cmpint(qint_get_int(qint), ==, -42); + qobject_decref(res); + + v = visitor_input_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo' }"); + visit_type_any(v, NULL, &res, &error_abort); + qdict = qobject_to_qdict(res); + g_assert(qdict && qdict_size(qdict) == 3); + qobj = qdict_get(qdict, "integer"); + g_assert(qobj); + qint = qobject_to_qint(qobj); + g_assert(qint); + g_assert_cmpint(qint_get_int(qint), ==, -42); + qobj = qdict_get(qdict, "boolean"); + g_assert(qobj); + qbool = qobject_to_qbool(qobj); + g_assert(qbool); + g_assert(qbool_get_bool(qbool) == true); + qobj = qdict_get(qdict, "string"); + g_assert(qobj); + qstring = qobject_to_qstring(qobj); + g_assert(qstring); + g_assert_cmpstr(qstring_get_str(qstring), ==, "foo"); + qobject_decref(res); } static void test_visitor_in_union_flat(TestInputVisitorData *data, const void *unused) { Visitor *v; - Error *err = NULL; UserDefFlatUnion *tmp; + UserDefUnionBase *base; v = visitor_input_test_init(data, "{ 'enum1': 'value1', " + "'integer': 41, " "'string': 'str', " "'boolean': true }"); - /* TODO when generator bug is fixed, add 'integer': 41 */ - visit_type_UserDefFlatUnion(v, &tmp, NULL, &err); - g_assert(err == NULL); - g_assert_cmpint(tmp->kind, ==, ENUM_ONE_VALUE1); + visit_type_UserDefFlatUnion(v, NULL, &tmp, &error_abort); + g_assert_cmpint(tmp->enum1, ==, ENUM_ONE_VALUE1); g_assert_cmpstr(tmp->string, ==, "str"); - /* TODO g_assert_cmpint(tmp->integer, ==, 41); */ - g_assert_cmpint(tmp->value1->boolean, ==, true); + g_assert_cmpint(tmp->integer, ==, 41); + g_assert_cmpint(tmp->u.value1.boolean, ==, true); + + base = qapi_UserDefFlatUnion_base(tmp); + g_assert(&base->enum1 == &tmp->enum1); + qapi_free_UserDefFlatUnion(tmp); } @@ -326,14 +310,144 @@ static void test_visitor_in_alternate(TestInputVisitorData *data, Visitor *v; Error *err = NULL; UserDefAlternate *tmp; + WrapAlternate *wrap; v = visitor_input_test_init(data, "42"); + visit_type_UserDefAlternate(v, NULL, &tmp, &error_abort); + g_assert_cmpint(tmp->type, ==, QTYPE_QINT); + g_assert_cmpint(tmp->u.i, ==, 42); + qapi_free_UserDefAlternate(tmp); + + v = visitor_input_test_init(data, "'string'"); + visit_type_UserDefAlternate(v, NULL, &tmp, &error_abort); + g_assert_cmpint(tmp->type, ==, QTYPE_QSTRING); + g_assert_cmpstr(tmp->u.s, ==, "string"); + qapi_free_UserDefAlternate(tmp); + + v = visitor_input_test_init(data, "{'integer':1, 'string':'str', " + "'enum1':'value1', 'boolean':true}"); + visit_type_UserDefAlternate(v, NULL, &tmp, &error_abort); + g_assert_cmpint(tmp->type, ==, QTYPE_QDICT); + g_assert_cmpint(tmp->u.udfu.integer, ==, 1); + g_assert_cmpstr(tmp->u.udfu.string, ==, "str"); + g_assert_cmpint(tmp->u.udfu.enum1, ==, ENUM_ONE_VALUE1); + g_assert_cmpint(tmp->u.udfu.u.value1.boolean, ==, true); + g_assert_cmpint(tmp->u.udfu.u.value1.has_a_b, ==, false); + qapi_free_UserDefAlternate(tmp); - visit_type_UserDefAlternate(v, &tmp, NULL, &err); - g_assert(err == NULL); - g_assert_cmpint(tmp->kind, ==, USER_DEF_ALTERNATE_KIND_I); - g_assert_cmpint(tmp->i, ==, 42); + v = visitor_input_test_init(data, "false"); + visit_type_UserDefAlternate(v, NULL, &tmp, &err); + error_free_or_abort(&err); qapi_free_UserDefAlternate(tmp); + + v = visitor_input_test_init(data, "{ 'alt': 42 }"); + visit_type_WrapAlternate(v, NULL, &wrap, &error_abort); + g_assert_cmpint(wrap->alt->type, ==, QTYPE_QINT); + g_assert_cmpint(wrap->alt->u.i, ==, 42); + qapi_free_WrapAlternate(wrap); + + v = visitor_input_test_init(data, "{ 'alt': 'string' }"); + visit_type_WrapAlternate(v, NULL, &wrap, &error_abort); + g_assert_cmpint(wrap->alt->type, ==, QTYPE_QSTRING); + g_assert_cmpstr(wrap->alt->u.s, ==, "string"); + qapi_free_WrapAlternate(wrap); + + v = visitor_input_test_init(data, "{ 'alt': {'integer':1, 'string':'str', " + "'enum1':'value1', 'boolean':true} }"); + visit_type_WrapAlternate(v, NULL, &wrap, &error_abort); + g_assert_cmpint(wrap->alt->type, ==, QTYPE_QDICT); + g_assert_cmpint(wrap->alt->u.udfu.integer, ==, 1); + g_assert_cmpstr(wrap->alt->u.udfu.string, ==, "str"); + g_assert_cmpint(wrap->alt->u.udfu.enum1, ==, ENUM_ONE_VALUE1); + g_assert_cmpint(wrap->alt->u.udfu.u.value1.boolean, ==, true); + g_assert_cmpint(wrap->alt->u.udfu.u.value1.has_a_b, ==, false); + qapi_free_WrapAlternate(wrap); +} + +static void test_visitor_in_alternate_number(TestInputVisitorData *data, + const void *unused) +{ + Visitor *v; + Error *err = NULL; + AltStrBool *asb; + AltStrNum *asn; + AltNumStr *ans; + AltStrInt *asi; + AltIntNum *ain; + AltNumInt *ani; + + /* Parsing an int */ + + v = visitor_input_test_init(data, "42"); + visit_type_AltStrBool(v, NULL, &asb, &err); + error_free_or_abort(&err); + qapi_free_AltStrBool(asb); + + v = visitor_input_test_init(data, "42"); + visit_type_AltStrNum(v, NULL, &asn, &error_abort); + g_assert_cmpint(asn->type, ==, QTYPE_QFLOAT); + g_assert_cmpfloat(asn->u.n, ==, 42); + qapi_free_AltStrNum(asn); + + v = visitor_input_test_init(data, "42"); + visit_type_AltNumStr(v, NULL, &ans, &error_abort); + g_assert_cmpint(ans->type, ==, QTYPE_QFLOAT); + g_assert_cmpfloat(ans->u.n, ==, 42); + qapi_free_AltNumStr(ans); + + v = visitor_input_test_init(data, "42"); + visit_type_AltStrInt(v, NULL, &asi, &error_abort); + g_assert_cmpint(asi->type, ==, QTYPE_QINT); + g_assert_cmpint(asi->u.i, ==, 42); + qapi_free_AltStrInt(asi); + + v = visitor_input_test_init(data, "42"); + visit_type_AltIntNum(v, NULL, &ain, &error_abort); + g_assert_cmpint(ain->type, ==, QTYPE_QINT); + g_assert_cmpint(ain->u.i, ==, 42); + qapi_free_AltIntNum(ain); + + v = visitor_input_test_init(data, "42"); + visit_type_AltNumInt(v, NULL, &ani, &error_abort); + g_assert_cmpint(ani->type, ==, QTYPE_QINT); + g_assert_cmpint(ani->u.i, ==, 42); + qapi_free_AltNumInt(ani); + + /* Parsing a double */ + + v = visitor_input_test_init(data, "42.5"); + visit_type_AltStrBool(v, NULL, &asb, &err); + error_free_or_abort(&err); + qapi_free_AltStrBool(asb); + + v = visitor_input_test_init(data, "42.5"); + visit_type_AltStrNum(v, NULL, &asn, &error_abort); + g_assert_cmpint(asn->type, ==, QTYPE_QFLOAT); + g_assert_cmpfloat(asn->u.n, ==, 42.5); + qapi_free_AltStrNum(asn); + + v = visitor_input_test_init(data, "42.5"); + visit_type_AltNumStr(v, NULL, &ans, &error_abort); + g_assert_cmpint(ans->type, ==, QTYPE_QFLOAT); + g_assert_cmpfloat(ans->u.n, ==, 42.5); + qapi_free_AltNumStr(ans); + + v = visitor_input_test_init(data, "42.5"); + visit_type_AltStrInt(v, NULL, &asi, &err); + error_free_or_abort(&err); + qapi_free_AltStrInt(asi); + + v = visitor_input_test_init(data, "42.5"); + visit_type_AltIntNum(v, NULL, &ain, &error_abort); + g_assert_cmpint(ain->type, ==, QTYPE_QFLOAT); + g_assert_cmpfloat(ain->u.n, ==, 42.5); + qapi_free_AltIntNum(ain); + + v = visitor_input_test_init(data, "42.5"); + visit_type_AltNumInt(v, NULL, &ani, &error_abort); + g_assert_cmpint(ani->type, ==, QTYPE_QFLOAT); + g_assert_cmpfloat(ani->u.n, ==, 42.5); + qapi_free_AltNumInt(ani); } static void test_native_list_integer_helper(TestInputVisitorData *data, @@ -341,7 +455,6 @@ static void test_native_list_integer_helper(TestInputVisitorData *data, UserDefNativeListUnionKind kind) { UserDefNativeListUnion *cvalue = NULL; - Error *err = NULL; Visitor *v; GString *gstr_list = g_string_new(""); GString *gstr_union = g_string_new(""); @@ -358,71 +471,71 @@ static void test_native_list_integer_helper(TestInputVisitorData *data, gstr_list->str); v = visitor_input_test_init_raw(data, gstr_union->str); - visit_type_UserDefNativeListUnion(v, &cvalue, NULL, &err); - g_assert(err == NULL); + visit_type_UserDefNativeListUnion(v, NULL, &cvalue, &error_abort); g_assert(cvalue != NULL); - g_assert_cmpint(cvalue->kind, ==, kind); + g_assert_cmpint(cvalue->type, ==, kind); switch (kind) { case USER_DEF_NATIVE_LIST_UNION_KIND_INTEGER: { intList *elem = NULL; - for (i = 0, elem = cvalue->integer; elem; elem = elem->next, i++) { + for (i = 0, elem = cvalue->u.integer.data; + elem; elem = elem->next, i++) { g_assert_cmpint(elem->value, ==, i); } break; } case USER_DEF_NATIVE_LIST_UNION_KIND_S8: { int8List *elem = NULL; - for (i = 0, elem = cvalue->s8; elem; elem = elem->next, i++) { + for (i = 0, elem = cvalue->u.s8.data; elem; elem = elem->next, i++) { g_assert_cmpint(elem->value, ==, i); } break; } case USER_DEF_NATIVE_LIST_UNION_KIND_S16: { int16List *elem = NULL; - for (i = 0, elem = cvalue->s16; elem; elem = elem->next, i++) { + for (i = 0, elem = cvalue->u.s16.data; elem; elem = elem->next, i++) { g_assert_cmpint(elem->value, ==, i); } break; } case USER_DEF_NATIVE_LIST_UNION_KIND_S32: { int32List *elem = NULL; - for (i = 0, elem = cvalue->s32; elem; elem = elem->next, i++) { + for (i = 0, elem = cvalue->u.s32.data; elem; elem = elem->next, i++) { g_assert_cmpint(elem->value, ==, i); } break; } case USER_DEF_NATIVE_LIST_UNION_KIND_S64: { int64List *elem = NULL; - for (i = 0, elem = cvalue->s64; elem; elem = elem->next, i++) { + for (i = 0, elem = cvalue->u.s64.data; elem; elem = elem->next, i++) { g_assert_cmpint(elem->value, ==, i); } break; } case USER_DEF_NATIVE_LIST_UNION_KIND_U8: { uint8List *elem = NULL; - for (i = 0, elem = cvalue->u8; elem; elem = elem->next, i++) { + for (i = 0, elem = cvalue->u.u8.data; elem; elem = elem->next, i++) { g_assert_cmpint(elem->value, ==, i); } break; } case USER_DEF_NATIVE_LIST_UNION_KIND_U16: { uint16List *elem = NULL; - for (i = 0, elem = cvalue->u16; elem; elem = elem->next, i++) { + for (i = 0, elem = cvalue->u.u16.data; elem; elem = elem->next, i++) { g_assert_cmpint(elem->value, ==, i); } break; } case USER_DEF_NATIVE_LIST_UNION_KIND_U32: { uint32List *elem = NULL; - for (i = 0, elem = cvalue->u32; elem; elem = elem->next, i++) { + for (i = 0, elem = cvalue->u.u32.data; elem; elem = elem->next, i++) { g_assert_cmpint(elem->value, ==, i); } break; } case USER_DEF_NATIVE_LIST_UNION_KIND_U64: { uint64List *elem = NULL; - for (i = 0, elem = cvalue->u64; elem; elem = elem->next, i++) { + for (i = 0, elem = cvalue->u.u64.data; elem; elem = elem->next, i++) { g_assert_cmpint(elem->value, ==, i); } break; @@ -504,7 +617,6 @@ static void test_visitor_in_native_list_bool(TestInputVisitorData *data, { UserDefNativeListUnion *cvalue = NULL; boolList *elem = NULL; - Error *err = NULL; Visitor *v; GString *gstr_list = g_string_new(""); GString *gstr_union = g_string_new(""); @@ -521,12 +633,11 @@ static void test_visitor_in_native_list_bool(TestInputVisitorData *data, gstr_list->str); v = visitor_input_test_init_raw(data, gstr_union->str); - visit_type_UserDefNativeListUnion(v, &cvalue, NULL, &err); - g_assert(err == NULL); + visit_type_UserDefNativeListUnion(v, NULL, &cvalue, &error_abort); g_assert(cvalue != NULL); - g_assert_cmpint(cvalue->kind, ==, USER_DEF_NATIVE_LIST_UNION_KIND_BOOLEAN); + g_assert_cmpint(cvalue->type, ==, USER_DEF_NATIVE_LIST_UNION_KIND_BOOLEAN); - for (i = 0, elem = cvalue->boolean; elem; elem = elem->next, i++) { + for (i = 0, elem = cvalue->u.boolean.data; elem; elem = elem->next, i++) { g_assert_cmpint(elem->value, ==, (i % 3 == 0) ? 1 : 0); } @@ -540,7 +651,6 @@ static void test_visitor_in_native_list_string(TestInputVisitorData *data, { UserDefNativeListUnion *cvalue = NULL; strList *elem = NULL; - Error *err = NULL; Visitor *v; GString *gstr_list = g_string_new(""); GString *gstr_union = g_string_new(""); @@ -556,12 +666,11 @@ static void test_visitor_in_native_list_string(TestInputVisitorData *data, gstr_list->str); v = visitor_input_test_init_raw(data, gstr_union->str); - visit_type_UserDefNativeListUnion(v, &cvalue, NULL, &err); - g_assert(err == NULL); + visit_type_UserDefNativeListUnion(v, NULL, &cvalue, &error_abort); g_assert(cvalue != NULL); - g_assert_cmpint(cvalue->kind, ==, USER_DEF_NATIVE_LIST_UNION_KIND_STRING); + g_assert_cmpint(cvalue->type, ==, USER_DEF_NATIVE_LIST_UNION_KIND_STRING); - for (i = 0, elem = cvalue->string; elem; elem = elem->next, i++) { + for (i = 0, elem = cvalue->u.string.data; elem; elem = elem->next, i++) { gchar str[8]; sprintf(str, "%d", i); g_assert_cmpstr(elem->value, ==, str); @@ -579,7 +688,6 @@ static void test_visitor_in_native_list_number(TestInputVisitorData *data, { UserDefNativeListUnion *cvalue = NULL; numberList *elem = NULL; - Error *err = NULL; Visitor *v; GString *gstr_list = g_string_new(""); GString *gstr_union = g_string_new(""); @@ -595,12 +703,11 @@ static void test_visitor_in_native_list_number(TestInputVisitorData *data, gstr_list->str); v = visitor_input_test_init_raw(data, gstr_union->str); - visit_type_UserDefNativeListUnion(v, &cvalue, NULL, &err); - g_assert(err == NULL); + visit_type_UserDefNativeListUnion(v, NULL, &cvalue, &error_abort); g_assert(cvalue != NULL); - g_assert_cmpint(cvalue->kind, ==, USER_DEF_NATIVE_LIST_UNION_KIND_NUMBER); + g_assert_cmpint(cvalue->type, ==, USER_DEF_NATIVE_LIST_UNION_KIND_NUMBER); - for (i = 0, elem = cvalue->number; elem; elem = elem->next, i++) { + for (i = 0, elem = cvalue->u.number.data; elem; elem = elem->next, i++) { GString *double_expected = g_string_new(""); GString *double_actual = g_string_new(""); @@ -631,16 +738,69 @@ static void test_visitor_in_errors(TestInputVisitorData *data, TestStruct *p = NULL; Error *err = NULL; Visitor *v; + strList *q = NULL; - v = visitor_input_test_init(data, "{ 'integer': false, 'boolean': 'foo', 'string': -42 }"); + v = visitor_input_test_init(data, "{ 'integer': false, 'boolean': 'foo', " + "'string': -42 }"); - visit_type_TestStruct(v, &p, NULL, &err); - g_assert(err); + visit_type_TestStruct(v, NULL, &p, &err); + error_free_or_abort(&err); + /* FIXME - a failed parse should not leave a partially-allocated p + * for us to clean up; this could cause callers to leak memory. */ g_assert(p->string == NULL); - error_free(err); g_free(p->string); g_free(p); + + v = visitor_input_test_init(data, "[ '1', '2', false, '3' ]"); + visit_type_strList(v, NULL, &q, &err); + error_free_or_abort(&err); + assert(q); + qapi_free_strList(q); +} + +static void test_visitor_in_wrong_type(TestInputVisitorData *data, + const void *unused) +{ + TestStruct *p = NULL; + Visitor *v; + strList *q = NULL; + int64_t i; + Error *err = NULL; + + /* Make sure arrays and structs cannot be confused */ + + v = visitor_input_test_init(data, "[]"); + visit_type_TestStruct(v, NULL, &p, &err); + error_free_or_abort(&err); + g_assert(!p); + + v = visitor_input_test_init(data, "{}"); + visit_type_strList(v, NULL, &q, &err); + error_free_or_abort(&err); + assert(!q); + + /* Make sure primitives and struct cannot be confused */ + + v = visitor_input_test_init(data, "1"); + visit_type_TestStruct(v, NULL, &p, &err); + error_free_or_abort(&err); + g_assert(!p); + + v = visitor_input_test_init(data, "{}"); + visit_type_int(v, NULL, &i, &err); + error_free_or_abort(&err); + + /* Make sure primitives and arrays cannot be confused */ + + v = visitor_input_test_init(data, "1"); + visit_type_strList(v, NULL, &q, &err); + error_free_or_abort(&err); + assert(!q); + + v = visitor_input_test_init(data, "[]"); + visit_type_int(v, NULL, &i, &err); + error_free_or_abort(&err); } int main(int argc, char **argv) @@ -667,12 +827,18 @@ int main(int argc, char **argv) &in_visitor_data, test_visitor_in_struct_nested); input_visitor_test_add("/visitor/input/list", &in_visitor_data, test_visitor_in_list); + input_visitor_test_add("/visitor/input/any", + &in_visitor_data, test_visitor_in_any); input_visitor_test_add("/visitor/input/union-flat", &in_visitor_data, test_visitor_in_union_flat); input_visitor_test_add("/visitor/input/alternate", &in_visitor_data, test_visitor_in_alternate); input_visitor_test_add("/visitor/input/errors", &in_visitor_data, test_visitor_in_errors); + input_visitor_test_add("/visitor/input/wrong-type", + &in_visitor_data, test_visitor_in_wrong_type); + input_visitor_test_add("/visitor/input/alternate-number", + &in_visitor_data, test_visitor_in_alternate_number); input_visitor_test_add("/visitor/input/native_list/int", &in_visitor_data, test_visitor_in_native_list_int); diff --git a/qemu/tests/test-qmp-output-visitor.c b/qemu/tests/test-qmp-output-visitor.c index 87ba350b4..c70926793 100644 --- a/qemu/tests/test-qmp-output-visitor.c +++ b/qemu/tests/test-qmp-output-visitor.c @@ -1,7 +1,7 @@ /* * QMP Output Visitor unit-tests. * - * Copyright (C) 2011, 2015 Red Hat Inc. + * Copyright (C) 2011-2016 Red Hat Inc. * * Authors: * Luiz Capitulino <lcapitulino@redhat.com> @@ -10,9 +10,11 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> #include "qemu-common.h" +#include "qapi/error.h" #include "qapi/qmp-output-visitor.h" #include "test-qapi-types.h" #include "test-qapi-visit.h" @@ -45,11 +47,9 @@ static void test_visitor_out_int(TestOutputVisitorData *data, const void *unused) { int64_t value = -42; - Error *err = NULL; QObject *obj; - visit_type_int(data->ov, &value, NULL, &err); - g_assert(!err); + visit_type_int(data->ov, NULL, &value, &error_abort); obj = qmp_output_get_qobject(data->qov); g_assert(obj != NULL); @@ -62,12 +62,10 @@ static void test_visitor_out_int(TestOutputVisitorData *data, static void test_visitor_out_bool(TestOutputVisitorData *data, const void *unused) { - Error *err = NULL; bool value = true; QObject *obj; - visit_type_bool(data->ov, &value, NULL, &err); - g_assert(!err); + visit_type_bool(data->ov, NULL, &value, &error_abort); obj = qmp_output_get_qobject(data->qov); g_assert(obj != NULL); @@ -81,11 +79,9 @@ static void test_visitor_out_number(TestOutputVisitorData *data, const void *unused) { double value = 3.14; - Error *err = NULL; QObject *obj; - visit_type_number(data->ov, &value, NULL, &err); - g_assert(!err); + visit_type_number(data->ov, NULL, &value, &error_abort); obj = qmp_output_get_qobject(data->qov); g_assert(obj != NULL); @@ -99,11 +95,9 @@ static void test_visitor_out_string(TestOutputVisitorData *data, const void *unused) { char *string = (char *) "Q E M U"; - Error *err = NULL; QObject *obj; - visit_type_str(data->ov, &string, NULL, &err); - g_assert(!err); + visit_type_str(data->ov, NULL, &string, &error_abort); obj = qmp_output_get_qobject(data->qov); g_assert(obj != NULL); @@ -117,12 +111,10 @@ static void test_visitor_out_no_string(TestOutputVisitorData *data, const void *unused) { char *string = NULL; - Error *err = NULL; QObject *obj; /* A null string should return "" */ - visit_type_str(data->ov, &string, NULL, &err); - g_assert(!err); + visit_type_str(data->ov, NULL, &string, &error_abort); obj = qmp_output_get_qobject(data->qov); g_assert(obj != NULL); @@ -135,13 +127,11 @@ static void test_visitor_out_no_string(TestOutputVisitorData *data, static void test_visitor_out_enum(TestOutputVisitorData *data, const void *unused) { - Error *err = NULL; QObject *obj; EnumOne i; - for (i = 0; i < ENUM_ONE_MAX; i++) { - visit_type_EnumOne(data->ov, &i, "unused", &err); - g_assert(!err); + for (i = 0; i < ENUM_ONE__MAX; i++) { + visit_type_EnumOne(data->ov, "unused", &i, &error_abort); obj = qmp_output_get_qobject(data->qov); g_assert(obj != NULL); @@ -155,52 +145,17 @@ static void test_visitor_out_enum(TestOutputVisitorData *data, static void test_visitor_out_enum_errors(TestOutputVisitorData *data, const void *unused) { - EnumOne i, bad_values[] = { ENUM_ONE_MAX, -1 }; + EnumOne i, bad_values[] = { ENUM_ONE__MAX, -1 }; Error *err; for (i = 0; i < ARRAY_SIZE(bad_values) ; i++) { err = NULL; - visit_type_EnumOne(data->ov, &bad_values[i], "unused", &err); + visit_type_EnumOne(data->ov, "unused", &bad_values[i], &err); g_assert(err); error_free(err); } } -typedef struct TestStruct -{ - int64_t integer; - bool boolean; - char *string; -} TestStruct; - -static void visit_type_TestStruct(Visitor *v, TestStruct **obj, - const char *name, Error **errp) -{ - Error *err = NULL; - - visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct), - &err); - if (err) { - goto out; - } - - visit_type_int(v, &(*obj)->integer, "integer", &err); - if (err) { - goto out_end; - } - visit_type_bool(v, &(*obj)->boolean, "boolean", &err); - if (err) { - goto out_end; - } - visit_type_str(v, &(*obj)->string, "string", &err); - -out_end: - error_propagate(errp, err); - err = NULL; - visit_end_struct(v, &err); -out: - error_propagate(errp, err); -} static void test_visitor_out_struct(TestOutputVisitorData *data, const void *unused) @@ -209,12 +164,10 @@ static void test_visitor_out_struct(TestOutputVisitorData *data, .boolean = false, .string = (char *) "foo"}; TestStruct *p = &test_struct; - Error *err = NULL; QObject *obj; QDict *qdict; - visit_type_TestStruct(data->ov, &p, NULL, &err); - g_assert(!err); + visit_type_TestStruct(data->ov, NULL, &p, &error_abort); obj = qmp_output_get_qobject(data->qov); g_assert(obj != NULL); @@ -233,7 +186,6 @@ static void test_visitor_out_struct_nested(TestOutputVisitorData *data, const void *unused) { int64_t value = 42; - Error *err = NULL; UserDefTwo *ud2; QObject *obj; QDict *qdict, *dict1, *dict2, *dict3, *userdef; @@ -250,20 +202,17 @@ static void test_visitor_out_struct_nested(TestOutputVisitorData *data, ud2->dict1->dict2 = g_malloc0(sizeof(*ud2->dict1->dict2)); ud2->dict1->dict2->userdef = g_new0(UserDefOne, 1); ud2->dict1->dict2->userdef->string = g_strdup(string); - ud2->dict1->dict2->userdef->base = g_new0(UserDefZero, 1); - ud2->dict1->dict2->userdef->base->integer = value; + ud2->dict1->dict2->userdef->integer = value; ud2->dict1->dict2->string = g_strdup(strings[2]); ud2->dict1->dict3 = g_malloc0(sizeof(*ud2->dict1->dict3)); ud2->dict1->has_dict3 = true; ud2->dict1->dict3->userdef = g_new0(UserDefOne, 1); ud2->dict1->dict3->userdef->string = g_strdup(string); - ud2->dict1->dict3->userdef->base = g_new0(UserDefZero, 1); - ud2->dict1->dict3->userdef->base->integer = value; + ud2->dict1->dict3->userdef->integer = value; ud2->dict1->dict3->string = g_strdup(strings[3]); - visit_type_UserDefTwo(data->ov, &ud2, "unused", &err); - g_assert(!err); + visit_type_UserDefTwo(data->ov, "unused", &ud2, &error_abort); obj = qmp_output_get_qobject(data->qov); g_assert(obj != NULL); @@ -300,9 +249,9 @@ static void test_visitor_out_struct_nested(TestOutputVisitorData *data, static void test_visitor_out_struct_errors(TestOutputVisitorData *data, const void *unused) { - EnumOne bad_values[] = { ENUM_ONE_MAX, -1 }; - UserDefZero b; - UserDefOne u = { .base = &b }, *pu = &u; + EnumOne bad_values[] = { ENUM_ONE__MAX, -1 }; + UserDefOne u = {0}; + UserDefOne *pu = &u; Error *err; int i; @@ -310,63 +259,39 @@ static void test_visitor_out_struct_errors(TestOutputVisitorData *data, err = NULL; u.has_enum1 = true; u.enum1 = bad_values[i]; - visit_type_UserDefOne(data->ov, &pu, "unused", &err); + visit_type_UserDefOne(data->ov, "unused", &pu, &err); g_assert(err); error_free(err); } } -typedef struct TestStructList -{ - union { - TestStruct *value; - uint64_t padding; - }; - struct TestStructList *next; -} TestStructList; - -static void visit_type_TestStructList(Visitor *v, TestStructList **obj, - const char *name, Error **errp) -{ - GenericList *i, **head = (GenericList **)obj; - - visit_start_list(v, name, errp); - - for (*head = i = visit_next_list(v, head, errp); i; i = visit_next_list(v, &i, errp)) { - TestStructList *native_i = (TestStructList *)i; - visit_type_TestStruct(v, &native_i->value, NULL, errp); - } - - visit_end_list(v, errp); -} static void test_visitor_out_list(TestOutputVisitorData *data, const void *unused) { - char *value_str = (char *) "list value"; + const char *value_str = "list value"; TestStructList *p, *head = NULL; const int max_items = 10; bool value_bool = true; int value_int = 10; - Error *err = NULL; QListEntry *entry; QObject *obj; QList *qlist; int i; + /* Build the list in reverse order... */ for (i = 0; i < max_items; i++) { p = g_malloc0(sizeof(*p)); p->value = g_malloc0(sizeof(*p->value)); - p->value->integer = value_int; + p->value->integer = value_int + (max_items - i - 1); p->value->boolean = value_bool; - p->value->string = value_str; + p->value->string = g_strdup(value_str); p->next = head; head = p; } - visit_type_TestStructList(data->ov, &head, NULL, &err); - g_assert(!err); + visit_type_TestStructList(data->ov, NULL, &head, &error_abort); obj = qmp_output_get_qobject(data->qov); g_assert(obj != NULL); @@ -375,6 +300,7 @@ static void test_visitor_out_list(TestOutputVisitorData *data, qlist = qobject_to_qlist(obj); g_assert(!qlist_empty(qlist)); + /* ...and ensure that the visitor sees it in order */ i = 0; QLIST_FOREACH_ENTRY(qlist, entry) { QDict *qdict; @@ -382,7 +308,7 @@ static void test_visitor_out_list(TestOutputVisitorData *data, g_assert(qobject_type(entry->value) == QTYPE_QDICT); qdict = qobject_to_qdict(entry->value); g_assert_cmpint(qdict_size(qdict), ==, 3); - g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, value_int); + g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, value_int + i); g_assert_cmpint(qdict_get_bool(qdict, "boolean"), ==, value_bool); g_assert_cmpstr(qdict_get_str(qdict, "string"), ==, value_str); i++; @@ -390,13 +316,7 @@ static void test_visitor_out_list(TestOutputVisitorData *data, g_assert_cmpint(i, ==, max_items); QDECREF(qlist); - - for (p = head; p;) { - TestStructList *tmp = p->next; - g_free(p->value); - g_free(p); - p = tmp; - } + qapi_free_TestStructList(head); } static void test_visitor_out_list_qapi_free(TestOutputVisitorData *data, @@ -416,8 +336,7 @@ static void test_visitor_out_list_qapi_free(TestOutputVisitorData *data, p->value->dict1->dict2 = g_new0(UserDefTwoDictDict, 1); p->value->dict1->dict2->userdef = g_new0(UserDefOne, 1); p->value->dict1->dict2->userdef->string = g_strdup(string); - p->value->dict1->dict2->userdef->base = g_new0(UserDefZero, 1); - p->value->dict1->dict2->userdef->base->integer = 42; + p->value->dict1->dict2->userdef->integer = 42; p->value->dict1->dict2->string = g_strdup(string); p->value->dict1->has_dict3 = false; @@ -428,23 +347,67 @@ static void test_visitor_out_list_qapi_free(TestOutputVisitorData *data, qapi_free_UserDefTwoList(head); } +static void test_visitor_out_any(TestOutputVisitorData *data, + const void *unused) +{ + QObject *qobj; + QInt *qint; + QBool *qbool; + QString *qstring; + QDict *qdict; + QObject *obj; + + qobj = QOBJECT(qint_from_int(-42)); + visit_type_any(data->ov, NULL, &qobj, &error_abort); + obj = qmp_output_get_qobject(data->qov); + g_assert(obj != NULL); + g_assert(qobject_type(obj) == QTYPE_QINT); + g_assert_cmpint(qint_get_int(qobject_to_qint(obj)), ==, -42); + qobject_decref(obj); + qobject_decref(qobj); + + qdict = qdict_new(); + qdict_put(qdict, "integer", qint_from_int(-42)); + qdict_put(qdict, "boolean", qbool_from_bool(true)); + qdict_put(qdict, "string", qstring_from_str("foo")); + qobj = QOBJECT(qdict); + visit_type_any(data->ov, NULL, &qobj, &error_abort); + qobject_decref(qobj); + obj = qmp_output_get_qobject(data->qov); + g_assert(obj != NULL); + qdict = qobject_to_qdict(obj); + g_assert(qdict); + qobj = qdict_get(qdict, "integer"); + g_assert(qobj); + qint = qobject_to_qint(qobj); + g_assert(qint); + g_assert_cmpint(qint_get_int(qint), ==, -42); + qobj = qdict_get(qdict, "boolean"); + g_assert(qobj); + qbool = qobject_to_qbool(qobj); + g_assert(qbool); + g_assert(qbool_get_bool(qbool) == true); + qobj = qdict_get(qdict, "string"); + g_assert(qobj); + qstring = qobject_to_qstring(qobj); + g_assert(qstring); + g_assert_cmpstr(qstring_get_str(qstring), ==, "foo"); + qobject_decref(obj); +} + static void test_visitor_out_union_flat(TestOutputVisitorData *data, const void *unused) { QObject *arg; QDict *qdict; - Error *err = NULL; - UserDefFlatUnion *tmp = g_malloc0(sizeof(UserDefFlatUnion)); - tmp->kind = ENUM_ONE_VALUE1; + tmp->enum1 = ENUM_ONE_VALUE1; tmp->string = g_strdup("str"); - tmp->value1 = g_malloc0(sizeof(UserDefA)); - /* TODO when generator bug is fixed: tmp->integer = 41; */ - tmp->value1->boolean = true; + tmp->integer = 41; + tmp->u.value1.boolean = true; - visit_type_UserDefFlatUnion(data->ov, &tmp, NULL, &err); - g_assert(err == NULL); + visit_type_UserDefFlatUnion(data->ov, NULL, &tmp, &error_abort); arg = qmp_output_get_qobject(data->qov); g_assert(qobject_type(arg) == QTYPE_QDICT); @@ -452,7 +415,7 @@ static void test_visitor_out_union_flat(TestOutputVisitorData *data, g_assert_cmpstr(qdict_get_str(qdict, "enum1"), ==, "value1"); g_assert_cmpstr(qdict_get_str(qdict, "string"), ==, "str"); - /* TODO g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, 41); */ + g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, 41); g_assert_cmpint(qdict_get_bool(qdict, "boolean"), ==, true); qapi_free_UserDefFlatUnion(tmp); @@ -463,20 +426,55 @@ static void test_visitor_out_alternate(TestOutputVisitorData *data, const void *unused) { QObject *arg; - Error *err = NULL; + UserDefAlternate *tmp; + QDict *qdict; - UserDefAlternate *tmp = g_malloc0(sizeof(UserDefAlternate)); - tmp->kind = USER_DEF_ALTERNATE_KIND_I; - tmp->i = 42; + tmp = g_new0(UserDefAlternate, 1); + tmp->type = QTYPE_QINT; + tmp->u.i = 42; - visit_type_UserDefAlternate(data->ov, &tmp, NULL, &err); - g_assert(err == NULL); + visit_type_UserDefAlternate(data->ov, NULL, &tmp, &error_abort); arg = qmp_output_get_qobject(data->qov); g_assert(qobject_type(arg) == QTYPE_QINT); g_assert_cmpint(qint_get_int(qobject_to_qint(arg)), ==, 42); qapi_free_UserDefAlternate(tmp); + qobject_decref(arg); + + tmp = g_new0(UserDefAlternate, 1); + tmp->type = QTYPE_QSTRING; + tmp->u.s = g_strdup("hello"); + + visit_type_UserDefAlternate(data->ov, NULL, &tmp, &error_abort); + arg = qmp_output_get_qobject(data->qov); + + g_assert(qobject_type(arg) == QTYPE_QSTRING); + g_assert_cmpstr(qstring_get_str(qobject_to_qstring(arg)), ==, "hello"); + + qapi_free_UserDefAlternate(tmp); + qobject_decref(arg); + + tmp = g_new0(UserDefAlternate, 1); + tmp->type = QTYPE_QDICT; + tmp->u.udfu.integer = 1; + tmp->u.udfu.string = g_strdup("str"); + tmp->u.udfu.enum1 = ENUM_ONE_VALUE1; + tmp->u.udfu.u.value1.boolean = true; + + visit_type_UserDefAlternate(data->ov, NULL, &tmp, &error_abort); + arg = qmp_output_get_qobject(data->qov); + + g_assert_cmpint(qobject_type(arg), ==, QTYPE_QDICT); + qdict = qobject_to_qdict(arg); + g_assert_cmpint(qdict_size(qdict), ==, 4); + g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, 1); + g_assert_cmpstr(qdict_get_str(qdict, "string"), ==, "str"); + g_assert_cmpstr(qdict_get_str(qdict, "enum1"), ==, "value1"); + g_assert_cmpint(qdict_get_bool(qdict, "boolean"), ==, true); + + qapi_free_UserDefAlternate(tmp); + qobject_decref(arg); } static void test_visitor_out_empty(TestOutputVisitorData *data, @@ -485,15 +483,18 @@ static void test_visitor_out_empty(TestOutputVisitorData *data, QObject *arg; arg = qmp_output_get_qobject(data->qov); - g_assert(!arg); + g_assert(qobject_type(arg) == QTYPE_QNULL); + /* Check that qnull reference counting is sane */ + g_assert(arg->refcnt == 2); + qobject_decref(arg); } static void init_native_list(UserDefNativeListUnion *cvalue) { int i; - switch (cvalue->kind) { + switch (cvalue->type) { case USER_DEF_NATIVE_LIST_UNION_KIND_INTEGER: { - intList **list = &cvalue->integer; + intList **list = &cvalue->u.integer.data; for (i = 0; i < 32; i++) { *list = g_new0(intList, 1); (*list)->value = i; @@ -503,7 +504,7 @@ static void init_native_list(UserDefNativeListUnion *cvalue) break; } case USER_DEF_NATIVE_LIST_UNION_KIND_S8: { - int8List **list = &cvalue->s8; + int8List **list = &cvalue->u.s8.data; for (i = 0; i < 32; i++) { *list = g_new0(int8List, 1); (*list)->value = i; @@ -513,7 +514,7 @@ static void init_native_list(UserDefNativeListUnion *cvalue) break; } case USER_DEF_NATIVE_LIST_UNION_KIND_S16: { - int16List **list = &cvalue->s16; + int16List **list = &cvalue->u.s16.data; for (i = 0; i < 32; i++) { *list = g_new0(int16List, 1); (*list)->value = i; @@ -523,7 +524,7 @@ static void init_native_list(UserDefNativeListUnion *cvalue) break; } case USER_DEF_NATIVE_LIST_UNION_KIND_S32: { - int32List **list = &cvalue->s32; + int32List **list = &cvalue->u.s32.data; for (i = 0; i < 32; i++) { *list = g_new0(int32List, 1); (*list)->value = i; @@ -533,7 +534,7 @@ static void init_native_list(UserDefNativeListUnion *cvalue) break; } case USER_DEF_NATIVE_LIST_UNION_KIND_S64: { - int64List **list = &cvalue->s64; + int64List **list = &cvalue->u.s64.data; for (i = 0; i < 32; i++) { *list = g_new0(int64List, 1); (*list)->value = i; @@ -543,7 +544,7 @@ static void init_native_list(UserDefNativeListUnion *cvalue) break; } case USER_DEF_NATIVE_LIST_UNION_KIND_U8: { - uint8List **list = &cvalue->u8; + uint8List **list = &cvalue->u.u8.data; for (i = 0; i < 32; i++) { *list = g_new0(uint8List, 1); (*list)->value = i; @@ -553,7 +554,7 @@ static void init_native_list(UserDefNativeListUnion *cvalue) break; } case USER_DEF_NATIVE_LIST_UNION_KIND_U16: { - uint16List **list = &cvalue->u16; + uint16List **list = &cvalue->u.u16.data; for (i = 0; i < 32; i++) { *list = g_new0(uint16List, 1); (*list)->value = i; @@ -563,7 +564,7 @@ static void init_native_list(UserDefNativeListUnion *cvalue) break; } case USER_DEF_NATIVE_LIST_UNION_KIND_U32: { - uint32List **list = &cvalue->u32; + uint32List **list = &cvalue->u.u32.data; for (i = 0; i < 32; i++) { *list = g_new0(uint32List, 1); (*list)->value = i; @@ -573,7 +574,7 @@ static void init_native_list(UserDefNativeListUnion *cvalue) break; } case USER_DEF_NATIVE_LIST_UNION_KIND_U64: { - uint64List **list = &cvalue->u64; + uint64List **list = &cvalue->u.u64.data; for (i = 0; i < 32; i++) { *list = g_new0(uint64List, 1); (*list)->value = i; @@ -583,7 +584,7 @@ static void init_native_list(UserDefNativeListUnion *cvalue) break; } case USER_DEF_NATIVE_LIST_UNION_KIND_BOOLEAN: { - boolList **list = &cvalue->boolean; + boolList **list = &cvalue->u.boolean.data; for (i = 0; i < 32; i++) { *list = g_new0(boolList, 1); (*list)->value = (i % 3 == 0); @@ -593,7 +594,7 @@ static void init_native_list(UserDefNativeListUnion *cvalue) break; } case USER_DEF_NATIVE_LIST_UNION_KIND_STRING: { - strList **list = &cvalue->string; + strList **list = &cvalue->u.string.data; for (i = 0; i < 32; i++) { *list = g_new0(strList, 1); (*list)->value = g_strdup_printf("%d", i); @@ -603,7 +604,7 @@ static void init_native_list(UserDefNativeListUnion *cvalue) break; } case USER_DEF_NATIVE_LIST_UNION_KIND_NUMBER: { - numberList **list = &cvalue->number; + numberList **list = &cvalue->u.number.data; for (i = 0; i < 32; i++) { *list = g_new0(numberList, 1); (*list)->value = (double)i / 3; @@ -709,17 +710,15 @@ static void test_native_list(TestOutputVisitorData *data, UserDefNativeListUnionKind kind) { UserDefNativeListUnion *cvalue = g_new0(UserDefNativeListUnion, 1); - Error *err = NULL; QObject *obj; - cvalue->kind = kind; + cvalue->type = kind; init_native_list(cvalue); - visit_type_UserDefNativeListUnion(data->ov, &cvalue, NULL, &err); - g_assert(err == NULL); + visit_type_UserDefNativeListUnion(data->ov, NULL, &cvalue, &error_abort); obj = qmp_output_get_qobject(data->qov); - check_native_list(obj, cvalue->kind); + check_native_list(obj, cvalue->type); qapi_free_UserDefNativeListUnion(cvalue); qobject_decref(obj); } @@ -832,6 +831,8 @@ int main(int argc, char **argv) &out_visitor_data, test_visitor_out_struct_errors); output_visitor_test_add("/visitor/output/list", &out_visitor_data, test_visitor_out_list); + output_visitor_test_add("/visitor/output/any", + &out_visitor_data, test_visitor_out_any); output_visitor_test_add("/visitor/output/list-qapi-free", &out_visitor_data, test_visitor_out_list_qapi_free); output_visitor_test_add("/visitor/output/union-flat", diff --git a/qemu/tests/test-rcu-list.c b/qemu/tests/test-rcu-list.c index daa8bf41d..79d375014 100644 --- a/qemu/tests/test-rcu-list.c +++ b/qemu/tests/test-rcu-list.c @@ -20,14 +20,10 @@ * Copyright (c) 2013 Mike D. Day, IBM Corporation. */ +#include "qemu/osdep.h" #include <glib.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> #include "qemu/atomic.h" #include "qemu/rcu.h" -#include "qemu/compiler.h" -#include "qemu/osdep.h" #include "qemu/thread.h" #include "qemu/rcu_queue.h" diff --git a/qemu/tests/test-rfifolock.c b/qemu/tests/test-rfifolock.c index 0572ebb42..9a3cb243b 100644 --- a/qemu/tests/test-rfifolock.c +++ b/qemu/tests/test-rfifolock.c @@ -10,6 +10,7 @@ * See the COPYING.LIB file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> #include "qemu-common.h" #include "qemu/rfifolock.h" diff --git a/qemu/tests/test-string-input-visitor.c b/qemu/tests/test-string-input-visitor.c index 8e3433e0c..9e6906a56 100644 --- a/qemu/tests/test-string-input-visitor.c +++ b/qemu/tests/test-string-input-visitor.c @@ -10,10 +10,11 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <stdarg.h> #include "qemu-common.h" +#include "qapi/error.h" #include "qapi/string-input-visitor.h" #include "test-qapi-types.h" #include "test-qapi-visit.h" @@ -59,7 +60,7 @@ static void test_visitor_in_int(TestInputVisitorData *data, v = visitor_input_test_init(data, "-42"); - visit_type_int(v, &res, NULL, &err); + visit_type_int(v, NULL, &res, &err); g_assert(!err); g_assert_cmpint(res, ==, value); } @@ -74,7 +75,7 @@ static void test_visitor_in_intList(TestInputVisitorData *data, v = visitor_input_test_init(data, "1,2,0,2-4,20,5-9,1-8"); - visit_type_int16List(v, &res, NULL, &error_abort); + visit_type_int16List(v, NULL, &res, &error_abort); tmp = res; while (i < sizeof(value) / sizeof(value[0])) { g_assert(tmp); @@ -100,42 +101,42 @@ static void test_visitor_in_bool(TestInputVisitorData *data, v = visitor_input_test_init(data, "true"); - visit_type_bool(v, &res, NULL, &err); + visit_type_bool(v, NULL, &res, &err); g_assert(!err); g_assert_cmpint(res, ==, true); visitor_input_teardown(data, unused); v = visitor_input_test_init(data, "yes"); - visit_type_bool(v, &res, NULL, &err); + visit_type_bool(v, NULL, &res, &err); g_assert(!err); g_assert_cmpint(res, ==, true); visitor_input_teardown(data, unused); v = visitor_input_test_init(data, "on"); - visit_type_bool(v, &res, NULL, &err); + visit_type_bool(v, NULL, &res, &err); g_assert(!err); g_assert_cmpint(res, ==, true); visitor_input_teardown(data, unused); v = visitor_input_test_init(data, "false"); - visit_type_bool(v, &res, NULL, &err); + visit_type_bool(v, NULL, &res, &err); g_assert(!err); g_assert_cmpint(res, ==, false); visitor_input_teardown(data, unused); v = visitor_input_test_init(data, "no"); - visit_type_bool(v, &res, NULL, &err); + visit_type_bool(v, NULL, &res, &err); g_assert(!err); g_assert_cmpint(res, ==, false); visitor_input_teardown(data, unused); v = visitor_input_test_init(data, "off"); - visit_type_bool(v, &res, NULL, &err); + visit_type_bool(v, NULL, &res, &err); g_assert(!err); g_assert_cmpint(res, ==, false); } @@ -149,7 +150,7 @@ static void test_visitor_in_number(TestInputVisitorData *data, v = visitor_input_test_init(data, "3.14"); - visit_type_number(v, &res, NULL, &err); + visit_type_number(v, NULL, &res, &err); g_assert(!err); g_assert_cmpfloat(res, ==, value); } @@ -163,7 +164,7 @@ static void test_visitor_in_string(TestInputVisitorData *data, v = visitor_input_test_init(data, value); - visit_type_str(v, &res, NULL, &err); + visit_type_str(v, NULL, &res, &err); g_assert(!err); g_assert_cmpstr(res, ==, value); @@ -182,7 +183,7 @@ static void test_visitor_in_enum(TestInputVisitorData *data, v = visitor_input_test_init(data, EnumOne_lookup[i]); - visit_type_EnumOne(v, &res, NULL, &err); + visit_type_EnumOne(v, NULL, &res, &err); g_assert(!err); g_assert_cmpint(i, ==, res); @@ -220,29 +221,29 @@ static void test_visitor_in_fuzz(TestInputVisitorData *data, } v = visitor_input_test_init(data, buf); - visit_type_int(v, &ires, NULL, NULL); + visit_type_int(v, NULL, &ires, NULL); visitor_input_teardown(data, NULL); v = visitor_input_test_init(data, buf); - visit_type_intList(v, &ilres, NULL, NULL); + visit_type_intList(v, NULL, &ilres, NULL); visitor_input_teardown(data, NULL); v = visitor_input_test_init(data, buf); - visit_type_bool(v, &bres, NULL, NULL); + visit_type_bool(v, NULL, &bres, NULL); visitor_input_teardown(data, NULL); v = visitor_input_test_init(data, buf); - visit_type_number(v, &nres, NULL, NULL); + visit_type_number(v, NULL, &nres, NULL); visitor_input_teardown(data, NULL); v = visitor_input_test_init(data, buf); sres = NULL; - visit_type_str(v, &sres, NULL, NULL); + visit_type_str(v, NULL, &sres, NULL); g_free(sres); visitor_input_teardown(data, NULL); v = visitor_input_test_init(data, buf); - visit_type_EnumOne(v, &eres, NULL, NULL); + visit_type_EnumOne(v, NULL, &eres, NULL); visitor_input_teardown(data, NULL); } } diff --git a/qemu/tests/test-string-output-visitor.c b/qemu/tests/test-string-output-visitor.c index 101fb27dd..1ecd75b85 100644 --- a/qemu/tests/test-string-output-visitor.c +++ b/qemu/tests/test-string-output-visitor.c @@ -10,9 +10,11 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> #include "qemu-common.h" +#include "qapi/error.h" #include "qapi/string-output-visitor.h" #include "test-qapi-types.h" #include "test-qapi-visit.h" @@ -61,7 +63,7 @@ static void test_visitor_out_int(TestOutputVisitorData *data, Error *err = NULL; char *str; - visit_type_int(data->ov, &value, NULL, &err); + visit_type_int(data->ov, NULL, &value, &err); g_assert(!err); str = string_output_get_string(data->sov); @@ -81,7 +83,7 @@ static void test_visitor_out_intList(TestOutputVisitorData *data, 3, 4, 5, 6, 11, 12, 13, 21, 22, INT64_MAX - 1, INT64_MAX}; intList *list = NULL, **tmp = &list; int i; - Error *errp = NULL; + Error *err = NULL; char *str; for (i = 0; i < sizeof(value) / sizeof(value[0]); i++) { @@ -90,8 +92,8 @@ static void test_visitor_out_intList(TestOutputVisitorData *data, tmp = &(*tmp)->next; } - visit_type_intList(data->ov, &list, NULL, &errp); - g_assert(errp == NULL); + visit_type_intList(data->ov, NULL, &list, &err); + g_assert(err == NULL); str = string_output_get_string(data->sov); g_assert(str != NULL); @@ -120,7 +122,7 @@ static void test_visitor_out_bool(TestOutputVisitorData *data, bool value = true; char *str; - visit_type_bool(data->ov, &value, NULL, &err); + visit_type_bool(data->ov, NULL, &value, &err); g_assert(!err); str = string_output_get_string(data->sov); @@ -136,7 +138,7 @@ static void test_visitor_out_number(TestOutputVisitorData *data, Error *err = NULL; char *str; - visit_type_number(data->ov, &value, NULL, &err); + visit_type_number(data->ov, NULL, &value, &err); g_assert(!err); str = string_output_get_string(data->sov); @@ -153,7 +155,7 @@ static void test_visitor_out_string(TestOutputVisitorData *data, Error *err = NULL; char *str; - visit_type_str(data->ov, &string, NULL, &err); + visit_type_str(data->ov, NULL, &string, &err); g_assert(!err); str = string_output_get_string(data->sov); @@ -174,7 +176,7 @@ static void test_visitor_out_no_string(TestOutputVisitorData *data, char *str; /* A null string should return "" */ - visit_type_str(data->ov, &string, NULL, &err); + visit_type_str(data->ov, NULL, &string, &err); g_assert(!err); str = string_output_get_string(data->sov); @@ -194,10 +196,10 @@ static void test_visitor_out_enum(TestOutputVisitorData *data, char *str; EnumOne i; - for (i = 0; i < ENUM_ONE_MAX; i++) { + for (i = 0; i < ENUM_ONE__MAX; i++) { char *str_human; - visit_type_EnumOne(data->ov, &i, "unused", &err); + visit_type_EnumOne(data->ov, "unused", &i, &err); g_assert(!err); str_human = g_strdup_printf("\"%s\"", EnumOne_lookup[i]); @@ -217,12 +219,12 @@ static void test_visitor_out_enum(TestOutputVisitorData *data, static void test_visitor_out_enum_errors(TestOutputVisitorData *data, const void *unused) { - EnumOne i, bad_values[] = { ENUM_ONE_MAX, -1 }; + EnumOne i, bad_values[] = { ENUM_ONE__MAX, -1 }; Error *err; for (i = 0; i < ARRAY_SIZE(bad_values) ; i++) { err = NULL; - visit_type_EnumOne(data->ov, &bad_values[i], "unused", &err); + visit_type_EnumOne(data->ov, "unused", &bad_values[i], &err); g_assert(err); error_free(err); } @@ -248,39 +250,39 @@ int main(int argc, char **argv) output_visitor_test_add("/string-visitor/output/int", &out_visitor_data, test_visitor_out_int, false); - output_visitor_test_add("/string-visitor/output/int", + output_visitor_test_add("/string-visitor/output/int-human", &out_visitor_data, test_visitor_out_int, true); output_visitor_test_add("/string-visitor/output/bool", &out_visitor_data, test_visitor_out_bool, false); - output_visitor_test_add("/string-visitor/output/bool", + output_visitor_test_add("/string-visitor/output/bool-human", &out_visitor_data, test_visitor_out_bool, true); output_visitor_test_add("/string-visitor/output/number", &out_visitor_data, test_visitor_out_number, false); - output_visitor_test_add("/string-visitor/output/number", + output_visitor_test_add("/string-visitor/output/number-human", &out_visitor_data, test_visitor_out_number, true); output_visitor_test_add("/string-visitor/output/string", &out_visitor_data, test_visitor_out_string, false); - output_visitor_test_add("/string-visitor/output/string", + output_visitor_test_add("/string-visitor/output/string-human", &out_visitor_data, test_visitor_out_string, true); output_visitor_test_add("/string-visitor/output/no-string", &out_visitor_data, test_visitor_out_no_string, false); - output_visitor_test_add("/string-visitor/output/no-string", + output_visitor_test_add("/string-visitor/output/no-string-human", &out_visitor_data, test_visitor_out_no_string, true); output_visitor_test_add("/string-visitor/output/enum", &out_visitor_data, test_visitor_out_enum, false); - output_visitor_test_add("/string-visitor/output/enum", + output_visitor_test_add("/string-visitor/output/enum-human", &out_visitor_data, test_visitor_out_enum, true); output_visitor_test_add("/string-visitor/output/enum-errors", &out_visitor_data, test_visitor_out_enum_errors, false); - output_visitor_test_add("/string-visitor/output/enum-errors", + output_visitor_test_add("/string-visitor/output/enum-errors-human", &out_visitor_data, test_visitor_out_enum_errors, true); output_visitor_test_add("/string-visitor/output/intList", &out_visitor_data, test_visitor_out_intList, false); - output_visitor_test_add("/string-visitor/output/intList", + output_visitor_test_add("/string-visitor/output/intList-human", &out_visitor_data, test_visitor_out_intList, true); g_test_run(); diff --git a/qemu/tests/test-thread-pool.c b/qemu/tests/test-thread-pool.c index 6a0b9813f..88dc7316b 100644 --- a/qemu/tests/test-thread-pool.c +++ b/qemu/tests/test-thread-pool.c @@ -1,8 +1,10 @@ +#include "qemu/osdep.h" #include <glib.h> #include "qemu-common.h" #include "block/aio.h" #include "block/thread-pool.h" #include "block/block.h" +#include "qapi/error.h" #include "qemu/timer.h" #include "qemu/error-report.h" @@ -229,9 +231,7 @@ int main(int argc, char **argv) ctx = aio_context_new(&local_error); if (!ctx) { - error_report("Failed to create AIO Context: '%s'", - error_get_pretty(local_error)); - error_free(local_error); + error_reportf_err(local_error, "Failed to create AIO Context: "); exit(1); } pool = aio_get_thread_pool(ctx); diff --git a/qemu/tests/test-throttle.c b/qemu/tests/test-throttle.c index 016844546..744a52436 100644 --- a/qemu/tests/test-throttle.c +++ b/qemu/tests/test-throttle.c @@ -12,9 +12,11 @@ * See the COPYING.LIB file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> #include <math.h> #include "block/aio.h" +#include "qapi/error.h" #include "qemu/throttle.h" #include "qemu/error-report.h" #include "block/throttle-groups.h" @@ -34,6 +36,9 @@ static bool double_cmp(double x, double y) /* tests for single bucket operations */ static void test_leak_bucket(void) { + throttle_config_init(&cfg); + bkt = cfg.buckets[THROTTLE_BPS_TOTAL]; + /* set initial value */ bkt.avg = 150; bkt.max = 15; @@ -56,13 +61,33 @@ static void test_leak_bucket(void) g_assert(bkt.avg == 150); g_assert(bkt.max == 15); g_assert(double_cmp(bkt.level, 0)); + + /* check that burst_level leaks correctly */ + bkt.burst_level = 6; + bkt.max = 250; + bkt.burst_length = 2; /* otherwise burst_level will not leak */ + throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 100); + g_assert(double_cmp(bkt.burst_level, 3.5)); + + throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 100); + g_assert(double_cmp(bkt.burst_level, 1)); + + throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 100); + g_assert(double_cmp(bkt.burst_level, 0)); + + throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 100); + g_assert(double_cmp(bkt.burst_level, 0)); } static void test_compute_wait(void) { + unsigned i; int64_t wait; int64_t result; + throttle_config_init(&cfg); + bkt = cfg.buckets[THROTTLE_BPS_TOTAL]; + /* no operation limit set */ bkt.avg = 0; bkt.max = 15; @@ -92,6 +117,27 @@ static void test_compute_wait(void) /* time required to do half an operation */ result = (int64_t) NANOSECONDS_PER_SECOND / 150 / 2; g_assert(wait == result); + + /* Perform I/O for 2.2 seconds at a rate of bkt.max */ + bkt.burst_length = 2; + bkt.level = 0; + bkt.avg = 10; + bkt.max = 200; + for (i = 0; i < 22; i++) { + double units = bkt.max / 10; + bkt.level += units; + bkt.burst_level += units; + throttle_leak_bucket(&bkt, NANOSECONDS_PER_SECOND / 10); + wait = throttle_compute_wait(&bkt); + g_assert(double_cmp(bkt.burst_level, 0)); + g_assert(double_cmp(bkt.level, (i + 1) * (bkt.max - bkt.avg) / 10)); + /* We can do bursts for the 2 seconds we have configured in + * burst_length. We have 100 extra miliseconds of burst + * because bkt.level has been leaking during this time. + * After that, we have to wait. */ + result = i < 21 ? 0 : 1.8 * NANOSECONDS_PER_SECOND; + g_assert(wait == result); + } } /* functions to test ThrottleState initialization/destroy methods */ @@ -221,6 +267,8 @@ static void set_cfg_value(bool is_max, int index, int value) { if (is_max) { cfg.buckets[index].max = value; + /* If max is set, avg should never be 0 */ + cfg.buckets[index].avg = MAX(cfg.buckets[index].avg, 1); } else { cfg.buckets[index].avg = value; } @@ -230,17 +278,17 @@ static void test_enabled(void) { int i; - memset(&cfg, 0, sizeof(cfg)); + throttle_config_init(&cfg); g_assert(!throttle_enabled(&cfg)); for (i = 0; i < BUCKETS_COUNT; i++) { - memset(&cfg, 0, sizeof(cfg)); + throttle_config_init(&cfg); set_cfg_value(false, i, 150); g_assert(throttle_enabled(&cfg)); } for (i = 0; i < BUCKETS_COUNT; i++) { - memset(&cfg, 0, sizeof(cfg)); + throttle_config_init(&cfg); set_cfg_value(false, i, -150); g_assert(!throttle_enabled(&cfg)); } @@ -253,32 +301,32 @@ static void test_conflicts_for_one_set(bool is_max, int read, int write) { - memset(&cfg, 0, sizeof(cfg)); - g_assert(!throttle_conflicting(&cfg)); + throttle_config_init(&cfg); + g_assert(throttle_is_valid(&cfg, NULL)); set_cfg_value(is_max, total, 1); set_cfg_value(is_max, read, 1); - g_assert(throttle_conflicting(&cfg)); + g_assert(!throttle_is_valid(&cfg, NULL)); - memset(&cfg, 0, sizeof(cfg)); + throttle_config_init(&cfg); set_cfg_value(is_max, total, 1); set_cfg_value(is_max, write, 1); - g_assert(throttle_conflicting(&cfg)); + g_assert(!throttle_is_valid(&cfg, NULL)); - memset(&cfg, 0, sizeof(cfg)); + throttle_config_init(&cfg); set_cfg_value(is_max, total, 1); set_cfg_value(is_max, read, 1); set_cfg_value(is_max, write, 1); - g_assert(throttle_conflicting(&cfg)); + g_assert(!throttle_is_valid(&cfg, NULL)); - memset(&cfg, 0, sizeof(cfg)); + throttle_config_init(&cfg); set_cfg_value(is_max, total, 1); - g_assert(!throttle_conflicting(&cfg)); + g_assert(throttle_is_valid(&cfg, NULL)); - memset(&cfg, 0, sizeof(cfg)); + throttle_config_init(&cfg); set_cfg_value(is_max, read, 1); set_cfg_value(is_max, write, 1); - g_assert(!throttle_conflicting(&cfg)); + g_assert(throttle_is_valid(&cfg, NULL)); } static void test_conflicting_config(void) @@ -312,9 +360,9 @@ static void test_is_valid_for_value(int value, bool should_be_valid) int is_max, index; for (is_max = 0; is_max < 2; is_max++) { for (index = 0; index < BUCKETS_COUNT; index++) { - memset(&cfg, 0, sizeof(cfg)); + throttle_config_init(&cfg); set_cfg_value(is_max, index, value); - g_assert(throttle_is_valid(&cfg) == should_be_valid); + g_assert(throttle_is_valid(&cfg, NULL) == should_be_valid); } } } @@ -329,6 +377,26 @@ static void test_is_valid(void) test_is_valid_for_value(1, true); } +static void test_max_is_missing_limit(void) +{ + int i; + + for (i = 0; i < BUCKETS_COUNT; i++) { + throttle_config_init(&cfg); + cfg.buckets[i].max = 100; + cfg.buckets[i].avg = 0; + g_assert(!throttle_is_valid(&cfg, NULL)); + + cfg.buckets[i].max = 0; + cfg.buckets[i].avg = 0; + g_assert(throttle_is_valid(&cfg, NULL)); + + cfg.buckets[i].max = 0; + cfg.buckets[i].avg = 100; + g_assert(throttle_is_valid(&cfg, NULL)); + } +} + static void test_have_timer(void) { /* zero structures */ @@ -529,7 +597,7 @@ static void test_groups(void) g_assert(bdrv1->throttle_state == bdrv3->throttle_state); /* Setting the config of a group member affects the whole group */ - memset(&cfg1, 0, sizeof(cfg1)); + throttle_config_init(&cfg1); cfg1.buckets[THROTTLE_BPS_READ].avg = 500000; cfg1.buckets[THROTTLE_BPS_WRITE].avg = 285000; cfg1.buckets[THROTTLE_OPS_READ].avg = 20000; @@ -561,21 +629,8 @@ static void test_groups(void) int main(int argc, char **argv) { - Error *local_error = NULL; - - qemu_init_main_loop(&local_error); + qemu_init_main_loop(&error_fatal); ctx = qemu_get_aio_context(); - - if (!ctx) { - error_report("Failed to create AIO Context: '%s'", - local_error ? error_get_pretty(local_error) : - "Failed to initialize the QEMU main loop"); - if (local_error) { - error_free(local_error); - } - exit(1); - } - bdrv_init(); do {} while (g_main_context_iteration(NULL, false)); @@ -591,6 +646,7 @@ int main(int argc, char **argv) g_test_add_func("/throttle/config/enabled", test_enabled); g_test_add_func("/throttle/config/conflicting", test_conflicting_config); g_test_add_func("/throttle/config/is_valid", test_is_valid); + g_test_add_func("/throttle/config/max", test_max_is_missing_limit); g_test_add_func("/throttle/config_functions", test_config_functions); g_test_add_func("/throttle/accounting", test_accounting); g_test_add_func("/throttle/groups", test_groups); diff --git a/qemu/tests/test-timed-average.c b/qemu/tests/test-timed-average.c new file mode 100644 index 000000000..1cc4ab302 --- /dev/null +++ b/qemu/tests/test-timed-average.c @@ -0,0 +1,90 @@ +/* + * Timed average computation tests + * + * Copyright Nodalink, EURL. 2014 + * + * Authors: + * Benoît Canet <benoit.canet@nodalink.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2 or later. + * See the COPYING.LIB file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include <glib.h> + +#include "qemu/timed-average.h" + +/* This is the clock for QEMU_CLOCK_VIRTUAL */ +static int64_t my_clock_value; + +int64_t cpu_get_clock(void) +{ + return my_clock_value; +} + +static void account(TimedAverage *ta) +{ + timed_average_account(ta, 1); + timed_average_account(ta, 5); + timed_average_account(ta, 2); + timed_average_account(ta, 4); + timed_average_account(ta, 3); +} + +static void test_average(void) +{ + TimedAverage ta; + uint64_t result; + int i; + + /* we will compute some average on a period of 1 second */ + timed_average_init(&ta, QEMU_CLOCK_VIRTUAL, NANOSECONDS_PER_SECOND); + + result = timed_average_min(&ta); + g_assert(result == 0); + result = timed_average_avg(&ta); + g_assert(result == 0); + result = timed_average_max(&ta); + g_assert(result == 0); + + for (i = 0; i < 100; i++) { + account(&ta); + result = timed_average_min(&ta); + g_assert(result == 1); + result = timed_average_avg(&ta); + g_assert(result == 3); + result = timed_average_max(&ta); + g_assert(result == 5); + my_clock_value += NANOSECONDS_PER_SECOND / 10; + } + + my_clock_value += NANOSECONDS_PER_SECOND * 100; + + result = timed_average_min(&ta); + g_assert(result == 0); + result = timed_average_avg(&ta); + g_assert(result == 0); + result = timed_average_max(&ta); + g_assert(result == 0); + + for (i = 0; i < 100; i++) { + account(&ta); + result = timed_average_min(&ta); + g_assert(result == 1); + result = timed_average_avg(&ta); + g_assert(result == 3); + result = timed_average_max(&ta); + g_assert(result == 5); + my_clock_value += NANOSECONDS_PER_SECOND / 10; + } +} + +int main(int argc, char **argv) +{ + /* tests in the same order as the header function declarations */ + g_test_init(&argc, &argv, NULL); + g_test_add_func("/timed-average/average", test_average); + return g_test_run(); +} + diff --git a/qemu/tests/test-visitor-serialization.c b/qemu/tests/test-visitor-serialization.c index fa86cae88..9adbc30a4 100644 --- a/qemu/tests/test-visitor-serialization.c +++ b/qemu/tests/test-visitor-serialization.c @@ -11,14 +11,14 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <stdlib.h> -#include <stdint.h> #include <float.h> #include "qemu-common.h" #include "test-qapi-types.h" #include "test-qapi-visit.h" +#include "qapi/error.h" #include "qapi/qmp/types.h" #include "qapi/qmp-input-visitor.h" #include "qapi/qmp-output-visitor.h" @@ -101,40 +101,40 @@ static void visit_primitive_type(Visitor *v, void **native, Error **errp) PrimitiveType *pt = *native; switch(pt->type) { case PTYPE_STRING: - visit_type_str(v, (char **)&pt->value.string, NULL, errp); + visit_type_str(v, NULL, (char **)&pt->value.string, errp); break; case PTYPE_BOOLEAN: - visit_type_bool(v, &pt->value.boolean, NULL, errp); + visit_type_bool(v, NULL, &pt->value.boolean, errp); break; case PTYPE_NUMBER: - visit_type_number(v, &pt->value.number, NULL, errp); + visit_type_number(v, NULL, &pt->value.number, errp); break; case PTYPE_INTEGER: - visit_type_int(v, &pt->value.integer, NULL, errp); + visit_type_int(v, NULL, &pt->value.integer, errp); break; case PTYPE_U8: - visit_type_uint8(v, &pt->value.u8, NULL, errp); + visit_type_uint8(v, NULL, &pt->value.u8, errp); break; case PTYPE_U16: - visit_type_uint16(v, &pt->value.u16, NULL, errp); + visit_type_uint16(v, NULL, &pt->value.u16, errp); break; case PTYPE_U32: - visit_type_uint32(v, &pt->value.u32, NULL, errp); + visit_type_uint32(v, NULL, &pt->value.u32, errp); break; case PTYPE_U64: - visit_type_uint64(v, &pt->value.u64, NULL, errp); + visit_type_uint64(v, NULL, &pt->value.u64, errp); break; case PTYPE_S8: - visit_type_int8(v, &pt->value.s8, NULL, errp); + visit_type_int8(v, NULL, &pt->value.s8, errp); break; case PTYPE_S16: - visit_type_int16(v, &pt->value.s16, NULL, errp); + visit_type_int16(v, NULL, &pt->value.s16, errp); break; case PTYPE_S32: - visit_type_int32(v, &pt->value.s32, NULL, errp); + visit_type_int32(v, NULL, &pt->value.s32, errp); break; case PTYPE_S64: - visit_type_int64(v, &pt->value.s64, NULL, errp); + visit_type_int64(v, NULL, &pt->value.s64, errp); break; case PTYPE_EOL: g_assert_not_reached(); @@ -146,80 +146,46 @@ static void visit_primitive_list(Visitor *v, void **native, Error **errp) PrimitiveList *pl = *native; switch (pl->type) { case PTYPE_STRING: - visit_type_strList(v, &pl->value.strings, NULL, errp); + visit_type_strList(v, NULL, &pl->value.strings, errp); break; case PTYPE_BOOLEAN: - visit_type_boolList(v, &pl->value.booleans, NULL, errp); + visit_type_boolList(v, NULL, &pl->value.booleans, errp); break; case PTYPE_NUMBER: - visit_type_numberList(v, &pl->value.numbers, NULL, errp); + visit_type_numberList(v, NULL, &pl->value.numbers, errp); break; case PTYPE_INTEGER: - visit_type_intList(v, &pl->value.integers, NULL, errp); + visit_type_intList(v, NULL, &pl->value.integers, errp); break; case PTYPE_S8: - visit_type_int8List(v, &pl->value.s8_integers, NULL, errp); + visit_type_int8List(v, NULL, &pl->value.s8_integers, errp); break; case PTYPE_S16: - visit_type_int16List(v, &pl->value.s16_integers, NULL, errp); + visit_type_int16List(v, NULL, &pl->value.s16_integers, errp); break; case PTYPE_S32: - visit_type_int32List(v, &pl->value.s32_integers, NULL, errp); + visit_type_int32List(v, NULL, &pl->value.s32_integers, errp); break; case PTYPE_S64: - visit_type_int64List(v, &pl->value.s64_integers, NULL, errp); + visit_type_int64List(v, NULL, &pl->value.s64_integers, errp); break; case PTYPE_U8: - visit_type_uint8List(v, &pl->value.u8_integers, NULL, errp); + visit_type_uint8List(v, NULL, &pl->value.u8_integers, errp); break; case PTYPE_U16: - visit_type_uint16List(v, &pl->value.u16_integers, NULL, errp); + visit_type_uint16List(v, NULL, &pl->value.u16_integers, errp); break; case PTYPE_U32: - visit_type_uint32List(v, &pl->value.u32_integers, NULL, errp); + visit_type_uint32List(v, NULL, &pl->value.u32_integers, errp); break; case PTYPE_U64: - visit_type_uint64List(v, &pl->value.u64_integers, NULL, errp); + visit_type_uint64List(v, NULL, &pl->value.u64_integers, errp); break; default: g_assert_not_reached(); } } -typedef struct TestStruct -{ - int64_t integer; - bool boolean; - char *string; -} TestStruct; - -static void visit_type_TestStruct(Visitor *v, TestStruct **obj, - const char *name, Error **errp) -{ - Error *err = NULL; - - visit_start_struct(v, (void **)obj, NULL, name, sizeof(TestStruct), &err); - if (err) { - goto out; - } - - visit_type_int(v, &(*obj)->integer, "integer", &err); - if (err) { - goto out_end; - } - visit_type_bool(v, &(*obj)->boolean, "boolean", &err); - if (err) { - goto out_end; - } - visit_type_str(v, &(*obj)->string, "string", &err); - -out_end: - error_propagate(errp, err); - err = NULL; - visit_end_struct(v, &err); -out: - error_propagate(errp, err); -} static TestStruct *struct_create(void) { @@ -247,7 +213,7 @@ static void struct_cleanup(TestStruct *ts) static void visit_struct(Visitor *v, void **native, Error **errp) { - visit_type_TestStruct(v, (TestStruct **)native, NULL, errp); + visit_type_TestStruct(v, NULL, (TestStruct **)native, errp); } static UserDefTwo *nested_struct_create(void) @@ -258,15 +224,13 @@ static UserDefTwo *nested_struct_create(void) udnp->dict1->string1 = strdup("test_string1"); udnp->dict1->dict2 = g_malloc0(sizeof(*udnp->dict1->dict2)); udnp->dict1->dict2->userdef = g_new0(UserDefOne, 1); - udnp->dict1->dict2->userdef->base = g_new0(UserDefZero, 1); - udnp->dict1->dict2->userdef->base->integer = 42; + udnp->dict1->dict2->userdef->integer = 42; udnp->dict1->dict2->userdef->string = strdup("test_string"); udnp->dict1->dict2->string = strdup("test_string2"); udnp->dict1->dict3 = g_malloc0(sizeof(*udnp->dict1->dict3)); udnp->dict1->has_dict3 = true; udnp->dict1->dict3->userdef = g_new0(UserDefOne, 1); - udnp->dict1->dict3->userdef->base = g_new0(UserDefZero, 1); - udnp->dict1->dict3->userdef->base->integer = 43; + udnp->dict1->dict3->userdef->integer = 43; udnp->dict1->dict3->userdef->string = strdup("test_string"); udnp->dict1->dict3->string = strdup("test_string3"); return udnp; @@ -278,15 +242,15 @@ static void nested_struct_compare(UserDefTwo *udnp1, UserDefTwo *udnp2) g_assert(udnp2); g_assert_cmpstr(udnp1->string0, ==, udnp2->string0); g_assert_cmpstr(udnp1->dict1->string1, ==, udnp2->dict1->string1); - g_assert_cmpint(udnp1->dict1->dict2->userdef->base->integer, ==, - udnp2->dict1->dict2->userdef->base->integer); + g_assert_cmpint(udnp1->dict1->dict2->userdef->integer, ==, + udnp2->dict1->dict2->userdef->integer); g_assert_cmpstr(udnp1->dict1->dict2->userdef->string, ==, udnp2->dict1->dict2->userdef->string); g_assert_cmpstr(udnp1->dict1->dict2->string, ==, udnp2->dict1->dict2->string); g_assert(udnp1->dict1->has_dict3 == udnp2->dict1->has_dict3); - g_assert_cmpint(udnp1->dict1->dict3->userdef->base->integer, ==, - udnp2->dict1->dict3->userdef->base->integer); + g_assert_cmpint(udnp1->dict1->dict3->userdef->integer, ==, + udnp2->dict1->dict3->userdef->integer); g_assert_cmpstr(udnp1->dict1->dict3->userdef->string, ==, udnp2->dict1->dict3->userdef->string); g_assert_cmpstr(udnp1->dict1->dict3->string, ==, @@ -300,12 +264,12 @@ static void nested_struct_cleanup(UserDefTwo *udnp) static void visit_nested_struct(Visitor *v, void **native, Error **errp) { - visit_type_UserDefTwo(v, (UserDefTwo **)native, NULL, errp); + visit_type_UserDefTwo(v, NULL, (UserDefTwo **)native, errp); } static void visit_nested_struct_list(Visitor *v, void **native, Error **errp) { - visit_type_UserDefTwoList(v, (UserDefTwoList **)native, NULL, errp); + visit_type_UserDefTwoList(v, NULL, (UserDefTwoList **)native, errp); } /* test cases */ @@ -338,14 +302,13 @@ static void test_primitives(gconstpointer opaque) const SerializeOps *ops = args->ops; PrimitiveType *pt = args->test_data; PrimitiveType *pt_copy = g_malloc0(sizeof(*pt_copy)); - Error *err = NULL; void *serialize_data; pt_copy->type = pt->type; - ops->serialize(pt, &serialize_data, visit_primitive_type, &err); - ops->deserialize((void **)&pt_copy, serialize_data, visit_primitive_type, &err); + ops->serialize(pt, &serialize_data, visit_primitive_type, &error_abort); + ops->deserialize((void **)&pt_copy, serialize_data, visit_primitive_type, + &error_abort); - g_assert(err == NULL); g_assert(pt_copy != NULL); if (pt->type == PTYPE_STRING) { g_assert_cmpstr(pt->value.string, ==, pt_copy->value.string); @@ -381,7 +344,6 @@ static void test_primitive_lists(gconstpointer opaque) PrimitiveList pl = { .value = { NULL } }; PrimitiveList pl_copy = { .value = { NULL } }; PrimitiveList *pl_copy_ptr = &pl_copy; - Error *err = NULL; void *serialize_data; void *cur_head = NULL; int i; @@ -528,10 +490,11 @@ static void test_primitive_lists(gconstpointer opaque) } } - ops->serialize((void **)&pl, &serialize_data, visit_primitive_list, &err); - ops->deserialize((void **)&pl_copy_ptr, serialize_data, visit_primitive_list, &err); + ops->serialize((void **)&pl, &serialize_data, visit_primitive_list, + &error_abort); + ops->deserialize((void **)&pl_copy_ptr, serialize_data, + visit_primitive_list, &error_abort); - g_assert(err == NULL); i = 0; /* compare our deserialized list of primitives to the original */ @@ -688,10 +651,8 @@ static void test_primitive_lists(gconstpointer opaque) g_assert_cmpint(i, ==, 33); ops->cleanup(serialize_data); - dealloc_helper(&pl, visit_primitive_list, &err); - g_assert(!err); - dealloc_helper(&pl_copy, visit_primitive_list, &err); - g_assert(!err); + dealloc_helper(&pl, visit_primitive_list, &error_abort); + dealloc_helper(&pl_copy, visit_primitive_list, &error_abort); g_free(args); } @@ -701,13 +662,12 @@ static void test_struct(gconstpointer opaque) const SerializeOps *ops = args->ops; TestStruct *ts = struct_create(); TestStruct *ts_copy = NULL; - Error *err = NULL; void *serialize_data; - ops->serialize(ts, &serialize_data, visit_struct, &err); - ops->deserialize((void **)&ts_copy, serialize_data, visit_struct, &err); + ops->serialize(ts, &serialize_data, visit_struct, &error_abort); + ops->deserialize((void **)&ts_copy, serialize_data, visit_struct, + &error_abort); - g_assert(err == NULL); struct_compare(ts, ts_copy); struct_cleanup(ts); @@ -723,14 +683,12 @@ static void test_nested_struct(gconstpointer opaque) const SerializeOps *ops = args->ops; UserDefTwo *udnp = nested_struct_create(); UserDefTwo *udnp_copy = NULL; - Error *err = NULL; void *serialize_data; - ops->serialize(udnp, &serialize_data, visit_nested_struct, &err); + ops->serialize(udnp, &serialize_data, visit_nested_struct, &error_abort); ops->deserialize((void **)&udnp_copy, serialize_data, visit_nested_struct, - &err); + &error_abort); - g_assert(err == NULL); nested_struct_compare(udnp, udnp_copy); nested_struct_cleanup(udnp); @@ -745,7 +703,6 @@ static void test_nested_struct_list(gconstpointer opaque) TestArgs *args = (TestArgs *) opaque; const SerializeOps *ops = args->ops; UserDefTwoList *listp = NULL, *tmp, *tmp_copy, *listp_copy = NULL; - Error *err = NULL; void *serialize_data; int i = 0; @@ -756,11 +713,10 @@ static void test_nested_struct_list(gconstpointer opaque) listp = tmp; } - ops->serialize(listp, &serialize_data, visit_nested_struct_list, &err); + ops->serialize(listp, &serialize_data, visit_nested_struct_list, + &error_abort); ops->deserialize((void **)&listp_copy, serialize_data, - visit_nested_struct_list, &err); - - g_assert(err == NULL); + visit_nested_struct_list, &error_abort); tmp = listp; tmp_copy = listp_copy; diff --git a/qemu/tests/test-vmstate.c b/qemu/tests/test-vmstate.c index 1d620e04f..713d4443b 100644 --- a/qemu/tests/test-vmstate.c +++ b/qemu/tests/test-vmstate.c @@ -22,12 +22,13 @@ * THE SOFTWARE. */ +#include "qemu/osdep.h" #include <glib.h> #include "qemu-common.h" #include "migration/migration.h" #include "migration/vmstate.h" -#include "block/coroutine.h" +#include "qemu/coroutine.h" static char temp_file[] = "/tmp/vmst.test.XXXXXX"; static int temp_fd; diff --git a/qemu/tests/test-write-threshold.c b/qemu/tests/test-write-threshold.c index faffa7b85..fdbc8020f 100644 --- a/qemu/tests/test-write-threshold.c +++ b/qemu/tests/test-write-threshold.c @@ -6,8 +6,8 @@ * */ +#include "qemu/osdep.h" #include <glib.h> -#include <stdint.h> #include "block/block_int.h" #include "block/write-threshold.h" diff --git a/qemu/tests/test-x86-cpuid.c b/qemu/tests/test-x86-cpuid.c index 6cd20d4a2..8eb0bc6ad 100644 --- a/qemu/tests/test-x86-cpuid.c +++ b/qemu/tests/test-x86-cpuid.c @@ -22,6 +22,7 @@ * THE SOFTWARE. */ +#include "qemu/osdep.h" #include <glib.h> #include "hw/i386/topology.h" diff --git a/qemu/tests/test-xbzrle.c b/qemu/tests/test-xbzrle.c index db93b0a3d..49f64195a 100644 --- a/qemu/tests/test-xbzrle.c +++ b/qemu/tests/test-xbzrle.c @@ -10,14 +10,9 @@ * See the COPYING file in the top-level directory. * */ -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <strings.h> -#include <string.h> -#include <sys/time.h> -#include <assert.h> +#include "qemu/osdep.h" #include "qemu-common.h" +#include "qemu/cutils.h" #include "include/migration/migration.h" #define PAGE_SIZE 4096 diff --git a/qemu/tests/tmp105-test.c b/qemu/tests/tmp105-test.c index 99db53819..235cae013 100644 --- a/qemu/tests/tmp105-test.c +++ b/qemu/tests/tmp105-test.c @@ -7,6 +7,7 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> #include "libqtest.h" diff --git a/qemu/tests/tpci200-test.c b/qemu/tests/tpci200-test.c index 9ae01277e..cb2b00ca8 100644 --- a/qemu/tests/tpci200-test.c +++ b/qemu/tests/tpci200-test.c @@ -7,10 +7,9 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <string.h> #include "libqtest.h" -#include "qemu/osdep.h" /* Tests only initialization so far. TODO: Replace with functional tests */ static void nop(void) diff --git a/qemu/tests/usb-hcd-ehci-test.c b/qemu/tests/usb-hcd-ehci-test.c index 75073bf24..a0f13ef40 100644 --- a/qemu/tests/usb-hcd-ehci-test.c +++ b/qemu/tests/usb-hcd-ehci-test.c @@ -7,12 +7,10 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <string.h> -#include <stdio.h> #include "libqtest.h" #include "libqos/pci-pc.h" -#include "qemu/osdep.h" #include "hw/usb/uhci-regs.h" #include "hw/usb/ehci-regs.h" #include "libqos/usb.h" diff --git a/qemu/tests/usb-hcd-ohci-test.c b/qemu/tests/usb-hcd-ohci-test.c index fa592d487..efd6669c7 100644 --- a/qemu/tests/usb-hcd-ohci-test.c +++ b/qemu/tests/usb-hcd-ohci-test.c @@ -7,10 +7,9 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <string.h> #include "libqtest.h" -#include "qemu/osdep.h" #include "libqos/usb.h" diff --git a/qemu/tests/usb-hcd-uhci-test.c b/qemu/tests/usb-hcd-uhci-test.c index a96b71683..71ff2ea18 100644 --- a/qemu/tests/usb-hcd-uhci-test.c +++ b/qemu/tests/usb-hcd-uhci-test.c @@ -7,10 +7,9 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <string.h> #include "libqtest.h" -#include "qemu/osdep.h" #include "libqos/usb.h" #include "hw/usb/uhci-regs.h" diff --git a/qemu/tests/usb-hcd-xhci-test.c b/qemu/tests/usb-hcd-xhci-test.c index 56ab36731..7e2e212df 100644 --- a/qemu/tests/usb-hcd-xhci-test.c +++ b/qemu/tests/usb-hcd-xhci-test.c @@ -7,10 +7,9 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <string.h> #include "libqtest.h" -#include "qemu/osdep.h" #include "libqos/usb.h" diff --git a/qemu/tests/vhost-user-bridge.c b/qemu/tests/vhost-user-bridge.c new file mode 100644 index 000000000..0779ba260 --- /dev/null +++ b/qemu/tests/vhost-user-bridge.c @@ -0,0 +1,1418 @@ +/* + * Vhost User Bridge + * + * Copyright (c) 2015 Red Hat, Inc. + * + * Authors: + * Victor Kaplansky <victork@redhat.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * later. See the COPYING file in the top-level directory. + */ + +/* + * TODO: + * - main should get parameters from the command line. + * - implement all request handlers. Still not implemented: + * vubr_get_queue_num_exec() + * vubr_send_rarp_exec() + * - test for broken requests and virtqueue. + * - implement features defined by Virtio 1.0 spec. + * - support mergeable buffers and indirect descriptors. + * - implement clean shutdown. + * - implement non-blocking writes to UDP backend. + * - implement polling strategy. + * - implement clean starting/stopping of vq processing + * - implement clean starting/stopping of used and buffers + * dirty page logging. + */ + +#define _FILE_OFFSET_BITS 64 + +#include "qemu/osdep.h" +#include <sys/socket.h> +#include <sys/un.h> +#include <sys/unistd.h> +#include <sys/mman.h> +#include <sys/eventfd.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <qemu/osdep.h> + +#include <linux/vhost.h> + +#include "qemu/atomic.h" +#include "standard-headers/linux/virtio_net.h" +#include "standard-headers/linux/virtio_ring.h" + +#define VHOST_USER_BRIDGE_DEBUG 1 + +#define DPRINT(...) \ + do { \ + if (VHOST_USER_BRIDGE_DEBUG) { \ + printf(__VA_ARGS__); \ + } \ + } while (0) + +typedef void (*CallbackFunc)(int sock, void *ctx); + +typedef struct Event { + void *ctx; + CallbackFunc callback; +} Event; + +typedef struct Dispatcher { + int max_sock; + fd_set fdset; + Event events[FD_SETSIZE]; +} Dispatcher; + +static void +vubr_die(const char *s) +{ + perror(s); + exit(1); +} + +static int +dispatcher_init(Dispatcher *dispr) +{ + FD_ZERO(&dispr->fdset); + dispr->max_sock = -1; + return 0; +} + +static int +dispatcher_add(Dispatcher *dispr, int sock, void *ctx, CallbackFunc cb) +{ + if (sock >= FD_SETSIZE) { + fprintf(stderr, + "Error: Failed to add new event. sock %d should be less than %d\n", + sock, FD_SETSIZE); + return -1; + } + + dispr->events[sock].ctx = ctx; + dispr->events[sock].callback = cb; + + FD_SET(sock, &dispr->fdset); + if (sock > dispr->max_sock) { + dispr->max_sock = sock; + } + DPRINT("Added sock %d for watching. max_sock: %d\n", + sock, dispr->max_sock); + return 0; +} + +/* dispatcher_remove() is not currently in use but may be useful + * in the future. */ +static int +dispatcher_remove(Dispatcher *dispr, int sock) +{ + if (sock >= FD_SETSIZE) { + fprintf(stderr, + "Error: Failed to remove event. sock %d should be less than %d\n", + sock, FD_SETSIZE); + return -1; + } + + FD_CLR(sock, &dispr->fdset); + DPRINT("Sock %d removed from dispatcher watch.\n", sock); + return 0; +} + +/* timeout in us */ +static int +dispatcher_wait(Dispatcher *dispr, uint32_t timeout) +{ + struct timeval tv; + tv.tv_sec = timeout / 1000000; + tv.tv_usec = timeout % 1000000; + + fd_set fdset = dispr->fdset; + + /* wait until some of sockets become readable. */ + int rc = select(dispr->max_sock + 1, &fdset, 0, 0, &tv); + + if (rc == -1) { + vubr_die("select"); + } + + /* Timeout */ + if (rc == 0) { + return 0; + } + + /* Now call callback for every ready socket. */ + + int sock; + for (sock = 0; sock < dispr->max_sock + 1; sock++) { + /* The callback on a socket can remove other sockets from the + * dispatcher, thus we have to check that the socket is + * still not removed from dispatcher's list + */ + if (FD_ISSET(sock, &fdset) && FD_ISSET(sock, &dispr->fdset)) { + Event *e = &dispr->events[sock]; + e->callback(sock, e->ctx); + } + } + + return 0; +} + +typedef struct VubrVirtq { + int call_fd; + int kick_fd; + uint32_t size; + uint16_t last_avail_index; + uint16_t last_used_index; + struct vring_desc *desc; + struct vring_avail *avail; + struct vring_used *used; + uint64_t log_guest_addr; + int enable; +} VubrVirtq; + +/* Based on qemu/hw/virtio/vhost-user.c */ + +#define VHOST_MEMORY_MAX_NREGIONS 8 +#define VHOST_USER_F_PROTOCOL_FEATURES 30 +/* v1.0 compliant. */ +#define VIRTIO_F_VERSION_1 32 + +#define VHOST_LOG_PAGE 4096 + +enum VhostUserProtocolFeature { + VHOST_USER_PROTOCOL_F_MQ = 0, + VHOST_USER_PROTOCOL_F_LOG_SHMFD = 1, + VHOST_USER_PROTOCOL_F_RARP = 2, + + VHOST_USER_PROTOCOL_F_MAX +}; + +#define VHOST_USER_PROTOCOL_FEATURE_MASK ((1 << VHOST_USER_PROTOCOL_F_MAX) - 1) + +typedef enum VhostUserRequest { + VHOST_USER_NONE = 0, + VHOST_USER_GET_FEATURES = 1, + VHOST_USER_SET_FEATURES = 2, + VHOST_USER_SET_OWNER = 3, + VHOST_USER_RESET_OWNER = 4, + VHOST_USER_SET_MEM_TABLE = 5, + VHOST_USER_SET_LOG_BASE = 6, + VHOST_USER_SET_LOG_FD = 7, + VHOST_USER_SET_VRING_NUM = 8, + VHOST_USER_SET_VRING_ADDR = 9, + VHOST_USER_SET_VRING_BASE = 10, + VHOST_USER_GET_VRING_BASE = 11, + VHOST_USER_SET_VRING_KICK = 12, + VHOST_USER_SET_VRING_CALL = 13, + VHOST_USER_SET_VRING_ERR = 14, + VHOST_USER_GET_PROTOCOL_FEATURES = 15, + VHOST_USER_SET_PROTOCOL_FEATURES = 16, + VHOST_USER_GET_QUEUE_NUM = 17, + VHOST_USER_SET_VRING_ENABLE = 18, + VHOST_USER_SEND_RARP = 19, + VHOST_USER_MAX +} VhostUserRequest; + +typedef struct VhostUserMemoryRegion { + uint64_t guest_phys_addr; + uint64_t memory_size; + uint64_t userspace_addr; + uint64_t mmap_offset; +} VhostUserMemoryRegion; + +typedef struct VhostUserMemory { + uint32_t nregions; + uint32_t padding; + VhostUserMemoryRegion regions[VHOST_MEMORY_MAX_NREGIONS]; +} VhostUserMemory; + +typedef struct VhostUserLog { + uint64_t mmap_size; + uint64_t mmap_offset; +} VhostUserLog; + +typedef struct VhostUserMsg { + VhostUserRequest request; + +#define VHOST_USER_VERSION_MASK (0x3) +#define VHOST_USER_REPLY_MASK (0x1<<2) + uint32_t flags; + uint32_t size; /* the following payload size */ + union { +#define VHOST_USER_VRING_IDX_MASK (0xff) +#define VHOST_USER_VRING_NOFD_MASK (0x1<<8) + uint64_t u64; + struct vhost_vring_state state; + struct vhost_vring_addr addr; + VhostUserMemory memory; + VhostUserLog log; + } payload; + int fds[VHOST_MEMORY_MAX_NREGIONS]; + int fd_num; +} QEMU_PACKED VhostUserMsg; + +#define VHOST_USER_HDR_SIZE offsetof(VhostUserMsg, payload.u64) + +/* The version of the protocol we support */ +#define VHOST_USER_VERSION (0x1) + +#define MAX_NR_VIRTQUEUE (8) + +typedef struct VubrDevRegion { + /* Guest Physical address. */ + uint64_t gpa; + /* Memory region size. */ + uint64_t size; + /* QEMU virtual address (userspace). */ + uint64_t qva; + /* Starting offset in our mmaped space. */ + uint64_t mmap_offset; + /* Start address of mmaped space. */ + uint64_t mmap_addr; +} VubrDevRegion; + +typedef struct VubrDev { + int sock; + Dispatcher dispatcher; + uint32_t nregions; + VubrDevRegion regions[VHOST_MEMORY_MAX_NREGIONS]; + VubrVirtq vq[MAX_NR_VIRTQUEUE]; + int log_call_fd; + uint64_t log_size; + uint8_t *log_table; + int backend_udp_sock; + struct sockaddr_in backend_udp_dest; + int ready; + uint64_t features; + int hdrlen; +} VubrDev; + +static const char *vubr_request_str[] = { + [VHOST_USER_NONE] = "VHOST_USER_NONE", + [VHOST_USER_GET_FEATURES] = "VHOST_USER_GET_FEATURES", + [VHOST_USER_SET_FEATURES] = "VHOST_USER_SET_FEATURES", + [VHOST_USER_SET_OWNER] = "VHOST_USER_SET_OWNER", + [VHOST_USER_RESET_OWNER] = "VHOST_USER_RESET_OWNER", + [VHOST_USER_SET_MEM_TABLE] = "VHOST_USER_SET_MEM_TABLE", + [VHOST_USER_SET_LOG_BASE] = "VHOST_USER_SET_LOG_BASE", + [VHOST_USER_SET_LOG_FD] = "VHOST_USER_SET_LOG_FD", + [VHOST_USER_SET_VRING_NUM] = "VHOST_USER_SET_VRING_NUM", + [VHOST_USER_SET_VRING_ADDR] = "VHOST_USER_SET_VRING_ADDR", + [VHOST_USER_SET_VRING_BASE] = "VHOST_USER_SET_VRING_BASE", + [VHOST_USER_GET_VRING_BASE] = "VHOST_USER_GET_VRING_BASE", + [VHOST_USER_SET_VRING_KICK] = "VHOST_USER_SET_VRING_KICK", + [VHOST_USER_SET_VRING_CALL] = "VHOST_USER_SET_VRING_CALL", + [VHOST_USER_SET_VRING_ERR] = "VHOST_USER_SET_VRING_ERR", + [VHOST_USER_GET_PROTOCOL_FEATURES] = "VHOST_USER_GET_PROTOCOL_FEATURES", + [VHOST_USER_SET_PROTOCOL_FEATURES] = "VHOST_USER_SET_PROTOCOL_FEATURES", + [VHOST_USER_GET_QUEUE_NUM] = "VHOST_USER_GET_QUEUE_NUM", + [VHOST_USER_SET_VRING_ENABLE] = "VHOST_USER_SET_VRING_ENABLE", + [VHOST_USER_SEND_RARP] = "VHOST_USER_SEND_RARP", + [VHOST_USER_MAX] = "VHOST_USER_MAX", +}; + +static void +print_buffer(uint8_t *buf, size_t len) +{ + int i; + printf("Raw buffer:\n"); + for (i = 0; i < len; i++) { + if (i % 16 == 0) { + printf("\n"); + } + if (i % 4 == 0) { + printf(" "); + } + printf("%02x ", buf[i]); + } + printf("\n............................................................\n"); +} + +/* Translate guest physical address to our virtual address. */ +static uint64_t +gpa_to_va(VubrDev *dev, uint64_t guest_addr) +{ + int i; + + /* Find matching memory region. */ + for (i = 0; i < dev->nregions; i++) { + VubrDevRegion *r = &dev->regions[i]; + + if ((guest_addr >= r->gpa) && (guest_addr < (r->gpa + r->size))) { + return guest_addr - r->gpa + r->mmap_addr + r->mmap_offset; + } + } + + assert(!"address not found in regions"); + return 0; +} + +/* Translate qemu virtual address to our virtual address. */ +static uint64_t +qva_to_va(VubrDev *dev, uint64_t qemu_addr) +{ + int i; + + /* Find matching memory region. */ + for (i = 0; i < dev->nregions; i++) { + VubrDevRegion *r = &dev->regions[i]; + + if ((qemu_addr >= r->qva) && (qemu_addr < (r->qva + r->size))) { + return qemu_addr - r->qva + r->mmap_addr + r->mmap_offset; + } + } + + assert(!"address not found in regions"); + return 0; +} + +static void +vubr_message_read(int conn_fd, VhostUserMsg *vmsg) +{ + char control[CMSG_SPACE(VHOST_MEMORY_MAX_NREGIONS * sizeof(int))] = { }; + struct iovec iov = { + .iov_base = (char *)vmsg, + .iov_len = VHOST_USER_HDR_SIZE, + }; + struct msghdr msg = { + .msg_iov = &iov, + .msg_iovlen = 1, + .msg_control = control, + .msg_controllen = sizeof(control), + }; + size_t fd_size; + struct cmsghdr *cmsg; + int rc; + + rc = recvmsg(conn_fd, &msg, 0); + + if (rc == 0) { + vubr_die("recvmsg"); + fprintf(stderr, "Peer disconnected.\n"); + exit(1); + } + if (rc < 0) { + vubr_die("recvmsg"); + } + + vmsg->fd_num = 0; + for (cmsg = CMSG_FIRSTHDR(&msg); + cmsg != NULL; + cmsg = CMSG_NXTHDR(&msg, cmsg)) + { + if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { + fd_size = cmsg->cmsg_len - CMSG_LEN(0); + vmsg->fd_num = fd_size / sizeof(int); + memcpy(vmsg->fds, CMSG_DATA(cmsg), fd_size); + break; + } + } + + if (vmsg->size > sizeof(vmsg->payload)) { + fprintf(stderr, + "Error: too big message request: %d, size: vmsg->size: %u, " + "while sizeof(vmsg->payload) = %zu\n", + vmsg->request, vmsg->size, sizeof(vmsg->payload)); + exit(1); + } + + if (vmsg->size) { + rc = read(conn_fd, &vmsg->payload, vmsg->size); + if (rc == 0) { + vubr_die("recvmsg"); + fprintf(stderr, "Peer disconnected.\n"); + exit(1); + } + if (rc < 0) { + vubr_die("recvmsg"); + } + + assert(rc == vmsg->size); + } +} + +static void +vubr_message_write(int conn_fd, VhostUserMsg *vmsg) +{ + int rc; + + do { + rc = write(conn_fd, vmsg, VHOST_USER_HDR_SIZE + vmsg->size); + } while (rc < 0 && errno == EINTR); + + if (rc < 0) { + vubr_die("write"); + } +} + +static void +vubr_backend_udp_sendbuf(VubrDev *dev, uint8_t *buf, size_t len) +{ + int slen = sizeof(struct sockaddr_in); + + if (sendto(dev->backend_udp_sock, buf, len, 0, + (struct sockaddr *) &dev->backend_udp_dest, slen) == -1) { + vubr_die("sendto()"); + } +} + +static int +vubr_backend_udp_recvbuf(VubrDev *dev, uint8_t *buf, size_t buflen) +{ + int slen = sizeof(struct sockaddr_in); + int rc; + + rc = recvfrom(dev->backend_udp_sock, buf, buflen, 0, + (struct sockaddr *) &dev->backend_udp_dest, + (socklen_t *)&slen); + if (rc == -1) { + vubr_die("recvfrom()"); + } + + return rc; +} + +static void +vubr_consume_raw_packet(VubrDev *dev, uint8_t *buf, uint32_t len) +{ + int hdrlen = dev->hdrlen; + DPRINT(" hdrlen = %d\n", dev->hdrlen); + + if (VHOST_USER_BRIDGE_DEBUG) { + print_buffer(buf, len); + } + vubr_backend_udp_sendbuf(dev, buf + hdrlen, len - hdrlen); +} + +/* Kick the log_call_fd if required. */ +static void +vubr_log_kick(VubrDev *dev) +{ + if (dev->log_call_fd != -1) { + DPRINT("Kicking the QEMU's log...\n"); + eventfd_write(dev->log_call_fd, 1); + } +} + +/* Kick the guest if necessary. */ +static void +vubr_virtqueue_kick(VubrVirtq *vq) +{ + if (!(vq->avail->flags & VRING_AVAIL_F_NO_INTERRUPT)) { + DPRINT("Kicking the guest...\n"); + eventfd_write(vq->call_fd, 1); + } +} + +static void +vubr_log_page(uint8_t *log_table, uint64_t page) +{ + DPRINT("Logged dirty guest page: %"PRId64"\n", page); + atomic_or(&log_table[page / 8], 1 << (page % 8)); +} + +static void +vubr_log_write(VubrDev *dev, uint64_t address, uint64_t length) +{ + uint64_t page; + + if (!(dev->features & (1ULL << VHOST_F_LOG_ALL)) || + !dev->log_table || !length) { + return; + } + + assert(dev->log_size > ((address + length - 1) / VHOST_LOG_PAGE / 8)); + + page = address / VHOST_LOG_PAGE; + while (page * VHOST_LOG_PAGE < address + length) { + vubr_log_page(dev->log_table, page); + page += VHOST_LOG_PAGE; + } + vubr_log_kick(dev); +} + +static void +vubr_post_buffer(VubrDev *dev, VubrVirtq *vq, uint8_t *buf, int32_t len) +{ + struct vring_desc *desc = vq->desc; + struct vring_avail *avail = vq->avail; + struct vring_used *used = vq->used; + uint64_t log_guest_addr = vq->log_guest_addr; + int32_t remaining_len = len; + + unsigned int size = vq->size; + + uint16_t avail_index = atomic_mb_read(&avail->idx); + + /* We check the available descriptors before posting the + * buffer, so here we assume that enough available + * descriptors. */ + assert(vq->last_avail_index != avail_index); + uint16_t a_index = vq->last_avail_index % size; + uint16_t u_index = vq->last_used_index % size; + uint16_t d_index = avail->ring[a_index]; + + int i = d_index; + uint32_t written_len = 0; + + do { + DPRINT("Post packet to guest on vq:\n"); + DPRINT(" size = %d\n", vq->size); + DPRINT(" last_avail_index = %d\n", vq->last_avail_index); + DPRINT(" last_used_index = %d\n", vq->last_used_index); + DPRINT(" a_index = %d\n", a_index); + DPRINT(" u_index = %d\n", u_index); + DPRINT(" d_index = %d\n", d_index); + DPRINT(" desc[%d].addr = 0x%016"PRIx64"\n", i, desc[i].addr); + DPRINT(" desc[%d].len = %d\n", i, desc[i].len); + DPRINT(" desc[%d].flags = %d\n", i, desc[i].flags); + DPRINT(" avail->idx = %d\n", avail_index); + DPRINT(" used->idx = %d\n", used->idx); + + if (!(desc[i].flags & VRING_DESC_F_WRITE)) { + /* FIXME: we should find writable descriptor. */ + fprintf(stderr, "Error: descriptor is not writable. Exiting.\n"); + exit(1); + } + + void *chunk_start = (void *)(uintptr_t)gpa_to_va(dev, desc[i].addr); + uint32_t chunk_len = desc[i].len; + uint32_t chunk_write_len = MIN(remaining_len, chunk_len); + + memcpy(chunk_start, buf + written_len, chunk_write_len); + vubr_log_write(dev, desc[i].addr, chunk_write_len); + remaining_len -= chunk_write_len; + written_len += chunk_write_len; + + if ((remaining_len == 0) || !(desc[i].flags & VRING_DESC_F_NEXT)) { + break; + } + + i = desc[i].next; + } while (1); + + if (remaining_len > 0) { + fprintf(stderr, + "Too long packet for RX, remaining_len = %d, Dropping...\n", + remaining_len); + return; + } + + /* Add descriptor to the used ring. */ + used->ring[u_index].id = d_index; + used->ring[u_index].len = len; + vubr_log_write(dev, + log_guest_addr + offsetof(struct vring_used, ring[u_index]), + sizeof(used->ring[u_index])); + + vq->last_avail_index++; + vq->last_used_index++; + + atomic_mb_set(&used->idx, vq->last_used_index); + vubr_log_write(dev, + log_guest_addr + offsetof(struct vring_used, idx), + sizeof(used->idx)); + + /* Kick the guest if necessary. */ + vubr_virtqueue_kick(vq); +} + +static int +vubr_process_desc(VubrDev *dev, VubrVirtq *vq) +{ + struct vring_desc *desc = vq->desc; + struct vring_avail *avail = vq->avail; + struct vring_used *used = vq->used; + uint64_t log_guest_addr = vq->log_guest_addr; + + unsigned int size = vq->size; + + uint16_t a_index = vq->last_avail_index % size; + uint16_t u_index = vq->last_used_index % size; + uint16_t d_index = avail->ring[a_index]; + + uint32_t i, len = 0; + size_t buf_size = 4096; + uint8_t buf[4096]; + + DPRINT("Chunks: "); + i = d_index; + do { + void *chunk_start = (void *)(uintptr_t)gpa_to_va(dev, desc[i].addr); + uint32_t chunk_len = desc[i].len; + + assert(!(desc[i].flags & VRING_DESC_F_WRITE)); + + if (len + chunk_len < buf_size) { + memcpy(buf + len, chunk_start, chunk_len); + DPRINT("%d ", chunk_len); + } else { + fprintf(stderr, "Error: too long packet. Dropping...\n"); + break; + } + + len += chunk_len; + + if (!(desc[i].flags & VRING_DESC_F_NEXT)) { + break; + } + + i = desc[i].next; + } while (1); + DPRINT("\n"); + + if (!len) { + return -1; + } + + /* Add descriptor to the used ring. */ + used->ring[u_index].id = d_index; + used->ring[u_index].len = len; + vubr_log_write(dev, + log_guest_addr + offsetof(struct vring_used, ring[u_index]), + sizeof(used->ring[u_index])); + + vubr_consume_raw_packet(dev, buf, len); + + return 0; +} + +static void +vubr_process_avail(VubrDev *dev, VubrVirtq *vq) +{ + struct vring_avail *avail = vq->avail; + struct vring_used *used = vq->used; + uint64_t log_guest_addr = vq->log_guest_addr; + + while (vq->last_avail_index != atomic_mb_read(&avail->idx)) { + vubr_process_desc(dev, vq); + vq->last_avail_index++; + vq->last_used_index++; + } + + atomic_mb_set(&used->idx, vq->last_used_index); + vubr_log_write(dev, + log_guest_addr + offsetof(struct vring_used, idx), + sizeof(used->idx)); +} + +static void +vubr_backend_recv_cb(int sock, void *ctx) +{ + VubrDev *dev = (VubrDev *) ctx; + VubrVirtq *rx_vq = &dev->vq[0]; + uint8_t buf[4096]; + struct virtio_net_hdr_v1 *hdr = (struct virtio_net_hdr_v1 *)buf; + int hdrlen = dev->hdrlen; + int buflen = sizeof(buf); + int len; + + if (!dev->ready) { + return; + } + + DPRINT("\n\n *** IN UDP RECEIVE CALLBACK ***\n\n"); + DPRINT(" hdrlen = %d\n", hdrlen); + + uint16_t avail_index = atomic_mb_read(&rx_vq->avail->idx); + + /* If there is no available descriptors, just do nothing. + * The buffer will be handled by next arrived UDP packet, + * or next kick on receive virtq. */ + if (rx_vq->last_avail_index == avail_index) { + DPRINT("Got UDP packet, but no available descriptors on RX virtq.\n"); + return; + } + + memset(buf, 0, hdrlen); + /* TODO: support mergeable buffers. */ + if (hdrlen == 12) + hdr->num_buffers = 1; + len = vubr_backend_udp_recvbuf(dev, buf + hdrlen, buflen - hdrlen); + + vubr_post_buffer(dev, rx_vq, buf, len + hdrlen); +} + +static void +vubr_kick_cb(int sock, void *ctx) +{ + VubrDev *dev = (VubrDev *) ctx; + eventfd_t kick_data; + ssize_t rc; + + rc = eventfd_read(sock, &kick_data); + if (rc == -1) { + vubr_die("eventfd_read()"); + } else { + DPRINT("Got kick_data: %016"PRIx64"\n", kick_data); + vubr_process_avail(dev, &dev->vq[1]); + } +} + +static int +vubr_none_exec(VubrDev *dev, VhostUserMsg *vmsg) +{ + DPRINT("Function %s() not implemented yet.\n", __func__); + return 0; +} + +static int +vubr_get_features_exec(VubrDev *dev, VhostUserMsg *vmsg) +{ + vmsg->payload.u64 = + ((1ULL << VIRTIO_NET_F_MRG_RXBUF) | + (1ULL << VHOST_F_LOG_ALL) | + (1ULL << VIRTIO_NET_F_GUEST_ANNOUNCE) | + (1ULL << VHOST_USER_F_PROTOCOL_FEATURES)); + + vmsg->size = sizeof(vmsg->payload.u64); + + DPRINT("Sending back to guest u64: 0x%016"PRIx64"\n", vmsg->payload.u64); + + /* Reply */ + return 1; +} + +static int +vubr_set_features_exec(VubrDev *dev, VhostUserMsg *vmsg) +{ + DPRINT("u64: 0x%016"PRIx64"\n", vmsg->payload.u64); + + dev->features = vmsg->payload.u64; + if ((dev->features & (1ULL << VIRTIO_F_VERSION_1)) || + (dev->features & (1ULL << VIRTIO_NET_F_MRG_RXBUF))) { + dev->hdrlen = 12; + } else { + dev->hdrlen = 10; + } + + return 0; +} + +static int +vubr_set_owner_exec(VubrDev *dev, VhostUserMsg *vmsg) +{ + return 0; +} + +static void +vubr_close_log(VubrDev *dev) +{ + if (dev->log_table) { + if (munmap(dev->log_table, dev->log_size) != 0) { + vubr_die("munmap()"); + } + + dev->log_table = 0; + } + if (dev->log_call_fd != -1) { + close(dev->log_call_fd); + dev->log_call_fd = -1; + } +} + +static int +vubr_reset_device_exec(VubrDev *dev, VhostUserMsg *vmsg) +{ + vubr_close_log(dev); + dev->ready = 0; + dev->features = 0; + return 0; +} + +static int +vubr_set_mem_table_exec(VubrDev *dev, VhostUserMsg *vmsg) +{ + int i; + VhostUserMemory *memory = &vmsg->payload.memory; + dev->nregions = memory->nregions; + + DPRINT("Nregions: %d\n", memory->nregions); + for (i = 0; i < dev->nregions; i++) { + void *mmap_addr; + VhostUserMemoryRegion *msg_region = &memory->regions[i]; + VubrDevRegion *dev_region = &dev->regions[i]; + + DPRINT("Region %d\n", i); + DPRINT(" guest_phys_addr: 0x%016"PRIx64"\n", + msg_region->guest_phys_addr); + DPRINT(" memory_size: 0x%016"PRIx64"\n", + msg_region->memory_size); + DPRINT(" userspace_addr 0x%016"PRIx64"\n", + msg_region->userspace_addr); + DPRINT(" mmap_offset 0x%016"PRIx64"\n", + msg_region->mmap_offset); + + dev_region->gpa = msg_region->guest_phys_addr; + dev_region->size = msg_region->memory_size; + dev_region->qva = msg_region->userspace_addr; + dev_region->mmap_offset = msg_region->mmap_offset; + + /* We don't use offset argument of mmap() since the + * mapped address has to be page aligned, and we use huge + * pages. */ + mmap_addr = mmap(0, dev_region->size + dev_region->mmap_offset, + PROT_READ | PROT_WRITE, MAP_SHARED, + vmsg->fds[i], 0); + + if (mmap_addr == MAP_FAILED) { + vubr_die("mmap"); + } + dev_region->mmap_addr = (uint64_t)(uintptr_t)mmap_addr; + DPRINT(" mmap_addr: 0x%016"PRIx64"\n", dev_region->mmap_addr); + + close(vmsg->fds[i]); + } + + return 0; +} + +static int +vubr_set_log_base_exec(VubrDev *dev, VhostUserMsg *vmsg) +{ + int fd; + uint64_t log_mmap_size, log_mmap_offset; + void *rc; + + assert(vmsg->fd_num == 1); + fd = vmsg->fds[0]; + + assert(vmsg->size == sizeof(vmsg->payload.log)); + log_mmap_offset = vmsg->payload.log.mmap_offset; + log_mmap_size = vmsg->payload.log.mmap_size; + DPRINT("Log mmap_offset: %"PRId64"\n", log_mmap_offset); + DPRINT("Log mmap_size: %"PRId64"\n", log_mmap_size); + + rc = mmap(0, log_mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, + log_mmap_offset); + if (rc == MAP_FAILED) { + vubr_die("mmap"); + } + dev->log_table = rc; + dev->log_size = log_mmap_size; + + vmsg->size = sizeof(vmsg->payload.u64); + /* Reply */ + return 1; +} + +static int +vubr_set_log_fd_exec(VubrDev *dev, VhostUserMsg *vmsg) +{ + assert(vmsg->fd_num == 1); + dev->log_call_fd = vmsg->fds[0]; + DPRINT("Got log_call_fd: %d\n", vmsg->fds[0]); + return 0; +} + +static int +vubr_set_vring_num_exec(VubrDev *dev, VhostUserMsg *vmsg) +{ + unsigned int index = vmsg->payload.state.index; + unsigned int num = vmsg->payload.state.num; + + DPRINT("State.index: %d\n", index); + DPRINT("State.num: %d\n", num); + dev->vq[index].size = num; + return 0; +} + +static int +vubr_set_vring_addr_exec(VubrDev *dev, VhostUserMsg *vmsg) +{ + struct vhost_vring_addr *vra = &vmsg->payload.addr; + unsigned int index = vra->index; + VubrVirtq *vq = &dev->vq[index]; + + DPRINT("vhost_vring_addr:\n"); + DPRINT(" index: %d\n", vra->index); + DPRINT(" flags: %d\n", vra->flags); + DPRINT(" desc_user_addr: 0x%016llx\n", vra->desc_user_addr); + DPRINT(" used_user_addr: 0x%016llx\n", vra->used_user_addr); + DPRINT(" avail_user_addr: 0x%016llx\n", vra->avail_user_addr); + DPRINT(" log_guest_addr: 0x%016llx\n", vra->log_guest_addr); + + vq->desc = (struct vring_desc *)(uintptr_t)qva_to_va(dev, vra->desc_user_addr); + vq->used = (struct vring_used *)(uintptr_t)qva_to_va(dev, vra->used_user_addr); + vq->avail = (struct vring_avail *)(uintptr_t)qva_to_va(dev, vra->avail_user_addr); + vq->log_guest_addr = vra->log_guest_addr; + + DPRINT("Setting virtq addresses:\n"); + DPRINT(" vring_desc at %p\n", vq->desc); + DPRINT(" vring_used at %p\n", vq->used); + DPRINT(" vring_avail at %p\n", vq->avail); + + vq->last_used_index = vq->used->idx; + return 0; +} + +static int +vubr_set_vring_base_exec(VubrDev *dev, VhostUserMsg *vmsg) +{ + unsigned int index = vmsg->payload.state.index; + unsigned int num = vmsg->payload.state.num; + + DPRINT("State.index: %d\n", index); + DPRINT("State.num: %d\n", num); + dev->vq[index].last_avail_index = num; + + return 0; +} + +static int +vubr_get_vring_base_exec(VubrDev *dev, VhostUserMsg *vmsg) +{ + unsigned int index = vmsg->payload.state.index; + + DPRINT("State.index: %d\n", index); + vmsg->payload.state.num = dev->vq[index].last_avail_index; + vmsg->size = sizeof(vmsg->payload.state); + /* FIXME: this is a work-around for a bug in QEMU enabling + * too early vrings. When protocol features are enabled, + * we have to respect * VHOST_USER_SET_VRING_ENABLE request. */ + dev->ready = 0; + + if (dev->vq[index].call_fd != -1) { + close(dev->vq[index].call_fd); + dispatcher_remove(&dev->dispatcher, dev->vq[index].call_fd); + dev->vq[index].call_fd = -1; + } + if (dev->vq[index].kick_fd != -1) { + close(dev->vq[index].kick_fd); + dispatcher_remove(&dev->dispatcher, dev->vq[index].kick_fd); + dev->vq[index].kick_fd = -1; + } + + /* Reply */ + return 1; +} + +static int +vubr_set_vring_kick_exec(VubrDev *dev, VhostUserMsg *vmsg) +{ + uint64_t u64_arg = vmsg->payload.u64; + int index = u64_arg & VHOST_USER_VRING_IDX_MASK; + + DPRINT("u64: 0x%016"PRIx64"\n", vmsg->payload.u64); + + assert((u64_arg & VHOST_USER_VRING_NOFD_MASK) == 0); + assert(vmsg->fd_num == 1); + + if (dev->vq[index].kick_fd != -1) { + close(dev->vq[index].kick_fd); + dispatcher_remove(&dev->dispatcher, dev->vq[index].kick_fd); + } + dev->vq[index].kick_fd = vmsg->fds[0]; + DPRINT("Got kick_fd: %d for vq: %d\n", vmsg->fds[0], index); + + if (index % 2 == 1) { + /* TX queue. */ + dispatcher_add(&dev->dispatcher, dev->vq[index].kick_fd, + dev, vubr_kick_cb); + + DPRINT("Waiting for kicks on fd: %d for vq: %d\n", + dev->vq[index].kick_fd, index); + } + /* We temporarily use this hack to determine that both TX and RX + * queues are set up and ready for processing. + * FIXME: we need to rely in VHOST_USER_SET_VRING_ENABLE and + * actual kicks. */ + if (dev->vq[0].kick_fd != -1 && + dev->vq[1].kick_fd != -1) { + dev->ready = 1; + DPRINT("vhost-user-bridge is ready for processing queues.\n"); + } + return 0; + +} + +static int +vubr_set_vring_call_exec(VubrDev *dev, VhostUserMsg *vmsg) +{ + uint64_t u64_arg = vmsg->payload.u64; + int index = u64_arg & VHOST_USER_VRING_IDX_MASK; + + DPRINT("u64: 0x%016"PRIx64"\n", vmsg->payload.u64); + assert((u64_arg & VHOST_USER_VRING_NOFD_MASK) == 0); + assert(vmsg->fd_num == 1); + + if (dev->vq[index].call_fd != -1) { + close(dev->vq[index].call_fd); + dispatcher_remove(&dev->dispatcher, dev->vq[index].call_fd); + } + dev->vq[index].call_fd = vmsg->fds[0]; + DPRINT("Got call_fd: %d for vq: %d\n", vmsg->fds[0], index); + + return 0; +} + +static int +vubr_set_vring_err_exec(VubrDev *dev, VhostUserMsg *vmsg) +{ + DPRINT("u64: 0x%016"PRIx64"\n", vmsg->payload.u64); + return 0; +} + +static int +vubr_get_protocol_features_exec(VubrDev *dev, VhostUserMsg *vmsg) +{ + vmsg->payload.u64 = 1ULL << VHOST_USER_PROTOCOL_F_LOG_SHMFD; + DPRINT("u64: 0x%016"PRIx64"\n", vmsg->payload.u64); + vmsg->size = sizeof(vmsg->payload.u64); + + /* Reply */ + return 1; +} + +static int +vubr_set_protocol_features_exec(VubrDev *dev, VhostUserMsg *vmsg) +{ + /* FIXME: unimplented */ + DPRINT("u64: 0x%016"PRIx64"\n", vmsg->payload.u64); + return 0; +} + +static int +vubr_get_queue_num_exec(VubrDev *dev, VhostUserMsg *vmsg) +{ + DPRINT("Function %s() not implemented yet.\n", __func__); + return 0; +} + +static int +vubr_set_vring_enable_exec(VubrDev *dev, VhostUserMsg *vmsg) +{ + unsigned int index = vmsg->payload.state.index; + unsigned int enable = vmsg->payload.state.num; + + DPRINT("State.index: %d\n", index); + DPRINT("State.enable: %d\n", enable); + dev->vq[index].enable = enable; + return 0; +} + +static int +vubr_send_rarp_exec(VubrDev *dev, VhostUserMsg *vmsg) +{ + DPRINT("Function %s() not implemented yet.\n", __func__); + return 0; +} + +static int +vubr_execute_request(VubrDev *dev, VhostUserMsg *vmsg) +{ + /* Print out generic part of the request. */ + DPRINT( + "================== Vhost user message from QEMU ==================\n"); + DPRINT("Request: %s (%d)\n", vubr_request_str[vmsg->request], + vmsg->request); + DPRINT("Flags: 0x%x\n", vmsg->flags); + DPRINT("Size: %d\n", vmsg->size); + + if (vmsg->fd_num) { + int i; + DPRINT("Fds:"); + for (i = 0; i < vmsg->fd_num; i++) { + DPRINT(" %d", vmsg->fds[i]); + } + DPRINT("\n"); + } + + switch (vmsg->request) { + case VHOST_USER_NONE: + return vubr_none_exec(dev, vmsg); + case VHOST_USER_GET_FEATURES: + return vubr_get_features_exec(dev, vmsg); + case VHOST_USER_SET_FEATURES: + return vubr_set_features_exec(dev, vmsg); + case VHOST_USER_SET_OWNER: + return vubr_set_owner_exec(dev, vmsg); + case VHOST_USER_RESET_OWNER: + return vubr_reset_device_exec(dev, vmsg); + case VHOST_USER_SET_MEM_TABLE: + return vubr_set_mem_table_exec(dev, vmsg); + case VHOST_USER_SET_LOG_BASE: + return vubr_set_log_base_exec(dev, vmsg); + case VHOST_USER_SET_LOG_FD: + return vubr_set_log_fd_exec(dev, vmsg); + case VHOST_USER_SET_VRING_NUM: + return vubr_set_vring_num_exec(dev, vmsg); + case VHOST_USER_SET_VRING_ADDR: + return vubr_set_vring_addr_exec(dev, vmsg); + case VHOST_USER_SET_VRING_BASE: + return vubr_set_vring_base_exec(dev, vmsg); + case VHOST_USER_GET_VRING_BASE: + return vubr_get_vring_base_exec(dev, vmsg); + case VHOST_USER_SET_VRING_KICK: + return vubr_set_vring_kick_exec(dev, vmsg); + case VHOST_USER_SET_VRING_CALL: + return vubr_set_vring_call_exec(dev, vmsg); + case VHOST_USER_SET_VRING_ERR: + return vubr_set_vring_err_exec(dev, vmsg); + case VHOST_USER_GET_PROTOCOL_FEATURES: + return vubr_get_protocol_features_exec(dev, vmsg); + case VHOST_USER_SET_PROTOCOL_FEATURES: + return vubr_set_protocol_features_exec(dev, vmsg); + case VHOST_USER_GET_QUEUE_NUM: + return vubr_get_queue_num_exec(dev, vmsg); + case VHOST_USER_SET_VRING_ENABLE: + return vubr_set_vring_enable_exec(dev, vmsg); + case VHOST_USER_SEND_RARP: + return vubr_send_rarp_exec(dev, vmsg); + + case VHOST_USER_MAX: + assert(vmsg->request != VHOST_USER_MAX); + } + return 0; +} + +static void +vubr_receive_cb(int sock, void *ctx) +{ + VubrDev *dev = (VubrDev *) ctx; + VhostUserMsg vmsg; + int reply_requested; + + vubr_message_read(sock, &vmsg); + reply_requested = vubr_execute_request(dev, &vmsg); + if (reply_requested) { + /* Set the version in the flags when sending the reply */ + vmsg.flags &= ~VHOST_USER_VERSION_MASK; + vmsg.flags |= VHOST_USER_VERSION; + vmsg.flags |= VHOST_USER_REPLY_MASK; + vubr_message_write(sock, &vmsg); + } +} + +static void +vubr_accept_cb(int sock, void *ctx) +{ + VubrDev *dev = (VubrDev *)ctx; + int conn_fd; + struct sockaddr_un un; + socklen_t len = sizeof(un); + + conn_fd = accept(sock, (struct sockaddr *) &un, &len); + if (conn_fd == -1) { + vubr_die("accept()"); + } + DPRINT("Got connection from remote peer on sock %d\n", conn_fd); + dispatcher_add(&dev->dispatcher, conn_fd, ctx, vubr_receive_cb); +} + +static VubrDev * +vubr_new(const char *path) +{ + VubrDev *dev = (VubrDev *) calloc(1, sizeof(VubrDev)); + dev->nregions = 0; + int i; + struct sockaddr_un un; + size_t len; + + for (i = 0; i < MAX_NR_VIRTQUEUE; i++) { + dev->vq[i] = (VubrVirtq) { + .call_fd = -1, .kick_fd = -1, + .size = 0, + .last_avail_index = 0, .last_used_index = 0, + .desc = 0, .avail = 0, .used = 0, + .enable = 0, + }; + } + + /* Init log */ + dev->log_call_fd = -1; + dev->log_size = 0; + dev->log_table = 0; + dev->ready = 0; + dev->features = 0; + + /* Get a UNIX socket. */ + dev->sock = socket(AF_UNIX, SOCK_STREAM, 0); + if (dev->sock == -1) { + vubr_die("socket"); + } + + un.sun_family = AF_UNIX; + strcpy(un.sun_path, path); + len = sizeof(un.sun_family) + strlen(path); + unlink(path); + + if (bind(dev->sock, (struct sockaddr *) &un, len) == -1) { + vubr_die("bind"); + } + + if (listen(dev->sock, 1) == -1) { + vubr_die("listen"); + } + + dispatcher_init(&dev->dispatcher); + dispatcher_add(&dev->dispatcher, dev->sock, (void *)dev, + vubr_accept_cb); + + DPRINT("Waiting for connections on UNIX socket %s ...\n", path); + return dev; +} + +static void +vubr_set_host(struct sockaddr_in *saddr, const char *host) +{ + if (isdigit(host[0])) { + if (!inet_aton(host, &saddr->sin_addr)) { + fprintf(stderr, "inet_aton() failed.\n"); + exit(1); + } + } else { + struct hostent *he = gethostbyname(host); + + if (!he) { + fprintf(stderr, "gethostbyname() failed.\n"); + exit(1); + } + saddr->sin_addr = *(struct in_addr *)he->h_addr; + } +} + +static void +vubr_backend_udp_setup(VubrDev *dev, + const char *local_host, + const char *local_port, + const char *remote_host, + const char *remote_port) +{ + int sock; + const char *r; + + int lport, rport; + + lport = strtol(local_port, (char **)&r, 0); + if (r == local_port) { + fprintf(stderr, "lport parsing failed.\n"); + exit(1); + } + + rport = strtol(remote_port, (char **)&r, 0); + if (r == remote_port) { + fprintf(stderr, "rport parsing failed.\n"); + exit(1); + } + + struct sockaddr_in si_local = { + .sin_family = AF_INET, + .sin_port = htons(lport), + }; + + vubr_set_host(&si_local, local_host); + + /* setup destination for sends */ + dev->backend_udp_dest = (struct sockaddr_in) { + .sin_family = AF_INET, + .sin_port = htons(rport), + }; + vubr_set_host(&dev->backend_udp_dest, remote_host); + + sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (sock == -1) { + vubr_die("socket"); + } + + if (bind(sock, (struct sockaddr *)&si_local, sizeof(si_local)) == -1) { + vubr_die("bind"); + } + + dev->backend_udp_sock = sock; + dispatcher_add(&dev->dispatcher, sock, dev, vubr_backend_recv_cb); + DPRINT("Waiting for data from udp backend on %s:%d...\n", + local_host, lport); +} + +static void +vubr_run(VubrDev *dev) +{ + while (1) { + /* timeout 200ms */ + dispatcher_wait(&dev->dispatcher, 200000); + /* Here one can try polling strategy. */ + } +} + +static int +vubr_parse_host_port(const char **host, const char **port, const char *buf) +{ + char *p = strchr(buf, ':'); + + if (!p) { + return -1; + } + *p = '\0'; + *host = strdup(buf); + *port = strdup(p + 1); + return 0; +} + +#define DEFAULT_UD_SOCKET "/tmp/vubr.sock" +#define DEFAULT_LHOST "127.0.0.1" +#define DEFAULT_LPORT "4444" +#define DEFAULT_RHOST "127.0.0.1" +#define DEFAULT_RPORT "5555" + +static const char *ud_socket_path = DEFAULT_UD_SOCKET; +static const char *lhost = DEFAULT_LHOST; +static const char *lport = DEFAULT_LPORT; +static const char *rhost = DEFAULT_RHOST; +static const char *rport = DEFAULT_RPORT; + +int +main(int argc, char *argv[]) +{ + VubrDev *dev; + int opt; + + while ((opt = getopt(argc, argv, "l:r:u:")) != -1) { + + switch (opt) { + case 'l': + if (vubr_parse_host_port(&lhost, &lport, optarg) < 0) { + goto out; + } + break; + case 'r': + if (vubr_parse_host_port(&rhost, &rport, optarg) < 0) { + goto out; + } + break; + case 'u': + ud_socket_path = strdup(optarg); + break; + default: + goto out; + } + } + + DPRINT("ud socket: %s\n", ud_socket_path); + DPRINT("local: %s:%s\n", lhost, lport); + DPRINT("remote: %s:%s\n", rhost, rport); + + dev = vubr_new(ud_socket_path); + if (!dev) { + return 1; + } + + vubr_backend_udp_setup(dev, lhost, lport, rhost, rport); + vubr_run(dev); + return 0; + +out: + fprintf(stderr, "Usage: %s ", argv[0]); + fprintf(stderr, "[-u ud_socket_path] [-l lhost:lport] [-r rhost:rport]\n"); + fprintf(stderr, "\t-u path to unix doman socket. default: %s\n", + DEFAULT_UD_SOCKET); + fprintf(stderr, "\t-l local host and port. default: %s:%s\n", + DEFAULT_LHOST, DEFAULT_LPORT); + fprintf(stderr, "\t-r remote host and port. default: %s:%s\n", + DEFAULT_RHOST, DEFAULT_RPORT); + + return 1; +} diff --git a/qemu/tests/vhost-user-test.c b/qemu/tests/vhost-user-test.c index 75fedf097..69615968c 100644 --- a/qemu/tests/vhost-user-test.c +++ b/qemu/tests/vhost-user-test.c @@ -8,11 +8,12 @@ * */ -#define QEMU_GLIB_COMPAT_H +#include "qemu/osdep.h" #include <glib.h> #include "libqtest.h" #include "qemu/option.h" +#include "qemu/range.h" #include "sysemu/char.h" #include "sysemu/sysemu.h" @@ -30,22 +31,15 @@ #define HAVE_MONOTONIC_TIME #endif -#if GLIB_CHECK_VERSION(2, 32, 0) -#define HAVE_MUTEX_INIT -#define HAVE_COND_INIT -#define HAVE_THREAD_NEW -#endif - #define QEMU_CMD_ACCEL " -machine accel=tcg" -#define QEMU_CMD_MEM " -m 512 -object memory-backend-file,id=mem,size=512M,"\ +#define QEMU_CMD_MEM " -m %d -object memory-backend-file,id=mem,size=%dM,"\ "mem-path=%s,share=on -numa node,memdev=mem" -#define QEMU_CMD_CHR " -chardev socket,id=chr0,path=%s" -#define QEMU_CMD_NETDEV " -netdev vhost-user,id=net0,chardev=chr0,vhostforce" -#define QEMU_CMD_NET " -device virtio-net-pci,netdev=net0 " -#define QEMU_CMD_ROM " -option-rom ../pc-bios/pxe-virtio.rom" +#define QEMU_CMD_CHR " -chardev socket,id=%s,path=%s" +#define QEMU_CMD_NETDEV " -netdev vhost-user,id=net0,chardev=%s,vhostforce" +#define QEMU_CMD_NET " -device virtio-net-pci,netdev=net0,romfile=./pc-bios/pxe-virtio.rom" #define QEMU_CMD QEMU_CMD_ACCEL QEMU_CMD_MEM QEMU_CMD_CHR \ - QEMU_CMD_NETDEV QEMU_CMD_NET QEMU_CMD_ROM + QEMU_CMD_NETDEV QEMU_CMD_NET #define HUGETLBFS_MAGIC 0x958458f6 @@ -53,6 +47,11 @@ #define VHOST_MEMORY_MAX_NREGIONS 8 +#define VHOST_USER_F_PROTOCOL_FEATURES 30 +#define VHOST_USER_PROTOCOL_F_LOG_SHMFD 1 + +#define VHOST_LOG_PAGE 0x1000 + typedef enum VhostUserRequest { VHOST_USER_NONE = 0, VHOST_USER_GET_FEATURES = 1, @@ -69,6 +68,9 @@ typedef enum VhostUserRequest { VHOST_USER_SET_VRING_KICK = 12, VHOST_USER_SET_VRING_CALL = 13, VHOST_USER_SET_VRING_ERR = 14, + VHOST_USER_GET_PROTOCOL_FEATURES = 15, + VHOST_USER_SET_PROTOCOL_FEATURES = 16, + VHOST_USER_SET_VRING_ENABLE = 18, VHOST_USER_MAX } VhostUserRequest; @@ -85,6 +87,11 @@ typedef struct VhostUserMemory { VhostUserMemoryRegion regions[VHOST_MEMORY_MAX_NREGIONS]; } VhostUserMemory; +typedef struct VhostUserLog { + uint64_t mmap_size; + uint64_t mmap_offset; +} VhostUserLog; + typedef struct VhostUserMsg { VhostUserRequest request; @@ -93,11 +100,14 @@ typedef struct VhostUserMsg { uint32_t flags; uint32_t size; /* the following payload size */ union { +#define VHOST_USER_VRING_IDX_MASK (0xff) +#define VHOST_USER_VRING_NOFD_MASK (0x1<<8) uint64_t u64; struct vhost_vring_state state; struct vhost_vring_addr addr; VhostUserMemory memory; - }; + VhostUserLog log; + } payload; } QEMU_PACKED VhostUserMsg; static VhostUserMsg m __attribute__ ((unused)); @@ -111,154 +121,104 @@ static VhostUserMsg m __attribute__ ((unused)); #define VHOST_USER_VERSION (0x1) /*****************************************************************************/ -int fds_num = 0, fds[VHOST_MEMORY_MAX_NREGIONS]; -static VhostUserMemory memory; -static GMutex *data_mutex; -static GCond *data_cond; - -static gint64 _get_time(void) -{ -#ifdef HAVE_MONOTONIC_TIME - return g_get_monotonic_time(); -#else - GTimeVal time; - g_get_current_time(&time); - - return time.tv_sec * G_TIME_SPAN_SECOND + time.tv_usec; -#endif -} - -static GMutex *_mutex_new(void) -{ - GMutex *mutex; - -#ifdef HAVE_MUTEX_INIT - mutex = g_new(GMutex, 1); - g_mutex_init(mutex); -#else - mutex = g_mutex_new(); -#endif - - return mutex; -} - -static void _mutex_free(GMutex *mutex) -{ -#ifdef HAVE_MUTEX_INIT - g_mutex_clear(mutex); - g_free(mutex); -#else - g_mutex_free(mutex); -#endif -} - -static GCond *_cond_new(void) -{ - GCond *cond; - -#ifdef HAVE_COND_INIT - cond = g_new(GCond, 1); - g_cond_init(cond); -#else - cond = g_cond_new(); -#endif - - return cond; -} - -static gboolean _cond_wait_until(GCond *cond, GMutex *mutex, gint64 end_time) +typedef struct TestServer { + gchar *socket_path; + gchar *mig_path; + gchar *chr_name; + CharDriverState *chr; + int fds_num; + int fds[VHOST_MEMORY_MAX_NREGIONS]; + VhostUserMemory memory; + GMutex data_mutex; + GCond data_cond; + int log_fd; + uint64_t rings; +} TestServer; + +#if !GLIB_CHECK_VERSION(2, 32, 0) +static gboolean g_cond_wait_until(CompatGCond cond, CompatGMutex mutex, + gint64 end_time) { gboolean ret = FALSE; -#ifdef HAVE_COND_INIT - ret = g_cond_wait_until(cond, mutex, end_time); -#else + end_time -= g_get_monotonic_time(); GTimeVal time = { end_time / G_TIME_SPAN_SECOND, end_time % G_TIME_SPAN_SECOND }; ret = g_cond_timed_wait(cond, mutex, &time); -#endif return ret; } - -static void _cond_free(GCond *cond) -{ -#ifdef HAVE_COND_INIT - g_cond_clear(cond); - g_free(cond); -#else - g_cond_free(cond); #endif -} -static GThread *_thread_new(const gchar *name, GThreadFunc func, gpointer data) -{ - GThread *thread = NULL; - GError *error = NULL; -#ifdef HAVE_THREAD_NEW - thread = g_thread_try_new(name, func, data, &error); -#else - thread = g_thread_create(func, data, TRUE, &error); -#endif - return thread; -} +static const char *tmpfs; +static const char *root; -static void read_guest_mem(void) +static void wait_for_fds(TestServer *s) { - uint32_t *guest_mem; gint64 end_time; - int i, j; - size_t size; - g_mutex_lock(data_mutex); + g_mutex_lock(&s->data_mutex); - end_time = _get_time() + 5 * G_TIME_SPAN_SECOND; - while (!fds_num) { - if (!_cond_wait_until(data_cond, data_mutex, end_time)) { + end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND; + while (!s->fds_num) { + if (!g_cond_wait_until(&s->data_cond, &s->data_mutex, end_time)) { /* timeout has passed */ - g_assert(fds_num); + g_assert(s->fds_num); break; } } /* check for sanity */ - g_assert_cmpint(fds_num, >, 0); - g_assert_cmpint(fds_num, ==, memory.nregions); + g_assert_cmpint(s->fds_num, >, 0); + g_assert_cmpint(s->fds_num, ==, s->memory.nregions); + + g_mutex_unlock(&s->data_mutex); +} + +static void read_guest_mem(const void *data) +{ + TestServer *s = (void *)data; + uint32_t *guest_mem; + int i, j; + size_t size; + + wait_for_fds(s); + + g_mutex_lock(&s->data_mutex); /* iterate all regions */ - for (i = 0; i < fds_num; i++) { + for (i = 0; i < s->fds_num; i++) { /* We'll check only the region statring at 0x0*/ - if (memory.regions[i].guest_phys_addr != 0x0) { + if (s->memory.regions[i].guest_phys_addr != 0x0) { continue; } - g_assert_cmpint(memory.regions[i].memory_size, >, 1024); + g_assert_cmpint(s->memory.regions[i].memory_size, >, 1024); - size = memory.regions[i].memory_size + memory.regions[i].mmap_offset; + size = s->memory.regions[i].memory_size + + s->memory.regions[i].mmap_offset; guest_mem = mmap(0, size, PROT_READ | PROT_WRITE, - MAP_SHARED, fds[i], 0); + MAP_SHARED, s->fds[i], 0); g_assert(guest_mem != MAP_FAILED); - guest_mem += (memory.regions[i].mmap_offset / sizeof(*guest_mem)); + guest_mem += (s->memory.regions[i].mmap_offset / sizeof(*guest_mem)); for (j = 0; j < 256; j++) { - uint32_t a = readl(memory.regions[i].guest_phys_addr + j*4); + uint32_t a = readl(s->memory.regions[i].guest_phys_addr + j*4); uint32_t b = guest_mem[j]; g_assert_cmpint(a, ==, b); } - munmap(guest_mem, memory.regions[i].memory_size); + munmap(guest_mem, s->memory.regions[i].memory_size); } - g_assert_cmpint(1, ==, 1); - g_mutex_unlock(data_mutex); + g_mutex_unlock(&s->data_mutex); } static void *thread_function(void *data) { - GMainLoop *loop; - loop = g_main_loop_new(NULL, FALSE); + GMainLoop *loop = data; g_main_loop_run(loop); return NULL; } @@ -270,7 +230,8 @@ static int chr_can_read(void *opaque) static void chr_read(void *opaque, const uint8_t *buf, int size) { - CharDriverState *chr = opaque; + TestServer *s = opaque; + CharDriverState *chr = s->chr; VhostUserMsg msg; uint8_t *p = (uint8_t *) &msg; int fd; @@ -280,20 +241,35 @@ static void chr_read(void *opaque, const uint8_t *buf, int size) return; } - g_mutex_lock(data_mutex); + g_mutex_lock(&s->data_mutex); memcpy(p, buf, VHOST_USER_HDR_SIZE); if (msg.size) { p += VHOST_USER_HDR_SIZE; - qemu_chr_fe_read_all(chr, p, msg.size); + g_assert_cmpint(qemu_chr_fe_read_all(chr, p, msg.size), ==, msg.size); } switch (msg.request) { case VHOST_USER_GET_FEATURES: /* send back features to qemu */ msg.flags |= VHOST_USER_REPLY_MASK; - msg.size = sizeof(m.u64); - msg.u64 = 0; + msg.size = sizeof(m.payload.u64); + msg.payload.u64 = 0x1ULL << VHOST_F_LOG_ALL | + 0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES; + p = (uint8_t *) &msg; + qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size); + break; + + case VHOST_USER_SET_FEATURES: + g_assert_cmpint(msg.payload.u64 & (0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES), + !=, 0ULL); + break; + + case VHOST_USER_GET_PROTOCOL_FEATURES: + /* send back features to qemu */ + msg.flags |= VHOST_USER_REPLY_MASK; + msg.size = sizeof(m.payload.u64); + msg.payload.u64 = 1 << VHOST_USER_PROTOCOL_F_LOG_SHMFD; p = (uint8_t *) &msg; qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size); break; @@ -301,19 +277,22 @@ static void chr_read(void *opaque, const uint8_t *buf, int size) case VHOST_USER_GET_VRING_BASE: /* send back vring base to qemu */ msg.flags |= VHOST_USER_REPLY_MASK; - msg.size = sizeof(m.state); - msg.state.num = 0; + msg.size = sizeof(m.payload.state); + msg.payload.state.num = 0; p = (uint8_t *) &msg; qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size); + + assert(msg.payload.state.index < 2); + s->rings &= ~(0x1ULL << msg.payload.state.index); break; case VHOST_USER_SET_MEM_TABLE: /* received the mem table */ - memcpy(&memory, &msg.memory, sizeof(msg.memory)); - fds_num = qemu_chr_fe_get_msgfds(chr, fds, sizeof(fds) / sizeof(int)); + memcpy(&s->memory, &msg.payload.memory, sizeof(msg.payload.memory)); + s->fds_num = qemu_chr_fe_get_msgfds(chr, s->fds, G_N_ELEMENTS(s->fds)); /* signal the test that it can continue */ - g_cond_signal(data_cond); + g_cond_signal(&s->data_cond); break; case VHOST_USER_SET_VRING_KICK: @@ -327,23 +306,38 @@ static void chr_read(void *opaque, const uint8_t *buf, int size) */ qemu_set_nonblock(fd); break; + + case VHOST_USER_SET_LOG_BASE: + if (s->log_fd != -1) { + close(s->log_fd); + s->log_fd = -1; + } + qemu_chr_fe_get_msgfds(chr, &s->log_fd, 1); + msg.flags |= VHOST_USER_REPLY_MASK; + msg.size = 0; + p = (uint8_t *) &msg; + qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE); + + g_cond_signal(&s->data_cond); + break; + + case VHOST_USER_SET_VRING_BASE: + assert(msg.payload.state.index < 2); + s->rings |= 0x1ULL << msg.payload.state.index; + break; + default: break; } - g_mutex_unlock(data_mutex); + + g_mutex_unlock(&s->data_mutex); } -static const char *init_hugepagefs(void) +static const char *init_hugepagefs(const char *path) { - const char *path; struct statfs fs; int ret; - path = getenv("QTEST_HUGETLBFS_PATH"); - if (!path) { - path = "/hugetlbfs"; - } - if (access(path, R_OK | W_OK | X_OK)) { g_test_message("access on path (%s): %s\n", path, strerror(errno)); return NULL; @@ -366,44 +360,294 @@ static const char *init_hugepagefs(void) return path; } +static TestServer *test_server_new(const gchar *name) +{ + TestServer *server = g_new0(TestServer, 1); + gchar *chr_path; + + server->socket_path = g_strdup_printf("%s/%s.sock", tmpfs, name); + server->mig_path = g_strdup_printf("%s/%s.mig", tmpfs, name); + + chr_path = g_strdup_printf("unix:%s,server,nowait", server->socket_path); + server->chr_name = g_strdup_printf("chr-%s", name); + server->chr = qemu_chr_new(server->chr_name, chr_path, NULL); + g_free(chr_path); + + qemu_chr_add_handlers(server->chr, chr_can_read, chr_read, NULL, server); + + g_mutex_init(&server->data_mutex); + g_cond_init(&server->data_cond); + + server->log_fd = -1; + + return server; +} + +#define GET_QEMU_CMD(s) \ + g_strdup_printf(QEMU_CMD, 512, 512, (root), (s)->chr_name, \ + (s)->socket_path, (s)->chr_name) + +#define GET_QEMU_CMDE(s, mem, extra, ...) \ + g_strdup_printf(QEMU_CMD extra, (mem), (mem), (root), (s)->chr_name, \ + (s)->socket_path, (s)->chr_name, ##__VA_ARGS__) + +static gboolean _test_server_free(TestServer *server) +{ + int i; + + qemu_chr_delete(server->chr); + + for (i = 0; i < server->fds_num; i++) { + close(server->fds[i]); + } + + if (server->log_fd != -1) { + close(server->log_fd); + } + + unlink(server->socket_path); + g_free(server->socket_path); + + unlink(server->mig_path); + g_free(server->mig_path); + + g_free(server->chr_name); + g_free(server); + + return FALSE; +} + +static void test_server_free(TestServer *server) +{ + g_idle_add((GSourceFunc)_test_server_free, server); +} + +static void wait_for_log_fd(TestServer *s) +{ + gint64 end_time; + + g_mutex_lock(&s->data_mutex); + end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND; + while (s->log_fd == -1) { + if (!g_cond_wait_until(&s->data_cond, &s->data_mutex, end_time)) { + /* timeout has passed */ + g_assert(s->log_fd != -1); + break; + } + } + + g_mutex_unlock(&s->data_mutex); +} + +static void write_guest_mem(TestServer *s, uint32_t seed) +{ + uint32_t *guest_mem; + int i, j; + size_t size; + + wait_for_fds(s); + + /* iterate all regions */ + for (i = 0; i < s->fds_num; i++) { + + /* We'll write only the region statring at 0x0 */ + if (s->memory.regions[i].guest_phys_addr != 0x0) { + continue; + } + + g_assert_cmpint(s->memory.regions[i].memory_size, >, 1024); + + size = s->memory.regions[i].memory_size + + s->memory.regions[i].mmap_offset; + + guest_mem = mmap(0, size, PROT_READ | PROT_WRITE, + MAP_SHARED, s->fds[i], 0); + + g_assert(guest_mem != MAP_FAILED); + guest_mem += (s->memory.regions[i].mmap_offset / sizeof(*guest_mem)); + + for (j = 0; j < 256; j++) { + guest_mem[j] = seed + j; + } + + munmap(guest_mem, s->memory.regions[i].memory_size); + break; + } +} + +static guint64 get_log_size(TestServer *s) +{ + guint64 log_size = 0; + int i; + + for (i = 0; i < s->memory.nregions; ++i) { + VhostUserMemoryRegion *reg = &s->memory.regions[i]; + guint64 last = range_get_last(reg->guest_phys_addr, + reg->memory_size); + log_size = MAX(log_size, last / (8 * VHOST_LOG_PAGE) + 1); + } + + return log_size; +} + +typedef struct TestMigrateSource { + GSource source; + TestServer *src; + TestServer *dest; +} TestMigrateSource; + +static gboolean +test_migrate_source_check(GSource *source) +{ + TestMigrateSource *t = (TestMigrateSource *)source; + gboolean overlap = t->src->rings && t->dest->rings; + + g_assert(!overlap); + + return FALSE; +} + +#if !GLIB_CHECK_VERSION(2,36,0) +/* this callback is unnecessary with glib >2.36, the default + * prepare for the source does the same */ +static gboolean +test_migrate_source_prepare(GSource *source, gint *timeout) +{ + *timeout = -1; + return FALSE; +} +#endif + +GSourceFuncs test_migrate_source_funcs = { +#if !GLIB_CHECK_VERSION(2,36,0) + .prepare = test_migrate_source_prepare, +#endif + .check = test_migrate_source_check, +}; + +static void test_migrate(void) +{ + TestServer *s = test_server_new("src"); + TestServer *dest = test_server_new("dest"); + char *uri = g_strdup_printf("%s%s", "unix:", dest->mig_path); + QTestState *global = global_qtest, *from, *to; + GSource *source; + gchar *cmd; + QDict *rsp; + guint8 *log; + guint64 size; + + cmd = GET_QEMU_CMDE(s, 2, ""); + from = qtest_start(cmd); + g_free(cmd); + + wait_for_fds(s); + size = get_log_size(s); + g_assert_cmpint(size, ==, (2 * 1024 * 1024) / (VHOST_LOG_PAGE * 8)); + + cmd = GET_QEMU_CMDE(dest, 2, " -incoming %s", uri); + to = qtest_init(cmd); + g_free(cmd); + + source = g_source_new(&test_migrate_source_funcs, + sizeof(TestMigrateSource)); + ((TestMigrateSource *)source)->src = s; + ((TestMigrateSource *)source)->dest = dest; + g_source_attach(source, NULL); + + /* slow down migration to have time to fiddle with log */ + /* TODO: qtest could learn to break on some places */ + rsp = qmp("{ 'execute': 'migrate_set_speed'," + "'arguments': { 'value': 10 } }"); + g_assert(qdict_haskey(rsp, "return")); + QDECREF(rsp); + + cmd = g_strdup_printf("{ 'execute': 'migrate'," + "'arguments': { 'uri': '%s' } }", + uri); + rsp = qmp(cmd); + g_free(cmd); + g_assert(qdict_haskey(rsp, "return")); + QDECREF(rsp); + + wait_for_log_fd(s); + + log = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, s->log_fd, 0); + g_assert(log != MAP_FAILED); + + /* modify first page */ + write_guest_mem(s, 0x42); + log[0] = 1; + munmap(log, size); + + /* speed things up */ + rsp = qmp("{ 'execute': 'migrate_set_speed'," + "'arguments': { 'value': 0 } }"); + g_assert(qdict_haskey(rsp, "return")); + QDECREF(rsp); + + qmp_eventwait("STOP"); + + global_qtest = to; + qmp_eventwait("RESUME"); + + read_guest_mem(dest); + + g_source_destroy(source); + g_source_unref(source); + + qtest_quit(to); + test_server_free(dest); + qtest_quit(from); + test_server_free(s); + g_free(uri); + + global_qtest = global; +} + int main(int argc, char **argv) { QTestState *s = NULL; - CharDriverState *chr = NULL; - const char *hugefs = 0; - char *socket_path = 0; - char *qemu_cmd = 0; - char *chr_path = 0; + TestServer *server = NULL; + const char *hugefs; + char *qemu_cmd = NULL; int ret; + char template[] = "/tmp/vhost-test-XXXXXX"; + GMainLoop *loop; + GThread *thread; g_test_init(&argc, &argv, NULL); module_call_init(MODULE_INIT_QOM); + qemu_add_opts(&qemu_chardev_opts); - hugefs = init_hugepagefs(); - if (!hugefs) { - return 0; + tmpfs = mkdtemp(template); + if (!tmpfs) { + g_test_message("mkdtemp on path (%s): %s\n", template, strerror(errno)); + } + g_assert(tmpfs); + + hugefs = getenv("QTEST_HUGETLBFS_PATH"); + if (hugefs) { + root = init_hugepagefs(hugefs); + g_assert(root); + } else { + root = tmpfs; } - socket_path = g_strdup_printf("/tmp/vhost-%d.sock", getpid()); - - /* create char dev and add read handlers */ - qemu_add_opts(&qemu_chardev_opts); - chr_path = g_strdup_printf("unix:%s,server,nowait", socket_path); - chr = qemu_chr_new("chr0", chr_path, NULL); - g_free(chr_path); - qemu_chr_add_handlers(chr, chr_can_read, chr_read, NULL, chr); + server = test_server_new("test"); + loop = g_main_loop_new(NULL, FALSE); /* run the main loop thread so the chardev may operate */ - data_mutex = _mutex_new(); - data_cond = _cond_new(); - _thread_new(NULL, thread_function, NULL); + thread = g_thread_new(NULL, thread_function, loop); + + qemu_cmd = GET_QEMU_CMD(server); - qemu_cmd = g_strdup_printf(QEMU_CMD, hugefs, socket_path); s = qtest_start(qemu_cmd); g_free(qemu_cmd); - qtest_add_func("/vhost-user/read-guest-mem", read_guest_mem); + qtest_add_data_func("/vhost-user/read-guest-mem", server, read_guest_mem); + qtest_add_func("/vhost-user/migrate", test_migrate); ret = g_test_run(); @@ -412,10 +656,22 @@ int main(int argc, char **argv) } /* cleanup */ - unlink(socket_path); - g_free(socket_path); - _cond_free(data_cond); - _mutex_free(data_mutex); + test_server_free(server); + + /* finish the helper thread and dispatch pending sources */ + g_main_loop_quit(loop); + g_thread_join(thread); + while (g_main_context_pending(NULL)) { + g_main_context_iteration (NULL, TRUE); + } + g_main_loop_unref(loop); + + ret = rmdir(tmpfs); + if (ret != 0) { + g_test_message("unable to rmdir: path (%s): %s\n", + tmpfs, strerror(errno)); + } + g_assert_cmpint(ret, ==, 0); return ret; } diff --git a/qemu/tests/virtio-9p-test.c b/qemu/tests/virtio-9p-test.c index 1fae47797..59d0f1fa9 100644 --- a/qemu/tests/virtio-9p-test.c +++ b/qemu/tests/virtio-9p-test.c @@ -7,12 +7,10 @@ * See the COPYING file in the top-level directory. */ -#include <stdlib.h> -#include <string.h> +#include "qemu/osdep.h" #include <glib.h> #include "libqtest.h" #include "qemu-common.h" -#include "qemu/osdep.h" /* Tests only initialization so far. TODO: Replace with functional tests */ static void pci_nop(void) diff --git a/qemu/tests/virtio-balloon-test.c b/qemu/tests/virtio-balloon-test.c index becebb51a..b010ce98e 100644 --- a/qemu/tests/virtio-balloon-test.c +++ b/qemu/tests/virtio-balloon-test.c @@ -7,10 +7,9 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <string.h> #include "libqtest.h" -#include "qemu/osdep.h" /* Tests only initialization so far. TODO: Replace with functional tests */ static void pci_nop(void) diff --git a/qemu/tests/virtio-blk-test.c b/qemu/tests/virtio-blk-test.c index 4078321a2..3a66630d7 100644 --- a/qemu/tests/virtio-blk-test.c +++ b/qemu/tests/virtio-blk-test.c @@ -8,11 +8,8 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <string.h> -#include <stdlib.h> -#include <unistd.h> -#include <stdio.h> #include "libqtest.h" #include "libqos/virtio.h" #include "libqos/virtio-pci.h" diff --git a/qemu/tests/virtio-console-test.c b/qemu/tests/virtio-console-test.c index 6be96e8c6..0b9c2a55e 100644 --- a/qemu/tests/virtio-console-test.c +++ b/qemu/tests/virtio-console-test.c @@ -7,10 +7,9 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <string.h> #include "libqtest.h" -#include "qemu/osdep.h" /* Tests only initialization so far. TODO: Replace with functional tests */ static void console_pci_nop(void) diff --git a/qemu/tests/virtio-net-test.c b/qemu/tests/virtio-net-test.c index ea7478c27..04cfcd594 100644 --- a/qemu/tests/virtio-net-test.c +++ b/qemu/tests/virtio-net-test.c @@ -7,23 +7,244 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <string.h> #include "libqtest.h" -#include "qemu/osdep.h" -#include "libqos/pci.h" +#include "qemu-common.h" +#include "qemu/sockets.h" +#include "qemu/iov.h" +#include "libqos/pci-pc.h" +#include "libqos/virtio.h" +#include "libqos/virtio-pci.h" +#include "libqos/malloc.h" +#include "libqos/malloc-pc.h" +#include "libqos/malloc-generic.h" +#include "qemu/bswap.h" +#include "hw/virtio/virtio-net.h" #define PCI_SLOT_HP 0x06 +#define PCI_SLOT 0x04 +#define PCI_FN 0x00 + +#define QVIRTIO_NET_TIMEOUT_US (30 * 1000 * 1000) +#define VNET_HDR_SIZE sizeof(struct virtio_net_hdr_mrg_rxbuf) + +static void test_end(void) +{ + qtest_end(); +} + +#ifndef _WIN32 + +static QVirtioPCIDevice *virtio_net_pci_init(QPCIBus *bus, int slot) +{ + QVirtioPCIDevice *dev; + + dev = qvirtio_pci_device_find(bus, QVIRTIO_NET_DEVICE_ID); + g_assert(dev != NULL); + g_assert_cmphex(dev->vdev.device_type, ==, QVIRTIO_NET_DEVICE_ID); + + qvirtio_pci_device_enable(dev); + qvirtio_reset(&qvirtio_pci, &dev->vdev); + qvirtio_set_acknowledge(&qvirtio_pci, &dev->vdev); + qvirtio_set_driver(&qvirtio_pci, &dev->vdev); + + return dev; +} + +static QPCIBus *pci_test_start(int socket) +{ + char *cmdline; + + cmdline = g_strdup_printf("-netdev socket,fd=%d,id=hs0 -device " + "virtio-net-pci,netdev=hs0", socket); + qtest_start(cmdline); + g_free(cmdline); + + return qpci_init_pc(); +} + +static void driver_init(const QVirtioBus *bus, QVirtioDevice *dev) +{ + uint32_t features; + + features = qvirtio_get_features(bus, dev); + features = features & ~(QVIRTIO_F_BAD_FEATURE | + QVIRTIO_F_RING_INDIRECT_DESC | + QVIRTIO_F_RING_EVENT_IDX); + qvirtio_set_features(bus, dev, features); + + qvirtio_set_driver_ok(bus, dev); +} + +static void rx_test(const QVirtioBus *bus, QVirtioDevice *dev, + QGuestAllocator *alloc, QVirtQueue *vq, + int socket) +{ + uint64_t req_addr; + uint32_t free_head; + char test[] = "TEST"; + char buffer[64]; + int len = htonl(sizeof(test)); + struct iovec iov[] = { + { + .iov_base = &len, + .iov_len = sizeof(len), + }, { + .iov_base = test, + .iov_len = sizeof(test), + }, + }; + int ret; + + req_addr = guest_alloc(alloc, 64); + + free_head = qvirtqueue_add(vq, req_addr, 64, true, false); + qvirtqueue_kick(bus, dev, vq, free_head); + + ret = iov_send(socket, iov, 2, 0, sizeof(len) + sizeof(test)); + g_assert_cmpint(ret, ==, sizeof(test) + sizeof(len)); + + qvirtio_wait_queue_isr(bus, dev, vq, QVIRTIO_NET_TIMEOUT_US); + memread(req_addr + VNET_HDR_SIZE, buffer, sizeof(test)); + g_assert_cmpstr(buffer, ==, "TEST"); + + guest_free(alloc, req_addr); +} + +static void tx_test(const QVirtioBus *bus, QVirtioDevice *dev, + QGuestAllocator *alloc, QVirtQueue *vq, + int socket) +{ + uint64_t req_addr; + uint32_t free_head; + uint32_t len; + char buffer[64]; + int ret; + + req_addr = guest_alloc(alloc, 64); + memwrite(req_addr + VNET_HDR_SIZE, "TEST", 4); + + free_head = qvirtqueue_add(vq, req_addr, 64, false, false); + qvirtqueue_kick(bus, dev, vq, free_head); + + qvirtio_wait_queue_isr(bus, dev, vq, QVIRTIO_NET_TIMEOUT_US); + guest_free(alloc, req_addr); + + ret = qemu_recv(socket, &len, sizeof(len), 0); + g_assert_cmpint(ret, ==, sizeof(len)); + len = ntohl(len); + + ret = qemu_recv(socket, buffer, len, 0); + g_assert_cmpstr(buffer, ==, "TEST"); +} + +static void rx_stop_cont_test(const QVirtioBus *bus, QVirtioDevice *dev, + QGuestAllocator *alloc, QVirtQueue *vq, + int socket) +{ + uint64_t req_addr; + uint32_t free_head; + char test[] = "TEST"; + char buffer[64]; + int len = htonl(sizeof(test)); + struct iovec iov[] = { + { + .iov_base = &len, + .iov_len = sizeof(len), + }, { + .iov_base = test, + .iov_len = sizeof(test), + }, + }; + int ret; + + req_addr = guest_alloc(alloc, 64); + + free_head = qvirtqueue_add(vq, req_addr, 64, true, false); + qvirtqueue_kick(bus, dev, vq, free_head); + + qmp("{ 'execute' : 'stop'}"); + + ret = iov_send(socket, iov, 2, 0, sizeof(len) + sizeof(test)); + g_assert_cmpint(ret, ==, sizeof(test) + sizeof(len)); + + /* We could check the status, but this command is more importantly to + * ensure the packet data gets queued in QEMU, before we do 'cont'. + */ + qmp("{ 'execute' : 'query-status'}"); + qmp("{ 'execute' : 'cont'}"); + + qvirtio_wait_queue_isr(bus, dev, vq, QVIRTIO_NET_TIMEOUT_US); + memread(req_addr + VNET_HDR_SIZE, buffer, sizeof(test)); + g_assert_cmpstr(buffer, ==, "TEST"); + + guest_free(alloc, req_addr); +} -/* Tests only initialization so far. TODO: Replace with functional tests */ -static void pci_nop(void) +static void send_recv_test(const QVirtioBus *bus, QVirtioDevice *dev, + QGuestAllocator *alloc, QVirtQueue *rvq, + QVirtQueue *tvq, int socket) { + rx_test(bus, dev, alloc, rvq, socket); + tx_test(bus, dev, alloc, tvq, socket); } +static void stop_cont_test(const QVirtioBus *bus, QVirtioDevice *dev, + QGuestAllocator *alloc, QVirtQueue *rvq, + QVirtQueue *tvq, int socket) +{ + rx_stop_cont_test(bus, dev, alloc, rvq, socket); +} + +static void pci_basic(gconstpointer data) +{ + QVirtioPCIDevice *dev; + QPCIBus *bus; + QVirtQueuePCI *tx, *rx; + QGuestAllocator *alloc; + void (*func) (const QVirtioBus *bus, + QVirtioDevice *dev, + QGuestAllocator *alloc, + QVirtQueue *rvq, + QVirtQueue *tvq, + int socket) = data; + int sv[2], ret; + + ret = socketpair(PF_UNIX, SOCK_STREAM, 0, sv); + g_assert_cmpint(ret, !=, -1); + + bus = pci_test_start(sv[1]); + dev = virtio_net_pci_init(bus, PCI_SLOT); + + alloc = pc_alloc_init(); + rx = (QVirtQueuePCI *)qvirtqueue_setup(&qvirtio_pci, &dev->vdev, + alloc, 0); + tx = (QVirtQueuePCI *)qvirtqueue_setup(&qvirtio_pci, &dev->vdev, + alloc, 1); + + driver_init(&qvirtio_pci, &dev->vdev); + func(&qvirtio_pci, &dev->vdev, alloc, &rx->vq, &tx->vq, sv[0]); + + /* End test */ + close(sv[0]); + guest_free(alloc, tx->vq.desc); + pc_alloc_uninit(alloc); + qvirtio_pci_device_disable(dev); + g_free(dev); + qpci_free_pc(bus); + test_end(); +} +#endif + static void hotplug(void) { + qtest_start("-device virtio-net-pci"); + qpci_plug_device_test("virtio-net-pci", "net1", PCI_SLOT_HP, NULL); qpci_unplug_acpi_device_test("net1", PCI_SLOT_HP); + + test_end(); } int main(int argc, char **argv) @@ -31,13 +252,14 @@ int main(int argc, char **argv) int ret; g_test_init(&argc, &argv, NULL); - qtest_add_func("/virtio/net/pci/nop", pci_nop); +#ifndef _WIN32 + qtest_add_data_func("/virtio/net/pci/basic", send_recv_test, pci_basic); + qtest_add_data_func("/virtio/net/pci/rx_stop_cont", + stop_cont_test, pci_basic); +#endif qtest_add_func("/virtio/net/pci/hotplug", hotplug); - qtest_start("-device virtio-net-pci"); ret = g_test_run(); - qtest_end(); - return ret; } diff --git a/qemu/tests/virtio-rng-test.c b/qemu/tests/virtio-rng-test.c index 41c1cdb1a..771dbd73a 100644 --- a/qemu/tests/virtio-rng-test.c +++ b/qemu/tests/virtio-rng-test.c @@ -7,10 +7,9 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <string.h> #include "libqtest.h" -#include "qemu/osdep.h" #include "libqos/pci.h" #define PCI_SLOT_HP 0x06 diff --git a/qemu/tests/virtio-scsi-test.c b/qemu/tests/virtio-scsi-test.c index 11ccdd632..d78747a46 100644 --- a/qemu/tests/virtio-scsi-test.c +++ b/qemu/tests/virtio-scsi-test.c @@ -8,11 +8,10 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <string.h> #include "libqtest.h" -#include "qemu/osdep.h" -#include <stdio.h> +#include "block/scsi.h" #include "libqos/virtio.h" #include "libqos/virtio-pci.h" #include "libqos/pci-pc.h" @@ -71,40 +70,6 @@ static void qvirtio_scsi_stop(void) qtest_end(); } -static QVirtIOSCSI *qvirtio_scsi_pci_init(int slot) -{ - QVirtIOSCSI *vs; - QVirtioPCIDevice *dev; - void *addr; - int i; - - vs = g_new0(QVirtIOSCSI, 1); - vs->alloc = pc_alloc_init(); - vs->bus = qpci_init_pc(); - - dev = qvirtio_pci_device_find(vs->bus, QVIRTIO_SCSI_DEVICE_ID); - vs->dev = (QVirtioDevice *)dev; - g_assert(dev != NULL); - g_assert_cmphex(vs->dev->device_type, ==, QVIRTIO_SCSI_DEVICE_ID); - - qvirtio_pci_device_enable(dev); - qvirtio_reset(&qvirtio_pci, vs->dev); - qvirtio_set_acknowledge(&qvirtio_pci, vs->dev); - qvirtio_set_driver(&qvirtio_pci, vs->dev); - - addr = dev->addr + QVIRTIO_PCI_DEVICE_SPECIFIC_NO_MSIX; - vs->num_queues = qvirtio_config_readl(&qvirtio_pci, vs->dev, - (uint64_t)(uintptr_t)addr); - - g_assert_cmpint(vs->num_queues, <, MAX_NUM_QUEUES); - - for (i = 0; i < vs->num_queues + 2; i++) { - vs->vq[i] = qvirtqueue_setup(&qvirtio_pci, vs->dev, vs->alloc, i); - } - - return vs; -} - static void qvirtio_scsi_pci_free(QVirtIOSCSI *vs) { int i; @@ -134,7 +99,8 @@ static uint64_t qvirtio_scsi_alloc(QVirtIOSCSI *vs, size_t alloc_size, static uint8_t virtio_scsi_do_command(QVirtIOSCSI *vs, const uint8_t *cdb, const uint8_t *data_in, size_t data_in_len, - uint8_t *data_out, size_t data_out_len) + uint8_t *data_out, size_t data_out_len, + QVirtIOSCSICmdResp *resp_out) { QVirtQueue *vq; QVirtIOSCSICmdReq req = { { 0 } }; @@ -174,6 +140,10 @@ static uint8_t virtio_scsi_do_command(QVirtIOSCSI *vs, const uint8_t *cdb, response = readb(resp_addr + offsetof(QVirtIOSCSICmdResp, response)); + if (resp_out) { + memread(resp_addr, resp_out, sizeof(*resp_out)); + } + guest_free(vs->alloc, req_addr); guest_free(vs->alloc, resp_addr); guest_free(vs->alloc, data_in_addr); @@ -181,6 +151,52 @@ static uint8_t virtio_scsi_do_command(QVirtIOSCSI *vs, const uint8_t *cdb, return response; } +static QVirtIOSCSI *qvirtio_scsi_pci_init(int slot) +{ + const uint8_t test_unit_ready_cdb[CDB_SIZE] = {}; + QVirtIOSCSI *vs; + QVirtioPCIDevice *dev; + QVirtIOSCSICmdResp resp; + void *addr; + int i; + + vs = g_new0(QVirtIOSCSI, 1); + vs->alloc = pc_alloc_init(); + vs->bus = qpci_init_pc(); + + dev = qvirtio_pci_device_find(vs->bus, QVIRTIO_SCSI_DEVICE_ID); + vs->dev = (QVirtioDevice *)dev; + g_assert(dev != NULL); + g_assert_cmphex(vs->dev->device_type, ==, QVIRTIO_SCSI_DEVICE_ID); + + qvirtio_pci_device_enable(dev); + qvirtio_reset(&qvirtio_pci, vs->dev); + qvirtio_set_acknowledge(&qvirtio_pci, vs->dev); + qvirtio_set_driver(&qvirtio_pci, vs->dev); + + addr = dev->addr + QVIRTIO_PCI_DEVICE_SPECIFIC_NO_MSIX; + vs->num_queues = qvirtio_config_readl(&qvirtio_pci, vs->dev, + (uint64_t)(uintptr_t)addr); + + g_assert_cmpint(vs->num_queues, <, MAX_NUM_QUEUES); + + for (i = 0; i < vs->num_queues + 2; i++) { + vs->vq[i] = qvirtqueue_setup(&qvirtio_pci, vs->dev, vs->alloc, i); + } + + /* Clear the POWER ON OCCURRED unit attention */ + g_assert_cmpint(virtio_scsi_do_command(vs, test_unit_ready_cdb, + NULL, 0, NULL, 0, &resp), + ==, 0); + g_assert_cmpint(resp.status, ==, CHECK_CONDITION); + g_assert_cmpint(resp.sense[0], ==, 0x70); /* Fixed format sense buffer */ + g_assert_cmpint(resp.sense[2], ==, UNIT_ATTENTION); + g_assert_cmpint(resp.sense[12], ==, 0x29); /* POWER ON */ + g_assert_cmpint(resp.sense[13], ==, 0x00); + + return vs; +} + /* Tests only initialization so far. TODO: Replace with functional tests */ static void pci_nop(void) { @@ -221,9 +237,12 @@ static void hotplug(void) static void test_unaligned_write_same(void) { QVirtIOSCSI *vs; - uint8_t buf[512] = { 0 }; - const uint8_t write_same_cdb[CDB_SIZE] = { 0x41, 0x00, 0x00, 0x00, 0x00, + uint8_t buf1[512] = { 0 }; + uint8_t buf2[512] = { 1 }; + const uint8_t write_same_cdb_1[CDB_SIZE] = { 0x41, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00 }; + const uint8_t write_same_cdb_2[CDB_SIZE] = { 0x41, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x33, 0x00, 0x00 }; qvirtio_scsi_start("-drive file=blkdebug::null-co://,if=none,id=dr1" ",format=raw,file.align=4k " @@ -231,7 +250,10 @@ static void test_unaligned_write_same(void) vs = qvirtio_scsi_pci_init(PCI_SLOT); g_assert_cmphex(0, ==, - virtio_scsi_do_command(vs, write_same_cdb, NULL, 0, buf, 512)); + virtio_scsi_do_command(vs, write_same_cdb_1, NULL, 0, buf1, 512, NULL)); + + g_assert_cmphex(0, ==, + virtio_scsi_do_command(vs, write_same_cdb_2, NULL, 0, buf2, 512, NULL)); qvirtio_scsi_pci_free(vs); qvirtio_scsi_stop(); diff --git a/qemu/tests/virtio-serial-test.c b/qemu/tests/virtio-serial-test.c index bf030a616..480d4abb2 100644 --- a/qemu/tests/virtio-serial-test.c +++ b/qemu/tests/virtio-serial-test.c @@ -7,10 +7,9 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <string.h> #include "libqtest.h" -#include "qemu/osdep.h" /* Tests only initialization so far. TODO: Replace with functional tests */ static void pci_nop(void) diff --git a/qemu/tests/vmxnet3-test.c b/qemu/tests/vmxnet3-test.c index a2ebed39c..6ef0e2f04 100644 --- a/qemu/tests/vmxnet3-test.c +++ b/qemu/tests/vmxnet3-test.c @@ -7,10 +7,9 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <string.h> #include "libqtest.h" -#include "qemu/osdep.h" /* Tests only initialization so far. TODO: Replace with functional tests */ static void nop(void) diff --git a/qemu/tests/wdt_ib700-test.c b/qemu/tests/wdt_ib700-test.c index 82ca59725..efe337045 100644 --- a/qemu/tests/wdt_ib700-test.c +++ b/qemu/tests/wdt_ib700-test.c @@ -7,10 +7,9 @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" #include <glib.h> -#include <string.h> #include "libqtest.h" -#include "qemu/osdep.h" #include "qemu/timer.h" static void qmp_check_no_event(void) |