Compare commits

..

72 Commits

Author SHA1 Message Date
85e0a3f630 fix comment 2022-09-07 21:29:56 +02:00
ab54074925 TESTING: add some code for instrumentation tests 2022-07-10 16:21:02 +02:00
f5b92c8907 new example in main 2022-07-10 16:18:46 +02:00
f438967783 extend libafl_exec_jmp_hook 2022-05-26 23:57:34 +02:00
3493dfa219 start interrupt timer on start 2022-05-04 22:58:30 +02:00
a5a49c3292 add hard-coded libafl_exec_systick_hook 2022-04-26 00:29:18 +02:00
8a379ba198 add libafl_send_irq 2022-04-19 23:44:36 +02:00
6ffc2bbe4f bugfix 2022-04-18 13:46:21 +02:00
0cf10fb0ff add jmp instrumentation 2022-04-11 22:56:11 +02:00
404cb91655 use libafl_gen_jmp 2022-04-08 00:54:21 +02:00
ff823f26ff save edges after interrupts 2022-04-06 21:16:15 +02:00
80af255c2e add native remove breakpoint 2022-02-06 20:50:16 +01:00
e62b0072ea switch to icount_get_raw 2022-02-01 15:00:06 +01:00
6ec50ee9c3 add libafl_get_clock 2022-01-31 19:42:07 +01:00
88a0358a4e ignore binaries 2022-01-28 12:22:43 +01:00
78dac2f524 add starters 2022-01-28 10:34:05 +01:00
9caef2e60f Fix tb->icount > TCG_MAX_INSNS for edges
Aparently tcg_tb_alloc does not return a 0ed field,
which can cause icount to appear to have a value above the
maximum allowed number of instructions per tb.
2022-01-15 23:33:33 +01:00
b781a3ebce EXPERIMENT: don't flush tbs on loadvm
This should speed up fuzzing somewhat, but could also create
use-after-free bugs.
2022-01-09 22:44:41 +01:00
5a1cf4d873 Add softmmu instumentation
Break up the control flow from softmmu/main.c:main to be called as a
library.
For now use gdb style breakpoints and native snapshots.
This keeps compatability with user-mode code.
2022-01-09 22:30:34 +01:00
c1dba1b39d backport libafl to v6.1.1
libafl state: fa2b9c4a25f548f15b3d1b1afcfdb75cc7165f9a
2022-01-09 13:20:46 +01:00
Michael Roth
54e1f5be86 Update version for v6.1.1 release
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-23 09:52:09 -06:00
Cole Robinson
fddd169de5 tests: tcg: Fix PVH test with binutils 2.36+
binutils started adding a .note.gnu.property ELF section which
makes the PVH test fail:

  TEST    hello on x86_64
qemu-system-x86_64: Error loading uncompressed kernel without PVH ELF Note

Discard .note.gnu* while keeping the PVH .note bits intact.

This also strips the build-id note, so drop the related comment.

Signed-off-by: Cole Robinson <crobinso@redhat.com>
Message-Id: <5ab2a54c262c61f64c22dbb49ade3e2db8a740bb.1633708346.git.crobinso@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 8e751e9c38e324737fd3d3aa0562f886313bba3c)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-15 07:13:37 -06:00
Richard Henderson
711bd602cc tcg/arm: Reduce vector alignment requirement for NEON
With arm32, the ABI gives us 8-byte alignment for the stack.
While it's possible to realign the stack to provide 16-byte alignment,
it's far easier to simply not encode 16-byte alignment in the
VLD1 and VST1 instructions that we emit.

Remove the assertion in temp_allocate_frame, limit natural alignment
to the provided stack alignment, and add a comment.

Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1999878
Reported-by: Richard W.M. Jones <rjones@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Message-Id: <20210912174925.200132-1-richard.henderson@linaro.org>
Message-Id: <20211206191335.230683-2-richard.henderson@linaro.org>
(cherry picked from commit b9537d5904f6e3df896264a6144883ab07db9608)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-15 07:13:27 -06:00
Daniel P. Berrangé
e88636b4d4 target/i386: add missing bits to CR4_RESERVED_MASK
Booting Fedora kernels with -cpu max hangs very early in boot. Disabling
the la57 CPUID bit fixes the problem. git bisect traced the regression to

  commit 213ff024a2f92020290296cb9dc29c2af3d4a221 (HEAD, refs/bisect/bad)
  Author: Lara Lazier <laramglazier@gmail.com>
  Date:   Wed Jul 21 17:26:50 2021 +0200

    target/i386: Added consistency checks for CR4

    All MBZ bits in CR4 must be zero. (APM2 15.5)
    Added reserved bitmask and added checks in both
    helper_vmrun and helper_write_crN.

    Signed-off-by: Lara Lazier <laramglazier@gmail.com>
    Message-Id: <20210721152651.14683-2-laramglazier@gmail.com>
    Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

In this commit CR4_RESERVED_MASK is missing CR4_LA57_MASK and
two others. Adding this lets Fedora kernels boot once again.

Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Tested-by: Richard W.M. Jones <rjones@redhat.com>
Message-Id: <20210831175033.175584-1-berrange@redhat.com>
[Removed VMXE/SMXE, matching the commit message. - Paolo]
Fixes: 213ff024a2 ("target/i386: Added consistency checks for CR4", 2021-07-22)
Cc: qemu-stable@nongnu.org
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 69e3895f9d37ca39536775b13ce63e8c291427ba)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-15 07:13:18 -06:00
Gerd Hoffmann
34833f361b qxl: fix pre-save logic
Oops.  Logic is backwards.

Fixes: 39b8a183e2f3 ("qxl: remove assert in qxl_pre_save.")
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/610
Resolves: https://bugzilla.redhat.com//show_bug.cgi?id=2002907
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20210910094203.3582378-1-kraxel@redhat.com>
(cherry picked from commit eb94846280df3f1e2a91b6179fc05f9890b7e384)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-15 07:13:12 -06:00
Jon Maloy
43583f0c07 e1000: fix tx re-entrancy problem
The fact that the MMIO handler is not re-entrant causes an infinite
loop under certain conditions:

Guest write to TDT ->  Loopback -> RX (DMA to TDT) -> TX

We now eliminate the effect of this problem locally in e1000, by adding
a boolean in struct E1000State indicating when the TX side is busy. This
will cause any entering new call to return early instead of interfering
with the ongoing work, and eliminates any risk of looping.

This is intended to address CVE-2021-20257.

Signed-off-by: Jon Maloy <jmaloy@redhat.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
(cherry picked from commit 25ddb946e6301f42cff3094ea1c25fb78813e7e9)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 17:40:06 -06:00
Prasad J Pandit
1ce084af08 net: vmxnet3: validate configuration values during activate (CVE-2021-20203)
While activating device in vmxnet3_acticate_device(), it does not
validate guest supplied configuration values against predefined
minimum - maximum limits. This may lead to integer overflow or
OOB access issues. Add checks to avoid it.

Fixes: CVE-2021-20203
Buglink: https://bugs.launchpad.net/qemu/+bug/1913873
Reported-by: Gaoning Pan <pgn@zju.edu.cn>
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
Signed-off-by: Jason Wang <jasowang@redhat.com>
(cherry picked from commit d05dcd94aee88728facafb993c7280547eb4d645)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 17:39:20 -06:00
Mark Mielke
fec12fc888 virtio-blk: Fix clean up of host notifiers for single MR transaction.
The code that introduced "virtio-blk: Configure all host notifiers in
a single MR transaction" introduced a second loop variable to perform
cleanup in second loop, but mistakenly still refers to the first
loop variable within the second loop body.

Fixes: d0267da61489 ("virtio-blk: Configure all host notifiers in a single MR transaction")
Signed-off-by: Mark Mielke <mark.mielke@gmail.com>
Message-id: CALm7yL08qarOu0dnQkTN+pa=BSRC92g31YpQQNDeAiT4yLZWQQ@mail.gmail.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
(cherry picked from commit 5b807181c27a940a3a7ad1f221a2e76a132cbdc0)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 15:10:56 -06:00
Philippe Mathieu-Daudé
ef0cf1887e tests/qtest/fdc-test: Add a regression test for CVE-2021-20196
Without the previous commit, when running 'make check-qtest-i386'
with QEMU configured with '--enable-sanitizers' we get:

  AddressSanitizer:DEADLYSIGNAL
  =================================================================
  ==287878==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000344
  ==287878==The signal is caused by a WRITE memory access.
  ==287878==Hint: address points to the zero page.
      #0 0x564b2e5bac27 in blk_inc_in_flight block/block-backend.c:1346:5
      #1 0x564b2e5bb228 in blk_pwritev_part block/block-backend.c:1317:5
      #2 0x564b2e5bcd57 in blk_pwrite block/block-backend.c:1498:11
      #3 0x564b2ca1cdd3 in fdctrl_write_data hw/block/fdc.c:2221:17
      #4 0x564b2ca1b2f7 in fdctrl_write hw/block/fdc.c:829:9
      #5 0x564b2dc49503 in portio_write softmmu/ioport.c:201:9

Add the reproducer for CVE-2021-20196.

Suggested-by: Alexander Bulekov <alxndr@bu.edu>
Reviewed-by: Darren Kenny <darren.kenny@oracle.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Message-id: 20211124161536.631563-4-philmd@redhat.com
Signed-off-by: John Snow <jsnow@redhat.com>
(cherry picked from commit cc20926e9b8077bff6813efc8dcdeae90d1a3b10)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 15:05:11 -06:00
Philippe Mathieu-Daudé
71ba2adfeb hw/block/fdc: Kludge missing floppy drive to fix CVE-2021-20196
Guest might select another drive on the bus by setting the
DRIVE_SEL bit of the DIGITAL OUTPUT REGISTER (DOR).
The current controller model doesn't expect a BlockBackend
to be NULL. A simple way to fix CVE-2021-20196 is to create
an empty BlockBackend when it is missing. All further
accesses will be safely handled, and the controller state
machines keep behaving correctly.

Cc: qemu-stable@nongnu.org
Fixes: CVE-2021-20196
Reported-by: Gaoning Pan (Ant Security Light-Year Lab) <pgn@zju.edu.cn>
Reviewed-by: Darren Kenny <darren.kenny@oracle.com>
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Message-id: 20211124161536.631563-3-philmd@redhat.com
BugLink: https://bugs.launchpad.net/qemu/+bug/1912780
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/338
Reviewed-by: Darren Kenny <darren.kenny@oracle.com>
Reviewed-by: Hanna Reitz <hreitz@redhat.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Signed-off-by: John Snow <jsnow@redhat.com>
(cherry picked from commit 1ab95af033a419e7a64e2d58e67dd96b20af5233)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 15:05:05 -06:00
Philippe Mathieu-Daudé
7629818574 hw/block/fdc: Extract blk_create_empty_drive()
We are going to re-use this code in the next commit,
so extract it as a new blk_create_empty_drive() function.

Inspired-by: Hanna Reitz <hreitz@redhat.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Message-id: 20211124161536.631563-2-philmd@redhat.com
Signed-off-by: John Snow <jsnow@redhat.com>
(cherry picked from commit b154791e7b6d4ca5cdcd54443484d97360bd7ad2)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 15:04:59 -06:00
Daniil Tatianin
4658dfcbc0 chardev/wctable: don't free the instance in wctablet_chr_finalize
Object is supposed to be freed by invoking obj->free, and not
obj->instance_finalize. This would lead to use-after-free followed by
double free in object_unref/object_finalize.

Signed-off-by: Daniil Tatianin <d-tatianin@yandex-team.ru>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-Id: <20211117142349.836279-1-d-tatianin@yandex-team.ru>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit fdc6e168181d06391711171b7c409b34f2981ced)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 14:54:14 -06:00
Klaus Jensen
2b2eb343a0 hw/nvme: fix buffer overrun in nvme_changed_nslist (CVE-2021-3947)
Fix missing offset verification.

Cc: qemu-stable@nongnu.org
Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
Reported-by: Qiuhao Li <Qiuhao.Li@outlook.com>
Fixes: f432fdfa121 ("support changed namespace asynchronous event")
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
(cherry picked from commit e2c57529c9306e4c9aac75d9879f6e7699584a22)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 14:52:50 -06:00
Eric Blake
932333c5f0 nbd/server: Don't complain on certain client disconnects
When a client disconnects abruptly, but did not have any pending
requests (for example, when using nbdsh without calling h.shutdown),
we used to output the following message:

$ qemu-nbd -f raw file
$ nbdsh -u 'nbd://localhost:10809' -c 'h.trim(1,0)'
qemu-nbd: Disconnect client, due to: Failed to read request: Unexpected end-of-file before all bytes were read

Then in commit f148ae7, we refactored nbd_receive_request() to use
nbd_read_eof(); when this returns 0, we regressed into tracing
uninitialized memory (if tracing is enabled) and reporting a
less-specific:

qemu-nbd: Disconnect client, due to: Request handling failed in intermediate state

Note that with Unix sockets, we have yet another error message,
unchanged by the 6.0 regression:

$ qemu-nbd -k /tmp/sock -f raw file
$ nbdsh -u 'nbd+unix:///?socket=/tmp/sock' -c 'h.trim(1,0)'
qemu-nbd: Disconnect client, due to: Failed to send reply: Unable to write to socket: Broken pipe

But in all cases, the error message goes away if the client performs a
soft shutdown by using NBD_CMD_DISC, rather than a hard shutdown by
abrupt disconnect:

$ nbdsh -u 'nbd://localhost:10809' -c 'h.trim(1,0)' -c 'h.shutdown()'

This patch fixes things to avoid uninitialized memory, and in general
avoids warning about a client that does a hard shutdown when not in
the middle of a packet.  A client that aborts mid-request, or which
does not read the full server's reply, can still result in warnings,
but those are indeed much more unusual situations.

CC: qemu-stable@nongnu.org
Fixes: f148ae7d36 ("nbd/server: Quiesce coroutines on context switch", v6.0.0)
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
[eblake: defer unrelated typo fixes to later patch]
Message-Id: <20211117170230.1128262-2-eblake@redhat.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
(cherry picked from commit 1644cccea5c71b02b9cf8f78b780e7069a29b189)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 14:51:17 -06:00
Peng Liang
8c2d5911de vfio: Fix memory leak of hostwin
hostwin is allocated and added to hostwin_list in vfio_host_win_add, but
it is only deleted from hostwin_list in vfio_host_win_del, which causes
a memory leak.  Also, freeing all elements in hostwin_list is missing in
vfio_disconnect_container.

Fix: 2e4109de8e58 ("vfio/spapr: Create DMA window dynamically (SPAPR IOMMU v2)")
CC: qemu-stable@nongnu.org
Signed-off-by: Peng Liang <liangpeng10@huawei.com>
Link: https://lore.kernel.org/r/20211117014739.1839263-1-liangpeng10@huawei.com
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
(cherry picked from commit f3bc3a73c908df15966e66f88d5a633bd42fd029)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 14:49:55 -06:00
Jason Wang
08e46e6d92 virtio: use virtio accessor to access packed event
We used to access packed descriptor event and off_wrap via
address_space_{write|read}_cached(). When we hit the cache, memcpy()
is used which is not atomic which may lead a wrong value to be read or
wrote.

This patch fixes this by switching to use
virito_{stw|lduw}_phys_cached() to make sure the access is atomic.

Fixes: 683f7665679c1 ("virtio: event suppression support for packed ring")
Cc: qemu-stable@nongnu.org
Signed-off-by: Jason Wang <jasowang@redhat.com>
Message-Id: <20211111063854.29060-2-jasowang@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
(cherry picked from commit d152cdd6f6fad381e804c8185f0ba938030ccac9)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 14:43:25 -06:00
Jason Wang
df1c9c3039 virtio: use virtio accessor to access packed descriptor flags
We used to access packed descriptor flags via
address_space_{write|read}_cached(). When we hit the cache, memcpy()
is used which is not an atomic operation which may lead a wrong value
is read or wrote.

So this patch switches to use virito_{stw|lduw}_phys_cached() to make
sure the aceess is atomic.

Fixes: 86044b24e865f ("virtio: basic packed virtqueue support")
Cc: qemu-stable@nongnu.org
Signed-off-by: Jason Wang <jasowang@redhat.com>
Message-Id: <20211111063854.29060-1-jasowang@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
(cherry picked from commit f463e761a41ee71e59892121e1c74d9c25c985d2)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 14:43:18 -06:00
Igor Mammedov
7204b8f3c6 pcie: rename 'native-hotplug' to 'x-native-hotplug'
Mark property as experimental/internal adding 'x-' prefix.

Property was introduced in 6.1 and it should have provided
ability to turn on native PCIE hotplug on port even when
ACPI PCI hotplug is in use is user explicitly sets property
on CLI. However that never worked since slot is wired to
ACPI hotplug controller.
Another non-intended usecase: disable native hotplug on slot
when APCI based hotplug is disabled, which works but slot has
'hotplug' property for this taks.

It should be relatively safe to rename it to experimental
as no users should exist for it and given that the property
is broken we don't really want to leave it around for much
longer lest users start using it.

Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Ani Sinha <ani@anisinha.ca>
Message-Id: <20211112110857.3116853-2-imammedo@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
(cherry picked from commit 2aa1842d6d79dcd1b84c58eeb44591a99a9e56df)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 14:38:08 -06:00
Greg Kurz
36c651c226 accel/tcg: Register a force_rcu notifier
A TCG vCPU doing a busy loop systematicaly hangs the QEMU monitor
if the user passes 'device_add' without argument. This is because
drain_cpu_all() which is called from qmp_device_add() cannot return
if readers don't exit read-side critical sections. That is typically
what busy-looping TCG vCPUs do:

int cpu_exec(CPUState *cpu)
{
[...]
    rcu_read_lock();
[...]
    while (!cpu_handle_exception(cpu, &ret)) {
        // Busy loop keeps vCPU here
    }
[...]
    rcu_read_unlock();

    return ret;
}

For MTTCG, have all vCPU threads register a force_rcu notifier that will
kick them out of the loop using async_run_on_cpu(). The notifier is called
with the rcu_registry_lock mutex held, using async_run_on_cpu() ensures
there are no deadlocks.

For RR, a single thread runs all vCPUs. Just register a single notifier
that kicks the current vCPU to the next one.

For MTTCG:
Suggested-by: Paolo Bonzini <pbonzini@redhat.com>

For RR:
Suggested-by: Richard Henderson <richard.henderson@linaro.org>

Fixes: 7bed89958bfb ("device_core: use drain_call_rcu in in qmp_device_add")
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/650
Signed-off-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-Id: <20211109183523.47726-3-groug@kaod.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit dd47a8f654d84f666b235ce8891e17ee76f9be8b)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 14:26:01 -06:00
Greg Kurz
fceaefb43f rcu: Introduce force_rcu notifier
The drain_rcu_call() function can be blocked as long as an RCU reader
stays in a read-side critical section. This is typically what happens
when a TCG vCPU is executing a busy loop. It can deadlock the QEMU
monitor as reported in https://gitlab.com/qemu-project/qemu/-/issues/650 .

This can be avoided by allowing drain_rcu_call() to enforce an RCU grace
period. Since each reader might need to do specific actions to end a
read-side critical section, do it with notifiers.

Prepare ground for this by adding a notifier list to the RCU reader
struct and use it in wait_for_readers() if drain_rcu_call() is in
progress. An API is added for readers to register their notifiers.

This is largely based on a draft from Paolo Bonzini.

Suggested-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-Id: <20211109183523.47726-2-groug@kaod.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit ef149763a8fcce70b85dfda27cc1222ecf765750)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 14:25:55 -06:00
Laurent Vivier
7d71e6bfb0 hw: m68k: virt: Add compat machine for 6.1
Add the missing machine type for m68k/virt

Cc: qemu-stable@nongnu.org
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
Message-Id: <20211106194158.4068596-2-laurent@vivier.eu>
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
(cherry picked from commit 6837f299762679429924242a63f16490862578e3)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 14:23:21 -06:00
Mauro Matteo Cascella
c2c7f108b8 hw/scsi/scsi-disk: MODE_PAGE_ALLS not allowed in MODE SELECT commands
This avoids an off-by-one read of 'mode_sense_valid' buffer in
hw/scsi/scsi-disk.c:mode_sense_page().

Fixes: CVE-2021-3930
Cc: qemu-stable@nongnu.org
Reported-by: Alexander Bulekov <alxndr@bu.edu>
Fixes: a8f4bbe2900 ("scsi-disk: store valid mode pages in a table")
Fixes: #546
Reported-by: Qiuhao Li <Qiuhao.Li@outlook.com>
Signed-off-by: Mauro Matteo Cascella <mcascell@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit b3af7fdf9cc537f8f0dd3e2423d83f5c99a457e8)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 14:22:44 -06:00
Paolo Bonzini
3488bb205d target-i386: mmu: fix handling of noncanonical virtual addresses
mmu_translate is supposed to return an error code for page faults; it is
not able to handle other exceptions.  The #GP case for noncanonical
virtual addresses is not handled correctly, and incorrectly raised as
a page fault with error code 1.  Since it cannot happen for nested
page tables, move it directly to handle_mmu_fault, even before the
invocation of mmu_translate.

Fixes: #676
Fixes: 661ff4879e ("target/i386: extract mmu_translate", 2021-05-11)
Cc: qemu-stable@nongnu.org
Tested-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit b04dc92e013d55c9ac8082caefff45dcfb1310e7)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 14:19:00 -06:00
Paolo Bonzini
cddfaf96ab target-i386: mmu: use pg_mode instead of HF_LMA_MASK
Correctly look up the paging mode of the hypervisor when it is using 64-bit
mode but the guest is not.

Fixes: 68746930ae ("target/i386: use mmu_translate for NPT walk", 2021-05-11)
Cc: qemu-stable@nongnu.org
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 93eae3583256896dd91a4c2ca38dcbb8d4051cff)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 14:18:25 -06:00
Jessica Clarke
43a457841f Partially revert "build: -no-pie is no functional linker flag"
This partially reverts commit bbd2d5a8120771ec59b86a80a1f51884e0a26e53.

This commit was misguided and broke using --disable-pie on any distro
that enables PIE by default in their compiler driver, including Debian
and its derivatives. Whilst -no-pie is not a linker flag, it is a
compiler driver flag that ensures -pie is not automatically passed by it
to the linker. Without it, all compile_prog checks will fail as any code
built with the explicit -fno-pie will fail to link with the implicit
default -pie due to trying to use position-dependent relocations. The
only bug that needed fixing was LDFLAGS_NOPIE being used as a flag for
the linker itself in pc-bios/optionrom/Makefile.

Note this does not reinstate exporting LDFLAGS_NOPIE, as it is unused,
since the only previous use was the one that should not have existed. I
have also updated the comment for the -fno-pie and -no-pie checks to
reflect what they're actually needed for.

Fixes: bbd2d5a8120771ec59b86a80a1f51884e0a26e53
Cc: Christian Ehrhardt <christian.ehrhardt@canonical.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: qemu-stable@nongnu.org
Signed-off-by: Jessica Clarke <jrtc27@jrtc27.com>
Message-Id: <20210805192545.38279-1-jrtc27@jrtc27.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit ffd205ef2901bd65fcfbd09a98c0ff7cfcec5e4d)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 14:13:38 -06:00
Ari Sundholm
ebf660beb1 block/file-posix: Fix return value translation for AIO discards
AIO discards regressed as a result of the following commit:
	0dfc7af2 block/file-posix: Optimize for macOS

When trying to run blkdiscard within a Linux guest, the request would
fail, with some errors in dmesg:

---- [ snip ] ----
[    4.010070] sd 2:0:0:0: [sda] tag#0 FAILED Result: hostbyte=DID_OK
driverbyte=DRIVER_SENSE
[    4.011061] sd 2:0:0:0: [sda] tag#0 Sense Key : Aborted Command
[current]
[    4.011061] sd 2:0:0:0: [sda] tag#0 Add. Sense: I/O process
terminated
[    4.011061] sd 2:0:0:0: [sda] tag#0 CDB: Unmap/Read sub-channel 42
00 00 00 00 00 00 00 18 00
[    4.011061] blk_update_request: I/O error, dev sda, sector 0
---- [ snip ] ----

This turns out to be a result of a flaw in changes to the error value
translation logic in handle_aiocb_discard(). The default return value
may be left untranslated in some configurations, and the wrong variable
is used in one translation.

Fix both issues.

Fixes: 0dfc7af2b28 ("block/file-posix: Optimize for macOS")
Cc: qemu-stable@nongnu.org
Signed-off-by: Ari Sundholm <ari@tuxera.com>
Signed-off-by: Emil Karlson <jkarlson@tuxera.com>
Reviewed-by: Akihiko Odaki <akihiko.odaki@gmail.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Message-Id: <20211019110954.4170931-1-ari@tuxera.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit 13a028336f2c05e7ff47dfdaf30dfac7f4883e80)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 14:12:50 -06:00
Ani Sinha
bbbdedb386 tests/acpi/bios-tables-test: update DSDT blob for multifunction bridge test
We added a new unit test for testing acpi hotplug on multifunction bridges in
q35 machines. Here, we update the DSDT table gloden master blob for this unit
test.

The test adds the following devices to qemu and then checks the changes
introduced in the DSDT table due to the addition of the following devices:

(a) a multifunction bridge device
(b) a bridge device with function 1
(c) a non-bridge device with function 2

In the DSDT table, we should see AML hotplug descriptions for (a) and (b).
For (a) we should find a hotplug AML description for function 0.

Following is the ASL diff between the original DSDT table and the modified DSDT
table due to the unit test. We see that multifunction bridge on bus 2 and single
function bridge on bus 3 function 1 are described, not the non-bridge balloon
device on bus 4, function 2.

@@ -1,30 +1,30 @@
 /*
  * Intel ACPI Component Architecture
  * AML/ASL+ Disassembler version 20190509 (64-bit version)
  * Copyright (c) 2000 - 2019 Intel Corporation
  *
  * Disassembling to symbolic ASL+ operators
  *
- * Disassembly of tests/data/acpi/q35/DSDT, Thu Oct  7 18:29:19 2021
+ * Disassembly of /tmp/aml-C7JCA1, Thu Oct  7 18:29:19 2021
  *
  * Original Table Header:
  *     Signature        "DSDT"
- *     Length           0x00002061 (8289)
+ *     Length           0x00002187 (8583)
  *     Revision         0x01 **** 32-bit table (V1), no 64-bit math support
- *     Checksum         0xF9
+ *     Checksum         0x8D
  *     OEM ID           "BOCHS "
  *     OEM Table ID     "BXPC    "
  *     OEM Revision     0x00000001 (1)
  *     Compiler ID      "BXPC"
  *     Compiler Version 0x00000001 (1)
  */
 DefinitionBlock ("", "DSDT", 1, "BOCHS ", "BXPC    ", 0x00000001)
 {
     Scope (\)
     {
         OperationRegion (DBG, SystemIO, 0x0402, One)
         Field (DBG, ByteAcc, NoLock, Preserve)
         {
             DBGB,   8
         }

@@ -3265,23 +3265,95 @@
                 Method (_S1D, 0, NotSerialized)  // _S1D: S1 Device State
                 {
                     Return (Zero)
                 }

                 Method (_S2D, 0, NotSerialized)  // _S2D: S2 Device State
                 {
                     Return (Zero)
                 }

                 Method (_S3D, 0, NotSerialized)  // _S3D: S3 Device State
                 {
                     Return (Zero)
                 }
             }

+            Device (S10)
+            {
+                Name (_ADR, 0x00020000)  // _ADR: Address
+                Name (BSEL, One)
+                Device (S00)
+                {
+                    Name (_SUN, Zero)  // _SUN: Slot User Number
+                    Name (_ADR, Zero)  // _ADR: Address
+                    Method (_EJ0, 1, NotSerialized)  // _EJx: Eject Device, x=0-9
+                    {
+                        PCEJ (BSEL, _SUN)
+                    }
+
+                    Method (_DSM, 4, Serialized)  // _DSM: Device-Specific Method
+                    {
+                        Return (PDSM (Arg0, Arg1, Arg2, Arg3, BSEL, _SUN))
+                    }
+                }
+
+                Method (DVNT, 2, NotSerialized)
+                {
+                    If ((Arg0 & One))
+                    {
+                        Notify (S00, Arg1)
+                    }
+                }
+
+                Method (PCNT, 0, NotSerialized)
+                {
+                    BNUM = One
+                    DVNT (PCIU, One)
+                    DVNT (PCID, 0x03)
+                }
+            }
+
+            Device (S19)
+            {
+                Name (_ADR, 0x00030001)  // _ADR: Address
+                Name (BSEL, Zero)
+                Device (S00)
+                {
+                    Name (_SUN, Zero)  // _SUN: Slot User Number
+                    Name (_ADR, Zero)  // _ADR: Address
+                    Method (_EJ0, 1, NotSerialized)  // _EJx: Eject Device, x=0-9
+                    {
+                        PCEJ (BSEL, _SUN)
+                    }
+
+                    Method (_DSM, 4, Serialized)  // _DSM: Device-Specific Method
+                    {
+                        Return (PDSM (Arg0, Arg1, Arg2, Arg3, BSEL, _SUN))
+                    }
+                }
+
+                Method (DVNT, 2, NotSerialized)
+                {
+                    If ((Arg0 & One))
+                    {
+                        Notify (S00, Arg1)
+                    }
+                }
+
+                Method (PCNT, 0, NotSerialized)
+                {
+                    BNUM = Zero
+                    DVNT (PCIU, One)
+                    DVNT (PCID, 0x03)
+                }
+            }
+
             Method (PCNT, 0, NotSerialized)
             {
+                ^S19.PCNT ()
+                ^S10.PCNT ()
             }
         }
     }
 }

Signed-off-by: Ani Sinha <ani@anisinha.ca>
Message-Id: <20211007135750.1277213-4-ani@anisinha.ca>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Acked-by: Igor Mammedov <imammedo@redhat.com>
(cherry picked from commit a8339e07f94a47f99560baef59d65a9e039aaf45)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 14:05:24 -06:00
Ani Sinha
8319de607f tests/acpi/pcihp: add unit tests for hotplug on multifunction bridges for q35
commit d7346e614f4ec ("acpi: x86: pcihp: add support hotplug on multifunction bridges")
added ACPI hotplug descriptions for cold plugged bridges for functions other
than 0. For all other devices, the ACPI hotplug descriptions are limited to
function 0 only. This change adds unit tests for this feature.

This test adds the following devices to qemu and then checks the changes
introduced in the DSDT table due to the addition of the following devices:

(a) a multifunction bridge device
(b) a bridge device with function 1
(c) a non-bridge device with function 2

In the DSDT table, we should see AML hotplug descriptions for (a) and (b).
For (a) we should find a hotplug AML description for function 0.

The following diff compares the DSDT table AML with the new unit test before
and after the change d7346e614f4ec is introduced. In other words,
this diff reflects the changes that occurs in the DSDT table due to the change
d7346e614f4ec .

@@ -1,60 +1,38 @@
 /*
  * Intel ACPI Component Architecture
  * AML/ASL+ Disassembler version 20190509 (64-bit version)
  * Copyright (c) 2000 - 2019 Intel Corporation
  *
  * Disassembling to symbolic ASL+ operators
  *
- * Disassembly of tests/data/acpi/q35/DSDT.multi-bridge, Thu Oct  7 18:56:05 2021
+ * Disassembly of /tmp/aml-AN0DA1, Thu Oct  7 18:56:05 2021
  *
  * Original Table Header:
  *     Signature        "DSDT"
- *     Length           0x000020FE (8446)
+ *     Length           0x00002187 (8583)
  *     Revision         0x01 **** 32-bit table (V1), no 64-bit math support
- *     Checksum         0xDE
+ *     Checksum         0x8D
  *     OEM ID           "BOCHS "
  *     OEM Table ID     "BXPC    "
  *     OEM Revision     0x00000001 (1)
  *     Compiler ID      "BXPC"
  *     Compiler Version 0x00000001 (1)
  */
 DefinitionBlock ("", "DSDT", 1, "BOCHS ", "BXPC    ", 0x00000001)
 {
-    /*
-     * iASL Warning: There was 1 external control method found during
-     * disassembly, but only 0 were resolved (1 unresolved). Additional
-     * ACPI tables may be required to properly disassemble the code. This
-     * resulting disassembler output file may not compile because the
-     * disassembler did not know how many arguments to assign to the
-     * unresolved methods. Note: SSDTs can be dynamically loaded at
-     * runtime and may or may not be available via the host OS.
-     *
-     * In addition, the -fe option can be used to specify a file containing
-     * control method external declarations with the associated method
-     * argument counts. Each line of the file must be of the form:
-     *     External (<method pathname>, MethodObj, <argument count>)
-     * Invocation:
-     *     iasl -fe refs.txt -d dsdt.aml
-     *
-     * The following methods were unresolved and many not compile properly
-     * because the disassembler had to guess at the number of arguments
-     * required for each:
-     */
-    External (_SB_.PCI0.S19_.PCNT, MethodObj)    // Warning: Unknown method, guessing 1 arguments
-
     Scope (\)
     {
         OperationRegion (DBG, SystemIO, 0x0402, One)
         Field (DBG, ByteAcc, NoLock, Preserve)
         {
             DBGB,   8
         }

         Method (DBUG, 1, NotSerialized)
         {
             ToHexString (Arg0, Local0)
             ToBuffer (Local0, Local0)
             Local1 = (SizeOf (Local0) - One)
             Local2 = Zero
             While ((Local2 < Local1))
             {
@@ -3322,24 +3300,60 @@
                 Method (DVNT, 2, NotSerialized)
                 {
                     If ((Arg0 & One))
                     {
                         Notify (S00, Arg1)
                     }
                 }

                 Method (PCNT, 0, NotSerialized)
                 {
                     BNUM = One
                     DVNT (PCIU, One)
                     DVNT (PCID, 0x03)
                 }
             }

+            Device (S19)
+            {
+                Name (_ADR, 0x00030001)  // _ADR: Address
+                Name (BSEL, Zero)
+                Device (S00)
+                {
+                    Name (_SUN, Zero)  // _SUN: Slot User Number
+                    Name (_ADR, Zero)  // _ADR: Address
+                    Method (_EJ0, 1, NotSerialized)  // _EJx: Eject Device, x=0-9
+                    {
+                        PCEJ (BSEL, _SUN)
+                    }
+
+                    Method (_DSM, 4, Serialized)  // _DSM: Device-Specific Method
+                    {
+                        Return (PDSM (Arg0, Arg1, Arg2, Arg3, BSEL, _SUN))
+                    }
+                }
+
+                Method (DVNT, 2, NotSerialized)
+                {
+                    If ((Arg0 & One))
+                    {
+                        Notify (S00, Arg1)
+                    }
+                }
+
+                Method (PCNT, 0, NotSerialized)
+                {
+                    BNUM = Zero
+                    DVNT (PCIU, One)
+                    DVNT (PCID, 0x03)
+                }
+            }
+
             Method (PCNT, 0, NotSerialized)
             {
-                ^S19.PCNT (^S10.PCNT ())
+                ^S19.PCNT ()
+                ^S10.PCNT ()
             }
         }
     }
 }

Signed-off-by: Ani Sinha <ani@anisinha.ca>
Message-Id: <20211007135750.1277213-3-ani@anisinha.ca>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
(cherry picked from commit 04dd78b9e85720226a148eef54b45cb02b463034)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 14:05:20 -06:00
Ani Sinha
a759dc19ec tests/acpi/bios-tables-test: add and allow changes to a new q35 DSDT table blob
We are adding a new unit test to cover the acpi hotplug support in q35 for
multi-function bridges. This test uses a new table DSDT.multi-bridge.
We need to allow changes in DSDT acpi table for addition of this new
unit test.

Signed-off-by: Ani Sinha <ani@anisinha.ca>
Message-Id: <20211007135750.1277213-2-ani@anisinha.ca>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Acked-by: Igor Mammedov <imammedo@redhat.com>
(cherry picked from commit 6dcb1cc9512c6b4cd8f85abc537abaf6f6c0738b)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 14:05:15 -06:00
Michael S. Tsirkin
24101e36f1 pci: fix PCI resource reserve capability on BE
PCI resource reserve capability should use LE format as all other PCI
things. If we don't then seabios won't boot:

=== PCI new allocation pass #1 ===
PCI: check devices
PCI: QEMU resource reserve cap: size 10000000000000 type io
PCI: secondary bus 1 size 10000000000000 type io
PCI: secondary bus 1 size 00200000 type mem
PCI: secondary bus 1 size 00200000 type prefmem
=== PCI new allocation pass #2 ===
PCI: out of I/O address space

This became more important since we started reserving IO by default,
previously no one noticed.

Fixes: e2a6290aab ("hw/pcie-root-port: Fix hotplug for PCI devices requiring IO")
Cc: marcel.apfelbaum@gmail.com
Fixes: 226263fb5c ("hw/pci: add QEMU-specific PCI capability to the Generic PCI Express Root Port")
Cc: zuban32s@gmail.com
Fixes: 6755e618d0 ("hw/pci: add PCI resource reserve capability to legacy PCI bridge")
Cc: jing2.liu@linux.intel.com
Tested-by: Thomas Huth <thuth@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
(cherry picked from commit 0e464f7d993113119f0fd17b890831440734ce15)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 14:01:41 -06:00
Paolo Bonzini
a43e057bd6 block: introduce max_hw_iov for use in scsi-generic
Linux limits the size of iovecs to 1024 (UIO_MAXIOV in the kernel
sources, IOV_MAX in POSIX).  Because of this, on some host adapters
requests with many iovecs are rejected with -EINVAL by the
io_submit() or readv()/writev() system calls.

In fact, the same limit applies to SG_IO as well.  To fix both the
EINVAL and the possible performance issues from using fewer iovecs
than allowed by Linux (some HBAs have max_segments as low as 128),
introduce a separate entry in BlockLimits to hold the max_segments
value from sysfs.  This new limit is used only for SG_IO and clamped
to bs->bl.max_iov anyway, just like max_hw_transfer is clamped to
bs->bl.max_transfer.

Reported-by: Halil Pasic <pasic@linux.ibm.com>
Cc: Hanna Reitz <hreitz@redhat.com>
Cc: Kevin Wolf <kwolf@redhat.com>
Cc: qemu-block@nongnu.org
Cc: qemu-stable@nongnu.org
Fixes: 18473467d5 ("file-posix: try BLKSECTGET on block devices too, do not round to power of 2", 2021-06-25)
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20210923130436.1187591-1-pbonzini@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit cc071629539dc1f303175a7e2d4ab854c0a8b20f)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 13:53:15 -06:00
Ani Sinha
3aa2c2cd67 bios-tables-test: Update ACPI DSDT table golden blobs for q35
We have modified the IO address range for ACPI pci hotplug in q35. See change:

5adcc9e39e6a5 ("hw/i386/acpi: fix conflicting IO address range for acpi pci hotplug in q35")

The ACPI DSDT table golden blobs must be regenrated in order to make the unit tests
pass. This change updates the golden ACPI DSDT table blobs.

Following is the ASL diff between the blobs:

@@ -1,30 +1,30 @@
 /*
  * Intel ACPI Component Architecture
  * AML/ASL+ Disassembler version 20190509 (64-bit version)
  * Copyright (c) 2000 - 2019 Intel Corporation
  *
  * Disassembling to symbolic ASL+ operators
  *
- * Disassembly of tests/data/acpi/q35/DSDT, Tue Sep 14 09:04:06 2021
+ * Disassembly of /tmp/aml-52DP90, Tue Sep 14 09:04:06 2021
  *
  * Original Table Header:
  *     Signature        "DSDT"
  *     Length           0x00002061 (8289)
  *     Revision         0x01 **** 32-bit table (V1), no 64-bit math support
- *     Checksum         0xE5
+ *     Checksum         0xF9
  *     OEM ID           "BOCHS "
  *     OEM Table ID     "BXPC    "
  *     OEM Revision     0x00000001 (1)
  *     Compiler ID      "BXPC"
  *     Compiler Version 0x00000001 (1)
  */
 DefinitionBlock ("", "DSDT", 1, "BOCHS ", "BXPC    ", 0x00000001)
 {
     Scope (\)
     {
         OperationRegion (DBG, SystemIO, 0x0402, One)
         Field (DBG, ByteAcc, NoLock, Preserve)
         {
             DBGB,   8
         }

@@ -226,46 +226,46 @@
             Name (_CRS, ResourceTemplate ()  // _CRS: Current Resource Settings
             {
                 IO (Decode16,
                     0x0070,             // Range Minimum
                     0x0070,             // Range Maximum
                     0x01,               // Alignment
                     0x08,               // Length
                     )
                 IRQNoFlags ()
                     {8}
             })
         }
     }

     Scope (_SB.PCI0)
     {
-        OperationRegion (PCST, SystemIO, 0x0CC4, 0x08)
+        OperationRegion (PCST, SystemIO, 0x0CC0, 0x08)
         Field (PCST, DWordAcc, NoLock, WriteAsZeros)
         {
             PCIU,   32,
             PCID,   32
         }

-        OperationRegion (SEJ, SystemIO, 0x0CCC, 0x04)
+        OperationRegion (SEJ, SystemIO, 0x0CC8, 0x04)
         Field (SEJ, DWordAcc, NoLock, WriteAsZeros)
         {
             B0EJ,   32
         }

-        OperationRegion (BNMR, SystemIO, 0x0CD4, 0x08)
+        OperationRegion (BNMR, SystemIO, 0x0CD0, 0x08)
         Field (BNMR, DWordAcc, NoLock, WriteAsZeros)
         {
             BNUM,   32,
             PIDX,   32
         }

         Mutex (BLCK, 0x00)
         Method (PCEJ, 2, NotSerialized)
         {
             Acquire (BLCK, 0xFFFF)
             BNUM = Arg0
             B0EJ = (One << Arg1)
             Release (BLCK)
             Return (Zero)
         }

@@ -3185,34 +3185,34 @@
                     0x0620,             // Range Minimum
                     0x0620,             // Range Maximum
                     0x01,               // Alignment
                     0x10,               // Length
                     )
             })
         }

         Device (PHPR)
         {
             Name (_HID, "PNP0A06" /* Generic Container Device */)  // _HID: Hardware ID
             Name (_UID, "PCI Hotplug resources")  // _UID: Unique ID
             Name (_STA, 0x0B)  // _STA: Status
             Name (_CRS, ResourceTemplate ()  // _CRS: Current Resource Settings
             {
                 IO (Decode16,
-                    0x0CC4,             // Range Minimum
-                    0x0CC4,             // Range Maximum
+                    0x0CC0,             // Range Minimum
+                    0x0CC0,             // Range Maximum
                     0x01,               // Alignment
                     0x18,               // Length
                     )
             })
         }
     }

     Scope (\)
     {
         Name (_S3, Package (0x04)  // _S3_: S3 System State
         {
             One,
             One,
             Zero,
             Zero
         })

Signed-off-by: Ani Sinha <ani@anisinha.ca>
Acked-by: Igor Mammedov <imammedo@redhat.com>
Message-Id: <20210916132838.3469580-4-ani@anisinha.ca>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
(cherry picked from commit 500eb21cff08dfb0478db9b34f2fdba69eb31496)
*drop dependency on 75539b886a ("tests: acpi: tpm1.2: Add expected TPM 1.2 ACPI blobs")
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 13:27:44 -06:00
Ani Sinha
9e80a430ed hw/i386/acpi: fix conflicting IO address range for acpi pci hotplug in q35
Change caf108bc58790 ("hw/i386/acpi-build: Add ACPI PCI hot-plug methods to Q35")
selects an IO address range for acpi based PCI hotplug for q35 arbitrarily. It
starts at address 0x0cc4 and ends at 0x0cdb. At the time when the patch was
written but the final version of the patch was not yet pushed upstream, this
address range was free and did not conflict with any other IO address ranges.
However, with the following change, this address range was no
longer conflict free as in this change, the IO address range
(value of ACPI_PCIHP_SIZE) was incremented by four bytes:

b32bd763a1ca92 ("pci: introduce acpi-index property for PCI device")

This can be seen from the output of QMP command 'info mtree' :

0000000000000600-0000000000000603 (prio 0, i/o): acpi-evt
0000000000000604-0000000000000605 (prio 0, i/o): acpi-cnt
0000000000000608-000000000000060b (prio 0, i/o): acpi-tmr
0000000000000620-000000000000062f (prio 0, i/o): acpi-gpe0
0000000000000630-0000000000000637 (prio 0, i/o): acpi-smi
0000000000000cc4-0000000000000cdb (prio 0, i/o): acpi-pci-hotplug
0000000000000cd8-0000000000000ce3 (prio 0, i/o): acpi-cpu-hotplug

It shows that there is a region of conflict between IO regions of acpi
pci hotplug and acpi cpu hotplug.

Unfortunately, the change caf108bc58790 did not update the IO address range
appropriately before it was pushed upstream to accommodate the increased
length of the IO address space introduced in change b32bd763a1ca92.

Due to this bug, windows guests complain 'This device cannot find
enough free resources it can use' in the device manager panel for extended
IO buses. This issue also breaks the correct functioning of pci hotplug as the
following shows that the IO space for pci hotplug has been truncated:

(qemu) info mtree -f
FlatView #0
 AS "I/O", root: io
 Root memory region: io
  0000000000000cc4-0000000000000cd7 (prio 0, i/o): acpi-pci-hotplug
  0000000000000cd8-0000000000000cf7 (prio 0, i/o): acpi-cpu-hotplug

Therefore, in this fix, we adjust the IO address range for the acpi pci
hotplug so that it does not conflict with cpu hotplug and there is no
truncation of IO spaces. The starting IO address of PCI hotplug region
has been decremented by four bytes in order to accommodate four byte
increment in the IO address space introduced by change
b32bd763a1ca92 ("pci: introduce acpi-index property for PCI device")

After fixing, the following are the corrected IO ranges:

0000000000000600-0000000000000603 (prio 0, i/o): acpi-evt
0000000000000604-0000000000000605 (prio 0, i/o): acpi-cnt
0000000000000608-000000000000060b (prio 0, i/o): acpi-tmr
0000000000000620-000000000000062f (prio 0, i/o): acpi-gpe0
0000000000000630-0000000000000637 (prio 0, i/o): acpi-smi
0000000000000cc0-0000000000000cd7 (prio 0, i/o): acpi-pci-hotplug
0000000000000cd8-0000000000000ce3 (prio 0, i/o): acpi-cpu-hotplug

This change has been tested using a Windows Server 2019 guest VM. Windows
no longer complains after this change.

Fixes: caf108bc58790 ("hw/i386/acpi-build: Add ACPI PCI hot-plug methods to Q35")
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/561

Signed-off-by: Ani Sinha <ani@anisinha.ca>
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Julia Suvorova <jusual@redhat.com>
Message-Id: <20210916132838.3469580-3-ani@anisinha.ca>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
(cherry picked from commit 0e780da76a6fe283a20283856718bca3986c104f)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 13:12:38 -06:00
Ani Sinha
c66f5dfc12 bios-tables-test: allow changes in DSDT ACPI tables for q35
We are going to commit a change to fix IO address range allocated for acpi pci
hotplug in q35. This affects DSDT tables. This change allows DSDT table
modification so that unit tests are not broken.

Signed-off-by: Ani Sinha <ani@anisinha.ca>
Acked-by: Igor Mammedov <imammedo@redhat.com>
Message-Id: <20210916132838.3469580-2-ani@anisinha.ca>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
(cherry picked from commit 9f29e872d5b3973003701401cf659cfb71c95013)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 13:12:31 -06:00
Jean-Philippe Brucker
5cf977a2a1 hw/i386: Rename default_bus_bypass_iommu
Since commit d8fb7d0969d5 ("vl: switch -M parsing to keyval"), machine
parameter definitions cannot use underscores, because keyval_dashify()
transforms them to dashes and the parser doesn't find the parameter.

This affects option default_bus_bypass_iommu which was introduced in the
same release:

$ qemu-system-x86_64 -M q35,default_bus_bypass_iommu=on
qemu-system-x86_64: Property 'pc-q35-6.1-machine.default-bus-bypass-iommu' not found

Rename the parameter to "default-bus-bypass-iommu". Passing
"default_bus_bypass_iommu" is still valid since the underscore are
transformed automatically.

Fixes: c9e96b04fc19 ("hw/i386: Add a default_bus_bypass_iommu pc machine option")
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Tested-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Message-Id: <20211025104737.1560274-1-jean-philippe@linaro.org>
Cc: qemu-stable@nongnu.org
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 739b38630c45585cd9d372d44537f69c0b2b4346)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 13:07:48 -06:00
Jean-Philippe Brucker
36cfd11a86 hw/arm/virt: Rename default_bus_bypass_iommu
Since commit d8fb7d0969d5 ("vl: switch -M parsing to keyval"), machine
parameter definitions cannot use underscores, because keyval_dashify()
transforms them to dashes and the parser doesn't find the parameter.

This affects option default_bus_bypass_iommu which was introduced in the
same release:

$ qemu-system-aarch64 -M virt,default_bus_bypass_iommu=on
qemu-system-aarch64: Property 'virt-6.1-machine.default-bus-bypass-iommu' not found

Rename the parameter to "default-bus-bypass-iommu". Passing
"default_bus_bypass_iommu" is still valid since the underscore are
transformed automatically.

Fixes: 6d7a85483a06 ("hw/arm/virt: Add default_bus_bypass_iommu machine option")
Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
Tested-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Message-Id: <20211026093733.2144161-1-jean-philippe@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
(cherry picked from commit 9dad363a223df8269175d218413aa8cd265e078e)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 13:07:27 -06:00
Stefano Garzarella
246ccfbf44 vhost-vsock: fix migration issue when seqpacket is supported
Commit 1e08fd0a46 ("vhost-vsock: SOCK_SEQPACKET feature bit support")
enabled the SEQPACKET feature bit.
This commit is released with QEMU 6.1, so if we try to migrate a VM where
the host kernel supports SEQPACKET but machine type version is less than
6.1, we get the following errors:

    Features 0x130000002 unsupported. Allowed features: 0x179000000
    Failed to load virtio-vhost_vsock:virtio
    error while loading state for instance 0x0 of device '0000:00:05.0/virtio-vhost_vsock'
    load of migration failed: Operation not permitted

Let's disable the feature bit for machine types < 6.1.
We add a new OnOffAuto property for this, called `seqpacket`.
When it is `auto` (default), QEMU behaves as before, trying to enable the
feature, when it is `on` QEMU will fail if the backend (vhost-vsock
kernel module) doesn't support it.

Fixes: 1e08fd0a46 ("vhost-vsock: SOCK_SEQPACKET feature bit support")
Cc: qemu-stable@nongnu.org
Reported-by: Jiang Wang <jiang.wang@bytedance.com>
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
Message-Id: <20210921161642.206461-2-sgarzare@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
(cherry picked from commit d6a9378f47515c6d70dbff4912c5740c98709880)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 13:04:13 -06:00
Michael Tokarev
3ee93e456d qemu-sockets: fix unix socket path copy (again)
Commit 4cfd970ec188558daa6214f26203fe553fb1e01f added an
assert which ensures the path within an address of a unix
socket returned from the kernel is at least one byte and
does not exceed sun_path buffer. Both of this constraints
are wrong:

A unix socket can be unnamed, in this case the path is
completely empty (not even \0)

And some implementations (notable linux) can add extra
trailing byte (\0) _after_ the sun_path buffer if we
passed buffer larger than it (and we do).

So remove the assertion (since it causes real-life breakage)
but at the same time fix the usage of sun_path. Namely,
we should not access sun_path[0] if kernel did not return
it at all (this is the case for unnamed sockets),
and use the returned salen when copyig actual path as an
upper constraint for the amount of bytes to copy - this
will ensure we wont exceed the information provided by
the kernel, regardless whenever there is a trailing \0
or not. This also helps with unnamed sockets.

Note the case of abstract socket, the sun_path is actually
a blob and can contain \0 characters, - it should not be
passed to g_strndup and the like, it should be accessed by
memcpy-like functions.

Fixes: 4cfd970ec188558daa6214f26203fe553fb1e01f
Fixes: http://bugs.debian.org/993145
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
CC: qemu-stable@nongnu.org
(cherry picked from commit 118d527f2e4baec5fe8060b22a6212468b8e4d3f)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 12:55:36 -06:00
Paolo Bonzini
ec08035102 plugins: do not limit exported symbols if modules are active
On Mac --enable-modules and --enable-plugins are currently incompatible, because the
Apple -Wl,-exported_symbols_list command line options prevents the export of any
symbols needed by the modules.  On x86 -Wl,--dynamic-list does not have this effect,
but only because the -Wl,--export-dynamic option provided by gmodule-2.0.pc overrides
it.  On Apple there is no -Wl,--export-dynamic, because it is the default, and thus
no override.

Either way, when modules are active there is no reason to include the plugin_ldflags.
While at it, avoid the useless -Wl,--export-dynamic when --enable-plugins is
specified but --enable-modules is not; this way, the GNU and Apple configurations
are more similar.

Resolves: https://gitlab.com/qemu-project/qemu/-/issues/516
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
[AJB: fix noexport to no-export]
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Message-Id: <20210811100550.54714-1-pbonzini@redhat.com>
Cc: qemu-stable@nongnu.org
(cherry picked from commit b906acace2d4f68b6ff8de73739a773cc4851436)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 12:49:09 -06:00
Mahmoud Mandour
f97853c8cb plugins/execlog: removed unintended "s" at the end of log lines.
Signed-off-by: Mahmoud Mandour <ma.mandourr@gmail.com>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Message-Id: <20210803151428.125323-1-ma.mandourr@gmail.com>
Message-Id: <20210806141015.2487502-2-alex.bennee@linaro.org>
Cc: qemu-stable@nongnu.org
(cherry picked from commit b40310616d2bd550279dd22b05483c3c613a00ff)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 12:48:25 -06:00
Christian Schoenebeck
abeee2a470 9pfs: fix crash in v9fs_walk()
v9fs_walk() utilizes the v9fs_co_run_in_worker({...}) macro to run the
supplied fs driver code block on a background worker thread.

When either the 'Twalk' client request was interrupted or if the client
requested fid for that 'Twalk' request caused a stat error then that
fs driver code block was left by 'break' keyword, with the intention to
return from worker thread back to main thread as well:

    v9fs_co_run_in_worker({
        if (v9fs_request_cancelled(pdu)) {
            err = -EINTR;
            break;
        }
        err = s->ops->lstat(&s->ctx, &dpath, &fidst);
        if (err < 0) {
            err = -errno;
            break;
        }
        ...
    });

However that 'break;' statement also skipped the v9fs_co_run_in_worker()
macro's final and mandatory

    /* re-enter back to qemu thread */
    qemu_coroutine_yield();

call and thus caused the rest of v9fs_walk() to be continued being
executed on the worker thread instead of main thread, eventually
leading to a crash in the transport virtio transport driver.

To fix this issue and to prevent the same error from happening again by
other users of v9fs_co_run_in_worker() in future, auto wrap the supplied
code block into its own

    do { } while (0);

loop inside the 'v9fs_co_run_in_worker' macro definition.

Full discussion and backtrace:
https://lists.gnu.org/archive/html/qemu-devel/2021-08/msg05209.html
https://lists.gnu.org/archive/html/qemu-devel/2021-09/msg00174.html

Fixes: 8d6cb100731c4d28535adbf2a3c2d1f29be3fef4
Signed-off-by: Christian Schoenebeck <qemu_oss@crudebyte.com>
Cc: qemu-stable@nongnu.org
Reviewed-by: Greg Kurz <groug@kaod.org>
Message-Id: <E1mLTBg-0002Bh-2D@lizzy.crudebyte.com>
(cherry picked from commit f83df00900816476cca41bb536e4d532b297d76e)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 12:46:48 -06:00
Yang Zhong
ff6d391e10 i386/cpu: Remove AVX_VNNI feature from Cooperlake cpu model
The AVX_VNNI feature is not in Cooperlake platform, remove it
from cpu model.

Signed-off-by: Yang Zhong <yang.zhong@intel.com>
Message-Id: <20210820054611.84303-1-yang.zhong@intel.com>
Fixes: c1826ea6a052 ("i386/cpu: Expose AVX_VNNI instruction to guest")
Cc: qemu-stable@nongnu.org
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
(cherry picked from commit f429dbf8fc526a9cacf531176b28d0c65701475a)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 12:43:09 -06:00
Helge Deller
b19de1137b hw/display/artist: Fix bug in coordinate extraction in artist_vram_read() and artist_vram_write()
The CDE desktop on HP-UX 10 shows wrongly rendered pixels when the local screen
menu is closed. This bug was introduced by commit c7050f3f167b
("hw/display/artist: Refactor x/y coordination extraction") which converted the
coordinate extraction in artist_vram_read() and artist_vram_write() to use the
ADDR_TO_X and ADDR_TO_Y macros, but forgot to right-shift the address by 2 as
it was done before.

Signed-off-by: Helge Deller <deller@gmx.de>
Fixes: c7050f3f167b ("hw/display/artist: Refactor x/y coordination extraction")
Cc: Philippe Mathieu-Daudé <f4bug@amsat.org>
Cc: Richard Henderson <richard.henderson@linaro.org>
Cc: Sven Schnelle <svens@stackframe.org>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
Message-Id: <YK1aPb8keur9W7h2@ls3530>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
(cherry picked from commit 01f750f5fef1afd8f6abc0548910f87d473e26d5)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 08:57:12 -06:00
David Hildenbrand
3c6e5df1f6 libvhost-user: fix VHOST_USER_REM_MEM_REG skipping mmap_addr
We end up not copying the mmap_addr of all existing regions, resulting
in a SEGFAULT once we actually try to map/access anything within our
memory regions.

Fixes: 875b9fd97b34 ("Support individual region unmap in libvhost-user")
Cc: qemu-stable@nongnu.org
Cc: Michael S. Tsirkin <mst@redhat.com>
Cc: Raphael Norwitz <raphael.norwitz@nutanix.com>
Cc: "Marc-André Lureau" <marcandre.lureau@redhat.com>
Cc: Stefan Hajnoczi <stefanha@redhat.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Coiby Xu <coiby.xu@gmail.com>
Signed-off-by: David Hildenbrand <david@redhat.com>
Message-Id: <20211011201047.62587-1-david@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Raphael Norwitz <raphael.norwitz@nutanix.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
(cherry picked from commit 6889eb2d431ae962e3e083b57bff47cd573cb1c4)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 08:57:07 -06:00
Xueming Li
695c25e167 vhost-user: fix duplicated notifier MR init
In case of device resume after suspend, VQ notifier MR still valid.
Duplicated registrations explode memory block list and slow down device
resume.

Fixes: 44866521bd6e ("vhost-user: support registering external host notifiers")
Cc: tiwei.bie@intel.com
Cc: qemu-stable@nongnu.org
Cc: Yuwei Zhang <zhangyuwei.9149@bytedance.com>

Signed-off-by: Xueming Li <xuemingl@nvidia.com>
Message-Id: <20211008080215.590292-1-xuemingl@nvidia.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
(cherry picked from commit a1ed9ef1de87c3e86ff68589604298ec90875a14)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 08:57:02 -06:00
Gerd Hoffmann
23ba9f170f uas: add stream number sanity checks.
The device uses the guest-supplied stream number unchecked, which can
lead to guest-triggered out-of-band access to the UASDevice->data3 and
UASDevice->status3 fields.  Add the missing checks.

Fixes: CVE-2021-3713
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reported-by: Chen Zhe <chenzhe@huawei.com>
Reported-by: Tan Jingguo <tanjingguo@huawei.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Message-Id: <20210818120505.1258262-2-kraxel@redhat.com>
(cherry picked from commit 13b250b12ad3c59114a6a17d59caf073ce45b33a)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 08:56:53 -06:00
David Hildenbrand
f0dee5a40d virtio-mem-pci: Fix memory leak when creating MEMORY_DEVICE_SIZE_CHANGE event
Apparently, we don't have to duplicate the string.

Fixes: 722a3c783ef4 ("virtio-pci: Send qapi events when the virtio-mem size changes")
Cc: qemu-stable@nongnu.org
Signed-off-by: David Hildenbrand <david@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <20210929162445.64060-2-david@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 75b98cb9f6456ccf194211beffcbf93b0a995fa4)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 08:56:49 -06:00
Markus Armbruster
7637373b23 hmp: Unbreak "change vnc"
HMP command "change vnc" can take the password as argument, or prompt
for it:

    (qemu) change vnc password 123
    (qemu) change vnc password
    Password: ***
    (qemu)

This regressed in commit cfb5387a1d "hmp: remove "change vnc TARGET"
command", v6.0.0.

    (qemu) change vnc passwd 123
    Password: ***
    (qemu) change vnc passwd
    (qemu)

The latter passes NULL to qmp_change_vnc_password(), which is a no-no.
Looks like it puts the display into "password required, but none set"
state.

The logic error is easy to miss in review, but testing should've
caught it.

Fix the obvious way.

Fixes: cfb5387a1de2acda23fb5c97d2378b9e7ddf8025
Cc: qemu-stable@nongnu.org
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Gerd Hoffmann <kraxel@redhat.com>
Message-Id: <20210909081219.308065-2-armbru@redhat.com>
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
(cherry picked from commit 6193344f9337f8b76cd44ce94a32c9900d907d35)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 08:56:41 -06:00
Nir Soffer
4c34ef3d34 qemu-nbd: Change default cache mode to writeback
Both qemu and qemu-img use writeback cache mode by default, which is
already documented in qemu(1). qemu-nbd uses writethrough cache mode by
default, and the default cache mode is not documented.

According to the qemu-nbd(8):

   --cache=CACHE
          The  cache  mode  to be used with the file.  See the
          documentation of the emulator's -drive cache=... option for
          allowed values.

qemu(1) says:

    The default mode is cache=writeback.

So users have no reason to assume that qemu-nbd is using writethough
cache mode. The only hint is the painfully slow writing when using the
defaults.

Looking in git history, it seems that qemu used writethrough in the past
to support broken guests that did not flush data properly, or could not
flush due to limitations in qemu. But qemu-nbd clients can use
NBD_CMD_FLUSH to flush data, so using writethrough does not help anyone.

Change the default cache mode to writback, and document the default and
available values properly in the online help and manual.

With this change converting image via qemu-nbd is 3.5 times faster.

    $ qemu-img create dst.img 50g
    $ qemu-nbd -t -f raw -k /tmp/nbd.sock dst.img

Before this change:

    $ hyperfine -r3 "./qemu-img convert -p -f raw -O raw -T none -W fedora34.img nbd+unix:///?socket=/tmp/nbd.sock"
    Benchmark #1: ./qemu-img convert -p -f raw -O raw -T none -W fedora34.img nbd+unix:///?socket=/tmp/nbd.sock
      Time (mean ± σ):     83.639 s ±  5.970 s    [User: 2.733 s, System: 6.112 s]
      Range (min … max):   76.749 s … 87.245 s    3 runs

After this change:

    $ hyperfine -r3 "./qemu-img convert -p -f raw -O raw -T none -W fedora34.img nbd+unix:///?socket=/tmp/nbd.sock"
    Benchmark #1: ./qemu-img convert -p -f raw -O raw -T none -W fedora34.img nbd+unix:///?socket=/tmp/nbd.sock
      Time (mean ± σ):     23.522 s ±  0.433 s    [User: 2.083 s, System: 5.475 s]
      Range (min … max):   23.234 s … 24.019 s    3 runs

Users can avoid the issue by using --cache=writeback[1] but the defaults
should give good performance for the common use case.

[1] https://bugzilla.redhat.com/1990656

Signed-off-by: Nir Soffer <nsoffer@redhat.com>
Message-Id: <20210813205519.50518-1-nsoffer@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
CC: qemu-stable@nongnu.org
Signed-off-by: Eric Blake <eblake@redhat.com>
(cherry picked from commit 09615257058a0ae87b837bb041f56f7312d9ead8)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 08:56:36 -06:00
Jason Wang
9e41f16fca virtio-net: fix use after unmap/free for sg
When mergeable buffer is enabled, we try to set the num_buffers after
the virtqueue elem has been unmapped. This will lead several issues,
E.g a use after free when the descriptor has an address which belongs
to the non direct access region. In this case we use bounce buffer
that is allocated during address_space_map() and freed during
address_space_unmap().

Fixing this by storing the elems temporarily in an array and delay the
unmap after we set the the num_buffers.

This addresses CVE-2021-3748.

Reported-by: Alexander Bulekov <alxndr@bu.edu>
Fixes: fbe78f4f55c6 ("virtio-net support")
Cc: qemu-stable@nongnu.org
Signed-off-by: Jason Wang <jasowang@redhat.com>
(cherry picked from commit bedd7e93d01961fcb16a97ae45d93acf357e11f6)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 08:56:31 -06:00
Peter Maydell
3054f772de target/arm: Don't skip M-profile reset entirely in user mode
Currently all of the M-profile specific code in arm_cpu_reset() is
inside a !defined(CONFIG_USER_ONLY) ifdef block.  This is
unintentional: it happened because originally the only
M-profile-specific handling was the setup of the initial SP and PC
from the vector table, which is system-emulation only.  But then we
added a lot of other M-profile setup to the same "if (ARM_FEATURE_M)"
code block without noticing that it was all inside a not-user-mode
ifdef.  This has generally been harmless, but with the addition of
v8.1M low-overhead-loop support we ran into a problem: the reset of
FPSCR.LTPSIZE to 4 was only being done for system emulation mode, so
if a user-mode guest tried to execute the LE instruction it would
incorrectly take a UsageFault.

Adjust the ifdefs so only the really system-emulation specific parts
are covered.  Because this means we now run some reset code that sets
up initial values in the FPCCR and similar FPU related registers,
explicitly set up the registers controlling FPU context handling in
user-emulation mode so that the FPU works by design and not by
chance.

Resolves: https://gitlab.com/qemu-project/qemu/-/issues/613
Cc: qemu-stable@nongnu.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20210914120725.24992-2-peter.maydell@linaro.org
(cherry picked from commit b62ceeaf8096fdbbbfdc6087da0028bc4a4dd77e)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 08:56:25 -06:00
David Hildenbrand
aa77e375a5 virtio-balloon: don't start free page hinting if postcopy is possible
Postcopy never worked properly with 'free-page-hint=on', as there are
at least two issues:

1) With postcopy, the guest will never receive a VIRTIO_BALLOON_CMD_ID_DONE
   and consequently won't release free pages back to the OS once
   migration finishes.

   The issue is that for postcopy, we won't do a final bitmap sync while
   the guest is stopped on the source and
   virtio_balloon_free_page_hint_notify() will only call
   virtio_balloon_free_page_done() on the source during
   PRECOPY_NOTIFY_CLEANUP, after the VM state was already migrated to
   the destination.

2) Once the VM touches a page on the destination that has been excluded
   from migration on the source via qemu_guest_free_page_hint() while
   postcopy is active, that thread will stall until postcopy finishes
   and all threads are woken up. (with older Linux kernels that won't
   retry faults when woken up via userfaultfd, we might actually get a
   SEGFAULT)

   The issue is that the source will refuse to migrate any pages that
   are not marked as dirty in the dirty bmap -- for example, because the
   page might just have been sent. Consequently, the faulting thread will
   stall, waiting for the page to be migrated -- which could take quite
   a while and result in guest OS issues.

While we could fix 1) comparatively easily, 2) is harder to get right and
might require more involved RAM migration changes on source and destination
[1].

As it never worked properly, let's not start free page hinting in the
precopy notifier if the postcopy migration capability was enabled to fix
it easily. Capabilities cannot be enabled once migration is already
running.

Note 1: in the future we might either adjust migration code on the source
        to track pages that have actually been sent or adjust
        migration code on source and destination  to eventually send
        pages multiple times from the source and and deal with pages
        that are sent multiple times on the destination.

Note 2: virtio-mem has similar issues, however, access to "unplugged"
        memory by the guest is very rare and we would have to be very
        lucky for it to happen during migration. The spec states
        "The driver SHOULD NOT read from unplugged memory blocks ..."
        and "The driver MUST NOT write to unplugged memory blocks".
        virtio-mem will move away from virtio_balloon_free_page_done()
        soon and handle this case explicitly on the destination.

[1] https://lkml.kernel.org/r/e79fd18c-aa62-c1d8-c7f3-ba3fc2c25fc8@redhat.com

Fixes: c13c4153f76d ("virtio-balloon: VIRTIO_BALLOON_F_FREE_PAGE_HINT")
Cc: qemu-stable@nongnu.org
Cc: Wei Wang <wei.w.wang@intel.com>
Cc: Michael S. Tsirkin <mst@redhat.com>
Cc: Philippe Mathieu-Daudé <philmd@redhat.com>
Cc: Alexander Duyck <alexander.duyck@gmail.com>
Cc: Juan Quintela <quintela@redhat.com>
Cc: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
Cc: Peter Xu <peterx@redhat.com>
Signed-off-by: David Hildenbrand <david@redhat.com>
Message-Id: <20210708095339.20274-2-david@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Peter Xu <peterx@redhat.com>
(cherry picked from commit fd51e54fa10221e5a8add894c38cc1cf199f4bc4)
Signed-off-by: Michael Roth <michael.roth@amd.com>
2021-12-14 08:56:18 -06:00
1848 changed files with 39304 additions and 84353 deletions

1
.envrc
View File

@ -1 +0,0 @@
use_nix shell.nix

34
.github/lockdown.yml vendored Normal file
View File

@ -0,0 +1,34 @@
# Configuration for Repo Lockdown - https://github.com/dessant/repo-lockdown
# Close issues and pull requests
close: true
# Lock issues and pull requests
lock: true
issues:
comment: |
Thank you for your interest in the QEMU project.
This repository is a read-only mirror of the project's repostories hosted
at https://gitlab.com/qemu-project/qemu.git.
The project does not process issues filed on GitHub.
The project issues are tracked on GitLab:
https://gitlab.com/qemu-project/qemu/-/issues
QEMU welcomes bug report contributions. You can file new ones on:
https://gitlab.com/qemu-project/qemu/-/issues/new
pulls:
comment: |
Thank you for your interest in the QEMU project.
This repository is a read-only mirror of the project's repostories hosted
on https://gitlab.com/qemu-project/qemu.git.
The project does not process merge requests filed on GitHub.
QEMU welcomes contributions of code (either fixing bugs or adding new
functionality). However, we get a lot of patches, and so we have some
guidelines about contributing on the project website:
https://www.qemu.org/contribute/

View File

@ -1,30 +0,0 @@
# Configuration for Repo Lockdown - https://github.com/dessant/repo-lockdown
name: 'Repo Lockdown'
on:
pull_request_target:
types: opened
permissions:
pull-requests: write
jobs:
action:
runs-on: ubuntu-latest
steps:
- uses: dessant/repo-lockdown@v2
with:
pull-comment: |
Thank you for your interest in the QEMU project.
This repository is a read-only mirror of the project's repostories hosted
on https://gitlab.com/qemu-project/qemu.git.
The project does not process merge requests filed on GitHub.
QEMU welcomes contributions of code (either fixing bugs or adding new
functionality). However, we get a lot of patches, and so we have some
guidelines about contributing on the project website:
https://www.qemu.org/contribute/
lock-pull: true
close-pull: true

6
.gitignore vendored
View File

@ -15,6 +15,6 @@ GTAGS
*.depend_raw *.depend_raw
*.swp *.swp
*.patch *.patch
.ccls* .cache
.direnv *.axf
.vscode *.qcow2

View File

@ -37,7 +37,7 @@
# Avoid recompiling by hiding ninja with NINJA=":" # Avoid recompiling by hiding ninja with NINJA=":"
- make NINJA=":" $MAKE_CHECK_ARGS - make NINJA=":" $MAKE_CHECK_ARGS
.avocado_test_job_template: .acceptance_test_job_template:
extends: .native_test_job_template extends: .native_test_job_template
cache: cache:
key: "${CI_JOB_NAME}-cache" key: "${CI_JOB_NAME}-cache"

View File

@ -26,14 +26,14 @@ check-system-alpine:
IMAGE: alpine IMAGE: alpine
MAKE_CHECK_ARGS: check MAKE_CHECK_ARGS: check
avocado-system-alpine: acceptance-system-alpine:
extends: .avocado_test_job_template extends: .acceptance_test_job_template
needs: needs:
- job: build-system-alpine - job: build-system-alpine
artifacts: true artifacts: true
variables: variables:
IMAGE: alpine IMAGE: alpine
MAKE_CHECK_ARGS: check-avocado MAKE_CHECK_ARGS: check-acceptance
build-system-ubuntu: build-system-ubuntu:
extends: .native_build_job_template extends: .native_build_job_template
@ -59,14 +59,14 @@ check-system-ubuntu:
IMAGE: ubuntu2004 IMAGE: ubuntu2004
MAKE_CHECK_ARGS: check MAKE_CHECK_ARGS: check
avocado-system-ubuntu: acceptance-system-ubuntu:
extends: .avocado_test_job_template extends: .acceptance_test_job_template
needs: needs:
- job: build-system-ubuntu - job: build-system-ubuntu
artifacts: true artifacts: true
variables: variables:
IMAGE: ubuntu2004 IMAGE: ubuntu2004
MAKE_CHECK_ARGS: check-avocado MAKE_CHECK_ARGS: check-acceptance
build-system-debian: build-system-debian:
extends: .native_build_job_template extends: .native_build_job_template
@ -74,6 +74,7 @@ build-system-debian:
job: amd64-debian-container job: amd64-debian-container
variables: variables:
IMAGE: debian-amd64 IMAGE: debian-amd64
CONFIGURE_ARGS: --enable-fdt=system
TARGETS: arm-softmmu avr-softmmu i386-softmmu mipsel-softmmu TARGETS: arm-softmmu avr-softmmu i386-softmmu mipsel-softmmu
riscv64-softmmu sh4eb-softmmu sparc-softmmu xtensaeb-softmmu riscv64-softmmu sh4eb-softmmu sparc-softmmu xtensaeb-softmmu
MAKE_CHECK_ARGS: check-build MAKE_CHECK_ARGS: check-build
@ -91,14 +92,14 @@ check-system-debian:
IMAGE: debian-amd64 IMAGE: debian-amd64
MAKE_CHECK_ARGS: check MAKE_CHECK_ARGS: check
avocado-system-debian: acceptance-system-debian:
extends: .avocado_test_job_template extends: .acceptance_test_job_template
needs: needs:
- job: build-system-debian - job: build-system-debian
artifacts: true artifacts: true
variables: variables:
IMAGE: debian-amd64 IMAGE: debian-amd64
MAKE_CHECK_ARGS: check-avocado MAKE_CHECK_ARGS: check-acceptance
build-system-fedora: build-system-fedora:
extends: .native_build_job_template extends: .native_build_job_template
@ -125,14 +126,14 @@ check-system-fedora:
IMAGE: fedora IMAGE: fedora
MAKE_CHECK_ARGS: check MAKE_CHECK_ARGS: check
avocado-system-fedora: acceptance-system-fedora:
extends: .avocado_test_job_template extends: .acceptance_test_job_template
needs: needs:
- job: build-system-fedora - job: build-system-fedora
artifacts: true artifacts: true
variables: variables:
IMAGE: fedora IMAGE: fedora
MAKE_CHECK_ARGS: check-avocado MAKE_CHECK_ARGS: check-acceptance
build-system-centos: build-system-centos:
extends: .native_build_job_template extends: .native_build_job_template
@ -159,14 +160,14 @@ check-system-centos:
IMAGE: centos8 IMAGE: centos8
MAKE_CHECK_ARGS: check MAKE_CHECK_ARGS: check
avocado-system-centos: acceptance-system-centos:
extends: .avocado_test_job_template extends: .acceptance_test_job_template
needs: needs:
- job: build-system-centos - job: build-system-centos
artifacts: true artifacts: true
variables: variables:
IMAGE: centos8 IMAGE: centos8
MAKE_CHECK_ARGS: check-avocado MAKE_CHECK_ARGS: check-acceptance
build-system-opensuse: build-system-opensuse:
extends: .native_build_job_template extends: .native_build_job_template
@ -191,16 +192,95 @@ check-system-opensuse:
IMAGE: opensuse-leap IMAGE: opensuse-leap
MAKE_CHECK_ARGS: check MAKE_CHECK_ARGS: check
avocado-system-opensuse: acceptance-system-opensuse:
extends: .avocado_test_job_template extends: .acceptance_test_job_template
needs: needs:
- job: build-system-opensuse - job: build-system-opensuse
artifacts: true artifacts: true
variables: variables:
IMAGE: opensuse-leap IMAGE: opensuse-leap
MAKE_CHECK_ARGS: check-avocado MAKE_CHECK_ARGS: check-acceptance
build-disabled:
extends: .native_build_job_template
needs:
job: amd64-fedora-container
variables:
IMAGE: fedora
CONFIGURE_ARGS:
--disable-attr
--disable-auth-pam
--disable-avx2
--disable-bochs
--disable-brlapi
--disable-bzip2
--disable-cap-ng
--disable-capstone
--disable-cloop
--disable-coroutine-pool
--disable-curl
--disable-curses
--disable-dmg
--disable-docs
--disable-gcrypt
--disable-glusterfs
--disable-gnutls
--disable-gtk
--disable-guest-agent
--disable-iconv
--disable-keyring
--disable-kvm
--disable-libiscsi
--disable-libpmem
--disable-libssh
--disable-libudev
--disable-libusb
--disable-libxml2
--disable-linux-aio
--disable-live-block-migration
--disable-lzo
--disable-malloc-trim
--disable-mpath
--disable-nettle
--disable-numa
--disable-opengl
--disable-parallels
--disable-pie
--disable-qcow1
--disable-qed
--disable-qom-cast-debug
--disable-rbd
--disable-rdma
--disable-replication
--disable-sdl
--disable-seccomp
--disable-slirp
--disable-smartcard
--disable-snappy
--disable-sparse
--disable-spice
--disable-strip
--disable-tpm
--disable-usb-redir
--disable-vdi
--disable-vhost-crypto
--disable-vhost-net
--disable-vhost-scsi
--disable-vhost-kernel
--disable-vhost-user
--disable-vhost-vdpa
--disable-vhost-vsock
--disable-virglrenderer
--disable-vnc
--disable-vte
--disable-vvfat
--disable-xen
--disable-zstd
TARGETS: arm-softmmu i386-softmmu ppc64-softmmu mips64-softmmu
s390x-softmmu i386-linux-user
MAKE_CHECK_ARGS: check-qtest SPEED=slow
# This jobs explicitly disable TCG (--disable-tcg), KVM is detected by # This jobs explicitly disable TCG (--disable-tcg), KVM is detected by
# the configure script. The container doesn't contain Xen headers so # the configure script. The container doesn't contain Xen headers so
# Xen accelerator is not detected / selected. As result it build the # Xen accelerator is not detected / selected. As result it build the
@ -225,11 +305,11 @@ build-tcg-disabled:
- cd tests/qemu-iotests/ - cd tests/qemu-iotests/
- ./check -raw 001 002 003 004 005 008 009 010 011 012 021 025 032 033 048 - ./check -raw 001 002 003 004 005 008 009 010 011 012 021 025 032 033 048
052 063 077 086 101 104 106 113 148 150 151 152 157 159 160 163 052 063 077 086 101 104 106 113 148 150 151 152 157 159 160 163
170 171 183 184 192 194 208 221 226 227 236 253 277 image-fleecing 170 171 183 184 192 194 208 221 222 226 227 236 253 277
- ./check -qcow2 028 051 056 057 058 065 068 082 085 091 095 096 102 122 - ./check -qcow2 028 051 056 057 058 065 068 082 085 091 095 096 102 122
124 132 139 142 144 145 151 152 155 157 165 194 196 200 202 124 132 139 142 144 145 151 152 155 157 165 194 196 200 202
208 209 216 218 227 234 246 247 248 250 254 255 257 258 208 209 216 218 222 227 234 246 247 248 250 254 255 257 258
260 261 262 263 264 270 272 273 277 279 image-fleecing 260 261 262 263 264 270 272 273 277 279
build-user: build-user:
extends: .native_build_job_template extends: .native_build_job_template
@ -317,7 +397,7 @@ clang-user:
# This can be accomplished by using -enable-slirp=git, which avoids the use of # This can be accomplished by using -enable-slirp=git, which avoids the use of
# a system-wide version of the library # a system-wide version of the library
# #
# Split in three sets of build/check/avocado to limit the execution time of each # Split in three sets of build/check/acceptance to limit the execution time of each
# job # job
build-cfi-aarch64: build-cfi-aarch64:
extends: .native_build_job_template extends: .native_build_job_template
@ -352,14 +432,14 @@ check-cfi-aarch64:
IMAGE: fedora IMAGE: fedora
MAKE_CHECK_ARGS: check MAKE_CHECK_ARGS: check
avocado-cfi-aarch64: acceptance-cfi-aarch64:
extends: .avocado_test_job_template extends: .acceptance_test_job_template
needs: needs:
- job: build-cfi-aarch64 - job: build-cfi-aarch64
artifacts: true artifacts: true
variables: variables:
IMAGE: fedora IMAGE: fedora
MAKE_CHECK_ARGS: check-avocado MAKE_CHECK_ARGS: check-acceptance
build-cfi-ppc64-s390x: build-cfi-ppc64-s390x:
extends: .native_build_job_template extends: .native_build_job_template
@ -394,14 +474,14 @@ check-cfi-ppc64-s390x:
IMAGE: fedora IMAGE: fedora
MAKE_CHECK_ARGS: check MAKE_CHECK_ARGS: check
avocado-cfi-ppc64-s390x: acceptance-cfi-ppc64-s390x:
extends: .avocado_test_job_template extends: .acceptance_test_job_template
needs: needs:
- job: build-cfi-ppc64-s390x - job: build-cfi-ppc64-s390x
artifacts: true artifacts: true
variables: variables:
IMAGE: fedora IMAGE: fedora
MAKE_CHECK_ARGS: check-avocado MAKE_CHECK_ARGS: check-acceptance
build-cfi-x86_64: build-cfi-x86_64:
extends: .native_build_job_template extends: .native_build_job_template
@ -430,14 +510,14 @@ check-cfi-x86_64:
IMAGE: fedora IMAGE: fedora
MAKE_CHECK_ARGS: check MAKE_CHECK_ARGS: check
avocado-cfi-x86_64: acceptance-cfi-x86_64:
extends: .avocado_test_job_template extends: .acceptance_test_job_template
needs: needs:
- job: build-cfi-x86_64 - job: build-cfi-x86_64
artifacts: true artifacts: true
variables: variables:
IMAGE: fedora IMAGE: fedora
MAKE_CHECK_ARGS: check-avocado MAKE_CHECK_ARGS: check-acceptance
tsan-build: tsan-build:
extends: .native_build_job_template extends: .native_build_job_template
@ -569,25 +649,20 @@ build-without-default-devices:
build-without-default-features: build-without-default-features:
extends: .native_build_job_template extends: .native_build_job_template
needs: needs:
job: amd64-fedora-container job: amd64-debian-container
variables: variables:
IMAGE: fedora IMAGE: debian-amd64
CONFIGURE_ARGS: CONFIGURE_ARGS: --without-default-features --disable-user
--without-default-features --target-list-exclude=arm-softmmu,i386-softmmu,mipsel-softmmu,mips64-softmmu,ppc-softmmu
--disable-capstone MAKE_CHECK_ARGS: check-unit
--disable-pie
--disable-qom-cast-debug
--disable-slirp
--disable-strip
TARGETS: avr-softmmu i386-softmmu mips64-softmmu s390x-softmmu sh4-softmmu
sparc64-softmmu hexagon-linux-user i386-linux-user s390x-linux-user
MAKE_CHECK_ARGS: check-unit check-qtest SPEED=slow
build-libvhost-user: build-libvhost-user:
stage: build stage: build
image: $CI_REGISTRY_IMAGE/qemu/fedora:latest image: $CI_REGISTRY_IMAGE/qemu/fedora:latest
needs: needs:
job: amd64-fedora-container job: amd64-fedora-container
before_script:
- dnf install -y meson ninja-build
script: script:
- mkdir subprojects/libvhost-user/build - mkdir subprojects/libvhost-user/build
- cd subprojects/libvhost-user/build - cd subprojects/libvhost-user/build

View File

@ -14,7 +14,6 @@
stage: build stage: build
image: registry.gitlab.com/libvirt/libvirt-ci/cirrus-run:master image: registry.gitlab.com/libvirt/libvirt-ci/cirrus-run:master
needs: [] needs: []
timeout: 80m
allow_failure: true allow_failure: true
script: script:
- source .gitlab-ci.d/cirrus/$NAME.vars - source .gitlab-ci.d/cirrus/$NAME.vars
@ -36,14 +35,11 @@
-e "s|[@]PIP3@|$PIP3|g" -e "s|[@]PIP3@|$PIP3|g"
-e "s|[@]PYPI_PKGS@|$PYPI_PKGS|g" -e "s|[@]PYPI_PKGS@|$PYPI_PKGS|g"
-e "s|[@]CONFIGURE_ARGS@|$CONFIGURE_ARGS|g" -e "s|[@]CONFIGURE_ARGS@|$CONFIGURE_ARGS|g"
-e "s|[@]TEST_TARGETS@|$TEST_TARGETS|g" -e "s|[@]TEST_TARGETSS@|$TEST_TARGETSS|g"
<.gitlab-ci.d/cirrus/build.yml >.gitlab-ci.d/cirrus/$NAME.yml <.gitlab-ci.d/cirrus/build.yml >.gitlab-ci.d/cirrus/$NAME.yml
- cat .gitlab-ci.d/cirrus/$NAME.yml - cat .gitlab-ci.d/cirrus/$NAME.yml
- cirrus-run -v --show-build-log always .gitlab-ci.d/cirrus/$NAME.yml - cirrus-run -v --show-build-log always .gitlab-ci.d/cirrus/$NAME.yml
rules: rules:
# Allow on 'staging' branch and 'stable-X.Y-staging' branches only
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH !~ /staging/'
when: never
- if: "$CIRRUS_GITHUB_REPO && $CIRRUS_API_TOKEN" - if: "$CIRRUS_GITHUB_REPO && $CIRRUS_API_TOKEN"
x64-freebsd-12-build: x64-freebsd-12-build:

View File

@ -13,7 +13,6 @@ env:
PYTHON: "@PYTHON@" PYTHON: "@PYTHON@"
MAKE: "@MAKE@" MAKE: "@MAKE@"
CONFIGURE_ARGS: "@CONFIGURE_ARGS@" CONFIGURE_ARGS: "@CONFIGURE_ARGS@"
TEST_TARGETS: "@TEST_TARGETS@"
build_task: build_task:
install_script: install_script:

View File

@ -134,8 +134,7 @@ ppc64el-debian-cross-container:
riscv64-debian-cross-container: riscv64-debian-cross-container:
extends: .container_job_template extends: .container_job_template
stage: containers-layer2 stage: containers-layer2
# as we are currently based on 'sid/unstable' we may break so... needs: ['amd64-debian10-container']
allow_failure: true
variables: variables:
NAME: debian-riscv64-cross NAME: debian-riscv64-cross

View File

@ -124,25 +124,6 @@ cross-ppc64el-user:
variables: variables:
IMAGE: debian-ppc64el-cross IMAGE: debian-ppc64el-cross
# The riscv64 cross-builds currently use a 'sid' container to get
# compilers and libraries. Until something more stable is found we
# allow_failure so as not to block CI.
cross-riscv64-system:
extends: .cross_system_build_job
allow_failure: true
needs:
job: riscv64-debian-cross-container
variables:
IMAGE: debian-riscv64-cross
cross-riscv64-user:
extends: .cross_user_build_job
allow_failure: true
needs:
job: riscv64-debian-cross-container
variables:
IMAGE: debian-riscv64-cross
cross-s390x-system: cross-s390x-system:
extends: .cross_system_build_job extends: .cross_system_build_job
needs: needs:

View File

@ -13,7 +13,226 @@
variables: variables:
GIT_STRATEGY: clone GIT_STRATEGY: clone
include: # All ubuntu-18.04 jobs should run successfully in an environment
- local: '/.gitlab-ci.d/custom-runners/ubuntu-18.04-s390x.yml' # setup by the scripts/ci/setup/build-environment.yml task
- local: '/.gitlab-ci.d/custom-runners/ubuntu-20.04-aarch64.yml' # "Install basic packages to build QEMU on Ubuntu 18.04/20.04"
- local: '/.gitlab-ci.d/custom-runners/centos-stream-8-x86_64.yml' ubuntu-18.04-s390x-all-linux-static:
allow_failure: true
needs: []
stage: build
tags:
- ubuntu_18.04
- s390x
rules:
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
- if: "$S390X_RUNNER_AVAILABLE"
script:
# --disable-libssh is needed because of https://bugs.launchpad.net/qemu/+bug/1838763
# --disable-glusterfs is needed because there's no static version of those libs in distro supplied packages
- mkdir build
- cd build
- ../configure --enable-debug --static --disable-system --disable-glusterfs --disable-libssh
- make --output-sync -j`nproc`
- make --output-sync -j`nproc` check V=1
- make --output-sync -j`nproc` check-tcg V=1
ubuntu-18.04-s390x-all:
allow_failure: true
needs: []
stage: build
tags:
- ubuntu_18.04
- s390x
rules:
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
- if: "$S390X_RUNNER_AVAILABLE"
script:
- mkdir build
- cd build
- ../configure --disable-libssh
- make --output-sync -j`nproc`
- make --output-sync -j`nproc` check V=1
ubuntu-18.04-s390x-alldbg:
allow_failure: true
needs: []
stage: build
tags:
- ubuntu_18.04
- s390x
rules:
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
- if: "$S390X_RUNNER_AVAILABLE"
script:
- mkdir build
- cd build
- ../configure --enable-debug --disable-libssh
- make clean
- make --output-sync -j`nproc`
- make --output-sync -j`nproc` check V=1
ubuntu-18.04-s390x-clang:
allow_failure: true
needs: []
stage: build
tags:
- ubuntu_18.04
- s390x
rules:
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
when: manual
- if: "$S390X_RUNNER_AVAILABLE"
when: manual
script:
- mkdir build
- cd build
- ../configure --disable-libssh --cc=clang --cxx=clang++ --enable-sanitizers
- make --output-sync -j`nproc`
- make --output-sync -j`nproc` check V=1
ubuntu-18.04-s390x-tci:
allow_failure: true
needs: []
stage: build
tags:
- ubuntu_18.04
- s390x
rules:
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
- if: "$S390X_RUNNER_AVAILABLE"
script:
- mkdir build
- cd build
- ../configure --disable-libssh --enable-tcg-interpreter
- make --output-sync -j`nproc`
ubuntu-18.04-s390x-notcg:
allow_failure: true
needs: []
stage: build
tags:
- ubuntu_18.04
- s390x
rules:
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
when: manual
- if: "$S390X_RUNNER_AVAILABLE"
when: manual
script:
- mkdir build
- cd build
- ../configure --disable-libssh --disable-tcg
- make --output-sync -j`nproc`
- make --output-sync -j`nproc` check V=1
# All ubuntu-20.04 jobs should run successfully in an environment
# setup by the scripts/ci/setup/qemu/build-environment.yml task
# "Install basic packages to build QEMU on Ubuntu 18.04/20.04"
ubuntu-20.04-aarch64-all-linux-static:
allow_failure: true
needs: []
stage: build
tags:
- ubuntu_20.04
- aarch64
rules:
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
- if: "$S390X_RUNNER_AVAILABLE"
script:
# --disable-libssh is needed because of https://bugs.launchpad.net/qemu/+bug/1838763
# --disable-glusterfs is needed because there's no static version of those libs in distro supplied packages
- mkdir build
- cd build
- ../configure --enable-debug --static --disable-system --disable-glusterfs --disable-libssh
- make --output-sync -j`nproc`
- make --output-sync -j`nproc` check V=1
- make --output-sync -j`nproc` check-tcg V=1
ubuntu-20.04-aarch64-all:
allow_failure: true
needs: []
stage: build
tags:
- ubuntu_20.04
- aarch64
rules:
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
- if: "$S390X_RUNNER_AVAILABLE"
script:
- mkdir build
- cd build
- ../configure --disable-libssh
- make --output-sync -j`nproc`
- make --output-sync -j`nproc` check V=1
ubuntu-20.04-aarch64-alldbg:
allow_failure: true
needs: []
stage: build
tags:
- ubuntu_20.04
- aarch64
rules:
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
- if: "$S390X_RUNNER_AVAILABLE"
script:
- mkdir build
- cd build
- ../configure --enable-debug --disable-libssh
- make clean
- make --output-sync -j`nproc`
- make --output-sync -j`nproc` check V=1
ubuntu-20.04-aarch64-clang:
allow_failure: true
needs: []
stage: build
tags:
- ubuntu_20.04
- aarch64
rules:
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
when: manual
- if: "$S390X_RUNNER_AVAILABLE"
when: manual
script:
- mkdir build
- cd build
- ../configure --disable-libssh --cc=clang-10 --cxx=clang++-10 --enable-sanitizers
- make --output-sync -j`nproc`
- make --output-sync -j`nproc` check V=1
ubuntu-20.04-aarch64-tci:
allow_failure: true
needs: []
stage: build
tags:
- ubuntu_20.04
- aarch64
rules:
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
- if: "$S390X_RUNNER_AVAILABLE"
script:
- mkdir build
- cd build
- ../configure --disable-libssh --enable-tcg-interpreter
- make --output-sync -j`nproc`
ubuntu-20.04-aarch64-notcg:
allow_failure: true
needs: []
stage: build
tags:
- ubuntu_20.04
- aarch64
rules:
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
when: manual
- if: "$S390X_RUNNER_AVAILABLE"
when: manual
script:
- mkdir build
- cd build
- ../configure --disable-libssh --disable-tcg
- make --output-sync -j`nproc`
- make --output-sync -j`nproc` check V=1

View File

@ -1,28 +0,0 @@
centos-stream-8-x86_64:
allow_failure: true
needs: []
stage: build
tags:
- centos_stream_8
- x86_64
rules:
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
- if: "$CENTOS_STREAM_8_x86_64_RUNNER_AVAILABLE"
artifacts:
name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
when: on_failure
expire_in: 7 days
paths:
- build/tests/results/latest/results.xml
- build/tests/results/latest/test-results
reports:
junit: build/tests/results/latest/results.xml
before_script:
- JOBS=$(expr $(nproc) + 1)
script:
- mkdir build
- cd build
- ../scripts/ci/org.centos/stream/8/x86_64/configure
- make -j"$JOBS"
- make NINJA=":" check
- ../scripts/ci/org.centos/stream/8/x86_64/test-avocado

View File

@ -1,118 +0,0 @@
# All ubuntu-18.04 jobs should run successfully in an environment
# setup by the scripts/ci/setup/build-environment.yml task
# "Install basic packages to build QEMU on Ubuntu 18.04/20.04"
ubuntu-18.04-s390x-all-linux-static:
needs: []
stage: build
tags:
- ubuntu_18.04
- s390x
rules:
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
- if: "$S390X_RUNNER_AVAILABLE"
script:
# --disable-libssh is needed because of https://bugs.launchpad.net/qemu/+bug/1838763
# --disable-glusterfs is needed because there's no static version of those libs in distro supplied packages
- mkdir build
- cd build
- ../configure --enable-debug --static --disable-system --disable-glusterfs --disable-libssh
- make --output-sync -j`nproc`
- make --output-sync -j`nproc` check V=1
- make --output-sync -j`nproc` check-tcg V=1
ubuntu-18.04-s390x-all:
needs: []
stage: build
tags:
- ubuntu_18.04
- s390x
rules:
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
- if: "$S390X_RUNNER_AVAILABLE"
script:
- mkdir build
- cd build
- ../configure --disable-libssh
- make --output-sync -j`nproc`
- make --output-sync -j`nproc` check V=1
ubuntu-18.04-s390x-alldbg:
needs: []
stage: build
tags:
- ubuntu_18.04
- s390x
rules:
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
when: manual
allow_failure: true
- if: "$S390X_RUNNER_AVAILABLE"
when: manual
allow_failure: true
script:
- mkdir build
- cd build
- ../configure --enable-debug --disable-libssh
- make clean
- make --output-sync -j`nproc`
- make --output-sync -j`nproc` check V=1
ubuntu-18.04-s390x-clang:
needs: []
stage: build
tags:
- ubuntu_18.04
- s390x
rules:
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
when: manual
allow_failure: true
- if: "$S390X_RUNNER_AVAILABLE"
when: manual
allow_failure: true
script:
- mkdir build
- cd build
- ../configure --disable-libssh --cc=clang --cxx=clang++ --enable-sanitizers
- make --output-sync -j`nproc`
- make --output-sync -j`nproc` check V=1
ubuntu-18.04-s390x-tci:
needs: []
stage: build
tags:
- ubuntu_18.04
- s390x
rules:
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
when: manual
allow_failure: true
- if: "$S390X_RUNNER_AVAILABLE"
when: manual
allow_failure: true
script:
- mkdir build
- cd build
- ../configure --disable-libssh --enable-tcg-interpreter
- make --output-sync -j`nproc`
ubuntu-18.04-s390x-notcg:
needs: []
stage: build
tags:
- ubuntu_18.04
- s390x
rules:
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
when: manual
allow_failure: true
- if: "$S390X_RUNNER_AVAILABLE"
when: manual
allow_failure: true
script:
- mkdir build
- cd build
- ../configure --disable-libssh --disable-tcg
- make --output-sync -j`nproc`
- make --output-sync -j`nproc` check V=1

View File

@ -1,118 +0,0 @@
# All ubuntu-20.04 jobs should run successfully in an environment
# setup by the scripts/ci/setup/qemu/build-environment.yml task
# "Install basic packages to build QEMU on Ubuntu 18.04/20.04"
ubuntu-20.04-aarch64-all-linux-static:
needs: []
stage: build
tags:
- ubuntu_20.04
- aarch64
rules:
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
- if: "$AARCH64_RUNNER_AVAILABLE"
script:
# --disable-libssh is needed because of https://bugs.launchpad.net/qemu/+bug/1838763
# --disable-glusterfs is needed because there's no static version of those libs in distro supplied packages
- mkdir build
- cd build
- ../configure --enable-debug --static --disable-system --disable-glusterfs --disable-libssh
- make --output-sync -j`nproc`
- make --output-sync -j`nproc` check V=1
- make --output-sync -j`nproc` check-tcg V=1
ubuntu-20.04-aarch64-all:
needs: []
stage: build
tags:
- ubuntu_20.04
- aarch64
rules:
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
when: manual
allow_failure: true
- if: "$AARCH64_RUNNER_AVAILABLE"
when: manual
allow_failure: true
script:
- mkdir build
- cd build
- ../configure --disable-libssh
- make --output-sync -j`nproc`
- make --output-sync -j`nproc` check V=1
ubuntu-20.04-aarch64-alldbg:
needs: []
stage: build
tags:
- ubuntu_20.04
- aarch64
rules:
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
- if: "$AARCH64_RUNNER_AVAILABLE"
script:
- mkdir build
- cd build
- ../configure --enable-debug --disable-libssh
- make clean
- make --output-sync -j`nproc`
- make --output-sync -j`nproc` check V=1
ubuntu-20.04-aarch64-clang:
needs: []
stage: build
tags:
- ubuntu_20.04
- aarch64
rules:
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
when: manual
allow_failure: true
- if: "$AARCH64_RUNNER_AVAILABLE"
when: manual
allow_failure: true
script:
- mkdir build
- cd build
- ../configure --disable-libssh --cc=clang-10 --cxx=clang++-10 --enable-sanitizers
- make --output-sync -j`nproc`
- make --output-sync -j`nproc` check V=1
ubuntu-20.04-aarch64-tci:
needs: []
stage: build
tags:
- ubuntu_20.04
- aarch64
rules:
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
when: manual
allow_failure: true
- if: "$AARCH64_RUNNER_AVAILABLE"
when: manual
allow_failure: true
script:
- mkdir build
- cd build
- ../configure --disable-libssh --enable-tcg-interpreter
- make --output-sync -j`nproc`
ubuntu-20.04-aarch64-notcg:
needs: []
stage: build
tags:
- ubuntu_20.04
- aarch64
rules:
- if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH =~ /^staging/'
when: manual
allow_failure: true
- if: "$AARCH64_RUNNER_AVAILABLE"
when: manual
allow_failure: true
script:
- mkdir build
- cd build
- ../configure --disable-libssh --disable-tcg
- make --output-sync -j`nproc`
- make --output-sync -j`nproc` check V=1

View File

@ -50,11 +50,7 @@ build-edk2:
GIT_DEPTH: 3 GIT_DEPTH: 3
script: # Clone the required submodules and build EDK2 script: # Clone the required submodules and build EDK2
- git submodule update --init roms/edk2 - git submodule update --init roms/edk2
- git -C roms/edk2 submodule update --init -- - git -C roms/edk2 submodule update --init
ArmPkg/Library/ArmSoftFloatLib/berkeley-softfloat-3
BaseTools/Source/C/BrotliCompress/brotli
CryptoPkg/Library/OpensslLib/openssl
MdeModulePkg/Library/BrotliCustomDecompressLib/brotli
- export JOBS=$(($(getconf _NPROCESSORS_ONLN) + 1)) - export JOBS=$(($(getconf _NPROCESSORS_ONLN) + 1))
- echo "=== Using ${JOBS} simultaneous jobs ===" - echo "=== Using ${JOBS} simultaneous jobs ==="
- make -j${JOBS} -C roms efi 2>&1 1>edk2-stdout.log | tee -a edk2-stderr.log >&2 - make -j${JOBS} -C roms efi 2>&1 1>edk2-stdout.log | tee -a edk2-stderr.log >&2

View File

@ -8,7 +8,7 @@ check-patch:
variables: variables:
GIT_DEPTH: 1000 GIT_DEPTH: 1000
rules: rules:
- if: '$CI_PROJECT_NAMESPACE == "qemu-project"' - if: '$CI_PROJECT_NAMESPACE == "qemu-project" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
when: never when: never
- when: on_success - when: on_success
allow_failure: true allow_failure: true

View File

@ -69,7 +69,6 @@ Yongbok Kim <yongbok.kim@mips.com> <yongbok.kim@imgtec.com>
# git author config, or had utf8/latin1 encoding issues. # git author config, or had utf8/latin1 encoding issues.
Aaron Lindsay <aaron@os.amperecomputing.com> Aaron Lindsay <aaron@os.amperecomputing.com>
Alexey Gerasimenko <x1917x@gmail.com> Alexey Gerasimenko <x1917x@gmail.com>
Alex Chen <alex.chen@huawei.com>
Alex Ivanov <void@aleksoft.net> Alex Ivanov <void@aleksoft.net>
Andreas Färber <afaerber@suse.de> Andreas Färber <afaerber@suse.de>
Bandan Das <bsd@redhat.com> Bandan Das <bsd@redhat.com>
@ -100,11 +99,9 @@ Gautham R. Shenoy <ego@in.ibm.com>
Gautham R. Shenoy <ego@linux.vnet.ibm.com> Gautham R. Shenoy <ego@linux.vnet.ibm.com>
Gonglei (Arei) <arei.gonglei@huawei.com> Gonglei (Arei) <arei.gonglei@huawei.com>
Guang Wang <wang.guang55@zte.com.cn> Guang Wang <wang.guang55@zte.com.cn>
Haibin Zhang <haibinzhang@tencent.com>
Hailiang Zhang <zhang.zhanghailiang@huawei.com> Hailiang Zhang <zhang.zhanghailiang@huawei.com>
Hanna Reitz <hreitz@redhat.com> <mreitz@redhat.com> Hanna Reitz <hreitz@redhat.com> <mreitz@redhat.com>
Hervé Poussineau <hpoussin@reactos.org> Hervé Poussineau <hpoussin@reactos.org>
Hyman Huang <huangy81@chinatelecom.cn>
Jakub Jermář <jakub@jermar.eu> Jakub Jermář <jakub@jermar.eu>
Jakub Jermář <jakub.jermar@kernkonzept.com> Jakub Jermář <jakub.jermar@kernkonzept.com>
Jean-Christophe Dubois <jcd@tribudubois.net> Jean-Christophe Dubois <jcd@tribudubois.net>
@ -138,7 +135,6 @@ Nicholas Thomas <nick@bytemark.co.uk>
Nikunj A Dadhania <nikunj@linux.vnet.ibm.com> Nikunj A Dadhania <nikunj@linux.vnet.ibm.com>
Orit Wasserman <owasserm@redhat.com> Orit Wasserman <owasserm@redhat.com>
Paolo Bonzini <pbonzini@redhat.com> Paolo Bonzini <pbonzini@redhat.com>
Pan Nengyuan <pannengyuan@huawei.com>
Pavel Dovgaluk <dovgaluk@ispras.ru> Pavel Dovgaluk <dovgaluk@ispras.ru>
Pavel Dovgaluk <pavel.dovgaluk@gmail.com> Pavel Dovgaluk <pavel.dovgaluk@gmail.com>
Pavel Dovgaluk <Pavel.Dovgaluk@ispras.ru> Pavel Dovgaluk <Pavel.Dovgaluk@ispras.ru>

View File

@ -305,3 +305,26 @@ jobs:
- CONFIG="--disable-containers --disable-tcg --enable-kvm - CONFIG="--disable-containers --disable-tcg --enable-kvm
--disable-tools --host-cc=clang --cxx=clang++" --disable-tools --host-cc=clang --cxx=clang++"
- UNRELIABLE=true - UNRELIABLE=true
# Release builds
# The make-release script expect a QEMU version, so our tag must start with a 'v'.
# This is the case when release candidate tags are created.
- name: "Release tarball"
if: tag IS present AND tag =~ /^v\d+\.\d+(\.\d+)?(-\S*)?$/
env:
# We want to build from the release tarball
- BUILD_DIR="release/build/dir" SRC_DIR="../../.."
- BASE_CONFIG="--prefix=$PWD/dist"
- CONFIG="--target-list=x86_64-softmmu,aarch64-softmmu,armeb-linux-user,ppc-linux-user"
- TEST_CMD="make install -j${JOBS}"
- QEMU_VERSION="${TRAVIS_TAG:1}"
- CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-default"
script:
- make -C ${SRC_DIR} qemu-${QEMU_VERSION}.tar.bz2
- ls -l ${SRC_DIR}/qemu-${QEMU_VERSION}.tar.bz2
- tar -xf ${SRC_DIR}/qemu-${QEMU_VERSION}.tar.bz2 && cd qemu-${QEMU_VERSION}
- mkdir -p release-build && cd release-build
- ../configure ${BASE_CONFIG} ${CONFIG} || { cat config.log meson-logs/meson-log.txt && exit 1; }
- make install
allow_failures:
- env: UNRELIABLE=true

72
3k.c Normal file
View File

@ -0,0 +1,72 @@
#include <stdio.h>
#include <stdint.h>
void libafl_qemu_main_loop( void );
void libafl_qemu_sys_init(int argc, char **argv, char **envp);
void libafl_qemu_cleanup( void );
void libafl_qemu_set_breakpoint( unsigned long int );
void libafl_qemu_remove_native_breakpoint( unsigned long int );
void libafl_qemu_set_native_breakpoint( unsigned long int );
void libafl_snapshot_save( const char* );
void libafl_snapshot_load( const char* );
void libafl_phys_read(uint32_t, uint8_t*, int);
void libafl_phys_write(uint32_t, uint8_t*, int);
int64_t icount_to_ns(int64_t icount);
int64_t libafl_get_clock( void );
int main(int argc, char **argv, char **envp)
{
unsigned char buf[32] = "_`abcdefghijklmnopqrstuvwxyz{|}~";
unsigned char buf2[32] = "0";
unsigned char buf3[32] = "z";
unsigned char buf4[32] = "a!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
unsigned char buf5[32] = "b!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
libafl_qemu_sys_init(argc, argv, envp);
int pheader = 0x00006a4c;
// libafl_phys_read(0x20000110-0x20000100+pheader, buf,32);
// printf("FUZZ_INPUT[0]: %c\n", buf[0]);
// Start pre-run
libafl_qemu_set_native_breakpoint(0x4ce2);//send 217028
libafl_qemu_main_loop();
libafl_qemu_remove_native_breakpoint(0x4ce2);
// End pre-run
libafl_snapshot_save("Start");
libafl_qemu_set_native_breakpoint(0x4be0);
int64_t tmp = libafl_get_clock();
printf("snapshot icount: %ld, %ldns\n",tmp,icount_to_ns(tmp));
libafl_snapshot_load("Start");
tmp = libafl_get_clock();
printf("snapshot icount after load: %ld, %ldns\n",tmp,icount_to_ns(tmp));
libafl_phys_write(0x20000110-0x20000100+pheader, buf,32);
libafl_qemu_main_loop();
printf("%ld für %s\n",libafl_get_clock(),buf);
libafl_snapshot_load("Start");
libafl_phys_write(0x20000110-0x20000100+pheader, buf2,32);
libafl_qemu_main_loop();
printf("%ld für %s\n",libafl_get_clock(),buf2);
libafl_snapshot_load("Start");
libafl_phys_write(0x20000110-0x20000100+pheader, buf3,32);
libafl_qemu_main_loop();
printf("%ld für %s\n",libafl_get_clock(),buf3);
libafl_snapshot_load("Start");
/*int counter = 3000;
do {
libafl_phys_write(0x20000110-0x20000100+pheader, buf,32);
libafl_qemu_main_loop();
int64_t tmp = libafl_get_clock();
printf("%ld, %ldns\n",tmp,icount_to_ns(tmp));
libafl_snapshot_load("Start");
// puts("Reload has occured");
counter--;
} while (counter);*/
libafl_qemu_cleanup();
return 0;
}

View File

@ -41,7 +41,3 @@ config PVRDMA
config MULTIPROCESS_ALLOWED config MULTIPROCESS_ALLOWED
bool bool
imply MULTIPROCESS imply MULTIPROCESS
config FUZZ
bool
select SPARSE_MEM

View File

@ -109,12 +109,6 @@ K: ^Subject:.*(?i)s390x?
T: git https://gitlab.com/cohuck/qemu.git s390-next T: git https://gitlab.com/cohuck/qemu.git s390-next
L: qemu-s390x@nongnu.org L: qemu-s390x@nongnu.org
MIPS general architecture support
M: Philippe Mathieu-Daudé <f4bug@amsat.org>
R: Jiaxun Yang <jiaxun.yang@flygoat.com>
S: Odd Fixes
K: ^Subject:.*(?i)mips
Guest CPU cores (TCG) Guest CPU cores (TCG)
--------------------- ---------------------
Overall TCG CPUs Overall TCG CPUs
@ -177,7 +171,7 @@ L: qemu-arm@nongnu.org
S: Maintained S: Maintained
F: hw/arm/smmu* F: hw/arm/smmu*
F: include/hw/arm/smmu* F: include/hw/arm/smmu*
F: tests/avocado/smmu.py F: tests/acceptance/smmu.py
AVR TCG CPUs AVR TCG CPUs
M: Michael Rolnik <mrolnik@gmail.com> M: Michael Rolnik <mrolnik@gmail.com>
@ -185,7 +179,7 @@ S: Maintained
F: docs/system/target-avr.rst F: docs/system/target-avr.rst
F: gdb-xml/avr-cpu.xml F: gdb-xml/avr-cpu.xml
F: target/avr/ F: target/avr/
F: tests/avocado/machine_avr6.py F: tests/acceptance/machine_avr6.py
CRIS TCG CPUs CRIS TCG CPUs
M: Edgar E. Iglesias <edgar.iglesias@gmail.com> M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
@ -211,7 +205,10 @@ HPPA (PA-RISC) TCG CPUs
M: Richard Henderson <richard.henderson@linaro.org> M: Richard Henderson <richard.henderson@linaro.org>
S: Maintained S: Maintained
F: target/hppa/ F: target/hppa/
F: hw/hppa/
F: disas/hppa.c F: disas/hppa.c
F: hw/net/*i82596*
F: include/hw/net/lasi_82596.h
M68K TCG CPUs M68K TCG CPUs
M: Laurent Vivier <laurent@vivier.eu> M: Laurent Vivier <laurent@vivier.eu>
@ -225,8 +222,6 @@ S: Maintained
F: target/microblaze/ F: target/microblaze/
F: hw/microblaze/ F: hw/microblaze/
F: disas/microblaze.c F: disas/microblaze.c
F: tests/docker/dockerfiles/debian-microblaze-cross.d/build-toolchain.sh
F: tests/tcg/nios2/Makefile.target
MIPS TCG CPUs MIPS TCG CPUs
M: Philippe Mathieu-Daudé <f4bug@amsat.org> M: Philippe Mathieu-Daudé <f4bug@amsat.org>
@ -235,9 +230,19 @@ R: Jiaxun Yang <jiaxun.yang@flygoat.com>
R: Aleksandar Rikalo <aleksandar.rikalo@syrmia.com> R: Aleksandar Rikalo <aleksandar.rikalo@syrmia.com>
S: Odd Fixes S: Odd Fixes
F: target/mips/ F: target/mips/
F: configs/devices/mips*/*
F: disas/mips.c F: disas/mips.c
F: docs/system/cpu-models-mips.rst.inc F: docs/system/cpu-models-mips.rst.inc
F: hw/intc/mips_gic.c
F: hw/mips/
F: hw/misc/mips_*
F: hw/timer/mips_gictimer.c
F: include/hw/intc/mips_gic.h
F: include/hw/mips/
F: include/hw/misc/mips_*
F: include/hw/timer/mips_gictimer.h
F: tests/tcg/mips/ F: tests/tcg/mips/
K: ^Subject:.*(?i)mips
MIPS TCG CPUs (nanoMIPS ISA) MIPS TCG CPUs (nanoMIPS ISA)
S: Orphan S: Orphan
@ -252,7 +257,6 @@ F: target/nios2/
F: hw/nios2/ F: hw/nios2/
F: disas/nios2.c F: disas/nios2.c
F: configs/devices/nios2-softmmu/default.mak F: configs/devices/nios2-softmmu/default.mak
F: tests/docker/dockerfiles/debian-nios2-cross.d/build-toolchain.sh
OpenRISC TCG CPUs OpenRISC TCG CPUs
M: Stafford Horne <shorne@gmail.com> M: Stafford Horne <shorne@gmail.com>
@ -262,17 +266,15 @@ F: hw/openrisc/
F: tests/tcg/openrisc/ F: tests/tcg/openrisc/
PowerPC TCG CPUs PowerPC TCG CPUs
M: Cédric Le Goater <clg@kaod.org> M: David Gibson <david@gibson.dropbear.id.au>
M: Daniel Henrique Barboza <danielhb413@gmail.com> M: Greg Kurz <groug@kaod.org>
R: David Gibson <david@gibson.dropbear.id.au>
R: Greg Kurz <groug@kaod.org>
L: qemu-ppc@nongnu.org L: qemu-ppc@nongnu.org
S: Maintained S: Maintained
F: target/ppc/ F: target/ppc/
F: hw/ppc/ppc.c F: hw/ppc/
F: hw/ppc/ppc_booke.c F: include/hw/ppc/
F: include/hw/ppc/ppc.h
F: disas/ppc.c F: disas/ppc.c
F: tests/acceptance/machine_ppc.py
RISC-V TCG CPUs RISC-V TCG CPUs
M: Palmer Dabbelt <palmer@dabbelt.com> M: Palmer Dabbelt <palmer@dabbelt.com>
@ -324,7 +326,7 @@ F: disas/sparc.c
X86 TCG CPUs X86 TCG CPUs
M: Paolo Bonzini <pbonzini@redhat.com> M: Paolo Bonzini <pbonzini@redhat.com>
M: Richard Henderson <richard.henderson@linaro.org> M: Richard Henderson <richard.henderson@linaro.org>
M: Eduardo Habkost <eduardo@habkost.net> M: Eduardo Habkost <ehabkost@redhat.com>
S: Maintained S: Maintained
F: target/i386/tcg/ F: target/i386/tcg/
F: tests/tcg/i386/ F: tests/tcg/i386/
@ -384,15 +386,14 @@ F: target/mips/kvm*
F: target/mips/sysemu/ F: target/mips/sysemu/
PPC KVM CPUs PPC KVM CPUs
M: Cédric Le Goater <clg@kaod.org> M: David Gibson <david@gibson.dropbear.id.au>
M: Daniel Henrique Barboza <danielhb413@gmail.com> M: Greg Kurz <groug@kaod.org>
R: David Gibson <david@gibson.dropbear.id.au>
R: Greg Kurz <groug@kaod.org>
S: Maintained S: Maintained
F: target/ppc/kvm.c F: target/ppc/kvm.c
S390 KVM CPUs S390 KVM CPUs
M: Halil Pasic <pasic@linux.ibm.com> M: Halil Pasic <pasic@linux.ibm.com>
M: Cornelia Huck <cohuck@redhat.com>
M: Christian Borntraeger <borntraeger@de.ibm.com> M: Christian Borntraeger <borntraeger@de.ibm.com>
S: Supported S: Supported
F: target/s390x/kvm/ F: target/s390x/kvm/
@ -407,6 +408,7 @@ F: hw/intc/s390_flic.c
F: hw/intc/s390_flic_kvm.c F: hw/intc/s390_flic_kvm.c
F: include/hw/s390x/s390_flic.h F: include/hw/s390x/s390_flic.h
F: gdb-xml/s390*.xml F: gdb-xml/s390*.xml
T: git https://gitlab.com/cohuck/qemu.git s390-next
T: git https://github.com/borntraeger/qemu.git s390-next T: git https://github.com/borntraeger/qemu.git s390-next
L: qemu-s390x@nongnu.org L: qemu-s390x@nongnu.org
@ -415,10 +417,7 @@ M: Paolo Bonzini <pbonzini@redhat.com>
M: Marcelo Tosatti <mtosatti@redhat.com> M: Marcelo Tosatti <mtosatti@redhat.com>
L: kvm@vger.kernel.org L: kvm@vger.kernel.org
S: Supported S: Supported
F: docs/amd-memory-encryption.txt
F: docs/system/i386/sgx.rst
F: target/i386/kvm/ F: target/i386/kvm/
F: target/i386/sev*
F: scripts/kvm/vmxcap F: scripts/kvm/vmxcap
Guest CPU Cores (other accelerators) Guest CPU Cores (other accelerators)
@ -434,11 +433,6 @@ F: accel/accel-*.c
F: accel/Makefile.objs F: accel/Makefile.objs
F: accel/stubs/Makefile.objs F: accel/stubs/Makefile.objs
Apple Silicon HVF CPUs
M: Alexander Graf <agraf@csgraf.de>
S: Maintained
F: target/arm/hvf/
X86 HVF CPUs X86 HVF CPUs
M: Cameron Esfahani <dirty@apple.com> M: Cameron Esfahani <dirty@apple.com>
M: Roman Bolshakov <r.bolshakov@yadro.com> M: Roman Bolshakov <r.bolshakov@yadro.com>
@ -623,7 +617,6 @@ F: hw/intc/gic_internal.h
F: hw/misc/a9scu.c F: hw/misc/a9scu.c
F: hw/misc/arm11scu.c F: hw/misc/arm11scu.c
F: hw/misc/arm_l2x0.c F: hw/misc/arm_l2x0.c
F: hw/misc/armv7m_ras.c
F: hw/timer/a9gtimer* F: hw/timer/a9gtimer*
F: hw/timer/arm* F: hw/timer/arm*
F: include/hw/arm/arm*.h F: include/hw/arm/arm*.h
@ -633,7 +626,6 @@ F: include/hw/misc/arm11scu.h
F: include/hw/timer/a9gtimer.h F: include/hw/timer/a9gtimer.h
F: include/hw/timer/arm_mptimer.h F: include/hw/timer/arm_mptimer.h
F: include/hw/timer/armv7m_systick.h F: include/hw/timer/armv7m_systick.h
F: include/hw/misc/armv7m_ras.h
F: tests/qtest/test-arm-mptimer.c F: tests/qtest/test-arm-mptimer.c
Exynos Exynos
@ -661,7 +653,7 @@ S: Odd Fixes
F: include/hw/arm/digic.h F: include/hw/arm/digic.h
F: hw/*/digic* F: hw/*/digic*
F: include/hw/*/digic* F: include/hw/*/digic*
F: tests/avocado/machine_arm_canona1100.py F: tests/acceptance/machine_arm_canona1100.py
F: docs/system/arm/digic.rst F: docs/system/arm/digic.rst
Goldfish RTC Goldfish RTC
@ -712,7 +704,7 @@ S: Maintained
F: hw/arm/integratorcp.c F: hw/arm/integratorcp.c
F: hw/misc/arm_integrator_debug.c F: hw/misc/arm_integrator_debug.c
F: include/hw/misc/arm_integrator_debug.h F: include/hw/misc/arm_integrator_debug.h
F: tests/avocado/machine_arm_integratorcp.py F: tests/acceptance/machine_arm_integratorcp.py
F: docs/system/arm/integratorcp.rst F: docs/system/arm/integratorcp.rst
MCIMX6UL EVK / i.MX6ul MCIMX6UL EVK / i.MX6ul
@ -809,7 +801,7 @@ F: include/hw/display/blizzard.h
F: include/hw/input/lm832x.h F: include/hw/input/lm832x.h
F: include/hw/input/tsc2xxx.h F: include/hw/input/tsc2xxx.h
F: include/hw/misc/cbus.h F: include/hw/misc/cbus.h
F: tests/avocado/machine_arm_n8x0.py F: tests/acceptance/machine_arm_n8x0.py
F: docs/system/arm/nseries.rst F: docs/system/arm/nseries.rst
Palm Palm
@ -1099,8 +1091,6 @@ R: Helge Deller <deller@gmx.de>
S: Odd Fixes S: Odd Fixes
F: configs/devices/hppa-softmmu/default.mak F: configs/devices/hppa-softmmu/default.mak
F: hw/hppa/ F: hw/hppa/
F: hw/net/*i82596*
F: include/hw/net/lasi_82596.h
F: pc-bios/hppa-firmware.img F: pc-bios/hppa-firmware.img
M68K Machines M68K Machines
@ -1163,7 +1153,7 @@ M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
S: Maintained S: Maintained
F: hw/microblaze/petalogix_s3adsp1800_mmu.c F: hw/microblaze/petalogix_s3adsp1800_mmu.c
F: include/hw/char/xilinx_uartlite.h F: include/hw/char/xilinx_uartlite.h
F: tests/avocado/machine_microblaze.py F: tests/acceptance/machine_microblaze.py
petalogix_ml605 petalogix_ml605
M: Edgar E. Iglesias <edgar.iglesias@gmail.com> M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
@ -1172,13 +1162,6 @@ F: hw/microblaze/petalogix_ml605_mmu.c
MIPS Machines MIPS Machines
------------- -------------
Overall MIPS Machines
M: Philippe Mathieu-Daudé <f4bug@amsat.org>
S: Odd Fixes
F: configs/devices/mips*/*
F: hw/mips/
F: include/hw/mips/
Jazz Jazz
M: Hervé Poussineau <hpoussin@reactos.org> M: Hervé Poussineau <hpoussin@reactos.org>
R: Aleksandar Rikalo <aleksandar.rikalo@syrmia.com> R: Aleksandar Rikalo <aleksandar.rikalo@syrmia.com>
@ -1196,8 +1179,8 @@ F: hw/acpi/piix4.c
F: hw/mips/malta.c F: hw/mips/malta.c
F: hw/mips/gt64xxx_pci.c F: hw/mips/gt64xxx_pci.c
F: include/hw/southbridge/piix.h F: include/hw/southbridge/piix.h
F: tests/avocado/linux_ssh_mips_malta.py F: tests/acceptance/linux_ssh_mips_malta.py
F: tests/avocado/machine_mips_malta.py F: tests/acceptance/machine_mips_malta.py
Mipssim Mipssim
R: Aleksandar Rikalo <aleksandar.rikalo@syrmia.com> R: Aleksandar Rikalo <aleksandar.rikalo@syrmia.com>
@ -1215,7 +1198,7 @@ F: hw/isa/vt82c686.c
F: hw/pci-host/bonito.c F: hw/pci-host/bonito.c
F: hw/usb/vt82c686-uhci-pci.c F: hw/usb/vt82c686-uhci-pci.c
F: include/hw/isa/vt82c686.h F: include/hw/isa/vt82c686.h
F: tests/avocado/machine_mips_fuloong2e.py F: tests/acceptance/machine_mips_fuloong2e.py
Loongson-3 virtual platforms Loongson-3 virtual platforms
M: Huacai Chen <chenhuacai@kernel.org> M: Huacai Chen <chenhuacai@kernel.org>
@ -1225,7 +1208,7 @@ F: hw/intc/loongson_liointc.c
F: hw/mips/loongson3_bootp.c F: hw/mips/loongson3_bootp.c
F: hw/mips/loongson3_bootp.h F: hw/mips/loongson3_bootp.h
F: hw/mips/loongson3_virt.c F: hw/mips/loongson3_virt.c
F: tests/avocado/machine_mips_loongson3v.py F: tests/acceptance/machine_mips_loongson3v.py
Boston Boston
M: Paul Burton <paulburton@kernel.org> M: Paul Burton <paulburton@kernel.org>
@ -1246,19 +1229,24 @@ F: hw/openrisc/openrisc_sim.c
PowerPC Machines PowerPC Machines
---------------- ----------------
405 405
M: David Gibson <david@gibson.dropbear.id.au>
M: Greg Kurz <groug@kaod.org>
L: qemu-ppc@nongnu.org L: qemu-ppc@nongnu.org
S: Orphan S: Odd Fixes
F: hw/ppc/ppc405_boards.c F: hw/ppc/ppc405_boards.c
Bamboo Bamboo
M: David Gibson <david@gibson.dropbear.id.au>
M: Greg Kurz <groug@kaod.org>
L: qemu-ppc@nongnu.org L: qemu-ppc@nongnu.org
S: Orphan S: Odd Fixes
F: hw/ppc/ppc440_bamboo.c F: hw/ppc/ppc440_bamboo.c
F: tests/avocado/ppc_bamboo.py
e500 e500
M: David Gibson <david@gibson.dropbear.id.au>
M: Greg Kurz <groug@kaod.org>
L: qemu-ppc@nongnu.org L: qemu-ppc@nongnu.org
S: Orphan S: Odd Fixes
F: hw/ppc/e500* F: hw/ppc/e500*
F: hw/gpio/mpc8xxx.c F: hw/gpio/mpc8xxx.c
F: hw/i2c/mpc_i2c.c F: hw/i2c/mpc_i2c.c
@ -1267,18 +1255,19 @@ F: hw/pci-host/ppce500.c
F: include/hw/ppc/ppc_e500.h F: include/hw/ppc/ppc_e500.h
F: include/hw/pci-host/ppce500.h F: include/hw/pci-host/ppce500.h
F: pc-bios/u-boot.e500 F: pc-bios/u-boot.e500
F: hw/intc/openpic_kvm.h
F: include/hw/ppc/openpic_kvm.h
mpc8544ds mpc8544ds
M: David Gibson <david@gibson.dropbear.id.au>
M: Greg Kurz <groug@kaod.org>
L: qemu-ppc@nongnu.org L: qemu-ppc@nongnu.org
S: Orphan S: Odd Fixes
F: hw/ppc/mpc8544ds.c F: hw/ppc/mpc8544ds.c
F: hw/ppc/mpc8544_guts.c F: hw/ppc/mpc8544_guts.c
F: tests/avocado/ppc_mpc8544ds.py
New World (mac99) New World (mac99)
M: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> M: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
R: David Gibson <david@gibson.dropbear.id.au>
R: Greg Kurz <groug@kaod.org>
L: qemu-ppc@nongnu.org L: qemu-ppc@nongnu.org
S: Odd Fixes S: Odd Fixes
F: hw/ppc/mac_newworld.c F: hw/ppc/mac_newworld.c
@ -1297,6 +1286,8 @@ F: pc-bios/qemu_vga.ndrv
Old World (g3beige) Old World (g3beige)
M: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> M: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
R: David Gibson <david@gibson.dropbear.id.au>
R: Greg Kurz <groug@kaod.org>
L: qemu-ppc@nongnu.org L: qemu-ppc@nongnu.org
S: Odd Fixes S: Odd Fixes
F: hw/ppc/mac_oldworld.c F: hw/ppc/mac_oldworld.c
@ -1310,6 +1301,8 @@ F: pc-bios/qemu_vga.ndrv
PReP PReP
M: Hervé Poussineau <hpoussin@reactos.org> M: Hervé Poussineau <hpoussin@reactos.org>
R: David Gibson <david@gibson.dropbear.id.au>
R: Greg Kurz <groug@kaod.org>
L: qemu-ppc@nongnu.org L: qemu-ppc@nongnu.org
S: Maintained S: Maintained
F: hw/ppc/prep.c F: hw/ppc/prep.c
@ -1322,15 +1315,13 @@ F: hw/dma/i82374.c
F: hw/rtc/m48t59-isa.c F: hw/rtc/m48t59-isa.c
F: include/hw/isa/pc87312.h F: include/hw/isa/pc87312.h
F: include/hw/rtc/m48t59.h F: include/hw/rtc/m48t59.h
F: tests/avocado/ppc_prep_40p.py F: tests/acceptance/ppc_prep_40p.py
sPAPR sPAPR
M: Cédric Le Goater <clg@kaod.org> M: David Gibson <david@gibson.dropbear.id.au>
M: Daniel Henrique Barboza <danielhb413@gmail.com> M: Greg Kurz <groug@kaod.org>
R: David Gibson <david@gibson.dropbear.id.au>
R: Greg Kurz <groug@kaod.org>
L: qemu-ppc@nongnu.org L: qemu-ppc@nongnu.org
S: Maintained S: Supported
F: hw/*/spapr* F: hw/*/spapr*
F: include/hw/*/spapr* F: include/hw/*/spapr*
F: hw/*/xics* F: hw/*/xics*
@ -1342,10 +1333,11 @@ F: tests/qtest/spapr*
F: tests/qtest/libqos/*spapr* F: tests/qtest/libqos/*spapr*
F: tests/qtest/rtas* F: tests/qtest/rtas*
F: tests/qtest/libqos/rtas* F: tests/qtest/libqos/rtas*
F: tests/avocado/ppc_pseries.py
PowerNV (Non-Virtualized) PowerNV (Non-Virtualized)
M: Cédric Le Goater <clg@kaod.org> M: Cédric Le Goater <clg@kaod.org>
M: David Gibson <david@gibson.dropbear.id.au>
M: Greg Kurz <groug@kaod.org>
L: qemu-ppc@nongnu.org L: qemu-ppc@nongnu.org
S: Maintained S: Maintained
F: hw/ppc/pnv* F: hw/ppc/pnv*
@ -1362,10 +1354,11 @@ M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
L: qemu-ppc@nongnu.org L: qemu-ppc@nongnu.org
S: Odd Fixes S: Odd Fixes
F: hw/ppc/virtex_ml507.c F: hw/ppc/virtex_ml507.c
F: tests/avocado/ppc_virtex_ml507.py
sam460ex sam460ex
M: BALATON Zoltan <balaton@eik.bme.hu> M: BALATON Zoltan <balaton@eik.bme.hu>
R: David Gibson <david@gibson.dropbear.id.au>
R: Greg Kurz <groug@kaod.org>
L: qemu-ppc@nongnu.org L: qemu-ppc@nongnu.org
S: Maintained S: Maintained
F: hw/ppc/sam460ex.c F: hw/ppc/sam460ex.c
@ -1379,6 +1372,7 @@ F: roms/u-boot-sam460ex
pegasos2 pegasos2
M: BALATON Zoltan <balaton@eik.bme.hu> M: BALATON Zoltan <balaton@eik.bme.hu>
R: David Gibson <david@gibson.dropbear.id.au>
L: qemu-ppc@nongnu.org L: qemu-ppc@nongnu.org
S: Maintained S: Maintained
F: hw/ppc/pegasos2.c F: hw/ppc/pegasos2.c
@ -1388,8 +1382,6 @@ F: include/hw/pci-host/mv64361.h
Virtual Open Firmware (VOF) Virtual Open Firmware (VOF)
M: Alexey Kardashevskiy <aik@ozlabs.ru> M: Alexey Kardashevskiy <aik@ozlabs.ru>
R: Cédric Le Goater <clg@kaod.org>
R: Daniel Henrique Barboza <danielhb413@gmail.com>
R: David Gibson <david@gibson.dropbear.id.au> R: David Gibson <david@gibson.dropbear.id.au>
R: Greg Kurz <groug@kaod.org> R: Greg Kurz <groug@kaod.org>
L: qemu-ppc@nongnu.org L: qemu-ppc@nongnu.org
@ -1451,7 +1443,7 @@ R: Yoshinori Sato <ysato@users.sourceforge.jp>
S: Orphan S: Orphan
F: docs/system/target-rx.rst F: docs/system/target-rx.rst
F: hw/rx/rx-gdbsim.c F: hw/rx/rx-gdbsim.c
F: tests/avocado/machine_rx_gdbsim.py F: tests/acceptance/machine_rx_gdbsim.py
SH4 Machines SH4 Machines
------------ ------------
@ -1505,7 +1497,7 @@ F: include/hw/pci-host/sabre.h
F: hw/pci-bridge/simba.c F: hw/pci-bridge/simba.c
F: include/hw/pci-bridge/simba.h F: include/hw/pci-bridge/simba.h
F: pc-bios/openbios-sparc64 F: pc-bios/openbios-sparc64
F: tests/avocado/machine_sparc64_sun4u.py F: tests/acceptance/machine_sparc64_sun4u.py
Sun4v Sun4v
M: Artyom Tarasenko <atar4qemu@gmail.com> M: Artyom Tarasenko <atar4qemu@gmail.com>
@ -1521,11 +1513,12 @@ S: Maintained
F: hw/sparc/leon3.c F: hw/sparc/leon3.c
F: hw/*/grlib* F: hw/*/grlib*
F: include/hw/*/grlib* F: include/hw/*/grlib*
F: tests/avocado/machine_sparc_leon3.py F: tests/acceptance/machine_sparc_leon3.py
S390 Machines S390 Machines
------------- -------------
S390 Virtio-ccw S390 Virtio-ccw
M: Cornelia Huck <cohuck@redhat.com>
M: Halil Pasic <pasic@linux.ibm.com> M: Halil Pasic <pasic@linux.ibm.com>
M: Christian Borntraeger <borntraeger@de.ibm.com> M: Christian Borntraeger <borntraeger@de.ibm.com>
S: Supported S: Supported
@ -1536,7 +1529,8 @@ F: include/hw/s390x/
F: hw/watchdog/wdt_diag288.c F: hw/watchdog/wdt_diag288.c
F: include/hw/watchdog/wdt_diag288.h F: include/hw/watchdog/wdt_diag288.h
F: configs/devices/s390x-softmmu/default.mak F: configs/devices/s390x-softmmu/default.mak
F: tests/avocado/machine_s390_ccw_virtio.py F: tests/acceptance/machine_s390_ccw_virtio.py
T: git https://gitlab.com/cohuck/qemu.git s390-next
T: git https://github.com/borntraeger/qemu.git s390-next T: git https://github.com/borntraeger/qemu.git s390-next
L: qemu-s390x@nongnu.org L: qemu-s390x@nongnu.org
@ -1622,21 +1616,19 @@ microvm
M: Sergio Lopez <slp@redhat.com> M: Sergio Lopez <slp@redhat.com>
M: Paolo Bonzini <pbonzini@redhat.com> M: Paolo Bonzini <pbonzini@redhat.com>
S: Maintained S: Maintained
F: docs/system/i386/microvm.rst F: docs/microvm.rst
F: hw/i386/microvm.c F: hw/i386/microvm.c
F: include/hw/i386/microvm.h F: include/hw/i386/microvm.h
F: pc-bios/bios-microvm.bin F: pc-bios/bios-microvm.bin
Machine core Machine core
M: Eduardo Habkost <eduardo@habkost.net> M: Eduardo Habkost <ehabkost@redhat.com>
M: Marcel Apfelbaum <marcel.apfelbaum@gmail.com> M: Marcel Apfelbaum <marcel.apfelbaum@gmail.com>
R: Philippe Mathieu-Daudé <philmd@redhat.com>
S: Supported S: Supported
F: cpu.c F: cpu.c
F: hw/core/cpu.c F: hw/core/cpu.c
F: hw/core/machine-qmp-cmds.c F: hw/core/machine-qmp-cmds.c
F: hw/core/machine.c F: hw/core/machine.c
F: hw/core/machine-smp.c
F: hw/core/null-machine.c F: hw/core/null-machine.c
F: hw/core/numa.c F: hw/core/numa.c
F: hw/cpu/cluster.c F: hw/cpu/cluster.c
@ -1646,7 +1638,6 @@ F: include/hw/boards.h
F: include/hw/core/cpu.h F: include/hw/core/cpu.h
F: include/hw/cpu/cluster.h F: include/hw/cpu/cluster.h
F: include/sysemu/numa.h F: include/sysemu/numa.h
F: tests/unit/test-smp-parse.c
T: git https://gitlab.com/ehabkost/qemu.git machine-next T: git https://gitlab.com/ehabkost/qemu.git machine-next
Xtensa Machines Xtensa Machines
@ -1669,16 +1660,6 @@ F: hw/net/opencores_eth.c
Devices Devices
------- -------
Overall Audio frontends
M: Gerd Hoffmann <kraxel@redhat.com>
S: Odd Fixes
F: hw/audio/
F: include/hw/audio/
F: tests/qtest/ac97-test.c
F: tests/qtest/es1370-test.c
F: tests/qtest/intel-hda-test.c
F: tests/qtest/fuzz-sb16-test.c
Xilinx CAN Xilinx CAN
M: Vikram Garhwal <fnu.vikram@xilinx.com> M: Vikram Garhwal <fnu.vikram@xilinx.com>
M: Francisco Iglesias <francisco.iglesias@xilinx.com> M: Francisco Iglesias <francisco.iglesias@xilinx.com>
@ -1758,7 +1739,6 @@ F: docs/specs/*pci*
ACPI/SMBIOS ACPI/SMBIOS
M: Michael S. Tsirkin <mst@redhat.com> M: Michael S. Tsirkin <mst@redhat.com>
M: Igor Mammedov <imammedo@redhat.com> M: Igor Mammedov <imammedo@redhat.com>
R: Ani Sinha <ani@anisinha.ca>
S: Supported S: Supported
F: include/hw/acpi/* F: include/hw/acpi/*
F: include/hw/firmware/smbios.h F: include/hw/firmware/smbios.h
@ -1771,10 +1751,6 @@ F: qapi/acpi.json
F: tests/qtest/bios-tables-test* F: tests/qtest/bios-tables-test*
F: tests/qtest/acpi-utils.[hc] F: tests/qtest/acpi-utils.[hc]
F: tests/data/acpi/ F: tests/data/acpi/
F: docs/specs/acpi_cpu_hotplug.rst
F: docs/specs/acpi_mem_hotplug.rst
F: docs/specs/acpi_pci_hotplug.rst
F: docs/specs/acpi_hw_reduced_hotplug.rst
ACPI/HEST/GHES ACPI/HEST/GHES
R: Dongjiu Geng <gengdongjiu1@gmail.com> R: Dongjiu Geng <gengdongjiu1@gmail.com>
@ -1785,8 +1761,9 @@ F: include/hw/acpi/ghes.h
F: docs/specs/acpi_hest_ghes.rst F: docs/specs/acpi_hest_ghes.rst
ppc4xx ppc4xx
M: David Gibson <david@gibson.dropbear.id.au>
L: qemu-ppc@nongnu.org L: qemu-ppc@nongnu.org
S: Orphan S: Odd Fixes
F: hw/ppc/ppc4*.c F: hw/ppc/ppc4*.c
F: hw/i2c/ppc4xx_i2c.c F: hw/i2c/ppc4xx_i2c.c
F: include/hw/ppc/ppc4xx.h F: include/hw/ppc/ppc4xx.h
@ -1878,6 +1855,7 @@ F: docs/igd-assign.txt
F: docs/devel/vfio-migration.rst F: docs/devel/vfio-migration.rst
vfio-ccw vfio-ccw
M: Cornelia Huck <cohuck@redhat.com>
M: Eric Farman <farman@linux.ibm.com> M: Eric Farman <farman@linux.ibm.com>
M: Matthew Rosato <mjrosato@linux.ibm.com> M: Matthew Rosato <mjrosato@linux.ibm.com>
S: Supported S: Supported
@ -1885,6 +1863,7 @@ F: hw/vfio/ccw.c
F: hw/s390x/s390-ccw.c F: hw/s390x/s390-ccw.c
F: include/hw/s390x/s390-ccw.h F: include/hw/s390x/s390-ccw.h
F: include/hw/s390x/vfio-ccw.h F: include/hw/s390x/vfio-ccw.h
T: git https://gitlab.com/cohuck/qemu.git s390-next
L: qemu-s390x@nongnu.org L: qemu-s390x@nongnu.org
vfio-ap vfio-ap
@ -2078,7 +2057,6 @@ F: hw/acpi/nvdimm.c
F: hw/mem/nvdimm.c F: hw/mem/nvdimm.c
F: include/hw/mem/nvdimm.h F: include/hw/mem/nvdimm.h
F: docs/nvdimm.txt F: docs/nvdimm.txt
F: docs/specs/acpi_nvdimm.rst
e1000x e1000x
M: Dmitry Fleytman <dmitry.fleytman@gmail.com> M: Dmitry Fleytman <dmitry.fleytman@gmail.com>
@ -2120,7 +2098,7 @@ M: Alex Bennée <alex.bennee@linaro.org>
S: Maintained S: Maintained
F: hw/core/guest-loader.c F: hw/core/guest-loader.c
F: docs/system/guest-loader.rst F: docs/system/guest-loader.rst
F: tests/avocado/boot_xen.py F: tests/acceptance/boot_xen.py
Intel Hexadecimal Object File Loader Intel Hexadecimal Object File Loader
M: Su Hang <suhang16@mails.ucas.ac.cn> M: Su Hang <suhang16@mails.ucas.ac.cn>
@ -2239,6 +2217,8 @@ T: git https://github.com/philmd/qemu.git fw_cfg-next
XIVE XIVE
M: Cédric Le Goater <clg@kaod.org> M: Cédric Le Goater <clg@kaod.org>
R: David Gibson <david@gibson.dropbear.id.au>
R: Greg Kurz <groug@kaod.org>
L: qemu-ppc@nongnu.org L: qemu-ppc@nongnu.org
S: Supported S: Supported
F: hw/*/*xive* F: hw/*/*xive*
@ -2274,80 +2254,19 @@ F: net/can/*
F: hw/net/can/* F: hw/net/can/*
F: include/net/can_*.h F: include/net/can_*.h
OpenPIC interrupt controller
M: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
S: Odd Fixes
F: hw/intc/openpic.c
F: include/hw/ppc/openpic.h
MIPS CPS
M: Philippe Mathieu-Daudé <f4bug@amsat.org>
S: Odd Fixes
F: hw/misc/mips_*
F: include/hw/misc/mips_*
MIPS GIC
M: Philippe Mathieu-Daudé <f4bug@amsat.org>
S: Odd Fixes
F: hw/intc/mips_gic.c
F: hw/timer/mips_gictimer.c
F: include/hw/intc/mips_gic.h
F: include/hw/timer/mips_gictimer.h
Subsystems Subsystems
---------- ----------
Overall Audio backends Audio
M: Gerd Hoffmann <kraxel@redhat.com> M: Gerd Hoffmann <kraxel@redhat.com>
S: Odd Fixes S: Odd Fixes
F: audio/ F: audio/
X: audio/alsaaudio.c F: hw/audio/
X: audio/coreaudio.c F: include/hw/audio/
X: audio/dsound*
X: audio/jackaudio.c
X: audio/ossaudio.c
X: audio/paaudio.c
X: audio/sdlaudio.c
X: audio/spiceaudio.c
F: qapi/audio.json F: qapi/audio.json
F: tests/qtest/ac97-test.c
ALSA Audio backend F: tests/qtest/es1370-test.c
M: Gerd Hoffmann <kraxel@redhat.com> F: tests/qtest/intel-hda-test.c
R: Christian Schoenebeck <qemu_oss@crudebyte.com> F: tests/qtest/fuzz-sb16-test.c
S: Odd Fixes
F: audio/alsaaudio.c
Core Audio framework backend
M: Gerd Hoffmann <kraxel@redhat.com>
R: Christian Schoenebeck <qemu_oss@crudebyte.com>
S: Odd Fixes
F: audio/coreaudio.c
DSound Audio backend
M: Gerd Hoffmann <kraxel@redhat.com>
S: Odd Fixes
F: audio/dsound*
JACK Audio Connection Kit backend
M: Gerd Hoffmann <kraxel@redhat.com>
R: Christian Schoenebeck <qemu_oss@crudebyte.com>
S: Odd Fixes
F: audio/jackaudio.c
Open Sound System (OSS) Audio backend
M: Gerd Hoffmann <kraxel@redhat.com>
S: Odd Fixes
F: audio/ossaudio.c
PulseAudio backend
M: Gerd Hoffmann <kraxel@redhat.com>
S: Odd Fixes
F: audio/paaudio.c
SDL Audio backend
M: Gerd Hoffmann <kraxel@redhat.com>
R: Thomas Huth <huth@tuxfamily.org>
S: Odd Fixes
F: audio/sdlaudio.c
Block layer core Block layer core
M: Kevin Wolf <kwolf@redhat.com> M: Kevin Wolf <kwolf@redhat.com>
@ -2418,8 +2337,8 @@ F: block/mirror.c
F: qapi/job.json F: qapi/job.json
F: block/block-copy.c F: block/block-copy.c
F: include/block/block-copy.c F: include/block/block-copy.c
F: block/copy-before-write.h F: block/backup-top.h
F: block/copy-before-write.c F: block/backup-top.c
F: include/block/aio_task.h F: include/block/aio_task.h
F: block/aio_task.c F: block/aio_task.c
F: util/qemu-co-shared-resource.c F: util/qemu-co-shared-resource.c
@ -2534,7 +2453,6 @@ Memory API
M: Paolo Bonzini <pbonzini@redhat.com> M: Paolo Bonzini <pbonzini@redhat.com>
M: Peter Xu <peterx@redhat.com> M: Peter Xu <peterx@redhat.com>
M: David Hildenbrand <david@redhat.com> M: David Hildenbrand <david@redhat.com>
R: Philippe Mathieu-Daudé <philmd@redhat.com>
S: Supported S: Supported
F: include/exec/ioport.h F: include/exec/ioport.h
F: include/exec/memop.h F: include/exec/memop.h
@ -2648,13 +2566,13 @@ F: backends/cryptodev*.c
Python library Python library
M: John Snow <jsnow@redhat.com> M: John Snow <jsnow@redhat.com>
M: Cleber Rosa <crosa@redhat.com> M: Cleber Rosa <crosa@redhat.com>
R: Eduardo Habkost <eduardo@habkost.net> R: Eduardo Habkost <ehabkost@redhat.com>
S: Maintained S: Maintained
F: python/ F: python/
T: git https://gitlab.com/jsnow/qemu.git python T: git https://gitlab.com/jsnow/qemu.git python
Python scripts Python scripts
M: Eduardo Habkost <eduardo@habkost.net> M: Eduardo Habkost <ehabkost@redhat.com>
M: Cleber Rosa <crosa@redhat.com> M: Cleber Rosa <crosa@redhat.com>
S: Odd Fixes S: Odd Fixes
F: scripts/*.py F: scripts/*.py
@ -2730,7 +2648,7 @@ T: git https://github.com/mdroth/qemu.git qga
QOM QOM
M: Paolo Bonzini <pbonzini@redhat.com> M: Paolo Bonzini <pbonzini@redhat.com>
R: Daniel P. Berrange <berrange@redhat.com> R: Daniel P. Berrange <berrange@redhat.com>
R: Eduardo Habkost <eduardo@habkost.net> R: Eduardo Habkost <ehabkost@redhat.com>
S: Supported S: Supported
F: docs/qdev-device-use.txt F: docs/qdev-device-use.txt
F: hw/core/qdev* F: hw/core/qdev*
@ -2750,7 +2668,7 @@ F: tests/unit/check-qom-proplist.c
F: tests/unit/test-qdev-global-props.c F: tests/unit/test-qdev-global-props.c
QOM boilerplate conversion script QOM boilerplate conversion script
M: Eduardo Habkost <eduardo@habkost.net> M: Eduardo Habkost <ehabkost@redhat.com>
S: Maintained S: Maintained
F: scripts/codeconverter/ F: scripts/codeconverter/
@ -2788,8 +2706,6 @@ R: Paolo Bonzini <pbonzini@redhat.com>
R: Bandan Das <bsd@redhat.com> R: Bandan Das <bsd@redhat.com>
R: Stefan Hajnoczi <stefanha@redhat.com> R: Stefan Hajnoczi <stefanha@redhat.com>
R: Thomas Huth <thuth@redhat.com> R: Thomas Huth <thuth@redhat.com>
R: Darren Kenny <darren.kenny@oracle.com>
R: Qiuhao Li <Qiuhao.Li@outlook.com>
S: Maintained S: Maintained
F: tests/qtest/fuzz/ F: tests/qtest/fuzz/
F: tests/qtest/fuzz-*test.c F: tests/qtest/fuzz-*test.c
@ -2994,9 +2910,8 @@ F: net/filter-replay.c
F: include/sysemu/replay.h F: include/sysemu/replay.h
F: docs/replay.txt F: docs/replay.txt
F: stubs/replay.c F: stubs/replay.c
F: tests/avocado/replay_kernel.py F: tests/acceptance/replay_kernel.py
F: tests/avocado/replay_linux.py F: tests/acceptance/reverse_debugging.py
F: tests/avocado/reverse_debugging.py
F: qapi/replay.json F: qapi/replay.json
IOVA Tree IOVA Tree
@ -3113,7 +3028,7 @@ S: Maintained
F: docs/devel/tcg-plugins.rst F: docs/devel/tcg-plugins.rst
F: plugins/ F: plugins/
F: tests/plugin/ F: tests/plugin/
F: tests/avocado/tcg_plugins.py F: tests/acceptance/tcg_plugins.py
F: contrib/plugins/ F: contrib/plugins/
AArch64 TCG target AArch64 TCG target
@ -3469,7 +3384,7 @@ M: Alex Bennée <alex.bennee@linaro.org>
M: Philippe Mathieu-Daudé <f4bug@amsat.org> M: Philippe Mathieu-Daudé <f4bug@amsat.org>
M: Thomas Huth <thuth@redhat.com> M: Thomas Huth <thuth@redhat.com>
R: Wainer dos Santos Moschetta <wainersm@redhat.com> R: Wainer dos Santos Moschetta <wainersm@redhat.com>
R: Beraldo Leal <bleal@redhat.com> R: Willian Rampazzo <willianr@redhat.com>
S: Maintained S: Maintained
F: .github/lockdown.yml F: .github/lockdown.yml
F: .gitlab-ci.yml F: .gitlab-ci.yml
@ -3502,20 +3417,13 @@ S: Maintained
F: tests/tcg/Makefile F: tests/tcg/Makefile
F: tests/tcg/Makefile.include F: tests/tcg/Makefile.include
Integration Testing with the Avocado framework Acceptance (Integration) Testing with the Avocado framework
W: https://trello.com/b/6Qi1pxVn/avocado-qemu W: https://trello.com/b/6Qi1pxVn/avocado-qemu
R: Cleber Rosa <crosa@redhat.com> R: Cleber Rosa <crosa@redhat.com>
R: Philippe Mathieu-Daudé <philmd@redhat.com> R: Philippe Mathieu-Daudé <philmd@redhat.com>
R: Wainer dos Santos Moschetta <wainersm@redhat.com> R: Wainer dos Santos Moschetta <wainersm@redhat.com>
R: Beraldo Leal <bleal@redhat.com>
S: Odd Fixes S: Odd Fixes
F: tests/avocado/ F: tests/acceptance/
GitLab custom runner (Works On Arm Sponsored)
M: Alex Bennée <alex.bennee@linaro.org>
M: Philippe Mathieu-Daudé <f4bug@amsat.org>
S: Maintained
F: .gitlab-ci.d/custom-runners/ubuntu-20.04-aarch64.yml
Documentation Documentation
------------- -------------

View File

@ -87,7 +87,7 @@ x := $(shell rm -rf meson-private meson-info meson-logs)
endif endif
# 1. ensure config-host.mak is up-to-date # 1. ensure config-host.mak is up-to-date
config-host.mak: $(SRC_PATH)/configure $(SRC_PATH)/scripts/meson-buildoptions.sh $(SRC_PATH)/pc-bios $(SRC_PATH)/VERSION config-host.mak: $(SRC_PATH)/configure $(SRC_PATH)/pc-bios $(SRC_PATH)/VERSION
@echo config-host.mak is out-of-date, running configure @echo config-host.mak is out-of-date, running configure
@if test -f meson-private/coredata.dat; then \ @if test -f meson-private/coredata.dat; then \
./config.status --skip-meson; \ ./config.status --skip-meson; \
@ -124,12 +124,6 @@ ifneq ($(MESON),)
Makefile.mtest: build.ninja scripts/mtest2make.py Makefile.mtest: build.ninja scripts/mtest2make.py
$(MESON) introspect --targets --tests --benchmarks | $(PYTHON) scripts/mtest2make.py > $@ $(MESON) introspect --targets --tests --benchmarks | $(PYTHON) scripts/mtest2make.py > $@
-include Makefile.mtest -include Makefile.mtest
.PHONY: update-buildoptions
all update-buildoptions: $(SRC_PATH)/scripts/meson-buildoptions.sh
$(SRC_PATH)/scripts/meson-buildoptions.sh: $(SRC_PATH)/meson_options.txt
$(MESON) introspect --buildoptions $(SRC_PATH)/meson.build | $(PYTHON) \
scripts/meson-buildoptions.py > $@.tmp && mv $@.tmp $@
endif endif
# 4. Rules to bridge to other makefiles # 4. Rules to bridge to other makefiles
@ -235,8 +229,7 @@ distclean: clean
rm -f linux-headers/asm rm -f linux-headers/asm
rm -Rf .sdk rm -Rf .sdk
find-src-path = find "$(SRC_PATH)" -path "$(SRC_PATH)/meson" -prune -o \ find-src-path = find "$(SRC_PATH)/" -path "$(SRC_PATH)/meson" -prune -o \( -name "*.[chsS]" -o -name "*.[ch].inc" \)
-type l -prune -o \( -name "*.[chsS]" -o -name "*.[ch].inc" \)
.PHONY: ctags .PHONY: ctags
ctags: ctags:
@ -257,7 +250,7 @@ gtags:
"GTAGS", "Remove old $@ files") "GTAGS", "Remove old $@ files")
$(call quiet-command, \ $(call quiet-command, \
(cd $(SRC_PATH) && \ (cd $(SRC_PATH) && \
$(find-src-path) -print | gtags -f -), \ $(find-src-path) | gtags -f -), \
"GTAGS", "Re-index $(SRC_PATH)") "GTAGS", "Re-index $(SRC_PATH)")
.PHONY: TAGS .PHONY: TAGS

13
README.md Normal file
View File

@ -0,0 +1,13 @@
# QEMU LibAFL Bridge
This is a patched QEMU that exposes an interface for LibAFL-based fuzzers.
This raw interface is used in `libafl_qemu` that expose a more Rusty API.
#### License
<sup>
This project extends the QEMU emulator, and our contributions to previously existing files adopt those files' respective licenses; the files that we have added are made available 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.
</sup>
<br>

View File

@ -59,9 +59,9 @@ of other UNIX targets. The simple steps to build QEMU are:
Additional information can also be found online via the QEMU website: Additional information can also be found online via the QEMU website:
* `<https://wiki.qemu.org/Hosts/Linux>`_ * `<https://qemu.org/Hosts/Linux>`_
* `<https://wiki.qemu.org/Hosts/Mac>`_ * `<https://qemu.org/Hosts/Mac>`_
* `<https://wiki.qemu.org/Hosts/W32>`_ * `<https://qemu.org/Hosts/W32>`_
Submitting patches Submitting patches
@ -84,8 +84,8 @@ the Developers Guide.
Additional information on submitting patches can be found online via Additional information on submitting patches can be found online via
the QEMU website the QEMU website
* `<https://wiki.qemu.org/Contribute/SubmitAPatch>`_ * `<https://qemu.org/Contribute/SubmitAPatch>`_
* `<https://wiki.qemu.org/Contribute/TrivialPatches>`_ * `<https://qemu.org/Contribute/TrivialPatches>`_
The QEMU website is also maintained under source control. The QEMU website is also maintained under source control.
@ -144,7 +144,7 @@ reported via GitLab.
For additional information on bug reporting consult: For additional information on bug reporting consult:
* `<https://wiki.qemu.org/Contribute/ReportABug>`_ * `<https://qemu.org/Contribute/ReportABug>`_
ChangeLog ChangeLog
@ -168,4 +168,4 @@ main methods being email and IRC
Information on additional methods of contacting the community can be Information on additional methods of contacting the community can be
found online via the QEMU website: found online via the QEMU website:
* `<https://wiki.qemu.org/Contribute/StartHere>`_ * `<https://qemu.org/Contribute/StartHere>`_

View File

@ -1 +1 @@
6.2.0 6.1.1

View File

@ -60,10 +60,6 @@
HVFState *hvf_state; HVFState *hvf_state;
#ifdef __aarch64__
#define HV_VM_DEFAULT NULL
#endif
/* Memory slots */ /* Memory slots */
hvf_slot *hvf_find_overlap_slot(uint64_t start, uint64_t size) hvf_slot *hvf_find_overlap_slot(uint64_t start, uint64_t size)
@ -122,7 +118,6 @@ static void hvf_set_phys_mem(MemoryRegionSection *section, bool add)
MemoryRegion *area = section->mr; MemoryRegion *area = section->mr;
bool writeable = !area->readonly && !area->rom_device; bool writeable = !area->readonly && !area->rom_device;
hv_memory_flags_t flags; hv_memory_flags_t flags;
uint64_t page_size = qemu_real_host_page_size;
if (!memory_region_is_ram(area)) { if (!memory_region_is_ram(area)) {
if (writeable) { if (writeable) {
@ -136,12 +131,6 @@ static void hvf_set_phys_mem(MemoryRegionSection *section, bool add)
} }
} }
if (!QEMU_IS_ALIGNED(int128_get64(section->size), page_size) ||
!QEMU_IS_ALIGNED(section->offset_within_address_space, page_size)) {
/* Not page aligned, so we can not map as RAM */
add = false;
}
mem = hvf_find_overlap_slot( mem = hvf_find_overlap_slot(
section->offset_within_address_space, section->offset_within_address_space,
int128_get64(section->size)); int128_get64(section->size));
@ -250,12 +239,12 @@ static void hvf_set_dirty_tracking(MemoryRegionSection *section, bool on)
if (on) { if (on) {
slot->flags |= HVF_SLOT_LOG; slot->flags |= HVF_SLOT_LOG;
hv_vm_protect((uintptr_t)slot->start, (size_t)slot->size, hv_vm_protect((uintptr_t)slot->start, (size_t)slot->size,
HV_MEMORY_READ | HV_MEMORY_EXEC); HV_MEMORY_READ);
/* stop tracking region*/ /* stop tracking region*/
} else { } else {
slot->flags &= ~HVF_SLOT_LOG; slot->flags &= ~HVF_SLOT_LOG;
hv_vm_protect((uintptr_t)slot->start, (size_t)slot->size, hv_vm_protect((uintptr_t)slot->start, (size_t)slot->size,
HV_MEMORY_READ | HV_MEMORY_WRITE | HV_MEMORY_EXEC); HV_MEMORY_READ | HV_MEMORY_WRITE);
} }
} }
@ -302,7 +291,6 @@ static void hvf_region_del(MemoryListener *listener,
} }
static MemoryListener hvf_memory_listener = { static MemoryListener hvf_memory_listener = {
.name = "hvf",
.priority = 10, .priority = 10,
.region_add = hvf_region_add, .region_add = hvf_region_add,
.region_del = hvf_region_del, .region_del = hvf_region_del,
@ -328,7 +316,7 @@ static int hvf_accel_init(MachineState *ms)
s = g_new0(HVFState, 1); s = g_new0(HVFState, 1);
s->num_slots = ARRAY_SIZE(s->slots); s->num_slots = 32;
for (x = 0; x < s->num_slots; ++x) { for (x = 0; x < s->num_slots; ++x) {
s->slots[x].size = 0; s->slots[x].size = 0;
s->slots[x].slot_id = x; s->slots[x].slot_id = x;
@ -336,8 +324,7 @@ static int hvf_accel_init(MachineState *ms)
hvf_state = s; hvf_state = s;
memory_listener_register(&hvf_memory_listener, &address_space_memory); memory_listener_register(&hvf_memory_listener, &address_space_memory);
return 0;
return hvf_arch_init();
} }
static void hvf_accel_class_init(ObjectClass *oc, void *data) static void hvf_accel_class_init(ObjectClass *oc, void *data)
@ -378,20 +365,17 @@ static int hvf_init_vcpu(CPUState *cpu)
cpu->hvf = g_malloc0(sizeof(*cpu->hvf)); cpu->hvf = g_malloc0(sizeof(*cpu->hvf));
/* init cpu signals */ /* init cpu signals */
sigset_t set;
struct sigaction sigact; struct sigaction sigact;
memset(&sigact, 0, sizeof(sigact)); memset(&sigact, 0, sizeof(sigact));
sigact.sa_handler = dummy_signal; sigact.sa_handler = dummy_signal;
sigaction(SIG_IPI, &sigact, NULL); sigaction(SIG_IPI, &sigact, NULL);
pthread_sigmask(SIG_BLOCK, NULL, &cpu->hvf->unblock_ipi_mask); pthread_sigmask(SIG_BLOCK, NULL, &set);
sigdelset(&cpu->hvf->unblock_ipi_mask, SIG_IPI); sigdelset(&set, SIG_IPI);
#ifdef __aarch64__
r = hv_vcpu_create(&cpu->hvf->fd, (hv_vcpu_exit_t **)&cpu->hvf->exit, NULL);
#else
r = hv_vcpu_create((hv_vcpuid_t *)&cpu->hvf->fd, HV_VCPU_DEFAULT); r = hv_vcpu_create((hv_vcpuid_t *)&cpu->hvf->fd, HV_VCPU_DEFAULT);
#endif
cpu->vcpu_dirty = 1; cpu->vcpu_dirty = 1;
assert_hvf_ok(r); assert_hvf_ok(r);
@ -467,7 +451,6 @@ static void hvf_accel_ops_class_init(ObjectClass *oc, void *data)
AccelOpsClass *ops = ACCEL_OPS_CLASS(oc); AccelOpsClass *ops = ACCEL_OPS_CLASS(oc);
ops->create_vcpu_thread = hvf_start_vcpu_thread; ops->create_vcpu_thread = hvf_start_vcpu_thread;
ops->kick_vcpu_thread = hvf_kick_vcpu_thread;
ops->synchronize_post_reset = hvf_cpu_synchronize_post_reset; ops->synchronize_post_reset = hvf_cpu_synchronize_post_reset;
ops->synchronize_post_init = hvf_cpu_synchronize_post_init; ops->synchronize_post_init = hvf_cpu_synchronize_post_init;

View File

@ -469,7 +469,6 @@ int kvm_init_vcpu(CPUState *cpu, Error **errp)
cpu->kvm_fd = ret; cpu->kvm_fd = ret;
cpu->kvm_state = s; cpu->kvm_state = s;
cpu->vcpu_dirty = true; cpu->vcpu_dirty = true;
cpu->dirty_pages = 0;
mmap_size = kvm_ioctl(s, KVM_GET_VCPU_MMAP_SIZE, 0); mmap_size = kvm_ioctl(s, KVM_GET_VCPU_MMAP_SIZE, 0);
if (mmap_size < 0) { if (mmap_size < 0) {
@ -744,7 +743,6 @@ static uint32_t kvm_dirty_ring_reap_one(KVMState *s, CPUState *cpu)
count++; count++;
} }
cpu->kvm_fetch_index = fetch; cpu->kvm_fetch_index = fetch;
cpu->dirty_pages += count;
return count; return count;
} }
@ -1131,7 +1129,6 @@ static void kvm_coalesce_pio_del(MemoryListener *listener,
} }
static MemoryListener kvm_coalesced_pio_listener = { static MemoryListener kvm_coalesced_pio_listener = {
.name = "kvm-coalesced-pio",
.coalesced_io_add = kvm_coalesce_pio_add, .coalesced_io_add = kvm_coalesce_pio_add,
.coalesced_io_del = kvm_coalesce_pio_del, .coalesced_io_del = kvm_coalesce_pio_del,
}; };
@ -1636,7 +1633,7 @@ static void kvm_io_ioeventfd_del(MemoryListener *listener,
} }
void kvm_memory_listener_register(KVMState *s, KVMMemoryListener *kml, void kvm_memory_listener_register(KVMState *s, KVMMemoryListener *kml,
AddressSpace *as, int as_id, const char *name) AddressSpace *as, int as_id)
{ {
int i; int i;
@ -1652,7 +1649,6 @@ void kvm_memory_listener_register(KVMState *s, KVMMemoryListener *kml,
kml->listener.log_start = kvm_log_start; kml->listener.log_start = kvm_log_start;
kml->listener.log_stop = kvm_log_stop; kml->listener.log_stop = kvm_log_stop;
kml->listener.priority = 10; kml->listener.priority = 10;
kml->listener.name = name;
if (s->kvm_dirty_ring_size) { if (s->kvm_dirty_ring_size) {
kml->listener.log_sync_global = kvm_log_sync_global; kml->listener.log_sync_global = kvm_log_sync_global;
@ -1673,7 +1669,6 @@ void kvm_memory_listener_register(KVMState *s, KVMMemoryListener *kml,
} }
static MemoryListener kvm_io_listener = { static MemoryListener kvm_io_listener = {
.name = "kvm-io",
.eventfd_add = kvm_io_ioeventfd_add, .eventfd_add = kvm_io_ioeventfd_add,
.eventfd_del = kvm_io_ioeventfd_del, .eventfd_del = kvm_io_ioeventfd_del,
.priority = 10, .priority = 10,
@ -2298,11 +2293,6 @@ bool kvm_vcpu_id_is_valid(int vcpu_id)
return vcpu_id >= 0 && vcpu_id < kvm_max_vcpu_id(s); return vcpu_id >= 0 && vcpu_id < kvm_max_vcpu_id(s);
} }
bool kvm_dirty_ring_enabled(void)
{
return kvm_state->kvm_dirty_ring_size ? true : false;
}
static int kvm_init(MachineState *ms) static int kvm_init(MachineState *ms)
{ {
MachineClass *mc = MACHINE_GET_CLASS(ms); MachineClass *mc = MACHINE_GET_CLASS(ms);
@ -2479,7 +2469,7 @@ static int kvm_init(MachineState *ms)
ret = kvm_vm_enable_cap(s, KVM_CAP_DIRTY_LOG_RING, 0, ring_bytes); ret = kvm_vm_enable_cap(s, KVM_CAP_DIRTY_LOG_RING, 0, ring_bytes);
if (ret) { if (ret) {
error_report("Enabling of KVM dirty ring failed: %s. " error_report("Enabling of KVM dirty ring failed: %s. "
"Suggested minimum value is 1024.", strerror(-ret)); "Suggested mininum value is 1024.", strerror(-ret));
goto err; goto err;
} }
@ -2589,7 +2579,7 @@ static int kvm_init(MachineState *ms)
s->memory_listener.listener.coalesced_io_del = kvm_uncoalesce_mmio_region; s->memory_listener.listener.coalesced_io_del = kvm_uncoalesce_mmio_region;
kvm_memory_listener_register(s, &s->memory_listener, kvm_memory_listener_register(s, &s->memory_listener,
&address_space_memory, 0, "kvm-memory"); &address_space_memory, 0);
if (kvm_eventfds_allowed) { if (kvm_eventfds_allowed) {
memory_listener_register(&kvm_io_listener, memory_listener_register(&kvm_io_listener,
&address_space_io); &address_space_io);

View File

@ -3,5 +3,6 @@ kvm_ss.add(files(
'kvm-all.c', 'kvm-all.c',
'kvm-accel-ops.c', 'kvm-accel-ops.c',
)) ))
kvm_ss.add(when: 'CONFIG_SEV', if_false: files('sev-stub.c'))
specific_ss.add_all(when: 'CONFIG_KVM', if_true: kvm_ss) specific_ss.add_all(when: 'CONFIG_KVM', if_true: kvm_ss)

View File

@ -13,7 +13,7 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qemu-common.h" #include "qemu-common.h"
#include "sev.h" #include "sysemu/sev.h"
int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) int sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
{ {

View File

@ -147,9 +147,4 @@ bool kvm_arm_supports_user_irq(void)
{ {
return false; return false;
} }
bool kvm_dirty_ring_enabled(void)
{
return false;
}
#endif #endif

View File

@ -13,43 +13,56 @@
* See the COPYING file in the top-level directory. * See the COPYING file in the top-level directory.
*/ */
static void atomic_trace_rmw_pre(CPUArchState *env, target_ulong addr, static uint16_t atomic_trace_rmw_pre(CPUArchState *env, target_ulong addr,
MemOpIdx oi) TCGMemOpIdx oi)
{ {
CPUState *cpu = env_cpu(env); CPUState *cpu = env_cpu(env);
uint16_t info = trace_mem_get_info(get_memop(oi), get_mmuidx(oi), false);
trace_guest_rmw_before_exec(cpu, addr, oi); trace_guest_mem_before_exec(cpu, addr, info);
trace_guest_mem_before_exec(cpu, addr, info | TRACE_MEM_ST);
return info;
} }
static void atomic_trace_rmw_post(CPUArchState *env, target_ulong addr, static void atomic_trace_rmw_post(CPUArchState *env, target_ulong addr,
MemOpIdx oi) uint16_t info)
{ {
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_RW); qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, info);
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, info | TRACE_MEM_ST);
} }
#if HAVE_ATOMIC128 #if HAVE_ATOMIC128
static void atomic_trace_ld_pre(CPUArchState *env, target_ulong addr, static uint16_t atomic_trace_ld_pre(CPUArchState *env, target_ulong addr,
MemOpIdx oi) TCGMemOpIdx oi)
{ {
trace_guest_ld_before_exec(env_cpu(env), addr, oi); uint16_t info = trace_mem_get_info(get_memop(oi), get_mmuidx(oi), false);
trace_guest_mem_before_exec(env_cpu(env), addr, info);
return info;
} }
static void atomic_trace_ld_post(CPUArchState *env, target_ulong addr, static void atomic_trace_ld_post(CPUArchState *env, target_ulong addr,
MemOpIdx oi) uint16_t info)
{ {
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_R); qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, info);
} }
static void atomic_trace_st_pre(CPUArchState *env, target_ulong addr, static uint16_t atomic_trace_st_pre(CPUArchState *env, target_ulong addr,
MemOpIdx oi) TCGMemOpIdx oi)
{ {
trace_guest_st_before_exec(env_cpu(env), addr, oi); uint16_t info = trace_mem_get_info(get_memop(oi), get_mmuidx(oi), true);
trace_guest_mem_before_exec(env_cpu(env), addr, info);
return info;
} }
static void atomic_trace_st_post(CPUArchState *env, target_ulong addr, static void atomic_trace_st_post(CPUArchState *env, target_ulong addr,
MemOpIdx oi) uint16_t info)
{ {
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_W); qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, info);
} }
#endif #endif

View File

@ -19,6 +19,7 @@
*/ */
#include "qemu/plugin.h" #include "qemu/plugin.h"
#include "trace/mem.h"
#if DATA_SIZE == 16 #if DATA_SIZE == 16
# define SUFFIX o # define SUFFIX o
@ -71,77 +72,77 @@
ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
ABI_TYPE cmpv, ABI_TYPE newv, ABI_TYPE cmpv, ABI_TYPE newv,
MemOpIdx oi, uintptr_t retaddr) TCGMemOpIdx oi, uintptr_t retaddr)
{ {
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
PAGE_READ | PAGE_WRITE, retaddr); PAGE_READ | PAGE_WRITE, retaddr);
DATA_TYPE ret; DATA_TYPE ret;
uint16_t info = atomic_trace_rmw_pre(env, addr, oi);
atomic_trace_rmw_pre(env, addr, oi);
#if DATA_SIZE == 16 #if DATA_SIZE == 16
ret = atomic16_cmpxchg(haddr, cmpv, newv); ret = atomic16_cmpxchg(haddr, cmpv, newv);
#else #else
ret = qatomic_cmpxchg__nocheck(haddr, cmpv, newv); ret = qatomic_cmpxchg__nocheck(haddr, cmpv, newv);
#endif #endif
ATOMIC_MMU_CLEANUP; ATOMIC_MMU_CLEANUP;
atomic_trace_rmw_post(env, addr, oi); atomic_trace_rmw_post(env, addr, info);
return ret; return ret;
} }
#if DATA_SIZE >= 16 #if DATA_SIZE >= 16
#if HAVE_ATOMIC128 #if HAVE_ATOMIC128
ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr, ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr,
MemOpIdx oi, uintptr_t retaddr) TCGMemOpIdx oi, uintptr_t retaddr)
{ {
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
PAGE_READ, retaddr); PAGE_READ, retaddr);
DATA_TYPE val; DATA_TYPE val;
uint16_t info = atomic_trace_ld_pre(env, addr, oi);
atomic_trace_ld_pre(env, addr, oi);
val = atomic16_read(haddr); val = atomic16_read(haddr);
ATOMIC_MMU_CLEANUP; ATOMIC_MMU_CLEANUP;
atomic_trace_ld_post(env, addr, oi); atomic_trace_ld_post(env, addr, info);
return val; return val;
} }
void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val, void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
MemOpIdx oi, uintptr_t retaddr) TCGMemOpIdx oi, uintptr_t retaddr)
{ {
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
PAGE_WRITE, retaddr); PAGE_WRITE, retaddr);
uint16_t info = atomic_trace_st_pre(env, addr, oi);
atomic_trace_st_pre(env, addr, oi);
atomic16_set(haddr, val); atomic16_set(haddr, val);
ATOMIC_MMU_CLEANUP; ATOMIC_MMU_CLEANUP;
atomic_trace_st_post(env, addr, oi); atomic_trace_st_post(env, addr, info);
} }
#endif #endif
#else #else
ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val, ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
MemOpIdx oi, uintptr_t retaddr) TCGMemOpIdx oi, uintptr_t retaddr)
{ {
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
PAGE_READ | PAGE_WRITE, retaddr); PAGE_READ | PAGE_WRITE, retaddr);
DATA_TYPE ret; DATA_TYPE ret;
uint16_t info = atomic_trace_rmw_pre(env, addr, oi);
atomic_trace_rmw_pre(env, addr, oi);
ret = qatomic_xchg__nocheck(haddr, val); ret = qatomic_xchg__nocheck(haddr, val);
ATOMIC_MMU_CLEANUP; ATOMIC_MMU_CLEANUP;
atomic_trace_rmw_post(env, addr, oi); atomic_trace_rmw_post(env, addr, info);
return ret; return ret;
} }
#define GEN_ATOMIC_HELPER(X) \ #define GEN_ATOMIC_HELPER(X) \
ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
ABI_TYPE val, MemOpIdx oi, uintptr_t retaddr) \ ABI_TYPE val, TCGMemOpIdx oi, uintptr_t retaddr) \
{ \ { \
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \ DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \
PAGE_READ | PAGE_WRITE, retaddr); \ PAGE_READ | PAGE_WRITE, retaddr); \
DATA_TYPE ret; \ DATA_TYPE ret; \
atomic_trace_rmw_pre(env, addr, oi); \ uint16_t info = atomic_trace_rmw_pre(env, addr, oi); \
ret = qatomic_##X(haddr, val); \ ret = qatomic_##X(haddr, val); \
ATOMIC_MMU_CLEANUP; \ ATOMIC_MMU_CLEANUP; \
atomic_trace_rmw_post(env, addr, oi); \ atomic_trace_rmw_post(env, addr, info); \
return ret; \ return ret; \
} }
@ -166,12 +167,12 @@ GEN_ATOMIC_HELPER(xor_fetch)
*/ */
#define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET) \ #define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET) \
ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
ABI_TYPE xval, MemOpIdx oi, uintptr_t retaddr) \ ABI_TYPE xval, TCGMemOpIdx oi, uintptr_t retaddr) \
{ \ { \
XDATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \ XDATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \
PAGE_READ | PAGE_WRITE, retaddr); \ PAGE_READ | PAGE_WRITE, retaddr); \
XDATA_TYPE cmp, old, new, val = xval; \ XDATA_TYPE cmp, old, new, val = xval; \
atomic_trace_rmw_pre(env, addr, oi); \ uint16_t info = atomic_trace_rmw_pre(env, addr, oi); \
smp_mb(); \ smp_mb(); \
cmp = qatomic_read__nocheck(haddr); \ cmp = qatomic_read__nocheck(haddr); \
do { \ do { \
@ -179,7 +180,7 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
cmp = qatomic_cmpxchg__nocheck(haddr, old, new); \ cmp = qatomic_cmpxchg__nocheck(haddr, old, new); \
} while (cmp != old); \ } while (cmp != old); \
ATOMIC_MMU_CLEANUP; \ ATOMIC_MMU_CLEANUP; \
atomic_trace_rmw_post(env, addr, oi); \ atomic_trace_rmw_post(env, addr, info); \
return RET; \ return RET; \
} }
@ -210,78 +211,78 @@ GEN_ATOMIC_HELPER_FN(umax_fetch, MAX, DATA_TYPE, new)
ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr, ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, target_ulong addr,
ABI_TYPE cmpv, ABI_TYPE newv, ABI_TYPE cmpv, ABI_TYPE newv,
MemOpIdx oi, uintptr_t retaddr) TCGMemOpIdx oi, uintptr_t retaddr)
{ {
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
PAGE_READ | PAGE_WRITE, retaddr); PAGE_READ | PAGE_WRITE, retaddr);
DATA_TYPE ret; DATA_TYPE ret;
uint16_t info = atomic_trace_rmw_pre(env, addr, oi);
atomic_trace_rmw_pre(env, addr, oi);
#if DATA_SIZE == 16 #if DATA_SIZE == 16
ret = atomic16_cmpxchg(haddr, BSWAP(cmpv), BSWAP(newv)); ret = atomic16_cmpxchg(haddr, BSWAP(cmpv), BSWAP(newv));
#else #else
ret = qatomic_cmpxchg__nocheck(haddr, BSWAP(cmpv), BSWAP(newv)); ret = qatomic_cmpxchg__nocheck(haddr, BSWAP(cmpv), BSWAP(newv));
#endif #endif
ATOMIC_MMU_CLEANUP; ATOMIC_MMU_CLEANUP;
atomic_trace_rmw_post(env, addr, oi); atomic_trace_rmw_post(env, addr, info);
return BSWAP(ret); return BSWAP(ret);
} }
#if DATA_SIZE >= 16 #if DATA_SIZE >= 16
#if HAVE_ATOMIC128 #if HAVE_ATOMIC128
ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr, ABI_TYPE ATOMIC_NAME(ld)(CPUArchState *env, target_ulong addr,
MemOpIdx oi, uintptr_t retaddr) TCGMemOpIdx oi, uintptr_t retaddr)
{ {
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
PAGE_READ, retaddr); PAGE_READ, retaddr);
DATA_TYPE val; DATA_TYPE val;
uint16_t info = atomic_trace_ld_pre(env, addr, oi);
atomic_trace_ld_pre(env, addr, oi);
val = atomic16_read(haddr); val = atomic16_read(haddr);
ATOMIC_MMU_CLEANUP; ATOMIC_MMU_CLEANUP;
atomic_trace_ld_post(env, addr, oi); atomic_trace_ld_post(env, addr, info);
return BSWAP(val); return BSWAP(val);
} }
void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val, void ATOMIC_NAME(st)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
MemOpIdx oi, uintptr_t retaddr) TCGMemOpIdx oi, uintptr_t retaddr)
{ {
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
PAGE_WRITE, retaddr); PAGE_WRITE, retaddr);
uint16_t info = atomic_trace_st_pre(env, addr, oi);
atomic_trace_st_pre(env, addr, oi);
val = BSWAP(val); val = BSWAP(val);
atomic16_set(haddr, val); atomic16_set(haddr, val);
ATOMIC_MMU_CLEANUP; ATOMIC_MMU_CLEANUP;
atomic_trace_st_post(env, addr, oi); atomic_trace_st_post(env, addr, info);
} }
#endif #endif
#else #else
ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val, ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, ABI_TYPE val,
MemOpIdx oi, uintptr_t retaddr) TCGMemOpIdx oi, uintptr_t retaddr)
{ {
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE,
PAGE_READ | PAGE_WRITE, retaddr); PAGE_READ | PAGE_WRITE, retaddr);
ABI_TYPE ret; ABI_TYPE ret;
uint16_t info = atomic_trace_rmw_pre(env, addr, oi);
atomic_trace_rmw_pre(env, addr, oi);
ret = qatomic_xchg__nocheck(haddr, BSWAP(val)); ret = qatomic_xchg__nocheck(haddr, BSWAP(val));
ATOMIC_MMU_CLEANUP; ATOMIC_MMU_CLEANUP;
atomic_trace_rmw_post(env, addr, oi); atomic_trace_rmw_post(env, addr, info);
return BSWAP(ret); return BSWAP(ret);
} }
#define GEN_ATOMIC_HELPER(X) \ #define GEN_ATOMIC_HELPER(X) \
ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
ABI_TYPE val, MemOpIdx oi, uintptr_t retaddr) \ ABI_TYPE val, TCGMemOpIdx oi, uintptr_t retaddr) \
{ \ { \
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \ DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \
PAGE_READ | PAGE_WRITE, retaddr); \ PAGE_READ | PAGE_WRITE, retaddr); \
DATA_TYPE ret; \ DATA_TYPE ret; \
atomic_trace_rmw_pre(env, addr, oi); \ uint16_t info = atomic_trace_rmw_pre(env, addr, oi); \
ret = qatomic_##X(haddr, BSWAP(val)); \ ret = qatomic_##X(haddr, BSWAP(val)); \
ATOMIC_MMU_CLEANUP; \ ATOMIC_MMU_CLEANUP; \
atomic_trace_rmw_post(env, addr, oi); \ atomic_trace_rmw_post(env, addr, info); \
return BSWAP(ret); \ return BSWAP(ret); \
} }
@ -303,12 +304,12 @@ GEN_ATOMIC_HELPER(xor_fetch)
*/ */
#define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET) \ #define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET) \
ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
ABI_TYPE xval, MemOpIdx oi, uintptr_t retaddr) \ ABI_TYPE xval, TCGMemOpIdx oi, uintptr_t retaddr) \
{ \ { \
XDATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \ XDATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, \
PAGE_READ | PAGE_WRITE, retaddr); \ PAGE_READ | PAGE_WRITE, retaddr); \
XDATA_TYPE ldo, ldn, old, new, val = xval; \ XDATA_TYPE ldo, ldn, old, new, val = xval; \
atomic_trace_rmw_pre(env, addr, oi); \ uint16_t info = atomic_trace_rmw_pre(env, addr, oi); \
smp_mb(); \ smp_mb(); \
ldn = qatomic_read__nocheck(haddr); \ ldn = qatomic_read__nocheck(haddr); \
do { \ do { \
@ -316,7 +317,7 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, target_ulong addr, \
ldn = qatomic_cmpxchg__nocheck(haddr, ldo, BSWAP(new)); \ ldn = qatomic_cmpxchg__nocheck(haddr, ldo, BSWAP(new)); \
} while (ldo != ldn); \ } while (ldo != ldn); \
ATOMIC_MMU_CLEANUP; \ ATOMIC_MMU_CLEANUP; \
atomic_trace_rmw_post(env, addr, oi); \ atomic_trace_rmw_post(env, addr, info); \
return RET; \ return RET; \
} }

View File

@ -20,9 +20,6 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qemu-common.h" #include "qemu-common.h"
#include "qemu/qemu-print.h" #include "qemu/qemu-print.h"
#include "qapi/error.h"
#include "qapi/qapi-commands-machine.h"
#include "qapi/type-helpers.h"
#include "hw/core/tcg-cpu-ops.h" #include "hw/core/tcg-cpu-ops.h"
#include "trace.h" #include "trace.h"
#include "disas/disas.h" #include "disas/disas.h"
@ -41,7 +38,6 @@
#include "exec/cpu-all.h" #include "exec/cpu-all.h"
#include "sysemu/cpu-timers.h" #include "sysemu/cpu-timers.h"
#include "sysemu/replay.h" #include "sysemu/replay.h"
#include "sysemu/tcg.h"
#include "exec/helper-proto.h" #include "exec/helper-proto.h"
#include "tb-hash.h" #include "tb-hash.h"
#include "tb-context.h" #include "tb-context.h"
@ -387,17 +383,6 @@ cpu_tb_exec(CPUState *cpu, TranslationBlock *itb, int *tb_exit)
cc->set_pc(cpu, last_tb->pc); cc->set_pc(cpu, last_tb->pc);
} }
} }
/*
* If gdb single-step, and we haven't raised another exception,
* raise a debug exception. Single-step with another exception
* is handled in cpu_handle_exception.
*/
if (unlikely(cpu->singlestep_enabled) && cpu->exception_index == -1) {
cpu->exception_index = EXCP_DEBUG;
cpu_loop_exit(cpu);
}
return last_tb; return last_tb;
} }
@ -466,7 +451,6 @@ void cpu_exec_step_atomic(CPUState *cpu)
* memory. * memory.
*/ */
#ifndef CONFIG_SOFTMMU #ifndef CONFIG_SOFTMMU
clear_helper_retaddr();
tcg_debug_assert(!have_mmap_lock()); tcg_debug_assert(!have_mmap_lock());
#endif #endif
if (qemu_mutex_iothread_locked()) { if (qemu_mutex_iothread_locked()) {
@ -476,6 +460,7 @@ void cpu_exec_step_atomic(CPUState *cpu)
qemu_plugin_disable_mem_helpers(cpu); qemu_plugin_disable_mem_helpers(cpu);
} }
/* /*
* As we start the exclusive region before codegen we must still * As we start the exclusive region before codegen we must still
* be in the region if we longjump out of either the codegen or * be in the region if we longjump out of either the codegen or
@ -603,9 +588,8 @@ static inline void tb_add_jump(TranslationBlock *tb, int n,
static inline bool cpu_handle_halt(CPUState *cpu) static inline bool cpu_handle_halt(CPUState *cpu)
{ {
#ifndef CONFIG_USER_ONLY
if (cpu->halted) { if (cpu->halted) {
#if defined(TARGET_I386) #if defined(TARGET_I386) && !defined(CONFIG_USER_ONLY)
if (cpu->interrupt_request & CPU_INTERRUPT_POLL) { if (cpu->interrupt_request & CPU_INTERRUPT_POLL) {
X86CPU *x86_cpu = X86_CPU(cpu); X86CPU *x86_cpu = X86_CPU(cpu);
qemu_mutex_lock_iothread(); qemu_mutex_lock_iothread();
@ -613,14 +597,13 @@ static inline bool cpu_handle_halt(CPUState *cpu)
cpu_reset_interrupt(cpu, CPU_INTERRUPT_POLL); cpu_reset_interrupt(cpu, CPU_INTERRUPT_POLL);
qemu_mutex_unlock_iothread(); qemu_mutex_unlock_iothread();
} }
#endif /* TARGET_I386 */ #endif
if (!cpu_has_work(cpu)) { if (!cpu_has_work(cpu)) {
return true; return true;
} }
cpu->halted = 0; cpu->halted = 0;
} }
#endif /* !CONFIG_USER_ONLY */
return false; return false;
} }
@ -643,6 +626,18 @@ static inline void cpu_handle_debug_exception(CPUState *cpu)
static inline bool cpu_handle_exception(CPUState *cpu, int *ret) static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
{ {
//// --- Begin LibAFL code ---
#define EXCP_LIBAFL_BP 0xf4775747
if (cpu->exception_index == EXCP_LIBAFL_BP) {
*ret = cpu->exception_index;
cpu->exception_index = -1;
return true;
}
//// --- End LibAFL code ---
if (cpu->exception_index < 0) { if (cpu->exception_index < 0) {
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
if (replay_has_exception() if (replay_has_exception()
@ -668,8 +663,8 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
loop */ loop */
#if defined(TARGET_I386) #if defined(TARGET_I386)
CPUClass *cc = CPU_GET_CLASS(cpu); CPUClass *cc = CPU_GET_CLASS(cpu);
cc->tcg_ops->fake_user_interrupt(cpu); cc->tcg_ops->do_interrupt(cpu);
#endif /* TARGET_I386 */ #endif
*ret = cpu->exception_index; *ret = cpu->exception_index;
cpu->exception_index = -1; cpu->exception_index = -1;
return true; return true;
@ -702,7 +697,6 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
return false; return false;
} }
#ifndef CONFIG_USER_ONLY
/* /*
* CPU_INTERRUPT_POLL is a virtual event which gets converted into a * CPU_INTERRUPT_POLL is a virtual event which gets converted into a
* "real" interrupt event later. It does not need to be recorded for * "real" interrupt event later. It does not need to be recorded for
@ -716,19 +710,11 @@ static inline bool need_replay_interrupt(int interrupt_request)
return true; return true;
#endif #endif
} }
#endif /* !CONFIG_USER_ONLY */
static inline bool cpu_handle_interrupt(CPUState *cpu, static inline bool cpu_handle_interrupt(CPUState *cpu,
TranslationBlock **last_tb) TranslationBlock **last_tb)
{ {
/* CPUClass *cc = CPU_GET_CLASS(cpu);
* If we have requested custom cflags with CF_NOIRQ we should
* skip checking here. Any pending interrupts will get picked up
* by the next TB we execute under normal cflags.
*/
if (cpu->cflags_next_tb != -1 && cpu->cflags_next_tb & CF_NOIRQ) {
return false;
}
/* Clear the interrupt flag now since we're processing /* Clear the interrupt flag now since we're processing
* cpu->interrupt_request and cpu->exit_request. * cpu->interrupt_request and cpu->exit_request.
@ -751,7 +737,6 @@ static inline bool cpu_handle_interrupt(CPUState *cpu,
qemu_mutex_unlock_iothread(); qemu_mutex_unlock_iothread();
return true; return true;
} }
#if !defined(CONFIG_USER_ONLY)
if (replay_mode == REPLAY_MODE_PLAY && !replay_has_interrupt()) { if (replay_mode == REPLAY_MODE_PLAY && !replay_has_interrupt()) {
/* Do nothing */ /* Do nothing */
} else if (interrupt_request & CPU_INTERRUPT_HALT) { } else if (interrupt_request & CPU_INTERRUPT_HALT) {
@ -780,14 +765,12 @@ static inline bool cpu_handle_interrupt(CPUState *cpu,
qemu_mutex_unlock_iothread(); qemu_mutex_unlock_iothread();
return true; return true;
} }
#endif /* !TARGET_I386 */ #endif
/* The target hook has 3 exit conditions: /* The target hook has 3 exit conditions:
False when the interrupt isn't processed, False when the interrupt isn't processed,
True when it is, and we should restart on a new TB, True when it is, and we should restart on a new TB,
and via longjmp via cpu_loop_exit. */ and via longjmp via cpu_loop_exit. */
else { else {
CPUClass *cc = CPU_GET_CLASS(cpu);
if (cc->tcg_ops->cpu_exec_interrupt && if (cc->tcg_ops->cpu_exec_interrupt &&
cc->tcg_ops->cpu_exec_interrupt(cpu, interrupt_request)) { cc->tcg_ops->cpu_exec_interrupt(cpu, interrupt_request)) {
if (need_replay_interrupt(interrupt_request)) { if (need_replay_interrupt(interrupt_request)) {
@ -806,7 +789,6 @@ static inline bool cpu_handle_interrupt(CPUState *cpu,
* reload the 'interrupt_request' value */ * reload the 'interrupt_request' value */
interrupt_request = cpu->interrupt_request; interrupt_request = cpu->interrupt_request;
} }
#endif /* !CONFIG_USER_ONLY */
if (interrupt_request & CPU_INTERRUPT_EXITTB) { if (interrupt_request & CPU_INTERRUPT_EXITTB) {
cpu->interrupt_request &= ~CPU_INTERRUPT_EXITTB; cpu->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
/* ensure that no TB jump will be modified as /* ensure that no TB jump will be modified as
@ -881,6 +863,15 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb,
#endif #endif
} }
//// --- Begin LibAFL code ---
TranslationBlock *libafl_gen_edge(CPUState *cpu, target_ulong src_block,
target_ulong dst_block, target_ulong cs_base,
uint32_t flags, int cflags);
void libafl_exec_edge_one_off(target_ulong src_block, target_ulong dst_block);
//// --- End LibAFL code ---
/* main execution loop */ /* main execution loop */
int cpu_exec(CPUState *cpu) int cpu_exec(CPUState *cpu)
@ -929,7 +920,6 @@ int cpu_exec(CPUState *cpu)
#endif #endif
#ifndef CONFIG_SOFTMMU #ifndef CONFIG_SOFTMMU
clear_helper_retaddr();
tcg_debug_assert(!have_mmap_lock()); tcg_debug_assert(!have_mmap_lock());
#endif #endif
if (qemu_mutex_iothread_locked()) { if (qemu_mutex_iothread_locked()) {
@ -981,6 +971,12 @@ int cpu_exec(CPUState *cpu)
*/ */
qatomic_set(&cpu->tb_jmp_cache[tb_jmp_cache_hash_func(pc)], tb); qatomic_set(&cpu->tb_jmp_cache[tb_jmp_cache_hash_func(pc)], tb);
} }
//// --- Begin LibAFL code ---
// This will save an edge (0,pc) after interrupts
// if (!last_tb) {
// libafl_exec_edge_one_off(0, tb->pc);
// }
//// --- End LibAFL code ---
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
/* /*
@ -995,7 +991,27 @@ int cpu_exec(CPUState *cpu)
#endif #endif
/* See if we can patch the calling TB. */ /* See if we can patch the calling TB. */
if (last_tb) { if (last_tb) {
tb_add_jump(last_tb, tb_exit, tb); // tb_add_jump(last_tb, tb_exit, tb);
//// --- Begin LibAFL code ---
if (last_tb->jmp_reset_offset[1] != TB_JMP_RESET_OFFSET_INVALID) {
mmap_lock();
TranslationBlock *edge = libafl_gen_edge(cpu, last_tb->pc, tb->pc,
cs_base, flags, cflags);
mmap_unlock();
if (edge) {
tb_add_jump(last_tb, tb_exit, edge);
tb_add_jump(edge, 0, tb);
} else {
tb_add_jump(last_tb, tb_exit, tb);
}
} else {
tb_add_jump(last_tb, tb_exit, tb);
}
//// --- End LibAFL code ---
} }
cpu_loop_exec_tb(cpu, tb, &last_tb, &tb_exit); cpu_loop_exec_tb(cpu, tb, &last_tb, &tb_exit);
@ -1042,52 +1058,23 @@ void tcg_exec_unrealizefn(CPUState *cpu)
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
void dump_drift_info(GString *buf) void dump_drift_info(void)
{ {
if (!icount_enabled()) { if (!icount_enabled()) {
return; return;
} }
g_string_append_printf(buf, "Host - Guest clock %"PRIi64" ms\n", qemu_printf("Host - Guest clock %"PRIi64" ms\n",
(cpu_get_clock() - icount_get()) / SCALE_MS); (cpu_get_clock() - icount_get()) / SCALE_MS);
if (icount_align_option) { if (icount_align_option) {
g_string_append_printf(buf, "Max guest delay %"PRIi64" ms\n", qemu_printf("Max guest delay %"PRIi64" ms\n",
-max_delay / SCALE_MS); -max_delay / SCALE_MS);
g_string_append_printf(buf, "Max guest advance %"PRIi64" ms\n", qemu_printf("Max guest advance %"PRIi64" ms\n",
max_advance / SCALE_MS); max_advance / SCALE_MS);
} else { } else {
g_string_append_printf(buf, "Max guest delay NA\n"); qemu_printf("Max guest delay NA\n");
g_string_append_printf(buf, "Max guest advance NA\n"); qemu_printf("Max guest advance NA\n");
} }
} }
HumanReadableText *qmp_x_query_jit(Error **errp)
{
g_autoptr(GString) buf = g_string_new("");
if (!tcg_enabled()) {
error_setg(errp, "JIT information is only available with accel=tcg");
return NULL;
}
dump_exec_info(buf);
dump_drift_info(buf);
return human_readable_text_from_str(buf);
}
HumanReadableText *qmp_x_query_opcount(Error **errp)
{
g_autoptr(GString) buf = g_string_new("");
if (!tcg_enabled()) {
error_setg(errp, "Opcode count information is only available with accel=tcg");
return NULL;
}
dump_opcount_info(buf);
return human_readable_text_from_str(buf);
}
#endif /* !CONFIG_USER_ONLY */ #endif /* !CONFIG_USER_ONLY */

View File

@ -34,12 +34,12 @@
#include "qemu/atomic128.h" #include "qemu/atomic128.h"
#include "exec/translate-all.h" #include "exec/translate-all.h"
#include "trace/trace-root.h" #include "trace/trace-root.h"
#include "trace/mem.h"
#include "tb-hash.h" #include "tb-hash.h"
#include "internal.h" #include "internal.h"
#ifdef CONFIG_PLUGIN #ifdef CONFIG_PLUGIN
#include "qemu/plugin-memory.h" #include "qemu/plugin-memory.h"
#endif #endif
#include "tcg/tcg-ldst.h"
/* DEBUG defines, enable DEBUG_TLB_LOG to log to the CPU_LOG_MMU target */ /* DEBUG defines, enable DEBUG_TLB_LOG to log to the CPU_LOG_MMU target */
/* #define DEBUG_TLB */ /* #define DEBUG_TLB */
@ -1749,7 +1749,7 @@ bool tlb_plugin_lookup(CPUState *cpu, target_ulong addr, int mmu_idx,
* @prot may be PAGE_READ, PAGE_WRITE, or PAGE_READ|PAGE_WRITE. * @prot may be PAGE_READ, PAGE_WRITE, or PAGE_READ|PAGE_WRITE.
*/ */
static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr, static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr,
MemOpIdx oi, int size, int prot, TCGMemOpIdx oi, int size, int prot,
uintptr_t retaddr) uintptr_t retaddr)
{ {
size_t mmu_idx = get_mmuidx(oi); size_t mmu_idx = get_mmuidx(oi);
@ -1840,25 +1840,6 @@ static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr,
cpu_loop_exit_atomic(env_cpu(env), retaddr); cpu_loop_exit_atomic(env_cpu(env), retaddr);
} }
/*
* Verify that we have passed the correct MemOp to the correct function.
*
* In the case of the helper_*_mmu functions, we will have done this by
* using the MemOp to look up the helper during code generation.
*
* In the case of the cpu_*_mmu functions, this is up to the caller.
* We could present one function to target code, and dispatch based on
* the MemOp, but so far we have worked hard to avoid an indirect function
* call along the memory path.
*/
static void validate_memop(MemOpIdx oi, MemOp expected)
{
#ifdef CONFIG_DEBUG_TCG
MemOp have = get_memop(oi) & (MO_SIZE | MO_BSWAP);
assert(have == expected);
#endif
}
/* /*
* Load Helpers * Load Helpers
* *
@ -1869,7 +1850,7 @@ static void validate_memop(MemOpIdx oi, MemOp expected)
*/ */
typedef uint64_t FullLoadHelper(CPUArchState *env, target_ulong addr, typedef uint64_t FullLoadHelper(CPUArchState *env, target_ulong addr,
MemOpIdx oi, uintptr_t retaddr); TCGMemOpIdx oi, uintptr_t retaddr);
static inline uint64_t QEMU_ALWAYS_INLINE static inline uint64_t QEMU_ALWAYS_INLINE
load_memop(const void *haddr, MemOp op) load_memop(const void *haddr, MemOp op)
@ -1895,7 +1876,7 @@ load_memop(const void *haddr, MemOp op)
} }
static inline uint64_t QEMU_ALWAYS_INLINE static inline uint64_t QEMU_ALWAYS_INLINE
load_helper(CPUArchState *env, target_ulong addr, MemOpIdx oi, load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi,
uintptr_t retaddr, MemOp op, bool code_read, uintptr_t retaddr, MemOp op, bool code_read,
FullLoadHelper *full_load) FullLoadHelper *full_load)
{ {
@ -2010,86 +1991,79 @@ load_helper(CPUArchState *env, target_ulong addr, MemOpIdx oi,
*/ */
static uint64_t full_ldub_mmu(CPUArchState *env, target_ulong addr, static uint64_t full_ldub_mmu(CPUArchState *env, target_ulong addr,
MemOpIdx oi, uintptr_t retaddr) TCGMemOpIdx oi, uintptr_t retaddr)
{ {
validate_memop(oi, MO_UB);
return load_helper(env, addr, oi, retaddr, MO_UB, false, full_ldub_mmu); return load_helper(env, addr, oi, retaddr, MO_UB, false, full_ldub_mmu);
} }
tcg_target_ulong helper_ret_ldub_mmu(CPUArchState *env, target_ulong addr, tcg_target_ulong helper_ret_ldub_mmu(CPUArchState *env, target_ulong addr,
MemOpIdx oi, uintptr_t retaddr) TCGMemOpIdx oi, uintptr_t retaddr)
{ {
return full_ldub_mmu(env, addr, oi, retaddr); return full_ldub_mmu(env, addr, oi, retaddr);
} }
static uint64_t full_le_lduw_mmu(CPUArchState *env, target_ulong addr, static uint64_t full_le_lduw_mmu(CPUArchState *env, target_ulong addr,
MemOpIdx oi, uintptr_t retaddr) TCGMemOpIdx oi, uintptr_t retaddr)
{ {
validate_memop(oi, MO_LEUW);
return load_helper(env, addr, oi, retaddr, MO_LEUW, false, return load_helper(env, addr, oi, retaddr, MO_LEUW, false,
full_le_lduw_mmu); full_le_lduw_mmu);
} }
tcg_target_ulong helper_le_lduw_mmu(CPUArchState *env, target_ulong addr, tcg_target_ulong helper_le_lduw_mmu(CPUArchState *env, target_ulong addr,
MemOpIdx oi, uintptr_t retaddr) TCGMemOpIdx oi, uintptr_t retaddr)
{ {
return full_le_lduw_mmu(env, addr, oi, retaddr); return full_le_lduw_mmu(env, addr, oi, retaddr);
} }
static uint64_t full_be_lduw_mmu(CPUArchState *env, target_ulong addr, static uint64_t full_be_lduw_mmu(CPUArchState *env, target_ulong addr,
MemOpIdx oi, uintptr_t retaddr) TCGMemOpIdx oi, uintptr_t retaddr)
{ {
validate_memop(oi, MO_BEUW);
return load_helper(env, addr, oi, retaddr, MO_BEUW, false, return load_helper(env, addr, oi, retaddr, MO_BEUW, false,
full_be_lduw_mmu); full_be_lduw_mmu);
} }
tcg_target_ulong helper_be_lduw_mmu(CPUArchState *env, target_ulong addr, tcg_target_ulong helper_be_lduw_mmu(CPUArchState *env, target_ulong addr,
MemOpIdx oi, uintptr_t retaddr) TCGMemOpIdx oi, uintptr_t retaddr)
{ {
return full_be_lduw_mmu(env, addr, oi, retaddr); return full_be_lduw_mmu(env, addr, oi, retaddr);
} }
static uint64_t full_le_ldul_mmu(CPUArchState *env, target_ulong addr, static uint64_t full_le_ldul_mmu(CPUArchState *env, target_ulong addr,
MemOpIdx oi, uintptr_t retaddr) TCGMemOpIdx oi, uintptr_t retaddr)
{ {
validate_memop(oi, MO_LEUL);
return load_helper(env, addr, oi, retaddr, MO_LEUL, false, return load_helper(env, addr, oi, retaddr, MO_LEUL, false,
full_le_ldul_mmu); full_le_ldul_mmu);
} }
tcg_target_ulong helper_le_ldul_mmu(CPUArchState *env, target_ulong addr, tcg_target_ulong helper_le_ldul_mmu(CPUArchState *env, target_ulong addr,
MemOpIdx oi, uintptr_t retaddr) TCGMemOpIdx oi, uintptr_t retaddr)
{ {
return full_le_ldul_mmu(env, addr, oi, retaddr); return full_le_ldul_mmu(env, addr, oi, retaddr);
} }
static uint64_t full_be_ldul_mmu(CPUArchState *env, target_ulong addr, static uint64_t full_be_ldul_mmu(CPUArchState *env, target_ulong addr,
MemOpIdx oi, uintptr_t retaddr) TCGMemOpIdx oi, uintptr_t retaddr)
{ {
validate_memop(oi, MO_BEUL);
return load_helper(env, addr, oi, retaddr, MO_BEUL, false, return load_helper(env, addr, oi, retaddr, MO_BEUL, false,
full_be_ldul_mmu); full_be_ldul_mmu);
} }
tcg_target_ulong helper_be_ldul_mmu(CPUArchState *env, target_ulong addr, tcg_target_ulong helper_be_ldul_mmu(CPUArchState *env, target_ulong addr,
MemOpIdx oi, uintptr_t retaddr) TCGMemOpIdx oi, uintptr_t retaddr)
{ {
return full_be_ldul_mmu(env, addr, oi, retaddr); return full_be_ldul_mmu(env, addr, oi, retaddr);
} }
uint64_t helper_le_ldq_mmu(CPUArchState *env, target_ulong addr, uint64_t helper_le_ldq_mmu(CPUArchState *env, target_ulong addr,
MemOpIdx oi, uintptr_t retaddr) TCGMemOpIdx oi, uintptr_t retaddr)
{ {
validate_memop(oi, MO_LEQ);
return load_helper(env, addr, oi, retaddr, MO_LEQ, false, return load_helper(env, addr, oi, retaddr, MO_LEQ, false,
helper_le_ldq_mmu); helper_le_ldq_mmu);
} }
uint64_t helper_be_ldq_mmu(CPUArchState *env, target_ulong addr, uint64_t helper_be_ldq_mmu(CPUArchState *env, target_ulong addr,
MemOpIdx oi, uintptr_t retaddr) TCGMemOpIdx oi, uintptr_t retaddr)
{ {
validate_memop(oi, MO_BEQ);
return load_helper(env, addr, oi, retaddr, MO_BEQ, false, return load_helper(env, addr, oi, retaddr, MO_BEQ, false,
helper_be_ldq_mmu); helper_be_ldq_mmu);
} }
@ -2101,31 +2075,31 @@ uint64_t helper_be_ldq_mmu(CPUArchState *env, target_ulong addr,
tcg_target_ulong helper_ret_ldsb_mmu(CPUArchState *env, target_ulong addr, tcg_target_ulong helper_ret_ldsb_mmu(CPUArchState *env, target_ulong addr,
MemOpIdx oi, uintptr_t retaddr) TCGMemOpIdx oi, uintptr_t retaddr)
{ {
return (int8_t)helper_ret_ldub_mmu(env, addr, oi, retaddr); return (int8_t)helper_ret_ldub_mmu(env, addr, oi, retaddr);
} }
tcg_target_ulong helper_le_ldsw_mmu(CPUArchState *env, target_ulong addr, tcg_target_ulong helper_le_ldsw_mmu(CPUArchState *env, target_ulong addr,
MemOpIdx oi, uintptr_t retaddr) TCGMemOpIdx oi, uintptr_t retaddr)
{ {
return (int16_t)helper_le_lduw_mmu(env, addr, oi, retaddr); return (int16_t)helper_le_lduw_mmu(env, addr, oi, retaddr);
} }
tcg_target_ulong helper_be_ldsw_mmu(CPUArchState *env, target_ulong addr, tcg_target_ulong helper_be_ldsw_mmu(CPUArchState *env, target_ulong addr,
MemOpIdx oi, uintptr_t retaddr) TCGMemOpIdx oi, uintptr_t retaddr)
{ {
return (int16_t)helper_be_lduw_mmu(env, addr, oi, retaddr); return (int16_t)helper_be_lduw_mmu(env, addr, oi, retaddr);
} }
tcg_target_ulong helper_le_ldsl_mmu(CPUArchState *env, target_ulong addr, tcg_target_ulong helper_le_ldsl_mmu(CPUArchState *env, target_ulong addr,
MemOpIdx oi, uintptr_t retaddr) TCGMemOpIdx oi, uintptr_t retaddr)
{ {
return (int32_t)helper_le_ldul_mmu(env, addr, oi, retaddr); return (int32_t)helper_le_ldul_mmu(env, addr, oi, retaddr);
} }
tcg_target_ulong helper_be_ldsl_mmu(CPUArchState *env, target_ulong addr, tcg_target_ulong helper_be_ldsl_mmu(CPUArchState *env, target_ulong addr,
MemOpIdx oi, uintptr_t retaddr) TCGMemOpIdx oi, uintptr_t retaddr)
{ {
return (int32_t)helper_be_ldul_mmu(env, addr, oi, retaddr); return (int32_t)helper_be_ldul_mmu(env, addr, oi, retaddr);
} }
@ -2135,56 +2109,193 @@ tcg_target_ulong helper_be_ldsl_mmu(CPUArchState *env, target_ulong addr,
*/ */
static inline uint64_t cpu_load_helper(CPUArchState *env, abi_ptr addr, static inline uint64_t cpu_load_helper(CPUArchState *env, abi_ptr addr,
MemOpIdx oi, uintptr_t retaddr, int mmu_idx, uintptr_t retaddr,
FullLoadHelper *full_load) MemOp op, FullLoadHelper *full_load)
{ {
uint16_t meminfo;
TCGMemOpIdx oi;
uint64_t ret; uint64_t ret;
trace_guest_ld_before_exec(env_cpu(env), addr, oi); meminfo = trace_mem_get_info(op, mmu_idx, false);
trace_guest_mem_before_exec(env_cpu(env), addr, meminfo);
op &= ~MO_SIGN;
oi = make_memop_idx(op, mmu_idx);
ret = full_load(env, addr, oi, retaddr); ret = full_load(env, addr, oi, retaddr);
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_R);
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, meminfo);
return ret; return ret;
} }
uint8_t cpu_ldb_mmu(CPUArchState *env, abi_ptr addr, MemOpIdx oi, uintptr_t ra) uint32_t cpu_ldub_mmuidx_ra(CPUArchState *env, abi_ptr addr,
int mmu_idx, uintptr_t ra)
{ {
return cpu_load_helper(env, addr, oi, ra, full_ldub_mmu); return cpu_load_helper(env, addr, mmu_idx, ra, MO_UB, full_ldub_mmu);
} }
uint16_t cpu_ldw_be_mmu(CPUArchState *env, abi_ptr addr, int cpu_ldsb_mmuidx_ra(CPUArchState *env, abi_ptr addr,
MemOpIdx oi, uintptr_t ra) int mmu_idx, uintptr_t ra)
{ {
return cpu_load_helper(env, addr, oi, ra, full_be_lduw_mmu); return (int8_t)cpu_load_helper(env, addr, mmu_idx, ra, MO_SB,
full_ldub_mmu);
} }
uint32_t cpu_ldl_be_mmu(CPUArchState *env, abi_ptr addr, uint32_t cpu_lduw_be_mmuidx_ra(CPUArchState *env, abi_ptr addr,
MemOpIdx oi, uintptr_t ra) int mmu_idx, uintptr_t ra)
{ {
return cpu_load_helper(env, addr, oi, ra, full_be_ldul_mmu); return cpu_load_helper(env, addr, mmu_idx, ra, MO_BEUW, full_be_lduw_mmu);
} }
uint64_t cpu_ldq_be_mmu(CPUArchState *env, abi_ptr addr, int cpu_ldsw_be_mmuidx_ra(CPUArchState *env, abi_ptr addr,
MemOpIdx oi, uintptr_t ra) int mmu_idx, uintptr_t ra)
{ {
return cpu_load_helper(env, addr, oi, MO_BEQ, helper_be_ldq_mmu); return (int16_t)cpu_load_helper(env, addr, mmu_idx, ra, MO_BESW,
full_be_lduw_mmu);
} }
uint16_t cpu_ldw_le_mmu(CPUArchState *env, abi_ptr addr, uint32_t cpu_ldl_be_mmuidx_ra(CPUArchState *env, abi_ptr addr,
MemOpIdx oi, uintptr_t ra) int mmu_idx, uintptr_t ra)
{ {
return cpu_load_helper(env, addr, oi, ra, full_le_lduw_mmu); return cpu_load_helper(env, addr, mmu_idx, ra, MO_BEUL, full_be_ldul_mmu);
} }
uint32_t cpu_ldl_le_mmu(CPUArchState *env, abi_ptr addr, uint64_t cpu_ldq_be_mmuidx_ra(CPUArchState *env, abi_ptr addr,
MemOpIdx oi, uintptr_t ra) int mmu_idx, uintptr_t ra)
{ {
return cpu_load_helper(env, addr, oi, ra, full_le_ldul_mmu); return cpu_load_helper(env, addr, mmu_idx, ra, MO_BEQ, helper_be_ldq_mmu);
} }
uint64_t cpu_ldq_le_mmu(CPUArchState *env, abi_ptr addr, uint32_t cpu_lduw_le_mmuidx_ra(CPUArchState *env, abi_ptr addr,
MemOpIdx oi, uintptr_t ra) int mmu_idx, uintptr_t ra)
{ {
return cpu_load_helper(env, addr, oi, ra, helper_le_ldq_mmu); return cpu_load_helper(env, addr, mmu_idx, ra, MO_LEUW, full_le_lduw_mmu);
}
int cpu_ldsw_le_mmuidx_ra(CPUArchState *env, abi_ptr addr,
int mmu_idx, uintptr_t ra)
{
return (int16_t)cpu_load_helper(env, addr, mmu_idx, ra, MO_LESW,
full_le_lduw_mmu);
}
uint32_t cpu_ldl_le_mmuidx_ra(CPUArchState *env, abi_ptr addr,
int mmu_idx, uintptr_t ra)
{
return cpu_load_helper(env, addr, mmu_idx, ra, MO_LEUL, full_le_ldul_mmu);
}
uint64_t cpu_ldq_le_mmuidx_ra(CPUArchState *env, abi_ptr addr,
int mmu_idx, uintptr_t ra)
{
return cpu_load_helper(env, addr, mmu_idx, ra, MO_LEQ, helper_le_ldq_mmu);
}
uint32_t cpu_ldub_data_ra(CPUArchState *env, target_ulong ptr,
uintptr_t retaddr)
{
return cpu_ldub_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr);
}
int cpu_ldsb_data_ra(CPUArchState *env, target_ulong ptr, uintptr_t retaddr)
{
return cpu_ldsb_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr);
}
uint32_t cpu_lduw_be_data_ra(CPUArchState *env, target_ulong ptr,
uintptr_t retaddr)
{
return cpu_lduw_be_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr);
}
int cpu_ldsw_be_data_ra(CPUArchState *env, target_ulong ptr, uintptr_t retaddr)
{
return cpu_ldsw_be_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr);
}
uint32_t cpu_ldl_be_data_ra(CPUArchState *env, target_ulong ptr,
uintptr_t retaddr)
{
return cpu_ldl_be_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr);
}
uint64_t cpu_ldq_be_data_ra(CPUArchState *env, target_ulong ptr,
uintptr_t retaddr)
{
return cpu_ldq_be_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr);
}
uint32_t cpu_lduw_le_data_ra(CPUArchState *env, target_ulong ptr,
uintptr_t retaddr)
{
return cpu_lduw_le_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr);
}
int cpu_ldsw_le_data_ra(CPUArchState *env, target_ulong ptr, uintptr_t retaddr)
{
return cpu_ldsw_le_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr);
}
uint32_t cpu_ldl_le_data_ra(CPUArchState *env, target_ulong ptr,
uintptr_t retaddr)
{
return cpu_ldl_le_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr);
}
uint64_t cpu_ldq_le_data_ra(CPUArchState *env, target_ulong ptr,
uintptr_t retaddr)
{
return cpu_ldq_le_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr);
}
uint32_t cpu_ldub_data(CPUArchState *env, target_ulong ptr)
{
return cpu_ldub_data_ra(env, ptr, 0);
}
int cpu_ldsb_data(CPUArchState *env, target_ulong ptr)
{
return cpu_ldsb_data_ra(env, ptr, 0);
}
uint32_t cpu_lduw_be_data(CPUArchState *env, target_ulong ptr)
{
return cpu_lduw_be_data_ra(env, ptr, 0);
}
int cpu_ldsw_be_data(CPUArchState *env, target_ulong ptr)
{
return cpu_ldsw_be_data_ra(env, ptr, 0);
}
uint32_t cpu_ldl_be_data(CPUArchState *env, target_ulong ptr)
{
return cpu_ldl_be_data_ra(env, ptr, 0);
}
uint64_t cpu_ldq_be_data(CPUArchState *env, target_ulong ptr)
{
return cpu_ldq_be_data_ra(env, ptr, 0);
}
uint32_t cpu_lduw_le_data(CPUArchState *env, target_ulong ptr)
{
return cpu_lduw_le_data_ra(env, ptr, 0);
}
int cpu_ldsw_le_data(CPUArchState *env, target_ulong ptr)
{
return cpu_ldsw_le_data_ra(env, ptr, 0);
}
uint32_t cpu_ldl_le_data(CPUArchState *env, target_ulong ptr)
{
return cpu_ldl_le_data_ra(env, ptr, 0);
}
uint64_t cpu_ldq_le_data(CPUArchState *env, target_ulong ptr)
{
return cpu_ldq_le_data_ra(env, ptr, 0);
} }
/* /*
@ -2221,9 +2332,6 @@ store_memop(void *haddr, uint64_t val, MemOp op)
} }
} }
static void full_stb_mmu(CPUArchState *env, target_ulong addr, uint64_t val,
MemOpIdx oi, uintptr_t retaddr);
static void __attribute__((noinline)) static void __attribute__((noinline))
store_helper_unaligned(CPUArchState *env, target_ulong addr, uint64_t val, store_helper_unaligned(CPUArchState *env, target_ulong addr, uint64_t val,
uintptr_t retaddr, size_t size, uintptr_t mmu_idx, uintptr_t retaddr, size_t size, uintptr_t mmu_idx,
@ -2233,7 +2341,7 @@ store_helper_unaligned(CPUArchState *env, target_ulong addr, uint64_t val,
uintptr_t index, index2; uintptr_t index, index2;
CPUTLBEntry *entry, *entry2; CPUTLBEntry *entry, *entry2;
target_ulong page2, tlb_addr, tlb_addr2; target_ulong page2, tlb_addr, tlb_addr2;
MemOpIdx oi; TCGMemOpIdx oi;
size_t size2; size_t size2;
int i; int i;
@ -2287,20 +2395,20 @@ store_helper_unaligned(CPUArchState *env, target_ulong addr, uint64_t val,
for (i = 0; i < size; ++i) { for (i = 0; i < size; ++i) {
/* Big-endian extract. */ /* Big-endian extract. */
uint8_t val8 = val >> (((size - 1) * 8) - (i * 8)); uint8_t val8 = val >> (((size - 1) * 8) - (i * 8));
full_stb_mmu(env, addr + i, val8, oi, retaddr); helper_ret_stb_mmu(env, addr + i, val8, oi, retaddr);
} }
} else { } else {
for (i = 0; i < size; ++i) { for (i = 0; i < size; ++i) {
/* Little-endian extract. */ /* Little-endian extract. */
uint8_t val8 = val >> (i * 8); uint8_t val8 = val >> (i * 8);
full_stb_mmu(env, addr + i, val8, oi, retaddr); helper_ret_stb_mmu(env, addr + i, val8, oi, retaddr);
} }
} }
} }
static inline void QEMU_ALWAYS_INLINE static inline void QEMU_ALWAYS_INLINE
store_helper(CPUArchState *env, target_ulong addr, uint64_t val, store_helper(CPUArchState *env, target_ulong addr, uint64_t val,
MemOpIdx oi, uintptr_t retaddr, MemOp op) TCGMemOpIdx oi, uintptr_t retaddr, MemOp op)
{ {
uintptr_t mmu_idx = get_mmuidx(oi); uintptr_t mmu_idx = get_mmuidx(oi);
uintptr_t index = tlb_index(env, mmu_idx, addr); uintptr_t index = tlb_index(env, mmu_idx, addr);
@ -2396,83 +2504,46 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val,
store_memop(haddr, val, op); store_memop(haddr, val, op);
} }
static void __attribute__((noinline)) void __attribute__((noinline))
full_stb_mmu(CPUArchState *env, target_ulong addr, uint64_t val, helper_ret_stb_mmu(CPUArchState *env, target_ulong addr, uint8_t val,
MemOpIdx oi, uintptr_t retaddr) TCGMemOpIdx oi, uintptr_t retaddr)
{ {
validate_memop(oi, MO_UB);
store_helper(env, addr, val, oi, retaddr, MO_UB); store_helper(env, addr, val, oi, retaddr, MO_UB);
} }
void helper_ret_stb_mmu(CPUArchState *env, target_ulong addr, uint8_t val, void helper_le_stw_mmu(CPUArchState *env, target_ulong addr, uint16_t val,
MemOpIdx oi, uintptr_t retaddr) TCGMemOpIdx oi, uintptr_t retaddr)
{ {
full_stb_mmu(env, addr, val, oi, retaddr);
}
static void full_le_stw_mmu(CPUArchState *env, target_ulong addr, uint64_t val,
MemOpIdx oi, uintptr_t retaddr)
{
validate_memop(oi, MO_LEUW);
store_helper(env, addr, val, oi, retaddr, MO_LEUW); store_helper(env, addr, val, oi, retaddr, MO_LEUW);
} }
void helper_le_stw_mmu(CPUArchState *env, target_ulong addr, uint16_t val, void helper_be_stw_mmu(CPUArchState *env, target_ulong addr, uint16_t val,
MemOpIdx oi, uintptr_t retaddr) TCGMemOpIdx oi, uintptr_t retaddr)
{ {
full_le_stw_mmu(env, addr, val, oi, retaddr);
}
static void full_be_stw_mmu(CPUArchState *env, target_ulong addr, uint64_t val,
MemOpIdx oi, uintptr_t retaddr)
{
validate_memop(oi, MO_BEUW);
store_helper(env, addr, val, oi, retaddr, MO_BEUW); store_helper(env, addr, val, oi, retaddr, MO_BEUW);
} }
void helper_be_stw_mmu(CPUArchState *env, target_ulong addr, uint16_t val, void helper_le_stl_mmu(CPUArchState *env, target_ulong addr, uint32_t val,
MemOpIdx oi, uintptr_t retaddr) TCGMemOpIdx oi, uintptr_t retaddr)
{ {
full_be_stw_mmu(env, addr, val, oi, retaddr);
}
static void full_le_stl_mmu(CPUArchState *env, target_ulong addr, uint64_t val,
MemOpIdx oi, uintptr_t retaddr)
{
validate_memop(oi, MO_LEUL);
store_helper(env, addr, val, oi, retaddr, MO_LEUL); store_helper(env, addr, val, oi, retaddr, MO_LEUL);
} }
void helper_le_stl_mmu(CPUArchState *env, target_ulong addr, uint32_t val, void helper_be_stl_mmu(CPUArchState *env, target_ulong addr, uint32_t val,
MemOpIdx oi, uintptr_t retaddr) TCGMemOpIdx oi, uintptr_t retaddr)
{ {
full_le_stl_mmu(env, addr, val, oi, retaddr);
}
static void full_be_stl_mmu(CPUArchState *env, target_ulong addr, uint64_t val,
MemOpIdx oi, uintptr_t retaddr)
{
validate_memop(oi, MO_BEUL);
store_helper(env, addr, val, oi, retaddr, MO_BEUL); store_helper(env, addr, val, oi, retaddr, MO_BEUL);
} }
void helper_be_stl_mmu(CPUArchState *env, target_ulong addr, uint32_t val,
MemOpIdx oi, uintptr_t retaddr)
{
full_be_stl_mmu(env, addr, val, oi, retaddr);
}
void helper_le_stq_mmu(CPUArchState *env, target_ulong addr, uint64_t val, void helper_le_stq_mmu(CPUArchState *env, target_ulong addr, uint64_t val,
MemOpIdx oi, uintptr_t retaddr) TCGMemOpIdx oi, uintptr_t retaddr)
{ {
validate_memop(oi, MO_LEQ);
store_helper(env, addr, val, oi, retaddr, MO_LEQ); store_helper(env, addr, val, oi, retaddr, MO_LEQ);
} }
void helper_be_stq_mmu(CPUArchState *env, target_ulong addr, uint64_t val, void helper_be_stq_mmu(CPUArchState *env, target_ulong addr, uint64_t val,
MemOpIdx oi, uintptr_t retaddr) TCGMemOpIdx oi, uintptr_t retaddr)
{ {
validate_memop(oi, MO_BEQ);
store_helper(env, addr, val, oi, retaddr, MO_BEQ); store_helper(env, addr, val, oi, retaddr, MO_BEQ);
} }
@ -2480,61 +2551,140 @@ void helper_be_stq_mmu(CPUArchState *env, target_ulong addr, uint64_t val,
* Store Helpers for cpu_ldst.h * Store Helpers for cpu_ldst.h
*/ */
typedef void FullStoreHelper(CPUArchState *env, target_ulong addr, static inline void QEMU_ALWAYS_INLINE
uint64_t val, MemOpIdx oi, uintptr_t retaddr); cpu_store_helper(CPUArchState *env, target_ulong addr, uint64_t val,
int mmu_idx, uintptr_t retaddr, MemOp op)
static inline void cpu_store_helper(CPUArchState *env, target_ulong addr,
uint64_t val, MemOpIdx oi, uintptr_t ra,
FullStoreHelper *full_store)
{ {
trace_guest_st_before_exec(env_cpu(env), addr, oi); TCGMemOpIdx oi;
full_store(env, addr, val, oi, ra); uint16_t meminfo;
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_W);
meminfo = trace_mem_get_info(op, mmu_idx, true);
trace_guest_mem_before_exec(env_cpu(env), addr, meminfo);
oi = make_memop_idx(op, mmu_idx);
store_helper(env, addr, val, oi, retaddr, op);
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, meminfo);
} }
void cpu_stb_mmu(CPUArchState *env, target_ulong addr, uint8_t val, void cpu_stb_mmuidx_ra(CPUArchState *env, target_ulong addr, uint32_t val,
MemOpIdx oi, uintptr_t retaddr) int mmu_idx, uintptr_t retaddr)
{ {
cpu_store_helper(env, addr, val, oi, retaddr, full_stb_mmu); cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_UB);
} }
void cpu_stw_be_mmu(CPUArchState *env, target_ulong addr, uint16_t val, void cpu_stw_be_mmuidx_ra(CPUArchState *env, target_ulong addr, uint32_t val,
MemOpIdx oi, uintptr_t retaddr) int mmu_idx, uintptr_t retaddr)
{ {
cpu_store_helper(env, addr, val, oi, retaddr, full_be_stw_mmu); cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_BEUW);
} }
void cpu_stl_be_mmu(CPUArchState *env, target_ulong addr, uint32_t val, void cpu_stl_be_mmuidx_ra(CPUArchState *env, target_ulong addr, uint32_t val,
MemOpIdx oi, uintptr_t retaddr) int mmu_idx, uintptr_t retaddr)
{ {
cpu_store_helper(env, addr, val, oi, retaddr, full_be_stl_mmu); cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_BEUL);
} }
void cpu_stq_be_mmu(CPUArchState *env, target_ulong addr, uint64_t val, void cpu_stq_be_mmuidx_ra(CPUArchState *env, target_ulong addr, uint64_t val,
MemOpIdx oi, uintptr_t retaddr) int mmu_idx, uintptr_t retaddr)
{ {
cpu_store_helper(env, addr, val, oi, retaddr, helper_be_stq_mmu); cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_BEQ);
} }
void cpu_stw_le_mmu(CPUArchState *env, target_ulong addr, uint16_t val, void cpu_stw_le_mmuidx_ra(CPUArchState *env, target_ulong addr, uint32_t val,
MemOpIdx oi, uintptr_t retaddr) int mmu_idx, uintptr_t retaddr)
{ {
cpu_store_helper(env, addr, val, oi, retaddr, full_le_stw_mmu); cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_LEUW);
} }
void cpu_stl_le_mmu(CPUArchState *env, target_ulong addr, uint32_t val, void cpu_stl_le_mmuidx_ra(CPUArchState *env, target_ulong addr, uint32_t val,
MemOpIdx oi, uintptr_t retaddr) int mmu_idx, uintptr_t retaddr)
{ {
cpu_store_helper(env, addr, val, oi, retaddr, full_le_stl_mmu); cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_LEUL);
} }
void cpu_stq_le_mmu(CPUArchState *env, target_ulong addr, uint64_t val, void cpu_stq_le_mmuidx_ra(CPUArchState *env, target_ulong addr, uint64_t val,
MemOpIdx oi, uintptr_t retaddr) int mmu_idx, uintptr_t retaddr)
{ {
cpu_store_helper(env, addr, val, oi, retaddr, helper_le_stq_mmu); cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_LEQ);
} }
#include "ldst_common.c.inc" void cpu_stb_data_ra(CPUArchState *env, target_ulong ptr,
uint32_t val, uintptr_t retaddr)
{
cpu_stb_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr);
}
void cpu_stw_be_data_ra(CPUArchState *env, target_ulong ptr,
uint32_t val, uintptr_t retaddr)
{
cpu_stw_be_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr);
}
void cpu_stl_be_data_ra(CPUArchState *env, target_ulong ptr,
uint32_t val, uintptr_t retaddr)
{
cpu_stl_be_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr);
}
void cpu_stq_be_data_ra(CPUArchState *env, target_ulong ptr,
uint64_t val, uintptr_t retaddr)
{
cpu_stq_be_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr);
}
void cpu_stw_le_data_ra(CPUArchState *env, target_ulong ptr,
uint32_t val, uintptr_t retaddr)
{
cpu_stw_le_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr);
}
void cpu_stl_le_data_ra(CPUArchState *env, target_ulong ptr,
uint32_t val, uintptr_t retaddr)
{
cpu_stl_le_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr);
}
void cpu_stq_le_data_ra(CPUArchState *env, target_ulong ptr,
uint64_t val, uintptr_t retaddr)
{
cpu_stq_le_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr);
}
void cpu_stb_data(CPUArchState *env, target_ulong ptr, uint32_t val)
{
cpu_stb_data_ra(env, ptr, val, 0);
}
void cpu_stw_be_data(CPUArchState *env, target_ulong ptr, uint32_t val)
{
cpu_stw_be_data_ra(env, ptr, val, 0);
}
void cpu_stl_be_data(CPUArchState *env, target_ulong ptr, uint32_t val)
{
cpu_stl_be_data_ra(env, ptr, val, 0);
}
void cpu_stq_be_data(CPUArchState *env, target_ulong ptr, uint64_t val)
{
cpu_stq_be_data_ra(env, ptr, val, 0);
}
void cpu_stw_le_data(CPUArchState *env, target_ulong ptr, uint32_t val)
{
cpu_stw_le_data_ra(env, ptr, val, 0);
}
void cpu_stl_le_data(CPUArchState *env, target_ulong ptr, uint32_t val)
{
cpu_stl_le_data_ra(env, ptr, val, 0);
}
void cpu_stq_le_data(CPUArchState *env, target_ulong ptr, uint64_t val)
{
cpu_stq_le_data_ra(env, ptr, val, 0);
}
/* /*
* First set of functions passes in OI and RETADDR. * First set of functions passes in OI and RETADDR.
@ -2571,49 +2721,49 @@ void cpu_stq_le_mmu(CPUArchState *env, target_ulong addr, uint64_t val,
/* Code access functions. */ /* Code access functions. */
static uint64_t full_ldub_code(CPUArchState *env, target_ulong addr, static uint64_t full_ldub_code(CPUArchState *env, target_ulong addr,
MemOpIdx oi, uintptr_t retaddr) TCGMemOpIdx oi, uintptr_t retaddr)
{ {
return load_helper(env, addr, oi, retaddr, MO_8, true, full_ldub_code); return load_helper(env, addr, oi, retaddr, MO_8, true, full_ldub_code);
} }
uint32_t cpu_ldub_code(CPUArchState *env, abi_ptr addr) uint32_t cpu_ldub_code(CPUArchState *env, abi_ptr addr)
{ {
MemOpIdx oi = make_memop_idx(MO_UB, cpu_mmu_index(env, true)); TCGMemOpIdx oi = make_memop_idx(MO_UB, cpu_mmu_index(env, true));
return full_ldub_code(env, addr, oi, 0); return full_ldub_code(env, addr, oi, 0);
} }
static uint64_t full_lduw_code(CPUArchState *env, target_ulong addr, static uint64_t full_lduw_code(CPUArchState *env, target_ulong addr,
MemOpIdx oi, uintptr_t retaddr) TCGMemOpIdx oi, uintptr_t retaddr)
{ {
return load_helper(env, addr, oi, retaddr, MO_TEUW, true, full_lduw_code); return load_helper(env, addr, oi, retaddr, MO_TEUW, true, full_lduw_code);
} }
uint32_t cpu_lduw_code(CPUArchState *env, abi_ptr addr) uint32_t cpu_lduw_code(CPUArchState *env, abi_ptr addr)
{ {
MemOpIdx oi = make_memop_idx(MO_TEUW, cpu_mmu_index(env, true)); TCGMemOpIdx oi = make_memop_idx(MO_TEUW, cpu_mmu_index(env, true));
return full_lduw_code(env, addr, oi, 0); return full_lduw_code(env, addr, oi, 0);
} }
static uint64_t full_ldl_code(CPUArchState *env, target_ulong addr, static uint64_t full_ldl_code(CPUArchState *env, target_ulong addr,
MemOpIdx oi, uintptr_t retaddr) TCGMemOpIdx oi, uintptr_t retaddr)
{ {
return load_helper(env, addr, oi, retaddr, MO_TEUL, true, full_ldl_code); return load_helper(env, addr, oi, retaddr, MO_TEUL, true, full_ldl_code);
} }
uint32_t cpu_ldl_code(CPUArchState *env, abi_ptr addr) uint32_t cpu_ldl_code(CPUArchState *env, abi_ptr addr)
{ {
MemOpIdx oi = make_memop_idx(MO_TEUL, cpu_mmu_index(env, true)); TCGMemOpIdx oi = make_memop_idx(MO_TEUL, cpu_mmu_index(env, true));
return full_ldl_code(env, addr, oi, 0); return full_ldl_code(env, addr, oi, 0);
} }
static uint64_t full_ldq_code(CPUArchState *env, target_ulong addr, static uint64_t full_ldq_code(CPUArchState *env, target_ulong addr,
MemOpIdx oi, uintptr_t retaddr) TCGMemOpIdx oi, uintptr_t retaddr)
{ {
return load_helper(env, addr, oi, retaddr, MO_TEQ, true, full_ldq_code); return load_helper(env, addr, oi, retaddr, MO_TEQ, true, full_ldq_code);
} }
uint64_t cpu_ldq_code(CPUArchState *env, abi_ptr addr) uint64_t cpu_ldq_code(CPUArchState *env, abi_ptr addr)
{ {
MemOpIdx oi = make_memop_idx(MO_TEQ, cpu_mmu_index(env, true)); TCGMemOpIdx oi = make_memop_idx(MO_TEQ, cpu_mmu_index(env, true));
return full_ldq_code(env, addr, oi, 0); return full_ldq_code(env, addr, oi, 0);
} }

View File

@ -1,15 +1,29 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "qapi/error.h"
#include "qapi/qapi-commands-machine.h"
#include "exec/exec-all.h" #include "exec/exec-all.h"
#include "monitor/monitor.h" #include "monitor/monitor.h"
#include "sysemu/tcg.h" #include "sysemu/tcg.h"
static void hmp_info_jit(Monitor *mon, const QDict *qdict)
{
if (!tcg_enabled()) {
error_report("JIT information is only available with accel=tcg");
return;
}
dump_exec_info();
dump_drift_info();
}
static void hmp_info_opcount(Monitor *mon, const QDict *qdict)
{
dump_opcount_info();
}
static void hmp_tcg_register(void) static void hmp_tcg_register(void)
{ {
monitor_register_hmp_info_hrt("jit", qmp_x_query_jit); monitor_register_hmp("jit", true, hmp_info_jit);
monitor_register_hmp_info_hrt("opcount", qmp_x_query_opcount); monitor_register_hmp("opcount", true, hmp_info_opcount);
} }
type_init(hmp_tcg_register); type_init(hmp_tcg_register);

View File

@ -1,307 +0,0 @@
/*
* Routines common to user and system emulation of load/store.
*
* Copyright (c) 2003 Fabrice Bellard
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
uint32_t cpu_ldub_mmuidx_ra(CPUArchState *env, abi_ptr addr,
int mmu_idx, uintptr_t ra)
{
MemOpIdx oi = make_memop_idx(MO_UB, mmu_idx);
return cpu_ldb_mmu(env, addr, oi, ra);
}
int cpu_ldsb_mmuidx_ra(CPUArchState *env, abi_ptr addr,
int mmu_idx, uintptr_t ra)
{
return (int8_t)cpu_ldub_mmuidx_ra(env, addr, mmu_idx, ra);
}
uint32_t cpu_lduw_be_mmuidx_ra(CPUArchState *env, abi_ptr addr,
int mmu_idx, uintptr_t ra)
{
MemOpIdx oi = make_memop_idx(MO_BEUW | MO_UNALN, mmu_idx);
return cpu_ldw_be_mmu(env, addr, oi, ra);
}
int cpu_ldsw_be_mmuidx_ra(CPUArchState *env, abi_ptr addr,
int mmu_idx, uintptr_t ra)
{
return (int16_t)cpu_lduw_be_mmuidx_ra(env, addr, mmu_idx, ra);
}
uint32_t cpu_ldl_be_mmuidx_ra(CPUArchState *env, abi_ptr addr,
int mmu_idx, uintptr_t ra)
{
MemOpIdx oi = make_memop_idx(MO_BEUL | MO_UNALN, mmu_idx);
return cpu_ldl_be_mmu(env, addr, oi, ra);
}
uint64_t cpu_ldq_be_mmuidx_ra(CPUArchState *env, abi_ptr addr,
int mmu_idx, uintptr_t ra)
{
MemOpIdx oi = make_memop_idx(MO_BEQ | MO_UNALN, mmu_idx);
return cpu_ldq_be_mmu(env, addr, oi, ra);
}
uint32_t cpu_lduw_le_mmuidx_ra(CPUArchState *env, abi_ptr addr,
int mmu_idx, uintptr_t ra)
{
MemOpIdx oi = make_memop_idx(MO_LEUW | MO_UNALN, mmu_idx);
return cpu_ldw_le_mmu(env, addr, oi, ra);
}
int cpu_ldsw_le_mmuidx_ra(CPUArchState *env, abi_ptr addr,
int mmu_idx, uintptr_t ra)
{
return (int16_t)cpu_lduw_le_mmuidx_ra(env, addr, mmu_idx, ra);
}
uint32_t cpu_ldl_le_mmuidx_ra(CPUArchState *env, abi_ptr addr,
int mmu_idx, uintptr_t ra)
{
MemOpIdx oi = make_memop_idx(MO_LEUL | MO_UNALN, mmu_idx);
return cpu_ldl_le_mmu(env, addr, oi, ra);
}
uint64_t cpu_ldq_le_mmuidx_ra(CPUArchState *env, abi_ptr addr,
int mmu_idx, uintptr_t ra)
{
MemOpIdx oi = make_memop_idx(MO_LEQ | MO_UNALN, mmu_idx);
return cpu_ldq_le_mmu(env, addr, oi, ra);
}
void cpu_stb_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val,
int mmu_idx, uintptr_t ra)
{
MemOpIdx oi = make_memop_idx(MO_UB, mmu_idx);
cpu_stb_mmu(env, addr, val, oi, ra);
}
void cpu_stw_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val,
int mmu_idx, uintptr_t ra)
{
MemOpIdx oi = make_memop_idx(MO_BEUW | MO_UNALN, mmu_idx);
cpu_stw_be_mmu(env, addr, val, oi, ra);
}
void cpu_stl_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val,
int mmu_idx, uintptr_t ra)
{
MemOpIdx oi = make_memop_idx(MO_BEUL | MO_UNALN, mmu_idx);
cpu_stl_be_mmu(env, addr, val, oi, ra);
}
void cpu_stq_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint64_t val,
int mmu_idx, uintptr_t ra)
{
MemOpIdx oi = make_memop_idx(MO_BEQ | MO_UNALN, mmu_idx);
cpu_stq_be_mmu(env, addr, val, oi, ra);
}
void cpu_stw_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val,
int mmu_idx, uintptr_t ra)
{
MemOpIdx oi = make_memop_idx(MO_LEUW | MO_UNALN, mmu_idx);
cpu_stw_le_mmu(env, addr, val, oi, ra);
}
void cpu_stl_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val,
int mmu_idx, uintptr_t ra)
{
MemOpIdx oi = make_memop_idx(MO_LEUL | MO_UNALN, mmu_idx);
cpu_stl_le_mmu(env, addr, val, oi, ra);
}
void cpu_stq_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint64_t val,
int mmu_idx, uintptr_t ra)
{
MemOpIdx oi = make_memop_idx(MO_LEQ | MO_UNALN, mmu_idx);
cpu_stq_le_mmu(env, addr, val, oi, ra);
}
/*--------------------------*/
uint32_t cpu_ldub_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
{
return cpu_ldub_mmuidx_ra(env, addr, cpu_mmu_index(env, false), ra);
}
int cpu_ldsb_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
{
return (int8_t)cpu_ldub_data_ra(env, addr, ra);
}
uint32_t cpu_lduw_be_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
{
return cpu_lduw_be_mmuidx_ra(env, addr, cpu_mmu_index(env, false), ra);
}
int cpu_ldsw_be_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
{
return (int16_t)cpu_lduw_be_data_ra(env, addr, ra);
}
uint32_t cpu_ldl_be_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
{
return cpu_ldl_be_mmuidx_ra(env, addr, cpu_mmu_index(env, false), ra);
}
uint64_t cpu_ldq_be_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
{
return cpu_ldq_be_mmuidx_ra(env, addr, cpu_mmu_index(env, false), ra);
}
uint32_t cpu_lduw_le_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
{
return cpu_lduw_le_mmuidx_ra(env, addr, cpu_mmu_index(env, false), ra);
}
int cpu_ldsw_le_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
{
return (int16_t)cpu_lduw_le_data_ra(env, addr, ra);
}
uint32_t cpu_ldl_le_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
{
return cpu_ldl_le_mmuidx_ra(env, addr, cpu_mmu_index(env, false), ra);
}
uint64_t cpu_ldq_le_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra)
{
return cpu_ldq_le_mmuidx_ra(env, addr, cpu_mmu_index(env, false), ra);
}
void cpu_stb_data_ra(CPUArchState *env, abi_ptr addr,
uint32_t val, uintptr_t ra)
{
cpu_stb_mmuidx_ra(env, addr, val, cpu_mmu_index(env, false), ra);
}
void cpu_stw_be_data_ra(CPUArchState *env, abi_ptr addr,
uint32_t val, uintptr_t ra)
{
cpu_stw_be_mmuidx_ra(env, addr, val, cpu_mmu_index(env, false), ra);
}
void cpu_stl_be_data_ra(CPUArchState *env, abi_ptr addr,
uint32_t val, uintptr_t ra)
{
cpu_stl_be_mmuidx_ra(env, addr, val, cpu_mmu_index(env, false), ra);
}
void cpu_stq_be_data_ra(CPUArchState *env, abi_ptr addr,
uint64_t val, uintptr_t ra)
{
cpu_stq_be_mmuidx_ra(env, addr, val, cpu_mmu_index(env, false), ra);
}
void cpu_stw_le_data_ra(CPUArchState *env, abi_ptr addr,
uint32_t val, uintptr_t ra)
{
cpu_stw_le_mmuidx_ra(env, addr, val, cpu_mmu_index(env, false), ra);
}
void cpu_stl_le_data_ra(CPUArchState *env, abi_ptr addr,
uint32_t val, uintptr_t ra)
{
cpu_stl_le_mmuidx_ra(env, addr, val, cpu_mmu_index(env, false), ra);
}
void cpu_stq_le_data_ra(CPUArchState *env, abi_ptr addr,
uint64_t val, uintptr_t ra)
{
cpu_stq_le_mmuidx_ra(env, addr, val, cpu_mmu_index(env, false), ra);
}
/*--------------------------*/
uint32_t cpu_ldub_data(CPUArchState *env, abi_ptr addr)
{
return cpu_ldub_data_ra(env, addr, 0);
}
int cpu_ldsb_data(CPUArchState *env, abi_ptr addr)
{
return (int8_t)cpu_ldub_data(env, addr);
}
uint32_t cpu_lduw_be_data(CPUArchState *env, abi_ptr addr)
{
return cpu_lduw_be_data_ra(env, addr, 0);
}
int cpu_ldsw_be_data(CPUArchState *env, abi_ptr addr)
{
return (int16_t)cpu_lduw_be_data(env, addr);
}
uint32_t cpu_ldl_be_data(CPUArchState *env, abi_ptr addr)
{
return cpu_ldl_be_data_ra(env, addr, 0);
}
uint64_t cpu_ldq_be_data(CPUArchState *env, abi_ptr addr)
{
return cpu_ldq_be_data_ra(env, addr, 0);
}
uint32_t cpu_lduw_le_data(CPUArchState *env, abi_ptr addr)
{
return cpu_lduw_le_data_ra(env, addr, 0);
}
int cpu_ldsw_le_data(CPUArchState *env, abi_ptr addr)
{
return (int16_t)cpu_lduw_le_data(env, addr);
}
uint32_t cpu_ldl_le_data(CPUArchState *env, abi_ptr addr)
{
return cpu_ldl_le_data_ra(env, addr, 0);
}
uint64_t cpu_ldq_le_data(CPUArchState *env, abi_ptr addr)
{
return cpu_ldq_le_data_ra(env, addr, 0);
}
void cpu_stb_data(CPUArchState *env, abi_ptr addr, uint32_t val)
{
cpu_stb_data_ra(env, addr, val, 0);
}
void cpu_stw_be_data(CPUArchState *env, abi_ptr addr, uint32_t val)
{
cpu_stw_be_data_ra(env, addr, val, 0);
}
void cpu_stl_be_data(CPUArchState *env, abi_ptr addr, uint32_t val)
{
cpu_stl_be_data_ra(env, addr, val, 0);
}
void cpu_stq_be_data(CPUArchState *env, abi_ptr addr, uint64_t val)
{
cpu_stq_be_data_ra(env, addr, val, 0);
}
void cpu_stw_le_data(CPUArchState *env, abi_ptr addr, uint32_t val)
{
cpu_stw_le_data_ra(env, addr, val, 0);
}
void cpu_stl_le_data(CPUArchState *env, abi_ptr addr, uint32_t val)
{
cpu_stl_le_data_ra(env, addr, val, 0);
}
void cpu_stq_le_data(CPUArchState *env, abi_ptr addr, uint64_t val)
{
cpu_stq_le_data_ra(env, addr, val, 0);
}

View File

@ -10,7 +10,7 @@ tcg_ss.add(files(
)) ))
tcg_ss.add(when: 'CONFIG_USER_ONLY', if_true: files('user-exec.c')) tcg_ss.add(when: 'CONFIG_USER_ONLY', if_true: files('user-exec.c'))
tcg_ss.add(when: 'CONFIG_SOFTMMU', if_false: files('user-exec-stub.c')) tcg_ss.add(when: 'CONFIG_SOFTMMU', if_false: files('user-exec-stub.c'))
tcg_ss.add(when: 'CONFIG_PLUGIN', if_true: [files('plugin-gen.c')]) tcg_ss.add(when: 'CONFIG_PLUGIN', if_true: [files('plugin-gen.c'), libdl])
specific_ss.add_all(when: 'CONFIG_TCG', if_true: tcg_ss) specific_ss.add_all(when: 'CONFIG_TCG', if_true: tcg_ss)
specific_ss.add(when: ['CONFIG_SOFTMMU', 'CONFIG_TCG'], if_true: files( specific_ss.add(when: ['CONFIG_SOFTMMU', 'CONFIG_TCG'], if_true: files(

View File

@ -45,6 +45,7 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "tcg/tcg.h" #include "tcg/tcg.h"
#include "tcg/tcg-op.h" #include "tcg/tcg-op.h"
#include "trace/mem.h"
#include "exec/exec-all.h" #include "exec/exec-all.h"
#include "exec/plugin-gen.h" #include "exec/plugin-gen.h"
#include "exec/translator.h" #include "exec/translator.h"
@ -162,7 +163,11 @@ static void gen_empty_mem_helper(void)
static void gen_plugin_cb_start(enum plugin_gen_from from, static void gen_plugin_cb_start(enum plugin_gen_from from,
enum plugin_gen_cb type, unsigned wr) enum plugin_gen_cb type, unsigned wr)
{ {
TCGOp *op;
tcg_gen_plugin_cb_start(from, type, wr); tcg_gen_plugin_cb_start(from, type, wr);
op = tcg_last_op();
QSIMPLEQ_INSERT_TAIL(&tcg_ctx->plugin_ops, op, plugin_link);
} }
static void gen_wrapped(enum plugin_gen_from from, static void gen_wrapped(enum plugin_gen_from from,
@ -206,9 +211,9 @@ static void gen_mem_wrapped(enum plugin_gen_cb type,
const union mem_gen_fn *f, TCGv addr, const union mem_gen_fn *f, TCGv addr,
uint32_t info, bool is_mem) uint32_t info, bool is_mem)
{ {
enum qemu_plugin_mem_rw rw = get_plugin_meminfo_rw(info); int wr = !!(info & TRACE_MEM_ST);
gen_plugin_cb_start(PLUGIN_GEN_FROM_MEM, type, rw); gen_plugin_cb_start(PLUGIN_GEN_FROM_MEM, type, wr);
if (is_mem) { if (is_mem) {
f->mem_fn(addr, info); f->mem_fn(addr, info);
} else { } else {
@ -702,6 +707,62 @@ static void plugin_gen_disable_mem_helper(const struct qemu_plugin_tb *ptb,
inject_mem_disable_helper(insn, begin_op); inject_mem_disable_helper(insn, begin_op);
} }
static void plugin_inject_cb(const struct qemu_plugin_tb *ptb, TCGOp *begin_op,
int insn_idx)
{
enum plugin_gen_from from = begin_op->args[0];
enum plugin_gen_cb type = begin_op->args[1];
switch (from) {
case PLUGIN_GEN_FROM_TB:
switch (type) {
case PLUGIN_GEN_CB_UDATA:
plugin_gen_tb_udata(ptb, begin_op);
return;
case PLUGIN_GEN_CB_INLINE:
plugin_gen_tb_inline(ptb, begin_op);
return;
default:
g_assert_not_reached();
}
case PLUGIN_GEN_FROM_INSN:
switch (type) {
case PLUGIN_GEN_CB_UDATA:
plugin_gen_insn_udata(ptb, begin_op, insn_idx);
return;
case PLUGIN_GEN_CB_INLINE:
plugin_gen_insn_inline(ptb, begin_op, insn_idx);
return;
case PLUGIN_GEN_ENABLE_MEM_HELPER:
plugin_gen_enable_mem_helper(ptb, begin_op, insn_idx);
return;
default:
g_assert_not_reached();
}
case PLUGIN_GEN_FROM_MEM:
switch (type) {
case PLUGIN_GEN_CB_MEM:
plugin_gen_mem_regular(ptb, begin_op, insn_idx);
return;
case PLUGIN_GEN_CB_INLINE:
plugin_gen_mem_inline(ptb, begin_op, insn_idx);
return;
default:
g_assert_not_reached();
}
case PLUGIN_GEN_AFTER_INSN:
switch (type) {
case PLUGIN_GEN_DISABLE_MEM_HELPER:
plugin_gen_disable_mem_helper(ptb, begin_op, insn_idx);
return;
default:
g_assert_not_reached();
}
default:
g_assert_not_reached();
}
}
/* #define DEBUG_PLUGIN_GEN_OPS */ /* #define DEBUG_PLUGIN_GEN_OPS */
static void pr_ops(void) static void pr_ops(void)
{ {
@ -759,95 +820,21 @@ static void pr_ops(void)
static void plugin_gen_inject(const struct qemu_plugin_tb *plugin_tb) static void plugin_gen_inject(const struct qemu_plugin_tb *plugin_tb)
{ {
TCGOp *op; TCGOp *op;
int insn_idx = -1; int insn_idx;
pr_ops(); pr_ops();
insn_idx = -1;
QSIMPLEQ_FOREACH(op, &tcg_ctx->plugin_ops, plugin_link) {
enum plugin_gen_from from = op->args[0];
enum plugin_gen_cb type = op->args[1];
QTAILQ_FOREACH(op, &tcg_ctx->ops, link) { tcg_debug_assert(op->opc == INDEX_op_plugin_cb_start);
switch (op->opc) { /* ENABLE_MEM_HELPER is the first callback of an instruction */
case INDEX_op_insn_start: if (from == PLUGIN_GEN_FROM_INSN &&
type == PLUGIN_GEN_ENABLE_MEM_HELPER) {
insn_idx++; insn_idx++;
break;
case INDEX_op_plugin_cb_start:
{
enum plugin_gen_from from = op->args[0];
enum plugin_gen_cb type = op->args[1];
switch (from) {
case PLUGIN_GEN_FROM_TB:
{
g_assert(insn_idx == -1);
switch (type) {
case PLUGIN_GEN_CB_UDATA:
plugin_gen_tb_udata(plugin_tb, op);
break;
case PLUGIN_GEN_CB_INLINE:
plugin_gen_tb_inline(plugin_tb, op);
break;
default:
g_assert_not_reached();
}
break;
}
case PLUGIN_GEN_FROM_INSN:
{
g_assert(insn_idx >= 0);
switch (type) {
case PLUGIN_GEN_CB_UDATA:
plugin_gen_insn_udata(plugin_tb, op, insn_idx);
break;
case PLUGIN_GEN_CB_INLINE:
plugin_gen_insn_inline(plugin_tb, op, insn_idx);
break;
case PLUGIN_GEN_ENABLE_MEM_HELPER:
plugin_gen_enable_mem_helper(plugin_tb, op, insn_idx);
break;
default:
g_assert_not_reached();
}
break;
}
case PLUGIN_GEN_FROM_MEM:
{
g_assert(insn_idx >= 0);
switch (type) {
case PLUGIN_GEN_CB_MEM:
plugin_gen_mem_regular(plugin_tb, op, insn_idx);
break;
case PLUGIN_GEN_CB_INLINE:
plugin_gen_mem_inline(plugin_tb, op, insn_idx);
break;
default:
g_assert_not_reached();
}
break;
}
case PLUGIN_GEN_AFTER_INSN:
{
g_assert(insn_idx >= 0);
switch (type) {
case PLUGIN_GEN_DISABLE_MEM_HELPER:
plugin_gen_disable_mem_helper(plugin_tb, op, insn_idx);
break;
default:
g_assert_not_reached();
}
break;
}
default:
g_assert_not_reached();
}
break;
}
default:
/* plugins don't care about any other ops */
break;
} }
plugin_inject_cb(plugin_tb, op, insn_idx);
} }
pr_ops(); pr_ops();
} }
@ -860,6 +847,7 @@ bool plugin_gen_tb_start(CPUState *cpu, const TranslationBlock *tb, bool mem_onl
if (test_bit(QEMU_PLUGIN_EV_VCPU_TB_TRANS, cpu->plugin_mask)) { if (test_bit(QEMU_PLUGIN_EV_VCPU_TB_TRANS, cpu->plugin_mask)) {
ret = true; ret = true;
QSIMPLEQ_INIT(&tcg_ctx->plugin_ops);
ptb->vaddr = tb->pc; ptb->vaddr = tb->pc;
ptb->vaddr2 = -1; ptb->vaddr2 = -1;
get_page_addr_code_hostp(cpu->env_ptr, tb->pc, &ptb->haddr1); get_page_addr_code_hostp(cpu->env_ptr, tb->pc, &ptb->haddr1);
@ -876,8 +864,9 @@ void plugin_gen_insn_start(CPUState *cpu, const DisasContextBase *db)
struct qemu_plugin_tb *ptb = tcg_ctx->plugin_tb; struct qemu_plugin_tb *ptb = tcg_ctx->plugin_tb;
struct qemu_plugin_insn *pinsn; struct qemu_plugin_insn *pinsn;
pinsn = qemu_plugin_tb_insn_get(ptb, db->pc_next); pinsn = qemu_plugin_tb_insn_get(ptb);
tcg_ctx->plugin_insn = pinsn; tcg_ctx->plugin_insn = pinsn;
pinsn->vaddr = db->pc_next;
plugin_gen_empty_callback(PLUGIN_GEN_FROM_INSN); plugin_gen_empty_callback(PLUGIN_GEN_FROM_INSN);
/* /*

View File

@ -61,6 +61,8 @@ void rr_kick_vcpu_thread(CPUState *unused)
static QEMUTimer *rr_kick_vcpu_timer; static QEMUTimer *rr_kick_vcpu_timer;
static CPUState *rr_current_cpu; static CPUState *rr_current_cpu;
#define TCG_KICK_PERIOD (NANOSECONDS_PER_SECOND / 10)
static inline int64_t rr_next_kick_time(void) static inline int64_t rr_next_kick_time(void)
{ {
return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + TCG_KICK_PERIOD; return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + TCG_KICK_PERIOD;

View File

@ -31,6 +31,19 @@
#include "exec/log.h" #include "exec/log.h"
#include "tcg/tcg.h" #include "tcg/tcg.h"
//// --- Begin LibAFL code ---
#define EXCP_LIBAFL_BP 0xf4775747
void HELPER(libafl_qemu_handle_breakpoint)(CPUArchState *env)
{
CPUState* cpu = env_cpu(env);
cpu->exception_index = EXCP_LIBAFL_BP;
cpu_loop_exit(cpu);
}
//// --- End LibAFL code ---
/* 32-bit helpers */ /* 32-bit helpers */
int32_t HELPER(div_i32)(int32_t arg1, int32_t arg2) int32_t HELPER(div_i32)(int32_t arg1, int32_t arg2)

View File

@ -285,3 +285,9 @@ DEF_HELPER_FLAGS_4(gvec_leu32, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_4(gvec_leu64, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(gvec_leu64, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_5(gvec_bitsel, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_5(gvec_bitsel, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32)
//// --- Begin LibAFL code ---
DEF_HELPER_FLAGS_1(libafl_qemu_handle_breakpoint, TCG_CALL_NO_RWG, void, env)
//// --- End LibAFL code ---

View File

@ -61,6 +61,386 @@
#include "tb-context.h" #include "tb-context.h"
#include "internal.h" #include "internal.h"
//// --- Begin LibAFL code ---
#include "tcg/tcg-op.h"
#include "tcg/tcg-internal.h"
#include "exec/helper-head.h"
void libafl_helper_table_add(TCGHelperInfo* info);
void libafl_gen_jmp(target_ulong src, target_ulong dst);
void libafl_exec_edge_one_off(target_ulong src_block, target_ulong dst_block);
TranslationBlock *libafl_gen_edge(CPUState *cpu, target_ulong src_block,
target_ulong dst_block, target_ulong cs_base,
uint32_t flags, int cflags);
void libafl_gen_read(TCGv addr, MemOp ot);
void libafl_gen_read_N(TCGv addr, uint32_t size);
void libafl_gen_write(TCGv addr, MemOp ot);
void libafl_gen_write_N(TCGv addr, uint32_t size);
void libafl_gen_cmp(target_ulong pc, TCGv op0, TCGv op1, MemOp ot);
void (*libafl_exec_edge_hook)(uint64_t id);
uint64_t (*libafl_gen_edge_hook)(uint64_t src, uint64_t dst);
void (*libafl_exec_jmp_hook)(uint64_t src, uint64_t dst, uint64_t id);
uint64_t (*libafl_gen_jmp_hook)(uint64_t src, uint64_t dst);
static TCGHelperInfo libafl_exec_edge_hook_info = {
.func = NULL, .name = "libafl_exec_edge_hook", \
.flags = dh_callflag(void), \
.typemask = dh_typemask(void, 0) | dh_typemask(i64, 1)
};
static int exec_edge_hook_added = 0;
static TCGHelperInfo libafl_exec_jmp_hook_info = {
.func = NULL, .name = "libafl_exec_jmp_hook", \
.flags = dh_callflag(void), \
.typemask = dh_typemask(void, 0) | dh_typemask(i64, 3)
};
static int exec_jmp_hook_added = 0;
void (*libafl_exec_block_hook)(uint64_t id);
uint64_t (*libafl_gen_block_hook)(uint64_t pc);
static TCGHelperInfo libafl_exec_block_hook_info = {
.func = NULL, .name = "libafl_exec_block_hook", \
.flags = dh_callflag(void), \
.typemask = dh_typemask(void, 0) | dh_typemask(i64, 1)
};
static int exec_block_hook_added = 0;
void (*libafl_exec_read_hook1)(uint64_t id, uint64_t addr);
void (*libafl_exec_read_hook2)(uint64_t id, uint64_t addr);
void (*libafl_exec_read_hook4)(uint64_t id, uint64_t addr);
void (*libafl_exec_read_hook8)(uint64_t id, uint64_t addr);
void (*libafl_exec_read_hookN)(uint64_t id, uint64_t addr, uint32_t size);
uint64_t (*libafl_gen_read_hook)(uint32_t size);
static TCGHelperInfo libafl_exec_read_hook1_info = {
.func = NULL, .name = "libafl_exec_read_hook1", \
.flags = dh_callflag(void), \
.typemask = dh_typemask(void, 0) | dh_typemask(tl, 1)
};
static TCGHelperInfo libafl_exec_read_hook2_info = {
.func = NULL, .name = "libafl_exec_read_hook2", \
.flags = dh_callflag(void), \
.typemask = dh_typemask(void, 0) | dh_typemask(tl, 1)
};
static TCGHelperInfo libafl_exec_read_hook4_info = {
.func = NULL, .name = "libafl_exec_read_hook4", \
.flags = dh_callflag(void), \
.typemask = dh_typemask(void, 0) | dh_typemask(tl, 1)
};
static TCGHelperInfo libafl_exec_read_hook8_info = {
.func = NULL, .name = "libafl_exec_read_hook8", \
.flags = dh_callflag(void), \
.typemask = dh_typemask(void, 0) | dh_typemask(tl, 1)
};
static TCGHelperInfo libafl_exec_read_hookN_info = {
.func = NULL, .name = "libafl_exec_read_hookN", \
.flags = dh_callflag(void), \
.typemask = dh_typemask(void, 0) | dh_typemask(tl, 1) | dh_typemask(i32, 2)
};
static int exec_read_hook_added = 0;
void libafl_gen_read(TCGv addr, MemOp ot)
{
uint32_t size = 0;
void* func = NULL;
switch (ot & MO_SIZE) {
case MO_64:
size = 8;
func = libafl_exec_read_hook8;
break;
case MO_32:
size = 4;
func = libafl_exec_read_hook4;
break;
case MO_16:
size = 2;
func = libafl_exec_read_hook2;
break;
case MO_8:
size = 1;
func = libafl_exec_read_hook1;
break;
default:
return;
}
uint32_t libafl_id = 0;
if (libafl_gen_read_hook)
libafl_id = libafl_gen_read_hook(size);
if (func && libafl_id != (uint32_t)-1) {
if (!exec_read_hook_added) {
exec_read_hook_added = 1;
libafl_exec_read_hook1_info.func = libafl_exec_read_hook1;
libafl_helper_table_add(&libafl_exec_read_hook1_info);
libafl_exec_read_hook2_info.func = libafl_exec_read_hook2;
libafl_helper_table_add(&libafl_exec_read_hook2_info);
libafl_exec_read_hook4_info.func = libafl_exec_read_hook4;
libafl_helper_table_add(&libafl_exec_read_hook4_info);
libafl_exec_read_hook8_info.func = libafl_exec_read_hook8;
libafl_helper_table_add(&libafl_exec_read_hook8_info);
libafl_exec_read_hookN_info.func = libafl_exec_read_hookN;
libafl_helper_table_add(&libafl_exec_read_hookN_info);
}
TCGv_i64 tmp0 = tcg_const_i64(libafl_id);
TCGTemp *tmp1[2] = { tcgv_i64_temp(tmp0),
#if TARGET_LONG_BITS == 32
tcgv_i32_temp(addr) };
#else
tcgv_i64_temp(addr) };
#endif
tcg_gen_callN(func, NULL, 2, tmp1);
tcg_temp_free_i64(tmp0);
}
}
void libafl_gen_read_N(TCGv addr, uint32_t size)
{
uint32_t libafl_id = 0;
if (libafl_gen_read_hook)
libafl_id = libafl_gen_read_hook(size);
if (libafl_id != (uint32_t)-1) {
if (!exec_read_hook_added) {
exec_read_hook_added = 1;
libafl_exec_read_hook1_info.func = libafl_exec_read_hook1;
libafl_helper_table_add(&libafl_exec_read_hook1_info);
libafl_exec_read_hook2_info.func = libafl_exec_read_hook2;
libafl_helper_table_add(&libafl_exec_read_hook2_info);
libafl_exec_read_hook4_info.func = libafl_exec_read_hook4;
libafl_helper_table_add(&libafl_exec_read_hook4_info);
libafl_exec_read_hook8_info.func = libafl_exec_read_hook8;
libafl_helper_table_add(&libafl_exec_read_hook8_info);
libafl_exec_read_hookN_info.func = libafl_exec_read_hookN;
libafl_helper_table_add(&libafl_exec_read_hookN_info);
}
TCGv_i64 tmp0 = tcg_const_i64(libafl_id);
TCGv_i32 tmp1 = tcg_const_i32(size);
TCGTemp *tmp2[3] = { tcgv_i64_temp(tmp0),
#if TARGET_LONG_BITS == 32
tcgv_i32_temp(addr),
#else
tcgv_i64_temp(addr),
#endif
tcgv_i32_temp(tmp1)
};
tcg_gen_callN(libafl_exec_read_hookN, NULL, 3, tmp2);
tcg_temp_free_i32(tmp1);
tcg_temp_free_i64(tmp0);
}
}
void (*libafl_exec_write_hook1)(uint64_t id, uint64_t addr);
void (*libafl_exec_write_hook2)(uint64_t id, uint64_t addr);
void (*libafl_exec_write_hook4)(uint64_t id, uint64_t addr);
void (*libafl_exec_write_hook8)(uint64_t id, uint64_t addr);
void (*libafl_exec_write_hookN)(uint64_t id, uint64_t addr, uint32_t size);
uint64_t (*libafl_gen_write_hook)(uint32_t size);
static TCGHelperInfo libafl_exec_write_hook1_info = {
.func = NULL, .name = "libafl_exec_write_hook1", \
.flags = dh_callflag(void), \
.typemask = dh_typemask(void, 0) | dh_typemask(tl, 1)
};
static TCGHelperInfo libafl_exec_write_hook2_info = {
.func = NULL, .name = "libafl_exec_write_hook2", \
.flags = dh_callflag(void), \
.typemask = dh_typemask(void, 0) | dh_typemask(tl, 1)
};
static TCGHelperInfo libafl_exec_write_hook4_info = {
.func = NULL, .name = "libafl_exec_write_hook4", \
.flags = dh_callflag(void), \
.typemask = dh_typemask(void, 0) | dh_typemask(tl, 1)
};
static TCGHelperInfo libafl_exec_write_hook8_info = {
.func = NULL, .name = "libafl_exec_write_hook8", \
.flags = dh_callflag(void), \
.typemask = dh_typemask(void, 0) | dh_typemask(tl, 1)
};
static TCGHelperInfo libafl_exec_write_hookN_info = {
.func = NULL, .name = "libafl_exec_write_hookN", \
.flags = dh_callflag(void), \
.typemask = dh_typemask(void, 0) | dh_typemask(tl, 1) | dh_typemask(i32, 2)
};
static int exec_write_hook_added = 0;
void libafl_gen_write(TCGv addr, MemOp ot)
{
uint32_t size = 0;
void* func = NULL;
switch (ot & MO_SIZE) {
case MO_64:
size = 8;
func = libafl_exec_write_hook8;
break;
case MO_32:
size = 4;
func = libafl_exec_write_hook4;
break;
case MO_16:
size = 2;
func = libafl_exec_write_hook2;
break;
case MO_8:
size = 1;
func = libafl_exec_write_hook1;
break;
default:
return;
}
uint32_t libafl_id = 0;
if (libafl_gen_write_hook)
libafl_id = libafl_gen_write_hook(size);
if (func && libafl_id != (uint32_t)-1) {
if (!exec_write_hook_added) {
exec_write_hook_added = 1;
libafl_exec_write_hook1_info.func = libafl_exec_write_hook1;
libafl_helper_table_add(&libafl_exec_write_hook1_info);
libafl_exec_write_hook2_info.func = libafl_exec_write_hook2;
libafl_helper_table_add(&libafl_exec_write_hook2_info);
libafl_exec_write_hook4_info.func = libafl_exec_write_hook4;
libafl_helper_table_add(&libafl_exec_write_hook4_info);
libafl_exec_write_hook8_info.func = libafl_exec_write_hook8;
libafl_helper_table_add(&libafl_exec_write_hook8_info);
libafl_exec_write_hookN_info.func = libafl_exec_write_hookN;
libafl_helper_table_add(&libafl_exec_write_hookN_info);
}
TCGv_i64 tmp0 = tcg_const_i64(libafl_id);
TCGTemp *tmp1[2] = { tcgv_i64_temp(tmp0),
#if TARGET_LONG_BITS == 32
tcgv_i32_temp(addr) };
#else
tcgv_i64_temp(addr) };
#endif
tcg_gen_callN(func, NULL, 2, tmp1);
tcg_temp_free_i64(tmp0);
}
}
void libafl_gen_write_N(TCGv addr, uint32_t size)
{
uint32_t libafl_id = 0;
if (libafl_gen_write_hook)
libafl_id = libafl_gen_write_hook(size);
if (libafl_id != (uint32_t)-1) {
if (!exec_write_hook_added) {
exec_write_hook_added = 1;
libafl_exec_write_hook1_info.func = libafl_exec_write_hook1;
libafl_helper_table_add(&libafl_exec_write_hook1_info);
libafl_exec_write_hook2_info.func = libafl_exec_write_hook2;
libafl_helper_table_add(&libafl_exec_write_hook2_info);
libafl_exec_write_hook4_info.func = libafl_exec_write_hook4;
libafl_helper_table_add(&libafl_exec_write_hook4_info);
libafl_exec_write_hook8_info.func = libafl_exec_write_hook8;
libafl_helper_table_add(&libafl_exec_write_hook8_info);
libafl_exec_write_hookN_info.func = libafl_exec_write_hookN;
libafl_helper_table_add(&libafl_exec_write_hookN_info);
}
TCGv_i64 tmp0 = tcg_const_i64(libafl_id);
TCGv_i32 tmp1 = tcg_const_i32(size);
TCGTemp *tmp2[3] = { tcgv_i64_temp(tmp0),
#if TARGET_LONG_BITS == 32
tcgv_i32_temp(addr),
#else
tcgv_i64_temp(addr),
#endif
tcgv_i32_temp(tmp1)
};
tcg_gen_callN(libafl_exec_write_hookN, NULL, 3, tmp2);
tcg_temp_free_i32(tmp1);
tcg_temp_free_i64(tmp0);
}
}
void (*libafl_exec_cmp_hook1)(uint64_t id, uint8_t v0, uint8_t v1);
void (*libafl_exec_cmp_hook2)(uint64_t id, uint16_t v0, uint16_t v1);
void (*libafl_exec_cmp_hook4)(uint64_t id, uint32_t v0, uint32_t v1);
void (*libafl_exec_cmp_hook8)(uint64_t id, uint64_t v0, uint64_t v1);
uint64_t (*libafl_gen_cmp_hook)(uint64_t pc, uint32_t size);
static TCGHelperInfo libafl_exec_cmp_hook1_info = {
.func = NULL, .name = "libafl_exec_cmp_hook1", \
.flags = dh_callflag(void), \
.typemask = dh_typemask(void, 0) | dh_typemask(i32, 1)
| dh_typemask(tl, 2) | dh_typemask(tl, 3)
};
static TCGHelperInfo libafl_exec_cmp_hook2_info = {
.func = NULL, .name = "libafl_exec_cmp_hook2", \
.flags = dh_callflag(void), \
.typemask = dh_typemask(void, 0) | dh_typemask(i32, 1)
| dh_typemask(tl, 2) | dh_typemask(tl, 3)
};
static TCGHelperInfo libafl_exec_cmp_hook4_info = {
.func = NULL, .name = "libafl_exec_cmp_hook4", \
.flags = dh_callflag(void), \
.typemask = dh_typemask(void, 0) | dh_typemask(i32, 1)
| dh_typemask(tl, 2) | dh_typemask(tl, 3)
};
static TCGHelperInfo libafl_exec_cmp_hook8_info = {
.func = NULL, .name = "libafl_exec_cmp_hook8", \
.flags = dh_callflag(void), \
.typemask = dh_typemask(void, 0) | dh_typemask(i32, 1)
| dh_typemask(tl, 2) | dh_typemask(tl, 3)
};
static int exec_cmp_hook_added = 0;
void libafl_gen_cmp(target_ulong pc, TCGv op0, TCGv op1, MemOp ot)
{
uint32_t size = 0;
void* func = NULL;
switch (ot & MO_SIZE) {
case MO_64:
size = 8;
func = libafl_exec_cmp_hook8;
break;
case MO_32:
size = 4;
func = libafl_exec_cmp_hook4;
break;
case MO_16:
size = 2;
func = libafl_exec_cmp_hook2;
break;
case MO_8:
size = 1;
func = libafl_exec_cmp_hook1;
break;
default:
return;
}
uint32_t libafl_id = 0;
if (libafl_gen_cmp_hook)
libafl_id = libafl_gen_cmp_hook((uint64_t)pc, size);
if (func && libafl_id != (uint32_t)-1) {
if (!exec_cmp_hook_added) {
exec_cmp_hook_added = 1;
libafl_exec_cmp_hook1_info.func = libafl_exec_cmp_hook1;
libafl_helper_table_add(&libafl_exec_cmp_hook1_info);
libafl_exec_cmp_hook2_info.func = libafl_exec_cmp_hook2;
libafl_helper_table_add(&libafl_exec_cmp_hook2_info);
libafl_exec_cmp_hook4_info.func = libafl_exec_cmp_hook4;
libafl_helper_table_add(&libafl_exec_cmp_hook4_info);
libafl_exec_cmp_hook8_info.func = libafl_exec_cmp_hook8;
libafl_helper_table_add(&libafl_exec_cmp_hook8_info);
}
TCGv_i64 tmp0 = tcg_const_i64(libafl_id);
TCGTemp *tmp1[3] = { tcgv_i64_temp(tmp0),
#if TARGET_LONG_BITS == 32
tcgv_i32_temp(op0), tcgv_i32_temp(op1) };
#else
tcgv_i64_temp(op0), tcgv_i64_temp(op1) };
#endif
tcg_gen_callN(func, NULL, 3, tmp1);
tcg_temp_free_i64(tmp0);
}
}
//// --- End LibAFL code ---
/* #define DEBUG_TB_INVALIDATE */ /* #define DEBUG_TB_INVALIDATE */
/* #define DEBUG_TB_FLUSH */ /* #define DEBUG_TB_FLUSH */
/* make various TB consistency checks */ /* make various TB consistency checks */
@ -1297,8 +1677,31 @@ static inline void tb_page_add(PageDesc *p, TranslationBlock *tb,
invalidate_page_bitmap(p); invalidate_page_bitmap(p);
#if defined(CONFIG_USER_ONLY) #if defined(CONFIG_USER_ONLY)
/* translator_loop() must have made all TB pages non-writable */ if (p->flags & PAGE_WRITE) {
assert(!(p->flags & PAGE_WRITE)); target_ulong addr;
PageDesc *p2;
int prot;
/* force the host page as non writable (writes will have a
page fault + mprotect overhead) */
page_addr &= qemu_host_page_mask;
prot = 0;
for (addr = page_addr; addr < page_addr + qemu_host_page_size;
addr += TARGET_PAGE_SIZE) {
p2 = page_find(addr >> TARGET_PAGE_BITS);
if (!p2) {
continue;
}
prot |= p2->flags;
p2->flags &= ~PAGE_WRITE;
}
mprotect(g2h_untagged(page_addr), qemu_host_page_size,
(prot & PAGE_BITS) & ~PAGE_WRITE);
if (DEBUG_TB_INVALIDATE_GATE) {
printf("protecting code page: 0x" TB_PAGE_ADDR_FMT "\n", page_addr);
}
}
#else #else
/* if some code is already present, then the pages are already /* if some code is already present, then the pages are already
protected. So we handle the case where only the first TB is protected. So we handle the case where only the first TB is
@ -1377,6 +1780,157 @@ tb_link_page(TranslationBlock *tb, tb_page_addr_t phys_pc,
return tb; return tb;
} }
//// --- Begin LibAFL code ---
void libafl_exec_edge_one_off(target_ulong src_block, target_ulong dst_block)
{
uint32_t libafl_id = 0;
if (libafl_gen_edge_hook)
libafl_id = libafl_gen_edge_hook((uint64_t)src_block, (uint64_t)dst_block);
if (!libafl_exec_edge_hook || libafl_id == (uint32_t)-1)
return;
if (!exec_edge_hook_added) {
exec_edge_hook_added = 1;
libafl_exec_edge_hook_info.func = libafl_exec_edge_hook;
libafl_helper_table_add(&libafl_exec_edge_hook_info);
}
libafl_exec_edge_hook(libafl_id);
}
void libafl_gen_jmp(target_ulong src, target_ulong dst)
{
uint32_t libafl_id = 0;
if (libafl_gen_jmp_hook)
libafl_id = libafl_gen_jmp_hook((uint64_t)src, (uint64_t)dst);
if (!libafl_exec_jmp_hook || libafl_id == (uint32_t)-1)
return;
if (!exec_jmp_hook_added) {
exec_jmp_hook_added = 1;
libafl_exec_jmp_hook_info.func = libafl_exec_jmp_hook;
libafl_helper_table_add(&libafl_exec_jmp_hook_info);
}
TCGv_i64 tmp0 = tcg_const_i64(src);
TCGv_i64 tmp1 = tcg_const_i64(dst);
TCGv_i64 tmp2 = tcg_const_i64(libafl_id);
TCGTemp *tmp3[3] = { tcgv_i64_temp(tmp0), tcgv_i64_temp(tmp1), tcgv_i64_temp(tmp2) };
tcg_gen_callN(libafl_exec_jmp_hook, NULL, 3, tmp3);
tcg_temp_free_i64(tmp0);
}
/* Called with mmap_lock held for user mode emulation. */
TranslationBlock *libafl_gen_edge(CPUState *cpu, target_ulong src_block,
target_ulong dst_block, target_ulong cs_base,
uint32_t flags, int cflags)
{
CPUArchState *env = cpu->env_ptr;
TranslationBlock *tb;
tcg_insn_unit *gen_code_buf;
int gen_code_size, search_size;
assert_memory_lock();
uint32_t libafl_id = 0;
if (libafl_gen_edge_hook)
libafl_id = libafl_gen_edge_hook((uint64_t)src_block, (uint64_t)dst_block);
if (!libafl_exec_edge_hook || libafl_id == (uint32_t)-1)
return NULL;
if (!exec_edge_hook_added) {
exec_edge_hook_added = 1;
libafl_exec_edge_hook_info.func = libafl_exec_edge_hook;
libafl_helper_table_add(&libafl_exec_edge_hook_info);
}
buffer_overflow1:
tb = tcg_tb_alloc(tcg_ctx);
if (unlikely(!tb)) {
/* flush must be done */
tb_flush(cpu);
mmap_unlock();
/* Make the execution loop process the flush as soon as possible. */
cpu->exception_index = EXCP_INTERRUPT;
cpu_loop_exit(cpu);
}
libafl_exec_edge_hook(libafl_id);
gen_code_buf = tcg_ctx->code_gen_ptr;
tb->tc.ptr = gen_code_buf;
tb->pc = 0;
tb->cs_base = cs_base;
tb->flags = flags;
tb->cflags = cflags;
tb->trace_vcpu_dstate = *cpu->trace_dstate;
tb->icount = 0;
tcg_ctx->tb_cflags = 0;
tcg_func_start(tcg_ctx);
tcg_ctx->cpu = env_cpu(env);
TCGv_i64 tmp0 = tcg_const_i64(libafl_id);
TCGTemp *tmp1[1] = { tcgv_i64_temp(tmp0) };
tcg_gen_callN(libafl_exec_edge_hook, NULL, 1, tmp1);
tcg_temp_free_i64(tmp0);
tcg_gen_goto_tb(0);
tcg_gen_exit_tb(tb, 0);
tcg_ctx->cpu = NULL;
trace_translate_block(tb, tb->pc, tb->tc.ptr);
/* generate machine code */
tb->jmp_reset_offset[0] = TB_JMP_RESET_OFFSET_INVALID;
tb->jmp_reset_offset[1] = TB_JMP_RESET_OFFSET_INVALID;
tcg_ctx->tb_jmp_reset_offset = tb->jmp_reset_offset;
if (TCG_TARGET_HAS_direct_jump) {
tcg_ctx->tb_jmp_insn_offset = tb->jmp_target_arg;
tcg_ctx->tb_jmp_target_addr = NULL;
} else {
tcg_ctx->tb_jmp_insn_offset = NULL;
tcg_ctx->tb_jmp_target_addr = tb->jmp_target_arg;
}
/* ??? Overflow could be handled better here. In particular, we
don't need to re-do gen_intermediate_code, nor should we re-do
the tcg optimization currently hidden inside tcg_gen_code. All
that should be required is to flush the TBs, allocate a new TB,
re-initialize it per above, and re-do the actual code generation. */
gen_code_size = tcg_gen_code(tcg_ctx, tb);
if (unlikely(gen_code_size < 0)) {
goto buffer_overflow1;
}
search_size = encode_search(tb, (void *)gen_code_buf + gen_code_size);
if (unlikely(search_size < 0)) {
goto buffer_overflow1;
}
tb->tc.size = gen_code_size;
qatomic_set(&tcg_ctx->code_gen_ptr, (void *)
ROUND_UP((uintptr_t)gen_code_buf + gen_code_size + search_size,
CODE_GEN_ALIGN));
/* init jump list */
qemu_spin_init(&tb->jmp_lock);
tb->jmp_list_head = (uintptr_t)NULL;
tb->jmp_list_next[0] = (uintptr_t)NULL;
tb->jmp_list_next[1] = (uintptr_t)NULL;
tb->jmp_dest[0] = (uintptr_t)NULL;
tb->jmp_dest[1] = (uintptr_t)NULL;
/* init original jump addresses which have been set during tcg_gen_code() */
if (tb->jmp_reset_offset[0] != TB_JMP_RESET_OFFSET_INVALID) {
tb_reset_jump(tb, 0);
}
if (tb->jmp_reset_offset[1] != TB_JMP_RESET_OFFSET_INVALID) {
tb_reset_jump(tb, 1);
}
return tb;
}
//// --- End LibAFL code ---
/* Called with mmap_lock held for user mode emulation. */ /* Called with mmap_lock held for user mode emulation. */
TranslationBlock *tb_gen_code(CPUState *cpu, TranslationBlock *tb_gen_code(CPUState *cpu,
target_ulong pc, target_ulong cs_base, target_ulong pc, target_ulong cs_base,
@ -1427,6 +1981,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
tb->flags = flags; tb->flags = flags;
tb->cflags = cflags; tb->cflags = cflags;
tb->trace_vcpu_dstate = *cpu->trace_dstate; tb->trace_vcpu_dstate = *cpu->trace_dstate;
tb->icount = 0;
tcg_ctx->tb_cflags = cflags; tcg_ctx->tb_cflags = cflags;
tb_overflow: tb_overflow:
@ -1444,6 +1999,26 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
tcg_func_start(tcg_ctx); tcg_func_start(tcg_ctx);
tcg_ctx->cpu = env_cpu(env); tcg_ctx->cpu = env_cpu(env);
//// --- Begin LibAFL code ---
uint32_t libafl_id = 0;
if (libafl_gen_block_hook)
libafl_id = libafl_gen_block_hook((uint64_t)pc);
if (libafl_exec_block_hook && libafl_id != (uint32_t)-1) {
if (!exec_block_hook_added) {
exec_block_hook_added = 1;
libafl_exec_block_hook_info.func = libafl_exec_block_hook;
libafl_helper_table_add(&libafl_exec_block_hook_info);
}
TCGv_i64 tmp0 = tcg_const_i64((uint64_t)pc);
TCGTemp *tmp1[1] = { tcgv_i64_temp(tmp0) };
tcg_gen_callN(libafl_exec_block_hook, NULL, 1, tmp1);
tcg_temp_free_i64(tmp0);
}
//// --- End LibAFL code ---
gen_intermediate_code(cpu, tb, max_insns); gen_intermediate_code(cpu, tb, max_insns);
assert(tb->size != 0); assert(tb->size != 0);
tcg_ctx->cpu = NULL; tcg_ctx->cpu = NULL;
@ -1738,7 +2313,7 @@ tb_invalidate_phys_page_range__locked(struct page_collection *pages,
if (current_tb_modified) { if (current_tb_modified) {
page_collection_unlock(pages); page_collection_unlock(pages);
/* Force execution of one insn next time. */ /* Force execution of one insn next time. */
cpu->cflags_next_tb = 1 | CF_NOIRQ | curr_cflags(cpu); cpu->cflags_next_tb = 1 | curr_cflags(cpu);
mmap_unlock(); mmap_unlock();
cpu_loop_exit_noexc(cpu); cpu_loop_exit_noexc(cpu);
} }
@ -1906,7 +2481,7 @@ static bool tb_invalidate_phys_page(tb_page_addr_t addr, uintptr_t pc)
#ifdef TARGET_HAS_PRECISE_SMC #ifdef TARGET_HAS_PRECISE_SMC
if (current_tb_modified) { if (current_tb_modified) {
/* Force execution of one insn next time. */ /* Force execution of one insn next time. */
cpu->cflags_next_tb = 1 | CF_NOIRQ | curr_cflags(cpu); cpu->cflags_next_tb = 1 | curr_cflags(cpu);
return true; return true;
} }
#endif #endif
@ -1991,7 +2566,7 @@ void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr)
cpu_loop_exit_noexc(cpu); cpu_loop_exit_noexc(cpu);
} }
static void print_qht_statistics(struct qht_stats hst, GString *buf) static void print_qht_statistics(struct qht_stats hst)
{ {
uint32_t hgram_opts; uint32_t hgram_opts;
size_t hgram_bins; size_t hgram_bins;
@ -2000,11 +2575,9 @@ static void print_qht_statistics(struct qht_stats hst, GString *buf)
if (!hst.head_buckets) { if (!hst.head_buckets) {
return; return;
} }
g_string_append_printf(buf, "TB hash buckets %zu/%zu " qemu_printf("TB hash buckets %zu/%zu (%0.2f%% head buckets used)\n",
"(%0.2f%% head buckets used)\n", hst.used_head_buckets, hst.head_buckets,
hst.used_head_buckets, hst.head_buckets, (double)hst.used_head_buckets / hst.head_buckets * 100);
(double)hst.used_head_buckets /
hst.head_buckets * 100);
hgram_opts = QDIST_PR_BORDER | QDIST_PR_LABELS; hgram_opts = QDIST_PR_BORDER | QDIST_PR_LABELS;
hgram_opts |= QDIST_PR_100X | QDIST_PR_PERCENT; hgram_opts |= QDIST_PR_100X | QDIST_PR_PERCENT;
@ -2012,9 +2585,8 @@ static void print_qht_statistics(struct qht_stats hst, GString *buf)
hgram_opts |= QDIST_PR_NODECIMAL; hgram_opts |= QDIST_PR_NODECIMAL;
} }
hgram = qdist_pr(&hst.occupancy, 10, hgram_opts); hgram = qdist_pr(&hst.occupancy, 10, hgram_opts);
g_string_append_printf(buf, "TB hash occupancy %0.2f%% avg chain occ. " qemu_printf("TB hash occupancy %0.2f%% avg chain occ. Histogram: %s\n",
"Histogram: %s\n", qdist_avg(&hst.occupancy) * 100, hgram);
qdist_avg(&hst.occupancy) * 100, hgram);
g_free(hgram); g_free(hgram);
hgram_opts = QDIST_PR_BORDER | QDIST_PR_LABELS; hgram_opts = QDIST_PR_BORDER | QDIST_PR_LABELS;
@ -2026,9 +2598,8 @@ static void print_qht_statistics(struct qht_stats hst, GString *buf)
hgram_opts |= QDIST_PR_NODECIMAL | QDIST_PR_NOBINRANGE; hgram_opts |= QDIST_PR_NODECIMAL | QDIST_PR_NOBINRANGE;
} }
hgram = qdist_pr(&hst.chain, hgram_bins, hgram_opts); hgram = qdist_pr(&hst.chain, hgram_bins, hgram_opts);
g_string_append_printf(buf, "TB hash avg chain %0.3f buckets. " qemu_printf("TB hash avg chain %0.3f buckets. Histogram: %s\n",
"Histogram: %s\n", qdist_avg(&hst.chain), hgram);
qdist_avg(&hst.chain), hgram);
g_free(hgram); g_free(hgram);
} }
@ -2065,7 +2636,7 @@ static gboolean tb_tree_stats_iter(gpointer key, gpointer value, gpointer data)
return false; return false;
} }
void dump_exec_info(GString *buf) void dump_exec_info(void)
{ {
struct tb_tree_stats tst = {}; struct tb_tree_stats tst = {};
struct qht_stats hst; struct qht_stats hst;
@ -2074,53 +2645,49 @@ void dump_exec_info(GString *buf)
tcg_tb_foreach(tb_tree_stats_iter, &tst); tcg_tb_foreach(tb_tree_stats_iter, &tst);
nb_tbs = tst.nb_tbs; nb_tbs = tst.nb_tbs;
/* XXX: avoid using doubles ? */ /* XXX: avoid using doubles ? */
g_string_append_printf(buf, "Translation buffer state:\n"); qemu_printf("Translation buffer state:\n");
/* /*
* Report total code size including the padding and TB structs; * Report total code size including the padding and TB structs;
* otherwise users might think "-accel tcg,tb-size" is not honoured. * otherwise users might think "-accel tcg,tb-size" is not honoured.
* For avg host size we use the precise numbers from tb_tree_stats though. * For avg host size we use the precise numbers from tb_tree_stats though.
*/ */
g_string_append_printf(buf, "gen code size %zu/%zu\n", qemu_printf("gen code size %zu/%zu\n",
tcg_code_size(), tcg_code_capacity()); tcg_code_size(), tcg_code_capacity());
g_string_append_printf(buf, "TB count %zu\n", nb_tbs); qemu_printf("TB count %zu\n", nb_tbs);
g_string_append_printf(buf, "TB avg target size %zu max=%zu bytes\n", qemu_printf("TB avg target size %zu max=%zu bytes\n",
nb_tbs ? tst.target_size / nb_tbs : 0, nb_tbs ? tst.target_size / nb_tbs : 0,
tst.max_target_size); tst.max_target_size);
g_string_append_printf(buf, "TB avg host size %zu bytes " qemu_printf("TB avg host size %zu bytes (expansion ratio: %0.1f)\n",
"(expansion ratio: %0.1f)\n", nb_tbs ? tst.host_size / nb_tbs : 0,
nb_tbs ? tst.host_size / nb_tbs : 0, tst.target_size ? (double)tst.host_size / tst.target_size : 0);
tst.target_size ? qemu_printf("cross page TB count %zu (%zu%%)\n", tst.cross_page,
(double)tst.host_size / tst.target_size : 0); nb_tbs ? (tst.cross_page * 100) / nb_tbs : 0);
g_string_append_printf(buf, "cross page TB count %zu (%zu%%)\n", qemu_printf("direct jump count %zu (%zu%%) (2 jumps=%zu %zu%%)\n",
tst.cross_page, tst.direct_jmp_count,
nb_tbs ? (tst.cross_page * 100) / nb_tbs : 0); nb_tbs ? (tst.direct_jmp_count * 100) / nb_tbs : 0,
g_string_append_printf(buf, "direct jump count %zu (%zu%%) " tst.direct_jmp2_count,
"(2 jumps=%zu %zu%%)\n", nb_tbs ? (tst.direct_jmp2_count * 100) / nb_tbs : 0);
tst.direct_jmp_count,
nb_tbs ? (tst.direct_jmp_count * 100) / nb_tbs : 0,
tst.direct_jmp2_count,
nb_tbs ? (tst.direct_jmp2_count * 100) / nb_tbs : 0);
qht_statistics_init(&tb_ctx.htable, &hst); qht_statistics_init(&tb_ctx.htable, &hst);
print_qht_statistics(hst, buf); print_qht_statistics(hst);
qht_statistics_destroy(&hst); qht_statistics_destroy(&hst);
g_string_append_printf(buf, "\nStatistics:\n"); qemu_printf("\nStatistics:\n");
g_string_append_printf(buf, "TB flush count %u\n", qemu_printf("TB flush count %u\n",
qatomic_read(&tb_ctx.tb_flush_count)); qatomic_read(&tb_ctx.tb_flush_count));
g_string_append_printf(buf, "TB invalidate count %u\n", qemu_printf("TB invalidate count %u\n",
qatomic_read(&tb_ctx.tb_phys_invalidate_count)); qatomic_read(&tb_ctx.tb_phys_invalidate_count));
tlb_flush_counts(&flush_full, &flush_part, &flush_elide); tlb_flush_counts(&flush_full, &flush_part, &flush_elide);
g_string_append_printf(buf, "TLB full flushes %zu\n", flush_full); qemu_printf("TLB full flushes %zu\n", flush_full);
g_string_append_printf(buf, "TLB partial flushes %zu\n", flush_part); qemu_printf("TLB partial flushes %zu\n", flush_part);
g_string_append_printf(buf, "TLB elided flushes %zu\n", flush_elide); qemu_printf("TLB elided flushes %zu\n", flush_elide);
tcg_dump_info(buf); tcg_dump_info();
} }
void dump_opcount_info(GString *buf) void dump_opcount_info(void)
{ {
tcg_dump_op_count(buf); tcg_dump_op_count();
} }
#else /* CONFIG_USER_ONLY */ #else /* CONFIG_USER_ONLY */
@ -2379,38 +2946,6 @@ int page_check_range(target_ulong start, target_ulong len, int flags)
return 0; return 0;
} }
void page_protect(tb_page_addr_t page_addr)
{
target_ulong addr;
PageDesc *p;
int prot;
p = page_find(page_addr >> TARGET_PAGE_BITS);
if (p && (p->flags & PAGE_WRITE)) {
/*
* Force the host page as non writable (writes will have a page fault +
* mprotect overhead).
*/
page_addr &= qemu_host_page_mask;
prot = 0;
for (addr = page_addr; addr < page_addr + qemu_host_page_size;
addr += TARGET_PAGE_SIZE) {
p = page_find(addr >> TARGET_PAGE_BITS);
if (!p) {
continue;
}
prot |= p->flags;
p->flags &= ~PAGE_WRITE;
}
mprotect(g2h_untagged(page_addr), qemu_host_page_size,
(prot & PAGE_BITS) & ~PAGE_WRITE);
if (DEBUG_TB_INVALIDATE_GATE) {
printf("protecting code page: 0x" TB_PAGE_ADDR_FMT "\n", page_addr);
}
}
}
/* called from signal handler: invalidate the code and unprotect the /* called from signal handler: invalidate the code and unprotect the
* page. Return 0 if the fault was not handled, 1 if it was handled, * page. Return 0 if the fault was not handled, 1 if it was handled,
* and 2 if it was handled but the caller must cause the TB to be * and 2 if it was handled but the caller must cause the TB to be

View File

@ -18,6 +18,29 @@
#include "exec/plugin-gen.h" #include "exec/plugin-gen.h"
#include "sysemu/replay.h" #include "sysemu/replay.h"
//// --- Begin LibAFL code ---
#include "tcg/tcg-internal.h"
struct libafl_breakpoint {
target_ulong addr;
struct libafl_breakpoint* next;
};
extern struct libafl_breakpoint* libafl_qemu_breakpoints;
struct libafl_hook {
target_ulong addr;
void (*callback)(uint64_t);
uint64_t value;
TCGHelperInfo helper_info;
struct libafl_hook* next;
};
extern struct libafl_hook* libafl_qemu_hooks;
//// --- End LibAFL code ---
/* Pairs with tcg_clear_temp_count. /* Pairs with tcg_clear_temp_count.
To be called by #TranslatorOps.{translate_insn,tb_stop} if To be called by #TranslatorOps.{translate_insn,tb_stop} if
(1) the target is sufficiently clean to support reporting, (1) the target is sufficiently clean to support reporting,
@ -42,15 +65,6 @@ bool translator_use_goto_tb(DisasContextBase *db, target_ulong dest)
return ((db->pc_first ^ dest) & TARGET_PAGE_MASK) == 0; return ((db->pc_first ^ dest) & TARGET_PAGE_MASK) == 0;
} }
static inline void translator_page_protect(DisasContextBase *dcbase,
target_ulong pc)
{
#ifdef CONFIG_USER_ONLY
dcbase->page_protect_end = pc | ~TARGET_PAGE_MASK;
page_protect(pc);
#endif
}
void translator_loop(const TranslatorOps *ops, DisasContextBase *db, void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
CPUState *cpu, TranslationBlock *tb, int max_insns) CPUState *cpu, TranslationBlock *tb, int max_insns)
{ {
@ -65,7 +79,6 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
db->num_insns = 0; db->num_insns = 0;
db->max_insns = max_insns; db->max_insns = max_insns;
db->singlestep_enabled = cflags & CF_SINGLE_STEP; db->singlestep_enabled = cflags & CF_SINGLE_STEP;
translator_page_protect(db, db->pc_next);
ops->init_disas_context(db, cpu); ops->init_disas_context(db, cpu);
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */ tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */
@ -89,6 +102,29 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
plugin_gen_insn_start(cpu, db); plugin_gen_insn_start(cpu, db);
} }
//// --- Begin LibAFL code ---
struct libafl_hook* hk = libafl_qemu_hooks;
while (hk) {
if (hk->addr == db->pc_next) {
TCGv_i64 tmp0 = tcg_const_i64(hk->value);
TCGTemp *tmp1[1] = { tcgv_i64_temp(tmp0) };
tcg_gen_callN(hk->callback, NULL, 1, tmp1);
tcg_temp_free_i64(tmp0);
}
hk = hk->next;
}
struct libafl_breakpoint* bp = libafl_qemu_breakpoints;
while (bp) {
if (bp->addr == db->pc_next) {
gen_helper_libafl_qemu_handle_breakpoint(cpu_env);
}
bp = bp->next;
}
//// --- End LibAFL code ---
/* Disassemble one instruction. The translate_insn hook should /* Disassemble one instruction. The translate_insn hook should
update db->pc_next and db->is_jmp to indicate what should be update db->pc_next and db->is_jmp to indicate what should be
done next -- either exiting this loop or locate the start of done next -- either exiting this loop or locate the start of
@ -147,32 +183,3 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
} }
#endif #endif
} }
static inline void translator_maybe_page_protect(DisasContextBase *dcbase,
target_ulong pc, size_t len)
{
#ifdef CONFIG_USER_ONLY
target_ulong end = pc + len - 1;
if (end > dcbase->page_protect_end) {
translator_page_protect(dcbase, end);
}
#endif
}
#define GEN_TRANSLATOR_LD(fullname, type, load_fn, swap_fn) \
type fullname ## _swap(CPUArchState *env, DisasContextBase *dcbase, \
abi_ptr pc, bool do_swap) \
{ \
translator_maybe_page_protect(dcbase, pc, sizeof(type)); \
type ret = load_fn(env, pc); \
if (do_swap) { \
ret = swap_fn(ret); \
} \
plugin_insn_append(pc, &ret, sizeof(ret)); \
return ret; \
}
FOR_EACH_TRANSLATOR_LD(GEN_TRANSLATOR_LD)
#undef GEN_TRANSLATOR_LD

File diff suppressed because it is too large Load Diff

View File

@ -7,22 +7,23 @@ softmmu_ss.add(files(
'wavcapture.c', 'wavcapture.c',
)) ))
softmmu_ss.add(when: coreaudio, if_true: files('coreaudio.c')) softmmu_ss.add(when: [coreaudio, 'CONFIG_AUDIO_COREAUDIO'], if_true: files('coreaudio.c'))
softmmu_ss.add(when: dsound, if_true: files('dsoundaudio.c', 'audio_win_int.c')) softmmu_ss.add(when: [dsound, 'CONFIG_AUDIO_DSOUND'], if_true: files('dsoundaudio.c'))
softmmu_ss.add(when: ['CONFIG_AUDIO_WIN_INT'], if_true: files('audio_win_int.c'))
audio_modules = {} audio_modules = {}
foreach m : [ foreach m : [
['alsa', alsa, files('alsaaudio.c')], ['CONFIG_AUDIO_ALSA', 'alsa', alsa, 'alsaaudio.c'],
['oss', oss, files('ossaudio.c')], ['CONFIG_AUDIO_OSS', 'oss', oss, 'ossaudio.c'],
['pa', pulse, files('paaudio.c')], ['CONFIG_AUDIO_PA', 'pa', pulse, 'paaudio.c'],
['sdl', sdl, files('sdlaudio.c')], ['CONFIG_AUDIO_SDL', 'sdl', sdl, 'sdlaudio.c'],
['jack', jack, files('jackaudio.c')], ['CONFIG_AUDIO_JACK', 'jack', jack, 'jackaudio.c'],
['spice', spice, files('spiceaudio.c')] ['CONFIG_SPICE', 'spice', spice, 'spiceaudio.c']
] ]
if m[1].found() if config_host.has_key(m[0])
module_ss = ss.source_set() module_ss = ss.source_set()
module_ss.add(m[1], m[2]) module_ss.add(when: m[2], if_true: files(m[3]))
audio_modules += {m[0] : module_ss} audio_modules += {m[1] : module_ss}
endif endif
endforeach endforeach

View File

@ -1,82 +0,0 @@
/*
* QEMU host SGX EPC memory backend
*
* Copyright (C) 2019 Intel Corporation
*
* Authors:
* Sean Christopherson <sean.j.christopherson@intel.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include <sys/ioctl.h>
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "qom/object_interfaces.h"
#include "qapi/error.h"
#include "sysemu/hostmem.h"
#include "hw/i386/hostmem-epc.h"
static void
sgx_epc_backend_memory_alloc(HostMemoryBackend *backend, Error **errp)
{
uint32_t ram_flags;
char *name;
int fd;
if (!backend->size) {
error_setg(errp, "can't create backend with size 0");
return;
}
fd = qemu_open_old("/dev/sgx_vepc", O_RDWR);
if (fd < 0) {
error_setg_errno(errp, errno,
"failed to open /dev/sgx_vepc to alloc SGX EPC");
return;
}
name = object_get_canonical_path(OBJECT(backend));
ram_flags = (backend->share ? RAM_SHARED : 0) | RAM_PROTECTED;
memory_region_init_ram_from_fd(&backend->mr, OBJECT(backend),
name, backend->size, ram_flags,
fd, 0, errp);
g_free(name);
}
static void sgx_epc_backend_instance_init(Object *obj)
{
HostMemoryBackend *m = MEMORY_BACKEND(obj);
m->share = true;
m->merge = false;
m->dump = false;
}
static void sgx_epc_backend_class_init(ObjectClass *oc, void *data)
{
HostMemoryBackendClass *bc = MEMORY_BACKEND_CLASS(oc);
bc->alloc = sgx_epc_backend_memory_alloc;
}
static const TypeInfo sgx_epc_backed_info = {
.name = TYPE_MEMORY_BACKEND_EPC,
.parent = TYPE_MEMORY_BACKEND,
.instance_init = sgx_epc_backend_instance_init,
.class_init = sgx_epc_backend_class_init,
.instance_size = sizeof(HostMemoryBackendEpc),
};
static void register_types(void)
{
int fd = qemu_open_old("/dev/sgx_vepc", O_RDWR);
if (fd >= 0) {
close(fd);
type_register_static(&sgx_epc_backed_info);
}
}
type_init(register_types);

View File

@ -16,6 +16,5 @@ softmmu_ss.add(when: ['CONFIG_VHOST_USER', 'CONFIG_VIRTIO'], if_true: files('vho
softmmu_ss.add(when: 'CONFIG_VIRTIO_CRYPTO', if_true: files('cryptodev-vhost.c')) softmmu_ss.add(when: 'CONFIG_VIRTIO_CRYPTO', if_true: files('cryptodev-vhost.c'))
softmmu_ss.add(when: ['CONFIG_VIRTIO_CRYPTO', 'CONFIG_VHOST_CRYPTO'], if_true: files('cryptodev-vhost-user.c')) softmmu_ss.add(when: ['CONFIG_VIRTIO_CRYPTO', 'CONFIG_VHOST_CRYPTO'], if_true: files('cryptodev-vhost-user.c'))
softmmu_ss.add(when: 'CONFIG_GIO', if_true: [files('dbus-vmstate.c'), gio]) softmmu_ss.add(when: 'CONFIG_GIO', if_true: [files('dbus-vmstate.c'), gio])
softmmu_ss.add(when: 'CONFIG_SGX', if_true: files('hostmem-epc.c'))
subdir('tpm') subdir('tpm')

View File

@ -492,7 +492,8 @@ static int tpm_emulator_block_migration(TPMEmulator *tpm_emu)
error_setg(&tpm_emu->migration_blocker, error_setg(&tpm_emu->migration_blocker,
"Migration disabled: TPM emulator does not support " "Migration disabled: TPM emulator does not support "
"migration"); "migration");
if (migrate_add_blocker(tpm_emu->migration_blocker, &err) < 0) { migrate_add_blocker(tpm_emu->migration_blocker, &err);
if (err) {
error_report_err(err); error_report_err(err);
error_free(tpm_emu->migration_blocker); error_free(tpm_emu->migration_blocker);
tpm_emu->migration_blocker = NULL; tpm_emu->migration_blocker = NULL;
@ -623,7 +624,7 @@ static TpmTypeOptions *tpm_emulator_get_tpm_options(TPMBackend *tb)
TPMEmulator *tpm_emu = TPM_EMULATOR(tb); TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
TpmTypeOptions *options = g_new0(TpmTypeOptions, 1); TpmTypeOptions *options = g_new0(TpmTypeOptions, 1);
options->type = TPM_TYPE_EMULATOR; options->type = TPM_TYPE_OPTIONS_KIND_EMULATOR;
options->u.emulator.data = QAPI_CLONE(TPMEmulatorOptions, tpm_emu->options); options->u.emulator.data = QAPI_CLONE(TPMEmulatorOptions, tpm_emu->options);
return options; return options;

View File

@ -321,7 +321,7 @@ static TpmTypeOptions *tpm_passthrough_get_tpm_options(TPMBackend *tb)
{ {
TpmTypeOptions *options = g_new0(TpmTypeOptions, 1); TpmTypeOptions *options = g_new0(TpmTypeOptions, 1);
options->type = TPM_TYPE_PASSTHROUGH; options->type = TPM_TYPE_OPTIONS_KIND_PASSTHROUGH;
options->u.passthrough.data = QAPI_CLONE(TPMPassthroughOptions, options->u.passthrough.data = QAPI_CLONE(TPMPassthroughOptions,
TPM_PASSTHROUGH(tb)->options); TPM_PASSTHROUGH(tb)->options);

441
block.c
View File

@ -49,8 +49,6 @@
#include "qemu/timer.h" #include "qemu/timer.h"
#include "qemu/cutils.h" #include "qemu/cutils.h"
#include "qemu/id.h" #include "qemu/id.h"
#include "qemu/range.h"
#include "qemu/rcu.h"
#include "block/coroutines.h" #include "block/coroutines.h"
#ifdef CONFIG_BSD #ifdef CONFIG_BSD
@ -84,13 +82,8 @@ static BlockDriverState *bdrv_open_inherit(const char *filename,
BdrvChildRole child_role, BdrvChildRole child_role,
Error **errp); Error **errp);
static bool bdrv_recurse_has_child(BlockDriverState *bs, static void bdrv_replace_child_noperm(BdrvChild *child,
BlockDriverState *child); BlockDriverState *new_bs);
static void bdrv_child_free(BdrvChild *child);
static void bdrv_replace_child_noperm(BdrvChild **child,
BlockDriverState *new_bs,
bool free_empty_child);
static void bdrv_remove_file_or_backing_child(BlockDriverState *bs, static void bdrv_remove_file_or_backing_child(BlockDriverState *bs,
BdrvChild *child, BdrvChild *child,
Transaction *tran); Transaction *tran);
@ -408,9 +401,6 @@ BlockDriverState *bdrv_new(void)
qemu_co_queue_init(&bs->flush_queue); qemu_co_queue_init(&bs->flush_queue);
qemu_co_mutex_init(&bs->bsc_modify_lock);
bs->block_status_cache = g_new0(BdrvBlockStatusCache, 1);
for (i = 0; i < bdrv_drain_all_count; i++) { for (i = 0; i < bdrv_drain_all_count; i++) {
bdrv_drained_begin(bs); bdrv_drained_begin(bs);
} }
@ -1389,8 +1379,6 @@ static void bdrv_child_cb_attach(BdrvChild *child)
{ {
BlockDriverState *bs = child->opaque; BlockDriverState *bs = child->opaque;
QLIST_INSERT_HEAD(&bs->children, child, next);
if (child->role & BDRV_CHILD_COW) { if (child->role & BDRV_CHILD_COW) {
bdrv_backing_attach(child); bdrv_backing_attach(child);
} }
@ -1407,8 +1395,6 @@ static void bdrv_child_cb_detach(BdrvChild *child)
} }
bdrv_unapply_subtree_drain(child, bs); bdrv_unapply_subtree_drain(child, bs);
QLIST_REMOVE(child, next);
} }
static int bdrv_child_cb_update_filename(BdrvChild *c, BlockDriverState *base, static int bdrv_child_cb_update_filename(BdrvChild *c, BlockDriverState *base,
@ -1613,26 +1599,16 @@ open_failed:
return ret; return ret;
} }
/* BlockDriverState *bdrv_new_open_driver(BlockDriver *drv, const char *node_name,
* Create and open a block node. int flags, Error **errp)
*
* @options is a QDict of options to pass to the block drivers, or NULL for an
* empty set of options. The reference to the QDict belongs to the block layer
* after the call (even on failure), so if the caller intends to reuse the
* dictionary, it needs to use qobject_ref() before calling bdrv_open.
*/
BlockDriverState *bdrv_new_open_driver_opts(BlockDriver *drv,
const char *node_name,
QDict *options, int flags,
Error **errp)
{ {
BlockDriverState *bs; BlockDriverState *bs;
int ret; int ret;
bs = bdrv_new(); bs = bdrv_new();
bs->open_flags = flags; bs->open_flags = flags;
bs->options = options ?: qdict_new(); bs->explicit_options = qdict_new();
bs->explicit_options = qdict_clone_shallow(bs->options); bs->options = qdict_new();
bs->opaque = NULL; bs->opaque = NULL;
update_options_from_flags(bs->options, flags); update_options_from_flags(bs->options, flags);
@ -1650,13 +1626,6 @@ BlockDriverState *bdrv_new_open_driver_opts(BlockDriver *drv,
return bs; return bs;
} }
/* Create and open a block node. */
BlockDriverState *bdrv_new_open_driver(BlockDriver *drv, const char *node_name,
int flags, Error **errp)
{
return bdrv_new_open_driver_opts(drv, node_name, NULL, flags, errp);
}
QemuOptsList bdrv_runtime_opts = { QemuOptsList bdrv_runtime_opts = {
.name = "bdrv_common", .name = "bdrv_common",
.head = QTAILQ_HEAD_INITIALIZER(bdrv_runtime_opts.head), .head = QTAILQ_HEAD_INITIALIZER(bdrv_runtime_opts.head),
@ -2256,18 +2225,13 @@ static int bdrv_drv_set_perm(BlockDriverState *bs, uint64_t perm,
typedef struct BdrvReplaceChildState { typedef struct BdrvReplaceChildState {
BdrvChild *child; BdrvChild *child;
BdrvChild **childp;
BlockDriverState *old_bs; BlockDriverState *old_bs;
bool free_empty_child;
} BdrvReplaceChildState; } BdrvReplaceChildState;
static void bdrv_replace_child_commit(void *opaque) static void bdrv_replace_child_commit(void *opaque)
{ {
BdrvReplaceChildState *s = opaque; BdrvReplaceChildState *s = opaque;
if (s->free_empty_child && !s->child->bs) {
bdrv_child_free(s->child);
}
bdrv_unref(s->old_bs); bdrv_unref(s->old_bs);
} }
@ -2276,34 +2240,8 @@ static void bdrv_replace_child_abort(void *opaque)
BdrvReplaceChildState *s = opaque; BdrvReplaceChildState *s = opaque;
BlockDriverState *new_bs = s->child->bs; BlockDriverState *new_bs = s->child->bs;
/* /* old_bs reference is transparently moved from @s to @s->child */
* old_bs reference is transparently moved from @s to s->child. bdrv_replace_child_noperm(s->child, s->old_bs);
*
* Pass &s->child here instead of s->childp, because:
* (1) s->old_bs must be non-NULL, so bdrv_replace_child_noperm() will not
* modify the BdrvChild * pointer we indirectly pass to it, i.e. it
* will not modify s->child. From that perspective, it does not matter
* whether we pass s->childp or &s->child.
* (2) If new_bs is not NULL, s->childp will be NULL. We then cannot use
* it here.
* (3) If new_bs is NULL, *s->childp will have been NULLed by
* bdrv_replace_child_tran()'s bdrv_replace_child_noperm() call, and we
* must not pass a NULL *s->childp here.
*
* So whether new_bs was NULL or not, we cannot pass s->childp here; and in
* any case, there is no reason to pass it anyway.
*/
bdrv_replace_child_noperm(&s->child, s->old_bs, true);
/*
* The child was pre-existing, so s->old_bs must be non-NULL, and
* s->child thus must not have been freed
*/
assert(s->child != NULL);
if (!new_bs) {
/* As described above, *s->childp was cleared, so restore it */
assert(s->childp != NULL);
*s->childp = s->child;
}
bdrv_unref(new_bs); bdrv_unref(new_bs);
} }
@ -2319,46 +2257,22 @@ static TransactionActionDrv bdrv_replace_child_drv = {
* Note: real unref of old_bs is done only on commit. * Note: real unref of old_bs is done only on commit.
* *
* The function doesn't update permissions, caller is responsible for this. * The function doesn't update permissions, caller is responsible for this.
*
* (*childp)->bs must not be NULL.
*
* Note that if new_bs == NULL, @childp is stored in a state object attached
* to @tran, so that the old child can be reinstated in the abort handler.
* Therefore, if @new_bs can be NULL, @childp must stay valid until the
* transaction is committed or aborted.
*
* If @free_empty_child is true and @new_bs is NULL, the BdrvChild is
* freed (on commit). @free_empty_child should only be false if the
* caller will free the BDrvChild themselves (which may be important
* if this is in turn called in another transactional context).
*/ */
static void bdrv_replace_child_tran(BdrvChild **childp, static void bdrv_replace_child_tran(BdrvChild *child, BlockDriverState *new_bs,
BlockDriverState *new_bs, Transaction *tran)
Transaction *tran,
bool free_empty_child)
{ {
BdrvReplaceChildState *s = g_new(BdrvReplaceChildState, 1); BdrvReplaceChildState *s = g_new(BdrvReplaceChildState, 1);
*s = (BdrvReplaceChildState) { *s = (BdrvReplaceChildState) {
.child = *childp, .child = child,
.childp = new_bs == NULL ? childp : NULL, .old_bs = child->bs,
.old_bs = (*childp)->bs,
.free_empty_child = free_empty_child,
}; };
tran_add(tran, &bdrv_replace_child_drv, s); tran_add(tran, &bdrv_replace_child_drv, s);
/* The abort handler relies on this */
assert(s->old_bs != NULL);
if (new_bs) { if (new_bs) {
bdrv_ref(new_bs); bdrv_ref(new_bs);
} }
/* bdrv_replace_child_noperm(child, new_bs);
* Pass free_empty_child=false, we will free the child (if /* old_bs reference is transparently moved from @child to @s */
* necessary) in bdrv_replace_child_commit() (if our
* @free_empty_child parameter was true).
*/
bdrv_replace_child_noperm(childp, new_bs, false);
/* old_bs reference is transparently moved from *childp to @s */
} }
/* /*
@ -2729,30 +2643,14 @@ uint64_t bdrv_qapi_perm_to_blk_perm(BlockPermission qapi_perm)
return permissions[qapi_perm]; return permissions[qapi_perm];
} }
/** static void bdrv_replace_child_noperm(BdrvChild *child,
* Replace (*childp)->bs by @new_bs. BlockDriverState *new_bs)
*
* If @new_bs is NULL, *childp will be set to NULL, too: BDS parents
* generally cannot handle a BdrvChild with .bs == NULL, so clearing
* BdrvChild.bs should generally immediately be followed by the
* BdrvChild pointer being cleared as well.
*
* If @free_empty_child is true and @new_bs is NULL, the BdrvChild is
* freed. @free_empty_child should only be false if the caller will
* free the BdrvChild themselves (this may be important in a
* transactional context, where it may only be freed on commit).
*/
static void bdrv_replace_child_noperm(BdrvChild **childp,
BlockDriverState *new_bs,
bool free_empty_child)
{ {
BdrvChild *child = *childp;
BlockDriverState *old_bs = child->bs; BlockDriverState *old_bs = child->bs;
int new_bs_quiesce_counter; int new_bs_quiesce_counter;
int drain_saldo; int drain_saldo;
assert(!child->frozen); assert(!child->frozen);
assert(old_bs != new_bs);
if (old_bs && new_bs) { if (old_bs && new_bs) {
assert(bdrv_get_aio_context(old_bs) == bdrv_get_aio_context(new_bs)); assert(bdrv_get_aio_context(old_bs) == bdrv_get_aio_context(new_bs));
@ -2781,9 +2679,6 @@ static void bdrv_replace_child_noperm(BdrvChild **childp,
} }
child->bs = new_bs; child->bs = new_bs;
if (!new_bs) {
*childp = NULL;
}
if (new_bs) { if (new_bs) {
QLIST_INSERT_HEAD(&new_bs->parents, child, next_parent); QLIST_INSERT_HEAD(&new_bs->parents, child, next_parent);
@ -2813,25 +2708,21 @@ static void bdrv_replace_child_noperm(BdrvChild **childp,
bdrv_parent_drained_end_single(child); bdrv_parent_drained_end_single(child);
drain_saldo++; drain_saldo++;
} }
if (free_empty_child && !child->bs) {
bdrv_child_free(child);
}
} }
/** static void bdrv_child_free(void *opaque)
* Free the given @child. {
* BdrvChild *c = opaque;
* The child must be empty (i.e. `child->bs == NULL`) and it must be
* unused (i.e. not in a children list). g_free(c->name);
*/ g_free(c);
static void bdrv_child_free(BdrvChild *child) }
static void bdrv_remove_empty_child(BdrvChild *child)
{ {
assert(!child->bs); assert(!child->bs);
assert(!child->next.le_prev); /* not in children list */ QLIST_SAFE_REMOVE(child, next);
bdrv_child_free(child);
g_free(child->name);
g_free(child);
} }
typedef struct BdrvAttachChildCommonState { typedef struct BdrvAttachChildCommonState {
@ -2846,35 +2737,27 @@ static void bdrv_attach_child_common_abort(void *opaque)
BdrvChild *child = *s->child; BdrvChild *child = *s->child;
BlockDriverState *bs = child->bs; BlockDriverState *bs = child->bs;
/* bdrv_replace_child_noperm(child, NULL);
* Pass free_empty_child=false, because we still need the child
* for the AioContext operations on the parent below; those
* BdrvChildClass methods all work on a BdrvChild object, so we
* need to keep it as an empty shell (after this function, it will
* not be attached to any parent, and it will not have a .bs).
*/
bdrv_replace_child_noperm(s->child, NULL, false);
if (bdrv_get_aio_context(bs) != s->old_child_ctx) { if (bdrv_get_aio_context(bs) != s->old_child_ctx) {
bdrv_try_set_aio_context(bs, s->old_child_ctx, &error_abort); bdrv_try_set_aio_context(bs, s->old_child_ctx, &error_abort);
} }
if (bdrv_child_get_parent_aio_context(child) != s->old_parent_ctx) { if (bdrv_child_get_parent_aio_context(child) != s->old_parent_ctx) {
GSList *ignore; GSList *ignore = g_slist_prepend(NULL, child);
/* No need to ignore `child`, because it has been detached already */
ignore = NULL;
child->klass->can_set_aio_ctx(child, s->old_parent_ctx, &ignore, child->klass->can_set_aio_ctx(child, s->old_parent_ctx, &ignore,
&error_abort); &error_abort);
g_slist_free(ignore); g_slist_free(ignore);
ignore = g_slist_prepend(NULL, child);
ignore = NULL;
child->klass->set_aio_ctx(child, s->old_parent_ctx, &ignore); child->klass->set_aio_ctx(child, s->old_parent_ctx, &ignore);
g_slist_free(ignore); g_slist_free(ignore);
} }
bdrv_unref(bs); bdrv_unref(bs);
bdrv_child_free(child); bdrv_remove_empty_child(child);
*s->child = NULL;
} }
static TransactionActionDrv bdrv_attach_child_common_drv = { static TransactionActionDrv bdrv_attach_child_common_drv = {
@ -2946,15 +2829,13 @@ static int bdrv_attach_child_common(BlockDriverState *child_bs,
if (ret < 0) { if (ret < 0) {
error_propagate(errp, local_err); error_propagate(errp, local_err);
bdrv_child_free(new_child); bdrv_remove_empty_child(new_child);
return ret; return ret;
} }
} }
bdrv_ref(child_bs); bdrv_ref(child_bs);
bdrv_replace_child_noperm(&new_child, child_bs, true); bdrv_replace_child_noperm(new_child, child_bs);
/* child_bs was non-NULL, so new_child must not have been freed */
assert(new_child != NULL);
*child = new_child; *child = new_child;
@ -2989,12 +2870,6 @@ static int bdrv_attach_child_noperm(BlockDriverState *parent_bs,
assert(parent_bs->drv); assert(parent_bs->drv);
if (bdrv_recurse_has_child(child_bs, parent_bs)) {
error_setg(errp, "Making '%s' a %s child of '%s' would create a cycle",
child_bs->node_name, child_name, parent_bs->node_name);
return -EINVAL;
}
bdrv_get_cumulative_perm(parent_bs, &perm, &shared_perm); bdrv_get_cumulative_perm(parent_bs, &perm, &shared_perm);
bdrv_child_perm(parent_bs, child_bs, NULL, child_role, NULL, bdrv_child_perm(parent_bs, child_bs, NULL, child_role, NULL,
perm, shared_perm, &perm, &shared_perm); perm, shared_perm, &perm, &shared_perm);
@ -3006,14 +2881,21 @@ static int bdrv_attach_child_noperm(BlockDriverState *parent_bs,
return ret; return ret;
} }
QLIST_INSERT_HEAD(&parent_bs->children, *child, next);
/*
* child is removed in bdrv_attach_child_common_abort(), so don't care to
* abort this change separately.
*/
return 0; return 0;
} }
static void bdrv_detach_child(BdrvChild **childp) static void bdrv_detach_child(BdrvChild *child)
{ {
BlockDriverState *old_bs = (*childp)->bs; BlockDriverState *old_bs = child->bs;
bdrv_replace_child_noperm(childp, NULL, true); bdrv_replace_child_noperm(child, NULL);
bdrv_remove_empty_child(child);
if (old_bs) { if (old_bs) {
/* /*
@ -3119,7 +3001,7 @@ void bdrv_root_unref_child(BdrvChild *child)
BlockDriverState *child_bs; BlockDriverState *child_bs;
child_bs = child->bs; child_bs = child->bs;
bdrv_detach_child(&child); bdrv_detach_child(child);
bdrv_unref(child_bs); bdrv_unref(child_bs);
} }
@ -4812,8 +4694,6 @@ static void bdrv_close(BlockDriverState *bs)
bs->explicit_options = NULL; bs->explicit_options = NULL;
qobject_unref(bs->full_open_options); qobject_unref(bs->full_open_options);
bs->full_open_options = NULL; bs->full_open_options = NULL;
g_free(bs->block_status_cache);
bs->block_status_cache = NULL;
bdrv_release_named_dirty_bitmaps(bs); bdrv_release_named_dirty_bitmaps(bs);
assert(QLIST_EMPTY(&bs->dirty_bitmaps)); assert(QLIST_EMPTY(&bs->dirty_bitmaps));
@ -4929,7 +4809,6 @@ static bool should_update_child(BdrvChild *c, BlockDriverState *to)
typedef struct BdrvRemoveFilterOrCowChild { typedef struct BdrvRemoveFilterOrCowChild {
BdrvChild *child; BdrvChild *child;
BlockDriverState *bs;
bool is_backing; bool is_backing;
} BdrvRemoveFilterOrCowChild; } BdrvRemoveFilterOrCowChild;
@ -4938,6 +4817,7 @@ static void bdrv_remove_filter_or_cow_child_abort(void *opaque)
BdrvRemoveFilterOrCowChild *s = opaque; BdrvRemoveFilterOrCowChild *s = opaque;
BlockDriverState *parent_bs = s->child->opaque; BlockDriverState *parent_bs = s->child->opaque;
QLIST_INSERT_HEAD(&parent_bs->children, s->child, next);
if (s->is_backing) { if (s->is_backing) {
parent_bs->backing = s->child; parent_bs->backing = s->child;
} else { } else {
@ -4959,19 +4839,10 @@ static void bdrv_remove_filter_or_cow_child_commit(void *opaque)
bdrv_child_free(s->child); bdrv_child_free(s->child);
} }
static void bdrv_remove_filter_or_cow_child_clean(void *opaque)
{
BdrvRemoveFilterOrCowChild *s = opaque;
/* Drop the bs reference after the transaction is done */
bdrv_unref(s->bs);
g_free(s);
}
static TransactionActionDrv bdrv_remove_filter_or_cow_child_drv = { static TransactionActionDrv bdrv_remove_filter_or_cow_child_drv = {
.abort = bdrv_remove_filter_or_cow_child_abort, .abort = bdrv_remove_filter_or_cow_child_abort,
.commit = bdrv_remove_filter_or_cow_child_commit, .commit = bdrv_remove_filter_or_cow_child_commit,
.clean = bdrv_remove_filter_or_cow_child_clean, .clean = g_free,
}; };
/* /*
@ -4982,41 +4853,31 @@ static void bdrv_remove_file_or_backing_child(BlockDriverState *bs,
BdrvChild *child, BdrvChild *child,
Transaction *tran) Transaction *tran)
{ {
BdrvChild **childp;
BdrvRemoveFilterOrCowChild *s; BdrvRemoveFilterOrCowChild *s;
assert(child == bs->backing || child == bs->file);
if (!child) { if (!child) {
return; return;
} }
/*
* Keep a reference to @bs so @childp will stay valid throughout the
* transaction (required by bdrv_replace_child_tran())
*/
bdrv_ref(bs);
if (child == bs->backing) {
childp = &bs->backing;
} else if (child == bs->file) {
childp = &bs->file;
} else {
g_assert_not_reached();
}
if (child->bs) { if (child->bs) {
/* bdrv_replace_child_tran(child, NULL, tran);
* Pass free_empty_child=false, we will free the child in
* bdrv_remove_filter_or_cow_child_commit()
*/
bdrv_replace_child_tran(childp, NULL, tran, false);
} }
s = g_new(BdrvRemoveFilterOrCowChild, 1); s = g_new(BdrvRemoveFilterOrCowChild, 1);
*s = (BdrvRemoveFilterOrCowChild) { *s = (BdrvRemoveFilterOrCowChild) {
.child = child, .child = child,
.bs = bs, .is_backing = (child == bs->backing),
.is_backing = (childp == &bs->backing),
}; };
tran_add(tran, &bdrv_remove_filter_or_cow_child_drv, s); tran_add(tran, &bdrv_remove_filter_or_cow_child_drv, s);
QLIST_SAFE_REMOVE(child, next);
if (s->is_backing) {
bs->backing = NULL;
} else {
bs->file = NULL;
}
} }
/* /*
@ -5037,8 +4898,6 @@ static int bdrv_replace_node_noperm(BlockDriverState *from,
{ {
BdrvChild *c, *next; BdrvChild *c, *next;
assert(to != NULL);
QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) { QLIST_FOREACH_SAFE(c, &from->parents, next_parent, next) {
assert(c->bs == from); assert(c->bs == from);
if (!should_update_child(c, to)) { if (!should_update_child(c, to)) {
@ -5054,12 +4913,7 @@ static int bdrv_replace_node_noperm(BlockDriverState *from,
c->name, from->node_name); c->name, from->node_name);
return -EPERM; return -EPERM;
} }
bdrv_replace_child_tran(c, to, tran);
/*
* Passing a pointer to the local variable @c is fine here, because
* @to is not NULL, and so &c will not be attached to the transaction.
*/
bdrv_replace_child_tran(&c, to, tran, true);
} }
return 0; return 0;
@ -5074,8 +4928,6 @@ static int bdrv_replace_node_noperm(BlockDriverState *from,
* *
* With @detach_subchain=true @to must be in a backing chain of @from. In this * With @detach_subchain=true @to must be in a backing chain of @from. In this
* case backing link of the cow-parent of @to is removed. * case backing link of the cow-parent of @to is removed.
*
* @to must not be NULL.
*/ */
static int bdrv_replace_node_common(BlockDriverState *from, static int bdrv_replace_node_common(BlockDriverState *from,
BlockDriverState *to, BlockDriverState *to,
@ -5088,8 +4940,6 @@ static int bdrv_replace_node_common(BlockDriverState *from,
BlockDriverState *to_cow_parent = NULL; BlockDriverState *to_cow_parent = NULL;
int ret; int ret;
assert(to != NULL);
if (detach_subchain) { if (detach_subchain) {
assert(bdrv_chain_contains(from, to)); assert(bdrv_chain_contains(from, to));
assert(from != to); assert(from != to);
@ -5145,9 +4995,6 @@ out:
return ret; return ret;
} }
/**
* Replace node @from by @to (where neither may be NULL).
*/
int bdrv_replace_node(BlockDriverState *from, BlockDriverState *to, int bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
Error **errp) Error **errp)
{ {
@ -5201,39 +5048,6 @@ out:
return ret; return ret;
} }
/* Not for empty child */
int bdrv_replace_child_bs(BdrvChild *child, BlockDriverState *new_bs,
Error **errp)
{
int ret;
Transaction *tran = tran_new();
g_autoptr(GHashTable) found = NULL;
g_autoptr(GSList) refresh_list = NULL;
BlockDriverState *old_bs = child->bs;
bdrv_ref(old_bs);
bdrv_drained_begin(old_bs);
bdrv_drained_begin(new_bs);
bdrv_replace_child_tran(&child, new_bs, tran, true);
/* @new_bs must have been non-NULL, so @child must not have been freed */
assert(child != NULL);
found = g_hash_table_new(NULL, NULL);
refresh_list = bdrv_topological_dfs(refresh_list, found, old_bs);
refresh_list = bdrv_topological_dfs(refresh_list, found, new_bs);
ret = bdrv_list_refresh_perms(refresh_list, NULL, tran, errp);
tran_finalize(tran, ret);
bdrv_drained_end(old_bs);
bdrv_drained_end(new_bs);
bdrv_unref(old_bs);
return ret;
}
static void bdrv_delete(BlockDriverState *bs) static void bdrv_delete(BlockDriverState *bs)
{ {
assert(bdrv_op_blocker_is_empty(bs)); assert(bdrv_op_blocker_is_empty(bs));
@ -5250,61 +5064,29 @@ static void bdrv_delete(BlockDriverState *bs)
g_free(bs); g_free(bs);
} }
BlockDriverState *bdrv_insert_node(BlockDriverState *bs, QDict *node_options,
/*
* Replace @bs by newly created block node.
*
* @options is a QDict of options to pass to the block drivers, or NULL for an
* empty set of options. The reference to the QDict belongs to the block layer
* after the call (even on failure), so if the caller intends to reuse the
* dictionary, it needs to use qobject_ref() before calling bdrv_open.
*/
BlockDriverState *bdrv_insert_node(BlockDriverState *bs, QDict *options,
int flags, Error **errp) int flags, Error **errp)
{ {
ERRP_GUARD(); BlockDriverState *new_node_bs;
int ret; Error *local_err = NULL;
BlockDriverState *new_node_bs = NULL;
const char *drvname, *node_name;
BlockDriver *drv;
drvname = qdict_get_try_str(options, "driver"); new_node_bs = bdrv_open(NULL, NULL, node_options, flags, errp);
if (!drvname) { if (new_node_bs == NULL) {
error_setg(errp, "driver is not specified");
goto fail;
}
drv = bdrv_find_format(drvname);
if (!drv) {
error_setg(errp, "Unknown driver: '%s'", drvname);
goto fail;
}
node_name = qdict_get_try_str(options, "node-name");
new_node_bs = bdrv_new_open_driver_opts(drv, node_name, options, flags,
errp);
options = NULL; /* bdrv_new_open_driver() eats options */
if (!new_node_bs) {
error_prepend(errp, "Could not create node: "); error_prepend(errp, "Could not create node: ");
goto fail; return NULL;
} }
bdrv_drained_begin(bs); bdrv_drained_begin(bs);
ret = bdrv_replace_node(bs, new_node_bs, errp); bdrv_replace_node(bs, new_node_bs, &local_err);
bdrv_drained_end(bs); bdrv_drained_end(bs);
if (ret < 0) { if (local_err) {
error_prepend(errp, "Could not replace node: "); bdrv_unref(new_node_bs);
goto fail; error_propagate(errp, local_err);
return NULL;
} }
return new_node_bs; return new_node_bs;
fail:
qobject_unref(options);
bdrv_unref(new_node_bs);
return NULL;
} }
/* /*
@ -6506,7 +6288,6 @@ static int bdrv_inactivate_recurse(BlockDriverState *bs)
{ {
BdrvChild *child, *parent; BdrvChild *child, *parent;
int ret; int ret;
uint64_t cumulative_perms, cumulative_shared_perms;
if (!bs->drv) { if (!bs->drv) {
return -ENOMEDIUM; return -ENOMEDIUM;
@ -6537,13 +6318,6 @@ static int bdrv_inactivate_recurse(BlockDriverState *bs)
} }
} }
bdrv_get_cumulative_perm(bs, &cumulative_perms,
&cumulative_shared_perms);
if (cumulative_perms & (BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED)) {
/* Our inactive parents still need write access. Inactivation failed. */
return -EPERM;
}
bs->open_flags |= BDRV_O_INACTIVE; bs->open_flags |= BDRV_O_INACTIVE;
/* /*
@ -7879,76 +7653,3 @@ BlockDriverState *bdrv_backing_chain_next(BlockDriverState *bs)
{ {
return bdrv_skip_filters(bdrv_cow_bs(bdrv_skip_filters(bs))); return bdrv_skip_filters(bdrv_cow_bs(bdrv_skip_filters(bs)));
} }
/**
* Check whether [offset, offset + bytes) overlaps with the cached
* block-status data region.
*
* If so, and @pnum is not NULL, set *pnum to `bsc.data_end - offset`,
* which is what bdrv_bsc_is_data()'s interface needs.
* Otherwise, *pnum is not touched.
*/
static bool bdrv_bsc_range_overlaps_locked(BlockDriverState *bs,
int64_t offset, int64_t bytes,
int64_t *pnum)
{
BdrvBlockStatusCache *bsc = qatomic_rcu_read(&bs->block_status_cache);
bool overlaps;
overlaps =
qatomic_read(&bsc->valid) &&
ranges_overlap(offset, bytes, bsc->data_start,
bsc->data_end - bsc->data_start);
if (overlaps && pnum) {
*pnum = bsc->data_end - offset;
}
return overlaps;
}
/**
* See block_int.h for this function's documentation.
*/
bool bdrv_bsc_is_data(BlockDriverState *bs, int64_t offset, int64_t *pnum)
{
RCU_READ_LOCK_GUARD();
return bdrv_bsc_range_overlaps_locked(bs, offset, 1, pnum);
}
/**
* See block_int.h for this function's documentation.
*/
void bdrv_bsc_invalidate_range(BlockDriverState *bs,
int64_t offset, int64_t bytes)
{
RCU_READ_LOCK_GUARD();
if (bdrv_bsc_range_overlaps_locked(bs, offset, bytes, NULL)) {
qatomic_set(&bs->block_status_cache->valid, false);
}
}
/**
* See block_int.h for this function's documentation.
*/
void bdrv_bsc_fill(BlockDriverState *bs, int64_t offset, int64_t bytes)
{
BdrvBlockStatusCache *new_bsc = g_new(BdrvBlockStatusCache, 1);
BdrvBlockStatusCache *old_bsc;
*new_bsc = (BdrvBlockStatusCache) {
.valid = true,
.data_start = offset,
.data_end = offset + bytes,
};
QEMU_LOCK_GUARD(&bs->bsc_modify_lock);
old_bsc = qatomic_rcu_read(&bs->block_status_cache);
qatomic_rcu_set(&bs->block_status_cache, new_bsc);
if (old_bsc) {
g_free_rcu(old_bsc, rcu);
}
}

View File

@ -98,8 +98,6 @@ AioTaskPool *coroutine_fn aio_task_pool_new(int max_busy_tasks)
{ {
AioTaskPool *pool = g_new0(AioTaskPool, 1); AioTaskPool *pool = g_new0(AioTaskPool, 1);
assert(max_busy_tasks > 0);
pool->main_co = qemu_coroutine_self(); pool->main_co = qemu_coroutine_self();
pool->max_busy_tasks = max_busy_tasks; pool->max_busy_tasks = max_busy_tasks;

253
block/backup-top.c Normal file
View File

@ -0,0 +1,253 @@
/*
* backup-top filter driver
*
* The driver performs Copy-Before-Write (CBW) operation: it is injected above
* some node, and before each write it copies _old_ data to the target node.
*
* Copyright (c) 2018-2019 Virtuozzo International GmbH.
*
* Author:
* Sementsov-Ogievskiy Vladimir <vsementsov@virtuozzo.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "sysemu/block-backend.h"
#include "qemu/cutils.h"
#include "qapi/error.h"
#include "block/block_int.h"
#include "block/qdict.h"
#include "block/block-copy.h"
#include "block/backup-top.h"
typedef struct BDRVBackupTopState {
BlockCopyState *bcs;
BdrvChild *target;
int64_t cluster_size;
} BDRVBackupTopState;
static coroutine_fn int backup_top_co_preadv(
BlockDriverState *bs, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, int flags)
{
return bdrv_co_preadv(bs->backing, offset, bytes, qiov, flags);
}
static coroutine_fn int backup_top_cbw(BlockDriverState *bs, uint64_t offset,
uint64_t bytes, BdrvRequestFlags flags)
{
BDRVBackupTopState *s = bs->opaque;
uint64_t off, end;
if (flags & BDRV_REQ_WRITE_UNCHANGED) {
return 0;
}
off = QEMU_ALIGN_DOWN(offset, s->cluster_size);
end = QEMU_ALIGN_UP(offset + bytes, s->cluster_size);
return block_copy(s->bcs, off, end - off, true);
}
static int coroutine_fn backup_top_co_pdiscard(BlockDriverState *bs,
int64_t offset, int bytes)
{
int ret = backup_top_cbw(bs, offset, bytes, 0);
if (ret < 0) {
return ret;
}
return bdrv_co_pdiscard(bs->backing, offset, bytes);
}
static int coroutine_fn backup_top_co_pwrite_zeroes(BlockDriverState *bs,
int64_t offset, int bytes, BdrvRequestFlags flags)
{
int ret = backup_top_cbw(bs, offset, bytes, flags);
if (ret < 0) {
return ret;
}
return bdrv_co_pwrite_zeroes(bs->backing, offset, bytes, flags);
}
static coroutine_fn int backup_top_co_pwritev(BlockDriverState *bs,
uint64_t offset,
uint64_t bytes,
QEMUIOVector *qiov, int flags)
{
int ret = backup_top_cbw(bs, offset, bytes, flags);
if (ret < 0) {
return ret;
}
return bdrv_co_pwritev(bs->backing, offset, bytes, qiov, flags);
}
static int coroutine_fn backup_top_co_flush(BlockDriverState *bs)
{
if (!bs->backing) {
return 0;
}
return bdrv_co_flush(bs->backing->bs);
}
static void backup_top_refresh_filename(BlockDriverState *bs)
{
if (bs->backing == NULL) {
/*
* we can be here after failed bdrv_attach_child in
* bdrv_set_backing_hd
*/
return;
}
pstrcpy(bs->exact_filename, sizeof(bs->exact_filename),
bs->backing->bs->filename);
}
static void backup_top_child_perm(BlockDriverState *bs, BdrvChild *c,
BdrvChildRole role,
BlockReopenQueue *reopen_queue,
uint64_t perm, uint64_t shared,
uint64_t *nperm, uint64_t *nshared)
{
if (!(role & BDRV_CHILD_FILTERED)) {
/*
* Target child
*
* Share write to target (child_file), to not interfere
* with guest writes to its disk which may be in target backing chain.
* Can't resize during a backup block job because we check the size
* only upfront.
*/
*nshared = BLK_PERM_ALL & ~BLK_PERM_RESIZE;
*nperm = BLK_PERM_WRITE;
} else {
/* Source child */
bdrv_default_perms(bs, c, role, reopen_queue,
perm, shared, nperm, nshared);
if (perm & BLK_PERM_WRITE) {
*nperm = *nperm | BLK_PERM_CONSISTENT_READ;
}
*nshared &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE);
}
}
BlockDriver bdrv_backup_top_filter = {
.format_name = "backup-top",
.instance_size = sizeof(BDRVBackupTopState),
.bdrv_co_preadv = backup_top_co_preadv,
.bdrv_co_pwritev = backup_top_co_pwritev,
.bdrv_co_pwrite_zeroes = backup_top_co_pwrite_zeroes,
.bdrv_co_pdiscard = backup_top_co_pdiscard,
.bdrv_co_flush = backup_top_co_flush,
.bdrv_refresh_filename = backup_top_refresh_filename,
.bdrv_child_perm = backup_top_child_perm,
.is_filter = true,
};
BlockDriverState *bdrv_backup_top_append(BlockDriverState *source,
BlockDriverState *target,
const char *filter_node_name,
uint64_t cluster_size,
BackupPerf *perf,
BdrvRequestFlags write_flags,
BlockCopyState **bcs,
Error **errp)
{
ERRP_GUARD();
int ret;
BDRVBackupTopState *state;
BlockDriverState *top;
bool appended = false;
assert(source->total_sectors == target->total_sectors);
top = bdrv_new_open_driver(&bdrv_backup_top_filter, filter_node_name,
BDRV_O_RDWR, errp);
if (!top) {
return NULL;
}
state = top->opaque;
top->total_sectors = source->total_sectors;
top->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED |
(BDRV_REQ_FUA & source->supported_write_flags);
top->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED |
((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) &
source->supported_zero_flags);
bdrv_ref(target);
state->target = bdrv_attach_child(top, target, "target", &child_of_bds,
BDRV_CHILD_DATA, errp);
if (!state->target) {
bdrv_unref(target);
bdrv_unref(top);
return NULL;
}
bdrv_drained_begin(source);
ret = bdrv_append(top, source, errp);
if (ret < 0) {
error_prepend(errp, "Cannot append backup-top filter: ");
goto fail;
}
appended = true;
state->cluster_size = cluster_size;
state->bcs = block_copy_state_new(top->backing, state->target,
cluster_size, perf->use_copy_range,
write_flags, errp);
if (!state->bcs) {
error_prepend(errp, "Cannot create block-copy-state: ");
goto fail;
}
*bcs = state->bcs;
bdrv_drained_end(source);
return top;
fail:
if (appended) {
bdrv_backup_top_drop(top);
} else {
bdrv_unref(top);
}
bdrv_drained_end(source);
return NULL;
}
void bdrv_backup_top_drop(BlockDriverState *bs)
{
BDRVBackupTopState *s = bs->opaque;
bdrv_drop_filter(bs, &error_abort);
block_copy_state_free(s->bcs);
bdrv_unref(bs);
}

View File

@ -1,10 +1,10 @@
/* /*
* copy-before-write filter driver * backup-top filter driver
* *
* The driver performs Copy-Before-Write (CBW) operation: it is injected above * The driver performs Copy-Before-Write (CBW) operation: it is injected above
* some node, and before each write it copies _old_ data to the target node. * some node, and before each write it copies _old_ data to the target node.
* *
* Copyright (c) 2018-2021 Virtuozzo International GmbH. * Copyright (c) 2018-2019 Virtuozzo International GmbH.
* *
* Author: * Author:
* Sementsov-Ogievskiy Vladimir <vsementsov@virtuozzo.com> * Sementsov-Ogievskiy Vladimir <vsementsov@virtuozzo.com>
@ -23,17 +23,20 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef COPY_BEFORE_WRITE_H #ifndef BACKUP_TOP_H
#define COPY_BEFORE_WRITE_H #define BACKUP_TOP_H
#include "block/block_int.h" #include "block/block_int.h"
#include "block/block-copy.h" #include "block/block-copy.h"
BlockDriverState *bdrv_cbw_append(BlockDriverState *source, BlockDriverState *bdrv_backup_top_append(BlockDriverState *source,
BlockDriverState *target, BlockDriverState *target,
const char *filter_node_name, const char *filter_node_name,
BlockCopyState **bcs, uint64_t cluster_size,
Error **errp); BackupPerf *perf,
void bdrv_cbw_drop(BlockDriverState *bs); BdrvRequestFlags write_flags,
BlockCopyState **bcs,
Error **errp);
void bdrv_backup_top_drop(BlockDriverState *bs);
#endif /* COPY_BEFORE_WRITE_H */ #endif /* BACKUP_TOP_H */

View File

@ -27,11 +27,13 @@
#include "qemu/bitmap.h" #include "qemu/bitmap.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "block/copy-before-write.h" #include "block/backup-top.h"
#define BACKUP_CLUSTER_SIZE_DEFAULT (1 << 16)
typedef struct BackupBlockJob { typedef struct BackupBlockJob {
BlockJob common; BlockJob common;
BlockDriverState *cbw; BlockDriverState *backup_top;
BlockDriverState *source_bs; BlockDriverState *source_bs;
BlockDriverState *target_bs; BlockDriverState *target_bs;
@ -102,7 +104,7 @@ static void backup_clean(Job *job)
{ {
BackupBlockJob *s = container_of(job, BackupBlockJob, common.job); BackupBlockJob *s = container_of(job, BackupBlockJob, common.job);
block_job_remove_all_bdrv(&s->common); block_job_remove_all_bdrv(&s->common);
bdrv_cbw_drop(s->cbw); bdrv_backup_top_drop(s->backup_top);
} }
void backup_do_checkpoint(BlockJob *job, Error **errp) void backup_do_checkpoint(BlockJob *job, Error **errp)
@ -233,16 +235,18 @@ static void backup_init_bcs_bitmap(BackupBlockJob *job)
BdrvDirtyBitmap *bcs_bitmap = block_copy_dirty_bitmap(job->bcs); BdrvDirtyBitmap *bcs_bitmap = block_copy_dirty_bitmap(job->bcs);
if (job->sync_mode == MIRROR_SYNC_MODE_BITMAP) { if (job->sync_mode == MIRROR_SYNC_MODE_BITMAP) {
bdrv_clear_dirty_bitmap(bcs_bitmap, NULL);
ret = bdrv_dirty_bitmap_merge_internal(bcs_bitmap, job->sync_bitmap, ret = bdrv_dirty_bitmap_merge_internal(bcs_bitmap, job->sync_bitmap,
NULL, true); NULL, true);
assert(ret); assert(ret);
} else if (job->sync_mode == MIRROR_SYNC_MODE_TOP) { } else {
/* if (job->sync_mode == MIRROR_SYNC_MODE_TOP) {
* We can't hog the coroutine to initialize this thoroughly. /*
* Set a flag and resume work when we are able to yield safely. * We can't hog the coroutine to initialize this thoroughly.
*/ * Set a flag and resume work when we are able to yield safely.
block_copy_set_skip_unallocated(job->bcs, true); */
block_copy_set_skip_unallocated(job->bcs, true);
}
bdrv_set_dirty_bitmap(bcs_bitmap, 0, job->len);
} }
estimate = bdrv_get_dirty_count(bcs_bitmap); estimate = bdrv_get_dirty_count(bcs_bitmap);
@ -327,12 +331,11 @@ static void coroutine_fn backup_set_speed(BlockJob *job, int64_t speed)
} }
} }
static bool backup_cancel(Job *job, bool force) static void backup_cancel(Job *job, bool force)
{ {
BackupBlockJob *s = container_of(job, BackupBlockJob, common.job); BackupBlockJob *s = container_of(job, BackupBlockJob, common.job);
bdrv_cancel_in_flight(s->target_bs); bdrv_cancel_in_flight(s->target_bs);
return true;
} }
static const BlockJobDriver backup_job_driver = { static const BlockJobDriver backup_job_driver = {
@ -351,6 +354,43 @@ static const BlockJobDriver backup_job_driver = {
.set_speed = backup_set_speed, .set_speed = backup_set_speed,
}; };
static int64_t backup_calculate_cluster_size(BlockDriverState *target,
Error **errp)
{
int ret;
BlockDriverInfo bdi;
bool target_does_cow = bdrv_backing_chain_next(target);
/*
* If there is no backing file on the target, we cannot rely on COW if our
* backup cluster size is smaller than the target cluster size. Even for
* targets with a backing file, try to avoid COW if possible.
*/
ret = bdrv_get_info(target, &bdi);
if (ret == -ENOTSUP && !target_does_cow) {
/* Cluster size is not defined */
warn_report("The target block device doesn't provide "
"information about the block size and it doesn't have a "
"backing file. The default block size of %u bytes is "
"used. If the actual block size of the target exceeds "
"this default, the backup may be unusable",
BACKUP_CLUSTER_SIZE_DEFAULT);
return BACKUP_CLUSTER_SIZE_DEFAULT;
} else if (ret < 0 && !target_does_cow) {
error_setg_errno(errp, -ret,
"Couldn't determine the cluster size of the target image, "
"which has no backing file");
error_append_hint(errp,
"Aborting, since this may create an unusable destination image\n");
return ret;
} else if (ret < 0 && target_does_cow) {
/* Not fatal; just trudge on ahead. */
return BACKUP_CLUSTER_SIZE_DEFAULT;
}
return MAX(BACKUP_CLUSTER_SIZE_DEFAULT, bdi.cluster_size);
}
BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs, BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
BlockDriverState *target, int64_t speed, BlockDriverState *target, int64_t speed,
MirrorSyncMode sync_mode, BdrvDirtyBitmap *sync_bitmap, MirrorSyncMode sync_mode, BdrvDirtyBitmap *sync_bitmap,
@ -367,7 +407,8 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
int64_t len, target_len; int64_t len, target_len;
BackupBlockJob *job = NULL; BackupBlockJob *job = NULL;
int64_t cluster_size; int64_t cluster_size;
BlockDriverState *cbw = NULL; BdrvRequestFlags write_flags;
BlockDriverState *backup_top = NULL;
BlockCopyState *bcs = NULL; BlockCopyState *bcs = NULL;
assert(bs); assert(bs);
@ -408,8 +449,13 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
return NULL; return NULL;
} }
if (perf->max_workers < 1 || perf->max_workers > INT_MAX) { cluster_size = backup_calculate_cluster_size(target, errp);
error_setg(errp, "max-workers must be between 1 and %d", INT_MAX); if (cluster_size < 0) {
goto error;
}
if (perf->max_workers < 1) {
error_setg(errp, "max-workers must be greater than zero");
return NULL; return NULL;
} }
@ -419,6 +465,13 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
return NULL; return NULL;
} }
if (perf->max_chunk && perf->max_chunk < cluster_size) {
error_setg(errp, "Required max-chunk (%" PRIi64 ") is less than backup "
"cluster size (%" PRIi64 ")", perf->max_chunk, cluster_size);
return NULL;
}
if (sync_bitmap) { if (sync_bitmap) {
/* If we need to write to this bitmap, check that we can: */ /* If we need to write to this bitmap, check that we can: */
if (bitmap_mode != BITMAP_SYNC_MODE_NEVER && if (bitmap_mode != BITMAP_SYNC_MODE_NEVER &&
@ -451,28 +504,39 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
goto error; goto error;
} }
cbw = bdrv_cbw_append(bs, target, filter_node_name, &bcs, errp); /*
if (!cbw) { * If source is in backing chain of target assume that target is going to be
goto error; * used for "image fleecing", i.e. it should represent a kind of snapshot of
} * source at backup-start point in time. And target is going to be read by
* somebody (for example, used as NBD export) during backup job.
*
* In this case, we need to add BDRV_REQ_SERIALISING write flag to avoid
* intersection of backup writes and third party reads from target,
* otherwise reading from target we may occasionally read already updated by
* guest data.
*
* For more information see commit f8d59dfb40bb and test
* tests/qemu-iotests/222
*/
write_flags = (bdrv_chain_contains(target, bs) ? BDRV_REQ_SERIALISING : 0) |
(compress ? BDRV_REQ_WRITE_COMPRESSED : 0),
cluster_size = block_copy_cluster_size(bcs); backup_top = bdrv_backup_top_append(bs, target, filter_node_name,
cluster_size, perf,
if (perf->max_chunk && perf->max_chunk < cluster_size) { write_flags, &bcs, errp);
error_setg(errp, "Required max-chunk (%" PRIi64 ") is less than backup " if (!backup_top) {
"cluster size (%" PRIi64 ")", perf->max_chunk, cluster_size);
goto error; goto error;
} }
/* job->len is fixed, so we can't allow resize */ /* job->len is fixed, so we can't allow resize */
job = block_job_create(job_id, &backup_job_driver, txn, cbw, job = block_job_create(job_id, &backup_job_driver, txn, backup_top,
0, BLK_PERM_ALL, 0, BLK_PERM_ALL,
speed, creation_flags, cb, opaque, errp); speed, creation_flags, cb, opaque, errp);
if (!job) { if (!job) {
goto error; goto error;
} }
job->cbw = cbw; job->backup_top = backup_top;
job->source_bs = bs; job->source_bs = bs;
job->target_bs = target; job->target_bs = target;
job->on_source_error = on_source_error; job->on_source_error = on_source_error;
@ -485,11 +549,10 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
job->len = len; job->len = len;
job->perf = *perf; job->perf = *perf;
block_copy_set_copy_opts(bcs, perf->use_copy_range, compress);
block_copy_set_progress_meter(bcs, &job->common.job.progress); block_copy_set_progress_meter(bcs, &job->common.job.progress);
block_copy_set_speed(bcs, speed); block_copy_set_speed(bcs, speed);
/* Required permissions are taken by copy-before-write filter target */ /* Required permissions are already taken by backup-top target */
block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL, block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL,
&error_abort); &error_abort);
@ -499,8 +562,8 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
if (sync_bitmap) { if (sync_bitmap) {
bdrv_reclaim_dirty_bitmap(sync_bitmap, NULL); bdrv_reclaim_dirty_bitmap(sync_bitmap, NULL);
} }
if (cbw) { if (backup_top) {
bdrv_cbw_drop(cbw); bdrv_backup_top_drop(backup_top);
} }
return NULL; return NULL;

View File

@ -631,8 +631,8 @@ static int rule_check(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
} }
static int coroutine_fn static int coroutine_fn
blkdebug_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, blkdebug_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, BdrvRequestFlags flags) QEMUIOVector *qiov, int flags)
{ {
int err; int err;
@ -652,8 +652,8 @@ blkdebug_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
} }
static int coroutine_fn static int coroutine_fn
blkdebug_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, blkdebug_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, BdrvRequestFlags flags) QEMUIOVector *qiov, int flags)
{ {
int err; int err;
@ -684,7 +684,7 @@ static int blkdebug_co_flush(BlockDriverState *bs)
} }
static int coroutine_fn blkdebug_co_pwrite_zeroes(BlockDriverState *bs, static int coroutine_fn blkdebug_co_pwrite_zeroes(BlockDriverState *bs,
int64_t offset, int64_t bytes, int64_t offset, int bytes,
BdrvRequestFlags flags) BdrvRequestFlags flags)
{ {
uint32_t align = MAX(bs->bl.request_alignment, uint32_t align = MAX(bs->bl.request_alignment,
@ -717,7 +717,7 @@ static int coroutine_fn blkdebug_co_pwrite_zeroes(BlockDriverState *bs,
} }
static int coroutine_fn blkdebug_co_pdiscard(BlockDriverState *bs, static int coroutine_fn blkdebug_co_pdiscard(BlockDriverState *bs,
int64_t offset, int64_t bytes) int64_t offset, int bytes)
{ {
uint32_t align = bs->bl.pdiscard_alignment; uint32_t align = bs->bl.pdiscard_alignment;
int err; int err;

View File

@ -301,8 +301,8 @@ static void blk_log_writes_refresh_limits(BlockDriverState *bs, Error **errp)
} }
static int coroutine_fn static int coroutine_fn
blk_log_writes_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, blk_log_writes_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, BdrvRequestFlags flags) QEMUIOVector *qiov, int flags)
{ {
return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags); return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
} }
@ -460,16 +460,16 @@ blk_log_writes_co_do_file_pdiscard(BlkLogWritesFileReq *fr)
} }
static int coroutine_fn static int coroutine_fn
blk_log_writes_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, blk_log_writes_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, BdrvRequestFlags flags) QEMUIOVector *qiov, int flags)
{ {
return blk_log_writes_co_log(bs, offset, bytes, qiov, flags, return blk_log_writes_co_log(bs, offset, bytes, qiov, flags,
blk_log_writes_co_do_file_pwritev, 0, false); blk_log_writes_co_do_file_pwritev, 0, false);
} }
static int coroutine_fn static int coroutine_fn
blk_log_writes_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, blk_log_writes_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int bytes,
int64_t bytes, BdrvRequestFlags flags) BdrvRequestFlags flags)
{ {
return blk_log_writes_co_log(bs, offset, bytes, NULL, flags, return blk_log_writes_co_log(bs, offset, bytes, NULL, flags,
blk_log_writes_co_do_file_pwrite_zeroes, 0, blk_log_writes_co_do_file_pwrite_zeroes, 0,
@ -484,9 +484,9 @@ static int coroutine_fn blk_log_writes_co_flush_to_disk(BlockDriverState *bs)
} }
static int coroutine_fn static int coroutine_fn
blk_log_writes_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes) blk_log_writes_co_pdiscard(BlockDriverState *bs, int64_t offset, int count)
{ {
return blk_log_writes_co_log(bs, offset, bytes, NULL, 0, return blk_log_writes_co_log(bs, offset, count, NULL, 0,
blk_log_writes_co_do_file_pdiscard, blk_log_writes_co_do_file_pdiscard,
LOG_DISCARD_FLAG, false); LOG_DISCARD_FLAG, false);
} }

View File

@ -72,7 +72,7 @@ static void block_request_create(uint64_t reqid, BlockDriverState *bs,
} }
static int coroutine_fn blkreplay_co_preadv(BlockDriverState *bs, static int coroutine_fn blkreplay_co_preadv(BlockDriverState *bs,
int64_t offset, int64_t bytes, QEMUIOVector *qiov, BdrvRequestFlags flags) uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags)
{ {
uint64_t reqid = blkreplay_next_id(); uint64_t reqid = blkreplay_next_id();
int ret = bdrv_co_preadv(bs->file, offset, bytes, qiov, flags); int ret = bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
@ -83,7 +83,7 @@ static int coroutine_fn blkreplay_co_preadv(BlockDriverState *bs,
} }
static int coroutine_fn blkreplay_co_pwritev(BlockDriverState *bs, static int coroutine_fn blkreplay_co_pwritev(BlockDriverState *bs,
int64_t offset, int64_t bytes, QEMUIOVector *qiov, BdrvRequestFlags flags) uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags)
{ {
uint64_t reqid = blkreplay_next_id(); uint64_t reqid = blkreplay_next_id();
int ret = bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags); int ret = bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags);
@ -94,7 +94,7 @@ static int coroutine_fn blkreplay_co_pwritev(BlockDriverState *bs,
} }
static int coroutine_fn blkreplay_co_pwrite_zeroes(BlockDriverState *bs, static int coroutine_fn blkreplay_co_pwrite_zeroes(BlockDriverState *bs,
int64_t offset, int64_t bytes, BdrvRequestFlags flags) int64_t offset, int bytes, BdrvRequestFlags flags)
{ {
uint64_t reqid = blkreplay_next_id(); uint64_t reqid = blkreplay_next_id();
int ret = bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags); int ret = bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags);
@ -105,7 +105,7 @@ static int coroutine_fn blkreplay_co_pwrite_zeroes(BlockDriverState *bs,
} }
static int coroutine_fn blkreplay_co_pdiscard(BlockDriverState *bs, static int coroutine_fn blkreplay_co_pdiscard(BlockDriverState *bs,
int64_t offset, int64_t bytes) int64_t offset, int bytes)
{ {
uint64_t reqid = blkreplay_next_id(); uint64_t reqid = blkreplay_next_id();
int ret = bdrv_co_pdiscard(bs->file, offset, bytes); int ret = bdrv_co_pdiscard(bs->file, offset, bytes);

View File

@ -221,8 +221,8 @@ blkverify_co_prwv(BlockDriverState *bs, BlkverifyRequest *r, uint64_t offset,
} }
static int coroutine_fn static int coroutine_fn
blkverify_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, blkverify_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, BdrvRequestFlags flags) QEMUIOVector *qiov, int flags)
{ {
BlkverifyRequest r; BlkverifyRequest r;
QEMUIOVector raw_qiov; QEMUIOVector raw_qiov;
@ -250,8 +250,8 @@ blkverify_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
} }
static int coroutine_fn static int coroutine_fn
blkverify_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, blkverify_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, BdrvRequestFlags flags) QEMUIOVector *qiov, int flags)
{ {
BlkverifyRequest r; BlkverifyRequest r;
return blkverify_co_prwv(bs, &r, offset, bytes, qiov, qiov, flags, true); return blkverify_co_prwv(bs, &r, offset, bytes, qiov, qiov, flags, true);

View File

@ -14,7 +14,6 @@
#include "sysemu/block-backend.h" #include "sysemu/block-backend.h"
#include "block/block_int.h" #include "block/block_int.h"
#include "block/blockjob.h" #include "block/blockjob.h"
#include "block/coroutines.h"
#include "block/throttle-groups.h" #include "block/throttle-groups.h"
#include "hw/qdev-core.h" #include "hw/qdev-core.h"
#include "sysemu/blockdev.h" #include "sysemu/blockdev.h"
@ -870,14 +869,6 @@ int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp)
return 0; return 0;
} }
/*
* Change BlockDriverState associated with @blk.
*/
int blk_replace_bs(BlockBackend *blk, BlockDriverState *new_bs, Error **errp)
{
return bdrv_replace_child_bs(blk->root, new_bs, errp);
}
/* /*
* Sets the permission bitmasks that the user of the BlockBackend needs. * Sets the permission bitmasks that the user of the BlockBackend needs.
*/ */
@ -1162,11 +1153,11 @@ void blk_set_disable_request_queuing(BlockBackend *blk, bool disable)
} }
static int blk_check_byte_request(BlockBackend *blk, int64_t offset, static int blk_check_byte_request(BlockBackend *blk, int64_t offset,
int64_t bytes) size_t size)
{ {
int64_t len; int64_t len;
if (bytes < 0) { if (size > INT_MAX) {
return -EIO; return -EIO;
} }
@ -1184,7 +1175,7 @@ static int blk_check_byte_request(BlockBackend *blk, int64_t offset,
return len; return len;
} }
if (offset > len || len - offset < bytes) { if (offset > len || len - offset < size) {
return -EIO; return -EIO;
} }
} }
@ -1205,9 +1196,9 @@ static void coroutine_fn blk_wait_while_drained(BlockBackend *blk)
} }
/* To be called between exactly one pair of blk_inc/dec_in_flight() */ /* To be called between exactly one pair of blk_inc/dec_in_flight() */
int coroutine_fn static int coroutine_fn
blk_co_do_preadv(BlockBackend *blk, int64_t offset, int64_t bytes, blk_do_preadv(BlockBackend *blk, int64_t offset, unsigned int bytes,
QEMUIOVector *qiov, BdrvRequestFlags flags) QEMUIOVector *qiov, BdrvRequestFlags flags)
{ {
int ret; int ret;
BlockDriverState *bs; BlockDriverState *bs;
@ -1237,23 +1228,23 @@ blk_co_do_preadv(BlockBackend *blk, int64_t offset, int64_t bytes,
} }
int coroutine_fn blk_co_preadv(BlockBackend *blk, int64_t offset, int coroutine_fn blk_co_preadv(BlockBackend *blk, int64_t offset,
int64_t bytes, QEMUIOVector *qiov, unsigned int bytes, QEMUIOVector *qiov,
BdrvRequestFlags flags) BdrvRequestFlags flags)
{ {
int ret; int ret;
blk_inc_in_flight(blk); blk_inc_in_flight(blk);
ret = blk_co_do_preadv(blk, offset, bytes, qiov, flags); ret = blk_do_preadv(blk, offset, bytes, qiov, flags);
blk_dec_in_flight(blk); blk_dec_in_flight(blk);
return ret; return ret;
} }
/* To be called between exactly one pair of blk_inc/dec_in_flight() */ /* To be called between exactly one pair of blk_inc/dec_in_flight() */
int coroutine_fn static int coroutine_fn
blk_co_do_pwritev_part(BlockBackend *blk, int64_t offset, int64_t bytes, blk_do_pwritev_part(BlockBackend *blk, int64_t offset, unsigned int bytes,
QEMUIOVector *qiov, size_t qiov_offset, QEMUIOVector *qiov, size_t qiov_offset,
BdrvRequestFlags flags) BdrvRequestFlags flags)
{ {
int ret; int ret;
BlockDriverState *bs; BlockDriverState *bs;
@ -1287,33 +1278,12 @@ blk_co_do_pwritev_part(BlockBackend *blk, int64_t offset, int64_t bytes,
} }
int coroutine_fn blk_co_pwritev_part(BlockBackend *blk, int64_t offset, int coroutine_fn blk_co_pwritev_part(BlockBackend *blk, int64_t offset,
int64_t bytes, unsigned int bytes,
QEMUIOVector *qiov, size_t qiov_offset, QEMUIOVector *qiov, size_t qiov_offset,
BdrvRequestFlags flags) BdrvRequestFlags flags)
{ {
int ret; int ret;
blk_inc_in_flight(blk);
ret = blk_co_do_pwritev_part(blk, offset, bytes, qiov, qiov_offset, flags);
blk_dec_in_flight(blk);
return ret;
}
int coroutine_fn blk_co_pwritev(BlockBackend *blk, int64_t offset,
int64_t bytes, QEMUIOVector *qiov,
BdrvRequestFlags flags)
{
return blk_co_pwritev_part(blk, offset, bytes, qiov, 0, flags);
}
static int coroutine_fn blk_pwritev_part(BlockBackend *blk, int64_t offset,
int64_t bytes,
QEMUIOVector *qiov, size_t qiov_offset,
BdrvRequestFlags flags)
{
int ret;
blk_inc_in_flight(blk); blk_inc_in_flight(blk);
ret = blk_do_pwritev_part(blk, offset, bytes, qiov, qiov_offset, flags); ret = blk_do_pwritev_part(blk, offset, bytes, qiov, qiov_offset, flags);
blk_dec_in_flight(blk); blk_dec_in_flight(blk);
@ -1321,6 +1291,13 @@ static int coroutine_fn blk_pwritev_part(BlockBackend *blk, int64_t offset,
return ret; return ret;
} }
int coroutine_fn blk_co_pwritev(BlockBackend *blk, int64_t offset,
unsigned int bytes, QEMUIOVector *qiov,
BdrvRequestFlags flags)
{
return blk_co_pwritev_part(blk, offset, bytes, qiov, 0, flags);
}
typedef struct BlkRwCo { typedef struct BlkRwCo {
BlockBackend *blk; BlockBackend *blk;
int64_t offset; int64_t offset;
@ -1329,11 +1306,58 @@ typedef struct BlkRwCo {
BdrvRequestFlags flags; BdrvRequestFlags flags;
} BlkRwCo; } BlkRwCo;
int blk_pwrite_zeroes(BlockBackend *blk, int64_t offset, static void blk_read_entry(void *opaque)
int64_t bytes, BdrvRequestFlags flags)
{ {
return blk_pwritev_part(blk, offset, bytes, NULL, 0, BlkRwCo *rwco = opaque;
flags | BDRV_REQ_ZERO_WRITE); QEMUIOVector *qiov = rwco->iobuf;
rwco->ret = blk_do_preadv(rwco->blk, rwco->offset, qiov->size,
qiov, rwco->flags);
aio_wait_kick();
}
static void blk_write_entry(void *opaque)
{
BlkRwCo *rwco = opaque;
QEMUIOVector *qiov = rwco->iobuf;
rwco->ret = blk_do_pwritev_part(rwco->blk, rwco->offset, qiov->size,
qiov, 0, rwco->flags);
aio_wait_kick();
}
static int blk_prw(BlockBackend *blk, int64_t offset, uint8_t *buf,
int64_t bytes, CoroutineEntry co_entry,
BdrvRequestFlags flags)
{
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes);
BlkRwCo rwco = {
.blk = blk,
.offset = offset,
.iobuf = &qiov,
.flags = flags,
.ret = NOT_DONE,
};
blk_inc_in_flight(blk);
if (qemu_in_coroutine()) {
/* Fast-path if already in coroutine context */
co_entry(&rwco);
} else {
Coroutine *co = qemu_coroutine_create(co_entry, &rwco);
bdrv_coroutine_enter(blk_bs(blk), co);
BDRV_POLL_WHILE(blk_bs(blk), rwco.ret == NOT_DONE);
}
blk_dec_in_flight(blk);
return rwco.ret;
}
int blk_pwrite_zeroes(BlockBackend *blk, int64_t offset,
int bytes, BdrvRequestFlags flags)
{
return blk_prw(blk, offset, NULL, bytes, blk_write_entry,
flags | BDRV_REQ_ZERO_WRITE);
} }
int blk_make_zero(BlockBackend *blk, BdrvRequestFlags flags) int blk_make_zero(BlockBackend *blk, BdrvRequestFlags flags)
@ -1380,7 +1404,7 @@ BlockAIOCB *blk_abort_aio_request(BlockBackend *blk,
typedef struct BlkAioEmAIOCB { typedef struct BlkAioEmAIOCB {
BlockAIOCB common; BlockAIOCB common;
BlkRwCo rwco; BlkRwCo rwco;
int64_t bytes; int bytes;
bool has_returned; bool has_returned;
} BlkAioEmAIOCB; } BlkAioEmAIOCB;
@ -1412,8 +1436,7 @@ static void blk_aio_complete_bh(void *opaque)
blk_aio_complete(acb); blk_aio_complete(acb);
} }
static BlockAIOCB *blk_aio_prwv(BlockBackend *blk, int64_t offset, static BlockAIOCB *blk_aio_prwv(BlockBackend *blk, int64_t offset, int bytes,
int64_t bytes,
void *iobuf, CoroutineEntry co_entry, void *iobuf, CoroutineEntry co_entry,
BdrvRequestFlags flags, BdrvRequestFlags flags,
BlockCompletionFunc *cb, void *opaque) BlockCompletionFunc *cb, void *opaque)
@ -1452,8 +1475,8 @@ static void blk_aio_read_entry(void *opaque)
QEMUIOVector *qiov = rwco->iobuf; QEMUIOVector *qiov = rwco->iobuf;
assert(qiov->size == acb->bytes); assert(qiov->size == acb->bytes);
rwco->ret = blk_co_do_preadv(rwco->blk, rwco->offset, acb->bytes, rwco->ret = blk_do_preadv(rwco->blk, rwco->offset, acb->bytes,
qiov, rwco->flags); qiov, rwco->flags);
blk_aio_complete(acb); blk_aio_complete(acb);
} }
@ -1464,40 +1487,37 @@ static void blk_aio_write_entry(void *opaque)
QEMUIOVector *qiov = rwco->iobuf; QEMUIOVector *qiov = rwco->iobuf;
assert(!qiov || qiov->size == acb->bytes); assert(!qiov || qiov->size == acb->bytes);
rwco->ret = blk_co_do_pwritev_part(rwco->blk, rwco->offset, acb->bytes, rwco->ret = blk_do_pwritev_part(rwco->blk, rwco->offset, acb->bytes,
qiov, 0, rwco->flags); qiov, 0, rwco->flags);
blk_aio_complete(acb); blk_aio_complete(acb);
} }
BlockAIOCB *blk_aio_pwrite_zeroes(BlockBackend *blk, int64_t offset, BlockAIOCB *blk_aio_pwrite_zeroes(BlockBackend *blk, int64_t offset,
int64_t bytes, BdrvRequestFlags flags, int count, BdrvRequestFlags flags,
BlockCompletionFunc *cb, void *opaque) BlockCompletionFunc *cb, void *opaque)
{ {
return blk_aio_prwv(blk, offset, bytes, NULL, blk_aio_write_entry, return blk_aio_prwv(blk, offset, count, NULL, blk_aio_write_entry,
flags | BDRV_REQ_ZERO_WRITE, cb, opaque); flags | BDRV_REQ_ZERO_WRITE, cb, opaque);
} }
int blk_pread(BlockBackend *blk, int64_t offset, void *buf, int bytes) int blk_pread(BlockBackend *blk, int64_t offset, void *buf, int count)
{ {
int ret; int ret = blk_prw(blk, offset, buf, count, blk_read_entry, 0);
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); if (ret < 0) {
return ret;
blk_inc_in_flight(blk); }
ret = blk_do_preadv(blk, offset, bytes, &qiov, 0); return count;
blk_dec_in_flight(blk);
return ret < 0 ? ret : bytes;
} }
int blk_pwrite(BlockBackend *blk, int64_t offset, const void *buf, int bytes, int blk_pwrite(BlockBackend *blk, int64_t offset, const void *buf, int count,
BdrvRequestFlags flags) BdrvRequestFlags flags)
{ {
int ret; int ret = blk_prw(blk, offset, (void *) buf, count, blk_write_entry,
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); flags);
if (ret < 0) {
ret = blk_pwritev_part(blk, offset, bytes, &qiov, 0, flags); return ret;
}
return ret < 0 ? ret : bytes; return count;
} }
int64_t blk_getlength(BlockBackend *blk) int64_t blk_getlength(BlockBackend *blk)
@ -1531,7 +1551,6 @@ BlockAIOCB *blk_aio_preadv(BlockBackend *blk, int64_t offset,
QEMUIOVector *qiov, BdrvRequestFlags flags, QEMUIOVector *qiov, BdrvRequestFlags flags,
BlockCompletionFunc *cb, void *opaque) BlockCompletionFunc *cb, void *opaque)
{ {
assert((uint64_t)qiov->size <= INT64_MAX);
return blk_aio_prwv(blk, offset, qiov->size, qiov, return blk_aio_prwv(blk, offset, qiov->size, qiov,
blk_aio_read_entry, flags, cb, opaque); blk_aio_read_entry, flags, cb, opaque);
} }
@ -1540,7 +1559,6 @@ BlockAIOCB *blk_aio_pwritev(BlockBackend *blk, int64_t offset,
QEMUIOVector *qiov, BdrvRequestFlags flags, QEMUIOVector *qiov, BdrvRequestFlags flags,
BlockCompletionFunc *cb, void *opaque) BlockCompletionFunc *cb, void *opaque)
{ {
assert((uint64_t)qiov->size <= INT64_MAX);
return blk_aio_prwv(blk, offset, qiov->size, qiov, return blk_aio_prwv(blk, offset, qiov->size, qiov,
blk_aio_write_entry, flags, cb, opaque); blk_aio_write_entry, flags, cb, opaque);
} }
@ -1556,8 +1574,8 @@ void blk_aio_cancel_async(BlockAIOCB *acb)
} }
/* To be called between exactly one pair of blk_inc/dec_in_flight() */ /* To be called between exactly one pair of blk_inc/dec_in_flight() */
int coroutine_fn static int coroutine_fn
blk_co_do_ioctl(BlockBackend *blk, unsigned long int req, void *buf) blk_do_ioctl(BlockBackend *blk, unsigned long int req, void *buf)
{ {
blk_wait_while_drained(blk); blk_wait_while_drained(blk);
@ -1568,15 +1586,18 @@ blk_co_do_ioctl(BlockBackend *blk, unsigned long int req, void *buf)
return bdrv_co_ioctl(blk_bs(blk), req, buf); return bdrv_co_ioctl(blk_bs(blk), req, buf);
} }
static void blk_ioctl_entry(void *opaque)
{
BlkRwCo *rwco = opaque;
QEMUIOVector *qiov = rwco->iobuf;
rwco->ret = blk_do_ioctl(rwco->blk, rwco->offset, qiov->iov[0].iov_base);
aio_wait_kick();
}
int blk_ioctl(BlockBackend *blk, unsigned long int req, void *buf) int blk_ioctl(BlockBackend *blk, unsigned long int req, void *buf)
{ {
int ret; return blk_prw(blk, req, buf, 0, blk_ioctl_entry, 0);
blk_inc_in_flight(blk);
ret = blk_do_ioctl(blk, req, buf);
blk_dec_in_flight(blk);
return ret;
} }
static void blk_aio_ioctl_entry(void *opaque) static void blk_aio_ioctl_entry(void *opaque)
@ -1584,7 +1605,7 @@ static void blk_aio_ioctl_entry(void *opaque)
BlkAioEmAIOCB *acb = opaque; BlkAioEmAIOCB *acb = opaque;
BlkRwCo *rwco = &acb->rwco; BlkRwCo *rwco = &acb->rwco;
rwco->ret = blk_co_do_ioctl(rwco->blk, rwco->offset, rwco->iobuf); rwco->ret = blk_do_ioctl(rwco->blk, rwco->offset, rwco->iobuf);
blk_aio_complete(acb); blk_aio_complete(acb);
} }
@ -1596,8 +1617,8 @@ BlockAIOCB *blk_aio_ioctl(BlockBackend *blk, unsigned long int req, void *buf,
} }
/* To be called between exactly one pair of blk_inc/dec_in_flight() */ /* To be called between exactly one pair of blk_inc/dec_in_flight() */
int coroutine_fn static int coroutine_fn
blk_co_do_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes) blk_do_pdiscard(BlockBackend *blk, int64_t offset, int bytes)
{ {
int ret; int ret;
@ -1616,31 +1637,19 @@ static void blk_aio_pdiscard_entry(void *opaque)
BlkAioEmAIOCB *acb = opaque; BlkAioEmAIOCB *acb = opaque;
BlkRwCo *rwco = &acb->rwco; BlkRwCo *rwco = &acb->rwco;
rwco->ret = blk_co_do_pdiscard(rwco->blk, rwco->offset, acb->bytes); rwco->ret = blk_do_pdiscard(rwco->blk, rwco->offset, acb->bytes);
blk_aio_complete(acb); blk_aio_complete(acb);
} }
BlockAIOCB *blk_aio_pdiscard(BlockBackend *blk, BlockAIOCB *blk_aio_pdiscard(BlockBackend *blk,
int64_t offset, int64_t bytes, int64_t offset, int bytes,
BlockCompletionFunc *cb, void *opaque) BlockCompletionFunc *cb, void *opaque)
{ {
return blk_aio_prwv(blk, offset, bytes, NULL, blk_aio_pdiscard_entry, 0, return blk_aio_prwv(blk, offset, bytes, NULL, blk_aio_pdiscard_entry, 0,
cb, opaque); cb, opaque);
} }
int coroutine_fn blk_co_pdiscard(BlockBackend *blk, int64_t offset, int coroutine_fn blk_co_pdiscard(BlockBackend *blk, int64_t offset, int bytes)
int64_t bytes)
{
int ret;
blk_inc_in_flight(blk);
ret = blk_co_do_pdiscard(blk, offset, bytes);
blk_dec_in_flight(blk);
return ret;
}
int blk_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes)
{ {
int ret; int ret;
@ -1651,8 +1660,22 @@ int blk_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes)
return ret; return ret;
} }
static void blk_pdiscard_entry(void *opaque)
{
BlkRwCo *rwco = opaque;
QEMUIOVector *qiov = rwco->iobuf;
rwco->ret = blk_do_pdiscard(rwco->blk, rwco->offset, qiov->size);
aio_wait_kick();
}
int blk_pdiscard(BlockBackend *blk, int64_t offset, int bytes)
{
return blk_prw(blk, offset, NULL, bytes, blk_pdiscard_entry, 0);
}
/* To be called between exactly one pair of blk_inc/dec_in_flight() */ /* To be called between exactly one pair of blk_inc/dec_in_flight() */
int coroutine_fn blk_co_do_flush(BlockBackend *blk) static int coroutine_fn blk_do_flush(BlockBackend *blk)
{ {
blk_wait_while_drained(blk); blk_wait_while_drained(blk);
@ -1668,7 +1691,7 @@ static void blk_aio_flush_entry(void *opaque)
BlkAioEmAIOCB *acb = opaque; BlkAioEmAIOCB *acb = opaque;
BlkRwCo *rwco = &acb->rwco; BlkRwCo *rwco = &acb->rwco;
rwco->ret = blk_co_do_flush(rwco->blk); rwco->ret = blk_do_flush(rwco->blk);
blk_aio_complete(acb); blk_aio_complete(acb);
} }
@ -1683,21 +1706,22 @@ int coroutine_fn blk_co_flush(BlockBackend *blk)
int ret; int ret;
blk_inc_in_flight(blk); blk_inc_in_flight(blk);
ret = blk_co_do_flush(blk); ret = blk_do_flush(blk);
blk_dec_in_flight(blk); blk_dec_in_flight(blk);
return ret; return ret;
} }
static void blk_flush_entry(void *opaque)
{
BlkRwCo *rwco = opaque;
rwco->ret = blk_do_flush(rwco->blk);
aio_wait_kick();
}
int blk_flush(BlockBackend *blk) int blk_flush(BlockBackend *blk)
{ {
int ret; return blk_prw(blk, 0, NULL, 0, blk_flush_entry, 0);
blk_inc_in_flight(blk);
ret = blk_do_flush(blk);
blk_dec_in_flight(blk);
return ret;
} }
void blk_drain(BlockBackend *blk) void blk_drain(BlockBackend *blk)
@ -2182,18 +2206,17 @@ void *blk_aio_get(const AIOCBInfo *aiocb_info, BlockBackend *blk,
} }
int coroutine_fn blk_co_pwrite_zeroes(BlockBackend *blk, int64_t offset, int coroutine_fn blk_co_pwrite_zeroes(BlockBackend *blk, int64_t offset,
int64_t bytes, BdrvRequestFlags flags) int bytes, BdrvRequestFlags flags)
{ {
return blk_co_pwritev(blk, offset, bytes, NULL, return blk_co_pwritev(blk, offset, bytes, NULL,
flags | BDRV_REQ_ZERO_WRITE); flags | BDRV_REQ_ZERO_WRITE);
} }
int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf, int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf,
int64_t bytes) int count)
{ {
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, bytes); return blk_prw(blk, offset, (void *) buf, count, blk_write_entry,
return blk_pwritev_part(blk, offset, bytes, &qiov, 0, BDRV_REQ_WRITE_COMPRESSED);
BDRV_REQ_WRITE_COMPRESSED);
} }
int blk_truncate(BlockBackend *blk, int64_t offset, bool exact, int blk_truncate(BlockBackend *blk, int64_t offset, bool exact,
@ -2421,7 +2444,7 @@ void blk_unregister_buf(BlockBackend *blk, void *host)
int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in, int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in,
BlockBackend *blk_out, int64_t off_out, BlockBackend *blk_out, int64_t off_out,
int64_t bytes, BdrvRequestFlags read_flags, int bytes, BdrvRequestFlags read_flags,
BdrvRequestFlags write_flags) BdrvRequestFlags write_flags)
{ {
int r; int r;

View File

@ -21,14 +21,12 @@
#include "qemu/units.h" #include "qemu/units.h"
#include "qemu/coroutine.h" #include "qemu/coroutine.h"
#include "block/aio_task.h" #include "block/aio_task.h"
#include "qemu/error-report.h"
#define BLOCK_COPY_MAX_COPY_RANGE (16 * MiB) #define BLOCK_COPY_MAX_COPY_RANGE (16 * MiB)
#define BLOCK_COPY_MAX_BUFFER (1 * MiB) #define BLOCK_COPY_MAX_BUFFER (1 * MiB)
#define BLOCK_COPY_MAX_MEM (128 * MiB) #define BLOCK_COPY_MAX_MEM (128 * MiB)
#define BLOCK_COPY_MAX_WORKERS 64 #define BLOCK_COPY_MAX_WORKERS 64
#define BLOCK_COPY_SLICE_TIME 100000000ULL /* ns */ #define BLOCK_COPY_SLICE_TIME 100000000ULL /* ns */
#define BLOCK_COPY_CLUSTER_SIZE_DEFAULT (1 << 16)
typedef enum { typedef enum {
COPY_READ_WRITE_CLUSTER, COPY_READ_WRITE_CLUSTER,
@ -292,11 +290,9 @@ static void coroutine_fn block_copy_task_end(BlockCopyTask *task, int ret)
bdrv_set_dirty_bitmap(task->s->copy_bitmap, task->offset, task->bytes); bdrv_set_dirty_bitmap(task->s->copy_bitmap, task->offset, task->bytes);
} }
QLIST_REMOVE(task, list); QLIST_REMOVE(task, list);
if (task->s->progress) { progress_set_remaining(task->s->progress,
progress_set_remaining(task->s->progress, bdrv_get_dirty_count(task->s->copy_bitmap) +
bdrv_get_dirty_count(task->s->copy_bitmap) + task->s->in_flight_bytes);
task->s->in_flight_bytes);
}
qemu_co_queue_restart_all(&task->wait_queue); qemu_co_queue_restart_all(&task->wait_queue);
} }
@ -319,14 +315,35 @@ static uint32_t block_copy_max_transfer(BdrvChild *source, BdrvChild *target)
target->bs->bl.max_transfer)); target->bs->bl.max_transfer));
} }
void block_copy_set_copy_opts(BlockCopyState *s, bool use_copy_range, BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
bool compress) int64_t cluster_size, bool use_copy_range,
BdrvRequestFlags write_flags, Error **errp)
{ {
/* Keep BDRV_REQ_SERIALISING set (or not set) in block_copy_state_new() */ BlockCopyState *s;
s->write_flags = (s->write_flags & BDRV_REQ_SERIALISING) | BdrvDirtyBitmap *copy_bitmap;
(compress ? BDRV_REQ_WRITE_COMPRESSED : 0);
if (s->max_transfer < s->cluster_size) { copy_bitmap = bdrv_create_dirty_bitmap(source->bs, cluster_size, NULL,
errp);
if (!copy_bitmap) {
return NULL;
}
bdrv_disable_dirty_bitmap(copy_bitmap);
s = g_new(BlockCopyState, 1);
*s = (BlockCopyState) {
.source = source,
.target = target,
.copy_bitmap = copy_bitmap,
.cluster_size = cluster_size,
.len = bdrv_dirty_bitmap_size(copy_bitmap),
.write_flags = write_flags,
.mem = shres_create(BLOCK_COPY_MAX_MEM),
.max_transfer = QEMU_ALIGN_DOWN(
block_copy_max_transfer(source, target),
cluster_size),
};
if (s->max_transfer < cluster_size) {
/* /*
* copy_range does not respect max_transfer. We don't want to bother * copy_range does not respect max_transfer. We don't want to bother
* with requests smaller than block-copy cluster size, so fallback to * with requests smaller than block-copy cluster size, so fallback to
@ -334,7 +351,7 @@ void block_copy_set_copy_opts(BlockCopyState *s, bool use_copy_range,
* behalf). * behalf).
*/ */
s->method = COPY_READ_WRITE_CLUSTER; s->method = COPY_READ_WRITE_CLUSTER;
} else if (compress) { } else if (write_flags & BDRV_REQ_WRITE_COMPRESSED) {
/* Compression supports only cluster-size writes and no copy-range. */ /* Compression supports only cluster-size writes and no copy-range. */
s->method = COPY_READ_WRITE_CLUSTER; s->method = COPY_READ_WRITE_CLUSTER;
} else { } else {
@ -344,96 +361,6 @@ void block_copy_set_copy_opts(BlockCopyState *s, bool use_copy_range,
*/ */
s->method = use_copy_range ? COPY_RANGE_SMALL : COPY_READ_WRITE; s->method = use_copy_range ? COPY_RANGE_SMALL : COPY_READ_WRITE;
} }
}
static int64_t block_copy_calculate_cluster_size(BlockDriverState *target,
Error **errp)
{
int ret;
BlockDriverInfo bdi;
bool target_does_cow = bdrv_backing_chain_next(target);
/*
* If there is no backing file on the target, we cannot rely on COW if our
* backup cluster size is smaller than the target cluster size. Even for
* targets with a backing file, try to avoid COW if possible.
*/
ret = bdrv_get_info(target, &bdi);
if (ret == -ENOTSUP && !target_does_cow) {
/* Cluster size is not defined */
warn_report("The target block device doesn't provide "
"information about the block size and it doesn't have a "
"backing file. The default block size of %u bytes is "
"used. If the actual block size of the target exceeds "
"this default, the backup may be unusable",
BLOCK_COPY_CLUSTER_SIZE_DEFAULT);
return BLOCK_COPY_CLUSTER_SIZE_DEFAULT;
} else if (ret < 0 && !target_does_cow) {
error_setg_errno(errp, -ret,
"Couldn't determine the cluster size of the target image, "
"which has no backing file");
error_append_hint(errp,
"Aborting, since this may create an unusable destination image\n");
return ret;
} else if (ret < 0 && target_does_cow) {
/* Not fatal; just trudge on ahead. */
return BLOCK_COPY_CLUSTER_SIZE_DEFAULT;
}
return MAX(BLOCK_COPY_CLUSTER_SIZE_DEFAULT, bdi.cluster_size);
}
BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
Error **errp)
{
BlockCopyState *s;
int64_t cluster_size;
BdrvDirtyBitmap *copy_bitmap;
bool is_fleecing;
cluster_size = block_copy_calculate_cluster_size(target->bs, errp);
if (cluster_size < 0) {
return NULL;
}
copy_bitmap = bdrv_create_dirty_bitmap(source->bs, cluster_size, NULL,
errp);
if (!copy_bitmap) {
return NULL;
}
bdrv_disable_dirty_bitmap(copy_bitmap);
/*
* If source is in backing chain of target assume that target is going to be
* used for "image fleecing", i.e. it should represent a kind of snapshot of
* source at backup-start point in time. And target is going to be read by
* somebody (for example, used as NBD export) during backup job.
*
* In this case, we need to add BDRV_REQ_SERIALISING write flag to avoid
* intersection of backup writes and third party reads from target,
* otherwise reading from target we may occasionally read already updated by
* guest data.
*
* For more information see commit f8d59dfb40bb and test
* tests/qemu-iotests/222
*/
is_fleecing = bdrv_chain_contains(target->bs, source->bs);
s = g_new(BlockCopyState, 1);
*s = (BlockCopyState) {
.source = source,
.target = target,
.copy_bitmap = copy_bitmap,
.cluster_size = cluster_size,
.len = bdrv_dirty_bitmap_size(copy_bitmap),
.write_flags = (is_fleecing ? BDRV_REQ_SERIALISING : 0),
.mem = shres_create(BLOCK_COPY_MAX_MEM),
.max_transfer = QEMU_ALIGN_DOWN(
block_copy_max_transfer(source, target),
cluster_size),
};
block_copy_set_copy_opts(s, false, false);
ratelimit_init(&s->rate_limit); ratelimit_init(&s->rate_limit);
qemu_co_mutex_init(&s->lock); qemu_co_mutex_init(&s->lock);
@ -595,7 +522,7 @@ static coroutine_fn int block_copy_task_entry(AioTask *task)
t->call_state->ret = ret; t->call_state->ret = ret;
t->call_state->error_is_read = error_is_read; t->call_state->error_is_read = error_is_read;
} }
} else if (s->progress) { } else {
progress_work_done(s->progress, t->bytes); progress_work_done(s->progress, t->bytes);
} }
} }
@ -701,11 +628,9 @@ int64_t block_copy_reset_unallocated(BlockCopyState *s,
if (!ret) { if (!ret) {
qemu_co_mutex_lock(&s->lock); qemu_co_mutex_lock(&s->lock);
bdrv_reset_dirty_bitmap(s->copy_bitmap, offset, bytes); bdrv_reset_dirty_bitmap(s->copy_bitmap, offset, bytes);
if (s->progress) { progress_set_remaining(s->progress,
progress_set_remaining(s->progress, bdrv_get_dirty_count(s->copy_bitmap) +
bdrv_get_dirty_count(s->copy_bitmap) + s->in_flight_bytes);
s->in_flight_bytes);
}
qemu_co_mutex_unlock(&s->lock); qemu_co_mutex_unlock(&s->lock);
} }
@ -1008,11 +933,6 @@ BdrvDirtyBitmap *block_copy_dirty_bitmap(BlockCopyState *s)
return s->copy_bitmap; return s->copy_bitmap;
} }
int64_t block_copy_cluster_size(BlockCopyState *s)
{
return s->cluster_size;
}
void block_copy_set_skip_unallocated(BlockCopyState *s, bool skip) void block_copy_set_skip_unallocated(BlockCopyState *s, bool skip)
{ {
qatomic_set(&s->skip_unallocated, skip); qatomic_set(&s->skip_unallocated, skip);

View File

@ -238,8 +238,8 @@ static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
} }
static int coroutine_fn static int coroutine_fn
bochs_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, bochs_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, BdrvRequestFlags flags) QEMUIOVector *qiov, int flags)
{ {
BDRVBochsState *s = bs->opaque; BDRVBochsState *s = bs->opaque;
uint64_t sector_num = offset >> BDRV_SECTOR_BITS; uint64_t sector_num = offset >> BDRV_SECTOR_BITS;

View File

@ -245,8 +245,8 @@ static inline int cloop_read_block(BlockDriverState *bs, int block_num)
} }
static int coroutine_fn static int coroutine_fn
cloop_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, cloop_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, BdrvRequestFlags flags) QEMUIOVector *qiov, int flags)
{ {
BDRVCloopState *s = bs->opaque; BDRVCloopState *s = bs->opaque;
uint64_t sector_num = offset >> BDRV_SECTOR_BITS; uint64_t sector_num = offset >> BDRV_SECTOR_BITS;

View File

@ -207,7 +207,7 @@ static const BlockJobDriver commit_job_driver = {
}; };
static int coroutine_fn bdrv_commit_top_preadv(BlockDriverState *bs, static int coroutine_fn bdrv_commit_top_preadv(BlockDriverState *bs,
int64_t offset, int64_t bytes, QEMUIOVector *qiov, BdrvRequestFlags flags) uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags)
{ {
return bdrv_co_preadv(bs->backing, offset, bytes, qiov, flags); return bdrv_co_preadv(bs->backing, offset, bytes, qiov, flags);
} }

View File

@ -1,257 +0,0 @@
/*
* copy-before-write filter driver
*
* The driver performs Copy-Before-Write (CBW) operation: it is injected above
* some node, and before each write it copies _old_ data to the target node.
*
* Copyright (c) 2018-2021 Virtuozzo International GmbH.
*
* Author:
* Sementsov-Ogievskiy Vladimir <vsementsov@virtuozzo.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "sysemu/block-backend.h"
#include "qemu/cutils.h"
#include "qapi/error.h"
#include "block/block_int.h"
#include "block/qdict.h"
#include "block/block-copy.h"
#include "block/copy-before-write.h"
typedef struct BDRVCopyBeforeWriteState {
BlockCopyState *bcs;
BdrvChild *target;
} BDRVCopyBeforeWriteState;
static coroutine_fn int cbw_co_preadv(
BlockDriverState *bs, int64_t offset, int64_t bytes,
QEMUIOVector *qiov, BdrvRequestFlags flags)
{
return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
}
static coroutine_fn int cbw_do_copy_before_write(BlockDriverState *bs,
uint64_t offset, uint64_t bytes, BdrvRequestFlags flags)
{
BDRVCopyBeforeWriteState *s = bs->opaque;
uint64_t off, end;
int64_t cluster_size = block_copy_cluster_size(s->bcs);
if (flags & BDRV_REQ_WRITE_UNCHANGED) {
return 0;
}
off = QEMU_ALIGN_DOWN(offset, cluster_size);
end = QEMU_ALIGN_UP(offset + bytes, cluster_size);
return block_copy(s->bcs, off, end - off, true);
}
static int coroutine_fn cbw_co_pdiscard(BlockDriverState *bs,
int64_t offset, int64_t bytes)
{
int ret = cbw_do_copy_before_write(bs, offset, bytes, 0);
if (ret < 0) {
return ret;
}
return bdrv_co_pdiscard(bs->file, offset, bytes);
}
static int coroutine_fn cbw_co_pwrite_zeroes(BlockDriverState *bs,
int64_t offset, int64_t bytes, BdrvRequestFlags flags)
{
int ret = cbw_do_copy_before_write(bs, offset, bytes, flags);
if (ret < 0) {
return ret;
}
return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags);
}
static coroutine_fn int cbw_co_pwritev(BlockDriverState *bs,
int64_t offset,
int64_t bytes,
QEMUIOVector *qiov,
BdrvRequestFlags flags)
{
int ret = cbw_do_copy_before_write(bs, offset, bytes, flags);
if (ret < 0) {
return ret;
}
return bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags);
}
static int coroutine_fn cbw_co_flush(BlockDriverState *bs)
{
if (!bs->file) {
return 0;
}
return bdrv_co_flush(bs->file->bs);
}
static void cbw_refresh_filename(BlockDriverState *bs)
{
pstrcpy(bs->exact_filename, sizeof(bs->exact_filename),
bs->file->bs->filename);
}
static void cbw_child_perm(BlockDriverState *bs, BdrvChild *c,
BdrvChildRole role,
BlockReopenQueue *reopen_queue,
uint64_t perm, uint64_t shared,
uint64_t *nperm, uint64_t *nshared)
{
if (!(role & BDRV_CHILD_FILTERED)) {
/*
* Target child
*
* Share write to target (child_file), to not interfere
* with guest writes to its disk which may be in target backing chain.
* Can't resize during a backup block job because we check the size
* only upfront.
*/
*nshared = BLK_PERM_ALL & ~BLK_PERM_RESIZE;
*nperm = BLK_PERM_WRITE;
} else {
/* Source child */
bdrv_default_perms(bs, c, role, reopen_queue,
perm, shared, nperm, nshared);
if (!QLIST_EMPTY(&bs->parents)) {
if (perm & BLK_PERM_WRITE) {
*nperm = *nperm | BLK_PERM_CONSISTENT_READ;
}
*nshared &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE);
}
}
}
static int cbw_open(BlockDriverState *bs, QDict *options, int flags,
Error **errp)
{
BDRVCopyBeforeWriteState *s = bs->opaque;
BdrvDirtyBitmap *copy_bitmap;
bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
false, errp);
if (!bs->file) {
return -EINVAL;
}
s->target = bdrv_open_child(NULL, options, "target", bs, &child_of_bds,
BDRV_CHILD_DATA, false, errp);
if (!s->target) {
return -EINVAL;
}
bs->total_sectors = bs->file->bs->total_sectors;
bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED |
(BDRV_REQ_FUA & bs->file->bs->supported_write_flags);
bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED |
((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) &
bs->file->bs->supported_zero_flags);
s->bcs = block_copy_state_new(bs->file, s->target, errp);
if (!s->bcs) {
error_prepend(errp, "Cannot create block-copy-state: ");
return -EINVAL;
}
copy_bitmap = block_copy_dirty_bitmap(s->bcs);
bdrv_set_dirty_bitmap(copy_bitmap, 0, bdrv_dirty_bitmap_size(copy_bitmap));
return 0;
}
static void cbw_close(BlockDriverState *bs)
{
BDRVCopyBeforeWriteState *s = bs->opaque;
block_copy_state_free(s->bcs);
s->bcs = NULL;
}
BlockDriver bdrv_cbw_filter = {
.format_name = "copy-before-write",
.instance_size = sizeof(BDRVCopyBeforeWriteState),
.bdrv_open = cbw_open,
.bdrv_close = cbw_close,
.bdrv_co_preadv = cbw_co_preadv,
.bdrv_co_pwritev = cbw_co_pwritev,
.bdrv_co_pwrite_zeroes = cbw_co_pwrite_zeroes,
.bdrv_co_pdiscard = cbw_co_pdiscard,
.bdrv_co_flush = cbw_co_flush,
.bdrv_refresh_filename = cbw_refresh_filename,
.bdrv_child_perm = cbw_child_perm,
.is_filter = true,
};
BlockDriverState *bdrv_cbw_append(BlockDriverState *source,
BlockDriverState *target,
const char *filter_node_name,
BlockCopyState **bcs,
Error **errp)
{
ERRP_GUARD();
BDRVCopyBeforeWriteState *state;
BlockDriverState *top;
QDict *opts;
assert(source->total_sectors == target->total_sectors);
opts = qdict_new();
qdict_put_str(opts, "driver", "copy-before-write");
if (filter_node_name) {
qdict_put_str(opts, "node-name", filter_node_name);
}
qdict_put_str(opts, "file", bdrv_get_node_name(source));
qdict_put_str(opts, "target", bdrv_get_node_name(target));
top = bdrv_insert_node(source, opts, BDRV_O_RDWR, errp);
if (!top) {
return NULL;
}
state = top->opaque;
*bcs = state->bcs;
return top;
}
void bdrv_cbw_drop(BlockDriverState *bs)
{
bdrv_drop_filter(bs, &error_abort);
bdrv_unref(bs);
}
static void cbw_init(void)
{
bdrv_register(&bdrv_cbw_filter);
}
block_init(cbw_init);

View File

@ -128,10 +128,10 @@ static int64_t cor_getlength(BlockDriverState *bs)
static int coroutine_fn cor_co_preadv_part(BlockDriverState *bs, static int coroutine_fn cor_co_preadv_part(BlockDriverState *bs,
int64_t offset, int64_t bytes, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, QEMUIOVector *qiov,
size_t qiov_offset, size_t qiov_offset,
BdrvRequestFlags flags) int flags)
{ {
int64_t n; int64_t n;
int local_flags; int local_flags;
@ -181,11 +181,10 @@ static int coroutine_fn cor_co_preadv_part(BlockDriverState *bs,
static int coroutine_fn cor_co_pwritev_part(BlockDriverState *bs, static int coroutine_fn cor_co_pwritev_part(BlockDriverState *bs,
int64_t offset, uint64_t offset,
int64_t bytes, uint64_t bytes,
QEMUIOVector *qiov, QEMUIOVector *qiov,
size_t qiov_offset, size_t qiov_offset, int flags)
BdrvRequestFlags flags)
{ {
return bdrv_co_pwritev_part(bs->file, offset, bytes, qiov, qiov_offset, return bdrv_co_pwritev_part(bs->file, offset, bytes, qiov, qiov_offset,
flags); flags);
@ -193,7 +192,7 @@ static int coroutine_fn cor_co_pwritev_part(BlockDriverState *bs,
static int coroutine_fn cor_co_pwrite_zeroes(BlockDriverState *bs, static int coroutine_fn cor_co_pwrite_zeroes(BlockDriverState *bs,
int64_t offset, int64_t bytes, int64_t offset, int bytes,
BdrvRequestFlags flags) BdrvRequestFlags flags)
{ {
return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags); return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags);
@ -201,15 +200,15 @@ static int coroutine_fn cor_co_pwrite_zeroes(BlockDriverState *bs,
static int coroutine_fn cor_co_pdiscard(BlockDriverState *bs, static int coroutine_fn cor_co_pdiscard(BlockDriverState *bs,
int64_t offset, int64_t bytes) int64_t offset, int bytes)
{ {
return bdrv_co_pdiscard(bs->file, offset, bytes); return bdrv_co_pdiscard(bs->file, offset, bytes);
} }
static int coroutine_fn cor_co_pwritev_compressed(BlockDriverState *bs, static int coroutine_fn cor_co_pwritev_compressed(BlockDriverState *bs,
int64_t offset, uint64_t offset,
int64_t bytes, uint64_t bytes,
QEMUIOVector *qiov) QEMUIOVector *qiov)
{ {
return bdrv_co_pwritev(bs->file, offset, bytes, qiov, return bdrv_co_pwritev(bs->file, offset, bytes, qiov,

View File

@ -27,9 +27,6 @@
#include "block/block_int.h" #include "block/block_int.h"
/* For blk_bs() in generated block/block-gen.c */
#include "sysemu/block-backend.h"
int coroutine_fn bdrv_co_check(BlockDriverState *bs, int coroutine_fn bdrv_co_check(BlockDriverState *bs,
BdrvCheckResult *res, BdrvCheckMode fix); BdrvCheckResult *res, BdrvCheckMode fix);
int coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, Error **errp); int coroutine_fn bdrv_co_invalidate_cache(BlockDriverState *bs, Error **errp);
@ -75,34 +72,4 @@ int coroutine_fn
nbd_co_do_establish_connection(BlockDriverState *bs, Error **errp); nbd_co_do_establish_connection(BlockDriverState *bs, Error **errp);
int generated_co_wrapper
blk_do_preadv(BlockBackend *blk, int64_t offset, int64_t bytes,
QEMUIOVector *qiov, BdrvRequestFlags flags);
int coroutine_fn
blk_co_do_preadv(BlockBackend *blk, int64_t offset, int64_t bytes,
QEMUIOVector *qiov, BdrvRequestFlags flags);
int generated_co_wrapper
blk_do_pwritev_part(BlockBackend *blk, int64_t offset, int64_t bytes,
QEMUIOVector *qiov, size_t qiov_offset,
BdrvRequestFlags flags);
int coroutine_fn
blk_co_do_pwritev_part(BlockBackend *blk, int64_t offset, int64_t bytes,
QEMUIOVector *qiov, size_t qiov_offset,
BdrvRequestFlags flags);
int generated_co_wrapper
blk_do_ioctl(BlockBackend *blk, unsigned long int req, void *buf);
int coroutine_fn
blk_co_do_ioctl(BlockBackend *blk, unsigned long int req, void *buf);
int generated_co_wrapper
blk_do_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes);
int coroutine_fn
blk_co_do_pdiscard(BlockBackend *blk, int64_t offset, int64_t bytes);
int generated_co_wrapper blk_do_flush(BlockBackend *blk);
int coroutine_fn blk_co_do_flush(BlockBackend *blk);
#endif /* BLOCK_COROUTINES_INT_H */ #endif /* BLOCK_COROUTINES_INT_H */

View File

@ -397,8 +397,8 @@ static int block_crypto_reopen_prepare(BDRVReopenState *state,
#define BLOCK_CRYPTO_MAX_IO_SIZE (1024 * 1024) #define BLOCK_CRYPTO_MAX_IO_SIZE (1024 * 1024)
static coroutine_fn int static coroutine_fn int
block_crypto_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, block_crypto_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, BdrvRequestFlags flags) QEMUIOVector *qiov, int flags)
{ {
BlockCrypto *crypto = bs->opaque; BlockCrypto *crypto = bs->opaque;
uint64_t cur_bytes; /* number of bytes in current iteration */ uint64_t cur_bytes; /* number of bytes in current iteration */
@ -460,8 +460,8 @@ block_crypto_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
static coroutine_fn int static coroutine_fn int
block_crypto_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, block_crypto_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, BdrvRequestFlags flags) QEMUIOVector *qiov, int flags)
{ {
BlockCrypto *crypto = bs->opaque; BlockCrypto *crypto = bs->opaque;
uint64_t cur_bytes; /* number of bytes in current iteration */ uint64_t cur_bytes; /* number of bytes in current iteration */

View File

@ -896,8 +896,7 @@ out:
} }
static int coroutine_fn curl_co_preadv(BlockDriverState *bs, static int coroutine_fn curl_co_preadv(BlockDriverState *bs,
int64_t offset, int64_t bytes, QEMUIOVector *qiov, uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags)
BdrvRequestFlags flags)
{ {
CURLAIOCB acb = { CURLAIOCB acb = {
.co = qemu_coroutine_self(), .co = qemu_coroutine_self(),

View File

@ -689,8 +689,8 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
} }
static int coroutine_fn static int coroutine_fn
dmg_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, dmg_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, BdrvRequestFlags flags) QEMUIOVector *qiov, int flags)
{ {
BDRVDMGState *s = bs->opaque; BDRVDMGState *s = bs->opaque;
uint64_t sector_num = offset >> BDRV_SECTOR_BITS; uint64_t sector_num = offset >> BDRV_SECTOR_BITS;

View File

@ -31,13 +31,6 @@
#include <fuse.h> #include <fuse.h>
#include <fuse_lowlevel.h> #include <fuse_lowlevel.h>
#if defined(CONFIG_FALLOCATE_ZERO_RANGE)
#include <linux/falloc.h>
#endif
#ifdef __linux__
#include <linux/fs.h>
#endif
/* Prevent overly long bounce buffer allocations */ /* Prevent overly long bounce buffer allocations */
#define FUSE_MAX_BOUNCE_BYTES (MIN(BDRV_REQUEST_MAX_BYTES, 64 * 1024 * 1024)) #define FUSE_MAX_BOUNCE_BYTES (MIN(BDRV_REQUEST_MAX_BYTES, 64 * 1024 * 1024))

View File

@ -150,8 +150,6 @@ typedef struct BDRVRawState {
uint64_t locked_perm; uint64_t locked_perm;
uint64_t locked_shared_perm; uint64_t locked_shared_perm;
uint64_t aio_max_batch;
int perm_change_fd; int perm_change_fd;
int perm_change_flags; int perm_change_flags;
BDRVReopenState *reopen_state; BDRVReopenState *reopen_state;
@ -167,7 +165,6 @@ typedef struct BDRVRawState {
int page_cache_inconsistent; /* errno from fdatasync failure */ int page_cache_inconsistent; /* errno from fdatasync failure */
bool has_fallocate; bool has_fallocate;
bool needs_alignment; bool needs_alignment;
bool force_alignment;
bool drop_cache; bool drop_cache;
bool check_cache_dropped; bool check_cache_dropped;
struct { struct {
@ -352,17 +349,6 @@ static bool dio_byte_aligned(int fd)
return false; return false;
} }
static bool raw_needs_alignment(BlockDriverState *bs)
{
BDRVRawState *s = bs->opaque;
if ((bs->open_flags & BDRV_O_NOCACHE) != 0 && !dio_byte_aligned(s->fd)) {
return true;
}
return s->force_alignment;
}
/* Check if read is allowed with given memory buffer and length. /* Check if read is allowed with given memory buffer and length.
* *
* This function is used to check O_DIRECT memory buffer and request alignment. * This function is used to check O_DIRECT memory buffer and request alignment.
@ -544,11 +530,6 @@ static QemuOptsList raw_runtime_opts = {
.type = QEMU_OPT_STRING, .type = QEMU_OPT_STRING,
.help = "host AIO implementation (threads, native, io_uring)", .help = "host AIO implementation (threads, native, io_uring)",
}, },
{
.name = "aio-max-batch",
.type = QEMU_OPT_NUMBER,
.help = "AIO max batch size (0 = auto handled by AIO backend, default: 0)",
},
{ {
.name = "locking", .name = "locking",
.type = QEMU_OPT_STRING, .type = QEMU_OPT_STRING,
@ -628,8 +609,6 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
s->use_linux_io_uring = (aio == BLOCKDEV_AIO_OPTIONS_IO_URING); s->use_linux_io_uring = (aio == BLOCKDEV_AIO_OPTIONS_IO_URING);
#endif #endif
s->aio_max_batch = qemu_opt_get_number(opts, "aio-max-batch", 0);
locking = qapi_enum_parse(&OnOffAuto_lookup, locking = qapi_enum_parse(&OnOffAuto_lookup,
qemu_opt_get(opts, "locking"), qemu_opt_get(opts, "locking"),
ON_OFF_AUTO_AUTO, &local_err); ON_OFF_AUTO_AUTO, &local_err);
@ -740,6 +719,9 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
s->has_discard = true; s->has_discard = true;
s->has_write_zeroes = true; s->has_write_zeroes = true;
if ((bs->open_flags & BDRV_O_NOCACHE) != 0 && !dio_byte_aligned(s->fd)) {
s->needs_alignment = true;
}
if (fstat(s->fd, &st) < 0) { if (fstat(s->fd, &st) < 0) {
ret = -errno; ret = -errno;
@ -793,10 +775,9 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
* so QEMU makes sure all IO operations on the device are aligned * so QEMU makes sure all IO operations on the device are aligned
* to sector size, or else FreeBSD will reject them with EINVAL. * to sector size, or else FreeBSD will reject them with EINVAL.
*/ */
s->force_alignment = true; s->needs_alignment = true;
} }
#endif #endif
s->needs_alignment = raw_needs_alignment(bs);
#ifdef CONFIG_XFS #ifdef CONFIG_XFS
if (platform_test_xfs_fd(s->fd)) { if (platform_test_xfs_fd(s->fd)) {
@ -1261,9 +1242,7 @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
BDRVRawState *s = bs->opaque; BDRVRawState *s = bs->opaque;
struct stat st; struct stat st;
s->needs_alignment = raw_needs_alignment(bs);
raw_probe_alignment(bs, s->fd, errp); raw_probe_alignment(bs, s->fd, errp);
bs->bl.min_mem_alignment = s->buf_align; bs->bl.min_mem_alignment = s->buf_align;
bs->bl.opt_mem_alignment = MAX(s->buf_align, qemu_real_host_page_size); bs->bl.opt_mem_alignment = MAX(s->buf_align, qemu_real_host_page_size);
@ -1726,7 +1705,7 @@ static int handle_aiocb_write_zeroes(void *opaque)
*/ */
warn_report_once("Your file system is misbehaving: " warn_report_once("Your file system is misbehaving: "
"fallocate(FALLOC_FL_PUNCH_HOLE) returned EINVAL. " "fallocate(FALLOC_FL_PUNCH_HOLE) returned EINVAL. "
"Please report this bug to your file system " "Please report this bug to your file sytem "
"vendor."); "vendor.");
} else if (ret != -ENOTSUP) { } else if (ret != -ENOTSUP) {
return ret; return ret;
@ -2078,8 +2057,7 @@ static int coroutine_fn raw_co_prw(BlockDriverState *bs, uint64_t offset,
} else if (s->use_linux_aio) { } else if (s->use_linux_aio) {
LinuxAioState *aio = aio_get_linux_aio(bdrv_get_aio_context(bs)); LinuxAioState *aio = aio_get_linux_aio(bdrv_get_aio_context(bs));
assert(qiov->size == bytes); assert(qiov->size == bytes);
return laio_co_submit(bs, aio, s->fd, offset, qiov, type, return laio_co_submit(bs, aio, s->fd, offset, qiov, type);
s->aio_max_batch);
#endif #endif
} }
@ -2099,16 +2077,16 @@ static int coroutine_fn raw_co_prw(BlockDriverState *bs, uint64_t offset,
return raw_thread_pool_submit(bs, handle_aiocb_rw, &acb); return raw_thread_pool_submit(bs, handle_aiocb_rw, &acb);
} }
static int coroutine_fn raw_co_preadv(BlockDriverState *bs, int64_t offset, static int coroutine_fn raw_co_preadv(BlockDriverState *bs, uint64_t offset,
int64_t bytes, QEMUIOVector *qiov, uint64_t bytes, QEMUIOVector *qiov,
BdrvRequestFlags flags) int flags)
{ {
return raw_co_prw(bs, offset, bytes, qiov, QEMU_AIO_READ); return raw_co_prw(bs, offset, bytes, qiov, QEMU_AIO_READ);
} }
static int coroutine_fn raw_co_pwritev(BlockDriverState *bs, int64_t offset, static int coroutine_fn raw_co_pwritev(BlockDriverState *bs, uint64_t offset,
int64_t bytes, QEMUIOVector *qiov, uint64_t bytes, QEMUIOVector *qiov,
BdrvRequestFlags flags) int flags)
{ {
assert(flags == 0); assert(flags == 0);
return raw_co_prw(bs, offset, bytes, qiov, QEMU_AIO_WRITE); return raw_co_prw(bs, offset, bytes, qiov, QEMU_AIO_WRITE);
@ -2137,7 +2115,7 @@ static void raw_aio_unplug(BlockDriverState *bs)
#ifdef CONFIG_LINUX_AIO #ifdef CONFIG_LINUX_AIO
if (s->use_linux_aio) { if (s->use_linux_aio) {
LinuxAioState *aio = aio_get_linux_aio(bdrv_get_aio_context(bs)); LinuxAioState *aio = aio_get_linux_aio(bdrv_get_aio_context(bs));
laio_io_unplug(bs, aio, s->aio_max_batch); laio_io_unplug(bs, aio);
} }
#endif #endif
#ifdef CONFIG_LINUX_IO_URING #ifdef CONFIG_LINUX_IO_URING
@ -2766,8 +2744,7 @@ static int find_allocation(BlockDriverState *bs, off_t start,
* the specified offset) that are known to be in the same * the specified offset) that are known to be in the same
* allocated/unallocated state. * allocated/unallocated state.
* *
* 'bytes' is a soft cap for 'pnum'. If the information is free, 'pnum' may * 'bytes' is the max value 'pnum' should be set to.
* well exceed it.
*/ */
static int coroutine_fn raw_co_block_status(BlockDriverState *bs, static int coroutine_fn raw_co_block_status(BlockDriverState *bs,
bool want_zero, bool want_zero,
@ -2805,7 +2782,7 @@ static int coroutine_fn raw_co_block_status(BlockDriverState *bs,
} else if (data == offset) { } else if (data == offset) {
/* On a data extent, compute bytes to the end of the extent, /* On a data extent, compute bytes to the end of the extent,
* possibly including a partial sector at EOF. */ * possibly including a partial sector at EOF. */
*pnum = hole - offset; *pnum = MIN(bytes, hole - offset);
/* /*
* We are not allowed to return partial sectors, though, so * We are not allowed to return partial sectors, though, so
@ -2824,7 +2801,7 @@ static int coroutine_fn raw_co_block_status(BlockDriverState *bs,
} else { } else {
/* On a hole, compute bytes to the beginning of the next extent. */ /* On a hole, compute bytes to the beginning of the next extent. */
assert(hole == offset); assert(hole == offset);
*pnum = data - offset; *pnum = MIN(bytes, data - offset);
ret = BDRV_BLOCK_ZERO; ret = BDRV_BLOCK_ZERO;
} }
*map = offset; *map = offset;
@ -2964,8 +2941,7 @@ static void raw_account_discard(BDRVRawState *s, uint64_t nbytes, int ret)
} }
static coroutine_fn int static coroutine_fn int
raw_do_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes, raw_do_pdiscard(BlockDriverState *bs, int64_t offset, int bytes, bool blkdev)
bool blkdev)
{ {
BDRVRawState *s = bs->opaque; BDRVRawState *s = bs->opaque;
RawPosixAIOData acb; RawPosixAIOData acb;
@ -2989,13 +2965,13 @@ raw_do_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes,
} }
static coroutine_fn int static coroutine_fn int
raw_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes) raw_co_pdiscard(BlockDriverState *bs, int64_t offset, int bytes)
{ {
return raw_do_pdiscard(bs, offset, bytes, false); return raw_do_pdiscard(bs, offset, bytes, false);
} }
static int coroutine_fn static int coroutine_fn
raw_do_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes, raw_do_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int bytes,
BdrvRequestFlags flags, bool blkdev) BdrvRequestFlags flags, bool blkdev)
{ {
BDRVRawState *s = bs->opaque; BDRVRawState *s = bs->opaque;
@ -3063,7 +3039,7 @@ raw_do_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes,
static int coroutine_fn raw_co_pwrite_zeroes( static int coroutine_fn raw_co_pwrite_zeroes(
BlockDriverState *bs, int64_t offset, BlockDriverState *bs, int64_t offset,
int64_t bytes, BdrvRequestFlags flags) int bytes, BdrvRequestFlags flags)
{ {
return raw_do_pwrite_zeroes(bs, offset, bytes, flags, false); return raw_do_pwrite_zeroes(bs, offset, bytes, flags, false);
} }
@ -3226,8 +3202,8 @@ static void raw_abort_perm_update(BlockDriverState *bs)
} }
static int coroutine_fn raw_co_copy_range_from( static int coroutine_fn raw_co_copy_range_from(
BlockDriverState *bs, BdrvChild *src, int64_t src_offset, BlockDriverState *bs, BdrvChild *src, uint64_t src_offset,
BdrvChild *dst, int64_t dst_offset, int64_t bytes, BdrvChild *dst, uint64_t dst_offset, uint64_t bytes,
BdrvRequestFlags read_flags, BdrvRequestFlags write_flags) BdrvRequestFlags read_flags, BdrvRequestFlags write_flags)
{ {
return bdrv_co_copy_range_to(src, src_offset, dst, dst_offset, bytes, return bdrv_co_copy_range_to(src, src_offset, dst, dst_offset, bytes,
@ -3236,10 +3212,10 @@ static int coroutine_fn raw_co_copy_range_from(
static int coroutine_fn raw_co_copy_range_to(BlockDriverState *bs, static int coroutine_fn raw_co_copy_range_to(BlockDriverState *bs,
BdrvChild *src, BdrvChild *src,
int64_t src_offset, uint64_t src_offset,
BdrvChild *dst, BdrvChild *dst,
int64_t dst_offset, uint64_t dst_offset,
int64_t bytes, uint64_t bytes,
BdrvRequestFlags read_flags, BdrvRequestFlags read_flags,
BdrvRequestFlags write_flags) BdrvRequestFlags write_flags)
{ {
@ -3614,7 +3590,7 @@ hdev_co_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
#endif /* linux */ #endif /* linux */
static coroutine_fn int static coroutine_fn int
hdev_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes) hdev_co_pdiscard(BlockDriverState *bs, int64_t offset, int bytes)
{ {
BDRVRawState *s = bs->opaque; BDRVRawState *s = bs->opaque;
int ret; int ret;
@ -3628,7 +3604,7 @@ hdev_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes)
} }
static coroutine_fn int hdev_co_pwrite_zeroes(BlockDriverState *bs, static coroutine_fn int hdev_co_pwrite_zeroes(BlockDriverState *bs,
int64_t offset, int64_t bytes, BdrvRequestFlags flags) int64_t offset, int bytes, BdrvRequestFlags flags)
{ {
int rc; int rc;

View File

@ -58,10 +58,6 @@ typedef struct BDRVRawState {
QEMUWin32AIOState *aio; QEMUWin32AIOState *aio;
} BDRVRawState; } BDRVRawState;
typedef struct BDRVRawReopenState {
HANDLE hfile;
} BDRVRawReopenState;
/* /*
* Read/writes the data to/from a given linear buffer. * Read/writes the data to/from a given linear buffer.
* *
@ -396,7 +392,7 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
} }
s->hfile = CreateFile(filename, access_flags, s->hfile = CreateFile(filename, access_flags,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, FILE_SHARE_READ, NULL,
OPEN_EXISTING, overlapped, NULL); OPEN_EXISTING, overlapped, NULL);
if (s->hfile == INVALID_HANDLE_VALUE) { if (s->hfile == INVALID_HANDLE_VALUE) {
int err = GetLastError(); int err = GetLastError();
@ -440,8 +436,8 @@ fail:
} }
static BlockAIOCB *raw_aio_preadv(BlockDriverState *bs, static BlockAIOCB *raw_aio_preadv(BlockDriverState *bs,
int64_t offset, int64_t bytes, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, BdrvRequestFlags flags, QEMUIOVector *qiov, int flags,
BlockCompletionFunc *cb, void *opaque) BlockCompletionFunc *cb, void *opaque)
{ {
BDRVRawState *s = bs->opaque; BDRVRawState *s = bs->opaque;
@ -455,8 +451,8 @@ static BlockAIOCB *raw_aio_preadv(BlockDriverState *bs,
} }
static BlockAIOCB *raw_aio_pwritev(BlockDriverState *bs, static BlockAIOCB *raw_aio_pwritev(BlockDriverState *bs,
int64_t offset, int64_t bytes, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, BdrvRequestFlags flags, QEMUIOVector *qiov, int flags,
BlockCompletionFunc *cb, void *opaque) BlockCompletionFunc *cb, void *opaque)
{ {
BDRVRawState *s = bs->opaque; BDRVRawState *s = bs->opaque;
@ -638,97 +634,6 @@ static int coroutine_fn raw_co_create_opts(BlockDriver *drv,
return raw_co_create(&options, errp); return raw_co_create(&options, errp);
} }
static int raw_reopen_prepare(BDRVReopenState *state,
BlockReopenQueue *queue, Error **errp)
{
BDRVRawState *s = state->bs->opaque;
BDRVRawReopenState *rs;
int access_flags;
DWORD overlapped;
int ret = 0;
if (s->type != FTYPE_FILE) {
error_setg(errp, "Can only reopen files");
return -EINVAL;
}
rs = g_new0(BDRVRawReopenState, 1);
/*
* We do not support changing any options (only flags). By leaving
* all options in state->options, we tell the generic reopen code
* that we do not support changing any of them, so it will verify
* that their values did not change.
*/
raw_parse_flags(state->flags, s->aio != NULL, &access_flags, &overlapped);
rs->hfile = CreateFile(state->bs->filename, access_flags,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, overlapped, NULL);
if (rs->hfile == INVALID_HANDLE_VALUE) {
int err = GetLastError();
error_setg_win32(errp, err, "Could not reopen '%s'",
state->bs->filename);
if (err == ERROR_ACCESS_DENIED) {
ret = -EACCES;
} else {
ret = -EINVAL;
}
goto fail;
}
if (s->aio) {
ret = win32_aio_attach(s->aio, rs->hfile);
if (ret < 0) {
error_setg_errno(errp, -ret, "Could not enable AIO");
CloseHandle(rs->hfile);
goto fail;
}
}
state->opaque = rs;
return 0;
fail:
g_free(rs);
state->opaque = NULL;
return ret;
}
static void raw_reopen_commit(BDRVReopenState *state)
{
BDRVRawState *s = state->bs->opaque;
BDRVRawReopenState *rs = state->opaque;
assert(rs != NULL);
CloseHandle(s->hfile);
s->hfile = rs->hfile;
g_free(rs);
state->opaque = NULL;
}
static void raw_reopen_abort(BDRVReopenState *state)
{
BDRVRawReopenState *rs = state->opaque;
if (!rs) {
return;
}
if (rs->hfile != INVALID_HANDLE_VALUE) {
CloseHandle(rs->hfile);
}
g_free(rs);
state->opaque = NULL;
}
static QemuOptsList raw_create_opts = { static QemuOptsList raw_create_opts = {
.name = "raw-create-opts", .name = "raw-create-opts",
.head = QTAILQ_HEAD_INITIALIZER(raw_create_opts.head), .head = QTAILQ_HEAD_INITIALIZER(raw_create_opts.head),
@ -754,10 +659,6 @@ BlockDriver bdrv_file = {
.bdrv_co_create_opts = raw_co_create_opts, .bdrv_co_create_opts = raw_co_create_opts,
.bdrv_has_zero_init = bdrv_has_zero_init_1, .bdrv_has_zero_init = bdrv_has_zero_init_1,
.bdrv_reopen_prepare = raw_reopen_prepare,
.bdrv_reopen_commit = raw_reopen_commit,
.bdrv_reopen_abort = raw_reopen_abort,
.bdrv_aio_preadv = raw_aio_preadv, .bdrv_aio_preadv = raw_aio_preadv,
.bdrv_aio_pwritev = raw_aio_pwritev, .bdrv_aio_pwritev = raw_aio_pwritev,
.bdrv_aio_flush = raw_aio_flush, .bdrv_aio_flush = raw_aio_flush,

View File

@ -63,10 +63,10 @@ static int64_t compress_getlength(BlockDriverState *bs)
static int coroutine_fn compress_co_preadv_part(BlockDriverState *bs, static int coroutine_fn compress_co_preadv_part(BlockDriverState *bs,
int64_t offset, int64_t bytes, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, QEMUIOVector *qiov,
size_t qiov_offset, size_t qiov_offset,
BdrvRequestFlags flags) int flags)
{ {
return bdrv_co_preadv_part(bs->file, offset, bytes, qiov, qiov_offset, return bdrv_co_preadv_part(bs->file, offset, bytes, qiov, qiov_offset,
flags); flags);
@ -74,11 +74,10 @@ static int coroutine_fn compress_co_preadv_part(BlockDriverState *bs,
static int coroutine_fn compress_co_pwritev_part(BlockDriverState *bs, static int coroutine_fn compress_co_pwritev_part(BlockDriverState *bs,
int64_t offset, uint64_t offset,
int64_t bytes, uint64_t bytes,
QEMUIOVector *qiov, QEMUIOVector *qiov,
size_t qiov_offset, size_t qiov_offset, int flags)
BdrvRequestFlags flags)
{ {
return bdrv_co_pwritev_part(bs->file, offset, bytes, qiov, qiov_offset, return bdrv_co_pwritev_part(bs->file, offset, bytes, qiov, qiov_offset,
flags | BDRV_REQ_WRITE_COMPRESSED); flags | BDRV_REQ_WRITE_COMPRESSED);
@ -86,7 +85,7 @@ static int coroutine_fn compress_co_pwritev_part(BlockDriverState *bs,
static int coroutine_fn compress_co_pwrite_zeroes(BlockDriverState *bs, static int coroutine_fn compress_co_pwrite_zeroes(BlockDriverState *bs,
int64_t offset, int64_t bytes, int64_t offset, int bytes,
BdrvRequestFlags flags) BdrvRequestFlags flags)
{ {
return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags); return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags);
@ -94,7 +93,7 @@ static int coroutine_fn compress_co_pwrite_zeroes(BlockDriverState *bs,
static int coroutine_fn compress_co_pdiscard(BlockDriverState *bs, static int coroutine_fn compress_co_pdiscard(BlockDriverState *bs,
int64_t offset, int64_t bytes) int64_t offset, int bytes)
{ {
return bdrv_co_pdiscard(bs->file, offset, bytes); return bdrv_co_pdiscard(bs->file, offset, bytes);
} }

View File

@ -891,7 +891,6 @@ out:
static void qemu_gluster_refresh_limits(BlockDriverState *bs, Error **errp) static void qemu_gluster_refresh_limits(BlockDriverState *bs, Error **errp)
{ {
bs->bl.max_transfer = GLUSTER_MAX_TRANSFER; bs->bl.max_transfer = GLUSTER_MAX_TRANSFER;
bs->bl.max_pdiscard = SIZE_MAX;
} }
static int qemu_gluster_reopen_prepare(BDRVReopenState *state, static int qemu_gluster_reopen_prepare(BDRVReopenState *state,
@ -1004,19 +1003,19 @@ static void qemu_gluster_reopen_abort(BDRVReopenState *state)
#ifdef CONFIG_GLUSTERFS_ZEROFILL #ifdef CONFIG_GLUSTERFS_ZEROFILL
static coroutine_fn int qemu_gluster_co_pwrite_zeroes(BlockDriverState *bs, static coroutine_fn int qemu_gluster_co_pwrite_zeroes(BlockDriverState *bs,
int64_t offset, int64_t offset,
int64_t bytes, int size,
BdrvRequestFlags flags) BdrvRequestFlags flags)
{ {
int ret; int ret;
GlusterAIOCB acb; GlusterAIOCB acb;
BDRVGlusterState *s = bs->opaque; BDRVGlusterState *s = bs->opaque;
acb.size = bytes; acb.size = size;
acb.ret = 0; acb.ret = 0;
acb.coroutine = qemu_coroutine_self(); acb.coroutine = qemu_coroutine_self();
acb.aio_context = bdrv_get_aio_context(bs); acb.aio_context = bdrv_get_aio_context(bs);
ret = glfs_zerofill_async(s->fd, offset, bytes, gluster_finish_aiocb, &acb); ret = glfs_zerofill_async(s->fd, offset, size, gluster_finish_aiocb, &acb);
if (ret < 0) { if (ret < 0) {
return -errno; return -errno;
} }
@ -1298,20 +1297,18 @@ error:
#ifdef CONFIG_GLUSTERFS_DISCARD #ifdef CONFIG_GLUSTERFS_DISCARD
static coroutine_fn int qemu_gluster_co_pdiscard(BlockDriverState *bs, static coroutine_fn int qemu_gluster_co_pdiscard(BlockDriverState *bs,
int64_t offset, int64_t bytes) int64_t offset, int size)
{ {
int ret; int ret;
GlusterAIOCB acb; GlusterAIOCB acb;
BDRVGlusterState *s = bs->opaque; BDRVGlusterState *s = bs->opaque;
assert(bytes <= SIZE_MAX); /* rely on max_pdiscard */
acb.size = 0; acb.size = 0;
acb.ret = 0; acb.ret = 0;
acb.coroutine = qemu_coroutine_self(); acb.coroutine = qemu_coroutine_self();
acb.aio_context = bdrv_get_aio_context(bs); acb.aio_context = bdrv_get_aio_context(bs);
ret = glfs_discard_async(s->fd, offset, bytes, gluster_finish_aiocb, &acb); ret = glfs_discard_async(s->fd, offset, size, gluster_finish_aiocb, &acb);
if (ret < 0) { if (ret < 0) {
return -errno; return -errno;
} }
@ -1464,8 +1461,7 @@ exit:
* the specified offset) that are known to be in the same * the specified offset) that are known to be in the same
* allocated/unallocated state. * allocated/unallocated state.
* *
* 'bytes' is a soft cap for 'pnum'. If the information is free, 'pnum' may * 'bytes' is the max value 'pnum' should be set to.
* well exceed it.
* *
* (Based on raw_co_block_status() from file-posix.c.) * (Based on raw_co_block_status() from file-posix.c.)
*/ */
@ -1481,8 +1477,6 @@ static int coroutine_fn qemu_gluster_co_block_status(BlockDriverState *bs,
off_t data = 0, hole = 0; off_t data = 0, hole = 0;
int ret = -EINVAL; int ret = -EINVAL;
assert(QEMU_IS_ALIGNED(offset | bytes, bs->bl.request_alignment));
if (!s->fd) { if (!s->fd) {
return ret; return ret;
} }
@ -1506,26 +1500,12 @@ static int coroutine_fn qemu_gluster_co_block_status(BlockDriverState *bs,
} else if (data == offset) { } else if (data == offset) {
/* On a data extent, compute bytes to the end of the extent, /* On a data extent, compute bytes to the end of the extent,
* possibly including a partial sector at EOF. */ * possibly including a partial sector at EOF. */
*pnum = hole - offset; *pnum = MIN(bytes, hole - offset);
/*
* We are not allowed to return partial sectors, though, so
* round up if necessary.
*/
if (!QEMU_IS_ALIGNED(*pnum, bs->bl.request_alignment)) {
int64_t file_length = qemu_gluster_getlength(bs);
if (file_length > 0) {
/* Ignore errors, this is just a safeguard */
assert(hole == file_length);
}
*pnum = ROUND_UP(*pnum, bs->bl.request_alignment);
}
ret = BDRV_BLOCK_DATA; ret = BDRV_BLOCK_DATA;
} else { } else {
/* On a hole, compute bytes to the beginning of the next extent. */ /* On a hole, compute bytes to the beginning of the next extent. */
assert(hole == offset); assert(hole == offset);
*pnum = data - offset; *pnum = MIN(bytes, data - offset);
ret = BDRV_BLOCK_ZERO; ret = BDRV_BLOCK_ZERO;
} }

View File

@ -957,9 +957,9 @@ bool coroutine_fn bdrv_make_request_serialising(BdrvTrackedRequest *req,
return waited; return waited;
} }
int bdrv_check_qiov_request(int64_t offset, int64_t bytes, static int bdrv_check_qiov_request(int64_t offset, int64_t bytes,
QEMUIOVector *qiov, size_t qiov_offset, QEMUIOVector *qiov, size_t qiov_offset,
Error **errp) Error **errp)
{ {
/* /*
* Check generic offset/bytes correctness * Check generic offset/bytes correctness
@ -1231,8 +1231,7 @@ out:
static int coroutine_fn bdrv_driver_pwritev(BlockDriverState *bs, static int coroutine_fn bdrv_driver_pwritev(BlockDriverState *bs,
int64_t offset, int64_t bytes, int64_t offset, int64_t bytes,
QEMUIOVector *qiov, QEMUIOVector *qiov,
size_t qiov_offset, size_t qiov_offset, int flags)
BdrvRequestFlags flags)
{ {
BlockDriver *drv = bs->drv; BlockDriver *drv = bs->drv;
int64_t sector_num; int64_t sector_num;
@ -1870,8 +1869,7 @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
int head = 0; int head = 0;
int tail = 0; int tail = 0;
int64_t max_write_zeroes = MIN_NON_ZERO(bs->bl.max_pwrite_zeroes, int max_write_zeroes = MIN_NON_ZERO(bs->bl.max_pwrite_zeroes, INT_MAX);
INT64_MAX);
int alignment = MAX(bs->bl.pwrite_zeroes_alignment, int alignment = MAX(bs->bl.pwrite_zeroes_alignment,
bs->bl.request_alignment); bs->bl.request_alignment);
int max_transfer = MIN_NON_ZERO(bs->bl.max_transfer, MAX_BOUNCE_BUFFER); int max_transfer = MIN_NON_ZERO(bs->bl.max_transfer, MAX_BOUNCE_BUFFER);
@ -1886,9 +1884,6 @@ static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
return -ENOTSUP; return -ENOTSUP;
} }
/* Invalidate the cached block-status data range if this write overlaps */
bdrv_bsc_invalidate_range(bs, offset, bytes);
assert(alignment % bs->bl.request_alignment == 0); assert(alignment % bs->bl.request_alignment == 0);
head = offset % alignment; head = offset % alignment;
tail = (offset + bytes) % alignment; tail = (offset + bytes) % alignment;
@ -2076,8 +2071,7 @@ bdrv_co_write_req_finish(BdrvChild *child, int64_t offset, int64_t bytes,
*/ */
static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child, static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
BdrvTrackedRequest *req, int64_t offset, int64_t bytes, BdrvTrackedRequest *req, int64_t offset, int64_t bytes,
int64_t align, QEMUIOVector *qiov, size_t qiov_offset, int64_t align, QEMUIOVector *qiov, size_t qiov_offset, int flags)
BdrvRequestFlags flags)
{ {
BlockDriverState *bs = child->bs; BlockDriverState *bs = child->bs;
BlockDriver *drv = bs->drv; BlockDriver *drv = bs->drv;
@ -2250,11 +2244,7 @@ int coroutine_fn bdrv_co_pwritev_part(BdrvChild *child,
return -ENOMEDIUM; return -ENOMEDIUM;
} }
if (flags & BDRV_REQ_ZERO_WRITE) { ret = bdrv_check_request32(offset, bytes, qiov, qiov_offset);
ret = bdrv_check_qiov_request(offset, bytes, qiov, qiov_offset, NULL);
} else {
ret = bdrv_check_request32(offset, bytes, qiov, qiov_offset);
}
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
@ -2458,65 +2448,9 @@ static int coroutine_fn bdrv_co_block_status(BlockDriverState *bs,
aligned_bytes = ROUND_UP(offset + bytes, align) - aligned_offset; aligned_bytes = ROUND_UP(offset + bytes, align) - aligned_offset;
if (bs->drv->bdrv_co_block_status) { if (bs->drv->bdrv_co_block_status) {
/* ret = bs->drv->bdrv_co_block_status(bs, want_zero, aligned_offset,
* Use the block-status cache only for protocol nodes: Format aligned_bytes, pnum, &local_map,
* drivers are generally quick to inquire the status, but protocol &local_file);
* drivers often need to get information from outside of qemu, so
* we do not have control over the actual implementation. There
* have been cases where inquiring the status took an unreasonably
* long time, and we can do nothing in qemu to fix it.
* This is especially problematic for images with large data areas,
* because finding the few holes in them and giving them special
* treatment does not gain much performance. Therefore, we try to
* cache the last-identified data region.
*
* Second, limiting ourselves to protocol nodes allows us to assume
* the block status for data regions to be DATA | OFFSET_VALID, and
* that the host offset is the same as the guest offset.
*
* Note that it is possible that external writers zero parts of
* the cached regions without the cache being invalidated, and so
* we may report zeroes as data. This is not catastrophic,
* however, because reporting zeroes as data is fine.
*/
if (QLIST_EMPTY(&bs->children) &&
bdrv_bsc_is_data(bs, aligned_offset, pnum))
{
ret = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID;
local_file = bs;
local_map = aligned_offset;
} else {
ret = bs->drv->bdrv_co_block_status(bs, want_zero, aligned_offset,
aligned_bytes, pnum, &local_map,
&local_file);
/*
* Note that checking QLIST_EMPTY(&bs->children) is also done when
* the cache is queried above. Technically, we do not need to check
* it here; the worst that can happen is that we fill the cache for
* non-protocol nodes, and then it is never used. However, filling
* the cache requires an RCU update, so double check here to avoid
* such an update if possible.
*/
if (ret == (BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID) &&
QLIST_EMPTY(&bs->children))
{
/*
* When a protocol driver reports BLOCK_OFFSET_VALID, the
* returned local_map value must be the same as the offset we
* have passed (aligned_offset), and local_bs must be the node
* itself.
* Assert this, because we follow this rule when reading from
* the cache (see the `local_file = bs` and
* `local_map = aligned_offset` assignments above), and the
* result the cache delivers must be the same as the driver
* would deliver.
*/
assert(local_file == bs);
assert(local_map == aligned_offset);
bdrv_bsc_fill(bs, aligned_offset, *pnum);
}
}
} else { } else {
/* Default code for filters */ /* Default code for filters */
@ -2818,12 +2752,7 @@ bdrv_co_readv_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos)
{ {
BlockDriver *drv = bs->drv; BlockDriver *drv = bs->drv;
BlockDriverState *child_bs = bdrv_primary_bs(bs); BlockDriverState *child_bs = bdrv_primary_bs(bs);
int ret; int ret = -ENOTSUP;
ret = bdrv_check_qiov_request(pos, qiov->size, qiov, 0, NULL);
if (ret < 0) {
return ret;
}
if (!drv) { if (!drv) {
return -ENOMEDIUM; return -ENOMEDIUM;
@ -2835,8 +2764,6 @@ bdrv_co_readv_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos)
ret = drv->bdrv_load_vmstate(bs, qiov, pos); ret = drv->bdrv_load_vmstate(bs, qiov, pos);
} else if (child_bs) { } else if (child_bs) {
ret = bdrv_co_readv_vmstate(child_bs, qiov, pos); ret = bdrv_co_readv_vmstate(child_bs, qiov, pos);
} else {
ret = -ENOTSUP;
} }
bdrv_dec_in_flight(bs); bdrv_dec_in_flight(bs);
@ -2849,12 +2776,7 @@ bdrv_co_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos)
{ {
BlockDriver *drv = bs->drv; BlockDriver *drv = bs->drv;
BlockDriverState *child_bs = bdrv_primary_bs(bs); BlockDriverState *child_bs = bdrv_primary_bs(bs);
int ret; int ret = -ENOTSUP;
ret = bdrv_check_qiov_request(pos, qiov->size, qiov, 0, NULL);
if (ret < 0) {
return ret;
}
if (!drv) { if (!drv) {
return -ENOMEDIUM; return -ENOMEDIUM;
@ -2866,8 +2788,6 @@ bdrv_co_writev_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos)
ret = drv->bdrv_save_vmstate(bs, qiov, pos); ret = drv->bdrv_save_vmstate(bs, qiov, pos);
} else if (child_bs) { } else if (child_bs) {
ret = bdrv_co_writev_vmstate(child_bs, qiov, pos); ret = bdrv_co_writev_vmstate(child_bs, qiov, pos);
} else {
ret = -ENOTSUP;
} }
bdrv_dec_in_flight(bs); bdrv_dec_in_flight(bs);
@ -3057,8 +2977,7 @@ int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset,
int64_t bytes) int64_t bytes)
{ {
BdrvTrackedRequest req; BdrvTrackedRequest req;
int ret; int max_pdiscard, ret;
int64_t max_pdiscard;
int head, tail, align; int head, tail, align;
BlockDriverState *bs = child->bs; BlockDriverState *bs = child->bs;
@ -3084,9 +3003,6 @@ int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset,
return 0; return 0;
} }
/* Invalidate the cached block-status data range if this discard overlaps */
bdrv_bsc_invalidate_range(bs, offset, bytes);
/* Discard is advisory, but some devices track and coalesce /* Discard is advisory, but some devices track and coalesce
* unaligned requests, so we must pass everything down rather than * unaligned requests, so we must pass everything down rather than
* round here. Still, most devices will just silently ignore * round here. Still, most devices will just silently ignore
@ -3105,7 +3021,7 @@ int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset,
goto out; goto out;
} }
max_pdiscard = QEMU_ALIGN_DOWN(MIN_NON_ZERO(bs->bl.max_pdiscard, INT64_MAX), max_pdiscard = QEMU_ALIGN_DOWN(MIN_NON_ZERO(bs->bl.max_pdiscard, INT_MAX),
align); align);
assert(max_pdiscard >= bs->bl.request_alignment); assert(max_pdiscard >= bs->bl.request_alignment);

View File

@ -427,14 +427,14 @@ static int64_t sector_qemu2lun(int64_t sector, IscsiLun *iscsilun)
return sector * BDRV_SECTOR_SIZE / iscsilun->block_size; return sector * BDRV_SECTOR_SIZE / iscsilun->block_size;
} }
static bool is_byte_request_lun_aligned(int64_t offset, int64_t bytes, static bool is_byte_request_lun_aligned(int64_t offset, int count,
IscsiLun *iscsilun) IscsiLun *iscsilun)
{ {
if (offset % iscsilun->block_size || bytes % iscsilun->block_size) { if (offset % iscsilun->block_size || count % iscsilun->block_size) {
error_report("iSCSI misaligned request: " error_report("iSCSI misaligned request: "
"iscsilun->block_size %u, offset %" PRIi64 "iscsilun->block_size %u, offset %" PRIi64
", bytes %" PRIi64, ", count %d",
iscsilun->block_size, offset, bytes); iscsilun->block_size, offset, count);
return false; return false;
} }
return true; return true;
@ -781,6 +781,9 @@ retry:
iscsi_allocmap_set_allocated(iscsilun, offset, *pnum); iscsi_allocmap_set_allocated(iscsilun, offset, *pnum);
} }
if (*pnum > bytes) {
*pnum = bytes;
}
out_unlock: out_unlock:
qemu_mutex_unlock(&iscsilun->mutex); qemu_mutex_unlock(&iscsilun->mutex);
g_free(iTask.err_str); g_free(iTask.err_str);
@ -1138,8 +1141,7 @@ iscsi_getlength(BlockDriverState *bs)
} }
static int static int
coroutine_fn iscsi_co_pdiscard(BlockDriverState *bs, int64_t offset, coroutine_fn iscsi_co_pdiscard(BlockDriverState *bs, int64_t offset, int bytes)
int64_t bytes)
{ {
IscsiLun *iscsilun = bs->opaque; IscsiLun *iscsilun = bs->opaque;
struct IscsiTask iTask; struct IscsiTask iTask;
@ -1155,12 +1157,6 @@ coroutine_fn iscsi_co_pdiscard(BlockDriverState *bs, int64_t offset,
return 0; return 0;
} }
/*
* We don't want to overflow list.num which is uint32_t.
* We rely on our max_pdiscard.
*/
assert(bytes / iscsilun->block_size <= UINT32_MAX);
list.lba = offset / iscsilun->block_size; list.lba = offset / iscsilun->block_size;
list.num = bytes / iscsilun->block_size; list.num = bytes / iscsilun->block_size;
@ -1209,12 +1205,12 @@ out_unlock:
static int static int
coroutine_fn iscsi_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, coroutine_fn iscsi_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
int64_t bytes, BdrvRequestFlags flags) int bytes, BdrvRequestFlags flags)
{ {
IscsiLun *iscsilun = bs->opaque; IscsiLun *iscsilun = bs->opaque;
struct IscsiTask iTask; struct IscsiTask iTask;
uint64_t lba; uint64_t lba;
uint64_t nb_blocks; uint32_t nb_blocks;
bool use_16_for_ws = iscsilun->use_16_for_rw; bool use_16_for_ws = iscsilun->use_16_for_rw;
int r = 0; int r = 0;
@ -1254,21 +1250,11 @@ coroutine_fn iscsi_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
iscsi_co_init_iscsitask(iscsilun, &iTask); iscsi_co_init_iscsitask(iscsilun, &iTask);
retry: retry:
if (use_16_for_ws) { if (use_16_for_ws) {
/*
* iscsi_writesame16_task num_blocks argument is uint32_t. We rely here
* on our max_pwrite_zeroes limit.
*/
assert(nb_blocks <= UINT32_MAX);
iTask.task = iscsi_writesame16_task(iscsilun->iscsi, iscsilun->lun, lba, iTask.task = iscsi_writesame16_task(iscsilun->iscsi, iscsilun->lun, lba,
iscsilun->zeroblock, iscsilun->block_size, iscsilun->zeroblock, iscsilun->block_size,
nb_blocks, 0, !!(flags & BDRV_REQ_MAY_UNMAP), nb_blocks, 0, !!(flags & BDRV_REQ_MAY_UNMAP),
0, 0, iscsi_co_generic_cb, &iTask); 0, 0, iscsi_co_generic_cb, &iTask);
} else { } else {
/*
* iscsi_writesame10_task num_blocks argument is uint16_t. We rely here
* on our max_pwrite_zeroes limit.
*/
assert(nb_blocks <= UINT16_MAX);
iTask.task = iscsi_writesame10_task(iscsilun->iscsi, iscsilun->lun, lba, iTask.task = iscsi_writesame10_task(iscsilun->iscsi, iscsilun->lun, lba,
iscsilun->zeroblock, iscsilun->block_size, iscsilun->zeroblock, iscsilun->block_size,
nb_blocks, 0, !!(flags & BDRV_REQ_MAY_UNMAP), nb_blocks, 0, !!(flags & BDRV_REQ_MAY_UNMAP),
@ -2078,19 +2064,20 @@ static void iscsi_refresh_limits(BlockDriverState *bs, Error **errp)
} }
if (iscsilun->lbp.lbpu) { if (iscsilun->lbp.lbpu) {
bs->bl.max_pdiscard = if (iscsilun->bl.max_unmap < 0xffffffff / block_size) {
MIN_NON_ZERO(iscsilun->bl.max_unmap * iscsilun->block_size, bs->bl.max_pdiscard =
(uint64_t)UINT32_MAX * iscsilun->block_size); iscsilun->bl.max_unmap * iscsilun->block_size;
}
bs->bl.pdiscard_alignment = bs->bl.pdiscard_alignment =
iscsilun->bl.opt_unmap_gran * iscsilun->block_size; iscsilun->bl.opt_unmap_gran * iscsilun->block_size;
} else { } else {
bs->bl.pdiscard_alignment = iscsilun->block_size; bs->bl.pdiscard_alignment = iscsilun->block_size;
} }
bs->bl.max_pwrite_zeroes = if (iscsilun->bl.max_ws_len < 0xffffffff / block_size) {
MIN_NON_ZERO(iscsilun->bl.max_ws_len * iscsilun->block_size, bs->bl.max_pwrite_zeroes =
max_xfer_len * iscsilun->block_size); iscsilun->bl.max_ws_len * iscsilun->block_size;
}
if (iscsilun->lbp.lbpws) { if (iscsilun->lbp.lbpws) {
bs->bl.pwrite_zeroes_alignment = bs->bl.pwrite_zeroes_alignment =
iscsilun->bl.opt_unmap_gran * iscsilun->block_size; iscsilun->bl.opt_unmap_gran * iscsilun->block_size;
@ -2185,10 +2172,10 @@ static void coroutine_fn iscsi_co_invalidate_cache(BlockDriverState *bs,
static int coroutine_fn iscsi_co_copy_range_from(BlockDriverState *bs, static int coroutine_fn iscsi_co_copy_range_from(BlockDriverState *bs,
BdrvChild *src, BdrvChild *src,
int64_t src_offset, uint64_t src_offset,
BdrvChild *dst, BdrvChild *dst,
int64_t dst_offset, uint64_t dst_offset,
int64_t bytes, uint64_t bytes,
BdrvRequestFlags read_flags, BdrvRequestFlags read_flags,
BdrvRequestFlags write_flags) BdrvRequestFlags write_flags)
{ {
@ -2326,10 +2313,10 @@ static void iscsi_xcopy_data(struct iscsi_data *data,
static int coroutine_fn iscsi_co_copy_range_to(BlockDriverState *bs, static int coroutine_fn iscsi_co_copy_range_to(BlockDriverState *bs,
BdrvChild *src, BdrvChild *src,
int64_t src_offset, uint64_t src_offset,
BdrvChild *dst, BdrvChild *dst,
int64_t dst_offset, uint64_t dst_offset,
int64_t bytes, uint64_t bytes,
BdrvRequestFlags read_flags, BdrvRequestFlags read_flags,
BdrvRequestFlags write_flags) BdrvRequestFlags write_flags)
{ {

View File

@ -334,45 +334,30 @@ static void ioq_submit(LinuxAioState *s)
} }
} }
static uint64_t laio_max_batch(LinuxAioState *s, uint64_t dev_max_batch)
{
uint64_t max_batch = s->aio_context->aio_max_batch ?: DEFAULT_MAX_BATCH;
/*
* AIO context can be shared between multiple block devices, so
* `dev_max_batch` allows reducing the batch size for latency-sensitive
* devices.
*/
max_batch = MIN_NON_ZERO(dev_max_batch, max_batch);
/* limit the batch with the number of available events */
max_batch = MIN_NON_ZERO(MAX_EVENTS - s->io_q.in_flight, max_batch);
return max_batch;
}
void laio_io_plug(BlockDriverState *bs, LinuxAioState *s) void laio_io_plug(BlockDriverState *bs, LinuxAioState *s)
{ {
s->io_q.plugged++; s->io_q.plugged++;
} }
void laio_io_unplug(BlockDriverState *bs, LinuxAioState *s, void laio_io_unplug(BlockDriverState *bs, LinuxAioState *s)
uint64_t dev_max_batch)
{ {
assert(s->io_q.plugged); assert(s->io_q.plugged);
if (s->io_q.in_queue >= laio_max_batch(s, dev_max_batch) || if (--s->io_q.plugged == 0 &&
(--s->io_q.plugged == 0 && !s->io_q.blocked && !QSIMPLEQ_EMPTY(&s->io_q.pending)) {
!s->io_q.blocked && !QSIMPLEQ_EMPTY(&s->io_q.pending))) {
ioq_submit(s); ioq_submit(s);
} }
} }
static int laio_do_submit(int fd, struct qemu_laiocb *laiocb, off_t offset, static int laio_do_submit(int fd, struct qemu_laiocb *laiocb, off_t offset,
int type, uint64_t dev_max_batch) int type)
{ {
LinuxAioState *s = laiocb->ctx; LinuxAioState *s = laiocb->ctx;
struct iocb *iocbs = &laiocb->iocb; struct iocb *iocbs = &laiocb->iocb;
QEMUIOVector *qiov = laiocb->qiov; QEMUIOVector *qiov = laiocb->qiov;
int64_t max_batch = s->aio_context->aio_max_batch ?: DEFAULT_MAX_BATCH;
/* limit the batch with the number of available events */
max_batch = MIN_NON_ZERO(MAX_EVENTS - s->io_q.in_flight, max_batch);
switch (type) { switch (type) {
case QEMU_AIO_WRITE: case QEMU_AIO_WRITE:
@ -393,7 +378,7 @@ static int laio_do_submit(int fd, struct qemu_laiocb *laiocb, off_t offset,
s->io_q.in_queue++; s->io_q.in_queue++;
if (!s->io_q.blocked && if (!s->io_q.blocked &&
(!s->io_q.plugged || (!s->io_q.plugged ||
s->io_q.in_queue >= laio_max_batch(s, dev_max_batch))) { s->io_q.in_queue >= max_batch)) {
ioq_submit(s); ioq_submit(s);
} }
@ -401,8 +386,7 @@ static int laio_do_submit(int fd, struct qemu_laiocb *laiocb, off_t offset,
} }
int coroutine_fn laio_co_submit(BlockDriverState *bs, LinuxAioState *s, int fd, int coroutine_fn laio_co_submit(BlockDriverState *bs, LinuxAioState *s, int fd,
uint64_t offset, QEMUIOVector *qiov, int type, uint64_t offset, QEMUIOVector *qiov, int type)
uint64_t dev_max_batch)
{ {
int ret; int ret;
struct qemu_laiocb laiocb = { struct qemu_laiocb laiocb = {
@ -414,7 +398,7 @@ int coroutine_fn laio_co_submit(BlockDriverState *bs, LinuxAioState *s, int fd,
.qiov = qiov, .qiov = qiov,
}; };
ret = laio_do_submit(fd, &laiocb, offset, type, dev_max_batch); ret = laio_do_submit(fd, &laiocb, offset, type);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }

View File

@ -4,7 +4,7 @@ block_ss.add(files(
'aio_task.c', 'aio_task.c',
'amend.c', 'amend.c',
'backup.c', 'backup.c',
'copy-before-write.c', 'backup-top.c',
'blkdebug.c', 'blkdebug.c',
'blklogwrites.c', 'blklogwrites.c',
'blkverify.c', 'blkverify.c',
@ -65,7 +65,7 @@ block_ss.add(when: 'CONFIG_POSIX', if_true: [files('file-posix.c'), coref, iokit
block_ss.add(when: libiscsi, if_true: files('iscsi-opts.c')) block_ss.add(when: libiscsi, if_true: files('iscsi-opts.c'))
block_ss.add(when: 'CONFIG_LINUX', if_true: files('nvme.c')) block_ss.add(when: 'CONFIG_LINUX', if_true: files('nvme.c'))
block_ss.add(when: 'CONFIG_REPLICATION', if_true: files('replication.c')) block_ss.add(when: 'CONFIG_REPLICATION', if_true: files('replication.c'))
block_ss.add(when: libaio, if_true: files('linux-aio.c')) block_ss.add(when: ['CONFIG_LINUX_AIO', libaio], if_true: files('linux-aio.c'))
block_ss.add(when: linux_io_uring, if_true: files('io_uring.c')) block_ss.add(when: linux_io_uring, if_true: files('io_uring.c'))
block_modules = {} block_modules = {}

View File

@ -56,6 +56,7 @@ typedef struct MirrorBlockJob {
bool zero_target; bool zero_target;
MirrorCopyMode copy_mode; MirrorCopyMode copy_mode;
BlockdevOnError on_source_error, on_target_error; BlockdevOnError on_source_error, on_target_error;
bool synced;
/* Set when the target is synced (dirty bitmap is clean, nothing /* Set when the target is synced (dirty bitmap is clean, nothing
* in flight) and the job is running in active mode */ * in flight) and the job is running in active mode */
bool actively_synced; bool actively_synced;
@ -120,6 +121,7 @@ typedef enum MirrorMethod {
static BlockErrorAction mirror_error_action(MirrorBlockJob *s, bool read, static BlockErrorAction mirror_error_action(MirrorBlockJob *s, bool read,
int error) int error)
{ {
s->synced = false;
s->actively_synced = false; s->actively_synced = false;
if (read) { if (read) {
return block_job_error_action(&s->common, s->on_source_error, return block_job_error_action(&s->common, s->on_source_error,
@ -158,25 +160,18 @@ static void coroutine_fn mirror_wait_on_conflicts(MirrorOp *self,
if (ranges_overlap(self_start_chunk, self_nb_chunks, if (ranges_overlap(self_start_chunk, self_nb_chunks,
op_start_chunk, op_nb_chunks)) op_start_chunk, op_nb_chunks))
{ {
if (self) { /*
/* * If the operation is already (indirectly) waiting for us, or
* If the operation is already (indirectly) waiting for us, * will wait for us as soon as it wakes up, then just go on
* or will wait for us as soon as it wakes up, then just go * (instead of producing a deadlock in the former case).
* on (instead of producing a deadlock in the former case). */
*/ if (op->waiting_for_op) {
if (op->waiting_for_op) { continue;
continue;
}
self->waiting_for_op = op;
} }
self->waiting_for_op = op;
qemu_co_queue_wait(&op->waiting_requests, NULL); qemu_co_queue_wait(&op->waiting_requests, NULL);
self->waiting_for_op = NULL;
if (self) {
self->waiting_for_op = NULL;
}
break; break;
} }
} }
@ -942,10 +937,12 @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
if (s->bdev_length == 0) { if (s->bdev_length == 0) {
/* Transition to the READY state and wait for complete. */ /* Transition to the READY state and wait for complete. */
job_transition_to_ready(&s->common.job); job_transition_to_ready(&s->common.job);
s->synced = true;
s->actively_synced = true; s->actively_synced = true;
while (!job_cancel_requested(&s->common.job) && !s->should_complete) { while (!job_is_cancelled(&s->common.job) && !s->should_complete) {
job_yield(&s->common.job); job_yield(&s->common.job);
} }
s->common.job.cancelled = false;
goto immediate_exit; goto immediate_exit;
} }
@ -1006,11 +1003,6 @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
job_pause_point(&s->common.job); job_pause_point(&s->common.job);
if (job_is_cancelled(&s->common.job)) {
ret = 0;
goto immediate_exit;
}
cnt = bdrv_get_dirty_count(s->dirty_bitmap); cnt = bdrv_get_dirty_count(s->dirty_bitmap);
/* cnt is the number of dirty bytes remaining and s->bytes_in_flight is /* cnt is the number of dirty bytes remaining and s->bytes_in_flight is
* the number of bytes currently being processed; together those are * the number of bytes currently being processed; together those are
@ -1037,7 +1029,7 @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
should_complete = false; should_complete = false;
if (s->in_flight == 0 && cnt == 0) { if (s->in_flight == 0 && cnt == 0) {
trace_mirror_before_flush(s); trace_mirror_before_flush(s);
if (!job_is_ready(&s->common.job)) { if (!s->synced) {
if (mirror_flush(s) < 0) { if (mirror_flush(s) < 0) {
/* Go check s->ret. */ /* Go check s->ret. */
continue; continue;
@ -1048,13 +1040,14 @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
* the target in a consistent state. * the target in a consistent state.
*/ */
job_transition_to_ready(&s->common.job); job_transition_to_ready(&s->common.job);
s->synced = true;
if (s->copy_mode != MIRROR_COPY_MODE_BACKGROUND) { if (s->copy_mode != MIRROR_COPY_MODE_BACKGROUND) {
s->actively_synced = true; s->actively_synced = true;
} }
} }
should_complete = s->should_complete || should_complete = s->should_complete ||
job_cancel_requested(&s->common.job); job_is_cancelled(&s->common.job);
cnt = bdrv_get_dirty_count(s->dirty_bitmap); cnt = bdrv_get_dirty_count(s->dirty_bitmap);
} }
@ -1084,17 +1077,24 @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
* completion. * completion.
*/ */
assert(QLIST_EMPTY(&bs->tracked_requests)); assert(QLIST_EMPTY(&bs->tracked_requests));
s->common.job.cancelled = false;
need_drain = false; need_drain = false;
break; break;
} }
if (job_is_ready(&s->common.job) && !should_complete) { ret = 0;
if (s->synced && !should_complete) {
delay_ns = (s->in_flight == 0 && delay_ns = (s->in_flight == 0 &&
cnt == 0 ? BLOCK_JOB_SLICE_TIME : 0); cnt == 0 ? BLOCK_JOB_SLICE_TIME : 0);
} }
trace_mirror_before_sleep(s, cnt, job_is_ready(&s->common.job), trace_mirror_before_sleep(s, cnt, s->synced, delay_ns);
delay_ns);
job_sleep_ns(&s->common.job, delay_ns); job_sleep_ns(&s->common.job, delay_ns);
if (job_is_cancelled(&s->common.job) &&
(!s->synced || s->common.job.force_cancel))
{
break;
}
s->last_pause_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); s->last_pause_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
} }
@ -1104,7 +1104,8 @@ immediate_exit:
* or it was cancelled prematurely so that we do not guarantee that * or it was cancelled prematurely so that we do not guarantee that
* the target is a copy of the source. * the target is a copy of the source.
*/ */
assert(ret < 0 || job_is_cancelled(&s->common.job)); assert(ret < 0 || ((s->common.job.force_cancel || !s->synced) &&
job_is_cancelled(&s->common.job)));
assert(need_drain); assert(need_drain);
mirror_wait_for_all_io(s); mirror_wait_for_all_io(s);
} }
@ -1127,7 +1128,7 @@ static void mirror_complete(Job *job, Error **errp)
{ {
MirrorBlockJob *s = container_of(job, MirrorBlockJob, common.job); MirrorBlockJob *s = container_of(job, MirrorBlockJob, common.job);
if (!job_is_ready(job)) { if (!s->synced) {
error_setg(errp, "The active block job '%s' cannot be completed", error_setg(errp, "The active block job '%s' cannot be completed",
job->id); job->id);
return; return;
@ -1182,34 +1183,21 @@ static bool mirror_drained_poll(BlockJob *job)
* from one of our own drain sections, to avoid a deadlock waiting for * from one of our own drain sections, to avoid a deadlock waiting for
* ourselves. * ourselves.
*/ */
if (!s->common.job.paused && !job_is_cancelled(&job->job) && !s->in_drain) { if (!s->common.job.paused && !s->common.job.cancelled && !s->in_drain) {
return true; return true;
} }
return !!s->in_flight; return !!s->in_flight;
} }
static bool mirror_cancel(Job *job, bool force) static void mirror_cancel(Job *job, bool force)
{ {
MirrorBlockJob *s = container_of(job, MirrorBlockJob, common.job); MirrorBlockJob *s = container_of(job, MirrorBlockJob, common.job);
BlockDriverState *target = blk_bs(s->target); BlockDriverState *target = blk_bs(s->target);
/* if (force || !job_is_ready(job)) {
* Before the job is READY, we treat any cancellation like a
* force-cancellation.
*/
force = force || !job_is_ready(job);
if (force) {
bdrv_cancel_in_flight(target); bdrv_cancel_in_flight(target);
} }
return force;
}
static bool commit_active_cancel(Job *job, bool force)
{
/* Same as above in mirror_cancel() */
return force || !job_is_ready(job);
} }
static const BlockJobDriver mirror_job_driver = { static const BlockJobDriver mirror_job_driver = {
@ -1239,7 +1227,6 @@ static const BlockJobDriver commit_active_job_driver = {
.abort = mirror_abort, .abort = mirror_abort,
.pause = mirror_pause, .pause = mirror_pause,
.complete = mirror_complete, .complete = mirror_complete,
.cancel = commit_active_cancel,
}, },
.drained_poll = mirror_drained_poll, .drained_poll = mirror_drained_poll,
}; };
@ -1408,7 +1395,7 @@ static void coroutine_fn active_write_settle(MirrorOp *op)
} }
static int coroutine_fn bdrv_mirror_top_preadv(BlockDriverState *bs, static int coroutine_fn bdrv_mirror_top_preadv(BlockDriverState *bs,
int64_t offset, int64_t bytes, QEMUIOVector *qiov, BdrvRequestFlags flags) uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags)
{ {
return bdrv_co_preadv(bs->backing, offset, bytes, qiov, flags); return bdrv_co_preadv(bs->backing, offset, bytes, qiov, flags);
} }
@ -1423,7 +1410,6 @@ static int coroutine_fn bdrv_mirror_top_do_write(BlockDriverState *bs,
bool copy_to_target; bool copy_to_target;
copy_to_target = s->job->ret >= 0 && copy_to_target = s->job->ret >= 0 &&
!job_is_cancelled(&s->job->common.job) &&
s->job->copy_mode == MIRROR_COPY_MODE_WRITE_BLOCKING; s->job->copy_mode == MIRROR_COPY_MODE_WRITE_BLOCKING;
if (copy_to_target) { if (copy_to_target) {
@ -1463,7 +1449,7 @@ out:
} }
static int coroutine_fn bdrv_mirror_top_pwritev(BlockDriverState *bs, static int coroutine_fn bdrv_mirror_top_pwritev(BlockDriverState *bs,
int64_t offset, int64_t bytes, QEMUIOVector *qiov, BdrvRequestFlags flags) uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags)
{ {
MirrorBDSOpaque *s = bs->opaque; MirrorBDSOpaque *s = bs->opaque;
QEMUIOVector bounce_qiov; QEMUIOVector bounce_qiov;
@ -1472,7 +1458,6 @@ static int coroutine_fn bdrv_mirror_top_pwritev(BlockDriverState *bs,
bool copy_to_target; bool copy_to_target;
copy_to_target = s->job->ret >= 0 && copy_to_target = s->job->ret >= 0 &&
!job_is_cancelled(&s->job->common.job) &&
s->job->copy_mode == MIRROR_COPY_MODE_WRITE_BLOCKING; s->job->copy_mode == MIRROR_COPY_MODE_WRITE_BLOCKING;
if (copy_to_target) { if (copy_to_target) {
@ -1509,14 +1494,14 @@ static int coroutine_fn bdrv_mirror_top_flush(BlockDriverState *bs)
} }
static int coroutine_fn bdrv_mirror_top_pwrite_zeroes(BlockDriverState *bs, static int coroutine_fn bdrv_mirror_top_pwrite_zeroes(BlockDriverState *bs,
int64_t offset, int64_t bytes, BdrvRequestFlags flags) int64_t offset, int bytes, BdrvRequestFlags flags)
{ {
return bdrv_mirror_top_do_write(bs, MIRROR_METHOD_ZERO, offset, bytes, NULL, return bdrv_mirror_top_do_write(bs, MIRROR_METHOD_ZERO, offset, bytes, NULL,
flags); flags);
} }
static int coroutine_fn bdrv_mirror_top_pdiscard(BlockDriverState *bs, static int coroutine_fn bdrv_mirror_top_pdiscard(BlockDriverState *bs,
int64_t offset, int64_t bytes) int64_t offset, int bytes)
{ {
return bdrv_mirror_top_do_write(bs, MIRROR_METHOD_DISCARD, offset, bytes, return bdrv_mirror_top_do_write(bs, MIRROR_METHOD_DISCARD, offset, bytes,
NULL, 0); NULL, 0);

View File

@ -251,10 +251,10 @@ void hmp_drive_mirror(Monitor *mon, const QDict *qdict)
if (!filename) { if (!filename) {
error_setg(&err, QERR_MISSING_PARAMETER, "target"); error_setg(&err, QERR_MISSING_PARAMETER, "target");
goto end; hmp_handle_error(mon, err);
return;
} }
qmp_drive_mirror(&mirror, &err); qmp_drive_mirror(&mirror, &err);
end:
hmp_handle_error(mon, err); hmp_handle_error(mon, err);
} }
@ -281,11 +281,11 @@ void hmp_drive_backup(Monitor *mon, const QDict *qdict)
if (!filename) { if (!filename) {
error_setg(&err, QERR_MISSING_PARAMETER, "target"); error_setg(&err, QERR_MISSING_PARAMETER, "target");
goto end; hmp_handle_error(mon, err);
return;
} }
qmp_drive_backup(&backup, &err); qmp_drive_backup(&backup, &err);
end:
hmp_handle_error(mon, err); hmp_handle_error(mon, err);
} }
@ -356,7 +356,8 @@ void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict)
* will be taken internally. Today it's actually required. * will be taken internally. Today it's actually required.
*/ */
error_setg(&err, QERR_MISSING_PARAMETER, "snapshot-file"); error_setg(&err, QERR_MISSING_PARAMETER, "snapshot-file");
goto end; hmp_handle_error(mon, err);
return;
} }
mode = reuse ? NEW_IMAGE_MODE_EXISTING : NEW_IMAGE_MODE_ABSOLUTE_PATHS; mode = reuse ? NEW_IMAGE_MODE_EXISTING : NEW_IMAGE_MODE_ABSOLUTE_PATHS;
@ -364,7 +365,6 @@ void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict)
filename, false, NULL, filename, false, NULL,
!!format, format, !!format, format,
true, mode, &err); true, mode, &err);
end:
hmp_handle_error(mon, err); hmp_handle_error(mon, err);
} }

View File

@ -57,8 +57,7 @@
typedef struct { typedef struct {
Coroutine *coroutine; Coroutine *coroutine;
uint64_t offset; /* original offset of the request */ uint64_t offset; /* original offset of the request */
bool receiving; /* sleeping in the yield in nbd_receive_replies */ bool receiving; /* waiting for connection_co? */
bool reply_possible; /* reply header not yet received */
} NBDClientRequest; } NBDClientRequest;
typedef enum NBDClientState { typedef enum NBDClientState {
@ -74,10 +73,14 @@ typedef struct BDRVNBDState {
CoMutex send_mutex; CoMutex send_mutex;
CoQueue free_sema; CoQueue free_sema;
Coroutine *connection_co;
CoMutex receive_mutex; Coroutine *teardown_co;
QemuCoSleep reconnect_sleep;
bool drained;
bool wait_drained_end;
int in_flight; int in_flight;
NBDClientState state; NBDClientState state;
bool wait_in_flight;
QEMUTimer *reconnect_delay_timer; QEMUTimer *reconnect_delay_timer;
@ -124,44 +127,33 @@ static bool nbd_client_connected(BDRVNBDState *s)
return qatomic_load_acquire(&s->state) == NBD_CLIENT_CONNECTED; return qatomic_load_acquire(&s->state) == NBD_CLIENT_CONNECTED;
} }
static bool nbd_recv_coroutine_wake_one(NBDClientRequest *req)
{
if (req->receiving) {
req->receiving = false;
aio_co_wake(req->coroutine);
return true;
}
return false;
}
static void nbd_recv_coroutines_wake(BDRVNBDState *s, bool all)
{
int i;
for (i = 0; i < MAX_NBD_REQUESTS; i++) {
if (nbd_recv_coroutine_wake_one(&s->requests[i]) && !all) {
return;
}
}
}
static void nbd_channel_error(BDRVNBDState *s, int ret) static void nbd_channel_error(BDRVNBDState *s, int ret)
{ {
if (nbd_client_connected(s)) {
qio_channel_shutdown(s->ioc, QIO_CHANNEL_SHUTDOWN_BOTH, NULL);
}
if (ret == -EIO) { if (ret == -EIO) {
if (nbd_client_connected(s)) { if (nbd_client_connected(s)) {
s->state = s->reconnect_delay ? NBD_CLIENT_CONNECTING_WAIT : s->state = s->reconnect_delay ? NBD_CLIENT_CONNECTING_WAIT :
NBD_CLIENT_CONNECTING_NOWAIT; NBD_CLIENT_CONNECTING_NOWAIT;
} }
} else { } else {
if (nbd_client_connected(s)) {
qio_channel_shutdown(s->ioc, QIO_CHANNEL_SHUTDOWN_BOTH, NULL);
}
s->state = NBD_CLIENT_QUIT; s->state = NBD_CLIENT_QUIT;
} }
}
nbd_recv_coroutines_wake(s, true); static void nbd_recv_coroutines_wake_all(BDRVNBDState *s)
{
int i;
for (i = 0; i < MAX_NBD_REQUESTS; i++) {
NBDClientRequest *req = &s->requests[i];
if (req->coroutine && req->receiving) {
req->receiving = false;
aio_co_wake(req->coroutine);
}
}
} }
static void reconnect_delay_timer_del(BDRVNBDState *s) static void reconnect_delay_timer_del(BDRVNBDState *s)
@ -178,7 +170,6 @@ static void reconnect_delay_timer_cb(void *opaque)
if (qatomic_load_acquire(&s->state) == NBD_CLIENT_CONNECTING_WAIT) { if (qatomic_load_acquire(&s->state) == NBD_CLIENT_CONNECTING_WAIT) {
s->state = NBD_CLIENT_CONNECTING_NOWAIT; s->state = NBD_CLIENT_CONNECTING_NOWAIT;
nbd_co_establish_connection_cancel(s->conn);
while (qemu_co_enter_next(&s->free_sema, NULL)) { while (qemu_co_enter_next(&s->free_sema, NULL)) {
/* Resume all queued requests */ /* Resume all queued requests */
} }
@ -201,21 +192,113 @@ static void reconnect_delay_timer_init(BDRVNBDState *s, uint64_t expire_time_ns)
timer_mod(s->reconnect_delay_timer, expire_time_ns); timer_mod(s->reconnect_delay_timer, expire_time_ns);
} }
static void nbd_client_detach_aio_context(BlockDriverState *bs)
{
BDRVNBDState *s = (BDRVNBDState *)bs->opaque;
/* Timer is deleted in nbd_client_co_drain_begin() */
assert(!s->reconnect_delay_timer);
/*
* If reconnect is in progress we may have no ->ioc. It will be
* re-instantiated in the proper aio context once the connection is
* reestablished.
*/
if (s->ioc) {
qio_channel_detach_aio_context(QIO_CHANNEL(s->ioc));
}
}
static void nbd_client_attach_aio_context_bh(void *opaque)
{
BlockDriverState *bs = opaque;
BDRVNBDState *s = (BDRVNBDState *)bs->opaque;
if (s->connection_co) {
/*
* The node is still drained, so we know the coroutine has yielded in
* nbd_read_eof(), the only place where bs->in_flight can reach 0, or
* it is entered for the first time. Both places are safe for entering
* the coroutine.
*/
qemu_aio_coroutine_enter(bs->aio_context, s->connection_co);
}
bdrv_dec_in_flight(bs);
}
static void nbd_client_attach_aio_context(BlockDriverState *bs,
AioContext *new_context)
{
BDRVNBDState *s = (BDRVNBDState *)bs->opaque;
/*
* s->connection_co is either yielded from nbd_receive_reply or from
* nbd_co_reconnect_loop()
*/
if (nbd_client_connected(s)) {
qio_channel_attach_aio_context(QIO_CHANNEL(s->ioc), new_context);
}
bdrv_inc_in_flight(bs);
/*
* Need to wait here for the BH to run because the BH must run while the
* node is still drained.
*/
aio_wait_bh_oneshot(new_context, nbd_client_attach_aio_context_bh, bs);
}
static void coroutine_fn nbd_client_co_drain_begin(BlockDriverState *bs)
{
BDRVNBDState *s = (BDRVNBDState *)bs->opaque;
s->drained = true;
qemu_co_sleep_wake(&s->reconnect_sleep);
nbd_co_establish_connection_cancel(s->conn);
reconnect_delay_timer_del(s);
if (qatomic_load_acquire(&s->state) == NBD_CLIENT_CONNECTING_WAIT) {
s->state = NBD_CLIENT_CONNECTING_NOWAIT;
qemu_co_queue_restart_all(&s->free_sema);
}
}
static void coroutine_fn nbd_client_co_drain_end(BlockDriverState *bs)
{
BDRVNBDState *s = (BDRVNBDState *)bs->opaque;
s->drained = false;
if (s->wait_drained_end) {
s->wait_drained_end = false;
aio_co_wake(s->connection_co);
}
}
static void nbd_teardown_connection(BlockDriverState *bs) static void nbd_teardown_connection(BlockDriverState *bs)
{ {
BDRVNBDState *s = (BDRVNBDState *)bs->opaque; BDRVNBDState *s = (BDRVNBDState *)bs->opaque;
assert(!s->in_flight);
if (s->ioc) { if (s->ioc) {
/* finish any pending coroutines */
qio_channel_shutdown(s->ioc, QIO_CHANNEL_SHUTDOWN_BOTH, NULL); qio_channel_shutdown(s->ioc, QIO_CHANNEL_SHUTDOWN_BOTH, NULL);
yank_unregister_function(BLOCKDEV_YANK_INSTANCE(s->bs->node_name),
nbd_yank, s->bs);
object_unref(OBJECT(s->ioc));
s->ioc = NULL;
} }
s->state = NBD_CLIENT_QUIT; s->state = NBD_CLIENT_QUIT;
if (s->connection_co) {
qemu_co_sleep_wake(&s->reconnect_sleep);
nbd_co_establish_connection_cancel(s->conn);
}
if (qemu_in_coroutine()) {
s->teardown_co = qemu_coroutine_self();
/* connection_co resumes us when it terminates */
qemu_coroutine_yield();
s->teardown_co = NULL;
} else {
BDRV_POLL_WHILE(bs, s->connection_co);
}
assert(!s->connection_co);
} }
static bool nbd_client_connecting(BDRVNBDState *s) static bool nbd_client_connecting(BDRVNBDState *s)
@ -280,11 +363,10 @@ int coroutine_fn nbd_co_do_establish_connection(BlockDriverState *bs,
{ {
BDRVNBDState *s = (BDRVNBDState *)bs->opaque; BDRVNBDState *s = (BDRVNBDState *)bs->opaque;
int ret; int ret;
bool blocking = nbd_client_connecting_wait(s);
assert(!s->ioc); assert(!s->ioc);
s->ioc = nbd_co_establish_connection(s->conn, &s->info, blocking, errp); s->ioc = nbd_co_establish_connection(s->conn, &s->info, true, errp);
if (!s->ioc) { if (!s->ioc) {
return -ECONNREFUSED; return -ECONNREFUSED;
} }
@ -320,22 +402,29 @@ int coroutine_fn nbd_co_do_establish_connection(BlockDriverState *bs,
return 0; return 0;
} }
/* called under s->send_mutex */
static coroutine_fn void nbd_reconnect_attempt(BDRVNBDState *s) static coroutine_fn void nbd_reconnect_attempt(BDRVNBDState *s)
{ {
assert(nbd_client_connecting(s)); if (!nbd_client_connecting(s)) {
assert(s->in_flight == 0); return;
}
if (nbd_client_connecting_wait(s) && s->reconnect_delay && /* Wait for completion of all in-flight requests */
!s->reconnect_delay_timer)
{ qemu_co_mutex_lock(&s->send_mutex);
/*
* It's first reconnect attempt after switching to while (s->in_flight > 0) {
* NBD_CLIENT_CONNECTING_WAIT qemu_co_mutex_unlock(&s->send_mutex);
*/ nbd_recv_coroutines_wake_all(s);
reconnect_delay_timer_init(s, s->wait_in_flight = true;
qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + qemu_coroutine_yield();
s->reconnect_delay * NANOSECONDS_PER_SECOND); s->wait_in_flight = false;
qemu_co_mutex_lock(&s->send_mutex);
}
qemu_co_mutex_unlock(&s->send_mutex);
if (!nbd_client_connecting(s)) {
return;
} }
/* /*
@ -355,73 +444,135 @@ static coroutine_fn void nbd_reconnect_attempt(BDRVNBDState *s)
nbd_co_do_establish_connection(s->bs, NULL); nbd_co_do_establish_connection(s->bs, NULL);
} }
static coroutine_fn int nbd_receive_replies(BDRVNBDState *s, uint64_t handle) static coroutine_fn void nbd_co_reconnect_loop(BDRVNBDState *s)
{ {
int ret; uint64_t timeout = 1 * NANOSECONDS_PER_SECOND;
uint64_t ind = HANDLE_TO_INDEX(s, handle), ind2; uint64_t max_timeout = 16 * NANOSECONDS_PER_SECOND;
QEMU_LOCK_GUARD(&s->receive_mutex);
while (true) { if (qatomic_load_acquire(&s->state) == NBD_CLIENT_CONNECTING_WAIT) {
if (s->reply.handle == handle) { reconnect_delay_timer_init(s, qemu_clock_get_ns(QEMU_CLOCK_REALTIME) +
/* We are done */ s->reconnect_delay * NANOSECONDS_PER_SECOND);
return 0; }
nbd_reconnect_attempt(s);
while (nbd_client_connecting(s)) {
if (s->drained) {
bdrv_dec_in_flight(s->bs);
s->wait_drained_end = true;
while (s->drained) {
/*
* We may be entered once from nbd_client_attach_aio_context_bh
* and then from nbd_client_co_drain_end. So here is a loop.
*/
qemu_coroutine_yield();
}
bdrv_inc_in_flight(s->bs);
} else {
qemu_co_sleep_ns_wakeable(&s->reconnect_sleep,
QEMU_CLOCK_REALTIME, timeout);
if (s->drained) {
continue;
}
if (timeout < max_timeout) {
timeout *= 2;
}
}
nbd_reconnect_attempt(s);
}
reconnect_delay_timer_del(s);
}
static coroutine_fn void nbd_connection_entry(void *opaque)
{
BDRVNBDState *s = opaque;
uint64_t i;
int ret = 0;
Error *local_err = NULL;
while (qatomic_load_acquire(&s->state) != NBD_CLIENT_QUIT) {
/*
* The NBD client can only really be considered idle when it has
* yielded from qio_channel_readv_all_eof(), waiting for data. This is
* the point where the additional scheduled coroutine entry happens
* after nbd_client_attach_aio_context().
*
* Therefore we keep an additional in_flight reference all the time and
* only drop it temporarily here.
*/
if (nbd_client_connecting(s)) {
nbd_co_reconnect_loop(s);
} }
if (!nbd_client_connected(s)) { if (!nbd_client_connected(s)) {
return -EIO;
}
if (s->reply.handle != 0) {
/*
* Some other request is being handled now. It should already be
* woken by whoever set s->reply.handle (or never wait in this
* yield). So, we should not wake it here.
*/
ind2 = HANDLE_TO_INDEX(s, s->reply.handle);
assert(!s->requests[ind2].receiving);
s->requests[ind].receiving = true;
qemu_co_mutex_unlock(&s->receive_mutex);
qemu_coroutine_yield();
/*
* We may be woken for 3 reasons:
* 1. From this function, executing in parallel coroutine, when our
* handle is received.
* 2. From nbd_channel_error(), when connection is lost.
* 3. From nbd_co_receive_one_chunk(), when previous request is
* finished and s->reply.handle set to 0.
* Anyway, it's OK to lock the mutex and go to the next iteration.
*/
qemu_co_mutex_lock(&s->receive_mutex);
assert(!s->requests[ind].receiving);
continue; continue;
} }
/* We are under mutex and handle is 0. We have to do the dirty work. */
assert(s->reply.handle == 0); assert(s->reply.handle == 0);
ret = nbd_receive_reply(s->bs, s->ioc, &s->reply, NULL); ret = nbd_receive_reply(s->bs, s->ioc, &s->reply, &local_err);
if (local_err) {
trace_nbd_read_reply_entry_fail(ret, error_get_pretty(local_err));
error_free(local_err);
local_err = NULL;
}
if (ret <= 0) { if (ret <= 0) {
ret = ret ? ret : -EIO; nbd_channel_error(s, ret ? ret : -EIO);
nbd_channel_error(s, ret); continue;
return ret;
} }
if (nbd_reply_is_structured(&s->reply) && !s->info.structured_reply) {
/*
* There's no need for a mutex on the receive side, because the
* handler acts as a synchronization point and ensures that only
* one coroutine is called until the reply finishes.
*/
i = HANDLE_TO_INDEX(s, s->reply.handle);
if (i >= MAX_NBD_REQUESTS ||
!s->requests[i].coroutine ||
!s->requests[i].receiving ||
(nbd_reply_is_structured(&s->reply) && !s->info.structured_reply))
{
nbd_channel_error(s, -EINVAL); nbd_channel_error(s, -EINVAL);
return -EINVAL; continue;
} }
if (s->reply.handle == handle) {
/* We are done */ /*
return 0; * We're woken up again by the request itself. Note that there
} * is no race between yielding and reentering connection_co. This
ind2 = HANDLE_TO_INDEX(s, s->reply.handle); * is because:
if (ind2 >= MAX_NBD_REQUESTS || !s->requests[ind2].reply_possible) { *
nbd_channel_error(s, -EINVAL); * - if the request runs on the same AioContext, it is only
return -EINVAL; * entered after we yield
} *
nbd_recv_coroutine_wake_one(&s->requests[ind2]); * - if the request runs on a different AioContext, reentering
* connection_co happens through a bottom half, which can only
* run after we yield.
*/
s->requests[i].receiving = false;
aio_co_wake(s->requests[i].coroutine);
qemu_coroutine_yield();
} }
qemu_co_queue_restart_all(&s->free_sema);
nbd_recv_coroutines_wake_all(s);
bdrv_dec_in_flight(s->bs);
s->connection_co = NULL;
if (s->ioc) {
qio_channel_detach_aio_context(QIO_CHANNEL(s->ioc));
yank_unregister_function(BLOCKDEV_YANK_INSTANCE(s->bs->node_name),
nbd_yank, s->bs);
object_unref(OBJECT(s->ioc));
s->ioc = NULL;
}
if (s->teardown_co) {
aio_co_wake(s->teardown_co);
}
aio_wait_kick();
} }
static int nbd_co_send_request(BlockDriverState *bs, static int nbd_co_send_request(BlockDriverState *bs,
@ -432,17 +583,10 @@ static int nbd_co_send_request(BlockDriverState *bs,
int rc, i = -1; int rc, i = -1;
qemu_co_mutex_lock(&s->send_mutex); qemu_co_mutex_lock(&s->send_mutex);
while (s->in_flight == MAX_NBD_REQUESTS || nbd_client_connecting_wait(s)) {
while (s->in_flight == MAX_NBD_REQUESTS ||
(!nbd_client_connected(s) && s->in_flight > 0))
{
qemu_co_queue_wait(&s->free_sema, &s->send_mutex); qemu_co_queue_wait(&s->free_sema, &s->send_mutex);
} }
if (nbd_client_connecting(s)) {
nbd_reconnect_attempt(s);
}
if (!nbd_client_connected(s)) { if (!nbd_client_connected(s)) {
rc = -EIO; rc = -EIO;
goto err; goto err;
@ -462,7 +606,6 @@ static int nbd_co_send_request(BlockDriverState *bs,
s->requests[i].coroutine = qemu_coroutine_self(); s->requests[i].coroutine = qemu_coroutine_self();
s->requests[i].offset = request->from; s->requests[i].offset = request->from;
s->requests[i].receiving = false; s->requests[i].receiving = false;
s->requests[i].reply_possible = true;
request->handle = INDEX_TO_HANDLE(s, i); request->handle = INDEX_TO_HANDLE(s, i);
@ -490,6 +633,10 @@ err:
if (i != -1) { if (i != -1) {
s->requests[i].coroutine = NULL; s->requests[i].coroutine = NULL;
s->in_flight--; s->in_flight--;
}
if (s->in_flight == 0 && s->wait_in_flight) {
aio_co_wake(s->connection_co);
} else {
qemu_co_queue_next(&s->free_sema); qemu_co_queue_next(&s->free_sema);
} }
} }
@ -788,7 +935,10 @@ static coroutine_fn int nbd_co_do_receive_one_chunk(
} }
*request_ret = 0; *request_ret = 0;
nbd_receive_replies(s, handle); /* Wait until we're woken up by nbd_connection_entry. */
s->requests[i].receiving = true;
qemu_coroutine_yield();
assert(!s->requests[i].receiving);
if (!nbd_client_connected(s)) { if (!nbd_client_connected(s)) {
error_setg(errp, "Connection closed"); error_setg(errp, "Connection closed");
return -EIO; return -EIO;
@ -881,7 +1031,14 @@ static coroutine_fn int nbd_co_receive_one_chunk(
} }
s->reply.handle = 0; s->reply.handle = 0;
nbd_recv_coroutines_wake(s, false); if (s->connection_co && !s->wait_in_flight) {
/*
* We must check s->wait_in_flight, because we may entered by
* nbd_recv_coroutines_wake_all(), in this case we should not
* wake connection_co here, it will woken by last request.
*/
aio_co_wake(s->connection_co);
}
return ret; return ret;
} }
@ -992,7 +1149,11 @@ break_loop:
qemu_co_mutex_lock(&s->send_mutex); qemu_co_mutex_lock(&s->send_mutex);
s->in_flight--; s->in_flight--;
qemu_co_queue_next(&s->free_sema); if (s->in_flight == 0 && s->wait_in_flight) {
aio_co_wake(s->connection_co);
} else {
qemu_co_queue_next(&s->free_sema);
}
qemu_co_mutex_unlock(&s->send_mutex); qemu_co_mutex_unlock(&s->send_mutex);
return false; return false;
@ -1161,9 +1322,8 @@ static int nbd_co_request(BlockDriverState *bs, NBDRequest *request,
return ret ? ret : request_ret; return ret ? ret : request_ret;
} }
static int nbd_client_co_preadv(BlockDriverState *bs, int64_t offset, static int nbd_client_co_preadv(BlockDriverState *bs, uint64_t offset,
int64_t bytes, QEMUIOVector *qiov, uint64_t bytes, QEMUIOVector *qiov, int flags)
BdrvRequestFlags flags)
{ {
int ret, request_ret; int ret, request_ret;
Error *local_err = NULL; Error *local_err = NULL;
@ -1220,9 +1380,8 @@ static int nbd_client_co_preadv(BlockDriverState *bs, int64_t offset,
return ret ? ret : request_ret; return ret ? ret : request_ret;
} }
static int nbd_client_co_pwritev(BlockDriverState *bs, int64_t offset, static int nbd_client_co_pwritev(BlockDriverState *bs, uint64_t offset,
int64_t bytes, QEMUIOVector *qiov, uint64_t bytes, QEMUIOVector *qiov, int flags)
BdrvRequestFlags flags)
{ {
BDRVNBDState *s = (BDRVNBDState *)bs->opaque; BDRVNBDState *s = (BDRVNBDState *)bs->opaque;
NBDRequest request = { NBDRequest request = {
@ -1246,17 +1405,15 @@ static int nbd_client_co_pwritev(BlockDriverState *bs, int64_t offset,
} }
static int nbd_client_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, static int nbd_client_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
int64_t bytes, BdrvRequestFlags flags) int bytes, BdrvRequestFlags flags)
{ {
BDRVNBDState *s = (BDRVNBDState *)bs->opaque; BDRVNBDState *s = (BDRVNBDState *)bs->opaque;
NBDRequest request = { NBDRequest request = {
.type = NBD_CMD_WRITE_ZEROES, .type = NBD_CMD_WRITE_ZEROES,
.from = offset, .from = offset,
.len = bytes, /* .len is uint32_t actually */ .len = bytes,
}; };
assert(bytes <= UINT32_MAX); /* rely on max_pwrite_zeroes */
assert(!(s->info.flags & NBD_FLAG_READ_ONLY)); assert(!(s->info.flags & NBD_FLAG_READ_ONLY));
if (!(s->info.flags & NBD_FLAG_SEND_WRITE_ZEROES)) { if (!(s->info.flags & NBD_FLAG_SEND_WRITE_ZEROES)) {
return -ENOTSUP; return -ENOTSUP;
@ -1296,17 +1453,15 @@ static int nbd_client_co_flush(BlockDriverState *bs)
} }
static int nbd_client_co_pdiscard(BlockDriverState *bs, int64_t offset, static int nbd_client_co_pdiscard(BlockDriverState *bs, int64_t offset,
int64_t bytes) int bytes)
{ {
BDRVNBDState *s = (BDRVNBDState *)bs->opaque; BDRVNBDState *s = (BDRVNBDState *)bs->opaque;
NBDRequest request = { NBDRequest request = {
.type = NBD_CMD_TRIM, .type = NBD_CMD_TRIM,
.from = offset, .from = offset,
.len = bytes, /* len is uint32_t */ .len = bytes,
}; };
assert(bytes <= UINT32_MAX); /* rely on max_pdiscard */
assert(!(s->info.flags & NBD_FLAG_READ_ONLY)); assert(!(s->info.flags & NBD_FLAG_READ_ONLY));
if (!(s->info.flags & NBD_FLAG_SEND_TRIM) || !bytes) { if (!(s->info.flags & NBD_FLAG_SEND_TRIM) || !bytes) {
return 0; return 0;
@ -1814,7 +1969,6 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags,
s->bs = bs; s->bs = bs;
qemu_co_mutex_init(&s->send_mutex); qemu_co_mutex_init(&s->send_mutex);
qemu_co_queue_init(&s->free_sema); qemu_co_queue_init(&s->free_sema);
qemu_co_mutex_init(&s->receive_mutex);
if (!yank_register_instance(BLOCKDEV_YANK_INSTANCE(bs->node_name), errp)) { if (!yank_register_instance(BLOCKDEV_YANK_INSTANCE(bs->node_name), errp)) {
return -EEXIST; return -EEXIST;
@ -1829,13 +1983,14 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags,
s->x_dirty_bitmap, s->tlscreds); s->x_dirty_bitmap, s->tlscreds);
/* TODO: Configurable retry-until-timeout behaviour. */ /* TODO: Configurable retry-until-timeout behaviour. */
s->state = NBD_CLIENT_CONNECTING_WAIT;
ret = nbd_do_establish_connection(bs, errp); ret = nbd_do_establish_connection(bs, errp);
if (ret < 0) { if (ret < 0) {
goto fail; goto fail;
} }
nbd_client_connection_enable_retry(s->conn); s->connection_co = qemu_coroutine_create(nbd_connection_entry, s);
bdrv_inc_in_flight(bs);
aio_co_schedule(bdrv_get_aio_context(bs), s->connection_co);
return 0; return 0;
@ -1989,8 +2144,6 @@ static void nbd_cancel_in_flight(BlockDriverState *bs)
s->state = NBD_CLIENT_CONNECTING_NOWAIT; s->state = NBD_CLIENT_CONNECTING_NOWAIT;
qemu_co_queue_restart_all(&s->free_sema); qemu_co_queue_restart_all(&s->free_sema);
} }
nbd_co_establish_connection_cancel(s->conn);
} }
static BlockDriver bdrv_nbd = { static BlockDriver bdrv_nbd = {
@ -2011,6 +2164,10 @@ static BlockDriver bdrv_nbd = {
.bdrv_refresh_limits = nbd_refresh_limits, .bdrv_refresh_limits = nbd_refresh_limits,
.bdrv_co_truncate = nbd_co_truncate, .bdrv_co_truncate = nbd_co_truncate,
.bdrv_getlength = nbd_getlength, .bdrv_getlength = nbd_getlength,
.bdrv_detach_aio_context = nbd_client_detach_aio_context,
.bdrv_attach_aio_context = nbd_client_attach_aio_context,
.bdrv_co_drain_begin = nbd_client_co_drain_begin,
.bdrv_co_drain_end = nbd_client_co_drain_end,
.bdrv_refresh_filename = nbd_refresh_filename, .bdrv_refresh_filename = nbd_refresh_filename,
.bdrv_co_block_status = nbd_client_co_block_status, .bdrv_co_block_status = nbd_client_co_block_status,
.bdrv_dirname = nbd_dirname, .bdrv_dirname = nbd_dirname,
@ -2036,6 +2193,10 @@ static BlockDriver bdrv_nbd_tcp = {
.bdrv_refresh_limits = nbd_refresh_limits, .bdrv_refresh_limits = nbd_refresh_limits,
.bdrv_co_truncate = nbd_co_truncate, .bdrv_co_truncate = nbd_co_truncate,
.bdrv_getlength = nbd_getlength, .bdrv_getlength = nbd_getlength,
.bdrv_detach_aio_context = nbd_client_detach_aio_context,
.bdrv_attach_aio_context = nbd_client_attach_aio_context,
.bdrv_co_drain_begin = nbd_client_co_drain_begin,
.bdrv_co_drain_end = nbd_client_co_drain_end,
.bdrv_refresh_filename = nbd_refresh_filename, .bdrv_refresh_filename = nbd_refresh_filename,
.bdrv_co_block_status = nbd_client_co_block_status, .bdrv_co_block_status = nbd_client_co_block_status,
.bdrv_dirname = nbd_dirname, .bdrv_dirname = nbd_dirname,
@ -2061,6 +2222,10 @@ static BlockDriver bdrv_nbd_unix = {
.bdrv_refresh_limits = nbd_refresh_limits, .bdrv_refresh_limits = nbd_refresh_limits,
.bdrv_co_truncate = nbd_co_truncate, .bdrv_co_truncate = nbd_co_truncate,
.bdrv_getlength = nbd_getlength, .bdrv_getlength = nbd_getlength,
.bdrv_detach_aio_context = nbd_client_detach_aio_context,
.bdrv_attach_aio_context = nbd_client_attach_aio_context,
.bdrv_co_drain_begin = nbd_client_co_drain_begin,
.bdrv_co_drain_end = nbd_client_co_drain_end,
.bdrv_refresh_filename = nbd_refresh_filename, .bdrv_refresh_filename = nbd_refresh_filename,
.bdrv_co_block_status = nbd_client_co_block_status, .bdrv_co_block_status = nbd_client_co_block_status,
.bdrv_dirname = nbd_dirname, .bdrv_dirname = nbd_dirname,

View File

@ -262,9 +262,9 @@ nfs_co_generic_cb(int ret, struct nfs_context *nfs, void *data,
nfs_co_generic_bh_cb, task); nfs_co_generic_bh_cb, task);
} }
static int coroutine_fn nfs_co_preadv(BlockDriverState *bs, int64_t offset, static int coroutine_fn nfs_co_preadv(BlockDriverState *bs, uint64_t offset,
int64_t bytes, QEMUIOVector *iov, uint64_t bytes, QEMUIOVector *iov,
BdrvRequestFlags flags) int flags)
{ {
NFSClient *client = bs->opaque; NFSClient *client = bs->opaque;
NFSRPC task; NFSRPC task;
@ -296,9 +296,9 @@ static int coroutine_fn nfs_co_preadv(BlockDriverState *bs, int64_t offset,
return 0; return 0;
} }
static int coroutine_fn nfs_co_pwritev(BlockDriverState *bs, int64_t offset, static int coroutine_fn nfs_co_pwritev(BlockDriverState *bs, uint64_t offset,
int64_t bytes, QEMUIOVector *iov, uint64_t bytes, QEMUIOVector *iov,
BdrvRequestFlags flags) int flags)
{ {
NFSClient *client = bs->opaque; NFSClient *client = bs->opaque;
NFSRPC task; NFSRPC task;

View File

@ -116,9 +116,8 @@ static coroutine_fn int null_co_common(BlockDriverState *bs)
} }
static coroutine_fn int null_co_preadv(BlockDriverState *bs, static coroutine_fn int null_co_preadv(BlockDriverState *bs,
int64_t offset, int64_t bytes, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, QEMUIOVector *qiov, int flags)
BdrvRequestFlags flags)
{ {
BDRVNullState *s = bs->opaque; BDRVNullState *s = bs->opaque;
@ -130,9 +129,8 @@ static coroutine_fn int null_co_preadv(BlockDriverState *bs,
} }
static coroutine_fn int null_co_pwritev(BlockDriverState *bs, static coroutine_fn int null_co_pwritev(BlockDriverState *bs,
int64_t offset, int64_t bytes, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, QEMUIOVector *qiov, int flags)
BdrvRequestFlags flags)
{ {
return null_co_common(bs); return null_co_common(bs);
} }
@ -189,8 +187,8 @@ static inline BlockAIOCB *null_aio_common(BlockDriverState *bs,
} }
static BlockAIOCB *null_aio_preadv(BlockDriverState *bs, static BlockAIOCB *null_aio_preadv(BlockDriverState *bs,
int64_t offset, int64_t bytes, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, BdrvRequestFlags flags, QEMUIOVector *qiov, int flags,
BlockCompletionFunc *cb, BlockCompletionFunc *cb,
void *opaque) void *opaque)
{ {
@ -204,8 +202,8 @@ static BlockAIOCB *null_aio_preadv(BlockDriverState *bs,
} }
static BlockAIOCB *null_aio_pwritev(BlockDriverState *bs, static BlockAIOCB *null_aio_pwritev(BlockDriverState *bs,
int64_t offset, int64_t bytes, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, BdrvRequestFlags flags, QEMUIOVector *qiov, int flags,
BlockCompletionFunc *cb, BlockCompletionFunc *cb,
void *opaque) void *opaque)
{ {

View File

@ -176,27 +176,23 @@ static bool nvme_init_queue(BDRVNVMeState *s, NVMeQueue *q,
return false; return false;
} }
memset(q->queue, 0, bytes); memset(q->queue, 0, bytes);
r = qemu_vfio_dma_map(s->vfio, q->queue, bytes, false, &q->iova, errp); r = qemu_vfio_dma_map(s->vfio, q->queue, bytes, false, &q->iova);
if (r) { if (r) {
error_prepend(errp, "Cannot map queue: "); error_setg(errp, "Cannot map queue");
return false;
} }
return r == 0; return true;
}
static void nvme_free_queue(NVMeQueue *q)
{
qemu_vfree(q->queue);
} }
static void nvme_free_queue_pair(NVMeQueuePair *q) static void nvme_free_queue_pair(NVMeQueuePair *q)
{ {
trace_nvme_free_queue_pair(q->index, q, &q->cq, &q->sq); trace_nvme_free_queue_pair(q->index, q);
if (q->completion_bh) { if (q->completion_bh) {
qemu_bh_delete(q->completion_bh); qemu_bh_delete(q->completion_bh);
} }
nvme_free_queue(&q->sq);
nvme_free_queue(&q->cq);
qemu_vfree(q->prp_list_pages); qemu_vfree(q->prp_list_pages);
qemu_vfree(q->sq.queue);
qemu_vfree(q->cq.queue);
qemu_mutex_destroy(&q->lock); qemu_mutex_destroy(&q->lock);
g_free(q); g_free(q);
} }
@ -224,7 +220,6 @@ static NVMeQueuePair *nvme_create_queue_pair(BDRVNVMeState *s,
q = g_try_new0(NVMeQueuePair, 1); q = g_try_new0(NVMeQueuePair, 1);
if (!q) { if (!q) {
error_setg(errp, "Cannot allocate queue pair");
return NULL; return NULL;
} }
trace_nvme_create_queue_pair(idx, q, size, aio_context, trace_nvme_create_queue_pair(idx, q, size, aio_context,
@ -233,7 +228,6 @@ static NVMeQueuePair *nvme_create_queue_pair(BDRVNVMeState *s,
qemu_real_host_page_size); qemu_real_host_page_size);
q->prp_list_pages = qemu_try_memalign(qemu_real_host_page_size, bytes); q->prp_list_pages = qemu_try_memalign(qemu_real_host_page_size, bytes);
if (!q->prp_list_pages) { if (!q->prp_list_pages) {
error_setg(errp, "Cannot allocate PRP page list");
goto fail; goto fail;
} }
memset(q->prp_list_pages, 0, bytes); memset(q->prp_list_pages, 0, bytes);
@ -243,9 +237,8 @@ static NVMeQueuePair *nvme_create_queue_pair(BDRVNVMeState *s,
qemu_co_queue_init(&q->free_req_queue); qemu_co_queue_init(&q->free_req_queue);
q->completion_bh = aio_bh_new(aio_context, nvme_process_completion_bh, q); q->completion_bh = aio_bh_new(aio_context, nvme_process_completion_bh, q);
r = qemu_vfio_dma_map(s->vfio, q->prp_list_pages, bytes, r = qemu_vfio_dma_map(s->vfio, q->prp_list_pages, bytes,
false, &prp_list_iova, errp); false, &prp_list_iova);
if (r) { if (r) {
error_prepend(errp, "Cannot map buffer for DMA: ");
goto fail; goto fail;
} }
q->free_req_head = -1; q->free_req_head = -1;
@ -519,10 +512,10 @@ static bool nvme_identify(BlockDriverState *bs, int namespace, Error **errp)
{ {
BDRVNVMeState *s = bs->opaque; BDRVNVMeState *s = bs->opaque;
bool ret = false; bool ret = false;
QEMU_AUTO_VFREE union { union {
NvmeIdCtrl ctrl; NvmeIdCtrl ctrl;
NvmeIdNs ns; NvmeIdNs ns;
} *id = NULL; } *id;
NvmeLBAF *lbaf; NvmeLBAF *lbaf;
uint16_t oncs; uint16_t oncs;
int r; int r;
@ -538,9 +531,9 @@ static bool nvme_identify(BlockDriverState *bs, int namespace, Error **errp)
error_setg(errp, "Cannot allocate buffer for identify response"); error_setg(errp, "Cannot allocate buffer for identify response");
goto out; goto out;
} }
r = qemu_vfio_dma_map(s->vfio, id, id_size, true, &iova, errp); r = qemu_vfio_dma_map(s->vfio, id, id_size, true, &iova);
if (r) { if (r) {
error_prepend(errp, "Cannot map buffer for DMA: "); error_setg(errp, "Cannot map buffer for DMA");
goto out; goto out;
} }
@ -600,6 +593,7 @@ static bool nvme_identify(BlockDriverState *bs, int namespace, Error **errp)
s->blkshift = lbaf->ds; s->blkshift = lbaf->ds;
out: out:
qemu_vfio_dma_unmap(s->vfio, id); qemu_vfio_dma_unmap(s->vfio, id);
qemu_vfree(id);
return ret; return ret;
} }
@ -1023,7 +1017,6 @@ static coroutine_fn int nvme_cmd_map_qiov(BlockDriverState *bs, NvmeCmd *cmd,
uint64_t *pagelist = req->prp_list_page; uint64_t *pagelist = req->prp_list_page;
int i, j, r; int i, j, r;
int entries = 0; int entries = 0;
Error *local_err = NULL, **errp = NULL;
assert(qiov->size); assert(qiov->size);
assert(QEMU_IS_ALIGNED(qiov->size, s->page_size)); assert(QEMU_IS_ALIGNED(qiov->size, s->page_size));
@ -1036,7 +1029,7 @@ static coroutine_fn int nvme_cmd_map_qiov(BlockDriverState *bs, NvmeCmd *cmd,
try_map: try_map:
r = qemu_vfio_dma_map(s->vfio, r = qemu_vfio_dma_map(s->vfio,
qiov->iov[i].iov_base, qiov->iov[i].iov_base,
len, true, &iova, errp); len, true, &iova);
if (r == -ENOSPC) { if (r == -ENOSPC) {
/* /*
* In addition to the -ENOMEM error, the VFIO_IOMMU_MAP_DMA * In addition to the -ENOMEM error, the VFIO_IOMMU_MAP_DMA
@ -1071,8 +1064,6 @@ try_map:
goto fail; goto fail;
} }
} }
errp = &local_err;
goto try_map; goto try_map;
} }
if (r) { if (r) {
@ -1116,9 +1107,6 @@ fail:
* because they are already mapped before calling this function; for * because they are already mapped before calling this function; for
* temporary mappings, a later nvme_cmd_(un)map_qiov will reclaim by * temporary mappings, a later nvme_cmd_(un)map_qiov will reclaim by
* calling qemu_vfio_dma_reset_temporary when necessary. */ * calling qemu_vfio_dma_reset_temporary when necessary. */
if (local_err) {
error_reportf_err(local_err, "Cannot map buffer for DMA: ");
}
return r; return r;
} }
@ -1223,7 +1211,7 @@ static int nvme_co_prw(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
{ {
BDRVNVMeState *s = bs->opaque; BDRVNVMeState *s = bs->opaque;
int r; int r;
QEMU_AUTO_VFREE uint8_t *buf = NULL; uint8_t *buf = NULL;
QEMUIOVector local_qiov; QEMUIOVector local_qiov;
size_t len = QEMU_ALIGN_UP(bytes, qemu_real_host_page_size); size_t len = QEMU_ALIGN_UP(bytes, qemu_real_host_page_size);
assert(QEMU_IS_ALIGNED(offset, s->page_size)); assert(QEMU_IS_ALIGNED(offset, s->page_size));
@ -1250,21 +1238,20 @@ static int nvme_co_prw(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
if (!r && !is_write) { if (!r && !is_write) {
qemu_iovec_from_buf(qiov, 0, buf, bytes); qemu_iovec_from_buf(qiov, 0, buf, bytes);
} }
qemu_vfree(buf);
return r; return r;
} }
static coroutine_fn int nvme_co_preadv(BlockDriverState *bs, static coroutine_fn int nvme_co_preadv(BlockDriverState *bs,
int64_t offset, int64_t bytes, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, QEMUIOVector *qiov, int flags)
BdrvRequestFlags flags)
{ {
return nvme_co_prw(bs, offset, bytes, qiov, false, flags); return nvme_co_prw(bs, offset, bytes, qiov, false, flags);
} }
static coroutine_fn int nvme_co_pwritev(BlockDriverState *bs, static coroutine_fn int nvme_co_pwritev(BlockDriverState *bs,
int64_t offset, int64_t bytes, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, QEMUIOVector *qiov, int flags)
BdrvRequestFlags flags)
{ {
return nvme_co_prw(bs, offset, bytes, qiov, true, flags); return nvme_co_prw(bs, offset, bytes, qiov, true, flags);
} }
@ -1299,29 +1286,19 @@ static coroutine_fn int nvme_co_flush(BlockDriverState *bs)
static coroutine_fn int nvme_co_pwrite_zeroes(BlockDriverState *bs, static coroutine_fn int nvme_co_pwrite_zeroes(BlockDriverState *bs,
int64_t offset, int64_t offset,
int64_t bytes, int bytes,
BdrvRequestFlags flags) BdrvRequestFlags flags)
{ {
BDRVNVMeState *s = bs->opaque; BDRVNVMeState *s = bs->opaque;
NVMeQueuePair *ioq = s->queues[INDEX_IO(0)]; NVMeQueuePair *ioq = s->queues[INDEX_IO(0)];
NVMeRequest *req; NVMeRequest *req;
uint32_t cdw12;
uint32_t cdw12 = ((bytes >> s->blkshift) - 1) & 0xFFFF;
if (!s->supports_write_zeroes) { if (!s->supports_write_zeroes) {
return -ENOTSUP; return -ENOTSUP;
} }
if (bytes == 0) {
return 0;
}
cdw12 = ((bytes >> s->blkshift) - 1) & 0xFFFF;
/*
* We should not lose information. pwrite_zeroes_alignment and
* max_pwrite_zeroes guarantees it.
*/
assert(((cdw12 + 1) << s->blkshift) == bytes);
NvmeCmd cmd = { NvmeCmd cmd = {
.opcode = NVME_CMD_WRITE_ZEROES, .opcode = NVME_CMD_WRITE_ZEROES,
.nsid = cpu_to_le32(s->nsid), .nsid = cpu_to_le32(s->nsid),
@ -1363,12 +1340,12 @@ static coroutine_fn int nvme_co_pwrite_zeroes(BlockDriverState *bs,
static int coroutine_fn nvme_co_pdiscard(BlockDriverState *bs, static int coroutine_fn nvme_co_pdiscard(BlockDriverState *bs,
int64_t offset, int64_t offset,
int64_t bytes) int bytes)
{ {
BDRVNVMeState *s = bs->opaque; BDRVNVMeState *s = bs->opaque;
NVMeQueuePair *ioq = s->queues[INDEX_IO(0)]; NVMeQueuePair *ioq = s->queues[INDEX_IO(0)];
NVMeRequest *req; NVMeRequest *req;
QEMU_AUTO_VFREE NvmeDsmRange *buf = NULL; NvmeDsmRange *buf;
QEMUIOVector local_qiov; QEMUIOVector local_qiov;
int ret; int ret;
@ -1390,14 +1367,6 @@ static int coroutine_fn nvme_co_pdiscard(BlockDriverState *bs,
assert(s->queue_count > 1); assert(s->queue_count > 1);
/*
* Filling the @buf requires @offset and @bytes to satisfy restrictions
* defined in nvme_refresh_limits().
*/
assert(QEMU_IS_ALIGNED(bytes, 1UL << s->blkshift));
assert(QEMU_IS_ALIGNED(offset, 1UL << s->blkshift));
assert((bytes >> s->blkshift) <= UINT32_MAX);
buf = qemu_try_memalign(s->page_size, s->page_size); buf = qemu_try_memalign(s->page_size, s->page_size);
if (!buf) { if (!buf) {
return -ENOMEM; return -ENOMEM;
@ -1443,6 +1412,7 @@ static int coroutine_fn nvme_co_pdiscard(BlockDriverState *bs,
trace_nvme_dsm_done(s, offset, bytes, ret); trace_nvme_dsm_done(s, offset, bytes, ret);
out: out:
qemu_iovec_destroy(&local_qiov); qemu_iovec_destroy(&local_qiov);
qemu_vfree(buf);
return ret; return ret;
} }
@ -1492,18 +1462,6 @@ static void nvme_refresh_limits(BlockDriverState *bs, Error **errp)
bs->bl.opt_mem_alignment = s->page_size; bs->bl.opt_mem_alignment = s->page_size;
bs->bl.request_alignment = s->page_size; bs->bl.request_alignment = s->page_size;
bs->bl.max_transfer = s->max_transfer; bs->bl.max_transfer = s->max_transfer;
/*
* Look at nvme_co_pwrite_zeroes: after shift and decrement we should get
* at most 0xFFFF
*/
bs->bl.max_pwrite_zeroes = 1ULL << (s->blkshift + 16);
bs->bl.pwrite_zeroes_alignment = MAX(bs->bl.request_alignment,
1UL << s->blkshift);
bs->bl.max_pdiscard = (uint64_t)UINT32_MAX << s->blkshift;
bs->bl.pdiscard_alignment = MAX(bs->bl.request_alignment,
1UL << s->blkshift);
} }
static void nvme_detach_aio_context(BlockDriverState *bs) static void nvme_detach_aio_context(BlockDriverState *bs)
@ -1563,15 +1521,14 @@ static void nvme_aio_unplug(BlockDriverState *bs)
static void nvme_register_buf(BlockDriverState *bs, void *host, size_t size) static void nvme_register_buf(BlockDriverState *bs, void *host, size_t size)
{ {
int ret; int ret;
Error *local_err = NULL;
BDRVNVMeState *s = bs->opaque; BDRVNVMeState *s = bs->opaque;
ret = qemu_vfio_dma_map(s->vfio, host, size, false, NULL, &local_err); ret = qemu_vfio_dma_map(s->vfio, host, size, false, NULL);
if (ret) { if (ret) {
/* FIXME: we may run out of IOVA addresses after repeated /* FIXME: we may run out of IOVA addresses after repeated
* bdrv_register_buf/bdrv_unregister_buf, because nvme_vfio_dma_unmap * bdrv_register_buf/bdrv_unregister_buf, because nvme_vfio_dma_unmap
* doesn't reclaim addresses for fixed mappings. */ * doesn't reclaim addresses for fixed mappings. */
error_reportf_err(local_err, "nvme_register_buf failed: "); error_report("nvme_register_buf failed: %s", strerror(-ret));
} }
} }

View File

@ -227,15 +227,15 @@ static void preallocate_reopen_abort(BDRVReopenState *state)
} }
static coroutine_fn int preallocate_co_preadv_part( static coroutine_fn int preallocate_co_preadv_part(
BlockDriverState *bs, int64_t offset, int64_t bytes, BlockDriverState *bs, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, size_t qiov_offset, BdrvRequestFlags flags) QEMUIOVector *qiov, size_t qiov_offset, int flags)
{ {
return bdrv_co_preadv_part(bs->file, offset, bytes, qiov, qiov_offset, return bdrv_co_preadv_part(bs->file, offset, bytes, qiov, qiov_offset,
flags); flags);
} }
static int coroutine_fn preallocate_co_pdiscard(BlockDriverState *bs, static int coroutine_fn preallocate_co_pdiscard(BlockDriverState *bs,
int64_t offset, int64_t bytes) int64_t offset, int bytes)
{ {
return bdrv_co_pdiscard(bs->file, offset, bytes); return bdrv_co_pdiscard(bs->file, offset, bytes);
} }
@ -337,7 +337,7 @@ static bool coroutine_fn handle_write(BlockDriverState *bs, int64_t offset,
} }
static int coroutine_fn preallocate_co_pwrite_zeroes(BlockDriverState *bs, static int coroutine_fn preallocate_co_pwrite_zeroes(BlockDriverState *bs,
int64_t offset, int64_t bytes, BdrvRequestFlags flags) int64_t offset, int bytes, BdrvRequestFlags flags)
{ {
bool want_merge_zero = bool want_merge_zero =
!(flags & ~(BDRV_REQ_ZERO_WRITE | BDRV_REQ_NO_FALLBACK)); !(flags & ~(BDRV_REQ_ZERO_WRITE | BDRV_REQ_NO_FALLBACK));
@ -349,11 +349,11 @@ static int coroutine_fn preallocate_co_pwrite_zeroes(BlockDriverState *bs,
} }
static coroutine_fn int preallocate_co_pwritev_part(BlockDriverState *bs, static coroutine_fn int preallocate_co_pwritev_part(BlockDriverState *bs,
int64_t offset, uint64_t offset,
int64_t bytes, uint64_t bytes,
QEMUIOVector *qiov, QEMUIOVector *qiov,
size_t qiov_offset, size_t qiov_offset,
BdrvRequestFlags flags) int flags)
{ {
handle_write(bs, offset, bytes, false); handle_write(bs, offset, bytes, false);

View File

@ -617,9 +617,9 @@ static void qcow_refresh_limits(BlockDriverState *bs, Error **errp)
bs->bl.request_alignment = BDRV_SECTOR_SIZE; bs->bl.request_alignment = BDRV_SECTOR_SIZE;
} }
static coroutine_fn int qcow_co_preadv(BlockDriverState *bs, int64_t offset, static coroutine_fn int qcow_co_preadv(BlockDriverState *bs, uint64_t offset,
int64_t bytes, QEMUIOVector *qiov, uint64_t bytes, QEMUIOVector *qiov,
BdrvRequestFlags flags) int flags)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcowState *s = bs->opaque;
int offset_in_cluster; int offset_in_cluster;
@ -714,9 +714,9 @@ static coroutine_fn int qcow_co_preadv(BlockDriverState *bs, int64_t offset,
return ret; return ret;
} }
static coroutine_fn int qcow_co_pwritev(BlockDriverState *bs, int64_t offset, static coroutine_fn int qcow_co_pwritev(BlockDriverState *bs, uint64_t offset,
int64_t bytes, QEMUIOVector *qiov, uint64_t bytes, QEMUIOVector *qiov,
BdrvRequestFlags flags) int flags)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcowState *s = bs->opaque;
int offset_in_cluster; int offset_in_cluster;
@ -1047,8 +1047,8 @@ static int qcow_make_empty(BlockDriverState *bs)
/* XXX: put compressed sectors first, then all the cluster aligned /* XXX: put compressed sectors first, then all the cluster aligned
tables to avoid losing bytes in alignment */ tables to avoid losing bytes in alignment */
static coroutine_fn int static coroutine_fn int
qcow_co_pwritev_compressed(BlockDriverState *bs, int64_t offset, int64_t bytes, qcow_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
QEMUIOVector *qiov) uint64_t bytes, QEMUIOVector *qiov)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcowState *s = bs->opaque;
z_stream strm; z_stream strm;

View File

@ -505,20 +505,7 @@ static int coroutine_fn do_perform_cow_read(BlockDriverState *bs,
return -ENOMEDIUM; return -ENOMEDIUM;
} }
/* /* Call .bdrv_co_readv() directly instead of using the public block-layer
* We never deal with requests that don't satisfy
* bdrv_check_qiov_request(), and aligning requests to clusters never
* breaks this condition. So, do some assertions before calling
* bs->drv->bdrv_co_preadv_part() which has int64_t arguments.
*/
assert(src_cluster_offset <= INT64_MAX);
assert(src_cluster_offset + offset_in_cluster <= INT64_MAX);
/* Cast qiov->size to uint64_t to silence a compiler warning on -m32 */
assert((uint64_t)qiov->size <= INT64_MAX);
bdrv_check_qiov_request(src_cluster_offset + offset_in_cluster, qiov->size,
qiov, 0, &error_abort);
/*
* Call .bdrv_co_readv() directly instead of using the public block-layer
* interface. This avoids double I/O throttling and request tracking, * interface. This avoids double I/O throttling and request tracking,
* which can lead to deadlock when block layer copy-on-read is enabled. * which can lead to deadlock when block layer copy-on-read is enabled.
*/ */
@ -569,7 +556,8 @@ static int coroutine_fn do_perform_cow_write(BlockDriverState *bs,
* offset needs to be aligned to a cluster boundary. * offset needs to be aligned to a cluster boundary.
* *
* If the cluster is unallocated then *host_offset will be 0. * If the cluster is unallocated then *host_offset will be 0.
* If the cluster is compressed then *host_offset will contain the l2 entry. * If the cluster is compressed then *host_offset will contain the
* complete compressed cluster descriptor.
* *
* On entry, *bytes is the maximum number of contiguous bytes starting at * On entry, *bytes is the maximum number of contiguous bytes starting at
* offset that we are interested in. * offset that we are interested in.
@ -672,7 +660,7 @@ int qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset,
ret = -EIO; ret = -EIO;
goto fail; goto fail;
} }
*host_offset = l2_entry; *host_offset = l2_entry & L2E_COMPRESSED_OFFSET_SIZE_MASK;
break; break;
case QCOW2_SUBCLUSTER_ZERO_PLAIN: case QCOW2_SUBCLUSTER_ZERO_PLAIN:
case QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN: case QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN:
@ -1412,47 +1400,29 @@ static int handle_dependencies(BlockDriverState *bs, uint64_t guest_offset,
if (end <= old_start || start >= old_end) { if (end <= old_start || start >= old_end) {
/* No intersection */ /* No intersection */
continue;
}
if (old_alloc->keep_old_clusters &&
(end <= l2meta_cow_start(old_alloc) ||
start >= l2meta_cow_end(old_alloc)))
{
/*
* Clusters intersect but COW areas don't. And cluster itself is
* already allocated. So, there is no actual conflict.
*/
continue;
}
/* Conflict */
if (start < old_start) {
/* Stop at the start of a running allocation */
bytes = old_start - start;
} else { } else {
bytes = 0; if (start < old_start) {
} /* Stop at the start of a running allocation */
bytes = old_start - start;
} else {
bytes = 0;
}
/* /* Stop if already an l2meta exists. After yielding, it wouldn't
* Stop if an l2meta already exists. After yielding, it wouldn't * be valid any more, so we'd have to clean up the old L2Metas
* be valid any more, so we'd have to clean up the old L2Metas * and deal with requests depending on them before starting to
* and deal with requests depending on them before starting to * gather new ones. Not worth the trouble. */
* gather new ones. Not worth the trouble. if (bytes == 0 && *m) {
*/ *cur_bytes = 0;
if (bytes == 0 && *m) { return 0;
*cur_bytes = 0; }
return 0;
}
if (bytes == 0) { if (bytes == 0) {
/* /* Wait for the dependency to complete. We need to recheck
* Wait for the dependency to complete. We need to recheck * the free/allocated clusters when we continue. */
* the free/allocated clusters when we continue. qemu_co_queue_wait(&old_alloc->dependent_requests, &s->lock);
*/ return -EAGAIN;
qemu_co_queue_wait(&old_alloc->dependent_requests, &s->lock); }
return -EAGAIN;
} }
} }
@ -2493,18 +2463,3 @@ fail:
g_free(l1_table); g_free(l1_table);
return ret; return ret;
} }
void qcow2_parse_compressed_l2_entry(BlockDriverState *bs, uint64_t l2_entry,
uint64_t *coffset, int *csize)
{
BDRVQcow2State *s = bs->opaque;
int nb_csectors;
assert(qcow2_get_cluster_type(bs, l2_entry) == QCOW2_CLUSTER_COMPRESSED);
*coffset = l2_entry & s->cluster_offset_mask;
nb_csectors = ((l2_entry >> s->csize_shift) & s->csize_mask) + 1;
*csize = nb_csectors * QCOW2_COMPRESSED_SECTOR_SIZE -
(*coffset & (QCOW2_COMPRESSED_SECTOR_SIZE - 1));
}

View File

@ -1177,11 +1177,11 @@ void qcow2_free_any_cluster(BlockDriverState *bs, uint64_t l2_entry,
switch (ctype) { switch (ctype) {
case QCOW2_CLUSTER_COMPRESSED: case QCOW2_CLUSTER_COMPRESSED:
{ {
uint64_t coffset; int64_t offset = (l2_entry & s->cluster_offset_mask)
int csize; & QCOW2_COMPRESSED_SECTOR_MASK;
int size = QCOW2_COMPRESSED_SECTOR_SIZE *
qcow2_parse_compressed_l2_entry(bs, l2_entry, &coffset, &csize); (((l2_entry >> s->csize_shift) & s->csize_mask) + 1);
qcow2_free_clusters(bs, coffset, csize, type); qcow2_free_clusters(bs, offset, size, type);
} }
break; break;
case QCOW2_CLUSTER_NORMAL: case QCOW2_CLUSTER_NORMAL:
@ -1247,7 +1247,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
bool l1_allocated = false; bool l1_allocated = false;
int64_t old_entry, old_l2_offset; int64_t old_entry, old_l2_offset;
unsigned slice, slice_size2, n_slices; unsigned slice, slice_size2, n_slices;
int i, j, l1_modified = 0; int i, j, l1_modified = 0, nb_csectors;
int ret; int ret;
assert(addend >= -1 && addend <= 1); assert(addend >= -1 && addend <= 1);
@ -1318,14 +1318,14 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
switch (qcow2_get_cluster_type(bs, entry)) { switch (qcow2_get_cluster_type(bs, entry)) {
case QCOW2_CLUSTER_COMPRESSED: case QCOW2_CLUSTER_COMPRESSED:
nb_csectors = ((entry >> s->csize_shift) &
s->csize_mask) + 1;
if (addend != 0) { if (addend != 0) {
uint64_t coffset; uint64_t coffset = (entry & s->cluster_offset_mask)
int csize; & QCOW2_COMPRESSED_SECTOR_MASK;
qcow2_parse_compressed_l2_entry(bs, entry,
&coffset, &csize);
ret = update_refcount( ret = update_refcount(
bs, coffset, csize, bs, coffset,
nb_csectors * QCOW2_COMPRESSED_SECTOR_SIZE,
abs(addend), addend < 0, abs(addend), addend < 0,
QCOW2_DISCARD_SNAPSHOT); QCOW2_DISCARD_SNAPSHOT);
if (ret < 0) { if (ret < 0) {
@ -1587,66 +1587,6 @@ enum {
CHECK_FRAG_INFO = 0x2, /* update BlockFragInfo counters */ CHECK_FRAG_INFO = 0x2, /* update BlockFragInfo counters */
}; };
/*
* Fix L2 entry by making it QCOW2_CLUSTER_ZERO_PLAIN (or making all its present
* subclusters QCOW2_SUBCLUSTER_ZERO_PLAIN).
*
* This function decrements res->corruptions on success, so the caller is
* responsible to increment res->corruptions prior to the call.
*
* On failure in-memory @l2_table may be modified.
*/
static int fix_l2_entry_by_zero(BlockDriverState *bs, BdrvCheckResult *res,
uint64_t l2_offset,
uint64_t *l2_table, int l2_index, bool active,
bool *metadata_overlap)
{
BDRVQcow2State *s = bs->opaque;
int ret;
int idx = l2_index * (l2_entry_size(s) / sizeof(uint64_t));
uint64_t l2e_offset = l2_offset + (uint64_t)l2_index * l2_entry_size(s);
int ign = active ? QCOW2_OL_ACTIVE_L2 : QCOW2_OL_INACTIVE_L2;
if (has_subclusters(s)) {
uint64_t l2_bitmap = get_l2_bitmap(s, l2_table, l2_index);
/* Allocated subclusters become zero */
l2_bitmap |= l2_bitmap << 32;
l2_bitmap &= QCOW_L2_BITMAP_ALL_ZEROES;
set_l2_bitmap(s, l2_table, l2_index, l2_bitmap);
set_l2_entry(s, l2_table, l2_index, 0);
} else {
set_l2_entry(s, l2_table, l2_index, QCOW_OFLAG_ZERO);
}
ret = qcow2_pre_write_overlap_check(bs, ign, l2e_offset, l2_entry_size(s),
false);
if (metadata_overlap) {
*metadata_overlap = ret < 0;
}
if (ret < 0) {
fprintf(stderr, "ERROR: Overlap check failed\n");
goto fail;
}
ret = bdrv_pwrite_sync(bs->file, l2e_offset, &l2_table[idx],
l2_entry_size(s));
if (ret < 0) {
fprintf(stderr, "ERROR: Failed to overwrite L2 "
"table entry: %s\n", strerror(-ret));
goto fail;
}
res->corruptions--;
res->corruptions_fixed++;
return 0;
fail:
res->check_errors++;
return ret;
}
/* /*
* Increases the refcount in the given refcount table for the all clusters * Increases the refcount in the given refcount table for the all clusters
* referenced in the L2 table. While doing so, performs some checks on L2 * referenced in the L2 table. While doing so, performs some checks on L2
@ -1661,41 +1601,26 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
int flags, BdrvCheckMode fix, bool active) int flags, BdrvCheckMode fix, bool active)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
uint64_t l2_entry, l2_bitmap; uint64_t *l2_table, l2_entry;
uint64_t next_contiguous_offset = 0; uint64_t next_contiguous_offset = 0;
int i, ret; int i, l2_size, nb_csectors, ret;
size_t l2_size_bytes = s->l2_size * l2_entry_size(s);
g_autofree uint64_t *l2_table = g_malloc(l2_size_bytes);
bool metadata_overlap;
/* Read L2 table from disk */ /* Read L2 table from disk */
ret = bdrv_pread(bs->file, l2_offset, l2_table, l2_size_bytes); l2_size = s->l2_size * l2_entry_size(s);
l2_table = g_malloc(l2_size);
ret = bdrv_pread(bs->file, l2_offset, l2_table, l2_size);
if (ret < 0) { if (ret < 0) {
fprintf(stderr, "ERROR: I/O error in check_refcounts_l2\n"); fprintf(stderr, "ERROR: I/O error in check_refcounts_l2\n");
res->check_errors++; res->check_errors++;
return ret; goto fail;
} }
/* Do the actual checks */ /* Do the actual checks */
for (i = 0; i < s->l2_size; i++) { for(i = 0; i < s->l2_size; i++) {
uint64_t coffset;
int csize;
QCow2ClusterType type;
l2_entry = get_l2_entry(s, l2_table, i); l2_entry = get_l2_entry(s, l2_table, i);
l2_bitmap = get_l2_bitmap(s, l2_table, i);
type = qcow2_get_cluster_type(bs, l2_entry);
if (type != QCOW2_CLUSTER_COMPRESSED) { switch (qcow2_get_cluster_type(bs, l2_entry)) {
/* Check reserved bits of Standard Cluster Descriptor */
if (l2_entry & L2E_STD_RESERVED_MASK) {
fprintf(stderr, "ERROR found l2 entry with reserved bits set: "
"%" PRIx64 "\n", l2_entry);
res->corruptions++;
}
}
switch (type) {
case QCOW2_CLUSTER_COMPRESSED: case QCOW2_CLUSTER_COMPRESSED:
/* Compressed clusters don't have QCOW_OFLAG_COPIED */ /* Compressed clusters don't have QCOW_OFLAG_COPIED */
if (l2_entry & QCOW_OFLAG_COPIED) { if (l2_entry & QCOW_OFLAG_COPIED) {
@ -1713,28 +1638,23 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
break; break;
} }
if (l2_bitmap) {
fprintf(stderr, "ERROR compressed cluster %d with non-zero "
"subcluster allocation bitmap, entry=0x%" PRIx64 "\n",
i, l2_entry);
res->corruptions++;
break;
}
/* Mark cluster as used */ /* Mark cluster as used */
qcow2_parse_compressed_l2_entry(bs, l2_entry, &coffset, &csize); nb_csectors = ((l2_entry >> s->csize_shift) &
s->csize_mask) + 1;
l2_entry &= s->cluster_offset_mask;
ret = qcow2_inc_refcounts_imrt( ret = qcow2_inc_refcounts_imrt(
bs, res, refcount_table, refcount_table_size, coffset, csize); bs, res, refcount_table, refcount_table_size,
l2_entry & QCOW2_COMPRESSED_SECTOR_MASK,
nb_csectors * QCOW2_COMPRESSED_SECTOR_SIZE);
if (ret < 0) { if (ret < 0) {
return ret; goto fail;
} }
if (flags & CHECK_FRAG_INFO) { if (flags & CHECK_FRAG_INFO) {
res->bfi.allocated_clusters++; res->bfi.allocated_clusters++;
res->bfi.compressed_clusters++; res->bfi.compressed_clusters++;
/* /* Compressed clusters are fragmented by nature. Since they
* Compressed clusters are fragmented by nature. Since they
* take up sub-sector space but we only have sector granularity * take up sub-sector space but we only have sector granularity
* I/O we need to re-read the same sectors even for adjacent * I/O we need to re-read the same sectors even for adjacent
* compressed clusters. * compressed clusters.
@ -1748,19 +1668,13 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
{ {
uint64_t offset = l2_entry & L2E_OFFSET_MASK; uint64_t offset = l2_entry & L2E_OFFSET_MASK;
if ((l2_bitmap >> 32) & l2_bitmap) {
res->corruptions++;
fprintf(stderr, "ERROR offset=%" PRIx64 ": Allocated "
"cluster has corrupted subcluster allocation bitmap\n",
offset);
}
/* Correct offsets are cluster aligned */ /* Correct offsets are cluster aligned */
if (offset_into_cluster(s, offset)) { if (offset_into_cluster(s, offset)) {
bool contains_data; bool contains_data;
res->corruptions++; res->corruptions++;
if (has_subclusters(s)) { if (has_subclusters(s)) {
uint64_t l2_bitmap = get_l2_bitmap(s, l2_table, i);
contains_data = (l2_bitmap & QCOW_L2_BITMAP_ALL_ALLOC); contains_data = (l2_bitmap & QCOW_L2_BITMAP_ALL_ALLOC);
} else { } else {
contains_data = !(l2_entry & QCOW_OFLAG_ZERO); contains_data = !(l2_entry & QCOW_OFLAG_ZERO);
@ -1773,30 +1687,40 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR", fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR",
offset); offset);
if (fix & BDRV_FIX_ERRORS) { if (fix & BDRV_FIX_ERRORS) {
ret = fix_l2_entry_by_zero(bs, res, l2_offset, int idx = i * (l2_entry_size(s) / sizeof(uint64_t));
l2_table, i, active, uint64_t l2e_offset =
&metadata_overlap); l2_offset + (uint64_t)i * l2_entry_size(s);
if (metadata_overlap) { int ign = active ? QCOW2_OL_ACTIVE_L2 :
/* QCOW2_OL_INACTIVE_L2;
* Something is seriously wrong, so abort checking
* this L2 table. l2_entry = has_subclusters(s) ? 0 : QCOW_OFLAG_ZERO;
*/ set_l2_entry(s, l2_table, i, l2_entry);
return ret; ret = qcow2_pre_write_overlap_check(bs, ign,
l2e_offset, l2_entry_size(s), false);
if (ret < 0) {
fprintf(stderr, "ERROR: Overlap check failed\n");
res->check_errors++;
/* Something is seriously wrong, so abort checking
* this L2 table */
goto fail;
} }
if (ret == 0) { ret = bdrv_pwrite_sync(bs->file, l2e_offset,
/* &l2_table[idx],
* Skip marking the cluster as used l2_entry_size(s));
* (it is unused now). if (ret < 0) {
*/ fprintf(stderr, "ERROR: Failed to overwrite L2 "
"table entry: %s\n", strerror(-ret));
res->check_errors++;
/* Do not abort, continue checking the rest of this
* L2 table's entries */
} else {
res->corruptions--;
res->corruptions_fixed++;
/* Skip marking the cluster as used
* (it is unused now) */
continue; continue;
} }
/*
* Failed to fix.
* Do not abort, continue checking the rest of this
* L2 table's entries.
*/
} }
} else { } else {
fprintf(stderr, "ERROR offset=%" PRIx64 ": Data cluster is " fprintf(stderr, "ERROR offset=%" PRIx64 ": Data cluster is "
@ -1819,23 +1743,14 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
refcount_table_size, refcount_table_size,
offset, s->cluster_size); offset, s->cluster_size);
if (ret < 0) { if (ret < 0) {
return ret; goto fail;
} }
} }
break; break;
} }
case QCOW2_CLUSTER_ZERO_PLAIN: case QCOW2_CLUSTER_ZERO_PLAIN:
/* Impossible when image has subclusters */
assert(!l2_bitmap);
break;
case QCOW2_CLUSTER_UNALLOCATED: case QCOW2_CLUSTER_UNALLOCATED:
if (l2_bitmap & QCOW_L2_BITMAP_ALL_ALLOC) {
res->corruptions++;
fprintf(stderr, "ERROR: Unallocated "
"cluster has non-zero subcluster allocation map\n");
}
break; break;
default: default:
@ -1843,7 +1758,12 @@ static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
} }
} }
g_free(l2_table);
return 0; return 0;
fail:
g_free(l2_table);
return ret;
} }
/* /*
@ -1862,79 +1782,71 @@ static int check_refcounts_l1(BlockDriverState *bs,
int flags, BdrvCheckMode fix, bool active) int flags, BdrvCheckMode fix, bool active)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
size_t l1_size_bytes = l1_size * L1E_SIZE; uint64_t *l1_table = NULL, l2_offset, l1_size2;
g_autofree uint64_t *l1_table = NULL;
uint64_t l2_offset;
int i, ret; int i, ret;
if (!l1_size) { l1_size2 = l1_size * L1E_SIZE;
return 0;
}
/* Mark L1 table as used */ /* Mark L1 table as used */
ret = qcow2_inc_refcounts_imrt(bs, res, refcount_table, refcount_table_size, ret = qcow2_inc_refcounts_imrt(bs, res, refcount_table, refcount_table_size,
l1_table_offset, l1_size_bytes); l1_table_offset, l1_size2);
if (ret < 0) { if (ret < 0) {
return ret; goto fail;
}
l1_table = g_try_malloc(l1_size_bytes);
if (l1_table == NULL) {
res->check_errors++;
return -ENOMEM;
} }
/* Read L1 table entries from disk */ /* Read L1 table entries from disk */
ret = bdrv_pread(bs->file, l1_table_offset, l1_table, l1_size_bytes); if (l1_size2 > 0) {
if (ret < 0) { l1_table = g_try_malloc(l1_size2);
fprintf(stderr, "ERROR: I/O error in check_refcounts_l1\n"); if (l1_table == NULL) {
res->check_errors++; ret = -ENOMEM;
return ret; res->check_errors++;
} goto fail;
}
for (i = 0; i < l1_size; i++) { ret = bdrv_pread(bs->file, l1_table_offset, l1_table, l1_size2);
be64_to_cpus(&l1_table[i]); if (ret < 0) {
fprintf(stderr, "ERROR: I/O error in check_refcounts_l1\n");
res->check_errors++;
goto fail;
}
for(i = 0;i < l1_size; i++)
be64_to_cpus(&l1_table[i]);
} }
/* Do the actual checks */ /* Do the actual checks */
for (i = 0; i < l1_size; i++) { for(i = 0; i < l1_size; i++) {
if (!l1_table[i]) { l2_offset = l1_table[i];
continue; if (l2_offset) {
} /* Mark L2 table as used */
l2_offset &= L1E_OFFSET_MASK;
ret = qcow2_inc_refcounts_imrt(bs, res,
refcount_table, refcount_table_size,
l2_offset, s->cluster_size);
if (ret < 0) {
goto fail;
}
if (l1_table[i] & L1E_RESERVED_MASK) { /* L2 tables are cluster aligned */
fprintf(stderr, "ERROR found L1 entry with reserved bits set: " if (offset_into_cluster(s, l2_offset)) {
"%" PRIx64 "\n", l1_table[i]); fprintf(stderr, "ERROR l2_offset=%" PRIx64 ": Table is not "
res->corruptions++; "cluster aligned; L1 entry corrupted\n", l2_offset);
} res->corruptions++;
}
l2_offset = l1_table[i] & L1E_OFFSET_MASK; /* Process and check L2 entries */
ret = check_refcounts_l2(bs, res, refcount_table,
/* Mark L2 table as used */ refcount_table_size, l2_offset, flags,
ret = qcow2_inc_refcounts_imrt(bs, res, fix, active);
refcount_table, refcount_table_size, if (ret < 0) {
l2_offset, s->cluster_size); goto fail;
if (ret < 0) { }
return ret;
}
/* L2 tables are cluster aligned */
if (offset_into_cluster(s, l2_offset)) {
fprintf(stderr, "ERROR l2_offset=%" PRIx64 ": Table is not "
"cluster aligned; L1 entry corrupted\n", l2_offset);
res->corruptions++;
}
/* Process and check L2 entries */
ret = check_refcounts_l2(bs, res, refcount_table,
refcount_table_size, l2_offset, flags,
fix, active);
if (ret < 0) {
return ret;
} }
} }
g_free(l1_table);
return 0; return 0;
fail:
g_free(l1_table);
return ret;
} }
/* /*
@ -2089,17 +2001,9 @@ static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res,
for(i = 0; i < s->refcount_table_size; i++) { for(i = 0; i < s->refcount_table_size; i++) {
uint64_t offset, cluster; uint64_t offset, cluster;
offset = s->refcount_table[i] & REFT_OFFSET_MASK; offset = s->refcount_table[i];
cluster = offset >> s->cluster_bits; cluster = offset >> s->cluster_bits;
if (s->refcount_table[i] & REFT_RESERVED_MASK) {
fprintf(stderr, "ERROR refcount table entry %" PRId64 " has "
"reserved bits set\n", i);
res->corruptions++;
*rebuild = true;
continue;
}
/* Refcount blocks are cluster aligned */ /* Refcount blocks are cluster aligned */
if (offset_into_cluster(s, offset)) { if (offset_into_cluster(s, offset)) {
fprintf(stderr, "ERROR refcount block %" PRId64 " is not " fprintf(stderr, "ERROR refcount block %" PRId64 " is not "

View File

@ -74,7 +74,7 @@ typedef struct {
static int coroutine_fn static int coroutine_fn
qcow2_co_preadv_compressed(BlockDriverState *bs, qcow2_co_preadv_compressed(BlockDriverState *bs,
uint64_t l2_entry, uint64_t cluster_descriptor,
uint64_t offset, uint64_t offset,
uint64_t bytes, uint64_t bytes,
QEMUIOVector *qiov, QEMUIOVector *qiov,
@ -2205,7 +2205,7 @@ typedef struct Qcow2AioTask {
BlockDriverState *bs; BlockDriverState *bs;
QCow2SubclusterType subcluster_type; /* only for read */ QCow2SubclusterType subcluster_type; /* only for read */
uint64_t host_offset; /* or l2_entry for compressed read */ uint64_t host_offset; /* or full descriptor in compressed clusters */
uint64_t offset; uint64_t offset;
uint64_t bytes; uint64_t bytes;
QEMUIOVector *qiov; QEMUIOVector *qiov;
@ -2310,10 +2310,9 @@ static coroutine_fn int qcow2_co_preadv_task_entry(AioTask *task)
} }
static coroutine_fn int qcow2_co_preadv_part(BlockDriverState *bs, static coroutine_fn int qcow2_co_preadv_part(BlockDriverState *bs,
int64_t offset, int64_t bytes, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, QEMUIOVector *qiov,
size_t qiov_offset, size_t qiov_offset, int flags)
BdrvRequestFlags flags)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int ret = 0; int ret = 0;
@ -2597,8 +2596,8 @@ static coroutine_fn int qcow2_co_pwritev_task_entry(AioTask *task)
} }
static coroutine_fn int qcow2_co_pwritev_part( static coroutine_fn int qcow2_co_pwritev_part(
BlockDriverState *bs, int64_t offset, int64_t bytes, BlockDriverState *bs, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, size_t qiov_offset, BdrvRequestFlags flags) QEMUIOVector *qiov, size_t qiov_offset, int flags)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int offset_in_cluster; int offset_in_cluster;
@ -3941,7 +3940,7 @@ static bool is_zero(BlockDriverState *bs, int64_t offset, int64_t bytes)
} }
static coroutine_fn int qcow2_co_pwrite_zeroes(BlockDriverState *bs, static coroutine_fn int qcow2_co_pwrite_zeroes(BlockDriverState *bs,
int64_t offset, int64_t bytes, BdrvRequestFlags flags) int64_t offset, int bytes, BdrvRequestFlags flags)
{ {
int ret; int ret;
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
@ -3996,7 +3995,7 @@ static coroutine_fn int qcow2_co_pwrite_zeroes(BlockDriverState *bs,
} }
static coroutine_fn int qcow2_co_pdiscard(BlockDriverState *bs, static coroutine_fn int qcow2_co_pdiscard(BlockDriverState *bs,
int64_t offset, int64_t bytes) int64_t offset, int bytes)
{ {
int ret; int ret;
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
@ -4026,9 +4025,9 @@ static coroutine_fn int qcow2_co_pdiscard(BlockDriverState *bs,
static int coroutine_fn static int coroutine_fn
qcow2_co_copy_range_from(BlockDriverState *bs, qcow2_co_copy_range_from(BlockDriverState *bs,
BdrvChild *src, int64_t src_offset, BdrvChild *src, uint64_t src_offset,
BdrvChild *dst, int64_t dst_offset, BdrvChild *dst, uint64_t dst_offset,
int64_t bytes, BdrvRequestFlags read_flags, uint64_t bytes, BdrvRequestFlags read_flags,
BdrvRequestFlags write_flags) BdrvRequestFlags write_flags)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
@ -4109,9 +4108,9 @@ out:
static int coroutine_fn static int coroutine_fn
qcow2_co_copy_range_to(BlockDriverState *bs, qcow2_co_copy_range_to(BlockDriverState *bs,
BdrvChild *src, int64_t src_offset, BdrvChild *src, uint64_t src_offset,
BdrvChild *dst, int64_t dst_offset, BdrvChild *dst, uint64_t dst_offset,
int64_t bytes, BdrvRequestFlags read_flags, uint64_t bytes, BdrvRequestFlags read_flags,
BdrvRequestFlags write_flags) BdrvRequestFlags write_flags)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
@ -4631,7 +4630,7 @@ static coroutine_fn int qcow2_co_pwritev_compressed_task_entry(AioTask *task)
*/ */
static coroutine_fn int static coroutine_fn int
qcow2_co_pwritev_compressed_part(BlockDriverState *bs, qcow2_co_pwritev_compressed_part(BlockDriverState *bs,
int64_t offset, int64_t bytes, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, size_t qiov_offset) QEMUIOVector *qiov, size_t qiov_offset)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
@ -4694,19 +4693,22 @@ qcow2_co_pwritev_compressed_part(BlockDriverState *bs,
static int coroutine_fn static int coroutine_fn
qcow2_co_preadv_compressed(BlockDriverState *bs, qcow2_co_preadv_compressed(BlockDriverState *bs,
uint64_t l2_entry, uint64_t cluster_descriptor,
uint64_t offset, uint64_t offset,
uint64_t bytes, uint64_t bytes,
QEMUIOVector *qiov, QEMUIOVector *qiov,
size_t qiov_offset) size_t qiov_offset)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int ret = 0, csize; int ret = 0, csize, nb_csectors;
uint64_t coffset; uint64_t coffset;
uint8_t *buf, *out_buf; uint8_t *buf, *out_buf;
int offset_in_cluster = offset_into_cluster(s, offset); int offset_in_cluster = offset_into_cluster(s, offset);
qcow2_parse_compressed_l2_entry(bs, l2_entry, &coffset, &csize); coffset = cluster_descriptor & s->cluster_offset_mask;
nb_csectors = ((cluster_descriptor >> s->csize_shift) & s->csize_mask) + 1;
csize = nb_csectors * QCOW2_COMPRESSED_SECTOR_SIZE -
(coffset & ~QCOW2_COMPRESSED_SECTOR_MASK);
buf = g_try_malloc(csize); buf = g_try_malloc(csize);
if (!buf) { if (!buf) {
@ -5228,55 +5230,24 @@ static int qcow2_has_zero_init(BlockDriverState *bs)
} }
} }
/*
* Check the request to vmstate. On success return
* qcow2_vm_state_offset(bs) + @pos
*/
static int64_t qcow2_check_vmstate_request(BlockDriverState *bs,
QEMUIOVector *qiov, int64_t pos)
{
BDRVQcow2State *s = bs->opaque;
int64_t vmstate_offset = qcow2_vm_state_offset(s);
int ret;
/* Incoming requests must be OK */
bdrv_check_qiov_request(pos, qiov->size, qiov, 0, &error_abort);
if (INT64_MAX - pos < vmstate_offset) {
return -EIO;
}
pos += vmstate_offset;
ret = bdrv_check_qiov_request(pos, qiov->size, qiov, 0, NULL);
if (ret < 0) {
return ret;
}
return pos;
}
static int qcow2_save_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, static int qcow2_save_vmstate(BlockDriverState *bs, QEMUIOVector *qiov,
int64_t pos) int64_t pos)
{ {
int64_t offset = qcow2_check_vmstate_request(bs, qiov, pos); BDRVQcow2State *s = bs->opaque;
if (offset < 0) {
return offset;
}
BLKDBG_EVENT(bs->file, BLKDBG_VMSTATE_SAVE); BLKDBG_EVENT(bs->file, BLKDBG_VMSTATE_SAVE);
return bs->drv->bdrv_co_pwritev_part(bs, offset, qiov->size, qiov, 0, 0); return bs->drv->bdrv_co_pwritev_part(bs, qcow2_vm_state_offset(s) + pos,
qiov->size, qiov, 0, 0);
} }
static int qcow2_load_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, static int qcow2_load_vmstate(BlockDriverState *bs, QEMUIOVector *qiov,
int64_t pos) int64_t pos)
{ {
int64_t offset = qcow2_check_vmstate_request(bs, qiov, pos); BDRVQcow2State *s = bs->opaque;
if (offset < 0) {
return offset;
}
BLKDBG_EVENT(bs->file, BLKDBG_VMSTATE_LOAD); BLKDBG_EVENT(bs->file, BLKDBG_VMSTATE_LOAD);
return bs->drv->bdrv_co_preadv_part(bs, offset, qiov->size, qiov, 0, 0); return bs->drv->bdrv_co_preadv_part(bs, qcow2_vm_state_offset(s) + pos,
qiov->size, qiov, 0, 0);
} }
/* /*

View File

@ -110,6 +110,7 @@
/* Defined in the qcow2 spec (compressed cluster descriptor) */ /* Defined in the qcow2 spec (compressed cluster descriptor) */
#define QCOW2_COMPRESSED_SECTOR_SIZE 512U #define QCOW2_COMPRESSED_SECTOR_SIZE 512U
#define QCOW2_COMPRESSED_SECTOR_MASK (~(QCOW2_COMPRESSED_SECTOR_SIZE - 1ULL))
/* Must be at least 2 to cover COW */ /* Must be at least 2 to cover COW */
#define MIN_L2_CACHE_SIZE 2 /* cache entries */ #define MIN_L2_CACHE_SIZE 2 /* cache entries */
@ -586,12 +587,10 @@ typedef enum QCow2MetadataOverlap {
(QCOW2_OL_CACHED | QCOW2_OL_INACTIVE_L2) (QCOW2_OL_CACHED | QCOW2_OL_INACTIVE_L2)
#define L1E_OFFSET_MASK 0x00fffffffffffe00ULL #define L1E_OFFSET_MASK 0x00fffffffffffe00ULL
#define L1E_RESERVED_MASK 0x7f000000000001ffULL
#define L2E_OFFSET_MASK 0x00fffffffffffe00ULL #define L2E_OFFSET_MASK 0x00fffffffffffe00ULL
#define L2E_STD_RESERVED_MASK 0x3f000000000001feULL #define L2E_COMPRESSED_OFFSET_SIZE_MASK 0x3fffffffffffffffULL
#define REFT_OFFSET_MASK 0xfffffffffffffe00ULL #define REFT_OFFSET_MASK 0xfffffffffffffe00ULL
#define REFT_RESERVED_MASK 0x1ffULL
#define INV_OFFSET (-1ULL) #define INV_OFFSET (-1ULL)
@ -915,8 +914,6 @@ int qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
uint64_t offset, uint64_t offset,
int compressed_size, int compressed_size,
uint64_t *host_offset); uint64_t *host_offset);
void qcow2_parse_compressed_l2_entry(BlockDriverState *bs, uint64_t l2_entry,
uint64_t *coffset, int *csize);
int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m); int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m);
void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m); void qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m);

View File

@ -582,7 +582,6 @@ static void bdrv_qed_refresh_limits(BlockDriverState *bs, Error **errp)
BDRVQEDState *s = bs->opaque; BDRVQEDState *s = bs->opaque;
bs->bl.pwrite_zeroes_alignment = s->header.cluster_size; bs->bl.pwrite_zeroes_alignment = s->header.cluster_size;
bs->bl.max_pwrite_zeroes = QEMU_ALIGN_DOWN(INT_MAX, s->header.cluster_size);
} }
/* We have nothing to do for QED reopen, stubs just return /* We have nothing to do for QED reopen, stubs just return
@ -1398,7 +1397,7 @@ static int coroutine_fn bdrv_qed_co_writev(BlockDriverState *bs,
static int coroutine_fn bdrv_qed_co_pwrite_zeroes(BlockDriverState *bs, static int coroutine_fn bdrv_qed_co_pwrite_zeroes(BlockDriverState *bs,
int64_t offset, int64_t offset,
int64_t bytes, int bytes,
BdrvRequestFlags flags) BdrvRequestFlags flags)
{ {
BDRVQEDState *s = bs->opaque; BDRVQEDState *s = bs->opaque;
@ -1409,12 +1408,6 @@ static int coroutine_fn bdrv_qed_co_pwrite_zeroes(BlockDriverState *bs,
*/ */
QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, NULL, bytes); QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, NULL, bytes);
/*
* QED is not prepared for 63bit write-zero requests, so rely on
* max_pwrite_zeroes.
*/
assert(bytes <= INT_MAX);
/* Fall back if the request is not aligned */ /* Fall back if the request is not aligned */
if (qed_offset_into_cluster(s, offset) || if (qed_offset_into_cluster(s, offset) ||
qed_offset_into_cluster(s, bytes)) { qed_offset_into_cluster(s, bytes)) {

View File

@ -663,8 +663,8 @@ static int read_fifo_child(QuorumAIOCB *acb)
return ret; return ret;
} }
static int quorum_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, static int quorum_co_preadv(BlockDriverState *bs, uint64_t offset,
QEMUIOVector *qiov, BdrvRequestFlags flags) uint64_t bytes, QEMUIOVector *qiov, int flags)
{ {
BDRVQuorumState *s = bs->opaque; BDRVQuorumState *s = bs->opaque;
QuorumAIOCB *acb = quorum_aio_get(bs, qiov, offset, bytes, flags); QuorumAIOCB *acb = quorum_aio_get(bs, qiov, offset, bytes, flags);
@ -714,9 +714,8 @@ static void write_quorum_entry(void *opaque)
} }
} }
static int quorum_co_pwritev(BlockDriverState *bs, int64_t offset, static int quorum_co_pwritev(BlockDriverState *bs, uint64_t offset,
int64_t bytes, QEMUIOVector *qiov, uint64_t bytes, QEMUIOVector *qiov, int flags)
BdrvRequestFlags flags)
{ {
BDRVQuorumState *s = bs->opaque; BDRVQuorumState *s = bs->opaque;
QuorumAIOCB *acb = quorum_aio_get(bs, qiov, offset, bytes, flags); QuorumAIOCB *acb = quorum_aio_get(bs, qiov, offset, bytes, flags);
@ -746,7 +745,7 @@ static int quorum_co_pwritev(BlockDriverState *bs, int64_t offset,
} }
static int quorum_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, static int quorum_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
int64_t bytes, BdrvRequestFlags flags) int bytes, BdrvRequestFlags flags)
{ {
return quorum_co_pwritev(bs, offset, bytes, NULL, return quorum_co_pwritev(bs, offset, bytes, NULL,

View File

@ -181,8 +181,8 @@ static void raw_reopen_abort(BDRVReopenState *state)
} }
/* Check and adjust the offset, against 'offset' and 'size' options. */ /* Check and adjust the offset, against 'offset' and 'size' options. */
static inline int raw_adjust_offset(BlockDriverState *bs, int64_t *offset, static inline int raw_adjust_offset(BlockDriverState *bs, uint64_t *offset,
int64_t bytes, bool is_write) uint64_t bytes, bool is_write)
{ {
BDRVRawState *s = bs->opaque; BDRVRawState *s = bs->opaque;
@ -201,9 +201,9 @@ static inline int raw_adjust_offset(BlockDriverState *bs, int64_t *offset,
return 0; return 0;
} }
static int coroutine_fn raw_co_preadv(BlockDriverState *bs, int64_t offset, static int coroutine_fn raw_co_preadv(BlockDriverState *bs, uint64_t offset,
int64_t bytes, QEMUIOVector *qiov, uint64_t bytes, QEMUIOVector *qiov,
BdrvRequestFlags flags) int flags)
{ {
int ret; int ret;
@ -216,9 +216,9 @@ static int coroutine_fn raw_co_preadv(BlockDriverState *bs, int64_t offset,
return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags); return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
} }
static int coroutine_fn raw_co_pwritev(BlockDriverState *bs, int64_t offset, static int coroutine_fn raw_co_pwritev(BlockDriverState *bs, uint64_t offset,
int64_t bytes, QEMUIOVector *qiov, uint64_t bytes, QEMUIOVector *qiov,
BdrvRequestFlags flags) int flags)
{ {
void *buf = NULL; void *buf = NULL;
BlockDriver *drv; BlockDriver *drv;
@ -289,12 +289,12 @@ static int coroutine_fn raw_co_block_status(BlockDriverState *bs,
} }
static int coroutine_fn raw_co_pwrite_zeroes(BlockDriverState *bs, static int coroutine_fn raw_co_pwrite_zeroes(BlockDriverState *bs,
int64_t offset, int64_t bytes, int64_t offset, int bytes,
BdrvRequestFlags flags) BdrvRequestFlags flags)
{ {
int ret; int ret;
ret = raw_adjust_offset(bs, &offset, bytes, true); ret = raw_adjust_offset(bs, (uint64_t *)&offset, bytes, true);
if (ret) { if (ret) {
return ret; return ret;
} }
@ -302,11 +302,11 @@ static int coroutine_fn raw_co_pwrite_zeroes(BlockDriverState *bs,
} }
static int coroutine_fn raw_co_pdiscard(BlockDriverState *bs, static int coroutine_fn raw_co_pdiscard(BlockDriverState *bs,
int64_t offset, int64_t bytes) int64_t offset, int bytes)
{ {
int ret; int ret;
ret = raw_adjust_offset(bs, &offset, bytes, true); ret = raw_adjust_offset(bs, (uint64_t *)&offset, bytes, true);
if (ret) { if (ret) {
return ret; return ret;
} }
@ -532,10 +532,10 @@ static int raw_probe_geometry(BlockDriverState *bs, HDGeometry *geo)
static int coroutine_fn raw_co_copy_range_from(BlockDriverState *bs, static int coroutine_fn raw_co_copy_range_from(BlockDriverState *bs,
BdrvChild *src, BdrvChild *src,
int64_t src_offset, uint64_t src_offset,
BdrvChild *dst, BdrvChild *dst,
int64_t dst_offset, uint64_t dst_offset,
int64_t bytes, uint64_t bytes,
BdrvRequestFlags read_flags, BdrvRequestFlags read_flags,
BdrvRequestFlags write_flags) BdrvRequestFlags write_flags)
{ {
@ -551,10 +551,10 @@ static int coroutine_fn raw_co_copy_range_from(BlockDriverState *bs,
static int coroutine_fn raw_co_copy_range_to(BlockDriverState *bs, static int coroutine_fn raw_co_copy_range_to(BlockDriverState *bs,
BdrvChild *src, BdrvChild *src,
int64_t src_offset, uint64_t src_offset,
BdrvChild *dst, BdrvChild *dst,
int64_t dst_offset, uint64_t dst_offset,
int64_t bytes, uint64_t bytes,
BdrvRequestFlags read_flags, BdrvRequestFlags read_flags,
BdrvRequestFlags write_flags) BdrvRequestFlags write_flags)
{ {
@ -580,25 +580,6 @@ static void raw_cancel_in_flight(BlockDriverState *bs)
bdrv_cancel_in_flight(bs->file->bs); bdrv_cancel_in_flight(bs->file->bs);
} }
static void raw_child_perm(BlockDriverState *bs, BdrvChild *c,
BdrvChildRole role,
BlockReopenQueue *reopen_queue,
uint64_t parent_perm, uint64_t parent_shared,
uint64_t *nperm, uint64_t *nshared)
{
bdrv_default_perms(bs, c, role, reopen_queue, parent_perm,
parent_shared, nperm, nshared);
/*
* bdrv_default_perms() may add WRITE and/or RESIZE (see comment in
* bdrv_default_perms_for_storage() for an explanation) but we only need
* them if they are in parent_perm. Drop WRITE and RESIZE whenever possible
* to avoid permission conflicts.
*/
*nperm &= ~(BLK_PERM_WRITE | BLK_PERM_RESIZE);
*nperm |= parent_perm & (BLK_PERM_WRITE | BLK_PERM_RESIZE);
}
BlockDriver bdrv_raw = { BlockDriver bdrv_raw = {
.format_name = "raw", .format_name = "raw",
.instance_size = sizeof(BDRVRawState), .instance_size = sizeof(BDRVRawState),
@ -607,7 +588,7 @@ BlockDriver bdrv_raw = {
.bdrv_reopen_commit = &raw_reopen_commit, .bdrv_reopen_commit = &raw_reopen_commit,
.bdrv_reopen_abort = &raw_reopen_abort, .bdrv_reopen_abort = &raw_reopen_abort,
.bdrv_open = &raw_open, .bdrv_open = &raw_open,
.bdrv_child_perm = raw_child_perm, .bdrv_child_perm = bdrv_default_perms,
.bdrv_co_create_opts = &raw_co_create_opts, .bdrv_co_create_opts = &raw_co_create_opts,
.bdrv_co_preadv = &raw_co_preadv, .bdrv_co_preadv = &raw_co_preadv,
.bdrv_co_pwritev = &raw_co_pwritev, .bdrv_co_pwritev = &raw_co_pwritev,

View File

@ -97,12 +97,6 @@ typedef struct RBDTask {
int64_t ret; int64_t ret;
} RBDTask; } RBDTask;
typedef struct RBDDiffIterateReq {
uint64_t offs;
uint64_t bytes;
bool exists;
} RBDDiffIterateReq;
static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx, static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
BlockdevOptionsRbd *opts, bool cache, BlockdevOptionsRbd *opts, bool cache,
const char *keypairs, const char *secretid, const char *keypairs, const char *secretid,
@ -1170,17 +1164,17 @@ static int coroutine_fn qemu_rbd_start_co(BlockDriverState *bs,
} }
static int static int
coroutine_fn qemu_rbd_co_preadv(BlockDriverState *bs, int64_t offset, coroutine_fn qemu_rbd_co_preadv(BlockDriverState *bs, uint64_t offset,
int64_t bytes, QEMUIOVector *qiov, uint64_t bytes, QEMUIOVector *qiov,
BdrvRequestFlags flags) int flags)
{ {
return qemu_rbd_start_co(bs, offset, bytes, qiov, flags, RBD_AIO_READ); return qemu_rbd_start_co(bs, offset, bytes, qiov, flags, RBD_AIO_READ);
} }
static int static int
coroutine_fn qemu_rbd_co_pwritev(BlockDriverState *bs, int64_t offset, coroutine_fn qemu_rbd_co_pwritev(BlockDriverState *bs, uint64_t offset,
int64_t bytes, QEMUIOVector *qiov, uint64_t bytes, QEMUIOVector *qiov,
BdrvRequestFlags flags) int flags)
{ {
BDRVRBDState *s = bs->opaque; BDRVRBDState *s = bs->opaque;
/* /*
@ -1203,17 +1197,17 @@ static int coroutine_fn qemu_rbd_co_flush(BlockDriverState *bs)
} }
static int coroutine_fn qemu_rbd_co_pdiscard(BlockDriverState *bs, static int coroutine_fn qemu_rbd_co_pdiscard(BlockDriverState *bs,
int64_t offset, int64_t bytes) int64_t offset, int count)
{ {
return qemu_rbd_start_co(bs, offset, bytes, NULL, 0, RBD_AIO_DISCARD); return qemu_rbd_start_co(bs, offset, count, NULL, 0, RBD_AIO_DISCARD);
} }
#ifdef LIBRBD_SUPPORTS_WRITE_ZEROES #ifdef LIBRBD_SUPPORTS_WRITE_ZEROES
static int static int
coroutine_fn qemu_rbd_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, coroutine_fn qemu_rbd_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
int64_t bytes, BdrvRequestFlags flags) int count, BdrvRequestFlags flags)
{ {
return qemu_rbd_start_co(bs, offset, bytes, NULL, flags, return qemu_rbd_start_co(bs, offset, count, NULL, flags,
RBD_AIO_WRITE_ZEROES); RBD_AIO_WRITE_ZEROES);
} }
#endif #endif
@ -1265,111 +1259,6 @@ static ImageInfoSpecific *qemu_rbd_get_specific_info(BlockDriverState *bs,
return spec_info; return spec_info;
} }
/*
* rbd_diff_iterate2 allows to interrupt the exection by returning a negative
* value in the callback routine. Choose a value that does not conflict with
* an existing exitcode and return it if we want to prematurely stop the
* execution because we detected a change in the allocation status.
*/
#define QEMU_RBD_EXIT_DIFF_ITERATE2 -9000
static int qemu_rbd_diff_iterate_cb(uint64_t offs, size_t len,
int exists, void *opaque)
{
RBDDiffIterateReq *req = opaque;
assert(req->offs + req->bytes <= offs);
/*
* we do not diff against a snapshot so we should never receive a callback
* for a hole.
*/
assert(exists);
if (!req->exists && offs > req->offs) {
/*
* we started in an unallocated area and hit the first allocated
* block. req->bytes must be set to the length of the unallocated area
* before the allocated area. stop further processing.
*/
req->bytes = offs - req->offs;
return QEMU_RBD_EXIT_DIFF_ITERATE2;
}
if (req->exists && offs > req->offs + req->bytes) {
/*
* we started in an allocated area and jumped over an unallocated area,
* req->bytes contains the length of the allocated area before the
* unallocated area. stop further processing.
*/
return QEMU_RBD_EXIT_DIFF_ITERATE2;
}
req->bytes += len;
req->exists = true;
return 0;
}
static int coroutine_fn qemu_rbd_co_block_status(BlockDriverState *bs,
bool want_zero, int64_t offset,
int64_t bytes, int64_t *pnum,
int64_t *map,
BlockDriverState **file)
{
BDRVRBDState *s = bs->opaque;
int status, r;
RBDDiffIterateReq req = { .offs = offset };
uint64_t features, flags;
assert(offset + bytes <= s->image_size);
/* default to all sectors allocated */
status = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID;
*map = offset;
*file = bs;
*pnum = bytes;
/* check if RBD image supports fast-diff */
r = rbd_get_features(s->image, &features);
if (r < 0) {
return status;
}
if (!(features & RBD_FEATURE_FAST_DIFF)) {
return status;
}
/* check if RBD fast-diff result is valid */
r = rbd_get_flags(s->image, &flags);
if (r < 0) {
return status;
}
if (flags & RBD_FLAG_FAST_DIFF_INVALID) {
return status;
}
r = rbd_diff_iterate2(s->image, NULL, offset, bytes, true, true,
qemu_rbd_diff_iterate_cb, &req);
if (r < 0 && r != QEMU_RBD_EXIT_DIFF_ITERATE2) {
return status;
}
assert(req.bytes <= bytes);
if (!req.exists) {
if (r == 0) {
/*
* rbd_diff_iterate2 does not invoke callbacks for unallocated
* areas. This here catches the case where no callback was
* invoked at all (req.bytes == 0).
*/
assert(req.bytes == 0);
req.bytes = bytes;
}
status = BDRV_BLOCK_ZERO | BDRV_BLOCK_OFFSET_VALID;
}
*pnum = req.bytes;
return status;
}
static int64_t qemu_rbd_getlength(BlockDriverState *bs) static int64_t qemu_rbd_getlength(BlockDriverState *bs)
{ {
BDRVRBDState *s = bs->opaque; BDRVRBDState *s = bs->opaque;
@ -1605,7 +1494,6 @@ static BlockDriver bdrv_rbd = {
#ifdef LIBRBD_SUPPORTS_WRITE_ZEROES #ifdef LIBRBD_SUPPORTS_WRITE_ZEROES
.bdrv_co_pwrite_zeroes = qemu_rbd_co_pwrite_zeroes, .bdrv_co_pwrite_zeroes = qemu_rbd_co_pwrite_zeroes,
#endif #endif
.bdrv_co_block_status = qemu_rbd_co_block_status,
.bdrv_snapshot_create = qemu_rbd_snap_create, .bdrv_snapshot_create = qemu_rbd_snap_create,
.bdrv_snapshot_delete = qemu_rbd_snap_remove, .bdrv_snapshot_delete = qemu_rbd_snap_remove,

View File

@ -149,7 +149,7 @@ static void replication_close(BlockDriverState *bs)
if (s->stage == BLOCK_REPLICATION_FAILOVER) { if (s->stage == BLOCK_REPLICATION_FAILOVER) {
commit_job = &s->commit_job->job; commit_job = &s->commit_job->job;
assert(commit_job->aio_context == qemu_get_current_aio_context()); assert(commit_job->aio_context == qemu_get_current_aio_context());
job_cancel_sync(commit_job, false); job_cancel_sync(commit_job);
} }
if (s->mode == REPLICATION_MODE_SECONDARY) { if (s->mode == REPLICATION_MODE_SECONDARY) {
@ -726,7 +726,7 @@ static void replication_stop(ReplicationState *rs, bool failover, Error **errp)
* disk, secondary disk in backup_job_completed(). * disk, secondary disk in backup_job_completed().
*/ */
if (s->backup_job) { if (s->backup_job) {
job_cancel_sync(&s->backup_job->job, true); job_cancel_sync(&s->backup_job->job);
} }
if (!failover) { if (!failover) {

View File

@ -54,8 +54,8 @@ static int stream_prepare(Job *job)
{ {
StreamBlockJob *s = container_of(job, StreamBlockJob, common.job); StreamBlockJob *s = container_of(job, StreamBlockJob, common.job);
BlockDriverState *unfiltered_bs = bdrv_skip_filters(s->target_bs); BlockDriverState *unfiltered_bs = bdrv_skip_filters(s->target_bs);
BlockDriverState *base; BlockDriverState *base = bdrv_filter_or_cow_bs(s->above_base);
BlockDriverState *unfiltered_base; BlockDriverState *unfiltered_base = bdrv_skip_filters(base);
Error *local_err = NULL; Error *local_err = NULL;
int ret = 0; int ret = 0;
@ -63,9 +63,6 @@ static int stream_prepare(Job *job)
bdrv_cor_filter_drop(s->cor_filter_bs); bdrv_cor_filter_drop(s->cor_filter_bs);
s->cor_filter_bs = NULL; s->cor_filter_bs = NULL;
base = bdrv_filter_or_cow_bs(s->above_base);
unfiltered_base = bdrv_skip_filters(base);
if (bdrv_cow_child(unfiltered_bs)) { if (bdrv_cow_child(unfiltered_bs)) {
const char *base_id = NULL, *base_fmt = NULL; const char *base_id = NULL, *base_fmt = NULL;
if (unfiltered_base) { if (unfiltered_base) {

View File

@ -112,9 +112,8 @@ static int64_t throttle_getlength(BlockDriverState *bs)
} }
static int coroutine_fn throttle_co_preadv(BlockDriverState *bs, static int coroutine_fn throttle_co_preadv(BlockDriverState *bs,
int64_t offset, int64_t bytes, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, QEMUIOVector *qiov, int flags)
BdrvRequestFlags flags)
{ {
ThrottleGroupMember *tgm = bs->opaque; ThrottleGroupMember *tgm = bs->opaque;
@ -124,9 +123,8 @@ static int coroutine_fn throttle_co_preadv(BlockDriverState *bs,
} }
static int coroutine_fn throttle_co_pwritev(BlockDriverState *bs, static int coroutine_fn throttle_co_pwritev(BlockDriverState *bs,
int64_t offset, int64_t bytes, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, QEMUIOVector *qiov, int flags)
BdrvRequestFlags flags)
{ {
ThrottleGroupMember *tgm = bs->opaque; ThrottleGroupMember *tgm = bs->opaque;
throttle_group_co_io_limits_intercept(tgm, bytes, true); throttle_group_co_io_limits_intercept(tgm, bytes, true);
@ -135,7 +133,7 @@ static int coroutine_fn throttle_co_pwritev(BlockDriverState *bs,
} }
static int coroutine_fn throttle_co_pwrite_zeroes(BlockDriverState *bs, static int coroutine_fn throttle_co_pwrite_zeroes(BlockDriverState *bs,
int64_t offset, int64_t bytes, int64_t offset, int bytes,
BdrvRequestFlags flags) BdrvRequestFlags flags)
{ {
ThrottleGroupMember *tgm = bs->opaque; ThrottleGroupMember *tgm = bs->opaque;
@ -145,7 +143,7 @@ static int coroutine_fn throttle_co_pwrite_zeroes(BlockDriverState *bs,
} }
static int coroutine_fn throttle_co_pdiscard(BlockDriverState *bs, static int coroutine_fn throttle_co_pdiscard(BlockDriverState *bs,
int64_t offset, int64_t bytes) int64_t offset, int bytes)
{ {
ThrottleGroupMember *tgm = bs->opaque; ThrottleGroupMember *tgm = bs->opaque;
throttle_group_co_io_limits_intercept(tgm, bytes, true); throttle_group_co_io_limits_intercept(tgm, bytes, true);
@ -154,8 +152,8 @@ static int coroutine_fn throttle_co_pdiscard(BlockDriverState *bs,
} }
static int coroutine_fn throttle_co_pwritev_compressed(BlockDriverState *bs, static int coroutine_fn throttle_co_pwritev_compressed(BlockDriverState *bs,
int64_t offset, uint64_t offset,
int64_t bytes, uint64_t bytes,
QEMUIOVector *qiov) QEMUIOVector *qiov)
{ {
return throttle_co_pwritev(bs, offset, bytes, qiov, return throttle_co_pwritev(bs, offset, bytes, qiov,

View File

@ -5,8 +5,8 @@ bdrv_open_common(void *bs, const char *filename, int flags, const char *format_n
bdrv_lock_medium(void *bs, bool locked) "bs %p locked %d" bdrv_lock_medium(void *bs, bool locked) "bs %p locked %d"
# block-backend.c # block-backend.c
blk_co_preadv(void *blk, void *bs, int64_t offset, int64_t bytes, int flags) "blk %p bs %p offset %"PRId64" bytes %" PRId64 " flags 0x%x" blk_co_preadv(void *blk, void *bs, int64_t offset, unsigned int bytes, int flags) "blk %p bs %p offset %"PRId64" bytes %u flags 0x%x"
blk_co_pwritev(void *blk, void *bs, int64_t offset, int64_t bytes, int flags) "blk %p bs %p offset %"PRId64" bytes %" PRId64 " flags 0x%x" blk_co_pwritev(void *blk, void *bs, int64_t offset, unsigned int bytes, int flags) "blk %p bs %p offset %"PRId64" bytes %u flags 0x%x"
blk_root_attach(void *child, void *blk, void *bs) "child %p blk %p bs %p" blk_root_attach(void *child, void *blk, void *bs) "child %p blk %p bs %p"
blk_root_detach(void *child, void *blk, void *bs) "child %p blk %p bs %p" blk_root_detach(void *child, void *blk, void *bs) "child %p blk %p bs %p"
@ -75,13 +75,13 @@ luring_resubmit_short_read(void *s, void *luringcb, int nread) "LuringState %p l
# qcow2.c # qcow2.c
qcow2_add_task(void *co, void *bs, void *pool, const char *action, int cluster_type, uint64_t host_offset, uint64_t offset, uint64_t bytes, void *qiov, size_t qiov_offset) "co %p bs %p pool %p: %s: cluster_type %d file_cluster_offset %" PRIu64 " offset %" PRIu64 " bytes %" PRIu64 " qiov %p qiov_offset %zu" qcow2_add_task(void *co, void *bs, void *pool, const char *action, int cluster_type, uint64_t host_offset, uint64_t offset, uint64_t bytes, void *qiov, size_t qiov_offset) "co %p bs %p pool %p: %s: cluster_type %d file_cluster_offset %" PRIu64 " offset %" PRIu64 " bytes %" PRIu64 " qiov %p qiov_offset %zu"
qcow2_writev_start_req(void *co, int64_t offset, int64_t bytes) "co %p offset 0x%" PRIx64 " bytes %" PRId64 qcow2_writev_start_req(void *co, int64_t offset, int bytes) "co %p offset 0x%" PRIx64 " bytes %d"
qcow2_writev_done_req(void *co, int ret) "co %p ret %d" qcow2_writev_done_req(void *co, int ret) "co %p ret %d"
qcow2_writev_start_part(void *co) "co %p" qcow2_writev_start_part(void *co) "co %p"
qcow2_writev_done_part(void *co, int cur_bytes) "co %p cur_bytes %d" qcow2_writev_done_part(void *co, int cur_bytes) "co %p cur_bytes %d"
qcow2_writev_data(void *co, uint64_t offset) "co %p offset 0x%" PRIx64 qcow2_writev_data(void *co, uint64_t offset) "co %p offset 0x%" PRIx64
qcow2_pwrite_zeroes_start_req(void *co, int64_t offset, int64_t bytes) "co %p offset 0x%" PRIx64 " bytes %" PRId64 qcow2_pwrite_zeroes_start_req(void *co, int64_t offset, int count) "co %p offset 0x%" PRIx64 " count %d"
qcow2_pwrite_zeroes(void *co, int64_t offset, int64_t bytes) "co %p offset 0x%" PRIx64 " bytes %" PRId64 qcow2_pwrite_zeroes(void *co, int64_t offset, int count) "co %p offset 0x%" PRIx64 " count %d"
qcow2_skip_cow(void *co, uint64_t offset, int nb_clusters) "co %p offset 0x%" PRIx64 " nb_clusters %d" qcow2_skip_cow(void *co, uint64_t offset, int nb_clusters) "co %p offset 0x%" PRIx64 " nb_clusters %d"
# qcow2-cluster.c # qcow2-cluster.c
@ -152,12 +152,12 @@ nvme_write_zeroes(void *s, uint64_t offset, uint64_t bytes, int flags) "s %p off
nvme_qiov_unaligned(const void *qiov, int n, void *base, size_t size, int align) "qiov %p n %d base %p size 0x%zx align 0x%x" nvme_qiov_unaligned(const void *qiov, int n, void *base, size_t size, int align) "qiov %p n %d base %p size 0x%zx align 0x%x"
nvme_prw_buffered(void *s, uint64_t offset, uint64_t bytes, int niov, int is_write) "s %p offset 0x%"PRIx64" bytes %"PRId64" niov %d is_write %d" nvme_prw_buffered(void *s, uint64_t offset, uint64_t bytes, int niov, int is_write) "s %p offset 0x%"PRIx64" bytes %"PRId64" niov %d is_write %d"
nvme_rw_done(void *s, int is_write, uint64_t offset, uint64_t bytes, int ret) "s %p is_write %d offset 0x%"PRIx64" bytes %"PRId64" ret %d" nvme_rw_done(void *s, int is_write, uint64_t offset, uint64_t bytes, int ret) "s %p is_write %d offset 0x%"PRIx64" bytes %"PRId64" ret %d"
nvme_dsm(void *s, int64_t offset, int64_t bytes) "s %p offset 0x%"PRIx64" bytes %"PRId64"" nvme_dsm(void *s, uint64_t offset, uint64_t bytes) "s %p offset 0x%"PRIx64" bytes %"PRId64""
nvme_dsm_done(void *s, int64_t offset, int64_t bytes, int ret) "s %p offset 0x%"PRIx64" bytes %"PRId64" ret %d" nvme_dsm_done(void *s, uint64_t offset, uint64_t bytes, int ret) "s %p offset 0x%"PRIx64" bytes %"PRId64" ret %d"
nvme_dma_map_flush(void *s) "s %p" nvme_dma_map_flush(void *s) "s %p"
nvme_free_req_queue_wait(void *s, unsigned q_index) "s %p q #%u" nvme_free_req_queue_wait(void *s, unsigned q_index) "s %p q #%u"
nvme_create_queue_pair(unsigned q_index, void *q, size_t size, void *aio_context, int fd) "index %u q %p size %zu aioctx %p fd %d" nvme_create_queue_pair(unsigned q_index, void *q, unsigned size, void *aio_context, int fd) "index %u q %p size %u aioctx %p fd %d"
nvme_free_queue_pair(unsigned q_index, void *q, void *cq, void *sq) "index %u q %p cq %p sq %p" nvme_free_queue_pair(unsigned q_index, void *q) "index %u q %p"
nvme_cmd_map_qiov(void *s, void *cmd, void *req, void *qiov, int entries) "s %p cmd %p req %p qiov %p entries %d" nvme_cmd_map_qiov(void *s, void *cmd, void *req, void *qiov, int entries) "s %p cmd %p req %p qiov %p entries %d"
nvme_cmd_map_qiov_pages(void *s, int i, uint64_t page) "s %p page[%d] 0x%"PRIx64 nvme_cmd_map_qiov_pages(void *s, int i, uint64_t page) "s %p page[%d] 0x%"PRIx64
nvme_cmd_map_qiov_iov(void *s, int i, void *page, int pages) "s %p iov[%d] %p pages %d" nvme_cmd_map_qiov_iov(void *s, int i, void *page, int pages) "s %p iov[%d] %p pages %d"

View File

@ -544,8 +544,8 @@ static int coroutine_fn vdi_co_block_status(BlockDriverState *bs,
} }
static int coroutine_fn static int coroutine_fn
vdi_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, vdi_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, BdrvRequestFlags flags) QEMUIOVector *qiov, int flags)
{ {
BDRVVdiState *s = bs->opaque; BDRVVdiState *s = bs->opaque;
QEMUIOVector local_qiov; QEMUIOVector local_qiov;
@ -600,8 +600,8 @@ vdi_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
} }
static int coroutine_fn static int coroutine_fn
vdi_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, vdi_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, BdrvRequestFlags flags) QEMUIOVector *qiov, int flags)
{ {
BDRVVdiState *s = bs->opaque; BDRVVdiState *s = bs->opaque;
QEMUIOVector local_qiov; QEMUIOVector local_qiov;

View File

@ -60,7 +60,6 @@
#define VMDK_ZEROED (-3) #define VMDK_ZEROED (-3)
#define BLOCK_OPT_ZEROED_GRAIN "zeroed_grain" #define BLOCK_OPT_ZEROED_GRAIN "zeroed_grain"
#define BLOCK_OPT_TOOLSVERSION "toolsversion"
typedef struct { typedef struct {
uint32_t version; uint32_t version;
@ -1889,8 +1888,8 @@ static int vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset,
} }
static int coroutine_fn static int coroutine_fn
vmdk_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, vmdk_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, BdrvRequestFlags flags) QEMUIOVector *qiov, int flags)
{ {
BDRVVmdkState *s = bs->opaque; BDRVVmdkState *s = bs->opaque;
int ret; int ret;
@ -2069,8 +2068,8 @@ static int vmdk_pwritev(BlockDriverState *bs, uint64_t offset,
} }
static int coroutine_fn static int coroutine_fn
vmdk_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, vmdk_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov, BdrvRequestFlags flags) QEMUIOVector *qiov, int flags)
{ {
int ret; int ret;
BDRVVmdkState *s = bs->opaque; BDRVVmdkState *s = bs->opaque;
@ -2081,8 +2080,8 @@ vmdk_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
} }
static int coroutine_fn static int coroutine_fn
vmdk_co_pwritev_compressed(BlockDriverState *bs, int64_t offset, int64_t bytes, vmdk_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
QEMUIOVector *qiov) uint64_t bytes, QEMUIOVector *qiov)
{ {
if (bytes == 0) { if (bytes == 0) {
/* The caller will write bytes 0 to signal EOF. /* The caller will write bytes 0 to signal EOF.
@ -2110,7 +2109,7 @@ vmdk_co_pwritev_compressed(BlockDriverState *bs, int64_t offset, int64_t bytes,
static int coroutine_fn vmdk_co_pwrite_zeroes(BlockDriverState *bs, static int coroutine_fn vmdk_co_pwrite_zeroes(BlockDriverState *bs,
int64_t offset, int64_t offset,
int64_t bytes, int bytes,
BdrvRequestFlags flags) BdrvRequestFlags flags)
{ {
int ret; int ret;
@ -2345,7 +2344,6 @@ static int coroutine_fn vmdk_co_do_create(int64_t size,
BlockdevVmdkAdapterType adapter_type, BlockdevVmdkAdapterType adapter_type,
const char *backing_file, const char *backing_file,
const char *hw_version, const char *hw_version,
const char *toolsversion,
bool compat6, bool compat6,
bool zeroed_grain, bool zeroed_grain,
vmdk_create_extent_fn extent_fn, vmdk_create_extent_fn extent_fn,
@ -2386,8 +2384,7 @@ static int coroutine_fn vmdk_co_do_create(int64_t size,
"ddb.geometry.cylinders = \"%" PRId64 "\"\n" "ddb.geometry.cylinders = \"%" PRId64 "\"\n"
"ddb.geometry.heads = \"%" PRIu32 "\"\n" "ddb.geometry.heads = \"%" PRIu32 "\"\n"
"ddb.geometry.sectors = \"63\"\n" "ddb.geometry.sectors = \"63\"\n"
"ddb.adapterType = \"%s\"\n" "ddb.adapterType = \"%s\"\n";
"ddb.toolsVersion = \"%s\"\n";
ext_desc_lines = g_string_new(NULL); ext_desc_lines = g_string_new(NULL);
@ -2404,9 +2401,6 @@ static int coroutine_fn vmdk_co_do_create(int64_t size,
if (!hw_version) { if (!hw_version) {
hw_version = "4"; hw_version = "4";
} }
if (!toolsversion) {
toolsversion = "2147483647";
}
if (adapter_type != BLOCKDEV_VMDK_ADAPTER_TYPE_IDE) { if (adapter_type != BLOCKDEV_VMDK_ADAPTER_TYPE_IDE) {
/* that's the number of heads with which vmware operates when /* that's the number of heads with which vmware operates when
@ -2531,8 +2525,7 @@ static int coroutine_fn vmdk_co_do_create(int64_t size,
size / size /
(int64_t)(63 * number_heads * BDRV_SECTOR_SIZE), (int64_t)(63 * number_heads * BDRV_SECTOR_SIZE),
number_heads, number_heads,
BlockdevVmdkAdapterType_str(adapter_type), BlockdevVmdkAdapterType_str(adapter_type));
toolsversion);
desc_len = strlen(desc); desc_len = strlen(desc);
/* the descriptor offset = 0x200 */ /* the descriptor offset = 0x200 */
if (!split && !flat) { if (!split && !flat) {
@ -2624,7 +2617,6 @@ static int coroutine_fn vmdk_co_create_opts(BlockDriver *drv,
BlockdevVmdkAdapterType adapter_type_enum; BlockdevVmdkAdapterType adapter_type_enum;
char *backing_file = NULL; char *backing_file = NULL;
char *hw_version = NULL; char *hw_version = NULL;
char *toolsversion = NULL;
char *fmt = NULL; char *fmt = NULL;
BlockdevVmdkSubformat subformat; BlockdevVmdkSubformat subformat;
int ret = 0; int ret = 0;
@ -2657,7 +2649,6 @@ static int coroutine_fn vmdk_co_create_opts(BlockDriver *drv,
adapter_type = qemu_opt_get_del(opts, BLOCK_OPT_ADAPTER_TYPE); adapter_type = qemu_opt_get_del(opts, BLOCK_OPT_ADAPTER_TYPE);
backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE); backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);
hw_version = qemu_opt_get_del(opts, BLOCK_OPT_HWVERSION); hw_version = qemu_opt_get_del(opts, BLOCK_OPT_HWVERSION);
toolsversion = qemu_opt_get_del(opts, BLOCK_OPT_TOOLSVERSION);
compat6 = qemu_opt_get_bool_del(opts, BLOCK_OPT_COMPAT6, false); compat6 = qemu_opt_get_bool_del(opts, BLOCK_OPT_COMPAT6, false);
if (strcmp(hw_version, "undefined") == 0) { if (strcmp(hw_version, "undefined") == 0) {
g_free(hw_version); g_free(hw_version);
@ -2701,15 +2692,14 @@ static int coroutine_fn vmdk_co_create_opts(BlockDriver *drv,
.opts = opts, .opts = opts,
}; };
ret = vmdk_co_do_create(total_size, subformat, adapter_type_enum, ret = vmdk_co_do_create(total_size, subformat, adapter_type_enum,
backing_file, hw_version, toolsversion, compat6, backing_file, hw_version, compat6, zeroed_grain,
zeroed_grain, vmdk_co_create_opts_cb, &data, errp); vmdk_co_create_opts_cb, &data, errp);
exit: exit:
g_free(backing_fmt); g_free(backing_fmt);
g_free(adapter_type); g_free(adapter_type);
g_free(backing_file); g_free(backing_file);
g_free(hw_version); g_free(hw_version);
g_free(toolsversion);
g_free(fmt); g_free(fmt);
g_free(desc); g_free(desc);
g_free(path); g_free(path);
@ -2792,7 +2782,6 @@ static int coroutine_fn vmdk_co_create(BlockdevCreateOptions *create_options,
opts->adapter_type, opts->adapter_type,
opts->backing_file, opts->backing_file,
opts->hwversion, opts->hwversion,
opts->toolsversion,
false, false,
opts->zeroed_grain, opts->zeroed_grain,
vmdk_co_create_cb, vmdk_co_create_cb,
@ -3042,11 +3031,6 @@ static QemuOptsList vmdk_create_opts = {
.help = "VMDK hardware version", .help = "VMDK hardware version",
.def_value_str = "undefined" .def_value_str = "undefined"
}, },
{
.name = BLOCK_OPT_TOOLSVERSION,
.type = QEMU_OPT_STRING,
.help = "VMware guest tools version",
},
{ {
.name = BLOCK_OPT_SUBFMT, .name = BLOCK_OPT_SUBFMT,
.type = QEMU_OPT_STRING, .type = QEMU_OPT_STRING,

Some files were not shown because too many files have changed in this diff Show More