Merge
This commit is contained in:
commit
d86aae8ed9
@ -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
|
||||||
|
@ -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'
|
||||||
|
@ -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:
|
||||||
|
19
.mailmap
19
.mailmap
@ -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>
|
||||||
|
@ -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:
|
||||||
|
191
MAINTAINERS
191
MAINTAINERS
@ -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/
|
||||||
|
@ -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);
|
@ -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 */
|
@ -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();
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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')
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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 { \
|
||||||
|
@ -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);
|
||||||
|
@ -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
@ -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);
|
||||||
}
|
}
|
28
accel/tcg/internal-common.h
Normal file
28
accel/tcg/internal-common.h
Normal 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
|
@ -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;
|
||||||
|
|
||||||
/**
|
/**
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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',
|
||||||
))
|
))
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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 */
|
||||||
|
@ -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. */
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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),
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
223
audio/audio.c
223
audio/audio.c
@ -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);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return default_audio_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AUD_register_card (const char *name, QEMUSoundCard *card)
|
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,17 +2144,24 @@ 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)
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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) \
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
|
||||||
}
|
|
@ -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);
|
||||||
|
@ -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),
|
||||||
|
@ -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),
|
||||||
|
@ -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),
|
||||||
|
@ -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),
|
||||||
|
@ -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',
|
||||||
|
@ -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),
|
||||||
|
@ -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),
|
||||||
|
@ -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),
|
||||||
|
@ -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),
|
||||||
|
@ -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),
|
||||||
|
@ -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),
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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),
|
||||||
|
@ -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
117
block.c
@ -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]);
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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.
|
||||||
|
@ -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) {
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
117
block/io.c
117
block/io.c
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
64
block/nbd.c
64
block/nbd.c
@ -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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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;
|
||||||
|
11
block/qapi.c
11
block/qapi.c
@ -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;
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
135
block/qcow2.h
135
block/qcow2.h
@ -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);
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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"
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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'"
|
||||||
|
16
block/vdi.c
16
block/vdi.c
@ -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)
|
||||||
|
10
block/vhdx.c
10
block/vhdx.c
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user