This commit is contained in:
Andrea Fioraldi 2023-10-25 11:36:37 +02:00
commit d86aae8ed9
1127 changed files with 33393 additions and 19056 deletions

View File

@ -30,6 +30,7 @@ avocado-system-alpine:
variables: variables:
IMAGE: alpine IMAGE: alpine
MAKE_CHECK_ARGS: check-avocado MAKE_CHECK_ARGS: check-avocado
AVOCADO_TAGS: arch:avr arch:loongarch64 arch:mips64 arch:mipsel
build-system-ubuntu: build-system-ubuntu:
extends: extends:
@ -40,8 +41,7 @@ build-system-ubuntu:
variables: variables:
IMAGE: ubuntu2204 IMAGE: ubuntu2204
CONFIGURE_ARGS: --enable-docs CONFIGURE_ARGS: --enable-docs
TARGETS: alpha-softmmu cris-softmmu hppa-softmmu TARGETS: alpha-softmmu microblazeel-softmmu mips64el-softmmu
microblazeel-softmmu mips64el-softmmu
MAKE_CHECK_ARGS: check-build MAKE_CHECK_ARGS: check-build
check-system-ubuntu: check-system-ubuntu:
@ -61,6 +61,7 @@ avocado-system-ubuntu:
variables: variables:
IMAGE: ubuntu2204 IMAGE: ubuntu2204
MAKE_CHECK_ARGS: check-avocado MAKE_CHECK_ARGS: check-avocado
AVOCADO_TAGS: arch:alpha arch:microblaze arch:mips64el
build-system-debian: build-system-debian:
extends: extends:
@ -72,7 +73,7 @@ build-system-debian:
IMAGE: debian-amd64 IMAGE: debian-amd64
CONFIGURE_ARGS: --with-coroutine=sigaltstack CONFIGURE_ARGS: --with-coroutine=sigaltstack
TARGETS: arm-softmmu i386-softmmu riscv64-softmmu sh4eb-softmmu TARGETS: arm-softmmu i386-softmmu riscv64-softmmu sh4eb-softmmu
sparc-softmmu xtensaeb-softmmu sparc-softmmu xtensa-softmmu
MAKE_CHECK_ARGS: check-build MAKE_CHECK_ARGS: check-build
check-system-debian: check-system-debian:
@ -92,6 +93,7 @@ avocado-system-debian:
variables: variables:
IMAGE: debian-amd64 IMAGE: debian-amd64
MAKE_CHECK_ARGS: check-avocado MAKE_CHECK_ARGS: check-avocado
AVOCADO_TAGS: arch:arm arch:i386 arch:riscv64 arch:sh4 arch:sparc arch:xtensa
crash-test-debian: crash-test-debian:
extends: .native_test_job_template extends: .native_test_job_template
@ -114,7 +116,7 @@ build-system-fedora:
variables: variables:
IMAGE: fedora IMAGE: fedora
CONFIGURE_ARGS: --disable-gcrypt --enable-nettle --enable-docs CONFIGURE_ARGS: --disable-gcrypt --enable-nettle --enable-docs
TARGETS: tricore-softmmu microblaze-softmmu mips-softmmu TARGETS: microblaze-softmmu mips-softmmu
xtensa-softmmu m68k-softmmu riscv32-softmmu ppc-softmmu sparc64-softmmu xtensa-softmmu m68k-softmmu riscv32-softmmu ppc-softmmu sparc64-softmmu
MAKE_CHECK_ARGS: check-build MAKE_CHECK_ARGS: check-build
@ -135,6 +137,8 @@ avocado-system-fedora:
variables: variables:
IMAGE: fedora IMAGE: fedora
MAKE_CHECK_ARGS: check-avocado MAKE_CHECK_ARGS: check-avocado
AVOCADO_TAGS: arch:microblaze arch:mips arch:xtensa arch:m68k
arch:riscv32 arch:ppc arch:sparc64
crash-test-fedora: crash-test-fedora:
extends: .native_test_job_template extends: .native_test_job_template
@ -180,6 +184,8 @@ avocado-system-centos:
variables: variables:
IMAGE: centos8 IMAGE: centos8
MAKE_CHECK_ARGS: check-avocado MAKE_CHECK_ARGS: check-avocado
AVOCADO_TAGS: arch:ppc64 arch:or1k arch:390x arch:x86_64 arch:rx
arch:sh4 arch:nios2
build-system-opensuse: build-system-opensuse:
extends: extends:
@ -209,6 +215,7 @@ avocado-system-opensuse:
variables: variables:
IMAGE: opensuse-leap IMAGE: opensuse-leap
MAKE_CHECK_ARGS: check-avocado MAKE_CHECK_ARGS: check-avocado
AVOCADO_TAGS: arch:s390x arch:x86_64 arch:aarch64
# This jobs explicitly disable TCG (--disable-tcg), KVM is detected by # This jobs explicitly disable TCG (--disable-tcg), KVM is detected by

View File

@ -11,6 +11,6 @@ MAKE='/opt/homebrew/bin/gmake'
NINJA='/opt/homebrew/bin/ninja' NINJA='/opt/homebrew/bin/ninja'
PACKAGING_COMMAND='brew' PACKAGING_COMMAND='brew'
PIP3='/opt/homebrew/bin/pip3' PIP3='/opt/homebrew/bin/pip3'
PKGS='bash bc bison bzip2 capstone ccache cmocka ctags curl dbus diffutils dtc flex gcovr gettext git glib gnu-sed gnutls gtk+3 jemalloc jpeg-turbo json-c libepoxy libffi libgcrypt libiscsi libnfs libpng libslirp libssh libtasn1 libusb llvm lzo make meson mtools ncurses nettle ninja pixman pkg-config python3 rpm2cpio sdl2 sdl2_image snappy socat sparse spice-protocol tesseract usbredir vde vte3 xorriso zlib zstd' PKGS='bash bc bison bzip2 capstone ccache cmocka ctags curl dbus diffutils dtc flex gcovr gettext git glib gnu-sed gnutls gtk+3 jemalloc jpeg-turbo json-c libepoxy libffi libgcrypt libiscsi libnfs libpng libslirp libssh libtasn1 libusb llvm lzo make meson mtools ncurses nettle ninja pixman pkg-config python3 rpm2cpio sdl2 sdl2_image snappy socat sparse spice-protocol swtpm tesseract usbredir vde vte3 xorriso zlib zstd'
PYPI_PKGS='PyYAML numpy pillow sphinx sphinx-rtd-theme tomli' PYPI_PKGS='PyYAML numpy pillow sphinx sphinx-rtd-theme tomli'
PYTHON='/opt/homebrew/bin/python3' PYTHON='/opt/homebrew/bin/python3'

View File

@ -95,6 +95,7 @@ riscv64-debian-cross-container:
allow_failure: true allow_failure: true
variables: variables:
NAME: debian-riscv64-cross NAME: debian-riscv64-cross
QEMU_JOB_OPTIONAL: 1
# we can however build TCG tests using a non-sid base # we can however build TCG tests using a non-sid base
riscv64-debian-test-cross-container: riscv64-debian-test-cross-container:

View File

@ -40,12 +40,26 @@ Nick Hudson <hnick@vmware.com> hnick@vmware.com <hnick@vmware.com>
# for the cvs2svn initialization commit e63c3dc74bf. # for the cvs2svn initialization commit e63c3dc74bf.
# Next, translate a few commits where mailman rewrote the From: line due # Next, translate a few commits where mailman rewrote the From: line due
# to strict SPF, although we prefer to avoid adding more entries like that. # to strict SPF and DMARC. Usually, our build process should be flagging
# commits like these before maintainer merges; if you find the need to add
# a line here, please also report a bug against the part of the build
# process that let the mis-attribution slip through in the first place.
#
# If the mailing list munges your emails, use:
# git config sendemail.from '"Your Name" <your.email@example.com>'
# the use of "" in that line will differ from the typically unquoted
# 'git config user.name', which in turn is sufficient for 'git send-email'
# to add an extra From: line in the body of your email that takes
# precedence over any munged From: in the mail's headers.
# See https://lists.openembedded.org/g/openembedded-core/message/166515
# and https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg06784.html
Ed Swierk <eswierk@skyportsystems.com> Ed Swierk via Qemu-devel <qemu-devel@nongnu.org> Ed Swierk <eswierk@skyportsystems.com> Ed Swierk via Qemu-devel <qemu-devel@nongnu.org>
Ian McKellar <ianloic@google.com> Ian McKellar via Qemu-devel <qemu-devel@nongnu.org> Ian McKellar <ianloic@google.com> Ian McKellar via Qemu-devel <qemu-devel@nongnu.org>
Julia Suvorova <jusual@mail.ru> Julia Suvorova via Qemu-devel <qemu-devel@nongnu.org> Julia Suvorova <jusual@mail.ru> Julia Suvorova via Qemu-devel <qemu-devel@nongnu.org>
Justin Terry (VM) <juterry@microsoft.com> Justin Terry (VM) via Qemu-devel <qemu-devel@nongnu.org> Justin Terry (VM) <juterry@microsoft.com> Justin Terry (VM) via Qemu-devel <qemu-devel@nongnu.org>
Stefan Weil <sw@weilnetz.de> Stefan Weil via <qemu-devel@nongnu.org> Stefan Weil <sw@weilnetz.de> Stefan Weil via <qemu-devel@nongnu.org>
Andrey Drobyshev <andrey.drobyshev@virtuozzo.com> Andrey Drobyshev via <qemu-block@nongnu.org>
BALATON Zoltan <balaton@eik.bme.hu> BALATON Zoltan via <qemu-ppc@nongnu.org>
# Next, replace old addresses by a more recent one. # Next, replace old addresses by a more recent one.
Aleksandar Markovic <aleksandar.qemu.devel@gmail.com> <aleksandar.markovic@mips.com> Aleksandar Markovic <aleksandar.qemu.devel@gmail.com> <aleksandar.markovic@mips.com>
@ -67,6 +81,9 @@ 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

@ -34,7 +34,7 @@ env:
- BASE_CONFIG="--disable-docs --disable-tools" - BASE_CONFIG="--disable-docs --disable-tools"
- TEST_BUILD_CMD="" - TEST_BUILD_CMD=""
- TEST_CMD="make check V=1" - TEST_CMD="make check V=1"
# This is broadly a list of "mainline" softmmu targets which have support across the major distros # This is broadly a list of "mainline" system targets which have support across the major distros
- MAIN_SOFTMMU_TARGETS="aarch64-softmmu,mips64-softmmu,ppc64-softmmu,riscv64-softmmu,s390x-softmmu,x86_64-softmmu" - MAIN_SOFTMMU_TARGETS="aarch64-softmmu,mips64-softmmu,ppc64-softmmu,riscv64-softmmu,s390x-softmmu,x86_64-softmmu"
- CCACHE_SLOPPINESS="include_file_ctime,include_file_mtime" - CCACHE_SLOPPINESS="include_file_ctime,include_file_mtime"
- CCACHE_MAXSIZE=1G - CCACHE_MAXSIZE=1G
@ -197,7 +197,7 @@ jobs:
$(exit $BUILD_RC); $(exit $BUILD_RC);
fi fi
- name: "[s390x] GCC (other-softmmu)" - name: "[s390x] GCC (other-system)"
arch: s390x arch: s390x
dist: focal dist: focal
addons: addons:

View File

@ -137,10 +137,11 @@ Overall TCG CPUs
M: Richard Henderson <richard.henderson@linaro.org> M: Richard Henderson <richard.henderson@linaro.org>
R: Paolo Bonzini <pbonzini@redhat.com> R: Paolo Bonzini <pbonzini@redhat.com>
S: Maintained S: Maintained
F: softmmu/cpus.c F: system/cpus.c
F: softmmu/watchpoint.c F: system/watchpoint.c
F: cpus-common.c F: cpu-common.c
F: page-vary.c F: cpu-target.c
F: page-vary-target.c
F: page-vary-common.c F: page-vary-common.c
F: accel/tcg/ F: accel/tcg/
F: accel/stubs/tcg-stub.c F: accel/stubs/tcg-stub.c
@ -244,10 +245,10 @@ 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>
M: Xiaojuan Yang <yangxiaojuan@loongson.cn>
S: Maintained S: Maintained
F: target/loongarch/ F: target/loongarch/
F: tests/tcg/loongarch64/ F: tests/tcg/loongarch64/
@ -258,6 +259,7 @@ 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>
@ -284,7 +286,9 @@ 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/
@ -295,6 +299,7 @@ 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
@ -307,6 +312,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>
@ -317,11 +328,15 @@ 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
S: Supported S: Supported
F: configs/targets/riscv*
F: docs/system/target-riscv.rst
F: target/riscv/ F: target/riscv/
F: hw/riscv/ F: hw/riscv/
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>
@ -330,6 +345,7 @@ L: qemu-riscv@nongnu.org
S: Supported S: Supported
F: target/riscv/insn_trans/trans_xthead.c.inc F: target/riscv/insn_trans/trans_xthead.c.inc
F: target/riscv/xthead*.decode F: target/riscv/xthead*.decode
F: disas/riscv-xthead*
RISC-V XVentanaCondOps extension RISC-V XVentanaCondOps extension
M: Philipp Tomsich <philipp.tomsich@vrull.eu> M: Philipp Tomsich <philipp.tomsich@vrull.eu>
@ -337,6 +353,7 @@ L: qemu-riscv@nongnu.org
S: Maintained S: Maintained
F: target/riscv/XVentanaCondOps.decode F: target/riscv/XVentanaCondOps.decode
F: target/riscv/insn_trans/trans_xventanacondops.c.inc F: target/riscv/insn_trans/trans_xventanacondops.c.inc
F: disas/riscv-xventana*
RENESAS RX CPUs RENESAS RX CPUs
R: Yoshinori Sato <ysato@users.sourceforge.jp> R: Yoshinori Sato <ysato@users.sourceforge.jp>
@ -361,6 +378,7 @@ 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>
@ -371,6 +389,7 @@ 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>
@ -556,6 +575,7 @@ M: Cornelia Huck <cohuck@redhat.com>
M: Paolo Bonzini <pbonzini@redhat.com> M: Paolo Bonzini <pbonzini@redhat.com>
S: Maintained S: Maintained
F: linux-headers/ F: linux-headers/
F: include/standard-headers/
F: scripts/update-linux-headers.sh F: scripts/update-linux-headers.sh
POSIX POSIX
@ -879,7 +899,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/raspi* F: include/hw/arm/rasp*
F: include/hw/*/bcm283* F: include/hw/*/bcm283*
F: docs/system/arm/raspi.rst F: docs/system/arm/raspi.rst
@ -938,6 +958,9 @@ R: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org>
L: qemu-arm@nongnu.org L: qemu-arm@nongnu.org
S: Maintained S: Maintained
F: hw/arm/sbsa-ref.c F: hw/arm/sbsa-ref.c
F: hw/misc/sbsa_ec.c
F: hw/watchdog/sbsa_gwdt.c
F: include/hw/watchdog/sbsa_gwdt.h
F: docs/system/arm/sbsa.rst F: docs/system/arm/sbsa.rst
F: tests/avocado/machine_aarch64_sbsaref.py F: tests/avocado/machine_aarch64_sbsaref.py
@ -1164,24 +1187,28 @@ F: hw/*/etraxfs_*.c
HP-PARISC Machines HP-PARISC Machines
------------------ ------------------
HP B160L HP B160L, HP C3700
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/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
------------------ ------------------
Virt Virt
M: Xiaojuan Yang <yangxiaojuan@loongson.cn>
M: Song Gao <gaosong@loongson.cn> M: Song Gao <gaosong@loongson.cn>
S: Maintained S: Maintained
F: docs/system/loongarch/virt.rst F: docs/system/loongarch/virt.rst
@ -1228,6 +1255,9 @@ F: hw/misc/mac_via.c
F: hw/nubus/* F: hw/nubus/*
F: hw/display/macfb.c F: hw/display/macfb.c
F: hw/block/swim.c F: hw/block/swim.c
F: hw/misc/djmemc.c
F: hw/misc/iosb.c
F: hw/audio/asc.c
F: hw/m68k/bootinfo.h F: hw/m68k/bootinfo.h
F: include/standard-headers/asm-m68k/bootinfo.h F: include/standard-headers/asm-m68k/bootinfo.h
F: include/standard-headers/asm-m68k/bootinfo-mac.h F: include/standard-headers/asm-m68k/bootinfo-mac.h
@ -1237,6 +1267,9 @@ F: include/hw/display/macfb.h
F: include/hw/block/swim.h F: include/hw/block/swim.h
F: include/hw/m68k/q800.h F: include/hw/m68k/q800.h
F: include/hw/m68k/q800-glue.h F: include/hw/m68k/q800-glue.h
F: include/hw/misc/djmemc.h
F: include/hw/misc/iosb.h
F: include/hw/audio/asc.h
virt virt
M: Laurent Vivier <laurent@vivier.eu> M: Laurent Vivier <laurent@vivier.eu>
@ -1279,14 +1312,16 @@ M: Hervé Poussineau <hpoussin@reactos.org>
R: Aleksandar Rikalo <aleksandar.rikalo@syrmia.com> R: Aleksandar Rikalo <aleksandar.rikalo@syrmia.com>
S: Maintained S: Maintained
F: hw/mips/jazz.c F: hw/mips/jazz.c
F: hw/display/g364fb.c
F: hw/display/jazz_led.c F: hw/display/jazz_led.c
F: hw/dma/rc4030.c F: hw/dma/rc4030.c
F: hw/nvram/ds1225y.c
Malta 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/piix4.c F: hw/isa/piix.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
@ -1306,10 +1341,7 @@ 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
@ -1321,6 +1353,7 @@ F: hw/intc/loongson_liointc.c
F: hw/mips/loongson3_bootp.c F: hw/mips/loongson3_bootp.c
F: hw/mips/loongson3_bootp.h F: hw/mips/loongson3_bootp.h
F: hw/mips/loongson3_virt.c F: hw/mips/loongson3_virt.c
F: include/hw/intc/loongson_liointc.h
F: tests/avocado/machine_mips_loongson3v.py F: tests/avocado/machine_mips_loongson3v.py
Boston Boston
@ -1338,6 +1371,7 @@ 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
@ -1345,7 +1379,8 @@ PowerPC Machines
405 (ref405ep) 405 (ref405ep)
L: qemu-ppc@nongnu.org L: qemu-ppc@nongnu.org
S: Orphan S: Orphan
F: hw/ppc/ppc405_boards.c F: hw/ppc/ppc405*
F: tests/avocado/ppc_405.py
Bamboo Bamboo
L: qemu-ppc@nongnu.org L: qemu-ppc@nongnu.org
@ -1357,6 +1392,7 @@ 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/
@ -1364,8 +1400,9 @@ F: hw/pci-host/ppce500.c
F: include/hw/ppc/ppc_e500.h F: include/hw/ppc/ppc_e500.h
F: include/hw/pci-host/ppce500.h F: include/hw/pci-host/ppce500.h
F: pc-bios/u-boot.e500 F: pc-bios/u-boot.e500
F: hw/intc/openpic_kvm.h F: hw/intc/openpic_kvm.c
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
@ -1385,6 +1422,7 @@ 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
@ -1438,6 +1476,10 @@ 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-*
@ -1475,6 +1517,7 @@ 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
@ -1518,6 +1561,7 @@ Microchip PolarFire SoC Icicle Kit
M: Bin Meng <bin.meng@windriver.com> M: Bin Meng <bin.meng@windriver.com>
L: qemu-riscv@nongnu.org L: qemu-riscv@nongnu.org
S: Supported S: Supported
F: docs/system/riscv/microchip-icicle-kit.rst
F: hw/riscv/microchip_pfsoc.c F: hw/riscv/microchip_pfsoc.c
F: hw/char/mchp_pfsoc_mmuart.c F: hw/char/mchp_pfsoc_mmuart.c
F: hw/misc/mchp_pfsoc_dmc.c F: hw/misc/mchp_pfsoc_dmc.c
@ -1533,6 +1577,7 @@ Shakti C class SoC
M: Vijai Kumar K <vijai@behindbytes.com> M: Vijai Kumar K <vijai@behindbytes.com>
L: qemu-riscv@nongnu.org L: qemu-riscv@nongnu.org
S: Supported S: Supported
F: docs/system/riscv/shakti-c.rst
F: hw/riscv/shakti_c.c F: hw/riscv/shakti_c.c
F: hw/char/shakti_uart.c F: hw/char/shakti_uart.c
F: include/hw/riscv/shakti_c.h F: include/hw/riscv/shakti_c.h
@ -1544,6 +1589,7 @@ M: Bin Meng <bin.meng@windriver.com>
M: Palmer Dabbelt <palmer@dabbelt.com> M: Palmer Dabbelt <palmer@dabbelt.com>
L: qemu-riscv@nongnu.org L: qemu-riscv@nongnu.org
S: Supported S: Supported
F: docs/system/riscv/sifive_u.rst
F: hw/*/*sifive*.c F: hw/*/*sifive*.c
F: include/hw/*/*sifive*.h F: include/hw/*/*sifive*.h
@ -1691,6 +1737,16 @@ 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
@ -1705,7 +1761,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/piix3.c F: hw/isa/piix.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
@ -1745,6 +1801,7 @@ 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
@ -1766,7 +1823,6 @@ M: Marcel Apfelbaum <marcel.apfelbaum@gmail.com>
R: Philippe Mathieu-Daudé <philmd@linaro.org> R: Philippe Mathieu-Daudé <philmd@linaro.org>
R: Yanan Wang <wangyanan55@huawei.com> R: Yanan Wang <wangyanan55@huawei.com>
S: Supported S: Supported
F: cpu.c
F: hw/core/cpu.c F: hw/core/cpu.c
F: hw/core/machine-qmp-cmds.c F: hw/core/machine-qmp-cmds.c
F: hw/core/machine.c F: hw/core/machine.c
@ -1775,6 +1831,7 @@ 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
@ -1960,7 +2017,9 @@ 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/ppc4*.c F: hw/ppc/ppc4xx*.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
@ -1972,6 +2031,7 @@ M: Marc-André Lureau <marcandre.lureau@redhat.com>
R: Paolo Bonzini <pbonzini@redhat.com> R: Paolo Bonzini <pbonzini@redhat.com>
S: Odd Fixes S: Odd Fixes
F: hw/char/ F: hw/char/
F: include/hw/char/
Network devices Network devices
M: Jason Wang <jasowang@redhat.com> M: Jason Wang <jasowang@redhat.com>
@ -2108,7 +2168,7 @@ S: Maintained
F: docs/interop/virtio-balloon-stats.rst F: docs/interop/virtio-balloon-stats.rst
F: hw/virtio/virtio-balloon*.c F: hw/virtio/virtio-balloon*.c
F: include/hw/virtio/virtio-balloon.h F: include/hw/virtio/virtio-balloon.h
F: softmmu/balloon.c F: system/balloon.c
F: include/sysemu/balloon.h F: include/sysemu/balloon.h
virtio-9p virtio-9p
@ -2154,6 +2214,13 @@ T: git https://gitlab.com/cohuck/qemu.git s390-next
T: git https://github.com/borntraeger/qemu.git s390-next T: git https://github.com/borntraeger/qemu.git s390-next
L: qemu-s390x@nongnu.org L: qemu-s390x@nongnu.org
virtio-dmabuf
M: Albert Esteve <aesteve@redhat.com>
S: Supported
F: hw/display/virtio-dmabuf.c
F: include/hw/virtio/virtio-dmabuf.h
F: tests/unit/test-virtio-dmabuf.c
virtiofs virtiofs
M: Stefan Hajnoczi <stefanha@redhat.com> M: Stefan Hajnoczi <stefanha@redhat.com>
S: Supported S: Supported
@ -2452,9 +2519,18 @@ 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/piix4.c F: hw/isa/piix.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>
@ -2548,7 +2624,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/390x/s390-skeys*.c F: hw/s390x/s390-skeys*.c
L: qemu-s390x@nongnu.org L: qemu-s390x@nongnu.org
S390 storage attribute device S390 storage attribute device
@ -2556,7 +2632,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/s390/s390-stattrib*.c F: hw/s390x/s390-stattrib*.c
L: qemu-s390x@nongnu.org L: qemu-s390x@nongnu.org
S390 floating interrupt controller S390 floating interrupt controller
@ -2788,7 +2864,7 @@ Device Tree
M: Alistair Francis <alistair.francis@wdc.com> M: Alistair Francis <alistair.francis@wdc.com>
R: David Gibson <david@gibson.dropbear.id.au> R: David Gibson <david@gibson.dropbear.id.au>
S: Maintained S: Maintained
F: softmmu/device_tree.c F: system/device_tree.c
F: include/sysemu/device_tree.h F: include/sysemu/device_tree.h
Dump Dump
@ -2829,7 +2905,7 @@ 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.sh F: scripts/feature_to_c.py
F: scripts/probe-gdb-support.py F: scripts/probe-gdb-support.py
Memory API Memory API
@ -2844,11 +2920,11 @@ F: include/exec/memory.h
F: include/exec/ram_addr.h F: include/exec/ram_addr.h
F: include/exec/ramblock.h F: include/exec/ramblock.h
F: include/sysemu/memory_mapping.h F: include/sysemu/memory_mapping.h
F: softmmu/dma-helpers.c F: system/dma-helpers.c
F: softmmu/ioport.c F: system/ioport.c
F: softmmu/memory.c F: system/memory.c
F: softmmu/memory_mapping.c F: system/memory_mapping.c
F: softmmu/physmem.c F: system/physmem.c
F: include/exec/memory-internal.h F: include/exec/memory-internal.h
F: scripts/coccinelle/memory-region-housekeeping.cocci F: scripts/coccinelle/memory-region-housekeeping.cocci
@ -2863,6 +2939,7 @@ F: hw/mem/pc-dimm.c
F: include/hw/mem/memory-device.h F: include/hw/mem/memory-device.h
F: include/hw/mem/nvdimm.h F: include/hw/mem/nvdimm.h
F: include/hw/mem/pc-dimm.h F: include/hw/mem/pc-dimm.h
F: stubs/memory_device.c
F: docs/nvdimm.txt F: docs/nvdimm.txt
SPICE SPICE
@ -2900,14 +2977,13 @@ 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: softmmu/vl.c F: system/vl.c
F: softmmu/main.c F: system/main.c
F: softmmu/cpus.c F: system/cpus.c
F: softmmu/cpu-throttle.c F: system/cpu-throttle.c
F: softmmu/cpu-timers.c F: system/cpu-timers.c
F: softmmu/icount.c F: system/runstate*
F: softmmu/runstate*
F: qapi/run-state.json F: qapi/run-state.json
Read, Copy, Update (RCU) Read, Copy, Update (RCU)
@ -3081,7 +3157,7 @@ F: qapi/qom.json
F: qapi/qdev.json F: qapi/qdev.json
F: scripts/coccinelle/qom-parent-type.cocci F: scripts/coccinelle/qom-parent-type.cocci
F: scripts/qom-cast-macro-clean-cocci-gen.py F: scripts/qom-cast-macro-clean-cocci-gen.py
F: softmmu/qdev-monitor.c F: system/qdev-monitor.c
F: stubs/qdev.c F: stubs/qdev.c
F: qom/ F: qom/
F: tests/unit/check-qom-interface.c F: tests/unit/check-qom-interface.c
@ -3115,7 +3191,8 @@ M: Thomas Huth <thuth@redhat.com>
M: Laurent Vivier <lvivier@redhat.com> M: Laurent Vivier <lvivier@redhat.com>
R: Paolo Bonzini <pbonzini@redhat.com> R: Paolo Bonzini <pbonzini@redhat.com>
S: Maintained S: Maintained
F: softmmu/qtest.c F: system/qtest.c
F: include/sysemu/qtest.h
F: accel/qtest/ F: accel/qtest/
F: tests/qtest/ F: tests/qtest/
F: docs/devel/qgraph.rst F: docs/devel/qgraph.rst
@ -3170,6 +3247,7 @@ F: stubs/
Tracing Tracing
M: Stefan Hajnoczi <stefanha@redhat.com> M: Stefan Hajnoczi <stefanha@redhat.com>
R: Mads Ynddal <mads@ynddal.dk>
S: Maintained S: Maintained
F: trace/ F: trace/
F: trace-events F: trace-events
@ -3182,10 +3260,15 @@ F: docs/tools/qemu-trace-stap.rst
F: docs/devel/tracing.rst F: docs/devel/tracing.rst
T: git https://github.com/stefanha/qemu.git tracing T: git https://github.com/stefanha/qemu.git tracing
Simpletrace
M: Mads Ynddal <mads@ynddal.dk>
S: Maintained
F: scripts/simpletrace.py
TPM TPM
M: Stefan Berger <stefanb@linux.ibm.com> M: Stefan Berger <stefanb@linux.ibm.com>
S: Maintained S: Maintained
F: softmmu/tpm* F: system/tpm*
F: hw/tpm/* F: hw/tpm/*
F: include/hw/acpi/tpm.h F: include/hw/acpi/tpm.h
F: include/sysemu/tpm* F: include/sysemu/tpm*
@ -3201,7 +3284,8 @@ F: scripts/checkpatch.pl
Migration Migration
M: Juan Quintela <quintela@redhat.com> M: Juan Quintela <quintela@redhat.com>
R: Peter Xu <peterx@redhat.com> M: Peter Xu <peterx@redhat.com>
M: Fabiano Rosas <farosas@suse.de>
R: Leonardo Bras <leobras@redhat.com> R: Leonardo Bras <leobras@redhat.com>
S: Maintained S: Maintained
F: hw/core/vmstate-if.c F: hw/core/vmstate-if.c
@ -3216,11 +3300,20 @@ F: docs/devel/migration.rst
F: qapi/migration.json F: qapi/migration.json
F: tests/migration/ F: tests/migration/
F: util/userfaultfd.c F: util/userfaultfd.c
X: migration/rdma*
RDMA Migration
M: Juan Quintela <quintela@redhat.com>
R: Li Zhijian <lizhijian@fujitsu.com>
R: Peter Xu <peterx@redhat.com>
R: Leonardo Bras <leobras@redhat.com>
S: Odd Fixes
F: migration/rdma*
Migration dirty limit and dirty page rate Migration dirty limit and dirty page rate
M: Hyman Huang <yong.huang@smartx.com> M: Hyman Huang <yong.huang@smartx.com>
S: Maintained S: Maintained
F: softmmu/dirtylimit.c F: system/dirtylimit.c
F: include/sysemu/dirtylimit.h F: include/sysemu/dirtylimit.h
F: migration/dirtyrate.c F: migration/dirtyrate.c
F: migration/dirtyrate.h F: migration/dirtyrate.h
@ -3244,7 +3337,7 @@ F: scripts/xml-preprocess*
Seccomp Seccomp
M: Daniel P. Berrange <berrange@redhat.com> M: Daniel P. Berrange <berrange@redhat.com>
S: Odd Fixes S: Odd Fixes
F: softmmu/qemu-seccomp.c F: system/qemu-seccomp.c
F: include/sysemu/seccomp.h F: include/sysemu/seccomp.h
F: tests/unit/test-seccomp.c F: tests/unit/test-seccomp.c
@ -3378,6 +3471,12 @@ M: Viktor Prutyanov <viktor.prutyanov@phystech.edu>
S: Maintained S: Maintained
F: contrib/elf2dmp/ F: contrib/elf2dmp/
Overall sensors
M: Philippe Mathieu-Daudé <philmd@linaro.org>
S: Odd Fixes
F: hw/sensor
F: include/hw/sensor
I2C and SMBus I2C and SMBus
M: Corey Minyard <cminyard@mvista.com> M: Corey Minyard <cminyard@mvista.com>
S: Maintained S: Maintained
@ -3543,7 +3642,7 @@ M: Alistair Francis <Alistair.Francis@wdc.com>
L: qemu-riscv@nongnu.org L: qemu-riscv@nongnu.org
S: Maintained S: Maintained
F: tcg/riscv/ F: tcg/riscv/
F: disas/riscv.c F: disas/riscv.[ch]
S390 TCG target S390 TCG target
M: Richard Henderson <richard.henderson@linaro.org> M: Richard Henderson <richard.henderson@linaro.org>
@ -3663,7 +3762,7 @@ T: git https://github.com/stefanha/qemu.git block
Bootdevice Bootdevice
M: Gonglei <arei.gonglei@huawei.com> M: Gonglei <arei.gonglei@huawei.com>
S: Maintained S: Maintained
F: softmmu/bootdevice.c F: system/bootdevice.c
Quorum Quorum
M: Alberto Garcia <berto@igalia.com> M: Alberto Garcia <berto@igalia.com>
@ -3815,7 +3914,7 @@ F: docs/block-replication.txt
PVRDMA PVRDMA
M: Yuval Shaia <yuval.shaia.ml@gmail.com> M: Yuval Shaia <yuval.shaia.ml@gmail.com>
M: Marcel Apfelbaum <marcel.apfelbaum@gmail.com> M: Marcel Apfelbaum <marcel.apfelbaum@gmail.com>
S: Maintained S: Odd Fixes
F: hw/rdma/* F: hw/rdma/*
F: hw/rdma/vmw/* F: hw/rdma/vmw/*
F: docs/pvrdma.txt F: docs/pvrdma.txt
@ -3863,6 +3962,7 @@ 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/*
@ -3879,6 +3979,7 @@ F: .github/workflows/lockdown.yml
F: .gitlab-ci.yml F: .gitlab-ci.yml
F: .gitlab-ci.d/ F: .gitlab-ci.d/
F: .travis.yml F: .travis.yml
F: docs/devel/ci*
F: scripts/ci/ F: scripts/ci/
F: tests/docker/ F: tests/docker/
F: tests/vm/ F: tests/vm/

View File

@ -28,7 +28,7 @@
#include "hw/boards.h" #include "hw/boards.h"
#include "sysemu/cpus.h" #include "sysemu/cpus.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "accel-softmmu.h" #include "accel-system.h"
int accel_init_machine(AccelState *accel, MachineState *ms) int accel_init_machine(AccelState *accel, MachineState *ms)
{ {
@ -99,8 +99,8 @@ static const TypeInfo accel_ops_type_info = {
.class_size = sizeof(AccelOpsClass), .class_size = sizeof(AccelOpsClass),
}; };
static void accel_softmmu_register_types(void) static void accel_system_register_types(void)
{ {
type_register_static(&accel_ops_type_info); type_register_static(&accel_ops_type_info);
} }
type_init(accel_softmmu_register_types); type_init(accel_system_register_types);

View File

@ -7,9 +7,9 @@
* See the COPYING file in the top-level directory. * See the COPYING file in the top-level directory.
*/ */
#ifndef ACCEL_SOFTMMU_H #ifndef ACCEL_SYSTEM_H
#define ACCEL_SOFTMMU_H #define ACCEL_SYSTEM_H
void accel_init_ops_interfaces(AccelClass *ac); void accel_init_ops_interfaces(AccelClass *ac);
#endif /* ACCEL_SOFTMMU_H */ #endif /* ACCEL_SYSTEM_H */

View File

@ -30,7 +30,7 @@
#include "hw/core/accel-cpu.h" #include "hw/core/accel-cpu.h"
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
#include "accel-softmmu.h" #include "accel-system.h"
#endif /* !CONFIG_USER_ONLY */ #endif /* !CONFIG_USER_ONLY */
static const TypeInfo accel_type = { static const TypeInfo accel_type = {
@ -119,16 +119,37 @@ void accel_cpu_instance_init(CPUState *cpu)
} }
} }
bool accel_cpu_realizefn(CPUState *cpu, Error **errp) bool accel_cpu_common_realize(CPUState *cpu, Error **errp)
{ {
CPUClass *cc = CPU_GET_CLASS(cpu); CPUClass *cc = CPU_GET_CLASS(cpu);
AccelState *accel = current_accel();
AccelClass *acc = ACCEL_GET_CLASS(accel);
if (cc->accel_cpu && cc->accel_cpu->cpu_realizefn) { /* target specific realization */
return cc->accel_cpu->cpu_realizefn(cpu, errp); if (cc->accel_cpu && cc->accel_cpu->cpu_target_realize
&& !cc->accel_cpu->cpu_target_realize(cpu, errp)) {
return false;
} }
/* generic realization */
if (acc->cpu_common_realize && !acc->cpu_common_realize(cpu, errp)) {
return false;
}
return true; return true;
} }
void accel_cpu_common_unrealize(CPUState *cpu)
{
AccelState *accel = current_accel();
AccelClass *acc = ACCEL_GET_CLASS(accel);
/* generic unrealization */
if (acc->cpu_common_unrealize) {
acc->cpu_common_unrealize(cpu);
}
}
int accel_supported_gdbstub_sstep_flags(void) int accel_supported_gdbstub_sstep_flags(void)
{ {
AccelState *accel = current_accel(); AccelState *accel = current_accel();

View File

@ -27,7 +27,7 @@ static void *dummy_cpu_thread_fn(void *arg)
qemu_mutex_lock_iothread(); qemu_mutex_lock_iothread();
qemu_thread_get_self(cpu->thread); qemu_thread_get_self(cpu->thread);
cpu->thread_id = qemu_get_thread_id(); cpu->thread_id = qemu_get_thread_id();
cpu->can_do_io = 1; cpu->neg.can_do_io = true;
current_cpu = cpu; current_cpu = cpu;
#ifndef _WIN32 #ifndef _WIN32

View File

@ -428,7 +428,7 @@ static void *hvf_cpu_thread_fn(void *arg)
qemu_thread_get_self(cpu->thread); qemu_thread_get_self(cpu->thread);
cpu->thread_id = qemu_get_thread_id(); cpu->thread_id = qemu_get_thread_id();
cpu->can_do_io = 1; cpu->neg.can_do_io = true;
current_cpu = cpu; current_cpu = cpu;
hvf_init_vcpu(cpu); hvf_init_vcpu(cpu);

View File

@ -36,7 +36,7 @@ static void *kvm_vcpu_thread_fn(void *arg)
qemu_mutex_lock_iothread(); qemu_mutex_lock_iothread();
qemu_thread_get_self(cpu->thread); qemu_thread_get_self(cpu->thread);
cpu->thread_id = qemu_get_thread_id(); cpu->thread_id = qemu_get_thread_id();
cpu->can_do_io = 1; cpu->neg.can_do_io = true;
current_cpu = cpu; current_cpu = cpu;
r = kvm_init_vcpu(cpu, &error_fatal); r = kvm_init_vcpu(cpu, &error_fatal);

View File

@ -174,13 +174,31 @@ void kvm_resample_fd_notify(int gsi)
} }
} }
int kvm_get_max_memslots(void) unsigned int kvm_get_max_memslots(void)
{ {
KVMState *s = KVM_STATE(current_accel()); KVMState *s = KVM_STATE(current_accel());
return s->nr_slots; return s->nr_slots;
} }
unsigned int kvm_get_free_memslots(void)
{
unsigned int used_slots = 0;
KVMState *s = kvm_state;
int i;
kvm_slots_lock();
for (i = 0; i < s->nr_as; i++) {
if (!s->as[i].ml) {
continue;
}
used_slots = MAX(used_slots, s->as[i].ml->nr_used_slots);
}
kvm_slots_unlock();
return s->nr_slots - used_slots;
}
/* Called with KVMMemoryListener.slots_lock held */ /* Called with KVMMemoryListener.slots_lock held */
static KVMSlot *kvm_get_free_slot(KVMMemoryListener *kml) static KVMSlot *kvm_get_free_slot(KVMMemoryListener *kml)
{ {
@ -196,19 +214,6 @@ static KVMSlot *kvm_get_free_slot(KVMMemoryListener *kml)
return NULL; return NULL;
} }
bool kvm_has_free_slot(MachineState *ms)
{
KVMState *s = KVM_STATE(ms->accelerator);
bool result;
KVMMemoryListener *kml = &s->memory_listener;
kvm_slots_lock();
result = !!kvm_get_free_slot(kml);
kvm_slots_unlock();
return result;
}
/* Called with KVMMemoryListener.slots_lock held */ /* Called with KVMMemoryListener.slots_lock held */
static KVMSlot *kvm_alloc_slot(KVMMemoryListener *kml) static KVMSlot *kvm_alloc_slot(KVMMemoryListener *kml)
{ {
@ -1387,6 +1392,7 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml,
} }
start_addr += slot_size; start_addr += slot_size;
size -= slot_size; size -= slot_size;
kml->nr_used_slots--;
} while (size); } while (size);
return; return;
} }
@ -1412,6 +1418,7 @@ static void kvm_set_phys_mem(KVMMemoryListener *kml,
ram_start_offset += slot_size; ram_start_offset += slot_size;
ram += slot_size; ram += slot_size;
size -= slot_size; size -= slot_size;
kml->nr_used_slots++;
} while (size); } while (size);
} }
@ -2851,7 +2858,13 @@ bool kvm_cpu_check_are_resettable(void)
static void do_kvm_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg) static void do_kvm_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg)
{ {
if (!cpu->vcpu_dirty) { if (!cpu->vcpu_dirty) {
kvm_arch_get_registers(cpu); int ret = kvm_arch_get_registers(cpu);
if (ret) {
error_report("Failed to get registers: %s", strerror(-ret));
cpu_dump_state(cpu, stderr, CPU_DUMP_CODE);
vm_stop(RUN_STATE_INTERNAL_ERROR);
}
cpu->vcpu_dirty = true; cpu->vcpu_dirty = true;
} }
} }
@ -2865,7 +2878,13 @@ void kvm_cpu_synchronize_state(CPUState *cpu)
static void do_kvm_cpu_synchronize_post_reset(CPUState *cpu, run_on_cpu_data arg) static void do_kvm_cpu_synchronize_post_reset(CPUState *cpu, run_on_cpu_data arg)
{ {
kvm_arch_put_registers(cpu, KVM_PUT_RESET_STATE); int ret = kvm_arch_put_registers(cpu, KVM_PUT_RESET_STATE);
if (ret) {
error_report("Failed to put registers after reset: %s", strerror(-ret));
cpu_dump_state(cpu, stderr, CPU_DUMP_CODE);
vm_stop(RUN_STATE_INTERNAL_ERROR);
}
cpu->vcpu_dirty = false; cpu->vcpu_dirty = false;
} }
@ -2876,7 +2895,12 @@ void kvm_cpu_synchronize_post_reset(CPUState *cpu)
static void do_kvm_cpu_synchronize_post_init(CPUState *cpu, run_on_cpu_data arg) static void do_kvm_cpu_synchronize_post_init(CPUState *cpu, run_on_cpu_data arg)
{ {
kvm_arch_put_registers(cpu, KVM_PUT_FULL_STATE); int ret = kvm_arch_put_registers(cpu, KVM_PUT_FULL_STATE);
if (ret) {
error_report("Failed to put registers after init: %s", strerror(-ret));
exit(1);
}
cpu->vcpu_dirty = false; cpu->vcpu_dirty = false;
} }
@ -2969,7 +2993,14 @@ int kvm_cpu_exec(CPUState *cpu)
MemTxAttrs attrs; MemTxAttrs attrs;
if (cpu->vcpu_dirty) { if (cpu->vcpu_dirty) {
kvm_arch_put_registers(cpu, KVM_PUT_RUNTIME_STATE); ret = kvm_arch_put_registers(cpu, KVM_PUT_RUNTIME_STATE);
if (ret) {
error_report("Failed to put registers after init: %s",
strerror(-ret));
ret = -1;
break;
}
cpu->vcpu_dirty = false; cpu->vcpu_dirty = false;
} }

View File

@ -1,5 +1,5 @@
specific_ss.add(files('accel-common.c', 'accel-blocker.c')) specific_ss.add(files('accel-target.c'))
system_ss.add(files('accel-softmmu.c')) system_ss.add(files('accel-system.c', 'accel-blocker.c'))
user_ss.add(files('accel-user.c')) user_ss.add(files('accel-user.c'))
subdir('tcg') subdir('tcg')

View File

@ -109,9 +109,14 @@ int kvm_irqchip_remove_irqfd_notifier_gsi(KVMState *s, EventNotifier *n,
return -ENOSYS; return -ENOSYS;
} }
bool kvm_has_free_slot(MachineState *ms) unsigned int kvm_get_max_memslots(void)
{ {
return false; return 0;
}
unsigned int kvm_get_free_memslots(void)
{
return 0;
} }
void kvm_init_cpu_signals(CPUState *cpu) void kvm_init_cpu_signals(CPUState *cpu)

View File

@ -1,6 +1,6 @@
sysemu_stubs_ss = ss.source_set() system_stubs_ss = ss.source_set()
sysemu_stubs_ss.add(when: 'CONFIG_XEN', if_false: files('xen-stub.c')) system_stubs_ss.add(when: 'CONFIG_XEN', if_false: files('xen-stub.c'))
sysemu_stubs_ss.add(when: 'CONFIG_KVM', if_false: files('kvm-stub.c')) system_stubs_ss.add(when: 'CONFIG_KVM', if_false: files('kvm-stub.c'))
sysemu_stubs_ss.add(when: 'CONFIG_TCG', if_false: files('tcg-stub.c')) system_stubs_ss.add(when: 'CONFIG_TCG', if_false: files('tcg-stub.c'))
specific_ss.add_all(when: ['CONFIG_SYSTEM_ONLY'], if_true: sysemu_stubs_ss) specific_ss.add_all(when: ['CONFIG_SYSTEM_ONLY'], if_true: system_stubs_ss)

View File

@ -73,7 +73,8 @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, abi_ptr addr,
ABI_TYPE cmpv, ABI_TYPE newv, ABI_TYPE cmpv, ABI_TYPE newv,
MemOpIdx oi, uintptr_t retaddr) MemOpIdx oi, uintptr_t retaddr)
{ {
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, retaddr); DATA_TYPE *haddr = atomic_mmu_lookup(env_cpu(env), addr, oi,
DATA_SIZE, retaddr);
DATA_TYPE ret; DATA_TYPE ret;
#if DATA_SIZE == 16 #if DATA_SIZE == 16
@ -90,7 +91,8 @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, abi_ptr addr,
ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, abi_ptr addr, ABI_TYPE val, ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, abi_ptr addr, ABI_TYPE val,
MemOpIdx oi, uintptr_t retaddr) MemOpIdx oi, uintptr_t retaddr)
{ {
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, retaddr); DATA_TYPE *haddr = atomic_mmu_lookup(env_cpu(env), addr, oi,
DATA_SIZE, retaddr);
DATA_TYPE ret; DATA_TYPE ret;
ret = qatomic_xchg__nocheck(haddr, val); ret = qatomic_xchg__nocheck(haddr, val);
@ -104,7 +106,7 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, abi_ptr addr, \
ABI_TYPE val, MemOpIdx oi, uintptr_t retaddr) \ ABI_TYPE val, MemOpIdx oi, uintptr_t retaddr) \
{ \ { \
DATA_TYPE *haddr, ret; \ DATA_TYPE *haddr, ret; \
haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, retaddr); \ haddr = atomic_mmu_lookup(env_cpu(env), addr, oi, DATA_SIZE, retaddr); \
ret = qatomic_##X(haddr, val); \ ret = qatomic_##X(haddr, val); \
ATOMIC_MMU_CLEANUP; \ ATOMIC_MMU_CLEANUP; \
atomic_trace_rmw_post(env, addr, oi); \ atomic_trace_rmw_post(env, addr, oi); \
@ -135,7 +137,7 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, abi_ptr addr, \
ABI_TYPE xval, MemOpIdx oi, uintptr_t retaddr) \ ABI_TYPE xval, MemOpIdx oi, uintptr_t retaddr) \
{ \ { \
XDATA_TYPE *haddr, cmp, old, new, val = xval; \ XDATA_TYPE *haddr, cmp, old, new, val = xval; \
haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, retaddr); \ haddr = atomic_mmu_lookup(env_cpu(env), addr, oi, DATA_SIZE, retaddr); \
smp_mb(); \ smp_mb(); \
cmp = qatomic_read__nocheck(haddr); \ cmp = qatomic_read__nocheck(haddr); \
do { \ do { \
@ -176,7 +178,8 @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, abi_ptr addr,
ABI_TYPE cmpv, ABI_TYPE newv, ABI_TYPE cmpv, ABI_TYPE newv,
MemOpIdx oi, uintptr_t retaddr) MemOpIdx oi, uintptr_t retaddr)
{ {
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, retaddr); DATA_TYPE *haddr = atomic_mmu_lookup(env_cpu(env), addr, oi,
DATA_SIZE, retaddr);
DATA_TYPE ret; DATA_TYPE ret;
#if DATA_SIZE == 16 #if DATA_SIZE == 16
@ -193,7 +196,8 @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, abi_ptr addr,
ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, abi_ptr addr, ABI_TYPE val, ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, abi_ptr addr, ABI_TYPE val,
MemOpIdx oi, uintptr_t retaddr) MemOpIdx oi, uintptr_t retaddr)
{ {
DATA_TYPE *haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, retaddr); DATA_TYPE *haddr = atomic_mmu_lookup(env_cpu(env), addr, oi,
DATA_SIZE, retaddr);
ABI_TYPE ret; ABI_TYPE ret;
ret = qatomic_xchg__nocheck(haddr, BSWAP(val)); ret = qatomic_xchg__nocheck(haddr, BSWAP(val));
@ -207,7 +211,7 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, abi_ptr addr, \
ABI_TYPE val, MemOpIdx oi, uintptr_t retaddr) \ ABI_TYPE val, MemOpIdx oi, uintptr_t retaddr) \
{ \ { \
DATA_TYPE *haddr, ret; \ DATA_TYPE *haddr, ret; \
haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, retaddr); \ haddr = atomic_mmu_lookup(env_cpu(env), addr, oi, DATA_SIZE, retaddr); \
ret = qatomic_##X(haddr, BSWAP(val)); \ ret = qatomic_##X(haddr, BSWAP(val)); \
ATOMIC_MMU_CLEANUP; \ ATOMIC_MMU_CLEANUP; \
atomic_trace_rmw_post(env, addr, oi); \ atomic_trace_rmw_post(env, addr, oi); \
@ -235,7 +239,7 @@ ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, abi_ptr addr, \
ABI_TYPE xval, MemOpIdx oi, uintptr_t retaddr) \ ABI_TYPE xval, MemOpIdx oi, uintptr_t retaddr) \
{ \ { \
XDATA_TYPE *haddr, ldo, ldn, old, new, val = xval; \ XDATA_TYPE *haddr, ldo, ldn, old, new, val = xval; \
haddr = atomic_mmu_lookup(env, addr, oi, DATA_SIZE, retaddr); \ haddr = atomic_mmu_lookup(env_cpu(env), addr, oi, DATA_SIZE, retaddr); \
smp_mb(); \ smp_mb(); \
ldn = qatomic_read__nocheck(haddr); \ ldn = qatomic_read__nocheck(haddr); \
do { \ do { \

View File

@ -20,9 +20,8 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "sysemu/cpus.h" #include "sysemu/cpus.h"
#include "sysemu/tcg.h" #include "sysemu/tcg.h"
#include "exec/exec-all.h"
#include "qemu/plugin.h" #include "qemu/plugin.h"
#include "internal.h" #include "internal-common.h"
bool tcg_allowed; bool tcg_allowed;
@ -36,7 +35,7 @@ void cpu_loop_exit_noexc(CPUState *cpu)
void cpu_loop_exit(CPUState *cpu) void cpu_loop_exit(CPUState *cpu)
{ {
/* Undo the setting in cpu_tb_exec. */ /* Undo the setting in cpu_tb_exec. */
cpu->can_do_io = 1; cpu->neg.can_do_io = true;
/* Undo any setting in generated code. */ /* Undo any setting in generated code. */
qemu_plugin_disable_mem_helpers(cpu); qemu_plugin_disable_mem_helpers(cpu);
siglongjmp(cpu->jmp_env, 1); siglongjmp(cpu->jmp_env, 1);

View File

@ -42,7 +42,8 @@
#include "tb-jmp-cache.h" #include "tb-jmp-cache.h"
#include "tb-hash.h" #include "tb-hash.h"
#include "tb-context.h" #include "tb-context.h"
#include "internal.h" #include "internal-common.h"
#include "internal-target.h"
/* -icount align implementation. */ /* -icount align implementation. */
@ -73,7 +74,7 @@ static void align_clocks(SyncClocks *sc, CPUState *cpu)
return; return;
} }
cpu_icount = cpu->icount_extra + cpu_neg(cpu)->icount_decr.u16.low; cpu_icount = cpu->icount_extra + cpu->neg.icount_decr.u16.low;
sc->diff_clk += icount_to_ns(sc->last_cpu_icount - cpu_icount); sc->diff_clk += icount_to_ns(sc->last_cpu_icount - cpu_icount);
sc->last_cpu_icount = cpu_icount; sc->last_cpu_icount = cpu_icount;
@ -124,7 +125,7 @@ static void init_delay_params(SyncClocks *sc, CPUState *cpu)
sc->realtime_clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL_RT); sc->realtime_clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL_RT);
sc->diff_clk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - sc->realtime_clock; sc->diff_clk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - sc->realtime_clock;
sc->last_cpu_icount sc->last_cpu_icount
= cpu->icount_extra + cpu_neg(cpu)->icount_decr.u16.low; = cpu->icount_extra + cpu->neg.icount_decr.u16.low;
if (sc->diff_clk < max_delay) { if (sc->diff_clk < max_delay) {
max_delay = sc->diff_clk; max_delay = sc->diff_clk;
} }
@ -222,7 +223,7 @@ static TranslationBlock *tb_htable_lookup(CPUState *cpu, vaddr pc,
struct tb_desc desc; struct tb_desc desc;
uint32_t h; uint32_t h;
desc.env = cpu->env_ptr; desc.env = cpu_env(cpu);
desc.cs_base = cs_base; desc.cs_base = cs_base;
desc.flags = flags; desc.flags = flags;
desc.cflags = cflags; desc.cflags = cflags;
@ -444,7 +445,7 @@ const void *HELPER(lookup_tb_ptr)(CPUArchState *env)
static inline TranslationBlock * QEMU_DISABLE_CFI static inline TranslationBlock * QEMU_DISABLE_CFI
cpu_tb_exec(CPUState *cpu, TranslationBlock *itb, int *tb_exit) cpu_tb_exec(CPUState *cpu, TranslationBlock *itb, int *tb_exit)
{ {
CPUArchState *env = cpu->env_ptr; CPUArchState *env = cpu_env(cpu);
uintptr_t ret; uintptr_t ret;
TranslationBlock *last_tb; TranslationBlock *last_tb;
const void *tb_ptr = itb->tc.ptr; const void *tb_ptr = itb->tc.ptr;
@ -455,7 +456,7 @@ cpu_tb_exec(CPUState *cpu, TranslationBlock *itb, int *tb_exit)
qemu_thread_jit_execute(); qemu_thread_jit_execute();
ret = tcg_qemu_tb_exec(env, tb_ptr); ret = tcg_qemu_tb_exec(env, tb_ptr);
cpu->can_do_io = 1; cpu->neg.can_do_io = true;
qemu_plugin_disable_mem_helpers(cpu); qemu_plugin_disable_mem_helpers(cpu);
/* /*
* TODO: Delay swapping back to the read-write region of the TB * TODO: Delay swapping back to the read-write region of the TB
@ -565,7 +566,7 @@ static void cpu_exec_longjmp_cleanup(CPUState *cpu)
void cpu_exec_step_atomic(CPUState *cpu) void cpu_exec_step_atomic(CPUState *cpu)
{ {
CPUArchState *env = cpu->env_ptr; CPUArchState *env = cpu_env(cpu);
TranslationBlock *tb; TranslationBlock *tb;
vaddr pc; vaddr pc;
uint64_t cs_base; uint64_t cs_base;
@ -737,10 +738,10 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
if (cpu->exception_index < 0) { if (cpu->exception_index < 0) {
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
if (replay_has_exception() if (replay_has_exception()
&& cpu_neg(cpu)->icount_decr.u16.low + cpu->icount_extra == 0) { && cpu->neg.icount_decr.u16.low + cpu->icount_extra == 0) {
/* Execute just one insn to trigger exception pending in the log */ /* Execute just one insn to trigger exception pending in the log */
cpu->cflags_next_tb = (curr_cflags(cpu) & ~CF_USE_ICOUNT) cpu->cflags_next_tb = (curr_cflags(cpu) & ~CF_USE_ICOUNT)
| CF_NOIRQ | 1; | CF_LAST_IO | CF_NOIRQ | 1;
} }
#endif #endif
return false; return false;
@ -827,7 +828,7 @@ static inline bool cpu_handle_interrupt(CPUState *cpu,
* Ensure zeroing happens before reading cpu->exit_request or * Ensure zeroing happens before reading cpu->exit_request or
* cpu->interrupt_request (see also smp_wmb in cpu_exit()) * cpu->interrupt_request (see also smp_wmb in cpu_exit())
*/ */
qatomic_set_mb(&cpu_neg(cpu)->icount_decr.u16.high, 0); qatomic_set_mb(&cpu->neg.icount_decr.u16.high, 0);
if (unlikely(qatomic_read(&cpu->interrupt_request))) { if (unlikely(qatomic_read(&cpu->interrupt_request))) {
int interrupt_request; int interrupt_request;
@ -918,7 +919,7 @@ static inline bool cpu_handle_interrupt(CPUState *cpu,
if (unlikely(qatomic_read(&cpu->exit_request)) if (unlikely(qatomic_read(&cpu->exit_request))
|| (icount_enabled() || (icount_enabled()
&& (cpu->cflags_next_tb == -1 || cpu->cflags_next_tb & CF_USE_ICOUNT) && (cpu->cflags_next_tb == -1 || cpu->cflags_next_tb & CF_USE_ICOUNT)
&& cpu_neg(cpu)->icount_decr.u16.low + cpu->icount_extra == 0)) { && cpu->neg.icount_decr.u16.low + cpu->icount_extra == 0)) {
qatomic_set(&cpu->exit_request, 0); qatomic_set(&cpu->exit_request, 0);
if (cpu->exception_index == -1) { if (cpu->exception_index == -1) {
cpu->exception_index = EXCP_INTERRUPT; cpu->exception_index = EXCP_INTERRUPT;
@ -950,7 +951,7 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb,
} }
*last_tb = NULL; *last_tb = NULL;
insns_left = qatomic_read(&cpu_neg(cpu)->icount_decr.u32); insns_left = qatomic_read(&cpu->neg.icount_decr.u32);
if (insns_left < 0) { if (insns_left < 0) {
/* Something asked us to stop executing chained TBs; just /* Something asked us to stop executing chained TBs; just
* continue round the main loop. Whatever requested the exit * continue round the main loop. Whatever requested the exit
@ -969,7 +970,7 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb,
icount_update(cpu); icount_update(cpu);
/* Refill decrementer and continue execution. */ /* Refill decrementer and continue execution. */
insns_left = MIN(0xffff, cpu->icount_budget); insns_left = MIN(0xffff, cpu->icount_budget);
cpu_neg(cpu)->icount_decr.u16.low = insns_left; cpu->neg.icount_decr.u16.low = insns_left;
cpu->icount_extra = cpu->icount_budget - insns_left; cpu->icount_extra = cpu->icount_budget - insns_left;
/* /*
@ -1017,7 +1018,7 @@ cpu_exec_loop(CPUState *cpu, SyncClocks *sc)
uint64_t cs_base; uint64_t cs_base;
uint32_t flags, cflags; uint32_t flags, cflags;
cpu_get_tb_cpu_state(cpu->env_ptr, &pc, &cs_base, &flags); cpu_get_tb_cpu_state(cpu_env(cpu), &pc, &cs_base, &flags);
/* /*
* When requested, use an exact setting for cflags for the next * When requested, use an exact setting for cflags for the next
@ -1154,7 +1155,7 @@ int cpu_exec(CPUState *cpu)
return ret; return ret;
} }
void tcg_exec_realizefn(CPUState *cpu, Error **errp) bool tcg_exec_realizefn(CPUState *cpu, Error **errp)
{ {
static bool tcg_target_initialized; static bool tcg_target_initialized;
CPUClass *cc = CPU_GET_CLASS(cpu); CPUClass *cc = CPU_GET_CLASS(cpu);
@ -1170,6 +1171,8 @@ void tcg_exec_realizefn(CPUState *cpu, Error **errp)
tcg_iommu_init_notifier_list(cpu); tcg_iommu_init_notifier_list(cpu);
#endif /* !CONFIG_USER_ONLY */ #endif /* !CONFIG_USER_ONLY */
/* qemu_plugin_vcpu_init_hook delayed until cpu_index assigned. */ /* qemu_plugin_vcpu_init_hook delayed until cpu_index assigned. */
return true;
} }
/* undo the initializations in reverse order */ /* undo the initializations in reverse order */

File diff suppressed because it is too large Load Diff

View File

@ -27,7 +27,6 @@
#include "migration/vmstate.h" #include "migration/vmstate.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "exec/exec-all.h"
#include "sysemu/cpus.h" #include "sysemu/cpus.h"
#include "sysemu/qtest.h" #include "sysemu/qtest.h"
#include "qemu/main-loop.h" #include "qemu/main-loop.h"
@ -38,7 +37,7 @@
#include "hw/core/cpu.h" #include "hw/core/cpu.h"
#include "sysemu/cpu-timers.h" #include "sysemu/cpu-timers.h"
#include "sysemu/cpu-throttle.h" #include "sysemu/cpu-throttle.h"
#include "timers-state.h" #include "sysemu/cpu-timers-internal.h"
/* /*
* ICOUNT: Instruction Counter * ICOUNT: Instruction Counter
@ -75,7 +74,7 @@ static void icount_enable_adaptive(void)
static int64_t icount_get_executed(CPUState *cpu) static int64_t icount_get_executed(CPUState *cpu)
{ {
return (cpu->icount_budget - return (cpu->icount_budget -
(cpu_neg(cpu)->icount_decr.u16.low + cpu->icount_extra)); (cpu->neg.icount_decr.u16.low + cpu->icount_extra));
} }
/* /*
@ -111,7 +110,7 @@ static int64_t icount_get_raw_locked(void)
CPUState *cpu = current_cpu; CPUState *cpu = current_cpu;
if (cpu && cpu->running) { if (cpu && cpu->running) {
if (!cpu->can_do_io) { if (!cpu->neg.can_do_io) {
error_report("Bad icount read"); error_report("Bad icount read");
exit(1); exit(1);
} }

View File

@ -0,0 +1,28 @@
/*
* Internal execution defines for qemu (target agnostic)
*
* Copyright (c) 2003 Fabrice Bellard
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#ifndef ACCEL_TCG_INTERNAL_COMMON_H
#define ACCEL_TCG_INTERNAL_COMMON_H
#include "exec/translation-block.h"
extern int64_t max_delay;
extern int64_t max_advance;
void dump_exec_info(GString *buf);
/*
* 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.
*/
static inline bool cpu_in_serial_context(CPUState *cs)
{
return !(cs->tcg_cflags & CF_PARALLEL) || cpu_in_exclusive_context(cs);
}
#endif

View File

@ -1,13 +1,13 @@
/* /*
* Internal execution defines for qemu * Internal execution defines for qemu (target specific)
* *
* Copyright (c) 2003 Fabrice Bellard * Copyright (c) 2003 Fabrice Bellard
* *
* SPDX-License-Identifier: LGPL-2.1-or-later * SPDX-License-Identifier: LGPL-2.1-or-later
*/ */
#ifndef ACCEL_TCG_INTERNAL_H #ifndef ACCEL_TCG_INTERNAL_TARGET_H
#define ACCEL_TCG_INTERNAL_H #define ACCEL_TCG_INTERNAL_TARGET_H
#include "exec/exec-all.h" #include "exec/exec-all.h"
#include "exec/translate-all.h" #include "exec/translate-all.h"
@ -80,6 +80,9 @@ bool tb_invalidate_phys_page_unwind(tb_page_addr_t addr, uintptr_t pc);
void cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb, void cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb,
uintptr_t host_pc); uintptr_t host_pc);
bool tcg_exec_realizefn(CPUState *cpu, Error **errp);
void tcg_exec_unrealizefn(CPUState *cpu);
/* Return the current PC from CPU, which may be cached in TB. */ /* Return the current PC from CPU, which may be cached in TB. */
static inline vaddr log_pc(CPUState *cpu, const TranslationBlock *tb) static inline vaddr log_pc(CPUState *cpu, const TranslationBlock *tb)
{ {
@ -90,18 +93,6 @@ static inline vaddr log_pc(CPUState *cpu, const TranslationBlock *tb)
} }
} }
/*
* 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.
*/
static inline bool cpu_in_serial_context(CPUState *cs)
{
return !(cs->tcg_cflags & CF_PARALLEL) || cpu_in_exclusive_context(cs);
}
extern int64_t max_delay;
extern int64_t max_advance;
extern bool one_insn_per_tb; extern bool one_insn_per_tb;
/** /**

View File

@ -26,7 +26,7 @@
* If the operation must be split into two operations to be * If the operation must be split into two operations to be
* examined separately for atomicity, return -lg2. * examined separately for atomicity, return -lg2.
*/ */
static int required_atomicity(CPUArchState *env, uintptr_t p, MemOp memop) static int required_atomicity(CPUState *cpu, uintptr_t p, MemOp memop)
{ {
MemOp atom = memop & MO_ATOM_MASK; MemOp atom = memop & MO_ATOM_MASK;
MemOp size = memop & MO_SIZE; MemOp size = memop & MO_SIZE;
@ -93,7 +93,7 @@ static int required_atomicity(CPUArchState *env, uintptr_t p, MemOp memop)
* host atomicity in order to avoid racing. This reduction * host atomicity in order to avoid racing. This reduction
* avoids looping with cpu_loop_exit_atomic. * avoids looping with cpu_loop_exit_atomic.
*/ */
if (cpu_in_serial_context(env_cpu(env))) { if (cpu_in_serial_context(cpu)) {
return MO_8; return MO_8;
} }
return atmax; return atmax;
@ -139,14 +139,14 @@ static inline uint64_t load_atomic8(void *pv)
/** /**
* load_atomic8_or_exit: * load_atomic8_or_exit:
* @env: cpu context * @cpu: generic cpu state
* @ra: host unwind address * @ra: host unwind address
* @pv: host address * @pv: host address
* *
* Atomically load 8 aligned bytes from @pv. * Atomically load 8 aligned bytes from @pv.
* If this is not possible, longjmp out to restart serially. * If this is not possible, longjmp out to restart serially.
*/ */
static uint64_t load_atomic8_or_exit(CPUArchState *env, uintptr_t ra, void *pv) static uint64_t load_atomic8_or_exit(CPUState *cpu, uintptr_t ra, void *pv)
{ {
if (HAVE_al8) { if (HAVE_al8) {
return load_atomic8(pv); return load_atomic8(pv);
@ -168,19 +168,19 @@ static uint64_t load_atomic8_or_exit(CPUArchState *env, uintptr_t ra, void *pv)
#endif #endif
/* Ultimate fallback: re-execute in serial context. */ /* Ultimate fallback: re-execute in serial context. */
cpu_loop_exit_atomic(env_cpu(env), ra); cpu_loop_exit_atomic(cpu, ra);
} }
/** /**
* load_atomic16_or_exit: * load_atomic16_or_exit:
* @env: cpu context * @cpu: generic cpu state
* @ra: host unwind address * @ra: host unwind address
* @pv: host address * @pv: host address
* *
* Atomically load 16 aligned bytes from @pv. * Atomically load 16 aligned bytes from @pv.
* If this is not possible, longjmp out to restart serially. * If this is not possible, longjmp out to restart serially.
*/ */
static Int128 load_atomic16_or_exit(CPUArchState *env, uintptr_t ra, void *pv) static Int128 load_atomic16_or_exit(CPUState *cpu, uintptr_t ra, void *pv)
{ {
Int128 *p = __builtin_assume_aligned(pv, 16); Int128 *p = __builtin_assume_aligned(pv, 16);
@ -212,7 +212,7 @@ static Int128 load_atomic16_or_exit(CPUArchState *env, uintptr_t ra, void *pv)
} }
/* Ultimate fallback: re-execute in serial context. */ /* Ultimate fallback: re-execute in serial context. */
cpu_loop_exit_atomic(env_cpu(env), ra); cpu_loop_exit_atomic(cpu, ra);
} }
/** /**
@ -263,7 +263,7 @@ static uint64_t load_atom_extract_al8x2(void *pv)
/** /**
* load_atom_extract_al8_or_exit: * load_atom_extract_al8_or_exit:
* @env: cpu context * @cpu: generic cpu state
* @ra: host unwind address * @ra: host unwind address
* @pv: host address * @pv: host address
* @s: object size in bytes, @s <= 4. * @s: object size in bytes, @s <= 4.
@ -273,7 +273,7 @@ static uint64_t load_atom_extract_al8x2(void *pv)
* 8-byte load and extract. * 8-byte load and extract.
* The value is returned in the low bits of a uint32_t. * The value is returned in the low bits of a uint32_t.
*/ */
static uint32_t load_atom_extract_al8_or_exit(CPUArchState *env, uintptr_t ra, static uint32_t load_atom_extract_al8_or_exit(CPUState *cpu, uintptr_t ra,
void *pv, int s) void *pv, int s)
{ {
uintptr_t pi = (uintptr_t)pv; uintptr_t pi = (uintptr_t)pv;
@ -281,12 +281,12 @@ static uint32_t load_atom_extract_al8_or_exit(CPUArchState *env, uintptr_t ra,
int shr = (HOST_BIG_ENDIAN ? 8 - s - o : o) * 8; int shr = (HOST_BIG_ENDIAN ? 8 - s - o : o) * 8;
pv = (void *)(pi & ~7); pv = (void *)(pi & ~7);
return load_atomic8_or_exit(env, ra, pv) >> shr; return load_atomic8_or_exit(cpu, ra, pv) >> shr;
} }
/** /**
* load_atom_extract_al16_or_exit: * load_atom_extract_al16_or_exit:
* @env: cpu context * @cpu: generic cpu state
* @ra: host unwind address * @ra: host unwind address
* @p: host address * @p: host address
* @s: object size in bytes, @s <= 8. * @s: object size in bytes, @s <= 8.
@ -299,7 +299,7 @@ static uint32_t load_atom_extract_al8_or_exit(CPUArchState *env, uintptr_t ra,
* *
* If this is not possible, longjmp out to restart serially. * If this is not possible, longjmp out to restart serially.
*/ */
static uint64_t load_atom_extract_al16_or_exit(CPUArchState *env, uintptr_t ra, static uint64_t load_atom_extract_al16_or_exit(CPUState *cpu, uintptr_t ra,
void *pv, int s) void *pv, int s)
{ {
uintptr_t pi = (uintptr_t)pv; uintptr_t pi = (uintptr_t)pv;
@ -312,7 +312,7 @@ static uint64_t load_atom_extract_al16_or_exit(CPUArchState *env, uintptr_t ra,
* Provoke SIGBUS if possible otherwise. * Provoke SIGBUS if possible otherwise.
*/ */
pv = (void *)(pi & ~7); pv = (void *)(pi & ~7);
r = load_atomic16_or_exit(env, ra, pv); r = load_atomic16_or_exit(cpu, ra, pv);
r = int128_urshift(r, shr); r = int128_urshift(r, shr);
return int128_getlo(r); return int128_getlo(r);
@ -394,7 +394,7 @@ static inline uint64_t load_atom_8_by_8_or_4(void *pv)
* *
* Load 2 bytes from @p, honoring the atomicity of @memop. * Load 2 bytes from @p, honoring the atomicity of @memop.
*/ */
static uint16_t load_atom_2(CPUArchState *env, uintptr_t ra, static uint16_t load_atom_2(CPUState *cpu, uintptr_t ra,
void *pv, MemOp memop) void *pv, MemOp memop)
{ {
uintptr_t pi = (uintptr_t)pv; uintptr_t pi = (uintptr_t)pv;
@ -410,7 +410,7 @@ static uint16_t load_atom_2(CPUArchState *env, uintptr_t ra,
} }
} }
atmax = required_atomicity(env, pi, memop); atmax = required_atomicity(cpu, pi, memop);
switch (atmax) { switch (atmax) {
case MO_8: case MO_8:
return lduw_he_p(pv); return lduw_he_p(pv);
@ -421,9 +421,9 @@ static uint16_t load_atom_2(CPUArchState *env, uintptr_t ra,
return load_atomic4(pv - 1) >> 8; return load_atomic4(pv - 1) >> 8;
} }
if ((pi & 15) != 7) { if ((pi & 15) != 7) {
return load_atom_extract_al8_or_exit(env, ra, pv, 2); return load_atom_extract_al8_or_exit(cpu, ra, pv, 2);
} }
return load_atom_extract_al16_or_exit(env, ra, pv, 2); return load_atom_extract_al16_or_exit(cpu, ra, pv, 2);
default: default:
g_assert_not_reached(); g_assert_not_reached();
} }
@ -436,7 +436,7 @@ static uint16_t load_atom_2(CPUArchState *env, uintptr_t ra,
* *
* Load 4 bytes from @p, honoring the atomicity of @memop. * Load 4 bytes from @p, honoring the atomicity of @memop.
*/ */
static uint32_t load_atom_4(CPUArchState *env, uintptr_t ra, static uint32_t load_atom_4(CPUState *cpu, uintptr_t ra,
void *pv, MemOp memop) void *pv, MemOp memop)
{ {
uintptr_t pi = (uintptr_t)pv; uintptr_t pi = (uintptr_t)pv;
@ -452,7 +452,7 @@ static uint32_t load_atom_4(CPUArchState *env, uintptr_t ra,
} }
} }
atmax = required_atomicity(env, pi, memop); atmax = required_atomicity(cpu, pi, memop);
switch (atmax) { switch (atmax) {
case MO_8: case MO_8:
case MO_16: case MO_16:
@ -466,9 +466,9 @@ static uint32_t load_atom_4(CPUArchState *env, uintptr_t ra,
return load_atom_extract_al4x2(pv); return load_atom_extract_al4x2(pv);
case MO_32: case MO_32:
if (!(pi & 4)) { if (!(pi & 4)) {
return load_atom_extract_al8_or_exit(env, ra, pv, 4); return load_atom_extract_al8_or_exit(cpu, ra, pv, 4);
} }
return load_atom_extract_al16_or_exit(env, ra, pv, 4); return load_atom_extract_al16_or_exit(cpu, ra, pv, 4);
default: default:
g_assert_not_reached(); g_assert_not_reached();
} }
@ -481,7 +481,7 @@ static uint32_t load_atom_4(CPUArchState *env, uintptr_t ra,
* *
* Load 8 bytes from @p, honoring the atomicity of @memop. * Load 8 bytes from @p, honoring the atomicity of @memop.
*/ */
static uint64_t load_atom_8(CPUArchState *env, uintptr_t ra, static uint64_t load_atom_8(CPUState *cpu, uintptr_t ra,
void *pv, MemOp memop) void *pv, MemOp memop)
{ {
uintptr_t pi = (uintptr_t)pv; uintptr_t pi = (uintptr_t)pv;
@ -498,12 +498,12 @@ static uint64_t load_atom_8(CPUArchState *env, uintptr_t ra,
return load_atom_extract_al16_or_al8(pv, 8); return load_atom_extract_al16_or_al8(pv, 8);
} }
atmax = required_atomicity(env, pi, memop); atmax = required_atomicity(cpu, pi, memop);
if (atmax == MO_64) { if (atmax == MO_64) {
if (!HAVE_al8 && (pi & 7) == 0) { if (!HAVE_al8 && (pi & 7) == 0) {
load_atomic8_or_exit(env, ra, pv); load_atomic8_or_exit(cpu, ra, pv);
} }
return load_atom_extract_al16_or_exit(env, ra, pv, 8); return load_atom_extract_al16_or_exit(cpu, ra, pv, 8);
} }
if (HAVE_al8_fast) { if (HAVE_al8_fast) {
return load_atom_extract_al8x2(pv); return load_atom_extract_al8x2(pv);
@ -519,7 +519,7 @@ static uint64_t load_atom_8(CPUArchState *env, uintptr_t ra,
if (HAVE_al8) { if (HAVE_al8) {
return load_atom_extract_al8x2(pv); return load_atom_extract_al8x2(pv);
} }
cpu_loop_exit_atomic(env_cpu(env), ra); cpu_loop_exit_atomic(cpu, ra);
default: default:
g_assert_not_reached(); g_assert_not_reached();
} }
@ -532,7 +532,7 @@ static uint64_t load_atom_8(CPUArchState *env, uintptr_t ra,
* *
* Load 16 bytes from @p, honoring the atomicity of @memop. * Load 16 bytes from @p, honoring the atomicity of @memop.
*/ */
static Int128 load_atom_16(CPUArchState *env, uintptr_t ra, static Int128 load_atom_16(CPUState *cpu, uintptr_t ra,
void *pv, MemOp memop) void *pv, MemOp memop)
{ {
uintptr_t pi = (uintptr_t)pv; uintptr_t pi = (uintptr_t)pv;
@ -548,7 +548,7 @@ static Int128 load_atom_16(CPUArchState *env, uintptr_t ra,
return atomic16_read_ro(pv); return atomic16_read_ro(pv);
} }
atmax = required_atomicity(env, pi, memop); atmax = required_atomicity(cpu, pi, memop);
switch (atmax) { switch (atmax) {
case MO_8: case MO_8:
memcpy(&r, pv, 16); memcpy(&r, pv, 16);
@ -563,20 +563,20 @@ static Int128 load_atom_16(CPUArchState *env, uintptr_t ra,
break; break;
case MO_64: case MO_64:
if (!HAVE_al8) { if (!HAVE_al8) {
cpu_loop_exit_atomic(env_cpu(env), ra); cpu_loop_exit_atomic(cpu, ra);
} }
a = load_atomic8(pv); a = load_atomic8(pv);
b = load_atomic8(pv + 8); b = load_atomic8(pv + 8);
break; break;
case -MO_64: case -MO_64:
if (!HAVE_al8) { if (!HAVE_al8) {
cpu_loop_exit_atomic(env_cpu(env), ra); cpu_loop_exit_atomic(cpu, ra);
} }
a = load_atom_extract_al8x2(pv); a = load_atom_extract_al8x2(pv);
b = load_atom_extract_al8x2(pv + 8); b = load_atom_extract_al8x2(pv + 8);
break; break;
case MO_128: case MO_128:
return load_atomic16_or_exit(env, ra, pv); return load_atomic16_or_exit(cpu, ra, pv);
default: default:
g_assert_not_reached(); g_assert_not_reached();
} }
@ -857,7 +857,7 @@ static uint64_t store_whole_le16(void *pv, int size, Int128 val_le)
* *
* Store 2 bytes to @p, honoring the atomicity of @memop. * Store 2 bytes to @p, honoring the atomicity of @memop.
*/ */
static void store_atom_2(CPUArchState *env, uintptr_t ra, static void store_atom_2(CPUState *cpu, uintptr_t ra,
void *pv, MemOp memop, uint16_t val) void *pv, MemOp memop, uint16_t val)
{ {
uintptr_t pi = (uintptr_t)pv; uintptr_t pi = (uintptr_t)pv;
@ -868,7 +868,7 @@ static void store_atom_2(CPUArchState *env, uintptr_t ra,
return; return;
} }
atmax = required_atomicity(env, pi, memop); atmax = required_atomicity(cpu, pi, memop);
if (atmax == MO_8) { if (atmax == MO_8) {
stw_he_p(pv, val); stw_he_p(pv, val);
return; return;
@ -897,7 +897,7 @@ static void store_atom_2(CPUArchState *env, uintptr_t ra,
g_assert_not_reached(); g_assert_not_reached();
} }
cpu_loop_exit_atomic(env_cpu(env), ra); cpu_loop_exit_atomic(cpu, ra);
} }
/** /**
@ -908,7 +908,7 @@ static void store_atom_2(CPUArchState *env, uintptr_t ra,
* *
* Store 4 bytes to @p, honoring the atomicity of @memop. * Store 4 bytes to @p, honoring the atomicity of @memop.
*/ */
static void store_atom_4(CPUArchState *env, uintptr_t ra, static void store_atom_4(CPUState *cpu, uintptr_t ra,
void *pv, MemOp memop, uint32_t val) void *pv, MemOp memop, uint32_t val)
{ {
uintptr_t pi = (uintptr_t)pv; uintptr_t pi = (uintptr_t)pv;
@ -919,7 +919,7 @@ static void store_atom_4(CPUArchState *env, uintptr_t ra,
return; return;
} }
atmax = required_atomicity(env, pi, memop); atmax = required_atomicity(cpu, pi, memop);
switch (atmax) { switch (atmax) {
case MO_8: case MO_8:
stl_he_p(pv, val); stl_he_p(pv, val);
@ -961,7 +961,7 @@ static void store_atom_4(CPUArchState *env, uintptr_t ra,
return; return;
} }
} }
cpu_loop_exit_atomic(env_cpu(env), ra); cpu_loop_exit_atomic(cpu, ra);
default: default:
g_assert_not_reached(); g_assert_not_reached();
} }
@ -975,7 +975,7 @@ static void store_atom_4(CPUArchState *env, uintptr_t ra,
* *
* Store 8 bytes to @p, honoring the atomicity of @memop. * Store 8 bytes to @p, honoring the atomicity of @memop.
*/ */
static void store_atom_8(CPUArchState *env, uintptr_t ra, static void store_atom_8(CPUState *cpu, uintptr_t ra,
void *pv, MemOp memop, uint64_t val) void *pv, MemOp memop, uint64_t val)
{ {
uintptr_t pi = (uintptr_t)pv; uintptr_t pi = (uintptr_t)pv;
@ -986,7 +986,7 @@ static void store_atom_8(CPUArchState *env, uintptr_t ra,
return; return;
} }
atmax = required_atomicity(env, pi, memop); atmax = required_atomicity(cpu, pi, memop);
switch (atmax) { switch (atmax) {
case MO_8: case MO_8:
stq_he_p(pv, val); stq_he_p(pv, val);
@ -1029,7 +1029,7 @@ static void store_atom_8(CPUArchState *env, uintptr_t ra,
default: default:
g_assert_not_reached(); g_assert_not_reached();
} }
cpu_loop_exit_atomic(env_cpu(env), ra); cpu_loop_exit_atomic(cpu, ra);
} }
/** /**
@ -1040,7 +1040,7 @@ static void store_atom_8(CPUArchState *env, uintptr_t ra,
* *
* Store 16 bytes to @p, honoring the atomicity of @memop. * Store 16 bytes to @p, honoring the atomicity of @memop.
*/ */
static void store_atom_16(CPUArchState *env, uintptr_t ra, static void store_atom_16(CPUState *cpu, uintptr_t ra,
void *pv, MemOp memop, Int128 val) void *pv, MemOp memop, Int128 val)
{ {
uintptr_t pi = (uintptr_t)pv; uintptr_t pi = (uintptr_t)pv;
@ -1052,7 +1052,7 @@ static void store_atom_16(CPUArchState *env, uintptr_t ra,
return; return;
} }
atmax = required_atomicity(env, pi, memop); atmax = required_atomicity(cpu, pi, memop);
a = HOST_BIG_ENDIAN ? int128_gethi(val) : int128_getlo(val); a = HOST_BIG_ENDIAN ? int128_gethi(val) : int128_getlo(val);
b = HOST_BIG_ENDIAN ? int128_getlo(val) : int128_gethi(val); b = HOST_BIG_ENDIAN ? int128_getlo(val) : int128_gethi(val);
@ -1111,5 +1111,5 @@ static void store_atom_16(CPUArchState *env, uintptr_t ra,
default: default:
g_assert_not_reached(); g_assert_not_reached();
} }
cpu_loop_exit_atomic(env_cpu(env), ra); cpu_loop_exit_atomic(cpu, ra);
} }

View File

@ -8,6 +8,231 @@
* This work is licensed under the terms of the GNU GPL, version 2 or later. * This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory. * See the COPYING file in the top-level directory.
*/ */
/*
* Load helpers for tcg-ldst.h
*/
tcg_target_ulong helper_ldub_mmu(CPUArchState *env, uint64_t addr,
MemOpIdx oi, uintptr_t retaddr)
{
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_8);
return do_ld1_mmu(env_cpu(env), addr, oi, retaddr, MMU_DATA_LOAD);
}
tcg_target_ulong helper_lduw_mmu(CPUArchState *env, uint64_t addr,
MemOpIdx oi, uintptr_t retaddr)
{
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_16);
return do_ld2_mmu(env_cpu(env), addr, oi, retaddr, MMU_DATA_LOAD);
}
tcg_target_ulong helper_ldul_mmu(CPUArchState *env, uint64_t addr,
MemOpIdx oi, uintptr_t retaddr)
{
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_32);
return do_ld4_mmu(env_cpu(env), addr, oi, retaddr, MMU_DATA_LOAD);
}
uint64_t helper_ldq_mmu(CPUArchState *env, uint64_t addr,
MemOpIdx oi, uintptr_t retaddr)
{
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_64);
return do_ld8_mmu(env_cpu(env), addr, oi, retaddr, MMU_DATA_LOAD);
}
/*
* Provide signed versions of the load routines as well. We can of course
* avoid this for 64-bit data, or for 32-bit data on 32-bit host.
*/
tcg_target_ulong helper_ldsb_mmu(CPUArchState *env, uint64_t addr,
MemOpIdx oi, uintptr_t retaddr)
{
return (int8_t)helper_ldub_mmu(env, addr, oi, retaddr);
}
tcg_target_ulong helper_ldsw_mmu(CPUArchState *env, uint64_t addr,
MemOpIdx oi, uintptr_t retaddr)
{
return (int16_t)helper_lduw_mmu(env, addr, oi, retaddr);
}
tcg_target_ulong helper_ldsl_mmu(CPUArchState *env, uint64_t addr,
MemOpIdx oi, uintptr_t retaddr)
{
return (int32_t)helper_ldul_mmu(env, addr, oi, retaddr);
}
Int128 helper_ld16_mmu(CPUArchState *env, uint64_t addr,
MemOpIdx oi, uintptr_t retaddr)
{
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_128);
return do_ld16_mmu(env_cpu(env), addr, oi, retaddr);
}
Int128 helper_ld_i128(CPUArchState *env, uint64_t addr, uint32_t oi)
{
return helper_ld16_mmu(env, addr, oi, GETPC());
}
/*
* Store helpers for tcg-ldst.h
*/
void helper_stb_mmu(CPUArchState *env, uint64_t addr, uint32_t val,
MemOpIdx oi, uintptr_t ra)
{
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_8);
do_st1_mmu(env_cpu(env), addr, val, oi, ra);
}
void helper_stw_mmu(CPUArchState *env, uint64_t addr, uint32_t val,
MemOpIdx oi, uintptr_t retaddr)
{
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_16);
do_st2_mmu(env_cpu(env), addr, val, oi, retaddr);
}
void helper_stl_mmu(CPUArchState *env, uint64_t addr, uint32_t val,
MemOpIdx oi, uintptr_t retaddr)
{
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_32);
do_st4_mmu(env_cpu(env), addr, val, oi, retaddr);
}
void helper_stq_mmu(CPUArchState *env, uint64_t addr, uint64_t val,
MemOpIdx oi, uintptr_t retaddr)
{
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_64);
do_st8_mmu(env_cpu(env), addr, val, oi, retaddr);
}
void helper_st16_mmu(CPUArchState *env, uint64_t addr, Int128 val,
MemOpIdx oi, uintptr_t retaddr)
{
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_128);
do_st16_mmu(env_cpu(env), addr, val, oi, retaddr);
}
void helper_st_i128(CPUArchState *env, uint64_t addr, Int128 val, MemOpIdx oi)
{
helper_st16_mmu(env, addr, val, oi, GETPC());
}
/*
* Load helpers for cpu_ldst.h
*/
static void plugin_load_cb(CPUArchState *env, abi_ptr addr, MemOpIdx oi)
{
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_R);
}
uint8_t cpu_ldb_mmu(CPUArchState *env, abi_ptr addr, MemOpIdx oi, uintptr_t ra)
{
uint8_t ret;
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_UB);
ret = do_ld1_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD);
plugin_load_cb(env, addr, oi);
return ret;
}
uint16_t cpu_ldw_mmu(CPUArchState *env, abi_ptr addr,
MemOpIdx oi, uintptr_t ra)
{
uint16_t ret;
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_16);
ret = do_ld2_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD);
plugin_load_cb(env, addr, oi);
return ret;
}
uint32_t cpu_ldl_mmu(CPUArchState *env, abi_ptr addr,
MemOpIdx oi, uintptr_t ra)
{
uint32_t ret;
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_32);
ret = do_ld4_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD);
plugin_load_cb(env, addr, oi);
return ret;
}
uint64_t cpu_ldq_mmu(CPUArchState *env, abi_ptr addr,
MemOpIdx oi, uintptr_t ra)
{
uint64_t ret;
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_64);
ret = do_ld8_mmu(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD);
plugin_load_cb(env, addr, oi);
return ret;
}
Int128 cpu_ld16_mmu(CPUArchState *env, abi_ptr addr,
MemOpIdx oi, uintptr_t ra)
{
Int128 ret;
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_128);
ret = do_ld16_mmu(env_cpu(env), addr, oi, ra);
plugin_load_cb(env, addr, oi);
return ret;
}
/*
* Store helpers for cpu_ldst.h
*/
static void plugin_store_cb(CPUArchState *env, abi_ptr addr, MemOpIdx oi)
{
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_W);
}
void cpu_stb_mmu(CPUArchState *env, abi_ptr addr, uint8_t val,
MemOpIdx oi, uintptr_t retaddr)
{
helper_stb_mmu(env, addr, val, oi, retaddr);
plugin_store_cb(env, addr, oi);
}
void cpu_stw_mmu(CPUArchState *env, abi_ptr addr, uint16_t val,
MemOpIdx oi, uintptr_t retaddr)
{
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_16);
do_st2_mmu(env_cpu(env), addr, val, oi, retaddr);
plugin_store_cb(env, addr, oi);
}
void cpu_stl_mmu(CPUArchState *env, abi_ptr addr, uint32_t val,
MemOpIdx oi, uintptr_t retaddr)
{
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_32);
do_st4_mmu(env_cpu(env), addr, val, oi, retaddr);
plugin_store_cb(env, addr, oi);
}
void cpu_stq_mmu(CPUArchState *env, abi_ptr addr, uint64_t val,
MemOpIdx oi, uintptr_t retaddr)
{
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_64);
do_st8_mmu(env_cpu(env), addr, val, oi, retaddr);
plugin_store_cb(env, addr, oi);
}
void cpu_st16_mmu(CPUArchState *env, abi_ptr addr, Int128 val,
MemOpIdx oi, uintptr_t retaddr)
{
tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_128);
do_st16_mmu(env_cpu(env), addr, val, oi, retaddr);
plugin_store_cb(env, addr, oi);
}
/*
* Wrappers of the above
*/
uint32_t cpu_ldub_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t cpu_ldub_mmuidx_ra(CPUArchState *env, abi_ptr addr,
int mmu_idx, uintptr_t ra) int mmu_idx, uintptr_t ra)

View File

@ -1,7 +1,9 @@
tcg_ss = ss.source_set() tcg_ss = ss.source_set()
common_ss.add(when: 'CONFIG_TCG', if_true: files(
'cpu-exec-common.c',
))
tcg_ss.add(files( tcg_ss.add(files(
'tcg-all.c', 'tcg-all.c',
'cpu-exec-common.c',
'cpu-exec.c', 'cpu-exec.c',
'tb-maint.c', 'tb-maint.c',
'tcg-runtime-gvec.c', 'tcg-runtime-gvec.c',
@ -20,6 +22,10 @@ specific_ss.add_all(when: 'CONFIG_TCG', if_true: tcg_ss)
specific_ss.add(when: ['CONFIG_SYSTEM_ONLY', 'CONFIG_TCG'], if_true: files( specific_ss.add(when: ['CONFIG_SYSTEM_ONLY', 'CONFIG_TCG'], if_true: files(
'cputlb.c', 'cputlb.c',
))
system_ss.add(when: ['CONFIG_TCG'], if_true: files(
'icount-common.c',
'monitor.c', 'monitor.c',
)) ))

View File

@ -16,7 +16,7 @@
#include "sysemu/cpu-timers.h" #include "sysemu/cpu-timers.h"
#include "sysemu/tcg.h" #include "sysemu/tcg.h"
#include "tcg/tcg.h" #include "tcg/tcg.h"
#include "internal.h" #include "internal-common.h"
static void dump_drift_info(GString *buf) static void dump_drift_info(GString *buf)

View File

@ -104,7 +104,7 @@ static void gen_empty_udata_cb(void)
TCGv_ptr udata = tcg_temp_ebb_new_ptr(); TCGv_ptr udata = tcg_temp_ebb_new_ptr();
tcg_gen_movi_ptr(udata, 0); tcg_gen_movi_ptr(udata, 0);
tcg_gen_ld_i32(cpu_index, cpu_env, tcg_gen_ld_i32(cpu_index, tcg_env,
-offsetof(ArchCPU, env) + offsetof(CPUState, cpu_index)); -offsetof(ArchCPU, env) + offsetof(CPUState, cpu_index));
gen_helper_plugin_vcpu_udata_cb(cpu_index, udata); gen_helper_plugin_vcpu_udata_cb(cpu_index, udata);
@ -138,7 +138,7 @@ static void gen_empty_mem_cb(TCGv_i64 addr, uint32_t info)
tcg_gen_movi_i32(meminfo, info); tcg_gen_movi_i32(meminfo, info);
tcg_gen_movi_ptr(udata, 0); tcg_gen_movi_ptr(udata, 0);
tcg_gen_ld_i32(cpu_index, cpu_env, tcg_gen_ld_i32(cpu_index, tcg_env,
-offsetof(ArchCPU, env) + offsetof(CPUState, cpu_index)); -offsetof(ArchCPU, env) + offsetof(CPUState, cpu_index));
gen_helper_plugin_vcpu_mem_cb(cpu_index, meminfo, addr, udata); gen_helper_plugin_vcpu_mem_cb(cpu_index, meminfo, addr, udata);
@ -157,7 +157,7 @@ static void gen_empty_mem_helper(void)
TCGv_ptr ptr = tcg_temp_ebb_new_ptr(); TCGv_ptr ptr = tcg_temp_ebb_new_ptr();
tcg_gen_movi_ptr(ptr, 0); tcg_gen_movi_ptr(ptr, 0);
tcg_gen_st_ptr(ptr, cpu_env, offsetof(CPUState, plugin_mem_cbs) - tcg_gen_st_ptr(ptr, tcg_env, offsetof(CPUState, plugin_mem_cbs) -
offsetof(ArchCPU, env)); offsetof(ArchCPU, env));
tcg_temp_free_ptr(ptr); tcg_temp_free_ptr(ptr);
} }
@ -581,7 +581,7 @@ void plugin_gen_disable_mem_helpers(void)
if (!tcg_ctx->plugin_tb->mem_helper) { if (!tcg_ctx->plugin_tb->mem_helper) {
return; return;
} }
tcg_gen_st_ptr(tcg_constant_ptr(NULL), cpu_env, tcg_gen_st_ptr(tcg_constant_ptr(NULL), tcg_env,
offsetof(CPUState, plugin_mem_cbs) - offsetof(ArchCPU, env)); offsetof(CPUState, plugin_mem_cbs) - offsetof(ArchCPU, env));
} }
@ -849,7 +849,7 @@ void plugin_gen_insn_start(CPUState *cpu, const DisasContextBase *db)
} else { } else {
if (ptb->vaddr2 == -1) { if (ptb->vaddr2 == -1) {
ptb->vaddr2 = TARGET_PAGE_ALIGN(db->pc_first); ptb->vaddr2 = TARGET_PAGE_ALIGN(db->pc_first);
get_page_addr_code_hostp(cpu->env_ptr, ptb->vaddr2, &ptb->haddr2); get_page_addr_code_hostp(cpu_env(cpu), ptb->vaddr2, &ptb->haddr2);
} }
pinsn->haddr = ptb->haddr2 + pinsn->vaddr - ptb->vaddr2; pinsn->haddr = ptb->haddr2 + pinsn->vaddr - ptb->vaddr2;
} }
@ -866,10 +866,14 @@ void plugin_gen_insn_end(void)
* do any clean-up here and make sure things are reset in * do any clean-up here and make sure things are reset in
* plugin_gen_tb_start. * plugin_gen_tb_start.
*/ */
void plugin_gen_tb_end(CPUState *cpu) void plugin_gen_tb_end(CPUState *cpu, size_t num_insns)
{ {
struct qemu_plugin_tb *ptb = tcg_ctx->plugin_tb; struct qemu_plugin_tb *ptb = tcg_ctx->plugin_tb;
/* translator may have removed instructions, update final count */
g_assert(num_insns <= ptb->n);
ptb->n = num_insns;
/* collect instrumentation requests */ /* collect instrumentation requests */
qemu_plugin_tb_trans_cb(cpu, ptb); qemu_plugin_tb_trans_cb(cpu, ptb);

View File

@ -29,7 +29,8 @@
#include "tcg/tcg.h" #include "tcg/tcg.h"
#include "tb-hash.h" #include "tb-hash.h"
#include "tb-context.h" #include "tb-context.h"
#include "internal.h" #include "internal-common.h"
#include "internal-target.h"
/* List iterators for lists of tagged pointers in TranslationBlock. */ /* List iterators for lists of tagged pointers in TranslationBlock. */
@ -207,13 +208,12 @@ static PageDesc *page_find_alloc(tb_page_addr_t index, bool alloc)
{ {
PageDesc *pd; PageDesc *pd;
void **lp; void **lp;
int i;
/* Level 1. Always allocated. */ /* Level 1. Always allocated. */
lp = l1_map + ((index >> v_l1_shift) & (v_l1_size - 1)); lp = l1_map + ((index >> v_l1_shift) & (v_l1_size - 1));
/* Level 2..N-1. */ /* Level 2..N-1. */
for (i = v_l2_levels; i > 0; i--) { for (int i = v_l2_levels; i > 0; i--) {
void **p = qatomic_rcu_read(lp); void **p = qatomic_rcu_read(lp);
if (p == NULL) { if (p == NULL) {
@ -1083,7 +1083,8 @@ bool tb_invalidate_phys_page_unwind(tb_page_addr_t addr, uintptr_t pc)
if (current_tb_modified) { if (current_tb_modified) {
/* Force execution of one insn next time. */ /* Force execution of one insn next time. */
CPUState *cpu = current_cpu; CPUState *cpu = current_cpu;
cpu->cflags_next_tb = 1 | CF_NOIRQ | curr_cflags(current_cpu); cpu->cflags_next_tb =
1 | CF_LAST_IO | CF_NOIRQ | curr_cflags(current_cpu);
return true; return true;
} }
return false; return false;
@ -1153,7 +1154,8 @@ tb_invalidate_phys_page_range__locked(struct page_collection *pages,
if (current_tb_modified) { if (current_tb_modified) {
page_collection_unlock(pages); page_collection_unlock(pages);
/* Force execution of one insn next time. */ /* Force execution of one insn next time. */
current_cpu->cflags_next_tb = 1 | CF_NOIRQ | curr_cflags(current_cpu); current_cpu->cflags_next_tb =
1 | CF_LAST_IO | CF_NOIRQ | curr_cflags(current_cpu);
mmap_unlock(); mmap_unlock();
cpu_loop_exit_noexc(current_cpu); cpu_loop_exit_noexc(current_cpu);
} }

View File

@ -111,14 +111,14 @@ void icount_prepare_for_run(CPUState *cpu, int64_t cpu_budget)
* each vCPU execution. However u16.high can be raised * each vCPU execution. However u16.high can be raised
* asynchronously by cpu_exit/cpu_interrupt/tcg_handle_interrupt * asynchronously by cpu_exit/cpu_interrupt/tcg_handle_interrupt
*/ */
g_assert(cpu_neg(cpu)->icount_decr.u16.low == 0); g_assert(cpu->neg.icount_decr.u16.low == 0);
g_assert(cpu->icount_extra == 0); g_assert(cpu->icount_extra == 0);
replay_mutex_lock(); replay_mutex_lock();
cpu->icount_budget = MIN(icount_get_limit(), cpu_budget); cpu->icount_budget = MIN(icount_get_limit(), cpu_budget);
insns_left = MIN(0xffff, cpu->icount_budget); insns_left = MIN(0xffff, cpu->icount_budget);
cpu_neg(cpu)->icount_decr.u16.low = insns_left; cpu->neg.icount_decr.u16.low = insns_left;
cpu->icount_extra = cpu->icount_budget - insns_left; cpu->icount_extra = cpu->icount_budget - insns_left;
if (cpu->icount_budget == 0) { if (cpu->icount_budget == 0) {
@ -138,7 +138,7 @@ void icount_process_data(CPUState *cpu)
icount_update(cpu); icount_update(cpu);
/* Reset the counters */ /* Reset the counters */
cpu_neg(cpu)->icount_decr.u16.low = 0; cpu->neg.icount_decr.u16.low = 0;
cpu->icount_extra = 0; cpu->icount_extra = 0;
cpu->icount_budget = 0; cpu->icount_budget = 0;
@ -153,7 +153,7 @@ void icount_handle_interrupt(CPUState *cpu, int mask)
tcg_handle_interrupt(cpu, mask); tcg_handle_interrupt(cpu, mask);
if (qemu_cpu_is_self(cpu) && if (qemu_cpu_is_self(cpu) &&
!cpu->can_do_io !cpu->neg.can_do_io
&& (mask & ~old_mask) != 0) { && (mask & ~old_mask) != 0) {
cpu_abort(cpu, "Raised interrupt while not in I/O function"); cpu_abort(cpu, "Raised interrupt while not in I/O function");
} }

View File

@ -32,7 +32,7 @@
#include "qemu/guest-random.h" #include "qemu/guest-random.h"
#include "exec/exec-all.h" #include "exec/exec-all.h"
#include "hw/boards.h" #include "hw/boards.h"
#include "tcg/tcg.h" #include "tcg/startup.h"
#include "tcg-accel-ops.h" #include "tcg-accel-ops.h"
#include "tcg-accel-ops-mttcg.h" #include "tcg-accel-ops-mttcg.h"
@ -80,7 +80,7 @@ static void *mttcg_cpu_thread_fn(void *arg)
qemu_thread_get_self(cpu->thread); qemu_thread_get_self(cpu->thread);
cpu->thread_id = qemu_get_thread_id(); cpu->thread_id = qemu_get_thread_id();
cpu->can_do_io = 1; cpu->neg.can_do_io = true;
current_cpu = cpu; current_cpu = cpu;
cpu_thread_signal_created(cpu); cpu_thread_signal_created(cpu);
qemu_guest_random_seed_thread_part2(cpu->random_seed); qemu_guest_random_seed_thread_part2(cpu->random_seed);

View File

@ -32,7 +32,7 @@
#include "qemu/notify.h" #include "qemu/notify.h"
#include "qemu/guest-random.h" #include "qemu/guest-random.h"
#include "exec/exec-all.h" #include "exec/exec-all.h"
#include "tcg/tcg.h" #include "tcg/startup.h"
#include "tcg-accel-ops.h" #include "tcg-accel-ops.h"
#include "tcg-accel-ops-rr.h" #include "tcg-accel-ops-rr.h"
#include "tcg-accel-ops-icount.h" #include "tcg-accel-ops-icount.h"
@ -192,7 +192,7 @@ static void *rr_cpu_thread_fn(void *arg)
qemu_thread_get_self(cpu->thread); qemu_thread_get_self(cpu->thread);
cpu->thread_id = qemu_get_thread_id(); cpu->thread_id = qemu_get_thread_id();
cpu->can_do_io = 1; cpu->neg.can_do_io = true;
cpu_thread_signal_created(cpu); cpu_thread_signal_created(cpu);
qemu_guest_random_seed_thread_part2(cpu->random_seed); qemu_guest_random_seed_thread_part2(cpu->random_seed);
@ -334,7 +334,7 @@ void rr_start_vcpu_thread(CPUState *cpu)
cpu->thread = single_tcg_cpu_thread; cpu->thread = single_tcg_cpu_thread;
cpu->halt_cond = single_tcg_halt_cond; cpu->halt_cond = single_tcg_halt_cond;
cpu->thread_id = first_cpu->thread_id; cpu->thread_id = first_cpu->thread_id;
cpu->can_do_io = 1; cpu->neg.can_do_io = 1;
cpu->created = true; cpu->created = true;
} }
} }

View File

@ -91,7 +91,7 @@ void tcg_handle_interrupt(CPUState *cpu, int mask)
if (!qemu_cpu_is_self(cpu)) { if (!qemu_cpu_is_self(cpu)) {
qemu_cpu_kick(cpu); qemu_cpu_kick(cpu);
} else { } else {
qatomic_set(&cpu_neg(cpu)->icount_decr.u16.high, -1); qatomic_set(&cpu->neg.icount_decr.u16.high, -1);
} }
} }

View File

@ -27,7 +27,7 @@
#include "sysemu/tcg.h" #include "sysemu/tcg.h"
#include "exec/replay-core.h" #include "exec/replay-core.h"
#include "sysemu/cpu-timers.h" #include "sysemu/cpu-timers.h"
#include "tcg/tcg.h" #include "tcg/startup.h"
#include "tcg/oversized-guest.h" #include "tcg/oversized-guest.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
@ -38,7 +38,7 @@
#if !defined(CONFIG_USER_ONLY) #if !defined(CONFIG_USER_ONLY)
#include "hw/boards.h" #include "hw/boards.h"
#endif #endif
#include "internal.h" #include "internal-target.h"
struct TCGState { struct TCGState {
AccelState parent_obj; AccelState parent_obj;
@ -129,7 +129,7 @@ static int tcg_init_machine(MachineState *ms)
* There's no guest base to take into account, so go ahead and * There's no guest base to take into account, so go ahead and
* initialize the prologue now. * initialize the prologue now.
*/ */
tcg_prologue_init(tcg_ctx); tcg_prologue_init();
#endif #endif
return 0; return 0;
@ -235,6 +235,8 @@ static void tcg_accel_class_init(ObjectClass *oc, void *data)
AccelClass *ac = ACCEL_CLASS(oc); AccelClass *ac = ACCEL_CLASS(oc);
ac->name = "tcg"; ac->name = "tcg";
ac->init_machine = tcg_init_machine; ac->init_machine = tcg_init_machine;
ac->cpu_common_realize = tcg_exec_realizefn;
ac->cpu_common_unrealize = tcg_exec_unrealizefn;
ac->allowed = &tcg_allowed; ac->allowed = &tcg_allowed;
ac->gdbstub_supported_sstep_flags = tcg_gdbstub_supported_sstep_flags; ac->gdbstub_supported_sstep_flags = tcg_gdbstub_supported_sstep_flags;

View File

@ -138,7 +138,7 @@ __thread CPUState* libafl_breakpoint_cpu;
__thread vaddr libafl_breakpoint_pc; __thread vaddr libafl_breakpoint_pc;
#ifdef TARGET_ARM #ifdef TARGET_ARM
#define THUMB_MASK(value) (value | libafl_breakpoint_cpu->env_ptr->thumb) #define THUMB_MASK(value) (value | cpu_env(libafl_breakpoint_cpu)->thumb)
#else #else
#define THUMB_MASK(value) value #define THUMB_MASK(value) value
#endif #endif

View File

@ -61,7 +61,8 @@
#include "tb-jmp-cache.h" #include "tb-jmp-cache.h"
#include "tb-hash.h" #include "tb-hash.h"
#include "tb-context.h" #include "tb-context.h"
#include "internal.h" #include "internal-common.h"
#include "internal-target.h"
#include "perf.h" #include "perf.h"
#include "tcg/insn-start-words.h" #include "tcg/insn-start-words.h"
@ -771,7 +772,7 @@ void cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb,
* Reset the cycle counter to the start of the block and * Reset the cycle counter to the start of the block and
* shift if to the number of actually executed instructions. * shift if to the number of actually executed instructions.
*/ */
cpu_neg(cpu)->icount_decr.u16.low += insns_left; cpu->neg.icount_decr.u16.low += insns_left;
} }
cpu->cc->tcg_ops->restore_state_to_opc(cpu, tb, data); cpu->cc->tcg_ops->restore_state_to_opc(cpu, tb, data);
@ -886,7 +887,7 @@ TranslationBlock *libafl_gen_edge(CPUState *cpu, target_ulong src_block,
target_ulong cs_base, uint32_t flags, target_ulong cs_base, uint32_t flags,
int cflags) int cflags)
{ {
CPUArchState *env = cpu->env_ptr; CPUArchState *env = cpu_env(cpu);
TranslationBlock *tb, *existing_tb; TranslationBlock *tb, *existing_tb;
tb_page_addr_t phys_pc, phys_page2; tb_page_addr_t phys_pc, phys_page2;
target_ulong virt_page2; target_ulong virt_page2;
@ -1048,7 +1049,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
vaddr pc, uint64_t cs_base, vaddr pc, uint64_t cs_base,
uint32_t flags, int cflags) uint32_t flags, int cflags)
{ {
CPUArchState *env = cpu->env_ptr; CPUArchState *env = cpu_env(cpu);
TranslationBlock *tb, *existing_tb; TranslationBlock *tb, *existing_tb;
tb_page_addr_t phys_pc, phys_p2; tb_page_addr_t phys_pc, phys_p2;
tcg_insn_unit *gen_code_buf; tcg_insn_unit *gen_code_buf;
@ -1104,8 +1105,6 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
tcg_ctx->page_bits = TARGET_PAGE_BITS; tcg_ctx->page_bits = TARGET_PAGE_BITS;
tcg_ctx->page_mask = TARGET_PAGE_MASK; tcg_ctx->page_mask = TARGET_PAGE_MASK;
tcg_ctx->tlb_dyn_max_bits = CPU_TLB_DYN_MAX_BITS; tcg_ctx->tlb_dyn_max_bits = CPU_TLB_DYN_MAX_BITS;
tcg_ctx->tlb_fast_offset =
(int)offsetof(ArchCPU, neg.tlb.f) - (int)offsetof(ArchCPU, env);
#endif #endif
tcg_ctx->insn_start_words = TARGET_INSN_START_WORDS; tcg_ctx->insn_start_words = TARGET_INSN_START_WORDS;
#ifdef TCG_GUEST_DEFAULT_MO #ifdef TCG_GUEST_DEFAULT_MO
@ -1348,7 +1347,7 @@ void tb_check_watchpoint(CPUState *cpu, uintptr_t retaddr)
} else { } else {
/* The exception probably happened in a helper. The CPU state should /* The exception probably happened in a helper. The CPU state should
have been saved before calling it. Fetch the PC from there. */ have been saved before calling it. Fetch the PC from there. */
CPUArchState *env = cpu->env_ptr; CPUArchState *env = cpu_env(cpu);
vaddr pc; vaddr pc;
uint64_t cs_base; uint64_t cs_base;
tb_page_addr_t addr; tb_page_addr_t addr;
@ -1391,7 +1390,7 @@ void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr)
cc = CPU_GET_CLASS(cpu); cc = CPU_GET_CLASS(cpu);
if (cc->tcg_ops->io_recompile_replay_branch && if (cc->tcg_ops->io_recompile_replay_branch &&
cc->tcg_ops->io_recompile_replay_branch(cpu, tb)) { cc->tcg_ops->io_recompile_replay_branch(cpu, tb)) {
cpu_neg(cpu)->icount_decr.u16.low++; cpu->neg.icount_decr.u16.low++;
n = 2; n = 2;
} }
@ -1547,7 +1546,7 @@ void cpu_interrupt(CPUState *cpu, int mask)
{ {
g_assert(qemu_mutex_iothread_locked()); g_assert(qemu_mutex_iothread_locked());
cpu->interrupt_request |= mask; cpu->interrupt_request |= mask;
qatomic_set(&cpu_neg(cpu)->icount_decr.u16.high, -1); qatomic_set(&cpu->neg.icount_decr.u16.high, -1);
} }
#endif /* CONFIG_USER_ONLY */ #endif /* CONFIG_USER_ONLY */

View File

@ -14,28 +14,23 @@
#include "exec/translator.h" #include "exec/translator.h"
#include "exec/plugin-gen.h" #include "exec/plugin-gen.h"
#include "tcg/tcg-op-common.h" #include "tcg/tcg-op-common.h"
#include "internal.h" #include "internal-target.h"
static void gen_io_start(void) static void set_can_do_io(DisasContextBase *db, bool val)
{ {
tcg_gen_st_i32(tcg_constant_i32(1), cpu_env, if (db->saved_can_do_io != val) {
offsetof(ArchCPU, parent_obj.can_do_io) - db->saved_can_do_io = val;
QEMU_BUILD_BUG_ON(sizeof_field(CPUState, neg.can_do_io) != 1);
tcg_gen_st8_i32(tcg_constant_i32(val), tcg_env,
offsetof(ArchCPU, parent_obj.neg.can_do_io) -
offsetof(ArchCPU, env)); offsetof(ArchCPU, env));
} }
}
bool translator_io_start(DisasContextBase *db) bool translator_io_start(DisasContextBase *db)
{ {
uint32_t cflags = tb_cflags(db->tb); set_can_do_io(db, true);
if (!(cflags & CF_USE_ICOUNT)) {
return false;
}
if (db->num_insns == db->max_insns && (cflags & CF_LAST_IO)) {
/* Already started in translator_loop. */
return true;
}
gen_io_start();
/* /*
* Ensure that this instruction will be the last in the TB. * Ensure that this instruction will be the last in the TB.
@ -47,14 +42,17 @@ bool translator_io_start(DisasContextBase *db)
return true; return true;
} }
static TCGOp *gen_tb_start(uint32_t cflags) static TCGOp *gen_tb_start(DisasContextBase *db, uint32_t cflags)
{ {
TCGv_i32 count = tcg_temp_new_i32(); TCGv_i32 count = NULL;
TCGOp *icount_start_insn = NULL; TCGOp *icount_start_insn = NULL;
tcg_gen_ld_i32(count, cpu_env, if ((cflags & CF_USE_ICOUNT) || !(cflags & CF_NOIRQ)) {
offsetof(ArchCPU, neg.icount_decr.u32) - count = tcg_temp_new_i32();
offsetof(ArchCPU, env)); tcg_gen_ld_i32(count, tcg_env,
offsetof(ArchCPU, parent_obj.neg.icount_decr.u32)
- offsetof(ArchCPU, env));
}
if (cflags & CF_USE_ICOUNT) { if (cflags & CF_USE_ICOUNT) {
/* /*
@ -81,21 +79,18 @@ static TCGOp *gen_tb_start(uint32_t cflags)
} }
if (cflags & CF_USE_ICOUNT) { if (cflags & CF_USE_ICOUNT) {
tcg_gen_st16_i32(count, cpu_env, tcg_gen_st16_i32(count, tcg_env,
offsetof(ArchCPU, neg.icount_decr.u16.low) - offsetof(ArchCPU, parent_obj.neg.icount_decr.u16.low)
offsetof(ArchCPU, env)); - offsetof(ArchCPU, env));
/*
* cpu->can_do_io is cleared automatically here at the beginning of
* each translation block. The cost is minimal and only paid for
* -icount, plus it would be very easy to forget doing it in the
* translator. Doing it here means we don't need a gen_io_end() to
* go with gen_io_start().
*/
tcg_gen_st_i32(tcg_constant_i32(0), cpu_env,
offsetof(ArchCPU, parent_obj.can_do_io) -
offsetof(ArchCPU, env));
} }
/*
* cpu->neg.can_do_io is set automatically here at the beginning of
* each translation block. The cost is minimal, plus it would be
* very easy to forget doing it in the translator.
*/
set_can_do_io(db, db->max_insns == 1 && (cflags & CF_LAST_IO));
return icount_start_insn; return icount_start_insn;
} }
@ -187,6 +182,7 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns,
db->num_insns = 0; db->num_insns = 0;
db->max_insns = *max_insns; db->max_insns = *max_insns;
db->singlestep_enabled = cflags & CF_SINGLE_STEP; db->singlestep_enabled = cflags & CF_SINGLE_STEP;
db->saved_can_do_io = -1;
db->host_addr[0] = host_pc; db->host_addr[0] = host_pc;
db->host_addr[1] = NULL; db->host_addr[1] = NULL;
@ -194,11 +190,18 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns,
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */ tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */
/* Start translating. */ /* Start translating. */
icount_start_insn = gen_tb_start(cflags); icount_start_insn = gen_tb_start(db, cflags);
ops->tb_start(db, cpu); ops->tb_start(db, cpu);
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */ tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */
plugin_enabled = plugin_gen_tb_start(cpu, db, cflags & CF_MEMI_ONLY); if (cflags & CF_MEMI_ONLY) {
/* We should only see CF_MEMI_ONLY for io_recompile. */
assert(cflags & CF_LAST_IO);
plugin_enabled = plugin_gen_tb_start(cpu, db, true);
} else {
plugin_enabled = plugin_gen_tb_start(cpu, db, false);
}
db->plugin_enabled = plugin_enabled;
while (true) { while (true) {
*max_insns = ++db->num_insns; *max_insns = ++db->num_insns;
@ -235,7 +238,7 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns,
while (bp) { while (bp) {
if (bp->addr == db->pc_next) { if (bp->addr == db->pc_next) {
TCGv_i64 tmp0 = tcg_constant_i64((uint64_t)db->pc_next); TCGv_i64 tmp0 = tcg_constant_i64((uint64_t)db->pc_next);
gen_helper_libafl_qemu_handle_breakpoint(cpu_env, tmp0); gen_helper_libafl_qemu_handle_breakpoint(tcg_env, tmp0);
tcg_temp_free_i64(tmp0); tcg_temp_free_i64(tmp0);
} }
bp = bp->next; bp = bp->next;
@ -244,13 +247,13 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns,
libafl_gen_cur_pc = db->pc_next; libafl_gen_cur_pc = db->pc_next;
// 0x0f, 0x3a, 0xf2, 0x44 // 0x0f, 0x3a, 0xf2, 0x44
uint8_t backdoor = translator_ldub(cpu->env_ptr, db, db->pc_next); uint8_t backdoor = translator_ldub(cpu_env(cpu), db, db->pc_next);
if (backdoor == 0x0f) { if (backdoor == 0x0f) {
backdoor = translator_ldub(cpu->env_ptr, db, db->pc_next +1); backdoor = translator_ldub(cpu_env(cpu), db, db->pc_next +1);
if (backdoor == 0x3a) { if (backdoor == 0x3a) {
backdoor = translator_ldub(cpu->env_ptr, db, db->pc_next +2); backdoor = translator_ldub(cpu_env(cpu), db, db->pc_next +2);
if (backdoor == 0xf2) { if (backdoor == 0xf2) {
backdoor = translator_ldub(cpu->env_ptr, db, db->pc_next +3); backdoor = translator_ldub(cpu_env(cpu), db, db->pc_next +3);
if (backdoor == 0x44) { if (backdoor == 0x44) {
struct libafl_backdoor_hook* hk = libafl_backdoor_hooks; struct libafl_backdoor_hook* hk = libafl_backdoor_hooks;
while (hk) { while (hk) {
@ -288,13 +291,9 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns,
the next instruction. */ the next instruction. */
if (db->num_insns == db->max_insns && (cflags & CF_LAST_IO)) { if (db->num_insns == db->max_insns && (cflags & CF_LAST_IO)) {
/* Accept I/O on the last instruction. */ /* Accept I/O on the last instruction. */
gen_io_start(); set_can_do_io(db, true);
ops->translate_insn(db, cpu);
} else {
/* we should only see CF_MEMI_ONLY for io_recompile */
tcg_debug_assert(!(cflags & CF_MEMI_ONLY));
ops->translate_insn(db, cpu);
} }
ops->translate_insn(db, cpu);
post_translate_insn: post_translate_insn:
/* /*
@ -328,7 +327,7 @@ post_translate_insn:
gen_tb_end(tb, cflags, icount_start_insn, db->num_insns); gen_tb_end(tb, cflags, icount_start_insn, db->num_insns);
if (plugin_enabled) { if (plugin_enabled) {
plugin_gen_tb_end(cpu); plugin_gen_tb_end(cpu, db->num_insns);
} }
/* The disas_log hook may use these values rather than recompute. */ /* The disas_log hook may use these values rather than recompute. */

View File

@ -29,7 +29,8 @@
#include "qemu/atomic128.h" #include "qemu/atomic128.h"
#include "trace/trace-root.h" #include "trace/trace-root.h"
#include "tcg/tcg-ldst.h" #include "tcg/tcg-ldst.h"
#include "internal.h" #include "internal-common.h"
#include "internal-target.h"
__thread uintptr_t helper_retaddr; __thread uintptr_t helper_retaddr;
@ -939,9 +940,9 @@ void *page_get_target_data(target_ulong address)
void page_reset_target_data(target_ulong start, target_ulong last) { } void page_reset_target_data(target_ulong start, target_ulong last) { }
#endif /* TARGET_PAGE_DATA_SIZE */ #endif /* TARGET_PAGE_DATA_SIZE */
/* The softmmu versions of these helpers are in cputlb.c. */ /* The system-mode versions of these helpers are in cputlb.c. */
static void *cpu_mmu_lookup(CPUArchState *env, vaddr addr, static void *cpu_mmu_lookup(CPUState *cpu, vaddr addr,
MemOp mop, uintptr_t ra, MMUAccessType type) MemOp mop, uintptr_t ra, MMUAccessType type)
{ {
int a_bits = get_alignment_bits(mop); int a_bits = get_alignment_bits(mop);
@ -949,60 +950,39 @@ static void *cpu_mmu_lookup(CPUArchState *env, vaddr addr,
/* Enforce guest required alignment. */ /* Enforce guest required alignment. */
if (unlikely(addr & ((1 << a_bits) - 1))) { if (unlikely(addr & ((1 << a_bits) - 1))) {
cpu_loop_exit_sigbus(env_cpu(env), addr, type, ra); cpu_loop_exit_sigbus(cpu, addr, type, ra);
} }
ret = g2h(env_cpu(env), addr); ret = g2h(cpu, addr);
set_helper_retaddr(ra); set_helper_retaddr(ra);
return ret; return ret;
} }
#include "ldst_atomicity.c.inc" #include "ldst_atomicity.c.inc"
static uint8_t do_ld1_mmu(CPUArchState *env, abi_ptr addr, static uint8_t do_ld1_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi,
MemOp mop, uintptr_t ra) uintptr_t ra, MMUAccessType access_type)
{ {
void *haddr; void *haddr;
uint8_t ret; uint8_t ret;
tcg_debug_assert((mop & MO_SIZE) == MO_8);
cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD);
haddr = cpu_mmu_lookup(env, addr, mop, ra, MMU_DATA_LOAD); haddr = cpu_mmu_lookup(cpu, addr, get_memop(oi), ra, access_type);
ret = ldub_p(haddr); ret = ldub_p(haddr);
clear_helper_retaddr(); clear_helper_retaddr();
return ret; return ret;
} }
tcg_target_ulong helper_ldub_mmu(CPUArchState *env, uint64_t addr, static uint16_t do_ld2_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi,
MemOpIdx oi, uintptr_t ra) uintptr_t ra, MMUAccessType access_type)
{
return do_ld1_mmu(env, addr, get_memop(oi), ra);
}
tcg_target_ulong helper_ldsb_mmu(CPUArchState *env, uint64_t addr,
MemOpIdx oi, uintptr_t ra)
{
return (int8_t)do_ld1_mmu(env, addr, get_memop(oi), ra);
}
uint8_t cpu_ldb_mmu(CPUArchState *env, abi_ptr addr,
MemOpIdx oi, uintptr_t ra)
{
uint8_t ret = do_ld1_mmu(env, addr, get_memop(oi), ra);
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_R);
return ret;
}
static uint16_t do_ld2_mmu(CPUArchState *env, abi_ptr addr,
MemOp mop, uintptr_t ra)
{ {
void *haddr; void *haddr;
uint16_t ret; uint16_t ret;
MemOp mop = get_memop(oi);
tcg_debug_assert((mop & MO_SIZE) == MO_16);
cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD);
haddr = cpu_mmu_lookup(env, addr, mop, ra, MMU_DATA_LOAD); haddr = cpu_mmu_lookup(cpu, addr, mop, ra, access_type);
ret = load_atom_2(env, ra, haddr, mop); ret = load_atom_2(cpu, ra, haddr, mop);
clear_helper_retaddr(); clear_helper_retaddr();
if (mop & MO_BSWAP) { if (mop & MO_BSWAP) {
@ -1011,36 +991,16 @@ static uint16_t do_ld2_mmu(CPUArchState *env, abi_ptr addr,
return ret; return ret;
} }
tcg_target_ulong helper_lduw_mmu(CPUArchState *env, uint64_t addr, static uint32_t do_ld4_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi,
MemOpIdx oi, uintptr_t ra) uintptr_t ra, MMUAccessType access_type)
{
return do_ld2_mmu(env, addr, get_memop(oi), ra);
}
tcg_target_ulong helper_ldsw_mmu(CPUArchState *env, uint64_t addr,
MemOpIdx oi, uintptr_t ra)
{
return (int16_t)do_ld2_mmu(env, addr, get_memop(oi), ra);
}
uint16_t cpu_ldw_mmu(CPUArchState *env, abi_ptr addr,
MemOpIdx oi, uintptr_t ra)
{
uint16_t ret = do_ld2_mmu(env, addr, get_memop(oi), ra);
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_R);
return ret;
}
static uint32_t do_ld4_mmu(CPUArchState *env, abi_ptr addr,
MemOp mop, uintptr_t ra)
{ {
void *haddr; void *haddr;
uint32_t ret; uint32_t ret;
MemOp mop = get_memop(oi);
tcg_debug_assert((mop & MO_SIZE) == MO_32);
cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD);
haddr = cpu_mmu_lookup(env, addr, mop, ra, MMU_DATA_LOAD); haddr = cpu_mmu_lookup(cpu, addr, mop, ra, access_type);
ret = load_atom_4(env, ra, haddr, mop); ret = load_atom_4(cpu, ra, haddr, mop);
clear_helper_retaddr(); clear_helper_retaddr();
if (mop & MO_BSWAP) { if (mop & MO_BSWAP) {
@ -1049,36 +1009,16 @@ static uint32_t do_ld4_mmu(CPUArchState *env, abi_ptr addr,
return ret; return ret;
} }
tcg_target_ulong helper_ldul_mmu(CPUArchState *env, uint64_t addr, static uint64_t do_ld8_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi,
MemOpIdx oi, uintptr_t ra) uintptr_t ra, MMUAccessType access_type)
{
return do_ld4_mmu(env, addr, get_memop(oi), ra);
}
tcg_target_ulong helper_ldsl_mmu(CPUArchState *env, uint64_t addr,
MemOpIdx oi, uintptr_t ra)
{
return (int32_t)do_ld4_mmu(env, addr, get_memop(oi), ra);
}
uint32_t cpu_ldl_mmu(CPUArchState *env, abi_ptr addr,
MemOpIdx oi, uintptr_t ra)
{
uint32_t ret = do_ld4_mmu(env, addr, get_memop(oi), ra);
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_R);
return ret;
}
static uint64_t do_ld8_mmu(CPUArchState *env, abi_ptr addr,
MemOp mop, uintptr_t ra)
{ {
void *haddr; void *haddr;
uint64_t ret; uint64_t ret;
MemOp mop = get_memop(oi);
tcg_debug_assert((mop & MO_SIZE) == MO_64);
cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD);
haddr = cpu_mmu_lookup(env, addr, mop, ra, MMU_DATA_LOAD); haddr = cpu_mmu_lookup(cpu, addr, mop, ra, access_type);
ret = load_atom_8(env, ra, haddr, mop); ret = load_atom_8(cpu, ra, haddr, mop);
clear_helper_retaddr(); clear_helper_retaddr();
if (mop & MO_BSWAP) { if (mop & MO_BSWAP) {
@ -1087,30 +1027,17 @@ static uint64_t do_ld8_mmu(CPUArchState *env, abi_ptr addr,
return ret; return ret;
} }
uint64_t helper_ldq_mmu(CPUArchState *env, uint64_t addr, static Int128 do_ld16_mmu(CPUState *cpu, abi_ptr addr,
MemOpIdx oi, uintptr_t ra) MemOpIdx oi, uintptr_t ra)
{
return do_ld8_mmu(env, addr, get_memop(oi), ra);
}
uint64_t cpu_ldq_mmu(CPUArchState *env, abi_ptr addr,
MemOpIdx oi, uintptr_t ra)
{
uint64_t ret = do_ld8_mmu(env, addr, get_memop(oi), ra);
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_R);
return ret;
}
static Int128 do_ld16_mmu(CPUArchState *env, abi_ptr addr,
MemOp mop, uintptr_t ra)
{ {
void *haddr; void *haddr;
Int128 ret; Int128 ret;
MemOp mop = get_memop(oi);
tcg_debug_assert((mop & MO_SIZE) == MO_128); tcg_debug_assert((mop & MO_SIZE) == MO_128);
cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD);
haddr = cpu_mmu_lookup(env, addr, mop, ra, MMU_DATA_LOAD); haddr = cpu_mmu_lookup(cpu, addr, mop, ra, MMU_DATA_LOAD);
ret = load_atom_16(env, ra, haddr, mop); ret = load_atom_16(cpu, ra, haddr, mop);
clear_helper_retaddr(); clear_helper_retaddr();
if (mop & MO_BSWAP) { if (mop & MO_BSWAP) {
@ -1119,171 +1046,81 @@ static Int128 do_ld16_mmu(CPUArchState *env, abi_ptr addr,
return ret; return ret;
} }
Int128 helper_ld16_mmu(CPUArchState *env, uint64_t addr, static void do_st1_mmu(CPUState *cpu, vaddr addr, uint8_t val,
MemOpIdx oi, uintptr_t ra) MemOpIdx oi, uintptr_t ra)
{
return do_ld16_mmu(env, addr, get_memop(oi), ra);
}
Int128 helper_ld_i128(CPUArchState *env, uint64_t addr, MemOpIdx oi)
{
return helper_ld16_mmu(env, addr, oi, GETPC());
}
Int128 cpu_ld16_mmu(CPUArchState *env, abi_ptr addr,
MemOpIdx oi, uintptr_t ra)
{
Int128 ret = do_ld16_mmu(env, addr, get_memop(oi), ra);
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_R);
return ret;
}
static void do_st1_mmu(CPUArchState *env, abi_ptr addr, uint8_t val,
MemOp mop, uintptr_t ra)
{ {
void *haddr; void *haddr;
tcg_debug_assert((mop & MO_SIZE) == MO_8);
cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST);
haddr = cpu_mmu_lookup(env, addr, mop, ra, MMU_DATA_STORE); haddr = cpu_mmu_lookup(cpu, addr, get_memop(oi), ra, MMU_DATA_STORE);
stb_p(haddr, val); stb_p(haddr, val);
clear_helper_retaddr(); clear_helper_retaddr();
} }
void helper_stb_mmu(CPUArchState *env, uint64_t addr, uint32_t val, static void do_st2_mmu(CPUState *cpu, vaddr addr, uint16_t val,
MemOpIdx oi, uintptr_t ra) MemOpIdx oi, uintptr_t ra)
{
do_st1_mmu(env, addr, val, get_memop(oi), ra);
}
void cpu_stb_mmu(CPUArchState *env, abi_ptr addr, uint8_t val,
MemOpIdx oi, uintptr_t ra)
{
do_st1_mmu(env, addr, val, get_memop(oi), ra);
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_W);
}
static void do_st2_mmu(CPUArchState *env, abi_ptr addr, uint16_t val,
MemOp mop, uintptr_t ra)
{ {
void *haddr; void *haddr;
MemOp mop = get_memop(oi);
tcg_debug_assert((mop & MO_SIZE) == MO_16);
cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST);
haddr = cpu_mmu_lookup(env, addr, mop, ra, MMU_DATA_STORE); haddr = cpu_mmu_lookup(cpu, addr, mop, ra, MMU_DATA_STORE);
if (mop & MO_BSWAP) { if (mop & MO_BSWAP) {
val = bswap16(val); val = bswap16(val);
} }
store_atom_2(env, ra, haddr, mop, val); store_atom_2(cpu, ra, haddr, mop, val);
clear_helper_retaddr(); clear_helper_retaddr();
} }
void helper_stw_mmu(CPUArchState *env, uint64_t addr, uint32_t val, static void do_st4_mmu(CPUState *cpu, vaddr addr, uint32_t val,
MemOpIdx oi, uintptr_t ra) MemOpIdx oi, uintptr_t ra)
{
do_st2_mmu(env, addr, val, get_memop(oi), ra);
}
void cpu_stw_mmu(CPUArchState *env, abi_ptr addr, uint16_t val,
MemOpIdx oi, uintptr_t ra)
{
do_st2_mmu(env, addr, val, get_memop(oi), ra);
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_W);
}
static void do_st4_mmu(CPUArchState *env, abi_ptr addr, uint32_t val,
MemOp mop, uintptr_t ra)
{ {
void *haddr; void *haddr;
MemOp mop = get_memop(oi);
tcg_debug_assert((mop & MO_SIZE) == MO_32);
cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST);
haddr = cpu_mmu_lookup(env, addr, mop, ra, MMU_DATA_STORE); haddr = cpu_mmu_lookup(cpu, addr, mop, ra, MMU_DATA_STORE);
if (mop & MO_BSWAP) { if (mop & MO_BSWAP) {
val = bswap32(val); val = bswap32(val);
} }
store_atom_4(env, ra, haddr, mop, val); store_atom_4(cpu, ra, haddr, mop, val);
clear_helper_retaddr(); clear_helper_retaddr();
} }
void helper_stl_mmu(CPUArchState *env, uint64_t addr, uint32_t val, static void do_st8_mmu(CPUState *cpu, vaddr addr, uint64_t val,
MemOpIdx oi, uintptr_t ra) MemOpIdx oi, uintptr_t ra)
{
do_st4_mmu(env, addr, val, get_memop(oi), ra);
}
void cpu_stl_mmu(CPUArchState *env, abi_ptr addr, uint32_t val,
MemOpIdx oi, uintptr_t ra)
{
do_st4_mmu(env, addr, val, get_memop(oi), ra);
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_W);
}
static void do_st8_mmu(CPUArchState *env, abi_ptr addr, uint64_t val,
MemOp mop, uintptr_t ra)
{ {
void *haddr; void *haddr;
MemOp mop = get_memop(oi);
tcg_debug_assert((mop & MO_SIZE) == MO_64);
cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST);
haddr = cpu_mmu_lookup(env, addr, mop, ra, MMU_DATA_STORE); haddr = cpu_mmu_lookup(cpu, addr, mop, ra, MMU_DATA_STORE);
if (mop & MO_BSWAP) { if (mop & MO_BSWAP) {
val = bswap64(val); val = bswap64(val);
} }
store_atom_8(env, ra, haddr, mop, val); store_atom_8(cpu, ra, haddr, mop, val);
clear_helper_retaddr(); clear_helper_retaddr();
} }
void helper_stq_mmu(CPUArchState *env, uint64_t addr, uint64_t val, static void do_st16_mmu(CPUState *cpu, vaddr addr, Int128 val,
MemOpIdx oi, uintptr_t ra) MemOpIdx oi, uintptr_t ra)
{
do_st8_mmu(env, addr, val, get_memop(oi), ra);
}
void cpu_stq_mmu(CPUArchState *env, abi_ptr addr, uint64_t val,
MemOpIdx oi, uintptr_t ra)
{
do_st8_mmu(env, addr, val, get_memop(oi), ra);
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_W);
}
static void do_st16_mmu(CPUArchState *env, abi_ptr addr, Int128 val,
MemOp mop, uintptr_t ra)
{ {
void *haddr; void *haddr;
MemOpIdx mop = get_memop(oi);
tcg_debug_assert((mop & MO_SIZE) == MO_128);
cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST);
haddr = cpu_mmu_lookup(env, addr, mop, ra, MMU_DATA_STORE); haddr = cpu_mmu_lookup(cpu, addr, mop, ra, MMU_DATA_STORE);
if (mop & MO_BSWAP) { if (mop & MO_BSWAP) {
val = bswap128(val); val = bswap128(val);
} }
store_atom_16(env, ra, haddr, mop, val); store_atom_16(cpu, ra, haddr, mop, val);
clear_helper_retaddr(); clear_helper_retaddr();
} }
void helper_st16_mmu(CPUArchState *env, uint64_t addr, Int128 val,
MemOpIdx oi, uintptr_t ra)
{
do_st16_mmu(env, addr, val, get_memop(oi), ra);
}
void helper_st_i128(CPUArchState *env, uint64_t addr, Int128 val, MemOpIdx oi)
{
helper_st16_mmu(env, addr, val, oi, GETPC());
}
void cpu_st16_mmu(CPUArchState *env, abi_ptr addr,
Int128 val, MemOpIdx oi, uintptr_t ra)
{
do_st16_mmu(env, addr, val, get_memop(oi), ra);
qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_W);
}
uint32_t cpu_ldub_code(CPUArchState *env, abi_ptr ptr) uint32_t cpu_ldub_code(CPUArchState *env, abi_ptr ptr)
{ {
uint32_t ret; uint32_t ret;
@ -1330,7 +1167,7 @@ uint8_t cpu_ldb_code_mmu(CPUArchState *env, abi_ptr addr,
void *haddr; void *haddr;
uint8_t ret; uint8_t ret;
haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_INST_FETCH); haddr = cpu_mmu_lookup(env_cpu(env), addr, oi, ra, MMU_INST_FETCH);
ret = ldub_p(haddr); ret = ldub_p(haddr);
clear_helper_retaddr(); clear_helper_retaddr();
return ret; return ret;
@ -1342,7 +1179,7 @@ uint16_t cpu_ldw_code_mmu(CPUArchState *env, abi_ptr addr,
void *haddr; void *haddr;
uint16_t ret; uint16_t ret;
haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_INST_FETCH); haddr = cpu_mmu_lookup(env_cpu(env), addr, oi, ra, MMU_INST_FETCH);
ret = lduw_p(haddr); ret = lduw_p(haddr);
clear_helper_retaddr(); clear_helper_retaddr();
if (get_memop(oi) & MO_BSWAP) { if (get_memop(oi) & MO_BSWAP) {
@ -1357,7 +1194,7 @@ uint32_t cpu_ldl_code_mmu(CPUArchState *env, abi_ptr addr,
void *haddr; void *haddr;
uint32_t ret; uint32_t ret;
haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_INST_FETCH); haddr = cpu_mmu_lookup(env_cpu(env), addr, oi, ra, MMU_INST_FETCH);
ret = ldl_p(haddr); ret = ldl_p(haddr);
clear_helper_retaddr(); clear_helper_retaddr();
if (get_memop(oi) & MO_BSWAP) { if (get_memop(oi) & MO_BSWAP) {
@ -1372,7 +1209,7 @@ uint64_t cpu_ldq_code_mmu(CPUArchState *env, abi_ptr addr,
void *haddr; void *haddr;
uint64_t ret; uint64_t ret;
haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_LOAD); haddr = cpu_mmu_lookup(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD);
ret = ldq_p(haddr); ret = ldq_p(haddr);
clear_helper_retaddr(); clear_helper_retaddr();
if (get_memop(oi) & MO_BSWAP) { if (get_memop(oi) & MO_BSWAP) {
@ -1386,7 +1223,7 @@ uint64_t cpu_ldq_code_mmu(CPUArchState *env, abi_ptr addr,
/* /*
* Do not allow unaligned operations to proceed. Return the host address. * Do not allow unaligned operations to proceed. Return the host address.
*/ */
static void *atomic_mmu_lookup(CPUArchState *env, vaddr addr, MemOpIdx oi, static void *atomic_mmu_lookup(CPUState *cpu, vaddr addr, MemOpIdx oi,
int size, uintptr_t retaddr) int size, uintptr_t retaddr)
{ {
MemOp mop = get_memop(oi); MemOp mop = get_memop(oi);
@ -1395,15 +1232,15 @@ static void *atomic_mmu_lookup(CPUArchState *env, vaddr addr, MemOpIdx oi,
/* Enforce guest required alignment. */ /* Enforce guest required alignment. */
if (unlikely(addr & ((1 << a_bits) - 1))) { if (unlikely(addr & ((1 << a_bits) - 1))) {
cpu_loop_exit_sigbus(env_cpu(env), addr, MMU_DATA_STORE, retaddr); cpu_loop_exit_sigbus(cpu, addr, MMU_DATA_STORE, retaddr);
} }
/* Enforce qemu required alignment. */ /* Enforce qemu required alignment. */
if (unlikely(addr & (size - 1))) { if (unlikely(addr & (size - 1))) {
cpu_loop_exit_atomic(env_cpu(env), retaddr); cpu_loop_exit_atomic(cpu, retaddr);
} }
ret = g2h(env_cpu(env), addr); ret = g2h(cpu, addr);
set_helper_retaddr(retaddr); set_helper_retaddr(retaddr);
return ret; return ret;
} }

View File

@ -904,7 +904,7 @@ static void alsa_init_per_direction(AudiodevAlsaPerDirectionOptions *apdo)
} }
} }
static void *alsa_audio_init(Audiodev *dev) static void *alsa_audio_init(Audiodev *dev, Error **errp)
{ {
AudiodevAlsaOptions *aopts; AudiodevAlsaOptions *aopts;
assert(dev->driver == AUDIODEV_DRIVER_ALSA); assert(dev->driver == AUDIODEV_DRIVER_ALSA);
@ -960,7 +960,6 @@ static struct audio_driver alsa_audio_driver = {
.init = alsa_audio_init, .init = alsa_audio_init,
.fini = alsa_audio_fini, .fini = alsa_audio_fini,
.pcm_ops = &alsa_pcm_ops, .pcm_ops = &alsa_pcm_ops,
.can_be_default = 1,
.max_voices_out = INT_MAX, .max_voices_out = INT_MAX,
.max_voices_in = INT_MAX, .max_voices_in = INT_MAX,
.voice_size_out = sizeof (ALSAVoiceOut), .voice_size_out = sizeof (ALSAVoiceOut),

View File

@ -26,6 +26,7 @@
#include "audio/audio.h" #include "audio/audio.h"
#include "monitor/hmp.h" #include "monitor/hmp.h"
#include "monitor/monitor.h" #include "monitor/monitor.h"
#include "qapi/error.h"
#include "qapi/qmp/qdict.h" #include "qapi/qmp/qdict.h"
static QLIST_HEAD (capture_list_head, CaptureState) capture_head; static QLIST_HEAD (capture_list_head, CaptureState) capture_head;
@ -65,10 +66,11 @@ void hmp_wavcapture(Monitor *mon, const QDict *qdict)
int nchannels = qdict_get_try_int(qdict, "nchannels", 2); int nchannels = qdict_get_try_int(qdict, "nchannels", 2);
const char *audiodev = qdict_get_str(qdict, "audiodev"); const char *audiodev = qdict_get_str(qdict, "audiodev");
CaptureState *s; CaptureState *s;
AudioState *as = audio_state_by_name(audiodev); Error *local_err = NULL;
AudioState *as = audio_state_by_name(audiodev, &local_err);
if (!as) { if (!as) {
monitor_printf(mon, "Audiodev '%s' not found\n", audiodev); error_report_err(local_err);
return; return;
} }

View File

@ -32,7 +32,9 @@
#include "qapi/qobject-input-visitor.h" #include "qapi/qobject-input-visitor.h"
#include "qapi/qapi-visit-audio.h" #include "qapi/qapi-visit-audio.h"
#include "qapi/qapi-commands-audio.h" #include "qapi/qapi-commands-audio.h"
#include "qapi/qmp/qdict.h"
#include "qemu/cutils.h" #include "qemu/cutils.h"
#include "qemu/error-report.h"
#include "qemu/log.h" #include "qemu/log.h"
#include "qemu/module.h" #include "qemu/module.h"
#include "qemu/help_option.h" #include "qemu/help_option.h"
@ -61,19 +63,22 @@ const char *audio_prio_list[] = {
"spice", "spice",
CONFIG_AUDIO_DRIVERS CONFIG_AUDIO_DRIVERS
"none", "none",
"wav",
NULL NULL
}; };
static QLIST_HEAD(, audio_driver) audio_drivers; static QLIST_HEAD(, audio_driver) audio_drivers;
static AudiodevListHead audiodevs = QSIMPLEQ_HEAD_INITIALIZER(audiodevs); static AudiodevListHead audiodevs =
QSIMPLEQ_HEAD_INITIALIZER(audiodevs);
static AudiodevListHead default_audiodevs =
QSIMPLEQ_HEAD_INITIALIZER(default_audiodevs);
void audio_driver_register(audio_driver *drv) void audio_driver_register(audio_driver *drv)
{ {
QLIST_INSERT_HEAD(&audio_drivers, drv, next); QLIST_INSERT_HEAD(&audio_drivers, drv, next);
} }
audio_driver *audio_driver_lookup(const char *name) static audio_driver *audio_driver_lookup(const char *name)
{ {
struct audio_driver *d; struct audio_driver *d;
Error *local_err = NULL; Error *local_err = NULL;
@ -99,6 +104,7 @@ audio_driver *audio_driver_lookup(const char *name)
static QTAILQ_HEAD(AudioStateHead, AudioState) audio_states = static QTAILQ_HEAD(AudioStateHead, AudioState) audio_states =
QTAILQ_HEAD_INITIALIZER(audio_states); QTAILQ_HEAD_INITIALIZER(audio_states);
static AudioState *default_audio_state;
const struct mixeng_volume nominal_volume = { const struct mixeng_volume nominal_volume = {
.mute = 0, .mute = 0,
@ -111,8 +117,6 @@ const struct mixeng_volume nominal_volume = {
#endif #endif
}; };
static bool legacy_config = true;
int audio_bug (const char *funcname, int cond) int audio_bug (const char *funcname, int cond)
{ {
if (cond) { if (cond) {
@ -1553,9 +1557,11 @@ size_t audio_generic_read(HWVoiceIn *hw, void *buf, size_t size)
} }
static int audio_driver_init(AudioState *s, struct audio_driver *drv, static int audio_driver_init(AudioState *s, struct audio_driver *drv,
bool msg, Audiodev *dev) Audiodev *dev, Error **errp)
{ {
s->drv_opaque = drv->init(dev); Error *local_err = NULL;
s->drv_opaque = drv->init(dev, &local_err);
if (s->drv_opaque) { if (s->drv_opaque) {
if (!drv->pcm_ops->get_buffer_in) { if (!drv->pcm_ops->get_buffer_in) {
@ -1567,13 +1573,15 @@ static int audio_driver_init(AudioState *s, struct audio_driver *drv,
drv->pcm_ops->put_buffer_out = audio_generic_put_buffer_out; drv->pcm_ops->put_buffer_out = audio_generic_put_buffer_out;
} }
audio_init_nb_voices_out(s, drv); audio_init_nb_voices_out(s, drv, 1);
audio_init_nb_voices_in(s, drv); audio_init_nb_voices_in(s, drv, 0);
s->drv = drv; s->drv = drv;
return 0; return 0;
} else { } else {
if (msg) { if (local_err) {
dolog("Could not init `%s' audio driver\n", drv->name); error_propagate(errp, local_err);
} else {
error_setg(errp, "Could not init `%s' audio driver", drv->name);
} }
return -1; return -1;
} }
@ -1653,6 +1661,7 @@ static void free_audio_state(AudioState *s)
void audio_cleanup(void) void audio_cleanup(void)
{ {
default_audio_state = NULL;
while (!QTAILQ_EMPTY(&audio_states)) { while (!QTAILQ_EMPTY(&audio_states)) {
AudioState *s = QTAILQ_FIRST(&audio_states); AudioState *s = QTAILQ_FIRST(&audio_states);
QTAILQ_REMOVE(&audio_states, s, list); QTAILQ_REMOVE(&audio_states, s, list);
@ -1679,19 +1688,25 @@ static const VMStateDescription vmstate_audio = {
} }
}; };
static void audio_validate_opts(Audiodev *dev, Error **errp); void audio_create_default_audiodevs(void)
static AudiodevListEntry *audiodev_find(
AudiodevListHead *head, const char *drvname)
{ {
AudiodevListEntry *e; for (int i = 0; audio_prio_list[i]; i++) {
QSIMPLEQ_FOREACH(e, head, next) { if (audio_driver_lookup(audio_prio_list[i])) {
if (strcmp(AudiodevDriver_str(e->dev->driver), drvname) == 0) { QDict *dict = qdict_new();
return e; Audiodev *dev = NULL;
} Visitor *v;
}
return NULL; qdict_put_str(dict, "driver", audio_prio_list[i]);
qdict_put_str(dict, "id", "#default");
v = qobject_input_visitor_new_keyval(QOBJECT(dict));
qobject_unref(dict);
visit_type_Audiodev(v, NULL, &dev, &error_fatal);
visit_free(v);
audio_define_default(dev, &error_abort);
}
}
} }
/* /*
@ -1700,62 +1715,16 @@ static AudiodevListEntry *audiodev_find(
* if dev == NULL => legacy implicit initialization, return the already created * if dev == NULL => legacy implicit initialization, return the already created
* state or create a new one * state or create a new one
*/ */
static AudioState *audio_init(Audiodev *dev, const char *name) static AudioState *audio_init(Audiodev *dev, Error **errp)
{ {
static bool atexit_registered; static bool atexit_registered;
size_t i;
int done = 0; int done = 0;
const char *drvname = NULL; const char *drvname;
VMChangeStateEntry *vmse; VMChangeStateEntry *vmse;
AudioState *s; AudioState *s;
struct audio_driver *driver; struct audio_driver *driver;
/* silence gcc warning about uninitialized variable */
AudiodevListHead head = QSIMPLEQ_HEAD_INITIALIZER(head);
if (using_spice) {
/*
* When using spice allow the spice audio driver being picked
* as default.
*
* Temporary hack. Using audio devices without explicit
* audiodev= property is already deprecated. Same goes for
* the -soundhw switch. Once this support gets finally
* removed we can also drop the concept of a default audio
* backend and this can go away.
*/
driver = audio_driver_lookup("spice");
if (driver) {
driver->can_be_default = 1;
}
}
if (dev) {
/* -audiodev option */
legacy_config = false;
drvname = AudiodevDriver_str(dev->driver);
} else if (!QTAILQ_EMPTY(&audio_states)) {
if (!legacy_config) {
dolog("Device %s: audiodev default parameter is deprecated, please "
"specify audiodev=%s\n", name,
QTAILQ_FIRST(&audio_states)->dev->id);
}
return QTAILQ_FIRST(&audio_states);
} else {
/* legacy implicit initialization */
head = audio_handle_legacy_opts();
/*
* In case of legacy initialization, all Audiodevs in the list will have
* the same configuration (except the driver), so it doesn't matter which
* one we chose. We need an Audiodev to set up AudioState before we can
* init a driver. Also note that dev at this point is still in the
* list.
*/
dev = QSIMPLEQ_FIRST(&head)->dev;
audio_validate_opts(dev, &error_abort);
}
s = g_new0(AudioState, 1); s = g_new0(AudioState, 1);
s->dev = dev;
QLIST_INIT (&s->hw_head_out); QLIST_INIT (&s->hw_head_out);
QLIST_INIT (&s->hw_head_in); QLIST_INIT (&s->hw_head_in);
@ -1767,56 +1736,36 @@ static AudioState *audio_init(Audiodev *dev, const char *name)
s->ts = timer_new_ns(QEMU_CLOCK_VIRTUAL, audio_timer, s); s->ts = timer_new_ns(QEMU_CLOCK_VIRTUAL, audio_timer, s);
s->nb_hw_voices_out = audio_get_pdo_out(dev)->voices; if (dev) {
s->nb_hw_voices_in = audio_get_pdo_in(dev)->voices; /* -audiodev option */
s->dev = dev;
if (s->nb_hw_voices_out < 1) { drvname = AudiodevDriver_str(dev->driver);
dolog ("Bogus number of playback voices %d, setting to 1\n",
s->nb_hw_voices_out);
s->nb_hw_voices_out = 1;
}
if (s->nb_hw_voices_in < 0) {
dolog ("Bogus number of capture voices %d, setting to 0\n",
s->nb_hw_voices_in);
s->nb_hw_voices_in = 0;
}
if (drvname) {
driver = audio_driver_lookup(drvname); driver = audio_driver_lookup(drvname);
if (driver) { if (driver) {
done = !audio_driver_init(s, driver, true, dev); done = !audio_driver_init(s, driver, dev, errp);
} else { } else {
dolog ("Unknown audio driver `%s'\n", drvname); error_setg(errp, "Unknown audio driver `%s'\n", drvname);
} }
if (!done) { if (!done) {
free_audio_state(s); goto out;
return NULL;
} }
} else { } else {
for (i = 0; audio_prio_list[i]; i++) { assert(!default_audio_state);
AudiodevListEntry *e = audiodev_find(&head, audio_prio_list[i]); for (;;) {
driver = audio_driver_lookup(audio_prio_list[i]); AudiodevListEntry *e = QSIMPLEQ_FIRST(&default_audiodevs);
if (!e) {
if (e && driver) { error_setg(errp, "no default audio driver available");
goto out;
}
s->dev = dev = e->dev; s->dev = dev = e->dev;
audio_validate_opts(dev, &error_abort); drvname = AudiodevDriver_str(dev->driver);
done = !audio_driver_init(s, driver, false, dev); driver = audio_driver_lookup(drvname);
if (done) { if (!audio_driver_init(s, driver, dev, NULL)) {
e->dev = NULL;
break; break;
} }
QSIMPLEQ_REMOVE_HEAD(&default_audiodevs, next);
} }
} }
}
audio_free_audiodev_list(&head);
if (!done) {
driver = audio_driver_lookup("none");
done = !audio_driver_init(s, driver, false, dev);
assert(done);
dolog("warning: Using timer based audio emulation\n");
}
if (dev->timer_period <= 0) { if (dev->timer_period <= 0) {
s->period_ticks = 1; s->period_ticks = 1;
@ -1834,27 +1783,41 @@ static AudioState *audio_init(Audiodev *dev, const char *name)
QLIST_INIT (&s->card_head); QLIST_INIT (&s->card_head);
vmstate_register (NULL, 0, &vmstate_audio, s); vmstate_register (NULL, 0, &vmstate_audio, s);
return s; return s;
out:
free_audio_state(s);
return NULL;
} }
void audio_free_audiodev_list(AudiodevListHead *head) AudioState *audio_get_default_audio_state(Error **errp)
{ {
AudiodevListEntry *e; if (!default_audio_state) {
while ((e = QSIMPLEQ_FIRST(head))) { default_audio_state = audio_init(NULL, errp);
QSIMPLEQ_REMOVE_HEAD(head, next); if (!default_audio_state) {
qapi_free_Audiodev(e->dev); if (!QSIMPLEQ_EMPTY(&audiodevs)) {
g_free(e); error_append_hint(errp, "Perhaps you wanted to use -audio or set audiodev=%s?\n",
QSIMPLEQ_FIRST(&audiodevs)->dev->id);
}
} }
} }
void AUD_register_card (const char *name, QEMUSoundCard *card) return default_audio_state;
}
bool AUD_register_card (const char *name, QEMUSoundCard *card, Error **errp)
{ {
if (!card->state) { if (!card->state) {
card->state = audio_init(NULL, name); card->state = audio_get_default_audio_state(errp);
if (!card->state) {
return false;
}
} }
card->name = g_strdup (name); card->name = g_strdup (name);
memset (&card->entries, 0, sizeof (card->entries)); memset (&card->entries, 0, sizeof (card->entries));
QLIST_INSERT_HEAD(&card->state->card_head, card, entries); QLIST_INSERT_HEAD(&card->state->card_head, card, entries);
return true;
} }
void AUD_remove_card (QEMUSoundCard *card) void AUD_remove_card (QEMUSoundCard *card)
@ -1876,10 +1839,8 @@ CaptureVoiceOut *AUD_add_capture(
struct capture_callback *cb; struct capture_callback *cb;
if (!s) { if (!s) {
if (!legacy_config) { error_report("Capturing without setting an audiodev is not supported");
dolog("Capturing without setting an audiodev is deprecated\n"); abort();
}
s = audio_init(NULL, NULL);
} }
if (!audio_get_pdo_out(s->dev)->mixing_engine) { if (!audio_get_pdo_out(s->dev)->mixing_engine) {
@ -2183,19 +2144,26 @@ void audio_define(Audiodev *dev)
QSIMPLEQ_INSERT_TAIL(&audiodevs, e, next); QSIMPLEQ_INSERT_TAIL(&audiodevs, e, next);
} }
bool audio_init_audiodevs(void) void audio_define_default(Audiodev *dev, Error **errp)
{
AudiodevListEntry *e;
audio_validate_opts(dev, errp);
e = g_new0(AudiodevListEntry, 1);
e->dev = dev;
QSIMPLEQ_INSERT_TAIL(&default_audiodevs, e, next);
}
void audio_init_audiodevs(void)
{ {
AudiodevListEntry *e; AudiodevListEntry *e;
QSIMPLEQ_FOREACH(e, &audiodevs, next) { QSIMPLEQ_FOREACH(e, &audiodevs, next) {
if (!audio_init(e->dev, NULL)) { audio_init(e->dev, &error_fatal);
return false;
} }
} }
return true;
}
audsettings audiodev_to_audsettings(AudiodevPerDirectionOptions *pdo) audsettings audiodev_to_audsettings(AudiodevPerDirectionOptions *pdo)
{ {
return (audsettings) { return (audsettings) {
@ -2255,7 +2223,7 @@ int audio_buffer_bytes(AudiodevPerDirectionOptions *pdo,
audioformat_bytes_per_sample(as->fmt); audioformat_bytes_per_sample(as->fmt);
} }
AudioState *audio_state_by_name(const char *name) AudioState *audio_state_by_name(const char *name, Error **errp)
{ {
AudioState *s; AudioState *s;
QTAILQ_FOREACH(s, &audio_states, list) { QTAILQ_FOREACH(s, &audio_states, list) {
@ -2264,6 +2232,7 @@ AudioState *audio_state_by_name(const char *name)
return s; return s;
} }
} }
error_setg(errp, "audiodev '%s' not found", name);
return NULL; return NULL;
} }

View File

@ -94,7 +94,7 @@ typedef struct QEMUAudioTimeStamp {
void AUD_vlog (const char *cap, const char *fmt, va_list ap) G_GNUC_PRINTF(2, 0); void AUD_vlog (const char *cap, const char *fmt, va_list ap) G_GNUC_PRINTF(2, 0);
void AUD_log (const char *cap, const char *fmt, ...) G_GNUC_PRINTF(2, 3); void AUD_log (const char *cap, const char *fmt, ...) G_GNUC_PRINTF(2, 3);
void AUD_register_card (const char *name, QEMUSoundCard *card); bool AUD_register_card (const char *name, QEMUSoundCard *card, Error **errp);
void AUD_remove_card (QEMUSoundCard *card); void AUD_remove_card (QEMUSoundCard *card);
CaptureVoiceOut *AUD_add_capture( CaptureVoiceOut *AUD_add_capture(
AudioState *s, AudioState *s,
@ -169,12 +169,14 @@ void audio_sample_from_uint64(void *samples, int pos,
uint64_t left, uint64_t right); uint64_t left, uint64_t right);
void audio_define(Audiodev *audio); void audio_define(Audiodev *audio);
void audio_define_default(Audiodev *dev, Error **errp);
void audio_parse_option(const char *opt); void audio_parse_option(const char *opt);
bool audio_init_audiodevs(void); void audio_create_default_audiodevs(void);
void audio_init_audiodevs(void);
void audio_help(void); void audio_help(void);
void audio_legacy_help(void);
AudioState *audio_state_by_name(const char *name); AudioState *audio_state_by_name(const char *name, Error **errp);
AudioState *audio_get_default_audio_state(Error **errp);
const char *audio_get_id(QEMUSoundCard *card); const char *audio_get_id(QEMUSoundCard *card);
#define DEFINE_AUDIO_PROPERTIES(_s, _f) \ #define DEFINE_AUDIO_PROPERTIES(_s, _f) \

View File

@ -140,13 +140,12 @@ typedef struct audio_driver audio_driver;
struct audio_driver { struct audio_driver {
const char *name; const char *name;
const char *descr; const char *descr;
void *(*init) (Audiodev *); void *(*init) (Audiodev *, Error **);
void (*fini) (void *); void (*fini) (void *);
#ifdef CONFIG_GIO #ifdef CONFIG_GIO
void (*set_dbus_server) (AudioState *s, GDBusObjectManagerServer *manager, bool p2p); void (*set_dbus_server) (AudioState *s, GDBusObjectManagerServer *manager, bool p2p);
#endif #endif
struct audio_pcm_ops *pcm_ops; struct audio_pcm_ops *pcm_ops;
int can_be_default;
int max_voices_out; int max_voices_out;
int max_voices_in; int max_voices_in;
size_t voice_size_out; size_t voice_size_out;
@ -243,7 +242,6 @@ extern const struct mixeng_volume nominal_volume;
extern const char *audio_prio_list[]; extern const char *audio_prio_list[];
void audio_driver_register(audio_driver *drv); void audio_driver_register(audio_driver *drv);
audio_driver *audio_driver_lookup(const char *name);
void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as); void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as);
void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len); void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len);
@ -297,9 +295,6 @@ typedef struct AudiodevListEntry {
} AudiodevListEntry; } AudiodevListEntry;
typedef QSIMPLEQ_HEAD(, AudiodevListEntry) AudiodevListHead; typedef QSIMPLEQ_HEAD(, AudiodevListEntry) AudiodevListHead;
AudiodevListHead audio_handle_legacy_opts(void);
void audio_free_audiodev_list(AudiodevListHead *head);
void audio_create_pdos(Audiodev *dev); void audio_create_pdos(Audiodev *dev);
AudiodevPerDirectionOptions *audio_get_pdo_in(Audiodev *dev); AudiodevPerDirectionOptions *audio_get_pdo_in(Audiodev *dev);

View File

@ -1,591 +0,0 @@
/*
* QEMU Audio subsystem: legacy configuration handling
*
* Copyright (c) 2015-2019 Zoltán Kővágó <DirtY.iCE.hu@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "qemu/osdep.h"
#include "audio.h"
#include "audio_int.h"
#include "qemu/cutils.h"
#include "qemu/timer.h"
#include "qapi/error.h"
#include "qapi/qapi-visit-audio.h"
#include "qapi/visitor-impl.h"
#define AUDIO_CAP "audio-legacy"
#include "audio_int.h"
static uint32_t toui32(const char *str)
{
uint64_t ret;
if (parse_uint_full(str, 10, &ret) || ret > UINT32_MAX) {
dolog("Invalid integer value `%s'\n", str);
exit(1);
}
return ret;
}
/* helper functions to convert env variables */
static void get_bool(const char *env, bool *dst, bool *has_dst)
{
const char *val = getenv(env);
if (val) {
*dst = toui32(val) != 0;
*has_dst = true;
}
}
static void get_int(const char *env, uint32_t *dst, bool *has_dst)
{
const char *val = getenv(env);
if (val) {
*dst = toui32(val);
*has_dst = true;
}
}
static void get_str(const char *env, char **dst)
{
const char *val = getenv(env);
if (val) {
g_free(*dst);
*dst = g_strdup(val);
}
}
static void get_fmt(const char *env, AudioFormat *dst, bool *has_dst)
{
const char *val = getenv(env);
if (val) {
size_t i;
for (i = 0; AudioFormat_lookup.size; ++i) {
if (strcasecmp(val, AudioFormat_lookup.array[i]) == 0) {
*dst = i;
*has_dst = true;
return;
}
}
dolog("Invalid audio format `%s'\n", val);
exit(1);
}
}
#if defined(CONFIG_AUDIO_ALSA) || defined(CONFIG_AUDIO_DSOUND)
static void get_millis_to_usecs(const char *env, uint32_t *dst, bool *has_dst)
{
const char *val = getenv(env);
if (val) {
*dst = toui32(val) * 1000;
*has_dst = true;
}
}
#endif
#if defined(CONFIG_AUDIO_ALSA) || defined(CONFIG_AUDIO_COREAUDIO) || \
defined(CONFIG_AUDIO_PA) || defined(CONFIG_AUDIO_SDL) || \
defined(CONFIG_AUDIO_DSOUND) || defined(CONFIG_AUDIO_OSS)
static uint32_t frames_to_usecs(uint32_t frames,
AudiodevPerDirectionOptions *pdo)
{
uint32_t freq = pdo->has_frequency ? pdo->frequency : 44100;
return (frames * 1000000 + freq / 2) / freq;
}
#endif
#ifdef CONFIG_AUDIO_COREAUDIO
static void get_frames_to_usecs(const char *env, uint32_t *dst, bool *has_dst,
AudiodevPerDirectionOptions *pdo)
{
const char *val = getenv(env);
if (val) {
*dst = frames_to_usecs(toui32(val), pdo);
*has_dst = true;
}
}
#endif
#if defined(CONFIG_AUDIO_PA) || defined(CONFIG_AUDIO_SDL) || \
defined(CONFIG_AUDIO_DSOUND) || defined(CONFIG_AUDIO_OSS)
static uint32_t samples_to_usecs(uint32_t samples,
AudiodevPerDirectionOptions *pdo)
{
uint32_t channels = pdo->has_channels ? pdo->channels : 2;
return frames_to_usecs(samples / channels, pdo);
}
#endif
#if defined(CONFIG_AUDIO_PA) || defined(CONFIG_AUDIO_SDL)
static void get_samples_to_usecs(const char *env, uint32_t *dst, bool *has_dst,
AudiodevPerDirectionOptions *pdo)
{
const char *val = getenv(env);
if (val) {
*dst = samples_to_usecs(toui32(val), pdo);
*has_dst = true;
}
}
#endif
#if defined(CONFIG_AUDIO_DSOUND) || defined(CONFIG_AUDIO_OSS)
static uint32_t bytes_to_usecs(uint32_t bytes, AudiodevPerDirectionOptions *pdo)
{
AudioFormat fmt = pdo->has_format ? pdo->format : AUDIO_FORMAT_S16;
uint32_t bytes_per_sample = audioformat_bytes_per_sample(fmt);
return samples_to_usecs(bytes / bytes_per_sample, pdo);
}
static void get_bytes_to_usecs(const char *env, uint32_t *dst, bool *has_dst,
AudiodevPerDirectionOptions *pdo)
{
const char *val = getenv(env);
if (val) {
*dst = bytes_to_usecs(toui32(val), pdo);
*has_dst = true;
}
}
#endif
/* backend specific functions */
#ifdef CONFIG_AUDIO_ALSA
/* ALSA */
static void handle_alsa_per_direction(
AudiodevAlsaPerDirectionOptions *apdo, const char *prefix)
{
char buf[64];
size_t len = strlen(prefix);
bool size_in_usecs = false;
bool dummy;
memcpy(buf, prefix, len);
strcpy(buf + len, "TRY_POLL");
get_bool(buf, &apdo->try_poll, &apdo->has_try_poll);
strcpy(buf + len, "DEV");
get_str(buf, &apdo->dev);
strcpy(buf + len, "SIZE_IN_USEC");
get_bool(buf, &size_in_usecs, &dummy);
strcpy(buf + len, "PERIOD_SIZE");
get_int(buf, &apdo->period_length, &apdo->has_period_length);
if (apdo->has_period_length && !size_in_usecs) {
apdo->period_length = frames_to_usecs(
apdo->period_length,
qapi_AudiodevAlsaPerDirectionOptions_base(apdo));
}
strcpy(buf + len, "BUFFER_SIZE");
get_int(buf, &apdo->buffer_length, &apdo->has_buffer_length);
if (apdo->has_buffer_length && !size_in_usecs) {
apdo->buffer_length = frames_to_usecs(
apdo->buffer_length,
qapi_AudiodevAlsaPerDirectionOptions_base(apdo));
}
}
static void handle_alsa(Audiodev *dev)
{
AudiodevAlsaOptions *aopt = &dev->u.alsa;
handle_alsa_per_direction(aopt->in, "QEMU_ALSA_ADC_");
handle_alsa_per_direction(aopt->out, "QEMU_ALSA_DAC_");
get_millis_to_usecs("QEMU_ALSA_THRESHOLD",
&aopt->threshold, &aopt->has_threshold);
}
#endif
#ifdef CONFIG_AUDIO_COREAUDIO
/* coreaudio */
static void handle_coreaudio(Audiodev *dev)
{
get_frames_to_usecs(
"QEMU_COREAUDIO_BUFFER_SIZE",
&dev->u.coreaudio.out->buffer_length,
&dev->u.coreaudio.out->has_buffer_length,
qapi_AudiodevCoreaudioPerDirectionOptions_base(dev->u.coreaudio.out));
get_int("QEMU_COREAUDIO_BUFFER_COUNT",
&dev->u.coreaudio.out->buffer_count,
&dev->u.coreaudio.out->has_buffer_count);
}
#endif
#ifdef CONFIG_AUDIO_DSOUND
/* dsound */
static void handle_dsound(Audiodev *dev)
{
get_millis_to_usecs("QEMU_DSOUND_LATENCY_MILLIS",
&dev->u.dsound.latency, &dev->u.dsound.has_latency);
get_bytes_to_usecs("QEMU_DSOUND_BUFSIZE_OUT",
&dev->u.dsound.out->buffer_length,
&dev->u.dsound.out->has_buffer_length,
dev->u.dsound.out);
get_bytes_to_usecs("QEMU_DSOUND_BUFSIZE_IN",
&dev->u.dsound.in->buffer_length,
&dev->u.dsound.in->has_buffer_length,
dev->u.dsound.in);
}
#endif
#ifdef CONFIG_AUDIO_OSS
/* OSS */
static void handle_oss_per_direction(
AudiodevOssPerDirectionOptions *opdo, const char *try_poll_env,
const char *dev_env)
{
get_bool(try_poll_env, &opdo->try_poll, &opdo->has_try_poll);
get_str(dev_env, &opdo->dev);
get_bytes_to_usecs("QEMU_OSS_FRAGSIZE",
&opdo->buffer_length, &opdo->has_buffer_length,
qapi_AudiodevOssPerDirectionOptions_base(opdo));
get_int("QEMU_OSS_NFRAGS", &opdo->buffer_count,
&opdo->has_buffer_count);
}
static void handle_oss(Audiodev *dev)
{
AudiodevOssOptions *oopt = &dev->u.oss;
handle_oss_per_direction(oopt->in, "QEMU_AUDIO_ADC_TRY_POLL",
"QEMU_OSS_ADC_DEV");
handle_oss_per_direction(oopt->out, "QEMU_AUDIO_DAC_TRY_POLL",
"QEMU_OSS_DAC_DEV");
get_bool("QEMU_OSS_MMAP", &oopt->try_mmap, &oopt->has_try_mmap);
get_bool("QEMU_OSS_EXCLUSIVE", &oopt->exclusive, &oopt->has_exclusive);
get_int("QEMU_OSS_POLICY", &oopt->dsp_policy, &oopt->has_dsp_policy);
}
#endif
#ifdef CONFIG_AUDIO_PA
/* pulseaudio */
static void handle_pa_per_direction(
AudiodevPaPerDirectionOptions *ppdo, const char *env)
{
get_str(env, &ppdo->name);
}
static void handle_pa(Audiodev *dev)
{
handle_pa_per_direction(dev->u.pa.in, "QEMU_PA_SOURCE");
handle_pa_per_direction(dev->u.pa.out, "QEMU_PA_SINK");
get_samples_to_usecs(
"QEMU_PA_SAMPLES", &dev->u.pa.in->buffer_length,
&dev->u.pa.in->has_buffer_length,
qapi_AudiodevPaPerDirectionOptions_base(dev->u.pa.in));
get_samples_to_usecs(
"QEMU_PA_SAMPLES", &dev->u.pa.out->buffer_length,
&dev->u.pa.out->has_buffer_length,
qapi_AudiodevPaPerDirectionOptions_base(dev->u.pa.out));
get_str("QEMU_PA_SERVER", &dev->u.pa.server);
}
#endif
#ifdef CONFIG_AUDIO_SDL
/* SDL */
static void handle_sdl(Audiodev *dev)
{
/* SDL is output only */
get_samples_to_usecs("QEMU_SDL_SAMPLES", &dev->u.sdl.out->buffer_length,
&dev->u.sdl.out->has_buffer_length,
qapi_AudiodevSdlPerDirectionOptions_base(dev->u.sdl.out));
}
#endif
/* wav */
static void handle_wav(Audiodev *dev)
{
get_int("QEMU_WAV_FREQUENCY",
&dev->u.wav.out->frequency, &dev->u.wav.out->has_frequency);
get_fmt("QEMU_WAV_FORMAT", &dev->u.wav.out->format,
&dev->u.wav.out->has_format);
get_int("QEMU_WAV_DAC_FIXED_CHANNELS",
&dev->u.wav.out->channels, &dev->u.wav.out->has_channels);
get_str("QEMU_WAV_PATH", &dev->u.wav.path);
}
/* general */
static void handle_per_direction(
AudiodevPerDirectionOptions *pdo, const char *prefix)
{
char buf[64];
size_t len = strlen(prefix);
memcpy(buf, prefix, len);
strcpy(buf + len, "FIXED_SETTINGS");
get_bool(buf, &pdo->fixed_settings, &pdo->has_fixed_settings);
strcpy(buf + len, "FIXED_FREQ");
get_int(buf, &pdo->frequency, &pdo->has_frequency);
strcpy(buf + len, "FIXED_FMT");
get_fmt(buf, &pdo->format, &pdo->has_format);
strcpy(buf + len, "FIXED_CHANNELS");
get_int(buf, &pdo->channels, &pdo->has_channels);
strcpy(buf + len, "VOICES");
get_int(buf, &pdo->voices, &pdo->has_voices);
}
static AudiodevListEntry *legacy_opt(const char *drvname)
{
AudiodevListEntry *e = g_new0(AudiodevListEntry, 1);
e->dev = g_new0(Audiodev, 1);
e->dev->id = g_strdup(drvname);
e->dev->driver = qapi_enum_parse(
&AudiodevDriver_lookup, drvname, -1, &error_abort);
audio_create_pdos(e->dev);
handle_per_direction(audio_get_pdo_in(e->dev), "QEMU_AUDIO_ADC_");
handle_per_direction(audio_get_pdo_out(e->dev), "QEMU_AUDIO_DAC_");
/* Original description: Timer period in HZ (0 - use lowest possible) */
get_int("QEMU_AUDIO_TIMER_PERIOD",
&e->dev->timer_period, &e->dev->has_timer_period);
if (e->dev->has_timer_period && e->dev->timer_period) {
e->dev->timer_period = NANOSECONDS_PER_SECOND / 1000 /
e->dev->timer_period;
}
switch (e->dev->driver) {
#ifdef CONFIG_AUDIO_ALSA
case AUDIODEV_DRIVER_ALSA:
handle_alsa(e->dev);
break;
#endif
#ifdef CONFIG_AUDIO_COREAUDIO
case AUDIODEV_DRIVER_COREAUDIO:
handle_coreaudio(e->dev);
break;
#endif
#ifdef CONFIG_AUDIO_DSOUND
case AUDIODEV_DRIVER_DSOUND:
handle_dsound(e->dev);
break;
#endif
#ifdef CONFIG_AUDIO_OSS
case AUDIODEV_DRIVER_OSS:
handle_oss(e->dev);
break;
#endif
#ifdef CONFIG_AUDIO_PA
case AUDIODEV_DRIVER_PA:
handle_pa(e->dev);
break;
#endif
#ifdef CONFIG_AUDIO_SDL
case AUDIODEV_DRIVER_SDL:
handle_sdl(e->dev);
break;
#endif
case AUDIODEV_DRIVER_WAV:
handle_wav(e->dev);
break;
default:
break;
}
return e;
}
AudiodevListHead audio_handle_legacy_opts(void)
{
const char *drvname = getenv("QEMU_AUDIO_DRV");
AudiodevListHead head = QSIMPLEQ_HEAD_INITIALIZER(head);
if (drvname) {
AudiodevListEntry *e;
audio_driver *driver = audio_driver_lookup(drvname);
if (!driver) {
dolog("Unknown audio driver `%s'\n", drvname);
exit(1);
}
e = legacy_opt(drvname);
QSIMPLEQ_INSERT_TAIL(&head, e, next);
} else {
for (int i = 0; audio_prio_list[i]; i++) {
audio_driver *driver = audio_driver_lookup(audio_prio_list[i]);
if (driver && driver->can_be_default) {
AudiodevListEntry *e = legacy_opt(driver->name);
QSIMPLEQ_INSERT_TAIL(&head, e, next);
}
}
if (QSIMPLEQ_EMPTY(&head)) {
dolog("Internal error: no default audio driver available\n");
exit(1);
}
}
return head;
}
/* visitor to print -audiodev option */
typedef struct {
Visitor visitor;
bool comma;
GList *path;
} LegacyPrintVisitor;
static bool lv_start_struct(Visitor *v, const char *name, void **obj,
size_t size, Error **errp)
{
LegacyPrintVisitor *lv = (LegacyPrintVisitor *) v;
lv->path = g_list_append(lv->path, g_strdup(name));
return true;
}
static void lv_end_struct(Visitor *v, void **obj)
{
LegacyPrintVisitor *lv = (LegacyPrintVisitor *) v;
lv->path = g_list_delete_link(lv->path, g_list_last(lv->path));
}
static void lv_print_key(Visitor *v, const char *name)
{
GList *e;
LegacyPrintVisitor *lv = (LegacyPrintVisitor *) v;
if (lv->comma) {
putchar(',');
} else {
lv->comma = true;
}
for (e = lv->path; e; e = e->next) {
if (e->data) {
printf("%s.", (const char *) e->data);
}
}
printf("%s=", name);
}
static bool lv_type_int64(Visitor *v, const char *name, int64_t *obj,
Error **errp)
{
lv_print_key(v, name);
printf("%" PRIi64, *obj);
return true;
}
static bool lv_type_uint64(Visitor *v, const char *name, uint64_t *obj,
Error **errp)
{
lv_print_key(v, name);
printf("%" PRIu64, *obj);
return true;
}
static bool lv_type_bool(Visitor *v, const char *name, bool *obj, Error **errp)
{
lv_print_key(v, name);
printf("%s", *obj ? "on" : "off");
return true;
}
static bool lv_type_str(Visitor *v, const char *name, char **obj, Error **errp)
{
const char *str = *obj;
lv_print_key(v, name);
while (*str) {
if (*str == ',') {
putchar(',');
}
putchar(*str++);
}
return true;
}
static void lv_complete(Visitor *v, void *opaque)
{
LegacyPrintVisitor *lv = (LegacyPrintVisitor *) v;
assert(lv->path == NULL);
}
static void lv_free(Visitor *v)
{
LegacyPrintVisitor *lv = (LegacyPrintVisitor *) v;
g_list_free_full(lv->path, g_free);
g_free(lv);
}
static Visitor *legacy_visitor_new(void)
{
LegacyPrintVisitor *lv = g_new0(LegacyPrintVisitor, 1);
lv->visitor.start_struct = lv_start_struct;
lv->visitor.end_struct = lv_end_struct;
/* lists not supported */
lv->visitor.type_int64 = lv_type_int64;
lv->visitor.type_uint64 = lv_type_uint64;
lv->visitor.type_bool = lv_type_bool;
lv->visitor.type_str = lv_type_str;
lv->visitor.type = VISITOR_OUTPUT;
lv->visitor.complete = lv_complete;
lv->visitor.free = lv_free;
return &lv->visitor;
}
void audio_legacy_help(void)
{
AudiodevListHead head;
AudiodevListEntry *e;
printf("Environment variable based configuration deprecated.\n");
printf("Please use the new -audiodev option.\n");
head = audio_handle_legacy_opts();
printf("\nEquivalent -audiodev to your current environment variables:\n");
if (!getenv("QEMU_AUDIO_DRV")) {
printf("(Since you didn't specify QEMU_AUDIO_DRV, I'll list all "
"possibilities)\n");
}
QSIMPLEQ_FOREACH(e, &head, next) {
Visitor *v;
Audiodev *dev = e->dev;
printf("-audiodev ");
v = legacy_visitor_new();
visit_type_Audiodev(v, NULL, &dev, &error_abort);
visit_free(v);
printf("\n");
}
audio_free_audiodev_list(&head);
}

View File

@ -37,11 +37,12 @@
#endif #endif
static void glue(audio_init_nb_voices_, TYPE)(AudioState *s, static void glue(audio_init_nb_voices_, TYPE)(AudioState *s,
struct audio_driver *drv) struct audio_driver *drv, int min_voices)
{ {
int max_voices = glue (drv->max_voices_, TYPE); int max_voices = glue (drv->max_voices_, TYPE);
size_t voice_size = glue(drv->voice_size_, TYPE); size_t voice_size = glue(drv->voice_size_, TYPE);
glue (s->nb_hw_voices_, TYPE) = glue(audio_get_pdo_, TYPE)(s->dev)->voices;
if (glue (s->nb_hw_voices_, TYPE) > max_voices) { if (glue (s->nb_hw_voices_, TYPE) > max_voices) {
if (!max_voices) { if (!max_voices) {
#ifdef DAC #ifdef DAC
@ -56,6 +57,12 @@ static void glue(audio_init_nb_voices_, TYPE)(AudioState *s,
glue (s->nb_hw_voices_, TYPE) = max_voices; glue (s->nb_hw_voices_, TYPE) = max_voices;
} }
if (glue (s->nb_hw_voices_, TYPE) < min_voices) {
dolog ("Bogus number of " NAME " voices %d, setting to %d\n",
glue (s->nb_hw_voices_, TYPE),
min_voices);
}
if (audio_bug(__func__, !voice_size && max_voices)) { if (audio_bug(__func__, !voice_size && max_voices)) {
dolog ("drv=`%s' voice_size=0 max_voices=%d\n", dolog ("drv=`%s' voice_size=0 max_voices=%d\n",
drv->name, max_voices); drv->name, max_voices);

View File

@ -644,7 +644,7 @@ static void coreaudio_enable_out(HWVoiceOut *hw, bool enable)
update_device_playback_state(core); update_device_playback_state(core);
} }
static void *coreaudio_audio_init(Audiodev *dev) static void *coreaudio_audio_init(Audiodev *dev, Error **errp)
{ {
return dev; return dev;
} }
@ -673,7 +673,6 @@ static struct audio_driver coreaudio_audio_driver = {
.init = coreaudio_audio_init, .init = coreaudio_audio_init,
.fini = coreaudio_audio_fini, .fini = coreaudio_audio_fini,
.pcm_ops = &coreaudio_pcm_ops, .pcm_ops = &coreaudio_pcm_ops,
.can_be_default = 1,
.max_voices_out = 1, .max_voices_out = 1,
.max_voices_in = 0, .max_voices_in = 0,
.voice_size_out = sizeof (coreaudioVoiceOut), .voice_size_out = sizeof (coreaudioVoiceOut),

View File

@ -395,7 +395,7 @@ dbus_enable_in(HWVoiceIn *hw, bool enable)
} }
static void * static void *
dbus_audio_init(Audiodev *dev) dbus_audio_init(Audiodev *dev, Error **errp)
{ {
DBusAudio *da = g_new0(DBusAudio, 1); DBusAudio *da = g_new0(DBusAudio, 1);
@ -676,7 +676,6 @@ static struct audio_driver dbus_audio_driver = {
.fini = dbus_audio_fini, .fini = dbus_audio_fini,
.set_dbus_server = dbus_audio_set_server, .set_dbus_server = dbus_audio_set_server,
.pcm_ops = &dbus_pcm_ops, .pcm_ops = &dbus_pcm_ops,
.can_be_default = 1,
.max_voices_out = INT_MAX, .max_voices_out = INT_MAX,
.max_voices_in = INT_MAX, .max_voices_in = INT_MAX,
.voice_size_out = sizeof(DBusVoiceOut), .voice_size_out = sizeof(DBusVoiceOut),

View File

@ -619,7 +619,7 @@ static void dsound_audio_fini (void *opaque)
g_free(s); g_free(s);
} }
static void *dsound_audio_init(Audiodev *dev) static void *dsound_audio_init(Audiodev *dev, Error **errp)
{ {
int err; int err;
HRESULT hr; HRESULT hr;
@ -721,7 +721,6 @@ static struct audio_driver dsound_audio_driver = {
.init = dsound_audio_init, .init = dsound_audio_init,
.fini = dsound_audio_fini, .fini = dsound_audio_fini,
.pcm_ops = &dsound_pcm_ops, .pcm_ops = &dsound_pcm_ops,
.can_be_default = 1,
.max_voices_out = INT_MAX, .max_voices_out = INT_MAX,
.max_voices_in = 1, .max_voices_in = 1,
.voice_size_out = sizeof (DSoundVoiceOut), .voice_size_out = sizeof (DSoundVoiceOut),

View File

@ -645,7 +645,7 @@ static int qjack_thread_creator(jack_native_thread_t *thread,
} }
#endif #endif
static void *qjack_init(Audiodev *dev) static void *qjack_init(Audiodev *dev, Error **errp)
{ {
assert(dev->driver == AUDIODEV_DRIVER_JACK); assert(dev->driver == AUDIODEV_DRIVER_JACK);
return dev; return dev;
@ -676,7 +676,6 @@ static struct audio_driver jack_driver = {
.init = qjack_init, .init = qjack_init,
.fini = qjack_fini, .fini = qjack_fini,
.pcm_ops = &jack_pcm_ops, .pcm_ops = &jack_pcm_ops,
.can_be_default = 1,
.max_voices_out = INT_MAX, .max_voices_out = INT_MAX,
.max_voices_in = INT_MAX, .max_voices_in = INT_MAX,
.voice_size_out = sizeof(QJackOut), .voice_size_out = sizeof(QJackOut),

View File

@ -1,7 +1,6 @@
system_ss.add([spice_headers, files('audio.c')]) system_ss.add([spice_headers, files('audio.c')])
system_ss.add(files( system_ss.add(files(
'audio-hmp-cmds.c', 'audio-hmp-cmds.c',
'audio_legacy.c',
'mixeng.c', 'mixeng.c',
'noaudio.c', 'noaudio.c',
'wavaudio.c', 'wavaudio.c',

View File

@ -104,7 +104,7 @@ static void no_enable_in(HWVoiceIn *hw, bool enable)
} }
} }
static void *no_audio_init(Audiodev *dev) static void *no_audio_init(Audiodev *dev, Error **errp)
{ {
return &no_audio_init; return &no_audio_init;
} }
@ -135,7 +135,6 @@ static struct audio_driver no_audio_driver = {
.init = no_audio_init, .init = no_audio_init,
.fini = no_audio_fini, .fini = no_audio_fini,
.pcm_ops = &no_pcm_ops, .pcm_ops = &no_pcm_ops,
.can_be_default = 1,
.max_voices_out = INT_MAX, .max_voices_out = INT_MAX,
.max_voices_in = INT_MAX, .max_voices_in = INT_MAX,
.voice_size_out = sizeof (NoVoiceOut), .voice_size_out = sizeof (NoVoiceOut),

View File

@ -28,6 +28,7 @@
#include "qemu/main-loop.h" #include "qemu/main-loop.h"
#include "qemu/module.h" #include "qemu/module.h"
#include "qemu/host-utils.h" #include "qemu/host-utils.h"
#include "qapi/error.h"
#include "audio.h" #include "audio.h"
#include "trace.h" #include "trace.h"
@ -548,7 +549,6 @@ static int oss_init_out(HWVoiceOut *hw, struct audsettings *as,
hw->size_emul); hw->size_emul);
hw->buf_emul = NULL; hw->buf_emul = NULL;
} else { } else {
int err;
int trig = 0; int trig = 0;
if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n"); oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
@ -736,7 +736,7 @@ static void oss_init_per_direction(AudiodevOssPerDirectionOptions *opdo)
} }
} }
static void *oss_audio_init(Audiodev *dev) static void *oss_audio_init(Audiodev *dev, Error **errp)
{ {
AudiodevOssOptions *oopts; AudiodevOssOptions *oopts;
assert(dev->driver == AUDIODEV_DRIVER_OSS); assert(dev->driver == AUDIODEV_DRIVER_OSS);
@ -745,8 +745,12 @@ static void *oss_audio_init(Audiodev *dev)
oss_init_per_direction(oopts->in); oss_init_per_direction(oopts->in);
oss_init_per_direction(oopts->out); oss_init_per_direction(oopts->out);
if (access(oopts->in->dev ?: "/dev/dsp", R_OK | W_OK) < 0 || if (access(oopts->in->dev ?: "/dev/dsp", R_OK | W_OK) < 0) {
access(oopts->out->dev ?: "/dev/dsp", R_OK | W_OK) < 0) { error_setg_errno(errp, errno, "%s not accessible", oopts->in->dev ?: "/dev/dsp");
return NULL;
}
if (access(oopts->out->dev ?: "/dev/dsp", R_OK | W_OK) < 0) {
error_setg_errno(errp, errno, "%s not accessible", oopts->out->dev ?: "/dev/dsp");
return NULL; return NULL;
} }
return dev; return dev;
@ -779,7 +783,6 @@ static struct audio_driver oss_audio_driver = {
.init = oss_audio_init, .init = oss_audio_init,
.fini = oss_audio_fini, .fini = oss_audio_fini,
.pcm_ops = &oss_pcm_ops, .pcm_ops = &oss_pcm_ops,
.can_be_default = 1,
.max_voices_out = INT_MAX, .max_voices_out = INT_MAX,
.max_voices_in = INT_MAX, .max_voices_in = INT_MAX,
.voice_size_out = sizeof (OSSVoiceOut), .voice_size_out = sizeof (OSSVoiceOut),

View File

@ -3,7 +3,7 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qemu/module.h" #include "qemu/module.h"
#include "audio.h" #include "audio.h"
#include "qapi/opts-visitor.h" #include "qapi/error.h"
#include <pulse/pulseaudio.h> #include <pulse/pulseaudio.h>
@ -818,7 +818,7 @@ fail:
return NULL; return NULL;
} }
static void *qpa_audio_init(Audiodev *dev) static void *qpa_audio_init(Audiodev *dev, Error **errp)
{ {
paaudio *g; paaudio *g;
AudiodevPaOptions *popts = &dev->u.pa; AudiodevPaOptions *popts = &dev->u.pa;
@ -834,10 +834,12 @@ static void *qpa_audio_init(Audiodev *dev)
runtime = getenv("XDG_RUNTIME_DIR"); runtime = getenv("XDG_RUNTIME_DIR");
if (!runtime) { if (!runtime) {
error_setg(errp, "XDG_RUNTIME_DIR not set");
return NULL; return NULL;
} }
snprintf(pidfile, sizeof(pidfile), "%s/pulse/pid", runtime); snprintf(pidfile, sizeof(pidfile), "%s/pulse/pid", runtime);
if (stat(pidfile, &st) != 0) { if (stat(pidfile, &st) != 0) {
error_setg_errno(errp, errno, "could not stat pidfile %s", pidfile);
return NULL; return NULL;
} }
} }
@ -867,6 +869,7 @@ static void *qpa_audio_init(Audiodev *dev)
} }
if (!g->conn) { if (!g->conn) {
g_free(g); g_free(g);
error_setg(errp, "could not connect to PulseAudio server");
return NULL; return NULL;
} }
@ -928,7 +931,6 @@ static struct audio_driver pa_audio_driver = {
.init = qpa_audio_init, .init = qpa_audio_init,
.fini = qpa_audio_fini, .fini = qpa_audio_fini,
.pcm_ops = &qpa_pcm_ops, .pcm_ops = &qpa_pcm_ops,
.can_be_default = 1,
.max_voices_out = INT_MAX, .max_voices_out = INT_MAX,
.max_voices_in = INT_MAX, .max_voices_in = INT_MAX,
.voice_size_out = sizeof (PAVoiceOut), .voice_size_out = sizeof (PAVoiceOut),

View File

@ -13,6 +13,7 @@
#include "audio.h" #include "audio.h"
#include <errno.h> #include <errno.h>
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "qapi/error.h"
#include <spa/param/audio/format-utils.h> #include <spa/param/audio/format-utils.h>
#include <spa/utils/ringbuffer.h> #include <spa/utils/ringbuffer.h>
#include <spa/utils/result.h> #include <spa/utils/result.h>
@ -736,7 +737,7 @@ static const struct pw_core_events core_events = {
}; };
static void * static void *
qpw_audio_init(Audiodev *dev) qpw_audio_init(Audiodev *dev, Error **errp)
{ {
g_autofree pwaudio *pw = g_new0(pwaudio, 1); g_autofree pwaudio *pw = g_new0(pwaudio, 1);
@ -748,19 +749,19 @@ qpw_audio_init(Audiodev *dev)
pw->dev = dev; pw->dev = dev;
pw->thread_loop = pw_thread_loop_new("PipeWire thread loop", NULL); pw->thread_loop = pw_thread_loop_new("PipeWire thread loop", NULL);
if (pw->thread_loop == NULL) { if (pw->thread_loop == NULL) {
error_report("Could not create PipeWire loop: %s", g_strerror(errno)); error_setg_errno(errp, errno, "Could not create PipeWire loop");
goto fail; goto fail;
} }
pw->context = pw->context =
pw_context_new(pw_thread_loop_get_loop(pw->thread_loop), NULL, 0); pw_context_new(pw_thread_loop_get_loop(pw->thread_loop), NULL, 0);
if (pw->context == NULL) { if (pw->context == NULL) {
error_report("Could not create PipeWire context: %s", g_strerror(errno)); error_setg_errno(errp, errno, "Could not create PipeWire context");
goto fail; goto fail;
} }
if (pw_thread_loop_start(pw->thread_loop) < 0) { if (pw_thread_loop_start(pw->thread_loop) < 0) {
error_report("Could not start PipeWire loop: %s", g_strerror(errno)); error_setg_errno(errp, errno, "Could not start PipeWire loop");
goto fail; goto fail;
} }
@ -769,13 +770,13 @@ qpw_audio_init(Audiodev *dev)
pw->core = pw_context_connect(pw->context, NULL, 0); pw->core = pw_context_connect(pw->context, NULL, 0);
if (pw->core == NULL) { if (pw->core == NULL) {
pw_thread_loop_unlock(pw->thread_loop); pw_thread_loop_unlock(pw->thread_loop);
goto fail; goto fail_error;
} }
if (pw_core_add_listener(pw->core, &pw->core_listener, if (pw_core_add_listener(pw->core, &pw->core_listener,
&core_events, pw) < 0) { &core_events, pw) < 0) {
pw_thread_loop_unlock(pw->thread_loop); pw_thread_loop_unlock(pw->thread_loop);
goto fail; goto fail_error;
} }
if (wait_resync(pw) < 0) { if (wait_resync(pw) < 0) {
pw_thread_loop_unlock(pw->thread_loop); pw_thread_loop_unlock(pw->thread_loop);
@ -785,8 +786,9 @@ qpw_audio_init(Audiodev *dev)
return g_steal_pointer(&pw); return g_steal_pointer(&pw);
fail_error:
error_setg(errp, "Failed to initialize PW context");
fail: fail:
AUD_log(AUDIO_CAP, "Failed to initialize PW context");
if (pw->thread_loop) { if (pw->thread_loop) {
pw_thread_loop_stop(pw->thread_loop); pw_thread_loop_stop(pw->thread_loop);
} }
@ -841,7 +843,6 @@ static struct audio_driver pw_audio_driver = {
.init = qpw_audio_init, .init = qpw_audio_init,
.fini = qpw_audio_fini, .fini = qpw_audio_fini,
.pcm_ops = &qpw_pcm_ops, .pcm_ops = &qpw_pcm_ops,
.can_be_default = 1,
.max_voices_out = INT_MAX, .max_voices_out = INT_MAX,
.max_voices_in = INT_MAX, .max_voices_in = INT_MAX,
.voice_size_out = sizeof(PWVoiceOut), .voice_size_out = sizeof(PWVoiceOut),

View File

@ -26,6 +26,7 @@
#include <SDL.h> #include <SDL.h>
#include <SDL_thread.h> #include <SDL_thread.h>
#include "qemu/module.h" #include "qemu/module.h"
#include "qapi/error.h"
#include "audio.h" #include "audio.h"
#ifndef _WIN32 #ifndef _WIN32
@ -449,10 +450,10 @@ static void sdl_enable_in(HWVoiceIn *hw, bool enable)
SDL_PauseAudioDevice(sdl->devid, !enable); SDL_PauseAudioDevice(sdl->devid, !enable);
} }
static void *sdl_audio_init(Audiodev *dev) static void *sdl_audio_init(Audiodev *dev, Error **errp)
{ {
if (SDL_InitSubSystem (SDL_INIT_AUDIO)) { if (SDL_InitSubSystem (SDL_INIT_AUDIO)) {
sdl_logerr ("SDL failed to initialize audio subsystem\n"); error_setg(errp, "SDL failed to initialize audio subsystem");
return NULL; return NULL;
} }
@ -493,7 +494,6 @@ static struct audio_driver sdl_audio_driver = {
.init = sdl_audio_init, .init = sdl_audio_init,
.fini = sdl_audio_fini, .fini = sdl_audio_fini,
.pcm_ops = &sdl_pcm_ops, .pcm_ops = &sdl_pcm_ops,
.can_be_default = 1,
.max_voices_out = INT_MAX, .max_voices_out = INT_MAX,
.max_voices_in = INT_MAX, .max_voices_in = INT_MAX,
.voice_size_out = sizeof(SDLVoiceOut), .voice_size_out = sizeof(SDLVoiceOut),

View File

@ -518,7 +518,7 @@ static void sndio_fini_in(HWVoiceIn *hw)
sndio_fini(self); sndio_fini(self);
} }
static void *sndio_audio_init(Audiodev *dev) static void *sndio_audio_init(Audiodev *dev, Error **errp)
{ {
assert(dev->driver == AUDIODEV_DRIVER_SNDIO); assert(dev->driver == AUDIODEV_DRIVER_SNDIO);
return dev; return dev;
@ -550,7 +550,6 @@ static struct audio_driver sndio_audio_driver = {
.init = sndio_audio_init, .init = sndio_audio_init,
.fini = sndio_audio_fini, .fini = sndio_audio_fini,
.pcm_ops = &sndio_pcm_ops, .pcm_ops = &sndio_pcm_ops,
.can_be_default = 1,
.max_voices_out = INT_MAX, .max_voices_out = INT_MAX,
.max_voices_in = INT_MAX, .max_voices_in = INT_MAX,
.voice_size_out = sizeof(SndioVoice), .voice_size_out = sizeof(SndioVoice),

View File

@ -22,6 +22,7 @@
#include "qemu/module.h" #include "qemu/module.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "qemu/timer.h" #include "qemu/timer.h"
#include "qapi/error.h"
#include "ui/qemu-spice.h" #include "ui/qemu-spice.h"
#define AUDIO_CAP "spice" #define AUDIO_CAP "spice"
@ -71,11 +72,13 @@ static const SpiceRecordInterface record_sif = {
.base.minor_version = SPICE_INTERFACE_RECORD_MINOR, .base.minor_version = SPICE_INTERFACE_RECORD_MINOR,
}; };
static void *spice_audio_init(Audiodev *dev) static void *spice_audio_init(Audiodev *dev, Error **errp)
{ {
if (!using_spice) { if (!using_spice) {
error_setg(errp, "Cannot use spice audio without -spice");
return NULL; return NULL;
} }
return &spice_audio_init; return &spice_audio_init;
} }

View File

@ -182,7 +182,7 @@ static void wav_enable_out(HWVoiceOut *hw, bool enable)
} }
} }
static void *wav_audio_init(Audiodev *dev) static void *wav_audio_init(Audiodev *dev, Error **errp)
{ {
assert(dev->driver == AUDIODEV_DRIVER_WAV); assert(dev->driver == AUDIODEV_DRIVER_WAV);
return dev; return dev;
@ -208,7 +208,6 @@ static struct audio_driver wav_audio_driver = {
.init = wav_audio_init, .init = wav_audio_init,
.fini = wav_audio_fini, .fini = wav_audio_fini,
.pcm_ops = &wav_pcm_ops, .pcm_ops = &wav_pcm_ops,
.can_be_default = 0,
.max_voices_out = 1, .max_voices_out = 1,
.max_voices_in = 0, .max_voices_in = 0,
.voice_size_out = sizeof (WAVVoiceOut), .voice_size_out = sizeof (WAVVoiceOut),

View File

@ -534,11 +534,8 @@ static int tpm_emulator_block_migration(TPMEmulator *tpm_emu)
error_setg(&tpm_emu->migration_blocker, error_setg(&tpm_emu->migration_blocker,
"Migration disabled: TPM emulator does not support " "Migration disabled: TPM emulator does not support "
"migration"); "migration");
if (migrate_add_blocker(tpm_emu->migration_blocker, &err) < 0) { 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;
} }
} }
@ -1016,10 +1013,7 @@ static void tpm_emulator_inst_finalize(Object *obj)
qapi_free_TPMEmulatorOptions(tpm_emu->options); qapi_free_TPMEmulatorOptions(tpm_emu->options);
if (tpm_emu->migration_blocker) { migrate_del_blocker(&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);

117
block.c
View File

@ -279,7 +279,8 @@ bool bdrv_is_read_only(BlockDriverState *bs)
return !(bs->open_flags & BDRV_O_RDWR); return !(bs->open_flags & BDRV_O_RDWR);
} }
static int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only, static int GRAPH_RDLOCK
bdrv_can_set_read_only(BlockDriverState *bs, bool read_only,
bool ignore_allow_rdw, Error **errp) bool ignore_allow_rdw, Error **errp)
{ {
IO_CODE(); IO_CODE();
@ -371,7 +372,8 @@ char *bdrv_get_full_backing_filename_from_filename(const char *backed,
* setting @errp. In all other cases, NULL will only be returned with * setting @errp. In all other cases, NULL will only be returned with
* @errp set. * @errp set.
*/ */
static char *bdrv_make_absolute_filename(BlockDriverState *relative_to, static char * GRAPH_RDLOCK
bdrv_make_absolute_filename(BlockDriverState *relative_to,
const char *filename, Error **errp) const char *filename, Error **errp)
{ {
char *dir, *full_name; char *dir, *full_name;
@ -1192,19 +1194,19 @@ static char *bdrv_child_get_parent_desc(BdrvChild *c)
return g_strdup_printf("node '%s'", bdrv_get_node_name(parent)); return g_strdup_printf("node '%s'", bdrv_get_node_name(parent));
} }
static void bdrv_child_cb_drained_begin(BdrvChild *child) static void GRAPH_RDLOCK bdrv_child_cb_drained_begin(BdrvChild *child)
{ {
BlockDriverState *bs = child->opaque; BlockDriverState *bs = child->opaque;
bdrv_do_drained_begin_quiesce(bs, NULL); bdrv_do_drained_begin_quiesce(bs, NULL);
} }
static bool bdrv_child_cb_drained_poll(BdrvChild *child) static bool GRAPH_RDLOCK bdrv_child_cb_drained_poll(BdrvChild *child)
{ {
BlockDriverState *bs = child->opaque; BlockDriverState *bs = child->opaque;
return bdrv_drain_poll(bs, NULL, false); return bdrv_drain_poll(bs, NULL, false);
} }
static void bdrv_child_cb_drained_end(BdrvChild *child) static void GRAPH_RDLOCK bdrv_child_cb_drained_end(BdrvChild *child)
{ {
BlockDriverState *bs = child->opaque; BlockDriverState *bs = child->opaque;
bdrv_drained_end(bs); bdrv_drained_end(bs);
@ -1250,7 +1252,7 @@ static void bdrv_temp_snapshot_options(int *child_flags, QDict *child_options,
*child_flags &= ~BDRV_O_NATIVE_AIO; *child_flags &= ~BDRV_O_NATIVE_AIO;
} }
static void bdrv_backing_attach(BdrvChild *c) static void GRAPH_WRLOCK bdrv_backing_attach(BdrvChild *c)
{ {
BlockDriverState *parent = c->opaque; BlockDriverState *parent = c->opaque;
BlockDriverState *backing_hd = c->bs; BlockDriverState *backing_hd = c->bs;
@ -1874,7 +1876,10 @@ static int bdrv_open_common(BlockDriverState *bs, BlockBackend *file,
} }
if (file != NULL) { if (file != NULL) {
bdrv_graph_rdlock_main_loop();
bdrv_refresh_filename(blk_bs(file)); bdrv_refresh_filename(blk_bs(file));
bdrv_graph_rdunlock_main_loop();
filename = blk_bs(file)->filename; filename = blk_bs(file)->filename;
} else { } else {
/* /*
@ -1901,7 +1906,9 @@ static int bdrv_open_common(BlockDriverState *bs, BlockBackend *file,
if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv, ro)) { if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv, ro)) {
if (!ro && bdrv_is_whitelisted(drv, true)) { if (!ro && bdrv_is_whitelisted(drv, true)) {
bdrv_graph_rdlock_main_loop();
ret = bdrv_apply_auto_read_only(bs, NULL, NULL); ret = bdrv_apply_auto_read_only(bs, NULL, NULL);
bdrv_graph_rdunlock_main_loop();
} else { } else {
ret = -ENOTSUP; ret = -ENOTSUP;
} }
@ -2966,6 +2973,8 @@ static void bdrv_child_free(BdrvChild *child)
{ {
assert(!child->bs); assert(!child->bs);
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
assert(!child->next.le_prev); /* not in children list */ assert(!child->next.le_prev); /* not in children list */
g_free(child->name); g_free(child->name);
@ -3072,18 +3081,19 @@ bdrv_attach_child_common(BlockDriverState *child_bs,
&local_err); &local_err);
if (ret < 0 && child_class->change_aio_ctx) { if (ret < 0 && child_class->change_aio_ctx) {
Transaction *tran = tran_new(); Transaction *aio_ctx_tran = tran_new();
GHashTable *visited = g_hash_table_new(NULL, NULL); GHashTable *visited = g_hash_table_new(NULL, NULL);
bool ret_child; bool ret_child;
g_hash_table_add(visited, new_child); g_hash_table_add(visited, new_child);
ret_child = child_class->change_aio_ctx(new_child, child_ctx, ret_child = child_class->change_aio_ctx(new_child, child_ctx,
visited, tran, NULL); visited, aio_ctx_tran,
NULL);
if (ret_child == true) { if (ret_child == true) {
error_free(local_err); error_free(local_err);
ret = 0; ret = 0;
} }
tran_finalize(tran, ret_child == true ? 0 : -1); tran_finalize(aio_ctx_tran, ret_child == true ? 0 : -1);
g_hash_table_destroy(visited); g_hash_table_destroy(visited);
} }
@ -3643,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);
@ -3674,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);
} }
@ -4313,8 +4328,8 @@ static int bdrv_reset_options_allowed(BlockDriverState *bs,
/* /*
* Returns true if @child can be reached recursively from @bs * Returns true if @child can be reached recursively from @bs
*/ */
static bool bdrv_recurse_has_child(BlockDriverState *bs, static bool GRAPH_RDLOCK
BlockDriverState *child) bdrv_recurse_has_child(BlockDriverState *bs, BlockDriverState *child)
{ {
BdrvChild *c; BdrvChild *c;
@ -4355,14 +4370,11 @@ static bool bdrv_recurse_has_child(BlockDriverState *bs,
* *
* To be called with bs->aio_context locked. * To be called with bs->aio_context locked.
*/ */
static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, static BlockReopenQueue * GRAPH_RDLOCK
BlockDriverState *bs, bdrv_reopen_queue_child(BlockReopenQueue *bs_queue, BlockDriverState *bs,
QDict *options, QDict *options, const BdrvChildClass *klass,
const BdrvChildClass *klass, BdrvChildRole role, bool parent_is_format,
BdrvChildRole role, QDict *parent_options, int parent_flags,
bool parent_is_format,
QDict *parent_options,
int parent_flags,
bool keep_old_opts) bool keep_old_opts)
{ {
assert(bs != NULL); assert(bs != NULL);
@ -4375,6 +4387,11 @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
/*
* Strictly speaking, draining is illegal under GRAPH_RDLOCK. We know that
* we've been called with bdrv_graph_rdlock_main_loop(), though, so it's ok
* in practice.
*/
bdrv_drained_begin(bs); bdrv_drained_begin(bs);
if (bs_queue == NULL) { if (bs_queue == NULL) {
@ -4516,6 +4533,7 @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
QDict *options, bool keep_old_opts) QDict *options, bool keep_old_opts)
{ {
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
return bdrv_reopen_queue_child(bs_queue, bs, options, NULL, 0, false, return bdrv_reopen_queue_child(bs_queue, bs, options, NULL, 0, false,
NULL, 0, keep_old_opts); NULL, 0, keep_old_opts);
@ -4735,7 +4753,8 @@ int bdrv_reopen_set_read_only(BlockDriverState *bs, bool read_only,
* Callers must make sure that their AioContext locking is still correct after * Callers must make sure that their AioContext locking is still correct after
* this. * this.
*/ */
static int bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state, static int GRAPH_UNLOCKED
bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state,
bool is_backing, Transaction *tran, bool is_backing, Transaction *tran,
Error **errp) Error **errp)
{ {
@ -4747,6 +4766,7 @@ static int bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state,
QObject *value; QObject *value;
const char *str; const char *str;
AioContext *ctx, *old_ctx; AioContext *ctx, *old_ctx;
bool has_child;
int ret; int ret;
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
@ -4766,7 +4786,13 @@ static int bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state,
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) {
return -EINVAL; return -EINVAL;
} else if (bdrv_recurse_has_child(new_child_bs, bs)) { }
bdrv_graph_rdlock_main_loop();
has_child = bdrv_recurse_has_child(new_child_bs, bs);
bdrv_graph_rdunlock_main_loop();
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);
return -EINVAL; return -EINVAL;
@ -4865,8 +4891,8 @@ static int bdrv_reopen_parse_file_or_backing(BDRVReopenState *reopen_state,
* After calling this function, the transaction @change_child_tran may only be * After calling this function, the transaction @change_child_tran may only be
* completed while holding a writer lock for the graph. * completed while holding a writer lock for the graph.
*/ */
static int bdrv_reopen_prepare(BDRVReopenState *reopen_state, static int GRAPH_UNLOCKED
BlockReopenQueue *queue, bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
Transaction *change_child_tran, Error **errp) Transaction *change_child_tran, Error **errp)
{ {
int ret = -1; int ret = -1;
@ -4929,7 +4955,10 @@ static int bdrv_reopen_prepare(BDRVReopenState *reopen_state,
* to r/w. Attempting to set to r/w may fail if either BDRV_O_ALLOW_RDWR is * to r/w. Attempting to set to r/w may fail if either BDRV_O_ALLOW_RDWR is
* not set, or if the BDS still has copy_on_read enabled */ * not set, or if the BDS still has copy_on_read enabled */
read_only = !(reopen_state->flags & BDRV_O_RDWR); read_only = !(reopen_state->flags & BDRV_O_RDWR);
bdrv_graph_rdlock_main_loop();
ret = bdrv_can_set_read_only(reopen_state->bs, read_only, true, &local_err); ret = bdrv_can_set_read_only(reopen_state->bs, read_only, true, &local_err);
bdrv_graph_rdunlock_main_loop();
if (local_err) { if (local_err) {
error_propagate(errp, local_err); error_propagate(errp, local_err);
goto error; goto error;
@ -4952,7 +4981,9 @@ static int bdrv_reopen_prepare(BDRVReopenState *reopen_state,
if (local_err != NULL) { if (local_err != NULL) {
error_propagate(errp, local_err); error_propagate(errp, local_err);
} else { } else {
bdrv_graph_rdlock_main_loop();
bdrv_refresh_filename(reopen_state->bs); bdrv_refresh_filename(reopen_state->bs);
bdrv_graph_rdunlock_main_loop();
error_setg(errp, "failed while preparing to reopen image '%s'", error_setg(errp, "failed while preparing to reopen image '%s'",
reopen_state->bs->filename); reopen_state->bs->filename);
} }
@ -4961,9 +4992,11 @@ static int bdrv_reopen_prepare(BDRVReopenState *reopen_state,
} else { } else {
/* It is currently mandatory to have a bdrv_reopen_prepare() /* It is currently mandatory to have a bdrv_reopen_prepare()
* handler for each supported drv. */ * handler for each supported drv. */
bdrv_graph_rdlock_main_loop();
error_setg(errp, "Block format '%s' used by node '%s' " error_setg(errp, "Block format '%s' used by node '%s' "
"does not support reopening files", drv->format_name, "does not support reopening files", drv->format_name,
bdrv_get_device_or_node_name(reopen_state->bs)); bdrv_get_device_or_node_name(reopen_state->bs));
bdrv_graph_rdunlock_main_loop();
ret = -1; ret = -1;
goto error; goto error;
} }
@ -5009,6 +5042,8 @@ static int bdrv_reopen_prepare(BDRVReopenState *reopen_state,
if (qdict_size(reopen_state->options)) { if (qdict_size(reopen_state->options)) {
const QDictEntry *entry = qdict_first(reopen_state->options); const QDictEntry *entry = qdict_first(reopen_state->options);
GRAPH_RDLOCK_GUARD_MAINLOOP();
do { do {
QObject *new = entry->value; QObject *new = entry->value;
QObject *old = qdict_get(reopen_state->bs->options, entry->key); QObject *old = qdict_get(reopen_state->bs->options, entry->key);
@ -5082,7 +5117,7 @@ error:
* makes them final by swapping the staging BlockDriverState contents into * makes them final by swapping the staging BlockDriverState contents into
* the active BlockDriverState contents. * the active BlockDriverState contents.
*/ */
static void bdrv_reopen_commit(BDRVReopenState *reopen_state) static void GRAPH_UNLOCKED bdrv_reopen_commit(BDRVReopenState *reopen_state)
{ {
BlockDriver *drv; BlockDriver *drv;
BlockDriverState *bs; BlockDriverState *bs;
@ -5099,6 +5134,8 @@ static void bdrv_reopen_commit(BDRVReopenState *reopen_state)
drv->bdrv_reopen_commit(reopen_state); drv->bdrv_reopen_commit(reopen_state);
} }
GRAPH_RDLOCK_GUARD_MAINLOOP();
/* set BDS specific flags now */ /* set BDS specific flags now */
qobject_unref(bs->explicit_options); qobject_unref(bs->explicit_options);
qobject_unref(bs->options); qobject_unref(bs->options);
@ -5120,9 +5157,7 @@ static void bdrv_reopen_commit(BDRVReopenState *reopen_state)
qdict_del(bs->explicit_options, "backing"); qdict_del(bs->explicit_options, "backing");
qdict_del(bs->options, "backing"); qdict_del(bs->options, "backing");
bdrv_graph_rdlock_main_loop();
bdrv_refresh_limits(bs, NULL, NULL); bdrv_refresh_limits(bs, NULL, NULL);
bdrv_graph_rdunlock_main_loop();
bdrv_refresh_total_sectors(bs, bs->total_sectors); bdrv_refresh_total_sectors(bs, bs->total_sectors);
} }
@ -5130,7 +5165,7 @@ static void bdrv_reopen_commit(BDRVReopenState *reopen_state)
* Abort the reopen, and delete and free the staged changes in * Abort the reopen, and delete and free the staged changes in
* reopen_state * reopen_state
*/ */
static void bdrv_reopen_abort(BDRVReopenState *reopen_state) static void GRAPH_UNLOCKED bdrv_reopen_abort(BDRVReopenState *reopen_state)
{ {
BlockDriver *drv; BlockDriver *drv;
@ -5917,6 +5952,7 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
bdrv_ref(top); bdrv_ref(top);
bdrv_drained_begin(base); bdrv_drained_begin(base);
bdrv_graph_rdlock_main_loop();
if (!top->drv || !base->drv) { if (!top->drv || !base->drv) {
goto exit; goto exit;
@ -5941,11 +5977,9 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
backing_file_str = base->filename; backing_file_str = base->filename;
} }
bdrv_graph_rdlock_main_loop();
QLIST_FOREACH(c, &top->parents, next_parent) { QLIST_FOREACH(c, &top->parents, next_parent) {
updated_children = g_slist_prepend(updated_children, c); updated_children = g_slist_prepend(updated_children, c);
} }
bdrv_graph_rdunlock_main_loop();
/* /*
* It seems correct to pass detach_subchain=true here, but it triggers * It seems correct to pass detach_subchain=true here, but it triggers
@ -5991,6 +6025,7 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
ret = 0; ret = 0;
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;
@ -6208,12 +6243,12 @@ void bdrv_iterate_format(void (*it)(void *opaque, const char *name),
QLIST_FOREACH(drv, &bdrv_drivers, list) { QLIST_FOREACH(drv, &bdrv_drivers, list) {
if (drv->format_name) { if (drv->format_name) {
bool found = false; bool found = false;
int i = count;
if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv, read_only)) { if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv, read_only)) {
continue; continue;
} }
i = count;
while (formats && i && !found) { while (formats && i && !found) {
found = !strcmp(formats[--i], drv->format_name); found = !strcmp(formats[--i], drv->format_name);
} }
@ -6281,6 +6316,7 @@ BlockDeviceInfoList *bdrv_named_nodes_list(bool flat,
BlockDriverState *bs; BlockDriverState *bs;
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
list = NULL; list = NULL;
QTAILQ_FOREACH(bs, &graph_bdrv_states, node_list) { QTAILQ_FOREACH(bs, &graph_bdrv_states, node_list) {
@ -6666,7 +6702,8 @@ void coroutine_fn bdrv_co_debug_event(BlockDriverState *bs, BlkdebugEvent event)
bs->drv->bdrv_co_debug_event(bs, event); bs->drv->bdrv_co_debug_event(bs, event);
} }
static BlockDriverState *bdrv_find_debug_node(BlockDriverState *bs) static BlockDriverState * GRAPH_RDLOCK
bdrv_find_debug_node(BlockDriverState *bs)
{ {
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
while (bs && bs->drv && !bs->drv->bdrv_debug_breakpoint) { while (bs && bs->drv && !bs->drv->bdrv_debug_breakpoint) {
@ -6685,6 +6722,8 @@ int bdrv_debug_breakpoint(BlockDriverState *bs, const char *event,
const char *tag) const char *tag)
{ {
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
bs = bdrv_find_debug_node(bs); bs = bdrv_find_debug_node(bs);
if (bs) { if (bs) {
return bs->drv->bdrv_debug_breakpoint(bs, event, tag); return bs->drv->bdrv_debug_breakpoint(bs, event, tag);
@ -6696,6 +6735,8 @@ int bdrv_debug_breakpoint(BlockDriverState *bs, const char *event,
int bdrv_debug_remove_breakpoint(BlockDriverState *bs, const char *tag) int bdrv_debug_remove_breakpoint(BlockDriverState *bs, const char *tag)
{ {
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
bs = bdrv_find_debug_node(bs); bs = bdrv_find_debug_node(bs);
if (bs) { if (bs) {
return bs->drv->bdrv_debug_remove_breakpoint(bs, tag); return bs->drv->bdrv_debug_remove_breakpoint(bs, tag);
@ -6707,6 +6748,8 @@ int bdrv_debug_remove_breakpoint(BlockDriverState *bs, const char *tag)
int bdrv_debug_resume(BlockDriverState *bs, const char *tag) int bdrv_debug_resume(BlockDriverState *bs, const char *tag)
{ {
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
while (bs && (!bs->drv || !bs->drv->bdrv_debug_resume)) { while (bs && (!bs->drv || !bs->drv->bdrv_debug_resume)) {
bs = bdrv_primary_bs(bs); bs = bdrv_primary_bs(bs);
} }
@ -6721,6 +6764,8 @@ int bdrv_debug_resume(BlockDriverState *bs, const char *tag)
bool bdrv_debug_is_suspended(BlockDriverState *bs, const char *tag) bool bdrv_debug_is_suspended(BlockDriverState *bs, const char *tag)
{ {
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
while (bs && bs->drv && !bs->drv->bdrv_debug_is_suspended) { while (bs && bs->drv && !bs->drv->bdrv_debug_is_suspended) {
bs = bdrv_primary_bs(bs); bs = bdrv_primary_bs(bs);
} }
@ -6749,6 +6794,7 @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
BlockDriverState *bs_below; BlockDriverState *bs_below;
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
if (!bs || !bs->drv || !backing_file) { if (!bs || !bs->drv || !backing_file) {
return NULL; return NULL;
@ -6960,6 +7006,7 @@ void bdrv_activate_all(Error **errp)
BdrvNextIterator it; BdrvNextIterator it;
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
AioContext *aio_context = bdrv_get_aio_context(bs); AioContext *aio_context = bdrv_get_aio_context(bs);
@ -6975,7 +7022,8 @@ void bdrv_activate_all(Error **errp)
} }
} }
static bool bdrv_has_bds_parent(BlockDriverState *bs, bool only_active) static bool GRAPH_RDLOCK
bdrv_has_bds_parent(BlockDriverState *bs, bool only_active)
{ {
BdrvChild *parent; BdrvChild *parent;
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
@ -6992,14 +7040,13 @@ static bool bdrv_has_bds_parent(BlockDriverState *bs, bool only_active)
return false; return false;
} }
static int bdrv_inactivate_recurse(BlockDriverState *bs) static int GRAPH_RDLOCK bdrv_inactivate_recurse(BlockDriverState *bs)
{ {
BdrvChild *child, *parent; BdrvChild *child, *parent;
int ret; int ret;
uint64_t cumulative_perms, cumulative_shared_perms; uint64_t cumulative_perms, cumulative_shared_perms;
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
if (!bs->drv) { if (!bs->drv) {
return -ENOMEDIUM; return -ENOMEDIUM;
@ -7065,6 +7112,7 @@ int bdrv_inactivate_all(void)
GSList *aio_ctxs = NULL, *ctx; GSList *aio_ctxs = NULL, *ctx;
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) { for (bs = bdrv_first(&it); bs; bs = bdrv_next(&it)) {
AioContext *aio_context = bdrv_get_aio_context(bs); AioContext *aio_context = bdrv_get_aio_context(bs);
@ -7204,6 +7252,7 @@ bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp)
{ {
BdrvOpBlocker *blocker; BdrvOpBlocker *blocker;
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
assert((int) op >= 0 && op < BLOCK_OP_TYPE_MAX); assert((int) op >= 0 && op < BLOCK_OP_TYPE_MAX);
if (!QLIST_EMPTY(&bs->op_blockers[op])) { if (!QLIST_EMPTY(&bs->op_blockers[op])) {
blocker = QLIST_FIRST(&bs->op_blockers[op]); blocker = QLIST_FIRST(&bs->op_blockers[op]);

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);

View File

@ -780,11 +780,12 @@ BlockDriverState *blk_bs(BlockBackend *blk)
return blk->root ? blk->root->bs : NULL; return blk->root ? blk->root->bs : NULL;
} }
static BlockBackend *bdrv_first_blk(BlockDriverState *bs) static BlockBackend * GRAPH_RDLOCK bdrv_first_blk(BlockDriverState *bs)
{ {
BdrvChild *child; BdrvChild *child;
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
assert_bdrv_graph_readable();
QLIST_FOREACH(child, &bs->parents, next_parent) { QLIST_FOREACH(child, &bs->parents, next_parent) {
if (child->klass == &child_root) { if (child->klass == &child_root) {
@ -812,6 +813,8 @@ bool bdrv_is_root_node(BlockDriverState *bs)
BdrvChild *c; BdrvChild *c;
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
assert_bdrv_graph_readable();
QLIST_FOREACH(c, &bs->parents, next_parent) { QLIST_FOREACH(c, &bs->parents, next_parent) {
if (c->klass != &child_root) { if (c->klass != &child_root) {
return false; return false;
@ -2259,6 +2262,7 @@ void blk_activate(BlockBackend *blk, Error **errp)
if (qemu_in_coroutine()) { if (qemu_in_coroutine()) {
bdrv_co_activate(bs, errp); bdrv_co_activate(bs, errp);
} else { } else {
GRAPH_RDLOCK_GUARD_MAINLOOP();
bdrv_activate(bs, errp); bdrv_activate(bs, errp);
} }
} }
@ -2384,6 +2388,7 @@ bool blk_op_is_blocked(BlockBackend *blk, BlockOpType op, Error **errp)
{ {
BlockDriverState *bs = blk_bs(blk); BlockDriverState *bs = blk_bs(blk);
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
if (!bs) { if (!bs) {
return false; return false;
@ -2901,6 +2906,8 @@ const BdrvChild *blk_root(BlockBackend *blk)
int blk_make_empty(BlockBackend *blk, Error **errp) int blk_make_empty(BlockBackend *blk, Error **errp)
{ {
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
if (!blk_is_available(blk)) { if (!blk_is_available(blk)) {
error_setg(errp, "No medium inserted"); error_setg(errp, "No medium inserted");
return -ENOMEDIUM; return -ENOMEDIUM;

View File

@ -106,7 +106,9 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
int ret; int ret;
/* No write support yet */ /* No write support yet */
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();
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }

View File

@ -67,7 +67,9 @@ 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;
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();
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }

View File

@ -434,6 +434,7 @@ int bdrv_commit(BlockDriverState *bs)
Error *local_err = NULL; Error *local_err = NULL;
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
if (!drv) if (!drv)
return -ENOMEDIUM; return -ENOMEDIUM;

View File

@ -305,7 +305,7 @@ cbw_co_snapshot_block_status(BlockDriverState *bs,
return -EACCES; return -EACCES;
} }
ret = bdrv_block_status(child->bs, offset, cur_bytes, pnum, map, file); ret = bdrv_co_block_status(child->bs, offset, cur_bytes, pnum, map, file);
if (child == s->target) { if (child == s->target) {
/* /*
* We refer to s->target only for areas that we've written to it. * We refer to s->target only for areas that we've written to it.

View File

@ -146,9 +146,9 @@ cor_co_preadv_part(BlockDriverState *bs, int64_t offset, int64_t bytes,
local_flags = flags; local_flags = flags;
/* In case of failure, try to copy-on-read anyway */ /* In case of failure, try to copy-on-read anyway */
ret = bdrv_is_allocated(bs->file->bs, offset, bytes, &n); ret = bdrv_co_is_allocated(bs->file->bs, offset, bytes, &n);
if (ret <= 0) { if (ret <= 0) {
ret = bdrv_is_allocated_above(bdrv_backing_chain_next(bs->file->bs), ret = bdrv_co_is_allocated_above(bdrv_backing_chain_next(bs->file->bs),
state->bottom_bs, true, offset, state->bottom_bs, true, offset,
n, &n); n, &n);
if (ret > 0 || ret < 0) { if (ret > 0 || ret < 0) {

View File

@ -828,7 +828,7 @@ block_crypto_amend_options_generic_luks(BlockDriverState *bs,
errp); errp);
} }
static int static int GRAPH_RDLOCK
block_crypto_amend_options_luks(BlockDriverState *bs, block_crypto_amend_options_luks(BlockDriverState *bs,
QemuOpts *opts, QemuOpts *opts,
BlockDriverAmendStatusCB *status_cb, BlockDriverAmendStatusCB *status_cb,
@ -841,8 +841,6 @@ block_crypto_amend_options_luks(BlockDriverState *bs,
QCryptoBlockAmendOptions *amend_options = NULL; QCryptoBlockAmendOptions *amend_options = NULL;
int ret = -EINVAL; int ret = -EINVAL;
assume_graph_lock(); /* FIXME */
assert(crypto); assert(crypto);
assert(crypto->block); assert(crypto->block);

View File

@ -696,8 +696,10 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
const char *protocol_delimiter; const char *protocol_delimiter;
int ret; int ret;
bdrv_graph_rdlock_main_loop();
ret = bdrv_apply_auto_read_only(bs, "curl driver does not support writes", ret = bdrv_apply_auto_read_only(bs, "curl driver does not support writes",
errp); errp);
bdrv_graph_rdunlock_main_loop();
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }

View File

@ -452,7 +452,9 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
int64_t offset; int64_t offset;
int ret; int ret;
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();
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }

View File

@ -83,6 +83,8 @@ BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp)
uint64_t perm; uint64_t perm;
int ret; int ret;
GLOBAL_STATE_CODE();
if (!id_wellformed(export->id)) { if (!id_wellformed(export->id)) {
error_setg(errp, "Invalid block export id"); error_setg(errp, "Invalid block export id");
return NULL; return NULL;
@ -145,7 +147,9 @@ BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp)
* access since the export could be available before migration handover. * access since the export could be available before migration handover.
* ctx was acquired in the caller. * ctx was acquired in the caller.
*/ */
bdrv_graph_rdlock_main_loop();
bdrv_activate(bs, NULL); bdrv_activate(bs, NULL);
bdrv_graph_rdunlock_main_loop();
perm = BLK_PERM_CONSISTENT_READ; perm = BLK_PERM_CONSISTENT_READ;
if (export->writable) { if (export->writable) {

View File

@ -863,11 +863,13 @@ static int qemu_gluster_open(BlockDriverState *bs, QDict *options,
if (ret == -EACCES || ret == -EROFS) { if (ret == -EACCES || ret == -EROFS) {
/* Try to degrade to read-only, but if it doesn't work, still use the /* Try to degrade to read-only, but if it doesn't work, still use the
* normal error message. */ * normal error message. */
bdrv_graph_rdlock_main_loop();
if (bdrv_apply_auto_read_only(bs, NULL, NULL) == 0) { if (bdrv_apply_auto_read_only(bs, NULL, NULL) == 0) {
open_flags = (open_flags & ~O_RDWR) | O_RDONLY; open_flags = (open_flags & ~O_RDWR) | O_RDONLY;
s->fd = glfs_open(s->glfs, gconf->path, open_flags); s->fd = glfs_open(s->glfs, gconf->path, open_flags);
ret = s->fd ? 0 : -errno; ret = s->fd ? 0 : -errno;
} }
bdrv_graph_rdunlock_main_loop();
} }
s->supports_seek_data = qemu_gluster_test_seek(s->fd); s->supports_seek_data = qemu_gluster_test_seek(s->fd);

View File

@ -106,12 +106,13 @@ static uint32_t reader_count(void)
return rd; return rd;
} }
void bdrv_graph_wrlock(BlockDriverState *bs) void no_coroutine_fn bdrv_graph_wrlock(BlockDriverState *bs)
{ {
AioContext *ctx = NULL; AioContext *ctx = NULL;
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
assert(!qatomic_read(&has_writer)); assert(!qatomic_read(&has_writer));
assert(!qemu_in_coroutine());
/* /*
* Release only non-mainloop AioContext. The mainloop often relies on the * Release only non-mainloop AioContext. The mainloop often relies on the

View File

@ -42,13 +42,18 @@
/* Maximum bounce buffer for copy-on-read and write zeroes, in bytes */ /* Maximum bounce buffer for copy-on-read and write zeroes, in bytes */
#define MAX_BOUNCE_BUFFER (32768 << BDRV_SECTOR_BITS) #define MAX_BOUNCE_BUFFER (32768 << BDRV_SECTOR_BITS)
static void bdrv_parent_cb_resize(BlockDriverState *bs); static void coroutine_fn GRAPH_RDLOCK
bdrv_parent_cb_resize(BlockDriverState *bs);
static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs, static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
int64_t offset, int64_t bytes, BdrvRequestFlags flags); int64_t offset, int64_t bytes, BdrvRequestFlags flags);
static void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore) static void GRAPH_RDLOCK
bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore)
{ {
BdrvChild *c, *next; BdrvChild *c, *next;
IO_OR_GS_CODE();
assert_bdrv_graph_readable();
QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) { QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) {
if (c == ignore) { if (c == ignore) {
@ -70,9 +75,12 @@ void bdrv_parent_drained_end_single(BdrvChild *c)
} }
} }
static void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore) static void GRAPH_RDLOCK
bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore)
{ {
BdrvChild *c; BdrvChild *c;
IO_OR_GS_CODE();
assert_bdrv_graph_readable();
QLIST_FOREACH(c, &bs->parents, next_parent) { QLIST_FOREACH(c, &bs->parents, next_parent) {
if (c == ignore) { if (c == ignore) {
@ -84,17 +92,22 @@ static void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore)
bool bdrv_parent_drained_poll_single(BdrvChild *c) bool bdrv_parent_drained_poll_single(BdrvChild *c)
{ {
IO_OR_GS_CODE();
if (c->klass->drained_poll) { if (c->klass->drained_poll) {
return c->klass->drained_poll(c); return c->klass->drained_poll(c);
} }
return false; return false;
} }
static bool bdrv_parent_drained_poll(BlockDriverState *bs, BdrvChild *ignore, static bool GRAPH_RDLOCK
bdrv_parent_drained_poll(BlockDriverState *bs, BdrvChild *ignore,
bool ignore_bds_parents) bool ignore_bds_parents)
{ {
BdrvChild *c, *next; BdrvChild *c, *next;
bool busy = false; bool busy = false;
IO_OR_GS_CODE();
assert_bdrv_graph_readable();
QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) { QLIST_FOREACH_SAFE(c, &bs->parents, next_parent, next) {
if (c == ignore || (ignore_bds_parents && c->klass->parent_is_bds)) { if (c == ignore || (ignore_bds_parents && c->klass->parent_is_bds)) {
@ -114,6 +127,7 @@ void bdrv_parent_drained_begin_single(BdrvChild *c)
c->quiesced_parent = true; c->quiesced_parent = true;
if (c->klass->drained_begin) { if (c->klass->drained_begin) {
/* called with rdlock taken, but it doesn't really need it. */
c->klass->drained_begin(c); c->klass->drained_begin(c);
} }
} }
@ -263,6 +277,9 @@ bool bdrv_drain_poll(BlockDriverState *bs, BdrvChild *ignore_parent,
static bool bdrv_drain_poll_top_level(BlockDriverState *bs, static bool bdrv_drain_poll_top_level(BlockDriverState *bs,
BdrvChild *ignore_parent) BdrvChild *ignore_parent)
{ {
GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
return bdrv_drain_poll(bs, ignore_parent, false); return bdrv_drain_poll(bs, ignore_parent, false);
} }
@ -362,6 +379,7 @@ static void bdrv_do_drained_begin(BlockDriverState *bs, BdrvChild *parent,
/* Stop things in parent-to-child order */ /* Stop things in parent-to-child order */
if (qatomic_fetch_inc(&bs->quiesce_counter) == 0) { if (qatomic_fetch_inc(&bs->quiesce_counter) == 0) {
GRAPH_RDLOCK_GUARD_MAINLOOP();
bdrv_parent_drained_begin(bs, parent); bdrv_parent_drained_begin(bs, parent);
if (bs->drv && bs->drv->bdrv_drain_begin) { if (bs->drv && bs->drv->bdrv_drain_begin) {
bs->drv->bdrv_drain_begin(bs); bs->drv->bdrv_drain_begin(bs);
@ -408,12 +426,16 @@ static void bdrv_do_drained_end(BlockDriverState *bs, BdrvChild *parent)
bdrv_co_yield_to_drain(bs, false, parent, false); bdrv_co_yield_to_drain(bs, false, parent, false);
return; return;
} }
/* At this point, we should be always running in the main loop. */
GLOBAL_STATE_CODE();
assert(bs->quiesce_counter > 0); assert(bs->quiesce_counter > 0);
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
/* Re-enable things in child-to-parent order */ /* Re-enable things in child-to-parent order */
old_quiesce_counter = qatomic_fetch_dec(&bs->quiesce_counter); old_quiesce_counter = qatomic_fetch_dec(&bs->quiesce_counter);
if (old_quiesce_counter == 1) { if (old_quiesce_counter == 1) {
GRAPH_RDLOCK_GUARD_MAINLOOP();
if (bs->drv && bs->drv->bdrv_drain_end) { if (bs->drv && bs->drv->bdrv_drain_end) {
bs->drv->bdrv_drain_end(bs); bs->drv->bdrv_drain_end(bs);
} }
@ -437,6 +459,8 @@ void bdrv_drain(BlockDriverState *bs)
static void bdrv_drain_assert_idle(BlockDriverState *bs) static void bdrv_drain_assert_idle(BlockDriverState *bs)
{ {
BdrvChild *child, *next; BdrvChild *child, *next;
GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
assert(qatomic_read(&bs->in_flight) == 0); assert(qatomic_read(&bs->in_flight) == 0);
QLIST_FOREACH_SAFE(child, &bs->children, next, next) { QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
@ -450,7 +474,9 @@ static bool bdrv_drain_all_poll(void)
{ {
BlockDriverState *bs = NULL; BlockDriverState *bs = NULL;
bool result = false; bool result = false;
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
/* bdrv_drain_poll() can't make changes to the graph and we are holding the /* bdrv_drain_poll() can't make changes to the graph and we are holding the
* main AioContext lock, so iterating bdrv_next_all_states() is safe. */ * main AioContext lock, so iterating bdrv_next_all_states() is safe. */
@ -1223,7 +1249,7 @@ bdrv_co_do_copy_on_readv(BdrvChild *child, int64_t offset, int64_t bytes,
ret = 1; /* "already allocated", so nothing will be copied */ ret = 1; /* "already allocated", so nothing will be copied */
pnum = MIN(align_bytes, max_transfer); pnum = MIN(align_bytes, max_transfer);
} else { } else {
ret = bdrv_is_allocated(bs, align_offset, ret = bdrv_co_is_allocated(bs, align_offset,
MIN(align_bytes, max_transfer), &pnum); MIN(align_bytes, max_transfer), &pnum);
if (ret < 0) { if (ret < 0) {
/* /*
@ -1371,7 +1397,7 @@ bdrv_aligned_preadv(BdrvChild *child, BdrvTrackedRequest *req,
/* The flag BDRV_REQ_COPY_ON_READ has reached its addressee */ /* The flag BDRV_REQ_COPY_ON_READ has reached its addressee */
flags &= ~BDRV_REQ_COPY_ON_READ; flags &= ~BDRV_REQ_COPY_ON_READ;
ret = bdrv_is_allocated(bs, offset, bytes, &pnum); ret = bdrv_co_is_allocated(bs, offset, bytes, &pnum);
if (ret < 0) { if (ret < 0) {
goto out; goto out;
} }
@ -2003,7 +2029,7 @@ bdrv_co_write_req_prepare(BdrvChild *child, int64_t offset, int64_t bytes,
} }
} }
static inline void coroutine_fn static inline void coroutine_fn GRAPH_RDLOCK
bdrv_co_write_req_finish(BdrvChild *child, int64_t offset, int64_t bytes, bdrv_co_write_req_finish(BdrvChild *child, int64_t offset, int64_t bytes,
BdrvTrackedRequest *req, int ret) BdrvTrackedRequest *req, int ret)
{ {
@ -2330,6 +2356,7 @@ int bdrv_flush_all(void)
int result = 0; int result = 0;
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
/* /*
* bdrv queue is managed by record/replay, * bdrv queue is managed by record/replay,
@ -2383,7 +2410,7 @@ int bdrv_flush_all(void)
* set to the host mapping and BDS corresponding to the guest offset. * set to the host mapping and BDS corresponding to the guest offset.
*/ */
static int coroutine_fn GRAPH_RDLOCK static int coroutine_fn GRAPH_RDLOCK
bdrv_co_block_status(BlockDriverState *bs, bool want_zero, bdrv_co_do_block_status(BlockDriverState *bs, bool want_zero,
int64_t offset, int64_t bytes, int64_t offset, int64_t bytes,
int64_t *pnum, int64_t *map, BlockDriverState **file) int64_t *pnum, int64_t *map, BlockDriverState **file)
{ {
@ -2544,7 +2571,7 @@ bdrv_co_block_status(BlockDriverState *bs, bool want_zero,
if (ret & BDRV_BLOCK_RAW) { if (ret & BDRV_BLOCK_RAW) {
assert(ret & BDRV_BLOCK_OFFSET_VALID && local_file); assert(ret & BDRV_BLOCK_OFFSET_VALID && local_file);
ret = bdrv_co_block_status(local_file, want_zero, local_map, ret = bdrv_co_do_block_status(local_file, want_zero, local_map,
*pnum, pnum, &local_map, &local_file); *pnum, pnum, &local_map, &local_file);
goto out; goto out;
} }
@ -2572,7 +2599,7 @@ bdrv_co_block_status(BlockDriverState *bs, bool want_zero,
int64_t file_pnum; int64_t file_pnum;
int ret2; int ret2;
ret2 = bdrv_co_block_status(local_file, want_zero, local_map, ret2 = bdrv_co_do_block_status(local_file, want_zero, local_map,
*pnum, &file_pnum, NULL, NULL); *pnum, &file_pnum, NULL, NULL);
if (ret2 >= 0) { if (ret2 >= 0) {
/* Ignore errors. This is just providing extra information, it /* Ignore errors. This is just providing extra information, it
@ -2640,7 +2667,8 @@ bdrv_co_common_block_status_above(BlockDriverState *bs,
return 0; return 0;
} }
ret = bdrv_co_block_status(bs, want_zero, offset, bytes, pnum, map, file); ret = bdrv_co_do_block_status(bs, want_zero, offset, bytes, pnum,
map, file);
++*depth; ++*depth;
if (ret < 0 || *pnum == 0 || ret & BDRV_BLOCK_ALLOCATED || bs == base) { if (ret < 0 || *pnum == 0 || ret & BDRV_BLOCK_ALLOCATED || bs == base) {
return ret; return ret;
@ -2656,8 +2684,8 @@ bdrv_co_common_block_status_above(BlockDriverState *bs,
for (p = bdrv_filter_or_cow_bs(bs); include_base || p != base; for (p = bdrv_filter_or_cow_bs(bs); include_base || p != base;
p = bdrv_filter_or_cow_bs(p)) p = bdrv_filter_or_cow_bs(p))
{ {
ret = bdrv_co_block_status(p, want_zero, offset, bytes, pnum, map, ret = bdrv_co_do_block_status(p, want_zero, offset, bytes, pnum,
file); map, file);
++*depth; ++*depth;
if (ret < 0) { if (ret < 0) {
return ret; return ret;
@ -2723,20 +2751,12 @@ int coroutine_fn bdrv_co_block_status_above(BlockDriverState *bs,
bytes, pnum, map, file, NULL); bytes, pnum, map, file, NULL);
} }
int bdrv_block_status_above(BlockDriverState *bs, BlockDriverState *base, int coroutine_fn bdrv_co_block_status(BlockDriverState *bs, int64_t offset,
int64_t offset, int64_t bytes, int64_t *pnum, int64_t bytes, int64_t *pnum,
int64_t *map, BlockDriverState **file) int64_t *map, BlockDriverState **file)
{ {
IO_CODE(); IO_CODE();
return bdrv_common_block_status_above(bs, base, false, true, offset, bytes, return bdrv_co_block_status_above(bs, bdrv_filter_or_cow_bs(bs),
pnum, map, file, NULL);
}
int bdrv_block_status(BlockDriverState *bs, int64_t offset, int64_t bytes,
int64_t *pnum, int64_t *map, BlockDriverState **file)
{
IO_CODE();
return bdrv_block_status_above(bs, bdrv_filter_or_cow_bs(bs),
offset, bytes, pnum, map, file); offset, bytes, pnum, map, file);
} }
@ -2784,45 +2804,6 @@ int coroutine_fn bdrv_co_is_allocated(BlockDriverState *bs, int64_t offset,
return !!(ret & BDRV_BLOCK_ALLOCATED); return !!(ret & BDRV_BLOCK_ALLOCATED);
} }
int bdrv_is_allocated(BlockDriverState *bs, int64_t offset, int64_t bytes,
int64_t *pnum)
{
int ret;
int64_t dummy;
IO_CODE();
ret = bdrv_common_block_status_above(bs, bs, true, false, offset,
bytes, pnum ? pnum : &dummy, NULL,
NULL, NULL);
if (ret < 0) {
return ret;
}
return !!(ret & BDRV_BLOCK_ALLOCATED);
}
/* See bdrv_is_allocated_above for documentation */
int coroutine_fn bdrv_co_is_allocated_above(BlockDriverState *top,
BlockDriverState *base,
bool include_base, int64_t offset,
int64_t bytes, int64_t *pnum)
{
int depth;
int ret;
IO_CODE();
ret = bdrv_co_common_block_status_above(top, base, include_base, false,
offset, bytes, pnum, NULL, NULL,
&depth);
if (ret < 0) {
return ret;
}
if (ret & BDRV_BLOCK_ALLOCATED) {
return depth;
}
return 0;
}
/* /*
* Given an image chain: ... -> [BASE] -> [INTER1] -> [INTER2] -> [TOP] * Given an image chain: ... -> [BASE] -> [INTER1] -> [INTER2] -> [TOP]
* *
@ -2840,7 +2821,7 @@ int coroutine_fn bdrv_co_is_allocated_above(BlockDriverState *top,
* words, the result is not necessarily the maximum possible range); * words, the result is not necessarily the maximum possible range);
* but 'pnum' will only be 0 when end of file is reached. * but 'pnum' will only be 0 when end of file is reached.
*/ */
int bdrv_is_allocated_above(BlockDriverState *top, int coroutine_fn bdrv_co_is_allocated_above(BlockDriverState *bs,
BlockDriverState *base, BlockDriverState *base,
bool include_base, int64_t offset, bool include_base, int64_t offset,
int64_t bytes, int64_t *pnum) int64_t bytes, int64_t *pnum)
@ -2849,7 +2830,7 @@ int bdrv_is_allocated_above(BlockDriverState *top,
int ret; int ret;
IO_CODE(); IO_CODE();
ret = bdrv_common_block_status_above(top, base, include_base, false, ret = bdrv_co_common_block_status_above(bs, base, include_base, false,
offset, bytes, pnum, NULL, NULL, offset, bytes, pnum, NULL, NULL,
&depth); &depth);
if (ret < 0) { if (ret < 0) {
@ -3551,9 +3532,13 @@ int coroutine_fn bdrv_co_copy_range(BdrvChild *src, int64_t src_offset,
bytes, read_flags, write_flags); bytes, read_flags, write_flags);
} }
static void bdrv_parent_cb_resize(BlockDriverState *bs) static void coroutine_fn GRAPH_RDLOCK
bdrv_parent_cb_resize(BlockDriverState *bs)
{ {
BdrvChild *c; BdrvChild *c;
assert_bdrv_graph_readable();
QLIST_FOREACH(c, &bs->parents, next_parent) { QLIST_FOREACH(c, &bs->parents, next_parent) {
if (c->klass->resize) { if (c->klass->resize) {
c->klass->resize(c); c->klass->resize(c);

View File

@ -1925,7 +1925,9 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
/* Check the write protect flag of the LUN if we want to write */ /* Check the write protect flag of the LUN if we want to write */
if (iscsilun->type == TYPE_DISK && (flags & BDRV_O_RDWR) && if (iscsilun->type == TYPE_DISK && (flags & BDRV_O_RDWR) &&
iscsilun->write_protected) { iscsilun->write_protected) {
bdrv_graph_rdlock_main_loop();
ret = bdrv_apply_auto_read_only(bs, "LUN is write protected", errp); ret = bdrv_apply_auto_read_only(bs, "LUN is write protected", errp);
bdrv_graph_rdunlock_main_loop();
if (ret < 0) { if (ret < 0) {
goto out; goto out;
} }

View File

@ -559,7 +559,7 @@ static void coroutine_fn mirror_iteration(MirrorBlockJob *s)
assert(!(offset % s->granularity)); assert(!(offset % s->granularity));
WITH_GRAPH_RDLOCK_GUARD() { WITH_GRAPH_RDLOCK_GUARD() {
ret = bdrv_block_status_above(source, NULL, offset, ret = bdrv_co_block_status_above(source, NULL, offset,
nb_chunks * s->granularity, nb_chunks * s->granularity,
&io_bytes, NULL, NULL); &io_bytes, NULL, NULL);
} }
@ -879,7 +879,7 @@ static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s)
} }
WITH_GRAPH_RDLOCK_GUARD() { WITH_GRAPH_RDLOCK_GUARD() {
ret = bdrv_is_allocated_above(bs, s->base_overlay, true, offset, ret = bdrv_co_is_allocated_above(bs, s->base_overlay, true, offset,
bytes, &count); bytes, &count);
} }
if (ret < 0) { if (ret < 0) {

View File

@ -258,37 +258,38 @@ void qmp_block_dirty_bitmap_disable(const char *node, const char *name,
bdrv_disable_dirty_bitmap(bitmap); bdrv_disable_dirty_bitmap(bitmap);
} }
BdrvDirtyBitmap *block_dirty_bitmap_merge(const char *node, const char *target, BdrvDirtyBitmap *block_dirty_bitmap_merge(const char *dst_node,
const char *dst_bitmap,
BlockDirtyBitmapOrStrList *bms, BlockDirtyBitmapOrStrList *bms,
HBitmap **backup, Error **errp) HBitmap **backup, Error **errp)
{ {
BlockDriverState *bs; BlockDriverState *bs;
BdrvDirtyBitmap *dst, *src; BdrvDirtyBitmap *dst, *src;
BlockDirtyBitmapOrStrList *lst; BlockDirtyBitmapOrStrList *lst;
const char *src_node, *src_bitmap;
HBitmap *local_backup = NULL; HBitmap *local_backup = NULL;
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
dst = block_dirty_bitmap_lookup(node, target, &bs, errp); dst = block_dirty_bitmap_lookup(dst_node, dst_bitmap, &bs, errp);
if (!dst) { if (!dst) {
return NULL; return NULL;
} }
for (lst = bms; lst; lst = lst->next) { for (lst = bms; lst; lst = lst->next) {
switch (lst->value->type) { switch (lst->value->type) {
const char *name, *node;
case QTYPE_QSTRING: case QTYPE_QSTRING:
name = lst->value->u.local; src_bitmap = lst->value->u.local;
src = bdrv_find_dirty_bitmap(bs, name); src = bdrv_find_dirty_bitmap(bs, src_bitmap);
if (!src) { if (!src) {
error_setg(errp, "Dirty bitmap '%s' not found", name); error_setg(errp, "Dirty bitmap '%s' not found", src_bitmap);
goto fail; goto fail;
} }
break; break;
case QTYPE_QDICT: case QTYPE_QDICT:
node = lst->value->u.external.node; src_node = lst->value->u.external.node;
name = lst->value->u.external.name; src_bitmap = lst->value->u.external.name;
src = block_dirty_bitmap_lookup(node, name, NULL, errp); src = block_dirty_bitmap_lookup(src_node, src_bitmap, NULL, errp);
if (!src) { if (!src) {
goto fail; goto fail;
} }

View File

@ -144,6 +144,9 @@ void hmp_drive_del(Monitor *mon, const QDict *qdict)
AioContext *aio_context; AioContext *aio_context;
Error *local_err = NULL; Error *local_err = NULL;
GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
bs = bdrv_find_node(id); bs = bdrv_find_node(id);
if (bs) { if (bs) {
qmp_blockdev_del(id, &local_err); qmp_blockdev_del(id, &local_err);
@ -896,6 +899,8 @@ void hmp_info_snapshots(Monitor *mon, const QDict *qdict)
SnapshotEntry *snapshot_entry; SnapshotEntry *snapshot_entry;
Error *err = NULL; Error *err = NULL;
GRAPH_RDLOCK_GUARD_MAINLOOP();
bs = bdrv_all_find_vmstate_bs(NULL, false, NULL, &err); bs = bdrv_all_find_vmstate_bs(NULL, false, NULL, &err);
if (!bs) { if (!bs) {
error_report_err(err); error_report_err(err);

View File

@ -275,7 +275,8 @@ static bool nbd_client_will_reconnect(BDRVNBDState *s)
* Return failure if the server's advertised options are incompatible with the * Return failure if the server's advertised options are incompatible with the
* client's needs. * client's needs.
*/ */
static int nbd_handle_updated_info(BlockDriverState *bs, Error **errp) static int coroutine_fn GRAPH_RDLOCK
nbd_handle_updated_info(BlockDriverState *bs, Error **errp)
{ {
BDRVNBDState *s = (BDRVNBDState *)bs->opaque; BDRVNBDState *s = (BDRVNBDState *)bs->opaque;
int ret; int ret;
@ -416,7 +417,8 @@ static void coroutine_fn GRAPH_RDLOCK nbd_reconnect_attempt(BDRVNBDState *s)
reconnect_delay_timer_del(s); reconnect_delay_timer_del(s);
} }
static coroutine_fn int nbd_receive_replies(BDRVNBDState *s, uint64_t cookie) static coroutine_fn int nbd_receive_replies(BDRVNBDState *s, uint64_t cookie,
Error **errp)
{ {
int ret; int ret;
uint64_t ind = COOKIE_TO_INDEX(cookie), ind2; uint64_t ind = COOKIE_TO_INDEX(cookie), ind2;
@ -457,20 +459,25 @@ static coroutine_fn int nbd_receive_replies(BDRVNBDState *s, uint64_t cookie)
/* We are under mutex and cookie is 0. We have to do the dirty work. */ /* We are under mutex and cookie is 0. We have to do the dirty work. */
assert(s->reply.cookie == 0); assert(s->reply.cookie == 0);
ret = nbd_receive_reply(s->bs, s->ioc, &s->reply, NULL); ret = nbd_receive_reply(s->bs, s->ioc, &s->reply, s->info.mode, errp);
if (ret <= 0) { if (ret == 0) {
ret = ret ? ret : -EIO; ret = -EIO;
error_setg(errp, "server dropped connection");
}
if (ret < 0) {
nbd_channel_error(s, ret); nbd_channel_error(s, ret);
return ret; return ret;
} }
if (nbd_reply_is_structured(&s->reply) && if (nbd_reply_is_structured(&s->reply) &&
s->info.mode < NBD_MODE_STRUCTURED) { s->info.mode < NBD_MODE_STRUCTURED) {
nbd_channel_error(s, -EINVAL); nbd_channel_error(s, -EINVAL);
error_setg(errp, "unexpected structured reply");
return -EINVAL; return -EINVAL;
} }
ind2 = COOKIE_TO_INDEX(s->reply.cookie); ind2 = COOKIE_TO_INDEX(s->reply.cookie);
if (ind2 >= MAX_NBD_REQUESTS || !s->requests[ind2].coroutine) { if (ind2 >= MAX_NBD_REQUESTS || !s->requests[ind2].coroutine) {
nbd_channel_error(s, -EINVAL); nbd_channel_error(s, -EINVAL);
error_setg(errp, "unexpected cookie value");
return -EINVAL; return -EINVAL;
} }
if (s->reply.cookie == cookie) { if (s->reply.cookie == cookie) {
@ -609,13 +616,17 @@ static int nbd_parse_offset_hole_payload(BDRVNBDState *s,
*/ */
static int nbd_parse_blockstatus_payload(BDRVNBDState *s, static int nbd_parse_blockstatus_payload(BDRVNBDState *s,
NBDStructuredReplyChunk *chunk, NBDStructuredReplyChunk *chunk,
uint8_t *payload, uint64_t orig_length, uint8_t *payload, bool wide,
NBDExtent32 *extent, Error **errp) uint64_t orig_length,
NBDExtent64 *extent, Error **errp)
{ {
uint32_t context_id; uint32_t context_id;
uint32_t count;
size_t ext_len = wide ? sizeof(*extent) : sizeof(NBDExtent32);
size_t pay_len = sizeof(context_id) + wide * sizeof(count) + ext_len;
/* The server succeeded, so it must have sent [at least] one extent */ /* The server succeeded, so it must have sent [at least] one extent */
if (chunk->length < sizeof(context_id) + sizeof(*extent)) { if (chunk->length < pay_len) {
error_setg(errp, "Protocol error: invalid payload for " error_setg(errp, "Protocol error: invalid payload for "
"NBD_REPLY_TYPE_BLOCK_STATUS"); "NBD_REPLY_TYPE_BLOCK_STATUS");
return -EINVAL; return -EINVAL;
@ -630,8 +641,15 @@ static int nbd_parse_blockstatus_payload(BDRVNBDState *s,
return -EINVAL; return -EINVAL;
} }
if (wide) {
count = payload_advance32(&payload);
extent->length = payload_advance64(&payload);
extent->flags = payload_advance64(&payload);
} else {
count = 0;
extent->length = payload_advance32(&payload); extent->length = payload_advance32(&payload);
extent->flags = payload_advance32(&payload); extent->flags = payload_advance32(&payload);
}
if (extent->length == 0) { if (extent->length == 0) {
error_setg(errp, "Protocol error: server sent status chunk with " error_setg(errp, "Protocol error: server sent status chunk with "
@ -666,13 +684,15 @@ static int nbd_parse_blockstatus_payload(BDRVNBDState *s,
/* /*
* We used NBD_CMD_FLAG_REQ_ONE, so the server should not have * We used NBD_CMD_FLAG_REQ_ONE, so the server should not have
* sent us any more than one extent, nor should it have included * sent us any more than one extent, nor should it have included
* status beyond our request in that extent. However, it's easy * status beyond our request in that extent. Furthermore, a wide
* enough to ignore the server's noncompliance without killing the * server should have replied with an accurate count (we left
* count at 0 for a narrow server). However, it's easy enough to
* ignore the server's noncompliance without killing the
* connection; just ignore trailing extents, and clamp things to * connection; just ignore trailing extents, and clamp things to
* the length of our request. * the length of our request.
*/ */
if (chunk->length > sizeof(context_id) + sizeof(*extent)) { if (count != wide || chunk->length > pay_len) {
trace_nbd_parse_blockstatus_compliance("more than one extent"); trace_nbd_parse_blockstatus_compliance("unexpected extent count");
} }
if (extent->length > orig_length) { if (extent->length > orig_length) {
extent->length = orig_length; extent->length = orig_length;
@ -842,9 +862,9 @@ static coroutine_fn int nbd_co_do_receive_one_chunk(
} }
*request_ret = 0; *request_ret = 0;
ret = nbd_receive_replies(s, cookie); ret = nbd_receive_replies(s, cookie, errp);
if (ret < 0) { if (ret < 0) {
error_setg(errp, "Connection closed"); error_prepend(errp, "Connection closed: ");
return -EIO; return -EIO;
} }
assert(s->ioc); assert(s->ioc);
@ -1118,7 +1138,7 @@ nbd_co_receive_cmdread_reply(BDRVNBDState *s, uint64_t cookie,
static int coroutine_fn static int coroutine_fn
nbd_co_receive_blockstatus_reply(BDRVNBDState *s, uint64_t cookie, nbd_co_receive_blockstatus_reply(BDRVNBDState *s, uint64_t cookie,
uint64_t length, NBDExtent32 *extent, uint64_t length, NBDExtent64 *extent,
int *request_ret, Error **errp) int *request_ret, Error **errp)
{ {
NBDReplyChunkIter iter; NBDReplyChunkIter iter;
@ -1131,11 +1151,17 @@ nbd_co_receive_blockstatus_reply(BDRVNBDState *s, uint64_t cookie,
NBD_FOREACH_REPLY_CHUNK(s, iter, cookie, false, NULL, &reply, &payload) { NBD_FOREACH_REPLY_CHUNK(s, iter, cookie, false, NULL, &reply, &payload) {
int ret; int ret;
NBDStructuredReplyChunk *chunk = &reply.structured; NBDStructuredReplyChunk *chunk = &reply.structured;
bool wide;
assert(nbd_reply_is_structured(&reply)); assert(nbd_reply_is_structured(&reply));
switch (chunk->type) { switch (chunk->type) {
case NBD_REPLY_TYPE_BLOCK_STATUS_EXT:
case NBD_REPLY_TYPE_BLOCK_STATUS: case NBD_REPLY_TYPE_BLOCK_STATUS:
wide = chunk->type == NBD_REPLY_TYPE_BLOCK_STATUS_EXT;
if ((s->info.mode >= NBD_MODE_EXTENDED) != wide) {
trace_nbd_extended_headers_compliance("block_status");
}
if (received) { if (received) {
nbd_channel_error(s, -EINVAL); nbd_channel_error(s, -EINVAL);
error_setg(&local_err, "Several BLOCK_STATUS chunks in reply"); error_setg(&local_err, "Several BLOCK_STATUS chunks in reply");
@ -1143,9 +1169,9 @@ nbd_co_receive_blockstatus_reply(BDRVNBDState *s, uint64_t cookie,
} }
received = true; received = true;
ret = nbd_parse_blockstatus_payload(s, &reply.structured, ret = nbd_parse_blockstatus_payload(
payload, length, extent, s, &reply.structured, payload, wide,
&local_err); length, extent, &local_err);
if (ret < 0) { if (ret < 0) {
nbd_channel_error(s, ret); nbd_channel_error(s, ret);
nbd_iter_channel_error(&iter, ret, &local_err); nbd_iter_channel_error(&iter, ret, &local_err);
@ -1375,7 +1401,7 @@ static int coroutine_fn GRAPH_RDLOCK nbd_client_co_block_status(
int64_t *pnum, int64_t *map, BlockDriverState **file) int64_t *pnum, int64_t *map, BlockDriverState **file)
{ {
int ret, request_ret; int ret, request_ret;
NBDExtent32 extent = { 0 }; NBDExtent64 extent = { 0 };
BDRVNBDState *s = (BDRVNBDState *)bs->opaque; BDRVNBDState *s = (BDRVNBDState *)bs->opaque;
Error *local_err = NULL; Error *local_err = NULL;

View File

@ -843,7 +843,7 @@ static void nfs_refresh_filename(BlockDriverState *bs)
} }
} }
static char *nfs_dirname(BlockDriverState *bs, Error **errp) static char * GRAPH_RDLOCK nfs_dirname(BlockDriverState *bs, Error **errp)
{ {
NFSClient *client = bs->opaque; NFSClient *client = bs->opaque;

View File

@ -1363,12 +1363,14 @@ 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));
ret = migrate_add_blocker(s->migration_blocker, errp); bdrv_graph_rdunlock_main_loop();
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);
@ -1403,7 +1405,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;
} }
} }
@ -1420,7 +1422,6 @@ 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;
@ -1445,8 +1446,7 @@ 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

@ -169,14 +169,16 @@ void qmp_blockdev_close_tray(const char *device,
} }
} }
static void blockdev_remove_medium(const char *device, const char *id, static void GRAPH_UNLOCKED
Error **errp) blockdev_remove_medium(const char *device, const char *id, Error **errp)
{ {
BlockBackend *blk; BlockBackend *blk;
BlockDriverState *bs; BlockDriverState *bs;
AioContext *aio_context; AioContext *aio_context;
bool has_attached_device; bool has_attached_device;
GLOBAL_STATE_CODE();
blk = qmp_get_blk(device, id, errp); blk = qmp_get_blk(device, id, errp);
if (!blk) { if (!blk) {
return; return;
@ -205,9 +207,12 @@ static void blockdev_remove_medium(const char *device, const char *id,
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 (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) { if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) {
bdrv_graph_rdunlock_main_loop();
goto out; goto out;
} }
bdrv_graph_rdunlock_main_loop();
blk_remove_bs(blk); blk_remove_bs(blk);
@ -279,6 +284,8 @@ static void blockdev_insert_medium(const char *device, const char *id,
BlockBackend *blk; BlockBackend *blk;
BlockDriverState *bs; BlockDriverState *bs;
GRAPH_RDLOCK_GUARD_MAINLOOP();
blk = qmp_get_blk(device, id, errp); blk = qmp_get_blk(device, id, errp);
if (!blk) { if (!blk) {
return; return;

View File

@ -225,9 +225,8 @@ int bdrv_query_snapshot_info_list(BlockDriverState *bs,
* Helper function for other query info functions. Store information about @bs * Helper function for other query info functions. Store information about @bs
* in @info, setting @errp on error. * in @info, setting @errp on error.
*/ */
static void bdrv_do_query_node_info(BlockDriverState *bs, static void GRAPH_RDLOCK
BlockNodeInfo *info, bdrv_do_query_node_info(BlockDriverState *bs, BlockNodeInfo *info, Error **errp)
Error **errp)
{ {
int64_t size; int64_t size;
const char *backing_filename; const char *backing_filename;
@ -423,8 +422,8 @@ fail:
} }
/* @p_info will be set only on success. */ /* @p_info will be set only on success. */
static void bdrv_query_info(BlockBackend *blk, BlockInfo **p_info, static void GRAPH_RDLOCK
Error **errp) bdrv_query_info(BlockBackend *blk, BlockInfo **p_info, Error **errp)
{ {
BlockInfo *info = g_malloc0(sizeof(*info)); BlockInfo *info = g_malloc0(sizeof(*info));
BlockDriverState *bs = blk_bs(blk); BlockDriverState *bs = blk_bs(blk);
@ -672,6 +671,8 @@ BlockInfoList *qmp_query_block(Error **errp)
BlockBackend *blk; BlockBackend *blk;
Error *local_err = NULL; Error *local_err = NULL;
GRAPH_RDLOCK_GUARD_MAINLOOP();
for (blk = blk_all_next(NULL); blk; blk = blk_all_next(blk)) { for (blk = blk_all_next(NULL); blk; blk = blk_all_next(blk)) {
BlockInfoList *info; BlockInfoList *info;

View File

@ -301,12 +301,14 @@ 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));
ret = migrate_add_blocker(s->migration_blocker, errp); bdrv_graph_rdunlock_main_loop();
ret = migrate_add_blocker(&s->migration_blocker, errp);
if (ret < 0) { if (ret < 0) {
error_free(s->migration_blocker);
goto fail; goto fail;
} }
@ -799,8 +801,7 @@ 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

View File

@ -156,10 +156,9 @@ static int64_t get_bitmap_bytes_needed(int64_t len, uint32_t granularity)
return DIV_ROUND_UP(num_bits, 8); return DIV_ROUND_UP(num_bits, 8);
} }
static int check_constraints_on_bitmap(BlockDriverState *bs, static int GRAPH_RDLOCK
const char *name, check_constraints_on_bitmap(BlockDriverState *bs, const char *name,
uint32_t granularity, uint32_t granularity, Error **errp)
Error **errp)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int granularity_bits = ctz32(granularity); int granularity_bits = ctz32(granularity);
@ -204,7 +203,8 @@ static int check_constraints_on_bitmap(BlockDriverState *bs,
return 0; return 0;
} }
static void clear_bitmap_table(BlockDriverState *bs, uint64_t *bitmap_table, static void GRAPH_RDLOCK
clear_bitmap_table(BlockDriverState *bs, uint64_t *bitmap_table,
uint32_t bitmap_table_size) uint32_t bitmap_table_size)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
@ -259,7 +259,8 @@ fail:
return ret; return ret;
} }
static int free_bitmap_clusters(BlockDriverState *bs, Qcow2BitmapTable *tb) static int GRAPH_RDLOCK
free_bitmap_clusters(BlockDriverState *bs, Qcow2BitmapTable *tb)
{ {
int ret; int ret;
uint64_t *bitmap_table; uint64_t *bitmap_table;
@ -730,7 +731,8 @@ out:
* Store bitmap list to qcow2 image as a bitmap directory. * Store bitmap list to qcow2 image as a bitmap directory.
* Everything is checked. * Everything is checked.
*/ */
static int bitmap_list_store(BlockDriverState *bs, Qcow2BitmapList *bm_list, static int GRAPH_RDLOCK
bitmap_list_store(BlockDriverState *bs, Qcow2BitmapList *bm_list,
uint64_t *offset, uint64_t *size, bool in_place) uint64_t *offset, uint64_t *size, bool in_place)
{ {
int ret; int ret;
@ -829,7 +831,8 @@ fail:
* Bitmap List end * Bitmap List end
*/ */
static int update_ext_header_and_dir_in_place(BlockDriverState *bs, static int GRAPH_RDLOCK
update_ext_header_and_dir_in_place(BlockDriverState *bs,
Qcow2BitmapList *bm_list) Qcow2BitmapList *bm_list)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
@ -877,8 +880,8 @@ static int update_ext_header_and_dir_in_place(BlockDriverState *bs,
*/ */
} }
static int update_ext_header_and_dir(BlockDriverState *bs, static int GRAPH_RDLOCK
Qcow2BitmapList *bm_list) update_ext_header_and_dir(BlockDriverState *bs, Qcow2BitmapList *bm_list)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int ret; int ret;
@ -1271,8 +1274,8 @@ out:
/* store_bitmap_data() /* store_bitmap_data()
* Store bitmap to image, filling bitmap table accordingly. * Store bitmap to image, filling bitmap table accordingly.
*/ */
static uint64_t *store_bitmap_data(BlockDriverState *bs, static uint64_t * GRAPH_RDLOCK
BdrvDirtyBitmap *bitmap, store_bitmap_data(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
uint32_t *bitmap_table_size, Error **errp) uint32_t *bitmap_table_size, Error **errp)
{ {
int ret; int ret;
@ -1370,7 +1373,8 @@ fail:
* Store bm->dirty_bitmap to qcow2. * Store bm->dirty_bitmap to qcow2.
* Set bm->table_offset and bm->table_size accordingly. * Set bm->table_offset and bm->table_size accordingly.
*/ */
static int store_bitmap(BlockDriverState *bs, Qcow2Bitmap *bm, Error **errp) static int GRAPH_RDLOCK
store_bitmap(BlockDriverState *bs, Qcow2Bitmap *bm, Error **errp)
{ {
int ret; int ret;
uint64_t *tb; uint64_t *tb;
@ -1555,7 +1559,6 @@ bool qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs,
FOR_EACH_DIRTY_BITMAP(bs, bitmap) { FOR_EACH_DIRTY_BITMAP(bs, bitmap) {
const char *name = bdrv_dirty_bitmap_name(bitmap); const char *name = bdrv_dirty_bitmap_name(bitmap);
uint32_t granularity = bdrv_dirty_bitmap_granularity(bitmap); uint32_t granularity = bdrv_dirty_bitmap_granularity(bitmap);
Qcow2Bitmap *bm;
if (!bdrv_dirty_bitmap_get_persistence(bitmap) || if (!bdrv_dirty_bitmap_get_persistence(bitmap) ||
bdrv_dirty_bitmap_inconsistent(bitmap)) { bdrv_dirty_bitmap_inconsistent(bitmap)) {
@ -1625,7 +1628,7 @@ bool qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs,
/* allocate clusters and store bitmaps */ /* allocate clusters and store bitmaps */
QSIMPLEQ_FOREACH(bm, bm_list, entry) { QSIMPLEQ_FOREACH(bm, bm_list, entry) {
BdrvDirtyBitmap *bitmap = bm->dirty_bitmap; bitmap = bm->dirty_bitmap;
if (bitmap == NULL || bdrv_dirty_bitmap_readonly(bitmap)) { if (bitmap == NULL || bdrv_dirty_bitmap_readonly(bitmap)) {
continue; continue;

View File

@ -163,7 +163,8 @@ int qcow2_cache_destroy(Qcow2Cache *c)
return 0; return 0;
} }
static int qcow2_cache_flush_dependency(BlockDriverState *bs, Qcow2Cache *c) static int GRAPH_RDLOCK
qcow2_cache_flush_dependency(BlockDriverState *bs, Qcow2Cache *c)
{ {
int ret; int ret;
@ -178,7 +179,8 @@ static int qcow2_cache_flush_dependency(BlockDriverState *bs, Qcow2Cache *c)
return 0; return 0;
} }
static int qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i) static int GRAPH_RDLOCK
qcow2_cache_entry_flush(BlockDriverState *bs, Qcow2Cache *c, int i)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int ret = 0; int ret = 0;
@ -318,8 +320,9 @@ int qcow2_cache_empty(BlockDriverState *bs, Qcow2Cache *c)
return 0; return 0;
} }
static int qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c, static int GRAPH_RDLOCK
uint64_t offset, void **table, bool read_from_disk) qcow2_cache_do_get(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
void **table, bool read_from_disk)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int i; int i;

View File

@ -207,7 +207,8 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
* the cache is used; otherwise the L2 slice is loaded from the image * the cache is used; otherwise the L2 slice is loaded from the image
* file. * file.
*/ */
static int l2_load(BlockDriverState *bs, uint64_t offset, static int GRAPH_RDLOCK
l2_load(BlockDriverState *bs, uint64_t offset,
uint64_t l2_offset, uint64_t **l2_slice) uint64_t l2_offset, uint64_t **l2_slice)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
@ -269,7 +270,7 @@ int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index)
* *
*/ */
static int l2_allocate(BlockDriverState *bs, int l1_index) static int GRAPH_RDLOCK l2_allocate(BlockDriverState *bs, int l1_index)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
uint64_t old_l2_offset; uint64_t old_l2_offset;
@ -751,9 +752,9 @@ fail:
* *
* Returns 0 on success, -errno in failure case * Returns 0 on success, -errno in failure case
*/ */
static int get_cluster_table(BlockDriverState *bs, uint64_t offset, static int GRAPH_RDLOCK
uint64_t **new_l2_slice, get_cluster_table(BlockDriverState *bs, uint64_t offset,
int *new_l2_index) uint64_t **new_l2_slice, int *new_l2_index)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
unsigned int l2_index; unsigned int l2_index;
@ -1155,11 +1156,10 @@ void coroutine_fn qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m)
* *
* Returns 0 on success, -errno on failure. * Returns 0 on success, -errno on failure.
*/ */
static int coroutine_fn calculate_l2_meta(BlockDriverState *bs, static int coroutine_fn GRAPH_RDLOCK
uint64_t host_cluster_offset, calculate_l2_meta(BlockDriverState *bs, uint64_t host_cluster_offset,
uint64_t guest_offset, unsigned bytes, uint64_t guest_offset, unsigned bytes, uint64_t *l2_slice,
uint64_t *l2_slice, QCowL2Meta **m, QCowL2Meta **m, bool keep_old)
bool keep_old)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int sc_index, l2_index = offset_to_l2_slice_index(s, guest_offset); int sc_index, l2_index = offset_to_l2_slice_index(s, guest_offset);
@ -1490,9 +1490,9 @@ static int coroutine_fn handle_dependencies(BlockDriverState *bs,
* *
* -errno: in error cases * -errno: in error cases
*/ */
static int coroutine_fn handle_copied(BlockDriverState *bs, static int coroutine_fn GRAPH_RDLOCK
uint64_t guest_offset, uint64_t *host_offset, uint64_t *bytes, handle_copied(BlockDriverState *bs, uint64_t guest_offset,
QCowL2Meta **m) uint64_t *host_offset, uint64_t *bytes, QCowL2Meta **m)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int l2_index; int l2_index;
@ -1600,10 +1600,9 @@ out:
* function has been waiting for another request and the allocation must be * function has been waiting for another request and the allocation must be
* restarted, but the whole request should not be failed. * restarted, but the whole request should not be failed.
*/ */
static int coroutine_fn do_alloc_cluster_offset(BlockDriverState *bs, static int coroutine_fn GRAPH_RDLOCK
uint64_t guest_offset, do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset,
uint64_t *host_offset, uint64_t *host_offset, uint64_t *nb_clusters)
uint64_t *nb_clusters)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
@ -1658,9 +1657,9 @@ static int coroutine_fn do_alloc_cluster_offset(BlockDriverState *bs,
* *
* -errno: in error cases * -errno: in error cases
*/ */
static int coroutine_fn handle_alloc(BlockDriverState *bs, static int coroutine_fn GRAPH_RDLOCK
uint64_t guest_offset, uint64_t *host_offset, uint64_t *bytes, handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
QCowL2Meta **m) uint64_t *host_offset, uint64_t *bytes, QCowL2Meta **m)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int l2_index; int l2_index;
@ -1898,8 +1897,8 @@ again:
* all clusters in the same L2 slice) and returns the number of discarded * all clusters in the same L2 slice) and returns the number of discarded
* clusters. * clusters.
*/ */
static int discard_in_l2_slice(BlockDriverState *bs, uint64_t offset, static int GRAPH_RDLOCK
uint64_t nb_clusters, discard_in_l2_slice(BlockDriverState *bs, uint64_t offset, uint64_t nb_clusters,
enum qcow2_discard_type type, bool full_discard) enum qcow2_discard_type type, bool full_discard)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
@ -2037,7 +2036,7 @@ fail:
* all clusters in the same L2 slice) and returns the number of zeroed * all clusters in the same L2 slice) and returns the number of zeroed
* clusters. * clusters.
*/ */
static int coroutine_fn static int coroutine_fn GRAPH_RDLOCK
zero_in_l2_slice(BlockDriverState *bs, uint64_t offset, zero_in_l2_slice(BlockDriverState *bs, uint64_t offset,
uint64_t nb_clusters, int flags) uint64_t nb_clusters, int flags)
{ {
@ -2093,7 +2092,7 @@ zero_in_l2_slice(BlockDriverState *bs, uint64_t offset,
return nb_clusters; return nb_clusters;
} }
static int coroutine_fn static int coroutine_fn GRAPH_RDLOCK
zero_l2_subclusters(BlockDriverState *bs, uint64_t offset, zero_l2_subclusters(BlockDriverState *bs, uint64_t offset,
unsigned nb_subclusters) unsigned nb_subclusters)
{ {
@ -2231,7 +2230,8 @@ fail:
* status_cb(). l1_entries contains the total number of L1 entries and * status_cb(). l1_entries contains the total number of L1 entries and
* *visited_l1_entries counts all visited L1 entries. * *visited_l1_entries counts all visited L1 entries.
*/ */
static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table, static int GRAPH_RDLOCK
expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
int l1_size, int64_t *visited_l1_entries, int l1_size, int64_t *visited_l1_entries,
int64_t l1_entries, int64_t l1_entries,
BlockDriverAmendStatusCB *status_cb, BlockDriverAmendStatusCB *status_cb,

View File

@ -229,8 +229,8 @@ static void set_refcount_ro6(void *refcount_array, uint64_t index,
} }
static int load_refcount_block(BlockDriverState *bs, static int GRAPH_RDLOCK
int64_t refcount_block_offset, load_refcount_block(BlockDriverState *bs, int64_t refcount_block_offset,
void **refcount_block) void **refcount_block)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
@ -302,8 +302,9 @@ static int in_same_refcount_block(BDRVQcow2State *s, uint64_t offset_a,
* *
* Returns 0 on success or -errno in error case * Returns 0 on success or -errno in error case
*/ */
static int alloc_refcount_block(BlockDriverState *bs, static int GRAPH_RDLOCK
int64_t cluster_index, void **refcount_block) alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index,
void **refcount_block)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
unsigned int refcount_table_index; unsigned int refcount_table_index;
@ -806,12 +807,9 @@ found:
/* XXX: cache several refcount block clusters ? */ /* XXX: cache several refcount block clusters ? */
/* @addend is the absolute value of the addend; if @decrease is set, @addend /* @addend is the absolute value of the addend; if @decrease is set, @addend
* will be subtracted from the current refcount, otherwise it will be added */ * will be subtracted from the current refcount, otherwise it will be added */
static int update_refcount(BlockDriverState *bs, static int GRAPH_RDLOCK
int64_t offset, update_refcount(BlockDriverState *bs, int64_t offset, int64_t length,
int64_t length, uint64_t addend, bool decrease, enum qcow2_discard_type type)
uint64_t addend,
bool decrease,
enum qcow2_discard_type type)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int64_t start, last, cluster_offset; int64_t start, last, cluster_offset;
@ -967,8 +965,8 @@ int qcow2_update_cluster_refcount(BlockDriverState *bs,
/* return < 0 if error */ /* return < 0 if error */
static int64_t alloc_clusters_noref(BlockDriverState *bs, uint64_t size, static int64_t GRAPH_RDLOCK
uint64_t max) alloc_clusters_noref(BlockDriverState *bs, uint64_t size, uint64_t max)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
uint64_t i, nb_clusters, refcount; uint64_t i, nb_clusters, refcount;
@ -2302,7 +2300,7 @@ calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
* Compares the actual reference count for each cluster in the image against the * Compares the actual reference count for each cluster in the image against the
* refcount as reported by the refcount structures on-disk. * refcount as reported by the refcount structures on-disk.
*/ */
static void coroutine_fn static void coroutine_fn GRAPH_RDLOCK
compare_refcounts(BlockDriverState *bs, BdrvCheckResult *res, compare_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
BdrvCheckMode fix, bool *rebuild, BdrvCheckMode fix, bool *rebuild,
int64_t *highest_cluster, int64_t *highest_cluster,
@ -3103,7 +3101,8 @@ int qcow2_pre_write_overlap_check(BlockDriverState *bs, int ign, int64_t offset,
* *
* @allocated should be set to true if a new cluster has been allocated. * @allocated should be set to true if a new cluster has been allocated.
*/ */
typedef int (RefblockFinishOp)(BlockDriverState *bs, uint64_t **reftable, typedef int /* GRAPH_RDLOCK_PTR */
(RefblockFinishOp)(BlockDriverState *bs, uint64_t **reftable,
uint64_t reftable_index, uint64_t *reftable_size, uint64_t reftable_index, uint64_t *reftable_size,
void *refblock, bool refblock_empty, void *refblock, bool refblock_empty,
bool *allocated, Error **errp); bool *allocated, Error **errp);
@ -3113,7 +3112,8 @@ typedef int (RefblockFinishOp)(BlockDriverState *bs, uint64_t **reftable,
* it is not empty) and inserts its offset into the new reftable. The size of * it is not empty) and inserts its offset into the new reftable. The size of
* this new reftable is increased as required. * this new reftable is increased as required.
*/ */
static int alloc_refblock(BlockDriverState *bs, uint64_t **reftable, static int GRAPH_RDLOCK
alloc_refblock(BlockDriverState *bs, uint64_t **reftable,
uint64_t reftable_index, uint64_t *reftable_size, uint64_t reftable_index, uint64_t *reftable_size,
void *refblock, bool refblock_empty, bool *allocated, void *refblock, bool refblock_empty, bool *allocated,
Error **errp) Error **errp)
@ -3166,7 +3166,8 @@ static int alloc_refblock(BlockDriverState *bs, uint64_t **reftable,
* offset specified by the new reftable's entry. It does not modify the new * offset specified by the new reftable's entry. It does not modify the new
* reftable or change any refcounts. * reftable or change any refcounts.
*/ */
static int flush_refblock(BlockDriverState *bs, uint64_t **reftable, static int GRAPH_RDLOCK
flush_refblock(BlockDriverState *bs, uint64_t **reftable,
uint64_t reftable_index, uint64_t *reftable_size, uint64_t reftable_index, uint64_t *reftable_size,
void *refblock, bool refblock_empty, bool *allocated, void *refblock, bool refblock_empty, bool *allocated,
Error **errp) Error **errp)
@ -3210,7 +3211,8 @@ static int flush_refblock(BlockDriverState *bs, uint64_t **reftable,
* *
* @allocated is set to true if a new cluster has been allocated. * @allocated is set to true if a new cluster has been allocated.
*/ */
static int walk_over_reftable(BlockDriverState *bs, uint64_t **new_reftable, static int GRAPH_RDLOCK
walk_over_reftable(BlockDriverState *bs, uint64_t **new_reftable,
uint64_t *new_reftable_index, uint64_t *new_reftable_index,
uint64_t *new_reftable_size, uint64_t *new_reftable_size,
void *new_refblock, int new_refblock_size, void *new_refblock, int new_refblock_size,
@ -3545,8 +3547,8 @@ done:
return ret; return ret;
} }
static int64_t coroutine_fn get_refblock_offset(BlockDriverState *bs, static int64_t coroutine_fn GRAPH_RDLOCK
uint64_t offset) get_refblock_offset(BlockDriverState *bs, uint64_t offset)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
uint32_t index = offset_to_reftable_index(s, offset); uint32_t index = offset_to_reftable_index(s, offset);
@ -3565,7 +3567,7 @@ static int64_t coroutine_fn get_refblock_offset(BlockDriverState *bs,
return covering_refblock_offset; return covering_refblock_offset;
} }
static int coroutine_fn static int coroutine_fn GRAPH_RDLOCK
qcow2_discard_refcount_block(BlockDriverState *bs, uint64_t discard_block_offs) qcow2_discard_refcount_block(BlockDriverState *bs, uint64_t discard_block_offs)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;

View File

@ -536,7 +536,7 @@ int qcow2_mark_dirty(BlockDriverState *bs)
* function when there are no pending requests, it does not guard against * function when there are no pending requests, it does not guard against
* concurrent requests dirtying the image. * concurrent requests dirtying the image.
*/ */
static int qcow2_mark_clean(BlockDriverState *bs) static int GRAPH_RDLOCK qcow2_mark_clean(BlockDriverState *bs)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
@ -570,7 +570,8 @@ int qcow2_mark_corrupt(BlockDriverState *bs)
* Marks the image as consistent, i.e., unsets the corrupt bit, and flushes * Marks the image as consistent, i.e., unsets the corrupt bit, and flushes
* before if necessary. * before if necessary.
*/ */
static int coroutine_fn qcow2_mark_consistent(BlockDriverState *bs) static int coroutine_fn GRAPH_RDLOCK
qcow2_mark_consistent(BlockDriverState *bs)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
@ -980,10 +981,9 @@ typedef struct Qcow2ReopenState {
QCryptoBlockOpenOptions *crypto_opts; /* Disk encryption runtime options */ QCryptoBlockOpenOptions *crypto_opts; /* Disk encryption runtime options */
} Qcow2ReopenState; } Qcow2ReopenState;
static int qcow2_update_options_prepare(BlockDriverState *bs, static int GRAPH_RDLOCK
Qcow2ReopenState *r, qcow2_update_options_prepare(BlockDriverState *bs, Qcow2ReopenState *r,
QDict *options, int flags, QDict *options, int flags, Error **errp)
Error **errp)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
QemuOpts *opts = NULL; QemuOpts *opts = NULL;
@ -1260,7 +1260,7 @@ static void qcow2_update_options_abort(BlockDriverState *bs,
qapi_free_QCryptoBlockOpenOptions(r->crypto_opts); qapi_free_QCryptoBlockOpenOptions(r->crypto_opts);
} }
static int coroutine_fn static int coroutine_fn GRAPH_RDLOCK
qcow2_update_options(BlockDriverState *bs, QDict *options, int flags, qcow2_update_options(BlockDriverState *bs, QDict *options, int flags,
Error **errp) Error **errp)
{ {
@ -1969,13 +1969,17 @@ static void qcow2_refresh_limits(BlockDriverState *bs, Error **errp)
bs->bl.pdiscard_alignment = s->cluster_size; bs->bl.pdiscard_alignment = s->cluster_size;
} }
static int qcow2_reopen_prepare(BDRVReopenState *state, static int GRAPH_UNLOCKED
BlockReopenQueue *queue, Error **errp) qcow2_reopen_prepare(BDRVReopenState *state,BlockReopenQueue *queue,
Error **errp)
{ {
BDRVQcow2State *s = state->bs->opaque; BDRVQcow2State *s = state->bs->opaque;
Qcow2ReopenState *r; Qcow2ReopenState *r;
int ret; int ret;
GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
r = g_new0(Qcow2ReopenState, 1); r = g_new0(Qcow2ReopenState, 1);
state->opaque = r; state->opaque = r;
@ -2038,6 +2042,8 @@ static void qcow2_reopen_commit(BDRVReopenState *state)
static void qcow2_reopen_commit_post(BDRVReopenState *state) static void qcow2_reopen_commit_post(BDRVReopenState *state)
{ {
GRAPH_RDLOCK_GUARD_MAINLOOP();
if (state->flags & BDRV_O_RDWR) { if (state->flags & BDRV_O_RDWR) {
Error *local_err = NULL; Error *local_err = NULL;
@ -2731,7 +2737,7 @@ fail_nometa:
return ret; return ret;
} }
static int qcow2_inactivate(BlockDriverState *bs) static int GRAPH_RDLOCK qcow2_inactivate(BlockDriverState *bs)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int ret, result = 0; int ret, result = 0;
@ -2766,7 +2772,8 @@ static int qcow2_inactivate(BlockDriverState *bs)
return result; return result;
} }
static void qcow2_do_close(BlockDriverState *bs, bool close_data_file) static void coroutine_mixed_fn GRAPH_RDLOCK
qcow2_do_close(BlockDriverState *bs, bool close_data_file)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
qemu_vfree(s->l1_table); qemu_vfree(s->l1_table);
@ -2793,18 +2800,24 @@ static void qcow2_do_close(BlockDriverState *bs, bool close_data_file)
g_free(s->image_backing_format); g_free(s->image_backing_format);
if (close_data_file && has_data_file(bs)) { if (close_data_file && has_data_file(bs)) {
GLOBAL_STATE_CODE();
bdrv_graph_rdunlock_main_loop();
bdrv_graph_wrlock(NULL); bdrv_graph_wrlock(NULL);
bdrv_unref_child(bs, s->data_file); bdrv_unref_child(bs, s->data_file);
bdrv_graph_wrunlock(); bdrv_graph_wrunlock();
s->data_file = NULL; s->data_file = NULL;
bdrv_graph_rdlock_main_loop();
} }
qcow2_refcount_close(bs); qcow2_refcount_close(bs);
qcow2_free_snapshots(bs); qcow2_free_snapshots(bs);
} }
static void qcow2_close(BlockDriverState *bs) static void GRAPH_UNLOCKED qcow2_close(BlockDriverState *bs)
{ {
GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
qcow2_do_close(bs, true); qcow2_do_close(bs, true);
} }
@ -3991,7 +4004,8 @@ finish:
} }
static bool is_zero(BlockDriverState *bs, int64_t offset, int64_t bytes) static bool coroutine_fn GRAPH_RDLOCK
is_zero(BlockDriverState *bs, int64_t offset, int64_t bytes)
{ {
int64_t nr; int64_t nr;
int res; int res;
@ -4012,7 +4026,7 @@ static bool is_zero(BlockDriverState *bs, int64_t offset, int64_t bytes)
* backing file. So, we need a loop. * backing file. So, we need a loop.
*/ */
do { do {
res = bdrv_block_status_above(bs, NULL, offset, bytes, &nr, NULL, NULL); res = bdrv_co_block_status_above(bs, NULL, offset, bytes, &nr, NULL, NULL);
offset += nr; offset += nr;
bytes -= nr; bytes -= nr;
} while (res >= 0 && (res & BDRV_BLOCK_ZERO) && nr && bytes); } while (res >= 0 && (res & BDRV_BLOCK_ZERO) && nr && bytes);
@ -4076,8 +4090,8 @@ qcow2_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes,
return ret; return ret;
} }
static coroutine_fn int qcow2_co_pdiscard(BlockDriverState *bs, static int coroutine_fn GRAPH_RDLOCK
int64_t offset, int64_t bytes) qcow2_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes)
{ {
int ret; int ret;
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
@ -4822,7 +4836,7 @@ fail:
return ret; return ret;
} }
static int make_completely_empty(BlockDriverState *bs) static int GRAPH_RDLOCK make_completely_empty(BlockDriverState *bs)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
Error *local_err = NULL; Error *local_err = NULL;
@ -4973,7 +4987,7 @@ fail:
return ret; return ret;
} }
static int qcow2_make_empty(BlockDriverState *bs) static int GRAPH_RDLOCK qcow2_make_empty(BlockDriverState *bs)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
uint64_t offset, end_offset; uint64_t offset, end_offset;
@ -5017,7 +5031,7 @@ static int qcow2_make_empty(BlockDriverState *bs)
return ret; return ret;
} }
static coroutine_fn int qcow2_co_flush_to_os(BlockDriverState *bs) static coroutine_fn GRAPH_RDLOCK int qcow2_co_flush_to_os(BlockDriverState *bs)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int ret; int ret;
@ -5366,7 +5380,7 @@ qcow2_co_load_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos)
return bs->drv->bdrv_co_preadv_part(bs, offset, qiov->size, qiov, 0, 0); return bs->drv->bdrv_co_preadv_part(bs, offset, qiov->size, qiov, 0, 0);
} }
static int qcow2_has_compressed_clusters(BlockDriverState *bs) static int GRAPH_RDLOCK qcow2_has_compressed_clusters(BlockDriverState *bs)
{ {
int64_t offset = 0; int64_t offset = 0;
int64_t bytes = bdrv_getlength(bs); int64_t bytes = bdrv_getlength(bs);
@ -5402,7 +5416,8 @@ static int qcow2_has_compressed_clusters(BlockDriverState *bs)
* Downgrades an image's version. To achieve this, any incompatible features * Downgrades an image's version. To achieve this, any incompatible features
* have to be removed. * have to be removed.
*/ */
static int qcow2_downgrade(BlockDriverState *bs, int target_version, static int GRAPH_RDLOCK
qcow2_downgrade(BlockDriverState *bs, int target_version,
BlockDriverAmendStatusCB *status_cb, void *cb_opaque, BlockDriverAmendStatusCB *status_cb, void *cb_opaque,
Error **errp) Error **errp)
{ {
@ -5512,7 +5527,8 @@ static int qcow2_downgrade(BlockDriverState *bs, int target_version,
* features of older versions, some things may have to be presented * features of older versions, some things may have to be presented
* differently. * differently.
*/ */
static int qcow2_upgrade(BlockDriverState *bs, int target_version, static int GRAPH_RDLOCK
qcow2_upgrade(BlockDriverState *bs, int target_version,
BlockDriverAmendStatusCB *status_cb, void *cb_opaque, BlockDriverAmendStatusCB *status_cb, void *cb_opaque,
Error **errp) Error **errp)
{ {
@ -5640,11 +5656,10 @@ static void qcow2_amend_helper_cb(BlockDriverState *bs,
info->original_cb_opaque); info->original_cb_opaque);
} }
static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts, static int GRAPH_RDLOCK
BlockDriverAmendStatusCB *status_cb, qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
void *cb_opaque, BlockDriverAmendStatusCB *status_cb, void *cb_opaque,
bool force, bool force, Error **errp)
Error **errp)
{ {
BDRVQcow2State *s = bs->opaque; BDRVQcow2State *s = bs->opaque;
int old_version = s->qcow_version, new_version = old_version; int old_version = s->qcow_version, new_version = old_version;

View File

@ -838,7 +838,8 @@ int qcow2_mark_dirty(BlockDriverState *bs);
int qcow2_mark_corrupt(BlockDriverState *bs); int qcow2_mark_corrupt(BlockDriverState *bs);
int qcow2_update_header(BlockDriverState *bs); int qcow2_update_header(BlockDriverState *bs);
void qcow2_signal_corruption(BlockDriverState *bs, bool fatal, int64_t offset, void GRAPH_RDLOCK
qcow2_signal_corruption(BlockDriverState *bs, bool fatal, int64_t offset,
int64_t size, const char *message_format, ...) int64_t size, const char *message_format, ...)
G_GNUC_PRINTF(5, 6); G_GNUC_PRINTF(5, 6);
@ -851,33 +852,41 @@ int qcow2_validate_table(BlockDriverState *bs, uint64_t offset,
int coroutine_fn GRAPH_RDLOCK qcow2_refcount_init(BlockDriverState *bs); int coroutine_fn GRAPH_RDLOCK qcow2_refcount_init(BlockDriverState *bs);
void qcow2_refcount_close(BlockDriverState *bs); void qcow2_refcount_close(BlockDriverState *bs);
int qcow2_get_refcount(BlockDriverState *bs, int64_t cluster_index, int GRAPH_RDLOCK qcow2_get_refcount(BlockDriverState *bs, int64_t cluster_index,
uint64_t *refcount); uint64_t *refcount);
int qcow2_update_cluster_refcount(BlockDriverState *bs, int64_t cluster_index, int GRAPH_RDLOCK
qcow2_update_cluster_refcount(BlockDriverState *bs, int64_t cluster_index,
uint64_t addend, bool decrease, uint64_t addend, bool decrease,
enum qcow2_discard_type type); enum qcow2_discard_type type);
int64_t qcow2_refcount_area(BlockDriverState *bs, uint64_t offset, int64_t GRAPH_RDLOCK
qcow2_refcount_area(BlockDriverState *bs, uint64_t offset,
uint64_t additional_clusters, bool exact_size, uint64_t additional_clusters, bool exact_size,
int new_refblock_index, int new_refblock_index,
uint64_t new_refblock_offset); uint64_t new_refblock_offset);
int64_t qcow2_alloc_clusters(BlockDriverState *bs, uint64_t size); int64_t GRAPH_RDLOCK
int64_t coroutine_fn qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset, qcow2_alloc_clusters(BlockDriverState *bs, uint64_t size);
int64_t GRAPH_RDLOCK coroutine_fn
qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
int64_t nb_clusters); int64_t nb_clusters);
int64_t coroutine_fn GRAPH_RDLOCK qcow2_alloc_bytes(BlockDriverState *bs, int size); int64_t coroutine_fn GRAPH_RDLOCK qcow2_alloc_bytes(BlockDriverState *bs, int size);
void qcow2_free_clusters(BlockDriverState *bs, void GRAPH_RDLOCK qcow2_free_clusters(BlockDriverState *bs,
int64_t offset, int64_t size, int64_t offset, int64_t size,
enum qcow2_discard_type type); enum qcow2_discard_type type);
void qcow2_free_any_cluster(BlockDriverState *bs, uint64_t l2_entry, void GRAPH_RDLOCK
qcow2_free_any_cluster(BlockDriverState *bs, uint64_t l2_entry,
enum qcow2_discard_type type); enum qcow2_discard_type type);
int qcow2_update_snapshot_refcount(BlockDriverState *bs, int GRAPH_RDLOCK
int64_t l1_table_offset, int l1_size, int addend); qcow2_update_snapshot_refcount(BlockDriverState *bs, int64_t l1_table_offset,
int l1_size, int addend);
int qcow2_flush_caches(BlockDriverState *bs); int GRAPH_RDLOCK qcow2_flush_caches(BlockDriverState *bs);
int qcow2_write_caches(BlockDriverState *bs); 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);
@ -885,39 +894,48 @@ void qcow2_process_discards(BlockDriverState *bs, int ret);
int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset, int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset,
int64_t size); int64_t size);
int qcow2_pre_write_overlap_check(BlockDriverState *bs, int ign, int64_t offset, int GRAPH_RDLOCK
qcow2_pre_write_overlap_check(BlockDriverState *bs, int ign, int64_t offset,
int64_t size, bool data_file); int64_t size, bool data_file);
int coroutine_fn qcow2_inc_refcounts_imrt(BlockDriverState *bs, BdrvCheckResult *res, int coroutine_fn qcow2_inc_refcounts_imrt(BlockDriverState *bs, BdrvCheckResult *res,
void **refcount_table, void **refcount_table,
int64_t *refcount_table_size, int64_t *refcount_table_size,
int64_t offset, int64_t size); int64_t offset, int64_t size);
int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order, int GRAPH_RDLOCK
qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order,
BlockDriverAmendStatusCB *status_cb, BlockDriverAmendStatusCB *status_cb,
void *cb_opaque, Error **errp); void *cb_opaque, Error **errp);
int coroutine_fn GRAPH_RDLOCK qcow2_shrink_reftable(BlockDriverState *bs); int coroutine_fn GRAPH_RDLOCK qcow2_shrink_reftable(BlockDriverState *bs);
int64_t coroutine_fn qcow2_get_last_cluster(BlockDriverState *bs, int64_t size);
int64_t coroutine_fn GRAPH_RDLOCK
qcow2_get_last_cluster(BlockDriverState *bs, int64_t size);
int coroutine_fn GRAPH_RDLOCK int coroutine_fn GRAPH_RDLOCK
qcow2_detect_metadata_preallocation(BlockDriverState *bs); qcow2_detect_metadata_preallocation(BlockDriverState *bs);
/* qcow2-cluster.c functions */ /* qcow2-cluster.c functions */
int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size, int GRAPH_RDLOCK
bool exact_size); qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size, bool exact_size);
int coroutine_fn GRAPH_RDLOCK int coroutine_fn GRAPH_RDLOCK
qcow2_shrink_l1_table(BlockDriverState *bs, uint64_t max_size); qcow2_shrink_l1_table(BlockDriverState *bs, uint64_t max_size);
int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index); int GRAPH_RDLOCK qcow2_write_l1_entry(BlockDriverState *bs, int l1_index);
int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num, int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num,
uint8_t *buf, int nb_sectors, bool enc, Error **errp); uint8_t *buf, int nb_sectors, bool enc, Error **errp);
int qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset, int GRAPH_RDLOCK
qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset,
unsigned int *bytes, uint64_t *host_offset, unsigned int *bytes, uint64_t *host_offset,
QCow2SubclusterType *subcluster_type); QCow2SubclusterType *subcluster_type);
int coroutine_fn qcow2_alloc_host_offset(BlockDriverState *bs, uint64_t offset,
unsigned int *bytes, int coroutine_fn GRAPH_RDLOCK
uint64_t *host_offset, QCowL2Meta **m); qcow2_alloc_host_offset(BlockDriverState *bs, uint64_t offset,
unsigned int *bytes, uint64_t *host_offset,
QCowL2Meta **m);
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);
@ -927,26 +945,33 @@ void qcow2_parse_compressed_l2_entry(BlockDriverState *bs, uint64_t l2_entry,
int coroutine_fn GRAPH_RDLOCK int coroutine_fn GRAPH_RDLOCK
qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m); qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m);
void coroutine_fn qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m); void coroutine_fn GRAPH_RDLOCK
int qcow2_cluster_discard(BlockDriverState *bs, uint64_t offset, qcow2_alloc_cluster_abort(BlockDriverState *bs, QCowL2Meta *m);
uint64_t bytes, enum qcow2_discard_type type,
bool full_discard); int GRAPH_RDLOCK
qcow2_cluster_discard(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
enum qcow2_discard_type type, bool full_discard);
int coroutine_fn GRAPH_RDLOCK int coroutine_fn GRAPH_RDLOCK
qcow2_subcluster_zeroize(BlockDriverState *bs, uint64_t offset, uint64_t bytes, qcow2_subcluster_zeroize(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
int flags); int flags);
int qcow2_expand_zero_clusters(BlockDriverState *bs, int GRAPH_RDLOCK
qcow2_expand_zero_clusters(BlockDriverState *bs,
BlockDriverAmendStatusCB *status_cb, BlockDriverAmendStatusCB *status_cb,
void *cb_opaque); void *cb_opaque);
/* qcow2-snapshot.c functions */ /* qcow2-snapshot.c functions */
int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info); int GRAPH_RDLOCK
int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id); qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info);
int qcow2_snapshot_delete(BlockDriverState *bs,
const char *snapshot_id, int GRAPH_RDLOCK
const char *name, qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id);
Error **errp);
int GRAPH_RDLOCK
qcow2_snapshot_delete(BlockDriverState *bs, const char *snapshot_id,
const char *name, Error **errp);
int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab); int qcow2_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab);
int qcow2_snapshot_load_tmp(BlockDriverState *bs, int qcow2_snapshot_load_tmp(BlockDriverState *bs,
const char *snapshot_id, const char *snapshot_id,
@ -956,14 +981,14 @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs,
void qcow2_free_snapshots(BlockDriverState *bs); void qcow2_free_snapshots(BlockDriverState *bs);
int coroutine_fn GRAPH_RDLOCK int coroutine_fn GRAPH_RDLOCK
qcow2_read_snapshots(BlockDriverState *bs, Error **errp); qcow2_read_snapshots(BlockDriverState *bs, Error **errp);
int qcow2_write_snapshots(BlockDriverState *bs); int GRAPH_RDLOCK qcow2_write_snapshots(BlockDriverState *bs);
int coroutine_fn GRAPH_RDLOCK int coroutine_fn GRAPH_RDLOCK
qcow2_check_read_snapshot_table(BlockDriverState *bs, BdrvCheckResult *result, qcow2_check_read_snapshot_table(BlockDriverState *bs, BdrvCheckResult *result,
BdrvCheckMode fix); BdrvCheckMode fix);
int coroutine_fn qcow2_check_fix_snapshot_table(BlockDriverState *bs, int coroutine_fn GRAPH_RDLOCK
BdrvCheckResult *result, qcow2_check_fix_snapshot_table(BlockDriverState *bs, BdrvCheckResult *result,
BdrvCheckMode fix); BdrvCheckMode fix);
/* qcow2-cache.c functions */ /* qcow2-cache.c functions */
@ -972,19 +997,23 @@ Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables,
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);
int qcow2_cache_flush(BlockDriverState *bs, Qcow2Cache *c); int GRAPH_RDLOCK qcow2_cache_flush(BlockDriverState *bs, Qcow2Cache *c);
int qcow2_cache_write(BlockDriverState *bs, Qcow2Cache *c); int GRAPH_RDLOCK qcow2_cache_write(BlockDriverState *bs, Qcow2Cache *c);
int qcow2_cache_set_dependency(BlockDriverState *bs, Qcow2Cache *c, int GRAPH_RDLOCK qcow2_cache_set_dependency(BlockDriverState *bs, Qcow2Cache *c,
Qcow2Cache *dependency); Qcow2Cache *dependency);
void qcow2_cache_depends_on_flush(Qcow2Cache *c); void qcow2_cache_depends_on_flush(Qcow2Cache *c);
void qcow2_cache_clean_unused(Qcow2Cache *c); void qcow2_cache_clean_unused(Qcow2Cache *c);
int qcow2_cache_empty(BlockDriverState *bs, Qcow2Cache *c); int GRAPH_RDLOCK qcow2_cache_empty(BlockDriverState *bs, Qcow2Cache *c);
int qcow2_cache_get(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset, int GRAPH_RDLOCK
qcow2_cache_get(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
void **table); void **table);
int qcow2_cache_get_empty(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
int GRAPH_RDLOCK
qcow2_cache_get_empty(BlockDriverState *bs, Qcow2Cache *c, uint64_t offset,
void **table); void **table);
void qcow2_cache_put(Qcow2Cache *c, void **table); void qcow2_cache_put(Qcow2Cache *c, void **table);
void *qcow2_cache_is_table_offset(Qcow2Cache *c, uint64_t offset); 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);
@ -998,18 +1027,22 @@ bool coroutine_fn GRAPH_RDLOCK
qcow2_load_dirty_bitmaps(BlockDriverState *bs, bool *header_updated, Error **errp); qcow2_load_dirty_bitmaps(BlockDriverState *bs, bool *header_updated, Error **errp);
bool qcow2_get_bitmap_info_list(BlockDriverState *bs, bool qcow2_get_bitmap_info_list(BlockDriverState *bs,
Qcow2BitmapInfoList **info_list, Error **errp); Qcow2BitmapInfoList **info_list, Error **errp);
int 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 coroutine_fn qcow2_truncate_bitmaps_check(BlockDriverState *bs, Error **errp); int coroutine_fn qcow2_truncate_bitmaps_check(BlockDriverState *bs, Error **errp);
bool qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs,
bool release_stored, Error **errp); bool GRAPH_RDLOCK
int qcow2_reopen_bitmaps_ro(BlockDriverState *bs, Error **errp); qcow2_store_persistent_dirty_bitmaps(BlockDriverState *bs, bool release_stored,
bool coroutine_fn qcow2_co_can_store_new_dirty_bitmap(BlockDriverState *bs,
const char *name,
uint32_t granularity,
Error **errp); Error **errp);
int coroutine_fn qcow2_co_remove_persistent_dirty_bitmap(BlockDriverState *bs,
const char *name, bool coroutine_fn GRAPH_RDLOCK
qcow2_co_can_store_new_dirty_bitmap(BlockDriverState *bs, const char *name,
uint32_t granularity, Error **errp);
int coroutine_fn GRAPH_RDLOCK
qcow2_co_remove_persistent_dirty_bitmap(BlockDriverState *bs, const char *name,
Error **errp); Error **errp);
bool qcow2_supports_persistent_dirty_bitmap(BlockDriverState *bs); bool qcow2_supports_persistent_dirty_bitmap(BlockDriverState *bs);
uint64_t qcow2_get_persistent_dirty_bitmap_size(BlockDriverState *bs, uint64_t qcow2_get_persistent_dirty_bitmap_size(BlockDriverState *bs,
uint32_t cluster_size); uint32_t cluster_size);

View File

@ -206,7 +206,7 @@ static void quorum_report_bad(QuorumOpType type, uint64_t offset,
end_sector - start_sector); end_sector - start_sector);
} }
static void quorum_report_failure(QuorumAIOCB *acb) static void GRAPH_RDLOCK quorum_report_failure(QuorumAIOCB *acb)
{ {
const char *reference = bdrv_get_device_or_node_name(acb->bs); const char *reference = bdrv_get_device_or_node_name(acb->bs);
int64_t start_sector = acb->offset / BDRV_SECTOR_SIZE; int64_t start_sector = acb->offset / BDRV_SECTOR_SIZE;
@ -219,7 +219,7 @@ static void quorum_report_failure(QuorumAIOCB *acb)
static int quorum_vote_error(QuorumAIOCB *acb); static int quorum_vote_error(QuorumAIOCB *acb);
static bool quorum_has_too_much_io_failed(QuorumAIOCB *acb) static bool GRAPH_RDLOCK quorum_has_too_much_io_failed(QuorumAIOCB *acb)
{ {
BDRVQuorumState *s = acb->bs->opaque; BDRVQuorumState *s = acb->bs->opaque;

View File

@ -505,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"

View File

@ -1168,7 +1168,9 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
/* If we are using an rbd snapshot, we must be r/o, otherwise /* If we are using an rbd snapshot, we must be r/o, otherwise
* leave as-is */ * leave as-is */
if (s->snap != NULL) { if (s->snap != NULL) {
bdrv_graph_rdlock_main_loop();
r = bdrv_apply_auto_read_only(bs, "rbd snapshots are read-only", errp); r = bdrv_apply_auto_read_only(bs, "rbd snapshots are read-only", errp);
bdrv_graph_rdunlock_main_loop();
if (r < 0) { if (r < 0) {
goto failed_post_open; goto failed_post_open;
} }
@ -1208,6 +1210,8 @@ static int qemu_rbd_reopen_prepare(BDRVReopenState *state,
BDRVRBDState *s = state->bs->opaque; BDRVRBDState *s = state->bs->opaque;
int ret = 0; int ret = 0;
GRAPH_RDLOCK_GUARD_MAINLOOP();
if (s->snap && state->flags & BDRV_O_RDWR) { if (s->snap && state->flags & BDRV_O_RDWR) {
error_setg(errp, error_setg(errp,
"Cannot change node '%s' to r/w when using RBD snapshot", "Cannot change node '%s' to r/w when using RBD snapshot",
@ -1290,7 +1294,7 @@ static int coroutine_fn qemu_rbd_start_co(BlockDriverState *bs,
* operations that exceed the current size. * operations that exceed the current size.
*/ */
if (offset + bytes > s->image_size) { if (offset + bytes > s->image_size) {
int r = qemu_rbd_resize(bs, offset + bytes); r = qemu_rbd_resize(bs, offset + bytes);
if (r < 0) { if (r < 0) {
return r; return r;
} }

View File

@ -276,7 +276,7 @@ replication_co_writev(BlockDriverState *bs, int64_t sector_num,
while (remaining_sectors > 0) { while (remaining_sectors > 0) {
int64_t count; int64_t count;
ret = bdrv_is_allocated_above(top->bs, base->bs, false, ret = bdrv_co_is_allocated_above(top->bs, base->bs, false,
sector_num * BDRV_SECTOR_SIZE, sector_num * BDRV_SECTOR_SIZE,
remaining_sectors * BDRV_SECTOR_SIZE, remaining_sectors * BDRV_SECTOR_SIZE,
&count); &count);
@ -307,13 +307,16 @@ out:
return ret; return ret;
} }
static void secondary_do_checkpoint(BlockDriverState *bs, Error **errp) static void GRAPH_UNLOCKED
secondary_do_checkpoint(BlockDriverState *bs, Error **errp)
{ {
BDRVReplicationState *s = bs->opaque; BDRVReplicationState *s = bs->opaque;
BdrvChild *active_disk = bs->file; BdrvChild *active_disk = bs->file;
Error *local_err = NULL; Error *local_err = NULL;
int ret; int ret;
GRAPH_RDLOCK_GUARD_MAINLOOP();
if (!s->backup_job) { if (!s->backup_job) {
error_setg(errp, "Backup job was cancelled unexpectedly"); error_setg(errp, "Backup job was cancelled unexpectedly");
return; return;
@ -427,7 +430,8 @@ static void backup_job_completed(void *opaque, int ret)
backup_job_cleanup(bs); backup_job_cleanup(bs);
} }
static bool check_top_bs(BlockDriverState *top_bs, BlockDriverState *bs) static bool GRAPH_RDLOCK
check_top_bs(BlockDriverState *top_bs, BlockDriverState *bs)
{ {
BdrvChild *child; BdrvChild *child;
@ -458,6 +462,8 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
Error *local_err = NULL; Error *local_err = NULL;
BackupPerf perf = { .use_copy_range = true, .max_workers = 1 }; BackupPerf perf = { .use_copy_range = true, .max_workers = 1 };
GLOBAL_STATE_CODE();
aio_context = bdrv_get_aio_context(bs); aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context); aio_context_acquire(aio_context);
s = bs->opaque; s = bs->opaque;
@ -504,12 +510,15 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
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");
bdrv_graph_rdunlock_main_loop();
aio_context_release(aio_context); aio_context_release(aio_context);
return; return;
} }
bdrv_graph_rdunlock_main_loop();
/* verify the length */ /* verify the length */
active_length = bdrv_getlength(active_disk->bs); active_length = bdrv_getlength(active_disk->bs);
@ -526,13 +535,16 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
/* Must be true, or the bdrv_getlength() calls would have failed */ /* Must be true, or the bdrv_getlength() calls would have failed */
assert(active_disk->bs->drv && hidden_disk->bs->drv); assert(active_disk->bs->drv && hidden_disk->bs->drv);
bdrv_graph_rdlock_main_loop();
if (!active_disk->bs->drv->bdrv_make_empty || if (!active_disk->bs->drv->bdrv_make_empty ||
!hidden_disk->bs->drv->bdrv_make_empty) { !hidden_disk->bs->drv->bdrv_make_empty) {
error_setg(errp, error_setg(errp,
"Active disk or hidden disk doesn't support make_empty"); "Active disk or hidden disk doesn't support make_empty");
aio_context_release(aio_context); aio_context_release(aio_context);
bdrv_graph_rdunlock_main_loop();
return; return;
} }
bdrv_graph_rdunlock_main_loop();
/* reopen the backing file in r/w mode */ /* reopen the backing file in r/w mode */
reopen_backing_file(bs, true, &local_err); reopen_backing_file(bs, true, &local_err);
@ -566,8 +578,6 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
return; return;
} }
bdrv_graph_wrunlock();
/* start backup job now */ /* start backup job now */
error_setg(&s->blocker, error_setg(&s->blocker,
"Block device is in use by internal backup job"); "Block device is in use by internal backup job");
@ -576,6 +586,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
if (!top_bs || !bdrv_is_root_node(top_bs) || if (!top_bs || !bdrv_is_root_node(top_bs) ||
!check_top_bs(top_bs, bs)) { !check_top_bs(top_bs, bs)) {
error_setg(errp, "No top_bs or it is invalid"); error_setg(errp, "No top_bs or it is invalid");
bdrv_graph_wrunlock();
reopen_backing_file(bs, false, NULL); reopen_backing_file(bs, false, NULL);
aio_context_release(aio_context); aio_context_release(aio_context);
return; return;
@ -583,6 +594,8 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
bdrv_op_block_all(top_bs, s->blocker); bdrv_op_block_all(top_bs, s->blocker);
bdrv_op_unblock(top_bs, BLOCK_OP_TYPE_DATAPLANE, s->blocker); bdrv_op_unblock(top_bs, BLOCK_OP_TYPE_DATAPLANE, s->blocker);
bdrv_graph_wrunlock();
s->backup_job = backup_job_create( s->backup_job = backup_job_create(
NULL, s->secondary_disk->bs, s->hidden_disk->bs, NULL, s->secondary_disk->bs, s->hidden_disk->bs,
0, MIRROR_SYNC_MODE_NONE, NULL, 0, false, NULL, 0, MIRROR_SYNC_MODE_NONE, NULL, 0, false, NULL,

View File

@ -155,11 +155,15 @@ bool bdrv_snapshot_find_by_id_and_name(BlockDriverState *bs,
* back if the given BDS does not support snapshots. * back if the given BDS does not support snapshots.
* Return NULL if there is no BDS to (safely) fall back to. * Return NULL if there is no BDS to (safely) fall back to.
*/ */
static BdrvChild *bdrv_snapshot_fallback_child(BlockDriverState *bs) static BdrvChild * GRAPH_RDLOCK
bdrv_snapshot_fallback_child(BlockDriverState *bs)
{ {
BdrvChild *fallback = bdrv_primary_child(bs); BdrvChild *fallback = bdrv_primary_child(bs);
BdrvChild *child; BdrvChild *child;
GLOBAL_STATE_CODE();
assert_bdrv_graph_readable();
/* We allow fallback only to primary child */ /* We allow fallback only to primary child */
if (!fallback) { if (!fallback) {
return NULL; return NULL;
@ -182,8 +186,10 @@ static BdrvChild *bdrv_snapshot_fallback_child(BlockDriverState *bs)
return fallback; return fallback;
} }
static BlockDriverState *bdrv_snapshot_fallback(BlockDriverState *bs) static BlockDriverState * GRAPH_RDLOCK
bdrv_snapshot_fallback(BlockDriverState *bs)
{ {
GLOBAL_STATE_CODE();
return child_bs(bdrv_snapshot_fallback_child(bs)); return child_bs(bdrv_snapshot_fallback_child(bs));
} }
@ -254,7 +260,10 @@ int bdrv_snapshot_goto(BlockDriverState *bs,
return ret; return ret;
} }
bdrv_graph_rdlock_main_loop();
fallback = bdrv_snapshot_fallback_child(bs); fallback = bdrv_snapshot_fallback_child(bs);
bdrv_graph_rdunlock_main_loop();
if (fallback) { if (fallback) {
QDict *options; QDict *options;
QDict *file_options; QDict *file_options;
@ -302,7 +311,10 @@ int bdrv_snapshot_goto(BlockDriverState *bs,
* respective option (with the qdict_put_str() call above). * respective option (with the qdict_put_str() call above).
* Assert that .bdrv_open() has attached the right BDS as primary child. * Assert that .bdrv_open() has attached the right BDS as primary child.
*/ */
bdrv_graph_rdlock_main_loop();
assert(bdrv_primary_bs(bs) == fallback_bs); assert(bdrv_primary_bs(bs) == fallback_bs);
bdrv_graph_rdunlock_main_loop();
bdrv_unref(fallback_bs); bdrv_unref(fallback_bs);
return ret; return ret;
} }
@ -374,10 +386,12 @@ int bdrv_snapshot_delete(BlockDriverState *bs,
int bdrv_snapshot_list(BlockDriverState *bs, int bdrv_snapshot_list(BlockDriverState *bs,
QEMUSnapshotInfo **psn_info) QEMUSnapshotInfo **psn_info)
{ {
GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
BlockDriver *drv = bs->drv; BlockDriver *drv = bs->drv;
BlockDriverState *fallback_bs = bdrv_snapshot_fallback(bs); BlockDriverState *fallback_bs = bdrv_snapshot_fallback(bs);
GLOBAL_STATE_CODE();
if (!drv) { if (!drv) {
return -ENOMEDIUM; return -ENOMEDIUM;
} }
@ -418,6 +432,7 @@ int bdrv_snapshot_load_tmp(BlockDriverState *bs,
BlockDriver *drv = bs->drv; BlockDriver *drv = bs->drv;
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
if (!drv) { if (!drv) {
error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, bdrv_get_device_name(bs)); error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, bdrv_get_device_name(bs));
@ -462,9 +477,9 @@ int bdrv_snapshot_load_tmp_by_id_or_name(BlockDriverState *bs,
} }
static int bdrv_all_get_snapshot_devices(bool has_devices, strList *devices, static int GRAPH_RDLOCK
GList **all_bdrvs, bdrv_all_get_snapshot_devices(bool has_devices, strList *devices,
Error **errp) GList **all_bdrvs, Error **errp)
{ {
g_autoptr(GList) bdrvs = NULL; g_autoptr(GList) bdrvs = NULL;
@ -496,8 +511,11 @@ static int bdrv_all_get_snapshot_devices(bool has_devices, strList *devices,
} }
static bool bdrv_all_snapshots_includes_bs(BlockDriverState *bs) static bool GRAPH_RDLOCK bdrv_all_snapshots_includes_bs(BlockDriverState *bs)
{ {
GLOBAL_STATE_CODE();
assert_bdrv_graph_readable();
if (!bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) { if (!bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) {
return false; return false;
} }
@ -518,6 +536,7 @@ bool bdrv_all_can_snapshot(bool has_devices, strList *devices,
GList *iterbdrvs; GList *iterbdrvs;
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) { if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) {
return false; return false;
@ -554,6 +573,7 @@ int bdrv_all_delete_snapshot(const char *name,
GList *iterbdrvs; GList *iterbdrvs;
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) { if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) {
return -1; return -1;
@ -593,10 +613,15 @@ int bdrv_all_goto_snapshot(const char *name,
{ {
g_autoptr(GList) bdrvs = NULL; g_autoptr(GList) bdrvs = NULL;
GList *iterbdrvs; GList *iterbdrvs;
int ret;
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) { bdrv_graph_rdlock_main_loop();
ret = bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp);
bdrv_graph_rdunlock_main_loop();
if (ret < 0) {
return -1; return -1;
} }
@ -605,15 +630,22 @@ int bdrv_all_goto_snapshot(const char *name,
BlockDriverState *bs = iterbdrvs->data; BlockDriverState *bs = iterbdrvs->data;
AioContext *ctx = bdrv_get_aio_context(bs); AioContext *ctx = bdrv_get_aio_context(bs);
int ret = 0; int ret = 0;
bool all_snapshots_includes_bs;
aio_context_acquire(ctx); aio_context_acquire(ctx);
if (devices || bdrv_all_snapshots_includes_bs(bs)) { bdrv_graph_rdlock_main_loop();
all_snapshots_includes_bs = bdrv_all_snapshots_includes_bs(bs);
bdrv_graph_rdunlock_main_loop();
if (devices || all_snapshots_includes_bs) {
ret = bdrv_snapshot_goto(bs, name, errp); ret = bdrv_snapshot_goto(bs, name, errp);
} }
aio_context_release(ctx); aio_context_release(ctx);
if (ret < 0) { if (ret < 0) {
bdrv_graph_rdlock_main_loop();
error_prepend(errp, "Could not load snapshot '%s' on '%s': ", error_prepend(errp, "Could not load snapshot '%s' on '%s': ",
name, bdrv_get_device_or_node_name(bs)); name, bdrv_get_device_or_node_name(bs));
bdrv_graph_rdunlock_main_loop();
return -1; return -1;
} }
@ -631,6 +663,7 @@ int bdrv_all_has_snapshot(const char *name,
GList *iterbdrvs; GList *iterbdrvs;
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) { if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) {
return -1; return -1;
@ -673,7 +706,9 @@ int bdrv_all_create_snapshot(QEMUSnapshotInfo *sn,
{ {
g_autoptr(GList) bdrvs = NULL; g_autoptr(GList) bdrvs = NULL;
GList *iterbdrvs; GList *iterbdrvs;
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) { if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) {
return -1; return -1;
@ -715,6 +750,7 @@ BlockDriverState *bdrv_all_find_vmstate_bs(const char *vmstate_bs,
GList *iterbdrvs; GList *iterbdrvs;
GLOBAL_STATE_CODE(); GLOBAL_STATE_CODE();
GRAPH_RDLOCK_GUARD_MAINLOOP();
if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) { if (bdrv_all_get_snapshot_devices(has_devices, devices, &bdrvs, errp) < 0) {
return NULL; return NULL;

View File

@ -172,7 +172,7 @@ static int coroutine_fn stream_run(Job *job, Error **errp)
copy = false; copy = false;
WITH_GRAPH_RDLOCK_GUARD() { WITH_GRAPH_RDLOCK_GUARD() {
ret = bdrv_is_allocated(unfiltered_bs, offset, STREAM_CHUNK, &n); ret = bdrv_co_is_allocated(unfiltered_bs, offset, STREAM_CHUNK, &n);
if (ret == 1) { if (ret == 1) {
/* Allocated in the top, no need to copy. */ /* Allocated in the top, no need to copy. */
} else if (ret >= 0) { } else if (ret >= 0) {
@ -180,7 +180,7 @@ static int coroutine_fn stream_run(Job *job, Error **errp)
* Copy if allocated in the intermediate images. Limit to the * Copy if allocated in the intermediate images. Limit to the
* known-unallocated area [offset, offset+n*BDRV_SECTOR_SIZE). * known-unallocated area [offset, offset+n*BDRV_SECTOR_SIZE).
*/ */
ret = bdrv_is_allocated_above(bdrv_cow_bs(unfiltered_bs), ret = bdrv_co_is_allocated_above(bdrv_cow_bs(unfiltered_bs),
s->base_overlay, true, s->base_overlay, true,
offset, n, &n); offset, n, &n);
/* Finish early if end of backing file has been reached */ /* Finish early if end of backing file has been reached */
@ -292,7 +292,6 @@ void stream_start(const char *job_id, BlockDriverState *bs,
/* Make sure that the image is opened in read-write mode */ /* Make sure that the image is opened in read-write mode */
bs_read_only = bdrv_is_read_only(bs); bs_read_only = bdrv_is_read_only(bs);
if (bs_read_only) { if (bs_read_only) {
int ret;
/* 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) {
return; return;

View File

@ -166,6 +166,7 @@ iscsi_xcopy(void *src_lun, uint64_t src_off, void *dst_lun, uint64_t dst_off, ui
# nbd.c # nbd.c
nbd_parse_blockstatus_compliance(const char *err) "ignoring extra data from non-compliant server: %s" nbd_parse_blockstatus_compliance(const char *err) "ignoring extra data from non-compliant server: %s"
nbd_structured_read_compliance(const char *type) "server sent non-compliant unaligned read %s chunk" nbd_structured_read_compliance(const char *type) "server sent non-compliant unaligned read %s chunk"
nbd_extended_headers_compliance(const char *type) "server sent non-compliant %s chunk not matching choice of extended headers"
nbd_read_reply_entry_fail(int ret, const char *err) "ret = %d, err: %s" nbd_read_reply_entry_fail(int ret, const char *err) "ret = %d, err: %s"
nbd_co_request_fail(uint64_t from, uint64_t len, uint64_t handle, uint16_t flags, uint16_t type, const char *name, int ret, const char *err) "Request failed { .from = %" PRIu64", .len = %" PRIu64 ", .handle = %" PRIu64 ", .flags = 0x%" PRIx16 ", .type = %" PRIu16 " (%s) } ret = %d, err: %s" nbd_co_request_fail(uint64_t from, uint64_t len, uint64_t handle, uint16_t flags, uint16_t type, const char *name, int ret, const char *err) "Request failed { .from = %" PRIu64", .len = %" PRIu64 ", .handle = %" PRIu64 ", .flags = 0x%" PRIx16 ", .type = %" PRIu16 " (%s) } ret = %d, err: %s"
nbd_client_handshake(const char *export_name) "export '%s'" nbd_client_handshake(const char *export_name) "export '%s'"

View File

@ -492,12 +492,14 @@ 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));
ret = migrate_add_blocker(s->migration_blocker, errp); bdrv_graph_rdunlock_main_loop();
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;
} }
@ -634,7 +636,6 @@ vdi_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
bmap_entry = le32_to_cpu(s->bmap[block_index]); bmap_entry = le32_to_cpu(s->bmap[block_index]);
if (!VDI_IS_ALLOCATED(bmap_entry)) { if (!VDI_IS_ALLOCATED(bmap_entry)) {
/* Allocate new block and write to it. */ /* Allocate new block and write to it. */
uint64_t data_offset;
qemu_co_rwlock_upgrade(&s->bmap_lock); qemu_co_rwlock_upgrade(&s->bmap_lock);
bmap_entry = le32_to_cpu(s->bmap[block_index]); bmap_entry = le32_to_cpu(s->bmap[block_index]);
if (VDI_IS_ALLOCATED(bmap_entry)) { if (VDI_IS_ALLOCATED(bmap_entry)) {
@ -700,7 +701,7 @@ nonallocating_write:
/* One or more new blocks were allocated. */ /* One or more new blocks were allocated. */
VdiHeader *header; VdiHeader *header;
uint8_t *base; uint8_t *base;
uint64_t offset; uint64_t bmap_offset;
uint32_t n_sectors; uint32_t n_sectors;
g_free(block); g_free(block);
@ -723,11 +724,11 @@ nonallocating_write:
bmap_first /= (SECTOR_SIZE / sizeof(uint32_t)); bmap_first /= (SECTOR_SIZE / sizeof(uint32_t));
bmap_last /= (SECTOR_SIZE / sizeof(uint32_t)); bmap_last /= (SECTOR_SIZE / sizeof(uint32_t));
n_sectors = bmap_last - bmap_first + 1; n_sectors = bmap_last - bmap_first + 1;
offset = s->bmap_sector + bmap_first; bmap_offset = s->bmap_sector + bmap_first;
base = ((uint8_t *)&s->bmap[0]) + bmap_first * SECTOR_SIZE; base = ((uint8_t *)&s->bmap[0]) + bmap_first * SECTOR_SIZE;
logout("will write %u block map sectors starting from entry %u\n", logout("will write %u block map sectors starting from entry %u\n",
n_sectors, bmap_first); n_sectors, bmap_first);
ret = bdrv_co_pwrite(bs->file, offset * SECTOR_SIZE, ret = bdrv_co_pwrite(bs->file, bmap_offset * SECTOR_SIZE,
n_sectors * SECTOR_SIZE, base, 0); n_sectors * SECTOR_SIZE, base, 0);
} }
@ -986,8 +987,7 @@ 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 vdi_has_zero_init(BlockDriverState *bs) static int vdi_has_zero_init(BlockDriverState *bs)

View File

@ -985,8 +985,7 @@ 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);
@ -1001,11 +1000,15 @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags,
uint64_t signature; uint64_t signature;
Error *local_err = NULL; Error *local_err = 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();
s->bat = NULL; s->bat = NULL;
s->first_visible_write = true; s->first_visible_write = true;
@ -1093,9 +1096,8 @@ 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(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;
} }

View File

@ -410,7 +410,8 @@ uint32_t vhdx_checksum_calc(uint32_t crc, uint8_t *buf, size_t size,
bool vhdx_checksum_is_valid(uint8_t *buf, size_t size, int crc_offset); bool vhdx_checksum_is_valid(uint8_t *buf, size_t size, int crc_offset);
int vhdx_parse_log(BlockDriverState *bs, BDRVVHDXState *s, bool *flushed, int GRAPH_RDLOCK
vhdx_parse_log(BlockDriverState *bs, BDRVVHDXState *s, bool *flushed,
Error **errp); Error **errp);
int coroutine_fn GRAPH_RDLOCK int coroutine_fn GRAPH_RDLOCK

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