Compare commits

..

34 Commits

Author SHA1 Message Date
Fabiano Rosas
1840319498 tests/qtest: Add a test for migration with direct-io and multifd
Signed-off-by: Fabiano Rosas <farosas@suse.de>
2023-10-20 10:32:56 -03:00
Fabiano Rosas
bc955a8851 migration: Add direct-io parameter
Add the direct-io migration parameter that tells the migration code to
use O_DIRECT when opening the migration stream file whenever possible.

This is currently only used for the secondary channels of fixed-ram
migration, which can guarantee that writes are page aligned.

However the parameter could be made to affect other types of
file-based migrations in the future.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
2023-10-20 10:32:56 -03:00
Fabiano Rosas
1f7ba58d38 tests/qtest: Add a multifd + fixed-ram migration test
Signed-off-by: Fabiano Rosas <farosas@suse.de>
2023-10-20 10:32:56 -03:00
Fabiano Rosas
753f7a1fda migration/multifd: Support incoming fixed-ram stream format
For the incoming fixed-ram migration we need to read the ramblock
headers, get the pages bitmap and send the host address of each
non-zero page to the multifd channel thread for writing.

To read from the migration file we need a preadv function that can
read into the iovs in segments of contiguous pages because (as in the
writing case) the file offset applies to the entire iovec.

Usage on HMP is:

(qemu) migrate_set_capability multifd on
(qemu) migrate_set_capability fixed-ram on
(qemu) migrate_set_parameter max-bandwidth 0
(qemu) migrate_set_parameter multifd-channels 8
(qemu) migrate_incoming file:migfile
(qemu) info status
(qemu) c

Signed-off-by: Fabiano Rosas <farosas@suse.de>
2023-10-20 10:32:56 -03:00
Fabiano Rosas
76f10251fb migration/multifd: Support outgoing fixed-ram stream format
The new fixed-ram stream format uses a file transport and puts ram
pages in the migration file at their respective offsets and can be
done in parallel by using the pwritev system call which takes iovecs
and an offset.

Add support to enabling the new format along with multifd to make use
of the threading and page handling already in place.

This requires multifd to stop sending headers and leaving the stream
format to the fixed-ram code. When it comes time to write the data, we
need to call a version of qio_channel_write that can take an offset.

Usage on HMP is:

(qemu) stop
(qemu) migrate_set_capability multifd on
(qemu) migrate_set_capability fixed-ram on
(qemu) migrate_set_parameter max-bandwidth 0
(qemu) migrate_set_parameter multifd-channels 8
(qemu) migrate file:migfile

Signed-off-by: Fabiano Rosas <farosas@suse.de>
2023-10-20 10:32:54 -03:00
Fabiano Rosas
1f9e15b3fc migration/ram: Ignore multifd flush when doing fixed-ram migration
Some functionalities of multifd are incompatible with the 'fixed-ram'
migration format.

The MULTIFD_FLUSH flag in particular is not used because in fixed-ram
there is no sinchronicity between migration source and destination so
there is not need for a sync packet. In fact, fixed-ram disables
packets in multifd as a whole.

Make sure RAM_SAVE_FLAG_MULTIFD_FLUSH is never emitted when fixed-ram
is enabled.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
2023-10-20 10:32:39 -03:00
Fabiano Rosas
3b3c62d980 migration/ram: Add a wrapper for fixed-ram shadow bitmap
We'll need to set the shadow_bmap bits from outside ram.c soon and
TARGET_PAGE_BITS is poisoned, so add a wrapper to it.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
2023-10-20 10:32:39 -03:00
Fabiano Rosas
c896325abd io: Add a pwritev/preadv version that takes a discontiguous iovec
For the upcoming support to fixed-ram migration with multifd, we need
to be able to accept an iovec array with non-contiguous data.

Add a pwritev and preadv version that splits the array into contiguous
segments before writing. With that we can have the ram code continue
to add pages in any order and the multifd code continue to send large
arrays for reading and writing.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
Since iovs can be non contiguous, we'd need a separate array on the
side to carry an extra file offset for each of them, so I'm relying on
the fact that iovs are all within a same host page and passing in an
encoded offset that takes the host page into account.
2023-10-20 10:32:38 -03:00
Fabiano Rosas
81fb46a8ca migration/multifd: Add pages to the receiving side
Currently multifd does not need to have knowledge of pages on the
receiving side because all the information needed is within the
packets that come in the stream.

We're about to add support to fixed-ram migration, which cannot use
packets because it expects the ramblock section in the migration file
to contain only the guest pages data.

Add a pointer to MultiFDPages in the multifd_recv_state and use the
pages similarly to what we already do on the sending side. The pages
are used to transfer data between the ram migration code in the main
migration thread and the multifd receiving threads.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
2023-10-20 10:32:38 -03:00
Fabiano Rosas
09bda0fd7e migration/multifd: Add incoming QIOChannelFile support
On the receiving side we don't need to differentiate between main
channel and threads, so whichever channel is defined first gets to be
the main one. And since there are no packets, use the atomic channel
count to index into the params array.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
2023-10-20 10:32:38 -03:00
Fabiano Rosas
a7bcfd06be migration/multifd: Add outgoing QIOChannelFile support
Allow multifd to open file-backed channels. This will be used when
enabling the fixed-ram migration stream format which expects a
seekable transport.

The QIOChannel read and write methods will use the preadv/pwritev
versions which don't update the file offset at each call so we can
reuse the fd without re-opening for every channel.

Note that this is just setup code and multifd cannot yet make use of
the file channels.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
2023-10-20 10:32:38 -03:00
Fabiano Rosas
7e96d0e65a migration/multifd: Allow multifd without packets
For the upcoming support to the new 'fixed-ram' migration stream
format, we cannot use multifd packets because each write into the
ramblock section in the migration file is expected to contain only the
guest pages. They are written at their respective offsets relative to
the ramblock section header.

There is no space for the packet information and the expected gains
from the new approach come partly from being able to write the pages
sequentially without extraneous data in between.

The new format also doesn't need the packets and all necessary
information can be taken from the standard migration headers with some
(future) changes to multifd code.

Use the presence of the fixed-ram capability to decide whether to send
packets. For now this has no effect as fixed-ram cannot yet be enabled
with multifd.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
2023-10-20 10:32:38 -03:00
Fabiano Rosas
9cf5d9881e migration/multifd: Extract sem_done waiting into a function
This helps document the intent of the loop via the function name and
we can reuse this in the future.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
2023-10-20 10:32:38 -03:00
Fabiano Rosas
608dcba7b6 migration/multifd: Decouple control flow from the SYNC packet
We currently have the sem_sync semaphore that is used:

1) on the sending side, to know when the multifd_send_thread has
   finished sending the MULTIFD_FLAG_SYNC packet;

  This is unnecessary. Multifd sends packets (not pages) one by one
  and completion is already bound by both the channels_ready and sem
  semaphores. The SYNC packet has nothing special that would require
  it to have a separate semaphore on the sending side.

2) on the receiving side, to know when the multifd_recv_thread has
   finished receiving the MULTIFD_FLAG_SYNC packet;

  This is unnecessary because the multifd_recv_state->sem_sync
  semaphore already does the same thing. We care that the SYNC arrived
  from the source, knowing that the SYNC has been received by the recv
  thread doesn't add anything.

3) on both sending and receiving sides, to wait for the multifd threads
   to finish before cleaning up;

   This happens because multifd_send_sync_main() blocks
   ram_save_complete() from finishing until the semaphore is
   posted. This is surprising and not documented.

Clarify the above situation by renaming 'sem_sync' to 'sem_done' and
making the #3 usage the main one. Stop tracking the SYNC packet on
source (#1) and leave multifd_recv_state->sem_sync untouched on the
destination (#2).

Due to the 'channels_ready' and 'sem' semaphores, we always send
packets in lockstep with switching MultiFDSendParams, so
p->pending_job is always either 1 or 0. The thread has no knowledge of
whether it will have more to send once it posts to
channels_ready. Send it on an extra loop so it sees no pending_job and
releases the semaphore.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
2023-10-20 10:32:38 -03:00
Fabiano Rosas
766947c46a migration/multifd: Move channels_ready semaphore
Commit d2026ee117 ("multifd: Fix the number of channels ready") moved
the "post" of channels_ready to the start of the multifd_send_thread()
loop and added a missing "wait" at multifd_send_sync_main(). While it
does work, the placement of the wait goes against what the rest of the
code does.

The sequence at multifd_send_thread() is:

    qemu_sem_post(&multifd_send_state->channels_ready);
    qemu_sem_wait(&p->sem);
    <work>
    if (flags & MULTIFD_FLAG_SYNC) {
        qemu_sem_post(&p->sem_sync);
    }

Which means that the sending thread makes itself available
(channels_ready) and waits for more work (sem). So the sequence in the
migration thread should be to check if any channel is available
(channels_ready), give it some work and set it off (sem):

    qemu_sem_wait(&multifd_send_state->channels_ready);
    <enqueue work>
    qemu_sem_post(&p->sem);
    if (flags & MULTIFD_FLAG_SYNC) {
        qemu_sem_wait(&p->sem_sync);
    }

The reason there's no deadlock today is that the migration thread
enqueues the SYNC packet right before the wait on channels_ready and
we end up taking advantage of the out-of-order post to sem:

        ...
        qemu_sem_post(&p->sem);
    }
    for (i = 0; i < migrate_multifd_channels(); i++) {
        MultiFDSendParams *p = &multifd_send_state->params[i];

        qemu_sem_wait(&multifd_send_state->channels_ready);
        trace_multifd_send_sync_main_wait(p->id);
        qemu_sem_wait(&p->sem_sync);
	...

Move the channels_ready wait before the sem post to keep the sequence
consistent. Also fix the error path to post to channels_ready and
sem_sync in the correct order.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
2023-10-20 10:32:38 -03:00
Fabiano Rosas
5dcb74fe5b migration: Add completion tracepoint
Add a completion tracepoint that provides basic stats for
debug. Displays throughput (MB/s and pages/s) and total time (ms).

Usage:
  $QEMU ... -trace migration_status

Output:
  migration_status 1506 MB/s, 436725 pages/s, 8698 ms

Signed-off-by: Fabiano Rosas <farosas@suse.de>
2023-10-20 10:32:37 -03:00
Nikolay Borisov
9d0a611c97 tests/qtest: migration-test: Add tests for fixed-ram file-based migration
Add basic tests for 'fixed-ram' migration.

Signed-off-by: Nikolay Borisov <nborisov@suse.com>
Signed-off-by: Fabiano Rosas <farosas@suse.de>
2023-10-20 10:32:37 -03:00
Nikolay Borisov
9d3d829cd4 migration/ram: Add support for 'fixed-ram' migration restore
Add the necessary code to parse the format changes for the 'fixed-ram'
capability.

One of the more notable changes in behavior is that in the 'fixed-ram'
case ram pages are restored in one go rather than constantly looping
through the migration stream.

Signed-off-by: Nikolay Borisov <nborisov@suse.com>
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
(farosas) reused more of the common code by making the fixed-ram
function take only one ramblock and calling it from inside
parse_ramblock.
2023-10-20 10:32:37 -03:00
Nikolay Borisov
8e24e8362f migration/ram: Add support for 'fixed-ram' outgoing migration
Implement the outgoing migration side for the 'fixed-ram' capability.

A bitmap is introduced to track which pages have been written in the
migration file. Pages are written at a fixed location for every
ramblock. Zero pages are ignored as they'd be zero in the destination
migration as well.

The migration stream is altered to put the dirty pages for a ramblock
after its header instead of having a sequential stream of pages that
follow the ramblock headers. Since all pages have a fixed location,
RAM_SAVE_FLAG_EOS is no longer generated on every migration iteration.

Without fixed-ram (current):

ramblock 1 header|ramblock 2 header|...|RAM_SAVE_FLAG_EOS|stream of
 pages (iter 1)|RAM_SAVE_FLAG_EOS|stream of pages (iter 2)|...

With fixed-ram (new):

ramblock 1 header|ramblock 1 fixed-ram header|ramblock 1 pages (fixed
 offsets)|ramblock 2 header|ramblock 2 fixed-ram header|ramblock 2
 pages (fixed offsets)|...|RAM_SAVE_FLAG_EOS

where:
 - ramblock header: the generic information for a ramblock, such as
   idstr, used_len, etc.

 - ramblock fixed-ram header: the new information added by this
   feature: bitmap of pages written, bitmap size and offset of pages
   in the migration file.

Signed-off-by: Nikolay Borisov <nborisov@suse.com>
Signed-off-by: Fabiano Rosas <farosas@suse.de>
2023-10-20 10:32:35 -03:00
Fabiano Rosas
0e48ba2ba3 migration/ram: Introduce 'fixed-ram' migration capability
Add a new migration capability 'fixed-ram'.

The core of the feature is to ensure that each ram page has a specific
offset in the resulting migration stream. The reason why we'd want
such behavior are two fold:

 - When doing a 'fixed-ram' migration the resulting file will have a
   bounded size, since pages which are dirtied multiple times will
   always go to a fixed location in the file, rather than constantly
   being added to a sequential stream. This eliminates cases where a vm
   with, say, 1G of ram can result in a migration file that's 10s of
   GBs, provided that the workload constantly redirties memory.

 - It paves the way to implement DIRECT_IO-enabled save/restore of the
   migration stream as the pages are ensured to be written at aligned
   offsets.

For now, enabling the capability has no effect. The next couple of
patches implement the core funcionality.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
2023-10-20 10:25:29 -03:00
Fabiano Rosas
c1605a937f migration: fixed-ram: Add URI compatibility check
The fixed-ram migration format needs a channel that supports seeking
to be able to write each page to an arbitrary offset in the migration
stream.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
2023-10-20 10:25:28 -03:00
Nikolay Borisov
ed84f4666a migration/qemu-file: add utility methods for working with seekable channels
Add utility methods that will be needed when implementing 'fixed-ram'
migration capability.

qemu_file_is_seekable
qemu_put_buffer_at
qemu_get_buffer_at
qemu_set_offset
qemu_get_offset

Signed-off-by: Nikolay Borisov <nborisov@suse.com>
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
fixed total_transferred accounting

restructured to use qio_channel_file_preadv instead of the _full
variant
2023-10-20 10:25:26 -03:00
Nikolay Borisov
453dffb218 io: implement io_pwritev/preadv for QIOChannelFile
The upcoming 'fixed-ram' feature will require qemu to write data to
(and restore from) specific offsets of the migration file.

Add a minimal implementation of pwritev/preadv and expose them via the
io_pwritev and io_preadv interfaces.

Signed-off-by: Nikolay Borisov <nborisov@suse.com>
Signed-off-by: Fabiano Rosas <farosas@suse.de>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
2023-10-20 10:25:04 -03:00
Nikolay Borisov
08a135824a io: Add generic pwritev/preadv interface
Introduce basic pwritev/preadv support in the generic channel layer.
Specific implementation will follow for the file channel as this is
required in order to support migration streams with fixed location of
each ram page.

Signed-off-by: Nikolay Borisov <nborisov@suse.com>
Signed-off-by: Fabiano Rosas <farosas@suse.de>
2023-10-20 10:25:04 -03:00
Nikolay Borisov
67371217bc io: add and implement QIO_CHANNEL_FEATURE_SEEKABLE for channel file
Add a generic QIOChannel feature SEEKABLE which would be used by the
qemu_file* apis. For the time being this will be only implemented for
file channels.

Signed-off-by: Nikolay Borisov <nborisov@suse.com>
Signed-off-by: Fabiano Rosas <farosas@suse.de>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
2023-10-20 10:25:04 -03:00
Fabiano Rosas
bcbbf4fad3 tests/qtest: File migration auto-pause tests
Adapt the file migration tests to take into account the auto-pause
feature.

The test currently has a flag 'stop_src' that is used to know if the
test itself should stop the VM. Add a new flag 'auto_pause' to enable
QEMU to stop the VM instead.. The two in combination allow us to
migrate a already stopped VM and check that it is still stopped on the
destination (auto-pause in effect restoring the original state).

By adding a more precise tracking of migration state changes, we can
also make sure that auto-pause is actually stopping the VM right after
qmp_migrate(), as opposed to the vm_stop() that happens at
migration_complete().

When resuming the destination a similar situation occurs, we use
'stop_src' to have a stopped VM and check that the destination does
not get a "resume" event.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
2023-10-20 10:25:04 -03:00
Fabiano Rosas
87f965378e migration: Run "file:" migration with a stopped VM
The file migration is asynchronous, so it benefits from being done
with a stopped VM. Allow the file migration to take benefit of the
auto-pause capability.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
2023-10-20 10:25:04 -03:00
Fabiano Rosas
5e984cac37 migration: Add auto-pause capability
Add a capability that allows the management layer to delegate to QEMU
the decision of whether to pause a VM and perform a non-live
migration. Depending on the type of migration being performed, this
could bring performance benefits.

Note that the capability is enabled by default but at this moment no
migration scheme is making use of it.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
2023-10-20 10:25:04 -03:00
Fabiano Rosas
583920ec39 migration: Introduce global_state_store_once
There are some situations during migration when we want to change the
runstate of the VM, but don't actually want the new runstate to be put
on the wire to be restored on the destination VM. In those cases, the
pattern is to use global_state_store() to save the state for migration
before changing it.

One scenario where this happens is when switching the source VM into
the FINISH_MIGRATE state. This state only makes sense on the source
VM. Another situation is when pausing the source VM prior to migration
completion.

We are about to introduce a third scenario when the whole migration
should be performed with a paused VM. In this case we will want to
save the VM runstate at the very start of the migration and that state
will be the one restored on the destination regardless of all the
runstate changes that happen in between.

To achieve that we need to make sure that the other two calls to
global_state_store() do not overwrite the state that is to be
migrated.

Introduce a version of global_state_store() that only saves the state
if no other state has already been saved.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
2023-10-20 10:25:01 -03:00
Fabiano Rosas
556772609b migration: Return the saved state from global_state_store
There is a pattern of calling runstate_get() to store the current
runstate and calling global_state_store() to save the current runstate
for migration. Since global_state_store() also calls runstate_get(),
make it return the runstate instead.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
2023-10-20 10:24:38 -03:00
Fabiano Rosas
4672ce13f5 tests/qtest: Allow waiting for migration events
Add support for waiting for a migration state change event to
happen. This can help disambiguate between runstate changes that
happen during VM lifecycle.

Specifically, the next couple of patches want to know whether STOP
events happened at the migration start or end. Add the "setup" and
"active" migration states for that purpose.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
2023-10-20 10:23:54 -03:00
Fabiano Rosas
52d4dd925a tests/qtest: Move QTestMigrationState to libqtest
Move the QTestMigrationState into QTestState so we don't have to pass
it around to the wait_for_* helpers anymore. Since QTestState is
private to libqtest.c, move the migration state struct to libqtest.h
and add a getter.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
2023-10-20 10:23:54 -03:00
Steve Sistare
7ca75f79af tests/qtest: migration events
Define a state object to capture events seen by migration tests, to allow
more events to be captured in a subsequent patch, and simplify event
checking in wait_for_migration_pass.  No functional change.

Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
2023-10-20 10:23:54 -03:00
Fabiano Rosas
6b0e07b270 tests/qtest: Re-enable multifd cancel test
We've found the source of flakiness in this test, so re-enable it.

Reviewed-by: Juan Quintela <quintela@redhat.com>
Signed-off-by: Fabiano Rosas <farosas@suse.de>
2023-10-20 10:23:21 -03:00
1122 changed files with 22848 additions and 47319 deletions

View File

@@ -256,7 +256,6 @@ build-user:
variables: variables:
IMAGE: debian-all-test-cross IMAGE: debian-all-test-cross
CONFIGURE_ARGS: --disable-tools --disable-system CONFIGURE_ARGS: --disable-tools --disable-system
--target-list-exclude=alpha-linux-user,sh4-linux-user
MAKE_CHECK_ARGS: check-tcg MAKE_CHECK_ARGS: check-tcg
build-user-static: build-user-static:
@@ -266,18 +265,6 @@ build-user-static:
variables: variables:
IMAGE: debian-all-test-cross IMAGE: debian-all-test-cross
CONFIGURE_ARGS: --disable-tools --disable-system --static CONFIGURE_ARGS: --disable-tools --disable-system --static
--target-list-exclude=alpha-linux-user,sh4-linux-user
MAKE_CHECK_ARGS: check-tcg
# targets stuck on older compilers
build-legacy:
extends: .native_build_job_template
needs:
job: amd64-debian-legacy-cross-container
variables:
IMAGE: debian-legacy-test-cross
TARGETS: alpha-linux-user alpha-softmmu sh4-linux-user
CONFIGURE_ARGS: --disable-tools
MAKE_CHECK_ARGS: check-tcg MAKE_CHECK_ARGS: check-tcg
build-user-hexagon: build-user-hexagon:
@@ -290,9 +277,7 @@ build-user-hexagon:
CONFIGURE_ARGS: --disable-tools --disable-docs --enable-debug-tcg CONFIGURE_ARGS: --disable-tools --disable-docs --enable-debug-tcg
MAKE_CHECK_ARGS: check-tcg MAKE_CHECK_ARGS: check-tcg
# Build the softmmu targets we have check-tcg tests and compilers in # Only build the softmmu targets we have check-tcg tests for
# our omnibus all-test-cross container. Those targets that haven't got
# Debian cross compiler support need to use special containers.
build-some-softmmu: build-some-softmmu:
extends: .native_build_job_template extends: .native_build_job_template
needs: needs:
@@ -300,18 +285,7 @@ build-some-softmmu:
variables: variables:
IMAGE: debian-all-test-cross IMAGE: debian-all-test-cross
CONFIGURE_ARGS: --disable-tools --enable-debug CONFIGURE_ARGS: --disable-tools --enable-debug
TARGETS: arm-softmmu aarch64-softmmu i386-softmmu riscv64-softmmu TARGETS: xtensa-softmmu arm-softmmu aarch64-softmmu alpha-softmmu
s390x-softmmu x86_64-softmmu
MAKE_CHECK_ARGS: check-tcg
build-loongarch64:
extends: .native_build_job_template
needs:
job: loongarch-debian-cross-container
variables:
IMAGE: debian-loongarch-cross
CONFIGURE_ARGS: --disable-tools --enable-debug
TARGETS: loongarch64-linux-user loongarch64-softmmu
MAKE_CHECK_ARGS: check-tcg MAKE_CHECK_ARGS: check-tcg
# We build tricore in a very minimal tricore only container # We build tricore in a very minimal tricore only container
@@ -344,7 +318,7 @@ clang-user:
variables: variables:
IMAGE: debian-all-test-cross IMAGE: debian-all-test-cross
CONFIGURE_ARGS: --cc=clang --cxx=clang++ --disable-system CONFIGURE_ARGS: --cc=clang --cxx=clang++ --disable-system
--target-list-exclude=alpha-linux-user,microblazeel-linux-user,aarch64_be-linux-user,i386-linux-user,m68k-linux-user,mipsn32el-linux-user,xtensaeb-linux-user --target-list-exclude=microblazeel-linux-user,aarch64_be-linux-user,i386-linux-user,m68k-linux-user,mipsn32el-linux-user,xtensaeb-linux-user
--extra-cflags=-fsanitize=undefined --extra-cflags=-fno-sanitize-recover=undefined --extra-cflags=-fsanitize=undefined --extra-cflags=-fno-sanitize-recover=undefined
MAKE_CHECK_ARGS: check-unit check-tcg MAKE_CHECK_ARGS: check-unit check-tcg
@@ -531,7 +505,7 @@ build-tci:
variables: variables:
IMAGE: debian-all-test-cross IMAGE: debian-all-test-cross
script: script:
- TARGETS="aarch64 arm hppa m68k microblaze ppc64 s390x x86_64" - TARGETS="aarch64 alpha arm hppa m68k microblaze ppc64 s390x x86_64"
- mkdir build - mkdir build
- cd build - cd build
- ../configure --enable-tcg-interpreter --disable-docs --disable-gtk --disable-vnc - ../configure --enable-tcg-interpreter --disable-docs --disable-gtk --disable-vnc

View File

@@ -1,3 +1,9 @@
alpha-debian-cross-container:
extends: .container_job_template
stage: containers
variables:
NAME: debian-alpha-cross
amd64-debian-cross-container: amd64-debian-cross-container:
extends: .container_job_template extends: .container_job_template
stage: containers stage: containers
@@ -10,12 +16,6 @@ amd64-debian-user-cross-container:
variables: variables:
NAME: debian-all-test-cross NAME: debian-all-test-cross
amd64-debian-legacy-cross-container:
extends: .container_job_template
stage: containers
variables:
NAME: debian-legacy-test-cross
arm64-debian-cross-container: arm64-debian-cross-container:
extends: .container_job_template extends: .container_job_template
stage: containers stage: containers
@@ -40,11 +40,23 @@ hexagon-cross-container:
variables: variables:
NAME: debian-hexagon-cross NAME: debian-hexagon-cross
loongarch-debian-cross-container: hppa-debian-cross-container:
extends: .container_job_template extends: .container_job_template
stage: containers stage: containers
variables: variables:
NAME: debian-loongarch-cross NAME: debian-hppa-cross
m68k-debian-cross-container:
extends: .container_job_template
stage: containers
variables:
NAME: debian-m68k-cross
mips64-debian-cross-container:
extends: .container_job_template
stage: containers
variables:
NAME: debian-mips64-cross
mips64el-debian-cross-container: mips64el-debian-cross-container:
extends: .container_job_template extends: .container_job_template
@@ -52,12 +64,24 @@ mips64el-debian-cross-container:
variables: variables:
NAME: debian-mips64el-cross NAME: debian-mips64el-cross
mips-debian-cross-container:
extends: .container_job_template
stage: containers
variables:
NAME: debian-mips-cross
mipsel-debian-cross-container: mipsel-debian-cross-container:
extends: .container_job_template extends: .container_job_template
stage: containers stage: containers
variables: variables:
NAME: debian-mipsel-cross NAME: debian-mipsel-cross
powerpc-test-cross-container:
extends: .container_job_template
stage: containers
variables:
NAME: debian-powerpc-test-cross
ppc64el-debian-cross-container: ppc64el-debian-cross-container:
extends: .container_job_template extends: .container_job_template
stage: containers stage: containers
@@ -73,12 +97,31 @@ riscv64-debian-cross-container:
NAME: debian-riscv64-cross NAME: debian-riscv64-cross
QEMU_JOB_OPTIONAL: 1 QEMU_JOB_OPTIONAL: 1
# we can however build TCG tests using a non-sid base
riscv64-debian-test-cross-container:
extends: .container_job_template
stage: containers
variables:
NAME: debian-riscv64-test-cross
s390x-debian-cross-container: s390x-debian-cross-container:
extends: .container_job_template extends: .container_job_template
stage: containers stage: containers
variables: variables:
NAME: debian-s390x-cross NAME: debian-s390x-cross
sh4-debian-cross-container:
extends: .container_job_template
stage: containers
variables:
NAME: debian-sh4-cross
sparc64-debian-cross-container:
extends: .container_job_template
stage: containers
variables:
NAME: debian-sparc64-cross
tricore-debian-cross-container: tricore-debian-cross-container:
extends: .container_job_template extends: .container_job_template
stage: containers stage: containers

View File

@@ -165,7 +165,7 @@ cross-win32-system:
job: win32-fedora-cross-container job: win32-fedora-cross-container
variables: variables:
IMAGE: fedora-win32-cross IMAGE: fedora-win32-cross
EXTRA_CONFIGURE_OPTS: --enable-fdt=internal --disable-plugins EXTRA_CONFIGURE_OPTS: --enable-fdt=internal
CROSS_SKIP_TARGETS: alpha-softmmu avr-softmmu hppa-softmmu m68k-softmmu CROSS_SKIP_TARGETS: alpha-softmmu avr-softmmu hppa-softmmu m68k-softmmu
microblazeel-softmmu mips64el-softmmu nios2-softmmu microblazeel-softmmu mips64el-softmmu nios2-softmmu
artifacts: artifacts:
@@ -179,7 +179,7 @@ cross-win64-system:
job: win64-fedora-cross-container job: win64-fedora-cross-container
variables: variables:
IMAGE: fedora-win64-cross IMAGE: fedora-win64-cross
EXTRA_CONFIGURE_OPTS: --enable-fdt=internal --disable-plugins EXTRA_CONFIGURE_OPTS: --enable-fdt=internal
CROSS_SKIP_TARGETS: alpha-softmmu avr-softmmu hppa-softmmu CROSS_SKIP_TARGETS: alpha-softmmu avr-softmmu hppa-softmmu
m68k-softmmu microblazeel-softmmu nios2-softmmu m68k-softmmu microblazeel-softmmu nios2-softmmu
or1k-softmmu rx-softmmu sh4eb-softmmu sparc64-softmmu or1k-softmmu rx-softmmu sh4eb-softmmu sparc64-softmmu

View File

@@ -72,7 +72,6 @@
- .\msys64\usr\bin\bash -lc "pacman -Sy --noconfirm --needed - .\msys64\usr\bin\bash -lc "pacman -Sy --noconfirm --needed
bison diffutils flex bison diffutils flex
git grep make sed git grep make sed
$MINGW_TARGET-binutils
$MINGW_TARGET-capstone $MINGW_TARGET-capstone
$MINGW_TARGET-ccache $MINGW_TARGET-ccache
$MINGW_TARGET-curl $MINGW_TARGET-curl

View File

@@ -30,12 +30,10 @@ malc <av1474@comtv.ru> malc <malc@c046a42c-6fe2-441c-8c8c-71466251a162>
# Corrupted Author fields # Corrupted Author fields
Aaron Larson <alarson@ddci.com> alarson@ddci.com Aaron Larson <alarson@ddci.com> alarson@ddci.com
Andreas Färber <andreas.faerber@web.de> Andreas Färber <andreas.faerber> Andreas Färber <andreas.faerber@web.de> Andreas Färber <andreas.faerber>
fanwenjie <fanwj@mail.ustc.edu.cn> fanwj@mail.ustc.edu.cn <fanwj@mail.ustc.edu.cn>
Jason Wang <jasowang@redhat.com> Jason Wang <jasowang> Jason Wang <jasowang@redhat.com> Jason Wang <jasowang>
Marek Dolata <mkdolata@us.ibm.com> mkdolata@us.ibm.com <mkdolata@us.ibm.com> Marek Dolata <mkdolata@us.ibm.com> mkdolata@us.ibm.com <mkdolata@us.ibm.com>
Michael Ellerman <mpe@ellerman.id.au> michael@ozlabs.org <michael@ozlabs.org> Michael Ellerman <mpe@ellerman.id.au> michael@ozlabs.org <michael@ozlabs.org>
Nick Hudson <hnick@vmware.com> hnick@vmware.com <hnick@vmware.com> Nick Hudson <hnick@vmware.com> hnick@vmware.com <hnick@vmware.com>
Timothée Cocault <timothee.cocault@gmail.com> timothee.cocault@gmail.com <timothee.cocault@gmail.com>
# There is also a: # There is also a:
# (no author) <(no author)@c046a42c-6fe2-441c-8c8c-71466251a162> # (no author) <(no author)@c046a42c-6fe2-441c-8c8c-71466251a162>
@@ -83,9 +81,6 @@ Huacai Chen <chenhuacai@kernel.org> <chenhuacai@loongson.cn>
James Hogan <jhogan@kernel.org> <james.hogan@imgtec.com> James Hogan <jhogan@kernel.org> <james.hogan@imgtec.com>
Leif Lindholm <quic_llindhol@quicinc.com> <leif.lindholm@linaro.org> Leif Lindholm <quic_llindhol@quicinc.com> <leif.lindholm@linaro.org>
Leif Lindholm <quic_llindhol@quicinc.com> <leif@nuviainc.com> Leif Lindholm <quic_llindhol@quicinc.com> <leif@nuviainc.com>
Luc Michel <luc@lmichel.fr> <luc.michel@git.antfield.fr>
Luc Michel <luc@lmichel.fr> <luc.michel@greensocs.com>
Luc Michel <luc@lmichel.fr> <lmichel@kalray.eu>
Radoslaw Biernacki <rad@semihalf.com> <radoslaw.biernacki@linaro.org> Radoslaw Biernacki <rad@semihalf.com> <radoslaw.biernacki@linaro.org>
Paul Brook <paul@nowt.org> <paul@codesourcery.com> Paul Brook <paul@nowt.org> <paul@codesourcery.com>
Paul Burton <paulburton@kernel.org> <paul.burton@mips.com> Paul Burton <paulburton@kernel.org> <paul.burton@mips.com>

View File

@@ -11,9 +11,6 @@ config OPENGL
config X11 config X11
bool bool
config PIXMAN
bool
config SPICE config SPICE
bool bool
@@ -49,6 +46,3 @@ config FUZZ
config VFIO_USER_SERVER_ALLOWED config VFIO_USER_SERVER_ALLOWED
bool bool
imply VFIO_USER_SERVER imply VFIO_USER_SERVER
config HV_BALLOON_POSSIBLE
bool

View File

@@ -245,7 +245,6 @@ M: Richard Henderson <richard.henderson@linaro.org>
S: Maintained S: Maintained
F: target/hppa/ F: target/hppa/
F: disas/hppa.c F: disas/hppa.c
F: tests/tcg/hppa/
LoongArch TCG CPUs LoongArch TCG CPUs
M: Song Gao <gaosong@loongson.cn> M: Song Gao <gaosong@loongson.cn>
@@ -259,7 +258,6 @@ M: Laurent Vivier <laurent@vivier.eu>
S: Maintained S: Maintained
F: target/m68k/ F: target/m68k/
F: disas/m68k.c F: disas/m68k.c
F: tests/tcg/m68k/
MicroBlaze TCG CPUs MicroBlaze TCG CPUs
M: Edgar E. Iglesias <edgar.iglesias@gmail.com> M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
@@ -286,9 +284,7 @@ R: Marek Vasut <marex@denx.de>
S: Orphan S: Orphan
F: target/nios2/ F: target/nios2/
F: hw/nios2/ F: hw/nios2/
F: hw/intc/nios2_vic.c
F: disas/nios2.c F: disas/nios2.c
F: include/hw/intc/nios2_vic.h
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 F: tests/docker/dockerfiles/debian-nios2-cross.d/build-toolchain.sh
F: tests/tcg/nios2/ F: tests/tcg/nios2/
@@ -299,7 +295,6 @@ S: Odd Fixes
F: docs/system/openrisc/cpu-features.rst F: docs/system/openrisc/cpu-features.rst
F: target/openrisc/ F: target/openrisc/
F: hw/openrisc/ F: hw/openrisc/
F: include/hw/openrisc/
F: tests/tcg/openrisc/ F: tests/tcg/openrisc/
PowerPC TCG CPUs PowerPC TCG CPUs
@@ -312,18 +307,12 @@ F: target/ppc/
F: hw/ppc/ppc.c F: hw/ppc/ppc.c
F: hw/ppc/ppc_booke.c F: hw/ppc/ppc_booke.c
F: include/hw/ppc/ppc.h F: include/hw/ppc/ppc.h
F: hw/ppc/meson.build
F: hw/ppc/trace*
F: configs/devices/ppc*
F: docs/system/ppc/embedded.rst
F: docs/system/target-ppc.rst
F: tests/tcg/ppc*/*
RISC-V TCG CPUs RISC-V TCG CPUs
M: Palmer Dabbelt <palmer@dabbelt.com> M: Palmer Dabbelt <palmer@dabbelt.com>
M: Alistair Francis <alistair.francis@wdc.com> M: Alistair Francis <alistair.francis@wdc.com>
M: Bin Meng <bin.meng@windriver.com> M: Bin Meng <bin.meng@windriver.com>
R: Weiwei Li <liwei1518@gmail.com> R: Weiwei Li <liweiwei@iscas.ac.cn>
R: Daniel Henrique Barboza <dbarboza@ventanamicro.com> R: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
R: Liu Zhiwei <zhiwei_liu@linux.alibaba.com> R: Liu Zhiwei <zhiwei_liu@linux.alibaba.com>
L: qemu-riscv@nongnu.org L: qemu-riscv@nongnu.org
@@ -336,7 +325,6 @@ F: hw/intc/riscv*
F: include/hw/riscv/ F: include/hw/riscv/
F: linux-user/host/riscv32/ F: linux-user/host/riscv32/
F: linux-user/host/riscv64/ F: linux-user/host/riscv64/
F: tests/tcg/riscv64/
RISC-V XThead* extensions RISC-V XThead* extensions
M: Christoph Muellner <christoph.muellner@vrull.eu> M: Christoph Muellner <christoph.muellner@vrull.eu>
@@ -378,7 +366,6 @@ F: target/sh4/
F: hw/sh4/ F: hw/sh4/
F: disas/sh4.c F: disas/sh4.c
F: include/hw/sh4/ F: include/hw/sh4/
F: tests/tcg/sh4/
SPARC TCG CPUs SPARC TCG CPUs
M: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> M: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
@@ -389,7 +376,6 @@ F: hw/sparc/
F: hw/sparc64/ F: hw/sparc64/
F: include/hw/sparc/sparc64.h F: include/hw/sparc/sparc64.h
F: disas/sparc.c F: disas/sparc.c
F: tests/tcg/sparc64/
X86 TCG CPUs X86 TCG CPUs
M: Paolo Bonzini <pbonzini@redhat.com> M: Paolo Bonzini <pbonzini@redhat.com>
@@ -490,7 +476,7 @@ S: Supported
F: include/sysemu/kvm_xen.h F: include/sysemu/kvm_xen.h
F: target/i386/kvm/xen* F: target/i386/kvm/xen*
F: hw/i386/kvm/xen* F: hw/i386/kvm/xen*
F: tests/avocado/kvm_xen_guest.py F: tests/avocado/xen_guest.py
Guest CPU Cores (other accelerators) Guest CPU Cores (other accelerators)
------------------------------------ ------------------------------------
@@ -687,7 +673,7 @@ M: Peter Maydell <peter.maydell@linaro.org>
L: qemu-arm@nongnu.org L: qemu-arm@nongnu.org
S: Maintained S: Maintained
F: hw/intc/arm* F: hw/intc/arm*
F: hw/intc/gic*_internal.h 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
@@ -859,10 +845,8 @@ M: Hao Wu <wuhaotsh@google.com>
L: qemu-arm@nongnu.org L: qemu-arm@nongnu.org
S: Supported S: Supported
F: hw/*/npcm* F: hw/*/npcm*
F: hw/sensor/adm1266.c
F: include/hw/*/npcm* F: include/hw/*/npcm*
F: tests/qtest/npcm* F: tests/qtest/npcm*
F: tests/qtest/adm1266-test.c
F: pc-bios/npcm7xx_bootrom.bin F: pc-bios/npcm7xx_bootrom.bin
F: roms/vbootrom F: roms/vbootrom
F: docs/system/arm/nuvoton.rst F: docs/system/arm/nuvoton.rst
@@ -901,7 +885,7 @@ S: Odd Fixes
F: hw/arm/raspi.c F: hw/arm/raspi.c
F: hw/arm/raspi_platform.h F: hw/arm/raspi_platform.h
F: hw/*/bcm283* F: hw/*/bcm283*
F: include/hw/arm/rasp* F: include/hw/arm/raspi*
F: include/hw/*/bcm283* F: include/hw/*/bcm283*
F: docs/system/arm/raspi.rst F: docs/system/arm/raspi.rst
@@ -1133,7 +1117,7 @@ F: docs/system/arm/emcraft-sf2.rst
ASPEED BMCs ASPEED BMCs
M: Cédric Le Goater <clg@kaod.org> M: Cédric Le Goater <clg@kaod.org>
M: Peter Maydell <peter.maydell@linaro.org> M: Peter Maydell <peter.maydell@linaro.org>
R: Andrew Jeffery <andrew@codeconstruct.com.au> R: Andrew Jeffery <andrew@aj.id.au>
R: Joel Stanley <joel@jms.id.au> R: Joel Stanley <joel@jms.id.au>
L: qemu-arm@nongnu.org L: qemu-arm@nongnu.org
S: Maintained S: Maintained
@@ -1189,25 +1173,19 @@ F: hw/*/etraxfs_*.c
HP-PARISC Machines HP-PARISC Machines
------------------ ------------------
HP B160L, HP C3700 HP B160L
M: Richard Henderson <richard.henderson@linaro.org> M: Richard Henderson <richard.henderson@linaro.org>
R: Helge Deller <deller@gmx.de> 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/display/artist.c
F: hw/hppa/ F: hw/hppa/
F: hw/input/lasips2.c
F: hw/net/*i82596* F: hw/net/*i82596*
F: hw/misc/lasi.c F: hw/misc/lasi.c
F: hw/pci-host/astro.c
F: hw/pci-host/dino.c F: hw/pci-host/dino.c
F: include/hw/input/lasips2.h
F: include/hw/misc/lasi.h F: include/hw/misc/lasi.h
F: include/hw/net/lasi_82596.h F: include/hw/net/lasi_82596.h
F: include/hw/pci-host/astro.h
F: include/hw/pci-host/dino.h F: include/hw/pci-host/dino.h
F: pc-bios/hppa-firmware.img F: pc-bios/hppa-firmware.img
F: roms/seabios-hppa/
LoongArch Machines LoongArch Machines
------------------ ------------------
@@ -1286,7 +1264,6 @@ F: include/hw/char/goldfish_tty.h
F: include/hw/intc/goldfish_pic.h F: include/hw/intc/goldfish_pic.h
F: include/hw/intc/m68k_irqc.h F: include/hw/intc/m68k_irqc.h
F: include/hw/misc/virt_ctrl.h F: include/hw/misc/virt_ctrl.h
F: docs/specs/virt-ctlr.rst
MicroBlaze Machines MicroBlaze Machines
------------------- -------------------
@@ -1325,7 +1302,7 @@ Malta
M: Philippe Mathieu-Daudé <philmd@linaro.org> M: Philippe Mathieu-Daudé <philmd@linaro.org>
R: Aurelien Jarno <aurelien@aurel32.net> R: Aurelien Jarno <aurelien@aurel32.net>
S: Odd Fixes S: Odd Fixes
F: hw/isa/piix.c F: hw/isa/piix4.c
F: hw/acpi/piix4.c F: hw/acpi/piix4.c
F: hw/mips/malta.c F: hw/mips/malta.c
F: hw/pci-host/gt64120.c F: hw/pci-host/gt64120.c
@@ -1345,7 +1322,10 @@ M: Philippe Mathieu-Daudé <philmd@linaro.org>
R: Jiaxun Yang <jiaxun.yang@flygoat.com> R: Jiaxun Yang <jiaxun.yang@flygoat.com>
S: Odd Fixes S: Odd Fixes
F: hw/mips/fuloong2e.c F: hw/mips/fuloong2e.c
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: include/hw/isa/vt82c686.h
F: include/hw/pci-host/bonito.h F: include/hw/pci-host/bonito.h
F: tests/avocado/machine_mips_fuloong2e.py F: tests/avocado/machine_mips_fuloong2e.py
@@ -1357,7 +1337,6 @@ 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: include/hw/intc/loongson_liointc.h
F: tests/avocado/machine_mips_loongson3v.py F: tests/avocado/machine_mips_loongson3v.py
Boston Boston
@@ -1375,7 +1354,6 @@ or1k-sim
M: Jia Liu <proljc@gmail.com> M: Jia Liu <proljc@gmail.com>
S: Maintained S: Maintained
F: docs/system/openrisc/or1k-sim.rst F: docs/system/openrisc/or1k-sim.rst
F: hw/intc/ompic.c
F: hw/openrisc/openrisc_sim.c F: hw/openrisc/openrisc_sim.c
PowerPC Machines PowerPC Machines
@@ -1383,8 +1361,7 @@ PowerPC Machines
405 (ref405ep) 405 (ref405ep)
L: qemu-ppc@nongnu.org L: qemu-ppc@nongnu.org
S: Orphan S: Orphan
F: hw/ppc/ppc405* F: hw/ppc/ppc405_boards.c
F: tests/avocado/ppc_405.py
Bamboo Bamboo
L: qemu-ppc@nongnu.org L: qemu-ppc@nongnu.org
@@ -1396,7 +1373,6 @@ e500
L: qemu-ppc@nongnu.org L: qemu-ppc@nongnu.org
S: Orphan S: Orphan
F: hw/ppc/e500* F: hw/ppc/e500*
F: hw/ppc/ppce500_spin.c
F: hw/gpio/mpc8xxx.c F: hw/gpio/mpc8xxx.c
F: hw/i2c/mpc_i2c.c F: hw/i2c/mpc_i2c.c
F: hw/net/fsl_etsec/ F: hw/net/fsl_etsec/
@@ -1404,9 +1380,8 @@ 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.c F: hw/intc/openpic_kvm.h
F: include/hw/ppc/openpic_kvm.h F: include/hw/ppc/openpic_kvm.h
F: docs/system/ppc/ppce500.rst
mpc8544ds mpc8544ds
L: qemu-ppc@nongnu.org L: qemu-ppc@nongnu.org
@@ -1426,7 +1401,6 @@ F: hw/pci-bridge/dec.[hc]
F: hw/misc/macio/ F: hw/misc/macio/
F: hw/misc/mos6522.c F: hw/misc/mos6522.c
F: hw/nvram/mac_nvram.c F: hw/nvram/mac_nvram.c
F: hw/ppc/fw_cfg.c
F: hw/input/adb* F: hw/input/adb*
F: include/hw/misc/macio/ F: include/hw/misc/macio/
F: include/hw/misc/mos6522.h F: include/hw/misc/mos6522.h
@@ -1480,10 +1454,6 @@ F: hw/*/spapr*
F: include/hw/*/spapr* F: include/hw/*/spapr*
F: hw/*/xics* F: hw/*/xics*
F: include/hw/*/xics* F: include/hw/*/xics*
F: include/hw/ppc/fdt.h
F: hw/ppc/fdt.c
F: include/hw/ppc/pef.h
F: hw/ppc/pef.c
F: pc-bios/slof.bin F: pc-bios/slof.bin
F: docs/system/ppc/pseries.rst F: docs/system/ppc/pseries.rst
F: docs/specs/ppc-spapr-* F: docs/specs/ppc-spapr-*
@@ -1521,7 +1491,6 @@ M: BALATON Zoltan <balaton@eik.bme.hu>
L: qemu-ppc@nongnu.org L: qemu-ppc@nongnu.org
S: Maintained S: Maintained
F: hw/ppc/sam460ex.c F: hw/ppc/sam460ex.c
F: hw/ppc/ppc440_uc.c
F: hw/ppc/ppc440_pcix.c F: hw/ppc/ppc440_pcix.c
F: hw/display/sm501* F: hw/display/sm501*
F: hw/ide/sii3112.c F: hw/ide/sii3112.c
@@ -1539,14 +1508,6 @@ F: hw/pci-host/mv64361.c
F: hw/pci-host/mv643xx.h F: hw/pci-host/mv643xx.h
F: include/hw/pci-host/mv64361.h F: include/hw/pci-host/mv64361.h
amigaone
M: BALATON Zoltan <balaton@eik.bme.hu>
L: qemu-ppc@nongnu.org
S: Maintained
F: hw/ppc/amigaone.c
F: hw/pci-host/articia.c
F: include/hw/pci-host/articia.h
Virtual Open Firmware (VOF) Virtual Open Firmware (VOF)
M: Alexey Kardashevskiy <aik@ozlabs.ru> M: Alexey Kardashevskiy <aik@ozlabs.ru>
R: David Gibson <david@gibson.dropbear.id.au> R: David Gibson <david@gibson.dropbear.id.au>
@@ -1626,7 +1587,6 @@ F: hw/intc/sh_intc.c
F: hw/pci-host/sh_pci.c F: hw/pci-host/sh_pci.c
F: hw/timer/sh_timer.c F: hw/timer/sh_timer.c
F: include/hw/sh4/sh_intc.h F: include/hw/sh4/sh_intc.h
F: include/hw/timer/tmu012.h
Shix Shix
R: Yoshinori Sato <ysato@users.sourceforge.jp> R: Yoshinori Sato <ysato@users.sourceforge.jp>
@@ -1750,16 +1710,6 @@ F: hw/s390x/event-facility.c
F: hw/s390x/sclp*.c F: hw/s390x/sclp*.c
L: qemu-s390x@nongnu.org L: qemu-s390x@nongnu.org
S390 CPU topology
M: Nina Schoetterl-Glausch <nsg@linux.ibm.com>
S: Supported
F: include/hw/s390x/cpu-topology.h
F: hw/s390x/cpu-topology.c
F: target/s390x/kvm/stsi-topology.c
F: docs/devel/s390-cpu-topology.rst
F: docs/system/s390x/cpu-topology.rst
F: tests/avocado/s390_topology.py
X86 Machines X86 Machines
------------ ------------
PC PC
@@ -1774,7 +1724,7 @@ F: hw/pci-host/pam.c
F: include/hw/pci-host/i440fx.h F: include/hw/pci-host/i440fx.h
F: include/hw/pci-host/q35.h F: include/hw/pci-host/q35.h
F: include/hw/pci-host/pam.h F: include/hw/pci-host/pam.h
F: hw/isa/piix.c F: hw/isa/piix3.c
F: hw/isa/lpc_ich9.c F: hw/isa/lpc_ich9.c
F: hw/i2c/smbus_ich9.c F: hw/i2c/smbus_ich9.c
F: hw/acpi/piix4.c F: hw/acpi/piix4.c
@@ -1784,7 +1734,7 @@ F: include/hw/southbridge/ich9.h
F: include/hw/southbridge/piix.h F: include/hw/southbridge/piix.h
F: hw/isa/apm.c F: hw/isa/apm.c
F: include/hw/isa/apm.h F: include/hw/isa/apm.h
F: tests/unit/test-x86-topo.c F: tests/unit/test-x86-cpuid.c
F: tests/qtest/test-x86-cpuid-compat.c F: tests/qtest/test-x86-cpuid-compat.c
PC Chipset PC Chipset
@@ -1814,7 +1764,6 @@ F: include/hw/dma/i8257.h
F: include/hw/i2c/pm_smbus.h F: include/hw/i2c/pm_smbus.h
F: include/hw/input/i8042.h F: include/hw/input/i8042.h
F: include/hw/intc/ioapic* F: include/hw/intc/ioapic*
F: include/hw/intc/i8259.h
F: include/hw/isa/i8259_internal.h F: include/hw/isa/i8259_internal.h
F: include/hw/isa/superio.h F: include/hw/isa/superio.h
F: include/hw/timer/hpet.h F: include/hw/timer/hpet.h
@@ -1844,7 +1793,6 @@ 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
F: qapi/machine.json F: qapi/machine.json
F: qapi/machine-common.json
F: qapi/machine-target.json F: qapi/machine-target.json
F: include/hw/boards.h F: include/hw/boards.h
F: include/hw/core/cpu.h F: include/hw/core/cpu.h
@@ -1870,7 +1818,6 @@ M: Max Filippov <jcmvbkbc@gmail.com>
S: Maintained S: Maintained
F: hw/xtensa/xtfpga.c F: hw/xtensa/xtfpga.c
F: hw/net/opencores_eth.c F: hw/net/opencores_eth.c
F: include/hw/xtensa/mx_pic.h
Devices Devices
------- -------
@@ -1896,7 +1843,6 @@ EDU
M: Jiri Slaby <jslaby@suse.cz> M: Jiri Slaby <jslaby@suse.cz>
S: Maintained S: Maintained
F: hw/misc/edu.c F: hw/misc/edu.c
F: docs/specs/edu.rst
IDE IDE
M: John Snow <jsnow@redhat.com> M: John Snow <jsnow@redhat.com>
@@ -2032,9 +1978,7 @@ F: docs/specs/acpi_hest_ghes.rst
ppc4xx ppc4xx
L: qemu-ppc@nongnu.org L: qemu-ppc@nongnu.org
S: Orphan S: Orphan
F: hw/ppc/ppc4xx*.c F: hw/ppc/ppc4*.c
F: hw/ppc/ppc440_uc.c
F: hw/ppc/ppc440.h
F: hw/i2c/ppc4xx_i2c.c F: hw/i2c/ppc4xx_i2c.c
F: include/hw/ppc/ppc4xx.h F: include/hw/ppc/ppc4xx.h
F: include/hw/i2c/ppc4xx_i2c.h F: include/hw/i2c/ppc4xx_i2c.h
@@ -2323,15 +2267,6 @@ F: hw/virtio/virtio-mem-pci.h
F: hw/virtio/virtio-mem-pci.c F: hw/virtio/virtio-mem-pci.c
F: include/hw/virtio/virtio-mem.h F: include/hw/virtio/virtio-mem.h
virtio-snd
M: Gerd Hoffmann <kraxel@redhat.com>
R: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
S: Supported
F: hw/audio/virtio-snd.c
F: hw/audio/virtio-snd-pci.c
F: include/hw/audio/virtio-snd.h
F: docs/system/devices/virtio-snd.rst
nvme nvme
M: Keith Busch <kbusch@kernel.org> M: Keith Busch <kbusch@kernel.org>
M: Klaus Jensen <its@irrelevant.dk> M: Klaus Jensen <its@irrelevant.dk>
@@ -2374,7 +2309,6 @@ S: Maintained
F: hw/net/vmxnet* F: hw/net/vmxnet*
F: hw/scsi/vmw_pvscsi* F: hw/scsi/vmw_pvscsi*
F: tests/qtest/vmxnet3-test.c F: tests/qtest/vmxnet3-test.c
F: docs/specs/vwm_pvscsi-spec.rst
Rocker Rocker
M: Jiri Pirko <jiri@resnulli.us> M: Jiri Pirko <jiri@resnulli.us>
@@ -2459,7 +2393,7 @@ S: Orphan
R: Ani Sinha <ani@anisinha.ca> R: Ani Sinha <ani@anisinha.ca>
F: hw/acpi/vmgenid.c F: hw/acpi/vmgenid.c
F: include/hw/acpi/vmgenid.h F: include/hw/acpi/vmgenid.h
F: docs/specs/vmgenid.rst F: docs/specs/vmgenid.txt
F: tests/qtest/vmgenid-test.c F: tests/qtest/vmgenid-test.c
LED LED
@@ -2491,7 +2425,6 @@ F: hw/display/vga*
F: hw/display/bochs-display.c F: hw/display/bochs-display.c
F: include/hw/display/vga.h F: include/hw/display/vga.h
F: include/hw/display/bochs-vbe.h F: include/hw/display/bochs-vbe.h
F: docs/specs/standard-vga.rst
ramfb ramfb
M: Gerd Hoffmann <kraxel@redhat.com> M: Gerd Hoffmann <kraxel@redhat.com>
@@ -2505,7 +2438,6 @@ S: Odd Fixes
F: hw/display/virtio-gpu* F: hw/display/virtio-gpu*
F: hw/display/virtio-vga.* F: hw/display/virtio-vga.*
F: include/hw/virtio/virtio-gpu.h F: include/hw/virtio/virtio-gpu.h
F: docs/system/devices/virtio-gpu.rst
vhost-user-blk vhost-user-blk
M: Raphael Norwitz <raphael.norwitz@nutanix.com> M: Raphael Norwitz <raphael.norwitz@nutanix.com>
@@ -2546,18 +2478,9 @@ PIIX4 South Bridge (i82371AB)
M: Hervé Poussineau <hpoussin@reactos.org> M: Hervé Poussineau <hpoussin@reactos.org>
M: Philippe Mathieu-Daudé <philmd@linaro.org> M: Philippe Mathieu-Daudé <philmd@linaro.org>
S: Maintained S: Maintained
F: hw/isa/piix.c F: hw/isa/piix4.c
F: include/hw/southbridge/piix.h F: include/hw/southbridge/piix.h
VIA South Bridges (VT82C686B, VT8231)
M: BALATON Zoltan <balaton@eik.bme.hu>
M: Philippe Mathieu-Daudé <philmd@linaro.org>
R: Jiaxun Yang <jiaxun.yang@flygoat.com>
S: Maintained
F: hw/isa/vt82c686.c
F: hw/usb/vt82c686-uhci-pci.c
F: include/hw/isa/vt82c686.h
Firmware configuration (fw_cfg) Firmware configuration (fw_cfg)
M: Philippe Mathieu-Daudé <philmd@linaro.org> M: Philippe Mathieu-Daudé <philmd@linaro.org>
R: Gerd Hoffmann <kraxel@redhat.com> R: Gerd Hoffmann <kraxel@redhat.com>
@@ -2608,7 +2531,6 @@ W: https://canbus.pages.fel.cvut.cz/
F: net/can/* F: net/can/*
F: hw/net/can/* F: hw/net/can/*
F: include/net/can_*.h F: include/net/can_*.h
F: docs/system/devices/can.rst
OpenPIC interrupt controller OpenPIC interrupt controller
M: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> M: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
@@ -2652,7 +2574,7 @@ M: Halil Pasic <pasic@linux.ibm.com>
M: Christian Borntraeger <borntraeger@linux.ibm.com> M: Christian Borntraeger <borntraeger@linux.ibm.com>
S: Supported S: Supported
F: hw/s390x/storage-keys.h F: hw/s390x/storage-keys.h
F: hw/s390x/s390-skeys*.c F: hw/390x/s390-skeys*.c
L: qemu-s390x@nongnu.org L: qemu-s390x@nongnu.org
S390 storage attribute device S390 storage attribute device
@@ -2660,7 +2582,7 @@ M: Halil Pasic <pasic@linux.ibm.com>
M: Christian Borntraeger <borntraeger@linux.ibm.com> M: Christian Borntraeger <borntraeger@linux.ibm.com>
S: Supported S: Supported
F: hw/s390x/storage-attributes.h F: hw/s390x/storage-attributes.h
F: hw/s390x/s390-stattrib*.c F: hw/s390/s390-stattrib*.c
L: qemu-s390x@nongnu.org L: qemu-s390x@nongnu.org
S390 floating interrupt controller S390 floating interrupt controller
@@ -2680,14 +2602,6 @@ F: hw/usb/canokey.c
F: hw/usb/canokey.h F: hw/usb/canokey.h
F: docs/system/devices/canokey.rst F: docs/system/devices/canokey.rst
Hyper-V Dynamic Memory Protocol
M: Maciej S. Szmigiero <maciej.szmigiero@oracle.com>
S: Supported
F: hw/hyperv/hv-balloon*.c
F: hw/hyperv/hv-balloon*.h
F: include/hw/hyperv/dynmem-proto.h
F: include/hw/hyperv/hv-balloon.h
Subsystems Subsystems
---------- ----------
Overall Audio backends Overall Audio backends
@@ -2791,13 +2705,12 @@ S: Supported
F: util/async.c F: util/async.c
F: util/aio-*.c F: util/aio-*.c
F: util/aio-*.h F: util/aio-*.h
F: util/defer-call.c
F: util/fdmon-*.c F: util/fdmon-*.c
F: block/io.c F: block/io.c
F: block/plug.c
F: migration/block* F: migration/block*
F: include/block/aio.h F: include/block/aio.h
F: include/block/aio-wait.h F: include/block/aio-wait.h
F: include/qemu/defer-call.h
F: scripts/qemugdb/aio.py F: scripts/qemugdb/aio.py
F: tests/unit/test-fdmon-epoll.c F: tests/unit/test-fdmon-epoll.c
T: git https://github.com/stefanha/qemu.git block T: git https://github.com/stefanha/qemu.git block
@@ -2916,7 +2829,6 @@ F: include/sysemu/dump.h
F: qapi/dump.json F: qapi/dump.json
F: scripts/dump-guest-memory.py F: scripts/dump-guest-memory.py
F: stubs/dump.c F: stubs/dump.c
F: docs/specs/vmcoreinfo.rst
Error reporting Error reporting
M: Markus Armbruster <armbru@redhat.com> M: Markus Armbruster <armbru@redhat.com>
@@ -2942,7 +2854,7 @@ F: gdbstub/*
F: include/exec/gdbstub.h F: include/exec/gdbstub.h
F: include/gdbstub/* F: include/gdbstub/*
F: gdb-xml/ F: gdb-xml/
F: tests/tcg/multiarch/gdbstub/* F: tests/tcg/multiarch/gdbstub/
F: scripts/feature_to_c.py F: scripts/feature_to_c.py
F: scripts/probe-gdb-support.py F: scripts/probe-gdb-support.py
@@ -3015,7 +2927,7 @@ F: include/qemu/main-loop.h
F: include/sysemu/runstate.h F: include/sysemu/runstate.h
F: include/sysemu/runstate-action.h F: include/sysemu/runstate-action.h
F: util/main-loop.c F: util/main-loop.c
F: util/qemu-timer*.c F: util/qemu-timer.c
F: system/vl.c F: system/vl.c
F: system/main.c F: system/main.c
F: system/cpus.c F: system/cpus.c
@@ -3164,11 +3076,10 @@ M: Michael Roth <michael.roth@amd.com>
M: Konstantin Kostiuk <kkostiuk@redhat.com> M: Konstantin Kostiuk <kkostiuk@redhat.com>
S: Maintained S: Maintained
F: qga/ F: qga/
F: contrib/systemd/qemu-guest-agent.service
F: docs/interop/qemu-ga.rst F: docs/interop/qemu-ga.rst
F: docs/interop/qemu-ga-ref.rst F: docs/interop/qemu-ga-ref.rst
F: scripts/qemu-guest-agent/ F: scripts/qemu-guest-agent/
F: tests/*/test-qga* F: tests/unit/test-qga.c
T: git https://github.com/mdroth/qemu.git qga T: git https://github.com/mdroth/qemu.git qga
QEMU Guest Agent Win32 QEMU Guest Agent Win32
@@ -4001,7 +3912,6 @@ M: Jason Wang <jasowang@redhat.com>
R: Andrew Melnychenko <andrew@daynix.com> R: Andrew Melnychenko <andrew@daynix.com>
R: Yuri Benditovich <yuri.benditovich@daynix.com> R: Yuri Benditovich <yuri.benditovich@daynix.com>
S: Maintained S: Maintained
F: docs/devel/ebpf_rss.rst
F: ebpf/* F: ebpf/*
F: tools/ebpf/* F: tools/ebpf/*
@@ -4078,7 +3988,7 @@ F: gitdm.config
F: contrib/gitdm/* F: contrib/gitdm/*
Incompatible changes Incompatible changes
R: devel@lists.libvirt.org R: libvir-list@redhat.com
F: docs/about/deprecated.rst F: docs/about/deprecated.rst
Build System Build System

View File

@@ -283,13 +283,6 @@ include $(SRC_PATH)/tests/vm/Makefile.include
print-help-run = printf " %-30s - %s\\n" "$1" "$2" print-help-run = printf " %-30s - %s\\n" "$1" "$2"
print-help = @$(call print-help-run,$1,$2) print-help = @$(call print-help-run,$1,$2)
.PHONY: update-linux-vdso
update-linux-vdso:
@for m in $(SRC_PATH)/linux-user/*/Makefile.vdso; do \
$(MAKE) $(SUBDIR_MAKEFLAGS) -C $$(dirname $$m) -f Makefile.vdso \
SRC_PATH=$(SRC_PATH) BUILD_DIR=$(BUILD_DIR); \
done
.PHONY: help .PHONY: help
help: help:
@echo 'Generic targets:' @echo 'Generic targets:'
@@ -310,9 +303,6 @@ endif
$(call print-help,distclean,Remove all generated files) $(call print-help,distclean,Remove all generated files)
$(call print-help,dist,Build a distributable tarball) $(call print-help,dist,Build a distributable tarball)
@echo '' @echo ''
@echo 'Linux-user targets:'
$(call print-help,update-linux-vdso,Build linux-user vdso images)
@echo ''
@echo 'Test targets:' @echo 'Test targets:'
$(call print-help,check,Run all tests (check-help for details)) $(call print-help,check,Run all tests (check-help for details))
$(call print-help,bench,Run all benchmarks) $(call print-help,bench,Run all benchmarks)

View File

@@ -90,6 +90,8 @@ bool kvm_kernel_irqchip;
bool kvm_split_irqchip; bool kvm_split_irqchip;
bool kvm_async_interrupts_allowed; bool kvm_async_interrupts_allowed;
bool kvm_halt_in_kernel_allowed; bool kvm_halt_in_kernel_allowed;
bool kvm_eventfds_allowed;
bool kvm_irqfds_allowed;
bool kvm_resamplefds_allowed; bool kvm_resamplefds_allowed;
bool kvm_msi_via_irqfd_allowed; bool kvm_msi_via_irqfd_allowed;
bool kvm_gsi_routing_allowed; bool kvm_gsi_routing_allowed;
@@ -97,6 +99,8 @@ bool kvm_gsi_direct_mapping;
bool kvm_allowed; bool kvm_allowed;
bool kvm_readonly_mem_allowed; bool kvm_readonly_mem_allowed;
bool kvm_vm_attributes_allowed; bool kvm_vm_attributes_allowed;
bool kvm_direct_msi_allowed;
bool kvm_ioeventfd_any_length_allowed;
bool kvm_msi_use_devid; bool kvm_msi_use_devid;
bool kvm_has_guest_debug; bool kvm_has_guest_debug;
static int kvm_sstep_flags; static int kvm_sstep_flags;
@@ -107,9 +111,6 @@ static const KVMCapabilityInfo kvm_required_capabilites[] = {
KVM_CAP_INFO(USER_MEMORY), KVM_CAP_INFO(USER_MEMORY),
KVM_CAP_INFO(DESTROY_MEMORY_REGION_WORKS), KVM_CAP_INFO(DESTROY_MEMORY_REGION_WORKS),
KVM_CAP_INFO(JOIN_MEMORY_REGIONS_WORKS), KVM_CAP_INFO(JOIN_MEMORY_REGIONS_WORKS),
KVM_CAP_INFO(INTERNAL_ERROR_DATA),
KVM_CAP_INFO(IOEVENTFD),
KVM_CAP_INFO(IOEVENTFD_ANY_LENGTH),
KVM_CAP_LAST_INFO KVM_CAP_LAST_INFO
}; };
@@ -1105,6 +1106,13 @@ static void kvm_coalesce_pio_del(MemoryListener *listener,
} }
} }
static MemoryListener kvm_coalesced_pio_listener = {
.name = "kvm-coalesced-pio",
.coalesced_io_add = kvm_coalesce_pio_add,
.coalesced_io_del = kvm_coalesce_pio_del,
.priority = MEMORY_LISTENER_PRIORITY_MIN,
};
int kvm_check_extension(KVMState *s, unsigned int extension) int kvm_check_extension(KVMState *s, unsigned int extension)
{ {
int ret; int ret;
@@ -1246,6 +1254,43 @@ static int kvm_set_ioeventfd_pio(int fd, uint16_t addr, uint16_t val,
} }
static int kvm_check_many_ioeventfds(void)
{
/* Userspace can use ioeventfd for io notification. This requires a host
* that supports eventfd(2) and an I/O thread; since eventfd does not
* support SIGIO it cannot interrupt the vcpu.
*
* Older kernels have a 6 device limit on the KVM io bus. Find out so we
* can avoid creating too many ioeventfds.
*/
#if defined(CONFIG_EVENTFD)
int ioeventfds[7];
int i, ret = 0;
for (i = 0; i < ARRAY_SIZE(ioeventfds); i++) {
ioeventfds[i] = eventfd(0, EFD_CLOEXEC);
if (ioeventfds[i] < 0) {
break;
}
ret = kvm_set_ioeventfd_pio(ioeventfds[i], 0, i, true, 2, true);
if (ret < 0) {
close(ioeventfds[i]);
break;
}
}
/* Decide whether many devices are supported or not */
ret = i == ARRAY_SIZE(ioeventfds);
while (i-- > 0) {
kvm_set_ioeventfd_pio(ioeventfds[i], 0, i, false, 2, true);
close(ioeventfds[i]);
}
return ret;
#else
return 0;
#endif
}
static const KVMCapabilityInfo * static const KVMCapabilityInfo *
kvm_check_extension_list(KVMState *s, const KVMCapabilityInfo *list) kvm_check_extension_list(KVMState *s, const KVMCapabilityInfo *list)
{ {
@@ -1761,8 +1806,6 @@ void kvm_memory_listener_register(KVMState *s, KVMMemoryListener *kml,
static MemoryListener kvm_io_listener = { static MemoryListener kvm_io_listener = {
.name = "kvm-io", .name = "kvm-io",
.coalesced_io_add = kvm_coalesce_pio_add,
.coalesced_io_del = kvm_coalesce_pio_del,
.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 = MEMORY_LISTENER_PRIORITY_DEV_BACKEND, .priority = MEMORY_LISTENER_PRIORITY_DEV_BACKEND,
@@ -1804,7 +1847,7 @@ static void clear_gsi(KVMState *s, unsigned int gsi)
void kvm_init_irq_routing(KVMState *s) void kvm_init_irq_routing(KVMState *s)
{ {
int gsi_count; int gsi_count, i;
gsi_count = kvm_check_extension(s, KVM_CAP_IRQ_ROUTING) - 1; gsi_count = kvm_check_extension(s, KVM_CAP_IRQ_ROUTING) - 1;
if (gsi_count > 0) { if (gsi_count > 0) {
@@ -1816,6 +1859,12 @@ void kvm_init_irq_routing(KVMState *s)
s->irq_routes = g_malloc0(sizeof(*s->irq_routes)); s->irq_routes = g_malloc0(sizeof(*s->irq_routes));
s->nr_allocated_irq_routes = 0; s->nr_allocated_irq_routes = 0;
if (!kvm_direct_msi_allowed) {
for (i = 0; i < KVM_MSI_HASHTAB_SIZE; i++) {
QTAILQ_INIT(&s->msi_hashtab[i]);
}
}
kvm_arch_init_irq_routing(s); kvm_arch_init_irq_routing(s);
} }
@@ -1935,10 +1984,41 @@ void kvm_irqchip_change_notify(void)
notifier_list_notify(&kvm_irqchip_change_notifiers, NULL); notifier_list_notify(&kvm_irqchip_change_notifiers, NULL);
} }
static unsigned int kvm_hash_msi(uint32_t data)
{
/* This is optimized for IA32 MSI layout. However, no other arch shall
* repeat the mistake of not providing a direct MSI injection API. */
return data & 0xff;
}
static void kvm_flush_dynamic_msi_routes(KVMState *s)
{
KVMMSIRoute *route, *next;
unsigned int hash;
for (hash = 0; hash < KVM_MSI_HASHTAB_SIZE; hash++) {
QTAILQ_FOREACH_SAFE(route, &s->msi_hashtab[hash], entry, next) {
kvm_irqchip_release_virq(s, route->kroute.gsi);
QTAILQ_REMOVE(&s->msi_hashtab[hash], route, entry);
g_free(route);
}
}
}
static int kvm_irqchip_get_virq(KVMState *s) static int kvm_irqchip_get_virq(KVMState *s)
{ {
int next_virq; int next_virq;
/*
* PIC and IOAPIC share the first 16 GSI numbers, thus the available
* GSI numbers are more than the number of IRQ route. Allocating a GSI
* number can succeed even though a new route entry cannot be added.
* When this happens, flush dynamic MSI entries to free IRQ route entries.
*/
if (!kvm_direct_msi_allowed && s->irq_routes->nr == s->gsi_count) {
kvm_flush_dynamic_msi_routes(s);
}
/* Return the lowest unused GSI in the bitmap */ /* Return the lowest unused GSI in the bitmap */
next_virq = find_first_zero_bit(s->used_gsi_bitmap, s->gsi_count); next_virq = find_first_zero_bit(s->used_gsi_bitmap, s->gsi_count);
if (next_virq >= s->gsi_count) { if (next_virq >= s->gsi_count) {
@@ -1948,10 +2028,27 @@ static int kvm_irqchip_get_virq(KVMState *s)
} }
} }
static KVMMSIRoute *kvm_lookup_msi_route(KVMState *s, MSIMessage msg)
{
unsigned int hash = kvm_hash_msi(msg.data);
KVMMSIRoute *route;
QTAILQ_FOREACH(route, &s->msi_hashtab[hash], entry) {
if (route->kroute.u.msi.address_lo == (uint32_t)msg.address &&
route->kroute.u.msi.address_hi == (msg.address >> 32) &&
route->kroute.u.msi.data == le32_to_cpu(msg.data)) {
return route;
}
}
return NULL;
}
int kvm_irqchip_send_msi(KVMState *s, MSIMessage msg) int kvm_irqchip_send_msi(KVMState *s, MSIMessage msg)
{ {
struct kvm_msi msi; struct kvm_msi msi;
KVMMSIRoute *route;
if (kvm_direct_msi_allowed) {
msi.address_lo = (uint32_t)msg.address; msi.address_lo = (uint32_t)msg.address;
msi.address_hi = msg.address >> 32; msi.address_hi = msg.address >> 32;
msi.data = le32_to_cpu(msg.data); msi.data = le32_to_cpu(msg.data);
@@ -1961,6 +2058,35 @@ int kvm_irqchip_send_msi(KVMState *s, MSIMessage msg)
return kvm_vm_ioctl(s, KVM_SIGNAL_MSI, &msi); return kvm_vm_ioctl(s, KVM_SIGNAL_MSI, &msi);
} }
route = kvm_lookup_msi_route(s, msg);
if (!route) {
int virq;
virq = kvm_irqchip_get_virq(s);
if (virq < 0) {
return virq;
}
route = g_new0(KVMMSIRoute, 1);
route->kroute.gsi = virq;
route->kroute.type = KVM_IRQ_ROUTING_MSI;
route->kroute.flags = 0;
route->kroute.u.msi.address_lo = (uint32_t)msg.address;
route->kroute.u.msi.address_hi = msg.address >> 32;
route->kroute.u.msi.data = le32_to_cpu(msg.data);
kvm_add_routing_entry(s, &route->kroute);
kvm_irqchip_commit_routes(s);
QTAILQ_INSERT_TAIL(&s->msi_hashtab[kvm_hash_msi(msg.data)], route,
entry);
}
assert(route->kroute.type == KVM_IRQ_ROUTING_MSI);
return kvm_set_irq(s, route->kroute.gsi, 1);
}
int kvm_irqchip_add_msi_route(KVMRouteChange *c, int vector, PCIDevice *dev) int kvm_irqchip_add_msi_route(KVMRouteChange *c, int vector, PCIDevice *dev)
{ {
struct kvm_irq_routing_entry kroute = {}; struct kvm_irq_routing_entry kroute = {};
@@ -2085,6 +2211,10 @@ static int kvm_irqchip_assign_irqfd(KVMState *s, EventNotifier *event,
} }
} }
if (!kvm_irqfds_enabled()) {
return -ENOSYS;
}
return kvm_vm_ioctl(s, KVM_IRQFD, &irqfd); return kvm_vm_ioctl(s, KVM_IRQFD, &irqfd);
} }
@@ -2245,11 +2375,6 @@ static void kvm_irqchip_create(KVMState *s)
return; return;
} }
if (kvm_check_extension(s, KVM_CAP_IRQFD) <= 0) {
fprintf(stderr, "kvm: irqfd not implemented\n");
exit(1);
}
/* First probe and see if there's a arch-specific hook to create the /* First probe and see if there's a arch-specific hook to create the
* in-kernel irqchip for us */ * in-kernel irqchip for us */
ret = kvm_arch_irqchip_create(s); ret = kvm_arch_irqchip_create(s);
@@ -2524,8 +2649,22 @@ static int kvm_init(MachineState *ms)
#ifdef KVM_CAP_VCPU_EVENTS #ifdef KVM_CAP_VCPU_EVENTS
s->vcpu_events = kvm_check_extension(s, KVM_CAP_VCPU_EVENTS); s->vcpu_events = kvm_check_extension(s, KVM_CAP_VCPU_EVENTS);
#endif #endif
s->robust_singlestep =
kvm_check_extension(s, KVM_CAP_X86_ROBUST_SINGLESTEP);
#ifdef KVM_CAP_DEBUGREGS
s->debugregs = kvm_check_extension(s, KVM_CAP_DEBUGREGS);
#endif
s->max_nested_state_len = kvm_check_extension(s, KVM_CAP_NESTED_STATE); s->max_nested_state_len = kvm_check_extension(s, KVM_CAP_NESTED_STATE);
#ifdef KVM_CAP_IRQ_ROUTING
kvm_direct_msi_allowed = (kvm_check_extension(s, KVM_CAP_SIGNAL_MSI) > 0);
#endif
s->intx_set_mask = kvm_check_extension(s, KVM_CAP_PCI_2_3);
s->irq_set_ioctl = KVM_IRQ_LINE; s->irq_set_ioctl = KVM_IRQ_LINE;
if (kvm_check_extension(s, KVM_CAP_IRQ_INJECT_STATUS)) { if (kvm_check_extension(s, KVM_CAP_IRQ_INJECT_STATUS)) {
s->irq_set_ioctl = KVM_IRQ_LINE_STATUS; s->irq_set_ioctl = KVM_IRQ_LINE_STATUS;
@@ -2534,12 +2673,21 @@ static int kvm_init(MachineState *ms)
kvm_readonly_mem_allowed = kvm_readonly_mem_allowed =
(kvm_check_extension(s, KVM_CAP_READONLY_MEM) > 0); (kvm_check_extension(s, KVM_CAP_READONLY_MEM) > 0);
kvm_eventfds_allowed =
(kvm_check_extension(s, KVM_CAP_IOEVENTFD) > 0);
kvm_irqfds_allowed =
(kvm_check_extension(s, KVM_CAP_IRQFD) > 0);
kvm_resamplefds_allowed = kvm_resamplefds_allowed =
(kvm_check_extension(s, KVM_CAP_IRQFD_RESAMPLE) > 0); (kvm_check_extension(s, KVM_CAP_IRQFD_RESAMPLE) > 0);
kvm_vm_attributes_allowed = kvm_vm_attributes_allowed =
(kvm_check_extension(s, KVM_CAP_VM_ATTRIBUTES) > 0); (kvm_check_extension(s, KVM_CAP_VM_ATTRIBUTES) > 0);
kvm_ioeventfd_any_length_allowed =
(kvm_check_extension(s, KVM_CAP_IOEVENTFD_ANY_LENGTH) > 0);
#ifdef KVM_CAP_SET_GUEST_DEBUG #ifdef KVM_CAP_SET_GUEST_DEBUG
kvm_has_guest_debug = kvm_has_guest_debug =
(kvm_check_extension(s, KVM_CAP_SET_GUEST_DEBUG) > 0); (kvm_check_extension(s, KVM_CAP_SET_GUEST_DEBUG) > 0);
@@ -2576,15 +2724,23 @@ static int kvm_init(MachineState *ms)
kvm_irqchip_create(s); kvm_irqchip_create(s);
} }
if (kvm_eventfds_allowed) {
s->memory_listener.listener.eventfd_add = kvm_mem_ioeventfd_add; s->memory_listener.listener.eventfd_add = kvm_mem_ioeventfd_add;
s->memory_listener.listener.eventfd_del = kvm_mem_ioeventfd_del; s->memory_listener.listener.eventfd_del = kvm_mem_ioeventfd_del;
}
s->memory_listener.listener.coalesced_io_add = kvm_coalesce_mmio_region; s->memory_listener.listener.coalesced_io_add = kvm_coalesce_mmio_region;
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, "kvm-memory");
if (kvm_eventfds_allowed) {
memory_listener_register(&kvm_io_listener, memory_listener_register(&kvm_io_listener,
&address_space_io); &address_space_io);
}
memory_listener_register(&kvm_coalesced_pio_listener,
&address_space_io);
s->many_ioeventfds = kvm_check_many_ioeventfds();
s->sync_mmu = !!kvm_vm_check_extension(kvm_state, KVM_CAP_SYNC_MMU); s->sync_mmu = !!kvm_vm_check_extension(kvm_state, KVM_CAP_SYNC_MMU);
if (!s->sync_mmu) { if (!s->sync_mmu) {
@@ -2638,15 +2794,17 @@ static void kvm_handle_io(uint16_t port, MemTxAttrs attrs, void *data, int direc
static int kvm_handle_internal_error(CPUState *cpu, struct kvm_run *run) static int kvm_handle_internal_error(CPUState *cpu, struct kvm_run *run)
{ {
int i;
fprintf(stderr, "KVM internal error. Suberror: %d\n", fprintf(stderr, "KVM internal error. Suberror: %d\n",
run->internal.suberror); run->internal.suberror);
if (kvm_check_extension(kvm_state, KVM_CAP_INTERNAL_ERROR_DATA)) {
int i;
for (i = 0; i < run->internal.ndata; ++i) { for (i = 0; i < run->internal.ndata; ++i) {
fprintf(stderr, "extra data[%d]: 0x%016"PRIx64"\n", fprintf(stderr, "extra data[%d]: 0x%016"PRIx64"\n",
i, (uint64_t)run->internal.data[i]); i, (uint64_t)run->internal.data[i]);
} }
}
if (run->internal.suberror == KVM_INTERNAL_ERROR_EMULATION) { if (run->internal.suberror == KVM_INTERNAL_ERROR_EMULATION) {
fprintf(stderr, "emulation failure\n"); fprintf(stderr, "emulation failure\n");
if (!kvm_arch_stop_on_emulation_error(cpu)) { if (!kvm_arch_stop_on_emulation_error(cpu)) {
@@ -3139,11 +3297,29 @@ int kvm_has_vcpu_events(void)
return kvm_state->vcpu_events; return kvm_state->vcpu_events;
} }
int kvm_has_robust_singlestep(void)
{
return kvm_state->robust_singlestep;
}
int kvm_has_debugregs(void)
{
return kvm_state->debugregs;
}
int kvm_max_nested_state_length(void) int kvm_max_nested_state_length(void)
{ {
return kvm_state->max_nested_state_len; return kvm_state->max_nested_state_len;
} }
int kvm_has_many_ioeventfds(void)
{
if (!kvm_enabled()) {
return 0;
}
return kvm_state->many_ioeventfds;
}
int kvm_has_gsi_routing(void) int kvm_has_gsi_routing(void)
{ {
#ifdef KVM_CAP_IRQ_ROUTING #ifdef KVM_CAP_IRQ_ROUTING
@@ -3153,6 +3329,11 @@ int kvm_has_gsi_routing(void)
#endif #endif
} }
int kvm_has_intx_set_mask(void)
{
return kvm_state->intx_set_mask;
}
bool kvm_arm_supports_user_irq(void) bool kvm_arm_supports_user_irq(void)
{ {
return kvm_check_extension(kvm_state, KVM_CAP_ARM_USER_IRQ); return kvm_check_extension(kvm_state, KVM_CAP_ARM_USER_IRQ);

View File

@@ -17,13 +17,17 @@
KVMState *kvm_state; KVMState *kvm_state;
bool kvm_kernel_irqchip; bool kvm_kernel_irqchip;
bool kvm_async_interrupts_allowed; bool kvm_async_interrupts_allowed;
bool kvm_eventfds_allowed;
bool kvm_irqfds_allowed;
bool kvm_resamplefds_allowed; bool kvm_resamplefds_allowed;
bool kvm_msi_via_irqfd_allowed; bool kvm_msi_via_irqfd_allowed;
bool kvm_gsi_routing_allowed; bool kvm_gsi_routing_allowed;
bool kvm_gsi_direct_mapping; bool kvm_gsi_direct_mapping;
bool kvm_allowed; bool kvm_allowed;
bool kvm_readonly_mem_allowed; bool kvm_readonly_mem_allowed;
bool kvm_ioeventfd_any_length_allowed;
bool kvm_msi_use_devid; bool kvm_msi_use_devid;
bool kvm_direct_msi_allowed;
void kvm_flush_coalesced_mmio_buffer(void) void kvm_flush_coalesced_mmio_buffer(void)
{ {
@@ -38,6 +42,11 @@ bool kvm_has_sync_mmu(void)
return false; return false;
} }
int kvm_has_many_ioeventfds(void)
{
return 0;
}
int kvm_on_sigbus_vcpu(CPUState *cpu, int code, void *addr) int kvm_on_sigbus_vcpu(CPUState *cpu, int code, void *addr)
{ {
return 1; return 1;
@@ -83,6 +92,11 @@ void kvm_irqchip_change_notify(void)
{ {
} }
int kvm_irqchip_add_adapter_route(KVMState *s, AdapterInfo *adapter)
{
return -ENOSYS;
}
int kvm_irqchip_add_irqfd_notifier_gsi(KVMState *s, EventNotifier *n, int kvm_irqchip_add_irqfd_notifier_gsi(KVMState *s, EventNotifier *n,
EventNotifier *rn, int virq) EventNotifier *rn, int virq)
{ {

View File

@@ -22,6 +22,10 @@ void tlb_set_dirty(CPUState *cpu, vaddr vaddr)
{ {
} }
void tcg_flush_jmp_cache(CPUState *cpu)
{
}
int probe_access_flags(CPUArchState *env, vaddr addr, int size, int probe_access_flags(CPUArchState *env, vaddr addr, int size,
MMUAccessType access_type, int mmu_idx, MMUAccessType access_type, int mmu_idx,
bool nonfault, void **phost, uintptr_t retaddr) bool nonfault, void **phost, uintptr_t retaddr)

View File

@@ -24,7 +24,6 @@
#include "exec/memory.h" #include "exec/memory.h"
#include "exec/cpu_ldst.h" #include "exec/cpu_ldst.h"
#include "exec/cputlb.h" #include "exec/cputlb.h"
#include "exec/tb-flush.h"
#include "exec/memory-internal.h" #include "exec/memory-internal.h"
#include "exec/ram_addr.h" #include "exec/ram_addr.h"
#include "tcg/tcg.h" #include "tcg/tcg.h"
@@ -322,6 +321,21 @@ static void flush_all_helper(CPUState *src, run_on_cpu_func fn,
} }
} }
void tlb_flush_counts(size_t *pfull, size_t *ppart, size_t *pelide)
{
CPUState *cpu;
size_t full = 0, part = 0, elide = 0;
CPU_FOREACH(cpu) {
full += qatomic_read(&cpu->neg.tlb.c.full_flush_count);
part += qatomic_read(&cpu->neg.tlb.c.part_flush_count);
elide += qatomic_read(&cpu->neg.tlb.c.elide_flush_count);
}
*pfull = full;
*ppart = part;
*pelide = elide;
}
static void tlb_flush_by_mmuidx_async_work(CPUState *cpu, run_on_cpu_data data) static void tlb_flush_by_mmuidx_async_work(CPUState *cpu, run_on_cpu_data data)
{ {
uint16_t asked = data.host_int; uint16_t asked = data.host_int;
@@ -2692,7 +2706,7 @@ static uint64_t do_st16_leN(CPUState *cpu, MMULookupPageData *p,
case MO_ATOM_WITHIN16_PAIR: case MO_ATOM_WITHIN16_PAIR:
/* Since size > 8, this is the half that must be atomic. */ /* Since size > 8, this is the half that must be atomic. */
if (!HAVE_CMPXCHG128) { if (!HAVE_ATOMIC128_RW) {
cpu_loop_exit_atomic(cpu, ra); cpu_loop_exit_atomic(cpu, ra);
} }
return store_whole_le16(p->haddr, p->size, val_le); return store_whole_le16(p->haddr, p->size, val_le);

View File

@@ -14,6 +14,8 @@
extern int64_t max_delay; extern int64_t max_delay;
extern int64_t max_advance; extern int64_t max_advance;
void dump_exec_info(GString *buf);
/* /*
* Return true if CS is not running in parallel with other cpus, either * Return true if CS is not running in parallel with other cpus, either
* because there are no other cpus or we are within an exclusive context. * because there are no other cpus or we are within an exclusive context.

View File

@@ -825,7 +825,7 @@ static uint64_t store_whole_le16(void *pv, int size, Int128 val_le)
int sh = o * 8; int sh = o * 8;
Int128 m, v; Int128 m, v;
qemu_build_assert(HAVE_CMPXCHG128); qemu_build_assert(HAVE_ATOMIC128_RW);
/* Like MAKE_64BIT_MASK(0, sz), but larger. */ /* Like MAKE_64BIT_MASK(0, sz), but larger. */
if (sz <= 64) { if (sz <= 64) {
@@ -887,7 +887,7 @@ static void store_atom_2(CPUState *cpu, uintptr_t ra,
return; return;
} }
} else if ((pi & 15) == 7) { } else if ((pi & 15) == 7) {
if (HAVE_CMPXCHG128) { if (HAVE_ATOMIC128_RW) {
Int128 v = int128_lshift(int128_make64(val), 56); Int128 v = int128_lshift(int128_make64(val), 56);
Int128 m = int128_lshift(int128_make64(0xffff), 56); Int128 m = int128_lshift(int128_make64(0xffff), 56);
store_atom_insert_al16(pv - 7, v, m); store_atom_insert_al16(pv - 7, v, m);
@@ -956,7 +956,7 @@ static void store_atom_4(CPUState *cpu, uintptr_t ra,
return; return;
} }
} else { } else {
if (HAVE_CMPXCHG128) { if (HAVE_ATOMIC128_RW) {
store_whole_le16(pv, 4, int128_make64(cpu_to_le32(val))); store_whole_le16(pv, 4, int128_make64(cpu_to_le32(val)));
return; return;
} }
@@ -1021,7 +1021,7 @@ static void store_atom_8(CPUState *cpu, uintptr_t ra,
} }
break; break;
case MO_64: case MO_64:
if (HAVE_CMPXCHG128) { if (HAVE_ATOMIC128_RW) {
store_whole_le16(pv, 8, int128_make64(cpu_to_le64(val))); store_whole_le16(pv, 8, int128_make64(cpu_to_le64(val)));
return; return;
} }
@@ -1076,7 +1076,7 @@ static void store_atom_16(CPUState *cpu, uintptr_t ra,
} }
break; break;
case -MO_64: case -MO_64:
if (HAVE_CMPXCHG128) { if (HAVE_ATOMIC128_RW) {
uint64_t val_le; uint64_t val_le;
int s2 = pi & 15; int s2 = pi & 15;
int s1 = 16 - s2; int s1 = 16 - s2;
@@ -1103,6 +1103,10 @@ static void store_atom_16(CPUState *cpu, uintptr_t ra,
} }
break; break;
case MO_128: case MO_128:
if (HAVE_ATOMIC128_RW) {
atomic16_set(pv, val);
return;
}
break; break;
default: default:
g_assert_not_reached(); g_assert_not_reached();

View File

@@ -8,7 +8,6 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qemu/accel.h" #include "qemu/accel.h"
#include "qemu/qht.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "qapi/type-helpers.h" #include "qapi/type-helpers.h"
#include "qapi/qapi-commands-machine.h" #include "qapi/qapi-commands-machine.h"
@@ -18,7 +17,6 @@
#include "sysemu/tcg.h" #include "sysemu/tcg.h"
#include "tcg/tcg.h" #include "tcg/tcg.h"
#include "internal-common.h" #include "internal-common.h"
#include "tb-context.h"
static void dump_drift_info(GString *buf) static void dump_drift_info(GString *buf)
@@ -52,153 +50,6 @@ static void dump_accel_info(GString *buf)
one_insn_per_tb ? "on" : "off"); one_insn_per_tb ? "on" : "off");
} }
static void print_qht_statistics(struct qht_stats hst, GString *buf)
{
uint32_t hgram_opts;
size_t hgram_bins;
char *hgram;
if (!hst.head_buckets) {
return;
}
g_string_append_printf(buf, "TB hash buckets %zu/%zu "
"(%0.2f%% head buckets used)\n",
hst.used_head_buckets, hst.head_buckets,
(double)hst.used_head_buckets /
hst.head_buckets * 100);
hgram_opts = QDIST_PR_BORDER | QDIST_PR_LABELS;
hgram_opts |= QDIST_PR_100X | QDIST_PR_PERCENT;
if (qdist_xmax(&hst.occupancy) - qdist_xmin(&hst.occupancy) == 1) {
hgram_opts |= QDIST_PR_NODECIMAL;
}
hgram = qdist_pr(&hst.occupancy, 10, hgram_opts);
g_string_append_printf(buf, "TB hash occupancy %0.2f%% avg chain occ. "
"Histogram: %s\n",
qdist_avg(&hst.occupancy) * 100, hgram);
g_free(hgram);
hgram_opts = QDIST_PR_BORDER | QDIST_PR_LABELS;
hgram_bins = qdist_xmax(&hst.chain) - qdist_xmin(&hst.chain);
if (hgram_bins > 10) {
hgram_bins = 10;
} else {
hgram_bins = 0;
hgram_opts |= QDIST_PR_NODECIMAL | QDIST_PR_NOBINRANGE;
}
hgram = qdist_pr(&hst.chain, hgram_bins, hgram_opts);
g_string_append_printf(buf, "TB hash avg chain %0.3f buckets. "
"Histogram: %s\n",
qdist_avg(&hst.chain), hgram);
g_free(hgram);
}
struct tb_tree_stats {
size_t nb_tbs;
size_t host_size;
size_t target_size;
size_t max_target_size;
size_t direct_jmp_count;
size_t direct_jmp2_count;
size_t cross_page;
};
static gboolean tb_tree_stats_iter(gpointer key, gpointer value, gpointer data)
{
const TranslationBlock *tb = value;
struct tb_tree_stats *tst = data;
tst->nb_tbs++;
tst->host_size += tb->tc.size;
tst->target_size += tb->size;
if (tb->size > tst->max_target_size) {
tst->max_target_size = tb->size;
}
if (tb->page_addr[1] != -1) {
tst->cross_page++;
}
if (tb->jmp_reset_offset[0] != TB_JMP_OFFSET_INVALID) {
tst->direct_jmp_count++;
if (tb->jmp_reset_offset[1] != TB_JMP_OFFSET_INVALID) {
tst->direct_jmp2_count++;
}
}
return false;
}
static void tlb_flush_counts(size_t *pfull, size_t *ppart, size_t *pelide)
{
CPUState *cpu;
size_t full = 0, part = 0, elide = 0;
CPU_FOREACH(cpu) {
full += qatomic_read(&cpu->neg.tlb.c.full_flush_count);
part += qatomic_read(&cpu->neg.tlb.c.part_flush_count);
elide += qatomic_read(&cpu->neg.tlb.c.elide_flush_count);
}
*pfull = full;
*ppart = part;
*pelide = elide;
}
static void tcg_dump_info(GString *buf)
{
g_string_append_printf(buf, "[TCG profiler not compiled]\n");
}
static void dump_exec_info(GString *buf)
{
struct tb_tree_stats tst = {};
struct qht_stats hst;
size_t nb_tbs, flush_full, flush_part, flush_elide;
tcg_tb_foreach(tb_tree_stats_iter, &tst);
nb_tbs = tst.nb_tbs;
/* XXX: avoid using doubles ? */
g_string_append_printf(buf, "Translation buffer state:\n");
/*
* Report total code size including the padding and TB structs;
* 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.
*/
g_string_append_printf(buf, "gen code size %zu/%zu\n",
tcg_code_size(), tcg_code_capacity());
g_string_append_printf(buf, "TB count %zu\n", nb_tbs);
g_string_append_printf(buf, "TB avg target size %zu max=%zu bytes\n",
nb_tbs ? tst.target_size / nb_tbs : 0,
tst.max_target_size);
g_string_append_printf(buf, "TB avg host size %zu bytes "
"(expansion ratio: %0.1f)\n",
nb_tbs ? tst.host_size / nb_tbs : 0,
tst.target_size ?
(double)tst.host_size / tst.target_size : 0);
g_string_append_printf(buf, "cross page TB count %zu (%zu%%)\n",
tst.cross_page,
nb_tbs ? (tst.cross_page * 100) / nb_tbs : 0);
g_string_append_printf(buf, "direct jump count %zu (%zu%%) "
"(2 jumps=%zu %zu%%)\n",
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);
print_qht_statistics(hst, buf);
qht_statistics_destroy(&hst);
g_string_append_printf(buf, "\nStatistics:\n");
g_string_append_printf(buf, "TB flush count %u\n",
qatomic_read(&tb_ctx.tb_flush_count));
g_string_append_printf(buf, "TB invalidate count %u\n",
qatomic_read(&tb_ctx.tb_phys_invalidate_count));
tlb_flush_counts(&flush_full, &flush_part, &flush_elide);
g_string_append_printf(buf, "TLB full flushes %zu\n", flush_full);
g_string_append_printf(buf, "TLB partial flushes %zu\n", flush_part);
g_string_append_printf(buf, "TLB elided flushes %zu\n", flush_elide);
tcg_dump_info(buf);
}
HumanReadableText *qmp_x_query_jit(Error **errp) HumanReadableText *qmp_x_query_jit(Error **errp)
{ {
g_autoptr(GString) buf = g_string_new(""); g_autoptr(GString) buf = g_string_new("");
@@ -215,11 +66,6 @@ HumanReadableText *qmp_x_query_jit(Error **errp)
return human_readable_text_from_str(buf); return human_readable_text_from_str(buf);
} }
static void tcg_dump_op_count(GString *buf)
{
g_string_append_printf(buf, "[TCG profiler not compiled]\n");
}
HumanReadableText *qmp_x_query_opcount(Error **errp) HumanReadableText *qmp_x_query_opcount(Error **errp)
{ {
g_autoptr(GString) buf = g_string_new(""); g_autoptr(GString) buf = g_string_new("");

View File

@@ -327,7 +327,8 @@ static TCGOp *copy_st_ptr(TCGOp **begin_op, TCGOp *op)
return op; return op;
} }
static TCGOp *copy_call(TCGOp **begin_op, TCGOp *op, void *func, int *cb_idx) static TCGOp *copy_call(TCGOp **begin_op, TCGOp *op, void *empty_func,
void *func, int *cb_idx)
{ {
TCGOp *old_op; TCGOp *old_op;
int func_idx; int func_idx;
@@ -371,7 +372,8 @@ static TCGOp *append_udata_cb(const struct qemu_plugin_dyn_cb *cb,
} }
/* call */ /* call */
op = copy_call(&begin_op, op, cb->f.vcpu_udata, cb_idx); op = copy_call(&begin_op, op, HELPER(plugin_vcpu_udata_cb),
cb->f.vcpu_udata, cb_idx);
return op; return op;
} }
@@ -418,7 +420,8 @@ static TCGOp *append_mem_cb(const struct qemu_plugin_dyn_cb *cb,
if (type == PLUGIN_GEN_CB_MEM) { if (type == PLUGIN_GEN_CB_MEM) {
/* call */ /* call */
op = copy_call(&begin_op, op, cb->f.vcpu_udata, cb_idx); op = copy_call(&begin_op, op, HELPER(plugin_vcpu_mem_cb),
cb->f.vcpu_udata, cb_idx);
} }
return op; return op;

View File

@@ -34,7 +34,6 @@
#include "qemu/timer.h" #include "qemu/timer.h"
#include "exec/exec-all.h" #include "exec/exec-all.h"
#include "exec/hwaddr.h" #include "exec/hwaddr.h"
#include "exec/tb-flush.h"
#include "exec/gdbstub.h" #include "exec/gdbstub.h"
#include "tcg-accel-ops.h" #include "tcg-accel-ops.h"
@@ -78,13 +77,6 @@ int tcg_cpus_exec(CPUState *cpu)
return ret; return ret;
} }
static void tcg_cpu_reset_hold(CPUState *cpu)
{
tcg_flush_jmp_cache(cpu);
tlb_flush(cpu);
}
/* mask must never be zero, except for A20 change call */ /* mask must never be zero, except for A20 change call */
void tcg_handle_interrupt(CPUState *cpu, int mask) void tcg_handle_interrupt(CPUState *cpu, int mask)
{ {
@@ -213,7 +205,6 @@ static void tcg_accel_ops_init(AccelOpsClass *ops)
} }
} }
ops->cpu_reset_hold = tcg_cpu_reset_hold;
ops->supports_guest_debug = tcg_supports_guest_debug; ops->supports_guest_debug = tcg_supports_guest_debug;
ops->insert_breakpoint = tcg_insert_breakpoint; ops->insert_breakpoint = tcg_insert_breakpoint;
ops->remove_breakpoint = tcg_remove_breakpoint; ops->remove_breakpoint = tcg_remove_breakpoint;

View File

@@ -645,6 +645,133 @@ 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)
{
uint32_t hgram_opts;
size_t hgram_bins;
char *hgram;
if (!hst.head_buckets) {
return;
}
g_string_append_printf(buf, "TB hash buckets %zu/%zu "
"(%0.2f%% head buckets used)\n",
hst.used_head_buckets, hst.head_buckets,
(double)hst.used_head_buckets /
hst.head_buckets * 100);
hgram_opts = QDIST_PR_BORDER | QDIST_PR_LABELS;
hgram_opts |= QDIST_PR_100X | QDIST_PR_PERCENT;
if (qdist_xmax(&hst.occupancy) - qdist_xmin(&hst.occupancy) == 1) {
hgram_opts |= QDIST_PR_NODECIMAL;
}
hgram = qdist_pr(&hst.occupancy, 10, hgram_opts);
g_string_append_printf(buf, "TB hash occupancy %0.2f%% avg chain occ. "
"Histogram: %s\n",
qdist_avg(&hst.occupancy) * 100, hgram);
g_free(hgram);
hgram_opts = QDIST_PR_BORDER | QDIST_PR_LABELS;
hgram_bins = qdist_xmax(&hst.chain) - qdist_xmin(&hst.chain);
if (hgram_bins > 10) {
hgram_bins = 10;
} else {
hgram_bins = 0;
hgram_opts |= QDIST_PR_NODECIMAL | QDIST_PR_NOBINRANGE;
}
hgram = qdist_pr(&hst.chain, hgram_bins, hgram_opts);
g_string_append_printf(buf, "TB hash avg chain %0.3f buckets. "
"Histogram: %s\n",
qdist_avg(&hst.chain), hgram);
g_free(hgram);
}
struct tb_tree_stats {
size_t nb_tbs;
size_t host_size;
size_t target_size;
size_t max_target_size;
size_t direct_jmp_count;
size_t direct_jmp2_count;
size_t cross_page;
};
static gboolean tb_tree_stats_iter(gpointer key, gpointer value, gpointer data)
{
const TranslationBlock *tb = value;
struct tb_tree_stats *tst = data;
tst->nb_tbs++;
tst->host_size += tb->tc.size;
tst->target_size += tb->size;
if (tb->size > tst->max_target_size) {
tst->max_target_size = tb->size;
}
if (tb_page_addr1(tb) != -1) {
tst->cross_page++;
}
if (tb->jmp_reset_offset[0] != TB_JMP_OFFSET_INVALID) {
tst->direct_jmp_count++;
if (tb->jmp_reset_offset[1] != TB_JMP_OFFSET_INVALID) {
tst->direct_jmp2_count++;
}
}
return false;
}
void dump_exec_info(GString *buf)
{
struct tb_tree_stats tst = {};
struct qht_stats hst;
size_t nb_tbs, flush_full, flush_part, flush_elide;
tcg_tb_foreach(tb_tree_stats_iter, &tst);
nb_tbs = tst.nb_tbs;
/* XXX: avoid using doubles ? */
g_string_append_printf(buf, "Translation buffer state:\n");
/*
* Report total code size including the padding and TB structs;
* 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.
*/
g_string_append_printf(buf, "gen code size %zu/%zu\n",
tcg_code_size(), tcg_code_capacity());
g_string_append_printf(buf, "TB count %zu\n", nb_tbs);
g_string_append_printf(buf, "TB avg target size %zu max=%zu bytes\n",
nb_tbs ? tst.target_size / nb_tbs : 0,
tst.max_target_size);
g_string_append_printf(buf, "TB avg host size %zu bytes "
"(expansion ratio: %0.1f)\n",
nb_tbs ? tst.host_size / nb_tbs : 0,
tst.target_size ?
(double)tst.host_size / tst.target_size : 0);
g_string_append_printf(buf, "cross page TB count %zu (%zu%%)\n",
tst.cross_page,
nb_tbs ? (tst.cross_page * 100) / nb_tbs : 0);
g_string_append_printf(buf, "direct jump count %zu (%zu%%) "
"(2 jumps=%zu %zu%%)\n",
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);
print_qht_statistics(hst, buf);
qht_statistics_destroy(&hst);
g_string_append_printf(buf, "\nStatistics:\n");
g_string_append_printf(buf, "TB flush count %u\n",
qatomic_read(&tb_ctx.tb_flush_count));
g_string_append_printf(buf, "TB invalidate count %u\n",
qatomic_read(&tb_ctx.tb_phys_invalidate_count));
tlb_flush_counts(&flush_full, &flush_part, &flush_elide);
g_string_append_printf(buf, "TLB full flushes %zu\n", flush_full);
g_string_append_printf(buf, "TLB partial flushes %zu\n", flush_part);
g_string_append_printf(buf, "TLB elided flushes %zu\n", flush_elide);
tcg_dump_info(buf);
}
#else /* CONFIG_USER_ONLY */ #else /* CONFIG_USER_ONLY */
void cpu_interrupt(CPUState *cpu, int mask) void cpu_interrupt(CPUState *cpu, int mask)
@@ -673,3 +800,11 @@ void tcg_flush_jmp_cache(CPUState *cpu)
qatomic_set(&jc->array[i].tb, NULL); qatomic_set(&jc->array[i].tb, NULL);
} }
} }
/* This is a wrapper for common code that can not use CONFIG_SOFTMMU */
void tcg_flush_softmmu_tlb(CPUState *cs)
{
#ifdef CONFIG_SOFTMMU
tlb_flush(cs);
#endif
}

View File

@@ -14,10 +14,6 @@ void qemu_init_vcpu(CPUState *cpu)
{ {
} }
void cpu_exec_reset_hold(CPUState *cpu)
{
}
/* User mode emulation does not support record/replay yet. */ /* User mode emulation does not support record/replay yet. */
bool replay_exception(void) bool replay_exception(void)

View File

@@ -1781,7 +1781,7 @@ static AudioState *audio_init(Audiodev *dev, Error **errp)
QTAILQ_INSERT_TAIL(&audio_states, s, list); QTAILQ_INSERT_TAIL(&audio_states, s, list);
QLIST_INIT (&s->card_head); QLIST_INIT (&s->card_head);
vmstate_register_any(NULL, &vmstate_audio, s); vmstate_register (NULL, 0, &vmstate_audio, s);
return s; return s;
out: out:

View File

@@ -97,10 +97,6 @@ static int wav_init_out(HWVoiceOut *hw, struct audsettings *as,
dolog ("WAVE files can not handle 32bit formats\n"); dolog ("WAVE files can not handle 32bit formats\n");
return -1; return -1;
case AUDIO_FORMAT_F32:
dolog("WAVE files can not handle float formats\n");
return -1;
default: default:
abort(); abort();
} }

View File

@@ -426,7 +426,8 @@ dbus_vmstate_complete(UserCreatable *uc, Error **errp)
return; return;
} }
if (vmstate_register_any(VMSTATE_IF(self), &dbus_vmstate, self) < 0) { if (vmstate_register(VMSTATE_IF(self), VMSTATE_INSTANCE_ID_ANY,
&dbus_vmstate, self) < 0) {
error_setg(errp, "Failed to register vmstate"); error_setg(errp, "Failed to register vmstate");
} }
} }

View File

@@ -534,8 +534,11 @@ 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) { if (migrate_add_blocker(tpm_emu->migration_blocker, &err) < 0) {
error_report_err(err); error_report_err(err);
error_free(tpm_emu->migration_blocker);
tpm_emu->migration_blocker = NULL;
return -1; return -1;
} }
} }
@@ -975,7 +978,8 @@ static void tpm_emulator_inst_init(Object *obj)
qemu_add_vm_change_state_handler(tpm_emulator_vm_state_change, qemu_add_vm_change_state_handler(tpm_emulator_vm_state_change,
tpm_emu); tpm_emu);
vmstate_register_any(NULL, &vmstate_tpm_emulator, obj); vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY,
&vmstate_tpm_emulator, obj);
} }
/* /*
@@ -1012,7 +1016,10 @@ static void tpm_emulator_inst_finalize(Object *obj)
qapi_free_TPMEmulatorOptions(tpm_emu->options); qapi_free_TPMEmulatorOptions(tpm_emu->options);
migrate_del_blocker(&tpm_emu->migration_blocker); if (tpm_emu->migration_blocker) {
migrate_del_blocker(tpm_emu->migration_blocker);
error_free(tpm_emu->migration_blocker);
}
tpm_sized_buffer_reset(&state_blobs->volatil); tpm_sized_buffer_reset(&state_blobs->volatil);
tpm_sized_buffer_reset(&state_blobs->permanent); tpm_sized_buffer_reset(&state_blobs->permanent);

190
block.c
View File

@@ -820,17 +820,12 @@ int bdrv_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz)
int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo) int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo)
{ {
BlockDriver *drv = bs->drv; BlockDriver *drv = bs->drv;
BlockDriverState *filtered; BlockDriverState *filtered = bdrv_filter_bs(bs);
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
if (drv && drv->bdrv_probe_geometry) { if (drv && drv->bdrv_probe_geometry) {
return drv->bdrv_probe_geometry(bs, geo); return drv->bdrv_probe_geometry(bs, geo);
} } else if (filtered) {
filtered = bdrv_filter_bs(bs);
if (filtered) {
return bdrv_probe_geometry(filtered, geo); return bdrv_probe_geometry(filtered, geo);
} }
@@ -1707,14 +1702,12 @@ bdrv_open_driver(BlockDriverState *bs, BlockDriver *drv, const char *node_name,
return 0; return 0;
open_failed: open_failed:
bs->drv = NULL; bs->drv = NULL;
bdrv_graph_wrlock(NULL);
if (bs->file != NULL) { if (bs->file != NULL) {
bdrv_graph_wrlock(NULL);
bdrv_unref_child(bs, bs->file); bdrv_unref_child(bs, bs->file);
bdrv_graph_wrunlock();
assert(!bs->file); assert(!bs->file);
} }
bdrv_graph_wrunlock();
g_free(bs->opaque); g_free(bs->opaque);
bs->opaque = NULL; bs->opaque = NULL;
return ret; return ret;
@@ -1856,12 +1849,9 @@ static int bdrv_open_common(BlockDriverState *bs, BlockBackend *file,
Error *local_err = NULL; Error *local_err = NULL;
bool ro; bool ro;
GLOBAL_STATE_CODE();
bdrv_graph_rdlock_main_loop();
assert(bs->file == NULL); assert(bs->file == NULL);
assert(options != NULL && bs->options != options); assert(options != NULL && bs->options != options);
bdrv_graph_rdunlock_main_loop(); GLOBAL_STATE_CODE();
opts = qemu_opts_create(&bdrv_runtime_opts, NULL, 0, &error_abort); opts = qemu_opts_create(&bdrv_runtime_opts, NULL, 0, &error_abort);
if (!qemu_opts_absorb_qdict(opts, options, errp)) { if (!qemu_opts_absorb_qdict(opts, options, errp)) {
@@ -3219,6 +3209,8 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
bdrv_graph_wrlock(child_bs);
child = bdrv_attach_child_common(child_bs, child_name, child_class, child = bdrv_attach_child_common(child_bs, child_name, child_class,
child_role, perm, shared_perm, opaque, child_role, perm, shared_perm, opaque,
tran, errp); tran, errp);
@@ -3231,8 +3223,9 @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
out: out:
tran_finalize(tran, ret); tran_finalize(tran, ret);
bdrv_graph_wrunlock();
bdrv_schedule_unref(child_bs); bdrv_unref(child_bs);
return ret < 0 ? NULL : child; return ret < 0 ? NULL : child;
} }
@@ -3537,7 +3530,19 @@ out:
* *
* If a backing child is already present (i.e. we're detaching a node), that * If a backing child is already present (i.e. we're detaching a node), that
* child node must be drained. * child node must be drained.
*
* After calling this function, the transaction @tran may only be completed
* while holding a writer lock for the graph.
*/ */
static int GRAPH_WRLOCK
bdrv_set_backing_noperm(BlockDriverState *bs,
BlockDriverState *backing_hd,
Transaction *tran, Error **errp)
{
GLOBAL_STATE_CODE();
return bdrv_set_file_or_backing_noperm(bs, backing_hd, true, tran, errp);
}
int bdrv_set_backing_hd_drained(BlockDriverState *bs, int bdrv_set_backing_hd_drained(BlockDriverState *bs,
BlockDriverState *backing_hd, BlockDriverState *backing_hd,
Error **errp) Error **errp)
@@ -3550,8 +3555,9 @@ int bdrv_set_backing_hd_drained(BlockDriverState *bs,
if (bs->backing) { if (bs->backing) {
assert(bs->backing->bs->quiesce_counter > 0); assert(bs->backing->bs->quiesce_counter > 0);
} }
bdrv_graph_wrlock(backing_hd);
ret = bdrv_set_file_or_backing_noperm(bs, backing_hd, true, tran, errp); ret = bdrv_set_backing_noperm(bs, backing_hd, tran, errp);
if (ret < 0) { if (ret < 0) {
goto out; goto out;
} }
@@ -3559,25 +3565,20 @@ int bdrv_set_backing_hd_drained(BlockDriverState *bs,
ret = bdrv_refresh_perms(bs, tran, errp); ret = bdrv_refresh_perms(bs, tran, errp);
out: out:
tran_finalize(tran, ret); tran_finalize(tran, ret);
bdrv_graph_wrunlock();
return ret; return ret;
} }
int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd, int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
Error **errp) Error **errp)
{ {
BlockDriverState *drain_bs; BlockDriverState *drain_bs = bs->backing ? bs->backing->bs : bs;
int ret; int ret;
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
bdrv_graph_rdlock_main_loop();
drain_bs = bs->backing ? bs->backing->bs : bs;
bdrv_graph_rdunlock_main_loop();
bdrv_ref(drain_bs); bdrv_ref(drain_bs);
bdrv_drained_begin(drain_bs); bdrv_drained_begin(drain_bs);
bdrv_graph_wrlock(backing_hd);
ret = bdrv_set_backing_hd_drained(bs, backing_hd, errp); ret = bdrv_set_backing_hd_drained(bs, backing_hd, errp);
bdrv_graph_wrunlock();
bdrv_drained_end(drain_bs); bdrv_drained_end(drain_bs);
bdrv_unref(drain_bs); bdrv_unref(drain_bs);
@@ -3611,7 +3612,6 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
Error *local_err = NULL; Error *local_err = NULL;
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
if (bs->backing != NULL) { if (bs->backing != NULL) {
goto free_exit; goto free_exit;
@@ -3653,7 +3653,10 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
implicit_backing = !strcmp(bs->auto_backing_file, bs->backing_file); implicit_backing = !strcmp(bs->auto_backing_file, bs->backing_file);
} }
bdrv_graph_rdlock_main_loop();
backing_filename = bdrv_get_full_backing_filename(bs, &local_err); backing_filename = bdrv_get_full_backing_filename(bs, &local_err);
bdrv_graph_rdunlock_main_loop();
if (local_err) { if (local_err) {
ret = -EINVAL; ret = -EINVAL;
error_propagate(errp, local_err); error_propagate(errp, local_err);
@@ -3684,7 +3687,9 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *parent_options,
} }
if (implicit_backing) { if (implicit_backing) {
bdrv_graph_rdlock_main_loop();
bdrv_refresh_filename(backing_hd); bdrv_refresh_filename(backing_hd);
bdrv_graph_rdunlock_main_loop();
pstrcpy(bs->auto_backing_file, sizeof(bs->auto_backing_file), pstrcpy(bs->auto_backing_file, sizeof(bs->auto_backing_file),
backing_hd->filename); backing_hd->filename);
} }
@@ -4755,8 +4760,8 @@ bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state,
{ {
BlockDriverState *bs = reopen_state->bs; BlockDriverState *bs = reopen_state->bs;
BlockDriverState *new_child_bs; BlockDriverState *new_child_bs;
BlockDriverState *old_child_bs; BlockDriverState *old_child_bs = is_backing ? child_bs(bs->backing) :
child_bs(bs->file);
const char *child_name = is_backing ? "backing" : "file"; const char *child_name = is_backing ? "backing" : "file";
QObject *value; QObject *value;
const char *str; const char *str;
@@ -4771,8 +4776,6 @@ bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state,
return 0; return 0;
} }
bdrv_graph_rdlock_main_loop();
switch (qobject_type(value)) { switch (qobject_type(value)) {
case QTYPE_QNULL: case QTYPE_QNULL:
assert(is_backing); /* The 'file' option does not allow a null value */ assert(is_backing); /* The 'file' option does not allow a null value */
@@ -4782,16 +4785,17 @@ bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state,
str = qstring_get_str(qobject_to(QString, value)); str = qstring_get_str(qobject_to(QString, value));
new_child_bs = bdrv_lookup_bs(NULL, str, errp); new_child_bs = bdrv_lookup_bs(NULL, str, errp);
if (new_child_bs == NULL) { if (new_child_bs == NULL) {
ret = -EINVAL; return -EINVAL;
goto out_rdlock;
} }
bdrv_graph_rdlock_main_loop();
has_child = bdrv_recurse_has_child(new_child_bs, bs); has_child = bdrv_recurse_has_child(new_child_bs, bs);
bdrv_graph_rdunlock_main_loop();
if (has_child) { if (has_child) {
error_setg(errp, "Making '%s' a %s child of '%s' would create a " error_setg(errp, "Making '%s' a %s child of '%s' would create a "
"cycle", str, child_name, bs->node_name); "cycle", str, child_name, bs->node_name);
ret = -EINVAL; return -EINVAL;
goto out_rdlock;
} }
break; break;
default: default:
@@ -4802,23 +4806,19 @@ bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state,
g_assert_not_reached(); g_assert_not_reached();
} }
old_child_bs = is_backing ? child_bs(bs->backing) : child_bs(bs->file);
if (old_child_bs == new_child_bs) { if (old_child_bs == new_child_bs) {
ret = 0; return 0;
goto out_rdlock;
} }
if (old_child_bs) { if (old_child_bs) {
if (bdrv_skip_implicit_filters(old_child_bs) == new_child_bs) { if (bdrv_skip_implicit_filters(old_child_bs) == new_child_bs) {
ret = 0; return 0;
goto out_rdlock;
} }
if (old_child_bs->implicit) { if (old_child_bs->implicit) {
error_setg(errp, "Cannot replace implicit %s child of %s", error_setg(errp, "Cannot replace implicit %s child of %s",
child_name, bs->node_name); child_name, bs->node_name);
ret = -EPERM; return -EPERM;
goto out_rdlock;
} }
} }
@@ -4829,8 +4829,7 @@ bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state,
*/ */
error_setg(errp, "'%s' is a %s filter node that does not support a " error_setg(errp, "'%s' is a %s filter node that does not support a "
"%s child", bs->node_name, bs->drv->format_name, child_name); "%s child", bs->node_name, bs->drv->format_name, child_name);
ret = -EINVAL; return -EINVAL;
goto out_rdlock;
} }
if (is_backing) { if (is_backing) {
@@ -4851,7 +4850,6 @@ bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state,
aio_context_acquire(ctx); aio_context_acquire(ctx);
} }
bdrv_graph_rdunlock_main_loop();
bdrv_graph_wrlock(new_child_bs); bdrv_graph_wrlock(new_child_bs);
ret = bdrv_set_file_or_backing_noperm(bs, new_child_bs, is_backing, ret = bdrv_set_file_or_backing_noperm(bs, new_child_bs, is_backing,
@@ -4870,10 +4868,6 @@ bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state,
} }
return ret; return ret;
out_rdlock:
bdrv_graph_rdunlock_main_loop();
return ret;
} }
/* /*
@@ -5014,16 +5008,13 @@ bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
* file or if the image file has a backing file name as part of * file or if the image file has a backing file name as part of
* its metadata. Otherwise the 'backing' option can be omitted. * its metadata. Otherwise the 'backing' option can be omitted.
*/ */
bdrv_graph_rdlock_main_loop();
if (drv->supports_backing && reopen_state->backing_missing && if (drv->supports_backing && reopen_state->backing_missing &&
(reopen_state->bs->backing || reopen_state->bs->backing_file[0])) { (reopen_state->bs->backing || reopen_state->bs->backing_file[0])) {
error_setg(errp, "backing is missing for '%s'", error_setg(errp, "backing is missing for '%s'",
reopen_state->bs->node_name); reopen_state->bs->node_name);
bdrv_graph_rdunlock_main_loop();
ret = -EINVAL; ret = -EINVAL;
goto error; goto error;
} }
bdrv_graph_rdunlock_main_loop();
/* /*
* Allow changing the 'backing' option. The new value can be * Allow changing the 'backing' option. The new value can be
@@ -5209,15 +5200,14 @@ static void bdrv_close(BlockDriverState *bs)
bs->drv = NULL; bs->drv = NULL;
} }
bdrv_graph_wrlock(bs); bdrv_graph_wrlock(NULL);
QLIST_FOREACH_SAFE(child, &bs->children, next, next) { QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
bdrv_unref_child(bs, child); bdrv_unref_child(bs, child);
} }
bdrv_graph_wrunlock();
assert(!bs->backing); assert(!bs->backing);
assert(!bs->file); assert(!bs->file);
bdrv_graph_wrunlock();
g_free(bs->opaque); g_free(bs->opaque);
bs->opaque = NULL; bs->opaque = NULL;
qatomic_set(&bs->copy_on_read, 0); qatomic_set(&bs->copy_on_read, 0);
@@ -5422,9 +5412,6 @@ bdrv_replace_node_noperm(BlockDriverState *from,
} }
/* /*
* Switch all parents of @from to point to @to instead. @from and @to must be in
* the same AioContext and both must be drained.
*
* With auto_skip=true bdrv_replace_node_common skips updating from parents * With auto_skip=true bdrv_replace_node_common skips updating from parents
* if it creates a parent-child relation loop or if parent is block-job. * if it creates a parent-child relation loop or if parent is block-job.
* *
@@ -5434,9 +5421,10 @@ 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.
*/ */
static int GRAPH_WRLOCK static int bdrv_replace_node_common(BlockDriverState *from,
bdrv_replace_node_common(BlockDriverState *from, BlockDriverState *to, BlockDriverState *to,
bool auto_skip, bool detach_subchain, Error **errp) bool auto_skip, bool detach_subchain,
Error **errp)
{ {
Transaction *tran = tran_new(); Transaction *tran = tran_new();
g_autoptr(GSList) refresh_list = NULL; g_autoptr(GSList) refresh_list = NULL;
@@ -5445,10 +5433,6 @@ bdrv_replace_node_common(BlockDriverState *from, BlockDriverState *to,
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
assert(from->quiesce_counter);
assert(to->quiesce_counter);
assert(bdrv_get_aio_context(from) == bdrv_get_aio_context(to));
if (detach_subchain) { if (detach_subchain) {
assert(bdrv_chain_contains(from, to)); assert(bdrv_chain_contains(from, to));
assert(from != to); assert(from != to);
@@ -5460,6 +5444,17 @@ bdrv_replace_node_common(BlockDriverState *from, BlockDriverState *to,
} }
} }
/* Make sure that @from doesn't go away until we have successfully attached
* all of its parents to @to. */
bdrv_ref(from);
assert(qemu_get_current_aio_context() == qemu_get_aio_context());
assert(bdrv_get_aio_context(from) == bdrv_get_aio_context(to));
bdrv_drained_begin(from);
bdrv_drained_begin(to);
bdrv_graph_wrlock(to);
/* /*
* Do the replacement without permission update. * Do the replacement without permission update.
* Replacement may influence the permissions, we should calculate new * Replacement may influence the permissions, we should calculate new
@@ -5488,33 +5483,29 @@ bdrv_replace_node_common(BlockDriverState *from, BlockDriverState *to,
out: out:
tran_finalize(tran, ret); tran_finalize(tran, ret);
bdrv_graph_wrunlock();
bdrv_drained_end(to);
bdrv_drained_end(from);
bdrv_unref(from);
return ret; return ret;
} }
int bdrv_replace_node(BlockDriverState *from, BlockDriverState *to, int bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
Error **errp) Error **errp)
{ {
GLOBAL_STATE_CODE();
return bdrv_replace_node_common(from, to, true, false, errp); return bdrv_replace_node_common(from, to, true, false, errp);
} }
int bdrv_drop_filter(BlockDriverState *bs, Error **errp) int bdrv_drop_filter(BlockDriverState *bs, Error **errp)
{ {
BlockDriverState *child_bs;
int ret;
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
bdrv_graph_rdlock_main_loop(); return bdrv_replace_node_common(bs, bdrv_filter_or_cow_bs(bs), true, true,
child_bs = bdrv_filter_or_cow_bs(bs); errp);
bdrv_graph_rdunlock_main_loop();
bdrv_drained_begin(child_bs);
bdrv_graph_wrlock(bs);
ret = bdrv_replace_node_common(bs, child_bs, true, true, errp);
bdrv_graph_wrunlock();
bdrv_drained_end(child_bs);
return ret;
} }
/* /*
@@ -5541,9 +5532,7 @@ int bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top,
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
bdrv_graph_rdlock_main_loop();
assert(!bs_new->backing); assert(!bs_new->backing);
bdrv_graph_rdunlock_main_loop();
old_context = bdrv_get_aio_context(bs_top); old_context = bdrv_get_aio_context(bs_top);
bdrv_drained_begin(bs_top); bdrv_drained_begin(bs_top);
@@ -5711,19 +5700,9 @@ BlockDriverState *bdrv_insert_node(BlockDriverState *bs, QDict *options,
goto fail; goto fail;
} }
/*
* Make sure that @bs doesn't go away until we have successfully attached
* all of its parents to @new_node_bs and undrained it again.
*/
bdrv_ref(bs);
bdrv_drained_begin(bs); bdrv_drained_begin(bs);
bdrv_drained_begin(new_node_bs);
bdrv_graph_wrlock(new_node_bs);
ret = bdrv_replace_node(bs, new_node_bs, errp); ret = bdrv_replace_node(bs, new_node_bs, errp);
bdrv_graph_wrunlock();
bdrv_drained_end(new_node_bs);
bdrv_drained_end(bs); bdrv_drained_end(bs);
bdrv_unref(bs);
if (ret < 0) { if (ret < 0) {
error_prepend(errp, "Could not replace node: "); error_prepend(errp, "Could not replace node: ");
@@ -5769,14 +5748,13 @@ int coroutine_fn bdrv_co_check(BlockDriverState *bs,
* image file header * image file header
* -ENOTSUP - format driver doesn't support changing the backing file * -ENOTSUP - format driver doesn't support changing the backing file
*/ */
int coroutine_fn int bdrv_change_backing_file(BlockDriverState *bs, const char *backing_file,
bdrv_co_change_backing_file(BlockDriverState *bs, const char *backing_file,
const char *backing_fmt, bool require) const char *backing_fmt, bool require)
{ {
BlockDriver *drv = bs->drv; BlockDriver *drv = bs->drv;
int ret; int ret;
IO_CODE(); GLOBAL_STATE_CODE();
if (!drv) { if (!drv) {
return -ENOMEDIUM; return -ENOMEDIUM;
@@ -5791,8 +5769,8 @@ bdrv_co_change_backing_file(BlockDriverState *bs, const char *backing_file,
return -EINVAL; return -EINVAL;
} }
if (drv->bdrv_co_change_backing_file != NULL) { if (drv->bdrv_change_backing_file != NULL) {
ret = drv->bdrv_co_change_backing_file(bs, backing_file, backing_fmt); ret = drv->bdrv_change_backing_file(bs, backing_file, backing_fmt);
} else { } else {
ret = -ENOTSUP; ret = -ENOTSUP;
} }
@@ -5849,8 +5827,7 @@ BlockDriverState *bdrv_find_base(BlockDriverState *bs)
* between @bs and @base is frozen. @errp is set if that's the case. * between @bs and @base is frozen. @errp is set if that's the case.
* @base must be reachable from @bs, or NULL. * @base must be reachable from @bs, or NULL.
*/ */
static bool GRAPH_RDLOCK bool bdrv_is_backing_chain_frozen(BlockDriverState *bs, BlockDriverState *base,
bdrv_is_backing_chain_frozen(BlockDriverState *bs, BlockDriverState *base,
Error **errp) Error **errp)
{ {
BlockDriverState *i; BlockDriverState *i;
@@ -5975,15 +5952,15 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
bdrv_ref(top); bdrv_ref(top);
bdrv_drained_begin(base); bdrv_drained_begin(base);
bdrv_graph_wrlock(base); bdrv_graph_rdlock_main_loop();
if (!top->drv || !base->drv) { if (!top->drv || !base->drv) {
goto exit_wrlock; goto exit;
} }
/* Make sure that base is in the backing chain of top */ /* Make sure that base is in the backing chain of top */
if (!bdrv_chain_contains(top, base)) { if (!bdrv_chain_contains(top, base)) {
goto exit_wrlock; goto exit;
} }
/* If 'base' recursively inherits from 'top' then we should set /* If 'base' recursively inherits from 'top' then we should set
@@ -6015,8 +5992,6 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
* That's a FIXME. * That's a FIXME.
*/ */
bdrv_replace_node_common(top, base, false, false, &local_err); bdrv_replace_node_common(top, base, false, false, &local_err);
bdrv_graph_wrunlock();
if (local_err) { if (local_err) {
error_report_err(local_err); error_report_err(local_err);
goto exit; goto exit;
@@ -6049,11 +6024,8 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
} }
ret = 0; ret = 0;
goto exit;
exit_wrlock:
bdrv_graph_wrunlock();
exit: exit:
bdrv_graph_rdunlock_main_loop();
bdrv_drained_end(base); bdrv_drained_end(base);
bdrv_unref(top); bdrv_unref(top);
return ret; return ret;
@@ -6615,7 +6587,7 @@ int bdrv_has_zero_init_1(BlockDriverState *bs)
return 1; return 1;
} }
int coroutine_mixed_fn bdrv_has_zero_init(BlockDriverState *bs) int bdrv_has_zero_init(BlockDriverState *bs)
{ {
BlockDriverState *filtered; BlockDriverState *filtered;
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
@@ -8128,7 +8100,7 @@ static bool append_strong_runtime_options(QDict *d, BlockDriverState *bs)
/* Note: This function may return false positives; it may return true /* Note: This function may return false positives; it may return true
* even if opening the backing file specified by bs's image header * even if opening the backing file specified by bs's image header
* would result in exactly bs->backing. */ * would result in exactly bs->backing. */
static bool GRAPH_RDLOCK bdrv_backing_overridden(BlockDriverState *bs) static bool bdrv_backing_overridden(BlockDriverState *bs)
{ {
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
if (bs->backing) { if (bs->backing) {
@@ -8502,8 +8474,8 @@ BdrvChild *bdrv_primary_child(BlockDriverState *bs)
return found; return found;
} }
static BlockDriverState * GRAPH_RDLOCK static BlockDriverState *bdrv_do_skip_filters(BlockDriverState *bs,
bdrv_do_skip_filters(BlockDriverState *bs, bool stop_on_explicit_filter) bool stop_on_explicit_filter)
{ {
BdrvChild *c; BdrvChild *c;

View File

@@ -374,6 +374,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
assert(bs); assert(bs);
assert(target); assert(target);
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
/* QMP interface protects us from these cases */ /* QMP interface protects us from these cases */
assert(sync_mode != MIRROR_SYNC_MODE_INCREMENTAL); assert(sync_mode != MIRROR_SYNC_MODE_INCREMENTAL);
@@ -384,33 +385,31 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
return NULL; return NULL;
} }
bdrv_graph_rdlock_main_loop();
if (!bdrv_is_inserted(bs)) { if (!bdrv_is_inserted(bs)) {
error_setg(errp, "Device is not inserted: %s", error_setg(errp, "Device is not inserted: %s",
bdrv_get_device_name(bs)); bdrv_get_device_name(bs));
goto error_rdlock; return NULL;
} }
if (!bdrv_is_inserted(target)) { if (!bdrv_is_inserted(target)) {
error_setg(errp, "Device is not inserted: %s", error_setg(errp, "Device is not inserted: %s",
bdrv_get_device_name(target)); bdrv_get_device_name(target));
goto error_rdlock; return NULL;
} }
if (compress && !bdrv_supports_compressed_writes(target)) { if (compress && !bdrv_supports_compressed_writes(target)) {
error_setg(errp, "Compression is not supported for this drive %s", error_setg(errp, "Compression is not supported for this drive %s",
bdrv_get_device_name(target)); bdrv_get_device_name(target));
goto error_rdlock; return NULL;
} }
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) { if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) {
goto error_rdlock; return NULL;
} }
if (bdrv_op_is_blocked(target, BLOCK_OP_TYPE_BACKUP_TARGET, errp)) { if (bdrv_op_is_blocked(target, BLOCK_OP_TYPE_BACKUP_TARGET, errp)) {
goto error_rdlock; return NULL;
} }
bdrv_graph_rdunlock_main_loop();
if (perf->max_workers < 1 || perf->max_workers > INT_MAX) { if (perf->max_workers < 1 || perf->max_workers > INT_MAX) {
error_setg(errp, "max-workers must be between 1 and %d", INT_MAX); error_setg(errp, "max-workers must be between 1 and %d", INT_MAX);
@@ -438,7 +437,6 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
len = bdrv_getlength(bs); len = bdrv_getlength(bs);
if (len < 0) { if (len < 0) {
GRAPH_RDLOCK_GUARD_MAINLOOP();
error_setg_errno(errp, -len, "Unable to get length for '%s'", error_setg_errno(errp, -len, "Unable to get length for '%s'",
bdrv_get_device_or_node_name(bs)); bdrv_get_device_or_node_name(bs));
goto error; goto error;
@@ -446,7 +444,6 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
target_len = bdrv_getlength(target); target_len = bdrv_getlength(target);
if (target_len < 0) { if (target_len < 0) {
GRAPH_RDLOCK_GUARD_MAINLOOP();
error_setg_errno(errp, -target_len, "Unable to get length for '%s'", error_setg_errno(errp, -target_len, "Unable to get length for '%s'",
bdrv_get_device_or_node_name(bs)); bdrv_get_device_or_node_name(bs));
goto error; goto error;
@@ -496,10 +493,8 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
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 taken by copy-before-write filter target */
bdrv_graph_wrlock(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);
bdrv_graph_wrunlock();
return &job->common; return &job->common;
@@ -512,8 +507,4 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
} }
return NULL; return NULL;
error_rdlock:
bdrv_graph_rdunlock_main_loop();
return NULL;
} }

View File

@@ -508,8 +508,6 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
goto out; goto out;
} }
bdrv_graph_rdlock_main_loop();
bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED | bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED |
(BDRV_REQ_FUA & bs->file->bs->supported_write_flags); (BDRV_REQ_FUA & bs->file->bs->supported_write_flags);
bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED | bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED |
@@ -522,7 +520,7 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
if (s->align && (s->align >= INT_MAX || !is_power_of_2(s->align))) { if (s->align && (s->align >= INT_MAX || !is_power_of_2(s->align))) {
error_setg(errp, "Cannot meet constraints with align %" PRIu64, error_setg(errp, "Cannot meet constraints with align %" PRIu64,
s->align); s->align);
goto out_rdlock; goto out;
} }
align = MAX(s->align, bs->file->bs->bl.request_alignment); align = MAX(s->align, bs->file->bs->bl.request_alignment);
@@ -532,7 +530,7 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
!QEMU_IS_ALIGNED(s->max_transfer, align))) { !QEMU_IS_ALIGNED(s->max_transfer, align))) {
error_setg(errp, "Cannot meet constraints with max-transfer %" PRIu64, error_setg(errp, "Cannot meet constraints with max-transfer %" PRIu64,
s->max_transfer); s->max_transfer);
goto out_rdlock; goto out;
} }
s->opt_write_zero = qemu_opt_get_size(opts, "opt-write-zero", 0); s->opt_write_zero = qemu_opt_get_size(opts, "opt-write-zero", 0);
@@ -541,7 +539,7 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
!QEMU_IS_ALIGNED(s->opt_write_zero, align))) { !QEMU_IS_ALIGNED(s->opt_write_zero, align))) {
error_setg(errp, "Cannot meet constraints with opt-write-zero %" PRIu64, error_setg(errp, "Cannot meet constraints with opt-write-zero %" PRIu64,
s->opt_write_zero); s->opt_write_zero);
goto out_rdlock; goto out;
} }
s->max_write_zero = qemu_opt_get_size(opts, "max-write-zero", 0); s->max_write_zero = qemu_opt_get_size(opts, "max-write-zero", 0);
@@ -551,7 +549,7 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
MAX(s->opt_write_zero, align)))) { MAX(s->opt_write_zero, align)))) {
error_setg(errp, "Cannot meet constraints with max-write-zero %" PRIu64, error_setg(errp, "Cannot meet constraints with max-write-zero %" PRIu64,
s->max_write_zero); s->max_write_zero);
goto out_rdlock; goto out;
} }
s->opt_discard = qemu_opt_get_size(opts, "opt-discard", 0); s->opt_discard = qemu_opt_get_size(opts, "opt-discard", 0);
@@ -560,7 +558,7 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
!QEMU_IS_ALIGNED(s->opt_discard, align))) { !QEMU_IS_ALIGNED(s->opt_discard, align))) {
error_setg(errp, "Cannot meet constraints with opt-discard %" PRIu64, error_setg(errp, "Cannot meet constraints with opt-discard %" PRIu64,
s->opt_discard); s->opt_discard);
goto out_rdlock; goto out;
} }
s->max_discard = qemu_opt_get_size(opts, "max-discard", 0); s->max_discard = qemu_opt_get_size(opts, "max-discard", 0);
@@ -570,14 +568,12 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
MAX(s->opt_discard, align)))) { MAX(s->opt_discard, align)))) {
error_setg(errp, "Cannot meet constraints with max-discard %" PRIu64, error_setg(errp, "Cannot meet constraints with max-discard %" PRIu64,
s->max_discard); s->max_discard);
goto out_rdlock; goto out;
} }
bdrv_debug_event(bs, BLKDBG_NONE); bdrv_debug_event(bs, BLKDBG_NONE);
ret = 0; ret = 0;
out_rdlock:
bdrv_graph_rdunlock_main_loop();
out: out:
if (ret < 0) { if (ret < 0) {
qemu_mutex_destroy(&s->lock); qemu_mutex_destroy(&s->lock);
@@ -750,9 +746,12 @@ blkdebug_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes)
return bdrv_co_pdiscard(bs->file, offset, bytes); return bdrv_co_pdiscard(bs->file, offset, bytes);
} }
static int coroutine_fn GRAPH_RDLOCK static int coroutine_fn blkdebug_co_block_status(BlockDriverState *bs,
blkdebug_co_block_status(BlockDriverState *bs, bool want_zero, int64_t offset, bool want_zero,
int64_t bytes, int64_t *pnum, int64_t *map, int64_t offset,
int64_t bytes,
int64_t *pnum,
int64_t *map,
BlockDriverState **file) BlockDriverState **file)
{ {
int err; int err;
@@ -974,7 +973,7 @@ blkdebug_co_getlength(BlockDriverState *bs)
return bdrv_co_getlength(bs->file->bs); return bdrv_co_getlength(bs->file->bs);
} }
static void GRAPH_RDLOCK blkdebug_refresh_filename(BlockDriverState *bs) static void blkdebug_refresh_filename(BlockDriverState *bs)
{ {
BDRVBlkdebugState *s = bs->opaque; BDRVBlkdebugState *s = bs->opaque;
const QDictEntry *e; const QDictEntry *e;

View File

@@ -13,7 +13,6 @@
#include "block/block_int.h" #include "block/block_int.h"
#include "exec/memory.h" #include "exec/memory.h"
#include "exec/cpu-common.h" /* for qemu_ram_get_fd() */ #include "exec/cpu-common.h" /* for qemu_ram_get_fd() */
#include "qemu/defer-call.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "qapi/qmp/qdict.h" #include "qapi/qmp/qdict.h"
@@ -313,10 +312,10 @@ static void blkio_detach_aio_context(BlockDriverState *bs)
} }
/* /*
* Called by defer_call_end() or immediately if not in a deferred section. * Called by blk_io_unplug() or immediately if not plugged. Called without
* Called without blkio_lock. * blkio_lock.
*/ */
static void blkio_deferred_fn(void *opaque) static void blkio_unplug_fn(void *opaque)
{ {
BDRVBlkioState *s = opaque; BDRVBlkioState *s = opaque;
@@ -333,7 +332,7 @@ static void blkio_submit_io(BlockDriverState *bs)
{ {
BDRVBlkioState *s = bs->opaque; BDRVBlkioState *s = bs->opaque;
defer_call(blkio_deferred_fn, s); blk_io_plug_call(blkio_unplug_fn, s);
} }
static int coroutine_fn static int coroutine_fn

View File

@@ -130,13 +130,7 @@ static int coroutine_fn GRAPH_RDLOCK blkreplay_co_flush(BlockDriverState *bs)
static int blkreplay_snapshot_goto(BlockDriverState *bs, static int blkreplay_snapshot_goto(BlockDriverState *bs,
const char *snapshot_id) const char *snapshot_id)
{ {
BlockDriverState *file_bs; return bdrv_snapshot_goto(bs->file->bs, snapshot_id, NULL);
bdrv_graph_rdlock_main_loop();
file_bs = bs->file->bs;
bdrv_graph_rdunlock_main_loop();
return bdrv_snapshot_goto(file_bs, snapshot_id, NULL);
} }
static BlockDriver bdrv_blkreplay = { static BlockDriver bdrv_blkreplay = {

View File

@@ -33,8 +33,8 @@ typedef struct BlkverifyRequest {
uint64_t bytes; uint64_t bytes;
int flags; int flags;
int GRAPH_RDLOCK_PTR (*request_fn)( int (*request_fn)(BdrvChild *, int64_t, int64_t, QEMUIOVector *,
BdrvChild *, int64_t, int64_t, QEMUIOVector *, BdrvRequestFlags); BdrvRequestFlags);
int ret; /* test image result */ int ret; /* test image result */
int raw_ret; /* raw image result */ int raw_ret; /* raw image result */
@@ -170,11 +170,8 @@ static void coroutine_fn blkverify_do_test_req(void *opaque)
BlkverifyRequest *r = opaque; BlkverifyRequest *r = opaque;
BDRVBlkverifyState *s = r->bs->opaque; BDRVBlkverifyState *s = r->bs->opaque;
bdrv_graph_co_rdlock();
r->ret = r->request_fn(s->test_file, r->offset, r->bytes, r->qiov, r->ret = r->request_fn(s->test_file, r->offset, r->bytes, r->qiov,
r->flags); r->flags);
bdrv_graph_co_rdunlock();
r->done++; r->done++;
qemu_coroutine_enter_if_inactive(r->co); qemu_coroutine_enter_if_inactive(r->co);
} }
@@ -183,16 +180,13 @@ static void coroutine_fn blkverify_do_raw_req(void *opaque)
{ {
BlkverifyRequest *r = opaque; BlkverifyRequest *r = opaque;
bdrv_graph_co_rdlock();
r->raw_ret = r->request_fn(r->bs->file, r->offset, r->bytes, r->raw_qiov, r->raw_ret = r->request_fn(r->bs->file, r->offset, r->bytes, r->raw_qiov,
r->flags); r->flags);
bdrv_graph_co_rdunlock();
r->done++; r->done++;
qemu_coroutine_enter_if_inactive(r->co); qemu_coroutine_enter_if_inactive(r->co);
} }
static int coroutine_fn GRAPH_RDLOCK static int coroutine_fn
blkverify_co_prwv(BlockDriverState *bs, BlkverifyRequest *r, uint64_t offset, blkverify_co_prwv(BlockDriverState *bs, BlkverifyRequest *r, uint64_t offset,
uint64_t bytes, QEMUIOVector *qiov, QEMUIOVector *raw_qiov, uint64_t bytes, QEMUIOVector *qiov, QEMUIOVector *raw_qiov,
int flags, bool is_write) int flags, bool is_write)
@@ -228,7 +222,7 @@ blkverify_co_prwv(BlockDriverState *bs, BlkverifyRequest *r, uint64_t offset,
return r->ret; return r->ret;
} }
static int coroutine_fn GRAPH_RDLOCK static int coroutine_fn
blkverify_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, blkverify_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
QEMUIOVector *qiov, BdrvRequestFlags flags) QEMUIOVector *qiov, BdrvRequestFlags flags)
{ {
@@ -257,7 +251,7 @@ blkverify_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
return ret; return ret;
} }
static int coroutine_fn GRAPH_RDLOCK static int coroutine_fn
blkverify_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, blkverify_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
QEMUIOVector *qiov, BdrvRequestFlags flags) QEMUIOVector *qiov, BdrvRequestFlags flags)
{ {
@@ -288,7 +282,7 @@ blkverify_recurse_can_replace(BlockDriverState *bs,
bdrv_recurse_can_replace(s->test_file->bs, to_replace); bdrv_recurse_can_replace(s->test_file->bs, to_replace);
} }
static void GRAPH_RDLOCK blkverify_refresh_filename(BlockDriverState *bs) static void blkverify_refresh_filename(BlockDriverState *bs)
{ {
BDRVBlkverifyState *s = bs->opaque; BDRVBlkverifyState *s = bs->opaque;

View File

@@ -931,12 +931,10 @@ int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp)
ThrottleGroupMember *tgm = &blk->public.throttle_group_member; ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
bdrv_ref(bs); bdrv_ref(bs);
bdrv_graph_wrlock(bs);
blk->root = bdrv_root_attach_child(bs, "root", &child_root, blk->root = bdrv_root_attach_child(bs, "root", &child_root,
BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY, BDRV_CHILD_FILTERED | BDRV_CHILD_PRIMARY,
blk->perm, blk->shared_perm, blk->perm, blk->shared_perm,
blk, errp); blk, errp);
bdrv_graph_wrunlock();
if (blk->root == NULL) { if (blk->root == NULL) {
return -EPERM; return -EPERM;
} }
@@ -2668,8 +2666,6 @@ int blk_load_vmstate(BlockBackend *blk, uint8_t *buf, int64_t pos, int size)
int blk_probe_blocksizes(BlockBackend *blk, BlockSizes *bsz) int blk_probe_blocksizes(BlockBackend *blk, BlockSizes *bsz)
{ {
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
if (!blk_is_available(blk)) { if (!blk_is_available(blk)) {
return -ENOMEDIUM; return -ENOMEDIUM;
} }
@@ -2730,7 +2726,6 @@ int blk_commit_all(void)
{ {
BlockBackend *blk = NULL; BlockBackend *blk = NULL;
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
while ((blk = blk_all_next(blk)) != NULL) { while ((blk = blk_all_next(blk)) != NULL) {
AioContext *aio_context = blk_get_aio_context(blk); AioContext *aio_context = blk_get_aio_context(blk);

View File

@@ -313,12 +313,7 @@ static int64_t block_copy_calculate_cluster_size(BlockDriverState *target,
{ {
int ret; int ret;
BlockDriverInfo bdi; BlockDriverInfo bdi;
bool target_does_cow; bool target_does_cow = bdrv_backing_chain_next(target);
GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
target_does_cow = bdrv_backing_chain_next(target);
/* /*
* If there is no backing file on the target, we cannot rely on COW if our * If there is no backing file on the target, we cannot rely on COW if our
@@ -360,8 +355,6 @@ BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
BdrvDirtyBitmap *copy_bitmap; BdrvDirtyBitmap *copy_bitmap;
bool is_fleecing; bool is_fleecing;
GLOBAL_STATE_CODE();
cluster_size = block_copy_calculate_cluster_size(target->bs, errp); cluster_size = block_copy_calculate_cluster_size(target->bs, errp);
if (cluster_size < 0) { if (cluster_size < 0) {
return NULL; return NULL;
@@ -399,9 +392,7 @@ BlockCopyState *block_copy_state_new(BdrvChild *source, BdrvChild *target,
* For more information see commit f8d59dfb40bb and test * For more information see commit f8d59dfb40bb and test
* tests/qemu-iotests/222 * tests/qemu-iotests/222
*/ */
bdrv_graph_rdlock_main_loop();
is_fleecing = bdrv_chain_contains(target->bs, source->bs); is_fleecing = bdrv_chain_contains(target->bs, source->bs);
bdrv_graph_rdunlock_main_loop();
s = g_new(BlockCopyState, 1); s = g_new(BlockCopyState, 1);
*s = (BlockCopyState) { *s = (BlockCopyState) {

View File

@@ -105,8 +105,6 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
struct bochs_header bochs; struct bochs_header bochs;
int ret; int ret;
GLOBAL_STATE_CODE();
/* No write support yet */ /* No write support yet */
bdrv_graph_rdlock_main_loop(); bdrv_graph_rdlock_main_loop();
ret = bdrv_apply_auto_read_only(bs, NULL, errp); ret = bdrv_apply_auto_read_only(bs, NULL, errp);
@@ -120,8 +118,6 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
return ret; return ret;
} }
GRAPH_RDLOCK_GUARD_MAINLOOP();
ret = bdrv_pread(bs->file, 0, sizeof(bochs), &bochs, 0); ret = bdrv_pread(bs->file, 0, sizeof(bochs), &bochs, 0);
if (ret < 0) { if (ret < 0) {
return ret; return ret;

View File

@@ -67,8 +67,6 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
uint32_t offsets_size, max_compressed_block_size = 1, i; uint32_t offsets_size, max_compressed_block_size = 1, i;
int ret; int ret;
GLOBAL_STATE_CODE();
bdrv_graph_rdlock_main_loop(); bdrv_graph_rdlock_main_loop();
ret = bdrv_apply_auto_read_only(bs, NULL, errp); ret = bdrv_apply_auto_read_only(bs, NULL, errp);
bdrv_graph_rdunlock_main_loop(); bdrv_graph_rdunlock_main_loop();
@@ -81,8 +79,6 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
return ret; return ret;
} }
GRAPH_RDLOCK_GUARD_MAINLOOP();
/* read header */ /* read header */
ret = bdrv_pread(bs->file, 128, 4, &s->block_size, 0); ret = bdrv_pread(bs->file, 128, 4, &s->block_size, 0);
if (ret < 0) { if (ret < 0) {

View File

@@ -48,10 +48,8 @@ static int commit_prepare(Job *job)
{ {
CommitBlockJob *s = container_of(job, CommitBlockJob, common.job); CommitBlockJob *s = container_of(job, CommitBlockJob, common.job);
bdrv_graph_rdlock_main_loop();
bdrv_unfreeze_backing_chain(s->commit_top_bs, s->base_bs); bdrv_unfreeze_backing_chain(s->commit_top_bs, s->base_bs);
s->chain_frozen = false; s->chain_frozen = false;
bdrv_graph_rdunlock_main_loop();
/* Remove base node parent that still uses BLK_PERM_WRITE/RESIZE before /* Remove base node parent that still uses BLK_PERM_WRITE/RESIZE before
* the normal backing chain can be restored. */ * the normal backing chain can be restored. */
@@ -68,12 +66,9 @@ static void commit_abort(Job *job)
{ {
CommitBlockJob *s = container_of(job, CommitBlockJob, common.job); CommitBlockJob *s = container_of(job, CommitBlockJob, common.job);
BlockDriverState *top_bs = blk_bs(s->top); BlockDriverState *top_bs = blk_bs(s->top);
BlockDriverState *commit_top_backing_bs;
if (s->chain_frozen) { if (s->chain_frozen) {
bdrv_graph_rdlock_main_loop();
bdrv_unfreeze_backing_chain(s->commit_top_bs, s->base_bs); bdrv_unfreeze_backing_chain(s->commit_top_bs, s->base_bs);
bdrv_graph_rdunlock_main_loop();
} }
/* Make sure commit_top_bs and top stay around until bdrv_replace_node() */ /* Make sure commit_top_bs and top stay around until bdrv_replace_node() */
@@ -95,15 +90,8 @@ static void commit_abort(Job *job)
* XXX Can (or should) we somehow keep 'consistent read' blocked even * XXX Can (or should) we somehow keep 'consistent read' blocked even
* after the failed/cancelled commit job is gone? If we already wrote * after the failed/cancelled commit job is gone? If we already wrote
* something to base, the intermediate images aren't valid any more. */ * something to base, the intermediate images aren't valid any more. */
bdrv_graph_rdlock_main_loop(); bdrv_replace_node(s->commit_top_bs, s->commit_top_bs->backing->bs,
commit_top_backing_bs = s->commit_top_bs->backing->bs; &error_abort);
bdrv_graph_rdunlock_main_loop();
bdrv_drained_begin(commit_top_backing_bs);
bdrv_graph_wrlock(commit_top_backing_bs);
bdrv_replace_node(s->commit_top_bs, commit_top_backing_bs, &error_abort);
bdrv_graph_wrunlock();
bdrv_drained_end(commit_top_backing_bs);
bdrv_unref(s->commit_top_bs); bdrv_unref(s->commit_top_bs);
bdrv_unref(top_bs); bdrv_unref(top_bs);
@@ -222,7 +210,7 @@ bdrv_commit_top_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
return bdrv_co_preadv(bs->backing, offset, bytes, qiov, flags); return bdrv_co_preadv(bs->backing, offset, bytes, qiov, flags);
} }
static GRAPH_RDLOCK void bdrv_commit_top_refresh_filename(BlockDriverState *bs) static void bdrv_commit_top_refresh_filename(BlockDriverState *bs)
{ {
pstrcpy(bs->exact_filename, sizeof(bs->exact_filename), pstrcpy(bs->exact_filename, sizeof(bs->exact_filename),
bs->backing->bs->filename); bs->backing->bs->filename);
@@ -267,13 +255,10 @@ void commit_start(const char *job_id, BlockDriverState *bs,
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
assert(top != bs); assert(top != bs);
bdrv_graph_rdlock_main_loop();
if (bdrv_skip_filters(top) == bdrv_skip_filters(base)) { if (bdrv_skip_filters(top) == bdrv_skip_filters(base)) {
error_setg(errp, "Invalid files for merge: top and base are the same"); error_setg(errp, "Invalid files for merge: top and base are the same");
bdrv_graph_rdunlock_main_loop();
return; return;
} }
bdrv_graph_rdunlock_main_loop();
base_size = bdrv_getlength(base); base_size = bdrv_getlength(base);
if (base_size < 0) { if (base_size < 0) {
@@ -339,7 +324,6 @@ void commit_start(const char *job_id, BlockDriverState *bs,
* this is the responsibility of the interface (i.e. whoever calls * this is the responsibility of the interface (i.e. whoever calls
* commit_start()). * commit_start()).
*/ */
bdrv_graph_wrlock(top);
s->base_overlay = bdrv_find_overlay(top, base); s->base_overlay = bdrv_find_overlay(top, base);
assert(s->base_overlay); assert(s->base_overlay);
@@ -370,20 +354,16 @@ void commit_start(const char *job_id, BlockDriverState *bs,
ret = block_job_add_bdrv(&s->common, "intermediate node", iter, 0, ret = block_job_add_bdrv(&s->common, "intermediate node", iter, 0,
iter_shared_perms, errp); iter_shared_perms, errp);
if (ret < 0) { if (ret < 0) {
bdrv_graph_wrunlock();
goto fail; goto fail;
} }
} }
if (bdrv_freeze_backing_chain(commit_top_bs, base, errp) < 0) { if (bdrv_freeze_backing_chain(commit_top_bs, base, errp) < 0) {
bdrv_graph_wrunlock();
goto fail; goto fail;
} }
s->chain_frozen = true; s->chain_frozen = true;
ret = block_job_add_bdrv(&s->common, "base", base, 0, BLK_PERM_ALL, errp); ret = block_job_add_bdrv(&s->common, "base", base, 0, BLK_PERM_ALL, errp);
bdrv_graph_wrunlock();
if (ret < 0) { if (ret < 0) {
goto fail; goto fail;
} }
@@ -416,9 +396,7 @@ void commit_start(const char *job_id, BlockDriverState *bs,
fail: fail:
if (s->chain_frozen) { if (s->chain_frozen) {
bdrv_graph_rdlock_main_loop();
bdrv_unfreeze_backing_chain(commit_top_bs, base); bdrv_unfreeze_backing_chain(commit_top_bs, base);
bdrv_graph_rdunlock_main_loop();
} }
if (s->base) { if (s->base) {
blk_unref(s->base); blk_unref(s->base);
@@ -433,11 +411,7 @@ fail:
/* commit_top_bs has to be replaced after deleting the block job, /* commit_top_bs has to be replaced after deleting the block job,
* otherwise this would fail because of lack of permissions. */ * otherwise this would fail because of lack of permissions. */
if (commit_top_bs) { if (commit_top_bs) {
bdrv_drained_begin(top);
bdrv_graph_wrlock(top);
bdrv_replace_node(commit_top_bs, top, &error_abort); bdrv_replace_node(commit_top_bs, top, &error_abort);
bdrv_graph_wrunlock();
bdrv_drained_end(top);
} }
} }

View File

@@ -203,7 +203,7 @@ static int coroutine_fn GRAPH_RDLOCK cbw_co_flush(BlockDriverState *bs)
* It's guaranteed that guest writes will not interact in the region until * It's guaranteed that guest writes will not interact in the region until
* cbw_snapshot_read_unlock() called. * cbw_snapshot_read_unlock() called.
*/ */
static BlockReq * coroutine_fn GRAPH_RDLOCK static coroutine_fn BlockReq *
cbw_snapshot_read_lock(BlockDriverState *bs, int64_t offset, int64_t bytes, cbw_snapshot_read_lock(BlockDriverState *bs, int64_t offset, int64_t bytes,
int64_t *pnum, BdrvChild **file) int64_t *pnum, BdrvChild **file)
{ {
@@ -335,7 +335,7 @@ cbw_co_pdiscard_snapshot(BlockDriverState *bs, int64_t offset, int64_t bytes)
return bdrv_co_pdiscard(s->target, offset, bytes); return bdrv_co_pdiscard(s->target, offset, bytes);
} }
static void GRAPH_RDLOCK cbw_refresh_filename(BlockDriverState *bs) static void cbw_refresh_filename(BlockDriverState *bs)
{ {
pstrcpy(bs->exact_filename, sizeof(bs->exact_filename), pstrcpy(bs->exact_filename, sizeof(bs->exact_filename),
bs->file->bs->filename); bs->file->bs->filename);
@@ -433,8 +433,6 @@ static int cbw_open(BlockDriverState *bs, QDict *options, int flags,
return -EINVAL; return -EINVAL;
} }
GRAPH_RDLOCK_GUARD_MAINLOOP();
ctx = bdrv_get_aio_context(bs); ctx = bdrv_get_aio_context(bs);
aio_context_acquire(ctx); aio_context_acquire(ctx);

View File

@@ -35,8 +35,8 @@ typedef struct BDRVStateCOR {
} BDRVStateCOR; } BDRVStateCOR;
static int GRAPH_UNLOCKED static int cor_open(BlockDriverState *bs, QDict *options, int flags,
cor_open(BlockDriverState *bs, QDict *options, int flags, Error **errp) Error **errp)
{ {
BlockDriverState *bottom_bs = NULL; BlockDriverState *bottom_bs = NULL;
BDRVStateCOR *state = bs->opaque; BDRVStateCOR *state = bs->opaque;
@@ -44,15 +44,11 @@ cor_open(BlockDriverState *bs, QDict *options, int flags, Error **errp)
const char *bottom_node = qdict_get_try_str(options, "bottom"); const char *bottom_node = qdict_get_try_str(options, "bottom");
int ret; int ret;
GLOBAL_STATE_CODE();
ret = bdrv_open_file_child(NULL, options, "file", bs, errp); ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
GRAPH_RDLOCK_GUARD_MAINLOOP();
bs->supported_read_flags = BDRV_REQ_PREFETCH; bs->supported_read_flags = BDRV_REQ_PREFETCH;
bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED | bs->supported_write_flags = BDRV_REQ_WRITE_UNCHANGED |
@@ -231,17 +227,13 @@ cor_co_lock_medium(BlockDriverState *bs, bool locked)
} }
static void GRAPH_UNLOCKED cor_close(BlockDriverState *bs) static void cor_close(BlockDriverState *bs)
{ {
BDRVStateCOR *s = bs->opaque; BDRVStateCOR *s = bs->opaque;
GLOBAL_STATE_CODE();
if (s->chain_frozen) { if (s->chain_frozen) {
bdrv_graph_rdlock_main_loop();
s->chain_frozen = false; s->chain_frozen = false;
bdrv_unfreeze_backing_chain(bs, s->bottom_bs); bdrv_unfreeze_backing_chain(bs, s->bottom_bs);
bdrv_graph_rdunlock_main_loop();
} }
bdrv_unref(s->bottom_bs); bdrv_unref(s->bottom_bs);
@@ -271,15 +263,12 @@ static BlockDriver bdrv_copy_on_read = {
}; };
void no_coroutine_fn bdrv_cor_filter_drop(BlockDriverState *cor_filter_bs) void bdrv_cor_filter_drop(BlockDriverState *cor_filter_bs)
{ {
BDRVStateCOR *s = cor_filter_bs->opaque; BDRVStateCOR *s = cor_filter_bs->opaque;
GLOBAL_STATE_CODE();
/* unfreeze, as otherwise bdrv_replace_node() will fail */ /* unfreeze, as otherwise bdrv_replace_node() will fail */
if (s->chain_frozen) { if (s->chain_frozen) {
GRAPH_RDLOCK_GUARD_MAINLOOP();
s->chain_frozen = false; s->chain_frozen = false;
bdrv_unfreeze_backing_chain(cor_filter_bs, s->bottom_bs); bdrv_unfreeze_backing_chain(cor_filter_bs, s->bottom_bs);
} }

View File

@@ -27,7 +27,6 @@
#include "block/block_int.h" #include "block/block_int.h"
void no_coroutine_fn GRAPH_UNLOCKED void bdrv_cor_filter_drop(BlockDriverState *cor_filter_bs);
bdrv_cor_filter_drop(BlockDriverState *cor_filter_bs);
#endif /* BLOCK_COPY_ON_READ_H */ #endif /* BLOCK_COPY_ON_READ_H */

View File

@@ -65,9 +65,6 @@ static int block_crypto_read_func(QCryptoBlock *block,
BlockDriverState *bs = opaque; BlockDriverState *bs = opaque;
ssize_t ret; ssize_t ret;
GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
ret = bdrv_pread(bs->file, offset, buflen, buf, 0); ret = bdrv_pread(bs->file, offset, buflen, buf, 0);
if (ret < 0) { if (ret < 0) {
error_setg_errno(errp, -ret, "Could not read encryption header"); error_setg_errno(errp, -ret, "Could not read encryption header");
@@ -86,9 +83,6 @@ static int block_crypto_write_func(QCryptoBlock *block,
BlockDriverState *bs = opaque; BlockDriverState *bs = opaque;
ssize_t ret; ssize_t ret;
GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
ret = bdrv_pwrite(bs->file, offset, buflen, buf, 0); ret = bdrv_pwrite(bs->file, offset, buflen, buf, 0);
if (ret < 0) { if (ret < 0) {
error_setg_errno(errp, -ret, "Could not write encryption header"); error_setg_errno(errp, -ret, "Could not write encryption header");
@@ -269,15 +263,11 @@ static int block_crypto_open_generic(QCryptoBlockFormat format,
unsigned int cflags = 0; unsigned int cflags = 0;
QDict *cryptoopts = NULL; QDict *cryptoopts = NULL;
GLOBAL_STATE_CODE();
ret = bdrv_open_file_child(NULL, options, "file", bs, errp); ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
GRAPH_RDLOCK_GUARD_MAINLOOP();
bs->supported_write_flags = BDRV_REQ_FUA & bs->supported_write_flags = BDRV_REQ_FUA &
bs->file->bs->supported_write_flags; bs->file->bs->supported_write_flags;

View File

@@ -70,8 +70,7 @@ static int dmg_probe(const uint8_t *buf, int buf_size, const char *filename)
return 0; return 0;
} }
static int GRAPH_RDLOCK static int read_uint64(BlockDriverState *bs, int64_t offset, uint64_t *result)
read_uint64(BlockDriverState *bs, int64_t offset, uint64_t *result)
{ {
uint64_t buffer; uint64_t buffer;
int ret; int ret;
@@ -85,8 +84,7 @@ read_uint64(BlockDriverState *bs, int64_t offset, uint64_t *result)
return 0; return 0;
} }
static int GRAPH_RDLOCK static int read_uint32(BlockDriverState *bs, int64_t offset, uint32_t *result)
read_uint32(BlockDriverState *bs, int64_t offset, uint32_t *result)
{ {
uint32_t buffer; uint32_t buffer;
int ret; int ret;
@@ -323,8 +321,7 @@ fail:
return ret; return ret;
} }
static int GRAPH_RDLOCK static int dmg_read_resource_fork(BlockDriverState *bs, DmgHeaderState *ds,
dmg_read_resource_fork(BlockDriverState *bs, DmgHeaderState *ds,
uint64_t info_begin, uint64_t info_length) uint64_t info_begin, uint64_t info_length)
{ {
BDRVDMGState *s = bs->opaque; BDRVDMGState *s = bs->opaque;
@@ -391,8 +388,7 @@ fail:
return ret; return ret;
} }
static int GRAPH_RDLOCK static int dmg_read_plist_xml(BlockDriverState *bs, DmgHeaderState *ds,
dmg_read_plist_xml(BlockDriverState *bs, DmgHeaderState *ds,
uint64_t info_begin, uint64_t info_length) uint64_t info_begin, uint64_t info_length)
{ {
BDRVDMGState *s = bs->opaque; BDRVDMGState *s = bs->opaque;
@@ -456,8 +452,6 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
int64_t offset; int64_t offset;
int ret; int ret;
GLOBAL_STATE_CODE();
bdrv_graph_rdlock_main_loop(); bdrv_graph_rdlock_main_loop();
ret = bdrv_apply_auto_read_only(bs, NULL, errp); ret = bdrv_apply_auto_read_only(bs, NULL, errp);
bdrv_graph_rdunlock_main_loop(); bdrv_graph_rdunlock_main_loop();
@@ -469,9 +463,6 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
GRAPH_RDLOCK_GUARD_MAINLOOP();
/* /*
* NB: if uncompress submodules are absent, * NB: if uncompress submodules are absent,
* ie block_module_load return value == 0, the function pointers * ie block_module_load return value == 0, the function pointers

View File

@@ -160,6 +160,7 @@ typedef struct BDRVRawState {
bool has_write_zeroes:1; bool has_write_zeroes:1;
bool use_linux_aio:1; bool use_linux_aio:1;
bool use_linux_io_uring:1; bool use_linux_io_uring:1;
int64_t *offset; /* offset of zone append operation */
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;
@@ -2444,13 +2445,12 @@ static bool bdrv_qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov)
return true; return true;
} }
static int coroutine_fn raw_co_prw(BlockDriverState *bs, int64_t *offset_ptr, static int coroutine_fn raw_co_prw(BlockDriverState *bs, uint64_t offset,
uint64_t bytes, QEMUIOVector *qiov, int type) uint64_t bytes, QEMUIOVector *qiov, int type)
{ {
BDRVRawState *s = bs->opaque; BDRVRawState *s = bs->opaque;
RawPosixAIOData acb; RawPosixAIOData acb;
int ret; int ret;
uint64_t offset = *offset_ptr;
if (fd_open(bs) < 0) if (fd_open(bs) < 0)
return -EIO; return -EIO;
@@ -2513,8 +2513,8 @@ out:
uint64_t *wp = &wps->wp[offset / bs->bl.zone_size]; uint64_t *wp = &wps->wp[offset / bs->bl.zone_size];
if (!BDRV_ZT_IS_CONV(*wp)) { if (!BDRV_ZT_IS_CONV(*wp)) {
if (type & QEMU_AIO_ZONE_APPEND) { if (type & QEMU_AIO_ZONE_APPEND) {
*offset_ptr = *wp; *s->offset = *wp;
trace_zbd_zone_append_complete(bs, *offset_ptr trace_zbd_zone_append_complete(bs, *s->offset
>> BDRV_SECTOR_BITS); >> BDRV_SECTOR_BITS);
} }
/* Advance the wp if needed */ /* Advance the wp if needed */
@@ -2523,10 +2523,7 @@ out:
} }
} }
} else { } else {
/* update_zones_wp(bs, s->fd, 0, 1);
* write and append write are not allowed to cross zone boundaries
*/
update_zones_wp(bs, s->fd, offset, 1);
} }
qemu_co_mutex_unlock(&wps->colock); qemu_co_mutex_unlock(&wps->colock);
@@ -2539,14 +2536,14 @@ static int coroutine_fn raw_co_preadv(BlockDriverState *bs, int64_t offset,
int64_t bytes, QEMUIOVector *qiov, int64_t bytes, QEMUIOVector *qiov,
BdrvRequestFlags flags) BdrvRequestFlags 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, int64_t offset,
int64_t bytes, QEMUIOVector *qiov, int64_t bytes, QEMUIOVector *qiov,
BdrvRequestFlags flags) BdrvRequestFlags flags)
{ {
return raw_co_prw(bs, &offset, bytes, qiov, QEMU_AIO_WRITE); return raw_co_prw(bs, offset, bytes, qiov, QEMU_AIO_WRITE);
} }
static int coroutine_fn raw_co_flush_to_disk(BlockDriverState *bs) static int coroutine_fn raw_co_flush_to_disk(BlockDriverState *bs)
@@ -3473,7 +3470,7 @@ static int coroutine_fn raw_co_zone_mgmt(BlockDriverState *bs, BlockZoneOp op,
len >> BDRV_SECTOR_BITS); len >> BDRV_SECTOR_BITS);
ret = raw_thread_pool_submit(handle_aiocb_zone_mgmt, &acb); ret = raw_thread_pool_submit(handle_aiocb_zone_mgmt, &acb);
if (ret != 0) { if (ret != 0) {
update_zones_wp(bs, s->fd, offset, nrz); update_zones_wp(bs, s->fd, offset, i);
error_report("ioctl %s failed %d", op_name, ret); error_report("ioctl %s failed %d", op_name, ret);
return ret; return ret;
} }
@@ -3509,6 +3506,8 @@ static int coroutine_fn raw_co_zone_append(BlockDriverState *bs,
int64_t zone_size_mask = bs->bl.zone_size - 1; int64_t zone_size_mask = bs->bl.zone_size - 1;
int64_t iov_len = 0; int64_t iov_len = 0;
int64_t len = 0; int64_t len = 0;
BDRVRawState *s = bs->opaque;
s->offset = offset;
if (*offset & zone_size_mask) { if (*offset & zone_size_mask) {
error_report("sector offset %" PRId64 " is not aligned to zone size " error_report("sector offset %" PRId64 " is not aligned to zone size "
@@ -3529,7 +3528,7 @@ static int coroutine_fn raw_co_zone_append(BlockDriverState *bs,
} }
trace_zbd_zone_append(bs, *offset >> BDRV_SECTOR_BITS); trace_zbd_zone_append(bs, *offset >> BDRV_SECTOR_BITS);
return raw_co_prw(bs, offset, len, qiov, QEMU_AIO_ZONE_APPEND); return raw_co_prw(bs, *offset, len, qiov, QEMU_AIO_ZONE_APPEND);
} }
#endif #endif

View File

@@ -36,8 +36,6 @@ static int compress_open(BlockDriverState *bs, QDict *options, int flags,
return ret; return ret;
} }
GRAPH_RDLOCK_GUARD_MAINLOOP();
if (!bs->file->bs->drv || !block_driver_can_compress(bs->file->bs->drv)) { if (!bs->file->bs->drv || !block_driver_can_compress(bs->file->bs->drv)) {
error_setg(errp, error_setg(errp,
"Compression is not supported for underlying format: %s", "Compression is not supported for underlying format: %s",
@@ -99,8 +97,7 @@ compress_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes)
} }
static void GRAPH_RDLOCK static void compress_refresh_limits(BlockDriverState *bs, Error **errp)
compress_refresh_limits(BlockDriverState *bs, Error **errp)
{ {
BlockDriverInfo bdi; BlockDriverInfo bdi;
int ret; int ret;

View File

@@ -3685,8 +3685,6 @@ out:
void bdrv_cancel_in_flight(BlockDriverState *bs) void bdrv_cancel_in_flight(BlockDriverState *bs)
{ {
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
if (!bs || !bs->drv) { if (!bs || !bs->drv) {
return; return;
} }

View File

@@ -15,7 +15,6 @@
#include "block/block.h" #include "block/block.h"
#include "block/raw-aio.h" #include "block/raw-aio.h"
#include "qemu/coroutine.h" #include "qemu/coroutine.h"
#include "qemu/defer-call.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "sysemu/block-backend.h" #include "sysemu/block-backend.h"
#include "trace.h" #include "trace.h"
@@ -125,9 +124,6 @@ static void luring_process_completions(LuringState *s)
{ {
struct io_uring_cqe *cqes; struct io_uring_cqe *cqes;
int total_bytes; int total_bytes;
defer_call_begin();
/* /*
* Request completion callbacks can run the nested event loop. * Request completion callbacks can run the nested event loop.
* Schedule ourselves so the nested event loop will "see" remaining * Schedule ourselves so the nested event loop will "see" remaining
@@ -220,10 +216,7 @@ end:
aio_co_wake(luringcb->co); aio_co_wake(luringcb->co);
} }
} }
qemu_bh_cancel(s->completion_bh); qemu_bh_cancel(s->completion_bh);
defer_call_end();
} }
static int ioq_submit(LuringState *s) static int ioq_submit(LuringState *s)
@@ -313,7 +306,7 @@ static void ioq_init(LuringQueue *io_q)
io_q->blocked = false; io_q->blocked = false;
} }
static void luring_deferred_fn(void *opaque) static void luring_unplug_fn(void *opaque)
{ {
LuringState *s = opaque; LuringState *s = opaque;
trace_luring_unplug_fn(s, s->io_q.blocked, s->io_q.in_queue, trace_luring_unplug_fn(s, s->io_q.blocked, s->io_q.in_queue,
@@ -374,7 +367,7 @@ static int luring_do_submit(int fd, LuringAIOCB *luringcb, LuringState *s,
return ret; return ret;
} }
defer_call(luring_deferred_fn, s); blk_io_plug_call(luring_unplug_fn, s);
} }
return 0; return 0;
} }

View File

@@ -14,7 +14,6 @@
#include "block/raw-aio.h" #include "block/raw-aio.h"
#include "qemu/event_notifier.h" #include "qemu/event_notifier.h"
#include "qemu/coroutine.h" #include "qemu/coroutine.h"
#include "qemu/defer-call.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "sysemu/block-backend.h" #include "sysemu/block-backend.h"
@@ -205,8 +204,6 @@ static void qemu_laio_process_completions(LinuxAioState *s)
{ {
struct io_event *events; struct io_event *events;
defer_call_begin();
/* Reschedule so nested event loops see currently pending completions */ /* Reschedule so nested event loops see currently pending completions */
qemu_bh_schedule(s->completion_bh); qemu_bh_schedule(s->completion_bh);
@@ -233,8 +230,6 @@ static void qemu_laio_process_completions(LinuxAioState *s)
* own `for` loop. If we are the last all counters dropped to zero. */ * own `for` loop. If we are the last all counters dropped to zero. */
s->event_max = 0; s->event_max = 0;
s->event_idx = 0; s->event_idx = 0;
defer_call_end();
} }
static void qemu_laio_process_completions_and_submit(LinuxAioState *s) static void qemu_laio_process_completions_and_submit(LinuxAioState *s)
@@ -358,7 +353,7 @@ static uint64_t laio_max_batch(LinuxAioState *s, uint64_t dev_max_batch)
return max_batch; return max_batch;
} }
static void laio_deferred_fn(void *opaque) static void laio_unplug_fn(void *opaque)
{ {
LinuxAioState *s = opaque; LinuxAioState *s = opaque;
@@ -398,7 +393,7 @@ static int laio_do_submit(int fd, struct qemu_laiocb *laiocb, off_t offset,
if (s->io_q.in_queue >= laio_max_batch(s, dev_max_batch)) { if (s->io_q.in_queue >= laio_max_batch(s, dev_max_batch)) {
ioq_submit(s); ioq_submit(s);
} else { } else {
defer_call(laio_deferred_fn, s); blk_io_plug_call(laio_unplug_fn, s);
} }
} }

View File

@@ -21,6 +21,7 @@ block_ss.add(files(
'mirror.c', 'mirror.c',
'nbd.c', 'nbd.c',
'null.c', 'null.c',
'plug.c',
'preallocate.c', 'preallocate.c',
'progress_meter.c', 'progress_meter.c',
'qapi.c', 'qapi.c',

View File

@@ -55,18 +55,10 @@ typedef struct MirrorBlockJob {
BlockMirrorBackingMode backing_mode; BlockMirrorBackingMode backing_mode;
/* Whether the target image requires explicit zero-initialization */ /* Whether the target image requires explicit zero-initialization */
bool zero_target; bool zero_target;
/*
* To be accesssed with atomics. Written only under the BQL (required by the
* current implementation of mirror_change()).
*/
MirrorCopyMode copy_mode; MirrorCopyMode copy_mode;
BlockdevOnError on_source_error, on_target_error; BlockdevOnError on_source_error, on_target_error;
/* /* Set when the target is synced (dirty bitmap is clean, nothing
* To be accessed with atomics. * in flight) and the job is running in active mode */
*
* Set when the target is synced (dirty bitmap is clean, nothing in flight)
* and the job is running in active mode.
*/
bool actively_synced; bool actively_synced;
bool should_complete; bool should_complete;
int64_t granularity; int64_t granularity;
@@ -130,7 +122,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)
{ {
qatomic_set(&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,
true, error); true, error);
@@ -479,7 +471,7 @@ static unsigned mirror_perform(MirrorBlockJob *s, int64_t offset,
return bytes_handled; return bytes_handled;
} }
static void coroutine_fn GRAPH_RDLOCK mirror_iteration(MirrorBlockJob *s) static void coroutine_fn mirror_iteration(MirrorBlockJob *s)
{ {
BlockDriverState *source = s->mirror_top_bs->backing->bs; BlockDriverState *source = s->mirror_top_bs->backing->bs;
MirrorOp *pseudo_op; MirrorOp *pseudo_op;
@@ -678,7 +670,6 @@ static int mirror_exit_common(Job *job)
s->prepared = true; s->prepared = true;
aio_context_acquire(qemu_get_aio_context()); aio_context_acquire(qemu_get_aio_context());
bdrv_graph_rdlock_main_loop();
mirror_top_bs = s->mirror_top_bs; mirror_top_bs = s->mirror_top_bs;
bs_opaque = mirror_top_bs->opaque; bs_opaque = mirror_top_bs->opaque;
@@ -697,8 +688,6 @@ static int mirror_exit_common(Job *job)
bdrv_ref(mirror_top_bs); bdrv_ref(mirror_top_bs);
bdrv_ref(target_bs); bdrv_ref(target_bs);
bdrv_graph_rdunlock_main_loop();
/* /*
* Remove target parent that still uses BLK_PERM_WRITE/RESIZE before * Remove target parent that still uses BLK_PERM_WRITE/RESIZE before
* inserting target_bs at s->to_replace, where we might not be able to get * inserting target_bs at s->to_replace, where we might not be able to get
@@ -712,12 +701,12 @@ static int mirror_exit_common(Job *job)
* these permissions any more means that we can't allow any new requests on * these permissions any more means that we can't allow any new requests on
* mirror_top_bs from now on, so keep it drained. */ * mirror_top_bs from now on, so keep it drained. */
bdrv_drained_begin(mirror_top_bs); bdrv_drained_begin(mirror_top_bs);
bdrv_drained_begin(target_bs);
bs_opaque->stop = true; bs_opaque->stop = true;
bdrv_graph_rdlock_main_loop(); bdrv_graph_rdlock_main_loop();
bdrv_child_refresh_perms(mirror_top_bs, mirror_top_bs->backing, bdrv_child_refresh_perms(mirror_top_bs, mirror_top_bs->backing,
&error_abort); &error_abort);
bdrv_graph_rdunlock_main_loop();
if (!abort && s->backing_mode == MIRROR_SOURCE_BACKING_CHAIN) { if (!abort && s->backing_mode == MIRROR_SOURCE_BACKING_CHAIN) {
BlockDriverState *backing = s->is_none_mode ? src : s->base; BlockDriverState *backing = s->is_none_mode ? src : s->base;
@@ -740,7 +729,6 @@ static int mirror_exit_common(Job *job)
local_err = NULL; local_err = NULL;
} }
} }
bdrv_graph_rdunlock_main_loop();
if (s->to_replace) { if (s->to_replace) {
replace_aio_context = bdrv_get_aio_context(s->to_replace); replace_aio_context = bdrv_get_aio_context(s->to_replace);
@@ -758,13 +746,15 @@ static int mirror_exit_common(Job *job)
/* The mirror job has no requests in flight any more, but we need to /* The mirror job has no requests in flight any more, but we need to
* drain potential other users of the BDS before changing the graph. */ * drain potential other users of the BDS before changing the graph. */
assert(s->in_drain); assert(s->in_drain);
bdrv_drained_begin(to_replace); bdrv_drained_begin(target_bs);
/* /*
* Cannot use check_to_replace_node() here, because that would * Cannot use check_to_replace_node() here, because that would
* check for an op blocker on @to_replace, and we have our own * check for an op blocker on @to_replace, and we have our own
* there. * there.
*
* TODO Pull out the writer lock from bdrv_replace_node() to here
*/ */
bdrv_graph_wrlock(target_bs); bdrv_graph_rdlock_main_loop();
if (bdrv_recurse_can_replace(src, to_replace)) { if (bdrv_recurse_can_replace(src, to_replace)) {
bdrv_replace_node(to_replace, target_bs, &local_err); bdrv_replace_node(to_replace, target_bs, &local_err);
} else { } else {
@@ -773,8 +763,8 @@ static int mirror_exit_common(Job *job)
"would not lead to an abrupt change of visible data", "would not lead to an abrupt change of visible data",
to_replace->node_name, target_bs->node_name); to_replace->node_name, target_bs->node_name);
} }
bdrv_graph_wrunlock(); bdrv_graph_rdunlock_main_loop();
bdrv_drained_end(to_replace); bdrv_drained_end(target_bs);
if (local_err) { if (local_err) {
error_report_err(local_err); error_report_err(local_err);
ret = -EPERM; ret = -EPERM;
@@ -789,6 +779,7 @@ static int mirror_exit_common(Job *job)
aio_context_release(replace_aio_context); aio_context_release(replace_aio_context);
} }
g_free(s->replaces); g_free(s->replaces);
bdrv_unref(target_bs);
/* /*
* Remove the mirror filter driver from the graph. Before this, get rid of * Remove the mirror filter driver from the graph. Before this, get rid of
@@ -796,12 +787,7 @@ static int mirror_exit_common(Job *job)
* valid. * valid.
*/ */
block_job_remove_all_bdrv(bjob); block_job_remove_all_bdrv(bjob);
bdrv_graph_wrlock(mirror_top_bs);
bdrv_replace_node(mirror_top_bs, mirror_top_bs->backing->bs, &error_abort); bdrv_replace_node(mirror_top_bs, mirror_top_bs->backing->bs, &error_abort);
bdrv_graph_wrunlock();
bdrv_drained_end(target_bs);
bdrv_unref(target_bs);
bs_opaque->job = NULL; bs_opaque->job = NULL;
@@ -839,18 +825,14 @@ static void coroutine_fn mirror_throttle(MirrorBlockJob *s)
} }
} }
static int coroutine_fn GRAPH_UNLOCKED mirror_dirty_init(MirrorBlockJob *s) static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s)
{ {
int64_t offset; int64_t offset;
BlockDriverState *bs; BlockDriverState *bs = s->mirror_top_bs->backing->bs;
BlockDriverState *target_bs = blk_bs(s->target); BlockDriverState *target_bs = blk_bs(s->target);
int ret; int ret;
int64_t count; int64_t count;
bdrv_graph_co_rdlock();
bs = s->mirror_top_bs->backing->bs;
bdrv_graph_co_rdunlock();
if (s->zero_target) { if (s->zero_target) {
if (!bdrv_can_write_zeroes_with_unmap(target_bs)) { if (!bdrv_can_write_zeroes_with_unmap(target_bs)) {
bdrv_set_dirty_bitmap(s->dirty_bitmap, 0, s->bdev_length); bdrv_set_dirty_bitmap(s->dirty_bitmap, 0, s->bdev_length);
@@ -930,7 +912,7 @@ static int coroutine_fn mirror_flush(MirrorBlockJob *s)
static int coroutine_fn mirror_run(Job *job, Error **errp) static int coroutine_fn mirror_run(Job *job, Error **errp)
{ {
MirrorBlockJob *s = container_of(job, MirrorBlockJob, common.job); MirrorBlockJob *s = container_of(job, MirrorBlockJob, common.job);
BlockDriverState *bs; BlockDriverState *bs = s->mirror_top_bs->backing->bs;
MirrorBDSOpaque *mirror_top_opaque = s->mirror_top_bs->opaque; MirrorBDSOpaque *mirror_top_opaque = s->mirror_top_bs->opaque;
BlockDriverState *target_bs = blk_bs(s->target); BlockDriverState *target_bs = blk_bs(s->target);
bool need_drain = true; bool need_drain = true;
@@ -942,10 +924,6 @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
checking for a NULL string */ checking for a NULL string */
int ret = 0; int ret = 0;
bdrv_graph_co_rdlock();
bs = bdrv_filter_bs(s->mirror_top_bs);
bdrv_graph_co_rdunlock();
if (job_is_cancelled(&s->common.job)) { if (job_is_cancelled(&s->common.job)) {
goto immediate_exit; goto immediate_exit;
} }
@@ -984,7 +962,7 @@ 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);
qatomic_set(&s->actively_synced, true); s->actively_synced = true;
while (!job_cancel_requested(&s->common.job) && !s->should_complete) { while (!job_cancel_requested(&s->common.job) && !s->should_complete) {
job_yield(&s->common.job); job_yield(&s->common.job);
} }
@@ -1006,13 +984,13 @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
} else { } else {
s->target_cluster_size = BDRV_SECTOR_SIZE; s->target_cluster_size = BDRV_SECTOR_SIZE;
} }
bdrv_graph_co_rdunlock();
if (backing_filename[0] && !bdrv_backing_chain_next(target_bs) && if (backing_filename[0] && !bdrv_backing_chain_next(target_bs) &&
s->granularity < s->target_cluster_size) { s->granularity < s->target_cluster_size) {
s->buf_size = MAX(s->buf_size, s->target_cluster_size); s->buf_size = MAX(s->buf_size, s->target_cluster_size);
s->cow_bitmap = bitmap_new(length); s->cow_bitmap = bitmap_new(length);
} }
s->max_iov = MIN(bs->bl.max_iov, target_bs->bl.max_iov); s->max_iov = MIN(bs->bl.max_iov, target_bs->bl.max_iov);
bdrv_graph_co_rdunlock();
s->buf = qemu_try_blockalign(bs, s->buf_size); s->buf = qemu_try_blockalign(bs, s->buf_size);
if (s->buf == NULL) { if (s->buf == NULL) {
@@ -1078,9 +1056,7 @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
mirror_wait_for_free_in_flight_slot(s); mirror_wait_for_free_in_flight_slot(s);
continue; continue;
} else if (cnt != 0) { } else if (cnt != 0) {
bdrv_graph_co_rdlock();
mirror_iteration(s); mirror_iteration(s);
bdrv_graph_co_rdunlock();
} }
} }
@@ -1098,9 +1074,9 @@ 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);
if (s->copy_mode != MIRROR_COPY_MODE_BACKGROUND) {
s->actively_synced = true;
} }
if (qatomic_read(&s->copy_mode) != MIRROR_COPY_MODE_BACKGROUND) {
qatomic_set(&s->actively_synced, true);
} }
should_complete = s->should_complete || should_complete = s->should_complete ||
@@ -1270,48 +1246,6 @@ static bool commit_active_cancel(Job *job, bool force)
return force || !job_is_ready(job); return force || !job_is_ready(job);
} }
static void mirror_change(BlockJob *job, BlockJobChangeOptions *opts,
Error **errp)
{
MirrorBlockJob *s = container_of(job, MirrorBlockJob, common);
BlockJobChangeOptionsMirror *change_opts = &opts->u.mirror;
MirrorCopyMode current;
/*
* The implementation relies on the fact that copy_mode is only written
* under the BQL. Otherwise, further synchronization would be required.
*/
GLOBAL_STATE_CODE();
if (qatomic_read(&s->copy_mode) == change_opts->copy_mode) {
return;
}
if (change_opts->copy_mode != MIRROR_COPY_MODE_WRITE_BLOCKING) {
error_setg(errp, "Change to copy mode '%s' is not implemented",
MirrorCopyMode_str(change_opts->copy_mode));
return;
}
current = qatomic_cmpxchg(&s->copy_mode, MIRROR_COPY_MODE_BACKGROUND,
change_opts->copy_mode);
if (current != MIRROR_COPY_MODE_BACKGROUND) {
error_setg(errp, "Expected current copy mode '%s', got '%s'",
MirrorCopyMode_str(MIRROR_COPY_MODE_BACKGROUND),
MirrorCopyMode_str(current));
}
}
static void mirror_query(BlockJob *job, BlockJobInfo *info)
{
MirrorBlockJob *s = container_of(job, MirrorBlockJob, common);
info->u.mirror = (BlockJobInfoMirror) {
.actively_synced = qatomic_read(&s->actively_synced),
};
}
static const BlockJobDriver mirror_job_driver = { static const BlockJobDriver mirror_job_driver = {
.job_driver = { .job_driver = {
.instance_size = sizeof(MirrorBlockJob), .instance_size = sizeof(MirrorBlockJob),
@@ -1326,8 +1260,6 @@ static const BlockJobDriver mirror_job_driver = {
.cancel = mirror_cancel, .cancel = mirror_cancel,
}, },
.drained_poll = mirror_drained_poll, .drained_poll = mirror_drained_poll,
.change = mirror_change,
.query = mirror_query,
}; };
static const BlockJobDriver commit_active_job_driver = { static const BlockJobDriver commit_active_job_driver = {
@@ -1446,7 +1378,7 @@ do_sync_target_write(MirrorBlockJob *job, MirrorMethod method,
bitmap_end = QEMU_ALIGN_UP(offset + bytes, job->granularity); bitmap_end = QEMU_ALIGN_UP(offset + bytes, job->granularity);
bdrv_set_dirty_bitmap(job->dirty_bitmap, bitmap_offset, bdrv_set_dirty_bitmap(job->dirty_bitmap, bitmap_offset,
bitmap_end - bitmap_offset); bitmap_end - bitmap_offset);
qatomic_set(&job->actively_synced, false); job->actively_synced = false;
action = mirror_error_action(job, false, -ret); action = mirror_error_action(job, false, -ret);
if (action == BLOCK_ERROR_ACTION_REPORT) { if (action == BLOCK_ERROR_ACTION_REPORT) {
@@ -1505,8 +1437,7 @@ static void coroutine_fn GRAPH_RDLOCK active_write_settle(MirrorOp *op)
uint64_t end_chunk = DIV_ROUND_UP(op->offset + op->bytes, uint64_t end_chunk = DIV_ROUND_UP(op->offset + op->bytes,
op->s->granularity); op->s->granularity);
if (!--op->s->in_active_write_counter && if (!--op->s->in_active_write_counter && op->s->actively_synced) {
qatomic_read(&op->s->actively_synced)) {
BdrvChild *source = op->s->mirror_top_bs->backing; BdrvChild *source = op->s->mirror_top_bs->backing;
if (QLIST_FIRST(&source->bs->parents) == source && if (QLIST_FIRST(&source->bs->parents) == source &&
@@ -1532,21 +1463,21 @@ bdrv_mirror_top_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
return bdrv_co_preadv(bs->backing, offset, bytes, qiov, flags); return bdrv_co_preadv(bs->backing, offset, bytes, qiov, flags);
} }
static bool should_copy_to_target(MirrorBDSOpaque *s)
{
return s->job && s->job->ret >= 0 &&
!job_is_cancelled(&s->job->common.job) &&
qatomic_read(&s->job->copy_mode) == MIRROR_COPY_MODE_WRITE_BLOCKING;
}
static int coroutine_fn GRAPH_RDLOCK static int coroutine_fn GRAPH_RDLOCK
bdrv_mirror_top_do_write(BlockDriverState *bs, MirrorMethod method, bdrv_mirror_top_do_write(BlockDriverState *bs, MirrorMethod method,
bool copy_to_target, uint64_t offset, uint64_t bytes, uint64_t offset, uint64_t bytes, QEMUIOVector *qiov,
QEMUIOVector *qiov, int flags) int flags)
{ {
MirrorOp *op = NULL; MirrorOp *op = NULL;
MirrorBDSOpaque *s = bs->opaque; MirrorBDSOpaque *s = bs->opaque;
int ret = 0; int ret = 0;
bool copy_to_target = false;
if (s->job) {
copy_to_target = s->job->ret >= 0 &&
!job_is_cancelled(&s->job->common.job) &&
s->job->copy_mode == MIRROR_COPY_MODE_WRITE_BLOCKING;
}
if (copy_to_target) { if (copy_to_target) {
op = active_write_prepare(s->job, offset, bytes); op = active_write_prepare(s->job, offset, bytes);
@@ -1569,11 +1500,6 @@ bdrv_mirror_top_do_write(BlockDriverState *bs, MirrorMethod method,
abort(); abort();
} }
if (!copy_to_target && s->job && s->job->dirty_bitmap) {
qatomic_set(&s->job->actively_synced, false);
bdrv_set_dirty_bitmap(s->job->dirty_bitmap, offset, bytes);
}
if (ret < 0) { if (ret < 0) {
goto out; goto out;
} }
@@ -1593,10 +1519,17 @@ static int coroutine_fn GRAPH_RDLOCK
bdrv_mirror_top_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, bdrv_mirror_top_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
QEMUIOVector *qiov, BdrvRequestFlags flags) QEMUIOVector *qiov, BdrvRequestFlags flags)
{ {
MirrorBDSOpaque *s = bs->opaque;
QEMUIOVector bounce_qiov; QEMUIOVector bounce_qiov;
void *bounce_buf; void *bounce_buf;
int ret = 0; int ret = 0;
bool copy_to_target = should_copy_to_target(bs->opaque); bool copy_to_target = false;
if (s->job) {
copy_to_target = s->job->ret >= 0 &&
!job_is_cancelled(&s->job->common.job) &&
s->job->copy_mode == MIRROR_COPY_MODE_WRITE_BLOCKING;
}
if (copy_to_target) { if (copy_to_target) {
/* The guest might concurrently modify the data to write; but /* The guest might concurrently modify the data to write; but
@@ -1613,8 +1546,8 @@ bdrv_mirror_top_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
flags &= ~BDRV_REQ_REGISTERED_BUF; flags &= ~BDRV_REQ_REGISTERED_BUF;
} }
ret = bdrv_mirror_top_do_write(bs, MIRROR_METHOD_COPY, copy_to_target, ret = bdrv_mirror_top_do_write(bs, MIRROR_METHOD_COPY, offset, bytes, qiov,
offset, bytes, qiov, flags); flags);
if (copy_to_target) { if (copy_to_target) {
qemu_iovec_destroy(&bounce_qiov); qemu_iovec_destroy(&bounce_qiov);
@@ -1637,20 +1570,18 @@ static int coroutine_fn GRAPH_RDLOCK
bdrv_mirror_top_pwrite_zeroes(BlockDriverState *bs, int64_t offset, bdrv_mirror_top_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
int64_t bytes, BdrvRequestFlags flags) int64_t bytes, BdrvRequestFlags flags)
{ {
bool copy_to_target = should_copy_to_target(bs->opaque); return bdrv_mirror_top_do_write(bs, MIRROR_METHOD_ZERO, offset, bytes, NULL,
return bdrv_mirror_top_do_write(bs, MIRROR_METHOD_ZERO, copy_to_target, flags);
offset, bytes, NULL, flags);
} }
static int coroutine_fn GRAPH_RDLOCK static int coroutine_fn GRAPH_RDLOCK
bdrv_mirror_top_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes) bdrv_mirror_top_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes)
{ {
bool copy_to_target = should_copy_to_target(bs->opaque); return bdrv_mirror_top_do_write(bs, MIRROR_METHOD_DISCARD, offset, bytes,
return bdrv_mirror_top_do_write(bs, MIRROR_METHOD_DISCARD, copy_to_target, NULL, 0);
offset, bytes, NULL, 0);
} }
static void GRAPH_RDLOCK bdrv_mirror_top_refresh_filename(BlockDriverState *bs) static void bdrv_mirror_top_refresh_filename(BlockDriverState *bs)
{ {
if (bs->backing == NULL) { if (bs->backing == NULL) {
/* we can be here after failed bdrv_attach_child in /* we can be here after failed bdrv_attach_child in
@@ -1760,15 +1691,12 @@ static BlockJob *mirror_start_job(
buf_size = DEFAULT_MIRROR_BUF_SIZE; buf_size = DEFAULT_MIRROR_BUF_SIZE;
} }
bdrv_graph_rdlock_main_loop();
if (bdrv_skip_filters(bs) == bdrv_skip_filters(target)) { if (bdrv_skip_filters(bs) == bdrv_skip_filters(target)) {
error_setg(errp, "Can't mirror node into itself"); error_setg(errp, "Can't mirror node into itself");
bdrv_graph_rdunlock_main_loop();
return NULL; return NULL;
} }
target_is_backing = bdrv_chain_contains(bs, target); target_is_backing = bdrv_chain_contains(bs, target);
bdrv_graph_rdunlock_main_loop();
/* In the case of active commit, add dummy driver to provide consistent /* In the case of active commit, add dummy driver to provide consistent
* reads on the top, while disabling it in the intermediate nodes, and make * reads on the top, while disabling it in the intermediate nodes, and make
@@ -1851,20 +1779,15 @@ static BlockJob *mirror_start_job(
} }
target_shared_perms |= BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE; target_shared_perms |= BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE;
} else { } else if (bdrv_chain_contains(bs, bdrv_skip_filters(target))) {
bdrv_graph_rdlock_main_loop();
if (bdrv_chain_contains(bs, bdrv_skip_filters(target))) {
/* /*
* We may want to allow this in the future, but it would * We may want to allow this in the future, but it would
* require taking some extra care. * require taking some extra care.
*/ */
error_setg(errp, "Cannot mirror to a filter on top of a node in " error_setg(errp, "Cannot mirror to a filter on top of a node in the "
"the source's backing chain"); "source's backing chain");
bdrv_graph_rdunlock_main_loop();
goto fail; goto fail;
} }
bdrv_graph_rdunlock_main_loop();
}
s->target = blk_new(s->common.job.aio_context, s->target = blk_new(s->common.job.aio_context,
target_perms, target_shared_perms); target_perms, target_shared_perms);
@@ -1884,14 +1807,13 @@ static BlockJob *mirror_start_job(
blk_set_allow_aio_context_change(s->target, true); blk_set_allow_aio_context_change(s->target, true);
blk_set_disable_request_queuing(s->target, true); blk_set_disable_request_queuing(s->target, true);
bdrv_graph_rdlock_main_loop();
s->replaces = g_strdup(replaces); s->replaces = g_strdup(replaces);
s->on_source_error = on_source_error; s->on_source_error = on_source_error;
s->on_target_error = on_target_error; s->on_target_error = on_target_error;
s->is_none_mode = is_none_mode; s->is_none_mode = is_none_mode;
s->backing_mode = backing_mode; s->backing_mode = backing_mode;
s->zero_target = zero_target; s->zero_target = zero_target;
qatomic_set(&s->copy_mode, copy_mode); s->copy_mode = copy_mode;
s->base = base; s->base = base;
s->base_overlay = bdrv_find_overlay(bs, base); s->base_overlay = bdrv_find_overlay(bs, base);
s->granularity = granularity; s->granularity = granularity;
@@ -1900,27 +1822,20 @@ static BlockJob *mirror_start_job(
if (auto_complete) { if (auto_complete) {
s->should_complete = true; s->should_complete = true;
} }
bdrv_graph_rdunlock_main_loop();
s->dirty_bitmap = bdrv_create_dirty_bitmap(s->mirror_top_bs, granularity, s->dirty_bitmap = bdrv_create_dirty_bitmap(bs, granularity, NULL, errp);
NULL, errp);
if (!s->dirty_bitmap) { if (!s->dirty_bitmap) {
goto fail; goto fail;
} }
if (s->copy_mode == MIRROR_COPY_MODE_WRITE_BLOCKING) {
/*
* The dirty bitmap is set by bdrv_mirror_top_do_write() when not in active
* mode.
*/
bdrv_disable_dirty_bitmap(s->dirty_bitmap); bdrv_disable_dirty_bitmap(s->dirty_bitmap);
}
bdrv_graph_wrlock(bs);
ret = block_job_add_bdrv(&s->common, "source", bs, 0, ret = block_job_add_bdrv(&s->common, "source", bs, 0,
BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE |
BLK_PERM_CONSISTENT_READ, BLK_PERM_CONSISTENT_READ,
errp); errp);
if (ret < 0) { if (ret < 0) {
bdrv_graph_wrunlock();
goto fail; goto fail;
} }
@@ -1965,17 +1880,14 @@ static BlockJob *mirror_start_job(
ret = block_job_add_bdrv(&s->common, "intermediate node", iter, 0, ret = block_job_add_bdrv(&s->common, "intermediate node", iter, 0,
iter_shared_perms, errp); iter_shared_perms, errp);
if (ret < 0) { if (ret < 0) {
bdrv_graph_wrunlock();
goto fail; goto fail;
} }
} }
if (bdrv_freeze_backing_chain(mirror_top_bs, target, errp) < 0) { if (bdrv_freeze_backing_chain(mirror_top_bs, target, errp) < 0) {
bdrv_graph_wrunlock();
goto fail; goto fail;
} }
} }
bdrv_graph_wrunlock();
QTAILQ_INIT(&s->ops_in_flight); QTAILQ_INIT(&s->ops_in_flight);
@@ -2000,14 +1912,11 @@ fail:
} }
bs_opaque->stop = true; bs_opaque->stop = true;
bdrv_drained_begin(bs); bdrv_graph_rdlock_main_loop();
bdrv_graph_wrlock(bs);
assert(mirror_top_bs->backing->bs == bs);
bdrv_child_refresh_perms(mirror_top_bs, mirror_top_bs->backing, bdrv_child_refresh_perms(mirror_top_bs, mirror_top_bs->backing,
&error_abort); &error_abort);
bdrv_replace_node(mirror_top_bs, bs, &error_abort); bdrv_graph_rdunlock_main_loop();
bdrv_graph_wrunlock(); bdrv_replace_node(mirror_top_bs, mirror_top_bs->backing->bs, &error_abort);
bdrv_drained_end(bs);
bdrv_unref(mirror_top_bs); bdrv_unref(mirror_top_bs);
@@ -2036,12 +1945,8 @@ void mirror_start(const char *job_id, BlockDriverState *bs,
MirrorSyncMode_str(mode)); MirrorSyncMode_str(mode));
return; return;
} }
bdrv_graph_rdlock_main_loop();
is_none_mode = mode == MIRROR_SYNC_MODE_NONE; is_none_mode = mode == MIRROR_SYNC_MODE_NONE;
base = mode == MIRROR_SYNC_MODE_TOP ? bdrv_backing_chain_next(bs) : NULL; base = mode == MIRROR_SYNC_MODE_TOP ? bdrv_backing_chain_next(bs) : NULL;
bdrv_graph_rdunlock_main_loop();
mirror_start_job(job_id, bs, creation_flags, target, replaces, mirror_start_job(job_id, bs, creation_flags, target, replaces,
speed, granularity, buf_size, backing_mode, zero_target, speed, granularity, buf_size, backing_mode, zero_target,
on_source_error, on_target_error, unmap, NULL, NULL, on_source_error, on_target_error, unmap, NULL, NULL,

View File

@@ -206,9 +206,6 @@ void hmp_commit(Monitor *mon, const QDict *qdict)
BlockBackend *blk; BlockBackend *blk;
int ret; int ret;
GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
if (!strcmp(device, "all")) { if (!strcmp(device, "all")) {
ret = blk_commit_all(); ret = blk_commit_all();
} else { } else {
@@ -849,7 +846,7 @@ void hmp_info_block_jobs(Monitor *mon, const QDict *qdict)
} }
while (list) { while (list) {
if (list->value->type == JOB_TYPE_STREAM) { if (strcmp(list->value->type, "stream") == 0) {
monitor_printf(mon, "Streaming device %s: Completed %" PRId64 monitor_printf(mon, "Streaming device %s: Completed %" PRId64
" of %" PRId64 " bytes, speed limit %" PRId64 " of %" PRId64 " bytes, speed limit %" PRId64
" bytes/s\n", " bytes/s\n",
@@ -861,7 +858,7 @@ void hmp_info_block_jobs(Monitor *mon, const QDict *qdict)
monitor_printf(mon, "Type %s, device %s: Completed %" PRId64 monitor_printf(mon, "Type %s, device %s: Completed %" PRId64
" of %" PRId64 " bytes, speed limit %" PRId64 " of %" PRId64 " bytes, speed limit %" PRId64
" bytes/s\n", " bytes/s\n",
JobType_str(list->value->type), list->value->type,
list->value->device, list->value->device,
list->value->offset, list->value->offset,
list->value->len, list->value->len,

View File

@@ -16,7 +16,6 @@
#include "qapi/error.h" #include "qapi/error.h"
#include "qapi/qmp/qdict.h" #include "qapi/qmp/qdict.h"
#include "qapi/qmp/qstring.h" #include "qapi/qmp/qstring.h"
#include "qemu/defer-call.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "qemu/main-loop.h" #include "qemu/main-loop.h"
#include "qemu/module.h" #include "qemu/module.h"
@@ -417,10 +416,9 @@ static bool nvme_process_completion(NVMeQueuePair *q)
q->cq_phase = !q->cq_phase; q->cq_phase = !q->cq_phase;
} }
cid = le16_to_cpu(c->cid); cid = le16_to_cpu(c->cid);
if (cid == 0 || cid > NVME_NUM_REQS) { if (cid == 0 || cid > NVME_QUEUE_SIZE) {
warn_report("NVMe: Unexpected CID in completion queue: %" PRIu32 warn_report("NVMe: Unexpected CID in completion queue: %"PRIu32", "
", should be within: 1..%u inclusively", cid, "queue size: %u", cid, NVME_QUEUE_SIZE);
NVME_NUM_REQS);
continue; continue;
} }
trace_nvme_complete_command(s, q->index, cid); trace_nvme_complete_command(s, q->index, cid);
@@ -478,7 +476,7 @@ static void nvme_trace_command(const NvmeCmd *cmd)
} }
} }
static void nvme_deferred_fn(void *opaque) static void nvme_unplug_fn(void *opaque)
{ {
NVMeQueuePair *q = opaque; NVMeQueuePair *q = opaque;
@@ -505,7 +503,7 @@ static void nvme_submit_command(NVMeQueuePair *q, NVMeRequest *req,
q->need_kick++; q->need_kick++;
qemu_mutex_unlock(&q->lock); qemu_mutex_unlock(&q->lock);
defer_call(nvme_deferred_fn, q); blk_io_plug_call(nvme_unplug_fn, q);
} }
static void nvme_admin_cmd_sync_cb(void *opaque, int ret) static void nvme_admin_cmd_sync_cb(void *opaque, int ret)

View File

@@ -59,9 +59,10 @@ typedef struct ParallelsDirtyBitmapFeature {
} QEMU_PACKED ParallelsDirtyBitmapFeature; } QEMU_PACKED ParallelsDirtyBitmapFeature;
/* Given L1 table read bitmap data from the image and populate @bitmap */ /* Given L1 table read bitmap data from the image and populate @bitmap */
static int GRAPH_RDLOCK static int parallels_load_bitmap_data(BlockDriverState *bs,
parallels_load_bitmap_data(BlockDriverState *bs, const uint64_t *l1_table, const uint64_t *l1_table,
uint32_t l1_size, BdrvDirtyBitmap *bitmap, uint32_t l1_size,
BdrvDirtyBitmap *bitmap,
Error **errp) Error **errp)
{ {
BDRVParallelsState *s = bs->opaque; BDRVParallelsState *s = bs->opaque;
@@ -119,8 +120,9 @@ finish:
* @data buffer (of @data_size size) is the Dirty bitmaps feature which * @data buffer (of @data_size size) is the Dirty bitmaps feature which
* consists of ParallelsDirtyBitmapFeature followed by L1 table. * consists of ParallelsDirtyBitmapFeature followed by L1 table.
*/ */
static BdrvDirtyBitmap * GRAPH_RDLOCK static BdrvDirtyBitmap *parallels_load_bitmap(BlockDriverState *bs,
parallels_load_bitmap(BlockDriverState *bs, uint8_t *data, size_t data_size, uint8_t *data,
size_t data_size,
Error **errp) Error **errp)
{ {
int ret; int ret;
@@ -128,7 +130,7 @@ parallels_load_bitmap(BlockDriverState *bs, uint8_t *data, size_t data_size,
g_autofree uint64_t *l1_table = NULL; g_autofree uint64_t *l1_table = NULL;
BdrvDirtyBitmap *bitmap; BdrvDirtyBitmap *bitmap;
QemuUUID uuid; QemuUUID uuid;
char uuidstr[UUID_STR_LEN]; char uuidstr[UUID_FMT_LEN + 1];
int i; int i;
if (data_size < sizeof(bf)) { if (data_size < sizeof(bf)) {
@@ -181,9 +183,8 @@ parallels_load_bitmap(BlockDriverState *bs, uint8_t *data, size_t data_size,
return bitmap; return bitmap;
} }
static int GRAPH_RDLOCK static int parallels_parse_format_extension(BlockDriverState *bs,
parallels_parse_format_extension(BlockDriverState *bs, uint8_t *ext_cluster, uint8_t *ext_cluster, Error **errp)
Error **errp)
{ {
BDRVParallelsState *s = bs->opaque; BDRVParallelsState *s = bs->opaque;
int ret; int ret;

View File

@@ -200,7 +200,7 @@ static int mark_used(BlockDriverState *bs, unsigned long *bitmap,
* bitmap anyway, as much as we can. This information will be used for * bitmap anyway, as much as we can. This information will be used for
* error resolution. * error resolution.
*/ */
static int GRAPH_RDLOCK parallels_fill_used_bitmap(BlockDriverState *bs) static int parallels_fill_used_bitmap(BlockDriverState *bs)
{ {
BDRVParallelsState *s = bs->opaque; BDRVParallelsState *s = bs->opaque;
int64_t payload_bytes; int64_t payload_bytes;
@@ -415,9 +415,13 @@ parallels_co_flush_to_os(BlockDriverState *bs)
return 0; return 0;
} }
static int coroutine_fn GRAPH_RDLOCK
parallels_co_block_status(BlockDriverState *bs, bool want_zero, int64_t offset, static int coroutine_fn parallels_co_block_status(BlockDriverState *bs,
int64_t bytes, int64_t *pnum, int64_t *map, bool want_zero,
int64_t offset,
int64_t bytes,
int64_t *pnum,
int64_t *map,
BlockDriverState **file) BlockDriverState **file)
{ {
BDRVParallelsState *s = bs->opaque; BDRVParallelsState *s = bs->opaque;
@@ -1185,7 +1189,7 @@ static int parallels_probe(const uint8_t *buf, int buf_size,
return 0; return 0;
} }
static int GRAPH_RDLOCK parallels_update_header(BlockDriverState *bs) static int parallels_update_header(BlockDriverState *bs)
{ {
BDRVParallelsState *s = bs->opaque; BDRVParallelsState *s = bs->opaque;
unsigned size = MAX(bdrv_opt_mem_align(bs->file->bs), unsigned size = MAX(bdrv_opt_mem_align(bs->file->bs),
@@ -1255,8 +1259,6 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
return ret; return ret;
} }
GRAPH_RDLOCK_GUARD_MAINLOOP();
file_nb_sectors = bdrv_nb_sectors(bs->file->bs); file_nb_sectors = bdrv_nb_sectors(bs->file->bs);
if (file_nb_sectors < 0) { if (file_nb_sectors < 0) {
return -EINVAL; return -EINVAL;
@@ -1361,12 +1363,15 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
bitmap_new(DIV_ROUND_UP(s->header_size, s->bat_dirty_block)); bitmap_new(DIV_ROUND_UP(s->header_size, s->bat_dirty_block));
/* Disable migration until bdrv_activate method is added */ /* Disable migration until bdrv_activate method is added */
bdrv_graph_rdlock_main_loop();
error_setg(&s->migration_blocker, "The Parallels format used by node '%s' " error_setg(&s->migration_blocker, "The Parallels format used by node '%s' "
"does not support live migration", "does not support live migration",
bdrv_get_device_or_node_name(bs)); bdrv_get_device_or_node_name(bs));
bdrv_graph_rdunlock_main_loop();
ret = migrate_add_blocker_normal(&s->migration_blocker, errp); ret = migrate_add_blocker(s->migration_blocker, errp);
if (ret < 0) { if (ret < 0) {
error_setg(errp, "Migration blocker error");
goto fail; goto fail;
} }
qemu_co_mutex_init(&s->lock); qemu_co_mutex_init(&s->lock);
@@ -1401,7 +1406,7 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
ret = bdrv_check(bs, &res, BDRV_FIX_ERRORS | BDRV_FIX_LEAKS); ret = bdrv_check(bs, &res, BDRV_FIX_ERRORS | BDRV_FIX_LEAKS);
if (ret < 0) { if (ret < 0) {
error_setg_errno(errp, -ret, "Could not repair corrupted image"); error_setg_errno(errp, -ret, "Could not repair corrupted image");
migrate_del_blocker(&s->migration_blocker); migrate_del_blocker(s->migration_blocker);
goto fail; goto fail;
} }
} }
@@ -1418,6 +1423,7 @@ fail:
*/ */
parallels_free_used_bitmap(bs); parallels_free_used_bitmap(bs);
error_free(s->migration_blocker);
g_free(s->bat_dirty_bmap); g_free(s->bat_dirty_bmap);
qemu_vfree(s->header); qemu_vfree(s->header);
return ret; return ret;
@@ -1428,8 +1434,6 @@ static void parallels_close(BlockDriverState *bs)
{ {
BDRVParallelsState *s = bs->opaque; BDRVParallelsState *s = bs->opaque;
GRAPH_RDLOCK_GUARD_MAINLOOP();
if ((bs->open_flags & BDRV_O_RDWR) && !(bs->open_flags & BDRV_O_INACTIVE)) { if ((bs->open_flags & BDRV_O_RDWR) && !(bs->open_flags & BDRV_O_INACTIVE)) {
s->header->inuse = 0; s->header->inuse = 0;
parallels_update_header(bs); parallels_update_header(bs);
@@ -1444,7 +1448,8 @@ static void parallels_close(BlockDriverState *bs)
g_free(s->bat_dirty_bmap); g_free(s->bat_dirty_bmap);
qemu_vfree(s->header); qemu_vfree(s->header);
migrate_del_blocker(&s->migration_blocker); migrate_del_blocker(s->migration_blocker);
error_free(s->migration_blocker);
} }
static bool parallels_is_support_dirty_bitmaps(BlockDriverState *bs) static bool parallels_is_support_dirty_bitmaps(BlockDriverState *bs)

View File

@@ -90,8 +90,7 @@ typedef struct BDRVParallelsState {
Error *migration_blocker; Error *migration_blocker;
} BDRVParallelsState; } BDRVParallelsState;
int GRAPH_RDLOCK int parallels_read_format_extension(BlockDriverState *bs,
parallels_read_format_extension(BlockDriverState *bs, int64_t ext_off, int64_t ext_off, Error **errp);
Error **errp);
#endif #endif

159
block/plug.c Normal file
View File

@@ -0,0 +1,159 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Block I/O plugging
*
* Copyright Red Hat.
*
* This API defers a function call within a blk_io_plug()/blk_io_unplug()
* section, allowing multiple calls to batch up. This is a performance
* optimization that is used in the block layer to submit several I/O requests
* at once instead of individually:
*
* blk_io_plug(); <-- start of plugged region
* ...
* blk_io_plug_call(my_func, my_obj); <-- deferred my_func(my_obj) call
* blk_io_plug_call(my_func, my_obj); <-- another
* blk_io_plug_call(my_func, my_obj); <-- another
* ...
* blk_io_unplug(); <-- end of plugged region, my_func(my_obj) is called once
*
* This code is actually generic and not tied to the block layer. If another
* subsystem needs this functionality, it could be renamed.
*/
#include "qemu/osdep.h"
#include "qemu/coroutine-tls.h"
#include "qemu/notify.h"
#include "qemu/thread.h"
#include "sysemu/block-backend.h"
/* A function call that has been deferred until unplug() */
typedef struct {
void (*fn)(void *);
void *opaque;
} UnplugFn;
/* Per-thread state */
typedef struct {
unsigned count; /* how many times has plug() been called? */
GArray *unplug_fns; /* functions to call at unplug time */
} Plug;
/* Use get_ptr_plug() to fetch this thread-local value */
QEMU_DEFINE_STATIC_CO_TLS(Plug, plug);
/* Called at thread cleanup time */
static void blk_io_plug_atexit(Notifier *n, void *value)
{
Plug *plug = get_ptr_plug();
g_array_free(plug->unplug_fns, TRUE);
}
/* This won't involve coroutines, so use __thread */
static __thread Notifier blk_io_plug_atexit_notifier;
/**
* blk_io_plug_call:
* @fn: a function pointer to be invoked
* @opaque: a user-defined argument to @fn()
*
* Call @fn(@opaque) immediately if not within a blk_io_plug()/blk_io_unplug()
* section.
*
* Otherwise defer the call until the end of the outermost
* blk_io_plug()/blk_io_unplug() section in this thread. If the same
* @fn/@opaque pair has already been deferred, it will only be called once upon
* blk_io_unplug() so that accumulated calls are batched into a single call.
*
* The caller must ensure that @opaque is not freed before @fn() is invoked.
*/
void blk_io_plug_call(void (*fn)(void *), void *opaque)
{
Plug *plug = get_ptr_plug();
/* Call immediately if we're not plugged */
if (plug->count == 0) {
fn(opaque);
return;
}
GArray *array = plug->unplug_fns;
if (!array) {
array = g_array_new(FALSE, FALSE, sizeof(UnplugFn));
plug->unplug_fns = array;
blk_io_plug_atexit_notifier.notify = blk_io_plug_atexit;
qemu_thread_atexit_add(&blk_io_plug_atexit_notifier);
}
UnplugFn *fns = (UnplugFn *)array->data;
UnplugFn new_fn = {
.fn = fn,
.opaque = opaque,
};
/*
* There won't be many, so do a linear search. If this becomes a bottleneck
* then a binary search (glib 2.62+) or different data structure could be
* used.
*/
for (guint i = 0; i < array->len; i++) {
if (memcmp(&fns[i], &new_fn, sizeof(new_fn)) == 0) {
return; /* already exists */
}
}
g_array_append_val(array, new_fn);
}
/**
* blk_io_plug: Defer blk_io_plug_call() functions until blk_io_unplug()
*
* blk_io_plug/unplug are thread-local operations. This means that multiple
* threads can simultaneously call plug/unplug, but the caller must ensure that
* each unplug() is called in the same thread of the matching plug().
*
* Nesting is supported. blk_io_plug_call() functions are only called at the
* outermost blk_io_unplug().
*/
void blk_io_plug(void)
{
Plug *plug = get_ptr_plug();
assert(plug->count < UINT32_MAX);
plug->count++;
}
/**
* blk_io_unplug: Run any pending blk_io_plug_call() functions
*
* There must have been a matching blk_io_plug() call in the same thread prior
* to this blk_io_unplug() call.
*/
void blk_io_unplug(void)
{
Plug *plug = get_ptr_plug();
assert(plug->count > 0);
if (--plug->count > 0) {
return;
}
GArray *array = plug->unplug_fns;
if (!array) {
return;
}
UnplugFn *fns = (UnplugFn *)array->data;
for (guint i = 0; i < array->len; i++) {
fns[i].fn(fns[i].opaque);
}
/*
* This resets the array without freeing memory so that appending is cheap
* in the future.
*/
g_array_set_size(array, 0);
}

View File

@@ -143,8 +143,6 @@ static int preallocate_open(BlockDriverState *bs, QDict *options, int flags,
BDRVPreallocateState *s = bs->opaque; BDRVPreallocateState *s = bs->opaque;
int ret; int ret;
GLOBAL_STATE_CODE();
/* /*
* s->data_end and friends should be initialized on permission update. * s->data_end and friends should be initialized on permission update.
* For this to work, mark them invalid. * For this to work, mark them invalid.
@@ -157,8 +155,6 @@ static int preallocate_open(BlockDriverState *bs, QDict *options, int flags,
return ret; return ret;
} }
GRAPH_RDLOCK_GUARD_MAINLOOP();
if (!preallocate_absorb_opts(&s->opts, options, bs->file->bs, errp)) { if (!preallocate_absorb_opts(&s->opts, options, bs->file->bs, errp)) {
return -EINVAL; return -EINVAL;
} }
@@ -173,8 +169,7 @@ static int preallocate_open(BlockDriverState *bs, QDict *options, int flags,
return 0; return 0;
} }
static int GRAPH_RDLOCK static int preallocate_truncate_to_real_size(BlockDriverState *bs, Error **errp)
preallocate_truncate_to_real_size(BlockDriverState *bs, Error **errp)
{ {
BDRVPreallocateState *s = bs->opaque; BDRVPreallocateState *s = bs->opaque;
int ret; int ret;
@@ -205,9 +200,6 @@ static void preallocate_close(BlockDriverState *bs)
{ {
BDRVPreallocateState *s = bs->opaque; BDRVPreallocateState *s = bs->opaque;
GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
qemu_bh_cancel(s->drop_resize_bh); qemu_bh_cancel(s->drop_resize_bh);
qemu_bh_delete(s->drop_resize_bh); qemu_bh_delete(s->drop_resize_bh);
@@ -231,9 +223,6 @@ static int preallocate_reopen_prepare(BDRVReopenState *reopen_state,
PreallocateOpts *opts = g_new0(PreallocateOpts, 1); PreallocateOpts *opts = g_new0(PreallocateOpts, 1);
int ret; int ret;
GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
if (!preallocate_absorb_opts(opts, reopen_state->options, if (!preallocate_absorb_opts(opts, reopen_state->options,
reopen_state->bs->file->bs, errp)) { reopen_state->bs->file->bs, errp)) {
g_free(opts); g_free(opts);
@@ -294,7 +283,7 @@ static bool can_write_resize(uint64_t perm)
return (perm & BLK_PERM_WRITE) && (perm & BLK_PERM_RESIZE); return (perm & BLK_PERM_WRITE) && (perm & BLK_PERM_RESIZE);
} }
static bool GRAPH_RDLOCK has_prealloc_perms(BlockDriverState *bs) static bool has_prealloc_perms(BlockDriverState *bs)
{ {
BDRVPreallocateState *s = bs->opaque; BDRVPreallocateState *s = bs->opaque;
@@ -510,8 +499,7 @@ preallocate_co_getlength(BlockDriverState *bs)
return ret; return ret;
} }
static int GRAPH_RDLOCK static int preallocate_drop_resize(BlockDriverState *bs, Error **errp)
preallocate_drop_resize(BlockDriverState *bs, Error **errp)
{ {
BDRVPreallocateState *s = bs->opaque; BDRVPreallocateState *s = bs->opaque;
int ret; int ret;
@@ -537,16 +525,15 @@ preallocate_drop_resize(BlockDriverState *bs, Error **errp)
*/ */
s->data_end = s->file_end = s->zero_start = -EINVAL; s->data_end = s->file_end = s->zero_start = -EINVAL;
bdrv_graph_rdlock_main_loop();
bdrv_child_refresh_perms(bs, bs->file, NULL); bdrv_child_refresh_perms(bs, bs->file, NULL);
bdrv_graph_rdunlock_main_loop();
return 0; return 0;
} }
static void preallocate_drop_resize_bh(void *opaque) static void preallocate_drop_resize_bh(void *opaque)
{ {
GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
/* /*
* In case of errors, we'll simply keep the exclusive lock on the image * In case of errors, we'll simply keep the exclusive lock on the image
* indefinitely. * indefinitely.
@@ -554,8 +541,8 @@ static void preallocate_drop_resize_bh(void *opaque)
preallocate_drop_resize(opaque, NULL); preallocate_drop_resize(opaque, NULL);
} }
static void GRAPH_RDLOCK static void preallocate_set_perm(BlockDriverState *bs,
preallocate_set_perm(BlockDriverState *bs, uint64_t perm, uint64_t shared) uint64_t perm, uint64_t shared)
{ {
BDRVPreallocateState *s = bs->opaque; BDRVPreallocateState *s = bs->opaque;

View File

@@ -237,7 +237,6 @@ static void qmp_blockdev_insert_anon_medium(BlockBackend *blk,
BlockDriverState *bs, Error **errp) BlockDriverState *bs, Error **errp)
{ {
Error *local_err = NULL; Error *local_err = NULL;
AioContext *ctx;
bool has_device; bool has_device;
int ret; int ret;
@@ -259,11 +258,7 @@ static void qmp_blockdev_insert_anon_medium(BlockBackend *blk,
return; return;
} }
ctx = bdrv_get_aio_context(bs);
aio_context_acquire(ctx);
ret = blk_insert_bs(blk, bs, errp); ret = blk_insert_bs(blk, bs, errp);
aio_context_release(ctx);
if (ret < 0) { if (ret < 0) {
return; return;
} }

View File

@@ -124,11 +124,9 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
ret = bdrv_open_file_child(NULL, options, "file", bs, errp); ret = bdrv_open_file_child(NULL, options, "file", bs, errp);
if (ret < 0) { if (ret < 0) {
goto fail_unlocked; goto fail;
} }
bdrv_graph_rdlock_main_loop();
ret = bdrv_pread(bs->file, 0, sizeof(header), &header, 0); ret = bdrv_pread(bs->file, 0, sizeof(header), &header, 0);
if (ret < 0) { if (ret < 0) {
goto fail; goto fail;
@@ -303,24 +301,24 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
} }
/* Disable migration when qcow images are used */ /* Disable migration when qcow images are used */
bdrv_graph_rdlock_main_loop();
error_setg(&s->migration_blocker, "The qcow format used by node '%s' " error_setg(&s->migration_blocker, "The qcow format used by node '%s' "
"does not support live migration", "does not support live migration",
bdrv_get_device_or_node_name(bs)); bdrv_get_device_or_node_name(bs));
bdrv_graph_rdunlock_main_loop();
ret = migrate_add_blocker_normal(&s->migration_blocker, errp); ret = migrate_add_blocker(s->migration_blocker, errp);
if (ret < 0) { if (ret < 0) {
error_free(s->migration_blocker);
goto fail; goto fail;
} }
qobject_unref(encryptopts); qobject_unref(encryptopts);
qapi_free_QCryptoBlockOpenOptions(crypto_opts); qapi_free_QCryptoBlockOpenOptions(crypto_opts);
qemu_co_mutex_init(&s->lock); qemu_co_mutex_init(&s->lock);
bdrv_graph_rdunlock_main_loop();
return 0; return 0;
fail: fail:
bdrv_graph_rdunlock_main_loop();
fail_unlocked:
g_free(s->l1_table); g_free(s->l1_table);
qemu_vfree(s->l2_cache); qemu_vfree(s->l2_cache);
g_free(s->cluster_cache); g_free(s->cluster_cache);
@@ -804,7 +802,8 @@ static void qcow_close(BlockDriverState *bs)
g_free(s->cluster_cache); g_free(s->cluster_cache);
g_free(s->cluster_data); g_free(s->cluster_data);
migrate_del_blocker(&s->migration_blocker); migrate_del_blocker(s->migration_blocker);
error_free(s->migration_blocker);
} }
static int coroutine_fn GRAPH_UNLOCKED static int coroutine_fn GRAPH_UNLOCKED
@@ -1027,7 +1026,7 @@ fail:
return ret; return ret;
} }
static int GRAPH_RDLOCK qcow_make_empty(BlockDriverState *bs) static int qcow_make_empty(BlockDriverState *bs)
{ {
BDRVQcowState *s = bs->opaque; BDRVQcowState *s = bs->opaque;
uint32_t l1_length = s->l1_size * sizeof(uint64_t); uint32_t l1_length = s->l1_size * sizeof(uint64_t);

View File

@@ -105,7 +105,7 @@ static inline bool can_write(BlockDriverState *bs)
return !bdrv_is_read_only(bs) && !(bdrv_get_flags(bs) & BDRV_O_INACTIVE); return !bdrv_is_read_only(bs) && !(bdrv_get_flags(bs) & BDRV_O_INACTIVE);
} }
static int GRAPH_RDLOCK update_header_sync(BlockDriverState *bs) static int update_header_sync(BlockDriverState *bs)
{ {
int ret; int ret;
@@ -221,8 +221,7 @@ clear_bitmap_table(BlockDriverState *bs, uint64_t *bitmap_table,
} }
} }
static int GRAPH_RDLOCK static int bitmap_table_load(BlockDriverState *bs, Qcow2BitmapTable *tb,
bitmap_table_load(BlockDriverState *bs, Qcow2BitmapTable *tb,
uint64_t **bitmap_table) uint64_t **bitmap_table)
{ {
int ret; int ret;
@@ -552,9 +551,8 @@ static uint32_t bitmap_list_count(Qcow2BitmapList *bm_list)
* Get bitmap list from qcow2 image. Actually reads bitmap directory, * Get bitmap list from qcow2 image. Actually reads bitmap directory,
* checks it and convert to bitmap list. * checks it and convert to bitmap list.
*/ */
static Qcow2BitmapList * GRAPH_RDLOCK static Qcow2BitmapList *bitmap_list_load(BlockDriverState *bs, uint64_t offset,
bitmap_list_load(BlockDriverState *bs, uint64_t offset, uint64_t size, uint64_t size, Error **errp)
Error **errp)
{ {
int ret; int ret;
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
@@ -963,7 +961,7 @@ static void set_readonly_helper(gpointer bitmap, gpointer value)
* If header_updated is not NULL then it is set appropriately regardless of * If header_updated is not NULL then it is set appropriately regardless of
* the return value. * the return value.
*/ */
bool coroutine_fn bool coroutine_fn GRAPH_RDLOCK
qcow2_load_dirty_bitmaps(BlockDriverState *bs, qcow2_load_dirty_bitmaps(BlockDriverState *bs,
bool *header_updated, Error **errp) bool *header_updated, Error **errp)
{ {

View File

@@ -391,9 +391,10 @@ fail:
* If the L2 entry is invalid return -errno and set @type to * If the L2 entry is invalid return -errno and set @type to
* QCOW2_SUBCLUSTER_INVALID. * QCOW2_SUBCLUSTER_INVALID.
*/ */
static int GRAPH_RDLOCK static int qcow2_get_subcluster_range_type(BlockDriverState *bs,
qcow2_get_subcluster_range_type(BlockDriverState *bs, uint64_t l2_entry, uint64_t l2_entry,
uint64_t l2_bitmap, unsigned sc_from, uint64_t l2_bitmap,
unsigned sc_from,
QCow2SubclusterType *type) QCow2SubclusterType *type)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
@@ -441,8 +442,7 @@ qcow2_get_subcluster_range_type(BlockDriverState *bs, uint64_t l2_entry,
* On failure return -errno and update @l2_index to point to the * On failure return -errno and update @l2_index to point to the
* invalid entry. * invalid entry.
*/ */
static int GRAPH_RDLOCK static int count_contiguous_subclusters(BlockDriverState *bs, int nb_clusters,
count_contiguous_subclusters(BlockDriverState *bs, int nb_clusters,
unsigned sc_index, uint64_t *l2_slice, unsigned sc_index, uint64_t *l2_slice,
unsigned *l2_index) unsigned *l2_index)
{ {
@@ -1329,8 +1329,7 @@ calculate_l2_meta(BlockDriverState *bs, uint64_t host_cluster_offset,
* requires a new allocation (that is, if the cluster is unallocated * requires a new allocation (that is, if the cluster is unallocated
* or has refcount > 1 and therefore cannot be written in-place). * or has refcount > 1 and therefore cannot be written in-place).
*/ */
static bool GRAPH_RDLOCK static bool cluster_needs_new_alloc(BlockDriverState *bs, uint64_t l2_entry)
cluster_needs_new_alloc(BlockDriverState *bs, uint64_t l2_entry)
{ {
switch (qcow2_get_cluster_type(bs, l2_entry)) { switch (qcow2_get_cluster_type(bs, l2_entry)) {
case QCOW2_CLUSTER_NORMAL: case QCOW2_CLUSTER_NORMAL:
@@ -1361,9 +1360,9 @@ cluster_needs_new_alloc(BlockDriverState *bs, uint64_t l2_entry)
* allocated and can be overwritten in-place (this includes clusters * allocated and can be overwritten in-place (this includes clusters
* of type QCOW2_CLUSTER_ZERO_ALLOC). * of type QCOW2_CLUSTER_ZERO_ALLOC).
*/ */
static int GRAPH_RDLOCK static int count_single_write_clusters(BlockDriverState *bs, int nb_clusters,
count_single_write_clusters(BlockDriverState *bs, int nb_clusters, uint64_t *l2_slice, int l2_index,
uint64_t *l2_slice, int l2_index, bool new_alloc) bool new_alloc)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
uint64_t l2_entry = get_l2_entry(s, l2_slice, l2_index); uint64_t l2_entry = get_l2_entry(s, l2_slice, l2_index);
@@ -2062,15 +2061,9 @@ zero_in_l2_slice(BlockDriverState *bs, uint64_t offset,
QCow2ClusterType type = qcow2_get_cluster_type(bs, old_l2_entry); QCow2ClusterType type = qcow2_get_cluster_type(bs, old_l2_entry);
bool unmap = (type == QCOW2_CLUSTER_COMPRESSED) || bool unmap = (type == QCOW2_CLUSTER_COMPRESSED) ||
((flags & BDRV_REQ_MAY_UNMAP) && qcow2_cluster_is_allocated(type)); ((flags & BDRV_REQ_MAY_UNMAP) && qcow2_cluster_is_allocated(type));
bool keep_reference = uint64_t new_l2_entry = unmap ? 0 : old_l2_entry;
(s->discard_no_unref && type != QCOW2_CLUSTER_COMPRESSED);
uint64_t new_l2_entry = old_l2_entry;
uint64_t new_l2_bitmap = old_l2_bitmap; uint64_t new_l2_bitmap = old_l2_bitmap;
if (unmap && !keep_reference) {
new_l2_entry = 0;
}
if (has_subclusters(s)) { if (has_subclusters(s)) {
new_l2_bitmap = QCOW_L2_BITMAP_ALL_ZEROES; new_l2_bitmap = QCOW_L2_BITMAP_ALL_ZEROES;
} else { } else {
@@ -2088,17 +2081,9 @@ zero_in_l2_slice(BlockDriverState *bs, uint64_t offset,
set_l2_bitmap(s, l2_slice, l2_index + i, new_l2_bitmap); set_l2_bitmap(s, l2_slice, l2_index + i, new_l2_bitmap);
} }
if (unmap) {
if (!keep_reference) {
/* Then decrease the refcount */ /* Then decrease the refcount */
if (unmap) {
qcow2_free_any_cluster(bs, old_l2_entry, QCOW2_DISCARD_REQUEST); qcow2_free_any_cluster(bs, old_l2_entry, QCOW2_DISCARD_REQUEST);
} else if (s->discard_passthrough[QCOW2_DISCARD_REQUEST] &&
(type == QCOW2_CLUSTER_NORMAL ||
type == QCOW2_CLUSTER_ZERO_ALLOC)) {
/* If we keep the reference, pass on the discard still */
bdrv_pdiscard(s->data_file, old_l2_entry & L2E_OFFSET_MASK,
s->cluster_size);
}
} }
} }

View File

@@ -95,8 +95,7 @@ static int qcow2_probe(const uint8_t *buf, int buf_size, const char *filename)
} }
static int GRAPH_RDLOCK static int qcow2_crypto_hdr_read_func(QCryptoBlock *block, size_t offset,
qcow2_crypto_hdr_read_func(QCryptoBlock *block, size_t offset,
uint8_t *buf, size_t buflen, uint8_t *buf, size_t buflen,
void *opaque, Error **errp) void *opaque, Error **errp)
{ {
@@ -157,7 +156,7 @@ qcow2_crypto_hdr_init_func(QCryptoBlock *block, size_t headerlen, void *opaque,
/* The graph lock must be held when called in coroutine context */ /* The graph lock must be held when called in coroutine context */
static int coroutine_mixed_fn GRAPH_RDLOCK static int coroutine_mixed_fn
qcow2_crypto_hdr_write_func(QCryptoBlock *block, size_t offset, qcow2_crypto_hdr_write_func(QCryptoBlock *block, size_t offset,
const uint8_t *buf, size_t buflen, const uint8_t *buf, size_t buflen,
void *opaque, Error **errp) void *opaque, Error **errp)
@@ -2030,8 +2029,6 @@ static void qcow2_reopen_commit(BDRVReopenState *state)
{ {
BDRVQcow2State *s = state->bs->opaque; BDRVQcow2State *s = state->bs->opaque;
GRAPH_RDLOCK_GUARD_MAINLOOP();
qcow2_update_options_commit(state->bs, state->opaque); qcow2_update_options_commit(state->bs, state->opaque);
if (!s->data_file) { if (!s->data_file) {
/* /*
@@ -2067,8 +2064,6 @@ static void qcow2_reopen_abort(BDRVReopenState *state)
{ {
BDRVQcow2State *s = state->bs->opaque; BDRVQcow2State *s = state->bs->opaque;
GRAPH_RDLOCK_GUARD_MAINLOOP();
if (!s->data_file) { if (!s->data_file) {
/* /*
* If we don't have an external data file, s->data_file was cleared by * If we don't have an external data file, s->data_file was cleared by
@@ -3160,9 +3155,8 @@ fail:
return ret; return ret;
} }
static int coroutine_fn GRAPH_RDLOCK static int qcow2_change_backing_file(BlockDriverState *bs,
qcow2_co_change_backing_file(BlockDriverState *bs, const char *backing_file, const char *backing_file, const char *backing_fmt)
const char *backing_fmt)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
@@ -3822,11 +3816,8 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
backing_format = BlockdevDriver_str(qcow2_opts->backing_fmt); backing_format = BlockdevDriver_str(qcow2_opts->backing_fmt);
} }
bdrv_graph_co_rdlock(); ret = bdrv_change_backing_file(blk_bs(blk), qcow2_opts->backing_file,
ret = bdrv_co_change_backing_file(blk_bs(blk), qcow2_opts->backing_file,
backing_format, false); backing_format, false);
bdrv_graph_co_rdunlock();
if (ret < 0) { if (ret < 0) {
error_setg_errno(errp, -ret, "Could not assign backing file '%s' " error_setg_errno(errp, -ret, "Could not assign backing file '%s' "
"with format '%s'", qcow2_opts->backing_file, "with format '%s'", qcow2_opts->backing_file,
@@ -5231,8 +5222,8 @@ qcow2_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
return 0; return 0;
} }
static ImageInfoSpecific * GRAPH_RDLOCK static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs,
qcow2_get_specific_info(BlockDriverState *bs, Error **errp) Error **errp)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
ImageInfoSpecific *spec_info; ImageInfoSpecific *spec_info;
@@ -5311,8 +5302,7 @@ qcow2_get_specific_info(BlockDriverState *bs, Error **errp)
return spec_info; return spec_info;
} }
static int coroutine_mixed_fn GRAPH_RDLOCK static int coroutine_mixed_fn qcow2_has_zero_init(BlockDriverState *bs)
qcow2_has_zero_init(BlockDriverState *bs)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
bool preallocated; bool preallocated;
@@ -6166,7 +6156,7 @@ BlockDriver bdrv_qcow2 = {
.is_format = true, .is_format = true,
.supports_backing = true, .supports_backing = true,
.bdrv_co_change_backing_file = qcow2_co_change_backing_file, .bdrv_change_backing_file = qcow2_change_backing_file,
.bdrv_refresh_limits = qcow2_refresh_limits, .bdrv_refresh_limits = qcow2_refresh_limits,
.bdrv_co_invalidate_cache = qcow2_co_invalidate_cache, .bdrv_co_invalidate_cache = qcow2_co_invalidate_cache,

View File

@@ -641,7 +641,7 @@ static inline void set_l2_bitmap(BDRVQcow2State *s, uint64_t *l2_slice,
l2_slice[idx + 1] = cpu_to_be64(bitmap); l2_slice[idx + 1] = cpu_to_be64(bitmap);
} }
static inline bool GRAPH_RDLOCK has_data_file(BlockDriverState *bs) static inline bool has_data_file(BlockDriverState *bs)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
return (s->data_file != bs->file); return (s->data_file != bs->file);
@@ -709,8 +709,8 @@ static inline int64_t qcow2_vm_state_offset(BDRVQcow2State *s)
return (int64_t)s->l1_vm_state_index << (s->cluster_bits + s->l2_bits); return (int64_t)s->l1_vm_state_index << (s->cluster_bits + s->l2_bits);
} }
static inline QCow2ClusterType GRAPH_RDLOCK static inline QCow2ClusterType qcow2_get_cluster_type(BlockDriverState *bs,
qcow2_get_cluster_type(BlockDriverState *bs, uint64_t l2_entry) uint64_t l2_entry)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
@@ -743,7 +743,7 @@ qcow2_get_cluster_type(BlockDriverState *bs, uint64_t l2_entry)
* (this checks the whole entry and bitmap, not only the bits related * (this checks the whole entry and bitmap, not only the bits related
* to subcluster @sc_index). * to subcluster @sc_index).
*/ */
static inline GRAPH_RDLOCK static inline
QCow2SubclusterType qcow2_get_subcluster_type(BlockDriverState *bs, QCow2SubclusterType qcow2_get_subcluster_type(BlockDriverState *bs,
uint64_t l2_entry, uint64_t l2_entry,
uint64_t l2_bitmap, uint64_t l2_bitmap,
@@ -834,9 +834,9 @@ int64_t qcow2_refcount_metadata_size(int64_t clusters, size_t cluster_size,
int refcount_order, bool generous_increase, int refcount_order, bool generous_increase,
uint64_t *refblock_count); uint64_t *refblock_count);
int GRAPH_RDLOCK qcow2_mark_dirty(BlockDriverState *bs); int qcow2_mark_dirty(BlockDriverState *bs);
int GRAPH_RDLOCK qcow2_mark_corrupt(BlockDriverState *bs); int qcow2_mark_corrupt(BlockDriverState *bs);
int GRAPH_RDLOCK qcow2_update_header(BlockDriverState *bs); int qcow2_update_header(BlockDriverState *bs);
void GRAPH_RDLOCK void GRAPH_RDLOCK
qcow2_signal_corruption(BlockDriverState *bs, bool fatal, int64_t offset, qcow2_signal_corruption(BlockDriverState *bs, bool fatal, int64_t offset,
@@ -890,10 +890,9 @@ int GRAPH_RDLOCK qcow2_write_caches(BlockDriverState *bs);
int coroutine_fn qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res, int coroutine_fn qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
BdrvCheckMode fix); BdrvCheckMode fix);
void GRAPH_RDLOCK qcow2_process_discards(BlockDriverState *bs, int ret); void qcow2_process_discards(BlockDriverState *bs, int ret);
int GRAPH_RDLOCK int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset,
qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset,
int64_t size); int64_t size);
int GRAPH_RDLOCK int GRAPH_RDLOCK
qcow2_pre_write_overlap_check(BlockDriverState *bs, int ign, int64_t offset, qcow2_pre_write_overlap_check(BlockDriverState *bs, int ign, int64_t offset,
@@ -940,8 +939,7 @@ qcow2_alloc_host_offset(BlockDriverState *bs, uint64_t offset,
int coroutine_fn GRAPH_RDLOCK int coroutine_fn GRAPH_RDLOCK
qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, uint64_t offset, qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, uint64_t offset,
int compressed_size, uint64_t *host_offset); int compressed_size, uint64_t *host_offset);
void GRAPH_RDLOCK void qcow2_parse_compressed_l2_entry(BlockDriverState *bs, uint64_t l2_entry,
qcow2_parse_compressed_l2_entry(BlockDriverState *bs, uint64_t l2_entry,
uint64_t *coffset, int *csize); uint64_t *coffset, int *csize);
int coroutine_fn GRAPH_RDLOCK int coroutine_fn GRAPH_RDLOCK
@@ -974,12 +972,11 @@ int GRAPH_RDLOCK
qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id, qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id,
const char *name, Error **errp); const char *name, Error **errp);
int GRAPH_RDLOCK int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab);
qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab); int qcow2_snapshot_load_tmp(BlockDriverState *bs,
const char *snapshot_id,
int GRAPH_RDLOCK const char *name,
qcow2_snapshot_load_tmp(BlockDriverState *bs, const char *snapshot_id, Error **errp);
const char *name, Error **errp);
void qcow2_free_snapshots(BlockDriverState *bs); void qcow2_free_snapshots(BlockDriverState *bs);
int coroutine_fn GRAPH_RDLOCK int coroutine_fn GRAPH_RDLOCK
@@ -995,9 +992,8 @@ qcow2_check_fix_snapshot_table(BlockDriverState *bs, BdrvCheckResult *result,
BdrvCheckMode fix); BdrvCheckMode fix);
/* qcow2-cache.c functions */ /* qcow2-cache.c functions */
Qcow2Cache * GRAPH_RDLOCK Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables,
qcow2_cache_create(BlockDriverState *bs, int num_tables, unsigned table_size); unsigned table_size);
int qcow2_cache_destroy(Qcow2Cache *c); int qcow2_cache_destroy(Qcow2Cache *c);
void qcow2_cache_entry_mark_dirty(Qcow2Cache *c, void *table); void qcow2_cache_entry_mark_dirty(Qcow2Cache *c, void *table);
@@ -1023,24 +1019,17 @@ void *qcow2_cache_is_table_offset(Qcow2Cache *c, uint64_t offset);
void qcow2_cache_discard(Qcow2Cache *c, void *table); void qcow2_cache_discard(Qcow2Cache *c, void *table);
/* qcow2-bitmap.c functions */ /* qcow2-bitmap.c functions */
int coroutine_fn GRAPH_RDLOCK int coroutine_fn
qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res, qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
void **refcount_table, void **refcount_table,
int64_t *refcount_table_size); int64_t *refcount_table_size);
bool coroutine_fn GRAPH_RDLOCK bool coroutine_fn GRAPH_RDLOCK
qcow2_load_dirty_bitmaps(BlockDriverState *bs, bool *header_updated, qcow2_load_dirty_bitmaps(BlockDriverState *bs, bool *header_updated, Error **errp);
Error **errp); bool qcow2_get_bitmap_info_list(BlockDriverState *bs,
bool GRAPH_RDLOCK
qcow2_get_bitmap_info_list(BlockDriverState *bs,
Qcow2BitmapInfoList **info_list, Error **errp); Qcow2BitmapInfoList **info_list, Error **errp);
int GRAPH_RDLOCK qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp); int GRAPH_RDLOCK qcow2_reopen_bitmaps_rw(BlockDriverState *bs, Error **errp);
int GRAPH_RDLOCK qcow2_reopen_bitmaps_ro(BlockDriverState *bs, Error **errp); int GRAPH_RDLOCK qcow2_reopen_bitmaps_ro(BlockDriverState *bs, Error **errp);
int coroutine_fn qcow2_truncate_bitmaps_check(BlockDriverState *bs, Error **errp);
int coroutine_fn GRAPH_RDLOCK
qcow2_truncate_bitmaps_check(BlockDriverState *bs, Error **errp);
bool GRAPH_RDLOCK bool GRAPH_RDLOCK
qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, bool release_stored, qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, bool release_stored,

View File

@@ -612,7 +612,7 @@ static int bdrv_qed_reopen_prepare(BDRVReopenState *state,
return 0; return 0;
} }
static void GRAPH_RDLOCK bdrv_qed_do_close(BlockDriverState *bs) static void bdrv_qed_close(BlockDriverState *bs)
{ {
BDRVQEDState *s = bs->opaque; BDRVQEDState *s = bs->opaque;
@@ -631,14 +631,6 @@ static void GRAPH_RDLOCK bdrv_qed_do_close(BlockDriverState *bs)
qemu_vfree(s->l1_table); qemu_vfree(s->l1_table);
} }
static void GRAPH_UNLOCKED bdrv_qed_close(BlockDriverState *bs)
{
GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
bdrv_qed_do_close(bs);
}
static int coroutine_fn GRAPH_UNLOCKED static int coroutine_fn GRAPH_UNLOCKED
bdrv_qed_co_create(BlockdevCreateOptions *opts, Error **errp) bdrv_qed_co_create(BlockdevCreateOptions *opts, Error **errp)
{ {
@@ -1146,7 +1138,7 @@ out:
/** /**
* Check if the QED_F_NEED_CHECK bit should be set during allocating write * Check if the QED_F_NEED_CHECK bit should be set during allocating write
*/ */
static bool GRAPH_RDLOCK qed_should_set_need_check(BDRVQEDState *s) static bool qed_should_set_need_check(BDRVQEDState *s)
{ {
/* The flush before L2 update path ensures consistency */ /* The flush before L2 update path ensures consistency */
if (s->bs->backing) { if (s->bs->backing) {
@@ -1451,9 +1443,11 @@ bdrv_qed_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes,
QED_AIOCB_WRITE | QED_AIOCB_ZERO); QED_AIOCB_WRITE | QED_AIOCB_ZERO);
} }
static int coroutine_fn GRAPH_RDLOCK static int coroutine_fn bdrv_qed_co_truncate(BlockDriverState *bs,
bdrv_qed_co_truncate(BlockDriverState *bs, int64_t offset, bool exact, int64_t offset,
PreallocMode prealloc, BdrvRequestFlags flags, bool exact,
PreallocMode prealloc,
BdrvRequestFlags flags,
Error **errp) Error **errp)
{ {
BDRVQEDState *s = bs->opaque; BDRVQEDState *s = bs->opaque;
@@ -1504,8 +1498,8 @@ bdrv_qed_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
return 0; return 0;
} }
static int coroutine_fn GRAPH_RDLOCK static int bdrv_qed_change_backing_file(BlockDriverState *bs,
bdrv_qed_co_change_backing_file(BlockDriverState *bs, const char *backing_file, const char *backing_file,
const char *backing_fmt) const char *backing_fmt)
{ {
BDRVQEDState *s = bs->opaque; BDRVQEDState *s = bs->opaque;
@@ -1568,7 +1562,7 @@ bdrv_qed_co_change_backing_file(BlockDriverState *bs, const char *backing_file,
} }
/* Write new header */ /* Write new header */
ret = bdrv_co_pwrite_sync(bs->file, 0, buffer_len, buffer, 0); ret = bdrv_pwrite_sync(bs->file, 0, buffer_len, buffer, 0);
g_free(buffer); g_free(buffer);
if (ret == 0) { if (ret == 0) {
memcpy(&s->header, &new_header, sizeof(new_header)); memcpy(&s->header, &new_header, sizeof(new_header));
@@ -1582,7 +1576,7 @@ bdrv_qed_co_invalidate_cache(BlockDriverState *bs, Error **errp)
BDRVQEDState *s = bs->opaque; BDRVQEDState *s = bs->opaque;
int ret; int ret;
bdrv_qed_do_close(bs); bdrv_qed_close(bs);
bdrv_qed_init_state(bs); bdrv_qed_init_state(bs);
qemu_co_mutex_lock(&s->table_lock); qemu_co_mutex_lock(&s->table_lock);
@@ -1664,7 +1658,7 @@ static BlockDriver bdrv_qed = {
.bdrv_co_getlength = bdrv_qed_co_getlength, .bdrv_co_getlength = bdrv_qed_co_getlength,
.bdrv_co_get_info = bdrv_qed_co_get_info, .bdrv_co_get_info = bdrv_qed_co_get_info,
.bdrv_refresh_limits = bdrv_qed_refresh_limits, .bdrv_refresh_limits = bdrv_qed_refresh_limits,
.bdrv_co_change_backing_file = bdrv_qed_co_change_backing_file, .bdrv_change_backing_file = bdrv_qed_change_backing_file,
.bdrv_co_invalidate_cache = bdrv_qed_co_invalidate_cache, .bdrv_co_invalidate_cache = bdrv_qed_co_invalidate_cache,
.bdrv_co_check = bdrv_qed_co_check, .bdrv_co_check = bdrv_qed_co_check,
.bdrv_detach_aio_context = bdrv_qed_detach_aio_context, .bdrv_detach_aio_context = bdrv_qed_detach_aio_context,

View File

@@ -185,7 +185,7 @@ enum {
/** /**
* Header functions * Header functions
*/ */
int GRAPH_RDLOCK qed_write_header_sync(BDRVQEDState *s); int qed_write_header_sync(BDRVQEDState *s);
/** /**
* L2 cache functions * L2 cache functions

View File

@@ -95,9 +95,9 @@ end:
return ret; return ret;
} }
static int GRAPH_RDLOCK static int raw_apply_options(BlockDriverState *bs, BDRVRawState *s,
raw_apply_options(BlockDriverState *bs, BDRVRawState *s, uint64_t offset, uint64_t offset, bool has_size, uint64_t size,
bool has_size, uint64_t size, Error **errp) Error **errp)
{ {
int64_t real_size = 0; int64_t real_size = 0;
@@ -145,9 +145,6 @@ static int raw_reopen_prepare(BDRVReopenState *reopen_state,
uint64_t offset, size; uint64_t offset, size;
int ret; int ret;
GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
assert(reopen_state != NULL); assert(reopen_state != NULL);
assert(reopen_state->bs != NULL); assert(reopen_state->bs != NULL);
@@ -282,9 +279,10 @@ fail:
return ret; return ret;
} }
static int coroutine_fn GRAPH_RDLOCK static int coroutine_fn raw_co_block_status(BlockDriverState *bs,
raw_co_block_status(BlockDriverState *bs, bool want_zero, int64_t offset, bool want_zero, int64_t offset,
int64_t bytes, int64_t *pnum, int64_t *map, int64_t bytes, int64_t *pnum,
int64_t *map,
BlockDriverState **file) BlockDriverState **file)
{ {
BDRVRawState *s = bs->opaque; BDRVRawState *s = bs->opaque;
@@ -399,7 +397,7 @@ raw_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
return bdrv_co_get_info(bs->file->bs, bdi); return bdrv_co_get_info(bs->file->bs, bdi);
} }
static void GRAPH_RDLOCK raw_refresh_limits(BlockDriverState *bs, Error **errp) static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
{ {
bs->bl.has_variable_length = bs->file->bs->bl.has_variable_length; bs->bl.has_variable_length = bs->file->bs->bl.has_variable_length;
@@ -454,7 +452,7 @@ raw_co_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
return bdrv_co_ioctl(bs->file->bs, req, buf); return bdrv_co_ioctl(bs->file->bs, req, buf);
} }
static int GRAPH_RDLOCK raw_has_zero_init(BlockDriverState *bs) static int raw_has_zero_init(BlockDriverState *bs)
{ {
return bdrv_has_zero_init(bs->file->bs); return bdrv_has_zero_init(bs->file->bs);
} }
@@ -476,8 +474,6 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
BdrvChildRole file_role; BdrvChildRole file_role;
int ret; int ret;
GLOBAL_STATE_CODE();
ret = raw_read_options(options, &offset, &has_size, &size, errp); ret = raw_read_options(options, &offset, &has_size, &size, errp);
if (ret < 0) { if (ret < 0) {
return ret; return ret;
@@ -495,8 +491,6 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
bdrv_open_child(NULL, options, "file", bs, &child_of_bds, bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
file_role, false, errp); file_role, false, errp);
GRAPH_RDLOCK_GUARD_MAINLOOP();
if (!bs->file) { if (!bs->file) {
return -EINVAL; return -EINVAL;
} }
@@ -511,7 +505,9 @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
BDRV_REQ_ZERO_WRITE; BDRV_REQ_ZERO_WRITE;
if (bs->probed && !bdrv_is_read_only(bs)) { if (bs->probed && !bdrv_is_read_only(bs)) {
bdrv_graph_rdlock_main_loop();
bdrv_refresh_filename(bs->file->bs); bdrv_refresh_filename(bs->file->bs);
bdrv_graph_rdunlock_main_loop();
fprintf(stderr, fprintf(stderr,
"WARNING: Image format was not specified for '%s' and probing " "WARNING: Image format was not specified for '%s' and probing "
"guessed raw.\n" "guessed raw.\n"
@@ -547,8 +543,7 @@ static int raw_probe(const uint8_t *buf, int buf_size, const char *filename)
return 1; return 1;
} }
static int GRAPH_RDLOCK static int raw_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz)
raw_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz)
{ {
BDRVRawState *s = bs->opaque; BDRVRawState *s = bs->opaque;
int ret; int ret;
@@ -565,8 +560,7 @@ raw_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz)
return 0; return 0;
} }
static int GRAPH_RDLOCK static int raw_probe_geometry(BlockDriverState *bs, HDGeometry *geo)
raw_probe_geometry(BlockDriverState *bs, HDGeometry *geo)
{ {
BDRVRawState *s = bs->opaque; BDRVRawState *s = bs->opaque;
if (s->offset || s->has_size) { if (s->offset || s->has_size) {
@@ -616,7 +610,7 @@ static const char *const raw_strong_runtime_opts[] = {
NULL NULL
}; };
static void GRAPH_RDLOCK raw_cancel_in_flight(BlockDriverState *bs) static void raw_cancel_in_flight(BlockDriverState *bs)
{ {
bdrv_cancel_in_flight(bs->file->bs); bdrv_cancel_in_flight(bs->file->bs);
} }

View File

@@ -311,7 +311,7 @@ static void GRAPH_UNLOCKED
secondary_do_checkpoint(BlockDriverState *bs, Error **errp) secondary_do_checkpoint(BlockDriverState *bs, Error **errp)
{ {
BDRVReplicationState *s = bs->opaque; BDRVReplicationState *s = bs->opaque;
BdrvChild *active_disk; BdrvChild *active_disk = bs->file;
Error *local_err = NULL; Error *local_err = NULL;
int ret; int ret;
@@ -328,7 +328,6 @@ secondary_do_checkpoint(BlockDriverState *bs, Error **errp)
return; return;
} }
active_disk = bs->file;
if (!active_disk->bs->drv) { if (!active_disk->bs->drv) {
error_setg(errp, "Active disk %s is ejected", error_setg(errp, "Active disk %s is ejected",
active_disk->bs->node_name); active_disk->bs->node_name);
@@ -364,9 +363,6 @@ static void reopen_backing_file(BlockDriverState *bs, bool writable,
BdrvChild *hidden_disk, *secondary_disk; BdrvChild *hidden_disk, *secondary_disk;
BlockReopenQueue *reopen_queue = NULL; BlockReopenQueue *reopen_queue = NULL;
GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
/* /*
* s->hidden_disk and s->secondary_disk may not be set yet, as they will * s->hidden_disk and s->secondary_disk may not be set yet, as they will
* only be set after the children are writable. * only be set after the children are writable.
@@ -500,11 +496,9 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
case REPLICATION_MODE_PRIMARY: case REPLICATION_MODE_PRIMARY:
break; break;
case REPLICATION_MODE_SECONDARY: case REPLICATION_MODE_SECONDARY:
bdrv_graph_rdlock_main_loop();
active_disk = bs->file; active_disk = bs->file;
if (!active_disk || !active_disk->bs || !active_disk->bs->backing) { if (!active_disk || !active_disk->bs || !active_disk->bs->backing) {
error_setg(errp, "Active disk doesn't have backing file"); error_setg(errp, "Active disk doesn't have backing file");
bdrv_graph_rdunlock_main_loop();
aio_context_release(aio_context); aio_context_release(aio_context);
return; return;
} }
@@ -512,11 +506,11 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
hidden_disk = active_disk->bs->backing; hidden_disk = active_disk->bs->backing;
if (!hidden_disk->bs || !hidden_disk->bs->backing) { if (!hidden_disk->bs || !hidden_disk->bs->backing) {
error_setg(errp, "Hidden disk doesn't have backing file"); error_setg(errp, "Hidden disk doesn't have backing file");
bdrv_graph_rdunlock_main_loop();
aio_context_release(aio_context); aio_context_release(aio_context);
return; return;
} }
bdrv_graph_rdlock_main_loop();
secondary_disk = hidden_disk->bs->backing; secondary_disk = hidden_disk->bs->backing;
if (!secondary_disk->bs || !bdrv_has_blk(secondary_disk->bs)) { if (!secondary_disk->bs || !bdrv_has_blk(secondary_disk->bs)) {
error_setg(errp, "The secondary disk doesn't have block backend"); error_setg(errp, "The secondary disk doesn't have block backend");
@@ -756,13 +750,11 @@ static void replication_stop(ReplicationState *rs, bool failover, Error **errp)
return; return;
} }
bdrv_graph_rdlock_main_loop();
s->stage = BLOCK_REPLICATION_FAILOVER; s->stage = BLOCK_REPLICATION_FAILOVER;
s->commit_job = commit_active_start( s->commit_job = commit_active_start(
NULL, bs->file->bs, s->secondary_disk->bs, NULL, bs->file->bs, s->secondary_disk->bs,
JOB_INTERNAL, 0, BLOCKDEV_ON_ERROR_REPORT, JOB_INTERNAL, 0, BLOCKDEV_ON_ERROR_REPORT,
NULL, replication_done, bs, true, errp); NULL, replication_done, bs, true, errp);
bdrv_graph_rdunlock_main_loop();
break; break;
default: default:
aio_context_release(aio_context); aio_context_release(aio_context);

View File

@@ -73,7 +73,7 @@ snapshot_access_co_pwritev_part(BlockDriverState *bs,
} }
static void GRAPH_RDLOCK snapshot_access_refresh_filename(BlockDriverState *bs) static void snapshot_access_refresh_filename(BlockDriverState *bs)
{ {
pstrcpy(bs->exact_filename, sizeof(bs->exact_filename), pstrcpy(bs->exact_filename, sizeof(bs->exact_filename),
bs->file->bs->filename); bs->file->bs->filename);
@@ -85,9 +85,6 @@ static int snapshot_access_open(BlockDriverState *bs, QDict *options, int flags,
bdrv_open_child(NULL, options, "file", bs, &child_of_bds, bdrv_open_child(NULL, options, "file", bs, &child_of_bds,
BDRV_CHILD_DATA | BDRV_CHILD_PRIMARY, BDRV_CHILD_DATA | BDRV_CHILD_PRIMARY,
false, errp); false, errp);
GRAPH_RDLOCK_GUARD_MAINLOOP();
if (!bs->file) { if (!bs->file) {
return -EINVAL; return -EINVAL;
} }

View File

@@ -53,20 +53,13 @@ static int coroutine_fn stream_populate(BlockBackend *blk,
static int stream_prepare(Job *job) 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; BlockDriverState *unfiltered_bs = bdrv_skip_filters(s->target_bs);
BlockDriverState *unfiltered_bs_cow; BlockDriverState *unfiltered_bs_cow = bdrv_cow_bs(unfiltered_bs);
BlockDriverState *base; BlockDriverState *base;
BlockDriverState *unfiltered_base; BlockDriverState *unfiltered_base;
Error *local_err = NULL; Error *local_err = NULL;
int ret = 0; int ret = 0;
GLOBAL_STATE_CODE();
bdrv_graph_rdlock_main_loop();
unfiltered_bs = bdrv_skip_filters(s->target_bs);
unfiltered_bs_cow = bdrv_cow_bs(unfiltered_bs);
bdrv_graph_rdunlock_main_loop();
/* We should drop filter at this point, as filter hold the backing chain */ /* We should drop filter at this point, as filter hold the backing chain */
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;
@@ -85,12 +78,10 @@ static int stream_prepare(Job *job)
bdrv_drained_begin(unfiltered_bs_cow); bdrv_drained_begin(unfiltered_bs_cow);
} }
bdrv_graph_rdlock_main_loop();
base = bdrv_filter_or_cow_bs(s->above_base); base = bdrv_filter_or_cow_bs(s->above_base);
unfiltered_base = bdrv_skip_filters(base); unfiltered_base = bdrv_skip_filters(base);
bdrv_graph_rdunlock_main_loop();
if (unfiltered_bs_cow) { 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) {
base_id = s->backing_file_str ?: unfiltered_base->filename; base_id = s->backing_file_str ?: unfiltered_base->filename;
@@ -99,9 +90,7 @@ static int stream_prepare(Job *job)
} }
} }
bdrv_graph_wrlock(base);
bdrv_set_backing_hd_drained(unfiltered_bs, base, &local_err); bdrv_set_backing_hd_drained(unfiltered_bs, base, &local_err);
bdrv_graph_wrunlock();
/* /*
* This call will do I/O, so the graph can change again from here on. * This call will do I/O, so the graph can change again from here on.
@@ -149,19 +138,18 @@ static void stream_clean(Job *job)
static int coroutine_fn stream_run(Job *job, Error **errp) static int coroutine_fn stream_run(Job *job, Error **errp)
{ {
StreamBlockJob *s = container_of(job, StreamBlockJob, common.job); StreamBlockJob *s = container_of(job, StreamBlockJob, common.job);
BlockDriverState *unfiltered_bs; BlockDriverState *unfiltered_bs = bdrv_skip_filters(s->target_bs);
int64_t len; int64_t len;
int64_t offset = 0; int64_t offset = 0;
int error = 0; int error = 0;
int64_t n = 0; /* bytes */ int64_t n = 0; /* bytes */
WITH_GRAPH_RDLOCK_GUARD() {
unfiltered_bs = bdrv_skip_filters(s->target_bs);
if (unfiltered_bs == s->base_overlay) { if (unfiltered_bs == s->base_overlay) {
/* Nothing to stream */ /* Nothing to stream */
return 0; return 0;
} }
WITH_GRAPH_RDLOCK_GUARD() {
len = bdrv_co_getlength(s->target_bs); len = bdrv_co_getlength(s->target_bs);
if (len < 0) { if (len < 0) {
return len; return len;
@@ -268,8 +256,6 @@ void stream_start(const char *job_id, BlockDriverState *bs,
assert(!(base && bottom)); assert(!(base && bottom));
assert(!(backing_file_str && bottom)); assert(!(backing_file_str && bottom));
bdrv_graph_rdlock_main_loop();
if (bottom) { if (bottom) {
/* /*
* New simple interface. The code is written in terms of old interface * New simple interface. The code is written in terms of old interface
@@ -286,7 +272,7 @@ void stream_start(const char *job_id, BlockDriverState *bs,
if (!base_overlay) { if (!base_overlay) {
error_setg(errp, "'%s' is not in the backing chain of '%s'", error_setg(errp, "'%s' is not in the backing chain of '%s'",
base->node_name, bs->node_name); base->node_name, bs->node_name);
goto out_rdlock; return;
} }
/* /*
@@ -308,7 +294,7 @@ void stream_start(const char *job_id, BlockDriverState *bs,
if (bs_read_only) { if (bs_read_only) {
/* Hold the chain during reopen */ /* Hold the chain during reopen */
if (bdrv_freeze_backing_chain(bs, above_base, errp) < 0) { if (bdrv_freeze_backing_chain(bs, above_base, errp) < 0) {
goto out_rdlock; return;
} }
ret = bdrv_reopen_set_read_only(bs, false, errp); ret = bdrv_reopen_set_read_only(bs, false, errp);
@@ -317,12 +303,10 @@ void stream_start(const char *job_id, BlockDriverState *bs,
bdrv_unfreeze_backing_chain(bs, above_base); bdrv_unfreeze_backing_chain(bs, above_base);
if (ret < 0) { if (ret < 0) {
goto out_rdlock; return;
} }
} }
bdrv_graph_rdunlock_main_loop();
opts = qdict_new(); opts = qdict_new();
qdict_put_str(opts, "driver", "copy-on-read"); qdict_put_str(opts, "driver", "copy-on-read");
@@ -366,10 +350,8 @@ void stream_start(const char *job_id, BlockDriverState *bs,
* already have our own plans. Also don't allow resize as the image size is * already have our own plans. Also don't allow resize as the image size is
* queried only at the job start and then cached. * queried only at the job start and then cached.
*/ */
bdrv_graph_wrlock(bs);
if (block_job_add_bdrv(&s->common, "active node", bs, 0, if (block_job_add_bdrv(&s->common, "active node", bs, 0,
basic_flags | BLK_PERM_WRITE, errp)) { basic_flags | BLK_PERM_WRITE, errp)) {
bdrv_graph_wrunlock();
goto fail; goto fail;
} }
@@ -389,11 +371,9 @@ void stream_start(const char *job_id, BlockDriverState *bs,
ret = block_job_add_bdrv(&s->common, "intermediate node", iter, 0, ret = block_job_add_bdrv(&s->common, "intermediate node", iter, 0,
basic_flags, errp); basic_flags, errp);
if (ret < 0) { if (ret < 0) {
bdrv_graph_wrunlock();
goto fail; goto fail;
} }
} }
bdrv_graph_wrunlock();
s->base_overlay = base_overlay; s->base_overlay = base_overlay;
s->above_base = above_base; s->above_base = above_base;
@@ -417,8 +397,4 @@ fail:
if (bs_read_only) { if (bs_read_only) {
bdrv_reopen_set_read_only(bs, true, NULL); bdrv_reopen_set_read_only(bs, true, NULL);
} }
return;
out_rdlock:
bdrv_graph_rdunlock_main_loop();
} }

View File

@@ -84,9 +84,6 @@ static int throttle_open(BlockDriverState *bs, QDict *options,
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
GRAPH_RDLOCK_GUARD_MAINLOOP();
bs->supported_write_flags = bs->file->bs->supported_write_flags | bs->supported_write_flags = bs->file->bs->supported_write_flags |
BDRV_REQ_WRITE_UNCHANGED; BDRV_REQ_WRITE_UNCHANGED;
bs->supported_zero_flags = bs->file->bs->supported_zero_flags | bs->supported_zero_flags = bs->file->bs->supported_zero_flags |

View File

@@ -239,7 +239,7 @@ static void vdi_header_to_le(VdiHeader *header)
static void vdi_header_print(VdiHeader *header) static void vdi_header_print(VdiHeader *header)
{ {
char uuidstr[UUID_STR_LEN]; char uuidstr[37];
QemuUUID uuid; QemuUUID uuid;
logout("text %s", header->text); logout("text %s", header->text);
logout("signature 0x%08x\n", header->signature); logout("signature 0x%08x\n", header->signature);
@@ -383,8 +383,6 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
return ret; return ret;
} }
GRAPH_RDLOCK_GUARD_MAINLOOP();
logout("\n"); logout("\n");
ret = bdrv_pread(bs->file, 0, sizeof(header), &header, 0); ret = bdrv_pread(bs->file, 0, sizeof(header), &header, 0);
@@ -494,12 +492,15 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
} }
/* Disable migration when vdi images are used */ /* Disable migration when vdi images are used */
bdrv_graph_rdlock_main_loop();
error_setg(&s->migration_blocker, "The vdi format used by node '%s' " error_setg(&s->migration_blocker, "The vdi format used by node '%s' "
"does not support live migration", "does not support live migration",
bdrv_get_device_or_node_name(bs)); bdrv_get_device_or_node_name(bs));
bdrv_graph_rdunlock_main_loop();
ret = migrate_add_blocker_normal(&s->migration_blocker, errp); ret = migrate_add_blocker(s->migration_blocker, errp);
if (ret < 0) { if (ret < 0) {
error_free(s->migration_blocker);
goto fail_free_bmap; goto fail_free_bmap;
} }
@@ -520,9 +521,10 @@ static int vdi_reopen_prepare(BDRVReopenState *state,
return 0; return 0;
} }
static int coroutine_fn GRAPH_RDLOCK static int coroutine_fn vdi_co_block_status(BlockDriverState *bs,
vdi_co_block_status(BlockDriverState *bs, bool want_zero, int64_t offset, bool want_zero,
int64_t bytes, int64_t *pnum, int64_t *map, int64_t offset, int64_t bytes,
int64_t *pnum, int64_t *map,
BlockDriverState **file) BlockDriverState **file)
{ {
BDRVVdiState *s = (BDRVVdiState *)bs->opaque; BDRVVdiState *s = (BDRVVdiState *)bs->opaque;
@@ -986,10 +988,11 @@ static void vdi_close(BlockDriverState *bs)
qemu_vfree(s->bmap); qemu_vfree(s->bmap);
migrate_del_blocker(&s->migration_blocker); migrate_del_blocker(s->migration_blocker);
error_free(s->migration_blocker);
} }
static int GRAPH_RDLOCK vdi_has_zero_init(BlockDriverState *bs) static int vdi_has_zero_init(BlockDriverState *bs)
{ {
BDRVVdiState *s = bs->opaque; BDRVVdiState *s = bs->opaque;

View File

@@ -55,8 +55,7 @@ static const MSGUID zero_guid = { 0 };
/* Allow peeking at the hdr entry at the beginning of the current /* Allow peeking at the hdr entry at the beginning of the current
* read index, without advancing the read index */ * read index, without advancing the read index */
static int GRAPH_RDLOCK static int vhdx_log_peek_hdr(BlockDriverState *bs, VHDXLogEntries *log,
vhdx_log_peek_hdr(BlockDriverState *bs, VHDXLogEntries *log,
VHDXLogEntryHeader *hdr) VHDXLogEntryHeader *hdr)
{ {
int ret = 0; int ret = 0;
@@ -108,7 +107,7 @@ static int vhdx_log_inc_idx(uint32_t idx, uint64_t length)
/* Reset the log to empty */ /* Reset the log to empty */
static void GRAPH_RDLOCK vhdx_log_reset(BlockDriverState *bs, BDRVVHDXState *s) static void vhdx_log_reset(BlockDriverState *bs, BDRVVHDXState *s)
{ {
MSGUID guid = { 0 }; MSGUID guid = { 0 };
s->log.read = s->log.write = 0; s->log.read = s->log.write = 0;
@@ -128,8 +127,7 @@ static void GRAPH_RDLOCK vhdx_log_reset(BlockDriverState *bs, BDRVVHDXState *s)
* not modified. * not modified.
* *
* 0 is returned on success, -errno otherwise. */ * 0 is returned on success, -errno otherwise. */
static int GRAPH_RDLOCK static int vhdx_log_read_sectors(BlockDriverState *bs, VHDXLogEntries *log,
vhdx_log_read_sectors(BlockDriverState *bs, VHDXLogEntries *log,
uint32_t *sectors_read, void *buffer, uint32_t *sectors_read, void *buffer,
uint32_t num_sectors, bool peek) uint32_t num_sectors, bool peek)
{ {
@@ -335,9 +333,9 @@ static int vhdx_compute_desc_sectors(uint32_t desc_cnt)
* will allocate all the space for buffer, which must be NULL when * will allocate all the space for buffer, which must be NULL when
* passed into this function. Each descriptor will also be validated, * passed into this function. Each descriptor will also be validated,
* and error returned if any are invalid. */ * and error returned if any are invalid. */
static int GRAPH_RDLOCK static int vhdx_log_read_desc(BlockDriverState *bs, BDRVVHDXState *s,
vhdx_log_read_desc(BlockDriverState *bs, BDRVVHDXState *s, VHDXLogEntries *log, VHDXLogEntries *log, VHDXLogDescEntries **buffer,
VHDXLogDescEntries **buffer, bool convert_endian) bool convert_endian)
{ {
int ret = 0; int ret = 0;
uint32_t desc_sectors; uint32_t desc_sectors;
@@ -414,8 +412,7 @@ exit:
* For a zero descriptor, it may describe multiple sectors to fill with zeroes. * For a zero descriptor, it may describe multiple sectors to fill with zeroes.
* In this case, it should be noted that zeroes are written to disk, and the * In this case, it should be noted that zeroes are written to disk, and the
* image file is not extended as a sparse file. */ * image file is not extended as a sparse file. */
static int GRAPH_RDLOCK static int vhdx_log_flush_desc(BlockDriverState *bs, VHDXLogDescriptor *desc,
vhdx_log_flush_desc(BlockDriverState *bs, VHDXLogDescriptor *desc,
VHDXLogDataSector *data) VHDXLogDataSector *data)
{ {
int ret = 0; int ret = 0;
@@ -487,8 +484,8 @@ exit:
* file, and then set the log to 'empty' status once complete. * file, and then set the log to 'empty' status once complete.
* *
* The log entries should be validate prior to flushing */ * The log entries should be validate prior to flushing */
static int GRAPH_RDLOCK static int vhdx_log_flush(BlockDriverState *bs, BDRVVHDXState *s,
vhdx_log_flush(BlockDriverState *bs, BDRVVHDXState *s, VHDXLogSequence *logs) VHDXLogSequence *logs)
{ {
int ret = 0; int ret = 0;
int i; int i;
@@ -587,8 +584,7 @@ exit:
return ret; return ret;
} }
static int GRAPH_RDLOCK static int vhdx_validate_log_entry(BlockDriverState *bs, BDRVVHDXState *s,
vhdx_validate_log_entry(BlockDriverState *bs, BDRVVHDXState *s,
VHDXLogEntries *log, uint64_t seq, VHDXLogEntries *log, uint64_t seq,
bool *valid, VHDXLogEntryHeader *entry) bool *valid, VHDXLogEntryHeader *entry)
{ {
@@ -667,8 +663,8 @@ free_and_exit:
/* Search through the log circular buffer, and find the valid, active /* Search through the log circular buffer, and find the valid, active
* log sequence, if any exists * log sequence, if any exists
* */ * */
static int GRAPH_RDLOCK static int vhdx_log_search(BlockDriverState *bs, BDRVVHDXState *s,
vhdx_log_search(BlockDriverState *bs, BDRVVHDXState *s, VHDXLogSequence *logs) VHDXLogSequence *logs)
{ {
int ret = 0; int ret = 0;
uint32_t tail; uint32_t tail;

View File

@@ -353,8 +353,7 @@ exit:
* *
* - non-current header is updated with largest sequence number * - non-current header is updated with largest sequence number
*/ */
static int GRAPH_RDLOCK static int vhdx_update_header(BlockDriverState *bs, BDRVVHDXState *s,
vhdx_update_header(BlockDriverState *bs, BDRVVHDXState *s,
bool generate_data_write_guid, MSGUID *log_guid) bool generate_data_write_guid, MSGUID *log_guid)
{ {
int ret = 0; int ret = 0;
@@ -417,8 +416,8 @@ int vhdx_update_headers(BlockDriverState *bs, BDRVVHDXState *s,
} }
/* opens the specified header block from the VHDX file header section */ /* opens the specified header block from the VHDX file header section */
static void GRAPH_RDLOCK static void vhdx_parse_header(BlockDriverState *bs, BDRVVHDXState *s,
vhdx_parse_header(BlockDriverState *bs, BDRVVHDXState *s, Error **errp) Error **errp)
{ {
int ret; int ret;
VHDXHeader *header1; VHDXHeader *header1;
@@ -518,8 +517,7 @@ exit:
} }
static int GRAPH_RDLOCK static int vhdx_open_region_tables(BlockDriverState *bs, BDRVVHDXState *s)
vhdx_open_region_tables(BlockDriverState *bs, BDRVVHDXState *s)
{ {
int ret = 0; int ret = 0;
uint8_t *buffer; uint8_t *buffer;
@@ -636,8 +634,7 @@ fail:
* Also, if the File Parameters indicate this is a differencing file, * Also, if the File Parameters indicate this is a differencing file,
* we must also look for the Parent Locator metadata item. * we must also look for the Parent Locator metadata item.
*/ */
static int GRAPH_RDLOCK static int vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s)
vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s)
{ {
int ret = 0; int ret = 0;
uint8_t *buffer; uint8_t *buffer;
@@ -888,8 +885,7 @@ static void vhdx_calc_bat_entries(BDRVVHDXState *s)
} }
static int coroutine_mixed_fn GRAPH_RDLOCK static int vhdx_check_bat_entries(BlockDriverState *bs, int *errcnt)
vhdx_check_bat_entries(BlockDriverState *bs, int *errcnt)
{ {
BDRVVHDXState *s = bs->opaque; BDRVVHDXState *s = bs->opaque;
int64_t image_file_size = bdrv_getlength(bs->file->bs); int64_t image_file_size = bdrv_getlength(bs->file->bs);
@@ -989,7 +985,8 @@ static void vhdx_close(BlockDriverState *bs)
s->bat = NULL; s->bat = NULL;
qemu_vfree(s->parent_entries); qemu_vfree(s->parent_entries);
s->parent_entries = NULL; s->parent_entries = NULL;
migrate_del_blocker(&s->migration_blocker); migrate_del_blocker(s->migration_blocker);
error_free(s->migration_blocker);
qemu_vfree(s->log.hdr); qemu_vfree(s->log.hdr);
s->log.hdr = NULL; s->log.hdr = NULL;
vhdx_region_unregister_all(s); vhdx_region_unregister_all(s);
@@ -1100,8 +1097,9 @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags,
error_setg(&s->migration_blocker, "The vhdx format used by node '%s' " error_setg(&s->migration_blocker, "The vhdx format used by node '%s' "
"does not support live migration", "does not support live migration",
bdrv_get_device_or_node_name(bs)); bdrv_get_device_or_node_name(bs));
ret = migrate_add_blocker_normal(&s->migration_blocker, errp); ret = migrate_add_blocker(s->migration_blocker, errp);
if (ret < 0) { if (ret < 0) {
error_free(s->migration_blocker);
goto fail; goto fail;
} }
@@ -1699,7 +1697,7 @@ exit:
* Fixed images: default state of the BAT is fully populated, with * Fixed images: default state of the BAT is fully populated, with
* file offsets and state PAYLOAD_BLOCK_FULLY_PRESENT. * file offsets and state PAYLOAD_BLOCK_FULLY_PRESENT.
*/ */
static int coroutine_fn GRAPH_UNLOCKED static int coroutine_fn
vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s, vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s,
uint64_t image_size, VHDXImageType type, uint64_t image_size, VHDXImageType type,
bool use_zero_blocks, uint64_t file_offset, bool use_zero_blocks, uint64_t file_offset,
@@ -1712,7 +1710,6 @@ vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s,
uint64_t unused; uint64_t unused;
int block_state; int block_state;
VHDXSectorInfo sinfo; VHDXSectorInfo sinfo;
bool has_zero_init;
assert(s->bat == NULL); assert(s->bat == NULL);
@@ -1742,13 +1739,9 @@ vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s,
goto exit; goto exit;
} }
bdrv_graph_co_rdlock();
has_zero_init = bdrv_has_zero_init(blk_bs(blk));
bdrv_graph_co_rdunlock();
if (type == VHDX_TYPE_FIXED || if (type == VHDX_TYPE_FIXED ||
use_zero_blocks || use_zero_blocks ||
has_zero_init == 0) { bdrv_has_zero_init(blk_bs(blk)) == 0) {
/* for a fixed file, the default BAT entry is not zero */ /* for a fixed file, the default BAT entry is not zero */
s->bat = g_try_malloc0(length); s->bat = g_try_malloc0(length);
if (length && s->bat == NULL) { if (length && s->bat == NULL) {
@@ -1791,7 +1784,7 @@ exit:
* to create the BAT itself, we will also cause the BAT to be * to create the BAT itself, we will also cause the BAT to be
* created. * created.
*/ */
static int coroutine_fn GRAPH_UNLOCKED static int coroutine_fn
vhdx_create_new_region_table(BlockBackend *blk, uint64_t image_size, vhdx_create_new_region_table(BlockBackend *blk, uint64_t image_size,
uint32_t block_size, uint32_t sector_size, uint32_t block_size, uint32_t sector_size,
uint32_t log_size, bool use_zero_blocks, uint32_t log_size, bool use_zero_blocks,
@@ -2167,8 +2160,8 @@ fail:
* r/w and any log has already been replayed, so there is nothing (currently) * r/w and any log has already been replayed, so there is nothing (currently)
* for us to do here * for us to do here
*/ */
static int coroutine_fn GRAPH_RDLOCK static int coroutine_fn vhdx_co_check(BlockDriverState *bs,
vhdx_co_check(BlockDriverState *bs, BdrvCheckResult *result, BdrvCheckResult *result,
BdrvCheckMode fix) BdrvCheckMode fix)
{ {
BDRVVHDXState *s = bs->opaque; BDRVVHDXState *s = bs->opaque;
@@ -2182,7 +2175,7 @@ vhdx_co_check(BlockDriverState *bs, BdrvCheckResult *result,
return 0; return 0;
} }
static int GRAPH_RDLOCK vhdx_has_zero_init(BlockDriverState *bs) static int vhdx_has_zero_init(BlockDriverState *bs)
{ {
BDRVVHDXState *s = bs->opaque; BDRVVHDXState *s = bs->opaque;
int state; int state;

View File

@@ -401,8 +401,7 @@ typedef struct BDRVVHDXState {
void vhdx_guid_generate(MSGUID *guid); void vhdx_guid_generate(MSGUID *guid);
int GRAPH_RDLOCK int vhdx_update_headers(BlockDriverState *bs, BDRVVHDXState *s, bool rw,
vhdx_update_headers(BlockDriverState *bs, BDRVVHDXState *s, bool rw,
MSGUID *log_guid); MSGUID *log_guid);
uint32_t vhdx_update_checksum(uint8_t *buf, size_t size, int crc_offset); uint32_t vhdx_update_checksum(uint8_t *buf, size_t size, int crc_offset);
@@ -449,8 +448,6 @@ void vhdx_metadata_header_le_import(VHDXMetadataTableHeader *hdr);
void vhdx_metadata_header_le_export(VHDXMetadataTableHeader *hdr); void vhdx_metadata_header_le_export(VHDXMetadataTableHeader *hdr);
void vhdx_metadata_entry_le_import(VHDXMetadataTableEntry *e); void vhdx_metadata_entry_le_import(VHDXMetadataTableEntry *e);
void vhdx_metadata_entry_le_export(VHDXMetadataTableEntry *e); void vhdx_metadata_entry_le_export(VHDXMetadataTableEntry *e);
int vhdx_user_visible_write(BlockDriverState *bs, BDRVVHDXState *s);
int GRAPH_RDLOCK
vhdx_user_visible_write(BlockDriverState *bs, BDRVVHDXState *s);
#endif #endif

View File

@@ -300,8 +300,7 @@ static void vmdk_free_last_extent(BlockDriverState *bs)
} }
/* Return -ve errno, or 0 on success and write CID into *pcid. */ /* Return -ve errno, or 0 on success and write CID into *pcid. */
static int GRAPH_RDLOCK static int vmdk_read_cid(BlockDriverState *bs, int parent, uint32_t *pcid)
vmdk_read_cid(BlockDriverState *bs, int parent, uint32_t *pcid)
{ {
char *desc; char *desc;
uint32_t cid; uint32_t cid;
@@ -381,7 +380,7 @@ out:
return ret; return ret;
} }
static int coroutine_fn GRAPH_RDLOCK vmdk_is_cid_valid(BlockDriverState *bs) static int coroutine_fn vmdk_is_cid_valid(BlockDriverState *bs)
{ {
BDRVVmdkState *s = bs->opaque; BDRVVmdkState *s = bs->opaque;
uint32_t cur_pcid; uint32_t cur_pcid;
@@ -416,9 +415,6 @@ static int vmdk_reopen_prepare(BDRVReopenState *state,
BDRVVmdkReopenState *rs; BDRVVmdkReopenState *rs;
int i; int i;
GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
assert(state != NULL); assert(state != NULL);
assert(state->bs != NULL); assert(state->bs != NULL);
assert(state->opaque == NULL); assert(state->opaque == NULL);
@@ -455,9 +451,6 @@ static void vmdk_reopen_commit(BDRVReopenState *state)
BDRVVmdkReopenState *rs = state->opaque; BDRVVmdkReopenState *rs = state->opaque;
int i; int i;
GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
for (i = 0; i < s->num_extents; i++) { for (i = 0; i < s->num_extents; i++) {
if (rs->extents_using_bs_file[i]) { if (rs->extents_using_bs_file[i]) {
s->extents[i].file = state->bs->file; s->extents[i].file = state->bs->file;
@@ -472,7 +465,7 @@ static void vmdk_reopen_abort(BDRVReopenState *state)
vmdk_reopen_clean(state); vmdk_reopen_clean(state);
} }
static int GRAPH_RDLOCK vmdk_parent_open(BlockDriverState *bs) static int vmdk_parent_open(BlockDriverState *bs)
{ {
char *p_name; char *p_name;
char *desc; char *desc;
@@ -1393,8 +1386,9 @@ static int vmdk_open(BlockDriverState *bs, QDict *options, int flags,
error_setg(&s->migration_blocker, "The vmdk format used by node '%s' " error_setg(&s->migration_blocker, "The vmdk format used by node '%s' "
"does not support live migration", "does not support live migration",
bdrv_get_device_or_node_name(bs)); bdrv_get_device_or_node_name(bs));
ret = migrate_add_blocker_normal(&s->migration_blocker, errp); ret = migrate_add_blocker(s->migration_blocker, errp);
if (ret < 0) { if (ret < 0) {
error_free(s->migration_blocker);
goto fail; goto fail;
} }
@@ -2554,10 +2548,7 @@ vmdk_co_do_create(int64_t size,
ret = -EINVAL; ret = -EINVAL;
goto exit; goto exit;
} }
bdrv_graph_co_rdlock();
ret = vmdk_read_cid(blk_bs(backing), 0, &parent_cid); ret = vmdk_read_cid(blk_bs(backing), 0, &parent_cid);
bdrv_graph_co_rdunlock();
blk_co_unref(backing); blk_co_unref(backing);
if (ret) { if (ret) {
error_setg(errp, "Failed to read parent CID"); error_setg(errp, "Failed to read parent CID");
@@ -2876,7 +2867,8 @@ static void vmdk_close(BlockDriverState *bs)
vmdk_free_extents(bs); vmdk_free_extents(bs);
g_free(s->create_type); g_free(s->create_type);
migrate_del_blocker(&s->migration_blocker); migrate_del_blocker(s->migration_blocker);
error_free(s->migration_blocker);
} }
static int64_t coroutine_fn GRAPH_RDLOCK static int64_t coroutine_fn GRAPH_RDLOCK
@@ -2904,7 +2896,7 @@ vmdk_co_get_allocated_file_size(BlockDriverState *bs)
return ret; return ret;
} }
static int GRAPH_RDLOCK vmdk_has_zero_init(BlockDriverState *bs) static int vmdk_has_zero_init(BlockDriverState *bs)
{ {
int i; int i;
BDRVVmdkState *s = bs->opaque; BDRVVmdkState *s = bs->opaque;
@@ -3054,8 +3046,7 @@ vmdk_co_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
return 0; return 0;
} }
static void GRAPH_RDLOCK static void vmdk_gather_child_options(BlockDriverState *bs, QDict *target,
vmdk_gather_child_options(BlockDriverState *bs, QDict *target,
bool backing_overridden) bool backing_overridden)
{ {
/* No children but file and backing can be explicitly specified (TODO) */ /* No children but file and backing can be explicitly specified (TODO) */

View File

@@ -238,8 +238,6 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
return ret; return ret;
} }
GRAPH_RDLOCK_GUARD_MAINLOOP();
opts = qemu_opts_create(&vpc_runtime_opts, NULL, 0, &error_abort); opts = qemu_opts_create(&vpc_runtime_opts, NULL, 0, &error_abort);
if (!qemu_opts_absorb_qdict(opts, options, errp)) { if (!qemu_opts_absorb_qdict(opts, options, errp)) {
ret = -EINVAL; ret = -EINVAL;
@@ -448,12 +446,15 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
} }
/* Disable migration when VHD images are used */ /* Disable migration when VHD images are used */
bdrv_graph_rdlock_main_loop();
error_setg(&s->migration_blocker, "The vpc format used by node '%s' " error_setg(&s->migration_blocker, "The vpc format used by node '%s' "
"does not support live migration", "does not support live migration",
bdrv_get_device_or_node_name(bs)); bdrv_get_device_or_node_name(bs));
bdrv_graph_rdunlock_main_loop();
ret = migrate_add_blocker_normal(&s->migration_blocker, errp); ret = migrate_add_blocker(s->migration_blocker, errp);
if (ret < 0) { if (ret < 0) {
error_free(s->migration_blocker);
goto fail; goto fail;
} }
@@ -1170,7 +1171,7 @@ fail:
} }
static int GRAPH_RDLOCK vpc_has_zero_init(BlockDriverState *bs) static int vpc_has_zero_init(BlockDriverState *bs)
{ {
BDRVVPCState *s = bs->opaque; BDRVVPCState *s = bs->opaque;
@@ -1189,7 +1190,8 @@ static void vpc_close(BlockDriverState *bs)
g_free(s->pageentry_u8); g_free(s->pageentry_u8);
#endif #endif
migrate_del_blocker(&s->migration_blocker); migrate_del_blocker(s->migration_blocker);
error_free(s->migration_blocker);
} }
static QemuOptsList vpc_create_opts = { static QemuOptsList vpc_create_opts = {

View File

@@ -1268,8 +1268,9 @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
"The vvfat (rw) format used by node '%s' " "The vvfat (rw) format used by node '%s' "
"does not support live migration", "does not support live migration",
bdrv_get_device_or_node_name(bs)); bdrv_get_device_or_node_name(bs));
ret = migrate_add_blocker_normal(&s->migration_blocker, errp); ret = migrate_add_blocker(s->migration_blocker, errp);
if (ret < 0) { if (ret < 0) {
error_free(s->migration_blocker);
goto fail; goto fail;
} }
} }
@@ -3238,7 +3239,8 @@ static void vvfat_close(BlockDriverState *bs)
g_free(s->cluster_buffer); g_free(s->cluster_buffer);
if (s->qcow) { if (s->qcow) {
migrate_del_blocker(&s->migration_blocker); migrate_del_blocker(s->migration_blocker);
error_free(s->migration_blocker);
} }
} }

View File

@@ -255,13 +255,13 @@ void drive_check_orphaned(void)
* Ignore default drives, because we create certain default * Ignore default drives, because we create certain default
* drives unconditionally, then leave them unclaimed. Not the * drives unconditionally, then leave them unclaimed. Not the
* users fault. * users fault.
* Ignore IF_VIRTIO or IF_XEN, because it gets desugared into * Ignore IF_VIRTIO, because it gets desugared into -device,
* -device, so we can leave failing to -device. * so we can leave failing to -device.
* Ignore IF_NONE, because leaving unclaimed IF_NONE remains * Ignore IF_NONE, because leaving unclaimed IF_NONE remains
* available for device_add is a feature. * available for device_add is a feature.
*/ */
if (dinfo->is_default || dinfo->type == IF_VIRTIO if (dinfo->is_default || dinfo->type == IF_VIRTIO
|| dinfo->type == IF_XEN || dinfo->type == IF_NONE) { || dinfo->type == IF_NONE) {
continue; continue;
} }
if (!blk_get_attached_dev(blk)) { if (!blk_get_attached_dev(blk)) {
@@ -977,15 +977,6 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type,
qemu_opt_set(devopts, "driver", "virtio-blk", &error_abort); qemu_opt_set(devopts, "driver", "virtio-blk", &error_abort);
qemu_opt_set(devopts, "drive", qdict_get_str(bs_opts, "id"), qemu_opt_set(devopts, "drive", qdict_get_str(bs_opts, "id"),
&error_abort); &error_abort);
} else if (type == IF_XEN) {
QemuOpts *devopts;
devopts = qemu_opts_create(qemu_find_opts("device"), NULL, 0,
&error_abort);
qemu_opt_set(devopts, "driver",
(media == MEDIA_CDROM) ? "xen-cdrom" : "xen-disk",
&error_abort);
qemu_opt_set(devopts, "drive", qdict_get_str(bs_opts, "id"),
&error_abort);
} }
filename = qemu_opt_get(legacy_opts, "file"); filename = qemu_opt_get(legacy_opts, "file");
@@ -1610,12 +1601,7 @@ static void external_snapshot_abort(void *opaque)
aio_context_acquire(aio_context); aio_context_acquire(aio_context);
} }
bdrv_drained_begin(state->new_bs);
bdrv_graph_wrlock(state->old_bs);
bdrv_replace_node(state->new_bs, state->old_bs, &error_abort); bdrv_replace_node(state->new_bs, state->old_bs, &error_abort);
bdrv_graph_wrunlock();
bdrv_drained_end(state->new_bs);
bdrv_unref(state->old_bs); /* bdrv_replace_node() ref'ed old_bs */ bdrv_unref(state->old_bs); /* bdrv_replace_node() ref'ed old_bs */
aio_context_release(aio_context); aio_context_release(aio_context);
@@ -1715,6 +1701,7 @@ static void drive_backup_action(DriveBackup *backup,
bdrv_graph_rdunlock_main_loop(); bdrv_graph_rdunlock_main_loop();
goto out; goto out;
} }
bdrv_graph_rdunlock_main_loop();
flags = bs->open_flags | BDRV_O_RDWR; flags = bs->open_flags | BDRV_O_RDWR;
@@ -1739,7 +1726,6 @@ static void drive_backup_action(DriveBackup *backup,
flags |= BDRV_O_NO_BACKING; flags |= BDRV_O_NO_BACKING;
set_backing_hd = true; set_backing_hd = true;
} }
bdrv_graph_rdunlock_main_loop();
size = bdrv_getlength(bs); size = bdrv_getlength(bs);
if (size < 0) { if (size < 0) {
@@ -1751,10 +1737,10 @@ static void drive_backup_action(DriveBackup *backup,
assert(format); assert(format);
if (source) { if (source) {
/* Implicit filters should not appear in the filename */ /* Implicit filters should not appear in the filename */
BlockDriverState *explicit_backing; BlockDriverState *explicit_backing =
bdrv_skip_implicit_filters(source);
bdrv_graph_rdlock_main_loop(); bdrv_graph_rdlock_main_loop();
explicit_backing = bdrv_skip_implicit_filters(source);
bdrv_refresh_filename(explicit_backing); bdrv_refresh_filename(explicit_backing);
bdrv_graph_rdunlock_main_loop(); bdrv_graph_rdunlock_main_loop();
@@ -2455,12 +2441,11 @@ void qmp_block_stream(const char *job_id, const char *device,
aio_context = bdrv_get_aio_context(bs); aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context); aio_context_acquire(aio_context);
bdrv_graph_rdlock_main_loop();
if (base) { if (base) {
base_bs = bdrv_find_backing_image(bs, base); base_bs = bdrv_find_backing_image(bs, base);
if (base_bs == NULL) { if (base_bs == NULL) {
error_setg(errp, "Can't find '%s' in the backing chain", base); error_setg(errp, "Can't find '%s' in the backing chain", base);
goto out_rdlock; goto out;
} }
assert(bdrv_get_aio_context(base_bs) == aio_context); assert(bdrv_get_aio_context(base_bs) == aio_context);
} }
@@ -2468,36 +2453,38 @@ void qmp_block_stream(const char *job_id, const char *device,
if (base_node) { if (base_node) {
base_bs = bdrv_lookup_bs(NULL, base_node, errp); base_bs = bdrv_lookup_bs(NULL, base_node, errp);
if (!base_bs) { if (!base_bs) {
goto out_rdlock; goto out;
} }
if (bs == base_bs || !bdrv_chain_contains(bs, base_bs)) { if (bs == base_bs || !bdrv_chain_contains(bs, base_bs)) {
error_setg(errp, "Node '%s' is not a backing image of '%s'", error_setg(errp, "Node '%s' is not a backing image of '%s'",
base_node, device); base_node, device);
goto out_rdlock; goto out;
} }
assert(bdrv_get_aio_context(base_bs) == aio_context); assert(bdrv_get_aio_context(base_bs) == aio_context);
bdrv_graph_rdlock_main_loop();
bdrv_refresh_filename(base_bs); bdrv_refresh_filename(base_bs);
bdrv_graph_rdunlock_main_loop();
} }
if (bottom) { if (bottom) {
bottom_bs = bdrv_lookup_bs(NULL, bottom, errp); bottom_bs = bdrv_lookup_bs(NULL, bottom, errp);
if (!bottom_bs) { if (!bottom_bs) {
goto out_rdlock; goto out;
} }
if (!bottom_bs->drv) { if (!bottom_bs->drv) {
error_setg(errp, "Node '%s' is not open", bottom); error_setg(errp, "Node '%s' is not open", bottom);
goto out_rdlock; goto out;
} }
if (bottom_bs->drv->is_filter) { if (bottom_bs->drv->is_filter) {
error_setg(errp, "Node '%s' is a filter, use a non-filter node " error_setg(errp, "Node '%s' is a filter, use a non-filter node "
"as 'bottom'", bottom); "as 'bottom'", bottom);
goto out_rdlock; goto out;
} }
if (!bdrv_chain_contains(bs, bottom_bs)) { if (!bdrv_chain_contains(bs, bottom_bs)) {
error_setg(errp, "Node '%s' is not in a chain starting from '%s'", error_setg(errp, "Node '%s' is not in a chain starting from '%s'",
bottom, device); bottom, device);
goto out_rdlock; goto out;
} }
assert(bdrv_get_aio_context(bottom_bs) == aio_context); assert(bdrv_get_aio_context(bottom_bs) == aio_context);
} }
@@ -2506,11 +2493,13 @@ void qmp_block_stream(const char *job_id, const char *device,
* Check for op blockers in the whole chain between bs and base (or bottom) * Check for op blockers in the whole chain between bs and base (or bottom)
*/ */
iter_end = bottom ? bdrv_filter_or_cow_bs(bottom_bs) : base_bs; iter_end = bottom ? bdrv_filter_or_cow_bs(bottom_bs) : base_bs;
bdrv_graph_rdlock_main_loop();
for (iter = bs; iter && iter != iter_end; for (iter = bs; iter && iter != iter_end;
iter = bdrv_filter_or_cow_bs(iter)) iter = bdrv_filter_or_cow_bs(iter))
{ {
if (bdrv_op_is_blocked(iter, BLOCK_OP_TYPE_STREAM, errp)) { if (bdrv_op_is_blocked(iter, BLOCK_OP_TYPE_STREAM, errp)) {
goto out_rdlock; bdrv_graph_rdunlock_main_loop();
goto out;
} }
} }
bdrv_graph_rdunlock_main_loop(); bdrv_graph_rdunlock_main_loop();
@@ -2542,11 +2531,6 @@ void qmp_block_stream(const char *job_id, const char *device,
out: out:
aio_context_release(aio_context); aio_context_release(aio_context);
return;
out_rdlock:
bdrv_graph_rdunlock_main_loop();
aio_context_release(aio_context);
} }
void qmp_block_commit(const char *job_id, const char *device, void qmp_block_commit(const char *job_id, const char *device,
@@ -2984,7 +2968,6 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs,
if (replaces) { if (replaces) {
BlockDriverState *to_replace_bs; BlockDriverState *to_replace_bs;
AioContext *aio_context;
AioContext *replace_aio_context; AioContext *replace_aio_context;
int64_t bs_size, replace_size; int64_t bs_size, replace_size;
@@ -2999,19 +2982,10 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs,
return; return;
} }
aio_context = bdrv_get_aio_context(bs);
replace_aio_context = bdrv_get_aio_context(to_replace_bs); replace_aio_context = bdrv_get_aio_context(to_replace_bs);
/*
* bdrv_getlength() is a co-wrapper and uses AIO_WAIT_WHILE. Be sure not
* to acquire the same AioContext twice.
*/
if (replace_aio_context != aio_context) {
aio_context_acquire(replace_aio_context); aio_context_acquire(replace_aio_context);
}
replace_size = bdrv_getlength(to_replace_bs); replace_size = bdrv_getlength(to_replace_bs);
if (replace_aio_context != aio_context) {
aio_context_release(replace_aio_context); aio_context_release(replace_aio_context);
}
if (replace_size < 0) { if (replace_size < 0) {
error_setg_errno(errp, -replace_size, error_setg_errno(errp, -replace_size,
@@ -3061,6 +3035,7 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
bdrv_graph_rdunlock_main_loop(); bdrv_graph_rdunlock_main_loop();
return; return;
} }
bdrv_graph_rdunlock_main_loop();
aio_context = bdrv_get_aio_context(bs); aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context); aio_context_acquire(aio_context);
@@ -3082,7 +3057,6 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
if (arg->sync == MIRROR_SYNC_MODE_NONE) { if (arg->sync == MIRROR_SYNC_MODE_NONE) {
target_backing_bs = bs; target_backing_bs = bs;
} }
bdrv_graph_rdunlock_main_loop();
size = bdrv_getlength(bs); size = bdrv_getlength(bs);
if (size < 0) { if (size < 0) {
@@ -3115,18 +3089,16 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
bdrv_img_create(arg->target, format, bdrv_img_create(arg->target, format,
NULL, NULL, NULL, size, flags, false, &local_err); NULL, NULL, NULL, size, flags, false, &local_err);
} else { } else {
BlockDriverState *explicit_backing; /* Implicit filters should not appear in the filename */
BlockDriverState *explicit_backing =
bdrv_skip_implicit_filters(target_backing_bs);
switch (arg->mode) { switch (arg->mode) {
case NEW_IMAGE_MODE_EXISTING: case NEW_IMAGE_MODE_EXISTING:
break; break;
case NEW_IMAGE_MODE_ABSOLUTE_PATHS: case NEW_IMAGE_MODE_ABSOLUTE_PATHS:
/* /* create new image with backing file */
* Create new image with backing file.
* Implicit filters should not appear in the filename.
*/
bdrv_graph_rdlock_main_loop(); bdrv_graph_rdlock_main_loop();
explicit_backing = bdrv_skip_implicit_filters(target_backing_bs);
bdrv_refresh_filename(explicit_backing); bdrv_refresh_filename(explicit_backing);
bdrv_graph_rdunlock_main_loop(); bdrv_graph_rdunlock_main_loop();
@@ -3165,11 +3137,9 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
return; return;
} }
bdrv_graph_rdlock_main_loop();
zero_target = (arg->sync == MIRROR_SYNC_MODE_FULL && zero_target = (arg->sync == MIRROR_SYNC_MODE_FULL &&
(arg->mode == NEW_IMAGE_MODE_EXISTING || (arg->mode == NEW_IMAGE_MODE_EXISTING ||
!bdrv_has_zero_init(target_bs))); !bdrv_has_zero_init(target_bs)));
bdrv_graph_rdunlock_main_loop();
/* Honor bdrv_try_change_aio_context() context acquisition requirements. */ /* Honor bdrv_try_change_aio_context() context acquisition requirements. */
@@ -3412,20 +3382,6 @@ void qmp_block_job_dismiss(const char *id, Error **errp)
job_dismiss_locked(&job, errp); job_dismiss_locked(&job, errp);
} }
void qmp_block_job_change(BlockJobChangeOptions *opts, Error **errp)
{
BlockJob *job;
JOB_LOCK_GUARD();
job = find_block_job_locked(opts->id, errp);
if (!job) {
return;
}
block_job_change_locked(job, opts, errp);
}
void qmp_change_backing_file(const char *device, void qmp_change_backing_file(const char *device,
const char *image_node_name, const char *image_node_name,
const char *backing_file, const char *backing_file,
@@ -3446,38 +3402,38 @@ void qmp_change_backing_file(const char *device,
aio_context = bdrv_get_aio_context(bs); aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context); aio_context_acquire(aio_context);
bdrv_graph_rdlock_main_loop();
image_bs = bdrv_lookup_bs(NULL, image_node_name, &local_err); image_bs = bdrv_lookup_bs(NULL, image_node_name, &local_err);
if (local_err) { if (local_err) {
error_propagate(errp, local_err); error_propagate(errp, local_err);
goto out_rdlock; goto out;
} }
if (!image_bs) { if (!image_bs) {
error_setg(errp, "image file not found"); error_setg(errp, "image file not found");
goto out_rdlock; goto out;
} }
if (bdrv_find_base(image_bs) == image_bs) { if (bdrv_find_base(image_bs) == image_bs) {
error_setg(errp, "not allowing backing file change on an image " error_setg(errp, "not allowing backing file change on an image "
"without a backing file"); "without a backing file");
goto out_rdlock; goto out;
} }
/* even though we are not necessarily operating on bs, we need it to /* even though we are not necessarily operating on bs, we need it to
* determine if block ops are currently prohibited on the chain */ * determine if block ops are currently prohibited on the chain */
bdrv_graph_rdlock_main_loop();
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_CHANGE, errp)) { if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_CHANGE, errp)) {
goto out_rdlock; bdrv_graph_rdunlock_main_loop();
goto out;
} }
bdrv_graph_rdunlock_main_loop();
/* final sanity check */ /* final sanity check */
if (!bdrv_chain_contains(bs, image_bs)) { if (!bdrv_chain_contains(bs, image_bs)) {
error_setg(errp, "'%s' and image file are not in the same chain", error_setg(errp, "'%s' and image file are not in the same chain",
device); device);
goto out_rdlock; goto out;
} }
bdrv_graph_rdunlock_main_loop();
/* if not r/w, reopen to make r/w */ /* if not r/w, reopen to make r/w */
ro = bdrv_is_read_only(image_bs); ro = bdrv_is_read_only(image_bs);
@@ -3505,11 +3461,6 @@ void qmp_change_backing_file(const char *device,
out: out:
aio_context_release(aio_context); aio_context_release(aio_context);
return;
out_rdlock:
bdrv_graph_rdunlock_main_loop();
aio_context_release(aio_context);
} }
void qmp_blockdev_add(BlockdevOptions *options, Error **errp) void qmp_blockdev_add(BlockdevOptions *options, Error **errp)

View File

@@ -198,9 +198,7 @@ void block_job_remove_all_bdrv(BlockJob *job)
* one to make sure that such a concurrent access does not attempt * one to make sure that such a concurrent access does not attempt
* to process an already freed BdrvChild. * to process an already freed BdrvChild.
*/ */
aio_context_release(job->job.aio_context);
bdrv_graph_wrlock(NULL); bdrv_graph_wrlock(NULL);
aio_context_acquire(job->job.aio_context);
while (job->nodes) { while (job->nodes) {
GSList *l = job->nodes; GSList *l = job->nodes;
BdrvChild *c = l->data; BdrvChild *c = l->data;
@@ -330,26 +328,6 @@ static bool block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
return block_job_set_speed_locked(job, speed, errp); return block_job_set_speed_locked(job, speed, errp);
} }
void block_job_change_locked(BlockJob *job, BlockJobChangeOptions *opts,
Error **errp)
{
const BlockJobDriver *drv = block_job_driver(job);
GLOBAL_STATE_CODE();
if (job_apply_verb_locked(&job->job, JOB_VERB_CHANGE, errp)) {
return;
}
if (drv->change) {
job_unlock();
drv->change(job, opts, errp);
job_lock();
} else {
error_setg(errp, "Job type does not support change");
}
}
void block_job_ratelimit_processed_bytes(BlockJob *job, uint64_t n) void block_job_ratelimit_processed_bytes(BlockJob *job, uint64_t n)
{ {
IO_CODE(); IO_CODE();
@@ -378,7 +356,6 @@ BlockJobInfo *block_job_query_locked(BlockJob *job, Error **errp)
{ {
BlockJobInfo *info; BlockJobInfo *info;
uint64_t progress_current, progress_total; uint64_t progress_current, progress_total;
const BlockJobDriver *drv = block_job_driver(job);
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
@@ -391,7 +368,7 @@ BlockJobInfo *block_job_query_locked(BlockJob *job, Error **errp)
&progress_total); &progress_total);
info = g_new0(BlockJobInfo, 1); info = g_new0(BlockJobInfo, 1);
info->type = job_type(&job->job); info->type = g_strdup(job_type_str(&job->job));
info->device = g_strdup(job->job.id); info->device = g_strdup(job->job.id);
info->busy = job->job.busy; info->busy = job->job.busy;
info->paused = job->job.pause_count > 0; info->paused = job->job.pause_count > 0;
@@ -408,11 +385,6 @@ BlockJobInfo *block_job_query_locked(BlockJob *job, Error **errp)
g_strdup(error_get_pretty(job->job.err)) : g_strdup(error_get_pretty(job->job.err)) :
g_strdup(strerror(-job->job.ret)); g_strdup(strerror(-job->job.ret));
} }
if (drv->query) {
job_unlock();
drv->query(job, info);
job_lock();
}
return info; return info;
} }
@@ -513,8 +485,7 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
BlockJob *job; BlockJob *job;
int ret; int ret;
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
bdrv_graph_wrlock(bs);
if (job_id == NULL && !(flags & JOB_INTERNAL)) { if (job_id == NULL && !(flags & JOB_INTERNAL)) {
job_id = bdrv_get_device_name(bs); job_id = bdrv_get_device_name(bs);
@@ -523,7 +494,6 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
job = job_create(job_id, &driver->job_driver, txn, bdrv_get_aio_context(bs), job = job_create(job_id, &driver->job_driver, txn, bdrv_get_aio_context(bs),
flags, cb, opaque, errp); flags, cb, opaque, errp);
if (job == NULL) { if (job == NULL) {
bdrv_graph_wrunlock();
return NULL; return NULL;
} }
@@ -563,11 +533,9 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
goto fail; goto fail;
} }
bdrv_graph_wrunlock();
return job; return job;
fail: fail:
bdrv_graph_wrunlock();
job_early_fail(&job->job); job_early_fail(&job->job);
return NULL; return NULL;
} }

View File

@@ -21,7 +21,6 @@
#define TARGET_ARCH_H #define TARGET_ARCH_H
#include "qemu.h" #include "qemu.h"
#include "target/arm/cpu-features.h"
void target_cpu_set_tls(CPUARMState *env, target_ulong newtls); void target_cpu_set_tls(CPUARMState *env, target_ulong newtls);
target_ulong target_cpu_get_tls(CPUARMState *env); target_ulong target_cpu_get_tls(CPUARMState *env);

View File

@@ -118,7 +118,7 @@ void fork_end(int child)
*/ */
CPU_FOREACH_SAFE(cpu, next_cpu) { CPU_FOREACH_SAFE(cpu, next_cpu) {
if (cpu != thread_cpu) { if (cpu != thread_cpu) {
QTAILQ_REMOVE_RCU(&cpus_queue, cpu, node); QTAILQ_REMOVE_RCU(&cpus, cpu, node);
} }
} }
mmap_fork_end(child); mmap_fork_end(child);

View File

@@ -171,7 +171,7 @@ static int msmouse_chr_write(struct Chardev *s, const uint8_t *buf, int len)
return len; return len;
} }
static const QemuInputHandler msmouse_handler = { static QemuInputHandler msmouse_handler = {
.name = "QEMU Microsoft Mouse", .name = "QEMU Microsoft Mouse",
.mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL, .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
.event = msmouse_input_event, .event = msmouse_input_event,

View File

@@ -178,7 +178,7 @@ static void wctablet_input_sync(DeviceState *dev)
} }
} }
static const QemuInputHandler wctablet_handler = { static QemuInputHandler wctablet_handler = {
.name = "QEMU Wacom Pen Tablet", .name = "QEMU Wacom Pen Tablet",
.mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS, .mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS,
.event = wctablet_input_event, .event = wctablet_input_event,

View File

@@ -14,7 +14,6 @@ CONFIG_SAM460EX=y
CONFIG_MAC_OLDWORLD=y CONFIG_MAC_OLDWORLD=y
CONFIG_MAC_NEWWORLD=y CONFIG_MAC_NEWWORLD=y
CONFIG_AMIGAONE=y
CONFIG_PEGASOS2=y CONFIG_PEGASOS2=y
# For PReP # For PReP

View File

@@ -1,5 +1,4 @@
TARGET_ARCH=hppa TARGET_ARCH=hppa
TARGET_ABI32=y
TARGET_SYSTBL_ABI=common,32 TARGET_SYSTBL_ABI=common,32
TARGET_SYSTBL=syscall.tbl TARGET_SYSTBL=syscall.tbl
TARGET_BIG_ENDIAN=y TARGET_BIG_ENDIAN=y

View File

@@ -1,4 +1,3 @@
# Default configuration for loongarch64-linux-user # Default configuration for loongarch64-linux-user
TARGET_ARCH=loongarch64 TARGET_ARCH=loongarch64
TARGET_BASE_ARCH=loongarch TARGET_BASE_ARCH=loongarch
TARGET_XML_FILES=gdb-xml/loongarch-base64.xml gdb-xml/loongarch-fpu.xml

View File

@@ -1,3 +1,2 @@
TARGET_ARCH=sparc TARGET_ARCH=sparc
TARGET_BIG_ENDIAN=y TARGET_BIG_ENDIAN=y
TARGET_SUPPORTS_MTTCG=y

View File

@@ -1,4 +1,3 @@
TARGET_ARCH=sparc64 TARGET_ARCH=sparc64
TARGET_BASE_ARCH=sparc TARGET_BASE_ARCH=sparc
TARGET_BIG_ENDIAN=y TARGET_BIG_ENDIAN=y
TARGET_SUPPORTS_MTTCG=y

51
configure vendored
View File

@@ -309,7 +309,6 @@ fi
ar="${AR-${cross_prefix}ar}" ar="${AR-${cross_prefix}ar}"
as="${AS-${cross_prefix}as}" as="${AS-${cross_prefix}as}"
ccas="${CCAS-$cc}" ccas="${CCAS-$cc}"
dlltool="${DLLTOOL-${cross_prefix}dlltool}"
objcopy="${OBJCOPY-${cross_prefix}objcopy}" objcopy="${OBJCOPY-${cross_prefix}objcopy}"
ld="${LD-${cross_prefix}ld}" ld="${LD-${cross_prefix}ld}"
ranlib="${RANLIB-${cross_prefix}ranlib}" ranlib="${RANLIB-${cross_prefix}ranlib}"
@@ -1011,9 +1010,9 @@ if test "$targetos" = "bogus"; then
fi fi
# test for any invalid configuration combinations # test for any invalid configuration combinations
if test "$targetos" = "windows" && ! has "$dlltool"; then if test "$targetos" = "windows"; then
if test "$plugins" = "yes"; then if test "$plugins" = "yes"; then
error_exit "TCG plugins requires dlltool to build on Windows platforms" error_exit "TCG plugins not currently supported on Windows platforms"
fi fi
plugins="no" plugins="no"
fi fi
@@ -1282,11 +1281,6 @@ probe_target_compiler() {
container_cross_prefix=aarch64-linux-gnu- container_cross_prefix=aarch64-linux-gnu-
container_cross_cc=${container_cross_prefix}gcc container_cross_cc=${container_cross_prefix}gcc
;; ;;
alpha)
container_image=debian-legacy-test-cross
container_cross_prefix=alpha-linux-gnu-
container_cross_cc=${container_cross_prefix}gcc
;;
arm) arm)
# We don't have any bigendian build tools so we only use this for ARM # We don't have any bigendian build tools so we only use this for ARM
container_image=debian-armhf-cross container_image=debian-armhf-cross
@@ -1301,11 +1295,6 @@ probe_target_compiler() {
container_cross_prefix=hexagon-unknown-linux-musl- container_cross_prefix=hexagon-unknown-linux-musl-
container_cross_cc=${container_cross_prefix}clang container_cross_cc=${container_cross_prefix}clang
;; ;;
hppa)
container_image=debian-all-test-cross
container_cross_prefix=hppa-linux-gnu-
container_cross_cc=${container_cross_prefix}gcc
;;
i386) i386)
container_image=fedora-i386-cross container_image=fedora-i386-cross
container_cross_prefix= container_cross_prefix=
@@ -1314,11 +1303,6 @@ probe_target_compiler() {
container_image=debian-loongarch-cross container_image=debian-loongarch-cross
container_cross_prefix=loongarch64-unknown-linux-gnu- container_cross_prefix=loongarch64-unknown-linux-gnu-
;; ;;
m68k)
container_image=debian-all-test-cross
container_cross_prefix=m68k-linux-gnu-
container_cross_cc=${container_cross_prefix}gcc
;;
microblaze) microblaze)
container_image=debian-microblaze-cross container_image=debian-microblaze-cross
container_cross_prefix=microblaze-linux-musl- container_cross_prefix=microblaze-linux-musl-
@@ -1328,37 +1312,22 @@ probe_target_compiler() {
container_cross_prefix=mips64el-linux-gnuabi64- container_cross_prefix=mips64el-linux-gnuabi64-
;; ;;
mips64) mips64)
container_image=debian-all-test-cross container_image=debian-mips64-cross
container_cross_prefix=mips64-linux-gnuabi64- container_cross_prefix=mips64-linux-gnuabi64-
;; ;;
mips)
container_image=debian-all-test-cross
container_cross_prefix=mips-linux-gnu-
;;
nios2) nios2)
container_image=debian-nios2-cross container_image=debian-nios2-cross
container_cross_prefix=nios2-linux-gnu- container_cross_prefix=nios2-linux-gnu-
;; ;;
ppc) ppc)
container_image=debian-all-test-cross container_image=debian-powerpc-test-cross
container_cross_prefix=powerpc-linux-gnu- container_cross_prefix=powerpc-linux-gnu-
container_cross_cc=${container_cross_prefix}gcc container_cross_cc=${container_cross_prefix}gcc
;; ;;
ppc64|ppc64le) ppc64|ppc64le)
container_image=debian-all-test-cross container_image=debian-powerpc-test-cross
container_cross_prefix=powerpc${target_arch#ppc}-linux-gnu- container_cross_prefix=powerpc${target_arch#ppc}-linux-gnu-
;; container_cross_cc=${container_cross_prefix}gcc-10
riscv64)
container_image=debian-all-test-cross
container_cross_prefix=riscv64-linux-gnu-
;;
sh4)
container_image=debian-legacy-test-cross
container_cross_prefix=sh4-linux-gnu-
;;
sparc64)
container_image=debian-all-test-cross
container_cross_prefix=sparc64-linux-gnu-
;; ;;
tricore) tricore)
container_image=debian-tricore-cross container_image=debian-tricore-cross
@@ -1660,15 +1629,9 @@ echo "SRC_PATH=$source_path/contrib/plugins" >> contrib/plugins/$config_host_mak
echo "PKG_CONFIG=${pkg_config}" >> contrib/plugins/$config_host_mak echo "PKG_CONFIG=${pkg_config}" >> contrib/plugins/$config_host_mak
echo "CC=$cc $CPU_CFLAGS" >> contrib/plugins/$config_host_mak echo "CC=$cc $CPU_CFLAGS" >> contrib/plugins/$config_host_mak
echo "CFLAGS=${CFLAGS-$default_cflags} $EXTRA_CFLAGS" >> contrib/plugins/$config_host_mak echo "CFLAGS=${CFLAGS-$default_cflags} $EXTRA_CFLAGS" >> contrib/plugins/$config_host_mak
if test "$targetos" = windows; then
echo "DLLTOOL=$dlltool" >> contrib/plugins/$config_host_mak
fi
if test "$targetos" = darwin; then if test "$targetos" = darwin; then
echo "CONFIG_DARWIN=y" >> contrib/plugins/$config_host_mak echo "CONFIG_DARWIN=y" >> contrib/plugins/$config_host_mak
fi fi
if test "$targetos" = windows; then
echo "CONFIG_WIN32=y" >> contrib/plugins/$config_host_mak
fi
# tests/tcg configuration # tests/tcg configuration
(config_host_mak=tests/tcg/config-host.mak (config_host_mak=tests/tcg/config-host.mak
@@ -1771,7 +1734,6 @@ if test "$skip_meson" = no; then
test -n "$cxx" && echo "cpp = [$(meson_quote $cxx $CPU_CFLAGS)]" >> $cross test -n "$cxx" && echo "cpp = [$(meson_quote $cxx $CPU_CFLAGS)]" >> $cross
test -n "$objcc" && echo "objc = [$(meson_quote $objcc $CPU_CFLAGS)]" >> $cross test -n "$objcc" && echo "objc = [$(meson_quote $objcc $CPU_CFLAGS)]" >> $cross
echo "ar = [$(meson_quote $ar)]" >> $cross echo "ar = [$(meson_quote $ar)]" >> $cross
echo "dlltool = [$(meson_quote $dlltool)]" >> $cross
echo "nm = [$(meson_quote $nm)]" >> $cross echo "nm = [$(meson_quote $nm)]" >> $cross
echo "pkgconfig = [$(meson_quote $pkg_config)]" >> $cross echo "pkgconfig = [$(meson_quote $pkg_config)]" >> $cross
echo "pkg-config = [$(meson_quote $pkg_config)]" >> $cross echo "pkg-config = [$(meson_quote $pkg_config)]" >> $cross
@@ -1877,7 +1839,6 @@ preserve_env CC
preserve_env CFLAGS preserve_env CFLAGS
preserve_env CXX preserve_env CXX
preserve_env CXXFLAGS preserve_env CXXFLAGS
preserve_env DLLTOOL
preserve_env LD preserve_env LD
preserve_env LDFLAGS preserve_env LDFLAGS
preserve_env LD_LIBRARY_PATH preserve_env LD_LIBRARY_PATH

View File

@@ -72,7 +72,10 @@ int pa_space_create(struct pa_space *ps, QEMU_Elf *qemu_elf)
} }
} }
ps->block = g_new(struct pa_block, ps->block_nr); ps->block = malloc(sizeof(*ps->block) * ps->block_nr);
if (!ps->block) {
return 1;
}
for (i = 0; i < phdr_nr; i++) { for (i = 0; i < phdr_nr; i++) {
if (phdr[i].p_type == PT_LOAD) { if (phdr[i].p_type == PT_LOAD) {
@@ -94,7 +97,7 @@ int pa_space_create(struct pa_space *ps, QEMU_Elf *qemu_elf)
void pa_space_destroy(struct pa_space *ps) void pa_space_destroy(struct pa_space *ps)
{ {
ps->block_nr = 0; ps->block_nr = 0;
g_free(ps->block); free(ps->block);
} }
void va_space_set_dtb(struct va_space *vs, uint64_t dtb) void va_space_set_dtb(struct va_space *vs, uint64_t dtb)

View File

@@ -120,11 +120,14 @@ static KDDEBUGGER_DATA64 *get_kdbg(uint64_t KernBase, struct pdb_reader *pdb,
} }
} }
kdbg = g_malloc(kdbg_hdr.Size); kdbg = malloc(kdbg_hdr.Size);
if (!kdbg) {
return NULL;
}
if (va_space_rw(vs, KdDebuggerDataBlock, kdbg, kdbg_hdr.Size, 0)) { if (va_space_rw(vs, KdDebuggerDataBlock, kdbg, kdbg_hdr.Size, 0)) {
eprintf("Failed to extract entire KDBG\n"); eprintf("Failed to extract entire KDBG\n");
g_free(kdbg); free(kdbg);
return NULL; return NULL;
} }
@@ -475,7 +478,7 @@ static bool pe_check_pdb_name(uint64_t base, void *start_addr,
} }
if (memcmp(&rsds->Signature, sign_rsds, sizeof(sign_rsds))) { if (memcmp(&rsds->Signature, sign_rsds, sizeof(sign_rsds))) {
eprintf("CodeView signature is \'%.4s\', \'%.4s\' expected\n", eprintf("CodeView signature is \'%.4s\', \'%s\' expected\n",
rsds->Signature, sign_rsds); rsds->Signature, sign_rsds);
return false; return false;
} }
@@ -640,7 +643,7 @@ int main(int argc, char *argv[])
} }
out_kdbg: out_kdbg:
g_free(kdbg); free(kdbg);
out_pdb: out_pdb:
pdb_exit(&pdb); pdb_exit(&pdb);
out_pdb_file: out_pdb_file:

View File

@@ -25,10 +25,6 @@
static uint32_t pdb_get_file_size(const struct pdb_reader *r, unsigned idx) static uint32_t pdb_get_file_size(const struct pdb_reader *r, unsigned idx)
{ {
if (idx >= r->ds.toc->num_files) {
return 0;
}
return r->ds.toc->file_size[idx]; return r->ds.toc->file_size[idx];
} }
@@ -94,18 +90,18 @@ uint64_t pdb_resolve(uint64_t img_base, struct pdb_reader *r, const char *name)
static void pdb_reader_ds_exit(struct pdb_reader *r) static void pdb_reader_ds_exit(struct pdb_reader *r)
{ {
g_free(r->ds.toc); free(r->ds.toc);
} }
static void pdb_exit_symbols(struct pdb_reader *r) static void pdb_exit_symbols(struct pdb_reader *r)
{ {
g_free(r->modimage); free(r->modimage);
g_free(r->symbols); free(r->symbols);
} }
static void pdb_exit_segments(struct pdb_reader *r) static void pdb_exit_segments(struct pdb_reader *r)
{ {
g_free(r->segs); free(r->segs);
} }
static void *pdb_ds_read(const PDB_DS_HEADER *header, static void *pdb_ds_read(const PDB_DS_HEADER *header,
@@ -120,7 +116,10 @@ static void *pdb_ds_read(const PDB_DS_HEADER *header,
nBlocks = (size + header->block_size - 1) / header->block_size; nBlocks = (size + header->block_size - 1) / header->block_size;
buffer = g_malloc(nBlocks * header->block_size); buffer = malloc(nBlocks * header->block_size);
if (!buffer) {
return NULL;
}
for (i = 0; i < nBlocks; i++) { for (i = 0; i < nBlocks; i++) {
memcpy(buffer + i * header->block_size, (const char *)header + memcpy(buffer + i * header->block_size, (const char *)header +
@@ -160,17 +159,16 @@ static void *pdb_ds_read_file(struct pdb_reader* r, uint32_t file_number)
static int pdb_init_segments(struct pdb_reader *r) static int pdb_init_segments(struct pdb_reader *r)
{ {
char *segs;
unsigned stream_idx = r->segments; unsigned stream_idx = r->segments;
r->segs = pdb_ds_read_file(r, stream_idx); segs = pdb_ds_read_file(r, stream_idx);
if (!r->segs) { if (!segs) {
return 1; return 1;
} }
r->segs = segs;
r->segs_size = pdb_get_file_size(r, stream_idx); r->segs_size = pdb_get_file_size(r, stream_idx);
if (!r->segs_size) {
return 1;
}
return 0; return 0;
} }
@@ -203,7 +201,7 @@ static int pdb_init_symbols(struct pdb_reader *r)
return 0; return 0;
out_symbols: out_symbols:
g_free(symbols); free(symbols);
return err; return err;
} }
@@ -260,7 +258,7 @@ static int pdb_reader_init(struct pdb_reader *r, void *data)
out_sym: out_sym:
pdb_exit_symbols(r); pdb_exit_symbols(r);
out_root: out_root:
g_free(r->ds.root); free(r->ds.root);
out_ds: out_ds:
pdb_reader_ds_exit(r); pdb_reader_ds_exit(r);
@@ -271,7 +269,7 @@ static void pdb_reader_exit(struct pdb_reader *r)
{ {
pdb_exit_segments(r); pdb_exit_segments(r);
pdb_exit_symbols(r); pdb_exit_symbols(r);
g_free(r->ds.root); free(r->ds.root);
pdb_reader_ds_exit(r); pdb_reader_ds_exit(r);
} }

View File

@@ -94,7 +94,10 @@ static int init_states(QEMU_Elf *qe)
printf("%zu CPU states has been found\n", cpu_nr); printf("%zu CPU states has been found\n", cpu_nr);
qe->state = g_new(QEMUCPUState*, cpu_nr); qe->state = malloc(sizeof(*qe->state) * cpu_nr);
if (!qe->state) {
return 1;
}
cpu_nr = 0; cpu_nr = 0;
@@ -112,7 +115,7 @@ static int init_states(QEMU_Elf *qe)
static void exit_states(QEMU_Elf *qe) static void exit_states(QEMU_Elf *qe)
{ {
g_free(qe->state); free(qe->state);
} }
static bool check_ehdr(QEMU_Elf *qe) static bool check_ehdr(QEMU_Elf *qe)

View File

@@ -12,18 +12,15 @@ amd.com AMD
aspeedtech.com ASPEED Technology Inc. aspeedtech.com ASPEED Technology Inc.
baidu.com Baidu baidu.com Baidu
bytedance.com ByteDance bytedance.com ByteDance
cestc.cn Cestc
cmss.chinamobile.com China Mobile cmss.chinamobile.com China Mobile
citrix.com Citrix citrix.com Citrix
crudebyte.com Crudebyte crudebyte.com Crudebyte
chinatelecom.cn China Telecom chinatelecom.cn China Telecom
daynix.com Daynix
eldorado.org.br Instituto de Pesquisas Eldorado eldorado.org.br Instituto de Pesquisas Eldorado
fb.com Facebook fb.com Facebook
fujitsu.com Fujitsu fujitsu.com Fujitsu
google.com Google google.com Google
greensocs.com GreenSocs greensocs.com GreenSocs
hisilicon.com Huawei
huawei.com Huawei huawei.com Huawei
ibm.com IBM ibm.com IBM
igalia.com Igalia igalia.com Igalia
@@ -41,7 +38,6 @@ proxmox.com Proxmox
quicinc.com Qualcomm Innovation Center quicinc.com Qualcomm Innovation Center
redhat.com Red Hat redhat.com Red Hat
rev.ng rev.ng Labs rev.ng rev.ng Labs
rivosinc.com Rivos Inc
rt-rk.com RT-RK rt-rk.com RT-RK
samsung.com Samsung samsung.com Samsung
siemens.com Siemens siemens.com Siemens

View File

@@ -17,25 +17,12 @@ NAMES += execlog
NAMES += hotblocks NAMES += hotblocks
NAMES += hotpages NAMES += hotpages
NAMES += howvec NAMES += howvec
# The lockstep example communicates using unix sockets,
# and can't be easily made to work on windows.
ifneq ($(CONFIG_WIN32),y)
NAMES += lockstep NAMES += lockstep
endif
NAMES += hwprofile NAMES += hwprofile
NAMES += cache NAMES += cache
NAMES += drcov NAMES += drcov
ifeq ($(CONFIG_WIN32),y) SONAMES := $(addsuffix .so,$(addprefix lib,$(NAMES)))
SO_SUFFIX := .dll
LDLIBS += $(shell $(PKG_CONFIG) --libs glib-2.0)
else
SO_SUFFIX := .so
endif
SONAMES := $(addsuffix $(SO_SUFFIX),$(addprefix lib,$(NAMES)))
# The main QEMU uses Glib extensively so it's perfectly fine to use it # The main QEMU uses Glib extensively so it's perfectly fine to use it
# in plugins (which many example do). # in plugins (which many example do).
@@ -48,20 +35,15 @@ all: $(SONAMES)
%.o: %.c %.o: %.c
$(CC) $(CFLAGS) $(PLUGIN_CFLAGS) -c -o $@ $< $(CC) $(CFLAGS) $(PLUGIN_CFLAGS) -c -o $@ $<
ifeq ($(CONFIG_WIN32),y) lib%.so: %.o
lib%$(SO_SUFFIX): %.o win32_linker.o ../../plugins/qemu_plugin_api.lib ifeq ($(CONFIG_DARWIN),y)
$(CC) -shared -o $@ $^ $(LDLIBS)
else ifeq ($(CONFIG_DARWIN),y)
lib%$(SO_SUFFIX): %.o
$(CC) -bundle -Wl,-undefined,dynamic_lookup -o $@ $^ $(LDLIBS) $(CC) -bundle -Wl,-undefined,dynamic_lookup -o $@ $^ $(LDLIBS)
else else
lib%$(SO_SUFFIX): %.o
$(CC) -shared -o $@ $^ $(LDLIBS) $(CC) -shared -o $@ $^ $(LDLIBS)
endif endif
clean: clean:
rm -f *.o *$(SO_SUFFIX) *.d rm -f *.o *.so *.d
rm -Rf .libs rm -Rf .libs
.PHONY: all clean .PHONY: all clean

View File

@@ -257,7 +257,6 @@ static bool setup_socket(const char *path)
sockaddr.sun_family = AF_UNIX; sockaddr.sun_family = AF_UNIX;
if (g_strlcpy(sockaddr.sun_path, path, pathlen) >= pathlen) { if (g_strlcpy(sockaddr.sun_path, path, pathlen) >= pathlen) {
perror("bad path"); perror("bad path");
close(fd);
return false; return false;
} }
@@ -304,7 +303,6 @@ static bool connect_socket(const char *path)
sockaddr.sun_family = AF_UNIX; sockaddr.sun_family = AF_UNIX;
if (g_strlcpy(sockaddr.sun_path, path, pathlen) >= pathlen) { if (g_strlcpy(sockaddr.sun_path, path, pathlen) >= pathlen) {
perror("bad path"); perror("bad path");
close(fd);
return false; return false;
} }

View File

@@ -1,34 +0,0 @@
/*
* Copyright (C) 2023, Greg Manning <gmanning@rapitasystems.com>
*
* This hook, __pfnDliFailureHook2, is documented in the microsoft documentation here:
* https://learn.microsoft.com/en-us/cpp/build/reference/error-handling-and-notification
* It gets called when a delay-loaded DLL encounters various errors.
* We handle the specific case of a DLL looking for a "qemu.exe",
* and give it the running executable (regardless of what it is named).
*
* This work is licensed under the terms of the GNU LGPL, version 2 or later.
* See the COPYING.LIB file in the top-level directory.
*/
#include <windows.h>
#include <delayimp.h>
FARPROC WINAPI dll_failure_hook(unsigned dliNotify, PDelayLoadInfo pdli);
PfnDliHook __pfnDliFailureHook2 = dll_failure_hook;
FARPROC WINAPI dll_failure_hook(unsigned dliNotify, PDelayLoadInfo pdli) {
if (dliNotify == dliFailLoadLib) {
/* If the failing request was for qemu.exe, ... */
if (strcmp(pdli->szDll, "qemu.exe") == 0) {
/* Then pass back a pointer to the top level module. */
HMODULE top = GetModuleHandle(NULL);
return (FARPROC) top;
}
}
/* Otherwise we can't do anything special. */
return 0;
}

View File

@@ -73,7 +73,7 @@ static int cpu_get_free_index(void)
return max_cpu_index; return max_cpu_index;
} }
CPUTailQ cpus_queue = QTAILQ_HEAD_INITIALIZER(cpus_queue); CPUTailQ cpus = QTAILQ_HEAD_INITIALIZER(cpus);
static unsigned int cpu_list_generation_id; static unsigned int cpu_list_generation_id;
unsigned int cpu_list_generation_id_get(void) unsigned int cpu_list_generation_id_get(void)
@@ -90,7 +90,7 @@ void cpu_list_add(CPUState *cpu)
} else { } else {
assert(!cpu_index_auto_assigned); assert(!cpu_index_auto_assigned);
} }
QTAILQ_INSERT_TAIL_RCU(&cpus_queue, cpu, node); QTAILQ_INSERT_TAIL_RCU(&cpus, cpu, node);
cpu_list_generation_id++; cpu_list_generation_id++;
} }
@@ -102,7 +102,7 @@ void cpu_list_remove(CPUState *cpu)
return; return;
} }
QTAILQ_REMOVE_RCU(&cpus_queue, cpu, node); QTAILQ_REMOVE_RCU(&cpus, cpu, node);
cpu->cpu_index = UNASSIGNED_CPU_INDEX; cpu->cpu_index = UNASSIGNED_CPU_INDEX;
cpu_list_generation_id++; cpu_list_generation_id++;
} }

View File

@@ -42,6 +42,7 @@
#include "hw/core/accel-cpu.h" #include "hw/core/accel-cpu.h"
#include "trace/trace-root.h" #include "trace/trace-root.h"
#include "qemu/accel.h" #include "qemu/accel.h"
#include "qemu/plugin.h"
uintptr_t qemu_host_page_size; uintptr_t qemu_host_page_size;
intptr_t qemu_host_page_mask; intptr_t qemu_host_page_mask;
@@ -130,18 +131,23 @@ const VMStateDescription vmstate_cpu_common = {
}; };
#endif #endif
bool cpu_exec_realizefn(CPUState *cpu, Error **errp) void cpu_exec_realizefn(CPUState *cpu, Error **errp)
{ {
/* cache the cpu class for the hotpath */ /* cache the cpu class for the hotpath */
cpu->cc = CPU_GET_CLASS(cpu); cpu->cc = CPU_GET_CLASS(cpu);
if (!accel_cpu_common_realize(cpu, errp)) { if (!accel_cpu_common_realize(cpu, errp)) {
return false; return;
} }
/* Wait until cpu initialization complete before exposing cpu. */ /* Wait until cpu initialization complete before exposing cpu. */
cpu_list_add(cpu); cpu_list_add(cpu);
/* Plugin initialization must wait until cpu_index assigned. */
if (tcg_enabled()) {
qemu_plugin_vcpu_init_hook(cpu);
}
#ifdef CONFIG_USER_ONLY #ifdef CONFIG_USER_ONLY
assert(qdev_get_vmsd(DEVICE(cpu)) == NULL || assert(qdev_get_vmsd(DEVICE(cpu)) == NULL ||
qdev_get_vmsd(DEVICE(cpu))->unmigratable); qdev_get_vmsd(DEVICE(cpu))->unmigratable);
@@ -153,8 +159,6 @@ bool cpu_exec_realizefn(CPUState *cpu, Error **errp)
vmstate_register(NULL, cpu->cpu_index, cpu->cc->sysemu_ops->legacy_vmsd, cpu); vmstate_register(NULL, cpu->cpu_index, cpu->cc->sysemu_ops->legacy_vmsd, cpu);
} }
#endif /* CONFIG_USER_ONLY */ #endif /* CONFIG_USER_ONLY */
return true;
} }
void cpu_exec_unrealizefn(CPUState *cpu) void cpu_exec_unrealizefn(CPUState *cpu)
@@ -170,6 +174,11 @@ void cpu_exec_unrealizefn(CPUState *cpu)
} }
#endif #endif
/* Call the plugin hook before clearing cpu->cpu_index in cpu_list_remove */
if (tcg_enabled()) {
qemu_plugin_vcpu_exit_hook(cpu);
}
cpu_list_remove(cpu); cpu_list_remove(cpu);
/* /*
* Now that the vCPU has been removed from the RCU list, we can call * Now that the vCPU has been removed from the RCU list, we can call

View File

@@ -88,13 +88,15 @@ static QCryptoAkCipherRSAKey *qcrypto_builtin_rsa_public_key_parse(
goto error; goto error;
} }
if (seq_length != 0) { if (seq_length != 0) {
error_setg(errp, "Invalid RSA public key");
goto error; goto error;
} }
return rsa; return rsa;
error: error:
if (errp && !*errp) {
error_setg(errp, "Invalid RSA public key");
}
qcrypto_akcipher_rsakey_free(rsa); qcrypto_akcipher_rsakey_free(rsa);
return NULL; return NULL;
} }
@@ -167,13 +169,15 @@ static QCryptoAkCipherRSAKey *qcrypto_builtin_rsa_private_key_parse(
return rsa; return rsa;
} }
if (seq_length != 0) { if (seq_length != 0) {
error_setg(errp, "Invalid RSA private key");
goto error; goto error;
} }
return rsa; return rsa;
error: error:
if (errp && !*errp) {
error_setg(errp, "Invalid RSA private key");
}
qcrypto_akcipher_rsakey_free(rsa); qcrypto_akcipher_rsakey_free(rsa);
return NULL; return NULL;
} }

View File

@@ -862,47 +862,6 @@ typedef enum {
rv_op_fltq_q = 831, rv_op_fltq_q = 831,
rv_op_fleq_h = 832, rv_op_fleq_h = 832,
rv_op_fltq_h = 833, rv_op_fltq_h = 833,
rv_op_vaesdf_vv = 834,
rv_op_vaesdf_vs = 835,
rv_op_vaesdm_vv = 836,
rv_op_vaesdm_vs = 837,
rv_op_vaesef_vv = 838,
rv_op_vaesef_vs = 839,
rv_op_vaesem_vv = 840,
rv_op_vaesem_vs = 841,
rv_op_vaeskf1_vi = 842,
rv_op_vaeskf2_vi = 843,
rv_op_vaesz_vs = 844,
rv_op_vandn_vv = 845,
rv_op_vandn_vx = 846,
rv_op_vbrev_v = 847,
rv_op_vbrev8_v = 848,
rv_op_vclmul_vv = 849,
rv_op_vclmul_vx = 850,
rv_op_vclmulh_vv = 851,
rv_op_vclmulh_vx = 852,
rv_op_vclz_v = 853,
rv_op_vcpop_v = 854,
rv_op_vctz_v = 855,
rv_op_vghsh_vv = 856,
rv_op_vgmul_vv = 857,
rv_op_vrev8_v = 858,
rv_op_vrol_vv = 859,
rv_op_vrol_vx = 860,
rv_op_vror_vv = 861,
rv_op_vror_vx = 862,
rv_op_vror_vi = 863,
rv_op_vsha2ch_vv = 864,
rv_op_vsha2cl_vv = 865,
rv_op_vsha2ms_vv = 866,
rv_op_vsm3c_vi = 867,
rv_op_vsm3me_vv = 868,
rv_op_vsm4k_vi = 869,
rv_op_vsm4r_vv = 870,
rv_op_vsm4r_vs = 871,
rv_op_vwsll_vv = 872,
rv_op_vwsll_vx = 873,
rv_op_vwsll_vi = 874,
} rv_op; } rv_op;
/* register names */ /* register names */
@@ -2049,47 +2008,6 @@ const rv_opcode_data rvi_opcode_data[] = {
{ "fltq.q", rv_codec_r, rv_fmt_rd_frs1_frs2, NULL, 0, 0, 0 }, { "fltq.q", rv_codec_r, rv_fmt_rd_frs1_frs2, NULL, 0, 0, 0 },
{ "fleq.h", rv_codec_r, rv_fmt_rd_frs1_frs2, NULL, 0, 0, 0 }, { "fleq.h", rv_codec_r, rv_fmt_rd_frs1_frs2, NULL, 0, 0, 0 },
{ "fltq.h", rv_codec_r, rv_fmt_rd_frs1_frs2, NULL, 0, 0, 0 }, { "fltq.h", rv_codec_r, rv_fmt_rd_frs1_frs2, NULL, 0, 0, 0 },
{ "vaesdf.vv", rv_codec_v_r, rv_fmt_vd_vs2, NULL, 0, 0, 0 },
{ "vaesdf.vs", rv_codec_v_r, rv_fmt_vd_vs2, NULL, 0, 0, 0 },
{ "vaesdm.vv", rv_codec_v_r, rv_fmt_vd_vs2, NULL, 0, 0, 0 },
{ "vaesdm.vs", rv_codec_v_r, rv_fmt_vd_vs2, NULL, 0, 0, 0 },
{ "vaesef.vv", rv_codec_v_r, rv_fmt_vd_vs2, NULL, 0, 0, 0 },
{ "vaesef.vs", rv_codec_v_r, rv_fmt_vd_vs2, NULL, 0, 0, 0 },
{ "vaesem.vv", rv_codec_v_r, rv_fmt_vd_vs2, NULL, 0, 0, 0 },
{ "vaesem.vs", rv_codec_v_r, rv_fmt_vd_vs2, NULL, 0, 0, 0 },
{ "vaeskf1.vi", rv_codec_v_i, rv_fmt_vd_vs2_uimm, NULL, 0, 0, 0 },
{ "vaeskf2.vi", rv_codec_v_i, rv_fmt_vd_vs2_uimm, NULL, 0, 0, 0 },
{ "vaesz.vs", rv_codec_v_r, rv_fmt_vd_vs2, NULL, 0, 0, 0 },
{ "vandn.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 },
{ "vandn.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 },
{ "vbrev.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 },
{ "vbrev8.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 },
{ "vclmul.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 },
{ "vclmul.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 },
{ "vclmulh.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 },
{ "vclmulh.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 },
{ "vclz.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 },
{ "vcpop.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 },
{ "vctz.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 },
{ "vghsh.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1, NULL, 0, 0, 0 },
{ "vgmul.vv", rv_codec_v_r, rv_fmt_vd_vs2, NULL, 0, 0, 0 },
{ "vrev8.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 },
{ "vrol.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 },
{ "vrol.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 },
{ "vror.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 },
{ "vror.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 },
{ "vror.vi", rv_codec_vror_vi, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 },
{ "vsha2ch.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1, NULL, 0, 0, 0 },
{ "vsha2cl.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1, NULL, 0, 0, 0 },
{ "vsha2ms.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1, NULL, 0, 0, 0 },
{ "vsm3c.vi", rv_codec_v_i, rv_fmt_vd_vs2_uimm, NULL, 0, 0, 0 },
{ "vsm3me.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1, NULL, 0, 0, 0 },
{ "vsm4k.vi", rv_codec_v_i, rv_fmt_vd_vs2_uimm, NULL, 0, 0, 0 },
{ "vsm4r.vv", rv_codec_v_r, rv_fmt_vd_vs2, NULL, 0, 0, 0 },
{ "vsm4r.vs", rv_codec_v_r, rv_fmt_vd_vs2, NULL, 0, 0, 0 },
{ "vwsll.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm, NULL, 0, 0, 0 },
{ "vwsll.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, NULL, 0, 0, 0 },
{ "vwsll.vi", rv_codec_v_i, rv_fmt_vd_vs2_uimm_vm, NULL, 0, 0, 0 },
}; };
/* CSR names */ /* CSR names */
@@ -3258,7 +3176,6 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa)
case 0: case 0:
switch ((inst >> 26) & 0b111111) { switch ((inst >> 26) & 0b111111) {
case 0: op = rv_op_vadd_vv; break; case 0: op = rv_op_vadd_vv; break;
case 1: op = rv_op_vandn_vv; break;
case 2: op = rv_op_vsub_vv; break; case 2: op = rv_op_vsub_vv; break;
case 4: op = rv_op_vminu_vv; break; case 4: op = rv_op_vminu_vv; break;
case 5: op = rv_op_vmin_vv; break; case 5: op = rv_op_vmin_vv; break;
@@ -3281,8 +3198,6 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa)
} }
break; break;
case 19: op = rv_op_vmsbc_vvm; break; case 19: op = rv_op_vmsbc_vvm; break;
case 20: op = rv_op_vror_vv; break;
case 21: op = rv_op_vrol_vv; break;
case 23: case 23:
if (((inst >> 20) & 0b111111) == 32) if (((inst >> 20) & 0b111111) == 32)
op = rv_op_vmv_v_v; op = rv_op_vmv_v_v;
@@ -3311,7 +3226,6 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa)
case 47: op = rv_op_vnclip_wv; break; case 47: op = rv_op_vnclip_wv; break;
case 48: op = rv_op_vwredsumu_vs; break; case 48: op = rv_op_vwredsumu_vs; break;
case 49: op = rv_op_vwredsum_vs; break; case 49: op = rv_op_vwredsum_vs; break;
case 53: op = rv_op_vwsll_vv; break;
} }
break; break;
case 1: case 1:
@@ -3409,8 +3323,6 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa)
case 9: op = rv_op_vaadd_vv; break; case 9: op = rv_op_vaadd_vv; break;
case 10: op = rv_op_vasubu_vv; break; case 10: op = rv_op_vasubu_vv; break;
case 11: op = rv_op_vasub_vv; break; case 11: op = rv_op_vasub_vv; break;
case 12: op = rv_op_vclmul_vv; break;
case 13: op = rv_op_vclmulh_vv; break;
case 16: case 16:
switch ((inst >> 15) & 0b11111) { switch ((inst >> 15) & 0b11111) {
case 0: if ((inst >> 25) & 1) op = rv_op_vmv_x_s; break; case 0: if ((inst >> 25) & 1) op = rv_op_vmv_x_s; break;
@@ -3426,12 +3338,6 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa)
case 5: op = rv_op_vsext_vf4; break; case 5: op = rv_op_vsext_vf4; break;
case 6: op = rv_op_vzext_vf2; break; case 6: op = rv_op_vzext_vf2; break;
case 7: op = rv_op_vsext_vf2; break; case 7: op = rv_op_vsext_vf2; break;
case 8: op = rv_op_vbrev8_v; break;
case 9: op = rv_op_vrev8_v; break;
case 10: op = rv_op_vbrev_v; break;
case 12: op = rv_op_vclz_v; break;
case 13: op = rv_op_vctz_v; break;
case 14: op = rv_op_vcpop_v; break;
} }
break; break;
case 20: case 20:
@@ -3500,7 +3406,6 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa)
} }
break; break;
case 17: op = rv_op_vmadc_vim; break; case 17: op = rv_op_vmadc_vim; break;
case 20: case 21: op = rv_op_vror_vi; break;
case 23: case 23:
if (((inst >> 20) & 0b111111) == 32) if (((inst >> 20) & 0b111111) == 32)
op = rv_op_vmv_v_i; op = rv_op_vmv_v_i;
@@ -3532,13 +3437,11 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa)
case 45: op = rv_op_vnsra_wi; break; case 45: op = rv_op_vnsra_wi; break;
case 46: op = rv_op_vnclipu_wi; break; case 46: op = rv_op_vnclipu_wi; break;
case 47: op = rv_op_vnclip_wi; break; case 47: op = rv_op_vnclip_wi; break;
case 53: op = rv_op_vwsll_vi; break;
} }
break; break;
case 4: case 4:
switch ((inst >> 26) & 0b111111) { switch ((inst >> 26) & 0b111111) {
case 0: op = rv_op_vadd_vx; break; case 0: op = rv_op_vadd_vx; break;
case 1: op = rv_op_vandn_vx; break;
case 2: op = rv_op_vsub_vx; break; case 2: op = rv_op_vsub_vx; break;
case 3: op = rv_op_vrsub_vx; break; case 3: op = rv_op_vrsub_vx; break;
case 4: op = rv_op_vminu_vx; break; case 4: op = rv_op_vminu_vx; break;
@@ -3563,8 +3466,6 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa)
} }
break; break;
case 19: op = rv_op_vmsbc_vxm; break; case 19: op = rv_op_vmsbc_vxm; break;
case 20: op = rv_op_vror_vx; break;
case 21: op = rv_op_vrol_vx; break;
case 23: case 23:
if (((inst >> 20) & 0b111111) == 32) if (((inst >> 20) & 0b111111) == 32)
op = rv_op_vmv_v_x; op = rv_op_vmv_v_x;
@@ -3593,7 +3494,6 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa)
case 45: op = rv_op_vnsra_wx; break; case 45: op = rv_op_vnsra_wx; break;
case 46: op = rv_op_vnclipu_wx; break; case 46: op = rv_op_vnclipu_wx; break;
case 47: op = rv_op_vnclip_wx; break; case 47: op = rv_op_vnclip_wx; break;
case 53: op = rv_op_vwsll_vx; break;
} }
break; break;
case 5: case 5:
@@ -3654,8 +3554,6 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa)
case 9: op = rv_op_vaadd_vx; break; case 9: op = rv_op_vaadd_vx; break;
case 10: op = rv_op_vasubu_vx; break; case 10: op = rv_op_vasubu_vx; break;
case 11: op = rv_op_vasub_vx; break; case 11: op = rv_op_vasub_vx; break;
case 12: op = rv_op_vclmul_vx; break;
case 13: op = rv_op_vclmulh_vx; break;
case 14: op = rv_op_vslide1up_vx; break; case 14: op = rv_op_vslide1up_vx; break;
case 15: op = rv_op_vslide1down_vx; break; case 15: op = rv_op_vslide1down_vx; break;
case 16: case 16:
@@ -3788,41 +3686,6 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa)
case 7: op = rv_op_csrrci; break; case 7: op = rv_op_csrrci; break;
} }
break; break;
case 29:
if (((inst >> 25) & 1) == 1 && ((inst >> 12) & 0b111) == 2) {
switch ((inst >> 26) & 0b111111) {
case 32: op = rv_op_vsm3me_vv; break;
case 33: op = rv_op_vsm4k_vi; break;
case 34: op = rv_op_vaeskf1_vi; break;
case 40:
switch ((inst >> 15) & 0b11111) {
case 0: op = rv_op_vaesdm_vv; break;
case 1: op = rv_op_vaesdf_vv; break;
case 2: op = rv_op_vaesem_vv; break;
case 3: op = rv_op_vaesef_vv; break;
case 16: op = rv_op_vsm4r_vv; break;
case 17: op = rv_op_vgmul_vv; break;
}
break;
case 41:
switch ((inst >> 15) & 0b11111) {
case 0: op = rv_op_vaesdm_vs; break;
case 1: op = rv_op_vaesdf_vs; break;
case 2: op = rv_op_vaesem_vs; break;
case 3: op = rv_op_vaesef_vs; break;
case 7: op = rv_op_vaesz_vs; break;
case 16: op = rv_op_vsm4r_vs; break;
}
break;
case 42: op = rv_op_vaeskf2_vi; break;
case 43: op = rv_op_vsm3c_vi; break;
case 44: op = rv_op_vghsh_vv; break;
case 45: op = rv_op_vsha2ms_vv; break;
case 46: op = rv_op_vsha2ch_vv; break;
case 47: op = rv_op_vsha2cl_vv; break;
}
}
break;
case 30: case 30:
switch (((inst >> 22) & 0b1111111000) | switch (((inst >> 22) & 0b1111111000) |
((inst >> 12) & 0b0000000111)) { ((inst >> 12) & 0b0000000111)) {
@@ -4148,12 +4011,6 @@ static uint32_t operand_vzimm10(rv_inst inst)
return (inst << 34) >> 54; return (inst << 34) >> 54;
} }
static uint32_t operand_vzimm6(rv_inst inst)
{
return ((inst << 37) >> 63) << 5 |
((inst << 44) >> 59);
}
static uint32_t operand_bs(rv_inst inst) static uint32_t operand_bs(rv_inst inst)
{ {
return (inst << 32) >> 62; return (inst << 32) >> 62;
@@ -4536,12 +4393,6 @@ static void decode_inst_operands(rv_decode *dec, rv_isa isa)
dec->imm = operand_vimm(inst); dec->imm = operand_vimm(inst);
dec->vm = operand_vm(inst); dec->vm = operand_vm(inst);
break; break;
case rv_codec_vror_vi:
dec->rd = operand_rd(inst);
dec->rs2 = operand_rs2(inst);
dec->imm = operand_vzimm6(inst);
dec->vm = operand_vm(inst);
break;
case rv_codec_vsetvli: case rv_codec_vsetvli:
dec->rd = operand_rd(inst); dec->rd = operand_rd(inst);
dec->rs1 = operand_rs1(inst); dec->rs1 = operand_rs1(inst);
@@ -4826,7 +4677,7 @@ static void format_inst(char *buf, size_t buflen, size_t tab, rv_decode *dec)
append(buf, tmp, buflen); append(buf, tmp, buflen);
break; break;
case 'u': case 'u':
snprintf(tmp, sizeof(tmp), "%u", ((uint32_t)dec->imm & 0b111111)); snprintf(tmp, sizeof(tmp), "%u", ((uint32_t)dec->imm & 0b11111));
append(buf, tmp, buflen); append(buf, tmp, buflen);
break; break;
case 'j': case 'j':

View File

@@ -152,7 +152,6 @@ typedef enum {
rv_codec_v_i, rv_codec_v_i,
rv_codec_vsetvli, rv_codec_vsetvli,
rv_codec_vsetivli, rv_codec_vsetivli,
rv_codec_vror_vi,
rv_codec_zcb_ext, rv_codec_zcb_ext,
rv_codec_zcb_mul, rv_codec_zcb_mul,
rv_codec_zcb_lb, rv_codec_zcb_lb,
@@ -275,7 +274,6 @@ enum {
#define rv_fmt_vd_vs2_fs1_vm "O\tD,F,4m" #define rv_fmt_vd_vs2_fs1_vm "O\tD,F,4m"
#define rv_fmt_vd_vs2_imm_vl "O\tD,F,il" #define rv_fmt_vd_vs2_imm_vl "O\tD,F,il"
#define rv_fmt_vd_vs2_imm_vm "O\tD,F,im" #define rv_fmt_vd_vs2_imm_vm "O\tD,F,im"
#define rv_fmt_vd_vs2_uimm "O\tD,F,u"
#define rv_fmt_vd_vs2_uimm_vm "O\tD,F,um" #define rv_fmt_vd_vs2_uimm_vm "O\tD,F,um"
#define rv_fmt_vd_vs1_vs2_vm "O\tD,E,Fm" #define rv_fmt_vd_vs1_vs2_vm "O\tD,E,Fm"
#define rv_fmt_vd_rs1_vs2_vm "O\tD,1,Fm" #define rv_fmt_vd_rs1_vs2_vm "O\tD,1,Fm"

View File

@@ -247,14 +247,6 @@ deprecated; use the new name ``dtb-randomness`` instead. The new name
better reflects the way this property affects all random data within better reflects the way this property affects all random data within
the device tree blob, not just the ``kaslr-seed`` node. the device tree blob, not just the ``kaslr-seed`` node.
``pc-i440fx-2.0`` up to ``pc-i440fx-2.3`` (since 8.2)
'''''''''''''''''''''''''''''''''''''''''''''''''''''
These old machine types are quite neglected nowadays and thus might have
various pitfalls with regards to live migration. Use a newer machine type
instead.
Backend options Backend options
--------------- ---------------
@@ -413,18 +405,6 @@ Specifying the iSCSI password in plain text on the command line using the
used instead, to refer to a ``--object secret...`` instance that provides used instead, to refer to a ``--object secret...`` instance that provides
a password via a file, or encrypted. a password via a file, or encrypted.
CPU device properties
'''''''''''''''''''''
``pmu-num=n`` on RISC-V CPUs (since 8.2)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In order to support more flexible counter configurations this has been replaced
by a ``pmu-mask`` property. If set of counters is continuous then the mask can
be calculated with ``((2 ^ n) - 1) << 3``. The least significant three bits
must be left clear.
Backwards compatibility Backwards compatibility
----------------------- -----------------------
@@ -481,38 +461,3 @@ Migration
``skipped`` field in Migration stats has been deprecated. It hasn't ``skipped`` field in Migration stats has been deprecated. It hasn't
been used for more than 10 years. been used for more than 10 years.
``inc`` migrate command option (since 8.2)
''''''''''''''''''''''''''''''''''''''''''
Use blockdev-mirror with NBD instead.
As an intermediate step the ``inc`` functionality can be achieved by
setting the ``block-incremental`` migration parameter to ``true``.
But this parameter is also deprecated.
``blk`` migrate command option (since 8.2)
''''''''''''''''''''''''''''''''''''''''''
Use blockdev-mirror with NBD instead.
As an intermediate step the ``blk`` functionality can be achieved by
setting the ``block`` migration capability to ``true``. But this
capability is also deprecated.
block migration (since 8.2)
'''''''''''''''''''''''''''
Block migration is too inflexible. It needs to migrate all block
devices or none.
Please see "QMP invocation for live storage migration with
``blockdev-mirror`` + NBD" in docs/interop/live-block-operations.rst
for a detailed explanation.
old compression method (since 8.2)
''''''''''''''''''''''''''''''''''
Compression method fails too much. Too many races. We are going to
remove it if nobody fixes it. For starters, migration-test
compression tests are disabled becase they fail randomly. If you need
compression, use multifd compression methods.

View File

@@ -11,7 +11,6 @@ generated from in-code annotations to function prototypes.
loads-stores loads-stores
memory memory
modules modules
pci
qom-api qom-api
qdev-api qdev-api
ui ui

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