Compare commits

...
31 Commits
Author SHA1 Message Date
Michael Tokarev 0c918cb0ab Update version for 7.2.9 release
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
2024-01-29 12:49:21 +03:00
Max Filippov ecc23c6e95 target/xtensa: fix OOB TLB entry access
r[id]tlb[01], [iw][id]tlb opcodes use TLB way index passed in a register
by the guest. The host uses 3 bits of the index for ITLB indexing and 4
bits for DTLB, but there's only 7 entries in the ITLB array and 10 in
the DTLB array, so a malicious guest may trigger out-of-bound access to
these arrays.

Change split_tlb_entry_spec return type to bool to indicate whether TLB
way passed to it is valid. Change get_tlb_entry to return NULL in case
invalid TLB way is requested. Add assertion to xtensa_tlb_get_entry that
requested TLB way and entry indices are valid. Add checks to the
[rwi]tlb helpers that requested TLB way is valid and return 0 or do
nothing when it's not.

Cc: qemu-stable@nongnu.org
Fixes: b67ea0cd74 ("target-xtensa: implement memory protection options")
Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 20231215120307.545381-1-jcmvbkbc@gmail.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
(cherry picked from commit 604927e357)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
2024-01-27 18:05:30 +03:00
Daniel P. Berrangé fa020ef10b qtest: bump aspeed_smc-test timeout to 6 minutes
On a loaded system with --enable-debug, this test can take longer than
5 minutes. Raising the timeout to 6 minutes gives greater headroom for
such situations.

Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
[thuth: Increase the timeout to 6 minutes for very loaded systems]
Signed-off-by: Thomas Huth <thuth@redhat.com>
Message-Id: <20231215070357.10888-11-thuth@redhat.com>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
(cherry picked from commit e8a12fe31f)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
(Mjt: context fixup in tests/qtest/meson.build)
2024-01-26 19:53:14 +03:00
Stefan Hajnoczi 8ec90598e9 monitor: only run coroutine commands in qemu_aio_context
monitor_qmp_dispatcher_co() runs in the iohandler AioContext that is not
polled during nested event loops. The coroutine currently reschedules
itself in the main loop's qemu_aio_context AioContext, which is polled
during nested event loops. One known problem is that QMP device-add
calls drain_call_rcu(), which temporarily drops the BQL, leading to all
sorts of havoc like other vCPU threads re-entering device emulation code
while another vCPU thread is waiting in device emulation code with
aio_poll().

Paolo Bonzini suggested running non-coroutine QMP handlers in the
iohandler AioContext. This avoids trouble with nested event loops. His
original idea was to move coroutine rescheduling to
monitor_qmp_dispatch(), but I resorted to moving it to qmp_dispatch()
because we don't know if the QMP handler needs to run in coroutine
context in monitor_qmp_dispatch(). monitor_qmp_dispatch() would have
been nicer since it's associated with the monitor implementation and not
as general as qmp_dispatch(), which is also used by qemu-ga.

A number of qemu-iotests need updated .out files because the order of
QMP events vs QMP responses has changed.

Solves Issue #1933.

Cc: qemu-stable@nongnu.org
Fixes: 7bed89958b ("device_core: use drain_call_rcu in in qmp_device_add")
Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=2215192
Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=2214985
Buglink: https://issues.redhat.com/browse/RHEL-17369
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Message-ID: <20240118144823.1497953-4-stefanha@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Tested-by: Fiona Ebner <f.ebner@proxmox.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit effd60c878)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
(Mjt: omit changes to tests missing in 7.2)
2024-01-26 19:40:19 +03:00
Stefan Hajnoczi 219cea653e iotests: port 141 to Python for reliable QMP testing
The common.qemu bash functions allow tests to interact with the QMP
monitor of a QEMU process. I spent two days trying to update 141 when
the order of the test output changed, but found it would still fail
occassionally because printf() and QMP events race with synchronous QMP
communication.

I gave up and ported 141 to the existing Python API for QMP tests. The
Python API is less affected by the order in which QEMU prints output
because it does not print all QMP traffic by default.

The next commit changes the order in which QMP messages are received.
Make 141 reliable first.

Cc: Hanna Czenczek <hreitz@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Message-ID: <20240118144823.1497953-3-stefanha@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 9ee2dd4c22)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
2024-01-26 19:38:54 +03:00
Stefan Hajnoczi 3b53bfd4c8 iotests: add filter_qmp_generated_node_ids()
Add a filter function for QMP responses that contain QEMU's
automatically generated node ids. The ids change between runs and must
be masked in the reference output.

The next commit will use this new function.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Message-ID: <20240118144823.1497953-2-stefanha@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit da62b507a2)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
(Mjt: context fix in tests/qemu-iotests/iotests.py due to
 v7.2.0-939-gbcc6777ad6 "iotests: Filter child node information")
2024-01-26 19:37:29 +03:00
Ari Sundholm e9eb53c5fe block/blklogwrites: Fix a bug when logging "write zeroes" operations.
There is a bug in the blklogwrites driver pertaining to logging "write
zeroes" operations, causing log corruption. This can be easily observed
by setting detect-zeroes to something other than "off" for the driver.

The issue is caused by a concurrency bug pertaining to the fact that
"write zeroes" operations have to be logged in two parts: first the log
entry metadata, then the zeroed-out region. While the log entry
metadata is being written by bdrv_co_pwritev(), another operation may
begin in the meanwhile and modify the state of the blklogwrites driver.
This is as intended by the coroutine-driven I/O model in QEMU, of
course.

Unfortunately, this specific scenario is mishandled. A short example:
    1. Initially, in the current operation (#1), the current log sector
number in the driver state is only incremented by the number of sectors
taken by the log entry metadata, after which the log entry metadata is
written. The current operation yields.
    2. Another operation (#2) may start while the log entry metadata is
being written. It uses the current log position as the start offset for
its log entry. This is in the sector right after the operation #1 log
entry metadata, which is bad!
    3. After bdrv_co_pwritev() returns (#1), the current log sector
number is reread from the driver state in order to find out the start
offset for bdrv_co_pwrite_zeroes(). This is an obvious blunder, as the
offset will be the sector right after the (misplaced) operation #2 log
entry, which means that the zeroed-out region begins at the wrong
offset.
    4. As a result of the above, the log is corrupt.

Fix this by only reading the driver metadata once, computing the
offsets and sizes in one go (including the optional zeroed-out region)
and setting the log sector number to the appropriate value for the next
operation in line.

Signed-off-by: Ari Sundholm <ari@tuxera.com>
Cc: qemu-stable@nongnu.org
Message-ID: <20240109184646.1128475-1-megari@gmx.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit a9c8ea9547)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
2024-01-26 18:36:00 +03:00
Jason Wang 415f21c723 virtio-net: correctly copy vnet header when flushing TX
When HASH_REPORT is negotiated, the guest_hdr_len might be larger than
the size of the mergeable rx buffer header. Using
virtio_net_hdr_mrg_rxbuf during the header swap might lead a stack
overflow in this case. Fixing this by using virtio_net_hdr_v1_hash
instead.

Reported-by: Xiao Lei <leixiao.nop@zju.edu.cn>
Cc: Yuri Benditovich <yuri.benditovich@daynix.com>
Cc: qemu-stable@nongnu.org
Cc: Mauro Matteo Cascella <mcascell@redhat.com>
Fixes: CVE-2023-6693
Fixes: e22f0603fb ("virtio-net: reference implementation of hash report")
Reviewed-by: Michael Tokarev <mjt@tls.msk.ru>
Signed-off-by: Jason Wang <jasowang@redhat.com>
(cherry picked from commit 2220e8189f)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
2024-01-26 16:20:07 +03:00
Fiona Ebner 06e11b7589 block/io: clear BDRV_BLOCK_RECURSE flag after recursing in bdrv_co_block_status
Using fleecing backup like in [0] on a qcow2 image (with metadata
preallocation) can lead to the following assertion failure:

> bdrv_co_do_block_status: Assertion `!(ret & BDRV_BLOCK_ZERO)' failed.

In the reproducer [0], it happens because the BDRV_BLOCK_RECURSE flag
will be set by the qcow2 driver, so the caller will recursively check
the file child. Then the BDRV_BLOCK_ZERO set too. Later up the call
chain, in bdrv_co_do_block_status() for the snapshot-access driver,
the assertion failure will happen, because both flags are set.

To fix it, clear the recurse flag after the recursive check was done.

In detail:

> #0  qcow2_co_block_status

Returns 0x45 = BDRV_BLOCK_RECURSE | BDRV_BLOCK_DATA |
BDRV_BLOCK_OFFSET_VALID.

> #1  bdrv_co_do_block_status

Because of the data flag, bdrv_co_do_block_status() will now also set
BDRV_BLOCK_ALLOCATED. Because of the recurse flag,
bdrv_co_do_block_status() for the bdrv_file child will be called,
which returns 0x16 = BDRV_BLOCK_ALLOCATED | BDRV_BLOCK_OFFSET_VALID |
BDRV_BLOCK_ZERO. Now the return value inherits the zero flag.

Returns 0x57 = BDRV_BLOCK_RECURSE | BDRV_BLOCK_DATA |
BDRV_BLOCK_OFFSET_VALID | BDRV_BLOCK_ALLOCATED | BDRV_BLOCK_ZERO.

> #2  bdrv_co_common_block_status_above
> #3  bdrv_co_block_status_above
> #4  bdrv_co_block_status
> #5  cbw_co_snapshot_block_status
> #6  bdrv_co_snapshot_block_status
> #7  snapshot_access_co_block_status
> #8  bdrv_co_do_block_status

Return value is propagated all the way up to here, where the assertion
failure happens, because BDRV_BLOCK_RECURSE and BDRV_BLOCK_ZERO are
both set.

> #9  bdrv_co_common_block_status_above
> #10 bdrv_co_block_status_above
> #11 block_copy_block_status
> #12 block_copy_dirty_clusters
> #13 block_copy_common
> #14 block_copy_async_co_entry
> #15 coroutine_trampoline

[0]:

> #!/bin/bash
> rm /tmp/disk.qcow2
> ./qemu-img create /tmp/disk.qcow2 -o preallocation=metadata -f qcow2 1G
> ./qemu-img create /tmp/fleecing.qcow2 -f qcow2 1G
> ./qemu-img create /tmp/backup.qcow2 -f qcow2 1G
> ./qemu-system-x86_64 --qmp stdio \
> --blockdev qcow2,node-name=node0,file.driver=file,file.filename=/tmp/disk.qcow2 \
> --blockdev qcow2,node-name=node1,file.driver=file,file.filename=/tmp/fleecing.qcow2 \
> --blockdev qcow2,node-name=node2,file.driver=file,file.filename=/tmp/backup.qcow2 \
> <<EOF
> {"execute": "qmp_capabilities"}
> {"execute": "blockdev-add", "arguments": { "driver": "copy-before-write", "file": "node0", "target": "node1", "node-name": "node3" } }
> {"execute": "blockdev-add", "arguments": { "driver": "snapshot-access", "file": "node3", "node-name": "snap0" } }
> {"execute": "blockdev-backup", "arguments": { "device": "snap0", "target": "node1", "sync": "full", "job-id": "backup0" } }
> EOF

Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
Message-id: 20240116154839.401030-1-f.ebner@proxmox.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
(cherry picked from commit 8a9be79924)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
2024-01-25 19:14:18 +03:00
Paolo Bonzini b67924a048 accel/tcg: Revert mapping of PCREL translation block to multiple virtual addresses
This is causing regressions that have not been analyzed yet.  Revert the
change on stable branches.

Cc: qemu-stable@nongnu.org
Cc: Michael Tokarev <mjt@tls.msk.ru>
Related: https://gitlab.com/qemu-project/qemu/-/issues/2092
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
2024-01-25 19:14:18 +03:00
Alex Bennée 024e8945fa readthodocs: fully specify a build environment
This is now expected by rtd so I've expanded using their example as
22.04 is one of our supported platforms. I tried to work out if there
was an easy way to re-generate a requirements.txt from our
pythondeps.toml but in the end went for the easier solution.

Cc:  <qemu-stable@nongnu.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Message-Id: <20231221174200.2693694-1-alex.bennee@linaro.org>
(cherry picked from commit b16a45bc5e)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
2024-01-23 18:48:46 +03:00
Mark Cave-Ayland 7837d7e31d hw/scsi/esp-pci: set DMA_STAT_BCMBLT when BLAST command issued
Even though the BLAST command isn't fully implemented in QEMU, the DMA_STAT_BCMBLT
bit should be set after the command has been issued to indicate that the command
has completed.

This fixes an issue with the DC390 DOS driver which issues the BLAST command as
part of its normal error recovery routine at startup, and otherwise sits in a
tight loop waiting for DMA_STAT_BCMBLT to be set before continuing.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Tested-by: Guenter Roeck <linux@roeck-us.net>
Message-ID: <20240112131529.515642-5-mark.cave-ayland@ilande.co.uk>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
(cherry picked from commit c2d7de557d)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
2024-01-20 18:31:36 +03:00
Mark Cave-Ayland 5bdc6b9571 hw/scsi/esp-pci: synchronise setting of DMA_STAT_DONE with ESP completion interrupt
The setting of DMA_STAT_DONE at the end of a DMA transfer can be configured to
generate an interrupt, however the Linux driver manually checks for DMA_STAT_DONE
being set and if it is, considers that a DMA transfer has completed.

If DMA_STAT_DONE is set but the ESP device isn't indicating an interrupt then
the Linux driver considers this to be a spurious interrupt. However this can
occur in QEMU as there is a delay between the end of DMA transfer where
DMA_STAT_DONE is set, and the ESP device raising its completion interrupt.

This appears to be an incorrect assumption in the Linux driver as the ESP and
PCI DMA interrupt sources are separate (and may not be raised exactly
together), however we can work around this by synchronising the setting of
DMA_STAT_DONE at the end of a DMA transfer with the ESP completion interrupt.

In conjunction with the previous commit Linux is now able to correctly boot
from an am53c974 PCI SCSI device on the hppa C3700 machine without emitting
"iget: checksum invalid" and "Spurious irq, sreg=10" errors.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Tested-by: Guenter Roeck <linux@roeck-us.net>
Message-ID: <20240112131529.515642-4-mark.cave-ayland@ilande.co.uk>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
(cherry picked from commit 1e8e6644e0)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
2024-01-20 18:31:36 +03:00
Mark Cave-Ayland fd4e677c79 hw/scsi/esp-pci: generate PCI interrupt from separate ESP and PCI sources
The am53c974/dc390 PCI interrupt has two separate sources: the first is from the
internal ESP device, and the second is from the PCI DMA transfer logic.

Update the ESP interrupt handler so that it sets DMA_STAT_SCSIINT rather than
driving the PCI IRQ directly, and introduce a new esp_pci_update_irq() function
to generate the correct PCI IRQ level. In particular this fixes spurious interrupts
being generated by setting DMA_STAT_DONE at the end of a transfer if DMA_CMD_INTE_D
isn't set in the DMA_CMD register.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Tested-by: Guenter Roeck <linux@roeck-us.net>
Message-ID: <20240112131529.515642-3-mark.cave-ayland@ilande.co.uk>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
(cherry picked from commit 6b41417d93)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
(Mjt: fixup in hw/scsi/esp-pci.c due to v8.0.0-1556-g7d5b0d6864
 "bulk: Remove pointless QOM casts")
2024-01-20 18:30:32 +03:00
Mark Cave-Ayland 528496a5d4 hw/scsi/esp-pci: use correct address register for PCI DMA transfers
The current code in esp_pci_dma_memory_rw() sets the DMA address to the value
of the DMA_SPA (Starting Physical Address) register which is incorrect: this
means that for each callback from the SCSI layer the DMA address is set back
to the starting address.

In the case where only a single SCSI callback occurs (currently for transfer
lengths < 128kB) this works fine, however for larger transfers the DMA address
wraps back to the initial starting address, corrupting the buffer holding the
data transferred to the guest.

Fix esp_pci_dma_memory_rw() to use the DMA_WAC (Working Address Counter) for
the DMA address which is correctly incremented across multiple SCSI layer
transfers.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Tested-by: Guenter Roeck <linux@roeck-us.net>
Message-ID: <20240112131529.515642-2-mark.cave-ayland@ilande.co.uk>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
(cherry picked from commit 84a6835e00)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
2024-01-20 18:25:55 +03:00
Gerd Hoffmann 16f6a650a8 hw/pflash: implement update buffer for block writes
Add an update buffer where all block updates are staged.
Flush or discard updates properly, so we should never see
half-completed block writes in pflash storage.

Drop a bunch of FIXME comments ;)

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-ID: <20240108160900.104835-4-kraxel@redhat.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
(cherry picked from commit 284a7ee2e2)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
(Mjt: drop const in hw/block/pflash_cfi01.c for before
 v8.2.0-220-g7d5dc0a367 "hw/block: Constify VMState")
2024-01-20 17:41:47 +03:00
Gerd Hoffmann d56cc9b5e5 hw/pflash: use ldn_{be,le}_p and stn_{be,le}_p
Use the helper functions we have to read/write multi-byte values
in correct byte order.

Suggested-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-ID: <20240108160900.104835-3-kraxel@redhat.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
(cherry picked from commit 5dd58358a5)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
2024-01-20 17:41:47 +03:00
Gerd Hoffmann 06679ac8b5 hw/pflash: refactor pflash_data_write()
Move the offset calculation, do it once at the start of the function and
let the 'p' variable point directly to the memory location which should
be updated.  This makes it simpler to update other buffers than
pfl->storage in an upcoming patch.  No functional change.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-ID: <20240108160900.104835-2-kraxel@redhat.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
(cherry picked from commit 3b14a555fd)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
2024-01-20 17:41:47 +03:00
Paolo Bonzini a290e43f58 target/i386: pcrel: store low bits of physical address in data[0]
For PC-relative translation blocks, env->eip changes during the
execution of a translation block, Therefore, QEMU must be able to
recover an instruction's PC just from the TranslationBlock struct and
the instruction data with.  Because a TB will not span two pages, QEMU
stores all the low bits of EIP in the instruction data and replaces them
in x86_restore_state_to_opc.  Bits 12 and higher (which may vary between
executions of a PCREL TB, since these only use the physical address in
the hash key) are kept unmodified from env->eip.  The assumption is that
these bits of EIP, unlike bits 0-11, will not change as the translation
block executes.

Unfortunately, this is incorrect when the CS base is not aligned to a page.
Then the linear address of the instructions (i.e. the one with the
CS base addred) indeed will never span two pages, but bits 12+ of EIP
can actually change.  For example, if CS base is 0x80262200 and EIP =
0x6FF4, the first instruction in the translation block will be at linear
address 0x802691F4.  Even a very small TB will cross to EIP = 0x7xxx,
while the linear addresses will remain comfortably within a single page.

The fix is simply to use the low bits of the linear address for data[0],
since those don't change.  Then x86_restore_state_to_opc uses tb->cs_base
to compute a temporary linear address (referring to some unknown
instruction in the TB, but with the correct values of bits 12 and higher);
the low bits are replaced with data[0], and EIP is obtained by subtracting
again the CS base.

Huge thanks to Mark Cave-Ayland for the image and initial debugging,
and to Gitlab user @kjliew for help with bisecting another occurrence
of (hopefully!) the same bug.

It should be relatively easy to write a testcase that performs MMIO on
an EIP with different bits 12+ than the first instruction of the translation
block; any help is welcome.

Fixes: e3a79e0e87 ("target/i386: Enable TARGET_TB_PCREL", 2022-10-11)
Cc: qemu-stable@nongnu.org
Cc: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Cc: Richard Henderson <richard.henderson@linaro.org>
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1759
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1964
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2012
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 729ba8e933)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
(Mjt: fixup in target/i386/tcg/tcg-cpu.c target/i386/tcg/translate.c for
 v7.2.0-1839-g2e3afe8e19 "target/i386: Replace `TARGET_TB_PCREL` with `CF_PCREL`")
2024-01-20 17:41:47 +03:00
guoguangyao 7d6aebaec5 target/i386: fix incorrect EIP in PC-relative translation blocks
The PCREL patches introduced a bug when updating EIP in the !CF_PCREL case.
Using s->pc in func gen_update_eip_next() solves the problem.

Cc: qemu-stable@nongnu.org
Fixes: b5e0d5d22f ("target/i386: Fix 32-bit wrapping of pc/eip computation")
Signed-off-by: guoguangyao <guoguangyao18@mails.ucas.ac.cn>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-ID: <20240115020804.30272-1-guoguangyao18@mails.ucas.ac.cn>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 2926eab896)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
2024-01-20 17:41:47 +03:00
Richard Henderson 6abbb26bbc target/i386: Do not re-compute new pc with CF_PCREL
With PCREL, we have a page-relative view of EIP, and an
approximation of PC = EIP+CSBASE that is good enough to
detect page crossings.  If we try to recompute PC after
masking EIP, we will mess up that approximation and write
a corrupt value to EIP.

We already handled masking properly for PCREL, so the
fix in b5e0d5d2 was only needed for the !PCREL path.

Cc: qemu-stable@nongnu.org
Fixes: b5e0d5d22f ("target/i386: Fix 32-bit wrapping of pc/eip computation")
Reported-by: Michael Tokarev <mjt@tls.msk.ru>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Message-ID: <20240101230617.129349-1-richard.henderson@linaro.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit a58506b748)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
2024-01-20 17:41:47 +03:00
Richard Henderson 15e207b9ed target/i386: Fix 32-bit wrapping of pc/eip computation
In 32-bit mode, pc = eip + cs_base is also 32-bit, and must wrap.
Failure to do so results in incorrect memory exceptions to the guest.
Before 732d548732, this was implicitly done via truncation to
target_ulong but only in qemu-system-i386, not qemu-system-x86_64.

To fix this, we must add conditional zero-extensions.
Since we have to test for 32 vs 64-bit anyway, note that cs_base
is always zero in 64-bit mode.

Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2022
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20231212172510.103305-1-richard.henderson@linaro.org>
(cherry picked from commit b5e0d5d22f)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
(Mjt: context fix in target/i386/tcg/tcg-cpu.c for v8.1.0-1190-gb77af26e97
 "accel/tcg: Replace CPUState.env_ptr with cpu_env()")
(Mjt: fixup in target/i386/tcg/tcg-cpu.c for v7.2.0-1854-g34a39c2443
 "target/i386: Replace `tb_pc()` with `tb->pc`")
2024-01-20 17:41:47 +03:00
Anastasia Belova 2ad4ebb350 load_elf: fix iterator's type for elf file processing
j is used while loading an ELF file to byteswap segments'
data. If data is larger than 2GB an overflow may happen.
So j should be elf_word.

This commit fixes a minor bug: it's unlikely anybody is trying to
load ELF files with 2GB+ segments for wrong-endianness targets,
but if they did, it wouldn't work correctly.

Found by Linux Verification Center (linuxtesting.org) with SVACE.

Cc: qemu-stable@nongnu.org
Fixes: 7ef295ea5b ("loader: Add data swap option to load-elf")
Signed-off-by: Anastasia Belova <abelova@astralinux.ru>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
(cherry picked from commit 410c2a4d75)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
2024-01-19 13:41:14 +03:00
Peter Maydell c59ce9fef6 .gitlab-ci.d/buildtest.yml: Work around htags bug when environment is large
Sometimes the CI "pages" job fails with a message like this from
htags:

$ htags -anT --tree-view=filetree -m qemu_init -t "Welcome to the QEMU sourcecode"
htags: Negative exec line limit = -371

This is due to a bug in hflags where if the environment is too large it
falls over:
https://lists.gnu.org/archive/html/bug-global/2024-01/msg00000.html

This happens to us because GitLab CI puts the commit message of the
commit under test into the CI_COMMIT_MESSAGE and/or CI_COMMIT_TAG_MESSAGE
environment variables, so the job will fail if the commit happens to
have a verbose commit message.

Work around the htags bug by unsetting these variables while running
htags.

Cc: qemu-stable@nongnu.org
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2080
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Message-ID: <20240111125543.1573473-1-peter.maydell@linaro.org>
Signed-off-by: Thomas Huth <thuth@redhat.com>
(cherry picked from commit 52a21689cd)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
2024-01-13 11:30:27 +03:00
Ilya Leoshkevich 9222f3ee43 target/s390x: Fix LAE setting a wrong access register
LAE should set the access register corresponding to the first operand,
instead, it always modifies access register 1.

Co-developed-by: Ido Plat <Ido.Plat@ibm.com>
Cc: qemu-stable@nongnu.org
Fixes: a1c7610a68 ("target-s390x: implement LAY and LAEY instructions")
Reviewed-by: David Hildenbrand <david@redhat.com>
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
Message-ID: <20240111092328.929421-2-iii@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
(cherry picked from commit e358a25a97)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
(Mjt: target/s390x/tcg/translate.c: fixup for
 v8.1.0-1189-gad75a51e84  "tcg: Rename cpu_env to tcg_env" and
 v7.2.0-2636-g3ac6f91bca "target/s390x: Drop tcg_temp_free from translate.c")
2024-01-13 11:28:02 +03:00
Peter Maydell dbf80fdef8 hw/intc/arm_gicv3_cpuif: handle LPIs in in the list registers
The hypervisor can deliver (virtual) LPIs to a guest by setting up a
list register to have an intid which is an LPI.  The GIC has to treat
these a little differently to standard interrupt IDs, because LPIs
have no Active state, and so the guest will only EOI them, it will
not also deactivate them.  So icv_eoir_write() must do two things:

 * if the LPI ID is not in any list register, we drop the
   priority but do not increment the EOI count
 * if the LPI ID is in a list register, we immediately deactivate
   it, regardless of the split-drop-and-deactivate control

This can be seen in the VirtualWriteEOIR0() and VirtualWriteEOIR1()
pseudocode in the GICv3 architecture specification.

Without this fix, potentially a hypervisor guest might stall because
LPIs get stuck in a bogus Active+Pending state.

Cc: qemu-stable@nongnu.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Tested-by: Miguel Luis <miguel.luis@oracle.com>
(cherry picked from commit 82a65e3188)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
2024-01-11 20:59:59 +03:00
Michael Tokarev c0a2b77dd8 chardev/char.c: fix "abstract device type" error message
Current error message:

 qemu-system-x86_64: -chardev spice,id=foo: Parameter 'driver' expects an abstract device type

while in fact the meaning is in reverse, -chardev expects
a non-abstract device type.

Fixes: 777357d758 ("chardev: qom-ify" 2016-12-07)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
(cherry picked from commit 4ad87cd4b2)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
2024-01-08 19:25:14 +03:00
Xu Lu 0eab8d42e1 target/riscv: Fix mcycle/minstret increment behavior
The mcycle/minstret counter's stop flag is mistakenly updated on a copy
on stack. Thus the counter increments even when the CY/IR bit in the
mcountinhibit register is set. This commit corrects its behavior.

Fixes: 3780e33732 (target/riscv: Support mcycle/minstret write operation)
Signed-off-by: Xu Lu <luxu.kernel@bytedance.com>
Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
(cherry picked from commit 5cb0e7abe1)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
2024-01-08 19:24:44 +03:00
Kevin Wolf c6f64736de iotests: Basic tests for internal snapshots
We have a few test cases that include tests for corner case aspects of
internal snapshots, but nothing that tests that they actually function
as snapshots or that involves deleting a snapshot. Add a test for this
kind of basic internal snapshot functionality.

The error cases include a regression test for the crash we just fixed
with snapshot operations on inactive images.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-ID: <20231201142520.32255-4-kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit bb6e2511eb)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
2023-12-22 22:25:35 +03:00
Kevin Wolf ad24078e3f vl: Improve error message for conflicting -incoming and -loadvm
Currently, the conflict between -incoming and -loadvm is only detected
when loading the snapshot fails because the image is still inactive for
the incoming migration. This results in a suboptimal error message:

$ ./qemu-system-x86_64 -hda /tmp/test.qcow2 -loadvm foo -incoming defer
qemu-system-x86_64: Device 'ide0-hd0' is writable but does not support snapshots

Catch the situation already in qemu_validate_options() to improve the
message:

$ ./qemu-system-x86_64 -hda /tmp/test.qcow2 -loadvm foo -incoming defer
qemu-system-x86_64: 'incoming' and 'loadvm' options are mutually exclusive

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-ID: <20231201142520.32255-3-kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 5a7f21efaf)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
2023-12-22 22:25:35 +03:00
Kevin Wolf a629fee99b block: Fix crash when loading snapshot on inactive node
bdrv_is_read_only() only checks if the node is configured to be
read-only eventually, but even if it returns false, writing to the node
may not be permitted at the moment (because it's inactive).

bdrv_is_writable() checks that the node can be written to right now, and
this is what the snapshot operations really need.

Change bdrv_can_snapshot() to use bdrv_is_writable() to fix crashes like
the following:

$ ./qemu-system-x86_64 -hda /tmp/test.qcow2 -loadvm foo -incoming defer
qemu-system-x86_64: ../block/io.c:1990: int bdrv_co_write_req_prepare(BdrvChild *, int64_t, int64_t, BdrvTrackedRequest *, int): Assertion `!(bs->open_flags & BDRV_O_INACTIVE)' failed.

The resulting error message after this patch isn't perfect yet, but at
least it doesn't crash any more:

$ ./qemu-system-x86_64 -hda /tmp/test.qcow2 -loadvm foo -incoming defer
qemu-system-x86_64: Device 'ide0-hd0' is writable but does not support snapshots

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-ID: <20231201142520.32255-2-kwolf@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit d3007d348a)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
2023-12-22 22:25:35 +03:00
62 changed files with 958 additions and 660 deletions
+4 -1
View File
@@ -637,7 +637,10 @@ pages:
- mkdir -p public
# HTML-ised source tree
- make gtags
- htags -anT --tree-view=filetree -m qemu_init
# We unset variables to work around a bug in some htags versions
# which causes it to fail when the environment is large
- CI_COMMIT_MESSAGE= CI_COMMIT_TAG_MESSAGE= htags
-anT --tree-view=filetree -m qemu_init
-t "Welcome to the QEMU sourcecode"
- mv HTML public/src
# Project documentation
+12 -7
View File
@@ -5,16 +5,21 @@
# Required
version: 2
# Set the version of Python and other tools you might need
build:
os: ubuntu-22.04
tools:
python: "3.11"
# Build documentation in the docs/ directory with Sphinx
sphinx:
configuration: docs/conf.py
# We recommend specifying your dependencies to enable reproducible builds:
# https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
python:
install:
- requirements: docs/requirements.txt
# We want all the document formats
formats: all
# For consistency, we require that QEMU's Sphinx extensions
# run with at least the same minimum version of Python that
# we require for other Python in our codebase (our conf.py
# enforces this, and some code needs it.)
python:
version: 3.6
+1 -1
View File
@@ -1 +1 @@
7.2.8
7.2.9
+2 -2
View File
@@ -186,7 +186,7 @@ static bool tb_lookup_cmp(const void *p, const void *d)
const TranslationBlock *tb = p;
const struct tb_desc *desc = d;
if ((TARGET_TB_PCREL || tb_pc(tb) == desc->pc) &&
if (tb_pc(tb) == desc->pc &&
tb_page_addr0(tb) == desc->page_addr0 &&
tb->cs_base == desc->cs_base &&
tb->flags == desc->flags &&
@@ -238,7 +238,7 @@ static TranslationBlock *tb_htable_lookup(CPUState *cpu, target_ulong pc,
return NULL;
}
desc.page_addr0 = phys_pc;
h = tb_hash_func(phys_pc, (TARGET_TB_PCREL ? 0 : pc),
h = tb_hash_func(phys_pc, pc,
flags, cflags, *cpu->trace_dstate);
return qht_lookup_custom(&tb_ctx.htable, &desc, h, tb_lookup_cmp);
}
+3 -3
View File
@@ -34,7 +34,7 @@ static bool tb_cmp(const void *ap, const void *bp)
const TranslationBlock *a = ap;
const TranslationBlock *b = bp;
return ((TARGET_TB_PCREL || tb_pc(a) == tb_pc(b)) &&
return (tb_pc(a) == tb_pc(b) &&
a->cs_base == b->cs_base &&
a->flags == b->flags &&
(tb_cflags(a) & ~CF_INVALID) == (tb_cflags(b) & ~CF_INVALID) &&
@@ -269,7 +269,7 @@ static void do_tb_phys_invalidate(TranslationBlock *tb, bool rm_from_page_list)
/* remove the TB from the hash list */
phys_pc = tb_page_addr0(tb);
h = tb_hash_func(phys_pc, (TARGET_TB_PCREL ? 0 : tb_pc(tb)),
h = tb_hash_func(phys_pc, tb_pc(tb),
tb->flags, orig_cflags, tb->trace_vcpu_dstate);
if (!qht_remove(&tb_ctx.htable, tb, h)) {
return;
@@ -459,7 +459,7 @@ TranslationBlock *tb_link_page(TranslationBlock *tb, tb_page_addr_t phys_pc,
}
/* add in the hash table */
h = tb_hash_func(phys_pc, (TARGET_TB_PCREL ? 0 : tb_pc(tb)),
h = tb_hash_func(phys_pc, tb_pc(tb),
tb->flags, tb->cflags, tb->trace_vcpu_dstate);
qht_insert(&tb_ctx.htable, tb, h, &existing_tb);
-2
View File
@@ -818,9 +818,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
gen_code_buf = tcg_ctx->code_gen_ptr;
tb->tc.ptr = tcg_splitwx_to_rx(gen_code_buf);
#if !TARGET_TB_PCREL
tb->pc = pc;
#endif
tb->cs_base = cs_base;
tb->flags = flags;
tb->cflags = cflags;
+25 -8
View File
@@ -321,22 +321,39 @@ typedef struct {
static void coroutine_fn blk_log_writes_co_do_log(BlkLogWritesLogReq *lr)
{
BDRVBlkLogWritesState *s = lr->bs->opaque;
uint64_t cur_log_offset = s->cur_log_sector << s->sectorbits;
/*
* Determine the offsets and sizes of different parts of the entry, and
* update the state of the driver.
*
* This needs to be done in one go, before any actual I/O is done, as the
* log entry may have to be written in two parts, and the state of the
* driver may be modified by other driver operations while waiting for the
* I/O to complete.
*/
const uint64_t entry_start_sector = s->cur_log_sector;
const uint64_t entry_offset = entry_start_sector << s->sectorbits;
const uint64_t qiov_aligned_size = ROUND_UP(lr->qiov->size, s->sectorsize);
const uint64_t entry_aligned_size = qiov_aligned_size +
ROUND_UP(lr->zero_size, s->sectorsize);
const uint64_t entry_nr_sectors = entry_aligned_size >> s->sectorbits;
s->nr_entries++;
s->cur_log_sector +=
ROUND_UP(lr->qiov->size, s->sectorsize) >> s->sectorbits;
s->cur_log_sector += entry_nr_sectors;
lr->log_ret = bdrv_co_pwritev(s->log_file, cur_log_offset, lr->qiov->size,
/*
* Write the log entry. Note that if this is a "write zeroes" operation,
* only the entry header is written here, with the zeroing being done
* separately below.
*/
lr->log_ret = bdrv_co_pwritev(s->log_file, entry_offset, lr->qiov->size,
lr->qiov, 0);
/* Logging for the "write zeroes" operation */
if (lr->log_ret == 0 && lr->zero_size) {
cur_log_offset = s->cur_log_sector << s->sectorbits;
s->cur_log_sector +=
ROUND_UP(lr->zero_size, s->sectorsize) >> s->sectorbits;
const uint64_t zeroes_offset = entry_offset + qiov_aligned_size;
lr->log_ret = bdrv_co_pwrite_zeroes(s->log_file, cur_log_offset,
lr->log_ret = bdrv_co_pwrite_zeroes(s->log_file, zeroes_offset,
lr->zero_size, 0);
}
+10
View File
@@ -2595,6 +2595,16 @@ static int coroutine_fn bdrv_co_block_status(BlockDriverState *bs,
ret |= (ret2 & BDRV_BLOCK_ZERO);
}
}
/*
* Now that the recursive search was done, clear the flag. Otherwise,
* with more complicated block graphs like snapshot-access ->
* copy-before-write -> qcow2, where the return value will be propagated
* further up to a parent bdrv_co_do_block_status() call, both the
* BDRV_BLOCK_RECURSE and BDRV_BLOCK_ZERO flags would be set, which is
* not allowed.
*/
ret &= ~BDRV_BLOCK_RECURSE;
}
out:
+3 -1
View File
@@ -190,8 +190,10 @@ static BlockDriverState *bdrv_snapshot_fallback(BlockDriverState *bs)
int bdrv_can_snapshot(BlockDriverState *bs)
{
BlockDriver *drv = bs->drv;
GLOBAL_STATE_CODE();
if (!drv || !bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) {
if (!drv || !bdrv_is_inserted(bs) || !bdrv_is_writable(bs)) {
return 0;
}
+1 -1
View File
@@ -519,7 +519,7 @@ static const ChardevClass *char_get_class(const char *driver, Error **errp)
if (object_class_is_abstract(oc)) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "driver",
"an abstract device type");
"a non-abstract device type");
return NULL;
}
+2
View File
@@ -0,0 +1,2 @@
sphinx==5.3.0
sphinx_rtd_theme==1.1.1
+91 -80
View File
@@ -81,16 +81,39 @@ struct PFlashCFI01 {
uint16_t ident3;
uint8_t cfi_table[0x52];
uint64_t counter;
unsigned int writeblock_size;
uint32_t writeblock_size;
MemoryRegion mem;
char *name;
void *storage;
VMChangeStateEntry *vmstate;
bool old_multiple_chip_handling;
/* block update buffer */
unsigned char *blk_bytes;
uint32_t blk_offset;
};
static int pflash_post_load(void *opaque, int version_id);
static bool pflash_blk_write_state_needed(void *opaque)
{
PFlashCFI01 *pfl = opaque;
return (pfl->blk_offset != -1);
}
static const VMStateDescription vmstate_pflash_blk_write = {
.name = "pflash_cfi01_blk_write",
.version_id = 1,
.minimum_version_id = 1,
.needed = pflash_blk_write_state_needed,
.fields = (const VMStateField[]) {
VMSTATE_VBUFFER_UINT32(blk_bytes, PFlashCFI01, 0, NULL, writeblock_size),
VMSTATE_UINT32(blk_offset, PFlashCFI01),
VMSTATE_END_OF_LIST()
}
};
static const VMStateDescription vmstate_pflash = {
.name = "pflash_cfi01",
.version_id = 1,
@@ -102,6 +125,10 @@ static const VMStateDescription vmstate_pflash = {
VMSTATE_UINT8(status, PFlashCFI01),
VMSTATE_UINT64(counter, PFlashCFI01),
VMSTATE_END_OF_LIST()
},
.subsections = (const VMStateDescription * []) {
&vmstate_pflash_blk_write,
NULL
}
};
@@ -226,34 +253,10 @@ static uint32_t pflash_data_read(PFlashCFI01 *pfl, hwaddr offset,
uint32_t ret;
p = pfl->storage;
switch (width) {
case 1:
ret = p[offset];
break;
case 2:
if (be) {
ret = p[offset] << 8;
ret |= p[offset + 1];
} else {
ret = p[offset];
ret |= p[offset + 1] << 8;
}
break;
case 4:
if (be) {
ret = p[offset] << 24;
ret |= p[offset + 1] << 16;
ret |= p[offset + 2] << 8;
ret |= p[offset + 3];
} else {
ret = p[offset];
ret |= p[offset + 1] << 8;
ret |= p[offset + 2] << 16;
ret |= p[offset + 3] << 24;
}
break;
default:
abort();
if (be) {
ret = ldn_be_p(p + offset, width);
} else {
ret = ldn_le_p(p + offset, width);
}
trace_pflash_data_read(pfl->name, offset, width, ret);
return ret;
@@ -401,40 +404,61 @@ static void pflash_update(PFlashCFI01 *pfl, int offset,
}
}
/* copy current flash content to block update buffer */
static void pflash_blk_write_start(PFlashCFI01 *pfl, hwaddr offset)
{
hwaddr mask = ~(pfl->writeblock_size - 1);
trace_pflash_write_block_start(pfl->name, pfl->counter);
pfl->blk_offset = offset & mask;
memcpy(pfl->blk_bytes, pfl->storage + pfl->blk_offset,
pfl->writeblock_size);
}
/* commit block update buffer changes */
static void pflash_blk_write_flush(PFlashCFI01 *pfl)
{
g_assert(pfl->blk_offset != -1);
trace_pflash_write_block_flush(pfl->name);
memcpy(pfl->storage + pfl->blk_offset, pfl->blk_bytes,
pfl->writeblock_size);
pflash_update(pfl, pfl->blk_offset, pfl->writeblock_size);
pfl->blk_offset = -1;
}
/* discard block update buffer changes */
static void pflash_blk_write_abort(PFlashCFI01 *pfl)
{
trace_pflash_write_block_abort(pfl->name);
pfl->blk_offset = -1;
}
static inline void pflash_data_write(PFlashCFI01 *pfl, hwaddr offset,
uint32_t value, int width, int be)
{
uint8_t *p = pfl->storage;
uint8_t *p;
trace_pflash_data_write(pfl->name, offset, width, value, pfl->counter);
switch (width) {
case 1:
p[offset] = value;
break;
case 2:
if (be) {
p[offset] = value >> 8;
p[offset + 1] = value;
} else {
p[offset] = value;
p[offset + 1] = value >> 8;
if (pfl->blk_offset != -1) {
/* block write: redirect writes to block update buffer */
if ((offset < pfl->blk_offset) ||
(offset + width > pfl->blk_offset + pfl->writeblock_size)) {
pfl->status |= 0x10; /* Programming error */
return;
}
break;
case 4:
if (be) {
p[offset] = value >> 24;
p[offset + 1] = value >> 16;
p[offset + 2] = value >> 8;
p[offset + 3] = value;
} else {
p[offset] = value;
p[offset + 1] = value >> 8;
p[offset + 2] = value >> 16;
p[offset + 3] = value >> 24;
}
break;
trace_pflash_data_write_block(pfl->name, offset, width, value,
pfl->counter);
p = pfl->blk_bytes + (offset - pfl->blk_offset);
} else {
/* write directly to storage */
trace_pflash_data_write(pfl->name, offset, width, value);
p = pfl->storage + offset;
}
if (be) {
stn_be_p(p, width, value);
} else {
stn_le_p(p, width, value);
}
}
static void pflash_write(PFlashCFI01 *pfl, hwaddr offset,
@@ -549,9 +573,9 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset,
} else {
value = extract32(value, 0, pfl->bank_width * 8);
}
trace_pflash_write_block(pfl->name, value);
pfl->counter = value;
pfl->wcycle++;
pflash_blk_write_start(pfl, offset);
break;
case 0x60:
if (cmd == 0xd0) {
@@ -582,12 +606,7 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset,
switch (pfl->cmd) {
case 0xe8: /* Block write */
/* FIXME check @offset, @width */
if (!pfl->ro) {
/*
* FIXME writing straight to memory is *wrong*. We
* should write to a buffer, and flush it to memory
* only on confirm command (see below).
*/
if (!pfl->ro && (pfl->blk_offset != -1)) {
pflash_data_write(pfl, offset, value, width, be);
} else {
pfl->status |= 0x10; /* Programming error */
@@ -596,18 +615,8 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset,
pfl->status |= 0x80;
if (!pfl->counter) {
hwaddr mask = pfl->writeblock_size - 1;
mask = ~mask;
trace_pflash_write(pfl->name, "block write finished");
pfl->wcycle++;
if (!pfl->ro) {
/* Flush the entire write buffer onto backing storage. */
/* FIXME premature! */
pflash_update(pfl, offset & mask, pfl->writeblock_size);
} else {
pfl->status |= 0x10; /* Programming error */
}
}
pfl->counter--;
@@ -619,20 +628,17 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset,
case 3: /* Confirm mode */
switch (pfl->cmd) {
case 0xe8: /* Block write */
if (cmd == 0xd0) {
/* FIXME this is where we should write out the buffer */
if ((cmd == 0xd0) && !(pfl->status & 0x10)) {
pflash_blk_write_flush(pfl);
pfl->wcycle = 0;
pfl->status |= 0x80;
} else {
qemu_log_mask(LOG_UNIMP,
"%s: Aborting write to buffer not implemented,"
" the data is already written to storage!\n"
"Flash device reset into READ mode.\n",
__func__);
pflash_blk_write_abort(pfl);
goto mode_read_array;
}
break;
default:
pflash_blk_write_abort(pfl);
goto error_flash;
}
break;
@@ -866,6 +872,9 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp)
pfl->cmd = 0x00;
pfl->status = 0x80; /* WSM ready */
pflash_cfi01_fill_cfi_table(pfl);
pfl->blk_bytes = g_malloc(pfl->writeblock_size);
pfl->blk_offset = -1;
}
static void pflash_cfi01_system_reset(DeviceState *dev)
@@ -885,6 +894,8 @@ static void pflash_cfi01_system_reset(DeviceState *dev)
* This model deliberately ignores this delay.
*/
pfl->status = 0x80;
pfl->blk_offset = -1;
}
static Property pflash_cfi01_properties[] = {
+1 -1
View File
@@ -546,7 +546,7 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
}
goto reset_flash;
}
trace_pflash_data_write(pfl->name, offset, width, value, 0);
trace_pflash_data_write(pfl->name, offset, width, value);
if (!pfl->ro) {
p = (uint8_t *)pfl->storage + offset;
if (pfl->be) {
+5 -2
View File
@@ -12,7 +12,8 @@ fdctrl_tc_pulse(int level) "TC pulse: %u"
pflash_chip_erase_invalid(const char *name, uint64_t offset) "%s: chip erase: invalid address 0x%" PRIx64
pflash_chip_erase_start(const char *name) "%s: start chip erase"
pflash_data_read(const char *name, uint64_t offset, unsigned size, uint32_t value) "%s: data offset:0x%04"PRIx64" size:%u value:0x%04x"
pflash_data_write(const char *name, uint64_t offset, unsigned size, uint32_t value, uint64_t counter) "%s: data offset:0x%04"PRIx64" size:%u value:0x%04x counter:0x%016"PRIx64
pflash_data_write(const char *name, uint64_t offset, unsigned size, uint32_t value) "%s: data offset:0x%04"PRIx64" size:%u value:0x%04x"
pflash_data_write_block(const char *name, uint64_t offset, unsigned size, uint32_t value, uint64_t counter) "%s: data offset:0x%04"PRIx64" size:%u value:0x%04x counter:0x%016"PRIx64
pflash_device_id(const char *name, uint16_t id) "%s: read device ID: 0x%04x"
pflash_device_info(const char *name, uint64_t offset) "%s: read device information offset:0x%04" PRIx64
pflash_erase_complete(const char *name) "%s: sector erase complete"
@@ -32,7 +33,9 @@ pflash_unlock0_failed(const char *name, uint64_t offset, uint8_t cmd, uint16_t a
pflash_unlock1_failed(const char *name, uint64_t offset, uint8_t cmd) "%s: unlock0 failed 0x%" PRIx64 " 0x%02x"
pflash_unsupported_device_configuration(const char *name, uint8_t width, uint8_t max) "%s: unsupported device configuration: device_width:%d max_device_width:%d"
pflash_write(const char *name, const char *str) "%s: %s"
pflash_write_block(const char *name, uint32_t value) "%s: block write: bytes:0x%x"
pflash_write_block_start(const char *name, uint32_t value) "%s: block write start: bytes:0x%x"
pflash_write_block_flush(const char *name) "%s: block write flush"
pflash_write_block_abort(const char *name) "%s: block write abort"
pflash_write_block_erase(const char *name, uint64_t offset, uint64_t len) "%s: block erase offset:0x%" PRIx64 " bytes:0x%" PRIx64
pflash_write_failed(const char *name, uint64_t offset, uint8_t cmd) "%s: command failed 0x%" PRIx64 " 0x%02x"
pflash_write_invalid(const char *name, uint8_t cmd) "%s: invalid write for command 0x%02x"
+13 -4
View File
@@ -1432,16 +1432,25 @@ static void icv_eoir_write(CPUARMState *env, const ARMCPRegInfo *ri,
idx = icv_find_active(cs, irq);
if (idx < 0) {
/* No valid list register corresponding to EOI ID */
icv_increment_eoicount(cs);
/*
* No valid list register corresponding to EOI ID; if this is a vLPI
* not in the list regs then do nothing; otherwise increment EOI count
*/
if (irq < GICV3_LPI_INTID_START) {
icv_increment_eoicount(cs);
}
} else {
uint64_t lr = cs->ich_lr_el2[idx];
int thisgrp = (lr & ICH_LR_EL2_GROUP) ? GICV3_G1NS : GICV3_G0;
int lr_gprio = ich_lr_prio(lr) & icv_gprio_mask(cs, grp);
if (thisgrp == grp && lr_gprio == dropprio) {
if (!icv_eoi_split(env, cs)) {
/* Priority drop and deactivate not split: deactivate irq now */
if (!icv_eoi_split(env, cs) || irq >= GICV3_LPI_INTID_START) {
/*
* Priority drop and deactivate not split: deactivate irq now.
* LPIs always get their active state cleared immediately
* because no separate deactivate is expected.
*/
icv_deactivate_irq(cs, idx);
}
}
+9 -4
View File
@@ -664,6 +664,11 @@ static void virtio_net_set_mrg_rx_bufs(VirtIONet *n, int mergeable_rx_bufs,
n->mergeable_rx_bufs = mergeable_rx_bufs;
/*
* Note: when extending the vnet header, please make sure to
* change the vnet header copying logic in virtio_net_flush_tx()
* as well.
*/
if (version_1) {
n->guest_hdr_len = hash_report ?
sizeof(struct virtio_net_hdr_v1_hash) :
@@ -2630,7 +2635,7 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
ssize_t ret;
unsigned int out_num;
struct iovec sg[VIRTQUEUE_MAX_SIZE], sg2[VIRTQUEUE_MAX_SIZE + 1], *out_sg;
struct virtio_net_hdr_mrg_rxbuf mhdr;
struct virtio_net_hdr_v1_hash vhdr;
elem = virtqueue_pop(q->tx_vq, sizeof(VirtQueueElement));
if (!elem) {
@@ -2647,7 +2652,7 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
}
if (n->has_vnet_hdr) {
if (iov_to_buf(out_sg, out_num, 0, &mhdr, n->guest_hdr_len) <
if (iov_to_buf(out_sg, out_num, 0, &vhdr, n->guest_hdr_len) <
n->guest_hdr_len) {
virtio_error(vdev, "virtio-net header incorrect");
virtqueue_detach_element(q->tx_vq, elem, 0);
@@ -2655,8 +2660,8 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
return -EINVAL;
}
if (n->needs_vnet_hdr_swap) {
virtio_net_hdr_swap(vdev, (void *) &mhdr);
sg2[0].iov_base = &mhdr;
virtio_net_hdr_swap(vdev, (void *) &vhdr);
sg2[0].iov_base = &vhdr;
sg2[0].iov_len = n->guest_hdr_len;
out_num = iov_copy(&sg2[1], ARRAY_SIZE(sg2) - 1,
out_sg, out_num,
+41 -20
View File
@@ -77,6 +77,41 @@ struct PCIESPState {
ESPState esp;
};
static void esp_pci_update_irq(PCIESPState *pci)
{
int scsi_level = !!(pci->dma_regs[DMA_STAT] & DMA_STAT_SCSIINT);
int dma_level = (pci->dma_regs[DMA_CMD] & DMA_CMD_INTE_D) ?
!!(pci->dma_regs[DMA_STAT] & DMA_STAT_DONE) : 0;
int level = scsi_level || dma_level;
pci_set_irq(PCI_DEVICE(pci), level);
}
static void esp_irq_handler(void *opaque, int irq_num, int level)
{
PCIESPState *pci = PCI_ESP(opaque);
if (level) {
pci->dma_regs[DMA_STAT] |= DMA_STAT_SCSIINT;
/*
* If raising the ESP IRQ to indicate end of DMA transfer, set
* DMA_STAT_DONE at the same time. In theory this should be done in
* esp_pci_dma_memory_rw(), however there is a delay between setting
* DMA_STAT_DONE and the ESP IRQ arriving which is visible to the
* guest that can cause confusion e.g. Linux
*/
if ((pci->dma_regs[DMA_CMD] & DMA_CMD_MASK) == 0x3 &&
pci->dma_regs[DMA_WBC] == 0) {
pci->dma_regs[DMA_STAT] |= DMA_STAT_DONE;
}
} else {
pci->dma_regs[DMA_STAT] &= ~DMA_STAT_SCSIINT;
}
esp_pci_update_irq(pci);
}
static void esp_pci_handle_idle(PCIESPState *pci, uint32_t val)
{
ESPState *s = ESP(&pci->esp);
@@ -89,6 +124,7 @@ static void esp_pci_handle_blast(PCIESPState *pci, uint32_t val)
{
trace_esp_pci_dma_blast(val);
qemu_log_mask(LOG_UNIMP, "am53c974: cmd BLAST not implemented\n");
pci->dma_regs[DMA_STAT] |= DMA_STAT_BCMBLT;
}
static void esp_pci_handle_abort(PCIESPState *pci, uint32_t val)
@@ -151,6 +187,7 @@ static void esp_pci_dma_write(PCIESPState *pci, uint32_t saddr, uint32_t val)
/* clear some bits on write */
uint32_t mask = DMA_STAT_ERROR | DMA_STAT_ABORT | DMA_STAT_DONE;
pci->dma_regs[DMA_STAT] &= ~(val & mask);
esp_pci_update_irq(pci);
}
break;
default:
@@ -161,17 +198,14 @@ static void esp_pci_dma_write(PCIESPState *pci, uint32_t saddr, uint32_t val)
static uint32_t esp_pci_dma_read(PCIESPState *pci, uint32_t saddr)
{
ESPState *s = ESP(&pci->esp);
uint32_t val;
val = pci->dma_regs[saddr];
if (saddr == DMA_STAT) {
if (s->rregs[ESP_RSTAT] & STAT_INT) {
val |= DMA_STAT_SCSIINT;
}
if (!(pci->sbac & SBAC_STATUS)) {
pci->dma_regs[DMA_STAT] &= ~(DMA_STAT_ERROR | DMA_STAT_ABORT |
DMA_STAT_DONE);
esp_pci_update_irq(pci);
}
}
@@ -275,7 +309,7 @@ static void esp_pci_dma_memory_rw(PCIESPState *pci, uint8_t *buf, int len,
qemu_log_mask(LOG_UNIMP, "am53c974: MDL transfer not implemented\n");
}
addr = pci->dma_regs[DMA_SPA];
addr = pci->dma_regs[DMA_WAC];
if (pci->dma_regs[DMA_WBC] < len) {
len = pci->dma_regs[DMA_WBC];
}
@@ -285,9 +319,6 @@ static void esp_pci_dma_memory_rw(PCIESPState *pci, uint8_t *buf, int len,
/* update status registers */
pci->dma_regs[DMA_WBC] -= len;
pci->dma_regs[DMA_WAC] += len;
if (pci->dma_regs[DMA_WBC] == 0) {
pci->dma_regs[DMA_STAT] |= DMA_STAT_DONE;
}
}
static void esp_pci_dma_memory_read(void *opaque, uint8_t *buf, int len)
@@ -342,23 +373,13 @@ static const VMStateDescription vmstate_esp_pci_scsi = {
}
};
static void esp_pci_command_complete(SCSIRequest *req, size_t resid)
{
ESPState *s = req->hba_private;
PCIESPState *pci = container_of(s, PCIESPState, esp);
esp_command_complete(req, resid);
pci->dma_regs[DMA_WBC] = 0;
pci->dma_regs[DMA_STAT] |= DMA_STAT_DONE;
}
static const struct SCSIBusInfo esp_pci_scsi_info = {
.tcq = false,
.max_target = ESP_MAX_DEVS,
.max_lun = 7,
.transfer_data = esp_transfer_data,
.complete = esp_pci_command_complete,
.complete = esp_command_complete,
.cancel = esp_request_cancelled,
};
@@ -386,7 +407,7 @@ static void esp_pci_scsi_realize(PCIDevice *dev, Error **errp)
"esp-io", 0x80);
pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &pci->io);
s->irq = pci_allocate_irq(dev);
s->irq = qemu_allocate_irq(esp_irq_handler, pci, 0);
scsi_bus_init(&s->bus, sizeof(s->bus), d, &esp_pci_scsi_info);
}
-6
View File
@@ -503,7 +503,6 @@ struct tb_tc {
};
struct TranslationBlock {
#if !TARGET_TB_PCREL
/*
* Guest PC corresponding to this block. This must be the true
* virtual address. Therefore e.g. x86 stores EIP + CS_BASE, and
@@ -518,7 +517,6 @@ struct TranslationBlock {
* deposited into the "current" PC.
*/
target_ulong pc;
#endif
/*
* Target-specific data associated with the TranslationBlock, e.g.:
@@ -604,11 +602,7 @@ struct TranslationBlock {
/* Hide the read to avoid ifdefs for TARGET_TB_PCREL. */
static inline target_ulong tb_pc(const TranslationBlock *tb)
{
#if TARGET_TB_PCREL
qemu_build_not_reached();
#else
return tb->pc;
#endif
}
/* Hide the qatomic_read to make code a little easier on the eyes */
+1 -1
View File
@@ -499,7 +499,7 @@ static ssize_t glue(load_elf, SZ)(const char *name, int fd,
}
if (data_swab) {
int j;
elf_word j;
for (j = 0; j < file_size; j += (1 << data_swab)) {
uint8_t *dp = data + j;
switch (data_swab) {
-17
View File
@@ -296,14 +296,6 @@ void coroutine_fn monitor_qmp_dispatcher_co(void *data)
qemu_coroutine_yield();
}
/*
* Move the coroutine from iohandler_ctx to qemu_aio_context for
* executing the command handler so that it can make progress if it
* involves an AIO_WAIT_WHILE().
*/
aio_co_schedule(qemu_get_aio_context(), qmp_dispatcher_co);
qemu_coroutine_yield();
/* Process request */
if (req_obj->req) {
if (trace_event_get_state(TRACE_MONITOR_QMP_CMD_IN_BAND)) {
@@ -330,15 +322,6 @@ void coroutine_fn monitor_qmp_dispatcher_co(void *data)
}
qmp_request_free(req_obj);
/*
* Yield and reschedule so the main loop stays responsive.
*
* Move back to iohandler_ctx so that nested event loops for
* qemu_aio_context don't start new monitor commands.
*/
aio_co_schedule(iohandler_get_aio_context(), qmp_dispatcher_co);
qemu_coroutine_yield();
}
}
+23 -1
View File
@@ -206,9 +206,31 @@ QDict *qmp_dispatch(const QmpCommandList *cmds, QObject *request,
assert(!(oob && qemu_in_coroutine()));
assert(monitor_cur() == NULL);
if (!!(cmd->options & QCO_COROUTINE) == qemu_in_coroutine()) {
if (qemu_in_coroutine()) {
/*
* Move the coroutine from iohandler_ctx to qemu_aio_context for
* executing the command handler so that it can make progress if it
* involves an AIO_WAIT_WHILE().
*/
aio_co_schedule(qemu_get_aio_context(), qemu_coroutine_self());
qemu_coroutine_yield();
}
monitor_set_cur(qemu_coroutine_self(), cur_mon);
cmd->fn(args, &ret, &err);
monitor_set_cur(qemu_coroutine_self(), NULL);
if (qemu_in_coroutine()) {
/*
* Yield and reschedule so the main loop stays responsive.
*
* Move back to iohandler_ctx so that nested event loops for
* qemu_aio_context don't start new monitor commands.
*/
aio_co_schedule(iohandler_get_aio_context(),
qemu_coroutine_self());
qemu_coroutine_yield();
}
} else {
/*
* Actual context doesn't match the one the command needs.
@@ -232,7 +254,7 @@ QDict *qmp_dispatch(const QmpCommandList *cmds, QObject *request,
.errp = &err,
.co = qemu_coroutine_self(),
};
aio_bh_schedule_oneshot(qemu_get_aio_context(), do_qmp_dispatch_bh,
aio_bh_schedule_oneshot(iohandler_get_aio_context(), do_qmp_dispatch_bh,
&data);
qemu_coroutine_yield();
}
+4
View File
@@ -2321,6 +2321,10 @@ static void qemu_validate_options(const QDict *machine_opts)
}
}
if (loadvm && incoming) {
error_report("'incoming' and 'loadvm' options are mutually exclusive");
exit(EXIT_FAILURE);
}
if (loadvm && preconfig_requested) {
error_report("'preconfig' and 'loadvm' options are "
"mutually exclusive");
+7 -2
View File
@@ -2217,10 +2217,15 @@ static inline int cpu_mmu_index_kernel(CPUX86State *env)
static inline void cpu_get_tb_cpu_state(CPUX86State *env, target_ulong *pc,
target_ulong *cs_base, uint32_t *flags)
{
*cs_base = env->segs[R_CS].base;
*pc = *cs_base + env->eip;
*flags = env->hflags |
(env->eflags & (IOPL_MASK | TF_MASK | RF_MASK | VM_MASK | AC_MASK));
if (env->hflags & HF_CS64_MASK) {
*cs_base = 0;
*pc = env->eip;
} else {
*cs_base = env->segs[R_CS].base;
*pc = (uint32_t)(*cs_base + env->eip);
}
}
void do_cpu_init(X86CPU *cpu);
+22 -3
View File
@@ -52,7 +52,12 @@ static void x86_cpu_synchronize_from_tb(CPUState *cs,
/* The instruction pointer is always up to date with TARGET_TB_PCREL. */
if (!TARGET_TB_PCREL) {
CPUX86State *env = cs->env_ptr;
env->eip = tb_pc(tb) - tb->cs_base;
if (tb->flags & HF_CS64_MASK) {
env->eip = tb_pc(tb);
} else {
env->eip = (uint32_t)(tb_pc(tb) - tb->cs_base);
}
}
}
@@ -63,12 +68,26 @@ static void x86_restore_state_to_opc(CPUState *cs,
X86CPU *cpu = X86_CPU(cs);
CPUX86State *env = &cpu->env;
int cc_op = data[1];
uint64_t new_pc;
if (TARGET_TB_PCREL) {
env->eip = (env->eip & TARGET_PAGE_MASK) | data[0];
/*
* data[0] in PC-relative TBs is also a linear address, i.e. an address with
* the CS base added, because it is not guaranteed that EIP bits 12 and higher
* stay the same across the translation block. Add the CS base back before
* replacing the low bits, and subtract it below just like for !CF_PCREL.
*/
uint64_t pc = env->eip + tb->cs_base;
new_pc = (pc & TARGET_PAGE_MASK) | data[0];
} else {
env->eip = data[0] - tb->cs_base;
new_pc = data[0];
}
if (tb->flags & HF_CS64_MASK) {
env->eip = new_pc;
} else {
env->eip = (uint32_t)(new_pc - tb->cs_base);
}
if (cc_op != CC_OP_DYNAMIC) {
env->cc_op = cc_op;
}
+15 -7
View File
@@ -547,8 +547,10 @@ static void gen_update_eip_cur(DisasContext *s)
assert(s->pc_save != -1);
if (TARGET_TB_PCREL) {
tcg_gen_addi_tl(cpu_eip, cpu_eip, s->base.pc_next - s->pc_save);
} else if (CODE64(s)) {
tcg_gen_movi_tl(cpu_eip, s->base.pc_next);
} else {
tcg_gen_movi_tl(cpu_eip, s->base.pc_next - s->cs_base);
tcg_gen_movi_tl(cpu_eip, (uint32_t)(s->base.pc_next - s->cs_base));
}
s->pc_save = s->base.pc_next;
}
@@ -558,8 +560,10 @@ static void gen_update_eip_next(DisasContext *s)
assert(s->pc_save != -1);
if (TARGET_TB_PCREL) {
tcg_gen_addi_tl(cpu_eip, cpu_eip, s->pc - s->pc_save);
} else if (CODE64(s)) {
tcg_gen_movi_tl(cpu_eip, s->pc);
} else {
tcg_gen_movi_tl(cpu_eip, s->pc - s->cs_base);
tcg_gen_movi_tl(cpu_eip, (uint32_t)(s->pc - s->cs_base));
}
s->pc_save = s->pc;
}
@@ -605,8 +609,10 @@ static TCGv eip_next_tl(DisasContext *s)
TCGv ret = tcg_temp_new();
tcg_gen_addi_tl(ret, cpu_eip, s->pc - s->pc_save);
return ret;
} else if (CODE64(s)) {
return tcg_constant_tl(s->pc);
} else {
return tcg_constant_tl(s->pc - s->cs_base);
return tcg_constant_tl((uint32_t)(s->pc - s->cs_base));
}
}
@@ -617,8 +623,10 @@ static TCGv eip_cur_tl(DisasContext *s)
TCGv ret = tcg_temp_new();
tcg_gen_addi_tl(ret, cpu_eip, s->base.pc_next - s->pc_save);
return ret;
} else if (CODE64(s)) {
return tcg_constant_tl(s->base.pc_next);
} else {
return tcg_constant_tl(s->base.pc_next - s->cs_base);
return tcg_constant_tl((uint32_t)(s->base.pc_next - s->cs_base));
}
}
@@ -2890,10 +2898,11 @@ static void gen_jmp_rel(DisasContext *s, MemOp ot, int diff, int tb_num)
tcg_gen_andi_tl(cpu_eip, cpu_eip, mask);
use_goto_tb = false;
}
} else if (!CODE64(s)) {
new_pc = (uint32_t)(new_eip + s->cs_base);
}
if (use_goto_tb &&
translator_use_goto_tb(&s->base, new_eip + s->cs_base)) {
if (use_goto_tb && translator_use_goto_tb(&s->base, new_pc)) {
/* jump to same page: we can use a direct jump */
tcg_gen_goto_tb(tb_num);
if (!TARGET_TB_PCREL) {
@@ -6974,7 +6983,6 @@ static void i386_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
dc->prev_insn_end = tcg_last_op();
if (TARGET_TB_PCREL) {
pc_arg -= dc->cs_base;
pc_arg &= ~TARGET_PAGE_MASK;
}
tcg_gen_insn_start(pc_arg, dc->cc_op);
+7 -7
View File
@@ -697,11 +697,11 @@ static int write_mhpmcounterh(CPURISCVState *env, int csrno, target_ulong val)
static RISCVException riscv_pmu_read_ctr(CPURISCVState *env, target_ulong *val,
bool upper_half, uint32_t ctr_idx)
{
PMUCTRState counter = env->pmu_ctrs[ctr_idx];
target_ulong ctr_prev = upper_half ? counter.mhpmcounterh_prev :
counter.mhpmcounter_prev;
target_ulong ctr_val = upper_half ? counter.mhpmcounterh_val :
counter.mhpmcounter_val;
PMUCTRState *counter = &env->pmu_ctrs[ctr_idx];
target_ulong ctr_prev = upper_half ? counter->mhpmcounterh_prev :
counter->mhpmcounter_prev;
target_ulong ctr_val = upper_half ? counter->mhpmcounterh_val :
counter->mhpmcounter_val;
if (get_field(env->mcountinhibit, BIT(ctr_idx))) {
/**
@@ -709,12 +709,12 @@ static RISCVException riscv_pmu_read_ctr(CPURISCVState *env, target_ulong *val,
* stop the icount counting. Just return the counter value written by
* the supervisor to indicate that counter was not incremented.
*/
if (!counter.started) {
if (!counter->started) {
*val = ctr_val;
return RISCV_EXCP_NONE;
} else {
/* Mark that the counter has been stopped */
counter.started = false;
counter->started = false;
}
}
+2 -1
View File
@@ -3394,6 +3394,7 @@ static DisasJumpType op_mov2e(DisasContext *s, DisasOps *o)
{
int b2 = get_field(s, b2);
TCGv ar1 = tcg_temp_new_i64();
int r1 = get_field(s, r1);
o->out = o->in2;
o->g_out = o->g_in2;
@@ -3419,7 +3420,7 @@ static DisasJumpType op_mov2e(DisasContext *s, DisasOps *o)
break;
}
tcg_gen_st32_i64(ar1, cpu_env, offsetof(CPUS390XState, aregs[1]));
tcg_gen_st32_i64(ar1, cpu_env, offsetof(CPUS390XState, aregs[r1]));
tcg_temp_free_i64(ar1);
return DISAS_NEXT;
+35 -12
View File
@@ -226,22 +226,31 @@ static void split_tlb_entry_spec_way(const CPUXtensaState *env, uint32_t v,
* Split TLB address into TLB way, entry index and VPN (with index).
* See ISA, 4.6.5.5 - 4.6.5.8 for the TLB addressing format
*/
static void split_tlb_entry_spec(CPUXtensaState *env, uint32_t v, bool dtlb,
uint32_t *vpn, uint32_t *wi, uint32_t *ei)
static bool split_tlb_entry_spec(CPUXtensaState *env, uint32_t v, bool dtlb,
uint32_t *vpn, uint32_t *wi, uint32_t *ei)
{
if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
*wi = v & (dtlb ? 0xf : 0x7);
split_tlb_entry_spec_way(env, v, dtlb, vpn, *wi, ei);
if (*wi < (dtlb ? env->config->dtlb.nways : env->config->itlb.nways)) {
split_tlb_entry_spec_way(env, v, dtlb, vpn, *wi, ei);
return true;
} else {
return false;
}
} else {
*vpn = v & REGION_PAGE_MASK;
*wi = 0;
*ei = (v >> 29) & 0x7;
return true;
}
}
static xtensa_tlb_entry *xtensa_tlb_get_entry(CPUXtensaState *env, bool dtlb,
unsigned wi, unsigned ei)
{
const xtensa_tlb *tlb = dtlb ? &env->config->dtlb : &env->config->itlb;
assert(wi < tlb->nways && ei < tlb->way_size[wi]);
return dtlb ?
env->dtlb[wi] + ei :
env->itlb[wi] + ei;
@@ -254,11 +263,14 @@ static xtensa_tlb_entry *get_tlb_entry(CPUXtensaState *env,
uint32_t wi;
uint32_t ei;
split_tlb_entry_spec(env, v, dtlb, &vpn, &wi, &ei);
if (pwi) {
*pwi = wi;
if (split_tlb_entry_spec(env, v, dtlb, &vpn, &wi, &ei)) {
if (pwi) {
*pwi = wi;
}
return xtensa_tlb_get_entry(env, dtlb, wi, ei);
} else {
return NULL;
}
return xtensa_tlb_get_entry(env, dtlb, wi, ei);
}
static void xtensa_tlb_set_entry_mmu(const CPUXtensaState *env,
@@ -484,7 +496,12 @@ uint32_t HELPER(rtlb0)(CPUXtensaState *env, uint32_t v, uint32_t dtlb)
if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
uint32_t wi;
const xtensa_tlb_entry *entry = get_tlb_entry(env, v, dtlb, &wi);
return (entry->vaddr & get_vpn_mask(env, dtlb, wi)) | entry->asid;
if (entry) {
return (entry->vaddr & get_vpn_mask(env, dtlb, wi)) | entry->asid;
} else {
return 0;
}
} else {
return v & REGION_PAGE_MASK;
}
@@ -493,7 +510,12 @@ uint32_t HELPER(rtlb0)(CPUXtensaState *env, uint32_t v, uint32_t dtlb)
uint32_t HELPER(rtlb1)(CPUXtensaState *env, uint32_t v, uint32_t dtlb)
{
const xtensa_tlb_entry *entry = get_tlb_entry(env, v, dtlb, NULL);
return entry->paddr | entry->attr;
if (entry) {
return entry->paddr | entry->attr;
} else {
return 0;
}
}
void HELPER(itlb)(CPUXtensaState *env, uint32_t v, uint32_t dtlb)
@@ -501,7 +523,7 @@ void HELPER(itlb)(CPUXtensaState *env, uint32_t v, uint32_t dtlb)
if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
uint32_t wi;
xtensa_tlb_entry *entry = get_tlb_entry(env, v, dtlb, &wi);
if (entry->variable && entry->asid) {
if (entry && entry->variable && entry->asid) {
tlb_flush_page(env_cpu(env), entry->vaddr);
entry->asid = 0;
}
@@ -539,8 +561,9 @@ void HELPER(wtlb)(CPUXtensaState *env, uint32_t p, uint32_t v, uint32_t dtlb)
uint32_t vpn;
uint32_t wi;
uint32_t ei;
split_tlb_entry_spec(env, v, dtlb, &vpn, &wi, &ei);
xtensa_tlb_set_entry(env, dtlb, wi, ei, vpn, p);
if (split_tlb_entry_spec(env, v, dtlb, &vpn, &wi, &ei)) {
xtensa_tlb_set_entry(env, dtlb, wi, ei, vpn, p);
}
}
/*!
+2 -2
View File
@@ -421,8 +421,8 @@ QMP_VERSION
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_IMAGE_CORRUPTED", "data": {"device": "none0", "msg": "Preventing invalid write on metadata (overlaps with refcount table)", "offset": 65536, "node-name": "drive", "fatal": true, "size": 65536}}
write failed: Input/output error
{"return": ""}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
=== Testing incoming inactive corrupted image ===
@@ -432,8 +432,8 @@ QMP_VERSION
qcow2: Image is corrupt: L2 table offset 0x2a2a2a00 unaligned (L1 index: 0); further non-fatal corruption events will be suppressed
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_IMAGE_CORRUPTED", "data": {"device": "", "msg": "L2 table offset 0x2a2a2a00 unaligned (L1 index: 0)", "node-name": "drive", "fatal": false}}
{"return": ""}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
corrupt: false
*** done
+2 -2
View File
@@ -45,8 +45,8 @@ QMP_VERSION
{"return": {}}
read failed: Input/output error
{"return": ""}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
=== Testing blkverify on existing block device ===
@@ -84,9 +84,9 @@ wrote 512/512 bytes at offset 0
{"return": ""}
read failed: Input/output error
{"return": ""}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
QEMU_PROG: Failed to flush the L2 table cache: Input/output error
QEMU_PROG: Failed to flush the refcount block cache: Input/output error
{"return": {}}
*** done
+8 -8
View File
@@ -35,8 +35,8 @@ QMP_VERSION
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", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
== using quorum rewrite corrupted mode ==
@@ -67,8 +67,8 @@ QMP_VERSION
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", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
-- checking that the image has been corrected --
read 10485760/10485760 bytes at offset 0
@@ -106,8 +106,8 @@ QMP_VERSION
{"return": {}}
{"return": {}}
{"return": {}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
Testing:
QMP_VERSION
@@ -115,8 +115,8 @@ QMP_VERSION
{"return": {}}
{"return": {}}
{"error": {"class": "GenericError", "desc": "Cannot add a child to a quorum in blkverify mode"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
== dynamically removing a child from a quorum ==
@@ -125,31 +125,31 @@ QMP_VERSION
{"return": {}}
{"return": {}}
{"return": {}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
Testing:
QMP_VERSION
{"return": {}}
{"return": {}}
{"error": {"class": "GenericError", "desc": "The number of children cannot be lower than the vote threshold 2"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
Testing:
QMP_VERSION
{"return": {}}
{"error": {"class": "GenericError", "desc": "blkverify=on can only be set if there are exactly two files and vote-threshold is 2"}}
{"error": {"class": "GenericError", "desc": "Cannot find device='drive0-quorum' nor node-name='drive0-quorum'"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
Testing:
QMP_VERSION
{"return": {}}
{"return": {}}
{"error": {"class": "GenericError", "desc": "The number of children cannot be lower than the vote threshold 2"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
*** done
+6 -6
View File
@@ -7,8 +7,8 @@ Testing:
QMP_VERSION
{"return": {}}
{"error": {"class": "GenericError", "desc": "'node-name' must be specified for the root node"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
=== Duplicate ID ===
@@ -18,8 +18,8 @@ QMP_VERSION
{"return": {}}
{"error": {"class": "GenericError", "desc": "node-name=disk is conflicting with a device id"}}
{"error": {"class": "GenericError", "desc": "Duplicate nodes with node-name='test-node'"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
=== aio=native without O_DIRECT ===
@@ -28,8 +28,8 @@ Testing:
QMP_VERSION
{"return": {}}
{"error": {"class": "GenericError", "desc": "aio=native was specified, but it requires cache.direct=on, which was not specified."}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
=== Encrypted image QCow ===
@@ -40,8 +40,8 @@ QMP_VERSION
{"return": {}}
{"return": {}}
{"error": {"class": "GenericError", "desc": "Use of AES-CBC encrypted IMGFMT images is no longer supported in system emulators"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
=== Encrypted image LUKS ===
@@ -52,8 +52,8 @@ QMP_VERSION
{"return": {}}
{"return": {}}
{"return": {}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
=== Missing driver ===
@@ -63,7 +63,7 @@ Testing: -S
QMP_VERSION
{"return": {}}
{"error": {"class": "GenericError", "desc": "Parameter 'driver' is missing"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
*** done
+1 -1
View File
@@ -173,8 +173,8 @@ OK: Reftable is where we expect it
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "create"}}
{"return": {}}
{ "execute": "quit" }
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
wrote 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+2 -2
View File
@@ -57,13 +57,13 @@ run_qemu()
_launch_qemu -drive file="${source_img}",format=raw,cache=${CACHEMODE},aio=${AIOMODE},id=src
_send_qemu_cmd $QEMU_HANDLE "{ 'execute': 'qmp_capabilities' }" "return"
_send_qemu_cmd $QEMU_HANDLE \
capture_events="$qmp_event" _send_qemu_cmd $QEMU_HANDLE \
"{'execute':'drive-mirror', 'arguments':{
'device': 'src', 'target': '$raw_img', $qmp_format
'mode': 'existing', 'sync': 'full'}}" \
"return"
_send_qemu_cmd $QEMU_HANDLE '' "$qmp_event"
capture_events="$qmp_event JOB_STATUS_CHANGE" _wait_event $QEMU_HANDLE "$qmp_event"
if test "$qmp_event" = BLOCK_JOB_ERROR; then
_send_qemu_cmd $QEMU_HANDLE '' '"status": "null"'
fi
+33 -45
View File
@@ -7,7 +7,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE
{ 'execute': 'qmp_capabilities' }
{"return": {}}
{'execute':'drive-mirror', 'arguments':{
'device': 'src', 'target': 'TEST_DIR/t.IMGFMT',
'device': 'src', 'target': 'TEST_DIR/t.IMGFMT',
'mode': 'existing', 'sync': 'full'}}
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,8 +23,8 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed
{"execute":"query-block-jobs"}
{"return": []}
{"execute":"quit"}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
read 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{ 'execute': 'qmp_capabilities' }
@@ -35,12 +35,10 @@ read 512/512 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 1024, "offset": 1024, "speed": 0, "type": "mirror"}}
{"execute":"query-block-jobs"}
{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 1024, "offset": 1024, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
{"execute":"quit"}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "standby", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}}
@@ -48,6 +46,7 @@ read 512/512 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "src", "len": 1024, "offset": 1024, "speed": 0, "type": "mirror"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
{"return": {}}
Images are identical.
=== Writing a qcow2 header into raw ===
@@ -57,7 +56,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE
{ 'execute': 'qmp_capabilities' }
{"return": {}}
{'execute':'drive-mirror', 'arguments':{
'device': 'src', 'target': 'TEST_DIR/t.IMGFMT',
'device': 'src', 'target': 'TEST_DIR/t.IMGFMT',
'mode': 'existing', 'sync': 'full'}}
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.
@@ -73,8 +72,8 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed
{"execute":"query-block-jobs"}
{"return": []}
{"execute":"quit"}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
read 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{ 'execute': 'qmp_capabilities' }
@@ -85,12 +84,10 @@ read 512/512 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 197120, "offset": 197120, "speed": 0, "type": "mirror"}}
{"execute":"query-block-jobs"}
{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 197120, "offset": 197120, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
{"execute":"quit"}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "standby", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}}
@@ -98,6 +95,7 @@ read 512/512 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "src", "len": 197120, "offset": 197120, "speed": 0, "type": "mirror"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
{"return": {}}
Images are identical.
=== Writing a qed header into raw ===
@@ -107,7 +105,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE
{ 'execute': 'qmp_capabilities' }
{"return": {}}
{'execute':'drive-mirror', 'arguments':{
'device': 'src', 'target': 'TEST_DIR/t.IMGFMT',
'device': 'src', 'target': 'TEST_DIR/t.IMGFMT',
'mode': 'existing', 'sync': 'full'}}
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.
@@ -123,8 +121,8 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed
{"execute":"query-block-jobs"}
{"return": []}
{"execute":"quit"}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
read 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{ 'execute': 'qmp_capabilities' }
@@ -135,12 +133,10 @@ read 512/512 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 327680, "offset": 327680, "speed": 0, "type": "mirror"}}
{"execute":"query-block-jobs"}
{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 327680, "offset": 327680, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
{"execute":"quit"}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "standby", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}}
@@ -148,6 +144,7 @@ read 512/512 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "src", "len": 327680, "offset": 327680, "speed": 0, "type": "mirror"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
{"return": {}}
Images are identical.
=== Writing a vdi header into raw ===
@@ -157,7 +154,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE
{ 'execute': 'qmp_capabilities' }
{"return": {}}
{'execute':'drive-mirror', 'arguments':{
'device': 'src', 'target': 'TEST_DIR/t.IMGFMT',
'device': 'src', 'target': 'TEST_DIR/t.IMGFMT',
'mode': 'existing', 'sync': 'full'}}
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.
@@ -173,8 +170,8 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed
{"execute":"query-block-jobs"}
{"return": []}
{"execute":"quit"}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
read 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{ 'execute': 'qmp_capabilities' }
@@ -185,12 +182,10 @@ read 512/512 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 1024, "offset": 1024, "speed": 0, "type": "mirror"}}
{"execute":"query-block-jobs"}
{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 1024, "offset": 1024, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
{"execute":"quit"}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "standby", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}}
@@ -198,6 +193,7 @@ read 512/512 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "src", "len": 1024, "offset": 1024, "speed": 0, "type": "mirror"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
{"return": {}}
Images are identical.
=== Writing a vmdk header into raw ===
@@ -207,7 +203,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE
{ 'execute': 'qmp_capabilities' }
{"return": {}}
{'execute':'drive-mirror', 'arguments':{
'device': 'src', 'target': 'TEST_DIR/t.IMGFMT',
'device': 'src', 'target': 'TEST_DIR/t.IMGFMT',
'mode': 'existing', 'sync': 'full'}}
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.
@@ -223,8 +219,8 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed
{"execute":"query-block-jobs"}
{"return": []}
{"execute":"quit"}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
read 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{ 'execute': 'qmp_capabilities' }
@@ -235,12 +231,10 @@ read 512/512 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 65536, "offset": 65536, "speed": 0, "type": "mirror"}}
{"execute":"query-block-jobs"}
{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 65536, "offset": 65536, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
{"execute":"quit"}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "standby", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}}
@@ -248,6 +242,7 @@ read 512/512 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "src", "len": 65536, "offset": 65536, "speed": 0, "type": "mirror"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
{"return": {}}
Images are identical.
=== Writing a vpc header into raw ===
@@ -257,7 +252,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE
{ 'execute': 'qmp_capabilities' }
{"return": {}}
{'execute':'drive-mirror', 'arguments':{
'device': 'src', 'target': 'TEST_DIR/t.IMGFMT',
'device': 'src', 'target': 'TEST_DIR/t.IMGFMT',
'mode': 'existing', 'sync': 'full'}}
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.
@@ -273,8 +268,8 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed
{"execute":"query-block-jobs"}
{"return": []}
{"execute":"quit"}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
read 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{ 'execute': 'qmp_capabilities' }
@@ -285,12 +280,10 @@ read 512/512 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 2560, "offset": 2560, "speed": 0, "type": "mirror"}}
{"execute":"query-block-jobs"}
{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 2560, "offset": 2560, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
{"execute":"quit"}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "standby", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}}
@@ -298,6 +291,7 @@ read 512/512 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "src", "len": 2560, "offset": 2560, "speed": 0, "type": "mirror"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
{"return": {}}
Images are identical.
=== Copying sample image empty.bochs into raw ===
@@ -306,7 +300,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE
{ 'execute': 'qmp_capabilities' }
{"return": {}}
{'execute':'drive-mirror', 'arguments':{
'device': 'src', 'target': 'TEST_DIR/t.IMGFMT',
'device': 'src', 'target': 'TEST_DIR/t.IMGFMT',
'mode': 'existing', 'sync': 'full'}}
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.
@@ -322,8 +316,8 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed
{"execute":"query-block-jobs"}
{"return": []}
{"execute":"quit"}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
read 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{ 'execute': 'qmp_capabilities' }
@@ -334,12 +328,10 @@ read 512/512 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 2560, "offset": 2560, "speed": 0, "type": "mirror"}}
{"execute":"query-block-jobs"}
{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 2560, "offset": 2560, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
{"execute":"quit"}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "standby", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}}
@@ -347,6 +339,7 @@ read 512/512 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "src", "len": 2560, "offset": 2560, "speed": 0, "type": "mirror"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
{"return": {}}
Images are identical.
=== Copying sample image iotest-dirtylog-10G-4M.vhdx into raw ===
@@ -355,7 +348,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE
{ 'execute': 'qmp_capabilities' }
{"return": {}}
{'execute':'drive-mirror', 'arguments':{
'device': 'src', 'target': 'TEST_DIR/t.IMGFMT',
'device': 'src', 'target': 'TEST_DIR/t.IMGFMT',
'mode': 'existing', 'sync': 'full'}}
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.
@@ -371,8 +364,8 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed
{"execute":"query-block-jobs"}
{"return": []}
{"execute":"quit"}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
read 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{ 'execute': 'qmp_capabilities' }
@@ -383,12 +376,10 @@ read 512/512 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 31457280, "offset": 31457280, "speed": 0, "type": "mirror"}}
{"execute":"query-block-jobs"}
{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 31457280, "offset": 31457280, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
{"execute":"quit"}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "standby", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}}
@@ -396,6 +387,7 @@ read 512/512 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "src", "len": 31457280, "offset": 31457280, "speed": 0, "type": "mirror"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
{"return": {}}
Images are identical.
=== Copying sample image parallels-v1 into raw ===
@@ -404,7 +396,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE
{ 'execute': 'qmp_capabilities' }
{"return": {}}
{'execute':'drive-mirror', 'arguments':{
'device': 'src', 'target': 'TEST_DIR/t.IMGFMT',
'device': 'src', 'target': 'TEST_DIR/t.IMGFMT',
'mode': 'existing', 'sync': 'full'}}
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.
@@ -420,8 +412,8 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed
{"execute":"query-block-jobs"}
{"return": []}
{"execute":"quit"}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
read 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{ 'execute': 'qmp_capabilities' }
@@ -432,12 +424,10 @@ read 512/512 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 327680, "offset": 327680, "speed": 0, "type": "mirror"}}
{"execute":"query-block-jobs"}
{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 327680, "offset": 327680, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
{"execute":"quit"}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "standby", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}}
@@ -445,6 +435,7 @@ read 512/512 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "src", "len": 327680, "offset": 327680, "speed": 0, "type": "mirror"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
{"return": {}}
Images are identical.
=== Copying sample image simple-pattern.cloop into raw ===
@@ -453,7 +444,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE
{ 'execute': 'qmp_capabilities' }
{"return": {}}
{'execute':'drive-mirror', 'arguments':{
'device': 'src', 'target': 'TEST_DIR/t.IMGFMT',
'device': 'src', 'target': 'TEST_DIR/t.IMGFMT',
'mode': 'existing', 'sync': 'full'}}
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.
@@ -469,8 +460,8 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed
{"execute":"query-block-jobs"}
{"return": []}
{"execute":"quit"}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
read 512/512 bytes at offset 0
512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{ 'execute': 'qmp_capabilities' }
@@ -481,12 +472,10 @@ read 512/512 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 2048, "offset": 2048, "speed": 0, "type": "mirror"}}
{"execute":"query-block-jobs"}
{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 2048, "offset": 2048, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
{"execute":"quit"}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "standby", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}}
@@ -494,6 +483,7 @@ read 512/512 bytes at offset 0
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "src", "len": 2048, "offset": 2048, "speed": 0, "type": "mirror"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
{"return": {}}
Images are identical.
=== Write legitimate MBR into raw ===
@@ -502,7 +492,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=SIZE
{ 'execute': 'qmp_capabilities' }
{"return": {}}
{'execute':'drive-mirror', 'arguments':{
'device': 'src', 'target': 'TEST_DIR/t.IMGFMT',
'device': 'src', 'target': 'TEST_DIR/t.IMGFMT',
'mode': 'existing', 'sync': 'full'}}
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.
@@ -510,12 +500,10 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 512, "offset": 512, "speed": 0, "type": "mirror"}}
{"execute":"query-block-jobs"}
{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 512, "offset": 512, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
{"execute":"quit"}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "standby", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}}
@@ -523,6 +511,7 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "src", "len": 512, "offset": 512, "speed": 0, "type": "mirror"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
{"return": {}}
Images are identical.
{ 'execute': 'qmp_capabilities' }
{"return": {}}
@@ -532,12 +521,10 @@ Images are identical.
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "src"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "src", "len": 512, "offset": 512, "speed": 0, "type": "mirror"}}
{"execute":"query-block-jobs"}
{"return": [{"auto-finalize": true, "io-status": "ok", "device": "src", "auto-dismiss": true, "busy": false, "len": 512, "offset": 512, "status": "ready", "paused": false, "speed": 0, "ready": true, "type": "mirror"}]}
{"execute":"quit"}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "standby", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "src"}}
@@ -545,5 +532,6 @@ Images are identical.
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "src", "len": 512, "offset": 512, "speed": 0, "type": "mirror"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "src"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "src"}}
{"return": {}}
Images are identical.
*** done
+1 -1
View File
@@ -18,8 +18,8 @@ wrote 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
{"return": ""}
{ 'execute': 'quit' }
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
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)
+1 -1
View File
@@ -5,8 +5,8 @@ QMP_VERSION
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", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
read 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
read 65536/65536 bytes at offset 0
+1 -1
View File
@@ -28,6 +28,6 @@ wrote 42/42 bytes at offset 0
{ 'execute': 'quit' }
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "mirror"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "mirror"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
*** done
+1 -1
View File
@@ -19,6 +19,6 @@ read 65536/65536 bytes at offset 0
qemu-io: can't open device nbd+unix:///drv?socket=SOCK_DIR/nbd: Requested export not available
server reported: export 'drv' not present
{ 'execute': 'quit' }
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
*** done
+114 -159
View File
@@ -1,9 +1,12 @@
#!/usr/bin/env bash
#!/usr/bin/env python3
# group: rw auto quick
#
# Test case for ejecting BDSs with block jobs still running on them
#
# Copyright (C) 2016 Red Hat, Inc.
# Originally written in bash by Hanna Czenczek, ported to Python by Stefan
# Hajnoczi.
#
# Copyright Red Hat
#
# 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
@@ -19,177 +22,129 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# creator
owner=hreitz@redhat.com
import iotests
seq="$(basename $0)"
echo "QA output created by $seq"
status=1 # failure is the default!
_cleanup()
{
_cleanup_qemu
_cleanup_test_img
for img in "$TEST_DIR"/{b,m,o}.$IMGFMT; do
_rm_test_img "$img"
done
}
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
# Common filters to mask values that vary in the test output
QMP_FILTERS = [iotests.filter_qmp_testfiles, \
iotests.filter_qmp_imgfmt]
test_blockjob()
{
_send_qemu_cmd $QEMU_HANDLE \
"{'execute': 'blockdev-add',
'arguments': {
'node-name': 'drv0',
'driver': '$IMGFMT',
'file': {
'driver': 'file',
'filename': '$TEST_IMG'
}}}" \
'return'
class TestCase:
def __init__(self, name, vm, image_path, cancel_event):
self.name = name
self.vm = vm
self.image_path = image_path
self.cancel_event = cancel_event
# If "$2" is an event, we may or may not see it before the
# {"return": {}}. Therefore, filter the {"return": {}} out both
# here and in the next command. (Naturally, if we do not see it
# here, we will see it before the next command can be executed,
# so it will appear in the next _send_qemu_cmd's output.)
_send_qemu_cmd $QEMU_HANDLE \
"$1" \
"$2" \
| _filter_img_create | _filter_qmp_empty_return
def __enter__(self):
iotests.log(f'=== Testing {self.name} ===')
self.vm.qmp_log('blockdev-add', \
node_name='drv0', \
driver=iotests.imgfmt, \
file={'driver': 'file', 'filename': self.image_path}, \
filters=QMP_FILTERS)
# We want this to return an error because the block job is still running
_send_qemu_cmd $QEMU_HANDLE \
"{'execute': 'blockdev-del',
'arguments': {'node-name': 'drv0'}}" \
'error' | _filter_generated_node_ids | _filter_qmp_empty_return
def __exit__(self, *exc_details):
# This is expected to fail because the job still exists
self.vm.qmp_log('blockdev-del', node_name='drv0', \
filters=[iotests.filter_qmp_generated_node_ids])
_send_qemu_cmd $QEMU_HANDLE \
"{'execute': 'block-job-cancel',
'arguments': {'device': 'job0'}}" \
"$3"
self.vm.qmp_log('block-job-cancel', device='job0')
event = self.vm.event_wait(self.cancel_event)
iotests.log(event, filters=[iotests.filter_qmp_event])
_send_qemu_cmd $QEMU_HANDLE \
"{'execute': 'blockdev-del',
'arguments': {'node-name': 'drv0'}}" \
'return'
}
# This time it succeeds
self.vm.qmp_log('blockdev-del', node_name='drv0')
# Separate test cases in output
iotests.log('')
TEST_IMG="$TEST_DIR/b.$IMGFMT" _make_test_img 1M
TEST_IMG="$TEST_DIR/m.$IMGFMT" _make_test_img -b "$TEST_DIR/b.$IMGFMT" -F $IMGFMT 1M
_make_test_img -b "$TEST_DIR/m.$IMGFMT" 1M -F $IMGFMT
def main() -> None:
with iotests.FilePath('bottom', 'middle', 'top', 'target') as \
(bottom_path, middle_path, top_path, target_path), \
iotests.VM() as vm:
_launch_qemu -nodefaults
iotests.log('Creating bottom <- middle <- top backing file chain...')
IMAGE_SIZE='1M'
iotests.qemu_img_create('-f', iotests.imgfmt, bottom_path, IMAGE_SIZE)
iotests.qemu_img_create('-f', iotests.imgfmt, \
'-F', iotests.imgfmt, \
'-b', bottom_path, \
middle_path, \
IMAGE_SIZE)
iotests.qemu_img_create('-f', iotests.imgfmt, \
'-F', iotests.imgfmt, \
'-b', middle_path, \
top_path, \
IMAGE_SIZE)
_send_qemu_cmd $QEMU_HANDLE \
"{'execute': 'qmp_capabilities'}" \
'return'
iotests.log('Starting VM...')
vm.add_args('-nodefaults')
vm.launch()
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.
with TestCase('drive-backup', vm, top_path, 'BLOCK_JOB_CANCELLED'):
vm.qmp_log('drive-backup', \
job_id='job0', \
device='drv0', \
target=target_path, \
format=iotests.imgfmt, \
sync='none', \
filters=QMP_FILTERS)
# drive-backup will not send BLOCK_JOB_READY by itself, and cancelling the job
# will consequently result in BLOCK_JOB_CANCELLED being emitted.
# drive-mirror will send BLOCK_JOB_READY basically immediately, and
# cancelling the job will consequently result in BLOCK_JOB_COMPLETED
# being emitted.
with TestCase('drive-mirror', vm, top_path, 'BLOCK_JOB_COMPLETED'):
vm.qmp_log('drive-mirror', \
job_id='job0', \
device='drv0', \
target=target_path, \
format=iotests.imgfmt, \
sync='none', \
filters=QMP_FILTERS)
event = vm.event_wait('BLOCK_JOB_READY')
assert event is not None # silence mypy
iotests.log(event, filters=[iotests.filter_qmp_event])
test_blockjob \
"{'execute': 'drive-backup',
'arguments': {'job-id': 'job0',
'device': 'drv0',
'target': '$TEST_DIR/o.$IMGFMT',
'format': '$IMGFMT',
'sync': 'none'}}" \
'return' \
'"status": "null"'
# An active block-commit will send BLOCK_JOB_READY basically
# immediately, and cancelling the job will consequently result in
# BLOCK_JOB_COMPLETED being emitted.
with TestCase('active block-commit', vm, top_path, \
'BLOCK_JOB_COMPLETED'):
vm.qmp_log('block-commit', \
job_id='job0', \
device='drv0')
event = vm.event_wait('BLOCK_JOB_READY')
assert event is not None # silence mypy
iotests.log(event, filters=[iotests.filter_qmp_event])
echo
echo '=== Testing drive-mirror ==='
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.
iotests.qemu_io(middle_path, '-c', f'write 0 {IMAGE_SIZE}')
with TestCase('non-active block-commit', vm, top_path, \
'BLOCK_JOB_CANCELLED'):
vm.qmp_log('block-commit', \
job_id='job0', \
device='drv0', \
top=middle_path, \
speed=1, \
filters=[iotests.filter_qmp_testfiles])
# drive-mirror will send BLOCK_JOB_READY basically immediately, and cancelling
# the job will consequently result in BLOCK_JOB_COMPLETED being emitted.
# 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.
iotests.qemu_io(bottom_path, '-c', f'write 0 {IMAGE_SIZE}')
with TestCase('block-stream', vm, top_path, 'BLOCK_JOB_CANCELLED'):
vm.qmp_log('block-stream', \
job_id='job0', \
device='drv0', \
speed=1)
test_blockjob \
"{'execute': 'drive-mirror',
'arguments': {'job-id': 'job0',
'device': 'drv0',
'target': '$TEST_DIR/o.$IMGFMT',
'format': '$IMGFMT',
'sync': 'none'}}" \
'BLOCK_JOB_READY' \
'"status": "null"'
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': {'job-id': 'job0', 'device': 'drv0'}}" \
'BLOCK_JOB_READY' \
'"status": "null"'
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': {'job-id': 'job0',
'device': 'drv0',
'top': '$TEST_DIR/m.$IMGFMT',
'speed': 1}}" \
'return' \
'"status": "null"'
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.
test_blockjob \
"{'execute': 'block-stream',
'arguments': {'job-id': 'job0',
'device': 'drv0',
'speed': 1}}" \
'return' \
'"status": "null"'
_cleanup_qemu
# success, all done
echo "*** done"
rm -f $seq.full
status=0
if __name__ == '__main__':
iotests.script_main(main, supported_fmts=['qcow2', 'qed'],
supported_protocols=['file'])
+40 -150
View File
@@ -1,179 +1,69 @@
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 backing_fmt=IMGFMT
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/m.IMGFMT backing_fmt=IMGFMT
{'execute': 'qmp_capabilities'}
{"return": {}}
Creating bottom <- middle <- top backing file chain...
Starting VM...
=== Testing drive-backup ===
{'execute': 'blockdev-add',
'arguments': {
'node-name': 'drv0',
'driver': 'IMGFMT',
'file': {
'driver': 'file',
'filename': 'TEST_DIR/t.IMGFMT'
}}}
{"execute": "blockdev-add", "arguments": {"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top"}, "node-name": "drv0"}}
{"return": {}}
{'execute': 'drive-backup',
'arguments': {'job-id': 'job0',
'device': 'drv0',
'target': 'TEST_DIR/o.IMGFMT',
'format': 'IMGFMT',
'sync': 'none'}}
Formatting 'TEST_DIR/o.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT backing_fmt=IMGFMT
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "paused", "id": "job0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}}
{'execute': 'blockdev-del',
'arguments': {'node-name': 'drv0'}}
{"execute": "drive-backup", "arguments": {"device": "drv0", "format": "IMGFMT", "job-id": "job0", "sync": "none", "target": "TEST_DIR/PID-target"}}
{"return": {}}
{"execute": "blockdev-del", "arguments": {"node-name": "drv0"}}
{"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: node is used as backing hd of 'NODE_NAME'"}}
{'execute': 'block-job-cancel',
'arguments': {'device': 'job0'}}
{"execute": "block-job-cancel", "arguments": {"device": "job0"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "job0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "job0", "len": 1048576, "offset": 0, "speed": 0, "type": "backup"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job0"}}
{'execute': 'blockdev-del',
'arguments': {'node-name': 'drv0'}}
{"data": {"device": "job0", "len": 1048576, "offset": 0, "speed": 0, "type": "backup"}, "event": "BLOCK_JOB_CANCELLED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"execute": "blockdev-del", "arguments": {"node-name": "drv0"}}
{"return": {}}
=== Testing drive-mirror ===
{'execute': 'blockdev-add',
'arguments': {
'node-name': 'drv0',
'driver': 'IMGFMT',
'file': {
'driver': 'file',
'filename': 'TEST_DIR/t.IMGFMT'
}}}
{"execute": "blockdev-add", "arguments": {"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top"}, "node-name": "drv0"}}
{"return": {}}
{'execute': 'drive-mirror',
'arguments': {'job-id': 'job0',
'device': 'drv0',
'target': 'TEST_DIR/o.IMGFMT',
'format': 'IMGFMT',
'sync': 'none'}}
Formatting 'TEST_DIR/o.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT backing_fmt=IMGFMT
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "job0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "mirror"}}
{'execute': 'blockdev-del',
'arguments': {'node-name': 'drv0'}}
{"execute": "drive-mirror", "arguments": {"device": "drv0", "format": "IMGFMT", "job-id": "job0", "sync": "none", "target": "TEST_DIR/PID-target"}}
{"return": {}}
{"data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"execute": "blockdev-del", "arguments": {"node-name": "drv0"}}
{"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: block device is in use by block job: mirror"}}
{'execute': 'block-job-cancel',
'arguments': {'device': 'job0'}}
{"execute": "block-job-cancel", "arguments": {"device": "job0"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "mirror"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job0"}}
{'execute': 'blockdev-del',
'arguments': {'node-name': 'drv0'}}
{"data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"execute": "blockdev-del", "arguments": {"node-name": "drv0"}}
{"return": {}}
=== Testing active block-commit ===
{'execute': 'blockdev-add',
'arguments': {
'node-name': 'drv0',
'driver': 'IMGFMT',
'file': {
'driver': 'file',
'filename': 'TEST_DIR/t.IMGFMT'
}}}
{"execute": "blockdev-add", "arguments": {"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top"}, "node-name": "drv0"}}
{"return": {}}
{'execute': 'block-commit',
'arguments': {'job-id': 'job0', 'device': 'drv0'}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "job0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}}
{'execute': 'blockdev-del',
'arguments': {'node-name': 'drv0'}}
{"execute": "block-commit", "arguments": {"device": "drv0", "job-id": "job0"}}
{"return": {}}
{"data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"execute": "blockdev-del", "arguments": {"node-name": "drv0"}}
{"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: block device is in use by block job: commit"}}
{'execute': 'block-job-cancel',
'arguments': {'device': 'job0'}}
{"execute": "block-job-cancel", "arguments": {"device": "job0"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job0"}}
{'execute': 'blockdev-del',
'arguments': {'node-name': 'drv0'}}
{"data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"execute": "blockdev-del", "arguments": {"node-name": "drv0"}}
{"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)
{'execute': 'blockdev-add',
'arguments': {
'node-name': 'drv0',
'driver': 'IMGFMT',
'file': {
'driver': 'file',
'filename': 'TEST_DIR/t.IMGFMT'
}}}
{"execute": "blockdev-add", "arguments": {"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top"}, "node-name": "drv0"}}
{"return": {}}
{'execute': 'block-commit',
'arguments': {'job-id': 'job0',
'device': 'drv0',
'top': 'TEST_DIR/m.IMGFMT',
'speed': 1}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}}
{'execute': 'blockdev-del',
'arguments': {'node-name': 'drv0'}}
{"execute": "block-commit", "arguments": {"device": "drv0", "job-id": "job0", "speed": 1, "top": "TEST_DIR/PID-middle"}}
{"return": {}}
{"execute": "blockdev-del", "arguments": {"node-name": "drv0"}}
{"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: block device is in use by block job: commit"}}
{'execute': 'block-job-cancel',
'arguments': {'device': 'job0'}}
{"execute": "block-job-cancel", "arguments": {"device": "job0"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "job0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "job0", "len": 1048576, "offset": 524288, "speed": 1, "type": "commit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job0"}}
{'execute': 'blockdev-del',
'arguments': {'node-name': 'drv0'}}
{"data": {"device": "job0", "len": 1048576, "offset": 524288, "speed": 1, "type": "commit"}, "event": "BLOCK_JOB_CANCELLED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"execute": "blockdev-del", "arguments": {"node-name": "drv0"}}
{"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)
{'execute': 'blockdev-add',
'arguments': {
'node-name': 'drv0',
'driver': 'IMGFMT',
'file': {
'driver': 'file',
'filename': 'TEST_DIR/t.IMGFMT'
}}}
{"execute": "blockdev-add", "arguments": {"driver": "IMGFMT", "file": {"driver": "file", "filename": "TEST_DIR/PID-top"}, "node-name": "drv0"}}
{"return": {}}
{'execute': 'block-stream',
'arguments': {'job-id': 'job0',
'device': 'drv0',
'speed': 1}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}}
{'execute': 'blockdev-del',
'arguments': {'node-name': 'drv0'}}
{"execute": "block-stream", "arguments": {"device": "drv0", "job-id": "job0", "speed": 1}}
{"return": {}}
{"execute": "blockdev-del", "arguments": {"node-name": "drv0"}}
{"error": {"class": "GenericError", "desc": "Node 'drv0' is busy: block device is in use by block job: stream"}}
{'execute': 'block-job-cancel',
'arguments': {'device': 'job0'}}
{"execute": "block-job-cancel", "arguments": {"device": "job0"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "job0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "job0", "len": 1048576, "offset": 524288, "speed": 1, "type": "stream"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job0"}}
{'execute': 'blockdev-del',
'arguments': {'node-name': 'drv0'}}
{"data": {"device": "job0", "len": 1048576, "offset": 524288, "speed": 1, "type": "stream"}, "event": "BLOCK_JOB_CANCELLED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"execute": "blockdev-del", "arguments": {"node-name": "drv0"}}
{"return": {}}
*** done
+1 -1
View File
@@ -10,6 +10,6 @@ server reported: export 'no_such_export' not present
qemu-io: can't open device nbd+unix:///aa--aa1?socket=SOCK_DIR/nbd: Requested export not available
server reported: export 'aa--aa...' not present
{ 'execute': 'quit' }
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
*** done
+1 -1
View File
@@ -72,8 +72,8 @@ read 65536/65536 bytes at offset 196608
{"return": ""}
{ 'execute': 'quit' }
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
read 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+8 -8
View File
@@ -169,8 +169,8 @@ QMP_VERSION
{"return": {}}
{"return": {}}
{"return": {}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
wrote 196608/196608 bytes at offset 2147287040
192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 131072/131072 bytes at offset 2147352576
@@ -206,8 +206,8 @@ QMP_VERSION
{"return": {}}
{"return": {}}
{"return": {"sha256": HASH}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
=== Test pass bitmap.1 ===
@@ -218,8 +218,8 @@ QMP_VERSION
{"return": {}}
{"return": {}}
{"return": {}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
wrote 196608/196608 bytes at offset 2147287040
192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 131072/131072 bytes at offset 2147352576
@@ -256,8 +256,8 @@ QMP_VERSION
{"return": {}}
{"return": {}}
{"return": {"sha256": HASH}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
=== Test pass bitmap.2 ===
@@ -268,8 +268,8 @@ QMP_VERSION
{"return": {}}
{"return": {}}
{"return": {}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
wrote 196608/196608 bytes at offset 2147287040
192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 131072/131072 bytes at offset 2147352576
@@ -306,8 +306,8 @@ QMP_VERSION
{"return": {}}
{"return": {}}
{"return": {"sha256": HASH}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
=== Test pass bitmap.3 ===
@@ -318,8 +318,8 @@ QMP_VERSION
{"return": {}}
{"return": {}}
{"return": {}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
wrote 196608/196608 bytes at offset 2147287040
192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 131072/131072 bytes at offset 2147352576
@@ -353,6 +353,6 @@ QMP_VERSION
{"return": {}}
{"return": {}}
{"return": {"sha256": HASH}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
*** done
+1 -1
View File
@@ -53,6 +53,6 @@ Formatting 'TEST_DIR/t.qcow2.overlay', fmt=qcow2 cluster_size=65536 extended_l2=
{'execute': 'qmp_capabilities'}
{"return": {}}
{'execute': 'quit'}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
*** done
+2 -2
View File
@@ -53,11 +53,11 @@ wrote 65536/65536 bytes at offset 1048576
=== Shut down and check image ===
{"execute":"quit"}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
{"execute":"quit"}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
No errors were found on the image.
No errors were found on the image.
wrote 65536/65536 bytes at offset 1048576
+16 -16
View File
@@ -89,10 +89,6 @@ Testing:
"return": [
]
}
{
"return": {
}
}
{
"timestamp": {
"seconds": TIMESTAMP,
@@ -104,6 +100,10 @@ Testing:
"reason": "host-qmp-quit"
}
}
{
"return": {
}
}
== property changes in ThrottleGroup ==
@@ -169,10 +169,6 @@ Testing:
"iops-total-max": 0
}
}
{
"return": {
}
}
{
"timestamp": {
"seconds": TIMESTAMP,
@@ -184,6 +180,10 @@ Testing:
"reason": "host-qmp-quit"
}
}
{
"return": {
}
}
== object creation/set errors ==
@@ -211,10 +211,6 @@ Testing:
"desc": "bps/iops/max total values and read/write values cannot be used at the same time"
}
}
{
"return": {
}
}
{
"timestamp": {
"seconds": TIMESTAMP,
@@ -226,6 +222,10 @@ Testing:
"reason": "host-qmp-quit"
}
}
{
"return": {
}
}
== don't specify group ==
@@ -247,10 +247,6 @@ Testing:
"desc": "Parameter 'throttle-group' is missing"
}
}
{
"return": {
}
}
{
"timestamp": {
"seconds": TIMESTAMP,
@@ -262,6 +258,10 @@ Testing:
"reason": "host-qmp-quit"
}
}
{
"return": {
}
}
*** done
+3 -3
View File
@@ -344,14 +344,14 @@ wait_for_job_and_quit() {
sleep 1
# List of expected events
capture_events='BLOCK_JOB_CANCELLED JOB_STATUS_CHANGE SHUTDOWN'
_send_qemu_cmd $h \
'{"execute": "quit"}' \
'return'
# List of expected events
capture_events='BLOCK_JOB_CANCELLED JOB_STATUS_CHANGE SHUTDOWN'
_wait_event $h 'SHUTDOWN'
QEMU_EVENTS= # Ignore all JOB_STATUS_CHANGE events that came before SHUTDOWN
_wait_event $h 'JOB_STATUS_CHANGE' # standby
_wait_event $h 'JOB_STATUS_CHANGE' # ready
_wait_event $h 'JOB_STATUS_CHANGE' # aborting
+40 -5
View File
@@ -40,9 +40,16 @@ Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off comp
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}}
{"return": {}}
{ 'execute': 'quit' }
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "paused", "id": "disk"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "paused", "id": "disk"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "disk"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "disk", "len": 67108864, "offset": 524288, "speed": 65536, "type": "commit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "disk"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "disk"}}
{"return": {}}
=== Start active commit job and exit qemu ===
@@ -56,9 +63,16 @@ Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off comp
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}}
{"return": {}}
{ 'execute': 'quit' }
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "paused", "id": "disk"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "paused", "id": "disk"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "disk"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "disk", "len": 4194304, "offset": 4194304, "speed": 65536, "type": "commit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "disk"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "disk"}}
{"return": {}}
=== Start mirror job and exit qemu ===
@@ -75,9 +89,16 @@ Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 cluster_size=65536 extended_l2=off
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}}
{"return": {}}
{ 'execute': 'quit' }
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "paused", "id": "disk"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "paused", "id": "disk"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "disk"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "disk", "len": 4194304, "offset": 4194304, "speed": 65536, "type": "mirror"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "disk"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "disk"}}
{"return": {}}
=== Start backup job and exit qemu ===
@@ -97,9 +118,16 @@ Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 cluster_size=65536 extended_l2=off
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}}
{"return": {}}
{ 'execute': 'quit' }
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "paused", "id": "disk"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "paused", "id": "disk"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "disk"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "disk", "len": 67108864, "offset": 65536, "speed": 65536, "type": "backup"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "disk"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "disk"}}
{"return": {}}
=== Start streaming job and exit qemu ===
@@ -112,9 +140,16 @@ Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 cluster_size=65536 extended_l2=off
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}}
{"return": {}}
{ 'execute': 'quit' }
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "paused", "id": "disk"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "paused", "id": "disk"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "disk"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "disk"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "disk", "len": 67108864, "offset": 524288, "speed": 65536, "type": "stream"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "disk"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "disk"}}
{"return": {}}
No errors were found on the image.
=== Start mirror to throttled QSD and exit qemu ===
+8 -8
View File
@@ -378,10 +378,6 @@ wrote 65536/65536 bytes at offset 1048576
]
}
{ 'execute': 'quit' }
{
"return": {
}
}
{
"timestamp": {
"seconds": TIMESTAMP,
@@ -393,6 +389,10 @@ wrote 65536/65536 bytes at offset 1048576
"reason": "host-qmp-quit"
}
}
{
"return": {
}
}
image: TEST_DIR/t.IMGFMT
file format: IMGFMT
virtual size: 64 MiB (67108864 bytes)
@@ -796,10 +796,6 @@ wrote 65536/65536 bytes at offset 1048576
]
}
{ 'execute': 'quit' }
{
"return": {
}
}
{
"timestamp": {
"seconds": TIMESTAMP,
@@ -811,6 +807,10 @@ wrote 65536/65536 bytes at offset 1048576
"reason": "host-qmp-quit"
}
}
{
"return": {
}
}
image: TEST_DIR/t.IMGFMT
file format: IMGFMT
virtual size: 64 MiB (67108864 bytes)
+8 -8
View File
@@ -17,10 +17,6 @@ Testing: -drive if=none,file=TEST_DIR/t.IMGFMT,backing.node-name=mid
"return": {
}
}
{
"return": {
}
}
{
"timestamp": {
"seconds": TIMESTAMP,
@@ -32,6 +28,10 @@ Testing: -drive if=none,file=TEST_DIR/t.IMGFMT,backing.node-name=mid
"reason": "host-qmp-quit"
}
}
{
"return": {
}
}
image: TEST_DIR/t.IMGFMT.mid
file format: IMGFMT
@@ -55,10 +55,6 @@ Testing: -drive if=none,file=TEST_DIR/t.IMGFMT,node-name=top
"return": {
}
}
{
"return": {
}
}
{
"timestamp": {
"seconds": TIMESTAMP,
@@ -70,6 +66,10 @@ Testing: -drive if=none,file=TEST_DIR/t.IMGFMT,node-name=top
"reason": "host-qmp-quit"
}
}
{
"return": {
}
}
image: TEST_DIR/t.IMGFMT
file format: IMGFMT
+8 -8
View File
@@ -11,8 +11,8 @@ QMP_VERSION
{"return": {}}
{"return": {}}
{"return": {}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
=== Write part of the file under active bitmap ===
@@ -142,14 +142,14 @@ read 2097152/2097152 bytes at offset 2097152
{"execute":"nbd-server-remove",
"arguments":{"name":"n"}}
{"return": {}}
{"execute":"nbd-server-remove",
"arguments":{"name":"n2"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "n"}}
{"return": {}}
{"execute":"nbd-server-remove",
"arguments":{"name":"n2"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "n2"}}
{"return": {}}
{"execute":"nbd-server-remove",
"arguments":{"name":"n2"}}
{"error": {"class": "GenericError", "desc": "Export 'n2' is not found"}}
{"execute":"nbd-server-stop"}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "n3"}}
@@ -261,14 +261,14 @@ read 2097152/2097152 bytes at offset 2097152
{"execute":"nbd-server-remove",
"arguments":{"name":"n"}}
{"return": {}}
{"execute":"nbd-server-remove",
"arguments":{"name":"n2"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "n"}}
{"return": {}}
{"execute":"nbd-server-remove",
"arguments":{"name":"n2"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "n2"}}
{"return": {}}
{"execute":"nbd-server-remove",
"arguments":{"name":"n2"}}
{"error": {"class": "GenericError", "desc": "Export 'n2' is not found"}}
{"execute":"nbd-server-stop"}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "n3"}}
@@ -276,8 +276,8 @@ read 2097152/2097152 bytes at offset 2097152
{"execute":"nbd-server-stop"}
{"error": {"class": "GenericError", "desc": "NBD server not running"}}
{"execute":"quit"}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
=== Use qemu-nbd as server ===
+16 -16
View File
@@ -48,10 +48,6 @@ Testing: -drive driver=null-co,read-zeroes=on,if=virtio
}
]
}
{
"return": {
}
}
{
"timestamp": {
"seconds": TIMESTAMP,
@@ -63,6 +59,10 @@ Testing: -drive driver=null-co,read-zeroes=on,if=virtio
"reason": "host-qmp-quit"
}
}
{
"return": {
}
}
=== blockstats with -drive if=none ===
@@ -112,10 +112,6 @@ Testing: -drive driver=null-co,if=none
}
]
}
{
"return": {
}
}
{
"timestamp": {
"seconds": TIMESTAMP,
@@ -127,6 +123,10 @@ Testing: -drive driver=null-co,if=none
"reason": "host-qmp-quit"
}
}
{
"return": {
}
}
=== blockstats with -blockdev ===
@@ -143,10 +143,6 @@ Testing: -blockdev driver=null-co,node-name=null
"return": [
]
}
{
"return": {
}
}
{
"timestamp": {
"seconds": TIMESTAMP,
@@ -158,6 +154,10 @@ Testing: -blockdev driver=null-co,node-name=null
"reason": "host-qmp-quit"
}
}
{
"return": {
}
}
=== blockstats with -blockdev and -device ===
@@ -208,10 +208,6 @@ Testing: -blockdev driver=null-co,read-zeroes=on,node-name=null -device virtio-b
}
]
}
{
"return": {
}
}
{
"timestamp": {
"seconds": TIMESTAMP,
@@ -223,5 +219,9 @@ Testing: -blockdev driver=null-co,read-zeroes=on,node-name=null -device virtio-b
"reason": "host-qmp-quit"
}
}
{
"return": {
}
}
*** done
+1 -1
View File
@@ -17,6 +17,6 @@ QMP_VERSION
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "job0", "len": 134217728, "offset": 134217728, "speed": 0, "type": "commit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job0"}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"return": {}}
*** done
+4 -4
View File
@@ -282,10 +282,6 @@ Testing: -blockdev file,node-name=base,filename=TEST_DIR/t.IMGFMT.base -blockdev
]
}
}
{
"return": {
}
}
{
"timestamp": {
"seconds": TIMESTAMP,
@@ -297,5 +293,9 @@ Testing: -blockdev file,node-name=base,filename=TEST_DIR/t.IMGFMT.base -blockdev
"reason": "host-qmp-quit"
}
}
{
"return": {
}
}
*** done
+2 -2
View File
@@ -77,6 +77,7 @@ fuse_export_add()
# $1: Export ID
fuse_export_del()
{
capture_events="BLOCK_EXPORT_DELETED" \
_send_qemu_cmd $QEMU_HANDLE \
"{'execute': 'block-export-del',
'arguments': {
@@ -84,8 +85,7 @@ fuse_export_del()
} }" \
'return'
_send_qemu_cmd $QEMU_HANDLE \
'' \
_wait_event $QEMU_HANDLE \
'BLOCK_EXPORT_DELETED'
}
+1 -1
View File
@@ -165,9 +165,9 @@ OK: Post-truncate image size is as expected
=== Tear down ===
{'execute': 'quit'}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "export-mp"}}
{"return": {}}
=== Compare copy with original ===
Images are identical.
+7
View File
@@ -642,6 +642,13 @@ def filter_qmp_virtio_scsi(qmsg):
def filter_generated_node_ids(msg):
return re.sub("#block[0-9]+", "NODE_NAME", msg)
def filter_qmp_generated_node_ids(qmsg):
def _filter(_key, value):
if is_str(value):
return filter_generated_node_ids(value)
return value
return filter_qmp(qmsg, _filter)
def filter_img_info(output, filename):
lines = []
for line in output.split('\n'):
+170
View File
@@ -0,0 +1,170 @@
#!/usr/bin/env bash
# group: rw quick
#
# Test case for internal snapshots in qcow2
#
# Copyright (C) 2023 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"
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 qcow2-specific low-level functionality
_supported_fmt qcow2
_supported_proto generic
# Internal snapshots are (currently) impossible with refcount_bits=1,
# and generally impossible with external data files
_unsupported_imgopts 'compat=0.10' 'refcount_bits=1[^0-9]' data_file
IMG_SIZE=64M
_qemu()
{
$QEMU -no-shutdown -nographic -monitor stdio -serial none \
-blockdev file,filename="$TEST_IMG",node-name=disk0-file \
-blockdev "$IMGFMT",file=disk0-file,node-name=disk0 \
-object iothread,id=iothread0 \
-device virtio-scsi,iothread=iothread0 \
-device scsi-hd,drive=disk0,share-rw=on \
"$@" 2>&1 |\
_filter_qemu | _filter_hmp | _filter_qemu_io
}
_make_test_img $IMG_SIZE
echo
echo "=== Write some data, take a snapshot and overwrite part of it ==="
echo
{
echo 'qemu-io disk0 "write -P0x11 0 1M"'
# Give qemu some time to boot before saving the VM state
sleep 0.5
echo "savevm snap0"
echo 'qemu-io disk0 "write -P0x22 0 512k"'
echo "quit"
} | _qemu
echo
$QEMU_IMG snapshot -l "$TEST_IMG" | _filter_date | _filter_vmstate_size
_check_test_img
echo
echo "=== Verify that loading the snapshot reverts to the old content ==="
echo
{
# -loadvm reverted the write from the previous QEMU instance
echo 'qemu-io disk0 "read -P0x11 0 1M"'
# Verify that it works without restarting QEMU, too
echo 'qemu-io disk0 "write -P0x33 512k 512k"'
echo "loadvm snap0"
echo 'qemu-io disk0 "read -P0x11 0 1M"'
# Verify COW by writing a partial cluster
echo 'qemu-io disk0 "write -P0x33 63k 2k"'
echo 'qemu-io disk0 "read -P0x11 0 63k"'
echo 'qemu-io disk0 "read -P0x33 63k 2k"'
echo 'qemu-io disk0 "read -P0x11 65k 63k"'
# Take a second snapshot
echo "savevm snap1"
echo "quit"
} | _qemu -loadvm snap0
echo
$QEMU_IMG snapshot -l "$TEST_IMG" | _filter_date | _filter_vmstate_size
_check_test_img
echo
echo "=== qemu-img snapshot can revert to snapshots ==="
echo
$QEMU_IMG snapshot -a snap0 "$TEST_IMG"
$QEMU_IO -c "read -P0x11 0 1M" "$TEST_IMG" | _filter_qemu_io
$QEMU_IMG snapshot -a snap1 "$TEST_IMG"
$QEMU_IO \
-c "read -P0x11 0 63k" \
-c "read -P0x33 63k 2k" \
-c "read -P0x11 65k 63k" \
"$TEST_IMG" | _filter_qemu_io
echo
echo "=== Deleting snapshots ==="
echo
{
# The active layer stays unaffected by deleting the snapshot
echo "delvm snap1"
echo 'qemu-io disk0 "read -P0x11 0 63k"'
echo 'qemu-io disk0 "read -P0x33 63k 2k"'
echo 'qemu-io disk0 "read -P0x11 65k 63k"'
echo "quit"
} | _qemu
echo
$QEMU_IMG snapshot -l "$TEST_IMG" | _filter_date | _filter_vmstate_size
_check_test_img
echo
echo "=== Error cases ==="
echo
# snap1 should not exist any more
_qemu -loadvm snap1
echo
{
echo "loadvm snap1"
echo "quit"
} | _qemu
# Snapshot operations and inactive images are incompatible
echo
_qemu -loadvm snap0 -incoming defer
{
echo "loadvm snap0"
echo "delvm snap0"
echo "savevm snap1"
echo "quit"
} | _qemu -incoming defer
# -loadvm and -preconfig are incompatible
echo
_qemu -loadvm snap0 -preconfig
# success, all done
echo "*** done"
rm -f $seq.full
status=0
@@ -0,0 +1,107 @@
QA output created by qcow2-internal-snapshots
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
=== Write some data, take a snapshot and overwrite part of it ===
QEMU X.Y.Z monitor - type 'help' for more information
(qemu) qemu-io disk0 "write -P0x11 0 1M"
wrote 1048576/1048576 bytes at offset 0
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
(qemu) savevm snap0
(qemu) qemu-io disk0 "write -P0x22 0 512k"
wrote 524288/524288 bytes at offset 0
512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
(qemu) quit
Snapshot list:
ID TAG VM SIZE DATE VM CLOCK ICOUNT
1 snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000
No errors were found on the image.
=== Verify that loading the snapshot reverts to the old content ===
QEMU X.Y.Z monitor - type 'help' for more information
(qemu) qemu-io disk0 "read -P0x11 0 1M"
read 1048576/1048576 bytes at offset 0
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
(qemu) qemu-io disk0 "write -P0x33 512k 512k"
wrote 524288/524288 bytes at offset 524288
512 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
(qemu) loadvm snap0
(qemu) qemu-io disk0 "read -P0x11 0 1M"
read 1048576/1048576 bytes at offset 0
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
(qemu) qemu-io disk0 "write -P0x33 63k 2k"
wrote 2048/2048 bytes at offset 64512
2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
(qemu) qemu-io disk0 "read -P0x11 0 63k"
read 64512/64512 bytes at offset 0
63 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
(qemu) qemu-io disk0 "read -P0x33 63k 2k"
read 2048/2048 bytes at offset 64512
2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
(qemu) qemu-io disk0 "read -P0x11 65k 63k"
read 64512/64512 bytes at offset 66560
63 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
(qemu) savevm snap1
(qemu) quit
Snapshot list:
ID TAG VM SIZE DATE VM CLOCK ICOUNT
1 snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000
2 snap1 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000
No errors were found on the image.
=== qemu-img snapshot can revert to snapshots ===
read 1048576/1048576 bytes at offset 0
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
read 64512/64512 bytes at offset 0
63 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
read 2048/2048 bytes at offset 64512
2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
read 64512/64512 bytes at offset 66560
63 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
=== Deleting snapshots ===
QEMU X.Y.Z monitor - type 'help' for more information
(qemu) delvm snap1
(qemu) qemu-io disk0 "read -P0x11 0 63k"
read 64512/64512 bytes at offset 0
63 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
(qemu) qemu-io disk0 "read -P0x33 63k 2k"
read 2048/2048 bytes at offset 64512
2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
(qemu) qemu-io disk0 "read -P0x11 65k 63k"
read 64512/64512 bytes at offset 66560
63 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
(qemu) quit
Snapshot list:
ID TAG VM SIZE DATE VM CLOCK ICOUNT
1 snap0 SIZE yyyy-mm-dd hh:mm:ss 00:00:00.000
No errors were found on the image.
=== Error cases ===
QEMU X.Y.Z monitor - type 'help' for more information
(qemu) QEMU_PROG: Snapshot 'snap1' does not exist in one or more devices
QEMU X.Y.Z monitor - type 'help' for more information
(qemu) loadvm snap1
Error: Snapshot 'snap1' does not exist in one or more devices
(qemu) quit
QEMU_PROG: 'incoming' and 'loadvm' options are mutually exclusive
QEMU X.Y.Z monitor - type 'help' for more information
(qemu) loadvm snap0
Error: Device 'disk0' is writable but does not support snapshots
(qemu) delvm snap0
Error: Device 'disk0' is writable but does not support snapshots
(qemu) savevm snap1
Error: Device 'disk0' is writable but does not support snapshots
(qemu) quit
QEMU_PROG: 'preconfig' and 'loadvm' options are mutually exclusive
*** done
+2 -2
View File
@@ -7,8 +7,8 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/
QMP_VERSION
{"return": {}}
{"return": {}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_CANCELLED", "data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}}
{"return": {}}
=== Streaming can't get permission on base node ===
@@ -17,6 +17,6 @@ QMP_VERSION
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job0"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job0"}}
{"error": {"class": "GenericError", "desc": "Permission conflict on node 'fmt_base': permissions 'write' are both required by an unnamed block device (uses node 'fmt_base' as 'root' child) and unshared by stream job 'job0' (uses node 'fmt_base' as 'intermediate node' child)."}}
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "export1"}}
{"return": {}}
*** done
+1
View File
@@ -6,6 +6,7 @@ endif
slow_qtests = {
'ahci-test' : 60,
'aspeed_smc-test': 360,
'bios-tables-test' : 120,
'boot-serial-test' : 60,
'migration-test' : 150,